From 98782f88991a390a358cea960b5776f72fc14451 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Thu, 11 Feb 2016 17:04:17 +0100 Subject: [PATCH] rbd: Use RBD fast-diff for querying actual volume allocation Since Ceph version Infernalis (9.2.0) the new fast-diff mechanism of RBD allows for querying actual volume usage. Prior to this version there was no easy and fast way to query how much allocation a RBD volume had inside a Ceph cluster. To use the fast-diff feature it needs to be enabled per RBD image and is only supported by Ceph cluster running version Infernalis (9.2.0) or newer. Without the fast-diff feature enabled libvirt will report an allocation identical to the image capacity. This is how libvirt behaves currently. 'virsh vol-info rbd/image2' might output for example: Name: image2 Type: network Capacity: 1,00 GiB Allocation: 124,00 MiB Newly created volumes will have the fast-diff feature enabled if the backing Ceph cluster supports it. Signed-off-by: Wido den Hollander --- src/storage/storage_backend_rbd.c | 85 +++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c index 887db0bfdd..098b7dc5f0 100644 --- a/src/storage/storage_backend_rbd.c +++ b/src/storage/storage_backend_rbd.c @@ -297,6 +297,68 @@ volStorageBackendRBDGetFeatures(rbd_image_t image, return ret; } +#if LIBRBD_VERSION_CODE > 265 +static bool +volStorageBackendRBDUseFastDiff(uint64_t features) +{ + return features & RBD_FEATURE_FAST_DIFF; +} + +static int +virStorageBackendRBDRefreshVolInfoCb(uint64_t offset ATTRIBUTE_UNUSED, + size_t len, + int exists, + void *arg) +{ + uint64_t *used_size = (uint64_t *)(arg); + if (exists) + (*used_size) += len; + + return 0; +} + +static int +virStorageBackendRBDSetAllocation(virStorageVolDefPtr vol, + rbd_image_t *image, + rbd_image_info_t *info) +{ + int r, ret = -1; + uint64_t allocation = 0; + + if ((r = rbd_diff_iterate2(image, NULL, 0, info->size, 0, 1, + &virStorageBackendRBDRefreshVolInfoCb, + &allocation)) < 0) { + virReportSystemError(-r, _("failed to iterate RBD image '%s'"), + vol->name); + goto cleanup; + } + + VIR_DEBUG("Found %zu bytes allocated for RBD image %s", + allocation, vol->name); + + vol->target.allocation = allocation; + ret = 0; + + cleanup: + return ret; +} + +#else +static int +volStorageBackendRBDUseFastDiff(uint64_t features ATTRIBUTE_UNUSED) +{ + return false; +} + +static int +virStorageBackendRBDSetAllocation(virStorageVolDefPtr vol ATTRIBUTE_UNUSED, + rbd_image_t *image ATTRIBUTE_UNUSED, + rbd_image_info_t *info ATTRIBUTE_UNUSED) +{ + return false; +} +#endif + static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol, virStoragePoolObjPtr pool, @@ -306,6 +368,7 @@ volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol, int r = 0; rbd_image_t image = NULL; rbd_image_info_t info; + uint64_t features; if ((r = rbd_open_read_only(ptr->ioctx, vol->name, &image, NULL)) < 0) { ret = -r; @@ -321,15 +384,29 @@ volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol, goto cleanup; } - VIR_DEBUG("Refreshed RBD image %s/%s (size: %zu obj_size: %zu num_objs: %zu)", - pool->def->source.name, vol->name, info.size, info.obj_size, - info.num_objs); + if (volStorageBackendRBDGetFeatures(image, vol->name, &features) < 0) + goto cleanup; vol->target.capacity = info.size; - vol->target.allocation = info.obj_size * info.num_objs; vol->type = VIR_STORAGE_VOL_NETWORK; vol->target.format = VIR_STORAGE_FILE_RAW; + if (volStorageBackendRBDUseFastDiff(features)) { + VIR_DEBUG("RBD image %s/%s has fast-diff feature enabled. " + "Querying for actual allocation", + pool->def->source.name, vol->name); + + if (virStorageBackendRBDSetAllocation(vol, image, &info) < 0) + goto cleanup; + } else { + vol->target.allocation = info.obj_size * info.num_objs; + } + + VIR_DEBUG("Refreshed RBD image %s/%s (capacity: %llu allocation: %llu " + "obj_size: %zu num_objs: %zu)", + pool->def->source.name, vol->name, vol->target.capacity, + vol->target.allocation, info.obj_size, info.num_objs); + VIR_FREE(vol->target.path); if (virAsprintf(&vol->target.path, "%s/%s", pool->def->source.name, -- GitLab