From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45571) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YKtyF-0005rS-EA for qemu-devel@nongnu.org; Mon, 09 Feb 2015 14:26:12 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YKty9-0003Wf-40 for qemu-devel@nongnu.org; Mon, 09 Feb 2015 14:26:11 -0500 Received: from mx1.redhat.com ([209.132.183.28]:33718) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YKty8-0003WL-T9 for qemu-devel@nongnu.org; Mon, 09 Feb 2015 14:26:05 -0500 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t19JQ4EH010547 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Mon, 9 Feb 2015 14:26:04 -0500 From: Max Reitz Date: Mon, 9 Feb 2015 14:25:49 -0500 Message-Id: <1423509950-7468-12-git-send-email-mreitz@redhat.com> In-Reply-To: <1423509950-7468-1-git-send-email-mreitz@redhat.com> References: <1423509950-7468-1-git-send-email-mreitz@redhat.com> Subject: [Qemu-devel] [PATCH v3 11/12] qcow2/overlaps: Protect inactive L2 tables List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Kevin Wolf , Stefan Hajnoczi , Max Reitz Keep track of the inactive L2 tables in the metadata list to protect them against accidental modifications. Signed-off-by: Max Reitz --- block/qcow2-refcount.c | 20 ++++++++++++++++++++ block/qcow2-snapshot.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 6255ed2..f092a57 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -1045,8 +1045,28 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, s->cluster_bits, addend, QCOW2_DISCARD_SNAPSHOT); if (addend < 0) { if (!l1_allocated) { + /* This is easy */ qcow2_metadata_list_remove(bs, l2_offset, 1, QCOW2_OL_ACTIVE_L2); + } else { + /* If refcount == 0, this is, too. If refcount > 1, we + * know that there must be some other inactive L2 + * reference; and for refcount == 1, if this is an + * active L2 table, this was the last inactive L2 + * reference. */ + bool remove; + if (refcount == 0) { + remove = true; + } else if (refcount == 1) { + remove = qcow2_check_metadata_overlap(bs, + ~QCOW2_OL_ACTIVE_L2, l2_offset,s->cluster_size); + } else { + remove = false; + } + if (remove) { + qcow2_metadata_list_remove(bs, l2_offset, 1, + QCOW2_OL_INACTIVE_L2); + } } } } else { diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index b3122d8..65f979e 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -46,9 +46,10 @@ int qcow2_read_snapshots(BlockDriverState *bs) QCowSnapshotHeader h; QCowSnapshotExtraData extra; QCowSnapshot *sn; - int i, id_str_size, name_size; + int i, j, id_str_size, name_size; int64_t offset; uint32_t extra_data_size; + uint64_t *l1_table; int ret; if (!s->nb_snapshots) { @@ -122,11 +123,12 @@ int qcow2_read_snapshots(BlockDriverState *bs) goto fail; } - if (!(s->overlap_check & QCOW2_OL_INACTIVE_L1)) { + if (!(s->overlap_check & (QCOW2_OL_INACTIVE_L1 | QCOW2_OL_INACTIVE_L2))) + { continue; } - if (sn->l1_size > INT_MAX / sizeof(uint64_t)) { + if (sn->l1_size > QCOW_MAX_L1_SIZE) { /* Do not fail opening the image because a snapshot is broken which * might not be used anyway */ continue; @@ -136,6 +138,34 @@ int qcow2_read_snapshots(BlockDriverState *bs) size_to_clusters(s, sn->l1_size * sizeof(uint64_t)), QCOW2_OL_INACTIVE_L1); + + if (!(s->overlap_check & QCOW2_OL_INACTIVE_L2)) { + continue; + } + + l1_table = qemu_try_blockalign(bs->file, + sn->l1_size * sizeof(uint64_t)); + if (!l1_table) { + /* Do not fail opening the image just because a snapshot's L2 tables + * cannot be covered by the overlap checks */ + continue; + } + + ret = bdrv_pread(bs->file, sn->l1_table_offset, l1_table, + sn->l1_size * sizeof(uint64_t)); + if (ret < 0) { + qemu_vfree(l1_table); + continue; + } + for (j = 0; j < sn->l1_size; j++) { + uint64_t l2_offset = be64_to_cpu(l1_table[j]) & L1E_OFFSET_MASK; + if (l2_offset) { + qcow2_metadata_list_enter(bs, l2_offset, 1, + QCOW2_OL_INACTIVE_L2); + } + } + + qemu_vfree(l1_table); } assert(offset - s->snapshots_offset <= INT_MAX); @@ -436,6 +466,13 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) sizeof(uint64_t)), QCOW2_OL_INACTIVE_L1); + for (i = 0; i < s->l1_size; i++) { + uint64_t l2_offset = s->l1_table[i] & L1E_OFFSET_MASK; + if (l2_offset) { + qcow2_metadata_list_enter(bs, l2_offset, 1, QCOW2_OL_INACTIVE_L2); + } + } + /* * Increase the refcounts of all clusters and make sure everything is * stable on disk before updating the snapshot table to contain a pointer -- 2.1.0