new helpers: kern_path_create/user_path_create
Al Viro [Sun, 26 Jun 2011 15:50:15 +0000 (11:50 -0400)]
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>

fs/namei.c
fs/ocfs2/refcounttree.c
include/linux/namei.h
net/unix/af_unix.c

index f49d6ab..b292eb0 100644 (file)
@@ -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;
-
-       error = user_path_parent(dfd, pathname, &nd, &tmp);
-       if (error)
-               goto out_err;
+       struct path path;
+       int error;
 
-       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);
 
index ebfd382..cf78233 100644 (file)
@@ -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);
 
index 3439ab8..b8cea80 100644 (file)
@@ -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 *);
index 0722a25..ec68e1c 100644 (file)
@@ -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;