mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +00:00
rbd: Remove snapshots if the DELETE_WITH_SNAPSHOTS flag has been provided
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@widodh.nl>
This commit is contained in:
parent
10fe8d0668
commit
3c7590e0a4
@ -115,6 +115,7 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
VIR_STORAGE_VOL_DELETE_NORMAL = 0, /* Delete metadata only (fast) */
|
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_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;
|
} virStorageVolDeleteFlags;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -421,6 +421,87 @@ static int virStorageBackendRBDRefreshPool(virConnectPtr conn,
|
|||||||
return ret;
|
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 = 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,
|
static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
|
||||||
virStoragePoolObjPtr pool,
|
virStoragePoolObjPtr pool,
|
||||||
virStorageVolDefPtr vol,
|
virStorageVolDefPtr vol,
|
||||||
@ -443,6 +524,14 @@ static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
|
|||||||
if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
|
if (virStorageBackendRBDOpenIoCTX(&ptr, pool) < 0)
|
||||||
goto cleanup;
|
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);
|
r = rbd_remove(ptr.ioctx, vol->name);
|
||||||
if (r < 0 && (-r) != ENOENT) {
|
if (r < 0 && (-r) != ENOENT) {
|
||||||
virReportSystemError(-r, _("failed to remove volume '%s/%s'"),
|
virReportSystemError(-r, _("failed to remove volume '%s/%s'"),
|
||||||
|
Loading…
Reference in New Issue
Block a user