diff mbox

[07/29] qcow2-bitmap: add qcow2_bitmap_load()

Message ID 1470668720-211300-8-git-send-email-vsementsov@virtuozzo.com (mailing list archive)
State New, archived
Headers show

Commit Message

Vladimir Sementsov-Ogievskiy Aug. 8, 2016, 3:04 p.m. UTC
This function loads block dirty bitmap from qcow2.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
 block/qcow2-bitmap.c      | 165 ++++++++++++++++++++++++++++++++++++++++++++++
 block/qcow2.c             |   2 +
 block/qcow2.h             |   3 +
 include/block/block_int.h |   4 ++
 4 files changed, 174 insertions(+)

Comments

Kevin Wolf Aug. 11, 2016, 1 p.m. UTC | #1
Am 08.08.2016 um 17:04 hat Vladimir Sementsov-Ogievskiy geschrieben:
> This function loads block dirty bitmap from qcow2.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

As you said this is really unused at the moment, I'll mostly skip this
patch. Just one thing:

> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index 1fe0fd9..2c11ad7 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -224,6 +224,10 @@ struct BlockDriver {
>      int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
>      ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs);
>  
> +    BdrvDirtyBitmap *(*bdrv_dirty_bitmap_load)(BlockDriverState *bs,
> +                                               const char *name,
> +                                               Error **errp);
> +

I would prefer adding BlockDriver callbacks in the same patch as the
wrapper function, and keeping them separate from the first format driver
implementation. The reason for this is that sometimes people want to
backport the infrastructure, but not the driver change.

Similar to my comment on an earlier series, this means doing patch 16
(which this hunk added) first and only then implementing the function in
qcow2.

This specific instance probably disappears anyway as you remove the dead
code for now, but just to clarify what the preferred order is generally
(and I think you're going to re-submit it later, right?)

Kevin
diff mbox

Patch

diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
index 91ddd5f..280b7bf 100644
--- a/block/qcow2-bitmap.c
+++ b/block/qcow2-bitmap.c
@@ -53,6 +53,10 @@ 
          h < (QCow2BitmapHeader *)((uint8_t *)(dir) + size); \
          h = next_dir_entry(h))
 
+#define for_each_bitmap_header(h, s) \
+    for_each_bitmap_header_in_dir(h, s->bitmap_directory, \
+                                  s->bitmap_directory_size)
+
 typedef enum BitmapType {
     BT_DIRTY_TRACKING_BITMAP = 1
 } BitmapType;
@@ -66,6 +70,15 @@  static inline void bitmap_header_to_cpu(QCow2BitmapHeader *h)
     be32_to_cpus(&h->extra_data_size);
 }
 
+static inline void bitmap_table_to_cpu(uint64_t *bitmap_table, size_t size)
+{
+    size_t i;
+
+    for (i = 0; i < size; ++i) {
+        be64_to_cpus(&bitmap_table[i]);
+    }
+}
+
 static inline int calc_dir_entry_size(size_t name_size)
 {
     return align_offset(sizeof(QCow2BitmapHeader) + name_size, 8);
@@ -145,3 +158,155 @@  int qcow2_read_bitmaps(BlockDriverState *bs, Error **errp)
 
     return 0;
 }
+
+static QCow2BitmapHeader *find_bitmap_by_name(BlockDriverState *bs,
+                                              const char *name)
+{
+    BDRVQcow2State *s = bs->opaque;
+    QCow2BitmapHeader *h;
+
+    for_each_bitmap_header(h, s) {
+        if (strncmp((char *)(h + 1), name, h->name_size) == 0) {
+            return h;
+        }
+    }
+
+    return NULL;
+}
+
+/* dirty sectors in cluster is a number of sectors in the image, corresponding
+ * to one cluster of bitmap data */
+static uint64_t dirty_sectors_in_cluster(const BDRVQcow2State *s,
+                                         const BdrvDirtyBitmap *bitmap)
+{
+    uint32_t sector_granularity =
+            bdrv_dirty_bitmap_granularity(bitmap) >> BDRV_SECTOR_BITS;
+
+    return (uint64_t)sector_granularity * (s->cluster_size << 3);
+}
+
+static int load_bitmap_data(BlockDriverState *bs,
+                            const uint64_t *dirty_bitmap_table,
+                            uint32_t dirty_bitmap_table_size,
+                            BdrvDirtyBitmap *bitmap)
+{
+    int ret = 0;
+    BDRVQcow2State *s = bs->opaque;
+    uint64_t sector, dsc;
+    uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap);
+    int cl_size = s->cluster_size;
+    uint8_t *buf = NULL;
+    uint32_t i, tab_size =
+            size_to_clusters(s,
+                bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size));
+
+    if (tab_size != dirty_bitmap_table_size) {
+        return -EINVAL;
+    }
+
+    bdrv_clear_dirty_bitmap(bitmap, NULL);
+
+    buf = g_malloc0(cl_size);
+    dsc = dirty_sectors_in_cluster(s, bitmap);
+    for (i = 0, sector = 0; i < tab_size; ++i, sector += dsc) {
+        uint64_t end = MIN(bm_size, sector + dsc);
+        uint64_t offset = dirty_bitmap_table[i];
+
+        if (offset == 1) {
+            bdrv_dirty_bitmap_deserialize_ones(bitmap, sector, end, false);
+        } else if (offset > 1) {
+            ret = bdrv_pread(bs->file, offset, buf, cl_size);
+            if (ret < 0) {
+                goto finish;
+            }
+            bdrv_dirty_bitmap_deserialize_part(bitmap, buf, sector, end, false);
+        }
+    }
+    ret = 0;
+
+    bdrv_dirty_bitmap_deserialize_finish(bitmap);
+
+finish:
+    g_free(buf);
+
+    return ret;
+}
+
+static int bitmap_table_load(BlockDriverState *bs, QCow2BitmapHeader *bmh,
+                             uint64_t **table)
+{
+    int ret;
+
+    *table = g_try_new(uint64_t, bmh->bitmap_table_size);
+    if (*table == NULL) {
+        return -ENOMEM;
+    }
+
+    ret = bdrv_pread(bs->file, bmh->bitmap_table_offset,
+                     *table, bmh->bitmap_table_size * sizeof(uint64_t));
+    if (ret < 0) {
+        g_free(*table);
+        *table = NULL;
+        return ret;
+    }
+
+    bitmap_table_to_cpu(*table, bmh->bitmap_table_size);
+
+    return 0;
+}
+
+static BdrvDirtyBitmap *load_bitmap(BlockDriverState *bs,
+                                    QCow2BitmapHeader *bmh, Error **errp)
+{
+    int ret;
+    uint64_t *bitmap_table = NULL;
+    uint32_t granularity;
+    BdrvDirtyBitmap *bitmap = NULL;
+    char *name = g_strndup((char *)(bmh + 1), bmh->name_size);
+
+    ret = bitmap_table_load(bs, bmh, &bitmap_table);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret,
+                         "Could not read bitmap_table table from image");
+        goto fail;
+    }
+
+    granularity = 1U << bmh->granularity_bits;
+    bitmap = bdrv_create_dirty_bitmap(bs, granularity, name, errp);
+    if (bitmap == NULL) {
+        goto fail;
+    }
+
+    ret = load_bitmap_data(bs, bitmap_table, bmh->bitmap_table_size,
+                           bitmap);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "Could not read bitmap from image");
+        goto fail;
+    }
+
+    g_free(name);
+    g_free(bitmap_table);
+    return bitmap;
+
+fail:
+    g_free(name);
+    g_free(bitmap_table);
+    if (bitmap != NULL) {
+        bdrv_release_dirty_bitmap(bs, bitmap);
+    }
+
+    return NULL;
+}
+
+BdrvDirtyBitmap *qcow2_bitmap_load(BlockDriverState *bs, const char *name,
+                                   Error **errp)
+{
+    QCow2BitmapHeader *h = find_bitmap_by_name(bs, name);
+    if (h == NULL) {
+        error_setg(errp, "Could not find bitmap '%s' in the node '%s'", name,
+                   bdrv_get_device_or_node_name(bs));
+        return NULL;
+    }
+
+    return load_bitmap(bs, h, errp);
+}
diff --git a/block/qcow2.c b/block/qcow2.c
index 91ef4df..74dab08 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3423,6 +3423,8 @@  BlockDriver bdrv_qcow2 = {
     .bdrv_get_info          = qcow2_get_info,
     .bdrv_get_specific_info = qcow2_get_specific_info,
 
+    .bdrv_dirty_bitmap_load = qcow2_bitmap_load,
+
     .bdrv_save_vmstate    = qcow2_save_vmstate,
     .bdrv_load_vmstate    = qcow2_load_vmstate,
 
diff --git a/block/qcow2.h b/block/qcow2.h
index 7f6e023..573fc36 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -608,6 +608,9 @@  int qcow2_read_snapshots(BlockDriverState *bs);
 void qcow2_free_bitmaps(BlockDriverState *bs);
 int qcow2_read_bitmaps(BlockDriverState *bs, Error **errp);
 
+BdrvDirtyBitmap *qcow2_bitmap_load(BlockDriverState *bs, const char *name,
+                                   Error **errp);
+
 /* qcow2-cache.c functions */
 Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables);
 int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 1fe0fd9..2c11ad7 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -224,6 +224,10 @@  struct BlockDriver {
     int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
     ImageInfoSpecific *(*bdrv_get_specific_info)(BlockDriverState *bs);
 
+    BdrvDirtyBitmap *(*bdrv_dirty_bitmap_load)(BlockDriverState *bs,
+                                               const char *name,
+                                               Error **errp);
+
     int coroutine_fn (*bdrv_save_vmstate)(BlockDriverState *bs,
                                           QEMUIOVector *qiov,
                                           int64_t pos);