21.10.2020 17:44, Stefan Reiter wrote:
sectors_per_chunk is a 64 bit integer, but the calculation is done in 32
bits, leading to an overflow for coarse bitmap granularities.
If that results in the value 0, it leads to a hang where no progress is
made but send_bitmap_bits is constantly called with nr_sectors being 0.
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
---
migration/block-dirty-bitmap.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/migration/block-dirty-bitmap.c b/migration/block-dirty-bitmap.c
index 5bef793ac0..5398869e2b 100644
--- a/migration/block-dirty-bitmap.c
+++ b/migration/block-dirty-bitmap.c
@@ -562,8 +562,9 @@ static int add_bitmaps_to_list(DBMSaveState *s,
BlockDriverState *bs,
dbms->bitmap_alias = g_strdup(bitmap_alias);
dbms->bitmap = bitmap;
dbms->total_sectors = bdrv_nb_sectors(bs);
- dbms->sectors_per_chunk = CHUNK_SIZE * 8 *
+ dbms->sectors_per_chunk = CHUNK_SIZE * 8lu *
I'd prefer 8llu for absolute safety.
bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
+ assert(dbms->sectors_per_chunk != 0);
I doubt that we need this assertion. Bug fixed, and it's obviously impossible.
And if we really want to assert that there is no overflow (assuming future
changes),
it should look like this:
assert(bdrv_dirty_bitmap_granularity(bitmap) < (1ull << 63) / CHUNK_SIZE / 8
>> BDRV_SECTOR_BITS);
to cover not only corner case but any overflow.. And of course we should modify
original expression
to do ">> BDRV_SECTOR_BITS" earlier than all multiplies, like
dbms->sectors_per_chunk = CHUNK_SIZE * 8llu *
(bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS);
But I think that only s/8/8ull/ change is enough.