From patchwork Tue Mar 15 20:04:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Sementsov-Ogievskiy X-Patchwork-Id: 8592141 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 8DC179F44D for ; Tue, 15 Mar 2016 20:07:36 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C298C201DD for ; Tue, 15 Mar 2016 20:07:34 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C758F201BC for ; Tue, 15 Mar 2016 20:07:33 +0000 (UTC) Received: from localhost ([::1]:51170 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1afvFd-00039n-2y for patchwork-qemu-devel@patchwork.kernel.org; Tue, 15 Mar 2016 16:07:33 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38726) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1afvDS-0007a9-M2 for qemu-devel@nongnu.org; Tue, 15 Mar 2016 16:05:20 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1afvDR-0008G6-Ep for qemu-devel@nongnu.org; Tue, 15 Mar 2016 16:05:18 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:42628 helo=relay.sw.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1afvDQ-0008Eq-VF for qemu-devel@nongnu.org; Tue, 15 Mar 2016 16:05:17 -0400 Received: from kvm.sw.ru. ([10.28.8.145]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id u2FK4bCi005992; Tue, 15 Mar 2016 23:05:00 +0300 (MSK) From: Vladimir Sementsov-Ogievskiy To: qemu-devel@nongnu.org Date: Tue, 15 Mar 2016 23:04:14 +0300 Message-Id: <1458072268-53705-9-git-send-email-vsementsov@virtuozzo.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1458072268-53705-1-git-send-email-vsementsov@virtuozzo.com> References: <1458072268-53705-1-git-send-email-vsementsov@virtuozzo.com> X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x X-Received-From: 195.214.232.25 Cc: kwolf@redhat.com, vsementsov@virtuozzo.com, famz@redhat.com, qemu-block@nongnu.org, mreitz@redhat.com, stefanha@redhat.com, pbonzini@redhat.com, den@openvz.org, jsnow@redhat.com Subject: [Qemu-devel] [PATCH 08/22] qcow2-dirty-bitmap: read dirty bitmap directory X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Adds qcow2_read_bitmaps, reading bitmap directory as specified in docs/specs/qcow2.txt Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/qcow2-dirty-bitmap.c | 165 +++++++++++++++++++++++++++++++++++++++++++++ block/qcow2.h | 10 +++ 2 files changed, 175 insertions(+) diff --git a/block/qcow2-dirty-bitmap.c b/block/qcow2-dirty-bitmap.c index 2c749ab..e57058c 100644 --- a/block/qcow2-dirty-bitmap.c +++ b/block/qcow2-dirty-bitmap.c @@ -25,6 +25,11 @@ * THE SOFTWARE. */ +#include "qemu/osdep.h" + +#include "block/block_int.h" +#include "block/qcow2.h" + /* NOTICE: BME here means Bitmaps Extension and used as a namespace for * _internal_ constants. Please do not use this _internal_ abbreviation for * other needs and/or outside of this file. */ @@ -45,3 +50,163 @@ typedef enum BitmapType { BT_DIRTY_TRACKING_BITMAP = 1 } BitmapType; + +void qcow2_free_bitmaps(BlockDriverState *bs) +{ + BDRVQcow2State *s = bs->opaque; + int i; + + for (i = 0; i < s->nb_bitmaps; i++) { + g_free(s->bitmaps[i].name); + } + g_free(s->bitmaps); + s->bitmaps = NULL; + s->nb_bitmaps = 0; + + g_free(s->bitmap_directory); + s->bitmap_directory = NULL; +} + +static void bitmap_header_to_cpu(QCow2BitmapHeader *h) +{ + be64_to_cpus(&h->bitmap_table_offset); + be32_to_cpus(&h->bitmap_table_size); + be32_to_cpus(&h->flags); + be16_to_cpus(&h->name_size); + be32_to_cpus(&h->extra_data_size); +} + +static int calc_dir_entry_size(size_t name_size) +{ + return align_offset(sizeof(QCow2BitmapHeader) + name_size, 8); +} + +static int dir_entry_size(QCow2BitmapHeader *h) +{ + return calc_dir_entry_size(h->name_size); +} + +static int check_constraints(QCow2BitmapHeader *h, int cluster_size, + uint64_t disk_size) +{ + uint64_t phys_bitmap_bytes = + (uint64_t)h->bitmap_table_size * cluster_size; + uint64_t max_virtual_bits = (phys_bitmap_bytes * 8) << h->granularity_bits; + + int fail = + (h->bitmap_table_offset % cluster_size) || + (h->bitmap_table_size > BME_MAX_TABLE_SIZE) || + (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) || + (disk_size > max_virtual_bits) || + (h->granularity_bits > BME_MAX_GRANULARITY_BITS) || + (h->granularity_bits < BME_MIN_GRANULARITY_BITS) || + (h->flags & BME_RESERVED_FLAGS) || + (h->name_size > BME_MAX_NAME_SIZE) || + (h->type != BT_DIRTY_TRACKING_BITMAP); + + return fail ? -EINVAL : 0; +} + +static int directory_read(BlockDriverState *bs, Error **errp) +{ + int ret; + BDRVQcow2State *s = bs->opaque; + QCow2Bitmap *bm, *end; + int64_t nb_sectors = bdrv_nb_sectors(bs); + size_t offset; + + if (nb_sectors < 0) { + error_setg(errp, "Can't calculate number of disk sectors."); + return nb_sectors; + } + + if (s->bitmap_directory != NULL) { + /* already read */ + error_setg(errp, "Try read bitmaps, when they are already read."); + return -EEXIST; + } + + s->bitmap_directory = g_try_malloc0(s->bitmap_directory_size); + if (s->bitmap_directory == NULL) { + error_setg(errp, "Can't allocate space for bitmap directory."); + return -ENOMEM; + } + + ret = bdrv_pread(bs->file->bs, + s->bitmap_directory_offset, + s->bitmap_directory, + s->bitmap_directory_size); + if (ret < 0) { + error_setg(errp, "Can't read bitmap directory."); + goto fail; + } + + offset = 0; + end = s->bitmaps + s->nb_bitmaps; + for (bm = s->bitmaps; bm < end; ++bm) { + QCow2BitmapHeader *h = + (QCow2BitmapHeader *)(s->bitmap_directory + offset); + + if (offset >= s->bitmap_directory_size) { + error_setg(errp, "Broken bitmap directory."); + goto fail; + } + + bitmap_header_to_cpu(h); + + ret = check_constraints(h, s->cluster_size, + nb_sectors << BDRV_SECTOR_BITS); + if (ret < 0) { + error_setg(errp, "Bitmap doesn't satisfy the constraints."); + goto fail; + } + + bm->offset = offset; + bm->name = g_strndup((char *)(h + 1), h->name_size); + + offset += dir_entry_size(h); + } + return 0; + +fail: + g_free(s->bitmap_directory); + s->bitmap_directory = NULL; + + return ret; +} + +int qcow2_read_bitmaps(BlockDriverState *bs, Error **errp) +{ + int ret; + BDRVQcow2State *s = bs->opaque; + + if (s->bitmap_directory != NULL || s->bitmaps != NULL) { + /* already read */ + error_setg(errp, "Try read bitmaps, when they are already read."); + return -EEXIST; + } + + if (s->nb_bitmaps == 0) { + /* No bitmaps - nothing to do */ + return 0; + } + + s->bitmaps = g_try_new0(QCow2Bitmap, s->nb_bitmaps); + if (s->bitmaps == NULL) { + error_setg(errp, "Can't allocate space for qcow2 bitmaps."); + ret = -ENOMEM; + goto fail; + } + + ret = directory_read(bs, errp); + if (ret < 0) { + goto fail; + } + + return 0; + +fail: + qcow2_free_bitmaps(bs); + + return ret; +} diff --git a/block/qcow2.h b/block/qcow2.h index 3f7429e..48fb2a5 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -297,6 +297,12 @@ typedef struct BDRVQcow2State { unsigned int nb_snapshots; QCowSnapshot *snapshots; + uint64_t bitmap_directory_offset; + uint64_t bitmap_directory_size; + uint8_t *bitmap_directory; + unsigned int nb_bitmaps; + QCow2Bitmap *bitmaps; + int flags; int qcow_version; bool use_lazy_refcounts; @@ -610,6 +616,10 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, void qcow2_free_snapshots(BlockDriverState *bs); int qcow2_read_snapshots(BlockDriverState *bs); +/* qcow2-dirty-bitmap.c functions */ +void qcow2_free_bitmaps(BlockDriverState *bs); +int qcow2_read_bitmaps(BlockDriverState *bs, Error **errp); + /* qcow2-cache.c functions */ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables); int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c);