mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-20 07:59:00 +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",
|
"seamless-migration",
|
||||||
"block-commit",
|
"block-commit",
|
||||||
"vnc",
|
"vnc",
|
||||||
|
|
||||||
|
"drive-mirror", /* 115 */
|
||||||
);
|
);
|
||||||
|
|
||||||
struct _qemuCaps {
|
struct _qemuCaps {
|
||||||
@ -1889,6 +1891,8 @@ qemuCapsProbeQMPCommands(qemuCapsPtr caps,
|
|||||||
qemuCapsSet(caps, QEMU_CAPS_BLOCK_COMMIT);
|
qemuCapsSet(caps, QEMU_CAPS_BLOCK_COMMIT);
|
||||||
else if (STREQ(name, "query-vnc"))
|
else if (STREQ(name, "query-vnc"))
|
||||||
qemuCapsSet(caps, QEMU_CAPS_VNC);
|
qemuCapsSet(caps, QEMU_CAPS_VNC);
|
||||||
|
else if (STREQ(name, "drive-mirror"))
|
||||||
|
qemuCapsSet(caps, QEMU_CAPS_DRIVE_MIRROR);
|
||||||
VIR_FREE(name);
|
VIR_FREE(name);
|
||||||
}
|
}
|
||||||
VIR_FREE(commands);
|
VIR_FREE(commands);
|
||||||
|
@ -152,6 +152,7 @@ enum qemuCapsFlags {
|
|||||||
QEMU_CAPS_SEAMLESS_MIGRATION = 112, /* seamless-migration for SPICE */
|
QEMU_CAPS_SEAMLESS_MIGRATION = 112, /* seamless-migration for SPICE */
|
||||||
QEMU_CAPS_BLOCK_COMMIT = 113, /* block-commit */
|
QEMU_CAPS_BLOCK_COMMIT = 113, /* block-commit */
|
||||||
QEMU_CAPS_VNC = 114, /* Is -vnc available? */
|
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 */
|
QEMU_CAPS_LAST, /* this must always be the last item */
|
||||||
};
|
};
|
||||||
|
@ -2780,6 +2780,39 @@ qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions,
|
|||||||
return ret;
|
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. */
|
/* Use the transaction QMP command to run atomic snapshot commands. */
|
||||||
int
|
int
|
||||||
qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
|
qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
|
||||||
@ -2796,7 +2829,7 @@ qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
|
|||||||
return ret;
|
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
|
int
|
||||||
qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
|
qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
|
||||||
const char *top, const char *base,
|
const char *top, const char *base,
|
||||||
@ -2826,6 +2859,25 @@ qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
|
|||||||
return ret;
|
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,
|
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
|
||||||
const char *cmd,
|
const char *cmd,
|
||||||
char **reply,
|
char **reply,
|
||||||
@ -2893,7 +2945,7 @@ int qemuMonitorScreendump(qemuMonitorPtr mon,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* bandwidth is in MB/sec */
|
/* bandwidth is in MiB/sec */
|
||||||
int qemuMonitorBlockJob(qemuMonitorPtr mon,
|
int qemuMonitorBlockJob(qemuMonitorPtr mon,
|
||||||
const char *device,
|
const char *device,
|
||||||
const char *base,
|
const char *base,
|
||||||
|
@ -523,6 +523,18 @@ int qemuMonitorDiskSnapshot(qemuMonitorPtr mon,
|
|||||||
bool reuse);
|
bool reuse);
|
||||||
int qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
|
int qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
|
||||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
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,
|
int qemuMonitorBlockCommit(qemuMonitorPtr mon,
|
||||||
const char *device,
|
const char *device,
|
||||||
|
@ -3249,6 +3249,41 @@ cleanup:
|
|||||||
return ret;
|
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
|
int
|
||||||
qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
|
qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
|
||||||
{
|
{
|
||||||
@ -3306,6 +3341,31 @@ cleanup:
|
|||||||
return ret;
|
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,
|
int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
|
||||||
const char *cmd_str,
|
const char *cmd_str,
|
||||||
|
@ -232,8 +232,23 @@ int qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon,
|
|||||||
const char *device,
|
const char *device,
|
||||||
const char *file,
|
const char *file,
|
||||||
const char *format,
|
const char *format,
|
||||||
bool reuse);
|
bool reuse)
|
||||||
int qemuMonitorJSONTransaction(qemuMonitorPtr mon, virJSONValuePtr actions);
|
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,
|
int qemuMonitorJSONBlockCommit(qemuMonitorPtr mon,
|
||||||
const char *device,
|
const char *device,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user