blockjob: add qemu capabilities related to block jobs

Upstream qemu 1.3 is adding two new monitor commands, 'drive-mirror'
and 'block-job-complete'[1], which can drive live block copy and
storage migration.  [Additionally, RHEL 6.3 had backported an earlier
version of most of the same functionality, but under the names
'__com.redhat_drive-mirror' and '__com.redhat_drive-reopen' and with
slightly different JSON arguments, and has been using patches similar
to these upstream patches for several months now.]

The libvirt API virDomainBlockRebase as already committed for 0.9.12
is flexible enough to expose the basics of block copy, but some
additional features in the 'drive-mirror' qemu command, such as
setting error policy, setting granularity, or using a persistent
bitmap, may later require a new libvirt API virDomainBlockCopy.  I
will wait to add that API until we know more about what qemu 1.3
will finally provide.

This patch caters only to the upstream qemu 1.3 interface, although
I have proven that the changes for RHEL 6.3 can be isolated to
just qemu_monitor_json.c, and the rest of this series will
gracefully handle either interface once the JSON differences are
papered over in a downstream patch.

For consistency with other block job commands, libvirt must handle
the bandwidth argument as MiB/sec from the user, even though qemu
exposes the speed argument as bytes/sec; then again, qemu rounds
up to cluster size internally, so using MiB hides the worst effects
of that rounding if you pass small numbers.

[1]https://lists.gnu.org/archive/html/qemu-devel/2012-10/msg04123.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, qemuMonitorDrivePivot): New functions.
* src/qemu/qemu_monitor_json.h (qemuMonitorJSONDriveMirror)
(qemuMonitorDrivePivot): Declare them.
* src/qemu/qemu_monitor.c (qemuMonitorDriveMirror)
(qemuMonitorDrivePivot): New passthroughs.
* src/qemu/qemu_monitor.h (qemuMonitorDriveMirror)
(qemuMonitorDrivePivot): Declare them.
This commit is contained in:
Eric Blake 2012-09-28 17:29:53 -06:00
parent def31e4c58
commit 6d264c9182
6 changed files with 148 additions and 4 deletions

View File

@ -189,6 +189,8 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"seamless-migration",
"block-commit",
"vnc",
"drive-mirror", /* 115 */
);
struct _qemuCaps {
@ -1889,6 +1891,8 @@ qemuCapsProbeQMPCommands(qemuCapsPtr caps,
qemuCapsSet(caps, QEMU_CAPS_BLOCK_COMMIT);
else if (STREQ(name, "query-vnc"))
qemuCapsSet(caps, QEMU_CAPS_VNC);
else if (STREQ(name, "drive-mirror"))
qemuCapsSet(caps, QEMU_CAPS_DRIVE_MIRROR);
VIR_FREE(name);
}
VIR_FREE(commands);

View File

@ -152,6 +152,7 @@ enum qemuCapsFlags {
QEMU_CAPS_SEAMLESS_MIGRATION = 112, /* seamless-migration for SPICE */
QEMU_CAPS_BLOCK_COMMIT = 113, /* block-commit */
QEMU_CAPS_VNC = 114, /* Is -vnc available? */
QEMU_CAPS_DRIVE_MIRROR = 115, /* drive-mirror monitor command */
QEMU_CAPS_LAST, /* this must always be the last item */
};

View File

@ -2780,6 +2780,39 @@ qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions,
return ret;
}
/* Start a drive-mirror block job. bandwidth is in MiB/sec. */
int
qemuMonitorDriveMirror(qemuMonitorPtr mon,
const char *device, const char *file,
const char *format, unsigned long bandwidth,
unsigned int flags)
{
int ret = -1;
unsigned long long speed;
VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s, bandwidth=%ld, "
"flags=%x",
mon, device, file, NULLSTR(format), bandwidth, flags);
/* Convert bandwidth MiB to bytes */
speed = bandwidth;
if (speed > ULLONG_MAX / 1024 / 1024) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth must be less than %llu"),
ULLONG_MAX / 1024 / 1024);
return -1;
}
speed <<= 20;
if (mon->json)
ret = qemuMonitorJSONDriveMirror(mon, device, file, format, speed,
flags);
else
virReportError(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)
@ -2796,7 +2829,7 @@ qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
return ret;
}
/* Start a block-commit block job. bandwidth is in MB/sec. */
/* Start a block-commit block job. bandwidth is in MiB/sec. */
int
qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
const char *top, const char *base,
@ -2826,6 +2859,25 @@ qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
return ret;
}
/* Use the block-job-complete monitor command to pivot a block copy
* job. */
int
qemuMonitorDrivePivot(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 = qemuMonitorJSONDrivePivot(mon, device, file, format);
else
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("drive pivot requires JSON monitor"));
return ret;
}
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
const char *cmd,
char **reply,
@ -2893,7 +2945,7 @@ int qemuMonitorScreendump(qemuMonitorPtr mon,
return ret;
}
/* bandwidth is in MB/sec */
/* bandwidth is in MiB/sec */
int qemuMonitorBlockJob(qemuMonitorPtr mon,
const char *device,
const char *base,

View File

@ -523,6 +523,18 @@ 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 long bandwidth,
unsigned int flags)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorDrivePivot(qemuMonitorPtr mon,
const char *device,
const char *file,
const char *format)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorBlockCommit(qemuMonitorPtr mon,
const char *device,

View File

@ -3249,6 +3249,41 @@ cleanup:
return ret;
}
/* speed is in bytes/sec */
int
qemuMonitorJSONDriveMirror(qemuMonitorPtr mon,
const char *device, const char *file,
const char *format, unsigned long long speed,
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,
"U:speed", speed,
"s:sync", shallow ? "top" : "full",
"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)
{
@ -3306,6 +3341,31 @@ cleanup:
return ret;
}
int
qemuMonitorJSONDrivePivot(qemuMonitorPtr mon, const char *device,
const char *file ATTRIBUTE_UNUSED,
const char *format ATTRIBUTE_UNUSED)
{
int ret;
virJSONValuePtr cmd;
virJSONValuePtr reply = NULL;
cmd = qemuMonitorJSONMakeCommand("block-job-complete",
"s:device", device,
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,

View File

@ -232,8 +232,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 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 long long speed,
unsigned int flags)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorJSONDrivePivot(qemuMonitorPtr mon,
const char *device,
const char *file,
const char *format)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorJSONBlockCommit(qemuMonitorPtr mon,
const char *device,