At the same time, in the qemu driver this is exposed as qemuNodeHugeTLB. Signed-off-by: Michal Privoznik <mprivozn@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list