From nobody Tue Mar 24 01:41:05 2026 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=1774103429; cv=none; d=zohomail.com; s=zohoarc; b=IK+SDQAT0D+3DeUD3JVsUPJ3N+fg3rJNRWS+oPS2kx/A9QXF4HaXNUgnWSK55ZTLEjA+9PSr9/nLBfARg41aL/pFX46Uoq3pNWpQMl8L8lpPcIqrVqzfuY9Q9Fbjh1+Oc7h5lSXjLf9F0kSYI1lIW1IUaototMG8i2oUS6nDWEw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1774103429; h=Content-Transfer-Encoding:Cc:Cc: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; bh=IqhZXr7/M22XCssEs4Dcr+Q8CFg3GZ3h+nsIXcBO4Fc=; b=eHIY1OcyR9ATlrzckTdVNb3/muNYj1IiMJMjxMvmX18w4NW1hZxzkWbtMtWed3IPaM1bLyEuNrFo8zR3WRHlqgE4mNS3Ze73zDekJpFQSk7AvMYNlvLFya4eIlDXsSLDvVBRakAV13Cz08vGAhHtPRDdJvUd4V8g50R/eAq7tgQ= 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 1774103429384896.101480459795; Sat, 21 Mar 2026 07:30:29 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 8D0D94194A; Sat, 21 Mar 2026 10:30:27 -0400 (EDT) Received: from [172.19.199.12] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 4F36841AFB; Sat, 21 Mar 2026 10:29:44 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id 3E4F2417D6; Sat, 21 Mar 2026 10:29:40 -0400 (EDT) Received: from smtp-8fa8.mail.infomaniak.ch (smtp-8fa8.mail.infomaniak.ch [83.166.143.168]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 56B4A41831 for ; Sat, 21 Mar 2026 10:29:39 -0400 (EDT) Received: from smtp-3-0000.mail.infomaniak.ch (smtp-3-0000.mail.infomaniak.ch [10.4.36.107]) by smtp-3-3000.mail.infomaniak.ch (Postfix) with ESMTPS id 4fdLt73PRVzGZ2; Sat, 21 Mar 2026 15:10:07 +0100 (CET) Received: from unknown by smtp-3-0000.mail.infomaniak.ch (Postfix) with ESMTPA id 4fdLt703Swz1LT; Sat, 21 Mar 2026 15:10:06 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HELO_MISC_IP,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=gugod.fr; s=20250112; t=1774102207; bh=IqhZXr7/M22XCssEs4Dcr+Q8CFg3GZ3h+nsIXcBO4Fc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sUhb4qGHs7spdp2wUVk9PQSpKbWPLwFAXS+UO8HOXPmg22puDQN2jnptFdXOVVYkq m9mnnBPkVMGCOHd2B+Wi4WdKOeMg8Tm4EgDl66AFhWPSyWZb3d6PXVY54Pnv//QyrG x9f1ms8oD4SR6T+0dgSlSAn1kOhUjbxkRJgNkRJwiRXZFAEqRbw7A8++PfaNsdxbGa +DyzGHNoXeye23nU4Jv3BrHabt0nLk5EXtUepCy59rify1HTB1aOR7zj5KgAzmsY2a DgnhalvI+zIv36YvigU+t8Q2pY6IwZSZpCyYy/anN9Zf8CgIHRryQnowWOCc4iYoga i91OTOgu18V9Q== To: devel@lists.libvirt.org Subject: [PATCHv2 4/4] qemu, libxl: migration: Call hook script on source host when migration fails Date: Sat, 21 Mar 2026 15:09:04 +0100 Message-ID: <20260321140923.23807-5-guy.godfroy@gugod.fr> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260321140923.23807-1-guy.godfroy@gugod.fr> References: <20260321140923.23807-1-guy.godfroy@gugod.fr> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Infomaniak-Routing: alpha Message-ID-Hash: WDLHI4ANLFN2I2UFNK2N6XGDIA36JI7P X-Message-ID-Hash: WDLHI4ANLFN2I2UFNK2N6XGDIA36JI7P X-MailFrom: guy.godfroy@gugod.fr 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 CC: pkrempa@redhat.com, Guy Godfroy 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: Guy Godfroy via Devel Reply-To: Guy Godfroy X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1774103431943154100 Content-Type: text/plain; charset="utf-8" When outgoing migration fails after the "migrate-outgoing begin source" hook was executed, the source host has no way to be notified and cannot undo changes made in the begin hook (e.g., restoring exclusive storage locks after switching to shared mode). Add a hook call on the source host when migration fails, using the "migrate-outgoing" operation with "end" as the sub-operation and "failed" as the extra argument. The hook output and return code are ignored since migration has already failed. For qemu, the fail hook is called in the confirm phase when retcode !=3D 0. For libxl, the fail hook is called in both the perform phase (when perform fails, since confirm is not called) and the confirm phase when cancelled is true. Resolves: https://gitlab.com/libvirt/libvirt/-/issues/37 Signed-off-by: Guy Godfroy --- docs/hooks.rst | 27 ++++++++++++++++++++++++++- src/libxl/libxl_migration.c | 22 ++++++++++++++++++++++ src/qemu/qemu_migration.c | 12 ++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/docs/hooks.rst b/docs/hooks.rst index cff1711536..4fe02b7c28 100644 --- a/docs/hooks.rst +++ b/docs/hooks.rst @@ -269,6 +269,17 @@ operation. There is no specific operation to indicate = a "restart" is occurring. script returns failure, the migration will be canceled. This hook may b= e used, e.g., to change storage lock mode from exclusive to shared before migra= tion. =20 +- :since:`Since 12.3.0`, when migration fails on the source host, the qemu + hook script is called to allow the source host to undo any changes made= in + the begin hook. It is called as: + + :: + + /etc/libvirt/hooks/qemu guest_name migrate-outgoing end failed + + with domain XML sent to standard input of the script. Any output and the + return code of the script are ignored. + - :since:`Since 1.2.9`, the qemu hook script is also called when restorin= g a saved image either via the API or automatically when restoring a manage= d save machine. It is called as: @@ -454,6 +465,17 @@ operation. There is no specific operation to indicate = a "restart" is occurring. script returns failure, the migration will be canceled. This hook may b= e used, e.g., to change storage lock mode from exclusive to shared before migra= tion. =20 +- :since:`Since 12.3.0`, when migration fails on the source host, the lib= xl + hook script is called to allow the source host to undo any changes made= in + the begin hook. It is called as: + + :: + + /etc/libvirt/hooks/libxl guest_name migrate-outgoing end failed + + with domain XML sent to standard input of the script. Any output and the + return code of the script are ignored. + - :since:`Since 6.5.0`, you can also place several hook scripts in the directory ``/etc/libvirt/hooks/libxl.d/``. They are executed in alphabe= tical order after main script. In this case each script also acts as filter a= nd can @@ -599,7 +621,10 @@ destination hosts: called for domain start are executed on **destination** host. #. If all of these hook script executions exit successfully (exit status 0= ), the migration continues. Any other exit code indicates failure, and the - migration is aborted. + migration is aborted. If migration is aborted, the *qemu* hook script on + the **source** host is executed with the "migrate-outgoing" operation, + "end" sub-operation, and "failed" as the extra argument + (:since:`since 12.3.0`). The return code is ignored. #. The QEMU guest is then migrated to the destination host. #. Unless an error occurs during the migration process, the *qemu* hook sc= ript on the **source** host is then executed with the "stopped" and "release" diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c index be51cfd316..4e7e2bdbe9 100644 --- a/src/libxl/libxl_migration.c +++ b/src/libxl/libxl_migration.c @@ -1237,6 +1237,17 @@ libxlDomainMigrationSrcPerform(libxlDriverPrivate *d= river, VIR_WARN("Unable to release lease on %s", vm->def->name); } } else { + /* Call hook to notify source host that migration failed */ + if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) { + g_autofree char *hookxml =3D NULL; + + if ((hookxml =3D virDomainDefFormat(vm->def, driver->xmlopt, + VIR_DOMAIN_DEF_FORMAT_SECURE= ))) + virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name, + VIR_HOOK_LIBXL_OP_MIGRATE_OUTGOING, VIR_HOOK_S= UBOP_END, + "failed", hookxml, NULL); + } + /* * Confirm phase will not be executed if perform fails. End the * job started in begin phase. @@ -1358,6 +1369,17 @@ libxlDomainMigrationSrcConfirm(libxlDriverPrivate *d= river, virObjectEvent *event =3D NULL; =20 if (cancelled) { + /* Call hook to notify source host that migration failed */ + if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) { + g_autofree char *hookxml =3D NULL; + + if ((hookxml =3D virDomainDefFormat(vm->def, driver->xmlopt, + VIR_DOMAIN_DEF_FORMAT_SECURE= ))) + virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name, + VIR_HOOK_LIBXL_OP_MIGRATE_OUTGOING, VIR_HOOK_S= UBOP_END, + "failed", hookxml, NULL); + } + /* Resume lock process that was paused in MigrationSrcPerform */ virDomainLockProcessResume(driver->lockManager, "xen:///system", diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index e9ce2d8b8b..afb5161ea3 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -4218,6 +4218,18 @@ qemuMigrationSrcConfirmPhase(virQEMUDriver *driver, qemuDomainSetMaxMemLock(vm, 0, &priv->preMigrationMemlock); } =20 + /* Call hook to notify source host that migration failed */ + if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { + g_autofree char *xml =3D NULL; + + if ((xml =3D qemuDomainDefFormatLive(driver, priv->qemuCaps, + vm->def, priv->origCPU, + false, true))) + virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name, + VIR_HOOK_QEMU_OP_MIGRATE_OUTGOING, VIR_HOOK_SU= BOP_END, + "failed", xml, NULL); + } + qemuDomainSaveStatus(vm); virErrorRestore(&orig_err); } --=20 2.53.0