]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
Shift rcu_read_{,un}lock() inside fast_dput()
authorAl Viro <viro@zeniv.linux.org.uk>
Sat, 11 Apr 2026 07:56:42 +0000 (03:56 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Fri, 5 Jun 2026 04:34:55 +0000 (00:34 -0400)
Shrink rcu_read_lock() scopes surrounding fast_dput() calls.
Both callers are immediately preceded and followed by
rcu_read_lock()/rcu_read_unlock() resp.  Shrink that down
into fast_dput() itself; in case when fast_dput() ends up
grabbing ->d_lock, we can pull rcu_read_unlock() up to
right after spin_lock().

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

index 9851d387349d54e0576703ed5e3a17d40870c322..ae9b7151e6a4caef6b4abdcf17700007315ae765 100644 (file)
@@ -885,17 +885,17 @@ EXPORT_SYMBOL(d_mark_dontcache);
  * If unsuccessful, we return false, having already taken the dentry lock.
  * In that case refcount is guaranteed to be zero and we have already
  * decided that it's not worth keeping around.
- *
- * The caller needs to hold the RCU read lock, so that the dentry is
- * guaranteed to stay around even if the refcount goes down to zero!
  */
 static inline bool fast_dput(struct dentry *dentry)
 {
        int ret;
 
        /*
-        * try to decrement the lockref optimistically.
+        * Try to decrement the lockref optimistically.
+        * RCU read lock held so that dentry is guaranteed to stay around
+        * even if the refcount goes down to zero.
         */
+       rcu_read_lock();
        ret = lockref_put_return(&dentry->d_lockref);
 
        /*
@@ -905,6 +905,7 @@ static inline bool fast_dput(struct dentry *dentry)
         */
        if (unlikely(ret < 0)) {
                spin_lock(&dentry->d_lock);
+               rcu_read_unlock();
                if (WARN_ON_ONCE(dentry->d_lockref.count <= 0)) {
                        spin_unlock(&dentry->d_lock);
                        return true;
@@ -916,8 +917,10 @@ static inline bool fast_dput(struct dentry *dentry)
        /*
         * If we weren't the last ref, we're done.
         */
-       if (ret)
+       if (ret) {
+               rcu_read_unlock();
                return true;
+       }
 
        /*
         * Can we decide that decrement of refcount is all we needed without
@@ -925,8 +928,10 @@ static inline bool fast_dput(struct dentry *dentry)
         * dentry looks like it ought to be retained and there's nothing else
         * to do.
         */
-       if (retain_dentry(dentry, false))
+       if (retain_dentry(dentry, false)) {
+               rcu_read_unlock();
                return true;
+       }
 
        /*
         * Either not worth retaining or we can't tell without the lock.
@@ -934,6 +939,7 @@ static inline bool fast_dput(struct dentry *dentry)
         * but we'll need to re-check the situation after getting the lock.
         */
        spin_lock(&dentry->d_lock);
+       rcu_read_unlock();
 
        /*
         * Did somebody else grab a reference to it in the meantime, and
@@ -991,12 +997,8 @@ void dput(struct dentry *dentry)
        if (!dentry)
                return;
        might_sleep();
-       rcu_read_lock();
-       if (likely(fast_dput(dentry))) {
-               rcu_read_unlock();
+       if (likely(fast_dput(dentry)))
                return;
-       }
-       rcu_read_unlock();
        finish_dput(dentry);
 }
 EXPORT_SYMBOL(dput);
@@ -1044,12 +1046,8 @@ EXPORT_SYMBOL(__move_to_shrink_list);
 
 void dput_to_list(struct dentry *dentry, struct list_head *list)
 {
-       rcu_read_lock();
-       if (likely(fast_dput(dentry))) {
-               rcu_read_unlock();
+       if (likely(fast_dput(dentry)))
                return;
-       }
-       rcu_read_unlock();
        __move_to_shrink_list(dentry, list);
        spin_unlock(&dentry->d_lock);
 }