Commit a61d90d7 authored by Jan Kara's avatar Jan Kara Committed by Linus Torvalds

jbd: fix race in buffer processing in commit code

In commit code, we scan buffers attached to a transaction.  During this
scan, we sometimes have to drop j_list_lock and then we recheck whether
the journal buffer head didn't get freed by journal_try_to_free_buffers().
 But checking for buffer_jbd(bh) isn't enough because a new journal head
could get attached to our buffer head.  So add a check whether the journal
head remained the same and whether it's still at the same transaction and
list.

This is a nasty bug and can cause problems like memory corruption (use after
free) or trigger various assertions in JBD code (observed).
Signed-off-by: default avatarJan Kara <jack@suse.cz>
Cc: <stable@kernel.org>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 463aea1a
...@@ -241,7 +241,7 @@ static int journal_submit_data_buffers(journal_t *journal, ...@@ -241,7 +241,7 @@ static int journal_submit_data_buffers(journal_t *journal,
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
} }
/* Someone already cleaned up the buffer? */ /* Someone already cleaned up the buffer? */
if (!buffer_jbd(bh) if (!buffer_jbd(bh) || bh2jh(bh) != jh
|| jh->b_transaction != commit_transaction || jh->b_transaction != commit_transaction
|| jh->b_jlist != BJ_SyncData) { || jh->b_jlist != BJ_SyncData) {
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
...@@ -478,7 +478,9 @@ void journal_commit_transaction(journal_t *journal) ...@@ -478,7 +478,9 @@ void journal_commit_transaction(journal_t *journal)
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
continue; continue;
} }
if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) { if (buffer_jbd(bh) && bh2jh(bh) == jh &&
jh->b_transaction == commit_transaction &&
jh->b_jlist == BJ_Locked) {
__journal_unfile_buffer(jh); __journal_unfile_buffer(jh);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
journal_remove_journal_head(bh); journal_remove_journal_head(bh);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment