open-style analog of vfs_path_lookup()
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 11 Mar 2011 17:08:24 +0000 (12:08 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 14 Mar 2011 13:15:28 +0000 (09:15 -0400)
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>
arch/um/drivers/mconsole_kern.c
fs/internal.h
fs/namei.c
fs/nfsctl.c
fs/open.c
include/linux/fs.h
kernel/sysctl_binary.c

index 975613b23dcfb9cd0b60d46afa05260e733d90c2..c70e047eed72e192cd9d0a8ade7cc6f8302a9d6c 100644 (file)
@@ -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;
        }
 
index 6fdbdf2c60479fa2b4fc265590375f38b077ed0f..52abc5287f50d16467ab38ab717588b8e89b73cc 100644 (file)
@@ -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
index 8ee7785d5642d0e52b2b9bd0c973c1715e90f164..abc8d2df121cb414e2cbdebbb9c6a8dfa98bbf3d 100644 (file)
@@ -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
index bf9cbd242dddbe5f7cda1969fc3eeebbd6e023ad..124e8fcb0dd6ad1fbe55c166ec30019abdd9c410 100644 (file)
 
 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);
-       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);
+       file = file_open_root(mnt->mnt_root, mnt, name, flags);
 
-       if (!error)
-               return dentry_open(nd.path.dentry, nd.path.mnt, flags,
-                                  current_cred());
-
-       path_put(&nd.path);
-       return ERR_PTR(error);
+       mntput(mnt);    /* drop do_kern_mount reference */
+       return file;
 }
 
 static struct {
index d05e18c60baec9e9b422c57338c01debda07f214..48afc5c139d247e634d9926507d2a8d9354015db 100644 (file)
--- a/fs/open.c
+++ b/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;
index 9c75714f92c1f4836db760ebb2e02b0926d88706..bf5c3c8960725133df0b4b04afee1109263fa05b 100644 (file)
@@ -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 *);
  
index b875bedf7c9abd2efd068cd67a84a4f359356cc9..3b8e028b96014a088b6227859b9163e8bceddb5a 100644 (file)
@@ -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;
 }