From d669aa9afbdbeb8393b6acdbe0a659a7d1173646 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Wed, 18 Mar 2026 23:48:49 -0600 Subject: [PATCH] fix: retry BLKRRPART on busy device during OS install --- core/src/os_install/gpt.rs | 31 ++++++++++++++++++++++++++----- core/src/os_install/mbr.rs | 31 ++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/core/src/os_install/gpt.rs b/core/src/os_install/gpt.rs index 932538d98..9823f98d8 100644 --- a/core/src/os_install/gpt.rs +++ b/core/src/os_install/gpt.rs @@ -187,11 +187,32 @@ pub async fn partition( .invoke(crate::ErrorKind::DiskManagement) .await .ok(); - Command::new("blockdev") - .arg("--rereadpt") - .arg(&disk_path) - .invoke(crate::ErrorKind::DiskManagement) - .await?; + // BLKRRPART can fail with "Device or resource busy" if the kernel still + // holds references to old partitions. Retry a few times with a delay. + let mut last_err = None; + for attempt in 0..5u32 { + if attempt > 0 { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + } + match Command::new("blockdev") + .arg("--rereadpt") + .arg(&disk_path) + .invoke(crate::ErrorKind::DiskManagement) + .await + { + Ok(_) => { + last_err = None; + break; + } + Err(e) => { + tracing::warn!("blockdev --rereadpt attempt {} failed: {e}", attempt + 1); + last_err = Some(e); + } + } + } + if let Some(e) = last_err { + return Err(e); + } Command::new("udevadm") .arg("settle") .invoke(crate::ErrorKind::DiskManagement) diff --git a/core/src/os_install/mbr.rs b/core/src/os_install/mbr.rs index 090fa9554..3e9de57e8 100644 --- a/core/src/os_install/mbr.rs +++ b/core/src/os_install/mbr.rs @@ -153,11 +153,32 @@ pub async fn partition( .invoke(crate::ErrorKind::DiskManagement) .await .ok(); - Command::new("blockdev") - .arg("--rereadpt") - .arg(&disk_path) - .invoke(crate::ErrorKind::DiskManagement) - .await?; + // BLKRRPART can fail with "Device or resource busy" if the kernel still + // holds references to old partitions. Retry a few times with a delay. + let mut last_err = None; + for attempt in 0..5u32 { + if attempt > 0 { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + } + match Command::new("blockdev") + .arg("--rereadpt") + .arg(&disk_path) + .invoke(crate::ErrorKind::DiskManagement) + .await + { + Ok(_) => { + last_err = None; + break; + } + Err(e) => { + tracing::warn!("blockdev --rereadpt attempt {} failed: {e}", attempt + 1); + last_err = Some(e); + } + } + } + if let Some(e) = last_err { + return Err(e); + } Command::new("udevadm") .arg("settle") .invoke(crate::ErrorKind::DiskManagement)