diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c index dac619b..e67374f 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/txg.c @@ -359,6 +359,23 @@ txg_dispatch_callbacks(dsl_pool_t *dp, uint64_t txg) } } +/* + * dsl_scan_active may perform I/O and we do not want to hold tx_sync_lock + * across that. + * + * NOTE that tx state can be changed across this call. + */ +static boolean_t +dsl_scan_active_unlocked(tx_state_t *tx, dsl_scan_t *scn) +{ + boolean_t active; + + mutex_exit(&tx->tx_sync_lock); + active = dsl_scan_active(scn); + mutex_enter(&tx->tx_sync_lock); + return (active); +} + static void txg_sync_thread(void *arg) { @@ -379,9 +396,12 @@ txg_sync_thread(void *arg) * We sync when we're scanning, there's someone waiting * on us, or the quiesce thread has handed off a txg to * us, or we have reached our timeout. + * + * Call dsl_scan_active_unlocked first, so that tx state + * is unchanged between the checks and txg_thread_wait. */ timer = (delta >= timeout ? 0 : timeout - delta); - while (!dsl_scan_active(dp->dp_scan) && + while (!dsl_scan_active_unlocked(tx, dp->dp_scan) && !tx->tx_exiting && timer > 0 && tx->tx_synced_txg >= tx->tx_sync_txg_waiting && tx->tx_quiesced_txg == 0) {