Skip to content

Commit 2fb5285

Browse files
authored
Avoid dirtying the final TXGs when exporting a pool
There are two codepaths than can dirty final TXGs: 1) If calling spa_export_common()->spa_unload()-> spa_unload_log_sm_flush_all() after the spa_final_txg is set, then spa_sync()->spa_flush_metaslabs() may end up dirtying the final TXGs. Then we have the following panic: Call Trace: <TASK> dump_stack_lvl+0x46/0x62 spl_panic+0xea/0x102 [spl] dbuf_dirty+0xcd6/0x11b0 [zfs] zap_lockdir_impl+0x321/0x590 [zfs] zap_lockdir+0xed/0x150 [zfs] zap_update+0x69/0x250 [zfs] feature_sync+0x5f/0x190 [zfs] space_map_alloc+0x83/0xc0 [zfs] spa_generate_syncing_log_sm+0x10b/0x2f0 [zfs] spa_flush_metaslabs+0xb2/0x350 [zfs] spa_sync_iterate_to_convergence+0x15a/0x320 [zfs] spa_sync+0x2e0/0x840 [zfs] txg_sync_thread+0x2b1/0x3f0 [zfs] thread_generic_wrapper+0x62/0xa0 [spl] kthread+0x127/0x150 ret_from_fork+0x22/0x30 </TASK> 2) Calling vdev_*_stop_all() for a second time in spa_unload() after spa_export_common() unnecessarily delays the final TXGs beyond what spa_final_txg is set at. Fix this by performing the check and call for spa_unload_log_sm_flush_all() before the spa_final_txg is set in spa_export_common(). Also check if the spa_final_txg has already been set in spa_unload() and skip those calls in this case. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: George Amanakis <[email protected]> External-issue: https://www.illumos.org/issues/9081 Closes openzfs#13048 Closes openzfs#13098
1 parent 9a70e97 commit 2fb5285

File tree

1 file changed

+43
-17
lines changed

1 file changed

+43
-17
lines changed

module/zfs/spa.c

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,25 +1597,33 @@ spa_unload(spa_t *spa)
15971597
spa_wake_waiters(spa);
15981598

15991599
/*
1600-
* If the log space map feature is enabled and the pool is getting
1601-
* exported (but not destroyed), we want to spend some time flushing
1602-
* as many metaslabs as we can in an attempt to destroy log space
1603-
* maps and save import time.
1600+
* If we have set the spa_final_txg, we have already performed the
1601+
* tasks below in spa_export_common(). We should not redo it here since
1602+
* we delay the final TXGs beyond what spa_final_txg is set at.
16041603
*/
1605-
if (spa_should_flush_logs_on_unload(spa))
1606-
spa_unload_log_sm_flush_all(spa);
1604+
if (spa->spa_final_txg == UINT64_MAX) {
1605+
/*
1606+
* If the log space map feature is enabled and the pool is
1607+
* getting exported (but not destroyed), we want to spend some
1608+
* time flushing as many metaslabs as we can in an attempt to
1609+
* destroy log space maps and save import time.
1610+
*/
1611+
if (spa_should_flush_logs_on_unload(spa))
1612+
spa_unload_log_sm_flush_all(spa);
16071613

1608-
/*
1609-
* Stop async tasks.
1610-
*/
1611-
spa_async_suspend(spa);
1614+
/*
1615+
* Stop async tasks.
1616+
*/
1617+
spa_async_suspend(spa);
16121618

1613-
if (spa->spa_root_vdev) {
1614-
vdev_t *root_vdev = spa->spa_root_vdev;
1615-
vdev_initialize_stop_all(root_vdev, VDEV_INITIALIZE_ACTIVE);
1616-
vdev_trim_stop_all(root_vdev, VDEV_TRIM_ACTIVE);
1617-
vdev_autotrim_stop_all(spa);
1618-
vdev_rebuild_stop_all(spa);
1619+
if (spa->spa_root_vdev) {
1620+
vdev_t *root_vdev = spa->spa_root_vdev;
1621+
vdev_initialize_stop_all(root_vdev,
1622+
VDEV_INITIALIZE_ACTIVE);
1623+
vdev_trim_stop_all(root_vdev, VDEV_TRIM_ACTIVE);
1624+
vdev_autotrim_stop_all(spa);
1625+
vdev_rebuild_stop_all(spa);
1626+
}
16191627
}
16201628

16211629
/*
@@ -6427,9 +6435,27 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig,
64276435
if (new_state != POOL_STATE_UNINITIALIZED && !hardforce) {
64286436
spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
64296437
spa->spa_state = new_state;
6438+
vdev_config_dirty(spa->spa_root_vdev);
6439+
spa_config_exit(spa, SCL_ALL, FTAG);
6440+
}
6441+
6442+
/*
6443+
* If the log space map feature is enabled and the pool is
6444+
* getting exported (but not destroyed), we want to spend some
6445+
* time flushing as many metaslabs as we can in an attempt to
6446+
* destroy log space maps and save import time. This has to be
6447+
* done before we set the spa_final_txg, otherwise
6448+
* spa_sync() -> spa_flush_metaslabs() may dirty the final TXGs.
6449+
* spa_should_flush_logs_on_unload() should be called after
6450+
* spa_state has been set to the new_state.
6451+
*/
6452+
if (spa_should_flush_logs_on_unload(spa))
6453+
spa_unload_log_sm_flush_all(spa);
6454+
6455+
if (new_state != POOL_STATE_UNINITIALIZED && !hardforce) {
6456+
spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
64306457
spa->spa_final_txg = spa_last_synced_txg(spa) +
64316458
TXG_DEFER_SIZE + 1;
6432-
vdev_config_dirty(spa->spa_root_vdev);
64336459
spa_config_exit(spa, SCL_ALL, FTAG);
64346460
}
64356461
}

0 commit comments

Comments
 (0)