[pbs-devel] [PATCH proxmox-backup v4 08/22] api2: disks list: add exclude-used flag

Hannes Laimer h.laimer at proxmox.com
Tue Apr 16 17:24:02 CEST 2024


... used by the partition selector for removable datastore creation.

Signed-off-by: Hannes Laimer <h.laimer at proxmox.com>
---
 src/api2/node/disks/mod.rs |  8 +++++
 src/tools/disks/mod.rs     | 62 ++++++++++++++++++++++++++++++++------
 2 files changed, 61 insertions(+), 9 deletions(-)

diff --git a/src/api2/node/disks/mod.rs b/src/api2/node/disks/mod.rs
index 711dae7b..f63bbd9b 100644
--- a/src/api2/node/disks/mod.rs
+++ b/src/api2/node/disks/mod.rs
@@ -41,6 +41,12 @@ pub mod zfs;
                 optional: true,
                 default: false,
             },
+            "exclude-used": {
+                description: "Exclude partitions already used for removable datastores or mounted directories.",
+                type: bool,
+                optional: true,
+                default: false,
+            },
             "usage-type": {
                 type: DiskUsageType,
                 optional: true,
@@ -62,6 +68,7 @@ pub mod zfs;
 pub fn list_disks(
     skipsmart: bool,
     include_partitions: bool,
+    exclude_used: bool,
     usage_type: Option<DiskUsageType>,
 ) -> Result<Vec<DiskUsageInfo>, Error> {
     let mut list = Vec::new();
@@ -69,6 +76,7 @@ pub fn list_disks(
     for (_, info) in DiskUsageQuery::new()
         .smart(!skipsmart)
         .partitions(include_partitions)
+        .exclude_used(exclude_used)
         .query()?
     {
         if let Some(ref usage_type) = usage_type {
diff --git a/src/tools/disks/mod.rs b/src/tools/disks/mod.rs
index eaf016df..d27f5086 100644
--- a/src/tools/disks/mod.rs
+++ b/src/tools/disks/mod.rs
@@ -20,6 +20,7 @@ use proxmox_rest_server::WorkerTask;
 use proxmox_schema::api;
 use proxmox_sys::linux::procfs::{mountinfo::Device, MountInfo};
 use proxmox_sys::task_log;
+use serde_json::Value;
 
 use pbs_api_types::{BLOCKDEVICE_DISK_AND_PARTITION_NAME_REGEX, BLOCKDEVICE_NAME_REGEX};
 
@@ -32,6 +33,7 @@ pub use zpool_list::*;
 mod lvm;
 pub use lvm::*;
 mod smart;
+use crate::api2::node::disks::directory::list_datastore_mounts;
 pub use smart::*;
 
 lazy_static::lazy_static! {
@@ -828,6 +830,7 @@ fn scan_partitions(
 pub struct DiskUsageQuery {
     smart: bool,
     partitions: bool,
+    exclude_used: bool,
 }
 
 impl DiskUsageQuery {
@@ -835,6 +838,7 @@ impl DiskUsageQuery {
         Self {
             smart: true,
             partitions: false,
+            exclude_used: false,
         }
     }
 
@@ -848,12 +852,22 @@ impl DiskUsageQuery {
         self
     }
 
+    pub fn exclude_used(&mut self, exclude_used: bool) -> &mut Self {
+        self.exclude_used = exclude_used;
+        self
+    }
+
     pub fn query(&self) -> Result<HashMap<String, DiskUsageInfo>, Error> {
-        get_disks(None, !self.smart, self.partitions)
+        get_disks(None, !self.smart, self.partitions, self.exclude_used)
     }
 
     pub fn find(&self, disk: &str) -> Result<DiskUsageInfo, Error> {
-        let mut map = get_disks(Some(vec![disk.to_string()]), !self.smart, self.partitions)?;
+        let mut map = get_disks(
+            Some(vec![disk.to_string()]),
+            !self.smart,
+            self.partitions,
+            self.exclude_used,
+        )?;
         if let Some(info) = map.remove(disk) {
             Ok(info)
         } else {
@@ -862,7 +876,7 @@ impl DiskUsageQuery {
     }
 
     pub fn find_all(&self, disks: Vec<String>) -> Result<HashMap<String, DiskUsageInfo>, Error> {
-        get_disks(Some(disks), !self.smart, self.partitions)
+        get_disks(Some(disks), !self.smart, self.partitions, self.exclude_used)
     }
 }
 
@@ -935,6 +949,8 @@ fn get_disks(
     no_smart: bool,
     // include partitions
     include_partitions: bool,
+    // skip partitions which are in use
+    exclude_used: bool,
 ) -> Result<HashMap<String, DiskUsageInfo>, Error> {
     let disk_manager = DiskManage::new();
 
@@ -952,6 +968,30 @@ fn get_disks(
 
     // fixme: ceph journals/volumes
 
+    let uuids_in_use = if exclude_used && include_partitions {
+        let (config, _digest) = pbs_config::datastore::config()?;
+
+        let uuids_from_datastores: Vec<String> = config
+            .sections
+            .iter()
+            .filter_map(|(_, (_, data))| {
+                data.as_object()
+                    .and_then(|cfg| cfg.get("backing-device"))
+                    .and_then(Value::as_str)
+                    .map(String::from)
+            })
+            .collect();
+
+        let uuids_from_mounts: Vec<String> = list_datastore_mounts()?
+            .into_iter()
+            .filter_map(|mount| mount.device.split('/').last().map(String::from))
+            .collect();
+
+        [&uuids_from_datastores[..], &uuids_from_mounts[..]].concat()
+    } else {
+        Vec::new()
+    };
+
     let mut result = HashMap::new();
 
     for item in proxmox_sys::fs::scan_subdir(libc::AT_FDCWD, "/sys/block", &BLOCKDEVICE_NAME_REGEX)?
@@ -1024,12 +1064,16 @@ fn get_disks(
 
         let partitions: Option<Vec<PartitionInfo>> = if include_partitions {
             disk.partitions().map_or(None, |parts| {
-                Some(get_partitions_info(
-                    parts,
-                    &lvm_devices,
-                    &zfs_devices,
-                    &file_system_devices,
-                ))
+                let infos =
+                    get_partitions_info(parts, &lvm_devices, &zfs_devices, &file_system_devices)
+                        .into_iter()
+                        .filter(|part| {
+                            part.uuid
+                                .as_ref()
+                                .map_or(true, |u| !uuids_in_use.contains(u))
+                        })
+                        .collect();
+                Some(infos)
             })
         } else {
             None
-- 
2.39.2





More information about the pbs-devel mailing list