Send a stopped writer's slot and refuse to create over it#1650

merged1
volume-cut/p3-design
volume-cut/p4-slot
openedOct 12, 2026byNNick
View on GitHubGitHub import enabledPR last imported 21d ago

Summary

This is PR 4 of 7 in the Volume RPC cut. It fixes two plugin gaps that the cut's design depends on, before PR 5 adds SetVolumeCopy. At the cut the source's root moves into its mirror slot, <pool>/ployz-mirror/<V>/fs, while its Container is stopped. Two things go wrong on main in that window.

  • /volume-send serves only the root, so the target cannot pull the final increment from a source whose root sits in the slot.
  • Plugin Create checks only the root. Any Docker Create caller, such as docker volume create, docker run -v or compose, makes a fresh empty root with a new guid next to the slot. Ployz's own Deploy is already protected, because admit_plain_mount refuses a slot copy.

Refs #1633. This PR fixes the Create half. The Get half moves to PR 5. A Get that hangs up whenever the slot exists breaks docker volume rm after Demote, because moby's Remove calls Get and fails on a driver error even with --force. It also breaks Close.

Changes

  • volume_send.rs. The stream source is the root <pool>/ployz/<V> if it exists, else the slot <pool>/ployz-mirror/<V>/fs. The root wins when both exist. Full, incremental and resumed sends work from either. The base guid and resume token checks run against whichever dataset was picked.
  • storage.rs, Create. If the root does not exist and <pool>/ployz-mirror/<V> does, Create refuses with "Volume V is held in slot ...; promote or restore it before creating it again" and runs no zfs create. An existing root still returns as before.
  • Tests. streams_from_the_slot_of_a_stopped_writer sends full, incremental and resumed streams from a slot, and checks that a base guid from the root and a mismatched token are refused. create_refuses_a_name_whose_writer_is_held_in_its_slot checks the refusal and that no zfs create ran.
  • Create calls super::lease::slot_parent. PR 5 or PR 7 moves that helper out of lease.rs before PR 7 deletes the file.

List and Remove need no change. moby's List never purges a record, and only Close and departure send Remove inside the window.

Verification

The builder ran these in core/ before the stack was rebased onto bea6ccf16, and all exited 0.

  • cargo fmt --check
  • cargo clippy -p ployzd --all-targets, clean
  • cargo nextest run -p ployzd -E 'test(volume_send) | test(slot) | test(storage) | test(removal) | test(volume_plugin)' gave 206 passed.

Not verified on real ZFS. PR 6 runs the volume move check, which reaches this window in the undo-after-cut case.

Merge Danger

  • docker volume create of a name whose slot exists now fails. That includes a Machine that holds only a mirror of the Volume. Ployz's Deploy already refused a slot copy, so only direct Docker callers see the change.
  • Get, List and Remove are unchanged. On main, ployzd's observation loop inspects every ployz-driver Volume every 30 seconds and on Docker volume events. An inspect during the slot window makes moby purge the record. A later docker start re-creates it bare, and the next Deploy refuses it. That was read from source, not run, and PR 5 owns the fix.
  • /volume-send now answers for a Volume whose root is in its slot. It never served that case before, so no caller depends on the old refusal.

Checks

2 failing · 5 successful · 5 skipped
Some checks failed

Failing2

7b7ea06

Added 1 commit

  • Send a stopped writer's slot and refuse to create over it7b7ea06
Synced from GitHub

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

yaml
1reviews:
2 auto_review:
3 drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.