At the same time, in the qemu driver this is exposed as
qemuNodeHugeTLB.
Signed-off-by: Michal Privoznik <mprivozn(a)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(¶ms[i],
+ VIR_NODE_HUGE_PAGE_SIZE,
+ VIR_TYPED_PARAM_ULLONG,
+ page_size) < 0)
+ goto cleanup;
+ i++;
+
+ if (i < *nparams &&
+ virTypedParameterAssign(¶ms[i],
+ VIR_NODE_HUGE_PAGE_AVAILABLE,
+ VIR_TYPED_PARAM_ULLONG,
+ page_avail) < 0)
+ goto cleanup;
+ i++;
+
+ if (i < *nparams &&
+ virTypedParameterAssign(¶ms[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