* src/qemu/qemu_monitor.h, src/qemu/qemu_monitor.c: Add a new
qemuMonitorGetCPUInfo() command
* src/qemu/qemu_driver.c: Refactor qemudDetectVcpuPIDs to
use qemuMonitorGetCPUInfo()
---
src/qemu/qemu_driver.c | 114 ++++++++++--------------------------------
src/qemu/qemu_monitor_text.c | 85 +++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 4 +-
3 files changed, 115 insertions(+), 88 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9f17aae..30d1468 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -110,8 +110,8 @@ static int qemudDomainGetMaxVcpus(virDomainPtr dom);
static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
virDomainObjPtr vm,
unsigned long newmem);
-static int qemudDetectVcpuPIDs(virConnectPtr conn,
- virDomainObjPtr vm);
+static int qemuDetectVcpuPIDs(virConnectPtr conn,
+ virDomainObjPtr vm);
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
virDomainDefPtr def);
@@ -1186,100 +1186,40 @@ qemudWaitForMonitor(virConnectPtr conn,
}
static int
-qemudDetectVcpuPIDs(virConnectPtr conn,
- virDomainObjPtr vm) {
- char *qemucpus = NULL;
- char *line;
- int lastVcpu = -1;
-
- /* Only KVM has seperate threads for CPUs,
- others just use main QEMU process for CPU */
- if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM)
- vm->nvcpupids = 1;
- else
- vm->nvcpupids = vm->def->vcpus;
-
- if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) {
- virReportOOMError(conn);
- return -1;
- }
+qemuDetectVcpuPIDs(virConnectPtr conn,
+ virDomainObjPtr vm) {
+ pid_t *cpupids = NULL;
+ int ncpupids;
if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
+ vm->nvcpupids = 1;
+ if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) {
+ virReportOOMError(conn);
+ return -1;
+ }
vm->vcpupids[0] = vm->pid;
return 0;
}
- if (qemudMonitorCommand(vm, "info cpus", &qemucpus) < 0) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- "%s", _("cannot run monitor command to fetch CPU
thread info"));
- VIR_FREE(vm->vcpupids);
- vm->nvcpupids = 0;
- return -1;
- }
-
- /*
- * This is the gross format we're about to parse :-{
- *
- * (qemu) info cpus
- * * CPU #0: pc=0x00000000000f0c4a thread_id=30019
- * CPU #1: pc=0x00000000fffffff0 thread_id=30020
- * CPU #2: pc=0x00000000fffffff0 thread_id=30021
- *
- */
- line = qemucpus;
- do {
- char *offset = strchr(line, '#');
- char *end = NULL;
- int vcpu = 0, tid = 0;
-
- /* See if we're all done */
- if (offset == NULL)
- break;
+ /* What follows is now all KVM specific */
- /* Extract VCPU number */
- if (virStrToLong_i(offset + 1, &end, 10, &vcpu) < 0)
- goto error;
- if (end == NULL || *end != ':')
- goto error;
-
- /* Extract host Thread ID */
- if ((offset = strstr(line, "thread_id=")) == NULL)
- goto error;
- if (virStrToLong_i(offset + strlen("thread_id="), &end, 10,
&tid) < 0)
- goto error;
- if (end == NULL || !c_isspace(*end))
- goto error;
-
- /* Validate the VCPU is in expected range & order */
- if (vcpu > vm->nvcpupids ||
- vcpu != (lastVcpu + 1))
- goto error;
-
- lastVcpu = vcpu;
- vm->vcpupids[vcpu] = tid;
-
- /* Skip to next data line */
- line = strchr(offset, '\r');
- if (line == NULL)
- line = strchr(offset, '\n');
- } while (line != NULL);
-
- /* Validate we got data for all VCPUs we expected */
- if (lastVcpu != (vm->def->vcpus - 1))
- goto error;
+ if ((ncpupids = qemuMonitorGetCPUInfo(vm, &cpupids)) < 0)
+ return -1;
- VIR_FREE(qemucpus);
- return 0;
+ /* Treat failure to get VCPU<->PID mapping as non-fatal */
+ if (ncpupids == 0)
+ return 0;
-error:
- VIR_FREE(vm->vcpupids);
- vm->nvcpupids = 0;
- VIR_FREE(qemucpus);
+ if (ncpupids != vm->def->vcpus) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("got wrong number of vCPU pids from QEMU monitor. got %d,
wanted %d"),
+ ncpupids, (int)vm->def->vcpus);
+ VIR_FREE(cpupids);
+ return -1;
+ }
- /* Explicitly return success, not error. Older KVM does
- not have vCPU -> Thread mapping info and we don't
- want to break its use. This merely disables ability
- to pin vCPUS with libvirt */
+ vm->nvcpupids = ncpupids;
+ vm->vcpupids = cpupids;
return 0;
}
@@ -2202,7 +2142,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
goto cleanup;
if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) ||
- (qemudDetectVcpuPIDs(conn, vm) < 0) ||
+ (qemuDetectVcpuPIDs(conn, vm) < 0) ||
(qemudInitCpus(conn, vm, migrateFrom) < 0) ||
(qemudInitPasswords(conn, driver, vm) < 0) ||
(qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) ||
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 76842a5..d93e475 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -31,6 +31,7 @@
#include "qemu_monitor_text.h"
#include "qemu_conf.h"
+#include "c-ctype.h"
#include "memory.h"
#include "logging.h"
#include "driver.h"
@@ -435,3 +436,87 @@ qemudMonitorSendCont(virConnectPtr conn,
VIR_FREE(reply);
return 0;
}
+
+
+int qemuMonitorGetCPUInfo(const virDomainObjPtr vm,
+ int **pids)
+{
+ char *qemucpus = NULL;
+ char *line;
+ int lastVcpu = -1;
+ pid_t *cpupids = NULL;
+ size_t ncpupids = 0;
+
+ if (qemudMonitorCommand(vm, "info cpus", &qemucpus) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot run monitor command to fetch CPU
thread info"));
+ return -1;
+ }
+
+ /*
+ * This is the gross format we're about to parse :-{
+ *
+ * (qemu) info cpus
+ * * CPU #0: pc=0x00000000000f0c4a thread_id=30019
+ * CPU #1: pc=0x00000000fffffff0 thread_id=30020
+ * CPU #2: pc=0x00000000fffffff0 thread_id=30021
+ *
+ */
+ line = qemucpus;
+ do {
+ char *offset = strchr(line, '#');
+ char *end = NULL;
+ int vcpu = 0, tid = 0;
+
+ /* See if we're all done */
+ if (offset == NULL)
+ break;
+
+ /* Extract VCPU number */
+ if (virStrToLong_i(offset + 1, &end, 10, &vcpu) < 0)
+ goto error;
+
+ if (end == NULL || *end != ':')
+ goto error;
+
+ /* Extract host Thread ID */
+ if ((offset = strstr(line, "thread_id=")) == NULL)
+ goto error;
+
+ if (virStrToLong_i(offset + strlen("thread_id="), &end, 10,
&tid) < 0)
+ goto error;
+ if (end == NULL || !c_isspace(*end))
+ goto error;
+
+ if (vcpu != (lastVcpu + 1))
+ goto error;
+
+ if (VIR_REALLOC_N(cpupids, ncpupids+1) < 0)
+ goto error;
+
+ cpupids[ncpupids++] = tid;
+ lastVcpu = vcpu;
+
+ /* Skip to next data line */
+ line = strchr(offset, '\r');
+ if (line == NULL)
+ line = strchr(offset, '\n');
+ } while (line != NULL);
+
+ /* Validate we got data for all VCPUs we expected */
+ VIR_FREE(qemucpus);
+ *pids = cpupids;
+ return ncpupids;
+
+error:
+ VIR_FREE(qemucpus);
+ VIR_FREE(cpupids);
+
+ /* Returning 0 to indicate non-fatal failure, since
+ * older QEMU does not have VCPU<->PID mapping and
+ * we don't want to fail on that
+ */
+ return 0;
+}
+
+
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 35ca81d..973c3b6 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -68,5 +68,7 @@ int qemudMonitorCommandExtra(const virDomainObjPtr vm,
int qemudMonitorSendCont(virConnectPtr conn,
const virDomainObjPtr vm);
-#endif /* QEMU_MONITOR_TEXT_H */
+int qemuMonitorGetCPUInfo(const virDomainObjPtr vm,
+ int **pids);
+#endif /* QEMU_MONITOR_TEXT_H */
--
1.6.2.5