From 468d22d60cedd4d174b43949d58c67fcfe10903b Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 24 Feb 2025 13:56:08 +1100 Subject: [PATCH] txg_wait_synced_flags: add TXG_WAIT_SUSPEND flag to not wait if pool suspended This allows a caller to request a wait for txg sync, with an appropriate error return if the pool is suspended or becomes suspended during the wait. To support this, txg_wait_kick() is added to signal the sync condvar, which wakes up the waiters, causing them to loop and reconsider their wait conditions again. zio_suspend() now calls this to trigger the break if the pool suspends while waiting. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: Brian Behlendorf Reviewed-by: Alexander Motin Reviewed-by: Paul Dagnelie Signed-off-by: Rob Norris Closes #17355 --- include/sys/txg.h | 9 +++++++++ module/zfs/txg.c | 21 ++++++++++++++++++++- module/zfs/zio.c | 2 ++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/include/sys/txg.h b/include/sys/txg.h index 5ce727a27..eabb6f7aa 100644 --- a/include/sys/txg.h +++ b/include/sys/txg.h @@ -25,6 +25,7 @@ */ /* * Copyright (c) 2012, 2017 by Delphix. All rights reserved. + * Copyright (c) 2025, Klara, Inc. */ #ifndef _SYS_TXG_H @@ -78,6 +79,9 @@ typedef enum { /* If a signal arrives while waiting, abort and return EINTR */ TXG_WAIT_SIGNAL = (1 << 0), + + /* If the pool suspends while waiting, abort and return ESHUTDOWN. */ + TXG_WAIT_SUSPEND = (1 << 1), } txg_wait_flag_t; struct dsl_pool; @@ -111,6 +115,11 @@ extern int txg_wait_synced_flags(struct dsl_pool *dp, uint64_t txg, */ extern void txg_wait_synced(struct dsl_pool *dp, uint64_t txg); +/* + * Wake all threads waiting in txg_wait_synced_flags() so they can reevaluate. + */ +extern void txg_wait_kick(struct dsl_pool *dp); + /* * Wait until the given transaction group, or one after it, is * the open transaction group. Try to make this happen as soon diff --git a/module/zfs/txg.c b/module/zfs/txg.c index dbeacc4ab..46a1d06a7 100644 --- a/module/zfs/txg.c +++ b/module/zfs/txg.c @@ -23,6 +23,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Portions Copyright 2011 Martin Matuska * Copyright (c) 2012, 2019 by Delphix. All rights reserved. + * Copyright (c) 2025, Klara, Inc. */ #include @@ -705,7 +706,7 @@ txg_wait_synced_flags(dsl_pool_t *dp, uint64_t txg, txg_wait_flag_t flags) int error = 0; tx_state_t *tx = &dp->dp_tx; - ASSERT0(flags & ~TXG_WAIT_SIGNAL); + ASSERT0(flags & ~(TXG_WAIT_SIGNAL | TXG_WAIT_SUSPEND)); ASSERT(!dsl_pool_config_held(dp)); mutex_enter(&tx->tx_sync_lock); @@ -723,6 +724,15 @@ txg_wait_synced_flags(dsl_pool_t *dp, uint64_t txg, txg_wait_flag_t flags) * else interesting happens, we'll set an error and break out. */ while (tx->tx_synced_txg < txg) { + if ((flags & TXG_WAIT_SUSPEND) && spa_suspended(dp->dp_spa)) { + /* + * Pool suspended and the caller does not want to + * block; inform them immediately. + */ + error = SET_ERROR(ESHUTDOWN); + break; + } + dprintf("broadcasting sync more " "tx_synced=%llu waiting=%llu dp=%px\n", (u_longlong_t)tx->tx_synced_txg, @@ -756,6 +766,15 @@ txg_wait_synced(dsl_pool_t *dp, uint64_t txg) VERIFY0(txg_wait_synced_flags(dp, txg, TXG_WAIT_NONE)); } +void +txg_wait_kick(dsl_pool_t *dp) +{ + tx_state_t *tx = &dp->dp_tx; + mutex_enter(&tx->tx_sync_lock); + cv_broadcast(&tx->tx_sync_done_cv); + mutex_exit(&tx->tx_sync_lock); +} + /* * Wait for the specified open transaction group. Set should_quiesce * when the current open txg should be quiesced immediately. diff --git a/module/zfs/zio.c b/module/zfs/zio.c index 1769606eb..c24faeada 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -2714,6 +2714,8 @@ zio_suspend(spa_t *spa, zio_t *zio, zio_suspend_reason_t reason) } mutex_exit(&spa->spa_suspend_lock); + + txg_wait_kick(spa->spa_dsl_pool); } int