[libvirt] [PATCH] rbd: Remove snapshots if the DELETE_WITH_SNAPSHOTS flag has been provided

Wido den Hollander wido at widodh.nl
Tue Oct 27 14:16:34 UTC 2015


When a RBD volume has snapshots it can not be removed.

This patch introduces a new flag to force volume removal,
VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS.

With this flag any existing snapshots will be removed prior to
removing the volume.

No existing mechanism in libvirt allowed us to pass such information,
so that's why a new flag was introduced.

Signed-off-by: Wido den Hollander <wido at widodh.nl>
---
 include/libvirt/libvirt-storage.h |  1 +
 src/storage/storage_backend_rbd.c | 89 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 90 insertions(+)

diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h
index 453089e..9fc3c2d 100644
--- a/include/libvirt/libvirt-storage.h
+++ b/include/libvirt/libvirt-storage.h
@@ -115,6 +115,7 @@ typedef enum {
 typedef enum {
     VIR_STORAGE_VOL_DELETE_NORMAL = 0, /* Delete metadata only    (fast) */
     VIR_STORAGE_VOL_DELETE_ZEROED = 1 << 0,  /* Clear all data to zeros (slow) */
+    VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS = 1 << 1, /* Force removal of volume, even if in use */
 } virStorageVolDeleteFlags;
 
 typedef enum {
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
index 5ae4713..a37d286 100644
--- a/src/storage/storage_backend_rbd.c
+++ b/src/storage/storage_backend_rbd.c
@@ -421,6 +421,87 @@ static int virStorageBackendRBDRefreshPool(virConnectPtr conn,
     return ret;
 }
 
+static int virStorageBackendRBDCleanupSnapshots(rados_ioctx_t ioctx,
+                                                virStoragePoolSourcePtr source,
+                                                virStorageVolDefPtr vol)
+{
+    int ret = -1;
+    int r = 0;
+    int max_snaps = 128;
+    int snap_count, protected;
+    size_t i;
+    rbd_snap_info_t *snaps;
+    rbd_image_t image = NULL;
+
+    r = rbd_open(ioctx, vol->name, &image, NULL);
+    if (r < 0) {
+       virReportSystemError(-r, _("failed to open the RBD image '%s'"),
+                            vol->name);
+       goto cleanup;
+    }
+
+    do {
+        if (VIR_ALLOC_N(snaps, max_snaps))
+            goto cleanup;
+
+        snap_count = rbd_snap_list(image, snaps, &max_snaps);
+        if (snap_count <= 0)
+            VIR_FREE(snaps);
+
+    } while (snap_count == -ERANGE);
+
+    VIR_DEBUG("Found %d snapshots for volume %s/%s", snap_count,
+              source->name, vol->name);
+
+    if (snap_count > 0) {
+        for (i = 0; i < snap_count; i++) {
+            if (rbd_snap_is_protected(image, snaps[i].name, &protected)) {
+                virReportSystemError(-r, _("failed to verify if snapshot '%s/%s@%s' is protected"),
+                                     source->name, vol->name,
+                                     snaps[i].name);
+                goto cleanup;
+            }
+
+            if (protected == 1) {
+                VIR_DEBUG("Snapshot %s/%s@%s is protected needs to be "
+                          "unprotected", source->name, vol->name,
+                          snaps[i].name);
+
+                if (rbd_snap_unprotect(image, snaps[i].name) < 0) {
+                    virReportSystemError(-r, _("failed to unprotect snapshot '%s/%s@%s'"),
+                                         source->name, vol->name,
+                                         snaps[i].name);
+                    goto cleanup;
+                }
+            }
+
+            VIR_DEBUG("Removing snapshot %s/%s@%s", source->name,
+                      vol->name, snaps[i].name);
+
+            r = rbd_snap_remove(image, snaps[i].name);
+            if (r < 0) {
+                virReportSystemError(-r, _("failed to remove snapshot '%s/%s@%s'"),
+                                     source->name, vol->name,
+                                     snaps[i].name);
+                goto cleanup;
+            }
+        }
+    }
+
+    ret = 0;
+
+ cleanup:
+    if (snaps)
+        rbd_snap_list_end(snaps);
+
+    VIR_FREE(snaps);
+
+    if (image)
+        rbd_close(image);
+
+    return ret;
+}
+
 static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
                                          virStoragePoolObjPtr pool,
                                          virStorageVolDefPtr vol,
@@ -443,6 +524,14 @@ static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
     if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
         goto cleanup;
 
+    if (flags & VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS) {
+        if (virStorageBackendRBDCleanupSnapshots(ptr.ioctx, &pool->def->source,
+                                                 vol) < 0)
+            goto cleanup;
+    }
+
+    VIR_DEBUG("Removing volume %s/%s", pool->def->source.name, vol->name);
+
     r = rbd_remove(ptr.ioctx, vol->name);
     if (r < 0 && (-r) != ENOENT) {
         virReportSystemError(-r, _("failed to remove volume '%s/%s'"),
-- 
1.9.1




More information about the libvir-list mailing list