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