[12/18] block/dirty-bitmap: Add bdrv_dirty_iter_next_area

Message ID 20170913181910.29688-13-mreitz@redhat.com
State New
Headers show
Series
  • block/mirror: Add active-sync mirroring
Related show

Commit Message

Max Reitz Sept. 13, 2017, 6:19 p.m.
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(+)

Comments

Vladimir Sementsov-Ogievskiy Sept. 25, 2017, 3:49 p.m. | #1
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)
Max Reitz Sept. 25, 2017, 8:43 p.m. | #2
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
Vladimir Sementsov-Ogievskiy Oct. 2, 2017, 1:32 p.m. | #3
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

Patch

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)