mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 21:34:54 +03:00
qemu: implement memory failure event
Since QEMU 5.2 (commit-77b285f7f6), QEMU supports 'memory failure' event, posts event to monitor if hitting a hardware memory error. Fully support this feature for QEMU. Test with commit 'libvirt: support memory failure event', build a little complex environment(nested KVM): 1, install newly built libvirt in L1, and start a L2 vm. run command in L1: ~# virsh event l2 --event memory-failure 2, run command in L0 to inject MCE to L1: ~# virsh qemu-monitor-command l1 --hmp mce 0 9 0xbd000000000000c0 0xd 0x62000000 0x8c Test result in l1(recipient hypervisor case): event 'memory-failure' for domain l2: recipient: hypervisor action: ignore flags: action required: 0 recursive: 0 Test result in l1(recipient guest case): event 'memory-failure' for domain l2: recipient: guest action: inject flags: action required: 0 recursive: 0 Signed-off-by: zhenwei pi <pizhenwei@bytedance.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
b866adf8d9
commit
7555a55470
@ -197,6 +197,14 @@ VIR_ENUM_IMPL(qemuMonitorDumpStatus,
|
||||
"none", "active", "completed", "failed",
|
||||
);
|
||||
|
||||
VIR_ENUM_IMPL(qemuMonitorMemoryFailureRecipient,
|
||||
QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_LAST,
|
||||
"hypervisor", "guest");
|
||||
|
||||
VIR_ENUM_IMPL(qemuMonitorMemoryFailureAction,
|
||||
QEMU_MONITOR_MEMORY_FAILURE_ACTION_LAST,
|
||||
"ignore", "inject",
|
||||
"fatal", "reset");
|
||||
|
||||
#if DEBUG_RAW_IO
|
||||
static char *
|
||||
@ -1427,6 +1435,18 @@ qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuMonitorEmitMemoryFailure(qemuMonitorPtr mon,
|
||||
qemuMonitorEventMemoryFailurePtr mfp)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
QEMU_MONITOR_CALLBACK(mon, ret, domainMemoryFailure, mon->vm, mfp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuMonitorEmitMigrationStatus(qemuMonitorPtr mon,
|
||||
int status)
|
||||
|
@ -340,6 +340,40 @@ typedef int (*qemuMonitorDomainGuestCrashloadedCallback)(qemuMonitorPtr mon,
|
||||
virDomainObjPtr vm,
|
||||
void *opaque);
|
||||
|
||||
typedef enum {
|
||||
QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_HYPERVISOR,
|
||||
QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_GUEST,
|
||||
|
||||
QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_LAST
|
||||
} qemuMonitorMemoryFailureRecipient;
|
||||
|
||||
VIR_ENUM_DECL(qemuMonitorMemoryFailureRecipient);
|
||||
|
||||
typedef enum {
|
||||
QEMU_MONITOR_MEMORY_FAILURE_ACTION_IGNORE,
|
||||
QEMU_MONITOR_MEMORY_FAILURE_ACTION_INJECT,
|
||||
QEMU_MONITOR_MEMORY_FAILURE_ACTION_FATAL,
|
||||
QEMU_MONITOR_MEMORY_FAILURE_ACTION_RESET,
|
||||
|
||||
QEMU_MONITOR_MEMORY_FAILURE_ACTION_LAST
|
||||
} qemuMonitorMemoryFailureAction;
|
||||
|
||||
VIR_ENUM_DECL(qemuMonitorMemoryFailureAction);
|
||||
|
||||
typedef struct _qemuMonitorEventMemoryFailure qemuMonitorEventMemoryFailure;
|
||||
typedef qemuMonitorEventMemoryFailure *qemuMonitorEventMemoryFailurePtr;
|
||||
struct _qemuMonitorEventMemoryFailure {
|
||||
qemuMonitorMemoryFailureRecipient recipient;
|
||||
qemuMonitorMemoryFailureAction action;
|
||||
bool action_required;
|
||||
bool recursive;
|
||||
};
|
||||
|
||||
typedef int (*qemuMonitorDomainMemoryFailureCallback)(qemuMonitorPtr mon,
|
||||
virDomainObjPtr vm,
|
||||
qemuMonitorEventMemoryFailurePtr mfp,
|
||||
void *opaque);
|
||||
|
||||
typedef struct _qemuMonitorCallbacks qemuMonitorCallbacks;
|
||||
typedef qemuMonitorCallbacks *qemuMonitorCallbacksPtr;
|
||||
struct _qemuMonitorCallbacks {
|
||||
@ -376,6 +410,7 @@ struct _qemuMonitorCallbacks {
|
||||
qemuMonitorDomainPRManagerStatusChangedCallback domainPRManagerStatusChanged;
|
||||
qemuMonitorDomainRdmaGidStatusChangedCallback domainRdmaGidStatusChanged;
|
||||
qemuMonitorDomainGuestCrashloadedCallback domainGuestCrashloaded;
|
||||
qemuMonitorDomainMemoryFailureCallback domainMemoryFailure;
|
||||
};
|
||||
|
||||
qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm,
|
||||
@ -475,6 +510,10 @@ int qemuMonitorEmitSerialChange(qemuMonitorPtr mon,
|
||||
const char *devAlias,
|
||||
bool connected);
|
||||
int qemuMonitorEmitSpiceMigrated(qemuMonitorPtr mon);
|
||||
|
||||
int qemuMonitorEmitMemoryFailure(qemuMonitorPtr mon,
|
||||
qemuMonitorEventMemoryFailurePtr mfp);
|
||||
|
||||
int qemuMonitorEmitMigrationStatus(qemuMonitorPtr mon,
|
||||
int status);
|
||||
int qemuMonitorEmitMigrationPass(qemuMonitorPtr mon,
|
||||
|
@ -112,6 +112,7 @@ static void qemuMonitorJSONHandleBlockThreshold(qemuMonitorPtr mon, virJSONValue
|
||||
static void qemuMonitorJSONHandleDumpCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||
static void qemuMonitorJSONHandlePRManagerStatusChanged(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||
static void qemuMonitorJSONHandleRdmaGidStatusChanged(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||
static void qemuMonitorJSONHandleMemoryFailure(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||
|
||||
typedef struct {
|
||||
const char *type;
|
||||
@ -132,6 +133,7 @@ static qemuEventHandler eventHandlers[] = {
|
||||
{ "GUEST_CRASHLOADED", qemuMonitorJSONHandleGuestCrashloaded, },
|
||||
{ "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
|
||||
{ "JOB_STATUS_CHANGE", qemuMonitorJSONHandleJobStatusChange, },
|
||||
{ "MEMORY_FAILURE", qemuMonitorJSONHandleMemoryFailure, },
|
||||
{ "MIGRATION", qemuMonitorJSONHandleMigrationStatus, },
|
||||
{ "MIGRATION_PASS", qemuMonitorJSONHandleMigrationPass, },
|
||||
{ "NIC_RX_FILTER_CHANGED", qemuMonitorJSONHandleNicRxFilterChanged, },
|
||||
@ -1335,6 +1337,53 @@ qemuMonitorJSONHandleSpiceMigrated(qemuMonitorPtr mon,
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qemuMonitorJSONHandleMemoryFailure(qemuMonitorPtr mon,
|
||||
virJSONValuePtr data)
|
||||
{
|
||||
virJSONValuePtr flagsjson = virJSONValueObjectGetObject(data, "flags");
|
||||
const char *str;
|
||||
int recipient;
|
||||
int action;
|
||||
bool ar = false;
|
||||
bool recursive = false;
|
||||
qemuMonitorEventMemoryFailure mf = {0};
|
||||
|
||||
if (!(str = virJSONValueObjectGetString(data, "recipient"))) {
|
||||
VIR_WARN("missing recipient in memory failure event");
|
||||
return;
|
||||
}
|
||||
|
||||
recipient = qemuMonitorMemoryFailureRecipientTypeFromString(str);
|
||||
if (recipient < 0) {
|
||||
VIR_WARN("unknown recipient '%s' in memory_failure event", str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(str = virJSONValueObjectGetString(data, "action"))) {
|
||||
VIR_WARN("missing action in memory failure event");
|
||||
return;
|
||||
}
|
||||
|
||||
action = qemuMonitorMemoryFailureActionTypeFromString(str);
|
||||
if (action < 0) {
|
||||
VIR_WARN("unknown action '%s' in memory_failure event", str);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flagsjson) {
|
||||
virJSONValueObjectGetBoolean(flagsjson, "action-required", &ar);
|
||||
virJSONValueObjectGetBoolean(flagsjson, "recursive", &recursive);
|
||||
}
|
||||
|
||||
mf.recipient = recipient;
|
||||
mf.action = action;
|
||||
mf.action_required = ar;
|
||||
mf.recursive = recursive;
|
||||
qemuMonitorEmitMemoryFailure(mon, &mf);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qemuMonitorJSONHandleMigrationStatus(qemuMonitorPtr mon,
|
||||
virJSONValuePtr data)
|
||||
|
@ -1878,6 +1878,64 @@ qemuProcessHandleGuestCrashloaded(qemuMonitorPtr mon G_GNUC_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuProcessHandleMemoryFailure(qemuMonitorPtr mon G_GNUC_UNUSED,
|
||||
virDomainObjPtr vm,
|
||||
qemuMonitorEventMemoryFailurePtr mfp,
|
||||
void *opaque)
|
||||
{
|
||||
virQEMUDriverPtr driver = opaque;
|
||||
virObjectEventPtr event = NULL;
|
||||
virDomainMemoryFailureRecipientType recipient;
|
||||
virDomainMemoryFailureActionType action;
|
||||
unsigned int flags = 0;
|
||||
|
||||
switch (mfp->recipient) {
|
||||
case QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_HYPERVISOR:
|
||||
recipient = VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_HYPERVISOR;
|
||||
break;
|
||||
case QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_GUEST:
|
||||
recipient = VIR_DOMAIN_EVENT_MEMORY_FAILURE_RECIPIENT_GUEST;
|
||||
break;
|
||||
case QEMU_MONITOR_MEMORY_FAILURE_RECIPIENT_LAST:
|
||||
default:
|
||||
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||
_("requested unknown memory failure recipient"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (mfp->action) {
|
||||
case QEMU_MONITOR_MEMORY_FAILURE_ACTION_IGNORE:
|
||||
action = VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_IGNORE;
|
||||
break;
|
||||
case QEMU_MONITOR_MEMORY_FAILURE_ACTION_INJECT:
|
||||
action = VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_INJECT;
|
||||
break;
|
||||
case QEMU_MONITOR_MEMORY_FAILURE_ACTION_FATAL:
|
||||
action = VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_FATAL;
|
||||
break;
|
||||
case QEMU_MONITOR_MEMORY_FAILURE_ACTION_RESET:
|
||||
action = VIR_DOMAIN_EVENT_MEMORY_FAILURE_ACTION_RESET;
|
||||
break;
|
||||
case QEMU_MONITOR_MEMORY_FAILURE_ACTION_LAST:
|
||||
default:
|
||||
virReportError(VIR_ERR_INVALID_ARG, "%s",
|
||||
_("requested unknown memory failure action"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mfp->action_required)
|
||||
flags |= VIR_DOMAIN_MEMORY_FAILURE_ACTION_REQUIRED;
|
||||
if (mfp->recursive)
|
||||
flags |= VIR_DOMAIN_MEMORY_FAILURE_RECURSIVE;
|
||||
|
||||
event = virDomainEventMemoryFailureNewFromObj(vm, recipient, action, flags);
|
||||
virObjectEventStateQueue(driver->domainEventState, event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static qemuMonitorCallbacks monitorCallbacks = {
|
||||
.eofNotify = qemuProcessHandleMonitorEOF,
|
||||
.errorNotify = qemuProcessHandleMonitorError,
|
||||
@ -1910,6 +1968,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
|
||||
.domainPRManagerStatusChanged = qemuProcessHandlePRManagerStatusChanged,
|
||||
.domainRdmaGidStatusChanged = qemuProcessHandleRdmaGidStatusChanged,
|
||||
.domainGuestCrashloaded = qemuProcessHandleGuestCrashloaded,
|
||||
.domainMemoryFailure = qemuProcessHandleMemoryFailure,
|
||||
};
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user