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(a)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