Skip to content

Commit 15fc3d6

Browse files
ixhamzabehlendorf
authored andcommitted
L2ARC: Lazy sublist reset flags for persistent markers
Replace direct marker-to-tail manipulation with per-sublist boolean flags consumed lazily by feed threads. Each scanning thread resets its own marker when it sees the flag, rather than having another thread manipulate the marker directly. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Alexander Motin <[email protected]> Signed-off-by: Ameer Hamza <[email protected]> Closes #18289
1 parent 22fdaf0 commit 15fc3d6

File tree

2 files changed

+61
-35
lines changed

2 files changed

+61
-35
lines changed

include/sys/arc_impl.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ typedef struct l2arc_info {
5656
uint64_t l2arc_total_capacity; /* total L2ARC capacity */
5757
uint64_t l2arc_smallest_capacity; /* smallest device capacity */
5858
/*
59-
* Per-device thread coordination for sublist processing
59+
* Per-device thread coordination for sublist processing.
60+
* reset: flags sublist marker for lazy reset to tail.
6061
*/
6162
boolean_t *l2arc_sublist_busy[L2ARC_FEED_TYPES];
62-
kmutex_t l2arc_sublist_lock; /* protects busy flags */
63+
boolean_t *l2arc_sublist_reset[L2ARC_FEED_TYPES];
64+
kmutex_t l2arc_sublist_lock; /* protects busy/reset flags */
6365
int l2arc_next_sublist[L2ARC_FEED_TYPES]; /* round-robin */
6466
} l2arc_info_t;
6567

module/zfs/arc.c

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9073,6 +9073,8 @@ l2arc_pool_markers_init(spa_t *spa)
90739073
arc_state_alloc_markers(num_sublists);
90749074
spa->spa_l2arc_info.l2arc_sublist_busy[pass] =
90759075
kmem_zalloc(num_sublists * sizeof (boolean_t), KM_SLEEP);
9076+
spa->spa_l2arc_info.l2arc_sublist_reset[pass] =
9077+
kmem_zalloc(num_sublists * sizeof (boolean_t), KM_SLEEP);
90769078

90779079
for (int i = 0; i < num_sublists; i++) {
90789080
multilist_sublist_t *mls =
@@ -9117,12 +9119,18 @@ l2arc_pool_markers_fini(spa_t *spa)
91179119
num_sublists);
91189120
spa->spa_l2arc_info.l2arc_markers[pass] = NULL;
91199121

9120-
/* Free sublist busy flags for this pass */
9122+
/* Free sublist busy and reset flags for this pass */
91219123
ASSERT3P(spa->spa_l2arc_info.l2arc_sublist_busy[pass], !=,
91229124
NULL);
91239125
kmem_free(spa->spa_l2arc_info.l2arc_sublist_busy[pass],
91249126
num_sublists * sizeof (boolean_t));
91259127
spa->spa_l2arc_info.l2arc_sublist_busy[pass] = NULL;
9128+
9129+
ASSERT3P(spa->spa_l2arc_info.l2arc_sublist_reset[pass], !=,
9130+
NULL);
9131+
kmem_free(spa->spa_l2arc_info.l2arc_sublist_reset[pass],
9132+
num_sublists * sizeof (boolean_t));
9133+
spa->spa_l2arc_info.l2arc_sublist_reset[pass] = NULL;
91269134
}
91279135

91289136
mutex_destroy(&spa->spa_l2arc_info.l2arc_sublist_lock);
@@ -9608,6 +9616,19 @@ l2arc_write_sublist(spa_t *spa, l2arc_dev_t *dev, int pass, int sublist_idx,
96089616
persistent_marker = spa->spa_l2arc_info.
96099617
l2arc_markers[pass][sublist_idx];
96109618

9619+
/*
9620+
* Check if this sublist's marker was flagged for reset to tail.
9621+
* This handles depth cap resets and global resets without needing
9622+
* to coordinate with actively-scanning threads.
9623+
*/
9624+
if (save_position &&
9625+
spa->spa_l2arc_info.l2arc_sublist_reset[pass][sublist_idx]) {
9626+
multilist_sublist_remove(mls, persistent_marker);
9627+
multilist_sublist_insert_tail(mls, persistent_marker);
9628+
spa->spa_l2arc_info.l2arc_sublist_reset[pass][sublist_idx] =
9629+
B_FALSE;
9630+
}
9631+
96119632
if (save_position && persistent_marker == multilist_sublist_head(mls)) {
96129633
multilist_sublist_unlock(mls);
96139634
return (B_FALSE);
@@ -9798,14 +9819,24 @@ l2arc_write_sublist(spa_t *spa, l2arc_dev_t *dev, int pass, int sublist_idx,
97989819
}
97999820

98009821
/*
9801-
* Position persistent marker for next iteration. In case of
9802-
* save_position, validate that prev_hdr still belongs to the current
9803-
* sublist. The sublist lock is dropped during L2ARC write I/O, allowing
9804-
* ARC eviction to potentially free prev_hdr. If freed, we can't do much
9805-
* except to reset the marker.
9822+
* Position persistent marker for next iteration.
9823+
*
9824+
* If a reset was flagged during our scan (sublist lock was dropped
9825+
* for I/O, allowing another thread to set the flag), honor it by
9826+
* moving the marker to tail instead of advancing.
9827+
*
9828+
* Otherwise, validate that prev_hdr still belongs to the current
9829+
* sublist. The sublist lock is dropped during L2ARC write I/O,
9830+
* allowing ARC eviction to potentially free prev_hdr. If freed,
9831+
* we can't do much except to reset the marker.
98069832
*/
98079833
multilist_sublist_remove(mls, persistent_marker);
98089834
if (save_position &&
9835+
spa->spa_l2arc_info.l2arc_sublist_reset[pass][sublist_idx]) {
9836+
multilist_sublist_insert_tail(mls, persistent_marker);
9837+
spa->spa_l2arc_info.l2arc_sublist_reset[pass][sublist_idx] =
9838+
B_FALSE;
9839+
} else if (save_position &&
98099840
multilist_link_active(&prev_hdr->b_l1hdr.b_arc_node)) {
98109841
if (hdr != NULL) {
98119842
/*
@@ -9845,40 +9876,33 @@ l2arc_blk_fetch_done(zio_t *zio)
98459876
}
98469877

98479878
/*
9848-
* Reset all L2ARC markers to tail position for the given spa.
9879+
* Flag all sublists for a single pass for lazy marker reset to tail.
9880+
* Each sublist's marker will be reset when next visited by a feed thread.
98499881
*/
98509882
static void
9851-
l2arc_reset_all_markers(spa_t *spa)
9883+
l2arc_flag_pass_reset(spa_t *spa, int pass)
98529884
{
9853-
ASSERT(spa->spa_l2arc_info.l2arc_markers != NULL);
98549885
ASSERT(MUTEX_HELD(&spa->spa_l2arc_info.l2arc_sublist_lock));
98559886

9856-
for (int pass = 0; pass < L2ARC_FEED_TYPES; pass++) {
9857-
if (spa->spa_l2arc_info.l2arc_markers[pass] == NULL)
9858-
continue;
9859-
9860-
multilist_t *ml = l2arc_get_list(pass);
9861-
int num_sublists = multilist_get_num_sublists(ml);
9862-
9863-
for (int i = 0; i < num_sublists; i++) {
9864-
ASSERT3P(spa->spa_l2arc_info.l2arc_markers[pass][i],
9865-
!=, NULL);
9866-
multilist_sublist_t *mls =
9867-
multilist_sublist_lock_idx(ml, i);
9868-
9869-
/* Remove from current position */
9870-
ASSERT(multilist_link_active(&spa->spa_l2arc_info.
9871-
l2arc_markers[pass][i]->b_l1hdr.b_arc_node));
9872-
multilist_sublist_remove(mls, spa->spa_l2arc_info.
9873-
l2arc_markers[pass][i]);
9887+
multilist_t *ml = l2arc_get_list(pass);
9888+
int num_sublists = multilist_get_num_sublists(ml);
98749889

9875-
/* Insert at tail (like initialization) */
9876-
multilist_sublist_insert_tail(mls,
9877-
spa->spa_l2arc_info.l2arc_markers[pass][i]);
9878-
9879-
multilist_sublist_unlock(mls);
9880-
}
9890+
for (int i = 0; i < num_sublists; i++) {
9891+
multilist_sublist_t *mls = multilist_sublist_lock_idx(ml, i);
9892+
spa->spa_l2arc_info.l2arc_sublist_reset[pass][i] = B_TRUE;
9893+
multilist_sublist_unlock(mls);
98819894
}
9895+
}
9896+
9897+
/*
9898+
* Flag all L2ARC markers for lazy reset to tail for the given spa.
9899+
* Each sublist's marker will be reset when next visited by a feed thread.
9900+
*/
9901+
static void
9902+
l2arc_reset_all_markers(spa_t *spa)
9903+
{
9904+
for (int pass = 0; pass < L2ARC_FEED_TYPES; pass++)
9905+
l2arc_flag_pass_reset(spa, pass);
98829906

98839907
/* Reset write counter */
98849908
spa->spa_l2arc_info.l2arc_total_writes = 0;

0 commit comments

Comments
 (0)