mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
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:
parent
def31e4c58
commit
6d264c9182
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user