qemu: monitor: Extract additional info from GUEST_PANICKED event

For certain kinds of panic notifiers (notably hyper-v) qemu is able to
report some data regarding the crash passed from the guest.

Make the data accessible to the callback in qemu so that it can be
processed further.
This commit is contained in:
Peter Krempa 2017-03-20 14:35:33 +01:00
parent 7d5c27e923
commit d7580dd643
4 changed files with 100 additions and 5 deletions

View File

@ -1358,11 +1358,12 @@ qemuMonitorEmitResume(qemuMonitorPtr mon)
int
qemuMonitorEmitGuestPanic(qemuMonitorPtr mon)
qemuMonitorEmitGuestPanic(qemuMonitorPtr mon,
qemuMonitorEventPanicInfoPtr info)
{
int ret = -1;
VIR_DEBUG("mon=%p", mon);
QEMU_MONITOR_CALLBACK(mon, ret, domainGuestPanic, mon->vm);
QEMU_MONITOR_CALLBACK(mon, ret, domainGuestPanic, mon->vm, info);
return ret;
}
@ -4240,3 +4241,13 @@ qemuMonitorQueryNamedBlockNodes(qemuMonitorPtr mon)
return qemuMonitorJSONQueryNamedBlockNodes(mon);
}
void
qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfoPtr info)
{
if (!info)
return;
VIR_FREE(info);
}

View File

@ -70,6 +70,34 @@ struct _qemuMonitorMessage {
void *passwordOpaque;
};
typedef enum {
QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_NONE = 0,
QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_HYPERV,
QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_LAST
} qemuMonitorEventPanicInfoType;
typedef struct _qemuMonitorEventPanicInfoHyperv qemuMonitorEventPanicInfoHyperv;
typedef qemuMonitorEventPanicInfoHyperv *qemuMonitorEventPanicInfoHypervPtr;
struct _qemuMonitorEventPanicInfoHyperv {
/* Hyper-V specific guest panic information (HV crash MSRs) */
unsigned long long arg1;
unsigned long long arg2;
unsigned long long arg3;
unsigned long long arg4;
unsigned long long arg5;
};
typedef struct _qemuMonitorEventPanicInfo qemuMonitorEventPanicInfo;
typedef qemuMonitorEventPanicInfo *qemuMonitorEventPanicInfoPtr;
struct _qemuMonitorEventPanicInfo {
qemuMonitorEventPanicInfoType type;
union {
qemuMonitorEventPanicInfoHyperv hyperv;
} data;
};
void qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfoPtr info);
typedef void (*qemuMonitorDestroyCallback)(qemuMonitorPtr mon,
virDomainObjPtr vm,
@ -167,6 +195,7 @@ typedef int (*qemuMonitorDomainPMSuspendDiskCallback)(qemuMonitorPtr mon,
void *opaque);
typedef int (*qemuMonitorDomainGuestPanicCallback)(qemuMonitorPtr mon,
virDomainObjPtr vm,
qemuMonitorEventPanicInfoPtr info,
void *opaque);
typedef int (*qemuMonitorDomainDeviceDeletedCallback)(qemuMonitorPtr mon,
virDomainObjPtr vm,
@ -346,7 +375,8 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
unsigned long long actual);
int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon);
int qemuMonitorEmitGuestPanic(qemuMonitorPtr mon);
int qemuMonitorEmitGuestPanic(qemuMonitorPtr mon,
qemuMonitorEventPanicInfoPtr info);
int qemuMonitorEmitDeviceDeleted(qemuMonitorPtr mon,
const char *devAlias);
int qemuMonitorEmitNicRxFilterChanged(qemuMonitorPtr mon,

View File

@ -548,11 +548,63 @@ static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data
qemuMonitorEmitResume(mon);
}
static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
static qemuMonitorEventPanicInfoPtr
qemuMonitorJSONGuestPanicExtractInfoHyperv(virJSONValuePtr data)
{
qemuMonitorEmitGuestPanic(mon);
qemuMonitorEventPanicInfoPtr ret;
if (VIR_ALLOC(ret) < 0)
return NULL;
ret->type = QEMU_MONITOR_EVENT_PANIC_INFO_TYPE_HYPERV;
if (virJSONValueObjectGetNumberUlong(data, "arg1", &ret->data.hyperv.arg1) < 0 ||
virJSONValueObjectGetNumberUlong(data, "arg2", &ret->data.hyperv.arg2) < 0 ||
virJSONValueObjectGetNumberUlong(data, "arg3", &ret->data.hyperv.arg3) < 0 ||
virJSONValueObjectGetNumberUlong(data, "arg4", &ret->data.hyperv.arg4) < 0 ||
virJSONValueObjectGetNumberUlong(data, "arg5", &ret->data.hyperv.arg5) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("malformed hyperv panic data"));
goto error;
}
return ret;
error:
qemuMonitorEventPanicInfoFree(ret);
return NULL;
}
static qemuMonitorEventPanicInfoPtr
qemuMonitorJSONGuestPanicExtractInfo(virJSONValuePtr data)
{
const char *type = virJSONValueObjectGetString(data, "type");
if (STREQ_NULLABLE(type, "hyper-v"))
return qemuMonitorJSONGuestPanicExtractInfoHyperv(data);
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown panic info type '%s'"), NULLSTR(type));
return NULL;
}
static void
qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon,
virJSONValuePtr data)
{
virJSONValuePtr infojson = virJSONValueObjectGetObject(data, "info");
qemuMonitorEventPanicInfoPtr info = NULL;
if (infojson)
info = qemuMonitorJSONGuestPanicExtractInfo(infojson);
qemuMonitorEmitGuestPanic(mon, info);
}
static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data)
{
long long offset = 0;

View File

@ -1298,6 +1298,7 @@ qemuProcessHandlePMSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
static int
qemuProcessHandleGuestPanic(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
virDomainObjPtr vm,
qemuMonitorEventPanicInfoPtr info,
void *opaque)
{
virQEMUDriverPtr driver = opaque;
@ -1310,6 +1311,7 @@ qemuProcessHandleGuestPanic(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
processEvent->eventType = QEMU_PROCESS_EVENT_GUESTPANIC;
processEvent->action = vm->def->onCrash;
processEvent->vm = vm;
processEvent->data = info;
/* Hold an extra reference because we can't allow 'vm' to be
* deleted before handling guest panic event is finished.
*/