diff mbox

[11/24] block: introduce persistent dirty bitmaps

Message ID 20170203094018.15493-12-vsementsov@virtuozzo.com
State New
Headers show

Commit Message

Vladimir Sementsov-Ogievskiy Feb. 3, 2017, 9:40 a.m. UTC
New field BdrvDirtyBitmap.persistent means, that bitmap should be saved
on bdrv_close, using format driver. Format driver should maintain bitmap
storing.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block.c                      | 32 ++++++++++++++++++++++++++++++++
 block/dirty-bitmap.c         | 26 ++++++++++++++++++++++++++
 block/qcow2-bitmap.c         |  1 +
 include/block/block.h        |  1 +
 include/block/block_int.h    |  2 ++
 include/block/dirty-bitmap.h |  6 ++++++
 6 files changed, 68 insertions(+)

Comments

John Snow Feb. 10, 2017, 11:20 p.m. UTC | #1
On 02/03/2017 04:40 AM, Vladimir Sementsov-Ogievskiy wrote:
> New field BdrvDirtyBitmap.persistent means, that bitmap should be saved
> on bdrv_close, using format driver. Format driver should maintain bitmap
> storing.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
> ---
>  block.c                      | 32 ++++++++++++++++++++++++++++++++
>  block/dirty-bitmap.c         | 26 ++++++++++++++++++++++++++
>  block/qcow2-bitmap.c         |  1 +
>  include/block/block.h        |  1 +
>  include/block/block_int.h    |  2 ++
>  include/block/dirty-bitmap.h |  6 ++++++
>  6 files changed, 68 insertions(+)
> 
> diff --git a/block.c b/block.c
> index 56f030c562..970e4ca50e 100644
> --- a/block.c
> +++ b/block.c
> @@ -2321,6 +2321,7 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
>  static void bdrv_close(BlockDriverState *bs)
>  {
>      BdrvAioNotifier *ban, *ban_next;
> +    Error *local_err = NULL;
>  
>      assert(!bs->job);
>      assert(!bs->refcnt);
> @@ -2329,6 +2330,12 @@ static void bdrv_close(BlockDriverState *bs)
>      bdrv_flush(bs);
>      bdrv_drain(bs); /* in case flush left pending I/O */
>  
> +    bdrv_store_persistent_dirty_bitmaps(bs, &local_err);
> +    if (local_err != NULL) {
> +        error_report_err(local_err);
> +        error_report("Persistent bitmaps are lost for node '%s'",
> +                     bdrv_get_device_or_node_name(bs));
> +    }

Ouch! I guess there's not much else we can do here, eh?

>      bdrv_release_named_dirty_bitmaps(bs);
>      assert(QLIST_EMPTY(&bs->dirty_bitmaps));
>  
> @@ -4107,3 +4114,28 @@ void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
>          bs->drv->bdrv_load_autoloading_dirty_bitmaps(bs, errp);
>      }
>  }
> +
> +void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
> +{
> +    BlockDriver *drv = bs->drv;
> +
> +    if (!bdrv_has_persistent_bitmaps(bs)) {
> +        return;
> +    }
> +
> +    if (!drv) {
> +        error_setg_errno(errp, ENOMEDIUM,
> +                         "Can't store persistent bitmaps to %s",
> +                         bdrv_get_device_or_node_name(bs));
> +        return;
> +    }
> +
> +    if (!drv->bdrv_store_persistent_dirty_bitmaps) {
> +        error_setg_errno(errp, ENOTSUP,
> +                         "Can't store persistent bitmaps to %s",
> +                         bdrv_get_device_or_node_name(bs));
> +        return;
> +    }
> +

I suppose this is for the case for where we have added a persistent
bitmap during runtime, but the driver does not support it?

I'd rather fail this type of thing earlier if possible, but I'm not that
far in your series yet.

> +    drv->bdrv_store_persistent_dirty_bitmaps(bs, errp);
> +}
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index 2d27494dc7..4d026df1bd 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -44,6 +44,7 @@ struct BdrvDirtyBitmap {
>      int64_t size;               /* Size of the bitmap (Number of sectors) */
>      bool disabled;              /* Bitmap is read-only */
>      int active_iterators;       /* How many iterators are active */
> +    bool persistent;            /* bitmap must be saved to owner disk image */
>      bool autoload;              /* For persistent bitmaps: bitmap must be
>                                     autoloaded on image opening */
>      QLIST_ENTRY(BdrvDirtyBitmap) list;
> @@ -73,6 +74,7 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
>      g_free(bitmap->name);
>      bitmap->name = NULL;
>  
> +    bitmap->persistent = false;
>      bitmap->autoload = false;
>  }
>  
> @@ -242,6 +244,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
>      bitmap->name = NULL;
>      successor->name = name;
>      bitmap->successor = NULL;
> +    successor->persistent = bitmap->persistent;
> +    bitmap->persistent = false;
>      successor->autoload = bitmap->autoload;
>      bitmap->autoload = false;
>      bdrv_release_dirty_bitmap(bs, bitmap);
> @@ -556,3 +560,25 @@ bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
>  {
>      return bitmap->autoload;
>  }
> +
> +void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
> +{
> +    bitmap->persistent = persistent;
> +}
> +
> +bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
> +{
> +    return bitmap->persistent;
> +}
> +
> +bool bdrv_has_persistent_bitmaps(BlockDriverState *bs)
> +{
> +    BdrvDirtyBitmap *bm;
> +    QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
> +        if (bm->persistent) {
> +            return true;
> +        }
> +    }
> +
> +    return false;
> +}

Probably not worth optimizing.

> diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
> index bcbb0491ee..9af658a0f4 100644
> --- a/block/qcow2-bitmap.c
> +++ b/block/qcow2-bitmap.c
> @@ -707,6 +707,7 @@ void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
>                  goto fail;
>              }
>  
> +            bdrv_dirty_bitmap_set_persistance(bitmap, true);
>              bdrv_dirty_bitmap_set_autoload(bitmap, true);
>              bm->flags |= BME_FLAG_IN_USE;
>              created_dirty_bitmaps =
> diff --git a/include/block/block.h b/include/block/block.h
> index 154ac7f955..0a20d68f0f 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -552,5 +552,6 @@ void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
>  void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
>  
>  void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
> +void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
>  
>  #endif
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 6b2b50c6a2..c3505da56e 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -322,6 +322,8 @@ struct BlockDriver {
>  
>      void (*bdrv_load_autoloading_dirty_bitmaps)(BlockDriverState *bs,
>                                                  Error **errp);
> +    void (*bdrv_store_persistent_dirty_bitmaps)(BlockDriverState *bs,
> +                                                Error **errp);
>  
>      QLIST_ENTRY(BlockDriver) list;
>  };
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index 45a389a20a..8dbd16b040 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -77,4 +77,10 @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
>  
>  void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
>  bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
> +void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
> +                                                bool persistent);
> +bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
> +
> +bool bdrv_has_persistent_bitmaps(BlockDriverState *bs);
> +
>  #endif
> 

Reviewed-by: John Snow <jsnow@redhat.com>
Vladimir Sementsov-Ogievskiy Feb. 14, 2017, 12:05 p.m. UTC | #2
11.02.2017 02:20, John Snow wrote:
>
> On 02/03/2017 04:40 AM, Vladimir Sementsov-Ogievskiy wrote:
>> New field BdrvDirtyBitmap.persistent means, that bitmap should be saved
>> on bdrv_close, using format driver. Format driver should maintain bitmap
>> storing.
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>> ---
>>   block.c                      | 32 ++++++++++++++++++++++++++++++++
>>   block/dirty-bitmap.c         | 26 ++++++++++++++++++++++++++
>>   block/qcow2-bitmap.c         |  1 +
>>   include/block/block.h        |  1 +
>>   include/block/block_int.h    |  2 ++
>>   include/block/dirty-bitmap.h |  6 ++++++
>>   6 files changed, 68 insertions(+)
>>
>> diff --git a/block.c b/block.c
>> index 56f030c562..970e4ca50e 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -2321,6 +2321,7 @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
>>   static void bdrv_close(BlockDriverState *bs)
>>   {
>>       BdrvAioNotifier *ban, *ban_next;
>> +    Error *local_err = NULL;
>>   
>>       assert(!bs->job);
>>       assert(!bs->refcnt);
>> @@ -2329,6 +2330,12 @@ static void bdrv_close(BlockDriverState *bs)
>>       bdrv_flush(bs);
>>       bdrv_drain(bs); /* in case flush left pending I/O */
>>   
>> +    bdrv_store_persistent_dirty_bitmaps(bs, &local_err);
>> +    if (local_err != NULL) {
>> +        error_report_err(local_err);
>> +        error_report("Persistent bitmaps are lost for node '%s'",
>> +                     bdrv_get_device_or_node_name(bs));
>> +    }
> Ouch! I guess there's not much else we can do here, eh?
>
>>       bdrv_release_named_dirty_bitmaps(bs);
>>       assert(QLIST_EMPTY(&bs->dirty_bitmaps));
>>   
>> @@ -4107,3 +4114,28 @@ void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
>>           bs->drv->bdrv_load_autoloading_dirty_bitmaps(bs, errp);
>>       }
>>   }
>> +
>> +void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
>> +{
>> +    BlockDriver *drv = bs->drv;
>> +
>> +    if (!bdrv_has_persistent_bitmaps(bs)) {
>> +        return;
>> +    }
>> +
>> +    if (!drv) {
>> +        error_setg_errno(errp, ENOMEDIUM,
>> +                         "Can't store persistent bitmaps to %s",
>> +                         bdrv_get_device_or_node_name(bs));
>> +        return;
>> +    }
>> +
>> +    if (!drv->bdrv_store_persistent_dirty_bitmaps) {
>> +        error_setg_errno(errp, ENOTSUP,
>> +                         "Can't store persistent bitmaps to %s",
>> +                         bdrv_get_device_or_node_name(bs));
>> +        return;
>> +    }
>> +
> I suppose this is for the case for where we have added a persistent
> bitmap during runtime, but the driver does not support it?
>
> I'd rather fail this type of thing earlier if possible, but I'm not that
> far in your series yet.

qmp bitmap add checks for availability of 
drv->bdrv_can_store_new_dirty_bitmap,
and loaded bitmaps of course should be attached to bds with appropriate 
driver.
So, it is mostly a paranoic check.

>
>> +    drv->bdrv_store_persistent_dirty_bitmaps(bs, errp);
>> +}
>> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
>> index 2d27494dc7..4d026df1bd 100644
>> --- a/block/dirty-bitmap.c
>> +++ b/block/dirty-bitmap.c
>> @@ -44,6 +44,7 @@ struct BdrvDirtyBitmap {
>>       int64_t size;               /* Size of the bitmap (Number of sectors) */
>>       bool disabled;              /* Bitmap is read-only */
>>       int active_iterators;       /* How many iterators are active */
>> +    bool persistent;            /* bitmap must be saved to owner disk image */
>>       bool autoload;              /* For persistent bitmaps: bitmap must be
>>                                      autoloaded on image opening */
>>       QLIST_ENTRY(BdrvDirtyBitmap) list;
>> @@ -73,6 +74,7 @@ void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
>>       g_free(bitmap->name);
>>       bitmap->name = NULL;
>>   
>> +    bitmap->persistent = false;
>>       bitmap->autoload = false;
>>   }
>>   
>> @@ -242,6 +244,8 @@ BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
>>       bitmap->name = NULL;
>>       successor->name = name;
>>       bitmap->successor = NULL;
>> +    successor->persistent = bitmap->persistent;
>> +    bitmap->persistent = false;
>>       successor->autoload = bitmap->autoload;
>>       bitmap->autoload = false;
>>       bdrv_release_dirty_bitmap(bs, bitmap);
>> @@ -556,3 +560,25 @@ bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
>>   {
>>       return bitmap->autoload;
>>   }
>> +
>> +void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
>> +{
>> +    bitmap->persistent = persistent;
>> +}
>> +
>> +bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
>> +{
>> +    return bitmap->persistent;
>> +}
>> +
>> +bool bdrv_has_persistent_bitmaps(BlockDriverState *bs)
>> +{
>> +    BdrvDirtyBitmap *bm;
>> +    QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
>> +        if (bm->persistent) {
>> +            return true;
>> +        }
>> +    }
>> +
>> +    return false;
>> +}
> Probably not worth optimizing.
>
>> diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
>> index bcbb0491ee..9af658a0f4 100644
>> --- a/block/qcow2-bitmap.c
>> +++ b/block/qcow2-bitmap.c
>> @@ -707,6 +707,7 @@ void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
>>                   goto fail;
>>               }
>>   
>> +            bdrv_dirty_bitmap_set_persistance(bitmap, true);
>>               bdrv_dirty_bitmap_set_autoload(bitmap, true);
>>               bm->flags |= BME_FLAG_IN_USE;
>>               created_dirty_bitmaps =
>> diff --git a/include/block/block.h b/include/block/block.h
>> index 154ac7f955..0a20d68f0f 100644
>> --- a/include/block/block.h
>> +++ b/include/block/block.h
>> @@ -552,5 +552,6 @@ void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
>>   void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
>>   
>>   void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
>> +void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
>>   
>>   #endif
>> diff --git a/include/block/block_int.h b/include/block/block_int.h
>> index 6b2b50c6a2..c3505da56e 100644
>> --- a/include/block/block_int.h
>> +++ b/include/block/block_int.h
>> @@ -322,6 +322,8 @@ struct BlockDriver {
>>   
>>       void (*bdrv_load_autoloading_dirty_bitmaps)(BlockDriverState *bs,
>>                                                   Error **errp);
>> +    void (*bdrv_store_persistent_dirty_bitmaps)(BlockDriverState *bs,
>> +                                                Error **errp);
>>   
>>       QLIST_ENTRY(BlockDriver) list;
>>   };
>> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
>> index 45a389a20a..8dbd16b040 100644
>> --- a/include/block/dirty-bitmap.h
>> +++ b/include/block/dirty-bitmap.h
>> @@ -77,4 +77,10 @@ void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
>>   
>>   void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
>>   bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
>> +void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
>> +                                                bool persistent);
>> +bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
>> +
>> +bool bdrv_has_persistent_bitmaps(BlockDriverState *bs);
>> +
>>   #endif
>>
> Reviewed-by: John Snow <jsnow@redhat.com>
John Snow Feb. 14, 2017, 5:35 p.m. UTC | #3
On 02/14/2017 07:05 AM, Vladimir Sementsov-Ogievskiy wrote:
> 11.02.2017 02:20, John Snow wrote:
>> On 02/03/2017 04:40 AM, Vladimir Sementsov-Ogievskiy wrote:

>>> +void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error
>>> **errp)
>>> +{
>>> +    BlockDriver *drv = bs->drv;
>>> +
>>> +    if (!bdrv_has_persistent_bitmaps(bs)) {
>>> +        return;
>>> +    }
>>> +
>>> +    if (!drv) {
>>> +        error_setg_errno(errp, ENOMEDIUM,
>>> +                         "Can't store persistent bitmaps to %s",
>>> +                         bdrv_get_device_or_node_name(bs));
>>> +        return;
>>> +    }
>>> +
>>> +    if (!drv->bdrv_store_persistent_dirty_bitmaps) {
>>> +        error_setg_errno(errp, ENOTSUP,
>>> +                         "Can't store persistent bitmaps to %s",
>>> +                         bdrv_get_device_or_node_name(bs));
>>> +        return;
>>> +    }
>>> +
>> I suppose this is for the case for where we have added a persistent
>> bitmap during runtime, but the driver does not support it?
>>
>> I'd rather fail this type of thing earlier if possible, but I'm not that
>> far in your series yet.
> 
> qmp bitmap add checks for availability of
> drv->bdrv_can_store_new_dirty_bitmap,
> and loaded bitmaps of course should be attached to bds with appropriate
> driver.
> So, it is mostly a paranoic check.
> 

OK, understood. Not a problem, then.

--js
diff mbox

Patch

diff --git a/block.c b/block.c
index 56f030c562..970e4ca50e 100644
--- a/block.c
+++ b/block.c
@@ -2321,6 +2321,7 @@  void bdrv_reopen_abort(BDRVReopenState *reopen_state)
 static void bdrv_close(BlockDriverState *bs)
 {
     BdrvAioNotifier *ban, *ban_next;
+    Error *local_err = NULL;
 
     assert(!bs->job);
     assert(!bs->refcnt);
@@ -2329,6 +2330,12 @@  static void bdrv_close(BlockDriverState *bs)
     bdrv_flush(bs);
     bdrv_drain(bs); /* in case flush left pending I/O */
 
+    bdrv_store_persistent_dirty_bitmaps(bs, &local_err);
+    if (local_err != NULL) {
+        error_report_err(local_err);
+        error_report("Persistent bitmaps are lost for node '%s'",
+                     bdrv_get_device_or_node_name(bs));
+    }
     bdrv_release_named_dirty_bitmaps(bs);
     assert(QLIST_EMPTY(&bs->dirty_bitmaps));
 
@@ -4107,3 +4114,28 @@  void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
         bs->drv->bdrv_load_autoloading_dirty_bitmaps(bs, errp);
     }
 }
+
+void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp)
+{
+    BlockDriver *drv = bs->drv;
+
+    if (!bdrv_has_persistent_bitmaps(bs)) {
+        return;
+    }
+
+    if (!drv) {
+        error_setg_errno(errp, ENOMEDIUM,
+                         "Can't store persistent bitmaps to %s",
+                         bdrv_get_device_or_node_name(bs));
+        return;
+    }
+
+    if (!drv->bdrv_store_persistent_dirty_bitmaps) {
+        error_setg_errno(errp, ENOTSUP,
+                         "Can't store persistent bitmaps to %s",
+                         bdrv_get_device_or_node_name(bs));
+        return;
+    }
+
+    drv->bdrv_store_persistent_dirty_bitmaps(bs, errp);
+}
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 2d27494dc7..4d026df1bd 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -44,6 +44,7 @@  struct BdrvDirtyBitmap {
     int64_t size;               /* Size of the bitmap (Number of sectors) */
     bool disabled;              /* Bitmap is read-only */
     int active_iterators;       /* How many iterators are active */
+    bool persistent;            /* bitmap must be saved to owner disk image */
     bool autoload;              /* For persistent bitmaps: bitmap must be
                                    autoloaded on image opening */
     QLIST_ENTRY(BdrvDirtyBitmap) list;
@@ -73,6 +74,7 @@  void bdrv_dirty_bitmap_make_anon(BdrvDirtyBitmap *bitmap)
     g_free(bitmap->name);
     bitmap->name = NULL;
 
+    bitmap->persistent = false;
     bitmap->autoload = false;
 }
 
@@ -242,6 +244,8 @@  BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
     bitmap->name = NULL;
     successor->name = name;
     bitmap->successor = NULL;
+    successor->persistent = bitmap->persistent;
+    bitmap->persistent = false;
     successor->autoload = bitmap->autoload;
     bitmap->autoload = false;
     bdrv_release_dirty_bitmap(bs, bitmap);
@@ -556,3 +560,25 @@  bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap)
 {
     return bitmap->autoload;
 }
+
+void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap, bool persistent)
+{
+    bitmap->persistent = persistent;
+}
+
+bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap)
+{
+    return bitmap->persistent;
+}
+
+bool bdrv_has_persistent_bitmaps(BlockDriverState *bs)
+{
+    BdrvDirtyBitmap *bm;
+    QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
+        if (bm->persistent) {
+            return true;
+        }
+    }
+
+    return false;
+}
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index bcbb0491ee..9af658a0f4 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -707,6 +707,7 @@  void qcow2_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp)
                 goto fail;
             }
 
+            bdrv_dirty_bitmap_set_persistance(bitmap, true);
             bdrv_dirty_bitmap_set_autoload(bitmap, true);
             bm->flags |= BME_FLAG_IN_USE;
             created_dirty_bitmaps =
diff --git a/include/block/block.h b/include/block/block.h
index 154ac7f955..0a20d68f0f 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -552,5 +552,6 @@  void bdrv_add_child(BlockDriverState *parent, BlockDriverState *child,
 void bdrv_del_child(BlockDriverState *parent, BdrvChild *child, Error **errp);
 
 void bdrv_load_autoloading_dirty_bitmaps(BlockDriverState *bs, Error **errp);
+void bdrv_store_persistent_dirty_bitmaps(BlockDriverState *bs, Error **errp);
 
 #endif
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 6b2b50c6a2..c3505da56e 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -322,6 +322,8 @@  struct BlockDriver {
 
     void (*bdrv_load_autoloading_dirty_bitmaps)(BlockDriverState *bs,
                                                 Error **errp);
+    void (*bdrv_store_persistent_dirty_bitmaps)(BlockDriverState *bs,
+                                                Error **errp);
 
     QLIST_ENTRY(BlockDriver) list;
 };
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 45a389a20a..8dbd16b040 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -77,4 +77,10 @@  void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
 
 void bdrv_dirty_bitmap_set_autoload(BdrvDirtyBitmap *bitmap, bool autoload);
 bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
+void bdrv_dirty_bitmap_set_persistance(BdrvDirtyBitmap *bitmap,
+                                                bool persistent);
+bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
+
+bool bdrv_has_persistent_bitmaps(BlockDriverState *bs);
+
 #endif