diff options
author | Nick Piggin <npiggin@suse.de> | 2010-01-29 15:38:24 -0800 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2010-04-27 17:32:36 +0200 |
commit | 68d0cacc5da18248a173c2fd83f8870f6a242729 (patch) | |
tree | fe6b14055f83dd039d64b92573c4b27ff2a60dbf | |
parent | 6465e96519c08e46bd8e366ad5e7039fa9a035bb (diff) | |
download | lwn-68d0cacc5da18248a173c2fd83f8870f6a242729.tar.gz lwn-68d0cacc5da18248a173c2fd83f8870f6a242729.zip |
dcache-dput-less-dcache_lock
It is possible to run dput without taking locks up-front. In many cases
where we don't kill the dentry anyway, these locks are not required.
(I think... need to think about it more). Further changes ->d_delete
locking which is not all audited.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: John Stultz <johnstul@us.ibm.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | fs/dcache.c | 58 |
1 files changed, 31 insertions, 27 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 47ff94316553..2ad61b0d01c5 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -264,7 +264,8 @@ static struct dentry *d_kill(struct dentry *dentry) void dput(struct dentry *dentry) { - struct dentry *parent = NULL; + struct dentry *parent; + if (!dentry) return; @@ -272,25 +273,10 @@ repeat: if (dentry->d_count == 1) might_sleep(); spin_lock(&dentry->d_lock); - if (dentry->d_count == 1) { - if (!spin_trylock(&dcache_inode_lock)) { -drop2: - spin_unlock(&dentry->d_lock); - goto repeat; - } - parent = dentry->d_parent; - if (parent && parent != dentry) { - if (!spin_trylock(&parent->d_lock)) { - spin_unlock(&dcache_inode_lock); - goto drop2; - } - } - } - dentry->d_count--; - if (dentry->d_count) { + BUG_ON(!dentry->d_count); + if (dentry->d_count > 1) { + dentry->d_count--; spin_unlock(&dentry->d_lock); - if (parent && parent != dentry) - spin_unlock(&parent->d_lock); return; } @@ -298,8 +284,10 @@ drop2: * AV: ->d_delete() is _NOT_ allowed to block now. */ if (dentry->d_op && dentry->d_op->d_delete) { - if (dentry->d_op->d_delete(dentry)) - goto unhash_it; + if (dentry->d_op->d_delete(dentry)) { + __d_drop(dentry); + goto kill_it; + } } /* Unreachable? Get rid of it */ if (d_unhashed(dentry)) @@ -308,15 +296,31 @@ drop2: dentry->d_flags |= DCACHE_REFERENCED; dentry_lru_add(dentry); } - spin_unlock(&dentry->d_lock); - if (parent && parent != dentry) - spin_unlock(&parent->d_lock); - spin_unlock(&dcache_inode_lock); + dentry->d_count--; + spin_unlock(&dentry->d_lock); return; -unhash_it: - __d_drop(dentry); kill_it: + spin_unlock(&dentry->d_lock); + spin_lock(&dcache_inode_lock); +relock: + spin_lock(&dentry->d_lock); + parent = dentry->d_parent; + if (parent && parent != dentry) { + if (!spin_trylock(&parent->d_lock)) { + spin_unlock(&dentry->d_lock); + goto relock; + } + } + dentry->d_count--; + if (dentry->d_count) { + /* This case should be fine */ + spin_unlock(&dentry->d_lock); + if (parent && parent != dentry) + spin_unlock(&parent->d_lock); + spin_unlock(&dcache_inode_lock); + return; + } /* if dentry was on the d_lru list delete it from there */ dentry_lru_del(dentry); dentry = d_kill(dentry); |