From: John Snow <jsnow@redhat.com>
To: Fam Zheng <famz@redhat.com>, qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, Jeff Cody <jcody@redhat.com>,
Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>,
qemu-block@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 11/13] hbitmap: serialization
Date: Thu, 7 Jan 2016 16:11:56 -0500 [thread overview]
Message-ID: <568ED49C.6040108@redhat.com> (raw)
In-Reply-To: <1451903234-32529-12-git-send-email-famz@redhat.com>
On 01/04/2016 05:27 AM, Fam Zheng wrote:
> From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>
> Functions to serialize / deserialize(restore) HBitmap. HBitmap should be
> saved to linear sequence of bits independently of endianness and bitmap
> array element (unsigned long) size. Therefore Little Endian is chosen.
>
> These functions are appropriate for dirty bitmap migration, restoring
> the bitmap in several steps is available. To save performance, every
> step writes only the last level of the bitmap. All other levels are
> restored by hbitmap_deserialize_finish() as a last step of restoring.
> So, HBitmap is inconsistent while restoring.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> [Fix left shift operand to 1UL; add "finish" parameter. - Fam]
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
> include/qemu/hbitmap.h | 76 +++++++++++++++++++++++++++
> util/hbitmap.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 212 insertions(+)
>
> diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
> index ed672e7..3414113 100644
> --- a/include/qemu/hbitmap.h
> +++ b/include/qemu/hbitmap.h
> @@ -149,6 +149,82 @@ void hbitmap_reset_all(HBitmap *hb);
> bool hbitmap_get(const HBitmap *hb, uint64_t item);
>
> /**
> + * hbitmap_data_size:
> + * @hb: HBitmap to operate on.
> + * @count: Number of bits
> + *
> + * Grunularity of serialization chunks, used by other serializetion functions.
> + * For every chunk:
> + * 1. Chunk start should be aligned to this granularity.
> + * 2. Chunk size should be aligned too, except for last chunk (for which
> + * start + count == hb->size)
> + */
Whoops, this is the documentation for the function below. Looks like you
updated this one instead of the one adjacent to the prototype, too.
> +uint64_t hbitmap_serialization_granularity(const HBitmap *hb);
> +
> +/**
> + * hbitmap_data_size:
> + * @hb: HBitmap to operate on.
> + * @count: Number of bits
> + *
> + * Return amount of bytes hbitmap_(de)serialize_part needs
> + */
> +uint64_t hbitmap_serialization_size(const HBitmap *hb,
> + uint64_t start, uint64_t count);
> +
> +/**
> + * hbitmap_serialize_part
> + * @hb: HBitmap to operate on.
> + * @buf: Buffer to store serialized bitmap.
> + * @start: First bit to store.
> + * @count: Number of bits to store.
> + *
> + * Stores HBitmap data corresponding to given region. The format of saved data
> + * is linear sequence of bits, so it can be used by hbitmap_deserialize_part
> + * independently of endianness and size of HBitmap level array elements
> + */
I suppose that the buffer needs to be pre-allocated and "count/8" bytes
long; but rather specifically it needs to be hbitmap_serialization_size
bytes long, probably. Worth mentioning in the notes for @count since
we're already writing docs?
> +void hbitmap_serialize_part(const HBitmap *hb, uint8_t *buf,
> + uint64_t start, uint64_t count);
> +
> +/**
> + * hbitmap_deserialize_part
> + * @hb: HBitmap to operate on.
> + * @buf: Buffer to restore bitmap data from.
> + * @start: First bit to restore.
> + * @count: Number of bits to restore.
> + * @finish: Whether to call hbitmap_deserialize_finish automatically.
> + *
> + * Restores HBitmap data corresponding to given region. The format is the same
> + * as for hbitmap_serialize_part.
> + *
> + * if @finish is false, caller must call hbitmap_serialize_finish before using
> + * the bitmap.
> + */
> +void hbitmap_deserialize_part(HBitmap *hb, uint8_t *buf,
> + uint64_t start, uint64_t count,
> + bool finish);
> +
> +/**
> + * hbitmap_deserialize_zeroes
> + * @hb: HBitmap to operate on.
> + * @start: First bit to restore.
> + * @count: Number of bits to restore.
> + * @finish: Whether to call hbitmap_deserialize_finish automatically.
> + *
> + * Same as hbitmap_serialize_part, but fills the bitmap with zeroes.
> + */
Fills the bitmap with zeroes?
> +void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
> + bool finish);
> +
> +/**
> + * hbitmap_deserialize_finish
> + * @hb: HBitmap to operate on.
> + *
> + * Repair HBitmap after calling hbitmap_deserialize_data. Actually, all HBitmap
> + * layers are restored here.
> + */
> +void hbitmap_deserialize_finish(HBitmap *hb);
> +
> +/**
> * hbitmap_free:
> * @hb: HBitmap to operate on.
> *
> diff --git a/util/hbitmap.c b/util/hbitmap.c
> index 55d3182..ab8cd81 100644
> --- a/util/hbitmap.c
> +++ b/util/hbitmap.c
> @@ -397,6 +397,142 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
> return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0;
> }
>
> +uint64_t hbitmap_serialization_granularity(const HBitmap *hb)
> +{
> + return BITS_PER_LONG << hb->granularity;
> +}
> +
> +/* serilization chunk start should be aligned to serialization granularity.
> + * Serilization chunk size scould be aligned to serialization granularity too,
> + * except for last chunk.
> + */
SeriAlization misspelled at the beginning of both lines. (missing the 'a')
> +static void serialization_chunk(const HBitmap *hb,
> + uint64_t start, uint64_t count,
> + unsigned long **first_el, size_t *el_count)
> +{
> + uint64_t last = start + count - 1;
> + uint64_t gran = hbitmap_serialization_granularity(hb);
> +
> + assert(((start + count - 1) >> hb->granularity) < hb->size);
> + assert((start & (gran - 1)) == 0);
> + if ((last >> hb->granularity) != hb->size - 1) {
> + assert((count & (gran - 1)) == 0);
> + }
> +
> + start = (start >> hb->granularity) >> BITS_PER_LEVEL;
> + last = (last >> hb->granularity) >> BITS_PER_LEVEL;
> +
> + *first_el = &hb->levels[HBITMAP_LEVELS - 1][start];
> + *el_count = last - start + 1;
> +}
> +
> +uint64_t hbitmap_serialization_size(const HBitmap *hb,
> + uint64_t start, uint64_t count)
> +{
> + uint64_t el_count;
> + unsigned long *cur;
> +
> + if (!count) {
> + return 0;
> + }
> + serialization_chunk(hb, start, count, &cur, &el_count);
Seems like a waste just to get the size.
> +
> + return el_count * sizeof(unsigned long);
> +}
> +
> +void hbitmap_serialize_part(const HBitmap *hb, uint8_t *buf,
> + uint64_t start, uint64_t count)
> +{
> + uint64_t el_count;
> + unsigned long *cur, *end;
> +
> + if (!count) {
> + return;
> + }
> + serialization_chunk(hb, start, count, &cur, &el_count);
> + end = cur + el_count;
> +
> + while (cur != end) {
> + unsigned long el =
> + (BITS_PER_LONG == 32 ? cpu_to_le32(*cur) : cpu_to_le64(*cur));
> +
> + memcpy(buf, &el, sizeof(el));
> + buf += sizeof(el);
> + cur++;
> + }
> +}
> +
> +void hbitmap_deserialize_part(HBitmap *hb, uint8_t *buf,
> + uint64_t start, uint64_t count,
> + bool finish)
> +{
> + uint64_t el_count;
> + unsigned long *cur, *end;
> +
> + if (!count) {
> + return;
> + }
> + serialization_chunk(hb, start, count, &cur, &el_count);
> + end = cur + el_count;
> +
> + while (cur != end) {
> + memcpy(cur, buf, sizeof(*cur));
> +
> + if (BITS_PER_LONG == 32) {
> + cpu_to_le32s((uint32_t *)cur);
> + } else {
> + cpu_to_le64s((uint64_t *)cur);
> + }
> +
> + buf += sizeof(unsigned long);
> + cur++;
> + }
> + if (finish) {
> + hbitmap_deserialize_finish(hb);
> + }
> +}
> +
> +void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
> + bool finish)
> +{
> + uint64_t el_count;
> + unsigned long *first;
> +
> + if (!count) {
> + return;
> + }
> + serialization_chunk(hb, start, count, &first, &el_count);
> +
I guess this is just to get the el_count, primarily, because we just
bowl over it just below.
Shouldn't this just use the serialization size function up above, anyway?
> + memset(first, 0, el_count * sizeof(unsigned long));
> + if (finish) {
> + hbitmap_deserialize_finish(hb);
> + }
> +}
> +
> +void hbitmap_deserialize_finish(HBitmap *bitmap)
> +{
> + int64_t i, size, prev_size;
> + int lev;
> +
> + /* restore levels starting from penultimate to zero level, assuming
> + * that the last level is ok */
> + size = MAX((bitmap->size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
> + for (lev = HBITMAP_LEVELS - 1; lev-- > 0; ) {
> + prev_size = size;
> + size = MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
> + memset(bitmap->levels[lev], 0, size * sizeof(unsigned long));
> +
> + for (i = 0; i < prev_size; ++i) {
> + if (bitmap->levels[lev + 1][i]) {
> + bitmap->levels[lev][i >> BITS_PER_LEVEL] |=
> + 1UL << (i & (BITS_PER_LONG - 1));
> + }
> + }
> + }
> +
> + bitmap->levels[0][0] |= 1UL << (BITS_PER_LONG - 1);
> +}
> +
> void hbitmap_free(HBitmap *hb)
> {
> unsigned i;
>
next prev parent reply other threads:[~2016-01-07 21:12 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-01-04 10:27 [Qemu-devel] [PATCH 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
2016-01-04 10:27 ` [Qemu-devel] [PATCH 01/13] backup: Use Bitmap to replace "s->bitmap" Fam Zheng
2016-01-04 10:27 ` [Qemu-devel] [PATCH 02/13] typedefs: Add BdrvDirtyBitmap and HBitmapIter Fam Zheng
2016-01-05 22:14 ` John Snow
2016-01-08 2:13 ` Fam Zheng
2016-01-04 10:27 ` [Qemu-devel] [PATCH 03/13] block: Move block dirty bitmap code to separate files Fam Zheng
2016-01-05 22:32 ` John Snow
2016-01-04 10:27 ` [Qemu-devel] [PATCH 04/13] block: Remove unused typedef of BlockDriverDirtyHandler Fam Zheng
2016-01-05 22:35 ` John Snow
2016-01-04 10:27 ` [Qemu-devel] [PATCH 05/13] block: Hide HBitmap in block dirty bitmap interface Fam Zheng
2016-01-05 23:01 ` John Snow
2016-01-20 5:09 ` Fam Zheng
2016-01-04 10:27 ` [Qemu-devel] [PATCH 06/13] HBitmap: Introduce "meta" bitmap to track bit changes Fam Zheng
2016-01-06 0:09 ` John Snow
2016-01-11 15:40 ` Vladimir Sementsov-Ogievskiy
2016-01-11 18:56 ` John Snow
2016-01-12 8:25 ` Vladimir Sementsov-Ogievskiy
2016-01-04 10:27 ` [Qemu-devel] [PATCH 07/13] tests: Add test code for meta bitmap Fam Zheng
2016-01-06 20:46 ` John Snow
2016-01-04 10:27 ` [Qemu-devel] [PATCH 08/13] block: Support meta dirty bitmap Fam Zheng
2016-01-07 19:30 ` John Snow
2016-01-20 6:07 ` Fam Zheng
2016-01-20 21:46 ` John Snow
2016-01-04 10:27 ` [Qemu-devel] [PATCH 09/13] block: Add two dirty bitmap getters Fam Zheng
2016-01-07 19:35 ` John Snow
2016-01-04 10:27 ` [Qemu-devel] [PATCH 10/13] block: Assert that bdrv_release_dirty_bitmap succeeded Fam Zheng
2016-01-07 19:38 ` John Snow
2016-01-04 10:27 ` [Qemu-devel] [PATCH 11/13] hbitmap: serialization Fam Zheng
2016-01-07 21:11 ` John Snow [this message]
2016-01-11 15:12 ` Vladimir Sementsov-Ogievskiy
2016-01-11 14:48 ` Vladimir Sementsov-Ogievskiy
2016-01-11 15:19 ` Vladimir Sementsov-Ogievskiy
2016-01-04 10:27 ` [Qemu-devel] [PATCH 12/13] block: BdrvDirtyBitmap serialization interface Fam Zheng
2016-01-04 10:27 ` [Qemu-devel] [PATCH 13/13] tests: Add test code for hbitmap serialization Fam Zheng
2016-01-07 21:32 ` [Qemu-devel] [PATCH 00/13] Dirty bitmap changes for migration/persistence work John Snow
2016-01-08 0:29 ` Fam Zheng
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=568ED49C.6040108@redhat.com \
--to=jsnow@redhat.com \
--cc=famz@redhat.com \
--cc=jcody@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).