diff options
author | Al Viro <viro@ZenIV.linux.org.uk> | 2009-02-15 21:38:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-02-17 17:02:08 -0500 |
commit | 1a88b5364b535edaa321d70a566e358390ff0872 (patch) | |
tree | 41c557358a595de85ba8a7a7697901ff21d1de1a /fs/namespace.c | |
parent | d2f8d7ee1a9b4650b4e43325b321801264f7c37a (diff) |
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>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 6 |
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) | |||
614 | */ | 614 | */ |
615 | for_each_possible_cpu(cpu) { | 615 | for_each_possible_cpu(cpu) { |
616 | struct mnt_writer *cpu_writer = &per_cpu(mnt_writers, cpu); | 616 | struct mnt_writer *cpu_writer = &per_cpu(mnt_writers, cpu); |
617 | if (cpu_writer->mnt != mnt) | ||
618 | continue; | ||
619 | spin_lock(&cpu_writer->lock); | 617 | spin_lock(&cpu_writer->lock); |
618 | if (cpu_writer->mnt != mnt) { | ||
619 | spin_unlock(&cpu_writer->lock); | ||
620 | continue; | ||
621 | } | ||
620 | atomic_add(cpu_writer->count, &mnt->__mnt_writers); | 622 | atomic_add(cpu_writer->count, &mnt->__mnt_writers); |
621 | cpu_writer->count = 0; | 623 | cpu_writer->count = 0; |
622 | /* | 624 | /* |