This allows user to use the volume wiping functionality of the libvirt
storage driver.
This patch also adds a new wiping algorithm VIR_STORAGE_VOL_WIPE_ALG_DISCARD
By default the VIR_STORAGE_VOL_WIPE_ALG_ZERO algorithm is used and with
RBD this will called rbd_write() in chunks of the underlying object size
to completely zero out the volume.
With VIR_STORAGE_VOL_WIPE_ALG_DISCARD it will call rbd_discard() in the
same object size chunks which will trim/discard all underlying RADOS objects
in the Ceph cluster.
Signed-off-by: Wido den Hollander <wido(a)widodh.nl>
---
include/libvirt/libvirt-storage.h | 4 +
src/storage/storage_backend_rbd.c | 157 +++++++++++++++++++++++++++++++++++++-
tools/virsh-volume.c | 2 +-
3 files changed, 161 insertions(+), 2 deletions(-)
diff --git a/include/libvirt/libvirt-storage.h b/include/libvirt/libvirt-storage.h
index 2c55c93..139add3 100644
--- a/include/libvirt/libvirt-storage.h
+++ b/include/libvirt/libvirt-storage.h
@@ -153,6 +153,10 @@ typedef enum {
VIR_STORAGE_VOL_WIPE_ALG_RANDOM = 8, /* 1-pass random */
+ VIR_STORAGE_VOL_WIPE_ALG_DISCARD = 9, /* 1-pass, discard all data on the
+ volume by using TRIM or
+ DISCARD */
+
# ifdef VIR_ENUM_SENTINELS
VIR_STORAGE_VOL_WIPE_ALG_LAST
/*
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
index e20a54d..c0001d0 100644
--- a/src/storage/storage_backend_rbd.c
+++ b/src/storage/storage_backend_rbd.c
@@ -32,6 +32,7 @@
#include "base64.h"
#include "viruuid.h"
#include "virstring.h"
+#include "virutil.h"
#include "rados/librados.h"
#include "rbd/librbd.h"
@@ -730,6 +731,159 @@ static int virStorageBackendRBDResizeVol(virConnectPtr conn
ATTRIBUTE_UNUSED,
return ret;
}
+static int virStorageBackendRBDVolWipeZero(rbd_image_t image,
+ char *imgname,
+ rbd_image_info_t info,
+ uint64_t stripe_count)
+{
+ int r = -1;
+ size_t offset = 0;
+ uint64_t length;
+ char *writebuf;
+
+ if (VIR_ALLOC_N(writebuf, info.obj_size * stripe_count) < 0)
+ goto cleanup;
+
+ while (offset < info.size) {
+ length = MIN((info.size - offset), (info.obj_size * stripe_count));
+
+ r = rbd_write(image, offset, length, writebuf);
+ if (r < 0) {
+ virReportSystemError(-r, _("writing %llu bytes failed on "
+ " RBD image %s at offset %llu"),
+ (unsigned long long)length,
+ imgname,
+ (unsigned long long)offset);
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Wrote %llu bytes to RBD image %s at offset %llu",
+ (unsigned long long)length,
+ imgname, (unsigned long long)offset);
+
+ offset += length;
+ }
+
+ cleanup:
+ VIR_FREE(writebuf);
+
+ return r;
+}
+
+static int virStorageBackendRBDVolWipeDiscard(rbd_image_t image,
+ char *imgname,
+ rbd_image_info_t info,
+ uint64_t stripe_count)
+{
+ int r = -1;
+ size_t offset = 0;
+ uint64_t length;
+
+ VIR_DEBUG("Wiping RBD %s volume using discard)", imgname);
+
+ while (offset < info.size) {
+ length = MIN((info.size - offset), (info.obj_size * stripe_count));
+
+ r = rbd_discard(image, offset, length);
+ if (r < 0) {
+ virReportSystemError(-r, _("discarding %llu bytes failed on "
+ " RBD image %s at offset %llu"),
+ (unsigned long long)length,
+ imgname,
+ (unsigned long long)offset);
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Discarded %llu bytes of RBD image %s at offset %llu",
+ (unsigned long long)length,
+ imgname, (unsigned long long)offset);
+
+ offset += length;
+ }
+
+ cleanup:
+ return r;
+}
+
+static int virStorageBackendRBDVolWipe(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ unsigned int algorithm,
+ unsigned int flags)
+{
+ virStorageBackendRBDState ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+ rbd_image_t image = NULL;
+ rbd_image_info_t info;
+ uint64_t stripe_count;
+ int r = -1;
+
+ virCheckFlags(VIR_STORAGE_VOL_WIPE_ALG_ZERO |
+ VIR_STORAGE_VOL_WIPE_ALG_DISCARD, -1);
+
+ VIR_DEBUG("Wiping RBD image %s/%s", pool->def->source.name,
vol->name);
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, &pool->def->source)
< 0)
+ goto cleanup;
+
+ 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;
+ }
+
+ r = rbd_stat(image, &info, sizeof(info));
+ if (r < 0) {
+ virReportSystemError(-r, _("failed to stat the RBD image %s"),
+ vol->name);
+ goto cleanup;
+ }
+
+ r = rbd_get_stripe_count(image, &stripe_count);
+ if (r < 0) {
+ virReportSystemError(-r, _("failed to get stripe count of RBD image
%s"),
+ vol->name);
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Need to wipe %llu bytes from RBD image %s/%s",
+ (unsigned long long)info.size, pool->def->source.name,
vol->name);
+
+ switch (algorithm) {
+ case VIR_STORAGE_VOL_WIPE_ALG_ZERO:
+ r = virStorageBackendRBDVolWipeZero(image, vol->name,
+ info, stripe_count);
+ break;
+ case VIR_STORAGE_VOL_WIPE_ALG_DISCARD:
+ r = virStorageBackendRBDVolWipeDiscard(image, vol->name,
+ info, stripe_count);
+ break;
+ default:
+ virReportError(VIR_ERR_INVALID_ARG, _("unsupported algorithm %d"),
+ algorithm);
+ r = -VIR_ERR_INVALID_ARG;
+ goto cleanup;
+ }
+
+ if (r < 0) {
+ virReportSystemError(-r, _("failed to wipe RBD image %s"),
+ vol->name);
+ goto cleanup;
+ }
+
+ cleanup:
+ if (image)
+ rbd_close(image);
+
+ virStorageBackendRBDCloseRADOSConn(&ptr);
+ return r;
+}
+
virStorageBackend virStorageBackendRBD = {
.type = VIR_STORAGE_POOL_RBD,
@@ -738,5 +892,6 @@ virStorageBackend virStorageBackendRBD = {
.buildVol = virStorageBackendRBDBuildVol,
.refreshVol = virStorageBackendRBDRefreshVol,
.deleteVol = virStorageBackendRBDDeleteVol,
- .resizeVol = virStorageBackendRBDResizeVol,
+ .wipeVol = virStorageBackendRBDVolWipe,
+ .resizeVol = virStorageBackendRBDResizeVol
};
diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c
index 661c876..f86980f 100644
--- a/tools/virsh-volume.c
+++ b/tools/virsh-volume.c
@@ -906,7 +906,7 @@ static const vshCmdOptDef opts_vol_wipe[] = {
VIR_ENUM_DECL(virStorageVolWipeAlgorithm)
VIR_ENUM_IMPL(virStorageVolWipeAlgorithm, VIR_STORAGE_VOL_WIPE_ALG_LAST,
"zero", "nnsa", "dod", "bsi",
"gutmann", "schneier",
- "pfitzner7", "pfitzner33", "random");
+ "pfitzner7", "pfitzner33", "random",
"discard");
static bool
cmdVolWipe(vshControl *ctl, const vshCmd *cmd)
--
1.9.1