* [PATCH 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers [not found] <20260713102229.1598812-1-max.kellermann@ionos.com> @ 2026-07-13 10:22 ` Max Kellermann 2026-07-13 12:16 ` Jan Kara ` (2 more replies) 2026-07-13 10:22 ` [PATCH 2/2] jbd2: bound shrinker scans by examined " Max Kellermann 1 sibling, 3 replies; 8+ messages in thread From: Max Kellermann @ 2026-07-13 10:22 UTC (permalink / raw) To: tytso, jack, linux-ext4, linux-kernel; +Cc: Max Kellermann, stable journal_shrink_one_cp_list() skips busy checkpoint buffers when called with JBD2_SHRINK_BUSY_SKIP. The continue statement on this path also skips the need_resched() check at the end of the loop body. Consequently, when a checkpoint list contains mostly busy buffers, the shrinker can walk the entire list while holding journal->j_list_lock, even when a reschedule has been requested. Large checkpoint lists under memory pressure can therefore cause long lock hold times and leave other CPUs spinning on j_list_lock, resulting in soft lockups or RCU stalls. Route the busy-buffer path through the need_resched() check so that the shrinker can release j_list_lock and reschedule promptly, restoring parity with the clean-buffer path, which already checks need_resched(). This does not change which checkpoint buffers are eligible for removal. Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()") Cc: stable@vger.kernel.org Signed-off-by: Max Kellermann <max.kellermann@ionos.com> --- fs/jbd2/checkpoint.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 1508e2f54462..5266017565ac 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c @@ -389,7 +389,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh, ret = jbd2_journal_try_remove_checkpoint(jh); if (ret < 0) { if (type == JBD2_SHRINK_BUSY_SKIP) - continue; + goto next; break; } } @@ -400,6 +400,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh, break; } +next: if (need_resched()) break; } while (jh != last_jh); -- 2.47.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers 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-16 20:04 ` Andreas Dilger 2 siblings, 0 replies; 8+ messages in thread From: Jan Kara @ 2026-07-13 12:16 UTC (permalink / raw) To: Max Kellermann; +Cc: tytso, jack, linux-ext4, linux-kernel, stable On Mon 13-07-26 12:22:28, Max Kellermann wrote: > journal_shrink_one_cp_list() skips busy checkpoint buffers when called > with JBD2_SHRINK_BUSY_SKIP. The continue statement on this path also > skips the need_resched() check at the end of the loop body. > > Consequently, when a checkpoint list contains mostly busy buffers, the > shrinker can walk the entire list while holding journal->j_list_lock, > even when a reschedule has been requested. Large checkpoint lists under > memory pressure can therefore cause long lock hold times and leave other > CPUs spinning on j_list_lock, resulting in soft lockups or RCU stalls. > > Route the busy-buffer path through the need_resched() check so that the > shrinker can release j_list_lock and reschedule promptly, restoring > parity with the clean-buffer path, which already checks need_resched(). > This does not change which checkpoint buffers are eligible for removal. > > Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()") > Cc: stable@vger.kernel.org > Signed-off-by: Max Kellermann <max.kellermann@ionos.com> Good catch! Thanks for fixing this. Feel free to add: Reviewed-by: Jan Kara <jack@suse.cz> Honza > --- > fs/jbd2/checkpoint.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c > index 1508e2f54462..5266017565ac 100644 > --- a/fs/jbd2/checkpoint.c > +++ b/fs/jbd2/checkpoint.c > @@ -389,7 +389,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh, > ret = jbd2_journal_try_remove_checkpoint(jh); > if (ret < 0) { > if (type == JBD2_SHRINK_BUSY_SKIP) > - continue; > + goto next; > break; > } > } > @@ -400,6 +400,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh, > break; > } > > +next: > if (need_resched()) > break; > } while (jh != last_jh); > -- > 2.47.3 > -- Jan Kara <jack@suse.com> SUSE Labs, CR ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers 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-16 20:04 ` Andreas Dilger 2 siblings, 0 replies; 8+ messages in thread From: Zhang Yi @ 2026-07-14 6:26 UTC (permalink / raw) To: Max Kellermann; +Cc: linux-ext4, linux-kernel, tytso, jack, stable On 7/13/2026 6:22 PM, Max Kellermann wrote: > journal_shrink_one_cp_list() skips busy checkpoint buffers when called > with JBD2_SHRINK_BUSY_SKIP. The continue statement on this path also > skips the need_resched() check at the end of the loop body. > > Consequently, when a checkpoint list contains mostly busy buffers, the > shrinker can walk the entire list while holding journal->j_list_lock, > even when a reschedule has been requested. Large checkpoint lists under > memory pressure can therefore cause long lock hold times and leave other > CPUs spinning on j_list_lock, resulting in soft lockups or RCU stalls. > > Route the busy-buffer path through the need_resched() check so that the > shrinker can release j_list_lock and reschedule promptly, restoring > parity with the clean-buffer path, which already checks need_resched(). > This does not change which checkpoint buffers are eligible for removal. > > Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()") > Cc: stable@vger.kernel.org > Signed-off-by: Max Kellermann <max.kellermann@ionos.com> Thanks for the fix! This looks good to me. Reviewed-by: Zhang Yi <yi.zhang@huawei.com> > --- > fs/jbd2/checkpoint.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c > index 1508e2f54462..5266017565ac 100644 > --- a/fs/jbd2/checkpoint.c > +++ b/fs/jbd2/checkpoint.c > @@ -389,7 +389,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh, > ret = jbd2_journal_try_remove_checkpoint(jh); > if (ret < 0) { > if (type == JBD2_SHRINK_BUSY_SKIP) > - continue; > + goto next; > break; > } > } > @@ -400,6 +400,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh, > break; > } > > +next: > if (need_resched()) > break; > } while (jh != last_jh); ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers 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-16 20:04 ` Andreas Dilger 2026-07-17 5:47 ` Max Kellermann 2 siblings, 1 reply; 8+ messages in thread From: Andreas Dilger @ 2026-07-16 20:04 UTC (permalink / raw) To: Max Kellermann; +Cc: tytso, jack, linux-ext4, linux-kernel, stable On Jul 13, 2026, at 04:22, Max Kellermann <max.kellermann@ionos.com> wrote: > > journal_shrink_one_cp_list() skips busy checkpoint buffers when called > with JBD2_SHRINK_BUSY_SKIP. The continue statement on this path also > skips the need_resched() check at the end of the loop body. > > Consequently, when a checkpoint list contains mostly busy buffers, the > shrinker can walk the entire list while holding journal->j_list_lock, > even when a reschedule has been requested. Large checkpoint lists under > memory pressure can therefore cause long lock hold times and leave other > CPUs spinning on j_list_lock, resulting in soft lockups or RCU stalls. > > Route the busy-buffer path through the need_resched() check so that the > shrinker can release j_list_lock and reschedule promptly, restoring > parity with the clean-buffer path, which already checks need_resched(). > This does not change which checkpoint buffers are eligible for removal. One question I had about this patch is whether the list cleanup could get into a livelock if it becomes too large? If the iterator is processing a large number of jh that cannot be freed, then `need_resched()` is hit, if it restarts from the beginning of the list each time without processing at least one jh it will not make forward progress. Cheers, Andreas > Fixes: b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()") > Cc: stable@vger.kernel.org > Signed-off-by: Max Kellermann <max.kellermann@ionos.com> > --- > fs/jbd2/checkpoint.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c > index 1508e2f54462..5266017565ac 100644 > --- a/fs/jbd2/checkpoint.c > +++ b/fs/jbd2/checkpoint.c > @@ -389,7 +389,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh, > ret = jbd2_journal_try_remove_checkpoint(jh); > if (ret < 0) { > if (type == JBD2_SHRINK_BUSY_SKIP) > - continue; > + goto next; > break; > } > } > @@ -400,6 +400,7 @@ static unsigned long journal_shrink_one_cp_list(struct journal_head *jh, > break; > } > > +next: > if (need_resched()) > break; > } while (jh != last_jh); > -- > 2.47.3 > > Cheers, Andreas ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers 2026-07-16 20:04 ` Andreas Dilger @ 2026-07-17 5:47 ` Max Kellermann 0 siblings, 0 replies; 8+ messages in thread From: Max Kellermann @ 2026-07-17 5:47 UTC (permalink / raw) To: Andreas Dilger; +Cc: tytso, jack, linux-ext4, linux-kernel, stable On Thu, Jul 16, 2026 at 10:04 PM Andreas Dilger <adilger@dilger.ca> wrote: > One question I had about this patch is whether the list cleanup could get > into a livelock if it becomes too large? It was a livelock *without* this patch, because all CPUs were busy inside this piece of shrinker code; one of them holding j_list_lock, all others spinning on that very spinlock (all CPUs busy), and actal I/O was stalled seemingly forever. > If the iterator is processing > a large number of jh that cannot be freed, then `need_resched()` is hit, > if it restarts from the beginning of the list each time without processing > at least one jh it will not make forward progress. If no progress is made, then this shrinker call just wasn't able to free anything. That was the behavior before b98dba273a0e ("jbd2: remove journal_clean_one_cp_list()") and my patch restores this behavior. It's not a problem. It's faily normal for shrinkers to not be able to free anything. -- Max Kellermann Principal Architect Hosting Technology cm4all | Im Mediapark 6a | 50670 Köln | Germany General information about the company can be found here: https://www.cm4all.com/impressum A member of the IONOS Group ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] jbd2: bound shrinker scans by examined checkpoint buffers [not found] <20260713102229.1598812-1-max.kellermann@ionos.com> 2026-07-13 10:22 ` [PATCH 1/2] jbd2: check need_resched() when skipping busy checkpoint buffers Max Kellermann @ 2026-07-13 10:22 ` Max Kellermann 2026-07-13 12:24 ` Jan Kara 2026-07-14 6:53 ` Zhang Yi 1 sibling, 2 replies; 8+ messages in thread From: Max Kellermann @ 2026-07-13 10:22 UTC (permalink / raw) To: tytso, jack, linux-ext4, linux-kernel; +Cc: Max Kellermann, stable 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> --- 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 -- 2.47.3 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] jbd2: bound shrinker scans by examined checkpoint buffers 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 1 sibling, 0 replies; 8+ messages in thread From: Jan Kara @ 2026-07-13 12:24 UTC (permalink / raw) To: Max Kellermann; +Cc: tytso, jack, linux-ext4, linux-kernel, stable On Mon 13-07-26 12:22:29, 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> Looks good. Feel free to add: Reviewed-by: Jan Kara <jack@suse.cz> Honza > --- > 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 > -- > 2.47.3 > -- Jan Kara <jack@suse.com> SUSE Labs, CR ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] jbd2: bound shrinker scans by examined checkpoint buffers 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 1 sibling, 0 replies; 8+ messages in thread From: Zhang Yi @ 2026-07-14 6:53 UTC (permalink / raw) To: Max Kellermann; +Cc: linux-ext4, linux-kernel, jack, tytso, stable 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 ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-07-17 5:47 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260713102229.1598812-1-max.kellermann@ionos.com>
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-16 20:04 ` Andreas Dilger
2026-07-17 5:47 ` Max Kellermann
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 is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox