qemu: support Panic Crashloaded event handling

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>
This commit is contained in:
zhenwei pi 2020-02-04 15:41:00 +08:00 committed by Daniel P. Berrangé
parent 039787c71a
commit 26badd13e8
10 changed files with 84 additions and 1 deletions

View 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;
}

View 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

View 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:

View 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;

View 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;
}

View 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)
{

View 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);

View 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,

View 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

View 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)