[PATCH] namei fixes (14/19)
[safe/jmp/linux-2.6] / fs / namei.c
index 935b08d..411bb32 100644 (file)
@@ -543,11 +543,15 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd)
        current->link_count++;
        current->total_link_count++;
        nd->depth++;
+       if (path->mnt != nd->mnt)
+               mntput(nd->mnt);
        err = __do_follow_link(path, nd);
        current->link_count--;
        nd->depth--;
        return err;
 loop:
+       if (path->mnt != nd->mnt)
+               mntput(nd->mnt);
        dput(path->dentry);
        path_release(nd);
        return err;
@@ -791,8 +795,6 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
                        break;
                /* Check mountpoints.. */
                __follow_mount(&next);
-               if (nd->mnt != next.mnt)
-                       mntput(nd->mnt);
 
                err = -ENOENT;
                inode = next.dentry->d_inode;
@@ -815,6 +817,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
                                break;
                } else {
                        dput(nd->dentry);
+                       if (nd->mnt != next.mnt)
+                               mntput(nd->mnt);
                        nd->mnt = next.mnt;
                        nd->dentry = next.dentry;
                }
@@ -851,8 +855,6 @@ last_component:
                if (err)
                        break;
                __follow_mount(&next);
-               if (nd->mnt != next.mnt)
-                       mntput(nd->mnt);
                inode = next.dentry->d_inode;
                if ((lookup_flags & LOOKUP_FOLLOW)
                    && inode && inode->i_op && inode->i_op->follow_link) {
@@ -862,6 +864,8 @@ last_component:
                        inode = nd->dentry->d_inode;
                } else {
                        dput(nd->dentry);
+                       if (nd->mnt != next.mnt)
+                               mntput(nd->mnt);
                        nd->mnt = next.mnt;
                        nd->dentry = next.dentry;
                }
@@ -901,6 +905,8 @@ return_base:
                return 0;
 out_dput:
                dput(next.dentry);
+               if (nd->mnt != next.mnt)
+                       mntput(nd->mnt);
                break;
        }
        path_release(nd);
@@ -1495,13 +1501,8 @@ do_last:
 
        if (__follow_mount(&path)) {
                error = -ELOOP;
-               if (flag & O_NOFOLLOW) {
-                       dput(path.dentry);
-                       mntput(path.mnt);
-                       goto exit;
-               }
-               mntput(nd->mnt);
-               nd->mnt = path.mnt;
+               if (flag & O_NOFOLLOW)
+                       goto exit_dput;
        }
        error = -ENOENT;
        if (!path.dentry->d_inode)
@@ -1511,6 +1512,9 @@ do_last:
 
        dput(nd->dentry);
        nd->dentry = path.dentry;
+       if (nd->mnt != path.mnt)
+               mntput(nd->mnt);
+       nd->mnt = path.mnt;
        error = -EISDIR;
        if (path.dentry->d_inode && S_ISDIR(path.dentry->d_inode->i_mode))
                goto exit;
@@ -1522,6 +1526,8 @@ ok:
 
 exit_dput:
        dput(path.dentry);
+       if (nd->mnt != path.mnt)
+               mntput(path.mnt);
 exit:
        path_release(nd);
        return error;
@@ -1544,6 +1550,9 @@ do_link:
        error = security_inode_follow_link(path.dentry, nd);
        if (error)
                goto exit_dput;
+       if (nd->mnt != path.mnt)
+               mntput(nd->mnt);
+       nd->mnt = path.mnt;
        error = __do_follow_link(&path, nd);
        if (error)
                return error;