[libvirt] [PATCH 02/10] util: Add virResctrlInfo

Martin Kletzander posted 10 patches 7 years, 3 months ago
[libvirt] [PATCH 02/10] util: Add virResctrlInfo
Posted by Martin Kletzander 7 years, 3 months ago
This will make the current functions obsolete and it will provide more
information to the virresctrl module so that it can be used later.

Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
---
 po/POTFILES.in           |   1 +
 src/libvirt_private.syms |   3 +
 src/util/virresctrl.c    | 305 +++++++++++++++++++++++++++++++++++++++++++++++
 src/util/virresctrl.h    |  19 +++
 4 files changed, 328 insertions(+)

diff --git a/po/POTFILES.in b/po/POTFILES.in
index c1fa23427eff..8382ee633621 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -252,6 +252,7 @@ src/util/virportallocator.c
 src/util/virprocess.c
 src/util/virqemu.c
 src/util/virrandom.c
+src/util/virresctrl.c
 src/util/virrotatingfile.c
 src/util/virscsi.c
 src/util/virscsihost.c
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index bc8cc1fba9e3..e951a5495b3f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2554,6 +2554,9 @@ virCacheTypeFromString;
 virCacheTypeToString;
 virResctrlGetCacheControlType;
 virResctrlGetCacheInfo;
+virResctrlGetInfo;
+virResctrlInfoGetCache;
+virResctrlInfoNew;
 
 
 # util/virrotatingfile.h
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
index 050a08178e24..25c11a1314dc 100644
--- a/src/util/virresctrl.c
+++ b/src/util/virresctrl.c
@@ -25,12 +25,15 @@
 #include "viralloc.h"
 #include "virfile.h"
 #include "virlog.h"
+#include "virobject.h"
 #include "virstring.h"
 
 #define VIR_FROM_THIS VIR_FROM_RESCTRL
 
 VIR_LOG_INIT("util.virresctrl")
 
+
+/* Common definitions */
 #define SYSFS_RESCTRL_PATH "/sys/fs/resctrl"
 
 /* Resctrl is short for Resource Control.  It might be implemented for various
@@ -55,6 +58,308 @@ VIR_ENUM_IMPL(virResctrl, VIR_CACHE_TYPE_LAST,
               "CODE",
               "DATA")
 
+
+/* Info-related definitions and InfoClass-related functions */
+typedef struct _virResctrlInfoPerType virResctrlInfoPerType;
+typedef virResctrlInfoPerType *virResctrlInfoPerTypePtr;
+struct _virResctrlInfoPerType {
+    /* Kernel-provided information */
+    char *cbm_mask;
+    unsigned int min_cbm_bits;
+
+    /* Our computed information from the above */
+    unsigned int bits;
+    unsigned int max_cache_id;
+
+    /* In order to be self-sufficient we need size information per cache.
+     * Funnily enough, one of the outcomes of the resctrlfs design is that it
+     * does not account for different sizes per cache on the same level.  So
+     * for the sake of easiness, let's copy that, for now. */
+    unsigned long long size;
+
+    /* Information that we will return upon request (this is public struct) as
+     * until now all the above is internal to this module */
+    virResctrlInfoPerCache control;
+};
+
+typedef struct _virResctrlInfoPerLevel virResctrlInfoPerLevel;
+typedef virResctrlInfoPerLevel *virResctrlInfoPerLevelPtr;
+struct _virResctrlInfoPerLevel {
+    virResctrlInfoPerTypePtr *types;
+};
+
+struct _virResctrlInfo {
+    virObject parent;
+
+    virResctrlInfoPerLevelPtr *levels;
+    size_t nlevels;
+};
+
+static virClassPtr virResctrlInfoClass;
+
+static void
+virResctrlInfoDispose(void *obj)
+{
+    size_t i = 0;
+    size_t j = 0;
+
+    virResctrlInfoPtr resctrl = obj;
+
+    for (i = 0; i < resctrl->nlevels; i++) {
+        virResctrlInfoPerLevelPtr level = resctrl->levels[i];
+
+        if (!level)
+            continue;
+
+        if (level->types) {
+            for (j = 0; j < VIR_CACHE_TYPE_LAST; j++) {
+                if (level->types[j])
+                    VIR_FREE(level->types[j]->cbm_mask);
+                VIR_FREE(level->types[j]);
+            }
+        }
+        VIR_FREE(level->types);
+        VIR_FREE(level);
+    }
+
+    VIR_FREE(resctrl->levels);
+}
+
+
+static int
+virResctrlInfoOnceInit(void)
+{
+    if (!(virResctrlInfoClass = virClassNew(virClassForObject(),
+                                            "virResctrlInfo",
+                                            sizeof(virResctrlInfo),
+                                            virResctrlInfoDispose)))
+        return -1;
+
+    return 0;
+}
+
+
+VIR_ONCE_GLOBAL_INIT(virResctrlInfo)
+
+
+virResctrlInfoPtr
+virResctrlInfoNew(void)
+{
+    if (virResctrlInfoInitialize() < 0)
+        return NULL;
+
+    return virObjectNew(virResctrlInfoClass);
+}
+
+
+/* Info-related functions */
+bool
+virResctrlInfoIsEmpty(virResctrlInfoPtr resctrl)
+{
+    size_t i = 0;
+    size_t j = 0;
+
+    if (!resctrl)
+        return true;
+
+    for (i = 0; i < resctrl->nlevels; i++) {
+        virResctrlInfoPerLevelPtr i_level = resctrl->levels[i];
+
+        if (!i_level)
+            continue;
+
+        for (j = 0; j < VIR_CACHE_TYPE_LAST; j++) {
+            if (i_level->types[j])
+                return false;
+        }
+    }
+
+    return true;
+}
+
+
+int
+virResctrlGetInfo(virResctrlInfoPtr resctrl)
+{
+    DIR *dirp = NULL;
+    char *info_path = NULL;
+    char *endptr = NULL;
+    char *tmp_str = NULL;
+    int ret = -1;
+    int rv = -1;
+    int type = 0;
+    struct dirent *ent = NULL;
+    unsigned int level = 0;
+    virResctrlInfoPerLevelPtr i_level = NULL;
+    virResctrlInfoPerTypePtr i_type = NULL;
+
+    rv = virDirOpenIfExists(&dirp, SYSFS_RESCTRL_PATH "/info");
+    if (rv <= 0) {
+        ret = rv;
+        goto cleanup;
+    }
+
+    while ((rv = virDirRead(dirp, &ent, SYSFS_RESCTRL_PATH "/info")) > 0) {
+        if (ent->d_type != DT_DIR)
+            continue;
+
+        if (ent->d_name[0] != 'L')
+            continue;
+
+        if (virStrToLong_uip(ent->d_name + 1, &endptr, 10, &level) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Cannot parse resctrl cache info level"));
+            goto cleanup;
+        }
+
+        type = virResctrlTypeFromString(endptr);
+        if (type < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Cannot parse resctrl cache info type"));
+            goto cleanup;
+        }
+
+        if (VIR_ALLOC(i_type) < 0)
+            goto cleanup;
+
+        i_type->control.scope = type;
+
+        rv = virFileReadValueUint(&i_type->control.max_allocation,
+                                  SYSFS_RESCTRL_PATH "/info/%s/num_closids",
+                                  ent->d_name);
+        if (rv == -2)
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Cannot get num_closids from resctrl cache info"));
+        if (rv < 0)
+            goto cleanup;
+
+        rv = virFileReadValueString(&i_type->cbm_mask,
+                                    SYSFS_RESCTRL_PATH
+                                    "/info/%s/cbm_mask",
+                                    ent->d_name);
+        if (rv == -2)
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Cannot get cbm_mask from resctrl cache info"));
+        if (rv < 0)
+            goto cleanup;
+
+        virStringTrimOptionalNewline(i_type->cbm_mask);
+
+        rv = virFileReadValueUint(&i_type->min_cbm_bits,
+                                  SYSFS_RESCTRL_PATH "/info/%s/min_cbm_bits",
+                                  ent->d_name);
+        if (rv == -2)
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Cannot get min_cbm_bits from resctrl cache info"));
+        if (rv < 0)
+            goto cleanup;
+
+        if (resctrl->nlevels <= level &&
+            VIR_EXPAND_N(resctrl->levels, resctrl->nlevels,
+                         level - resctrl->nlevels + 1) < 0)
+            goto cleanup;
+
+        if (!resctrl->levels[level] &&
+            (VIR_ALLOC(resctrl->levels[level]) < 0 ||
+             VIR_ALLOC_N(resctrl->levels[level]->types, VIR_CACHE_TYPE_LAST) < 0))
+            goto cleanup;
+        i_level = resctrl->levels[level];
+
+        if (i_level->types[type]) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Duplicate cache type in resctrlfs for level %u"),
+                           level);
+            goto cleanup;
+        }
+
+        for (tmp_str = i_type->cbm_mask; *tmp_str != '\0'; tmp_str++) {
+            if (!c_isxdigit(*tmp_str)) {
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("Cannot parse cbm_mask from resctrl cache info"));
+                goto cleanup;
+            }
+
+            i_type->bits += count_one_bits(virHexToBin(*tmp_str));
+        }
+
+        VIR_STEAL_PTR(i_level->types[type], i_type);
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_DIR_CLOSE(dirp);
+    VIR_FREE(info_path);
+    if (i_type)
+        VIR_FREE(i_type->cbm_mask);
+    VIR_FREE(i_type);
+    return ret;
+}
+
+
+int
+virResctrlInfoGetCache(virResctrlInfoPtr resctrl,
+                       unsigned int level,
+                       unsigned long long size,
+                       size_t *ncontrols,
+                       virResctrlInfoPerCachePtr **controls)
+{
+    virResctrlInfoPerLevelPtr i_level = NULL;
+    virResctrlInfoPerTypePtr i_type = NULL;
+    size_t i = 0;
+    int ret = -1;
+
+    if (virResctrlInfoIsEmpty(resctrl))
+        return 0;
+
+    if (level >= resctrl->nlevels)
+        return 0;
+
+    i_level = resctrl->levels[level];
+    if (!i_level)
+        return 0;
+
+    for (i = 0; i < VIR_CACHE_TYPE_LAST; i++) {
+        i_type = i_level->types[i];
+        if (!i_type)
+            continue;
+
+        /* Let's take the opportunity to update our internal information about
+         * the cache size */
+        if (!i_type->size) {
+            i_type->size = size;
+            i_type->control.granularity = size / i_type->bits;
+            if (i_type->min_cbm_bits != 1)
+                i_type->control.min = i_type->min_cbm_bits * i_type->control.granularity;
+        } else {
+            if (i_type->size != size) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("level %u cache size %llu doesn not match "
+                                 "expected size %llu"),
+                                 level, i_type->size, size);
+                goto error;
+            }
+            i_type->max_cache_id++;
+        }
+
+        if (VIR_EXPAND_N(*controls, *ncontrols, 1) < 0)
+            goto error;
+        if (VIR_ALLOC((*controls)[*ncontrols - 1]) < 0)
+            goto error;
+
+        memcpy((*controls)[*ncontrols - 1], &i_type->control, sizeof(i_type->control));
+    }
+
+    ret = 0;
+ cleanup:
+    return ret;
+ error:
+    while (*ncontrols)
+        VIR_FREE((*controls)[--*ncontrols]);
+    VIR_FREE(*controls);
+    goto cleanup;
+}
+
+
 int
 virResctrlGetCacheInfo(unsigned int level,
                        unsigned long long size,
diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
index 42e852780318..43063903730b 100644
--- a/src/util/virresctrl.h
+++ b/src/util/virresctrl.h
@@ -49,7 +49,26 @@ struct _virResctrlInfoPerCache {
     unsigned int max_allocation;
 };
 
+typedef struct _virResctrlInfo virResctrlInfo;
+typedef virResctrlInfo *virResctrlInfoPtr;
 
+virResctrlInfoPtr
+virResctrlInfoNew(void);
+
+bool
+virResctrlInfoIsEmpty(virResctrlInfoPtr resctrl);
+
+int
+virResctrlGetInfo(virResctrlInfoPtr resctrl);
+
+int
+virResctrlInfoGetCache(virResctrlInfoPtr resctrl,
+                       unsigned int level,
+                       unsigned long long size,
+                       size_t *ncontrols,
+                       virResctrlInfoPerCachePtr **controls);
+
+/* To be removed */
 int
 virResctrlGetCacheInfo(unsigned int level,
                        unsigned long long size,
-- 
2.16.1

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 02/10] util: Add virResctrlInfo
Posted by Pavel Hrdina 7 years, 3 months ago
On Tue, Jan 23, 2018 at 07:05:11PM +0100, Martin Kletzander wrote:
> This will make the current functions obsolete and it will provide more
> information to the virresctrl module so that it can be used later.
> 
> Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
> ---
>  po/POTFILES.in           |   1 +
>  src/libvirt_private.syms |   3 +
>  src/util/virresctrl.c    | 305 +++++++++++++++++++++++++++++++++++++++++++++++
>  src/util/virresctrl.h    |  19 +++
>  4 files changed, 328 insertions(+)
> 
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index c1fa23427eff..8382ee633621 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -252,6 +252,7 @@ src/util/virportallocator.c
>  src/util/virprocess.c
>  src/util/virqemu.c
>  src/util/virrandom.c
> +src/util/virresctrl.c
>  src/util/virrotatingfile.c
>  src/util/virscsi.c
>  src/util/virscsihost.c
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index bc8cc1fba9e3..e951a5495b3f 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -2554,6 +2554,9 @@ virCacheTypeFromString;
>  virCacheTypeToString;
>  virResctrlGetCacheControlType;
>  virResctrlGetCacheInfo;
> +virResctrlGetInfo;
> +virResctrlInfoGetCache;
> +virResctrlInfoNew;
>  
>  
>  # util/virrotatingfile.h
> diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
> index 050a08178e24..25c11a1314dc 100644
> --- a/src/util/virresctrl.c
> +++ b/src/util/virresctrl.c
> @@ -25,12 +25,15 @@
>  #include "viralloc.h"
>  #include "virfile.h"
>  #include "virlog.h"
> +#include "virobject.h"
>  #include "virstring.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_RESCTRL
>  
>  VIR_LOG_INIT("util.virresctrl")
>  
> +
> +/* Common definitions */
>  #define SYSFS_RESCTRL_PATH "/sys/fs/resctrl"
>  
>  /* Resctrl is short for Resource Control.  It might be implemented for various
> @@ -55,6 +58,308 @@ VIR_ENUM_IMPL(virResctrl, VIR_CACHE_TYPE_LAST,
>                "CODE",
>                "DATA")
>  
> +
> +/* Info-related definitions and InfoClass-related functions */
> +typedef struct _virResctrlInfoPerType virResctrlInfoPerType;
> +typedef virResctrlInfoPerType *virResctrlInfoPerTypePtr;
> +struct _virResctrlInfoPerType {
> +    /* Kernel-provided information */
> +    char *cbm_mask;
> +    unsigned int min_cbm_bits;
> +
> +    /* Our computed information from the above */
> +    unsigned int bits;
> +    unsigned int max_cache_id;
> +
> +    /* In order to be self-sufficient we need size information per cache.
> +     * Funnily enough, one of the outcomes of the resctrlfs design is that it
> +     * does not account for different sizes per cache on the same level.  So
> +     * for the sake of easiness, let's copy that, for now. */
> +    unsigned long long size;
> +
> +    /* Information that we will return upon request (this is public struct) as
> +     * until now all the above is internal to this module */
> +    virResctrlInfoPerCache control;
> +};
> +
> +typedef struct _virResctrlInfoPerLevel virResctrlInfoPerLevel;
> +typedef virResctrlInfoPerLevel *virResctrlInfoPerLevelPtr;
> +struct _virResctrlInfoPerLevel {
> +    virResctrlInfoPerTypePtr *types;
> +};
> +
> +struct _virResctrlInfo {
> +    virObject parent;
> +
> +    virResctrlInfoPerLevelPtr *levels;
> +    size_t nlevels;
> +};
> +
> +static virClassPtr virResctrlInfoClass;
> +
> +static void
> +virResctrlInfoDispose(void *obj)
> +{
> +    size_t i = 0;
> +    size_t j = 0;
> +
> +    virResctrlInfoPtr resctrl = obj;
> +
> +    for (i = 0; i < resctrl->nlevels; i++) {
> +        virResctrlInfoPerLevelPtr level = resctrl->levels[i];
> +
> +        if (!level)
> +            continue;
> +
> +        if (level->types) {
> +            for (j = 0; j < VIR_CACHE_TYPE_LAST; j++) {
> +                if (level->types[j])
> +                    VIR_FREE(level->types[j]->cbm_mask);
> +                VIR_FREE(level->types[j]);
> +            }
> +        }
> +        VIR_FREE(level->types);
> +        VIR_FREE(level);
> +    }
> +
> +    VIR_FREE(resctrl->levels);
> +}
> +
> +
> +static int
> +virResctrlInfoOnceInit(void)
> +{
> +    if (!(virResctrlInfoClass = virClassNew(virClassForObject(),
> +                                            "virResctrlInfo",
> +                                            sizeof(virResctrlInfo),
> +                                            virResctrlInfoDispose)))
> +        return -1;
> +
> +    return 0;
> +}
> +
> +
> +VIR_ONCE_GLOBAL_INIT(virResctrlInfo)
> +
> +
> +virResctrlInfoPtr
> +virResctrlInfoNew(void)
> +{
> +    if (virResctrlInfoInitialize() < 0)
> +        return NULL;
> +
> +    return virObjectNew(virResctrlInfoClass);
> +}
> +
> +
> +/* Info-related functions */
> +bool
> +virResctrlInfoIsEmpty(virResctrlInfoPtr resctrl)
> +{

This one can be static since it's not used outside of this file and
it's not exported in private symbols.

> +    size_t i = 0;
> +    size_t j = 0;
> +
> +    if (!resctrl)
> +        return true;
> +
> +    for (i = 0; i < resctrl->nlevels; i++) {
> +        virResctrlInfoPerLevelPtr i_level = resctrl->levels[i];
> +
> +        if (!i_level)
> +            continue;
> +
> +        for (j = 0; j < VIR_CACHE_TYPE_LAST; j++) {
> +            if (i_level->types[j])
> +                return false;
> +        }
> +    }
> +
> +    return true;
> +}
> +
> +
> +int
> +virResctrlGetInfo(virResctrlInfoPtr resctrl)
> +{
> +    DIR *dirp = NULL;
> +    char *info_path = NULL;
> +    char *endptr = NULL;
> +    char *tmp_str = NULL;
> +    int ret = -1;
> +    int rv = -1;
> +    int type = 0;
> +    struct dirent *ent = NULL;
> +    unsigned int level = 0;
> +    virResctrlInfoPerLevelPtr i_level = NULL;
> +    virResctrlInfoPerTypePtr i_type = NULL;
> +
> +    rv = virDirOpenIfExists(&dirp, SYSFS_RESCTRL_PATH "/info");
> +    if (rv <= 0) {
> +        ret = rv;
> +        goto cleanup;
> +    }
> +
> +    while ((rv = virDirRead(dirp, &ent, SYSFS_RESCTRL_PATH "/info")) > 0) {
> +        if (ent->d_type != DT_DIR)
> +            continue;
> +
> +        if (ent->d_name[0] != 'L')
> +            continue;
> +
> +        if (virStrToLong_uip(ent->d_name + 1, &endptr, 10, &level) < 0) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("Cannot parse resctrl cache info level"));
> +            goto cleanup;
> +        }
> +
> +        type = virResctrlTypeFromString(endptr);
> +        if (type < 0) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("Cannot parse resctrl cache info type"));
> +            goto cleanup;
> +        }
> +
> +        if (VIR_ALLOC(i_type) < 0)
> +            goto cleanup;
> +
> +        i_type->control.scope = type;
> +
> +        rv = virFileReadValueUint(&i_type->control.max_allocation,
> +                                  SYSFS_RESCTRL_PATH "/info/%s/num_closids",
> +                                  ent->d_name);
> +        if (rv == -2)
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("Cannot get num_closids from resctrl cache info"));
> +        if (rv < 0)
> +            goto cleanup;
> +
> +        rv = virFileReadValueString(&i_type->cbm_mask,
> +                                    SYSFS_RESCTRL_PATH
> +                                    "/info/%s/cbm_mask",
> +                                    ent->d_name);
> +        if (rv == -2)
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("Cannot get cbm_mask from resctrl cache info"));
> +        if (rv < 0)
> +            goto cleanup;
> +
> +        virStringTrimOptionalNewline(i_type->cbm_mask);
> +
> +        rv = virFileReadValueUint(&i_type->min_cbm_bits,
> +                                  SYSFS_RESCTRL_PATH "/info/%s/min_cbm_bits",
> +                                  ent->d_name);
> +        if (rv == -2)
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("Cannot get min_cbm_bits from resctrl cache info"));
> +        if (rv < 0)
> +            goto cleanup;
> +
> +        if (resctrl->nlevels <= level &&
> +            VIR_EXPAND_N(resctrl->levels, resctrl->nlevels,
> +                         level - resctrl->nlevels + 1) < 0)
> +            goto cleanup;
> +
> +        if (!resctrl->levels[level] &&
> +            (VIR_ALLOC(resctrl->levels[level]) < 0 ||
> +             VIR_ALLOC_N(resctrl->levels[level]->types, VIR_CACHE_TYPE_LAST) < 0))
> +            goto cleanup;
> +        i_level = resctrl->levels[level];
> +
> +        if (i_level->types[type]) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR,
> +                           _("Duplicate cache type in resctrlfs for level %u"),
> +                           level);
> +            goto cleanup;
> +        }
> +
> +        for (tmp_str = i_type->cbm_mask; *tmp_str != '\0'; tmp_str++) {
> +            if (!c_isxdigit(*tmp_str)) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                               _("Cannot parse cbm_mask from resctrl cache info"));
> +                goto cleanup;
> +            }
> +
> +            i_type->bits += count_one_bits(virHexToBin(*tmp_str));
> +        }
> +
> +        VIR_STEAL_PTR(i_level->types[type], i_type);
> +    }
> +
> +    ret = 0;
> + cleanup:
> +    VIR_DIR_CLOSE(dirp);
> +    VIR_FREE(info_path);
> +    if (i_type)
> +        VIR_FREE(i_type->cbm_mask);
> +    VIR_FREE(i_type);
> +    return ret;
> +}
> +
> +
> +int
> +virResctrlInfoGetCache(virResctrlInfoPtr resctrl,
> +                       unsigned int level,
> +                       unsigned long long size,
> +                       size_t *ncontrols,
> +                       virResctrlInfoPerCachePtr **controls)
> +{
> +    virResctrlInfoPerLevelPtr i_level = NULL;
> +    virResctrlInfoPerTypePtr i_type = NULL;
> +    size_t i = 0;
> +    int ret = -1;
> +
> +    if (virResctrlInfoIsEmpty(resctrl))
> +        return 0;
> +
> +    if (level >= resctrl->nlevels)
> +        return 0;
> +
> +    i_level = resctrl->levels[level];
> +    if (!i_level)
> +        return 0;
> +
> +    for (i = 0; i < VIR_CACHE_TYPE_LAST; i++) {
> +        i_type = i_level->types[i];
> +        if (!i_type)
> +            continue;
> +
> +        /* Let's take the opportunity to update our internal information about
> +         * the cache size */
> +        if (!i_type->size) {
> +            i_type->size = size;
> +            i_type->control.granularity = size / i_type->bits;
> +            if (i_type->min_cbm_bits != 1)
> +                i_type->control.min = i_type->min_cbm_bits * i_type->control.granularity;
> +        } else {
> +            if (i_type->size != size) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR,
> +                               _("level %u cache size %llu doesn not match "

s/doesn/does/

With the issues fixed

Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list