Skip to content

feat(blaze): capture Firecracker checkpoints - #2473

Merged
WeissonHan merged 2 commits into
alibaba:mainfrom
WeissonHan:feature/blaze/firecracker-checkpoint-capture-draft-v1
Aug 19, 2026
Merged

feat(blaze): capture Firecracker checkpoints#2473
WeissonHan merged 2 commits into
alibaba:mainfrom
WeissonHan:feature/blaze/firecracker-checkpoint-capture-draft-v1

Conversation

@WeissonHan

@WeissonHan WeissonHan commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Why

Blaze already exposes checkpoint capture (#2472) and checkpoint restore (#2475),
but both were backend-neutral: on the only real production backend the routes
refused the request, because FirecrackerInstance implemented neither pause and
snapshot nor a restore adapter. Capture returned 501, and restore reported an
unsupported backend.

This PR implements both halves for Firecracker, which is what turns those two
merged APIs from mock-only into usable on a real VM backend. It also unblocks
#2476, whose hibernation flow needs the same restore adapter.

What changed

No new HTTP routes. Two commits, each independently buildable and reviewable.

Commit 1 — capture (Closes #2470)

Adds the Firecracker HTTP-over-UDS API client and implements pause, resume,
snapshot, version and supports_checkpoint_capture on the owner. A capture
pauses the VM, writes full VM-state and guest-memory snapshots, and resumes the
runtime.

Version provenance. The owner resolves its version from the running VM
(GET /version) instead of from the configured binary, and freezes it. A
concurrent binary replacement therefore cannot make a capture claim a version
this VM never ran. Because Firecracker snapshot formats are tied to that exact
version, a record without one cannot be restored safely, so capture refuses a
Firecracker sandbox whose owner reports no version and the checkpoint manifest
rejects the same shape. Both user guides state that invariant explicitly, including
that the refusal happens before the sandbox is paused.

Losing the version costs only the capability, not the sandbox: a cold start whose VM
answers on its API socket but not for its version keeps running without capture, so a
checkpoint capability failure is not turned into a failed sandbox creation. A restore
stays fatal there, because it must load a snapshot into a VM whose version was
confirmed to match the one that captured it.

Snapshot deadline. A control request must answer immediately, so a short bound
catches a wedged VMM; snapshot work is throughput-bound on guest memory size and
storage speed. Sharing one value meant a capture that was still progressing was
reported as an unknown outcome — the E3 run below captured a 512 MiB guest in
29.04 s against a 30 s budget, so the example policy's memory = "2G" could not
have checkpointed. Guest memory has no configured upper bound either, so no fixed
replacement would hold: at that measured rate a 16 GiB guest needs about 15.5
minutes. The deadline is therefore max(bytes / 4 MiB/s, 120 s) and exists only
to catch a VMM that never answers. A cold start sizes it from the configured
memory; a restored owner sizes it from the captured memory image, whose size is the
guest memory it holds, because a restore writes no VM configuration to read it from
and defaulting it would leave a later capture of a restored large guest with the
minimum deadline.

Scratch ownership. Firecracker writes snapshot files itself from inside a
private mount namespace, so a capture names a scratch directory below the
runtime directory the VM already owns, then transfers the artifacts to the
destinations the publisher chose. Scratch is reclaimed only when the outcome is
known: a rejected request never wrote anything, while an unknown outcome may
still have a live writer, so that scratch is retained for reconciliation and
reclaimed by destroy or startup instead of being deleted underneath Firecracker.

Commit 2 — restore (Closes #2633)

Implements restore_capability and restore, and makes start checkpoint-aware.

A cold start still writes the machine configuration and boots vmlinux. A
restore instead launches a bare VMM — the snapshot carries the machine
configuration the capture froze — and hands the retained VM state and guest
memory to Firecracker through PUT /snapshot/load with resume_vm: true. The
tap device and guest socket are recreated with fresh host names on every start,
so the load overrides the names the snapshot recorded rather than requiring the
previous host resources to still exist.

Version, backend, snapshot flavour and guest-transport shape are all checked
before the current runtime is stopped, so a mismatch refuses the restore instead
of tearing down a live VM.

Failure boundaries use the two the trait already expresses. Everything
before spawn reports SpawnFailure::clean: no VMM was started and no host
resource was allocated. Once spawn returns, the load runs against the owned
instance, and any failure — compatibility rejection or /snapshot/load error —
transfers the owner through SpawnFailure::compensate_started, so the generic
transaction reconciles a runtime whose cleanup is still owned rather than leaking
a started VMM.

The captured host shape travels with the request rather than being guessed:
BackendInstance::holds_network_slot and records_console_log are probed by the
generic transaction while the captured owner is still alive, and travel in
RestoreRequest beside expose_guest_socket. A restore consumes exactly three
backend configuration fields — the network and guest-transport shapes name host
devices the snapshot references, and the console setting decides whether guest
output keeps being recorded. boot_args, vcpus and memory are read only by
the machine configuration a restore does not write, so rebuilding those from
defaults is harmless while rebuilding the other three was not. Because the console
setting now survives, the log is reopened in append mode: a restore reuses the
directory of the sandbox it replaces, and truncating would have erased the console
history captured before the restore.

Executable pinning. Preflight reads the backend version, and the launch that
follows happens after the running sandbox is stopped. An executable changed in that
window was only caught by the post-spawn version comparison, once the original
could no longer be kept, so a restore preflight could have refused without harm
instead left the sandbox needing recovery. A descriptor alone does not close this:
it pins the inode, not the contents, and the kernel refuses an in-place rewrite
only while some process executes that inode — which stops holding for the replaced
sandbox's own binary once its runtime is killed. PinnedExecutable therefore
copies the bytes into a sealed memory file, opened once by the generic transaction
and handed to both the capability check and the launch. Sealing makes the copy
immutable but does not make reading the source atomic, so the pin also refuses a
source that did not hold still across the copy — a spliced image could still answer
--version and fail only once the sandbox was already stopped. Length and
modification time cannot carry that alone, since a same-length rewrite can restore
both, so the comparison includes inode change time, which an ordinary writer cannot
put back. That copy is executable in
its own right, so the executability of the file it copies is checked first —
against that opened descriptor rather than the path, so a replacement cannot vouch
for a source it is not. Otherwise a restore would run a backend a cold start would
refuse, overriding an operator who withdrew execute permission, and only after the
current VM was already stopped. A backend that runs no
program of its own carries no configured path, so the pin is optional and an
adapter that needs an executable refuses its absence itself.

Two operability consequences, both intentional. A restored VMM shows
/proc/self/fd/N as argv[0], so process listings match on --id fc-<uuid>
rather than the binary name. And /proc/<pid>/exe reports
/memfd:firecracker (deleted): the copy is named after its source so it stays
identifiable, while the memfd: prefix says plainly that the running image is a
sealed copy the on-disk path can no longer change.

User guides. The support matrix said Firecracker could not capture and that
only the mock adapter restores, which this makes untrue, so both language versions
are corrected — each statement in the commit that makes it true. They also record
the prerequisites an operator needs: a checkpoint is restorable only by the
Firecracker build that took it, so that version must stay installed; a restore
replaces the monitor process while keeping the sandbox identity; the replacement
keeps the captured host shape; earlier console and diagnostic output survives; and a
version mismatch is refused before anything is stopped.

Deliberately not included

The earlier draft branch parsed a payload directory with its own manifest and
file-set validation. That layer is dropped: the generic restore transaction from
#2475 already verified the checkpoint, its parent chain and every artifact hash,
and passes the artifact paths and expected identity directly. Re-validating them
in the adapter would duplicate #2475 rather than adapt to it.

Scope

  • base: db0e4654e14808d2398c813719e4742567e88954 (main, includes merged feat(blaze): capture sandbox checkpoints #2472 and feat(blaze): restore sandbox checkpoints #2475)
  • commit 1: `f8834d7d87` — capture
  • commit 2: `3a2a1697f` — restore
  • tree: `30eca8a89e6689621c7054c371596bd76692846c`
  • gate source identity (sha256 before and after the run):
    `b8f54ce87b4da84860f80b98bb54378579509c8942e9769730427fb6a5f8ea6a`
  • 9 files, +2548/-87; no new routes, no /v1/instances paths

This PR does not re-carry the 22 accumulated commits of the previous draft
branch. Its history is rebuilt on current main.

Validation

Linux gate — 14/14 pass

An uninterrupted Linux x86_64 run on Rust 1.88.0 completed for the tree above.

Stage Result
cargo fmt --all -- --check pass
cargo metadata (default / all-features) pass
cargo build --workspace --all-targets (default / all-features) pass
cargo clippy --workspace --all-targets -- -D warnings (default / all-features) pass
cargo test --workspace -- --test-threads=1 412 passed, 0 failed
cargo test --workspace --all-features -- --test-threads=1 474 passed, 0 failed
cargo doc --workspace --no-deps (default / all-features) pass, -D warnings
scripts/docs-lint.sh / docs-link-check.py / git diff --check pass
source tree hash before and after the run unchanged

38 Firecracker tests cover the frozen version, a full snapshot over the API
socket, scratch transfer through inherited descriptors, the retained-scratch
boundaries for rejected requests and uncleanable scratch, transport classification
of disconnects, timeouts and oversized responses, the load payload rebinding the
tap and guest socket this start created, and refusal of a mismatched version, a
missing version, a foreign backend, and an unavailable guest transport.

Real Firecracker on KVM — E3

Bare-metal host, /dev/kvm available, Firecracker v1.16.0, real vmlinux
and 482 MiB rootfs.ext4.

Step Evidence
create state: running, real firecracker process started
capture lifecycle running → paused → checkpointed → running
artifacts vmstate.snap 13 768 B, memory.snap 512 753 664 B, rootfs.snap 482 344 960 B, metadata.json
version frozen "backend_version": "Firecracker v1.16.0" in the manifest
scratch no .firecracker-checkpoint-* left after a successful capture
history GET .../checkpoints reports the entry as is_head and on_head_chain
restore lifecycle running → restoring → running, response "restored": true
backend replaced Firecracker pid 848480 → 849090
real snapshot load restored process command line has no --config-file, only --api-sock and --id, proving a bare VMM loaded the snapshot instead of falling back to a cold boot
last_checkpoint points at the restored checkpoint
destroy netns 0 → 0, tap 0 → 0, 0 residual Firecracker processes, 0 residual instance directories
daemon log 0 errors across the whole run

The --config-file check is the decisive one: a cold start always passes a
machine configuration file, so its absence on the restored owner is what
distinguishes a genuine /snapshot/load from a silent cold-boot fallback.

Issues

Remaining dependency

This PR stays a draft until a maintainer confirms the E3 evidence above is
sufficient for the phase-3 acceptance gate. Once it merges, checkpoint capture and
restore become usable on Firecracker, and #2476 can complete its own real-backend
hibernate–restart–resume validation.

Rollback

Revert both commits. Firecracker returns to advertising no capture and no restore
capability, so the generic routes go back to reporting an unsupported backend.
Checkpoints captured by this code remain on disk and are not read by the reverted
build.

@github-actions github-actions Bot added component:blaze src/blaze scope:documentation ./docs/|./*.md|./NOTICE labels Aug 13, 2026
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 0df7f3e to 6f8dd79 Compare August 18, 2026 09:42
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Rebuilt as two commits on current main (includes merged #2472 and #2475): Firecracker checkpoint capture via /snapshot/create with version provenance frozen from the running VM, and Firecracker restore via /snapshot/load starting a bare VMM. Verified on real KVM with Firecracker v1.16.0; the restored owner carries no --config-file, proving a genuine snapshot load rather than a cold-boot fallback.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6f8dd79fb6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 6f8dd79 to 51d580a Compare August 18, 2026 10:08
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed the P1: the captured network shape now travels with the request via BackendInstance::holds_network_slot and RestoreRequest::preserve_network, probed while the captured owner is still alive, so a restore of a networked sandbox creates a fresh slot and rebinds through network_overrides instead of referencing a deleted tap.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 51d580a024

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 51d580a to fa98793 Compare August 18, 2026 11:15
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed the P2 as the second instance of one flaw: all three backend configuration fields a restore actually consumes (network shape, guest transport, console logging) now travel with the request via BackendInstance probes taken while the captured owner is still alive, instead of being rebuilt from defaults.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa98793eef

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from fa98793 to 305be57 Compare August 18, 2026 11:41
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed the snapshot deadline: control requests keep the short bound that catches a wedged VMM, while /snapshot/create and /snapshot/load use their own documented bound. This PR's own E3 run captured a 512 MiB guest in 29.04s against the old 30s budget, so the shipped 2G example policy could not have checkpointed. Split across both commits so the capture commit is independently correct.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 305be57c1c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 305be57 to 5a25cad Compare August 18, 2026 12:00
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed the console-log truncation that the previous fix exposed: the log is now reopened in append mode, so a restore keeps the history captured before it while rotation still bounds the file. Two tests pin both the retained-history and recording-disabled cases.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a25cad16b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs Outdated
@WeissonHan
WeissonHan marked this pull request as ready for review August 18, 2026 12:34
@WeissonHan
WeissonHan requested a review from casparant as a code owner August 18, 2026 12:34

@qoderai qoderai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 核查 Firecracker 检查点/恢复路径中的版本与二进制固定策略。
  • 确认 Firecracker 版本缺失约束在捕获与 manifest 校验层次上的职责边界。
  • 确保未来运维策略变化时,版本校验与错误信息保持一致。

🤖 Generated by QoderView workflow run

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs Outdated
Comment thread src/blaze/crates/blaze-core/src/checkpoint.rs
Comment thread src/blaze/crates/blazed/src/sandbox/checkpoint.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 5a25cad to 7f34a6a Compare August 18, 2026 13:16
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Closed the executable TOCTOU: the generic transaction pins the backend executable once before the capability check and the launch executes that same pinned file, so a binary replaced after preflight can no longer be discovered only after the original was killed. Re-verified on real hardware — the restored VMM runs from /proc/self/fd/N with /proc/pid/exe resolving to the intended binary, through the ip-netns-exec and unshare chain.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f34a6add9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner.rs Outdated
Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 7f34a6a to 176a311 Compare August 18, 2026 16:12
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Both fixed. The pin is now a sealed memfd copy rather than a descriptor to the original inode — measured on the target host that the kernel only blocks an in-place rewrite while a process executes that inode, which stops holding exactly when a restore kills the runtime it replaces. The copy is named after its source so a running backend stays identifiable as /memfd:firecracker. stderr.log now appends alongside the console log, so a failed replacement can still be debugged from pre-restore diagnostics. Gate 14/14 and E3 re-run end to end.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 176a311521

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner.rs
Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs Outdated
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 176a311 to 8dfe9fc Compare August 19, 2026 00:36
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 8dfe9fc to d6d6a76 Compare August 19, 2026 01:54
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed: the executability check now names the already-opened descriptor through /proc rather than the path, so the file that is checked and the file that is sealed are the same one by construction. Checking the path would have let a replacement vouch for a non-executable source — the same defect class this change exists to close. Used the /proc form instead of AT_EMPTY_PATH to avoid a faccessat2 kernel-version branch, since the change already depends on /proc for the exec itself.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d6d6a762ac

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs Outdated
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from d6d6a76 to 96471e9 Compare August 19, 2026 02:14
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed, and it corrected a claim I had made earlier: memory stopped being a don't-care for restore the moment the snapshot deadline depended on it. A restored owner now takes its guest memory size from the captured memory artifact — for a full snapshot that size is the guest memory it holds — so a restored large guest no longer inherits the default and its next checkpoint gets a deadline that matches the work. The load reads the same recorded value instead of stat-ing separately.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 96471e9ab1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 96471e9 to a018abf Compare August 19, 2026 02:34
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed the documentation gap, which also corrects a judgement I made early on: I treated this as having no user-facing surface because it adds no routes, but the support matrix is user-facing behaviour documentation. Both language guides now state the actual Firecracker capture and restore support plus the prerequisites — version pinning for restorability, monitor process replacement, host-shape preservation, retained diagnostics, and refusal before anything is stopped on version mismatch. Split so each commit carries the statement it makes true.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a018abf52a

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner.rs
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from a018abf to 0191790 Compare August 19, 2026 03:05
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed: sealing protects the copy but not the reading, so the pin now brackets the copy and refuses a source whose copied length, post-copy size, or modification time moved. Rejecting rather than retrying, since a refusal during preflight leaves the sandbox untouched. Noted in the reply that only the length arm has a deterministic test — my first attempt at a racing test was wrong and driving the real race would need the pin restructured — rather than implying fuller coverage.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0191790a73

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner.rs Outdated
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from 0191790 to a1bafa2 Compare August 19, 2026 03:22
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed: measured on the target host that a same-length rewrite plus utimensat restores both size and mtime while ctime still moves, so the stability check now compares inode change time as well — the one indicator an ordinary writer cannot put back. This property is deterministically testable without the race, so it is pinned by a test rather than left to inspection.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: a1bafa23b0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from a1bafa2 to f29d6cb Compare August 19, 2026 06:54
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f29d6cbd43

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/blaze/crates/blazed/src/spawner/firecracker.rs Outdated
This lets Firecracker-backed sandboxes use the checkpoint API that alibaba#2472 already
exposes, by pausing the VM, writing full VM-state and guest-memory snapshots
through the Firecracker API socket, and resuming the owned runtime.

The owner resolves its version from the running VM rather than from the
configured binary and freezes it, so a concurrent binary replacement cannot make
a capture claim a version this VM never ran. Firecracker snapshot formats are
tied to that exact version, so a record without one cannot be restored safely;
capture therefore refuses a Firecracker sandbox whose owner reports no version,
and the checkpoint manifest rejects the same shape.

Firecracker writes snapshot files itself from inside a private mount namespace,
so a capture names a scratch directory below the runtime directory the VM
already owns and transfers the artifacts to the destinations the publisher
chose. Scratch is reclaimed only when the outcome is known: a rejected request
never wrote anything, while an unknown outcome may still have a live writer, so
that scratch is retained for reconciliation and reclaimed by destroy or startup
instead of being deleted underneath Firecracker.

Snapshot requests get their own deadline, scaled by guest memory. A control
request such as `/version` or a pause should answer immediately, so a short bound
catches a wedged VMM, but a full snapshot moves the whole guest memory and its
duration scales with memory size and storage speed. Sharing the short bound would
report an unknown outcome and fail a capture that was still making progress: a
512 MiB guest already takes about 29 seconds on real hardware. Guest memory has
no configured upper bound either, so no fixed replacement bound would hold — at
that rate a 16 GiB guest outlives a 15-minute deadline. The deadline is therefore
derived from the memory size against a conservative throughput floor, with a floor
for fixed overhead, and exists only to catch a VMM that never answers.

A VM that answers on its API socket but not for its version stays a usable sandbox
and only loses checkpoint capture: the owner carries no capture context, so it
reports no version, does not advertise the capability, and a later capture is refused
before anything is paused. Treating the probe as fatal would turn a lost checkpoint
capability into a failed sandbox creation.

Only full capture is enabled. Restore stays unavailable until its adapter lands.

The user guides previously stated that Firecracker does not advertise capture
support, which this makes untrue, so both language versions are corrected. They
also now state the operational consequence of freezing the version: a checkpoint
can only be loaded back by the Firecracker build that took it, and capture refuses a
Firecracker sandbox whose monitor reports no version, before the sandbox is paused,
so a checkpoint without a recorded version cannot be produced.

Tests cover the frozen version, a full snapshot over the API socket, scratch
transfer through inherited descriptors, and the retained-scratch boundaries for
rejected requests, uncleanable scratch, and disconnects.

Closes alibaba#2470

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
This lets the generic restore workflow from alibaba#2475 replace a running
Firecracker-backed sandbox with the state committed to one of its checkpoints,
which is the missing half a alibaba#2470 capture cannot exercise on its own.

The adapter declares its restore identity from the configured binary version so
the generic transaction only calls in when the checkpoint recorded that exact
version. Version, backend, snapshot flavour and guest-transport shape are all
checked before the current runtime is stopped, so a mismatch refuses the
restore instead of tearing down a live VM.

Start becomes checkpoint-aware. A cold start still writes the machine
configuration file and boots vmlinux; a restore instead launches a bare VMM,
because the snapshot carries the machine configuration the capture froze, and
then hands the retained VM state and guest memory to Firecracker through
`/snapshot/load` with `resume_vm: true`. The tap device and guest socket are
recreated with fresh host names on every start, so the load overrides the names
the snapshot recorded rather than requiring the previous host resources to
still exist.

The executable is pinned before anything is stopped. A restore reads the backend
version during preflight and launches after the running sandbox is gone, so an
executable changed in that window would only be noticed once the original could
no longer be kept — turning a restore preflight could have refused without harm
into a sandbox needing recovery. Holding a descriptor to the original file is not
enough, because a descriptor pins the inode and not its contents; the kernel
refuses an in-place rewrite only while some process executes that inode, which
stops holding for the replaced sandbox's own binary once its runtime is killed.
`PinnedExecutable` therefore copies the bytes into a sealed memory file, and
refuses a source that did not hold still across that copy: sealing protects the
destination, not the reading, so an in-place rewrite mid-copy would otherwise splice
an old prefix onto new bytes and seal that permanently. Length and modification time
cannot carry that check alone, because a same-length rewrite can restore both, so
the comparison includes inode change time — the one indicator an ordinary writer
cannot put back. That copy
is executable in its own right, so the source's own execute permission is checked
first: otherwise a restore would run a backend a cold start would refuse, quietly
overriding an operator who withdrew it. A restored owner is sized by the captured
memory image rather than by the reconstructed configuration: a restore writes no VM
configuration to state guest memory, so reading it from there would freeze the
default and leave a later capture of a restored large guest with the minimum
deadline. Both the load and any subsequent capture are bounded from that one
recorded size.

The user guides previously stated that only the mock adapter restores checkpoints,
which this makes untrue, so both language versions are corrected. They also state
what an operator observes: the monitor process is replaced while the sandbox
identity is not, the replacement keeps the captured host shape, earlier console and
diagnostic output survives, and a version mismatch is refused before anything is
stopped. The
generic transaction pins once, hands the same pin to both the capability check and
the launch, and the replacement executes the sealed copy rather than re-resolving
the configured path.

Because the console setting now survives, reopening the console log and the VMM
diagnostics appends instead of truncating. A cold start owns a fresh runtime directory so nothing
changes there, but a restore reuses the directory of the sandbox it replaces, and
truncating would have erased the console history captured before the restore.

Loading a snapshot shares the capture-side deadline rather than the short control
bound, for the same reason: reading a large memory image back is throughput-bound,
so a short bound would abandon a load that was still progressing.

The capture-version probe stays fatal on this path, unlike a cold start which keeps
running without capture: a restore must load the snapshot into a VM whose version was
confirmed to match the one that captured it, and an unverified replacement is worse
than a refused restore.

Failure edges follow the two boundaries the trait already expresses. Everything
before `spawn` uses `SpawnFailure::clean`: no VMM was started, no host resource
was allocated. Once `spawn` returns, the load runs against the owned instance
and any failure — compatibility rejection or `/snapshot/load` error — transfers
the owner through `SpawnFailure::compensate_started` so the generic transaction
can reconcile a runtime whose cleanup is still owned rather than leaking a
started VMM.

The captured host shape travels with the request rather than being rebuilt from
defaults. `BackendInstance` gains `holds_network_slot` and `records_console_log`,
which the generic transaction probes while the captured owner is still alive,
because that owner's cleanup removes the host device the snapshot names. A
restore consumes exactly three backend configuration fields: the network and
guest-transport shapes name host devices the snapshot references, and the console
setting decides whether guest output keeps being recorded; the remaining fields
only feed the machine configuration a restore does not write. Rebuilding from
defaults would have left a restored VM bound to a deleted tap after the running
VM was already stopped, and would have silently stopped recording console output.

Tests cover the load payload rebinding the tap and guest socket this start
created, omitting overrides the sandbox does not own, and refusing a mismatched
version, a missing version, a foreign backend, and a guest-transport shape the
policy does not provide.

Closes alibaba#2633

Signed-off-by: Weisson <Weisson@linux.alibaba.com>
@WeissonHan
WeissonHan force-pushed the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch from f29d6cb to 3a2a169 Compare August 19, 2026 07:28
@WeissonHan

Copy link
Copy Markdown
Collaborator Author

@codex review Fixed the cold-start regression: a VM that answers on its API socket but not for its version now keeps running without checkpoint capture, instead of failing sandbox creation. A restore stays fatal on that path, since it must load a snapshot into a VM whose version was confirmed. Split across both commits so the capture commit degrades on its own and the restore commit adds the guard. Also replied to three earlier qoderai comments I had missed — my unreplied-comment check filtered on a single reviewer account, which is fixed.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: 3a2a1697f0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@casparant casparant left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed against the baseline we have been applying since #1830.

Review baseline — all met:

  • Unified motivation: clear Why grounded in the post-#2472/#2475 main — the checkpoint capture and restore workflows were backend-neutral and returned unsupported/501 for Firecracker; this PR supplies the real /snapshot/create and /snapshot/load transport so Firecracker-backed sandboxes are no longer mock-only. Two commits, capture (Closes #2470) and restore (Closes #2633).
  • No caller-less code: every new pub item has a production call site — FirecrackerInstance implements the #2472 capture contract (supports_checkpoint_capture/version/pause/snapshot/resume), FirecrackerSpawner implements the #2475 restore contract (restore_capability/restore), and PinnedExecutable is exercised in the restore preflight and launch paths; MockSpawner retains only its test-contract implementation.
  • Explicit boundary: only Full snapshots are exposed (validate_restore_compatibility rejects non-full); non-Firecracker backends stay fail-closed; #2476 remains the follow-up that this PR unblocks. No new HTTP routes.
  • Docs: bilingual user guides updated with the Firecracker capture/restore support matrix, exact-version requirement, monitor-process replacement, and preserved console/diagnostics behavior.
  • Commits: two atomic commits mapped to their issues; CI 8/8 green; all inline threads carry replies and the key fixes (preserve_network, record_console_log, memory-scaled snapshot timeout, PinnedExecutable, cold-start version-probe degradation) are verified present in the final head.
  • Naming: restore/resume/load_snapshot confined to the data plane; control-plane failure handling uses cleanup/compensate/journal vocabulary; dirty appears only as the Firecracker track_dirty_pages payload field.

Porting note (for the record):

The Firecracker orchestration (pause → snapshot create → resume; restore via bare VMM + /snapshot/load) is migrated from the Go PoC, but the Rust side is a productization redesign layered on the #2472/#2475 backend contracts — adding an exact-version compatibility gate, a pinned backend executable (sealed memfd with len/mtime/ctime comparison), and a clean-vs-compensate failure boundary that the PoC did not have.

One non-blocking note:

The functional boundary is complete but scattered across "No new HTTP routes", the closed issues, and the full-only restriction — a short explicit "Not in this PR" paragraph in the body would aid discoverability.

LGTM.

@WeissonHan
WeissonHan merged commit 0de6ac1 into alibaba:main Aug 19, 2026
27 checks passed
@WeissonHan
WeissonHan deleted the feature/blaze/firecracker-checkpoint-capture-draft-v1 branch August 19, 2026 12:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component:blaze src/blaze scope:documentation ./docs/|./*.md|./NOTICE

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants