From nobody Mon Feb 9 19:54:25 2026 Delivered-To: importer@patchew.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 1505738687702246.46221464275345; Mon, 18 Sep 2017 05:44:47 -0700 (PDT) Received: from localhost ([::1]:36371 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dtvPq-0004X0-Qu for importer@patchew.org; Mon, 18 Sep 2017 08:44:46 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33419) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dtvO8-0003Lt-IR for qemu-devel@nongnu.org; Mon, 18 Sep 2017 08:43:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dtvO6-0003QC-K8 for qemu-devel@nongnu.org; Mon, 18 Sep 2017 08:43:00 -0400 Received: from mail-eopbgr00136.outbound.protection.outlook.com ([40.107.0.136]:6071 helo=EUR02-AM5-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dtvO0-0003Gr-QF; Mon, 18 Sep 2017 08:42:52 -0400 Received: from pavelb-Z68P-DS3.sw.ru (195.214.232.6) by DB6PR0802MB2549.eurprd08.prod.outlook.com (2603:10a6:4:a1::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.35.12; Mon, 18 Sep 2017 12:42:49 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=virtuozzo.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=DtN/Qdp6uLD70Mzgir2z3/0qnWBdX67Wyt2KuUAZ288=; b=MU+LWuec6cDncpbuDDwvdgLbMkwB7dS/nSOl6UcEeITWPkEAb0V4dz+Q+sIflrK4peokmfSDOVR5dL4Jxx9MX2yFW3o+nZG1mUJrUu4/176h5Jjw6xfmlX2+Ogg6I4W8Xjipf7tGp30prz3zIDcAI/eGON2w/nOjxivDy+ySPFM= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=pbutsykin@virtuozzo.com; From: Pavel Butsykin To: qemu-block@nongnu.org, qemu-devel@nongnu.org Date: Mon, 18 Sep 2017 15:42:29 +0300 Message-Id: <20170918124230.8152-4-pbutsykin@virtuozzo.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170918124230.8152-1-pbutsykin@virtuozzo.com> References: <20170918124230.8152-1-pbutsykin@virtuozzo.com> MIME-Version: 1.0 X-Originating-IP: [195.214.232.6] X-ClientProxiedBy: DB6PR0202CA0006.eurprd02.prod.outlook.com (2603:10a6:4:29::16) To DB6PR0802MB2549.eurprd08.prod.outlook.com (2603:10a6:4:a1::19) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: d73d0d8b-0589-4864-6ff2-08d4fe92c5e3 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(300000500095)(300135000095)(300000501095)(300135300095)(22001)(300000502095)(300135100095)(2017030254152)(300000503095)(300135400095)(201703131423075)(201703031133081)(201702281549075)(300000504095)(300135200095)(300000505095)(300135600095)(300000506095)(300135500095); SRVR:DB6PR0802MB2549; X-Microsoft-Exchange-Diagnostics: 1; DB6PR0802MB2549; 3:N2Ctqqr4ApmE68j08jf7zdvixBfJ+v0AGgdOV/YChkvAnjMb9JB3k8A8tBHuT1/zyRd+Pc0OnPUTL+YW9V620GkWp3b7IvjnaDIk5v9i8i9sCY74HJvSGUq+L/lmIZC5K8fXzs3OynJIkkmlq6zadD/An82l0kO8a8l3ZnSzEKXNHbSN50bXvBoW5LFf3NtZ2DgvJ0VkYXaeDgTP8qdR6jNNJIfIRMXHFG7hujVTPAEumBeyhNR5LdzDueJDRzz7; 25:Xp31bMkZq7i6/hZRncq16IwovMel6ScG8ce0Cg0Ur66J5UFJ5XugMZMeZ7iI9GcrxaMwJfe5oZOHX/1k7JqNxE8D2JOGr7GQVZtRORlYH562O6i1NctiGFTUbUiH6Tw4pvrfjylJgN3Mmey1kCe07IjXt9QpekZzRDH0/Xn2wO/2yybnt/hKsAf6z84Rkj/sPar57hWUnDfLEuxdYV+Vq9DffPGfMruJbg6P8gm9nZn0FilWdk7uWYC7+3NHNktywRiNwvPx0+xxThg6cXgwDQ8622Id/5u2zknwet/IpiPi/uzf+Fl09lAQwQFQEshwGY0OClp6RW1DHU7xkEV0lw==; 31:U+81mxTBx1rtLT5EAeJaZCiS6kLXcf13/ESQnGtVosYFoIgvPOBPhOwPunbP2hW0ryU7HCFZfy7slRQqEYakrgnncFTzGkd4pKwG6DvNQi0ljrxYN8XBNEFgeSAoAFBDo+neB/WyeuoWzrGmhTFrBZpTqMRFWKtlvixAB06mtx4mWm1im0quGVLUc2woJEOl3E75v0mMck4+5iU9sX9CuupJv4H3ceq2lzI9xD4l/Sc= X-MS-TrafficTypeDiagnostic: DB6PR0802MB2549: X-Microsoft-Exchange-Diagnostics: 1; DB6PR0802MB2549; 20:KqzkmCpe7p31lY/3PQMxjdS70pEjvTrluQ0EuPokJgMch5EftOPuxrogk+JBgOKIhjNVvkSTmnX1n5fUx4K//QIyBWinJcG15+6xBbkQmbOKtdsVqyxk+oZP+wBNQKkaf0OPwnXjhGW76b4UVAO5nMwNOxKKKnPMzC6gkJM4tJs4l7zRy5Kz2NcwD/rCejf1UZRdRSCsmdmKWIIA7oSwHmjibJgMADWoJ263PlTL3ivI7/GT/28m8nIylj3dB+5dzjcuCiQLtnrUyQogpK0tzCUbJtE1For1AcHUI9PSp8nrXne6sVaK1EXchsHcU4tic6OtH1oijwZVtyM22V4gsOk2cQMQqpEBwU0+Z6LVRwM5WMQ9myZEJYDrrE3ZyQEexovdNEtKGgUn6DgVeOHCR96OWp8D680MhUqj1s8okJc=; 4:NTUf08AK/B0Yvv5yI3L9wJlEbDxZU+eNz1smfkl5QrUfkfo4kGR1e7rOLdt6VGCMbnMTX94zCAl9Bha6W2YukpRbEZnWBkMF/h6AaJ0ArdS36euE7nsNrlJE7fhzb/NL+cWp+Qq56leBgy315/vNV49U4DScH4nnl25A/ViP7ULMAZ6DgTpQX+/9gJmRYrhtfJu48zMPCXlq+1lOc5jyDd/w0pvYziDqdlMRhx/lgZXUyIDbNVVqxzZjaKwJLARk X-Exchange-Antispam-Report-Test: UriScan:; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(5005006)(8121501046)(3002001)(10201501046)(93006095)(93001095)(100000703101)(100105400095)(6041248)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123562025)(20161123558100)(20161123564025)(20161123555025)(20161123560025)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095); SRVR:DB6PR0802MB2549; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:DB6PR0802MB2549; X-Forefront-PRVS: 04347F8039 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(7370300001)(4630300001)(6009001)(346002)(376002)(39830400002)(199003)(189002)(36756003)(48376002)(105586002)(50466002)(107886003)(101416001)(110136004)(53416004)(50226002)(25786009)(305945005)(7736002)(53936002)(81156014)(4326008)(81166006)(6666003)(5003940100001)(68736007)(2906002)(8676002)(6506006)(3846002)(86362001)(478600001)(6486002)(6512007)(1076002)(6116002)(50986999)(76176999)(47776003)(2950100002)(33646002)(575784001)(16586007)(7350300001)(97736004)(16526017)(106356001)(316002)(5660300001)(66066001)(69596002)(189998001); DIR:OUT; SFP:1102; SCL:1; SRVR:DB6PR0802MB2549; H:pavelb-Z68P-DS3.sw.ru; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; 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; Received-SPF: None (protection.outlook.com: virtuozzo.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; DB6PR0802MB2549; 23:L6Lws0PTAAXnzVbIJ2Xf3J+rau6dN9s7+oDMSFZ?= =?us-ascii?Q?jJyqvQqvcXBtxSzae/hgy3lqyfbv/gzIpJvGm0jJo+AtcHKDkXo4x7R42qjw?= =?us-ascii?Q?w1xA3XRz+71CYqay82DwzE6c3bx+XO+sgqcKXxJhfLU+dTr4SKcEJm76jcp3?= =?us-ascii?Q?mK6Nkhdmo9qeA0FCgCKBPiacs4YR+qFaBtPtSiwlftHxeCZ81QfczWm6yheX?= =?us-ascii?Q?B+XoA4HYbtcD46a+51sHpkMMrnV4N4+4Q6A2cp9jKBZAs4ClnMFbHA1CoS8Z?= =?us-ascii?Q?lY3Sc3smZYzHjLP1HbPZKOPxuafccJZNFQIDV0HlE36Mw2W/qRlU5P6c8sP3?= =?us-ascii?Q?bGvlBUfG2aX5z6WC8eF8Bm+Y45uHt1cnmGXkL1rKgV6eFT9Ns9W/uqayqQrc?= =?us-ascii?Q?F/3bAk5fwLyFsBA4RnaibWCI0VnzYHCI/epLaygoGiPKu1EmkA5t7H5Zdccv?= =?us-ascii?Q?U6h7xjTcVcKLzOJYzezwcElXc/r80JKiekeF+euY9aAaiFDNYVfG0iDSNbN6?= =?us-ascii?Q?Ob+zUxBuIVwC0AT5601x2GojRBVnD5XgVGMybBhSuGx5QBN91L8jogu7kC6J?= =?us-ascii?Q?cj6XpMMdyKL+S/7Go5rgymg6bowTF2EmI0Dmpu0VV29RLnjhlJBR8St+NV2Y?= =?us-ascii?Q?9WFlBedaNg3Zi7OrfvAO8Wwy0MktLfo1lCYfVc+/PPphHQ8tKD1AMyK0LNlV?= =?us-ascii?Q?Rt0FDvDrrnS/pl48QbldCuWs1H21JPucqBKnMIfeXa0Mx7vFSmIY65UB0BzP?= =?us-ascii?Q?u99LAiUneCyYejCvDJNkeKShcZyUzE/KRLf+eI1Hix+1s784aMW2spD+V/Mj?= =?us-ascii?Q?4oSNeRQOfihCNv04fvtzXcfVUTsG0qEFMfc3CyzJUxruK3HEVMKMpBzIXAWv?= =?us-ascii?Q?8dtUP5Rt7k7qwZR6gzP1JVlkGPxjr40a3X/8weVkIpyF+s4Fxi2BrncYY4Dv?= =?us-ascii?Q?K0uDMeaOmlBRiA1mAjKBSC0ZMFsxT+VAIewV9mFwJq4orepHsv1q8NPmC7yS?= =?us-ascii?Q?9tWlKIKlFwIUVhhd8XJajQ7tTL2K8MfiG8dVYuiyLUSsonI+1yZPXTx+L6UP?= =?us-ascii?Q?nxuqihlh4Cekoj4a0OjUIV01gA4GAZlrWqp/njdkyJMFuDLIgWH4aajYvy4z?= =?us-ascii?Q?uWvmn1BSdIsiFKBTZ2PR5/tcZki1xl8RZcvyOO16JmmSQS4z9KpTFApHN6fd?= =?us-ascii?Q?rnt7HiVwQ2TEieOtvVZW/vWzYz7xTHs81JJsDNadezJFG+LbLk2YXV2peviI?= =?us-ascii?Q?JWBXtR/s+DHx33yDU1Wl5Xgq8QCxGjU55F8bwSDiV?= X-Microsoft-Exchange-Diagnostics: 1; DB6PR0802MB2549; 6:SlHNJqo8M6dLMC50MvIGu2R8MDbID933/xdL9XF7zVzazCt/4qKct7YAT4rPObWBU65Dkz6qqxzSrPZN+VwwwqJ2oi0Jdgsjh094Zsms+/R0hlJCg34b/oac2d8EhPW44zyU2667++e0PxKDm2ZPDsZAIiPFi2ygMFqzQWADV9DsCfd9poTJxwNska6Sk43ra7WMzX4phIQa/jBNPuN5NTcBdGoLDg6USDVxhce5pLIIeEMPHfIFkoSh906N5OkCrN6mzS7jrPqDsTfAPTFn49W6sC6QDjHVdnp3cI2sWS+XU0gxnXwVN2WTXGg3eFuxX4nhZv9QhIoakgPejEWS9g==; 5:nQwwf3cUwXavWnrYLRnV5Pwr+8dNlMPrH+WnuyNndQXoGVySx06jTxlOpSkGpZytqM/fsmr9sj6UUZUfjgwNvWn6kcE4V/AaIunz4S8GQgGLbnAUjxxNnY02Y/5W76k2AKvhREcn8KIVSm6y63n+7g==; 24:yykRWY5tWAgOQTc8PtX6BsaJxqd5wX8prsluIVBX9WpR6kd7y6t/WSmSbVBu5lCB4sZ7C3nuUcPORLsaq+Q5JARTufbDDuU5pNn85OQwtiA=; 7:01CHTZPcoQyNeOHFckh4njb8h1VTCqGK6MS9Es3L205cpKhn2Fc+IglkB0r1aJeHP1NjEuTdnWn9Uv9u10wkcvdY8qD2RYzYIHWlqg40mstrpVwjwsMNrHNSmutA2pG8Cqkdfg9M3OBCUVyUmWtBtoT92Adni6IH/hx4/5ttMpJxSfcXf/39Dbg4y/3LLf7zb30veyLkUiYVjf3Gga2i/0VNZAlFewdnCLhnzoEkNjY= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; DB6PR0802MB2549; 20:qhxo6Meoku3xSYQ3J4Dr6CxuaeDM4GSrBForhCmqZNLB4qr6Oa9Fl3Xnk9S3lqdmf3CQ+LTPJee+HG700fD915T0yFyyGA0kM8rJqHw9D+/vKBBoO4FZV1c5COA4zMXMueFWhqHbKzdobYSSLAgo3XvQ2SYAwTIipg9szDfkz3E= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Sep 2017 12:42:49.6967 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB6PR0802MB2549 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 40.107.0.136 Subject: [Qemu-devel] [PATCH v8 3/4] qcow2: add shrink image support 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: kwolf@redhat.com, pbutsykin@virtuozzo.com, jsnow@redhat.com, armbru@redhat.com, mreitz@redhat.com, den@openvz.org 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 Content-Type: text/plain; charset="utf-8" This patch add shrinking of the image file for qcow2. As a result, this all= ows us to reduce the virtual image size and free up space on the disk without copying the image. Image can be fragmented and shrink is done by punching h= oles in the image file. Signed-off-by: Pavel Butsykin Reviewed-by: Max Reitz Reviewed-by: John Snow --- block/qcow2-cluster.c | 50 +++++++++++++++++++++ block/qcow2-refcount.c | 120 +++++++++++++++++++++++++++++++++++++++++++++= ++++ block/qcow2.c | 43 ++++++++++++++---- block/qcow2.h | 14 ++++++ qapi/block-core.json | 8 +++- 5 files changed, 225 insertions(+), 10 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 0d4824993c..d2518d1893 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -32,6 +32,56 @@ #include "qemu/bswap.h" #include "trace.h" =20 +int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t exact_size) +{ + BDRVQcow2State *s =3D bs->opaque; + int new_l1_size, i, ret; + + if (exact_size >=3D s->l1_size) { + return 0; + } + + new_l1_size =3D exact_size; + +#ifdef DEBUG_ALLOC2 + fprintf(stderr, "shrink l1_table from %d to %d\n", s->l1_size, new_l1_= size); +#endif + + BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE); + ret =3D bdrv_pwrite_zeroes(bs->file, s->l1_table_offset + + new_l1_size * sizeof(uint64_t), + (s->l1_size - new_l1_size) * sizeof(uint64_t)= , 0); + if (ret < 0) { + goto fail; + } + + ret =3D bdrv_flush(bs->file->bs); + if (ret < 0) { + goto fail; + } + + BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_FREE_L2_CLUSTERS); + for (i =3D s->l1_size - 1; i > new_l1_size - 1; i--) { + if ((s->l1_table[i] & L1E_OFFSET_MASK) =3D=3D 0) { + continue; + } + qcow2_free_clusters(bs, s->l1_table[i] & L1E_OFFSET_MASK, + s->cluster_size, QCOW2_DISCARD_ALWAYS); + s->l1_table[i] =3D 0; + } + return 0; + +fail: + /* + * If the write in the l1_table failed the image may contain a partial= ly + * overwritten l1_table. In this case it would be better to clear the + * l1_table in memory to avoid possible image corruption. + */ + memset(s->l1_table + new_l1_size, 0, + (s->l1_size - new_l1_size) * sizeof(uint64_t)); + return ret; +} + int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size) { diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 8c17c0e3aa..88d5a3f1ad 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -29,6 +29,7 @@ #include "block/qcow2.h" #include "qemu/range.h" #include "qemu/bswap.h" +#include "qemu/cutils.h" =20 static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size); static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, @@ -3061,3 +3062,122 @@ done: qemu_vfree(new_refblock); return ret; } + +static int qcow2_discard_refcount_block(BlockDriverState *bs, + uint64_t discard_block_offs) +{ + BDRVQcow2State *s =3D bs->opaque; + uint64_t refblock_offs =3D get_refblock_offset(s, discard_block_offs); + uint64_t cluster_index =3D discard_block_offs >> s->cluster_bits; + uint32_t block_index =3D cluster_index & (s->refcount_block_size - 1); + void *refblock; + int ret; + + assert(discard_block_offs !=3D 0); + + ret =3D qcow2_cache_get(bs, s->refcount_block_cache, refblock_offs, + &refblock); + if (ret < 0) { + return ret; + } + + if (s->get_refcount(refblock, block_index) !=3D 1) { + qcow2_signal_corruption(bs, true, -1, -1, "Invalid refcount:" + " refblock offset %#" PRIx64 + ", reftable index %u" + ", block offset %#" PRIx64 + ", refcount %#" PRIx64, + refblock_offs, + offset_to_reftable_index(s, discard_block_= offs), + discard_block_offs, + s->get_refcount(refblock, block_index)); + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); + return -EINVAL; + } + s->set_refcount(refblock, block_index, 0); + + qcow2_cache_entry_mark_dirty(bs, s->refcount_block_cache, refblock); + + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); + + if (cluster_index < s->free_cluster_index) { + s->free_cluster_index =3D cluster_index; + } + + refblock =3D qcow2_cache_is_table_offset(bs, s->refcount_block_cache, + discard_block_offs); + if (refblock) { + /* discard refblock from the cache if refblock is cached */ + qcow2_cache_discard(bs, s->refcount_block_cache, refblock); + } + update_refcount_discard(bs, discard_block_offs, s->cluster_size); + + return 0; +} + +int qcow2_shrink_reftable(BlockDriverState *bs) +{ + BDRVQcow2State *s =3D bs->opaque; + uint64_t *reftable_tmp =3D + g_malloc(s->refcount_table_size * sizeof(uint64_t)); + int i, ret; + + for (i =3D 0; i < s->refcount_table_size; i++) { + int64_t refblock_offs =3D s->refcount_table[i] & REFT_OFFSET_MASK; + void *refblock; + bool unused_block; + + if (refblock_offs =3D=3D 0) { + reftable_tmp[i] =3D 0; + continue; + } + ret =3D qcow2_cache_get(bs, s->refcount_block_cache, refblock_offs, + &refblock); + if (ret < 0) { + goto out; + } + + /* the refblock has own reference */ + if (i =3D=3D offset_to_reftable_index(s, refblock_offs)) { + uint64_t block_index =3D (refblock_offs >> s->cluster_bits) & + (s->refcount_block_size - 1); + uint64_t refcount =3D s->get_refcount(refblock, block_index); + + s->set_refcount(refblock, block_index, 0); + + unused_block =3D buffer_is_zero(refblock, s->cluster_size); + + s->set_refcount(refblock, block_index, refcount); + } else { + unused_block =3D buffer_is_zero(refblock, s->cluster_size); + } + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); + + reftable_tmp[i] =3D unused_block ? 0 : cpu_to_be64(s->refcount_tab= le[i]); + } + + ret =3D bdrv_pwrite_sync(bs->file, s->refcount_table_offset, reftable_= tmp, + s->refcount_table_size * sizeof(uint64_t)); + /* + * If the write in the reftable failed the image may contain a partial= ly + * overwritten reftable. In this case it would be better to clear the + * reftable in memory to avoid possible image corruption. + */ + for (i =3D 0; i < s->refcount_table_size; i++) { + if (s->refcount_table[i] && !reftable_tmp[i]) { + if (ret =3D=3D 0) { + ret =3D qcow2_discard_refcount_block(bs, s->refcount_table= [i] & + REFT_OFFSET_MASK); + } + s->refcount_table[i] =3D 0; + } + } + + if (!s->cache_discards) { + qcow2_process_discards(bs, ret); + } + +out: + g_free(reftable_tmp); + return ret; +} diff --git a/block/qcow2.c b/block/qcow2.c index a3679c69e8..1fa9492499 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3105,18 +3105,43 @@ static int qcow2_truncate(BlockDriverState *bs, int= 64_t offset, } =20 old_length =3D bs->total_sectors * 512; + new_l1_size =3D size_to_l1(s, offset); =20 - /* shrinking is currently not supported */ if (offset < old_length) { - error_setg(errp, "qcow2 doesn't support shrinking images yet"); - return -ENOTSUP; - } + if (prealloc !=3D PREALLOC_MODE_OFF) { + error_setg(errp, + "Preallocation can't be used for shrinking an image= "); + return -EINVAL; + } =20 - new_l1_size =3D size_to_l1(s, offset); - ret =3D qcow2_grow_l1_table(bs, new_l1_size, true); - if (ret < 0) { - error_setg_errno(errp, -ret, "Failed to grow the L1 table"); - return ret; + ret =3D qcow2_cluster_discard(bs, ROUND_UP(offset, s->cluster_size= ), + old_length - ROUND_UP(offset, + s->cluster_size), + QCOW2_DISCARD_ALWAYS, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to discard cropped cluste= rs"); + return ret; + } + + ret =3D qcow2_shrink_l1_table(bs, new_l1_size); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Failed to reduce the number of L2 tables"); + return ret; + } + + ret =3D qcow2_shrink_reftable(bs); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Failed to discard unused refblocks"); + return ret; + } + } else { + ret =3D qcow2_grow_l1_table(bs, new_l1_size, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to grow the L1 table"); + return ret; + } } =20 switch (prealloc) { diff --git a/block/qcow2.h b/block/qcow2.h index 52c374e9ed..5a289a81e2 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -521,6 +521,18 @@ static inline uint64_t refcount_diff(uint64_t r1, uint= 64_t r2) return r1 > r2 ? r1 - r2 : r2 - r1; } =20 +static inline +uint32_t offset_to_reftable_index(BDRVQcow2State *s, uint64_t offset) +{ + return offset >> (s->refcount_block_bits + s->cluster_bits); +} + +static inline uint64_t get_refblock_offset(BDRVQcow2State *s, uint64_t off= set) +{ + uint32_t index =3D offset_to_reftable_index(s, offset); + return s->refcount_table[index] & REFT_OFFSET_MASK; +} + /* qcow2.c functions */ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov, int64_t sector_num, int nb_sectors); @@ -584,10 +596,12 @@ int qcow2_inc_refcounts_imrt(BlockDriverState *bs, Bd= rvCheckResult *res, int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, BlockDriverAmendStatusCB *status_cb, void *cb_opaque, Error **errp); +int qcow2_shrink_reftable(BlockDriverState *bs); =20 /* qcow2-cluster.c functions */ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size); +int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size); int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index); int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset= ); int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t sector_num, diff --git a/qapi/block-core.json b/qapi/block-core.json index 833c602150..c55cd0c8db 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2479,6 +2479,11 @@ # # Trigger events supported by blkdebug. # +# @l1_shrink_write_table: write zeros to the l1 table to shrink image. +# (since 2.11) +# +# @l1_shrink_free_l2_clusters: discard the l2 tables. (since 2.11) +# # Since: 2.9 ## { 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG', @@ -2495,7 +2500,8 @@ 'cluster_alloc_bytes', 'cluster_free', 'flush_to_os', 'flush_to_disk', 'pwritev_rmw_head', 'pwritev_rmw_after_head', 'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev', - 'pwritev_zero', 'pwritev_done', 'empty_image_prepare' ] } + 'pwritev_zero', 'pwritev_done', 'empty_image_prepare', + 'l1_shrink_write_table', 'l1_shrink_free_l2_clusters' ] } =20 ## # @BlkdebugInjectErrorOptions: --=20 2.14.1