[libvirt] [PATCH 03/12] nodeinfo: Implement nodeHugeTLB

Michal Privoznik mprivozn at redhat.com
Thu May 29 08:32:37 UTC 2014


At the same time, in the qemu driver this is exposed as
qemuNodeHugeTLB.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 include/libvirt/libvirt.h.in |  20 +++++
 src/libvirt.c                |  13 +++-
 src/libvirt_private.syms     |   1 +
 src/nodeinfo.c               | 177 +++++++++++++++++++++++++++++++++++++++++++
 src/nodeinfo.h               |   5 ++
 src/qemu/qemu_driver.c       |  14 ++++
 6 files changed, 226 insertions(+), 4 deletions(-)

diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index cb1cad9..c492129 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -858,6 +858,26 @@ int virNodeSetMemoryParameters(virConnectPtr conn,
                                int nparams,
                                unsigned int flags);
 
+/* VIR_NODE_HUGE_PAGE_SIZE:
+ *
+ * Macro for typed parameter that represents a huge page size.
+ * The size is expressed in kibibytes, so for example 2MB is
+ * expressed as 2048. */
+# define VIR_NODE_HUGE_PAGE_SIZE "hugepage_size"
+
+/* VIR_NODE_HUGE_PAGE_AVAILABLE:
+ *
+ * Macro for typed parameter that represents the size of the pool
+ * of huge pages of certain size. It's the sum of allocated plus
+ * free. */
+# define VIR_NODE_HUGE_PAGE_AVAILABLE "hugepage_available"
+
+/* VIR_NODE_HUGE_PAGE_FREE:
+ *
+ * Macro for typed parameter that represents the number of huge
+ * pages in the pool that are not yet allocated. */
+# define VIR_NODE_HUGE_PAGE_FREE "hugepage_free"
+
 int virNodeHugeTLB(virConnectPtr conn,
                    int type,
                    virTypedParameterPtr params,
diff --git a/src/libvirt.c b/src/libvirt.c
index de20b0c..ab7c347 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -7569,10 +7569,15 @@ virNodeSetMemoryParameters(virConnectPtr conn,
  * @nparams: pointer to number of memory parameters; input and output
  * @flags: extra flags; not used yet, so callers should always pass 0
  *
- * Get information about host's huge pages. On input, @nparams
- * gives the size of the @params array; on output, @nparams gives
- * how many slots were filled with parameter information, which
- * might be less but will not exceed the input value.
+ * Get information about host's huge pages. The parameters are
+ * positioned. That is, they form a tuple starting with
+ * VIR_NODE_HUGE_PAGE_SIZE followed by other values (e.g.
+ * VIR_NODE_HUGE_PAGE_AVAILABLE and VIR_NODE_HUGE_PAGE_FREE).
+ * Next tuple again starts with the size parameter. On input,
+ * @nparams gives the size of the @params array; on output,
+ * @nparams gives how many slots were filled with parameter
+ * information, which might be less but will not exceed the
+ * input value.
  *
  * As a special case, calling with @params as NULL and @nparams
  * as 0 on input will cause @nparams on output to contain the
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index cb635cd..1d97c89 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -874,6 +874,7 @@ nodeGetFreeMemory;
 nodeGetInfo;
 nodeGetMemoryParameters;
 nodeGetMemoryStats;
+nodeHugeTLB;
 nodeSetMemoryParameters;
 
 
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 56f2b02..be63a30 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -1880,3 +1880,180 @@ nodeGetFreeMemory(void)
 
     return freeMem;
 }
+
+static int
+nodeHugePageDumpInfo(const char *prefix,
+                     const char *name,
+                     unsigned long long *page_avail,
+                     unsigned long long *page_free)
+{
+    int ret = -1;
+    char *buf = NULL;
+    char *path = NULL;
+    char *end;
+
+    if (virAsprintf(&path, "%s/%s/nr_hugepages", prefix, name) < 0)
+        goto cleanup;
+
+    if (virFileReadAll(path, 1024, &buf) < 0) {
+        virReportSystemError(errno,
+                             _("unable to read %s"),
+                             path);
+        goto cleanup;
+    }
+
+    if (virStrToLong_ull(buf, &end, 10, page_avail) < 0 ||
+        *end != '\n') {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unable to parse: %s"),
+                       buf);
+        goto cleanup;
+    }
+
+    VIR_FREE(path);
+    VIR_FREE(buf);
+
+    if (virAsprintf(&path, "%s/%s/free_hugepages", prefix, name) < 0)
+        goto cleanup;
+
+    if (virFileReadAll(path, 1024, &buf) < 0) {
+        virReportSystemError(errno,
+                             _("unable to read %s"),
+                             path);
+        goto cleanup;
+    }
+
+    if (virStrToLong_ull(buf, &end, 10, page_free) < 0 ||
+        *end != '\n') {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("unable to parse: %s"),
+                       buf);
+        goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(path);
+    VIR_FREE(buf);
+    return ret;
+}
+
+#define HUGEPAGES_PREFIX "hugepages-"
+
+static int
+nodeHugePageSupported(const char *prefix,
+                      virTypedParameterPtr params,
+                      int *nparams)
+{
+    int ret = -1;
+    DIR *dir = NULL;
+    struct dirent *entry = NULL;
+    size_t i = 0;
+
+    if (!(dir = opendir(prefix))) {
+        virReportSystemError(errno,
+                             _("failed to open path: %s"),
+                             prefix);
+        return ret;
+    }
+
+    while (virDirRead(dir, &entry, prefix) > 0) {
+        const char *page_name = entry->d_name;
+        unsigned long long page_size, page_avail, page_free;
+        char *end;
+
+        /* Just to give you a hint, we're dealing with this:
+         * hugepages-2048kB/  or   hugepages-1048576kB/ */
+        if (!STRPREFIX(entry->d_name, HUGEPAGES_PREFIX))
+            continue;
+
+        page_name += strlen(HUGEPAGES_PREFIX);
+
+        if (virStrToLong_ull(page_name, &end, 10, &page_size) < 0 ||
+            STRCASENEQ(end, "kB")) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("unable to parse %s"),
+                           entry->d_name);
+            goto cleanup;
+        }
+
+        if (nodeHugePageDumpInfo(prefix, entry->d_name,
+                                 &page_avail, &page_free) < 0)
+            goto cleanup;
+
+        if (!params) {
+            (*nparams) += 3;
+        } else {
+            if (i < *nparams &&
+                virTypedParameterAssign(&params[i],
+                                        VIR_NODE_HUGE_PAGE_SIZE,
+                                        VIR_TYPED_PARAM_ULLONG,
+                                        page_size) < 0)
+                goto cleanup;
+            i++;
+
+            if (i < *nparams &&
+                virTypedParameterAssign(&params[i],
+                                        VIR_NODE_HUGE_PAGE_AVAILABLE,
+                                        VIR_TYPED_PARAM_ULLONG,
+                                        page_avail) < 0)
+                goto cleanup;
+            i++;
+
+            if (i < *nparams &&
+                virTypedParameterAssign(&params[i],
+                                        VIR_NODE_HUGE_PAGE_FREE,
+                                        VIR_TYPED_PARAM_ULLONG,
+                                        page_free) < 0)
+                goto cleanup;
+            i++;
+        }
+    }
+
+    if (i)
+        *nparams = i;
+
+    ret = 0;
+
+ cleanup:
+    closedir(dir);
+    return ret;
+}
+
+#define HUGEPAGES_HOST_PREFIX "/sys/kernel/mm/hugepages/"
+#define HUGEPAGES_NUMA_PREFIX "/sys/devices/system/node/"
+
+static int
+nodeHugePageInfo(int node,
+                 virTypedParameterPtr params,
+                 int *nparams)
+{
+    int ret = -1;
+    char *path = NULL;
+
+    if (virAsprintf(&path, HUGEPAGES_NUMA_PREFIX "node%d/hugepages/", node) < 0)
+        goto cleanup;
+
+    if (nodeHugePageSupported(path, params, nparams) < 0)
+        goto cleanup;
+
+    ret = 0;
+ cleanup:
+    VIR_FREE(path);
+    return ret;
+}
+
+int nodeHugeTLB(int type,
+                virTypedParameterPtr params,
+                int *nparams,
+                unsigned int flags)
+{
+    int ret = -1;
+
+    virCheckFlags(0, ret);
+
+    if (type == -1)
+        return nodeHugePageSupported(HUGEPAGES_HOST_PREFIX, params, nparams);
+
+    return nodeHugePageInfo(type, params, nparams);
+}
diff --git a/src/nodeinfo.h b/src/nodeinfo.h
index c81fcbb..625de39 100644
--- a/src/nodeinfo.h
+++ b/src/nodeinfo.h
@@ -53,6 +53,11 @@ int nodeSetMemoryParameters(virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags);
 
+int nodeHugeTLB(int type,
+                virTypedParameterPtr params,
+                int *nparams,
+                unsigned int flags);
+
 int nodeGetCPUMap(unsigned char **cpumap,
                   unsigned int *online,
                   unsigned int flags);
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9becc0a..aa7deb3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -16690,6 +16690,19 @@ qemuDomainSetTime(virDomainPtr dom,
     return ret;
 }
 
+static int
+qemuNodeHugeTLB(virConnectPtr conn,
+                int type,
+                virTypedParameterPtr params,
+                int *nparams,
+                unsigned int flags)
+{
+    if (virNodeHugeTlbEnsureACL(conn) < 0)
+        return -1;
+
+    return nodeHugeTLB(type, params, nparams, flags);
+}
+
 
 static int
 qemuDomainFSFreeze(virDomainPtr dom,
@@ -16975,6 +16988,7 @@ static virDriver qemuDriver = {
     .domainFSThaw = qemuDomainFSThaw, /* 1.2.5 */
     .domainGetTime = qemuDomainGetTime, /* 1.2.5 */
     .domainSetTime = qemuDomainSetTime, /* 1.2.5 */
+    .nodeHugeTLB = qemuNodeHugeTLB, /* 1.2.6 */
 };
 
 
-- 
1.9.3




More information about the libvir-list mailing list