Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > ebe084c140192657f9094e135a84202c > files > 115

libvirt-0.8.2-29.el5.src.rpm

From f0835d3cc79f212378659eb50d076bd01c3c2967 Mon Sep 17 00:00:00 2001
Message-Id: <f0835d3cc79f212378659eb50d076bd01c3c2967.1289922177.git.jdenemar@redhat.com>
From: Jiri Denemark <jdenemar@redhat.com>
Date: Fri, 5 Nov 2010 13:51:50 +0100
Subject: [PATCH] qemu: Wire up text monitor events

Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=574017

This patch wires up async events sent through qemu's text monitor to
libvirt events. The main purpose is to update guest's state if it was
stopped because of an I/O error. While I was at it, I wired up other
events as well.

Unfortunately, this is a RHEL-5-only patch since upstream qemu has no
support for event notifications in text monitor.
---
 src/qemu/qemu_monitor.c      |    2 +-
 src/qemu/qemu_monitor_text.c |  132 +++++++++++++++++++++++++++++++++++++++++-
 src/qemu/qemu_monitor_text.h |    4 +-
 3 files changed, 134 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index b05032a..de25dc4 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -912,7 +912,7 @@ int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
     if (mon->json)
         ret = qemuMonitorJSONSetCapabilities(mon);
     else
-        ret = 0;
+        ret = qemuMonitorTextSetCapabilities(mon);
     return ret;
 }
 
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 569742a..4c5de55 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -68,12 +68,83 @@ typedef int qemuMonitorExtraPromptHandler(qemuMonitorPtr mon,
 #define DISK_ENCRYPTION_POSTFIX ") is encrypted."
 #define LINE_ENDING "\r\n"
 
-int qemuMonitorTextIOProcess(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
-                             const char *data,
+#define EVENT_PREFIX        "# "
+#define EVENT_SHUTDOWN      "GUEST: Got shutdown request"
+#define EVENT_POWERDOWN     "GUEST: Got powerdown request"
+#define EVENT_REBOOT        "GUEST: Got reboot request"
+#define EVENT_VMSTOP_PREFIX "VM is stopped due to disk write error: "
+#define EVENT_RTC_PREFIX    "RTC: new time is UTC"
+
+
+static void
+qemuMonitorTextHandleVMStop(qemuMonitorPtr mon,
+                            char *event)
+{
+    char *device;
+    char *sep;
+
+    device = event + strlen(EVENT_VMSTOP_PREFIX);
+
+    sep = strstr(device, ": ");
+    if (sep)
+        *sep = '\0';
+
+    /*
+     * qemu-kvm in RHEL-5 provides human readable reason string in
+     * strerror(errno) form for VMSTOP event. However, qemu-kvm only sends
+     * this event on ENOSPC error so instead of trying to map the
+     * provided reason to a corresponding symbolic name we just hardcode it.
+     */
+    qemuMonitorEmitIOError(mon, device, VIR_DOMAIN_EVENT_IO_ERROR_PAUSE,
+                           "enospc");
+    if (sep)
+        *sep = ':';
+}
+
+
+static void
+qemuMonitorTextHandleRTCChange(qemuMonitorPtr mon,
+                               char *event)
+{
+    long offset;
+
+    if (virStrToLong_i(event + strlen(EVENT_RTC_PREFIX),
+                       NULL, 10, &offset) < 0) {
+        VIR_WARN("cannot parse offset in RTC change event: %s", event);
+        offset = 0;
+    }
+    qemuMonitorEmitRTCChange(mon, offset);
+}
+
+
+static void
+qemuMonitorTextIOProcessEvent(qemuMonitorPtr mon,
+                              char *event)
+{
+    VIR_DEBUG("mon=%p, event='%s'", mon, event);
+
+    if (STREQ(event, EVENT_SHUTDOWN))
+        qemuMonitorEmitShutdown(mon);
+    else if (STREQ(event, EVENT_POWERDOWN))
+        qemuMonitorEmitPowerdown(mon);
+    else if (STREQ(event, EVENT_REBOOT))
+        qemuMonitorEmitReset(mon);
+    else if (STRPREFIX(event, EVENT_VMSTOP_PREFIX))
+        qemuMonitorTextHandleVMStop(mon, event);
+    else if (STRPREFIX(event, EVENT_RTC_PREFIX))
+        qemuMonitorTextHandleRTCChange(mon, event);
+    else
+        VIR_DEBUG("No handler for event '%s'", event);
+}
+
+
+int qemuMonitorTextIOProcess(qemuMonitorPtr mon,
+                             char *data,
                              size_t len ATTRIBUTE_UNUSED,
                              qemuMonitorMessagePtr msg)
 {
     int used = 0;
+    char *evstart;
 
     /* Check for & discard greeting */
     if (STRPREFIX(data, GREETING_PREFIX)) {
@@ -101,6 +172,42 @@ int qemuMonitorTextIOProcess(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     VIR_DEBUG("Process data %d byts of data", (int)(len - used));
 #endif
 
+    /* First process all events and move them to the beginning of data */
+    while ((evstart = strstr(data + used, EVENT_PREFIX))) {
+        char *start = data + used;
+        unsigned int evlen;
+        char *event;
+        char *nl;
+        char end;
+
+        if (!(nl = strstr(evstart, LINE_ENDING))) {
+#if DEBUG_IO
+            VIR_DEBUG0("Partial event, getting out and waiting for more");
+#endif
+            return used;
+        }
+        nl += strlen(LINE_ENDING);
+        end = *nl;
+        *nl = '\0';
+
+        evlen = strlen(evstart);
+        event = strdup(evstart);
+        *nl = end;
+        if (!event) {
+            virReportOOMError();
+            return -1;
+        }
+
+        memmove(start + evlen, start, evstart - start);
+        memcpy(start, event, evlen);
+
+        event[evlen - strlen(LINE_ENDING)] = '\0';
+        qemuMonitorTextIOProcessEvent(mon, event + strlen(EVENT_PREFIX));
+        free(event);
+
+        used += evlen;
+    }
+
     /* Look for a non-zero reply followed by prompt */
     if (msg && !msg->finished) {
         char *start = NULL;
@@ -346,6 +453,27 @@ qemuMonitorSendDiskPassphrase(qemuMonitorPtr mon,
     return 0;
 }
 
+
+int
+qemuMonitorTextSetCapabilities(qemuMonitorPtr mon)
+{
+    char *info = NULL;
+    char *offset;
+
+    if (qemuMonitorCommand(mon, "notify all on", &info) < 0)
+        return -1;
+
+    if (info && *info) {
+        VIR_WARN("Could not enable event notifications on monitor %p: %s",
+                 mon, info);
+    }
+
+    VIR_FREE(info);
+
+    return 0;
+}
+
+
 int
 qemuMonitorTextStartCPUs(qemuMonitorPtr mon,
                          virConnectPtr conn) {
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 9926d34..4e5ac7d 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -31,10 +31,12 @@
 # include "hash.h"
 
 int qemuMonitorTextIOProcess(qemuMonitorPtr mon,
-                             const char *data,
+                             char *data,
                              size_t len,
                              qemuMonitorMessagePtr msg);
 
+int qemuMonitorTextSetCapabilities(qemuMonitorPtr mon);
+
 int qemuMonitorTextStartCPUs(qemuMonitorPtr mon,
                              virConnectPtr conn);
 int qemuMonitorTextStopCPUs(qemuMonitorPtr mon);
-- 
1.7.3.2