[libvirt] [PATCH v3 05/18] blockjob: hoist bandwidth scaling out of monitor code

Peter Krempa pkrempa at redhat.com
Thu Sep 4 15:54:25 UTC 2014


On 08/31/14 06:02, Eric Blake wrote:
> 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.
> 
> 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.
> 
> * 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: Eric Blake <eblake at redhat.com>
> ---
>  src/qemu/qemu_driver.c  | 40 +++++++++++++++++++++++++++++---
>  src/qemu/qemu_monitor.c | 61 +++++++++++--------------------------------------
>  src/qemu/qemu_monitor.h |  6 ++---
>  3 files changed, 53 insertions(+), 54 deletions(-)


> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 4493051..ef35e6a 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -3178,33 +3178,21 @@ qemuMonitorDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions,
>      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
>  qemuMonitorDriveMirror(qemuMonitorPtr mon,
>                         const char *device, const char *file,
> -                       const char *format, unsigned long bandwidth,
> +                       const char *format, unsigned long long bandwidth,
>                         unsigned int flags)
>  {
>      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",
>                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;

I started from bottom, so see at the end for a common comment ...

> -    }
> -    speed <<= 20;
> -
>      if (mon->json)
> -        ret = qemuMonitorJSONDriveMirror(mon, device, file, format, speed,
> +        ret = qemuMonitorJSONDriveMirror(mon, device, file, format, bandwidth,
>                                           flags);
>      else
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> @@ -3228,33 +3216,22 @@ qemuMonitorTransaction(qemuMonitorPtr mon, virJSONValuePtr actions)
>      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
>  qemuMonitorBlockCommit(qemuMonitorPtr mon, const char *device,
>                         const char *top, const char *base,
>                         const char *backingName,
> -                       unsigned long bandwidth)
> +                       unsigned long long bandwidth)
>  {
>      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);
> 
> -    /* 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);

See below ...

> -        return -1;
> -    }
> -    speed <<= 20;
> -
>      if (mon->json)
>          ret = qemuMonitorJSONBlockCommit(mon, device, top, base,
> -                                         backingName, speed);
> +                                         backingName, bandwidth);
>      else
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
>                         _("block-commit requires JSON monitor"));
> @@ -3359,38 +3336,26 @@ int qemuMonitorScreendump(qemuMonitorPtr mon,
>      return ret;
>  }
> 
> -/* bandwidth is in MiB/sec */
> +/* bandwidth is in bytes/sec */
>  int
>  qemuMonitorBlockJob(qemuMonitorPtr mon,
>                      const char *device,
>                      const char *base,
>                      const char *backingName,
> -                    unsigned long bandwidth,
> +                    unsigned long long bandwidth,
>                      qemuMonitorBlockJobCmd mode,
>                      bool modern)
>  {
>      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",
>                mon, device, NULLSTR(base), NULLSTR(backingName),
>                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);

I'd keep the check for if (speed > LLONG_MAX) here to be sure that we
don't pass something between LLONG_MAX and ULLONG_MAX to qemu as it
would be converted to signed by the monitor code.


> -        return -1;
> -    }
> -    speed <<= 20;

Of course this has to be dropped.

> -
>      if (mon->json)
>          ret = qemuMonitorJSONBlockJob(mon, device, base, backingName,
> -                                      speed, mode, modern);
> +                                      bandwidth, mode, modern);
>      else
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
>                         _("block jobs require JSON monitor"));


Possibly we could add a new conversion option to
qemuMonitorJSONMakeCommand that would check and reject numbers between
LLONG_MAX and ULLONG_MAX rather than converting them to signed silently...

If you decide against the option above I ACK this with the bandwidth
check added in the monitor APIs.

Peter

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20140904/de4994ed/attachment-0001.sig>


More information about the libvir-list mailing list