Skip to content

composefs: follow-ups to #2448 (three regressions) #2598

Open

Description

@jmarrero-bot

These are three regressions from #2448, found while reviewing its last revision; @jmarrero chose to merge it and fix them as follow-ups. All three come from reading the code at c153cda and haven't been reproduced.

1. A subdirectory in the ESP's loader/addons fails every UKI upgrade/switch

Every bootc upgrade/switch that stages a deployment on a composefs UKI system now copies the ESP's loader/addons into loader/addons.staged with Dir::copy, which rejects anything that isn't a regular file. So a subdirectory there aborts staging, including on systems that never used the addon options.

Reproduce: on a composefs UKI system, mkdir <ESP>/loader/addons/foo, then bootc upgrade or bootc switch to a new image. The error should end with Staging Global UKI Addons: Copying addon foo: the source path is not an existing regular file.

Code: copy loop, call site.

Fix: skip non-regular entries with a warning, or copy directories recursively.

2. An image with more than one UKI fails install, upgrade and switch

setup_composefs_uki_boot now parses every UKI's cmdline into one UKIInfo, and parse_uki_cmdline bails on the second composefs= it sees, even when the digests match. So an image with two UKIs in /boot/EFI/Linux (for example two kernel flavors sealed against the same rootfs) fails with Already had cmdline ..., found another .... Before #2448 each UKI was validated and written to the same ESP file name, so the last one won.

Reproduce: build a sealed-UKI image with two UKIs that carry the same composefs= digest, then install or switch to it.

Code: the check, the loop that feeds every UKI into it. Nothing rejects such an image earlier: the image-level digest check reads only the first UKI, and kernel discovery picks the first of several.

Fix: refuse a second composefs= only when it comes from an addon. If more than one UKI per image isn't supported, reject it up front with a clear error and document that.

3. Pruning GC can fail on a live deployment's /boot, aboot included

The pruning GC (run by upgrade, switch and delete-deployment) now dumps /boot from the non-bootable image of every live deployment, to keep objects that a pruned deployment shares. composefs_ctl::dump_files fails if the image has no /boot (/boot not found), and each line goes through Entry::parse(line).unwrap(). Before #2448 these could only fail for a deployment being pruned. Now any live deployment, the booted one included, can fail GC or panic it, and upgrade/switch then exit with an error after staging. Unlike the orphan loop, the live loop isn't skipped on aboot, so aboot systems run it too wherever a non-bootable image is linked. This is unlikely in practice, since bootc images normally ship /boot.

Reproduce: deploy a composefs image that has no /boot directory, then run bootc internals composefs-gc --prune-repo or bootc upgrade.

Relatedly, get_boot_dump returns None with a warning when a live deployment's linked images can't be resolved, and that deployment's objects then aren't protected (fail-open).

Code: get_boot_dump, live loop, orphan loop, skipped on aboot.

Fix: skip the live scan on aboot, as the orphan loop does. When a live root's /boot can't be dumped or parsed, warn and skip the /boot object cleanup for that run. Replace the unwrap with an error.

cc @Johan-Liebert1

Generated-by: https://github.com/jmarrero-bot#llms

Activity

  1. moved this to In Review in Workstreamon Oct 28, 2026
  2. moved this from In Review to Done in Workstreamon Oct 28, 2026
  3. Johan-Liebert1 commented on Oct 29, 2026

    @Johan-Liebert1
    Member
    1. A subdirectory in the ESP's loader/addons fails every UKI upgrade/switch

    I don't think we should support this anyway. As even with only global addons we have a lot of quirks and edge cases

    1. An image with more than one UKI fails install, upgrade and switch

    We don't allow multiple UKIs and never install more than one, so this is expected

    Reproduce: deploy a composefs image that has no /boot directory, then run bootc internals composefs-gc --prune-repo or bootc upgrade.

    though unlikely, this can happen. I'll open a PR

    Relatedly, get_boot_dump returns None with a warning when a live deployment's linked images can't be resolved, and that deployment's objects then aren't protected (fail-open).

    We always save a non-bootable image, so this shouldn't happen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions