The new block copy storage migration sequence requires both the
'drive-mirror' action in 'transaction' (present if the
'drive-mirror'
standalone monitor command also exists) and the 'drive-reopen' monitor
command (it would be nice if that were also part of a 'transaction',
but the initial qemu implementation has it standalone only).
As of this[1] qemu email, both commands have been proposed but not yet
incorporated into the tree, so there is a risk that qemu 1.1 will
not have these commands, or will have something subtly different.
[
1]https://lists.gnu.org/archive/html/qemu-devel/2012-03/msg01524.html
* src/qemu/qemu_capabilities.h (QEMU_CAPS_DRIVE_MIRROR)
(QEMU_CAPS_DRIVE_REOPEN): New bits.
* src/qemu/qemu_capabilities.c (qemuCaps): Name them.
* src/qemu/qemu_monitor_json.c (qemuMonitorJSONCheckCommands): Set
them.
(qemuMonitorJSONDriveMirror, qemuMonitorDriveReopen): New functions.
* src/qemu/qemu_monitor_json.h (qemuMonitorJSONDriveMirror)
(qemuMonitorDriveReopen): Declare them.
* src/qemu/qemu_monitor.c (qemuMonitorDriveMirror)
(qemuMonitorDriveReopen): New passthroughs.
* src/qemu/qemu_monitor.h (qemuMonitorDriveMirror)
(qemuMonitorDriveReopen): Declare them.
---
src/qemu/qemu_capabilities.c | 3 +
src/qemu/qemu_capabilities.h | 2 +
src/qemu/qemu_monitor.c | 50 ++++++++++++++++++++++++
src/qemu/qemu_monitor.h | 21 ++++++++++
src/qemu/qemu_monitor_json.c | 86 ++++++++++++++++++++++++++++++++++++++---
src/qemu/qemu_monitor_json.h | 19 ++++++++-
6 files changed, 172 insertions(+), 9 deletions(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 0e09d6d..1938ae4 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -156,6 +156,9 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"scsi-disk.channel",
"scsi-block",
"transaction",
+
+ "drive-mirror", /* 90 */
+ "drive-reopen",
);
struct qemu_feature_flags {
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 78cdbe0..405bf2a 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -124,6 +124,8 @@ enum qemuCapsFlags {
QEMU_CAPS_SCSI_DISK_CHANNEL = 87, /* Is scsi-disk.channel available? */
QEMU_CAPS_SCSI_BLOCK = 88, /* -device scsi-block */
QEMU_CAPS_TRANSACTION = 89, /* transaction monitor command */
+ QEMU_CAPS_DRIVE_MIRROR = 90, /* drive-mirror monitor command */
+ QEMU_CAPS_DRIVE_REOPEN = 91, /* drive-reopen monitor command */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index e1a8d4c..75694b7 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2685,6 +2685,32 @@ qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr
actions,
return ret;
}
+/* Add the drive-mirror action to a transaction. */
+int
+qemuMonitorDriveMirror(qemuMonitorPtr mon, virJSONValuePtr actions,
+ const char *device, const char *file,
+ const char *format, int mode)
+{
+ int ret = -1;
+
+ VIR_DEBUG("mon=%p, actions=%p, device=%s, file=%s, format=%s, mode=%o",
+ mon, actions, device, file, format, mode);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONDriveMirror(mon, actions, device, file, format,
+ mode);
+ else
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("drive-mirror requires JSON monitor"));
+ return ret;
+}
+
/* Use the transaction QMP command to run atomic snapshot commands. */
int
qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
@@ -2701,6 +2727,30 @@ qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr
actions)
return ret;
}
+/* Use the drive-reopen monitor command. */
+int
+qemuMonitorDriveReopen(qemuMonitorPtr mon, const char *device,
+ const char *file, const char *format)
+{
+ int ret = -1;
+
+ VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s",
+ mon, device, file, format);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONDriveReopen(mon, device, file, format);
+ else
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("drive-reopen requires JSON monitor"));
+ 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 2e6ac79..a432b6f 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -508,8 +508,29 @@ int qemuMonitorDiskSnapshot(qemuMonitorPtr mon,
const char *file,
const char *format,
bool reuse);
+
+typedef enum {
+ QEMU_MONITOR_DRIVE_MIRROR_ABSOLUTE,
+ QEMU_MONITOR_DRIVE_MIRROR_EXISTING,
+ QEMU_MONITOR_DRIVE_MIRROR_NO_BACKING,
+
+ QEMU_MONITOR_DRIVE_MIRROR_LAST
+} qemuMonitorDriveMirrorMode;
+
+int qemuMonitorDriveMirror(qemuMonitorPtr mon,
+ virJSONValuePtr actions,
+ const char *device,
+ const char *file,
+ const char *format,
+ int mode)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
int qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorDriveReopen(qemuMonitorPtr mon,
+ const char *device,
+ const char *file,
+ const char *format)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
const char *cmd,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 13c35c8..ffa6c0c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -967,12 +967,14 @@ qemuMonitorJSONCheckCommands(qemuMonitorPtr mon,
if (STREQ(name, "human-monitor-command"))
*json_hmp = 1;
-
- if (STREQ(name, "system_wakeup"))
+ else if (STREQ(name, "system_wakeup"))
qemuCapsSet(qemuCaps, QEMU_CAPS_WAKEUP);
-
- if (STREQ(name, "transaction"))
+ else if (STREQ(name, "transaction"))
qemuCapsSet(qemuCaps, QEMU_CAPS_TRANSACTION);
+ else if (STREQ(name, "drive-mirror"))
+ qemuCapsSet(qemuCaps, QEMU_CAPS_DRIVE_MIRROR);
+ else if (STREQ(name, "drive-reopen"))
+ qemuCapsSet(qemuCaps, QEMU_CAPS_DRIVE_REOPEN);
}
ret = 0;
@@ -3142,7 +3144,7 @@ qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr
actions,
const char *device, const char *file,
const char *format, bool reuse)
{
- int ret;
+ int ret = -1;
virJSONValuePtr cmd;
virJSONValuePtr reply = NULL;
@@ -3160,14 +3162,13 @@ qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr
actions,
if (actions) {
if (virJSONValueArrayAppend(actions, cmd) < 0) {
virReportOOMError();
- ret = -1;
} else {
ret = 0;
cmd = NULL;
}
} else {
if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
- goto cleanup;
+ goto cleanup;
if (qemuMonitorJSONHasError(reply, "CommandNotFound") &&
qemuMonitorCheckHMP(mon, "snapshot_blkdev")) {
@@ -3185,6 +3186,50 @@ cleanup:
return ret;
}
+VIR_ENUM_DECL(qemuMonitorDriveMirror)
+VIR_ENUM_IMPL(qemuMonitorDriveMirror, QEMU_MONITOR_DRIVE_MIRROR_LAST,
+ "absolute-paths", "exsisting",
"no-backing-file");
+
+int
+qemuMonitorJSONDriveMirror(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+ virJSONValuePtr actions,
+ const char *device, const char *file,
+ const char *format, int mode)
+{
+ int ret = -1;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ cmd = qemuMonitorJSONMakeCommandRaw(actions != NULL,
+ "drive-mirror",
+ "s:device", device,
+ "s:target", file,
+ "s:mode",
+ qemuMonitorDriveMirrorTypeToString(mode),
+ format ? "s:format" : NULL, format,
+ NULL);
+ if (!cmd)
+ return -1;
+
+ if (actions) {
+ if (virJSONValueArrayAppend(actions, cmd) < 0) {
+ virReportOOMError();
+ } else {
+ cmd = NULL;
+ ret = 0;
+ }
+ } else {
+ if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+ goto cleanup;
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+ }
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
int
qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
{
@@ -3213,6 +3258,33 @@ cleanup:
return ret;
}
+int
+qemuMonitorJSONDriveReopen(qemuMonitorPtr mon, const char *device,
+ const char *file, const char *format)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ cmd = qemuMonitorJSONMakeCommand("drive-reopen",
+ "s:device", device,
+ "s:new-image-file", file,
+ format ? "s:format" : NULL, format,
+ NULL);
+ if (!cmd)
+ return -1;
+
+ if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+ 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 a0f67aa..136c0f3 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -230,8 +230,23 @@ int qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon,
const char *device,
const char *file,
const char *format,
- bool reuse);
-int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions);
+ bool reuse)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3)
+ ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
+int qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
+ virJSONValuePtr actions,
+ const char *device,
+ const char *file,
+ const char *format,
+ int mode)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
+int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorJSONDriveReopen(qemuMonitorPtr mon,
+ const char *device,
+ const char *file,
+ const char *format)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
const char *cmd_str,
--
1.7.7.6