Skip to content

Commit f94ee90

Browse files
committed
blockdev: handle ZFS dataset sources in list_dev_by_dir
ZFS filesystems report their mount source as a dataset name (e.g. 'rpool/root') rather than a block device path. Passing this to lsblk causes it to fail with 'not a block device', breaking bootc status and bootc upgrade on ZFS-rooted systems. Add list_dev_for_zfs_dataset() which extracts the pool name and queries 'zpool list -H -v -P <pool>' to find the underlying block device path, then delegates to list_dev() as normal. Detect ZFS sources in list_dev_by_dir() via fstype=='zfs' or by a non-absolute path containing '/' (dataset name form). Fixes: #1240 Signed-off-by: James Reilly <jreilly1821@gmail.com>
1 parent b1fe5d6 commit f94ee90

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

crates/blockdev/src/blockdev.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,10 +382,39 @@ pub fn list_dev(dev: &Utf8Path) -> Result<Device> {
382382
.ok_or_else(|| anyhow!("no device output from lsblk for {dev}"))
383383
}
384384

385+
#[context("Finding block device for ZFS dataset {dataset}")]
386+
fn list_dev_for_zfs_dataset(dataset: &str) -> Result<Device> {
387+
let dataset = dataset.strip_prefix("ZFS=").unwrap_or(dataset);
388+
let pool = dataset
389+
.split('/')
390+
.next()
391+
.ok_or_else(|| anyhow!("Invalid ZFS dataset: {dataset}"))?;
392+
393+
let output = Command::new("zpool")
394+
.args(["list", "-H", "-v", "-P", pool])
395+
.run_get_string()
396+
.with_context(|| format!("Querying ZFS pool {pool}"))?;
397+
398+
for line in output.lines() {
399+
if line.starts_with('\t') || line.starts_with(' ') {
400+
let dev_path = line.trim_start().split('\t').next().unwrap_or("").trim();
401+
if dev_path.starts_with('/') {
402+
return list_dev(Utf8Path::new(dev_path));
403+
}
404+
}
405+
}
406+
407+
anyhow::bail!("Could not find a block device backing ZFS pool {pool}")
408+
}
409+
385410
/// List the device containing the filesystem mounted at the given directory.
386411
pub fn list_dev_by_dir(dir: &Dir) -> Result<Device> {
387412
let fsinfo = bootc_mount::inspect_filesystem_of_dir(dir)?;
388-
list_dev(&Utf8PathBuf::from(&fsinfo.source))
413+
let source = &fsinfo.source;
414+
if fsinfo.fstype == "zfs" || (!source.starts_with('/') && source.contains('/')) {
415+
return list_dev_for_zfs_dataset(source);
416+
}
417+
list_dev(&Utf8PathBuf::from(source))
389418
}
390419

391420
pub struct LoopbackDevice {

0 commit comments

Comments
 (0)