Patch "jbd2: Fix wrongly judgement for buffer head removing while doing checkpoint" has been added to the 6.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

    jbd2: Fix wrongly judgement for buffer head removing while doing checkpoint

to the 6.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:
     jbd2-fix-wrongly-judgement-for-buffer-head-removing-.patch
and it can be found in the queue-6.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 3f003a96c8117824ae7320b53c5fcad340bd1910
Author: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
Date:   Tue Jun 6 21:59:26 2023 +0800

    jbd2: Fix wrongly judgement for buffer head removing while doing checkpoint
    
    [ Upstream commit e34c8dd238d0c9368b746480f313055f5bab5040 ]
    
    Following process,
    
    jbd2_journal_commit_transaction
    // there are several dirty buffer heads in transaction->t_checkpoint_list
              P1                   wb_workfn
    jbd2_log_do_checkpoint
     if (buffer_locked(bh)) // false
                                __block_write_full_page
                                 trylock_buffer(bh)
                                 test_clear_buffer_dirty(bh)
     if (!buffer_dirty(bh))
      __jbd2_journal_remove_checkpoint(jh)
       if (buffer_write_io_error(bh)) // false
                                 >> bh IO error occurs <<
     jbd2_cleanup_journal_tail
      __jbd2_update_log_tail
       jbd2_write_superblock
       // The bh won't be replayed in next mount.
    , which could corrupt the ext4 image, fetch a reproducer in [Link].
    
    Since writeback process clears buffer dirty after locking buffer head,
    we can fix it by try locking buffer and check dirtiness while buffer is
    locked, the buffer head can be removed if it is neither dirty nor locked.
    
    Link: https://bugzilla.kernel.org/show_bug.cgi?id=217490
    Fixes: 470decc613ab ("[PATCH] jbd2: initial copy of files from jbd")
    Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
    Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx>
    Reviewed-by: Jan Kara <jack@xxxxxxx>
    Link: https://lore.kernel.org/r/20230606135928.434610-5-yi.zhang@xxxxxxxxxxxxxxx
    Signed-off-by: Theodore Ts'o <tytso@xxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 25e3c20eb19f6..c4e0da6db7195 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -221,20 +221,6 @@ int jbd2_log_do_checkpoint(journal_t *journal)
 		jh = transaction->t_checkpoint_list;
 		bh = jh2bh(jh);
 
-		/*
-		 * The buffer may be writing back, or flushing out in the
-		 * last couple of cycles, or re-adding into a new transaction,
-		 * need to check it again until it's unlocked.
-		 */
-		if (buffer_locked(bh)) {
-			get_bh(bh);
-			spin_unlock(&journal->j_list_lock);
-			wait_on_buffer(bh);
-			/* the journal_head may have gone by now */
-			BUFFER_TRACE(bh, "brelse");
-			__brelse(bh);
-			goto retry;
-		}
 		if (jh->b_transaction != NULL) {
 			transaction_t *t = jh->b_transaction;
 			tid_t tid = t->t_tid;
@@ -269,7 +255,22 @@ int jbd2_log_do_checkpoint(journal_t *journal)
 			spin_lock(&journal->j_list_lock);
 			goto restart;
 		}
-		if (!buffer_dirty(bh)) {
+		if (!trylock_buffer(bh)) {
+			/*
+			 * The buffer is locked, it may be writing back, or
+			 * flushing out in the last couple of cycles, or
+			 * re-adding into a new transaction, need to check
+			 * it again until it's unlocked.
+			 */
+			get_bh(bh);
+			spin_unlock(&journal->j_list_lock);
+			wait_on_buffer(bh);
+			/* the journal_head may have gone by now */
+			BUFFER_TRACE(bh, "brelse");
+			__brelse(bh);
+			goto retry;
+		} else if (!buffer_dirty(bh)) {
+			unlock_buffer(bh);
 			BUFFER_TRACE(bh, "remove from checkpoint");
 			/*
 			 * If the transaction was released or the checkpoint
@@ -279,6 +280,7 @@ int jbd2_log_do_checkpoint(journal_t *journal)
 			    !transaction->t_checkpoint_list)
 				goto out;
 		} else {
+			unlock_buffer(bh);
 			/*
 			 * We are about to write the buffer, it could be
 			 * raced by some other transaction shrink or buffer



[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