mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-04-01 20:05:19 +00:00
qemu: monitor: Add support for calling query-hotpluggable-cpus
Add support for retrieving information regarding hotpluggable cpu units supported by qemu. Data returned by the command carries information needed to figure out the granularity of hotplug, the necessary cpu type name and the topology information. Note that qemu doesn't specify any particular order of the entries thus it's necessary sort them by socket_id, core_id and thread_id to the order libvirt expects.
This commit is contained in:
parent
c91be16b9f
commit
1213f0f8a5
@ -398,6 +398,22 @@ void qemuMonitorQueryCpusFree(struct qemuMonitorQueryCpusEntry *entries,
|
||||
size_t nentries);
|
||||
|
||||
|
||||
struct qemuMonitorQueryHotpluggableCpusEntry {
|
||||
char *type; /* name of the cpu to use with device_add */
|
||||
unsigned int vcpus; /* count of virtual cpus in the guest this entry adds */
|
||||
char *qom_path; /* full device qom path only present for online cpus */
|
||||
char *alias; /* device alias, may be NULL for non-hotpluggable entities */
|
||||
|
||||
/* topology information -1 if qemu didn't report given parameter */
|
||||
int node_id;
|
||||
int socket_id;
|
||||
int core_id;
|
||||
int thread_id;
|
||||
};
|
||||
void qemuMonitorQueryHotpluggableCpusFree(struct qemuMonitorQueryHotpluggableCpusEntry *entries,
|
||||
size_t nentries);
|
||||
|
||||
|
||||
struct _qemuMonitorCPUInfo {
|
||||
pid_t tid;
|
||||
};
|
||||
|
@ -7070,3 +7070,173 @@ qemuMonitorJSONGetRTCTime(qemuMonitorPtr mon,
|
||||
virJSONValueFree(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
qemuMonitorQueryHotpluggableCpusFree(struct qemuMonitorQueryHotpluggableCpusEntry *entries,
|
||||
size_t nentries)
|
||||
{
|
||||
struct qemuMonitorQueryHotpluggableCpusEntry *entry;
|
||||
size_t i;
|
||||
|
||||
if (!entries)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nentries; i++) {
|
||||
entry = entries + i;
|
||||
|
||||
VIR_FREE(entry->type);
|
||||
VIR_FREE(entry->qom_path);
|
||||
VIR_FREE(entry->alias);
|
||||
}
|
||||
|
||||
VIR_FREE(entries);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [{
|
||||
* "props": {
|
||||
* "core-id": 0,
|
||||
* "thread-id": 0,
|
||||
* "socket-id": 0
|
||||
* },
|
||||
* "vcpus-count": 1,
|
||||
* "qom-path": "/machine/unattached/device[0]",
|
||||
* "type": "qemu64-x86_64-cpu"
|
||||
* },
|
||||
* {...}
|
||||
* ]
|
||||
*/
|
||||
static int
|
||||
qemuMonitorJSONProcessHotpluggableCpusReply(virJSONValuePtr vcpu,
|
||||
struct qemuMonitorQueryHotpluggableCpusEntry *entry)
|
||||
{
|
||||
virJSONValuePtr props;
|
||||
const char *tmp;
|
||||
|
||||
if (!(tmp = virJSONValueObjectGetString(vcpu, "type"))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("query-hotpluggable-cpus didn't return device type"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (VIR_STRDUP(entry->type, tmp) < 0)
|
||||
return -1;
|
||||
|
||||
if (virJSONValueObjectGetNumberUint(vcpu, "vcpus-count", &entry->vcpus) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("query-hotpluggable-cpus didn't return vcpus-count"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(props = virJSONValueObjectGetObject(vcpu, "props"))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("query-hotpluggable-cpus didn't return device props"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
entry->node_id = -1;
|
||||
entry->socket_id = -1;
|
||||
entry->core_id = -1;
|
||||
entry->thread_id = -1;
|
||||
|
||||
ignore_value(virJSONValueObjectGetNumberInt(props, "node-id", &entry->node_id));
|
||||
ignore_value(virJSONValueObjectGetNumberInt(props, "socket-id", &entry->socket_id));
|
||||
ignore_value(virJSONValueObjectGetNumberInt(props, "core-id", &entry->core_id));
|
||||
ignore_value(virJSONValueObjectGetNumberInt(props, "thread-id", &entry->thread_id));
|
||||
|
||||
if (entry->node_id == -1 && entry->socket_id == -1 &&
|
||||
entry->core_id == -1 && entry->thread_id == -1) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("query-hotpluggable-cpus entry doesn't report "
|
||||
"topology information"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* qom path is not present unless the vCPU is online */
|
||||
if ((tmp = virJSONValueObjectGetString(vcpu, "qom-path"))) {
|
||||
if (VIR_STRDUP(entry->qom_path, tmp) < 0)
|
||||
return -1;
|
||||
|
||||
/* alias is the part after last slash having a "vcpu" prefix */
|
||||
if ((tmp = strrchr(tmp, '/')) && STRPREFIX(tmp + 1, "vcpu")) {
|
||||
if (VIR_STRDUP(entry->alias, tmp + 1) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuMonitorQueryHotpluggableCpusEntrySort(const void *p1,
|
||||
const void *p2)
|
||||
{
|
||||
const struct qemuMonitorQueryHotpluggableCpusEntry *a = p1;
|
||||
const struct qemuMonitorQueryHotpluggableCpusEntry *b = p2;
|
||||
|
||||
if (a->socket_id != b->socket_id)
|
||||
return a->socket_id - b->socket_id;
|
||||
|
||||
if (a->core_id != b->core_id)
|
||||
return a->core_id - b->core_id;
|
||||
|
||||
return a->thread_id - b->thread_id;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuMonitorJSONGetHotpluggableCPUs(qemuMonitorPtr mon,
|
||||
struct qemuMonitorQueryHotpluggableCpusEntry **entries,
|
||||
size_t *nentries)
|
||||
{
|
||||
struct qemuMonitorQueryHotpluggableCpusEntry *info = NULL;
|
||||
ssize_t ninfo = 0;
|
||||
int ret = -1;
|
||||
size_t i;
|
||||
virJSONValuePtr data;
|
||||
virJSONValuePtr cmd;
|
||||
virJSONValuePtr reply = NULL;
|
||||
virJSONValuePtr vcpu;
|
||||
|
||||
if (!(cmd = qemuMonitorJSONMakeCommand("query-hotpluggable-cpus", NULL)))
|
||||
return -1;
|
||||
|
||||
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (qemuMonitorJSONCheckError(cmd, reply) < 0)
|
||||
goto cleanup;
|
||||
|
||||
data = virJSONValueObjectGet(reply, "return");
|
||||
|
||||
if ((ninfo = virJSONValueArraySize(data)) < 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("query-hotpluggable-cpus reply is not an array"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC_N(info, ninfo) < 0)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < ninfo; i++) {
|
||||
vcpu = virJSONValueArrayGet(data, i);
|
||||
|
||||
if (qemuMonitorJSONProcessHotpluggableCpusReply(vcpu, info + i) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qsort(info, ninfo, sizeof(*info), qemuMonitorQueryHotpluggableCpusEntrySort);
|
||||
|
||||
VIR_STEAL_PTR(*entries, info);
|
||||
*nentries = ninfo;
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
qemuMonitorQueryHotpluggableCpusFree(info, ninfo);
|
||||
virJSONValueFree(cmd);
|
||||
virJSONValueFree(reply);
|
||||
return ret;
|
||||
}
|
||||
|
@ -494,4 +494,9 @@ int qemuMonitorJSONMigrateStartPostCopy(qemuMonitorPtr mon)
|
||||
int qemuMonitorJSONGetRTCTime(qemuMonitorPtr mon,
|
||||
struct tm *tm)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int qemuMonitorJSONGetHotpluggableCPUs(qemuMonitorPtr mon,
|
||||
struct qemuMonitorQueryHotpluggableCpusEntry **entries,
|
||||
size_t *nentries)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
|
||||
#endif /* QEMU_MONITOR_JSON_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user