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@xxxxxxxxxxxxx> --- 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