mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	new helpers: kern_path_create/user_path_create
combination of kern_path_parent() and lookup_create(). Does *not* expose struct nameidata to caller. Syscalls converted to that... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									49084c3bb2
								
							
						
					
					
						commit
						dae6ad8f37
					
				
					 4 changed files with 106 additions and 137 deletions
				
			
		
							
								
								
									
										154
									
								
								fs/namei.c
									
										
									
									
									
								
							
							
						
						
									
										154
									
								
								fs/namei.c
									
										
									
									
									
								
							|  | @ -2311,6 +2311,35 @@ fail: | |||
| } | ||||
| EXPORT_SYMBOL_GPL(lookup_create); | ||||
| 
 | ||||
| struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir) | ||||
| { | ||||
| 	struct nameidata nd; | ||||
| 	struct dentry *res; | ||||
| 	int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd); | ||||
| 	if (error) | ||||
| 		return ERR_PTR(error); | ||||
| 	res = lookup_create(&nd, is_dir); | ||||
| 	if (IS_ERR(res)) { | ||||
| 		mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 		path_put(&nd.path); | ||||
| 	} | ||||
| 	*path = nd.path; | ||||
| 	return res; | ||||
| } | ||||
| EXPORT_SYMBOL(kern_path_create); | ||||
| 
 | ||||
| struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir) | ||||
| { | ||||
| 	char *tmp = getname(pathname); | ||||
| 	struct dentry *res; | ||||
| 	if (IS_ERR(tmp)) | ||||
| 		return ERR_CAST(tmp); | ||||
| 	res = kern_path_create(dfd, tmp, path, is_dir); | ||||
| 	putname(tmp); | ||||
| 	return res; | ||||
| } | ||||
| EXPORT_SYMBOL(user_path_create); | ||||
| 
 | ||||
| int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | ||||
| { | ||||
| 	int error = may_create(dir, dentry); | ||||
|  | @ -2359,54 +2388,46 @@ static int may_mknod(mode_t mode) | |||
| SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, int, mode, | ||||
| 		unsigned, dev) | ||||
| { | ||||
| 	int error; | ||||
| 	char *tmp; | ||||
| 	struct dentry *dentry; | ||||
| 	struct nameidata nd; | ||||
| 	struct path path; | ||||
| 	int error; | ||||
| 
 | ||||
| 	if (S_ISDIR(mode)) | ||||
| 		return -EPERM; | ||||
| 
 | ||||
| 	error = user_path_parent(dfd, filename, &nd, &tmp); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 	dentry = user_path_create(dfd, filename, &path, 0); | ||||
| 	if (IS_ERR(dentry)) | ||||
| 		return PTR_ERR(dentry); | ||||
| 
 | ||||
| 	dentry = lookup_create(&nd, 0); | ||||
| 	if (IS_ERR(dentry)) { | ||||
| 		error = PTR_ERR(dentry); | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
| 	if (!IS_POSIXACL(nd.path.dentry->d_inode)) | ||||
| 	if (!IS_POSIXACL(path.dentry->d_inode)) | ||||
| 		mode &= ~current_umask(); | ||||
| 	error = may_mknod(mode); | ||||
| 	if (error) | ||||
| 		goto out_dput; | ||||
| 	error = mnt_want_write(nd.path.mnt); | ||||
| 	error = mnt_want_write(path.mnt); | ||||
| 	if (error) | ||||
| 		goto out_dput; | ||||
| 	error = security_path_mknod(&nd.path, dentry, mode, dev); | ||||
| 	error = security_path_mknod(&path, dentry, mode, dev); | ||||
| 	if (error) | ||||
| 		goto out_drop_write; | ||||
| 	switch (mode & S_IFMT) { | ||||
| 		case 0: case S_IFREG: | ||||
| 			error = vfs_create(nd.path.dentry->d_inode,dentry,mode,NULL); | ||||
| 			error = vfs_create(path.dentry->d_inode,dentry,mode,NULL); | ||||
| 			break; | ||||
| 		case S_IFCHR: case S_IFBLK: | ||||
| 			error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode, | ||||
| 			error = vfs_mknod(path.dentry->d_inode,dentry,mode, | ||||
| 					new_decode_dev(dev)); | ||||
| 			break; | ||||
| 		case S_IFIFO: case S_IFSOCK: | ||||
| 			error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0); | ||||
| 			error = vfs_mknod(path.dentry->d_inode,dentry,mode,0); | ||||
| 			break; | ||||
| 	} | ||||
| out_drop_write: | ||||
| 	mnt_drop_write(nd.path.mnt); | ||||
| 	mnt_drop_write(path.mnt); | ||||
| out_dput: | ||||
| 	dput(dentry); | ||||
| out_unlock: | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&nd.path); | ||||
| 	putname(tmp); | ||||
| 	mutex_unlock(&path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&path); | ||||
| 
 | ||||
| 	return error; | ||||
| } | ||||
|  | @ -2439,38 +2460,29 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 
 | ||||
| SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, int, mode) | ||||
| { | ||||
| 	int error = 0; | ||||
| 	char * tmp; | ||||
| 	struct dentry *dentry; | ||||
| 	struct nameidata nd; | ||||
| 	struct path path; | ||||
| 	int error; | ||||
| 
 | ||||
| 	error = user_path_parent(dfd, pathname, &nd, &tmp); | ||||
| 	if (error) | ||||
| 		goto out_err; | ||||
| 
 | ||||
| 	dentry = lookup_create(&nd, 1); | ||||
| 	error = PTR_ERR(dentry); | ||||
| 	dentry = user_path_create(dfd, pathname, &path, 1); | ||||
| 	if (IS_ERR(dentry)) | ||||
| 		goto out_unlock; | ||||
| 		return PTR_ERR(dentry); | ||||
| 
 | ||||
| 	if (!IS_POSIXACL(nd.path.dentry->d_inode)) | ||||
| 	if (!IS_POSIXACL(path.dentry->d_inode)) | ||||
| 		mode &= ~current_umask(); | ||||
| 	error = mnt_want_write(nd.path.mnt); | ||||
| 	error = mnt_want_write(path.mnt); | ||||
| 	if (error) | ||||
| 		goto out_dput; | ||||
| 	error = security_path_mkdir(&nd.path, dentry, mode); | ||||
| 	error = security_path_mkdir(&path, dentry, mode); | ||||
| 	if (error) | ||||
| 		goto out_drop_write; | ||||
| 	error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); | ||||
| 	error = vfs_mkdir(path.dentry->d_inode, dentry, mode); | ||||
| out_drop_write: | ||||
| 	mnt_drop_write(nd.path.mnt); | ||||
| 	mnt_drop_write(path.mnt); | ||||
| out_dput: | ||||
| 	dput(dentry); | ||||
| out_unlock: | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&nd.path); | ||||
| 	putname(tmp); | ||||
| out_err: | ||||
| 	mutex_unlock(&path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&path); | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
|  | @ -2730,38 +2742,31 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, | |||
| { | ||||
| 	int error; | ||||
| 	char *from; | ||||
| 	char *to; | ||||
| 	struct dentry *dentry; | ||||
| 	struct nameidata nd; | ||||
| 	struct path path; | ||||
| 
 | ||||
| 	from = getname(oldname); | ||||
| 	if (IS_ERR(from)) | ||||
| 		return PTR_ERR(from); | ||||
| 
 | ||||
| 	error = user_path_parent(newdfd, newname, &nd, &to); | ||||
| 	if (error) | ||||
| 		goto out_putname; | ||||
| 
 | ||||
| 	dentry = lookup_create(&nd, 0); | ||||
| 	dentry = user_path_create(newdfd, newname, &path, 0); | ||||
| 	error = PTR_ERR(dentry); | ||||
| 	if (IS_ERR(dentry)) | ||||
| 		goto out_unlock; | ||||
| 		goto out_putname; | ||||
| 
 | ||||
| 	error = mnt_want_write(nd.path.mnt); | ||||
| 	error = mnt_want_write(path.mnt); | ||||
| 	if (error) | ||||
| 		goto out_dput; | ||||
| 	error = security_path_symlink(&nd.path, dentry, from); | ||||
| 	error = security_path_symlink(&path, dentry, from); | ||||
| 	if (error) | ||||
| 		goto out_drop_write; | ||||
| 	error = vfs_symlink(nd.path.dentry->d_inode, dentry, from); | ||||
| 	error = vfs_symlink(path.dentry->d_inode, dentry, from); | ||||
| out_drop_write: | ||||
| 	mnt_drop_write(nd.path.mnt); | ||||
| 	mnt_drop_write(path.mnt); | ||||
| out_dput: | ||||
| 	dput(dentry); | ||||
| out_unlock: | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&nd.path); | ||||
| 	putname(to); | ||||
| 	mutex_unlock(&path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&path); | ||||
| out_putname: | ||||
| 	putname(from); | ||||
| 	return error; | ||||
|  | @ -2826,11 +2831,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, | |||
| 		int, newdfd, const char __user *, newname, int, flags) | ||||
| { | ||||
| 	struct dentry *new_dentry; | ||||
| 	struct nameidata nd; | ||||
| 	struct path old_path; | ||||
| 	struct path old_path, new_path; | ||||
| 	int how = 0; | ||||
| 	int error; | ||||
| 	char *to; | ||||
| 
 | ||||
| 	if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) | ||||
| 		return -EINVAL; | ||||
|  | @ -2852,32 +2855,27 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, | |||
| 	if (error) | ||||
| 		return error; | ||||
| 
 | ||||
| 	error = user_path_parent(newdfd, newname, &nd, &to); | ||||
| 	if (error) | ||||
| 		goto out; | ||||
| 	error = -EXDEV; | ||||
| 	if (old_path.mnt != nd.path.mnt) | ||||
| 		goto out_release; | ||||
| 	new_dentry = lookup_create(&nd, 0); | ||||
| 	new_dentry = user_path_create(newdfd, newname, &new_path, 0); | ||||
| 	error = PTR_ERR(new_dentry); | ||||
| 	if (IS_ERR(new_dentry)) | ||||
| 		goto out_unlock; | ||||
| 	error = mnt_want_write(nd.path.mnt); | ||||
| 		goto out; | ||||
| 
 | ||||
| 	error = -EXDEV; | ||||
| 	if (old_path.mnt != new_path.mnt) | ||||
| 		goto out_dput; | ||||
| 	error = mnt_want_write(new_path.mnt); | ||||
| 	if (error) | ||||
| 		goto out_dput; | ||||
| 	error = security_path_link(old_path.dentry, &nd.path, new_dentry); | ||||
| 	error = security_path_link(old_path.dentry, &new_path, new_dentry); | ||||
| 	if (error) | ||||
| 		goto out_drop_write; | ||||
| 	error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry); | ||||
| 	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); | ||||
| out_drop_write: | ||||
| 	mnt_drop_write(nd.path.mnt); | ||||
| 	mnt_drop_write(new_path.mnt); | ||||
| out_dput: | ||||
| 	dput(new_dentry); | ||||
| out_unlock: | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| out_release: | ||||
| 	path_put(&nd.path); | ||||
| 	putname(to); | ||||
| 	mutex_unlock(&new_path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&new_path); | ||||
| out: | ||||
| 	path_put(&old_path); | ||||
| 
 | ||||
|  |  | |||
|  | @ -4368,25 +4368,6 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child) | |||
| 	return inode_permission(dir, MAY_WRITE | MAY_EXEC); | ||||
| } | ||||
| 
 | ||||
| /* copied from user_path_parent. */ | ||||
| static int ocfs2_user_path_parent(const char __user *path, | ||||
| 				  struct nameidata *nd, char **name) | ||||
| { | ||||
| 	char *s = getname(path); | ||||
| 	int error; | ||||
| 
 | ||||
| 	if (IS_ERR(s)) | ||||
| 		return PTR_ERR(s); | ||||
| 
 | ||||
| 	error = kern_path_parent(s, nd); | ||||
| 	if (error) | ||||
| 		putname(s); | ||||
| 	else | ||||
| 		*name = s; | ||||
| 
 | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ocfs2_vfs_reflink - Create a reference-counted link | ||||
|  * | ||||
|  | @ -4460,10 +4441,8 @@ int ocfs2_reflink_ioctl(struct inode *inode, | |||
| 			bool preserve) | ||||
| { | ||||
| 	struct dentry *new_dentry; | ||||
| 	struct nameidata nd; | ||||
| 	struct path old_path; | ||||
| 	struct path old_path, new_path; | ||||
| 	int error; | ||||
| 	char *to = NULL; | ||||
| 
 | ||||
| 	if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) | ||||
| 		return -EOPNOTSUPP; | ||||
|  | @ -4474,39 +4453,33 @@ int ocfs2_reflink_ioctl(struct inode *inode, | |||
| 		return error; | ||||
| 	} | ||||
| 
 | ||||
| 	error = ocfs2_user_path_parent(newname, &nd, &to); | ||||
| 	if (error) { | ||||
| 	new_dentry = user_path_create(AT_FDCWD, newname, &new_path, 0); | ||||
| 	error = PTR_ERR(new_dentry); | ||||
| 	if (IS_ERR(new_dentry)) { | ||||
| 		mlog_errno(error); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	error = -EXDEV; | ||||
| 	if (old_path.mnt != nd.path.mnt) | ||||
| 		goto out_release; | ||||
| 	new_dentry = lookup_create(&nd, 0); | ||||
| 	error = PTR_ERR(new_dentry); | ||||
| 	if (IS_ERR(new_dentry)) { | ||||
| 	if (old_path.mnt != new_path.mnt) { | ||||
| 		mlog_errno(error); | ||||
| 		goto out_unlock; | ||||
| 		goto out_dput; | ||||
| 	} | ||||
| 
 | ||||
| 	error = mnt_want_write(nd.path.mnt); | ||||
| 	error = mnt_want_write(new_path.mnt); | ||||
| 	if (error) { | ||||
| 		mlog_errno(error); | ||||
| 		goto out_dput; | ||||
| 	} | ||||
| 
 | ||||
| 	error = ocfs2_vfs_reflink(old_path.dentry, | ||||
| 				  nd.path.dentry->d_inode, | ||||
| 				  new_path.dentry->d_inode, | ||||
| 				  new_dentry, preserve); | ||||
| 	mnt_drop_write(nd.path.mnt); | ||||
| 	mnt_drop_write(new_path.mnt); | ||||
| out_dput: | ||||
| 	dput(new_dentry); | ||||
| out_unlock: | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| out_release: | ||||
| 	path_put(&nd.path); | ||||
| 	putname(to); | ||||
| 	mutex_unlock(&new_path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&new_path); | ||||
| out: | ||||
| 	path_put(&old_path); | ||||
| 
 | ||||
|  |  | |||
|  | @ -74,6 +74,8 @@ extern int user_path_at(int, const char __user *, unsigned, struct path *); | |||
| 
 | ||||
| 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 int vfs_path_lookup(struct dentry *, struct vfsmount *, | ||||
| 			   const char *, unsigned int, struct nameidata *); | ||||
|  |  | |||
|  | @ -808,8 +808,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 	struct net *net = sock_net(sk); | ||||
| 	struct unix_sock *u = unix_sk(sk); | ||||
| 	struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; | ||||
| 	char *sun_path = sunaddr->sun_path; | ||||
| 	struct dentry *dentry = NULL; | ||||
| 	struct nameidata nd; | ||||
| 	struct path path; | ||||
| 	int err; | ||||
| 	unsigned hash; | ||||
| 	struct unix_address *addr; | ||||
|  | @ -845,48 +846,44 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
| 	addr->hash = hash ^ sk->sk_type; | ||||
| 	atomic_set(&addr->refcnt, 1); | ||||
| 
 | ||||
| 	if (sunaddr->sun_path[0]) { | ||||
| 	if (sun_path[0]) { | ||||
| 		unsigned int mode; | ||||
| 		err = 0; | ||||
| 		/*
 | ||||
| 		 * Get the parent directory, calculate the hash for last | ||||
| 		 * component. | ||||
| 		 */ | ||||
| 		err = kern_path_parent(sunaddr->sun_path, &nd); | ||||
| 		if (err) | ||||
| 			goto out_mknod_parent; | ||||
| 
 | ||||
| 		dentry = lookup_create(&nd, 0); | ||||
| 		dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0); | ||||
| 		err = PTR_ERR(dentry); | ||||
| 		if (IS_ERR(dentry)) | ||||
| 			goto out_mknod_unlock; | ||||
| 			goto out_mknod_parent; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * All right, let's create it. | ||||
| 		 */ | ||||
| 		mode = S_IFSOCK | | ||||
| 		       (SOCK_INODE(sock)->i_mode & ~current_umask()); | ||||
| 		err = mnt_want_write(nd.path.mnt); | ||||
| 		err = mnt_want_write(path.mnt); | ||||
| 		if (err) | ||||
| 			goto out_mknod_dput; | ||||
| 		err = security_path_mknod(&nd.path, dentry, mode, 0); | ||||
| 		err = security_path_mknod(&path, dentry, mode, 0); | ||||
| 		if (err) | ||||
| 			goto out_mknod_drop_write; | ||||
| 		err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0); | ||||
| 		err = vfs_mknod(path.dentry->d_inode, dentry, mode, 0); | ||||
| out_mknod_drop_write: | ||||
| 		mnt_drop_write(nd.path.mnt); | ||||
| 		mnt_drop_write(path.mnt); | ||||
| 		if (err) | ||||
| 			goto out_mknod_dput; | ||||
| 		mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 		dput(nd.path.dentry); | ||||
| 		nd.path.dentry = dentry; | ||||
| 		mutex_unlock(&path.dentry->d_inode->i_mutex); | ||||
| 		dput(path.dentry); | ||||
| 		path.dentry = dentry; | ||||
| 
 | ||||
| 		addr->hash = UNIX_HASH_SIZE; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock(&unix_table_lock); | ||||
| 
 | ||||
| 	if (!sunaddr->sun_path[0]) { | ||||
| 	if (!sun_path[0]) { | ||||
| 		err = -EADDRINUSE; | ||||
| 		if (__unix_find_socket_byname(net, sunaddr, addr_len, | ||||
| 					      sk->sk_type, hash)) { | ||||
|  | @ -897,8 +894,8 @@ out_mknod_drop_write: | |||
| 		list = &unix_socket_table[addr->hash]; | ||||
| 	} else { | ||||
| 		list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; | ||||
| 		u->dentry = nd.path.dentry; | ||||
| 		u->mnt    = nd.path.mnt; | ||||
| 		u->dentry = path.dentry; | ||||
| 		u->mnt    = path.mnt; | ||||
| 	} | ||||
| 
 | ||||
| 	err = 0; | ||||
|  | @ -915,9 +912,8 @@ out: | |||
| 
 | ||||
| out_mknod_dput: | ||||
| 	dput(dentry); | ||||
| out_mknod_unlock: | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&nd.path); | ||||
| 	mutex_unlock(&path.dentry->d_inode->i_mutex); | ||||
| 	path_put(&path); | ||||
| out_mknod_parent: | ||||
| 	if (err == -EEXIST) | ||||
| 		err = -EADDRINUSE; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Al Viro
						Al Viro