]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: support Panic Crashloaded event handling
authorzhenwei pi <pizhenwei@bytedance.com>
Tue, 4 Feb 2020 07:41:00 +0000 (15:41 +0800)
committerDaniel P. Berrangé <berrange@redhat.com>
Fri, 7 Feb 2020 14:05:25 +0000 (14:05 +0000)
Pvpanic device supports bit 1 as crashloaded event, it means that
guest actually panicked and run kexec to handle error by guest side.

Handle crashloaded as a lifecyle event in libvirt.

Test case:
Guest side:
before testing, we need make sure kdump is enabled,
1, build new pvpanic driver (with commit from upstream
   e0b9a42735f2672ca2764cfbea6e55a81098d5ba
   191941692a3d1b6a9614502b279be062926b70f5)
2, insmod new kmod
3, enable crash_kexec_post_notifiers,
  # echo 1 > /sys/module/kernel/parameters/crash_kexec_post_notifiers
4, trigger kernel panic
  # echo 1 > /proc/sys/kernel/sysrq
  # echo c > /proc/sysrq-trigger

Host side:
1, build new qemu with pvpanic patches (with commit from upstream
   600d7b47e8f5085919fd1d1157f25950ea8dbc11
   7dc58deea79a343ac3adc5cadb97215086054c86)
2, build libvirt with this patch
3, handle lifecycle event and trigger guest side panic
  # virsh event stretch --event lifecycle
  event 'lifecycle' for domain stretch: Crashed Crashloaded
  events received: 1

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
examples/c/misc/event-test.c
include/libvirt/libvirt-domain.h
src/qemu/qemu_domain.c
src/qemu/qemu_domain.h
src/qemu/qemu_driver.c
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_process.c
tools/virsh-domain.c

index 7e48cecc923e1ce54fd0f3ebeea5775687eaa908..52caa8ffa8fef55a56b9ed519c0bcdc27e53b39a 100644 (file)
@@ -273,6 +273,9 @@ eventDetailToString(int event,
            case VIR_DOMAIN_EVENT_CRASHED_PANICKED:
                return "Panicked";
 
+           case VIR_DOMAIN_EVENT_CRASHED_CRASHLOADED:
+               return "Crashloaded";
+
            case VIR_DOMAIN_EVENT_CRASHED_LAST:
                break;
            }
index 5846e93d98009e51f329a8eead90d1c36c6f150c..b440818ec269e5a7111ec918692deb35b4a1ef9b 100644 (file)
@@ -3175,6 +3175,7 @@ typedef enum {
  */
 typedef enum {
     VIR_DOMAIN_EVENT_CRASHED_PANICKED = 0, /* Guest was panicked */
+    VIR_DOMAIN_EVENT_CRASHED_CRASHLOADED = 1, /* Guest was crashloaded */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_EVENT_CRASHED_LAST
index 1b4825a539cf54cb7c8a4d0687b30f927dc8a9c2..6fc0bd4e683ce650d93acb8634ce7990af4e1928 100644 (file)
@@ -16375,6 +16375,7 @@ qemuProcessEventFree(struct qemuProcessEvent *event)
     case QEMU_PROCESS_EVENT_SERIAL_CHANGED:
     case QEMU_PROCESS_EVENT_BLOCK_JOB:
     case QEMU_PROCESS_EVENT_MONITOR_EOF:
+    case QEMU_PROCESS_EVENT_GUEST_CRASHLOADED:
         VIR_FREE(event->data);
         break;
     case QEMU_PROCESS_EVENT_JOB_STATUS_CHANGE:
index c581b3a1620a794998eed2aa26d41ff3da17d7ec..f8fb48f2ffcd62c5cba71e0ab02c768232fde297 100644 (file)
@@ -583,6 +583,7 @@ typedef enum {
     QEMU_PROCESS_EVENT_MONITOR_EOF,
     QEMU_PROCESS_EVENT_PR_DISCONNECT,
     QEMU_PROCESS_EVENT_RDMA_GID_STATUS_CHANGED,
+    QEMU_PROCESS_EVENT_GUEST_CRASHLOADED,
 
     QEMU_PROCESS_EVENT_LAST
 } qemuProcessEventType;
index 502f4ce342124d0bc7cc415f16c9ee1ac9ec8a74..e69d083836f7f15b3847eee0fa86522cc7169f8f 100644 (file)
@@ -4876,6 +4876,20 @@ processRdmaGidStatusChangedEvent(virDomainObjPtr vm,
 }
 
 
+static void
+processGuestCrashloadedEvent(virQEMUDriverPtr driver,
+                             virDomainObjPtr vm)
+{
+    virObjectEventPtr event = NULL;
+
+    event = virDomainEventLifecycleNewFromObj(vm,
+                                              VIR_DOMAIN_EVENT_CRASHED,
+                                              VIR_DOMAIN_EVENT_CRASHED_CRASHLOADED);
+
+    virObjectEventStateQueue(driver->domainEventState, event);
+}
+
+
 static void qemuProcessEventHandler(void *data, void *opaque)
 {
     struct qemuProcessEvent *processEvent = data;
@@ -4922,6 +4936,9 @@ static void qemuProcessEventHandler(void *data, void *opaque)
     case QEMU_PROCESS_EVENT_RDMA_GID_STATUS_CHANGED:
         processRdmaGidStatusChangedEvent(vm, processEvent->data);
         break;
+    case QEMU_PROCESS_EVENT_GUEST_CRASHLOADED:
+        processGuestCrashloadedEvent(driver, vm);
+        break;
     case QEMU_PROCESS_EVENT_LAST:
         break;
     }
index ceedcd527acf9475d56174208a17dd22539a030c..ba70d01d47208ed42ecb2a0e8c616c40bb559812 100644 (file)
@@ -1590,6 +1590,16 @@ qemuMonitorEmitRdmaGidStatusChanged(qemuMonitorPtr mon,
 }
 
 
+int
+qemuMonitorEmitGuestCrashloaded(qemuMonitorPtr mon)
+{
+    int ret = -1;
+    VIR_DEBUG("mon=%p", mon);
+    QEMU_MONITOR_CALLBACK(mon, ret, domainGuestCrashloaded, mon->vm);
+    return ret;
+}
+
+
 int
 qemuMonitorSetCapabilities(qemuMonitorPtr mon)
 {
index cca2cdcb278f8e4b8a29769dac7e3bf44668d254..89197cfe0d11b2500f18f6a35a85b018d35046c3 100644 (file)
@@ -345,6 +345,10 @@ typedef int (*qemuMonitorDomainRdmaGidStatusChangedCallback)(qemuMonitorPtr mon,
                                                              unsigned long long interface_id,
                                                              void *opaque);
 
+typedef int (*qemuMonitorDomainGuestCrashloadedCallback)(qemuMonitorPtr mon,
+                                                         virDomainObjPtr vm,
+                                                         void *opaque);
+
 typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
 typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr;
 struct _qemuMonitorCallbacks {
@@ -380,6 +384,7 @@ struct _qemuMonitorCallbacks {
     qemuMonitorDomainDumpCompletedCallback domainDumpCompleted;
     qemuMonitorDomainPRManagerStatusChangedCallback domainPRManagerStatusChanged;
     qemuMonitorDomainRdmaGidStatusChangedCallback domainRdmaGidStatusChanged;
+    qemuMonitorDomainGuestCrashloadedCallback domainGuestCrashloaded;
 };
 
 qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm,
@@ -512,6 +517,8 @@ int qemuMonitorEmitRdmaGidStatusChanged(qemuMonitorPtr mon,
                                         unsigned long long subnet_prefix,
                                         unsigned long long interface_id);
 
+int qemuMonitorEmitGuestCrashloaded(qemuMonitorPtr mon);
+
 int qemuMonitorStartCPUs(qemuMonitorPtr mon);
 int qemuMonitorStopCPUs(qemuMonitorPtr mon);
 
index dc1fc310ca3560eb1baddd97af3fedaa4dc66ce2..5defd29f3be76052b15c43ad59f3be79d75a5d75 100644 (file)
@@ -99,6 +99,7 @@ static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, virJSONValueP
 static void qemuMonitorJSONHandleJobStatusChange(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleGuestCrashloaded(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandleDeviceDeleted(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandleNicRxFilterChanged(qemuMonitorPtr mon, virJSONValuePtr data);
@@ -128,6 +129,7 @@ static qemuEventHandler eventHandlers[] = {
     { "DEVICE_DELETED", qemuMonitorJSONHandleDeviceDeleted, },
     { "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
     { "DUMP_COMPLETED", qemuMonitorJSONHandleDumpCompleted, },
+    { "GUEST_CRASHLOADED", qemuMonitorJSONHandleGuestCrashloaded, },
     { "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
     { "JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange, },
     { "MIGRATION", qemuMonitorJSONHandleMigrationStatus, },
@@ -1543,6 +1545,16 @@ static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitorPtr mon,
 }
 
 
+static void
+qemuMonitorJSONHandleGuestCrashloaded(qemuMonitorPtr mon,
+                                      virJSONValuePtr data)
+{
+    VIR_DEBUG("qemuMonitorJSONHandleGuestCrashloaded event, mon %p, data %p", mon, data);
+
+    qemuMonitorEmitGuestCrashloaded(mon);
+}
+
+
 int
 qemuMonitorJSONHumanCommand(qemuMonitorPtr mon,
                             const char *cmd_str,
index e3df75d28168d61b8130daee41312b5b51dca7ba..bf987a3bc30c0b047a594627e673759c0e747d68 100644 (file)
@@ -1848,6 +1848,35 @@ qemuProcessHandleRdmaGidStatusChanged(qemuMonitorPtr mon G_GNUC_UNUSED,
 }
 
 
+static int
+qemuProcessHandleGuestCrashloaded(qemuMonitorPtr mon G_GNUC_UNUSED,
+                                  virDomainObjPtr vm,
+                                  void *opaque)
+{
+    virQEMUDriverPtr driver = opaque;
+    struct qemuProcessEvent *processEvent;
+
+    virObjectLock(vm);
+    if (VIR_ALLOC(processEvent) < 0)
+        goto cleanup;
+
+    processEvent->eventType = QEMU_PROCESS_EVENT_GUEST_CRASHLOADED;
+    processEvent->vm = virObjectRef(vm);
+
+    if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
+        if (!virObjectUnref(vm))
+            vm = NULL;
+        qemuProcessEventFree(processEvent);
+    }
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+
+    return 0;
+}
+
+
 static qemuMonitorCallbacks monitorCallbacks = {
     .eofNotify = qemuProcessHandleMonitorEOF,
     .errorNotify = qemuProcessHandleMonitorError,
@@ -1879,6 +1908,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
     .domainDumpCompleted = qemuProcessHandleDumpCompleted,
     .domainPRManagerStatusChanged = qemuProcessHandlePRManagerStatusChanged,
     .domainRdmaGidStatusChanged = qemuProcessHandleRdmaGidStatusChanged,
+    .domainGuestCrashloaded = qemuProcessHandleGuestCrashloaded,
 };
 
 static void
index 781463f0e2f807f6a117bd28546e98058121ad80..91bf280f8e30fe6e58c6e5d9db5a80710b14101f 100644 (file)
@@ -12910,7 +12910,8 @@ VIR_ENUM_IMPL(virshDomainEventPMSuspended,
 VIR_ENUM_DECL(virshDomainEventCrashed);
 VIR_ENUM_IMPL(virshDomainEventCrashed,
               VIR_DOMAIN_EVENT_CRASHED_LAST,
-              N_("Panicked"));
+              N_("Panicked"),
+              N_("Crashloaded"));
 
 static const char *
 virshDomainEventDetailToString(int event, int detail)