aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-10 12:17:49 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-10 12:17:49 -0700
commitd0d272771035a36a7839bb70ab6ebae3f4f4960b (patch)
treeb577831d3d9dd2359b401783c3a3d7f70c8a8032 /fs
parentMerge tag 'dmaengine-3.12' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/dmaengine (diff)
downloadlinux-dev-d0d272771035a36a7839bb70ab6ebae3f4f4960b.tar.xz
linux-dev-d0d272771035a36a7839bb70ab6ebae3f4f4960b.zip
vfs: make sure we don't have a stale root path if unlazy_walk() fails
When I moved the RCU walk termination into unlazy_walk(), I didn't copy quite all of it: for the successful RCU termination we properly add the necessary reference counts to our temporary copy of the root path, but for the failure case we need to make sure that any temporary root path information is cleared out (since it does _not_ have the proper reference counts from the RCU lookup). We could clean up this mess by just always dropping the temporary root information, but Al points out that that would mean that a single lookup through symlinks could see multiple different root entries if it races with another thread doing chroot. Not that I think we should really care (we had that before too, back before we had a copy of the root path in the nameidata). Al says he has a cunning plan. In the meantime, this is the minimal fix for the problem, even if it's not all that pretty. Reported-by: Mace Moneta <moneta.mace@gmail.com> Acked-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/namei.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 56e4f4d537d0..5e6aaadc1dcd 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -574,9 +574,12 @@ unlock_and_drop_dentry:
drop_dentry:
unlock_rcu_walk();
dput(dentry);
- return -ECHILD;
+ goto drop_root_mnt;
out:
unlock_rcu_walk();
+drop_root_mnt:
+ if (!(nd->flags & LOOKUP_ROOT))
+ nd->root.mnt = NULL;
return -ECHILD;
}