From patchwork Wed May 31 14:43:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Butsykin X-Patchwork-Id: 9757419 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id CDA66602F0 for ; Wed, 31 May 2017 14:45:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BE0592094F for ; Wed, 31 May 2017 14:45:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B2CA528405; Wed, 31 May 2017 14:45:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAD_ENC_HEADER,BAYES_00, DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 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.wl.linuxfoundation.org (Postfix) with ESMTPS id BAF6326E78 for ; Wed, 31 May 2017 14:45:25 +0000 (UTC) Received: from localhost ([::1]:59943 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dG4sG-0001JQ-Nh for patchwork-qemu-devel@patchwork.kernel.org; Wed, 31 May 2017 10:45:24 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37617) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dG4r2-00013k-Jz for qemu-devel@nongnu.org; Wed, 31 May 2017 10:44:10 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dG4r1-0004tR-0o for qemu-devel@nongnu.org; Wed, 31 May 2017 10:44:08 -0400 Received: from mail-he1eur01on0091.outbound.protection.outlook.com ([104.47.0.91]:58940 helo=EUR01-HE1-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 1dG4qt-0004ep-5f; Wed, 31 May 2017 10:43:59 -0400 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=Qf0uOenQynUALTB3PqGJqcPrXLujaSupzX0VcOohk0o=; b=dHVJR0irOQjgcZd0lRRi04SCVBujH5rJybnr/90unKTymJe0DswC3pEI9MLbpXmpbiI5Fh+wl22FaK+f/bQZ4VzVgIKO0EgP99itM37kjDHBWZNeYi3x6xpbar49WnicxsxaZiHKmIQ5lUorvM4y4/AWlcGxFEsJGZmu75qQZ0o= Authentication-Results: nongnu.org; dkim=none (message not signed) header.d=none; nongnu.org; dmarc=none action=none header.from=virtuozzo.com; Received: from pavelb-Z68P-DS3.sw.ru (195.214.232.6) by VI1PR0802MB2557.eurprd08.prod.outlook.com (2603:10a6:800:ae::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1124.9; Wed, 31 May 2017 14:43:48 +0000 From: Pavel Butsykin To: , Date: Wed, 31 May 2017 17:43:30 +0300 Message-ID: <20170531144331.30173-2-pbutsykin@virtuozzo.com> X-Mailer: git-send-email 2.13.0 In-Reply-To: <20170531144331.30173-1-pbutsykin@virtuozzo.com> References: <20170531144331.30173-1-pbutsykin@virtuozzo.com> MIME-Version: 1.0 X-Originating-IP: [195.214.232.6] X-ClientProxiedBy: HE1PR0202CA0022.eurprd02.prod.outlook.com (2603:10a6:3:8c::32) To VI1PR0802MB2557.eurprd08.prod.outlook.com (2603:10a6:800:ae::7) X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI1PR0802MB2557: X-MS-Office365-Filtering-Correlation-Id: 86796568-ac56-43e2-d4da-08d4a83372d4 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001)(201703131423075)(201703031133081); SRVR:VI1PR0802MB2557; X-Microsoft-Exchange-Diagnostics: 1; VI1PR0802MB2557; 3:bkkpVmjK5h8/QRfacInjxWKXd5jGFFL0oQ/nroQXQjHK6aM8qfbvagpGst8JSI+vs30363wzV6nq/tYQjufxGYl1ZYN7lWL+sVN9HM0Ewm3YhbKXymMvjw+9pluC1pY7VuWuakdXbBkE+3CEF7MHlT0SCGLd4QzxLQom/YVzGXeM97OJVwb48x0GWTf7+yX/3iuItDBp7kmh+6S+QzKYi6UKRXWCeDnd7xIPNukebbHfiu9KtVTYoLOn8ZZrS26t6I3CMR47tx9c7zV0Ex2LdxdLaNDANKd04xigqLzesMdfVjFTDwUuig0SLXdq4q4sh9XbGcyOiaSjSKioycY8ew==; 25:ZTaKGRr1o87prCG8PUo2lz7QaaAO8ylSgrBfb4zO54JCEjSJQBvmhZycckdEQhuK0Wa+I3xIle8daOZ9dLl+0GypbRYCgFFa1A69kguBoxk0mwr811sG4ltzE7iBODHRy13hXIkT3siEtJ03nFzMs8gkhhS94MsWqVS1Y9dfYNv7y4XQN0GF79T+ZBT2y2h+TcOjb04GIME70tcyUfRDRiSk5zLjvYZdHKFMPNO1nBUvaYcksvVbeAnMPiAMbH1PbXu/UkbKkTdRFJRzbHH4baaPpU6affxP6Sk84P80zJbyfGNppXFFTrtJAlAdsmtR/gF+LHz1FMpskksjjGevwmjXfnAlk/snZu3V2xYU87oUW5sjhEQ1OuZ8sOQut2QKvI0Nn7rhmJeDYkl4Jcc0QJRa8aaoYtEYf7K2kLoyCxcOTMyhyfP0QtNiidT2gPhu35zLeZ1dm8q4IKc+v8wuruqckm8IIn7hPrDcqtwAENY= X-Microsoft-Exchange-Diagnostics: 1; VI1PR0802MB2557; 31:mwu1kOU6qIqgtTPr2zTmPU1iTZhu9zr3tbQKB/8V7TzpEggTDKLPZVkH+py5iBVguf1d9TrK7xsdNf9O9YcA8X9WK0ccQYWC/l/fuOGKsLcDx3I7FyXgK+K2UK3LwlXHmWPXhj0Ls2/Z09Oy0y6NWSrGJdCkkdFdd53uUKRSQ622gWJbTuZE3/3OSPs0IWGahea3q6dCLzP23rHOkqiGOzLUWh6CZRsTlBz7EC429DQ=; 20:lOrCeHCUjprQ5E5Oz/Z9W5Yd6ZFIO8lU9CelfoJlh+tdCj7HqFNBUvlxTRqJkTopCpA2Lw5fAs59LEQ3yo2ekXCvLsYCHfbGOwB6MtSSIwMpwwsnpPRUgsmO4PdmIe9pMqJL5XySxO8wN8yAbOxg165lwxgS7C2AZ8C83smFXcMtZFeUy3F+vbb3e6MfWj7FJuJjo/kISHSTdn2zs8ODm9VNhv4QiWLS8TGIE/eD504mnq6mETm+O5W95+CtaJfWyRaigWwHAuYJbew6WYz14ZKJ2XAjAMxbD9DSrXzy2GVymyiDjEJjOxBtPiN+39Oo0MCy7uFmSb+OE9Rd+ZKxpEwOL4ohind3RgegL5ncZZXFEB1hjd7TZytqmzORz3ln0WiYTSWEvh3A+jaoQUKePLJ366WYwSm3l/Q8OdcBm/o= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(100000700073)(100105000095)(100000701073)(100105300095)(100000702073)(100105100095)(6040450)(601004)(2401047)(5005006)(8121501046)(3002001)(100000703073)(100105400095)(10201501046)(93006095)(93001095)(6041248)(20161123560025)(20161123564025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123555025)(20161123562025)(20161123558100)(6072148)(100000704073)(100105200095)(100000705073)(100105500095); SRVR:VI1PR0802MB2557; BCL:0; PCL:0; RULEID:(100000800073)(100110000095)(100000801073)(100110300095)(100000802073)(100110100095)(100000803073)(100110400095)(100000804073)(100110200095)(100000805073)(100110500095); SRVR:VI1PR0802MB2557; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; VI1PR0802MB2557; 4:tV8V0NbozVVGQ2Oua9p3urJ07IAMJZP0J6RyGZ9Z?= =?us-ascii?Q?0+YpYPxxx3FrIyvzEcCjIkbc9duwn6btENvDAbtiARjzsgp4h2CJwT8+es9d?= =?us-ascii?Q?xhUMEx0VLjddRsjBbwOQqjkcLmsyGzZRIlIjiVI6EIlzfhuQmtW7TqAt6hkE?= =?us-ascii?Q?tlx9MnfjPGvrZVrFs7BFnYG/KS7mDUWWRuiS54nPfs/WPCkQwEdsj2BaHDOC?= =?us-ascii?Q?DGjTNqtg5jNtMA74C5YWNo+QvEoMRgU95c1x/8OwbTZgByHbRLGlm26rCAxB?= =?us-ascii?Q?jZ9jGuYry8JnZFh0oUd4Wp9UuVGiazF0PGmTI6n20T4s3YJDBZ1c7QrVAI3x?= =?us-ascii?Q?W5m6pvh1nyXwx8bRgVxAY8LHLsj84VEKviCYv6jiFzCvQceQ2dF4BixlRtZV?= =?us-ascii?Q?kaant36efb5X2Fv/Nru4Hx3v7voCPpkxVleRJyndVfjuEEq1QeyFTtEp7Dc7?= =?us-ascii?Q?pKWkXeVB/dJtEtF253v0LPMvlHe29hEP2Z4h/QEo/peixJEVShEAX8+EI3TB?= =?us-ascii?Q?FQ3fahlrsqxApZ3t2jEXe6msFDk9BqHSAOxhqe3/xTcENnayH84jDxrYf3dt?= =?us-ascii?Q?Y5MGG8Ho+wYfaUCeb8MTWvgwKCIn5IS9jEq24LuGonMJ0kz/iWz2NXfdp33j?= =?us-ascii?Q?ThPqvAm5yC+K4+IUXVFhaRZkf15ip5sd/iiVwc3sDzb3vogR7nhmcOo7+0Ar?= =?us-ascii?Q?zur5rnvNXiscTXLWhZz5AbnUEvtiRGCZbei2zQRIS9lxCnn+KNcpl4T4L+zX?= =?us-ascii?Q?zXOgY2/T7FNVbh03+nrL+8dP2pAc3DHV3d7kjjJvKGYR91Aw/RgFmAYwkCwz?= =?us-ascii?Q?qF8+4EliPYVVStytumcAm1NfWdXbNVacsnQmYXl8bwu1bW/rU//Bk7vae0s8?= =?us-ascii?Q?FHJP27IpHQT7kKZ8r+S/ZaK4MjAfCaVFI1NUXaK7kEEDC4FG9R5j50VgW3hq?= =?us-ascii?Q?P+AZ9C6lS0HBKF7ONfC6wQykMu8+C2j+5Fz7V0bFhZtljKEBAU6b+LtyCvkk?= =?us-ascii?Q?ahmMi5+cr1AQtGx0ZgWBpJn8GYTMd1/LnrB973Q9isWRjFjnRe2XVXjrtGBz?= =?us-ascii?Q?kMHBUrDzCbNaoIElLlMHE3a/39NHpc5TO3GbGhnz83Kaz20So1bNfhlFlRs0?= =?us-ascii?Q?712iFWhO9+VSLzpFPKkDFyQtesYacriN?= X-Forefront-PRVS: 0324C2C0E2 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(39410400002)(39450400003)(39400400002)(39840400002)(4326008)(107886003)(81166006)(48376002)(38730400002)(8676002)(7736002)(50986999)(5660300001)(6512007)(25786009)(76176999)(50226002)(50466002)(54906002)(305945005)(1076002)(6486002)(53936002)(6666003)(6506006)(5003940100001)(3846002)(6116002)(2950100002)(36756003)(33646002)(47776003)(478600001)(2906002)(189998001)(42186005)(53416004)(575784001)(86362001)(66066001); DIR:OUT; SFP:1102; SCL:1; SRVR:VI1PR0802MB2557; H:pavelb-Z68P-DS3.sw.ru; FPR:; SPF:None; MLV:sfv; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; VI1PR0802MB2557; 23:bH/qW5FqPxXhwZeZYgeqrkWM/ZHD1EUjYnAbNl1?= =?us-ascii?Q?vKYn+fRHkjc3TrK+Wr9mUrra4om4BBRPfr8H0V1dqHyDro3xB76hv65BUSz5?= =?us-ascii?Q?IsCfT4gIWM++eD4G1bE55KluhK0unrKf+X+XFzFA5sMA4RaLsdnC9z9rutc5?= =?us-ascii?Q?g8NVJ0LUYVvzUTdEdyvM7CclTVG/Uow8bzPTN1XOlL1ZKgNcEoIrnPHFQN3y?= =?us-ascii?Q?63cKYRbmZp5GaZ8RnRHl5PtsiBEkKHKP/rsqkYxr1+X9ssGKdISviqdCH4mG?= =?us-ascii?Q?KeV2c0bifbb+XZC/mUBUF3UkFe9ro4Qtkk6zYnQPhEVweo6qGJiV8lUOd2Sl?= =?us-ascii?Q?rQ4SvXEvNdKzzSzUCbwKCMRpzPdi73egRuQljPvwmVm95JD+WdjErKFXbSOo?= =?us-ascii?Q?LzTdcVvTbkRbZJo9SDQGfee6Z2LplEQaNqVYOJxqxRjTJT0GJ9wM9Q048c5K?= =?us-ascii?Q?B5y1jDfGXwCPWpSVAzmlAX2Wv5f2HPd5F8Mc4PbFnXldkWebEPXRHFfX1S4Z?= =?us-ascii?Q?hpjG1pGcSNgAXUmxyUX2zXcFKLHgOZWYJYxwkGppJMihKiNbLzMeBoiG92TT?= =?us-ascii?Q?V7e8jQ32n0lOw8XgxsFNfx0iZJ9UzF97yC9nCupy2ZxknlpI2hF6k0XuYMOV?= =?us-ascii?Q?JmBKpn2XEksETwAsjlCof5vFMS5gSTFeM3QhnIVM6tm+pY01HU5LE+kHN3t5?= =?us-ascii?Q?I2pnyS7SSxjuO8DJinRYSZ/cr6om8kp1VrF1VerSIY4bDOHxfv/D/1IRivVa?= =?us-ascii?Q?7+Oh5Wq3I7K+crBG6OTE0MZ5Y49bK1A22srOqcB4tMWisNnQhvrkUb+YG0vY?= =?us-ascii?Q?VwT0UeGbWz9zVsbjP2sf/YKVDC8cqFgPIhjF4GGbh6+uSgIeZSOc0kfkFjTC?= =?us-ascii?Q?kGVNhz0BhQKzlErX/HqoueBO31f4dAhQy2rXPJy1ceYS0GC3zr5VthwF+F8c?= =?us-ascii?Q?liR+tqHMFO18kTVb0i4NsuK9RyuQGXXMaoqlkileqjQmUHzorfFkpPDfQuJH?= =?us-ascii?Q?ZVyyk+uj4yaKkyIoF8nJZ+EDzQ47TQDAIDEiVea97pG3lVy35BTJ/bJbhFmV?= =?us-ascii?Q?xDr99BaS36QNOKUD5r/ahiv/2NWmi?= X-Microsoft-Exchange-Diagnostics: 1; VI1PR0802MB2557; 6:qnVR/xSg+Jv2/ankFRb21g94t061wNifeawtBy+9KHClBRCMRcHGV0vIZCbM4szgyo5hoVzUXTAwL6GrvjtsYL6TmEG7aNabyIQ/37CI3L9H8BCIf6+K43rVJwLHHzZkV4gVnRsUkJuNqahSiXYvq2RGZhbWGSGfQ6bYW74olV+YNGIxMb0s7IhSGdkp9Xk/NjmvK+6Y/p+P+r8QgkAWQKhKZjiYm3KAb3DaoCc3Qr93NqK+NtPGoHWtL0X24sLjyKySKX20R+3MgGUs7Cr33eUrhfe6mLdNGzdnbWwFXRPp7ksaMvi22Qohyv/c+OBSajylEOwmaQ+AjqChLj6xvXQEgqvhDd4MxtT0F0hdtlXAAFyjN4aGm71A+HZlYhTbeSX3yuq4F4bBYGffrHiRUNSgjgR7vx3ZIcRl8VDQmiCY69owGIsmN9dY/34tNQyrfivfehys34jJCvOtAbjtrWjRKGy2FhXWH6/91xpyPwiXBsAYUWz0+yDh0HhSrTLTJg1KAP+kfWxDOStxSqnzPw== X-Microsoft-Exchange-Diagnostics: 1; VI1PR0802MB2557; 5:eD1zDD05zIopJZrdxWc4Du8/EY97Bz2ggZE1GV6oJF75MW0xmISNxlilQM32kxVET7dLOtjDmJZcWrMdv8h1nqNY5GmWFpx4wd4cowLs/JVYYhIj2c94PQ7fdotlcyYrilgdGVwqsLFBfJyo1012BbJJj3wpe7kCHjm3RUt1ffRYVvNnMo5dfAIljepQtRftkNvqk8GnZOcWO47oryKhDkJumB95V/hk6nLH6tQRN86Blyddkp/+4jyYOQnl4FVxRMqgHwgNW2//kK6RYktWWsZzN1DlGSPBeB4FHExQoDf9I2BsvFjw+PgaildsnVJqzk+oichR2wRBfj5crkka45XkxBR5VZC4agAMiOScR+MErSvsdJtS+NF3GHP6tu7fva5jiiRDAWN56c5ShfzP/KBm98RX+CAiI4GoadRQUlCBnImyPZtpN+Ly4ycU9XUeo9B6+hLd1Q8g3tk8vMmC8QM6k/L7jjrkUm7YQuav0POPSkCQS9KnJ0iZdqBPCNDD; 24:+5lluXueVxCUxZXxY+SGBKHhXZQCa2mXEXhfPr4v6huGp1dnYufrCMMP0O+p5NnohJ7nBNwpvV0udgM3+IiYqjJSibCvQPVUnA3XyRiahS4= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; VI1PR0802MB2557; 7:FZYQAJ6l338jwEs5iNt4VU7QA94aQUiV2qwETayCsONHEy9YCmpEDIfMA31UZZWLgSyiWadRjNI/e9yklVwir6M/MQpgdjPdOyyz3o244pzwFARRtDzkXCFIqdtlYN/HJnk/w3VnLyjiD5zjfohRYpHnYX8GJtfg8a/MlOFsZzo8Z/0sADvQlCcOJ+/kRfMcTCDgAgAdbv5RDd44Oh8mYPoQi5/avCtdCHqjPosXg5Ta8JDtSr9ghiPvmSviLkUEP1S9iFdQYUaamNQ1J4QwCM5ZNELiPjwXHXL2jOfeWZxBiOhfkmMwLY/iRTJiNu+lfBrLdfJUwFwRUHC9Qx4y1A==; 20:0KOnaRSbRW87sO4zZDZxQW/JGog+baX3sjAm7D2Q8oTL2Gp9ZVLQ4kSjBA2uec9GNFUEpB6RstEu5XDhzVOdypf9Hp3TCW27xYDGFdP1XVcGWyiP/j8bHizX+2Vgt1snsmsEiYHTDiLN7XD7tp9I7z7ngzqoCUxiuP7LyR0atpI= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 31 May 2017 14:43:48.1619 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR0802MB2557 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.0.91 Subject: [Qemu-devel] [PATCH 1/2] qcow2: add reduce 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, armbru@redhat.com, mreitz@redhat.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP This patch adds the reduction of the image file for qcow2. As a result, this allows us to reduce the virtual image size and free up space on the disk without copying the image. Image can be fragmented and reduction is done by punching holes in the image file. Signed-off-by: Pavel Butsykin --- block/qcow2-cache.c | 8 +++++ block/qcow2-cluster.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ block/qcow2-refcount.c | 65 +++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 40 ++++++++++++++++++------ block/qcow2.h | 4 +++ qapi/block-core.json | 4 ++- 6 files changed, 193 insertions(+), 11 deletions(-) diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c index 1d25147392..da55118ca7 100644 --- a/block/qcow2-cache.c +++ b/block/qcow2-cache.c @@ -411,3 +411,11 @@ void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c, assert(c->entries[i].offset != 0); c->entries[i].dirty = true; } + +void qcow2_cache_entry_mark_clean(BlockDriverState *bs, Qcow2Cache *c, + void *table) +{ + int i = qcow2_cache_get_table_idx(bs, c, table); + assert(c->entries[i].offset != 0); + c->entries[i].dirty = false; +} diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 347d94b0d2..47e04d7317 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -32,6 +32,89 @@ #include "qemu/bswap.h" #include "trace.h" +int qcow2_reduce_l1_table(BlockDriverState *bs, uint64_t max_size) +{ + BDRVQcow2State *s = bs->opaque; + int64_t new_l1_size_bytes, free_l1_clusters; + uint64_t *new_l1_table; + int new_l1_size, i, ret; + + if (max_size >= s->l1_size) { + return 0; + } + + new_l1_size = max_size; + +#ifdef DEBUG_ALLOC2 + fprintf(stderr, "reduce l1_table from %d to %" PRId64 "\n", + s->l1_size, new_l1_size); +#endif + + ret = qcow2_cache_flush(bs, s->l2_table_cache); + if (ret < 0) { + return ret; + } + + BLKDBG_EVENT(bs->file, BLKDBG_L1_REDUCE_FREE_L2_CLUSTERS); + for (i = s->l1_size - 1; i > new_l1_size - 1; i--) { + if ((s->l1_table[i] & L1E_OFFSET_MASK) == 0) { + continue; + } + qcow2_free_clusters(bs, s->l1_table[i] & L1E_OFFSET_MASK, + s->l2_size * sizeof(uint64_t), + QCOW2_DISCARD_ALWAYS); + } + + new_l1_size_bytes = sizeof(uint64_t) * new_l1_size; + + BLKDBG_EVENT(bs->file, BLKDBG_L1_REDUCE_WRITE_TABLE); + ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset + new_l1_size_bytes, + s->l1_size * sizeof(uint64_t) - new_l1_size_bytes, + 0); + if (ret < 0) { + return ret; + } + + ret = bdrv_flush(bs->file->bs); + if (ret < 0) { + return ret; + } + + /* set new table size */ + BLKDBG_EVENT(bs->file, BLKDBG_L1_REDUCE_ACTIVATE_TABLE); + new_l1_size = cpu_to_be32(new_l1_size); + ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, l1_size), + &new_l1_size, sizeof(new_l1_size)); + new_l1_size = be32_to_cpu(new_l1_size); + if (ret < 0) { + return ret; + } + + BLKDBG_EVENT(bs->file, BLKDBG_L1_REDUCE_FREE_L1_CLUSTERS); + free_l1_clusters = + DIV_ROUND_UP(s->l1_size * sizeof(uint64_t), s->cluster_size) - + DIV_ROUND_UP(new_l1_size_bytes, s->cluster_size); + if (free_l1_clusters) { + qcow2_free_clusters(bs, s->l1_table_offset + + ROUND_UP(new_l1_size_bytes, s->cluster_size), + free_l1_clusters << s->cluster_bits, + QCOW2_DISCARD_ALWAYS); + } + + new_l1_table = qemu_try_blockalign(bs->file->bs, + align_offset(new_l1_size_bytes, 512)); + if (new_l1_table == NULL) { + return -ENOMEM; + } + memcpy(new_l1_table, s->l1_table, new_l1_size_bytes); + + qemu_vfree(s->l1_table); + s->l1_table = new_l1_table; + s->l1_size = new_l1_size; + + return 0; +} + 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 7c06061aae..5481b623cd 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" static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size); static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, @@ -2931,3 +2932,67 @@ done: qemu_vfree(new_refblock); return ret; } + +int qcow2_reftable_shrink(BlockDriverState *bs) +{ + BDRVQcow2State *s = bs->opaque; + int i, ret; + + ret = qcow2_cache_flush(bs, s->refcount_block_cache); + if (ret < 0) { + return ret; + } + + for (i = 0; i < s->refcount_table_size; i++) { + int64_t refblock_offs = s->refcount_table[i] & REFT_OFFSET_MASK; + void *refblock; + bool unused_block; + + if (refblock_offs == 0) { + continue; + } + ret = qcow2_cache_get(bs, s->refcount_block_cache, refblock_offs, + &refblock); + if (ret < 0) { + return ret; + } + + /* the refblock has own reference */ + if (i == refblock_offs >> (s->refcount_block_bits + s->cluster_bits)) { + uint64_t blk_index = (refblock_offs >> s->cluster_bits) & + (s->refcount_block_size - 1); + uint64_t refcount = s->get_refcount(refblock, blk_index); + + s->set_refcount(refblock, blk_index, 0); + + unused_block = buffer_is_zero(refblock, s->refcount_block_size); + + s->set_refcount(refblock, blk_index, refcount); + } else { + unused_block = buffer_is_zero(refblock, s->refcount_block_size); + } + + if (unused_block) { + qcow2_free_clusters(bs, refblock_offs, s->cluster_size, + QCOW2_DISCARD_ALWAYS); + qcow2_cache_entry_mark_clean(bs, s->refcount_block_cache, refblock); + s->refcount_table[i] = 0; + } + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); + } + + for (i = 0; i < s->refcount_table_size; i++) { + s->refcount_table[i] = cpu_to_be64(s->refcount_table[i]); + } + ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset, + s->refcount_table, + sizeof(uint64_t) * s->refcount_table_size); + if (ret < 0) { + return ret; + } + for (i = 0; i < s->refcount_table_size; i++) { + s->refcount_table[i] = be64_to_cpu(s->refcount_table[i]); + } + + return 0; +} diff --git a/block/qcow2.c b/block/qcow2.c index a8d61f0981..4da8bc85d1 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2545,6 +2545,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp) { BDRVQcow2State *s = bs->opaque; int64_t new_l1_size; + uint64_t total_size; int ret; if (offset & 511) { @@ -2558,17 +2559,36 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp) return -ENOTSUP; } - /* shrinking is currently not supported */ - if (offset < bs->total_sectors * 512) { - error_setg(errp, "qcow2 doesn't support shrinking images yet"); - return -ENOTSUP; - } - new_l1_size = size_to_l1(s, offset); - ret = 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; + total_size = bs->total_sectors << BDRV_SECTOR_BITS; + + if (offset < total_size) { + ret = qcow2_cluster_discard(bs, ROUND_UP(offset, s->cluster_size), + total_size - ROUND_UP(offset, + s->cluster_size), + QCOW2_DISCARD_ALWAYS, true); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to discard reduced clasters"); + return ret; + } + + ret = qcow2_reduce_l1_table(bs, new_l1_size); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to reduce the L1 table"); + return ret; + } + + ret = qcow2_reftable_shrink(bs); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to shrink the refcount table"); + return ret; + } + } else { + ret = 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; + } } /* write updated header.size */ diff --git a/block/qcow2.h b/block/qcow2.h index 1801dc30dc..03cebabb3d 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -531,10 +531,12 @@ int qcow2_pre_write_overlap_check(BlockDriverState *bs, int ign, int64_t offset, int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, BlockDriverAmendStatusCB *status_cb, void *cb_opaque, Error **errp); +int qcow2_reftable_shrink(BlockDriverState *bs); /* qcow2-cluster.c functions */ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size); +int qcow2_reduce_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, @@ -583,6 +585,8 @@ int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c); void qcow2_cache_entry_mark_dirty(BlockDriverState *bs, Qcow2Cache *c, void *table); +void qcow2_cache_entry_mark_clean(BlockDriverState *bs, Qcow2Cache *c, + void *table); int qcow2_cache_flush(BlockDriverState *bs, Qcow2Cache *c); int qcow2_cache_write(BlockDriverState *bs, Qcow2Cache *c); int qcow2_cache_set_dependency(BlockDriverState *bs, Qcow2Cache *c, diff --git a/qapi/block-core.json b/qapi/block-core.json index 6b974b952f..dcd2d0241f 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2371,7 +2371,9 @@ '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_reduce_write_table', 'l1_reduce_activate_table', + 'l1_reduce_free_l2_clusters', 'l1_reduce_free_l1_clusters' ] } ## # @BlkdebugInjectErrorOptions: