Source version analyzed: bootc v1.16.7
Tested operating system: Fedora 44 (aarch64, UEFI, GRUB)
Summary
A native-composefs installation with a separate boot filesystem mounts that
filesystem read-only at /boot, but bootc's composefs runtime code expects the
same filesystem at /sysroot/boot. Nothing mounts it there. As a result, bootc
reads the underlying physical root's stale installation-time /boot directory
instead of the real boot filesystem.
This causes bootc status and consumers that call it, including DNF, to fail
while looking for BLS entries. The same path is used by composefs upgrade,
rollback, finalization, deletion, and garbage-collection code.
Installation scenario
The system was installed using bootc install to-filesystem with the native
composefs backend, GRUB, a Btrfs root filesystem, a separate ext4 boot
filesystem, and a VFAT EFI System Partition. The relevant arguments included:
--composefs-backend
--bootloader=grub
--root-mount-spec=/dev/disk/by-label/root
--boot-mount-spec=UUID=<boot-filesystem-uuid>
After boot, the mount topology was:
$ findmnt /sysroot
TARGET SOURCE FSTYPE OPTIONS
/sysroot /dev/mapper/root[/root] btrfs ro,noatime,seclabel,compress=zstd:3,...
$ findmnt /boot
TARGET SOURCE FSTYPE OPTIONS
/boot /dev/nvme0n1p2 ext4 ro,relatime,seclabel
$ findmnt /sysroot/boot
# no result
$ findmnt /boot/efi
# no result
/sysroot/boot existed as an ordinary directory containing remnants from the
installation process, but it was not the separate boot filesystem.
Failure
bootc status failed while attempting to read BLS entries from the wrong
directory:
error: Status: Prepending custom prefix to EFI and BLS entries: Getting sorted Type1 boot entries: No such file or directory (os error 2)
This also prevented dnf update from proceeding because its bootc status check
returned the same error. SELinux audit messages printed around the command were
unrelated; this was a missing mount/path problem, not a labeling denial.
Source analysis
The install and runtime paths disagree:
- In
crates/lib/src/install.rs, a non-empty --boot-mount-spec becomes a
MountSpec targeting /boot and is forced read-only.
- In
crates/lib/src/bootc_composefs/boot.rs,
setup_composefs_bls_boot() converts that spec into a kernel argument of the
form systemd.mount-extra=<source>:/boot:<fstype>:<options>.
- In
crates/lib/src/store/mod.rs, BootedStorage::new() handles a
composefs/GRUB system by opening boot relative to the physical root. On a
running system that physical root is /sysroot, so the resulting boot
directory is /sysroot/boot.
Storage::bls_boot_binaries_dir() explicitly documents /sysroot/boot as
the GRUB Type 1 boot-binary location. The status and composefs lifecycle code
then reads loader/entries relative to that directory.
Remounting /sysroot read-write in bootc's private mount namespace does not
solve this. A filesystem mounted at /boot is not thereby also mounted at
/sysroot/boot.
The ESP is discovered and temporarily mounted by some bootc operations, but
the installed system also lacked the conventional persistent /boot/efi
mount. That leaves bootloader tooling outside those narrowly scoped bootc
operations without the expected ESP path.
Demonstrated workaround
Installing the following native systemd mount topology fixes the failure:
- Mount the boot filesystem by UUID read-write at
/sysroot/boot.
- Bind-mount
/sysroot/boot read-only at /boot.
- Mount the ESP by UUID read-write at
/boot/efi.
In unit terms, the essential relationships are:
# sysroot-boot.mount
[Mount]
What=/dev/disk/by-uuid/<boot-filesystem-uuid>
Where=/sysroot/boot
Type=ext4
Options=rw
# boot.mount
[Mount]
What=/sysroot/boot
Where=/boot
Type=none
Options=bind,ro
# boot-efi.mount
[Mount]
What=/dev/disk/by-uuid/<esp-filesystem-uuid>
Where=/boot/efi
Type=vfat
Options=rw,fmask=0177,dmask=0077
With these units active, /sysroot/boot is the writable authoritative boot
filesystem expected by bootc, /boot remains protected from ordinary package
manager writes, and the ESP is available at its conventional path.
Expected behavior
bootc install to-filesystem --composefs-backend should leave a separate boot
filesystem in a runtime mount arrangement consistent with bootc's own
composefs storage API. At minimum, a successful installation using
--boot-mount-spec should allow bootc status, upgrade, rollback, staged
finalization, and garbage collection to access the actual BLS entries.
Possible fixes include:
- Have native-composefs installation generate the persistent systemd mount
topology above, including appropriate ordering and UUID references.
- Or change the composefs runtime implementation to operate consistently on
the existing /boot mount, remounting or cloning it privately when writes
are required, and audit every caller that currently assumes
/sysroot/boot.
A regression test should install native composefs with a separate boot
filesystem, boot it, verify both the public read-only and private physical boot
paths, and exercise bootc status plus a staged upgrade.
AI assistance: OpenAI Codex (GPT-5) helped analyze the observed mount state,
review the bootc v1.16.7 source, and draft this report.
Source version analyzed: bootc v1.16.7
Tested operating system: Fedora 44 (aarch64, UEFI, GRUB)
Summary
A native-composefs installation with a separate boot filesystem mounts that
filesystem read-only at
/boot, but bootc's composefs runtime code expects thesame filesystem at
/sysroot/boot. Nothing mounts it there. As a result, bootcreads the underlying physical root's stale installation-time
/bootdirectoryinstead of the real boot filesystem.
This causes
bootc statusand consumers that call it, including DNF, to failwhile looking for BLS entries. The same path is used by composefs upgrade,
rollback, finalization, deletion, and garbage-collection code.
Installation scenario
The system was installed using
bootc install to-filesystemwith the nativecomposefs backend, GRUB, a Btrfs root filesystem, a separate ext4 boot
filesystem, and a VFAT EFI System Partition. The relevant arguments included:
After boot, the mount topology was:
/sysroot/bootexisted as an ordinary directory containing remnants from theinstallation process, but it was not the separate boot filesystem.
Failure
bootc statusfailed while attempting to read BLS entries from the wrongdirectory:
This also prevented
dnf updatefrom proceeding because its bootc status checkreturned the same error. SELinux audit messages printed around the command were
unrelated; this was a missing mount/path problem, not a labeling denial.
Source analysis
The install and runtime paths disagree:
crates/lib/src/install.rs, a non-empty--boot-mount-specbecomes aMountSpectargeting/bootand is forced read-only.crates/lib/src/bootc_composefs/boot.rs,setup_composefs_bls_boot()converts that spec into a kernel argument of theform
systemd.mount-extra=<source>:/boot:<fstype>:<options>.crates/lib/src/store/mod.rs,BootedStorage::new()handles acomposefs/GRUB system by opening
bootrelative to the physical root. On arunning system that physical root is
/sysroot, so the resulting bootdirectory is
/sysroot/boot.Storage::bls_boot_binaries_dir()explicitly documents/sysroot/bootasthe GRUB Type 1 boot-binary location. The status and composefs lifecycle code
then reads
loader/entriesrelative to that directory.Remounting
/sysrootread-write in bootc's private mount namespace does notsolve this. A filesystem mounted at
/bootis not thereby also mounted at/sysroot/boot.The ESP is discovered and temporarily mounted by some bootc operations, but
the installed system also lacked the conventional persistent
/boot/efimount. That leaves bootloader tooling outside those narrowly scoped bootc
operations without the expected ESP path.
Demonstrated workaround
Installing the following native systemd mount topology fixes the failure:
/sysroot/boot./sysroot/bootread-only at/boot./boot/efi.In unit terms, the essential relationships are:
With these units active,
/sysroot/bootis the writable authoritative bootfilesystem expected by bootc,
/bootremains protected from ordinary packagemanager writes, and the ESP is available at its conventional path.
Expected behavior
bootc install to-filesystem --composefs-backendshould leave a separate bootfilesystem in a runtime mount arrangement consistent with bootc's own
composefs storage API. At minimum, a successful installation using
--boot-mount-specshould allowbootc status, upgrade, rollback, stagedfinalization, and garbage collection to access the actual BLS entries.
Possible fixes include:
topology above, including appropriate ordering and UUID references.
the existing
/bootmount, remounting or cloning it privately when writesare required, and audit every caller that currently assumes
/sysroot/boot.A regression test should install native composefs with a separate boot
filesystem, boot it, verify both the public read-only and private physical boot
paths, and exercise
bootc statusplus a staged upgrade.AI assistance: OpenAI Codex (GPT-5) helped analyze the observed mount state,
review the bootc v1.16.7 source, and draft this report.