[libvirt] [PATCH v3 4/5] Add a watchdog action `dump'

Hu Tao hutao at cn.fujitsu.com
Tue Nov 30 07:13:13 UTC 2010


`dump' watchdog action lets libvirtd to dump the guest when receives a
watchdog event (which probably means a guest crash)

Currently only qemu is supported.
---
 src/Makefile.am        |    2 +-
 src/conf/domain_conf.c |    1 +
 src/conf/domain_conf.h |    1 +
 src/qemu/qemu.conf     |    5 +++
 src/qemu/qemu_conf.c   |   13 +++++++-
 src/qemu/qemu_conf.h   |    4 ++
 src/qemu/qemu_driver.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 5febd76..9484c2d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1089,7 +1089,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 3f14cee..a6cb444 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -245,6 +245,7 @@ VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST,
               "shutdown",
               "poweroff",
               "pause",
+              "dump",
               "none")
 
 VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 899b19f..7f50b79 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -462,6 +462,7 @@ enum virDomainWatchdogAction {
     VIR_DOMAIN_WATCHDOG_ACTION_SHUTDOWN,
     VIR_DOMAIN_WATCHDOG_ACTION_POWEROFF,
     VIR_DOMAIN_WATCHDOG_ACTION_PAUSE,
+    VIR_DOMAIN_WATCHDOG_ACTION_DUMP,
     VIR_DOMAIN_WATCHDOG_ACTION_NONE,
 
     VIR_DOMAIN_WATCHDOG_ACTION_LAST
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
index f4f965e..fb35ebc 100644
--- a/src/qemu/qemu.conf
+++ b/src/qemu/qemu.conf
@@ -191,6 +191,11 @@
 # save_image_format = "raw"
 # dump_image_format = "raw"
 
+# When a domain is configured to be auto-dumped when libvirtd receives a
+# watchdog event from qemu guest, libvirtd will saves dump files in directory
+# specified by auto_dump_path. Default value is /var/lib/libvirt/qemu/dump
+#
+# auto_dump_path = "/var/lib/libvirt/qemu/dump"
 
 # If provided by the host and a hugetlbfs mount point is configured,
 # a guest may request huge page backing.  When this mount point is
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 35caccc..accd0c4 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -386,6 +386,17 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
         }
     }
 
+    p = virConfGetValue (conf, "auto_dump_path");
+    CHECK_TYPE ("auto_dump_path", VIR_CONF_STRING);
+    if (p && p->str) {
+        VIR_FREE(driver->autoDumpPath);
+        if (!(driver->autoDumpPath = strdup(p->str))) {
+            virReportOOMError();
+            virConfFree(conf);
+            return -1;
+        }
+    }
+
      p = virConfGetValue (conf, "hugetlbfs_mount");
      CHECK_TYPE ("hugetlbfs_mount", VIR_CONF_STRING);
      if (p && p->str) {
@@ -5369,7 +5380,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
         }
         ADD_ARG(optstr);
 
-        const char *action = virDomainWatchdogActionTypeToString(watchdog->action);
+        const char *action = virDomainWatchdogActionTypeToString(watchdog->action == VIR_DOMAIN_WATCHDOG_ACTION_DUMP ? VIR_DOMAIN_WATCHDOG_ACTION_PAUSE : 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..72f961a 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -106,6 +106,8 @@ enum qemud_cmd_flags {
 struct qemud_driver {
     virMutex lock;
 
+    struct virWorkerPool *workerPool;
+
     int privileged;
 
     uid_t user;
@@ -173,6 +175,8 @@ struct qemud_driver {
     char *saveImageFormat;
     char *dumpImageFormat;
 
+    char *autoDumpPath;
+
     pciDeviceList *activePciHostdevs;
 
     virBitmapPtr reservedVNCPorts;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 80ce9f6..550c6da 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -55,6 +55,7 @@
 #include "qemu_driver.h"
 #include "qemu_conf.h"
 #include "qemu_monitor.h"
+#include "qemu_monitor_json.h"
 #include "qemu_bridge_filter.h"
 #include "c-ctype.h"
 #include "event.h"
@@ -85,6 +86,7 @@
 #include "files.h"
 #include "fdstream.h"
 #include "configmake.h"
+#include "threadpool.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -137,8 +139,15 @@ struct _qemuDomainObjPrivate {
     int persistentAddrs;
 };
 
+struct watchdogEvent
+{
+    virDomainObjPtr vm;
+    int action;
+};
+
 static int getCompressionType(struct qemud_driver *driver);
 static int doCoreDump(struct qemud_driver *driver, virDomainObjPtr vm, const char *path, int compress);
+static void processWatchdogEvent(void *data);
 
 static int qemudShutdown(void);
 
@@ -1206,6 +1215,16 @@ qemuHandleDomainWatchdog(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
         if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
             VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
     }
+
+    if (vm->def->watchdog->action == VIR_DOMAIN_WATCHDOG_ACTION_DUMP) {
+        struct watchdogEvent *wdEvent;
+        if (VIR_ALLOC(wdEvent) == 0) {
+            wdEvent->action = VIR_DOMAIN_WATCHDOG_ACTION_DUMP;
+            wdEvent->vm = vm;
+            virWorkerPoolSendJob(driver->workerPool, wdEvent);
+        }
+    }
+
     virDomainObjUnlock(vm);
 
     if (watchdogEvent || lifecycleEvent) {
@@ -1788,6 +1807,9 @@ qemudStartup(int privileged) {
         if (virAsprintf(&qemu_driver->snapshotDir,
                         "%s/lib/libvirt/qemu/snapshot", LOCALSTATEDIR) == -1)
             goto out_of_memory;
+        if (virAsprintf(&qemu_driver->autoDumpPath,
+                        "%s/lib/libvirt/qemu/dump", LOCALSTATEDIR) == -1)
+            goto out_of_memory;
     } else {
         uid_t uid = geteuid();
         char *userdir = virGetUserDirectory(uid);
@@ -1816,6 +1838,8 @@ qemudStartup(int privileged) {
             goto out_of_memory;
         if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
             goto out_of_memory;
+        if (virAsprintf(&qemu_driver->autoDumpPath, "%s/qemu/dump", base) == -1)
+            goto out_of_memory;
     }
 
     if (virFileMakePath(qemu_driver->stateDir) != 0) {
@@ -1848,6 +1872,12 @@ qemudStartup(int privileged) {
                   qemu_driver->snapshotDir, virStrerror(errno, ebuf, sizeof ebuf));
         goto error;
     }
+    if (virFileMakePath(qemu_driver->autoDumpPath) != 0) {
+        char ebuf[1024];
+        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
+                  qemu_driver->autoDumpPath, virStrerror(errno, ebuf, sizeof ebuf));
+        goto error;
+    }
 
     /* Configuration paths are either ~/.libvirt/qemu/... (session) or
      * /etc/libvirt/qemu/... (system).
@@ -1973,6 +2003,10 @@ qemudStartup(int privileged) {
 
     qemudAutostartConfigs(qemu_driver);
 
+    qemu_driver->workerPool = virWorkerPoolNew(0, 1, processWatchdogEvent);
+    if (!qemu_driver->workerPool)
+        goto error;
+
     if (conn)
         virConnectClose(conn);
 
@@ -2108,6 +2142,8 @@ qemudShutdown(void) {
 
     qemuDriverUnlock(qemu_driver);
     virMutexDestroy(&qemu_driver->lock);
+    if (qemu_driver->workerPool)
+        virWorkerPoolFree(qemu_driver->workerPool);
     VIR_FREE(qemu_driver);
 
     return 0;
@@ -4433,6 +4469,45 @@ retry:
     }
 }
 
+static void processWatchdogEvent(void *data)
+{
+    struct watchdogEvent *wdEvent = data;
+
+    switch (wdEvent->action) {
+    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
+        {
+            char *dumpfile;
+            int i;
+
+            qemuDomainObjPrivatePtr priv = wdEvent->vm->privateData;
+
+            i = virAsprintf(&dumpfile, "%s/%s-%u", qemu_driver->autoDumpPath, wdEvent->vm->def->name, (unsigned int)time(NULL));
+            dumpfile[i] = '\0';
+
+            qemuDriverLock(qemu_driver);
+            virDomainObjLock(wdEvent->vm);
+
+            if (qemuDomainObjBeginJobWithDriver(qemu_driver, wdEvent->vm) < 0)
+                break;
+
+            doCoreDump(qemu_driver, wdEvent->vm, dumpfile, getCompressionType(qemu_driver));
+            qemuDomainObjEnterMonitorWithDriver(qemu_driver, wdEvent->vm);
+            qemuMonitorJSONStartCPUs(priv->mon, NULL);
+            qemuDomainObjExitMonitorWithDriver(qemu_driver, wdEvent->vm);
+
+            qemuDomainObjEndJob(wdEvent->vm);
+
+            virDomainObjUnlock(wdEvent->vm);
+            qemuDriverUnlock(qemu_driver);
+
+            VIR_FREE(dumpfile);
+        }
+        break;
+    }
+
+    VIR_FREE(wdEvent);
+}
+
 static virDrvOpenStatus qemudOpen(virConnectPtr conn,
                                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                   int flags ATTRIBUTE_UNUSED) {
-- 
1.7.3


-- 
Thanks,
Hu Tao




More information about the libvir-list mailing list