[libvirt] [PATCH] rbd: Use RBD fast-diff for querying actual volume allocation
John Ferlan
jferlan at redhat.com
Wed Feb 10 22:18:23 UTC 2016
On 02/10/2016 04:21 AM, Wido den Hollander wrote:
> 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 <wido at widodh.nl>
> ---
> src/storage/storage_backend_rbd.c | 48 +++++++++++++++++++++++++++++++++++----
> 1 file changed, 44 insertions(+), 4 deletions(-)
>
> diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
> index 5d73370..cdcfa48 100644
> --- a/src/storage/storage_backend_rbd.c
> +++ b/src/storage/storage_backend_rbd.c
> @@ -279,6 +279,20 @@ virStorageBackendRBDCloseRADOSConn(virStorageBackendRBDStatePtr ptr)
> return ret;
> }
>
> +#if LIBRBD_VERSION_CODE > 265
> +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;
> +}
> +#endif
> +
The above could move into my suggestions below:
How about perhaps a
/*
* Returns 0 on success, -1 on failure and messages
*/
static int
volStorageBackendRBDGetFeatures(rbd_image_t image,
const char *volname,
uint64_t *features)
{
int r, ret = -1;
if ((r = rbd_get_features(image, features)) < 0) {
virReportSystemError(-r,
_("failed to get the features of RBD image
%s"),
volname);
goto cleanup;
}
ret = 0;
cleanup:
return ret;
}
[the above can be used by virStorageBackendRBDImageInfo]... So what I
would do is create a patch 1 that replaces the current usage with this
methodology. Then patch 2 can be these changes.
#if LIBRBD_VERSION_CODE > 265
static bool
volStorageBackendRBDUseFastDiff(uint64_t features)
{
return features & RBD_FEATURE_FAST_DIFF;
}
... The virStorageBackendRBDRefreshVolInfoCb function ...
static int
virStorageBackendRBDSetAllocation(virStorageVolDefPtr,
rbd_image_t *image,
rbd_image_info_t *info)
{
int r, ret = -1;
uint64_t used_size;
if ((r = rbd_diff_iterate2(image, NULL, 0, info->size, 0, 1,
&virStorageBackendRBDRefreshVolInfoCb,
&used_size)) < 0) {
virReportSystemError(-r, _("failed to iterate RBD image '%s'"),
vol->name);
goto cleanup;
}
vol->target.allocation = used_size
ret = 0;
cleanup:
return ret;
}
static int
#else
volStorageBackendRBDUseFastDiff(uint64_t features ATTRIBUTE_UNUSED)
{
return false;
}
#endif
> static int
> volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
> virStoragePoolObjPtr pool,
> @@ -288,6 +302,8 @@ volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
> int r = 0;
> rbd_image_t image = NULL;
> rbd_image_info_t info;
> + uint64_t features ATTRIBUTE_UNUSED;
This will remove the ATTRIBUTE_UNUSED
> + uint64_t used_size ATTRIBUTE_UNUSED = 0;
This isn't needed here anymore.
>
> if ((r = rbd_open_read_only(ptr->ioctx, vol->name, &image, NULL)) < 0) {
> ret = -r;
> @@ -303,15 +319,39 @@ 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;
Since you're just changing allocation...
if (volStorageBackendRBDUseFastDiff(features) {
if (virStorageBackendRBDSetAllocation(vol, image, &info) < 0)
goto cleanup;
} else {
vol->target.allocation = info.obj_size * info.num_objs;
}
> vol->type = VIR_STORAGE_VOL_NETWORK;
> vol->target.format = VIR_STORAGE_FILE_RAW;
>
> +#if LIBRBD_VERSION_CODE > 265
> + if ((r = rbd_get_features(image, &features)) < 0) {
^^
A call to rbd_get_features already exists, so it doesn't seem to need to
be placed inside that #if
> + virReportSystemError(-r, _("failed to get flags of RBD image '%s'"),
> + vol->name);
> + goto cleanup;
> + }
> +
> + if (features & RBD_FEATURE_FAST_DIFF) {
> + VIR_DEBUG("RBD image %s/%s has fast-diff enabled. Querying allocation",
> + pool->def->source.name, vol->name);
> +
> + if ((r = rbd_diff_iterate2(image, NULL, 0, info.size, 0, 1,
^^
Calling this is already in the code with:
#if LIBRBD_VERSION_CODE > 266
but this is > 265
does it matter? see my dilemma?
Hope this makes sense...
John
> + &virStorageBackendRBDRefreshVolInfoCb,
> + &used_size)) < 0) {
> + virReportSystemError(-r, _("failed to iterate RBD image '%s'"),
> + vol->name);
> + goto cleanup;
> + }
> +
> + vol->target.allocation = used_size;
> + }
> +#endif
> +
> + 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,
>
More information about the libvir-list
mailing list