From 11e6499f661ffa202530c6754512e025d9d38cb4 Mon Sep 17 00:00:00 2001 From: Kamil Monicz Date: Sun, 27 Sep 2026 14:55:35 +0200 Subject: [PATCH] vdev_rebuild: wait for the syncing txg before rebuilding a metaslab Before a sequential rebuild reads a metaslab, it disables allocations from it and waits for pending allocations to sync. Later passes of the syncing txg can still rewrite blocks born in that txg in place: a rewrite allocates nothing, and the first pass has already moved their allocations to the space map. A rebuild read which overlaps such a rewrite sees some columns before it and some after. dRAID then finds the row's parity inconsistent and withholds its repair, and a read which completes before the rewrite can write the old block over the new one on the device being rebuilt. Wait for the txg that is syncing when the metaslab is disabled. No later txg can allocate from it, so none can rewrite its blocks in place. Signed-off-by: Kamil Monicz --- module/zfs/vdev_rebuild.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/module/zfs/vdev_rebuild.c b/module/zfs/vdev_rebuild.c index 7e857448d97f..6e5069da274f 100644 --- a/module/zfs/vdev_rebuild.c +++ b/module/zfs/vdev_rebuild.c @@ -835,14 +835,17 @@ vdev_rebuild_thread(void *arg) spa_config_exit(spa, SCL_CONFIG, FTAG); metaslab_disable(msp); + /* + * Wait for remaining sync passes and outstanding allocations + * so all allocated ranges are on disk before rebuilding them. + * Later sync passes can rewrite blocks in place without + * allocating, so waiting for allocations alone is insufficient. + */ + txg_wait_synced(dp, spa_syncing_txg(spa)); + mutex_enter(&msp->ms_sync_lock); mutex_enter(&msp->ms_lock); - /* - * If there are outstanding allocations wait for them to be - * synced. This is needed to ensure all allocated ranges are - * on disk and therefore will be rebuilt. - */ for (int j = 0; j < TXG_SIZE; j++) { if (zfs_range_tree_space(msp->ms_allocating[j])) { mutex_exit(&msp->ms_lock);