<div>
                    hello,</div><div>ping
                </div>
                <div></div>
                 
                <p style="color: #A0A0A8;">On Monday, 12 June 2017 at 5:48 PM, Eli Qiao wrote:</p>
                <blockquote type="cite" style="border-left-style:solid;border-width:1px;margin-left:0px;padding-left:10px;">
                    <span><div><div><div>This patch adds 3 major private interface.</div><div><br></div><div>virResctrlGetFreeCache: return free cache, default cache substract cache</div><div>                        allocated.</div><div>virResctrlSetCachetunes: set cache banks which defined in a domain.</div><div>virResctrlRemoveCachetunes: remove cache allocation group from the</div><div>                            host.</div><div><br></div><div>There's some existed issue when do syntax-check as I reference the cache</div><div>tune and cachebank definition (from conf/domain_conf.h) in</div><div>util/virresctrl.h.</div><div>---</div><div> include/libvirt/virterror.h               |   1 +</div><div> src/<a href="http://Makefile.am">Makefile.am</a>                           |   1 +</div><div> src/libvirt_private.syms                  |   9 +</div><div> src/qemu/qemu_process.c                   |  54 ++</div><div> src/util/virerror.c                       |   1 +</div><div> src/util/virresctrl.c                     | 851 ++++++++++++++++++++++++++++++</div><div> src/util/virresctrl.h                     |  79 +++</div><div> tests/<a href="http://Makefile.am">Makefile.am</a>                         |   8 +-</div><div> tests/virresctrldata/L3-free.schemata     |   1 +</div><div> tests/virresctrldata/L3CODE-free.schemata |   1 +</div><div> tests/virresctrldata/L3DATA-free.schemata |   1 +</div><div> tests/virresctrldata/linux-resctrl        |   1 +</div><div> tests/virresctrldata/linux-resctrl-cdp    |   1 +</div><div> tests/virresctrltest.c                    | 119 +++++</div><div> 14 files changed, 1127 insertions(+), 1 deletion(-)</div><div> create mode 100644 src/util/virresctrl.c</div><div> create mode 100644 src/util/virresctrl.h</div><div> create mode 100644 tests/virresctrldata/L3-free.schemata</div><div> create mode 100644 tests/virresctrldata/L3CODE-free.schemata</div><div> create mode 100644 tests/virresctrldata/L3DATA-free.schemata</div><div> create mode 120000 tests/virresctrldata/linux-resctrl</div><div> create mode 120000 tests/virresctrldata/linux-resctrl-cdp</div><div> create mode 100644 tests/virresctrltest.c</div><div><br></div><div>diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h</div><div>index 2efee8f..4bc0c74 100644</div><div>--- a/include/libvirt/virterror.h</div><div>+++ b/include/libvirt/virterror.h</div><div>@@ -132,6 +132,7 @@ typedef enum {</div><div> </div><div>     VIR_FROM_PERF = 65,         /* Error from perf */</div><div>     VIR_FROM_LIBSSH = 66,       /* Error from libssh connection transport */</div><div>+    VIR_FROM_RESCTRL = 67,      /* Error from resctrl */</div><div> </div><div> # ifdef VIR_ENUM_SENTINELS</div><div>     VIR_ERR_DOMAIN_LAST</div><div>diff --git a/src/<a href="http://Makefile.am">Makefile.am</a> b/src/<a href="http://Makefile.am">Makefile.am</a></div><div>index eae32dc..8dbb778 100644</div><div>--- a/src/<a href="http://Makefile.am">Makefile.am</a></div><div>+++ b/src/<a href="http://Makefile.am">Makefile.am</a></div><div>@@ -167,6 +167,7 @@ UTIL_SOURCES =                                                       \</div><div>                util/virprocess.c util/virprocess.h             \</div><div>                util/virqemu.c util/virqemu.h                   \</div><div>                util/virrandom.h util/virrandom.c               \</div><div>+               util/virresctrl.h util/virresctrl.c             \</div><div>                util/virrotatingfile.h util/virrotatingfile.c   \</div><div>                util/virscsi.c util/virscsi.h                   \</div><div>                util/virscsihost.c util/virscsihost.h           \</div><div>diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms</div><div>index b6c828f..7392cfa 100644</div><div>--- a/src/libvirt_private.syms</div><div>+++ b/src/libvirt_private.syms</div><div>@@ -2440,6 +2440,15 @@ virRandomGenerateWWN;</div><div> virRandomInt;</div><div> </div><div> </div><div>+# util/virresctrl.h</div><div>+virResctrlBitmap2String;</div><div>+virResctrlFreeSchemata;</div><div>+virResctrlGetFreeCache;</div><div>+virResctrlRemoveCachetunes;</div><div>+virResctrlSetCachetunes;</div><div>+virResctrlTypeToString;</div><div>+</div><div>+</div><div> # util/virrotatingfile.h</div><div> virRotatingFileReaderConsume;</div><div> virRotatingFileReaderFree;</div><div>diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c</div><div>index 4a66f0d..8efeb19 100644</div><div>--- a/src/qemu/qemu_process.c</div><div>+++ b/src/qemu/qemu_process.c</div><div>@@ -70,6 +70,7 @@</div><div> #include "virbitmap.h"</div><div> #include "viratomic.h"</div><div> #include "virnuma.h"</div><div>+#include "virresctrl.h"</div><div> #include "virstring.h"</div><div> #include "virhostdev.h"</div><div> #include "secret_util.h"</div><div>@@ -5088,6 +5089,51 @@ qemuProcessSetupVcpus(virDomainObjPtr vm)</div><div>     return 0;</div><div> }</div><div> </div><div>+static int</div><div>+qemuProcessSetCacheBanks(virCapsHostPtr caps, virDomainObjPtr vm)</div><div>+{</div><div>+    size_t i, j;</div><div>+    virDomainCachetunePtr cachetune;</div><div>+    unsigned int max_vcpus = virDomainDefGetVcpusMax(vm->def);</div><div>+    pid_t *pids = NULL;</div><div>+    virDomainVcpuDefPtr vcpu;</div><div>+    size_t npid = 0;</div><div>+    size_t count = 0;</div><div>+    int ret = -1;</div><div>+</div><div>+    cachetune = &(vm->def->cachetune);</div><div>+</div><div>+    for (i = 0; i < cachetune->n_banks; i++) {</div><div>+        if (cachetune->cache_banks[i].vcpus) {</div><div>+            for (j = 0; j < max_vcpus; j++) {</div><div>+                if (virBitmapIsBitSet(cachetune->cache_banks[i].vcpus, j)) {</div><div>+</div><div>+                    vcpu = virDomainDefGetVcpu(vm->def, j);</div><div>+                    if (!vcpu->online)</div><div>+                        continue;</div><div>+</div><div>+                    if (VIR_RESIZE_N(pids, npid, count, 1) < 0)</div><div>+                        goto cleanup;</div><div>+                    pids[count ++] = qemuDomainGetVcpuPid(vm, j);</div><div>+                }</div><div>+            }</div><div>+        }</div><div>+    }</div><div>+</div><div>+    /* If not specify vcpus in cachetune, add vm->pid */</div><div>+    if (pids == NULL) {</div><div>+        if (VIR_ALLOC_N(pids, 1) < 0)</div><div>+            goto cleanup;</div><div>+        pids[0] = vm->pid;</div><div>+        count = 1;</div><div>+    }</div><div>+    ret = virResctrlSetCachetunes(caps, cachetune, vm->def->uuid, pids, count);</div><div>+</div><div>+ cleanup:</div><div>+    VIR_FREE(pids);</div><div>+    return ret;</div><div>+}</div><div>+</div><div> </div><div> int</div><div> qemuProcessSetupIOThread(virDomainObjPtr vm,</div><div>@@ -5914,6 +5960,11 @@ qemuProcessLaunch(virConnectPtr conn,</div><div>         qemuProcessAutoDestroyAdd(driver, vm, conn) < 0)</div><div>         goto cleanup;</div><div> </div><div>+    VIR_WARN("Cache allocation");</div><div>+    if (qemuProcessSetCacheBanks(&(driver->caps->host),</div><div>+                                 vm) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>     ret = 0;</div><div> </div><div>  cleanup:</div><div>@@ -6419,6 +6470,9 @@ void qemuProcessStop(virQEMUDriverPtr driver,</div><div>     virPerfFree(priv->perf);</div><div>     priv->perf = NULL;</div><div> </div><div>+    if (&(vm->def->cachetune) != NULL)</div><div>+        virResctrlRemoveCachetunes(vm->def->uuid);</div><div>+</div><div>     qemuProcessRemoveDomainStatus(driver, vm);</div><div> </div><div>     /* Remove VNC and Spice ports from port reservation bitmap, but only if</div><div>diff --git a/src/util/virerror.c b/src/util/virerror.c</div><div>index ef17fb5..02fabcc 100644</div><div>--- a/src/util/virerror.c</div><div>+++ b/src/util/virerror.c</div><div>@@ -139,6 +139,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,</div><div> </div><div>               "Perf", /* 65 */</div><div>               "Libssh transport layer",</div><div>+              "Resource Control",</div><div>     )</div><div> </div><div> </div><div>diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c</div><div>new file mode 100644</div><div>index 0000000..89bc43e</div><div>--- /dev/null</div><div>+++ b/src/util/virresctrl.c</div><div>@@ -0,0 +1,851 @@</div><div>+/*</div><div>+ * virresctrl.c: methods for managing resource control</div><div>+ *</div><div>+ * Copyright (C) 2017 Intel, Inc.</div><div>+ *</div><div>+ * This library is free software; you can redistribute it and/or</div><div>+ * modify it under the terms of the GNU Lesser General Public</div><div>+ * License as published by the Free Software Foundation; either</div><div>+ * version 2.1 of the License, or (at your option) any later version.</div><div>+ *</div><div>+ * This library is distributed in the hope that it will be useful,</div><div>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</div><div>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU</div><div>+ * Lesser General Public License for more details.</div><div>+ *</div><div>+ * You should have received a copy of the GNU Lesser General Public</div><div>+ * License along with this library.  If not, see</div><div>+ * <<a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.</div><div>+ *</div><div>+ * Authors:</div><div>+ *  Eli Qiao <<a href="mailto:liyong.qiao@intel.com">liyong.qiao@intel.com</a>></div><div>+ */</div><div>+</div><div>+#include <config.h></div><div>+#include <fcntl.h></div><div>+#include <sys/file.h></div><div>+#include <sys/stat.h></div><div>+#include <sys/types.h></div><div>+</div><div>+#include "virresctrl.h"</div><div>+#include "virerror.h"</div><div>+#include "virlog.h"</div><div>+#include "viralloc.h"</div><div>+#include "virstring.h"</div><div>+#include "virfile.h"</div><div>+</div><div>+VIR_LOG_INIT("util.resctrl");</div><div>+</div><div>+#define VIR_FROM_THIS VIR_FROM_RESCTRL</div><div>+#define SYSFS_RESCTRL_PATH "/sys/fs/resctrl"</div><div>+#define MAX_CBM_LEN 20</div><div>+#define VIR_RESCTRL_LOCK(fd, op) flock(fd, op)</div><div>+#define VIR_RESCTRL_UNLOCK(fd) flock(fd, LOCK_UN)</div><div>+#define CONSTRUCT_RESCTRL_PATH(domain_name, item_name) \</div><div>+do { \</div><div>+    if (NULL == domain_name) { \</div><div>+        if (virAsprintf(&path, "%s/%s", SYSFS_RESCTRL_PATH, item_name) < 0) \</div><div>+            return -1; \</div><div>+    } else { \</div><div>+        if (virAsprintf(&path, "%s/%s/%s", SYSFS_RESCTRL_PATH, domain_name, \</div><div>+                        item_name) < 0) \</div><div>+            return -1;  \</div><div>+    } \</div><div>+} while (0)</div><div>+</div><div>+VIR_ENUM_IMPL(virResctrl, VIR_RESCTRL_TYPE_LAST,</div><div>+              "L3",</div><div>+              "L3CODE",</div><div>+              "L3DATA")</div><div>+</div><div>+/**</div><div>+ * a virResctrlGroup represents a resource control group, it's a directory</div><div>+ * under /sys/fs/resctrl.</div><div>+ * e.g. /sys/fs/resctrl/CG1</div><div>+ * |-- cpus</div><div>+ * |-- schemata</div><div>+ * `-- tasks</div><div>+ * # cat schemata</div><div>+ * L3DATA:0=fffff;1=fffff</div><div>+ * L3CODE:0=fffff;1=fffff</div><div>+ *</div><div>+ * Besides, it can also represent the default resource control group of the</div><div>+ * host.</div><div>+ */</div><div>+</div><div>+typedef struct _virResctrlGroup virResctrlGroup;</div><div>+typedef virResctrlGroup *virResctrlGroupPtr;</div><div>+struct _virResctrlGroup {</div><div>+    char *name; /* resource group name, NULL for default host group */</div><div>+    size_t n_tasks; /* number of tasks assigned to the resource group */</div><div>+    char **tasks; /* task id list */</div><div>+    virResctrlSchemataPtr schemata[VIR_RESCTRL_TYPE_LAST]; /* Array for schemata */</div><div>+};</div><div>+</div><div>+/* All resource control groups on this host, including default resource group */</div><div>+typedef struct _virResctrlHost virResctrlHost;</div><div>+typedef virResctrlHost *virResctrlHostPtr;</div><div>+struct _virResctrlHost {</div><div>+    size_t n_groups; /* number of resource control group */</div><div>+    virResctrlGroupPtr *groups; /* list of resource control group */</div><div>+};</div><div>+</div><div>+void</div><div>+virResctrlFreeSchemata(virResctrlSchemataPtr ptr)</div><div>+{</div><div>+    size_t i;</div><div>+</div><div>+    if (!ptr)</div><div>+        return;</div><div>+</div><div>+    for (i = 0; i < ptr->n_masks; i++) {</div><div>+        virBitmapFree(ptr->masks[i]->mask);</div><div>+        VIR_FREE(ptr->masks[i]);</div><div>+    }</div><div>+</div><div>+    VIR_FREE(ptr);</div><div>+    ptr = NULL;</div><div>+}</div><div>+</div><div>+static void</div><div>+virResctrlFreeGroup(virResctrlGroupPtr ptr)</div><div>+{</div><div>+    size_t i;</div><div>+</div><div>+    if (!ptr)</div><div>+        return;</div><div>+</div><div>+    for (i = 0; i < ptr->n_tasks; i++)</div><div>+        VIR_FREE(ptr->tasks[i]);</div><div>+    VIR_FREE(ptr->name);</div><div>+</div><div>+    for (i = 0; i < VIR_RESCTRL_TYPE_LAST; i++)</div><div>+        virResctrlFreeSchemata(ptr->schemata[i]);</div><div>+</div><div>+    VIR_FREE(ptr);</div><div>+    ptr = NULL;</div><div>+}</div><div>+</div><div>+/* Return specify type of schemata string from schematalval.</div><div>+   e.g., 0=f;1=f */</div><div>+static int</div><div>+virResctrlGetSchemataString(virResctrlType type,</div><div>+                            const char *schemataval,</div><div>+                            char **schematastr)</div><div>+{</div><div>+    int rc = -1;</div><div>+    char *prefix = NULL;</div><div>+    char **lines = NULL;</div><div>+</div><div>+    if (virAsprintf(&prefix,</div><div>+                    "%s:",</div><div>+                    virResctrlTypeToString(type)) < 0)</div><div>+        return -1;</div><div>+</div><div>+    lines = virStringSplit(schemataval, "\n", 0);</div><div>+</div><div>+    if (VIR_STRDUP(*schematastr,</div><div>+                   virStringListGetFirstWithPrefix(lines, prefix)) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    if (*schematastr == NULL)</div><div>+        rc = -1;</div><div>+    else</div><div>+        rc = 0;</div><div>+</div><div>+ cleanup:</div><div>+    VIR_FREE(prefix);</div><div>+    virStringListFree(lines);</div><div>+    return rc;</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlRemoveSysGroup(const char* name)</div><div>+{</div><div>+    char *path = NULL;</div><div>+    int ret = -1;</div><div>+</div><div>+    if ((ret = virAsprintf(&path, "%s/%s", SYSFS_RESCTRL_PATH, name)) < 0)</div><div>+        return ret;</div><div>+</div><div>+    ret = rmdir(path);</div><div>+</div><div>+    VIR_FREE(path);</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlNewSysGroup(const char *name)</div><div>+{</div><div>+    char *path = NULL;</div><div>+    int ret = -1;</div><div>+    mode_t mode = 0755;</div><div>+</div><div>+    if (virAsprintf(&path, "%s/%s", SYSFS_RESCTRL_PATH, name) < 0)</div><div>+        return -1;</div><div>+</div><div>+    if (virDirCreate(path, mode, 0, 0, 0) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    ret = 0;</div><div>+</div><div>+ cleanup:</div><div>+    VIR_FREE(path);</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlWrite(const char *name, const char *item, const char *content)</div><div>+{</div><div>+    char *path;</div><div>+    int writefd;</div><div>+    int rc = -1;</div><div>+</div><div>+    CONSTRUCT_RESCTRL_PATH(name, item);</div><div>+</div><div>+    if (!virFileExists(path))</div><div>+        goto cleanup;</div><div>+</div><div>+    if ((writefd = open(path, O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR)) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    if (safewrite(writefd, content, strlen(content)) < 0)</div><div>+        goto cleanup;</div><div>+    rc = 0;</div><div>+</div><div>+ cleanup:</div><div>+    VIR_FREE(path);</div><div>+    VIR_FORCE_CLOSE(writefd);</div><div>+    return rc;</div><div>+}</div><div>+</div><div>+static</div><div>+virBitmapPtr virResctrlMask2Bitmap(const char *mask)</div><div>+{</div><div>+    virBitmapPtr bitmap;</div><div>+    unsigned int tmp;</div><div>+    size_t i;</div><div>+</div><div>+    if (virStrToLong_ui(mask, NULL, 16, &tmp) < 0)</div><div>+        return NULL;</div><div>+</div><div>+    bitmap = virBitmapNewEmpty();</div><div>+</div><div>+    for (i = 0; i < MAX_CBM_LEN; i++) {</div><div>+        if (((tmp & 0x1) == 0x1) &&</div><div>+                (virBitmapSetBitExpand(bitmap, i) < 0))</div><div>+            goto error;</div><div>+        tmp = tmp >> 1;</div><div>+    }</div><div>+    return bitmap;</div><div>+</div><div>+ error:</div><div>+    virBitmapFree(bitmap);</div><div>+    return NULL;</div><div>+}</div><div>+</div><div>+char *virResctrlBitmap2String(virBitmapPtr bitmap)</div><div>+{</div><div>+    char *tmp;</div><div>+    char *ret = NULL;</div><div>+    char *p;</div><div>+    tmp = virBitmapString(bitmap);</div><div>+    /* skip "0x" */</div><div>+    p = tmp + 2;</div><div>+</div><div>+    /* first non-0 position */</div><div>+    while (*++p == '0');</div><div>+</div><div>+    if (VIR_STRDUP(ret, p) < 0)</div><div>+        ret = NULL;</div><div>+</div><div>+    VIR_FREE(tmp);</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlParseSchemata(const char* schemata_str,</div><div>+                        virResctrlSchemataPtr schemata)</div><div>+{</div><div>+    VIR_DEBUG("schemata_str=%s, schemata=%p", schemata_str, schemata);</div><div>+</div><div>+    int ret = -1;</div><div>+    size_t i;</div><div>+    virResctrlMaskPtr mask;</div><div>+    char **schemata_list;</div><div>+    char *mask_str;</div><div>+</div><div>+    /* parse 0=fffff;1=f */</div><div>+    schemata_list = virStringSplit(schemata_str, ";", 0);</div><div>+</div><div>+    if (!schemata_list)</div><div>+        goto cleanup;</div><div>+</div><div>+    for (i = 0; schemata_list[i] != NULL; i++) {</div><div>+        /* parse 0=fffff */</div><div>+        mask_str = strchr(schemata_list[i], '=');</div><div>+</div><div>+        if (!mask_str)</div><div>+            goto cleanup;</div><div>+</div><div>+        if (VIR_ALLOC(mask) < 0)</div><div>+            goto cleanup;</div><div>+</div><div>+        mask->cache_id = i;</div><div>+        mask->mask = virResctrlMask2Bitmap(mask_str + 1);</div><div>+        schemata->n_masks += 1;</div><div>+        schemata->masks[i] = mask;</div><div>+</div><div>+    }</div><div>+    ret = 0;</div><div>+</div><div>+ cleanup:</div><div>+    virStringListFree(schemata_list);</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlLoadGroup(const char *name,</div><div>+                    virResctrlHostPtr host)</div><div>+{</div><div>+    VIR_DEBUG("name=%s, host=%p\n", name, host);</div><div>+</div><div>+    int ret = -1;</div><div>+    char *schemataval = NULL;</div><div>+    char *schemata_str = NULL;</div><div>+    virResctrlType i;</div><div>+    int rv;</div><div>+    virResctrlGroupPtr grp;</div><div>+    virResctrlSchemataPtr schemata;</div><div>+</div><div>+    rv = virFileReadValueString(&schemataval,</div><div>+                                SYSFS_RESCTRL_PATH "/%s/schemata",</div><div>+                                name ? name : "");</div><div>+</div><div>+    if (rv < 0)</div><div>+        return -1;</div><div>+</div><div>+    if (VIR_ALLOC(grp) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    if (VIR_STRDUP(grp->name, name) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    for (i = 0; i < VIR_RESCTRL_TYPE_LAST; i++) {</div><div>+        rv = virResctrlGetSchemataString(i, schemataval, &schemata_str);</div><div>+</div><div>+        if (rv < 0)</div><div>+            continue;</div><div>+</div><div>+        if (VIR_ALLOC(schemata) < 0)</div><div>+            goto cleanup;</div><div>+</div><div>+        schemata->type = i;</div><div>+</div><div>+        if (virResctrlParseSchemata(schemata_str, schemata) < 0) {</div><div>+            VIR_FREE(schemata);</div><div>+            VIR_FREE(schemata_str);</div><div>+            goto cleanup;</div><div>+        }</div><div>+</div><div>+        grp->schemata[i] = schemata;</div><div>+        VIR_FREE(schemata_str);</div><div>+    }</div><div>+</div><div>+    if (VIR_APPEND_ELEMENT(host->groups,</div><div>+                           host->n_groups,</div><div>+                           grp) < 0) {</div><div>+        virResctrlFreeGroup(grp);</div><div>+        goto cleanup;</div><div>+    }</div><div>+</div><div>+    ret = 0;</div><div>+</div><div>+ cleanup:</div><div>+    VIR_FREE(schemataval);</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlLoadHost(virResctrlHostPtr host)</div><div>+{</div><div>+    int rv = -1;</div><div>+    DIR *dirp = NULL;</div><div>+    char *path = NULL;</div><div>+    struct dirent *ent;</div><div>+</div><div>+    rv = virDirOpenIfExists(&dirp, SYSFS_RESCTRL_PATH);</div><div>+    if (rv < 0)</div><div>+        return -1;</div><div>+</div><div>+    /* load default group first */</div><div>+    if (virResctrlLoadGroup(NULL, host) < 0)</div><div>+        return -1;</div><div>+</div><div>+    while ((rv = virDirRead(dirp, &ent, path)) > 0) {</div><div>+        /* resctrl is not hierarchical, only read directory under</div><div>+           /sys/fs/resctrl */</div><div>+        if ((ent->d_type != DT_DIR) || STREQ(ent->d_name, "info"))</div><div>+            continue;</div><div>+</div><div>+        if (virResctrlLoadGroup(ent->d_name, host) < 0)</div><div>+            return -1;</div><div>+    }</div><div>+    return 0;</div><div>+}</div><div>+</div><div>+static void</div><div>+virResctrlRefreshHost(virResctrlHostPtr host)</div><div>+{</div><div>+    virResctrlGroupPtr default_grp = NULL;</div><div>+    virResctrlSchemataPtr schemata = NULL;</div><div>+    size_t i, j;</div><div>+    virResctrlType t;</div><div>+</div><div>+    default_grp = host->groups[0];</div><div>+</div><div>+    for (t = 0; t < VIR_RESCTRL_TYPE_LAST; t++) {</div><div>+        if (default_grp->schemata[t] != NULL) {</div><div>+            for (i = 0; i < default_grp->schemata[t]->n_masks; i++) {</div><div>+                /* Reset default group's mask */</div><div>+                virBitmapSetAll(default_grp->schemata[t]->masks[i]->mask);</div><div>+                /* Loop each other resource group except default group */</div><div>+                for (j = 1; j < host->n_groups; j++) {</div><div>+                    schemata = host->groups[j]->schemata[t];</div><div>+                    virBitmapSubtract(default_grp->schemata[t]->masks[i]->mask,</div><div>+                                      schemata->masks[i]->mask);</div><div>+                }</div><div>+            }</div><div>+        }</div><div>+    }</div><div>+}</div><div>+</div><div>+static virResctrlGroupPtr</div><div>+virResctrlGetFreeGroup(void)</div><div>+{</div><div>+    size_t i;</div><div>+    virResctrlHostPtr host = NULL;</div><div>+    virResctrlGroupPtr grp = NULL;</div><div>+</div><div>+    if (VIR_ALLOC(host) < 0)</div><div>+        return NULL;</div><div>+</div><div>+    if (virResctrlLoadHost(host) < 0)</div><div>+        goto error;</div><div>+</div><div>+    virResctrlRefreshHost(host);</div><div>+</div><div>+    for (i = 1; i < host->n_groups; i++)</div><div>+        virResctrlFreeGroup(host->groups[i]);</div><div>+</div><div>+    grp = host->groups[0];</div><div>+    VIR_FREE(host);</div><div>+</div><div>+    return grp;</div><div>+</div><div>+ error:</div><div>+    virResctrlFreeGroup(grp);</div><div>+    return NULL;</div><div>+}</div><div>+</div><div>+virResctrlSchemataPtr</div><div>+virResctrlGetFreeCache(virResctrlType type)</div><div>+{</div><div>+    VIR_DEBUG("type=%d", type);</div><div>+</div><div>+    virResctrlType t;</div><div>+    virResctrlGroupPtr grp = NULL;</div><div>+    virResctrlSchemataPtr schemata = NULL;</div><div>+    int lockfd = -1;</div><div>+</div><div>+    lockfd = open(SYSFS_RESCTRL_PATH, O_DIRECTORY);</div><div>+    if (lockfd < 0)</div><div>+        return NULL;</div><div>+</div><div>+    VIR_RESCTRL_LOCK(lockfd, LOCK_SH);</div><div>+</div><div>+    if ((grp = virResctrlGetFreeGroup()) == NULL)</div><div>+        goto cleanup;</div><div>+</div><div>+    for (t = 0; t < VIR_RESCTRL_TYPE_LAST; t++) {</div><div>+        if (t == type)</div><div>+            schemata = grp->schemata[t];</div><div>+        else</div><div>+            virResctrlFreeSchemata(grp->schemata[t]);</div><div>+</div><div>+    }</div><div>+</div><div>+ cleanup:</div><div>+    VIR_RESCTRL_UNLOCK(lockfd);</div><div>+    VIR_FORCE_CLOSE(lockfd);</div><div>+    return schemata;</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlCalculateCbm(int cbm_len,</div><div>+                       virBitmapPtr defaultcbm,</div><div>+                       virBitmapPtr newcbm)</div><div>+{</div><div>+    VIR_DEBUG("cbm_len=%d, defaultcbm=%p, newcbm=%p",</div><div>+              cbm_len, defaultcbm, newcbm);</div><div>+</div><div>+    ssize_t pos = -1;</div><div>+    size_t i;</div><div>+</div><div>+    /* not enough cache way to be allocated */</div><div>+    if (virBitmapCountBits(defaultcbm) < cbm_len + 1)</div><div>+        return -1;</div><div>+</div><div>+    while ((pos = virBitmapNextSetBit(defaultcbm, pos)) >= 0) {</div><div>+        for (i = 0; i < cbm_len; i++)</div><div>+            ignore_value(virBitmapSetBitExpand(newcbm, i + pos));</div><div>+        /* Test if newcbm is sub set of defaultcbm */</div><div>+        if (virBitmapNextClearBit(defaultcbm, pos) > i + pos) {</div><div>+            break;</div><div>+        } else {</div><div>+            pos = pos + i - 1;</div><div>+            virBitmapClearAll(newcbm);</div><div>+        }</div><div>+    }</div><div>+</div><div>+    if (virBitmapCountBits(newcbm) != cbm_len)</div><div>+        return -1;</div><div>+</div><div>+    /* consume default cbm after allocation */</div><div>+    virBitmapSubtract(defaultcbm, newcbm);</div><div>+</div><div>+    return 0;</div><div>+}</div><div>+</div><div>+/* Fill mask value for newly created resource group base on hostcachebank</div><div>+ * and domcachebank */</div><div>+static int</div><div>+virResctrlFillMask(virResctrlGroupPtr grp,</div><div>+                 virResctrlGroupPtr free_grp,</div><div>+                 virCapsHostCacheBankPtr hostcachebank,</div><div>+                 virDomainCacheBankPtr domcachebank)</div><div>+{</div><div>+    VIR_DEBUG("grp=%p, free_grp=%p, hostcachebank=%p, domcachebank=%p",</div><div>+              grp, free_grp, hostcachebank, domcachebank);</div><div>+</div><div>+    size_t i;</div><div>+    int cbm_candidate_len;</div><div>+    unsigned int cache_id;</div><div>+    unsigned int cache_type;</div><div>+    virCapsHostCacheControlPtr control = NULL;</div><div>+    virResctrlMaskPtr mask;</div><div>+    virResctrlSchemataPtr schemata = NULL;</div><div>+</div><div>+    /* Find control information for that kind type of cache */</div><div>+    for (i = 0; i < hostcachebank->ncontrols; i++) {</div><div>+        if (hostcachebank->controls[i]->scope == domcachebank->type) {</div><div>+            control = hostcachebank->controls[i];</div><div>+            break;</div><div>+        }</div><div>+    }</div><div>+</div><div>+    if (control == NULL)</div><div>+        return -1;</div><div>+</div><div>+    cache_type = domcachebank->type;</div><div>+    cache_id = domcachebank->cache_id;</div><div>+    schemata = grp->schemata[cache_type];</div><div>+</div><div>+    if ((schemata == NULL) && (VIR_ALLOC(schemata) < 0))</div><div>+        return -1;</div><div>+</div><div>+    if (VIR_ALLOC(mask) < 0)</div><div>+        return -1;</div><div>+</div><div>+    mask->cache_id = cache_id;</div><div>+    mask->mask = virBitmapNewEmpty();</div><div>+</div><div>+    /* here should be control->granularity and control->min</div><div>+       also domcachebank size should be checked while define domain xml */</div><div>+    cbm_candidate_len = domcachebank->size / control->min;</div><div>+    VIR_DEBUG("cbm_len = %d", cbm_candidate_len);</div><div>+    if (virResctrlCalculateCbm(cbm_candidate_len,</div><div>+                              free_grp->schemata[cache_type]->masks[cache_id]->mask,</div><div>+                              mask->mask) < 0)</div><div>+        goto error;</div><div>+</div><div>+    schemata->type = cache_type;</div><div>+    schemata->n_masks += 1;</div><div>+    schemata->masks[cache_id] = mask;</div><div>+    grp->schemata[cache_type] = schemata;</div><div>+</div><div>+    return 0;</div><div>+</div><div>+ error:</div><div>+    VIR_FREE(schemata);</div><div>+    return -1;</div><div>+}</div><div>+</div><div>+/* only keep the highest consecutive bits  */</div><div>+static void</div><div>+virResctrlTrimMask(virResctrlMaskPtr mask)</div><div>+{</div><div>+    size_t i;</div><div>+    ssize_t setbit = -1;</div><div>+    ssize_t clearbit = -1;</div><div>+</div><div>+    clearbit = virBitmapNextClearBit(mask->mask, -1);</div><div>+    setbit = virBitmapNextSetBit(mask->mask, -1);</div><div>+    for (i = setbit; i < clearbit; i++)</div><div>+        ignore_value(virBitmapClearBit(mask->mask, i));</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlCompleteMask(virResctrlSchemataPtr schemata,</div><div>+                       virResctrlSchemataPtr defaultschemata)</div><div>+{</div><div>+    size_t i;</div><div>+    virResctrlMaskPtr mask;</div><div>+</div><div>+    if (schemata == NULL && VIR_ALLOC(schemata) < 0)</div><div>+        return -1;</div><div>+</div><div>+    if (schemata->n_masks == defaultschemata->n_masks)</div><div>+        return 0;</div><div>+</div><div>+    for (i = 0; i < defaultschemata->n_masks; i++) {</div><div>+        if (schemata->masks[i] == NULL) {</div><div>+            if (VIR_ALLOC(mask) < 0)</div><div>+                goto error;</div><div>+</div><div>+            mask->cache_id = i;</div><div>+            mask->mask = virBitmapNewEmpty();</div><div>+            schemata->n_masks += 1;</div><div>+            schemata->masks[i] = mask;</div><div>+            /* resctrl doesn't allow mask to be zero</div><div>+               use higher bits to fill up the cbm which</div><div>+               domaincache bank doens't provide */</div><div>+            ignore_value(virBitmapSetBitExpand(mask->mask,</div><div>+                         virBitmapLastSetBit(defaultschemata->masks[i]->mask)));</div><div>+        }</div><div>+        /* only keep the highest consecutive bits for default group */</div><div>+        virResctrlTrimMask(defaultschemata->masks[i]);</div><div>+    }</div><div>+</div><div>+    return 0;</div><div>+</div><div>+ error:</div><div>+    VIR_FREE(schemata);</div><div>+    return -1;</div><div>+}</div><div>+</div><div>+/* complete the schemata in the resrouce group before it can be write back</div><div>+   to resctrl */</div><div>+static int</div><div>+virResctrlCompleteGroup(virResctrlGroupPtr grp,</div><div>+                        virResctrlGroupPtr default_grp)</div><div>+{</div><div>+    virResctrlType t;</div><div>+    virResctrlSchemataPtr schemata;</div><div>+    virResctrlSchemataPtr defaultschemata;</div><div>+</div><div>+</div><div>+    /* NOTES: resctrl system require we need provide all cache's cbm mask */</div><div>+    for (t = 0; t < VIR_RESCTRL_TYPE_LAST; t++) {</div><div>+        defaultschemata = default_grp->schemata[t];</div><div>+        if (defaultschemata != NULL) {</div><div>+            schemata = grp->schemata[t];</div><div>+            if (virResctrlCompleteMask(schemata, defaultschemata) < 0)</div><div>+                return -1;</div><div>+            /* only keep the highest consecutive bits for default group */</div><div>+        }</div><div>+    }</div><div>+    return 0;</div><div>+}</div><div>+</div><div>+static</div><div>+char *virResctrlGetSchemataStr(virResctrlSchemataPtr schemata)</div><div>+{</div><div>+    virBuffer buf = VIR_BUFFER_INITIALIZER;</div><div>+    size_t i;</div><div>+</div><div>+    virBufferAsprintf(&buf, "%s:%u=%s",</div><div>+                      virResctrlTypeToString(schemata->type),</div><div>+                      schemata->masks[0]->cache_id,</div><div>+                      virResctrlBitmap2String(schemata->masks[0]->mask));</div><div>+</div><div>+    for (i = 1; i < schemata->n_masks; i ++)</div><div>+        virBufferAsprintf(&buf, ";%u=%s",</div><div>+                          schemata->masks[i]->cache_id,</div><div>+                          virResctrlBitmap2String(schemata->masks[i]->mask));</div><div>+</div><div>+    return virBufferContentAndReset(&buf);</div><div>+}</div><div>+</div><div>+static int</div><div>+virResctrlFlushGroup(virResctrlGroupPtr grp)</div><div>+{</div><div>+    int ret = -1;</div><div>+    size_t i;</div><div>+    char *schemata_str = NULL;</div><div>+    virResctrlType t;</div><div>+    virBuffer buf = VIR_BUFFER_INITIALIZER;</div><div>+</div><div>+    VIR_DEBUG("grp=%p", grp);</div><div>+</div><div>+    if (grp->name != NULL && virResctrlNewSysGroup(grp->name) < 0)</div><div>+        return -1;</div><div>+</div><div>+    for (t = 0; t < VIR_RESCTRL_TYPE_LAST; t++) {</div><div>+        if (grp->schemata[t] != NULL) {</div><div>+            schemata_str = virResctrlGetSchemataStr(grp->schemata[t]);</div><div>+            virBufferAsprintf(&buf, "%s\n", schemata_str);</div><div>+            VIR_FREE(schemata_str);</div><div>+        }</div><div>+    }</div><div>+</div><div>+    schemata_str = virBufferContentAndReset(&buf);</div><div>+</div><div>+    if (virResctrlWrite(grp->name, "schemata", schemata_str) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    for (i = 0; i < grp->n_tasks; i++) {</div><div>+        if (virResctrlWrite(grp->name, "tasks", grp->tasks[i]) < 0)</div><div>+            goto cleanup;</div><div>+    }</div><div>+</div><div>+    ret = 0;</div><div>+</div><div>+ cleanup:</div><div>+    VIR_FREE(schemata_str);</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+int virResctrlSetCachetunes(virCapsHostPtr caps,</div><div>+                            virDomainCachetunePtr cachetune,</div><div>+                            unsigned char* uuid, pid_t *pids, int npid)</div><div>+{</div><div>+    size_t i;</div><div>+    size_t j;</div><div>+    int ret = -1;</div><div>+    char name[VIR_UUID_STRING_BUFLEN];</div><div>+    char *tmp;</div><div>+    int lockfd = -1;</div><div>+    virResctrlGroupPtr grp = NULL;</div><div>+    virResctrlGroupPtr default_grp = NULL;</div><div>+    virCapsHostCacheBankPtr hostcachebank;</div><div>+    virDomainCacheBankPtr domcachebank;</div><div>+</div><div>+    virUUIDFormat(uuid, name);</div><div>+</div><div>+    if (cachetune->n_banks < 1)</div><div>+        return 0;</div><div>+</div><div>+    /* create new resource group */</div><div>+    if (VIR_ALLOC(grp) < 0)</div><div>+        goto error;</div><div>+</div><div>+    if (VIR_STRDUP(grp->name, name) < 0)</div><div>+        goto error;</div><div>+</div><div>+    /* allocate file lock */</div><div>+    lockfd = open(SYSFS_RESCTRL_PATH, O_DIRECTORY);</div><div>+    if (lockfd < 0)</div><div>+        goto error;</div><div>+</div><div>+    VIR_RESCTRL_LOCK(lockfd, LOCK_EX);</div><div>+</div><div>+    if ((default_grp = virResctrlGetFreeGroup()) == NULL)</div><div>+        goto error;</div><div>+</div><div>+    /* Allocate cache for each cache bank defined in cache tune */</div><div>+    for (i = 0; i < cachetune->n_banks; i++) {</div><div>+        domcachebank = &cachetune->cache_banks[i];</div><div>+        hostcachebank = NULL;</div><div>+        /* find the host cache bank to be allocated on */</div><div>+        for (j = 0; j < caps->ncaches; j++) {</div><div>+            if (caps->caches[j]->id == domcachebank->cache_id) {</div><div>+                hostcachebank = caps->caches[j];</div><div>+                break;</div><div>+            }</div><div>+        }</div><div>+        /* fill up newly crated grp and consume from default_grp */</div><div>+        if (virResctrlFillMask(grp, default_grp, hostcachebank, domcachebank) < 0)</div><div>+            goto error;</div><div>+    }</div><div>+</div><div>+    /* Add tasks to grp */</div><div>+    for (i = 0; i < npid; i++) {</div><div>+        if (virAsprintf(&tmp, "%llu", (long long)pids[i]) < 0)</div><div>+            goto error;</div><div>+</div><div>+        if (VIR_APPEND_ELEMENT(grp->tasks,</div><div>+                               grp->n_tasks,</div><div>+                               tmp) < 0) {</div><div>+            VIR_FREE(tmp);</div><div>+            goto error;</div><div>+        }</div><div>+    }</div><div>+</div><div>+    if (virResctrlCompleteGroup(grp, default_grp) < 0) {</div><div>+        VIR_WARN("Failed to complete group");</div><div>+        goto error;</div><div>+    }</div><div>+</div><div>+    if (virResctrlFlushGroup(grp) < 0)</div><div>+        goto error;</div><div>+</div><div>+    if (virResctrlFlushGroup(default_grp) < 0) {</div><div>+        virResctrlRemoveSysGroup(grp->name);</div><div>+        goto error;</div><div>+    }</div><div>+</div><div>+    ret = 0;</div><div>+</div><div>+ error:</div><div>+    VIR_RESCTRL_UNLOCK(lockfd);</div><div>+    VIR_FORCE_CLOSE(lockfd);</div><div>+    virResctrlFreeGroup(grp);</div><div>+    virResctrlFreeGroup(default_grp);</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+int virResctrlRemoveCachetunes(unsigned char* uuid)</div><div>+{</div><div>+    int ret = -1;</div><div>+    int lockfd = -1;</div><div>+    size_t i;</div><div>+    virResctrlType t;</div><div>+    virResctrlSchemataPtr schemata;</div><div>+    char name[VIR_UUID_STRING_BUFLEN];</div><div>+    virResctrlGroupPtr default_grp = NULL;</div><div>+</div><div>+    virUUIDFormat(uuid, name);</div><div>+</div><div>+    VIR_DEBUG("name=%s", name);</div><div>+</div><div>+    lockfd = open(SYSFS_RESCTRL_PATH, O_DIRECTORY);</div><div>+    if (lockfd < 0)</div><div>+        return -1;</div><div>+</div><div>+    VIR_RESCTRL_LOCK(lockfd, LOCK_SH);</div><div>+</div><div>+    if (virResctrlRemoveSysGroup(name) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    if ((default_grp = virResctrlGetFreeGroup()) == NULL)</div><div>+        goto cleanup;</div><div>+</div><div>+    for (t = 0; t < VIR_RESCTRL_TYPE_LAST; t++) {</div><div>+        schemata = default_grp->schemata[t];</div><div>+        if (schemata != NULL) {</div><div>+            for (i = 0; i < schemata->n_masks; i++)</div><div>+                virResctrlTrimMask(schemata->masks[i]);</div><div>+        }</div><div>+    }</div><div>+</div><div>+    if (virResctrlFlushGroup(default_grp) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    ret = 0;</div><div>+</div><div>+ cleanup:</div><div>+    VIR_RESCTRL_UNLOCK(lockfd);</div><div>+    VIR_FORCE_CLOSE(lockfd);</div><div>+    return ret;</div><div>+}</div><div>diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h</div><div>new file mode 100644</div><div>index 0000000..7373c72</div><div>--- /dev/null</div><div>+++ b/src/util/virresctrl.h</div><div>@@ -0,0 +1,79 @@</div><div>+/*</div><div>+ * virresctrl.h: header for managing resctrl control</div><div>+ *</div><div>+ * Copyright (C) 2017 Intel, Inc.</div><div>+ *</div><div>+ * This library is free software; you can redistribute it and/or</div><div>+ * modify it under the terms of the GNU Lesser General Public</div><div>+ * License as published by the Free Software Foundation; either</div><div>+ * version 2.1 of the License, or (at your option) any later version.</div><div>+ *</div><div>+ * This library is distributed in the hope that it will be useful,</div><div>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</div><div>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU</div><div>+ * Lesser General Public License for more details.</div><div>+ *</div><div>+ * You should have received a copy of the GNU Lesser General Public</div><div>+ * License along with this library.  If not, see</div><div>+ * <<a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.</div><div>+ *</div><div>+ * Authors:</div><div>+ * Eli Qiao <<a href="mailto:liyong.qiao@intel.com">liyong.qiao@intel.com</a>></div><div>+ */</div><div>+</div><div>+#ifndef __VIR_RESCTRL_H__</div><div>+# define __VIR_RESCTRL_H__</div><div>+</div><div>+#include "virutil.h"</div><div>+#include "virbitmap.h"</div><div>+#include "conf/domain_conf.h"</div><div>+</div><div>+#define MAX_CACHE_ID 16</div><div>+</div><div>+typedef enum {</div><div>+    VIR_RESCTRL_TYPE_L3,</div><div>+    VIR_RESCTRL_TYPE_L3_CODE,</div><div>+    VIR_RESCTRL_TYPE_L3_DATA,</div><div>+</div><div>+    VIR_RESCTRL_TYPE_LAST</div><div>+} virResctrlType;</div><div>+</div><div>+VIR_ENUM_DECL(virResctrl);</div><div>+</div><div>+/*</div><div>+ * a virResctrlMask represents one of mask object in a</div><div>+ * resource control group.</div><div>+ * e.g., 0=f</div><div>+ */</div><div>+typedef struct _virResctrlMask virResctrlMask;</div><div>+typedef virResctrlMask *virResctrlMaskPtr;</div><div>+struct _virResctrlMask {</div><div>+    unsigned int cache_id; /* cache resource id */</div><div>+    virBitmapPtr mask; /* the cbm mask */</div><div>+};</div><div>+</div><div>+/*</div><div>+ * a virResctrlSchemata represents schemata objects of specific type of</div><div>+ * resource in a resource control group.</div><div>+ * eg: L3:0=f,1=ff</div><div>+ */</div><div>+typedef struct _virResctrlSchemata virResctrlSchemata;</div><div>+typedef virResctrlSchemata *virResctrlSchemataPtr;</div><div>+struct _virResctrlSchemata {</div><div>+    virResctrlType type; /* resource control type, e.g., L3 */</div><div>+    size_t n_masks; /* number of masks */</div><div>+    virResctrlMaskPtr masks[MAX_CACHE_ID]; /* array of mask, use array for easy index */</div><div>+};</div><div>+</div><div>+/* Get free cache of the host, result saved in schemata */</div><div>+virResctrlSchemataPtr virResctrlGetFreeCache(virResctrlType type);</div><div>+</div><div>+/* Get mask string from Bitmap */</div><div>+char *virResctrlBitmap2String(virBitmapPtr bitmap);</div><div>+</div><div>+void virResctrlFreeSchemata(virResctrlSchemataPtr ptr);</div><div>+int virResctrlSetCachetunes(virCapsHostPtr caps,</div><div>+                            virDomainCachetunePtr cachetune,</div><div>+                            unsigned char* uuid, pid_t *pids, int npid);</div><div>+int virResctrlRemoveCachetunes(unsigned char* uuid);</div><div>+#endif</div><div>diff --git a/tests/<a href="http://Makefile.am">Makefile.am</a> b/tests/<a href="http://Makefile.am">Makefile.am</a></div><div>index 19986dc..e0b9923 100644</div><div>--- a/tests/<a href="http://Makefile.am">Makefile.am</a></div><div>+++ b/tests/<a href="http://Makefile.am">Makefile.am</a></div><div>@@ -229,6 +229,7 @@ if WITH_LINUX</div><div> test_programs += fchosttest</div><div> test_programs += scsihosttest</div><div> test_programs += vircaps2xmltest</div><div>+test_programs += virresctrltest</div><div> test_libraries += <a href="http://virusbmock.la">virusbmock.la</a> \</div><div>      <a href="http://virnetdevbandwidthmock.la">virnetdevbandwidthmock.la</a> \</div><div>         <a href="http://virnumamock.la">virnumamock.la</a> \</div><div>@@ -1149,8 +1150,13 @@ virnumamock_la_CFLAGS = $(AM_CFLAGS)</div><div> virnumamock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS)</div><div> virnumamock_la_LIBADD = $(MOCKLIBS_LIBS)</div><div> </div><div>+virresctrltest_SOURCES = \</div><div>+      virresctrltest.c testutils.h testutils.c virfilewrapper.h virfilewrapper.c</div><div>+virresctrltest_LDADD = $(LDADDS)</div><div>+</div><div> else ! WITH_LINUX</div><div>-EXTRA_DIST += vircaps2xmltest.c virnumamock.c virfilewrapper.c virfilewrapper.h</div><div>+EXTRA_DIST += vircaps2xmltest.c virnumamock.c virfilewrapper.c \</div><div>+                        virfilewrapper.h virresctrltest.c</div><div> endif ! WITH_LINUX</div><div> </div><div> if WITH_NSS</div><div>diff --git a/tests/virresctrldata/L3-free.schemata b/tests/virresctrldata/L3-free.schemata</div><div>new file mode 100644</div><div>index 0000000..9b47d25</div><div>--- /dev/null</div><div>+++ b/tests/virresctrldata/L3-free.schemata</div><div>@@ -0,0 +1 @@</div><div>+L3:0=1ffff;1=1ffff</div><div>diff --git a/tests/virresctrldata/L3CODE-free.schemata b/tests/virresctrldata/L3CODE-free.schemata</div><div>new file mode 100644</div><div>index 0000000..7039c45</div><div>--- /dev/null</div><div>+++ b/tests/virresctrldata/L3CODE-free.schemata</div><div>@@ -0,0 +1 @@</div><div>+L3CODE:0=cffff;1=cffff</div><div>diff --git a/tests/virresctrldata/L3DATA-free.schemata b/tests/virresctrldata/L3DATA-free.schemata</div><div>new file mode 100644</div><div>index 0000000..30f1cbd</div><div>--- /dev/null</div><div>+++ b/tests/virresctrldata/L3DATA-free.schemata</div><div>@@ -0,0 +1 @@</div><div>+L3DATA:0=3ffff;1=3ffff</div><div>diff --git a/tests/virresctrldata/linux-resctrl b/tests/virresctrldata/linux-resctrl</div><div>new file mode 120000</div><div>index 0000000..069dfb2</div><div>--- /dev/null</div><div>+++ b/tests/virresctrldata/linux-resctrl</div><div>@@ -0,0 +1 @@</div><div>+../vircaps2xmldata/linux-resctrl</div><div>\ No newline at end of file</div><div>diff --git a/tests/virresctrldata/linux-resctrl-cdp b/tests/virresctrldata/linux-resctrl-cdp</div><div>new file mode 120000</div><div>index 0000000..c5a973f</div><div>--- /dev/null</div><div>+++ b/tests/virresctrldata/linux-resctrl-cdp</div><div>@@ -0,0 +1 @@</div><div>+../vircaps2xmldata/linux-resctrl-cdp</div><div>\ No newline at end of file</div><div>diff --git a/tests/virresctrltest.c b/tests/virresctrltest.c</div><div>new file mode 100644</div><div>index 0000000..a9d75f1</div><div>--- /dev/null</div><div>+++ b/tests/virresctrltest.c</div><div>@@ -0,0 +1,119 @@</div><div>+/*</div><div>+ * Copyright (C) Intel, Inc. 2017</div><div>+ *</div><div>+ * This library is free software; you can redistribute it and/or</div><div>+ * modify it under the terms of the GNU Lesser General Public</div><div>+ * License as published by the Free Software Foundation; either</div><div>+ * version 2.1 of the License, or (at your option) any later version.</div><div>+ *</div><div>+ * This library is distributed in the hope that it will be useful,</div><div>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</div><div>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU</div><div>+ * Lesser General Public License for more details.</div><div>+ *</div><div>+ * You should have received a copy of the GNU Lesser General Public</div><div>+ * License along with this library.  If not, see</div><div>+ * <<a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>>.</div><div>+ *</div><div>+ * Authors:</div><div>+ *      Eli Qiao <<a href="mailto:liyong.qiao@intel.com">liyong.qiao@intel.com</a>></div><div>+ */</div><div>+</div><div>+#include <config.h></div><div>+#include <stdlib.h></div><div>+</div><div>+#include "testutils.h"</div><div>+#include "virbitmap.h"</div><div>+#include "virfilewrapper.h"</div><div>+#include "virresctrl.h"</div><div>+</div><div>+</div><div>+#define VIR_FROM_THIS VIR_FROM_NONE</div><div>+</div><div>+struct virResctrlData {</div><div>+    const char *filename;</div><div>+    virResctrlType type;</div><div>+};</div><div>+</div><div>+static void</div><div>+GetSchemataStr(virResctrlSchemataPtr schemata, char **str)</div><div>+{</div><div>+    size_t i;</div><div>+</div><div>+    virBuffer buf = VIR_BUFFER_INITIALIZER;</div><div>+    virBufferAsprintf(&buf, "%s:%u=%s",</div><div>+                            virResctrlTypeToString(schemata->type),</div><div>+                            schemata->masks[0]->cache_id,</div><div>+                            virResctrlBitmap2String(schemata->masks[0]->mask));</div><div>+</div><div>+    for (i = 1; i < schemata->n_masks; i ++)</div><div>+        virBufferAsprintf(&buf, ";%u=%s",</div><div>+                                schemata->masks[i]->cache_id,</div><div>+                                virResctrlBitmap2String(schemata->masks[i]->mask));</div><div>+</div><div>+    *str = virBufferContentAndReset(&buf);</div><div>+}</div><div>+</div><div>+static int</div><div>+test_virResctrl(const void *opaque)</div><div>+{</div><div>+    struct virResctrlData *data = (struct virResctrlData *) opaque;</div><div>+    char *dir = NULL;</div><div>+    char *resctrl = NULL;</div><div>+    int ret = -1;</div><div>+    virResctrlSchemataPtr schemata = NULL;</div><div>+    char *schemata_str = NULL;</div><div>+    char *schemata_file;</div><div>+</div><div>+    if (virAsprintf(&resctrl, "%s/virresctrldata/linux-%s/resctrl",</div><div>+                    abs_srcdir, data->filename) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    if (virAsprintf(&schemata_file, "%s/virresctrldata/%s-free.schemata",</div><div>+                    abs_srcdir, virResctrlTypeToString(data->type)) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    if (virFileWrapperAddPrefix("/sys/fs/resctrl", resctrl) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    if ((schemata = virResctrlGetFreeCache(data->type)) == NULL)</div><div>+        goto cleanup;</div><div>+</div><div>+    virFileWrapperClearPrefixes();</div><div>+</div><div>+    GetSchemataStr(schemata, &schemata_str);</div><div>+</div><div>+    if (virTestCompareToFile(schemata_str, schemata_file) < 0)</div><div>+        goto cleanup;</div><div>+</div><div>+    ret = 0;</div><div>+</div><div>+ cleanup:</div><div>+    VIR_FREE(dir);</div><div>+    VIR_FREE(resctrl);</div><div>+    VIR_FREE(schemata_str);</div><div>+    virResctrlFreeSchemata(schemata);</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+static int</div><div>+mymain(void)</div><div>+{</div><div>+    int ret = 0;</div><div>+</div><div>+#define DO_TEST_FULL(filename, type) \</div><div>+    do {                                                                \</div><div>+        struct virResctrlData data = {filename,                         \</div><div>+                                      type};                            \</div><div>+        if (virTestRun(filename, test_virResctrl, &data) < 0)           \</div><div>+            ret = -1;                                                   \</div><div>+    } while (0)</div><div>+</div><div>+    DO_TEST_FULL("resctrl", VIR_RESCTRL_TYPE_L3);</div><div>+    DO_TEST_FULL("resctrl-cdp", VIR_RESCTRL_TYPE_L3_CODE);</div><div>+    DO_TEST_FULL("resctrl-cdp", VIR_RESCTRL_TYPE_L3_DATA);</div><div>+</div><div>+    return ret;</div><div>+}</div><div>+</div><div>+VIR_TEST_MAIN(mymain)</div><div>-- </div><div>1.9.1</div><div><br></div><div>--</div><div>libvir-list mailing list</div><div><a href="mailto:libvir-list@redhat.com">libvir-list@redhat.com</a></div><div><a href="https://www.redhat.com/mailman/listinfo/libvir-list">https://www.redhat.com/mailman/listinfo/libvir-list</a></div></div></div></span>
                 
                 
                 
                 
                </blockquote>
                 
                <div>
                    <br>
                </div>