libvirt/tests/virnumamock.c

195 lines
4.7 KiB
C

/*
* virnumamock.c: Mock some virNuma functions using sysfs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "internal.h"
#include "virmock.h"
#include "virnuma.h"
#include "virfile.h"
#include "viralloc.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_NONE
#define SYSFS_SYSTEM_PATH "/sys/devices/system"
static int numa_avail = -1;
/*
* Poor man's mocked NUMA guesser. We basically check if
* /sys/devices/system/node (where /sys/devices/system can already be mocked or
* changed in the tests) exists and cache the result.
*/
bool
virNumaIsAvailable(void)
{
if (numa_avail < 0) {
char *sysfs_node_path = NULL;
if (virAsprintfQuiet(&sysfs_node_path, "%s/node", SYSFS_SYSTEM_PATH) < 0)
return false;
numa_avail = virFileExists(sysfs_node_path);
VIR_FREE(sysfs_node_path);
}
/*
* Quite a few more things need to be mocked if NUMA is not available and
* you are using this file. Do not remove the abort() call below unless you
* make sure all under virCapabilitiesInitNUMAFake() is mocked (and whatever
* might have changed since this comment was added. You are welcome.
*/
if (!numa_avail)
abort();
return numa_avail;
}
int
virNumaGetMaxNode(void)
{
int ret = -1;
virBitmapPtr map = NULL;
if (virFileReadValueBitmap(&map, "%s/node/online", SYSFS_SYSTEM_PATH) < 0)
return -1;
ret = virBitmapLastSetBit(map);
virBitmapFree(map);
return ret;
}
bool
virNumaNodeIsAvailable(int node)
{
bool ret = false;
virBitmapPtr map = NULL;
if (virFileReadValueBitmap(&map, "%s/node/online", SYSFS_SYSTEM_PATH) < 0)
return false;
ret = virBitmapIsBitSet(map, node);
virBitmapFree(map);
return ret;
}
int
virNumaGetNodeMemory(int node,
unsigned long long *memsize,
unsigned long long *memfree)
{
const unsigned long long base = 1 << 30;
if (memsize)
*memsize = base * (node + 1);
if (memfree)
*memfree = base;
return 0;
}
int
virNumaGetDistances(int node G_GNUC_UNUSED,
int **distances,
int *ndistances)
{
*distances = NULL;
*ndistances = 0;
return 0;
}
/*
* TODO: Adapt virNumaGetHugePageInfo{Path,Dir} to use sysfs so that the
* paths can be modified and this function can be thrown away and instead we'd
* have copied info from /sys (as we do with /sys/devices/system).
*/
int
virNumaGetPages(int node,
unsigned int **pages_size,
unsigned long long **pages_avail,
unsigned long long **pages_free,
size_t *npages)
{
const int pages_def[] = { 4, 2 * 1024, 1 * 1024 * 1024};
const int npages_def = G_N_ELEMENTS(pages_def);
size_t i = 0;
if (pages_size)
*pages_size = NULL;
if (pages_avail)
*pages_avail = NULL;
if (pages_free)
*pages_free = NULL;
*npages = 0;
if ((pages_size && VIR_ALLOC_N(*pages_size, npages_def) < 0) ||
(pages_avail && VIR_ALLOC_N(*pages_avail, npages_def) < 0) ||
(pages_free && VIR_ALLOC_N(*pages_free, npages_def) < 0)) {
VIR_FREE(*pages_size);
VIR_FREE(*pages_avail);
return -1;
}
*npages = npages_def;
if (pages_size)
memcpy(*pages_size, pages_def, sizeof(pages_def));
node++;
if (node <= 0)
node = 32;
if (pages_avail || pages_free) {
for (i = 0; i < *npages; i++) {
if (pages_avail)
(*pages_avail)[i] = (node + i) * 2 << 10;
if (pages_free)
(*pages_free)[i] = (node + i) * 1 << 10;
}
}
return 0;
}
int
virNumaGetNodeCPUs(int node, virBitmapPtr *cpus)
{
int ret = -1;
char *cpulist = NULL;
if (virFileReadValueString(&cpulist,
"%s/node/node%u/cpulist",
SYSFS_SYSTEM_PATH, node) < 0)
return -1;
*cpus = virBitmapParseUnlimited(cpulist);
if (!*cpus)
goto cleanup;
ret = virBitmapCountBits(*cpus);
cleanup:
VIR_FREE(cpulist);
return ret;
}