mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	open-style analog of vfs_path_lookup()
new function: file_open_root(dentry, mnt, name, flags) opens the file vfs_path_lookup would arrive to. Note that name can be empty; in that case the usual requirement that dentry should be a directory is lifted. open-coded equivalents switched to it, may_open() got down exactly one caller and became static. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									5b6ca027d8
								
							
						
					
					
						commit
						73d049a40f
					
				
					 7 changed files with 77 additions and 84 deletions
				
			
		|  | @ -124,35 +124,18 @@ void mconsole_log(struct mc_request *req) | |||
| #if 0 | ||||
| void mconsole_proc(struct mc_request *req) | ||||
| { | ||||
| 	struct nameidata nd; | ||||
| 	struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt; | ||||
| 	struct file *file; | ||||
| 	int n, err; | ||||
| 	int n; | ||||
| 	char *ptr = req->request.data, *buf; | ||||
| 	mm_segment_t old_fs = get_fs(); | ||||
| 
 | ||||
| 	ptr += strlen("proc"); | ||||
| 	ptr = skip_spaces(ptr); | ||||
| 
 | ||||
| 	err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd); | ||||
| 	if (err) { | ||||
| 		mconsole_reply(req, "Failed to look up file", 1, 0); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	err = may_open(&nd.path, MAY_READ, O_RDONLY); | ||||
| 	if (result) { | ||||
| 		mconsole_reply(req, "Failed to open file", 1, 0); | ||||
| 		path_put(&nd.path); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY, | ||||
| 			   current_cred()); | ||||
| 	err = PTR_ERR(file); | ||||
| 	file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY); | ||||
| 	if (IS_ERR(file)) { | ||||
| 		mconsole_reply(req, "Failed to open file", 1, 0); | ||||
| 		path_put(&nd.path); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -114,6 +114,8 @@ struct open_flags { | |||
| }; | ||||
| extern struct file *do_filp_open(int dfd, const char *pathname, | ||||
| 		const struct open_flags *op, int lookup_flags); | ||||
| extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, | ||||
| 		const char *, const struct open_flags *, int lookup_flags); | ||||
| 
 | ||||
| /*
 | ||||
|  * inode.c | ||||
|  |  | |||
							
								
								
									
										80
									
								
								fs/namei.c
									
										
									
									
									
								
							
							
						
						
									
										80
									
								
								fs/namei.c
									
										
									
									
									
								
							|  | @ -1487,11 +1487,13 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
| 	nd->depth = 0; | ||||
| 	if (flags & LOOKUP_ROOT) { | ||||
| 		struct inode *inode = nd->root.dentry->d_inode; | ||||
| 		if (!inode->i_op->lookup) | ||||
| 			return -ENOTDIR; | ||||
| 		retval = inode_permission(inode, MAY_EXEC); | ||||
| 		if (retval) | ||||
| 			return retval; | ||||
| 		if (*name) { | ||||
| 			if (!inode->i_op->lookup) | ||||
| 				return -ENOTDIR; | ||||
| 			retval = inode_permission(inode, MAY_EXEC); | ||||
| 			if (retval) | ||||
| 				return retval; | ||||
| 		} | ||||
| 		nd->path = nd->root; | ||||
| 		nd->inode = inode; | ||||
| 		if (flags & LOOKUP_RCU) { | ||||
|  | @ -1937,7 +1939,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| int may_open(struct path *path, int acc_mode, int flag) | ||||
| static int may_open(struct path *path, int acc_mode, int flag) | ||||
| { | ||||
| 	struct dentry *dentry = path->dentry; | ||||
| 	struct inode *inode = dentry->d_inode; | ||||
|  | @ -2250,11 +2252,10 @@ exit: | |||
| } | ||||
| 
 | ||||
| static struct file *path_openat(int dfd, const char *pathname, | ||||
| 		const struct open_flags *op, int flags) | ||||
| 		struct nameidata *nd, const struct open_flags *op, int flags) | ||||
| { | ||||
| 	struct file *base = NULL; | ||||
| 	struct file *filp; | ||||
| 	struct nameidata nd; | ||||
| 	struct path path; | ||||
| 	int count = 0; | ||||
| 	int error; | ||||
|  | @ -2264,27 +2265,27 @@ static struct file *path_openat(int dfd, const char *pathname, | |||
| 		return ERR_PTR(-ENFILE); | ||||
| 
 | ||||
| 	filp->f_flags = op->open_flag; | ||||
| 	nd.intent.open.file = filp; | ||||
| 	nd.intent.open.flags = open_to_namei_flags(op->open_flag); | ||||
| 	nd.intent.open.create_mode = op->mode; | ||||
| 	nd->intent.open.file = filp; | ||||
| 	nd->intent.open.flags = open_to_namei_flags(op->open_flag); | ||||
| 	nd->intent.open.create_mode = op->mode; | ||||
| 
 | ||||
| 	error = path_init(dfd, pathname, flags | LOOKUP_PARENT, &nd, &base); | ||||
| 	error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base); | ||||
| 	if (unlikely(error)) | ||||
| 		goto out_filp; | ||||
| 
 | ||||
| 	current->total_link_count = 0; | ||||
| 	error = link_path_walk(pathname, &nd); | ||||
| 	error = link_path_walk(pathname, nd); | ||||
| 	if (unlikely(error)) | ||||
| 		goto out_filp; | ||||
| 
 | ||||
| 	filp = do_last(&nd, &path, op, pathname); | ||||
| 	filp = do_last(nd, &path, op, pathname); | ||||
| 	while (unlikely(!filp)) { /* trailing symlink */ | ||||
| 		struct path link = path; | ||||
| 		struct inode *linki = link.dentry->d_inode; | ||||
| 		void *cookie; | ||||
| 		if (!(nd.flags & LOOKUP_FOLLOW) || count++ == 32) { | ||||
| 			path_put_conditional(&path, &nd); | ||||
| 			path_put(&nd.path); | ||||
| 		if (!(nd->flags & LOOKUP_FOLLOW) || count++ == 32) { | ||||
| 			path_put_conditional(&path, nd); | ||||
| 			path_put(&nd->path); | ||||
| 			filp = ERR_PTR(-ELOOP); | ||||
| 			break; | ||||
| 		} | ||||
|  | @ -2299,23 +2300,23 @@ static struct file *path_openat(int dfd, const char *pathname, | |||
| 		 * have to putname() it when we are done. Procfs-like symlinks | ||||
| 		 * just set LAST_BIND. | ||||
| 		 */ | ||||
| 		nd.flags |= LOOKUP_PARENT; | ||||
| 		nd.flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); | ||||
| 		error = __do_follow_link(&link, &nd, &cookie); | ||||
| 		nd->flags |= LOOKUP_PARENT; | ||||
| 		nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); | ||||
| 		error = __do_follow_link(&link, nd, &cookie); | ||||
| 		if (unlikely(error)) | ||||
| 			filp = ERR_PTR(error); | ||||
| 		else | ||||
| 			filp = do_last(&nd, &path, op, pathname); | ||||
| 			filp = do_last(nd, &path, op, pathname); | ||||
| 		if (!IS_ERR(cookie) && linki->i_op->put_link) | ||||
| 			linki->i_op->put_link(link.dentry, &nd, cookie); | ||||
| 			linki->i_op->put_link(link.dentry, nd, cookie); | ||||
| 		path_put(&link); | ||||
| 	} | ||||
| out: | ||||
| 	if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT)) | ||||
| 		path_put(&nd.root); | ||||
| 	if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) | ||||
| 		path_put(&nd->root); | ||||
| 	if (base) | ||||
| 		fput(base); | ||||
| 	release_open_intent(&nd); | ||||
| 	release_open_intent(nd); | ||||
| 	return filp; | ||||
| 
 | ||||
| out_filp: | ||||
|  | @ -2326,16 +2327,39 @@ out_filp: | |||
| struct file *do_filp_open(int dfd, const char *pathname, | ||||
| 		const struct open_flags *op, int flags) | ||||
| { | ||||
| 	struct nameidata nd; | ||||
| 	struct file *filp; | ||||
| 
 | ||||
| 	filp = path_openat(dfd, pathname, op, flags | LOOKUP_RCU); | ||||
| 	filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_RCU); | ||||
| 	if (unlikely(filp == ERR_PTR(-ECHILD))) | ||||
| 		filp = path_openat(dfd, pathname, op, flags); | ||||
| 		filp = path_openat(dfd, pathname, &nd, op, flags); | ||||
| 	if (unlikely(filp == ERR_PTR(-ESTALE))) | ||||
| 		filp = path_openat(dfd, pathname, op, flags | LOOKUP_REVAL); | ||||
| 		filp = path_openat(dfd, pathname, &nd, op, flags | LOOKUP_REVAL); | ||||
| 	return filp; | ||||
| } | ||||
| 
 | ||||
| struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | ||||
| 		const char *name, const struct open_flags *op, int flags) | ||||
| { | ||||
| 	struct nameidata nd; | ||||
| 	struct file *file; | ||||
| 
 | ||||
| 	nd.root.mnt = mnt; | ||||
| 	nd.root.dentry = dentry; | ||||
| 
 | ||||
| 	flags |= LOOKUP_ROOT; | ||||
| 
 | ||||
| 	if (dentry->d_inode->i_op->follow_link) | ||||
| 		return ERR_PTR(-ELOOP); | ||||
| 
 | ||||
| 	file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU); | ||||
| 	if (unlikely(file == ERR_PTR(-ECHILD))) | ||||
| 		file = path_openat(-1, name, &nd, op, flags); | ||||
| 	if (unlikely(file == ERR_PTR(-ESTALE))) | ||||
| 		file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL); | ||||
| 	return file; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * lookup_create - lookup a dentry, creating it if it doesn't exist | ||||
|  * @nd: nameidata info | ||||
|  |  | |||
							
								
								
									
										21
									
								
								fs/nfsctl.c
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								fs/nfsctl.c
									
										
									
									
									
								
							|  | @ -22,30 +22,17 @@ | |||
| 
 | ||||
| static struct file *do_open(char *name, int flags) | ||||
| { | ||||
| 	struct nameidata nd; | ||||
| 	struct vfsmount *mnt; | ||||
| 	int error; | ||||
| 	struct file *file; | ||||
| 
 | ||||
| 	mnt = do_kern_mount("nfsd", 0, "nfsd", NULL); | ||||
| 	if (IS_ERR(mnt)) | ||||
| 		return (struct file *)mnt; | ||||
| 
 | ||||
| 	error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd); | ||||
| 	file = file_open_root(mnt->mnt_root, mnt, name, flags); | ||||
| 
 | ||||
| 	mntput(mnt);	/* drop do_kern_mount reference */ | ||||
| 	if (error) | ||||
| 		return ERR_PTR(error); | ||||
| 
 | ||||
| 	if (flags == O_RDWR) | ||||
| 		error = may_open(&nd.path, MAY_READ|MAY_WRITE, flags); | ||||
| 	else | ||||
| 		error = may_open(&nd.path, MAY_WRITE, flags); | ||||
| 
 | ||||
| 	if (!error) | ||||
| 		return dentry_open(nd.path.dentry, nd.path.mnt, flags, | ||||
| 				   current_cred()); | ||||
| 
 | ||||
| 	path_put(&nd.path); | ||||
| 	return ERR_PTR(error); | ||||
| 	return file; | ||||
| } | ||||
| 
 | ||||
| static struct { | ||||
|  |  | |||
							
								
								
									
										14
									
								
								fs/open.c
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								fs/open.c
									
										
									
									
									
								
							|  | @ -959,6 +959,20 @@ struct file *filp_open(const char *filename, int flags, int mode) | |||
| } | ||||
| EXPORT_SYMBOL(filp_open); | ||||
| 
 | ||||
| struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, | ||||
| 			    const char *filename, int flags) | ||||
| { | ||||
| 	struct open_flags op; | ||||
| 	int lookup = build_open_flags(flags, 0, &op); | ||||
| 	if (flags & O_CREAT) | ||||
| 		return ERR_PTR(-EINVAL); | ||||
| 	if (!filename && (flags & O_DIRECTORY)) | ||||
| 		if (!dentry->d_inode->i_op->lookup) | ||||
| 			return ERR_PTR(-ENOTDIR); | ||||
| 	return do_file_open_root(dentry, mnt, filename, &op, lookup); | ||||
| } | ||||
| EXPORT_SYMBOL(file_open_root); | ||||
| 
 | ||||
| long do_sys_open(int dfd, const char __user *filename, int flags, int mode) | ||||
| { | ||||
| 	struct open_flags op; | ||||
|  |  | |||
|  | @ -1990,6 +1990,8 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset, | |||
| extern long do_sys_open(int dfd, const char __user *filename, int flags, | ||||
| 			int mode); | ||||
| extern struct file *filp_open(const char *, int, int); | ||||
| extern struct file *file_open_root(struct dentry *, struct vfsmount *, | ||||
| 				   const char *, int); | ||||
| extern struct file * dentry_open(struct dentry *, struct vfsmount *, int, | ||||
| 				 const struct cred *); | ||||
| extern int filp_close(struct file *, fl_owner_t id); | ||||
|  | @ -2205,8 +2207,6 @@ extern struct file *create_read_pipe(struct file *f, int flags); | |||
| extern struct file *create_write_pipe(int flags); | ||||
| extern void free_write_pipe(struct file *); | ||||
| 
 | ||||
| extern int may_open(struct path *, int, int); | ||||
| 
 | ||||
| extern int kernel_read(struct file *, loff_t, char *, unsigned long); | ||||
| extern struct file * open_exec(const char *); | ||||
|   | ||||
|  |  | |||
|  | @ -1321,13 +1321,11 @@ static ssize_t binary_sysctl(const int *name, int nlen, | |||
| 	void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) | ||||
| { | ||||
| 	const struct bin_table *table = NULL; | ||||
| 	struct nameidata nd; | ||||
| 	struct vfsmount *mnt; | ||||
| 	struct file *file; | ||||
| 	ssize_t result; | ||||
| 	char *pathname; | ||||
| 	int flags; | ||||
| 	int acc_mode; | ||||
| 
 | ||||
| 	pathname = sysctl_getname(name, nlen, &table); | ||||
| 	result = PTR_ERR(pathname); | ||||
|  | @ -1337,28 +1335,17 @@ static ssize_t binary_sysctl(const int *name, int nlen, | |||
| 	/* How should the sysctl be accessed? */ | ||||
| 	if (oldval && oldlen && newval && newlen) { | ||||
| 		flags = O_RDWR; | ||||
| 		acc_mode = MAY_READ | MAY_WRITE; | ||||
| 	} else if (newval && newlen) { | ||||
| 		flags = O_WRONLY; | ||||
| 		acc_mode = MAY_WRITE; | ||||
| 	} else if (oldval && oldlen) { | ||||
| 		flags = O_RDONLY; | ||||
| 		acc_mode = MAY_READ; | ||||
| 	} else { | ||||
| 		result = 0; | ||||
| 		goto out_putname; | ||||
| 	} | ||||
| 
 | ||||
| 	mnt = current->nsproxy->pid_ns->proc_mnt; | ||||
| 	result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd); | ||||
| 	if (result) | ||||
| 		goto out_putname; | ||||
| 
 | ||||
| 	result = may_open(&nd.path, acc_mode, flags); | ||||
| 	if (result) | ||||
| 		goto out_putpath; | ||||
| 
 | ||||
| 	file = dentry_open(nd.path.dentry, nd.path.mnt, flags, current_cred()); | ||||
| 	file = file_open_root(mnt->mnt_root, mnt, pathname, flags); | ||||
| 	result = PTR_ERR(file); | ||||
| 	if (IS_ERR(file)) | ||||
| 		goto out_putname; | ||||
|  | @ -1370,10 +1357,6 @@ out_putname: | |||
| 	putname(pathname); | ||||
| out: | ||||
| 	return result; | ||||
| 
 | ||||
| out_putpath: | ||||
| 	path_put(&nd.path); | ||||
| 	goto out_putname; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Al Viro
						Al Viro