mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-02 18:05:20 +00:00
Add API for 'info cpus' monitor command
* 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()
This commit is contained in:
parent
a541c76238
commit
f38b654e9b
@ -110,7 +110,7 @@ static int qemudDomainGetMaxVcpus(virDomainPtr dom);
|
|||||||
static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
|
static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
unsigned long newmem);
|
unsigned long newmem);
|
||||||
static int qemudDetectVcpuPIDs(virConnectPtr conn,
|
static int qemuDetectVcpuPIDs(virConnectPtr conn,
|
||||||
virDomainObjPtr vm);
|
virDomainObjPtr vm);
|
||||||
|
|
||||||
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
|
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
|
||||||
@ -1186,100 +1186,40 @@ qemudWaitForMonitor(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemudDetectVcpuPIDs(virConnectPtr conn,
|
qemuDetectVcpuPIDs(virConnectPtr conn,
|
||||||
virDomainObjPtr vm) {
|
virDomainObjPtr vm) {
|
||||||
char *qemucpus = NULL;
|
pid_t *cpupids = NULL;
|
||||||
char *line;
|
int ncpupids;
|
||||||
int lastVcpu = -1;
|
|
||||||
|
|
||||||
/* Only KVM has seperate threads for CPUs,
|
if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
|
||||||
others just use main QEMU process for CPU */
|
|
||||||
if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM)
|
|
||||||
vm->nvcpupids = 1;
|
vm->nvcpupids = 1;
|
||||||
else
|
|
||||||
vm->nvcpupids = vm->def->vcpus;
|
|
||||||
|
|
||||||
if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) {
|
if (VIR_ALLOC_N(vm->vcpupids, vm->nvcpupids) < 0) {
|
||||||
virReportOOMError(conn);
|
virReportOOMError(conn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vm->def->virtType != VIR_DOMAIN_VIRT_KVM) {
|
|
||||||
vm->vcpupids[0] = vm->pid;
|
vm->vcpupids[0] = vm->pid;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemudMonitorCommand(vm, "info cpus", &qemucpus) < 0) {
|
/* What follows is now all KVM specific */
|
||||||
|
|
||||||
|
if ((ncpupids = qemuMonitorGetCPUInfo(vm, &cpupids)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Treat failure to get VCPU<->PID mapping as non-fatal */
|
||||||
|
if (ncpupids == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ncpupids != vm->def->vcpus) {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
"%s", _("cannot run monitor command to fetch CPU thread info"));
|
_("got wrong number of vCPU pids from QEMU monitor. got %d, wanted %d"),
|
||||||
VIR_FREE(vm->vcpupids);
|
ncpupids, (int)vm->def->vcpus);
|
||||||
vm->nvcpupids = 0;
|
VIR_FREE(cpupids);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
vm->nvcpupids = ncpupids;
|
||||||
* This is the gross format we're about to parse :-{
|
vm->vcpupids = cpupids;
|
||||||
*
|
|
||||||
* (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;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
VIR_FREE(qemucpus);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
VIR_FREE(vm->vcpupids);
|
|
||||||
vm->nvcpupids = 0;
|
|
||||||
VIR_FREE(qemucpus);
|
|
||||||
|
|
||||||
/* 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 */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2202,7 +2142,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) ||
|
if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) ||
|
||||||
(qemudDetectVcpuPIDs(conn, vm) < 0) ||
|
(qemuDetectVcpuPIDs(conn, vm) < 0) ||
|
||||||
(qemudInitCpus(conn, vm, migrateFrom) < 0) ||
|
(qemudInitCpus(conn, vm, migrateFrom) < 0) ||
|
||||||
(qemudInitPasswords(conn, driver, vm) < 0) ||
|
(qemudInitPasswords(conn, driver, vm) < 0) ||
|
||||||
(qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) ||
|
(qemudDomainSetMemoryBalloon(conn, vm, vm->def->memory) < 0) ||
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "qemu_monitor_text.h"
|
#include "qemu_monitor_text.h"
|
||||||
#include "qemu_conf.h"
|
#include "qemu_conf.h"
|
||||||
|
#include "c-ctype.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
@ -435,3 +436,87 @@ qemudMonitorSendCont(virConnectPtr conn,
|
|||||||
VIR_FREE(reply);
|
VIR_FREE(reply);
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,5 +68,7 @@ int qemudMonitorCommandExtra(const virDomainObjPtr vm,
|
|||||||
int qemudMonitorSendCont(virConnectPtr conn,
|
int qemudMonitorSendCont(virConnectPtr conn,
|
||||||
const virDomainObjPtr vm);
|
const virDomainObjPtr vm);
|
||||||
|
|
||||||
#endif /* QEMU_MONITOR_TEXT_H */
|
int qemuMonitorGetCPUInfo(const virDomainObjPtr vm,
|
||||||
|
int **pids);
|
||||||
|
|
||||||
|
#endif /* QEMU_MONITOR_TEXT_H */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user