diff options
Diffstat (limited to 'drivers/base/devtmpfs.c')
| -rw-r--r-- | drivers/base/devtmpfs.c | 100 | 
1 files changed, 50 insertions, 50 deletions
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index a1cb5afe6801..50375bb8e51d 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 rwlock_t dirlock; +  static int __init mount_param(char *str)  {  	dev_mount = simple_strtoul(str, NULL, 0); @@ -74,47 +76,35 @@ 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) { +	read_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) +			return -ENOMEM;  		s = path; -		while (1) { +		for (;;) {  			s = strchr(s, '/');  			if (!s)  				break; @@ -125,9 +115,9 @@ static int create_path(const char *nodepath)  			s[0] = '/';  			s++;  		} +		kfree(path);  	} - -	kfree(path); +	read_unlock(&dirlock);  	return err;  } @@ -156,34 +146,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 +201,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 +229,8 @@ static int delete_path(const char *nodepath)  	if (!path)  		return -ENOMEM; -	while (1) { +	write_lock(&dirlock); +	for (;;) {  		char *base;  		base = strrchr(path, '/'); @@ -239,6 +241,7 @@ static int delete_path(const char *nodepath)  		if (err)  			break;  	} +	write_unlock(&dirlock);  	kfree(path);  	return err; @@ -322,9 +325,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 +335,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;  } @@ -354,6 +352,8 @@ int __init devtmpfs_init(void)  	int err;  	struct vfsmount *mnt; +	rwlock_init(&dirlock); +  	err = register_filesystem(&dev_fs_type);  	if (err) {  		printk(KERN_ERR "devtmpfs: unable to register devtmpfs " @@ -361,7 +361,7 @@ int __init devtmpfs_init(void)  		return err;  	} -	mnt = kern_mount(&dev_fs_type); +	mnt = kern_mount_data(&dev_fs_type, "mode=0755");  	if (IS_ERR(mnt)) {  		err = PTR_ERR(mnt);  		printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err);  | 
