[PATCH] qemu: support Panic Crashloaded event handling

zhenwei pi posted 1 patch 3 weeks ago
Test syntax-check failed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20200204074100.879609-1-pizhenwei@bytedance.com
examples/c/misc/event-test.c     |  3 +++
include/libvirt/libvirt-domain.h |  1 +
src/qemu/qemu_domain.c           |  1 +
src/qemu/qemu_domain.h           |  1 +
src/qemu/qemu_driver.c           | 17 +++++++++++++++++
src/qemu/qemu_monitor.c          | 10 ++++++++++
src/qemu/qemu_monitor.h          |  7 +++++++
src/qemu/qemu_monitor_json.c     | 12 ++++++++++++
src/qemu/qemu_process.c          | 30 ++++++++++++++++++++++++++++++
tools/virsh-domain.c             |  3 ++-
10 files changed, 84 insertions(+), 1 deletion(-)

[PATCH] qemu: support Panic Crashloaded event handling

Posted by zhenwei pi 3 weeks ago
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

Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
---
 examples/c/misc/event-test.c     |  3 +++
 include/libvirt/libvirt-domain.h |  1 +
 src/qemu/qemu_domain.c           |  1 +
 src/qemu/qemu_domain.h           |  1 +
 src/qemu/qemu_driver.c           | 17 +++++++++++++++++
 src/qemu/qemu_monitor.c          | 10 ++++++++++
 src/qemu/qemu_monitor.h          |  7 +++++++
 src/qemu/qemu_monitor_json.c     | 12 ++++++++++++
 src/qemu/qemu_process.c          | 30 ++++++++++++++++++++++++++++++
 tools/virsh-domain.c             |  3 ++-
 10 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/examples/c/misc/event-test.c b/examples/c/misc/event-test.c
index 7e48cecc92..52caa8ffa8 100644
--- a/examples/c/misc/event-test.c
+++ b/examples/c/misc/event-test.c
@@ -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;
            }
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 5846e93d98..b440818ec2 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -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
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index cb691ca048..4933584cf2 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -16348,6 +16348,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:
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index c581b3a162..f8fb48f2ff 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -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;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 8bb845298b..def6631fed 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4877,6 +4877,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;
@@ -4923,6 +4937,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;
     }
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index ceedcd527a..ba70d01d47 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1591,6 +1591,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)
 {
     QEMU_CHECK_MONITOR(mon);
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index cca2cdcb27..89197cfe0d 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -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);
 
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 981d091ba0..385f6c4738 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -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,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index ddcc763cfd..458db2c09f 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -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
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index 32b2792694..f20150a258 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -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)
-- 
2.11.0