404507
From 6c23daa9238671767dec5c43387be996a066196f Mon Sep 17 00:00:00 2001
404507
Message-Id: <6c23daa9238671767dec5c43387be996a066196f@dist-git>
404507
From: Martin Kletzander <mkletzan@redhat.com>
404507
Date: Wed, 31 Jan 2018 16:32:25 +0100
404507
Subject: [PATCH] util: Add virResctrlInfo
404507
404507
https://bugzilla.redhat.com/show_bug.cgi?id=1289368
404507
404507
This will make the current functions obsolete and it will provide more
404507
information to the virresctrl module so that it can be used later.
404507
404507
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
404507
(cherry picked from commit cd572df89bc43405a970ad207b32f23c73bdaa75)
404507
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
404507
---
404507
 po/POTFILES.in           |   1 +
404507
 src/libvirt_private.syms |   3 +
404507
 src/util/virresctrl.c    | 305 +++++++++++++++++++++++++++++++++++++++++++++++
404507
 src/util/virresctrl.h    |  16 +++
404507
 4 files changed, 325 insertions(+)
404507
404507
diff --git a/po/POTFILES.in b/po/POTFILES.in
404507
index c1fa23427e..8382ee6336 100644
404507
--- a/po/POTFILES.in
404507
+++ b/po/POTFILES.in
404507
@@ -252,6 +252,7 @@ src/util/virportallocator.c
404507
 src/util/virprocess.c
404507
 src/util/virqemu.c
404507
 src/util/virrandom.c
404507
+src/util/virresctrl.c
404507
 src/util/virrotatingfile.c
404507
 src/util/virscsi.c
404507
 src/util/virscsihost.c
404507
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
404507
index 7dd4621b70..e0e0046522 100644
404507
--- a/src/libvirt_private.syms
404507
+++ b/src/libvirt_private.syms
404507
@@ -2549,6 +2549,9 @@ virCacheTypeFromString;
404507
 virCacheTypeToString;
404507
 virResctrlGetCacheControlType;
404507
 virResctrlGetCacheInfo;
404507
+virResctrlGetInfo;
404507
+virResctrlInfoGetCache;
404507
+virResctrlInfoNew;
404507
 
404507
 
404507
 # util/virrotatingfile.h
404507
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
404507
index 050a08178e..7ab68c6f74 100644
404507
--- a/src/util/virresctrl.c
404507
+++ b/src/util/virresctrl.c
404507
@@ -25,12 +25,15 @@
404507
 #include "viralloc.h"
404507
 #include "virfile.h"
404507
 #include "virlog.h"
404507
+#include "virobject.h"
404507
 #include "virstring.h"
404507
 
404507
 #define VIR_FROM_THIS VIR_FROM_RESCTRL
404507
 
404507
 VIR_LOG_INIT("util.virresctrl")
404507
 
404507
+
404507
+/* Common definitions */
404507
 #define SYSFS_RESCTRL_PATH "/sys/fs/resctrl"
404507
 
404507
 /* Resctrl is short for Resource Control.  It might be implemented for various
404507
@@ -55,6 +58,308 @@ VIR_ENUM_IMPL(virResctrl, VIR_CACHE_TYPE_LAST,
404507
               "CODE",
404507
               "DATA")
404507
 
404507
+
404507
+/* Info-related definitions and InfoClass-related functions */
404507
+typedef struct _virResctrlInfoPerType virResctrlInfoPerType;
404507
+typedef virResctrlInfoPerType *virResctrlInfoPerTypePtr;
404507
+struct _virResctrlInfoPerType {
404507
+    /* Kernel-provided information */
404507
+    char *cbm_mask;
404507
+    unsigned int min_cbm_bits;
404507
+
404507
+    /* Our computed information from the above */
404507
+    unsigned int bits;
404507
+    unsigned int max_cache_id;
404507
+
404507
+    /* In order to be self-sufficient we need size information per cache.
404507
+     * Funnily enough, one of the outcomes of the resctrlfs design is that it
404507
+     * does not account for different sizes per cache on the same level.  So
404507
+     * for the sake of easiness, let's copy that, for now. */
404507
+    unsigned long long size;
404507
+
404507
+    /* Information that we will return upon request (this is public struct) as
404507
+     * until now all the above is internal to this module */
404507
+    virResctrlInfoPerCache control;
404507
+};
404507
+
404507
+typedef struct _virResctrlInfoPerLevel virResctrlInfoPerLevel;
404507
+typedef virResctrlInfoPerLevel *virResctrlInfoPerLevelPtr;
404507
+struct _virResctrlInfoPerLevel {
404507
+    virResctrlInfoPerTypePtr *types;
404507
+};
404507
+
404507
+struct _virResctrlInfo {
404507
+    virObject parent;
404507
+
404507
+    virResctrlInfoPerLevelPtr *levels;
404507
+    size_t nlevels;
404507
+};
404507
+
404507
+static virClassPtr virResctrlInfoClass;
404507
+
404507
+static void
404507
+virResctrlInfoDispose(void *obj)
404507
+{
404507
+    size_t i = 0;
404507
+    size_t j = 0;
404507
+
404507
+    virResctrlInfoPtr resctrl = obj;
404507
+
404507
+    for (i = 0; i < resctrl->nlevels; i++) {
404507
+        virResctrlInfoPerLevelPtr level = resctrl->levels[i];
404507
+
404507
+        if (!level)
404507
+            continue;
404507
+
404507
+        if (level->types) {
404507
+            for (j = 0; j < VIR_CACHE_TYPE_LAST; j++) {
404507
+                if (level->types[j])
404507
+                    VIR_FREE(level->types[j]->cbm_mask);
404507
+                VIR_FREE(level->types[j]);
404507
+            }
404507
+        }
404507
+        VIR_FREE(level->types);
404507
+        VIR_FREE(level);
404507
+    }
404507
+
404507
+    VIR_FREE(resctrl->levels);
404507
+}
404507
+
404507
+
404507
+static int
404507
+virResctrlInfoOnceInit(void)
404507
+{
404507
+    if (!(virResctrlInfoClass = virClassNew(virClassForObject(),
404507
+                                            "virResctrlInfo",
404507
+                                            sizeof(virResctrlInfo),
404507
+                                            virResctrlInfoDispose)))
404507
+        return -1;
404507
+
404507
+    return 0;
404507
+}
404507
+
404507
+
404507
+VIR_ONCE_GLOBAL_INIT(virResctrlInfo)
404507
+
404507
+
404507
+virResctrlInfoPtr
404507
+virResctrlInfoNew(void)
404507
+{
404507
+    if (virResctrlInfoInitialize() < 0)
404507
+        return NULL;
404507
+
404507
+    return virObjectNew(virResctrlInfoClass);
404507
+}
404507
+
404507
+
404507
+/* Info-related functions */
404507
+static bool
404507
+virResctrlInfoIsEmpty(virResctrlInfoPtr resctrl)
404507
+{
404507
+    size_t i = 0;
404507
+    size_t j = 0;
404507
+
404507
+    if (!resctrl)
404507
+        return true;
404507
+
404507
+    for (i = 0; i < resctrl->nlevels; i++) {
404507
+        virResctrlInfoPerLevelPtr i_level = resctrl->levels[i];
404507
+
404507
+        if (!i_level)
404507
+            continue;
404507
+
404507
+        for (j = 0; j < VIR_CACHE_TYPE_LAST; j++) {
404507
+            if (i_level->types[j])
404507
+                return false;
404507
+        }
404507
+    }
404507
+
404507
+    return true;
404507
+}
404507
+
404507
+
404507
+int
404507
+virResctrlGetInfo(virResctrlInfoPtr resctrl)
404507
+{
404507
+    DIR *dirp = NULL;
404507
+    char *info_path = NULL;
404507
+    char *endptr = NULL;
404507
+    char *tmp_str = NULL;
404507
+    int ret = -1;
404507
+    int rv = -1;
404507
+    int type = 0;
404507
+    struct dirent *ent = NULL;
404507
+    unsigned int level = 0;
404507
+    virResctrlInfoPerLevelPtr i_level = NULL;
404507
+    virResctrlInfoPerTypePtr i_type = NULL;
404507
+
404507
+    rv = virDirOpenIfExists(&dirp, SYSFS_RESCTRL_PATH "/info");
404507
+    if (rv <= 0) {
404507
+        ret = rv;
404507
+        goto cleanup;
404507
+    }
404507
+
404507
+    while ((rv = virDirRead(dirp, &ent, SYSFS_RESCTRL_PATH "/info")) > 0) {
404507
+        if (ent->d_type != DT_DIR)
404507
+            continue;
404507
+
404507
+        if (ent->d_name[0] != 'L')
404507
+            continue;
404507
+
404507
+        if (virStrToLong_uip(ent->d_name + 1, &endptr, 10, &level) < 0) {
404507
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
404507
+                           _("Cannot parse resctrl cache info level"));
404507
+            goto cleanup;
404507
+        }
404507
+
404507
+        type = virResctrlTypeFromString(endptr);
404507
+        if (type < 0) {
404507
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
404507
+                           _("Cannot parse resctrl cache info type"));
404507
+            goto cleanup;
404507
+        }
404507
+
404507
+        if (VIR_ALLOC(i_type) < 0)
404507
+            goto cleanup;
404507
+
404507
+        i_type->control.scope = type;
404507
+
404507
+        rv = virFileReadValueUint(&i_type->control.max_allocation,
404507
+                                  SYSFS_RESCTRL_PATH "/info/%s/num_closids",
404507
+                                  ent->d_name);
404507
+        if (rv == -2)
404507
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
404507
+                           _("Cannot get num_closids from resctrl cache info"));
404507
+        if (rv < 0)
404507
+            goto cleanup;
404507
+
404507
+        rv = virFileReadValueString(&i_type->cbm_mask,
404507
+                                    SYSFS_RESCTRL_PATH
404507
+                                    "/info/%s/cbm_mask",
404507
+                                    ent->d_name);
404507
+        if (rv == -2)
404507
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
404507
+                           _("Cannot get cbm_mask from resctrl cache info"));
404507
+        if (rv < 0)
404507
+            goto cleanup;
404507
+
404507
+        virStringTrimOptionalNewline(i_type->cbm_mask);
404507
+
404507
+        rv = virFileReadValueUint(&i_type->min_cbm_bits,
404507
+                                  SYSFS_RESCTRL_PATH "/info/%s/min_cbm_bits",
404507
+                                  ent->d_name);
404507
+        if (rv == -2)
404507
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
404507
+                           _("Cannot get min_cbm_bits from resctrl cache info"));
404507
+        if (rv < 0)
404507
+            goto cleanup;
404507
+
404507
+        if (resctrl->nlevels <= level &&
404507
+            VIR_EXPAND_N(resctrl->levels, resctrl->nlevels,
404507
+                         level - resctrl->nlevels + 1) < 0)
404507
+            goto cleanup;
404507
+
404507
+        if (!resctrl->levels[level] &&
404507
+            (VIR_ALLOC(resctrl->levels[level]) < 0 ||
404507
+             VIR_ALLOC_N(resctrl->levels[level]->types, VIR_CACHE_TYPE_LAST) < 0))
404507
+            goto cleanup;
404507
+        i_level = resctrl->levels[level];
404507
+
404507
+        if (i_level->types[type]) {
404507
+            virReportError(VIR_ERR_INTERNAL_ERROR,
404507
+                           _("Duplicate cache type in resctrlfs for level %u"),
404507
+                           level);
404507
+            goto cleanup;
404507
+        }
404507
+
404507
+        for (tmp_str = i_type->cbm_mask; *tmp_str != '\0'; tmp_str++) {
404507
+            if (!c_isxdigit(*tmp_str)) {
404507
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
404507
+                               _("Cannot parse cbm_mask from resctrl cache info"));
404507
+                goto cleanup;
404507
+            }
404507
+
404507
+            i_type->bits += count_one_bits(virHexToBin(*tmp_str));
404507
+        }
404507
+
404507
+        VIR_STEAL_PTR(i_level->types[type], i_type);
404507
+    }
404507
+
404507
+    ret = 0;
404507
+ cleanup:
404507
+    VIR_DIR_CLOSE(dirp);
404507
+    VIR_FREE(info_path);
404507
+    if (i_type)
404507
+        VIR_FREE(i_type->cbm_mask);
404507
+    VIR_FREE(i_type);
404507
+    return ret;
404507
+}
404507
+
404507
+
404507
+int
404507
+virResctrlInfoGetCache(virResctrlInfoPtr resctrl,
404507
+                       unsigned int level,
404507
+                       unsigned long long size,
404507
+                       size_t *ncontrols,
404507
+                       virResctrlInfoPerCachePtr **controls)
404507
+{
404507
+    virResctrlInfoPerLevelPtr i_level = NULL;
404507
+    virResctrlInfoPerTypePtr i_type = NULL;
404507
+    size_t i = 0;
404507
+    int ret = -1;
404507
+
404507
+    if (virResctrlInfoIsEmpty(resctrl))
404507
+        return 0;
404507
+
404507
+    if (level >= resctrl->nlevels)
404507
+        return 0;
404507
+
404507
+    i_level = resctrl->levels[level];
404507
+    if (!i_level)
404507
+        return 0;
404507
+
404507
+    for (i = 0; i < VIR_CACHE_TYPE_LAST; i++) {
404507
+        i_type = i_level->types[i];
404507
+        if (!i_type)
404507
+            continue;
404507
+
404507
+        /* Let's take the opportunity to update our internal information about
404507
+         * the cache size */
404507
+        if (!i_type->size) {
404507
+            i_type->size = size;
404507
+            i_type->control.granularity = size / i_type->bits;
404507
+            if (i_type->min_cbm_bits != 1)
404507
+                i_type->control.min = i_type->min_cbm_bits * i_type->control.granularity;
404507
+        } else {
404507
+            if (i_type->size != size) {
404507
+                virReportError(VIR_ERR_INTERNAL_ERROR,
404507
+                               _("level %u cache size %llu does not match "
404507
+                                 "expected size %llu"),
404507
+                                 level, i_type->size, size);
404507
+                goto error;
404507
+            }
404507
+            i_type->max_cache_id++;
404507
+        }
404507
+
404507
+        if (VIR_EXPAND_N(*controls, *ncontrols, 1) < 0)
404507
+            goto error;
404507
+        if (VIR_ALLOC((*controls)[*ncontrols - 1]) < 0)
404507
+            goto error;
404507
+
404507
+        memcpy((*controls)[*ncontrols - 1], &i_type->control, sizeof(i_type->control));
404507
+    }
404507
+
404507
+    ret = 0;
404507
+ cleanup:
404507
+    return ret;
404507
+ error:
404507
+    while (*ncontrols)
404507
+        VIR_FREE((*controls)[--*ncontrols]);
404507
+    VIR_FREE(*controls);
404507
+    goto cleanup;
404507
+}
404507
+
404507
+
404507
 int
404507
 virResctrlGetCacheInfo(unsigned int level,
404507
                        unsigned long long size,
404507
diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
404507
index 42e8527803..c7f25c76e1 100644
404507
--- a/src/util/virresctrl.h
404507
+++ b/src/util/virresctrl.h
404507
@@ -49,7 +49,23 @@ struct _virResctrlInfoPerCache {
404507
     unsigned int max_allocation;
404507
 };
404507
 
404507
+typedef struct _virResctrlInfo virResctrlInfo;
404507
+typedef virResctrlInfo *virResctrlInfoPtr;
404507
 
404507
+virResctrlInfoPtr
404507
+virResctrlInfoNew(void);
404507
+
404507
+int
404507
+virResctrlGetInfo(virResctrlInfoPtr resctrl);
404507
+
404507
+int
404507
+virResctrlInfoGetCache(virResctrlInfoPtr resctrl,
404507
+                       unsigned int level,
404507
+                       unsigned long long size,
404507
+                       size_t *ncontrols,
404507
+                       virResctrlInfoPerCachePtr **controls);
404507
+
404507
+/* To be removed */
404507
 int
404507
 virResctrlGetCacheInfo(unsigned int level,
404507
                        unsigned long long size,
404507
-- 
404507
2.16.1
404507