devtmpfs.c revision 2b2af54a5bb6f7e80ccf78f20084b93c398c3a8b
12b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers/*
22b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * devtmpfs - kernel-maintained tmpfs-based /dev
32b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers *
42b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * Copyright (C) 2009, Kay Sievers <kay.sievers@vrfy.org>
52b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers *
62b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * During bootup, before any driver core device is registered,
72b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * devtmpfs, a tmpfs-based filesystem is created. Every driver-core
82b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * device which requests a device node, will add a node in this
92b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * filesystem. The node is named after the the name of the device,
102b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * or the susbsytem can provide a custom name. All devices are
112b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * owned by root and have a mode of 0600.
122b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers */
132b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
142b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/kernel.h>
152b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/syscalls.h>
162b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/mount.h>
172b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/device.h>
182b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/genhd.h>
192b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/namei.h>
202b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/fs.h>
212b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/shmem_fs.h>
222b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/cred.h>
232b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#include <linux/init_task.h>
242b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
252b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic struct vfsmount *dev_mnt;
262b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
272b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#if defined CONFIG_DEVTMPFS_MOUNT
282b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int dev_mount = 1;
292b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#else
302b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int dev_mount;
312b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#endif
322b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
332b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int __init mount_param(char *str)
342b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
352b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	dev_mount = simple_strtoul(str, NULL, 0);
362b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return 1;
372b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
382b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers__setup("devtmpfs.mount=", mount_param);
392b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
402b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int dev_get_sb(struct file_system_type *fs_type, int flags,
412b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		      const char *dev_name, void *data, struct vfsmount *mnt)
422b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
432b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt);
442b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
452b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
462b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic struct file_system_type dev_fs_type = {
472b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	.name = "devtmpfs",
482b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	.get_sb = dev_get_sb,
492b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	.kill_sb = kill_litter_super,
502b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers};
512b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
522b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#ifdef CONFIG_BLOCK
532b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic inline int is_blockdev(struct device *dev)
542b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
552b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return dev->class == &block_class;
562b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
572b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#else
582b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic inline int is_blockdev(struct device *dev) { return 0; }
592b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers#endif
602b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
612b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int dev_mkdir(const char *name, mode_t mode)
622b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
632b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct nameidata nd;
642b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct dentry *dentry;
652b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int err;
662b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
672b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
682b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			      name, LOOKUP_PARENT, &nd);
692b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (err)
702b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return err;
712b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
722b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	dentry = lookup_create(&nd, 1);
732b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!IS_ERR(dentry)) {
742b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode);
752b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		dput(dentry);
762b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	} else {
772b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = PTR_ERR(dentry);
782b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
792b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
802b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
812b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	path_put(&nd.path);
822b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return err;
832b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
842b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
852b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int create_path(const char *nodepath)
862b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
872b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	char *path;
882b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct nameidata nd;
892b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int err = 0;
902b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
912b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	path = kstrdup(nodepath, GFP_KERNEL);
922b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!path)
932b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return -ENOMEM;
942b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
952b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
962b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			      path, LOOKUP_PARENT, &nd);
972b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (err == 0) {
982b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		struct dentry *dentry;
992b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1002b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		/* create directory right away */
1012b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		dentry = lookup_create(&nd, 1);
1022b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (!IS_ERR(dentry)) {
1032b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			err = vfs_mkdir(nd.path.dentry->d_inode,
1042b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers					dentry, 0755);
1052b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			dput(dentry);
1062b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		}
1072b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
1082b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1092b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		path_put(&nd.path);
1102b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	} else if (err == -ENOENT) {
1112b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		char *s;
1122b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1132b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		/* parent directories do not exist, create them */
1142b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		s = path;
1152b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		while (1) {
1162b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			s = strchr(s, '/');
1172b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			if (!s)
1182b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers				break;
1192b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			s[0] = '\0';
1202b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			err = dev_mkdir(path, 0755);
1212b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			if (err && err != -EEXIST)
1222b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers				break;
1232b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			s[0] = '/';
1242b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			s++;
1252b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		}
1262b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
1272b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1282b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	kfree(path);
1292b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return err;
1302b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
1312b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1322b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversint devtmpfs_create_node(struct device *dev)
1332b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
1342b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	const char *tmp = NULL;
1352b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	const char *nodename;
1362b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	const struct cred *curr_cred;
1372b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	mode_t mode;
1382b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct nameidata nd;
1392b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct dentry *dentry;
1402b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int err;
1412b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1422b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!dev_mnt)
1432b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return 0;
1442b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1452b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	nodename = device_get_nodename(dev, &tmp);
1462b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!nodename)
1472b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return -ENOMEM;
1482b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1492b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (is_blockdev(dev))
1502b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		mode = S_IFBLK|0600;
1512b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	else
1522b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		mode = S_IFCHR|0600;
1532b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1542b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	curr_cred = override_creds(&init_cred);
1552b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
1562b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			      nodename, LOOKUP_PARENT, &nd);
1572b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (err == -ENOENT) {
1582b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		/* create missing parent directories */
1592b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		create_path(nodename);
1602b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
1612b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers				      nodename, LOOKUP_PARENT, &nd);
1622b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (err)
1632b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			goto out;
1642b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
1652b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1662b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	dentry = lookup_create(&nd, 0);
1672b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!IS_ERR(dentry)) {
1682b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = vfs_mknod(nd.path.dentry->d_inode,
1692b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers				dentry, mode, dev->devt);
1702b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		/* mark as kernel created inode */
1712b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (!err)
1722b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			dentry->d_inode->i_private = &dev_mnt;
1732b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		dput(dentry);
1742b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	} else {
1752b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = PTR_ERR(dentry);
1762b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
1772b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
1782b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1792b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	path_put(&nd.path);
1802b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversout:
1812b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	kfree(tmp);
1822b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	revert_creds(curr_cred);
1832b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return err;
1842b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
1852b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1862b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int dev_rmdir(const char *name)
1872b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
1882b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct nameidata nd;
1892b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct dentry *dentry;
1902b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int err;
1912b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1922b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
1932b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			      name, LOOKUP_PARENT, &nd);
1942b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (err)
1952b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return err;
1962b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
1972b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
1982b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
1992b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!IS_ERR(dentry)) {
2002b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (dentry->d_inode)
2012b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			err = vfs_rmdir(nd.path.dentry->d_inode, dentry);
2022b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		else
2032b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			err = -ENOENT;
2042b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		dput(dentry);
2052b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	} else {
2062b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = PTR_ERR(dentry);
2072b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
2082b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
2092b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2102b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	path_put(&nd.path);
2112b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return err;
2122b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
2132b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2142b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int delete_path(const char *nodepath)
2152b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
2162b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	const char *path;
2172b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int err = 0;
2182b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2192b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	path = kstrdup(nodepath, GFP_KERNEL);
2202b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!path)
2212b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return -ENOMEM;
2222b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2232b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	while (1) {
2242b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		char *base;
2252b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2262b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		base = strrchr(path, '/');
2272b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (!base)
2282b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			break;
2292b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		base[0] = '\0';
2302b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = dev_rmdir(path);
2312b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (err)
2322b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			break;
2332b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
2342b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2352b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	kfree(path);
2362b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return err;
2372b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
2382b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2392b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversstatic int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat)
2402b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
2412b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	/* did we create it */
2422b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (inode->i_private != &dev_mnt)
2432b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return 0;
2442b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2452b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	/* does the dev_t match */
2462b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (is_blockdev(dev)) {
2472b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (!S_ISBLK(stat->mode))
2482b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			return 0;
2492b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	} else {
2502b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (!S_ISCHR(stat->mode))
2512b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			return 0;
2522b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
2532b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (stat->rdev != dev->devt)
2542b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return 0;
2552b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2562b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	/* ours */
2572b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return 1;
2582b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
2592b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2602b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversint devtmpfs_delete_node(struct device *dev)
2612b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
2622b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	const char *tmp = NULL;
2632b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	const char *nodename;
2642b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	const struct cred *curr_cred;
2652b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct nameidata nd;
2662b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct dentry *dentry;
2672b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct kstat stat;
2682b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int deleted = 1;
2692b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int err;
2702b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2712b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!dev_mnt)
2722b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return 0;
2732b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2742b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	nodename = device_get_nodename(dev, &tmp);
2752b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!nodename)
2762b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return -ENOMEM;
2772b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2782b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	curr_cred = override_creds(&init_cred);
2792b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt,
2802b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			      nodename, LOOKUP_PARENT, &nd);
2812b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (err)
2822b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		goto out;
2832b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
2842b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
2852b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
2862b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!IS_ERR(dentry)) {
2872b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		if (dentry->d_inode) {
2882b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			err = vfs_getattr(nd.path.mnt, dentry, &stat);
2892b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			if (!err && dev_mynode(dev, dentry->d_inode, &stat)) {
2902b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers				err = vfs_unlink(nd.path.dentry->d_inode,
2912b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers						 dentry);
2922b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers				if (!err || err == -ENOENT)
2932b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers					deleted = 1;
2942b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			}
2952b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		} else {
2962b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers			err = -ENOENT;
2972b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		}
2982b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		dput(dentry);
2992b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	} else {
3002b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = PTR_ERR(dentry);
3012b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
3022b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
3032b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3042b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	path_put(&nd.path);
3052b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (deleted && strchr(nodename, '/'))
3062b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		delete_path(nodename);
3072b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversout:
3082b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	kfree(tmp);
3092b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	revert_creds(curr_cred);
3102b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return err;
3112b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
3122b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3132b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers/*
3142b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * If configured, or requested by the commandline, devtmpfs will be
3152b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * auto-mounted after the kernel mounted the root filesystem.
3162b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers */
3172b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversint devtmpfs_mount(const char *mountpoint)
3182b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
3192b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct path path;
3202b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int err;
3212b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3222b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!dev_mount)
3232b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return 0;
3242b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3252b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (!dev_mnt)
3262b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return 0;
3272b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3282b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	err = kern_path(mountpoint, LOOKUP_FOLLOW, &path);
3292b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (err)
3302b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return err;
3312b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	err = do_add_mount(dev_mnt, &path, 0, NULL);
3322b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (err)
3332b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
3342b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	else
3352b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		printk(KERN_INFO "devtmpfs: mounted\n");
3362b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	path_put(&path);
3372b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return err;
3382b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
3392b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3402b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers/*
3412b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * Create devtmpfs instance, driver-core devices will add their device
3422b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers * nodes here.
3432b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers */
3442b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sieversint __init devtmpfs_init(void)
3452b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers{
3462b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	int err;
3472b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	struct vfsmount *mnt;
3482b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3492b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	err = register_filesystem(&dev_fs_type);
3502b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (err) {
3512b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
3522b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		       "type %i\n", err);
3532b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return err;
3542b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
3552b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3562b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	mnt = kern_mount(&dev_fs_type);
3572b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	if (IS_ERR(mnt)) {
3582b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		err = PTR_ERR(mnt);
3592b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);
3602b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		unregister_filesystem(&dev_fs_type);
3612b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers		return err;
3622b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	}
3632b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	dev_mnt = mnt;
3642b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers
3652b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	printk(KERN_INFO "devtmpfs: initialized\n");
3662b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers	return 0;
3672b2af54a5bb6f7e80ccf78f20084b93c398c3a8bKay Sievers}
368