]> err.no Git - linux-2.6/blobdiff - fs/namei.c
Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6] / fs / namei.c
index 36925ff307b36fc39e46bedc42c390fd6f7afa90..fa8df81ce8cadd841e7f73aff5a40aa59dfcf73b 100644 (file)
@@ -503,7 +503,7 @@ static inline int __do_follow_link(struct path *path, struct nameidata *nd)
        int error;
        struct dentry *dentry = path->dentry;
 
-       touch_atime(nd->mnt, dentry);
+       touch_atime(path->mnt, dentry);
        nd_set_link(nd, NULL);
 
        if (path->mnt == nd->mnt)
@@ -682,6 +682,7 @@ static int do_lookup(struct nameidata *nd, struct qstr *name,
 done:
        path->mnt = mnt;
        path->dentry = dentry;
+       __follow_mount(path);
        return 0;
 
 need_lookup:
@@ -789,8 +790,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
                err = do_lookup(nd, &this, &next);
                if (err)
                        break;
-               /* Check mountpoints.. */
-               __follow_mount(&next);
 
                err = -ENOENT;
                inode = next.dentry->d_inode;
@@ -850,7 +849,6 @@ last_component:
                err = do_lookup(nd, &this, &next);
                if (err)
                        break;
-               __follow_mount(&next);
                inode = next.dentry->d_inode;
                if ((lookup_flags & LOOKUP_FOLLOW)
                    && inode && inode->i_op && inode->i_op->follow_link) {
@@ -1579,19 +1577,35 @@ do_link:
  *
  * Simple function to lookup and return a dentry and create it
  * if it doesn't exist.  Is SMP-safe.
+ *
+ * Returns with nd->dentry->d_inode->i_sem locked.
  */
 struct dentry *lookup_create(struct nameidata *nd, int is_dir)
 {
-       struct dentry *dentry;
+       struct dentry *dentry = ERR_PTR(-EEXIST);
 
        down(&nd->dentry->d_inode->i_sem);
-       dentry = ERR_PTR(-EEXIST);
+       /*
+        * Yucky last component or no last component at all?
+        * (foo/., foo/.., /////)
+        */
        if (nd->last_type != LAST_NORM)
                goto fail;
        nd->flags &= ~LOOKUP_PARENT;
+
+       /*
+        * Do the final lookup.
+        */
        dentry = lookup_hash(&nd->last, nd->dentry);
        if (IS_ERR(dentry))
                goto fail;
+
+       /*
+        * Special case - lookup gave negative, but... we had foo/bar/
+        * From the vfs_mknod() POV we just have a negative dentry -
+        * all is fine. Let's be bastards - you had / on the end, you've
+        * been asking for (non-existent) directory. -ENOENT for you.
+        */
        if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
                goto enoent;
        return dentry;