All of lore.kernel.org
 help / color / mirror / Atom feed
From: Max Reitz <mreitz@redhat.com>
To: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>,
	qemu-block@nongnu.org
Cc: fam@euphon.net, kwolf@redhat.com, jsnow@redhat.com,
	qemu-devel@nongnu.org, den@openvz.org
Subject: Re: [Qemu-devel] [PATCH] util/hbitmap: fix unaligned reset
Date: Mon, 5 Aug 2019 13:32:38 +0200	[thread overview]
Message-ID: <e97ff375-6527-8701-2ee5-bf5bb4e1a9bf@redhat.com> (raw)
In-Reply-To: <20190802185830.74648-1-vsementsov@virtuozzo.com>


[-- Attachment #1.1: Type: text/plain, Size: 3392 bytes --]

On 02.08.19 20:58, Vladimir Sementsov-Ogievskiy wrote:
> hbitmap_reset is broken: it rounds up the requested region. It leads to
> the following bug, which is shown by fixed test:
> 
> assume granularity = 2
> set(0, 3) # count becomes 4
> reset(0, 1) # count becomes 2
> 
> But user of the interface assume that virtual bit 1 should be still
> dirty, so hbitmap should report count to be 4!
> 
> In other words, because of granularity, when we set one "virtual" bit,
> yes, we make all "virtual" bits in same chunk to be dirty. But this
> should not be so for reset.
> 
> Fix this, aligning bound correctly.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> ---
> 
> Hi all!
> 
> Hmm, is it a bug or feature? :)
> I don't have a test for mirror yet, but I think that sync mirror may be broken
> because of this, as do_sync_target_write() seems to be using unaligned reset.
> 
>  tests/test-hbitmap.c |  2 +-
>  util/hbitmap.c       | 24 +++++++++++++++++++-----
>  2 files changed, 20 insertions(+), 6 deletions(-)
> 
> diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
> index 592d8219db..0008025a9f 100644
> --- a/tests/test-hbitmap.c
> +++ b/tests/test-hbitmap.c
> @@ -424,7 +424,7 @@ static void test_hbitmap_granularity(TestHBitmapData *data,
>      hbitmap_test_set(data, 0, 3);
>      g_assert_cmpint(hbitmap_count(data->hb), ==, 4);
>      hbitmap_test_reset(data, 0, 1);
> -    g_assert_cmpint(hbitmap_count(data->hb), ==, 2);
> +    g_assert_cmpint(hbitmap_count(data->hb), ==, 4);
>  }
>  
>  static void test_hbitmap_iter_granularity(TestHBitmapData *data,
> diff --git a/util/hbitmap.c b/util/hbitmap.c
> index 7905212a8b..61a813994a 100644
> --- a/util/hbitmap.c
> +++ b/util/hbitmap.c
> @@ -473,15 +473,29 @@ void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count)
>  {
>      /* Compute range in the last layer.  */
>      uint64_t first;
> -    uint64_t last = start + count - 1;
> +    uint64_t last;
> +    uint64_t end = start + count;
> +    uint64_t gran = UINT64_C(1) << hb->granularity;
>  
> -    trace_hbitmap_reset(hb, start, count,
> -                        start >> hb->granularity, last >> hb->granularity);
> +    /*
> +     * We should clear only bits, fully covered by requested region. Otherwise
> +     * we may clear something that is actually still dirty.
> +     */
> +    first = DIV_ROUND_UP(start, gran);
>  
> -    first = start >> hb->granularity;
> -    last >>= hb->granularity;
> +    if (end == hb->orig_size) {

This should be “>=”.

There are callers that don’t make sure that start + count <=
hb->orig_size (e.g. the backup job just calls it with multiples of
cluster_size, which may or may not end up at the image end; and
hbitmap_truncate() just uses “hb->size << hb->granularity” as the end,
which is arguably not ideal, but that’s how it is).

Max

> +        end = DIV_ROUND_UP(end, gran);
> +    } else {
> +        end = end >> hb->granularity;
> +    }
> +    if (end <= first) {
> +        return;
> +    }
> +    last = end - 1;
>      assert(last < hb->size);
>  
> +    trace_hbitmap_reset(hb, start, count, first, last);
> +
>      hb->count -= hb_count_between(hb, first, last);
>      if (hb_reset_between(hb, HBITMAP_LEVELS - 1, first, last) &&
>          hb->meta) {
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

  parent reply	other threads:[~2019-08-05 11:33 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-02 18:58 [Qemu-devel] [PATCH] util/hbitmap: fix unaligned reset Vladimir Sementsov-Ogievskiy
2019-08-02 19:21 ` John Snow
2019-08-05  9:26   ` Vladimir Sementsov-Ogievskiy
2019-08-05  9:48     ` Vladimir Sementsov-Ogievskiy
2019-08-05 20:03       ` John Snow
2019-08-02 21:19 ` Max Reitz
2019-08-05  9:45   ` Vladimir Sementsov-Ogievskiy
2019-08-05 11:26     ` Max Reitz
2019-08-05 11:43     ` Max Reitz
2019-08-05  9:56   ` Kevin Wolf
2019-08-05 11:30     ` Max Reitz
2019-08-05 23:31   ` Paolo Bonzini
2019-08-06 12:39   ` Vladimir Sementsov-Ogievskiy
2019-08-06 13:30     ` John Snow
2019-08-06 13:47       ` Vladimir Sementsov-Ogievskiy
2019-08-05 11:32 ` Max Reitz [this message]
2019-08-05 11:37   ` Vladimir Sementsov-Ogievskiy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e97ff375-6527-8701-2ee5-bf5bb4e1a9bf@redhat.com \
    --to=mreitz@redhat.com \
    --cc=den@openvz.org \
    --cc=fam@euphon.net \
    --cc=jsnow@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=vsementsov@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.