From 184f4cd083a2ddaa61039e3be6454dbbb6c3970e Mon Sep 17 00:00:00 2001 From: jxdking Date: Thu, 22 Apr 2021 17:53:25 +0000 Subject: [PATCH] Allow txg_kick() even there is a txg still syncing Current txg_kick() only works if there is no txg in either quiescing or syncing. This commit allow txg_kick() to work as long as there is no txg is quiescing. This keeps syncing stage busy, which should benefit write throughput. Also txg_kick() should be triggered on dp_dirty_pertxg[] instead of dp_dirty_total, because dp_dirty_total won't be decreased until the dirty txg is synced. This change prevent pushing a empty txg through pipeline in a row. Signed-off-by: jxdking --- include/sys/dsl_pool.h | 1 + include/sys/txg.h | 2 +- module/zfs/dmu_tx.c | 4 ++++ module/zfs/dsl_pool.c | 19 +++++++++++++++---- module/zfs/txg.c | 21 +++++++-------------- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/include/sys/dsl_pool.h b/include/sys/dsl_pool.h index 8249bb8fc633..31d0aa55b708 100644 --- a/include/sys/dsl_pool.h +++ b/include/sys/dsl_pool.h @@ -171,6 +171,7 @@ void dsl_pool_mos_diduse_space(dsl_pool_t *dp, void dsl_pool_ckpoint_diduse_space(dsl_pool_t *dp, int64_t used, int64_t comp, int64_t uncomp); boolean_t dsl_pool_need_dirty_delay(dsl_pool_t *dp); +boolean_t dsl_pool_need_dirty_sync(dsl_pool_t *dp, uint64_t txg); void dsl_pool_config_enter(dsl_pool_t *dp, void *tag); void dsl_pool_config_enter_prio(dsl_pool_t *dp, void *tag); void dsl_pool_config_exit(dsl_pool_t *dp, void *tag); diff --git a/include/sys/txg.h b/include/sys/txg.h index 22158bd1a5e6..f38f0006c040 100644 --- a/include/sys/txg.h +++ b/include/sys/txg.h @@ -78,7 +78,7 @@ extern void txg_register_callbacks(txg_handle_t *txghp, list_t *tx_callbacks); extern void txg_delay(struct dsl_pool *dp, uint64_t txg, hrtime_t delta, hrtime_t resolution); -extern void txg_kick(struct dsl_pool *dp); +extern void txg_kick(struct dsl_pool *dp, uint64_t txg); /* * Wait until the given transaction group has finished syncing. diff --git a/module/zfs/dmu_tx.c b/module/zfs/dmu_tx.c index 73667915df0f..fcdd9c296a86 100644 --- a/module/zfs/dmu_tx.c +++ b/module/zfs/dmu_tx.c @@ -38,6 +38,7 @@ #include #include #include +#include typedef void (*dmu_tx_hold_func_t)(dmu_tx_t *tx, struct dnode *dn, uint64_t arg1, uint64_t arg2); @@ -1055,6 +1056,9 @@ dmu_tx_assign(dmu_tx_t *tx, uint64_t txg_how) txg_rele_to_quiesce(&tx->tx_txgh); + if (dsl_pool_need_dirty_sync(tx->tx_pool, tx->tx_txg)) { + txg_kick(tx->tx_pool, tx->tx_txg); + } return (0); } diff --git a/module/zfs/dsl_pool.c b/module/zfs/dsl_pool.c index c770eafa75d8..42aff2b093cf 100644 --- a/module/zfs/dsl_pool.c +++ b/module/zfs/dsl_pool.c @@ -899,18 +899,29 @@ dsl_pool_need_dirty_delay(dsl_pool_t *dp) { uint64_t delay_min_bytes = zfs_dirty_data_max * zfs_delay_min_dirty_percent / 100; - uint64_t dirty_min_bytes = - zfs_dirty_data_max * zfs_dirty_data_sync_percent / 100; uint64_t dirty; mutex_enter(&dp->dp_lock); dirty = dp->dp_dirty_total; mutex_exit(&dp->dp_lock); - if (dirty > dirty_min_bytes) - txg_kick(dp); + return (dirty > delay_min_bytes); } +boolean_t +dsl_pool_need_dirty_sync(dsl_pool_t *dp, uint64_t txg) +{ + uint64_t dirty; + uint64_t dirty_min_bytes = + zfs_dirty_data_max * zfs_dirty_data_sync_percent / 100; + + mutex_enter(&dp->dp_lock); + dirty = dp->dp_dirty_pertxg[txg & TXG_MASK]; + mutex_exit(&dp->dp_lock); + + return (dirty > dirty_min_bytes); +} + void dsl_pool_dirty_space(dsl_pool_t *dp, int64_t space, dmu_tx_t *tx) { diff --git a/module/zfs/txg.c b/module/zfs/txg.c index 497e19dd58eb..53915feaed1d 100644 --- a/module/zfs/txg.c +++ b/module/zfs/txg.c @@ -498,14 +498,6 @@ txg_wait_callbacks(dsl_pool_t *dp) taskq_wait_outstanding(tx->tx_commit_cb_taskq, 0); } -static boolean_t -txg_is_syncing(dsl_pool_t *dp) -{ - tx_state_t *tx = &dp->dp_tx; - ASSERT(MUTEX_HELD(&tx->tx_sync_lock)); - return (tx->tx_syncing_txg != 0); -} - static boolean_t txg_is_quiescing(dsl_pool_t *dp) { @@ -784,22 +776,23 @@ txg_wait_open(dsl_pool_t *dp, uint64_t txg, boolean_t should_quiesce) } /* - * If there isn't a txg syncing or in the pipeline, push another txg through - * the pipeline by quiescing the open txg. + * If there isn't a txg quiescing in the pipeline, push the txg + * through the pipeline by quiescing the open txg. + * It is fine there is a txg still syncing. */ void -txg_kick(dsl_pool_t *dp) +txg_kick(dsl_pool_t *dp, uint64_t txg) { tx_state_t *tx = &dp->dp_tx; ASSERT(!dsl_pool_config_held(dp)); mutex_enter(&tx->tx_sync_lock); - if (!txg_is_syncing(dp) && + txg = txg == 0 ? tx->tx_open_txg : txg; + if (txg == tx->tx_open_txg && !txg_is_quiescing(dp) && tx->tx_quiesce_txg_waiting <= tx->tx_open_txg && - tx->tx_sync_txg_waiting <= tx->tx_synced_txg && - tx->tx_quiesced_txg <= tx->tx_synced_txg) { + tx->tx_sync_txg_waiting <= tx->tx_synced_txg) { tx->tx_quiesce_txg_waiting = tx->tx_open_txg + 1; cv_broadcast(&tx->tx_quiesce_more_cv); }