Skip to content

install mount: Select the deployment from the default boot entry - #32

Closed
cgwalters-bot wants to merge 10 commits into
mainfrom
bot/install-mount-default-entry
Closed

cgwalters-bot wants to merge 10 commits into
mainfrom
bot/install-mount-default-entry

Conversation

@cgwalters-bot

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

Copy link
Copy Markdown
Collaborator

bootc install mount --latest now mounts the deployment that the default boot entry boots, instead of requiring the sysroot to contain exactly one deployment. This is the follow-up to the review on bootc-dev#2483 (mount.rs:90). Design notes: https://gist.github.com/cgwalters-bot/3d295a3185c75c5a24989dda21018573

A booted system knows its deployment from the kernel command line. Offline, the equivalent is the command line of the entry the bootloader would pick. The entries come from SYSROOT/boot and the ESP, and they are ordered with the same code bootc status uses: for GRUB, the user.cfg UKI entries or else the Type 1 entries sorted by file name; otherwise the Type 1 entries in BLS order. For a composefs entry, its digest (or UKI name) picks the deployment. For an ostree= entry, it is OSTree's own default (deployments()[0], which OSTree orders from the same entries, as bootc status shows it), rather than re-sorting the entries: GRUB's file name order differs from OSTree's at ten or more deployments. The bootloader probe get_bootloader uses without EFI variables now takes the boot directories, so mount shares it. A new --esp option names the ESP, and defaults to SYSROOT/boot/efi.

Caveats:

  • There is no --boot. OSTree loads its deployments from SYSROOT/boot, so /boot has to be mounted there anyway, and the man page says so.
  • EFI variables (such as a one-time boot entry), boot counting, loader.conf's default and grubenv's saved_entry are not considered. bootc status doesn't consider them either.
  • With no boot entries at all, the old rule still applies: a sole deployment is mounted. That keeps a fresh install mountable without mounting the ESP.

Tested on a 16-core RHEL 10 devspace:

  • Plan 23 (install-outside-container) is extended. On ostree it deploys the same commit ten more times (11 deployments, so file-name order would pick the wrong one) and checks that --latest follows OSTree's default, also after ostree admin set-default. On composefs it rewrites the installed boot entries to name a missing deployment and checks that the mount fails naming it, then restores them. An earlier two-deployment version of the test, run with main's bootc (683bb05), failed with target must contain exactly one deployment (found 2 OSTree, 0 composefs).
  • With this change, plan 23 passes on ostree/grub, composefs grub/BLS/ext4 and composefs systemd-boot/UKI/ext4 (unsealed), and just validate and just unit-tests pass. The new unit tests cover entry ordering for each bootloader layout, the boot directory probe, and choosing the deployment.

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_lAHOAQ_SPs4Bj2Gizg81_2U
  • 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.

Bot run: session 929c7a64, agent ab90df78 · claude-opus-5-5 21.2M in (96% cached) / 84k out · ~$10.14 inference + ~$3.62 compute (est., list prices) · 1h 27m wall · 23.0 core-h, Actions run 36504696906

Bot run: session 929c7a64, agent ab90df78 · claude-opus-5-5 27.5M in (96% cached) / 106k out · ~$13.24 inference + ~$5.97 compute (est., list prices) · 2h 27m wall · 37.9 core-h, Actions runs 36511940554, 36504696906

@cgwalters-bot cgwalters-bot left a comment

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.

Review guide for head 6d62ee8a2c: where to look closely and what is safe to skim. It is advice from the bot's reviewer and doesn't replace reading the diff; the review app walks it.

bootc install mount --latest now mounts the deployment the default boot entry boots instead of requiring exactly one deployment. Composefs is handled by reusing status.rs's sorted Type 1 / GRUB user.cfg readers plus BLSConfig::get_verity, which matches bootc status. The risk is in the parts that are new code rather than reuse. For OSTree the PR parses ostree=/ostree/boot.N/... itself and picks the first entry in GRUB file-name order. bootc status instead uses ostree's own deployment list, which Sysroot::load already builds from these same entries in ostree's version order (deployments()[0] is the default). The PR's order differs from that one at 10 or more deployments (ostree-9 sorts after ostree-10). The GRUB-vs-BLS probe (is_grub, GRUB_DIRS) also repeats classify_bootloader's non-EFI branch in status.rs. The fallback for when no entries are found keeps the old exactly-one rule, so it fails closed. There is no --boot, which is consistent because OSTree only loads from SYSROOT/boot anyway. The tmt change extends plan 23, so no new test number is needed. It checks a real selection on OSTree (set-default) and only the negative case on composefs.

Hotspots

  1. look-closely · logic — crates/lib/src/mount.rs:111-139 (6d62ee8): This reimplements ostree's own bootlink parsing and entry-to-deployment mapping. ostree_sysroot.deployments() is already ordered from these same entries, and bootc status uses it for OSTree. For an ostree= default entry, taking ostree's deployments[0] would drop this parser and its tests and match status exactly.
  2. look-closely · logic — crates/lib/src/mount.rs:159-171 (6d62ee8): This duplicates classify_bootloader's non-EFI filesystem probe and GRUB_DIRS in bootc_composefs/status.rs, in relative-path form. Consider making the probe take a boot Dir and sharing it with get_bootloader, so the two cannot drift.
  3. look-closely · logic — crates/lib/src/mount.rs:185-208 (6d62ee8): This is the core ordering. For GRUB Type 1 it uses descending file-name order, which is right for bootc's composefs entries. For OSTree entries (ostree-N-stateroot.conf) it disagrees with ostree's version order at 10 or more deployments. Also, user.cfg existence stands in for status's origin boot_type, and systemd-boot merges /boot and ESP entries.
  4. note · error-handling — crates/lib/src/mount.rs:216-272 (6d62ee8): The fallback only applies with zero entries and still refuses more than one deployment, so it is safe. A foreign entry that sorts first (another OS on a shared ESP) fails hard with 'has no composefs or ostree kernel argument' rather than guessing, which is acceptable.
  5. note · api — crates/lib/src/mount.rs:309-334 (6d62ee8): --esp defaults to SYSROOT/boot/efi, and there is no --boot. That is consistent because ostree Sysroot::load only reads SYSROOT/boot, and --boot can be added later without breaking anything.
  6. note · test-gap — tmt/tests/booted/test-install-outside-container.nu:269-288 (6d62ee8): On composefs this only proves the entries are consulted (a missing target fails). It never selects between two composefs deployments, so that selection is covered only by the unit tests.
  7. note · test-gap — tmt/tests/booted/test-install-outside-container.nu:291 (6d62ee8): This removes the etc.transient prepare-root.conf written earlier so the markers persist. A short comment would say why.

Safe to skim

  • crates/lib/src/bootc_composefs/status.rs: thin wrapper exposing the existing sorted-entries helper for an explicit bootloader
  • docs/src/man/bootc-install-mount.8.md: man page prose matching the new behavior
  • crates/lib/src/mount.rs:499-684: table-driven unit tests

@cgwalters-bot
cgwalters-bot force-pushed the bot/install-mount-default-entry branch from 6d62ee8 to ba441d5 Compare September 29, 2026 03:12
HarshwardhanPatil07 and others added 9 commits September 29, 2026 10:14
Set manual headers from filenames, keep temporary inputs in target/man, and regenerate when version metadata changes. Escape leading apostrophes so roff does not silently drop prose. Add regression tests for headers, apostrophes, and boolean options.

Generated-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Map narrative chapters to stable section 7 names and validate one-to-one coverage with SUMMARY.md. Keep existing navigation flat while exposing the previously unlisted command references. Reject missing, duplicate, empty, and unsafe entries before rendering.

Generated-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Use parsed Markdown spans to preserve formatting and code examples while mapping chapter links to installed manuals. Keep external links intact and resolve generated web artifacts against bootc.dev. Reject missing or escaping local documentation links.

Generated-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Convert supported Mermaid flowcharts and two-column guide tables using parsed Markdown spans, leaving fenced examples untouched. Reject unsupported diagram syntax rather than silently losing it. Wrap long command examples for terminal reading.

Generated-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Render canonical narrative chapters into section 7 without creating Markdown copies. Generate bootc-docs(7) in website navigation order, include manual cross-references and version metadata, and remove stale generated guide output.

Generated-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Install section 7 alongside sections 5 and 8, fail the install target if generation fails, and validate coverage during website and generated-file checks. Route reference generation through the shared inventory and point bootc(8) at the offline index. The existing RPM man* file glob already covers the new manuals.

Generated-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Keep each shared explanation in one canonical source so website and
installed manuals cannot drift through separately maintained copies.

Keep installation configuration discovery and merge precedence in its
reference manual, and soft-reboot behavior in the upgrades guide. Replace
repeated explanations with links while retaining command-specific details.

Align the canonical text and CLI help with the implemented behavior,
including platform-specific bootloader setup and the experimental
composefs soft-reboot fallback limitation. No runtime behavior changes.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Keep one naming convention for guides and reference manuals instead of
maintaining a separate chapter-to-manual manifest.

Rename narrative chapters to stable section-7 filenames, reuse filename
parsing, and update links without changing prose or navigation. Preserve
published website URLs with mdBook redirects.

Generated-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Signed-off-by: bootc-bot[bot] <225049296+bootc-bot[bot]@users.noreply.github.com>
`--latest` counted deployments and refused anything but exactly one.
That fails on any installation that has been upgraded, and it can't
choose when a sysroot holds both OSTree and composefs deployments
(e.g. mid-migration). A booted system answers "which deployment" from
its kernel command line. Offline, the equivalent is the command line of
the boot entry the bootloader would pick.

So read the entries from /boot and the ESP and order them as `bootc
status` does, sharing its bootloader probe (now taking the boot
directories rather than looking at the host's /boot) and entry sorting.
A composefs default entry names its deployment by digest (or UKI name).
For an `ostree=` one, OSTree's own deployment order, which it loads from
the same entries, already has the default first, so use that rather than
re-sorting the entries: GRUB's file name order differs from it at ten or
more deployments. The ESP comes from a new `--esp`, defaulting to
SYSROOT/boot/efi. /boot has to be at SYSROOT/boot anyway, since OSTree
loads its deployments from there.

With no entries at all, e.g. when the ESP isn't mounted on a
systemd-boot install, a sole deployment is still selected as before, so
mounting a fresh installation needs no extra mounts.

Generated-by: AI
Signed-off-by: Colin Walters <walters@verbum.org>
@cgwalters-bot
cgwalters-bot force-pushed the bot/install-mount-default-entry branch from ba441d5 to a221ae8 Compare September 29, 2026 16:08
@cgwalters-bot

Copy link
Copy Markdown
Collaborator Author

Signed off 1 commit(s) with Signed-off-by: Colin Walters <walters@verbum.org> for bootc-dev/bootc's DCO check, on cgwalters's approval #32 (review) of ba441d50e809. Same trees; the head is now b298c49ceeaf.

@cgwalters-bot
cgwalters-bot force-pushed the bot/install-mount-default-entry branch from a221ae8 to b298c49 Compare September 29, 2026 16:08
@cgwalters-bot

Copy link
Copy Markdown
Collaborator Author

Opened upstream as bootc-dev#2515. Closing this review draft.

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