blob: 880a203b6688c752fffa5571bb584522f779226d [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
Kay Sieverse454cea2009-09-18 23:01:12 +02009 * filesystem.
10 * By default, all devices are named after the the name of the
11 * device, owned by root and have a default mode of 0600. Subsystems
12 * can overwrite the default setting if needed.
Kay Sievers2b2af542009-04-30 15:23:42 +020013 */
14
15#include <linux/kernel.h>
16#include <linux/syscalls.h>
17#include <linux/mount.h>
18#include <linux/device.h>
19#include <linux/genhd.h>
20#include <linux/namei.h>
21#include <linux/fs.h>
22#include <linux/shmem_fs.h>
23#include <linux/cred.h>
Kay Sieverse454cea2009-09-18 23:01:12 +020024#include <linux/sched.h>
Kay Sievers2b2af542009-04-30 15:23:42 +020025#include <linux/init_task.h>
26
27static struct vfsmount *dev_mnt;
28
29#if defined CONFIG_DEVTMPFS_MOUNT
30static int dev_mount = 1;
31#else
32static int dev_mount;
33#endif
34
Kay Sieversed413ae2009-10-28 19:51:06 +010035static rwlock_t dirlock;
36
Kay Sievers2b2af542009-04-30 15:23:42 +020037static int __init mount_param(char *str)
38{
39 dev_mount = simple_strtoul(str, NULL, 0);
40 return 1;
41}
42__setup("devtmpfs.mount=", mount_param);
43
44static int dev_get_sb(struct file_system_type *fs_type, int flags,
45 const char *dev_name, void *data, struct vfsmount *mnt)
46{
47 return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
48}
49
50static struct file_system_type dev_fs_type = {
51 .name = "devtmpfs",
52 .get_sb = dev_get_sb,
53 .kill_sb = kill_litter_super,
54};
55
56#ifdef CONFIG_BLOCK
57static inline int is_blockdev(struct device *dev)
58{
59 return dev->class == &block_class;
60}
61#else
62static inline int is_blockdev(struct device *dev) { return 0; }
63#endif
64
65static int dev_mkdir(const char *name, mode_t mode)
66{
67 struct nameidata nd;
68 struct dentry *dentry;
69 int err;
70
71 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
72 name, LOOKUP_PARENT, &nd);
73 if (err)
74 return err;
75
76 dentry = lookup_create(&nd, 1);
77 if (!IS_ERR(dentry)) {
78 err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
79 dput(dentry);
80 } else {
81 err = PTR_ERR(dentry);
82 }
83 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
84
85 path_put(&nd.path);
86 return err;
87}
88
89static int create_path(const char *nodepath)
90{
Kay Sievers2b2af542009-04-30 15:23:42 +020091 struct nameidata nd;
92 int err = 0;
93
Kay Sieversed413ae2009-10-28 19:51:06 +010094 read_lock(&dirlock);
Kay Sievers2b2af542009-04-30 15:23:42 +020095 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
Kay Sieversed413ae2009-10-28 19:51:06 +010096 nodepath, LOOKUP_PARENT, &nd);
Kay Sievers2b2af542009-04-30 15:23:42 +020097 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);
Kay Sievers2b2af542009-04-30 15:23:42 +0200108 path_put(&nd.path);
109 } else if (err == -ENOENT) {
Kay Sieversed413ae2009-10-28 19:51:06 +0100110 char *path;
Kay Sievers2b2af542009-04-30 15:23:42 +0200111 char *s;
112
113 /* parent directories do not exist, create them */
Kay Sieversed413ae2009-10-28 19:51:06 +0100114 path = kstrdup(nodepath, GFP_KERNEL);
115 if (!path)
116 return -ENOMEM;
Kay Sievers2b2af542009-04-30 15:23:42 +0200117 s = path;
Kay Sieversed413ae2009-10-28 19:51:06 +0100118 for (;;) {
Kay Sievers2b2af542009-04-30 15:23:42 +0200119 s = strchr(s, '/');
120 if (!s)
121 break;
122 s[0] = '\0';
123 err = dev_mkdir(path, 0755);
124 if (err && err != -EEXIST)
125 break;
126 s[0] = '/';
127 s++;
128 }
Kay Sieversed413ae2009-10-28 19:51:06 +0100129 kfree(path);
Kay Sievers2b2af542009-04-30 15:23:42 +0200130 }
Kay Sieversed413ae2009-10-28 19:51:06 +0100131 read_unlock(&dirlock);
Kay Sievers2b2af542009-04-30 15:23:42 +0200132
Kay Sievers2b2af542009-04-30 15:23:42 +0200133 return err;
134}
135
136int devtmpfs_create_node(struct device *dev)
137{
138 const char *tmp = NULL;
139 const char *nodename;
140 const struct cred *curr_cred;
Kay Sieverse454cea2009-09-18 23:01:12 +0200141 mode_t mode = 0;
Kay Sievers2b2af542009-04-30 15:23:42 +0200142 struct nameidata nd;
143 struct dentry *dentry;
144 int err;
145
146 if (!dev_mnt)
147 return 0;
148
Kay Sieverse454cea2009-09-18 23:01:12 +0200149 nodename = device_get_devnode(dev, &mode, &tmp);
Kay Sievers2b2af542009-04-30 15:23:42 +0200150 if (!nodename)
151 return -ENOMEM;
152
Kay Sieverse454cea2009-09-18 23:01:12 +0200153 if (mode == 0)
154 mode = 0600;
Kay Sievers2b2af542009-04-30 15:23:42 +0200155 if (is_blockdev(dev))
Kay Sieverse454cea2009-09-18 23:01:12 +0200156 mode |= S_IFBLK;
Kay Sievers2b2af542009-04-30 15:23:42 +0200157 else
Kay Sieverse454cea2009-09-18 23:01:12 +0200158 mode |= S_IFCHR;
Kay Sievers2b2af542009-04-30 15:23:42 +0200159
160 curr_cred = override_creds(&init_cred);
Kay Sievers00926992009-10-28 19:50:57 +0100161
Kay Sievers2b2af542009-04-30 15:23:42 +0200162 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
163 nodename, LOOKUP_PARENT, &nd);
164 if (err == -ENOENT) {
Kay Sievers2b2af542009-04-30 15:23:42 +0200165 create_path(nodename);
166 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
167 nodename, LOOKUP_PARENT, &nd);
Kay Sievers2b2af542009-04-30 15:23:42 +0200168 }
Kay Sievers00926992009-10-28 19:50:57 +0100169 if (err)
170 goto out;
Kay Sievers2b2af542009-04-30 15:23:42 +0200171
172 dentry = lookup_create(&nd, 0);
173 if (!IS_ERR(dentry)) {
174 err = vfs_mknod(nd.path.dentry->d_inode,
175 dentry, mode, dev->devt);
Kay Sievers00926992009-10-28 19:50:57 +0100176 if (!err) {
177 struct iattr newattrs;
178
179 /* fixup possibly umasked mode */
180 newattrs.ia_mode = mode;
181 newattrs.ia_valid = ATTR_MODE;
182 mutex_lock(&dentry->d_inode->i_mutex);
183 notify_change(dentry, &newattrs);
184 mutex_unlock(&dentry->d_inode->i_mutex);
185
186 /* mark as kernel-created inode */
Kay Sievers2b2af542009-04-30 15:23:42 +0200187 dentry->d_inode->i_private = &dev_mnt;
Kay Sievers00926992009-10-28 19:50:57 +0100188 }
Kay Sievers2b2af542009-04-30 15:23:42 +0200189 dput(dentry);
190 } else {
191 err = PTR_ERR(dentry);
192 }
Kay Sievers2b2af542009-04-30 15:23:42 +0200193
Kay Sievers00926992009-10-28 19:50:57 +0100194 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
Kay Sievers2b2af542009-04-30 15:23:42 +0200195 path_put(&nd.path);
196out:
197 kfree(tmp);
198 revert_creds(curr_cred);
199 return err;
200}
201
202static int dev_rmdir(const char *name)
203{
204 struct nameidata nd;
205 struct dentry *dentry;
206 int err;
207
208 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
209 name, LOOKUP_PARENT, &nd);
210 if (err)
211 return err;
212
213 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
214 dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
215 if (!IS_ERR(dentry)) {
216 if (dentry->d_inode)
217 err = vfs_rmdir(nd.path.dentry->d_inode, dentry);
218 else
219 err = -ENOENT;
220 dput(dentry);
221 } else {
222 err = PTR_ERR(dentry);
223 }
224 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
225
226 path_put(&nd.path);
227 return err;
228}
229
230static int delete_path(const char *nodepath)
231{
232 const char *path;
233 int err = 0;
234
235 path = kstrdup(nodepath, GFP_KERNEL);
236 if (!path)
237 return -ENOMEM;
238
Kay Sieversed413ae2009-10-28 19:51:06 +0100239 write_lock(&dirlock);
240 for (;;) {
Kay Sievers2b2af542009-04-30 15:23:42 +0200241 char *base;
242
243 base = strrchr(path, '/');
244 if (!base)
245 break;
246 base[0] = '\0';
247 err = dev_rmdir(path);
248 if (err)
249 break;
250 }
Kay Sieversed413ae2009-10-28 19:51:06 +0100251 write_unlock(&dirlock);
Kay Sievers2b2af542009-04-30 15:23:42 +0200252
253 kfree(path);
254 return err;
255}
256
257static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
258{
259 /* did we create it */
260 if (inode->i_private != &dev_mnt)
261 return 0;
262
263 /* does the dev_t match */
264 if (is_blockdev(dev)) {
265 if (!S_ISBLK(stat->mode))
266 return 0;
267 } else {
268 if (!S_ISCHR(stat->mode))
269 return 0;
270 }
271 if (stat->rdev != dev->devt)
272 return 0;
273
274 /* ours */
275 return 1;
276}
277
278int devtmpfs_delete_node(struct device *dev)
279{
280 const char *tmp = NULL;
281 const char *nodename;
282 const struct cred *curr_cred;
283 struct nameidata nd;
284 struct dentry *dentry;
285 struct kstat stat;
286 int deleted = 1;
287 int err;
288
289 if (!dev_mnt)
290 return 0;
291
Kay Sieverse454cea2009-09-18 23:01:12 +0200292 nodename = device_get_devnode(dev, NULL, &tmp);
Kay Sievers2b2af542009-04-30 15:23:42 +0200293 if (!nodename)
294 return -ENOMEM;
295
296 curr_cred = override_creds(&init_cred);
297 err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
298 nodename, LOOKUP_PARENT, &nd);
299 if (err)
300 goto out;
301
302 mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
303 dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
304 if (!IS_ERR(dentry)) {
305 if (dentry->d_inode) {
306 err = vfs_getattr(nd.path.mnt, dentry, &stat);
307 if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
308 err = vfs_unlink(nd.path.dentry->d_inode,
309 dentry);
310 if (!err || err == -ENOENT)
311 deleted = 1;
312 }
313 } else {
314 err = -ENOENT;
315 }
316 dput(dentry);
317 } else {
318 err = PTR_ERR(dentry);
319 }
320 mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
321
322 path_put(&nd.path);
323 if (deleted && strchr(nodename, '/'))
324 delete_path(nodename);
325out:
326 kfree(tmp);
327 revert_creds(curr_cred);
328 return err;
329}
330
331/*
332 * If configured, or requested by the commandline, devtmpfs will be
333 * auto-mounted after the kernel mounted the root filesystem.
334 */
Kay Sievers073120c2009-10-28 19:51:17 +0100335int devtmpfs_mount(const char *mntdir)
Kay Sievers2b2af542009-04-30 15:23:42 +0200336{
Kay Sievers2b2af542009-04-30 15:23:42 +0200337 int err;
338
339 if (!dev_mount)
340 return 0;
341
342 if (!dev_mnt)
343 return 0;
344
Kay Sievers073120c2009-10-28 19:51:17 +0100345 err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
Kay Sievers2b2af542009-04-30 15:23:42 +0200346 if (err)
347 printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
348 else
349 printk(KERN_INFO "devtmpfs: mounted\n");
Kay Sievers2b2af542009-04-30 15:23:42 +0200350 return err;
351}
352
353/*
354 * Create devtmpfs instance, driver-core devices will add their device
355 * nodes here.
356 */
357int __init devtmpfs_init(void)
358{
359 int err;
360 struct vfsmount *mnt;
361
Kay Sieversed413ae2009-10-28 19:51:06 +0100362 rwlock_init(&dirlock);
363
Kay Sievers2b2af542009-04-30 15:23:42 +0200364 err = register_filesystem(&dev_fs_type);
365 if (err) {
366 printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
367 "type %i\n", err);
368 return err;
369 }
370
371 mnt = kern_mount(&dev_fs_type);
372 if (IS_ERR(mnt)) {
373 err = PTR_ERR(mnt);
374 printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
375 unregister_filesystem(&dev_fs_type);
376 return err;
377 }
378 dev_mnt = mnt;
379
380 printk(KERN_INFO "devtmpfs: initialized\n");
381 return 0;
382}