Patch "jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborted" has been added to the 5.18-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 assertion 'jh->b_frozen_data == NULL' failure when journal aborted

to the 5.18-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-assertion-jh-b_frozen_data-null-failure-whe.patch
and it can be found in the queue-5.18 subdirectory.

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



commit c62951a9fd5034f1236461a9c203853638375d80
Author: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
Date:   Fri Jul 15 20:51:52 2022 +0800

    jbd2: fix assertion 'jh->b_frozen_data == NULL' failure when journal aborted
    
    [ Upstream commit 4a734f0869f970b8a9b65062ea40b09a5da9dba8 ]
    
    Following process will fail assertion 'jh->b_frozen_data == NULL' in
    jbd2_journal_dirty_metadata():
    
                       jbd2_journal_commit_transaction
    unlink(dir/a)
     jh->b_transaction = trans1
     jh->b_jlist = BJ_Metadata
                        journal->j_running_transaction = NULL
                        trans1->t_state = T_COMMIT
    unlink(dir/b)
     handle->h_trans = trans2
     do_get_write_access
      jh->b_modified = 0
      jh->b_frozen_data = frozen_buffer
      jh->b_next_transaction = trans2
     jbd2_journal_dirty_metadata
      is_handle_aborted
       is_journal_aborted // return false
    
               --> jbd2 abort <--
    
                         while (commit_transaction->t_buffers)
                          if (is_journal_aborted)
                           jbd2_journal_refile_buffer
                            __jbd2_journal_refile_buffer
                             WRITE_ONCE(jh->b_transaction,
                                                    jh->b_next_transaction)
                             WRITE_ONCE(jh->b_next_transaction, NULL)
                             __jbd2_journal_file_buffer(jh, BJ_Reserved)
            J_ASSERT_JH(jh, jh->b_frozen_data == NULL) // assertion failure !
    
    The reproducer (See detail in [Link]) reports:
     ------------[ cut here ]------------
     kernel BUG at fs/jbd2/transaction.c:1629!
     invalid opcode: 0000 [#1] PREEMPT SMP
     CPU: 2 PID: 584 Comm: unlink Tainted: G        W
     5.19.0-rc6-00115-g4a57a8400075-dirty #697
     RIP: 0010:jbd2_journal_dirty_metadata+0x3c5/0x470
     RSP: 0018:ffffc90000be7ce0 EFLAGS: 00010202
     Call Trace:
      <TASK>
      __ext4_handle_dirty_metadata+0xa0/0x290
      ext4_handle_dirty_dirblock+0x10c/0x1d0
      ext4_delete_entry+0x104/0x200
      __ext4_unlink+0x22b/0x360
      ext4_unlink+0x275/0x390
      vfs_unlink+0x20b/0x4c0
      do_unlinkat+0x42f/0x4c0
      __x64_sys_unlink+0x37/0x50
      do_syscall_64+0x35/0x80
    
    After journal aborting, __jbd2_journal_refile_buffer() is executed with
    holding @jh->b_state_lock, we can fix it by moving 'is_handle_aborted()'
    into the area protected by @jh->b_state_lock.
    
    Link: https://bugzilla.kernel.org/show_bug.cgi?id=216251
    Fixes: 470decc613ab20 ("[PATCH] jbd2: initial copy of files from jbd")
    Signed-off-by: Zhihao Cheng <chengzhihao1@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/20220715125152.4022726-1-chengzhihao1@xxxxxxxxxx
    Signed-off-by: Theodore Ts'o <tytso@xxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index fcb9175016a5..49f109699933 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1486,8 +1486,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
 	struct journal_head *jh;
 	int ret = 0;
 
-	if (is_handle_aborted(handle))
-		return -EROFS;
 	if (!buffer_jbd(bh))
 		return -EUCLEAN;
 
@@ -1534,6 +1532,18 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
 	journal = transaction->t_journal;
 	spin_lock(&jh->b_state_lock);
 
+	if (is_handle_aborted(handle)) {
+		/*
+		 * Check journal aborting with @jh->b_state_lock locked,
+		 * since 'jh->b_transaction' could be replaced with
+		 * 'jh->b_next_transaction' during old transaction
+		 * committing if journal aborted, which may fail
+		 * assertion on 'jh->b_frozen_data == NULL'.
+		 */
+		ret = -EROFS;
+		goto out_unlock_bh;
+	}
+
 	if (jh->b_modified == 0) {
 		/*
 		 * This buffer's got modified and becoming part



[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