util: pull gnulib physmem impl into local code

We don't need all the platforms gnulib deals with, so
this is a cut down version of GNULIB's physmem.c
code. This also allows us to integrate libvirt's
error reporting functions closer to the error cause.

Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2020-01-08 13:54:17 +00:00
parent 210e19702e
commit 4f128bbbfb
4 changed files with 153 additions and 33 deletions

View File

@ -2320,7 +2320,7 @@ exclude_file_name_regexp--sc_prohibit_virXXXFree = \
^(docs/|tests/|examples/|tools/|build-aux/syntax-check\.mk|src/test/test_driver.c|src/libvirt_public.syms|include/libvirt/libvirt-(domain|network|nodedev|storage|stream|secret|nwfilter|interface|domain-snapshot).h|src/libvirt-(domain|qemu|network|nodedev|storage|stream|secret|nwfilter|interface|domain-snapshot).c$$)
exclude_file_name_regexp--sc_prohibit_sysconf_pagesize = \
^(build-aux/syntax-check\.mk|src/util/virutil\.c)$$
^(build-aux/syntax-check\.mk|src/util/vir(hostmem|util)\.c)$$
exclude_file_name_regexp--sc_prohibit_pthread_create = \
^(build-aux/syntax-check\.mk|src/util/virthread\.c|tests/.*)$$

View File

@ -26,7 +26,6 @@
#include "capabilities.h"
#include "cpu_conf.h"
#include "domain_conf.h"
#include "physmem.h"
#include "storage_conf.h"
#include "viralloc.h"
#include "virarch.h"

View File

@ -41,7 +41,6 @@
#include "viralloc.h"
#define LIBVIRT_VIRHOSTCPUPRIV_H_ALLOW
#include "virhostcpupriv.h"
#include "physmem.h"
#include "virerror.h"
#include "virarch.h"
#include "virfile.h"

View File

@ -33,9 +33,13 @@
# include <sys/resource.h>
#endif
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif
#include "viralloc.h"
#include "virhostmem.h"
#include "physmem.h"
#include "virerror.h"
#include "virarch.h"
#include "virfile.h"
@ -577,13 +581,151 @@ virHostMemGetParameters(virTypedParameterPtr params G_GNUC_UNUSED,
}
#ifdef WIN32
/* MEMORYSTATUSEX is missing from older windows headers, so define
a local replacement. */
typedef struct
{
DWORD dwLength;
DWORD dwMemoryLoad;
DWORDLONG ullTotalPhys;
DWORDLONG ullAvailPhys;
DWORDLONG ullTotalPageFile;
DWORDLONG ullAvailPageFile;
DWORDLONG ullTotalVirtual;
DWORDLONG ullAvailVirtual;
DWORDLONG ullAvailExtendedVirtual;
} lMEMORYSTATUSEX;
typedef WINBOOL(WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*);
#endif /* !WIN32 */
static unsigned long long
virHostMemGetTotal(void)
{
#if defined HAVE_SYSCTLBYNAME
/* This works on freebsd & macOS. */
unsigned long long physmem = 0;
size_t len = sizeof(physmem);
if (sysctlbyname("hw.physmem", &physmem, &len, NULL, 0) < 0) {
virReportSystemError(errno, "%s",
_("Unable to query memory total"));
return 0;
}
return physmem;
#elif defined _SC_PHYS_PAGES && defined _SC_PAGESIZE
/* this works on linux */
long long pages;
long long pagesize;
if ((pages = sysconf(_SC_PHYS_PAGES)) < 0) {
virReportSystemError(errno, "%s",
_("Unable to query memory total"));
return 0;
}
if ((pagesize = sysconf(_SC_PAGESIZE)) < 0) {
virReportSystemError(errno, "%s",
_("Unable to query memory page size"));
return 0;
}
return (unsigned long long)pages * (unsigned long long)pagesize;
#elif defined WIN32
PFN_MS_EX pfnex;
HMODULE h = GetModuleHandle("kernel32.dll");
if (!h) {
virReportSystemError(errno, "%s",
_("Unable to access kernel32.dll"));
return 0;
}
/* Use GlobalMemoryStatusEx if available. */
if ((pfnex = (PFN_MS_EX) GetProcAddress(h, "GlobalMemoryStatusEx"))) {
lMEMORYSTATUSEX lms_ex;
lms_ex.dwLength = sizeof(lms_ex);
if (!pfnex(&lms_ex)) {
virReportSystemError(EIO, "%s",
_("Unable to query memory total"));
return 0;
}
return lms_ex.ullTotalPhys;
} else {
/* Fall back to GlobalMemoryStatus which is always available.
but returns wrong results for physical memory > 4GB. */
MEMORYSTATUS ms;
GlobalMemoryStatus(&ms);
return ms.dwTotalPhys;
}
#endif
}
static unsigned long long
virHostMemGetAvailable(void)
{
#if defined HAVE_SYSCTLBYNAME
/* This works on freebsd and macOS */
unsigned long long usermem = 0;
size_t len = sizeof(usermem);
if (sysctlbyname("hw.usermem", &usermem, &len, NULL, 0) < 0) {
virReportSystemError(errno, "%s",
_("Unable to query memory available"));
return 0;
}
return usermem;
#elif defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE
/* this works on linux */
long long pages;
long long pagesize;
if ((pages = sysconf(_SC_AVPHYS_PAGES)) < 0) {
virReportSystemError(errno, "%s",
_("Unable to query memory available"));
return 0;
}
if ((pagesize = sysconf(_SC_PAGESIZE)) < 0) {
virReportSystemError(errno, "%s",
_("Unable to query memory page size"));
return 0;
}
return (unsigned long long)pages * (unsigned long long)pagesize;
#elif defined WIN32
PFN_MS_EX pfnex;
HMODULE h = GetModuleHandle("kernel32.dll");
if (!h) {
virReportSystemError(errno, "%s",
_("Unable to access kernel32.dll"));
return 0;
}
/* Use GlobalMemoryStatusEx if available. */
if ((pfnex = (PFN_MS_EX) GetProcAddress(h, "GlobalMemoryStatusEx"))) {
lMEMORYSTATUSEX lms_ex;
lms_ex.dwLength = sizeof(lms_ex);
if (!pfnex(&lms_ex)) {
virReportSystemError(EIO, "%s",
_("Unable to query memory available"));
return 0;
}
return lms_ex.ullAvailPhys;
} else {
/* Fall back to GlobalMemoryStatus which is always available.
but returns wrong results for physical memory > 4GB */
MEMORYSTATUS ms;
GlobalMemoryStatus(&ms);
return ms.dwAvailPhys;
}
#endif
}
static int
virHostMemGetCellsFreeFake(unsigned long long *freeMems,
int startCell,
int maxCells G_GNUC_UNUSED)
{
double avail = physmem_available();
if (startCell != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("start cell %d out of range (0-%d)"),
@ -591,13 +733,8 @@ virHostMemGetCellsFreeFake(unsigned long long *freeMems,
return -1;
}
freeMems[0] = (unsigned long long)avail;
if (!freeMems[0]) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot determine free memory"));
if ((freeMems[0] = virHostMemGetAvailable()) == 0)
return -1;
}
return 1;
}
@ -606,28 +743,13 @@ static int
virHostMemGetInfoFake(unsigned long long *mem,
unsigned long long *freeMem)
{
if (mem) {
double total = physmem_total();
if (!total) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot determine free memory"));
return -1;
}
if (mem &&
(*mem = virHostMemGetTotal()) == 0)
return -1;
*mem = (unsigned long long) total;
}
if (freeMem) {
double avail = physmem_available();
if (!avail) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Cannot determine free memory"));
return -1;
}
*freeMem = (unsigned long long) avail;
}
if (freeMem &&
(*freeMem = virHostMemGetAvailable()) == 0)
return -1;
return 0;
}