Skip to content

vm: pin envelope blobs on every clone again (reverts #326) - #328

Merged
CMGS merged 2 commits into
masterfrom
fix/clone-pin-revert
Nov 9, 2026
Merged

CMGS merged 2 commits into
masterfrom
fix/clone-pin-revert

Conversation

@CMGS

@CMGS CMGS commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Reverts #326. A record-backed clone needs the envelope pin after all.

Image GC rechecks a candidate blob under its digest lock through pinnedElsewhere (cmd/core/init.go). It reads every hypervisor's VM records and then the snapshot records, as separate PinnedBlobIDs reads. Without the pin, this interleaving deletes a blob that a live VM still boots from:

  1. GC's first scan lists blob X as unreferenced. A snapshot that references X is then imported, for example by an archived wake fetching its checkpoint.
  2. GC takes X's digest lock and reads the VM records. The new clone has not prereserved yet, so no VM references X.
  3. The clone prereserves, finishes and releases the snapshot lease, and the snapshot is removed.
  4. GC reads the snapshot records. Nothing references X there either, so GC deletes it.

The source lease keeps the snapshot record alive for the length of the clone, but not across GC's two reads. With the pin, the clone waits on the digest lock until the recheck ends, and during the recheck the snapshot still holds the reference. Retries and later GC passes cannot restore a deleted blob, so this is permanent data loss.

The interleaving was found by a static review, not reproduced at runtime. #326 bought 0.6 ms per sequential clone (-1.65%) and about 1.7 ms per clone at 8-way.

The second commit corrects the comment above the pin. It claimed a record-backed clone's source already protects the blobs, and that claim led to #326. It is a one-line rewording, net zero comment lines.

Gates: make lint (0 issues on linux and darwin), make fmt-check, asl, go build ./... on both GOOS, and go test -race ./cmd/... on darwin and in a Linux arm64 container (8 packages ok each).

CMGS added 2 commits November 9, 2026 19:17
Image GC rechecks a candidate blob under its digest lock by reading the VM
records and then the snapshot records, in separate reads. Without the pin, a
record-backed clone can prereserve after the VM read, finish, release the
snapshot lease and see the snapshot removed before the snapshot read, so
neither read holds the reference and GC deletes a blob the new VM boots from.
The source lease keeps the snapshot record alive during the clone, not inside
GC's recheck. The pin made the clone wait out the recheck; it costs 0.6 ms per
sequential clone.
@CMGS
CMGS merged commit a107cec into master Nov 9, 2026
4 checks passed
@CMGS
CMGS deleted the fix/clone-pin-revert branch November 9, 2026 11:19
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