From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50169) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aePuW-0000vw-EN for qemu-devel@nongnu.org; Fri, 11 Mar 2016 11:27:33 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aePuV-0001X4-0C for qemu-devel@nongnu.org; Fri, 11 Mar 2016 11:27:32 -0500 References: <1457412306-18940-1-git-send-email-famz@redhat.com> <1457412306-18940-13-git-send-email-famz@redhat.com> From: Max Reitz Message-ID: <56E2F1E9.9050509@redhat.com> Date: Fri, 11 Mar 2016 17:27:21 +0100 MIME-Version: 1.0 In-Reply-To: <1457412306-18940-13-git-send-email-famz@redhat.com> Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="KpPS6AmSItQ99VDXQRX1u6mx6qK96rQ5b" Subject: Re: [Qemu-devel] [PATCH v4 12/15] hbitmap: serialization List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Fam Zheng , qemu-devel@nongnu.org Cc: kwolf@redhat.com, Vladimir Sementsov-Ogievskiy , jsnow@redhat.com, qemu-block@nongnu.org This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --KpPS6AmSItQ99VDXQRX1u6mx6qK96rQ5b Content-Type: multipart/mixed; boundary="tXPfSQboQ4nntXDEDbdBLI11bxXdjVcvS" From: Max Reitz To: Fam Zheng , qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, Vladimir Sementsov-Ogievskiy , jsnow@redhat.com, kwolf@redhat.com Message-ID: <56E2F1E9.9050509@redhat.com> Subject: Re: [PATCH v4 12/15] hbitmap: serialization References: <1457412306-18940-1-git-send-email-famz@redhat.com> <1457412306-18940-13-git-send-email-famz@redhat.com> In-Reply-To: <1457412306-18940-13-git-send-email-famz@redhat.com> --tXPfSQboQ4nntXDEDbdBLI11bxXdjVcvS Content-Type: text/plain; charset=iso-8859-15 Content-Transfer-Encoding: quoted-printable On 08.03.2016 05:45, Fam Zheng wrote: > From: Vladimir Sementsov-Ogievskiy >=20 > Functions to serialize / deserialize(restore) HBitmap. HBitmap should b= e > saved to linear sequence of bits independently of endianness and bitmap= > array element (unsigned long) size. Therefore Little Endian is chosen. >=20 > 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. >=20 > Signed-off-by: Vladimir Sementsov-Ogievskiy > [Fix left shift operand to 1UL; add "finish" parameter. - Fam] > Signed-off-by: Fam Zheng > --- > include/qemu/hbitmap.h | 79 ++++++++++++++++++++++++++++ > util/hbitmap.c | 137 +++++++++++++++++++++++++++++++++++++++++= ++++++++ > 2 files changed, 216 insertions(+) [...] > diff --git a/util/hbitmap.c b/util/hbitmap.c > index 2d3d04c..5f02c17 100644 > --- a/util/hbitmap.c > +++ b/util/hbitmap.c > @@ -395,6 +395,143 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item= ) > return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bi= t) !=3D 0; > } > =20 > +uint64_t hbitmap_serialization_granularity(const HBitmap *hb) > +{ > + /* Require at least 64 bit granularity to be safe on both 64 bit a= nd 32 bit > + * hosts. */ > + return 64 << hb->granularity; > +} > + > +/* Start should be aligned to serialization granularity, chunk size sh= ould be > + * aligned to serialization granularity too, except for last chunk. > + */ > +static void serialization_chunk(const HBitmap *hb, > + uint64_t start, uint64_t count, > + unsigned long **first_el, size_t *el_c= ount) > +{ > + uint64_t last =3D start + count - 1; > + uint64_t gran =3D hbitmap_serialization_granularity(hb); > + > + assert((start & (gran - 1)) =3D=3D 0); > + assert((last >> hb->granularity) < hb->size); > + if ((last >> hb->granularity) !=3D hb->size - 1) { > + assert((count & (gran - 1)) =3D=3D 0); > + } > + > + start =3D (start >> hb->granularity) >> BITS_PER_LEVEL; > + last =3D (last >> hb->granularity) >> BITS_PER_LEVEL; > + > + *first_el =3D &hb->levels[HBITMAP_LEVELS - 1][start]; > + *el_count =3D 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); > + > + 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 =3D cur + el_count; > + > + while (cur !=3D end) { > + unsigned long el =3D > + (BITS_PER_LONG =3D=3D 32 ? cpu_to_le32(*cur) : cpu_to_le64= (*cur)); Looks a bit fishy, but I can't come up with anything better. (Other than adding cpu_to_leul(); we already do have leul_to_cpu(), so that wouldn't be too far off.) > + > + memcpy(buf, &el, sizeof(el)); One could have used cpu_to_le32/64w((uint32/64_t *)buf, *cur); instead. Maybe I'd like the following better: #if BITS_PER_LONG =3D=3D 32 cpu_to_le32w((uint32_t *)buf, *cur); #elif BITS_PER_LONG =3D=3D 64 cpu_to_le64w((uint64_t *)buf, *cur); #else #error Unknown long size #endif Or just #else /* BITS_PER_LONG =3D=3D 64 */ instead of the #elif. I think that's safe to assume. > + buf +=3D 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 =3D cur + el_count; > + > + while (cur !=3D end) { > + memcpy(cur, buf, sizeof(*cur)); > + > + if (BITS_PER_LONG =3D=3D 32) { > + le32_to_cpus((uint32_t *)cur); > + } else { > + le64_to_cpus((uint64_t *)cur); > + } Here, I'd definitely like that variant better, i.e. #if BITS_PER_LONG =3D=3D 32 le32_to_cpuw(cur, *(uint32_t *)buf); #else /* BITS_PER_LONG =3D=3D 64 */ le64_to_cpuw(cur, *(uint64_t *)buf); #endif Unless a language lawyer NACKs this because the pointer cast violates strict aliasing. If so, I still strongly recommend replacing the if by an #if, not least because this saves us the pointer cast on cur. (Or does it? Maybe one still needs to explicitly cast an unsigned long * to uint32_t * even if both have the same size. However, in that case we can still do *cur =3D le32/64_to_cpu(*cur). The above would then become: #if BITS_PER_LONG =3D=3D 32 *cur =3D le32_to_cpu(*(uint32_t *)buf); #else /* BITS_PER_LONG =3D=3D 64 */ *cur =3D le64_to_cpu(*(uint64_t *)buf); #endif ) > + > + buf +=3D 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); > + > + 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, assumin= g > + * that the last level is ok */ > + size =3D MAX((bitmap->size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL,= 1); > + for (lev =3D HBITMAP_LEVELS - 1; lev-- > 0; ) { I'm always amazed of how much this notation (x-- > 0, or x --> 0, even worse) confuses me. Or rather I'm always amazed of how much it confuses me and how much other people love it (as opposed to me, who's rather unhappy every time he doesn't use all of the three "parameters" for a for loop). This time I wondered why we start at HBITMAP_LEVELS - 1 -- that's the ultimate and not the penultimate level after all. But of course, the loop condition is evaluated before the loop is executed for the first time, so we will indeed start at HBITMAP_LEVELS - 2. So, yeah, this is correct. > + prev_size =3D size; > + size =3D MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);= > + memset(bitmap->levels[lev], 0, size * sizeof(unsigned long)); > + > + for (i =3D 0; i < prev_size; ++i) { I hate using stand-alone pre-increment for scalars with a passion. Unfortunately, checkpatch does not. Reviewed-by: Max Reitz (All of the above are me just nagging and giving optional suggestions.) > + if (bitmap->levels[lev + 1][i]) { > + bitmap->levels[lev][i >> BITS_PER_LEVEL] |=3D > + 1UL << (i & (BITS_PER_LONG - 1)); > + } > + } > + } > + > + bitmap->levels[0][0] |=3D 1UL << (BITS_PER_LONG - 1); > +} > + > void hbitmap_free(HBitmap *hb) > { > unsigned i; >=20 --tXPfSQboQ4nntXDEDbdBLI11bxXdjVcvS-- --KpPS6AmSItQ99VDXQRX1u6mx6qK96rQ5b Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAEBCAAGBQJW4vHpAAoJEDuxQgLoOKytgZ0H/iWuCdIIYlNMpyWX4g13cOCE TtGiWvMG2x5XIxWlIE0KGWfvLB0q/acsKIbUiHBbO8V8tm1rV1jNvJOhp7fJprut 5sDB9aajZMGClW5X07RYcmQJiN0XAIeqIzBEEW5w/LyoAVprON7FoXEhBvuNcx2V naEkd2ll5DH6G1efbYmoALaZVTL7Jrkyr0YinIwN9NDC7mTkCpV6dI68lhbeB4L7 ObmuE8ItFZ6VzaCNEIexkSW/6HsirYUDi4Jt6AhLQuidMD2vuYnMKee0BaNjjIZX 5G/vMvXtRS4fkpRCPd7PiLRfjUizzrIb/pTwCXiYevKif6p5YfHydwgRO7V4OrU= =/xkU -----END PGP SIGNATURE----- --KpPS6AmSItQ99VDXQRX1u6mx6qK96rQ5b--