install: reflink-capable filesystems with ostree pull through composefs first#2205
install: reflink-capable filesystems with ostree pull through composefs first#2205cgwalters wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a "composefs-first" import pipeline that allows synthesizing ostree commits directly from a composefs OCI repository using reflinks (FICLONE) to share disk blocks. This approach avoids tar round-trips and improves space efficiency on reflink-capable filesystems like XFS and btrfs. Key changes include a new pull_auto dispatcher, updated installation and upgrade logic to utilize the new pipeline, new fsck consistency checks for composefs-ostree alignment, and comprehensive integration tests. Review feedback identified a missing argument in a GIO stream constructor, a type mismatch in GVariant array creation, and potential fragility in internal CLI argument parsing for the cfsctl proxy.
Ostree sets the immutable ext4 attribute on each deployment checkout directory, which causes lsetfilecon() to return EPERM during the final SELinux relabeling pass even though those files are already correctly labeled by the earlier composefs import pass. Rather than skipping the entire ostree/deploy subtree (which would leave stateroot metadata and var directories unlabeled), enumerate the actual checkout directories under ostree/deploy/<stateroot>/deploy/ and skip only those immutable roots by dev/ino. Also generalise ensure_dir_labeled_recurse to accept a slice of (dev, ino) pairs to skip rather than a single Option, so multiple checkout directories can be excluded in one pass. Assisted-by: OpenCode (Claude Sonnet 4.6) Signed-off-by: Colin Walters <walters@verbum.org>
BOOTC_filesystem was silently ignored when BOOTC_variant=ostree because install_args() only emitted --filesystem inside the composefs_backend block. bcvk's --filesystem flag is not composefs-specific (the cache hash includes filesystem type and bcvk creates a fresh base disk per filesystem), so the guard was wrong. Move --filesystem before the composefs_backend block so that e.g. BOOTC_filesystem=ext4 just test-tmt-nobuild readonly actually installs on ext4, exercising the reflink-probe fallback path. Assisted-by: OpenCode (claude-sonnet-4-6@default) Signed-off-by: Colin Walters <walters@verbum.org>
Without this, `bootc internals cfsctl oci images` (and other cfsctl subcommands) would fall back to cfsctl's own default repo heuristic. While cfsctl already picks /sysroot/composefs when running as root, being explicit here documents the intent and makes the behaviour consistent regardless of uid. Pass --system rather than hardcoding the path so the constant lives in one place (cfsctl's system_path()). Users can still override with --repo, --user, or --system and the injected flag is skipped in that case. Assisted-by: OpenCode (claude-sonnet-4-6@default) Signed-off-by: Colin Walters <walters@verbum.org>
a817bec to
0ecf7a0
Compare
…y path Add an end-to-end unified storage path for the ostree backend on reflink filesystems. When the composefs repo is present and unified storage has been enabled (via `bootc image set-unified`), `pull_auto` now routes through `pull_via_composefs_unified` which: 1. Pulls the image into bootc-owned containers-storage via `pull_composefs_unified` (zero-copy reflinks from the registry blobs). 2. Synthesizes an ostree commit from the composefs repo via `import_from_composefs_repo` + FICLONE, marking it META_COMPOSEFS_SYNTHESIZED so downstream code knows no per-layer blob refs exist. Unified storage mode is tracked by a new flag file `/sysroot/composefs/bootc.json` (BootcRepoMeta), written atomically on the first successful set-unified call and read cheaply on every pull_auto to decide which path to take. This avoids the previous heuristic that checked per-image presence in containers-storage and broke across `bootc switch` to a new image reference. The old ostree-native unified pull path (new_importer_with_config / check_disk_space_unified / prepare_for_pull_unified / pull_unified) is removed — it was dead code since the composefs pipeline was introduced. `bootc image copy-to-storage` is fixed for synthesized commits: because the synthesized ostree commit carries no per-layer blob refs, `ostree_ext::container::store::export()` would error out with "Refspec not found". `push_entrypoint` now detects META_COMPOSEFS_SYNTHESIZED on the resolved commit, reads the manifest and config from the commit metadata, and delegates to the composefs layer-streaming export path instead. The composefs export helper (`export_repo_to_image`) is refactored: the streaming core is extracted into `export_composefs_to_dest` so it can be called from both the composefs-boot and ostree-boot code paths. A new TMT plan (plan-44-readonly-unified) onboards a system to unified storage and then runs the full readonly test suite against it. Assisted-by: OpenCode (Claude Sonnet 4.6) Signed-off-by: Colin Walters <walters@verbum.org>
0ecf7a0 to
4f3055d
Compare
A spike of further work on #20 - basically, we control both ends of the composefs-rs and ostree sides, and if reflinks are enabled we can change things so we always pull into composefs first - making that the source of truth for image storage, and then just reflinking from there into ostree.