1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-08-30 05:50:08 +03:00

blockjob: allow finer bandwidth tuning for query

While reviewing the new virDomainBlockCopy API, Peter Krempa
pointed out that our existing design of using MiB/s for block
job bandwidth is rather coarse, especially since qemu tracks
it in bytes/s; so virDomainBlockCopy only accepts bytes/s.
But once the new API is implemented for qemu, we will be in
the situation where it is possible to set a value that cannot
be accurately reflected back to the user, because the existing
virDomainGetBlockJobInfo defaults to the coarser units.

Fortunately, we have an escape hatch; and one that has already
served us well in the past: we can use the flags argument to
specify which scale to use (see virDomainBlockResize for prior
art).  This patch fixes the query side of the API; made easier
by previous patches that split the query side out from the
modification code.  Later patches will address the virsh
interface, as well retrofitting all other blockjob APIs to
also accept a flag for toggling bandwidth units.

* include/libvirt/libvirt.h.in (_virDomainBlockJobInfo)
(VIR_DOMAIN_BLOCK_COPY_BANDWIDTH): Document sizing issues.
(virDomainBlockJobInfoFlags): New enum.
* src/libvirt.c (virDomainGetBlockJobInfo): Document new flag.
* src/qemu/qemu_monitor.h (qemuMonitorBlockJobInfo): Add parameter.
* src/qemu/qemu_monitor.c (qemuMonitorBlockJobInfo): Likewise.
* src/qemu/qemu_monitor_json.h (qemuMonitorJSONBlockJobInfo):
Likewise.
* src/qemu/qemu_monitor_json.c (qemuMonitorJSONBlockJobInfo)
(qemuMonitorJSONGetBlockJobInfoOne): Likewise. Don't scale here.
* src/qemu/qemu_migration.c (qemuMigrationDriveMirror): Update
callers.
* src/qemu/qemu_driver.c (qemuDomainBlockPivot)
(qemuDomainBlockJobImpl): Likewise.
(qemuDomainGetBlockJobInfo): Likewise, and support new flag.

Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Eric Blake
2014-08-27 14:04:36 -06:00
parent fcbeb2e9d1
commit db33cc2494
8 changed files with 70 additions and 32 deletions

View File

@ -2585,13 +2585,23 @@ typedef enum {
VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT = 1 << 1, VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT = 1 << 1,
} virDomainBlockJobAbortFlags; } virDomainBlockJobAbortFlags;
int virDomainBlockJobAbort(virDomainPtr dom, const char *disk,
unsigned int flags);
/* Flags for use with virDomainGetBlockJobInfo */
typedef enum {
VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES = 1 << 0, /* bandwidth in bytes/s
instead of MiB/s */
} virDomainBlockJobInfoFlags;
/* An iterator for monitoring block job operations */ /* An iterator for monitoring block job operations */
typedef unsigned long long virDomainBlockJobCursor; typedef unsigned long long virDomainBlockJobCursor;
typedef struct _virDomainBlockJobInfo virDomainBlockJobInfo; typedef struct _virDomainBlockJobInfo virDomainBlockJobInfo;
struct _virDomainBlockJobInfo { struct _virDomainBlockJobInfo {
int type; /* virDomainBlockJobType */ int type; /* virDomainBlockJobType */
unsigned long bandwidth; unsigned long bandwidth; /* either bytes/s or MiB/s, according to flags */
/* /*
* The following fields provide an indication of block job progress. @cur * The following fields provide an indication of block job progress. @cur
* indicates the current position and will be between 0 and @end. @end is * indicates the current position and will be between 0 and @end. @end is
@ -2603,11 +2613,10 @@ struct _virDomainBlockJobInfo {
}; };
typedef virDomainBlockJobInfo *virDomainBlockJobInfoPtr; typedef virDomainBlockJobInfo *virDomainBlockJobInfoPtr;
int virDomainBlockJobAbort(virDomainPtr dom, const char *disk, int virDomainGetBlockJobInfo(virDomainPtr dom, const char *disk,
unsigned int flags); virDomainBlockJobInfoPtr info,
int virDomainGetBlockJobInfo(virDomainPtr dom, const char *disk, unsigned int flags);
virDomainBlockJobInfoPtr info,
unsigned int flags);
int virDomainBlockJobSetSpeed(virDomainPtr dom, const char *disk, int virDomainBlockJobSetSpeed(virDomainPtr dom, const char *disk,
unsigned long bandwidth, unsigned int flags); unsigned long bandwidth, unsigned int flags);
@ -2653,13 +2662,16 @@ typedef enum {
* the maximum bandwidth in bytes/s, and is used while getting the * the maximum bandwidth in bytes/s, and is used while getting the
* copy operation into the mirrored phase, with a type of ullong. For * copy operation into the mirrored phase, with a type of ullong. For
* compatibility with virDomainBlockJobSetSpeed(), values larger than * compatibility with virDomainBlockJobSetSpeed(), values larger than
* 2^52 bytes/sec (a 32-bit MiB/s value) may be rejected due to * 2^52 bytes/sec (a 32-bit MiB/s value) may be rejected on input due
* overflow considerations, and hypervisors may further restrict the * to overflow considerations (but do you really have an interface
* set of valid values. Specifying 0 is the same as omitting this * with that much bandwidth?), and values larger than 2^31 bytes/sec
* parameter, to request no bandwidth limiting. Some hypervisors may * may cause overflow problems if queried in bytes/sec. Hypervisors
* lack support for this parameter, while still allowing a subsequent * may further restrict the set of valid values. Specifying 0 is the
* change of bandwidth via virDomainBlockJobSetSpeed(). The actual * same as omitting this parameter, to request no bandwidth limiting.
* speed can be determined with virDomainGetBlockJobInfo(). * Some hypervisors may lack support for this parameter, while still
* allowing a subsequent change of bandwidth via
* virDomainBlockJobSetSpeed(). The actual speed can be determined
* with virDomainGetBlockJobInfo().
*/ */
#define VIR_DOMAIN_BLOCK_COPY_BANDWIDTH "bandwidth" #define VIR_DOMAIN_BLOCK_COPY_BANDWIDTH "bandwidth"

View File

@ -19667,10 +19667,14 @@ virDomainBlockJobAbort(virDomainPtr dom, const char *disk,
* @dom: pointer to domain object * @dom: pointer to domain object
* @disk: path to the block device, or device shorthand * @disk: path to the block device, or device shorthand
* @info: pointer to a virDomainBlockJobInfo structure * @info: pointer to a virDomainBlockJobInfo structure
* @flags: extra flags; not used yet, so callers should always pass 0 * @flags: bitwise-OR of virDomainBlockJobInfoFlags
* *
* Request block job information for the given disk. If an operation is active * Request block job information for the given disk. If an operation is active
* @info will be updated with the current progress. * @info will be updated with the current progress. The units used for the
* bandwidth field of @info depends on @flags. If @flags includes
* VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES, bandwidth is in bytes/second
* (although this mode can risk failure due to overflow, depending on both
* client and server word size); otherwise, the value is rounded up to MiB/s.
* *
* The @disk parameter is either an unambiguous source name of the * The @disk parameter is either an unambiguous source name of the
* block device (the <source file='...'/> sub-element, such as * block device (the <source file='...'/> sub-element, such as

View File

@ -14857,7 +14857,7 @@ qemuDomainBlockPivot(virConnectPtr conn,
/* Probe the status, if needed. */ /* Probe the status, if needed. */
if (!disk->mirrorState) { if (!disk->mirrorState) {
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorBlockJobInfo(priv->mon, device, &info); rc = qemuMonitorBlockJobInfo(priv->mon, device, &info, NULL);
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
if (rc < 0) if (rc < 0)
goto cleanup; goto cleanup;
@ -15180,7 +15180,7 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm,
virDomainBlockJobInfo dummy; virDomainBlockJobInfo dummy;
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorBlockJobInfo(priv->mon, device, &dummy); ret = qemuMonitorBlockJobInfo(priv->mon, device, &dummy, NULL);
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
if (ret <= 0) if (ret <= 0)
@ -15253,8 +15253,9 @@ qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
int idx; int idx;
virDomainDiskDefPtr disk; virDomainDiskDefPtr disk;
int ret = -1; int ret = -1;
unsigned long long bandwidth;
virCheckFlags(0, -1); virCheckFlags(VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES, -1);
if (!(vm = qemuDomObjFromDomain(dom))) if (!(vm = qemuDomObjFromDomain(dom)))
return -1; return -1;
@ -15287,7 +15288,7 @@ qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
disk = vm->def->disks[idx]; disk = vm->def->disks[idx];
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorBlockJobInfo(priv->mon, device, info); ret = qemuMonitorBlockJobInfo(priv->mon, device, info, &bandwidth);
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
if (ret < 0) if (ret < 0)
goto endjob; goto endjob;
@ -15295,6 +15296,17 @@ qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
if (info->type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT && if (info->type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT &&
disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT) disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)
info->type = disk->mirrorJob; info->type = disk->mirrorJob;
if (bandwidth) {
if (!(flags & VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES))
bandwidth = VIR_DIV_UP(bandwidth, 1024 * 1024);
info->bandwidth = bandwidth;
if (info->bandwidth != bandwidth) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth %llu cannot be represented in result"),
bandwidth);
goto endjob;
}
}
/* Snoop block copy operations, so future cancel operations can /* Snoop block copy operations, so future cancel operations can
* avoid checking if pivot is safe. Save the change to XML, but * avoid checking if pivot is safe. Save the change to XML, but

View File

@ -1307,7 +1307,8 @@ qemuMigrationDriveMirror(virQEMUDriverPtr driver,
_("canceled by client")); _("canceled by client"));
goto error; goto error;
} }
mon_ret = qemuMonitorBlockJobInfo(priv->mon, diskAlias, &info); mon_ret = qemuMonitorBlockJobInfo(priv->mon, diskAlias, &info,
NULL);
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
if (mon_ret < 0) if (mon_ret < 0)

View File

@ -3366,14 +3366,16 @@ qemuMonitorBlockJob(qemuMonitorPtr mon,
int int
qemuMonitorBlockJobInfo(qemuMonitorPtr mon, qemuMonitorBlockJobInfo(qemuMonitorPtr mon,
const char *device, const char *device,
virDomainBlockJobInfoPtr info) virDomainBlockJobInfoPtr info,
unsigned long long *bandwidth)
{ {
int ret = -1; int ret = -1;
VIR_DEBUG("mon=%p, device=%s, info=%p", mon, device, info); VIR_DEBUG("mon=%p, device=%s, info=%p, bandwidth=%p",
mon, device, info, bandwidth);
if (mon->json) if (mon->json)
ret = qemuMonitorJSONBlockJobInfo(mon, device, info); ret = qemuMonitorJSONBlockJobInfo(mon, device, info, bandwidth);
else else
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("block jobs require JSON monitor")); _("block jobs require JSON monitor"));

View File

@ -700,7 +700,8 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
int qemuMonitorBlockJobInfo(qemuMonitorPtr mon, int qemuMonitorBlockJobInfo(qemuMonitorPtr mon,
const char *device, const char *device,
virDomainBlockJobInfoPtr info) virDomainBlockJobInfoPtr info,
unsigned long long *bandwidth)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorOpenGraphics(qemuMonitorPtr mon, int qemuMonitorOpenGraphics(qemuMonitorPtr mon,

View File

@ -3706,15 +3706,18 @@ int qemuMonitorJSONScreendump(qemuMonitorPtr mon,
return ret; return ret;
} }
/* Returns -1 on error, 0 if not the right device, 1 if info was populated. */ /* Returns -1 on error, 0 if not the right device, 1 if info was
* populated. However, rather than populate info->bandwidth (which
* might overflow on 32-bit machines), bandwidth is tracked optionally
* on the side. */
static int static int
qemuMonitorJSONGetBlockJobInfoOne(virJSONValuePtr entry, qemuMonitorJSONGetBlockJobInfoOne(virJSONValuePtr entry,
const char *device, const char *device,
virDomainBlockJobInfoPtr info) virDomainBlockJobInfoPtr info,
unsigned long long *bandwidth)
{ {
const char *this_dev; const char *this_dev;
const char *type; const char *type;
unsigned long long speed_bytes;
if ((this_dev = virJSONValueObjectGetString(entry, "device")) == NULL) { if ((this_dev = virJSONValueObjectGetString(entry, "device")) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@ -3739,12 +3742,12 @@ qemuMonitorJSONGetBlockJobInfoOne(virJSONValuePtr entry,
else else
info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN; info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
if (virJSONValueObjectGetNumberUlong(entry, "speed", &speed_bytes) < 0) { if (bandwidth &&
virJSONValueObjectGetNumberUlong(entry, "speed", bandwidth) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("entry was missing 'speed'")); _("entry was missing 'speed'"));
return -1; return -1;
} }
info->bandwidth = speed_bytes / 1024ULL / 1024ULL;
if (virJSONValueObjectGetNumberUlong(entry, "offset", &info->cur) < 0) { if (virJSONValueObjectGetNumberUlong(entry, "offset", &info->cur) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@ -3768,7 +3771,8 @@ qemuMonitorJSONGetBlockJobInfoOne(virJSONValuePtr entry,
int int
qemuMonitorJSONBlockJobInfo(qemuMonitorPtr mon, qemuMonitorJSONBlockJobInfo(qemuMonitorPtr mon,
const char *device, const char *device,
virDomainBlockJobInfoPtr info) virDomainBlockJobInfoPtr info,
unsigned long long *bandwidth)
{ {
virJSONValuePtr cmd = NULL; virJSONValuePtr cmd = NULL;
virJSONValuePtr reply = NULL; virJSONValuePtr reply = NULL;
@ -3809,7 +3813,8 @@ qemuMonitorJSONBlockJobInfo(qemuMonitorPtr mon,
ret = -1; ret = -1;
goto cleanup; goto cleanup;
} }
ret = qemuMonitorJSONGetBlockJobInfoOne(entry, device, info); ret = qemuMonitorJSONGetBlockJobInfoOne(entry, device, info,
bandwidth);
} }
cleanup: cleanup:

View File

@ -291,7 +291,8 @@ int qemuMonitorJSONBlockJob(qemuMonitorPtr mon,
int qemuMonitorJSONBlockJobInfo(qemuMonitorPtr mon, int qemuMonitorJSONBlockJobInfo(qemuMonitorPtr mon,
const char *device, const char *device,
virDomainBlockJobInfoPtr info) virDomainBlockJobInfoPtr info,
unsigned long long *bandwidth)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorJSONSetLink(qemuMonitorPtr mon, int qemuMonitorJSONSetLink(qemuMonitorPtr mon,