[pbs-devel] [PATCH proxmox-backup v9 06/26] datastore: add helper for checking if a removable datastore is available

Hannes Laimer h.laimer at proxmox.com
Thu Apr 25 08:05:27 CEST 2024


On Wed Apr 24, 2024 at 3:30 PM CEST, Wolfgang Bumiller wrote:
> On Tue, Apr 23, 2024 at 10:29:40AM +0200, Hannes Laimer wrote:
> > Signed-off-by: Hannes Laimer <h.laimer at proxmox.com>
> > ---
> >  pbs-api-types/src/maintenance.rs |  2 +-
> >  pbs-datastore/src/datastore.rs   | 44 ++++++++++++++++++++++++++++++++
> >  pbs-datastore/src/lib.rs         |  2 +-
> >  3 files changed, 46 insertions(+), 2 deletions(-)
> > 
> > diff --git a/pbs-api-types/src/maintenance.rs b/pbs-api-types/src/maintenance.rs
> > index fd4d3416..4f653ec7 100644
> > --- a/pbs-api-types/src/maintenance.rs
> > +++ b/pbs-api-types/src/maintenance.rs
> > @@ -81,7 +81,7 @@ impl MaintenanceMode {
> >      /// Used for deciding whether the datastore is cleared from the internal cache after the last
> >      /// task finishes, so all open files are closed.
> >      pub fn is_offline(&self) -> bool {
> > -        self.ty == MaintenanceType::Offline
> > +        self.ty == MaintenanceType::Offline || self.ty == MaintenanceType::Unmount
> >      }
> >  
> >      pub fn check(&self, operation: Option<Operation>) -> Result<(), Error> {
> > diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
> > index f9b986c1..978ebb70 100644
> > --- a/pbs-datastore/src/datastore.rs
> > +++ b/pbs-datastore/src/datastore.rs
> > @@ -14,6 +14,7 @@ use proxmox_schema::ApiType;
> >  use proxmox_sys::error::SysError;
> >  use proxmox_sys::fs::{file_read_optional_string, replace_file, CreateOptions};
> >  use proxmox_sys::fs::{lock_dir_noblock, DirLockGuard};
> > +use proxmox_sys::linux::procfs::MountInfo;
> >  use proxmox_sys::process_locker::ProcessLockSharedGuard;
> >  use proxmox_sys::WorkerTaskContext;
> >  use proxmox_sys::{task_log, task_warn};
> > @@ -49,6 +50,39 @@ pub fn check_backup_owner(owner: &Authid, auth_id: &Authid) -> Result<(), Error>
> >      Ok(())
> >  }
> >  
> > +/// check if a removable datastore is currently available/mounted by using the UUID
> > +/// to find the `/dev/sdX` path and checking in /proc/self/mountinfo for entries containing it.
> > +/// If it should mounted, but not in the expected path, so config.path, it is considered not
> > +/// available.
> > +pub fn is_datastore_available(config: &DataStoreConfig) -> bool {
> > +    config.backing_device.as_ref().map_or(true, |uuid| {
> > +        if let Ok(store_dev_path) = std::fs::read_link(Path::new("/dev/disk/by-uuid").join(uuid))
> > +            .map(|p| p.to_string_lossy().into_owned())
> > +            .map(|p| p.replace("../..", "/dev"))
>
> ^ Merge the two .maps together and you can drop the into_owned()
>
> Also, this is very fragile!
> `/proc/self/mountinfo` does NOT necessarily contain the final device
> node.
> For instance, for LVs you do NOT see `/dev/dm-xy`, but
> `/dev/mapper/foo-bar`.
>
> I pushed an alternative to my `staff` repo's
> `removable-datastore-review` branch which worked for my testing.
>
> There I instead `stat` the backing device and the source device found in
> the MountInfo and compare their `st_rdev` values.
>
This is a very good idea, and does sound more robust. But I don't think
we actually want to mount LVMs as removable datastores.

> > +            .map(PathBuf::from)
>
> ^ Not strictly needed
>
> > +        {
> > +            let store_mount_point = config.get_mount_point().map(|mp| PathBuf::from(&mp));
>
> ^ The loop below only ever returns true if this is Some, so we can leave
> early here if it is not.
>
> > +
> > +            MountInfo::read().map_or(false, |mount_info| {
> > +                mount_info
> > +                    .iter()
> > +                    .filter_map(|(_, entry)| {
> > +                        entry
> > +                            .mount_source
> > +                            .as_ref()
> > +                            .map(|source| (&entry.mount_point, source))
> > +                    })
> > +                    .any(|(mount_point, mount_source)| {
> > +                        Some(PathBuf::from(&mount_point)) == store_mount_point
> > +                            && PathBuf::from(&mount_source) == store_dev_path
>
> ^Note that you can always use `Path` instead of allocating PathBufs if
> all you want to do is comapre stuff.
>
> > +                    })
> > +            })
> > +        } else {
> > +            false
> > +        }
> > +    })
> > +}





More information about the pbs-devel mailing list