Add monitor callback API domainGUESTPanicked, that implements the 'on_crash' behavior in the XML when domain crashed. --- src/qemu/qemu_monitor.c | 14 +++++- src/qemu/qemu_monitor.h | 5 +++ src/qemu/qemu_monitor_json.c | 7 +++ src/qemu/qemu_process.c | 103 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 4e35f79..e0cd62c 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -113,7 +113,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-panicked") typedef enum { QEMU_MONITOR_BLOCK_IO_STATUS_OK, @@ -1032,6 +1032,15 @@ int qemuMonitorEmitResume(qemuMonitorPtr mon) } +int qemuMonitorEmitGUESTPanicked(qemuMonitorPtr mon) +{ + int ret = -1; + VIR_DEBUG("mon=%p", mon); + QEMU_MONITOR_CALLBACK(mon, ret, domainGUESTPanicked, mon->vm); + return ret; +} + + int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset) { int ret = -1; @@ -3185,6 +3194,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: ; diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index a607712..543050c 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -140,6 +140,8 @@ struct _qemuMonitorCallbacks { unsigned long long actual); int (*domainPMSuspendDisk)(qemuMonitorPtr mon, virDomainObjPtr vm); + int (*domainGUESTPanicked)(qemuMonitorPtr mon, + virDomainObjPtr vm); }; char *qemuMonitorEscapeArg(const char *in); @@ -220,6 +222,8 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon, int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon, unsigned long long actual); int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon); +int qemuMonitorEmitGUESTPanicked(qemuMonitorPtr mon); + int qemuMonitorStartCPUs(qemuMonitorPtr mon, virConnectPtr conn); @@ -239,6 +243,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; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2b73884..b6efa52 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -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 qemuMonitorJSONHandleGUESTPanicked(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", qemuMonitorJSONHandleGUESTPanicked, }, { "POWERDOWN", qemuMonitorJSONHandlePowerdown, }, { "RESET", qemuMonitorJSONHandleReset, }, { "RESUME", qemuMonitorJSONHandleResume, }, @@ -593,6 +595,11 @@ static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data qemuMonitorEmitResume(mon); } +static void qemuMonitorJSONHandleGUESTPanicked(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED) +{ + qemuMonitorEmitGUESTPanicked(mon); +} + static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data) { long long offset = 0; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d4fd4fb..29c8c4b 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -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, @@ -1269,6 +1273,98 @@ qemuProcessHandlePMSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED, return 0; } +static int +qemuProcessHandleGUESTPanicked(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm) +{ + virQEMUDriverPtr driver = qemu_driver; + qemuDomainObjPrivatePtr priv; + virDomainEventPtr event = NULL; + bool isReboot = true; + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + + VIR_DEBUG("vm=%p", vm); + + virObjectLock(vm); + + if (!virDomainObjIsActive(vm)) { + VIR_DEBUG("Ignoring GUEST_PANICKED event from inactive domain %s", + vm->def->name); + goto cleanup; + } + + priv = vm->privateData; + + virDomainObjSetState(vm, + VIR_DOMAIN_CRASHED, + VIR_DOMAIN_CRASHED_PANICKED); + + event = virDomainEventNewFromObj(vm, + VIR_DOMAIN_EVENT_CRASHED, + VIR_DOMAIN_EVENT_CRASHED_PANICKED); + + if (vm->def->onCrash == VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE) { + VIR_FREE(priv->lockState); + + 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); + } + + goto cleanup; + } + + if (vm->def->onCrash == VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY) { + isReboot = false; + VIR_INFO("Domain on_crash setting overridden, shutting down"); + } + + qemuDomainSetFakeReboot(driver, vm, isReboot); + + if (isReboot) { + qemuProcessShutdownOrReboot(driver, vm); + } else { + 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); + + virDomainAuditStop(vm, "destroyed"); + + if (! vm->persistent) { + qemuDomainRemoveInactive(driver, vm); + vm = NULL; + } + } + +cleanup: + if (vm) + virObjectUnlock(vm); + if (event) + qemuDomainEventQueue(driver, event); + virObjectUnref(cfg); + + return 0; +} static qemuMonitorCallbacks monitorCallbacks = { .destroy = qemuProcessHandleMonitorDestroy, @@ -1289,6 +1385,7 @@ static qemuMonitorCallbacks monitorCallbacks = { .domainPMSuspend = qemuProcessHandlePMSuspend, .domainBalloonChange = qemuProcessHandleBalloonChange, .domainPMSuspendDisk = qemuProcessHandlePMSuspendDisk, + .domainGUESTPanicked = qemuProcessHandleGUESTPanicked, }; static int @@ -2673,6 +2770,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, "was crashed")); } else { newState = VIR_DOMAIN_PAUSED; newReason = reason; -- 1.8.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list