Commit fe2e3cc
committed
unified-storage: Implement three-store pipeline for composefs and ostree backends
The goal of unified storage is to make the same on-disk layer data
simultaneously visible to containers-storage (for `podman run`),
composefs (for the boot overlay), and ostree (for deployment tracking),
using reflinks so layers are stored once regardless of how many stores
reference them.
This wires the full pipeline into the ostree backend. When a system has
unified storage enabled — either at install time via the
[install.storage] config key, or post-install via `bootc image
set-unified` — upgrades and switches route through pull_via_composefs:
Stage 1: pull image into bootc-owned containers-storage
Stage 2: zero-copy reflink import into the composefs OCI repo
Stage 3: synthesize an ostree commit from the composefs tree
Whether unified storage is active is tracked by composefs/bootc.json
(BootcRepoMeta). This replaces the previous heuristic that checked
per-image presence in containers-storage, which broke when switching to
a new image reference.
The install config gains a storage.unified key with three values:
disabled (default), enabled (fail if reflinks unavailable), and
enabled-with-copy (copy fallback). This lets an image opt into unified
storage without requiring a CLI flag to be threaded through every
installer.
bootc image list cross-references composefs tags against containers-storage
by config digest to report images as unified (in all three stores) or
partial (cstorage only, composefs import pending). bootc internals fsck
images checks consistency and --repair restores cstorage from composefs
when needed. The cstorage GC is extended to protect images that have
composefs tags, since the composefs splitstreams reference the cstorage
layer data — pruning one without the other would corrupt the repo.
On the composefs-native backend, onboarding must also reconcile the
non-booted deployments: a rollback or staged image lives in the composefs
repo but not yet in containers-storage. `bootc image set-unified` and the
new `bootc image sync` command now reconcile every bootloader-pinned
deployment (booted, rollback, staged) into bootc's containers-storage, so
`bootc internals fsck images` passes there too. The pinned set is grounded
in the bootloader entries (via list_bootloader_entries), which are the
authoritative record of what the system can boot, rather than the origin
state directories which can drift from it.
Reconciliation exports the missing image from the composefs repo. This
must preserve the config digest, since that is the image ID
containers-storage matches on: the export replays each layer's
uncompressed tar byte-exactly via SplitStreamReader::cat() (preserving the
diff_ids) and writes the original config JSON verbatim rather than
re-serializing it. The recovered image is imported into bootc's private
overlay store (not the host's default store) using the same bind-mount
plumbing as the booted-image copy path, so fsck actually sees it.
Assisted-by: OpenCode (claude-sonnet-4-6@default)
Signed-off-by: Colin Walters <walters@verbum.org>1 parent 068050a commit fe2e3cc
54 files changed
Lines changed: 4678 additions & 700 deletions
File tree
- .github/workflows
- ci
- contrib/packaging
- crates
- lib/src
- bootc_composefs
- install
- store
- ostree-ext
- src/container
- tests/it
- xtask/src
- docs/src
- man
- tmt
- plans
- tests
- booted
- readonly
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
158 | 158 | | |
159 | 159 | | |
160 | 160 | | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
161 | 168 | | |
162 | 169 | | |
163 | 170 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
290 | 290 | | |
291 | 291 | | |
292 | 292 | | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
293 | 307 | | |
294 | 308 | | |
295 | 309 | | |
296 | 310 | | |
297 | 311 | | |
298 | 312 | | |
| 313 | + | |
299 | 314 | | |
300 | 315 | | |
301 | 316 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
18 | | - | |
19 | | - | |
20 | | - | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
| 14 | + | |
| 15 | + | |
29 | 16 | | |
30 | 17 | | |
31 | 18 | | |
| |||
35 | 22 | | |
36 | 23 | | |
37 | 24 | | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
55 | 31 | | |
56 | 32 | | |
57 | | - | |
58 | | - | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
59 | 69 | | |
60 | 70 | | |
61 | 71 | | |
0 commit comments