From nobody Mon Feb 9 00:02:27 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; 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 1521121522664105.72928043157833; Thu, 15 Mar 2018 06:45:22 -0700 (PDT) Received: from localhost ([::1]:51687 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ewTC1-0003nF-SQ for importer@patchew.org; Thu, 15 Mar 2018 09:45:17 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:51400) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ewT4t-0005jj-7d for qemu-devel@nongnu.org; Thu, 15 Mar 2018 09:38:01 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ewT4p-0004vw-7N for qemu-devel@nongnu.org; Thu, 15 Mar 2018 09:37:55 -0400 Received: from [112.64.68.174] (port=39096 helo=robinhe-hp.sh.intel.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1ewT4o-0004kw-93 for qemu-devel@nongnu.org; Thu, 15 Mar 2018 09:37:51 -0400 Received: from robinhe-hp.sh.intel.com (localhost [127.0.0.1]) by robinhe-hp (8.15.2/8.15.2/Debian-3) with ESMTP id w2D8Xv5D018944; Tue, 13 Mar 2018 16:33:57 +0800 Received: (from robinhe@localhost) by robinhe-hp.sh.intel.com (8.15.2/8.15.2/Submit) id w2D8XvRi018943; Tue, 13 Mar 2018 16:33:57 +0800 From: junyan.he@intel.com To: qemu-devel@nongnu.org Date: Tue, 13 Mar 2018 16:33:45 +0800 Message-Id: <1520930033-18885-3-git-send-email-junyan.he@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1520930033-18885-1-git-send-email-junyan.he@intel.com> References: <1520930033-18885-1-git-send-email-junyan.he@intel.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 112.64.68.174 Subject: [Qemu-devel] [PATCH 02/10] RFC: Implement qcow2's snapshot dependent saving function. 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, famz@redhat.com, crosthwaite.peter@gmail.com, quintela@redhat.com, dgilbert@redhat.com, mreitz@redhat.com, Junyan He , pbonzini@redhat.com, rth@twiddle.net Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Junyan He For qcow2 format, we can increase the cluster's reference count of dependent snapshot content and link the offset to the L2 table of the new snapshot point. This way can avoid obvious snapshot's dependent relationship, so when we delete some snapshot point, just decrease the cluster count and no need to check further. Signed-off-by: Junyan He --- block/qcow2-snapshot.c | 154 +++++++++++++++++++++++++++++++++++++++++++++= ++++ block/qcow2.c | 2 + block/qcow2.h | 7 +++ 3 files changed, 163 insertions(+) diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index cee25f5..8e83084 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -736,3 +736,157 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, =20 return 0; } + +int qcow2_snapshot_save_dependency(BlockDriverState *bs, + const char *depend_snapshot_id, + int64_t depend_offset, + int64_t depend_size, + int64_t offset, + Error **errp) +{ + int snapshot_index; + BDRVQcow2State *s =3D bs->opaque; + QCowSnapshot *sn; + int ret; + int64_t i; + int64_t total_bytes =3D depend_size; + int64_t depend_offset1, offset1; + uint64_t *depend_l1_table =3D NULL; + uint64_t depend_l1_bytes; + uint64_t *depend_l2_table =3D NULL; + uint64_t depend_l2_offset; + uint64_t depend_entry; + QCowL2Meta l2meta; + + assert(bs->read_only =3D=3D false); + + if (depend_snapshot_id =3D=3D NULL) { + return 0; + } + + if (!QEMU_IS_ALIGNED(depend_offset, s->cluster_size)) { + error_setg(errp, "Specified snapshot offset is not multiple of %u", + s->cluster_size); + return -EINVAL; + } + + if (!QEMU_IS_ALIGNED(offset, s->cluster_size)) { + error_setg(errp, "Offset is not multiple of %u", s->cluster_size); + return -EINVAL; + } + + if (!QEMU_IS_ALIGNED(depend_size, s->cluster_size)) { + error_setg(errp, "depend_size is not multiple of %u", s->cluster_s= ize); + return -EINVAL; + } + + snapshot_index =3D find_snapshot_by_id_and_name(bs, NULL, depend_snaps= hot_id); + /* Search the snapshot */ + if (snapshot_index < 0) { + error_setg(errp, "Can't find snapshot"); + return -ENOENT; + } + + sn =3D &s->snapshots[snapshot_index]; + if (sn->disk_size !=3D bs->total_sectors * BDRV_SECTOR_SIZE) { + error_report("qcow2: depend on the snapshots with different disk " + "size is not implemented"); + return -ENOTSUP; + } + + /* Only can save dependency of snapshot's vmstate data */ + depend_offset1 =3D depend_offset + qcow2_vm_state_offset(s); + offset1 =3D offset + qcow2_vm_state_offset(s); + + depend_l1_bytes =3D s->l1_size * sizeof(uint64_t); + depend_l1_table =3D g_try_malloc0(depend_l1_bytes); + if (depend_l1_table =3D=3D NULL) { + return -ENOMEM; + } + + ret =3D bdrv_pread(bs->file, sn->l1_table_offset, depend_l1_table, + depend_l1_bytes); + if (ret < 0) { + g_free(depend_l1_table); + goto out; + } + for (i =3D 0; i < depend_l1_bytes / sizeof(uint64_t); i++) { + be64_to_cpus(&depend_l1_table[i]); + } + + while (total_bytes) { + assert(total_bytes > 0); + /* Find the cluster of depend */ + depend_l2_offset =3D + depend_l1_table[depend_offset1 >> (s->l2_bits + s->cluster_bit= s)]; + depend_l2_offset &=3D L1E_OFFSET_MASK; + if (depend_l2_offset =3D=3D 0) { + ret =3D -EINVAL; + goto out; + } + + if (offset_into_cluster(s, depend_l2_offset)) { + qcow2_signal_corruption(bs, true, -1, -1, "L2 table offset %#" + PRIx64 " unaligned (L1 index: %#" + PRIx64 ")", + depend_l2_offset, + depend_offset1 >> + (s->l2_bits + s->cluster_bits)); + return -EIO; + } + + ret =3D qcow2_cache_get(bs, s->l2_table_cache, depend_l2_offset, + (void **)(&depend_l2_table)); + if (ret < 0) { + goto out; + } + + depend_entry =3D + be64_to_cpu( + depend_l2_table[offset_to_l2_index(s, depend_offset1)]); + if (depend_entry =3D=3D 0) { + ret =3D -EINVAL; + qcow2_cache_put(s->l2_table_cache, (void **)(&depend_l2_table)= ); + goto out; + } + + memset(&l2meta, 0, sizeof(l2meta)); + l2meta.offset =3D offset1; + l2meta.alloc_offset =3D (depend_entry & L2E_OFFSET_MASK); + l2meta.nb_clusters =3D 1; + /* Add a ref to this cluster */ + ret =3D qcow2_update_cluster_refcount( + bs, l2meta.alloc_offset >> s->cluster_bits, + 1, false, QCOW2_DISCARD_SNAPSHOT); + if (ret < 0) { + qcow2_cache_put(s->l2_table_cache, (void **)(&depend_l2_table)= ); + goto out; + } + + ret =3D qcow2_alloc_cluster_link_l2(bs, &l2meta); + if (ret < 0) { + qcow2_cache_put(s->l2_table_cache, (void **)(&depend_l2_table)= ); + goto out; + } + + total_bytes -=3D s->cluster_size; + offset1 +=3D s->cluster_size; + depend_offset1 +=3D s->cluster_size; + + qcow2_cache_put(s->l2_table_cache, (void **)(&depend_l2_table)); + } + +out: + g_free(depend_l1_table); + return ret; +} + +int qcow2_snapshot_support_dependency(BlockDriverState *bs, int32_t *align= ment) +{ + BDRVQcow2State *s =3D bs->opaque; + if (alignment) { + *alignment =3D s->cluster_size; + } + + return 1; +} diff --git a/block/qcow2.c b/block/qcow2.c index 071dc4d..9786ba4 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -4371,6 +4371,8 @@ BlockDriver bdrv_qcow2 =3D { .bdrv_snapshot_delete =3D qcow2_snapshot_delete, .bdrv_snapshot_list =3D qcow2_snapshot_list, .bdrv_snapshot_load_tmp =3D qcow2_snapshot_load_tmp, + .bdrv_snapshot_support_dependency =3D qcow2_snapshot_support_dependenc= y, + .bdrv_snapshot_save_dependency =3D qcow2_snapshot_save_dependency, .bdrv_measure =3D qcow2_measure, .bdrv_get_info =3D qcow2_get_info, .bdrv_get_specific_info =3D qcow2_get_specific_info, diff --git a/block/qcow2.h b/block/qcow2.h index 1a84cc7..dc7ef45 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -640,6 +640,13 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs, =20 void qcow2_free_snapshots(BlockDriverState *bs); int qcow2_read_snapshots(BlockDriverState *bs); +int qcow2_snapshot_save_dependency(BlockDriverState *bs, + const char *depend_snapshot_id, + int64_t depend_offset, + int64_t depend_size, + int64_t offset, + Error **errp); +int qcow2_snapshot_support_dependency(BlockDriverState *bs, int32_t *align= ment); =20 /* qcow2-cache.c functions */ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables, --=20 2.7.4