提交 08cc14f7 编写于 作者: E Eric Blake

blockjob: hoist bandwidth scaling out of monitor code

qemu treats blockjob bandwidth as a 64-bit number, in the units
of bytes/second.  But we stupidly modeled block job bandwidth
after migration bandwidth, which in turn was an 'unsigned long'
and therefore subject to 32-bit vs. 64-bit interpretations, and
with a scale of MiB/s.  Our code already has to convert between
the two scales, and report overflow as appropriate; although
this conversion currently lives in the monitor code.  In fact,
our conversion code limited things to 63 bits, because we
checked against LLONG_MAX and reject what would be negative
bandwidth if treated as signed.

On the bright side, our use of MiB/s means that even with a
32-bit unsigned long, we still have no problem representing a
bandwidth of 2GiB/s, which is starting to be more feasible as
10-gigabit or even faster interfaces are used.  And once you
get past the physical speeds of existing interfaces, any larger
bandwidth number behaves the same - effectively unlimited.
But on the low side, the granularity of 1MiB/s tuning is rather
coarse.  So the new virDomainBlockJob API decided to go with
a direct 64-bit bytes/sec number instead of the scaled number
that prior blockjob APIs had used.  But there is no point in
rounding this number to MiB/s just to scale it back to bytes/s
for handing to qemu.

In order to make future code sharing possible between the old
virDomainBlockRebase and the new virDomainBlockCopy, this patch
moves the scaling and overflow detection into the driver code.
Several of the block job calls that can set speed are fed
through a common interface, so it was easier to adjust all block
jobs at once, for consistency.  This patch is just code motion;
there should be no user-visible change in behavior.

* src/qemu/qemu_monitor.h (qemuMonitorBlockJob)
(qemuMonitorBlockCommit, qemuMonitorDriveMirror): Change
parameter type and scale.
* src/qemu/qemu_monitor.c (qemuMonitorBlockJob)
(qemuMonitorBlockCommit, qemuMonitorDriveMirror): Move scaling
and overflow detection...
* src/qemu/qemu_driver.c (qemuDomainBlockJobImpl)
(qemuDomainBlockRebase, qemuDomainBlockCommit): ...here.
(qemuDomainBlockCopy): Use bytes/sec.
Signed-off-by: NEric Blake <eblake@redhat.com>
上级 ced81365
...@@ -14989,6 +14989,8 @@ qemuDomainBlockPivot(virConnectPtr conn, ...@@ -14989,6 +14989,8 @@ qemuDomainBlockPivot(virConnectPtr conn,
return ret; return ret;
} }
/* bandwidth in MiB/s per public API */
static int static int
qemuDomainBlockJobImpl(virDomainObjPtr vm, qemuDomainBlockJobImpl(virDomainObjPtr vm,
virConnectPtr conn, virConnectPtr conn,
...@@ -15011,6 +15013,7 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm, ...@@ -15011,6 +15013,7 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm,
char *backingPath = NULL; char *backingPath = NULL;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
bool save = false; bool save = false;
unsigned long long speed = bandwidth;
if (!virDomainObjIsActive(vm)) { if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s", virReportError(VIR_ERR_OPERATION_INVALID, "%s",
...@@ -15122,9 +15125,18 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm, ...@@ -15122,9 +15125,18 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm,
} }
} }
/* Convert bandwidth MiB to bytes */
if (speed > LLONG_MAX >> 20) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth must be less than %llu"),
LLONG_MAX >> 20);
goto endjob;
}
speed <<= 20;
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorBlockJob(priv->mon, device, basePath, backingPath, ret = qemuMonitorBlockJob(priv->mon, device, basePath, backingPath,
bandwidth, mode, async); speed, mode, async);
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
if (ret < 0) { if (ret < 0) {
if (mode == BLOCK_JOB_ABORT && disk->mirror) if (mode == BLOCK_JOB_ABORT && disk->mirror)
...@@ -15326,12 +15338,14 @@ qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path, ...@@ -15326,12 +15338,14 @@ qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
BLOCK_JOB_SPEED, flags); BLOCK_JOB_SPEED, flags);
} }
/* bandwidth in bytes/s */
static int static int
qemuDomainBlockCopy(virDomainObjPtr vm, qemuDomainBlockCopy(virDomainObjPtr vm,
virConnectPtr conn, virConnectPtr conn,
const char *path, const char *path,
const char *dest, const char *format, const char *dest, const char *format,
unsigned long bandwidth, unsigned int flags) unsigned long long bandwidth, unsigned int flags)
{ {
virQEMUDriverPtr driver = conn->privateData; virQEMUDriverPtr driver = conn->privateData;
qemuDomainObjPrivatePtr priv; qemuDomainObjPrivatePtr priv;
...@@ -15514,6 +15528,7 @@ qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base, ...@@ -15514,6 +15528,7 @@ qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
virDomainObjPtr vm; virDomainObjPtr vm;
const char *format = NULL; const char *format = NULL;
int ret = -1; int ret = -1;
unsigned long long speed = bandwidth;
virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW | virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT | VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
...@@ -15537,6 +15552,15 @@ qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base, ...@@ -15537,6 +15552,15 @@ qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY_RAW) if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
format = "raw"; format = "raw";
/* Convert bandwidth MiB to bytes */
if (speed > LLONG_MAX >> 20) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth must be less than %llu"),
LLONG_MAX >> 20);
goto cleanup;
}
speed <<= 20;
/* XXX: If we are doing a shallow copy but not reusing an external /* XXX: If we are doing a shallow copy but not reusing an external
* file, we should attempt to pre-create the destination with a * file, we should attempt to pre-create the destination with a
* relative backing chain instead of qemu's default of absolute */ * relative backing chain instead of qemu's default of absolute */
...@@ -15602,6 +15626,7 @@ qemuDomainBlockCommit(virDomainPtr dom, ...@@ -15602,6 +15626,7 @@ qemuDomainBlockCommit(virDomainPtr dom,
char *basePath = NULL; char *basePath = NULL;
char *backingPath = NULL; char *backingPath = NULL;
virStorageSourcePtr mirror = NULL; virStorageSourcePtr mirror = NULL;
unsigned long long speed = bandwidth;
/* XXX Add support for COMMIT_DELETE */ /* XXX Add support for COMMIT_DELETE */
virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW | virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW |
...@@ -15632,6 +15657,15 @@ qemuDomainBlockCommit(virDomainPtr dom, ...@@ -15632,6 +15657,15 @@ qemuDomainBlockCommit(virDomainPtr dom,
goto endjob; goto endjob;
} }
/* Convert bandwidth MiB to bytes */
if (speed > LLONG_MAX >> 20) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth must be less than %llu"),
LLONG_MAX >> 20);
goto endjob;
}
speed <<= 20;
device = qemuDiskPathToAlias(vm, path, &idx); device = qemuDiskPathToAlias(vm, path, &idx);
if (!device) if (!device)
goto endjob; goto endjob;
...@@ -15766,7 +15800,7 @@ qemuDomainBlockCommit(virDomainPtr dom, ...@@ -15766,7 +15800,7 @@ qemuDomainBlockCommit(virDomainPtr dom,
qemuDomainObjEnterMonitor(driver, vm); qemuDomainObjEnterMonitor(driver, vm);
ret = qemuMonitorBlockCommit(priv->mon, device, ret = qemuMonitorBlockCommit(priv->mon, device,
topPath, basePath, backingPath, topPath, basePath, backingPath,
bandwidth); speed);
qemuDomainObjExitMonitor(driver, vm); qemuDomainObjExitMonitor(driver, vm);
if (mirror) { if (mirror) {
......
...@@ -3178,33 +3178,21 @@ qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions, ...@@ -3178,33 +3178,21 @@ qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions,
return ret; return ret;
} }
/* Start a drive-mirror block job. bandwidth is in MiB/sec. */ /* Start a drive-mirror block job. bandwidth is in bytes/sec. */
int int
qemuMonitorDriveMirror(qemuMonitorPtr mon, qemuMonitorDriveMirror(qemuMonitorPtr mon,
const char *device, const char *file, const char *device, const char *file,
const char *format, unsigned long bandwidth, const char *format, unsigned long long bandwidth,
unsigned int flags) unsigned int flags)
{ {
int ret = -1; int ret = -1;
unsigned long long speed;
VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s, bandwidth=%ld, " VIR_DEBUG("mon=%p, device=%s, file=%s, format=%s, bandwidth=%lld, "
"flags=%x", "flags=%x",
mon, device, file, NULLSTR(format), bandwidth, flags); mon, device, file, NULLSTR(format), bandwidth, flags);
/* Convert bandwidth MiB to bytes - unfortunately the JSON QMP protocol is
* limited to LLONG_MAX also for unsigned values */
speed = bandwidth;
if (speed > LLONG_MAX >> 20) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth must be less than %llu"),
LLONG_MAX >> 20);
return -1;
}
speed <<= 20;
if (mon->json) if (mon->json)
ret = qemuMonitorJSONDriveMirror(mon, device, file, format, speed, ret = qemuMonitorJSONDriveMirror(mon, device, file, format, bandwidth,
flags); flags);
else else
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
...@@ -3228,33 +3216,22 @@ qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions) ...@@ -3228,33 +3216,22 @@ qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
return ret; return ret;
} }
/* Start a block-commit block job. bandwidth is in MiB/sec. */ /* Start a block-commit block job. bandwidth is in bytes/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,
const char *backingName, const char *backingName,
unsigned long bandwidth) unsigned long long bandwidth)
{ {
int ret = -1; int ret = -1;
unsigned long long speed;
VIR_DEBUG("mon=%p, device=%s, top=%s, base=%s, backingName=%s, bandwidth=%lu", VIR_DEBUG("mon=%p, device=%s, top=%s, base=%s, backingName=%s, "
"bandwidth=%llu",
mon, device, top, base, NULLSTR(backingName), bandwidth); mon, device, top, base, NULLSTR(backingName), bandwidth);
/* Convert bandwidth MiB to bytes - unfortunately the JSON QMP protocol is
* limited to LLONG_MAX also for unsigned values */
speed = bandwidth;
if (speed > LLONG_MAX >> 20) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth must be less than %llu"),
LLONG_MAX >> 20);
return -1;
}
speed <<= 20;
if (mon->json) if (mon->json)
ret = qemuMonitorJSONBlockCommit(mon, device, top, base, ret = qemuMonitorJSONBlockCommit(mon, device, top, base,
backingName, speed); backingName, bandwidth);
else else
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("block-commit requires JSON monitor")); _("block-commit requires JSON monitor"));
...@@ -3359,38 +3336,26 @@ int qemuMonitorScreendump(qemuMonitorPtr mon, ...@@ -3359,38 +3336,26 @@ int qemuMonitorScreendump(qemuMonitorPtr mon,
return ret; return ret;
} }
/* bandwidth is in MiB/sec */ /* bandwidth is in bytes/sec */
int int
qemuMonitorBlockJob(qemuMonitorPtr mon, qemuMonitorBlockJob(qemuMonitorPtr mon,
const char *device, const char *device,
const char *base, const char *base,
const char *backingName, const char *backingName,
unsigned long bandwidth, unsigned long long bandwidth,
qemuMonitorBlockJobCmd mode, qemuMonitorBlockJobCmd mode,
bool modern) bool modern)
{ {
int ret = -1; int ret = -1;
unsigned long long speed;
VIR_DEBUG("mon=%p, device=%s, base=%s, backingName=%s, bandwidth=%luM, " VIR_DEBUG("mon=%p, device=%s, base=%s, backingName=%s, bandwidth=%lluB, "
"mode=%o, modern=%d", "mode=%o, modern=%d",
mon, device, NULLSTR(base), NULLSTR(backingName), mon, device, NULLSTR(base), NULLSTR(backingName),
bandwidth, mode, modern); bandwidth, mode, modern);
/* Convert bandwidth MiB to bytes - unfortunately the JSON QMP protocol is
* limited to LLONG_MAX also for unsigned values */
speed = bandwidth;
if (speed > LLONG_MAX >> 20) {
virReportError(VIR_ERR_OVERFLOW,
_("bandwidth must be less than %llu"),
LLONG_MAX >> 20);
return -1;
}
speed <<= 20;
if (mon->json) if (mon->json)
ret = qemuMonitorJSONBlockJob(mon, device, base, backingName, ret = qemuMonitorJSONBlockJob(mon, device, base, backingName,
speed, mode, modern); bandwidth, mode, modern);
else else
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("block jobs require JSON monitor")); _("block jobs require JSON monitor"));
......
...@@ -649,7 +649,7 @@ int qemuMonitorDriveMirror(qemuMonitorPtr mon, ...@@ -649,7 +649,7 @@ int qemuMonitorDriveMirror(qemuMonitorPtr mon,
const char *device, const char *device,
const char *file, const char *file,
const char *format, const char *format,
unsigned long bandwidth, unsigned long long bandwidth,
unsigned int flags) unsigned int flags)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
int qemuMonitorDrivePivot(qemuMonitorPtr mon, int qemuMonitorDrivePivot(qemuMonitorPtr mon,
...@@ -663,7 +663,7 @@ int qemuMonitorBlockCommit(qemuMonitorPtr mon, ...@@ -663,7 +663,7 @@ int qemuMonitorBlockCommit(qemuMonitorPtr mon,
const char *top, const char *top,
const char *base, const char *base,
const char *backingName, const char *backingName,
unsigned long bandwidth) unsigned long long bandwidth)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
ATTRIBUTE_NONNULL(4); ATTRIBUTE_NONNULL(4);
bool qemuMonitorSupportsActiveCommit(qemuMonitorPtr mon); bool qemuMonitorSupportsActiveCommit(qemuMonitorPtr mon);
...@@ -693,7 +693,7 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon, ...@@ -693,7 +693,7 @@ int qemuMonitorBlockJob(qemuMonitorPtr mon,
const char *device, const char *device,
const char *base, const char *base,
const char *backingName, const char *backingName,
unsigned long bandwidth, unsigned long long bandwidth,
qemuMonitorBlockJobCmd mode, qemuMonitorBlockJobCmd mode,
bool modern) bool modern)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册