Skip to content

feat(disk): vm disk attach and detach are idempotent - #282

Merged
CMGS merged 3 commits into
masterfrom
fix/disk-attach-idempotent
Oct 9, 2026
Merged

CMGS merged 3 commits into
masterfrom
fix/disk-attach-idempotent

Conversation

@CMGS

@CMGS CMGS commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

What

cocoon vm disk attach and cocoon vm disk detach become idempotent on both Cloud Hypervisor and Firecracker (--pci).

call before after
attach a disk already attached under the same name, path and mode error disk name "x" already attached success, returns the existing id
attach the same name with a different path or mode error error (unchanged message family: already attached with a different path or mode)
attach a name whose serial or path another disk holds error error (unchanged)
detach a name that is not attached error disk "x" not attached success, with a warning log
detach retry while CH still waits for the guest to eject an earlier removal error disk "x" not attached waits for that eject, no second vm.remove-device

The decision is made under the existing VMM operation lock, from the same vm.info / drive-config snapshot the pre-checks already read, so a concurrent attach or detach of the same VM still serializes.

Why

sandboxd hot-attaches catalog volumes into running VMs, and cocoonstack/sandbox#339 proposes attaching and detaching them on a live sandbox. A control plane that converges a desired volume set has to retry after a crash or a lost reply. Today it can only learn whether a retry is needed by parsing vm inspect's attached_devices (which inspect drops when the VMM query fails) or by matching the not attached error text. With idempotent calls it simply calls attach or detach again.

Changes

  • hypervisor/cloudhypervisor/extend.go:
    • preCheckFn now returns (existingID, error), and attachWith returns the existing id without calling the VMM when the pre-check reports one.
    • The disk pre-check moves into diskAttached (same serial and path guards as before).
    • DiskDetach warns and returns nil for an absent disk.
    • findIDFn now returns (id, remove, err). CH drops a disk from config.disks as soon as vm.remove-device returns, but keeps it in device_tree until the guest acks the eject. So a disk found only in device_tree is a pending removal: detachWith skips the remove call and waits for the eject. Without this, a retry after an eject-wait timeout would report success while the slot and backing file are still held.
    • The fs and device pre-checks only change their return shape; their behavior is unchanged.
  • hypervisor/firecracker/extend.go: checkDriveFree becomes driveAttached (identical drive → attached, conflicting one → error), and DiskDetach warns and returns nil for an absent drive.
  • docs/devices.md: states the idempotency contract.

Hot path: zero added VMM calls. Both the pre-check and the pending-eject check read the vm.info snapshot already taken under the ops lock. An identical re-attach skips vm.add-disk entirely.

Tests

  • TestDiskAttached (CH, new) and TestDriveAttached (FC, replaces TestCheckDriveFree) are table tests over the free, identical, same-name-other-path, same-name-other-mode, serial-in-use (CH) and same-path-other-name cases.
  • Gates on macOS:
    • make lint: 0 issues. on linux and darwin.
    • golangci-lint fmt --diff: clean.
    • asl on darwin and linux: clean.
    • go test -race -count=1 ./...: passes.
  • The pending-eject retry path has no unit test. Device ops run only through LockedRunningOp, which needs a VM record and a live VMM, and no existing test drives that. The eject wait itself is covered by TestCHNICOpsRemoveNICWaitsForEject.
  • The Linux container run was skipped locally (no Docker daemon); CI covers Linux.

CMGS added 3 commits October 9, 2026 21:09
Attaching a disk that is already attached under the same name, path and mode now succeeds with its existing id instead of failing; the same name with a different path or mode is still refused. Detaching a name that is not attached succeeds with a warning log. A caller that retries after a crash or a lost reply (sandboxd converging a sandbox's volume set) can call either command again without parsing inspect output or matching error text. Both Cloud Hypervisor and Firecracker.
@CMGS
CMGS merged commit 6d76309 into master Oct 9, 2026
4 checks passed
@CMGS
CMGS deleted the fix/disk-attach-idempotent branch October 9, 2026 15:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant