/* * 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 * . */ #include #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 = ARRAY_CARDINALITY(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; }