summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2010-06-05 00:13:05 -0400
committerThomas Gleixner <tglx@linutronix.de>2010-06-08 20:02:30 +0200
commita06a8672c6e156fb443ee804dca7bc0245414bc6 (patch)
tree8e23c6c9b8702081ce4f396e436f31c4ba77d55d /fs
parentbdeadaf2f7daf6c098e83506d4d99142ca3912f8 (diff)
downloadlwn-a06a8672c6e156fb443ee804dca7bc0245414bc6.tar.gz
lwn-a06a8672c6e156fb443ee804dca7bc0245414bc6.zip
dcache: Prevent d_genocide() from decrementing d_count more than once
When d_genocide is called, it traverses the dentries decrementing the d_count. After the loops, a check is made to see if a rename or other change has been made, if so, it traverse the tree again. Unfortunately, this will decrement the same dentries that it decremented the first time. To avoid this multiple decrement, I added a DCACHE_GENOCIDE flag that will be set to a dentry when the d_genocide has decremented its counter. It will only decrement the counter if this flag is not set. Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Cc: Nick Piggin <npiggin@suse.de> Cc: John Kacur <jkacur@redhat.com> Cc: "Luis Claudio R. Goncalves" <lclaudio@uudg.org> Cc: Clark Williams <williams@redhat.com> Acked-by: john stultz <johnstul@us.ibm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/dcache.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 673cdc22ca46..18a3b762297c 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2568,7 +2568,10 @@ resume:
spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
goto repeat;
}
- atomic_dec(&dentry->d_count);
+ if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
+ atomic_dec(&dentry->d_count);
+ dentry->d_flags |= DCACHE_GENOCIDE;
+ }
spin_unlock(&dentry->d_lock);
}
if (this_parent != root) {
@@ -2576,7 +2579,10 @@ resume:
struct dentry *child;
tmp = this_parent->d_parent;
- atomic_dec(&this_parent->d_count);
+ if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
+ atomic_dec(&this_parent->d_count);
+ this_parent->d_flags |= DCACHE_GENOCIDE;
+ }
rcu_read_lock();
spin_unlock(&this_parent->d_lock);
child = this_parent;