Skip to content

Commit 2cb992a

Browse files
authored
ZIL: Fix config lock deadlock.
When we have some LWBs closed and their ZIOs ready to be issued, we can not afford sleeping on config lock if somebody else try to lock it as writer, or it will cause a deadlock. To solve it, move spa_config_enter() from zil_lwb_write_issue() to zil_lwb_write_close() under zl_issuer_lock to enforce lock ordering with other threads. Now if we can't immediately lock config, issue all previously closed LWBs so that they could drop their config locks after completion, and only then allow sleeping on our lock. Reviewed-by: Mark Maybee <mark.maybee@delphix.com> Reviewed-by: Prakash Surya <prakash.surya@delphix.com> Reviewed-by: George Wilson <george.wilson@delphix.com> Signed-off-by: Alexander Motin <mav@FreeBSD.org> Sponsored by: iXsystems, Inc. Closes #15078 Closes #15080
1 parent fb344f5 commit 2cb992a

File tree

1 file changed

+27
-7
lines changed

1 file changed

+27
-7
lines changed

module/zfs/zil.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ static kmem_cache_t *zil_lwb_cache;
151151
static kmem_cache_t *zil_zcw_cache;
152152

153153
static void zil_lwb_commit(zilog_t *zilog, lwb_t *lwb, itx_t *itx);
154+
static void zil_lwb_write_issue(zilog_t *zilog, lwb_t *lwb);
154155
static itx_t *zil_itx_clone(itx_t *oitx);
155156

156157
static int
@@ -1768,7 +1769,7 @@ static uint_t zil_maxblocksize = SPA_OLD_MAXBLOCKSIZE;
17681769
* Has to be called under zl_issuer_lock to chain more lwbs.
17691770
*/
17701771
static lwb_t *
1771-
zil_lwb_write_close(zilog_t *zilog, lwb_t *lwb)
1772+
zil_lwb_write_close(zilog_t *zilog, lwb_t *lwb, list_t *ilwbs)
17721773
{
17731774
lwb_t *nlwb = NULL;
17741775
zil_chain_t *zilc;
@@ -1870,6 +1871,27 @@ zil_lwb_write_close(zilog_t *zilog, lwb_t *lwb)
18701871

18711872
dmu_tx_commit(tx);
18721873

1874+
/*
1875+
* We need to acquire the config lock for the lwb to issue it later.
1876+
* However, if we already have a queue of closed parent lwbs already
1877+
* holding the config lock (but not yet issued), we can't block here
1878+
* waiting on the lock or we will deadlock. In that case we must
1879+
* first issue to parent IOs before waiting on the lock.
1880+
*/
1881+
if (ilwbs && !list_is_empty(ilwbs)) {
1882+
if (!spa_config_tryenter(spa, SCL_STATE, lwb, RW_READER)) {
1883+
lwb_t *tlwb;
1884+
while ((tlwb = list_remove_head(ilwbs)) != NULL)
1885+
zil_lwb_write_issue(zilog, tlwb);
1886+
spa_config_enter(spa, SCL_STATE, lwb, RW_READER);
1887+
}
1888+
} else {
1889+
spa_config_enter(spa, SCL_STATE, lwb, RW_READER);
1890+
}
1891+
1892+
if (ilwbs)
1893+
list_insert_tail(ilwbs, lwb);
1894+
18731895
/*
18741896
* If there was an allocation failure then nlwb will be null which
18751897
* forces a txg_wait_synced().
@@ -1933,7 +1955,7 @@ zil_lwb_write_issue(zilog_t *zilog, lwb_t *lwb)
19331955
ZIL_STAT_INCR(zilog, zil_itx_metaslab_normal_alloc,
19341956
BP_GET_LSIZE(&lwb->lwb_blk));
19351957
}
1936-
spa_config_enter(zilog->zl_spa, SCL_STATE, lwb, RW_READER);
1958+
ASSERT(spa_config_held(zilog->zl_spa, SCL_STATE, RW_READER));
19371959
zil_lwb_add_block(lwb, &lwb->lwb_blk);
19381960
lwb->lwb_issued_timestamp = gethrtime();
19391961
zio_nowait(lwb->lwb_root_zio);
@@ -2037,8 +2059,7 @@ zil_lwb_assign(zilog_t *zilog, lwb_t *lwb, itx_t *itx, list_t *ilwbs)
20372059
lwb_sp < zil_max_waste_space(zilog) &&
20382060
(dlen % max_log_data == 0 ||
20392061
lwb_sp < reclen + dlen % max_log_data))) {
2040-
list_insert_tail(ilwbs, lwb);
2041-
lwb = zil_lwb_write_close(zilog, lwb);
2062+
lwb = zil_lwb_write_close(zilog, lwb, ilwbs);
20422063
if (lwb == NULL)
20432064
return (NULL);
20442065
zil_lwb_write_open(zilog, lwb);
@@ -2937,8 +2958,7 @@ zil_process_commit_list(zilog_t *zilog, zil_commit_waiter_t *zcw, list_t *ilwbs)
29372958
zfs_commit_timeout_pct / 100;
29382959
if (sleep < zil_min_commit_timeout ||
29392960
lwb->lwb_sz - lwb->lwb_nused < lwb->lwb_sz / 8) {
2940-
list_insert_tail(ilwbs, lwb);
2941-
lwb = zil_lwb_write_close(zilog, lwb);
2961+
lwb = zil_lwb_write_close(zilog, lwb, ilwbs);
29422962
zilog->zl_cur_used = 0;
29432963
if (lwb == NULL) {
29442964
while ((lwb = list_remove_head(ilwbs))
@@ -3096,7 +3116,7 @@ zil_commit_waiter_timeout(zilog_t *zilog, zil_commit_waiter_t *zcw)
30963116
* since we've reached the commit waiter's timeout and it still
30973117
* hasn't been issued.
30983118
*/
3099-
lwb_t *nlwb = zil_lwb_write_close(zilog, lwb);
3119+
lwb_t *nlwb = zil_lwb_write_close(zilog, lwb, NULL);
31003120

31013121
ASSERT3S(lwb->lwb_state, !=, LWB_STATE_OPENED);
31023122

0 commit comments

Comments
 (0)