From nobody Mon Feb 2 05:57:17 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=1769422741; cv=none; d=zohomail.com; s=zohoarc; b=iCZ4BxZChTpw/t4qhpX53eKWDuQ1eH/0rx+ud8UO3EviBpEw0rrM8pn1kx3gW79GE4kFBVh6bHYGOIqLsLR1222YhFg3I+XPTI8kjTzbqGL9AyVHzSjh0CKf7WImPWMetqwcb0n6Leq6XhBJmy51STjXFGv2ZTyF4cWjNXq3KA4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1769422741; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:Subject:Subject:To:To:Message-Id; bh=Ubn79g4soXYFTpKKBNGSUsmYOzhm9sEe8ysWkDnXGqs=; b=L1s8uqf4SYvzmRu50kf0g5KWTDn5nZRslMCxU4rERZaWxEiCMs3BMXlBkPpc15FkQMJtAeZh+/uw5kufmRqQyYPP08vZ6iUMRBL55H8x1LajLcm6IYfT+U7H1l3m1B8Jhj24a1cuHmMa0ZO4P1yLpQhQKrzW20gMMqEmjs/m5Yw= 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 1769422741377264.5430788317931; Mon, 26 Jan 2026 02:19:01 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id D30CE418B7; Mon, 26 Jan 2026 05:19:00 -0500 (EST) Received: from [172.19.199.3] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 4EDF743DF9; Mon, 26 Jan 2026 05:17:13 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id A8D88417EB; Mon, 26 Jan 2026 05:10:49 -0500 (EST) Received: from mx1.osci.io (polly.osci.io [8.43.85.229]) (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 16D18417E1 for ; Mon, 26 Jan 2026 05:10:49 -0500 (EST) Received: by mx1.osci.io (Postfix, from userid 995) id DABD4207E0; Mon, 26 Jan 2026 05:10:48 -0500 (EST) Received: from smtp-bc0c.mail.infomaniak.ch (smtp-bc0c.mail.infomaniak.ch [IPv6:2001:1600:4:17::bc0c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-256) server-digest SHA256) (No client certificate requested) by mx1.osci.io (Postfix) with ESMTPS id B2BAF207D6 for ; Mon, 26 Jan 2026 05:10:47 -0500 (EST) 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 4f040Y4l8Rz6JR; Mon, 26 Jan 2026 11:05:17 +0100 (CET) Received: from unknown by smtp-3-0000.mail.infomaniak.ch (Postfix) with ESMTPA id 4f040Y0tHJzqR7; Mon, 26 Jan 2026 11:05:17 +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=-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 X-Greylist: delayed 326 seconds by postgrey-1.37 at polly.osci.io; Mon, 26 Jan 2026 05:10:47 EST DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gugod.fr; s=20250112; t=1769421917; bh=Ubn79g4soXYFTpKKBNGSUsmYOzhm9sEe8ysWkDnXGqs=; h=From:To:Cc:Subject:Date:From; b=gvHQDYPhNy1Y6Pkw4ubFhGIEpRSagy6SSbLfKgVf70ylsMs/5MONIf10yMDVFDr4U I+XFLfYtbRXueWiJlsfmfIX8/7ZjhCffvr+agXNFddylFt763MgGCOTszAeNSl3Kn+ 8S7tXobA3AXYh4kNEQKYc0gN/JZZNxUqzLWWqYGxQgoaLOvqFcaYjyZTchrkn4KvvZ QP+I4kdxOEvFCySlMPIgb6m8gS4IcFZUEoKBdFP9RAPdngahnYgksYkqd/MOYLuNHB RbTi98aDLjYy1nIFuTNjGBxDZqe08IcdiT/rSIuaFiB97zJCMK4asxrnI3q8tSka+1 TqGGflyNtu3bA== To: devel@lists.libvirt.org Subject: [PATCH] qemu: migration: Call hook script on source host at migration start Date: Mon, 26 Jan 2026 11:05:13 +0100 Message-Id: <20260126100513.59606-1-guy.godfroy@gugod.fr> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Infomaniak-Routing: alpha X-MailFrom: SRS0=NBqC=77=gugod.fr=guy.godfroy@osci.io X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation Message-ID-Hash: OS5O3K3OBPHIX74LPSCPEYIX3JSTG4MU X-Message-ID-Hash: OS5O3K3OBPHIX74LPSCPEYIX3JSTG4MU X-Mailman-Approved-At: Mon, 26 Jan 2026 10:17:09 +0000 CC: 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: 1769422743032154100 Content-Type: text/plain; charset="utf-8" Currently, the qemu hook script with the "migrate" operation is only called on the destination host at the beginning of incoming migration. This makes it impossible for the source host to prepare for migration, for example to change storage locks from exclusive to shared mode when using shared LVM storage with lvmlockd. Add a hook call on the source host at the beginning of outgoing migration. The hook is called with "source" as the extra argument to distinguish it from the destination hook which uses "-". The same change is also applied to the libxl driver for consistency. Resolves: https://gitlab.com/libvirt/libvirt/-/issues/37 Signed-off-by: Guy Godfroy --- docs/hooks.rst | 36 ++++++++++++++++++++++++++++++++---- src/libxl/libxl_migration.c | 17 +++++++++++++++++ src/qemu/qemu_migration.c | 17 +++++++++++++++++ 3 files changed, 66 insertions(+), 4 deletions(-) diff --git a/docs/hooks.rst b/docs/hooks.rst index e1745b8cc7..4c7cac56ba 100644 --- a/docs/hooks.rst +++ b/docs/hooks.rst @@ -244,7 +244,7 @@ operation. There is no specific operation to indicate a= "restart" is occurring. =20 =20 - :since:`Since 0.9.11`, the qemu hook script is also called at the begin= ning - of incoming migration. It is called as: + of incoming migration on the **destination** host. It is called as: =20 :: =20 @@ -257,6 +257,18 @@ operation. There is no specific operation to indicate = a "restart" is occurring. is not valid, incoming migration will be canceled. This hook may be use= d, e.g., to change location of disk images for incoming domains. =20 +- :since:`Since 12.1.0`, the qemu hook script is also called at the begin= ning + of outgoing migration on the **source** host. It is called as: + + :: + + /etc/libvirt/hooks/qemu guest_name migrate begin source + + with domain XML sent to standard input of the script. Unlike the destin= ation + hook, this script does not act as a filter and any output is ignored. I= f the + 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. + - :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: @@ -417,7 +429,7 @@ operation. There is no specific operation to indicate a= "restart" is occurring. /etc/libvirt/hooks/libxl guest_name release end - =20 - :since:`Since 2.1.0`, the libxl hook script is also called at the begin= ning - of incoming migration. It is called as: + of incoming migration on the **destination** host. It is called as: =20 :: =20 @@ -430,6 +442,18 @@ operation. There is no specific operation to indicate = a "restart" is occurring. is not valid, incoming migration will be canceled. This hook may be use= d, e.g., to change location of disk images for incoming domains. =20 +- :since:`Since 12.1.0`, the libxl hook script is also called at the begi= nning + of outgoing migration on the **source** host. It is called as: + + :: + + /etc/libvirt/hooks/libxl guest_name migrate begin source + + with domain XML sent to standard input of the script. Unlike the destin= ation + hook, this script does not act as a filter and any output is ignored. I= f the + 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. + - :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 @@ -566,10 +590,14 @@ Migration of a QEMU guest involves running hook scrip= ts on both the source and destination hosts: =20 #. At the beginning of the migration, the *qemu* hook script on the - **destination** host is executed with the "migrate" operation. + **source** host is executed with the "migrate" operation and "source" + as the extra argument (:since:`since 12.1.0`). This allows the source + host to prepare for migration, e.g., changing storage locks. +#. Then, the *qemu* hook script on the **destination** host is executed + with the "migrate" operation. #. Before QEMU process is spawned, the two operations ("prepare" and "star= t") called for domain start are executed on **destination** host. -#. If both of these hook script executions exit successfully (exit status = 0), +#. 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. #. The QEMU guest is then migrated to the destination host. diff --git a/src/libxl/libxl_migration.c b/src/libxl/libxl_migration.c index f5dee7627b..76f3c7ceb7 100644 --- a/src/libxl/libxl_migration.c +++ b/src/libxl/libxl_migration.c @@ -411,6 +411,23 @@ libxlDomainMigrationSrcBegin(virConnectPtr conn, if (!libxlDomainMigrationIsAllowed(def)) goto endjob; =20 + /* Call hook to allow source host to prepare for migration */ + if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) { + g_autofree char *hookxml =3D NULL; + int hookret; + + if (!(hookxml =3D virDomainDefFormat(def, driver->xmlopt, + VIR_DOMAIN_DEF_FORMAT_SECURE))) + goto endjob; + + hookret =3D virHookCall(VIR_HOOK_DRIVER_LIBXL, def->name, + VIR_HOOK_LIBXL_OP_MIGRATE, VIR_HOOK_SUBOP_BE= GIN, + "source", hookxml, NULL); + + if (hookret < 0) + goto endjob; + } + xml =3D virDomainDefFormat(def, driver->xmlopt, VIR_DOMAIN_DEF_FORMAT_= SECURE); /* Valid xml means success! EndJob in the confirm phase */ if (xml) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 6dd022163b..60e370319c 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2791,6 +2791,23 @@ qemuMigrationSrcBeginPhase(virQEMUDriver *driver, if (!qemuMigrationSrcIsAllowed(vm, true, vm->job->asyncJob, flags)) return NULL; =20 + /* Call hook to allow source host to prepare for migration */ + if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { + g_autofree char *xml =3D NULL; + int hookret; + + if (!(xml =3D qemuDomainDefFormatLive(driver, priv->qemuCaps, vm->= def, + priv->origCPU, false, true))) + return NULL; + + hookret =3D virHookCall(VIR_HOOK_DRIVER_QEMU, vm->def->name, + VIR_HOOK_QEMU_OP_MIGRATE, VIR_HOOK_SUBOP_BEG= IN, + "source", xml, NULL); + + if (hookret < 0) + return NULL; + } + if (!(flags & (VIR_MIGRATE_UNSAFE | VIR_MIGRATE_OFFLINE)) && !qemuMigrationSrcIsSafe(vm, migrate_disks, flags)) return NULL; --=20 2.34.1