[pbs-devel] [PATCH proxmox-backup v2 09/25] api2: disks list: add only-unused flag

Hannes Laimer h.laimer at proxmox.com
Thu Sep 21 14:51:51 CEST 2023


... 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        | 67 ++++++++++++++++++++++++++++++-----
 www/form/PartitionSelector.js |  2 +-
 3 files changed, 67 insertions(+), 10 deletions(-)

diff --git a/src/api2/node/disks/mod.rs b/src/api2/node/disks/mod.rs
index 5ee959cd..73cda339 100644
--- a/src/api2/node/disks/mod.rs
+++ b/src/api2/node/disks/mod.rs
@@ -40,6 +40,12 @@ pub mod zfs;
                 optional: true,
                 default: false,
             },
+            "only-unused": {
+                description: "Only list partitions not used for removable datastores or mounted directories.",
+                type: bool,
+                optional: true,
+                default: false,
+            },
             "usage-type": {
                 type: DiskUsageType,
                 optional: true,
@@ -61,6 +67,7 @@ pub mod zfs;
 pub fn list_disks(
     skipsmart: bool,
     include_partitions: bool,
+    only_unused: bool,
     usage_type: Option<DiskUsageType>,
 ) -> Result<Vec<DiskUsageInfo>, Error> {
     let mut list = Vec::new();
@@ -68,6 +75,7 @@ pub fn list_disks(
     for (_, info) in DiskUsageQuery::new()
         .smart(!skipsmart)
         .partitions(include_partitions)
+        .only_not_in_use(only_unused)
         .query()?
     {
         if let Some(ref usage_type) = usage_type {
diff --git a/src/tools/disks/mod.rs b/src/tools/disks/mod.rs
index f62db754..8ea0cbf4 100644
--- a/src/tools/disks/mod.rs
+++ b/src/tools/disks/mod.rs
@@ -18,6 +18,7 @@ use proxmox_lang::error::io_err_other;
 use proxmox_lang::{io_bail, io_format_err};
 use proxmox_schema::api;
 use proxmox_sys::linux::procfs::{mountinfo::Device, MountInfo};
+use serde_json::Value;
 
 use pbs_api_types::BLOCKDEVICE_NAME_REGEX;
 
@@ -30,6 +31,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! {
@@ -770,6 +772,7 @@ fn scan_partitions(
 pub struct DiskUsageQuery {
     smart: bool,
     partitions: bool,
+    only_not_in_use: bool,
 }
 
 impl DiskUsageQuery {
@@ -777,6 +780,7 @@ impl DiskUsageQuery {
         Self {
             smart: true,
             partitions: false,
+            only_not_in_use: false,
         }
     }
 
@@ -790,12 +794,22 @@ impl DiskUsageQuery {
         self
     }
 
+    pub fn only_not_in_use(&mut self, only_not_in_use: bool) -> &mut Self {
+        self.only_not_in_use = only_not_in_use;
+        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.only_not_in_use)
     }
 
     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.only_not_in_use,
+        )?;
         if let Some(info) = map.remove(disk) {
             Ok(info)
         } else {
@@ -804,7 +818,12 @@ 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.only_not_in_use,
+        )
     }
 }
 
@@ -877,6 +896,8 @@ fn get_disks(
     no_smart: bool,
     // include partitions
     include_partitions: bool,
+    // skip partitions which are in use
+    only_not_in_use: bool,
 ) -> Result<HashMap<String, DiskUsageInfo>, Error> {
     let disk_manager = DiskManage::new();
 
@@ -894,6 +915,30 @@ fn get_disks(
 
     // fixme: ceph journals/volumes
 
+    let uuids_in_use = if only_not_in_use && 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)?
@@ -966,12 +1011,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
diff --git a/www/form/PartitionSelector.js b/www/form/PartitionSelector.js
index 6246e958..64e7990a 100644
--- a/www/form/PartitionSelector.js
+++ b/www/form/PartitionSelector.js
@@ -3,7 +3,7 @@ Ext.define('pbs-partition-list', {
     fields: ['name', 'uuid', 'filesystem', 'devpath', 'size'],
     proxy: {
 	type: 'proxmox',
-	url: "/api2/json/nodes/localhost/disks/list?include-partitions=1",
+	url: "/api2/json/nodes/localhost/disks/list?include-partitions=1&only-unused=1",
 	reader: {
 	    transform: (rawData) => rawData.data
 		.flatMap(disk => (disk.partitions ?? [])
-- 
2.39.2






More information about the pbs-devel mailing list