Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / fs / namei.c
index 808e4ea..28d49b3 100644 (file)
@@ -518,18 +518,20 @@ static int __emul_lookup_dentry(const char *, struct nameidata *);
 static __always_inline int
 walk_init_root(const char *name, struct nameidata *nd)
 {
-       read_lock(&current->fs->lock);
-       if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
-               nd->mnt = mntget(current->fs->altrootmnt);
-               nd->dentry = dget(current->fs->altroot);
-               read_unlock(&current->fs->lock);
+       struct fs_struct *fs = current->fs;
+
+       read_lock(&fs->lock);
+       if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
+               nd->mnt = mntget(fs->altrootmnt);
+               nd->dentry = dget(fs->altroot);
+               read_unlock(&fs->lock);
                if (__emul_lookup_dentry(name,nd))
                        return 0;
-               read_lock(&current->fs->lock);
+               read_lock(&fs->lock);
        }
-       nd->mnt = mntget(current->fs->rootmnt);
-       nd->dentry = dget(current->fs->root);
-       read_unlock(&current->fs->lock);
+       nd->mnt = mntget(fs->rootmnt);
+       nd->dentry = dget(fs->root);
+       read_unlock(&fs->lock);
        return 1;
 }
 
@@ -724,17 +726,19 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry)
 
 static __always_inline void follow_dotdot(struct nameidata *nd)
 {
+       struct fs_struct *fs = current->fs;
+
        while(1) {
                struct vfsmount *parent;
                struct dentry *old = nd->dentry;
 
-                read_lock(&current->fs->lock);
-               if (nd->dentry == current->fs->root &&
-                   nd->mnt == current->fs->rootmnt) {
-                        read_unlock(&current->fs->lock);
+                read_lock(&fs->lock);
+               if (nd->dentry == fs->root &&
+                   nd->mnt == fs->rootmnt) {
+                        read_unlock(&fs->lock);
                        break;
                }
-                read_unlock(&current->fs->lock);
+                read_unlock(&fs->lock);
                spin_lock(&dcache_lock);
                if (nd->dentry != nd->mnt->mnt_root) {
                        nd->dentry = dget(nd->dentry->d_parent);
@@ -1042,15 +1046,17 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
                struct vfsmount *old_mnt = nd->mnt;
                struct qstr last = nd->last;
                int last_type = nd->last_type;
+               struct fs_struct *fs = current->fs;
+
                /*
-                * NAME was not found in alternate root or it's a directory.  Try to find
-                * it in the normal root:
+                * NAME was not found in alternate root or it's a directory.
+                * Try to find it in the normal root:
                 */
                nd->last_type = LAST_ROOT;
-               read_lock(&current->fs->lock);
-               nd->mnt = mntget(current->fs->rootmnt);
-               nd->dentry = dget(current->fs->root);
-               read_unlock(&current->fs->lock);
+               read_lock(&fs->lock);
+               nd->mnt = mntget(fs->rootmnt);
+               nd->dentry = dget(fs->root);
+               read_unlock(&fs->lock);
                if (path_walk(name, nd) == 0) {
                        if (nd->dentry->d_inode) {
                                dput(old_dentry);
@@ -1074,6 +1080,7 @@ void set_fs_altroot(void)
        struct vfsmount *mnt = NULL, *oldmnt;
        struct dentry *dentry = NULL, *olddentry;
        int err;
+       struct fs_struct *fs = current->fs;
 
        if (!emul)
                goto set_it;
@@ -1083,12 +1090,12 @@ void set_fs_altroot(void)
                dentry = nd.dentry;
        }
 set_it:
-       write_lock(&current->fs->lock);
-       oldmnt = current->fs->altrootmnt;
-       olddentry = current->fs->altroot;
-       current->fs->altrootmnt = mnt;
-       current->fs->altroot = dentry;
-       write_unlock(&current->fs->lock);
+       write_lock(&fs->lock);
+       oldmnt = fs->altrootmnt;
+       olddentry = fs->altroot;
+       fs->altrootmnt = mnt;
+       fs->altroot = dentry;
+       write_unlock(&fs->lock);
        if (olddentry) {
                dput(olddentry);
                mntput(oldmnt);
@@ -1102,29 +1109,30 @@ static int fastcall do_path_lookup(int dfd, const char *name,
        int retval = 0;
        int fput_needed;
        struct file *file;
+       struct fs_struct *fs = current->fs;
 
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
        nd->flags = flags;
        nd->depth = 0;
 
        if (*name=='/') {
-               read_lock(&current->fs->lock);
-               if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
-                       nd->mnt = mntget(current->fs->altrootmnt);
-                       nd->dentry = dget(current->fs->altroot);
-                       read_unlock(&current->fs->lock);
+               read_lock(&fs->lock);
+               if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
+                       nd->mnt = mntget(fs->altrootmnt);
+                       nd->dentry = dget(fs->altroot);
+                       read_unlock(&fs->lock);
                        if (__emul_lookup_dentry(name,nd))
                                goto out; /* found in altroot */
-                       read_lock(&current->fs->lock);
+                       read_lock(&fs->lock);
                }
-               nd->mnt = mntget(current->fs->rootmnt);
-               nd->dentry = dget(current->fs->root);
-               read_unlock(&current->fs->lock);
+               nd->mnt = mntget(fs->rootmnt);
+               nd->dentry = dget(fs->root);
+               read_unlock(&fs->lock);
        } else if (dfd == AT_FDCWD) {
-               read_lock(&current->fs->lock);
-               nd->mnt = mntget(current->fs->pwdmnt);
-               nd->dentry = dget(current->fs->pwd);
-               read_unlock(&current->fs->lock);
+               read_lock(&fs->lock);
+               nd->mnt = mntget(fs->pwdmnt);
+               nd->dentry = dget(fs->pwd);
+               read_unlock(&fs->lock);
        } else {
                struct dentry *dentry;
 
@@ -1587,6 +1595,24 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
        return 0;
 }
 
+static int open_namei_create(struct nameidata *nd, struct path *path,
+                               int flag, int mode)
+{
+       int error;
+       struct dentry *dir = nd->dentry;
+
+       if (!IS_POSIXACL(dir->d_inode))
+               mode &= ~current->fs->umask;
+       error = vfs_create(dir->d_inode, path->dentry, mode, nd);
+       mutex_unlock(&dir->d_inode->i_mutex);
+       dput(nd->dentry);
+       nd->dentry = path->dentry;
+       if (error)
+               return error;
+       /* Don't check for write permission, don't truncate */
+       return may_open(nd, 0, flag & ~O_TRUNC);
+}
+
 /*
  *     open_namei()
  *
@@ -1668,18 +1694,10 @@ do_last:
 
        /* Negative dentry, just create the file */
        if (!path.dentry->d_inode) {
-               if (!IS_POSIXACL(dir->d_inode))
-                       mode &= ~current->fs->umask;
-               error = vfs_create(dir->d_inode, path.dentry, mode, nd);
-               mutex_unlock(&dir->d_inode->i_mutex);
-               dput(nd->dentry);
-               nd->dentry = path.dentry;
+               error = open_namei_create(nd, &path, flag, mode);
                if (error)
                        goto exit;
-               /* Don't check for write permission, don't truncate */
-               acc_mode = 0;
-               flag &= ~O_TRUNC;
-               goto ok;
+               return 0;
        }
 
        /*
@@ -1926,30 +1944,32 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
 {
        int error = 0;
        char * tmp;
+       struct dentry *dentry;
+       struct nameidata nd;
 
        tmp = getname(pathname);
        error = PTR_ERR(tmp);
-       if (!IS_ERR(tmp)) {
-               struct dentry *dentry;
-               struct nameidata nd;
+       if (IS_ERR(tmp))
+               goto out_err;
 
-               error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
-               if (error)
-                       goto out;
-               dentry = lookup_create(&nd, 1);
-               error = PTR_ERR(dentry);
-               if (!IS_ERR(dentry)) {
-                       if (!IS_POSIXACL(nd.dentry->d_inode))
-                               mode &= ~current->fs->umask;
-                       error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
-                       dput(dentry);
-               }
-               mutex_unlock(&nd.dentry->d_inode->i_mutex);
-               path_release(&nd);
-out:
-               putname(tmp);
-       }
+       error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
+       if (error)
+               goto out;
+       dentry = lookup_create(&nd, 1);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
+               goto out_unlock;
 
+       if (!IS_POSIXACL(nd.dentry->d_inode))
+               mode &= ~current->fs->umask;
+       error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
+       dput(dentry);
+out_unlock:
+       mutex_unlock(&nd.dentry->d_inode->i_mutex);
+       path_release(&nd);
+out:
+       putname(tmp);
+out_err:
        return error;
 }
 
@@ -2048,10 +2068,11 @@ static long do_rmdir(int dfd, const char __user *pathname)
        mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
        dentry = lookup_hash(&nd);
        error = PTR_ERR(dentry);
-       if (!IS_ERR(dentry)) {
-               error = vfs_rmdir(nd.dentry->d_inode, dentry);
-               dput(dentry);
-       }
+       if (IS_ERR(dentry))
+               goto exit2;
+       error = vfs_rmdir(nd.dentry->d_inode, dentry);
+       dput(dentry);
+exit2:
        mutex_unlock(&nd.dentry->d_inode->i_mutex);
 exit1:
        path_release(&nd);
@@ -2191,30 +2212,33 @@ asmlinkage long sys_symlinkat(const char __user *oldname,
        int error = 0;
        char * from;
        char * to;
+       struct dentry *dentry;
+       struct nameidata nd;
 
        from = getname(oldname);
        if(IS_ERR(from))
                return PTR_ERR(from);
        to = getname(newname);
        error = PTR_ERR(to);
-       if (!IS_ERR(to)) {
-               struct dentry *dentry;
-               struct nameidata nd;
+       if (IS_ERR(to))
+               goto out_putname;
 
-               error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
-               if (error)
-                       goto out;
-               dentry = lookup_create(&nd, 0);
-               error = PTR_ERR(dentry);
-               if (!IS_ERR(dentry)) {
-                       error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
-                       dput(dentry);
-               }
-               mutex_unlock(&nd.dentry->d_inode->i_mutex);
-               path_release(&nd);
+       error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
+       if (error)
+               goto out;
+       dentry = lookup_create(&nd, 0);
+       error = PTR_ERR(dentry);
+       if (IS_ERR(dentry))
+               goto out_unlock;
+
+       error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
+       dput(dentry);
+out_unlock:
+       mutex_unlock(&nd.dentry->d_inode->i_mutex);
+       path_release(&nd);
 out:
-               putname(to);
-       }
+       putname(to);
+out_putname:
        putname(from);
        return error;
 }
@@ -2300,10 +2324,11 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
                goto out_release;
        new_dentry = lookup_create(&nd, 0);
        error = PTR_ERR(new_dentry);
-       if (!IS_ERR(new_dentry)) {
-               error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
-               dput(new_dentry);
-       }
+       if (IS_ERR(new_dentry))
+               goto out_unlock;
+       error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+       dput(new_dentry);
+out_unlock:
        mutex_unlock(&nd.dentry->d_inode->i_mutex);
 out_release:
        path_release(&nd);