FAILED: patch "[PATCH] jbd2: avoid infinite transaction commit loop" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x 27ba5b67312a944576addc4df44ac3b709aabede
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2024072940-corridor-private-1f67@gregkh' --subject-prefix 'PATCH 5.10.y' HEAD^..
Possible dependencies:
27ba5b67312a ("jbd2: avoid infinite transaction commit loop") b33d9f5909c8 ("jbd2: add sparse annotations for add_transaction_credits()")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 27ba5b67312a944576addc4df44ac3b709aabede Mon Sep 17 00:00:00 2001
From: Jan Kara <[email protected]>
Date: Mon, 24 Jun 2024 19:01:19 +0200
Subject: [PATCH] jbd2: avoid infinite transaction commit loop
Commit 9f356e5a4f12 ("jbd2: Account descriptor blocks into t_outstanding_credits") started to account descriptor blocks into transactions outstanding credits. However it didn't appropriately decrease the maximum amount of credits available to userspace. Thus if the filesystem requests a transaction smaller than j_max_transaction_buffers but large enough that when descriptor blocks are added the size exceeds j_max_transaction_buffers, we confuse add_transaction_credits() into thinking previous handles have grown the transaction too much and enter infinite journal commit loop in start_this_handle() -> add_transaction_credits() trying to create transaction with enough credits available.
Fix the problem by properly accounting for transaction space reserved for descriptor blocks when verifying requested transaction handle size.
fs/jbd2/transaction.c +14 -7
@@ -191,6 +191,13 @@ static void sub_reserved_credits(journal_t *journal, int blocks)wake_up (&journal->j_wait_reserved); } +/* Maximum number of blocks for user transaction payload */ +static int jbd2_max_user_trans_buffers (journal_t *journal) +{ +return journal->j_max_transaction_buffers - + journal->j_transaction_overhead_buffers; +} +/* * Wait until we can add credits for handle to the running transaction. Called * with j_state_lock held for reading. Returns 0 if handle joined the running
@@ -240,12 +247,12 @@ __must_hold(&journal->j_state_lock)* big to fit this handle? Wait until reserved credits are freed. */ if (atomic_read (&journal->j_reserved_credits) + total > - journal->j_max_transaction_buffers) { +jbd2_max_user_trans_buffers (journal)) {read_unlock (&journal->j_state_lock);jbd2_might_wait_for_commit (journal);wait_event (journal->j_wait_reserved,atomic_read (&journal->j_reserved_credits) + total <= - journal->j_max_transaction_buffers); +jbd2_max_user_trans_buffers (journal));__acquire (&journal->j_state_lock);/* fake out sparse */ return 1 ; }
@@ -285,14 +292,14 @@ __must_hold(&journal->j_state_lock) needed =atomic_add_return (rsv_blocks, &journal->j_reserved_credits);/* We allow at most half of a transaction to be reserved */ -if (needed > journal->j_max_transaction_buffers /2 ) { +if (needed >jbd2_max_user_trans_buffers (journal) /2 ) {sub_reserved_credits (journal, rsv_blocks);atomic_sub (total, &t->t_outstanding_credits);read_unlock (&journal->j_state_lock);jbd2_might_wait_for_commit (journal);wait_event (journal->j_wait_reserved,atomic_read (&journal->j_reserved_credits) + rsv_blocks - <= journal->j_max_transaction_buffers /2 ); + <=jbd2_max_user_trans_buffers (journal) /2 );__acquire (&journal->j_state_lock);/* fake out sparse */ return 1 ; }
@@ -322,12 +329,12 @@ static int start_this_handle(journal_t *journal, handle_t *handle,* size and limit the number of total credits to not exceed maximum * transaction size per operation. */ -if ((rsv_blocks > journal->j_max_transaction_buffers /2 ) || - (rsv_blocks + blocks > journal->j_max_transaction_buffers)) { +if (rsv_blocks >jbd2_max_user_trans_buffers (journal) /2 || + rsv_blocks + blocks >jbd2_max_user_trans_buffers (journal)) {printk (KERN_ERR "JBD2: %s wants too many credits " "credits:%d rsv_credits:%d max:%d\n" , current->comm, blocks, rsv_blocks, - journal->j_max_transaction_buffers); +jbd2_max_user_trans_buffers (journal));WARN_ON (1 );return -ENOSPC ; }