From patchwork Mon Aug 15 11:56:00 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: zhangzhiming X-Patchwork-Id: 9280849 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 B02A060467 for ; Mon, 15 Aug 2016 11:57:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9FDB528C66 for ; Mon, 15 Aug 2016 11:57:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9470A28C69; Mon, 15 Aug 2016 11:57:14 +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=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 7BA8028C66 for ; Mon, 15 Aug 2016 11:57:11 +0000 (UTC) Received: from localhost ([::1]:36261 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bZGVy-0003AN-Mw for patchwork-qemu-devel@patchwork.kernel.org; Mon, 15 Aug 2016 07:57:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58875) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bZGVZ-00035e-2S for qemu-devel@nongnu.org; Mon, 15 Aug 2016 07:56:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bZGVW-0002gt-Hr for qemu-devel@nongnu.org; Mon, 15 Aug 2016 07:56:44 -0400 Received: from [103.37.137.195] (port=58427 helo=mx01.meituan.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bZGVO-0002fk-15; Mon, 15 Aug 2016 07:56:36 -0400 Received: from localhost (localhost [127.0.0.1]) by yf-it-mx01.yf.sankuai.com (Postfix) with ESMTP id 51763352850D; Mon, 15 Aug 2016 19:56:20 +0800 (CST) Authentication-Results: yf-it-mx01.yf.sankuai.com (amavisd-new); dkim=pass (1024-bit key) header.d=meituan.com Received: from mx01.meituan.com ([127.0.0.1]) by localhost (yf-it-mx01.yf.sankuai.com [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id JDoFSWsHIfzP; Mon, 15 Aug 2016 19:56:20 +0800 (CST) Received: from localhost (localhost [127.0.0.1]) by yf-it-mx01.yf.sankuai.com (Postfix) with ESMTP id 1D2DA3528623; Mon, 15 Aug 2016 19:56:20 +0800 (CST) DKIM-Filter: OpenDKIM Filter v2.9.2 yf-it-mx01.yf.sankuai.com 1D2DA3528623 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=meituan.com; s=20130113; t=1471262180; bh=m1qtc4N3O6y440no2fpP/n1ffsbDocHCozH2wzb07EI=; h=From:Content-Type:Content-Transfer-Encoding:Subject:Date: Message-Id:To:Mime-Version; b=IbuSqFJ9O0ImAA4FrEK9SoaYk9yA2gwZDTlHGxBXjLE6MQaVs1Z7bOUyCltMPoCX3 lFPor3SQ9DWzfCBUHXOezT6ip1Jiiyk/tR1NcEsFHA8Gh9UCwrObp+9f2wqXKUFOKL rorZQAK19idLyKD69V0dKlmIkhL2iPBdFw7Xtgk4= X-Virus-Scanned: amavisd-new at Received: from mx01.meituan.com ([127.0.0.1]) by localhost (yf-it-mx01.yf.sankuai.com [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id NiFHrtOYBwHz; Mon, 15 Aug 2016 19:56:20 +0800 (CST) Received: from [172.18.169.230] (unknown [103.37.140.11]) (Authenticated sender: zhangzhiming02@meituan.com) by yf-it-mx01.yf.sankuai.com (Postfix) with ESMTPSA id D9284352850D; Mon, 15 Aug 2016 19:56:00 +0800 (CST) From: zhangzhiming Date: Mon, 15 Aug 2016 19:56:00 +0800 Message-Id: To: qemu-block@nongnu.org, Kevin Wolf Mime-Version: 1.0 (Mac OS X Mail 8.2 \(2070.6\)) X-Mailer: Apple Mail (2.2070.6) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 103.37.137.195 Subject: [Qemu-devel] Subject: [PATCH] qcow2 resize with snapshot, mod 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 , lihuiba , qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP hi, i modified my code by Kevin Wolf’s review. and thanks for review again. Signed-off-by: zhangzhiming --- block.c | 19 ---------------- block/qcow2-cluster.c | 55 ++++++++++++++++++++++++++++++++++-------------- block/qcow2-snapshot.c | 34 ++++++++++++++-------------- block/qcow2.c | 2 +- block/qcow2.h | 2 +- 5 files changed, 58 insertions(+), 54 deletions(-) diff --git a/block.c b/block.c index 0de7b2d..f54bc25 100644 --- a/block.c +++ b/block.c @@ -2586,25 +2586,6 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) return ret; } -int bdrv_apply_snapshot(BlockDriverState *bs, const char *snapshot_id, - uint64_t snapshot_size) -{ - int ret = bdrv_snapshot_goto(bs, snapshot_id); - if (ret < 0) { - return ret; - } - - ret = refresh_total_sectors(bs, snapshot_size >> BDRV_SECTOR_BITS); - if (ret < 0) { - return ret; - } - bdrv_dirty_bitmap_truncate(bs); - if (bs->blk) { - blk_dev_resize_cb(bs->blk); - } - return ret; -} - /** * Length of a allocated file in bytes. Sparse files are counted by actual * allocated space. Return < 0 if error or unknown. diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index ebadddf..2190528 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -32,32 +32,55 @@ #include "qemu/bswap.h" #include "trace.h" -int shrink_l1_table(BlockDriverState *bs, int64_t new_l1_size) +static int free_some_l2_table(BlockDriverState *bs, int64_t old_size, + int64_t new_size) { BDRVQcow2State *s = bs->opaque; - int64_t old_l1_size = s->l1_size; - s->l1_size = new_l1_size; - int ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, - s->l1_size, 1); - if (ret < 0) { - return ret; + int old_l1_size = size_to_l1(s, old_size); + int new_l1_size = size_to_l1(s, new_size); + if (old_l1_size == new_l1_size) { + return 0; } + int i; + for (i = new_l1_size; i < old_l1_size; i++) { + uint64_t l2_offset = s->l1_table[i] & L1E_OFFSET_MASK; + qcow2_free_clusters(bs, l2_offset, s->cluster_size, + QCOW2_DISCARD_OTHER); + s->l1_table[i] = 0; + /* write l1 entry will be called for several times and + * because l1 is short, i think is tolerated! */ + qcow2_write_l1_entry(bs, i); + } + return 0; +} - s->l1_size = old_l1_size; - ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, - s->l1_size, -1); +int shrink_disk(BlockDriverState *bs, int64_t new_size) +{ + BDRVQcow2State *s = bs->opaque; + int64_t old_size = bs->total_sectors * 512; + int64_t new_sector_nb = DIV_ROUND_UP(new_size, 512); + int64_t discard_sectors_nb = bs->total_sectors - new_sector_nb; + int64_t old_cluster_nb = DIV_ROUND_UP(old_size, s->cluster_size); + int64_t new_cluster_nb = DIV_ROUND_UP(new_size, s->cluster_size); + if (old_cluster_nb == new_cluster_nb) { + return 0; + } + s->l1_size = size_to_l1(s, new_size); + bs->total_sectors = new_sector_nb; + int ret = qcow2_update_header(bs); if (ret < 0) { + s->l1_size = size_to_l1(s, old_size); + bs->total_sectors = old_size / 512; return ret; } - s->l1_size = new_l1_size; - uint32_t be_l1_size = cpu_to_be32(s->l1_size); - ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_size), - &be_l1_size, sizeof(be_l1_size)); + /* can't be undone here, if failed nothing will be done */ + ret = qcow2_discard_clusters(bs, new_size, discard_sectors_nb, + QCOW2_DISCARD_OTHER, true); if (ret < 0) { - return ret; + return 0; } - + free_some_l2_table(bs, old_size, new_size); return 0; } diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 6dd6769..40a0d26 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -490,6 +490,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) cur_l1_bytes = s->l1_size * sizeof(uint64_t); sn_l1_bytes = sn->l1_size * sizeof(uint64_t); + int max_l1_size_bytes = MAX(sn_l1_bytes, cur_l1_bytes); /* * Copy the snapshot L1 table to the current L1 table. @@ -499,7 +500,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) * Decrease the refcount referenced by the old one only when the L1 * table is overwritten. */ - sn_l1_table = g_try_malloc0(sn_l1_bytes); + sn_l1_table = g_try_malloc0(max_l1_size_bytes); if (sn_l1_bytes && sn_l1_table == NULL) { ret = -ENOMEM; goto fail; @@ -517,34 +518,32 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) goto fail; } - ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1, - s->l1_table_offset, sn_l1_bytes); - if (ret < 0) { - goto fail; - } - - ret = bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, sn_l1_table, - sn_l1_bytes); + /* update meta data first, for failed */ + int old_l1_size = s->l1_size; + uint64_t old_total_sectors = bs->total_sectors; + bs->total_sectors = sn->disk_size / BDRV_SECTOR_SIZE; + s->l1_size = sn->l1_size; + ret = qcow2_update_header(bs); if (ret < 0) { + s->l1_size = old_l1_size; + bs->total_sectors = old_total_sectors; goto fail; } - /* write updated header.size */ - uint64_t be_disk_size = cpu_to_be64(sn->disk_size); - ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, size), - &be_disk_size, sizeof(uint64_t)); + /* and then update l1 table */ + ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_ACTIVE_L1, + s->l1_table_offset, max_l1_size_bytes); if (ret < 0) { goto fail; } - uint32_t be_l1_size = cpu_to_be32(sn->l1_size); - ret = bdrv_pwrite_sync(bs->file->bs, offsetof(QCowHeader, l1_size), - &be_l1_size, sizeof(be_l1_size)); + ret = bdrv_pwrite_sync(bs->file->bs, s->l1_table_offset, sn_l1_table, + max_l1_size_bytes); if (ret < 0) { goto fail; } - s->l1_vm_state_index = sn->l1_size; + s->l1_vm_state_index = size_to_l1(s, sn->disk_size);; /* * Decrease refcount of clusters of current L1 table. @@ -556,6 +555,7 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) * the in-memory data instead of really using the offset to load a new one, * which is why this works. */ + s->l1_size = old_l1_size; ret = qcow2_update_snapshot_refcount(bs, s->l1_table_offset, s->l1_size, -1); diff --git a/block/qcow2.c b/block/qcow2.c index 612a534..01a66f2 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2513,7 +2513,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset) new_l1_size = size_to_l1(s, offset); if (offset < bs->total_sectors * 512) { - ret = shrink_l1_table(bs, new_l1_size); + ret = shrink_disk(bs, offset); if (ret < 0) { return ret; } diff --git a/block/qcow2.h b/block/qcow2.h index 8efa735..ba622b6 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -534,7 +534,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order, void *cb_opaque, Error **errp); /* qcow2-cluster.c functions */ -int shrink_l1_table(BlockDriverState *bs, int64_t new_l1_size); +int shrink_disk(BlockDriverState *bs, int64_t new_size); int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size, bool exact_size); int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index);