fast_dput(): having ->d_delete() is not reason to delay refcount decrement
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 30 Oct 2023 04:02:14 +0000 (00:02 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 25 Nov 2023 07:33:42 +0000 (02:33 -0500)
->d_delete() is a way for filesystem to tell that dentry is not worth
keeping cached.  It is not guaranteed to be called every time a dentry
has refcount drop down to zero; it is not guaranteed to be called before
dentry gets evicted.  In other words, it is not suitable for any kind
of keeping track of dentry state.

None of the in-tree filesystems attempt to use it that way, fortunately.

So the contortions done by fast_dput() (as well as dentry_kill()) are
not warranted.  fast_dput() certainly should treat having ->d_delete()
instance as "can't assume we'll be keeping it", but that's not different
from the way we treat e.g. DCACHE_DONTCACHE (which is rather similar
to making ->d_delete() returns true when called).

Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/dcache.c

index c1025921f8d356eb552527b67e4388dc843aa9dc..00c19041adf30c5ebf4a8f545dc303b46b01471c 100644 (file)
@@ -768,15 +768,7 @@ static inline bool fast_dput(struct dentry *dentry)
        unsigned int d_flags;
 
        /*
-        * If we have a d_op->d_delete() operation, we sould not
-        * let the dentry count go to zero, so use "put_or_lock".
-        */
-       if (unlikely(dentry->d_flags & DCACHE_OP_DELETE))
-               return lockref_put_or_lock(&dentry->d_lockref);
-
-       /*
-        * .. otherwise, we can try to just decrement the
-        * lockref optimistically.
+        * try to decrement the lockref optimistically.
         */
        ret = lockref_put_return(&dentry->d_lockref);
 
@@ -830,7 +822,7 @@ static inline bool fast_dput(struct dentry *dentry)
         */
        smp_rmb();
        d_flags = READ_ONCE(dentry->d_flags);
-       d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST |
+       d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST | DCACHE_OP_DELETE |
                        DCACHE_DISCONNECTED | DCACHE_DONTCACHE;
 
        /* Nothing to do? Dropping the reference was all we needed? */