Initial reimplementation of composefs-c#225
Conversation
|
There's definitely some sub-tasks to this and pieces that we need to break out. One that I'm realizing is that the dumpfile format is hardcoded to sha256-12. I guess we can just auto-detect from length (like we're doing in other places) but the more I think about this the more I feel we need to formalize it (as is argued in #224 ) So how about a magic comment in the dumpfile like or so? |
4d43b61 to
1871128
Compare
|
Let's make the format layout a choice to avoid breaking sealed UKIs as is today |
8a5c48d to
9cb1923
Compare
6eda766 to
dc1fed7
Compare
dc1fed7 to
9a845fa
Compare
9a845fa to
9823c67
Compare
a8d6802 to
25cbbb1
Compare
895ccd1 to
8eeec80
Compare
|
bootc-dev/bootc#1812 is related to this - we need to fix how we generate the EROFS. The problem in a nutshell is that https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9ed50b8231e37b1ae863f5dec8153b98d9f389b4 fixed a legitimate bug, but it also made the kernel parser less strict than it needed to be to fix the bug; we now accept symlinks that cross a block boundary, whereas before we didn't. |
ad51b62 to
4081268
Compare
ae23696 to
5dab7f6
Compare
|
OK, this is obviously a giant PR, but I think it's getting closer into shape - the much extended proptest found lots of corner cases and we now have pretty robust parity with composefs-c as far as the V1 (original) EROFS layout. That said, when I was thinking about applying this to bootc I realized we have basically an upgrade compatibility hazard - I'll attach some LLM-assisted info on this. Details# Design: Dual-format EROFS generation (V1 + V2) with bootc UKI integration🤖 Assisted-by: OpenCode (Claude Sonnet 4.6) Backgroundcomposefs-rs added V1 EROFS format support (compatible with C The problem this design addresses: bootc uses composefs for sealed UKIs, where the
|
| Karg | Format | Notes |
|---|---|---|
composefs=<digest> |
V2 | Existing; no change to meaning. All currently sealed UKIs use this. |
composefs.digest=<digest> |
V1 | New; used by bootc container ukify --format=1. |
ComposefsCmdline in composefs-boot/src/cmdline.rs becomes an enum:
pub enum ComposefsCmdline {
/// Legacy V2 karg: `composefs=<digest>`
V2 { digest: Hex },
/// V1 karg: `composefs.digest=<digest>`
V1 { digest: Hex },
}Both variants are generated and parsed by composefs-boot. Since bootc maintains its own copy
of the initramfs karg parsing in bootc/crates/initramfs/src/lib.rs, the same logic must be
duplicated there. Both files carry a comment noting they must be kept in sync; the long-term
remedy is for bootc to consume composefs-boot directly rather than duplicating.
The initramfs logic at boot time:
- Check for
composefs.digest=→ look up V1 image incomposefs/images/<digest>, mount it. - Fall back to
composefs=→ look up V2 image, mount it (existing behaviour).
cfsctl init CLI
cfsctl init gains an --erofs option:
--erofs=v1 (default) Generate only V1 EROFS. Sets "v1_erofs" in ro_compat.
--erofs=dual Generate both V1 and V2 EROFS. Omits "v1_erofs" from ro_compat.
Idempotency: if the repo already exists and the erofs_formats setting differs, an error is
returned (same behaviour as a mismatched algorithm).
bootc integration
bootc initializes its composefs repository with:
RepositoryConfig {
algorithm: Algorithm::SHA512,
erofs_formats: FormatSet::BOTH, // no "v1_erofs" in ro_compat
..Default::default()
}This causes every image pull to generate both V1 and V2 EROFS objects automatically.
bootc container ukify gains a --format option:
--format=1 Embed composefs.digest=<v1-digest> in the UKI cmdline.
--format=2 (default for now) Embed composefs=<v2-digest> in the UKI cmdline.
The plan is to flip the default to --format=1 once the new initramfs logic ships broadly.
Migration
Existing bootc repos (initialized before this change, with V2 default and no v1_erofs
flag): because bootc will now pass erofs_formats: FormatSet::BOTH at init time, and init_path
is idempotent, the repo's meta.json is updated to reflect BOTH on next open. default_format_set()
then returns BOTH. On the next image pull, both formats are generated. Existing sealed V2 UKIs
continue to boot via the existing composefs=<v2-digest> karg and V2 image. No manual migration
step needed.
Existing plain cfsctl repos (V1 default, v1_erofs present): remain V1-only unless the
user re-runs cfsctl init --erofs=dual. Upgrading from V1-only to dual is allowed by init_path;
downgrading from dual back to V1-only returns an error (would silently stop generating V2 images
that existing sealed UKIs may depend on).
Files affected
composefs-rs
| File | Change |
|---|---|
crates/composefs/src/erofs/format.rs |
Add FormatSet type |
crates/composefs/src/repository.rs |
known_features::V1_EROFS, RepositoryConfig::erofs_formats, Repository::default_format_set(), commit_images() |
crates/composefs-oci/src/lib.rs |
IMAGE_REF_KEY_V1, BOOT_IMAGE_REF_KEY_V1; update create_filesystem and generate_boot_image |
crates/composefs-oci/src/boot.rs |
generate_boot_image gains FormatSet param |
crates/composefs-boot/src/cmdline.rs |
ComposefsCmdline enum; parse/generate both karg names |
crates/composefs-ctl/src/lib.rs |
`cfsctl init --erofs=v1 |
doc/repository.md |
Document v1_erofs feature flag and FormatSet semantics |
bootc (separate repo)
| File | Change |
|---|---|
crates/lib/src/store/mod.rs |
Init repo with FormatSet::BOTH |
crates/lib/src/ukify.rs |
`--format=1 |
crates/lib/src/bootc_composefs/status.rs |
Parse composefs.digest= alongside composefs= |
crates/initramfs/src/lib.rs |
Handle both karg names (duplicated from composefs-boot) |
67a3785 to
ec1e4ce
Compare
Add set_write_concurrency() to Repository for overriding the default parallelism. Add read_filesystem_with_semaphore() as a public entry point that accepts an explicit Semaphore, and refactor the internal read_filesystem_impl() to centralize semaphore selection. Prep for wiring up --threads in mkcomposefs. Assisted-by: OpenCode (Claude Sonnet 4.6) Signed-off-by: Colin Walters <walters@verbum.org>
The patch recipe referenced crates/cfsctl which was never a valid path; the crate has always been named composefs-ctl. Also relax the clean-tree check to allow untracked files (only committed changes need to match the pinned revision). Assisted-by: OpenCode (Claude Sonnet 4.6) Signed-off-by: Colin Walters <walters@verbum.org>
Signed-off-by: Colin Walters <walters@verbum.org>
import_oci_layout() was opening the layout directory before calling ensure_writable(), so pulling into a read-only repo produced a misleading ENOENT error instead of a clear 'not writable' message. Move the write check to the top of the function, matching the existing skopeo pull path. Fixes privileged_pull_readonly_repo integration test. Signed-off-by: Colin Walters <walters@verbum.org>
For compatibility with the C composefs, we need to support writing directly to a flat XX/DIGEST path, without a leading `objects/`. Assisted-by: OpenCode (Claude Sonnet 4.6) Signed-off-by: Colin Walters <walters@verbum.org>
The script hardcoded /usr/share/edk2/ovmf/OVMF_CODE.fd which is only present on Fedora. Probe a list of common paths (Ubuntu's ovmf package uses /usr/share/ovmf/OVMF.fd, Arch uses /usr/share/edk2/x64/OVMF.4m.fd) so the script works across distros without manual adjustment. Also add -machine q35, required on newer QEMU builds (e.g. RHEL10/CentOS Stream 10) where the default pc-i440fx machine type doesn't pair well with OVMF for EFI boot. Assisted-by: OpenCode (claude-sonnet-4-6@default) Signed-off-by: Colin Walters <walters@verbum.org>
The combined OVMF.qemuvars.fd with -bios hangs indefinitely on RHEL10/ CentOS Stream 10 QEMU (qemu-kvm 9.x). Use the split OVMF_CODE.fd + OVMF_VARS.fd files with -drive if=pflash and -machine q35 instead, which works correctly. Fall back to -bios with the combined image on distros that only ship the combined file (Ubuntu, Arch). Updated both testthing.py (which drives the example integration tests) and the fix-verity helper script (which runs the in-VM verity fixup pass). A temporary copy of OVMF_VARS.fd is made so UEFI can write to it without modifying the original system file. Assisted-by: OpenCode (claude-sonnet-4-6@default) Signed-off-by: Colin Walters <walters@verbum.org>
composefs-setup-root validates that the repo's meta.json has fs-verity enabled before trusting the repo. The dracut hook was only enabling verity on the content objects, so setup-root would see the repo as insecure and refuse to proceed. Switch the working directory to /sysroot/composefs (instead of the objects subdirectory) so we can enable verity on meta.json in addition to all the content objects. Also quote the loop variable and use the full relative path for clarity. Assisted-by: OpenCode (claude-sonnet-4-6@default) Signed-off-by: Colin Walters <walters@verbum.org>
The 30s default is tight on slower hardware (e.g. CentOS Stream 10 with OVMF pflash init overhead) — the VM boots successfully but just barely misses the window. 60s gives enough headroom while still being short enough to catch genuinely broken VMs. CI on Ubuntu with KVM acceleration boots well under 30s so the extra budget costs nothing. Assisted-by: OpenCode (claude-sonnet-4-6@default) Signed-off-by: Colin Walters <walters@verbum.org>
6c48658 to
03b9a32
Compare
Adds support for generating V1-format EROFS images alongside the existing
V2 ("composefs") format. V1 EROFS is the on-disk format used by the C
composefs implementation, enabling interoperability between the Rust and C
stacks.
Eventually, the idea is we deprecate the C implementation and replace
it with this.
It turns out that the EROFS filesystems we were generating can't
be mounted by RHEL9 era kernels. So that's another reason to fix this.
However: we can't change the EROFS layout we output by default, because
current sealed UKIs basically require compatibility.
So: Let's thread through the concept of versioning here.
While we're doing this, the idea is that for sealed UKIs, we will
distinguish "container image wants v1 format" by detecting a new
`composefs.cmdline=` karg.
Otherwise, the repository now defaults to v1 for new repos. Otherwise,
it defaults to generating both versions. Existing repositories can turn
off the V2 format as well.
Assisted-by: OpenCode (Claude Sonnet 4.6)
Signed-off-by: Colin Walters <walters@verbum.org>
03b9a32 to
6234700
Compare
|
OK, passing CI now, though re-reviewing I see a few more things to fix. |
Basically starting on composefs/composefs#423
3 key goals:
Assisted-by: OpenCode (Claude Sonnet 4)