diff options
Diffstat (limited to 'drivers/base/devtmpfs.c')
-rw-r--r-- | drivers/base/devtmpfs.c | 102 |
1 files changed, 52 insertions, 50 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index a1cb5afe680..42ae452b36b 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -32,6 +32,8 @@ static int dev_mount = 1; static int dev_mount; #endif +static DEFINE_MUTEX(dirlock); + static int __init mount_param(char *str) { dev_mount = simple_strtoul(str, NULL, 0); @@ -74,47 +76,37 @@ static int dev_mkdir(const char *name, mode_t mode) dentry = lookup_create(&nd, 1); if (!IS_ERR(dentry)) { err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); + if (!err) + /* mark as kernel-created inode */ + dentry->d_inode->i_private = &dev_mnt; dput(dentry); } else { err = PTR_ERR(dentry); } - mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); return err; } static int create_path(const char *nodepath) { - char *path; - struct nameidata nd; - int err = 0; - - path = kstrdup(nodepath, GFP_KERNEL); - if (!path) - return -ENOMEM; - - err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, - path, LOOKUP_PARENT, &nd); - if (err == 0) { - struct dentry *dentry; - - /* create directory right away */ - dentry = lookup_create(&nd, 1); - if (!IS_ERR(dentry)) { - err = vfs_mkdir(nd.path.dentry->d_inode, - dentry, 0755); - dput(dentry); - } - mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + int err; - path_put(&nd.path); - } else if (err == -ENOENT) { + mutex_lock(&dirlock); + err = dev_mkdir(nodepath, 0755); + if (err == -ENOENT) { + char *path; char *s; /* parent directories do not exist, create them */ + path = kstrdup(nodepath, GFP_KERNEL); + if (!path) { + err = -ENOMEM; + goto out; + } s = path; - while (1) { + for (;;) { s = strchr(s, '/'); if (!s) break; @@ -125,9 +117,10 @@ static int create_path(const char *nodepath) s[0] = '/'; s++; } + kfree(path); } - - kfree(path); +out: + mutex_unlock(&dirlock); return err; } @@ -156,34 +149,40 @@ int devtmpfs_create_node(struct device *dev) mode |= S_IFCHR; curr_cred = override_creds(&init_cred); + err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); if (err == -ENOENT) { - /* create missing parent directories */ create_path(nodename); err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, nodename, LOOKUP_PARENT, &nd); - if (err) - goto out; } + if (err) + goto out; dentry = lookup_create(&nd, 0); if (!IS_ERR(dentry)) { - int umask; - - umask = sys_umask(0000); err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, dev->devt); - sys_umask(umask); - /* mark as kernel created inode */ - if (!err) + if (!err) { + struct iattr newattrs; + + /* fixup possibly umasked mode */ + newattrs.ia_mode = mode; + newattrs.ia_valid = ATTR_MODE; + mutex_lock(&dentry->d_inode->i_mutex); + notify_change(dentry, &newattrs); + mutex_unlock(&dentry->d_inode->i_mutex); + + /* mark as kernel-created inode */ dentry->d_inode->i_private = &dev_mnt; + } dput(dentry); } else { err = PTR_ERR(dentry); } - mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); out: kfree(tmp); @@ -205,16 +204,21 @@ static int dev_rmdir(const char *name) mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); if (!IS_ERR(dentry)) { - if (dentry->d_inode) - err = vfs_rmdir(nd.path.dentry->d_inode, dentry); - else + if (dentry->d_inode) { + if (dentry->d_inode->i_private == &dev_mnt) + err = vfs_rmdir(nd.path.dentry->d_inode, + dentry); + else + err = -EPERM; + } else { err = -ENOENT; + } dput(dentry); } else { err = PTR_ERR(dentry); } - mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); return err; } @@ -228,7 +232,8 @@ static int delete_path(const char *nodepath) if (!path) return -ENOMEM; - while (1) { + mutex_lock(&dirlock); + for (;;) { char *base; base = strrchr(path, '/'); @@ -239,6 +244,7 @@ static int delete_path(const char *nodepath) if (err) break; } + mutex_unlock(&dirlock); kfree(path); return err; @@ -322,9 +328,8 @@ out: * If configured, or requested by the commandline, devtmpfs will be * auto-mounted after the kernel mounted the root filesystem. */ -int devtmpfs_mount(const char *mountpoint) +int devtmpfs_mount(const char *mntdir) { - struct path path; int err; if (!dev_mount) @@ -333,15 +338,11 @@ int devtmpfs_mount(const char *mountpoint) if (!dev_mnt) return 0; - err = kern_path(mountpoint, LOOKUP_FOLLOW, &path); - if (err) - return err; - err = do_add_mount(dev_mnt, &path, 0, NULL); + err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL); if (err) printk(KERN_INFO "devtmpfs: error mounting %i\n", err); else printk(KERN_INFO "devtmpfs: mounted\n"); - path_put(&path); return err; } @@ -353,6 +354,7 @@ int __init devtmpfs_init(void) { int err; struct vfsmount *mnt; + char options[] = "mode=0755"; err = register_filesystem(&dev_fs_type); if (err) { @@ -361,7 +363,7 @@ int __init devtmpfs_init(void) return err; } - mnt = kern_mount(&dev_fs_type); + mnt = kern_mount_data(&dev_fs_type, options); if (IS_ERR(mnt)) { err = PTR_ERR(mnt); printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); |