From d9b318a444db599ba3c526e580da4970666b0aab Mon Sep 17 00:00:00 2001 From: Stefan Reiter Date: Wed, 16 Jun 2021 12:55:52 +0200 Subject: [PATCH] file-restore/disk: support ZFS subvols with mountpoint=legacy These require mounting using the regular 'mount' syscall. Auto-generates an appropriate mount path. Note that subvols with mountpoint=none cannot be mounted this way, and would require setting the mountpoint property, which is not possible as the zpools have to be imported with readonly=on. Signed-off-by: Stefan Reiter --- src/bin/proxmox_restore_daemon/disk.rs | 43 ++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/bin/proxmox_restore_daemon/disk.rs b/src/bin/proxmox_restore_daemon/disk.rs index 5b66dd2f..9d0cbe32 100644 --- a/src/bin/proxmox_restore_daemon/disk.rs +++ b/src/bin/proxmox_restore_daemon/disk.rs @@ -228,6 +228,34 @@ impl Filesystems { cmd.args(["mount", "-a"].iter()); run_command(cmd, None)?; + // detect any datasets with 'legacy' mountpoints + let mut cmd = Command::new("/sbin/zfs"); + cmd.args(["list", "-Hpro", "name,mountpoint", &data.name].iter()); + let mps = run_command(cmd, None)?; + for subvol in mps.lines() { + let subvol = subvol.splitn(2, '\t').collect::>(); + if subvol.len() != 2 { + continue; + } + let name = subvol[0]; + let mp = subvol[1]; + + if mp == "legacy" { + let mut newmp = PathBuf::from(format!( + "{}/legacy-{}", + &mntpath, + name.replace('/', "_") + )); + let mut i = 1; + while newmp.exists() { + newmp.set_extension(i.to_string()); + i += 1; + } + create_dir_all(&newmp)?; + self.do_mount(Some(name), newmp.to_string_lossy().as_ref(), "zfs")?; + } + } + // Now that we have imported the pool, we can also query the size let mut cmd = Command::new("/sbin/zpool"); cmd.args(["list", "-o", "size", "-Hp", &data.name].iter()); @@ -244,19 +272,14 @@ impl Filesystems { } fn try_mount(&self, source: &str, target: &str) -> Result<(), Error> { - use nix::mount::*; - create_dir_all(target)?; // try all supported fs until one works - this is the way Busybox's 'mount' does it too: // https://git.busybox.net/busybox/tree/util-linux/mount.c?id=808d93c0eca49e0b22056e23d965f0d967433fbb#n2152 // note that ZFS is intentionally left out (see scan()) - let flags = - MsFlags::MS_RDONLY | MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID | MsFlags::MS_NODEV; for fs in &self.supported_fs { let fs: &str = fs.as_ref(); - let opts = FS_OPT_MAP.get(fs).copied(); - match mount(Some(source), target, Some(fs), flags, opts) { + match self.do_mount(Some(source), target, fs) { Ok(()) => { info!("mounting '{}' succeeded, fstype: '{}'", source, fs); return Ok(()); @@ -270,6 +293,14 @@ impl Filesystems { bail!("all mounts failed or no supported file system") } + + fn do_mount(&self, source: Option<&str>, target: &str, fs: &str) -> Result<(), nix::Error> { + use nix::mount::*; + let flags = + MsFlags::MS_RDONLY | MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID | MsFlags::MS_NODEV; + let opts = FS_OPT_MAP.get(fs).copied(); + mount(source, target, Some(fs), flags, opts) + } } pub struct DiskState {