No one uses this yet, but it will be important once
virDomainSnapshotCreateXML learns a VIR_DOMAIN_SNAPSHOT_DISK_ONLY
flag, and the xml allows passing in the new file names.
* src/qemu/qemu_monitor.h (qemuMonitorDiskSnapshot): New prototype.
* src/qemu/qemu_monitor_text.h (qemuMonitorTextDiskSnapshot):
Likewise.
* src/qemu/qemu_monitor_json.h (qemuMonitorJSONDiskSnapshot):
Likewise.
* src/qemu/qemu_monitor.c (qemuMonitorDiskSnapshot): New
function.
* src/qemu/qemu_monitor_json.c (qemuMonitorJSONDiskSnapshot):
Likewise.
---
src/qemu/qemu_monitor.c | 24 ++++++++++++++++++++++++
src/qemu/qemu_monitor.h | 4 ++++
src/qemu/qemu_monitor_json.c | 33 +++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 4 ++++
src/qemu/qemu_monitor_text.c | 40 ++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 4 ++++
6 files changed, 109 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index db6107c..efc49c4 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2391,6 +2391,30 @@ int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char
*name)
return ret;
}
+/* Use the snapshot_blkdev command to convert the existing file for
+ * device into a read-only backing file of a new qcow2 image located
+ * at file. */
+int
+qemuMonitorDiskSnapshot(qemuMonitorPtr mon, const char *device,
+ const char *file)
+{
+ int ret;
+
+ VIR_DEBUG("mon=%p, device=%s, file=%s", mon, device, file);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONDiskSnapshot(mon, device, file);
+ else
+ ret = qemuMonitorTextDiskSnapshot(mon, device, file);
+ return ret;
+}
+
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
const char *cmd,
char **reply,
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index f241c9e..b988a72 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -447,6 +447,10 @@ int qemuMonitorCreateSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name);
+int qemuMonitorDiskSnapshot(qemuMonitorPtr mon,
+ const char *device,
+ const char *file);
+
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
const char *cmd,
char **reply,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 4ceb536..572cf3f 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2703,6 +2703,39 @@ cleanup:
return ret;
}
+int
+qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, const char *device,
+ const char *file)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ cmd = qemuMonitorJSONMakeCommand("snapshot-blkdev-sync",
+ "s:device", device,
+ "s:snapshot-file", file,
+ NULL);
+ if (!cmd)
+ return -1;
+
+ if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+ goto cleanup;
+
+ if (qemuMonitorJSONHasError(reply, "CommandNotFound") &&
+ qemuMonitorCheckHMP(mon, "snapshot_blkdev")) {
+ VIR_DEBUG("snapshot-blkdev-sync command not found, trying HMP");
+ ret = qemuMonitorTextDiskSnapshot(mon, device, file);
+ goto cleanup;
+ }
+
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
const char *cmd_str,
char **reply_str,
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 9512793..a538e9f 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -210,6 +210,10 @@ int qemuMonitorJSONCreateSnapshot(qemuMonitorPtr mon, const char
*name);
int qemuMonitorJSONLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorJSONDeleteSnapshot(qemuMonitorPtr mon, const char *name);
+int qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon,
+ const char *device,
+ const char *file);
+
int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
const char *cmd_str,
char **reply_str,
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 854ee7f..0e4bb72 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2791,6 +2791,46 @@ cleanup:
return ret;
}
+int
+qemuMonitorTextDiskSnapshot(qemuMonitorPtr mon, const char *device,
+ const char *file)
+{
+ char *cmd = NULL;
+ char *reply = NULL;
+ int ret = -1;
+ char *safename;
+
+ if (!(safename = qemuMonitorEscapeArg(file)) ||
+ virAsprintf(&cmd, "snapshot_blkdev %s \"%s\"", device,
safename) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (qemuMonitorHMPCommand(mon, cmd, &reply)) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("failed to take snapshot using command
'%s'"), cmd);
+ goto cleanup;
+ }
+
+ if (strstr(reply, "error while creating qcow2") != NULL) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to take snapshot: %s"), reply);
+ goto cleanup;
+ }
+
+ /* XXX Should we scrape 'info block' output for
+ * 'device:... file=name backing_file=oldname' to make sure the
+ * command succeeded? */
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(safename);
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ return ret;
+}
+
int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
char **reply)
{
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index b250738..55f78b4 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -206,6 +206,10 @@ int qemuMonitorTextCreateSnapshot(qemuMonitorPtr mon, const char
*name);
int qemuMonitorTextLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name);
+int qemuMonitorTextDiskSnapshot(qemuMonitorPtr mon,
+ const char *device,
+ const char *file);
+
int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
char **reply);
--
1.7.4.4