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 <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com>
Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
Closes #18289
This commit is contained in:
Ameer Hamza 2026-03-05 18:18:05 +05:00 committed by Brian Behlendorf
parent 0b0971f82f
commit 22fdaf0b1f
2 changed files with 15 additions and 10 deletions

View File

@ -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;
/*

View File

@ -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;
}