From 0ca82c568073e0bb86d773c0f385455db41d7999 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Wed, 20 Nov 2024 09:11:51 -0500 Subject: [PATCH] L2ARC: Stop rebuild before setting spa_final_txg Without doing that there is a race window on export when history log write by completed rebuild dirties transaction beyond final, triggering assertion. Reviewed-by: Brian Behlendorf Reviewed-by: George Amanakis Signed-off-by: Alexander Motin Sponsored by: iXsystems, Inc. Closes #16714 Closes #16782 --- include/sys/arc.h | 1 + module/zfs/arc.c | 35 ++++++++++++++++++++++++++++++++--- module/zfs/spa.c | 2 ++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/include/sys/arc.h b/include/sys/arc.h index 883c07b4f..5148905c9 100644 --- a/include/sys/arc.h +++ b/include/sys/arc.h @@ -347,6 +347,7 @@ void l2arc_fini(void); void l2arc_start(void); void l2arc_stop(void); void l2arc_spa_rebuild_start(spa_t *spa); +void l2arc_spa_rebuild_stop(spa_t *spa); #ifndef _KERNEL extern boolean_t arc_watch; diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 0c086fc21..fa7baac04 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -9846,6 +9846,37 @@ l2arc_spa_rebuild_start(spa_t *spa) } } +void +l2arc_spa_rebuild_stop(spa_t *spa) +{ + ASSERT(MUTEX_HELD(&spa_namespace_lock) || + spa->spa_export_thread == curthread); + + for (int i = 0; i < spa->spa_l2cache.sav_count; i++) { + l2arc_dev_t *dev = + l2arc_vdev_get(spa->spa_l2cache.sav_vdevs[i]); + if (dev == NULL) + continue; + mutex_enter(&l2arc_rebuild_thr_lock); + dev->l2ad_rebuild_cancel = B_TRUE; + mutex_exit(&l2arc_rebuild_thr_lock); + } + for (int i = 0; i < spa->spa_l2cache.sav_count; i++) { + l2arc_dev_t *dev = + l2arc_vdev_get(spa->spa_l2cache.sav_vdevs[i]); + if (dev == NULL) + continue; + mutex_enter(&l2arc_rebuild_thr_lock); + if (dev->l2ad_rebuild_began == B_TRUE) { + while (dev->l2ad_rebuild == B_TRUE) { + cv_wait(&l2arc_rebuild_thr_cv, + &l2arc_rebuild_thr_lock); + } + } + mutex_exit(&l2arc_rebuild_thr_lock); + } +} + /* * Main entry point for L2ARC rebuilding. */ @@ -9854,12 +9885,12 @@ l2arc_dev_rebuild_thread(void *arg) { l2arc_dev_t *dev = arg; - VERIFY(!dev->l2ad_rebuild_cancel); VERIFY(dev->l2ad_rebuild); (void) l2arc_rebuild(dev); mutex_enter(&l2arc_rebuild_thr_lock); dev->l2ad_rebuild_began = B_FALSE; dev->l2ad_rebuild = B_FALSE; + cv_signal(&l2arc_rebuild_thr_cv); mutex_exit(&l2arc_rebuild_thr_lock); thread_exit(); @@ -10010,8 +10041,6 @@ l2arc_rebuild(l2arc_dev_t *dev) for (;;) { mutex_enter(&l2arc_rebuild_thr_lock); if (dev->l2ad_rebuild_cancel) { - dev->l2ad_rebuild = B_FALSE; - cv_signal(&l2arc_rebuild_thr_cv); mutex_exit(&l2arc_rebuild_thr_lock); err = SET_ERROR(ECANCELED); goto out; diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 6b8c7ee93..bf3b0d143 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -2081,6 +2081,7 @@ spa_unload(spa_t *spa) vdev_trim_stop_all(root_vdev, VDEV_TRIM_ACTIVE); vdev_autotrim_stop_all(spa); vdev_rebuild_stop_all(spa); + l2arc_spa_rebuild_stop(spa); } } @@ -7115,6 +7116,7 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, vdev_trim_stop_all(rvd, VDEV_TRIM_ACTIVE); vdev_autotrim_stop_all(spa); vdev_rebuild_stop_all(spa); + l2arc_spa_rebuild_stop(spa); /* * We want this to be reflected on every label,