Skip to content

oci: Generate composefs EROFS at pull time, track via config refs#263

Merged
cgwalters merged 6 commits intocomposefs:mainfrom
cgwalters:add-image-refs-for-gc
Apr 3, 2026
Merged

oci: Generate composefs EROFS at pull time, track via config refs#263
cgwalters merged 6 commits intocomposefs:mainfrom
cgwalters:add-image-refs-for-gc

Conversation

@cgwalters
Copy link
Copy Markdown
Collaborator

@cgwalters cgwalters commented Mar 14, 2026

Depends


Motivation: For bootc I want to store both erofs images automatically
without needing to manually hold references.

But really what I want is that for generic OCI container images,
we want a clean model where a tag points to a manifest, which
in turn should reference everything else automatically.

With this change when pulling an OCI container image, we deafult
to generating the EROFS and reference it from the splitstream
for the config.

The next step here: bootable images, the config can be rewritten with additional refs
(e.g. "composefs.image.boot").

@cgwalters cgwalters force-pushed the add-image-refs-for-gc branch 2 times, most recently from d62471b to c141eeb Compare March 14, 2026 20:39
@cgwalters cgwalters force-pushed the add-image-refs-for-gc branch 2 times, most recently from 5d15c15 to 8876ea0 Compare March 16, 2026 22:35
Johan-Liebert1
Johan-Liebert1 previously approved these changes Mar 17, 2026
Copy link
Copy Markdown
Collaborator

@Johan-Liebert1 Johan-Liebert1 left a comment

Choose a reason for hiding this comment

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

Skimming through the code and trying it out, LGTM

@Johan-Liebert1 Johan-Liebert1 dismissed their stale review March 17, 2026 05:51

The merge-base changed after approval.

@Johan-Liebert1 Johan-Liebert1 force-pushed the add-image-refs-for-gc branch from 8876ea0 to 07cd372 Compare March 17, 2026 05:51
@Johan-Liebert1
Copy link
Copy Markdown
Collaborator

Rebased and pushed

Johan-Liebert1 added a commit to Johan-Liebert1/composefs-rs that referenced this pull request Mar 17, 2026
While trying out composefs#263
locally, I found that Rust is rearranging the SplitStreamHeader
struct's fields to the following

```
[32, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83, 112, 108, 105, 116, 83, 116, 114, 101, 97, 109, 0, 2, 12]
```

The first two U64 are the start and end of the field `info` when `info`
is the last field in the struct; then comes the flags which is the third
field...

We probably don't want this undeterministic behaviour, which might also
change from arch to arch

Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
github-merge-queue Bot pushed a commit that referenced this pull request Mar 17, 2026
While trying out #263
locally, I found that Rust is rearranging the SplitStreamHeader
struct's fields to the following

```
[32, 0, 0, 0, 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83, 112, 108, 105, 116, 83, 116, 114, 101, 97, 109, 0, 2, 12]
```

The first two U64 are the start and end of the field `info` when `info`
is the last field in the struct; then comes the flags which is the third
field...

We probably don't want this undeterministic behaviour, which might also
change from arch to arch

Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
@cgwalters cgwalters force-pushed the add-image-refs-for-gc branch 4 times, most recently from 8567826 to 37b7da3 Compare March 20, 2026 18:28
@cgwalters cgwalters force-pushed the add-image-refs-for-gc branch from 37b7da3 to 4672150 Compare March 31, 2026 13:49
@Johan-Liebert1
Copy link
Copy Markdown
Collaborator

Needs another rebase

@cgwalters cgwalters force-pushed the add-image-refs-for-gc branch 2 times, most recently from 0558c8d to a341161 Compare April 2, 2026 15:12
The clean recipe now refuses to delete the bootc checkout if there are
any uncommitted changes, preventing accidental loss of in-progress work.

The patch recipe had a bug where the grep for an existing [patch] section
matched a commented-out example line, causing sed to replace the workspace
dependency instead of appending a new [patch] section.  Fix by anchoring
the pattern to reject comment lines.  Also drop the cargo update call
which was rewriting Cargo.toml (the lockfile updates on the next build).

Assisted-by: OpenCode (Claude Opus 4)
Signed-off-by: Colin Walters <walters@verbum.org>
The unprivileged smoke test needs fs-verity enabled on the root
filesystem to exercise verity-related code paths. Add tune2fs -O
verity before the test steps.

Assisted-by: OpenCode (Claude Opus 4)
Signed-off-by: Colin Walters <walters@verbum.org>
The old sealing approach stored an fsverity digest in OCI config labels
(containers.composefs.fsverity) and provided seal()/mount() functions to
write and consume it. This is being replaced by EROFS image refs stored
directly in config splitstreams, which integrates with the GC model and
avoids mutating the OCI config.

Remove the seal() and mount() library functions, the seal_digest() and
is_sealed() methods on OciImage, the "sealed" field from ImageInfo, and
the corresponding Seal/Mount CLI subcommands and SEALED table column.
Also remove the now-obsolete implementation plan doc.

Assisted-by: OpenCode (Claude claude-opus-4-6)
Signed-off-by: Colin Walters <walters@verbum.org>
Describe the current OCI storage model: naming conventions for
manifest/config/layer/blob splitstreams, how tags map to refs under
streams/refs/oci/, the named_ref chains (manifest→config+layers,
config→layers), and how the GC walks from tags to objects.

Also notes the current gap: EROFS images derived from OCI content are
not referenced by any splitstream, so their lifecycle must be managed
separately.

Assisted-by: OpenCode (Claude claude-opus-4-6)
Signed-off-by: Colin Walters <walters@verbum.org>
Add test utilities for creating multi-layer OCI images from composefs
dumpfile strings. This uses the real dumpfile format parsed by
dumpfile_to_filesystem(), then walks the resulting FileSystem tree to
emit tar bytes for import_layer().

Two convenience builders with versioned boot content:
- create_base_image: 5-layer busybox-like app image
- create_bootable_image(version): 20-layer bootable OS with kernel and UKI

v1 and v2 share userspace layers (busybox, libs, systemd, configs) but
differ in kernel version (6.1.0 vs 6.2.0), initramfs, modules, and UKI.
When both are pulled into the same repo the shared layers deduplicate,
exercising GC correctness with content referenced by multiple images.

Prep for adding boot image management API.

Assisted-by: OpenCode (Claude claude-opus-4-6)
Signed-off-by: Colin Walters <walters@verbum.org>
When pulling an OCI container image, automatically generate the composefs
EROFS image and reference it from the config splitstream. This creates a
clean GC chain: tag → manifest → config → EROFS image, so all derived
artifacts stay alive as long as the tag exists.

For bootable images, a second "boot" EROFS variant is generated with
transform_for_boot applied (clearing /boot to avoid circular UKI refs).

The old seal/mount mechanism is replaced by a simpler Mount subcommand
that looks up the EROFS ref from the config splitstream. OpenConfig struct
replaces the (config, layer_map) tuple for richer open_config returns.

Assisted-by: OpenCode (Claude Opus 4)
Signed-off-by: Colin Walters <walters@verbum.org>
@cgwalters cgwalters force-pushed the add-image-refs-for-gc branch from a341161 to 292a518 Compare April 2, 2026 20:10
@cgwalters cgwalters enabled auto-merge April 2, 2026 20:45
@cgwalters cgwalters requested a review from jeckersb April 3, 2026 15:47
@jeckersb jeckersb disabled auto-merge April 3, 2026 19:58
Copy link
Copy Markdown
Collaborator

@jeckersb jeckersb left a comment

Choose a reason for hiding this comment

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

Approving but disabled auto-merge in case you want to address the one comment below. If not, send it.

// Generate the composefs EROFS image and link it to the config splitstream.
// For container images this rewrites the config+manifest with the EROFS ref
// and tags the final manifest. Artifacts are skipped and tagged as-is.
let erofs = crate::ensure_oci_composefs_erofs(
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.

Not necessarily a huge problem, but if I'm following correctly the code above is going to pull all of the layers onto disk, but if we fail to generate the EROFS here the pull is going to early exit and we're not going to tag the image below, which means the layers will sit in the repo unreachable by tag until some future GC is run.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good question, thanks for looking at this!

which means the layers will sit in the repo unreachable by tag until some future GC is run.

Your concern is resumption of partial pulls, right? As long as we don't GC, we should still reuse those cached layers because we do save the layer streams I believe. I don't think this is a new issue - but we should definitely have some tests for interrupted/partial pulls. I'll look at that!

@cgwalters cgwalters added this pull request to the merge queue Apr 3, 2026
Merged via the queue into composefs:main with commit 9363459 Apr 3, 2026
100 of 110 checks passed
cgwalters added a commit to cgwalters/composefs-rs that referenced this pull request Apr 10, 2026
…ld to ImageInfo

These were part of the sealing-impl branch but were lost during
conflict resolution of PR composefs#263 rebase. The oci mount subcommand
needs signature verification flags for the sealed app container
workflow, and ImageInfo needs the sealed field for oci images --json.

Assisted-by: OpenCode (Claude Opus 4)
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.

3 participants