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