From nobody Fri Nov 21 10:12:04 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1763545719; cv=none; d=zohomail.com; s=zohoarc; b=kFnvrIX9BXKz+zlJFJErvFPkfXCYV1q/r7pwdb4KpBOxMx7aXuE/gy5eXTX+1hztw3EFD1YEBZkKzyK2q07W+WgTKQaKCeDny+Jv6/B975RMmOdgMlphrOERtILBOFIPEHyF0+oupwFGrD+gFxKW3YAI4POFyW0ipoGqwALBBfo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1763545719; h=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id:Cc; bh=YEPj5QvWsPJf4n0pF8eO7u83Undt5GuqkHUFolUVuHo=; b=AWBW3NCA/l+ZrPe32MG9ZDnoDCTJEvothM3vwC7wBdh421Z/EIdBCakqtgPlr9Alc3HzSSAU+Ul27M9xJ8N7/8HgjsArhq2YAvNpAfISZ0po5YyuDFQybEumeaIpwITRZ2gE5ySSvpjKamjtwZbU91boLT4ChcdWI+BeaAB5fv0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1763545719186604.2451243729193; Wed, 19 Nov 2025 01:48:39 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 383E944047; Wed, 19 Nov 2025 04:48:38 -0500 (EST) Received: from [172.19.199.50] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 988C244330; Wed, 19 Nov 2025 04:38:47 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id AE7C343F15; Wed, 19 Nov 2025 04:38:26 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id C15C143F8C for ; Wed, 19 Nov 2025 04:38:05 -0500 (EST) Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-449-cFeBGT26Mjilkio3XcECWg-1; Wed, 19 Nov 2025 04:38:03 -0500 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1B6F418AB300 for ; Wed, 19 Nov 2025 09:38:03 +0000 (UTC) Received: from speedmetal.openshiftapps.com (unknown [10.45.242.12]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 53FCC180049F for ; Wed, 19 Nov 2025 09:38:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1763545085; h=from:from: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; bh=YEPj5QvWsPJf4n0pF8eO7u83Undt5GuqkHUFolUVuHo=; b=PZ/+atKlqzieuy4xdo1SZ8gdRzQjBOtT/jK2xo8KaYvcM3dHO23xxyG6osLyu/Y9jBZakZ KKwJwvzBDZJ2tsZjTiHRlTjXk/Y3Nsg7YXsahX3RVim/aQo2dN2kKLOhwbpj44jC/eYxo5 rOH2OUZnQ8mCCUfz9mOdzEWmQI2XtjA= X-MC-Unique: cFeBGT26Mjilkio3XcECWg-1 X-Mimecast-MFC-AGG-ID: cFeBGT26Mjilkio3XcECWg_1763545083 To: devel@lists.libvirt.org Subject: [PATCH 7/8] qemu: backup: Add support for VIR_DOMAIN_BACKUP_BEGIN_PRESERVE_SHUTDOWN_DOMAIN Date: Wed, 19 Nov 2025 10:37:50 +0100 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: tXEcW9HSGgAiPrA0AqIdE3ZPCQtDqi-toSasSz-OpEU_1763545083 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 4LLB7ULMHDDBJVHADQ2XS56IZ7D44IB4 X-Message-ID-Hash: 4LLB7ULMHDDBJVHADQ2XS56IZ7D44IB4 X-MailFrom: pkrempa@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Peter Krempa via Devel Reply-To: Peter Krempa X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1763545720961158500 Content-Type: text/plain; charset="utf-8" From: Peter Krempa Implement the support for VIR_DOMAIN_BACKUP_BEGIN_PRESERVE_SHUTDOWN_DOMAIN which will keep the qemu process around while the backup is still running. The above is achieved by avoiding killing the qemu process in the shutdown qemu monitor event handlers. Instead 'system_reset' QMP command is issued and the domain object is transitioned into _PAUSED state in sync with what qemu does. Now once the backup job finishes (or is cancelled e.g. for pull mode backups) the backup job termination code re-asseses if the qemu process needs to be killed or the VM was re-started by un-pausing. Signed-off-by: Peter Krempa --- src/qemu/qemu_backup.c | 23 ++++++++++++- src/qemu/qemu_process.c | 76 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c index 5eed35b471..c3566bcd57 100644 --- a/src/qemu/qemu_backup.c +++ b/src/qemu/qemu_backup.c @@ -27,6 +27,7 @@ #include "qemu_checkpoint.h" #include "qemu_command.h" #include "qemu_security.h" +#include "qemu_process.h" #include "storage_source.h" #include "storage_source_conf.h" @@ -559,6 +560,8 @@ qemuBackupJobTerminate(virDomainObj *vm, { qemuDomainObjPrivate *priv =3D vm->privateData; g_autoptr(virQEMUDriverConfig) cfg =3D NULL; + /* some flags need to be probed after the private data is freed */ + unsigned int apiFlags =3D priv->backup->apiFlags; size_t i; for (i =3D 0; i < priv->backup->ndisks; i++) { @@ -623,6 +626,23 @@ qemuBackupJobTerminate(virDomainObj *vm, if (vm->job->asyncJob =3D=3D VIR_ASYNC_JOB_BACKUP) virDomainObjEndAsyncJob(vm); + + /* Users can request that the VM is preserved after a guest OS shutdow= n for + * the duration of the backup. This is the place where we need to chec= k if + * this happened and optionally terminate the VM if the guest OS is st= ill + * shut down */ + if (apiFlags & VIR_DOMAIN_BACKUP_BEGIN_PRESERVE_SHUTDOWN_DOMAIN) { + int reason =3D -1; + virDomainState state =3D virDomainObjGetState(vm, &reason); + + VIR_DEBUG("state: '%u', reason:'%d'", state, reason); + + if (state =3D=3D VIR_DOMAIN_SHUTDOWN || + (state =3D=3D VIR_DOMAIN_PAUSED && reason =3D=3D VIR_DOMAIN_PA= USED_SHUTTING_DOWN)) { + VIR_DEBUG("backup job finished terminating the previously shut= down VM"); + ignore_value(qemuProcessShutdownOrReboot(vm)); + } + } } @@ -766,7 +786,8 @@ qemuBackupBegin(virDomainObj *vm, int ret =3D -1; g_autoptr(qemuFDPassDirect) fdpass =3D NULL; - virCheckFlags(VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL, -1); + virCheckFlags(VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL | + VIR_DOMAIN_BACKUP_BEGIN_PRESERVE_SHUTDOWN_DOMAIN, -1); if (!(def =3D virDomainBackupDefParseString(backupXML, priv->driver->x= mlopt, 0))) return -1; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index bbd9859ef4..4769d6694d 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -597,6 +597,51 @@ qemuProcessFakeReboot(void *opaque) } +static void +qemuProcessResetPreservedDomain(void *opaque) +{ + virDomainObj *vm =3D opaque; + qemuDomainObjPrivate *priv =3D vm->privateData; + virQEMUDriver *driver =3D priv->driver; + virObjectEvent *event =3D NULL; + int rc; + + VIR_DEBUG("vm=3D%p", vm); + + virObjectLock(vm); + if (virDomainObjBeginJob(vm, VIR_JOB_MODIFY) < 0) + goto cleanup; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("guest unexpectedly quit")); + goto endjob; + } + + qemuDomainObjEnterMonitor(vm); + rc =3D qemuMonitorSystemReset(priv->mon); + qemuDomainObjExitMonitor(vm); + + /* A guest-initiated OS shutdown completes qemu pauses the CPUs thus w= e need + * to also update the state */ + virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_SHUTTING= _DOWN); + event =3D virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_SUSPENDED_G= UEST_SHUTDOWN); + + if (rc < 0) + goto endjob; + + endjob: + virDomainObjEndJob(vm); + + cleanup: + qemuDomainSaveStatus(vm); + virDomainObjEndAPI(&vm); + virObjectEventStateQueue(driver->domainEventState, event); +} + + /** * qemuProcessShutdownOrReboot: * @vm: domain object @@ -630,6 +675,37 @@ qemuProcessShutdownOrReboot(virDomainObj *vm) virObjectUnref(vm); } + return false; + } else if (priv->backup && priv->backup->apiFlags & VIR_DOMAIN_BACKUP_= BEGIN_PRESERVE_SHUTDOWN_DOMAIN) { + /* The users can request that while the 'backup' job is active (and + * possibly also other block jobs in the future) the qemu process = will + * be kept around even when the guest OS shuts down, evem when the + * requested action is to terminate the VM. + * + * In such case we'll reset the VM and keep it paused with proper = state + * so that users can re-start it if needed. + * + * Terminating of the qemu process once the backup job is + * completed/terminated (unless the guest was unpaused/restarted) = is + * then done in qemuBackupJobTerminate by invoking this function o= nce + * again. + */ + g_autofree char *name =3D g_strdup_printf("reset-%s", vm->def->nam= e); + virThread th; + + VIR_DEBUG("preserving qemu process while backup job is running"); + + virObjectRef(vm); + if (virThreadCreateFull(&th, + false, + qemuProcessResetPreservedDomain, + name, + false, + vm) < 0) { + VIR_WARN("Failed to create thread to reset shutdown VM"); + virObjectUnref(vm); + } + return false; } else { ignore_value(qemuProcessKill(vm, VIR_QEMU_PROCESS_KILL_NOWAIT)); --=20 2.51.1