[Libguestfs] [PATCH nbdkit v2] common: Introduce round up, down; and divide round up functions.

Eric Blake eblake at redhat.com
Mon Sep 17 21:05:10 UTC 2018


On 9/17/18 3:38 PM, Richard W.M. Jones wrote:
> These are used at various places in the code already.  This
> refactoring simply moves them to a common header file and should have
> no other effect.
> ---
>   common/include/rounding.h   | 59 +++++++++++++++++++++++++++++++++++++
>   filters/cache/Makefile.am   |  3 +-
>   filters/cache/cache.c       |  2 +-
>   filters/cow/Makefile.am     |  3 +-
>   filters/cow/cow.c           |  2 +-
>   filters/truncate/truncate.c |  5 ++--
>   6 files changed, 68 insertions(+), 6 deletions(-)
> 

> +/* Round up i to next multiple of n (n must be a power of 2).
> + */
> +#define ROUND_UP(i, n) ({                          \
> +      assert (is_power_of_2 (n));                  \
> +      ((i) + (n) - 1) & ~((n) - 1);                \
> +})

Potential bug: if n is 32-bit unsigned, but i is 64-bit, the bitmask on 
the right half of & will be inappropriately truncated (no sign extension 
is performed).

> +
> +/* Round down i to next multiple of n (n must be a power of 2).
> + */
> +#define ROUND_DOWN(i, n) ({                         \
> +      assert (is_power_of_2 (n));                   \
> +      (i) & ~((n) - 1);                             \
> +})

And again.

Also, ~((n)-1) is identical to -(n), if you want less typing (well, as 
long as you assume twos-complements signed numbers, but that's pretty 
safe to assume these days).

> +
> +/* Return n / d, rounding the result up to the next integer. */
> +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))

This one should be okay, though.

> +++ b/filters/truncate/truncate.c
> @@ -46,6 +46,7 @@
>   
>   #include "ispowerof2.h"
>   #include "iszero.h"
> +#include "rounding.h"
>   
>   #define THREAD_MODEL NBDKIT_THREAD_MODEL_PARALLEL
>   
> @@ -157,9 +158,9 @@ truncate_get_size (struct nbdkit_next_ops *next_ops, void *nxdata,
>     if (truncate_size >= 0)
>       size = truncate_size;
>     if (round_up > 0)
> -    size = (size + round_up - 1) & ~(round_up - 1);
> +    size = ROUND_UP (size, round_up);
>     if (round_down > 0)
> -    size &= ~(round_down - 1);
> +    size = ROUND_DOWN (size, round_down);

Ouch - the bug was pre-existing.  size is uint64_t, while 
round_{up,down} is unsigned (and hence 32-bit), which means this failed 
on sizes larger than 4G.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org




More information about the Libguestfs mailing list