From a1e3eb25c3e3db59a702246e5272dea90c0f0bbb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 7 Nov 2011 21:21:26 +0000 Subject: [PATCH] --- yaml --- r: 275112 b: refs/heads/master c: a3fbbde70a0cec017f2431e8f8de208708c76acc h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/fs/namei.c | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index 1dca3e8d5ab0..4c02a4d62c64 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 54a0f91301950af3d6ae2ff2bf710c9c68a9bfea +refs/heads/master: a3fbbde70a0cec017f2431e8f8de208708c76acc diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index ac6d214da827..5008f01787f5 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -852,7 +852,7 @@ static int follow_managed(struct path *path, unsigned flags) mntput(path->mnt); if (ret == -EISDIR) ret = 0; - return ret; + return ret < 0 ? ret : need_mntput; } int follow_down_one(struct path *path) @@ -900,6 +900,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, break; path->mnt = mounted; path->dentry = mounted->mnt_root; + nd->flags |= LOOKUP_JUMPED; nd->seq = read_seqcount_begin(&path->dentry->d_seq); /* * Update the inode too. We don't need to re-check the @@ -1213,6 +1214,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, path_put_conditional(path, nd); return err; } + if (err) + nd->flags |= LOOKUP_JUMPED; *inode = path->dentry->d_inode; return 0; } @@ -2146,6 +2149,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, } /* create side of things */ + /* + * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been + * cleared when we got to the last component we are about to look up + */ error = complete_walk(nd); if (error) return ERR_PTR(error); @@ -2214,6 +2221,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, if (error < 0) goto exit_dput; + if (error) + nd->flags |= LOOKUP_JUMPED; + error = -ENOENT; if (!path->dentry->d_inode) goto exit_dput; @@ -2223,6 +2233,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, path_to_nameidata(path, nd); nd->inode = path->dentry->d_inode; + /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ + error = complete_walk(nd); + if (error) + goto exit; error = -EISDIR; if (S_ISDIR(nd->inode->i_mode)) goto exit;