From 22fdaf0b1f624eeb16363fecf0a4d7294b335375 Mon Sep 17 00:00:00 2001 From: Ameer Hamza Date: Thu, 5 Mar 2026 18:18:05 +0500 Subject: [PATCH] L2ARC: Even sublist headroom distribution with round-robin selection The dynamic headroom redistribution formula gave later sublists progressively larger scanning budgets, and random sublist selection caused uneven coverage across sublists. For depth cap to work effectively, each sublist should be equally and fairly treated. Use equal per-sublist headroom (headroom / num_sublists) for even distribution and deterministic round-robin selection for fair coverage across cycles. Reviewed-by: Brian Behlendorf Reviewed-by: Alexander Motin Signed-off-by: Ameer Hamza Closes #18289 --- include/sys/arc_impl.h | 1 + module/zfs/arc.c | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/sys/arc_impl.h b/include/sys/arc_impl.h index 1c400c513..14f797959 100644 --- a/include/sys/arc_impl.h +++ b/include/sys/arc_impl.h @@ -60,6 +60,7 @@ typedef struct l2arc_info { */ boolean_t *l2arc_sublist_busy[L2ARC_FEED_TYPES]; kmutex_t l2arc_sublist_lock; /* protects busy flags */ + int l2arc_next_sublist[L2ARC_FEED_TYPES]; /* round-robin */ } l2arc_info_t; /* diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 5db549bcb..bd94a43ce 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -9960,20 +9960,20 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz) multilist_t *ml = l2arc_get_list(pass); ASSERT3P(ml, !=, NULL); int num_sublists = multilist_get_num_sublists(ml); - int current_sublist = multilist_get_random_index(ml); uint64_t consumed_headroom = 0; + /* + * Equal per-sublist headroom prevents later + * sublists from getting disproportionate shares + * that would defeat the depth cap. + */ + uint64_t sublist_headroom = headroom / num_sublists; + + int current_sublist = spa->spa_l2arc_info. + l2arc_next_sublist[pass]; int processed_sublists = 0; while (processed_sublists < num_sublists && !full) { - uint64_t sublist_headroom; - - if (consumed_headroom >= headroom) - break; - - sublist_headroom = (headroom - consumed_headroom) / - (num_sublists - processed_sublists); - - if (sublist_headroom == 0) + if (consumed_headroom + sublist_headroom > headroom) break; /* @@ -10016,6 +10016,10 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz) processed_sublists++; } + spa->spa_l2arc_info.l2arc_next_sublist[pass] = + (spa->spa_l2arc_info.l2arc_next_sublist[pass] + 1) % + num_sublists; + if (full == B_TRUE) break; }