[libvirt] [PATCH 0/8] RFC New API to retrieve host node CPU map

Rationale: In order to use the APIs listed below it is necessary for a client to know the maximum number of node CPUs which is passed via the maplen argument. virDomainGetEmulatorPinInfo virDomainGetVcpuPinInfo virDomainGetVcpus virDomainPinEmulator virDomainPinVcpu virDomainPinVcpuFlags The current approach uses virNodeGetInfo to determine the maximum CPU number. This can lead to incorrect results if not all node CPUs are online. The maximum CPU number should always be the number of CPUs present on the host, regardless of their online/offline state. The following example illustrates the issue: Host has 3 logical CPUs, 1 socket, 3 cores, 1 thread. Guest has 1 virtual CPU and is started while all 3 host CPUs are online. $ virsh vcpuinfo guest VCPU: 0 CPU: 0 State: running CPU time: 35.4s CPU Affinity: yyy $ echo 0 > /sys/devices/system/cpu/cpu1/online $ virsh vcpuinfo guest VCPU: 0 CPU: 0 State: running CPU time: 35.5s CPU Affinity: y- The correct display for CPU affinity would have been y-y, as the guest continues to use CPUs 0 and 2. This is not a display problem only, because it is also not possible to explicitly pin the virtual CPU to host CPUs 0 and 2, due to the truncated CPU mask. PROPOSAL: To help solve the issue above I suggest a new public API: int virNodeGetCPUMapFlags(virConnectPtr conn, unsigned char **cpumap, unsigned int *online, unsigned int flags); The function will return the number of CPUs present on the host or -1 on failure; If cpumap is non-NULL virNodeGetCPUMapFlags will allocate an array containing a bit map representation of the online CPUs. It's the callers responsibility to deallocate cpumap using free(). If online is non-NULL, the variable pointed to will contain the number of online host node CPUs. The variable flags has been added to support future extensions and must be set to 0. Clients can use virNodeGetCPUMapFlags to properly determine the maximum number of node CPUs and their online/offline state. Remarks: This series implements the QEMU and test drivers. This series doesn't introduce changes to the existing vcpu pinning, which I would submit as a succeeding patch set. No python binding yet. Viktor Mihajlovski (8): virNodeGetCPUMapFlags: Define public API. virNodeGetCPUMapFlags: Define driver API. virNodeGetCPUMapFlags: Implement public API. virNodeGetCPUMapFlags: Implement wire protocol. libvirt.h.in: Add new cpumap macro VIR_CPU_USED virNodeGetCPUMapFlags: Implement virsh support. virNodeGetCPUMapFlags: Implement support function in nodeinfo virNodeGetCPUMapFlags: Implement driver support daemon/remote.c | 44 +++++++++++++++++++++++++++++++++ include/libvirt/libvirt.h.in | 28 ++++++++++++++++++--- python/generator.py | 1 + src/driver.h | 7 +++++ src/libvirt.c | 56 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_private.syms | 1 + src/libvirt_public.syms | 5 +++ src/nodeinfo.c | 49 ++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 6 ++++ src/qemu/qemu_driver.c | 1 + src/remote/remote_driver.c | 49 ++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 13 +++++++++- src/remote_protocol-structs | 12 +++++++++ src/test/test_driver.c | 30 ++++++++++++++++++++++ tools/virsh-host.c | 41 ++++++++++++++++++++++++++++++ tools/virsh.pod | 5 +++ 16 files changed, 343 insertions(+), 5 deletions(-)

Adding a new API to obtain information about the host node's present, online and offline CPUs. int virNodeGetCPUMapFlags(virConnectPtr conn, unsigned char **cpumap, unsigned int *online, unsigned int flags); The function will return the number of CPUs present on the host or -1 on failure; If cpumap is non-NULL virNodeGetCPUMapFlags will allocate an array containing a bit map representation of the online CPUs. It's the callers responsibility to deallocate cpumap using free(). If online is non-NULL, the variable pointed to will contain the number of online host node CPUs. The variable flags has been added to support future extensions and must be set to 0. Note: the name virNodeGetCPUMapFlags has been chosen to avoid confusion with the nodeinfo function nodeGetCPUmap. Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 8 ++++++++ python/generator.py | 1 + src/libvirt_public.syms | 5 +++++ 3 files changed, 14 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index a4e8ca9..6b72159 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -4500,6 +4500,14 @@ int virNodeSetMemoryParameters(virConnectPtr conn, int nparams, unsigned int flags); +/* + * node CPU map + */ +int virNodeGetCPUMapFlags(virConnectPtr conn, + unsigned char **cpumap, + unsigned int *online, + unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/python/generator.py b/python/generator.py index ced7e41..8591b8d 100755 --- a/python/generator.py +++ b/python/generator.py @@ -429,6 +429,7 @@ skip_impl = ( 'virConnectRegisterCloseCallback', 'virNodeGetMemoryParameters', 'virNodeSetMemoryParameters', + 'virNodeGetCPUMapFlags', ) qemu_skip_impl = ( diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 2c924d5..0c8f4ff 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -569,4 +569,9 @@ LIBVIRT_0.10.2 { virStoragePoolListAllVolumes; } LIBVIRT_0.10.0; +LIBVIRT_1.0.0 { + global: + virNodeGetCPUMapFlags; +} LIBVIRT_0.10.2; + # .... define new API here using predicted next version number .... -- 1.7.0.4

Extend the driver structure by nodeGetCPUMapFlags entry in support of the new API virNodeGetCPUMapFlags. Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- src/driver.h | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/src/driver.h b/src/driver.h index bdcaa01..1af9568 100644 --- a/src/driver.h +++ b/src/driver.h @@ -898,6 +898,12 @@ typedef int int nparams, unsigned int flags); +typedef int + (*virDrvNodeGetCPUMapFlags)(virConnectPtr conn, + unsigned char **cpumap, + unsigned int *online, + unsigned int flags); + /** * _virDriver: * @@ -1087,6 +1093,7 @@ struct _virDriver { virDrvDomainGetMetadata domainGetMetadata; virDrvNodeGetMemoryParameters nodeGetMemoryParameters; virDrvNodeSetMemoryParameters nodeSetMemoryParameters; + virDrvNodeGetCPUMapFlags nodeGetCPUMapFlags; }; typedef int -- 1.7.0.4

Added implementation of virNodeGetCPUMapFlags to libvirt.c Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- src/libvirt.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 56 insertions(+), 0 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index 3c6d67d..25c37d3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -20098,3 +20098,59 @@ error: virDispatchError(domain->conn); return NULL; } + +/** + * virNodeGetCPUMapFlags: + * @conn: pointer to the hypervisor connection + * @cpumap: optional pointer to a bit map of real CPUs on the host node + * (in 8-bit bytes) (OUT) + * In case of success each bit set to 1 means that corresponding + * CPU is online. + * Bytes are stored in little-endian order: CPU0-7, 8-15... + * In each byte, lowest CPU number is least significant bit. + * The bit map is allocated by virNodeGetCPUMapFlags and needs + * to be released using free() by the caller. + * @online: optional number of online CPUs in cpumap (OUT) + * Contains the number of online CPUs if the call was successful. + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Get CPU map of host node CPUs. + * + * Returns number of CPUs present on the host node, + * or -1 if there was an error. + */ +int +virNodeGetCPUMapFlags (virConnectPtr conn, + unsigned char **cpumap, + unsigned int *online, + unsigned int flags) +{ + VIR_DEBUG("conn=%p, cpumap=%p, online=%p, flags=%x", + conn, cpumap, online, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECT (conn)) { + virLibConnError(VIR_ERR_INVALID_CONN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + if (conn->driver->nodeGetCPUMapFlags) { + int ret = conn->driver->nodeGetCPUMapFlags (conn, + cpumap, + online, + flags); + if (ret < 0) + goto error; + VIR_DEBUG("conn=%p, cpumap=%p, online=%u, flags=%x, ret=%d", + conn, cpumap, online ? *online : 0 , flags, ret); + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} -- 1.7.0.4

- Defined the wire protocol format for virNodeGetCPUMapFlags and its arguments - Implemented remote method invocation (remoteNodeGetCPUMapFlags) - Implemented method dispacher (remoteDispatchNodeGetCPUMapFlags) Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- daemon/remote.c | 44 +++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 49 ++++++++++++++++++++++++++++++++++++++++++ src/remote/remote_protocol.x | 13 ++++++++++- src/remote_protocol-structs | 12 ++++++++++ 4 files changed, 117 insertions(+), 1 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index e7fe128..36291d1 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -4544,6 +4544,50 @@ cleanup: return rv; } +static int +remoteDispatchNodeGetCPUMapFlags(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client ATTRIBUTE_UNUSED, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_node_get_cpu_map_flags_args *args, + remote_node_get_cpu_map_flags_ret *ret) +{ + unsigned char *cpumap; + unsigned int online; + unsigned int flags; + int cpunum; + int rv = -1; + struct daemonClientPrivate *priv = + virNetServerClientGetPrivateData(client); + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + flags = args->flags; + + cpunum = virNodeGetCPUMapFlags(priv->conn, &cpumap, &online, flags); + if (cpunum < 0) + goto cleanup; + + /* 'serialize' return cpumap */ + ret->cpumap.cpumap_len = VIR_CPU_MAPLEN(cpunum); + ret->cpumap.cpumap_val = (char *) cpumap; + cpumap = NULL; + + ret->online = online; + ret->ret = cpunum; + + rv = 0; + +cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + VIR_FREE(cpumap); + return rv; +} + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index fc4c696..7c89477 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -5749,6 +5749,54 @@ done: return rv; } +int +remoteNodeGetCPUMapFlags(virConnectPtr conn, + unsigned char **cpumap, + unsigned int *online, + unsigned int flags) +{ + int rv = -1; + remote_node_get_cpu_map_flags_args args; + remote_node_get_cpu_map_flags_ret ret; + struct private_data *priv = conn->privateData; + + remoteDriverLock(priv); + + /* IMPROVEME: send info about optional args */ + args.flags = flags; + + memset (&ret, 0, sizeof(ret)); + if (call (conn, priv, 0, REMOTE_PROC_NODE_GET_CPU_MAP_FLAGS, + (xdrproc_t) xdr_remote_node_get_cpu_map_flags_args, + (char *) &args, + (xdrproc_t) xdr_remote_node_get_cpu_map_flags_ret, + (char *) &ret) == -1) + goto done; + + if (ret.ret < 0) + goto cleanup; + + if (cpumap) { + if (VIR_ALLOC_N(*cpumap, ret.cpumap.cpumap_len) < 0) { + virReportOOMError(); + goto cleanup; + } + memcpy(*cpumap, ret.cpumap.cpumap_val, ret.cpumap.cpumap_len); + } + + if (online) + *online = ret.online; + + rv = ret.ret; + +cleanup: + xdr_free ((xdrproc_t) xdr_remote_node_get_cpu_map_flags_ret, + (char *) &ret); +done: + remoteDriverUnlock(priv); + return rv; +} + static void remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) { @@ -6063,6 +6111,7 @@ static virDriver remote_driver = { .domainGetHostname = remoteDomainGetHostname, /* 0.10.0 */ .nodeSetMemoryParameters = remoteNodeSetMemoryParameters, /* 0.10.2 */ .nodeGetMemoryParameters = remoteNodeGetMemoryParameters, /* 0.10.2 */ + .nodeGetCPUMapFlags = remoteNodeGetCPUMapFlags, /* 1.0.0 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index b0b530c..bc5e70f 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2666,6 +2666,16 @@ struct remote_node_get_memory_parameters_ret { int nparams; }; +struct remote_node_get_cpu_map_flags_args { + unsigned int flags; +}; + +struct remote_node_get_cpu_map_flags_ret { + opaque cpumap<REMOTE_CPUMAP_MAX>; + unsigned int online; + int ret; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -3008,7 +3018,8 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 289, /* skipgen skipgen */ REMOTE_PROC_DOMAIN_BLOCK_COMMIT = 290, /* autogen autogen */ - REMOTE_PROC_NETWORK_UPDATE = 291 /* autogen autogen priority:high */ + REMOTE_PROC_NETWORK_UPDATE = 291, /* autogen autogen priority:high */ + REMOTE_PROC_NODE_GET_CPU_MAP_FLAGS = 292 /* skipgen skipgen */ /* * Notice how the entries are grouped in sets of 10 ? diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index 4d2627a..8f1e678 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -2123,6 +2123,17 @@ struct remote_node_get_memory_parameters_ret { } params; int nparams; }; +struct remote_node_get_cpu_map_flags_args { + u_int flags; +}; +struct remote_node_get_cpu_map_flags_ret { + struct { + u_int cpumap_len; + char * cpumap_val; + } cpumap; + u_int online; + int ret; +}; enum remote_procedure { REMOTE_PROC_OPEN = 1, REMOTE_PROC_CLOSE = 2, @@ -2415,4 +2426,5 @@ enum remote_procedure { REMOTE_PROC_NODE_GET_MEMORY_PARAMETERS = 289, REMOTE_PROC_DOMAIN_BLOCK_COMMIT = 290, REMOTE_PROC_NETWORK_UPDATE = 291, + REMOTE_PROC_NODE_GET_CPU_MAP_FLAGS = 292, }; -- 1.7.0.4

New macro VIR_CPU_USED added to facilitate the interpretation of cpu maps. Further, hardened the other cpumap macros against invocations like VIR_CPU_USE(cpumap + 1, cpu) Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 20 ++++++++++++++++---- 1 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 6b72159..3e8e4f8 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1954,7 +1954,7 @@ int virDomainGetEmulatorPinInfo (virDomainPtr domain, * USE_CPU macro set the bit (CPU usable) of the related cpu in cpumap. */ -#define VIR_USE_CPU(cpumap,cpu) (cpumap[(cpu)/8] |= (1<<((cpu)%8))) +#define VIR_USE_CPU(cpumap,cpu) ((cpumap)[(cpu)/8] |= (1<<((cpu)%8))) /** * VIR_UNUSE_CPU: @@ -1965,7 +1965,19 @@ int virDomainGetEmulatorPinInfo (virDomainPtr domain, * USE_CPU macro reset the bit (CPU not usable) of the related cpu in cpumap. */ -#define VIR_UNUSE_CPU(cpumap,cpu) (cpumap[(cpu)/8] &= ~(1<<((cpu)%8))) +#define VIR_UNUSE_CPU(cpumap,cpu) ((cpumap)[(cpu)/8] &= ~(1<<((cpu)%8))) + +/** + * VIR_CPU_USED: + * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN) + * @cpu: the physical CPU number + * + * This macro can be used in conjunction with virNodeGetCPUMapFlags() API. + * VIR_CPU_USED returns true if the bit of the related CPU is set. + * + */ + +#define VIR_CPU_USED(cpumap,cpu) ((cpumap)[(cpu)/8] & (1<<((cpu)%8))) /** * VIR_CPU_MAPLEN: @@ -1976,7 +1988,7 @@ int virDomainGetEmulatorPinInfo (virDomainPtr domain, * CPU map between a single virtual & all physical CPUs of a domain. */ -#define VIR_CPU_MAPLEN(cpu) (((cpu)+7)/8) +#define VIR_CPU_MAPLEN(cpu) (((cpu)+7)/8) int virDomainGetVcpus (virDomainPtr domain, @@ -1998,7 +2010,7 @@ int virDomainGetVcpus (virDomainPtr domain, */ #define VIR_CPU_USABLE(cpumaps,maplen,vcpu,cpu) \ - (cpumaps[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8))) + ((cpumaps)[((vcpu)*(maplen))+((cpu)/8)] & (1<<((cpu)%8))) /** * VIR_COPY_CPUMAP: -- 1.7.0.4

- Added a new host command nodecpumap - Added documentation Example: $ virsh nodecpumap CPUs present: 8 CPUs online: 3 CPU map: 10101000 Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- tools/virsh-host.c | 41 +++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 5 +++++ 2 files changed, 46 insertions(+), 0 deletions(-) diff --git a/tools/virsh-host.c b/tools/virsh-host.c index 5cf192d..e4f9327 100644 --- a/tools/virsh-host.c +++ b/tools/virsh-host.c @@ -271,6 +271,46 @@ cmdNodeinfo(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) } /* + * "nodecpumap" command + */ +static const vshCmdInfo info_node_cpumap[] = { + {"help", N_("node cpu map")}, + {"desc", N_("Displays the node's total number of CPUs, the number of" + " online CPUs and the list of online CPUs.")}, + {NULL, NULL} +}; + +static bool +cmdNodeCpuMap(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + int cpu, cpunum; + unsigned char *cpumap = NULL; + unsigned int online; + bool ret = false; + + cpunum = virNodeGetCPUMapFlags(ctl->conn, &cpumap, &online, 0); + if (cpunum < 0) { + vshError(ctl, "%s", _("Unable to get cpu map")); + goto cleanup; + } + + vshPrint(ctl, "%-15s %d\n", _("CPUs present:"), cpunum); + vshPrint(ctl, "%-15s %d\n", _("CPUs online:"), online); + + vshPrint(ctl, "%-15s ", _("CPU map:")); + for (cpu = 0; cpu < cpunum; cpu++) { + vshPrint(ctl, "%d", VIR_CPU_USED(cpumap, cpu) ? 1 : 0); + } + vshPrint(ctl, "\n"); + + ret = true; + + cleanup: + VIR_FREE(cpumap); + return ret; +} + +/* * "nodecpustats" command */ static const vshCmdInfo info_nodecpustats[] = { @@ -1026,6 +1066,7 @@ const vshCmdDef hostAndHypervisorCmds[] = { {"hostname", cmdHostname, NULL, info_hostname, 0}, {"node-memory-tune", cmdNodeMemoryTune, opts_node_memory_tune, info_node_memory_tune, 0}, + {"nodecpumap", cmdNodeCpuMap, NULL, info_node_cpumap, 0}, {"nodecpustats", cmdNodeCpuStats, opts_node_cpustats, info_nodecpustats, 0}, {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo, 0}, {"nodememstats", cmdNodeMemStats, opts_node_memstats, info_nodememstats, 0}, diff --git a/tools/virsh.pod b/tools/virsh.pod index 2d90b7b..9a2c0e1 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -277,6 +277,11 @@ and size of the physical memory. The output corresponds to virNodeInfo structure. Specifically, the "CPU socket(s)" field means number of CPU sockets per NUMA cell. +=item B<nodecpumap> + +Displays the node's total number of CPUs, the number of online CPUs +and the list of online CPUs. + =item B<nodecpustats> [I<cpu>] [I<--percent>] Returns cpu stats of the node. -- 1.7.0.4

Added an implemention of virNodeGetCPUMapFlags to nodeinfo.c, (nodeGetCPUMapFlags) which can be used by all drivers for a Linux hypervisor host. Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- src/libvirt_private.syms | 1 + src/nodeinfo.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ src/nodeinfo.h | 6 +++++ 3 files changed, 56 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index fe31bbe..44d5927 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -900,6 +900,7 @@ virNodeDeviceObjUnlock; # nodeinfo.h nodeCapsInitNUMA; nodeGetCPUmap; +nodeGetCPUMapFlags; nodeGetCPUStats; nodeGetCellsFreeMemory; nodeGetFreeMemory; diff --git a/src/nodeinfo.c b/src/nodeinfo.c index c0e60d8..84cf796 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -1203,6 +1203,55 @@ nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, #endif } +int nodeGetCPUMapFlags(virConnectPtr conn, + unsigned char **cpumap, + unsigned int *online, + unsigned int flags) +{ + virBitmapPtr cpusPresent = NULL; + virBitmapPtr cpusOnline = NULL; + int maxpresent, maxonline, i; + int ret = -1; + + virCheckFlags(0, 1); + + if (!(cpusPresent = nodeGetCPUmap(conn, &maxpresent, "present"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to retrieve 'present' CPU map")); + goto cleanup; + } + + if (!(cpusOnline = nodeGetCPUmap(conn, &maxonline, "online"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to retrieve 'online' CPU map")); + goto cleanup; + } + + if (cpumap && VIR_ALLOC_N(*cpumap, VIR_CPU_MAPLEN(maxpresent)) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (online) + *online = 0; + + i = -1; + while ((i=virBitmapNextSetBit(cpusOnline, i)) >= 0) { + if (online) + (*online)++; + + if (cpumap) + VIR_USE_CPU(*cpumap,i); + } + + ret = maxpresent + 1; + +cleanup: + virBitmapFree(cpusPresent); + virBitmapFree(cpusOnline); + return ret; +} + #if HAVE_NUMACTL # if LIBNUMA_API_VERSION <= 1 # define NUMA_MAX_N_CPUS 4096 diff --git a/src/nodeinfo.h b/src/nodeinfo.h index 2eda846..e210e6b 100644 --- a/src/nodeinfo.h +++ b/src/nodeinfo.h @@ -59,4 +59,10 @@ int nodeSetMemoryParameters(virConnectPtr conn, virTypedParameterPtr params, int nparams, unsigned int flags); + +int nodeGetCPUMapFlags(virConnectPtr conn, + unsigned char **cpumap, + unsigned int *online, + unsigned int flags); + #endif /* __VIR_NODEINFO_H__*/ -- 1.7.0.4

Driver support added for: - test, pretending 8 host CPUS, 3 being online - qemu, using nodeGetCPUMapFlags Signed-off-by: Viktor Mihajlovski <mihajlov@linux.vnet.ibm.com> --- src/qemu/qemu_driver.c | 1 + src/test/test_driver.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 0 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0787039..2c6364b 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13928,6 +13928,7 @@ static virDriver qemuDriver = { .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */ .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */ .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */ + .nodeGetCPUMapFlags = nodeGetCPUMapFlags, /* 1.0.0 */ }; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index c9f9115..24f3b11 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -5687,6 +5687,35 @@ static int testListAllDomains(virConnectPtr conn, return ret; } +static int testNodeGetCPUMapFlags(virConnectPtr conn, + unsigned char **cpumap, + unsigned int *online, + unsigned int flags) +{ + testConnPtr privconn = conn->privateData; + int ret = -1; + + virCheckFlags(0, -1); + + testDriverLock(privconn); + if (cpumap) { + if (VIR_ALLOC_N(*cpumap, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + *cpumap[0] = 0x15; + } + + if (online) + *online = 3; + + ret = 8; + +cleanup: + testDriverUnlock(privconn); + return ret; +} + static virDriver testDriver = { .no = VIR_DRV_TEST, @@ -5756,6 +5785,7 @@ static virDriver testDriver = { .domainEventRegisterAny = testDomainEventRegisterAny, /* 0.8.0 */ .domainEventDeregisterAny = testDomainEventDeregisterAny, /* 0.8.0 */ .isAlive = testIsAlive, /* 0.9.8 */ + .nodeGetCPUMapFlags = testNodeGetCPUMapFlags, /* 1.0.0 */ }; static virNetworkDriver testNetworkDriver = { -- 1.7.0.4
participants (1)
-
Viktor Mihajlovski