From af7d60959278c03a5094879c8b7d418a4c109c70 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 6 Jun 2025 05:38:26 +1000 Subject: [PATCH] zpl: handle suspend from two remaining calls to `txg_wait_synced()` * zfs_link: allow tempfile sync to fail if pool suspends 4653e2f7d3 (#17355) allows dmu_tx_assign() to fail if the pool suspends when failmode=continue, but zfs_link() can fall back to txg_wait_synced() if it has to wait for a tempfile to be fully created before continuing, which will block if the pool suspends. Handle this by requesting an error return if the pool suspends when failmode=continue, and if that happens, return EIO. * zfs_clone_range: allow dirty wait to fail if pool suspends 4653e2f7d3 (#17355) allows dmu_tx_assign() to fail if the pool suspends when failmode=continue, but zfs_clone_range() can fall back to txg_wait_synced() if it has to wait for a dirty block to be written out, which will block if the pool suspends. Handle this by requesting an error return if the pool suspends when failmode=continue, and if that happens, return EIO. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: Brian Behlendorf Reviewed-by: Alexander Motin Signed-off-by: Rob Norris Closes #17413 --- module/os/linux/zfs/zfs_vnops_os.c | 13 +++++++++++-- module/zfs/zfs_vnops.c | 14 +++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index 0138afb14..ed9721dad 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -3672,8 +3672,17 @@ top: if (!is_tmpfile && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) zil_commit(zilog, 0); - if (is_tmpfile && zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED) - txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), txg); + if (is_tmpfile && zfsvfs->z_os->os_sync != ZFS_SYNC_DISABLED) { + txg_wait_flag_t wait_flags = + spa_get_failmode(dmu_objset_spa(zfsvfs->z_os)) == + ZIO_FAILURE_MODE_CONTINUE ? TXG_WAIT_SUSPEND : 0; + error = txg_wait_synced_flags(dmu_objset_pool(zfsvfs->z_os), + txg, wait_flags); + if (error != 0) { + ASSERT3U(error, ==, ESHUTDOWN); + error = SET_ERROR(EIO); + } + } zfs_znode_update_vfs(tdzp); zfs_znode_update_vfs(szp); diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 96cb2da5c..0b9eb05e8 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -1813,9 +1813,17 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp, * fallback, or wait for the next TXG and check again. */ if (error == EAGAIN && zfs_bclone_wait_dirty) { - txg_wait_synced(dmu_objset_pool(inos), - last_synced_txg + 1); - continue; + txg_wait_flag_t wait_flags = + spa_get_failmode(dmu_objset_spa(inos)) == + ZIO_FAILURE_MODE_CONTINUE ? + TXG_WAIT_SUSPEND : 0; + error = txg_wait_synced_flags( + dmu_objset_pool(inos), last_synced_txg + 1, + wait_flags); + if (error == 0) + continue; + ASSERT3U(error, ==, ESHUTDOWN); + error = SET_ERROR(EIO); } break;