The new QMP API query-current-machine reports VM capabilities that
can vary depending on the VM configuration, in contrast to most
QEMU caps that can be set once during libvirtd init as exposed in
qemu_capabilities.c.
As such, to properly set the runtime capabilities exposed by this
API, we must query them at VM launch time. To do that, a new function
called qemuProcessSetCurrentMachineCaps is called in qemuProcessLaunch.
A new struct called qemuMonitorCurrentMachineInfo was created to host
the output of the API (which contains only the wakeup-suspend-support
flag for now, but can be expanded in the future). This struct is
populated by qemuMonitorGetCurrentMachineInfo, which does the heavy
work - executes query-current-machine, parses the result and populates
the qemuMonitorCurrentMachineInfo struct.
qemuProcessSetCurrentMachineCaps can then read the structure and
set the capabilities accordingly.
Signed-off-by: Daniel Henrique Barboza <danielhb413@xxxxxxxxx>
---
src/qemu/qemu_monitor.c | 17 ++++++++++++
src/qemu/qemu_monitor.h | 11 ++++++++
src/qemu/qemu_monitor_json.c | 53 ++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 5 ++++
src/qemu/qemu_process.c | 36 ++++++++++++++++++++++++
5 files changed, 122 insertions(+)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index babcbde878..d4222f0bcc 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4472,3 +4472,20 @@ qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon,
virHashFree(info);
return ret;
}
+
+int
+qemuMonitorGetCurrentMachineInfo(qemuMonitorPtr mon,
+ qemuMonitorCurrentMachineInfoPtr info)
+{
+ int ret = -1;
+
+ QEMU_CHECK_MONITOR(mon);
+
+ if (qemuMonitorJSONGetCurrentMachineInfo(mon, info) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 086195ff98..fcd5a022b5 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1220,4 +1220,15 @@ struct _qemuMonitorPRManagerInfo {
int qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon,
virHashTablePtr *retinfo);
+struct _qemuMonitorCurrentMachineInfo {
+ bool wakeupSuspendSupport;
+};
+
+typedef struct _qemuMonitorCurrentMachineInfo qemuMonitorCurrentMachineInfo;
+typedef qemuMonitorCurrentMachineInfo *qemuMonitorCurrentMachineInfoPtr;
+
+int
+qemuMonitorGetCurrentMachineInfo(qemuMonitorPtr mon,
+ qemuMonitorCurrentMachineInfoPtr info);
+
#endif /* LIBVIRT_QEMU_MONITOR_H */
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 8e6c3ccd63..c6a2a59e6b 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -8449,3 +8449,56 @@ qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
return ret;
}
+
+static int
+qemuMonitorJSONExtractCurrentMachineInfo(virJSONValuePtr reply,
+ qemuMonitorCurrentMachineInfoPtr info)
+{
+ virJSONValuePtr data;
+ int ret = -1;
+
+ data = virJSONValueObjectGetObject(reply, "return");
+ if (!data)
+ goto malformed;
+
+ if (virJSONValueObjectGetBoolean(data, "wakeup-suspend-support",
+ &info->wakeupSuspendSupport) < 0) {
+ goto malformed;
+ }
+
+ ret = 0;
+
+ out:
+ return ret;
+
+ malformed:
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("malformed qemu-current-machine reply"));
+ goto out;
+}
+
+int
+qemuMonitorJSONGetCurrentMachineInfo(qemuMonitorPtr mon,
+ qemuMonitorCurrentMachineInfoPtr info)
+{
+ int ret = -1;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("query-current-machine",
+ NULL)))
+ return -1;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ goto cleanup;
+
+ if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0)
+ goto cleanup;
+
+ ret = qemuMonitorJSONExtractCurrentMachineInfo(reply, info);
+
+ cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index c10513da15..746b7072ca 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -576,4 +576,9 @@ int qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
virHashTablePtr info)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int
+qemuMonitorJSONGetCurrentMachineInfo(qemuMonitorPtr mon,
+ qemuMonitorCurrentMachineInfoPtr info)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
#endif /* LIBVIRT_QEMU_MONITOR_JSON_H */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 47d8ca2ff1..b60c1ecfbe 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -6461,6 +6461,39 @@ qemuProcessSetupDiskThrottlingBlockdev(virQEMUDriverPtr driver,
return ret;
}
+static int
+qemuProcessSetCurrentMachineCaps(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ qemuDomainAsyncJob asyncJob)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ qemuMonitorCurrentMachineInfoPtr info;
+ int ret = -1;
+
+ if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_CURRENT_MACHINE))
+ return 0;
+
+ if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+ return -1;
+
+ if (VIR_ALLOC(info) < 0)
+ return -1;
+
+ ret = qemuMonitorGetCurrentMachineInfo(priv->mon, info);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0)
+ ret = -1;
+
+ if (ret < 0)
+ goto cleanup;
+
+ if (info->wakeupSuspendSupport)
+ virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_PM_WAKEUP_SUPPORT);
+
+ cleanup:
+ VIR_FREE(info);
+ return ret;
+}
/**
* qemuProcessLaunch:
@@ -6778,6 +6811,9 @@ qemuProcessLaunch(virConnectPtr conn,
if (qemuProcessSetupDiskThrottlingBlockdev(driver, vm, asyncJob) < 0)
goto cleanup;
+ if (qemuProcessSetCurrentMachineCaps(driver, vm, asyncJob) < 0)
+ goto cleanup;