[libvirt] [PATCH] rbd: Remove snapshots if the DELETE_WITH_SNAPSHOTS flag has been provided
John Ferlan
jferlan at redhat.com
Tue Oct 27 21:10:29 UTC 2015
On 10/27/2015 10:16 AM, Wido den Hollander wrote:
> 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(+)
>
With one minor adjustment shown below to initialize snaps, this is now
pushed.
John
> 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;
snaps = NULL
> + 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'"),
>
More information about the libvir-list
mailing list