UBUNTU: Ubuntu-2.6.38-12.51
[linux-flexiantxendom0-natty.git] / fs / namei.c
index 42d2d28..44890c6 100644 (file)
@@ -169,8 +169,8 @@ EXPORT_SYMBOL(putname);
 /*
  * This does basic POSIX ACL permission checking
  */
-static int acl_permission_check(struct inode *inode, int mask,
-               int (*check_acl)(struct inode *inode, int mask))
+static int acl_permission_check(struct inode *inode, int mask, unsigned int flags,
+               int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
 {
        umode_t                 mode = inode->i_mode;
 
@@ -180,7 +180,7 @@ static int acl_permission_check(struct inode *inode, int mask,
                mode >>= 6;
        else {
                if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) {
-                       int error = check_acl(inode, mask);
+                       int error = check_acl(inode, mask, flags);
                        if (error != -EAGAIN)
                                return error;
                }
@@ -198,25 +198,30 @@ static int acl_permission_check(struct inode *inode, int mask,
 }
 
 /**
- * generic_permission  -  check for access rights on a Posix-like filesystem
+ * generic_permission -  check for access rights on a Posix-like filesystem
  * @inode:     inode to check access rights for
  * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
  * @check_acl: optional callback to check for Posix ACLs
+ * @flags:     IPERM_FLAG_ flags.
  *
  * Used to check for read/write/execute permissions on a file.
  * We use "fsuid" for this, letting us set arbitrary permissions
  * for filesystem access without changing the "normal" uids which
- * are used for other things..
+ * are used for other things.
+ *
+ * generic_permission is rcu-walk aware. It returns -ECHILD in case an rcu-walk
+ * request cannot be satisfied (eg. requires blocking or too much complexity).
+ * It would then be called again in ref-walk mode.
  */
-int generic_permission(struct inode *inode, int mask,
-               int (*check_acl)(struct inode *inode, int mask))
+int generic_permission(struct inode *inode, int mask, unsigned int flags,
+       int (*check_acl)(struct inode *inode, int mask, unsigned int flags))
 {
        int ret;
 
        /*
         * Do the basic POSIX ACL permission checks.
         */
-       ret = acl_permission_check(inode, mask, check_acl);
+       ret = acl_permission_check(inode, mask, flags, check_acl);
        if (ret != -EACCES)
                return ret;
 
@@ -271,9 +276,10 @@ int inode_permission(struct inode *inode, int mask)
        }
 
        if (inode->i_op->permission)
-               retval = inode->i_op->permission(inode, mask);
+               retval = inode->i_op->permission(inode, mask, 0);
        else
-               retval = generic_permission(inode, mask, inode->i_op->check_acl);
+               retval = generic_permission(inode, mask, 0,
+                               inode->i_op->check_acl);
 
        if (retval)
                return retval;
@@ -347,6 +353,7 @@ int deny_write_access(struct file * file)
 
        return 0;
 }
+EXPORT_SYMBOL(deny_write_access);
 
 /**
  * path_get - get a reference to a path
@@ -375,21 +382,197 @@ void path_put(struct path *path)
 EXPORT_SYMBOL(path_put);
 
 /**
+ * nameidata_drop_rcu - drop this nameidata out of rcu-walk
+ * @nd: nameidata pathwalk data to drop
+ * Returns: 0 on success, -ECHILD on failure
+ *
+ * Path walking has 2 modes, rcu-walk and ref-walk (see
+ * Documentation/filesystems/path-lookup.txt). __drop_rcu* functions attempt
+ * to drop out of rcu-walk mode and take normal reference counts on dentries
+ * and vfsmounts to transition to rcu-walk mode. __drop_rcu* functions take
+ * refcounts at the last known good point before rcu-walk got stuck, so
+ * ref-walk may continue from there. If this is not successful (eg. a seqcount
+ * has changed), then failure is returned and path walk restarts from the
+ * beginning in ref-walk mode.
+ *
+ * nameidata_drop_rcu attempts to drop the current nd->path and nd->root into
+ * ref-walk. Must be called from rcu-walk context.
+ */
+static int nameidata_drop_rcu(struct nameidata *nd)
+{
+       struct fs_struct *fs = current->fs;
+       struct dentry *dentry = nd->path.dentry;
+
+       BUG_ON(!(nd->flags & LOOKUP_RCU));
+       if (nd->root.mnt) {
+               spin_lock(&fs->lock);
+               if (nd->root.mnt != fs->root.mnt ||
+                               nd->root.dentry != fs->root.dentry)
+                       goto err_root;
+       }
+       spin_lock(&dentry->d_lock);
+       if (!__d_rcu_to_refcount(dentry, nd->seq))
+               goto err;
+       BUG_ON(nd->inode != dentry->d_inode);
+       spin_unlock(&dentry->d_lock);
+       if (nd->root.mnt) {
+               path_get(&nd->root);
+               spin_unlock(&fs->lock);
+       }
+       mntget(nd->path.mnt);
+
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+       nd->flags &= ~LOOKUP_RCU;
+       return 0;
+err:
+       spin_unlock(&dentry->d_lock);
+err_root:
+       if (nd->root.mnt)
+               spin_unlock(&fs->lock);
+       return -ECHILD;
+}
+
+/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
+static inline int nameidata_drop_rcu_maybe(struct nameidata *nd)
+{
+       if (nd->flags & LOOKUP_RCU)
+               return nameidata_drop_rcu(nd);
+       return 0;
+}
+
+/**
+ * nameidata_dentry_drop_rcu - drop nameidata and dentry out of rcu-walk
+ * @nd: nameidata pathwalk data to drop
+ * @dentry: dentry to drop
+ * Returns: 0 on success, -ECHILD on failure
+ *
+ * nameidata_dentry_drop_rcu attempts to drop the current nd->path and nd->root,
+ * and dentry into ref-walk. @dentry must be a path found by a do_lookup call on
+ * @nd. Must be called from rcu-walk context.
+ */
+static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry)
+{
+       struct fs_struct *fs = current->fs;
+       struct dentry *parent = nd->path.dentry;
+
+       BUG_ON(!(nd->flags & LOOKUP_RCU));
+       if (nd->root.mnt) {
+               spin_lock(&fs->lock);
+               if (nd->root.mnt != fs->root.mnt ||
+                               nd->root.dentry != fs->root.dentry)
+                       goto err_root;
+       }
+       spin_lock(&parent->d_lock);
+       spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
+       if (!__d_rcu_to_refcount(dentry, nd->seq))
+               goto err;
+       /*
+        * If the sequence check on the child dentry passed, then the child has
+        * not been removed from its parent. This means the parent dentry must
+        * be valid and able to take a reference at this point.
+        */
+       BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
+       BUG_ON(!parent->d_count);
+       parent->d_count++;
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&parent->d_lock);
+       if (nd->root.mnt) {
+               path_get(&nd->root);
+               spin_unlock(&fs->lock);
+       }
+       mntget(nd->path.mnt);
+
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+       nd->flags &= ~LOOKUP_RCU;
+       return 0;
+err:
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&parent->d_lock);
+err_root:
+       if (nd->root.mnt)
+               spin_unlock(&fs->lock);
+       return -ECHILD;
+}
+
+/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
+static inline int nameidata_dentry_drop_rcu_maybe(struct nameidata *nd, struct dentry *dentry)
+{
+       if (nd->flags & LOOKUP_RCU)
+               return nameidata_dentry_drop_rcu(nd, dentry);
+       return 0;
+}
+
+/**
+ * nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk
+ * @nd: nameidata pathwalk data to drop
+ * Returns: 0 on success, -ECHILD on failure
+ *
+ * nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk.
+ * nd->path should be the final element of the lookup, so nd->root is discarded.
+ * Must be called from rcu-walk context.
+ */
+static int nameidata_drop_rcu_last(struct nameidata *nd)
+{
+       struct dentry *dentry = nd->path.dentry;
+
+       BUG_ON(!(nd->flags & LOOKUP_RCU));
+       nd->flags &= ~LOOKUP_RCU;
+       nd->root.mnt = NULL;
+       spin_lock(&dentry->d_lock);
+       if (!__d_rcu_to_refcount(dentry, nd->seq))
+               goto err_unlock;
+       BUG_ON(nd->inode != dentry->d_inode);
+       spin_unlock(&dentry->d_lock);
+
+       mntget(nd->path.mnt);
+
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+
+       return 0;
+
+err_unlock:
+       spin_unlock(&dentry->d_lock);
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+       return -ECHILD;
+}
+
+/* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing.  */
+static inline int nameidata_drop_rcu_last_maybe(struct nameidata *nd)
+{
+       if (likely(nd->flags & LOOKUP_RCU))
+               return nameidata_drop_rcu_last(nd);
+       return 0;
+}
+
+/**
  * release_open_intent - free up open intent resources
  * @nd: pointer to nameidata
  */
 void release_open_intent(struct nameidata *nd)
 {
-       if (nd->intent.open.file->f_path.dentry == NULL)
-               put_filp(nd->intent.open.file);
-       else
-               fput(nd->intent.open.file);
+       struct file *file = nd->intent.open.file;
+
+       if (file && !IS_ERR(file)) {
+               if (file->f_path.dentry == NULL)
+                       put_filp(file);
+               else
+                       fput(file);
+       }
 }
 
-static inline struct dentry *
+static inline int d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       return dentry->d_op->d_revalidate(dentry, nd);
+}
+
+static struct dentry *
 do_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
-       int status = dentry->d_op->d_revalidate(dentry, nd);
+       int status = d_revalidate(dentry, nd);
        if (unlikely(status <= 0)) {
                /*
                 * The dentry failed validation.
@@ -397,19 +580,51 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd)
                 * the dentry otherwise d_revalidate is asking us
                 * to return a fail status.
                 */
-               if (!status) {
-                       if (!d_invalidate(dentry)) {
-                               dput(dentry);
-                               dentry = NULL;
-                       }
-               } else {
+               if (status < 0) {
                        dput(dentry);
                        dentry = ERR_PTR(status);
+               } else if (!d_invalidate(dentry)) {
+                       dput(dentry);
+                       dentry = NULL;
                }
        }
        return dentry;
 }
 
+static inline struct dentry *
+do_revalidate_rcu(struct dentry *dentry, struct nameidata *nd)
+{
+       int status = d_revalidate(dentry, nd);
+       if (likely(status > 0))
+               return dentry;
+       if (status == -ECHILD) {
+               if (nameidata_dentry_drop_rcu(nd, dentry))
+                       return ERR_PTR(-ECHILD);
+               return do_revalidate(dentry, nd);
+       }
+       if (status < 0)
+               return ERR_PTR(status);
+       /* Don't d_invalidate in rcu-walk mode */
+       if (nameidata_dentry_drop_rcu(nd, dentry))
+               return ERR_PTR(-ECHILD);
+       if (!d_invalidate(dentry)) {
+               dput(dentry);
+               dentry = NULL;
+       }
+       return dentry;
+}
+
+static inline int need_reval_dot(struct dentry *dentry)
+{
+       if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE)))
+               return 0;
+
+       if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)))
+               return 0;
+
+       return 1;
+}
+
 /*
  * force_reval_path - force revalidation of a dentry
  *
@@ -433,13 +648,12 @@ force_reval_path(struct path *path, struct nameidata *nd)
 
        /*
         * only check on filesystems where it's possible for the dentry to
-        * become stale. It's assumed that if this flag is set then the
-        * d_revalidate op will also be defined.
+        * become stale.
         */
-       if (!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT))
+       if (!need_reval_dot(dentry))
                return 0;
 
-       status = dentry->d_op->d_revalidate(dentry, nd);
+       status = d_revalidate(dentry, nd);
        if (status > 0)
                return 0;
 
@@ -459,43 +673,55 @@ force_reval_path(struct path *path, struct nameidata *nd)
  * short-cut DAC fails, then call ->permission() to do more
  * complete permission check.
  */
-static int exec_permission(struct inode *inode)
+static inline int exec_permission(struct inode *inode, unsigned int flags)
 {
        int ret;
 
        if (inode->i_op->permission) {
-               ret = inode->i_op->permission(inode, MAY_EXEC);
-               if (!ret)
-                       goto ok;
-               return ret;
+               ret = inode->i_op->permission(inode, MAY_EXEC, flags);
+       } else {
+               ret = acl_permission_check(inode, MAY_EXEC, flags,
+                               inode->i_op->check_acl);
        }
-       ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl);
-       if (!ret)
+       if (likely(!ret))
                goto ok;
+       if (ret == -ECHILD)
+               return ret;
 
        if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH))
                goto ok;
 
        return ret;
 ok:
-       return security_inode_permission(inode, MAY_EXEC);
+       return security_inode_exec_permission(inode, flags);
 }
 
 static __always_inline void set_root(struct nameidata *nd)
 {
+       if (!nd->root.mnt)
+               get_fs_root(current->fs, &nd->root);
+}
+
+static int link_path_walk(const char *, struct nameidata *);
+
+static __always_inline void set_root_rcu(struct nameidata *nd)
+{
        if (!nd->root.mnt) {
                struct fs_struct *fs = current->fs;
-               read_lock(&fs->lock);
-               nd->root = fs->root;
-               path_get(&nd->root);
-               read_unlock(&fs->lock);
+               unsigned seq;
+
+               do {
+                       seq = read_seqcount_begin(&fs->seq);
+                       nd->root = fs->root;
+                       nd->seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
+               } while (read_seqcount_retry(&fs->seq, seq));
        }
 }
 
-static int link_path_walk(const char *, struct nameidata *);
-
 static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
 {
+       int ret;
+
        if (IS_ERR(link))
                goto fail;
 
@@ -505,8 +731,10 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l
                nd->path = nd->root;
                path_get(&nd->root);
        }
+       nd->inode = nd->path.dentry->d_inode;
 
-       return link_path_walk(link, nd);
+       ret = link_path_walk(link, nd);
+       return ret;
 fail:
        path_put(&nd->path);
        return PTR_ERR(link);
@@ -519,30 +747,32 @@ static void path_put_conditional(struct path *path, struct nameidata *nd)
                mntput(path->mnt);
 }
 
-static inline void path_to_nameidata(struct path *path, struct nameidata *nd)
+static inline void path_to_nameidata(const struct path *path,
+                                       struct nameidata *nd)
 {
-       dput(nd->path.dentry);
-       if (nd->path.mnt != path->mnt) {
-               mntput(nd->path.mnt);
-               nd->path.mnt = path->mnt;
+       if (!(nd->flags & LOOKUP_RCU)) {
+               dput(nd->path.dentry);
+               if (nd->path.mnt != path->mnt)
+                       mntput(nd->path.mnt);
        }
+       nd->path.mnt = path->mnt;
        nd->path.dentry = path->dentry;
 }
 
 static __always_inline int
-__do_follow_link(struct path *path, struct nameidata *nd, void **p)
+__do_follow_link(const struct path *link, struct nameidata *nd, void **p)
 {
        int error;
-       struct dentry *dentry = path->dentry;
+       struct dentry *dentry = link->dentry;
 
-       touch_atime(path->mnt, dentry);
+       BUG_ON(nd->flags & LOOKUP_RCU);
+
+       touch_atime(link->mnt, dentry);
        nd_set_link(nd, NULL);
 
-       if (path->mnt != nd->path.mnt) {
-               path_to_nameidata(path, nd);
-               dget(dentry);
-       }
-       mntget(path->mnt);
+       if (link->mnt == nd->path.mnt)
+               mntget(link->mnt);
+
        nd->last_type = LAST_BIND;
        *p = dentry->d_inode->i_op->follow_link(dentry, nd);
        error = PTR_ERR(*p);
@@ -567,10 +797,16 @@ __do_follow_link(struct path *path, struct nameidata *nd, void **p)
  * Without that kind of total limit, nasty chains of consecutive
  * symlinks can cause almost arbitrarily long lookups. 
  */
-static inline int do_follow_link(struct path *path, struct nameidata *nd)
+static inline int do_follow_link(struct inode *inode, struct path *path, struct nameidata *nd)
 {
        void *cookie;
        int err = -ELOOP;
+
+       /* We drop rcu-walk here */
+       if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry))
+               return -ECHILD;
+       BUG_ON(inode != path->dentry->d_inode);
+
        if (current->link_count >= MAX_NESTED_LINKS)
                goto loop;
        if (current->total_link_count >= 40)
@@ -596,19 +832,34 @@ loop:
        return err;
 }
 
+static int follow_up_rcu(struct path *path)
+{
+       struct vfsmount *parent;
+       struct dentry *mountpoint;
+
+       parent = path->mnt->mnt_parent;
+       if (parent == path->mnt)
+               return 0;
+       mountpoint = path->mnt->mnt_mountpoint;
+       path->dentry = mountpoint;
+       path->mnt = parent;
+       return 1;
+}
+
 int follow_up(struct path *path)
 {
        struct vfsmount *parent;
        struct dentry *mountpoint;
-       spin_lock(&vfsmount_lock);
+
+       br_read_lock(vfsmount_lock);
        parent = path->mnt->mnt_parent;
        if (parent == path->mnt) {
-               spin_unlock(&vfsmount_lock);
+               br_read_unlock(vfsmount_lock);
                return 0;
        }
        mntget(parent);
        mountpoint = dget(path->mnt->mnt_mountpoint);
-       spin_unlock(&vfsmount_lock);
+       br_read_unlock(vfsmount_lock);
        dput(path->dentry);
        path->dentry = mountpoint;
        mntput(path->mnt);
@@ -616,58 +867,295 @@ int follow_up(struct path *path)
        return 1;
 }
 
-/* no need for dcache_lock, as serialization is taken care in
- * namespace.c
+/*
+ * Perform an automount
+ * - return -EISDIR to tell follow_managed() to stop and return the path we
+ *   were called with.
  */
-static int __follow_mount(struct path *path)
+static int follow_automount(struct path *path, unsigned flags,
+                           bool *need_mntput)
 {
-       int res = 0;
-       while (d_mountpoint(path->dentry)) {
-               struct vfsmount *mounted = lookup_mnt(path);
-               if (!mounted)
-                       break;
+       struct vfsmount *mnt;
+       int err;
+
+       if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
+               return -EREMOTE;
+
+       /* We don't want to mount if someone supplied AT_NO_AUTOMOUNT
+        * and this is the terminal part of the path.
+        */
+       if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE))
+               return -EISDIR; /* we actually want to stop here */
+
+       /* We want to mount if someone is trying to open/create a file of any
+        * type under the mountpoint, wants to traverse through the mountpoint
+        * or wants to open the mounted directory.
+        *
+        * We don't want to mount if someone's just doing a stat and they've
+        * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
+        * appended a '/' to the name.
+        */
+       if (!(flags & LOOKUP_FOLLOW) &&
+           !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY |
+                      LOOKUP_OPEN | LOOKUP_CREATE)))
+               return -EISDIR;
+
+       current->total_link_count++;
+       if (current->total_link_count >= 40)
+               return -ELOOP;
+
+       mnt = path->dentry->d_op->d_automount(path);
+       if (IS_ERR(mnt)) {
+               /*
+                * The filesystem is allowed to return -EISDIR here to indicate
+                * it doesn't want to automount.  For instance, autofs would do
+                * this so that its userspace daemon can mount on this dentry.
+                *
+                * However, we can only permit this if it's a terminal point in
+                * the path being looked up; if it wasn't then the remainder of
+                * the path is inaccessible and we should say so.
+                */
+               if (PTR_ERR(mnt) == -EISDIR && (flags & LOOKUP_CONTINUE))
+                       return -EREMOTE;
+               return PTR_ERR(mnt);
+       }
+
+       if (!mnt) /* mount collision */
+               return 0;
+
+       err = finish_automount(mnt, path);
+
+       switch (err) {
+       case -EBUSY:
+               /* Someone else made a mount here whilst we were busy */
+               return 0;
+       case 0:
                dput(path->dentry);
-               if (res)
+               if (*need_mntput)
                        mntput(path->mnt);
+               path->mnt = mnt;
+               path->dentry = dget(mnt->mnt_root);
+               *need_mntput = true;
+               return 0;
+       default:
+               return err;
+       }
+
+}
+
+/*
+ * Handle a dentry that is managed in some way.
+ * - Flagged for transit management (autofs)
+ * - Flagged as mountpoint
+ * - Flagged as automount point
+ *
+ * This may only be called in refwalk mode.
+ *
+ * Serialization is taken care of in namespace.c
+ */
+static int follow_managed(struct path *path, unsigned flags)
+{
+       unsigned managed;
+       bool need_mntput = false;
+       int ret;
+
+       /* 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
+        * the components of that value change under us */
+       while (managed = ACCESS_ONCE(path->dentry->d_flags),
+              managed &= DCACHE_MANAGED_DENTRY,
+              unlikely(managed != 0)) {
+               /* Allow the filesystem to manage the transit without i_mutex
+                * being held. */
+               if (managed & DCACHE_MANAGE_TRANSIT) {
+                       BUG_ON(!path->dentry->d_op);
+                       BUG_ON(!path->dentry->d_op->d_manage);
+                       ret = path->dentry->d_op->d_manage(path->dentry,
+                                                          false, false);
+                       if (ret < 0)
+                               return ret == -EISDIR ? 0 : ret;
+               }
+
+               /* Transit to a mounted filesystem. */
+               if (managed & DCACHE_MOUNTED) {
+                       struct vfsmount *mounted = lookup_mnt(path);
+                       if (mounted) {
+                               dput(path->dentry);
+                               if (need_mntput)
+                                       mntput(path->mnt);
+                               path->mnt = mounted;
+                               path->dentry = dget(mounted->mnt_root);
+                               need_mntput = true;
+                               continue;
+                       }
+
+                       /* Something is mounted on this dentry in another
+                        * namespace and/or whatever was mounted there in this
+                        * namespace got unmounted before we managed to get the
+                        * vfsmount_lock */
+               }
+
+               /* Handle an automount point */
+               if (managed & DCACHE_NEED_AUTOMOUNT) {
+                       ret = follow_automount(path, flags, &need_mntput);
+                       if (ret < 0)
+                               return ret == -EISDIR ? 0 : ret;
+                       continue;
+               }
+
+               /* We didn't change the current path point */
+               break;
+       }
+       return 0;
+}
+
+int follow_down_one(struct path *path)
+{
+       struct vfsmount *mounted;
+
+       mounted = lookup_mnt(path);
+       if (mounted) {
+               dput(path->dentry);
+               mntput(path->mnt);
                path->mnt = mounted;
                path->dentry = dget(mounted->mnt_root);
-               res = 1;
+               return 1;
        }
-       return res;
+       return 0;
 }
 
-static void follow_mount(struct path *path)
+/*
+ * Skip to top of mountpoint pile in rcuwalk mode.  We abort the rcu-walk if we
+ * meet a managed dentry and we're not walking to "..".  True is returned to
+ * continue, false to abort.
+ */
+static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
+                              struct inode **inode, bool reverse_transit)
 {
        while (d_mountpoint(path->dentry)) {
-               struct vfsmount *mounted = lookup_mnt(path);
+               struct vfsmount *mounted;
+               if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
+                   !reverse_transit &&
+                   path->dentry->d_op->d_manage(path->dentry, false, true) < 0)
+                       return false;
+               mounted = __lookup_mnt(path->mnt, path->dentry, 1);
                if (!mounted)
                        break;
-               dput(path->dentry);
-               mntput(path->mnt);
                path->mnt = mounted;
-               path->dentry = dget(mounted->mnt_root);
+               path->dentry = mounted->mnt_root;
+               nd->seq = read_seqcount_begin(&path->dentry->d_seq);
+               *inode = path->dentry->d_inode;
+       }
+
+       if (unlikely(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
+               return reverse_transit;
+       return true;
+}
+
+static int follow_dotdot_rcu(struct nameidata *nd)
+{
+       struct inode *inode = nd->inode;
+
+       set_root_rcu(nd);
+
+       while (1) {
+               if (nd->path.dentry == nd->root.dentry &&
+                   nd->path.mnt == nd->root.mnt) {
+                       break;
+               }
+               if (nd->path.dentry != nd->path.mnt->mnt_root) {
+                       struct dentry *old = nd->path.dentry;
+                       struct dentry *parent = old->d_parent;
+                       unsigned seq;
+
+                       seq = read_seqcount_begin(&parent->d_seq);
+                       if (read_seqcount_retry(&old->d_seq, nd->seq))
+                               return -ECHILD;
+                       inode = parent->d_inode;
+                       nd->path.dentry = parent;
+                       nd->seq = seq;
+                       break;
+               }
+               if (!follow_up_rcu(&nd->path))
+                       break;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               inode = nd->path.dentry->d_inode;
        }
+       __follow_mount_rcu(nd, &nd->path, &inode, true);
+       nd->inode = inode;
+
+       return 0;
 }
 
-/* no need for dcache_lock, as serialization is taken care in
- * namespace.c
+/*
+ * 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)
+int follow_down(struct path *path, bool mounting_here)
 {
-       struct vfsmount *mounted;
+       unsigned managed;
+       int ret;
 
-       mounted = lookup_mnt(path);
-       if (mounted) {
+       while (managed = ACCESS_ONCE(path->dentry->d_flags),
+              unlikely(managed & DCACHE_MANAGED_DENTRY)) {
+               /* Allow the filesystem to manage the transit without i_mutex
+                * being held.
+                *
+                * We indicate to the filesystem if someone is trying to mount
+                * something here.  This gives autofs the chance to deny anyone
+                * other than its daemon the right to mount on its
+                * superstructure.
+                *
+                * The filesystem may sleep at this point.
+                */
+               if (managed & DCACHE_MANAGE_TRANSIT) {
+                       BUG_ON(!path->dentry->d_op);
+                       BUG_ON(!path->dentry->d_op->d_manage);
+                       ret = path->dentry->d_op->d_manage(
+                               path->dentry, mounting_here, false);
+                       if (ret < 0)
+                               return ret == -EISDIR ? 0 : ret;
+               }
+
+               /* Transit to a mounted filesystem. */
+               if (managed & DCACHE_MOUNTED) {
+                       struct vfsmount *mounted = lookup_mnt(path);
+                       if (!mounted)
+                               break;
+                       dput(path->dentry);
+                       mntput(path->mnt);
+                       path->mnt = mounted;
+                       path->dentry = dget(mounted->mnt_root);
+                       continue;
+               }
+
+               /* Don't handle automount points here */
+               break;
+       }
+       return 0;
+}
+
+/*
+ * Skip to top of mountpoint pile in refwalk mode for follow_dotdot()
+ */
+static void follow_mount(struct path *path)
+{
+       while (d_mountpoint(path->dentry)) {
+               struct vfsmount *mounted = lookup_mnt(path);
+               if (!mounted)
+                       break;
                dput(path->dentry);
                mntput(path->mnt);
                path->mnt = mounted;
                path->dentry = dget(mounted->mnt_root);
-               return 1;
        }
-       return 0;
 }
 
-static __always_inline void follow_dotdot(struct nameidata *nd)
+static void follow_dotdot(struct nameidata *nd)
 {
        set_root(nd);
 
@@ -688,6 +1176,36 @@ static __always_inline void follow_dotdot(struct nameidata *nd)
                        break;
        }
        follow_mount(&nd->path);
+       nd->inode = nd->path.dentry->d_inode;
+}
+
+/*
+ * Allocate a dentry with name and parent, and perform a parent
+ * directory ->lookup on it. Returns the new dentry, or ERR_PTR
+ * on error. parent->d_inode->i_mutex must be held. d_lookup must
+ * have verified that no child exists while under i_mutex.
+ */
+static struct dentry *d_alloc_and_lookup(struct dentry *parent,
+                               struct qstr *name, struct nameidata *nd)
+{
+       struct inode *inode = parent->d_inode;
+       struct dentry *dentry;
+       struct dentry *old;
+
+       /* Don't create child dentry for a dead directory. */
+       if (unlikely(IS_DEADDIR(inode)))
+               return ERR_PTR(-ENOENT);
+
+       dentry = d_alloc(parent, name);
+       if (unlikely(!dentry))
+               return ERR_PTR(-ENOMEM);
+
+       old = inode->i_op->lookup(inode, dentry, nd);
+       if (unlikely(old)) {
+               dput(dentry);
+               dentry = old;
+       }
+       return dentry;
 }
 
 /*
@@ -696,114 +1214,117 @@ static __always_inline void follow_dotdot(struct nameidata *nd)
  *  It _is_ time-critical.
  */
 static int do_lookup(struct nameidata *nd, struct qstr *name,
-                    struct path *path)
+                       struct path *path, struct inode **inode)
 {
        struct vfsmount *mnt = nd->path.mnt;
-       struct dentry *dentry, *parent;
+       struct dentry *dentry, *parent = nd->path.dentry;
        struct inode *dir;
+       int err;
+
        /*
         * See if the low-level filesystem might want
         * to use its own hash..
         */
-       if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) {
-               int err = nd->path.dentry->d_op->d_hash(nd->path.dentry, name);
+       if (unlikely(parent->d_flags & DCACHE_OP_HASH)) {
+               err = parent->d_op->d_hash(parent, nd->inode, name);
                if (err < 0)
                        return err;
        }
 
-       dentry = __d_lookup(nd->path.dentry, name);
+       /*
+        * Rename seqlock is not required here because in the off chance
+        * of a false negative due to a concurrent rename, we're going to
+        * do the non-racy lookup, below.
+        */
+       if (nd->flags & LOOKUP_RCU) {
+               unsigned seq;
+
+               *inode = nd->inode;
+               dentry = __d_lookup_rcu(parent, name, &seq, inode);
+               if (!dentry) {
+                       if (nameidata_drop_rcu(nd))
+                               return -ECHILD;
+                       goto need_lookup;
+               }
+               /* Memory barrier in read_seqcount_begin of child is enough */
+               if (__read_seqcount_retry(&parent->d_seq, nd->seq))
+                       return -ECHILD;
+
+               nd->seq = seq;
+               if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
+                       dentry = do_revalidate_rcu(dentry, nd);
+                       if (!dentry)
+                               goto need_lookup;
+                       if (IS_ERR(dentry))
+                               goto fail;
+                       if (!(nd->flags & LOOKUP_RCU))
+                               goto done;
+               }
+               path->mnt = mnt;
+               path->dentry = dentry;
+               if (likely(__follow_mount_rcu(nd, path, inode, false)))
+                       return 0;
+               if (nameidata_drop_rcu(nd))
+                       return -ECHILD;
+               /* fallthru */
+       }
+       dentry = __d_lookup(parent, name);
        if (!dentry)
                goto need_lookup;
-       if (dentry->d_op && dentry->d_op->d_revalidate)
-               goto need_revalidate;
+found:
+       if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) {
+               dentry = do_revalidate(dentry, nd);
+               if (!dentry)
+                       goto need_lookup;
+               if (IS_ERR(dentry))
+                       goto fail;
+       }
 done:
        path->mnt = mnt;
        path->dentry = dentry;
-       __follow_mount(path);
+       err = follow_managed(path, nd->flags);
+       if (unlikely(err < 0)) {
+               path_put_conditional(path, nd);
+               return err;
+       }
+       *inode = path->dentry->d_inode;
        return 0;
 
 need_lookup:
-       parent = nd->path.dentry;
        dir = parent->d_inode;
+       BUG_ON(nd->inode != dir);
 
        mutex_lock(&dir->i_mutex);
        /*
         * First re-do the cached lookup just in case it was created
-        * while we waited for the directory semaphore..
-        *
-        * FIXME! This could use version numbering or similar to
-        * avoid unnecessary cache lookups.
-        *
-        * The "dcache_lock" is purely to protect the RCU list walker
-        * from concurrent renames at this point (we mustn't get false
-        * negatives from the RCU list walk here, unlike the optimistic
-        * fast walk).
+        * while we waited for the directory semaphore, or the first
+        * lookup failed due to an unrelated rename.
         *
-        * so doing d_lookup() (with seqlock), instead of lockfree __d_lookup
+        * This could use version numbering or similar to avoid unnecessary
+        * cache lookups, but then we'd have to do the first lookup in the
+        * non-racy way. However in the common case here, everything should
+        * be hot in cache, so would it be a big win?
         */
        dentry = d_lookup(parent, name);
-       if (!dentry) {
-               struct dentry *new;
-
-               /* Don't create child dentry for a dead directory. */
-               dentry = ERR_PTR(-ENOENT);
-               if (IS_DEADDIR(dir))
-                       goto out_unlock;
-
-               new = d_alloc(parent, name);
-               dentry = ERR_PTR(-ENOMEM);
-               if (new) {
-                       dentry = dir->i_op->lookup(dir, new, nd);
-                       if (dentry)
-                               dput(new);
-                       else
-                               dentry = new;
-               }
-out_unlock:
+       if (likely(!dentry)) {
+               dentry = d_alloc_and_lookup(parent, name, nd);
                mutex_unlock(&dir->i_mutex);
                if (IS_ERR(dentry))
                        goto fail;
                goto done;
        }
-
        /*
         * Uhhuh! Nasty case: the cache was re-populated while
         * we waited on the semaphore. Need to revalidate.
         */
        mutex_unlock(&dir->i_mutex);
-       if (dentry->d_op && dentry->d_op->d_revalidate) {
-               dentry = do_revalidate(dentry, nd);
-               if (!dentry)
-                       dentry = ERR_PTR(-ENOENT);
-       }
-       if (IS_ERR(dentry))
-               goto fail;
-       goto done;
-
-need_revalidate:
-       dentry = do_revalidate(dentry, nd);
-       if (!dentry)
-               goto need_lookup;
-       if (IS_ERR(dentry))
-               goto fail;
-       goto done;
+       goto found;
 
 fail:
        return PTR_ERR(dentry);
 }
 
 /*
- * This is a temporary kludge to deal with "automount" symlinks; proper
- * solution is to trigger them on follow_mount(), so that do_lookup()
- * would DTRT.  To be killed before 2.6.34-final.
- */
-static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
-{
-       return inode && unlikely(inode->i_op->follow_link) &&
-               ((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode));
-}
-
-/*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
  * the final dentry. We expect 'base' to be positive and a directory.
@@ -814,7 +1335,6 @@ static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
 static int link_path_walk(const char *name, struct nameidata *nd)
 {
        struct path next;
-       struct inode *inode;
        int err;
        unsigned int lookup_flags = nd->flags;
        
@@ -823,18 +1343,28 @@ static int link_path_walk(const char *name, struct nameidata *nd)
        if (!*name)
                goto return_reval;
 
-       inode = nd->path.dentry->d_inode;
        if (nd->depth)
                lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
 
        /* At this point we know we have a real path component. */
        for(;;) {
+               struct inode *inode;
                unsigned long hash;
                struct qstr this;
                unsigned int c;
 
                nd->flags |= LOOKUP_CONTINUE;
-               err = exec_permission(inode);
+               if (nd->flags & LOOKUP_RCU) {
+                       err = exec_permission(nd->inode, IPERM_FLAG_RCU);
+                       if (err == -ECHILD) {
+                               if (nameidata_drop_rcu(nd))
+                                       return -ECHILD;
+                               goto exec_again;
+                       }
+               } else {
+exec_again:
+                       err = exec_permission(nd->inode, 0);
+               }
                if (err)
                        break;
 
@@ -865,37 +1395,40 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                if (this.name[0] == '.') switch (this.len) {
                        default:
                                break;
-                       case 2: 
+                       case 2:
                                if (this.name[1] != '.')
                                        break;
-                               follow_dotdot(nd);
-                               inode = nd->path.dentry->d_inode;
+                               if (nd->flags & LOOKUP_RCU) {
+                                       if (follow_dotdot_rcu(nd))
+                                               return -ECHILD;
+                               } else
+                                       follow_dotdot(nd);
                                /* fallthrough */
                        case 1:
                                continue;
                }
                /* This does the actual lookups.. */
-               err = do_lookup(nd, &this, &next);
+               err = do_lookup(nd, &this, &next, &inode);
                if (err)
                        break;
-
                err = -ENOENT;
-               inode = next.dentry->d_inode;
                if (!inode)
                        goto out_dput;
 
                if (inode->i_op->follow_link) {
-                       err = do_follow_link(&next, nd);
+                       err = do_follow_link(inode, &next, nd);
                        if (err)
                                goto return_err;
+                       nd->inode = nd->path.dentry->d_inode;
                        err = -ENOENT;
-                       inode = nd->path.dentry->d_inode;
-                       if (!inode)
+                       if (!nd->inode)
                                break;
-               } else
+               } else {
                        path_to_nameidata(&next, nd);
+                       nd->inode = inode;
+               }
                err = -ENOTDIR; 
-               if (!inode->i_op->lookup)
+               if (!nd->inode->i_op->lookup)
                        break;
                continue;
                /* here ends the main loop */
@@ -910,32 +1443,37 @@ last_component:
                if (this.name[0] == '.') switch (this.len) {
                        default:
                                break;
-                       case 2: 
+                       case 2:
                                if (this.name[1] != '.')
                                        break;
-                               follow_dotdot(nd);
-                               inode = nd->path.dentry->d_inode;
+                               if (nd->flags & LOOKUP_RCU) {
+                                       if (follow_dotdot_rcu(nd))
+                                               return -ECHILD;
+                               } else
+                                       follow_dotdot(nd);
                                /* fallthrough */
                        case 1:
                                goto return_reval;
                }
-               err = do_lookup(nd, &this, &next);
+               err = do_lookup(nd, &this, &next, &inode);
                if (err)
                        break;
-               inode = next.dentry->d_inode;
-               if (follow_on_final(inode, lookup_flags)) {
-                       err = do_follow_link(&next, nd);
+               if (inode && unlikely(inode->i_op->follow_link) &&
+                   (lookup_flags & LOOKUP_FOLLOW)) {
+                       err = do_follow_link(inode, &next, nd);
                        if (err)
                                goto return_err;
-                       inode = nd->path.dentry->d_inode;
-               } else
+                       nd->inode = nd->path.dentry->d_inode;
+               } else {
                        path_to_nameidata(&next, nd);
+                       nd->inode = inode;
+               }
                err = -ENOENT;
-               if (!inode)
+               if (!nd->inode)
                        break;
                if (lookup_flags & LOOKUP_DIRECTORY) {
                        err = -ENOTDIR; 
-                       if (!inode->i_op->lookup)
+                       if (!nd->inode->i_op->lookup)
                                break;
                }
                goto return_base;
@@ -955,25 +1493,46 @@ return_reval:
                 * We bypassed the ordinary revalidation routines.
                 * We may need to check the cached dentry for staleness.
                 */
-               if (nd->path.dentry && nd->path.dentry->d_sb &&
-                   (nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) {
-                       err = -ESTALE;
+               if (need_reval_dot(nd->path.dentry)) {
+                       if (nameidata_drop_rcu_last_maybe(nd))
+                               return -ECHILD;
                        /* Note: we do not d_invalidate() */
-                       if (!nd->path.dentry->d_op->d_revalidate(
-                                       nd->path.dentry, nd))
+                       err = d_revalidate(nd->path.dentry, nd);
+                       if (!err)
+                               err = -ESTALE;
+                       if (err < 0)
                                break;
+                       return 0;
                }
 return_base:
+               if (nameidata_drop_rcu_last_maybe(nd))
+                       return -ECHILD;
                return 0;
 out_dput:
-               path_put_conditional(&next, nd);
+               if (!(nd->flags & LOOKUP_RCU))
+                       path_put_conditional(&next, nd);
                break;
        }
-       path_put(&nd->path);
+       if (!(nd->flags & LOOKUP_RCU))
+               path_put(&nd->path);
 return_err:
        return err;
 }
 
+static inline int path_walk_rcu(const char *name, struct nameidata *nd)
+{
+       current->total_link_count = 0;
+
+       return link_path_walk(name, nd);
+}
+
+static inline int path_walk_simple(const char *name, struct nameidata *nd)
+{
+       current->total_link_count = 0;
+
+       return link_path_walk(name, nd);
+}
+
 static int path_walk(const char *name, struct nameidata *nd)
 {
        struct path save = nd->path;
@@ -989,6 +1548,7 @@ static int path_walk(const char *name, struct nameidata *nd)
                /* nd->path had been dropped */
                current->total_link_count = 0;
                nd->path = save;
+               nd->inode = save.dentry->d_inode;
                path_get(&nd->path);
                nd->flags |= LOOKUP_REVAL;
                result = link_path_walk(name, nd);
@@ -999,6 +1559,93 @@ static int path_walk(const char *name, struct nameidata *nd)
        return result;
 }
 
+static void path_finish_rcu(struct nameidata *nd)
+{
+       if (nd->flags & LOOKUP_RCU) {
+               /* RCU dangling. Cancel it. */
+               nd->flags &= ~LOOKUP_RCU;
+               nd->root.mnt = NULL;
+               rcu_read_unlock();
+               br_read_unlock(vfsmount_lock);
+       }
+       if (nd->file)
+               fput(nd->file);
+}
+
+static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
+{
+       int retval = 0;
+       int fput_needed;
+       struct file *file;
+
+       nd->last_type = LAST_ROOT; /* if there are only slashes... */
+       nd->flags = flags | LOOKUP_RCU;
+       nd->depth = 0;
+       nd->root.mnt = NULL;
+       nd->file = NULL;
+
+       if (*name=='/') {
+               struct fs_struct *fs = current->fs;
+               unsigned seq;
+
+               br_read_lock(vfsmount_lock);
+               rcu_read_lock();
+
+               do {
+                       seq = read_seqcount_begin(&fs->seq);
+                       nd->root = fs->root;
+                       nd->path = nd->root;
+                       nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
+               } while (read_seqcount_retry(&fs->seq, seq));
+
+       } else if (dfd == AT_FDCWD) {
+               struct fs_struct *fs = current->fs;
+               unsigned seq;
+
+               br_read_lock(vfsmount_lock);
+               rcu_read_lock();
+
+               do {
+                       seq = read_seqcount_begin(&fs->seq);
+                       nd->path = fs->pwd;
+                       nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
+               } while (read_seqcount_retry(&fs->seq, seq));
+
+       } else {
+               struct dentry *dentry;
+
+               file = fget_light(dfd, &fput_needed);
+               retval = -EBADF;
+               if (!file)
+                       goto out_fail;
+
+               dentry = file->f_path.dentry;
+
+               retval = -ENOTDIR;
+               if (!S_ISDIR(dentry->d_inode->i_mode))
+                       goto fput_fail;
+
+               retval = file_permission(file, MAY_EXEC);
+               if (retval)
+                       goto fput_fail;
+
+               nd->path = file->f_path;
+               if (fput_needed)
+                       nd->file = file;
+
+               nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
+               br_read_lock(vfsmount_lock);
+               rcu_read_lock();
+       }
+       nd->inode = nd->path.dentry->d_inode;
+       return 0;
+
+fput_fail:
+       fput_light(file, fput_needed);
+out_fail:
+       return retval;
+}
+
 static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd)
 {
        int retval = 0;
@@ -1015,11 +1662,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei
                nd->path = nd->root;
                path_get(&nd->root);
        } else if (dfd == AT_FDCWD) {
-               struct fs_struct *fs = current->fs;
-               read_lock(&fs->lock);
-               nd->path = fs->pwd;
-               path_get(&fs->pwd);
-               read_unlock(&fs->lock);
+               get_fs_pwd(current->fs, &nd->path);
        } else {
                struct dentry *dentry;
 
@@ -1043,6 +1686,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei
 
                fput_light(file, fput_needed);
        }
+       nd->inode = nd->path.dentry->d_inode;
        return 0;
 
 fput_fail:
@@ -1055,16 +1699,53 @@ out_fail:
 static int do_path_lookup(int dfd, const char *name,
                                unsigned int flags, struct nameidata *nd)
 {
-       int retval = path_init(dfd, name, flags, nd);
-       if (!retval)
-               retval = path_walk(name, nd);
-       if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
-                               nd->path.dentry->d_inode))
-               audit_inode(name, nd->path.dentry);
+       int retval;
+
+       /*
+        * Path walking is largely split up into 2 different synchronisation
+        * schemes, rcu-walk and ref-walk (explained in
+        * Documentation/filesystems/path-lookup.txt). These share much of the
+        * path walk code, but some things particularly setup, cleanup, and
+        * following mounts are sufficiently divergent that functions are
+        * duplicated. Typically there is a function foo(), and its RCU
+        * analogue, foo_rcu().
+        *
+        * -ECHILD is the error number of choice (just to avoid clashes) that
+        * is returned if some aspect of an rcu-walk fails. Such an error must
+        * be handled by restarting a traditional ref-walk (which will always
+        * be able to complete).
+        */
+       retval = path_init_rcu(dfd, name, flags, nd);
+       if (unlikely(retval))
+               return retval;
+       retval = path_walk_rcu(name, nd);
+       path_finish_rcu(nd);
        if (nd->root.mnt) {
                path_put(&nd->root);
                nd->root.mnt = NULL;
        }
+
+       if (unlikely(retval == -ECHILD || retval == -ESTALE)) {
+               /* slower, locked walk */
+               if (retval == -ESTALE)
+                       flags |= LOOKUP_REVAL;
+               retval = path_init(dfd, name, flags, nd);
+               if (unlikely(retval))
+                       return retval;
+               retval = path_walk(name, nd);
+               if (nd->root.mnt) {
+                       path_put(&nd->root);
+                       nd->root.mnt = NULL;
+               }
+       }
+
+       if (likely(!retval)) {
+               if (unlikely(!audit_dummy_context())) {
+                       if (nd->path.dentry && nd->inode)
+                               audit_inode(name, nd->path.dentry);
+               }
+       }
+
        return retval;
 }
 
@@ -1107,10 +1788,11 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
        path_get(&nd->path);
        nd->root = nd->path;
        path_get(&nd->root);
+       nd->inode = nd->path.dentry->d_inode;
 
        retval = path_walk(name, nd);
        if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
-                               nd->path.dentry->d_inode))
+                               nd->inode))
                audit_inode(name, nd->path.dentry);
 
        path_put(&nd->root);
@@ -1122,52 +1804,37 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
 static struct dentry *__lookup_hash(struct qstr *name,
                struct dentry *base, struct nameidata *nd)
 {
+       struct inode *inode = base->d_inode;
        struct dentry *dentry;
-       struct inode *inode;
        int err;
 
-       inode = base->d_inode;
+       err = exec_permission(inode, 0);
+       if (err)
+               return ERR_PTR(err);
 
        /*
         * See if the low-level filesystem might want
         * to use its own hash..
         */
-       if (base->d_op && base->d_op->d_hash) {
-               err = base->d_op->d_hash(base, name);
+       if (base->d_flags & DCACHE_OP_HASH) {
+               err = base->d_op->d_hash(base, inode, name);
                dentry = ERR_PTR(err);
                if (err < 0)
                        goto out;
        }
 
-       dentry = __d_lookup(base, name);
-
-       /* lockess __d_lookup may fail due to concurrent d_move()
-        * in some unrelated directory, so try with d_lookup
+       /*
+        * Don't bother with __d_lookup: callers are for creat as
+        * well as unlink, so a lot of the time it would cost
+        * a double lookup.
         */
-       if (!dentry)
-               dentry = d_lookup(base, name);
+       dentry = d_lookup(base, name);
 
-       if (dentry && dentry->d_op && dentry->d_op->d_revalidate)
+       if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE))
                dentry = do_revalidate(dentry, nd);
 
-       if (!dentry) {
-               struct dentry *new;
-
-               /* Don't create child dentry for a dead directory. */
-               dentry = ERR_PTR(-ENOENT);
-               if (IS_DEADDIR(inode))
-                       goto out;
-
-               new = d_alloc(base, name);
-               dentry = ERR_PTR(-ENOMEM);
-               if (!new)
-                       goto out;
-               dentry = inode->i_op->lookup(inode, new, nd);
-               if (!dentry)
-                       dentry = new;
-               else
-                       dput(new);
-       }
+       if (!dentry)
+               dentry = d_alloc_and_lookup(base, name, nd);
 out:
        return dentry;
 }
@@ -1177,17 +1844,13 @@ out:
  * needs parent already locked. Doesn't follow mounts.
  * SMP-safe.
  */
-static struct dentry *lookup_hash(struct nameidata *nd)
+struct dentry *lookup_hash(struct nameidata *nd)
 {
-       int err;
-
-       err = exec_permission(nd->path.dentry->d_inode);
-       if (err)
-               return ERR_PTR(err);
        return __lookup_hash(&nd->last, nd->path.dentry, nd);
 }
+EXPORT_SYMBOL(lookup_hash);
 
-static int __lookup_one_len(const char *name, struct qstr *this,
+int __lookup_one_len(const char *name, struct qstr *this,
                struct dentry *base, int len)
 {
        unsigned long hash;
@@ -1208,6 +1871,7 @@ static int __lookup_one_len(const char *name, struct qstr *this,
        this->hash = end_name_hash(hash);
        return 0;
 }
+EXPORT_SYMBOL(__lookup_one_len);
 
 /**
  * lookup_one_len - filesystem helper to lookup single pathname component
@@ -1231,9 +1895,6 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
        if (err)
                return ERR_PTR(err);
 
-       err = exec_permission(base->d_inode);
-       if (err)
-               return ERR_PTR(err);
        return __lookup_hash(&this, base, NULL);
 }
 
@@ -1472,8 +2133,9 @@ int may_open(struct path *path, int acc_mode, int flag)
        return break_lease(inode, flag);
 }
 
-static int handle_truncate(struct path *path)
+static int handle_truncate(struct file *filp)
 {
+       struct path *path = &filp->f_path;
        struct inode *inode = path->dentry->d_inode;
        int error = get_write_access(inode);
        if (error)
@@ -1487,7 +2149,7 @@ static int handle_truncate(struct path *path)
        if (!error) {
                error = do_truncate(path->dentry, 0,
                                    ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
-                                   NULL);
+                                   filp);
        }
        put_write_access(inode);
        return error;
@@ -1514,6 +2176,7 @@ out_unlock:
        mutex_unlock(&dir->d_inode->i_mutex);
        dput(nd->path.dentry);
        nd->path.dentry = path->dentry;
+
        if (error)
                return error;
        /* Don't check for write permission, don't truncate */
@@ -1584,7 +2247,7 @@ static struct file *finish_open(struct nameidata *nd,
        }
        if (!IS_ERR(filp)) {
                if (will_truncate) {
-                       error = handle_truncate(&nd->path);
+                       error = handle_truncate(filp);
                        if (error) {
                                fput(filp);
                                filp = ERR_PTR(error);
@@ -1598,15 +2261,17 @@ static struct file *finish_open(struct nameidata *nd,
         */
        if (will_truncate)
                mnt_drop_write(nd->path.mnt);
+       path_put(&nd->path);
        return filp;
 
 exit:
-       if (!IS_ERR(nd->intent.open.file))
-               release_open_intent(nd);
        path_put(&nd->path);
        return ERR_PTR(error);
 }
 
+/*
+ * Handle O_CREAT case for do_filp_open
+ */
 static struct file *do_last(struct nameidata *nd, struct path *path,
                            int open_flag, int acc_mode,
                            int mode, const char *pathname)
@@ -1620,50 +2285,27 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                follow_dotdot(nd);
                dir = nd->path.dentry;
        case LAST_DOT:
-               if (nd->path.mnt->mnt_sb->s_type->fs_flags & FS_REVAL_DOT) {
-                       if (!dir->d_op->d_revalidate(dir, nd)) {
-                               error = -ESTALE;
+               if (need_reval_dot(dir)) {
+                       int status = d_revalidate(nd->path.dentry, nd);
+                       if (!status)
+                               status = -ESTALE;
+                       if (status < 0) {
+                               error = status;
                                goto exit;
                        }
                }
                /* fallthrough */
        case LAST_ROOT:
-               if (open_flag & O_CREAT)
-                       goto exit;
-               /* fallthrough */
+               goto exit;
        case LAST_BIND:
                audit_inode(pathname, dir);
                goto ok;
        }
 
        /* trailing slashes? */
-       if (nd->last.name[nd->last.len]) {
-               if (open_flag & O_CREAT)
-                       goto exit;
-               nd->flags |= LOOKUP_DIRECTORY | LOOKUP_FOLLOW;
-       }
-
-       /* just plain open? */
-       if (!(open_flag & O_CREAT)) {
-               error = do_lookup(nd, &nd->last, path);
-               if (error)
-                       goto exit;
-               error = -ENOENT;
-               if (!path->dentry->d_inode)
-                       goto exit_dput;
-               if (path->dentry->d_inode->i_op->follow_link)
-                       return NULL;
-               error = -ENOTDIR;
-               if (nd->flags & LOOKUP_DIRECTORY) {
-                       if (!path->dentry->d_inode->i_op->lookup)
-                               goto exit_dput;
-               }
-               path_to_nameidata(path, nd);
-               audit_inode(pathname, nd->path.dentry);
-               goto ok;
-       }
+       if (nd->last.name[nd->last.len])
+               goto exit;
 
-       /* OK, it's O_CREAT */
        mutex_lock(&dir->d_inode->i_mutex);
 
        path->dentry = lookup_hash(nd);
@@ -1699,6 +2341,7 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                }
                filp = nameidata_to_filp(nd);
                mnt_drop_write(nd->path.mnt);
+               path_put(&nd->path);
                if (!IS_ERR(filp)) {
                        error = ima_file_check(filp, acc_mode);
                        if (error) {
@@ -1719,11 +2362,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
        if (open_flag & O_EXCL)
                goto exit_dput;
 
-       if (__follow_mount(path)) {
-               error = -ELOOP;
-               if (open_flag & O_NOFOLLOW)
-                       goto exit_dput;
-       }
+       error = follow_managed(path, nd->flags);
+       if (error < 0)
+               goto exit_dput;
 
        error = -ENOENT;
        if (!path->dentry->d_inode)
@@ -1733,8 +2374,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
                return NULL;
 
        path_to_nameidata(path, nd);
+       nd->inode = path->dentry->d_inode;
        error = -EISDIR;
-       if (S_ISDIR(path->dentry->d_inode->i_mode))
+       if (S_ISDIR(nd->inode->i_mode))
                goto exit;
 ok:
        filp = finish_open(nd, open_flag, acc_mode);
@@ -1745,8 +2387,6 @@ exit_mutex_unlock:
 exit_dput:
        path_put_conditional(path, nd);
 exit:
-       if (!IS_ERR(nd->intent.open.file))
-               release_open_intent(nd);
        path_put(&nd->path);
        return ERR_PTR(error);
 }
@@ -1765,11 +2405,14 @@ struct file *do_filp_open(int dfd, const char *pathname,
        struct path path;
        int count = 0;
        int flag = open_to_namei_flags(open_flag);
-       int force_reval = 0;
+       int flags;
 
        if (!(open_flag & O_CREAT))
                mode = 0;
 
+       /* Must never be set by userspace */
+       open_flag &= ~FMODE_NONOTIFY;
+
        /*
         * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
         * check for O_DSYNC if the need any syncing at all we enforce it's
@@ -1791,54 +2434,92 @@ struct file *do_filp_open(int dfd, const char *pathname,
        if (open_flag & O_APPEND)
                acc_mode |= MAY_APPEND;
 
-       /* find the parent */
-reval:
-       error = path_init(dfd, pathname, LOOKUP_PARENT, &nd);
+       flags = LOOKUP_OPEN;
+       if (open_flag & O_CREAT) {
+               flags |= LOOKUP_CREATE;
+               if (open_flag & O_EXCL)
+                       flags |= LOOKUP_EXCL;
+       }
+       if (open_flag & O_DIRECTORY)
+               flags |= LOOKUP_DIRECTORY;
+       if (!(open_flag & O_NOFOLLOW))
+               flags |= LOOKUP_FOLLOW;
+
+       filp = get_empty_filp();
+       if (!filp)
+               return ERR_PTR(-ENFILE);
+
+       filp->f_flags = open_flag;
+       nd.intent.open.file = filp;
+       nd.intent.open.flags = flag;
+       nd.intent.open.create_mode = mode;
+
+       if (open_flag & O_CREAT)
+               goto creat;
+
+       /* !O_CREAT, simple open */
+       error = do_path_lookup(dfd, pathname, flags, &nd);
+       if (unlikely(error))
+               goto out_filp2;
+       error = -ELOOP;
+       if (!(nd.flags & LOOKUP_FOLLOW)) {
+               if (nd.inode->i_op->follow_link)
+                       goto out_path2;
+       }
+       error = -ENOTDIR;
+       if (nd.flags & LOOKUP_DIRECTORY) {
+               if (!nd.inode->i_op->lookup)
+                       goto out_path2;
+       }
+       audit_inode(pathname, nd.path.dentry);
+       filp = finish_open(&nd, open_flag, acc_mode);
+out2:
+       release_open_intent(&nd);
+       return filp;
+
+out_path2:
+       path_put(&nd.path);
+out_filp2:
+       filp = ERR_PTR(error);
+       goto out2;
+
+creat:
+       /* OK, have to create the file. Find the parent. */
+       error = path_init_rcu(dfd, pathname,
+                       LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
        if (error)
-               return ERR_PTR(error);
-       if (force_reval)
-               nd.flags |= LOOKUP_REVAL;
+               goto out_filp;
+       error = path_walk_rcu(pathname, &nd);
+       path_finish_rcu(&nd);
+       if (unlikely(error == -ECHILD || error == -ESTALE)) {
+               /* slower, locked walk */
+               if (error == -ESTALE) {
+reval:
+                       flags |= LOOKUP_REVAL;
+               }
+               error = path_init(dfd, pathname,
+                               LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd);
+               if (error)
+                       goto out_filp;
 
-       current->total_link_count = 0;
-       error = link_path_walk(pathname, &nd);
-       if (error) {
-               filp = ERR_PTR(error);
-               goto out;
+               error = path_walk_simple(pathname, &nd);
        }
-       if (unlikely(!audit_dummy_context()) && (open_flag & O_CREAT))
+       if (unlikely(error))
+               goto out_filp;
+       if (unlikely(!audit_dummy_context()))
                audit_inode(pathname, nd.path.dentry);
 
        /*
         * We have the parent and last component.
         */
-
-       error = -ENFILE;
-       filp = get_empty_filp();
-       if (filp == NULL)
-               goto exit_parent;
-       nd.intent.open.file = filp;
-       filp->f_flags = open_flag;
-       nd.intent.open.flags = flag;
-       nd.intent.open.create_mode = mode;
-       nd.flags &= ~LOOKUP_PARENT;
-       nd.flags |= LOOKUP_OPEN;
-       if (open_flag & O_CREAT) {
-               nd.flags |= LOOKUP_CREATE;
-               if (open_flag & O_EXCL)
-                       nd.flags |= LOOKUP_EXCL;
-       }
-       if (open_flag & O_DIRECTORY)
-               nd.flags |= LOOKUP_DIRECTORY;
-       if (!(open_flag & O_NOFOLLOW))
-               nd.flags |= LOOKUP_FOLLOW;
+       nd.flags = flags;
        filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
        while (unlikely(!filp)) { /* trailing symlink */
-               struct path holder;
-               struct inode *inode = path.dentry->d_inode;
+               struct path link = path;
+               struct inode *linki = link.dentry->d_inode;
                void *cookie;
                error = -ELOOP;
-               /* S_ISDIR part is a temporary automount kludge */
-               if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(inode->i_mode))
+               if (!(nd.flags & LOOKUP_FOLLOW))
                        goto exit_dput;
                if (count++ == 32)
                        goto exit_dput;
@@ -1854,41 +2535,36 @@ reval:
                 * just set LAST_BIND.
                 */
                nd.flags |= LOOKUP_PARENT;
-               error = security_inode_follow_link(path.dentry, &nd);
+               error = security_inode_follow_link(link.dentry, &nd);
                if (error)
                        goto exit_dput;
-               error = __do_follow_link(&path, &nd, &cookie);
+               error = __do_follow_link(&link, &nd, &cookie);
                if (unlikely(error)) {
+                       if (!IS_ERR(cookie) && linki->i_op->put_link)
+                               linki->i_op->put_link(link.dentry, &nd, cookie);
                        /* nd.path had been dropped */
-                       if (!IS_ERR(cookie) && inode->i_op->put_link)
-                               inode->i_op->put_link(path.dentry, &nd, cookie);
-                       path_put(&path);
-                       release_open_intent(&nd);
-                       filp = ERR_PTR(error);
-                       goto out;
+                       nd.path = link;
+                       goto out_path;
                }
-               holder = path;
                nd.flags &= ~LOOKUP_PARENT;
                filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname);
-               if (inode->i_op->put_link)
-                       inode->i_op->put_link(holder.dentry, &nd, cookie);
-               path_put(&holder);
+               if (linki->i_op->put_link)
+                       linki->i_op->put_link(link.dentry, &nd, cookie);
+               path_put(&link);
        }
 out:
        if (nd.root.mnt)
                path_put(&nd.root);
-       if (filp == ERR_PTR(-ESTALE) && !force_reval) {
-               force_reval = 1;
+       if (filp == ERR_PTR(-ESTALE) && !(flags & LOOKUP_REVAL))
                goto reval;
-       }
+       release_open_intent(&nd);
        return filp;
 
 exit_dput:
        path_put_conditional(&path, &nd);
-       if (!IS_ERR(nd.intent.open.file))
-               release_open_intent(&nd);
-exit_parent:
+out_path:
        path_put(&nd.path);
+out_filp:
        filp = ERR_PTR(error);
        goto out;
 }
@@ -2149,12 +2825,10 @@ void dentry_unhash(struct dentry *dentry)
 {
        dget(dentry);
        shrink_dcache_parent(dentry);
-       spin_lock(&dcache_lock);
        spin_lock(&dentry->d_lock);
-       if (atomic_read(&dentry->d_count) == 2)
+       if (dentry->d_count == 2)
                __d_drop(dentry);
        spin_unlock(&dentry->d_lock);
-       spin_unlock(&dcache_lock);
 }
 
 int vfs_rmdir(struct inode *dir, struct dentry *dentry)
@@ -2309,7 +2983,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
                        goto slashes;
                inode = dentry->d_inode;
                if (inode)
-                       atomic_inc(&inode->i_count);
+                       ihold(inode);
                error = mnt_want_write(nd.path.mnt);
                if (error)
                        goto exit2;
@@ -2633,7 +3307,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 {
        int error;
        int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
-       const char *old_name;
+       const unsigned char *old_name;
 
        if (old_dentry->d_inode == new_dentry->d_inode)
                return 0;
@@ -2903,6 +3577,7 @@ const struct inode_operations page_symlink_inode_operations = {
 };
 
 EXPORT_SYMBOL(user_path_at);
+EXPORT_SYMBOL(follow_down_one);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(get_write_access); /* binfmt_aout */