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 <[email protected]> > --- > 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 <[email protected]>
signature.asc
Description: PGP signature
-- libvir-list mailing list [email protected] https://www.redhat.com/mailman/listinfo/libvir-list
