|
|
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 |
|