Skip to content

composefs: Support boot counting for new systemd-boot deployments - #25

Draft
cgwalters-bot wants to merge 3 commits into
mainfrom
bot/composefs-boot-counting
Draft

cgwalters-bot wants to merge 3 commits into
mainfrom
bot/composefs-boot-counting

Conversation

@cgwalters-bot

@cgwalters-bot cgwalters-bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

With systemd-boot, when /etc/kernel/tries is set (the kernel-install convention, opt-in like ostree's boot-counting-tries; read from the booted system at staging time, and a malformed file is warned about and ignored), a staged composefs deployment's boot entry (BLS Type #1, and the .conf entries used for UKIs) gets a +N boot counter per the Boot Loader Specification. systemd-bless-boot marks it good after boot-complete.target; if the deployment never gets there, systemd-boot falls back to the previous one. Entries with no attempts left now sort last like in systemd-boot, so bootc status shows the failed deployment as the rollback instead of reporting a queued rollback. GRUB and the initial install are unchanged. A prep commit also replaces + in the version part of entry names, since an os-release version like 1.2.3+42 already produced a name systemd-boot reads as a boot counter.

Caveat: the current CentOS Stream 10 (selinux-policy 42.1.27) and Fedora 44 (44.10) policies have no allow init_t dosfs_t:file rename, so systemd-bless-boot can't rename entries on the ESP: new deployments are never marked good, and after N boots systemd-boot falls back. That needs fixing in fedora-selinux/selinux-policy (and RHEL); until then counting stays opt-in via /etc/kernel/tries. The tmt test loads a one-line CIL module ((allow init_t dosfs_t (file (rename)))) to work around it.

Rebased onto main b06e0b0 (after bootc-dev#2483 and the bootc-dev#2508 docs restructure); the rebase was clean, and the boot-failure-detection.md edit now lives in bootc-boot-failure-detection.7.md. Retested at 81e37da on a 16-core devspace (cgwalters-devspace-36601734885, CentOS Stream 10 base): just validate, just unit-tests (468 passed) and, with composefs + systemd-boot BLS/ext4, plan-53-composefs-boot-counting all passed.

Before the rebase: tested on a 16-core devspace (CentOS Stream 10 base): the bootc-lib bootc_composefs unit tests, just validate, and with composefs + systemd-boot BLS/ext4 the new plan-53-composefs-boot-counting (staged entry has +3; after reboot systemd-bless-boot blesses it; renamed to +0-3, status shows the rollback queued and the next boot falls back to the previous deployment). An earlier revision of this branch, before the review fixes (test renumbering, + sanitizing, docs, and ignoring a malformed tries file), also passed plan-36-rollback and plan-24-image-upgrade-reboot on BLS, and readonly, image-upgrade-reboot and boot-counting on sealed UKI.

Follow-ups, not in this PR:

  • File the SELinux policy issue (fedora-selinux/selinux-policy and RHEL), then consider enabling counting by default.
  • Show a failed deployment explicitly in bootc status, and maybe warn on the next bootc upgrade.
  • A composefs bootc-boot-complete-style check for bootc-finalize-staged failures, ordered before boot-complete.target.
  • Count boots after bootc rollback too (it rewrites both entries without a counter), and decide what a soft reboot into a counted entry should do.

Related: bootc-dev#1981

Generated-by: https://github.com/cgwalters/#llms


Review draft in cgwalters-forge, not upstream yet. This section is removed when the PR is opened upstream.

  • Upstream: bootc-dev/bootc, base main
  • Board item: PVTI_lADOE9oHIs4BlJLczg9kESM
  • Fork CI: off; the devspace testing described above is this PR's CI, and upstream CI runs once it is opened there

To review:

  • Approve, or comment /promote on a line of its own, to open it upstream, ready for review. Either covers only the commits pushed so far.
  • If upstream requires DCO, approving also signs off: promote adds Signed-off-by: Colin Walters <walters@verbum.org> to the commits lacking it (the bot's and yours; anyone else's only if you ask), with you as committer.
  • Add a /draft line (in the same comment or before) to open it upstream as a draft (/ready undoes that).
  • Close to drop it.
  • Edit the title and description freely: they become the upstream PR's. Review comments are squashed into the commits they concern, with a reply here.

A composefs deployment that fails to boot (kernel panic, initramfs
failure, a hang before boot-complete.target) stays the default boot
entry, and needs someone at the console to pick the previous one. The
ostree backend can opt into boot counting; the composefs backend writes
its own entries, so it has to do it itself.

With systemd-boot, write a staged deployment's entry with a `+N` boot
counter per the Boot Loader Specification. systemd-bless-boot renames it
to the plain name once the new deployment reaches boot-complete.target;
if it never gets there, systemd-boot falls back to the previous
deployment after N attempts. The rest of bootc reads entries by their
contents, not their names, so it doesn't care about the counter.

Like kernel-install (and ostree's boot-counting-tries), this is opt-in:
N comes from the booted system's /etc/kernel/tries when staging, and a
malformed file is warned about and ignored rather than blocking the
update. It also needs systemd-bless-boot in the new image, since
otherwise every entry would eventually be marked bad. A default-on
setting isn't safe yet because the current Fedora and CentOS SELinux
policies deny systemd-bless-boot renaming files on the ESP, so new
deployments are never marked good and fall back after N boots; the tmt
test adds a local policy module for that. GRUB has no boot counting, so
nothing changes there, and the initial install isn't counted as there
is nothing to fall back to.

Generated-by: AI
The Boot Loader Specification reserves `+` in entry file names for boot
counting, so an os-release version like `1.2.3+42` gave an entry that
systemd-boot treats as having 42 boot attempts left, and counts down.

Generated-by: AI
systemd-boot puts entries whose boot counter has run out after all
others, whatever their sort-key, so after a new deployment fails to boot
the previous one becomes the default. Mirror that when ordering Type #1
entries, so that `bootc status` reports the failed deployment as the
rollback rather than claiming a rollback is queued when it isn't, and
`bootc rollback` swaps the entries the bootloader actually uses.

Prep for enabling boot counting for new deployments.

Generated-by: AI
@cgwalters-bot

cgwalters-bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator Author

✅ dispatch ended well. Result: #25

@cgwalters-bot

cgwalters-bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator Author

Fix round 1 of 2 for b58df76abd8c: run.

Generated-by: https://github.com/cgwalters/#llms

@cgwalters-bot
cgwalters-bot force-pushed the bot/composefs-boot-counting branch from b58df76 to a65adf3 Compare October 31, 2026 18:13
@cgwalters-bot
cgwalters-bot marked this pull request as draft November 1, 2026 14:41
@cgwalters-bot

cgwalters-bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

Moved to draft. Pull requests on this midstream stay drafts (tracker#336), and the pass now follows this repository, so an approval of a ready one could land it on main ahead of upstream. Approving a draft is still fine, and the promote flow is unchanged. The lasting fix is cgwalters-forge/agent-board#570.

Generated-by: https://github.com/cgwalters/#llms

@cgwalters-bot cgwalters-bot added the needs-human The poll stopped here; a person decides what is next label Nov 1, 2026
@cgwalters-bot

Copy link
Copy Markdown
Collaborator Author

The poll stopped following this pull request: a draft with no checkpoint; mark it ready if the work is complete. It is labelled needs-human; remove the label to have the poll start again on it, with fresh fix rounds.

Generated-by: https://github.com/cgwalters/#llms

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

Labels

needs-human The poll stopped here; a person decides what is next review:deep Bot draft that needs a real review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant