This new function allows to look for a consecutively dirty area in a
dirty bitmap.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
include/block/dirty-bitmap.h | 2 ++
block/dirty-bitmap.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 54 insertions(+)
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index a79a58d2c3..7654748700 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -90,6 +90,8 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors);
int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
+bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset,
+ uint64_t *offset, int *bytes);
void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index aee57cf8c8..81b2f78016 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -550,6 +550,58 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
return hbitmap_iter_next(&iter->hbi, true);
}
+/**
+ * Return the next consecutively dirty area in the dirty bitmap
+ * belonging to the given iterator @iter.
+ *
+ * @max_offset: Maximum value that may be returned for
+ * *offset + *bytes
+ * @offset: Will contain the start offset of the next dirty area
+ * @bytes: Will contain the length of the next dirty area
+ *
+ * Returns: True if a dirty area could be found before max_offset
+ * (which means that *offset and *bytes then contain valid
+ * values), false otherwise.
+ */
+bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset,
+ uint64_t *offset, int *bytes)
+{
+ uint32_t granularity = bdrv_dirty_bitmap_granularity(iter->bitmap);
+ uint64_t gran_max_offset;
+ int sector_gran = granularity >> BDRV_SECTOR_BITS;
+ int64_t ret;
+ int size;
+
+ if (DIV_ROUND_UP(max_offset, BDRV_SECTOR_SIZE) == iter->bitmap->size) {
+ /* If max_offset points to the image end, round it up by the
+ * bitmap granularity */
+ gran_max_offset = ROUND_UP(max_offset, granularity);
+ } else {
+ gran_max_offset = max_offset;
+ }
+
+ ret = hbitmap_iter_next(&iter->hbi, false);
+ if (ret < 0 || (ret << BDRV_SECTOR_BITS) + granularity > gran_max_offset) {
+ return false;
+ }
+
+ *offset = ret << BDRV_SECTOR_BITS;
+ size = 0;
+
+ assert(granularity <= INT_MAX);
+
+ do {
+ /* Advance iterator */
+ ret = hbitmap_iter_next(&iter->hbi, true);
+ size += granularity;
+ } while ((ret << BDRV_SECTOR_BITS) + granularity <= gran_max_offset &&
+ hbitmap_iter_next(&iter->hbi, false) == ret + sector_gran &&
+ size <= INT_MAX - granularity);
+
+ *bytes = MIN(size, max_offset - *offset);
+ return true;
+}
+
/* Called within bdrv_dirty_bitmap_lock..unlock */
void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
int64_t cur_sector, int64_t nr_sectors)
--
2.13.5
I have a patch on list, which adds hbitmap_next_zero function, it may help
https://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg00809.html
13.09.2017 21:19, Max Reitz wrote:
> This new function allows to look for a consecutively dirty area in a
> dirty bitmap.
>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> ---
> include/block/dirty-bitmap.h | 2 ++
> block/dirty-bitmap.c | 52 ++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 54 insertions(+)
>
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index a79a58d2c3..7654748700 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -90,6 +90,8 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
> void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
> int64_t cur_sector, int64_t nr_sectors);
> int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
> +bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset,
> + uint64_t *offset, int *bytes);
> void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
> int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
> int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index aee57cf8c8..81b2f78016 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -550,6 +550,58 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
> return hbitmap_iter_next(&iter->hbi, true);
> }
>
> +/**
> + * Return the next consecutively dirty area in the dirty bitmap
> + * belonging to the given iterator @iter.
> + *
> + * @max_offset: Maximum value that may be returned for
> + * *offset + *bytes
> + * @offset: Will contain the start offset of the next dirty area
> + * @bytes: Will contain the length of the next dirty area
> + *
> + * Returns: True if a dirty area could be found before max_offset
> + * (which means that *offset and *bytes then contain valid
> + * values), false otherwise.
> + */
> +bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t max_offset,
> + uint64_t *offset, int *bytes)
> +{
> + uint32_t granularity = bdrv_dirty_bitmap_granularity(iter->bitmap);
> + uint64_t gran_max_offset;
> + int sector_gran = granularity >> BDRV_SECTOR_BITS;
> + int64_t ret;
> + int size;
> +
> + if (DIV_ROUND_UP(max_offset, BDRV_SECTOR_SIZE) == iter->bitmap->size) {
> + /* If max_offset points to the image end, round it up by the
> + * bitmap granularity */
> + gran_max_offset = ROUND_UP(max_offset, granularity);
> + } else {
> + gran_max_offset = max_offset;
> + }
> +
> + ret = hbitmap_iter_next(&iter->hbi, false);
> + if (ret < 0 || (ret << BDRV_SECTOR_BITS) + granularity > gran_max_offset) {
> + return false;
> + }
> +
> + *offset = ret << BDRV_SECTOR_BITS;
> + size = 0;
> +
> + assert(granularity <= INT_MAX);
> +
> + do {
> + /* Advance iterator */
> + ret = hbitmap_iter_next(&iter->hbi, true);
> + size += granularity;
> + } while ((ret << BDRV_SECTOR_BITS) + granularity <= gran_max_offset &&
> + hbitmap_iter_next(&iter->hbi, false) == ret + sector_gran &&
> + size <= INT_MAX - granularity);
> +
> + *bytes = MIN(size, max_offset - *offset);
> + return true;
> +}
> +
> /* Called within bdrv_dirty_bitmap_lock..unlock */
> void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
> int64_t cur_sector, int64_t nr_sectors)
--
Best regards,
Vladimir
On 2017-09-25 17:49, Vladimir Sementsov-Ogievskiy wrote: > I have a patch on list, which adds hbitmap_next_zero function, it may help > https://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg00809.html Hmmm. Sounds good, but (1) I would need to directly access the bitmap instead of the iterator, and (2) I would still need to clear the whole in the iterator... It does sound tempting because I could drop the previous patch, then (and thus wouldn't have to worry about concurrent resetting), but I don't think the whole implementation would be simpler. I'll think about it, but thanks for pointing it out in any case! Max
25.09.2017 18:49, Vladimir Sementsov-Ogievskiy wrote:
> I have a patch on list, which adds hbitmap_next_zero function, it may
> help
> https://lists.nongnu.org/archive/html/qemu-devel/2017-02/msg00809.html
there is a mistake in this hbitmap_next_zero, I'll send today corrected
version as part of small backup-related series.
>
> 13.09.2017 21:19, Max Reitz wrote:
>> This new function allows to look for a consecutively dirty area in a
>> dirty bitmap.
>>
>> Signed-off-by: Max Reitz <mreitz@redhat.com>
>> ---
>> include/block/dirty-bitmap.h | 2 ++
>> block/dirty-bitmap.c | 52
>> ++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 54 insertions(+)
>>
>> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
>> index a79a58d2c3..7654748700 100644
>> --- a/include/block/dirty-bitmap.h
>> +++ b/include/block/dirty-bitmap.h
>> @@ -90,6 +90,8 @@ void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap
>> *bitmap,
>> void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
>> int64_t cur_sector, int64_t
>> nr_sectors);
>> int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
>> +bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t
>> max_offset,
>> + uint64_t *offset, int *bytes);
>> void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t
>> sector_num);
>> int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
>> int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
>> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
>> index aee57cf8c8..81b2f78016 100644
>> --- a/block/dirty-bitmap.c
>> +++ b/block/dirty-bitmap.c
>> @@ -550,6 +550,58 @@ int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter
>> *iter)
>> return hbitmap_iter_next(&iter->hbi, true);
>> }
>> +/**
>> + * Return the next consecutively dirty area in the dirty bitmap
>> + * belonging to the given iterator @iter.
>> + *
>> + * @max_offset: Maximum value that may be returned for
>> + * *offset + *bytes
>> + * @offset: Will contain the start offset of the next dirty area
>> + * @bytes: Will contain the length of the next dirty area
>> + *
>> + * Returns: True if a dirty area could be found before max_offset
>> + * (which means that *offset and *bytes then contain valid
>> + * values), false otherwise.
>> + */
>> +bool bdrv_dirty_iter_next_area(BdrvDirtyBitmapIter *iter, uint64_t
>> max_offset,
>> + uint64_t *offset, int *bytes)
>> +{
>> + uint32_t granularity = bdrv_dirty_bitmap_granularity(iter->bitmap);
>> + uint64_t gran_max_offset;
>> + int sector_gran = granularity >> BDRV_SECTOR_BITS;
>> + int64_t ret;
>> + int size;
>> +
>> + if (DIV_ROUND_UP(max_offset, BDRV_SECTOR_SIZE) ==
>> iter->bitmap->size) {
>> + /* If max_offset points to the image end, round it up by the
>> + * bitmap granularity */
>> + gran_max_offset = ROUND_UP(max_offset, granularity);
>> + } else {
>> + gran_max_offset = max_offset;
>> + }
>> +
>> + ret = hbitmap_iter_next(&iter->hbi, false);
>> + if (ret < 0 || (ret << BDRV_SECTOR_BITS) + granularity >
>> gran_max_offset) {
>> + return false;
>> + }
>> +
>> + *offset = ret << BDRV_SECTOR_BITS;
>> + size = 0;
>> +
>> + assert(granularity <= INT_MAX);
>> +
>> + do {
>> + /* Advance iterator */
>> + ret = hbitmap_iter_next(&iter->hbi, true);
>> + size += granularity;
>> + } while ((ret << BDRV_SECTOR_BITS) + granularity <=
>> gran_max_offset &&
>> + hbitmap_iter_next(&iter->hbi, false) == ret +
>> sector_gran &&
>> + size <= INT_MAX - granularity);
>> +
>> + *bytes = MIN(size, max_offset - *offset);
>> + return true;
>> +}
>> +
>> /* Called within bdrv_dirty_bitmap_lock..unlock */
>> void bdrv_set_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
>> int64_t cur_sector, int64_t
>> nr_sectors)
>
>
--
Best regards,
Vladimir
© 2016 - 2026 Red Hat, Inc.