summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-05-30 11:25:30 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2014-10-09 02:38:59 -0400
commit29355c3904e1765948c7721719a028b7eb5dfe1d (patch)
treeed3b5660e0df3f0c725d678fa80d4cff719a29cd
parentbbd5192412fdedbae00888316bfe350bf89d0458 (diff)
d_prune_alias(): just lock the parent and call __dentry_kill()
The only reason for games with ->d_prune() was __d_drop(), which was needed only to force dput() into killing the sucker off. Note that lock_parent() can be called under ->i_lock and won't drop it, so dentry is safe from somebody managing to kill it under us - it won't happen while we are holding ->i_lock. __dentry_kill() is called only with ->d_lockref.count being 0 (here and when picked from shrink list) or 1 (dput() and dropping the ancestors in shrink_dentry_list()), so it will never be called twice - the first thing it's doing is making ->d_lockref.count negative and once that happens, nothing will increment it. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/dcache.c21
1 files changed, 7 insertions, 14 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 70d102e70271..d8a77b1c3d52 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -770,20 +770,13 @@ restart:
hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
spin_lock(&dentry->d_lock);
if (!dentry->d_lockref.count) {
- /*
- * inform the fs via d_prune that this dentry
- * is about to be unhashed and destroyed.
- */
- if ((dentry->d_flags & DCACHE_OP_PRUNE) &&
- !d_unhashed(dentry))
- dentry->d_op->d_prune(dentry);
-
- __dget_dlock(dentry);
- __d_drop(dentry);
- spin_unlock(&dentry->d_lock);
- spin_unlock(&inode->i_lock);
- dput(dentry);
- goto restart;
+ struct dentry *parent = lock_parent(dentry);
+ if (likely(!dentry->d_lockref.count)) {
+ __dentry_kill(dentry);
+ goto restart;
+ }
+ if (parent)
+ spin_unlock(&parent->d_lock);
}
spin_unlock(&dentry->d_lock);
}