[libvirt] [PATCH 2/2] Add a watchdog action `managed'.

Hu Tao hutao at cn.fujitsu.com
Wed Nov 17 07:45:28 UTC 2010


`managed' watchdog action lets libvirtd decide what to do if a guest
watchdog fires. It has a subaction argument which is the action libvirtd
will take. Currently only `dump' subaction is defined, it tells libvirtd
to dump the guest on a watchdog event.

`managed' watchdog action is mapped to `none' qemu watchdog action, thus
qemu will not get in the way of libvirtd's handling of watchdog events.

Currently only qemu is supported.
---
 src/Makefile.am        |    2 +-
 src/conf/domain_conf.c |   27 ++++++++-
 src/conf/domain_conf.h |   11 ++++-
 src/qemu/qemu_conf.c   |    2 +-
 src/qemu/qemu_conf.h   |    6 ++
 src/qemu/qemu_driver.c |  138 ++++++++++++++++++++++++++++++++++++++++++-----
 6 files changed, 165 insertions(+), 21 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 27bda63..c495e34 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1097,7 +1097,7 @@ libvirt_test_la_LIBADD = $(libvirt_la_LIBADD)
 libvirt_test_la_LDFLAGS = $(test_LDFLAGS) $(AM_LDFLAGS)
 libvirt_test_la_CFLAGS = $(AM_CFLAGS)
 
-libvirt_qemu_la_SOURCES = libvirt-qemu.c
+libvirt_qemu_la_SOURCES = libvirt-qemu.c util/threadpool.c
 libvirt_qemu_la_LDFLAGS = $(VERSION_SCRIPT_FLAGS)$(LIBVIRT_QEMU_SYMBOL_FILE) \
                           -version-info $(LIBVIRT_VERSION_INFO) \
                           $(CYGWIN_EXTRA_LDFLAGS) $(MINGW_EXTRA_LDFLAGS) \
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 30c27db..795cd54 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -245,7 +245,11 @@ VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST,
               "shutdown",
               "poweroff",
               "pause",
-              "none")
+              "none",
+              "managed")
+
+VIR_ENUM_IMPL(virDomainWatchdogSubaction, VIR_DOMAIN_WATCHDOG_SUBACTION_LAST,
+	      "dump")
 
 VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
               "vga",
@@ -3423,6 +3427,7 @@ virDomainWatchdogDefParseXML(const xmlNodePtr node,
 
     char *model = NULL;
     char *action = NULL;
+    char *subaction = NULL;
     virDomainWatchdogDefPtr def;
 
     if (VIR_ALLOC (def) < 0) {
@@ -3453,6 +3458,13 @@ virDomainWatchdogDefParseXML(const xmlNodePtr node,
                                  _("unknown watchdog action '%s'"), action);
             goto error;
         }
+        if (def->action == VIR_DOMAIN_WATCHDOG_ACTION_MANAGED) {
+            subaction = virXMLPropString(node, "subaction");
+            if (subaction) {
+                def->subaction = virDomainWatchdogSubactionTypeFromString(subaction);
+                def->subactionArg = virXMLPropString(node, "subaction_arg");
+            }
+        }
     }
 
     if (virDomainDeviceInfoParseXML(node, &def->info, flags) < 0)
@@ -3460,6 +3472,7 @@ virDomainWatchdogDefParseXML(const xmlNodePtr node,
 
 cleanup:
     VIR_FREE (action);
+    VIR_FREE (subaction);
     VIR_FREE (model);
 
     return def;
@@ -6398,6 +6411,7 @@ virDomainWatchdogDefFormat(virBufferPtr buf,
 {
     const char *model = virDomainWatchdogModelTypeToString (def->model);
     const char *action = virDomainWatchdogActionTypeToString (def->action);
+    const char *subaction = virDomainWatchdogSubactionTypeToString (def->subaction);
 
     if (!model) {
         virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -6411,8 +6425,15 @@ virDomainWatchdogDefFormat(virBufferPtr buf,
         return -1;
     }
 
-    virBufferVSprintf(buf, "    <watchdog model='%s' action='%s'",
-                      model, action);
+    if (subaction && !def->subactionArg)
+        virBufferVSprintf(buf, "    <watchdog model='%s' action='%s' subaction='%s'",
+                          model, action, subaction);
+    else if (subaction && def->subactionArg)
+        virBufferVSprintf(buf, "    <watchdog model='%s' action='%s' subaction='%s' subaction_arg='%s'",
+                          model, action, subaction, (char *)def->subactionArg);
+    else
+        virBufferVSprintf(buf, "    <watchdog model='%s' action='%s'",
+                          model, action);
 
     if (virDomainDeviceInfoIsSet(&def->info)) {
         virBufferAddLit(buf, ">\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 7d2d6f5..2cc6893 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -463,19 +463,27 @@ enum virDomainWatchdogAction {
     VIR_DOMAIN_WATCHDOG_ACTION_POWEROFF,
     VIR_DOMAIN_WATCHDOG_ACTION_PAUSE,
     VIR_DOMAIN_WATCHDOG_ACTION_NONE,
+    VIR_DOMAIN_WATCHDOG_ACTION_MANAGED,
 
     VIR_DOMAIN_WATCHDOG_ACTION_LAST
 };
 
+enum virDomainWatchdogSubAction {
+    VIR_DOMAIN_WATCHDOG_SUBACTION_DUMP,
+
+    VIR_DOMAIN_WATCHDOG_SUBACTION_LAST
+};
+
 typedef struct _virDomainWatchdogDef virDomainWatchdogDef;
 typedef virDomainWatchdogDef *virDomainWatchdogDefPtr;
 struct _virDomainWatchdogDef {
     int model;
     int action;
+    int subaction;
+    void *subactionArg;
     virDomainDeviceInfo info;
 };
 
-
 enum virDomainVideoType {
     VIR_DOMAIN_VIDEO_TYPE_VGA,
     VIR_DOMAIN_VIDEO_TYPE_CIRRUS,
@@ -1247,6 +1255,7 @@ VIR_ENUM_DECL(virDomainSysinfo)
 VIR_ENUM_DECL(virDomainSmbiosMode)
 VIR_ENUM_DECL(virDomainWatchdogModel)
 VIR_ENUM_DECL(virDomainWatchdogAction)
+VIR_ENUM_DECL(virDomainWatchdogSubaction)
 VIR_ENUM_DECL(virDomainVideo)
 VIR_ENUM_DECL(virDomainHostdevMode)
 VIR_ENUM_DECL(virDomainHostdevSubsys)
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 83a117a..f09a72d 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -5367,7 +5367,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
         }
         ADD_ARG(optstr);
 
-        const char *action = virDomainWatchdogActionTypeToString(watchdog->action);
+        const char *action = virDomainWatchdogActionTypeToString(watchdog->action == VIR_DOMAIN_WATCHDOG_ACTION_MANAGED ? VIR_DOMAIN_WATCHDOG_ACTION_NONE : watchdog->action);
         if (!action) {
             qemuReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("invalid watchdog action"));
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 790ce98..49584c8 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -106,6 +106,12 @@ enum qemud_cmd_flags {
 struct qemud_driver {
     virMutex lock;
 
+    virMutex workerPoolLock;
+    int poolRef;
+    struct virWorkerPool *workerPool;
+    int watchdogEventCallbackID;
+    virConnectPtr conn;
+
     int privileged;
 
     uid_t user;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 449534a..349cb0c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -84,6 +84,7 @@
 #include "virtaudit.h"
 #include "files.h"
 #include "fdstream.h"
+#include "threadpool.h"
 
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
@@ -858,18 +859,13 @@ qemudAutostartConfigs(struct qemud_driver *driver) {
      * to lookup the bridge associated with a virtual
      * network
      */
-    virConnectPtr conn = virConnectOpen(driver->privileged ?
-                                        "qemu:///system" :
-                                        "qemu:///session");
     /* Ignoring NULL conn which is mostly harmless here */
-    struct qemuAutostartData data = { driver, conn };
+    struct qemuAutostartData data = { driver, driver->conn };
 
     qemuDriverLock(driver);
     virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
-    qemuDriverUnlock(driver);
 
-    if (conn)
-        virConnectClose(conn);
+    qemuDriverUnlock(driver);
 }
 
 
@@ -1722,7 +1718,6 @@ qemudStartup(int privileged) {
     char *base = NULL;
     char driverConf[PATH_MAX];
     int rc;
-    virConnectPtr conn = NULL;
 
     if (VIR_ALLOC(qemu_driver) < 0)
         return -1;
@@ -1732,6 +1727,11 @@ qemudStartup(int privileged) {
         VIR_FREE(qemu_driver);
         return -1;
     }
+    if (virMutexInit(&qemu_driver->workerPoolLock)) {
+        VIR_ERROR0(_("cannot initialize mutex"));
+        VIR_FREE(qemu_driver);
+        return -1;
+    }
     qemuDriverLock(qemu_driver);
     qemu_driver->privileged = privileged;
 
@@ -1948,11 +1948,11 @@ qemudStartup(int privileged) {
                                 1, NULL, NULL) < 0)
         goto error;
 
-    conn = virConnectOpen(qemu_driver->privileged ?
+    qemu_driver->conn = virConnectOpen(qemu_driver->privileged ?
                           "qemu:///system" :
                           "qemu:///session");
 
-    qemuReconnectDomains(conn, qemu_driver);
+    qemuReconnectDomains(qemu_driver->conn, qemu_driver);
 
     /* Then inactive persistent configs */
     if (virDomainLoadAllConfigs(qemu_driver->caps,
@@ -1970,9 +1970,6 @@ qemudStartup(int privileged) {
 
     qemudAutostartConfigs(qemu_driver);
 
-    if (conn)
-        virConnectClose(conn);
-
     return 0;
 
 out_of_memory:
@@ -1980,8 +1977,6 @@ out_of_memory:
 error:
     if (qemu_driver)
         qemuDriverUnlock(qemu_driver);
-    if (conn)
-        virConnectClose(conn);
     VIR_FREE(base);
     qemudShutdown();
     return -1;
@@ -2059,7 +2054,11 @@ qemudShutdown(void) {
     if (!qemu_driver)
         return -1;
 
+    if (qemu_driver->conn)
+        virConnectClose(qemu_driver->conn);
+
     qemuDriverLock(qemu_driver);
+
     pciDeviceListFree(qemu_driver->activePciHostdevs);
     virCapabilitiesFree(qemu_driver->caps);
 
@@ -4425,6 +4424,82 @@ retry:
     }
 }
 
+struct watchdogEvent
+{
+    virDomain dom;
+    int action;
+    void *actionArg;
+};
+
+static void processWatchdogEvent(void *data)
+{
+    struct watchdogEvent *wdEvent = data;
+
+    switch (wdEvent->action) {
+    case VIR_DOMAIN_WATCHDOG_SUBACTION_DUMP:
+        {
+            char *path = wdEvent->actionArg;
+            char dumpfilePath[4096];
+            int i;
+
+            i = snprintf(dumpfilePath, 4096, "%s/%s-%u", path, wdEvent->dom.name, (unsigned int)time(NULL));
+            dumpfilePath[i] = '\0';
+            virDomainCoreDump(&wdEvent->dom, dumpfilePath, 0);
+        }
+        break;
+    }
+
+    free(wdEvent->dom.name);
+    free(wdEvent);
+}
+
+static int onWatchdogEvent(virConnectPtr conn,
+                           virDomainPtr dom,
+                           int action,
+                           void *opaque ATTRIBUTE_UNUSED)
+{
+    struct qemud_driver *driver = conn->privateData;
+    struct watchdogEvent *wdEvent;
+    virDomainObjPtr vm;
+
+    wdEvent = malloc(sizeof(*wdEvent));
+    if (!wdEvent)
+        return -1;
+
+    vm = virDomainFindByID(&driver->domains, dom->id);
+    if (!vm || !vm->def->watchdog) {
+        free(wdEvent);
+        return -1;
+    }
+
+    if (vm->def->watchdog->action != VIR_DOMAIN_WATCHDOG_ACTION_MANAGED) {
+        virDomainObjUnlock(vm);
+        free(wdEvent);
+        return 0;
+    }
+
+    if (action != 0)
+        return 0;
+
+    wdEvent->dom = *dom;
+    wdEvent->dom.name = malloc(strlen(dom->name));
+    if (!wdEvent->dom.name) {
+        virDomainObjUnlock(vm);
+        free(wdEvent);
+        return -1;
+    }
+    strcpy(wdEvent->dom.name, dom->name);
+
+    wdEvent->action = vm->def->watchdog->subaction;
+    wdEvent->actionArg = vm->def->watchdog->subactionArg;
+
+    virWorkerPoolSendJob(driver->workerPool, wdEvent);
+    virDomainObjUnlock(vm);
+
+    return 0;
+}
+
+
 static virDrvOpenStatus qemudOpen(virConnectPtr conn,
                                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                   int flags ATTRIBUTE_UNUSED) {
@@ -4481,6 +4556,30 @@ static virDrvOpenStatus qemudOpen(virConnectPtr conn,
             }
         }
     }
+
+    virMutexLock(&qemu_driver->workerPoolLock);
+    if (!qemu_driver->workerPool) {
+        qemu_driver->workerPool = virWorkerPoolNew(0, 1, processWatchdogEvent);
+        if (qemu_driver->workerPool) {
+            qemu_driver->watchdogEventCallbackID = virDomainEventCallbackListAddID(conn,
+                                                                                   qemu_driver->domainEventCallbacks,
+                                                                                   NULL,
+                                                                                   VIR_DOMAIN_EVENT_ID_WATCHDOG,
+                                                                                   VIR_DOMAIN_EVENT_CALLBACK(onWatchdogEvent),
+                                                                                   NULL,
+                                                                                   NULL);
+            if (qemu_driver->watchdogEventCallbackID == -1) {
+                virWorkerPoolFree(qemu_driver->workerPool);
+                qemu_driver->workerPool = NULL;
+            } else {
+                qemu_driver->poolRef = 1;
+                conn->refs--;
+            }
+        }
+    } else
+        qemu_driver->poolRef++;
+    virMutexUnlock(&qemu_driver->workerPoolLock);
+
     conn->privateData = qemu_driver;
 
     return VIR_DRV_OPEN_SUCCESS;
@@ -4489,6 +4588,15 @@ static virDrvOpenStatus qemudOpen(virConnectPtr conn,
 static int qemudClose(virConnectPtr conn) {
     struct qemud_driver *driver = conn->privateData;
 
+    virMutexLock(&driver->workerPoolLock);
+    if (--driver->poolRef == 0) {
+        conn->refs--;
+        virDomainEventCallbackListRemoveID(conn, driver->domainEventCallbacks, driver->watchdogEventCallbackID);
+        virWorkerPoolFree(driver->workerPool);
+        driver->workerPool = NULL;
+    }
+    virMutexUnlock(&driver->workerPoolLock);
+
     /* Get rid of callbacks registered for this conn */
     qemuDriverLock(driver);
     virDomainEventCallbackListRemoveConn(conn, driver->domainEventCallbacks);
-- 
1.7.3


-- 
Thanks,
Hu Tao




More information about the libvir-list mailing list