| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Both halves of one failure mode: a bake that runs out of space does not stop, it produces a *corrupt* artifact — a rootfs whose package files carry other files' bytes, or a truncated `memory.bin`. Inside a guest that surfaces much later as `uname: option requires an argument`, `Exec format error`, or `EBADMSG` on a `/var/lib/dpkg` entry, so it reads like a broken build rather than a broken image. - `forkd parent build` (conversion) and `forkd snapshot` (bake) check free space on the target filesystem before the first write and refuse below a 5 GiB reserve (`FORKD_MIN_FREE_GIB` overrides). Conversion is the first multi-GB write of the pipeline, and the snapshot dir holds the clone plus a fresh `memory.bin`. The probe stays advisory: if `statvfs` cannot run, warn and continue rather than block work on a broken measurement. `doctor::available_bytes(path)` is extracted from the check's hardcoded-path statvfs so both callers share one probe. - `forkd snapshot` removes its staging dir on every exit. Only the success path did, so any `?` after the volatile artifacts were written — boot timeout, snapshot error, publish error, interrupt — left a fully written `memory.bin` (GBs) beside the snapshot dir that nothing ever collected. Tests cover the guard (removal, and tolerance of an already-removed dir — the success path renames files out and a stale sweep may beat it) and the probe's ancestor walk, which is what makes it usable before the snapshot dir exists. Signed-off-by: jrimmer <jason@rimmer.net>
Parallel tests write to the same filesystem between the two calls, so exact equality flakes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md
There was a problem hiding this comment.
Reviewed. The preflight and staging guard both look right, and the drop order against rootfs_rollback (rollback unwinds first) is correct.
Two maintainer commits pushed to this branch:
Verified on Linux (Ubuntu 22.04, stable Rust in Docker): fmt, clippy -D warnings, and cargo test --all all green, both on its own and together with #314/#315/#322. The daemon restore-path gate you mentioned is welcome as a follow-up.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Two halves of one failure mode. Running out of space partway through a write does not fail cleanly — it leaves a corrupt artifact, and the corruption is invisible to anything that only checks the file still runs.
What that looks like inside a guest, from a bake that converted on a full filesystem:
plus Exec format error on the same path, EBADMSG on /var/lib/dpkg and /var/lib/apt/lists directory entries, and libidn2.so.0: cannot dynamically load position-independent executable. A settled rootfs hashed byte-identical to its source image in the same session, so the damage is in the write path, not the source. It reaches CI as a compile error ~40s deep (set -euo pipefail; OS="$(uname -s)" in a dependency's build hook) that reads like a broken build script.
Free-space preflight
forkd parent build (conversion) and forkd snapshot (bake) now check free space on the target filesystem before the first write and refuse below a 5 GiB reserve, overridable with FORKD_MIN_FREE_GIB:
Conversion is the first multi-GB write of the pipeline (it unpacks a whole image into a fresh ext4) and the snapshot dir holds the clone plus a fresh memory.bin. The reserve matches the threshold forkd doctor already reports as "recommended ≥5 GiB".
doctor::available_bytes(path) is extracted from check_snapshot_dir_space's statvfs, which was private and hardcoded to $XDG_DATA_HOME/forkd/snapshots — that is the wrong filesystem to gate --rootfs/--snapshot-root overrides against, which is why it takes a path now. The probe stays advisory: if statvfs cannot run, it warns and continues rather than blocking work on a broken measurement.
Not included: the same gate on the daemon's restore path. The controller cannot depend on forkd-cli, so that needs the helper in forkd-vmm plus a policy for the 507/409 response. Happy to do it as a follow-up if the shape here looks right.
Staging dir cleanup
forkd snapshot wrote vmstate, memory.bin and snapshot.json into <tag>.staging-<pid> and removed it only on the success path, so any ? after the files were written — boot timeout, snapshot error, publish error, interrupt — left a fully written memory.bin (GBs) beside the snapshot dir with nothing to collect it. A StagingDirGuard now owns the dir for the whole bake; the block comment claiming "a failure at any of those steps drops the staging dir" was not implemented and now is.
The guard holds the path, not a handle, so the successful rename of files out of the dir is unaffected, and the redundant success-path remove_dir_all is gone.
Tests
Guard removal and tolerance of an already-removed dir (the success path may have emptied it, and a stale sweep may beat the guard to it); the probe's ancestor walk, which is what makes it usable before the snapshot dir exists.
cargo fmt --check clean, cargo clippy --all-targets --all-features -D warnings clean, cargo test -p forkd-cli green (56 passed, 1 ignored). No KVM run — both changes are filesystem-level.