summaryrefslogtreecommitdiff
path: root/drivers/base/devtmpfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/devtmpfs.c')
-rw-r--r--drivers/base/devtmpfs.c102
1 files changed, 52 insertions, 50 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index a1cb5afe6801..42ae452b36b0 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);