[PATCH v6 13/25] parallels: Handle L1 entries equal to one
"Denis V. Lunev" <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu,gmane.comp.emulators.qemu.block |
|---|---|
| Message-ID | <[email protected]> |
From: Denis V. Lunev <[email protected]> If all the bits in a dirty bitmap cluster are ones, the cluster shouldn't be written. Instead the corresponding L1 entry should be set to 1. Ask bdrv_dirty_bitmap_next_zero() for a clean bit in the range the entry covers, and store the marker when there is none. Two things have to match the region rather than the cluster which serializes it: the search is bounded by the end of the region, as a count and not as an offset, and a missing clean bit is the answer we are looking for rather than a reason to give up. A dirty run is not a substitute for either. Its length says nothing about the region it lies in, so comparing it to the cluster size marks a chunk as all ones when only a cluster worth of it is dirty, and treating "no clean bit at all" as a failure leaves the entry at zero, which says the whole chunk is clean. Both directions are silent: a full disk overwrite comes back as a completely clean bitmap, and a single dirty cluster comes back as everything the entry covers being dirty. An incremental backup driven by the first one copies nothing. The marker goes through cpu_to_le64() like the cluster offsets below it, as the loading side reads the table with ldq_le_p(). The serialization moved behind the check, as there is nothing to write when the marker is stored. Based on the original work from Alexander Ivanov. Cc: Stefan Hajnoczi <[email protected]> Signed-off-by: Denis V. Lunev <[email protected]> --- block/parallels-ext.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/block/parallels-ext.c b/block/parallels-ext.c index e89c489730..6a889d86fa 100644 --- a/block/parallels-ext.c +++ b/block/parallels-ext.c @@ -439,12 +439,20 @@ static int GRAPH_RDLOCK parallels_save_bitmap(BlockDriverState *bs, offset = 0; while ((offset = bdrv_dirty_bitmap_next_dirty(bitmap, offset, bm_size)) >= 0) { - int64_t cluster_off, end, write_size; + int64_t cluster_off, end, write_size, first_zero; idx = offset / limit; offset = QEMU_ALIGN_DOWN(offset, limit); end = MIN(bm_size, offset + limit); + + first_zero = bdrv_dirty_bitmap_next_zero(bitmap, offset, end - offset); + if (first_zero < 0) { + l1_table[idx] = cpu_to_le64(1); + offset = end; + continue; + } + write_size = bdrv_dirty_bitmap_serialization_size(bitmap, offset, end - offset); assert(write_size <= s->cluster_size); -- 2.53.0