From patchwork Tue Jun 13 12:16:38 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Butsykin X-Patchwork-Id: 9783753 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 3780D602DC for ; Tue, 13 Jun 2017 12:22:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 28D6628635 for ; Tue, 13 Jun 2017 12:22:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1D5C928651; Tue, 13 Jun 2017 12:22:33 +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 2F92128635 for ; Tue, 13 Jun 2017 12:22:32 +0000 (UTC) Received: from localhost ([::1]:43017 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dKkq7-00032P-BT for patchwork-qemu-devel@patchwork.kernel.org; Tue, 13 Jun 2017 08:22:31 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60688) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dKkmO-0000zV-93 for qemu-devel@nongnu.org; Tue, 13 Jun 2017 08:18:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dKkmK-0007Cb-8Q for qemu-devel@nongnu.org; Tue, 13 Jun 2017 08:18:40 -0400 Received: from mail-db5eur01on0128.outbound.protection.outlook.com ([104.47.2.128]:54338 helo=EUR01-DB5-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 1dKkm6-00073l-UX; Tue, 13 Jun 2017 08:18:23 -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=XH7mxg1eRQlhEkEq6QRWWZCDv8hbvYgictuipS26TTw=; b=I9VDTZ7DTc5tXN9PzR8sPWaFzUecIxq/ybOmiRvWy3sErCW1ME1Lj0zTy4zd/nEKfWtJAXIzmw9UxDU/SGgyO6jgO/cXYcd5eWeisK0UnpWegwxvuBrW2mzHOE1cR4T7vhpyntPa2lSxFeGH6NuEO4gOYnbAofkH4RIPOoqT1HY= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=pbutsykin@virtuozzo.com; Received: from pavelb-Z68P-DS3.sw.ru (195.214.232.6) by HE1PR0802MB2555.eurprd08.prod.outlook.com (2603:10a6:3:e1::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1157.12; Tue, 13 Jun 2017 12:18:14 +0000 From: Pavel Butsykin To: qemu-block@nongnu.org, qemu-devel@nongnu.org Date: Tue, 13 Jun 2017 15:16:38 +0300 Message-Id: <20170613121639.17853-4-pbutsykin@virtuozzo.com> X-Mailer: git-send-email 2.13.0 In-Reply-To: <20170613121639.17853-1-pbutsykin@virtuozzo.com> References: <20170613121639.17853-1-pbutsykin@virtuozzo.com> MIME-Version: 1.0 X-Originating-IP: [195.214.232.6] X-ClientProxiedBy: HK2PR02CA0136.apcprd02.prod.outlook.com (2603:1096:202:16::20) To HE1PR0802MB2555.eurprd08.prod.outlook.com (2603:10a6:3:e1::20) X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: HE1PR0802MB2555: X-MS-Office365-Filtering-Correlation-Id: 6dffc150-002a-4996-3236-08d4b2564727 X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001)(201703131423075)(201703031133081); SRVR:HE1PR0802MB2555; X-Microsoft-Exchange-Diagnostics: 1; HE1PR0802MB2555; 3:gcqyhEBUChcO54MMLYliRlzn0FuU9dazpI0sGj04eqeVXoRqkcq4vUSI5Ngr4Otl3Y+rAYPfZ0XNFf1imY0bBYiPVl6rVUvlWUKNcgRcD2Eya8YRBtf7F5GFLfz6vyWzz3+hoqG1cyj13V8N2+bdmO4mMtxYaLZ5lovjwhBORRd4rSwuc9Q/6/rVxH2YOt++WafE+fENf282dUs6oQX/mn0Is0bxs5PAbNlHu+UPTssNI5E8BWqr4mI60/OqGs01psFgQVGZa4sQK05Y5w6iorsSOr5tof6xCeloHMy0of7R+y6wx2Sx+JKLl2UnZpCiTPSEbJnQMddA1Sk06rFtKg==; 25:jeFBFjIiA7IFo7OWb+rjy6f0mqkpHX3PJOgwbJIQRZVtdESLMFWJxfEAoyPMMWUteLFdAu2raxJTEq5oi2JU2savpXqJCpBHtAwTeFVbp9BABQuoFqS2OOdwa6JtMPphXTIH+YZXWw6c0cyNcdVLzHsbxUw3W7adFewTBpLrnK5tJ/0fJArWXYpB24kHf9MDrXRhCEzCFFcBzajKWT48vR9R9n4aCYVJJqHn0n+oVZ15iMgbKXNYzWlAlPCjbTd2AiN7dwWmOhuU+nbTMkfWDOno3taT+M/i0v16+dyKJN6U9jL0qfUKqMioqZhTxZAevCrXd+w43vBFH87tVre750utulGHso6bBQYEG00hq0HUolyTLlAMjIMT64CYfgvkneHMhL/ntPqozABxFOB+lntAoMFNaTT4iZPd3kKaxSsn/7qHdu2yHT1kbmNATm0AlVlXdSNCblul+lwoA72tQ2YliAVDTwbbpbaLavrgURg= X-Microsoft-Exchange-Diagnostics: 1; HE1PR0802MB2555; 31:ZXIDbx9FmHSZfjYANC2EiOyIlV4NDgtkXHxJeaIsSBcNoG9/wNfXzwtMIfP8M+qHU775oecDhoanljjewlLDLxiINOedsEGx83zIM2MnLDq0QCbIccMYYngt9F68P0dZGCywX9iOI+umQYFCuyDHf/kZj4YILx0i0jzodi6Wk9jeIACW4ECEqODPYCV+cUvSwirVARv7ei/03tJs51Wb54NshojDmDR9h4a6Scmx4XA=; 20:L68NEW2d0c9EWrujYkG1m1snvHcup/UI5JoHsUim1MUQtmSerXaeC54Hch4A7YtEwk11g8WVRxQce7C2k6BFUgtoF+qY7wzYIPj0JU2Iv+4vJxA7DYhBE8hrEiK9oy7eywkcoTNRNn5MayworDVSc8tsh87PATmw2fwBsoAg0uR47O+Qfp9pLS5YufxQSep3QQqu2XxQcIzKQ9Oe8iKysPL1iwYw1lmYVBG7qQ0O7LNSFVXBuhHcKaGE8U5zALGkmI7OK5vMYCsztT+FyoGkd3hzrM2QIpPtTzGaeE+k4Fg1wJjcngK+5ZzIXTr0EG12mUn+dMr1ZWISxKEENnM0TE0/RXNhtm9yLhL6ZygDXG2UCpaWK44EbtBYBMafETTMx1nu4vLU8riDT260zU51bMam7ch5+CxN2X2X4Gl/slk= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(601004)(2401047)(8121501046)(5005006)(93006095)(93001095)(3002001)(10201501046)(100000703101)(100105400095)(6041248)(20161123560025)(20161123562025)(20161123564025)(20161123555025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123558100)(6072148)(100000704101)(100105200095)(100000705101)(100105500095); SRVR:HE1PR0802MB2555; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:HE1PR0802MB2555; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; HE1PR0802MB2555; 4:nXsvU2g1Lg9ImTvLVk374awhVx/AiAYw5BAk4gOA?= =?us-ascii?Q?WVLaa52kjER5yoODKj7j9Yg1p00hqmH0beNwQsmL13Wn9PjHnxUo6MT9Rd+9?= =?us-ascii?Q?fxGAHH60CNpxooFck5IgwK2Gsu+vhohl4cfSCS7mwR91I2Gp3ba4SUbeTbgH?= =?us-ascii?Q?9Hr0c3D8HLviEze4RBa420ocKVon1ezL0/MK9n1LD4oHjMSw5/C6isC61CS1?= =?us-ascii?Q?++nUvyWfkljGT9HbrHwMnRZ9wUhGF93nwyu1Dw+8rALG01NWCLfJH2TRevKw?= =?us-ascii?Q?v3lP7UCEb0Wy9lSPpeUXnVNnIPkv1D1G0gm6xGyYxeNUlwwMPb8t85xyZoMk?= =?us-ascii?Q?wdXovxv9822b+Eh/qwGXO7vjJc9flMJWC49aI5cWOtnwgVI15DrLxfubOAqj?= =?us-ascii?Q?VganxEwoI978jGb2oZoM9vQ9czaDkaskUfLeKzmNCWoSVrrzLsh+9gqfOBqy?= =?us-ascii?Q?xqOA+qfRpbDWgGE59Az5bgyFJCBAs3+ZgOz7TUhAZNCDlI7g+356rB9ZeAvj?= =?us-ascii?Q?Zf/eD+K/j8i+SFyZo4vpVYRF1u5y7pkbF6BS/+oInVxhy7rmSSa8g8yRjuJ3?= =?us-ascii?Q?ZCma+WNsxlqhMs5boDsWYyiA5MuG3wG7y0qhSBu/j+PGinwIFmfcvjQADJpz?= =?us-ascii?Q?MBKNy4qM/ogJ46SO7uaT1vyV/XvyB9SGBt1OSezDOau4YTsAiFn0SPZkzy5I?= =?us-ascii?Q?V2pmUZa5HZnPNeiAN91MogT/ej+KyPnOARHJ/g7QSK0fMCbTKcT7r07wC24w?= =?us-ascii?Q?nj9NDNXQpq4zVXmrBVfI184vOPjbMDN8Ts9FXlAlSAdGzOWp7VtZRsBKvlGn?= =?us-ascii?Q?+HHn/wB+ZgEyUYNi0BB0rjDcHRm6GbBfW1w595Fl/OzKSsFvHfuV7nYPUsPI?= =?us-ascii?Q?a0tOhpjyl/nHNHEnJJjMUVxJHYlBWyEjilr8NzUJLAYHIgydbZ6eapr6NO6i?= =?us-ascii?Q?LLLs4Yyg3nDOrXPO8PKkl/QvPbk+MJ4M8gjyswpFJvM7uAiLgh0Etr93IOef?= =?us-ascii?Q?9q9cWyqv+X+EBeBmiNFUyCpOQgkwsLOxSM7K0gD6XiojYfiBozMw7wZypHGn?= =?us-ascii?Q?Q1iEqAkv8le6Tr3EBaMcdtnCIQwZ0Y2ZMEaVfcbaF8fJv6QvHyQh/F6YpycG?= =?us-ascii?Q?YFxnhQYQ8eN3Ig/yJW85EokGdQKhmOXU?= X-Forefront-PRVS: 0337AFFE9A X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6009001)(39450400003)(39400400002)(39410400002)(39830400002)(189002)(199003)(6506006)(25786009)(53936002)(50226002)(107886003)(110136004)(4326008)(53416004)(42186005)(6512007)(33646002)(6486002)(106356001)(38730400002)(5660300001)(105586002)(50466002)(5003940100001)(101416001)(305945005)(48376002)(69596002)(81156014)(189998001)(47776003)(66066001)(8676002)(81166006)(6116002)(36756003)(3846002)(97736004)(6666003)(68736007)(86362001)(1076002)(50986999)(76176999)(2950100002)(478600001)(2906002)(7736002); DIR:OUT; SFP:1102; SCL:1; SRVR:HE1PR0802MB2555; H:pavelb-Z68P-DS3.sw.ru; FPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; Received-SPF: None (protection.outlook.com: virtuozzo.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; HE1PR0802MB2555; 23:z973VQqVFawEVHMTLXMXL0YfwgAyKj0FN4XPs9z?= =?us-ascii?Q?FgVobXmvXcq/CDrIVatjijTjyCvvG9DXm8ECbFYGBGIKSMkByrwD+3DJ3nxs?= =?us-ascii?Q?UN4rbu8vfWzeNDnEFaUPCKydCgKLMuF2At9BEj9tE0QuRRA1e9eB7R0pOph3?= =?us-ascii?Q?9A9RmY1uPF/NGuFROACmxgBzJSBDv28lhjdnSm2xRzaeWmOEKIEDHaL96Mdz?= =?us-ascii?Q?JHBBP1nY+XLoB4ISRwgdDZPQaRRVHN5MZkR5f6UOxcjQLd9nb+xJwCBcZycj?= =?us-ascii?Q?LKxnBDBeL7F9oCDLWjjWUUehXn+7XuQmCWRvQhpdeLaYyA8GqFVaIubNUKjF?= =?us-ascii?Q?40g+nL/zyr5LBA28WXYogm8BzxUYXXmeCXsoQUefYomvQXHQMSHK9b8Cdpe/?= =?us-ascii?Q?nhqCoi65C8Wzg/4JZQLcCl/VerGezral52Fl02r0efBmPbdWQvFFXX/VEcpU?= =?us-ascii?Q?x/UBNhYz9azWyrxTuUhqL2ezVWZEM4R4K27FSsDLb7NaG3w/dFIYzSosTPn/?= =?us-ascii?Q?hySjYaUba5Vs4p6WjYpt4oMW/Dv96xweW44c0Eea6VhPZmkkhOxJw5V/nKML?= =?us-ascii?Q?w32OEAkRYwsJDqi+stkU6412C7u2V3QJQDfaoLIhF5jQ11lX09q2OfjHC6yo?= =?us-ascii?Q?6c7tYwLrAeVCJL/TJo9dEblQLDTFSE/t8RpJPo1QGQEEncxZ28jlJUgWusQx?= =?us-ascii?Q?vEkODMCa6v8GkHYyMVmsj8I5hpjJQGqO5qmVNGTT45z4v1+TZNgbsP1KyaKv?= =?us-ascii?Q?EPsqC/k9Z18AJIRrRm9j5vlctZTNU7rh8Zf+UbZkzSLhQXqzu99VXF/SEgQI?= =?us-ascii?Q?rMbJIO5uDlQAu2HekRrKs263PqoHzOApyfpEjreuLijYmslrY4irmIUXD8wu?= =?us-ascii?Q?FNt56C8GjPVi0WTAoL2usz4Nh2rW6nUcHTfpiEeSF+uVuP1VXkuKUTEjOAn6?= =?us-ascii?Q?jtPnk44b+0JZ/pCquywAS6xaV+yFRAAC1fHUDEaCyspibTXY/bSbsqXMjuYd?= =?us-ascii?Q?QQnLhAk4MbuQNjGk2yG8QBKsE7alcvlyazBjlLCYKlIQ4ZML7KdSBdQUeeW1?= =?us-ascii?Q?nx9QOibqA5t/GdxEKBmNOparAUjNpYwov1GZXlBOFc7ugfa/rAjEKkY3zWSV?= =?us-ascii?Q?26bpny2Mn67IZWCJT0S91sA61nBcFPH7g3zL5AS63qkD/+ohYJbIT3BiyvZC?= =?us-ascii?Q?YscBEESn43OXUtcReeRIEYZT9LXNQuAL5x+9bC0a58UzrAbEhmHhJvmNELQ?= =?us-ascii?Q?=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; HE1PR0802MB2555; 6:ZgJQY+BNjqxf+3vxemiQ9UgYo2FqIK0FpgTWmVo8Sgr7FIiWIiH3eQlBYYbFzQZ2IMZKNkm7+YTke4pPJZv+n/+nj5YH/7wVHt1DklEqLjM/2eyyTHtZSniXcwQocdY2DhbejUIsn1e6614zfZuAuqaRZcv3TXrue2gd5iL1ZpM2/2vXy7RhJrfoAcuIucQNKh2eECnX71wZixQuiAZPcMcA7ANSRLkyX0XTJDa5HXgEZBJpL/PclZEUJD65toNfcaSj4uxlsH/A+t9KtM6wOHZ5WZ2M1aLuwxS47RnVDltj06Mae68qvMkbnIY2AOE+rQ0hAB3C3KB9o9Ca4TGe65gUck4R7qzcYct/89qbO3Vttl01TYwgZimQjXhoxYOr6YnjziLqQK7j2cHwUvE/pkWN66cACl+r5cZ2ZDDhssgdC3TeH9tm9p4YHTVvNoijxffRYX0vvOJqaiW8p0ucu4D3qLu2eahHIfKPFeF/YTWnQNvUgXTv0s8pbHSgVYSWKNGRlIIvqOFxzX1pMLx6kQ== X-Microsoft-Exchange-Diagnostics: 1; HE1PR0802MB2555; 5:6lJ2sZg+iXB5mPCc4X9/JTkN4SsPqvO0Cm8UQYyALFpYPCiGSWJ5Gwii9haB2FJv5t32znr5m4o1/Fc1TECXyQjSCOk/XHjOpZ9SUBbalY9cSd7ywLR9iR0cByiryLz5HkxZ++8t9Jv82pL3P3tXpc9KgG5Ae1CGGaEsGAqo6TgcyQXxSjvajmPY9SNgUa4ipJy7qGoqJlKj2KvAjifnLYry4F2TFlKIWLaNq524PEpUKpLsqnuzuPFQEw2GN5Xf1dbi8DG0DAgDpx5cjDTGgZJgUkMDAIEJEAZpKn0XJ7DHSZuvi1z5NogW9DyIWmqYlK81go2s8Rx7380D7Pm4BG/NzlcOXWwqpJFfMhWczXfpfAEktoF4D2+ccJCY+2ghBHfYchRkrh5RDQGNo25X7fYLE/S+zSeisVHVeRPIkyri6aCSJPAj4kvFJ6VzQNfn3yNK0MHSkYoAmzIFBO1AG7CjbPzOAjyUwRBGdQNRh/cp8y2rFyV9fLIZXhVy/GI4; 24:8Od1kTpwakKqwobLBZe5JmBB4wSSCGic4LvQCdjzhfLfjQo8JERzncRV/A7vKWitoWWPSPC6QJYPQMFvEvCCpkcDhUSJJ2NvQIB0TrLYP+M= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; HE1PR0802MB2555; 7:XaFaRMomIaWv1aOw2yvxlbCUK6naVJ3OYJqhIJGGMFOEsa4JCZ0CMn4cOV6SgVVH1bLdMKzIIqdj9wXuUra4DXTBkwWdTGjl240QM9GFz+Y8D7K7hELMufGXMXHmpC6oQST/7UdgjRTPo2zBxo1x2bIBX3ZWmP+/GoyoEAbmBYQ1OedyoGHy/mN+k3JNARjGTdoPFKsvm1U7nvEYLgAyPpSaeNzGW3dubD3zhgFwSkdm/S17xTOVL/Q/gVfXYN+pE00fXKNSCQXu7VPUO8gIewIB7JYVvmNFq28XRLoC+r+do8FaC6ZogQAPaRZjHps5v/E1iCof1vzf653JLK6hoQ==; 20:1thCj0+eaaUdgHQOVVpwzWMwImDoD67PXo9izCeFAeFwfd76IdP3ptoHAV67nD+/va7hB8rmUNzIs3xLsyWUbPyWqwQyx31Mt4LjtSlfGHvuBlwN/VJav87u+FXn7ZgP4yXX3r0f+6w65gJ8sLgkjo1eQ+umo7N0V8zhZbFCYaI= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 Jun 2017 12:18:14.4461 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: HE1PR0802MB2555 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.2.128 Subject: [Qemu-devel] [PATCH v2 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, armbru@redhat.com, mreitz@redhat.com, den@openvz.org Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP This patch add shrinking 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 shrink is done by punching holes in the image file. Signed-off-by: Pavel Butsykin --- block/qcow2-cluster.c | 42 ++++++++++++++++++++++++++++++++ block/qcow2-refcount.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ block/qcow2.c | 40 +++++++++++++++++++++++-------- block/qcow2.h | 2 ++ qapi/block-core.json | 3 ++- 5 files changed, 141 insertions(+), 11 deletions(-) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index d779ea19cf..a84b7e607e 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -32,6 +32,48 @@ #include "qemu/bswap.h" #include "trace.h" +int qcow2_shrink_l1_table(BlockDriverState *bs, uint64_t max_size) +{ + BDRVQcow2State *s = bs->opaque; + int new_l1_size, i, ret; + + if (max_size >= s->l1_size) { + return 0; + } + + new_l1_size = max_size; + +#ifdef DEBUG_ALLOC2 + fprintf(stderr, "shrink l1_table from %d to %" PRId64 "\n", + s->l1_size, new_l1_size); +#endif + + BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_WRITE_TABLE); + ret = bdrv_pwrite_zeroes(bs->file, s->l1_table_offset + + sizeof(uint64_t) * new_l1_size, + (s->l1_size - new_l1_size) * sizeof(uint64_t), 0); + if (ret < 0) { + return ret; + } + + ret = bdrv_flush(bs->file->bs); + if (ret < 0) { + return ret; + } + + BLKDBG_EVENT(bs->file, BLKDBG_L1_SHRINK_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); + s->l1_table[i] = 0; + } + 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 576ab551d6..e98306acd8 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, @@ -2936,3 +2937,67 @@ done: qemu_vfree(new_refblock); return ret; } + +int qcow2_shrink_reftable(BlockDriverState *bs) +{ + BDRVQcow2State *s = bs->opaque; + uint64_t *reftable_tmp = + g_try_malloc(sizeof(uint64_t) * s->refcount_table_size); + int i, ret; + + if (s->refcount_table_size && reftable_tmp == NULL) { + return -ENOMEM; + } + + 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) { + reftable_tmp[i] = 0; + continue; + } + ret = qcow2_cache_get(bs, s->refcount_block_cache, refblock_offs, + &refblock); + if (ret < 0) { + goto out; + } + + /* 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); + } + qcow2_cache_put(bs, s->refcount_block_cache, &refblock); + + reftable_tmp[i] = unused_block ? 0 : cpu_to_be64(s->refcount_table[i]); + } + + ret = bdrv_pwrite_sync(bs->file, s->refcount_table_offset, reftable_tmp, + sizeof(uint64_t) * s->refcount_table_size); + if (ret < 0) { + goto out; + } + + for (i = 0; i < s->refcount_table_size; i++) { + if (s->refcount_table[i] && !reftable_tmp[i]) { + qcow2_free_clusters(bs, s->refcount_table[i] & REFT_OFFSET_MASK, + s->cluster_size, QCOW2_DISCARD_ALWAYS); + s->refcount_table[i] = 0; + } + } + +out: + g_free(reftable_tmp); + return ret; +} diff --git a/block/qcow2.c b/block/qcow2.c index b3ba5daa93..0ad46d2776 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_shrink_l1_table(bs, new_l1_size); + if (ret < 0) { + error_setg_errno(errp, -ret, "Failed to reduce the L1 table"); + return ret; + } + + ret = qcow2_shrink_reftable(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 07faa6dc78..600463bf8e 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_shrink_reftable(BlockDriverState *bs); /* 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 f85c2235c7..bcbffa3339 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2372,7 +2372,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' ] } ## # @BlkdebugInjectErrorOptions: