[libvirt] [PATCHv2.5 05/10] qemu: memdev: Add infrastructure to load memory device information
John Ferlan
jferlan at redhat.com
Fri Mar 13 14:38:51 UTC 2015
On 03/04/2015 11:24 AM, Peter Krempa wrote:
> When using 'dimm' memory devices with qemu, some of the information
> like the slot number and base address need to be reloaded from qemu
> after process start so that it reflects the actual state. The state then
> allows to use memory devices across migrations.
> ---
> src/qemu/qemu_domain.c | 49 +++++++++++++++++
> src/qemu/qemu_domain.h | 4 ++
> src/qemu/qemu_monitor.c | 42 +++++++++++++++
> src/qemu/qemu_monitor.h | 14 +++++
> src/qemu/qemu_monitor_json.c | 122 +++++++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_monitor_json.h | 5 ++
> src/qemu/qemu_process.c | 4 ++
> 7 files changed, 240 insertions(+)
>
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 4225f38..61b0fc8 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -2784,6 +2784,55 @@ qemuDomainUpdateDeviceList(virQEMUDriverPtr driver,
> return 0;
> }
>
> +
> +int
> +qemuDomainUpdateMemoryDeviceInfo(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + int asyncJob)
> +{
> + qemuDomainObjPrivatePtr priv = vm->privateData;
> + virHashTablePtr meminfo = NULL;
> + int rc;
> + size_t i;
> +
> + if (vm->def->nmems == 0)
> + return 0;
> +
> + if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
> + return -1;
> +
> + rc = qemuMonitorGetMemoryDeviceInfo(priv->mon, &meminfo);
> +
> + if (qemuDomainObjExitMonitor(driver, vm) < 0)
> + return -1;
> +
> + /* if qemu doesn't support the info request, just carry on */
> + if (rc == -2)
> + rc = 0;
[1] hmmm
Cannot remember if we agreed previously that not having a message was ok
(e.g. "requires json" or "requires query-memory-devices command"). I
guess I figure if we get this far, then some other check has failed us.
But, but returning 0 we say - yep it worked, which of course isn't true.
I'm conflicted since future patches become affected...
> +
> + if (rc < 0)
> + return -1;
> +
> + for (i = 0; i < vm->def->nmems; i++) {
[1] If "the real" rc == -2, then vm->def->nmems > 0 and we enter this
loop which is probably not a good idea.
> + virDomainMemoryDefPtr mem = vm->def->mems[i];
> + qemuMonitorMemoryDeviceInfoPtr dimm;
> +
> + if (!mem->info.alias)
> + continue;
> +
> + if (!(dimm = virHashLookup(meminfo, mem->info.alias)))
> + continue;
> +
> + mem->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM;
> + mem->info.addr.dimm.slot = dimm->slot;
> + mem->info.addr.dimm.base = dimm->address;
> + }
> +
> + virHashFree(meminfo);
> + return 0;
> +}
> +
> +
> bool
> qemuDomainDefCheckABIStability(virQEMUDriverPtr driver,
> virDomainDefPtr src,
> diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
> index 9760095..b2be323 100644
> --- a/src/qemu/qemu_domain.h
> +++ b/src/qemu/qemu_domain.h
> @@ -391,6 +391,10 @@ extern virDomainDefParserConfig virQEMUDriverDomainDefParserConfig;
> int qemuDomainUpdateDeviceList(virQEMUDriverPtr driver,
> virDomainObjPtr vm, int asyncJob);
>
> +int qemuDomainUpdateMemoryDeviceInfo(virQEMUDriverPtr driver,
> + virDomainObjPtr vm,
> + int asyncJob);
> +
> bool qemuDomainDefCheckABIStability(virQEMUDriverPtr driver,
> virDomainDefPtr src,
> virDomainDefPtr dst);
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 94495cd..34673e1 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -4359,3 +4359,45 @@ void qemuMonitorIOThreadsInfoFree(qemuMonitorIOThreadsInfoPtr iothread)
> VIR_FREE(iothread->name);
> VIR_FREE(iothread);
> }
> +
> +
> +/**
> + * qemuMonitorGetMemoryDeviceInfo:
> + * @mon: pointer to the monitor
> + * @info: Location to return the hash of qemuMonitorMemoryDeviceInfo
> + *
> + * Retrieve state and addresses of frontend memory devices present in
> + * the guest.
> + *
> + * Returns 0 on success and fills @info with a newly allocated struct; if the
> + * data can't be retrieved due to lack of support in qemu, returns -2. On
> + * other errors returns -1.
> + */
> +int
> +qemuMonitorGetMemoryDeviceInfo(qemuMonitorPtr mon,
> + virHashTablePtr *info)
> +{
> + VIR_DEBUG("mon=%p info=%p", mon, info);
> + int ret;
> +
> + *info = NULL;
> +
> + if (!mon) {
> + virReportError(VIR_ERR_INVALID_ARG, "%s",
> + _("monitor must not be NULL"));
> + return -1;
> + }
> +
> + if (!mon->json)
> + return -2;
> +
> + if (!(*info = virHashCreate(10, virHashValueFree)))
> + return -1;
> +
> + if ((ret = qemuMonitorJSONGetMemoryDeviceInfo(mon, *info)) < 0) {
> + virHashFree(*info);
> + *info = NULL;
> + }
> +
> + return ret;
> +}
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index 133d42d..811ce49 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -892,6 +892,20 @@ int qemuMonitorGetIOThreads(qemuMonitorPtr mon,
>
> void qemuMonitorIOThreadsInfoFree(qemuMonitorIOThreadsInfoPtr iothread);
>
> +typedef struct _qemuMonitorMemoryDeviceInfo qemuMonitorMemoryDeviceInfo;
> +typedef qemuMonitorMemoryDeviceInfo *qemuMonitorMemoryDeviceInfoPtr;
> +
> +struct _qemuMonitorMemoryDeviceInfo {
> + unsigned long long address;
> + unsigned int slot;
> + bool hotplugged;
> + bool hotpluggable;
> +};
> +
> +int qemuMonitorGetMemoryDeviceInfo(qemuMonitorPtr mon,
> + virHashTablePtr *info)
> + ATTRIBUTE_NONNULL(2);
> +
> /**
> * When running two dd process and using <> redirection, we need a
> * shell that will not truncate files. These two strings serve that
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 832f589..e463988 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -6569,3 +6569,125 @@ qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon,
> virJSONValueFree(reply);
> return ret;
> }
> +
> +
> +int
> +qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitorPtr mon,
> + virHashTablePtr info)
> +{
> + int ret = -1;
> + virJSONValuePtr cmd;
> + virJSONValuePtr reply = NULL;
> + virJSONValuePtr data = NULL;
> + qemuMonitorMemoryDeviceInfoPtr meminfo = NULL;
> + ssize_t n;
> + size_t i;
> +
> + if (!(cmd = qemuMonitorJSONMakeCommand("query-memory-devices", NULL)))
> + return -1;
> +
> + ret = qemuMonitorJSONCommand(mon, cmd, &reply);
> +
> + if (ret == 0) {
> + if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
> + ret = -2;
> + goto cleanup;
> + }
> +
> + ret = qemuMonitorJSONCheckError(cmd, reply);
> + }
> +
> + if (ret < 0)
> + goto cleanup;
> +
> + ret = -1;
> +
> + if (!(data = virJSONValueObjectGet(reply, "return"))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("query-memory-devices reply was missing return data"));
> + goto cleanup;
> + }
> +
> + if ((n = virJSONValueArraySize(data)) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("query-memory-devices reply data was not an array"));
> + goto cleanup;
> + }
> +
> + for (i = 0; i < n; i++) {
> + virJSONValuePtr elem = virJSONValueArrayGet(data, i);
> + const char *type;
> +
> + if (!(type = virJSONValueObjectGetString(elem, "type"))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("query-memory-devices reply data doesn't contain "
> + "enum type discriminator"));
> + goto cleanup;
> + }
> +
> + /* dimm memory devices */
> + if (STREQ(type, "dimm")) {
> + virJSONValuePtr dimminfo;
> + const char *devalias;
> +
> + if (!(dimminfo = virJSONValueObjectGet(elem, "data"))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("query-memory-devices reply data doesn't "
> + "contain enum data"));
> + goto cleanup;
> + }
> +
> + if (!(devalias = virJSONValueObjectGetString(dimminfo, "id"))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("dimm memory info data is missing 'id'"));
> + goto cleanup;
> + }
> +
> + if (VIR_ALLOC(meminfo) < 0)
> + goto cleanup;
> +
> + if (virJSONValueObjectGetNumberUlong(dimminfo, "addr",
> + &meminfo->address) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("malformed/missing addr in dimm memory info"));
> + goto cleanup;
> + }
> +
> + if (virJSONValueObjectGetNumberUint(dimminfo, "slot",
> + &meminfo->slot) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("malformed/missing slot in dimm memory info"));
> + goto cleanup;
> + }
> +
> + if (virJSONValueObjectGetBoolean(dimminfo, "hotplugged",
> + &meminfo->hotplugged) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("malformed/missing hotplugged in dimm memory info"));
> + goto cleanup;
> +
> + }
> +
> + if (virJSONValueObjectGetBoolean(dimminfo, "hotpluggable",
> + &meminfo->hotpluggable) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("malformed/missing hotpluggable in dimm memory info"));
> + goto cleanup;
> +
> + }
> +
> + if (virHashAddEntry(info, devalias, meminfo) < 0)
> + goto cleanup;
> +
> + meminfo = NULL;
> + }
> + }
> +
> + ret = 0;
> +
> + cleanup:
> + VIR_FREE(meminfo);
> + virJSONValueFree(cmd);
> + virJSONValueFree(reply);
> + return ret;
> +}
> diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
> index 1da1a00..eb51a60 100644
> --- a/src/qemu/qemu_monitor_json.h
> +++ b/src/qemu/qemu_monitor_json.h
> @@ -475,4 +475,9 @@ int qemuMonitorJSONRTCResetReinjection(qemuMonitorPtr mon);
> int qemuMonitorJSONGetIOThreads(qemuMonitorPtr mon,
> qemuMonitorIOThreadsInfoPtr **iothreads)
> ATTRIBUTE_NONNULL(2);
> +
> +int qemuMonitorJSONGetMemoryDeviceInfo(qemuMonitorPtr mon,
> + virHashTablePtr info)
> + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
> +
> #endif /* QEMU_MONITOR_JSON_H */
> diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
> index 019b477..fecc20c 100644
> --- a/src/qemu/qemu_process.c
> +++ b/src/qemu/qemu_process.c
> @@ -4989,6 +4989,10 @@ int qemuProcessStart(virConnectPtr conn,
> if (qemuDomainUpdateDeviceList(driver, vm, asyncJob) < 0)
> goto cleanup;
>
> + VIR_DEBUG("Updating info of memory devices");
> + if (qemuDomainUpdateMemoryDeviceInfo(driver, vm, asyncJob) < 0)
> + goto cleanup;
> +
> /* Technically, qemuProcessStart can be called from inside
> * QEMU_ASYNC_JOB_MIGRATION_IN, but we are okay treating this like
> * a sync job since no other job can call into the domain until
>
There's nothing through the qemuProcessAttach processing for this data
(although there is balloon info processing)
- Decision on error handling of -2 or not
- Don't drop into the loop to look at returned data if we had -2 returned
- And add some sort of qemuProcessAttach handling...
Just so it doesn't impede progress, I'm fine with a future follow-up
patch for the qemuProcessAttach. Leaving only handling the second point
above for an ACK
John
More information about the libvir-list
mailing list