Skip to content

Commit efbc3cb

Browse files
Zhihao Chenggregkh
authored andcommitted
jbd2: Fix wrongly judgement for buffer head removing while doing checkpoint
[ Upstream commit e34c8dd ] 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: 470decc ("[PATCH] jbd2: initial copy of files from jbd") Signed-off-by: Zhihao Cheng <[email protected]> Signed-off-by: Zhang Yi <[email protected]> Reviewed-by: Jan Kara <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 1440353 commit efbc3cb

File tree

1 file changed

+17
-15
lines changed

1 file changed

+17
-15
lines changed

fs/jbd2/checkpoint.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,6 @@ int jbd2_log_do_checkpoint(journal_t *journal)
221221
jh = transaction->t_checkpoint_list;
222222
bh = jh2bh(jh);
223223

224-
/*
225-
* The buffer may be writing back, or flushing out in the
226-
* last couple of cycles, or re-adding into a new transaction,
227-
* need to check it again until it's unlocked.
228-
*/
229-
if (buffer_locked(bh)) {
230-
get_bh(bh);
231-
spin_unlock(&journal->j_list_lock);
232-
wait_on_buffer(bh);
233-
/* the journal_head may have gone by now */
234-
BUFFER_TRACE(bh, "brelse");
235-
__brelse(bh);
236-
goto retry;
237-
}
238224
if (jh->b_transaction != NULL) {
239225
transaction_t *t = jh->b_transaction;
240226
tid_t tid = t->t_tid;
@@ -269,7 +255,22 @@ int jbd2_log_do_checkpoint(journal_t *journal)
269255
spin_lock(&journal->j_list_lock);
270256
goto restart;
271257
}
272-
if (!buffer_dirty(bh)) {
258+
if (!trylock_buffer(bh)) {
259+
/*
260+
* The buffer is locked, it may be writing back, or
261+
* flushing out in the last couple of cycles, or
262+
* re-adding into a new transaction, need to check
263+
* it again until it's unlocked.
264+
*/
265+
get_bh(bh);
266+
spin_unlock(&journal->j_list_lock);
267+
wait_on_buffer(bh);
268+
/* the journal_head may have gone by now */
269+
BUFFER_TRACE(bh, "brelse");
270+
__brelse(bh);
271+
goto retry;
272+
} else if (!buffer_dirty(bh)) {
273+
unlock_buffer(bh);
273274
BUFFER_TRACE(bh, "remove from checkpoint");
274275
/*
275276
* If the transaction was released or the checkpoint
@@ -279,6 +280,7 @@ int jbd2_log_do_checkpoint(journal_t *journal)
279280
!transaction->t_checkpoint_list)
280281
goto out;
281282
} else {
283+
unlock_buffer(bh);
282284
/*
283285
* We are about to write the buffer, it could be
284286
* raced by some other transaction shrink or buffer

0 commit comments

Comments
 (0)