summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@ZenIV.linux.org.uk>2009-02-16 03:38:12 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2009-02-17 23:02:08 +0100
commit1a88b5364b535edaa321d70a566e358390ff0872 (patch)
tree41c557358a595de85ba8a7a7697901ff21d1de1a
parentLinux 2.6.29-rc5 (diff)
downloadlinux-1a88b5364b535edaa321d70a566e358390ff0872.tar.xz
linux-1a88b5364b535edaa321d70a566e358390ff0872.zip
Fix incomplete __mntput locking
Getting this wrong caused WARNING: at fs/namespace.c:636 mntput_no_expire+0xac/0xf2() due to optimistically checking cpu_writer->mnt outside the spinlock. Here's what we really want: * we know that nobody will set cpu_writer->mnt to mnt from now on * all changes to that sucker are done under cpu_writer->lock * we want the laziest equivalent of spin_lock(&cpu_writer->lock); if (likely(cpu_writer->mnt != mnt)) { spin_unlock(&cpu_writer->lock); continue; } /* do stuff */ that would make sure we won't miss earlier setting of ->mnt done by another CPU. Anyway, for now we just move the spin_lock() earlier and move the test into the properly locked region. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Reported-and-tested-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/namespace.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 228d8c4bfd18..06f8e63f6cb1 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -614,9 +614,11 @@ static inline void __mntput(struct vfsmount *mnt)
*/
for_each_possible_cpu(cpu) {
struct mnt_writer *cpu_writer = &per_cpu(mnt_writers, cpu);
- if (cpu_writer->mnt != mnt)
- continue;
spin_lock(&cpu_writer->lock);
+ if (cpu_writer->mnt != mnt) {
+ spin_unlock(&cpu_writer->lock);
+ continue;
+ }
atomic_add(cpu_writer->count, &mnt->__mnt_writers);
cpu_writer->count = 0;
/*