From e96362d08b1156d759b0bb5506fffca989ce5aac Mon Sep 17 00:00:00 2001 From: ckyrouac Date: Thu, 12 Feb 2026 09:04:07 -0500 Subject: [PATCH 1/2] install: Mirror /run/udev into the install container Without access to udev state, lsblk may fail during install-to-disk operations. See https://github.com/bootc-dev/bootc/pull/688 Assisted-by: Claude Code (claude-opus-4-5-20251101) Signed-off-by: ckyrouac --- crates/lib/src/install.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/lib/src/install.rs b/crates/lib/src/install.rs index a056d03b7..ce7c513ea 100644 --- a/crates/lib/src/install.rs +++ b/crates/lib/src/install.rs @@ -1598,6 +1598,9 @@ async fn prepare_install( // In some cases we may create large files, and it's better not to have those // in our overlayfs. bootc_mount::ensure_mirrored_host_mount("/var/tmp")?; + // udev state is required for running lsblk during install to-disk + // see https://github.com/bootc-dev/bootc/pull/688 + bootc_mount::ensure_mirrored_host_mount("/run/udev")?; // We also always want /tmp to be a proper tmpfs on general principle. setup_tmp_mount()?; // Allocate a temporary directory we can use in various places to avoid From d18f6014d6ec61649f08729039921c108a7e82c8 Mon Sep 17 00:00:00 2001 From: ckyrouac Date: Thu, 12 Feb 2026 09:25:22 -0500 Subject: [PATCH 2/2] blockdev: Backfill partition number from sysfs for older lsblk The "partn" column was added in util-linux 2.39, which is newer than what CentOS 9 / RHEL 9 ship (2.37). Read the partition number from sysfs when lsblk doesn't provide it. This is done by refactoring the existing backfill function into a more generic one used to backfill both start and partn. Assisted-by: Claude Code (claude-opus-4-5-20251101) Signed-off-by: ckyrouac --- crates/blockdev/src/blockdev.rs | 51 ++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/crates/blockdev/src/blockdev.rs b/crates/blockdev/src/blockdev.rs index a12527a94..1024cd2f5 100644 --- a/crates/blockdev/src/blockdev.rs +++ b/crates/blockdev/src/blockdev.rs @@ -33,6 +33,8 @@ pub struct Device { pub partlabel: Option, pub parttype: Option, pub partuuid: Option, + /// Partition number (1-indexed). None for whole disk devices. + pub partn: Option, pub children: Option>, pub size: u64, #[serde(rename = "maj:min")] @@ -60,33 +62,42 @@ impl Device { self.children.as_ref().is_some_and(|v| !v.is_empty()) } - // The "start" parameter was only added in a version of util-linux that's only - // in Fedora 40 as of this writing. - fn backfill_start(&mut self) -> Result<()> { + /// Read a sysfs property for this device and parse it as the target type. + fn read_sysfs_property(&self, property: &str) -> Result> + where + T: std::str::FromStr, + T::Err: std::error::Error + Send + Sync + 'static, + { let Some(majmin) = self.maj_min.as_deref() else { - // This shouldn't happen - return Ok(()); + return Ok(None); }; - let sysfs_start_path = format!("/sys/dev/block/{majmin}/start"); - if Utf8Path::new(&sysfs_start_path).try_exists()? { - let start = std::fs::read_to_string(&sysfs_start_path) - .with_context(|| format!("Reading {sysfs_start_path}"))?; - tracing::debug!("backfilled start to {start}"); - self.start = Some( - start - .trim() - .parse() - .context("Parsing sysfs start property")?, - ); + let sysfs_path = format!("/sys/dev/block/{majmin}/{property}"); + if !Utf8Path::new(&sysfs_path).try_exists()? { + return Ok(None); } - Ok(()) + let value = std::fs::read_to_string(&sysfs_path) + .with_context(|| format!("Reading {sysfs_path}"))?; + let parsed = value + .trim() + .parse() + .with_context(|| format!("Parsing sysfs {property} property"))?; + tracing::debug!("backfilled {property} to {value}"); + Ok(Some(parsed)) } /// Older versions of util-linux may be missing some properties. Backfill them if they're missing. pub fn backfill_missing(&mut self) -> Result<()> { - // Add new properties to backfill here - self.backfill_start()?; - // And recurse to child devices + // The "start" parameter was only added in a version of util-linux that's only + // in Fedora 40 as of this writing. + if self.start.is_none() { + self.start = self.read_sysfs_property("start")?; + } + // The "partn" column was added in util-linux 2.39, which is newer than + // what CentOS 9 / RHEL 9 ship (2.37). Note: sysfs uses "partition" not "partn". + if self.partn.is_none() { + self.partn = self.read_sysfs_property("partition")?; + } + // Recurse to child devices for child in self.children.iter_mut().flatten() { child.backfill_missing()?; }