All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series
@ 2015-01-12 16:30 John Snow
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 01/13] block: fix spoiling all dirty bitmaps by mirror and migration John Snow
                   ` (16 more replies)
  0 siblings, 17 replies; 54+ messages in thread
From: John Snow @ 2015-01-12 16:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

Welcome to version 11. I hope you are enjoying our regular newsletter.

This patchset enables the in-memory part of the incremental backup
feature. A patchset by Vladimir Sementsov-Ogievskiy enables the
migration of in-memory dirty bitmaps, and a future patchset will
enable the storage and retrieval of dirty bitmaps to and from permanent
storage.

Enough changes have been made that most Reviewed-By lines from
previous iterations have been removed. (Sorry!)

This series was originally authored by Fam Zheng;
his cover letter is included below.

~John Snow

=================================================================

This is the in memory part of the incremental backup feature.

With the added commands, we can create a bitmap on a block
backend, from which point of time all the writes are tracked by
the bitmap, marking sectors as dirty. Later, we call drive-backup
and pass the bitmap to it, to do an incremental backup.

See the last patch which adds some tests for this use case.

Fam

=================================================================

For convenience, this patchset is available on github:
                https://github.com/jnsnow/qemu/commits/dbm-backup

v11:

 - Instead of copying BdrvDirtyBitmaps and keeping a pointer to the
   object we were copied from, we instead "freeze" a bitmap in-place
   without copying it. On success, we thaw and delete the bitmap.
   On failure, we merge the bitmap with a "successor," which is an
   anonymous bitmap attached as a child that records writes for us
   for the duration of the backup operation.

   This means that incremental backups can NEVER BE RETRIED in a
   deterministic fashion. If an incremental backup fails on a set
   of dirty sectors {x}, and a new set of dirty sectors {y} are
   introduced during the backup, then any possible retry action
   on an incremental backup can only operate on {x,y}. There is no
   way to get an incremental backup "as it would have been."

   So, the failure mode for incremental backup is to try again,
   and the resulting image will simply be a differential from the
   last successful dirty bitmap backup.

 - Removed hbitmap_copy and bdrv_dirty_bitmap_copy.

 - Added a small fixup patch:
   - Update all granularity fields to be uint64_t.
   - Update documentation around BdrvDirtyBitmap structure.

 - Modified transactions to obey frozen attribute of BdrvDirtyBitmaps.

 - Added frozen attribute to the info query.

v10 (Overview):

 - I've included one of Vladimir's bitmap fixes as patch #1.

 - QMP commands and transactions are now protected via
   aio_context functions.

 - QMP commands use "node-ref" as a parameter name now. Reasoning
   is thus: Either a "device name" or a "node name" can be used to
   reference a BDS, which is the key item we are actually acting
   on with these bitmap commands. Thus, I refer to this unified
   parameter as a "Node Reference," or "node-ref."

   We could also argue for "backend-ref" or "device-ref" for the
   reverse semantics: where we accept a unified parameter, but we
   intend to resolve it to the BlockBackend instead of resolving
   the parameter given to the BlockDriverState.

   Or, we could use "reference" for both cases, and to match the
   existing BlockdevRef command.

 - All QMP commands added are now per-node via a unified parameter
   name. Though backup only operates on "devices," you are free to
   create bitmaps for any arbitrary node you wish. It is obviously
   only useful for the root node, currently.

 - Bitmap Sync modes (CONSUME, RESET) are removed. See below
   (changelog, RFC questions) for more details.

 - Code to recover the bitmap after a failure has been added,
   but I have some major questions about drive_backup guarantees.
   See RFC questions.

v10 (Detailed Changelog):

   (1/13) New Patch:
 - Included Vladimir Sementsov-Ogievskiy's patch that clarifies
   the semantics of the bitmap primitives.

   (3/13):
 - Edited function names for consistency (Stefanha)
 - Removed compile-time constants (Stefanha)
 - Acquire aio_context for bitmap add/remove (Stefanha)
 - Documented optional granularity for bitmap-add in
   qmp-commands.hx file (Eric Blake)
 - block_dirty_bitmap_lookup moved forward to this patch to allow
   more re-use. (Stefanha)
 - Fixed a problem where the block_dirty_bitmap_lookup didn't
   always set an error if it returned NULL.
 - Added an optional return BDS lookup parameter to
   bdrv_dirty_bitmap_lookup.
 - Renamed "device" to "node-ref" for block_dirty_bitmap_lookup,
   adjusted calls to bdrv_lookup_bs() to reflect unified
   parameter usage.
 - qmp_block_dirty_bitmap_{add,remove} now reference arbitrary
   node names via @node-ref.

   (4/13):
 - Default granularity and granularity getters are both
   now uint64_t (Stefanha)

   (5/13):
 - Added documentation to warn about the necessity of updating
   the hbitmap deep copy. (Stefanha)

   (6/13)
 - Renamed bdrv_reset_dirty_bitmap to bdrv_clear_dirty_bitmap
   to be consistent with Vladimir's patches.
 - Removed const qualifier for bdrv_copy_dirty_bitmap,
   to accommodate patch 8.

   (7/13) New Patch:
 - Added an hbitmap_merge operation to join two bitmaps together.

   (8/13) New Patch:
 - Added bdrv_reclaim_dirty_bitmap() to allow us to "roll back" a
   bitmap into the bitmap that it was spawned from. This will let
   us maintain an accurate account of dirty sectors even after a
   failure.
 - This adds an "originator" pointer to the BdrvDirtyBitmap and
   is why "const" was removed for copy.

   (9/13):
 - QMP semantics changes as outlined for Patch #3.
 - Enable/Disable now protected by aio_context (Stefanha)

   (10/13):
 - Add coroutine_fn annotation to block backup helper. (Stefanha)
 - Removed sync_bitmap_gran from BackupBlockJob, just use the
   getter on the BdrvDirtyBitmap instead. (Stefanha)
 - bdrv_dirty_iter_set was renamed to bdrv_set_dirty_iter.
 - Calls to bdrv_reset_dirty_bitmap are modified to
   bdrv_clear_dirty_bitmap to reflect the rename in patch #6.
 - Bitmap usage modes (RESET vs. CONSUME) has been deleted, for
   the reason of targeting a simpler core usage first before
   targeting optimizations. CONSUME is particularly problematic
   in the case of errors; so this mode is omitted for now.
 - Adjusted error message to use MirrorSyncMode enum, not
   (incorrectly) the BitmapSyncMode enum.
 - In the event of a failure, the sync_bitmap is now merged back
   into the original bitmap so that we do not lose any dirty
   bitmap information needlessly.

   (11/13):
 - Changed block_dirty_bitmap_add_abort to use
   qmp_block_dirty_bitmap_remove:
    - Old code used bdrv_lookup_bs to acquire bitmap and bs
      anyway, and ignored the failure case.
    - New code relies on the same information, and with a NULL
      errp pointer we will similarly ignore the failure case.
      prepare() should have properly vetted this information
      before this point anyway.
      This new code is also now protected via aio_context through
      the use of the QMP commands.
 - More code re-use of block_dirty_bitmap_lookup to get both the
   bs and bitmap pointers.
 - aio_context protection and cleanup in new abort methods.

   (13/13):
 - Modified test for new parameter names.

v9:
 - Edited commit message, for English embetterment (02/10)
 - Rebased on top of stefanha/block-next (06,08/10)
 - Adjusted error message and line length (07/10)

v8:
 - Changed int64_t return for bdrv_dbm_calc_def_granularity to uint64_t (2/10)
 - Updated commit message (2/10)
 - Removed redundant check for null in device parameter (2/10)
 - Removed comment cruft. (2/10)
 - Removed redundant local_err propagation (several)
 - Updated commit message (3/10)
 - Fix HBitmap copy loop index (4/10)
 - Remove redundant ternary (5/10)
 - Shift up the block_dirty_bitmap_lookup function (6/10)
 - Error messages cleanup (7/10)
 - Add an assertion to explain the re-use of .prepare() for two transactions.
   (8/10)
 - Removed BDS argument from bitmap enable/disable helper; it was unused. (8/10)

v7: (highlights)
 - First version being authored by jsnow
 - Addressed most list feedback from V6, many small changes.
   All feedback was either addressed on-list (as a wontfix) or patched.
 - Replaced all error_set with error_setg
 - Replaced all bdrv_find with bdrv_lookup_bs()
 - Adjusted the max granularity to share a common function with
   backup/mirror that attempts to "guess" a reasonable default.
   It clamps between [4K,64K] currently.
 - The BdrvDirtyBitmap object now counts granularity exclusively in
   bytes to match its interface.
   It leaves the sector granularity concerns to HBitmap.
 - Reworked the backup loop to utilize the hbitmap iterator.
   There are some extra concerns to handle arrhythmic cases where the
   granularity of the bitmap does not match the backup cluster size.
   This iteration works best when it does match, but it's not a
   deal-breaker if it doesn't -- it just gets less efficient.
 - Reworked the transactional functions so that abort() wouldn't "undo"
   a redundant command. They now have been split into a prepare and a
   commit function (with state) and do not provide an abort command.
 - Added a block_dirty_bitmap_lookup(device, name, errp) function to
   shorten a few of the commands added in this series, particularly
   qmp_enable, qmp_disable, and the transaction preparations.

v6: Re-send of v5.

v5: Rebase to master.

v4: Last version tailored by Fam Zheng.

==

Fam Zheng (7):
  qapi: Add optional field "name" to block dirty bitmap
  qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  block: Introduce bdrv_dirty_bitmap_granularity()
  qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable
  qapi: Add transaction support to block-dirty-bitmap-{add, enable,
    disable}
  qmp: Add dirty bitmap status fields in query-block
  qemu-iotests: Add tests for drive-backup sync=dirty-bitmap

John Snow (5):
  block: Add bdrv_clear_dirty_bitmap
  hbitmap: add hbitmap_merge
  block: Add bitmap successors
  qmp: Add support of "dirty-bitmap" sync mode for drive-backup
  block: BdrvDirtyBitmap miscellaneous fixup

Vladimir Sementsov-Ogievskiy (1):
  block: fix spoiling all dirty bitmaps by mirror and migration

 block.c                       | 254 +++++++++++++++++++++++++++++++++++++--
 block/backup.c                | 120 +++++++++++++++----
 block/mirror.c                |  27 ++---
 blockdev.c                    | 273 +++++++++++++++++++++++++++++++++++++++++-
 hmp.c                         |   3 +-
 include/block/block.h         |  31 ++++-
 include/block/block_int.h     |   2 +
 include/qemu/hbitmap.h        |  11 ++
 migration/block.c             |   7 +-
 qapi-schema.json              |   5 +-
 qapi/block-core.json          | 103 +++++++++++++++-
 qmp-commands.hx               |  68 ++++++++++-
 tests/qemu-iotests/056        |  33 ++++-
 tests/qemu-iotests/056.out    |   4 +-
 tests/qemu-iotests/iotests.py |   8 ++
 util/hbitmap.c                |  28 +++++
 16 files changed, 910 insertions(+), 67 deletions(-)

-- 
1.9.3

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 01/13] block: fix spoiling all dirty bitmaps by mirror and migration
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
@ 2015-01-12 16:30 ` John Snow
  2015-01-13 15:54   ` Vladimir Sementsov-Ogievskiy
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 02/13] qapi: Add optional field "name" to block dirty bitmap John Snow
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-12 16:30 UTC (permalink / raw)
  To: qemu-devel
  Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha,
	Denis V. Lunev

From: Vladimir Sementsov-Ogievskiy <vsementsov@parallels.com>

Mirror and migration use dirty bitmaps for their purposes, and since
commit [block: per caller dirty bitmap] they use their own bitmaps, not
the global one. But they use old functions bdrv_set_dirty and
bdrv_reset_dirty, which change all dirty bitmaps.

Named dirty bitmaps series by Fam and Snow are affected: mirroring and
migration will spoil all (not related to this mirroring or migration)
named dirty bitmaps.

This patch fixes this by adding bdrv_set_dirty_bitmap and
bdrv_reset_dirty_bitmap, which change concrete bitmap. Also, to prevent
such mistakes in future, old functions bdrv_(set,reset)_dirty are made
static, for internal block usage.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@parallels.com>
CC: John Snow <jsnow@redhat.com>
CC: Fam Zheng <famz@redhat.com>
CC: Denis V. Lunev <den@openvz.org>
CC: Stefan Hajnoczi <stefanha@redhat.com>
CC: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c               | 23 ++++++++++++++++++++---
 block/mirror.c        | 11 +++++++----
 include/block/block.h |  6 ++++--
 migration/block.c     |  5 +++--
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/block.c b/block.c
index 4165d42..6c1b49a 100644
--- a/block.c
+++ b/block.c
@@ -97,6 +97,10 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
 static QLIST_HEAD(, BlockDriver) bdrv_drivers =
     QLIST_HEAD_INITIALIZER(bdrv_drivers);
 
+static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
+                           int nr_sectors);
+static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
+                             int nr_sectors);
 /* If non-zero, use only whitelisted block drivers */
 static int use_bdrv_whitelist;
 
@@ -5389,8 +5393,20 @@ void bdrv_dirty_iter_init(BlockDriverState *bs,
     hbitmap_iter_init(hbi, bitmap->bitmap, 0);
 }
 
-void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
-                    int nr_sectors)
+void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
+                           int64_t cur_sector, int nr_sectors)
+{
+    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
+}
+
+void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
+                             int64_t cur_sector, int nr_sectors)
+{
+    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
+}
+
+static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
+                           int nr_sectors)
 {
     BdrvDirtyBitmap *bitmap;
     QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
@@ -5398,7 +5414,8 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
     }
 }
 
-void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors)
+static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
+                             int nr_sectors)
 {
     BdrvDirtyBitmap *bitmap;
     QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
diff --git a/block/mirror.c b/block/mirror.c
index 2c6dd2a..9019d1b 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -128,7 +128,8 @@ static void mirror_write_complete(void *opaque, int ret)
         BlockDriverState *source = s->common.bs;
         BlockErrorAction action;
 
-        bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
+        bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
+                              op->nb_sectors);
         action = mirror_error_action(s, false, -ret);
         if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
             s->ret = ret;
@@ -145,7 +146,8 @@ static void mirror_read_complete(void *opaque, int ret)
         BlockDriverState *source = s->common.bs;
         BlockErrorAction action;
 
-        bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
+        bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
+                              op->nb_sectors);
         action = mirror_error_action(s, true, -ret);
         if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
             s->ret = ret;
@@ -286,7 +288,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
         next_sector += sectors_per_chunk;
     }
 
-    bdrv_reset_dirty(source, sector_num, nb_sectors);
+    bdrv_reset_dirty_bitmap(source, s->dirty_bitmap, sector_num,
+                            nb_sectors);
 
     /* Copy the dirty cluster.  */
     s->in_flight++;
@@ -442,7 +445,7 @@ static void coroutine_fn mirror_run(void *opaque)
 
             assert(n > 0);
             if (ret == 1) {
-                bdrv_set_dirty(bs, sector_num, n);
+                bdrv_set_dirty_bitmap(bs, s->dirty_bitmap, sector_num, n);
                 sector_num = next;
             } else {
                 sector_num += n;
diff --git a/include/block/block.h b/include/block/block.h
index 6e7275d..a77ed30 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -434,8 +434,10 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
 int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
-void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
-void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
+void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
+                           int64_t cur_sector, int nr_sectors);
+void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
+                             int64_t cur_sector, int nr_sectors);
 void bdrv_dirty_iter_init(BlockDriverState *bs,
                           BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
 int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
diff --git a/migration/block.c b/migration/block.c
index 74d9eb1..a0f908c 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -303,7 +303,7 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
     blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
                                 nr_sectors, blk_mig_read_cb, blk);
 
-    bdrv_reset_dirty(bs, cur_sector, nr_sectors);
+    bdrv_reset_dirty_bitmap(bs, bmds->dirty_bitmap, cur_sector, nr_sectors);
     qemu_mutex_unlock_iothread();
 
     bmds->cur_sector = cur_sector + nr_sectors;
@@ -496,7 +496,8 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
                 g_free(blk);
             }
 
-            bdrv_reset_dirty(bmds->bs, sector, nr_sectors);
+            bdrv_reset_dirty_bitmap(bmds->bs, bmds->dirty_bitmap, sector,
+                                    nr_sectors);
             break;
         }
         sector += BDRV_SECTORS_PER_DIRTY_CHUNK;
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 02/13] qapi: Add optional field "name" to block dirty bitmap
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 01/13] block: fix spoiling all dirty bitmaps by mirror and migration John Snow
@ 2015-01-12 16:30 ` John Snow
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove John Snow
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-12 16:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

From: Fam Zheng <famz@redhat.com>

This field will be set for user created dirty bitmap. Also pass in an
error pointer to bdrv_create_dirty_bitmap, so when a name is already
taken on this BDS, it can report an error message. This is not global
check, two BDSes can have dirty bitmap with a common name.

Implemented bdrv_find_dirty_bitmap to find a dirty bitmap by name, will
be used later when other QMP commands want to reference dirty bitmap by
name.

Add bdrv_dirty_bitmap_make_anon. This unsets the name of dirty bitmap.

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
---
 block.c               | 32 +++++++++++++++++++++++++++++++-
 block/mirror.c        |  2 +-
 include/block/block.h |  7 ++++++-
 migration/block.c     |  2 +-
 qapi/block-core.json  |  4 +++-
 5 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/block.c b/block.c
index 6c1b49a..bfeae6b 100644
--- a/block.c
+++ b/block.c
@@ -53,6 +53,7 @@
 
 struct BdrvDirtyBitmap {
     HBitmap *bitmap;
+    char *name;
     QLIST_ENTRY(BdrvDirtyBitmap) list;
 };
 
@@ -5323,7 +5324,28 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov)
     return true;
 }
 
-BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
+BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
+{
+    BdrvDirtyBitmap *bm;
+
+    assert(name);
+    QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
+        if (bm->name && !strcmp(name, bm->name)) {
+            return bm;
+        }
+    }
+    return NULL;
+}
+
+void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
+{
+    g_free(bitmap->name);
+    bitmap->name = NULL;
+}
+
+BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
+                                          int granularity,
+                                          const char *name,
                                           Error **errp)
 {
     int64_t bitmap_size;
@@ -5331,6 +5353,10 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
 
     assert((granularity & (granularity - 1)) == 0);
 
+    if (name && bdrv_find_dirty_bitmap(bs, name)) {
+        error_setg(errp, "Bitmap already exists: %s", name);
+        return NULL;
+    }
     granularity >>= BDRV_SECTOR_BITS;
     assert(granularity);
     bitmap_size = bdrv_nb_sectors(bs);
@@ -5341,6 +5367,7 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
     }
     bitmap = g_new0(BdrvDirtyBitmap, 1);
     bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
+    bitmap->name = g_strdup(name);
     QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
     return bitmap;
 }
@@ -5352,6 +5379,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
         if (bm == bitmap) {
             QLIST_REMOVE(bitmap, list);
             hbitmap_free(bitmap->bitmap);
+            g_free(bitmap->name);
             g_free(bitmap);
             return;
         }
@@ -5370,6 +5398,8 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
         info->count = bdrv_get_dirty_count(bs, bm);
         info->granularity =
             ((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bm->bitmap));
+        info->has_name = !!bm->name;
+        info->name = g_strdup(bm->name);
         entry->value = info;
         *plist = entry;
         plist = &entry->next;
diff --git a/block/mirror.c b/block/mirror.c
index 9019d1b..d819952 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -702,7 +702,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
     s->granularity = granularity;
     s->buf_size = MAX(buf_size, granularity);
 
-    s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, errp);
+    s->dirty_bitmap = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
     if (!s->dirty_bitmap) {
         return;
     }
diff --git a/include/block/block.h b/include/block/block.h
index a77ed30..bf767af 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -429,8 +429,13 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
 
 struct HBitmapIter;
 typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
-BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
+BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
+                                          int granularity,
+                                          const char *name,
                                           Error **errp);
+BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
+                                        const char *name);
+void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
 int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
diff --git a/migration/block.c b/migration/block.c
index a0f908c..4eeb72a 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -319,7 +319,7 @@ static int set_dirty_tracking(void)
 
     QSIMPLEQ_FOREACH(bmds, &block_mig_state.bmds_list, entry) {
         bmds->dirty_bitmap = bdrv_create_dirty_bitmap(bmds->bs, BLOCK_SIZE,
-                                                      NULL);
+                                                      NULL, NULL);
         if (!bmds->dirty_bitmap) {
             ret = -errno;
             goto fail;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 6e8db15..d176324 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -322,6 +322,8 @@
 #
 # Block dirty bitmap information.
 #
+# @name: #optional the name of the dirty bitmap (Since 2.3)
+#
 # @count: number of dirty bytes according to the dirty bitmap
 #
 # @granularity: granularity of the dirty bitmap in bytes (since 1.4)
@@ -329,7 +331,7 @@
 # Since: 1.3
 ##
 { 'type': 'BlockDirtyInfo',
-  'data': {'count': 'int', 'granularity': 'int'} }
+  'data': {'*name': 'str', 'count': 'int', 'granularity': 'int'} }
 
 ##
 # @BlockInfo:
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 01/13] block: fix spoiling all dirty bitmaps by mirror and migration John Snow
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 02/13] qapi: Add optional field "name" to block dirty bitmap John Snow
@ 2015-01-12 16:30 ` John Snow
  2015-01-16 15:36   ` Max Reitz
  2015-01-29 13:55   ` Vladimir Sementsov-Ogievskiy
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 04/13] block: Introduce bdrv_dirty_bitmap_granularity() John Snow
                   ` (13 subsequent siblings)
  16 siblings, 2 replies; 54+ messages in thread
From: John Snow @ 2015-01-12 16:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

From: Fam Zheng <famz@redhat.com>

The new command pair is added to manage user created dirty bitmap. The
dirty bitmap's name is mandatory and must be unique for the same device,
but different devices can have bitmaps with the same names.

The granularity is an optional field. If it is not specified, we will
choose a default granularity based on the cluster size if available,
clamped to between 4K and 64K to mirror how the 'mirror' code was
already choosing granularity. If we do not have cluster size info
available, we choose 64K. This code has been factored out into a helper
shared with block/mirror.

This patch also introduces the 'block_dirty_bitmap_lookup' helper,
which takes a device name and a dirty bitmap name and validates the
lookup, returning NULL and setting errp if there is a problem with
either field. This helper will be re-used in future patches in this
series.

The types added to block-core.json will be re-used in future patches
in this series, see:
'qapi: Add transaction support to block-dirty-bitmap-{add, enable, disable}'

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c               |  20 ++++++++++
 block/mirror.c        |  10 +----
 blockdev.c            | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/block/block.h |   1 +
 qapi/block-core.json  |  55 +++++++++++++++++++++++++++
 qmp-commands.hx       |  51 +++++++++++++++++++++++++
 6 files changed, 228 insertions(+), 9 deletions(-)

diff --git a/block.c b/block.c
index bfeae6b..3eb77ee 100644
--- a/block.c
+++ b/block.c
@@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector
     }
 }
 
+/**
+ * Chooses a default granularity based on the existing cluster size,
+ * but clamped between [4K, 64K]. Defaults to 64K in the case that there
+ * is no cluster size information available.
+ */
+uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
+{
+    BlockDriverInfo bdi;
+    uint64_t granularity;
+
+    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
+        granularity = MAX(4096, bdi.cluster_size);
+        granularity = MIN(65536, granularity);
+    } else {
+        granularity = 65536;
+    }
+
+    return granularity;
+}
+
 void bdrv_dirty_iter_init(BlockDriverState *bs,
                           BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
 {
diff --git a/block/mirror.c b/block/mirror.c
index d819952..fc545f1 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
     MirrorBlockJob *s;
 
     if (granularity == 0) {
-        /* Choose the default granularity based on the target file's cluster
-         * size, clamped between 4k and 64k.  */
-        BlockDriverInfo bdi;
-        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
-            granularity = MAX(4096, bdi.cluster_size);
-            granularity = MIN(65536, granularity);
-        } else {
-            granularity = 65536;
-        }
+        granularity = bdrv_get_default_bitmap_granularity(target);
     }
 
     assert ((granularity & (granularity - 1)) == 0);
diff --git a/blockdev.c b/blockdev.c
index 5651a8e..95251c7 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1173,6 +1173,48 @@ out_aio_context:
     return NULL;
 }
 
+/**
+ * Return a dirty bitmap (if present), after validating
+ * the node reference and bitmap names. Returns NULL on error,
+ * including when the BDS and/or bitmap is not found.
+ */
+static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
+                                                  const char *name,
+                                                  BlockDriverState **pbs,
+                                                  Error **errp)
+{
+    BlockDriverState *bs;
+    BdrvDirtyBitmap *bitmap;
+
+    if (!node_ref) {
+        error_setg(errp, "Node reference cannot be NULL");
+        return NULL;
+    }
+    if (!name) {
+        error_setg(errp, "Bitmap name cannot be NULL");
+        return NULL;
+    }
+
+    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
+    if (!bs) {
+        error_setg(errp, "Node reference '%s' not found", node_ref);
+        return NULL;
+    }
+
+    /* If caller provided a BDS*, provide the result of that lookup, too. */
+    if (pbs) {
+        *pbs = bs;
+    }
+
+    bitmap = bdrv_find_dirty_bitmap(bs, name);
+    if (!bitmap) {
+        error_setg(errp, "Dirty bitmap not found: %s", name);
+        return NULL;
+    }
+
+    return bitmap;
+}
+
 /* New and old BlockDriverState structs for atomic group operations */
 
 typedef struct BlkTransactionState BlkTransactionState;
@@ -1894,6 +1936,64 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
     aio_context_release(aio_context);
 }
 
+void qmp_block_dirty_bitmap_add(const char *node_ref, const char *name,
+                                bool has_granularity, int64_t granularity,
+                                Error **errp)
+{
+    AioContext *aio_context;
+    BlockDriverState *bs;
+
+    if (!name || name[0] == '\0') {
+        error_setg(errp, "Bitmap name cannot be empty");
+        return;
+    }
+
+    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
+    if (!bs) {
+        return;
+    }
+
+    aio_context = bdrv_get_aio_context(bs);
+    aio_context_acquire(aio_context);
+
+    if (has_granularity) {
+        if (granularity < 512 || !is_power_of_2(granularity)) {
+            error_setg(errp, "Granularity must be power of 2 "
+                             "and at least 512");
+            goto out;
+        }
+    } else {
+        /* Default to cluster size, if available: */
+        granularity = bdrv_get_default_bitmap_granularity(bs);
+    }
+
+    bdrv_create_dirty_bitmap(bs, granularity, name, errp);
+
+ out:
+    aio_context_release(aio_context);
+}
+
+void qmp_block_dirty_bitmap_remove(const char *node_ref, const char *name,
+                                   Error **errp)
+{
+    AioContext *aio_context;
+    BlockDriverState *bs;
+    BdrvDirtyBitmap *bitmap;
+
+    bitmap = block_dirty_bitmap_lookup(node_ref, name, &bs, errp);
+    if (!bitmap || !bs) {
+        return;
+    }
+
+    aio_context = bdrv_get_aio_context(bs);
+    aio_context_acquire(aio_context);
+
+    bdrv_dirty_bitmap_make_anon(bs, bitmap);
+    bdrv_release_dirty_bitmap(bs, bitmap);
+
+    aio_context_release(aio_context);
+}
+
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *id = qdict_get_str(qdict, "id");
diff --git a/include/block/block.h b/include/block/block.h
index bf767af..44dd6ca 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -438,6 +438,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
 void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
+uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
 int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
 void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
                            int64_t cur_sector, int nr_sectors);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index d176324..f79d165 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -894,6 +894,61 @@
             '*on-target-error': 'BlockdevOnError' } }
 
 ##
+# @BlockDirtyBitmap
+#
+# @node-ref: name of device/node-name which the bitmap is tracking
+#
+# @name: name of the dirty bitmap
+#
+# Since 2.3
+##
+{ 'type': 'BlockDirtyBitmap',
+  'data': { 'node-ref': 'str', 'name': 'str' } }
+
+##
+# @BlockDirtyBitmapAdd
+#
+# @node-ref: name of device/node-name which the bitmap is tracking
+#
+# @name: name of the dirty bitmap
+#
+# @granularity: #optional the bitmap granularity, default is 64k for
+#               block-dirty-bitmap-add
+#
+# Since 2.3
+##
+{ 'type': 'BlockDirtyBitmapAdd',
+  'data': { 'node-ref': 'str', 'name': 'str', '*granularity': 'int' } }
+
+##
+# @block-dirty-bitmap-add
+#
+# Create a dirty bitmap with a name on the node
+#
+# Returns: nothing on success
+#          If @node-ref is not a valid block device, DeviceNotFound
+#          If @name is already taken, GenericError with an explanation
+#
+# Since 2.3
+##
+{'command': 'block-dirty-bitmap-add',
+  'data': 'BlockDirtyBitmapAdd' }
+
+##
+# @block-dirty-bitmap-remove
+#
+# Remove a dirty bitmap on the node
+#
+# Returns: nothing on success
+#          If @node-ref is not a valid block device, DeviceNotFound
+#          If @name is not found, GenericError with an explanation
+#
+# Since 2.3
+##
+{'command': 'block-dirty-bitmap-remove',
+  'data': 'BlockDirtyBitmap' }
+
+##
 # @block_set_io_throttle:
 #
 # Change I/O throttle limits for a block drive.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6945d30..4ffca8a 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1202,6 +1202,57 @@ Example:
 EQMP
 
     {
+        .name       = "block-dirty-bitmap-add",
+        .args_type  = "node-ref:B,name:s,granularity:i?",
+        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_add,
+    },
+    {
+        .name       = "block-dirty-bitmap-remove",
+        .args_type  = "node-ref:B,name:s",
+        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_remove,
+    },
+
+SQMP
+
+block-dirty-bitmap-add
+----------------------
+Since 2.3
+
+Create a dirty bitmap with a name on the device, and start tracking the writes.
+
+Arguments:
+
+- "node-ref": device/node on which to create dirty bitmap (json-string)
+- "name": name of the new dirty bitmap (json-string)
+- "granularity": granularity to track writes with (int, optional)
+
+Example:
+
+-> { "execute": "block-dirty-bitmap-add", "arguments": { "node-ref": "drive0",
+                                                   "name": "bitmap0" } }
+<- { "return": {} }
+
+block-dirty-bitmap-remove
+-------------------------
+Since 2.3
+
+Stop write tracking and remove the dirty bitmap that was created with
+block-dirty-bitmap-add.
+
+Arguments:
+
+- "node-ref": device/node on which to remove dirty bitmap (json-string)
+- "name": name of the dirty bitmap to remove (json-string)
+
+Example:
+
+-> { "execute": "block-dirty-bitmap-remove", "arguments": { "node-ref": "drive0",
+                                                      "name": "bitmap0" } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "blockdev-snapshot-sync",
         .args_type  = "device:s?,node-name:s?,snapshot-file:s,snapshot-node-name:s?,format:s?,mode:s?",
         .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 04/13] block: Introduce bdrv_dirty_bitmap_granularity()
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (2 preceding siblings ...)
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove John Snow
@ 2015-01-12 16:30 ` John Snow
  2015-01-16 15:40   ` Max Reitz
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 05/13] block: Add bdrv_clear_dirty_bitmap John Snow
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-12 16:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

From: Fam Zheng <famz@redhat.com>

This returns the granularity (in bytes) of dirty bitmap,
which matches the QMP interface and the existing query
interface.

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c               | 9 +++++++--
 include/block/block.h | 2 ++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/block.c b/block.c
index 3eb77ee..a1d9e88 100644
--- a/block.c
+++ b/block.c
@@ -5396,8 +5396,7 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
         BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
         BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
         info->count = bdrv_get_dirty_count(bs, bm);
-        info->granularity =
-            ((int64_t) BDRV_SECTOR_SIZE << hbitmap_granularity(bm->bitmap));
+        info->granularity = bdrv_dirty_bitmap_granularity(bs, bm);
         info->has_name = !!bm->name;
         info->name = g_strdup(bm->name);
         entry->value = info;
@@ -5437,6 +5436,12 @@ uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
     return granularity;
 }
 
+uint64_t bdrv_dirty_bitmap_granularity(BlockDriverState *bs,
+                                       BdrvDirtyBitmap *bitmap)
+{
+    return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
+}
+
 void bdrv_dirty_iter_init(BlockDriverState *bs,
                           BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
 {
diff --git a/include/block/block.h b/include/block/block.h
index 44dd6ca..c7402e7 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -439,6 +439,8 @@ void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
 uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
+uint64_t bdrv_dirty_bitmap_granularity(BlockDriverState *bs,
+                                      BdrvDirtyBitmap *bitmap);
 int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
 void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
                            int64_t cur_sector, int nr_sectors);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 05/13] block: Add bdrv_clear_dirty_bitmap
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (3 preceding siblings ...)
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 04/13] block: Introduce bdrv_dirty_bitmap_granularity() John Snow
@ 2015-01-12 16:30 ` John Snow
  2015-01-16 15:56   ` Max Reitz
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 06/13] hbitmap: add hbitmap_merge John Snow
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-12 16:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c               | 24 ++++++++++++++++++++----
 include/block/block.h |  1 +
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/block.c b/block.c
index a1d9e88..7bf7079 100644
--- a/block.c
+++ b/block.c
@@ -53,6 +53,8 @@
 
 struct BdrvDirtyBitmap {
     HBitmap *bitmap;
+    int64_t size;
+    int64_t granularity;
     char *name;
     QLIST_ENTRY(BdrvDirtyBitmap) list;
 };
@@ -5350,6 +5352,7 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
 {
     int64_t bitmap_size;
     BdrvDirtyBitmap *bitmap;
+    int sector_granularity;
 
     assert((granularity & (granularity - 1)) == 0);
 
@@ -5357,8 +5360,8 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
         error_setg(errp, "Bitmap already exists: %s", name);
         return NULL;
     }
-    granularity >>= BDRV_SECTOR_BITS;
-    assert(granularity);
+    sector_granularity = granularity >> BDRV_SECTOR_BITS;
+    assert(sector_granularity);
     bitmap_size = bdrv_nb_sectors(bs);
     if (bitmap_size < 0) {
         error_setg_errno(errp, -bitmap_size, "could not get length of device");
@@ -5366,7 +5369,9 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
         return NULL;
     }
     bitmap = g_new0(BdrvDirtyBitmap, 1);
-    bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
+    bitmap->size = bitmap_size;
+    bitmap->granularity = granularity;
+    bitmap->bitmap = hbitmap_alloc(bitmap->size, ffs(sector_granularity) - 1);
     bitmap->name = g_strdup(name);
     QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
     return bitmap;
@@ -5439,7 +5444,9 @@ uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
 uint64_t bdrv_dirty_bitmap_granularity(BlockDriverState *bs,
                                        BdrvDirtyBitmap *bitmap)
 {
-    return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
+    g_assert(BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap) ==
+             bitmap->granularity);
+    return bitmap->granularity;
 }
 
 void bdrv_dirty_iter_init(BlockDriverState *bs,
@@ -5460,6 +5467,15 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
     hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
 }
 
+/**
+ * Effectively, reset the hbitmap from bits [0, size)
+ * Synonymous with bdrv_reset_dirty_bitmap(bs, bitmap, 0, bitmap->size)
+ */
+void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
+{
+    hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
+}
+
 static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
                            int nr_sectors)
 {
diff --git a/include/block/block.h b/include/block/block.h
index c7402e7..66f092a 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -446,6 +446,7 @@ void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
                            int64_t cur_sector, int nr_sectors);
 void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
                              int64_t cur_sector, int nr_sectors);
+void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_iter_init(BlockDriverState *bs,
                           BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
 int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 06/13] hbitmap: add hbitmap_merge
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (4 preceding siblings ...)
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 05/13] block: Add bdrv_clear_dirty_bitmap John Snow
@ 2015-01-12 16:30 ` John Snow
  2015-01-16 16:12   ` Max Reitz
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 07/13] qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable John Snow
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-12 16:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

We add a bitmap merge operation to assist in error cases
where we wish to combine two bitmaps together.

This is algorithmically O(bits) provided HBITMAP_LEVELS remains
constant. For a full bitmap on a 64bit machine:
sum(bits/64^k, k, 0, HBITMAP_LEVELS) ~= 1.01587 * bits

We may be able to improve running speed for particularly sparse
bitmaps by using iterators, but the running time for dense maps
will be worse.

We present the simpler solution first, and we can refine it later
if needed.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 include/qemu/hbitmap.h | 11 +++++++++++
 util/hbitmap.c         | 28 ++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
index 550d7ce..c19c1cb 100644
--- a/include/qemu/hbitmap.h
+++ b/include/qemu/hbitmap.h
@@ -65,6 +65,17 @@ struct HBitmapIter {
 HBitmap *hbitmap_alloc(uint64_t size, int granularity);
 
 /**
+ * hbitmap_merge:
+ * @a: The bitmap to store the result in.
+ * @b: The bitmap to merge into @a.
+ *
+ * Merge two bitmaps together.
+ * A := A (BITOR) B.
+ * B is left unmodified.
+ */
+bool hbitmap_merge(HBitmap *a, const HBitmap *b);
+
+/**
  * hbitmap_empty:
  * @hb: HBitmap to operate on.
  *
diff --git a/util/hbitmap.c b/util/hbitmap.c
index ab13971..47ce760 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -395,3 +395,31 @@ HBitmap *hbitmap_alloc(uint64_t size, int granularity)
     hb->levels[0][0] |= 1UL << (BITS_PER_LONG - 1);
     return hb;
 }
+
+/**
+ * Given HBitmaps A and B, let A := A (BITOR) B.
+ * Bitmap B will not be modified.
+ */
+bool hbitmap_merge(HBitmap *a, const HBitmap *b)
+{
+    int i, j;
+    uint64_t size;
+
+    if ((a->size != b->size) || (a->granularity != b->granularity)) {
+        return false;
+    }
+
+    /* This merge is O(size), as BITS_PER_LONG and HBITMAP_LEVELS are constant.
+     * It may be possible to improve running times for sparsely populated maps
+     * by using hbitmap_iter_next, but this is suboptimal for dense maps.
+     */
+    size = a->size;
+    for (i = HBITMAP_LEVELS - 1; i >= 0; i--) {
+        size = MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
+        for (j = 0; j < size; j++) {
+            a->levels[i][j] |= b->levels[i][j];
+        }
+    }
+
+    return true;
+}
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 07/13] qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (5 preceding siblings ...)
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 06/13] hbitmap: add hbitmap_merge John Snow
@ 2015-01-12 16:30 ` John Snow
  2015-01-16 16:28   ` Max Reitz
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors John Snow
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-12 16:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

From: Fam Zheng <famz@redhat.com>

This allows to put the dirty bitmap into a disabled state where no more
writes will be tracked.

It will be used before backup or writing to persistent file.

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c               | 24 +++++++++++++++++++++++-
 blockdev.c            | 40 ++++++++++++++++++++++++++++++++++++++++
 include/block/block.h |  3 +++
 qapi/block-core.json  | 28 ++++++++++++++++++++++++++++
 qmp-commands.hx       | 10 ++++++++++
 5 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/block.c b/block.c
index 7bf7079..bd4b449 100644
--- a/block.c
+++ b/block.c
@@ -56,6 +56,7 @@ struct BdrvDirtyBitmap {
     int64_t size;
     int64_t granularity;
     char *name;
+    bool enabled;
     QLIST_ENTRY(BdrvDirtyBitmap) list;
 };
 
@@ -5373,10 +5374,16 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
     bitmap->granularity = granularity;
     bitmap->bitmap = hbitmap_alloc(bitmap->size, ffs(sector_granularity) - 1);
     bitmap->name = g_strdup(name);
+    bitmap->enabled = true;
     QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
     return bitmap;
 }
 
+bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
+{
+    return bitmap->enabled;
+}
+
 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
 {
     BdrvDirtyBitmap *bm, *next;
@@ -5391,6 +5398,16 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
     }
 }
 
+void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
+{
+    bitmap->enabled = false;
+}
+
+void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
+{
+    bitmap->enabled = true;
+}
+
 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
 {
     BdrvDirtyBitmap *bm;
@@ -5458,7 +5475,9 @@ void bdrv_dirty_iter_init(BlockDriverState *bs,
 void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
                            int64_t cur_sector, int nr_sectors)
 {
-    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
+    if (bdrv_dirty_bitmap_enabled(bitmap)) {
+        hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
+    }
 }
 
 void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
@@ -5481,6 +5500,9 @@ static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
 {
     BdrvDirtyBitmap *bitmap;
     QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
+        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
+            continue;
+        }
         hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
     }
 }
diff --git a/blockdev.c b/blockdev.c
index 95251c7..118cb6c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1994,6 +1994,46 @@ void qmp_block_dirty_bitmap_remove(const char *node_ref, const char *name,
     aio_context_release(aio_context);
 }
 
+void qmp_block_dirty_bitmap_enable(const char *node_ref, const char *name,
+                                   Error **errp)
+{
+    AioContext *aio_context;
+    BdrvDirtyBitmap *bitmap;
+    BlockDriverState *bs;
+
+    bitmap = block_dirty_bitmap_lookup(node_ref, name, &bs, errp);
+    if (!bitmap) {
+        return;
+    }
+
+    aio_context = bdrv_get_aio_context(bs);
+    aio_context_acquire(aio_context);
+
+    bdrv_enable_dirty_bitmap(bitmap);
+
+    aio_context_release(aio_context);
+}
+
+void qmp_block_dirty_bitmap_disable(const char *node_ref, const char *name,
+                                    Error **errp)
+{
+    AioContext *aio_context;
+    BdrvDirtyBitmap *bitmap;
+    BlockDriverState *bs;
+
+    bitmap = block_dirty_bitmap_lookup(node_ref, name, &bs, errp);
+    if (!bitmap) {
+        return;
+    }
+
+    aio_context = bdrv_get_aio_context(bs);
+    aio_context_acquire(aio_context);
+
+    bdrv_disable_dirty_bitmap(bitmap);
+
+    aio_context_release(aio_context);
+}
+
 int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
 {
     const char *id = qdict_get_str(qdict, "id");
diff --git a/include/block/block.h b/include/block/block.h
index 66f092a..a5bc249 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -437,10 +437,13 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
                                         const char *name);
 void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
+void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
+void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
 uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
 uint64_t bdrv_dirty_bitmap_granularity(BlockDriverState *bs,
                                       BdrvDirtyBitmap *bitmap);
+bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
 int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
 void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
                            int64_t cur_sector, int nr_sectors);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index f79d165..3e863b9 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -949,6 +949,34 @@
   'data': 'BlockDirtyBitmap' }
 
 ##
+# @block-dirty-bitmap-enable
+#
+# Enable a dirty bitmap on the device
+#
+# Returns: nothing on success
+#          If @node-ref is not a valid block device, DeviceNotFound
+#          If @name is not found, GenericError with an explaining message
+#
+# Since 2.3
+##
+{'command': 'block-dirty-bitmap-enable',
+  'data': 'BlockDirtyBitmap' }
+
+##
+# @block-dirty-bitmap-disable
+#
+# Disable a dirty bitmap on the device
+#
+# Returns: nothing on success
+#          If @node-ref is not a valid block device, DeviceNotFound
+#          If @name is not found, GenericError with an explaining message
+#
+# Since 2.3
+##
+{'command': 'block-dirty-bitmap-disable',
+  'data': 'BlockDirtyBitmap' }
+
+##
 # @block_set_io_throttle:
 #
 # Change I/O throttle limits for a block drive.
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4ffca8a..59be8eb 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1211,6 +1211,16 @@ EQMP
         .args_type  = "node-ref:B,name:s",
         .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_remove,
     },
+    {
+        .name       = "block-dirty-bitmap-enable",
+        .args_type  = "node-ref:B,name:s",
+        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_enable,
+    },
+    {
+        .name       = "block-dirty-bitmap-disable",
+        .args_type  = "node-ref:B,name:s",
+        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_disable,
+    },
 
 SQMP
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (6 preceding siblings ...)
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 07/13] qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable John Snow
@ 2015-01-12 16:31 ` John Snow
  2015-01-13  9:24   ` Fam Zheng
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup John Snow
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-12 16:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

A bitmap successor is an anonymous BdrvDirtyBitmap that is intended to
be created just prior to a sensitive operation (e.g. Incremental Backup)
that can either succeed or fail, but during the course of which we still
want a bitmap tracking writes.

On creating a successor, we "freeze" the parent bitmap which prevents
its deletion, enabling, anonymization, or creating a bitmap with the
same name.

On success, the parent bitmap can "abdicate" responsibility to the
successor, which will inherit its name. The successor will have been
tracking writes during the course of the backup operation. The parent
will be safely deleted.

On failure, we can "reclaim" the successor from the parent, unifying
them such that the resulting bitmap describes all writes occurring since
the last successful backup, for instance. Reclamation will thaw the
parent, but not explicitly re-enable it.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c               | 123 ++++++++++++++++++++++++++++++++++++++++++++++++--
 blockdev.c            |  14 ++++++
 include/block/block.h |  10 ++++
 3 files changed, 144 insertions(+), 3 deletions(-)

diff --git a/block.c b/block.c
index bd4b449..3f33b9d 100644
--- a/block.c
+++ b/block.c
@@ -53,10 +53,12 @@
 
 struct BdrvDirtyBitmap {
     HBitmap *bitmap;
+    BdrvDirtyBitmap *successor;
     int64_t size;
     int64_t granularity;
     char *name;
     bool enabled;
+    bool frozen;
     QLIST_ENTRY(BdrvDirtyBitmap) list;
 };
 
@@ -5342,6 +5344,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
 
 void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
 {
+    assert(!bitmap->frozen);
     g_free(bitmap->name);
     bitmap->name = NULL;
 }
@@ -5379,9 +5382,114 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
     return bitmap;
 }
 
+/**
+  * A frozen bitmap cannot be renamed, deleted, cleared,
+  * or set. A frozen bitmap can only abdicate, reclaim,
+  * or thaw.
+  */
+static void bdrv_freeze_dirty_bitmap(BdrvDirtyBitmap *bitmap)
+{
+    bitmap->frozen = true;
+}
+
+static void bdrv_thaw_dirty_bitmap(BdrvDirtyBitmap *bitmap)
+{
+    bitmap->frozen = false;
+}
+
+bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
+{
+    return bitmap->frozen;
+}
+
 bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
 {
-    return bitmap->enabled;
+    return bitmap->enabled && !bitmap->frozen;
+}
+
+/**
+ * Create a successor bitmap destined to replace this bitmap after an operation.
+ * Requires that the bitmap is not frozen and has no successor.
+ */
+int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
+                                       BdrvDirtyBitmap *bitmap, Error **errp)
+{
+    uint64_t granularity;
+
+    if (bdrv_dirty_bitmap_frozen(bitmap)) {
+        error_setg(errp,
+                   "Cannot create a successor for a bitmap currently in-use.");
+        return -1;
+    } else if (bitmap->successor) {
+        error_setg(errp, "Cannot create a successor for a bitmap that "
+                   "already has one.");
+        return -1;
+    }
+
+    /* Create an anonymous successor */
+    granularity = bdrv_dirty_bitmap_granularity(bs, bitmap);
+    bitmap->successor = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
+    if (!bitmap->successor) {
+        return -1;
+    }
+
+    /* Successor will be on or off based on our current state.
+     * Parent will be disabled and frozen. */
+    bitmap->successor->enabled = bitmap->enabled;
+    bdrv_disable_dirty_bitmap(bitmap);
+    bdrv_freeze_dirty_bitmap(bitmap);
+    return 0;
+}
+
+/**
+ * For a bitmap with a successor, yield our name to the successor,
+ * Delete the old bitmap, and return a handle to the new bitmap.
+ */
+BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
+                                            BdrvDirtyBitmap *bitmap,
+                                            Error **errp)
+{
+    char *name;
+    BdrvDirtyBitmap *successor = bitmap->successor;
+
+    if (successor == NULL) {
+        error_setg(errp, "Cannot relinquish control if "
+                   "there's no successor present.\n");
+        return NULL;
+    }
+
+    name = bitmap->name;
+    bitmap->name = NULL;
+    successor->name = name;
+
+    bdrv_thaw_dirty_bitmap(bitmap);
+    bdrv_release_dirty_bitmap(bs, bitmap);
+
+    return successor;
+}
+
+/**
+ * In cases of failure where we can no longer safely delete the parent,
+ * We may wish to re-join the parent and child/successor.
+ * The merged parent will be un-frozen, but not explicitly re-enabled.
+ */
+BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
+                                           BdrvDirtyBitmap *parent,
+                                           Error **errp)
+{
+    BdrvDirtyBitmap *successor = parent->successor;
+    if (!successor) {
+        error_setg(errp, "Cannot reclaim a successor when none is present.\n");
+        return NULL;
+    }
+
+    hbitmap_merge(parent->bitmap, successor->bitmap);
+    bdrv_release_dirty_bitmap(bs, successor);
+
+    bdrv_thaw_dirty_bitmap(parent);
+    parent->successor = NULL;
+
+    return parent;
 }
 
 void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
@@ -5389,6 +5497,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
     BdrvDirtyBitmap *bm, *next;
     QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
         if (bm == bitmap) {
+            assert(!bm->frozen);
             QLIST_REMOVE(bitmap, list);
             hbitmap_free(bitmap->bitmap);
             g_free(bitmap->name);
@@ -5405,6 +5514,7 @@ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
 
 void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
 {
+    assert(!bitmap->frozen);
     bitmap->enabled = true;
 }
 
@@ -5483,7 +5593,9 @@ void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
 void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
                              int64_t cur_sector, int nr_sectors)
 {
-    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
+    if (!bitmap->frozen) {
+        hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
+    }
 }
 
 /**
@@ -5492,7 +5604,9 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
  */
 void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
 {
-    hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
+    if (!bitmap->frozen) {
+        hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
+    }
 }
 
 static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
@@ -5512,6 +5626,9 @@ static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
 {
     BdrvDirtyBitmap *bitmap;
     QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
+        if (bitmap->frozen) {
+            continue;
+        }
         hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
     }
 }
diff --git a/blockdev.c b/blockdev.c
index 118cb6c..8dde72a 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1988,9 +1988,16 @@ void qmp_block_dirty_bitmap_remove(const char *node_ref, const char *name,
     aio_context = bdrv_get_aio_context(bs);
     aio_context_acquire(aio_context);
 
+    if (bdrv_dirty_bitmap_frozen(bitmap)) {
+        error_setg(errp,
+                   "Bitmap %s is currently frozen and cannot be removed yet.\n",
+                   name);
+        goto out;
+    }
     bdrv_dirty_bitmap_make_anon(bs, bitmap);
     bdrv_release_dirty_bitmap(bs, bitmap);
 
+ out:
     aio_context_release(aio_context);
 }
 
@@ -2009,8 +2016,15 @@ void qmp_block_dirty_bitmap_enable(const char *node_ref, const char *name,
     aio_context = bdrv_get_aio_context(bs);
     aio_context_acquire(aio_context);
 
+    if (bdrv_dirty_bitmap_frozen(bitmap)) {
+        error_setg(errp, "Bitmap %s is frozen and cannot be enabled yet.\n",
+                   name);
+        goto out;
+    }
+
     bdrv_enable_dirty_bitmap(bitmap);
 
+ out:
     aio_context_release(aio_context);
 }
 
diff --git a/include/block/block.h b/include/block/block.h
index a5bc249..6138544 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -433,6 +433,15 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
                                           int granularity,
                                           const char *name,
                                           Error **errp);
+int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
+                                       BdrvDirtyBitmap *bitmap,
+                                       Error **errp);
+BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
+                                            BdrvDirtyBitmap *bitmap,
+                                            Error **errp);
+BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
+                                           BdrvDirtyBitmap *bitmap,
+                                           Error **errp);
 BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
                                         const char *name);
 void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
@@ -444,6 +453,7 @@ uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
 uint64_t bdrv_dirty_bitmap_granularity(BlockDriverState *bs,
                                       BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
+bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
 int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
 void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
                            int64_t cur_sector, int nr_sectors);
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (7 preceding siblings ...)
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors John Snow
@ 2015-01-12 16:31 ` John Snow
  2015-01-13  9:37   ` Fam Zheng
  2015-01-16 17:52   ` Max Reitz
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 10/13] qapi: Add transaction support to block-dirty-bitmap-{add, enable, disable} John Snow
                   ` (7 subsequent siblings)
  16 siblings, 2 replies; 54+ messages in thread
From: John Snow @ 2015-01-12 16:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

For "dirty-bitmap" sync mode, the block job will iterate through the
given dirty bitmap to decide if a sector needs backup (backup all the
dirty clusters and skip clean ones), just as allocation conditions of
"top" sync mode.

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c                   |   5 ++
 block/backup.c            | 120 ++++++++++++++++++++++++++++++++++++++--------
 block/mirror.c            |   4 ++
 blockdev.c                |  14 +++++-
 hmp.c                     |   3 +-
 include/block/block.h     |   1 +
 include/block/block_int.h |   2 +
 qapi/block-core.json      |  11 +++--
 qmp-commands.hx           |   7 +--
 9 files changed, 137 insertions(+), 30 deletions(-)

diff --git a/block.c b/block.c
index 3f33b9d..5eb6788 100644
--- a/block.c
+++ b/block.c
@@ -5633,6 +5633,11 @@ static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
     }
 }
 
+void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
+{
+    hbitmap_iter_init(hbi, hbi->hb, offset);
+}
+
 int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
 {
     return hbitmap_count(bitmap->bitmap);
diff --git a/block/backup.c b/block/backup.c
index 792e655..0626a3e 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -37,6 +37,8 @@ typedef struct CowRequest {
 typedef struct BackupBlockJob {
     BlockJob common;
     BlockDriverState *target;
+    /* bitmap for sync=dirty-bitmap */
+    BdrvDirtyBitmap *sync_bitmap;
     MirrorSyncMode sync_mode;
     RateLimit limit;
     BlockdevOnError on_source_error;
@@ -242,6 +244,31 @@ static void backup_complete(BlockJob *job, void *opaque)
     g_free(data);
 }
 
+static bool coroutine_fn yield_and_check(BackupBlockJob *job)
+{
+    if (block_job_is_cancelled(&job->common)) {
+        return true;
+    }
+
+    /* we need to yield so that qemu_aio_flush() returns.
+     * (without, VM does not reboot)
+     */
+    if (job->common.speed) {
+        uint64_t delay_ns = ratelimit_calculate_delay(&job->limit,
+                                                      job->sectors_read);
+        job->sectors_read = 0;
+        block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
+    } else {
+        block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
+    }
+
+    if (block_job_is_cancelled(&job->common)) {
+        return true;
+    }
+
+    return false;
+}
+
 static void coroutine_fn backup_run(void *opaque)
 {
     BackupBlockJob *job = opaque;
@@ -254,13 +281,13 @@ static void coroutine_fn backup_run(void *opaque)
     };
     int64_t start, end;
     int ret = 0;
+    bool error_is_read;
 
     QLIST_INIT(&job->inflight_reqs);
     qemu_co_rwlock_init(&job->flush_rwlock);
 
     start = 0;
-    end = DIV_ROUND_UP(job->common.len / BDRV_SECTOR_SIZE,
-                       BACKUP_SECTORS_PER_CLUSTER);
+    end = DIV_ROUND_UP(job->common.len, BACKUP_CLUSTER_SIZE);
 
     job->bitmap = hbitmap_alloc(end, 0);
 
@@ -278,28 +305,45 @@ static void coroutine_fn backup_run(void *opaque)
             qemu_coroutine_yield();
             job->common.busy = true;
         }
+    } else if (job->sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
+        /* Dirty Bitmap sync has a slightly different iteration method */
+        HBitmapIter hbi;
+        int64_t sector;
+        int64_t cluster;
+        bool polyrhythmic;
+
+        bdrv_dirty_iter_init(bs, job->sync_bitmap, &hbi);
+        /* Does the granularity happen to match our backup cluster size? */
+        polyrhythmic = (bdrv_dirty_bitmap_granularity(bs, job->sync_bitmap) !=
+                        BACKUP_CLUSTER_SIZE);
+
+        /* Find the next dirty /sector/ and copy that /cluster/ */
+        while ((sector = hbitmap_iter_next(&hbi)) != -1) {
+            if (yield_and_check(job)) {
+                goto leave;
+            }
+            cluster = sector / BACKUP_SECTORS_PER_CLUSTER;
+
+            do {
+                ret = backup_do_cow(bs, cluster * BACKUP_SECTORS_PER_CLUSTER,
+                                    BACKUP_SECTORS_PER_CLUSTER, &error_is_read);
+                if ((ret < 0) &&
+                    backup_error_action(job, error_is_read, -ret) ==
+                    BLOCK_ERROR_ACTION_REPORT) {
+                    goto leave;
+                }
+            } while (ret < 0);
+
+            /* Advance (or rewind) our iterator if we need to. */
+            if (polyrhythmic) {
+                bdrv_set_dirty_iter(&hbi,
+                                    (cluster + 1) * BACKUP_SECTORS_PER_CLUSTER);
+            }
+        }
     } else {
         /* Both FULL and TOP SYNC_MODE's require copying.. */
         for (; start < end; start++) {
-            bool error_is_read;
-
-            if (block_job_is_cancelled(&job->common)) {
-                break;
-            }
-
-            /* we need to yield so that qemu_aio_flush() returns.
-             * (without, VM does not reboot)
-             */
-            if (job->common.speed) {
-                uint64_t delay_ns = ratelimit_calculate_delay(
-                        &job->limit, job->sectors_read);
-                job->sectors_read = 0;
-                block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
-            } else {
-                block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
-            }
-
-            if (block_job_is_cancelled(&job->common)) {
+            if (yield_and_check(job)) {
                 break;
             }
 
@@ -351,12 +395,23 @@ static void coroutine_fn backup_run(void *opaque)
         }
     }
 
+leave:
     notifier_with_return_remove(&before_write);
 
     /* wait until pending backup_do_cow() calls have completed */
     qemu_co_rwlock_wrlock(&job->flush_rwlock);
     qemu_co_rwlock_unlock(&job->flush_rwlock);
 
+    if (job->sync_bitmap) {
+        if (ret < 0) {
+            /* Merge the successor back into the parent, delete nothing. */
+            assert(bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL));
+            bdrv_enable_dirty_bitmap(job->sync_bitmap);
+        } else {
+            /* Everything is fine, delete this bitmap and install the backup. */
+            assert(bdrv_dirty_bitmap_abdicate(bs, job->sync_bitmap, NULL));
+        }
+    }
     hbitmap_free(job->bitmap);
 
     bdrv_iostatus_disable(target);
@@ -368,6 +423,7 @@ static void coroutine_fn backup_run(void *opaque)
 
 void backup_start(BlockDriverState *bs, BlockDriverState *target,
                   int64_t speed, MirrorSyncMode sync_mode,
+                  BdrvDirtyBitmap *sync_bitmap,
                   BlockdevOnError on_source_error,
                   BlockdevOnError on_target_error,
                   BlockCompletionFunc *cb, void *opaque,
@@ -386,6 +442,26 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
         return;
     }
 
+    if (sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
+        if (!sync_bitmap) {
+            error_setg(errp, "must provide a valid bitmap name for "
+                             "\"dirty-bitmap\" sync mode");
+            return;
+        }
+
+        /* Create a new bitmap, and freeze/disable this one. */
+        if (bdrv_dirty_bitmap_create_successor(bs, sync_bitmap, errp) < 0) {
+            return;
+        }
+
+    } else if (sync_bitmap) {
+        error_setg(errp,
+                   "a sync_bitmap was provided to backup_run, "
+                   "but received an incompatible sync_mode (%s)",
+                   MirrorSyncMode_lookup[sync_mode]);
+        return;
+    }
+
     len = bdrv_getlength(bs);
     if (len < 0) {
         error_setg_errno(errp, -len, "unable to get length for '%s'",
@@ -403,6 +479,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
     job->on_target_error = on_target_error;
     job->target = target;
     job->sync_mode = sync_mode;
+    job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP ?
+                       sync_bitmap : NULL;
     job->common.len = len;
     job->common.co = qemu_coroutine_create(backup_run);
     qemu_coroutine_enter(job->common.co, job);
diff --git a/block/mirror.c b/block/mirror.c
index fc545f1..427c688 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -717,6 +717,10 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
     bool is_none_mode;
     BlockDriverState *base;
 
+    if (mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
+        error_setg(errp, "Sync mode 'dirty-bitmap' not supported");
+        return;
+    }
     is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
     base = mode == MIRROR_SYNC_MODE_TOP ? bs->backing_hd : NULL;
     mirror_start_job(bs, target, replaces,
diff --git a/blockdev.c b/blockdev.c
index 8dde72a..114a94c 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1569,6 +1569,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
                      backup->sync,
                      backup->has_mode, backup->mode,
                      backup->has_speed, backup->speed,
+                     backup->has_bitmap, backup->bitmap,
                      backup->has_on_source_error, backup->on_source_error,
                      backup->has_on_target_error, backup->on_target_error,
                      &local_err);
@@ -2358,6 +2359,7 @@ void qmp_drive_backup(const char *device, const char *target,
                       enum MirrorSyncMode sync,
                       bool has_mode, enum NewImageMode mode,
                       bool has_speed, int64_t speed,
+                      bool has_bitmap, const char *bitmap,
                       bool has_on_source_error, BlockdevOnError on_source_error,
                       bool has_on_target_error, BlockdevOnError on_target_error,
                       Error **errp)
@@ -2365,6 +2367,7 @@ void qmp_drive_backup(const char *device, const char *target,
     BlockDriverState *bs;
     BlockDriverState *target_bs;
     BlockDriverState *source = NULL;
+    BdrvDirtyBitmap *bmap = NULL;
     AioContext *aio_context;
     BlockDriver *drv = NULL;
     Error *local_err = NULL;
@@ -2460,7 +2463,16 @@ void qmp_drive_backup(const char *device, const char *target,
 
     bdrv_set_aio_context(target_bs, aio_context);
 
-    backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
+    if (has_bitmap) {
+        bmap = bdrv_find_dirty_bitmap(bs, bitmap);
+        if (!bmap) {
+            error_setg(errp, "Bitmap '%s' could not be found", bitmap);
+            goto out;
+        }
+    }
+
+    backup_start(bs, target_bs, speed, sync, bmap,
+                 on_source_error, on_target_error,
                  block_job_cb, bs, &local_err);
     if (local_err != NULL) {
         bdrv_unref(target_bs);
diff --git a/hmp.c b/hmp.c
index 481be80..63b19c7 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1021,7 +1021,8 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
 
     qmp_drive_backup(device, filename, !!format, format,
                      full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
-                     true, mode, false, 0, false, 0, false, 0, &err);
+                     true, mode, false, 0, false, NULL,
+                     false, 0, false, 0, &err);
     hmp_handle_error(mon, &err);
 }
 
diff --git a/include/block/block.h b/include/block/block.h
index 6138544..99ed679 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -462,6 +462,7 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
 void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_iter_init(BlockDriverState *bs,
                           BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
+void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
 int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
 
 void bdrv_enable_copy_on_read(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 06a21dd..cb1e4a1 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -584,6 +584,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
  * @target: Block device to write to.
  * @speed: The maximum speed, in bytes per second, or 0 for unlimited.
  * @sync_mode: What parts of the disk image should be copied to the destination.
+ * @sync_bitmap: The dirty bitmap if sync_mode is MIRROR_SYNC_MODE_DIRTY_BITMAP.
  * @on_source_error: The action to take upon error reading from the source.
  * @on_target_error: The action to take upon error writing to the target.
  * @cb: Completion function for the job.
@@ -594,6 +595,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
  */
 void backup_start(BlockDriverState *bs, BlockDriverState *target,
                   int64_t speed, MirrorSyncMode sync_mode,
+                  BdrvDirtyBitmap *sync_bitmap,
                   BlockdevOnError on_source_error,
                   BlockdevOnError on_target_error,
                   BlockCompletionFunc *cb, void *opaque,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 3e863b9..92c3a84 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -500,7 +500,7 @@
 # Since: 1.3
 ##
 { 'enum': 'MirrorSyncMode',
-  'data': ['top', 'full', 'none'] }
+  'data': ['top', 'full', 'none', 'dirty-bitmap'] }
 
 ##
 # @BlockJobType:
@@ -675,14 +675,17 @@
 #          probe if @mode is 'existing', else the format of the source
 #
 # @sync: what parts of the disk image should be copied to the destination
-#        (all the disk, only the sectors allocated in the topmost image, or
-#        only new I/O).
+#        (all the disk, only the sectors allocated in the topmost image, from a
+#        dirty bitmap, or only new I/O).
 #
 # @mode: #optional whether and how QEMU should create a new image, default is
 #        'absolute-paths'.
 #
 # @speed: #optional the maximum speed, in bytes per second
 #
+# @bitmap: #optional the name of dirty bitmap if sync is "dirty-bitmap"
+#          (Since 2.3)
+#
 # @on-source-error: #optional the action to take on an error on the source,
 #                   default 'report'.  'stop' and 'enospc' can only be used
 #                   if the block device supports io-status (see BlockInfo).
@@ -700,7 +703,7 @@
 { 'type': 'DriveBackup',
   'data': { 'device': 'str', 'target': 'str', '*format': 'str',
             'sync': 'MirrorSyncMode', '*mode': 'NewImageMode',
-            '*speed': 'int',
+            '*speed': 'int', '*bitmap': 'str',
             '*on-source-error': 'BlockdevOnError',
             '*on-target-error': 'BlockdevOnError' } }
 
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 59be8eb..479d4f5 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -1048,7 +1048,7 @@ EQMP
     {
         .name       = "drive-backup",
         .args_type  = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?,"
-                      "on-source-error:s?,on-target-error:s?",
+                      "bitmap:s?,on-source-error:s?,on-target-error:s?",
         .mhandler.cmd_new = qmp_marshal_input_drive_backup,
     },
 
@@ -1075,8 +1075,9 @@ Arguments:
             (json-string, optional)
 - "sync": what parts of the disk image should be copied to the destination;
   possibilities include "full" for all the disk, "top" for only the sectors
-  allocated in the topmost image, or "none" to only replicate new I/O
-  (MirrorSyncMode).
+  allocated in the topmost image, "dirty-bitmap" for only the dirty sectors in
+  the bitmap, or "none" to only replicate new I/O (MirrorSyncMode).
+- "bitmap": dirty bitmap name for sync==dirty-bitmap
 - "mode": whether and how QEMU should create a new image
           (NewImageMode, optional, default 'absolute-paths')
 - "speed": the maximum speed, in bytes per second (json-int, optional)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 10/13] qapi: Add transaction support to block-dirty-bitmap-{add, enable, disable}
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (8 preceding siblings ...)
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup John Snow
@ 2015-01-12 16:31 ` John Snow
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 11/13] qmp: Add dirty bitmap status fields in query-block John Snow
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-12 16:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

From: Fam Zheng <famz@redhat.com>

This adds three qmp commands to transactions.

Users can stop a dirty bitmap, start backup of it, and start another
dirty bitmap atomically, so that the dirty bitmap is tracked
incrementally and we don't miss any write.

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 blockdev.c       | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qapi-schema.json |   5 ++-
 2 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/blockdev.c b/blockdev.c
index 114a94c..e283581 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1602,6 +1602,94 @@ static void drive_backup_clean(BlkTransactionState *common)
     }
 }
 
+static void block_dirty_bitmap_add_prepare(BlkTransactionState *common,
+                                           Error **errp)
+{
+    BlockDirtyBitmapAdd *action;
+
+    action = common->action->block_dirty_bitmap_add;
+    qmp_block_dirty_bitmap_add(action->node_ref, action->name,
+                               action->has_granularity, action->granularity,
+                               errp);
+}
+
+static void block_dirty_bitmap_add_abort(BlkTransactionState *common)
+{
+    BlockDirtyBitmapAdd *action;
+
+    action = common->action->block_dirty_bitmap_add;
+    /* Should not fail meaningfully: IF the bitmap was added via .prepare(),
+     * then the node reference and bitmap name must have been valid.
+     * THUS: any failure here could only indicate the lack of a bitmap at all.
+     */
+    qmp_block_dirty_bitmap_remove(action->node_ref, action->name, NULL);
+}
+
+typedef struct BlockDirtyBitmapState {
+    BlkTransactionState common;
+    BdrvDirtyBitmap *bitmap;
+    AioContext *aio_context;
+} BlockDirtyBitmapState;
+
+/**
+ * Enable and Disable re-use the same preparation.
+ */
+static void block_dirty_bitmap_toggle_prepare(BlkTransactionState *common,
+                                              Error **errp)
+{
+    BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
+                                             common, common);
+    BlockDirtyBitmap *action;
+    BlockDriverState *bs;
+
+    /* We may be used by either enable or disable;
+     * We use the "enable" member of the union here,
+     * but "disable" should be functionally equivalent: */
+    action = common->action->block_dirty_bitmap_enable;
+    assert(action == common->action->block_dirty_bitmap_disable);
+
+    state->bitmap = block_dirty_bitmap_lookup(action->node_ref,
+                                              action->name,
+                                              &bs,
+                                              errp);
+    if (!state->bitmap) {
+        return;
+    }
+
+    if (bdrv_dirty_bitmap_frozen(state->bitmap)) {
+        error_setg(errp, "Cannot enable/disable a bitmap that is frozen.\n");
+        return;
+    }
+
+    /* AioContext is released in .clean() */
+    state->aio_context = bdrv_get_aio_context(bs);
+    aio_context_acquire(state->aio_context);
+}
+
+static void block_dirty_bitmap_enable_commit(BlkTransactionState *common)
+{
+    BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
+                                             common, common);
+    bdrv_enable_dirty_bitmap(state->bitmap);
+}
+
+static void block_dirty_bitmap_disable_commit(BlkTransactionState *common)
+{
+    BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
+                                             common, common);
+    bdrv_disable_dirty_bitmap(state->bitmap);
+}
+
+static void block_dirty_bitmap_toggle_clean(BlkTransactionState *common)
+{
+    BlockDirtyBitmapState *state = DO_UPCAST(BlockDirtyBitmapState,
+                                             common, common);
+
+    if (state->aio_context) {
+        aio_context_release(state->aio_context);
+    }
+}
+
 static void abort_prepare(BlkTransactionState *common, Error **errp)
 {
     error_setg(errp, "Transaction aborted using Abort action");
@@ -1636,6 +1724,23 @@ static const BdrvActionOps actions[] = {
         .abort = internal_snapshot_abort,
         .clean = internal_snapshot_clean,
     },
+    [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ADD] = {
+        .instance_size = sizeof(BlkTransactionState),
+        .prepare = block_dirty_bitmap_add_prepare,
+        .abort = block_dirty_bitmap_add_abort,
+    },
+    [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_ENABLE] = {
+        .instance_size = sizeof(BlockDirtyBitmapState),
+        .prepare = block_dirty_bitmap_toggle_prepare,
+        .commit = block_dirty_bitmap_enable_commit,
+        .clean = block_dirty_bitmap_toggle_clean,
+    },
+    [TRANSACTION_ACTION_KIND_BLOCK_DIRTY_BITMAP_DISABLE] = {
+        .instance_size = sizeof(BlockDirtyBitmapState),
+        .prepare = block_dirty_bitmap_toggle_prepare,
+        .commit = block_dirty_bitmap_disable_commit,
+        .clean = block_dirty_bitmap_toggle_clean,
+    },
 };
 
 /*
diff --git a/qapi-schema.json b/qapi-schema.json
index 563b4ad..85f55d9 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1260,7 +1260,10 @@
        'blockdev-snapshot-sync': 'BlockdevSnapshot',
        'drive-backup': 'DriveBackup',
        'abort': 'Abort',
-       'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal'
+       'blockdev-snapshot-internal-sync': 'BlockdevSnapshotInternal',
+       'block-dirty-bitmap-add': 'BlockDirtyBitmapAdd',
+       'block-dirty-bitmap-enable': 'BlockDirtyBitmap',
+       'block-dirty-bitmap-disable': 'BlockDirtyBitmap'
    } }
 
 ##
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 11/13] qmp: Add dirty bitmap status fields in query-block
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (9 preceding siblings ...)
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 10/13] qapi: Add transaction support to block-dirty-bitmap-{add, enable, disable} John Snow
@ 2015-01-12 16:31 ` John Snow
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 12/13] qemu-iotests: Add tests for drive-backup sync=dirty-bitmap John Snow
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-12 16:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

From: Fam Zheng <famz@redhat.com>

Adds the "enabled" and "frozen" status booleans.

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c              | 2 ++
 qapi/block-core.json | 7 ++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/block.c b/block.c
index 5eb6788..9e2b8c0 100644
--- a/block.c
+++ b/block.c
@@ -5531,6 +5531,8 @@ BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
         info->granularity = bdrv_dirty_bitmap_granularity(bs, bm);
         info->has_name = !!bm->name;
         info->name = g_strdup(bm->name);
+        info->enabled = bm->enabled;
+        info->frozen = bm->frozen;
         entry->value = info;
         *plist = entry;
         plist = &entry->next;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 92c3a84..5f82cf3 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -328,10 +328,15 @@
 #
 # @granularity: granularity of the dirty bitmap in bytes (since 1.4)
 #
+# @enabled: whether the dirty bitmap is enabled (Since 2.3)
+#
+# @frozen: whether the dirty bitmap is frozen (Since 2.3)
+#
 # Since: 1.3
 ##
 { 'type': 'BlockDirtyInfo',
-  'data': {'*name': 'str', 'count': 'int', 'granularity': 'int'} }
+  'data': {'*name': 'str', 'count': 'int', 'granularity': 'int',
+           'enabled': 'bool', 'frozen': 'bool'} }
 
 ##
 # @BlockInfo:
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 12/13] qemu-iotests: Add tests for drive-backup sync=dirty-bitmap
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (10 preceding siblings ...)
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 11/13] qmp: Add dirty bitmap status fields in query-block John Snow
@ 2015-01-12 16:31 ` John Snow
  2015-02-06 14:23   ` Vladimir Sementsov-Ogievskiy
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 13/13] block: BdrvDirtyBitmap miscellaneous fixup John Snow
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-12 16:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

From: Fam Zheng <famz@redhat.com>

Signed-off-by: Fam Zheng <famz@redhat.com>
Signed-off-by: John Snow <jsnow@redhat.com>
---
 tests/qemu-iotests/056        | 33 ++++++++++++++++++++++++++++++---
 tests/qemu-iotests/056.out    |  4 ++--
 tests/qemu-iotests/iotests.py |  8 ++++++++
 3 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056
index 54e4bd0..6f8aa9a 100755
--- a/tests/qemu-iotests/056
+++ b/tests/qemu-iotests/056
@@ -23,17 +23,17 @@
 import time
 import os
 import iotests
-from iotests import qemu_img, qemu_io, create_image
+from iotests import qemu_img, qemu_img_map_assert, qemu_io, create_image
 
 backing_img = os.path.join(iotests.test_dir, 'backing.img')
 test_img = os.path.join(iotests.test_dir, 'test.img')
 target_img = os.path.join(iotests.test_dir, 'target.img')
 
-class TestSyncModesNoneAndTop(iotests.QMPTestCase):
+class TestSyncModes(iotests.QMPTestCase):
     image_len = 64 * 1024 * 1024 # MB
 
     def setUp(self):
-        create_image(backing_img, TestSyncModesNoneAndTop.image_len)
+        create_image(backing_img, TestSyncModes.image_len)
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
         qemu_io('-c', 'write -P0x41 0 512', test_img)
         qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
@@ -64,6 +64,33 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase):
         self.assertTrue(iotests.compare_images(test_img, target_img),
                         'target image does not match source after backup')
 
+    def test_sync_dirty_bitmap_missing(self):
+        self.assert_no_active_block_jobs()
+        result = self.vm.qmp('drive-backup', device='drive0', sync='dirty-bitmap',
+                             format=iotests.imgfmt, target=target_img)
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+    def test_sync_dirty_bitmap_not_found(self):
+        self.assert_no_active_block_jobs()
+        result = self.vm.qmp('drive-backup', device='drive0', sync='dirty-bitmap',
+                             bitmap='unknown',
+                             format=iotests.imgfmt, target=target_img)
+        self.assert_qmp(result, 'error/class', 'GenericError')
+
+    def test_sync_dirty_bitmap(self):
+        self.assert_no_active_block_jobs()
+        result = self.vm.qmp('block-dirty-bitmap-add', node_ref='drive0', name='bitmap0')
+        self.assert_qmp(result, 'return', {})
+        self.vm.hmp_qemu_io('drive0', 'write -P0x5a 0 512')
+        self.vm.hmp_qemu_io('drive0', 'write -P0x5a 48M 512')
+        result = self.vm.qmp('drive-backup', device='drive0', sync='dirty-bitmap',
+                             bitmap='bitmap0',
+                             format=iotests.imgfmt, target=target_img)
+        self.assert_qmp(result, 'return', {})
+        self.wait_until_completed(check_offset=False)
+        self.assert_no_active_block_jobs()
+        qemu_img_map_assert(target_img, [0, 0x3000000])
+
     def test_cancel_sync_none(self):
         self.assert_no_active_block_jobs()
 
diff --git a/tests/qemu-iotests/056.out b/tests/qemu-iotests/056.out
index fbc63e6..914e373 100644
--- a/tests/qemu-iotests/056.out
+++ b/tests/qemu-iotests/056.out
@@ -1,5 +1,5 @@
-..
+.....
 ----------------------------------------------------------------------
-Ran 2 tests
+Ran 5 tests
 
 OK
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index f57f154..95bb959 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -55,6 +55,14 @@ def qemu_img_pipe(*args):
     '''Run qemu-img and return its output'''
     return subprocess.Popen(qemu_img_args + list(args), stdout=subprocess.PIPE).communicate()[0]
 
+def qemu_img_map_assert(img, offsets):
+    '''Run qemu-img map on img and check the mapped ranges'''
+    offs = []
+    for line in qemu_img_pipe('map', img).splitlines()[1:]:
+        offset, length, mapped, fname = line.split()
+        offs.append(int(offset, 16))
+    assert set(offs) == set(offsets), "mapped offsets in image '%s' not equal to '%s'" % (str(offs), str(offsets))
+
 def qemu_io(*args):
     '''Run qemu-io and return the stdout data'''
     args = qemu_io_args + list(args)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [Qemu-devel] [PATCH v11 13/13] block: BdrvDirtyBitmap miscellaneous fixup
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (11 preceding siblings ...)
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 12/13] qemu-iotests: Add tests for drive-backup sync=dirty-bitmap John Snow
@ 2015-01-12 16:31 ` John Snow
  2015-01-13 16:50   ` Vladimir Sementsov-Ogievskiy
  2015-01-13  1:21 ` [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series Fam Zheng
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-12 16:31 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, John Snow, armbru, mreitz, vsementsov, stefanha

(1) granularity type consistency: Update the granularity to be uint64_t
    in all places. This value is always in bytes.

(2) Some documentation for the fields within BdrvDirtyBitmap.

Signed-off-by: John Snow <jsnow@redhat.com>
---
 block.c               | 16 ++++++++--------
 include/block/block.h |  2 +-
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/block.c b/block.c
index 9e2b8c0..13f9cc0 100644
--- a/block.c
+++ b/block.c
@@ -52,13 +52,13 @@
 #endif
 
 struct BdrvDirtyBitmap {
-    HBitmap *bitmap;
-    BdrvDirtyBitmap *successor;
-    int64_t size;
-    int64_t granularity;
-    char *name;
-    bool enabled;
-    bool frozen;
+    HBitmap *bitmap;            /* Dirty sector bitmap */
+    BdrvDirtyBitmap *successor; /* Anonymous child */
+    int64_t size;               /* Number of sectors */
+    uint64_t granularity;       /* Granularity in bytes */
+    char *name;                 /* Optional non-empty unique ID */
+    bool enabled;               /* Writes are being tracked */
+    bool frozen;                /* Protected; see bdrv_freeze_dirty_bitmap() */
     QLIST_ENTRY(BdrvDirtyBitmap) list;
 };
 
@@ -5350,7 +5350,7 @@ void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
 }
 
 BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
-                                          int granularity,
+                                          uint64_t granularity,
                                           const char *name,
                                           Error **errp)
 {
diff --git a/include/block/block.h b/include/block/block.h
index 99ed679..749429e 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -430,7 +430,7 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
 struct HBitmapIter;
 typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
 BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
-                                          int granularity,
+                                          uint64_t granularity,
                                           const char *name,
                                           Error **errp);
 int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (12 preceding siblings ...)
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 13/13] block: BdrvDirtyBitmap miscellaneous fixup John Snow
@ 2015-01-13  1:21 ` Fam Zheng
  2015-01-13 19:52 ` John Snow
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 54+ messages in thread
From: Fam Zheng @ 2015-01-13  1:21 UTC (permalink / raw)
  To: John Snow; +Cc: kwolf, armbru, qemu-devel, mreitz, vsementsov, stefanha

On Mon, 01/12 11:30, John Snow wrote:
> Welcome to version 11. I hope you are enjoying our regular newsletter.
> 
> This patchset enables the in-memory part of the incremental backup
> feature. A patchset by Vladimir Sementsov-Ogievskiy enables the
> migration of in-memory dirty bitmaps, and a future patchset will
> enable the storage and retrieval of dirty bitmaps to and from permanent
> storage.
> 
> Enough changes have been made that most Reviewed-By lines from
> previous iterations have been removed. (Sorry!)
> 
> This series was originally authored by Fam Zheng;
> his cover letter is included below.

Speaking of the authorship, if there is v12, I don't mind switching all my
patches to your name, considering how long you've been taken them along since
very early versions (look at the changelog below :).

Fam

> 
> ~John Snow
> 
> =================================================================
> 
> This is the in memory part of the incremental backup feature.
> 
> With the added commands, we can create a bitmap on a block
> backend, from which point of time all the writes are tracked by
> the bitmap, marking sectors as dirty. Later, we call drive-backup
> and pass the bitmap to it, to do an incremental backup.
> 
> See the last patch which adds some tests for this use case.
> 
> Fam
> 
> =================================================================
> 
> For convenience, this patchset is available on github:
>                 https://github.com/jnsnow/qemu/commits/dbm-backup
> 
> v11:
> 
>  - Instead of copying BdrvDirtyBitmaps and keeping a pointer to the
>    object we were copied from, we instead "freeze" a bitmap in-place
>    without copying it. On success, we thaw and delete the bitmap.
>    On failure, we merge the bitmap with a "successor," which is an
>    anonymous bitmap attached as a child that records writes for us
>    for the duration of the backup operation.
> 
>    This means that incremental backups can NEVER BE RETRIED in a
>    deterministic fashion. If an incremental backup fails on a set
>    of dirty sectors {x}, and a new set of dirty sectors {y} are
>    introduced during the backup, then any possible retry action
>    on an incremental backup can only operate on {x,y}. There is no
>    way to get an incremental backup "as it would have been."
> 
>    So, the failure mode for incremental backup is to try again,
>    and the resulting image will simply be a differential from the
>    last successful dirty bitmap backup.
> 
>  - Removed hbitmap_copy and bdrv_dirty_bitmap_copy.
> 
>  - Added a small fixup patch:
>    - Update all granularity fields to be uint64_t.
>    - Update documentation around BdrvDirtyBitmap structure.
> 
>  - Modified transactions to obey frozen attribute of BdrvDirtyBitmaps.
> 
>  - Added frozen attribute to the info query.
> 
> v10 (Overview):
> 
>  - I've included one of Vladimir's bitmap fixes as patch #1.
> 
>  - QMP commands and transactions are now protected via
>    aio_context functions.
> 
>  - QMP commands use "node-ref" as a parameter name now. Reasoning
>    is thus: Either a "device name" or a "node name" can be used to
>    reference a BDS, which is the key item we are actually acting
>    on with these bitmap commands. Thus, I refer to this unified
>    parameter as a "Node Reference," or "node-ref."
> 
>    We could also argue for "backend-ref" or "device-ref" for the
>    reverse semantics: where we accept a unified parameter, but we
>    intend to resolve it to the BlockBackend instead of resolving
>    the parameter given to the BlockDriverState.
> 
>    Or, we could use "reference" for both cases, and to match the
>    existing BlockdevRef command.
> 
>  - All QMP commands added are now per-node via a unified parameter
>    name. Though backup only operates on "devices," you are free to
>    create bitmaps for any arbitrary node you wish. It is obviously
>    only useful for the root node, currently.
> 
>  - Bitmap Sync modes (CONSUME, RESET) are removed. See below
>    (changelog, RFC questions) for more details.
> 
>  - Code to recover the bitmap after a failure has been added,
>    but I have some major questions about drive_backup guarantees.
>    See RFC questions.
> 
> v10 (Detailed Changelog):
> 
>    (1/13) New Patch:
>  - Included Vladimir Sementsov-Ogievskiy's patch that clarifies
>    the semantics of the bitmap primitives.
> 
>    (3/13):
>  - Edited function names for consistency (Stefanha)
>  - Removed compile-time constants (Stefanha)
>  - Acquire aio_context for bitmap add/remove (Stefanha)
>  - Documented optional granularity for bitmap-add in
>    qmp-commands.hx file (Eric Blake)
>  - block_dirty_bitmap_lookup moved forward to this patch to allow
>    more re-use. (Stefanha)
>  - Fixed a problem where the block_dirty_bitmap_lookup didn't
>    always set an error if it returned NULL.
>  - Added an optional return BDS lookup parameter to
>    bdrv_dirty_bitmap_lookup.
>  - Renamed "device" to "node-ref" for block_dirty_bitmap_lookup,
>    adjusted calls to bdrv_lookup_bs() to reflect unified
>    parameter usage.
>  - qmp_block_dirty_bitmap_{add,remove} now reference arbitrary
>    node names via @node-ref.
> 
>    (4/13):
>  - Default granularity and granularity getters are both
>    now uint64_t (Stefanha)
> 
>    (5/13):
>  - Added documentation to warn about the necessity of updating
>    the hbitmap deep copy. (Stefanha)
> 
>    (6/13)
>  - Renamed bdrv_reset_dirty_bitmap to bdrv_clear_dirty_bitmap
>    to be consistent with Vladimir's patches.
>  - Removed const qualifier for bdrv_copy_dirty_bitmap,
>    to accommodate patch 8.
> 
>    (7/13) New Patch:
>  - Added an hbitmap_merge operation to join two bitmaps together.
> 
>    (8/13) New Patch:
>  - Added bdrv_reclaim_dirty_bitmap() to allow us to "roll back" a
>    bitmap into the bitmap that it was spawned from. This will let
>    us maintain an accurate account of dirty sectors even after a
>    failure.
>  - This adds an "originator" pointer to the BdrvDirtyBitmap and
>    is why "const" was removed for copy.
> 
>    (9/13):
>  - QMP semantics changes as outlined for Patch #3.
>  - Enable/Disable now protected by aio_context (Stefanha)
> 
>    (10/13):
>  - Add coroutine_fn annotation to block backup helper. (Stefanha)
>  - Removed sync_bitmap_gran from BackupBlockJob, just use the
>    getter on the BdrvDirtyBitmap instead. (Stefanha)
>  - bdrv_dirty_iter_set was renamed to bdrv_set_dirty_iter.
>  - Calls to bdrv_reset_dirty_bitmap are modified to
>    bdrv_clear_dirty_bitmap to reflect the rename in patch #6.
>  - Bitmap usage modes (RESET vs. CONSUME) has been deleted, for
>    the reason of targeting a simpler core usage first before
>    targeting optimizations. CONSUME is particularly problematic
>    in the case of errors; so this mode is omitted for now.
>  - Adjusted error message to use MirrorSyncMode enum, not
>    (incorrectly) the BitmapSyncMode enum.
>  - In the event of a failure, the sync_bitmap is now merged back
>    into the original bitmap so that we do not lose any dirty
>    bitmap information needlessly.
> 
>    (11/13):
>  - Changed block_dirty_bitmap_add_abort to use
>    qmp_block_dirty_bitmap_remove:
>     - Old code used bdrv_lookup_bs to acquire bitmap and bs
>       anyway, and ignored the failure case.
>     - New code relies on the same information, and with a NULL
>       errp pointer we will similarly ignore the failure case.
>       prepare() should have properly vetted this information
>       before this point anyway.
>       This new code is also now protected via aio_context through
>       the use of the QMP commands.
>  - More code re-use of block_dirty_bitmap_lookup to get both the
>    bs and bitmap pointers.
>  - aio_context protection and cleanup in new abort methods.
> 
>    (13/13):
>  - Modified test for new parameter names.
> 
> v9:
>  - Edited commit message, for English embetterment (02/10)
>  - Rebased on top of stefanha/block-next (06,08/10)
>  - Adjusted error message and line length (07/10)
> 
> v8:
>  - Changed int64_t return for bdrv_dbm_calc_def_granularity to uint64_t (2/10)
>  - Updated commit message (2/10)
>  - Removed redundant check for null in device parameter (2/10)
>  - Removed comment cruft. (2/10)
>  - Removed redundant local_err propagation (several)
>  - Updated commit message (3/10)
>  - Fix HBitmap copy loop index (4/10)
>  - Remove redundant ternary (5/10)
>  - Shift up the block_dirty_bitmap_lookup function (6/10)
>  - Error messages cleanup (7/10)
>  - Add an assertion to explain the re-use of .prepare() for two transactions.
>    (8/10)
>  - Removed BDS argument from bitmap enable/disable helper; it was unused. (8/10)
> 
> v7: (highlights)
>  - First version being authored by jsnow
>  - Addressed most list feedback from V6, many small changes.
>    All feedback was either addressed on-list (as a wontfix) or patched.
>  - Replaced all error_set with error_setg
>  - Replaced all bdrv_find with bdrv_lookup_bs()
>  - Adjusted the max granularity to share a common function with
>    backup/mirror that attempts to "guess" a reasonable default.
>    It clamps between [4K,64K] currently.
>  - The BdrvDirtyBitmap object now counts granularity exclusively in
>    bytes to match its interface.
>    It leaves the sector granularity concerns to HBitmap.
>  - Reworked the backup loop to utilize the hbitmap iterator.
>    There are some extra concerns to handle arrhythmic cases where the
>    granularity of the bitmap does not match the backup cluster size.
>    This iteration works best when it does match, but it's not a
>    deal-breaker if it doesn't -- it just gets less efficient.
>  - Reworked the transactional functions so that abort() wouldn't "undo"
>    a redundant command. They now have been split into a prepare and a
>    commit function (with state) and do not provide an abort command.
>  - Added a block_dirty_bitmap_lookup(device, name, errp) function to
>    shorten a few of the commands added in this series, particularly
>    qmp_enable, qmp_disable, and the transaction preparations.
> 
> v6: Re-send of v5.
> 
> v5: Rebase to master.
> 
> v4: Last version tailored by Fam Zheng.
> 
> ==
> 
> Fam Zheng (7):
>   qapi: Add optional field "name" to block dirty bitmap
>   qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
>   block: Introduce bdrv_dirty_bitmap_granularity()
>   qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable
>   qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>     disable}
>   qmp: Add dirty bitmap status fields in query-block
>   qemu-iotests: Add tests for drive-backup sync=dirty-bitmap
> 
> John Snow (5):
>   block: Add bdrv_clear_dirty_bitmap
>   hbitmap: add hbitmap_merge
>   block: Add bitmap successors
>   qmp: Add support of "dirty-bitmap" sync mode for drive-backup
>   block: BdrvDirtyBitmap miscellaneous fixup
> 
> Vladimir Sementsov-Ogievskiy (1):
>   block: fix spoiling all dirty bitmaps by mirror and migration
> 
>  block.c                       | 254 +++++++++++++++++++++++++++++++++++++--
>  block/backup.c                | 120 +++++++++++++++----
>  block/mirror.c                |  27 ++---
>  blockdev.c                    | 273 +++++++++++++++++++++++++++++++++++++++++-
>  hmp.c                         |   3 +-
>  include/block/block.h         |  31 ++++-
>  include/block/block_int.h     |   2 +
>  include/qemu/hbitmap.h        |  11 ++
>  migration/block.c             |   7 +-
>  qapi-schema.json              |   5 +-
>  qapi/block-core.json          | 103 +++++++++++++++-
>  qmp-commands.hx               |  68 ++++++++++-
>  tests/qemu-iotests/056        |  33 ++++-
>  tests/qemu-iotests/056.out    |   4 +-
>  tests/qemu-iotests/iotests.py |   8 ++
>  util/hbitmap.c                |  28 +++++
>  16 files changed, 910 insertions(+), 67 deletions(-)
> 
> -- 
> 1.9.3
> 

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors John Snow
@ 2015-01-13  9:24   ` Fam Zheng
  2015-01-13 17:26     ` John Snow
  2015-01-16 18:22     ` John Snow
  0 siblings, 2 replies; 54+ messages in thread
From: Fam Zheng @ 2015-01-13  9:24 UTC (permalink / raw)
  To: John Snow
  Cc: kwolf, armbru, qemu-devel, mreitz, vsementsov, stefanha, pbonzini

On Mon, 01/12 11:31, John Snow wrote:
> A bitmap successor is an anonymous BdrvDirtyBitmap that is intended to
> be created just prior to a sensitive operation (e.g. Incremental Backup)
> that can either succeed or fail, but during the course of which we still
> want a bitmap tracking writes.
> 
> On creating a successor, we "freeze" the parent bitmap which prevents
> its deletion, enabling, anonymization, or creating a bitmap with the
> same name.
> 
> On success, the parent bitmap can "abdicate" responsibility to the
> successor, which will inherit its name. The successor will have been
> tracking writes during the course of the backup operation. The parent
> will be safely deleted.
> 
> On failure, we can "reclaim" the successor from the parent, unifying
> them such that the resulting bitmap describes all writes occurring since
> the last successful backup, for instance. Reclamation will thaw the
> parent, but not explicitly re-enable it.

If we compare this with image snapshot and overlay, it fits the current backing
chain model very well.  Given that we're on the way to persistent dirty bitmap,
which will probably be read/written with general block.c code, I'm wondering if
it will be any better to reuse the block layer backing file code to handle
"successor" logic?

Also with the frozen feature built in dirty bitmaps, is it okay to drop
"enabled" state?

I think there are three states for a bitmap:

1) Active, no successor (similar to an read-write top image)
2) Frozen, no successor (similar to an read-only top image)
3) Frozen, with successor (similar to an read-only backing file, with an
   overlap)

Admittedly, more code is needed than this patch, in order to glue hbitmap and
block layer together, but it would probably make live migration of dirty bitmap
very easy, but I'm not sure without a closer look.

> 
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>  block.c               | 123 ++++++++++++++++++++++++++++++++++++++++++++++++--
>  blockdev.c            |  14 ++++++
>  include/block/block.h |  10 ++++
>  3 files changed, 144 insertions(+), 3 deletions(-)
> 
> diff --git a/block.c b/block.c
> index bd4b449..3f33b9d 100644
> --- a/block.c
> +++ b/block.c
> @@ -53,10 +53,12 @@
>  
>  struct BdrvDirtyBitmap {
>      HBitmap *bitmap;
> +    BdrvDirtyBitmap *successor;
>      int64_t size;
>      int64_t granularity;
>      char *name;
>      bool enabled;
> +    bool frozen;
>      QLIST_ENTRY(BdrvDirtyBitmap) list;
>  };
>  
> @@ -5342,6 +5344,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
>  
>  void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>  {
> +    assert(!bitmap->frozen);
>      g_free(bitmap->name);
>      bitmap->name = NULL;
>  }
> @@ -5379,9 +5382,114 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>      return bitmap;
>  }
>  
> +/**
> +  * A frozen bitmap cannot be renamed, deleted, cleared,
> +  * or set. A frozen bitmap can only abdicate, reclaim,
> +  * or thaw.
> +  */
> +static void bdrv_freeze_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    bitmap->frozen = true;
> +}
> +
> +static void bdrv_thaw_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    bitmap->frozen = false;
> +}
> +
> +bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
> +{
> +    return bitmap->frozen;
> +}
> +
>  bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
>  {
> -    return bitmap->enabled;
> +    return bitmap->enabled && !bitmap->frozen;

An indication that "enabled" could be replaced by "frozen". Otherwise it looks
confusing to me.

> +}
> +
> +/**
> + * Create a successor bitmap destined to replace this bitmap after an operation.
> + * Requires that the bitmap is not frozen and has no successor.
> + */
> +int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
> +                                       BdrvDirtyBitmap *bitmap, Error **errp)
> +{
> +    uint64_t granularity;
> +
> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
> +        error_setg(errp,
> +                   "Cannot create a successor for a bitmap currently in-use.");
> +        return -1;
> +    } else if (bitmap->successor) {
> +        error_setg(errp, "Cannot create a successor for a bitmap that "
> +                   "already has one.");
> +        return -1;
> +    }
> +
> +    /* Create an anonymous successor */
> +    granularity = bdrv_dirty_bitmap_granularity(bs, bitmap);
> +    bitmap->successor = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
> +    if (!bitmap->successor) {
> +        return -1;
> +    }
> +
> +    /* Successor will be on or off based on our current state.
> +     * Parent will be disabled and frozen. */
> +    bitmap->successor->enabled = bitmap->enabled;
> +    bdrv_disable_dirty_bitmap(bitmap);
> +    bdrv_freeze_dirty_bitmap(bitmap);
> +    return 0;
> +}
> +
> +/**
> + * For a bitmap with a successor, yield our name to the successor,
> + * Delete the old bitmap, and return a handle to the new bitmap.
> + */
> +BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
> +                                            BdrvDirtyBitmap *bitmap,
> +                                            Error **errp)
> +{
> +    char *name;
> +    BdrvDirtyBitmap *successor = bitmap->successor;
> +
> +    if (successor == NULL) {
> +        error_setg(errp, "Cannot relinquish control if "
> +                   "there's no successor present.\n");
> +        return NULL;
> +    }
> +
> +    name = bitmap->name;
> +    bitmap->name = NULL;
> +    successor->name = name;
> +
> +    bdrv_thaw_dirty_bitmap(bitmap);
> +    bdrv_release_dirty_bitmap(bs, bitmap);
> +
> +    return successor;
> +}
> +
> +/**
> + * In cases of failure where we can no longer safely delete the parent,
> + * We may wish to re-join the parent and child/successor.
> + * The merged parent will be un-frozen, but not explicitly re-enabled.
> + */
> +BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
> +                                           BdrvDirtyBitmap *parent,
> +                                           Error **errp)
> +{
> +    BdrvDirtyBitmap *successor = parent->successor;
> +    if (!successor) {
> +        error_setg(errp, "Cannot reclaim a successor when none is present.\n");
> +        return NULL;
> +    }
> +
> +    hbitmap_merge(parent->bitmap, successor->bitmap);
> +    bdrv_release_dirty_bitmap(bs, successor);
> +
> +    bdrv_thaw_dirty_bitmap(parent);
> +    parent->successor = NULL;
> +
> +    return parent;
>  }
>  
>  void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
> @@ -5389,6 +5497,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>      BdrvDirtyBitmap *bm, *next;
>      QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
>          if (bm == bitmap) {
> +            assert(!bm->frozen);
>              QLIST_REMOVE(bitmap, list);
>              hbitmap_free(bitmap->bitmap);
>              g_free(bitmap->name);
> @@ -5405,6 +5514,7 @@ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>  
>  void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>  {
> +    assert(!bitmap->frozen);
>      bitmap->enabled = true;
>  }
>  
> @@ -5483,7 +5593,9 @@ void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>  void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>                               int64_t cur_sector, int nr_sectors)
>  {
> -    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
> +    if (!bitmap->frozen) {

Probably just assert it's not frozen?

> +        hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
> +    }
>  }
>  
>  /**
> @@ -5492,7 +5604,9 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>   */
>  void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>  {
> -    hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
> +    if (!bitmap->frozen) {
> +        hbitmap_reset(bitmap->bitmap, 0, bitmap->size);

The same: probably just assert it's not frozen?

> +    }
>  }
>  
>  static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
> @@ -5512,6 +5626,9 @@ static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
>  {
>      BdrvDirtyBitmap *bitmap;
>      QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> +        if (bitmap->frozen) {
> +            continue;
> +        }
>          hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
>      }
>  }
> diff --git a/blockdev.c b/blockdev.c
> index 118cb6c..8dde72a 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1988,9 +1988,16 @@ void qmp_block_dirty_bitmap_remove(const char *node_ref, const char *name,
>      aio_context = bdrv_get_aio_context(bs);
>      aio_context_acquire(aio_context);
>  
> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
> +        error_setg(errp,
> +                   "Bitmap %s is currently frozen and cannot be removed yet.\n",
> +                   name);
> +        goto out;
> +    }
>      bdrv_dirty_bitmap_make_anon(bs, bitmap);
>      bdrv_release_dirty_bitmap(bs, bitmap);
>  
> + out:
>      aio_context_release(aio_context);
>  }
>  
> @@ -2009,8 +2016,15 @@ void qmp_block_dirty_bitmap_enable(const char *node_ref, const char *name,
>      aio_context = bdrv_get_aio_context(bs);
>      aio_context_acquire(aio_context);
>  
> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
> +        error_setg(errp, "Bitmap %s is frozen and cannot be enabled yet.\n",
> +                   name);
> +        goto out;
> +    }
> +
>      bdrv_enable_dirty_bitmap(bitmap);
>  
> + out:
>      aio_context_release(aio_context);
>  }
>  
> diff --git a/include/block/block.h b/include/block/block.h
> index a5bc249..6138544 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -433,6 +433,15 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>                                            int granularity,
>                                            const char *name,
>                                            Error **errp);
> +int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
> +                                       BdrvDirtyBitmap *bitmap,
> +                                       Error **errp);
> +BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
> +                                            BdrvDirtyBitmap *bitmap,
> +                                            Error **errp);
> +BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
> +                                           BdrvDirtyBitmap *bitmap,
> +                                           Error **errp);
>  BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
>                                          const char *name);
>  void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
> @@ -444,6 +453,7 @@ uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
>  uint64_t bdrv_dirty_bitmap_granularity(BlockDriverState *bs,
>                                        BdrvDirtyBitmap *bitmap);
>  bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
> +bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
>  int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
>  void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>                             int64_t cur_sector, int nr_sectors);
> -- 
> 1.9.3
> 

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup John Snow
@ 2015-01-13  9:37   ` Fam Zheng
  2015-01-13 17:50     ` John Snow
  2015-01-16 17:52   ` Max Reitz
  1 sibling, 1 reply; 54+ messages in thread
From: Fam Zheng @ 2015-01-13  9:37 UTC (permalink / raw)
  To: John Snow; +Cc: kwolf, armbru, qemu-devel, mreitz, vsementsov, stefanha

On Mon, 01/12 11:31, John Snow wrote:
> For "dirty-bitmap" sync mode, the block job will iterate through the
> given dirty bitmap to decide if a sector needs backup (backup all the
> dirty clusters and skip clean ones), just as allocation conditions of
> "top" sync mode.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>  block.c                   |   5 ++
>  block/backup.c            | 120 ++++++++++++++++++++++++++++++++++++++--------
>  block/mirror.c            |   4 ++
>  blockdev.c                |  14 +++++-
>  hmp.c                     |   3 +-
>  include/block/block.h     |   1 +
>  include/block/block_int.h |   2 +
>  qapi/block-core.json      |  11 +++--
>  qmp-commands.hx           |   7 +--
>  9 files changed, 137 insertions(+), 30 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 3f33b9d..5eb6788 100644
> --- a/block.c
> +++ b/block.c
> @@ -5633,6 +5633,11 @@ static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
>      }
>  }
>  
> +void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
> +{
> +    hbitmap_iter_init(hbi, hbi->hb, offset);

What's the reason for this indirection? Can caller just use hbitmap_iter_init?

> +}
> +
>  int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>  {
>      return hbitmap_count(bitmap->bitmap);
> diff --git a/block/backup.c b/block/backup.c
> index 792e655..0626a3e 100644
> --- a/block/backup.c
> +++ b/block/backup.c
> @@ -37,6 +37,8 @@ typedef struct CowRequest {
>  typedef struct BackupBlockJob {
>      BlockJob common;
>      BlockDriverState *target;
> +    /* bitmap for sync=dirty-bitmap */
> +    BdrvDirtyBitmap *sync_bitmap;
>      MirrorSyncMode sync_mode;
>      RateLimit limit;
>      BlockdevOnError on_source_error;
> @@ -242,6 +244,31 @@ static void backup_complete(BlockJob *job, void *opaque)
>      g_free(data);
>  }
>  
> +static bool coroutine_fn yield_and_check(BackupBlockJob *job)
> +{
> +    if (block_job_is_cancelled(&job->common)) {
> +        return true;
> +    }
> +
> +    /* we need to yield so that qemu_aio_flush() returns.
> +     * (without, VM does not reboot)
> +     */
> +    if (job->common.speed) {
> +        uint64_t delay_ns = ratelimit_calculate_delay(&job->limit,
> +                                                      job->sectors_read);
> +        job->sectors_read = 0;
> +        block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
> +    } else {
> +        block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
> +    }
> +
> +    if (block_job_is_cancelled(&job->common)) {
> +        return true;
> +    }
> +
> +    return false;
> +}
> +
>  static void coroutine_fn backup_run(void *opaque)
>  {
>      BackupBlockJob *job = opaque;
> @@ -254,13 +281,13 @@ static void coroutine_fn backup_run(void *opaque)
>      };
>      int64_t start, end;
>      int ret = 0;
> +    bool error_is_read;
>  
>      QLIST_INIT(&job->inflight_reqs);
>      qemu_co_rwlock_init(&job->flush_rwlock);
>  
>      start = 0;
> -    end = DIV_ROUND_UP(job->common.len / BDRV_SECTOR_SIZE,
> -                       BACKUP_SECTORS_PER_CLUSTER);
> +    end = DIV_ROUND_UP(job->common.len, BACKUP_CLUSTER_SIZE);
>  
>      job->bitmap = hbitmap_alloc(end, 0);
>  
> @@ -278,28 +305,45 @@ static void coroutine_fn backup_run(void *opaque)
>              qemu_coroutine_yield();
>              job->common.busy = true;
>          }
> +    } else if (job->sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
> +        /* Dirty Bitmap sync has a slightly different iteration method */
> +        HBitmapIter hbi;
> +        int64_t sector;
> +        int64_t cluster;
> +        bool polyrhythmic;
> +
> +        bdrv_dirty_iter_init(bs, job->sync_bitmap, &hbi);
> +        /* Does the granularity happen to match our backup cluster size? */
> +        polyrhythmic = (bdrv_dirty_bitmap_granularity(bs, job->sync_bitmap) !=
> +                        BACKUP_CLUSTER_SIZE);
> +
> +        /* Find the next dirty /sector/ and copy that /cluster/ */
> +        while ((sector = hbitmap_iter_next(&hbi)) != -1) {
> +            if (yield_and_check(job)) {
> +                goto leave;
> +            }
> +            cluster = sector / BACKUP_SECTORS_PER_CLUSTER;
> +
> +            do {
> +                ret = backup_do_cow(bs, cluster * BACKUP_SECTORS_PER_CLUSTER,
> +                                    BACKUP_SECTORS_PER_CLUSTER, &error_is_read);
> +                if ((ret < 0) &&
> +                    backup_error_action(job, error_is_read, -ret) ==
> +                    BLOCK_ERROR_ACTION_REPORT) {
> +                    goto leave;
> +                }
> +            } while (ret < 0);
> +
> +            /* Advance (or rewind) our iterator if we need to. */
> +            if (polyrhythmic) {
> +                bdrv_set_dirty_iter(&hbi,
> +                                    (cluster + 1) * BACKUP_SECTORS_PER_CLUSTER);
> +            }
> +        }
>      } else {
>          /* Both FULL and TOP SYNC_MODE's require copying.. */
>          for (; start < end; start++) {
> -            bool error_is_read;
> -
> -            if (block_job_is_cancelled(&job->common)) {
> -                break;
> -            }
> -
> -            /* we need to yield so that qemu_aio_flush() returns.
> -             * (without, VM does not reboot)
> -             */
> -            if (job->common.speed) {
> -                uint64_t delay_ns = ratelimit_calculate_delay(
> -                        &job->limit, job->sectors_read);
> -                job->sectors_read = 0;
> -                block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
> -            } else {
> -                block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
> -            }
> -
> -            if (block_job_is_cancelled(&job->common)) {
> +            if (yield_and_check(job)) {
>                  break;
>              }
>  
> @@ -351,12 +395,23 @@ static void coroutine_fn backup_run(void *opaque)
>          }
>      }
>  
> +leave:
>      notifier_with_return_remove(&before_write);
>  
>      /* wait until pending backup_do_cow() calls have completed */
>      qemu_co_rwlock_wrlock(&job->flush_rwlock);
>      qemu_co_rwlock_unlock(&job->flush_rwlock);
>  
> +    if (job->sync_bitmap) {
> +        if (ret < 0) {
> +            /* Merge the successor back into the parent, delete nothing. */
> +            assert(bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL));

Why can't reclaim fail here? If we canassert, please move the expression out
because it has a side effect.

> +            bdrv_enable_dirty_bitmap(job->sync_bitmap);
> +        } else {
> +            /* Everything is fine, delete this bitmap and install the backup. */
> +            assert(bdrv_dirty_bitmap_abdicate(bs, job->sync_bitmap, NULL));
> +        }
> +    }
>      hbitmap_free(job->bitmap);
>  
>      bdrv_iostatus_disable(target);
> @@ -368,6 +423,7 @@ static void coroutine_fn backup_run(void *opaque)
>  
>  void backup_start(BlockDriverState *bs, BlockDriverState *target,
>                    int64_t speed, MirrorSyncMode sync_mode,
> +                  BdrvDirtyBitmap *sync_bitmap,
>                    BlockdevOnError on_source_error,
>                    BlockdevOnError on_target_error,
>                    BlockCompletionFunc *cb, void *opaque,
> @@ -386,6 +442,26 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
>          return;
>      }
>  
> +    if (sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
> +        if (!sync_bitmap) {
> +            error_setg(errp, "must provide a valid bitmap name for "
> +                             "\"dirty-bitmap\" sync mode");
> +            return;
> +        }
> +
> +        /* Create a new bitmap, and freeze/disable this one. */
> +        if (bdrv_dirty_bitmap_create_successor(bs, sync_bitmap, errp) < 0) {
> +            return;
> +        }

There are two error paths in this function after this creation, need to release
it there?

> +
> +    } else if (sync_bitmap) {
> +        error_setg(errp,
> +                   "a sync_bitmap was provided to backup_run, "
> +                   "but received an incompatible sync_mode (%s)",
> +                   MirrorSyncMode_lookup[sync_mode]);
> +        return;
> +    }
> +
>      len = bdrv_getlength(bs);
>      if (len < 0) {
>          error_setg_errno(errp, -len, "unable to get length for '%s'",
> @@ -403,6 +479,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
>      job->on_target_error = on_target_error;
>      job->target = target;
>      job->sync_mode = sync_mode;
> +    job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP ?
> +                       sync_bitmap : NULL;
>      job->common.len = len;
>      job->common.co = qemu_coroutine_create(backup_run);
>      qemu_coroutine_enter(job->common.co, job);
> diff --git a/block/mirror.c b/block/mirror.c
> index fc545f1..427c688 100644
> --- a/block/mirror.c
> +++ b/block/mirror.c
> @@ -717,6 +717,10 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
>      bool is_none_mode;
>      BlockDriverState *base;
>  
> +    if (mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
> +        error_setg(errp, "Sync mode 'dirty-bitmap' not supported");
> +        return;
> +    }
>      is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
>      base = mode == MIRROR_SYNC_MODE_TOP ? bs->backing_hd : NULL;
>      mirror_start_job(bs, target, replaces,
> diff --git a/blockdev.c b/blockdev.c
> index 8dde72a..114a94c 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1569,6 +1569,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
>                       backup->sync,
>                       backup->has_mode, backup->mode,
>                       backup->has_speed, backup->speed,
> +                     backup->has_bitmap, backup->bitmap,
>                       backup->has_on_source_error, backup->on_source_error,
>                       backup->has_on_target_error, backup->on_target_error,
>                       &local_err);
> @@ -2358,6 +2359,7 @@ void qmp_drive_backup(const char *device, const char *target,
>                        enum MirrorSyncMode sync,
>                        bool has_mode, enum NewImageMode mode,
>                        bool has_speed, int64_t speed,
> +                      bool has_bitmap, const char *bitmap,
>                        bool has_on_source_error, BlockdevOnError on_source_error,
>                        bool has_on_target_error, BlockdevOnError on_target_error,
>                        Error **errp)
> @@ -2365,6 +2367,7 @@ void qmp_drive_backup(const char *device, const char *target,
>      BlockDriverState *bs;
>      BlockDriverState *target_bs;
>      BlockDriverState *source = NULL;
> +    BdrvDirtyBitmap *bmap = NULL;
>      AioContext *aio_context;
>      BlockDriver *drv = NULL;
>      Error *local_err = NULL;
> @@ -2460,7 +2463,16 @@ void qmp_drive_backup(const char *device, const char *target,
>  
>      bdrv_set_aio_context(target_bs, aio_context);
>  
> -    backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
> +    if (has_bitmap) {
> +        bmap = bdrv_find_dirty_bitmap(bs, bitmap);
> +        if (!bmap) {
> +            error_setg(errp, "Bitmap '%s' could not be found", bitmap);
> +            goto out;
> +        }
> +    }
> +
> +    backup_start(bs, target_bs, speed, sync, bmap,
> +                 on_source_error, on_target_error,
>                   block_job_cb, bs, &local_err);
>      if (local_err != NULL) {
>          bdrv_unref(target_bs);
> diff --git a/hmp.c b/hmp.c
> index 481be80..63b19c7 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -1021,7 +1021,8 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
>  
>      qmp_drive_backup(device, filename, !!format, format,
>                       full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
> -                     true, mode, false, 0, false, 0, false, 0, &err);
> +                     true, mode, false, 0, false, NULL,
> +                     false, 0, false, 0, &err);
>      hmp_handle_error(mon, &err);
>  }
>  
> diff --git a/include/block/block.h b/include/block/block.h
> index 6138544..99ed679 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -462,6 +462,7 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>  void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>  void bdrv_dirty_iter_init(BlockDriverState *bs,
>                            BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
> +void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
>  int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>  
>  void bdrv_enable_copy_on_read(BlockDriverState *bs);
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 06a21dd..cb1e4a1 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -584,6 +584,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
>   * @target: Block device to write to.
>   * @speed: The maximum speed, in bytes per second, or 0 for unlimited.
>   * @sync_mode: What parts of the disk image should be copied to the destination.
> + * @sync_bitmap: The dirty bitmap if sync_mode is MIRROR_SYNC_MODE_DIRTY_BITMAP.
>   * @on_source_error: The action to take upon error reading from the source.
>   * @on_target_error: The action to take upon error writing to the target.
>   * @cb: Completion function for the job.
> @@ -594,6 +595,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
>   */
>  void backup_start(BlockDriverState *bs, BlockDriverState *target,
>                    int64_t speed, MirrorSyncMode sync_mode,
> +                  BdrvDirtyBitmap *sync_bitmap,
>                    BlockdevOnError on_source_error,
>                    BlockdevOnError on_target_error,
>                    BlockCompletionFunc *cb, void *opaque,
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 3e863b9..92c3a84 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -500,7 +500,7 @@
>  # Since: 1.3
>  ##
>  { 'enum': 'MirrorSyncMode',
> -  'data': ['top', 'full', 'none'] }
> +  'data': ['top', 'full', 'none', 'dirty-bitmap'] }

Maybe document version info for 'dirty-bitmap'? Eric?

Fam

<snip>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 01/13] block: fix spoiling all dirty bitmaps by mirror and migration
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 01/13] block: fix spoiling all dirty bitmaps by mirror and migration John Snow
@ 2015-01-13 15:54   ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 54+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-01-13 15:54 UTC (permalink / raw)
  To: John Snow, qemu-devel
  Cc: kwolf, famz, armbru, mreitz, stefanha, Denis V. Lunev

it is already in master and can be dropped here

Best regards,
Vladimir

On 12.01.2015 19:30, John Snow wrote:
> From: Vladimir Sementsov-Ogievskiy <vsementsov@parallels.com>
>
> Mirror and migration use dirty bitmaps for their purposes, and since
> commit [block: per caller dirty bitmap] they use their own bitmaps, not
> the global one. But they use old functions bdrv_set_dirty and
> bdrv_reset_dirty, which change all dirty bitmaps.
>
> Named dirty bitmaps series by Fam and Snow are affected: mirroring and
> migration will spoil all (not related to this mirroring or migration)
> named dirty bitmaps.
>
> This patch fixes this by adding bdrv_set_dirty_bitmap and
> bdrv_reset_dirty_bitmap, which change concrete bitmap. Also, to prevent
> such mistakes in future, old functions bdrv_(set,reset)_dirty are made
> static, for internal block usage.
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@parallels.com>
> CC: John Snow <jsnow@redhat.com>
> CC: Fam Zheng <famz@redhat.com>
> CC: Denis V. Lunev <den@openvz.org>
> CC: Stefan Hajnoczi <stefanha@redhat.com>
> CC: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   block.c               | 23 ++++++++++++++++++++---
>   block/mirror.c        | 11 +++++++----
>   include/block/block.h |  6 ++++--
>   migration/block.c     |  5 +++--
>   4 files changed, 34 insertions(+), 11 deletions(-)
>
> diff --git a/block.c b/block.c
> index 4165d42..6c1b49a 100644
> --- a/block.c
> +++ b/block.c
> @@ -97,6 +97,10 @@ static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
>   static QLIST_HEAD(, BlockDriver) bdrv_drivers =
>       QLIST_HEAD_INITIALIZER(bdrv_drivers);
>   
> +static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
> +                           int nr_sectors);
> +static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
> +                             int nr_sectors);
>   /* If non-zero, use only whitelisted block drivers */
>   static int use_bdrv_whitelist;
>   
> @@ -5389,8 +5393,20 @@ void bdrv_dirty_iter_init(BlockDriverState *bs,
>       hbitmap_iter_init(hbi, bitmap->bitmap, 0);
>   }
>   
> -void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
> -                    int nr_sectors)
> +void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
> +                           int64_t cur_sector, int nr_sectors)
> +{
> +    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
> +}
> +
> +void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
> +                             int64_t cur_sector, int nr_sectors)
> +{
> +    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
> +}
> +
> +static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
> +                           int nr_sectors)
>   {
>       BdrvDirtyBitmap *bitmap;
>       QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> @@ -5398,7 +5414,8 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
>       }
>   }
>   
> -void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors)
> +static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
> +                             int nr_sectors)
>   {
>       BdrvDirtyBitmap *bitmap;
>       QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> diff --git a/block/mirror.c b/block/mirror.c
> index 2c6dd2a..9019d1b 100644
> --- a/block/mirror.c
> +++ b/block/mirror.c
> @@ -128,7 +128,8 @@ static void mirror_write_complete(void *opaque, int ret)
>           BlockDriverState *source = s->common.bs;
>           BlockErrorAction action;
>   
> -        bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
> +        bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
> +                              op->nb_sectors);
>           action = mirror_error_action(s, false, -ret);
>           if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
>               s->ret = ret;
> @@ -145,7 +146,8 @@ static void mirror_read_complete(void *opaque, int ret)
>           BlockDriverState *source = s->common.bs;
>           BlockErrorAction action;
>   
> -        bdrv_set_dirty(source, op->sector_num, op->nb_sectors);
> +        bdrv_set_dirty_bitmap(source, s->dirty_bitmap, op->sector_num,
> +                              op->nb_sectors);
>           action = mirror_error_action(s, true, -ret);
>           if (action == BLOCK_ERROR_ACTION_REPORT && s->ret >= 0) {
>               s->ret = ret;
> @@ -286,7 +288,8 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
>           next_sector += sectors_per_chunk;
>       }
>   
> -    bdrv_reset_dirty(source, sector_num, nb_sectors);
> +    bdrv_reset_dirty_bitmap(source, s->dirty_bitmap, sector_num,
> +                            nb_sectors);
>   
>       /* Copy the dirty cluster.  */
>       s->in_flight++;
> @@ -442,7 +445,7 @@ static void coroutine_fn mirror_run(void *opaque)
>   
>               assert(n > 0);
>               if (ret == 1) {
> -                bdrv_set_dirty(bs, sector_num, n);
> +                bdrv_set_dirty_bitmap(bs, s->dirty_bitmap, sector_num, n);
>                   sector_num = next;
>               } else {
>                   sector_num += n;
> diff --git a/include/block/block.h b/include/block/block.h
> index 6e7275d..a77ed30 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -434,8 +434,10 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
>   void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>   BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
>   int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
> -void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
> -void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
> +void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
> +                           int64_t cur_sector, int nr_sectors);
> +void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
> +                             int64_t cur_sector, int nr_sectors);
>   void bdrv_dirty_iter_init(BlockDriverState *bs,
>                             BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
>   int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
> diff --git a/migration/block.c b/migration/block.c
> index 74d9eb1..a0f908c 100644
> --- a/migration/block.c
> +++ b/migration/block.c
> @@ -303,7 +303,7 @@ static int mig_save_device_bulk(QEMUFile *f, BlkMigDevState *bmds)
>       blk->aiocb = bdrv_aio_readv(bs, cur_sector, &blk->qiov,
>                                   nr_sectors, blk_mig_read_cb, blk);
>   
> -    bdrv_reset_dirty(bs, cur_sector, nr_sectors);
> +    bdrv_reset_dirty_bitmap(bs, bmds->dirty_bitmap, cur_sector, nr_sectors);
>       qemu_mutex_unlock_iothread();
>   
>       bmds->cur_sector = cur_sector + nr_sectors;
> @@ -496,7 +496,8 @@ static int mig_save_device_dirty(QEMUFile *f, BlkMigDevState *bmds,
>                   g_free(blk);
>               }
>   
> -            bdrv_reset_dirty(bmds->bs, sector, nr_sectors);
> +            bdrv_reset_dirty_bitmap(bmds->bs, bmds->dirty_bitmap, sector,
> +                                    nr_sectors);
>               break;
>           }
>           sector += BDRV_SECTORS_PER_DIRTY_CHUNK;

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 13/13] block: BdrvDirtyBitmap miscellaneous fixup
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 13/13] block: BdrvDirtyBitmap miscellaneous fixup John Snow
@ 2015-01-13 16:50   ` Vladimir Sementsov-Ogievskiy
  2015-01-13 18:27     ` John Snow
  0 siblings, 1 reply; 54+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-01-13 16:50 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, mreitz, stefanha

Hmm. May be, update the size field to be uint64_t too? Negative size is 
not meaningful..

Best regards,
Vladimir

On 12.01.2015 19:31, John Snow wrote:
> (1) granularity type consistency: Update the granularity to be uint64_t
>      in all places. This value is always in bytes.
>
> (2) Some documentation for the fields within BdrvDirtyBitmap.
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   block.c               | 16 ++++++++--------
>   include/block/block.h |  2 +-
>   2 files changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/block.c b/block.c
> index 9e2b8c0..13f9cc0 100644
> --- a/block.c
> +++ b/block.c
> @@ -52,13 +52,13 @@
>   #endif
>   
>   struct BdrvDirtyBitmap {
> -    HBitmap *bitmap;
> -    BdrvDirtyBitmap *successor;
> -    int64_t size;
> -    int64_t granularity;
> -    char *name;
> -    bool enabled;
> -    bool frozen;
> +    HBitmap *bitmap;            /* Dirty sector bitmap */
> +    BdrvDirtyBitmap *successor; /* Anonymous child */
> +    int64_t size;               /* Number of sectors */
> +    uint64_t granularity;       /* Granularity in bytes */
> +    char *name;                 /* Optional non-empty unique ID */
> +    bool enabled;               /* Writes are being tracked */
> +    bool frozen;                /* Protected; see bdrv_freeze_dirty_bitmap() */
>       QLIST_ENTRY(BdrvDirtyBitmap) list;
>   };
>   
> @@ -5350,7 +5350,7 @@ void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>   }
>   
>   BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
> -                                          int granularity,
> +                                          uint64_t granularity,
>                                             const char *name,
>                                             Error **errp)
>   {
> diff --git a/include/block/block.h b/include/block/block.h
> index 99ed679..749429e 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -430,7 +430,7 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
>   struct HBitmapIter;
>   typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
>   BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
> -                                          int granularity,
> +                                          uint64_t granularity,
>                                             const char *name,
>                                             Error **errp);
>   int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors
  2015-01-13  9:24   ` Fam Zheng
@ 2015-01-13 17:26     ` John Snow
  2015-01-16 18:22     ` John Snow
  1 sibling, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-13 17:26 UTC (permalink / raw)
  To: Fam Zheng
  Cc: kwolf, qemu-devel, armbru, mreitz, vsementsov, stefanha, pbonzini



On 01/13/2015 04:24 AM, Fam Zheng wrote:
> On Mon, 01/12 11:31, John Snow wrote:
>> A bitmap successor is an anonymous BdrvDirtyBitmap that is intended to
>> be created just prior to a sensitive operation (e.g. Incremental Backup)
>> that can either succeed or fail, but during the course of which we still
>> want a bitmap tracking writes.
>>
>> On creating a successor, we "freeze" the parent bitmap which prevents
>> its deletion, enabling, anonymization, or creating a bitmap with the
>> same name.
>>
>> On success, the parent bitmap can "abdicate" responsibility to the
>> successor, which will inherit its name. The successor will have been
>> tracking writes during the course of the backup operation. The parent
>> will be safely deleted.
>>
>> On failure, we can "reclaim" the successor from the parent, unifying
>> them such that the resulting bitmap describes all writes occurring since
>> the last successful backup, for instance. Reclamation will thaw the
>> parent, but not explicitly re-enable it.
>
> If we compare this with image snapshot and overlay, it fits the current backing
> chain model very well.  Given that we're on the way to persistent dirty bitmap,
> which will probably be read/written with general block.c code, I'm wondering if
> it will be any better to reuse the block layer backing file code to handle
> "successor" logic?
>
> Also with the frozen feature built in dirty bitmaps, is it okay to drop
> "enabled" state?
>
> I think there are three states for a bitmap:
>
> 1) Active, no successor (similar to an read-write top image)
> 2) Frozen, no successor (similar to an read-only top image)
> 3) Frozen, with successor (similar to an read-only backing file, with an
>     overlap)
>
> Admittedly, more code is needed than this patch, in order to glue hbitmap and
> block layer together, but it would probably make live migration of dirty bitmap
> very easy, but I'm not sure without a closer look.
>

Hmm -- I suppose so. I was just treating "frozen" as a stricter "disabled."

Disabled just stops tracking writes, but frozen was intended to stop 
deletion, renaming, etc. If there is no use case for the softer 
"disabled," then it can really be just a single parameter.

>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   block.c               | 123 ++++++++++++++++++++++++++++++++++++++++++++++++--
>>   blockdev.c            |  14 ++++++
>>   include/block/block.h |  10 ++++
>>   3 files changed, 144 insertions(+), 3 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index bd4b449..3f33b9d 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -53,10 +53,12 @@
>>
>>   struct BdrvDirtyBitmap {
>>       HBitmap *bitmap;
>> +    BdrvDirtyBitmap *successor;
>>       int64_t size;
>>       int64_t granularity;
>>       char *name;
>>       bool enabled;
>> +    bool frozen;
>>       QLIST_ENTRY(BdrvDirtyBitmap) list;
>>   };
>>
>> @@ -5342,6 +5344,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
>>
>>   void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>>   {
>> +    assert(!bitmap->frozen);
>>       g_free(bitmap->name);
>>       bitmap->name = NULL;
>>   }
>> @@ -5379,9 +5382,114 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>>       return bitmap;
>>   }
>>
>> +/**
>> +  * A frozen bitmap cannot be renamed, deleted, cleared,
>> +  * or set. A frozen bitmap can only abdicate, reclaim,
>> +  * or thaw.
>> +  */
>> +static void bdrv_freeze_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>> +{
>> +    bitmap->frozen = true;
>> +}
>> +
>> +static void bdrv_thaw_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>> +{
>> +    bitmap->frozen = false;
>> +}
>> +
>> +bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
>> +{
>> +    return bitmap->frozen;
>> +}
>> +
>>   bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
>>   {
>> -    return bitmap->enabled;
>> +    return bitmap->enabled && !bitmap->frozen;
>
> An indication that "enabled" could be replaced by "frozen". Otherwise it looks
> confusing to me.
>

Perhaps. Here I mean to say that "Frozen implies disabled." The stronger 
condition implies the weaker.

>> +}
>> +
>> +/**
>> + * Create a successor bitmap destined to replace this bitmap after an operation.
>> + * Requires that the bitmap is not frozen and has no successor.
>> + */
>> +int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>> +                                       BdrvDirtyBitmap *bitmap, Error **errp)
>> +{
>> +    uint64_t granularity;
>> +
>> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
>> +        error_setg(errp,
>> +                   "Cannot create a successor for a bitmap currently in-use.");
>> +        return -1;
>> +    } else if (bitmap->successor) {
>> +        error_setg(errp, "Cannot create a successor for a bitmap that "
>> +                   "already has one.");
>> +        return -1;
>> +    }
>> +
>> +    /* Create an anonymous successor */
>> +    granularity = bdrv_dirty_bitmap_granularity(bs, bitmap);
>> +    bitmap->successor = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
>> +    if (!bitmap->successor) {
>> +        return -1;
>> +    }
>> +
>> +    /* Successor will be on or off based on our current state.
>> +     * Parent will be disabled and frozen. */
>> +    bitmap->successor->enabled = bitmap->enabled;
>> +    bdrv_disable_dirty_bitmap(bitmap);
>> +    bdrv_freeze_dirty_bitmap(bitmap);
>> +    return 0;
>> +}
>> +
>> +/**
>> + * For a bitmap with a successor, yield our name to the successor,
>> + * Delete the old bitmap, and return a handle to the new bitmap.
>> + */
>> +BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
>> +                                            BdrvDirtyBitmap *bitmap,
>> +                                            Error **errp)
>> +{
>> +    char *name;
>> +    BdrvDirtyBitmap *successor = bitmap->successor;
>> +
>> +    if (successor == NULL) {
>> +        error_setg(errp, "Cannot relinquish control if "
>> +                   "there's no successor present.\n");
>> +        return NULL;
>> +    }
>> +
>> +    name = bitmap->name;
>> +    bitmap->name = NULL;
>> +    successor->name = name;
>> +
>> +    bdrv_thaw_dirty_bitmap(bitmap);
>> +    bdrv_release_dirty_bitmap(bs, bitmap);
>> +
>> +    return successor;
>> +}
>> +
>> +/**
>> + * In cases of failure where we can no longer safely delete the parent,
>> + * We may wish to re-join the parent and child/successor.
>> + * The merged parent will be un-frozen, but not explicitly re-enabled.
>> + */
>> +BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
>> +                                           BdrvDirtyBitmap *parent,
>> +                                           Error **errp)
>> +{
>> +    BdrvDirtyBitmap *successor = parent->successor;
>> +    if (!successor) {
>> +        error_setg(errp, "Cannot reclaim a successor when none is present.\n");
>> +        return NULL;
>> +    }
>> +
>> +    hbitmap_merge(parent->bitmap, successor->bitmap);
>> +    bdrv_release_dirty_bitmap(bs, successor);
>> +
>> +    bdrv_thaw_dirty_bitmap(parent);
>> +    parent->successor = NULL;
>> +
>> +    return parent;
>>   }
>>
>>   void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>> @@ -5389,6 +5497,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>>       BdrvDirtyBitmap *bm, *next;
>>       QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
>>           if (bm == bitmap) {
>> +            assert(!bm->frozen);
>>               QLIST_REMOVE(bitmap, list);
>>               hbitmap_free(bitmap->bitmap);
>>               g_free(bitmap->name);
>> @@ -5405,6 +5514,7 @@ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>>
>>   void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>>   {
>> +    assert(!bitmap->frozen);
>>       bitmap->enabled = true;
>>   }
>>
>> @@ -5483,7 +5593,9 @@ void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>   void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>                                int64_t cur_sector, int nr_sectors)
>>   {
>> -    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
>> +    if (!bitmap->frozen) {
>
> Probably just assert it's not frozen?
>

If the only callers are other BdrvDirtyBitmap related functions, then 
OK. I want to avoid assertions by functions invoked by other layers, 
because a user could freeze/disable a bitmap at any time.

>> +        hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
>> +    }
>>   }
>>
>>   /**
>> @@ -5492,7 +5604,9 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>    */
>>   void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>>   {
>> -    hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
>> +    if (!bitmap->frozen) {
>> +        hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
>
> The same: probably just assert it's not frozen?
>

As above, OK.

>> +    }
>>   }
>>
>>   static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
>> @@ -5512,6 +5626,9 @@ static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
>>   {
>>       BdrvDirtyBitmap *bitmap;
>>       QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
>> +        if (bitmap->frozen) {
>> +            continue;
>> +        }
>>           hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
>>       }
>>   }
>> diff --git a/blockdev.c b/blockdev.c
>> index 118cb6c..8dde72a 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -1988,9 +1988,16 @@ void qmp_block_dirty_bitmap_remove(const char *node_ref, const char *name,
>>       aio_context = bdrv_get_aio_context(bs);
>>       aio_context_acquire(aio_context);
>>
>> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
>> +        error_setg(errp,
>> +                   "Bitmap %s is currently frozen and cannot be removed yet.\n",
>> +                   name);
>> +        goto out;
>> +    }
>>       bdrv_dirty_bitmap_make_anon(bs, bitmap);
>>       bdrv_release_dirty_bitmap(bs, bitmap);
>>
>> + out:
>>       aio_context_release(aio_context);
>>   }
>>
>> @@ -2009,8 +2016,15 @@ void qmp_block_dirty_bitmap_enable(const char *node_ref, const char *name,
>>       aio_context = bdrv_get_aio_context(bs);
>>       aio_context_acquire(aio_context);
>>
>> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
>> +        error_setg(errp, "Bitmap %s is frozen and cannot be enabled yet.\n",
>> +                   name);
>> +        goto out;
>> +    }
>> +
>>       bdrv_enable_dirty_bitmap(bitmap);
>>
>> + out:
>>       aio_context_release(aio_context);
>>   }
>>
>> diff --git a/include/block/block.h b/include/block/block.h
>> index a5bc249..6138544 100644
>> --- a/include/block/block.h
>> +++ b/include/block/block.h
>> @@ -433,6 +433,15 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>>                                             int granularity,
>>                                             const char *name,
>>                                             Error **errp);
>> +int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>> +                                       BdrvDirtyBitmap *bitmap,
>> +                                       Error **errp);
>> +BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
>> +                                            BdrvDirtyBitmap *bitmap,
>> +                                            Error **errp);
>> +BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
>> +                                           BdrvDirtyBitmap *bitmap,
>> +                                           Error **errp);
>>   BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
>>                                           const char *name);
>>   void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>> @@ -444,6 +453,7 @@ uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
>>   uint64_t bdrv_dirty_bitmap_granularity(BlockDriverState *bs,
>>                                         BdrvDirtyBitmap *bitmap);
>>   bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
>> +bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
>>   int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
>>   void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>                              int64_t cur_sector, int nr_sectors);
>> --
>> 1.9.3
>>
>

Thanks!
--John

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup
  2015-01-13  9:37   ` Fam Zheng
@ 2015-01-13 17:50     ` John Snow
  2015-01-14  6:29       ` Fam Zheng
  0 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-13 17:50 UTC (permalink / raw)
  To: Fam Zheng; +Cc: kwolf, qemu-devel, armbru, mreitz, vsementsov, stefanha



On 01/13/2015 04:37 AM, Fam Zheng wrote:
> On Mon, 01/12 11:31, John Snow wrote:
>> For "dirty-bitmap" sync mode, the block job will iterate through the
>> given dirty bitmap to decide if a sector needs backup (backup all the
>> dirty clusters and skip clean ones), just as allocation conditions of
>> "top" sync mode.
>>
>> Signed-off-by: Fam Zheng <famz@redhat.com>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   block.c                   |   5 ++
>>   block/backup.c            | 120 ++++++++++++++++++++++++++++++++++++++--------
>>   block/mirror.c            |   4 ++
>>   blockdev.c                |  14 +++++-
>>   hmp.c                     |   3 +-
>>   include/block/block.h     |   1 +
>>   include/block/block_int.h |   2 +
>>   qapi/block-core.json      |  11 +++--
>>   qmp-commands.hx           |   7 +--
>>   9 files changed, 137 insertions(+), 30 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index 3f33b9d..5eb6788 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -5633,6 +5633,11 @@ static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
>>       }
>>   }
>>
>> +void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
>> +{
>> +    hbitmap_iter_init(hbi, hbi->hb, offset);
>
> What's the reason for this indirection? Can caller just use hbitmap_iter_init?
>

Essentially it is just a rename of hbitmap_iter_init to make its usage 
here clear, that we are manually advancing the pointer. How we 
accomplish that (hbitmap_iter_init) is an implementation detail.

Yes, I can just call this directly from block/backup, but at the time I 
was less sure of how I would advance the pointer, so I created a wrapper 
where I could change details as needed, if I needed to.

>> +}
>> +
>>   int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>>   {
>>       return hbitmap_count(bitmap->bitmap);
>> diff --git a/block/backup.c b/block/backup.c
>> index 792e655..0626a3e 100644
>> --- a/block/backup.c
>> +++ b/block/backup.c
>> @@ -37,6 +37,8 @@ typedef struct CowRequest {
>>   typedef struct BackupBlockJob {
>>       BlockJob common;
>>       BlockDriverState *target;
>> +    /* bitmap for sync=dirty-bitmap */
>> +    BdrvDirtyBitmap *sync_bitmap;
>>       MirrorSyncMode sync_mode;
>>       RateLimit limit;
>>       BlockdevOnError on_source_error;
>> @@ -242,6 +244,31 @@ static void backup_complete(BlockJob *job, void *opaque)
>>       g_free(data);
>>   }
>>
>> +static bool coroutine_fn yield_and_check(BackupBlockJob *job)
>> +{
>> +    if (block_job_is_cancelled(&job->common)) {
>> +        return true;
>> +    }
>> +
>> +    /* we need to yield so that qemu_aio_flush() returns.
>> +     * (without, VM does not reboot)
>> +     */
>> +    if (job->common.speed) {
>> +        uint64_t delay_ns = ratelimit_calculate_delay(&job->limit,
>> +                                                      job->sectors_read);
>> +        job->sectors_read = 0;
>> +        block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
>> +    } else {
>> +        block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
>> +    }
>> +
>> +    if (block_job_is_cancelled(&job->common)) {
>> +        return true;
>> +    }
>> +
>> +    return false;
>> +}
>> +
>>   static void coroutine_fn backup_run(void *opaque)
>>   {
>>       BackupBlockJob *job = opaque;
>> @@ -254,13 +281,13 @@ static void coroutine_fn backup_run(void *opaque)
>>       };
>>       int64_t start, end;
>>       int ret = 0;
>> +    bool error_is_read;
>>
>>       QLIST_INIT(&job->inflight_reqs);
>>       qemu_co_rwlock_init(&job->flush_rwlock);
>>
>>       start = 0;
>> -    end = DIV_ROUND_UP(job->common.len / BDRV_SECTOR_SIZE,
>> -                       BACKUP_SECTORS_PER_CLUSTER);
>> +    end = DIV_ROUND_UP(job->common.len, BACKUP_CLUSTER_SIZE);
>>
>>       job->bitmap = hbitmap_alloc(end, 0);
>>
>> @@ -278,28 +305,45 @@ static void coroutine_fn backup_run(void *opaque)
>>               qemu_coroutine_yield();
>>               job->common.busy = true;
>>           }
>> +    } else if (job->sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
>> +        /* Dirty Bitmap sync has a slightly different iteration method */
>> +        HBitmapIter hbi;
>> +        int64_t sector;
>> +        int64_t cluster;
>> +        bool polyrhythmic;
>> +
>> +        bdrv_dirty_iter_init(bs, job->sync_bitmap, &hbi);
>> +        /* Does the granularity happen to match our backup cluster size? */
>> +        polyrhythmic = (bdrv_dirty_bitmap_granularity(bs, job->sync_bitmap) !=
>> +                        BACKUP_CLUSTER_SIZE);
>> +
>> +        /* Find the next dirty /sector/ and copy that /cluster/ */
>> +        while ((sector = hbitmap_iter_next(&hbi)) != -1) {
>> +            if (yield_and_check(job)) {
>> +                goto leave;
>> +            }
>> +            cluster = sector / BACKUP_SECTORS_PER_CLUSTER;
>> +
>> +            do {
>> +                ret = backup_do_cow(bs, cluster * BACKUP_SECTORS_PER_CLUSTER,
>> +                                    BACKUP_SECTORS_PER_CLUSTER, &error_is_read);
>> +                if ((ret < 0) &&
>> +                    backup_error_action(job, error_is_read, -ret) ==
>> +                    BLOCK_ERROR_ACTION_REPORT) {
>> +                    goto leave;
>> +                }
>> +            } while (ret < 0);
>> +
>> +            /* Advance (or rewind) our iterator if we need to. */
>> +            if (polyrhythmic) {
>> +                bdrv_set_dirty_iter(&hbi,
>> +                                    (cluster + 1) * BACKUP_SECTORS_PER_CLUSTER);
>> +            }
>> +        }
>>       } else {
>>           /* Both FULL and TOP SYNC_MODE's require copying.. */
>>           for (; start < end; start++) {
>> -            bool error_is_read;
>> -
>> -            if (block_job_is_cancelled(&job->common)) {
>> -                break;
>> -            }
>> -
>> -            /* we need to yield so that qemu_aio_flush() returns.
>> -             * (without, VM does not reboot)
>> -             */
>> -            if (job->common.speed) {
>> -                uint64_t delay_ns = ratelimit_calculate_delay(
>> -                        &job->limit, job->sectors_read);
>> -                job->sectors_read = 0;
>> -                block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
>> -            } else {
>> -                block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
>> -            }
>> -
>> -            if (block_job_is_cancelled(&job->common)) {
>> +            if (yield_and_check(job)) {
>>                   break;
>>               }
>>
>> @@ -351,12 +395,23 @@ static void coroutine_fn backup_run(void *opaque)
>>           }
>>       }
>>
>> +leave:
>>       notifier_with_return_remove(&before_write);
>>
>>       /* wait until pending backup_do_cow() calls have completed */
>>       qemu_co_rwlock_wrlock(&job->flush_rwlock);
>>       qemu_co_rwlock_unlock(&job->flush_rwlock);
>>
>> +    if (job->sync_bitmap) {
>> +        if (ret < 0) {
>> +            /* Merge the successor back into the parent, delete nothing. */
>> +            assert(bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL));
>
> Why can't reclaim fail here? If we canassert, please move the expression out
> because it has a side effect.
>

It shouldn't fail; if it does, something went very wrong. The only 
chance this has to fail is if the sync bitmap has no successor, but we 
explicitly installed one (and explicitly check that it succeeded) before 
going into the block backup.

I am not sure what other meaningful recovery could happen in this case, 
though we *could* just report an error and continue on, acknowledging 
that the BdrvDirtyBitmap is now compromised and of questionable validity.

Does anyone have an error handling preference here?

>> +            bdrv_enable_dirty_bitmap(job->sync_bitmap);
>> +        } else {
>> +            /* Everything is fine, delete this bitmap and install the backup. */
>> +            assert(bdrv_dirty_bitmap_abdicate(bs, job->sync_bitmap, NULL));
>> +        }
>> +    }
>>       hbitmap_free(job->bitmap);
>>
>>       bdrv_iostatus_disable(target);
>> @@ -368,6 +423,7 @@ static void coroutine_fn backup_run(void *opaque)
>>
>>   void backup_start(BlockDriverState *bs, BlockDriverState *target,
>>                     int64_t speed, MirrorSyncMode sync_mode,
>> +                  BdrvDirtyBitmap *sync_bitmap,
>>                     BlockdevOnError on_source_error,
>>                     BlockdevOnError on_target_error,
>>                     BlockCompletionFunc *cb, void *opaque,
>> @@ -386,6 +442,26 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
>>           return;
>>       }
>>
>> +    if (sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
>> +        if (!sync_bitmap) {
>> +            error_setg(errp, "must provide a valid bitmap name for "
>> +                             "\"dirty-bitmap\" sync mode");
>> +            return;
>> +        }
>> +
>> +        /* Create a new bitmap, and freeze/disable this one. */
>> +        if (bdrv_dirty_bitmap_create_successor(bs, sync_bitmap, errp) < 0) {
>> +            return;
>> +        }
>
> There are two error paths in this function after this creation, need to release
> it there?
>

Oh, yes. I will do two things:

(1) Add an optimization to reclaim such that if one of the bitmaps is 
empty, it just returns the other one, and
(2) Add a reclaim call in the error pathway.

>> +
>> +    } else if (sync_bitmap) {
>> +        error_setg(errp,
>> +                   "a sync_bitmap was provided to backup_run, "
>> +                   "but received an incompatible sync_mode (%s)",
>> +                   MirrorSyncMode_lookup[sync_mode]);
>> +        return;
>> +    }
>> +
>>       len = bdrv_getlength(bs);
>>       if (len < 0) {
>>           error_setg_errno(errp, -len, "unable to get length for '%s'",
>> @@ -403,6 +479,8 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
>>       job->on_target_error = on_target_error;
>>       job->target = target;
>>       job->sync_mode = sync_mode;
>> +    job->sync_bitmap = sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP ?
>> +                       sync_bitmap : NULL;
>>       job->common.len = len;
>>       job->common.co = qemu_coroutine_create(backup_run);
>>       qemu_coroutine_enter(job->common.co, job);
>> diff --git a/block/mirror.c b/block/mirror.c
>> index fc545f1..427c688 100644
>> --- a/block/mirror.c
>> +++ b/block/mirror.c
>> @@ -717,6 +717,10 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
>>       bool is_none_mode;
>>       BlockDriverState *base;
>>
>> +    if (mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
>> +        error_setg(errp, "Sync mode 'dirty-bitmap' not supported");
>> +        return;
>> +    }
>>       is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
>>       base = mode == MIRROR_SYNC_MODE_TOP ? bs->backing_hd : NULL;
>>       mirror_start_job(bs, target, replaces,
>> diff --git a/blockdev.c b/blockdev.c
>> index 8dde72a..114a94c 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -1569,6 +1569,7 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
>>                        backup->sync,
>>                        backup->has_mode, backup->mode,
>>                        backup->has_speed, backup->speed,
>> +                     backup->has_bitmap, backup->bitmap,
>>                        backup->has_on_source_error, backup->on_source_error,
>>                        backup->has_on_target_error, backup->on_target_error,
>>                        &local_err);
>> @@ -2358,6 +2359,7 @@ void qmp_drive_backup(const char *device, const char *target,
>>                         enum MirrorSyncMode sync,
>>                         bool has_mode, enum NewImageMode mode,
>>                         bool has_speed, int64_t speed,
>> +                      bool has_bitmap, const char *bitmap,
>>                         bool has_on_source_error, BlockdevOnError on_source_error,
>>                         bool has_on_target_error, BlockdevOnError on_target_error,
>>                         Error **errp)
>> @@ -2365,6 +2367,7 @@ void qmp_drive_backup(const char *device, const char *target,
>>       BlockDriverState *bs;
>>       BlockDriverState *target_bs;
>>       BlockDriverState *source = NULL;
>> +    BdrvDirtyBitmap *bmap = NULL;
>>       AioContext *aio_context;
>>       BlockDriver *drv = NULL;
>>       Error *local_err = NULL;
>> @@ -2460,7 +2463,16 @@ void qmp_drive_backup(const char *device, const char *target,
>>
>>       bdrv_set_aio_context(target_bs, aio_context);
>>
>> -    backup_start(bs, target_bs, speed, sync, on_source_error, on_target_error,
>> +    if (has_bitmap) {
>> +        bmap = bdrv_find_dirty_bitmap(bs, bitmap);
>> +        if (!bmap) {
>> +            error_setg(errp, "Bitmap '%s' could not be found", bitmap);
>> +            goto out;
>> +        }
>> +    }
>> +
>> +    backup_start(bs, target_bs, speed, sync, bmap,
>> +                 on_source_error, on_target_error,
>>                    block_job_cb, bs, &local_err);
>>       if (local_err != NULL) {
>>           bdrv_unref(target_bs);
>> diff --git a/hmp.c b/hmp.c
>> index 481be80..63b19c7 100644
>> --- a/hmp.c
>> +++ b/hmp.c
>> @@ -1021,7 +1021,8 @@ void hmp_drive_backup(Monitor *mon, const QDict *qdict)
>>
>>       qmp_drive_backup(device, filename, !!format, format,
>>                        full ? MIRROR_SYNC_MODE_FULL : MIRROR_SYNC_MODE_TOP,
>> -                     true, mode, false, 0, false, 0, false, 0, &err);
>> +                     true, mode, false, 0, false, NULL,
>> +                     false, 0, false, 0, &err);
>>       hmp_handle_error(mon, &err);
>>   }
>>
>> diff --git a/include/block/block.h b/include/block/block.h
>> index 6138544..99ed679 100644
>> --- a/include/block/block.h
>> +++ b/include/block/block.h
>> @@ -462,6 +462,7 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>   void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>>   void bdrv_dirty_iter_init(BlockDriverState *bs,
>>                             BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
>> +void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
>>   int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>>
>>   void bdrv_enable_copy_on_read(BlockDriverState *bs);
>> diff --git a/include/block/block_int.h b/include/block/block_int.h
>> index 06a21dd..cb1e4a1 100644
>> --- a/include/block/block_int.h
>> +++ b/include/block/block_int.h
>> @@ -584,6 +584,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
>>    * @target: Block device to write to.
>>    * @speed: The maximum speed, in bytes per second, or 0 for unlimited.
>>    * @sync_mode: What parts of the disk image should be copied to the destination.
>> + * @sync_bitmap: The dirty bitmap if sync_mode is MIRROR_SYNC_MODE_DIRTY_BITMAP.
>>    * @on_source_error: The action to take upon error reading from the source.
>>    * @on_target_error: The action to take upon error writing to the target.
>>    * @cb: Completion function for the job.
>> @@ -594,6 +595,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
>>    */
>>   void backup_start(BlockDriverState *bs, BlockDriverState *target,
>>                     int64_t speed, MirrorSyncMode sync_mode,
>> +                  BdrvDirtyBitmap *sync_bitmap,
>>                     BlockdevOnError on_source_error,
>>                     BlockdevOnError on_target_error,
>>                     BlockCompletionFunc *cb, void *opaque,
>> diff --git a/qapi/block-core.json b/qapi/block-core.json
>> index 3e863b9..92c3a84 100644
>> --- a/qapi/block-core.json
>> +++ b/qapi/block-core.json
>> @@ -500,7 +500,7 @@
>>   # Since: 1.3
>>   ##
>>   { 'enum': 'MirrorSyncMode',
>> -  'data': ['top', 'full', 'none'] }
>> +  'data': ['top', 'full', 'none', 'dirty-bitmap'] }
>
> Maybe document version info for 'dirty-bitmap'? Eric?
>
> Fam
>
> <snip>
>

Thanks!
--John

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 13/13] block: BdrvDirtyBitmap miscellaneous fixup
  2015-01-13 16:50   ` Vladimir Sementsov-Ogievskiy
@ 2015-01-13 18:27     ` John Snow
  0 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-13 18:27 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy, qemu-devel
  Cc: kwolf, famz, armbru, stefanha, mreitz



On 01/13/2015 11:50 AM, Vladimir Sementsov-Ogievskiy wrote:
> Hmm. May be, update the size field to be uint64_t too? Negative size is
> not meaningful..
>
> Best regards,
> Vladimir
>

No, it is not meaningful. However, it does match the return type from 
bdrv_nb_sectors(bs), which uses -1 to indicate an error. So we also 
don't really need to change it in this circumstance, since we'll not be 
exceeding what int64_t/bdrv_nb_sectors can provide anyway.

(Plus, INT64_MAX sectors is an absurdly large amount of bytes!)

I'll see how many changes this requires in other helper functions when I 
prepare a V12. If it's easy I will do it.

Thanks!
--js

> On 12.01.2015 19:31, John Snow wrote:
>> (1) granularity type consistency: Update the granularity to be uint64_t
>>      in all places. This value is always in bytes.
>>
>> (2) Some documentation for the fields within BdrvDirtyBitmap.
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   block.c               | 16 ++++++++--------
>>   include/block/block.h |  2 +-
>>   2 files changed, 9 insertions(+), 9 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index 9e2b8c0..13f9cc0 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -52,13 +52,13 @@
>>   #endif
>>   struct BdrvDirtyBitmap {
>> -    HBitmap *bitmap;
>> -    BdrvDirtyBitmap *successor;
>> -    int64_t size;
>> -    int64_t granularity;
>> -    char *name;
>> -    bool enabled;
>> -    bool frozen;
>> +    HBitmap *bitmap;            /* Dirty sector bitmap */
>> +    BdrvDirtyBitmap *successor; /* Anonymous child */
>> +    int64_t size;               /* Number of sectors */
>> +    uint64_t granularity;       /* Granularity in bytes */
>> +    char *name;                 /* Optional non-empty unique ID */
>> +    bool enabled;               /* Writes are being tracked */
>> +    bool frozen;                /* Protected; see
>> bdrv_freeze_dirty_bitmap() */
>>       QLIST_ENTRY(BdrvDirtyBitmap) list;
>>   };
>> @@ -5350,7 +5350,7 @@ void
>> bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap
>> *bitmap)
>>   }
>>   BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>> -                                          int granularity,
>> +                                          uint64_t granularity,
>>                                             const char *name,
>>                                             Error **errp)
>>   {
>> diff --git a/include/block/block.h b/include/block/block.h
>> index 99ed679..749429e 100644
>> --- a/include/block/block.h
>> +++ b/include/block/block.h
>> @@ -430,7 +430,7 @@ bool bdrv_qiov_is_aligned(BlockDriverState *bs,
>> QEMUIOVector *qiov);
>>   struct HBitmapIter;
>>   typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
>>   BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>> -                                          int granularity,
>> +                                          uint64_t granularity,
>>                                             const char *name,
>>                                             Error **errp);
>>   int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>
>

-- 
—js

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (13 preceding siblings ...)
  2015-01-13  1:21 ` [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series Fam Zheng
@ 2015-01-13 19:52 ` John Snow
  2015-01-29 22:38 ` John Snow
  2015-01-30 10:24 ` Vladimir Sementsov-Ogievskiy
  16 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-13 19:52 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, armbru, mreitz, vsementsov, stefanha

Minor update to the github version of this patchset that brings it 
inline with the recent block pull into master. It also drops a duplicate 
patch that has since made it upstream.

Not re-posting yet to allow time for review and critique.

--js

On 01/12/2015 11:30 AM, John Snow wrote:
> Welcome to version 11. I hope you are enjoying our regular newsletter.
>
> This patchset enables the in-memory part of the incremental backup
> feature. A patchset by Vladimir Sementsov-Ogievskiy enables the
> migration of in-memory dirty bitmaps, and a future patchset will
> enable the storage and retrieval of dirty bitmaps to and from permanent
> storage.
>
> Enough changes have been made that most Reviewed-By lines from
> previous iterations have been removed. (Sorry!)
>
> This series was originally authored by Fam Zheng;
> his cover letter is included below.
>
> ~John Snow
>
> =================================================================
>
> This is the in memory part of the incremental backup feature.
>
> With the added commands, we can create a bitmap on a block
> backend, from which point of time all the writes are tracked by
> the bitmap, marking sectors as dirty. Later, we call drive-backup
> and pass the bitmap to it, to do an incremental backup.
>
> See the last patch which adds some tests for this use case.
>
> Fam
>
> =================================================================
>
> For convenience, this patchset is available on github:
>                  https://github.com/jnsnow/qemu/commits/dbm-backup
>
> v11:
>
>   - Instead of copying BdrvDirtyBitmaps and keeping a pointer to the
>     object we were copied from, we instead "freeze" a bitmap in-place
>     without copying it. On success, we thaw and delete the bitmap.
>     On failure, we merge the bitmap with a "successor," which is an
>     anonymous bitmap attached as a child that records writes for us
>     for the duration of the backup operation.
>
>     This means that incremental backups can NEVER BE RETRIED in a
>     deterministic fashion. If an incremental backup fails on a set
>     of dirty sectors {x}, and a new set of dirty sectors {y} are
>     introduced during the backup, then any possible retry action
>     on an incremental backup can only operate on {x,y}. There is no
>     way to get an incremental backup "as it would have been."
>
>     So, the failure mode for incremental backup is to try again,
>     and the resulting image will simply be a differential from the
>     last successful dirty bitmap backup.
>
>   - Removed hbitmap_copy and bdrv_dirty_bitmap_copy.
>
>   - Added a small fixup patch:
>     - Update all granularity fields to be uint64_t.
>     - Update documentation around BdrvDirtyBitmap structure.
>
>   - Modified transactions to obey frozen attribute of BdrvDirtyBitmaps.
>
>   - Added frozen attribute to the info query.
>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup
  2015-01-13 17:50     ` John Snow
@ 2015-01-14  6:29       ` Fam Zheng
  0 siblings, 0 replies; 54+ messages in thread
From: Fam Zheng @ 2015-01-14  6:29 UTC (permalink / raw)
  To: John Snow; +Cc: kwolf, qemu-devel, armbru, mreitz, vsementsov, stefanha

On Tue, 01/13 12:50, John Snow wrote:
> 
> 
> On 01/13/2015 04:37 AM, Fam Zheng wrote:
> >On Mon, 01/12 11:31, John Snow wrote:
> >>For "dirty-bitmap" sync mode, the block job will iterate through the
> >>given dirty bitmap to decide if a sector needs backup (backup all the
> >>dirty clusters and skip clean ones), just as allocation conditions of
> >>"top" sync mode.
> >>
> >>Signed-off-by: Fam Zheng <famz@redhat.com>
> >>Signed-off-by: John Snow <jsnow@redhat.com>
> >>---
> >>  block.c                   |   5 ++
> >>  block/backup.c            | 120 ++++++++++++++++++++++++++++++++++++++--------
> >>  block/mirror.c            |   4 ++
> >>  blockdev.c                |  14 +++++-
> >>  hmp.c                     |   3 +-
> >>  include/block/block.h     |   1 +
> >>  include/block/block_int.h |   2 +
> >>  qapi/block-core.json      |  11 +++--
> >>  qmp-commands.hx           |   7 +--
> >>  9 files changed, 137 insertions(+), 30 deletions(-)
> >>
> >>diff --git a/block.c b/block.c
> >>index 3f33b9d..5eb6788 100644
> >>--- a/block.c
> >>+++ b/block.c
> >>@@ -5633,6 +5633,11 @@ static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
> >>      }
> >>  }
> >>
> >>+void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
> >>+{
> >>+    hbitmap_iter_init(hbi, hbi->hb, offset);
> >
> >What's the reason for this indirection? Can caller just use hbitmap_iter_init?
> >
> 
> Essentially it is just a rename of hbitmap_iter_init to make its usage here
> clear, that we are manually advancing the pointer. How we accomplish that
> (hbitmap_iter_init) is an implementation detail.
> 
> Yes, I can just call this directly from block/backup, but at the time I was
> less sure of how I would advance the pointer, so I created a wrapper where I
> could change details as needed, if I needed to.

OK, either is fine for me.

> 
> >>+}
> >>+
> >>  int64_t bdrv_get_dirty_count(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
> >>  {
> >>      return hbitmap_count(bitmap->bitmap);
> >>diff --git a/block/backup.c b/block/backup.c
> >>index 792e655..0626a3e 100644
> >>--- a/block/backup.c
> >>+++ b/block/backup.c
> >>@@ -37,6 +37,8 @@ typedef struct CowRequest {
> >>  typedef struct BackupBlockJob {
> >>      BlockJob common;
> >>      BlockDriverState *target;
> >>+    /* bitmap for sync=dirty-bitmap */
> >>+    BdrvDirtyBitmap *sync_bitmap;
> >>      MirrorSyncMode sync_mode;
> >>      RateLimit limit;
> >>      BlockdevOnError on_source_error;
> >>@@ -242,6 +244,31 @@ static void backup_complete(BlockJob *job, void *opaque)
> >>      g_free(data);
> >>  }
> >>
> >>+static bool coroutine_fn yield_and_check(BackupBlockJob *job)
> >>+{
> >>+    if (block_job_is_cancelled(&job->common)) {
> >>+        return true;
> >>+    }
> >>+
> >>+    /* we need to yield so that qemu_aio_flush() returns.
> >>+     * (without, VM does not reboot)
> >>+     */
> >>+    if (job->common.speed) {
> >>+        uint64_t delay_ns = ratelimit_calculate_delay(&job->limit,
> >>+                                                      job->sectors_read);
> >>+        job->sectors_read = 0;
> >>+        block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
> >>+    } else {
> >>+        block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
> >>+    }
> >>+
> >>+    if (block_job_is_cancelled(&job->common)) {
> >>+        return true;
> >>+    }
> >>+
> >>+    return false;
> >>+}
> >>+
> >>  static void coroutine_fn backup_run(void *opaque)
> >>  {
> >>      BackupBlockJob *job = opaque;
> >>@@ -254,13 +281,13 @@ static void coroutine_fn backup_run(void *opaque)
> >>      };
> >>      int64_t start, end;
> >>      int ret = 0;
> >>+    bool error_is_read;
> >>
> >>      QLIST_INIT(&job->inflight_reqs);
> >>      qemu_co_rwlock_init(&job->flush_rwlock);
> >>
> >>      start = 0;
> >>-    end = DIV_ROUND_UP(job->common.len / BDRV_SECTOR_SIZE,
> >>-                       BACKUP_SECTORS_PER_CLUSTER);
> >>+    end = DIV_ROUND_UP(job->common.len, BACKUP_CLUSTER_SIZE);
> >>
> >>      job->bitmap = hbitmap_alloc(end, 0);
> >>
> >>@@ -278,28 +305,45 @@ static void coroutine_fn backup_run(void *opaque)
> >>              qemu_coroutine_yield();
> >>              job->common.busy = true;
> >>          }
> >>+    } else if (job->sync_mode == MIRROR_SYNC_MODE_DIRTY_BITMAP) {
> >>+        /* Dirty Bitmap sync has a slightly different iteration method */
> >>+        HBitmapIter hbi;
> >>+        int64_t sector;
> >>+        int64_t cluster;
> >>+        bool polyrhythmic;
> >>+
> >>+        bdrv_dirty_iter_init(bs, job->sync_bitmap, &hbi);
> >>+        /* Does the granularity happen to match our backup cluster size? */
> >>+        polyrhythmic = (bdrv_dirty_bitmap_granularity(bs, job->sync_bitmap) !=
> >>+                        BACKUP_CLUSTER_SIZE);
> >>+
> >>+        /* Find the next dirty /sector/ and copy that /cluster/ */
> >>+        while ((sector = hbitmap_iter_next(&hbi)) != -1) {
> >>+            if (yield_and_check(job)) {
> >>+                goto leave;
> >>+            }
> >>+            cluster = sector / BACKUP_SECTORS_PER_CLUSTER;
> >>+
> >>+            do {
> >>+                ret = backup_do_cow(bs, cluster * BACKUP_SECTORS_PER_CLUSTER,
> >>+                                    BACKUP_SECTORS_PER_CLUSTER, &error_is_read);
> >>+                if ((ret < 0) &&
> >>+                    backup_error_action(job, error_is_read, -ret) ==
> >>+                    BLOCK_ERROR_ACTION_REPORT) {
> >>+                    goto leave;
> >>+                }
> >>+            } while (ret < 0);
> >>+
> >>+            /* Advance (or rewind) our iterator if we need to. */
> >>+            if (polyrhythmic) {
> >>+                bdrv_set_dirty_iter(&hbi,
> >>+                                    (cluster + 1) * BACKUP_SECTORS_PER_CLUSTER);
> >>+            }
> >>+        }
> >>      } else {
> >>          /* Both FULL and TOP SYNC_MODE's require copying.. */
> >>          for (; start < end; start++) {
> >>-            bool error_is_read;
> >>-
> >>-            if (block_job_is_cancelled(&job->common)) {
> >>-                break;
> >>-            }
> >>-
> >>-            /* we need to yield so that qemu_aio_flush() returns.
> >>-             * (without, VM does not reboot)
> >>-             */
> >>-            if (job->common.speed) {
> >>-                uint64_t delay_ns = ratelimit_calculate_delay(
> >>-                        &job->limit, job->sectors_read);
> >>-                job->sectors_read = 0;
> >>-                block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, delay_ns);
> >>-            } else {
> >>-                block_job_sleep_ns(&job->common, QEMU_CLOCK_REALTIME, 0);
> >>-            }
> >>-
> >>-            if (block_job_is_cancelled(&job->common)) {
> >>+            if (yield_and_check(job)) {
> >>                  break;
> >>              }
> >>
> >>@@ -351,12 +395,23 @@ static void coroutine_fn backup_run(void *opaque)
> >>          }
> >>      }
> >>
> >>+leave:
> >>      notifier_with_return_remove(&before_write);
> >>
> >>      /* wait until pending backup_do_cow() calls have completed */
> >>      qemu_co_rwlock_wrlock(&job->flush_rwlock);
> >>      qemu_co_rwlock_unlock(&job->flush_rwlock);
> >>
> >>+    if (job->sync_bitmap) {
> >>+        if (ret < 0) {
> >>+            /* Merge the successor back into the parent, delete nothing. */
> >>+            assert(bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL));
> >
> >Why can't reclaim fail here? If we canassert, please move the expression out
> >because it has a side effect.
> >
> 
> It shouldn't fail; if it does, something went very wrong. The only chance
> this has to fail is if the sync bitmap has no successor, but we explicitly
> installed one (and explicitly check that it succeeded) before going into the
> block backup.
> 
> I am not sure what other meaningful recovery could happen in this case,
> though we *could* just report an error and continue on, acknowledging that
> the BdrvDirtyBitmap is now compromised and of questionable validity.
> 
> Does anyone have an error handling preference here?

I don't, as long as you move it out from assert:

int r = bdrv_reclaim_dirty_bitmap(bs, job->sync_bitmap, NULL);
assert(r);

Fam

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove John Snow
@ 2015-01-16 15:36   ` Max Reitz
  2015-01-16 16:48     ` John Snow
  2015-01-29 13:55   ` Vladimir Sementsov-Ogievskiy
  1 sibling, 1 reply; 54+ messages in thread
From: Max Reitz @ 2015-01-16 15:36 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, vsementsov, stefanha

On 2015-01-12 at 11:30, John Snow wrote:
> From: Fam Zheng <famz@redhat.com>
>
> The new command pair is added to manage user created dirty bitmap. The
> dirty bitmap's name is mandatory and must be unique for the same device,
> but different devices can have bitmaps with the same names.
>
> The granularity is an optional field. If it is not specified, we will
> choose a default granularity based on the cluster size if available,
> clamped to between 4K and 64K to mirror how the 'mirror' code was
> already choosing granularity. If we do not have cluster size info
> available, we choose 64K. This code has been factored out into a helper
> shared with block/mirror.
>
> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
> which takes a device name and a dirty bitmap name and validates the
> lookup, returning NULL and setting errp if there is a problem with
> either field. This helper will be re-used in future patches in this
> series.
>
> The types added to block-core.json will be re-used in future patches
> in this series, see:
> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable, disable}'
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   block.c               |  20 ++++++++++
>   block/mirror.c        |  10 +----
>   blockdev.c            | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++
>   include/block/block.h |   1 +
>   qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>   qmp-commands.hx       |  51 +++++++++++++++++++++++++
>   6 files changed, 228 insertions(+), 9 deletions(-)
>
> diff --git a/block.c b/block.c
> index bfeae6b..3eb77ee 100644
> --- a/block.c
> +++ b/block.c
> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector
>       }
>   }
>   
> +/**
> + * Chooses a default granularity based on the existing cluster size,
> + * but clamped between [4K, 64K]. Defaults to 64K in the case that there
> + * is no cluster size information available.
> + */
> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
> +{
> +    BlockDriverInfo bdi;
> +    uint64_t granularity;
> +
> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
> +        granularity = MAX(4096, bdi.cluster_size);
> +        granularity = MIN(65536, granularity);
> +    } else {
> +        granularity = 65536;
> +    }
> +
> +    return granularity;
> +}
> +
>   void bdrv_dirty_iter_init(BlockDriverState *bs,
>                             BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>   {
> diff --git a/block/mirror.c b/block/mirror.c
> index d819952..fc545f1 100644
> --- a/block/mirror.c
> +++ b/block/mirror.c
> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
>       MirrorBlockJob *s;
>   
>       if (granularity == 0) {
> -        /* Choose the default granularity based on the target file's cluster
> -         * size, clamped between 4k and 64k.  */
> -        BlockDriverInfo bdi;
> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
> -            granularity = MAX(4096, bdi.cluster_size);
> -            granularity = MIN(65536, granularity);
> -        } else {
> -            granularity = 65536;
> -        }
> +        granularity = bdrv_get_default_bitmap_granularity(target);
>       }
>   
>       assert ((granularity & (granularity - 1)) == 0);
> diff --git a/blockdev.c b/blockdev.c
> index 5651a8e..95251c7 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1173,6 +1173,48 @@ out_aio_context:
>       return NULL;
>   }
>   
> +/**
> + * Return a dirty bitmap (if present), after validating
> + * the node reference and bitmap names. Returns NULL on error,
> + * including when the BDS and/or bitmap is not found.
> + */
> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
> +                                                  const char *name,
> +                                                  BlockDriverState **pbs,
> +                                                  Error **errp)
> +{
> +    BlockDriverState *bs;
> +    BdrvDirtyBitmap *bitmap;
> +
> +    if (!node_ref) {
> +        error_setg(errp, "Node reference cannot be NULL");
> +        return NULL;
> +    }
> +    if (!name) {
> +        error_setg(errp, "Bitmap name cannot be NULL");
> +        return NULL;
> +    }
> +
> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
> +    if (!bs) {
> +        error_setg(errp, "Node reference '%s' not found", node_ref);

No need to throw the (hopefully) perfectly fine Error code returned by 
bdrv_lookup_bs() away.

> +        return NULL;
> +    }
> +
> +    /* If caller provided a BDS*, provide the result of that lookup, too. */
> +    if (pbs) {
> +        *pbs = bs;
> +    }
> +
> +    bitmap = bdrv_find_dirty_bitmap(bs, name);
> +    if (!bitmap) {
> +        error_setg(errp, "Dirty bitmap not found: %s", name);

I'd use "Dirty bitmap '%s' not found", because "foo: bar" in an error 
message looks like "foo because bar" to me. But it's up to you, dirty 
bitmap names most likely don't look like error reasons so nobody should 
be able to confuse it.

So with the error_setg() in the fail path for bdrv_lookup_bs() removed:

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 04/13] block: Introduce bdrv_dirty_bitmap_granularity()
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 04/13] block: Introduce bdrv_dirty_bitmap_granularity() John Snow
@ 2015-01-16 15:40   ` Max Reitz
  0 siblings, 0 replies; 54+ messages in thread
From: Max Reitz @ 2015-01-16 15:40 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, vsementsov, stefanha

On 2015-01-12 at 11:30, John Snow wrote:
> From: Fam Zheng <famz@redhat.com>
>
> This returns the granularity (in bytes) of dirty bitmap,
> which matches the QMP interface and the existing query
> interface.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   block.c               | 9 +++++++--
>   include/block/block.h | 2 ++
>   2 files changed, 9 insertions(+), 2 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 05/13] block: Add bdrv_clear_dirty_bitmap
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 05/13] block: Add bdrv_clear_dirty_bitmap John Snow
@ 2015-01-16 15:56   ` Max Reitz
  0 siblings, 0 replies; 54+ messages in thread
From: Max Reitz @ 2015-01-16 15:56 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, vsementsov, stefanha

On 2015-01-12 at 11:30, John Snow wrote:
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   block.c               | 24 ++++++++++++++++++++----
>   include/block/block.h |  1 +
>   2 files changed, 21 insertions(+), 4 deletions(-)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 06/13] hbitmap: add hbitmap_merge
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 06/13] hbitmap: add hbitmap_merge John Snow
@ 2015-01-16 16:12   ` Max Reitz
  0 siblings, 0 replies; 54+ messages in thread
From: Max Reitz @ 2015-01-16 16:12 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, vsementsov, stefanha

On 2015-01-12 at 11:30, John Snow wrote:
> We add a bitmap merge operation to assist in error cases
> where we wish to combine two bitmaps together.
>
> This is algorithmically O(bits) provided HBITMAP_LEVELS remains
> constant. For a full bitmap on a 64bit machine:
> sum(bits/64^k, k, 0, HBITMAP_LEVELS) ~= 1.01587 * bits
>
> We may be able to improve running speed for particularly sparse
> bitmaps by using iterators, but the running time for dense maps
> will be worse.
>
> We present the simpler solution first, and we can refine it later
> if needed.
>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   include/qemu/hbitmap.h | 11 +++++++++++
>   util/hbitmap.c         | 28 ++++++++++++++++++++++++++++
>   2 files changed, 39 insertions(+)

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 07/13] qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 07/13] qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable John Snow
@ 2015-01-16 16:28   ` Max Reitz
  2015-01-16 17:09     ` John Snow
  0 siblings, 1 reply; 54+ messages in thread
From: Max Reitz @ 2015-01-16 16:28 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, vsementsov, stefanha

On 2015-01-12 at 11:30, John Snow wrote:
> From: Fam Zheng <famz@redhat.com>
>
> This allows to put the dirty bitmap into a disabled state where no more
> writes will be tracked.
>
> It will be used before backup or writing to persistent file.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   block.c               | 24 +++++++++++++++++++++++-
>   blockdev.c            | 40 ++++++++++++++++++++++++++++++++++++++++
>   include/block/block.h |  3 +++
>   qapi/block-core.json  | 28 ++++++++++++++++++++++++++++
>   qmp-commands.hx       | 10 ++++++++++
>   5 files changed, 104 insertions(+), 1 deletion(-)
>
> diff --git a/block.c b/block.c
> index 7bf7079..bd4b449 100644
> --- a/block.c
> +++ b/block.c
> @@ -56,6 +56,7 @@ struct BdrvDirtyBitmap {
>       int64_t size;
>       int64_t granularity;
>       char *name;
> +    bool enabled;
>       QLIST_ENTRY(BdrvDirtyBitmap) list;
>   };
>   
> @@ -5373,10 +5374,16 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>       bitmap->granularity = granularity;
>       bitmap->bitmap = hbitmap_alloc(bitmap->size, ffs(sector_granularity) - 1);
>       bitmap->name = g_strdup(name);
> +    bitmap->enabled = true;
>       QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
>       return bitmap;
>   }
>   
> +bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
> +{
> +    return bitmap->enabled;
> +}
> +
>   void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>   {
>       BdrvDirtyBitmap *bm, *next;
> @@ -5391,6 +5398,16 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>       }
>   }
>   
> +void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    bitmap->enabled = false;
> +}
> +
> +void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    bitmap->enabled = true;
> +}
> +
>   BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
>   {
>       BdrvDirtyBitmap *bm;
> @@ -5458,7 +5475,9 @@ void bdrv_dirty_iter_init(BlockDriverState *bs,
>   void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>                              int64_t cur_sector, int nr_sectors)
>   {
> -    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
> +    if (bdrv_dirty_bitmap_enabled(bitmap)) {
> +        hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
> +    }

Why are you checking whether the bitmap is enabled here in 
bdrv_set_dirty_bitmap(), but neither in bdrv_reset_dirty_bitmap() nor 
bdrv_clear_dirty_bitmap()?

It seems consistent with the commit message which only states that 
disabled state means that no more writes (i.e. bdrv_set_dirty_bitmap()) 
will be tracked, but it still seems strange to me.

>   }
>   
>   void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
> @@ -5481,6 +5500,9 @@ static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
>   {
>       BdrvDirtyBitmap *bitmap;
>       QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> +        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
> +            continue;
> +        }

Same question as above, only this time it's about bdrv_reset_dirty().

In case the answer to the question is "that's intentional":

Reviewed-by: Max Reitz <mreitz@redhat.com>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-16 15:36   ` Max Reitz
@ 2015-01-16 16:48     ` John Snow
  2015-01-16 16:51       ` Max Reitz
  2015-01-19 10:08       ` Markus Armbruster
  0 siblings, 2 replies; 54+ messages in thread
From: John Snow @ 2015-01-16 16:48 UTC (permalink / raw)
  To: Max Reitz, qemu-devel; +Cc: kwolf, vsementsov, famz, armbru, stefanha



On 01/16/2015 10:36 AM, Max Reitz wrote:
> On 2015-01-12 at 11:30, John Snow wrote:
>> From: Fam Zheng <famz@redhat.com>
>>
>> The new command pair is added to manage user created dirty bitmap. The
>> dirty bitmap's name is mandatory and must be unique for the same device,
>> but different devices can have bitmaps with the same names.
>>
>> The granularity is an optional field. If it is not specified, we will
>> choose a default granularity based on the cluster size if available,
>> clamped to between 4K and 64K to mirror how the 'mirror' code was
>> already choosing granularity. If we do not have cluster size info
>> available, we choose 64K. This code has been factored out into a helper
>> shared with block/mirror.
>>
>> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
>> which takes a device name and a dirty bitmap name and validates the
>> lookup, returning NULL and setting errp if there is a problem with
>> either field. This helper will be re-used in future patches in this
>> series.
>>
>> The types added to block-core.json will be re-used in future patches
>> in this series, see:
>> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>> disable}'
>>
>> Signed-off-by: Fam Zheng <famz@redhat.com>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   block.c               |  20 ++++++++++
>>   block/mirror.c        |  10 +----
>>   blockdev.c            | 100
>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>   include/block/block.h |   1 +
>>   qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>>   qmp-commands.hx       |  51 +++++++++++++++++++++++++
>>   6 files changed, 228 insertions(+), 9 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index bfeae6b..3eb77ee 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs,
>> BdrvDirtyBitmap *bitmap, int64_t sector
>>       }
>>   }
>> +/**
>> + * Chooses a default granularity based on the existing cluster size,
>> + * but clamped between [4K, 64K]. Defaults to 64K in the case that there
>> + * is no cluster size information available.
>> + */
>> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
>> +{
>> +    BlockDriverInfo bdi;
>> +    uint64_t granularity;
>> +
>> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
>> +        granularity = MAX(4096, bdi.cluster_size);
>> +        granularity = MIN(65536, granularity);
>> +    } else {
>> +        granularity = 65536;
>> +    }
>> +
>> +    return granularity;
>> +}
>> +
>>   void bdrv_dirty_iter_init(BlockDriverState *bs,
>>                             BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>>   {
>> diff --git a/block/mirror.c b/block/mirror.c
>> index d819952..fc545f1 100644
>> --- a/block/mirror.c
>> +++ b/block/mirror.c
>> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState
>> *bs, BlockDriverState *target,
>>       MirrorBlockJob *s;
>>       if (granularity == 0) {
>> -        /* Choose the default granularity based on the target file's
>> cluster
>> -         * size, clamped between 4k and 64k.  */
>> -        BlockDriverInfo bdi;
>> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
>> -            granularity = MAX(4096, bdi.cluster_size);
>> -            granularity = MIN(65536, granularity);
>> -        } else {
>> -            granularity = 65536;
>> -        }
>> +        granularity = bdrv_get_default_bitmap_granularity(target);
>>       }
>>       assert ((granularity & (granularity - 1)) == 0);
>> diff --git a/blockdev.c b/blockdev.c
>> index 5651a8e..95251c7 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -1173,6 +1173,48 @@ out_aio_context:
>>       return NULL;
>>   }
>> +/**
>> + * Return a dirty bitmap (if present), after validating
>> + * the node reference and bitmap names. Returns NULL on error,
>> + * including when the BDS and/or bitmap is not found.
>> + */
>> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
>> +                                                  const char *name,
>> +                                                  BlockDriverState
>> **pbs,
>> +                                                  Error **errp)
>> +{
>> +    BlockDriverState *bs;
>> +    BdrvDirtyBitmap *bitmap;
>> +
>> +    if (!node_ref) {
>> +        error_setg(errp, "Node reference cannot be NULL");
>> +        return NULL;
>> +    }
>> +    if (!name) {
>> +        error_setg(errp, "Bitmap name cannot be NULL");
>> +        return NULL;
>> +    }
>> +
>> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
>> +    if (!bs) {
>> +        error_setg(errp, "Node reference '%s' not found", node_ref);
>
> No need to throw the (hopefully) perfectly fine Error code returned by
> bdrv_lookup_bs() away.
>

I just wanted an error message consistent with the parameter name, in 
this case. i.e., We couldn't find the "Node reference" instead of 
"device" or "node name." Just trying to distinguish the fact that this 
is an arbitrary reference in the error message.

I can still remove it, but I am curious to see what Markus thinks of the 
names I have chosen before I monkey with the errors too much more.

>> +        return NULL;
>> +    }
>> +
>> +    /* If caller provided a BDS*, provide the result of that lookup,
>> too. */
>> +    if (pbs) {
>> +        *pbs = bs;
>> +    }
>> +
>> +    bitmap = bdrv_find_dirty_bitmap(bs, name);
>> +    if (!bitmap) {
>> +        error_setg(errp, "Dirty bitmap not found: %s", name);
>
> I'd use "Dirty bitmap '%s' not found", because "foo: bar" in an error
> message looks like "foo because bar" to me. But it's up to you, dirty
> bitmap names most likely don't look like error reasons so nobody should
> be able to confuse it.
>

No, I agree.

> So with the error_setg() in the fail path for bdrv_lookup_bs() removed:
>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-16 16:48     ` John Snow
@ 2015-01-16 16:51       ` Max Reitz
  2015-01-16 16:54         ` John Snow
  2015-01-19 10:08       ` Markus Armbruster
  1 sibling, 1 reply; 54+ messages in thread
From: Max Reitz @ 2015-01-16 16:51 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, vsementsov, famz, armbru, stefanha

On 2015-01-16 at 11:48, John Snow wrote:
>
>
> On 01/16/2015 10:36 AM, Max Reitz wrote:
>> On 2015-01-12 at 11:30, John Snow wrote:
>>> From: Fam Zheng <famz@redhat.com>
>>>
>>> The new command pair is added to manage user created dirty bitmap. The
>>> dirty bitmap's name is mandatory and must be unique for the same 
>>> device,
>>> but different devices can have bitmaps with the same names.
>>>
>>> The granularity is an optional field. If it is not specified, we will
>>> choose a default granularity based on the cluster size if available,
>>> clamped to between 4K and 64K to mirror how the 'mirror' code was
>>> already choosing granularity. If we do not have cluster size info
>>> available, we choose 64K. This code has been factored out into a helper
>>> shared with block/mirror.
>>>
>>> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
>>> which takes a device name and a dirty bitmap name and validates the
>>> lookup, returning NULL and setting errp if there is a problem with
>>> either field. This helper will be re-used in future patches in this
>>> series.
>>>
>>> The types added to block-core.json will be re-used in future patches
>>> in this series, see:
>>> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>>> disable}'
>>>
>>> Signed-off-by: Fam Zheng <famz@redhat.com>
>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>> ---
>>>   block.c               |  20 ++++++++++
>>>   block/mirror.c        |  10 +----
>>>   blockdev.c            | 100
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   include/block/block.h |   1 +
>>>   qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>>>   qmp-commands.hx       |  51 +++++++++++++++++++++++++
>>>   6 files changed, 228 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/block.c b/block.c
>>> index bfeae6b..3eb77ee 100644
>>> --- a/block.c
>>> +++ b/block.c
>>> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs,
>>> BdrvDirtyBitmap *bitmap, int64_t sector
>>>       }
>>>   }
>>> +/**
>>> + * Chooses a default granularity based on the existing cluster size,
>>> + * but clamped between [4K, 64K]. Defaults to 64K in the case that 
>>> there
>>> + * is no cluster size information available.
>>> + */
>>> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
>>> +{
>>> +    BlockDriverInfo bdi;
>>> +    uint64_t granularity;
>>> +
>>> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
>>> +        granularity = MAX(4096, bdi.cluster_size);
>>> +        granularity = MIN(65536, granularity);
>>> +    } else {
>>> +        granularity = 65536;
>>> +    }
>>> +
>>> +    return granularity;
>>> +}
>>> +
>>>   void bdrv_dirty_iter_init(BlockDriverState *bs,
>>>                             BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>>>   {
>>> diff --git a/block/mirror.c b/block/mirror.c
>>> index d819952..fc545f1 100644
>>> --- a/block/mirror.c
>>> +++ b/block/mirror.c
>>> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState
>>> *bs, BlockDriverState *target,
>>>       MirrorBlockJob *s;
>>>       if (granularity == 0) {
>>> -        /* Choose the default granularity based on the target file's
>>> cluster
>>> -         * size, clamped between 4k and 64k.  */
>>> -        BlockDriverInfo bdi;
>>> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 
>>> 0) {
>>> -            granularity = MAX(4096, bdi.cluster_size);
>>> -            granularity = MIN(65536, granularity);
>>> -        } else {
>>> -            granularity = 65536;
>>> -        }
>>> +        granularity = bdrv_get_default_bitmap_granularity(target);
>>>       }
>>>       assert ((granularity & (granularity - 1)) == 0);
>>> diff --git a/blockdev.c b/blockdev.c
>>> index 5651a8e..95251c7 100644
>>> --- a/blockdev.c
>>> +++ b/blockdev.c
>>> @@ -1173,6 +1173,48 @@ out_aio_context:
>>>       return NULL;
>>>   }
>>> +/**
>>> + * Return a dirty bitmap (if present), after validating
>>> + * the node reference and bitmap names. Returns NULL on error,
>>> + * including when the BDS and/or bitmap is not found.
>>> + */
>>> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char 
>>> *node_ref,
>>> +                                                  const char *name,
>>> + BlockDriverState
>>> **pbs,
>>> +                                                  Error **errp)
>>> +{
>>> +    BlockDriverState *bs;
>>> +    BdrvDirtyBitmap *bitmap;
>>> +
>>> +    if (!node_ref) {
>>> +        error_setg(errp, "Node reference cannot be NULL");
>>> +        return NULL;
>>> +    }
>>> +    if (!name) {
>>> +        error_setg(errp, "Bitmap name cannot be NULL");
>>> +        return NULL;
>>> +    }
>>> +
>>> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
>>> +    if (!bs) {
>>> +        error_setg(errp, "Node reference '%s' not found", node_ref);
>>
>> No need to throw the (hopefully) perfectly fine Error code returned by
>> bdrv_lookup_bs() away.
>>
>
> I just wanted an error message consistent with the parameter name, in 
> this case. i.e., We couldn't find the "Node reference" instead of 
> "device" or "node name." Just trying to distinguish the fact that this 
> is an arbitrary reference in the error message.
>
> I can still remove it, but I am curious to see what Markus thinks of 
> the names I have chosen before I monkey with the errors too much more.

Very well then, but you should clean up the error returned by 
bdrv_lookup_bs() (call error_free()).

Feel free to keep my R-b whichever decision you'll make (as long as the 
error returned by bdrv_lookup_bs() is not leaked).

Max

>
>>> +        return NULL;
>>> +    }
>>> +
>>> +    /* If caller provided a BDS*, provide the result of that lookup,
>>> too. */
>>> +    if (pbs) {
>>> +        *pbs = bs;
>>> +    }
>>> +
>>> +    bitmap = bdrv_find_dirty_bitmap(bs, name);
>>> +    if (!bitmap) {
>>> +        error_setg(errp, "Dirty bitmap not found: %s", name);
>>
>> I'd use "Dirty bitmap '%s' not found", because "foo: bar" in an error
>> message looks like "foo because bar" to me. But it's up to you, dirty
>> bitmap names most likely don't look like error reasons so nobody should
>> be able to confuse it.
>>
>
> No, I agree.
>
>> So with the error_setg() in the fail path for bdrv_lookup_bs() removed:
>>
>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>>
>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-16 16:51       ` Max Reitz
@ 2015-01-16 16:54         ` John Snow
  0 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-16 16:54 UTC (permalink / raw)
  To: Max Reitz, qemu-devel; +Cc: kwolf, vsementsov, famz, armbru, stefanha



On 01/16/2015 11:51 AM, Max Reitz wrote:
> On 2015-01-16 at 11:48, John Snow wrote:
>>
>>
>> On 01/16/2015 10:36 AM, Max Reitz wrote:
>>> On 2015-01-12 at 11:30, John Snow wrote:
>>>> From: Fam Zheng <famz@redhat.com>
>>>>
>>>> The new command pair is added to manage user created dirty bitmap. The
>>>> dirty bitmap's name is mandatory and must be unique for the same
>>>> device,
>>>> but different devices can have bitmaps with the same names.
>>>>
>>>> The granularity is an optional field. If it is not specified, we will
>>>> choose a default granularity based on the cluster size if available,
>>>> clamped to between 4K and 64K to mirror how the 'mirror' code was
>>>> already choosing granularity. If we do not have cluster size info
>>>> available, we choose 64K. This code has been factored out into a helper
>>>> shared with block/mirror.
>>>>
>>>> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
>>>> which takes a device name and a dirty bitmap name and validates the
>>>> lookup, returning NULL and setting errp if there is a problem with
>>>> either field. This helper will be re-used in future patches in this
>>>> series.
>>>>
>>>> The types added to block-core.json will be re-used in future patches
>>>> in this series, see:
>>>> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>>>> disable}'
>>>>
>>>> Signed-off-by: Fam Zheng <famz@redhat.com>
>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>> ---
>>>>   block.c               |  20 ++++++++++
>>>>   block/mirror.c        |  10 +----
>>>>   blockdev.c            | 100
>>>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>   include/block/block.h |   1 +
>>>>   qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>>>>   qmp-commands.hx       |  51 +++++++++++++++++++++++++
>>>>   6 files changed, 228 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/block.c b/block.c
>>>> index bfeae6b..3eb77ee 100644
>>>> --- a/block.c
>>>> +++ b/block.c
>>>> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs,
>>>> BdrvDirtyBitmap *bitmap, int64_t sector
>>>>       }
>>>>   }
>>>> +/**
>>>> + * Chooses a default granularity based on the existing cluster size,
>>>> + * but clamped between [4K, 64K]. Defaults to 64K in the case that
>>>> there
>>>> + * is no cluster size information available.
>>>> + */
>>>> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
>>>> +{
>>>> +    BlockDriverInfo bdi;
>>>> +    uint64_t granularity;
>>>> +
>>>> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>> +        granularity = MAX(4096, bdi.cluster_size);
>>>> +        granularity = MIN(65536, granularity);
>>>> +    } else {
>>>> +        granularity = 65536;
>>>> +    }
>>>> +
>>>> +    return granularity;
>>>> +}
>>>> +
>>>>   void bdrv_dirty_iter_init(BlockDriverState *bs,
>>>>                             BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>>>>   {
>>>> diff --git a/block/mirror.c b/block/mirror.c
>>>> index d819952..fc545f1 100644
>>>> --- a/block/mirror.c
>>>> +++ b/block/mirror.c
>>>> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState
>>>> *bs, BlockDriverState *target,
>>>>       MirrorBlockJob *s;
>>>>       if (granularity == 0) {
>>>> -        /* Choose the default granularity based on the target file's
>>>> cluster
>>>> -         * size, clamped between 4k and 64k.  */
>>>> -        BlockDriverInfo bdi;
>>>> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size !=
>>>> 0) {
>>>> -            granularity = MAX(4096, bdi.cluster_size);
>>>> -            granularity = MIN(65536, granularity);
>>>> -        } else {
>>>> -            granularity = 65536;
>>>> -        }
>>>> +        granularity = bdrv_get_default_bitmap_granularity(target);
>>>>       }
>>>>       assert ((granularity & (granularity - 1)) == 0);
>>>> diff --git a/blockdev.c b/blockdev.c
>>>> index 5651a8e..95251c7 100644
>>>> --- a/blockdev.c
>>>> +++ b/blockdev.c
>>>> @@ -1173,6 +1173,48 @@ out_aio_context:
>>>>       return NULL;
>>>>   }
>>>> +/**
>>>> + * Return a dirty bitmap (if present), after validating
>>>> + * the node reference and bitmap names. Returns NULL on error,
>>>> + * including when the BDS and/or bitmap is not found.
>>>> + */
>>>> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char
>>>> *node_ref,
>>>> +                                                  const char *name,
>>>> + BlockDriverState
>>>> **pbs,
>>>> +                                                  Error **errp)
>>>> +{
>>>> +    BlockDriverState *bs;
>>>> +    BdrvDirtyBitmap *bitmap;
>>>> +
>>>> +    if (!node_ref) {
>>>> +        error_setg(errp, "Node reference cannot be NULL");
>>>> +        return NULL;
>>>> +    }
>>>> +    if (!name) {
>>>> +        error_setg(errp, "Bitmap name cannot be NULL");
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
>>>> +    if (!bs) {
>>>> +        error_setg(errp, "Node reference '%s' not found", node_ref);
>>>
>>> No need to throw the (hopefully) perfectly fine Error code returned by
>>> bdrv_lookup_bs() away.
>>>
>>
>> I just wanted an error message consistent with the parameter name, in
>> this case. i.e., We couldn't find the "Node reference" instead of
>> "device" or "node name." Just trying to distinguish the fact that this
>> is an arbitrary reference in the error message.
>>
>> I can still remove it, but I am curious to see what Markus thinks of
>> the names I have chosen before I monkey with the errors too much more.
>
> Very well then, but you should clean up the error returned by
> bdrv_lookup_bs() (call error_free()).
>
> Feel free to keep my R-b whichever decision you'll make (as long as the
> error returned by bdrv_lookup_bs() is not leaked).
>
> Max
>

Or a new helper designed specifically for single argument "BB -or- BDS" 
lookups, too, that uses the name of the parameter that we eventually 
decide upon.

I'll clean up the leak for now.

Thanks!

>>
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    /* If caller provided a BDS*, provide the result of that lookup,
>>>> too. */
>>>> +    if (pbs) {
>>>> +        *pbs = bs;
>>>> +    }
>>>> +
>>>> +    bitmap = bdrv_find_dirty_bitmap(bs, name);
>>>> +    if (!bitmap) {
>>>> +        error_setg(errp, "Dirty bitmap not found: %s", name);
>>>
>>> I'd use "Dirty bitmap '%s' not found", because "foo: bar" in an error
>>> message looks like "foo because bar" to me. But it's up to you, dirty
>>> bitmap names most likely don't look like error reasons so nobody should
>>> be able to confuse it.
>>>
>>
>> No, I agree.
>>
>>> So with the error_setg() in the fail path for bdrv_lookup_bs() removed:
>>>
>>> Reviewed-by: Max Reitz <mreitz@redhat.com>
>>>
>>
>

-- 
—js

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 07/13] qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable
  2015-01-16 16:28   ` Max Reitz
@ 2015-01-16 17:09     ` John Snow
  0 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-16 17:09 UTC (permalink / raw)
  To: Max Reitz, qemu-devel; +Cc: kwolf, vsementsov, famz, armbru, stefanha



On 01/16/2015 11:28 AM, Max Reitz wrote:
> On 2015-01-12 at 11:30, John Snow wrote:
>> From: Fam Zheng <famz@redhat.com>
>>
>> This allows to put the dirty bitmap into a disabled state where no more
>> writes will be tracked.
>>
>> It will be used before backup or writing to persistent file.
>>
>> Signed-off-by: Fam Zheng <famz@redhat.com>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   block.c               | 24 +++++++++++++++++++++++-
>>   blockdev.c            | 40 ++++++++++++++++++++++++++++++++++++++++
>>   include/block/block.h |  3 +++
>>   qapi/block-core.json  | 28 ++++++++++++++++++++++++++++
>>   qmp-commands.hx       | 10 ++++++++++
>>   5 files changed, 104 insertions(+), 1 deletion(-)
>>
>> diff --git a/block.c b/block.c
>> index 7bf7079..bd4b449 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -56,6 +56,7 @@ struct BdrvDirtyBitmap {
>>       int64_t size;
>>       int64_t granularity;
>>       char *name;
>> +    bool enabled;
>>       QLIST_ENTRY(BdrvDirtyBitmap) list;
>>   };
>> @@ -5373,10 +5374,16 @@ BdrvDirtyBitmap
>> *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>>       bitmap->granularity = granularity;
>>       bitmap->bitmap = hbitmap_alloc(bitmap->size,
>> ffs(sector_granularity) - 1);
>>       bitmap->name = g_strdup(name);
>> +    bitmap->enabled = true;
>>       QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
>>       return bitmap;
>>   }
>> +bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
>> +{
>> +    return bitmap->enabled;
>> +}
>> +
>>   void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap
>> *bitmap)
>>   {
>>       BdrvDirtyBitmap *bm, *next;
>> @@ -5391,6 +5398,16 @@ void bdrv_release_dirty_bitmap(BlockDriverState
>> *bs, BdrvDirtyBitmap *bitmap)
>>       }
>>   }
>> +void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>> +{
>> +    bitmap->enabled = false;
>> +}
>> +
>> +void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>> +{
>> +    bitmap->enabled = true;
>> +}
>> +
>>   BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
>>   {
>>       BdrvDirtyBitmap *bm;
>> @@ -5458,7 +5475,9 @@ void bdrv_dirty_iter_init(BlockDriverState *bs,
>>   void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap
>> *bitmap,
>>                              int64_t cur_sector, int nr_sectors)
>>   {
>> -    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
>> +    if (bdrv_dirty_bitmap_enabled(bitmap)) {
>> +        hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
>> +    }
>
> Why are you checking whether the bitmap is enabled here in
> bdrv_set_dirty_bitmap(), but neither in bdrv_reset_dirty_bitmap() nor
> bdrv_clear_dirty_bitmap()?
>
> It seems consistent with the commit message which only states that
> disabled state means that no more writes (i.e. bdrv_set_dirty_bitmap())
> will be tracked, but it still seems strange to me.
>
>>   }
>>   void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap
>> *bitmap,
>> @@ -5481,6 +5500,9 @@ static void bdrv_set_dirty(BlockDriverState *bs,
>> int64_t cur_sector,
>>   {
>>       BdrvDirtyBitmap *bitmap;
>>       QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
>> +        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
>> +            continue;
>> +        }
>
> Same question as above, only this time it's about bdrv_reset_dirty().
>
> In case the answer to the question is "that's intentional":
>
> Reviewed-by: Max Reitz <mreitz@redhat.com>
>

Just because it's intentional doesn't make it a good idea.

Fam is currently suggesting we might just scrap the "enable/disable" and 
"frozen/normal" modes altogether in favor of a single unified status, 
but the original way he proposed enabled/disabled is that it simply, and 
exclusively enabled/disabled new writes to the bitmap -- it never was 
intended to block clears/resets.

So the bitmap is still able to be consumed while disabled, for instance.

How useful is this? Perhaps not very useful. Probably more confusing 
than useful.

I will *probably* try to unify these parameters as Fam suggested, but I 
am really eager to hear from Markus on the QMP interface side before I 
bother sending out another minor iteration.

I'll skip the R-b for now, since Fam had some ideas on how to make it nicer.

Thanks!
--js

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup John Snow
  2015-01-13  9:37   ` Fam Zheng
@ 2015-01-16 17:52   ` Max Reitz
  2015-01-16 17:59     ` John Snow
  1 sibling, 1 reply; 54+ messages in thread
From: Max Reitz @ 2015-01-16 17:52 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, vsementsov, stefanha

On 2015-01-12 at 11:31, John Snow wrote:
> For "dirty-bitmap" sync mode, the block job will iterate through the
> given dirty bitmap to decide if a sector needs backup (backup all the
> dirty clusters and skip clean ones), just as allocation conditions of
> "top" sync mode.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   block.c                   |   5 ++
>   block/backup.c            | 120 ++++++++++++++++++++++++++++++++++++++--------
>   block/mirror.c            |   4 ++
>   blockdev.c                |  14 +++++-
>   hmp.c                     |   3 +-
>   include/block/block.h     |   1 +
>   include/block/block_int.h |   2 +
>   qapi/block-core.json      |  11 +++--
>   qmp-commands.hx           |   7 +--
>   9 files changed, 137 insertions(+), 30 deletions(-)

Since you seem to be intending to rethink the "frozen" state, I'm just 
scanning through the series from patch 8 on.

While this patch doesn't seem to have changed much conceptually since 
the last version I reviewed, with it applied to master, qemu fails to 
build due to Fam's blockdev-backup series (some new calls to 
backup_start() which have to be adapted).

Max

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup
  2015-01-16 17:52   ` Max Reitz
@ 2015-01-16 17:59     ` John Snow
  0 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-16 17:59 UTC (permalink / raw)
  To: Max Reitz, qemu-devel; +Cc: kwolf, famz, armbru, vsementsov, stefanha



On 01/16/2015 12:52 PM, Max Reitz wrote:
> On 2015-01-12 at 11:31, John Snow wrote:
>> For "dirty-bitmap" sync mode, the block job will iterate through the
>> given dirty bitmap to decide if a sector needs backup (backup all the
>> dirty clusters and skip clean ones), just as allocation conditions of
>> "top" sync mode.
>>
>> Signed-off-by: Fam Zheng <famz@redhat.com>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   block.c                   |   5 ++
>>   block/backup.c            | 120
>> ++++++++++++++++++++++++++++++++++++++--------
>>   block/mirror.c            |   4 ++
>>   blockdev.c                |  14 +++++-
>>   hmp.c                     |   3 +-
>>   include/block/block.h     |   1 +
>>   include/block/block_int.h |   2 +
>>   qapi/block-core.json      |  11 +++--
>>   qmp-commands.hx           |   7 +--
>>   9 files changed, 137 insertions(+), 30 deletions(-)
>
> Since you seem to be intending to rethink the "frozen" state, I'm just
> scanning through the series from patch 8 on.
>
> While this patch doesn't seem to have changed much conceptually since
> the last version I reviewed, with it applied to master, qemu fails to
> build due to Fam's blockdev-backup series (some new calls to
> backup_start() which have to be adapted).
>
> Max

Understood. "Frozen" will still exist largely similar to what it doe s 
now, but the proposal from fam was to simply fold "enabled/disabled" 
into the same status, and perhaps differentiate between a simple 
"disabled" state and a "frozen" state by the presence or absence of a 
successor.

As for the rebase onto master, here's a v11.5:
https://github.com/jnsnow/qemu/commits/dbm-backup

-- 
—js

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors
  2015-01-13  9:24   ` Fam Zheng
  2015-01-13 17:26     ` John Snow
@ 2015-01-16 18:22     ` John Snow
  2015-01-19  1:00       ` Fam Zheng
  1 sibling, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-16 18:22 UTC (permalink / raw)
  To: Fam Zheng
  Cc: kwolf, qemu-devel, armbru, mreitz, vsementsov, stefanha, pbonzini



On 01/13/2015 04:24 AM, Fam Zheng wrote:
> On Mon, 01/12 11:31, John Snow wrote:
>> A bitmap successor is an anonymous BdrvDirtyBitmap that is intended to
>> be created just prior to a sensitive operation (e.g. Incremental Backup)
>> that can either succeed or fail, but during the course of which we still
>> want a bitmap tracking writes.
>>
>> On creating a successor, we "freeze" the parent bitmap which prevents
>> its deletion, enabling, anonymization, or creating a bitmap with the
>> same name.
>>
>> On success, the parent bitmap can "abdicate" responsibility to the
>> successor, which will inherit its name. The successor will have been
>> tracking writes during the course of the backup operation. The parent
>> will be safely deleted.
>>
>> On failure, we can "reclaim" the successor from the parent, unifying
>> them such that the resulting bitmap describes all writes occurring since
>> the last successful backup, for instance. Reclamation will thaw the
>> parent, but not explicitly re-enable it.
>
> If we compare this with image snapshot and overlay, it fits the current backing
> chain model very well.  Given that we're on the way to persistent dirty bitmap,
> which will probably be read/written with general block.c code, I'm wondering if
> it will be any better to reuse the block layer backing file code to handle
> "successor" logic?
>
> Also with the frozen feature built in dirty bitmaps, is it okay to drop
> "enabled" state?
>
> I think there are three states for a bitmap:
>
> 1) Active, no successor (similar to an read-write top image)
> 2) Frozen, no successor (similar to an read-only top image)
> 3) Frozen, with successor (similar to an read-only backing file, with an
>     overlap)
>
> Admittedly, more code is needed than this patch, in order to glue hbitmap and
> block layer together, but it would probably make live migration of dirty bitmap
> very easy, but I'm not sure without a closer look.
>
>>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   block.c               | 123 ++++++++++++++++++++++++++++++++++++++++++++++++--
>>   blockdev.c            |  14 ++++++
>>   include/block/block.h |  10 ++++
>>   3 files changed, 144 insertions(+), 3 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index bd4b449..3f33b9d 100644
>> --- a/block.c
>> +++ b/block.c
>> @@ -53,10 +53,12 @@
>>
>>   struct BdrvDirtyBitmap {
>>       HBitmap *bitmap;
>> +    BdrvDirtyBitmap *successor;
>>       int64_t size;
>>       int64_t granularity;
>>       char *name;
>>       bool enabled;
>> +    bool frozen;
>>       QLIST_ENTRY(BdrvDirtyBitmap) list;
>>   };
>>
>> @@ -5342,6 +5344,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
>>
>>   void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>>   {
>> +    assert(!bitmap->frozen);
>>       g_free(bitmap->name);
>>       bitmap->name = NULL;
>>   }
>> @@ -5379,9 +5382,114 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>>       return bitmap;
>>   }
>>
>> +/**
>> +  * A frozen bitmap cannot be renamed, deleted, cleared,
>> +  * or set. A frozen bitmap can only abdicate, reclaim,
>> +  * or thaw.
>> +  */
>> +static void bdrv_freeze_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>> +{
>> +    bitmap->frozen = true;
>> +}
>> +
>> +static void bdrv_thaw_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>> +{
>> +    bitmap->frozen = false;
>> +}
>> +
>> +bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
>> +{
>> +    return bitmap->frozen;
>> +}
>> +
>>   bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
>>   {
>> -    return bitmap->enabled;
>> +    return bitmap->enabled && !bitmap->frozen;
>
> An indication that "enabled" could be replaced by "frozen". Otherwise it looks
> confusing to me.
>
>> +}
>> +
>> +/**
>> + * Create a successor bitmap destined to replace this bitmap after an operation.
>> + * Requires that the bitmap is not frozen and has no successor.
>> + */
>> +int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>> +                                       BdrvDirtyBitmap *bitmap, Error **errp)
>> +{
>> +    uint64_t granularity;
>> +
>> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
>> +        error_setg(errp,
>> +                   "Cannot create a successor for a bitmap currently in-use.");
>> +        return -1;
>> +    } else if (bitmap->successor) {
>> +        error_setg(errp, "Cannot create a successor for a bitmap that "
>> +                   "already has one.");
>> +        return -1;
>> +    }
>> +
>> +    /* Create an anonymous successor */
>> +    granularity = bdrv_dirty_bitmap_granularity(bs, bitmap);
>> +    bitmap->successor = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
>> +    if (!bitmap->successor) {
>> +        return -1;
>> +    }
>> +
>> +    /* Successor will be on or off based on our current state.
>> +     * Parent will be disabled and frozen. */
>> +    bitmap->successor->enabled = bitmap->enabled;
>> +    bdrv_disable_dirty_bitmap(bitmap);
>> +    bdrv_freeze_dirty_bitmap(bitmap);
>> +    return 0;
>> +}
>> +
>> +/**
>> + * For a bitmap with a successor, yield our name to the successor,
>> + * Delete the old bitmap, and return a handle to the new bitmap.
>> + */
>> +BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
>> +                                            BdrvDirtyBitmap *bitmap,
>> +                                            Error **errp)
>> +{
>> +    char *name;
>> +    BdrvDirtyBitmap *successor = bitmap->successor;
>> +
>> +    if (successor == NULL) {
>> +        error_setg(errp, "Cannot relinquish control if "
>> +                   "there's no successor present.\n");
>> +        return NULL;
>> +    }
>> +
>> +    name = bitmap->name;
>> +    bitmap->name = NULL;
>> +    successor->name = name;
>> +
>> +    bdrv_thaw_dirty_bitmap(bitmap);
>> +    bdrv_release_dirty_bitmap(bs, bitmap);
>> +
>> +    return successor;
>> +}
>> +
>> +/**
>> + * In cases of failure where we can no longer safely delete the parent,
>> + * We may wish to re-join the parent and child/successor.
>> + * The merged parent will be un-frozen, but not explicitly re-enabled.
>> + */
>> +BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
>> +                                           BdrvDirtyBitmap *parent,
>> +                                           Error **errp)
>> +{
>> +    BdrvDirtyBitmap *successor = parent->successor;
>> +    if (!successor) {
>> +        error_setg(errp, "Cannot reclaim a successor when none is present.\n");
>> +        return NULL;
>> +    }
>> +
>> +    hbitmap_merge(parent->bitmap, successor->bitmap);
>> +    bdrv_release_dirty_bitmap(bs, successor);
>> +
>> +    bdrv_thaw_dirty_bitmap(parent);
>> +    parent->successor = NULL;
>> +
>> +    return parent;
>>   }
>>
>>   void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>> @@ -5389,6 +5497,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>>       BdrvDirtyBitmap *bm, *next;
>>       QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
>>           if (bm == bitmap) {
>> +            assert(!bm->frozen);
>>               QLIST_REMOVE(bitmap, list);
>>               hbitmap_free(bitmap->bitmap);
>>               g_free(bitmap->name);
>> @@ -5405,6 +5514,7 @@ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>>
>>   void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>>   {
>> +    assert(!bitmap->frozen);
>>       bitmap->enabled = true;
>>   }
>>
>> @@ -5483,7 +5593,9 @@ void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>   void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>                                int64_t cur_sector, int nr_sectors)
>>   {
>> -    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
>> +    if (!bitmap->frozen) {
>
> Probably just assert it's not frozen?
>
>> +        hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
>> +    }
>>   }
>>
>>   /**
>> @@ -5492,7 +5604,9 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>    */
>>   void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
>>   {
>> -    hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
>> +    if (!bitmap->frozen) {
>> +        hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
>
> The same: probably just assert it's not frozen?
>

Looking at this again, I see what I was trying to accomplish. Similar to 
how (!enabled) will silently ignore writes, I just wanted frozen bitmaps 
to silently ignore attempts to clear or reset bits, not assert or error out.

Just in case, in some future state, there is a more generic "set/clear 
bits" mechanism that may blindly try to clear bits to all attached 
bitmaps of a particular BDS, I didn't want to throw an error in that 
case -- just ignore it.

It would be a logical error to try to clear a bitmap we KNOW is frozen, 
but there may be cases where clears and resets may be done with less 
discrimination.

I think I will leave this as-is, but I can write some extra commentary 
for it. Is that OK?

--JS

>> +    }
>>   }
>>
>>   static void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
>> @@ -5512,6 +5626,9 @@ static void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
>>   {
>>       BdrvDirtyBitmap *bitmap;
>>       QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
>> +        if (bitmap->frozen) {
>> +            continue;
>> +        }
>>           hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
>>       }
>>   }
>> diff --git a/blockdev.c b/blockdev.c
>> index 118cb6c..8dde72a 100644
>> --- a/blockdev.c
>> +++ b/blockdev.c
>> @@ -1988,9 +1988,16 @@ void qmp_block_dirty_bitmap_remove(const char *node_ref, const char *name,
>>       aio_context = bdrv_get_aio_context(bs);
>>       aio_context_acquire(aio_context);
>>
>> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
>> +        error_setg(errp,
>> +                   "Bitmap %s is currently frozen and cannot be removed yet.\n",
>> +                   name);
>> +        goto out;
>> +    }
>>       bdrv_dirty_bitmap_make_anon(bs, bitmap);
>>       bdrv_release_dirty_bitmap(bs, bitmap);
>>
>> + out:
>>       aio_context_release(aio_context);
>>   }
>>
>> @@ -2009,8 +2016,15 @@ void qmp_block_dirty_bitmap_enable(const char *node_ref, const char *name,
>>       aio_context = bdrv_get_aio_context(bs);
>>       aio_context_acquire(aio_context);
>>
>> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
>> +        error_setg(errp, "Bitmap %s is frozen and cannot be enabled yet.\n",
>> +                   name);
>> +        goto out;
>> +    }
>> +
>>       bdrv_enable_dirty_bitmap(bitmap);
>>
>> + out:
>>       aio_context_release(aio_context);
>>   }
>>
>> diff --git a/include/block/block.h b/include/block/block.h
>> index a5bc249..6138544 100644
>> --- a/include/block/block.h
>> +++ b/include/block/block.h
>> @@ -433,6 +433,15 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>>                                             int granularity,
>>                                             const char *name,
>>                                             Error **errp);
>> +int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>> +                                       BdrvDirtyBitmap *bitmap,
>> +                                       Error **errp);
>> +BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
>> +                                            BdrvDirtyBitmap *bitmap,
>> +                                            Error **errp);
>> +BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
>> +                                           BdrvDirtyBitmap *bitmap,
>> +                                           Error **errp);
>>   BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
>>                                           const char *name);
>>   void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>> @@ -444,6 +453,7 @@ uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
>>   uint64_t bdrv_dirty_bitmap_granularity(BlockDriverState *bs,
>>                                         BdrvDirtyBitmap *bitmap);
>>   bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
>> +bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
>>   int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
>>   void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>>                              int64_t cur_sector, int nr_sectors);
>> --
>> 1.9.3
>>
>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors
  2015-01-16 18:22     ` John Snow
@ 2015-01-19  1:00       ` Fam Zheng
  0 siblings, 0 replies; 54+ messages in thread
From: Fam Zheng @ 2015-01-19  1:00 UTC (permalink / raw)
  To: John Snow
  Cc: kwolf, armbru, qemu-devel, mreitz, vsementsov, stefanha, pbonzini

On Fri, 01/16 13:22, John Snow wrote:
> 
> 
> On 01/13/2015 04:24 AM, Fam Zheng wrote:
> >On Mon, 01/12 11:31, John Snow wrote:
> >>A bitmap successor is an anonymous BdrvDirtyBitmap that is intended to
> >>be created just prior to a sensitive operation (e.g. Incremental Backup)
> >>that can either succeed or fail, but during the course of which we still
> >>want a bitmap tracking writes.
> >>
> >>On creating a successor, we "freeze" the parent bitmap which prevents
> >>its deletion, enabling, anonymization, or creating a bitmap with the
> >>same name.
> >>
> >>On success, the parent bitmap can "abdicate" responsibility to the
> >>successor, which will inherit its name. The successor will have been
> >>tracking writes during the course of the backup operation. The parent
> >>will be safely deleted.
> >>
> >>On failure, we can "reclaim" the successor from the parent, unifying
> >>them such that the resulting bitmap describes all writes occurring since
> >>the last successful backup, for instance. Reclamation will thaw the
> >>parent, but not explicitly re-enable it.
> >
> >If we compare this with image snapshot and overlay, it fits the current backing
> >chain model very well.  Given that we're on the way to persistent dirty bitmap,
> >which will probably be read/written with general block.c code, I'm wondering if
> >it will be any better to reuse the block layer backing file code to handle
> >"successor" logic?
> >
> >Also with the frozen feature built in dirty bitmaps, is it okay to drop
> >"enabled" state?
> >
> >I think there are three states for a bitmap:
> >
> >1) Active, no successor (similar to an read-write top image)
> >2) Frozen, no successor (similar to an read-only top image)
> >3) Frozen, with successor (similar to an read-only backing file, with an
> >    overlap)
> >
> >Admittedly, more code is needed than this patch, in order to glue hbitmap and
> >block layer together, but it would probably make live migration of dirty bitmap
> >very easy, but I'm not sure without a closer look.
> >
> >>
> >>Signed-off-by: John Snow <jsnow@redhat.com>
> >>---
> >>  block.c               | 123 ++++++++++++++++++++++++++++++++++++++++++++++++--
> >>  blockdev.c            |  14 ++++++
> >>  include/block/block.h |  10 ++++
> >>  3 files changed, 144 insertions(+), 3 deletions(-)
> >>
> >>diff --git a/block.c b/block.c
> >>index bd4b449..3f33b9d 100644
> >>--- a/block.c
> >>+++ b/block.c
> >>@@ -53,10 +53,12 @@
> >>
> >>  struct BdrvDirtyBitmap {
> >>      HBitmap *bitmap;
> >>+    BdrvDirtyBitmap *successor;
> >>      int64_t size;
> >>      int64_t granularity;
> >>      char *name;
> >>      bool enabled;
> >>+    bool frozen;
> >>      QLIST_ENTRY(BdrvDirtyBitmap) list;
> >>  };
> >>
> >>@@ -5342,6 +5344,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
> >>
> >>  void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
> >>  {
> >>+    assert(!bitmap->frozen);
> >>      g_free(bitmap->name);
> >>      bitmap->name = NULL;
> >>  }
> >>@@ -5379,9 +5382,114 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
> >>      return bitmap;
> >>  }
> >>
> >>+/**
> >>+  * A frozen bitmap cannot be renamed, deleted, cleared,
> >>+  * or set. A frozen bitmap can only abdicate, reclaim,
> >>+  * or thaw.
> >>+  */
> >>+static void bdrv_freeze_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> >>+{
> >>+    bitmap->frozen = true;
> >>+}
> >>+
> >>+static void bdrv_thaw_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> >>+{
> >>+    bitmap->frozen = false;
> >>+}
> >>+
> >>+bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
> >>+{
> >>+    return bitmap->frozen;
> >>+}
> >>+
> >>  bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
> >>  {
> >>-    return bitmap->enabled;
> >>+    return bitmap->enabled && !bitmap->frozen;
> >
> >An indication that "enabled" could be replaced by "frozen". Otherwise it looks
> >confusing to me.
> >
> >>+}
> >>+
> >>+/**
> >>+ * Create a successor bitmap destined to replace this bitmap after an operation.
> >>+ * Requires that the bitmap is not frozen and has no successor.
> >>+ */
> >>+int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
> >>+                                       BdrvDirtyBitmap *bitmap, Error **errp)
> >>+{
> >>+    uint64_t granularity;
> >>+
> >>+    if (bdrv_dirty_bitmap_frozen(bitmap)) {
> >>+        error_setg(errp,
> >>+                   "Cannot create a successor for a bitmap currently in-use.");
> >>+        return -1;
> >>+    } else if (bitmap->successor) {
> >>+        error_setg(errp, "Cannot create a successor for a bitmap that "
> >>+                   "already has one.");
> >>+        return -1;
> >>+    }
> >>+
> >>+    /* Create an anonymous successor */
> >>+    granularity = bdrv_dirty_bitmap_granularity(bs, bitmap);
> >>+    bitmap->successor = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
> >>+    if (!bitmap->successor) {
> >>+        return -1;
> >>+    }
> >>+
> >>+    /* Successor will be on or off based on our current state.
> >>+     * Parent will be disabled and frozen. */
> >>+    bitmap->successor->enabled = bitmap->enabled;
> >>+    bdrv_disable_dirty_bitmap(bitmap);
> >>+    bdrv_freeze_dirty_bitmap(bitmap);
> >>+    return 0;
> >>+}
> >>+
> >>+/**
> >>+ * For a bitmap with a successor, yield our name to the successor,
> >>+ * Delete the old bitmap, and return a handle to the new bitmap.
> >>+ */
> >>+BdrvDirtyBitmap *bdrv_dirty_bitmap_abdicate(BlockDriverState *bs,
> >>+                                            BdrvDirtyBitmap *bitmap,
> >>+                                            Error **errp)
> >>+{
> >>+    char *name;
> >>+    BdrvDirtyBitmap *successor = bitmap->successor;
> >>+
> >>+    if (successor == NULL) {
> >>+        error_setg(errp, "Cannot relinquish control if "
> >>+                   "there's no successor present.\n");
> >>+        return NULL;
> >>+    }
> >>+
> >>+    name = bitmap->name;
> >>+    bitmap->name = NULL;
> >>+    successor->name = name;
> >>+
> >>+    bdrv_thaw_dirty_bitmap(bitmap);
> >>+    bdrv_release_dirty_bitmap(bs, bitmap);
> >>+
> >>+    return successor;
> >>+}
> >>+
> >>+/**
> >>+ * In cases of failure where we can no longer safely delete the parent,
> >>+ * We may wish to re-join the parent and child/successor.
> >>+ * The merged parent will be un-frozen, but not explicitly re-enabled.
> >>+ */
> >>+BdrvDirtyBitmap *bdrv_reclaim_dirty_bitmap(BlockDriverState *bs,
> >>+                                           BdrvDirtyBitmap *parent,
> >>+                                           Error **errp)
> >>+{
> >>+    BdrvDirtyBitmap *successor = parent->successor;
> >>+    if (!successor) {
> >>+        error_setg(errp, "Cannot reclaim a successor when none is present.\n");
> >>+        return NULL;
> >>+    }
> >>+
> >>+    hbitmap_merge(parent->bitmap, successor->bitmap);
> >>+    bdrv_release_dirty_bitmap(bs, successor);
> >>+
> >>+    bdrv_thaw_dirty_bitmap(parent);
> >>+    parent->successor = NULL;
> >>+
> >>+    return parent;
> >>  }
> >>
> >>  void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
> >>@@ -5389,6 +5497,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
> >>      BdrvDirtyBitmap *bm, *next;
> >>      QLIST_FOREACH_SAFE(bm, &bs->dirty_bitmaps, list, next) {
> >>          if (bm == bitmap) {
> >>+            assert(!bm->frozen);
> >>              QLIST_REMOVE(bitmap, list);
> >>              hbitmap_free(bitmap->bitmap);
> >>              g_free(bitmap->name);
> >>@@ -5405,6 +5514,7 @@ void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> >>
> >>  void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> >>  {
> >>+    assert(!bitmap->frozen);
> >>      bitmap->enabled = true;
> >>  }
> >>
> >>@@ -5483,7 +5593,9 @@ void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
> >>  void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
> >>                               int64_t cur_sector, int nr_sectors)
> >>  {
> >>-    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
> >>+    if (!bitmap->frozen) {
> >
> >Probably just assert it's not frozen?
> >
> >>+        hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
> >>+    }
> >>  }
> >>
> >>  /**
> >>@@ -5492,7 +5604,9 @@ void bdrv_reset_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
> >>   */
> >>  void bdrv_clear_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
> >>  {
> >>-    hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
> >>+    if (!bitmap->frozen) {
> >>+        hbitmap_reset(bitmap->bitmap, 0, bitmap->size);
> >
> >The same: probably just assert it's not frozen?
> >
> 
> Looking at this again, I see what I was trying to accomplish. Similar to how
> (!enabled) will silently ignore writes, I just wanted frozen bitmaps to
> silently ignore attempts to clear or reset bits, not assert or error out.
> 
> Just in case, in some future state, there is a more generic "set/clear bits"
> mechanism that may blindly try to clear bits to all attached bitmaps of a
> particular BDS, I didn't want to throw an error in that case -- just ignore
> it.
> 
> It would be a logical error to try to clear a bitmap we KNOW is frozen, but
> there may be cases where clears and resets may be done with less
> discrimination.
> 
> I think I will leave this as-is, but I can write some extra commentary for
> it. Is that OK?
> 
> --JS

OK.

I thought "better be safe than be sorry" when suggesting the stricter and more
explicit calling contract, but since this is not wrong, it's your decision.

Fam

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-16 16:48     ` John Snow
  2015-01-16 16:51       ` Max Reitz
@ 2015-01-19 10:08       ` Markus Armbruster
  2015-01-19 21:05         ` John Snow
  1 sibling, 1 reply; 54+ messages in thread
From: Markus Armbruster @ 2015-01-19 10:08 UTC (permalink / raw)
  To: John Snow; +Cc: kwolf, famz, qemu-devel, Max Reitz, vsementsov, stefanha

John Snow <jsnow@redhat.com> writes:

> On 01/16/2015 10:36 AM, Max Reitz wrote:
>> On 2015-01-12 at 11:30, John Snow wrote:
>>> From: Fam Zheng <famz@redhat.com>
>>>
>>> The new command pair is added to manage user created dirty bitmap. The
>>> dirty bitmap's name is mandatory and must be unique for the same device,
>>> but different devices can have bitmaps with the same names.
>>>
>>> The granularity is an optional field. If it is not specified, we will
>>> choose a default granularity based on the cluster size if available,
>>> clamped to between 4K and 64K to mirror how the 'mirror' code was
>>> already choosing granularity. If we do not have cluster size info
>>> available, we choose 64K. This code has been factored out into a helper
>>> shared with block/mirror.
>>>
>>> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
>>> which takes a device name and a dirty bitmap name and validates the
>>> lookup, returning NULL and setting errp if there is a problem with
>>> either field. This helper will be re-used in future patches in this
>>> series.
>>>
>>> The types added to block-core.json will be re-used in future patches
>>> in this series, see:
>>> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>>> disable}'
>>>
>>> Signed-off-by: Fam Zheng <famz@redhat.com>
>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>> ---
>>>   block.c               |  20 ++++++++++
>>>   block/mirror.c        |  10 +----
>>>   blockdev.c            | 100
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   include/block/block.h |   1 +
>>>   qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>>>   qmp-commands.hx       |  51 +++++++++++++++++++++++++
>>>   6 files changed, 228 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/block.c b/block.c
>>> index bfeae6b..3eb77ee 100644
>>> --- a/block.c
>>> +++ b/block.c
>>> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs,
>>> BdrvDirtyBitmap *bitmap, int64_t sector
>>>       }
>>>   }
>>> +/**
>>> + * Chooses a default granularity based on the existing cluster size,
>>> + * but clamped between [4K, 64K]. Defaults to 64K in the case that there
>>> + * is no cluster size information available.
>>> + */
>>> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
>>> +{
>>> +    BlockDriverInfo bdi;
>>> +    uint64_t granularity;
>>> +
>>> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
>>> +        granularity = MAX(4096, bdi.cluster_size);
>>> +        granularity = MIN(65536, granularity);
>>> +    } else {
>>> +        granularity = 65536;
>>> +    }
>>> +
>>> +    return granularity;
>>> +}
>>> +
>>>   void bdrv_dirty_iter_init(BlockDriverState *bs,
>>>                             BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>>>   {
>>> diff --git a/block/mirror.c b/block/mirror.c
>>> index d819952..fc545f1 100644
>>> --- a/block/mirror.c
>>> +++ b/block/mirror.c
>>> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState
>>> *bs, BlockDriverState *target,
>>>       MirrorBlockJob *s;
>>>       if (granularity == 0) {
>>> -        /* Choose the default granularity based on the target file's
>>> cluster
>>> -         * size, clamped between 4k and 64k.  */
>>> -        BlockDriverInfo bdi;
>>> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
>>> -            granularity = MAX(4096, bdi.cluster_size);
>>> -            granularity = MIN(65536, granularity);
>>> -        } else {
>>> -            granularity = 65536;
>>> -        }
>>> +        granularity = bdrv_get_default_bitmap_granularity(target);
>>>       }
>>>       assert ((granularity & (granularity - 1)) == 0);
>>> diff --git a/blockdev.c b/blockdev.c
>>> index 5651a8e..95251c7 100644
>>> --- a/blockdev.c
>>> +++ b/blockdev.c
>>> @@ -1173,6 +1173,48 @@ out_aio_context:
>>>       return NULL;
>>>   }
>>> +/**
>>> + * Return a dirty bitmap (if present), after validating
>>> + * the node reference and bitmap names. Returns NULL on error,
>>> + * including when the BDS and/or bitmap is not found.
>>> + */
>>> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
>>> +                                                  const char *name,
>>> +                                                  BlockDriverState
>>> **pbs,
>>> +                                                  Error **errp)
>>> +{
>>> +    BlockDriverState *bs;
>>> +    BdrvDirtyBitmap *bitmap;
>>> +
>>> +    if (!node_ref) {
>>> +        error_setg(errp, "Node reference cannot be NULL");
>>> +        return NULL;
>>> +    }
>>> +    if (!name) {
>>> +        error_setg(errp, "Bitmap name cannot be NULL");
>>> +        return NULL;
>>> +    }
>>> +
>>> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
>>> +    if (!bs) {
>>> +        error_setg(errp, "Node reference '%s' not found", node_ref);
>>
>> No need to throw the (hopefully) perfectly fine Error code returned by
>> bdrv_lookup_bs() away.
>>
>
> I just wanted an error message consistent with the parameter name, in
> this case. i.e., We couldn't find the "Node reference" instead of
> "device" or "node name." Just trying to distinguish the fact that this
> is an arbitrary reference in the error message.
>
> I can still remove it, but I am curious to see what Markus thinks of
> the names I have chosen before I monkey with the errors too much more.

bdrv_lookup_bs() is an awkward interface.

If @device is non-null, try to look up a backend (BB) named @device.  If
it exists, return the backend's root node (BDS).

Else if @node_name is non-null, try to look up a node (BDS) named
@node_name.  If it exists, return it.

Else, set this error:

    error_setg(errp, "Cannot find device=%s nor node_name=%s",
                     device ? device : "",
                     node_name ? node_name : "");

The error message is crap unless both device and node_name are non-null
and different.  Which is never the case: we always either pass two
identical non-null arguments, or we pass a null and a non-null
argument[*].  In other words, the error message is always crap.

In case you wonder why @device takes precedence over node_name when both
are given: makes no sense.  But when both are given, they are always
identical, and since backend and node names share a name space, only one
can resolve.

A couple of cleaner solutions come to mind:

* Make bdrv_lookup_bs() suck less

  Assert its tacit preconditions:

    assert(device || node_name);
    assert(!device || !node_name || device == node_name);

  Then make it produce a decent error:

    if (device && node_name) {
        error_setg(errp, "Neither block backend nor node %s found", device);
    else if (device) {
        error_setg(errp, "Block backend %s not found", device);
    } else if (node_name) {
        error_setg(errp, "Block node %s not found", node_name);
    }

  Note how the three cases mirror the three usage patterns.

  Further note that the proposed error messages deviate from the
  existing practice of calling block backends "devices".  Calling
  everything and its dog a "device" is traditional, but it's also lazy
  and confusing.  End of digression.

* Make bdrv_lookup_bs suck less by doing less: leave error_setg() to its
  callers

  Drop the Error ** parameter.  Callers know whether a failed lookup was
  for a device name, a node name or both, and can set an appropriate
  error themselves.

  I'd still assert the preconditions.

* Replace the function by one for each of its usage patterns

  I think that's what I'd do.

[...]


[*] See
https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg01298.html

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-19 10:08       ` Markus Armbruster
@ 2015-01-19 21:05         ` John Snow
  2015-01-20  8:26           ` Markus Armbruster
  0 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-19 21:05 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: kwolf, famz, qemu-devel, Max Reitz, vsementsov, stefanha



On 01/19/2015 05:08 AM, Markus Armbruster wrote:
> John Snow <jsnow@redhat.com> writes:
>
>> On 01/16/2015 10:36 AM, Max Reitz wrote:
>>> On 2015-01-12 at 11:30, John Snow wrote:
>>>> From: Fam Zheng <famz@redhat.com>
>>>>
>>>> The new command pair is added to manage user created dirty bitmap. The
>>>> dirty bitmap's name is mandatory and must be unique for the same device,
>>>> but different devices can have bitmaps with the same names.
>>>>
>>>> The granularity is an optional field. If it is not specified, we will
>>>> choose a default granularity based on the cluster size if available,
>>>> clamped to between 4K and 64K to mirror how the 'mirror' code was
>>>> already choosing granularity. If we do not have cluster size info
>>>> available, we choose 64K. This code has been factored out into a helper
>>>> shared with block/mirror.
>>>>
>>>> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
>>>> which takes a device name and a dirty bitmap name and validates the
>>>> lookup, returning NULL and setting errp if there is a problem with
>>>> either field. This helper will be re-used in future patches in this
>>>> series.
>>>>
>>>> The types added to block-core.json will be re-used in future patches
>>>> in this series, see:
>>>> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>>>> disable}'
>>>>
>>>> Signed-off-by: Fam Zheng <famz@redhat.com>
>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>> ---
>>>>    block.c               |  20 ++++++++++
>>>>    block/mirror.c        |  10 +----
>>>>    blockdev.c            | 100
>>>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>    include/block/block.h |   1 +
>>>>    qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>>>>    qmp-commands.hx       |  51 +++++++++++++++++++++++++
>>>>    6 files changed, 228 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/block.c b/block.c
>>>> index bfeae6b..3eb77ee 100644
>>>> --- a/block.c
>>>> +++ b/block.c
>>>> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs,
>>>> BdrvDirtyBitmap *bitmap, int64_t sector
>>>>        }
>>>>    }
>>>> +/**
>>>> + * Chooses a default granularity based on the existing cluster size,
>>>> + * but clamped between [4K, 64K]. Defaults to 64K in the case that there
>>>> + * is no cluster size information available.
>>>> + */
>>>> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
>>>> +{
>>>> +    BlockDriverInfo bdi;
>>>> +    uint64_t granularity;
>>>> +
>>>> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>> +        granularity = MAX(4096, bdi.cluster_size);
>>>> +        granularity = MIN(65536, granularity);
>>>> +    } else {
>>>> +        granularity = 65536;
>>>> +    }
>>>> +
>>>> +    return granularity;
>>>> +}
>>>> +
>>>>    void bdrv_dirty_iter_init(BlockDriverState *bs,
>>>>                              BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>>>>    {
>>>> diff --git a/block/mirror.c b/block/mirror.c
>>>> index d819952..fc545f1 100644
>>>> --- a/block/mirror.c
>>>> +++ b/block/mirror.c
>>>> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState
>>>> *bs, BlockDriverState *target,
>>>>        MirrorBlockJob *s;
>>>>        if (granularity == 0) {
>>>> -        /* Choose the default granularity based on the target file's
>>>> cluster
>>>> -         * size, clamped between 4k and 64k.  */
>>>> -        BlockDriverInfo bdi;
>>>> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>> -            granularity = MAX(4096, bdi.cluster_size);
>>>> -            granularity = MIN(65536, granularity);
>>>> -        } else {
>>>> -            granularity = 65536;
>>>> -        }
>>>> +        granularity = bdrv_get_default_bitmap_granularity(target);
>>>>        }
>>>>        assert ((granularity & (granularity - 1)) == 0);
>>>> diff --git a/blockdev.c b/blockdev.c
>>>> index 5651a8e..95251c7 100644
>>>> --- a/blockdev.c
>>>> +++ b/blockdev.c
>>>> @@ -1173,6 +1173,48 @@ out_aio_context:
>>>>        return NULL;
>>>>    }
>>>> +/**
>>>> + * Return a dirty bitmap (if present), after validating
>>>> + * the node reference and bitmap names. Returns NULL on error,
>>>> + * including when the BDS and/or bitmap is not found.
>>>> + */
>>>> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
>>>> +                                                  const char *name,
>>>> +                                                  BlockDriverState
>>>> **pbs,
>>>> +                                                  Error **errp)
>>>> +{
>>>> +    BlockDriverState *bs;
>>>> +    BdrvDirtyBitmap *bitmap;
>>>> +
>>>> +    if (!node_ref) {
>>>> +        error_setg(errp, "Node reference cannot be NULL");
>>>> +        return NULL;
>>>> +    }
>>>> +    if (!name) {
>>>> +        error_setg(errp, "Bitmap name cannot be NULL");
>>>> +        return NULL;
>>>> +    }
>>>> +
>>>> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
>>>> +    if (!bs) {
>>>> +        error_setg(errp, "Node reference '%s' not found", node_ref);
>>>
>>> No need to throw the (hopefully) perfectly fine Error code returned by
>>> bdrv_lookup_bs() away.
>>>
>>
>> I just wanted an error message consistent with the parameter name, in
>> this case. i.e., We couldn't find the "Node reference" instead of
>> "device" or "node name." Just trying to distinguish the fact that this
>> is an arbitrary reference in the error message.
>>
>> I can still remove it, but I am curious to see what Markus thinks of
>> the names I have chosen before I monkey with the errors too much more.
>
> bdrv_lookup_bs() is an awkward interface.
>
> If @device is non-null, try to look up a backend (BB) named @device.  If
> it exists, return the backend's root node (BDS).
>
> Else if @node_name is non-null, try to look up a node (BDS) named
> @node_name.  If it exists, return it.
>
> Else, set this error:
>
>      error_setg(errp, "Cannot find device=%s nor node_name=%s",
>                       device ? device : "",
>                       node_name ? node_name : "");
>
> The error message is crap unless both device and node_name are non-null
> and different.  Which is never the case: we always either pass two
> identical non-null arguments, or we pass a null and a non-null
> argument[*].  In other words, the error message is always crap.
>
> In case you wonder why @device takes precedence over node_name when both
> are given: makes no sense.  But when both are given, they are always
> identical, and since backend and node names share a name space, only one
> can resolve.
>
> A couple of cleaner solutions come to mind:
>
> * Make bdrv_lookup_bs() suck less
>
>    Assert its tacit preconditions:
>
>      assert(device || node_name);
>      assert(!device || !node_name || device == node_name);
>
>    Then make it produce a decent error:
>
>      if (device && node_name) {
>          error_setg(errp, "Neither block backend nor node %s found", device);
>      else if (device) {
>          error_setg(errp, "Block backend %s not found", device);
>      } else if (node_name) {
>          error_setg(errp, "Block node %s not found", node_name);
>      }
>
>    Note how the three cases mirror the three usage patterns.
>
>    Further note that the proposed error messages deviate from the
>    existing practice of calling block backends "devices".  Calling
>    everything and its dog a "device" is traditional, but it's also lazy
>    and confusing.  End of digression.
>
> * Make bdrv_lookup_bs suck less by doing less: leave error_setg() to its
>    callers
>
>    Drop the Error ** parameter.  Callers know whether a failed lookup was
>    for a device name, a node name or both, and can set an appropriate
>    error themselves.
>
>    I'd still assert the preconditions.
>
> * Replace the function by one for each of its usage patterns
>
>    I think that's what I'd do.
>
> [...]
>
>
> [*] See
> https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg01298.html
>

I can submit a patch for making bdrv_lookup_bs "nicer," or at least its 
usage more clear, in a separate patch.

If you really want me to fold it into this series, I'd invite you to 
review explicitly my usage of the parameter "node-ref" before I embark 
on cleaning up other interface areas.

Does this naming scheme look sane to you, and fit with your general 
expectations?

I can also add a "bdrv_lookup_noderef" function that takes only one 
argument, which will help enforce the "If both arguments are provided, 
they must be the same" paradigm.

This patch (#3) covers my shot at a unified parameter, and you can see 
further consequences in #7, and #10 (transactions).

CC'ing Eric Blake, as well, for comments on a "unified parameter" 
interface in general.

Thanks,
--js

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-19 21:05         ` John Snow
@ 2015-01-20  8:26           ` Markus Armbruster
  2015-01-20 16:48             ` John Snow
  0 siblings, 1 reply; 54+ messages in thread
From: Markus Armbruster @ 2015-01-20  8:26 UTC (permalink / raw)
  To: John Snow; +Cc: kwolf, famz, qemu-devel, Max Reitz, vsementsov, stefanha

John Snow <jsnow@redhat.com> writes:

> On 01/19/2015 05:08 AM, Markus Armbruster wrote:
>> John Snow <jsnow@redhat.com> writes:
>>
>>> On 01/16/2015 10:36 AM, Max Reitz wrote:
>>>> On 2015-01-12 at 11:30, John Snow wrote:
>>>>> From: Fam Zheng <famz@redhat.com>
>>>>>
>>>>> The new command pair is added to manage user created dirty bitmap. The
>>>>> dirty bitmap's name is mandatory and must be unique for the same device,
>>>>> but different devices can have bitmaps with the same names.
>>>>>
>>>>> The granularity is an optional field. If it is not specified, we will
>>>>> choose a default granularity based on the cluster size if available,
>>>>> clamped to between 4K and 64K to mirror how the 'mirror' code was
>>>>> already choosing granularity. If we do not have cluster size info
>>>>> available, we choose 64K. This code has been factored out into a helper
>>>>> shared with block/mirror.
>>>>>
>>>>> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
>>>>> which takes a device name and a dirty bitmap name and validates the
>>>>> lookup, returning NULL and setting errp if there is a problem with
>>>>> either field. This helper will be re-used in future patches in this
>>>>> series.
>>>>>
>>>>> The types added to block-core.json will be re-used in future patches
>>>>> in this series, see:
>>>>> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>>>>> disable}'
>>>>>
>>>>> Signed-off-by: Fam Zheng <famz@redhat.com>
>>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>>> ---
>>>>>    block.c               |  20 ++++++++++
>>>>>    block/mirror.c        |  10 +----
>>>>>    blockdev.c            | 100
>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>    include/block/block.h |   1 +
>>>>>    qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>>>>>    qmp-commands.hx       |  51 +++++++++++++++++++++++++
>>>>>    6 files changed, 228 insertions(+), 9 deletions(-)
>>>>>
>>>>> diff --git a/block.c b/block.c
>>>>> index bfeae6b..3eb77ee 100644
>>>>> --- a/block.c
>>>>> +++ b/block.c
>>>>> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs,
>>>>> BdrvDirtyBitmap *bitmap, int64_t sector
>>>>>        }
>>>>>    }
>>>>> +/**
>>>>> + * Chooses a default granularity based on the existing cluster size,
>>>>> + * but clamped between [4K, 64K]. Defaults to 64K in the case that there
>>>>> + * is no cluster size information available.
>>>>> + */
>>>>> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
>>>>> +{
>>>>> +    BlockDriverInfo bdi;
>>>>> +    uint64_t granularity;
>>>>> +
>>>>> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>>> +        granularity = MAX(4096, bdi.cluster_size);
>>>>> +        granularity = MIN(65536, granularity);
>>>>> +    } else {
>>>>> +        granularity = 65536;
>>>>> +    }
>>>>> +
>>>>> +    return granularity;
>>>>> +}
>>>>> +
>>>>>    void bdrv_dirty_iter_init(BlockDriverState *bs,
>>>>>                              BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>>>>>    {
>>>>> diff --git a/block/mirror.c b/block/mirror.c
>>>>> index d819952..fc545f1 100644
>>>>> --- a/block/mirror.c
>>>>> +++ b/block/mirror.c
>>>>> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState
>>>>> *bs, BlockDriverState *target,
>>>>>        MirrorBlockJob *s;
>>>>>        if (granularity == 0) {
>>>>> -        /* Choose the default granularity based on the target file's
>>>>> cluster
>>>>> -         * size, clamped between 4k and 64k.  */
>>>>> -        BlockDriverInfo bdi;
>>>>> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>>> -            granularity = MAX(4096, bdi.cluster_size);
>>>>> -            granularity = MIN(65536, granularity);
>>>>> -        } else {
>>>>> -            granularity = 65536;
>>>>> -        }
>>>>> +        granularity = bdrv_get_default_bitmap_granularity(target);
>>>>>        }
>>>>>        assert ((granularity & (granularity - 1)) == 0);
>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>> index 5651a8e..95251c7 100644
>>>>> --- a/blockdev.c
>>>>> +++ b/blockdev.c
>>>>> @@ -1173,6 +1173,48 @@ out_aio_context:
>>>>>        return NULL;
>>>>>    }
>>>>> +/**
>>>>> + * Return a dirty bitmap (if present), after validating
>>>>> + * the node reference and bitmap names. Returns NULL on error,
>>>>> + * including when the BDS and/or bitmap is not found.
>>>>> + */
>>>>> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
>>>>> +                                                  const char *name,
>>>>> +                                                  BlockDriverState
>>>>> **pbs,
>>>>> +                                                  Error **errp)
>>>>> +{
>>>>> +    BlockDriverState *bs;
>>>>> +    BdrvDirtyBitmap *bitmap;
>>>>> +
>>>>> +    if (!node_ref) {
>>>>> +        error_setg(errp, "Node reference cannot be NULL");
>>>>> +        return NULL;
>>>>> +    }
>>>>> +    if (!name) {
>>>>> +        error_setg(errp, "Bitmap name cannot be NULL");
>>>>> +        return NULL;
>>>>> +    }
>>>>> +
>>>>> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
>>>>> +    if (!bs) {
>>>>> +        error_setg(errp, "Node reference '%s' not found", node_ref);
>>>>
>>>> No need to throw the (hopefully) perfectly fine Error code returned by
>>>> bdrv_lookup_bs() away.
>>>>
>>>
>>> I just wanted an error message consistent with the parameter name, in
>>> this case. i.e., We couldn't find the "Node reference" instead of
>>> "device" or "node name." Just trying to distinguish the fact that this
>>> is an arbitrary reference in the error message.
>>>
>>> I can still remove it, but I am curious to see what Markus thinks of
>>> the names I have chosen before I monkey with the errors too much more.
>>
>> bdrv_lookup_bs() is an awkward interface.
>>
>> If @device is non-null, try to look up a backend (BB) named @device.  If
>> it exists, return the backend's root node (BDS).
>>
>> Else if @node_name is non-null, try to look up a node (BDS) named
>> @node_name.  If it exists, return it.
>>
>> Else, set this error:
>>
>>      error_setg(errp, "Cannot find device=%s nor node_name=%s",
>>                       device ? device : "",
>>                       node_name ? node_name : "");
>>
>> The error message is crap unless both device and node_name are non-null
>> and different.  Which is never the case: we always either pass two
>> identical non-null arguments, or we pass a null and a non-null
>> argument[*].  In other words, the error message is always crap.
>>
>> In case you wonder why @device takes precedence over node_name when both
>> are given: makes no sense.  But when both are given, they are always
>> identical, and since backend and node names share a name space, only one
>> can resolve.
>>
>> A couple of cleaner solutions come to mind:
>>
>> * Make bdrv_lookup_bs() suck less
>>
>>    Assert its tacit preconditions:
>>
>>      assert(device || node_name);
>>      assert(!device || !node_name || device == node_name);
>>
>>    Then make it produce a decent error:
>>
>>      if (device && node_name) {
>>          error_setg(errp, "Neither block backend nor node %s found", device);
>>      else if (device) {
>>          error_setg(errp, "Block backend %s not found", device);
>>      } else if (node_name) {
>>          error_setg(errp, "Block node %s not found", node_name);
>>      }
>>
>>    Note how the three cases mirror the three usage patterns.
>>
>>    Further note that the proposed error messages deviate from the
>>    existing practice of calling block backends "devices".  Calling
>>    everything and its dog a "device" is traditional, but it's also lazy
>>    and confusing.  End of digression.
>>
>> * Make bdrv_lookup_bs suck less by doing less: leave error_setg() to its
>>    callers
>>
>>    Drop the Error ** parameter.  Callers know whether a failed lookup was
>>    for a device name, a node name or both, and can set an appropriate
>>    error themselves.
>>
>>    I'd still assert the preconditions.
>>
>> * Replace the function by one for each of its usage patterns
>>
>>    I think that's what I'd do.
>>
>> [...]
>>
>>
>> [*] See
>> https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg01298.html
>>
>
> I can submit a patch for making bdrv_lookup_bs "nicer," or at least
> its usage more clear, in a separate patch.

Yes, please.

> If you really want me to fold it into this series, I'd invite you to
> review explicitly my usage of the parameter "node-ref" before I embark
> on cleaning up other interface areas.

Follow-up patch is fine.  Adding one more bad error message along the
way before you fix them all doesn't bother me.

> Does this naming scheme look sane to you, and fit with your general
> expectations?
>
> I can also add a "bdrv_lookup_noderef" function that takes only one
> argument, which will help enforce the "If both arguments are provided,
> they must be the same" paradigm.
>
> This patch (#3) covers my shot at a unified parameter, and you can see
> further consequences in #7, and #10 (transactions).

Do we want to introduce a @node-ref naming convention?

Currently, QMP calls parameters or members naming nodes @node-name or
similar, and parameters/members naming backends @device or similar.  The
one place where we already accept either is called @reference in the
schema, but it's a member of an anonymous union, so it's not really
visible in QMP.

Previously[*], we agreed (I think) to replace and deprecate the four
commands that use the "pair of names" convention to identify a node.
Their replacement would use the "single name" convention.  The name can
either be a node name or a backend name, and the latter automatically
resolves to its root node.

The "backend name resolves to its root node" convenience feature should
be available consistently or not at all.  I think the consensus it to
want it consistently.

Therefore, your new @node-ref is really the same as the existing
@node-name, isn't it?

Why a new naming convention @node-ref?  Is it meant to be in addition to
@node-name, or is it meant to replace it?

> CC'ing Eric Blake, as well, for comments on a "unified parameter"
> interface in general.

Good move.


[*] https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg02572.html

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-20  8:26           ` Markus Armbruster
@ 2015-01-20 16:48             ` John Snow
  2015-01-21  9:34               ` Markus Armbruster
  0 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-20 16:48 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: kwolf, famz, qemu-devel, Max Reitz, vsementsov, stefanha



On 01/20/2015 03:26 AM, Markus Armbruster wrote:
> John Snow <jsnow@redhat.com> writes:
>
>> On 01/19/2015 05:08 AM, Markus Armbruster wrote:
>>> John Snow <jsnow@redhat.com> writes:
>>>
>>>> On 01/16/2015 10:36 AM, Max Reitz wrote:
>>>>> On 2015-01-12 at 11:30, John Snow wrote:
>>>>>> From: Fam Zheng <famz@redhat.com>
>>>>>>
>>>>>> The new command pair is added to manage user created dirty bitmap. The
>>>>>> dirty bitmap's name is mandatory and must be unique for the same device,
>>>>>> but different devices can have bitmaps with the same names.
>>>>>>
>>>>>> The granularity is an optional field. If it is not specified, we will
>>>>>> choose a default granularity based on the cluster size if available,
>>>>>> clamped to between 4K and 64K to mirror how the 'mirror' code was
>>>>>> already choosing granularity. If we do not have cluster size info
>>>>>> available, we choose 64K. This code has been factored out into a helper
>>>>>> shared with block/mirror.
>>>>>>
>>>>>> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
>>>>>> which takes a device name and a dirty bitmap name and validates the
>>>>>> lookup, returning NULL and setting errp if there is a problem with
>>>>>> either field. This helper will be re-used in future patches in this
>>>>>> series.
>>>>>>
>>>>>> The types added to block-core.json will be re-used in future patches
>>>>>> in this series, see:
>>>>>> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>>>>>> disable}'
>>>>>>
>>>>>> Signed-off-by: Fam Zheng <famz@redhat.com>
>>>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>>>> ---
>>>>>>     block.c               |  20 ++++++++++
>>>>>>     block/mirror.c        |  10 +----
>>>>>>     blockdev.c            | 100
>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>     include/block/block.h |   1 +
>>>>>>     qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>>>>>>     qmp-commands.hx       |  51 +++++++++++++++++++++++++
>>>>>>     6 files changed, 228 insertions(+), 9 deletions(-)
>>>>>>
>>>>>> diff --git a/block.c b/block.c
>>>>>> index bfeae6b..3eb77ee 100644
>>>>>> --- a/block.c
>>>>>> +++ b/block.c
>>>>>> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs,
>>>>>> BdrvDirtyBitmap *bitmap, int64_t sector
>>>>>>         }
>>>>>>     }
>>>>>> +/**
>>>>>> + * Chooses a default granularity based on the existing cluster size,
>>>>>> + * but clamped between [4K, 64K]. Defaults to 64K in the case that there
>>>>>> + * is no cluster size information available.
>>>>>> + */
>>>>>> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
>>>>>> +{
>>>>>> +    BlockDriverInfo bdi;
>>>>>> +    uint64_t granularity;
>>>>>> +
>>>>>> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>>>> +        granularity = MAX(4096, bdi.cluster_size);
>>>>>> +        granularity = MIN(65536, granularity);
>>>>>> +    } else {
>>>>>> +        granularity = 65536;
>>>>>> +    }
>>>>>> +
>>>>>> +    return granularity;
>>>>>> +}
>>>>>> +
>>>>>>     void bdrv_dirty_iter_init(BlockDriverState *bs,
>>>>>>                               BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>>>>>>     {
>>>>>> diff --git a/block/mirror.c b/block/mirror.c
>>>>>> index d819952..fc545f1 100644
>>>>>> --- a/block/mirror.c
>>>>>> +++ b/block/mirror.c
>>>>>> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState
>>>>>> *bs, BlockDriverState *target,
>>>>>>         MirrorBlockJob *s;
>>>>>>         if (granularity == 0) {
>>>>>> -        /* Choose the default granularity based on the target file's
>>>>>> cluster
>>>>>> -         * size, clamped between 4k and 64k.  */
>>>>>> -        BlockDriverInfo bdi;
>>>>>> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>>>> -            granularity = MAX(4096, bdi.cluster_size);
>>>>>> -            granularity = MIN(65536, granularity);
>>>>>> -        } else {
>>>>>> -            granularity = 65536;
>>>>>> -        }
>>>>>> +        granularity = bdrv_get_default_bitmap_granularity(target);
>>>>>>         }
>>>>>>         assert ((granularity & (granularity - 1)) == 0);
>>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>>> index 5651a8e..95251c7 100644
>>>>>> --- a/blockdev.c
>>>>>> +++ b/blockdev.c
>>>>>> @@ -1173,6 +1173,48 @@ out_aio_context:
>>>>>>         return NULL;
>>>>>>     }
>>>>>> +/**
>>>>>> + * Return a dirty bitmap (if present), after validating
>>>>>> + * the node reference and bitmap names. Returns NULL on error,
>>>>>> + * including when the BDS and/or bitmap is not found.
>>>>>> + */
>>>>>> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
>>>>>> +                                                  const char *name,
>>>>>> +                                                  BlockDriverState
>>>>>> **pbs,
>>>>>> +                                                  Error **errp)
>>>>>> +{
>>>>>> +    BlockDriverState *bs;
>>>>>> +    BdrvDirtyBitmap *bitmap;
>>>>>> +
>>>>>> +    if (!node_ref) {
>>>>>> +        error_setg(errp, "Node reference cannot be NULL");
>>>>>> +        return NULL;
>>>>>> +    }
>>>>>> +    if (!name) {
>>>>>> +        error_setg(errp, "Bitmap name cannot be NULL");
>>>>>> +        return NULL;
>>>>>> +    }
>>>>>> +
>>>>>> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
>>>>>> +    if (!bs) {
>>>>>> +        error_setg(errp, "Node reference '%s' not found", node_ref);
>>>>>
>>>>> No need to throw the (hopefully) perfectly fine Error code returned by
>>>>> bdrv_lookup_bs() away.
>>>>>
>>>>
>>>> I just wanted an error message consistent with the parameter name, in
>>>> this case. i.e., We couldn't find the "Node reference" instead of
>>>> "device" or "node name." Just trying to distinguish the fact that this
>>>> is an arbitrary reference in the error message.
>>>>
>>>> I can still remove it, but I am curious to see what Markus thinks of
>>>> the names I have chosen before I monkey with the errors too much more.
>>>
>>> bdrv_lookup_bs() is an awkward interface.
>>>
>>> If @device is non-null, try to look up a backend (BB) named @device.  If
>>> it exists, return the backend's root node (BDS).
>>>
>>> Else if @node_name is non-null, try to look up a node (BDS) named
>>> @node_name.  If it exists, return it.
>>>
>>> Else, set this error:
>>>
>>>       error_setg(errp, "Cannot find device=%s nor node_name=%s",
>>>                        device ? device : "",
>>>                        node_name ? node_name : "");
>>>
>>> The error message is crap unless both device and node_name are non-null
>>> and different.  Which is never the case: we always either pass two
>>> identical non-null arguments, or we pass a null and a non-null
>>> argument[*].  In other words, the error message is always crap.
>>>
>>> In case you wonder why @device takes precedence over node_name when both
>>> are given: makes no sense.  But when both are given, they are always
>>> identical, and since backend and node names share a name space, only one
>>> can resolve.
>>>
>>> A couple of cleaner solutions come to mind:
>>>
>>> * Make bdrv_lookup_bs() suck less
>>>
>>>     Assert its tacit preconditions:
>>>
>>>       assert(device || node_name);
>>>       assert(!device || !node_name || device == node_name);
>>>
>>>     Then make it produce a decent error:
>>>
>>>       if (device && node_name) {
>>>           error_setg(errp, "Neither block backend nor node %s found", device);
>>>       else if (device) {
>>>           error_setg(errp, "Block backend %s not found", device);
>>>       } else if (node_name) {
>>>           error_setg(errp, "Block node %s not found", node_name);
>>>       }
>>>
>>>     Note how the three cases mirror the three usage patterns.
>>>
>>>     Further note that the proposed error messages deviate from the
>>>     existing practice of calling block backends "devices".  Calling
>>>     everything and its dog a "device" is traditional, but it's also lazy
>>>     and confusing.  End of digression.
>>>
>>> * Make bdrv_lookup_bs suck less by doing less: leave error_setg() to its
>>>     callers
>>>
>>>     Drop the Error ** parameter.  Callers know whether a failed lookup was
>>>     for a device name, a node name or both, and can set an appropriate
>>>     error themselves.
>>>
>>>     I'd still assert the preconditions.
>>>
>>> * Replace the function by one for each of its usage patterns
>>>
>>>     I think that's what I'd do.
>>>
>>> [...]
>>>
>>>
>>> [*] See
>>> https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg01298.html
>>>
>>
>> I can submit a patch for making bdrv_lookup_bs "nicer," or at least
>> its usage more clear, in a separate patch.
>
> Yes, please.
>
>> If you really want me to fold it into this series, I'd invite you to
>> review explicitly my usage of the parameter "node-ref" before I embark
>> on cleaning up other interface areas.
>
> Follow-up patch is fine.  Adding one more bad error message along the
> way before you fix them all doesn't bother me.
>
>> Does this naming scheme look sane to you, and fit with your general
>> expectations?
>>
>> I can also add a "bdrv_lookup_noderef" function that takes only one
>> argument, which will help enforce the "If both arguments are provided,
>> they must be the same" paradigm.
>>
>> This patch (#3) covers my shot at a unified parameter, and you can see
>> further consequences in #7, and #10 (transactions).
>
> Do we want to introduce a @node-ref naming convention?
>
> Currently, QMP calls parameters or members naming nodes @node-name or
> similar, and parameters/members naming backends @device or similar.  The
> one place where we already accept either is called @reference in the
> schema, but it's a member of an anonymous union, so it's not really
> visible in QMP.
>
> Previously[*], we agreed (I think) to replace and deprecate the four
> commands that use the "pair of names" convention to identify a node.
> Their replacement would use the "single name" convention.  The name can
> either be a node name or a backend name, and the latter automatically
> resolves to its root node.
>
> The "backend name resolves to its root node" convenience feature should
> be available consistently or not at all.  I think the consensus it to
> want it consistently.
>
> Therefore, your new @node-ref is really the same as the existing
> @node-name, isn't it?

bdrv_lookup_bs() as used in the patch, as that function exists today, 
will resolve backends to root nodes, so these QMP commands will operate 
with device/backend names or node-names.

> Why a new naming convention @node-ref?  Is it meant to be in addition to
> @node-name, or is it meant to replace it?

Is it the same? It was my understanding that we didn't have a QMP 
command currently that accepted /only/ nodes; from your previous mail 
characterizing the existing patterns:

"3. Node name only

    No known example."

So this patch is /intending/ to add a command wherein you can identify 
either a "node-name" or a "device," where the real goal is to obtain any 
arbitrary node -- so I used a new name.

If we want a new unified parameter in the future, we should probably 
figure out what it is and start using it. I propose "node-ref."

I *did* see that "reference" was already used for this purpose, but as 
you say, the semantics are somewhat different there, so I opted for a 
new name to not confuse the usages. Maybe this is what we want, maybe it 
isn't: A case could be made for either case.

I'm making my case for node-ref:

Short for Node Reference, it's different from "Node Name" in that it 
does not describe a single node's name, it's simply a reference to one.
To me, this means that it could either be a node-name OR a backend-name, 
because a backend name could be considered a reference to the root node 
of that tree.

So it seems generic-y enough to be a unified parameter.

>> CC'ing Eric Blake, as well, for comments on a "unified parameter"
>> interface in general.
>
> Good move.
>
>
> [*] https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg02572.html
>

Adding Eric back in, where'd he go?

--js

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-20 16:48             ` John Snow
@ 2015-01-21  9:34               ` Markus Armbruster
  2015-01-21 15:51                 ` Eric Blake
  2015-01-30 14:32                 ` Kevin Wolf
  0 siblings, 2 replies; 54+ messages in thread
From: Markus Armbruster @ 2015-01-21  9:34 UTC (permalink / raw)
  To: John Snow; +Cc: kwolf, famz, qemu-devel, Max Reitz, vsementsov, stefanha

John Snow <jsnow@redhat.com> writes:

> On 01/20/2015 03:26 AM, Markus Armbruster wrote:
>> John Snow <jsnow@redhat.com> writes:
>>
>>> On 01/19/2015 05:08 AM, Markus Armbruster wrote:
>>>> John Snow <jsnow@redhat.com> writes:
>>>>
>>>>> On 01/16/2015 10:36 AM, Max Reitz wrote:
>>>>>> On 2015-01-12 at 11:30, John Snow wrote:
>>>>>>> From: Fam Zheng <famz@redhat.com>
>>>>>>>
>>>>>>> The new command pair is added to manage user created dirty bitmap. The
>>>>>>> dirty bitmap's name is mandatory and must be unique for the same device,
>>>>>>> but different devices can have bitmaps with the same names.
>>>>>>>
>>>>>>> The granularity is an optional field. If it is not specified, we will
>>>>>>> choose a default granularity based on the cluster size if available,
>>>>>>> clamped to between 4K and 64K to mirror how the 'mirror' code was
>>>>>>> already choosing granularity. If we do not have cluster size info
>>>>>>> available, we choose 64K. This code has been factored out into a helper
>>>>>>> shared with block/mirror.
>>>>>>>
>>>>>>> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
>>>>>>> which takes a device name and a dirty bitmap name and validates the
>>>>>>> lookup, returning NULL and setting errp if there is a problem with
>>>>>>> either field. This helper will be re-used in future patches in this
>>>>>>> series.
>>>>>>>
>>>>>>> The types added to block-core.json will be re-used in future patches
>>>>>>> in this series, see:
>>>>>>> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>>>>>>> disable}'
>>>>>>>
>>>>>>> Signed-off-by: Fam Zheng <famz@redhat.com>
>>>>>>> Signed-off-by: John Snow <jsnow@redhat.com>
>>>>>>> ---
>>>>>>>     block.c               |  20 ++++++++++
>>>>>>>     block/mirror.c        |  10 +----
>>>>>>>     blockdev.c            | 100
>>>>>>> ++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>>>     include/block/block.h |   1 +
>>>>>>>     qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>>>>>>>     qmp-commands.hx       |  51 +++++++++++++++++++++++++
>>>>>>>     6 files changed, 228 insertions(+), 9 deletions(-)
>>>>>>>
>>>>>>> diff --git a/block.c b/block.c
>>>>>>> index bfeae6b..3eb77ee 100644
>>>>>>> --- a/block.c
>>>>>>> +++ b/block.c
>>>>>>> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs,
>>>>>>> BdrvDirtyBitmap *bitmap, int64_t sector
>>>>>>>         }
>>>>>>>     }
>>>>>>> +/**
>>>>>>> + * Chooses a default granularity based on the existing cluster size,
>>>>>>> + * but clamped between [4K, 64K]. Defaults to 64K in the case that there
>>>>>>> + * is no cluster size information available.
>>>>>>> + */
>>>>>>> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
>>>>>>> +{
>>>>>>> +    BlockDriverInfo bdi;
>>>>>>> +    uint64_t granularity;
>>>>>>> +
>>>>>>> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>>>>> +        granularity = MAX(4096, bdi.cluster_size);
>>>>>>> +        granularity = MIN(65536, granularity);
>>>>>>> +    } else {
>>>>>>> +        granularity = 65536;
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    return granularity;
>>>>>>> +}
>>>>>>> +
>>>>>>>     void bdrv_dirty_iter_init(BlockDriverState *bs,
>>>>>>>                               BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>>>>>>>     {
>>>>>>> diff --git a/block/mirror.c b/block/mirror.c
>>>>>>> index d819952..fc545f1 100644
>>>>>>> --- a/block/mirror.c
>>>>>>> +++ b/block/mirror.c
>>>>>>> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState
>>>>>>> *bs, BlockDriverState *target,
>>>>>>>         MirrorBlockJob *s;
>>>>>>>         if (granularity == 0) {
>>>>>>> -        /* Choose the default granularity based on the target file's
>>>>>>> cluster
>>>>>>> -         * size, clamped between 4k and 64k.  */
>>>>>>> -        BlockDriverInfo bdi;
>>>>>>> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
>>>>>>> -            granularity = MAX(4096, bdi.cluster_size);
>>>>>>> -            granularity = MIN(65536, granularity);
>>>>>>> -        } else {
>>>>>>> -            granularity = 65536;
>>>>>>> -        }
>>>>>>> +        granularity = bdrv_get_default_bitmap_granularity(target);
>>>>>>>         }
>>>>>>>         assert ((granularity & (granularity - 1)) == 0);
>>>>>>> diff --git a/blockdev.c b/blockdev.c
>>>>>>> index 5651a8e..95251c7 100644
>>>>>>> --- a/blockdev.c
>>>>>>> +++ b/blockdev.c
>>>>>>> @@ -1173,6 +1173,48 @@ out_aio_context:
>>>>>>>         return NULL;
>>>>>>>     }
>>>>>>> +/**
>>>>>>> + * Return a dirty bitmap (if present), after validating
>>>>>>> + * the node reference and bitmap names. Returns NULL on error,
>>>>>>> + * including when the BDS and/or bitmap is not found.
>>>>>>> + */
>>>>>>> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
>>>>>>> +                                                  const char *name,
>>>>>>> +                                                  BlockDriverState
>>>>>>> **pbs,
>>>>>>> +                                                  Error **errp)
>>>>>>> +{
>>>>>>> +    BlockDriverState *bs;
>>>>>>> +    BdrvDirtyBitmap *bitmap;
>>>>>>> +
>>>>>>> +    if (!node_ref) {
>>>>>>> +        error_setg(errp, "Node reference cannot be NULL");
>>>>>>> +        return NULL;
>>>>>>> +    }
>>>>>>> +    if (!name) {
>>>>>>> +        error_setg(errp, "Bitmap name cannot be NULL");
>>>>>>> +        return NULL;
>>>>>>> +    }
>>>>>>> +
>>>>>>> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
>>>>>>> +    if (!bs) {
>>>>>>> +        error_setg(errp, "Node reference '%s' not found", node_ref);
>>>>>>
>>>>>> No need to throw the (hopefully) perfectly fine Error code returned by
>>>>>> bdrv_lookup_bs() away.
>>>>>>
>>>>>
>>>>> I just wanted an error message consistent with the parameter name, in
>>>>> this case. i.e., We couldn't find the "Node reference" instead of
>>>>> "device" or "node name." Just trying to distinguish the fact that this
>>>>> is an arbitrary reference in the error message.
>>>>>
>>>>> I can still remove it, but I am curious to see what Markus thinks of
>>>>> the names I have chosen before I monkey with the errors too much more.
>>>>
>>>> bdrv_lookup_bs() is an awkward interface.
>>>>
>>>> If @device is non-null, try to look up a backend (BB) named @device.  If
>>>> it exists, return the backend's root node (BDS).
>>>>
>>>> Else if @node_name is non-null, try to look up a node (BDS) named
>>>> @node_name.  If it exists, return it.
>>>>
>>>> Else, set this error:
>>>>
>>>>       error_setg(errp, "Cannot find device=%s nor node_name=%s",
>>>>                        device ? device : "",
>>>>                        node_name ? node_name : "");
>>>>
>>>> The error message is crap unless both device and node_name are non-null
>>>> and different.  Which is never the case: we always either pass two
>>>> identical non-null arguments, or we pass a null and a non-null
>>>> argument[*].  In other words, the error message is always crap.
>>>>
>>>> In case you wonder why @device takes precedence over node_name when both
>>>> are given: makes no sense.  But when both are given, they are always
>>>> identical, and since backend and node names share a name space, only one
>>>> can resolve.
>>>>
>>>> A couple of cleaner solutions come to mind:
>>>>
>>>> * Make bdrv_lookup_bs() suck less
>>>>
>>>>     Assert its tacit preconditions:
>>>>
>>>>       assert(device || node_name);
>>>>       assert(!device || !node_name || device == node_name);
>>>>
>>>>     Then make it produce a decent error:
>>>>
>>>>       if (device && node_name) {
>>>>           error_setg(errp, "Neither block backend nor node %s found", device);
>>>>       else if (device) {
>>>>           error_setg(errp, "Block backend %s not found", device);
>>>>       } else if (node_name) {
>>>>           error_setg(errp, "Block node %s not found", node_name);
>>>>       }
>>>>
>>>>     Note how the three cases mirror the three usage patterns.
>>>>
>>>>     Further note that the proposed error messages deviate from the
>>>>     existing practice of calling block backends "devices".  Calling
>>>>     everything and its dog a "device" is traditional, but it's also lazy
>>>>     and confusing.  End of digression.
>>>>
>>>> * Make bdrv_lookup_bs suck less by doing less: leave error_setg() to its
>>>>     callers
>>>>
>>>>     Drop the Error ** parameter.  Callers know whether a failed lookup was
>>>>     for a device name, a node name or both, and can set an appropriate
>>>>     error themselves.
>>>>
>>>>     I'd still assert the preconditions.
>>>>
>>>> * Replace the function by one for each of its usage patterns
>>>>
>>>>     I think that's what I'd do.
>>>>
>>>> [...]
>>>>
>>>>
>>>> [*] See
>>>> https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg01298.html
>>>>
>>>
>>> I can submit a patch for making bdrv_lookup_bs "nicer," or at least
>>> its usage more clear, in a separate patch.
>>
>> Yes, please.
>>
>>> If you really want me to fold it into this series, I'd invite you to
>>> review explicitly my usage of the parameter "node-ref" before I embark
>>> on cleaning up other interface areas.
>>
>> Follow-up patch is fine.  Adding one more bad error message along the
>> way before you fix them all doesn't bother me.
>>
>>> Does this naming scheme look sane to you, and fit with your general
>>> expectations?
>>>
>>> I can also add a "bdrv_lookup_noderef" function that takes only one
>>> argument, which will help enforce the "If both arguments are provided,
>>> they must be the same" paradigm.
>>>
>>> This patch (#3) covers my shot at a unified parameter, and you can see
>>> further consequences in #7, and #10 (transactions).
>>
>> Do we want to introduce a @node-ref naming convention?
>>
>> Currently, QMP calls parameters or members naming nodes @node-name or
>> similar, and parameters/members naming backends @device or similar.  The
>> one place where we already accept either is called @reference in the
>> schema, but it's a member of an anonymous union, so it's not really
>> visible in QMP.
>>
>> Previously[*], we agreed (I think) to replace and deprecate the four
>> commands that use the "pair of names" convention to identify a node.
>> Their replacement would use the "single name" convention.  The name can
>> either be a node name or a backend name, and the latter automatically
>> resolves to its root node.
>>
>> The "backend name resolves to its root node" convenience feature should
>> be available consistently or not at all.  I think the consensus it to
>> want it consistently.
>>
>> Therefore, your new @node-ref is really the same as the existing
>> @node-name, isn't it?
>
> bdrv_lookup_bs() as used in the patch, as that function exists today,
> will resolve backends to root nodes, so these QMP commands will
> operate with device/backend names or node-names.
>
>> Why a new naming convention @node-ref?  Is it meant to be in addition to
>> @node-name, or is it meant to replace it?
>
> Is it the same? It was my understanding that we didn't have a QMP
> command currently that accepted /only/ nodes; from your previous mail
> characterizing the existing patterns:
>
> "3. Node name only
>
>    No known example."
>
> So this patch is /intending/ to add a command wherein you can identify
> either a "node-name" or a "device," where the real goal is to obtain
> any arbitrary node -- so I used a new name.
>
> If we want a new unified parameter in the future, we should probably
> figure out what it is and start using it. I propose "node-ref."
>
> I *did* see that "reference" was already used for this purpose, but as
> you say, the semantics are somewhat different there, so I opted for a
> new name to not confuse the usages. Maybe this is what we want, maybe
> it isn't: A case could be made for either case.
>
> I'm making my case for node-ref:
>
> Short for Node Reference, it's different from "Node Name" in that it
> does not describe a single node's name, it's simply a reference to
> one.
> To me, this means that it could either be a node-name OR a
> backend-name, because a backend name could be considered a reference
> to the root node of that tree.
>
> So it seems generic-y enough to be a unified parameter.

I'm afraid I forgot much of the discussion we had before the break, and
only now it's coming back, slowly.

Quoting myself on naming parameters identifying nodes[*]:

    John Snow pointed out to me that we still haven't spelled out how this
    single parameter should be named.

    On obvious option is calling it node-name, or FOO-node-name when we have
    several.  However, we'd then have two subtly different kinds of
    parameters called like that: the old ones accept *only* node names, the
    new ones also accept backend names, which automatically resolve to the
    backend's root node.

    Three ways to cope with that:

    * Find a better name.

    * Make the old ones accept backend names, too.  Only a few, not that
      much work.  However, there are exceptions:

      - blockdev-add's node-name *defines* the node name.

      - query-named-block-nodes's node-name *is* the node's name.

    * Stop worrying and embrace the inconsistency.  The affected commands
      are headed for deprecation anyway.

    I think I'd go with "node" or "FOO-node" for parameters that reference
    nodes and accept both node names and backend names, and refrain from
    touching the existing node-name parameters.

Let's go through existing uses of @node-name again:

1. Define a node name

   QMP commands blockdev-add (type BlockdevOptionsBase), drive-mirror

2. Report a node name

   QMP command query-named-block-nodes (type BlockDeviceInfo)

3. Node reference with backend names permitted for convenience

   New QMP command block-dirty-bitmap-add (type BlockDirtyBitmapAdd) and
   others

4. Node reference with backend names not permitted
  
   QMP commands drive-mirror @replaces, change-backing-file
   @image-node-name

   We may want to support the "backend name resolves to root node"
   convenience feature here, for consistency.  Then this moves under 3.

   Note interface wart: change-backing-file additionally requires the
   backend owning the node.  We need the backend to set op-blockers, we
   can't easily find it from the node, so we make the user point it out
   to us.

5. "Pair of names" node reference, specify exactly one

   QMP commands block_passwd, block_resize, blockdev-snapshot-sync

   We can ignore this one, because we intend to replace the commands and
   deprecate the old ones.

If I understand you correctly, you're proposing to use @node-name or
@FOO-node-name when the value must be a node name (items 1+2 and 4), and
@node-ref or @FOO-node-ref where we additionally support the "backend
name resolves to root node" convenience feature (item 3).

Is that a fair description of your proposal?

PRO: the name makes it clear when the convenience feature is supported.

CON: if we eliminate 4 by supporting the convenience feature, we either
create ugly exceptions to the naming convention, or rename the
parameters.

Opinions?

>>> CC'ing Eric Blake, as well, for comments on a "unified parameter"
>>> interface in general.
>>
>> Good move.
>>
>>
>> [*] https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg02572.html
>>
>
> Adding Eric back in, where'd he go?

Looks like you announced the cc:, but didn't actually do it, twice %-)
Let me have a try.


[1] https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg03151.html

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-21  9:34               ` Markus Armbruster
@ 2015-01-21 15:51                 ` Eric Blake
  2015-01-30 14:32                 ` Kevin Wolf
  1 sibling, 0 replies; 54+ messages in thread
From: Eric Blake @ 2015-01-21 15:51 UTC (permalink / raw)
  To: Markus Armbruster, John Snow
  Cc: kwolf, famz, qemu-devel, Max Reitz, vsementsov, stefanha

[-- Attachment #1: Type: text/plain, Size: 1406 bytes --]

On 01/21/2015 02:34 AM, Markus Armbruster wrote:
> Opinions?
> 

I'm still thinking about my reply (it's a big enough question that I
want to make sure I consider ramifications), so this is just a
meta-reply to let you know I'm tracking this conversation.

>>>> CC'ing Eric Blake, as well, for comments on a "unified parameter"
>>>> interface in general.
>>>
>>> Good move.
>>>
>>>
>>> [*] https://lists.nongnu.org/archive/html/qemu-devel/2014-12/msg02572.html
>>>
>>
>> Adding Eric back in, where'd he go?
> 
> Looks like you announced the cc:, but didn't actually do it, twice %-)

I know that on some lists I'm subscribed to, mailman has an annoying
configuration where if a list member is subscribed to the list and has
requested that mailman not send dupe emails, then mailman rewrites CC:
lines to drop that list member from the copy of the mail that other list
readers receive.  I hate the behavior, but it may be why you appear to
not see me in cc, even though I've definitely been receiving the mails.
 At any rate, I have my mail filters set to flag mails that call out my
name, even if I get left out from cc, so I can usually spot threads like
this where you are trying to get my attention, regardless of whether you
remembered to include me directly.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove John Snow
  2015-01-16 15:36   ` Max Reitz
@ 2015-01-29 13:55   ` Vladimir Sementsov-Ogievskiy
  1 sibling, 0 replies; 54+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-01-29 13:55 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, mreitz, stefanha

s/{'command'/{ 'command'/g

- to be consistent with other staff in qapi/block-core.json

and the same fix for block-dirty-bitmap-enable and 
block-dirty-bitmap-disable

Best regards,
Vladimir

On 12.01.2015 19:30, John Snow wrote:
> From: Fam Zheng <famz@redhat.com>
>
> The new command pair is added to manage user created dirty bitmap. The
> dirty bitmap's name is mandatory and must be unique for the same device,
> but different devices can have bitmaps with the same names.
>
> The granularity is an optional field. If it is not specified, we will
> choose a default granularity based on the cluster size if available,
> clamped to between 4K and 64K to mirror how the 'mirror' code was
> already choosing granularity. If we do not have cluster size info
> available, we choose 64K. This code has been factored out into a helper
> shared with block/mirror.
>
> This patch also introduces the 'block_dirty_bitmap_lookup' helper,
> which takes a device name and a dirty bitmap name and validates the
> lookup, returning NULL and setting errp if there is a problem with
> either field. This helper will be re-used in future patches in this
> series.
>
> The types added to block-core.json will be re-used in future patches
> in this series, see:
> 'qapi: Add transaction support to block-dirty-bitmap-{add, enable, disable}'
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   block.c               |  20 ++++++++++
>   block/mirror.c        |  10 +----
>   blockdev.c            | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++
>   include/block/block.h |   1 +
>   qapi/block-core.json  |  55 +++++++++++++++++++++++++++
>   qmp-commands.hx       |  51 +++++++++++++++++++++++++
>   6 files changed, 228 insertions(+), 9 deletions(-)
>
> diff --git a/block.c b/block.c
> index bfeae6b..3eb77ee 100644
> --- a/block.c
> +++ b/block.c
> @@ -5417,6 +5417,26 @@ int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector
>       }
>   }
>   
> +/**
> + * Chooses a default granularity based on the existing cluster size,
> + * but clamped between [4K, 64K]. Defaults to 64K in the case that there
> + * is no cluster size information available.
> + */
> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
> +{
> +    BlockDriverInfo bdi;
> +    uint64_t granularity;
> +
> +    if (bdrv_get_info(bs, &bdi) >= 0 && bdi.cluster_size != 0) {
> +        granularity = MAX(4096, bdi.cluster_size);
> +        granularity = MIN(65536, granularity);
> +    } else {
> +        granularity = 65536;
> +    }
> +
> +    return granularity;
> +}
> +
>   void bdrv_dirty_iter_init(BlockDriverState *bs,
>                             BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
>   {
> diff --git a/block/mirror.c b/block/mirror.c
> index d819952..fc545f1 100644
> --- a/block/mirror.c
> +++ b/block/mirror.c
> @@ -667,15 +667,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
>       MirrorBlockJob *s;
>   
>       if (granularity == 0) {
> -        /* Choose the default granularity based on the target file's cluster
> -         * size, clamped between 4k and 64k.  */
> -        BlockDriverInfo bdi;
> -        if (bdrv_get_info(target, &bdi) >= 0 && bdi.cluster_size != 0) {
> -            granularity = MAX(4096, bdi.cluster_size);
> -            granularity = MIN(65536, granularity);
> -        } else {
> -            granularity = 65536;
> -        }
> +        granularity = bdrv_get_default_bitmap_granularity(target);
>       }
>   
>       assert ((granularity & (granularity - 1)) == 0);
> diff --git a/blockdev.c b/blockdev.c
> index 5651a8e..95251c7 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -1173,6 +1173,48 @@ out_aio_context:
>       return NULL;
>   }
>   
> +/**
> + * Return a dirty bitmap (if present), after validating
> + * the node reference and bitmap names. Returns NULL on error,
> + * including when the BDS and/or bitmap is not found.
> + */
> +static BdrvDirtyBitmap *block_dirty_bitmap_lookup(const char *node_ref,
> +                                                  const char *name,
> +                                                  BlockDriverState **pbs,
> +                                                  Error **errp)
> +{
> +    BlockDriverState *bs;
> +    BdrvDirtyBitmap *bitmap;
> +
> +    if (!node_ref) {
> +        error_setg(errp, "Node reference cannot be NULL");
> +        return NULL;
> +    }
> +    if (!name) {
> +        error_setg(errp, "Bitmap name cannot be NULL");
> +        return NULL;
> +    }
> +
> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
> +    if (!bs) {
> +        error_setg(errp, "Node reference '%s' not found", node_ref);
> +        return NULL;
> +    }
> +
> +    /* If caller provided a BDS*, provide the result of that lookup, too. */
> +    if (pbs) {
> +        *pbs = bs;
> +    }
> +
> +    bitmap = bdrv_find_dirty_bitmap(bs, name);
> +    if (!bitmap) {
> +        error_setg(errp, "Dirty bitmap not found: %s", name);
> +        return NULL;
> +    }
> +
> +    return bitmap;
> +}
> +
>   /* New and old BlockDriverState structs for atomic group operations */
>   
>   typedef struct BlkTransactionState BlkTransactionState;
> @@ -1894,6 +1936,64 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
>       aio_context_release(aio_context);
>   }
>   
> +void qmp_block_dirty_bitmap_add(const char *node_ref, const char *name,
> +                                bool has_granularity, int64_t granularity,
> +                                Error **errp)
> +{
> +    AioContext *aio_context;
> +    BlockDriverState *bs;
> +
> +    if (!name || name[0] == '\0') {
> +        error_setg(errp, "Bitmap name cannot be empty");
> +        return;
> +    }
> +
> +    bs = bdrv_lookup_bs(node_ref, node_ref, errp);
> +    if (!bs) {
> +        return;
> +    }
> +
> +    aio_context = bdrv_get_aio_context(bs);
> +    aio_context_acquire(aio_context);
> +
> +    if (has_granularity) {
> +        if (granularity < 512 || !is_power_of_2(granularity)) {
> +            error_setg(errp, "Granularity must be power of 2 "
> +                             "and at least 512");
> +            goto out;
> +        }
> +    } else {
> +        /* Default to cluster size, if available: */
> +        granularity = bdrv_get_default_bitmap_granularity(bs);
> +    }
> +
> +    bdrv_create_dirty_bitmap(bs, granularity, name, errp);
> +
> + out:
> +    aio_context_release(aio_context);
> +}
> +
> +void qmp_block_dirty_bitmap_remove(const char *node_ref, const char *name,
> +                                   Error **errp)
> +{
> +    AioContext *aio_context;
> +    BlockDriverState *bs;
> +    BdrvDirtyBitmap *bitmap;
> +
> +    bitmap = block_dirty_bitmap_lookup(node_ref, name, &bs, errp);
> +    if (!bitmap || !bs) {
> +        return;
> +    }
> +
> +    aio_context = bdrv_get_aio_context(bs);
> +    aio_context_acquire(aio_context);
> +
> +    bdrv_dirty_bitmap_make_anon(bs, bitmap);
> +    bdrv_release_dirty_bitmap(bs, bitmap);
> +
> +    aio_context_release(aio_context);
> +}
> +
>   int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
>   {
>       const char *id = qdict_get_str(qdict, "id");
> diff --git a/include/block/block.h b/include/block/block.h
> index bf767af..44dd6ca 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -438,6 +438,7 @@ BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs,
>   void bdrv_dirty_bitmap_make_anon(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>   void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap);
>   BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
> +uint64_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
>   int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
>   void bdrv_set_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap,
>                              int64_t cur_sector, int nr_sectors);
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index d176324..f79d165 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -894,6 +894,61 @@
>               '*on-target-error': 'BlockdevOnError' } }
>   
>   ##
> +# @BlockDirtyBitmap
> +#
> +# @node-ref: name of device/node-name which the bitmap is tracking
> +#
> +# @name: name of the dirty bitmap
> +#
> +# Since 2.3
> +##
> +{ 'type': 'BlockDirtyBitmap',
> +  'data': { 'node-ref': 'str', 'name': 'str' } }
> +
> +##
> +# @BlockDirtyBitmapAdd
> +#
> +# @node-ref: name of device/node-name which the bitmap is tracking
> +#
> +# @name: name of the dirty bitmap
> +#
> +# @granularity: #optional the bitmap granularity, default is 64k for
> +#               block-dirty-bitmap-add
> +#
> +# Since 2.3
> +##
> +{ 'type': 'BlockDirtyBitmapAdd',
> +  'data': { 'node-ref': 'str', 'name': 'str', '*granularity': 'int' } }
> +
> +##
> +# @block-dirty-bitmap-add
> +#
> +# Create a dirty bitmap with a name on the node
> +#
> +# Returns: nothing on success
> +#          If @node-ref is not a valid block device, DeviceNotFound
> +#          If @name is already taken, GenericError with an explanation
> +#
> +# Since 2.3
> +##
> +{'command': 'block-dirty-bitmap-add',
> +  'data': 'BlockDirtyBitmapAdd' }
> +
> +##
> +# @block-dirty-bitmap-remove
> +#
> +# Remove a dirty bitmap on the node
> +#
> +# Returns: nothing on success
> +#          If @node-ref is not a valid block device, DeviceNotFound
> +#          If @name is not found, GenericError with an explanation
> +#
> +# Since 2.3
> +##
> +{'command': 'block-dirty-bitmap-remove',
> +  'data': 'BlockDirtyBitmap' }
> +
> +##
>   # @block_set_io_throttle:
>   #
>   # Change I/O throttle limits for a block drive.
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 6945d30..4ffca8a 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -1202,6 +1202,57 @@ Example:
>   EQMP
>   
>       {
> +        .name       = "block-dirty-bitmap-add",
> +        .args_type  = "node-ref:B,name:s,granularity:i?",
> +        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_add,
> +    },
> +    {
> +        .name       = "block-dirty-bitmap-remove",
> +        .args_type  = "node-ref:B,name:s",
> +        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_remove,
> +    },
> +
> +SQMP
> +
> +block-dirty-bitmap-add
> +----------------------
> +Since 2.3
> +
> +Create a dirty bitmap with a name on the device, and start tracking the writes.
> +
> +Arguments:
> +
> +- "node-ref": device/node on which to create dirty bitmap (json-string)
> +- "name": name of the new dirty bitmap (json-string)
> +- "granularity": granularity to track writes with (int, optional)
> +
> +Example:
> +
> +-> { "execute": "block-dirty-bitmap-add", "arguments": { "node-ref": "drive0",
> +                                                   "name": "bitmap0" } }
> +<- { "return": {} }
> +
> +block-dirty-bitmap-remove
> +-------------------------
> +Since 2.3
> +
> +Stop write tracking and remove the dirty bitmap that was created with
> +block-dirty-bitmap-add.
> +
> +Arguments:
> +
> +- "node-ref": device/node on which to remove dirty bitmap (json-string)
> +- "name": name of the dirty bitmap to remove (json-string)
> +
> +Example:
> +
> +-> { "execute": "block-dirty-bitmap-remove", "arguments": { "node-ref": "drive0",
> +                                                      "name": "bitmap0" } }
> +<- { "return": {} }
> +
> +EQMP
> +
> +    {
>           .name       = "blockdev-snapshot-sync",
>           .args_type  = "device:s?,node-name:s?,snapshot-file:s,snapshot-node-name:s?,format:s?,mode:s?",
>           .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (14 preceding siblings ...)
  2015-01-13 19:52 ` John Snow
@ 2015-01-29 22:38 ` John Snow
  2015-01-30 10:24 ` Vladimir Sementsov-Ogievskiy
  16 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-29 22:38 UTC (permalink / raw)
  To: qemu-devel; +Cc: kwolf, famz, armbru, mreitz, vsementsov, stefanha

Just a ping.

There has been some feedback here, but I am hesitant to roll out a v12 
until there is a little more consensus from Eric Blake and Markus 
Armbruster on the parameter naming issue, as well as a cursory overview 
by Stefan or Kevin of the "successor" methodology.

--js

On 01/12/2015 11:30 AM, John Snow wrote:
> Welcome to version 11. I hope you are enjoying our regular newsletter.
>
> This patchset enables the in-memory part of the incremental backup
> feature. A patchset by Vladimir Sementsov-Ogievskiy enables the
> migration of in-memory dirty bitmaps, and a future patchset will
> enable the storage and retrieval of dirty bitmaps to and from permanent
> storage.
>
> Enough changes have been made that most Reviewed-By lines from
> previous iterations have been removed. (Sorry!)
>
> This series was originally authored by Fam Zheng;
> his cover letter is included below.
>
> ~John Snow
>
> =================================================================
>
> This is the in memory part of the incremental backup feature.
>
> With the added commands, we can create a bitmap on a block
> backend, from which point of time all the writes are tracked by
> the bitmap, marking sectors as dirty. Later, we call drive-backup
> and pass the bitmap to it, to do an incremental backup.
>
> See the last patch which adds some tests for this use case.
>
> Fam
>
> =================================================================
>
> For convenience, this patchset is available on github:
>                  https://github.com/jnsnow/qemu/commits/dbm-backup
>
> v11:
>
>   - Instead of copying BdrvDirtyBitmaps and keeping a pointer to the
>     object we were copied from, we instead "freeze" a bitmap in-place
>     without copying it. On success, we thaw and delete the bitmap.
>     On failure, we merge the bitmap with a "successor," which is an
>     anonymous bitmap attached as a child that records writes for us
>     for the duration of the backup operation.
>
>     This means that incremental backups can NEVER BE RETRIED in a
>     deterministic fashion. If an incremental backup fails on a set
>     of dirty sectors {x}, and a new set of dirty sectors {y} are
>     introduced during the backup, then any possible retry action
>     on an incremental backup can only operate on {x,y}. There is no
>     way to get an incremental backup "as it would have been."
>
>     So, the failure mode for incremental backup is to try again,
>     and the resulting image will simply be a differential from the
>     last successful dirty bitmap backup.
>
>   - Removed hbitmap_copy and bdrv_dirty_bitmap_copy.
>
>   - Added a small fixup patch:
>     - Update all granularity fields to be uint64_t.
>     - Update documentation around BdrvDirtyBitmap structure.
>
>   - Modified transactions to obey frozen attribute of BdrvDirtyBitmaps.
>
>   - Added frozen attribute to the info query.
>
> v10 (Overview):
>
>   - I've included one of Vladimir's bitmap fixes as patch #1.
>
>   - QMP commands and transactions are now protected via
>     aio_context functions.
>
>   - QMP commands use "node-ref" as a parameter name now. Reasoning
>     is thus: Either a "device name" or a "node name" can be used to
>     reference a BDS, which is the key item we are actually acting
>     on with these bitmap commands. Thus, I refer to this unified
>     parameter as a "Node Reference," or "node-ref."
>
>     We could also argue for "backend-ref" or "device-ref" for the
>     reverse semantics: where we accept a unified parameter, but we
>     intend to resolve it to the BlockBackend instead of resolving
>     the parameter given to the BlockDriverState.
>
>     Or, we could use "reference" for both cases, and to match the
>     existing BlockdevRef command.
>
>   - All QMP commands added are now per-node via a unified parameter
>     name. Though backup only operates on "devices," you are free to
>     create bitmaps for any arbitrary node you wish. It is obviously
>     only useful for the root node, currently.
>
>   - Bitmap Sync modes (CONSUME, RESET) are removed. See below
>     (changelog, RFC questions) for more details.
>
>   - Code to recover the bitmap after a failure has been added,
>     but I have some major questions about drive_backup guarantees.
>     See RFC questions.
>
> v10 (Detailed Changelog):
>
>     (1/13) New Patch:
>   - Included Vladimir Sementsov-Ogievskiy's patch that clarifies
>     the semantics of the bitmap primitives.
>
>     (3/13):
>   - Edited function names for consistency (Stefanha)
>   - Removed compile-time constants (Stefanha)
>   - Acquire aio_context for bitmap add/remove (Stefanha)
>   - Documented optional granularity for bitmap-add in
>     qmp-commands.hx file (Eric Blake)
>   - block_dirty_bitmap_lookup moved forward to this patch to allow
>     more re-use. (Stefanha)
>   - Fixed a problem where the block_dirty_bitmap_lookup didn't
>     always set an error if it returned NULL.
>   - Added an optional return BDS lookup parameter to
>     bdrv_dirty_bitmap_lookup.
>   - Renamed "device" to "node-ref" for block_dirty_bitmap_lookup,
>     adjusted calls to bdrv_lookup_bs() to reflect unified
>     parameter usage.
>   - qmp_block_dirty_bitmap_{add,remove} now reference arbitrary
>     node names via @node-ref.
>
>     (4/13):
>   - Default granularity and granularity getters are both
>     now uint64_t (Stefanha)
>
>     (5/13):
>   - Added documentation to warn about the necessity of updating
>     the hbitmap deep copy. (Stefanha)
>
>     (6/13)
>   - Renamed bdrv_reset_dirty_bitmap to bdrv_clear_dirty_bitmap
>     to be consistent with Vladimir's patches.
>   - Removed const qualifier for bdrv_copy_dirty_bitmap,
>     to accommodate patch 8.
>
>     (7/13) New Patch:
>   - Added an hbitmap_merge operation to join two bitmaps together.
>
>     (8/13) New Patch:
>   - Added bdrv_reclaim_dirty_bitmap() to allow us to "roll back" a
>     bitmap into the bitmap that it was spawned from. This will let
>     us maintain an accurate account of dirty sectors even after a
>     failure.
>   - This adds an "originator" pointer to the BdrvDirtyBitmap and
>     is why "const" was removed for copy.
>
>     (9/13):
>   - QMP semantics changes as outlined for Patch #3.
>   - Enable/Disable now protected by aio_context (Stefanha)
>
>     (10/13):
>   - Add coroutine_fn annotation to block backup helper. (Stefanha)
>   - Removed sync_bitmap_gran from BackupBlockJob, just use the
>     getter on the BdrvDirtyBitmap instead. (Stefanha)
>   - bdrv_dirty_iter_set was renamed to bdrv_set_dirty_iter.
>   - Calls to bdrv_reset_dirty_bitmap are modified to
>     bdrv_clear_dirty_bitmap to reflect the rename in patch #6.
>   - Bitmap usage modes (RESET vs. CONSUME) has been deleted, for
>     the reason of targeting a simpler core usage first before
>     targeting optimizations. CONSUME is particularly problematic
>     in the case of errors; so this mode is omitted for now.
>   - Adjusted error message to use MirrorSyncMode enum, not
>     (incorrectly) the BitmapSyncMode enum.
>   - In the event of a failure, the sync_bitmap is now merged back
>     into the original bitmap so that we do not lose any dirty
>     bitmap information needlessly.
>
>     (11/13):
>   - Changed block_dirty_bitmap_add_abort to use
>     qmp_block_dirty_bitmap_remove:
>      - Old code used bdrv_lookup_bs to acquire bitmap and bs
>        anyway, and ignored the failure case.
>      - New code relies on the same information, and with a NULL
>        errp pointer we will similarly ignore the failure case.
>        prepare() should have properly vetted this information
>        before this point anyway.
>        This new code is also now protected via aio_context through
>        the use of the QMP commands.
>   - More code re-use of block_dirty_bitmap_lookup to get both the
>     bs and bitmap pointers.
>   - aio_context protection and cleanup in new abort methods.
>
>     (13/13):
>   - Modified test for new parameter names.
>
> v9:
>   - Edited commit message, for English embetterment (02/10)
>   - Rebased on top of stefanha/block-next (06,08/10)
>   - Adjusted error message and line length (07/10)
>
> v8:
>   - Changed int64_t return for bdrv_dbm_calc_def_granularity to uint64_t (2/10)
>   - Updated commit message (2/10)
>   - Removed redundant check for null in device parameter (2/10)
>   - Removed comment cruft. (2/10)
>   - Removed redundant local_err propagation (several)
>   - Updated commit message (3/10)
>   - Fix HBitmap copy loop index (4/10)
>   - Remove redundant ternary (5/10)
>   - Shift up the block_dirty_bitmap_lookup function (6/10)
>   - Error messages cleanup (7/10)
>   - Add an assertion to explain the re-use of .prepare() for two transactions.
>     (8/10)
>   - Removed BDS argument from bitmap enable/disable helper; it was unused. (8/10)
>
> v7: (highlights)
>   - First version being authored by jsnow
>   - Addressed most list feedback from V6, many small changes.
>     All feedback was either addressed on-list (as a wontfix) or patched.
>   - Replaced all error_set with error_setg
>   - Replaced all bdrv_find with bdrv_lookup_bs()
>   - Adjusted the max granularity to share a common function with
>     backup/mirror that attempts to "guess" a reasonable default.
>     It clamps between [4K,64K] currently.
>   - The BdrvDirtyBitmap object now counts granularity exclusively in
>     bytes to match its interface.
>     It leaves the sector granularity concerns to HBitmap.
>   - Reworked the backup loop to utilize the hbitmap iterator.
>     There are some extra concerns to handle arrhythmic cases where the
>     granularity of the bitmap does not match the backup cluster size.
>     This iteration works best when it does match, but it's not a
>     deal-breaker if it doesn't -- it just gets less efficient.
>   - Reworked the transactional functions so that abort() wouldn't "undo"
>     a redundant command. They now have been split into a prepare and a
>     commit function (with state) and do not provide an abort command.
>   - Added a block_dirty_bitmap_lookup(device, name, errp) function to
>     shorten a few of the commands added in this series, particularly
>     qmp_enable, qmp_disable, and the transaction preparations.
>
> v6: Re-send of v5.
>
> v5: Rebase to master.
>
> v4: Last version tailored by Fam Zheng.
>
> ==
>
> Fam Zheng (7):
>    qapi: Add optional field "name" to block dirty bitmap
>    qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
>    block: Introduce bdrv_dirty_bitmap_granularity()
>    qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable
>    qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>      disable}
>    qmp: Add dirty bitmap status fields in query-block
>    qemu-iotests: Add tests for drive-backup sync=dirty-bitmap
>
> John Snow (5):
>    block: Add bdrv_clear_dirty_bitmap
>    hbitmap: add hbitmap_merge
>    block: Add bitmap successors
>    qmp: Add support of "dirty-bitmap" sync mode for drive-backup
>    block: BdrvDirtyBitmap miscellaneous fixup
>
> Vladimir Sementsov-Ogievskiy (1):
>    block: fix spoiling all dirty bitmaps by mirror and migration
>
>   block.c                       | 254 +++++++++++++++++++++++++++++++++++++--
>   block/backup.c                | 120 +++++++++++++++----
>   block/mirror.c                |  27 ++---
>   blockdev.c                    | 273 +++++++++++++++++++++++++++++++++++++++++-
>   hmp.c                         |   3 +-
>   include/block/block.h         |  31 ++++-
>   include/block/block_int.h     |   2 +
>   include/qemu/hbitmap.h        |  11 ++
>   migration/block.c             |   7 +-
>   qapi-schema.json              |   5 +-
>   qapi/block-core.json          | 103 +++++++++++++++-
>   qmp-commands.hx               |  68 ++++++++++-
>   tests/qemu-iotests/056        |  33 ++++-
>   tests/qemu-iotests/056.out    |   4 +-
>   tests/qemu-iotests/iotests.py |   8 ++
>   util/hbitmap.c                |  28 +++++
>   16 files changed, 910 insertions(+), 67 deletions(-)
>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series
  2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
                   ` (15 preceding siblings ...)
  2015-01-29 22:38 ` John Snow
@ 2015-01-30 10:24 ` Vladimir Sementsov-Ogievskiy
  2015-01-30 18:46   ` John Snow
  16 siblings, 1 reply; 54+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-01-30 10:24 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, mreitz, stefanha

About added functions for BdrvDirtyBitmap:

some functions has needless BlockDriverState* parameter, and others - 
doesn't:

with needless *bs:
bdrv_dirty_bitmap_make_anon
bdrv_dirty_bitmap_granularity
bdrv_clear_dirty_bitmap

without *bs:
bdrv_dirty_bitmap_enabled
bdrv_disable_dirty_bitmap
bdrv_enable_dirty_bitmap

I think, to be consistent, onlly one of two ways should be chosen:
1) all bdrv_dirty_bitmap_* functions has "BlockDriverState* bs" 
parameter, maybe needless
2) only bdrv_dirty_bitmap_* function that need "BlockDriverState* bs" 
parameter has it

Personally, I prefer the second one.

Best regards,
Vladimir

On 12.01.2015 19:30, John Snow wrote:
> Welcome to version 11. I hope you are enjoying our regular newsletter.
>
> This patchset enables the in-memory part of the incremental backup
> feature. A patchset by Vladimir Sementsov-Ogievskiy enables the
> migration of in-memory dirty bitmaps, and a future patchset will
> enable the storage and retrieval of dirty bitmaps to and from permanent
> storage.
>
> Enough changes have been made that most Reviewed-By lines from
> previous iterations have been removed. (Sorry!)
>
> This series was originally authored by Fam Zheng;
> his cover letter is included below.
>
> ~John Snow
>
> =================================================================
>
> This is the in memory part of the incremental backup feature.
>
> With the added commands, we can create a bitmap on a block
> backend, from which point of time all the writes are tracked by
> the bitmap, marking sectors as dirty. Later, we call drive-backup
> and pass the bitmap to it, to do an incremental backup.
>
> See the last patch which adds some tests for this use case.
>
> Fam
>
> =================================================================
>
> For convenience, this patchset is available on github:
>                  https://github.com/jnsnow/qemu/commits/dbm-backup
>
> v11:
>
>   - Instead of copying BdrvDirtyBitmaps and keeping a pointer to the
>     object we were copied from, we instead "freeze" a bitmap in-place
>     without copying it. On success, we thaw and delete the bitmap.
>     On failure, we merge the bitmap with a "successor," which is an
>     anonymous bitmap attached as a child that records writes for us
>     for the duration of the backup operation.
>
>     This means that incremental backups can NEVER BE RETRIED in a
>     deterministic fashion. If an incremental backup fails on a set
>     of dirty sectors {x}, and a new set of dirty sectors {y} are
>     introduced during the backup, then any possible retry action
>     on an incremental backup can only operate on {x,y}. There is no
>     way to get an incremental backup "as it would have been."
>
>     So, the failure mode for incremental backup is to try again,
>     and the resulting image will simply be a differential from the
>     last successful dirty bitmap backup.
>
>   - Removed hbitmap_copy and bdrv_dirty_bitmap_copy.
>
>   - Added a small fixup patch:
>     - Update all granularity fields to be uint64_t.
>     - Update documentation around BdrvDirtyBitmap structure.
>
>   - Modified transactions to obey frozen attribute of BdrvDirtyBitmaps.
>
>   - Added frozen attribute to the info query.
>
> v10 (Overview):
>
>   - I've included one of Vladimir's bitmap fixes as patch #1.
>
>   - QMP commands and transactions are now protected via
>     aio_context functions.
>
>   - QMP commands use "node-ref" as a parameter name now. Reasoning
>     is thus: Either a "device name" or a "node name" can be used to
>     reference a BDS, which is the key item we are actually acting
>     on with these bitmap commands. Thus, I refer to this unified
>     parameter as a "Node Reference," or "node-ref."
>
>     We could also argue for "backend-ref" or "device-ref" for the
>     reverse semantics: where we accept a unified parameter, but we
>     intend to resolve it to the BlockBackend instead of resolving
>     the parameter given to the BlockDriverState.
>
>     Or, we could use "reference" for both cases, and to match the
>     existing BlockdevRef command.
>
>   - All QMP commands added are now per-node via a unified parameter
>     name. Though backup only operates on "devices," you are free to
>     create bitmaps for any arbitrary node you wish. It is obviously
>     only useful for the root node, currently.
>
>   - Bitmap Sync modes (CONSUME, RESET) are removed. See below
>     (changelog, RFC questions) for more details.
>
>   - Code to recover the bitmap after a failure has been added,
>     but I have some major questions about drive_backup guarantees.
>     See RFC questions.
>
> v10 (Detailed Changelog):
>
>     (1/13) New Patch:
>   - Included Vladimir Sementsov-Ogievskiy's patch that clarifies
>     the semantics of the bitmap primitives.
>
>     (3/13):
>   - Edited function names for consistency (Stefanha)
>   - Removed compile-time constants (Stefanha)
>   - Acquire aio_context for bitmap add/remove (Stefanha)
>   - Documented optional granularity for bitmap-add in
>     qmp-commands.hx file (Eric Blake)
>   - block_dirty_bitmap_lookup moved forward to this patch to allow
>     more re-use. (Stefanha)
>   - Fixed a problem where the block_dirty_bitmap_lookup didn't
>     always set an error if it returned NULL.
>   - Added an optional return BDS lookup parameter to
>     bdrv_dirty_bitmap_lookup.
>   - Renamed "device" to "node-ref" for block_dirty_bitmap_lookup,
>     adjusted calls to bdrv_lookup_bs() to reflect unified
>     parameter usage.
>   - qmp_block_dirty_bitmap_{add,remove} now reference arbitrary
>     node names via @node-ref.
>
>     (4/13):
>   - Default granularity and granularity getters are both
>     now uint64_t (Stefanha)
>
>     (5/13):
>   - Added documentation to warn about the necessity of updating
>     the hbitmap deep copy. (Stefanha)
>
>     (6/13)
>   - Renamed bdrv_reset_dirty_bitmap to bdrv_clear_dirty_bitmap
>     to be consistent with Vladimir's patches.
>   - Removed const qualifier for bdrv_copy_dirty_bitmap,
>     to accommodate patch 8.
>
>     (7/13) New Patch:
>   - Added an hbitmap_merge operation to join two bitmaps together.
>
>     (8/13) New Patch:
>   - Added bdrv_reclaim_dirty_bitmap() to allow us to "roll back" a
>     bitmap into the bitmap that it was spawned from. This will let
>     us maintain an accurate account of dirty sectors even after a
>     failure.
>   - This adds an "originator" pointer to the BdrvDirtyBitmap and
>     is why "const" was removed for copy.
>
>     (9/13):
>   - QMP semantics changes as outlined for Patch #3.
>   - Enable/Disable now protected by aio_context (Stefanha)
>
>     (10/13):
>   - Add coroutine_fn annotation to block backup helper. (Stefanha)
>   - Removed sync_bitmap_gran from BackupBlockJob, just use the
>     getter on the BdrvDirtyBitmap instead. (Stefanha)
>   - bdrv_dirty_iter_set was renamed to bdrv_set_dirty_iter.
>   - Calls to bdrv_reset_dirty_bitmap are modified to
>     bdrv_clear_dirty_bitmap to reflect the rename in patch #6.
>   - Bitmap usage modes (RESET vs. CONSUME) has been deleted, for
>     the reason of targeting a simpler core usage first before
>     targeting optimizations. CONSUME is particularly problematic
>     in the case of errors; so this mode is omitted for now.
>   - Adjusted error message to use MirrorSyncMode enum, not
>     (incorrectly) the BitmapSyncMode enum.
>   - In the event of a failure, the sync_bitmap is now merged back
>     into the original bitmap so that we do not lose any dirty
>     bitmap information needlessly.
>
>     (11/13):
>   - Changed block_dirty_bitmap_add_abort to use
>     qmp_block_dirty_bitmap_remove:
>      - Old code used bdrv_lookup_bs to acquire bitmap and bs
>        anyway, and ignored the failure case.
>      - New code relies on the same information, and with a NULL
>        errp pointer we will similarly ignore the failure case.
>        prepare() should have properly vetted this information
>        before this point anyway.
>        This new code is also now protected via aio_context through
>        the use of the QMP commands.
>   - More code re-use of block_dirty_bitmap_lookup to get both the
>     bs and bitmap pointers.
>   - aio_context protection and cleanup in new abort methods.
>
>     (13/13):
>   - Modified test for new parameter names.
>
> v9:
>   - Edited commit message, for English embetterment (02/10)
>   - Rebased on top of stefanha/block-next (06,08/10)
>   - Adjusted error message and line length (07/10)
>
> v8:
>   - Changed int64_t return for bdrv_dbm_calc_def_granularity to uint64_t (2/10)
>   - Updated commit message (2/10)
>   - Removed redundant check for null in device parameter (2/10)
>   - Removed comment cruft. (2/10)
>   - Removed redundant local_err propagation (several)
>   - Updated commit message (3/10)
>   - Fix HBitmap copy loop index (4/10)
>   - Remove redundant ternary (5/10)
>   - Shift up the block_dirty_bitmap_lookup function (6/10)
>   - Error messages cleanup (7/10)
>   - Add an assertion to explain the re-use of .prepare() for two transactions.
>     (8/10)
>   - Removed BDS argument from bitmap enable/disable helper; it was unused. (8/10)
>
> v7: (highlights)
>   - First version being authored by jsnow
>   - Addressed most list feedback from V6, many small changes.
>     All feedback was either addressed on-list (as a wontfix) or patched.
>   - Replaced all error_set with error_setg
>   - Replaced all bdrv_find with bdrv_lookup_bs()
>   - Adjusted the max granularity to share a common function with
>     backup/mirror that attempts to "guess" a reasonable default.
>     It clamps between [4K,64K] currently.
>   - The BdrvDirtyBitmap object now counts granularity exclusively in
>     bytes to match its interface.
>     It leaves the sector granularity concerns to HBitmap.
>   - Reworked the backup loop to utilize the hbitmap iterator.
>     There are some extra concerns to handle arrhythmic cases where the
>     granularity of the bitmap does not match the backup cluster size.
>     This iteration works best when it does match, but it's not a
>     deal-breaker if it doesn't -- it just gets less efficient.
>   - Reworked the transactional functions so that abort() wouldn't "undo"
>     a redundant command. They now have been split into a prepare and a
>     commit function (with state) and do not provide an abort command.
>   - Added a block_dirty_bitmap_lookup(device, name, errp) function to
>     shorten a few of the commands added in this series, particularly
>     qmp_enable, qmp_disable, and the transaction preparations.
>
> v6: Re-send of v5.
>
> v5: Rebase to master.
>
> v4: Last version tailored by Fam Zheng.
>
> ==
>
> Fam Zheng (7):
>    qapi: Add optional field "name" to block dirty bitmap
>    qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
>    block: Introduce bdrv_dirty_bitmap_granularity()
>    qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable
>    qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>      disable}
>    qmp: Add dirty bitmap status fields in query-block
>    qemu-iotests: Add tests for drive-backup sync=dirty-bitmap
>
> John Snow (5):
>    block: Add bdrv_clear_dirty_bitmap
>    hbitmap: add hbitmap_merge
>    block: Add bitmap successors
>    qmp: Add support of "dirty-bitmap" sync mode for drive-backup
>    block: BdrvDirtyBitmap miscellaneous fixup
>
> Vladimir Sementsov-Ogievskiy (1):
>    block: fix spoiling all dirty bitmaps by mirror and migration
>
>   block.c                       | 254 +++++++++++++++++++++++++++++++++++++--
>   block/backup.c                | 120 +++++++++++++++----
>   block/mirror.c                |  27 ++---
>   blockdev.c                    | 273 +++++++++++++++++++++++++++++++++++++++++-
>   hmp.c                         |   3 +-
>   include/block/block.h         |  31 ++++-
>   include/block/block_int.h     |   2 +
>   include/qemu/hbitmap.h        |  11 ++
>   migration/block.c             |   7 +-
>   qapi-schema.json              |   5 +-
>   qapi/block-core.json          | 103 +++++++++++++++-
>   qmp-commands.hx               |  68 ++++++++++-
>   tests/qemu-iotests/056        |  33 ++++-
>   tests/qemu-iotests/056.out    |   4 +-
>   tests/qemu-iotests/iotests.py |   8 ++
>   util/hbitmap.c                |  28 +++++
>   16 files changed, 910 insertions(+), 67 deletions(-)
>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-21  9:34               ` Markus Armbruster
  2015-01-21 15:51                 ` Eric Blake
@ 2015-01-30 14:32                 ` Kevin Wolf
  2015-01-30 17:04                   ` John Snow
  1 sibling, 1 reply; 54+ messages in thread
From: Kevin Wolf @ 2015-01-30 14:32 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: famz, qemu-devel, Max Reitz, vsementsov, stefanha, John Snow

Am 21.01.2015 um 10:34 hat Markus Armbruster geschrieben:
> I'm afraid I forgot much of the discussion we had before the break, and
> only now it's coming back, slowly.
> 
> Quoting myself on naming parameters identifying nodes[*]:
> 
>     John Snow pointed out to me that we still haven't spelled out how this
>     single parameter should be named.
> 
>     On obvious option is calling it node-name, or FOO-node-name when we have
>     several.  However, we'd then have two subtly different kinds of
>     parameters called like that: the old ones accept *only* node names, the
>     new ones also accept backend names, which automatically resolve to the
>     backend's root node.
> 
>     Three ways to cope with that:
> 
>     * Find a better name.
> 
>     * Make the old ones accept backend names, too.  Only a few, not that
>       much work.  However, there are exceptions:
> 
>       - blockdev-add's node-name *defines* the node name.
> 
>       - query-named-block-nodes's node-name *is* the node's name.
> 
>     * Stop worrying and embrace the inconsistency.  The affected commands
>       are headed for deprecation anyway.
> 
>     I think I'd go with "node" or "FOO-node" for parameters that reference
>     nodes and accept both node names and backend names, and refrain from
>     touching the existing node-name parameters.

Wasn't the conclusion last time that we would try to find a better name
for new commands and leave old commands alone because they are going to
become deprecated? That is, a combination of your first and last option?

> Let's go through existing uses of @node-name again:
> 
> 1. Define a node name
> 
>    QMP commands blockdev-add (type BlockdevOptionsBase), drive-mirror
> 
> 2. Report a node name
> 
>    QMP command query-named-block-nodes (type BlockDeviceInfo)

Whatever name we end up using, 1. and 2. should probably use the same.

> 3. Node reference with backend names permitted for convenience
> 
>    New QMP command block-dirty-bitmap-add (type BlockDirtyBitmapAdd) and
>    others
> 
> 4. Node reference with backend names not permitted
>   
>    QMP commands drive-mirror @replaces, change-backing-file
>    @image-node-name
> 
>    We may want to support the "backend name resolves to root node"
>    convenience feature here, for consistency.  Then this moves under 3.
> 
>    Note interface wart: change-backing-file additionally requires the
>    backend owning the node.  We need the backend to set op-blockers, we
>    can't easily find it from the node, so we make the user point it out
>    to us.

These shouldn't be existing. As you say, we should move them to 3.

> 5. "Pair of names" node reference, specify exactly one
> 
>    QMP commands block_passwd, block_resize, blockdev-snapshot-sync
> 
>    We can ignore this one, because we intend to replace the commands and
>    deprecate the old ones.

Agreed, these shouldn't be existing either.

> If I understand you correctly, you're proposing to use @node-name or
> @FOO-node-name when the value must be a node name (items 1+2 and 4), and
> @node-ref or @FOO-node-ref where we additionally support the "backend
> name resolves to root node" convenience feature (item 3).
> 
> Is that a fair description of your proposal?
> 
> PRO: the name makes it clear when the convenience feature is supported.
> 
> CON: if we eliminate 4 by supporting the convenience feature, we either
> create ugly exceptions to the naming convention, or rename the
> parameters.
> 
> Opinions?

If we don't have any cases where node names are allowed, but backend
names are not, then there is no reason to have two different names. I've
yet to see a reason for having commands that can accept node names, but
not backend names.

It's a bit different when the command can already accept both, but uses
two separate arguments for it. But I think most of them will be
deprecated, so we can ignore them here.

As for the naming, I'm not that sure that it's even useful to add
something to the field name. After all, this is really the _type_ of the
object, not the name. We don't have fields like 'read-only-bool' either.

If we're more specifically looking at things that actually refer to
block devices, you already mentioned drive-mirrors @replaces, which is a
great name in my opinion. @replaces-node-ref wouldn't improve anything.
Likewise, blockdev-add already refers to 'file' and 'backing' instead of
'file-node' or 'backing-node-ref'.

This probably means that FOO-node-{ref,name} shouldn't exist, because
just FOO is as good or better. The question is a bit harder where there
is only one node involved and we don't have a nice word to describe its
role for the command. This is where we used to use 'device' in the past,
when node-level addressing didn't exist yet. I think just 'node' would
be fine there.

Kevin

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-30 14:32                 ` Kevin Wolf
@ 2015-01-30 17:04                   ` John Snow
  2015-01-30 18:52                     ` Kevin Wolf
  0 siblings, 1 reply; 54+ messages in thread
From: John Snow @ 2015-01-30 17:04 UTC (permalink / raw)
  To: Kevin Wolf, Markus Armbruster
  Cc: famz, qemu-devel, Max Reitz, vsementsov, stefanha



On 01/30/2015 09:32 AM, Kevin Wolf wrote:
> Am 21.01.2015 um 10:34 hat Markus Armbruster geschrieben:
>> I'm afraid I forgot much of the discussion we had before the break, and
>> only now it's coming back, slowly.
>>
>> Quoting myself on naming parameters identifying nodes[*]:
>>
>>      John Snow pointed out to me that we still haven't spelled out how this
>>      single parameter should be named.
>>
>>      On obvious option is calling it node-name, or FOO-node-name when we have
>>      several.  However, we'd then have two subtly different kinds of
>>      parameters called like that: the old ones accept *only* node names, the
>>      new ones also accept backend names, which automatically resolve to the
>>      backend's root node.
>>
>>      Three ways to cope with that:
>>
>>      * Find a better name.
>>
>>      * Make the old ones accept backend names, too.  Only a few, not that
>>        much work.  However, there are exceptions:
>>
>>        - blockdev-add's node-name *defines* the node name.
>>
>>        - query-named-block-nodes's node-name *is* the node's name.
>>
>>      * Stop worrying and embrace the inconsistency.  The affected commands
>>        are headed for deprecation anyway.
>>
>>      I think I'd go with "node" or "FOO-node" for parameters that reference
>>      nodes and accept both node names and backend names, and refrain from
>>      touching the existing node-name parameters.
>
> Wasn't the conclusion last time that we would try to find a better name
> for new commands and leave old commands alone because they are going to
> become deprecated? That is, a combination of your first and last option?
>

That was my impression, too: Use a new name for new commands and then 
slowly phase out the old things. This makes the new name clear as to 
what it supports (BOTH backends and nodes through a common namespace) to 
external management utilities like libvirt.

That's why I just rolled 'node-ref.'

>> Let's go through existing uses of @node-name again:
>>
>> 1. Define a node name
>>
>>     QMP commands blockdev-add (type BlockdevOptionsBase), drive-mirror
>>
>> 2. Report a node name
>>
>>     QMP command query-named-block-nodes (type BlockDeviceInfo)
>
> Whatever name we end up using, 1. and 2. should probably use the same.

Should they? If these commands accept directly *node* names and have no 
chance of referencing a backend, maybe they should use different 
parameter names.

>
>> 3. Node reference with backend names permitted for convenience
>>
>>     New QMP command block-dirty-bitmap-add (type BlockDirtyBitmapAdd) and
>>     others
>>
>> 4. Node reference with backend names not permitted
>>
>>     QMP commands drive-mirror @replaces, change-backing-file
>>     @image-node-name
>>
>>     We may want to support the "backend name resolves to root node"
>>     convenience feature here, for consistency.  Then this moves under 3.
>>
>>     Note interface wart: change-backing-file additionally requires the
>>     backend owning the node.  We need the backend to set op-blockers, we
>>     can't easily find it from the node, so we make the user point it out
>>     to us.
>
> These shouldn't be existing. As you say, we should move them to 3.
>

Technically #3 here isn't a usage of "node-name," because... I didn't 
use node-name for these commands. Unless I am reading this list wrong, 
but it's definitely not an "existing use."

I don't have any opinions about #4; presumably that's something we're 
aiming to phase out.

>> 5. "Pair of names" node reference, specify exactly one
>>
>>     QMP commands block_passwd, block_resize, blockdev-snapshot-sync
>>
>>     We can ignore this one, because we intend to replace the commands and
>>     deprecate the old ones.
>
> Agreed, these shouldn't be existing either.
>
>> If I understand you correctly, you're proposing to use @node-name or
>> @FOO-node-name when the value must be a node name (items 1+2 and 4), and
>> @node-ref or @FOO-node-ref where we additionally support the "backend
>> name resolves to root node" convenience feature (item 3).
>>
>> Is that a fair description of your proposal?
>>
>> PRO: the name makes it clear when the convenience feature is supported.
>>
>> CON: if we eliminate 4 by supporting the convenience feature, we either
>> create ugly exceptions to the naming convention, or rename the
>> parameters.
>>
>> Opinions?
>
> If we don't have any cases where node names are allowed, but backend
> names are not, then there is no reason to have two different names. I've
> yet to see a reason for having commands that can accept node names, but
> not backend names.
>
> It's a bit different when the command can already accept both, but uses
> two separate arguments for it. But I think most of them will be
> deprecated, so we can ignore them here.
>
> As for the naming, I'm not that sure that it's even useful to add
> something to the field name. After all, this is really the _type_ of the
> object, not the name. We don't have fields like 'read-only-bool' either.
>
> If we're more specifically looking at things that actually refer to
> block devices, you already mentioned drive-mirrors @replaces, which is a
> great name in my opinion. @replaces-node-ref wouldn't improve anything.
> Likewise, blockdev-add already refers to 'file' and 'backing' instead of
> 'file-node' or 'backing-node-ref'.
>
> This probably means that FOO-node-{ref,name} shouldn't exist, because
> just FOO is as good or better. The question is a bit harder where there
> is only one node involved and we don't have a nice word to describe its
> role for the command. This is where we used to use 'device' in the past,
> when node-level addressing didn't exist yet. I think just 'node' would
> be fine there.
>
> Kevin
>

I'd be happy with naming things "node" (or node-ref, either is fine) 
going forward; and leaving the old commands (node-name) alone. I seem to 
recall there was a reason we didn't want to just keep using node-name 
for the new unified parameters.

It makes sense that if we don't keep a "this means node name ONLY" 
parameter for any command then there is no reason to make some 
distinction between that and "this parameter accepts both," but I think 
for purposes of libvirt, it is helpful to have a concrete distinction 
between versions that it can rely on.

Could be mis-remembering, this whole discussion is spread out over 
months now.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series
  2015-01-30 10:24 ` Vladimir Sementsov-Ogievskiy
@ 2015-01-30 18:46   ` John Snow
  0 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-01-30 18:46 UTC (permalink / raw)
  To: famz
  Cc: kwolf, armbru, qemu-devel, mreitz, Vladimir Sementsov-Ogievskiy,
	stefanha



On 01/30/2015 05:24 AM, Vladimir Sementsov-Ogievskiy wrote:
> About added functions for BdrvDirtyBitmap:
>
> some functions has needless BlockDriverState* parameter, and others -
> doesn't:
>
> with needless *bs:
> bdrv_dirty_bitmap_make_anon
> bdrv_dirty_bitmap_granularity
> bdrv_clear_dirty_bitmap
>
> without *bs:
> bdrv_dirty_bitmap_enabled
> bdrv_disable_dirty_bitmap
> bdrv_enable_dirty_bitmap
>
> I think, to be consistent, onlly one of two ways should be chosen:
> 1) all bdrv_dirty_bitmap_* functions has "BlockDriverState* bs"
> parameter, maybe needless
> 2) only bdrv_dirty_bitmap_* function that need "BlockDriverState* bs"
> parameter has it
>
> Personally, I prefer the second one.
>
> Best regards,
> Vladimir

Fair enough, it is inconsistent. I was mostly following Fam's lead for 
his prototypes, so I could go either way with it.

Before I cull the unused parameters, though:

Fam, do we have a strong reason for why we want to maintain the unused 
BDS parameter for some of these functions? (Like making sure a caller 
HAS a BDS before they call these functions?)

Thanks,
--js

>
> On 12.01.2015 19:30, John Snow wrote:
>> Welcome to version 11. I hope you are enjoying our regular newsletter.
>>
>> This patchset enables the in-memory part of the incremental backup
>> feature. A patchset by Vladimir Sementsov-Ogievskiy enables the
>> migration of in-memory dirty bitmaps, and a future patchset will
>> enable the storage and retrieval of dirty bitmaps to and from permanent
>> storage.
>>
>> Enough changes have been made that most Reviewed-By lines from
>> previous iterations have been removed. (Sorry!)
>>
>> This series was originally authored by Fam Zheng;
>> his cover letter is included below.
>>
>> ~John Snow
>>
>> =================================================================
>>
>> This is the in memory part of the incremental backup feature.
>>
>> With the added commands, we can create a bitmap on a block
>> backend, from which point of time all the writes are tracked by
>> the bitmap, marking sectors as dirty. Later, we call drive-backup
>> and pass the bitmap to it, to do an incremental backup.
>>
>> See the last patch which adds some tests for this use case.
>>
>> Fam
>>
>> =================================================================
>>
>> For convenience, this patchset is available on github:
>>                  https://github.com/jnsnow/qemu/commits/dbm-backup
>>
>> v11:
>>
>>   - Instead of copying BdrvDirtyBitmaps and keeping a pointer to the
>>     object we were copied from, we instead "freeze" a bitmap in-place
>>     without copying it. On success, we thaw and delete the bitmap.
>>     On failure, we merge the bitmap with a "successor," which is an
>>     anonymous bitmap attached as a child that records writes for us
>>     for the duration of the backup operation.
>>
>>     This means that incremental backups can NEVER BE RETRIED in a
>>     deterministic fashion. If an incremental backup fails on a set
>>     of dirty sectors {x}, and a new set of dirty sectors {y} are
>>     introduced during the backup, then any possible retry action
>>     on an incremental backup can only operate on {x,y}. There is no
>>     way to get an incremental backup "as it would have been."
>>
>>     So, the failure mode for incremental backup is to try again,
>>     and the resulting image will simply be a differential from the
>>     last successful dirty bitmap backup.
>>
>>   - Removed hbitmap_copy and bdrv_dirty_bitmap_copy.
>>
>>   - Added a small fixup patch:
>>     - Update all granularity fields to be uint64_t.
>>     - Update documentation around BdrvDirtyBitmap structure.
>>
>>   - Modified transactions to obey frozen attribute of BdrvDirtyBitmaps.
>>
>>   - Added frozen attribute to the info query.
>>
>> v10 (Overview):
>>
>>   - I've included one of Vladimir's bitmap fixes as patch #1.
>>
>>   - QMP commands and transactions are now protected via
>>     aio_context functions.
>>
>>   - QMP commands use "node-ref" as a parameter name now. Reasoning
>>     is thus: Either a "device name" or a "node name" can be used to
>>     reference a BDS, which is the key item we are actually acting
>>     on with these bitmap commands. Thus, I refer to this unified
>>     parameter as a "Node Reference," or "node-ref."
>>
>>     We could also argue for "backend-ref" or "device-ref" for the
>>     reverse semantics: where we accept a unified parameter, but we
>>     intend to resolve it to the BlockBackend instead of resolving
>>     the parameter given to the BlockDriverState.
>>
>>     Or, we could use "reference" for both cases, and to match the
>>     existing BlockdevRef command.
>>
>>   - All QMP commands added are now per-node via a unified parameter
>>     name. Though backup only operates on "devices," you are free to
>>     create bitmaps for any arbitrary node you wish. It is obviously
>>     only useful for the root node, currently.
>>
>>   - Bitmap Sync modes (CONSUME, RESET) are removed. See below
>>     (changelog, RFC questions) for more details.
>>
>>   - Code to recover the bitmap after a failure has been added,
>>     but I have some major questions about drive_backup guarantees.
>>     See RFC questions.
>>
>> v10 (Detailed Changelog):
>>
>>     (1/13) New Patch:
>>   - Included Vladimir Sementsov-Ogievskiy's patch that clarifies
>>     the semantics of the bitmap primitives.
>>
>>     (3/13):
>>   - Edited function names for consistency (Stefanha)
>>   - Removed compile-time constants (Stefanha)
>>   - Acquire aio_context for bitmap add/remove (Stefanha)
>>   - Documented optional granularity for bitmap-add in
>>     qmp-commands.hx file (Eric Blake)
>>   - block_dirty_bitmap_lookup moved forward to this patch to allow
>>     more re-use. (Stefanha)
>>   - Fixed a problem where the block_dirty_bitmap_lookup didn't
>>     always set an error if it returned NULL.
>>   - Added an optional return BDS lookup parameter to
>>     bdrv_dirty_bitmap_lookup.
>>   - Renamed "device" to "node-ref" for block_dirty_bitmap_lookup,
>>     adjusted calls to bdrv_lookup_bs() to reflect unified
>>     parameter usage.
>>   - qmp_block_dirty_bitmap_{add,remove} now reference arbitrary
>>     node names via @node-ref.
>>
>>     (4/13):
>>   - Default granularity and granularity getters are both
>>     now uint64_t (Stefanha)
>>
>>     (5/13):
>>   - Added documentation to warn about the necessity of updating
>>     the hbitmap deep copy. (Stefanha)
>>
>>     (6/13)
>>   - Renamed bdrv_reset_dirty_bitmap to bdrv_clear_dirty_bitmap
>>     to be consistent with Vladimir's patches.
>>   - Removed const qualifier for bdrv_copy_dirty_bitmap,
>>     to accommodate patch 8.
>>
>>     (7/13) New Patch:
>>   - Added an hbitmap_merge operation to join two bitmaps together.
>>
>>     (8/13) New Patch:
>>   - Added bdrv_reclaim_dirty_bitmap() to allow us to "roll back" a
>>     bitmap into the bitmap that it was spawned from. This will let
>>     us maintain an accurate account of dirty sectors even after a
>>     failure.
>>   - This adds an "originator" pointer to the BdrvDirtyBitmap and
>>     is why "const" was removed for copy.
>>
>>     (9/13):
>>   - QMP semantics changes as outlined for Patch #3.
>>   - Enable/Disable now protected by aio_context (Stefanha)
>>
>>     (10/13):
>>   - Add coroutine_fn annotation to block backup helper. (Stefanha)
>>   - Removed sync_bitmap_gran from BackupBlockJob, just use the
>>     getter on the BdrvDirtyBitmap instead. (Stefanha)
>>   - bdrv_dirty_iter_set was renamed to bdrv_set_dirty_iter.
>>   - Calls to bdrv_reset_dirty_bitmap are modified to
>>     bdrv_clear_dirty_bitmap to reflect the rename in patch #6.
>>   - Bitmap usage modes (RESET vs. CONSUME) has been deleted, for
>>     the reason of targeting a simpler core usage first before
>>     targeting optimizations. CONSUME is particularly problematic
>>     in the case of errors; so this mode is omitted for now.
>>   - Adjusted error message to use MirrorSyncMode enum, not
>>     (incorrectly) the BitmapSyncMode enum.
>>   - In the event of a failure, the sync_bitmap is now merged back
>>     into the original bitmap so that we do not lose any dirty
>>     bitmap information needlessly.
>>
>>     (11/13):
>>   - Changed block_dirty_bitmap_add_abort to use
>>     qmp_block_dirty_bitmap_remove:
>>      - Old code used bdrv_lookup_bs to acquire bitmap and bs
>>        anyway, and ignored the failure case.
>>      - New code relies on the same information, and with a NULL
>>        errp pointer we will similarly ignore the failure case.
>>        prepare() should have properly vetted this information
>>        before this point anyway.
>>        This new code is also now protected via aio_context through
>>        the use of the QMP commands.
>>   - More code re-use of block_dirty_bitmap_lookup to get both the
>>     bs and bitmap pointers.
>>   - aio_context protection and cleanup in new abort methods.
>>
>>     (13/13):
>>   - Modified test for new parameter names.
>>
>> v9:
>>   - Edited commit message, for English embetterment (02/10)
>>   - Rebased on top of stefanha/block-next (06,08/10)
>>   - Adjusted error message and line length (07/10)
>>
>> v8:
>>   - Changed int64_t return for bdrv_dbm_calc_def_granularity to
>> uint64_t (2/10)
>>   - Updated commit message (2/10)
>>   - Removed redundant check for null in device parameter (2/10)
>>   - Removed comment cruft. (2/10)
>>   - Removed redundant local_err propagation (several)
>>   - Updated commit message (3/10)
>>   - Fix HBitmap copy loop index (4/10)
>>   - Remove redundant ternary (5/10)
>>   - Shift up the block_dirty_bitmap_lookup function (6/10)
>>   - Error messages cleanup (7/10)
>>   - Add an assertion to explain the re-use of .prepare() for two
>> transactions.
>>     (8/10)
>>   - Removed BDS argument from bitmap enable/disable helper; it was
>> unused. (8/10)
>>
>> v7: (highlights)
>>   - First version being authored by jsnow
>>   - Addressed most list feedback from V6, many small changes.
>>     All feedback was either addressed on-list (as a wontfix) or patched.
>>   - Replaced all error_set with error_setg
>>   - Replaced all bdrv_find with bdrv_lookup_bs()
>>   - Adjusted the max granularity to share a common function with
>>     backup/mirror that attempts to "guess" a reasonable default.
>>     It clamps between [4K,64K] currently.
>>   - The BdrvDirtyBitmap object now counts granularity exclusively in
>>     bytes to match its interface.
>>     It leaves the sector granularity concerns to HBitmap.
>>   - Reworked the backup loop to utilize the hbitmap iterator.
>>     There are some extra concerns to handle arrhythmic cases where the
>>     granularity of the bitmap does not match the backup cluster size.
>>     This iteration works best when it does match, but it's not a
>>     deal-breaker if it doesn't -- it just gets less efficient.
>>   - Reworked the transactional functions so that abort() wouldn't "undo"
>>     a redundant command. They now have been split into a prepare and a
>>     commit function (with state) and do not provide an abort command.
>>   - Added a block_dirty_bitmap_lookup(device, name, errp) function to
>>     shorten a few of the commands added in this series, particularly
>>     qmp_enable, qmp_disable, and the transaction preparations.
>>
>> v6: Re-send of v5.
>>
>> v5: Rebase to master.
>>
>> v4: Last version tailored by Fam Zheng.
>>
>> ==
>>
>> Fam Zheng (7):
>>    qapi: Add optional field "name" to block dirty bitmap
>>    qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
>>    block: Introduce bdrv_dirty_bitmap_granularity()
>>    qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable
>>    qapi: Add transaction support to block-dirty-bitmap-{add, enable,
>>      disable}
>>    qmp: Add dirty bitmap status fields in query-block
>>    qemu-iotests: Add tests for drive-backup sync=dirty-bitmap
>>
>> John Snow (5):
>>    block: Add bdrv_clear_dirty_bitmap
>>    hbitmap: add hbitmap_merge
>>    block: Add bitmap successors
>>    qmp: Add support of "dirty-bitmap" sync mode for drive-backup
>>    block: BdrvDirtyBitmap miscellaneous fixup
>>
>> Vladimir Sementsov-Ogievskiy (1):
>>    block: fix spoiling all dirty bitmaps by mirror and migration
>>
>>   block.c                       | 254
>> +++++++++++++++++++++++++++++++++++++--
>>   block/backup.c                | 120 +++++++++++++++----
>>   block/mirror.c                |  27 ++---
>>   blockdev.c                    | 273
>> +++++++++++++++++++++++++++++++++++++++++-
>>   hmp.c                         |   3 +-
>>   include/block/block.h         |  31 ++++-
>>   include/block/block_int.h     |   2 +
>>   include/qemu/hbitmap.h        |  11 ++
>>   migration/block.c             |   7 +-
>>   qapi-schema.json              |   5 +-
>>   qapi/block-core.json          | 103 +++++++++++++++-
>>   qmp-commands.hx               |  68 ++++++++++-
>>   tests/qemu-iotests/056        |  33 ++++-
>>   tests/qemu-iotests/056.out    |   4 +-
>>   tests/qemu-iotests/iotests.py |   8 ++
>>   util/hbitmap.c                |  28 +++++
>>   16 files changed, 910 insertions(+), 67 deletions(-)
>>
>

-- 
—js

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-30 17:04                   ` John Snow
@ 2015-01-30 18:52                     ` Kevin Wolf
  2015-02-02 10:10                       ` Markus Armbruster
  0 siblings, 1 reply; 54+ messages in thread
From: Kevin Wolf @ 2015-01-30 18:52 UTC (permalink / raw)
  To: John Snow
  Cc: famz, qemu-devel, Markus Armbruster, Max Reitz, vsementsov, stefanha

Am 30.01.2015 um 18:04 hat John Snow geschrieben:
> 
> 
> On 01/30/2015 09:32 AM, Kevin Wolf wrote:
> >Am 21.01.2015 um 10:34 hat Markus Armbruster geschrieben:
> >>I'm afraid I forgot much of the discussion we had before the break, and
> >>only now it's coming back, slowly.
> >>
> >>Quoting myself on naming parameters identifying nodes[*]:
> >>
> >>     John Snow pointed out to me that we still haven't spelled out how this
> >>     single parameter should be named.
> >>
> >>     On obvious option is calling it node-name, or FOO-node-name when we have
> >>     several.  However, we'd then have two subtly different kinds of
> >>     parameters called like that: the old ones accept *only* node names, the
> >>     new ones also accept backend names, which automatically resolve to the
> >>     backend's root node.
> >>
> >>     Three ways to cope with that:
> >>
> >>     * Find a better name.
> >>
> >>     * Make the old ones accept backend names, too.  Only a few, not that
> >>       much work.  However, there are exceptions:
> >>
> >>       - blockdev-add's node-name *defines* the node name.
> >>
> >>       - query-named-block-nodes's node-name *is* the node's name.
> >>
> >>     * Stop worrying and embrace the inconsistency.  The affected commands
> >>       are headed for deprecation anyway.
> >>
> >>     I think I'd go with "node" or "FOO-node" for parameters that reference
> >>     nodes and accept both node names and backend names, and refrain from
> >>     touching the existing node-name parameters.
> >
> >Wasn't the conclusion last time that we would try to find a better name
> >for new commands and leave old commands alone because they are going to
> >become deprecated? That is, a combination of your first and last option?
> >
> 
> That was my impression, too: Use a new name for new commands and
> then slowly phase out the old things. This makes the new name clear
> as to what it supports (BOTH backends and nodes through a common
> namespace) to external management utilities like libvirt.
> 
> That's why I just rolled 'node-ref.'

Yes, I agree with that in principle. I called it 'node' below because
that's shorter and doesn't include type information in the name, but if
everyone preferred 'node-ref', I wouldn't have a problem with it either.

> >>Let's go through existing uses of @node-name again:
> >>
> >>1. Define a node name
> >>
> >>    QMP commands blockdev-add (type BlockdevOptionsBase), drive-mirror
> >>
> >>2. Report a node name
> >>
> >>    QMP command query-named-block-nodes (type BlockDeviceInfo)
> >
> >Whatever name we end up using, 1. and 2. should probably use the same.
> 
> Should they? If these commands accept directly *node* names and have
> no chance of referencing a backend, maybe they should use different
> parameter names.

Note that these cases don't refer to a node, but they define/return the
name of a node. No way that could ever be a backend name, unless we
broke the code.

> >>3. Node reference with backend names permitted for convenience
> >>
> >>    New QMP command block-dirty-bitmap-add (type BlockDirtyBitmapAdd) and
> >>    others
> >>
> >>4. Node reference with backend names not permitted
> >>
> >>    QMP commands drive-mirror @replaces, change-backing-file
> >>    @image-node-name
> >>
> >>    We may want to support the "backend name resolves to root node"
> >>    convenience feature here, for consistency.  Then this moves under 3.
> >>
> >>    Note interface wart: change-backing-file additionally requires the
> >>    backend owning the node.  We need the backend to set op-blockers, we
> >>    can't easily find it from the node, so we make the user point it out
> >>    to us.
> >
> >These shouldn't be existing. As you say, we should move them to 3.
> >
> 
> Technically #3 here isn't a usage of "node-name," because... I
> didn't use node-name for these commands. Unless I am reading this
> list wrong, but it's definitely not an "existing use."
> 
> I don't have any opinions about #4; presumably that's something
> we're aiming to phase out.

Yes. Where "phasing out" simply means to extend it so that it accepts
backend names. That should in theory be an easy change, except that
@image-node-name has a name that isn't quite compatible with it...

> >>5. "Pair of names" node reference, specify exactly one
> >>
> >>    QMP commands block_passwd, block_resize, blockdev-snapshot-sync
> >>
> >>    We can ignore this one, because we intend to replace the commands and
> >>    deprecate the old ones.
> >
> >Agreed, these shouldn't be existing either.
> >
> >>If I understand you correctly, you're proposing to use @node-name or
> >>@FOO-node-name when the value must be a node name (items 1+2 and 4), and
> >>@node-ref or @FOO-node-ref where we additionally support the "backend
> >>name resolves to root node" convenience feature (item 3).
> >>
> >>Is that a fair description of your proposal?
> >>
> >>PRO: the name makes it clear when the convenience feature is supported.
> >>
> >>CON: if we eliminate 4 by supporting the convenience feature, we either
> >>create ugly exceptions to the naming convention, or rename the
> >>parameters.
> >>
> >>Opinions?
> >
> >If we don't have any cases where node names are allowed, but backend
> >names are not, then there is no reason to have two different names. I've
> >yet to see a reason for having commands that can accept node names, but
> >not backend names.
> >
> >It's a bit different when the command can already accept both, but uses
> >two separate arguments for it. But I think most of them will be
> >deprecated, so we can ignore them here.
> >
> >As for the naming, I'm not that sure that it's even useful to add
> >something to the field name. After all, this is really the _type_ of the
> >object, not the name. We don't have fields like 'read-only-bool' either.
> >
> >If we're more specifically looking at things that actually refer to
> >block devices, you already mentioned drive-mirrors @replaces, which is a
> >great name in my opinion. @replaces-node-ref wouldn't improve anything.
> >Likewise, blockdev-add already refers to 'file' and 'backing' instead of
> >'file-node' or 'backing-node-ref'.
> >
> >This probably means that FOO-node-{ref,name} shouldn't exist, because
> >just FOO is as good or better. The question is a bit harder where there
> >is only one node involved and we don't have a nice word to describe its
> >role for the command. This is where we used to use 'device' in the past,
> >when node-level addressing didn't exist yet. I think just 'node' would
> >be fine there.
> >
> >Kevin
> >
> 
> I'd be happy with naming things "node" (or node-ref, either is fine)
> going forward; and leaving the old commands (node-name) alone. I
> seem to recall there was a reason we didn't want to just keep using
> node-name for the new unified parameters.

It's probably a bad name when we accept backend names as well. And I'm
not completely sure, but I think we considered removing the relative
recent node-name again, which has to be probed by management tools
anyway. We can't remove 'device', which has always been there, and
keeping both as optional fields isn't really nice.

> It makes sense that if we don't keep a "this means node name ONLY"
> parameter for any command then there is no reason to make some
> distinction between that and "this parameter accepts both," but I
> think for purposes of libvirt, it is helpful to have a concrete
> distinction between versions that it can rely on.

Well, at least for new commands that doesn't matter.

> Could be mis-remembering, this whole discussion is spread out over
> months now.

Yes, remembering all the details is hard...

Kevin

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-01-30 18:52                     ` Kevin Wolf
@ 2015-02-02 10:10                       ` Markus Armbruster
  2015-02-02 21:40                         ` John Snow
  0 siblings, 1 reply; 54+ messages in thread
From: Markus Armbruster @ 2015-02-02 10:10 UTC (permalink / raw)
  To: Kevin Wolf; +Cc: famz, qemu-devel, Max Reitz, vsementsov, stefanha, John Snow

Kevin Wolf <kwolf@redhat.com> writes:

> Am 30.01.2015 um 18:04 hat John Snow geschrieben:
>> 
>> 
>> On 01/30/2015 09:32 AM, Kevin Wolf wrote:
>> >Am 21.01.2015 um 10:34 hat Markus Armbruster geschrieben:
>> >>I'm afraid I forgot much of the discussion we had before the break, and
>> >>only now it's coming back, slowly.
>> >>
>> >>Quoting myself on naming parameters identifying nodes[*]:
>> >>
>> >>     John Snow pointed out to me that we still haven't spelled out how this
>> >>     single parameter should be named.
>> >>
>> >>     On obvious option is calling it node-name, or FOO-node-name when we have
>> >>     several.  However, we'd then have two subtly different kinds of
>> >>     parameters called like that: the old ones accept *only* node names, the
>> >>     new ones also accept backend names, which automatically resolve to the
>> >>     backend's root node.
>> >>
>> >>     Three ways to cope with that:
>> >>
>> >>     * Find a better name.
>> >>
>> >>     * Make the old ones accept backend names, too.  Only a few, not that
>> >>       much work.  However, there are exceptions:
>> >>
>> >>       - blockdev-add's node-name *defines* the node name.
>> >>
>> >>       - query-named-block-nodes's node-name *is* the node's name.
>> >>
>> >>     * Stop worrying and embrace the inconsistency.  The affected commands
>> >>       are headed for deprecation anyway.
>> >>
>> >>     I think I'd go with "node" or "FOO-node" for parameters that reference
>> >>     nodes and accept both node names and backend names, and refrain from
>> >>     touching the existing node-name parameters.
>> >
>> >Wasn't the conclusion last time that we would try to find a better name
>> >for new commands and leave old commands alone because they are going to
>> >become deprecated? That is, a combination of your first and last option?
>> >
>> 
>> That was my impression, too: Use a new name for new commands and
>> then slowly phase out the old things. This makes the new name clear
>> as to what it supports (BOTH backends and nodes through a common
>> namespace) to external management utilities like libvirt.
>> 
>> That's why I just rolled 'node-ref.'
>
> Yes, I agree with that in principle. I called it 'node' below because
> that's shorter and doesn't include type information in the name, but if
> everyone preferred 'node-ref', I wouldn't have a problem with it either.



>> >>Let's go through existing uses of @node-name again:
>> >>
>> >>1. Define a node name
>> >>
>> >>    QMP commands blockdev-add (type BlockdevOptionsBase), drive-mirror
>> >>
>> >>2. Report a node name
>> >>
>> >>    QMP command query-named-block-nodes (type BlockDeviceInfo)
>> >
>> >Whatever name we end up using, 1. and 2. should probably use the same.
>> 
>> Should they? If these commands accept directly *node* names and have
>> no chance of referencing a backend, maybe they should use different
>> parameter names.

Maybe.  But even if we use different names for things that can only be
node names, never backend names, 1. and 2. should use the same name,
because they're both things that can only be node names.  That's what
Kevin said.

> Note that these cases don't refer to a node, but they define/return the
> name of a node. No way that could ever be a backend name, unless we
> broke the code.
>
>> >>3. Node reference with backend names permitted for convenience
>> >>
>> >>    New QMP command block-dirty-bitmap-add (type BlockDirtyBitmapAdd) and
>> >>    others
>> >>
>> >>4. Node reference with backend names not permitted
>> >>
>> >>    QMP commands drive-mirror @replaces, change-backing-file
>> >>    @image-node-name
>> >>
>> >>    We may want to support the "backend name resolves to root node"
>> >>    convenience feature here, for consistency.  Then this moves under 3.
>> >>
>> >>    Note interface wart: change-backing-file additionally requires the
>> >>    backend owning the node.  We need the backend to set op-blockers, we
>> >>    can't easily find it from the node, so we make the user point it out
>> >>    to us.
>> >
>> >These shouldn't be existing. As you say, we should move them to 3.
>> >
>> 
>> Technically #3 here isn't a usage of "node-name," because... I
>> didn't use node-name for these commands. Unless I am reading this
>> list wrong, but it's definitely not an "existing use."
>> 
>> I don't have any opinions about #4; presumably that's something
>> we're aiming to phase out.
>
> Yes. Where "phasing out" simply means to extend it so that it accepts
> backend names. That should in theory be an easy change, except that
> @image-node-name has a name that isn't quite compatible with it...

Our choice for 3. affects the phasing out of 4.

Our choice for 3 is a naming convention for parameters referencing nodes
that accept both node and backend names.

If, after extending the code to accept backend names, the old names for
4. follow the naming convention for 3., we're done.

Else, we still have an interface wart.  We can live with it, or we can
rename the parameter to follow the convention.

>> >>5. "Pair of names" node reference, specify exactly one
>> >>
>> >>    QMP commands block_passwd, block_resize, blockdev-snapshot-sync
>> >>
>> >>    We can ignore this one, because we intend to replace the commands and
>> >>    deprecate the old ones.
>> >
>> >Agreed, these shouldn't be existing either.
>> >
>> >>If I understand you correctly, you're proposing to use @node-name or
>> >>@FOO-node-name when the value must be a node name (items 1+2 and 4), and
>> >>@node-ref or @FOO-node-ref where we additionally support the "backend
>> >>name resolves to root node" convenience feature (item 3).
>> >>
>> >>Is that a fair description of your proposal?
>> >>
>> >>PRO: the name makes it clear when the convenience feature is supported.
>> >>
>> >>CON: if we eliminate 4 by supporting the convenience feature, we either
>> >>create ugly exceptions to the naming convention, or rename the
>> >>parameters.
>> >>
>> >>Opinions?
>> >
>> >If we don't have any cases where node names are allowed, but backend
>> >names are not, then there is no reason to have two different names. I've
>> >yet to see a reason for having commands that can accept node names, but
>> >not backend names.

Cases 1. and 2.  But I'm not sure using different names there to
emphasize "backend names not possible here" would be useful.

>> >It's a bit different when the command can already accept both, but uses
>> >two separate arguments for it. But I think most of them will be
>> >deprecated, so we can ignore them here.

Yes, case 5.

>> >As for the naming, I'm not that sure that it's even useful to add
>> >something to the field name. After all, this is really the _type_ of the
>> >object, not the name. We don't have fields like 'read-only-bool' either.

Yes, but there the type is actually bool, which makes the bool-ness
perfectly obvious.

Here, the type is string.  That's why I feel a FOO-node convention could
be useful.

>> >If we're more specifically looking at things that actually refer to
>> >block devices, you already mentioned drive-mirrors @replaces, which is a
>> >great name in my opinion. @replaces-node-ref wouldn't improve anything.
>> >Likewise, blockdev-add already refers to 'file' and 'backing' instead of
>> >'file-node' or 'backing-node-ref'.
>> >
>> >This probably means that FOO-node-{ref,name} shouldn't exist, because
>> >just FOO is as good or better. The question is a bit harder where there
>> >is only one node involved and we don't have a nice word to describe its
>> >role for the command. This is where we used to use 'device' in the past,
>> >when node-level addressing didn't exist yet. I think just 'node' would
>> >be fine there.

I'm fine with just 'node'.  I like it better than 'node-ref' or
'node-name'.

What sets the 'node-name' convention apart is that the existing
(FOO-)node-name already fit this convention.  A quick grep finds nine
occurences, in block-core.json and event.json.  Advantage if we want to
keep them, disadvantage if we want to get rid of them.

>> >
>> >Kevin
>> >
>> 
>> I'd be happy with naming things "node" (or node-ref, either is fine)
>> going forward; and leaving the old commands (node-name) alone. I
>> seem to recall there was a reason we didn't want to just keep using
>> node-name for the new unified parameters.
>
> It's probably a bad name when we accept backend names as well. And I'm
> not completely sure, but I think we considered removing the relative
> recent node-name again, which has to be probed by management tools
> anyway. We can't remove 'device', which has always been there, and
> keeping both as optional fields isn't really nice.

Sounds like we want to get rid of them.

>> It makes sense that if we don't keep a "this means node name ONLY"
>> parameter for any command

Cases 1. and 2.

>>                           then there is no reason to make some
>> distinction between that and "this parameter accepts both," but I
>> think for purposes of libvirt, it is helpful to have a concrete
>> distinction between versions that it can rely on.
>
> Well, at least for new commands that doesn't matter.
>
>> Could be mis-remembering, this whole discussion is spread out over
>> months now.
>
> Yes, remembering all the details is hard...

Quite a hairball :)

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove
  2015-02-02 10:10                       ` Markus Armbruster
@ 2015-02-02 21:40                         ` John Snow
  0 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-02-02 21:40 UTC (permalink / raw)
  To: Markus Armbruster, Kevin Wolf
  Cc: vsementsov, famz, qemu-devel, stefanha, Max Reitz



On 02/02/2015 05:10 AM, Markus Armbruster wrote:
> Kevin Wolf <kwolf@redhat.com> writes:
>
>> Am 30.01.2015 um 18:04 hat John Snow geschrieben:
>>>
>>>
>>> On 01/30/2015 09:32 AM, Kevin Wolf wrote:
>>>> Am 21.01.2015 um 10:34 hat Markus Armbruster geschrieben:
>>>>> I'm afraid I forgot much of the discussion we had before the break, and
>>>>> only now it's coming back, slowly.
>>>>>
>>>>> Quoting myself on naming parameters identifying nodes[*]:
>>>>>
>>>>>      John Snow pointed out to me that we still haven't spelled out how this
>>>>>      single parameter should be named.
>>>>>
>>>>>      On obvious option is calling it node-name, or FOO-node-name when we have
>>>>>      several.  However, we'd then have two subtly different kinds of
>>>>>      parameters called like that: the old ones accept *only* node names, the
>>>>>      new ones also accept backend names, which automatically resolve to the
>>>>>      backend's root node.
>>>>>
>>>>>      Three ways to cope with that:
>>>>>
>>>>>      * Find a better name.
>>>>>
>>>>>      * Make the old ones accept backend names, too.  Only a few, not that
>>>>>        much work.  However, there are exceptions:
>>>>>
>>>>>        - blockdev-add's node-name *defines* the node name.
>>>>>
>>>>>        - query-named-block-nodes's node-name *is* the node's name.
>>>>>
>>>>>      * Stop worrying and embrace the inconsistency.  The affected commands
>>>>>        are headed for deprecation anyway.
>>>>>
>>>>>      I think I'd go with "node" or "FOO-node" for parameters that reference
>>>>>      nodes and accept both node names and backend names, and refrain from
>>>>>      touching the existing node-name parameters.
>>>>
>>>> Wasn't the conclusion last time that we would try to find a better name
>>>> for new commands and leave old commands alone because they are going to
>>>> become deprecated? That is, a combination of your first and last option?
>>>>
>>>
>>> That was my impression, too: Use a new name for new commands and
>>> then slowly phase out the old things. This makes the new name clear
>>> as to what it supports (BOTH backends and nodes through a common
>>> namespace) to external management utilities like libvirt.
>>>
>>> That's why I just rolled 'node-ref.'
>>
>> Yes, I agree with that in principle. I called it 'node' below because
>> that's shorter and doesn't include type information in the name, but if
>> everyone preferred 'node-ref', I wouldn't have a problem with it either.
>
>
>
>>>>> Let's go through existing uses of @node-name again:
>>>>>
>>>>> 1. Define a node name
>>>>>
>>>>>     QMP commands blockdev-add (type BlockdevOptionsBase), drive-mirror
>>>>>
>>>>> 2. Report a node name
>>>>>
>>>>>     QMP command query-named-block-nodes (type BlockDeviceInfo)
>>>>
>>>> Whatever name we end up using, 1. and 2. should probably use the same.
>>>
>>> Should they? If these commands accept directly *node* names and have
>>> no chance of referencing a backend, maybe they should use different
>>> parameter names.
>
> Maybe.  But even if we use different names for things that can only be
> node names, never backend names, 1. and 2. should use the same name,
> because they're both things that can only be node names.  That's what
> Kevin said.
>
>> Note that these cases don't refer to a node, but they define/return the
>> name of a node. No way that could ever be a backend name, unless we
>> broke the code.
>>
>>>>> 3. Node reference with backend names permitted for convenience
>>>>>
>>>>>     New QMP command block-dirty-bitmap-add (type BlockDirtyBitmapAdd) and
>>>>>     others
>>>>>
>>>>> 4. Node reference with backend names not permitted
>>>>>
>>>>>     QMP commands drive-mirror @replaces, change-backing-file
>>>>>     @image-node-name
>>>>>
>>>>>     We may want to support the "backend name resolves to root node"
>>>>>     convenience feature here, for consistency.  Then this moves under 3.
>>>>>
>>>>>     Note interface wart: change-backing-file additionally requires the
>>>>>     backend owning the node.  We need the backend to set op-blockers, we
>>>>>     can't easily find it from the node, so we make the user point it out
>>>>>     to us.
>>>>
>>>> These shouldn't be existing. As you say, we should move them to 3.
>>>>
>>>
>>> Technically #3 here isn't a usage of "node-name," because... I
>>> didn't use node-name for these commands. Unless I am reading this
>>> list wrong, but it's definitely not an "existing use."
>>>
>>> I don't have any opinions about #4; presumably that's something
>>> we're aiming to phase out.
>>
>> Yes. Where "phasing out" simply means to extend it so that it accepts
>> backend names. That should in theory be an easy change, except that
>> @image-node-name has a name that isn't quite compatible with it...
>
> Our choice for 3. affects the phasing out of 4.
>
> Our choice for 3 is a naming convention for parameters referencing nodes
> that accept both node and backend names.
>
> If, after extending the code to accept backend names, the old names for
> 4. follow the naming convention for 3., we're done.
>
> Else, we still have an interface wart.  We can live with it, or we can
> rename the parameter to follow the convention.
>
>>>>> 5. "Pair of names" node reference, specify exactly one
>>>>>
>>>>>     QMP commands block_passwd, block_resize, blockdev-snapshot-sync
>>>>>
>>>>>     We can ignore this one, because we intend to replace the commands and
>>>>>     deprecate the old ones.
>>>>
>>>> Agreed, these shouldn't be existing either.
>>>>
>>>>> If I understand you correctly, you're proposing to use @node-name or
>>>>> @FOO-node-name when the value must be a node name (items 1+2 and 4), and
>>>>> @node-ref or @FOO-node-ref where we additionally support the "backend
>>>>> name resolves to root node" convenience feature (item 3).
>>>>>
>>>>> Is that a fair description of your proposal?
>>>>>
>>>>> PRO: the name makes it clear when the convenience feature is supported.
>>>>>
>>>>> CON: if we eliminate 4 by supporting the convenience feature, we either
>>>>> create ugly exceptions to the naming convention, or rename the
>>>>> parameters.
>>>>>
>>>>> Opinions?
>>>>
>>>> If we don't have any cases where node names are allowed, but backend
>>>> names are not, then there is no reason to have two different names. I've
>>>> yet to see a reason for having commands that can accept node names, but
>>>> not backend names.
>
> Cases 1. and 2.  But I'm not sure using different names there to
> emphasize "backend names not possible here" would be useful.
>
>>>> It's a bit different when the command can already accept both, but uses
>>>> two separate arguments for it. But I think most of them will be
>>>> deprecated, so we can ignore them here.
>
> Yes, case 5.
>
>>>> As for the naming, I'm not that sure that it's even useful to add
>>>> something to the field name. After all, this is really the _type_ of the
>>>> object, not the name. We don't have fields like 'read-only-bool' either.
>
> Yes, but there the type is actually bool, which makes the bool-ness
> perfectly obvious.
>
> Here, the type is string.  That's why I feel a FOO-node convention could
> be useful.
>
>>>> If we're more specifically looking at things that actually refer to
>>>> block devices, you already mentioned drive-mirrors @replaces, which is a
>>>> great name in my opinion. @replaces-node-ref wouldn't improve anything.
>>>> Likewise, blockdev-add already refers to 'file' and 'backing' instead of
>>>> 'file-node' or 'backing-node-ref'.
>>>>
>>>> This probably means that FOO-node-{ref,name} shouldn't exist, because
>>>> just FOO is as good or better. The question is a bit harder where there
>>>> is only one node involved and we don't have a nice word to describe its
>>>> role for the command. This is where we used to use 'device' in the past,
>>>> when node-level addressing didn't exist yet. I think just 'node' would
>>>> be fine there.
>
> I'm fine with just 'node'.  I like it better than 'node-ref' or
> 'node-name'.
>
> What sets the 'node-name' convention apart is that the existing
> (FOO-)node-name already fit this convention.  A quick grep finds nine
> occurences, in block-core.json and event.json.  Advantage if we want to
> keep them, disadvantage if we want to get rid of them.
>
>>>>
>>>> Kevin
>>>>
>>>
>>> I'd be happy with naming things "node" (or node-ref, either is fine)
>>> going forward; and leaving the old commands (node-name) alone. I
>>> seem to recall there was a reason we didn't want to just keep using
>>> node-name for the new unified parameters.
>>
>> It's probably a bad name when we accept backend names as well. And I'm
>> not completely sure, but I think we considered removing the relative
>> recent node-name again, which has to be probed by management tools
>> anyway. We can't remove 'device', which has always been there, and
>> keeping both as optional fields isn't really nice.
>
> Sounds like we want to get rid of them.
>
>>> It makes sense that if we don't keep a "this means node name ONLY"
>>> parameter for any command
>
> Cases 1. and 2.
>
>>>                            then there is no reason to make some
>>> distinction between that and "this parameter accepts both," but I
>>> think for purposes of libvirt, it is helpful to have a concrete
>>> distinction between versions that it can rely on.
>>
>> Well, at least for new commands that doesn't matter.
>>
>>> Could be mis-remembering, this whole discussion is spread out over
>>> months now.
>>
>> Yes, remembering all the details is hard...
>
> Quite a hairball :)
>

I can roll v12 tomorrow using parameters named "node" if that sounds 
agreeable to everyone, fixing up the other issues noted by other 
reviewers in the process.

Sound good?

--js

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 12/13] qemu-iotests: Add tests for drive-backup sync=dirty-bitmap
  2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 12/13] qemu-iotests: Add tests for drive-backup sync=dirty-bitmap John Snow
@ 2015-02-06 14:23   ` Vladimir Sementsov-Ogievskiy
  2015-02-06 17:14     ` John Snow
  0 siblings, 1 reply; 54+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2015-02-06 14:23 UTC (permalink / raw)
  To: John Snow, qemu-devel; +Cc: kwolf, famz, armbru, mreitz, stefanha

On 12.01.2015 19:31, John Snow wrote:
> From: Fam Zheng <famz@redhat.com>
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Signed-off-by: John Snow <jsnow@redhat.com>
> ---
>   tests/qemu-iotests/056        | 33 ++++++++++++++++++++++++++++++---
>   tests/qemu-iotests/056.out    |  4 ++--
>   tests/qemu-iotests/iotests.py |  8 ++++++++
>   3 files changed, 40 insertions(+), 5 deletions(-)
>
> diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056
> index 54e4bd0..6f8aa9a 100755
> --- a/tests/qemu-iotests/056
> +++ b/tests/qemu-iotests/056
> @@ -23,17 +23,17 @@
>   import time
>   import os
>   import iotests
> -from iotests import qemu_img, qemu_io, create_image
> +from iotests import qemu_img, qemu_img_map_assert, qemu_io, create_image
>   
>   backing_img = os.path.join(iotests.test_dir, 'backing.img')
>   test_img = os.path.join(iotests.test_dir, 'test.img')
>   target_img = os.path.join(iotests.test_dir, 'target.img')
>   
> -class TestSyncModesNoneAndTop(iotests.QMPTestCase):
> +class TestSyncModes(iotests.QMPTestCase):
>       image_len = 64 * 1024 * 1024 # MB
>   
>       def setUp(self):
> -        create_image(backing_img, TestSyncModesNoneAndTop.image_len)
> +        create_image(backing_img, TestSyncModes.image_len)
>           qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
>           qemu_io('-c', 'write -P0x41 0 512', test_img)
>           qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
> @@ -64,6 +64,33 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase):
>           self.assertTrue(iotests.compare_images(test_img, target_img),
>                           'target image does not match source after backup')
>   
> +    def test_sync_dirty_bitmap_missing(self):
> +        self.assert_no_active_block_jobs()
> +        result = self.vm.qmp('drive-backup', device='drive0', sync='dirty-bitmap',
> +                             format=iotests.imgfmt, target=target_img)
> +        self.assert_qmp(result, 'error/class', 'GenericError')
> +
> +    def test_sync_dirty_bitmap_not_found(self):
> +        self.assert_no_active_block_jobs()
> +        result = self.vm.qmp('drive-backup', device='drive0', sync='dirty-bitmap',
> +                             bitmap='unknown',
> +                             format=iotests.imgfmt, target=target_img)
> +        self.assert_qmp(result, 'error/class', 'GenericError')
> +
> +    def test_sync_dirty_bitmap(self):
> +        self.assert_no_active_block_jobs()
> +        result = self.vm.qmp('block-dirty-bitmap-add', node_ref='drive0', name='bitmap0')
> +        self.assert_qmp(result, 'return', {})
> +        self.vm.hmp_qemu_io('drive0', 'write -P0x5a 0 512')
> +        self.vm.hmp_qemu_io('drive0', 'write -P0x5a 48M 512')
> +        result = self.vm.qmp('drive-backup', device='drive0', sync='dirty-bitmap',
> +                             bitmap='bitmap0',
> +                             format=iotests.imgfmt, target=target_img)
> +        self.assert_qmp(result, 'return', {})
> +        self.wait_until_completed(check_offset=False)
> +        self.assert_no_active_block_jobs()
> +        qemu_img_map_assert(target_img, [0, 0x3000000])
> +
>       def test_cancel_sync_none(self):
>           self.assert_no_active_block_jobs()
>   
> diff --git a/tests/qemu-iotests/056.out b/tests/qemu-iotests/056.out
> index fbc63e6..914e373 100644
> --- a/tests/qemu-iotests/056.out
> +++ b/tests/qemu-iotests/056.out
> @@ -1,5 +1,5 @@
> -..
> +.....
>   ----------------------------------------------------------------------
> -Ran 2 tests
> +Ran 5 tests
>   
>   OK
> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> index f57f154..95bb959 100644
> --- a/tests/qemu-iotests/iotests.py
> +++ b/tests/qemu-iotests/iotests.py
> @@ -55,6 +55,14 @@ def qemu_img_pipe(*args):
>       '''Run qemu-img and return its output'''
>       return subprocess.Popen(qemu_img_args + list(args), stdout=subprocess.PIPE).communicate()[0]
>   
> +def qemu_img_map_assert(img, offsets):
> +    '''Run qemu-img map on img and check the mapped ranges'''
> +    offs = []
> +    for line in qemu_img_pipe('map', img).splitlines()[1:]:
> +        offset, length, mapped, fname = line.split()
> +        offs.append(int(offset, 16))
> +    assert set(offs) == set(offsets), "mapped offsets in image '%s' not equal to '%s'" % (str(offs), str(offsets))
> +
>   def qemu_io(*args):
>       '''Run qemu-io and return the stdout data'''
>       args = qemu_io_args + list(args)

why not just check by qemu-io -c "write -P0x5a 0 512" for symmetry?

-- Best regards, Vladimir

^ permalink raw reply	[flat|nested] 54+ messages in thread

* Re: [Qemu-devel] [PATCH v11 12/13] qemu-iotests: Add tests for drive-backup sync=dirty-bitmap
  2015-02-06 14:23   ` Vladimir Sementsov-Ogievskiy
@ 2015-02-06 17:14     ` John Snow
  0 siblings, 0 replies; 54+ messages in thread
From: John Snow @ 2015-02-06 17:14 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy, qemu-devel
  Cc: kwolf, famz, armbru, mreitz, stefanha



On 02/06/2015 09:23 AM, Vladimir Sementsov-Ogievskiy wrote:
> On 12.01.2015 19:31, John Snow wrote:
>> From: Fam Zheng <famz@redhat.com>
>>
>> Signed-off-by: Fam Zheng <famz@redhat.com>
>> Signed-off-by: John Snow <jsnow@redhat.com>
>> ---
>>   tests/qemu-iotests/056        | 33 ++++++++++++++++++++++++++++++---
>>   tests/qemu-iotests/056.out    |  4 ++--
>>   tests/qemu-iotests/iotests.py |  8 ++++++++
>>   3 files changed, 40 insertions(+), 5 deletions(-)
>>
>> diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056
>> index 54e4bd0..6f8aa9a 100755
>> --- a/tests/qemu-iotests/056
>> +++ b/tests/qemu-iotests/056
>> @@ -23,17 +23,17 @@
>>   import time
>>   import os
>>   import iotests
>> -from iotests import qemu_img, qemu_io, create_image
>> +from iotests import qemu_img, qemu_img_map_assert, qemu_io, create_image
>>   backing_img = os.path.join(iotests.test_dir, 'backing.img')
>>   test_img = os.path.join(iotests.test_dir, 'test.img')
>>   target_img = os.path.join(iotests.test_dir, 'target.img')
>> -class TestSyncModesNoneAndTop(iotests.QMPTestCase):
>> +class TestSyncModes(iotests.QMPTestCase):
>>       image_len = 64 * 1024 * 1024 # MB
>>       def setUp(self):
>> -        create_image(backing_img, TestSyncModesNoneAndTop.image_len)
>> +        create_image(backing_img, TestSyncModes.image_len)
>>           qemu_img('create', '-f', iotests.imgfmt, '-o',
>> 'backing_file=%s' % backing_img, test_img)
>>           qemu_io('-c', 'write -P0x41 0 512', test_img)
>>           qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
>> @@ -64,6 +64,33 @@ class TestSyncModesNoneAndTop(iotests.QMPTestCase):
>>           self.assertTrue(iotests.compare_images(test_img, target_img),
>>                           'target image does not match source after
>> backup')
>> +    def test_sync_dirty_bitmap_missing(self):
>> +        self.assert_no_active_block_jobs()
>> +        result = self.vm.qmp('drive-backup', device='drive0',
>> sync='dirty-bitmap',
>> +                             format=iotests.imgfmt, target=target_img)
>> +        self.assert_qmp(result, 'error/class', 'GenericError')
>> +
>> +    def test_sync_dirty_bitmap_not_found(self):
>> +        self.assert_no_active_block_jobs()
>> +        result = self.vm.qmp('drive-backup', device='drive0',
>> sync='dirty-bitmap',
>> +                             bitmap='unknown',
>> +                             format=iotests.imgfmt, target=target_img)
>> +        self.assert_qmp(result, 'error/class', 'GenericError')
>> +
>> +    def test_sync_dirty_bitmap(self):
>> +        self.assert_no_active_block_jobs()
>> +        result = self.vm.qmp('block-dirty-bitmap-add',
>> node_ref='drive0', name='bitmap0')
>> +        self.assert_qmp(result, 'return', {})
>> +        self.vm.hmp_qemu_io('drive0', 'write -P0x5a 0 512')
>> +        self.vm.hmp_qemu_io('drive0', 'write -P0x5a 48M 512')
>> +        result = self.vm.qmp('drive-backup', device='drive0',
>> sync='dirty-bitmap',
>> +                             bitmap='bitmap0',
>> +                             format=iotests.imgfmt, target=target_img)
>> +        self.assert_qmp(result, 'return', {})
>> +        self.wait_until_completed(check_offset=False)
>> +        self.assert_no_active_block_jobs()
>> +        qemu_img_map_assert(target_img, [0, 0x3000000])
>> +
>>       def test_cancel_sync_none(self):
>>           self.assert_no_active_block_jobs()
>> diff --git a/tests/qemu-iotests/056.out b/tests/qemu-iotests/056.out
>> index fbc63e6..914e373 100644
>> --- a/tests/qemu-iotests/056.out
>> +++ b/tests/qemu-iotests/056.out
>> @@ -1,5 +1,5 @@
>> -..
>> +.....
>>   ----------------------------------------------------------------------
>> -Ran 2 tests
>> +Ran 5 tests
>>   OK
>> diff --git a/tests/qemu-iotests/iotests.py
>> b/tests/qemu-iotests/iotests.py
>> index f57f154..95bb959 100644
>> --- a/tests/qemu-iotests/iotests.py
>> +++ b/tests/qemu-iotests/iotests.py
>> @@ -55,6 +55,14 @@ def qemu_img_pipe(*args):
>>       '''Run qemu-img and return its output'''
>>       return subprocess.Popen(qemu_img_args + list(args),
>> stdout=subprocess.PIPE).communicate()[0]
>> +def qemu_img_map_assert(img, offsets):
>> +    '''Run qemu-img map on img and check the mapped ranges'''
>> +    offs = []
>> +    for line in qemu_img_pipe('map', img).splitlines()[1:]:
>> +        offset, length, mapped, fname = line.split()
>> +        offs.append(int(offset, 16))
>> +    assert set(offs) == set(offsets), "mapped offsets in image '%s'
>> not equal to '%s'" % (str(offs), str(offsets))
>> +
>>   def qemu_io(*args):
>>       '''Run qemu-io and return the stdout data'''
>>       args = qemu_io_args + list(args)
>
> why not just check by qemu-io -c "write -P0x5a 0 512" for symmetry?
>
> -- Best regards, Vladimir

I actually have a much more thorough and rigorous iotest planned; this 
test is still mostly as it was written by Fam and I haven't made any 
changes to it yet (because nobody has objected!)

I wrote a proof-of-concept demo to actually test the incremental backup 
success and failure cases recently, I will port it to iotests and submit 
it as a patch soon.

^ permalink raw reply	[flat|nested] 54+ messages in thread

end of thread, other threads:[~2015-02-06 17:15 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-12 16:30 [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series John Snow
2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 01/13] block: fix spoiling all dirty bitmaps by mirror and migration John Snow
2015-01-13 15:54   ` Vladimir Sementsov-Ogievskiy
2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 02/13] qapi: Add optional field "name" to block dirty bitmap John Snow
2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 03/13] qmp: Add block-dirty-bitmap-add and block-dirty-bitmap-remove John Snow
2015-01-16 15:36   ` Max Reitz
2015-01-16 16:48     ` John Snow
2015-01-16 16:51       ` Max Reitz
2015-01-16 16:54         ` John Snow
2015-01-19 10:08       ` Markus Armbruster
2015-01-19 21:05         ` John Snow
2015-01-20  8:26           ` Markus Armbruster
2015-01-20 16:48             ` John Snow
2015-01-21  9:34               ` Markus Armbruster
2015-01-21 15:51                 ` Eric Blake
2015-01-30 14:32                 ` Kevin Wolf
2015-01-30 17:04                   ` John Snow
2015-01-30 18:52                     ` Kevin Wolf
2015-02-02 10:10                       ` Markus Armbruster
2015-02-02 21:40                         ` John Snow
2015-01-29 13:55   ` Vladimir Sementsov-Ogievskiy
2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 04/13] block: Introduce bdrv_dirty_bitmap_granularity() John Snow
2015-01-16 15:40   ` Max Reitz
2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 05/13] block: Add bdrv_clear_dirty_bitmap John Snow
2015-01-16 15:56   ` Max Reitz
2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 06/13] hbitmap: add hbitmap_merge John Snow
2015-01-16 16:12   ` Max Reitz
2015-01-12 16:30 ` [Qemu-devel] [PATCH v11 07/13] qmp: Add block-dirty-bitmap-enable and block-dirty-bitmap-disable John Snow
2015-01-16 16:28   ` Max Reitz
2015-01-16 17:09     ` John Snow
2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 08/13] block: Add bitmap successors John Snow
2015-01-13  9:24   ` Fam Zheng
2015-01-13 17:26     ` John Snow
2015-01-16 18:22     ` John Snow
2015-01-19  1:00       ` Fam Zheng
2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 09/13] qmp: Add support of "dirty-bitmap" sync mode for drive-backup John Snow
2015-01-13  9:37   ` Fam Zheng
2015-01-13 17:50     ` John Snow
2015-01-14  6:29       ` Fam Zheng
2015-01-16 17:52   ` Max Reitz
2015-01-16 17:59     ` John Snow
2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 10/13] qapi: Add transaction support to block-dirty-bitmap-{add, enable, disable} John Snow
2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 11/13] qmp: Add dirty bitmap status fields in query-block John Snow
2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 12/13] qemu-iotests: Add tests for drive-backup sync=dirty-bitmap John Snow
2015-02-06 14:23   ` Vladimir Sementsov-Ogievskiy
2015-02-06 17:14     ` John Snow
2015-01-12 16:31 ` [Qemu-devel] [PATCH v11 13/13] block: BdrvDirtyBitmap miscellaneous fixup John Snow
2015-01-13 16:50   ` Vladimir Sementsov-Ogievskiy
2015-01-13 18:27     ` John Snow
2015-01-13  1:21 ` [Qemu-devel] [PATCH v11 00/13] block: Incremental backup series Fam Zheng
2015-01-13 19:52 ` John Snow
2015-01-29 22:38 ` John Snow
2015-01-30 10:24 ` Vladimir Sementsov-Ogievskiy
2015-01-30 18:46   ` John Snow

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.