mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-09-09 17:24:53 +00:00
qemu: monitor: Return struct from qemuMonitor(Text|Json)QueryCPUs
Prepare to extract more data by returning an array of structs rather than just an array of thread ids. Additionally report fatal errors separately from qemu not being able to produce data.
This commit is contained in:
parent
5b5f494a1b
commit
b3180425ce
@ -1666,6 +1666,16 @@ qemuMonitorCPUInfoFree(qemuMonitorCPUInfoPtr cpus,
|
|||||||
VIR_FREE(cpus);
|
VIR_FREE(cpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
|
||||||
|
size_t nentries ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
if (!entries)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VIR_FREE(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemuMonitorGetCPUInfo:
|
* qemuMonitorGetCPUInfo:
|
||||||
@ -1686,7 +1696,8 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
|
|||||||
size_t maxvcpus)
|
size_t maxvcpus)
|
||||||
{
|
{
|
||||||
qemuMonitorCPUInfoPtr info = NULL;
|
qemuMonitorCPUInfoPtr info = NULL;
|
||||||
int *pids = NULL;
|
struct qemuMonitorQueryCpusEntry *cpuentries = NULL;
|
||||||
|
size_t ncpuentries = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int rc;
|
int rc;
|
||||||
@ -1697,26 +1708,28 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon,
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (mon->json)
|
if (mon->json)
|
||||||
rc = qemuMonitorJSONQueryCPUs(mon, &pids);
|
rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries);
|
||||||
else
|
else
|
||||||
rc = qemuMonitorTextQueryCPUs(mon, &pids);
|
rc = qemuMonitorTextQueryCPUs(mon, &cpuentries, &ncpuentries);
|
||||||
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
virResetLastError();
|
if (rc == -2) {
|
||||||
VIR_STEAL_PTR(*vcpus, info);
|
VIR_STEAL_PTR(*vcpus, info);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < rc; i++)
|
for (i = 0; i < ncpuentries; i++)
|
||||||
info[i].tid = pids[i];
|
info[i].tid = cpuentries[i].tid;
|
||||||
|
|
||||||
VIR_STEAL_PTR(*vcpus, info);
|
VIR_STEAL_PTR(*vcpus, info);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
qemuMonitorCPUInfoFree(info, maxvcpus);
|
qemuMonitorCPUInfoFree(info, maxvcpus);
|
||||||
VIR_FREE(pids);
|
qemuMonitorQueryCpusFree(cpuentries, ncpuentries);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,6 +390,12 @@ int qemuMonitorGetStatus(qemuMonitorPtr mon,
|
|||||||
int qemuMonitorSystemReset(qemuMonitorPtr mon);
|
int qemuMonitorSystemReset(qemuMonitorPtr mon);
|
||||||
int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
|
int qemuMonitorSystemPowerdown(qemuMonitorPtr mon);
|
||||||
|
|
||||||
|
struct qemuMonitorQueryCpusEntry {
|
||||||
|
pid_t tid;
|
||||||
|
};
|
||||||
|
void qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
|
||||||
|
size_t nentries);
|
||||||
|
|
||||||
|
|
||||||
struct _qemuMonitorCPUInfo {
|
struct _qemuMonitorCPUInfo {
|
||||||
pid_t tid;
|
pid_t tid;
|
||||||
|
@ -1323,69 +1323,69 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon)
|
|||||||
* { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ]
|
* { "CPU": 1, "current": false, "halted": true, "pc": 7108165 } ]
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
|
qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data,
|
||||||
int **pids)
|
struct qemuMonitorQueryCpusEntry **entries,
|
||||||
|
size_t *nentries)
|
||||||
{
|
{
|
||||||
virJSONValuePtr data;
|
struct qemuMonitorQueryCpusEntry *cpus = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
size_t i;
|
size_t i;
|
||||||
int *threads = NULL;
|
|
||||||
ssize_t ncpus;
|
ssize_t ncpus;
|
||||||
|
|
||||||
if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
|
if ((ncpus = virJSONValueArraySize(data)) <= 0)
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
return -2;
|
||||||
_("cpu reply was missing return data"));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ncpus = virJSONValueArraySize(data)) <= 0) {
|
if (VIR_ALLOC_N(cpus, ncpus) < 0)
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
||||||
_("cpu information was empty"));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (VIR_ALLOC_N(threads, ncpus) < 0)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
for (i = 0; i < ncpus; i++) {
|
for (i = 0; i < ncpus; i++) {
|
||||||
virJSONValuePtr entry = virJSONValueArrayGet(data, i);
|
virJSONValuePtr entry = virJSONValueArrayGet(data, i);
|
||||||
int thread;
|
int thread = 0;
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
ret = -2;
|
||||||
_("cpu information was missing an array element"));
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virJSONValueObjectGetNumberInt(entry, "thread_id", &thread) < 0) {
|
/* Some older qemu versions don't report the thread_id so treat this as
|
||||||
/* Some older qemu versions don't report the thread_id,
|
* non-fatal, simply returning no data */
|
||||||
* so treat this as non-fatal, simply returning no data */
|
ignore_value(virJSONValueObjectGetNumberInt(entry, "thread_id", &thread));
|
||||||
ret = 0;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
threads[i] = thread;
|
cpus[i].tid = thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pids = threads;
|
VIR_STEAL_PTR(*entries, cpus);
|
||||||
threads = NULL;
|
*nentries = ncpus;
|
||||||
ret = ncpus;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(threads);
|
qemuMonitorQueryCpusFree(cpus, ncpus);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qemuMonitorJSONQueryCPUs:
|
||||||
|
*
|
||||||
|
* @mon: monitor object
|
||||||
|
* @entries: filled with detected entries on success
|
||||||
|
* @nentries: number of entries returned
|
||||||
|
*
|
||||||
|
* Queries qemu for cpu-related information. Failure to execute the command or
|
||||||
|
* extract results does not produce an error as libvirt can continue without
|
||||||
|
* this information.
|
||||||
|
*
|
||||||
|
* Returns 0 on success success, -1 on a fatal error (oom ...) and -2 if the
|
||||||
|
* query failed gracefully.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
|
qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
|
||||||
int **pids)
|
struct qemuMonitorQueryCpusEntry **entries,
|
||||||
|
size_t *nentries)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus",
|
virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus", NULL);
|
||||||
NULL);
|
|
||||||
virJSONValuePtr reply = NULL;
|
virJSONValuePtr reply = NULL;
|
||||||
|
virJSONValuePtr data;
|
||||||
*pids = NULL;
|
|
||||||
|
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
return -1;
|
return -1;
|
||||||
@ -1393,10 +1393,13 @@ qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
|
|||||||
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
|
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (qemuMonitorJSONCheckError(cmd, reply) < 0)
|
if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
|
||||||
|
ret = -2;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = qemuMonitorJSONExtractCPUInfo(data, entries, nentries);
|
||||||
|
|
||||||
ret = qemuMonitorJSONExtractCPUInfo(reply, pids);
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virJSONValueFree(cmd);
|
virJSONValueFree(cmd);
|
||||||
virJSONValueFree(reply);
|
virJSONValueFree(reply);
|
||||||
|
@ -59,7 +59,8 @@ int qemuMonitorJSONSystemPowerdown(qemuMonitorPtr mon);
|
|||||||
int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
|
int qemuMonitorJSONSystemReset(qemuMonitorPtr mon);
|
||||||
|
|
||||||
int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
|
int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon,
|
||||||
int **pids);
|
struct qemuMonitorQueryCpusEntry **entries,
|
||||||
|
size_t *nentries);
|
||||||
int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
|
int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon,
|
||||||
virDomainVirtType *virtType);
|
virDomainVirtType *virtType);
|
||||||
int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
|
int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon,
|
||||||
|
@ -502,12 +502,15 @@ int qemuMonitorTextSystemReset(qemuMonitorPtr mon)
|
|||||||
|
|
||||||
int
|
int
|
||||||
qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
|
qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
|
||||||
int **pids)
|
struct qemuMonitorQueryCpusEntry **entries,
|
||||||
|
size_t *nentries)
|
||||||
{
|
{
|
||||||
char *qemucpus = NULL;
|
char *qemucpus = NULL;
|
||||||
char *line;
|
char *line;
|
||||||
pid_t *cpupids = NULL;
|
struct qemuMonitorQueryCpusEntry *cpus = NULL;
|
||||||
size_t ncpupids = 0;
|
size_t ncpus = 0;
|
||||||
|
struct qemuMonitorQueryCpusEntry cpu = {0};
|
||||||
|
int ret = -2; /* -2 denotes a non-fatal error to get the data */
|
||||||
|
|
||||||
if (qemuMonitorHMPCommand(mon, "info cpus", &qemucpus) < 0)
|
if (qemuMonitorHMPCommand(mon, "info cpus", &qemucpus) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -529,15 +532,19 @@ qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
|
|||||||
|
|
||||||
/* Extract host Thread ID */
|
/* Extract host Thread ID */
|
||||||
if ((offset = strstr(line, "thread_id=")) == NULL)
|
if ((offset = strstr(line, "thread_id=")) == NULL)
|
||||||
goto error;
|
goto cleanup;
|
||||||
|
|
||||||
if (virStrToLong_i(offset + strlen("thread_id="), &end, 10, &tid) < 0)
|
if (virStrToLong_i(offset + strlen("thread_id="), &end, 10, &tid) < 0)
|
||||||
goto error;
|
goto cleanup;
|
||||||
if (end == NULL || !c_isspace(*end))
|
if (end == NULL || !c_isspace(*end))
|
||||||
goto error;
|
goto cleanup;
|
||||||
|
|
||||||
if (VIR_APPEND_ELEMENT_COPY(cpupids, ncpupids, tid) < 0)
|
cpu.tid = tid;
|
||||||
goto error;
|
|
||||||
|
if (VIR_APPEND_ELEMENT_COPY(cpus, ncpus, cpu) < 0) {
|
||||||
|
ret = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
VIR_DEBUG("tid=%d", tid);
|
VIR_DEBUG("tid=%d", tid);
|
||||||
|
|
||||||
@ -547,20 +554,14 @@ qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
|
|||||||
line = strchr(offset, '\n');
|
line = strchr(offset, '\n');
|
||||||
} while (line != NULL);
|
} while (line != NULL);
|
||||||
|
|
||||||
/* Validate we got data for all VCPUs we expected */
|
VIR_STEAL_PTR(*entries, cpus);
|
||||||
VIR_FREE(qemucpus);
|
*nentries = ncpus;
|
||||||
*pids = cpupids;
|
ret = 0;
|
||||||
return ncpupids;
|
|
||||||
|
|
||||||
error:
|
cleanup:
|
||||||
|
qemuMonitorQueryCpusFree(cpus, ncpus);
|
||||||
VIR_FREE(qemucpus);
|
VIR_FREE(qemucpus);
|
||||||
VIR_FREE(cpupids);
|
return ret;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,7 +50,8 @@ int qemuMonitorTextSystemPowerdown(qemuMonitorPtr mon);
|
|||||||
int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
|
int qemuMonitorTextSystemReset(qemuMonitorPtr mon);
|
||||||
|
|
||||||
int qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
|
int qemuMonitorTextQueryCPUs(qemuMonitorPtr mon,
|
||||||
int **pids);
|
struct qemuMonitorQueryCpusEntry **entries,
|
||||||
|
size_t *nentries);
|
||||||
int qemuMonitorTextGetVirtType(qemuMonitorPtr mon,
|
int qemuMonitorTextGetVirtType(qemuMonitorPtr mon,
|
||||||
virDomainVirtType *virtType);
|
virDomainVirtType *virtType);
|
||||||
int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
|
int qemuMonitorTextGetBalloonInfo(qemuMonitorPtr mon,
|
||||||
|
@ -1201,6 +1201,16 @@ GEN_TEST_FUNC(qemuMonitorJSONNBDServerStart, "localhost", 12345)
|
|||||||
GEN_TEST_FUNC(qemuMonitorJSONNBDServerAdd, "vda", true)
|
GEN_TEST_FUNC(qemuMonitorJSONNBDServerAdd, "vda", true)
|
||||||
GEN_TEST_FUNC(qemuMonitorJSONDetachCharDev, "serial1")
|
GEN_TEST_FUNC(qemuMonitorJSONDetachCharDev, "serial1")
|
||||||
|
|
||||||
|
static bool
|
||||||
|
testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(struct qemuMonitorQueryCpusEntry *a,
|
||||||
|
struct qemuMonitorQueryCpusEntry *b)
|
||||||
|
{
|
||||||
|
if (a->tid != b->tid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
|
testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
|
||||||
@ -1208,9 +1218,14 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
|
|||||||
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
|
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
|
||||||
qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
|
qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
pid_t *cpupids = NULL;
|
struct qemuMonitorQueryCpusEntry *cpudata = NULL;
|
||||||
pid_t expected_cpupids[] = {17622, 17624, 17626, 17628};
|
struct qemuMonitorQueryCpusEntry expect[] = {
|
||||||
int ncpupids;
|
{17622},
|
||||||
|
{17624},
|
||||||
|
{17626},
|
||||||
|
{17628},
|
||||||
|
};
|
||||||
|
size_t ncpudata = 0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (!test)
|
if (!test)
|
||||||
@ -1252,19 +1267,21 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
|
|||||||
"}") < 0)
|
"}") < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
ncpupids = qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test), &cpupids);
|
if (qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test),
|
||||||
|
&cpudata, &ncpudata) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (ncpupids != 4) {
|
if (ncpudata != 4) {
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
"Expecting ncpupids = 4 but got %d", ncpupids);
|
"Expecting ncpupids = 4 but got %zu", ncpudata);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ncpupids; i++) {
|
for (i = 0; i < ncpudata; i++) {
|
||||||
if (cpupids[i] != expected_cpupids[i]) {
|
if (!testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(cpudata + i,
|
||||||
|
expect + i)) {
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
"Expecting cpupids[%zu] = %d but got %d",
|
"vcpu entry %zu does not match expected data", i);
|
||||||
i, expected_cpupids[i], cpupids[i]);
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1272,7 +1289,7 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
VIR_FREE(cpupids);
|
qemuMonitorQueryCpusFree(cpudata, ncpudata);
|
||||||
qemuMonitorTestFree(test);
|
qemuMonitorTestFree(test);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user