From nobody Mon Feb 9 01:31:12 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1513344055691269.2655571432497; Fri, 15 Dec 2017 05:20:55 -0800 (PST) Received: from localhost ([::1]:46307 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ePpuz-00076A-Oc for importer@patchew.org; Fri, 15 Dec 2017 08:20:49 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55572) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ePpVI-0000X9-7T for qemu-devel@nongnu.org; Fri, 15 Dec 2017 07:54:21 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ePpVC-0003JZ-U3 for qemu-devel@nongnu.org; Fri, 15 Dec 2017 07:54:16 -0500 Received: from fanzine.igalia.com ([91.117.99.155]:48103) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ePpVA-0003CP-UM; Fri, 15 Dec 2017 07:54:10 -0500 Received: from [192.168.12.179] (helo=perseus.local) by fanzine.igalia.com with esmtpsa (Cipher TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim) id 1ePpV8-00084p-78; Fri, 15 Dec 2017 13:54:06 +0100 Received: from berto by perseus.local with local (Exim 4.89) (envelope-from ) id 1ePpV8-0004Dz-2s; Fri, 15 Dec 2017 14:54:06 +0200 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=References:In-Reply-To:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=KOuG6P+9ZqSK4YpZtPhsle6zxVA8JP7YMARjW8b1dQk=; b=BuUwjzQZx4hfC8tnu4D7LeaJl97xRP6iYsLBEBnojcibe+rOV3TVDf5I7xi1GgZOWr4ejWq5yE6prqwdx4RcgW41GL9UcGn2QWhi7xdFAMlnGzYgXH9GdK4ZOZ9ssKFLiVZE9rtQQnCGGSBcE1riHycov96DGJqG9Pw74dK71ww0bxhfmOuyh4GZg5MGTH88MyMHick7LEVEjT2R5msM2Nsa6bICZORxJEuMG60npjiMqV/io2RP+UCQedqVql4sAtEgbOgGalfWkQLScFLi4NRezuILhhybWmIdBPfdKadkidUsv6A16z6/RESbr1achLcGtc2dJp1q5jmOyjesBA==; From: Alberto Garcia To: qemu-devel@nongnu.org Date: Fri, 15 Dec 2017 13:53:53 +0100 Message-Id: <1fb1816d471d712f2001ca3ce42c6682273c7daf.1513342045.git.berto@igalia.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (no timestamps) [generic] [fuzzy] X-Received-From: 91.117.99.155 Subject: [Qemu-devel] [PATCH v2 25/32] qcow2: Update expand_zero_clusters_in_l1() to support L2 slices X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , "Denis V . Lunev" , Alberto Garcia , qemu-block@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" expand_zero_clusters_in_l1() expands zero clusters as a necessary step to downgrade qcow2 images to a version that doesn't support metadata zero clusters. This function takes an L1 table (which may or may not be active) and iterates over all its L2 tables looking for zero clusters. Since we'll be loading L2 slices instead of full tables we need to add an extra loop that iterates over all slices of each L2 table, and we should also use the slice size when allocating the buffer used when the L1 table is not active. As a consequence of the new loop the refcount data also needs to be loaded before the L2 data, but this is a trivial change with no side effects. This function doesn't need any additional changes so apart from that this patch simply updates the variable name from l2_table to l2_slice. Signed-off-by: Alberto Garcia --- block/qcow2-cluster.c | 207 +++++++++++++++++++++++++++-------------------= ---- 1 file changed, 110 insertions(+), 97 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 8f7a04ba7d..ab840a449f 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -1872,15 +1872,19 @@ static int expand_zero_clusters_in_l1(BlockDriverSt= ate *bs, uint64_t *l1_table, { BDRVQcow2State *s =3D bs->opaque; bool is_active_l1 =3D (l1_table =3D=3D s->l1_table); - uint64_t *l2_table =3D NULL; + uint64_t *l2_slice =3D NULL; + unsigned slice, slice_size, n_slices; int ret; int i, j; =20 + slice_size =3D s->l2_slice_size * sizeof(uint64_t); + n_slices =3D s->cluster_size / slice_size; + if (!is_active_l1) { /* inactive L2 tables require a buffer to be stored in when loading * them from disk */ - l2_table =3D qemu_try_blockalign(bs->file->bs, s->cluster_size); - if (l2_table =3D=3D NULL) { + l2_slice =3D qemu_try_blockalign(bs->file->bs, slice_size); + if (l2_slice =3D=3D NULL) { return -ENOMEM; } } @@ -1907,124 +1911,133 @@ static int expand_zero_clusters_in_l1(BlockDriver= State *bs, uint64_t *l1_table, goto fail; } =20 - if (is_active_l1) { - /* get active L2 tables from cache */ - ret =3D qcow2_cache_get(bs, s->l2_table_cache, l2_offset, - (void **)&l2_table); - } else { - /* load inactive L2 tables from disk */ - ret =3D bdrv_read(bs->file, l2_offset / BDRV_SECTOR_SIZE, - (void *)l2_table, s->cluster_sectors); - } - if (ret < 0) { - goto fail; - } - ret =3D qcow2_get_refcount(bs, l2_offset >> s->cluster_bits, &l2_refcount); if (ret < 0) { goto fail; } =20 - for (j =3D 0; j < s->l2_size; j++) { - uint64_t l2_entry =3D be64_to_cpu(l2_table[j]); - int64_t offset =3D l2_entry & L2E_OFFSET_MASK; - QCow2ClusterType cluster_type =3D qcow2_get_cluster_type(l2_en= try); - - if (cluster_type !=3D QCOW2_CLUSTER_ZERO_PLAIN && - cluster_type !=3D QCOW2_CLUSTER_ZERO_ALLOC) { - continue; + for (slice =3D 0; slice < n_slices; slice++) { + uint64_t slice_offset =3D l2_offset + slice * slice_size; + if (is_active_l1) { + /* get active L2 tables from cache */ + ret =3D qcow2_cache_get(bs, s->l2_table_cache, slice_offse= t, + (void **)&l2_slice); + } else { + /* load inactive L2 tables from disk */ + ret =3D bdrv_read(bs->file, slice_offset >> BDRV_SECTOR_BI= TS, + (void *)l2_slice, + slice_size >> BDRV_SECTOR_BITS); + } + if (ret < 0) { + goto fail; } =20 - if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { - if (!bs->backing) { - /* not backed; therefore we can simply deallocate the - * cluster */ - l2_table[j] =3D 0; - l2_dirty =3D true; + for (j =3D 0; j < s->l2_slice_size; j++) { + uint64_t l2_entry =3D be64_to_cpu(l2_slice[j]); + int64_t offset =3D l2_entry & L2E_OFFSET_MASK; + QCow2ClusterType cluster_type =3D + qcow2_get_cluster_type(l2_entry); + + if (cluster_type !=3D QCOW2_CLUSTER_ZERO_PLAIN && + cluster_type !=3D QCOW2_CLUSTER_ZERO_ALLOC) { continue; } =20 - offset =3D qcow2_alloc_clusters(bs, s->cluster_size); - if (offset < 0) { - ret =3D offset; - goto fail; - } + if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { + if (!bs->backing) { + /* not backed; therefore we can simply deallocate = the + * cluster */ + l2_slice[j] =3D 0; + l2_dirty =3D true; + continue; + } =20 - if (l2_refcount > 1) { - /* For shared L2 tables, set the refcount accordingly = (it is - * already 1 and needs to be l2_refcount) */ - ret =3D qcow2_update_cluster_refcount(bs, - offset >> s->cluster_bits, + offset =3D qcow2_alloc_clusters(bs, s->cluster_size); + if (offset < 0) { + ret =3D offset; + goto fail; + } + + if (l2_refcount > 1) { + /* For shared L2 tables, set the refcount accordin= gly + * (it is already 1 and needs to be l2_refcount) */ + ret =3D qcow2_update_cluster_refcount( + bs, offset >> s->cluster_bits, refcount_diff(1, l2_refcount), false, QCOW2_DISCARD_OTHER); - if (ret < 0) { + if (ret < 0) { + qcow2_free_clusters(bs, offset, s->cluster_siz= e, + QCOW2_DISCARD_OTHER); + goto fail; + } + } + } + + if (offset_into_cluster(s, offset)) { + int l2_index =3D slice * s->l2_slice_size + j; + qcow2_signal_corruption( + bs, true, -1, -1, + "Cluster allocation offset " + "%#" PRIx64 " unaligned (L2 offset: %#" + PRIx64 ", L2 index: %#x)", offset, + l2_offset, l2_index); + if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { qcow2_free_clusters(bs, offset, s->cluster_size, - QCOW2_DISCARD_OTHER); - goto fail; + QCOW2_DISCARD_ALWAYS); } + ret =3D -EIO; + goto fail; } - } =20 - if (offset_into_cluster(s, offset)) { - qcow2_signal_corruption(bs, true, -1, -1, - "Cluster allocation offset " - "%#" PRIx64 " unaligned (L2 offset= : %#" - PRIx64 ", L2 index: %#x)", offset, - l2_offset, j); - if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { - qcow2_free_clusters(bs, offset, s->cluster_size, - QCOW2_DISCARD_ALWAYS); + ret =3D qcow2_pre_write_overlap_check(bs, 0, offset, + s->cluster_size); + if (ret < 0) { + if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { + qcow2_free_clusters(bs, offset, s->cluster_size, + QCOW2_DISCARD_ALWAYS); + } + goto fail; } - ret =3D -EIO; - goto fail; - } =20 - ret =3D qcow2_pre_write_overlap_check(bs, 0, offset, s->cluste= r_size); - if (ret < 0) { - if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { - qcow2_free_clusters(bs, offset, s->cluster_size, - QCOW2_DISCARD_ALWAYS); + ret =3D bdrv_pwrite_zeroes(bs->file, offset, s->cluster_si= ze, 0); + if (ret < 0) { + if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { + qcow2_free_clusters(bs, offset, s->cluster_size, + QCOW2_DISCARD_ALWAYS); + } + goto fail; } - goto fail; - } =20 - ret =3D bdrv_pwrite_zeroes(bs->file, offset, s->cluster_size, = 0); - if (ret < 0) { - if (cluster_type =3D=3D QCOW2_CLUSTER_ZERO_PLAIN) { - qcow2_free_clusters(bs, offset, s->cluster_size, - QCOW2_DISCARD_ALWAYS); + if (l2_refcount =3D=3D 1) { + l2_slice[j] =3D cpu_to_be64(offset | QCOW_OFLAG_COPIED= ); + } else { + l2_slice[j] =3D cpu_to_be64(offset); } - goto fail; + l2_dirty =3D true; } =20 - if (l2_refcount =3D=3D 1) { - l2_table[j] =3D cpu_to_be64(offset | QCOW_OFLAG_COPIED); + if (is_active_l1) { + if (l2_dirty) { + qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_sli= ce); + qcow2_cache_depends_on_flush(s->l2_table_cache); + } + qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); } else { - l2_table[j] =3D cpu_to_be64(offset); - } - l2_dirty =3D true; - } + if (l2_dirty) { + ret =3D qcow2_pre_write_overlap_check( + bs, QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, + slice_offset, slice_size); + if (ret < 0) { + goto fail; + } =20 - if (is_active_l1) { - if (l2_dirty) { - qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table); - qcow2_cache_depends_on_flush(s->l2_table_cache); - } - qcow2_cache_put(s->l2_table_cache, (void **) &l2_table); - } else { - if (l2_dirty) { - ret =3D qcow2_pre_write_overlap_check(bs, - QCOW2_OL_INACTIVE_L2 | QCOW2_OL_ACTIVE_L2, l2_offs= et, - s->cluster_size); - if (ret < 0) { - goto fail; - } - - ret =3D bdrv_write(bs->file, l2_offset / BDRV_SECTOR_SIZE, - (void *)l2_table, s->cluster_sectors); - if (ret < 0) { - goto fail; + ret =3D bdrv_write(bs->file, slice_offset >> BDRV_SECT= OR_BITS, + (void *)l2_slice, + slice_size >> BDRV_SECTOR_BITS); + if (ret < 0) { + goto fail; + } } } } @@ -2038,11 +2051,11 @@ static int expand_zero_clusters_in_l1(BlockDriverSt= ate *bs, uint64_t *l1_table, ret =3D 0; =20 fail: - if (l2_table) { + if (l2_slice) { if (!is_active_l1) { - qemu_vfree(l2_table); + qemu_vfree(l2_slice); } else { - qcow2_cache_put(s->l2_table_cache, (void **) &l2_table); + qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice); } } return ret; --=20 2.11.0