[libvirt] [PATCH 1/2] rbd: Add wiping RBD volumes by using rbd_discard() or rbd_write()

Wido den Hollander wido at widodh.nl
Wed Dec 23 15:06:57 UTC 2015


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 at widodh.nl>
---
 include/libvirt/libvirt-storage.h |   4 +
 src/storage/storage_backend_rbd.c | 155 +++++++++++++++++++++++++++++++++++++-
 tools/virsh-volume.c              |   2 +-
 3 files changed, 159 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 cdbfdee..d13658d 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"
 
@@ -700,6 +701,157 @@ 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:
+    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,
 
@@ -708,5 +860,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 7932ef2..3e95aa5 100644
--- a/tools/virsh-volume.c
+++ b/tools/virsh-volume.c
@@ -954,7 +954,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




More information about the libvir-list mailing list