12b2af54aSKay Sievers /* 22b2af54aSKay Sievers * devtmpfs - kernel-maintained tmpfs-based /dev 32b2af54aSKay Sievers * 42b2af54aSKay Sievers * Copyright (C) 2009, Kay Sievers <kay.sievers@vrfy.org> 52b2af54aSKay Sievers * 62b2af54aSKay Sievers * During bootup, before any driver core device is registered, 72b2af54aSKay Sievers * devtmpfs, a tmpfs-based filesystem is created. Every driver-core 82b2af54aSKay Sievers * device which requests a device node, will add a node in this 9e454cea2SKay Sievers * filesystem. 10e454cea2SKay Sievers * By default, all devices are named after the the name of the 11e454cea2SKay Sievers * device, owned by root and have a default mode of 0600. Subsystems 12e454cea2SKay Sievers * can overwrite the default setting if needed. 132b2af54aSKay Sievers */ 142b2af54aSKay Sievers 152b2af54aSKay Sievers #include <linux/kernel.h> 162b2af54aSKay Sievers #include <linux/syscalls.h> 172b2af54aSKay Sievers #include <linux/mount.h> 182b2af54aSKay Sievers #include <linux/device.h> 192b2af54aSKay Sievers #include <linux/genhd.h> 202b2af54aSKay Sievers #include <linux/namei.h> 212b2af54aSKay Sievers #include <linux/fs.h> 222b2af54aSKay Sievers #include <linux/shmem_fs.h> 232b2af54aSKay Sievers #include <linux/cred.h> 24e454cea2SKay Sievers #include <linux/sched.h> 252b2af54aSKay Sievers #include <linux/init_task.h> 265a0e3ad6STejun Heo #include <linux/slab.h> 272b2af54aSKay Sievers 282b2af54aSKay Sievers static struct vfsmount *dev_mnt; 292b2af54aSKay Sievers 302b2af54aSKay Sievers #if defined CONFIG_DEVTMPFS_MOUNT 312b2af54aSKay Sievers static int dev_mount = 1; 322b2af54aSKay Sievers #else 332b2af54aSKay Sievers static int dev_mount; 342b2af54aSKay Sievers #endif 352b2af54aSKay Sievers 36f1f76f86SThomas Gleixner static DEFINE_MUTEX(dirlock); 37ed413ae6SKay Sievers 382b2af54aSKay Sievers static int __init mount_param(char *str) 392b2af54aSKay Sievers { 402b2af54aSKay Sievers dev_mount = simple_strtoul(str, NULL, 0); 412b2af54aSKay Sievers return 1; 422b2af54aSKay Sievers } 432b2af54aSKay Sievers __setup("devtmpfs.mount=", mount_param); 442b2af54aSKay Sievers 452b2af54aSKay Sievers static int dev_get_sb(struct file_system_type *fs_type, int flags, 462b2af54aSKay Sievers const char *dev_name, void *data, struct vfsmount *mnt) 472b2af54aSKay Sievers { 482b2af54aSKay Sievers return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt); 492b2af54aSKay Sievers } 502b2af54aSKay Sievers 512b2af54aSKay Sievers static struct file_system_type dev_fs_type = { 522b2af54aSKay Sievers .name = "devtmpfs", 532b2af54aSKay Sievers .get_sb = dev_get_sb, 542b2af54aSKay Sievers .kill_sb = kill_litter_super, 552b2af54aSKay Sievers }; 562b2af54aSKay Sievers 572b2af54aSKay Sievers #ifdef CONFIG_BLOCK 582b2af54aSKay Sievers static inline int is_blockdev(struct device *dev) 592b2af54aSKay Sievers { 602b2af54aSKay Sievers return dev->class == &block_class; 612b2af54aSKay Sievers } 622b2af54aSKay Sievers #else 632b2af54aSKay Sievers static inline int is_blockdev(struct device *dev) { return 0; } 642b2af54aSKay Sievers #endif 652b2af54aSKay Sievers 662b2af54aSKay Sievers static int dev_mkdir(const char *name, mode_t mode) 672b2af54aSKay Sievers { 682b2af54aSKay Sievers struct nameidata nd; 692b2af54aSKay Sievers struct dentry *dentry; 702b2af54aSKay Sievers int err; 712b2af54aSKay Sievers 722b2af54aSKay Sievers err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, 732b2af54aSKay Sievers name, LOOKUP_PARENT, &nd); 742b2af54aSKay Sievers if (err) 752b2af54aSKay Sievers return err; 762b2af54aSKay Sievers 772b2af54aSKay Sievers dentry = lookup_create(&nd, 1); 782b2af54aSKay Sievers if (!IS_ERR(dentry)) { 792b2af54aSKay Sievers err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); 80015bf43bSKay Sievers if (!err) 81015bf43bSKay Sievers /* mark as kernel-created inode */ 82015bf43bSKay Sievers dentry->d_inode->i_private = &dev_mnt; 832b2af54aSKay Sievers dput(dentry); 842b2af54aSKay Sievers } else { 852b2af54aSKay Sievers err = PTR_ERR(dentry); 862b2af54aSKay Sievers } 872b2af54aSKay Sievers 88015bf43bSKay Sievers mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 892b2af54aSKay Sievers path_put(&nd.path); 902b2af54aSKay Sievers return err; 912b2af54aSKay Sievers } 922b2af54aSKay Sievers 932b2af54aSKay Sievers static int create_path(const char *nodepath) 942b2af54aSKay Sievers { 95015bf43bSKay Sievers int err; 962b2af54aSKay Sievers 97f1f76f86SThomas Gleixner mutex_lock(&dirlock); 98015bf43bSKay Sievers err = dev_mkdir(nodepath, 0755); 99015bf43bSKay Sievers if (err == -ENOENT) { 100ed413ae6SKay Sievers char *path; 1012b2af54aSKay Sievers char *s; 1022b2af54aSKay Sievers 1032b2af54aSKay Sievers /* parent directories do not exist, create them */ 104ed413ae6SKay Sievers path = kstrdup(nodepath, GFP_KERNEL); 10580422738SKay Sievers if (!path) { 10680422738SKay Sievers err = -ENOMEM; 10780422738SKay Sievers goto out; 10880422738SKay Sievers } 1092b2af54aSKay Sievers s = path; 110ed413ae6SKay Sievers for (;;) { 1112b2af54aSKay Sievers s = strchr(s, '/'); 1122b2af54aSKay Sievers if (!s) 1132b2af54aSKay Sievers break; 1142b2af54aSKay Sievers s[0] = '\0'; 1152b2af54aSKay Sievers err = dev_mkdir(path, 0755); 1162b2af54aSKay Sievers if (err && err != -EEXIST) 1172b2af54aSKay Sievers break; 1182b2af54aSKay Sievers s[0] = '/'; 1192b2af54aSKay Sievers s++; 1202b2af54aSKay Sievers } 1212b2af54aSKay Sievers kfree(path); 122ed413ae6SKay Sievers } 12380422738SKay Sievers out: 124f1f76f86SThomas Gleixner mutex_unlock(&dirlock); 1252b2af54aSKay Sievers return err; 1262b2af54aSKay Sievers } 1272b2af54aSKay Sievers 1282b2af54aSKay Sievers int devtmpfs_create_node(struct device *dev) 1292b2af54aSKay Sievers { 1302b2af54aSKay Sievers const char *tmp = NULL; 1312b2af54aSKay Sievers const char *nodename; 1322b2af54aSKay Sievers const struct cred *curr_cred; 133e454cea2SKay Sievers mode_t mode = 0; 1342b2af54aSKay Sievers struct nameidata nd; 1352b2af54aSKay Sievers struct dentry *dentry; 1362b2af54aSKay Sievers int err; 1372b2af54aSKay Sievers 1382b2af54aSKay Sievers if (!dev_mnt) 1392b2af54aSKay Sievers return 0; 1402b2af54aSKay Sievers 141e454cea2SKay Sievers nodename = device_get_devnode(dev, &mode, &tmp); 1422b2af54aSKay Sievers if (!nodename) 1432b2af54aSKay Sievers return -ENOMEM; 1442b2af54aSKay Sievers 145e454cea2SKay Sievers if (mode == 0) 146e454cea2SKay Sievers mode = 0600; 1472b2af54aSKay Sievers if (is_blockdev(dev)) 148e454cea2SKay Sievers mode |= S_IFBLK; 1492b2af54aSKay Sievers else 150e454cea2SKay Sievers mode |= S_IFCHR; 1512b2af54aSKay Sievers 1522b2af54aSKay Sievers curr_cred = override_creds(&init_cred); 15300926996SKay Sievers 1542b2af54aSKay Sievers err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, 1552b2af54aSKay Sievers nodename, LOOKUP_PARENT, &nd); 1562b2af54aSKay Sievers if (err == -ENOENT) { 1572b2af54aSKay Sievers create_path(nodename); 1582b2af54aSKay Sievers err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, 1592b2af54aSKay Sievers nodename, LOOKUP_PARENT, &nd); 16000926996SKay Sievers } 1612b2af54aSKay Sievers if (err) 1622b2af54aSKay Sievers goto out; 1632b2af54aSKay Sievers 1642b2af54aSKay Sievers dentry = lookup_create(&nd, 0); 1652b2af54aSKay Sievers if (!IS_ERR(dentry)) { 1662b2af54aSKay Sievers err = vfs_mknod(nd.path.dentry->d_inode, 1672b2af54aSKay Sievers dentry, mode, dev->devt); 16800926996SKay Sievers if (!err) { 16900926996SKay Sievers struct iattr newattrs; 17000926996SKay Sievers 17100926996SKay Sievers /* fixup possibly umasked mode */ 17200926996SKay Sievers newattrs.ia_mode = mode; 17300926996SKay Sievers newattrs.ia_valid = ATTR_MODE; 17400926996SKay Sievers mutex_lock(&dentry->d_inode->i_mutex); 17500926996SKay Sievers notify_change(dentry, &newattrs); 17600926996SKay Sievers mutex_unlock(&dentry->d_inode->i_mutex); 17700926996SKay Sievers 17800926996SKay Sievers /* mark as kernel-created inode */ 1792b2af54aSKay Sievers dentry->d_inode->i_private = &dev_mnt; 18000926996SKay Sievers } 1812b2af54aSKay Sievers dput(dentry); 1822b2af54aSKay Sievers } else { 1832b2af54aSKay Sievers err = PTR_ERR(dentry); 1842b2af54aSKay Sievers } 1852b2af54aSKay Sievers 18600926996SKay Sievers mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 1872b2af54aSKay Sievers path_put(&nd.path); 1882b2af54aSKay Sievers out: 1892b2af54aSKay Sievers kfree(tmp); 1902b2af54aSKay Sievers revert_creds(curr_cred); 1912b2af54aSKay Sievers return err; 1922b2af54aSKay Sievers } 1932b2af54aSKay Sievers 1942b2af54aSKay Sievers static int dev_rmdir(const char *name) 1952b2af54aSKay Sievers { 1962b2af54aSKay Sievers struct nameidata nd; 1972b2af54aSKay Sievers struct dentry *dentry; 1982b2af54aSKay Sievers int err; 1992b2af54aSKay Sievers 2002b2af54aSKay Sievers err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, 2012b2af54aSKay Sievers name, LOOKUP_PARENT, &nd); 2022b2af54aSKay Sievers if (err) 2032b2af54aSKay Sievers return err; 2042b2af54aSKay Sievers 2052b2af54aSKay Sievers mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); 2062b2af54aSKay Sievers dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); 2072b2af54aSKay Sievers if (!IS_ERR(dentry)) { 208015bf43bSKay Sievers if (dentry->d_inode) { 209015bf43bSKay Sievers if (dentry->d_inode->i_private == &dev_mnt) 210015bf43bSKay Sievers err = vfs_rmdir(nd.path.dentry->d_inode, 211015bf43bSKay Sievers dentry); 2122b2af54aSKay Sievers else 213015bf43bSKay Sievers err = -EPERM; 214015bf43bSKay Sievers } else { 2152b2af54aSKay Sievers err = -ENOENT; 216015bf43bSKay Sievers } 2172b2af54aSKay Sievers dput(dentry); 2182b2af54aSKay Sievers } else { 2192b2af54aSKay Sievers err = PTR_ERR(dentry); 2202b2af54aSKay Sievers } 2212b2af54aSKay Sievers 222015bf43bSKay Sievers mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 2232b2af54aSKay Sievers path_put(&nd.path); 2242b2af54aSKay Sievers return err; 2252b2af54aSKay Sievers } 2262b2af54aSKay Sievers 2272b2af54aSKay Sievers static int delete_path(const char *nodepath) 2282b2af54aSKay Sievers { 2292b2af54aSKay Sievers const char *path; 2302b2af54aSKay Sievers int err = 0; 2312b2af54aSKay Sievers 2322b2af54aSKay Sievers path = kstrdup(nodepath, GFP_KERNEL); 2332b2af54aSKay Sievers if (!path) 2342b2af54aSKay Sievers return -ENOMEM; 2352b2af54aSKay Sievers 236f1f76f86SThomas Gleixner mutex_lock(&dirlock); 237ed413ae6SKay Sievers for (;;) { 2382b2af54aSKay Sievers char *base; 2392b2af54aSKay Sievers 2402b2af54aSKay Sievers base = strrchr(path, '/'); 2412b2af54aSKay Sievers if (!base) 2422b2af54aSKay Sievers break; 2432b2af54aSKay Sievers base[0] = '\0'; 2442b2af54aSKay Sievers err = dev_rmdir(path); 2452b2af54aSKay Sievers if (err) 2462b2af54aSKay Sievers break; 2472b2af54aSKay Sievers } 248f1f76f86SThomas Gleixner mutex_unlock(&dirlock); 2492b2af54aSKay Sievers 2502b2af54aSKay Sievers kfree(path); 2512b2af54aSKay Sievers return err; 2522b2af54aSKay Sievers } 2532b2af54aSKay Sievers 2542b2af54aSKay Sievers static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat) 2552b2af54aSKay Sievers { 2562b2af54aSKay Sievers /* did we create it */ 2572b2af54aSKay Sievers if (inode->i_private != &dev_mnt) 2582b2af54aSKay Sievers return 0; 2592b2af54aSKay Sievers 2602b2af54aSKay Sievers /* does the dev_t match */ 2612b2af54aSKay Sievers if (is_blockdev(dev)) { 2622b2af54aSKay Sievers if (!S_ISBLK(stat->mode)) 2632b2af54aSKay Sievers return 0; 2642b2af54aSKay Sievers } else { 2652b2af54aSKay Sievers if (!S_ISCHR(stat->mode)) 2662b2af54aSKay Sievers return 0; 2672b2af54aSKay Sievers } 2682b2af54aSKay Sievers if (stat->rdev != dev->devt) 2692b2af54aSKay Sievers return 0; 2702b2af54aSKay Sievers 2712b2af54aSKay Sievers /* ours */ 2722b2af54aSKay Sievers return 1; 2732b2af54aSKay Sievers } 2742b2af54aSKay Sievers 2752b2af54aSKay Sievers int devtmpfs_delete_node(struct device *dev) 2762b2af54aSKay Sievers { 2772b2af54aSKay Sievers const char *tmp = NULL; 2782b2af54aSKay Sievers const char *nodename; 2792b2af54aSKay Sievers const struct cred *curr_cred; 2802b2af54aSKay Sievers struct nameidata nd; 2812b2af54aSKay Sievers struct dentry *dentry; 2822b2af54aSKay Sievers struct kstat stat; 2832b2af54aSKay Sievers int deleted = 1; 2842b2af54aSKay Sievers int err; 2852b2af54aSKay Sievers 2862b2af54aSKay Sievers if (!dev_mnt) 2872b2af54aSKay Sievers return 0; 2882b2af54aSKay Sievers 289e454cea2SKay Sievers nodename = device_get_devnode(dev, NULL, &tmp); 2902b2af54aSKay Sievers if (!nodename) 2912b2af54aSKay Sievers return -ENOMEM; 2922b2af54aSKay Sievers 2932b2af54aSKay Sievers curr_cred = override_creds(&init_cred); 2942b2af54aSKay Sievers err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, 2952b2af54aSKay Sievers nodename, LOOKUP_PARENT, &nd); 2962b2af54aSKay Sievers if (err) 2972b2af54aSKay Sievers goto out; 2982b2af54aSKay Sievers 2992b2af54aSKay Sievers mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); 3002b2af54aSKay Sievers dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); 3012b2af54aSKay Sievers if (!IS_ERR(dentry)) { 3022b2af54aSKay Sievers if (dentry->d_inode) { 3032b2af54aSKay Sievers err = vfs_getattr(nd.path.mnt, dentry, &stat); 3042b2af54aSKay Sievers if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { 3055e31d76fSKay Sievers struct iattr newattrs; 3065e31d76fSKay Sievers /* 3075e31d76fSKay Sievers * before unlinking this node, reset permissions 3085e31d76fSKay Sievers * of possible references like hardlinks 3095e31d76fSKay Sievers */ 3105e31d76fSKay Sievers newattrs.ia_uid = 0; 3115e31d76fSKay Sievers newattrs.ia_gid = 0; 3125e31d76fSKay Sievers newattrs.ia_mode = stat.mode & ~0777; 3135e31d76fSKay Sievers newattrs.ia_valid = 3145e31d76fSKay Sievers ATTR_UID|ATTR_GID|ATTR_MODE; 3155e31d76fSKay Sievers mutex_lock(&dentry->d_inode->i_mutex); 3165e31d76fSKay Sievers notify_change(dentry, &newattrs); 3175e31d76fSKay Sievers mutex_unlock(&dentry->d_inode->i_mutex); 3182b2af54aSKay Sievers err = vfs_unlink(nd.path.dentry->d_inode, 3192b2af54aSKay Sievers dentry); 3202b2af54aSKay Sievers if (!err || err == -ENOENT) 3212b2af54aSKay Sievers deleted = 1; 3222b2af54aSKay Sievers } 3232b2af54aSKay Sievers } else { 3242b2af54aSKay Sievers err = -ENOENT; 3252b2af54aSKay Sievers } 3262b2af54aSKay Sievers dput(dentry); 3272b2af54aSKay Sievers } else { 3282b2af54aSKay Sievers err = PTR_ERR(dentry); 3292b2af54aSKay Sievers } 3302b2af54aSKay Sievers mutex_unlock(&nd.path.dentry->d_inode->i_mutex); 3312b2af54aSKay Sievers 3322b2af54aSKay Sievers path_put(&nd.path); 3332b2af54aSKay Sievers if (deleted && strchr(nodename, '/')) 3342b2af54aSKay Sievers delete_path(nodename); 3352b2af54aSKay Sievers out: 3362b2af54aSKay Sievers kfree(tmp); 3372b2af54aSKay Sievers revert_creds(curr_cred); 3382b2af54aSKay Sievers return err; 3392b2af54aSKay Sievers } 3402b2af54aSKay Sievers 3412b2af54aSKay Sievers /* 3422b2af54aSKay Sievers * If configured, or requested by the commandline, devtmpfs will be 3432b2af54aSKay Sievers * auto-mounted after the kernel mounted the root filesystem. 3442b2af54aSKay Sievers */ 345073120ccSKay Sievers int devtmpfs_mount(const char *mntdir) 3462b2af54aSKay Sievers { 3472b2af54aSKay Sievers int err; 3482b2af54aSKay Sievers 3492b2af54aSKay Sievers if (!dev_mount) 3502b2af54aSKay Sievers return 0; 3512b2af54aSKay Sievers 3522b2af54aSKay Sievers if (!dev_mnt) 3532b2af54aSKay Sievers return 0; 3542b2af54aSKay Sievers 355073120ccSKay Sievers err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL); 3562b2af54aSKay Sievers if (err) 3572b2af54aSKay Sievers printk(KERN_INFO "devtmpfs: error mounting %i\n", err); 3582b2af54aSKay Sievers else 3592b2af54aSKay Sievers printk(KERN_INFO "devtmpfs: mounted\n"); 3602b2af54aSKay Sievers return err; 3612b2af54aSKay Sievers } 3622b2af54aSKay Sievers 3632b2af54aSKay Sievers /* 3642b2af54aSKay Sievers * Create devtmpfs instance, driver-core devices will add their device 3652b2af54aSKay Sievers * nodes here. 3662b2af54aSKay Sievers */ 3672b2af54aSKay Sievers int __init devtmpfs_init(void) 3682b2af54aSKay Sievers { 3692b2af54aSKay Sievers int err; 3702b2af54aSKay Sievers struct vfsmount *mnt; 371f776c5ecSHeiko Carstens char options[] = "mode=0755"; 3722b2af54aSKay Sievers 3732b2af54aSKay Sievers err = register_filesystem(&dev_fs_type); 3742b2af54aSKay Sievers if (err) { 3752b2af54aSKay Sievers printk(KERN_ERR "devtmpfs: unable to register devtmpfs " 3762b2af54aSKay Sievers "type %i\n", err); 3772b2af54aSKay Sievers return err; 3782b2af54aSKay Sievers } 3792b2af54aSKay Sievers 380f776c5ecSHeiko Carstens mnt = kern_mount_data(&dev_fs_type, options); 3812b2af54aSKay Sievers if (IS_ERR(mnt)) { 3822b2af54aSKay Sievers err = PTR_ERR(mnt); 3832b2af54aSKay Sievers printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); 3842b2af54aSKay Sievers unregister_filesystem(&dev_fs_type); 3852b2af54aSKay Sievers return err; 3862b2af54aSKay Sievers } 3872b2af54aSKay Sievers dev_mnt = mnt; 3882b2af54aSKay Sievers 3892b2af54aSKay Sievers printk(KERN_INFO "devtmpfs: initialized\n"); 3902b2af54aSKay Sievers return 0; 3912b2af54aSKay Sievers } 392