blob: fd488ad4263af3cdc38c39d4de93bf6976c73414 [file] [log] [blame]
Kay Sievers2b2af542009-04-30 15:23:42 +02001/*
2 * devtmpfs - kernel-maintained tmpfs-based /dev
3 *
4 * Copyright (C) 2009, Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * During bootup, before any driver core device is registered,
7 * devtmpfs, a tmpfs-based filesystem is created. Every driver-core
8 * device which requests a device node, will add a node in this
9 * filesystem. The node is named after the the name of the device,
10 * or the susbsytem can provide a custom name. All devices are
11 * owned by root and have a mode of 0600.
12 */
13
14#include <linux/kernel.h>
15#include <linux/syscalls.h>
16#include <linux/mount.h>
17#include <linux/device.h>
18#include <linux/genhd.h>
19#include <linux/namei.h>
20#include <linux/fs.h>
21#include <linux/shmem_fs.h>
22#include <linux/cred.h>
23#include <linux/init_task.h>
24
25static struct vfsmount *dev_mnt;
26
27#if defined CONFIG_DEVTMPFS_MOUNT
28static int dev_mount = 1;
29#else
30static int dev_mount;
31#endif
32
33static int __init mount_param(char *str)
34{
35 dev_mount = simple_strtoul(str, NULL, 0);
36 return 1;
37}
38__setup("devtmpfs.mount=", mount_param);
39
40static int dev_get_sb(struct file_system_type *fs_type, int flags,
41 const char *dev_name, void *data, struct vfsmount *mnt)
42{
43 return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
44}
45
46static struct file_system_type dev_fs_type = {
47 .name = "devtmpfs",
48 .get_sb = dev_get_sb,
49 .kill_sb = kill_litter_super,
50};
51
52#ifdef CONFIG_BLOCK
53static inline int is_blockdev(struct device *dev)
54{
55 return dev->class == &block_class;
56}
57#else
58static inline int is_blockdev(struct device *dev) { return 0; }
59#endif
60
61static int dev_mkdir(const char *name, mode_t mode)
62{
63 struct nameidata nd;
64 struct dentry *dentry;
65 int err;
66
67 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
68 name, LOOKUP_PARENT, &nd);
69 if (err)
70 return err;
71
72 dentry = lookup_create(&nd, 1);
73 if (!IS_ERR(dentry)) {
74 err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
75 dput(dentry);
76 } else {
77 err = PTR_ERR(dentry);
78 }
79 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
80
81 path_put(&nd.path);
82 return err;
83}
84
85static int create_path(const char *nodepath)
86{
87 char *path;
88 struct nameidata nd;
89 int err = 0;
90
91 path = kstrdup(nodepath, GFP_KERNEL);
92 if (!path)
93 return -ENOMEM;
94
95 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
96 path, LOOKUP_PARENT, &nd);
97 if (err == 0) {
98 struct dentry *dentry;
99
100 /* create directory right away */
101 dentry = lookup_create(&nd, 1);
102 if (!IS_ERR(dentry)) {
103 err = vfs_mkdir(nd.path.dentry->d_inode,
104 dentry, 0755);
105 dput(dentry);
106 }
107 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
108
109 path_put(&nd.path);
110 } else if (err == -ENOENT) {
111 char *s;
112
113 /* parent directories do not exist, create them */
114 s = path;
115 while (1) {
116 s = strchr(s, '/');
117 if (!s)
118 break;
119 s[0] = '\0';
120 err = dev_mkdir(path, 0755);
121 if (err && err != -EEXIST)
122 break;
123 s[0] = '/';
124 s++;
125 }
126 }
127
128 kfree(path);
129 return err;
130}
131
132int devtmpfs_create_node(struct device *dev)
133{
134 const char *tmp = NULL;
135 const char *nodename;
136 const struct cred *curr_cred;
137 mode_t mode;
138 struct nameidata nd;
139 struct dentry *dentry;
140 int err;
141
142 if (!dev_mnt)
143 return 0;
144
145 nodename = device_get_nodename(dev, &tmp);
146 if (!nodename)
147 return -ENOMEM;
148
149 if (is_blockdev(dev))
150 mode = S_IFBLK|0600;
151 else
152 mode = S_IFCHR|0600;
153
154 curr_cred = override_creds(&init_cred);
155 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
156 nodename, LOOKUP_PARENT, &nd);
157 if (err == -ENOENT) {
158 /* create missing parent directories */
159 create_path(nodename);
160 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
161 nodename, LOOKUP_PARENT, &nd);
162 if (err)
163 goto out;
164 }
165
166 dentry = lookup_create(&nd, 0);
167 if (!IS_ERR(dentry)) {
168 err = vfs_mknod(nd.path.dentry->d_inode,
169 dentry, mode, dev->devt);
170 /* mark as kernel created inode */
171 if (!err)
172 dentry->d_inode->i_private = &dev_mnt;
173 dput(dentry);
174 } else {
175 err = PTR_ERR(dentry);
176 }
177 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
178
179 path_put(&nd.path);
180out:
181 kfree(tmp);
182 revert_creds(curr_cred);
183 return err;
184}
185
186static int dev_rmdir(const char *name)
187{
188 struct nameidata nd;
189 struct dentry *dentry;
190 int err;
191
192 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
193 name, LOOKUP_PARENT, &nd);
194 if (err)
195 return err;
196
197 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
198 dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
199 if (!IS_ERR(dentry)) {
200 if (dentry->d_inode)
201 err = vfs_rmdir(nd.path.dentry->d_inode, dentry);
202 else
203 err = -ENOENT;
204 dput(dentry);
205 } else {
206 err = PTR_ERR(dentry);
207 }
208 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
209
210 path_put(&nd.path);
211 return err;
212}
213
214static int delete_path(const char *nodepath)
215{
216 const char *path;
217 int err = 0;
218
219 path = kstrdup(nodepath, GFP_KERNEL);
220 if (!path)
221 return -ENOMEM;
222
223 while (1) {
224 char *base;
225
226 base = strrchr(path, '/');
227 if (!base)
228 break;
229 base[0] = '\0';
230 err = dev_rmdir(path);
231 if (err)
232 break;
233 }
234
235 kfree(path);
236 return err;
237}
238
239static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
240{
241 /* did we create it */
242 if (inode->i_private != &dev_mnt)
243 return 0;
244
245 /* does the dev_t match */
246 if (is_blockdev(dev)) {
247 if (!S_ISBLK(stat->mode))
248 return 0;
249 } else {
250 if (!S_ISCHR(stat->mode))
251 return 0;
252 }
253 if (stat->rdev != dev->devt)
254 return 0;
255
256 /* ours */
257 return 1;
258}
259
260int devtmpfs_delete_node(struct device *dev)
261{
262 const char *tmp = NULL;
263 const char *nodename;
264 const struct cred *curr_cred;
265 struct nameidata nd;
266 struct dentry *dentry;
267 struct kstat stat;
268 int deleted = 1;
269 int err;
270
271 if (!dev_mnt)
272 return 0;
273
274 nodename = device_get_nodename(dev, &tmp);
275 if (!nodename)
276 return -ENOMEM;
277
278 curr_cred = override_creds(&init_cred);
279 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
280 nodename, LOOKUP_PARENT, &nd);
281 if (err)
282 goto out;
283
284 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
285 dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
286 if (!IS_ERR(dentry)) {
287 if (dentry->d_inode) {
288 err = vfs_getattr(nd.path.mnt, dentry, &stat);
289 if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
290 err = vfs_unlink(nd.path.dentry->d_inode,
291 dentry);
292 if (!err || err == -ENOENT)
293 deleted = 1;
294 }
295 } else {
296 err = -ENOENT;
297 }
298 dput(dentry);
299 } else {
300 err = PTR_ERR(dentry);
301 }
302 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
303
304 path_put(&nd.path);
305 if (deleted && strchr(nodename, '/'))
306 delete_path(nodename);
307out:
308 kfree(tmp);
309 revert_creds(curr_cred);
310 return err;
311}
312
313/*
314 * If configured, or requested by the commandline, devtmpfs will be
315 * auto-mounted after the kernel mounted the root filesystem.
316 */
317int devtmpfs_mount(const char *mountpoint)
318{
319 struct path path;
320 int err;
321
322 if (!dev_mount)
323 return 0;
324
325 if (!dev_mnt)
326 return 0;
327
328 err = kern_path(mountpoint, LOOKUP_FOLLOW, &path);
329 if (err)
330 return err;
331 err = do_add_mount(dev_mnt, &path, 0, NULL);
332 if (err)
333 printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
334 else
335 printk(KERN_INFO "devtmpfs: mounted\n");
336 path_put(&path);
337 return err;
338}
339
340/*
341 * Create devtmpfs instance, driver-core devices will add their device
342 * nodes here.
343 */
344int __init devtmpfs_init(void)
345{
346 int err;
347 struct vfsmount *mnt;
348
349 err = register_filesystem(&dev_fs_type);
350 if (err) {
351 printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
352 "type %i\n", err);
353 return err;
354 }
355
356 mnt = kern_mount(&dev_fs_type);
357 if (IS_ERR(mnt)) {
358 err = PTR_ERR(mnt);
359 printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
360 unregister_filesystem(&dev_fs_type);
361 return err;
362 }
363 dev_mnt = mnt;
364
365 printk(KERN_INFO "devtmpfs: initialized\n");
366 return 0;
367}