[libvirt] [PATCH 0/4] Introduce display of IOThreads Information

These patches satisfy part of: https://bugzilla.redhat.com/show_bug.cgi?id=1135491 Patches 1 and 2 are fairly straightforward adding a new API type patches although they were implemented with the thought of how patch 3 works. Also rather than implement a get iothreads and a get iothreadspin API, I combined the two into one. I could separate if that's more desirable, but it just seemed more natural to have one API do both. Patch 3 adds the qemu related to code to fetch not only the IOThreads data, but also the cpumap/cpumaplen in order to display the CPU Affinity. For that I somewhat followed how the vcpuinfo code works, but also a bit on how the nodecpumap code does things. Unlike the vcpuinfo code, I had no way to count the IOThreads before calling, so rather than pass in a cpumap/cpumaplen - I allocated them in the qemu code and passed them back within the IOThreadsInfo structure. Of course it did get me to thinking why are we doing 1 for each IOThread, but to that degree I was following the vcpu model. Patch 4 is the new 'virsh iothreads' command with no arguments (for now). It will display the IOThreads of active domains only. "Future" patches will implement a SetIOThreads API to change the thread pinning and allow for add/delete of IOThreads. I'm hoping to use the same command with new options --pin && --cpuset for pinning the IOThreads or --add/--del to add/remove IOThreads, but I wanted to make sure I had buyin on the use of one API to accomplish both get of basic IOThread data and CPU Affinity data. John Ferlan (4): Implement public API for virDomainGetIOThreadsInfo remote: Implement the remote plumbing for virDomainGetIOThreads qemu: Implement the qemu driver fetch for IOThreads virsh: Add 'iothreads' command daemon/remote.c | 75 +++++++++++++++++++++++++- include/libvirt/libvirt-domain.h | 22 +++++++- src/driver-hypervisor.h | 8 ++- src/libvirt-domain.c | 63 +++++++++++++++++++++- src/libvirt_public.syms | 6 +++ src/qemu/qemu_driver.c | 114 +++++++++++++++++++++++++++++++++++++++ src/remote/remote_driver.c | 82 +++++++++++++++++++++++++++- src/remote/remote_protocol.x | 29 +++++++++- src/remote_protocol-structs | 20 +++++++ src/rpc/gendispatch.pl | 1 + tools/virsh-domain.c | 72 +++++++++++++++++++++++++ tools/virsh.pod | 7 +++ 12 files changed, 492 insertions(+), 7 deletions(-) -- 2.1.0

Add virDomainGetIOThreadsInfo in order to returned a list of virDomainIOThreadsInfoPtr structures which list the IOThread ID, the thread_id, and the CPU Affinity map for each IOThread for the active domain. Also added virDomainIOThreadsInfoFree in order to free the cpumap and the array entry structure. For inactive domains or where IOThreads is not supported return an error and an empty structure Signed-off-by: John Ferlan <jferlan@redhat.com> --- include/libvirt/libvirt-domain.h | 22 +++++++++++++- src/driver-hypervisor.h | 8 ++++- src/libvirt-domain.c | 63 +++++++++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 6 ++++ 4 files changed, 96 insertions(+), 3 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 4dbd7f5..54f8de4 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4,7 +4,7 @@ * Description: Provides APIs for the management of domains * Author: Daniel Veillard <veillard@redhat.com> * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1568,6 +1568,26 @@ int virDomainGetEmulatorPinInfo (virDomainPtr domain, unsigned int flags); /** + * virIOThreadsInfo: + * + * The data structure for information about IOThreads in a domain + */ +typedef struct _virDomainIOThreadsInfo virDomainIOThreadsInfo; +typedef virDomainIOThreadsInfo *virDomainIOThreadsInfoPtr; +struct _virDomainIOThreadsInfo { + unsigned int iothread_id; /* IOThread ID */ + unsigned int thread_id; /* Thread ID associated with IOThread */ + unsigned char *cpumap; /* CPU map for thread */ + int cpumaplen; /* cpumap size */ +}; + +void virDomainIOThreadsInfoFree(virDomainIOThreadsInfoPtr info); + +int virDomainGetIOThreadsInfo(virDomainPtr domain, + virDomainIOThreadsInfoPtr **info, + unsigned int flags); + +/** * VIR_USE_CPU: * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN/OUT) * @cpu: the physical CPU number diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h index a1198ad..2ce1a51 100644 --- a/src/driver-hypervisor.h +++ b/src/driver-hypervisor.h @@ -1,7 +1,7 @@ /* * driver-hypervisor.h: entry points for hypervisor drivers * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -381,6 +381,11 @@ typedef int (*virDrvDomainGetMaxVcpus)(virDomainPtr domain); typedef int +(*virDrvDomainGetIOThreadsInfo)(virDomainPtr domain, + virDomainIOThreadsInfoPtr **info, + unsigned int flags); + +typedef int (*virDrvDomainGetSecurityLabel)(virDomainPtr domain, virSecurityLabelPtr seclabel); @@ -1254,6 +1259,7 @@ struct _virHypervisorDriver { virDrvDomainGetEmulatorPinInfo domainGetEmulatorPinInfo; virDrvDomainGetVcpus domainGetVcpus; virDrvDomainGetMaxVcpus domainGetMaxVcpus; + virDrvDomainGetIOThreadsInfo domainGetIOThreadsInfo; virDrvDomainGetSecurityLabel domainGetSecurityLabel; virDrvDomainGetSecurityLabelList domainGetSecurityLabelList; virDrvNodeGetSecurityModel nodeGetSecurityModel; diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c index 492e90a..6834d38 100644 --- a/src/libvirt-domain.c +++ b/src/libvirt-domain.c @@ -1,7 +1,7 @@ /* * libvirt-domain.c: entry points for virDomainPtr APIs * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7891,6 +7891,67 @@ virDomainGetMaxVcpus(virDomainPtr domain) /** + * virDomainGetIOThreadsInfo: + * @dom: a domain object + * @info: pointer to an array of virDomainIOThreadsInfo structures (OUT) + * @flags: extra flags; not used yet, so callers should always pass 0 + * + * Fetch IOThreads of an active domain including the cpumap information to + * determine on which CPU the IOThread has affinity to run. + * + * Returns the number of IOThreads or -1 in case of error. + * On success, the array of information is stored into @info. The caller is + * responsible for calling virDomainIOThreadsInfoFree() on each array element, + * then calling free() on @info. On error, @info is set to NULL. + */ +int +virDomainGetIOThreadsInfo(virDomainPtr dom, + virDomainIOThreadsInfoPtr **info, + unsigned int flags) +{ + VIR_DOMAIN_DEBUG(dom, "info=%p flags=%x", info, flags); + + virResetLastError(); + + virCheckDomainReturn(dom, -1); + virCheckReadOnlyGoto(dom->conn->flags, error); + virCheckNonNullArgGoto(info, error); + *info = NULL; + + if (dom->conn->driver->domainGetIOThreadsInfo) { + int ret; + ret = dom->conn->driver->domainGetIOThreadsInfo(dom, info, flags); + if (ret < 0) + goto error; + return ret; + } + + virReportUnsupportedError(); + + error: + virDispatchError(dom->conn); + return -1; +} + + +/** + * virDomainIOThreadsInfoFree: + * @info: pointer to a virDomainIOThreadsInfo object + * + * Frees the memory used by @info. + */ +void +virDomainIOThreadsInfoFree(virDomainIOThreadsInfoPtr info) +{ + if (!info) + return; + + VIR_FREE(info->cpumap); + VIR_FREE(info); +} + + +/** * virDomainGetSecurityLabel: * @domain: a domain object * @seclabel: pointer to a virSecurityLabel structure diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 4ea5cff..d3ddd24 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -695,4 +695,10 @@ LIBVIRT_1.2.12 { virDomainDefineXMLFlags; } LIBVIRT_1.2.11; +LIBVIRT_1.2.13 { + global: + virDomainIOThreadsInfoFree; + virDomainGetIOThreadsInfo; +} LIBVIRT_1.2.12; + # .... define new API here using predicted next version number .... -- 2.1.0

On Thu, Feb 12, 2015 at 08:03:44AM -0500, John Ferlan wrote:
Add virDomainGetIOThreadsInfo in order to returned a list of virDomainIOThreadsInfoPtr structures which list the IOThread ID, the thread_id, and the CPU Affinity map for each IOThread for the active domain.
Also added virDomainIOThreadsInfoFree in order to free the cpumap and the array entry structure.
For inactive domains or where IOThreads is not supported return an error and an empty structure
Signed-off-by: John Ferlan <jferlan@redhat.com> --- include/libvirt/libvirt-domain.h | 22 +++++++++++++- src/driver-hypervisor.h | 8 ++++- src/libvirt-domain.c | 63 +++++++++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 6 ++++ 4 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 4dbd7f5..54f8de4 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4,7 +4,7 @@ * Description: Provides APIs for the management of domains * Author: Daniel Veillard <veillard@redhat.com> * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1568,6 +1568,26 @@ int virDomainGetEmulatorPinInfo (virDomainPtr domain, unsigned int flags);
/** + * virIOThreadsInfo: + * + * The data structure for information about IOThreads in a domain + */ +typedef struct _virDomainIOThreadsInfo virDomainIOThreadsInfo; +typedef virDomainIOThreadsInfo *virDomainIOThreadsInfoPtr; +struct _virDomainIOThreadsInfo { + unsigned int iothread_id; /* IOThread ID */ + unsigned int thread_id; /* Thread ID associated with IOThread */
Hmm, one thing we've avoided doing in the past is to expose the idea of PIDs in any of the libvirt APIs - we never expose the QEMU PID anywhere. So I think I'd leave this thread_id field out of the info here, the iothread_id should be sufficient for apps. The actual thread_is should only be needed internally by libvirt itself, in order to do pinning & so forth - we don't want to have apps using it todo pinning themslves.
+ unsigned char *cpumap; /* CPU map for thread */ + int cpumaplen; /* cpumap size */ +}; + +void virDomainIOThreadsInfoFree(virDomainIOThreadsInfoPtr info); + +int virDomainGetIOThreadsInfo(virDomainPtr domain, + virDomainIOThreadsInfoPtr **info, + unsigned int flags);
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 02/12/2015 08:12 AM, Daniel P. Berrange wrote:
On Thu, Feb 12, 2015 at 08:03:44AM -0500, John Ferlan wrote:
Add virDomainGetIOThreadsInfo in order to returned a list of virDomainIOThreadsInfoPtr structures which list the IOThread ID, the thread_id, and the CPU Affinity map for each IOThread for the active domain.
Also added virDomainIOThreadsInfoFree in order to free the cpumap and the array entry structure.
For inactive domains or where IOThreads is not supported return an error and an empty structure
Signed-off-by: John Ferlan <jferlan@redhat.com> --- include/libvirt/libvirt-domain.h | 22 +++++++++++++- src/driver-hypervisor.h | 8 ++++- src/libvirt-domain.c | 63 +++++++++++++++++++++++++++++++++++++++- src/libvirt_public.syms | 6 ++++ 4 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index 4dbd7f5..54f8de4 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -4,7 +4,7 @@ * Description: Provides APIs for the management of domains * Author: Daniel Veillard <veillard@redhat.com> * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1568,6 +1568,26 @@ int virDomainGetEmulatorPinInfo (virDomainPtr domain, unsigned int flags);
/** + * virIOThreadsInfo: + * + * The data structure for information about IOThreads in a domain + */ +typedef struct _virDomainIOThreadsInfo virDomainIOThreadsInfo; +typedef virDomainIOThreadsInfo *virDomainIOThreadsInfoPtr; +struct _virDomainIOThreadsInfo { + unsigned int iothread_id; /* IOThread ID */ + unsigned int thread_id; /* Thread ID associated with IOThread */
Hmm, one thing we've avoided doing in the past is to expose the idea of PIDs in any of the libvirt APIs - we never expose the QEMU PID anywhere. So I think I'd leave this thread_id field out of the info here, the iothread_id should be sufficient for apps. The actual thread_is should only be needed internally by libvirt itself, in order to do pinning & so forth - we don't want to have apps using it todo pinning themslves.
OK no problem - that's "folklore" I wasn't aware of... Easy enough to remove. John

Implement the remote plumbing for virDomainGetIOThreads Signed-off-by: John Ferlan <jferlan@redhat.com> --- daemon/remote.c | 75 +++++++++++++++++++++++++++++++++++++++- src/remote/remote_driver.c | 82 +++++++++++++++++++++++++++++++++++++++++++- src/remote/remote_protocol.x | 29 ++++++++++++++-- src/remote_protocol-structs | 20 +++++++++++ src/rpc/gendispatch.pl | 1 + 5 files changed, 203 insertions(+), 4 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index d657a09..b3c4cc3 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -1,7 +1,7 @@ /* * remote.c: handlers for RPC method calls * - * Copyright (C) 2007-2014 Red Hat, Inc. + * Copyright (C) 2007-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -2269,6 +2269,79 @@ remoteDispatchDomainGetVcpus(virNetServerPtr server ATTRIBUTE_UNUSED, } static int +remoteDispatchDomainGetIOThreadsInfo(virNetServerPtr server ATTRIBUTE_UNUSED, + virNetServerClientPtr client, + virNetMessagePtr msg ATTRIBUTE_UNUSED, + virNetMessageErrorPtr rerr, + remote_domain_get_iothreads_info_args *args, + remote_domain_get_iothreads_info_ret *ret) +{ + int rv = -1; + size_t i; + struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); + virDomainIOThreadsInfoPtr *info = NULL; + virDomainPtr dom = NULL; + remote_domain_iothreads_info *dst; + int ninfo = 0; + + if (!priv->conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open")); + goto cleanup; + } + + if (!(dom = get_nonnull_domain(priv->conn, args->dom))) + goto cleanup; + + if ((ninfo = virDomainGetIOThreadsInfo(dom, &info, args->flags)) < 0) + goto cleanup; + + if (ninfo > REMOTE_IOTHREADS_INFO_MAX) { + virReportError(VIR_ERR_RPC, + _("Too many IOThreads in info: %d for limit %d"), + ninfo, REMOTE_IOTHREADS_INFO_MAX); + goto cleanup; + } + + if (ninfo) { + if (VIR_ALLOC_N(ret->info.info_val, ninfo) < 0) + goto cleanup; + + ret->info.info_len = ninfo; + + for (i = 0; i < ninfo; i++) { + dst = &ret->info.info_val[i]; + dst->iothread_id = info[i]->iothread_id; + dst->thread_id = info[i]->thread_id; + + /* No need to allocate/copy the cpumap if we make the reasonable + * assumption that unsigned char and char are the same size. + */ + dst->cpumap.cpumap_len = info[i]->cpumaplen; + dst->cpumap.cpumap_val = (char *)info[i]->cpumap; + info[i]->cpumap = NULL; + } + } else { + ret->info.info_len = 0; + ret->info.info_val = NULL; + } + + ret->ret = ninfo; + + rv = 0; + + cleanup: + if (rv < 0) + virNetMessageSaveError(rerr); + virObjectUnref(dom); + if (ninfo >= 0) + for (i = 0; i < ninfo; i++) + virDomainIOThreadsInfoFree(info[i]); + VIR_FREE(info); + + return rv; +} + +static int remoteDispatchDomainMigratePrepare(virNetServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client ATTRIBUTE_UNUSED, virNetMessagePtr msg ATTRIBUTE_UNUSED, diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index d4fd658..2587870 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -2,7 +2,7 @@ * remote_driver.c: driver to provide access to libvirtd running * on a remote machine * - * Copyright (C) 2007-2014 Red Hat, Inc. + * Copyright (C) 2007-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -2316,6 +2316,85 @@ remoteDomainGetVcpus(virDomainPtr domain, } static int +remoteDomainGetIOThreadsInfo(virDomainPtr dom, + virDomainIOThreadsInfoPtr **info, + unsigned int flags) +{ + int rv = -1; + size_t i; + struct private_data *priv = dom->conn->privateData; + remote_domain_get_iothreads_info_args args; + remote_domain_get_iothreads_info_ret ret; + remote_domain_iothreads_info *src; + virDomainIOThreadsInfoPtr *info_ret = NULL; + + remoteDriverLock(priv); + + make_nonnull_domain(&args.dom, dom); + + args.flags = flags; + + memset(&ret, 0, sizeof(ret)); + + if (call(dom->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_IOTHREADS_INFO, + (xdrproc_t)xdr_remote_domain_get_iothreads_info_args, + (char *)&args, + (xdrproc_t)xdr_remote_domain_get_iothreads_info_ret, + (char *)&ret) == -1) + goto done; + + if (ret.info.info_len > REMOTE_IOTHREADS_INFO_MAX) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Too many IOThreads in info: %d for limit %d"), + ret.info.info_len, REMOTE_IOTHREADS_INFO_MAX); + goto cleanup; + } + + if (info) { + if (!ret.info.info_len) { + *info = NULL; + rv = ret.ret; + goto cleanup; + } + + if (VIR_ALLOC_N(info_ret, ret.info.info_len) < 0) + goto cleanup; + + for (i = 0; i < ret.info.info_len; i++) { + src = &ret.info.info_val[i]; + + if (VIR_ALLOC(info_ret[i]) < 0) + goto cleanup; + + info_ret[i]->iothread_id = src->iothread_id; + info_ret[i]->thread_id = src->thread_id; + if (VIR_ALLOC_N(info_ret[i]->cpumap, src->cpumap.cpumap_len) < 0) + goto cleanup; + memcpy(info_ret[i]->cpumap, src->cpumap.cpumap_val, + src->cpumap.cpumap_len); + info_ret[i]->cpumaplen = src->cpumap.cpumap_len; + } + *info = info_ret; + info_ret = NULL; + } + + rv = ret.ret; + + cleanup: + if (info_ret) { + for (i = 0; i < ret.info.info_len; i++) + virDomainIOThreadsInfoFree(info_ret[i]); + VIR_FREE(info_ret); + } + xdr_free((xdrproc_t)xdr_remote_domain_get_iothreads_info_ret, + (char *) &ret); + + done: + remoteDriverUnlock(priv); + return rv; +} + +static int remoteDomainGetSecurityLabel(virDomainPtr domain, virSecurityLabelPtr seclabel) { remote_domain_get_security_label_args args; @@ -8027,6 +8106,7 @@ static virHypervisorDriver hypervisor_driver = { .domainGetEmulatorPinInfo = remoteDomainGetEmulatorPinInfo, /* 0.10.0 */ .domainGetVcpus = remoteDomainGetVcpus, /* 0.3.0 */ .domainGetMaxVcpus = remoteDomainGetMaxVcpus, /* 0.3.0 */ + .domainGetIOThreadsInfo = remoteDomainGetIOThreadsInfo, /* 1.2.13 */ .domainGetSecurityLabel = remoteDomainGetSecurityLabel, /* 0.6.1 */ .domainGetSecurityLabelList = remoteDomainGetSecurityLabelList, /* 0.10.0 */ .nodeGetSecurityModel = remoteNodeGetSecurityModel, /* 0.6.1 */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index c8162a5..c4a7e7a 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -3,7 +3,7 @@ * remote_internal driver and libvirtd. This protocol is * internal and may change at any time. * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -85,6 +85,9 @@ const REMOTE_VCPUINFO_MAX = 16384; /* Upper limit on cpumaps (bytes) passed to virDomainGetVcpus. */ const REMOTE_CPUMAPS_MAX = 8388608; +/* Upper limit on number of info fields returned by virDomainGetIOThreads. */ +const REMOTE_IOTHREADS_INFO_MAX = 16384; + /* Upper limit on migrate cookie. */ const REMOTE_MIGRATE_COOKIE_MAX = 4194304; @@ -1181,6 +1184,22 @@ struct remote_domain_get_max_vcpus_ret { int num; }; +struct remote_domain_iothreads_info { + unsigned int iothread_id; + unsigned int thread_id; + opaque cpumap<REMOTE_CPUMAP_MAX>; +}; + +struct remote_domain_get_iothreads_info_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + +struct remote_domain_get_iothreads_info_ret { + remote_domain_iothreads_info info<REMOTE_IOTHREADS_INFO_MAX>; + unsigned int ret; +}; + struct remote_domain_get_security_label_args { remote_nonnull_domain dom; }; @@ -5569,5 +5588,11 @@ enum remote_procedure { * @acl: domain:write * @acl: domain:save */ - REMOTE_PROC_DOMAIN_DEFINE_XML_FLAGS = 350 + REMOTE_PROC_DOMAIN_DEFINE_XML_FLAGS = 350, + + /** + * @generate: none + * @acl: domain:read + */ + REMOTE_PROC_DOMAIN_GET_IOTHREADS_INFO = 351 }; diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs index df6eaf3..01eef90 100644 --- a/src/remote_protocol-structs +++ b/src/remote_protocol-structs @@ -807,6 +807,25 @@ struct remote_domain_get_max_vcpus_args { struct remote_domain_get_max_vcpus_ret { int num; }; +struct remote_domain_iothreads_info { + u_int iothread_id; + u_int thread_id; + struct { + u_int cpumap_len; + char * cpumap_val; + } cpumap; +}; +struct remote_domain_get_iothreads_info_args { + remote_nonnull_domain dom; + u_int flags; +}; +struct remote_domain_get_iothreads_info_ret { + struct { + u_int info_len; + remote_domain_iothreads_info * info_val; + } info; + u_int ret; +}; struct remote_domain_get_security_label_args { remote_nonnull_domain dom; }; @@ -2963,4 +2982,5 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_EVENT_CALLBACK_AGENT_LIFECYCLE = 348, REMOTE_PROC_DOMAIN_GET_FSINFO = 349, REMOTE_PROC_DOMAIN_DEFINE_XML_FLAGS = 350, + REMOTE_PROC_DOMAIN_GET_IOTHREADS_INFO = 351, }; diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl index 0dc167a..78cb415 100755 --- a/src/rpc/gendispatch.pl +++ b/src/rpc/gendispatch.pl @@ -67,6 +67,7 @@ sub fixup_name { $name =~ s/Fsfreeze$/FSFreeze/; $name =~ s/Fsthaw$/FSThaw/; $name =~ s/Fsinfo$/FSInfo/; + $name =~ s/Iothreads$/IOThreads/; $name =~ s/Scsi/SCSI/; $name =~ s/Wwn$/WWN/; $name =~ s/Dhcp$/DHCP/; -- 2.1.0

Make necessary checks for active domain and IOThread capability before calling the monitor to fetch IOThread data for a domain. If there are threads, then also return the processor affinity maps - this is similar to existing GetVcpuPin, GetVcpuInfo, and GetEmulatorPin fetches of the processor affinity. Having a separate GetIOThreadsPin seemed to be waste if it could be done in one API. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 709f468..ea61015 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -5541,6 +5541,119 @@ qemuDomainGetMaxVcpus(virDomainPtr dom) VIR_DOMAIN_VCPU_MAXIMUM)); } +static int +qemuDomainGetIOThreadsInfo(virDomainPtr dom, + virDomainIOThreadsInfoPtr **info, + unsigned int flags) +{ + virQEMUDriverPtr driver = dom->conn->privateData; + virDomainObjPtr vm; + qemuDomainObjPrivatePtr priv; + qemuMonitorIOThreadsInfoPtr *iothreads = NULL; + virDomainIOThreadsInfoPtr *info_ret = NULL; + int niothreads = 0; + int maxcpu, hostcpus, maplen; + int ret = -1; + size_t i; + + virCheckFlags(0, -1); + + if (!(vm = qemuDomObjFromDomain(dom))) + goto cleanup; + + if (virDomainGetIOThreadsInfoEnsureACL(dom->conn, vm->def) < 0) + goto cleanup; + + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("cannot list IOThreads for an inactive domain")); + goto endjob; + } + + priv = vm->privateData; + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_IOTHREAD)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("IOThreads not supported with this binary")); + goto endjob; + } + + if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_NONE) < 0) + goto endjob; + niothreads = qemuMonitorGetIOThreads(priv->mon, &iothreads); + if (qemuDomainObjExitMonitor(driver, vm) < 0) + goto endjob; + if (niothreads < 0) + goto endjob; + + /* Nothing to do */ + if (niothreads == 0) { + ret = 0; + goto endjob; + } + + if ((hostcpus = nodeGetCPUCount()) < 0) + goto endjob; + + maplen = VIR_CPU_MAPLEN(hostcpus); + maxcpu = maplen * 8; + if (maxcpu > hostcpus) + maxcpu = hostcpus; + + if (VIR_ALLOC_N(info_ret, niothreads) < 0) + goto endjob; + + for (i = 0; i < niothreads; i++) { + virBitmapPtr map = NULL; + unsigned char *tmpmap = NULL; + int tmpmaplen = 0; + + if (VIR_ALLOC(info_ret[i]) < 0) + goto endjob; + + if (virStrToLong_ui(iothreads[i]->name + strlen("iothread"), NULL, 10, + &info_ret[i]->iothread_id) < 0) + goto endjob; + info_ret[i]->thread_id = iothreads[i]->thread_id; + + if (VIR_ALLOC_N(info_ret[i]->cpumap, maplen) < 0) + goto endjob; + + if (virProcessGetAffinity(iothreads[i]->thread_id, &map, maxcpu) < 0) + goto endjob; + + virBitmapToData(map, &tmpmap, &tmpmaplen); + if (tmpmaplen > maplen) + tmpmaplen = maplen; + memcpy(info_ret[i]->cpumap, tmpmap, tmpmaplen); + info_ret[i]->cpumaplen = tmpmaplen; + + VIR_FREE(tmpmap); + virBitmapFree(map); + } + + *info = info_ret; + info_ret = NULL; + ret = niothreads; + + endjob: + qemuDomainObjEndJob(driver, vm); + + cleanup: + qemuDomObjEndAPI(&vm); + + if (info_ret) { + for (i = 0; i < niothreads; i++) + virDomainIOThreadsInfoFree(info_ret[i]); + VIR_FREE(info_ret); + } + return ret; + +} + + static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel) { virQEMUDriverPtr driver = dom->conn->privateData; @@ -19141,6 +19254,7 @@ static virHypervisorDriver qemuHypervisorDriver = { .domainGetEmulatorPinInfo = qemuDomainGetEmulatorPinInfo, /* 0.10.0 */ .domainGetVcpus = qemuDomainGetVcpus, /* 0.4.4 */ .domainGetMaxVcpus = qemuDomainGetMaxVcpus, /* 0.4.4 */ + .domainGetIOThreadsInfo = qemuDomainGetIOThreadsInfo, /* 1.2.13 */ .domainGetSecurityLabel = qemuDomainGetSecurityLabel, /* 0.6.1 */ .domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */ .nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */ -- 2.1.0

Add the 'iothreads' command to display live IOThread Info data $ virsh iothreads $dom IOThread ID Thread ID CPU Affinity ------------------------------------------------------------ 1 31983 2 2 31984 3 3 31985 0-3 $ echo $? 0 For domains which don't have IOThreads the following is returned: $ virsh iothreads $dom error: No IOThreads found for the domain $ echo $? 0 For domains which are not running the following is returned: $ virsh iothreads $dom error: Unable to get domain IOThreads information error: Requested operation is not valid: cannot list IOThreads for an inactive domain $ echo $? 1 Signed-off-by: John Ferlan <jferlan@redhat.com> --- tools/virsh-domain.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 7 +++++ 2 files changed, 79 insertions(+) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 20bafbe..14cb3f8 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -6781,6 +6781,72 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd) } /* + * "iothreads" command + */ +static const vshCmdInfo info_iothreads[] = { + {.name = "help", + .data = N_("view domain IOThreads") + }, + {.name = "desc", + .data = N_("Returns basic information about the domain IOThreads.") + }, + {.name = NULL} +}; +static const vshCmdOptDef opts_iothreads[] = { + {.name = "domain", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("domain name, id or uuid") + }, + {.name = NULL} +}; + +static bool +cmdIOThreadsInfo(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int niothreads = 0; + virDomainIOThreadsInfoPtr *info; + size_t i; + int maxcpu; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if ((maxcpu = vshNodeGetCPUCount(ctl->conn)) < 0) + goto cleanup; + + if ((niothreads = virDomainGetIOThreadsInfo(dom, &info, 0)) < 0) { + vshError(ctl, _("Unable to get domain IOThreads information")); + goto cleanup; + } + + if (niothreads == 0) { + vshError(ctl, _("No IOThreads found for the domain")); + goto cleanup; + } + + vshPrintExtra(ctl, " %-15s %-15s %-15s\n", + _("IOThread ID"), _("Thread ID"), _("CPU Affinity")); + vshPrintExtra(ctl, "------------------------------------------------------------\n"); + for (i = 0; i < niothreads; i++) { + + vshPrintExtra(ctl, " %-15u %-15u ", + info[i]->iothread_id, + info[i]->thread_id); + ignore_value(vshPrintPinInfo(info[i]->cpumap, info[i]->cpumaplen, + maxcpu, 0)); + vshPrint(ctl, "\n"); + virDomainIOThreadsInfoFree(info[i]); + } + VIR_FREE(info); + + cleanup: + virDomainFree(dom); + return niothreads >= 0; +} + +/* * "cpu-compare" command */ static const vshCmdInfo info_cpu_compare[] = { @@ -12669,6 +12735,12 @@ const vshCmdDef domManagementCmds[] = { .info = info_inject_nmi, .flags = 0 }, + {.name = "iothreads", + .handler = cmdIOThreadsInfo, + .opts = opts_iothreads, + .info = info_iothreads, + .flags = 0 + }, {.name = "send-key", .handler = cmdSendKey, .opts = opts_send_key, diff --git a/tools/virsh.pod b/tools/virsh.pod index a3f527f..2c28acc 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1360,6 +1360,13 @@ If I<--timeout> is specified, the command gives up waiting for events after I<seconds> have elapsed. With I<--loop>, the command prints all events until a timeout or interrupt key. +=item B<iothreads> I<domain> + +Display basic domain IOThreads information including the IOThread ID, the +Thread ID, and the CPU Affinity for each IOThread. + +Note that the display of information only works for active domains. + =item B<managedsave> I<domain> [I<--bypass-cache>] [{I<--running> | I<--paused>}] [I<--verbose>] -- 2.1.0
participants (2)
-
Daniel P. Berrange
-
John Ferlan