]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Fix lock inversion in txg_sync_thread()
authorTom Caputi <tcaputi@datto.com>
Tue, 16 Oct 2018 21:00:55 +0000 (17:00 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 24 Oct 2018 21:37:02 +0000 (14:37 -0700)
This patch fixes a lock inversion issue in txg_sync_thread() where
the code would attempt hold the spa config lock as a reader while
holding tx->tx_sync_lock. This races with spa_vdev_remove() which
attempts to hold the tx->tx_sync_lock to assign a new tx (via
spa_history_log_internal()) while holding the spa config lock as a
writer.

Reviewed-by: Serapheim Dimitropoulos <serapheim.dimitro@delphix.com>
Reviewed-by: Matthew Ahrens <mahrens@delphix.com>
Co-authored-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tom Caputi <tcaputi@datto.com>
Closes #8010

module/zfs/txg.c

index aad1a8e572ea7c8ab8c48f2dcfeccd83a06a785b..db0f60cd15a344a0f2526918abab2126c35ce3f4 100644 (file)
@@ -562,22 +562,22 @@ txg_sync_thread(void *arg)
                tx->tx_quiesced_txg = 0;
                tx->tx_syncing_txg = txg;
                DTRACE_PROBE2(txg__syncing, dsl_pool_t *, dp, uint64_t, txg);
-               txg_stat_t *ts = spa_txg_history_init_io(spa, txg, dp);
                cv_broadcast(&tx->tx_quiesce_more_cv);
 
                dprintf("txg=%llu quiesce_txg=%llu sync_txg=%llu\n",
                    txg, tx->tx_quiesce_txg_waiting, tx->tx_sync_txg_waiting);
                mutex_exit(&tx->tx_sync_lock);
 
+               txg_stat_t *ts = spa_txg_history_init_io(spa, txg, dp);
                start = ddi_get_lbolt();
                spa_sync(spa, txg);
                delta = ddi_get_lbolt() - start;
+               spa_txg_history_fini_io(spa, ts);
 
                mutex_enter(&tx->tx_sync_lock);
                tx->tx_synced_txg = txg;
                tx->tx_syncing_txg = 0;
                DTRACE_PROBE2(txg__synced, dsl_pool_t *, dp, uint64_t, txg);
-               spa_txg_history_fini_io(spa, ts);
                cv_broadcast(&tx->tx_sync_done_cv);
 
                /*