From nobody Mon Feb 9 03:52:54 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1672919276; cv=none; d=zohomail.com; s=zohoarc; b=fjbv/Ab8nrWIc53rQLje85G7UNHpv3QounF527gDAsW1D7SNVp7lZlt8wgusBSZKtksbfEbYHa+Aqt4CNJ855xYcw4eh+kFtZl0w/VaA06F5nU6AQ2lrS7DUs/VvCsKOaoMmy68y+EMKqpqgvX4/oarFTfaylK2d+413MPyNIQ0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1672919276; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=grEn7OXW4HfTDb9rn6QJl7ReToE7eIFlSjngEQ5bPaE=; b=MR9D0ap4ejuJvQKQVY8WCUXlzj5cPjMoYtrx/VI0mIrNWxmY+ziYGU1YoOagsRgdoUKzz6gyG5IzWgaZbPsDCabr9ZgZ56s/GQGjVO8nRcLg88Y5QoY/qB1QinQOgqwNGHznNwFI0ooXwEUemUjdltTrxbCNCkjBWGagyUEvHQk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by mx.zohomail.com with SMTPS id 1672919276892973.595768262811; Thu, 5 Jan 2023 03:47:56 -0800 (PST) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-621-H6gqCO9cMcm_zLlwIFPJ_Q-1; Thu, 05 Jan 2023 06:47:51 -0500 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id DCB8F858F09; Thu, 5 Jan 2023 11:47:46 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (unknown [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id C8379492B06; Thu, 5 Jan 2023 11:47:46 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id B0F74194658C; Thu, 5 Jan 2023 11:47:46 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id DB16819465B7 for ; Thu, 5 Jan 2023 11:47:33 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id B45BC40147D; Thu, 5 Jan 2023 11:47:33 +0000 (UTC) Received: from localhost.localdomain (ovpn-194-38.brq.redhat.com [10.40.194.38]) by smtp.corp.redhat.com (Postfix) with ESMTP id 53A62492D8B for ; Thu, 5 Jan 2023 11:47:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1672919275; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=grEn7OXW4HfTDb9rn6QJl7ReToE7eIFlSjngEQ5bPaE=; b=U/nTbjOeERkKMXsDJKvt545u+hCoFYUSoVzRWwF2c8H0fd3T0IoFOP40orV4ym082/247k fUPSlFZGKibsz+NujM90NX4aDpO+9SaN7fco7CcmcLhh1iwE7ELRAr9qVK/fmzF/yFmYcc JCmgUDjmOo/idkuwXsS6ilV9q+xXOCI= X-MC-Unique: H6gqCO9cMcm_zLlwIFPJ_Q-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Pavel Hrdina To: libvir-list@redhat.com Subject: [libvirt PATCH v2 26/31] qemu_snapshot: update metadata when deleting snapshots Date: Thu, 5 Jan 2023 12:47:02 +0100 Message-Id: <200850958a491e5cbe03d978189b9b1ce6395373.1672918676.git.phrdina@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.10 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 3.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1672919279087100004 Content-Type: text/plain; charset="utf-8"; x-default="true" With external snapshots we need to modify the metadata bit more then what is required for internal snapshots. Mainly the storage source location changes with every external snapshot. This means that if we delete non-leaf snapshot we need to update all children snapshots and modify the disk sources for all affected disks. Signed-off-by: Pavel Hrdina Reviewed-by: Peter Krempa --- src/qemu/qemu_snapshot.c | 165 +++++++++++++++++++++++++++++++++++---- 1 file changed, 148 insertions(+), 17 deletions(-) diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index 6ca61301a7..094d56b13d 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -2410,6 +2410,127 @@ qemuSnapshotChildrenReparent(void *payload, } =20 =20 +typedef struct _qemuSnapshotUpdateDisksData qemuSnapshotUpdateDisksData; +struct _qemuSnapshotUpdateDisksData { + virDomainMomentObj *snap; + virDomainObj *vm; + int error; +}; + + +/** + * qemuSnapshotUpdateDisksSingle: + * @snap: snapshot object where we are updating disks + * @def: active or inactive definition from @snap + * @parentDef: parent snapshot object of snapshot that we are deleting + * @snapDisk: snapshot disk definition from snapshot we are deleting + * + * When deleting external snapshots we need to modify remaining metadata + * files stored by libvirt. + * + * The first part updates only metadata for external snapshots where we ne= ed + * to update the disk source in the domain definition stored within the + * snapshot metadata. There is no need to do it for internal snapshots as + * they don't create new disk files. + * + * The second part needs to be done for all metadata files. Both internal = and + * external snapshot metadata files have in the domain definition backingS= tore + * that could contain the deleted disk. + * + * Returns 0 on success, -1 on error. + * */ +static int +qemuSnapshotUpdateDisksSingle(virDomainMomentObj *snap, + virDomainDef *def, + virDomainDef *parentDef, + virDomainSnapshotDiskDef *snapDisk) +{ + virDomainDiskDef *disk =3D NULL; + + if (!(disk =3D qemuDomainDiskByName(def, snapDisk->name))) + return -1; + + if (virDomainSnapshotIsExternal(snap)) { + virDomainDiskDef *parentDisk =3D NULL; + + if (!(parentDisk =3D qemuDomainDiskByName(parentDef, snapDisk->nam= e))) + return -1; + + if (virStorageSourceIsSameLocation(snapDisk->src, disk->src)) { + virObjectUnref(disk->src); + disk->src =3D virStorageSourceCopy(parentDisk->src, false); + } + } + + if (disk->src->backingStore) { + virStorageSource *cur =3D disk->src; + virStorageSource *next =3D disk->src->backingStore; + + while (next) { + if (virStorageSourceIsSameLocation(snapDisk->src, next)) { + cur->backingStore =3D next->backingStore; + next->backingStore =3D NULL; + virObjectUnref(next); + break; + } + + cur =3D next; + next =3D cur->backingStore; + } + } + + return 0; +} + + +static int +qemuSnapshotDeleteUpdateDisks(void *payload, + const char *name G_GNUC_UNUSED, + void *opaque) +{ + virDomainMomentObj *snap =3D payload; + qemuSnapshotUpdateDisksData *data =3D opaque; + qemuDomainObjPrivate *priv =3D data->vm->privateData; + virQEMUDriver *driver =3D priv->driver; + g_autoptr(virQEMUDriverConfig) cfg =3D virQEMUDriverGetConfig(driver); + virDomainSnapshotDef *snapdef =3D virDomainSnapshotObjGetDef(data->sna= p); + ssize_t i; + + for (i =3D 0; i < snapdef->ndisks; i++) { + virDomainSnapshotDiskDef *snapDisk =3D &(snapdef->disks[i]); + + if (snapDisk->snapshot =3D=3D VIR_DOMAIN_SNAPSHOT_LOCATION_NO) + continue; + + if (qemuSnapshotUpdateDisksSingle(snap, snap->def->dom, + data->snap->def->dom, snapDisk) = < 0) { + data->error =3D -1; + } + + if (snap->def->inactiveDom) { + virDomainDef *dom =3D data->snap->def->inactiveDom; + + if (!dom) + dom =3D data->snap->def->dom; + + if (qemuSnapshotUpdateDisksSingle(snap, snap->def->inactiveDom, + dom, snapDisk) < 0) { + data->error =3D -1; + } + } + } + + if (qemuDomainSnapshotWriteMetadata(data->vm, + snap, + driver->xmlopt, + cfg->snapshotDir) < 0) { + data->error =3D -1; + } + + return 0; +} + + /* Deleting external snapshot is started by running qemu block-commit job. * We need to wait for all block-commit jobs to be 'ready' or 'pending' to * continue with external snapshot deletion. */ @@ -2612,24 +2733,34 @@ qemuSnapshotDiscardMetadata(virDomainObj *vm, virQEMUDriver *driver =3D priv->driver; g_autoptr(virQEMUDriverConfig) cfg =3D virQEMUDriverGetConfig(driver); g_autofree char *snapFile =3D NULL; + int ret =3D 0; =20 - if (update_parent) { - if (snap->nchildren) { - virQEMUMomentReparent rep; + if (update_parent && snap->nchildren) { + virQEMUMomentReparent rep; + qemuSnapshotUpdateDisksData data; =20 - rep.dir =3D cfg->snapshotDir; - rep.parent =3D snap->parent; - rep.vm =3D vm; - rep.err =3D 0; - rep.xmlopt =3D driver->xmlopt; - rep.writeMetadata =3D qemuDomainSnapshotWriteMetadata; - virDomainMomentForEachChild(snap, - qemuSnapshotChildrenReparent, - &rep); - if (rep.err < 0) - return -1; - virDomainMomentMoveChildren(snap, snap->parent); - } + rep.dir =3D cfg->snapshotDir; + rep.parent =3D snap->parent; + rep.vm =3D vm; + rep.err =3D 0; + rep.xmlopt =3D driver->xmlopt; + rep.writeMetadata =3D qemuDomainSnapshotWriteMetadata; + virDomainMomentForEachChild(snap, + qemuSnapshotChildrenReparent, + &rep); + if (rep.err < 0) + ret =3D -1; + + data.snap =3D snap; + data.vm =3D vm; + data.error =3D 0; + virDomainMomentForEachDescendant(snap, + qemuSnapshotDeleteUpdateDisks, + &data); + if (data.error < 0) + ret =3D -1; + + virDomainMomentMoveChildren(snap, snap->parent); } =20 snapFile =3D g_strdup_printf("%s/%s/%s.xml", cfg->snapshotDir, vm->def= ->name, @@ -2663,7 +2794,7 @@ qemuSnapshotDiscardMetadata(virDomainObj *vm, virDomainMomentDropParent(snap); virDomainSnapshotObjListRemove(vm->snapshots, snap); =20 - return 0; + return ret; } =20 =20 --=20 2.39.0