all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Hannes Laimer <h.laimer@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup v14 04/25] datastore: add helper for checking if a datastore is mounted
Date: Fri, 22 Nov 2024 15:46:51 +0100	[thread overview]
Message-ID: <20241122144713.299130-5-h.laimer@proxmox.com> (raw)
In-Reply-To: <20241122144713.299130-1-h.laimer@proxmox.com>

... at a specific location. Also adds two additional functions to
get the mount status, and ensuring a removable datastore is mounted.

Co-authored-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Signed-off-by: Hannes Laimer <h.laimer@proxmox.com>
---
change since v13:
 * add two helpers to not have to have the same code in a amount a
    million places

 pbs-datastore/src/datastore.rs      | 74 +++++++++++++++++++++++++++++
 pbs-datastore/src/lib.rs            |  4 +-
 src/server/metric_collection/mod.rs |  4 ++
 3 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 2bf2b8437..6a9fc2dc0 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -1,5 +1,6 @@
 use std::collections::{HashMap, HashSet};
 use std::io::{self, Write};
+use std::os::unix::ffi::OsStrExt;
 use std::os::unix::io::AsRawFd;
 use std::path::{Path, PathBuf};
 use std::sync::{Arc, LazyLock, Mutex};
@@ -14,6 +15,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_worker_task::WorkerTaskContext;
 
@@ -46,6 +48,70 @@ pub fn check_backup_owner(owner: &Authid, auth_id: &Authid) -> Result<(), Error>
     Ok(())
 }
 
+/// Check if a device with a given UUID is currently mounted at store_mount_point by
+/// comparing the `st_rdev` values of `/dev/disk/by-uuid/<uuid>` and the source device in
+/// /proc/self/mountinfo.
+///
+/// If we can't check if it is mounted, we treat that as not mounted,
+/// returning false.
+///
+/// Reasons it could fail other than not being mounted where expected:
+///  - could not read /proc/self/mountinfo
+///  - could not stat /dev/disk/by-uuid/<uuid>
+///  - /dev/disk/by-uuid/<uuid> is not a block device
+///
+/// Since these are very much out of our control, there is no real value in distinguishing
+/// between them, so for this function they all are treated as 'device not mounted'
+fn is_datastore_mounted_at(store_mount_point: String, device_uuid: &str) -> bool {
+    use nix::sys::stat::SFlag;
+
+    let store_mount_point = Path::new(&store_mount_point);
+
+    let dev_node = match nix::sys::stat::stat(format!("/dev/disk/by-uuid/{device_uuid}").as_str()) {
+        Ok(stat) if SFlag::from_bits_truncate(stat.st_mode) == SFlag::S_IFBLK => stat.st_rdev,
+        _ => return false,
+    };
+
+    let Ok(mount_info) = MountInfo::read() else {
+        return false;
+    };
+
+    for (_, entry) in mount_info {
+        let Some(source) = entry.mount_source else {
+            continue;
+        };
+
+        if entry.mount_point != store_mount_point || !source.as_bytes().starts_with(b"/") {
+            continue;
+        }
+
+        if let Ok(stat) = nix::sys::stat::stat(source.as_os_str()) {
+            let sflag = SFlag::from_bits_truncate(stat.st_mode);
+
+            if sflag == SFlag::S_IFBLK && stat.st_rdev == dev_node {
+                return true;
+            }
+        }
+    }
+
+    false
+}
+
+pub fn get_datastore_mount_status(config: &DataStoreConfig) -> Option<bool> {
+    let Some(ref device_uuid) = config.backing_device else {
+        return None;
+    };
+    Some(is_datastore_mounted_at(config.absolute_path(), device_uuid))
+}
+
+pub fn ensure_datastore_is_mounted(config: &DataStoreConfig) -> Result<(), Error> {
+    match get_datastore_mount_status(config) {
+        Some(true) => Ok(()),
+        Some(false) => Err(format_err!("Datastore '{}' is not mounted", config.name)),
+        None => Ok(()),
+    }
+}
+
 /// Datastore Management
 ///
 /// A Datastore can store severals backups, and provides the
@@ -156,6 +222,12 @@ impl DataStore {
             }
         }
 
+        if get_datastore_mount_status(&config) == Some(false) {
+            let mut datastore_cache = DATASTORE_MAP.lock().unwrap();
+            datastore_cache.remove(&config.name);
+            bail!("datastore '{}' is not mounted", config.name);
+        }
+
         let mut datastore_cache = DATASTORE_MAP.lock().unwrap();
         let entry = datastore_cache.get(name);
 
@@ -259,6 +331,8 @@ impl DataStore {
     ) -> Result<Arc<Self>, Error> {
         let name = config.name.clone();
 
+        ensure_datastore_is_mounted(&config)?;
+
         let tuning: DatastoreTuning = serde_json::from_value(
             DatastoreTuning::API_SCHEMA
                 .parse_property_string(config.tuning.as_deref().unwrap_or(""))?,
diff --git a/pbs-datastore/src/lib.rs b/pbs-datastore/src/lib.rs
index 8050cf4d0..5014b6c09 100644
--- a/pbs-datastore/src/lib.rs
+++ b/pbs-datastore/src/lib.rs
@@ -201,7 +201,9 @@ pub use manifest::BackupManifest;
 pub use store_progress::StoreProgress;
 
 mod datastore;
-pub use datastore::{check_backup_owner, DataStore};
+pub use datastore::{
+    check_backup_owner, ensure_datastore_is_mounted, get_datastore_mount_status, DataStore,
+};
 
 mod hierarchy;
 pub use hierarchy::{
diff --git a/src/server/metric_collection/mod.rs b/src/server/metric_collection/mod.rs
index b95dba203..2ede8408f 100644
--- a/src/server/metric_collection/mod.rs
+++ b/src/server/metric_collection/mod.rs
@@ -176,6 +176,10 @@ fn collect_disk_stats_sync() -> (DiskStat, Vec<DiskStat>) {
                     continue;
                 }
 
+                if pbs_datastore::get_datastore_mount_status(&config) == Some(false) {
+                    continue;
+                }
+
                 datastores.push(gather_disk_stats(
                     disk_manager.clone(),
                     Path::new(&config.absolute_path()),
-- 
2.39.5



_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel


  parent reply	other threads:[~2024-11-22 14:47 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-11-22 14:46 [pbs-devel] [PATCH proxmox-backup v14 00/26] add removable datastores Hannes Laimer
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 01/25] pbs-api-types: add backing-device to DataStoreConfig Hannes Laimer
2024-11-25 13:40   ` Fabian Grünbichler
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 02/25] maintenance: make is_offline more generic Hannes Laimer
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 03/26] maintenance: add 'Unmount' maintenance type Hannes Laimer
2024-11-22 14:46 ` Hannes Laimer [this message]
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 05/25] api: admin: add (un)mount endpoint for removable datastores Hannes Laimer
2024-11-25 13:24   ` Fabian Grünbichler
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 06/25] api: removable datastore creation Hannes Laimer
2024-11-25 13:40   ` Fabian Grünbichler
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 07/25] api: add check for nested datastores on creation Hannes Laimer
2024-11-25 13:44   ` Fabian Grünbichler
2024-11-25 14:48     ` Hannes Laimer
2024-11-25 14:53       ` Fabian Grünbichler
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 08/25] pbs-api-types: add mount_status field to DataStoreListItem Hannes Laimer
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 09/26] bin: manager: add (un)mount command Hannes Laimer
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 10/25] add auto-mounting for removable datastores Hannes Laimer
2024-11-25 13:47   ` Fabian Grünbichler
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 11/25] datastore: handle deletion of removable datastore properly Hannes Laimer
2024-11-22 14:46 ` [pbs-devel] [PATCH proxmox-backup v14 12/25] docs: add removable datastores section Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 13/26] ui: add partition selector form Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 14/26] ui: add removable datastore creation support Hannes Laimer
2024-11-25 12:44   ` Dominik Csapak
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 15/26] ui: add (un)mount button to summary Hannes Laimer
2024-11-25 13:00   ` Dominik Csapak
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 16/26] ui: tree: render unmounted datastores correctly Hannes Laimer
2024-11-25  8:47   ` [pbs-devel] [PATCH proxmox-backup v14] fixup! " Hannes Laimer
2024-11-25 13:06     ` Dominik Csapak
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 17/26] ui: utils: make parseMaintenanceMode more robust Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 18/26] ui: add datastore status mask for unmounted removable datastores Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 19/26] ui: maintenance: fix disable msg field if no type is selected Hannes Laimer
2024-11-25 13:23   ` Dominik Csapak
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 20/26] ui: render 'unmount' maintenance mode correctly Hannes Laimer
2024-11-25 13:24   ` Dominik Csapak
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 21/25] api: node: allow creation of removable datastore through directory endpoint Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 22/25] api: node: include removable datastores in directory list Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 23/26] node: disks: replace BASE_MOUNT_DIR with DATASTORE_MOUNT_DIR Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 24/26] ui: support create removable datastore through directory creation Hannes Laimer
2024-11-25 13:28   ` Dominik Csapak
2024-11-25 16:21     ` Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 25/26] bin: debug: add inspect device command Hannes Laimer
2024-11-22 14:47 ` [pbs-devel] [PATCH proxmox-backup v14 26/26] api: disks: only return UUID of partitions if it actually is one Hannes Laimer
2024-11-25  6:19 ` [pbs-devel] [PATCH proxmox-backup v14 00/26] add removable datastores Hannes Laimer
2024-11-25 13:15 ` Lukas Wagner
2024-11-25 13:32   ` Dominik Csapak

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241122144713.299130-5-h.laimer@proxmox.com \
    --to=h.laimer@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal