[libvirt] [PATCH] libvirt supports Guest Panicked

From: chenfan <chen.fan.fnst@cn.fujitsu.com> This patch implements qemu_driver supporting guest panicked, modified the 'on_crash' default value to 'preserve'. --- examples/domain-events/events-c/event-test.c | 10 +++ include/libvirt/libvirt.h.in | 16 +++++ src/conf/domain_conf.c | 14 ++-- src/qemu/qemu_monitor.c | 14 +++- src/qemu/qemu_monitor.h | 5 ++ src/qemu/qemu_monitor_json.c | 7 ++ src/qemu/qemu_process.c | 99 +++++++++++++++++++++++++++- tools/virsh-domain-monitor.c | 8 +++ 8 files changed, 166 insertions(+), 7 deletions(-) diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c index eeff50f..1b425fb 100644 --- a/examples/domain-events/events-c/event-test.c +++ b/examples/domain-events/events-c/event-test.c @@ -93,6 +93,9 @@ const char *eventToString(int event) { case VIR_DOMAIN_EVENT_PMSUSPENDED: ret = "PMSuspended"; break; + case VIR_DOMAIN_EVENT_CRASHED: + ret = "Crashed"; + break; } return ret; } @@ -209,6 +212,13 @@ static const char *eventDetailToString(int event, int detail) { break; } break; + case VIR_DOMAIN_EVENT_CRASHED: + switch ((virDomainEventCrashedDetailType) detail) { + case VIR_DOMAIN_EVENT_CRASHED_PANICKED: + ret = "Panicked"; + break; + } + break; } return ret; } diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 1804c93..56c6c5c 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -155,6 +155,7 @@ typedef enum { VIR_DOMAIN_RUNNING_SAVE_CANCELED = 7, /* returned from failed save process */ VIR_DOMAIN_RUNNING_WAKEUP = 8, /* returned from pmsuspended due to wakeup event */ + VIR_DOMAIN_RUNNING_CRASHED = 9, /* resumed from crashed */ #ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_RUNNING_LAST @@ -180,6 +181,7 @@ typedef enum { VIR_DOMAIN_PAUSED_FROM_SNAPSHOT = 7, /* paused after restoring from snapshot */ VIR_DOMAIN_PAUSED_SHUTTING_DOWN = 8, /* paused during shutdown process */ VIR_DOMAIN_PAUSED_SNAPSHOT = 9, /* paused while creating a snapshot */ + VIR_DOMAIN_PAUSED_GUEST_PANICKED = 10, /* paused due to a guest panicked event */ #ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_PAUSED_LAST @@ -189,6 +191,7 @@ typedef enum { typedef enum { VIR_DOMAIN_SHUTDOWN_UNKNOWN = 0, /* the reason is unknown */ VIR_DOMAIN_SHUTDOWN_USER = 1, /* shutting down on user request */ + VIR_DOMAIN_SHUTDOWN_CRASHED = 2, /* domain crashed */ #ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_SHUTDOWN_LAST @@ -212,6 +215,7 @@ typedef enum { typedef enum { VIR_DOMAIN_CRASHED_UNKNOWN = 0, /* crashed for unknown reason */ + VIR_DOMAIN_CRASHED_PANICKED = 1, /* domain panicked */ #ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_CRASHED_LAST @@ -3319,6 +3323,7 @@ typedef enum { VIR_DOMAIN_EVENT_STOPPED = 5, VIR_DOMAIN_EVENT_SHUTDOWN = 6, VIR_DOMAIN_EVENT_PMSUSPENDED = 7, + VIR_DOMAIN_EVENT_CRASHED = 8, #ifdef VIR_ENUM_SENTINELS VIR_DOMAIN_EVENT_LAST @@ -3450,6 +3455,17 @@ typedef enum { #endif } virDomainEventPMSuspendedDetailType; +/* + * Details about the 'crashed' lifecycle event + */ +typedef enum { + VIR_DOMAIN_EVENT_CRASHED_PANICKED = 0, /* Guest was panicked */ + +#ifdef VIR_ENUM_SENTINELS + VIR_DOMAIN_EVENT_CRASHED_LAST +#endif +} virDomainEventCrashedDetailType; + /** * virConnectDomainEventCallback: * @conn: virConnect connection diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a9656af..3f0786e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -642,7 +642,8 @@ VIR_ENUM_IMPL(virDomainRunningReason, VIR_DOMAIN_RUNNING_LAST, "unpaused", "migration canceled", "save canceled", - "wakeup") + "wakeup", + "from crashed") VIR_ENUM_IMPL(virDomainBlockedReason, VIR_DOMAIN_BLOCKED_LAST, "unknown") @@ -657,11 +658,13 @@ VIR_ENUM_IMPL(virDomainPausedReason, VIR_DOMAIN_PAUSED_LAST, "watchdog", "from snapshot", "shutdown", - "snapshot") + "snapshot", + "guest panicked") VIR_ENUM_IMPL(virDomainShutdownReason, VIR_DOMAIN_SHUTDOWN_LAST, "unknown", - "user") + "user", + "crashed") VIR_ENUM_IMPL(virDomainShutoffReason, VIR_DOMAIN_SHUTOFF_LAST, "unknown", @@ -674,7 +677,8 @@ VIR_ENUM_IMPL(virDomainShutoffReason, VIR_DOMAIN_SHUTOFF_LAST, "from snapshot") VIR_ENUM_IMPL(virDomainCrashedReason, VIR_DOMAIN_CRASHED_LAST, - "unknown") + "unknown", + "panicked") VIR_ENUM_IMPL(virDomainPMSuspendedReason, VIR_DOMAIN_PMSUSPENDED_LAST, "unknown") @@ -10943,7 +10947,7 @@ virDomainDefParseXML(xmlDocPtr xml, if (virDomainEventActionParseXML(ctxt, "on_crash", "string(./on_crash[1])", &def->onCrash, - VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY, + VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE, virDomainLifecycleCrashTypeFromString) < 0) goto error; 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..1dc1f3a 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 diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index 5ed89d1..4bddefe 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -192,6 +192,8 @@ vshDomainStateReasonToString(int state, int reason) return N_("save canceled"); case VIR_DOMAIN_RUNNING_WAKEUP: return N_("event wakeup"); + case VIR_DOMAIN_RUNNING_CRASHED: + return N_("from crashed"); case VIR_DOMAIN_RUNNING_UNKNOWN: case VIR_DOMAIN_RUNNING_LAST: ; @@ -226,6 +228,8 @@ vshDomainStateReasonToString(int state, int reason) return N_("shutting down"); case VIR_DOMAIN_PAUSED_SNAPSHOT: return N_("creating snapshot"); + case VIR_DOMAIN_PAUSED_GUEST_PANICKED: + return N_("guest panicked"); case VIR_DOMAIN_PAUSED_UNKNOWN: case VIR_DOMAIN_PAUSED_LAST: ; @@ -236,6 +240,8 @@ vshDomainStateReasonToString(int state, int reason) switch ((virDomainShutdownReason) reason) { case VIR_DOMAIN_SHUTDOWN_USER: return N_("user"); + case VIR_DOMAIN_SHUTDOWN_CRASHED: + return N_("crashed"); case VIR_DOMAIN_SHUTDOWN_UNKNOWN: case VIR_DOMAIN_SHUTDOWN_LAST: ; @@ -266,6 +272,8 @@ vshDomainStateReasonToString(int state, int reason) case VIR_DOMAIN_CRASHED: switch ((virDomainCrashedReason) reason) { + case VIR_DOMAIN_CRASHED_PANICKED: + return N_("panicked"); case VIR_DOMAIN_CRASHED_UNKNOWN: case VIR_DOMAIN_CRASHED_LAST: ; -- 1.8.1.4

From: chenfan <chen.fan.fnst@cn.fujitsu.com>
This patch implements qemu_driver supporting guest panicked, modified the 'on_crash' default value to 'preserve'. It's not good to change the default behavior, if someone wants
On 05/27/2013 10:41 AM, Chen Fan wrote: preserve, make them specify it in the XML.
--- examples/domain-events/events-c/event-test.c | 10 +++ include/libvirt/libvirt.h.in | 16 +++++ src/conf/domain_conf.c | 14 ++-- src/qemu/qemu_monitor.c | 14 +++- src/qemu/qemu_monitor.h | 5 ++ src/qemu/qemu_monitor_json.c | 7 ++ src/qemu/qemu_process.c | 99 +++++++++++++++++++++++++++- tools/virsh-domain-monitor.c | 8 +++ 8 files changed, 166 insertions(+), 7 deletions(-)
not an issue, since it's a fairly small patch, but one could imagine to split it up into a 3-part series: general libvirt, qemu and virsh.
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c @@ -10943,7 +10947,7 @@ virDomainDefParseXML(xmlDocPtr xml, if (virDomainEventActionParseXML(ctxt, "on_crash", "string(./on_crash[1])", &def->onCrash, - VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY, + VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE, virDomainLifecycleCrashTypeFromString) < 0) goto error;
see above, it's not good to change defaults, plus make check fails with this hunk applied. Other than that looks good to me (Tested on s390x with destroy, reboot and preserve). Looking forward to see this in libvirt. -- Mit freundlichen Grüßen/Kind Regards Viktor Mihajlovski IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martina Köderitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

From: chenfan <chen.fan.fnst@cn.fujitsu.com> @@ -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: ; I just have crashed the guest while libvirtd wasn't running, after a restart, virsh domstate --reason always reports
On 05/27/2013 10:41 AM, Chen Fan wrote: paused (guest panicked) while I would expect crashed (guest panicked). Either QEMU is reporting a bogus state or the state computation is flawed somewhere... -- Mit freundlichen Grüßen/Kind Regards Viktor Mihajlovski IBM Deutschland Research & Development GmbH Vorsitzender des Aufsichtsrats: Martina Köderitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294

On Mon, 2013-05-27 at 14:28 +0200, Viktor Mihajlovski wrote:
From: chenfan <chen.fan.fnst@cn.fujitsu.com> @@ -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: ; I just have crashed the guest while libvirtd wasn't running, after a restart, virsh domstate --reason always reports
On 05/27/2013 10:41 AM, Chen Fan wrote: paused (guest panicked) while I would expect crashed (guest panicked). Either QEMU is reporting a bogus state or the state computation is flawed somewhere...
Then I will fix this bug. and remain on_crash default behavior in the XML. Thanks for your comments.
participants (3)
-
Chen Fan
-
chenfan
-
Viktor Mihajlovski