On 5/3/21 1:07 PM, Peter Krempa wrote:
On Fri, Apr 23, 2021 at 15:24:23 +0200, Michal Privoznik wrote:
> New virHostMemGetTHPSize() is introduced which allows caller to
> obtain THP PMD (Page Middle Directory) size, which is equal to
> the minimal size that THP can use, taken from kernel doc
> (Documentation/admin-guide/mm/transhuge.rst):
>
> Some userspace (such as a test program, or an optimized memory allocation
> library) may want to know the size (in bytes) of a transparent hugepage::
>
> cat /sys/kernel/mm/transparent_hugepage/hpage_pmd_size
>
> Since this size depends on the host architecture and the kernel
> it won't change whilst libvirtd is running. Therefore, we can use
> virOnce() and cache the value. Of course, we can be running under
> kernel that has THP disabled or has no notion of THP at all. In
> that case a negative value is returned to signal error.
>
> Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
> ---
> src/libvirt_private.syms | 1 +
> src/util/virhostmem.c | 63 ++++++++++++++++++++++++++++++++++++++++
> src/util/virhostmem.h | 3 ++
> tests/domaincapsmock.c | 9 ++++++
> 4 files changed, 76 insertions(+)
[...]
> diff --git a/src/util/virhostmem.c b/src/util/virhostmem.c
> index ae42978ed2..89b31af3ca 100644
> --- a/src/util/virhostmem.c
> +++ b/src/util/virhostmem.c
> @@ -45,11 +45,14 @@
> #include "virstring.h"
> #include "virnuma.h"
> #include "virlog.h"
> +#include "virthread.h"
>
> #define VIR_FROM_THIS VIR_FROM_NONE
>
> VIR_LOG_INIT("util.hostmem");
>
> +static unsigned long long virHostTHPPMDSize; /* in kibibytes */
> +static virOnceControl virHostMemGetTHPSizeOnce = VIR_ONCE_CONTROL_INITIALIZER;
>
> #ifdef __FreeBSD__
> # define BSD_MEMORY_STATS_ALL 4
> @@ -920,3 +923,63 @@ virHostMemAllocPages(unsigned int npages,
>
> return ncounts;
> }
> +
> +#if defined(__linux__)
> +# define HPAGE_PMD_SIZE_PATH
"/sys/kernel/mm/transparent_hugepage/hpage_pmd_size"
> +static int
Nothing checks the return value.
> +virHostMemGetTHPSizeSysfs(unsigned long long *size)
> +{
> + g_autofree char *buf = NULL;
> +
> + /* 1KiB limit is more than enough. */
> + if (virFileReadAll(HPAGE_PMD_SIZE_PATH, 1024, &buf) < 0)
> + return -1;
> +
> + virStringTrimOptionalNewline(buf);
> + if (virStrToLong_ull(buf, NULL, 10, size) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("unable to parse THP PMD size: %s"), buf);
> + return -1;
> + }
> +
> + /* Size is now in bytes. Convert to KiB. */
> + *size >>= 10;
> + return 0;
> +}
> +#endif /* defined(__linux__) */
> +
> +
> +static void
> +virHostMemGetTHPSizeOnceInit(void)
> +{
> +#if defined(__linux__)
> + virHostMemGetTHPSizeSysfs(&virHostTHPPMDSize);
> +#else /* !defined(__linux__) */
> + VIR_WARN("Getting THP size not ported yet");
> +#endif /* !defined(__linux__) */
> +}
> +
> +
> +/**
> + * virHostMemGetTHPSize:
> + * @size: returned size of THP in kibibytes
> + *
> + * Obtain Transparent Huge Page size in kibibytes. The size
> + * depends on host architecture and kernel. Because of virOnce(),
> + * do not rely on errno in case of failure.
> + *
> + * Returns: 0 on success,
> + * -1 on failure.
> + */
> +int
> +virHostMemGetTHPSize(unsigned long long *size)
> +{
> + if (virOnce(&virHostMemGetTHPSizeOnce, virHostMemGetTHPSizeOnceInit) <
0)
This directly returns the return value from 'pthread_once' whose manual
entry states:
RETURN VALUE
Upon successful completion, pthread_once() shall return zero; otherwise, an error
number shall be returned to indicate the error.
Which reads as if 'errno' is returned by the function which would make
the '< 0' check wrong.
Interesting, never though about this. Just blindly copied what we have
elsewhere. Looking into glibc - pthread_once will never return anything
else than 0. Then uclibc-ng doesn't provide pthread_once and musl also
always returns 0. I'll send a patch that fixes this issue shortly.
Michal