[resend v2 4/7] Resctrl: Add private interface to set cachebanks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



virResCtrlSetCacheBanks: Set cache banks of a libvirt domain. It will
create new resource domain under `/sys/fs/resctrl` and fill the
schemata according the cache banks configration.

virResCtrlUpdate: Update the schemata after libvirt domain destroy.

Signed-off-by: Eli Qiao <liyong.qiao@xxxxxxxxx>
---
 src/libvirt_private.syms |   2 +
 src/util/virresctrl.c    | 644 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/util/virresctrl.h    |  47 +++-
 3 files changed, 691 insertions(+), 2 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 08a0bc4..2b3278a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2319,6 +2319,8 @@ virResCtrlInit;
 virResCtrlGet;
 virResCtrlTypeFromString;
 virResCtrlTypeToString;
+virResCtrlSetCacheBanks;
+virResCtrlUpdate;
 
 
 # util/virrotatingfile.h
diff --git a/src/util/virresctrl.c b/src/util/virresctrl.c
index 76d4ab8..002b539 100644
--- a/src/util/virresctrl.c
+++ b/src/util/virresctrl.c
@@ -68,6 +68,11 @@ do { \
 
 static unsigned int host_id = 0;
 
+/* Global static struct to be maintained which is a interface */
+static virResCtrlDomain DomainAll;
+
+/* Global static struct array to be maintained which indicate
+ * resource status on a host */
 static virResCtrl ResCtrlAll[] = {
     {
         .name = "L3",
@@ -87,6 +92,64 @@ static virResCtrl ResCtrlAll[] = {
     },
 };
 
+/*
+ * How many bits is set in schemata
+ * eg:
+ * virResCtrlBitsNum(1011) = 2 */
+static int virResCtrlBitsContinuesNum(unsigned schemata) {
+    int ret = 0;
+    for (int i = 0; i < MAX_CBM_BIT_LEN; i ++) {
+        if ((schemata & 0x1) == 0x1)
+            ret++;
+        else
+            break;
+        schemata = schemata >> 1;
+        if (schemata == 0) break;
+    }
+    return ret;
+}
+
+static int virResCtrlGetStr(const char *domain_name, const char *item_name, char **ret)
+{
+    char *path;
+    int rc = 0;
+
+    CONSTRUCT_RESCTRL_PATH(domain_name, item_name);
+
+    if (virFileReadAll(path, MAX_FILE_LEN, ret) < 0) {
+        rc = -1;
+        goto cleanup;
+    }
+
+cleanup:
+    VIR_FREE(path);
+    return rc;
+}
+
+static int virResCtrlGetTasks(const char *domain_name, char **pids)
+{
+    return virResCtrlGetStr(domain_name, "tasks", pids);
+}
+
+static int virResCtrlGetSchemata(const int type, const char *name, char **schemata)
+{
+    int rc;
+    char *tmp, *end;
+    char *buf;
+
+    if ((rc = virResCtrlGetStr(name, "schemata", &buf)) < 0)
+        return rc;
+
+    tmp = strstr(buf, ResCtrlAll[type].name);
+    end = strchr(tmp, '\n');
+    *end = '\0';
+    if(VIR_STRDUP(*schemata, tmp) < 0)
+        rc = -1;
+
+    VIR_FREE(buf);
+    return rc;
+}
+
 static int virResCtrlGetInfoStr(const int type, const char *item, char **str)
 {
     int ret = 0;
@@ -109,6 +172,70 @@ cleanup:
     return ret;
 }
 
+/* Return pointer of and ncount of schemata*/
+static virResSchemataPtr virParseSchemata(const char* schemata_str, int* ncount)
+{
+    const char *p, *q;
+    int pos;
+    int ischemata;
+    virResSchemataPtr schemata;
+    virResSchemataItemPtr schemataitems, tmpitem;
+    unsigned int socket_no = 0;
+    char *tmp;
+
+    if(VIR_ALLOC(schemata) < 0)
+        goto cleanup;
+
+    p = q = schemata_str;
+    pos = strchr(schemata_str, ':') - p;
+
+    /* calculate cpu socket count */
+    *ncount = 1;
+    while((q = strchr(p, ';')) != 0) {
+        p = q + 1;
+        (*ncount)++;
+    }
+
+    /* allocat an arrry to store schemata for each socket*/
+    if(VIR_ALLOC_N_QUIET(tmpitem, *ncount) < 0)
+        goto cleanup;
+
+    schemataitems = tmpitem;
+
+    p = q = schemata_str + pos + 1;
+
+    while(*p != '\0'){
+        if (*p == '='){
+            q = p + 1;
+
+            tmpitem->socket_no = socket_no++;
+
+            while(*p != ';' && *p != '\0') p++;
+
+            if (VIR_STRNDUP(tmp, q, p-q) < 0)
+                goto cleanup;
+
+            if (virStrToLong_i(tmp, NULL, 16, &ischemata) < 0)
+                goto cleanup;
+
+            VIR_FREE(tmp);
+            tmp = NULL;
+            tmpitem->schemata = ischemata;
+            tmpitem ++;
+            schemata->n_schemata_items +=1;
+        }
+        p++;
+    }
+
+    schemata->schemata_items = schemataitems;
+    return schemata;
+
+cleanup:
+    VIR_FREE(schemata);
+    VIR_FREE(tmpitem);
+    return NULL;
+}
+
 
 static int virResCtrlGetCPUValue(const char* path, char** value)
 {
@@ -252,6 +379,7 @@ static virResCacheBankPtr virResCtrlGetCacheBanks(int type, int* n_sockets)
             }
             bank[s_id].cache_size = cache_size;
             bank[s_id].cache_min = cache_size / ResCtrlAll[type].cbm_len;
+            bank[s_id].cache_left = cache_size - (bank[s_id].cache_min * ResCtrlAll[type].min_cbm_bits);
         }
     }
     return bank;
@@ -268,7 +396,7 @@ static int virResCtrlGetConfig(int type)
     int i;
     char *str;
 
-    /* Read min_cbm_bits from resctrl.
+    /* Read num_closids from resctrl.
        eg: /sys/fs/resctrl/info/L3/num_closids
     */
     if ((ret = virResCtrlGetInfoStr(type, "num_closids", &str)) < 0) {
@@ -325,6 +453,515 @@ static int virResCtrlGetConfig(int type)
     return ret;
 }
 
+/* Remove the Domain from sysfs, this should only success no pids in tasks
+ * of a partition.
+ */
+static
+int virRscctrlRemoveDomain(const char *name)
+{
+    char *path = NULL;
+    int rc = 0;
+
+    if ((rc = asprintf(&path, "%s/%s", RESCTRL_DIR, name)) < 0)
+        return rc;
+    rc = rmdir(path);
+    VIR_FREE(path);
+    return rc;
+}
+
+/* assemble schemata string*/
+static
+char* virResCtrlAssembleSchemata(virResSchemataPtr schemata, int type)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAsprintf(&buf, "%s:%u=%x", ResCtrlAll[type].name,
+                      schemata->schemata_items[0].socket_no,
+                      schemata->schemata_items[0].schemata);
+
+    for(int i = 1; i < schemata->n_schemata_items; i++) {
+        virBufferAsprintf(&buf, ";%u=%x",
+                       schemata->schemata_items[i].socket_no,
+                       schemata->schemata_items[i].schemata);
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+/* Refresh default domains' schemata
+ */
+static
+int virResCtrlRefreshSchemata(void)
+{
+    int i;
+    int j;
+    int k;
+    unsigned int tmp_schemata;
+    unsigned int default_schemata;
+
+    virResDomainPtr header, p;
+
+    header = DomainAll.domains;
+
+    for (i = 0; i < RDT_NUM_RESOURCES; i++) {
+        if (VIR_RESCTRL_ENABLED(i)) {
+            for(j = 0; j < header->schematas[i]->n_schemata_items; j ++) {
+                p = header->next;
+                default_schemata = VIR_RESCTRL_GET_SCHEMATA(ResCtrlAll[i].cbm_len);
+                tmp_schemata = 0;
+                /* NOTEs: if only header domain, the schemata will be set to default one*/
+                for (k = 1; k < DomainAll.num_domains; k++) {
+                    tmp_schemata |= p->schematas[i]->schemata_items[j].schemata;
+                    p = p->next;
+                }
+                /* sys fs doens't let us use 0 */
+                int min_bits =  VIR_RESCTRL_GET_SCHEMATA(ResCtrlAll[i].min_cbm_bits);
+                if((tmp_schemata & min_bits) == min_bits)
+                    tmp_schemata -= min_bits;
+
+                default_schemata ^= tmp_schemata;
+
+                int bitsnum = virResCtrlBitsContinuesNum(default_schemata);
+                // calcuate header's schemata
+                // NOTES: resctrl sysfs only allow us to set a continues schemata
+                header->schematas[i]->schemata_items[j].schemata = VIR_RESCTRL_GET_SCHEMATA(bitsnum);
+                ResCtrlAll[i].cache_banks[j].cache_left =
+                    (bitsnum - ResCtrlAll[i].min_cbm_bits) * ResCtrlAll[i].cache_banks[j].cache_min;
+            }
+        }
+    }
+
+    return 0;
+
+}
+
+/* Refresh all domains', remove the domains which has no task ids.
+ * This will be used after VM pause, restart, destroy etc.
+ */
+static int
+virResCtrlRefresh(void)
+{
+    int i;
+    char* tasks;
+    unsigned int origin_count = DomainAll.num_domains;
+    virResDomainPtr p, pre, del=NULL;
+    pre = DomainAll.domains;
+    p = pre->next;
+
+    for (i = 1; i < origin_count; i++) {
+        if(virResCtrlGetTasks(p->name, &tasks) < 0) {
+            VIR_WARN("Failed to get tasks from %s", p->name);
+            pre = p;
+            p = p->next;
+        }
+        if(virStringIsEmpty(tasks)) {
+            pre->next = p->next;
+            if(p->next != NULL)
+                p->next->pre = pre;
+
+            del = p;
+            p = p->next;
+            if(virRscctrlRemoveDomain(del->name) < 0)
+                VIR_WARN("Failed to remove partition %s", p->name);
+
+            VIR_DEBUG("Remove partition %s", del->name);
+
+            VIR_FREE(del->name);
+            VIR_FREE(del->tasks);
+            VIR_FREE(del);
+            del = NULL;
+
+            DomainAll.num_domains -=1;
+        } else {
+            pre = p;
+            p = p->next;
+        }
+        VIR_FREE(tasks);
+
+    }
+
+    return virResCtrlRefreshSchemata();
+}
+
+/* Get a domain ptr by domain's name*/
+static
+virResDomainPtr virResCtrlGetDomain(const char* name) {
+    int i;
+    virResDomainPtr p = DomainAll.domains;
+    for(i = 0; i < DomainAll.num_domains; i++)
+    {
+        if((p->name) && (strcmp(name, p->name) == 0)) {
+            return p;
+        }
+        p = p->next;
+    }
+    return NULL;
+}
+
+static int
+virResCtrlAddTask(virResDomainPtr dom, pid_t pid)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    if(dom->tasks == NULL) {
+        virBufferAsprintf(&buf, "%lld\n", (long long)pid);
+    } else {
+        virBufferAsprintf(&buf, "%s%lld\n", dom->tasks, (long long)pid);
+        VIR_FREE(dom->tasks);
+    }
+    dom->tasks = virBufferContentAndReset(&buf);
+    return 0;
+}
+
+static int
+virResCtrlWrite(const char* name, const char* item, const char* content)
+{
+    char* path;
+    int writefd;
+    int rc = -1;
+
+    CONSTRUCT_RESCTRL_PATH(name, item);
+
+    if (!virFileExists(path))
+        goto cleanup;
+
+    if ((writefd = open(path, O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR)) < 0)
+        goto cleanup;
+
+    if (safewrite(writefd, content, strlen(content)) < 0)
+        goto cleanup;
+
+    rc = 0;
+cleanup:
+    VIR_FREE(path);
+    VIR_FORCE_CLOSE(writefd);
+    return rc;
+}
+
+/* if name == NULL we load default schemata */
+static
+virResDomainPtr virResCtrlLoadDomain(const char* name)
+{
+    char* schematas;
+    char* tasks = NULL;
+    virResDomainPtr p;
+
+    if(VIR_ALLOC(p) < 0)
+        goto cleanup;
+
+    if(name != NULL && virResCtrlGetTasks(name, &tasks) < 0)
+        goto cleanup;
+
+    for(int i = 0; i < RDT_NUM_RESOURCES; i++) {
+        if(VIR_RESCTRL_ENABLED(i)) {
+            if (virResCtrlGetSchemata(i, name, &schematas) < 0)
+                goto cleanup;
+            p->schematas[i] = virParseSchemata(schematas, &(p->n_sockets));
+            VIR_FREE(schematas);
+        }
+    }
+
+    p->tasks = tasks;
+
+    if((name != NULL) && (VIR_STRDUP(p->name, name)) < 0)
+        goto cleanup;
+
+    return p;
+
+cleanup:
+    VIR_FREE(p);
+    return NULL;
+}
+
+static
+virResDomainPtr virResCtrlCreateDomain(const char* name)
+{
+    char *path;
+    mode_t mode = 0755;
+    virResDomainPtr p;
+    if (asprintf(&path, "%s/%s", RESCTRL_DIR, name) < 0)
+	    return NULL;
+    if (virDirCreate(path, mode, 0, 0, 0) < 0)
+        goto cleanup;
+
+    if((p = virResCtrlLoadDomain(name)) == NULL)
+        return p;
+
+    /* sys fs doens't let us use 0.
+     * reset schemata to min_bits*/
+    for(int i = 0; i < RDT_NUM_RESOURCES; i++) {
+        if(VIR_RESCTRL_ENABLED(i)) {
+            int min_bits =  VIR_RESCTRL_GET_SCHEMATA(ResCtrlAll[i].min_cbm_bits);
+            for(int j = 0; j < p->n_sockets; j++)
+                p->schematas[i]->schemata_items[j].schemata = min_bits;
+        }
+    }
+
+    VIR_FREE(path);
+    return p;
+
+cleanup:
+    VIR_FREE(path);
+    return NULL;
+}
+
+static
+int virResCtrlDestroyDomain(virResDomainPtr p)
+{
+    char *path;
+    if (asprintf(&path, "%s/%s", RESCTRL_DIR, p->name) < 0)
+	    return -1;
+    rmdir(path);
+
+    VIR_FREE(p->name);
+    p->name = NULL;
+    VIR_FREE(p->tasks);
+    VIR_FREE(p);
+    p = NULL;
+    return 0;
+}
+
+/* flush domains's information to sysfs*/
+static int
+virResCtrlFlushDomainToSysfs(virResDomainPtr dom)
+{
+    int i;
+    char* schemata;
+    char* tmp;
+    int rc = -1;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    for(i = 0; i < RDT_NUM_RESOURCES; i++) {
+        if(VIR_RESCTRL_ENABLED(i)) {
+            tmp = virResCtrlAssembleSchemata(dom->schematas[i], i);
+            virBufferAsprintf(&buf, "%s\n", tmp);
+            VIR_FREE(tmp);
+        }
+    }
+
+    schemata = virBufferContentAndReset(&buf);
+
+    if(virResCtrlWrite(dom->name, "schemata", schemata) < 0)
+        goto cleanup;
+    if(!virStringIsEmpty(dom->tasks)
+            && virResCtrlWrite(dom->name, "tasks", dom->tasks) < 0)
+        goto cleanup;
+    rc = 0;
+
+cleanup:
+    VIR_FREE(schemata);
+    return rc;
+}
+
+static virResDomainPtr virResCtrlGetAllDomains(unsigned int *len)
+{
+    struct dirent *ent;
+    DIR *dp = NULL;
+    int direrr;
+
+    *len = 0;
+    virResDomainPtr header, tmp, tmp_pre;
+    header = tmp = tmp_pre = NULL;
+    if (virDirOpenQuiet(&dp, RESCTRL_DIR) < 0) {
+        if (errno == ENOENT)
+            return NULL;
+        VIR_ERROR(_("Unable to open %s (%d)"), RESCTRL_DIR, errno);
+        goto cleanup;
+    }
+
+    header = virResCtrlLoadDomain(NULL);
+    if (header == NULL)
+        goto cleanup;
+
+    header->next = NULL;
+
+    *len = 1;
+
+    while ((direrr = virDirRead(dp, &ent, NULL)) > 0) {
+        if ((ent->d_type != DT_DIR) || STREQ(ent->d_name, "info"))
+            continue;
+
+        tmp = virResCtrlLoadDomain(ent->d_name);
+        if (tmp == NULL)
+            goto cleanup;
+
+        tmp->next = NULL;
+
+        if(header->next == NULL)
+            header->next = tmp;
+
+        if(tmp_pre == NULL)
+            tmp->pre = header;
+        else {
+            tmp->pre = tmp_pre;
+            tmp_pre->next = tmp;
+        }
+
+        tmp_pre = tmp;
+        (*len) ++;
+    }
+    return header;
+
+cleanup:
+    VIR_DIR_CLOSE(dp);
+    tmp_pre = tmp = header;
+    while(tmp) {
+        tmp_pre = tmp;
+        tmp = tmp->next;
+        VIR_FREE(tmp_pre);
+    }
+    return NULL;
+}
+
+static int
+virResCtrlAppendDomain(virResDomainPtr dom)
+{
+    virResDomainPtr p = DomainAll.domains;
+    while(p->next != NULL) p=p->next;
+    p->next = dom;
+    dom->pre = p;
+    DomainAll.num_domains +=1;
+    return 0;
+}
+
+static int
+virResCtrlGetSocketIdByHostID(int type, unsigned int hostid)
+{
+    int i;
+    for( i = 0; i < ResCtrlAll[type].num_banks; i++) {
+        if(ResCtrlAll[type].cache_banks[i].host_id == hostid)
+            return i;
+    }
+    return -1;
+}
+
+static int
+virResCtrlCalculateSchemata(int type,
+                            int sid,
+                            unsigned hostid,
+                            unsigned long long size)
+{
+    int i;
+    int count;
+    virResDomainPtr p;
+    unsigned int tmp_schemata;
+    unsigned int schemata_sum = 0;
+
+    if(ResCtrlAll[type].cache_banks[sid].cache_left < size) {
+        VIR_ERROR("Note enough cache left on bank %u", hostid);
+        return -1;
+    }
+    if ((count = size / ResCtrlAll[type].cache_banks[sid].cache_min) <= 0) {
+        VIR_ERROR("Error cache size %llu", size);
+        return -1;
+    }
+
+    tmp_schemata = VIR_RESCTRL_GET_SCHEMATA(count);
+
+    p = DomainAll.domains;
+    p = p->next;
+    for (i = 1; i < DomainAll.num_domains; i ++) {
+        schemata_sum |= p->schematas[type]->schemata_items[sid].schemata;
+        p = p->next;
+    }
+
+    tmp_schemata = tmp_schemata << (ResCtrlAll[type].cbm_len - count);
+
+    while ((tmp_schemata & schemata_sum) != 0)
+        tmp_schemata = tmp_schemata >> 1;
+    return tmp_schemata;
+}
+
+int virResCtrlSetCacheBanks(virDomainCachetunePtr cachetune,
+                            unsigned char* uuid, pid_t pid)
+{
+    size_t i;
+    char name[VIR_UUID_STRING_BUFLEN];
+    virResDomainPtr p;
+    int type;
+    int sid;
+    int schemata;
+
+    virUUIDFormat(uuid, name);
+
+    for(i = 0 ; i < cachetune->n_banks; i++) {
+        VIR_DEBUG("cache_banks %u, %u, %llu, %s",
+                 cachetune->cache_banks[i].id,
+                 cachetune->cache_banks[i].host_id,
+                 cachetune->cache_banks[i].size,
+                 cachetune->cache_banks[i].type);
+    }
+
+    if (cachetune->n_banks < 1)
+        return 0;
+
+    p = virResCtrlGetDomain(name);
+    if (p == NULL) {
+        VIR_DEBUG("no domain name %s found, create new one!", name);
+        p = virResCtrlCreateDomain(name);
+    }
+
+    if (p != NULL) {
+        for(i = 0 ; i < cachetune->n_banks; i++) {
+            if ((type = virResCtrlTypeFromString(
+                            cachetune->cache_banks[i].type)) < 0 ) {
+                VIR_WARN("Ignore unknown cache type %s.",
+                         cachetune->cache_banks[i].type);
+                continue;
+            }
+
+            if((sid = virResCtrlGetSocketIdByHostID(
+                            type, cachetune->cache_banks[i].host_id)) < 0) {
+                VIR_WARN("Can not find cache bank host id %u.",
+                         cachetune->cache_banks[i].host_id);
+                continue;
+            }
+
+            if((schemata = virResCtrlCalculateSchemata(
+                            type, sid, cachetune->cache_banks[i].host_id,
+                            cachetune->cache_banks[i].size)) < 0) {
+                VIR_WARN("Failed to set schemata for cache bank id %u",
+                         cachetune->cache_banks[i].id);
+                continue;
+            }
+
+            p->schematas[type]->schemata_items[sid].schemata = schemata;
+        }
+
+        virResCtrlAddTask(p, pid);
+
+        if(virResCtrlFlushDomainToSysfs(p) < 0) {
+            VIR_WARN("failed to flush domain %s to sysfs", name);
+            virResCtrlDestroyDomain(p);
+            return -1;
+        }
+        virResCtrlAppendDomain(p);
+    } else {
+        VIR_ERROR("Failed to create a domain in sysfs");
+        return -1;
+    }
+
+    virResCtrlRefresh();
+    /* after refresh, flush header's schemata changes to sys fs */
+    if(virResCtrlFlushDomainToSysfs(DomainAll.domains) < 0)
+        VIR_WARN("failed to flush domain to sysfs");
+
+    return 0;
+}
+
+/* Should be called after pid disappeared, we recalculate
+ * schemata of default and flush it to sys fs.
+ */
+int virResCtrlUpdate(void) {
+    int rc;
+    if ((rc = virResCtrlRefresh()) < 0)
+        VIR_WARN("failed to refresh rescontrol");
+
+    if ((rc = virResCtrlFlushDomainToSysfs(DomainAll.domains)) < 0)
+        VIR_WARN("failed to flush domain to sysfs");
+
+    return rc;
+}
+
 int virResCtrlInit(void) {
     int i = 0;
     char *tmp;
@@ -341,6 +978,11 @@ int virResCtrlInit(void) {
 
         VIR_FREE(tmp);
     }
+
+    DomainAll.domains = virResCtrlGetAllDomains(&(DomainAll.num_domains));
+
+    if((rc = virResCtrlRefresh()) < 0)
+        VIR_WARN("failed to refresh resource control");
     return rc;
 }
 
diff --git a/src/util/virresctrl.h b/src/util/virresctrl.h
index 3cc41da..11f43d8 100644
--- a/src/util/virresctrl.h
+++ b/src/util/virresctrl.h
@@ -26,6 +26,7 @@
 
 # include "virutil.h"
 # include "virbitmap.h"
+# include "domain_conf.h"
 
 #define RESCTRL_DIR "/sys/fs/resctrl"
 #define RESCTRL_INFO_DIR "/sys/fs/resctrl/info"
@@ -82,9 +83,53 @@ struct _virResCtrl {
         virResCacheBankPtr      cache_banks;
 };
 
+/**
+ * a virResSchemata represents a schemata object under a resource control
+ * domain.
+ */
+typedef struct _virResSchemataItem virResSchemataItem;
+typedef virResSchemataItem *virResSchemataItemPtr;
+struct _virResSchemataItem {
+    unsigned int socket_no;
+    unsigned schemata;
+};
+
+typedef struct _virResSchemata virResSchemata;
+typedef virResSchemata *virResSchemataPtr;
+struct _virResSchemata {
+    unsigned int n_schemata_items;
+    virResSchemataItemPtr schemata_items;
+};
+
+/**
+ * a virResDomain represents a resource control domain. It's a double linked
+ * list.
+ */
+
+typedef struct _virResDomain virResDomain;
+typedef virResDomain *virResDomainPtr;
+
+struct _virResDomain {
+    char* name;
+    virResSchemataPtr schematas[RDT_NUM_RESOURCES];
+    char* tasks;
+    int n_sockets;
+    virResDomainPtr pre;
+    virResDomainPtr next;
+};
+
+/* All resource control domains on this host*/
+
+typedef struct _virResCtrlDomain virResCtrlDomain;
+typedef virResCtrlDomain *virResCtrlDomainPtr;
+struct _virResCtrlDomain {
+    unsigned int num_domains;
+    virResDomainPtr domains;
+};
 
 bool virResCtrlAvailable(void);
 int virResCtrlInit(void);
 virResCtrlPtr virResCtrlGet(int);
-
+int virResCtrlSetCacheBanks(virDomainCachetunePtr, unsigned char*, pid_t);
+int virResCtrlUpdate(void);
 #endif
-- 
1.9.1

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]
  Powered by Linux