summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2026-04-11 03:56:42 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2026-06-05 00:34:55 -0400
commitb4143e0e71cd660d05de8d2861e980e7c840eb39 (patch)
tree4b3269bea49b2c4d43b4ba4ca427eb83ec111944
parent0954b4b558f7f582615b071b686f42a5a3ce2e53 (diff)
downloadlinux-b4143e0e71cd660d05de8d2861e980e7c840eb39.tar.gz
linux-b4143e0e71cd660d05de8d2861e980e7c840eb39.zip
Shift rcu_read_{,un}lock() inside fast_dput()
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>
-rw-r--r--fs/dcache.c30
1 files changed, 14 insertions, 16 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 9851d387349d..ae9b7151e6a4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -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);
}