aboutsummaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorAlexander Motin <[email protected]>2023-09-20 14:17:11 -0400
committerBrian Behlendorf <[email protected]>2023-09-20 16:41:23 -0700
commit62677576a75e94396e945c4ecd9372f5d34e50cb (patch)
treeba66572c43b2aff127a3c8d84ea16f94f6aa94ab /module
parentf7a07d76ee5a6b698540c6873f194350539a7065 (diff)
ZIL: Fix potential race on flush deferring.
zil_lwb_set_zio_dependency() can not set write ZIO dependency on previous LWB's write ZIO if one is already in done handler and set state to LWB_STATE_WRITE_DONE. So theoretically done handler of next LWB's write ZIO may run before done handler of previous LWB write ZIO completes. In such case we can not defer flushes, since the flush issue process is not locked. This may fix some reported assertions of lwb_vdev_tree not being empty inside zil_free_lwb(). Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Alexander Motin <[email protected]> Sponsored by: iXsystems, Inc. Closes #15278
Diffstat (limited to 'module')
-rw-r--r--module/zfs/zil.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/module/zfs/zil.c b/module/zfs/zil.c
index b30676b42..9e9c9c225 100644
--- a/module/zfs/zil.c
+++ b/module/zfs/zil.c
@@ -1550,7 +1550,16 @@ zil_lwb_write_done(zio_t *zio)
lwb->lwb_state = LWB_STATE_WRITE_DONE;
lwb->lwb_child_zio = NULL;
lwb->lwb_write_zio = NULL;
+
+ /*
+ * If nlwb is not yet issued, zil_lwb_set_zio_dependency() is not
+ * called for it yet, and when it will be, it won't be able to make
+ * its write ZIO a parent this ZIO. In such case we can not defer
+ * our flushes or below may be a race between the done callbacks.
+ */
nlwb = list_next(&zilog->zl_lwb_list, lwb);
+ if (nlwb && nlwb->lwb_state != LWB_STATE_ISSUED)
+ nlwb = NULL;
mutex_exit(&zilog->zl_lock);
if (avl_numnodes(t) == 0)