]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Keep track of guest paused state after disk IO / watchdog events
authorDaniel P. Berrange <berrange@redhat.com>
Tue, 16 Feb 2010 12:07:49 +0000 (12:07 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Thu, 1 Apr 2010 11:35:46 +0000 (12:35 +0100)
When a watchdog/IO error occurs, one of the possible actions that
QEMU might take is to pause the guest. In this scenario libvirt
needs to update its internal state for the VM, and emit a
lifecycle event:

  VIR_DOMAIN_EVENT_SUSPENDED

with a detail being one of:

  VIR_DOMAIN_EVENT_SUSPENDED_IOERROR
  VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG

To future proof against possible QEMU support for multiple monitor
consoles, this patch also hooks into the 'STOPPED' event in QEMU
and emits a generic VIR_DOMAIN_EVENT_SUSPENDED_PAUSED event

* include/libvirt/libvirt.h.in: Add VIR_DOMAIN_EVENT_SUSPENDED_IOERROR
* src/qemu/qemu_driver.c: Update VM state to paused when IO error
  or watchdog events occurrs
* src/qemu/qemu_monitor_json.c: Fix typo in disk IO event name

include/libvirt/libvirt.h.in
src/qemu/qemu_driver.c
src/qemu/qemu_monitor_json.c

index 6d8552f6eaadc1fa149a2d2cd4d230a98e595bfe..7cb483e76e7615873bc2db3ba24a4c92e3eade39 100644 (file)
@@ -1384,6 +1384,8 @@ typedef enum {
 typedef enum {
     VIR_DOMAIN_EVENT_SUSPENDED_PAUSED = 0,   /* Normal suspend due to admin pause */
     VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1, /* Suspended for offline migration */
+    VIR_DOMAIN_EVENT_SUSPENDED_IOERROR = 2,  /* Suspended due to a disk I/O error */
+    VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG = 3,  /* Suspended due to a watchdog firing */
 } virDomainEventSuspendedDetailType;
 
 /**
index 9ee5da718eab4538c8923b8e667b83387576651c..4291bc70a4b48543e7f0a226be7bd1f9d3b65510 100644 (file)
@@ -908,6 +908,38 @@ qemuHandleDomainReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
 }
 
 
+static int
+qemuHandleDomainStop(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+                     virDomainObjPtr vm)
+{
+    struct qemud_driver *driver = qemu_driver;
+    virDomainEventPtr event = NULL;
+
+    virDomainObjLock(vm);
+    if (vm->state == VIR_DOMAIN_RUNNING) {
+        VIR_DEBUG("Transitioned guest %s to paused state due to unknown event", vm->def->name);
+
+        vm->state = VIR_DOMAIN_PAUSED;
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_SUSPENDED,
+                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
+
+        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
+            VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
+    }
+    virDomainObjUnlock(vm);
+
+    if (event) {
+        qemuDriverLock(driver);
+        if (event)
+            qemuDomainEventQueue(driver, event);
+        qemuDriverUnlock(driver);
+    }
+
+    return 0;
+}
+
+
 static int
 qemuHandleDomainRTCChange(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                           virDomainObjPtr vm,
@@ -943,15 +975,32 @@ qemuHandleDomainWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                          int action)
 {
     struct qemud_driver *driver = qemu_driver;
-    virDomainEventPtr event;
+    virDomainEventPtr watchdogEvent = NULL;
+    virDomainEventPtr lifecycleEvent = NULL;
 
     virDomainObjLock(vm);
-    event = virDomainEventWatchdogNewFromObj(vm, action);
+    watchdogEvent = virDomainEventWatchdogNewFromObj(vm, action);
+
+    if (action == VIR_DOMAIN_EVENT_WATCHDOG_PAUSE &&
+        vm->state == VIR_DOMAIN_RUNNING) {
+        VIR_DEBUG("Transitioned guest %s to paused state due to watchdog", vm->def->name);
+
+        vm->state = VIR_DOMAIN_PAUSED;
+        lifecycleEvent = virDomainEventNewFromObj(vm,
+                                                  VIR_DOMAIN_EVENT_SUSPENDED,
+                                                  VIR_DOMAIN_EVENT_SUSPENDED_WATCHDOG);
+
+        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
+            VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
+    }
     virDomainObjUnlock(vm);
 
-    if (event) {
+    if (watchdogEvent || lifecycleEvent) {
         qemuDriverLock(driver);
-        qemuDomainEventQueue(driver, event);
+        if (watchdogEvent)
+            qemuDomainEventQueue(driver, watchdogEvent);
+        if (lifecycleEvent)
+            qemuDomainEventQueue(driver, lifecycleEvent);
         qemuDriverUnlock(driver);
     }
 
@@ -966,7 +1015,8 @@ qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
                         int action)
 {
     struct qemud_driver *driver = qemu_driver;
-    virDomainEventPtr event;
+    virDomainEventPtr ioErrorEvent = NULL;
+    virDomainEventPtr lifecycleEvent = NULL;
     const char *srcPath;
     const char *devAlias;
     virDomainDiskDefPtr disk;
@@ -982,12 +1032,28 @@ qemuHandleDomainIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         devAlias = "";
     }
 
-    event = virDomainEventIOErrorNewFromObj(vm, srcPath, devAlias, action);
+    ioErrorEvent = virDomainEventIOErrorNewFromObj(vm, srcPath, devAlias, action);
+
+    if (action == VIR_DOMAIN_EVENT_IO_ERROR_PAUSE &&
+        vm->state == VIR_DOMAIN_RUNNING) {
+        VIR_DEBUG("Transitioned guest %s to paused state due to IO error", vm->def->name);
+
+        vm->state = VIR_DOMAIN_PAUSED;
+        lifecycleEvent = virDomainEventNewFromObj(vm,
+                                                  VIR_DOMAIN_EVENT_SUSPENDED,
+                                                  VIR_DOMAIN_EVENT_SUSPENDED_IOERROR);
+
+        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
+            VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
+    }
     virDomainObjUnlock(vm);
 
-    if (event) {
+    if (ioErrorEvent || lifecycleEvent) {
         qemuDriverLock(driver);
-        qemuDomainEventQueue(driver, event);
+        if (ioErrorEvent)
+            qemuDomainEventQueue(driver, ioErrorEvent);
+        if (lifecycleEvent)
+            qemuDomainEventQueue(driver, lifecycleEvent);
         qemuDriverUnlock(driver);
     }
 
@@ -1090,6 +1156,7 @@ no_memory:
 static qemuMonitorCallbacks monitorCallbacks = {
     .eofNotify = qemuHandleMonitorEOF,
     .diskSecretLookup = findVolumeQcowPassphrase,
+    .domainStop = qemuHandleDomainStop,
     .domainReset = qemuHandleDomainReset,
     .domainRTCChange = qemuHandleDomainRTCChange,
     .domainWatchdog = qemuHandleDomainWatchdog,
index 3901d46674ebac840e03d1e2858e8c5a2913562d..eac3aca4966c8976c5699427d339079bf9c4d4ac 100644 (file)
@@ -66,7 +66,7 @@ struct {
     { "STOP", qemuMonitorJSONHandleStop, },
     { "RTC_CHANGE", qemuMonitorJSONHandleRTCChange, },
     { "WATCHDOG", qemuMonitorJSONHandleWatchdog, },
-    { "DISK_IO_ERROR", qemuMonitorJSONHandleIOError, },
+    { "BLOCK_IO_ERROR", qemuMonitorJSONHandleIOError, },
     { "VNC_CONNECTED", qemuMonitorJSONHandleVNCConnect, },
     { "VNC_INITIALIZED", qemuMonitorJSONHandleVNCInitialize, },
     { "VNC_DISCONNECTED", qemuMonitorJSONHandleVNCDisconnect, },