Skip to contentSkip to conversation

Dirty bitmaps fixing and refactoring

PATCH In review Vladimir Sementsov-Ogievskiy 2 participants 17 messages Apr 16, 2018 – Apr 20, 2018 Block layer

lore
Share & tools
lore
#0 lore raw

v2 cover Dirty bitmaps fixing and refactoring

v2:

05: drop bdrv_undo_clear_dirty_bitmap(), which becomes unused.

Vladimir Sementsov-Ogievskiy (7):
block/dirty-bitmap: add lock to bdrv_enable/disable_dirty_bitmap
dirty-bitmaps: fix comment about dirty_bitmap_mutex
dirty-bitmap: remove missed bdrv_dirty_bitmap_get_autoload header
dirty-bitmap: separate unused meta-bitmap related functions
blockdev: refactor block-dirty-bitmap-clear transaction block/dirty-bitmap: bdrv_clear_dirty_bitmap: drop unused parameter
blockdev: unify block-dirty-bitmap-clear command and transaction
action

 include/block/block_int.h    | 15 ++++++----
 include/block/dirty-bitmap.h | 15 ++++++----
 block/dirty-bitmap.c         | 32 +++++++++-----------
 blockdev.c                   | 69 ++++++++++++++------------------------------
 4 files changed, 54 insertions(+), 77 deletions(-)
Signature · 1 line
2.11.1
#1 lore raw

PATCH v2 1/7 block/dirty-bitmap: add lock to bdrv_enable/disable_dirty_bitmap

Functions write to BdrvDirtyBitmap field, so the should take the lock.

---
 block/dirty-bitmap.c | 4 ++++
 1 file changed, 4 insertions(+)
block/dirty-bitmap.c +4 -0
index 967159479d..6c00288fd7 100644
@@ -445,15 +445,19 @@ void bdrv_remove_persistent_dirty_bitmap(BlockDriverState *bs,
 /* Called with BQL taken.  */
 void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
 {
+    bdrv_dirty_bitmap_lock(bitmap);
     assert(!bdrv_dirty_bitmap_frozen(bitmap));
     bitmap->disabled = true;
+    bdrv_dirty_bitmap_unlock(bitmap);
 }
 
 /* Called with BQL taken.  */
 void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
 {
+    bdrv_dirty_bitmap_lock(bitmap);
     assert(!bdrv_dirty_bitmap_frozen(bitmap));
     bitmap->disabled = false;
+    bdrv_dirty_bitmap_unlock(bitmap);
 }
 
 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
Signature · 1 line
2.11.1
#3 lore raw

PATCH v2 2/7 dirty-bitmaps: fix comment about dirty_bitmap_mutex

In reply to Vladimir Sementsov-Ogievskiy

Clarify first two cases and fix Modify -> Any access in third case. Also, drop 'only' from third case, as it a bit confuses, when thinking about case where we modify BdrvDirtyBitmap and access HBitmap.

---
 include/block/block_int.h | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
include/block/block_int.h +8 -4
index c4dd1d4bb8..189666efa5 100644
@@ -709,10 +709,14 @@ struct BlockDriverState {
     uint64_t write_threshold_offset;
     NotifierWithReturn write_threshold_notifier;
 
-    /* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex.
-     * Reading from the list can be done with either the BQL or the
-     * dirty_bitmap_mutex.  Modifying a bitmap only requires
-     * dirty_bitmap_mutex.  */
+    /* Writing to the list (i.e. to any field of BdrvDirtyBitmap or to the
+     * list-head) requires both the BQL _and_ the dirty_bitmap_mutex.
+     *
+     * Reading from the list (from any field of BdrvDirtyBitmap or from the
+     * list-head) can be done with either the BQL or the dirty_bitmap_mutex.
+     *
+     * Any access to underlying HBitmap requires dirty_bitmap_mutex.
+     */
     QemuMutex dirty_bitmap_mutex;
     QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
 
Signature · 1 line
2.11.1
Reviewed-by on v2 2/7
#4 lore raw

Re: [Qemu-devel] [PATCH v2 2/7] dirty-bitmaps: fix comment about dirty_bitmap_mutex

Quoted 18 lines · Vladimir Sementsov-Ogievskiy

Clarify first two cases and fix Modify -> Any access in third case. Also, drop 'only' from third case, as it a bit confuses, when thinking about case where we modify BdrvDirtyBitmap and access HBitmap.

---
 include/block/block_int.h | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
include/block/block_int.h +0 -1
index c4dd1d4bb8..189666efa5 100644
@@ -709,10 +709,14 @@ struct BlockDriverState {
     uint64_t write_threshold_offset;
     NotifierWithReturn write_threshold_notifier;
 
-    /* Writing to the list requires the BQL _and_ the dirty_bitmap_mutex.

include/block/block_int.h struct BlockDriverState { · line 718

Quoted 10 lines
include/block/block_int.h +7 -3
-     * Reading from the list can be done with either the BQL or the
-     * dirty_bitmap_mutex.  Modifying a bitmap only requires
-     * dirty_bitmap_mutex.  */
+    /* Writing to the list (i.e. to any field of BdrvDirtyBitmap or to the
+     * list-head) requires both the BQL _and_ the dirty_bitmap_mutex.
+     *
+     * Reading from the list (from any field of BdrvDirtyBitmap or from the
+     * list-head) can be done with either the BQL or the dirty_bitmap_mutex.
+     *
+     * Any access to underlying HBitmap requires dirty_bitmap_mutex.

"to the underlying HBitmap," probably.

include/block/block_int.h struct BlockDriverState { · line 722

Quoted 5 lines
include/block/block_int.h +1 -0
+     */
     QemuMutex dirty_bitmap_mutex;
     QLIST_HEAD(, BdrvDirtyBitmap) dirty_bitmaps;
 
#5 lore raw

PATCH v2 3/7 dirty-bitmap: remove missed bdrv_dirty_bitmap_get_autoload header

In reply to Vladimir Sementsov-Ogievskiy
---
 include/block/dirty-bitmap.h | 1 -
 1 file changed, 1 deletion(-)
include/block/dirty-bitmap.h +0 -1
index 1ff8949b1b..c7e910016d 100644
@@ -88,7 +88,6 @@ int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
 bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
 bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
-bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap);
 bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs);
Signature · 1 line
2.11.1
Reviewed-by on v2 3/7
#6 lore raw

Re: [Qemu-devel] [PATCH v2 3/7] dirty-bitmap: remove missed bdrv_dirty_bitmap_get_autoload header

Quoted 11 lines · Vladimir Sementsov-Ogievskiy
---
 include/block/dirty-bitmap.h | 1 -
 1 file changed, 1 deletion(-)
include/block/dirty-bitmap.h +0 -0
index 1ff8949b1b..c7e910016d 100644

include/block/dirty-bitmap.h int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap); · line 93

Quoted 7 lines
include/block/dirty-bitmap.h +0 -1
@@ -88,7 +88,6 @@ int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
 bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
 bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
-bool bdrv_dirty_bitmap_get_autoload(const BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_get_persistance(BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_qmp_locked(BdrvDirtyBitmap *bitmap);
 bool bdrv_has_changed_persistent_bitmaps(BlockDriverState *bs);

Assuming you checked for others as well.

#7 lore raw

PATCH v2 4/7 dirty-bitmap: separate unused meta-bitmap related functions

In reply to Vladimir Sementsov-Ogievskiy

Separate them in the header and clarify needed locking in comments.

---
 include/block/dirty-bitmap.h | 14 +++++++++-----
 block/dirty-bitmap.c         |  5 +++++
 2 files changed, 14 insertions(+), 5 deletions(-)
include/block/dirty-bitmap.h +9 -5
index c7e910016d..b7ccfd1363 100644
@@ -9,9 +9,6 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
                                           uint32_t granularity,
                                           const char *name,
                                           Error **errp);
-void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
-                                   int chunk_size);
-void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
 int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
                                        BdrvDirtyBitmap *bitmap,
                                        Error **errp);
@@ -45,7 +42,6 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                            int64_t offset, int64_t bytes);
 void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                              int64_t offset, int64_t bytes);
-BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
 BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
 
@@ -84,7 +80,6 @@ void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
 int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
 void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset);
 int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
-int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
 bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
 bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
@@ -99,4 +94,13 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
                                                   BdrvDirtyBitmap *bitmap,
                                                   Error **errp);
 
+/*
+ * Unused for now meta-bitmaps related functions
+ */
+
+void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap, int chunk_size);
+void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
+BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
+int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
+
 #endif
block/dirty-bitmap.c +5 -0
index 6c00288fd7..1812e17549 100644
@@ -149,6 +149,8 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
  * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
  * @chunk_size: how many bytes of bitmap data does each bit in the meta bitmap
  * track.
+ *
+ * Called with BQL taken.
  */
 void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                                    int chunk_size)
@@ -160,6 +162,7 @@ void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
     qemu_mutex_unlock(bitmap->mutex);
 }
 
+/* Called with BQL taken. */
 void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
 {
     assert(bitmap->meta);
@@ -529,6 +532,7 @@ BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap)
     return iter;
 }
 
+/* Called with BQL and dirty_bitmap_mutex locked. */
 BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap)
 {
     BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
@@ -688,6 +692,7 @@ int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
     return hbitmap_count(bitmap->bitmap);
 }
 
+/* Called with BQL or dirty_bitmap_mutex locked */
 int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
 {
     return hbitmap_count(bitmap->meta);
Signature · 1 line
2.11.1
#8 lore raw

Re: [Qemu-devel] [PATCH v2 4/7] dirty-bitmap: separate unused meta-bitmap related functions

Quoted 39 lines · Vladimir Sementsov-Ogievskiy

Separate them in the header and clarify needed locking in comments.

---
 include/block/dirty-bitmap.h | 14 +++++++++-----
 block/dirty-bitmap.c         |  5 +++++
 2 files changed, 14 insertions(+), 5 deletions(-)
include/block/dirty-bitmap.h +0 -5
index c7e910016d..b7ccfd1363 100644
@@ -9,9 +9,6 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
                                           uint32_t granularity,
                                           const char *name,
                                           Error **errp);
-void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
-                                   int chunk_size);
-void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
 int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
                                        BdrvDirtyBitmap *bitmap,
                                        Error **errp);
@@ -45,7 +42,6 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                            int64_t offset, int64_t bytes);
 void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                              int64_t offset, int64_t bytes);
-BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
 BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
 
@@ -84,7 +80,6 @@ void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
 int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
 void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset);
 int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
-int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
 bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
 bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);

include/block/dirty-bitmap.h BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, · line 100

Quoted 7 lines
include/block/dirty-bitmap.h +4 -0
@@ -99,4 +94,13 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
                                                   BdrvDirtyBitmap *bitmap,
                                                   Error **errp);
 
+/*
+ * Unused for now meta-bitmaps related functions
+ */
+

I assume you have plans to use them still? I thought these were useful for storage migration -- but I guess we don't use these for the postcopy mechanism?

Quoted 44 lines
include/block/dirty-bitmap.h +5 -0
+void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap, int chunk_size);
+void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
+BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
+int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
+
 #endif
block/dirty-bitmap.c +5 -0
index 6c00288fd7..1812e17549 100644
@@ -149,6 +149,8 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
  * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
  * @chunk_size: how many bytes of bitmap data does each bit in the meta bitmap
  * track.
+ *
+ * Called with BQL taken.
  */
 void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                                    int chunk_size)
@@ -160,6 +162,7 @@ void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
     qemu_mutex_unlock(bitmap->mutex);
 }
 
+/* Called with BQL taken. */
 void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
 {
     assert(bitmap->meta);
@@ -529,6 +532,7 @@ BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap)
     return iter;
 }
 
+/* Called with BQL and dirty_bitmap_mutex locked. */
 BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap)
 {
     BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
@@ -688,6 +692,7 @@ int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
     return hbitmap_count(bitmap->bitmap);
 }
 
+/* Called with BQL or dirty_bitmap_mutex locked */
 int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
 {
     return hbitmap_count(bitmap->meta);
#9 lore raw

Re: [Qemu-devel] [PATCH v2 4/7] dirty-bitmap: separate unused meta-bitmap related functions

Quoted 43 lines · John Snow
Quoted 42 lines · Vladimir Sementsov-Ogievskiy

Separate them in the header and clarify needed locking in comments.

---
  include/block/dirty-bitmap.h | 14 +++++++++-----
  block/dirty-bitmap.c         |  5 +++++
  2 files changed, 14 insertions(+), 5 deletions(-)
include/block/dirty-bitmap.h +0 -5
index c7e910016d..b7ccfd1363 100644
@@ -9,9 +9,6 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
                                            uint32_t granularity,
                                            const char *name,
                                            Error **errp);
-void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
-                                   int chunk_size);
-void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
  int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
                                         BdrvDirtyBitmap *bitmap,
                                         Error **errp);
@@ -45,7 +42,6 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                             int64_t offset, int64_t bytes);
  void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                               int64_t offset, int64_t bytes);
-BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
  BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap);
  void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
 
@@ -84,7 +80,6 @@ void bdrv_reset_dirty_bitmap_locked(BdrvDirtyBitmap *bitmap,
  int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
  void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t offset);
  int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
-int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
  void bdrv_dirty_bitmap_truncate(BlockDriverState *bs, int64_t bytes);
  bool bdrv_dirty_bitmap_readonly(const BdrvDirtyBitmap *bitmap);
  bool bdrv_has_readonly_bitmaps(BlockDriverState *bs);
@@ -99,4 +94,13 @@ BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs,
                                                    BdrvDirtyBitmap *bitmap,
                                                    Error **errp);
 
Quoted 7 lines

include/block/dirty-bitmap.h BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap_locked(BlockDriverState *bs, · line 100

Quoted 4 lines
include/block/dirty-bitmap.h +4 -0
+/*
+ * Unused for now meta-bitmaps related functions
+ */
+

I assume you have plans to use them still? I thought these were useful for storage migration -- but I guess we don't use these for the postcopy mechanism?

I don't have plans for near future, so for me it's ok to drop them.

Theoretical usage is partial storing (if we know, which portions of bitmaps are changed, we can save to file only these portions, not the whole bitmaps), but it don't look like near future. May be, Fam has some plans?

Quoted 45 lines
Quoted 45 lines
include/block/dirty-bitmap.h +5 -0
+void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap, int chunk_size);
+void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
+BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
+int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
+
  #endif
block/dirty-bitmap.c +5 -0
index 6c00288fd7..1812e17549 100644
@@ -149,6 +149,8 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
   * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
   * @chunk_size: how many bytes of bitmap data does each bit in the meta bitmap
   * track.
+ *
+ * Called with BQL taken.
   */
  void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                                     int chunk_size)
@@ -160,6 +162,7 @@ void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
      qemu_mutex_unlock(bitmap->mutex);
  }
 
+/* Called with BQL taken. */
  void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
  {
      assert(bitmap->meta);
@@ -529,6 +532,7 @@ BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap)
      return iter;
  }
 
+/* Called with BQL and dirty_bitmap_mutex locked. */
  BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap)
  {
      BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
@@ -688,6 +692,7 @@ int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
      return hbitmap_count(bitmap->bitmap);
  }
 
+/* Called with BQL or dirty_bitmap_mutex locked */
  int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
  {
      return hbitmap_count(bitmap->meta);
Signature · 2 lines
Best regards,
Vladimir
#10 lore raw

PATCH v2 5/7 blockdev: refactor block-dirty-bitmap-clear transaction

In reply to Vladimir Sementsov-Ogievskiy

bdrv_clear_dirty_bitmap do not fail, so we can call it in transaction commit, avoiding any rollback.

After this, bdrv_undo_clear_dirty_bitmap() becomes unused, so, drop it.

---
 include/block/block_int.h |  1 -
 block/dirty-bitmap.c      |  9 ---------
 blockdev.c                | 16 +---------------
 3 files changed, 1 insertion(+), 25 deletions(-)
include/block/block_int.h +0 -1
index 189666efa5..22059c8119 100644
@@ -1087,7 +1087,6 @@ bool blk_dev_is_medium_locked(BlockBackend *blk);
 void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
 
 void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
 
 void bdrv_inc_in_flight(BlockDriverState *bs);
 void bdrv_dec_in_flight(BlockDriverState *bs);
block/dirty-bitmap.c +0 -9
index 1812e17549..3c69a8eed9 100644
@@ -607,15 +607,6 @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
     bdrv_dirty_bitmap_unlock(bitmap);
 }
 
-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
-{
-    HBitmap *tmp = bitmap->bitmap;
-    assert(bdrv_dirty_bitmap_enabled(bitmap));
-    assert(!bdrv_dirty_bitmap_readonly(bitmap));
-    bitmap->bitmap = in;
-    hbitmap_free(tmp);
-}
-
 uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
                                               uint64_t offset, uint64_t bytes)
 {
blockdev.c +1 -15
index c31bf3d98d..88eae60c1c 100644
@@ -2050,7 +2050,6 @@ typedef struct BlockDirtyBitmapState {
     BlkActionState common;
     BdrvDirtyBitmap *bitmap;
     BlockDriverState *bs;
-    HBitmap *backup;
     bool prepared;
 } BlockDirtyBitmapState;
 
@@ -2129,18 +2128,6 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
         error_setg(errp, "Cannot clear a readonly bitmap");
         return;
     }
-
-    bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
-}
-
-static void block_dirty_bitmap_clear_abort(BlkActionState *common)
-{
-    BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
-                                             common, common);
-
-    if (state->backup) {
-        bdrv_undo_clear_dirty_bitmap(state->bitmap, state->backup);
-    }
 }
 
 static void block_dirty_bitmap_clear_commit(BlkActionState *common)
@@ -2148,7 +2135,7 @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common)
     BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
                                              common, common);
 
-    hbitmap_free(state->backup);
+    bdrv_clear_dirty_bitmap(state->bitmap, NULL);
 }
 
 static void abort_prepare(BlkActionState *common, Error **errp)
@@ -2210,7 +2197,6 @@ static const BlkActionOps actions[] = {
         .instance_size = sizeof(BlockDirtyBitmapState),
         .prepare = block_dirty_bitmap_clear_prepare,
         .commit = block_dirty_bitmap_clear_commit,
-        .abort = block_dirty_bitmap_clear_abort,
     }
 };
 
Signature · 1 line
2.11.1
#11 lore raw

Re: [Qemu-devel] [PATCH v2 5/7] blockdev: refactor block-dirty-bitmap-clear transaction

Quoted 5 lines · Vladimir Sementsov-Ogievskiy

bdrv_clear_dirty_bitmap do not fail, so we can call it in transaction commit, avoiding any rollback.

After this, bdrv_undo_clear_dirty_bitmap() becomes unused, so, drop it.

I'm trying to remember why we ever bothered doing it the other way. Is it because of timings with respect to other operations and we wanted the "clear" to take effect sooner rather than later to co-operate with other commands?

(You and Nikolay hinted about similar problems in the Libvirt PULL api thread, too. It continues to be an issue.)

Hopping in my time machine:

https://lists.gnu.org/archive/html/qemu-devel/2015-05/msg01229.html

(Oh, I wrote it...)

Looks like it was a conscious decision to avoid ordering conflicts with other block jobs.

Quoted 88 lines
---
 include/block/block_int.h |  1 -
 block/dirty-bitmap.c      |  9 ---------
 blockdev.c                | 16 +---------------
 3 files changed, 1 insertion(+), 25 deletions(-)
include/block/block_int.h +0 -1
index 189666efa5..22059c8119 100644
@@ -1087,7 +1087,6 @@ bool blk_dev_is_medium_locked(BlockBackend *blk);
 void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
 
 void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
 
 void bdrv_inc_in_flight(BlockDriverState *bs);
 void bdrv_dec_in_flight(BlockDriverState *bs);
block/dirty-bitmap.c +0 -9
index 1812e17549..3c69a8eed9 100644
@@ -607,15 +607,6 @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
     bdrv_dirty_bitmap_unlock(bitmap);
 }
 
-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
-{
-    HBitmap *tmp = bitmap->bitmap;
-    assert(bdrv_dirty_bitmap_enabled(bitmap));
-    assert(!bdrv_dirty_bitmap_readonly(bitmap));
-    bitmap->bitmap = in;
-    hbitmap_free(tmp);
-}
-
 uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
                                               uint64_t offset, uint64_t bytes)
 {
blockdev.c +1 -15
index c31bf3d98d..88eae60c1c 100644
@@ -2050,7 +2050,6 @@ typedef struct BlockDirtyBitmapState {
     BlkActionState common;
     BdrvDirtyBitmap *bitmap;
     BlockDriverState *bs;
-    HBitmap *backup;
     bool prepared;
 } BlockDirtyBitmapState;
 
@@ -2129,18 +2128,6 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
         error_setg(errp, "Cannot clear a readonly bitmap");
         return;
     }
-
-    bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
-}
-
-static void block_dirty_bitmap_clear_abort(BlkActionState *common)
-{
-    BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
-                                             common, common);
-
-    if (state->backup) {
-        bdrv_undo_clear_dirty_bitmap(state->bitmap, state->backup);
-    }
 }
 
 static void block_dirty_bitmap_clear_commit(BlkActionState *common)
@@ -2148,7 +2135,7 @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common)
     BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
                                              common, common);
 
-    hbitmap_free(state->backup);
+    bdrv_clear_dirty_bitmap(state->bitmap, NULL);
 }
 
 static void abort_prepare(BlkActionState *common, Error **errp)
@@ -2210,7 +2197,6 @@ static const BlkActionOps actions[] = {
         .instance_size = sizeof(BlockDirtyBitmapState),
         .prepare = block_dirty_bitmap_clear_prepare,
         .commit = block_dirty_bitmap_clear_commit,
-        .abort = block_dirty_bitmap_clear_abort,
     }
 };
 
#12 lore raw

Re: [Qemu-devel] [PATCH v2 5/7] blockdev: refactor block-dirty-bitmap-clear transaction

Quoted 15 lines · John Snow
Quoted 5 lines · Vladimir Sementsov-Ogievskiy

bdrv_clear_dirty_bitmap do not fail, so we can call it in transaction commit, avoiding any rollback.

After this, bdrv_undo_clear_dirty_bitmap() becomes unused, so, drop it.

I'm trying to remember why we ever bothered doing it the other way. Is it because of timings with respect to other operations and we wanted the "clear" to take effect sooner rather than later to co-operate with other commands?

(You and Nikolay hinted about similar problems in the Libvirt PULL api thread, too. It continues to be an issue.)

Quoted 8 lines

Hopping in my time machine:

https://lists.gnu.org/archive/html/qemu-devel/2015-05/msg01229.html

(Oh, I wrote it...)

Looks like it was a conscious decision to avoid ordering conflicts with other block jobs.

ohh, interesting.. so, transactions are tricky.

Don't you think, that this letter shows, that backup transaction is wrong, rather than clear?

I think, when we write a transaction, we should understand, that full effect of the operation will be achieved only after corresponding .commit. So, backup should not do in .prepare something dependent on other operations.

Quoted 89 lines
Quoted 89 lines
---
  include/block/block_int.h |  1 -
  block/dirty-bitmap.c      |  9 ---------
  blockdev.c                | 16 +---------------
  3 files changed, 1 insertion(+), 25 deletions(-)
include/block/block_int.h +0 -1
index 189666efa5..22059c8119 100644
@@ -1087,7 +1087,6 @@ bool blk_dev_is_medium_locked(BlockBackend *blk);
  void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
 
  void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in);
 
  void bdrv_inc_in_flight(BlockDriverState *bs);
  void bdrv_dec_in_flight(BlockDriverState *bs);
block/dirty-bitmap.c +0 -9
index 1812e17549..3c69a8eed9 100644
@@ -607,15 +607,6 @@ void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
      bdrv_dirty_bitmap_unlock(bitmap);
  }
 
-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
-{
-    HBitmap *tmp = bitmap->bitmap;
-    assert(bdrv_dirty_bitmap_enabled(bitmap));
-    assert(!bdrv_dirty_bitmap_readonly(bitmap));
-    bitmap->bitmap = in;
-    hbitmap_free(tmp);
-}
-
  uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
                                                uint64_t offset, uint64_t bytes)
  {
blockdev.c +1 -15
index c31bf3d98d..88eae60c1c 100644
@@ -2050,7 +2050,6 @@ typedef struct BlockDirtyBitmapState {
      BlkActionState common;
      BdrvDirtyBitmap *bitmap;
      BlockDriverState *bs;
-    HBitmap *backup;
      bool prepared;
  } BlockDirtyBitmapState;
 
@@ -2129,18 +2128,6 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
          error_setg(errp, "Cannot clear a readonly bitmap");
          return;
      }
-
-    bdrv_clear_dirty_bitmap(state->bitmap, &state->backup);
-}
-
-static void block_dirty_bitmap_clear_abort(BlkActionState *common)
-{
-    BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
-                                             common, common);
-
-    if (state->backup) {
-        bdrv_undo_clear_dirty_bitmap(state->bitmap, state->backup);
-    }
  }
 
  static void block_dirty_bitmap_clear_commit(BlkActionState *common)
@@ -2148,7 +2135,7 @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common)
      BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
                                               common, common);
 
-    hbitmap_free(state->backup);
+    bdrv_clear_dirty_bitmap(state->bitmap, NULL);
  }
 
  static void abort_prepare(BlkActionState *common, Error **errp)
@@ -2210,7 +2197,6 @@ static const BlkActionOps actions[] = {
          .instance_size = sizeof(BlockDirtyBitmapState),
          .prepare = block_dirty_bitmap_clear_prepare,
          .commit = block_dirty_bitmap_clear_commit,
-        .abort = block_dirty_bitmap_clear_abort,
      }
  };
 
Signature · 2 lines
Best regards,
Vladimir
#13 lore raw

Re: [Qemu-devel] [PATCH v2 5/7] blockdev: refactor block-dirty-bitmap-clear transaction

In reply to Vladimir Sementsov-Ogievskiy
Quoted 7 lines · Vladimir Sementsov-Ogievskiy

bdrv_clear_dirty_bitmap do not fail, so we can call it in transaction commit, avoiding any rollback.

After this, bdrv_undo_clear_dirty_bitmap() becomes unused, so, drop it.

---

Sorry if it was my idea entirely that led you on this wild goose chase, I had forgotten :(

#14 lore raw

PATCH v2 6/7 block/dirty-bitmap: bdrv_clear_dirty_bitmap: drop unused parameter

In reply to Vladimir Sementsov-Ogievskiy

Drop parameter "HBitmap **out" which is unused now, all callers set it to NULL.

---
 include/block/block_int.h |  2 +-
 block/dirty-bitmap.c      | 14 +++++---------
 blockdev.c                |  4 ++--
 3 files changed, 8 insertions(+), 12 deletions(-)
include/block/block_int.h +1 -1
index 22059c8119..61fac62c06 100644
@@ -1086,7 +1086,7 @@ bool blk_dev_is_medium_locked(BlockBackend *blk);
 
 void bdrv_set_dirty(BlockDriverState *bs, int64_t offset, int64_t bytes);
 
-void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out);
+void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap);
 
 void bdrv_inc_in_flight(BlockDriverState *bs);
 void bdrv_dec_in_flight(BlockDriverState *bs);
block/dirty-bitmap.c +5 -9
index 3c69a8eed9..35600922f5 100644
@@ -591,19 +591,15 @@ void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
     bdrv_dirty_bitmap_unlock(bitmap);
 }
 
-void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
+void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap)
 {
     assert(bdrv_dirty_bitmap_enabled(bitmap));
     assert(!bdrv_dirty_bitmap_readonly(bitmap));
+
     bdrv_dirty_bitmap_lock(bitmap);
-    if (!out) {
-        hbitmap_reset_all(bitmap->bitmap);
-    } else {
-        HBitmap *backup = bitmap->bitmap;
-        bitmap->bitmap = hbitmap_alloc(bitmap->size,
-                                       hbitmap_granularity(backup));
-        *out = backup;
-    }
+
+    hbitmap_reset_all(bitmap->bitmap);
+
     bdrv_dirty_bitmap_unlock(bitmap);
 }
 
blockdev.c +2 -2
index 88eae60c1c..54e1ba8f44 100644
@@ -2135,7 +2135,7 @@ static void block_dirty_bitmap_clear_commit(BlkActionState *common)
     BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
                                              common, common);
 
-    bdrv_clear_dirty_bitmap(state->bitmap, NULL);
+    bdrv_clear_dirty_bitmap(state->bitmap);
 }
 
 static void abort_prepare(BlkActionState *common, Error **errp)
@@ -2906,7 +2906,7 @@ void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
         return;
     }
 
-    bdrv_clear_dirty_bitmap(bitmap, NULL);
+    bdrv_clear_dirty_bitmap(bitmap);
 }
 
 BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
Signature · 1 line
2.11.1
#15 lore raw

Re: [Qemu-devel] [PATCH v2 6/7] block/dirty-bitmap: bdrv_clear_dirty_bitmap: drop unused parameter

Quoted 4 lines · Vladimir Sementsov-Ogievskiy

Drop parameter "HBitmap **out" which is unused now, all callers set it to NULL.

And now this patch is in question too.

#16 lore raw

PATCH v2 7/7 blockdev: unify block-dirty-bitmap-clear command and transaction action

In reply to Vladimir Sementsov-Ogievskiy

- use error messages from qmp command, as they are more descriptive
- we need not check bs, as block_dirty_bitmap_lookup never returns bs = NULL on success (and if user set bs to be not NULL pointer), so, let's just assert it.

---
 blockdev.c | 53 +++++++++++++++++++++--------------------------------
 1 file changed, 21 insertions(+), 32 deletions(-)
blockdev.c +21 -32
index 54e1ba8f44..3f0979298e 100644
@@ -2114,18 +2114,26 @@ static void block_dirty_bitmap_clear_prepare(BlkActionState *common,
     if (!state->bitmap) {
         return;
     }
+    assert(state->bs != NULL);
 
     if (bdrv_dirty_bitmap_frozen(state->bitmap)) {
-        error_setg(errp, "Cannot modify a frozen bitmap");
+        error_setg(errp,
+                   "Bitmap '%s' is currently frozen and cannot be modified",
+                   action->name);
         return;
     } else if (bdrv_dirty_bitmap_qmp_locked(state->bitmap)) {
-        error_setg(errp, "Cannot modify a locked bitmap");
+        error_setg(errp,
+                   "Bitmap '%s' is currently locked and cannot be modified",
+                   action->name);
         return;
     } else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) {
-        error_setg(errp, "Cannot clear a disabled bitmap");
+        error_setg(errp,
+                   "Bitmap '%s' is currently disabled and cannot be cleared",
+                   action->name);
         return;
     } else if (bdrv_dirty_bitmap_readonly(state->bitmap)) {
-        error_setg(errp, "Cannot clear a readonly bitmap");
+        error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared",
+                   action->name);
         return;
     }
 }
@@ -2878,35 +2886,16 @@ void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
 void qmp_block_dirty_bitmap_clear(const char *node, const char *name,
                                   Error **errp)
 {
-    BdrvDirtyBitmap *bitmap;
-    BlockDriverState *bs;
-
-    bitmap = block_dirty_bitmap_lookup(node, name, &bs, errp);
-    if (!bitmap || !bs) {
-        return;
-    }
-
-    if (bdrv_dirty_bitmap_frozen(bitmap)) {
-        error_setg(errp,
-                   "Bitmap '%s' is currently frozen and cannot be modified",
-                   name);
-        return;
-    } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) {
-        error_setg(errp,
-                   "Bitmap '%s' is currently locked and cannot be modified",
-                   name);
-        return;
-    } else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
-        error_setg(errp,
-                   "Bitmap '%s' is currently disabled and cannot be cleared",
-                   name);
-        return;
-    } else if (bdrv_dirty_bitmap_readonly(bitmap)) {
-        error_setg(errp, "Bitmap '%s' is readonly and cannot be cleared", name);
-        return;
-    }
+    BlockDirtyBitmap data = {
+        .node = (char *)node,
+        .name = (char *)name
+    };
+    TransactionAction action = {
+        .type = TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_CLEAR,
+        .u.block_dirty_bitmap_clear.data = &data,
+    };
 
-    bdrv_clear_dirty_bitmap(bitmap);
+    blockdev_do_action(&action, errp);
 }
 
 BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
Signature · 1 line
2.11.1