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 | 301 +++++++++++++++++++++++++++++++++++++++++++++++
src/util/virresctrl.h | 19 +++
4 files changed, 324 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 de4ec4d442c9..75be612a2f13 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2550,6 +2550,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..6fd1ceb587cf 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,304 @@ 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;
+
+ 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;
+
+ virStringTrimOptionalNewline(i_type->cbm_mask);
+
+ 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);
+ 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,
+ _("Forbidden inconsistency for resctrlfs, "
+ "level %u caches have different sizes"),
+ level);
+ 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.15.1
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
On 12/13/2017 10:39 AM, 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 | 301 +++++++++++++++++++++++++++++++++++++++++++++++
> src/util/virresctrl.h | 19 +++
> 4 files changed, 324 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 de4ec4d442c9..75be612a2f13 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -2550,6 +2550,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..6fd1ceb587cf 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,304 @@ 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)
static int
virRes....
> +{
> + 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;
> +}
> +
Two blank lines
> +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;
> +
> + 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;
> +
> + virStringTrimOptionalNewline(i_type->cbm_mask);
Move this up a few lines to after cbm_mask successfully read...
> +
> + 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);
> + VIR_FREE(i_type);
In a cleanup/failure path i_type.cbm_mask is leaked, thus before this
if (i_type)
VIR_FREE(i_type->cbm_mask);
or go with the VIR_STEAL_PTR type logic for a local @cbm_mask to be
stored in i_type->cbm_mask (IDC whichever way you prefer)
> + 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) {
Not really a boolean or pointer comparison...
> + 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,
> + _("Forbidden inconsistency for resctrlfs, "
> + "level %u caches have different sizes"),
level %u cache size %llu not match expected %llu
levek, i_type->size, size
> + level);
> + 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:
Is this really necessary? The caller on failure will call
virCapsHostCacheBankFree(bank) which does the free's.
> + 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 */
Superfluous, but IDC
Reviewed-by: John Ferlan <jferlan@redhat.com>
John
> int
> virResctrlGetCacheInfo(unsigned int level,
> unsigned long long size,
>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
On Tue, Jan 02, 2018 at 03:08:30PM -0500, John Ferlan wrote:
>
>
>On 12/13/2017 10:39 AM, 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 | 301 +++++++++++++++++++++++++++++++++++++++++++++++
>> src/util/virresctrl.h | 19 +++
>> 4 files changed, 324 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 de4ec4d442c9..75be612a2f13 100644
>> --- a/src/libvirt_private.syms
>> +++ b/src/libvirt_private.syms
>> @@ -2550,6 +2550,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..6fd1ceb587cf 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,304 @@ 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)
>
>static int
>virRes....
>
>> +{
>> + 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;
>> +}
>> +
>
>Two blank lines
>
>> +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;
>> +
>> + 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;
>> +
>> + virStringTrimOptionalNewline(i_type->cbm_mask);
>
>Move this up a few lines to after cbm_mask successfully read...
>
>> +
>> + 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);
>> + VIR_FREE(i_type);
>
>In a cleanup/failure path i_type.cbm_mask is leaked, thus before this
>
>if (i_type)
> VIR_FREE(i_type->cbm_mask);
>
>or go with the VIR_STEAL_PTR type logic for a local @cbm_mask to be
>stored in i_type->cbm_mask (IDC whichever way you prefer)
>
>> + 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) {
>
>Not really a boolean or pointer comparison...
>
>> + 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,
>> + _("Forbidden inconsistency for resctrlfs, "
>> + "level %u caches have different sizes"),
>
>level %u cache size %llu not match expected %llu
>levek, i_type->size, size
>
>> + level);
>> + 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:
>
>Is this really necessary? The caller on failure will call
>virCapsHostCacheBankFree(bank) which does the free's.
>
It's not, but it's good coding practice not leaving anything (that you were
changing/allocating) in an inconsistent state when exiting a function.
Fixed everything else.--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
© 2016 - 2026 Red Hat, Inc.