From: Al Viro Date: Fri, 30 May 2014 15:25:30 +0000 (-0400) Subject: d_prune_alias(): just lock the parent and call __dentry_kill() X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=29355c3904e1765948c7721719a028b7eb5dfe1d;p=openwrt%2Fstaging%2Fblogic.git 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 --- 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); }