From nobody Tue Dec 16 11:10:55 2025 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=1673027595; cv=none; d=zohomail.com; s=zohoarc; b=CxGUVVRGdm69UbON+/ojRIkms3b/MDWpqx/O+Hct7jpD07WqKCh0aODOIMeQFdHjPZ3nVDq4zDa5O6c92j1YPYNHV3/NKy4CbkcPgNyDS2eCBJa89fNxIi1lzLtgJ/bNESHGu4NjGTTBmDl1hmvngh5AzjGWBcCIIz8N6fxPMvQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1673027595; 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=bj3qcnvpAgpPPVgeRnopMV06I37gXLTPiC72ewXPh0k=; b=JrkszNiHl84JmyWKduOwp3UHmPWoeo3bdMD9NVKTL/zLQ6IFOGpy95M+CAjo4j2I0buJHhwxToLQeeooCfuHVc7lDVOMTKIpDWNwTefWTv9/yu9/Jy5km5ZIJjXmQTUpEvzK0amp+C969BZN4XrcY3K/m30luuLAHGkkJ/1fJfQ= 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 1673027595921468.9009613285557; Fri, 6 Jan 2023 09:53:15 -0800 (PST) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-373-0fmVY1JoOWWL3yRFR6eraQ-1; Fri, 06 Jan 2023 12:52:40 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 668BF2802E44; Fri, 6 Jan 2023 17:52:33 +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 511982166B30; Fri, 6 Jan 2023 17:52:33 +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 15A8C19459D7; Fri, 6 Jan 2023 17:52:33 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id D0C3C19459D3 for ; Fri, 6 Jan 2023 17:52:31 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id C6AA440C2005; Fri, 6 Jan 2023 17:52:31 +0000 (UTC) Received: from antique-work.redhat.com (ovpn-193-172.brq.redhat.com [10.40.193.172]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6234E40C2064 for ; Fri, 6 Jan 2023 17:52:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1673027595; 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=bj3qcnvpAgpPPVgeRnopMV06I37gXLTPiC72ewXPh0k=; b=U+9nYN/uQTZwcuPEN9aVWMKamp4z8FPgPip9caUN+fzffCp57sFSzogFgYtCEqMDqQAhNB 1UrJs1WbpHApVGfWC2cw5J/VjfYC95hbiOufIzqgCDQ9mJLUoahTq3N0fLRjjKtfnt05S9 szunpvyanwLgcLWKgtJHxpxqV+jHnm8= X-MC-Unique: 0fmVY1JoOWWL3yRFR6eraQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Pavel Hrdina To: libvir-list@redhat.com Subject: [libvirt PATCH v3 26/32] qemu_snapshot: update metadata when deleting snapshots Date: Fri, 6 Jan 2023 18:52:01 +0100 Message-Id: <5d47a044cf03faf1884734cbf180af17f1bd70bb.1673027206.git.phrdina@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.1 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.6 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: 1673027597334100004 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 26f962ce82..06cc6ef8c0 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