Skip to content

Commit bbb28e0

Browse files
committed
install: Fix DPS support
This fixes bootc's use of the Discoverable Partition Specification (DPS) to properly support systemd-gpt-auto-generator. Previously, bootc was incorrectly setting filesystem UUIDs to the DPS partition type UUID value, which caused UUID collisions and prevented proper DPS functionality. It's still a TODO on our side to support systemd-repart in this flow. Note we go back to using random filesystem UUIDs with this, but per above we should likely reinitialize them on boot via repart. Note we remove root= parameter from kernel cmdline for composefs sealed images, allowing systemd-gpt-auto-generator to auto-discover the root partition and we test this. Fixes: #1771 Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters <[email protected]>
1 parent 71dc8e5 commit bbb28e0

File tree

7 files changed

+41
-13
lines changed

7 files changed

+41
-13
lines changed

Dockerfile.cfsuki

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ RUN --mount=type=secret,id=key \
2828
# Should be generated externally
2929
test -n "${COMPOSEFS_FSVERITY}"
3030

31-
# Inject the composefs kernel argument and specify a root with the x86_64 DPS UUID.
32-
# TODO: Discoverable partition fleshed out, or drop root UUID as systemd-stub extension
33-
# TODO: https://github.com/containers/composefs-rs/issues/183
34-
cmdline="composefs=${COMPOSEFS_FSVERITY} root=UUID=4f68bce3-e8cd-4db1-96e7-fbcaf984b709 console=ttyS0,115200n8 enforcing=0 rw"
31+
cmdline="composefs=${COMPOSEFS_FSVERITY} console=ttyS0,115200n8 enforcing=0 rw"
3532

3633
# pesign uses NSS database so create it from input cert/key
3734
mkdir pesign

crates/blockdev/src/blockdev.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub struct Device {
3737
// Filesystem-related properties
3838
pub label: Option<String>,
3939
pub fstype: Option<String>,
40+
pub uuid: Option<String>,
4041
pub path: Option<String>,
4142
}
4243

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ use crate::{
5151
BOOT_LOADER_ENTRIES, COMPOSEFS_CMDLINE, ORIGIN_KEY_BOOT, ORIGIN_KEY_BOOT_DIGEST,
5252
STAGED_BOOT_LOADER_ENTRIES, STATE_DIR_ABS, USER_CFG, USER_CFG_STAGED,
5353
},
54-
discoverable_partition_specification::this_arch_root,
5554
install::RW_KARG,
5655
spec::{Bootloader, Host},
5756
};
@@ -413,8 +412,7 @@ pub(crate) fn setup_composefs_bls_boot(
413412
Utf8PathBuf::from("/sysroot"),
414413
get_esp_partition(&sysroot_parent)?.0,
415414
Cmdline::from(format!(
416-
"root=UUID={} {RW_KARG} {COMPOSEFS_CMDLINE}={id_hex}",
417-
this_arch_root()
415+
"{RW_KARG} {COMPOSEFS_CMDLINE}={id_hex}"
418416
)),
419417
fs,
420418
bootloader,

crates/lib/src/install/baseline.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ pub(crate) const EFIPN_SIZE_MB: u32 = 512;
4141
/// We need more space than ostree as we have UKIs and UKI addons
4242
/// We might also need to store UKIs for pinned deployments
4343
pub(crate) const CFS_EFIPN_SIZE_MB: u32 = 1024;
44-
/// The GPT type for "linux"
45-
pub(crate) const LINUX_PARTTYPE: &str = "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
4644
#[cfg(feature = "install-to-disk")]
4745
pub(crate) const PREPBOOT_GUID: &str = "9E1A2D38-C612-4316-AA26-8B49521E5A8B";
4846
#[cfg(feature = "install-to-disk")]
@@ -113,7 +111,8 @@ fn mkfs<'a>(
113111
let devinfo = bootc_blockdev::list_dev(dev.into())?;
114112
let size = ostree_ext::glib::format_size(devinfo.size);
115113

116-
let u = uuid::Uuid::parse_str(crate::discoverable_partition_specification::this_arch_root())?;
114+
// Generate a random UUID for the filesystem
115+
let u = uuid::Uuid::new_v4();
117116

118117
let mut t = Task::new(
119118
&format!("Creating {label} filesystem ({fs}) on device {dev} (size={size})"),
@@ -315,9 +314,10 @@ pub(crate) fn install_create_rootfs(
315314
let root_size = root_size
316315
.map(|v| Cow::Owned(format!("size={v}MiB, ")))
317316
.unwrap_or_else(|| Cow::Borrowed(""));
317+
let rootpart_uuid = uuid::Uuid::parse_str(crate::discoverable_partition_specification::this_arch_root())?;
318318
writeln!(
319319
&mut partitioning_buf,
320-
r#"{root_size}type={LINUX_PARTTYPE}, name="root""#
320+
r#"{root_size}type={rootpart_uuid}, name="root""#
321321
)?;
322322
tracing::debug!("Partitioning: {partitioning_buf}");
323323
Task::new("Initializing partitions", "sfdisk")
@@ -336,9 +336,11 @@ pub(crate) fn install_create_rootfs(
336336
let base_partitions = &bootc_blockdev::partitions_of(&devpath)?;
337337

338338
let root_partition = base_partitions.find_partno(rootpn)?;
339-
if root_partition.parttype.as_str() != LINUX_PARTTYPE {
339+
// Verify the partition type matches the DPS root partition type for this architecture
340+
let expected_parttype = crate::discoverable_partition_specification::this_arch_root();
341+
if !root_partition.parttype.eq_ignore_ascii_case(expected_parttype) {
340342
anyhow::bail!(
341-
"root partition {partno} has type {}; expected {LINUX_PARTTYPE}",
343+
"root partition {rootpn} has type {}; expected {expected_parttype}",
342344
root_partition.parttype.as_str()
343345
);
344346
}

crates/tests-integration/src/composefs_bcvk.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ fn inner_tests() -> Vec<Trial> {
8080

8181
assert_eq!(verity_from_status.unwrap(), verity_from_cmdline);
8282

83+
// Verify that we booted via systemd-gpt-auto-generator by checking
84+
// that /proc/cmdline does NOT contain a root= parameter
85+
let has_root_param = cmdline.iter().any(|entry| {
86+
entry.key() == "root".into()
87+
});
88+
assert!(!has_root_param, "Sealed composefs image should not have root= in kernel cmdline; systemd-gpt-auto-generator should discover the root partition via DPS");
89+
8390
Ok(())
8491
})]
8592
.into_iter()

docs/src/man/bootc-install-to-disk.8.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@ the container image, alongside any required system partitions such as
1919
the EFI system partition. Use `install to-filesystem` for anything
2020
more complex such as RAID, LVM, LUKS etc.
2121

22+
## Partitioning details
23+
24+
The default as of bootc 1.11 uses the [Discoverable Partitions Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/)
25+
for the generated root filesystem, as well as any required system partitions
26+
such as the EFI system partition.
27+
28+
Note that by default when used with "type 1" bootloader setups (i.e. non-UKI)
29+
a kernel argument `root=UUID=<uuid of filesystem>` is injected by default.
30+
31+
When used with the composefs backend and UKIs, it's recommended that
32+
a bootloader implementing the DPS specification is used and that the root
33+
partition is auto-discovered.
34+
2235
# OPTIONS
2336

2437
<!-- BEGIN GENERATED OPTIONS -->

tmt/tests/booted/readonly/030-test-composefs.nu

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ let is_composefs = ($st.status.booted.composefs? != null)
99
let expecting_composefs = ($env.BOOTC_variant? | default "" | find "composefs") != null
1010
if $expecting_composefs {
1111
assert $is_composefs
12+
# When using systemd-boot with DPS (Discoverable Partition Specification),
13+
# /proc/cmdline should NOT contain a root= parameter because systemd-gpt-auto-generator
14+
# discovers the root partition automatically
15+
# Note that there is `bootctl --json=pretty` but it doesn't actually output JSON
16+
let bootctl_output = (bootctl)
17+
if ($bootctl_output | str contains 'Product: systemd-boot') {
18+
let cmdline = (open /proc/cmdline)
19+
let has_root_param = ($cmdline | str contains "root=")
20+
assert (not $has_root_param) "systemd-boot image should not have root= in kernel cmdline; systemd-gpt-auto-generator should discover the root partition via DPS"
21+
}
1222
}
1323

1424
if $is_composefs {

0 commit comments

Comments
 (0)