]> Pileus Git - ~andy/linux/blobdiff - fs/namei.c
Merge branch 'for-38-rc2' of git://codeaurora.org/quic/kernel/davidb/linux-msm
[~andy/linux] / fs / namei.c
index dc50bfb2f5d6fac3b613cc41c6d8833694fa2196..7d77f24d32a98a115e320605369006eeef30ae0d 100644 (file)
@@ -367,18 +367,6 @@ void path_get(struct path *path)
 }
 EXPORT_SYMBOL(path_get);
 
-/**
- * path_get_long - get a long reference to a path
- * @path: path to get the reference to
- *
- * Given a path increment the reference count to the dentry and the vfsmount.
- */
-void path_get_long(struct path *path)
-{
-       mntget_long(path->mnt);
-       dget(path->dentry);
-}
-
 /**
  * path_put - put a reference to a path
  * @path: path to put the reference to
@@ -392,18 +380,6 @@ void path_put(struct path *path)
 }
 EXPORT_SYMBOL(path_put);
 
-/**
- * path_put_long - put a long reference to a path
- * @path: path to put the reference to
- *
- * Given a path decrement the reference count to the dentry and the vfsmount.
- */
-void path_put_long(struct path *path)
-{
-       dput(path->dentry);
-       mntput_long(path->mnt);
-}
-
 /**
  * nameidata_drop_rcu - drop this nameidata out of rcu-walk
  * @nd: nameidata pathwalk data to drop
@@ -800,12 +776,8 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p)
        touch_atime(link->mnt, dentry);
        nd_set_link(nd, NULL);
 
-       if (link->mnt != nd->path.mnt) {
-               path_to_nameidata(link, nd);
-               nd->inode = nd->path.dentry->d_inode;
-               dget(dentry);
-       }
-       mntget(link->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);
@@ -904,6 +876,7 @@ static int follow_automount(struct path *path, unsigned flags,
                            bool *need_mntput)
 {
        struct vfsmount *mnt;
+       int err;
 
        if (!path->dentry->d_op || !path->dentry->d_op->d_automount)
                return -EREMOTE;
@@ -946,22 +919,28 @@ static int follow_automount(struct path *path, unsigned flags,
                        return -EREMOTE;
                return PTR_ERR(mnt);
        }
+
        if (!mnt) /* mount collision */
                return 0;
 
-       if (mnt->mnt_sb == path->mnt->mnt_sb &&
-           mnt->mnt_root == path->dentry) {
-               mntput(mnt);
-               return -ELOOP;
+       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 (*need_mntput)
+                       mntput(path->mnt);
+               path->mnt = mnt;
+               path->dentry = dget(mnt->mnt_root);
+               *need_mntput = true;
+               return 0;
+       default:
+               return err;
        }
 
-       dput(path->dentry);
-       if (*need_mntput)
-               mntput(path->mnt);
-       path->mnt = mnt;
-       path->dentry = dget(mnt->mnt_root);
-       *need_mntput = true;
-       return 0;
 }
 
 /*
@@ -991,7 +970,8 @@ static int follow_managed(struct path *path, unsigned flags)
                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);
+                       ret = path->dentry->d_op->d_manage(path->dentry,
+                                                          false, false);
                        if (ret < 0)
                                return ret == -EISDIR ? 0 : ret;
                }
@@ -1052,13 +1032,12 @@ int follow_down_one(struct path *path)
 static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                               struct inode **inode, bool reverse_transit)
 {
-       unsigned abort_mask =
-               reverse_transit ? 0 : DCACHE_MANAGE_TRANSIT;
-
        while (d_mountpoint(path->dentry)) {
                struct vfsmount *mounted;
-               if (path->dentry->d_flags & abort_mask)
-                       return true;
+               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;
@@ -1136,7 +1115,8 @@ int follow_down(struct path *path, bool mounting_here)
                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);
+                       ret = path->dentry->d_op->d_manage(
+                               path->dentry, mounting_here, false);
                        if (ret < 0)
                                return ret == -EISDIR ? 0 : ret;
                }
@@ -1292,8 +1272,10 @@ done:
        path->mnt = mnt;
        path->dentry = dentry;
        err = follow_managed(path, nd->flags);
-       if (unlikely(err < 0))
+       if (unlikely(err < 0)) {
+               path_put_conditional(path, nd);
                return err;
+       }
        *inode = path->dentry->d_inode;
        return 0;
 
@@ -1341,17 +1323,6 @@ 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
@@ -1490,7 +1461,8 @@ last_component:
                err = do_lookup(nd, &this, &next, &inode);
                if (err)
                        break;
-               if (follow_on_final(inode, lookup_flags)) {
+               if (inode && unlikely(inode->i_op->follow_link) &&
+                   (lookup_flags & LOOKUP_FOLLOW)) {
                        if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry))
                                return -ECHILD;
                        BUG_ON(inode != next.dentry->d_inode);
@@ -2543,8 +2515,7 @@ reval:
                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(linki->i_mode))
+               if (!(nd.flags & LOOKUP_FOLLOW))
                        goto exit_dput;
                if (count++ == 32)
                        goto exit_dput;