From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:42497) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bWm7V-00071P-E8 for qemu-devel@nongnu.org; Mon, 08 Aug 2016 11:05:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bWm7Q-0004TC-8b for qemu-devel@nongnu.org; Mon, 08 Aug 2016 11:05:37 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:44374 helo=relay.sw.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bWm7P-0004PH-GL for qemu-devel@nongnu.org; Mon, 08 Aug 2016 11:05:32 -0400 From: Vladimir Sementsov-Ogievskiy Date: Mon, 8 Aug 2016 18:04:58 +0300 Message-Id: <1470668720-211300-8-git-send-email-vsementsov@virtuozzo.com> In-Reply-To: <1470668720-211300-1-git-send-email-vsementsov@virtuozzo.com> References: <1470668720-211300-1-git-send-email-vsementsov@virtuozzo.com> Subject: [Qemu-devel] [PATCH 07/29] qcow2-bitmap: add qcow2_bitmap_load() List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-block@nongnu.org, qemu-devel@nongnu.org Cc: kwolf@redhat.com, mreitz@redhat.com, armbru@redhat.com, eblake@redhat.com, jsnow@redhat.com, famz@redhat.com, den@openvz.org, stefanha@redhat.com, vsementsov@virtuozzo.com, pbonzini@redhat.com This function loads block dirty bitmap from qcow2. Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/qcow2-bitmap.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 2 + block/qcow2.h | 3 + include/block/block_int.h | 4 ++ 4 files changed, 174 insertions(+) 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); -- 1.8.3.1