Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[pandora-kernel.git] / fs / namei.c
index 6301963..5c867dd 100644 (file)
@@ -238,7 +238,8 @@ int generic_permission(struct inode *inode, int mask, unsigned int flags,
 
        /*
         * Read/write DACs are always overridable.
-        * Executable DACs are overridable if at least one exec bit is set.
+        * Executable DACs are overridable for all directories and
+        * for non-directories that have least one exec bit set.
         */
        if (!(mask & MAY_EXEC) || execute_ok(inode))
                if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
@@ -432,6 +433,8 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
                        goto err_parent;
                BUG_ON(nd->inode != parent->d_inode);
        } else {
+               if (dentry->d_parent != parent)
+                       goto err_parent;
                spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
                if (!__d_rcu_to_refcount(dentry, nd->seq))
                        goto err_child;
@@ -812,6 +815,11 @@ static int follow_automount(struct path *path, unsigned flags,
        if (!mnt) /* mount collision */
                return 0;
 
+       if (!*need_mntput) {
+               /* lock_mount() may release path->mnt on error */
+               mntget(path->mnt);
+               *need_mntput = true;
+       }
        err = finish_automount(mnt, path);
 
        switch (err) {
@@ -819,12 +827,9 @@ static int follow_automount(struct path *path, unsigned flags,
                /* Someone else made a mount here whilst we were busy */
                return 0;
        case 0:
-               dput(path->dentry);
-               if (*need_mntput)
-                       mntput(path->mnt);
+               path_put(path);
                path->mnt = mnt;
                path->dentry = dget(mnt->mnt_root);
-               *need_mntput = true;
                return 0;
        default:
                return err;
@@ -844,9 +849,10 @@ static int follow_automount(struct path *path, unsigned flags,
  */
 static int follow_managed(struct path *path, unsigned flags)
 {
+       struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */
        unsigned managed;
        bool need_mntput = false;
-       int ret;
+       int ret = 0;
 
        /* Given that we're not holding a lock here, we retain the value in a
         * local variable for each dentry as we look at it so that we don't see
@@ -861,7 +867,7 @@ static int follow_managed(struct path *path, unsigned flags)
                        BUG_ON(!path->dentry->d_op->d_manage);
                        ret = path->dentry->d_op->d_manage(path->dentry, false);
                        if (ret < 0)
-                               return ret == -EISDIR ? 0 : ret;
+                               break;
                }
 
                /* Transit to a mounted filesystem. */
@@ -887,14 +893,19 @@ static int follow_managed(struct path *path, unsigned flags)
                if (managed & DCACHE_NEED_AUTOMOUNT) {
                        ret = follow_automount(path, flags, &need_mntput);
                        if (ret < 0)
-                               return ret == -EISDIR ? 0 : ret;
+                               break;
                        continue;
                }
 
                /* We didn't change the current path point */
                break;
        }
-       return 0;
+
+       if (need_mntput && path->mnt == mnt)
+               mntput(path->mnt);
+       if (ret == -EISDIR)
+               ret = 0;
+       return ret;
 }
 
 int follow_down_one(struct path *path)
@@ -1003,9 +1014,6 @@ failed:
  * Follow down to the covering mount currently visible to userspace.  At each
  * point, the filesystem owning that dentry may be queried as to whether the
  * caller is permitted to proceed or not.
- *
- * Care must be taken as namespace_sem may be held (indicated by mounting_here
- * being true).
  */
 int follow_down(struct path *path)
 {