@@ -279,34 +279,48 @@ impl Device {
279279 }
280280 }
281281
282- /// Walk the parent chain to find the root (whole disk) device.
282+ /// Walk the parent chain to find all root (whole disk) devices,
283+ /// and fail if more than one root is found.
283284 ///
284- /// Returns the root device with its children (partitions) populated.
285- /// If this device is already a root device, returns a clone of `self`.
286- /// Fails if the device has multiple parents at any level.
287- pub fn root_disk ( & self ) -> Result < Device > {
285+ /// This is a convenience wrapper around `find_all_roots` for callers
286+ /// that expect exactly one backing device (e.g. non-RAID setups).
287+ pub fn require_single_root ( & self ) -> Result < Device > {
288+ let mut roots = self . find_all_roots ( ) ?;
289+ match roots. len ( ) {
290+ 1 => Ok ( roots. remove ( 0 ) ) ,
291+ n => anyhow:: bail!(
292+ "Expected a single root device for {}, but found {n}" ,
293+ self . path( )
294+ ) ,
295+ }
296+ }
297+
298+ /// Walk the parent chain to find all root (whole disk) devices.
299+ ///
300+ /// Returns all root devices with their children (partitions) populated.
301+ /// This handles devices backed by multiple parents (e.g. RAID arrays)
302+ /// by following all branches of the parent tree.
303+ /// If this device is already a root device, returns a single-element list.
304+ pub fn find_all_roots ( & self ) -> Result < Vec < Device > > {
288305 let Some ( parents) = self . list_parents ( ) ? else {
289306 // Already a root device; re-query to ensure children are populated
290- return list_dev ( Utf8Path :: new ( & self . path ( ) ) ) ;
307+ return Ok ( vec ! [ list_dev( Utf8Path :: new( & self . path( ) ) ) ? ] ) ;
291308 } ;
292- let mut current = parents;
293- loop {
294- anyhow:: ensure!(
295- current. len( ) == 1 ,
296- "Device {} has multiple parents; cannot determine root disk" ,
297- self . path( )
298- ) ;
299- let mut parent = current. into_iter ( ) . next ( ) . unwrap ( ) ;
300- match parent. children . take ( ) {
309+
310+ let mut roots = Vec :: new ( ) ;
311+ let mut queue = parents;
312+ while let Some ( mut device) = queue. pop ( ) {
313+ match device. children . take ( ) {
301314 Some ( grandparents) if !grandparents. is_empty ( ) => {
302- current = grandparents;
315+ queue . extend ( grandparents) ;
303316 }
304317 _ => {
305- // Found the root; re-query to populate its actual children
306- return list_dev ( Utf8Path :: new ( & parent . path ( ) ) ) ;
318+ // Found a root; re-query to populate its actual children
319+ roots . push ( list_dev ( Utf8Path :: new ( & device . path ( ) ) ) ? ) ;
307320 }
308321 }
309322 }
323+ Ok ( roots)
310324 }
311325}
312326
0 commit comments