qemu driver in libvirt gained support for creating domain snapshots
almost a year ago in libvirt 0.8.0. Since then we enabled QMP support
for qemu >= 0.13.0 but a QMP equivalent of savevm command is not
implemented in current qemu (0.14.0) so the domain snapshot support is
not very useful.
This patch detects when the appropriate QMP command is not implemented
and tries to use human-monitor-command (aka HMP passthrough) to run
savevm HMP command.
---
src/qemu/qemu_monitor.c | 12 +++++
src/qemu/qemu_monitor.h | 8 +++-
src/qemu/qemu_monitor_json.c | 95 +++++++++++++++++++++++++++++------------
src/qemu/qemu_monitor_json.h | 5 ++
src/qemu/qemu_monitor_text.c | 18 +++-----
src/qemu/qemu_monitor_text.h | 5 ++
6 files changed, 102 insertions(+), 41 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index dfb1aad..2d5124e 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -742,6 +742,18 @@ cleanup:
}
+int qemuMonitorCommandWithFd(qemuMonitorPtr mon,
+ const char *cmd,
+ int scm_fd,
+ char **reply)
+{
+ if (mon->json)
+ return qemuMonitorJSONHumanCommandWithFd(mon, cmd, scm_fd, reply);
+ else
+ return qemuMonitorTextCommandWithFd(mon, cmd, scm_fd, reply);
+}
+
+
int qemuMonitorGetDiskSecret(qemuMonitorPtr mon,
virConnectPtr conn,
const char *path,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 0ea1330..7200db8 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -133,9 +133,15 @@ void qemuMonitorUnlock(qemuMonitorPtr mon);
int qemuMonitorRef(qemuMonitorPtr mon);
int qemuMonitorUnref(qemuMonitorPtr mon);
-/* This API is for use by the internal Text/JSON monitor impl code only */
+/* These APIs are for use by the internal Text/JSON monitor impl code only */
int qemuMonitorSend(qemuMonitorPtr mon,
qemuMonitorMessagePtr msg);
+int qemuMonitorCommandWithFd(qemuMonitorPtr mon,
+ const char *cmd,
+ int scm_fd,
+ char **reply);
+# define qemuMonitorCommand(mon, cmd, reply) \
+ qemuMonitorCommandWithFd(mon, cmd, -1, reply)
/* XXX same comment about virConnectPtr as above */
int qemuMonitorGetDiskSecret(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index e6903a1..afc29c8 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -31,6 +31,7 @@
#include <string.h>
#include <sys/time.h>
+#include "qemu_monitor_text.h"
#include "qemu_monitor_json.h"
#include "qemu_command.h"
#include "memory.h"
@@ -676,6 +677,56 @@ static void qemuMonitorJSONHandleVNCDisconnect(qemuMonitorPtr mon,
virJSONValueP
int
+qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
+ const char *cmd_str,
+ int scm_fd,
+ char **reply_str)
+{
+ virJSONValuePtr cmd = NULL;
+ virJSONValuePtr reply = NULL;
+ virJSONValuePtr obj;
+ int ret = -1;
+
+ cmd = qemuMonitorJSONMakeCommand("human-monitor-command",
+ "s:command-line", cmd_str,
+ NULL);
+
+ if (!cmd || qemuMonitorJSONCommandWithFd(mon, cmd, scm_fd, &reply) < 0)
+ goto cleanup;
+
+ if (qemuMonitorJSONCheckError(cmd, reply))
+ goto cleanup;
+
+ if (!(obj = virJSONValueObjectGet(reply, "return"))) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("human monitor command was missing return data"));
+ goto cleanup;
+ }
+
+ if (reply_str) {
+ const char *data;
+
+ if ((data = virJSONValueGetString(obj)))
+ *reply_str = strdup(data);
+ else
+ *reply_str = strdup("");
+
+ if (!*reply_str) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
+
+int
qemuMonitorJSONSetCapabilities(qemuMonitorPtr mon)
{
int ret;
@@ -2401,11 +2452,18 @@ int qemuMonitorJSONCreateSnapshot(qemuMonitorPtr mon, const char
*name)
if (!cmd)
return -1;
- ret = qemuMonitorJSONCommand(mon, cmd, &reply);
+ if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+ goto cleanup;
- if (ret == 0)
- ret = qemuMonitorJSONCheckError(cmd, reply);
+ if (qemuMonitorJSONHasError(reply, "CommandNotFound")) {
+ VIR_DEBUG0("savevm command not found, trying HMP");
+ ret = qemuMonitorTextCreateSnapshot(mon, name);
+ goto cleanup;
+ }
+
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+cleanup:
virJSONValueFree(cmd);
virJSONValueFree(reply);
return ret;
@@ -2464,36 +2522,17 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
virJSONValuePtr reply = NULL;
int ret = -1;
- if (!hmp) {
- cmd = virJSONValueFromString(cmd_str);
+ if (hmp) {
+ return qemuMonitorJSONHumanCommandWithFd(mon, cmd_str, -1, reply_str);
} else {
- cmd = qemuMonitorJSONMakeCommand("human-monitor-command",
- "s:command-line", cmd_str,
- NULL);
- }
-
- if (!cmd)
- return -1;
+ if (!(cmd = virJSONValueFromString(cmd_str)))
+ goto cleanup;
- if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
- goto cleanup;
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ goto cleanup;
- if (!hmp) {
if (!(*reply_str = virJSONValueToString(reply)))
goto cleanup;
- } else if (qemuMonitorJSONCheckError(cmd, reply)) {
- goto cleanup;
- } else {
- const char *data;
- if (!(data = virJSONValueObjectGetString(reply, "return"))) {
- qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("human monitor command was missing return
data"));
- goto cleanup;
- }
- if (!(*reply_str = strdup(data))) {
- virReportOOMError();
- goto cleanup;
- }
}
ret = 0;
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 4ae472a..3e0624d 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -34,6 +34,11 @@ int qemuMonitorJSONIOProcess(qemuMonitorPtr mon,
size_t len,
qemuMonitorMessagePtr msg);
+int qemuMonitorJSONHumanCommandWithFd(qemuMonitorPtr mon,
+ const char *cmd,
+ int scm_fd,
+ char **reply);
+
int qemuMonitorJSONSetCapabilities(qemuMonitorPtr mon);
int qemuMonitorJSONStartCPUs(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 0aed690..6949384 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -259,21 +259,15 @@ qemuMonitorCommandWithHandler(qemuMonitorPtr mon,
return ret;
}
-static int
-qemuMonitorCommandWithFd(qemuMonitorPtr mon,
- const char *cmd,
- int scm_fd,
- char **reply) {
+int
+qemuMonitorTextCommandWithFd(qemuMonitorPtr mon,
+ const char *cmd,
+ int scm_fd,
+ char **reply)
+{
return qemuMonitorCommandWithHandler(mon, cmd, NULL, NULL, scm_fd, reply);
}
-static int
-qemuMonitorCommand(qemuMonitorPtr mon,
- const char *cmd,
- char **reply) {
- return qemuMonitorCommandWithFd(mon, cmd, -1, reply);
-}
-
static int
qemuMonitorSendDiskPassphrase(qemuMonitorPtr mon,
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index b29dbcc..e6b27ec 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -35,6 +35,11 @@ int qemuMonitorTextIOProcess(qemuMonitorPtr mon,
size_t len,
qemuMonitorMessagePtr msg);
+int qemuMonitorTextCommandWithFd(qemuMonitorPtr mon,
+ const char *cmd,
+ int scm_fd,
+ char **reply);
+
int qemuMonitorTextStartCPUs(qemuMonitorPtr mon,
virConnectPtr conn);
int qemuMonitorTextStopCPUs(qemuMonitorPtr mon);
--
1.7.4.1