[PATCH v2 5/5] mm/mglru: reschedule between memcg reclaim attempts

From: Max Kellermann

Date: Tue Nov 03 2026 - 08:26:42 EST


shrink_one() can return immediately for empty or protected memcgs, and
try_to_shrink_lruvec() can break out before reaching its
cond_resched(). A scan through many memcgs can repeatedly rotate
entries without giving other runnable tasks a scheduling opportunity.

Call cond_resched_tasks_rcu_qs() (as the existing shrink_lruvec() loop
does) after shrink_one(), while the memcg reference still pins the
cursor and before reacquiring the RCU read lock. Also call it between
bins and nulls-marker retries, covering scans that skip every entry.

Signed-off-by: Max Kellermann <max.kellermann@xxxxxxxxx>
---
mm/vmscan.c | 11 +++++++++++
1 file changed, 11 insertions(+)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 899f756bd15b..5dc5e698e243 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -5395,6 +5395,9 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc)
gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq));
bin = first_bin = get_random_u32_below(MEMCG_NR_BINS);
restart:
+ /* Yield between bins/retries that contain only skipped entries. */
+ cond_resched_tasks_rcu_qs();
+
op = 0;
memcg = NULL;

@@ -5425,6 +5428,14 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc)

op = shrink_one(lruvec, sc);

+ /*
+ * Empty or protected memcgs can bypass the
+ * rescheduling points in page reclaim. The memcg
+ * reference pins our cursor while we yield outside
+ * the RCU read-side critical section.
+ */
+ cond_resched_tasks_rcu_qs();
+
rcu_read_lock();

if (should_abort_scan(lruvec, sc))
--
2.53.0