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(a)widodh.nl>
---
include/libvirt/libvirt-storage.h | 1 +
src/storage/storage_backend_rbd.c | 59 +++++++++++++++++++++++++++++++++++++++
2 files changed, 60 insertions(+)
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h
index 453089e..80da5a3 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 = 2, /* 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..71f7d10 100644
--- a/src/storage/storage_backend_rbd.c
+++ b/src/storage/storage_backend_rbd.c
@@ -428,9 +428,13 @@ static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
{
int ret = -1;
int r = 0;
+ int max_snaps = 128;
+ int i, snap_count, protected;
virStorageBackendRBDState ptr;
ptr.cluster = NULL;
ptr.ioctx = NULL;
+ rbd_snap_info_t *snaps;
+ rbd_image_t image = NULL;
VIR_DEBUG("Removing RBD image %s/%s", pool->def->source.name,
vol->name);
@@ -443,6 +447,60 @@ static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
goto cleanup;
+ r = rbd_open(ptr.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,
+ pool->def->source.name, vol->name);
+
+ if (snap_count > 0 && (flags & VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS))
{
+ for (i = 0; i < snap_count; i++) {
+ if (rbd_snap_is_protected(image, snaps[i].name, &protected))
+ goto cleanup;
+
+ if (protected == 1) {
+ VIR_DEBUG("Snapshot %s/%s@%s is protected needs to be "
+ "unprotected", pool->def->source.name,
vol->name,
+ snaps[i].name);
+
+ if (rbd_snap_unprotect(image, snaps[i].name) < 0)
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Removing snapshot %s/%s@%s",
pool->def->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'"),
+ pool->def->source.name, vol->name,
+ snaps[i].name);
+ goto cleanup;
+ }
+ }
+
+ rbd_snap_list_end(snaps);
+ }
+
+ if (rbd_close(image) < 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'"),
@@ -453,6 +511,7 @@ static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
ret = 0;
cleanup:
+ VIR_FREE(snaps);
virStorageBackendRBDCloseRADOSConn(&ptr);
return ret;
}
--
1.9.1