From: Zhang Yi <yizhang089@gmail.com>
To: Max Kellermann <max.kellermann@ionos.com>
Cc: linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org,
jack@suse.com, tytso@mit.edu, stable@vger.kernel.org
Subject: Re: [PATCH 2/2] jbd2: bound shrinker scans by examined checkpoint buffers
Date: Tue, 14 Jul 2026 14:53:41 +0800 [thread overview]
Message-ID: <7bb69013-c6f1-4dee-bb9c-c576c7b765d7@gmail.com> (raw)
In-Reply-To: <20260713102229.1598812-3-max.kellermann@ionos.com>
On 7/13/2026 6:22 PM, Max Kellermann wrote:
> The jbd2 shrinker currently accounts only checkpoint buffers that it
> successfully releases against nr_to_scan. Busy buffers therefore do not
> consume the scan budget.
>
> If a checkpoint transaction contains mostly busy buffers, the shrinker
> can scan its entire checkpoint list while holding journal->j_list_lock.
> Large checkpoint lists can result in excessive lock hold times and leave
> other CPUs spinning on j_list_lock, causing soft lockups or RCU stalls.
>
> Pass nr_to_scan into journal_shrink_one_cp_list() and decrement it for
> every buffer examined, including busy buffers. Pass NULL from checkpoint
> cleanup paths so their existing full-list behavior is preserved.
>
> This restores the scan-budget semantics that existed before
> journal_shrink_one_cp_list() was changed to always scan a complete
> checkpoint list.
>
> Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()")
> Cc: stable@vger.kernel.org
> Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
This makes the semantic of nr_to_scan more clear.
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
> ---
> fs/jbd2/checkpoint.c | 25 +++++++++++++------------
> 1 file changed, 13 insertions(+), 12 deletions(-)
>
> diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
> index 5266017565ac..513273712010 100644
> --- a/fs/jbd2/checkpoint.c
> +++ b/fs/jbd2/checkpoint.c
> @@ -358,15 +358,16 @@ int jbd2_cleanup_journal_tail(journal_t *journal)
> /*
> * journal_shrink_one_cp_list
> *
> - * Find all the written-back checkpoint buffers in the given list
> - * and try to release them. If the whole transaction is released, set
> - * the 'released' parameter. Return the number of released checkpointed
> - * buffers.
> + * Find written-back checkpoint buffers in the given list and try to release
> + * them. If 'nr_to_scan' is set, scan at most that many buffers. If the whole
> + * transaction is released, set the 'released' parameter. Return the number of
> + * released checkpointed buffers.
> *
> * Called with j_list_lock held.
> */
> static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
> enum jbd2_shrink_type type,
> + unsigned long *nr_to_scan,
> bool *released)
> {
> struct journal_head *last_jh;
> @@ -375,13 +376,15 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
> int ret;
>
> *released = false;
> - if (!jh)
> + if (!jh || (nr_to_scan && !*nr_to_scan))
> return 0;
>
> last_jh = jh->b_cpprev;
> do {
> jh = next_jh;
> next_jh = jh->b_cpnext;
> + if (nr_to_scan)
> + (*nr_to_scan)--;
>
> if (type == JBD2_SHRINK_DESTROY) {
> ret = __jbd2_journal_remove_checkpoint(jh);
> @@ -403,7 +406,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh,
> next:
> if (need_resched())
> break;
> - } while (jh != last_jh);
> + } while (jh != last_jh && (!nr_to_scan || *nr_to_scan));
>
> return nr_freed;
> }
> @@ -425,7 +428,6 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
> tid_t first_tid = 0, last_tid = 0, next_tid = 0;
> tid_t tid = 0;
> unsigned long nr_freed = 0;
> - unsigned long freed;
> bool first_set = false;
>
> again:
> @@ -458,10 +460,9 @@ unsigned long jbd2_journal_shrink_checkpoint_list(journal_t *journal,
> next_transaction = transaction->t_cpnext;
> tid = transaction->t_tid;
>
> - freed = journal_shrink_one_cp_list(transaction->t_checkpoint_list,
> - JBD2_SHRINK_BUSY_SKIP, &released);
> - nr_freed += freed;
> - (*nr_to_scan) -= min(*nr_to_scan, freed);
> + nr_freed += journal_shrink_one_cp_list(transaction->t_checkpoint_list,
> + JBD2_SHRINK_BUSY_SKIP,
> + nr_to_scan, &released);
> if (*nr_to_scan == 0)
> break;
> if (need_resched() || spin_needbreak(&journal->j_list_lock))
> @@ -517,7 +518,7 @@ void __jbd2_journal_clean_checkpoint_list(journal_t *journal,
> transaction = next_transaction;
> next_transaction = transaction->t_cpnext;
> journal_shrink_one_cp_list(transaction->t_checkpoint_list,
> - type, &released);
> + type, NULL, &released);
> /*
> * This function only frees up some memory if possible so we
> * dont have an obligation to finish processing. Bail out if
next prev parent reply other threads:[~2026-07-14 6:53 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-13 10:22 [PATCH 0/2] jbd2: bound j_list_lock hold time in the checkpoint shrinker Max Kellermann
2026-07-13 10:22 ` [PATCH 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers Max Kellermann
2026-07-13 12:16 ` Jan Kara
2026-07-14 6:26 ` Zhang Yi
2026-07-13 10:22 ` [PATCH 2/2] jbd2: bound shrinker scans by examined " Max Kellermann
2026-07-13 12:24 ` Jan Kara
2026-07-14 6:53 ` Zhang Yi [this message]
2026-07-13 12:53 ` [PATCH 0/2] jbd2: bound j_list_lock hold time in the checkpoint shrinker Zhang Yi
2026-07-13 15:03 ` Max Kellermann
2026-07-14 3:41 ` 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=7bb69013-c6f1-4dee-bb9c-c576c7b765d7@gmail.com \
--to=yizhang089@gmail.com \
--cc=jack@suse.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=max.kellermann@ionos.com \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.