Driver Core: devtmpfs - kernel-maintained tmpfs-based /dev
[safe/jmp/linux-2.6] / drivers / base / devtmpfs.c
1 /*
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
25 static struct vfsmount *dev_mnt;
26
27 #if defined CONFIG_DEVTMPFS_MOUNT
28 static int dev_mount = 1;
29 #else
30 static int dev_mount;
31 #endif
32
33 static 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
40 static 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
46 static 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
53 static inline int is_blockdev(struct device *dev)
54 {
55         return dev->class == &block_class;
56 }
57 #else
58 static inline int is_blockdev(struct device *dev) { return 0; }
59 #endif
60
61 static 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
85 static 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
132 int 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);
180 out:
181         kfree(tmp);
182         revert_creds(curr_cred);
183         return err;
184 }
185
186 static 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
214 static 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
239 static 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
260 int 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);
307 out:
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  */
317 int 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  */
344 int __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 }