forked from Minki/linux
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>
This commit is contained in:
parent
bbd5192412
commit
29355c3904
21
fs/dcache.c
21
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user