From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 432CF1FF189 for ; Fri, 22 Nov 2024 15:47:51 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 5667215A44; Fri, 22 Nov 2024 15:47:54 +0100 (CET) From: Hannes Laimer To: pbs-devel@lists.proxmox.com Date: Fri, 22 Nov 2024 15:46:51 +0100 Message-Id: <20241122144713.299130-5-h.laimer@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241122144713.299130-1-h.laimer@proxmox.com> References: <20241122144713.299130-1-h.laimer@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.024 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [PATCH proxmox-backup v14 04/25] datastore: add helper for checking if a datastore is mounted X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox Backup Server development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pbs-devel-bounces@lists.proxmox.com Sender: "pbs-devel" ... 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 Signed-off-by: Hannes Laimer --- 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/` 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/ +/// - /dev/disk/by-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 { + 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, 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) { 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