All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work
@ 2016-01-20  6:11 Fam Zheng
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 01/13] backup: Use Bitmap to replace "s->bitmap" Fam Zheng
                   ` (15 more replies)
  0 siblings, 16 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

v2: Various changes addressing John's and Vladimir's comments:

    [02/13] typedefs: Add BdrvDirtyBitmap
            Skip HBitmapIter because we'll hide it soon. [John]
            
    [03/13] block: Move block dirty bitmap code to separate files
    [04/13] block: Remove unused typedef of BlockDriverDirtyHandler
    [05/13] block: Hide HBitmap in block dirty bitmap interface
            Add assert in bdrv_dirty_bitmap_truncate(). [John]
            Add John's rev-by.

    [06/13] HBitmap: Introduce "meta" bitmap to track bit changes
            Caller of hbitmap_create_meta() frees it with hbitmap_free_meta().
            [John, Vladimir]

    [07/13] tests: Add test code for meta bitmap
            Add John's rev-by.

    [08/13] block: Support meta dirty bitmap
            Release the meta dirty bitmap in bdrv_release_dirty_bitmap().

    [09/13] block: Add two dirty bitmap getters
    [10/13] block: Assert that bdrv_release_dirty_bitmap succeeded
            Add John's rev-by.

    [11/13] hbitmap: serialization
            Fix comment for hbitmap_serialization_granularity() and
            hbitmap_deserialize_part(). [John]
            Document @finish in hbitmap_deserialize_zeroes more clearly.
            Fixed granularity in hbitmap_serialization_granularity().
            [Vladimir]
            Tweak the assertion in serialization_chunk. [Vladimir]
            cpu_to_leXXs -> leXX_to_cpus in hbitmap_deserialize_part.
            [Vladimir]
            Fix typo in serialization_chunk() comments. [John]

    [12/13] block: BdrvDirtyBitmap serialization interface
    [13/13] tests: Add test code for hbitmap serialization


Two major features are added to block dirty bitmap (and underlying HBitmap) in
this series: meta bitmap and serialization, together with all other supportive
patches.

Both operations are common in dirty bitmap migration and persistence: they need
to find whether and which part of the dirty bitmap in question has changed with
meta dirty bitmap, and they need to write it to the target with serialization.


Fam Zheng (11):
  backup: Use Bitmap to replace "s->bitmap"
  typedefs: Add BdrvDirtyBitmap
  block: Move block dirty bitmap code to separate files
  block: Remove unused typedef of BlockDriverDirtyHandler
  block: Hide HBitmap in block dirty bitmap interface
  HBitmap: Introduce "meta" bitmap to track bit changes
  tests: Add test code for meta bitmap
  block: Support meta dirty bitmap
  block: Add two dirty bitmap getters
  block: Assert that bdrv_release_dirty_bitmap succeeded
  tests: Add test code for hbitmap serialization

Vladimir Sementsov-Ogievskiy (2):
  hbitmap: serialization
  block: BdrvDirtyBitmap serialization interface

 block.c                      | 339 -----------------------------
 block/Makefile.objs          |   2 +-
 block/backup.c               |  25 ++-
 block/dirty-bitmap.c         | 492 +++++++++++++++++++++++++++++++++++++++++++
 block/mirror.c               |  14 +-
 include/block/block.h        |  40 +---
 include/block/dirty-bitmap.h |  71 +++++++
 include/qemu/hbitmap.h       |  95 +++++++++
 include/qemu/typedefs.h      |   2 +
 tests/test-hbitmap.c         | 255 ++++++++++++++++++++++
 util/hbitmap.c               | 201 ++++++++++++++++--
 11 files changed, 1126 insertions(+), 410 deletions(-)
 create mode 100644 block/dirty-bitmap.c
 create mode 100644 include/block/dirty-bitmap.h

-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 01/13] backup: Use Bitmap to replace "s->bitmap"
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap Fam Zheng
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

"s->bitmap" tracks done sectors, we only check bit states without using any
iterator which HBitmap is good for. Switch to "Bitmap" which is simpler and
more memory efficient.

Meanwhile, rename it to done_bitmap, to reflect the intention.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
 block/backup.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/block/backup.c b/block/backup.c
index 705bb77..56ddec0 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -22,6 +22,7 @@
 #include "qapi/qmp/qerror.h"
 #include "qemu/ratelimit.h"
 #include "sysemu/block-backend.h"
+#include "qemu/bitmap.h"
 
 #define BACKUP_CLUSTER_BITS 16
 #define BACKUP_CLUSTER_SIZE (1 << BACKUP_CLUSTER_BITS)
@@ -47,7 +48,7 @@ typedef struct BackupBlockJob {
     BlockdevOnError on_target_error;
     CoRwlock flush_rwlock;
     uint64_t sectors_read;
-    HBitmap *bitmap;
+    unsigned long *done_bitmap;
     QLIST_HEAD(, CowRequest) inflight_reqs;
 } BackupBlockJob;
 
@@ -113,7 +114,7 @@ static int coroutine_fn backup_do_cow(BlockDriverState *bs,
     cow_request_begin(&cow_request, job, start, end);
 
     for (; start < end; start++) {
-        if (hbitmap_get(job->bitmap, start)) {
+        if (test_bit(start, job->done_bitmap)) {
             trace_backup_do_cow_skip(job, start);
             continue; /* already copied */
         }
@@ -164,7 +165,7 @@ static int coroutine_fn backup_do_cow(BlockDriverState *bs,
             goto out;
         }
 
-        hbitmap_set(job->bitmap, start, 1);
+        set_bit(start, job->done_bitmap);
 
         /* Publish progress, guest I/O counts as progress too.  Note that the
          * offset field is an opaque progress value, it is not a disk offset.
@@ -394,7 +395,7 @@ static void coroutine_fn backup_run(void *opaque)
     start = 0;
     end = DIV_ROUND_UP(job->common.len, BACKUP_CLUSTER_SIZE);
 
-    job->bitmap = hbitmap_alloc(end, 0);
+    job->done_bitmap = bitmap_new(end);
 
     bdrv_set_enable_write_cache(target, true);
     if (target->blk) {
@@ -475,7 +476,7 @@ static void coroutine_fn backup_run(void *opaque)
     /* wait until pending backup_do_cow() calls have completed */
     qemu_co_rwlock_wrlock(&job->flush_rwlock);
     qemu_co_rwlock_unlock(&job->flush_rwlock);
-    hbitmap_free(job->bitmap);
+    g_free(job->done_bitmap);
 
     if (target->blk) {
         blk_iostatus_disable(target->blk);
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 01/13] backup: Use Bitmap to replace "s->bitmap" Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-20 16:56   ` Eric Blake
  2016-01-25 20:37   ` John Snow
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 03/13] block: Move block dirty bitmap code to separate files Fam Zheng
                   ` (13 subsequent siblings)
  15 siblings, 2 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

Following patches to refactor and move block dirty bitmap code could use
this.

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 include/block/block.h   | 3 +--
 include/qemu/typedefs.h | 1 +
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/include/block/block.h b/include/block/block.h
index c96923d..483bfd3 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -8,6 +8,7 @@
 #include "block/accounting.h"
 #include "qapi/qmp/qobject.h"
 #include "qapi-types.h"
+#include "qemu/hbitmap.h"
 
 /* block.c */
 typedef struct BlockDriver BlockDriver;
@@ -472,8 +473,6 @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
 void *qemu_try_blockalign0(BlockDriverState *bs, size_t size);
 bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
 
-struct HBitmapIter;
-typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
 BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
                                           uint32_t granularity,
                                           const char *name,
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 78fe6e8..0cf9d74 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -10,6 +10,7 @@ typedef struct AddressSpace AddressSpace;
 typedef struct AioContext AioContext;
 typedef struct AllwinnerAHCIState AllwinnerAHCIState;
 typedef struct AudioState AudioState;
+typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
 typedef struct BlockBackend BlockBackend;
 typedef struct BlockBackendRootState BlockBackendRootState;
 typedef struct BlockDriverState BlockDriverState;
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 03/13] block: Move block dirty bitmap code to separate files
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 01/13] backup: Use Bitmap to replace "s->bitmap" Fam Zheng
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-22  9:13   ` Vladimir Sementsov-Ogievskiy
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 04/13] block: Remove unused typedef of BlockDriverDirtyHandler Fam Zheng
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

The only change is making bdrv_dirty_bitmap_truncate public. It is used in
block.c.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
 block.c                      | 339 ---------------------------------------
 block/Makefile.objs          |   2 +-
 block/dirty-bitmap.c         | 366 +++++++++++++++++++++++++++++++++++++++++++
 include/block/block.h        |  35 +----
 include/block/dirty-bitmap.h |  43 +++++
 5 files changed, 411 insertions(+), 374 deletions(-)
 create mode 100644 block/dirty-bitmap.c
 create mode 100644 include/block/dirty-bitmap.h

diff --git a/block.c b/block.c
index 54c37f9..ab79bfe 100644
--- a/block.c
+++ b/block.c
@@ -55,23 +55,6 @@
 #include <windows.h>
 #endif
 
-/**
- * A BdrvDirtyBitmap can be in three possible states:
- * (1) successor is NULL and disabled is false: full r/w mode
- * (2) successor is NULL and disabled is true: read only mode ("disabled")
- * (3) successor is set: frozen mode.
- *     A frozen bitmap cannot be renamed, deleted, anonymized, cleared, set,
- *     or enabled. A frozen bitmap can only abdicate() or reclaim().
- */
-struct BdrvDirtyBitmap {
-    HBitmap *bitmap;            /* Dirty sector bitmap implementation */
-    BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
-    char *name;                 /* Optional non-empty unique ID */
-    int64_t size;               /* Size of the bitmap (Number of sectors) */
-    bool disabled;              /* Bitmap is read-only */
-    QLIST_ENTRY(BdrvDirtyBitmap) list;
-};
-
 #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
 
 struct BdrvStates bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states);
@@ -87,7 +70,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
                              BlockDriverState *parent,
                              const BdrvChildRole *child_role, Error **errp);
 
-static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
 /* If non-zero, use only whitelisted block drivers */
 static int use_bdrv_whitelist;
 
@@ -3373,327 +3355,6 @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked)
     }
 }
 
-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(BdrvDirtyBitmap *bitmap)
-{
-    assert(!bdrv_dirty_bitmap_frozen(bitmap));
-    g_free(bitmap->name);
-    bitmap->name = NULL;
-}
-
-BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
-                                          uint32_t granularity,
-                                          const char *name,
-                                          Error **errp)
-{
-    int64_t bitmap_size;
-    BdrvDirtyBitmap *bitmap;
-    uint32_t sector_granularity;
-
-    assert((granularity & (granularity - 1)) == 0);
-
-    if (name && bdrv_find_dirty_bitmap(bs, name)) {
-        error_setg(errp, "Bitmap already exists: %s", name);
-        return NULL;
-    }
-    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");
-        errno = -bitmap_size;
-        return NULL;
-    }
-    bitmap = g_new0(BdrvDirtyBitmap, 1);
-    bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
-    bitmap->size = bitmap_size;
-    bitmap->name = g_strdup(name);
-    bitmap->disabled = false;
-    QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
-    return bitmap;
-}
-
-bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
-{
-    return bitmap->successor;
-}
-
-bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
-{
-    return !(bitmap->disabled || bitmap->successor);
-}
-
-DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
-{
-    if (bdrv_dirty_bitmap_frozen(bitmap)) {
-        return DIRTY_BITMAP_STATUS_FROZEN;
-    } else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
-        return DIRTY_BITMAP_STATUS_DISABLED;
-    } else {
-        return DIRTY_BITMAP_STATUS_ACTIVE;
-    }
-}
-
-/**
- * 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;
-    BdrvDirtyBitmap *child;
-
-    if (bdrv_dirty_bitmap_frozen(bitmap)) {
-        error_setg(errp, "Cannot create a successor for a bitmap that is "
-                   "currently frozen");
-        return -1;
-    }
-    assert(!bitmap->successor);
-
-    /* Create an anonymous successor */
-    granularity = bdrv_dirty_bitmap_granularity(bitmap);
-    child = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
-    if (!child) {
-        return -1;
-    }
-
-    /* Successor will be on or off based on our current state. */
-    child->disabled = bitmap->disabled;
-
-    /* Install the successor and freeze the parent */
-    bitmap->successor = child;
-    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");
-        return NULL;
-    }
-
-    name = bitmap->name;
-    bitmap->name = NULL;
-    successor->name = name;
-    bitmap->successor = NULL;
-    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");
-        return NULL;
-    }
-
-    if (!hbitmap_merge(parent->bitmap, successor->bitmap)) {
-        error_setg(errp, "Merging of parent and successor bitmap failed");
-        return NULL;
-    }
-    bdrv_release_dirty_bitmap(bs, successor);
-    parent->successor = NULL;
-
-    return parent;
-}
-
-/**
- * Truncates _all_ bitmaps attached to a BDS.
- */
-static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
-{
-    BdrvDirtyBitmap *bitmap;
-    uint64_t size = bdrv_nb_sectors(bs);
-
-    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
-        assert(!bdrv_dirty_bitmap_frozen(bitmap));
-        hbitmap_truncate(bitmap->bitmap, size);
-        bitmap->size = size;
-    }
-}
-
-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(!bdrv_dirty_bitmap_frozen(bm));
-            QLIST_REMOVE(bitmap, list);
-            hbitmap_free(bitmap->bitmap);
-            g_free(bitmap->name);
-            g_free(bitmap);
-            return;
-        }
-    }
-}
-
-void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
-{
-    assert(!bdrv_dirty_bitmap_frozen(bitmap));
-    bitmap->disabled = true;
-}
-
-void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
-{
-    assert(!bdrv_dirty_bitmap_frozen(bitmap));
-    bitmap->disabled = false;
-}
-
-BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
-{
-    BdrvDirtyBitmap *bm;
-    BlockDirtyInfoList *list = NULL;
-    BlockDirtyInfoList **plist = &list;
-
-    QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
-        BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
-        BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
-        info->count = bdrv_get_dirty_count(bm);
-        info->granularity = bdrv_dirty_bitmap_granularity(bm);
-        info->has_name = !!bm->name;
-        info->name = g_strdup(bm->name);
-        info->status = bdrv_dirty_bitmap_status(bm);
-        entry->value = info;
-        *plist = entry;
-        plist = &entry->next;
-    }
-
-    return list;
-}
-
-int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector)
-{
-    if (bitmap) {
-        return hbitmap_get(bitmap->bitmap, sector);
-    } else {
-        return 0;
-    }
-}
-
-/**
- * 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.
- */
-uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
-{
-    BlockDriverInfo bdi;
-    uint32_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;
-}
-
-uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
-{
-    return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
-}
-
-void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
-{
-    hbitmap_iter_init(hbi, bitmap->bitmap, 0);
-}
-
-void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
-                           int64_t cur_sector, int nr_sectors)
-{
-    assert(bdrv_dirty_bitmap_enabled(bitmap));
-    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
-}
-
-void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
-                             int64_t cur_sector, int nr_sectors)
-{
-    assert(bdrv_dirty_bitmap_enabled(bitmap));
-    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
-}
-
-void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
-{
-    assert(bdrv_dirty_bitmap_enabled(bitmap));
-    if (!out) {
-        hbitmap_reset_all(bitmap->bitmap);
-    } else {
-        HBitmap *backup = bitmap->bitmap;
-        bitmap->bitmap = hbitmap_alloc(bitmap->size,
-                                       hbitmap_granularity(backup));
-        *out = backup;
-    }
-}
-
-void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
-{
-    HBitmap *tmp = bitmap->bitmap;
-    assert(bdrv_dirty_bitmap_enabled(bitmap));
-    bitmap->bitmap = in;
-    hbitmap_free(tmp);
-}
-
-void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
-                    int nr_sectors)
-{
-    BdrvDirtyBitmap *bitmap;
-    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
-        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
-            continue;
-        }
-        hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
-    }
-}
-
-/**
- * Advance an HBitmapIter to an arbitrary offset.
- */
-void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
-{
-    assert(hbi->hb);
-    hbitmap_iter_init(hbi, hbi->hb, offset);
-}
-
-int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
-{
-    return hbitmap_count(bitmap->bitmap);
-}
-
 /* Get a reference to bs */
 void bdrv_ref(BlockDriverState *bs)
 {
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 58ef2ef..cdd8655 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -20,7 +20,7 @@ block-obj-$(CONFIG_RBD) += rbd.o
 block-obj-$(CONFIG_GLUSTERFS) += gluster.o
 block-obj-$(CONFIG_ARCHIPELAGO) += archipelago.o
 block-obj-$(CONFIG_LIBSSH2) += ssh.o
-block-obj-y += accounting.o
+block-obj-y += accounting.o dirty-bitmap.o
 block-obj-y += write-threshold.o
 
 common-obj-y += stream.o
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
new file mode 100644
index 0000000..7924c38
--- /dev/null
+++ b/block/dirty-bitmap.c
@@ -0,0 +1,366 @@
+/*
+ * Block Dirty Bitmap
+ *
+ * Copyright (c) 2016 Red Hat. Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "config-host.h"
+#include "qemu-common.h"
+#include "trace.h"
+#include "block/block_int.h"
+#include "block/blockjob.h"
+
+/**
+ * A BdrvDirtyBitmap can be in three possible states:
+ * (1) successor is NULL and disabled is false: full r/w mode
+ * (2) successor is NULL and disabled is true: read only mode ("disabled")
+ * (3) successor is set: frozen mode.
+ *     A frozen bitmap cannot be renamed, deleted, anonymized, cleared, set,
+ *     or enabled. A frozen bitmap can only abdicate() or reclaim().
+ */
+struct BdrvDirtyBitmap {
+    HBitmap *bitmap;            /* Dirty sector bitmap implementation */
+    BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
+    char *name;                 /* Optional non-empty unique ID */
+    int64_t size;               /* Size of the bitmap (Number of sectors) */
+    bool disabled;              /* Bitmap is read-only */
+    QLIST_ENTRY(BdrvDirtyBitmap) list;
+};
+
+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(BdrvDirtyBitmap *bitmap)
+{
+    assert(!bdrv_dirty_bitmap_frozen(bitmap));
+    g_free(bitmap->name);
+    bitmap->name = NULL;
+}
+
+BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
+                                          uint32_t granularity,
+                                          const char *name,
+                                          Error **errp)
+{
+    int64_t bitmap_size;
+    BdrvDirtyBitmap *bitmap;
+    uint32_t sector_granularity;
+
+    assert((granularity & (granularity - 1)) == 0);
+
+    if (name && bdrv_find_dirty_bitmap(bs, name)) {
+        error_setg(errp, "Bitmap already exists: %s", name);
+        return NULL;
+    }
+    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");
+        errno = -bitmap_size;
+        return NULL;
+    }
+    bitmap = g_new0(BdrvDirtyBitmap, 1);
+    bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
+    bitmap->size = bitmap_size;
+    bitmap->name = g_strdup(name);
+    bitmap->disabled = false;
+    QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
+    return bitmap;
+}
+
+bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
+{
+    return bitmap->successor;
+}
+
+bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
+{
+    return !(bitmap->disabled || bitmap->successor);
+}
+
+DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
+{
+    if (bdrv_dirty_bitmap_frozen(bitmap)) {
+        return DIRTY_BITMAP_STATUS_FROZEN;
+    } else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
+        return DIRTY_BITMAP_STATUS_DISABLED;
+    } else {
+        return DIRTY_BITMAP_STATUS_ACTIVE;
+    }
+}
+
+/**
+ * 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;
+    BdrvDirtyBitmap *child;
+
+    if (bdrv_dirty_bitmap_frozen(bitmap)) {
+        error_setg(errp, "Cannot create a successor for a bitmap that is "
+                   "currently frozen");
+        return -1;
+    }
+    assert(!bitmap->successor);
+
+    /* Create an anonymous successor */
+    granularity = bdrv_dirty_bitmap_granularity(bitmap);
+    child = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
+    if (!child) {
+        return -1;
+    }
+
+    /* Successor will be on or off based on our current state. */
+    child->disabled = bitmap->disabled;
+
+    /* Install the successor and freeze the parent */
+    bitmap->successor = child;
+    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");
+        return NULL;
+    }
+
+    name = bitmap->name;
+    bitmap->name = NULL;
+    successor->name = name;
+    bitmap->successor = NULL;
+    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");
+        return NULL;
+    }
+
+    if (!hbitmap_merge(parent->bitmap, successor->bitmap)) {
+        error_setg(errp, "Merging of parent and successor bitmap failed");
+        return NULL;
+    }
+    bdrv_release_dirty_bitmap(bs, successor);
+    parent->successor = NULL;
+
+    return parent;
+}
+
+/**
+ * Truncates _all_ bitmaps attached to a BDS.
+ */
+void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
+{
+    BdrvDirtyBitmap *bitmap;
+    uint64_t size = bdrv_nb_sectors(bs);
+
+    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
+        assert(!bdrv_dirty_bitmap_frozen(bitmap));
+        hbitmap_truncate(bitmap->bitmap, size);
+        bitmap->size = size;
+    }
+}
+
+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(!bdrv_dirty_bitmap_frozen(bm));
+            QLIST_REMOVE(bitmap, list);
+            hbitmap_free(bitmap->bitmap);
+            g_free(bitmap->name);
+            g_free(bitmap);
+            return;
+        }
+    }
+}
+
+void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
+{
+    assert(!bdrv_dirty_bitmap_frozen(bitmap));
+    bitmap->disabled = true;
+}
+
+void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
+{
+    assert(!bdrv_dirty_bitmap_frozen(bitmap));
+    bitmap->disabled = false;
+}
+
+BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
+{
+    BdrvDirtyBitmap *bm;
+    BlockDirtyInfoList *list = NULL;
+    BlockDirtyInfoList **plist = &list;
+
+    QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
+        BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
+        BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
+        info->count = bdrv_get_dirty_count(bm);
+        info->granularity = bdrv_dirty_bitmap_granularity(bm);
+        info->has_name = !!bm->name;
+        info->name = g_strdup(bm->name);
+        info->status = bdrv_dirty_bitmap_status(bm);
+        entry->value = info;
+        *plist = entry;
+        plist = &entry->next;
+    }
+
+    return list;
+}
+
+int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector)
+{
+    if (bitmap) {
+        return hbitmap_get(bitmap->bitmap, sector);
+    } else {
+        return 0;
+    }
+}
+
+/**
+ * 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.
+ */
+uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
+{
+    BlockDriverInfo bdi;
+    uint32_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;
+}
+
+uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
+{
+    return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
+}
+
+void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
+{
+    hbitmap_iter_init(hbi, bitmap->bitmap, 0);
+}
+
+void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
+                           int64_t cur_sector, int nr_sectors)
+{
+    assert(bdrv_dirty_bitmap_enabled(bitmap));
+    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
+}
+
+void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
+                             int64_t cur_sector, int nr_sectors)
+{
+    assert(bdrv_dirty_bitmap_enabled(bitmap));
+    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
+}
+
+void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
+{
+    assert(bdrv_dirty_bitmap_enabled(bitmap));
+    if (!out) {
+        hbitmap_reset_all(bitmap->bitmap);
+    } else {
+        HBitmap *backup = bitmap->bitmap;
+        bitmap->bitmap = hbitmap_alloc(bitmap->size,
+                                       hbitmap_granularity(backup));
+        *out = backup;
+    }
+}
+
+void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
+{
+    HBitmap *tmp = bitmap->bitmap;
+    assert(bdrv_dirty_bitmap_enabled(bitmap));
+    bitmap->bitmap = in;
+    hbitmap_free(tmp);
+}
+
+void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
+                    int nr_sectors)
+{
+    BdrvDirtyBitmap *bitmap;
+    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
+        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
+            continue;
+        }
+        hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
+    }
+}
+
+/**
+ * Advance an HBitmapIter to an arbitrary offset.
+ */
+void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
+{
+    assert(hbi->hb);
+    hbitmap_iter_init(hbi, hbi->hb, offset);
+}
+
+int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
+{
+    return hbitmap_count(bitmap->bitmap);
+}
diff --git a/include/block/block.h b/include/block/block.h
index 483bfd3..339906b 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -6,6 +6,7 @@
 #include "qemu/option.h"
 #include "qemu/coroutine.h"
 #include "block/accounting.h"
+#include "block/dirty-bitmap.h"
 #include "qapi/qmp/qobject.h"
 #include "qapi-types.h"
 #include "qemu/hbitmap.h"
@@ -473,40 +474,6 @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
 void *qemu_try_blockalign0(BlockDriverState *bs, size_t size);
 bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
 
-BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
-                                          uint32_t 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(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);
-uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
-uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
-bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
-bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
-DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
-int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
-void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
-                           int64_t cur_sector, int nr_sectors);
-void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
-                             int64_t cur_sector, int nr_sectors);
-void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
-void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
-int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
-
 void bdrv_enable_copy_on_read(BlockDriverState *bs);
 void bdrv_disable_copy_on_read(BlockDriverState *bs);
 
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
new file mode 100644
index 0000000..02a9337
--- /dev/null
+++ b/include/block/dirty-bitmap.h
@@ -0,0 +1,43 @@
+#ifndef BLOCK_DIRTY_BITMAP_H
+#define BLOCK_DIRTY_BITMAP_H
+
+#include "qemu-common.h"
+#include "qemu/hbitmap.h"
+
+typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
+BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
+                                          uint32_t 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(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);
+uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
+uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
+bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
+bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
+DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
+int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
+void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
+                           int64_t cur_sector, int nr_sectors);
+void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
+                             int64_t cur_sector, int nr_sectors);
+void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
+void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
+int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
+void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
+
+#endif
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 04/13] block: Remove unused typedef of BlockDriverDirtyHandler
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (2 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 03/13] block: Move block dirty bitmap code to separate files Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 05/13] block: Hide HBitmap in block dirty bitmap interface Fam Zheng
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
 include/block/block.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/include/block/block.h b/include/block/block.h
index 339906b..054bf83 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -322,8 +322,6 @@ BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs,
                                         const char *node_name, Error **errp);
 
 /* async block I/O */
-typedef void BlockDriverDirtyHandler(BlockDriverState *bs, int64_t sector,
-                                     int sector_num);
 BlockAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
                            QEMUIOVector *iov, int nb_sectors,
                            BlockCompletionFunc *cb, void *opaque);
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 05/13] block: Hide HBitmap in block dirty bitmap interface
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (3 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 04/13] block: Remove unused typedef of BlockDriverDirtyHandler Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-26 16:02   ` Vladimir Sementsov-Ogievskiy
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 06/13] HBitmap: Introduce "meta" bitmap to track bit changes Fam Zheng
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

HBitmap is an implementation detail of block dirty bitmap that should be hidden
from users. Introduce a BdrvDirtyBitmapIter to encapsulate the underlying
HBitmapIter.

A small difference in the interface is, before, an HBitmapIter is initialized
in place, now the new BdrvDirtyBitmapIter must be dynamically allocated because
the structure definition is in block.c.

Two current users are converted too.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
 block/backup.c               | 14 ++++++++------
 block/dirty-bitmap.c         | 37 ++++++++++++++++++++++++++++++++-----
 block/mirror.c               | 14 ++++++++------
 include/block/dirty-bitmap.h |  7 +++++--
 include/qemu/typedefs.h      |  1 +
 5 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/block/backup.c b/block/backup.c
index 56ddec0..2388039 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -326,14 +326,14 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
     int64_t end;
     int64_t last_cluster = -1;
     BlockDriverState *bs = job->common.bs;
-    HBitmapIter hbi;
+    BdrvDirtyBitmapIter *dbi;
 
     granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
     clusters_per_iter = MAX((granularity / BACKUP_CLUSTER_SIZE), 1);
-    bdrv_dirty_iter_init(job->sync_bitmap, &hbi);
+    dbi = bdrv_dirty_iter_new(job->sync_bitmap, 0);
 
     /* Find the next dirty sector(s) */
-    while ((sector = hbitmap_iter_next(&hbi)) != -1) {
+    while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
         cluster = sector / BACKUP_SECTORS_PER_CLUSTER;
 
         /* Fake progress updates for any clusters we skipped */
@@ -345,7 +345,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
         for (end = cluster + clusters_per_iter; cluster < end; cluster++) {
             do {
                 if (yield_and_check(job)) {
-                    return ret;
+                    goto out;
                 }
                 ret = backup_do_cow(bs, cluster * BACKUP_SECTORS_PER_CLUSTER,
                                     BACKUP_SECTORS_PER_CLUSTER, &error_is_read,
@@ -353,7 +353,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
                 if ((ret < 0) &&
                     backup_error_action(job, error_is_read, -ret) ==
                     BLOCK_ERROR_ACTION_REPORT) {
-                    return ret;
+                    goto out;
                 }
             } while (ret < 0);
         }
@@ -361,7 +361,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
         /* If the bitmap granularity is smaller than the backup granularity,
          * we need to advance the iterator pointer to the next cluster. */
         if (granularity < BACKUP_CLUSTER_SIZE) {
-            bdrv_set_dirty_iter(&hbi, cluster * BACKUP_SECTORS_PER_CLUSTER);
+            bdrv_set_dirty_iter(dbi, cluster * BACKUP_SECTORS_PER_CLUSTER);
         }
 
         last_cluster = cluster - 1;
@@ -373,6 +373,8 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
         job->common.offset += ((end - last_cluster - 1) * BACKUP_CLUSTER_SIZE);
     }
 
+out:
+    bdrv_dirty_iter_free(dbi);
     return ret;
 }
 
diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index 7924c38..bd7758b 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -41,9 +41,15 @@ struct BdrvDirtyBitmap {
     char *name;                 /* Optional non-empty unique ID */
     int64_t size;               /* Size of the bitmap (Number of sectors) */
     bool disabled;              /* Bitmap is read-only */
+    int active_iterators;       /* How many iterators are active */
     QLIST_ENTRY(BdrvDirtyBitmap) list;
 };
 
+struct BdrvDirtyBitmapIter {
+    HBitmapIter hbi;
+    BdrvDirtyBitmap *bitmap;
+};
+
 BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
 {
     BdrvDirtyBitmap *bm;
@@ -211,6 +217,7 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
 
     QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
         assert(!bdrv_dirty_bitmap_frozen(bitmap));
+        assert(!bitmap->active_iterators);
         hbitmap_truncate(bitmap->bitmap, size);
         bitmap->size = size;
     }
@@ -221,6 +228,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(!bitmap->active_iterators);
             assert(!bdrv_dirty_bitmap_frozen(bm));
             QLIST_REMOVE(bitmap, list);
             hbitmap_free(bitmap->bitmap);
@@ -299,9 +307,29 @@ uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
     return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
 }
 
-void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
+BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
+                                         uint64_t first_sector)
 {
-    hbitmap_iter_init(hbi, bitmap->bitmap, 0);
+    BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
+    hbitmap_iter_init(&iter->hbi, bitmap->bitmap, first_sector);
+    iter->bitmap = bitmap;
+    bitmap->active_iterators++;
+    return iter;
+}
+
+void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
+{
+    if (!iter) {
+        return;
+    }
+    assert(iter->bitmap->active_iterators > 0);
+    iter->bitmap->active_iterators--;
+    g_free(iter);
+}
+
+int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
+{
+    return hbitmap_iter_next(&iter->hbi);
 }
 
 void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
@@ -354,10 +382,9 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
 /**
  * Advance an HBitmapIter to an arbitrary offset.
  */
-void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
+void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t sector_num)
 {
-    assert(hbi->hb);
-    hbitmap_iter_init(hbi, hbi->hb, offset);
+    hbitmap_iter_init(&iter->hbi, iter->bitmap->bitmap, sector_num);
 }
 
 int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
diff --git a/block/mirror.c b/block/mirror.c
index f201f2b..70ca844 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -52,7 +52,7 @@ typedef struct MirrorBlockJob {
     int64_t bdev_length;
     unsigned long *cow_bitmap;
     BdrvDirtyBitmap *dirty_bitmap;
-    HBitmapIter hbi;
+    BdrvDirtyBitmapIter *dbi;
     uint8_t *buf;
     QSIMPLEQ_HEAD(, MirrorBuffer) buf_free;
     int buf_free_count;
@@ -170,10 +170,11 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
 
     max_iov = MIN(source->bl.max_iov, s->target->bl.max_iov);
 
-    s->sector_num = hbitmap_iter_next(&s->hbi);
+    s->sector_num = bdrv_dirty_iter_next(s->dbi);
     if (s->sector_num < 0) {
-        bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
-        s->sector_num = hbitmap_iter_next(&s->hbi);
+        bdrv_dirty_iter_free(s->dbi);
+        s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap, 0);
+        s->sector_num = bdrv_dirty_iter_next(s->dbi);
         trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
         assert(s->sector_num >= 0);
     }
@@ -291,7 +292,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
          */
         if (next_sector > hbitmap_next_sector
             && bdrv_get_dirty(source, s->dirty_bitmap, next_sector)) {
-            hbitmap_next_sector = hbitmap_iter_next(&s->hbi);
+            hbitmap_next_sector = bdrv_dirty_iter_next(s->dbi);
         }
 
         next_sector += sectors_per_chunk;
@@ -502,7 +503,7 @@ static void coroutine_fn mirror_run(void *opaque)
         }
     }
 
-    bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
+    s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap, 0);
     for (;;) {
         uint64_t delay_ns = 0;
         int64_t cnt;
@@ -615,6 +616,7 @@ immediate_exit:
     qemu_vfree(s->buf);
     g_free(s->cow_bitmap);
     g_free(s->in_flight_bitmap);
+    bdrv_dirty_iter_free(s->dbi);
     bdrv_release_dirty_bitmap(bs, s->dirty_bitmap);
     if (s->target->blk) {
         blk_iostatus_disable(s->target->blk);
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 02a9337..120bac6 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -35,8 +35,11 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                            int64_t cur_sector, int nr_sectors);
 void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                              int64_t cur_sector, int nr_sectors);
-void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
-void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
+BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
+                                         uint64_t first_sector);
+void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
+int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
+void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
 int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
 
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 0cf9d74..a1bdb5a 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -11,6 +11,7 @@ typedef struct AioContext AioContext;
 typedef struct AllwinnerAHCIState AllwinnerAHCIState;
 typedef struct AudioState AudioState;
 typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
+typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter;
 typedef struct BlockBackend BlockBackend;
 typedef struct BlockBackendRootState BlockBackendRootState;
 typedef struct BlockDriverState BlockDriverState;
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 06/13] HBitmap: Introduce "meta" bitmap to track bit changes
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (4 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 05/13] block: Hide HBitmap in block dirty bitmap interface Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-25 22:02   ` John Snow
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 07/13] tests: Add test code for meta bitmap Fam Zheng
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

Upon each bit toggle, the corresponding bit in the meta bitmap will be
set.

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 include/qemu/hbitmap.h | 17 +++++++++++++
 util/hbitmap.c         | 66 ++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
index bb94a00..595ad65 100644
--- a/include/qemu/hbitmap.h
+++ b/include/qemu/hbitmap.h
@@ -181,6 +181,23 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
  */
 unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi);
 
+/* hbitmap_create_meta:
+ * Create a "meta" hbitmap to track dirtiness of the bits in this HBitmap.
+ * The caller owns the created bitmap and must call hbitmap_free_meta(hb) to
+ * free it.
+ *
+ * @hb: The HBitmap to operate on.
+ * @chunk_size: How many bits in @hb does one bit in the meta track.
+ */
+HBitmap *hbitmap_create_meta(HBitmap *hb, int chunk_size);
+
+/* hbitmap_free_meta:
+ * Free the meta bitmap of @hb.
+ *
+ * @hb: The HBitmap whose meta bitmap should be freed.
+ */
+void hbitmap_free_meta(HBitmap *hb);
+
 /**
  * hbitmap_iter_next:
  * @hbi: HBitmapIter to operate on.
diff --git a/util/hbitmap.c b/util/hbitmap.c
index 50b888f..79f6236 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -81,6 +81,9 @@ struct HBitmap {
      */
     int granularity;
 
+    /* A meta dirty bitmap to track the dirtiness of bits in this HBitmap. */
+    HBitmap *meta;
+
     /* A number of progressively less coarse bitmaps (i.e. level 0 is the
      * coarsest).  Each bit in level N represents a word in level N+1 that
      * has a set bit, except the last level where each bit represents the
@@ -212,25 +215,27 @@ static uint64_t hb_count_between(HBitmap *hb, uint64_t start, uint64_t last)
 }
 
 /* Setting starts at the last layer and propagates up if an element
- * changes from zero to non-zero.
+ * changes.
  */
 static inline bool hb_set_elem(unsigned long *elem, uint64_t start, uint64_t last)
 {
     unsigned long mask;
-    bool changed;
+    unsigned long old;
 
     assert((last >> BITS_PER_LEVEL) == (start >> BITS_PER_LEVEL));
     assert(start <= last);
 
     mask = 2UL << (last & (BITS_PER_LONG - 1));
     mask -= 1UL << (start & (BITS_PER_LONG - 1));
-    changed = (*elem == 0);
+    old = *elem;
     *elem |= mask;
-    return changed;
+    return old != *elem;
 }
 
-/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)... */
-static void hb_set_between(HBitmap *hb, int level, uint64_t start, uint64_t last)
+/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)...
+ * Returns true if at least one bit is changed. */
+static bool hb_set_between(HBitmap *hb, int level, uint64_t start,
+                           uint64_t last)
 {
     size_t pos = start >> BITS_PER_LEVEL;
     size_t lastpos = last >> BITS_PER_LEVEL;
@@ -259,22 +264,27 @@ static void hb_set_between(HBitmap *hb, int level, uint64_t start, uint64_t last
     if (level > 0 && changed) {
         hb_set_between(hb, level - 1, pos, lastpos);
     }
+    return changed;
 }
 
 void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count)
 {
     /* Compute range in the last layer.  */
+    uint64_t first, n;
     uint64_t last = start + count - 1;
 
     trace_hbitmap_set(hb, start, count,
                       start >> hb->granularity, last >> hb->granularity);
 
-    start >>= hb->granularity;
+    first = start >> hb->granularity;
     last >>= hb->granularity;
-    count = last - start + 1;
+    n = last - first + 1;
 
-    hb->count += count - hb_count_between(hb, start, last);
-    hb_set_between(hb, HBITMAP_LEVELS - 1, start, last);
+    hb->count += n - hb_count_between(hb, first, last);
+    if (hb_set_between(hb, HBITMAP_LEVELS - 1, first, last) &&
+        hb->meta) {
+        hbitmap_set(hb->meta, start, count);
+    }
 }
 
 /* Resetting works the other way round: propagate up if the new
@@ -295,8 +305,10 @@ static inline bool hb_reset_elem(unsigned long *elem, uint64_t start, uint64_t l
     return blanked;
 }
 
-/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)... */
-static void hb_reset_between(HBitmap *hb, int level, uint64_t start, uint64_t last)
+/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)...
+ * Returns true if at least one bit is changed. */
+static bool hb_reset_between(HBitmap *hb, int level, uint64_t start,
+                             uint64_t last)
 {
     size_t pos = start >> BITS_PER_LEVEL;
     size_t lastpos = last >> BITS_PER_LEVEL;
@@ -339,21 +351,28 @@ static void hb_reset_between(HBitmap *hb, int level, uint64_t start, uint64_t la
     if (level > 0 && changed) {
         hb_reset_between(hb, level - 1, pos, lastpos);
     }
+
+    return changed;
+
 }
 
 void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count)
 {
     /* Compute range in the last layer.  */
+    uint64_t first;
     uint64_t last = start + count - 1;
 
     trace_hbitmap_reset(hb, start, count,
                         start >> hb->granularity, last >> hb->granularity);
 
-    start >>= hb->granularity;
+    first = start >> hb->granularity;
     last >>= hb->granularity;
 
-    hb->count -= hb_count_between(hb, start, last);
-    hb_reset_between(hb, HBITMAP_LEVELS - 1, start, last);
+    hb->count -= hb_count_between(hb, first, last);
+    if (hb_reset_between(hb, HBITMAP_LEVELS - 1, first, last) &&
+        hb->meta) {
+        hbitmap_set(hb->meta, start, count);
+    }
 }
 
 void hbitmap_reset_all(HBitmap *hb)
@@ -381,6 +400,7 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
 void hbitmap_free(HBitmap *hb)
 {
     unsigned i;
+    assert(!hb->meta);
     for (i = HBITMAP_LEVELS; i-- > 0; ) {
         g_free(hb->levels[i]);
     }
@@ -493,3 +513,19 @@ bool hbitmap_merge(HBitmap *a, const HBitmap *b)
 
     return true;
 }
+
+HBitmap *hbitmap_create_meta(HBitmap *hb, int chunk_size)
+{
+    assert(!(chunk_size & (chunk_size - 1)));
+    assert(!hb->meta);
+    hb->meta = hbitmap_alloc(hb->size << hb->granularity,
+                             hb->granularity + ctz32(chunk_size));
+    return hb->meta;
+}
+
+void hbitmap_free_meta(HBitmap *hb)
+{
+    assert(hb->meta);
+    hbitmap_free(hb->meta);
+    hb->meta = NULL;
+}
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 07/13] tests: Add test code for meta bitmap
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (5 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 06/13] HBitmap: Introduce "meta" bitmap to track bit changes Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap Fam Zheng
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
 tests/test-hbitmap.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
index abcea0c..a341803 100644
--- a/tests/test-hbitmap.c
+++ b/tests/test-hbitmap.c
@@ -14,6 +14,7 @@
 #include <string.h>
 #include <sys/types.h>
 #include "qemu/hbitmap.h"
+#include "block/block.h"
 
 #define LOG_BITS_PER_LONG          (BITS_PER_LONG == 32 ? 5 : 6)
 
@@ -23,6 +24,7 @@
 
 typedef struct TestHBitmapData {
     HBitmap       *hb;
+    HBitmap       *meta;
     unsigned long *bits;
     size_t         size;
     size_t         old_size;
@@ -94,6 +96,14 @@ static void hbitmap_test_init(TestHBitmapData *data,
     }
 }
 
+static void hbitmap_test_init_meta(TestHBitmapData *data,
+                                   uint64_t size, int granularity,
+                                   int meta_chunk)
+{
+    hbitmap_test_init(data, size, granularity);
+    data->meta = hbitmap_create_meta(data->hb, meta_chunk);
+}
+
 static inline size_t hbitmap_test_array_size(size_t bits)
 {
     size_t n = (bits + BITS_PER_LONG - 1) / BITS_PER_LONG;
@@ -136,6 +146,9 @@ static void hbitmap_test_teardown(TestHBitmapData *data,
                                   const void *unused)
 {
     if (data->hb) {
+        if (data->meta) {
+            hbitmap_free_meta(data->hb);
+        }
         hbitmap_free(data->hb);
         data->hb = NULL;
     }
@@ -637,6 +650,103 @@ static void test_hbitmap_truncate_shrink_large(TestHBitmapData *data,
     hbitmap_test_truncate(data, size, -diff, 0);
 }
 
+static void hbitmap_check_meta(TestHBitmapData *data,
+                               int64_t start, int count)
+{
+    int64_t i;
+
+    for (i = 0; i < data->size; i++) {
+        if (i >= start && i < start + count) {
+            g_assert(hbitmap_get(data->meta, i));
+        } else {
+            g_assert(!hbitmap_get(data->meta, i));
+        }
+    }
+}
+
+static void hbitmap_test_meta(TestHBitmapData *data,
+                              int64_t start, int count,
+                              int64_t check_start, int check_count)
+{
+    hbitmap_reset_all(data->hb);
+    hbitmap_reset_all(data->meta);
+
+    /* Test "unset" -> "unset" will not update meta. */
+    hbitmap_reset(data->hb, start, count);
+    hbitmap_check_meta(data, 0, 0);
+
+    /* Test "unset" -> "set" will update meta */
+    hbitmap_set(data->hb, start, count);
+    hbitmap_check_meta(data, check_start, check_count);
+
+    /* Test "set" -> "set" will not update meta */
+    hbitmap_reset_all(data->meta);
+    hbitmap_set(data->hb, start, count);
+    hbitmap_check_meta(data, 0, 0);
+
+    /* Test "set" -> "unset" will update meta */
+    hbitmap_reset_all(data->meta);
+    hbitmap_reset(data->hb, start, count);
+    hbitmap_check_meta(data, check_start, check_count);
+}
+
+static void hbitmap_test_meta_do(TestHBitmapData *data, int chunk_size)
+{
+    uint64_t size = chunk_size * 100;
+    hbitmap_test_init_meta(data, size, 0, chunk_size);
+
+    hbitmap_test_meta(data, 0, 1, 0, chunk_size);
+    hbitmap_test_meta(data, 0, chunk_size, 0, chunk_size);
+    hbitmap_test_meta(data, chunk_size - 1, 1, 0, chunk_size);
+    hbitmap_test_meta(data, chunk_size - 1, 2, 0, chunk_size * 2);
+    hbitmap_test_meta(data, chunk_size - 1, chunk_size + 1, 0, chunk_size * 2);
+    hbitmap_test_meta(data, chunk_size - 1, chunk_size + 2, 0, chunk_size * 3);
+    hbitmap_test_meta(data, 7 * chunk_size - 1, chunk_size + 2,
+                      6 * chunk_size, chunk_size * 3);
+    hbitmap_test_meta(data, size - 1, 1, size - chunk_size, chunk_size);
+    hbitmap_test_meta(data, 0, size, 0, size);
+}
+
+static void test_hbitmap_meta_byte(TestHBitmapData *data, const void *unused)
+{
+    hbitmap_test_meta_do(data, BITS_PER_BYTE);
+}
+
+static void test_hbitmap_meta_word(TestHBitmapData *data, const void *unused)
+{
+    hbitmap_test_meta_do(data, BITS_PER_LONG);
+}
+
+static void test_hbitmap_meta_sector(TestHBitmapData *data, const void *unused)
+{
+    hbitmap_test_meta_do(data, BDRV_SECTOR_SIZE * BITS_PER_BYTE);
+}
+
+/**
+ * Create an HBitmap and test set/unset.
+ */
+static void test_hbitmap_meta_one(TestHBitmapData *data, const void *unused)
+{
+    int i;
+    int64_t offsets[] = {
+        0, 1, L1 - 1, L1, L1 + 1, L2 - 1, L2, L2 + 1, L3 - 1, L3, L3 + 1
+    };
+
+    hbitmap_test_init_meta(data, L3 * 2, 0, 1);
+    for (i = 0; i < ARRAY_SIZE(offsets); i++) {
+        hbitmap_test_meta(data, offsets[i], 1, offsets[i], 1);
+        hbitmap_test_meta(data, offsets[i], L1, offsets[i], L1);
+        hbitmap_test_meta(data, offsets[i], L2, offsets[i], L2);
+    }
+}
+
+static void test_hbitmap_meta_zero(TestHBitmapData *data, const void *unused)
+{
+    hbitmap_test_init_meta(data, 0, 0, 1);
+
+    hbitmap_check_meta(data, 0, 0);
+}
+
 static void hbitmap_test_add(const char *testpath,
                                    void (*test_func)(TestHBitmapData *data, const void *user_data))
 {
@@ -686,6 +796,12 @@ int main(int argc, char **argv)
                      test_hbitmap_truncate_grow_large);
     hbitmap_test_add("/hbitmap/truncate/shrink/large",
                      test_hbitmap_truncate_shrink_large);
+
+    hbitmap_test_add("/hbitmap/meta/zero", test_hbitmap_meta_zero);
+    hbitmap_test_add("/hbitmap/meta/one", test_hbitmap_meta_one);
+    hbitmap_test_add("/hbitmap/meta/byte", test_hbitmap_meta_byte);
+    hbitmap_test_add("/hbitmap/meta/word", test_hbitmap_meta_word);
+    hbitmap_test_add("/hbitmap/meta/sector", test_hbitmap_meta_sector);
     g_test_run();
 
     return 0;
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (6 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 07/13] tests: Add test code for meta bitmap Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-22 11:34   ` Vladimir Sementsov-Ogievskiy
                     ` (2 more replies)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 09/13] block: Add two dirty bitmap getters Fam Zheng
                   ` (7 subsequent siblings)
  15 siblings, 3 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

The added group of operations enables tracking of the changed bits in
the dirty bitmap.

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 block/dirty-bitmap.c         | 51 ++++++++++++++++++++++++++++++++++++++++++++
 include/block/dirty-bitmap.h |  9 ++++++++
 2 files changed, 60 insertions(+)

diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index bd7758b..d75dcf7 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -37,6 +37,7 @@
  */
 struct BdrvDirtyBitmap {
     HBitmap *bitmap;            /* Dirty sector bitmap implementation */
+    HBitmap *meta;              /* Meta dirty bitmap */
     BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
     char *name;                 /* Optional non-empty unique ID */
     int64_t size;               /* Size of the bitmap (Number of sectors) */
@@ -102,6 +103,56 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
     return bitmap;
 }
 
+/* bdrv_create_meta_dirty_bitmap
+ *
+ * Create a meta dirty bitmap that tracks the changes of bits in @bitmap. I.e.
+ * when a dirty status bit in @bitmap is changed (either from reset to set or
+ * the other way around), its respective meta dirty bitmap bit will be marked
+ * dirty as well.
+ *
+ * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
+ * @granularity: how many bytes of bitmap data does each bit in the meta bitmap
+ * track.
+ */
+void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
+                                   int granularity)
+{
+    assert(!bitmap->meta);
+    bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
+                                       BDRV_SECTOR_SIZE * BITS_PER_BYTE);
+}
+
+void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
+{
+    assert(bitmap->meta);
+    hbitmap_free_meta(bitmap->bitmap);
+    bitmap->meta = NULL;
+}
+
+int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
+                               BdrvDirtyBitmap *bitmap, int64_t sector,
+                               int nb_sectors)
+{
+    uint64_t i;
+    int gran = bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
+
+    /* To optimize: we can make hbitmap to internally check the range in a
+     * coarse level, or at least do it word by word. */
+    for (i = sector; i < sector + nb_sectors; i += gran) {
+        if (hbitmap_get(bitmap->meta, i)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
+                                  BdrvDirtyBitmap *bitmap, int64_t sector,
+                                  int nb_sectors)
+{
+    hbitmap_reset(bitmap->meta, sector, nb_sectors);
+}
+
 bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
 {
     return bitmap->successor;
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 120bac6..d9b281a 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -9,6 +9,9 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
                                           uint32_t granularity,
                                           const char *name,
                                           Error **errp);
+void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
+                                   int granularity);
+void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
 int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
                                        BdrvDirtyBitmap *bitmap,
                                        Error **errp);
@@ -35,6 +38,12 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                            int64_t cur_sector, int nr_sectors);
 void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
                              int64_t cur_sector, int nr_sectors);
+int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
+                               BdrvDirtyBitmap *bitmap, int64_t sector,
+                               int nb_sectors);
+void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
+                                  BdrvDirtyBitmap *bitmap, int64_t sector,
+                                  int nb_sectors);
 BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
                                          uint64_t first_sector);
 void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 09/13] block: Add two dirty bitmap getters
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (7 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-22 11:45   ` Vladimir Sementsov-Ogievskiy
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 10/13] block: Assert that bdrv_release_dirty_bitmap succeeded Fam Zheng
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

For dirty bitmap users to get the size and the name of a
BdrvDirtyBitmap.

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

diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index d75dcf7..de143f1 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -153,6 +153,16 @@ void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
     hbitmap_reset(bitmap->meta, sector, nb_sectors);
 }
 
+int64_t bdrv_dirty_bitmap_size(BdrvDirtyBitmap *bitmap)
+{
+    return bitmap->size;
+}
+
+const char *bdrv_dirty_bitmap_name(BdrvDirtyBitmap *bitmap)
+{
+    return bitmap->name;
+}
+
 bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
 {
     return bitmap->successor;
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index d9b281a..8c29c3e 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -32,6 +32,8 @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
 uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
+const char *bdrv_dirty_bitmap_name(BdrvDirtyBitmap *bitmap);
+int64_t bdrv_dirty_bitmap_size(BdrvDirtyBitmap *bitmap);
 DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
 int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
 void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 10/13] block: Assert that bdrv_release_dirty_bitmap succeeded
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (8 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 09/13] block: Add two dirty bitmap getters Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 11/13] hbitmap: serialization Fam Zheng
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

This makes sure we don't leak a dirty bitmap in any case.

Signed-off-by: Fam Zheng <famz@redhat.com>
Reviewed-by: John Snow <jsnow@redhat.com>
---
 block/dirty-bitmap.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index de143f1..ec13d38 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -298,6 +298,7 @@ void bdrv_release_dirty_bitmap(BlockDriverState *bs, BdrvDirtyBitmap *bitmap)
             return;
         }
     }
+    abort();
 }
 
 void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 11/13] hbitmap: serialization
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (9 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 10/13] block: Assert that bdrv_release_dirty_bitmap succeeded Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-26 17:01   ` John Snow
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 12/13] block: BdrvDirtyBitmap serialization interface Fam Zheng
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

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

Functions to serialize / deserialize(restore) HBitmap. HBitmap should be
saved to linear sequence of bits independently of endianness and bitmap
array element (unsigned long) size. Therefore Little Endian is chosen.

These functions are appropriate for dirty bitmap migration, restoring
the bitmap in several steps is available. To save performance, every
step writes only the last level of the bitmap. All other levels are
restored by hbitmap_deserialize_finish() as a last step of restoring.
So, HBitmap is inconsistent while restoring.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
[Fix left shift operand to 1UL; add "finish" parameter. - Fam]
Signed-off-by: Fam Zheng <famz@redhat.com>
---
 include/qemu/hbitmap.h |  78 ++++++++++++++++++++++++++++
 util/hbitmap.c         | 135 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 213 insertions(+)

diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
index 595ad65..00dbb60 100644
--- a/include/qemu/hbitmap.h
+++ b/include/qemu/hbitmap.h
@@ -149,6 +149,84 @@ void hbitmap_reset_all(HBitmap *hb);
 bool hbitmap_get(const HBitmap *hb, uint64_t item);
 
 /**
+ * hbitmap_serialization_granularity:
+ * @hb: HBitmap to operate on.
+ *
+ * Grunularity of serialization chunks, used by other serializetion functions.
+ * For every chunk:
+ * 1. Chunk start should be aligned to this granularity.
+ * 2. Chunk size should be aligned too, except for last chunk (for which
+ *      start + count == hb->size)
+ */
+uint64_t hbitmap_serialization_granularity(const HBitmap *hb);
+
+/**
+ * hbitmap_data_size:
+ * @hb: HBitmap to operate on.
+ * @count: Number of bits
+ *
+ * Return amount of bytes hbitmap_(de)serialize_part needs
+ */
+uint64_t hbitmap_serialization_size(const HBitmap *hb,
+                                    uint64_t start, uint64_t count);
+
+/**
+ * hbitmap_serialize_part
+ * @hb: HBitmap to operate on.
+ * @buf: Buffer to store serialized bitmap.
+ * @start: First bit to store.
+ * @count: Number of bits to store.
+ *
+ * Stores HBitmap data corresponding to given region. The format of saved data
+ * is linear sequence of bits, so it can be used by hbitmap_deserialize_part
+ * independently of endianness and size of HBitmap level array elements
+ */
+void hbitmap_serialize_part(const HBitmap *hb, uint8_t *buf,
+                            uint64_t start, uint64_t count);
+
+/**
+ * hbitmap_deserialize_part
+ * @hb: HBitmap to operate on.
+ * @buf: Buffer to restore bitmap data from.
+ * @start: First bit to restore.
+ * @count: Number of bits to restore.
+ * @finish: Whether to call hbitmap_deserialize_finish automatically.
+ *
+ * Restores HBitmap data corresponding to given region. The format is the same
+ * as for hbitmap_serialize_part.
+ *
+ * If @finish is false, caller must call hbitmap_serialize_finish before using
+ * the bitmap.
+ */
+void hbitmap_deserialize_part(HBitmap *hb, uint8_t *buf,
+                              uint64_t start, uint64_t count,
+                              bool finish);
+
+/**
+ * hbitmap_deserialize_zeroes
+ * @hb: HBitmap to operate on.
+ * @start: First bit to restore.
+ * @count: Number of bits to restore.
+ * @finish: Whether to call hbitmap_deserialize_finish automatically.
+ *
+ * Fills the bitmap with zeroes.
+ *
+ * If @finish is false, caller must call hbitmap_serialize_finish before using
+ * the bitmap.
+ */
+void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
+                                bool finish);
+
+/**
+ * hbitmap_deserialize_finish
+ * @hb: HBitmap to operate on.
+ *
+ * Repair HBitmap after calling hbitmap_deserialize_data. Actually, all HBitmap
+ * layers are restored here.
+ */
+void hbitmap_deserialize_finish(HBitmap *hb);
+
+/**
  * hbitmap_free:
  * @hb: HBitmap to operate on.
  *
diff --git a/util/hbitmap.c b/util/hbitmap.c
index 79f6236..1e49ab7 100644
--- a/util/hbitmap.c
+++ b/util/hbitmap.c
@@ -397,6 +397,141 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
     return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0;
 }
 
+uint64_t hbitmap_serialization_granularity(const HBitmap *hb)
+{
+    return 64 << hb->granularity;
+}
+
+/* Start should be aligned to serialization granularity, chunk size should be
+ * aligned to serialization granularity too, except for last chunk.
+ */
+static void serialization_chunk(const HBitmap *hb,
+                                uint64_t start, uint64_t count,
+                                unsigned long **first_el, size_t *el_count)
+{
+    uint64_t last = start + count - 1;
+    uint64_t gran = hbitmap_serialization_granularity(hb);
+
+    assert((start & (gran - 1)) == 0);
+    assert((last >> hb->granularity) < hb->size);
+    if ((last >> hb->granularity) != hb->size - 1) {
+        assert((count & (gran - 1)) == 0);
+    }
+
+    start = (start >> hb->granularity) >> BITS_PER_LEVEL;
+    last = (last >> hb->granularity) >> BITS_PER_LEVEL;
+
+    *first_el = &hb->levels[HBITMAP_LEVELS - 1][start];
+    *el_count = last - start + 1;
+}
+
+uint64_t hbitmap_serialization_size(const HBitmap *hb,
+                                    uint64_t start, uint64_t count)
+{
+    uint64_t el_count;
+    unsigned long *cur;
+
+    if (!count) {
+        return 0;
+    }
+    serialization_chunk(hb, start, count, &cur, &el_count);
+
+    return el_count * sizeof(unsigned long);
+}
+
+void hbitmap_serialize_part(const HBitmap *hb, uint8_t *buf,
+                            uint64_t start, uint64_t count)
+{
+    uint64_t el_count;
+    unsigned long *cur, *end;
+
+    if (!count) {
+        return;
+    }
+    serialization_chunk(hb, start, count, &cur, &el_count);
+    end = cur + el_count;
+
+    while (cur != end) {
+        unsigned long el =
+            (BITS_PER_LONG == 32 ? cpu_to_le32(*cur) : cpu_to_le64(*cur));
+
+        memcpy(buf, &el, sizeof(el));
+        buf += sizeof(el);
+        cur++;
+    }
+}
+
+void hbitmap_deserialize_part(HBitmap *hb, uint8_t *buf,
+                              uint64_t start, uint64_t count,
+                              bool finish)
+{
+    uint64_t el_count;
+    unsigned long *cur, *end;
+
+    if (!count) {
+        return;
+    }
+    serialization_chunk(hb, start, count, &cur, &el_count);
+    end = cur + el_count;
+
+    while (cur != end) {
+        memcpy(cur, buf, sizeof(*cur));
+
+        if (BITS_PER_LONG == 32) {
+            le32_to_cpus((uint32_t *)cur);
+        } else {
+            le64_to_cpus((uint64_t *)cur);
+        }
+
+        buf += sizeof(unsigned long);
+        cur++;
+    }
+    if (finish) {
+        hbitmap_deserialize_finish(hb);
+    }
+}
+
+void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
+                                bool finish)
+{
+    uint64_t el_count;
+    unsigned long *first;
+
+    if (!count) {
+        return;
+    }
+    serialization_chunk(hb, start, count, &first, &el_count);
+
+    memset(first, 0, el_count * sizeof(unsigned long));
+    if (finish) {
+        hbitmap_deserialize_finish(hb);
+    }
+}
+
+void hbitmap_deserialize_finish(HBitmap *bitmap)
+{
+    int64_t i, size, prev_size;
+    int lev;
+
+    /* restore levels starting from penultimate to zero level, assuming
+     * that the last level is ok */
+    size = MAX((bitmap->size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
+    for (lev = HBITMAP_LEVELS - 1; lev-- > 0; ) {
+        prev_size = size;
+        size = MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
+        memset(bitmap->levels[lev], 0, size * sizeof(unsigned long));
+
+        for (i = 0; i < prev_size; ++i) {
+            if (bitmap->levels[lev + 1][i]) {
+                bitmap->levels[lev][i >> BITS_PER_LEVEL] |=
+                    1UL << (i & (BITS_PER_LONG - 1));
+            }
+        }
+    }
+
+    bitmap->levels[0][0] |= 1UL << (BITS_PER_LONG - 1);
+}
+
 void hbitmap_free(HBitmap *hb)
 {
     unsigned i;
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 12/13] block: BdrvDirtyBitmap serialization interface
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (10 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 11/13] hbitmap: serialization Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-26 17:07   ` John Snow
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 13/13] tests: Add test code for hbitmap serialization Fam Zheng
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

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

Several functions to provide necessary access to BdrvDirtyBitmap for
block-migration.c

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
[Add the "finish" parameters. - Fam]
Signed-off-by: Fam Zheng <famz@redhat.com>
---
 block/dirty-bitmap.c         | 37 +++++++++++++++++++++++++++++++++++++
 include/block/dirty-bitmap.h | 14 ++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index ec13d38..919ce10 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -429,6 +429,43 @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
     hbitmap_free(tmp);
 }
 
+uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
+                                              uint64_t start, uint64_t count)
+{
+    return hbitmap_serialization_size(bitmap->bitmap, start, count);
+}
+
+uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
+{
+    return hbitmap_serialization_granularity(bitmap->bitmap);
+}
+
+void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
+                                      uint8_t *buf, uint64_t start,
+                                      uint64_t count)
+{
+    hbitmap_serialize_part(bitmap->bitmap, buf, start, count);
+}
+
+void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
+                                        uint8_t *buf, uint64_t start,
+                                        uint64_t count, bool finish)
+{
+    hbitmap_deserialize_part(bitmap->bitmap, buf, start, count, finish);
+}
+
+void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
+                                          uint64_t start, uint64_t count,
+                                          bool finish)
+{
+    hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish);
+}
+
+void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
+{
+    hbitmap_deserialize_finish(bitmap->bitmap);
+}
+
 void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
                     int nr_sectors)
 {
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 8c29c3e..6ba5bec 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -54,4 +54,18 @@ void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
 int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
 
+uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
+                                              uint64_t start, uint64_t count);
+uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap);
+void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
+                                      uint8_t *buf, uint64_t start,
+                                      uint64_t count);
+void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
+                                        uint8_t *buf, uint64_t start,
+                                        uint64_t count, bool finish);
+void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
+                                          uint64_t start, uint64_t count,
+                                          bool finish);
+void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
+
 #endif
-- 
2.4.3

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

* [Qemu-devel] [PATCH v2 13/13] tests: Add test code for hbitmap serialization
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (11 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 12/13] block: BdrvDirtyBitmap serialization interface Fam Zheng
@ 2016-01-20  6:11 ` Fam Zheng
  2016-01-26 17:10   ` John Snow
  2016-01-20 16:13 ` [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Vladimir Sementsov-Ogievskiy
                   ` (2 subsequent siblings)
  15 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-20  6:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 tests/test-hbitmap.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
index a341803..9b89751 100644
--- a/tests/test-hbitmap.c
+++ b/tests/test-hbitmap.c
@@ -14,6 +14,7 @@
 #include <string.h>
 #include <sys/types.h>
 #include "qemu/hbitmap.h"
+#include "qemu/bitmap.h"
 #include "block/block.h"
 
 #define LOG_BITS_PER_LONG          (BITS_PER_LONG == 32 ? 5 : 6)
@@ -740,6 +741,16 @@ static void test_hbitmap_meta_one(TestHBitmapData *data, const void *unused)
     }
 }
 
+static void test_hbitmap_serialize_granularity(TestHBitmapData *data,
+                                               const void *unused)
+{
+    int r;
+
+    hbitmap_test_init(data, L3 * 2, 3);
+    r = hbitmap_serialization_granularity(data->hb);
+    g_assert_cmpint(r, ==, BITS_PER_LONG << 3);
+}
+
 static void test_hbitmap_meta_zero(TestHBitmapData *data, const void *unused)
 {
     hbitmap_test_init_meta(data, 0, 0, 1);
@@ -747,6 +758,125 @@ static void test_hbitmap_meta_zero(TestHBitmapData *data, const void *unused)
     hbitmap_check_meta(data, 0, 0);
 }
 
+static void hbitmap_test_serialize_range(TestHBitmapData *data,
+                                         uint8_t *buf, size_t buf_size,
+                                         uint64_t pos, uint64_t count)
+{
+    size_t i;
+
+    assert(hbitmap_granularity(data->hb) == 0);
+    hbitmap_reset_all(data->hb);
+    memset(buf, 0, buf_size);
+    if (count) {
+        hbitmap_set(data->hb, pos, count);
+    }
+    hbitmap_serialize_part(data->hb, buf, 0, data->size);
+    for (i = 0; i < data->size; i++) {
+        int is_set = test_bit(i, (unsigned long *)buf);
+        if (i >= pos && i < pos + count) {
+            g_assert(is_set);
+        } else {
+            g_assert(!is_set);
+        }
+    }
+    hbitmap_reset_all(data->hb);
+    hbitmap_deserialize_part(data->hb, buf, 0, data->size, true);
+
+    for (i = 0; i < data->size; i++) {
+        int is_set = hbitmap_get(data->hb, i);
+        if (i >= pos && i < pos + count) {
+            g_assert(is_set);
+        } else {
+            g_assert(!is_set);
+        }
+    }
+}
+
+static void test_hbitmap_serialize_basic(TestHBitmapData *data,
+                                         const void *unused)
+{
+    int i, j;
+    size_t buf_size;
+    uint8_t *buf;
+    uint64_t positions[] = { 0, 1, L1 - 1, L1, L2 - 1, L2, L2 + 1, L3 - 1 };
+    int num_positions = sizeof(positions) / sizeof(positions[0]);
+
+    hbitmap_test_init(data, L3, 0);
+    buf_size = hbitmap_serialization_size(data->hb, 0, data->size);
+    buf = g_malloc0(buf_size);
+
+    for (i = 0; i < num_positions; i++) {
+        for (j = 0; j < num_positions; j++) {
+            hbitmap_test_serialize_range(data, buf, buf_size,
+                                         positions[i],
+                                         MIN(positions[j], L3 - positions[i]));
+        }
+    }
+
+    g_free(buf);
+}
+
+static void test_hbitmap_serialize_part(TestHBitmapData *data,
+                                        const void *unused)
+{
+    int i, j, k;
+    size_t buf_size;
+    uint8_t *buf;
+    uint64_t positions[] = { 0, 1, L1 - 1, L1, L2 - 1, L2, L2 + 1, L3 - 1 };
+    int num_positions = sizeof(positions) / sizeof(positions[0]);
+
+    hbitmap_test_init(data, L3, 0);
+    buf_size = L2;
+    buf = g_malloc0(buf_size);
+
+    for (i = 0; i < num_positions; i++) {
+        hbitmap_set(data->hb, positions[i], 1);
+    }
+
+    for (i = 0; i < data->size; i += buf_size) {
+        hbitmap_serialize_part(data->hb, buf, i, buf_size);
+        for (j = 0; j < buf_size; j++) {
+            bool should_set = false;
+            for (k = 0; k < num_positions; k++) {
+                if (positions[k] == j + i) {
+                    should_set = true;
+                    break;
+                }
+            }
+            g_assert_cmpint(should_set, ==, test_bit(j, (unsigned long *)buf));
+        }
+    }
+
+    g_free(buf);
+}
+
+static void test_hbitmap_serialize_zeroes(TestHBitmapData *data,
+                                          const void *unused)
+{
+    int i;
+    HBitmapIter iter;
+    int64_t next;
+    uint64_t positions[] = { 0, L1, L2, L3 - L1};
+    int num_positions = sizeof(positions) / sizeof(positions[0]);
+
+    hbitmap_test_init(data, L3, 0);
+
+    for (i = 0; i < num_positions; i++) {
+        hbitmap_set(data->hb, positions[i], L1);
+    }
+
+    for (i = 0; i < num_positions; i++) {
+        hbitmap_deserialize_zeroes(data->hb, positions[i], L1, true);
+        hbitmap_iter_init(&iter, data->hb, 0);
+        next = hbitmap_iter_next(&iter);
+        if (i == num_positions - 1) {
+            g_assert_cmpint(next, ==, -1);
+        } else {
+            g_assert_cmpint(next, ==, positions[i + 1]);
+        }
+    }
+}
+
 static void hbitmap_test_add(const char *testpath,
                                    void (*test_func)(TestHBitmapData *data, const void *user_data))
 {
@@ -802,6 +932,15 @@ int main(int argc, char **argv)
     hbitmap_test_add("/hbitmap/meta/byte", test_hbitmap_meta_byte);
     hbitmap_test_add("/hbitmap/meta/word", test_hbitmap_meta_word);
     hbitmap_test_add("/hbitmap/meta/sector", test_hbitmap_meta_sector);
+
+    hbitmap_test_add("/hbitmap/serialize/granularity",
+                     test_hbitmap_serialize_granularity);
+    hbitmap_test_add("/hbitmap/serialize/basic",
+                     test_hbitmap_serialize_basic);
+    hbitmap_test_add("/hbitmap/serialize/part",
+                     test_hbitmap_serialize_part);
+    hbitmap_test_add("/hbitmap/serialize/zeroes",
+                     test_hbitmap_serialize_zeroes);
     g_test_run();
 
     return 0;
-- 
2.4.3

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

* Re: [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (12 preceding siblings ...)
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 13/13] tests: Add test code for hbitmap serialization Fam Zheng
@ 2016-01-20 16:13 ` Vladimir Sementsov-Ogievskiy
  2016-01-22 12:07   ` Vladimir Sementsov-Ogievskiy
  2016-01-21 10:41 ` Vladimir Sementsov-Ogievskiy
  2016-01-26  7:26 ` [Qemu-devel] [PATCH v2 14/13] block: More operations for meta dirty bitmap Fam Zheng
  15 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-20 16:13 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

I'll try to rebase my series on this and run tests.

On 20.01.2016 09:11, Fam Zheng wrote:
> v2: Various changes addressing John's and Vladimir's comments:
>
>      [02/13] typedefs: Add BdrvDirtyBitmap
>              Skip HBitmapIter because we'll hide it soon. [John]
>              
>      [03/13] block: Move block dirty bitmap code to separate files
>      [04/13] block: Remove unused typedef of BlockDriverDirtyHandler
>      [05/13] block: Hide HBitmap in block dirty bitmap interface
>              Add assert in bdrv_dirty_bitmap_truncate(). [John]
>              Add John's rev-by.
>
>      [06/13] HBitmap: Introduce "meta" bitmap to track bit changes
>              Caller of hbitmap_create_meta() frees it with hbitmap_free_meta().
>              [John, Vladimir]
>
>      [07/13] tests: Add test code for meta bitmap
>              Add John's rev-by.
>
>      [08/13] block: Support meta dirty bitmap
>              Release the meta dirty bitmap in bdrv_release_dirty_bitmap().
>
>      [09/13] block: Add two dirty bitmap getters
>      [10/13] block: Assert that bdrv_release_dirty_bitmap succeeded
>              Add John's rev-by.
>
>      [11/13] hbitmap: serialization
>              Fix comment for hbitmap_serialization_granularity() and
>              hbitmap_deserialize_part(). [John]
>              Document @finish in hbitmap_deserialize_zeroes more clearly.
>              Fixed granularity in hbitmap_serialization_granularity().
>              [Vladimir]
>              Tweak the assertion in serialization_chunk. [Vladimir]
>              cpu_to_leXXs -> leXX_to_cpus in hbitmap_deserialize_part.
>              [Vladimir]
>              Fix typo in serialization_chunk() comments. [John]
>
>      [12/13] block: BdrvDirtyBitmap serialization interface
>      [13/13] tests: Add test code for hbitmap serialization
>
>
> Two major features are added to block dirty bitmap (and underlying HBitmap) in
> this series: meta bitmap and serialization, together with all other supportive
> patches.
>
> Both operations are common in dirty bitmap migration and persistence: they need
> to find whether and which part of the dirty bitmap in question has changed with
> meta dirty bitmap, and they need to write it to the target with serialization.
>
>
> Fam Zheng (11):
>    backup: Use Bitmap to replace "s->bitmap"
>    typedefs: Add BdrvDirtyBitmap
>    block: Move block dirty bitmap code to separate files
>    block: Remove unused typedef of BlockDriverDirtyHandler
>    block: Hide HBitmap in block dirty bitmap interface
>    HBitmap: Introduce "meta" bitmap to track bit changes
>    tests: Add test code for meta bitmap
>    block: Support meta dirty bitmap
>    block: Add two dirty bitmap getters
>    block: Assert that bdrv_release_dirty_bitmap succeeded
>    tests: Add test code for hbitmap serialization
>
> Vladimir Sementsov-Ogievskiy (2):
>    hbitmap: serialization
>    block: BdrvDirtyBitmap serialization interface
>
>   block.c                      | 339 -----------------------------
>   block/Makefile.objs          |   2 +-
>   block/backup.c               |  25 ++-
>   block/dirty-bitmap.c         | 492 +++++++++++++++++++++++++++++++++++++++++++
>   block/mirror.c               |  14 +-
>   include/block/block.h        |  40 +---
>   include/block/dirty-bitmap.h |  71 +++++++
>   include/qemu/hbitmap.h       |  95 +++++++++
>   include/qemu/typedefs.h      |   2 +
>   tests/test-hbitmap.c         | 255 ++++++++++++++++++++++
>   util/hbitmap.c               | 201 ++++++++++++++++--
>   11 files changed, 1126 insertions(+), 410 deletions(-)
>   create mode 100644 block/dirty-bitmap.c
>   create mode 100644 include/block/dirty-bitmap.h
>


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap Fam Zheng
@ 2016-01-20 16:56   ` Eric Blake
  2016-01-21  3:05     ` Fam Zheng
  2016-01-25 20:37   ` John Snow
  1 sibling, 1 reply; 42+ messages in thread
From: Eric Blake @ 2016-01-20 16:56 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, jsnow, qemu-block

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

On 01/19/2016 11:11 PM, Fam Zheng wrote:
> Following patches to refactor and move block dirty bitmap code could use
> this.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  include/block/block.h   | 3 +--
>  include/qemu/typedefs.h | 1 +
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/include/block/block.h b/include/block/block.h
> index c96923d..483bfd3 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -8,6 +8,7 @@
>  #include "block/accounting.h"
>  #include "qapi/qmp/qobject.h"
>  #include "qapi-types.h"
> +#include "qemu/hbitmap.h"
>  
>  /* block.c */
>  typedef struct BlockDriver BlockDriver;
> @@ -472,8 +473,6 @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
>  void *qemu_try_blockalign0(BlockDriverState *bs, size_t size);
>  bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
>  
> -struct HBitmapIter;

You didn't mention removing this forward declaration in the commit
message, making it look like an accident.

-- 
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] 42+ messages in thread

* Re: [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap
  2016-01-20 16:56   ` Eric Blake
@ 2016-01-21  3:05     ` Fam Zheng
  0 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-21  3:05 UTC (permalink / raw)
  To: Eric Blake
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, qemu-block, Jeff Cody,
	qemu-devel, jsnow

On Wed, 01/20 09:56, Eric Blake wrote:
> On 01/19/2016 11:11 PM, Fam Zheng wrote:
> > Following patches to refactor and move block dirty bitmap code could use
> > this.
> > 
> > Signed-off-by: Fam Zheng <famz@redhat.com>
> > ---
> >  include/block/block.h   | 3 +--
> >  include/qemu/typedefs.h | 1 +
> >  2 files changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/include/block/block.h b/include/block/block.h
> > index c96923d..483bfd3 100644
> > --- a/include/block/block.h
> > +++ b/include/block/block.h
> > @@ -8,6 +8,7 @@
> >  #include "block/accounting.h"
> >  #include "qapi/qmp/qobject.h"
> >  #include "qapi-types.h"
> > +#include "qemu/hbitmap.h"
> >  
> >  /* block.c */
> >  typedef struct BlockDriver BlockDriver;
> > @@ -472,8 +473,6 @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
> >  void *qemu_try_blockalign0(BlockDriverState *bs, size_t size);
> >  bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
> >  
> > -struct HBitmapIter;
> 
> You didn't mention removing this forward declaration in the commit
> message, making it look like an accident.
> 

It was intended, so it's the commit message. But I'll split the "#include" and
"HBitmapIter" hunks into another patch.

Fam

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

* Re: [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (13 preceding siblings ...)
  2016-01-20 16:13 ` [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Vladimir Sementsov-Ogievskiy
@ 2016-01-21 10:41 ` Vladimir Sementsov-Ogievskiy
  2016-01-21 13:03   ` Fam Zheng
  2016-01-26  7:26 ` [Qemu-devel] [PATCH v2 14/13] block: More operations for meta dirty bitmap Fam Zheng
  15 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-21 10:41 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

An idea/question.

What about make some const dirty bitmap finctions really const?

bdrv_dirty_bitmap_name(BdrvDirtyBitmap *bitmap)   -> 
bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
bdrv_dirty_bitmap_size(BdrvDirtyBitmap *bitmap)     -> 
bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)

etc..

I don't know, may be it is not Qemu style or there are some other 
restrictions, but in common case strict definitions are better.. In my 
persistent series I've included a fix for this "[PATCH 01/17] block: fix 
bdrv_dirty_bitmap_granularity()", necessary for my other functions with 
const BdrvDirtyBitmap *bitmap.

I can add such fixes into my series (but these series are better place, 
I think), or, if it is bad for Qemu, I'll remove all such const's from 
my series.


On 20.01.2016 09:11, Fam Zheng wrote:
> v2: Various changes addressing John's and Vladimir's comments:
>
>      [02/13] typedefs: Add BdrvDirtyBitmap
>              Skip HBitmapIter because we'll hide it soon. [John]
>              
>      [03/13] block: Move block dirty bitmap code to separate files
>      [04/13] block: Remove unused typedef of BlockDriverDirtyHandler
>      [05/13] block: Hide HBitmap in block dirty bitmap interface
>              Add assert in bdrv_dirty_bitmap_truncate(). [John]
>              Add John's rev-by.
>
>      [06/13] HBitmap: Introduce "meta" bitmap to track bit changes
>              Caller of hbitmap_create_meta() frees it with hbitmap_free_meta().
>              [John, Vladimir]
>
>      [07/13] tests: Add test code for meta bitmap
>              Add John's rev-by.
>
>      [08/13] block: Support meta dirty bitmap
>              Release the meta dirty bitmap in bdrv_release_dirty_bitmap().
>
>      [09/13] block: Add two dirty bitmap getters
>      [10/13] block: Assert that bdrv_release_dirty_bitmap succeeded
>              Add John's rev-by.
>
>      [11/13] hbitmap: serialization
>              Fix comment for hbitmap_serialization_granularity() and
>              hbitmap_deserialize_part(). [John]
>              Document @finish in hbitmap_deserialize_zeroes more clearly.
>              Fixed granularity in hbitmap_serialization_granularity().
>              [Vladimir]
>              Tweak the assertion in serialization_chunk. [Vladimir]
>              cpu_to_leXXs -> leXX_to_cpus in hbitmap_deserialize_part.
>              [Vladimir]
>              Fix typo in serialization_chunk() comments. [John]
>
>      [12/13] block: BdrvDirtyBitmap serialization interface
>      [13/13] tests: Add test code for hbitmap serialization
>
>
> Two major features are added to block dirty bitmap (and underlying HBitmap) in
> this series: meta bitmap and serialization, together with all other supportive
> patches.
>
> Both operations are common in dirty bitmap migration and persistence: they need
> to find whether and which part of the dirty bitmap in question has changed with
> meta dirty bitmap, and they need to write it to the target with serialization.
>
>
> Fam Zheng (11):
>    backup: Use Bitmap to replace "s->bitmap"
>    typedefs: Add BdrvDirtyBitmap
>    block: Move block dirty bitmap code to separate files
>    block: Remove unused typedef of BlockDriverDirtyHandler
>    block: Hide HBitmap in block dirty bitmap interface
>    HBitmap: Introduce "meta" bitmap to track bit changes
>    tests: Add test code for meta bitmap
>    block: Support meta dirty bitmap
>    block: Add two dirty bitmap getters
>    block: Assert that bdrv_release_dirty_bitmap succeeded
>    tests: Add test code for hbitmap serialization
>
> Vladimir Sementsov-Ogievskiy (2):
>    hbitmap: serialization
>    block: BdrvDirtyBitmap serialization interface
>
>   block.c                      | 339 -----------------------------
>   block/Makefile.objs          |   2 +-
>   block/backup.c               |  25 ++-
>   block/dirty-bitmap.c         | 492 +++++++++++++++++++++++++++++++++++++++++++
>   block/mirror.c               |  14 +-
>   include/block/block.h        |  40 +---
>   include/block/dirty-bitmap.h |  71 +++++++
>   include/qemu/hbitmap.h       |  95 +++++++++
>   include/qemu/typedefs.h      |   2 +
>   tests/test-hbitmap.c         | 255 ++++++++++++++++++++++
>   util/hbitmap.c               | 201 ++++++++++++++++--
>   11 files changed, 1126 insertions(+), 410 deletions(-)
>   create mode 100644 block/dirty-bitmap.c
>   create mode 100644 include/block/dirty-bitmap.h
>


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work
  2016-01-21 10:41 ` Vladimir Sementsov-Ogievskiy
@ 2016-01-21 13:03   ` Fam Zheng
  0 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-21 13:03 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-devel, qemu-block

On Thu, 01/21 13:41, Vladimir Sementsov-Ogievskiy wrote:
> An idea/question.
> 
> What about make some const dirty bitmap finctions really const?
> 
> bdrv_dirty_bitmap_name(BdrvDirtyBitmap *bitmap)   ->
> bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap)
> bdrv_dirty_bitmap_size(BdrvDirtyBitmap *bitmap)     ->
> bdrv_dirty_bitmap_size(const BdrvDirtyBitmap *bitmap)
> 
> etc..

That is fine. I think that is a good practice which is not always adopted.

Fam

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

* Re: [Qemu-devel] [PATCH v2 03/13] block: Move block dirty bitmap code to separate files
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 03/13] block: Move block dirty bitmap code to separate files Fam Zheng
@ 2016-01-22  9:13   ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-22  9:13 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

On 20.01.2016 09:11, Fam Zheng wrote:
> The only change is making bdrv_dirty_bitmap_truncate public. It is used in
> block.c.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Reviewed-by: John Snow <jsnow@redhat.com>
> ---
>   block.c                      | 339 ---------------------------------------
>   block/Makefile.objs          |   2 +-
>   block/dirty-bitmap.c         | 366 +++++++++++++++++++++++++++++++++++++++++++
>   include/block/block.h        |  35 +----
>   include/block/dirty-bitmap.h |  43 +++++
>   5 files changed, 411 insertions(+), 374 deletions(-)
>   create mode 100644 block/dirty-bitmap.c
>   create mode 100644 include/block/dirty-bitmap.h
>
> diff --git a/block.c b/block.c
> index 54c37f9..ab79bfe 100644
> --- a/block.c
> +++ b/block.c
> @@ -55,23 +55,6 @@
>   #include <windows.h>
>   #endif
>   
> -/**
> - * A BdrvDirtyBitmap can be in three possible states:
> - * (1) successor is NULL and disabled is false: full r/w mode
> - * (2) successor is NULL and disabled is true: read only mode ("disabled")
> - * (3) successor is set: frozen mode.
> - *     A frozen bitmap cannot be renamed, deleted, anonymized, cleared, set,
> - *     or enabled. A frozen bitmap can only abdicate() or reclaim().
> - */
> -struct BdrvDirtyBitmap {
> -    HBitmap *bitmap;            /* Dirty sector bitmap implementation */
> -    BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
> -    char *name;                 /* Optional non-empty unique ID */
> -    int64_t size;               /* Size of the bitmap (Number of sectors) */
> -    bool disabled;              /* Bitmap is read-only */
> -    QLIST_ENTRY(BdrvDirtyBitmap) list;
> -};
> -
>   #define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
>   
>   struct BdrvStates bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states);
> @@ -87,7 +70,6 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename,
>                                BlockDriverState *parent,
>                                const BdrvChildRole *child_role, Error **errp);
>   
> -static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
>   /* If non-zero, use only whitelisted block drivers */
>   static int use_bdrv_whitelist;
>   
> @@ -3373,327 +3355,6 @@ void bdrv_lock_medium(BlockDriverState *bs, bool locked)
>       }
>   }
>   
> -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(BdrvDirtyBitmap *bitmap)
> -{
> -    assert(!bdrv_dirty_bitmap_frozen(bitmap));
> -    g_free(bitmap->name);
> -    bitmap->name = NULL;
> -}
> -
> -BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
> -                                          uint32_t granularity,
> -                                          const char *name,
> -                                          Error **errp)
> -{
> -    int64_t bitmap_size;
> -    BdrvDirtyBitmap *bitmap;
> -    uint32_t sector_granularity;
> -
> -    assert((granularity & (granularity - 1)) == 0);
> -
> -    if (name && bdrv_find_dirty_bitmap(bs, name)) {
> -        error_setg(errp, "Bitmap already exists: %s", name);
> -        return NULL;
> -    }
> -    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");
> -        errno = -bitmap_size;
> -        return NULL;
> -    }
> -    bitmap = g_new0(BdrvDirtyBitmap, 1);
> -    bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
> -    bitmap->size = bitmap_size;
> -    bitmap->name = g_strdup(name);
> -    bitmap->disabled = false;
> -    QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
> -    return bitmap;
> -}
> -
> -bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
> -{
> -    return bitmap->successor;
> -}
> -
> -bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
> -{
> -    return !(bitmap->disabled || bitmap->successor);
> -}
> -
> -DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
> -{
> -    if (bdrv_dirty_bitmap_frozen(bitmap)) {
> -        return DIRTY_BITMAP_STATUS_FROZEN;
> -    } else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
> -        return DIRTY_BITMAP_STATUS_DISABLED;
> -    } else {
> -        return DIRTY_BITMAP_STATUS_ACTIVE;
> -    }
> -}
> -
> -/**
> - * 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;
> -    BdrvDirtyBitmap *child;
> -
> -    if (bdrv_dirty_bitmap_frozen(bitmap)) {
> -        error_setg(errp, "Cannot create a successor for a bitmap that is "
> -                   "currently frozen");
> -        return -1;
> -    }
> -    assert(!bitmap->successor);
> -
> -    /* Create an anonymous successor */
> -    granularity = bdrv_dirty_bitmap_granularity(bitmap);
> -    child = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
> -    if (!child) {
> -        return -1;
> -    }
> -
> -    /* Successor will be on or off based on our current state. */
> -    child->disabled = bitmap->disabled;
> -
> -    /* Install the successor and freeze the parent */
> -    bitmap->successor = child;
> -    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");
> -        return NULL;
> -    }
> -
> -    name = bitmap->name;
> -    bitmap->name = NULL;
> -    successor->name = name;
> -    bitmap->successor = NULL;
> -    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");
> -        return NULL;
> -    }
> -
> -    if (!hbitmap_merge(parent->bitmap, successor->bitmap)) {
> -        error_setg(errp, "Merging of parent and successor bitmap failed");
> -        return NULL;
> -    }
> -    bdrv_release_dirty_bitmap(bs, successor);
> -    parent->successor = NULL;
> -
> -    return parent;
> -}
> -
> -/**
> - * Truncates _all_ bitmaps attached to a BDS.
> - */
> -static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
> -{
> -    BdrvDirtyBitmap *bitmap;
> -    uint64_t size = bdrv_nb_sectors(bs);
> -
> -    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> -        assert(!bdrv_dirty_bitmap_frozen(bitmap));
> -        hbitmap_truncate(bitmap->bitmap, size);
> -        bitmap->size = size;
> -    }
> -}
> -
> -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(!bdrv_dirty_bitmap_frozen(bm));
> -            QLIST_REMOVE(bitmap, list);
> -            hbitmap_free(bitmap->bitmap);
> -            g_free(bitmap->name);
> -            g_free(bitmap);
> -            return;
> -        }
> -    }
> -}
> -
> -void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> -{
> -    assert(!bdrv_dirty_bitmap_frozen(bitmap));
> -    bitmap->disabled = true;
> -}
> -
> -void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> -{
> -    assert(!bdrv_dirty_bitmap_frozen(bitmap));
> -    bitmap->disabled = false;
> -}
> -
> -BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
> -{
> -    BdrvDirtyBitmap *bm;
> -    BlockDirtyInfoList *list = NULL;
> -    BlockDirtyInfoList **plist = &list;
> -
> -    QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
> -        BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
> -        BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
> -        info->count = bdrv_get_dirty_count(bm);
> -        info->granularity = bdrv_dirty_bitmap_granularity(bm);
> -        info->has_name = !!bm->name;
> -        info->name = g_strdup(bm->name);
> -        info->status = bdrv_dirty_bitmap_status(bm);
> -        entry->value = info;
> -        *plist = entry;
> -        plist = &entry->next;
> -    }
> -
> -    return list;
> -}
> -
> -int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector)
> -{
> -    if (bitmap) {
> -        return hbitmap_get(bitmap->bitmap, sector);
> -    } else {
> -        return 0;
> -    }
> -}
> -
> -/**
> - * 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.
> - */
> -uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
> -{
> -    BlockDriverInfo bdi;
> -    uint32_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;
> -}
> -
> -uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
> -{
> -    return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
> -}
> -
> -void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
> -{
> -    hbitmap_iter_init(hbi, bitmap->bitmap, 0);
> -}
> -
> -void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> -                           int64_t cur_sector, int nr_sectors)
> -{
> -    assert(bdrv_dirty_bitmap_enabled(bitmap));
> -    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
> -}
> -
> -void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> -                             int64_t cur_sector, int nr_sectors)
> -{
> -    assert(bdrv_dirty_bitmap_enabled(bitmap));
> -    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
> -}
> -
> -void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
> -{
> -    assert(bdrv_dirty_bitmap_enabled(bitmap));
> -    if (!out) {
> -        hbitmap_reset_all(bitmap->bitmap);
> -    } else {
> -        HBitmap *backup = bitmap->bitmap;
> -        bitmap->bitmap = hbitmap_alloc(bitmap->size,
> -                                       hbitmap_granularity(backup));
> -        *out = backup;
> -    }
> -}
> -
> -void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
> -{
> -    HBitmap *tmp = bitmap->bitmap;
> -    assert(bdrv_dirty_bitmap_enabled(bitmap));
> -    bitmap->bitmap = in;
> -    hbitmap_free(tmp);
> -}
> -
> -void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
> -                    int nr_sectors)
> -{
> -    BdrvDirtyBitmap *bitmap;
> -    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> -        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
> -            continue;
> -        }
> -        hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
> -    }
> -}
> -
> -/**
> - * Advance an HBitmapIter to an arbitrary offset.
> - */
> -void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
> -{
> -    assert(hbi->hb);
> -    hbitmap_iter_init(hbi, hbi->hb, offset);
> -}
> -
> -int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
> -{
> -    return hbitmap_count(bitmap->bitmap);
> -}
> -
>   /* Get a reference to bs */
>   void bdrv_ref(BlockDriverState *bs)
>   {
> diff --git a/block/Makefile.objs b/block/Makefile.objs
> index 58ef2ef..cdd8655 100644
> --- a/block/Makefile.objs
> +++ b/block/Makefile.objs
> @@ -20,7 +20,7 @@ block-obj-$(CONFIG_RBD) += rbd.o
>   block-obj-$(CONFIG_GLUSTERFS) += gluster.o
>   block-obj-$(CONFIG_ARCHIPELAGO) += archipelago.o
>   block-obj-$(CONFIG_LIBSSH2) += ssh.o
> -block-obj-y += accounting.o
> +block-obj-y += accounting.o dirty-bitmap.o
>   block-obj-y += write-threshold.o
>   
>   common-obj-y += stream.o
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> new file mode 100644
> index 0000000..7924c38
> --- /dev/null
> +++ b/block/dirty-bitmap.c
> @@ -0,0 +1,366 @@
> +/*
> + * Block Dirty Bitmap
> + *
> + * Copyright (c) 2016 Red Hat. Inc
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +#include "config-host.h"
> +#include "qemu-common.h"
> +#include "trace.h"
> +#include "block/block_int.h"
> +#include "block/blockjob.h"
> +
> +/**
> + * A BdrvDirtyBitmap can be in three possible states:
> + * (1) successor is NULL and disabled is false: full r/w mode
> + * (2) successor is NULL and disabled is true: read only mode ("disabled")
> + * (3) successor is set: frozen mode.
> + *     A frozen bitmap cannot be renamed, deleted, anonymized, cleared, set,
> + *     or enabled. A frozen bitmap can only abdicate() or reclaim().
> + */
> +struct BdrvDirtyBitmap {
> +    HBitmap *bitmap;            /* Dirty sector bitmap implementation */
> +    BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
> +    char *name;                 /* Optional non-empty unique ID */
> +    int64_t size;               /* Size of the bitmap (Number of sectors) */
> +    bool disabled;              /* Bitmap is read-only */
> +    QLIST_ENTRY(BdrvDirtyBitmap) list;
> +};
> +
> +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(BdrvDirtyBitmap *bitmap)
> +{
> +    assert(!bdrv_dirty_bitmap_frozen(bitmap));
> +    g_free(bitmap->name);
> +    bitmap->name = NULL;
> +}
> +
> +BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
> +                                          uint32_t granularity,
> +                                          const char *name,
> +                                          Error **errp)
> +{
> +    int64_t bitmap_size;
> +    BdrvDirtyBitmap *bitmap;
> +    uint32_t sector_granularity;
> +
> +    assert((granularity & (granularity - 1)) == 0);
> +
> +    if (name && bdrv_find_dirty_bitmap(bs, name)) {
> +        error_setg(errp, "Bitmap already exists: %s", name);
> +        return NULL;
> +    }
> +    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");
> +        errno = -bitmap_size;
> +        return NULL;
> +    }
> +    bitmap = g_new0(BdrvDirtyBitmap, 1);
> +    bitmap->bitmap = hbitmap_alloc(bitmap_size, ctz32(sector_granularity));
> +    bitmap->size = bitmap_size;
> +    bitmap->name = g_strdup(name);
> +    bitmap->disabled = false;
> +    QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
> +    return bitmap;
> +}
> +
> +bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
> +{
> +    return bitmap->successor;
> +}
> +
> +bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap)
> +{
> +    return !(bitmap->disabled || bitmap->successor);
> +}
> +
> +DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap)
> +{
> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
> +        return DIRTY_BITMAP_STATUS_FROZEN;
> +    } else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
> +        return DIRTY_BITMAP_STATUS_DISABLED;
> +    } else {
> +        return DIRTY_BITMAP_STATUS_ACTIVE;
> +    }
> +}
> +
> +/**
> + * 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;
> +    BdrvDirtyBitmap *child;
> +
> +    if (bdrv_dirty_bitmap_frozen(bitmap)) {
> +        error_setg(errp, "Cannot create a successor for a bitmap that is "
> +                   "currently frozen");
> +        return -1;
> +    }
> +    assert(!bitmap->successor);
> +
> +    /* Create an anonymous successor */
> +    granularity = bdrv_dirty_bitmap_granularity(bitmap);
> +    child = bdrv_create_dirty_bitmap(bs, granularity, NULL, errp);
> +    if (!child) {
> +        return -1;
> +    }
> +
> +    /* Successor will be on or off based on our current state. */
> +    child->disabled = bitmap->disabled;
> +
> +    /* Install the successor and freeze the parent */
> +    bitmap->successor = child;
> +    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");
> +        return NULL;
> +    }
> +
> +    name = bitmap->name;
> +    bitmap->name = NULL;
> +    successor->name = name;
> +    bitmap->successor = NULL;
> +    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");
> +        return NULL;
> +    }
> +
> +    if (!hbitmap_merge(parent->bitmap, successor->bitmap)) {
> +        error_setg(errp, "Merging of parent and successor bitmap failed");
> +        return NULL;
> +    }
> +    bdrv_release_dirty_bitmap(bs, successor);
> +    parent->successor = NULL;
> +
> +    return parent;
> +}
> +
> +/**
> + * Truncates _all_ bitmaps attached to a BDS.
> + */
> +void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
> +{
> +    BdrvDirtyBitmap *bitmap;
> +    uint64_t size = bdrv_nb_sectors(bs);
> +
> +    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> +        assert(!bdrv_dirty_bitmap_frozen(bitmap));
> +        hbitmap_truncate(bitmap->bitmap, size);
> +        bitmap->size = size;
> +    }
> +}
> +
> +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(!bdrv_dirty_bitmap_frozen(bm));
> +            QLIST_REMOVE(bitmap, list);
> +            hbitmap_free(bitmap->bitmap);
> +            g_free(bitmap->name);
> +            g_free(bitmap);
> +            return;
> +        }
> +    }
> +}
> +
> +void bdrv_disable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    assert(!bdrv_dirty_bitmap_frozen(bitmap));
> +    bitmap->disabled = true;
> +}
> +
> +void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    assert(!bdrv_dirty_bitmap_frozen(bitmap));
> +    bitmap->disabled = false;
> +}
> +
> +BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs)
> +{
> +    BdrvDirtyBitmap *bm;
> +    BlockDirtyInfoList *list = NULL;
> +    BlockDirtyInfoList **plist = &list;
> +
> +    QLIST_FOREACH(bm, &bs->dirty_bitmaps, list) {
> +        BlockDirtyInfo *info = g_new0(BlockDirtyInfo, 1);
> +        BlockDirtyInfoList *entry = g_new0(BlockDirtyInfoList, 1);
> +        info->count = bdrv_get_dirty_count(bm);
> +        info->granularity = bdrv_dirty_bitmap_granularity(bm);
> +        info->has_name = !!bm->name;
> +        info->name = g_strdup(bm->name);
> +        info->status = bdrv_dirty_bitmap_status(bm);
> +        entry->value = info;
> +        *plist = entry;
> +        plist = &entry->next;
> +    }
> +
> +    return list;
> +}
> +
> +int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector)
> +{
> +    if (bitmap) {
> +        return hbitmap_get(bitmap->bitmap, sector);
> +    } else {
> +        return 0;
> +    }
> +}
> +
> +/**
> + * 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.
> + */
> +uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs)
> +{
> +    BlockDriverInfo bdi;
> +    uint32_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;
> +}
> +
> +uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
> +{
> +    return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
> +}
> +
> +void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
> +{
> +    hbitmap_iter_init(hbi, bitmap->bitmap, 0);
> +}
> +
> +void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                           int64_t cur_sector, int nr_sectors)
> +{
> +    assert(bdrv_dirty_bitmap_enabled(bitmap));
> +    hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
> +}
> +
> +void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                             int64_t cur_sector, int nr_sectors)
> +{
> +    assert(bdrv_dirty_bitmap_enabled(bitmap));
> +    hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
> +}
> +
> +void bdrv_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap **out)
> +{
> +    assert(bdrv_dirty_bitmap_enabled(bitmap));
> +    if (!out) {
> +        hbitmap_reset_all(bitmap->bitmap);
> +    } else {
> +        HBitmap *backup = bitmap->bitmap;
> +        bitmap->bitmap = hbitmap_alloc(bitmap->size,
> +                                       hbitmap_granularity(backup));
> +        *out = backup;
> +    }
> +}
> +
> +void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
> +{
> +    HBitmap *tmp = bitmap->bitmap;
> +    assert(bdrv_dirty_bitmap_enabled(bitmap));
> +    bitmap->bitmap = in;
> +    hbitmap_free(tmp);
> +}
> +
> +void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
> +                    int nr_sectors)
> +{
> +    BdrvDirtyBitmap *bitmap;
> +    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> +        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
> +            continue;
> +        }
> +        hbitmap_set(bitmap->bitmap, cur_sector, nr_sectors);
> +    }
> +}
> +
> +/**
> + * Advance an HBitmapIter to an arbitrary offset.
> + */
> +void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
> +{
> +    assert(hbi->hb);
> +    hbitmap_iter_init(hbi, hbi->hb, offset);
> +}
> +
> +int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
> +{
> +    return hbitmap_count(bitmap->bitmap);
> +}
> diff --git a/include/block/block.h b/include/block/block.h
> index 483bfd3..339906b 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -6,6 +6,7 @@
>   #include "qemu/option.h"
>   #include "qemu/coroutine.h"
>   #include "block/accounting.h"
> +#include "block/dirty-bitmap.h"
>   #include "qapi/qmp/qobject.h"
>   #include "qapi-types.h"
>   #include "qemu/hbitmap.h"
> @@ -473,40 +474,6 @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
>   void *qemu_try_blockalign0(BlockDriverState *bs, size_t size);
>   bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
>   
> -BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
> -                                          uint32_t 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(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);
> -uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
> -uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
> -bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
> -bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
> -DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
> -int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
> -void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> -                           int64_t cur_sector, int nr_sectors);
> -void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> -                             int64_t cur_sector, int nr_sectors);
> -void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
> -void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
> -int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
> -
>   void bdrv_enable_copy_on_read(BlockDriverState *bs);
>   void bdrv_disable_copy_on_read(BlockDriverState *bs);
>   
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> new file mode 100644
> index 0000000..02a9337
> --- /dev/null
> +++ b/include/block/dirty-bitmap.h
> @@ -0,0 +1,43 @@
> +#ifndef BLOCK_DIRTY_BITMAP_H
> +#define BLOCK_DIRTY_BITMAP_H
> +
> +#include "qemu-common.h"
> +#include "qemu/hbitmap.h"
> +
> +typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
> +BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
> +                                          uint32_t 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(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);
> +uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
> +uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
> +bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
> +bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
> +DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
> +int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);

over 80 characters line. I think it will be good to add separate patch 
after this to fix it.

> +void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                           int64_t cur_sector, int nr_sectors);
> +void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                             int64_t cur_sector, int nr_sectors);
> +void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
> +void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
> +int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
> +void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
> +
> +#endif


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap Fam Zheng
@ 2016-01-22 11:34   ` Vladimir Sementsov-Ogievskiy
  2016-01-26  4:31     ` Fam Zheng
  2016-01-22 11:58   ` Vladimir Sementsov-Ogievskiy
  2016-01-25 22:16   ` John Snow
  2 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-22 11:34 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

On 20.01.2016 09:11, Fam Zheng wrote:
> The added group of operations enables tracking of the changed bits in
> the dirty bitmap.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>   block/dirty-bitmap.c         | 51 ++++++++++++++++++++++++++++++++++++++++++++
>   include/block/dirty-bitmap.h |  9 ++++++++
>   2 files changed, 60 insertions(+)
>
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index bd7758b..d75dcf7 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -37,6 +37,7 @@
>    */
>   struct BdrvDirtyBitmap {
>       HBitmap *bitmap;            /* Dirty sector bitmap implementation */
> +    HBitmap *meta;              /* Meta dirty bitmap */
>       BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
>       char *name;                 /* Optional non-empty unique ID */
>       int64_t size;               /* Size of the bitmap (Number of sectors) */
> @@ -102,6 +103,56 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>       return bitmap;
>   }
>   
> +/* bdrv_create_meta_dirty_bitmap
> + *
> + * Create a meta dirty bitmap that tracks the changes of bits in @bitmap. I.e.
> + * when a dirty status bit in @bitmap is changed (either from reset to set or
> + * the other way around), its respective meta dirty bitmap bit will be marked
> + * dirty as well.
> + *
> + * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
> + * @granularity: how many bytes of bitmap data does each bit in the meta bitmap
> + * track.
> + */
> +void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                                   int granularity)
> +{
> +    assert(!bitmap->meta);
> +    bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
> +                                       BDRV_SECTOR_SIZE * BITS_PER_BYTE);
> +}

what is granularity here? Is it unused?

Here should be chunk_size parameter, which then will be somehow send to 
hbitmap_create_meta.

> +
> +void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    assert(bitmap->meta);
> +    hbitmap_free_meta(bitmap->bitmap);
> +    bitmap->meta = NULL;
> +}
> +
> +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
> +                               BdrvDirtyBitmap *bitmap, int64_t sector,
> +                               int nb_sectors)
> +{
> +    uint64_t i;
> +    int gran = bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
> +
> +    /* To optimize: we can make hbitmap to internally check the range in a
> +     * coarse level, or at least do it word by word. */
> +    for (i = sector; i < sector + nb_sectors; i += gran) {
> +        if (hbitmap_get(bitmap->meta, i)) {
> +            return true;
> +        }
> +    }
> +    return false;
> +}
> +
> +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
> +                                  BdrvDirtyBitmap *bitmap, int64_t sector,
> +                                  int nb_sectors)
> +{
> +    hbitmap_reset(bitmap->meta, sector, nb_sectors);
> +}
> +
>   bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
>   {
>       return bitmap->successor;
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index 120bac6..d9b281a 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -9,6 +9,9 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>                                             uint32_t granularity,
>                                             const char *name,
>                                             Error **errp);
> +void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                                   int granularity);
> +void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
>   int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>                                          BdrvDirtyBitmap *bitmap,
>                                          Error **errp);
> @@ -35,6 +38,12 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>                              int64_t cur_sector, int nr_sectors);
>   void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>                                int64_t cur_sector, int nr_sectors);
> +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
> +                               BdrvDirtyBitmap *bitmap, int64_t sector,
> +                               int nb_sectors);
> +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
> +                                  BdrvDirtyBitmap *bitmap, int64_t sector,
> +                                  int nb_sectors);
>   BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
>                                            uint64_t first_sector);
>   void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 09/13] block: Add two dirty bitmap getters
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 09/13] block: Add two dirty bitmap getters Fam Zheng
@ 2016-01-22 11:45   ` Vladimir Sementsov-Ogievskiy
  2016-01-26  4:19     ` Fam Zheng
  0 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-22 11:45 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

On 20.01.2016 09:11, Fam Zheng wrote:
> For dirty bitmap users to get the size and the name of a
> BdrvDirtyBitmap.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Reviewed-by: John Snow <jsnow@redhat.com>
> ---
>   block/dirty-bitmap.c         | 10 ++++++++++
>   include/block/dirty-bitmap.h |  2 ++
>   2 files changed, 12 insertions(+)
>
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index d75dcf7..de143f1 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -153,6 +153,16 @@ void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
>       hbitmap_reset(bitmap->meta, sector, nb_sectors);
>   }
>   
> +int64_t bdrv_dirty_bitmap_size(BdrvDirtyBitmap *bitmap)
> +{
> +    return bitmap->size;
> +}
> +
> +const char *bdrv_dirty_bitmap_name(BdrvDirtyBitmap *bitmap)
> +{
> +    return bitmap->name;
> +}

Please, s/BdrvDirtyBitmap */const BdrvDirtyBitmap */

> +
>   bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
>   {
>       return bitmap->successor;
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index d9b281a..8c29c3e 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -32,6 +32,8 @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
>   uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
>   bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
>   bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
> +const char *bdrv_dirty_bitmap_name(BdrvDirtyBitmap *bitmap);
> +int64_t bdrv_dirty_bitmap_size(BdrvDirtyBitmap *bitmap);
>   DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
>   int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
>   void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap Fam Zheng
  2016-01-22 11:34   ` Vladimir Sementsov-Ogievskiy
@ 2016-01-22 11:58   ` Vladimir Sementsov-Ogievskiy
  2016-01-22 12:05     ` Vladimir Sementsov-Ogievskiy
  2016-01-25 22:16   ` John Snow
  2 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-22 11:58 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

On 20.01.2016 09:11, Fam Zheng wrote:
> The added group of operations enables tracking of the changed bits in
> the dirty bitmap.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>   block/dirty-bitmap.c         | 51 ++++++++++++++++++++++++++++++++++++++++++++
>   include/block/dirty-bitmap.h |  9 ++++++++
>   2 files changed, 60 insertions(+)
>
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index bd7758b..d75dcf7 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -37,6 +37,7 @@
>    */
>   struct BdrvDirtyBitmap {
>       HBitmap *bitmap;            /* Dirty sector bitmap implementation */
> +    HBitmap *meta;              /* Meta dirty bitmap */
>       BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
>       char *name;                 /* Optional non-empty unique ID */
>       int64_t size;               /* Size of the bitmap (Number of sectors) */
> @@ -102,6 +103,56 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>       return bitmap;
>   }
>   
> +/* bdrv_create_meta_dirty_bitmap
> + *
> + * Create a meta dirty bitmap that tracks the changes of bits in @bitmap. I.e.
> + * when a dirty status bit in @bitmap is changed (either from reset to set or
> + * the other way around), its respective meta dirty bitmap bit will be marked
> + * dirty as well.
> + *
> + * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
> + * @granularity: how many bytes of bitmap data does each bit in the meta bitmap
> + * track.
> + */
> +void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                                   int granularity)
> +{
> +    assert(!bitmap->meta);
> +    bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
> +                                       BDRV_SECTOR_SIZE * BITS_PER_BYTE);
> +}
> +
> +void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    assert(bitmap->meta);
> +    hbitmap_free_meta(bitmap->bitmap);
> +    bitmap->meta = NULL;
> +}
> +
> +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
> +                               BdrvDirtyBitmap *bitmap, int64_t sector,
> +                               int nb_sectors)
> +{
> +    uint64_t i;
> +    int gran = bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
> +
> +    /* To optimize: we can make hbitmap to internally check the range in a
> +     * coarse level, or at least do it word by word. */
> +    for (i = sector; i < sector + nb_sectors; i += gran) {
> +        if (hbitmap_get(bitmap->meta, i)) {
> +            return true;
> +        }
> +    }
> +    return false;
> +}
> +
> +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
> +                                  BdrvDirtyBitmap *bitmap, int64_t sector,
> +                                  int nb_sectors)
> +{
> +    hbitmap_reset(bitmap->meta, sector, nb_sectors);
> +}
> +
>   bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
>   {
>       return bitmap->successor;
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index 120bac6..d9b281a 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -9,6 +9,9 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>                                             uint32_t granularity,
>                                             const char *name,
>                                             Error **errp);
> +void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                                   int granularity);
> +void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
>   int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>                                          BdrvDirtyBitmap *bitmap,
>                                          Error **errp);
> @@ -35,6 +38,12 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>                              int64_t cur_sector, int nr_sectors);
>   void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>                                int64_t cur_sector, int nr_sectors);
> +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
> +                               BdrvDirtyBitmap *bitmap, int64_t sector,
> +                               int nb_sectors);
> +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
> +                                  BdrvDirtyBitmap *bitmap, int64_t sector,
> +                                  int nb_sectors);
>   BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
>                                            uint64_t first_sector);
>   void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);

In my migration series I need iterators, get granularity, and something 
like hbitmap_count  for meta bitmaps. You can add them here if you want, 
or I can add them in my series.

-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-22 11:58   ` Vladimir Sementsov-Ogievskiy
@ 2016-01-22 12:05     ` Vladimir Sementsov-Ogievskiy
  2016-01-26  6:25       ` Fam Zheng
  0 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-22 12:05 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

On 22.01.2016 14:58, Vladimir Sementsov-Ogievskiy wrote:
> On 20.01.2016 09:11, Fam Zheng wrote:
>> The added group of operations enables tracking of the changed bits in
>> the dirty bitmap.
>>
>> Signed-off-by: Fam Zheng <famz@redhat.com>
>> ---
>>   block/dirty-bitmap.c         | 51 
>> ++++++++++++++++++++++++++++++++++++++++++++
>>   include/block/dirty-bitmap.h |  9 ++++++++
>>   2 files changed, 60 insertions(+)
>>
>> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
>> index bd7758b..d75dcf7 100644
>> --- a/block/dirty-bitmap.c
>> +++ b/block/dirty-bitmap.c
>> @@ -37,6 +37,7 @@
>>    */
>>   struct BdrvDirtyBitmap {
>>       HBitmap *bitmap;            /* Dirty sector bitmap 
>> implementation */
>> +    HBitmap *meta;              /* Meta dirty bitmap */
>>       BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen 
>> status */
>>       char *name;                 /* Optional non-empty unique ID */
>>       int64_t size;               /* Size of the bitmap (Number of 
>> sectors) */
>> @@ -102,6 +103,56 @@ BdrvDirtyBitmap 
>> *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>>       return bitmap;
>>   }
>>   +/* bdrv_create_meta_dirty_bitmap
>> + *
>> + * Create a meta dirty bitmap that tracks the changes of bits in 
>> @bitmap. I.e.
>> + * when a dirty status bit in @bitmap is changed (either from reset 
>> to set or
>> + * the other way around), its respective meta dirty bitmap bit will 
>> be marked
>> + * dirty as well.
>> + *
>> + * @bitmap: the block dirty bitmap for which to create a meta dirty 
>> bitmap.
>> + * @granularity: how many bytes of bitmap data does each bit in the 
>> meta bitmap
>> + * track.
>> + */
>> +void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>> +                                   int granularity)
>> +{
>> +    assert(!bitmap->meta);
>> +    bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
>> +                                       BDRV_SECTOR_SIZE * 
>> BITS_PER_BYTE);
>> +}
>> +
>> +void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
>> +{
>> +    assert(bitmap->meta);
>> +    hbitmap_free_meta(bitmap->bitmap);
>> +    bitmap->meta = NULL;
>> +}
>> +
>> +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
>> +                               BdrvDirtyBitmap *bitmap, int64_t sector,
>> +                               int nb_sectors)
>> +{
>> +    uint64_t i;
>> +    int gran = bdrv_dirty_bitmap_granularity(bitmap) >> 
>> BDRV_SECTOR_BITS;
>> +
>> +    /* To optimize: we can make hbitmap to internally check the 
>> range in a
>> +     * coarse level, or at least do it word by word. */
>> +    for (i = sector; i < sector + nb_sectors; i += gran) {
>> +        if (hbitmap_get(bitmap->meta, i)) {
>> +            return true;
>> +        }
>> +    }
>> +    return false;
>> +}
>> +
>> +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
>> +                                  BdrvDirtyBitmap *bitmap, int64_t 
>> sector,
>> +                                  int nb_sectors)
>> +{
>> +    hbitmap_reset(bitmap->meta, sector, nb_sectors);
>> +}
>> +
>>   bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
>>   {
>>       return bitmap->successor;
>> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
>> index 120bac6..d9b281a 100644
>> --- a/include/block/dirty-bitmap.h
>> +++ b/include/block/dirty-bitmap.h
>> @@ -9,6 +9,9 @@ BdrvDirtyBitmap 
>> *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>>                                             uint32_t granularity,
>>                                             const char *name,
>>                                             Error **errp);
>> +void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>> +                                   int granularity);
>> +void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
>>   int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>>                                          BdrvDirtyBitmap *bitmap,
>>                                          Error **errp);
>> @@ -35,6 +38,12 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>>                              int64_t cur_sector, int nr_sectors);
>>   void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>>                                int64_t cur_sector, int nr_sectors);
>> +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
>> +                               BdrvDirtyBitmap *bitmap, int64_t sector,
>> +                               int nb_sectors);
>> +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
>> +                                  BdrvDirtyBitmap *bitmap, int64_t 
>> sector,
>> +                                  int nb_sectors);
>>   BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
>>                                            uint64_t first_sector);
>>   void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
>
> In my migration series I need iterators, get granularity, and 
> something like hbitmap_count  for meta bitmaps. You can add them here 
> if you want, or I can add them in my series.

Oh, sorry, I can't. I don't know what to do with active_iterators in 
this case, as it relates to bitmap, not to meta.. It is not as easy as 
it seemed. So, this should be resolved in these series.


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work
  2016-01-20 16:13 ` [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Vladimir Sementsov-Ogievskiy
@ 2016-01-22 12:07   ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-22 12:07 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

On 20.01.2016 19:13, Vladimir Sementsov-Ogievskiy wrote:
> I'll try to rebase my series on this and run tests.

Now failed because of iterators for meta bitmaps are unsupported, see 
answers to [PATCH v2 08/13]. Wait for v3.

>
> On 20.01.2016 09:11, Fam Zheng wrote:
>> v2: Various changes addressing John's and Vladimir's comments:
>>
>>      [02/13] typedefs: Add BdrvDirtyBitmap
>>              Skip HBitmapIter because we'll hide it soon. [John]
>>                   [03/13] block: Move block dirty bitmap code to 
>> separate files
>>      [04/13] block: Remove unused typedef of BlockDriverDirtyHandler
>>      [05/13] block: Hide HBitmap in block dirty bitmap interface
>>              Add assert in bdrv_dirty_bitmap_truncate(). [John]
>>              Add John's rev-by.
>>
>>      [06/13] HBitmap: Introduce "meta" bitmap to track bit changes
>>              Caller of hbitmap_create_meta() frees it with 
>> hbitmap_free_meta().
>>              [John, Vladimir]
>>
>>      [07/13] tests: Add test code for meta bitmap
>>              Add John's rev-by.
>>
>>      [08/13] block: Support meta dirty bitmap
>>              Release the meta dirty bitmap in 
>> bdrv_release_dirty_bitmap().
>>
>>      [09/13] block: Add two dirty bitmap getters
>>      [10/13] block: Assert that bdrv_release_dirty_bitmap succeeded
>>              Add John's rev-by.
>>
>>      [11/13] hbitmap: serialization
>>              Fix comment for hbitmap_serialization_granularity() and
>>              hbitmap_deserialize_part(). [John]
>>              Document @finish in hbitmap_deserialize_zeroes more 
>> clearly.
>>              Fixed granularity in hbitmap_serialization_granularity().
>>              [Vladimir]
>>              Tweak the assertion in serialization_chunk. [Vladimir]
>>              cpu_to_leXXs -> leXX_to_cpus in hbitmap_deserialize_part.
>>              [Vladimir]
>>              Fix typo in serialization_chunk() comments. [John]
>>
>>      [12/13] block: BdrvDirtyBitmap serialization interface
>>      [13/13] tests: Add test code for hbitmap serialization
>>
>>
>> Two major features are added to block dirty bitmap (and underlying 
>> HBitmap) in
>> this series: meta bitmap and serialization, together with all other 
>> supportive
>> patches.
>>
>> Both operations are common in dirty bitmap migration and persistence: 
>> they need
>> to find whether and which part of the dirty bitmap in question has 
>> changed with
>> meta dirty bitmap, and they need to write it to the target with 
>> serialization.
>>
>>
>> Fam Zheng (11):
>>    backup: Use Bitmap to replace "s->bitmap"
>>    typedefs: Add BdrvDirtyBitmap
>>    block: Move block dirty bitmap code to separate files
>>    block: Remove unused typedef of BlockDriverDirtyHandler
>>    block: Hide HBitmap in block dirty bitmap interface
>>    HBitmap: Introduce "meta" bitmap to track bit changes
>>    tests: Add test code for meta bitmap
>>    block: Support meta dirty bitmap
>>    block: Add two dirty bitmap getters
>>    block: Assert that bdrv_release_dirty_bitmap succeeded
>>    tests: Add test code for hbitmap serialization
>>
>> Vladimir Sementsov-Ogievskiy (2):
>>    hbitmap: serialization
>>    block: BdrvDirtyBitmap serialization interface
>>
>>   block.c                      | 339 -----------------------------
>>   block/Makefile.objs          |   2 +-
>>   block/backup.c               |  25 ++-
>>   block/dirty-bitmap.c         | 492 
>> +++++++++++++++++++++++++++++++++++++++++++
>>   block/mirror.c               |  14 +-
>>   include/block/block.h        |  40 +---
>>   include/block/dirty-bitmap.h |  71 +++++++
>>   include/qemu/hbitmap.h       |  95 +++++++++
>>   include/qemu/typedefs.h      |   2 +
>>   tests/test-hbitmap.c         | 255 ++++++++++++++++++++++
>>   util/hbitmap.c               | 201 ++++++++++++++++--
>>   11 files changed, 1126 insertions(+), 410 deletions(-)
>>   create mode 100644 block/dirty-bitmap.c
>>   create mode 100644 include/block/dirty-bitmap.h
>>
>
>


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap Fam Zheng
  2016-01-20 16:56   ` Eric Blake
@ 2016-01-25 20:37   ` John Snow
  1 sibling, 0 replies; 42+ messages in thread
From: John Snow @ 2016-01-25 20:37 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, qemu-block



On 01/20/2016 01:11 AM, Fam Zheng wrote:
> Following patches to refactor and move block dirty bitmap code could use
> this.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  include/block/block.h   | 3 +--
>  include/qemu/typedefs.h | 1 +
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/include/block/block.h b/include/block/block.h
> index c96923d..483bfd3 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -8,6 +8,7 @@
>  #include "block/accounting.h"
>  #include "qapi/qmp/qobject.h"
>  #include "qapi-types.h"
> +#include "qemu/hbitmap.h"
>  
>  /* block.c */
>  typedef struct BlockDriver BlockDriver;
> @@ -472,8 +473,6 @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
>  void *qemu_try_blockalign0(BlockDriverState *bs, size_t size);
>  bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
>  
> -struct HBitmapIter;
> -typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
>  BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>                                            uint32_t granularity,
>                                            const char *name,
> diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
> index 78fe6e8..0cf9d74 100644
> --- a/include/qemu/typedefs.h
> +++ b/include/qemu/typedefs.h
> @@ -10,6 +10,7 @@ typedef struct AddressSpace AddressSpace;
>  typedef struct AioContext AioContext;
>  typedef struct AllwinnerAHCIState AllwinnerAHCIState;
>  typedef struct AudioState AudioState;
> +typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
>  typedef struct BlockBackend BlockBackend;
>  typedef struct BlockBackendRootState BlockBackendRootState;
>  typedef struct BlockDriverState BlockDriverState;
> 

Reviewed-by: John Snow <jsnow@redhat.com>

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

* Re: [Qemu-devel] [PATCH v2 06/13] HBitmap: Introduce "meta" bitmap to track bit changes
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 06/13] HBitmap: Introduce "meta" bitmap to track bit changes Fam Zheng
@ 2016-01-25 22:02   ` John Snow
  0 siblings, 0 replies; 42+ messages in thread
From: John Snow @ 2016-01-25 22:02 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, qemu-block



On 01/20/2016 01:11 AM, Fam Zheng wrote:
> Upon each bit toggle, the corresponding bit in the meta bitmap will be
> set.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>

Reviewed-by: John Snow <jsnow@redhat.com>

> ---
>  include/qemu/hbitmap.h | 17 +++++++++++++
>  util/hbitmap.c         | 66 ++++++++++++++++++++++++++++++++++++++------------
>  2 files changed, 68 insertions(+), 15 deletions(-)
> 
> diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
> index bb94a00..595ad65 100644
> --- a/include/qemu/hbitmap.h
> +++ b/include/qemu/hbitmap.h
> @@ -181,6 +181,23 @@ void hbitmap_iter_init(HBitmapIter *hbi, const HBitmap *hb, uint64_t first);
>   */
>  unsigned long hbitmap_iter_skip_words(HBitmapIter *hbi);
>  
> +/* hbitmap_create_meta:
> + * Create a "meta" hbitmap to track dirtiness of the bits in this HBitmap.
> + * The caller owns the created bitmap and must call hbitmap_free_meta(hb) to
> + * free it.
> + *
> + * @hb: The HBitmap to operate on.
> + * @chunk_size: How many bits in @hb does one bit in the meta track.
> + */
> +HBitmap *hbitmap_create_meta(HBitmap *hb, int chunk_size);
> +
> +/* hbitmap_free_meta:
> + * Free the meta bitmap of @hb.
> + *
> + * @hb: The HBitmap whose meta bitmap should be freed.
> + */
> +void hbitmap_free_meta(HBitmap *hb);
> +
>  /**
>   * hbitmap_iter_next:
>   * @hbi: HBitmapIter to operate on.
> diff --git a/util/hbitmap.c b/util/hbitmap.c
> index 50b888f..79f6236 100644
> --- a/util/hbitmap.c
> +++ b/util/hbitmap.c
> @@ -81,6 +81,9 @@ struct HBitmap {
>       */
>      int granularity;
>  
> +    /* A meta dirty bitmap to track the dirtiness of bits in this HBitmap. */
> +    HBitmap *meta;
> +
>      /* A number of progressively less coarse bitmaps (i.e. level 0 is the
>       * coarsest).  Each bit in level N represents a word in level N+1 that
>       * has a set bit, except the last level where each bit represents the
> @@ -212,25 +215,27 @@ static uint64_t hb_count_between(HBitmap *hb, uint64_t start, uint64_t last)
>  }
>  
>  /* Setting starts at the last layer and propagates up if an element
> - * changes from zero to non-zero.
> + * changes.
>   */
>  static inline bool hb_set_elem(unsigned long *elem, uint64_t start, uint64_t last)
>  {
>      unsigned long mask;
> -    bool changed;
> +    unsigned long old;
>  
>      assert((last >> BITS_PER_LEVEL) == (start >> BITS_PER_LEVEL));
>      assert(start <= last);
>  
>      mask = 2UL << (last & (BITS_PER_LONG - 1));
>      mask -= 1UL << (start & (BITS_PER_LONG - 1));
> -    changed = (*elem == 0);
> +    old = *elem;
>      *elem |= mask;
> -    return changed;
> +    return old != *elem;
>  }
>  
> -/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)... */
> -static void hb_set_between(HBitmap *hb, int level, uint64_t start, uint64_t last)
> +/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)...
> + * Returns true if at least one bit is changed. */
> +static bool hb_set_between(HBitmap *hb, int level, uint64_t start,
> +                           uint64_t last)
>  {
>      size_t pos = start >> BITS_PER_LEVEL;
>      size_t lastpos = last >> BITS_PER_LEVEL;
> @@ -259,22 +264,27 @@ static void hb_set_between(HBitmap *hb, int level, uint64_t start, uint64_t last
>      if (level > 0 && changed) {
>          hb_set_between(hb, level - 1, pos, lastpos);
>      }
> +    return changed;
>  }
>  
>  void hbitmap_set(HBitmap *hb, uint64_t start, uint64_t count)
>  {
>      /* Compute range in the last layer.  */
> +    uint64_t first, n;
>      uint64_t last = start + count - 1;
>  
>      trace_hbitmap_set(hb, start, count,
>                        start >> hb->granularity, last >> hb->granularity);
>  
> -    start >>= hb->granularity;
> +    first = start >> hb->granularity;
>      last >>= hb->granularity;
> -    count = last - start + 1;
> +    n = last - first + 1;
>  
> -    hb->count += count - hb_count_between(hb, start, last);
> -    hb_set_between(hb, HBITMAP_LEVELS - 1, start, last);
> +    hb->count += n - hb_count_between(hb, first, last);
> +    if (hb_set_between(hb, HBITMAP_LEVELS - 1, first, last) &&
> +        hb->meta) {
> +        hbitmap_set(hb->meta, start, count);
> +    }
>  }
>  
>  /* Resetting works the other way round: propagate up if the new
> @@ -295,8 +305,10 @@ static inline bool hb_reset_elem(unsigned long *elem, uint64_t start, uint64_t l
>      return blanked;
>  }
>  
> -/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)... */
> -static void hb_reset_between(HBitmap *hb, int level, uint64_t start, uint64_t last)
> +/* The recursive workhorse (the depth is limited to HBITMAP_LEVELS)...
> + * Returns true if at least one bit is changed. */
> +static bool hb_reset_between(HBitmap *hb, int level, uint64_t start,
> +                             uint64_t last)
>  {
>      size_t pos = start >> BITS_PER_LEVEL;
>      size_t lastpos = last >> BITS_PER_LEVEL;
> @@ -339,21 +351,28 @@ static void hb_reset_between(HBitmap *hb, int level, uint64_t start, uint64_t la
>      if (level > 0 && changed) {
>          hb_reset_between(hb, level - 1, pos, lastpos);
>      }
> +
> +    return changed;
> +
>  }
>  
>  void hbitmap_reset(HBitmap *hb, uint64_t start, uint64_t count)
>  {
>      /* Compute range in the last layer.  */
> +    uint64_t first;
>      uint64_t last = start + count - 1;
>  
>      trace_hbitmap_reset(hb, start, count,
>                          start >> hb->granularity, last >> hb->granularity);
>  
> -    start >>= hb->granularity;
> +    first = start >> hb->granularity;
>      last >>= hb->granularity;
>  
> -    hb->count -= hb_count_between(hb, start, last);
> -    hb_reset_between(hb, HBITMAP_LEVELS - 1, start, last);
> +    hb->count -= hb_count_between(hb, first, last);
> +    if (hb_reset_between(hb, HBITMAP_LEVELS - 1, first, last) &&
> +        hb->meta) {
> +        hbitmap_set(hb->meta, start, count);
> +    }
>  }
>  
>  void hbitmap_reset_all(HBitmap *hb)
> @@ -381,6 +400,7 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
>  void hbitmap_free(HBitmap *hb)
>  {
>      unsigned i;
> +    assert(!hb->meta);
>      for (i = HBITMAP_LEVELS; i-- > 0; ) {
>          g_free(hb->levels[i]);
>      }
> @@ -493,3 +513,19 @@ bool hbitmap_merge(HBitmap *a, const HBitmap *b)
>  
>      return true;
>  }
> +
> +HBitmap *hbitmap_create_meta(HBitmap *hb, int chunk_size)
> +{
> +    assert(!(chunk_size & (chunk_size - 1)));
> +    assert(!hb->meta);
> +    hb->meta = hbitmap_alloc(hb->size << hb->granularity,
> +                             hb->granularity + ctz32(chunk_size));
> +    return hb->meta;
> +}
> +
> +void hbitmap_free_meta(HBitmap *hb)
> +{
> +    assert(hb->meta);
> +    hbitmap_free(hb->meta);
> +    hb->meta = NULL;
> +}
> 

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

* Re: [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap Fam Zheng
  2016-01-22 11:34   ` Vladimir Sementsov-Ogievskiy
  2016-01-22 11:58   ` Vladimir Sementsov-Ogievskiy
@ 2016-01-25 22:16   ` John Snow
  2 siblings, 0 replies; 42+ messages in thread
From: John Snow @ 2016-01-25 22:16 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, qemu-block



On 01/20/2016 01:11 AM, Fam Zheng wrote:
> The added group of operations enables tracking of the changed bits in
> the dirty bitmap.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>

Reviewed-by: John Snow <jsnow@redhat.com>

> ---
>  block/dirty-bitmap.c         | 51 ++++++++++++++++++++++++++++++++++++++++++++
>  include/block/dirty-bitmap.h |  9 ++++++++
>  2 files changed, 60 insertions(+)
> 
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index bd7758b..d75dcf7 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -37,6 +37,7 @@
>   */
>  struct BdrvDirtyBitmap {
>      HBitmap *bitmap;            /* Dirty sector bitmap implementation */
> +    HBitmap *meta;              /* Meta dirty bitmap */
>      BdrvDirtyBitmap *successor; /* Anonymous child; implies frozen status */
>      char *name;                 /* Optional non-empty unique ID */
>      int64_t size;               /* Size of the bitmap (Number of sectors) */
> @@ -102,6 +103,56 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>      return bitmap;
>  }
>  
> +/* bdrv_create_meta_dirty_bitmap
> + *
> + * Create a meta dirty bitmap that tracks the changes of bits in @bitmap. I.e.
> + * when a dirty status bit in @bitmap is changed (either from reset to set or
> + * the other way around), its respective meta dirty bitmap bit will be marked
> + * dirty as well.
> + *
> + * @bitmap: the block dirty bitmap for which to create a meta dirty bitmap.
> + * @granularity: how many bytes of bitmap data does each bit in the meta bitmap
> + * track.
> + */
> +void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                                   int granularity)
> +{
> +    assert(!bitmap->meta);
> +    bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
> +                                       BDRV_SECTOR_SIZE * BITS_PER_BYTE);
> +}
> +
> +void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap)
> +{
> +    assert(bitmap->meta);
> +    hbitmap_free_meta(bitmap->bitmap);
> +    bitmap->meta = NULL;
> +}
> +
> +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
> +                               BdrvDirtyBitmap *bitmap, int64_t sector,
> +                               int nb_sectors)
> +{
> +    uint64_t i;
> +    int gran = bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
> +
> +    /* To optimize: we can make hbitmap to internally check the range in a
> +     * coarse level, or at least do it word by word. */
> +    for (i = sector; i < sector + nb_sectors; i += gran) {
> +        if (hbitmap_get(bitmap->meta, i)) {
> +            return true;
> +        }
> +    }
> +    return false;
> +}
> +
> +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
> +                                  BdrvDirtyBitmap *bitmap, int64_t sector,
> +                                  int nb_sectors)
> +{
> +    hbitmap_reset(bitmap->meta, sector, nb_sectors);
> +}
> +
>  bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
>  {
>      return bitmap->successor;
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index 120bac6..d9b281a 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -9,6 +9,9 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs,
>                                            uint32_t granularity,
>                                            const char *name,
>                                            Error **errp);
> +void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> +                                   int granularity);
> +void bdrv_release_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap);
>  int bdrv_dirty_bitmap_create_successor(BlockDriverState *bs,
>                                         BdrvDirtyBitmap *bitmap,
>                                         Error **errp);
> @@ -35,6 +38,12 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>                             int64_t cur_sector, int nr_sectors);
>  void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>                               int64_t cur_sector, int nr_sectors);
> +int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
> +                               BdrvDirtyBitmap *bitmap, int64_t sector,
> +                               int nb_sectors);
> +void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
> +                                  BdrvDirtyBitmap *bitmap, int64_t sector,
> +                                  int nb_sectors);
>  BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
>                                           uint64_t first_sector);
>  void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
> 

-- 
—js

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

* Re: [Qemu-devel] [PATCH v2 09/13] block: Add two dirty bitmap getters
  2016-01-22 11:45   ` Vladimir Sementsov-Ogievskiy
@ 2016-01-26  4:19     ` Fam Zheng
  0 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-26  4:19 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-devel, qemu-block

On Fri, 01/22 14:45, Vladimir Sementsov-Ogievskiy wrote:
> On 20.01.2016 09:11, Fam Zheng wrote:
> >For dirty bitmap users to get the size and the name of a
> >BdrvDirtyBitmap.
> >
> >Signed-off-by: Fam Zheng <famz@redhat.com>
> >Reviewed-by: John Snow <jsnow@redhat.com>
> >---
> >  block/dirty-bitmap.c         | 10 ++++++++++
> >  include/block/dirty-bitmap.h |  2 ++
> >  2 files changed, 12 insertions(+)
> >
> >diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> >index d75dcf7..de143f1 100644
> >--- a/block/dirty-bitmap.c
> >+++ b/block/dirty-bitmap.c
> >@@ -153,6 +153,16 @@ void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
> >      hbitmap_reset(bitmap->meta, sector, nb_sectors);
> >  }
> >+int64_t bdrv_dirty_bitmap_size(BdrvDirtyBitmap *bitmap)
> >+{
> >+    return bitmap->size;
> >+}
> >+
> >+const char *bdrv_dirty_bitmap_name(BdrvDirtyBitmap *bitmap)
> >+{
> >+    return bitmap->name;
> >+}
> 
> Please, s/BdrvDirtyBitmap */const BdrvDirtyBitmap */

Okay, will add.

Fam

> 
> >+
> >  bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap)
> >  {
> >      return bitmap->successor;
> >diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> >index d9b281a..8c29c3e 100644
> >--- a/include/block/dirty-bitmap.h
> >+++ b/include/block/dirty-bitmap.h
> >@@ -32,6 +32,8 @@ uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
> >  uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
> >  bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
> >  bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
> >+const char *bdrv_dirty_bitmap_name(BdrvDirtyBitmap *bitmap);
> >+int64_t bdrv_dirty_bitmap_size(BdrvDirtyBitmap *bitmap);
> >  DirtyBitmapStatus bdrv_dirty_bitmap_status(BdrvDirtyBitmap *bitmap);
> >  int bdrv_get_dirty(BlockDriverState *bs, BdrvDirtyBitmap *bitmap, int64_t sector);
> >  void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> 
> 
> -- 
> Best regards,
> Vladimir
> * now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.
> 

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

* Re: [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-22 11:34   ` Vladimir Sementsov-Ogievskiy
@ 2016-01-26  4:31     ` Fam Zheng
  0 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-26  4:31 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-devel, qemu-block

On Fri, 01/22 14:34, Vladimir Sementsov-Ogievskiy wrote:
> >+void bdrv_create_meta_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> >+                                   int granularity)
> >+{
> >+    assert(!bitmap->meta);
> >+    bitmap->meta = hbitmap_create_meta(bitmap->bitmap,
> >+                                       BDRV_SECTOR_SIZE * BITS_PER_BYTE);
> >+}
> 
> what is granularity here? Is it unused?
> 
> Here should be chunk_size parameter, which then will be somehow send
> to hbitmap_create_meta.

Right, it should replace BDRV_SECTOR_SIZE.

Fam

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

* Re: [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-22 12:05     ` Vladimir Sementsov-Ogievskiy
@ 2016-01-26  6:25       ` Fam Zheng
  2016-01-26  7:49         ` Vladimir Sementsov-Ogievskiy
  0 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-26  6:25 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-devel, qemu-block

On Fri, 01/22 15:05, Vladimir Sementsov-Ogievskiy wrote:
> >In my migration series I need iterators, get granularity, and
> >something like hbitmap_count  for meta bitmaps. You can add them
> >here if you want, or I can add them in my series.

Okay, I can add that.

I have one more question on the interface: what dirty bitmaps are going to be
migrated? At this moment there are dirty bitmaps created by block jobs
(drive-mirror), and in-memory dirty bitmaps created for incremental backup;
later there will be persistent dirty bitmaps owned by block drivers (extended
version of qcow2, and in QBM driver I'm working on). Which of them are subject
of migration in your series?

I'm asking because I want to know whether we need to implement multiple meta
bitmaps on one block dirty bitmap.

Fam

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

* [Qemu-devel] [PATCH v2 14/13] block: More operations for meta dirty bitmap
  2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
                   ` (14 preceding siblings ...)
  2016-01-21 10:41 ` Vladimir Sementsov-Ogievskiy
@ 2016-01-26  7:26 ` Fam Zheng
  2016-01-27 14:57   ` Vladimir Sementsov-Ogievskiy
  15 siblings, 1 reply; 42+ messages in thread
From: Fam Zheng @ 2016-01-26  7:26 UTC (permalink / raw)
  To: qemu-devel; +Cc: Vladimir Sementsov-Ogievskiy, qemu-block

Callers can create an iterator of meta bitmap with
bdrv_dirty_meta_iter_new(), then use the bdrv_dirty_iter_* operations on
it. Meta iterators are also counted by bitmap->active_iterators.

Also add a couple of functions to retrieve granularity and count.

Signed-off-by: Fam Zheng <famz@redhat.com>

---

Vladimir, are these interfaces enough for your migration series? If it
is more convenient to you, you can adjust and take it into your series.
---
 block/dirty-bitmap.c         | 19 +++++++++++++++++++
 include/block/dirty-bitmap.h |  3 +++
 2 files changed, 22 insertions(+)

diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
index bf84b17..1aa7f76 100644
--- a/block/dirty-bitmap.c
+++ b/block/dirty-bitmap.c
@@ -369,6 +369,11 @@ uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
     return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
 }
 
+uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap)
+{
+    return hbitmap_granularity(bitmap->meta);
+}
+
 BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
                                          uint64_t first_sector)
 {
@@ -379,6 +384,15 @@ BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
     return iter;
 }
 
+BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap)
+{
+    BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
+    hbitmap_iter_init(&iter->hbi, bitmap->meta, 0);
+    iter->bitmap = bitmap;
+    bitmap->active_iterators++;
+    return iter;
+}
+
 void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
 {
     if (!iter) {
@@ -490,3 +504,8 @@ int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
 {
     return hbitmap_count(bitmap->bitmap);
 }
+
+int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
+{
+    return hbitmap_count(bitmap->meta);
+}
diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
index 76256fb..d14d923 100644
--- a/include/block/dirty-bitmap.h
+++ b/include/block/dirty-bitmap.h
@@ -30,6 +30,7 @@ void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
 BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
 uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
 uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
+uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
 bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
 const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
@@ -46,12 +47,14 @@ int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
 void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
                                   BdrvDirtyBitmap *bitmap, int64_t sector,
                                   int nb_sectors);
+BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
 BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
                                          uint64_t first_sector);
 void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
 int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
 void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
 int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
+int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
 void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
 
 uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
-- 
2.4.3

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

* Re: [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-26  6:25       ` Fam Zheng
@ 2016-01-26  7:49         ` Vladimir Sementsov-Ogievskiy
  2016-01-26  8:23           ` Fam Zheng
  0 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-26  7:49 UTC (permalink / raw)
  To: Fam Zheng; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-devel, qemu-block

On 26.01.2016 09:25, Fam Zheng wrote:
> On Fri, 01/22 15:05, Vladimir Sementsov-Ogievskiy wrote:
>>> In my migration series I need iterators, get granularity, and
>>> something like hbitmap_count  for meta bitmaps. You can add them
>>> here if you want, or I can add them in my series.
> Okay, I can add that.
>
> I have one more question on the interface: what dirty bitmaps are going to be
> migrated? At this moment there are dirty bitmaps created by block jobs
> (drive-mirror), and in-memory dirty bitmaps created for incremental backup;
> later there will be persistent dirty bitmaps owned by block drivers (extended
> version of qcow2, and in QBM driver I'm working on). Which of them are subject
> of migration in your series?
>
> I'm asking because I want to know whether we need to implement multiple meta
> bitmaps on one block dirty bitmap.
>
> Fam
Only named bitmaps are migrated. For now, only qmp-created bitmaps are 
named. So, it can be in-memory dirty bitmaps or, in future, persistent 
dirty bitmaps.

Why multiple meta bitmaps? What is your plan about meta, should it be 
used for something other than migration? There was ideas about async 
loading persistent metabitmaps - maybe here? We can disallow processes 
using meta bitmaps to be simultaneous.

-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap
  2016-01-26  7:49         ` Vladimir Sementsov-Ogievskiy
@ 2016-01-26  8:23           ` Fam Zheng
  0 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-01-26  8:23 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-devel, qemu-block

On Tue, 01/26 10:49, Vladimir Sementsov-Ogievskiy wrote:
> On 26.01.2016 09:25, Fam Zheng wrote:
> >On Fri, 01/22 15:05, Vladimir Sementsov-Ogievskiy wrote:
> >>>In my migration series I need iterators, get granularity, and
> >>>something like hbitmap_count  for meta bitmaps. You can add them
> >>>here if you want, or I can add them in my series.
> >Okay, I can add that.
> >
> >I have one more question on the interface: what dirty bitmaps are going to be
> >migrated? At this moment there are dirty bitmaps created by block jobs
> >(drive-mirror), and in-memory dirty bitmaps created for incremental backup;
> >later there will be persistent dirty bitmaps owned by block drivers (extended
> >version of qcow2, and in QBM driver I'm working on). Which of them are subject
> >of migration in your series?
> >
> >I'm asking because I want to know whether we need to implement multiple meta
> >bitmaps on one block dirty bitmap.
> >
> >Fam
> Only named bitmaps are migrated. For now, only qmp-created bitmaps
> are named. So, it can be in-memory dirty bitmaps or, in future,
> persistent dirty bitmaps.
> 
> Why multiple meta bitmaps?

The complication is from combining persistence and migration of a dirty bitmap.

To begin with, persistence drivers (qcow2 or QBM) would need meta dirty bitmaps
to avoid writing unchanged dirty bit ranges to disk, just like in migration.
This means if the persisted named dirty bitmap is being migrated, both the
block driver and migration code will then need their own meta dirty bitmaps,
that is where the question rose.

One step back, we haven't sorted out "migrating persistent dirty bitmap" at all
(see below). So it's probably okay to disallow that as the first step.

P.S. For discussion, I think we ultimately want users to be able to continue
their incremental backup even across the migration point.  If they're using
shared storage, I think it is possible even without dirty bitmap migration, by
flushing the dirty bitmap at src side then loading it at dest side. Otherwise
it is trickier as we will have to migrate the persisted dirty bitmap - the dest
side must use a capable format, and we need to check this capability when
migration starts.   By that time, the meta dirty bitmap interface can be
extended to allow at least two meta bitmaps on the same dirty bitmap.

Fam

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

* Re: [Qemu-devel] [PATCH v2 05/13] block: Hide HBitmap in block dirty bitmap interface
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 05/13] block: Hide HBitmap in block dirty bitmap interface Fam Zheng
@ 2016-01-26 16:02   ` Vladimir Sementsov-Ogievskiy
  2016-02-27  8:30     ` Fam Zheng
  0 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-26 16:02 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-block

On 20.01.2016 09:11, Fam Zheng wrote:
> HBitmap is an implementation detail of block dirty bitmap that should be hidden
> from users. Introduce a BdrvDirtyBitmapIter to encapsulate the underlying
> HBitmapIter.
>
> A small difference in the interface is, before, an HBitmapIter is initialized
> in place, now the new BdrvDirtyBitmapIter must be dynamically allocated because
> the structure definition is in block.c.
>
> Two current users are converted too.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> Reviewed-by: John Snow <jsnow@redhat.com>
> ---
>   block/backup.c               | 14 ++++++++------
>   block/dirty-bitmap.c         | 37 ++++++++++++++++++++++++++++++++-----
>   block/mirror.c               | 14 ++++++++------
>   include/block/dirty-bitmap.h |  7 +++++--
>   include/qemu/typedefs.h      |  1 +
>   5 files changed, 54 insertions(+), 19 deletions(-)
>
> diff --git a/block/backup.c b/block/backup.c
> index 56ddec0..2388039 100644
> --- a/block/backup.c
> +++ b/block/backup.c
> @@ -326,14 +326,14 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
>       int64_t end;
>       int64_t last_cluster = -1;
>       BlockDriverState *bs = job->common.bs;
> -    HBitmapIter hbi;
> +    BdrvDirtyBitmapIter *dbi;
>   
>       granularity = bdrv_dirty_bitmap_granularity(job->sync_bitmap);
>       clusters_per_iter = MAX((granularity / BACKUP_CLUSTER_SIZE), 1);
> -    bdrv_dirty_iter_init(job->sync_bitmap, &hbi);
> +    dbi = bdrv_dirty_iter_new(job->sync_bitmap, 0);
>   
>       /* Find the next dirty sector(s) */
> -    while ((sector = hbitmap_iter_next(&hbi)) != -1) {
> +    while ((sector = bdrv_dirty_iter_next(dbi)) != -1) {
>           cluster = sector / BACKUP_SECTORS_PER_CLUSTER;
>   
>           /* Fake progress updates for any clusters we skipped */
> @@ -345,7 +345,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
>           for (end = cluster + clusters_per_iter; cluster < end; cluster++) {
>               do {
>                   if (yield_and_check(job)) {
> -                    return ret;
> +                    goto out;
>                   }
>                   ret = backup_do_cow(bs, cluster * BACKUP_SECTORS_PER_CLUSTER,
>                                       BACKUP_SECTORS_PER_CLUSTER, &error_is_read,
> @@ -353,7 +353,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
>                   if ((ret < 0) &&
>                       backup_error_action(job, error_is_read, -ret) ==
>                       BLOCK_ERROR_ACTION_REPORT) {
> -                    return ret;
> +                    goto out;
>                   }
>               } while (ret < 0);
>           }
> @@ -361,7 +361,7 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
>           /* If the bitmap granularity is smaller than the backup granularity,
>            * we need to advance the iterator pointer to the next cluster. */
>           if (granularity < BACKUP_CLUSTER_SIZE) {
> -            bdrv_set_dirty_iter(&hbi, cluster * BACKUP_SECTORS_PER_CLUSTER);
> +            bdrv_set_dirty_iter(dbi, cluster * BACKUP_SECTORS_PER_CLUSTER);
>           }
>   
>           last_cluster = cluster - 1;
> @@ -373,6 +373,8 @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
>           job->common.offset += ((end - last_cluster - 1) * BACKUP_CLUSTER_SIZE);
>       }
>   
> +out:
> +    bdrv_dirty_iter_free(dbi);
>       return ret;
>   }
>   
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index 7924c38..bd7758b 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -41,9 +41,15 @@ struct BdrvDirtyBitmap {
>       char *name;                 /* Optional non-empty unique ID */
>       int64_t size;               /* Size of the bitmap (Number of sectors) */
>       bool disabled;              /* Bitmap is read-only */
> +    int active_iterators;       /* How many iterators are active */
>       QLIST_ENTRY(BdrvDirtyBitmap) list;
>   };
>   
> +struct BdrvDirtyBitmapIter {
> +    HBitmapIter hbi;
> +    BdrvDirtyBitmap *bitmap;
> +};
> +
>   BdrvDirtyBitmap *bdrv_find_dirty_bitmap(BlockDriverState *bs, const char *name)
>   {
>       BdrvDirtyBitmap *bm;
> @@ -211,6 +217,7 @@ void bdrv_dirty_bitmap_truncate(BlockDriverState *bs)
>   
>       QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
>           assert(!bdrv_dirty_bitmap_frozen(bitmap));
> +        assert(!bitmap->active_iterators);
>           hbitmap_truncate(bitmap->bitmap, size);
>           bitmap->size = size;
>       }
> @@ -221,6 +228,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(!bitmap->active_iterators);
>               assert(!bdrv_dirty_bitmap_frozen(bm));
>               QLIST_REMOVE(bitmap, list);
>               hbitmap_free(bitmap->bitmap);
> @@ -299,9 +307,29 @@ uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
>       return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
>   }
>   
> -void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, HBitmapIter *hbi)
> +BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
> +                                         uint64_t first_sector)
>   {
> -    hbitmap_iter_init(hbi, bitmap->bitmap, 0);
> +    BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
> +    hbitmap_iter_init(&iter->hbi, bitmap->bitmap, first_sector);
> +    iter->bitmap = bitmap;
> +    bitmap->active_iterators++;
> +    return iter;
> +}
> +
> +void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
> +{
> +    if (!iter) {
> +        return;
> +    }
> +    assert(iter->bitmap->active_iterators > 0);
> +    iter->bitmap->active_iterators--;
> +    g_free(iter);
> +}
> +
> +int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter)
> +{
> +    return hbitmap_iter_next(&iter->hbi);
>   }
>   
>   void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
> @@ -354,10 +382,9 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
>   /**
>    * Advance an HBitmapIter to an arbitrary offset.

fix comment.

>    */
> -void bdrv_set_dirty_iter(HBitmapIter *hbi, int64_t offset)
> +void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *iter, int64_t sector_num)
>   {
> -    assert(hbi->hb);
> -    hbitmap_iter_init(hbi, hbi->hb, offset);
> +    hbitmap_iter_init(&iter->hbi, iter->bitmap->bitmap, sector_num);

why? The old way works for meta iters. The new code - doesn't. I suppose

assert(iter->hbi.hb);
hbitmap_iter_init(&iter->hbi, iter->hbi.hb, sector_num);

>   }
>   
>   int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
> diff --git a/block/mirror.c b/block/mirror.c
> index f201f2b..70ca844 100644
> --- a/block/mirror.c
> +++ b/block/mirror.c
> @@ -52,7 +52,7 @@ typedef struct MirrorBlockJob {
>       int64_t bdev_length;
>       unsigned long *cow_bitmap;
>       BdrvDirtyBitmap *dirty_bitmap;
> -    HBitmapIter hbi;
> +    BdrvDirtyBitmapIter *dbi;
>       uint8_t *buf;
>       QSIMPLEQ_HEAD(, MirrorBuffer) buf_free;
>       int buf_free_count;
> @@ -170,10 +170,11 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
>   
>       max_iov = MIN(source->bl.max_iov, s->target->bl.max_iov);
>   
> -    s->sector_num = hbitmap_iter_next(&s->hbi);
> +    s->sector_num = bdrv_dirty_iter_next(s->dbi);
>       if (s->sector_num < 0) {
> -        bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
> -        s->sector_num = hbitmap_iter_next(&s->hbi);
> +        bdrv_dirty_iter_free(s->dbi);
> +        s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap, 0);
> +        s->sector_num = bdrv_dirty_iter_next(s->dbi);
>           trace_mirror_restart_iter(s, bdrv_get_dirty_count(s->dirty_bitmap));
>           assert(s->sector_num >= 0);
>       }
> @@ -291,7 +292,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
>            */
>           if (next_sector > hbitmap_next_sector
>               && bdrv_get_dirty(source, s->dirty_bitmap, next_sector)) {
> -            hbitmap_next_sector = hbitmap_iter_next(&s->hbi);
> +            hbitmap_next_sector = bdrv_dirty_iter_next(s->dbi);
>           }
>   
>           next_sector += sectors_per_chunk;
> @@ -502,7 +503,7 @@ static void coroutine_fn mirror_run(void *opaque)
>           }
>       }
>   
> -    bdrv_dirty_iter_init(s->dirty_bitmap, &s->hbi);
> +    s->dbi = bdrv_dirty_iter_new(s->dirty_bitmap, 0);
>       for (;;) {
>           uint64_t delay_ns = 0;
>           int64_t cnt;
> @@ -615,6 +616,7 @@ immediate_exit:
>       qemu_vfree(s->buf);
>       g_free(s->cow_bitmap);
>       g_free(s->in_flight_bitmap);
> +    bdrv_dirty_iter_free(s->dbi);
>       bdrv_release_dirty_bitmap(bs, s->dirty_bitmap);
>       if (s->target->blk) {
>           blk_iostatus_disable(s->target->blk);
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index 02a9337..120bac6 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -35,8 +35,11 @@ void bdrv_set_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>                              int64_t cur_sector, int nr_sectors);
>   void bdrv_reset_dirty_bitmap(BdrvDirtyBitmap *bitmap,
>                                int64_t cur_sector, int nr_sectors);
> -void bdrv_dirty_iter_init(BdrvDirtyBitmap *bitmap, struct HBitmapIter *hbi);
> -void bdrv_set_dirty_iter(struct HBitmapIter *hbi, int64_t offset);
> +BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
> +                                         uint64_t first_sector);
> +void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
> +int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
> +void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
>   int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
>   void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
>   
> diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
> index 0cf9d74..a1bdb5a 100644
> --- a/include/qemu/typedefs.h
> +++ b/include/qemu/typedefs.h
> @@ -11,6 +11,7 @@ typedef struct AioContext AioContext;
>   typedef struct AllwinnerAHCIState AllwinnerAHCIState;
>   typedef struct AudioState AudioState;
>   typedef struct BdrvDirtyBitmap BdrvDirtyBitmap;
> +typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter;
>   typedef struct BlockBackend BlockBackend;
>   typedef struct BlockBackendRootState BlockBackendRootState;
>   typedef struct BlockDriverState BlockDriverState;


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 11/13] hbitmap: serialization
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 11/13] hbitmap: serialization Fam Zheng
@ 2016-01-26 17:01   ` John Snow
  2016-02-27  8:55     ` Fam Zheng
  0 siblings, 1 reply; 42+ messages in thread
From: John Snow @ 2016-01-26 17:01 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, qemu-block



On 01/20/2016 01:11 AM, Fam Zheng wrote:
> From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> 
> Functions to serialize / deserialize(restore) HBitmap. HBitmap should be
> saved to linear sequence of bits independently of endianness and bitmap
> array element (unsigned long) size. Therefore Little Endian is chosen.
> 
> These functions are appropriate for dirty bitmap migration, restoring
> the bitmap in several steps is available. To save performance, every
> step writes only the last level of the bitmap. All other levels are
> restored by hbitmap_deserialize_finish() as a last step of restoring.
> So, HBitmap is inconsistent while restoring.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> [Fix left shift operand to 1UL; add "finish" parameter. - Fam]
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  include/qemu/hbitmap.h |  78 ++++++++++++++++++++++++++++
>  util/hbitmap.c         | 135 +++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 213 insertions(+)
> 
> diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
> index 595ad65..00dbb60 100644
> --- a/include/qemu/hbitmap.h
> +++ b/include/qemu/hbitmap.h
> @@ -149,6 +149,84 @@ void hbitmap_reset_all(HBitmap *hb);
>  bool hbitmap_get(const HBitmap *hb, uint64_t item);
>  
>  /**
> + * hbitmap_serialization_granularity:
> + * @hb: HBitmap to operate on.
> + *
> + * Grunularity of serialization chunks, used by other serializetion functions.

"Granularity," "serialization."

Perhaps we should be consistent with "hbitmap" vs "HBitmap" as well, too.

> + * For every chunk:
> + * 1. Chunk start should be aligned to this granularity.
> + * 2. Chunk size should be aligned too, except for last chunk (for which
> + *      start + count == hb->size)
> + */
> +uint64_t hbitmap_serialization_granularity(const HBitmap *hb);
> +
> +/**
> + * hbitmap_data_size:
> + * @hb: HBitmap to operate on.
> + * @count: Number of bits
> + *
> + * Return amount of bytes hbitmap_(de)serialize_part needs
> + */

"number of bytes" -- amount is for uncountable nouns (like "water.")

> +uint64_t hbitmap_serialization_size(const HBitmap *hb,
> +                                    uint64_t start, uint64_t count);
> +
> +/**
> + * hbitmap_serialize_part
> + * @hb: HBitmap to operate on.
> + * @buf: Buffer to store serialized bitmap.
> + * @start: First bit to store.
> + * @count: Number of bits to store.
> + *
> + * Stores HBitmap data corresponding to given region. The format of saved data
> + * is linear sequence of bits, so it can be used by hbitmap_deserialize_part
> + * independently of endianness and size of HBitmap level array elements
> + */
> +void hbitmap_serialize_part(const HBitmap *hb, uint8_t *buf,
> +                            uint64_t start, uint64_t count);
> +
> +/**
> + * hbitmap_deserialize_part
> + * @hb: HBitmap to operate on.
> + * @buf: Buffer to restore bitmap data from.
> + * @start: First bit to restore.
> + * @count: Number of bits to restore.
> + * @finish: Whether to call hbitmap_deserialize_finish automatically.
> + *
> + * Restores HBitmap data corresponding to given region. The format is the same
> + * as for hbitmap_serialize_part.
> + *
> + * If @finish is false, caller must call hbitmap_serialize_finish before using
> + * the bitmap.
> + */
> +void hbitmap_deserialize_part(HBitmap *hb, uint8_t *buf,
> +                              uint64_t start, uint64_t count,
> +                              bool finish);
> +
> +/**
> + * hbitmap_deserialize_zeroes
> + * @hb: HBitmap to operate on.
> + * @start: First bit to restore.
> + * @count: Number of bits to restore.
> + * @finish: Whether to call hbitmap_deserialize_finish automatically.
> + *
> + * Fills the bitmap with zeroes.
> + *
> + * If @finish is false, caller must call hbitmap_serialize_finish before using
> + * the bitmap.
> + */
> +void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
> +                                bool finish);
> +
> +/**
> + * hbitmap_deserialize_finish
> + * @hb: HBitmap to operate on.
> + *
> + * Repair HBitmap after calling hbitmap_deserialize_data. Actually, all HBitmap
> + * layers are restored here.
> + */
> +void hbitmap_deserialize_finish(HBitmap *hb);
> +
> +/**
>   * hbitmap_free:
>   * @hb: HBitmap to operate on.
>   *
> diff --git a/util/hbitmap.c b/util/hbitmap.c
> index 79f6236..1e49ab7 100644
> --- a/util/hbitmap.c
> +++ b/util/hbitmap.c
> @@ -397,6 +397,141 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
>      return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0;
>  }
>  
> +uint64_t hbitmap_serialization_granularity(const HBitmap *hb)
> +{
> +    return 64 << hb->granularity;
> +}
> +

Sorry, about to be confused about what this function is meant to do,
please bear with me:

Normally the granularity specifies the mapping of "interface" bits to
"implementation" bits. I've never came up with good terminology for
this, but if the user asks for 128 bits and a granularity of 2, we
secretly only allocate 32 bits.

So "virtually" we have 128, and "physically" we have 32.

What is this function giving us? for the size=128,g=2 example above this
gives us (64 << 2 == 256), which I guess is the number of "virtual" bits
represented by each physical uint64_t.

64 bits, each bit represents 2^g==2^2==4 bits, so 256 bits total for a
uint64_t.

If I'm right, perhaps just a brief comment to help me remember it in the
future?

Further: this function does not appear to be used for any reason other
than making sure the alignment is correct, so it appears that:

- On a 64bit host, an el is 64 bits and we will serialize like that
- On a 32bit host, an el is 32 bits and we'll serialize in multiples of
32 bits
- After transfer, though, the destination host may deserialize assuming
either 32bit or 64bit elements -- hence aligning to 64bits is the safest
bet.

Correct?

> +/* Start should be aligned to serialization granularity, chunk size should be
> + * aligned to serialization granularity too, except for last chunk.
> + */
> +static void serialization_chunk(const HBitmap *hb,
> +                                uint64_t start, uint64_t count,
> +                                unsigned long **first_el, size_t *el_count)
> +{
> +    uint64_t last = start + count - 1;
> +    uint64_t gran = hbitmap_serialization_granularity(hb);
> +
> +    assert((start & (gran - 1)) == 0);
> +    assert((last >> hb->granularity) < hb->size);
> +    if ((last >> hb->granularity) != hb->size - 1) {
> +        assert((count & (gran - 1)) == 0);
> +    }
> +

So we're just asserting that the serialization chunk we're doing aligns
well to a uint64_t boundary, right? and otherwise we're instantiating
"first_el" and "el_count" with information about the chunk to serialize...

(I assume first_el means "first element.")

> +    start = (start >> hb->granularity) >> BITS_PER_LEVEL;
> +    last = (last >> hb->granularity) >> BITS_PER_LEVEL;
> +
> +    *first_el = &hb->levels[HBITMAP_LEVELS - 1][start];
> +    *el_count = last - start + 1;
> +}
> +
> +uint64_t hbitmap_serialization_size(const HBitmap *hb,
> +                                    uint64_t start, uint64_t count)
> +{
> +    uint64_t el_count;
> +    unsigned long *cur;
> +
> +    if (!count) {
> +        return 0;
> +    }
> +    serialization_chunk(hb, start, count, &cur, &el_count);
> +
> +    return el_count * sizeof(unsigned long);
> +}
> +

Documentation says "hbitmap_data_size," but the function has been named
hbitmap_serialization_size.

Documentation only mentions @hb and @count, but not @start. (Though it's
obvious, it's still weird.)

> +void hbitmap_serialize_part(const HBitmap *hb, uint8_t *buf,
> +                            uint64_t start, uint64_t count)
> +{
> +    uint64_t el_count;
> +    unsigned long *cur, *end;
> +
> +    if (!count) {
> +        return;
> +    }
> +    serialization_chunk(hb, start, count, &cur, &el_count);
> +    end = cur + el_count;
> +
> +    while (cur != end) {
> +        unsigned long el =
> +            (BITS_PER_LONG == 32 ? cpu_to_le32(*cur) : cpu_to_le64(*cur));
> +
> +        memcpy(buf, &el, sizeof(el));
> +        buf += sizeof(el);
> +        cur++;
> +    }
> +}
> +
> +void hbitmap_deserialize_part(HBitmap *hb, uint8_t *buf,
> +                              uint64_t start, uint64_t count,
> +                              bool finish)
> +{
> +    uint64_t el_count;
> +    unsigned long *cur, *end;
> +
> +    if (!count) {
> +        return;
> +    }
> +    serialization_chunk(hb, start, count, &cur, &el_count);
> +    end = cur + el_count;
> +
> +    while (cur != end) {
> +        memcpy(cur, buf, sizeof(*cur));
> +
> +        if (BITS_PER_LONG == 32) {
> +            le32_to_cpus((uint32_t *)cur);
> +        } else {
> +            le64_to_cpus((uint64_t *)cur);
> +        }
> +
> +        buf += sizeof(unsigned long);
> +        cur++;
> +    }
> +    if (finish) {
> +        hbitmap_deserialize_finish(hb);
> +    }
> +}
> +
> +void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
> +                                bool finish)
> +{
> +    uint64_t el_count;
> +    unsigned long *first;
> +
> +    if (!count) {
> +        return;
> +    }
> +    serialization_chunk(hb, start, count, &first, &el_count);
> +
> +    memset(first, 0, el_count * sizeof(unsigned long));
> +    if (finish) {
> +        hbitmap_deserialize_finish(hb);
> +    }
> +}
> +

I still find this concept funny, since we're not really deserializing
anything :)

The function is fine though, of course.

> +void hbitmap_deserialize_finish(HBitmap *bitmap)
> +{
> +    int64_t i, size, prev_size;
> +    int lev;
> +
> +    /* restore levels starting from penultimate to zero level, assuming
> +     * that the last level is ok */
> +    size = MAX((bitmap->size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
> +    for (lev = HBITMAP_LEVELS - 1; lev-- > 0; ) {
> +        prev_size = size;
> +        size = MAX((size + BITS_PER_LONG - 1) >> BITS_PER_LEVEL, 1);
> +        memset(bitmap->levels[lev], 0, size * sizeof(unsigned long));
> +
> +        for (i = 0; i < prev_size; ++i) {
> +            if (bitmap->levels[lev + 1][i]) {
> +                bitmap->levels[lev][i >> BITS_PER_LEVEL] |=
> +                    1UL << (i & (BITS_PER_LONG - 1));
> +            }
> +        }
> +    }
> +
> +    bitmap->levels[0][0] |= 1UL << (BITS_PER_LONG - 1);
> +}
> +
>  void hbitmap_free(HBitmap *hb)
>  {
>      unsigned i;
> 

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

* Re: [Qemu-devel] [PATCH v2 12/13] block: BdrvDirtyBitmap serialization interface
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 12/13] block: BdrvDirtyBitmap serialization interface Fam Zheng
@ 2016-01-26 17:07   ` John Snow
  0 siblings, 0 replies; 42+ messages in thread
From: John Snow @ 2016-01-26 17:07 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, qemu-block



On 01/20/2016 01:11 AM, Fam Zheng wrote:
> From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> 
> Several functions to provide necessary access to BdrvDirtyBitmap for
> block-migration.c
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> [Add the "finish" parameters. - Fam]
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  block/dirty-bitmap.c         | 37 +++++++++++++++++++++++++++++++++++++
>  include/block/dirty-bitmap.h | 14 ++++++++++++++
>  2 files changed, 51 insertions(+)
> 
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index ec13d38..919ce10 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -429,6 +429,43 @@ void bdrv_undo_clear_dirty_bitmap(BdrvDirtyBitmap *bitmap, HBitmap *in)
>      hbitmap_free(tmp);
>  }
>  
> +uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
> +                                              uint64_t start, uint64_t count)
> +{
> +    return hbitmap_serialization_size(bitmap->bitmap, start, count);
> +}
> +
> +uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap)
> +{
> +    return hbitmap_serialization_granularity(bitmap->bitmap);
> +}
> +
> +void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
> +                                      uint8_t *buf, uint64_t start,
> +                                      uint64_t count)
> +{
> +    hbitmap_serialize_part(bitmap->bitmap, buf, start, count);
> +}
> +
> +void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
> +                                        uint8_t *buf, uint64_t start,
> +                                        uint64_t count, bool finish)
> +{
> +    hbitmap_deserialize_part(bitmap->bitmap, buf, start, count, finish);
> +}
> +
> +void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
> +                                          uint64_t start, uint64_t count,
> +                                          bool finish)
> +{
> +    hbitmap_deserialize_zeroes(bitmap->bitmap, start, count, finish);
> +}
> +
> +void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap)
> +{
> +    hbitmap_deserialize_finish(bitmap->bitmap);
> +}
> +
>  void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
>                      int nr_sectors)
>  {
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index 8c29c3e..6ba5bec 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -54,4 +54,18 @@ void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
>  int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
>  void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
>  
> +uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,
> +                                              uint64_t start, uint64_t count);
> +uint64_t bdrv_dirty_bitmap_serialization_align(const BdrvDirtyBitmap *bitmap);
> +void bdrv_dirty_bitmap_serialize_part(const BdrvDirtyBitmap *bitmap,
> +                                      uint8_t *buf, uint64_t start,
> +                                      uint64_t count);
> +void bdrv_dirty_bitmap_deserialize_part(BdrvDirtyBitmap *bitmap,
> +                                        uint8_t *buf, uint64_t start,
> +                                        uint64_t count, bool finish);
> +void bdrv_dirty_bitmap_deserialize_zeroes(BdrvDirtyBitmap *bitmap,
> +                                          uint64_t start, uint64_t count,
> +                                          bool finish);
> +void bdrv_dirty_bitmap_deserialize_finish(BdrvDirtyBitmap *bitmap);
> +
>  #endif
> 

Reviewed-by: John Snow <jsnow@redhat.com>

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

* Re: [Qemu-devel] [PATCH v2 13/13] tests: Add test code for hbitmap serialization
  2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 13/13] tests: Add test code for hbitmap serialization Fam Zheng
@ 2016-01-26 17:10   ` John Snow
  0 siblings, 0 replies; 42+ messages in thread
From: John Snow @ 2016-01-26 17:10 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, qemu-block



On 01/20/2016 01:11 AM, Fam Zheng wrote:
> Signed-off-by: Fam Zheng <famz@redhat.com>

Looks OK at 10,000 feet.

Acked-by: John Snow <jsnow@redhat.com>

> ---
>  tests/test-hbitmap.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 139 insertions(+)
> 
> diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
> index a341803..9b89751 100644
> --- a/tests/test-hbitmap.c
> +++ b/tests/test-hbitmap.c
> @@ -14,6 +14,7 @@
>  #include <string.h>
>  #include <sys/types.h>
>  #include "qemu/hbitmap.h"
> +#include "qemu/bitmap.h"
>  #include "block/block.h"
>  
>  #define LOG_BITS_PER_LONG          (BITS_PER_LONG == 32 ? 5 : 6)
> @@ -740,6 +741,16 @@ static void test_hbitmap_meta_one(TestHBitmapData *data, const void *unused)
>      }
>  }
>  
> +static void test_hbitmap_serialize_granularity(TestHBitmapData *data,
> +                                               const void *unused)
> +{
> +    int r;
> +
> +    hbitmap_test_init(data, L3 * 2, 3);
> +    r = hbitmap_serialization_granularity(data->hb);
> +    g_assert_cmpint(r, ==, BITS_PER_LONG << 3);
> +}
> +
>  static void test_hbitmap_meta_zero(TestHBitmapData *data, const void *unused)
>  {
>      hbitmap_test_init_meta(data, 0, 0, 1);
> @@ -747,6 +758,125 @@ static void test_hbitmap_meta_zero(TestHBitmapData *data, const void *unused)
>      hbitmap_check_meta(data, 0, 0);
>  }
>  
> +static void hbitmap_test_serialize_range(TestHBitmapData *data,
> +                                         uint8_t *buf, size_t buf_size,
> +                                         uint64_t pos, uint64_t count)
> +{
> +    size_t i;
> +
> +    assert(hbitmap_granularity(data->hb) == 0);
> +    hbitmap_reset_all(data->hb);
> +    memset(buf, 0, buf_size);
> +    if (count) {
> +        hbitmap_set(data->hb, pos, count);
> +    }
> +    hbitmap_serialize_part(data->hb, buf, 0, data->size);
> +    for (i = 0; i < data->size; i++) {
> +        int is_set = test_bit(i, (unsigned long *)buf);
> +        if (i >= pos && i < pos + count) {
> +            g_assert(is_set);
> +        } else {
> +            g_assert(!is_set);
> +        }
> +    }
> +    hbitmap_reset_all(data->hb);
> +    hbitmap_deserialize_part(data->hb, buf, 0, data->size, true);
> +
> +    for (i = 0; i < data->size; i++) {
> +        int is_set = hbitmap_get(data->hb, i);
> +        if (i >= pos && i < pos + count) {
> +            g_assert(is_set);
> +        } else {
> +            g_assert(!is_set);
> +        }
> +    }
> +}
> +
> +static void test_hbitmap_serialize_basic(TestHBitmapData *data,
> +                                         const void *unused)
> +{
> +    int i, j;
> +    size_t buf_size;
> +    uint8_t *buf;
> +    uint64_t positions[] = { 0, 1, L1 - 1, L1, L2 - 1, L2, L2 + 1, L3 - 1 };
> +    int num_positions = sizeof(positions) / sizeof(positions[0]);
> +
> +    hbitmap_test_init(data, L3, 0);
> +    buf_size = hbitmap_serialization_size(data->hb, 0, data->size);
> +    buf = g_malloc0(buf_size);
> +
> +    for (i = 0; i < num_positions; i++) {
> +        for (j = 0; j < num_positions; j++) {
> +            hbitmap_test_serialize_range(data, buf, buf_size,
> +                                         positions[i],
> +                                         MIN(positions[j], L3 - positions[i]));
> +        }
> +    }
> +
> +    g_free(buf);
> +}
> +
> +static void test_hbitmap_serialize_part(TestHBitmapData *data,
> +                                        const void *unused)
> +{
> +    int i, j, k;
> +    size_t buf_size;
> +    uint8_t *buf;
> +    uint64_t positions[] = { 0, 1, L1 - 1, L1, L2 - 1, L2, L2 + 1, L3 - 1 };
> +    int num_positions = sizeof(positions) / sizeof(positions[0]);
> +
> +    hbitmap_test_init(data, L3, 0);
> +    buf_size = L2;
> +    buf = g_malloc0(buf_size);
> +
> +    for (i = 0; i < num_positions; i++) {
> +        hbitmap_set(data->hb, positions[i], 1);
> +    }
> +
> +    for (i = 0; i < data->size; i += buf_size) {
> +        hbitmap_serialize_part(data->hb, buf, i, buf_size);
> +        for (j = 0; j < buf_size; j++) {
> +            bool should_set = false;
> +            for (k = 0; k < num_positions; k++) {
> +                if (positions[k] == j + i) {
> +                    should_set = true;
> +                    break;
> +                }
> +            }
> +            g_assert_cmpint(should_set, ==, test_bit(j, (unsigned long *)buf));
> +        }
> +    }
> +
> +    g_free(buf);
> +}
> +
> +static void test_hbitmap_serialize_zeroes(TestHBitmapData *data,
> +                                          const void *unused)
> +{
> +    int i;
> +    HBitmapIter iter;
> +    int64_t next;
> +    uint64_t positions[] = { 0, L1, L2, L3 - L1};
> +    int num_positions = sizeof(positions) / sizeof(positions[0]);
> +
> +    hbitmap_test_init(data, L3, 0);
> +
> +    for (i = 0; i < num_positions; i++) {
> +        hbitmap_set(data->hb, positions[i], L1);
> +    }
> +
> +    for (i = 0; i < num_positions; i++) {
> +        hbitmap_deserialize_zeroes(data->hb, positions[i], L1, true);
> +        hbitmap_iter_init(&iter, data->hb, 0);
> +        next = hbitmap_iter_next(&iter);
> +        if (i == num_positions - 1) {
> +            g_assert_cmpint(next, ==, -1);
> +        } else {
> +            g_assert_cmpint(next, ==, positions[i + 1]);
> +        }
> +    }
> +}
> +
>  static void hbitmap_test_add(const char *testpath,
>                                     void (*test_func)(TestHBitmapData *data, const void *user_data))
>  {
> @@ -802,6 +932,15 @@ int main(int argc, char **argv)
>      hbitmap_test_add("/hbitmap/meta/byte", test_hbitmap_meta_byte);
>      hbitmap_test_add("/hbitmap/meta/word", test_hbitmap_meta_word);
>      hbitmap_test_add("/hbitmap/meta/sector", test_hbitmap_meta_sector);
> +
> +    hbitmap_test_add("/hbitmap/serialize/granularity",
> +                     test_hbitmap_serialize_granularity);
> +    hbitmap_test_add("/hbitmap/serialize/basic",
> +                     test_hbitmap_serialize_basic);
> +    hbitmap_test_add("/hbitmap/serialize/part",
> +                     test_hbitmap_serialize_part);
> +    hbitmap_test_add("/hbitmap/serialize/zeroes",
> +                     test_hbitmap_serialize_zeroes);
>      g_test_run();
>  
>      return 0;
> 

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

* Re: [Qemu-devel] [PATCH v2 14/13] block: More operations for meta dirty bitmap
  2016-01-26  7:26 ` [Qemu-devel] [PATCH v2 14/13] block: More operations for meta dirty bitmap Fam Zheng
@ 2016-01-27 14:57   ` Vladimir Sementsov-Ogievskiy
  2016-02-27  8:35     ` Fam Zheng
  0 siblings, 1 reply; 42+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2016-01-27 14:57 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel; +Cc: qemu-block

On 26.01.2016 10:26, Fam Zheng wrote:
> Callers can create an iterator of meta bitmap with
> bdrv_dirty_meta_iter_new(), then use the bdrv_dirty_iter_* operations on
> it. Meta iterators are also counted by bitmap->active_iterators.
>
> Also add a couple of functions to retrieve granularity and count.
>
> Signed-off-by: Fam Zheng <famz@redhat.com>
>
> ---
>
> Vladimir, are these interfaces enough for your migration series? If it
> is more convenient to you, you can adjust and take it into your series.

This patch is ok (the only thing - see comment below), thanks. The only 
thing is that my migration series may be changed to use post-copy 
migration instead of meta-bitmaps..

> ---
>   block/dirty-bitmap.c         | 19 +++++++++++++++++++
>   include/block/dirty-bitmap.h |  3 +++
>   2 files changed, 22 insertions(+)
>
> diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> index bf84b17..1aa7f76 100644
> --- a/block/dirty-bitmap.c
> +++ b/block/dirty-bitmap.c
> @@ -369,6 +369,11 @@ uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
>       return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
>   }
>   
> +uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap)
> +{
> +    return hbitmap_granularity(bitmap->meta);
> +}

I think it should be more like bdrv_dirty_bitmap_granularity, with 
"BDRV_SECTOR_SIZE << ".

> +
>   BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
>                                            uint64_t first_sector)
>   {
> @@ -379,6 +384,15 @@ BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
>       return iter;
>   }
>   
> +BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap)
> +{
> +    BdrvDirtyBitmapIter *iter = g_new(BdrvDirtyBitmapIter, 1);
> +    hbitmap_iter_init(&iter->hbi, bitmap->meta, 0);
> +    iter->bitmap = bitmap;
> +    bitmap->active_iterators++;
> +    return iter;
> +}
> +
>   void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter)
>   {
>       if (!iter) {
> @@ -490,3 +504,8 @@ int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap)
>   {
>       return hbitmap_count(bitmap->bitmap);
>   }
> +
> +int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap)
> +{
> +    return hbitmap_count(bitmap->meta);
> +}
> diff --git a/include/block/dirty-bitmap.h b/include/block/dirty-bitmap.h
> index 76256fb..d14d923 100644
> --- a/include/block/dirty-bitmap.h
> +++ b/include/block/dirty-bitmap.h
> @@ -30,6 +30,7 @@ void bdrv_enable_dirty_bitmap(BdrvDirtyBitmap *bitmap);
>   BlockDirtyInfoList *bdrv_query_dirty_bitmaps(BlockDriverState *bs);
>   uint32_t bdrv_get_default_bitmap_granularity(BlockDriverState *bs);
>   uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap);
> +uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap);
>   bool bdrv_dirty_bitmap_enabled(BdrvDirtyBitmap *bitmap);
>   bool bdrv_dirty_bitmap_frozen(BdrvDirtyBitmap *bitmap);
>   const char *bdrv_dirty_bitmap_name(const BdrvDirtyBitmap *bitmap);
> @@ -46,12 +47,14 @@ int bdrv_dirty_bitmap_get_meta(BlockDriverState *bs,
>   void bdrv_dirty_bitmap_reset_meta(BlockDriverState *bs,
>                                     BdrvDirtyBitmap *bitmap, int64_t sector,
>                                     int nb_sectors);
> +BdrvDirtyBitmapIter *bdrv_dirty_meta_iter_new(BdrvDirtyBitmap *bitmap);
>   BdrvDirtyBitmapIter *bdrv_dirty_iter_new(BdrvDirtyBitmap *bitmap,
>                                            uint64_t first_sector);
>   void bdrv_dirty_iter_free(BdrvDirtyBitmapIter *iter);
>   int64_t bdrv_dirty_iter_next(BdrvDirtyBitmapIter *iter);
>   void bdrv_set_dirty_iter(BdrvDirtyBitmapIter *hbi, int64_t sector_num);
>   int64_t bdrv_get_dirty_count(BdrvDirtyBitmap *bitmap);
> +int64_t bdrv_get_meta_dirty_count(BdrvDirtyBitmap *bitmap);
>   void bdrv_dirty_bitmap_truncate(BlockDriverState *bs);
>   
>   uint64_t bdrv_dirty_bitmap_serialization_size(const BdrvDirtyBitmap *bitmap,


-- 
Best regards,
Vladimir
* now, @virtuozzo.com instead of @parallels.com. Sorry for this inconvenience.

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

* Re: [Qemu-devel] [PATCH v2 05/13] block: Hide HBitmap in block dirty bitmap interface
  2016-01-26 16:02   ` Vladimir Sementsov-Ogievskiy
@ 2016-02-27  8:30     ` Fam Zheng
  0 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-02-27  8:30 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Jeff Cody, jsnow, qemu-devel, qemu-block

On Tue, 01/26 19:02, Vladimir Sementsov-Ogievskiy wrote:
> 
> why? The old way works for meta iters. The new code - doesn't. I suppose
> 
> assert(iter->hbi.hb);
> hbitmap_iter_init(&iter->hbi, iter->hbi.hb, sector_num);

Okay, will change.

Fam

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

* Re: [Qemu-devel] [PATCH v2 14/13] block: More operations for meta dirty bitmap
  2016-01-27 14:57   ` Vladimir Sementsov-Ogievskiy
@ 2016-02-27  8:35     ` Fam Zheng
  0 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-02-27  8:35 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy; +Cc: qemu-devel, qemu-block

On Wed, 01/27 17:57, Vladimir Sementsov-Ogievskiy wrote:
> On 26.01.2016 10:26, Fam Zheng wrote:
> >Callers can create an iterator of meta bitmap with
> >bdrv_dirty_meta_iter_new(), then use the bdrv_dirty_iter_* operations on
> >it. Meta iterators are also counted by bitmap->active_iterators.
> >
> >Also add a couple of functions to retrieve granularity and count.
> >
> >Signed-off-by: Fam Zheng <famz@redhat.com>
> >
> >---
> >
> >Vladimir, are these interfaces enough for your migration series? If it
> >is more convenient to you, you can adjust and take it into your series.
> 
> This patch is ok (the only thing - see comment below), thanks. The
> only thing is that my migration series may be changed to use
> post-copy migration instead of meta-bitmaps..
> 
> >---
> >  block/dirty-bitmap.c         | 19 +++++++++++++++++++
> >  include/block/dirty-bitmap.h |  3 +++
> >  2 files changed, 22 insertions(+)
> >
> >diff --git a/block/dirty-bitmap.c b/block/dirty-bitmap.c
> >index bf84b17..1aa7f76 100644
> >--- a/block/dirty-bitmap.c
> >+++ b/block/dirty-bitmap.c
> >@@ -369,6 +369,11 @@ uint32_t bdrv_dirty_bitmap_granularity(BdrvDirtyBitmap *bitmap)
> >      return BDRV_SECTOR_SIZE << hbitmap_granularity(bitmap->bitmap);
> >  }
> >+uint32_t bdrv_dirty_bitmap_meta_granularity(BdrvDirtyBitmap *bitmap)
> >+{
> >+    return hbitmap_granularity(bitmap->meta);
> >+}
> 
> I think it should be more like bdrv_dirty_bitmap_granularity, with
> "BDRV_SECTOR_SIZE << ".

Yes, will change.

Fam

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

* Re: [Qemu-devel] [PATCH v2 11/13] hbitmap: serialization
  2016-01-26 17:01   ` John Snow
@ 2016-02-27  8:55     ` Fam Zheng
  0 siblings, 0 replies; 42+ messages in thread
From: Fam Zheng @ 2016-02-27  8:55 UTC (permalink / raw)
  To: John Snow
  Cc: Kevin Wolf, Jeff Cody, Vladimir Sementsov-Ogievskiy, qemu-devel,
	qemu-block

On Tue, 01/26 12:01, John Snow wrote:
> 
> 
> On 01/20/2016 01:11 AM, Fam Zheng wrote:
> > From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> > 
> > Functions to serialize / deserialize(restore) HBitmap. HBitmap should be
> > saved to linear sequence of bits independently of endianness and bitmap
> > array element (unsigned long) size. Therefore Little Endian is chosen.
> > 
> > These functions are appropriate for dirty bitmap migration, restoring
> > the bitmap in several steps is available. To save performance, every
> > step writes only the last level of the bitmap. All other levels are
> > restored by hbitmap_deserialize_finish() as a last step of restoring.
> > So, HBitmap is inconsistent while restoring.
> > 
> > Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> > [Fix left shift operand to 1UL; add "finish" parameter. - Fam]
> > Signed-off-by: Fam Zheng <famz@redhat.com>
> > ---
> >  include/qemu/hbitmap.h |  78 ++++++++++++++++++++++++++++
> >  util/hbitmap.c         | 135 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 213 insertions(+)
> > 
> > diff --git a/include/qemu/hbitmap.h b/include/qemu/hbitmap.h
> > index 595ad65..00dbb60 100644
> > --- a/include/qemu/hbitmap.h
> > +++ b/include/qemu/hbitmap.h
> > @@ -149,6 +149,84 @@ void hbitmap_reset_all(HBitmap *hb);
> >  bool hbitmap_get(const HBitmap *hb, uint64_t item);
> >  
> >  /**
> > + * hbitmap_serialization_granularity:
> > + * @hb: HBitmap to operate on.
> > + *
> > + * Grunularity of serialization chunks, used by other serializetion functions.
> 
> "Granularity," "serialization."
> 
> Perhaps we should be consistent with "hbitmap" vs "HBitmap" as well, too.
> 
> > + * For every chunk:
> > + * 1. Chunk start should be aligned to this granularity.
> > + * 2. Chunk size should be aligned too, except for last chunk (for which
> > + *      start + count == hb->size)
> > + */
> > +uint64_t hbitmap_serialization_granularity(const HBitmap *hb);
> > +
> > +/**
> > + * hbitmap_data_size:
> > + * @hb: HBitmap to operate on.
> > + * @count: Number of bits
> > + *
> > + * Return amount of bytes hbitmap_(de)serialize_part needs
> > + */
> 
> "number of bytes" -- amount is for uncountable nouns (like "water.")
> 
> > +uint64_t hbitmap_serialization_size(const HBitmap *hb,
> > +                                    uint64_t start, uint64_t count);
> > +
> > +/**
> > + * hbitmap_serialize_part
> > + * @hb: HBitmap to operate on.
> > + * @buf: Buffer to store serialized bitmap.
> > + * @start: First bit to store.
> > + * @count: Number of bits to store.
> > + *
> > + * Stores HBitmap data corresponding to given region. The format of saved data
> > + * is linear sequence of bits, so it can be used by hbitmap_deserialize_part
> > + * independently of endianness and size of HBitmap level array elements
> > + */
> > +void hbitmap_serialize_part(const HBitmap *hb, uint8_t *buf,
> > +                            uint64_t start, uint64_t count);
> > +
> > +/**
> > + * hbitmap_deserialize_part
> > + * @hb: HBitmap to operate on.
> > + * @buf: Buffer to restore bitmap data from.
> > + * @start: First bit to restore.
> > + * @count: Number of bits to restore.
> > + * @finish: Whether to call hbitmap_deserialize_finish automatically.
> > + *
> > + * Restores HBitmap data corresponding to given region. The format is the same
> > + * as for hbitmap_serialize_part.
> > + *
> > + * If @finish is false, caller must call hbitmap_serialize_finish before using
> > + * the bitmap.
> > + */
> > +void hbitmap_deserialize_part(HBitmap *hb, uint8_t *buf,
> > +                              uint64_t start, uint64_t count,
> > +                              bool finish);
> > +
> > +/**
> > + * hbitmap_deserialize_zeroes
> > + * @hb: HBitmap to operate on.
> > + * @start: First bit to restore.
> > + * @count: Number of bits to restore.
> > + * @finish: Whether to call hbitmap_deserialize_finish automatically.
> > + *
> > + * Fills the bitmap with zeroes.
> > + *
> > + * If @finish is false, caller must call hbitmap_serialize_finish before using
> > + * the bitmap.
> > + */
> > +void hbitmap_deserialize_zeroes(HBitmap *hb, uint64_t start, uint64_t count,
> > +                                bool finish);
> > +
> > +/**
> > + * hbitmap_deserialize_finish
> > + * @hb: HBitmap to operate on.
> > + *
> > + * Repair HBitmap after calling hbitmap_deserialize_data. Actually, all HBitmap
> > + * layers are restored here.
> > + */
> > +void hbitmap_deserialize_finish(HBitmap *hb);
> > +
> > +/**
> >   * hbitmap_free:
> >   * @hb: HBitmap to operate on.
> >   *
> > diff --git a/util/hbitmap.c b/util/hbitmap.c
> > index 79f6236..1e49ab7 100644
> > --- a/util/hbitmap.c
> > +++ b/util/hbitmap.c
> > @@ -397,6 +397,141 @@ bool hbitmap_get(const HBitmap *hb, uint64_t item)
> >      return (hb->levels[HBITMAP_LEVELS - 1][pos >> BITS_PER_LEVEL] & bit) != 0;
> >  }
> >  
> > +uint64_t hbitmap_serialization_granularity(const HBitmap *hb)
> > +{
> > +    return 64 << hb->granularity;
> > +}
> > +
> 
> Sorry, about to be confused about what this function is meant to do,
> please bear with me:
> 
> Normally the granularity specifies the mapping of "interface" bits to
> "implementation" bits. I've never came up with good terminology for
> this, but if the user asks for 128 bits and a granularity of 2, we
> secretly only allocate 32 bits.
> 
> So "virtually" we have 128, and "physically" we have 32.
> 
> What is this function giving us? for the size=128,g=2 example above this
> gives us (64 << 2 == 256), which I guess is the number of "virtual" bits
> represented by each physical uint64_t.
> 
> 64 bits, each bit represents 2^g==2^2==4 bits, so 256 bits total for a
> uint64_t.
> 
> If I'm right, perhaps just a brief comment to help me remember it in the
> future?

OK, I'll add a comment here.

> 
> Further: this function does not appear to be used for any reason other
> than making sure the alignment is correct, so it appears that:
> 
> - On a 64bit host, an el is 64 bits and we will serialize like that
> - On a 32bit host, an el is 32 bits and we'll serialize in multiples of
> 32 bits
> - After transfer, though, the destination host may deserialize assuming
> either 32bit or 64bit elements -- hence aligning to 64bits is the safest
> bet.
> 
> Correct?

Yes.

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

end of thread, other threads:[~2016-02-27  8:56 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-20  6:11 [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Fam Zheng
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 01/13] backup: Use Bitmap to replace "s->bitmap" Fam Zheng
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 02/13] typedefs: Add BdrvDirtyBitmap Fam Zheng
2016-01-20 16:56   ` Eric Blake
2016-01-21  3:05     ` Fam Zheng
2016-01-25 20:37   ` John Snow
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 03/13] block: Move block dirty bitmap code to separate files Fam Zheng
2016-01-22  9:13   ` Vladimir Sementsov-Ogievskiy
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 04/13] block: Remove unused typedef of BlockDriverDirtyHandler Fam Zheng
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 05/13] block: Hide HBitmap in block dirty bitmap interface Fam Zheng
2016-01-26 16:02   ` Vladimir Sementsov-Ogievskiy
2016-02-27  8:30     ` Fam Zheng
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 06/13] HBitmap: Introduce "meta" bitmap to track bit changes Fam Zheng
2016-01-25 22:02   ` John Snow
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 07/13] tests: Add test code for meta bitmap Fam Zheng
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 08/13] block: Support meta dirty bitmap Fam Zheng
2016-01-22 11:34   ` Vladimir Sementsov-Ogievskiy
2016-01-26  4:31     ` Fam Zheng
2016-01-22 11:58   ` Vladimir Sementsov-Ogievskiy
2016-01-22 12:05     ` Vladimir Sementsov-Ogievskiy
2016-01-26  6:25       ` Fam Zheng
2016-01-26  7:49         ` Vladimir Sementsov-Ogievskiy
2016-01-26  8:23           ` Fam Zheng
2016-01-25 22:16   ` John Snow
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 09/13] block: Add two dirty bitmap getters Fam Zheng
2016-01-22 11:45   ` Vladimir Sementsov-Ogievskiy
2016-01-26  4:19     ` Fam Zheng
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 10/13] block: Assert that bdrv_release_dirty_bitmap succeeded Fam Zheng
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 11/13] hbitmap: serialization Fam Zheng
2016-01-26 17:01   ` John Snow
2016-02-27  8:55     ` Fam Zheng
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 12/13] block: BdrvDirtyBitmap serialization interface Fam Zheng
2016-01-26 17:07   ` John Snow
2016-01-20  6:11 ` [Qemu-devel] [PATCH v2 13/13] tests: Add test code for hbitmap serialization Fam Zheng
2016-01-26 17:10   ` John Snow
2016-01-20 16:13 ` [Qemu-devel] [PATCH v2 00/13] Dirty bitmap changes for migration/persistence work Vladimir Sementsov-Ogievskiy
2016-01-22 12:07   ` Vladimir Sementsov-Ogievskiy
2016-01-21 10:41 ` Vladimir Sementsov-Ogievskiy
2016-01-21 13:03   ` Fam Zheng
2016-01-26  7:26 ` [Qemu-devel] [PATCH v2 14/13] block: More operations for meta dirty bitmap Fam Zheng
2016-01-27 14:57   ` Vladimir Sementsov-Ogievskiy
2016-02-27  8:35     ` Fam Zheng

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.