Repository navigation
vdev_rebuild: wait for the syncing txg before rebuilding a metaslab - #19198
Conversation
behlendorf
left a comment
There was a problem hiding this comment.
Thank you! We've been seeing the rare checksum errors in the redundancy_draid_spare3 causing failures since the test was add and it was never clear why the ->ms_allocating was insufficient. A rewrite in the syncing txg while there are no outstanding allocations would explain it.
@andriytk spent some time chasing this subtle failure as well and I'm sure he'd be interested in reviewing the fix.
|
I thought we've fixed it at #18473 where we are waiting for last rebuilt transactions of a metaslab to be sync-ed before enabling allocations from it. But this additional fix to wait for in-place re-writes before starting the rebuild of a metaslab also makes sense. I only didn't quite understand from the description how it was tested. And I also didn't get this: "It also prevents healthy rows from being rejected". |
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 <kamil@monicz.dev>
0cf03ab to
11e6499
Compare
|
Yes, this covers the in-place rewrites before rebuilding starts. For testing, I instrumented the rebuild path to record repairs skipped because of inconsistent parity, then ran By “healthy rows being rejected,” I meant that the rebuild could read some columns before a rewrite and others after it. That mixed view has inconsistent parity, so the repair is skipped even though the stored data isn’t damaged. |
|
Thanks, that makes sense now. I only still wonder, why scrubs didn't find any issues in cases when the repairs were skipped... |
|
The in-place rewrite also writes to the replacement device, independently of the rebuild. So even if the rebuild skips its repair, the rewrite can leave the replacement with the correct contents, and the later scrub has nothing wrong to find. |
|
Right, that makes sense. But there's still race possible between in-place re-writes and rebuilds which can result with wrong data, especially when the parity cannot verify the integrity of data (for example, when the amount of missing columns in the parity group equals the amount of parity columns), and that's why we need this fix. Thanks! See also: Lines 3308 to 3318 in 22013c3 and: Lines 672 to 685 in 22013c3 |
Motivation and Context
A sequential rebuild can read a block while the syncing txg rewrites it in place. Disabling metaslab allocations and waiting for pending allocations does not cover these rewrites: they reuse the block's address and allocate nothing.
On dRAID, a read can combine columns from before and after the rewrite, producing contradictory parity and withholding a repair. The same ordering can copy an older block over a newer copy on the rebuild destination.
This affects sequential rebuilds from 2.0.0. Replacing without
-savoids the race. The dRAID repair omission was reproduced; the newer-copy overwrite follows from the ordering but was not observed.Description
After disabling metaslab allocations, also wait for the txg currently syncing. Later txgs cannot allocate from that metaslab, so they cannot rewrite new blocks there in place. Keep the existing wait for pending allocations.
The added wait costs at most one txg sync per metaslab and returns immediately when none is syncing. It also prevents healthy rows from being rejected by #19121's dRAID error accounting.
How Has This Been Tested?
With only this wait toggled in an instrumented build,
redundancy_draid_spare3withheld a repair for contradictory parity in 5 of 80 runs without the fix and none of 80 with it. The post-rebuild scrub was disabled; every run's final scrub found no checksum errors.Types of Changes
Checklist
Signed-off-by.