Patch "fs: better handle deep ancestor chains in is_subdir()" has been added to the 5.4-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    fs: better handle deep ancestor chains in is_subdir()

to the 5.4-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     fs-better-handle-deep-ancestor-chains-in-is_subdir.patch
and it can be found in the queue-5.4 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 37581d420be0288e09bb6680bfe7bacd1c4b6622
Author: Christian Brauner <brauner@xxxxxxxxxx>
Date:   Tue Jul 2 21:03:26 2024 +0200

    fs: better handle deep ancestor chains in is_subdir()
    
    [ Upstream commit 391b59b045004d5b985d033263ccba3e941a7740 ]
    
    Jan reported that 'cd ..' may take a long time in deep directory
    hierarchies under a bind-mount. If concurrent renames happen it is
    possible to livelock in is_subdir() because it will keep retrying.
    
    Change is_subdir() from simply retrying over and over to retry once and
    then acquire the rename lock to handle deep ancestor chains better. The
    list of alternatives to this approach were less then pleasant. Change
    the scope of rcu lock to cover the whole walk while at it.
    
    A big thanks to Jan and Linus. Both Jan and Linus had proposed
    effectively the same thing just that one version ended up being slightly
    more elegant.
    
    Reported-by: Jan Kara <jack@xxxxxxx>
    Signed-off-by: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Christian Brauner <brauner@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/dcache.c b/fs/dcache.c
index c58b5e5cb045d..78081bdc49311 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -3073,28 +3073,25 @@ EXPORT_SYMBOL(d_splice_alias);
   
 bool is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
 {
-	bool result;
+	bool subdir;
 	unsigned seq;
 
 	if (new_dentry == old_dentry)
 		return true;
 
-	do {
-		/* for restarting inner loop in case of seq retry */
-		seq = read_seqbegin(&rename_lock);
-		/*
-		 * Need rcu_readlock to protect against the d_parent trashing
-		 * due to d_move
-		 */
-		rcu_read_lock();
-		if (d_ancestor(old_dentry, new_dentry))
-			result = true;
-		else
-			result = false;
-		rcu_read_unlock();
-	} while (read_seqretry(&rename_lock, seq));
-
-	return result;
+	/* Access d_parent under rcu as d_move() may change it. */
+	rcu_read_lock();
+	seq = read_seqbegin(&rename_lock);
+	subdir = d_ancestor(old_dentry, new_dentry);
+	 /* Try lockless once... */
+	if (read_seqretry(&rename_lock, seq)) {
+		/* ...else acquire lock for progress even on deep chains. */
+		read_seqlock_excl(&rename_lock);
+		subdir = d_ancestor(old_dentry, new_dentry);
+		read_sequnlock_excl(&rename_lock);
+	}
+	rcu_read_unlock();
+	return subdir;
 }
 EXPORT_SYMBOL(is_subdir);
 




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux