Pool split leaks DTL spacemap objects - #18808
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a long-standing resource leak during zpool split by ensuring that removed mirror leaf vdevs have their DTL spacemap objects released (matching the cleanup behavior used by spa_vdev_detach()), preventing leaked MOS objects and zdb spacemap refcount mismatches in the original pool.
Changes:
- Mark split-off leaf vdevs as detached and dirty their DTL so
vdev_dtl_sync()frees the leaf DTL spacemap object in syncing context. - Clear the leaf ZAP pointer on the detached leaf to avoid double-destruction during subsequent AVZ rebuild.
- Delay
vdev_free()of removed leaf vdevs until after the relevant TXG has synced.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /* | ||
| * As in spa_vdev_detach(), mark the vdev detached | ||
| * and dirty its DTL, so that vdev_dtl_sync() frees | ||
| * the leaf's DTL space map object. | ||
| */ | ||
| vml[c]->vdev_detached = B_TRUE; | ||
|
|
||
| /* | ||
| * The leaf ZAP was transferred to the new pool | ||
| * and this pool's copy is destroyed by the AVZ | ||
| * rebuild below, so clear it to keep | ||
| * vdev_dtl_sync() from destroying it again. | ||
| */ | ||
| vml[c]->vdev_leaf_zap = 0; | ||
|
|
||
| /* | ||
| * vml[c]->vdev_top may be stale; the | ||
| * surviving top-level vdev is rvd->vdev_child[c]. | ||
| */ | ||
| vdev_dirty(rvd->vdev_child[c], VDD_DTL, vml[c], txg); | ||
|
|
behlendorf
left a comment
There was a problem hiding this comment.
Let's make sure this stays fixed. Can you add a log_must zdb -MC $TESTPOOL to the while loop in cli_root/zpool_split/zpool_split_devices.ksh. It wouldn't hurt to check $TESTPOOL2 as well.
Sure. I actually did step on this while working on vdev_zaps_007 (on illumos), havent yet investigated OpenZFS tests (illumos is missing some of there). |
|
ah, I forgot to add. This work is addressing original pool. There is also new pool.... |
|
Oh, I'm glad you mentioned |
|
@tsoome are you planning to add the fixes for the new pool case to this PR as well? |
I think, it would need one for its own. I got the hints what we do leak, but I havent yet got to see how to clear those leaks - and how to actually test the presence. Also still need to update the tests here - but that has to wait for tomorrow (its 1am here and I should get some sleep:D) |
|
Got it. I'm fine with merging this in two parts. Could you just add the |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
tests/zfs-tests/tests/functional/cli_root/zpool_split/zpool_split_devices.ksh:100
- The new “Force creating DTL objects” sequence doesn’t guarantee that any TXG actually syncs while the leaf is offline. If the TXG sync happens only after
zpool online, the DTL spacemap may never be created, and the test may not reliably exercise the leak (potential flakiness). Sync the pool once while the device is still offline, and wait for the resilver triggered byzpool onlineto complete before splitting.
log_must zpool offline $TESTPOOL $dtldev
log_must dd if=/dev/zero of=$mntpnt/dtlfile bs=1k count=1
log_must zpool online $TESTPOOL $dtldev
sync_pool $TESTPOOL true
|
Pending the CI results I think this looks like it's ready. |
I actually have code now for new pool fix too. The zpool_split_device test update currently does receive FAIL status, because with DTL creation, the zdb -MC will detect space map leak from new pool, therefore it may be good idea to incorporate the second half here after all. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
module/zfs/spa.c:9447
- Typo in the new comment: "wont" -> "will not" (or "won't").
/*
* Free the DTL space map objects inherited from the original pool
* MOS so we wont leak them.
*/
tests/zfs-tests/tests/functional/cli_root/zpool_split/zpool_split_devices.ksh:100
- This block claims to "Force creating DTL objects on vdevs" but only does so for the first device in gooddevs[$i]. For configurations where multiple devices are split, the test may not create a DTL object for every split leaf, which can miss regressions that only manifest on some removed vdevs. Consider looping over all split devices (and quote the output path).
# Force creating DTL objects on vdevs
typeset dtldev=${gooddevs[$i]%% *}
typeset mntpnt=$(get_prop mountpoint $TESTPOOL)
log_must zpool offline $TESTPOOL $dtldev
log_must dd if=/dev/zero of=$mntpnt/dtlfile bs=1k count=1
log_must zpool online $TESTPOOL $dtldev
sync_pool $TESTPOOL true
| held = | ||
| spa_config_held(spa, SCL_STATE, RW_READER) == SCL_STATE || | ||
| spa_config_held(spa, SCL_STATE, RW_WRITER) == SCL_STATE; | ||
|
|
||
| if (!held) | ||
| spa_config_enter(spa, SCL_VDEV, FTAG, RW_READER); | ||
| rc = vdev_count_leaves_impl(spa->spa_root_vdev); | ||
| spa_config_exit(spa, SCL_VDEV, FTAG); | ||
| if (!held) | ||
| spa_config_exit(spa, SCL_VDEV, FTAG); |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
module/zfs/spa.c:9447
- Typo in comment: "wont" should be "won't".
/*
* Free the DTL space map objects inherited from the original pool
* MOS so we wont leak them.
*/
| /* | ||
| * vml[c]->vdev_top may be stale; the | ||
| * surviving top-level vdev is rvd->vdev_child[c]. | ||
| */ | ||
| vdev_dirty(rvd->vdev_child[c], VDD_DTL, vml[c], txg); |
zpool split does not release DTL space map objects for removed vdevs. Use the same approach as in spa_vdev_detach(). Mark vdev detached, and dirty DTL. Signed-off-by: Toomas Soome <tsoome@me.com> Closes openzfs#5599
Signed-off-by: Toomas Soome <tsoome@me.com>
Signed-off-by: Toomas Soome <tsoome@me.com>
vdev_count_leaves() is implemented to set reader lock to reliably count vdevs with private function. However, while we are already holding spa config locks, we can not count vdevs. Signed-off-by: Toomas Soome <tsoome@me.com>
zpool split does clone original pool MOS for new pool byte-by-byte, including DTL data for vdevs. As new pool does not have vdevs left into old pool, this would result leaking those DTL's. Signed-off-by: Toomas Soome <tsoome@me.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (1)
module/zfs/spa.c:9447
- Typo in the comment: "wont" should be "won't".
/*
* Free the DTL space map objects inherited from the original pool
* MOS so we wont leak them.
*/
|
Ah okay. Just let me know when this is ready for another look. |
I think, it should be good. |
|
|
||
| # check space maps | ||
| log_must zdb -MC $TESTPOOL | ||
| log_must zdb -MC $TESTPOOL2 |
There was a problem hiding this comment.
Interesting, this check is reliably failing in the CI. If we trust the error message it seems the split pool doesn't get added to the cache file. That sure seems like another bug which has been hiding.
11:41:07.28 failed to find config for pool 'testpool2': no matching pools
11:41:07.28 zdb: can't open 'testpool2': No such file or directory
11:41:07.28 ERROR: zdb -MC testpool2 exited 1
There was a problem hiding this comment.
in my test machine, the cause was left around pool traces - like exported pool once created from multiple disks, then new pool was created on some of those disks and zdb got confused from those. When I made sure all disks had destroyed pools, the error went away... I did that test on illumos, havent checked with OpenZFS yet.
zpool split does not release DTL space map objects for removed vdevs. Use the same approach as in spa_vdev_detach(). Mark vdev detached, and dirty DTL.
Closes #5599
Motivation and Context
End leak of space map objects in original pool resulting from 'zpool split' command.
#5599
Description
mark new pool vdevs detached and DTL dirty. This would trigger release of respective objects on TXG sync. Once sync is done, free vdevs.
How Has This Been Tested?
zpool create testpool mirror disk1 disk2
zpool split testpool testpool2 disk2
zdb -MC testpool # to verify space map refcounts - there is refcount mismatch before update and no mismatch after update.
Types of Changes
Checklist
Signed-off-by.