d_prune_alias(): just lock the parent and call __dentry_kill()
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 30 May 2014 15:25:30 +0000 (11:25 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 9 Oct 2014 06:38:59 +0000 (02:38 -0400)
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>
fs/dcache.c

index 70d102e70271707a3b6217f3a2b55ee77f681e89..d8a77b1c3d52b7bd68640ae33d6873bac5541968 100644 (file)
@@ -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);
        }