[pbs-devel] [PATCH v3 proxmox-backup 04/20] datastore: mark groups as trash on destroy

Christian Ebner c.ebner at proxmox.com
Tue May 13 15:52:31 CEST 2025


In order to implement the trash can functionality, mark all the
snapshots of the group and the group itself as trash instead of
deleting them right away. Cleanup of the group is deferred to the
garbage collection.

The group is marked as trash in order to skip over it in listings
without trashed items and to force an owner check when re-creation is
requested by a backup task to this group.

Snapshots already marked as trash within the same backup group will
be cleared as well when the group is requested to be destroyed with
skip trash.

Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
---
 pbs-datastore/src/backup_info.rs | 19 ++++++++++++++++---
 pbs-datastore/src/datastore.rs   |  4 ++--
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/pbs-datastore/src/backup_info.rs b/pbs-datastore/src/backup_info.rs
index 76bcd15f5..9ce4cb0f8 100644
--- a/pbs-datastore/src/backup_info.rs
+++ b/pbs-datastore/src/backup_info.rs
@@ -215,7 +215,7 @@ impl BackupGroup {
     ///
     /// Returns `BackupGroupDeleteStats`, containing the number of deleted snapshots
     /// and number of protected snaphsots, which therefore were not removed.
-    pub fn destroy(&self) -> Result<BackupGroupDeleteStats, Error> {
+    pub fn destroy(&self, skip_trash: bool) -> Result<BackupGroupDeleteStats, Error> {
         let _guard = self
             .lock()
             .with_context(|| format!("while destroying group '{self:?}'"))?;
@@ -229,14 +229,20 @@ impl BackupGroup {
                 delete_stats.increment_protected_snapshots();
                 continue;
             }
-            snap.destroy(false, false)?;
+            snap.destroy(false, skip_trash)?;
             delete_stats.increment_removed_snapshots();
         }
 
         // Note: make sure the old locking mechanism isn't used as `remove_dir_all` is not safe in
         // that case
         if delete_stats.all_removed() && !*OLD_LOCKING {
-            self.remove_group_dir()?;
+            if skip_trash {
+                self.remove_group_dir()?;
+            } else {
+                let path = self.full_group_path().join(TRASH_MARKER_FILENAME);
+                let _trash_file =
+                    std::fs::File::create(path).context("failed to set trash file")?;
+            }
             delete_stats.increment_removed_groups();
         }
 
@@ -245,6 +251,13 @@ impl BackupGroup {
 
     /// Helper function, assumes that no more snapshots are present in the group.
     fn remove_group_dir(&self) -> Result<(), Error> {
+        let trash_path = self.full_group_path().join(TRASH_MARKER_FILENAME);
+        if let Err(err) = std::fs::remove_file(&trash_path) {
+            if err.kind() != std::io::ErrorKind::NotFound {
+                bail!("removing the trash file '{trash_path:?}' failed - {err}")
+            }
+        }
+
         let owner_path = self.store.owner_path(&self.ns, &self.group);
 
         std::fs::remove_file(&owner_path).map_err(|err| {
diff --git a/pbs-datastore/src/datastore.rs b/pbs-datastore/src/datastore.rs
index 6df26e825..e546bc532 100644
--- a/pbs-datastore/src/datastore.rs
+++ b/pbs-datastore/src/datastore.rs
@@ -581,7 +581,7 @@ impl DataStore {
         let mut stats = BackupGroupDeleteStats::default();
 
         for group in self.iter_backup_groups(ns.to_owned())? {
-            let delete_stats = group?.destroy()?;
+            let delete_stats = group?.destroy(true)?;
             stats.add(&delete_stats);
             removed_all_groups = removed_all_groups && delete_stats.all_removed();
         }
@@ -674,7 +674,7 @@ impl DataStore {
     ) -> Result<BackupGroupDeleteStats, Error> {
         let backup_group = self.backup_group(ns.clone(), backup_group.clone());
 
-        backup_group.destroy()
+        backup_group.destroy(true)
     }
 
     /// Remove a backup directory including all content
-- 
2.39.5





More information about the pbs-devel mailing list