]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Add support for keeping VM running when panic notifier is used
authorPeter Krempa <pkrempa@redhat.com>
Wed, 22 Jul 2026 15:13:15 +0000 (17:13 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Mon, 27 Jul 2026 11:38:37 +0000 (13:38 +0200)
Some guest OSes (e.g. windows) can do an internal crash dump and reboot
after a crash. They unfortunately notify the OS before doing the crash
dump though so we need a new possibility for the <on_crash> action to
keep the VM as is.

This patch introduces 'preserve-running' mode for on_crash and wires it
up into the qemu driver.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
12 files changed:
docs/formatdomain.rst
include/libvirt/libvirt-domain.h
src/conf/domain_conf.c
src/conf/schemas/domaincommon.rng
src/libxl/libxl_conf.c
src/libxl/libxl_domain.c
src/qemu/qemu_driver.c
src/qemu/qemu_process.c
tests/qemuxmlconfdata/async-teardown.x86_64-latest.xml
tests/qemuxmlconfdata/async-teardown.xml
tests/qemuxmlconftest.c
tools/virsh-domain.c

index a861f9f17744cf7230406a889498c748719af1c1..fa5b62200bfed1fb5f37f1846575f4055415cd06 100644 (file)
@@ -2044,6 +2044,9 @@ The ``on_crash`` event supports these additional actions :since:`since 0.8.4`.
 ``coredump-restart``
    The crashed domain's core will be dumped, and then the domain will be
    restarted with the same configuration
+``preserve-running``
+   The crashed domain will continue to run. This is useful if the guest OS can
+   do an internal crash dump and reboot itself. :since:`Since 12.6.0`
 
 :since:`Since 3.9.0`, the lifecycle events can be configured via the
 `virDomainSetLifecycleAction <html/libvirt-libvirt-domain.html#virDomainSetLifecycleAction>`__
index 5b67f8f89738904dd36755ed4aba1518c76fe5d1..f4dfe9fb1a9d3bb5679fcc2a1ec9cdcff1fb4882 100644 (file)
@@ -8228,6 +8228,7 @@ typedef enum {
     VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE = 3, /* (Since: 3.9.0) */
     VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY = 4, /* (Since: 3.9.0) */
     VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART = 5, /* (Since: 3.9.0) */
+    VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING = 6, /* (Since: 12.6.0) */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_LIFECYCLE_ACTION_LAST /* (Since: 3.9.0) */
index ab5138acbcbc354ecc092e10eb64056bf08a6e3b..45235d74bc90aa72a7e59a9740207b6c5d1aded8 100644 (file)
@@ -303,6 +303,7 @@ VIR_ENUM_IMPL(virDomainLifecycleAction,
               "preserve",
               "coredump-destroy",
               "coredump-restart",
+              "preserve-running",
 );
 
 VIR_ENUM_IMPL(virDomainLockFailure,
@@ -5534,6 +5535,7 @@ virDomainDefLifecycleActionAllowed(virDomainLifecycle type,
             return true;
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
             break;
         }
         break;
index 121e4e06a6677da9d6b983ccae791c6dcf414000..81ffbfc2fa32e3b8f1825dbf1d34367bd2f72472 100644 (file)
       destroy: The domain is cleaned up
       restart: A new domain is started in place of the old one
       preserve: The domain will remain in memory until it is destroyed manually
+      preserve-running: Keep the domain as is, let the guest handle the crash.
       rename-restart: a variant of the previous one but where the old domain is
                       renamed before being saved to allow a restart
       coredump-destroy: The crashed domain's core will be dumped, and then the
       <value>rename-restart</value>
       <value>coredump-destroy</value>
       <value>coredump-restart</value>
+      <value>preserve-running</value>
     </choice>
   </define>
   <!--
index d25b92b4de0c9c61f21459d7c03850bc64ca22b8..3bb5c1e5917009be079f79e508def3dc97497807 100644 (file)
@@ -111,6 +111,7 @@ libxlActionFromVirLifecycle(virDomainLifecycleAction action)
     case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
         return LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART;
 
+    case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
     case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
         break;
     }
index c6717e31cf0fa45f2cd0952b9f972c229f7e8b73..51dc3edcc2ada0c759eb10e284f0baa3c6bf0934 100644 (file)
@@ -509,6 +509,7 @@ libxlDomainShutdownThread(void *opaque)
         case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
         case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
             goto endjob;
         }
@@ -529,6 +530,7 @@ libxlDomainShutdownThread(void *opaque)
             goto endjob;
         case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
         case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
             goto endjob;
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
             libxlDomainAutoCoreDump(driver, vm);
@@ -557,6 +559,7 @@ libxlDomainShutdownThread(void *opaque)
         case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
         case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
             goto endjob;
         }
index b83225cf3875fc9cf3413de4205e2716916b4f9e..44b41726fb09c4698b438f0827bd6a62307beb9c 100644 (file)
@@ -3644,6 +3644,11 @@ processGuestPanicEvent(virQEMUDriver *driver,
         qemuDomainSaveStatus(vm);
         break;
 
+    case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
+        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_CRASHED);
+        qemuDomainSaveStatus(vm);
+        break;
+
     case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
         break;
     }
@@ -3661,6 +3666,8 @@ processGuestPanicEvent(virQEMUDriver *driver,
         VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
         break;
 
+    case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
+        /* we need to keep resources locked */
     case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
         break;
     }
@@ -3678,6 +3685,7 @@ processGuestPanicEvent(virQEMUDriver *driver,
     case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
     case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
     case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
+    case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
     case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
         break;
     }
@@ -3704,6 +3712,7 @@ processGuestPanicEvent(virQEMUDriver *driver,
 
     case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
     case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
+    case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
     case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
         break;
     }
@@ -19591,13 +19600,36 @@ qemuDomainModifyLifecycleActionLive(virDomainObj *vm,
         case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
         case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
         case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
             break;
         }
         break;
 
-    case VIR_DOMAIN_LIFECYCLE_POWEROFF:
     case VIR_DOMAIN_LIFECYCLE_CRASH:
+        if (vm->def->onCrash == action)
+            break;
+
+        switch (vm->def->onCrash) {
+        case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
+            panic = QEMU_MONITOR_ACTION_PANIC_NONE;
+            break;
+
+        case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
+        case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
+            panic = QEMU_MONITOR_ACTION_PANIC_PAUSE;
+            break;
+
+        case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
+            break;
+        }
+        break;
+
+    case VIR_DOMAIN_LIFECYCLE_POWEROFF:
     case VIR_DOMAIN_LIFECYCLE_LAST:
         break;
     }
index 8389819ee4234c1337912b257a9ce75d4fc91bfa..b2506edce05157c3e9e4dcf004d345a9aa429a53 100644 (file)
@@ -8186,6 +8186,24 @@ qemuProcessSetupLifecycleActions(virDomainObj *vm,
     if (vm->def->onReboot == VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY)
         reboot = QEMU_MONITOR_ACTION_REBOOT_SHUTDOWN;
 
+    switch (vm->def->onCrash) {
+    case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE_RUNNING:
+        panic = QEMU_MONITOR_ACTION_PANIC_NONE;
+        break;
+
+    case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
+    case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
+    case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
+    case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
+    case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
+    case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
+        panic = QEMU_MONITOR_ACTION_PANIC_PAUSE;
+        break;
+
+    case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
+        break;
+    }
+
     if (shutdown == QEMU_MONITOR_ACTION_SHUTDOWN_KEEP &&
         reboot == QEMU_MONITOR_ACTION_REBOOT_KEEP &&
         watchdog == QEMU_MONITOR_ACTION_WATCHDOG_KEEP &&
index e98308a9b1c9fb47fdaefb5a299b5c69e2ce3a63..1c7c80ae8a006cfa488309154c57ddb14532b340 100644 (file)
@@ -17,7 +17,7 @@
   <clock offset='utc'/>
   <on_poweroff>destroy</on_poweroff>
   <on_reboot>restart</on_reboot>
-  <on_crash>destroy</on_crash>
+  <on_crash>preserve-running</on_crash>
   <devices>
     <emulator>/usr/bin/qemu-system-x86_64</emulator>
     <disk type='block' device='disk'>
index 70c1eccc55f492b88dfc2ade6cfc0edc777cac08..149b9ed16d3631c4345dab8222dd47fa38de243c 100644 (file)
@@ -11,7 +11,7 @@
   <clock offset='utc'/>
   <on_poweroff>destroy</on_poweroff>
   <on_reboot>restart</on_reboot>
-  <on_crash>destroy</on_crash>
+  <on_crash>preserve-running</on_crash>
   <features>
     <async-teardown enabled='yes'/>
   </features>
index df0b257cbefc334869a248dfb343d650877719b6..f9e426f4eb2134e8598292bb3d52260dfc5f1dd2 100644 (file)
@@ -3193,6 +3193,7 @@ mymain(void)
 
     DO_TEST_CAPS_LATEST("crypto-builtin");
 
+    /* this test case also tests 'preserve-running' onCrash action */
     DO_TEST_CAPS_LATEST("async-teardown");
     DO_TEST_CAPS_ARCH_LATEST("s390-async-teardown", "s390x");
     DO_TEST_CAPS_ARCH_LATEST("s390-async-teardown-no-attrib", "s390x");
index aa4f2a7a481bd182759a4f067fe2df63cf446bdf..0f177fb69ab2c11f984ffe34253eb2e00446be1b 100644 (file)
@@ -6242,7 +6242,8 @@ VIR_ENUM_IMPL(virshDomainLifecycleAction,
               "rename-restart",
               "preserve",
               "coredump-destroy",
-              "coredump-restart");
+              "coredump-restart",
+              "none");
 
 static bool
 cmdSetLifecycleAction(vshControl *ctl, const vshCmd *cmd)