From: Zhang Yi <yi.zhang@huawei.com>
To: Jan Kara <jack@suse.cz>
Cc: <linux-ext4@vger.kernel.org>,
Alexander Coffin <alex.coffin@maticrobots.com>,
<stable@vger.kernel.org>, Ted Tso <tytso@mit.edu>,
<chengzhihao1@huawei.com>
Subject: Re: [PATCH v2 3/4] jbd2: Avoid infinite transaction commit loop
Date: Wed, 26 Jun 2024 15:38:42 +0800 [thread overview]
Message-ID: <2d49e3de-d7e7-2fd1-0b7a-9a3f9e04cd4d@huawei.com> (raw)
In-Reply-To: <20240624170127.3253-3-jack@suse.cz>
On 2024/6/25 1:01, Jan Kara wrote:
> 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.
>
Hello Jan!
I understand that the incorrect max transaction limit in
start_this_handle() could lead to infinite loop in
start_this_handle()-> add_transaction_credits() with large enough
userspace credits (from j_max_transaction_buffers - overheads to
j_max_transaction_buffers), but I don't get how could it lead to ran
out of space in the journal commit traction? IIUC, below codes in
add_transaction_credits() could make sure that we have enough space
when committing traction:
static int add_transaction_credits()
{
...
if (jbd2_log_space_left(journal) < journal->j_max_transaction_buffers) {
...
return 1;
...
}
...
}
I can't open and download the image Alexander gave, so I can't get to
the bottom of this issue, please let me know what happened with
jbd2_journal_next_log_block().
Thanks,
Yi.
> Fix the problem by properly accounting for transaction space reserved
> for descriptor blocks when verifying requested transaction handle size.
>
> CC: stable@vger.kernel.org
> Fixes: 9f356e5a4f12 ("jbd2: Account descriptor blocks into t_outstanding_credits")
> Reported-by: Alexander Coffin <alex.coffin@maticrobots.com>
> Link: https://lore.kernel.org/all/CA+hUFcuGs04JHZ_WzA1zGN57+ehL2qmHOt5a7RMpo+rv6Vyxtw@mail.gmail.com
> Signed-off-by: Jan Kara <jack@suse.cz>
> ---
> fs/jbd2/transaction.c | 21 ++++++++++++++-------
> 1 file changed, 14 insertions(+), 7 deletions(-)
>
> diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
> index a095f1a3114b..66513c18ca29 100644
> --- a/fs/jbd2/transaction.c
> +++ b/fs/jbd2/transaction.c
> @@ -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;
> }
>
next prev parent reply other threads:[~2024-06-26 7:38 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20240624165406.12784-1-jack@suse.cz>
2024-06-24 17:01 ` [PATCH v2 1/4] jbd2: Make jbd2_journal_get_max_txn_bufs() internal Jan Kara
2024-06-27 6:47 ` Zhang Yi
2024-07-11 2:35 ` Theodore Ts'o
2024-06-24 17:01 ` [PATCH v2 2/4] jbd2: Precompute number of transaction descriptor blocks Jan Kara
2024-06-25 9:31 ` Kemeng Shi
2024-06-25 11:07 ` Jan Kara
2024-06-25 12:02 ` Kemeng Shi
2024-06-27 7:06 ` Zhang Yi
2024-06-24 17:01 ` [PATCH v2 3/4] jbd2: Avoid infinite transaction commit loop Jan Kara
2024-06-26 7:38 ` Zhang Yi [this message]
2024-06-26 11:22 ` Jan Kara
2024-06-26 13:24 ` Zhang Yi
2024-06-26 14:55 ` Jan Kara
2024-06-27 6:43 ` Zhang Yi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2d49e3de-d7e7-2fd1-0b7a-9a3f9e04cd4d@huawei.com \
--to=yi.zhang@huawei.com \
--cc=alex.coffin@maticrobots.com \
--cc=chengzhihao1@huawei.com \
--cc=jack@suse.cz \
--cc=linux-ext4@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox