From nobody Sun Feb 8 15:01:32 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=1661272455; cv=none; d=zohomail.com; s=zohoarc; b=NqZXvrR7tVYLsXX0+1m1EtiJ/mD12cWQrSQUK65ZhlVEudKl2Rce/SkwDc5QZz1IRV7P0x//EUghkaS9D4lqct9ERv8QJrRvB3v/binn99mmz1W6FsYHbQ0THgn3rtu2f+HjvPbu1IoQplvkIjxDD6aHzsUpz3SVVC6uGLAkldQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1661272455; 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=ZT3HKMYXzU3gtCtXMxhLD/1ixCgKIYLDqTJIpW2RHLA=; b=T4UjSdrQhm8FmDyqf1dRaKFQbQBRhT4wOOS4Z1aoM0t4g+goPnC0oVxd9dJ9jm0eCp2rT/PpylZfZ3NF+/IqzZ421yzqAnSxuxvSZK/BvBOtPQ1zbxAmZRJr7kcQuY5e1sGI4B+pqXnwrEjmdZYAbPW40K1N6iDG8dgNxXsL/8M= 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 1661272455566789.5925251085099; Tue, 23 Aug 2022 09:34:15 -0700 (PDT) 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-312-PUFEGCnyPTmrfbvIKh9ROQ-1; Tue, 23 Aug 2022 12:33:10 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 7D378382C96C; Tue, 23 Aug 2022 16:32:48 +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 657C8C15BB3; Tue, 23 Aug 2022 16:32:48 +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 5A4C21946A5E; Tue, 23 Aug 2022 16:32:48 +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 97EAC1946A67 for ; Tue, 23 Aug 2022 16:32:46 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 861C1403357; Tue, 23 Aug 2022 16:32:46 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.192.194]) by smtp.corp.redhat.com (Postfix) with ESMTP id 26ACC40315A for ; Tue, 23 Aug 2022 16:32:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1661272453; 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=ZT3HKMYXzU3gtCtXMxhLD/1ixCgKIYLDqTJIpW2RHLA=; b=dLgOvKaQNxoiS4wyXQcl9u7zK9DkwJ1UDLD6Dajgm3uSIQCau1lEwiFbu4NQrybT+JcpdM RVUfHp6XpOXsotA1ueDNSy7y193hXfkNOykaCIZWhW9D2rPZFTPrv0PXx/oLtkio9L0UDX F2aUJQ3EWTB85O7Vli94bQx6NrkjDTQ= X-MC-Unique: PUFEGCnyPTmrfbvIKh9ROQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Pavel Hrdina To: libvir-list@redhat.com Subject: [libvirt RFC 20/24] qemu_snapshot: prepare data for external snapshot deletion Date: Tue, 23 Aug 2022 18:32:23 +0200 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 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 2.85 on 10.11.54.8 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: 1661272455878100001 Content-Type: text/plain; charset="utf-8"; x-default="true" In order to save some CPU cycles we will collect all the necessary data to delete external snapshot before we even start. They will be later used by code that deletes the snapshots and updates metadata when needed. With external snapshots we need data that libvirt gets from running QEMU process so if the VM is not running we need to start paused QEMU process for the snapshot deletion and kill at afterwards. Signed-off-by: Pavel Hrdina --- src/qemu/qemu_snapshot.c | 144 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index da9b4c30f0..dade5dcea4 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -2232,6 +2232,120 @@ qemuSnapshotRevert(virDomainObj *vm, } =20 =20 +typedef struct { + virDomainMomentObj *parentSnap; + virDomainSnapshotDiskDef *snapDisk; + virDomainDiskDef *domDisk; + virDomainDiskDef *parentDomDisk; + virStorageSource *diskSrc; + virStorageSource *parentDiskSrc; + virStorageSource *prevDiskSrc; + qemuBlockJobData *job; +} qemuSnapshotDeleteExternalData; + + +static virDomainMomentObj* +qemuSnapshotFindParentSnapForDisk(virDomainMomentObj *snap, + virDomainSnapshotDiskDef *snapDisk) +{ + virDomainMomentObj *parentSnap =3D snap->parent; + + while (parentSnap) { + ssize_t i; + virDomainSnapshotDef *parentSnapdef =3D virDomainSnapshotObjGetDef= (parentSnap); + + if (!parentSnapdef) + break; + + for (i =3D 0; i < parentSnapdef->ndisks; i++) { + virDomainSnapshotDiskDef *parentSnapDisk =3D &(parentSnapdef->= disks[i]); + + if (parentSnapDisk->snapshot !=3D VIR_DOMAIN_SNAPSHOT_LOCATION= _NO && + STREQ(snapDisk->name, parentSnapDisk->name)) { + return parentSnap; + } + } + + parentSnap =3D parentSnap->parent; + } + + return NULL; +} + + +static GPtrArray* +qemuSnapshotDeleteExternalPrepare(virDomainObj *vm, + virDomainMomentObj *snap) +{ + ssize_t i; + virDomainSnapshotDef *snapdef =3D virDomainSnapshotObjGetDef(snap); + g_autoptr(GPtrArray) ret =3D g_ptr_array_new_full(0, g_free); + + for (i =3D 0; i < snapdef->ndisks; i++) { + g_autofree qemuSnapshotDeleteExternalData *data =3D NULL; + virDomainSnapshotDiskDef *snapDisk =3D &(snapdef->disks[i]); + + if (snapDisk->snapshot =3D=3D VIR_DOMAIN_SNAPSHOT_LOCATION_NO) + continue; + + data =3D g_new0(qemuSnapshotDeleteExternalData, 1); + data->snapDisk =3D snapDisk; + + data->domDisk =3D qemuDomainDiskByName(vm->def, snapDisk->name); + if (!data->domDisk) + return NULL; + + data->diskSrc =3D virStorageSourceChainLookup(data->domDisk->src, = NULL, + data->snapDisk->src->p= ath, + NULL, &data->prevDiskS= rc); + if (!data->diskSrc) + return NULL; + + if (!virStorageSourceIsSameLocation(data->diskSrc, data->snapDisk-= >src)) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("VM disk source and snapshot disk source are = not the same")); + return NULL; + } + + data->parentDomDisk =3D virDomainDiskByTarget(snapdef->parent.dom, + data->snapDisk->name); + if (!data->parentDomDisk) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("failed to find disk '%s' in snapshot VM XML"= ), + snapDisk->name); + return NULL; + } + + data->parentDiskSrc =3D data->diskSrc->backingStore; + if (!data->parentDiskSrc) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("failed to find parent disk source in backing= chain")); + return NULL; + } + + if (!virStorageSourceIsSameLocation(data->parentDiskSrc, data->par= entDomDisk->src)) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("snapshot VM disk source and parent disk sour= ce are not the same")); + return NULL; + } + + data->parentSnap =3D qemuSnapshotFindParentSnapForDisk(snap, data-= >snapDisk); + + if (data->parentSnap && !virDomainSnapshotIsExternal(data->parentS= nap)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("parent snapshot '%s' for disk '%s' is intern= al snapshot"), + snapDisk->name, + data->parentSnap->def->name); + return NULL; + } + + g_ptr_array_add(ret, g_steal_pointer(&data)); + } + + return g_steal_pointer(&ret); +} + + typedef struct _virQEMUMomentReparent virQEMUMomentReparent; struct _virQEMUMomentReparent { const char *dir; @@ -2504,9 +2618,9 @@ qemuSnapshotDeleteValidate(virDomainMomentObj *snap, } =20 if (virDomainSnapshotIsExternal(snap) && - !(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) { + (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("deletion of external disk snapshots not supporte= d")); + _("deletion of external disk snapshot with internal= children disk snapshots not supported")); return -1; } =20 @@ -2523,6 +2637,8 @@ qemuSnapshotDelete(virDomainObj *vm, int ret =3D -1; virDomainMomentObj *snap =3D NULL; bool metadata_only =3D !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_= ONLY); + bool stop_qemu =3D false; + g_autoptr(GPtrArray) externalData =3D NULL; =20 virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY | @@ -2537,6 +2653,25 @@ qemuSnapshotDelete(virDomainObj *vm, if (!metadata_only) { if (qemuSnapshotDeleteValidate(snap, flags) < 0) goto endjob; + + if (virDomainSnapshotIsExternal(snap) && + !(flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | + VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY))) { + if (!virDomainObjIsActive(vm)) { + if (qemuProcessStart(NULL, driver, vm, NULL, VIR_ASYNC_JOB= _NONE, + NULL, -1, NULL, NULL, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, + VIR_QEMU_PROCESS_START_PAUSED) < 0) { + goto endjob; + } + + stop_qemu =3D true; + } + + externalData =3D qemuSnapshotDeleteExternalPrepare(vm, snap); + if (!externalData) + goto endjob; + } } =20 if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN | @@ -2547,6 +2682,11 @@ qemuSnapshotDelete(virDomainObj *vm, } =20 endjob: + if (stop_qemu) { + qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN, + VIR_ASYNC_JOB_NONE, 0); + } + qemuDomainObjEndJob(vm); =20 return ret; --=20 2.37.2