L2ARC: Relax locking during write
Previous code held ARC state sublist lock throughout all L2ARC write process, which included number of allocations and even ZIO issues. Being blocked in any of those places the code could also block ARC eviction, that could cause OOM activation or even dead- lock if system is low on memory or one is too fragmented. Fix it by dropping the lock as soon as we see a block eligible for L2ARC writing and pick it up later using earlier inserted marker. While there, also reduce scope of hash lock, moving ZIO allocation and other operations not requiring header access out of it. All operations requiring header access move under hash lock, since L2_WRITING flag does not prevent header eviction only transition to arc_l2c_only state with L1 header. To be able to manipulate sublist lock and marker as needed add few more multilist functions and modify one. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Alexander Motin <mav@FreeBSD.org> Sponsored by: iXsystems, Inc. Closes #16040
This commit is contained in:
parent
9e63631dea
commit
997f85b4d3
|
@ -82,12 +82,15 @@ int multilist_is_empty(multilist_t *);
|
||||||
unsigned int multilist_get_num_sublists(multilist_t *);
|
unsigned int multilist_get_num_sublists(multilist_t *);
|
||||||
unsigned int multilist_get_random_index(multilist_t *);
|
unsigned int multilist_get_random_index(multilist_t *);
|
||||||
|
|
||||||
multilist_sublist_t *multilist_sublist_lock(multilist_t *, unsigned int);
|
void multilist_sublist_lock(multilist_sublist_t *);
|
||||||
|
multilist_sublist_t *multilist_sublist_lock_idx(multilist_t *, unsigned int);
|
||||||
multilist_sublist_t *multilist_sublist_lock_obj(multilist_t *, void *);
|
multilist_sublist_t *multilist_sublist_lock_obj(multilist_t *, void *);
|
||||||
void multilist_sublist_unlock(multilist_sublist_t *);
|
void multilist_sublist_unlock(multilist_sublist_t *);
|
||||||
|
|
||||||
void multilist_sublist_insert_head(multilist_sublist_t *, void *);
|
void multilist_sublist_insert_head(multilist_sublist_t *, void *);
|
||||||
void multilist_sublist_insert_tail(multilist_sublist_t *, void *);
|
void multilist_sublist_insert_tail(multilist_sublist_t *, void *);
|
||||||
|
void multilist_sublist_insert_after(multilist_sublist_t *, void *, void *);
|
||||||
|
void multilist_sublist_insert_before(multilist_sublist_t *, void *, void *);
|
||||||
void multilist_sublist_move_forward(multilist_sublist_t *mls, void *obj);
|
void multilist_sublist_move_forward(multilist_sublist_t *mls, void *obj);
|
||||||
void multilist_sublist_remove(multilist_sublist_t *, void *);
|
void multilist_sublist_remove(multilist_sublist_t *, void *);
|
||||||
int multilist_sublist_is_empty(multilist_sublist_t *);
|
int multilist_sublist_is_empty(multilist_sublist_t *);
|
||||||
|
|
187
module/zfs/arc.c
187
module/zfs/arc.c
|
@ -3872,7 +3872,7 @@ arc_evict_state_impl(multilist_t *ml, int idx, arc_buf_hdr_t *marker,
|
||||||
|
|
||||||
ASSERT3P(marker, !=, NULL);
|
ASSERT3P(marker, !=, NULL);
|
||||||
|
|
||||||
mls = multilist_sublist_lock(ml, idx);
|
mls = multilist_sublist_lock_idx(ml, idx);
|
||||||
|
|
||||||
for (hdr = multilist_sublist_prev(mls, marker); likely(hdr != NULL);
|
for (hdr = multilist_sublist_prev(mls, marker); likely(hdr != NULL);
|
||||||
hdr = multilist_sublist_prev(mls, marker)) {
|
hdr = multilist_sublist_prev(mls, marker)) {
|
||||||
|
@ -3984,6 +3984,26 @@ arc_evict_state_impl(multilist_t *ml, int idx, arc_buf_hdr_t *marker,
|
||||||
return (bytes_evicted);
|
return (bytes_evicted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static arc_buf_hdr_t *
|
||||||
|
arc_state_alloc_marker(void)
|
||||||
|
{
|
||||||
|
arc_buf_hdr_t *marker = kmem_cache_alloc(hdr_full_cache, KM_SLEEP);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A b_spa of 0 is used to indicate that this header is
|
||||||
|
* a marker. This fact is used in arc_evict_state_impl().
|
||||||
|
*/
|
||||||
|
marker->b_spa = 0;
|
||||||
|
|
||||||
|
return (marker);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
arc_state_free_marker(arc_buf_hdr_t *marker)
|
||||||
|
{
|
||||||
|
kmem_cache_free(hdr_full_cache, marker);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate an array of buffer headers used as placeholders during arc state
|
* Allocate an array of buffer headers used as placeholders during arc state
|
||||||
* eviction.
|
* eviction.
|
||||||
|
@ -3994,16 +4014,8 @@ arc_state_alloc_markers(int count)
|
||||||
arc_buf_hdr_t **markers;
|
arc_buf_hdr_t **markers;
|
||||||
|
|
||||||
markers = kmem_zalloc(sizeof (*markers) * count, KM_SLEEP);
|
markers = kmem_zalloc(sizeof (*markers) * count, KM_SLEEP);
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++)
|
||||||
markers[i] = kmem_cache_alloc(hdr_full_cache, KM_SLEEP);
|
markers[i] = arc_state_alloc_marker();
|
||||||
|
|
||||||
/*
|
|
||||||
* A b_spa of 0 is used to indicate that this header is
|
|
||||||
* a marker. This fact is used in arc_evict_state_impl().
|
|
||||||
*/
|
|
||||||
markers[i]->b_spa = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
return (markers);
|
return (markers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4011,7 +4023,7 @@ static void
|
||||||
arc_state_free_markers(arc_buf_hdr_t **markers, int count)
|
arc_state_free_markers(arc_buf_hdr_t **markers, int count)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
kmem_cache_free(hdr_full_cache, markers[i]);
|
arc_state_free_marker(markers[i]);
|
||||||
kmem_free(markers, sizeof (*markers) * count);
|
kmem_free(markers, sizeof (*markers) * count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4055,7 +4067,7 @@ arc_evict_state(arc_state_t *state, arc_buf_contents_t type, uint64_t spa,
|
||||||
for (int i = 0; i < num_sublists; i++) {
|
for (int i = 0; i < num_sublists; i++) {
|
||||||
multilist_sublist_t *mls;
|
multilist_sublist_t *mls;
|
||||||
|
|
||||||
mls = multilist_sublist_lock(ml, i);
|
mls = multilist_sublist_lock_idx(ml, i);
|
||||||
multilist_sublist_insert_tail(mls, markers[i]);
|
multilist_sublist_insert_tail(mls, markers[i]);
|
||||||
multilist_sublist_unlock(mls);
|
multilist_sublist_unlock(mls);
|
||||||
}
|
}
|
||||||
|
@ -4120,7 +4132,7 @@ arc_evict_state(arc_state_t *state, arc_buf_contents_t type, uint64_t spa,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < num_sublists; i++) {
|
for (int i = 0; i < num_sublists; i++) {
|
||||||
multilist_sublist_t *mls = multilist_sublist_lock(ml, i);
|
multilist_sublist_t *mls = multilist_sublist_lock_idx(ml, i);
|
||||||
multilist_sublist_remove(mls, markers[i]);
|
multilist_sublist_remove(mls, markers[i]);
|
||||||
multilist_sublist_unlock(mls);
|
multilist_sublist_unlock(mls);
|
||||||
}
|
}
|
||||||
|
@ -8633,7 +8645,7 @@ l2arc_sublist_lock(int list_num)
|
||||||
* sublists being selected.
|
* sublists being selected.
|
||||||
*/
|
*/
|
||||||
idx = multilist_get_random_index(ml);
|
idx = multilist_get_random_index(ml);
|
||||||
return (multilist_sublist_lock(ml, idx));
|
return (multilist_sublist_lock_idx(ml, idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -9046,9 +9058,9 @@ l2arc_blk_fetch_done(zio_t *zio)
|
||||||
static uint64_t
|
static uint64_t
|
||||||
l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
||||||
{
|
{
|
||||||
arc_buf_hdr_t *hdr, *hdr_prev, *head;
|
arc_buf_hdr_t *hdr, *head, *marker;
|
||||||
uint64_t write_asize, write_psize, write_lsize, headroom;
|
uint64_t write_asize, write_psize, headroom;
|
||||||
boolean_t full;
|
boolean_t full, from_head = !arc_warm;
|
||||||
l2arc_write_callback_t *cb = NULL;
|
l2arc_write_callback_t *cb = NULL;
|
||||||
zio_t *pio, *wzio;
|
zio_t *pio, *wzio;
|
||||||
uint64_t guid = spa_load_guid(spa);
|
uint64_t guid = spa_load_guid(spa);
|
||||||
|
@ -9057,10 +9069,11 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
||||||
ASSERT3P(dev->l2ad_vdev, !=, NULL);
|
ASSERT3P(dev->l2ad_vdev, !=, NULL);
|
||||||
|
|
||||||
pio = NULL;
|
pio = NULL;
|
||||||
write_lsize = write_asize = write_psize = 0;
|
write_asize = write_psize = 0;
|
||||||
full = B_FALSE;
|
full = B_FALSE;
|
||||||
head = kmem_cache_alloc(hdr_l2only_cache, KM_PUSHPAGE);
|
head = kmem_cache_alloc(hdr_l2only_cache, KM_PUSHPAGE);
|
||||||
arc_hdr_set_flags(head, ARC_FLAG_L2_WRITE_HEAD | ARC_FLAG_HAS_L2HDR);
|
arc_hdr_set_flags(head, ARC_FLAG_L2_WRITE_HEAD | ARC_FLAG_HAS_L2HDR);
|
||||||
|
marker = arc_state_alloc_marker();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy buffers for L2ARC writing.
|
* Copy buffers for L2ARC writing.
|
||||||
|
@ -9075,40 +9088,34 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
multilist_sublist_t *mls = l2arc_sublist_lock(pass);
|
|
||||||
uint64_t passed_sz = 0;
|
uint64_t passed_sz = 0;
|
||||||
|
|
||||||
VERIFY3P(mls, !=, NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* L2ARC fast warmup.
|
|
||||||
*
|
|
||||||
* Until the ARC is warm and starts to evict, read from the
|
|
||||||
* head of the ARC lists rather than the tail.
|
|
||||||
*/
|
|
||||||
if (arc_warm == B_FALSE)
|
|
||||||
hdr = multilist_sublist_head(mls);
|
|
||||||
else
|
|
||||||
hdr = multilist_sublist_tail(mls);
|
|
||||||
|
|
||||||
headroom = target_sz * l2arc_headroom;
|
headroom = target_sz * l2arc_headroom;
|
||||||
if (zfs_compressed_arc_enabled)
|
if (zfs_compressed_arc_enabled)
|
||||||
headroom = (headroom * l2arc_headroom_boost) / 100;
|
headroom = (headroom * l2arc_headroom_boost) / 100;
|
||||||
|
|
||||||
for (; hdr; hdr = hdr_prev) {
|
/*
|
||||||
|
* Until the ARC is warm and starts to evict, read from the
|
||||||
|
* head of the ARC lists rather than the tail.
|
||||||
|
*/
|
||||||
|
multilist_sublist_t *mls = l2arc_sublist_lock(pass);
|
||||||
|
ASSERT3P(mls, !=, NULL);
|
||||||
|
if (from_head)
|
||||||
|
hdr = multilist_sublist_head(mls);
|
||||||
|
else
|
||||||
|
hdr = multilist_sublist_tail(mls);
|
||||||
|
|
||||||
|
while (hdr != NULL) {
|
||||||
kmutex_t *hash_lock;
|
kmutex_t *hash_lock;
|
||||||
abd_t *to_write = NULL;
|
abd_t *to_write = NULL;
|
||||||
|
|
||||||
if (arc_warm == B_FALSE)
|
|
||||||
hdr_prev = multilist_sublist_next(mls, hdr);
|
|
||||||
else
|
|
||||||
hdr_prev = multilist_sublist_prev(mls, hdr);
|
|
||||||
|
|
||||||
hash_lock = HDR_LOCK(hdr);
|
hash_lock = HDR_LOCK(hdr);
|
||||||
if (!mutex_tryenter(hash_lock)) {
|
if (!mutex_tryenter(hash_lock)) {
|
||||||
/*
|
skip:
|
||||||
* Skip this buffer rather than waiting.
|
/* Skip this buffer rather than waiting. */
|
||||||
*/
|
if (from_head)
|
||||||
|
hdr = multilist_sublist_next(mls, hdr);
|
||||||
|
else
|
||||||
|
hdr = multilist_sublist_prev(mls, hdr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9123,11 +9130,10 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
||||||
|
|
||||||
if (!l2arc_write_eligible(guid, hdr)) {
|
if (!l2arc_write_eligible(guid, hdr)) {
|
||||||
mutex_exit(hash_lock);
|
mutex_exit(hash_lock);
|
||||||
continue;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(HDR_HAS_L1HDR(hdr));
|
ASSERT(HDR_HAS_L1HDR(hdr));
|
||||||
|
|
||||||
ASSERT3U(HDR_GET_PSIZE(hdr), >, 0);
|
ASSERT3U(HDR_GET_PSIZE(hdr), >, 0);
|
||||||
ASSERT3U(arc_hdr_size(hdr), >, 0);
|
ASSERT3U(arc_hdr_size(hdr), >, 0);
|
||||||
ASSERT(hdr->b_l1hdr.b_pabd != NULL ||
|
ASSERT(hdr->b_l1hdr.b_pabd != NULL ||
|
||||||
|
@ -9149,12 +9155,18 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We rely on the L1 portion of the header below, so
|
* We should not sleep with sublist lock held or it
|
||||||
* it's invalid for this header to have been evicted out
|
* may block ARC eviction. Insert a marker to save
|
||||||
* of the ghost cache, prior to being written out. The
|
* the position and drop the lock.
|
||||||
* ARC_FLAG_L2_WRITING bit ensures this won't happen.
|
|
||||||
*/
|
*/
|
||||||
arc_hdr_set_flags(hdr, ARC_FLAG_L2_WRITING);
|
if (from_head) {
|
||||||
|
multilist_sublist_insert_after(mls, hdr,
|
||||||
|
marker);
|
||||||
|
} else {
|
||||||
|
multilist_sublist_insert_before(mls, hdr,
|
||||||
|
marker);
|
||||||
|
}
|
||||||
|
multilist_sublist_unlock(mls);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this header has b_rabd, we can use this since it
|
* If this header has b_rabd, we can use this since it
|
||||||
|
@ -9185,32 +9197,45 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
||||||
&to_write);
|
&to_write);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
arc_hdr_clear_flags(hdr,
|
arc_hdr_clear_flags(hdr,
|
||||||
ARC_FLAG_L2_WRITING);
|
ARC_FLAG_L2CACHE);
|
||||||
mutex_exit(hash_lock);
|
mutex_exit(hash_lock);
|
||||||
continue;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
l2arc_free_abd_on_write(to_write, asize, type);
|
l2arc_free_abd_on_write(to_write, asize, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hdr->b_l2hdr.b_dev = dev;
|
||||||
|
hdr->b_l2hdr.b_daddr = dev->l2ad_hand;
|
||||||
|
hdr->b_l2hdr.b_hits = 0;
|
||||||
|
hdr->b_l2hdr.b_arcs_state =
|
||||||
|
hdr->b_l1hdr.b_state->arcs_state;
|
||||||
|
mutex_enter(&dev->l2ad_mtx);
|
||||||
if (pio == NULL) {
|
if (pio == NULL) {
|
||||||
/*
|
/*
|
||||||
* Insert a dummy header on the buflist so
|
* Insert a dummy header on the buflist so
|
||||||
* l2arc_write_done() can find where the
|
* l2arc_write_done() can find where the
|
||||||
* write buffers begin without searching.
|
* write buffers begin without searching.
|
||||||
*/
|
*/
|
||||||
mutex_enter(&dev->l2ad_mtx);
|
|
||||||
list_insert_head(&dev->l2ad_buflist, head);
|
list_insert_head(&dev->l2ad_buflist, head);
|
||||||
|
}
|
||||||
|
list_insert_head(&dev->l2ad_buflist, hdr);
|
||||||
mutex_exit(&dev->l2ad_mtx);
|
mutex_exit(&dev->l2ad_mtx);
|
||||||
|
arc_hdr_set_flags(hdr, ARC_FLAG_HAS_L2HDR |
|
||||||
|
ARC_FLAG_L2_WRITING);
|
||||||
|
|
||||||
|
(void) zfs_refcount_add_many(&dev->l2ad_alloc,
|
||||||
|
arc_hdr_size(hdr), hdr);
|
||||||
|
l2arc_hdr_arcstats_increment(hdr);
|
||||||
|
|
||||||
|
boolean_t commit = l2arc_log_blk_insert(dev, hdr);
|
||||||
|
mutex_exit(hash_lock);
|
||||||
|
|
||||||
|
if (pio == NULL) {
|
||||||
cb = kmem_alloc(
|
cb = kmem_alloc(
|
||||||
sizeof (l2arc_write_callback_t), KM_SLEEP);
|
sizeof (l2arc_write_callback_t), KM_SLEEP);
|
||||||
cb->l2wcb_dev = dev;
|
cb->l2wcb_dev = dev;
|
||||||
cb->l2wcb_head = head;
|
cb->l2wcb_head = head;
|
||||||
/*
|
|
||||||
* Create a list to save allocated abd buffers
|
|
||||||
* for l2arc_log_blk_commit().
|
|
||||||
*/
|
|
||||||
list_create(&cb->l2wcb_abd_list,
|
list_create(&cb->l2wcb_abd_list,
|
||||||
sizeof (l2arc_lb_abd_buf_t),
|
sizeof (l2arc_lb_abd_buf_t),
|
||||||
offsetof(l2arc_lb_abd_buf_t, node));
|
offsetof(l2arc_lb_abd_buf_t, node));
|
||||||
|
@ -9218,54 +9243,34 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
||||||
ZIO_FLAG_CANFAIL);
|
ZIO_FLAG_CANFAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
hdr->b_l2hdr.b_dev = dev;
|
|
||||||
hdr->b_l2hdr.b_hits = 0;
|
|
||||||
|
|
||||||
hdr->b_l2hdr.b_daddr = dev->l2ad_hand;
|
|
||||||
hdr->b_l2hdr.b_arcs_state =
|
|
||||||
hdr->b_l1hdr.b_state->arcs_state;
|
|
||||||
arc_hdr_set_flags(hdr, ARC_FLAG_HAS_L2HDR);
|
|
||||||
|
|
||||||
mutex_enter(&dev->l2ad_mtx);
|
|
||||||
list_insert_head(&dev->l2ad_buflist, hdr);
|
|
||||||
mutex_exit(&dev->l2ad_mtx);
|
|
||||||
|
|
||||||
(void) zfs_refcount_add_many(&dev->l2ad_alloc,
|
|
||||||
arc_hdr_size(hdr), hdr);
|
|
||||||
|
|
||||||
wzio = zio_write_phys(pio, dev->l2ad_vdev,
|
wzio = zio_write_phys(pio, dev->l2ad_vdev,
|
||||||
hdr->b_l2hdr.b_daddr, asize, to_write,
|
dev->l2ad_hand, asize, to_write,
|
||||||
ZIO_CHECKSUM_OFF, NULL, hdr,
|
ZIO_CHECKSUM_OFF, NULL, hdr,
|
||||||
ZIO_PRIORITY_ASYNC_WRITE,
|
ZIO_PRIORITY_ASYNC_WRITE,
|
||||||
ZIO_FLAG_CANFAIL, B_FALSE);
|
ZIO_FLAG_CANFAIL, B_FALSE);
|
||||||
|
|
||||||
write_lsize += HDR_GET_LSIZE(hdr);
|
|
||||||
DTRACE_PROBE2(l2arc__write, vdev_t *, dev->l2ad_vdev,
|
DTRACE_PROBE2(l2arc__write, vdev_t *, dev->l2ad_vdev,
|
||||||
zio_t *, wzio);
|
zio_t *, wzio);
|
||||||
|
zio_nowait(wzio);
|
||||||
|
|
||||||
write_psize += psize;
|
write_psize += psize;
|
||||||
write_asize += asize;
|
write_asize += asize;
|
||||||
dev->l2ad_hand += asize;
|
dev->l2ad_hand += asize;
|
||||||
l2arc_hdr_arcstats_increment(hdr);
|
|
||||||
vdev_space_update(dev->l2ad_vdev, asize, 0, 0);
|
vdev_space_update(dev->l2ad_vdev, asize, 0, 0);
|
||||||
|
|
||||||
mutex_exit(hash_lock);
|
if (commit) {
|
||||||
|
/* l2ad_hand will be adjusted inside. */
|
||||||
/*
|
|
||||||
* Append buf info to current log and commit if full.
|
|
||||||
* arcstat_l2_{size,asize} kstats are updated
|
|
||||||
* internally.
|
|
||||||
*/
|
|
||||||
if (l2arc_log_blk_insert(dev, hdr)) {
|
|
||||||
/*
|
|
||||||
* l2ad_hand will be adjusted in
|
|
||||||
* l2arc_log_blk_commit().
|
|
||||||
*/
|
|
||||||
write_asize +=
|
write_asize +=
|
||||||
l2arc_log_blk_commit(dev, pio, cb);
|
l2arc_log_blk_commit(dev, pio, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
zio_nowait(wzio);
|
next:
|
||||||
|
multilist_sublist_lock(mls);
|
||||||
|
if (from_head)
|
||||||
|
hdr = multilist_sublist_next(mls, marker);
|
||||||
|
else
|
||||||
|
hdr = multilist_sublist_prev(mls, marker);
|
||||||
|
multilist_sublist_remove(mls, marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
multilist_sublist_unlock(mls);
|
multilist_sublist_unlock(mls);
|
||||||
|
@ -9274,9 +9279,11 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arc_state_free_marker(marker);
|
||||||
|
|
||||||
/* No buffers selected for writing? */
|
/* No buffers selected for writing? */
|
||||||
if (pio == NULL) {
|
if (pio == NULL) {
|
||||||
ASSERT0(write_lsize);
|
ASSERT0(write_psize);
|
||||||
ASSERT(!HDR_HAS_L1HDR(head));
|
ASSERT(!HDR_HAS_L1HDR(head));
|
||||||
kmem_cache_free(hdr_l2only_cache, head);
|
kmem_cache_free(hdr_l2only_cache, head);
|
||||||
|
|
||||||
|
@ -10604,7 +10611,7 @@ l2arc_log_blk_insert(l2arc_dev_t *dev, const arc_buf_hdr_t *hdr)
|
||||||
L2BLK_SET_TYPE((le)->le_prop, hdr->b_type);
|
L2BLK_SET_TYPE((le)->le_prop, hdr->b_type);
|
||||||
L2BLK_SET_PROTECTED((le)->le_prop, !!(HDR_PROTECTED(hdr)));
|
L2BLK_SET_PROTECTED((le)->le_prop, !!(HDR_PROTECTED(hdr)));
|
||||||
L2BLK_SET_PREFETCH((le)->le_prop, !!(HDR_PREFETCH(hdr)));
|
L2BLK_SET_PREFETCH((le)->le_prop, !!(HDR_PREFETCH(hdr)));
|
||||||
L2BLK_SET_STATE((le)->le_prop, hdr->b_l1hdr.b_state->arcs_state);
|
L2BLK_SET_STATE((le)->le_prop, hdr->b_l2hdr.b_arcs_state);
|
||||||
|
|
||||||
dev->l2ad_log_blk_payload_asize += vdev_psize_to_asize(dev->l2ad_vdev,
|
dev->l2ad_log_blk_payload_asize += vdev_psize_to_asize(dev->l2ad_vdev,
|
||||||
HDR_GET_PSIZE(hdr));
|
HDR_GET_PSIZE(hdr));
|
||||||
|
|
|
@ -769,7 +769,7 @@ static void
|
||||||
dbuf_evict_one(void)
|
dbuf_evict_one(void)
|
||||||
{
|
{
|
||||||
int idx = multilist_get_random_index(&dbuf_caches[DB_DBUF_CACHE].cache);
|
int idx = multilist_get_random_index(&dbuf_caches[DB_DBUF_CACHE].cache);
|
||||||
multilist_sublist_t *mls = multilist_sublist_lock(
|
multilist_sublist_t *mls = multilist_sublist_lock_idx(
|
||||||
&dbuf_caches[DB_DBUF_CACHE].cache, idx);
|
&dbuf_caches[DB_DBUF_CACHE].cache, idx);
|
||||||
|
|
||||||
ASSERT(!MUTEX_HELD(&dbuf_evict_lock));
|
ASSERT(!MUTEX_HELD(&dbuf_evict_lock));
|
||||||
|
|
|
@ -1665,7 +1665,7 @@ sync_dnodes_task(void *arg)
|
||||||
objset_t *os = soa->soa_os;
|
objset_t *os = soa->soa_os;
|
||||||
|
|
||||||
multilist_sublist_t *ms =
|
multilist_sublist_t *ms =
|
||||||
multilist_sublist_lock(sda->sda_list, sda->sda_sublist_idx);
|
multilist_sublist_lock_idx(sda->sda_list, sda->sda_sublist_idx);
|
||||||
|
|
||||||
dmu_objset_sync_dnodes(ms, soa->soa_tx);
|
dmu_objset_sync_dnodes(ms, soa->soa_tx);
|
||||||
|
|
||||||
|
@ -2076,8 +2076,8 @@ userquota_updates_task(void *arg)
|
||||||
dnode_t *dn;
|
dnode_t *dn;
|
||||||
userquota_cache_t cache = { { 0 } };
|
userquota_cache_t cache = { { 0 } };
|
||||||
|
|
||||||
multilist_sublist_t *list =
|
multilist_sublist_t *list = multilist_sublist_lock_idx(
|
||||||
multilist_sublist_lock(&os->os_synced_dnodes, uua->uua_sublist_idx);
|
&os->os_synced_dnodes, uua->uua_sublist_idx);
|
||||||
|
|
||||||
ASSERT(multilist_sublist_head(list) == NULL ||
|
ASSERT(multilist_sublist_head(list) == NULL ||
|
||||||
dmu_objset_userused_enabled(os));
|
dmu_objset_userused_enabled(os));
|
||||||
|
@ -2159,8 +2159,8 @@ dnode_rele_task(void *arg)
|
||||||
userquota_updates_arg_t *uua = arg;
|
userquota_updates_arg_t *uua = arg;
|
||||||
objset_t *os = uua->uua_os;
|
objset_t *os = uua->uua_os;
|
||||||
|
|
||||||
multilist_sublist_t *list =
|
multilist_sublist_t *list = multilist_sublist_lock_idx(
|
||||||
multilist_sublist_lock(&os->os_synced_dnodes, uua->uua_sublist_idx);
|
&os->os_synced_dnodes, uua->uua_sublist_idx);
|
||||||
|
|
||||||
dnode_t *dn;
|
dnode_t *dn;
|
||||||
while ((dn = multilist_sublist_head(list)) != NULL) {
|
while ((dn = multilist_sublist_head(list)) != NULL) {
|
||||||
|
|
|
@ -639,7 +639,7 @@ metaslab_class_evict_old(metaslab_class_t *mc, uint64_t txg)
|
||||||
{
|
{
|
||||||
multilist_t *ml = &mc->mc_metaslab_txg_list;
|
multilist_t *ml = &mc->mc_metaslab_txg_list;
|
||||||
for (int i = 0; i < multilist_get_num_sublists(ml); i++) {
|
for (int i = 0; i < multilist_get_num_sublists(ml); i++) {
|
||||||
multilist_sublist_t *mls = multilist_sublist_lock(ml, i);
|
multilist_sublist_t *mls = multilist_sublist_lock_idx(ml, i);
|
||||||
metaslab_t *msp = multilist_sublist_head(mls);
|
metaslab_t *msp = multilist_sublist_head(mls);
|
||||||
multilist_sublist_unlock(mls);
|
multilist_sublist_unlock(mls);
|
||||||
while (msp != NULL) {
|
while (msp != NULL) {
|
||||||
|
@ -656,7 +656,7 @@ metaslab_class_evict_old(metaslab_class_t *mc, uint64_t txg)
|
||||||
i--;
|
i--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mls = multilist_sublist_lock(ml, i);
|
mls = multilist_sublist_lock_idx(ml, i);
|
||||||
metaslab_t *next_msp = multilist_sublist_next(mls, msp);
|
metaslab_t *next_msp = multilist_sublist_next(mls, msp);
|
||||||
multilist_sublist_unlock(mls);
|
multilist_sublist_unlock(mls);
|
||||||
if (txg >
|
if (txg >
|
||||||
|
@ -2232,12 +2232,12 @@ metaslab_potentially_evict(metaslab_class_t *mc)
|
||||||
unsigned int idx = multilist_get_random_index(
|
unsigned int idx = multilist_get_random_index(
|
||||||
&mc->mc_metaslab_txg_list);
|
&mc->mc_metaslab_txg_list);
|
||||||
multilist_sublist_t *mls =
|
multilist_sublist_t *mls =
|
||||||
multilist_sublist_lock(&mc->mc_metaslab_txg_list, idx);
|
multilist_sublist_lock_idx(&mc->mc_metaslab_txg_list, idx);
|
||||||
metaslab_t *msp = multilist_sublist_head(mls);
|
metaslab_t *msp = multilist_sublist_head(mls);
|
||||||
multilist_sublist_unlock(mls);
|
multilist_sublist_unlock(mls);
|
||||||
while (msp != NULL && allmem * zfs_metaslab_mem_limit / 100 <
|
while (msp != NULL && allmem * zfs_metaslab_mem_limit / 100 <
|
||||||
inuse * size) {
|
inuse * size) {
|
||||||
VERIFY3P(mls, ==, multilist_sublist_lock(
|
VERIFY3P(mls, ==, multilist_sublist_lock_idx(
|
||||||
&mc->mc_metaslab_txg_list, idx));
|
&mc->mc_metaslab_txg_list, idx));
|
||||||
ASSERT3U(idx, ==,
|
ASSERT3U(idx, ==,
|
||||||
metaslab_idx_func(&mc->mc_metaslab_txg_list, msp));
|
metaslab_idx_func(&mc->mc_metaslab_txg_list, msp));
|
||||||
|
|
|
@ -277,9 +277,15 @@ multilist_get_random_index(multilist_t *ml)
|
||||||
return (random_in_range(ml->ml_num_sublists));
|
return (random_in_range(ml->ml_num_sublists));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
multilist_sublist_lock(multilist_sublist_t *mls)
|
||||||
|
{
|
||||||
|
mutex_enter(&mls->mls_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* Lock and return the sublist specified at the given index */
|
/* Lock and return the sublist specified at the given index */
|
||||||
multilist_sublist_t *
|
multilist_sublist_t *
|
||||||
multilist_sublist_lock(multilist_t *ml, unsigned int sublist_idx)
|
multilist_sublist_lock_idx(multilist_t *ml, unsigned int sublist_idx)
|
||||||
{
|
{
|
||||||
multilist_sublist_t *mls;
|
multilist_sublist_t *mls;
|
||||||
|
|
||||||
|
@ -294,7 +300,7 @@ multilist_sublist_lock(multilist_t *ml, unsigned int sublist_idx)
|
||||||
multilist_sublist_t *
|
multilist_sublist_t *
|
||||||
multilist_sublist_lock_obj(multilist_t *ml, void *obj)
|
multilist_sublist_lock_obj(multilist_t *ml, void *obj)
|
||||||
{
|
{
|
||||||
return (multilist_sublist_lock(ml, ml->ml_index_func(ml, obj)));
|
return (multilist_sublist_lock_idx(ml, ml->ml_index_func(ml, obj)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -327,6 +333,22 @@ multilist_sublist_insert_tail(multilist_sublist_t *mls, void *obj)
|
||||||
list_insert_tail(&mls->mls_list, obj);
|
list_insert_tail(&mls->mls_list, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* please see comment above multilist_sublist_insert_head */
|
||||||
|
void
|
||||||
|
multilist_sublist_insert_after(multilist_sublist_t *mls, void *prev, void *obj)
|
||||||
|
{
|
||||||
|
ASSERT(MUTEX_HELD(&mls->mls_lock));
|
||||||
|
list_insert_after(&mls->mls_list, prev, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* please see comment above multilist_sublist_insert_head */
|
||||||
|
void
|
||||||
|
multilist_sublist_insert_before(multilist_sublist_t *mls, void *next, void *obj)
|
||||||
|
{
|
||||||
|
ASSERT(MUTEX_HELD(&mls->mls_lock));
|
||||||
|
list_insert_before(&mls->mls_list, next, obj);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Move the object one element forward in the list.
|
* Move the object one element forward in the list.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue