[libvirt] [PATCH v6 0/5] libvirt supports Guest Panicked

Changes: v5-v6: Refactor the patches, and fix the incorrect indentation and name. v4-v5: 1. fix the incorrect indentation and explanation (of some reasons). v3-v4: 1. Supports the dumpcore options of the oncrash element in the XML. 2. Move the previous code to processWatchdogEvent(). v2-v3: 1. split into 3 patches v1-v2: 1. fix the incorrect domain state: paused -> crashed, when crash the guest while libvirt isn't running, then restart libvirtd. Chen Fan (5): libvirt: Define domain crash event types qemu: Refactor the processwatchdogEvent code that can make the driver workpool more generalized qemu: Need to use qemuProcessShutdownOrReboot(), so we defined it at qemu_process.h qemu: Implement 'oncrash' events when guest panicked qemu: Implement 'oncrash' coredump events when guest panicked examples/domain-events/events-c/event-test.c | 10 ++ include/libvirt/libvirt.h.in | 16 ++ src/conf/domain_conf.c | 12 +- src/qemu/qemu_domain.h | 11 +- src/qemu/qemu_driver.c | 222 ++++++++++++++++++++++++--- src/qemu/qemu_monitor.c | 14 +- src/qemu/qemu_monitor.h | 4 + src/qemu/qemu_monitor_json.c | 7 + src/qemu/qemu_process.c | 60 +++++++- src/qemu/qemu_process.h | 3 + tools/virsh-domain-monitor.c | 8 + 11 files changed, 328 insertions(+), 39 deletions(-) -- 1.8.1.4

This patch introduces domain crashed types and crashed reasons which will be used while guest panicked. --- examples/domain-events/events-c/event-test.c | 10 ++++++++++ include/libvirt/libvirt.h.in | 16 ++++++++++++++++ src/conf/domain_conf.c | 12 ++++++++---- tools/virsh-domain-monitor.c | 8 ++++++++ 4 files changed, 42 insertions(+), 4 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..a406dc7 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 2b4e160..c02b725 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", + "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", + "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") diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index b284154..26e2c5e 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_("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

On Fri, Jun 07, 2013 at 06:23:31PM +0800, Chen Fan wrote:
This patch introduces domain crashed types and crashed reasons which will be used while guest panicked. --- examples/domain-events/events-c/event-test.c | 10 ++++++++++ include/libvirt/libvirt.h.in | 16 ++++++++++++++++ src/conf/domain_conf.c | 12 ++++++++---- tools/virsh-domain-monitor.c | 8 ++++++++ 4 files changed, 42 insertions(+), 4 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

--- src/qemu/qemu_domain.h | 10 ++++++-- src/qemu/qemu_driver.c | 65 +++++++++++++++++++++++++++++++------------------ src/qemu/qemu_process.c | 13 +++++----- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index f241296..aedb66b 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -170,9 +170,15 @@ struct _qemuDomainObjPrivate { virCgroupPtr cgroup; }; -struct qemuDomainWatchdogEvent -{ +typedef enum { + QEMU_PROCESS_EVENT_WATCHDOG = 0, + + QEMU_PROCESS_EVENT_LAST +} qemuProcessEventType; + +struct qemuProcessEvent { virDomainObjPtr vm; + qemuProcessEventType eventType; int action; }; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4a76f14..16f826c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -133,7 +133,11 @@ #define QEMU_NB_BANDWIDTH_PARAM 6 -static void processWatchdogEvent(void *data, void *opaque); +static void processWatchdogEvent(virQEMUDriverPtr driver, + virDomainObjPtr vm, + int action); + +static void qemuProcessEventHandler(void *data, void *opaque); static int qemuStateCleanup(void); @@ -809,7 +813,7 @@ qemuStateInitialize(bool privileged, qemuDomainManagedSaveLoad, qemu_driver); - qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, processWatchdogEvent, qemu_driver); + qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, qemuProcessEventHandler, qemu_driver); if (!qemu_driver->workerPool) goto error; @@ -3441,17 +3445,12 @@ cleanup: return ret; } -static void processWatchdogEvent(void *data, void *opaque) +static void processWatchdogEvent(virQEMUDriverPtr driver, virDomainObjPtr vm, int action) { int ret; - struct qemuDomainWatchdogEvent *wdEvent = data; - virQEMUDriverPtr driver = opaque; - virQEMUDriverConfigPtr cfg; - - virObjectLock(wdEvent->vm); - cfg = virQEMUDriverGetConfig(driver); + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); - switch (wdEvent->action) { + switch (action) { case VIR_DOMAIN_WATCHDOG_ACTION_DUMP: { char *dumpfile; @@ -3459,19 +3458,19 @@ static void processWatchdogEvent(void *data, void *opaque) if (virAsprintf(&dumpfile, "%s/%s-%u", cfg->autoDumpPath, - wdEvent->vm->def->name, + vm->def->name, (unsigned int)time(NULL)) < 0) { virReportOOMError(); - goto unlock; + goto cleanup; } - if (qemuDomainObjBeginAsyncJob(driver, wdEvent->vm, - QEMU_ASYNC_JOB_DUMP) < 0) { + if (qemuDomainObjBeginAsyncJob(driver, vm, + QEMU_ASYNC_JOB_DUMP) < 0) { VIR_FREE(dumpfile); - goto unlock; + goto cleanup; } - if (!virDomainObjIsActive(wdEvent->vm)) { + if (!virDomainObjIsActive(vm)) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("domain is not running")); VIR_FREE(dumpfile); @@ -3479,13 +3478,13 @@ static void processWatchdogEvent(void *data, void *opaque) } flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0; - ret = doCoreDump(driver, wdEvent->vm, dumpfile, + ret = doCoreDump(driver, vm, dumpfile, getCompressionType(driver), flags); if (ret < 0) virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("Dump failed")); - ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL, + ret = qemuProcessStartCPUs(driver, vm, NULL, VIR_DOMAIN_RUNNING_UNPAUSED, QEMU_ASYNC_JOB_DUMP); @@ -3497,22 +3496,40 @@ static void processWatchdogEvent(void *data, void *opaque) } break; default: - goto unlock; + goto cleanup; } endjob: /* Safe to ignore value since ref count was incremented in * qemuProcessHandleWatchdog(). */ - ignore_value(qemuDomainObjEndAsyncJob(driver, wdEvent->vm)); + ignore_value(qemuDomainObjEndAsyncJob(driver, vm)); -unlock: - virObjectUnlock(wdEvent->vm); - virObjectUnref(wdEvent->vm); - VIR_FREE(wdEvent); +cleanup: virObjectUnref(cfg); } +static void qemuProcessEventHandler(void *data, void *opaque) +{ + struct qemuProcessEvent *processEvent = data; + virDomainObjPtr vm = processEvent->vm; + virQEMUDriverPtr driver = opaque; + + virObjectLock(vm); + + switch (processEvent->eventType) { + case QEMU_PROCESS_EVENT_WATCHDOG: + processWatchdogEvent(driver, vm, processEvent->action); + break; + default: + break; + } + + if (virObjectUnref(vm)) + virObjectUnlock(vm); + VIR_FREE(processEvent); +} + static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver, virDomainObjPtr vm, unsigned int nvcpus) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d4fd4fb..7a1535e 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -848,18 +848,19 @@ qemuProcessHandleWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED, } if (vm->def->watchdog->action == VIR_DOMAIN_WATCHDOG_ACTION_DUMP) { - struct qemuDomainWatchdogEvent *wdEvent; - if (VIR_ALLOC(wdEvent) == 0) { - wdEvent->action = VIR_DOMAIN_WATCHDOG_ACTION_DUMP; - wdEvent->vm = vm; + struct qemuProcessEvent *processEvent; + if (VIR_ALLOC(processEvent) == 0) { + processEvent->eventType = QEMU_PROCESS_EVENT_WATCHDOG; + processEvent->action = VIR_DOMAIN_WATCHDOG_ACTION_DUMP; + processEvent->vm = vm; /* Hold an extra reference because we can't allow 'vm' to be * deleted before handling watchdog event is finished. */ virObjectRef(vm); - if (virThreadPoolSendJob(driver->workerPool, 0, wdEvent) < 0) { + if (virThreadPoolSendJob(driver->workerPool, 0, processEvent) < 0) { if (!virObjectUnref(vm)) vm = NULL; - VIR_FREE(wdEvent); + VIR_FREE(processEvent); } } else { virReportOOMError(); -- 1.8.1.4

On Fri, Jun 07, 2013 at 06:23:32PM +0800, Chen Fan wrote:
--- src/qemu/qemu_domain.h | 10 ++++++-- src/qemu/qemu_driver.c | 65 +++++++++++++++++++++++++++++++------------------ src/qemu/qemu_process.c | 13 +++++----- 3 files changed, 56 insertions(+), 32 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 06/07/2013 04:23 AM, Chen Fan wrote: I'm working on applying this series, now that it has acks. The subject line is rather long; I'm moving the bulk of it into the commit message so that 'git shortlog -30' remains readable.
--- src/qemu/qemu_domain.h | 10 ++++++-- src/qemu/qemu_driver.c | 65 +++++++++++++++++++++++++++++++------------------ src/qemu/qemu_process.c | 13 +++++----- 3 files changed, 56 insertions(+), 32 deletions(-)
-- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

--- src/qemu/qemu_process.c | 2 +- src/qemu/qemu_process.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 7a1535e..163bd96 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -611,7 +611,7 @@ cleanup: } -static void +void qemuProcessShutdownOrReboot(virQEMUDriverPtr driver, virDomainObjPtr vm) { diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index d4768fc..8c81e40 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -86,6 +86,9 @@ typedef enum { int qemuProcessKill(virDomainObjPtr vm, unsigned int flags); +void qemuProcessShutdownOrReboot(virQEMUDriverPtr driver, + virDomainObjPtr vm); + int qemuProcessAutoDestroyInit(virQEMUDriverPtr driver); void qemuProcessAutoDestroyShutdown(virQEMUDriverPtr driver); int qemuProcessAutoDestroyAdd(virQEMUDriverPtr driver, -- 1.8.1.4

On Fri, Jun 07, 2013 at 06:23:33PM +0800, Chen Fan wrote:
--- src/qemu/qemu_process.c | 2 +- src/qemu/qemu_process.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Add monitor callback API domainGuestPanic, that implements 'destroy', 'restart' and 'preserve' events of the 'on_crash' in the XML when domain crashed. --- src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 14 ++++++- src/qemu/qemu_monitor.h | 4 ++ src/qemu/qemu_monitor_json.c | 7 ++++ src/qemu/qemu_process.c | 45 +++++++++++++++++++++- 6 files changed, 161 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index aedb66b..ac3eea9 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -172,6 +172,7 @@ struct _qemuDomainObjPrivate { typedef enum { QEMU_PROCESS_EVENT_WATCHDOG = 0, + QEMU_PROCESS_EVENT_GUESTPANIC, QEMU_PROCESS_EVENT_LAST } qemuProcessEventType; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 16f826c..24df772 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -137,6 +137,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); @@ -3509,18 +3513,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; } diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 4e35f79..442f6fa 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-panic") typedef enum { QEMU_MONITOR_BLOCK_IO_STATUS_OK, @@ -1032,6 +1032,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; @@ -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..f0a8c6f 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 (*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; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2b73884..2dd832c 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 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; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 163bd96..0658d91 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, @@ -1271,6 +1275,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, @@ -1290,6 +1328,7 @@ static qemuMonitorCallbacks monitorCallbacks = { .domainPMSuspend = qemuProcessHandlePMSuspend, .domainBalloonChange = qemuProcessHandleBalloonChange, .domainPMSuspendDisk = qemuProcessHandlePMSuspendDisk, + .domainGuestPanic = qemuProcessHandleGuestPanic, }; static int @@ -2674,6 +2713,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; -- 1.8.1.4

On Fri, Jun 07, 2013 at 06:23:34PM +0800, Chen Fan wrote:
Add monitor callback API domainGuestPanic, that implements 'destroy', 'restart' and 'preserve' events of the 'on_crash' in the XML when domain crashed. --- src/qemu/qemu_domain.h | 1 + src/qemu/qemu_driver.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.c | 14 ++++++- src/qemu/qemu_monitor.h | 4 ++ src/qemu/qemu_monitor_json.c | 7 ++++ src/qemu/qemu_process.c | 45 +++++++++++++++++++++- 6 files changed, 161 insertions(+), 2 deletions(-)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Add doDumpCoreToAutoPath to implement 'coredump-destroy' and 'coredump-restart' events of the 'on_crash' in the XML when domain crashed. --- src/qemu/qemu_driver.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 24df772..eefe7a2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3513,6 +3513,59 @@ cleanup: virObjectUnref(cfg); } +static int +doCoreDumpToAutoDumpPath(virQEMUDriverPtr driver, + virDomainObjPtr vm, + unsigned int flags) +{ + int ret = -1; + char *dumpfile = NULL; + time_t curtime = time(NULL); + char timestr[100]; + struct tm time_info; + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + + localtime_r(&curtime, &time_info); + strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info); + + if (virAsprintf(&dumpfile, "%s/%s-%s", + cfg->autoDumpPath, + vm->def->name, + timestr) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (qemuDomainObjBeginAsyncJob(driver, vm, + QEMU_ASYNC_JOB_DUMP) < 0) { + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto endjob; + } + + flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0; + ret = doCoreDump(driver, vm, dumpfile, + getCompressionType(driver), flags); + if (ret < 0) + virReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("Dump failed")); + +endjob: + /* Safe to ignore value since ref count was incremented in + * qemuProcessHandleGuestPanic(). + */ + ignore_value(qemuDomainObjEndAsyncJob(driver, vm)); + +cleanup: + VIR_FREE(dumpfile); + virObjectUnref(cfg); + return ret; +} + static void processGuestPanicEvent(virQEMUDriverPtr driver, virDomainObjPtr vm, @@ -3549,6 +3602,12 @@ processGuestPanicEvent(virQEMUDriverPtr driver, } switch (action) { + case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY: + if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0) { + goto cleanup; + } + /* fall through */ + case VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY: priv->beingDestroyed = true; @@ -3580,6 +3639,12 @@ processGuestPanicEvent(virQEMUDriverPtr driver, } break; + case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_RESTART: + if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0) { + goto cleanup; + } + /* fall through */ + case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART: qemuDomainSetFakeReboot(driver, vm, true); qemuProcessShutdownOrReboot(driver, vm); -- 1.8.1.4

On Fri, Jun 07, 2013 at 06:23:35PM +0800, Chen Fan wrote:
Add doDumpCoreToAutoPath to implement 'coredump-destroy' and 'coredump-restart' events of the 'on_crash' in the XML when domain crashed. --- src/qemu/qemu_driver.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+)
ACK Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On 07/02/2013 05:19 AM, Daniel P. Berrange wrote:
On Fri, Jun 07, 2013 at 06:23:35PM +0800, Chen Fan wrote:
Add doDumpCoreToAutoPath to implement 'coredump-destroy' and 'coredump-restart' events of the 'on_crash' in the XML when domain crashed. --- src/qemu/qemu_driver.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+)
ACK
Series now pushed. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

Hi Chen, applied and tested successfully on s390x platform again. I think Daniel and/or Eric will have a look at this new version. Thanks so far. Mit freundlichen Grüßen / Kind regards Daniel Hansel IBM Deutschland Research & Development GmbH Vorsitzende des Aufsichtsrats: Martina Koederitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294 On 07.06.2013 12:23, Chen Fan wrote:
Changes: v5-v6: Refactor the patches, and fix the incorrect indentation and name.
v4-v5: 1. fix the incorrect indentation and explanation (of some reasons).
v3-v4: 1. Supports the dumpcore options of the oncrash element in the XML. 2. Move the previous code to processWatchdogEvent().
v2-v3: 1. split into 3 patches
v1-v2: 1. fix the incorrect domain state: paused -> crashed, when crash the guest while libvirt isn't running, then restart libvirtd.
Chen Fan (5): libvirt: Define domain crash event types qemu: Refactor the processwatchdogEvent code that can make the driver workpool more generalized qemu: Need to use qemuProcessShutdownOrReboot(), so we defined it at qemu_process.h qemu: Implement 'oncrash' events when guest panicked qemu: Implement 'oncrash' coredump events when guest panicked
examples/domain-events/events-c/event-test.c | 10 ++ include/libvirt/libvirt.h.in | 16 ++ src/conf/domain_conf.c | 12 +- src/qemu/qemu_domain.h | 11 +- src/qemu/qemu_driver.c | 222 ++++++++++++++++++++++++--- src/qemu/qemu_monitor.c | 14 +- src/qemu/qemu_monitor.h | 4 + src/qemu/qemu_monitor_json.c | 7 + src/qemu/qemu_process.c | 60 +++++++- src/qemu/qemu_process.h | 3 + tools/virsh-domain-monitor.c | 8 + 11 files changed, 328 insertions(+), 39 deletions(-)

On Thu, 2013-06-13 at 15:25 +0200, Daniel Hansel wrote:
Hi Chen,
applied and tested successfully on s390x platform again.
I think Daniel and/or Eric will have a look at this new version.
Thanks so far.
Thanks for your test. Actually,I need some ACK. I look forward to Daniel and/or Eric's reply. Thanks, Chen
Mit freundlichen Grüßen / Kind regards Daniel Hansel
IBM Deutschland Research & Development GmbH Vorsitzende des Aufsichtsrats: Martina Koederitz Geschäftsführung: Dirk Wittkopp Sitz der Gesellschaft: Böblingen Registergericht: Amtsgericht Stuttgart, HRB 243294
On 07.06.2013 12:23, Chen Fan wrote:
Changes: v5-v6: Refactor the patches, and fix the incorrect indentation and name.
v4-v5: 1. fix the incorrect indentation and explanation (of some reasons).
v3-v4: 1. Supports the dumpcore options of the oncrash element in the XML. 2. Move the previous code to processWatchdogEvent().
v2-v3: 1. split into 3 patches
v1-v2: 1. fix the incorrect domain state: paused -> crashed, when crash the guest while libvirt isn't running, then restart libvirtd.
Chen Fan (5): libvirt: Define domain crash event types qemu: Refactor the processwatchdogEvent code that can make the driver workpool more generalized qemu: Need to use qemuProcessShutdownOrReboot(), so we defined it at qemu_process.h qemu: Implement 'oncrash' events when guest panicked qemu: Implement 'oncrash' coredump events when guest panicked
examples/domain-events/events-c/event-test.c | 10 ++ include/libvirt/libvirt.h.in | 16 ++ src/conf/domain_conf.c | 12 +- src/qemu/qemu_domain.h | 11 +- src/qemu/qemu_driver.c | 222 ++++++++++++++++++++++++--- src/qemu/qemu_monitor.c | 14 +- src/qemu/qemu_monitor.h | 4 + src/qemu/qemu_monitor_json.c | 7 + src/qemu/qemu_process.c | 60 +++++++- src/qemu/qemu_process.h | 3 + tools/virsh-domain-monitor.c | 8 + 11 files changed, 328 insertions(+), 39 deletions(-)
participants (5)
-
Chen Fan
-
chenfan
-
Daniel Hansel
-
Daniel P. Berrange
-
Eric Blake