Walk the parent chain to find all root (whole disk) devices. Returns all root devices with their children (partitions) populated. This handles devices backed by multiple parents (e.g. RAID arrays) by following all branches of the parent tree. If this device is already a root device, returns a single-element list.
(&self)
| 425 | /// by following all branches of the parent tree. |
| 426 | /// If this device is already a root device, returns a single-element list. |
| 427 | pub fn find_all_roots(&self) -> Result<Vec<Device>> { |
| 428 | let Some(parents) = self.list_parents()? else { |
| 429 | // Already a root device; re-query to ensure children are populated |
| 430 | return Ok(vec![list_dev(Utf8Path::new(&self.path()))?]); |
| 431 | }; |
| 432 | |
| 433 | let mut roots = Vec::new(); |
| 434 | let mut seen = HashSet::new(); |
| 435 | let mut queue = parents; |
| 436 | while let Some(mut device) = queue.pop() { |
| 437 | match device.children.take() { |
| 438 | Some(grandparents) if !grandparents.is_empty() => { |
| 439 | queue.extend(grandparents); |
| 440 | } |
| 441 | _ => { |
| 442 | // Deduplicate: in complex topologies (e.g. multipath) |
| 443 | // multiple branches can converge on the same physical disk. |
| 444 | let name = device.name.clone(); |
| 445 | if seen.insert(name) { |
| 446 | // Found a new root; re-query to populate its actual children |
| 447 | roots.push(list_dev(Utf8Path::new(&device.path()))?); |
| 448 | } |
| 449 | } |
| 450 | } |
| 451 | } |
| 452 | Ok(roots) |
| 453 | } |
| 454 | } |
| 455 | |
| 456 | #[context("Listing device {dev}")] |
no test coverage detected