mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 11:22:23 +00:00
qemu: Implement 'oncrash' events when guest panicked
Add monitor callback API domainGuestPanic, that implements 'destroy', 'restart' and 'preserve' events of the 'on_crash' in the XML when domain crashed.
This commit is contained in:
parent
e8ccf7ed8a
commit
9aa527dccb
@ -172,6 +172,7 @@ struct _qemuDomainObjPrivate {
|
||||
|
||||
typedef enum {
|
||||
QEMU_PROCESS_EVENT_WATCHDOG = 0,
|
||||
QEMU_PROCESS_EVENT_GUESTPANIC,
|
||||
|
||||
QEMU_PROCESS_EVENT_LAST
|
||||
} qemuProcessEventType;
|
||||
|
@ -139,6 +139,10 @@ static void processWatchdogEvent(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
int action);
|
||||
|
||||
static void processGuestPanicEvent(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
int action);
|
||||
|
||||
static void qemuProcessEventHandler(void *data, void *opaque);
|
||||
|
||||
static int qemuStateCleanup(void);
|
||||
@ -3629,18 +3633,106 @@ cleanup:
|
||||
virObjectUnref(cfg);
|
||||
}
|
||||
|
||||
static void
|
||||
processGuestPanicEvent(virQEMUDriverPtr driver,
|
||||
virDomainObjPtr vm,
|
||||
int action)
|
||||
{
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
virDomainEventPtr event = NULL;
|
||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||
|
||||
if (!virDomainObjIsActive(vm)) {
|
||||
VIR_DEBUG("Ignoring GUEST_PANICKED event from inactive domain %s",
|
||||
vm->def->name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
virDomainObjSetState(vm,
|
||||
VIR_DOMAIN_CRASHED,
|
||||
VIR_DOMAIN_CRASHED_PANICKED);
|
||||
|
||||
event = virDomainEventNewFromObj(vm,
|
||||
VIR_DOMAIN_EVENT_CRASHED,
|
||||
VIR_DOMAIN_EVENT_CRASHED_PANICKED);
|
||||
|
||||
if (event)
|
||||
qemuDomainEventQueue(driver, event);
|
||||
|
||||
if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
|
||||
VIR_WARN("Unable to release lease on %s", vm->def->name);
|
||||
VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
|
||||
|
||||
if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
|
||||
VIR_WARN("Unable to save status on vm %s after state change",
|
||||
vm->def->name);
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY:
|
||||
priv->beingDestroyed = true;
|
||||
|
||||
if (qemuProcessKill(vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
|
||||
priv->beingDestroyed = false;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
priv->beingDestroyed = false;
|
||||
|
||||
if (!virDomainObjIsActive(vm)) {
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
"%s", _("domain is not running"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
|
||||
event = virDomainEventNewFromObj(vm,
|
||||
VIR_DOMAIN_EVENT_STOPPED,
|
||||
VIR_DOMAIN_EVENT_STOPPED_CRASHED);
|
||||
|
||||
if (event)
|
||||
qemuDomainEventQueue(driver, event);
|
||||
|
||||
virDomainAuditStop(vm, "destroyed");
|
||||
|
||||
if (!vm->persistent) {
|
||||
qemuDomainRemoveInactive(driver, vm);
|
||||
}
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART:
|
||||
qemuDomainSetFakeReboot(driver, vm, true);
|
||||
qemuProcessShutdownOrReboot(driver, vm);
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
virObjectUnref(cfg);
|
||||
}
|
||||
|
||||
static void qemuProcessEventHandler(void *data, void *opaque)
|
||||
{
|
||||
struct qemuProcessEvent *processEvent = data;
|
||||
virDomainObjPtr vm = processEvent->vm;
|
||||
virQEMUDriverPtr driver = opaque;
|
||||
|
||||
VIR_DEBUG("vm=%p", vm);
|
||||
|
||||
virObjectLock(vm);
|
||||
|
||||
switch (processEvent->eventType) {
|
||||
case QEMU_PROCESS_EVENT_WATCHDOG:
|
||||
processWatchdogEvent(driver, vm, processEvent->action);
|
||||
break;
|
||||
case QEMU_PROCESS_EVENT_GUESTPANIC:
|
||||
processGuestPanicEvent(driver, vm, processEvent->action);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ VIR_ENUM_IMPL(qemuMonitorVMStatus,
|
||||
QEMU_MONITOR_VM_STATUS_LAST,
|
||||
"debug", "inmigrate", "internal-error", "io-error", "paused",
|
||||
"postmigrate", "prelaunch", "finish-migrate", "restore-vm",
|
||||
"running", "save-vm", "shutdown", "watchdog")
|
||||
"running", "save-vm", "shutdown", "watchdog", "guest-panic")
|
||||
|
||||
typedef enum {
|
||||
QEMU_MONITOR_BLOCK_IO_STATUS_OK,
|
||||
@ -1033,6 +1033,15 @@ int qemuMonitorEmitResume(qemuMonitorPtr mon)
|
||||
}
|
||||
|
||||
|
||||
int qemuMonitorEmitGuestPanic(qemuMonitorPtr mon)
|
||||
{
|
||||
int ret = -1;
|
||||
VIR_DEBUG("mon=%p", mon);
|
||||
QEMU_MONITOR_CALLBACK(mon, ret, domainGuestPanic, mon->vm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset)
|
||||
{
|
||||
int ret = -1;
|
||||
@ -3186,6 +3195,9 @@ int qemuMonitorVMStatusToPausedReason(const char *status)
|
||||
case QEMU_MONITOR_VM_STATUS_WATCHDOG:
|
||||
return VIR_DOMAIN_PAUSED_WATCHDOG;
|
||||
|
||||
case QEMU_MONITOR_VM_STATUS_GUEST_PANICKED:
|
||||
return VIR_DOMAIN_PAUSED_GUEST_PANICKED;
|
||||
|
||||
/* unreachable from this point on */
|
||||
case QEMU_MONITOR_VM_STATUS_LAST:
|
||||
;
|
||||
|
@ -140,6 +140,8 @@ struct _qemuMonitorCallbacks {
|
||||
unsigned long long actual);
|
||||
int (*domainPMSuspendDisk)(qemuMonitorPtr mon,
|
||||
virDomainObjPtr vm);
|
||||
int (*domainGuestPanic)(qemuMonitorPtr mon,
|
||||
virDomainObjPtr vm);
|
||||
};
|
||||
|
||||
char *qemuMonitorEscapeArg(const char *in);
|
||||
@ -220,6 +222,7 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
|
||||
int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
|
||||
unsigned long long actual);
|
||||
int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon);
|
||||
int qemuMonitorEmitGuestPanic(qemuMonitorPtr mon);
|
||||
|
||||
int qemuMonitorStartCPUs(qemuMonitorPtr mon,
|
||||
virConnectPtr conn);
|
||||
@ -239,6 +242,7 @@ typedef enum {
|
||||
QEMU_MONITOR_VM_STATUS_SAVE_VM,
|
||||
QEMU_MONITOR_VM_STATUS_SHUTDOWN,
|
||||
QEMU_MONITOR_VM_STATUS_WATCHDOG,
|
||||
QEMU_MONITOR_VM_STATUS_GUEST_PANICKED,
|
||||
|
||||
QEMU_MONITOR_VM_STATUS_LAST
|
||||
} qemuMonitorVMStatus;
|
||||
|
@ -74,6 +74,7 @@ static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONVal
|
||||
static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||
static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||
static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||
static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data);
|
||||
|
||||
typedef struct {
|
||||
const char *type;
|
||||
@ -87,6 +88,7 @@ static qemuEventHandler eventHandlers[] = {
|
||||
{ "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJobCompleted, },
|
||||
{ "BLOCK_JOB_READY", qemuMonitorJSONHandleBlockJobReady, },
|
||||
{ "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
|
||||
{ "GUEST_PANICKED", qemuMonitorJSONHandleGuestPanic, },
|
||||
{ "POWERDOWN", qemuMonitorJSONHandlePowerdown, },
|
||||
{ "RESET", qemuMonitorJSONHandleReset, },
|
||||
{ "RESUME", qemuMonitorJSONHandleResume, },
|
||||
@ -593,6 +595,11 @@ static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data
|
||||
qemuMonitorEmitResume(mon);
|
||||
}
|
||||
|
||||
static void qemuMonitorJSONHandleGuestPanic(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
qemuMonitorEmitGuestPanic(mon);
|
||||
}
|
||||
|
||||
static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data)
|
||||
{
|
||||
long long offset = 0;
|
||||
|
@ -548,6 +548,7 @@ qemuProcessFakeReboot(void *opaque)
|
||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||
virDomainEventPtr event = NULL;
|
||||
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
||||
virDomainRunningReason reason = VIR_DOMAIN_RUNNING_BOOTED;
|
||||
int ret = -1;
|
||||
VIR_DEBUG("vm=%p", vm);
|
||||
virObjectLock(vm);
|
||||
@ -573,8 +574,11 @@ qemuProcessFakeReboot(void *opaque)
|
||||
goto endjob;
|
||||
}
|
||||
|
||||
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_CRASHED)
|
||||
reason = VIR_DOMAIN_RUNNING_CRASHED;
|
||||
|
||||
if (qemuProcessStartCPUs(driver, vm, NULL,
|
||||
VIR_DOMAIN_RUNNING_BOOTED,
|
||||
reason,
|
||||
QEMU_ASYNC_JOB_NONE) < 0) {
|
||||
if (virGetLastError() == NULL)
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
@ -1284,6 +1288,40 @@ qemuProcessHandlePMSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuProcessHandleGuestPanic(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||
virDomainObjPtr vm)
|
||||
{
|
||||
virQEMUDriverPtr driver = qemu_driver;
|
||||
struct qemuProcessEvent *processEvent;
|
||||
|
||||
virObjectLock(vm);
|
||||
if (VIR_ALLOC(processEvent) < 0) {
|
||||
virReportOOMError();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
processEvent->eventType = QEMU_PROCESS_EVENT_GUESTPANIC;
|
||||
processEvent->action = vm->def->onCrash;
|
||||
processEvent->vm = vm;
|
||||
/* Hold an extra reference because we can't allow 'vm' to be
|
||||
* deleted before handling guest panic event is finished.
|
||||
*/
|
||||
virObjectRef(vm);
|
||||
if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) {
|
||||
if (!virObjectUnref(vm))
|
||||
vm = NULL;
|
||||
VIR_FREE(processEvent);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static qemuMonitorCallbacks monitorCallbacks = {
|
||||
.destroy = qemuProcessHandleMonitorDestroy,
|
||||
.eofNotify = qemuProcessHandleMonitorEOF,
|
||||
@ -1303,6 +1341,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
|
||||
.domainPMSuspend = qemuProcessHandlePMSuspend,
|
||||
.domainBalloonChange = qemuProcessHandleBalloonChange,
|
||||
.domainPMSuspendDisk = qemuProcessHandlePMSuspendDisk,
|
||||
.domainGuestPanic = qemuProcessHandleGuestPanic,
|
||||
};
|
||||
|
||||
static int
|
||||
@ -2682,6 +2721,10 @@ qemuProcessUpdateState(virQEMUDriverPtr driver, virDomainObjPtr vm)
|
||||
newState = VIR_DOMAIN_SHUTDOWN;
|
||||
newReason = VIR_DOMAIN_SHUTDOWN_UNKNOWN;
|
||||
ignore_value(VIR_STRDUP_QUIET(msg, "shutdown"));
|
||||
} else if (reason == VIR_DOMAIN_PAUSED_GUEST_PANICKED) {
|
||||
newState = VIR_DOMAIN_CRASHED;
|
||||
newReason = VIR_DOMAIN_CRASHED_PANICKED;
|
||||
ignore_value(VIR_STRDUP_QUIET(msg, "crashed"));
|
||||
} else {
|
||||
newState = VIR_DOMAIN_PAUSED;
|
||||
newReason = reason;
|
||||
|
Loading…
x
Reference in New Issue
Block a user