diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2012-06-15 03:01:42 +0400 | 
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-14 16:35:02 +0400 | 
| commit | 79714f72d3b964611997de512cb29198c9f2dbbb (patch) | |
| tree | 27560778736691d1edb8276897f4ed3b9411bcb2 | |
| parent | 1acf0af9b981027f3e73e93f0d3f85abdc794f71 (diff) | |
| download | olio-linux-3.10-79714f72d3b964611997de512cb29198c9f2dbbb.tar.xz olio-linux-3.10-79714f72d3b964611997de512cb29198c9f2dbbb.zip | |
get rid of kern_path_parent()
all callers want the same thing, actually - a kinda-sorta analog of
kern_path_create().  I.e. they want parent vfsmount/dentry (with
->i_mutex held, to make sure the child dentry is still their child)
+ the child dentry.
Signed-off-by Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | drivers/base/devtmpfs.c | 98 | ||||
| -rw-r--r-- | fs/namei.c | 22 | ||||
| -rw-r--r-- | include/linux/namei.h | 2 | ||||
| -rw-r--r-- | kernel/audit_watch.c | 25 | 
4 files changed, 65 insertions, 82 deletions
| diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 765c3a28077..d91a3a0b232 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -227,33 +227,24 @@ static int handle_create(const char *nodename, umode_t mode, struct device *dev)  static int dev_rmdir(const char *name)  { -	struct nameidata nd; +	struct path parent;  	struct dentry *dentry;  	int err; -	err = kern_path_parent(name, &nd); -	if (err) -		return err; - -	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) { -			if (dentry->d_inode->i_private == &thread) -				err = vfs_rmdir(nd.path.dentry->d_inode, -						dentry); -			else -				err = -EPERM; -		} else { -			err = -ENOENT; -		} -		dput(dentry); +	dentry = kern_path_locked(name, &parent); +	if (IS_ERR(dentry)) +		return PTR_ERR(dentry); +	if (dentry->d_inode) { +		if (dentry->d_inode->i_private == &thread) +			err = vfs_rmdir(parent.dentry->d_inode, dentry); +		else +			err = -EPERM;  	} else { -		err = PTR_ERR(dentry); +		err = -ENOENT;  	} - -	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); -	path_put(&nd.path); +	dput(dentry); +	mutex_unlock(&parent.dentry->d_inode->i_mutex); +	path_put(&parent);  	return err;  } @@ -305,50 +296,43 @@ static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *sta  static int handle_remove(const char *nodename, struct device *dev)  { -	struct nameidata nd; +	struct path parent;  	struct dentry *dentry; -	struct kstat stat;  	int deleted = 1;  	int err; -	err = kern_path_parent(nodename, &nd); -	if (err) -		return err; +	dentry = kern_path_locked(nodename, &parent); +	if (IS_ERR(dentry)) +		return PTR_ERR(dentry); -	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_getattr(nd.path.mnt, dentry, &stat); -			if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { -				struct iattr newattrs; -				/* -				 * before unlinking this node, reset permissions -				 * of possible references like hardlinks -				 */ -				newattrs.ia_uid = 0; -				newattrs.ia_gid = 0; -				newattrs.ia_mode = stat.mode & ~0777; -				newattrs.ia_valid = -					ATTR_UID|ATTR_GID|ATTR_MODE; -				mutex_lock(&dentry->d_inode->i_mutex); -				notify_change(dentry, &newattrs); -				mutex_unlock(&dentry->d_inode->i_mutex); -				err = vfs_unlink(nd.path.dentry->d_inode, -						 dentry); -				if (!err || err == -ENOENT) -					deleted = 1; -			} -		} else { -			err = -ENOENT; +	if (dentry->d_inode) { +		struct kstat stat; +		err = vfs_getattr(parent.mnt, dentry, &stat); +		if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { +			struct iattr newattrs; +			/* +			 * before unlinking this node, reset permissions +			 * of possible references like hardlinks +			 */ +			newattrs.ia_uid = 0; +			newattrs.ia_gid = 0; +			newattrs.ia_mode = stat.mode & ~0777; +			newattrs.ia_valid = +				ATTR_UID|ATTR_GID|ATTR_MODE; +			mutex_lock(&dentry->d_inode->i_mutex); +			notify_change(dentry, &newattrs); +			mutex_unlock(&dentry->d_inode->i_mutex); +			err = vfs_unlink(parent.dentry->d_inode, dentry); +			if (!err || err == -ENOENT) +				deleted = 1;  		} -		dput(dentry);  	} else { -		err = PTR_ERR(dentry); +		err = -ENOENT;  	} -	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); +	dput(dentry); +	mutex_unlock(&parent.dentry->d_inode->i_mutex); -	path_put(&nd.path); +	path_put(&parent);  	if (deleted && strchr(nodename, '/'))  		delete_path(nodename);  	return err; diff --git a/fs/namei.c b/fs/namei.c index 5abab917690..6b29a51bef5 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1814,9 +1814,27 @@ static int do_path_lookup(int dfd, const char *name,  	return retval;  } -int kern_path_parent(const char *name, struct nameidata *nd) +/* does lookup, returns the object with parent locked */ +struct dentry *kern_path_locked(const char *name, struct path *path)  { -	return do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, nd); +	struct nameidata nd; +	struct dentry *d; +	int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd); +	if (err) +		return ERR_PTR(err); +	if (nd.last_type != LAST_NORM) { +		path_put(&nd.path); +		return ERR_PTR(-EINVAL); +	} +	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); +	d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); +	if (IS_ERR(d)) { +		mutex_unlock(&nd.path.dentry->d_inode->i_mutex); +		path_put(&nd.path); +		return d; +	} +	*path = nd.path; +	return d;  }  int kern_path(const char *name, unsigned int flags, struct path *path) diff --git a/include/linux/namei.h b/include/linux/namei.h index 23d85987921..f5931489e15 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -67,7 +67,7 @@ extern int kern_path(const char *, unsigned, struct path *);  extern struct dentry *kern_path_create(int, const char *, struct path *, int);  extern struct dentry *user_path_create(int, const char __user *, struct path *, int); -extern int kern_path_parent(const char *, struct nameidata *); +extern struct dentry *kern_path_locked(const char *, struct path *);  extern int vfs_path_lookup(struct dentry *, struct vfsmount *,  			   const char *, unsigned int, struct path *); diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index e683869365d..3823281401b 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -355,34 +355,15 @@ static void audit_remove_parent_watches(struct audit_parent *parent)  /* Get path information necessary for adding watches. */  static int audit_get_nd(struct audit_watch *watch, struct path *parent)  { -	struct nameidata nd; -	struct dentry *d; -	int err; - -	err = kern_path_parent(watch->path, &nd); -	if (err) -		return err; - -	if (nd.last_type != LAST_NORM) { -		path_put(&nd.path); -		return -EINVAL; -	} - -	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); -	d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); -	if (IS_ERR(d)) { -		mutex_unlock(&nd.path.dentry->d_inode->i_mutex); -		path_put(&nd.path); +	struct dentry *d = kern_path_locked(watch->path, parent); +	if (IS_ERR(d))  		return PTR_ERR(d); -	} +	mutex_unlock(&parent->dentry->d_inode->i_mutex);  	if (d->d_inode) {  		/* update watch filter fields */  		watch->dev = d->d_inode->i_sb->s_dev;  		watch->ino = d->d_inode->i_ino;  	} -	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); - -	*parent = nd.path;  	dput(d);  	return 0;  } |