The new block copy storage migration sequence requires new monitor
commands: adding just 'drive-mirror' allows live copy, and also adding
'drive-reopen' allows live migration. Both commands have been
proposed[1] for qemu 1.1, although as of the writing of this commit
message, it appears that drive-mirror might make it, but drive-reopen
will probably be delayed to qemu 1.2. There is consensus that the
libvirt API virDomainBlockRebase as already committed for 0.9.12 is
flexible enough to expose whatever qemu will eventually let us do,
even if the initial libvirt 0.9.12 driver for qemu can't expose the
full power of the API; also, at least RHEL 6.3 will probably be
backporting an early version of drive-reopen under the name
__com.redhat_drive-reopen, where the difference in naming will let us
cater to any minor differences in the monitor command interface while
still preserving the libvirt API at whatever point upstream qemu
commits to the monitor commands. This patch assumes the bare minimum
needed for live migration, but uses separate feature bits in case
qemu 1.1 ends up giving us only live copy.
[
1]https://lists.gnu.org/archive/html/qemu-devel/2012-04/msg01630.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.
(qemuMonitorJSONDiskSnapshot): Fix formatting issues.
(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.
---
v6: update commit message to point to newer qemu threads, fix
outdated comment in code
src/qemu/qemu_capabilities.c | 3 ++
src/qemu/qemu_capabilities.h | 2 +
src/qemu/qemu_monitor.c | 37 ++++++++++++++++++++++++
src/qemu/qemu_monitor.h | 11 +++++++
src/qemu/qemu_monitor_json.c | 63 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 18 ++++++++++-
6 files changed, 132 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 3d1fb43..c5cb1af 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -161,6 +161,9 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"block-job-async",
"scsi-cd",
"ide-cd",
+ "drive-mirror",
+
+ "drive-reopen", /* 95 */
);
struct qemu_feature_flags {
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 7279cdb..5472a44 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -128,6 +128,8 @@ enum qemuCapsFlags {
QEMU_CAPS_BLOCKJOB_ASYNC = 91, /* qemu 1.1 block-job-cancel */
QEMU_CAPS_SCSI_CD = 92, /* -device scsi-cd */
QEMU_CAPS_IDE_CD = 93, /* -device ide-cd */
+ QEMU_CAPS_DRIVE_MIRROR = 94, /* drive-mirror monitor command */
+ QEMU_CAPS_DRIVE_REOPEN = 95, /* 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 2f66c46..25704e7 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2685,6 +2685,25 @@ qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr
actions,
return ret;
}
+/* Start a drive-mirror block job. */
+int
+qemuMonitorDriveMirror(qemuMonitorPtr mon,
+ const char *device, const char *file,
+ const char *format, unsigned int flags)
+{
+ int ret = -1;
+
+ VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s, flags=%x",
+ mon, device, file, NULLSTR(format), flags);
+
+ if (mon->json)
+ ret = qemuMonitorJSONDriveMirror(mon, device, file, format, flags);
+ else
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%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 +2720,24 @@ 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, NULLSTR(format));
+
+ if (mon->json)
+ ret = qemuMonitorJSONDriveReopen(mon, device, file, format);
+ else
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%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 f3cdcdd..1b4b130 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -510,6 +510,17 @@ int qemuMonitorDiskSnapshot(qemuMonitorPtr mon,
bool reuse);
int qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorDriveMirror(qemuMonitorPtr mon,
+ const char *device,
+ const char *file,
+ const char *format,
+ unsigned int flags)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+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 eb58f13..e0ea505 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -987,6 +987,10 @@ qemuMonitorJSONCheckCommands(qemuMonitorPtr mon,
qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC);
else if (STREQ(name, "block-job-cancel"))
qemuCapsSet(qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC);
+ 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;
@@ -3199,6 +3203,38 @@ cleanup:
}
int
+qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
+ const char *device, const char *file,
+ const char *format, unsigned int flags)
+{
+ int ret = -1;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+ bool shallow = (flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) != 0;
+ bool reuse = (flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) != 0;
+
+ cmd = qemuMonitorJSONMakeCommand("drive-mirror",
+ "s:device", device,
+ "s:target", file,
+ "b:full", !shallow,
+ "s:mode",
+ reuse ? "existing" :
"absolute-paths",
+ 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
qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
{
int ret = -1;
@@ -3226,6 +3262,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 aacbb5f..d93c37d 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -230,8 +230,22 @@ 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 qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
+ const char *device,
+ const char *file,
+ const char *format,
+ unsigned int flags)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+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