]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/libvirt.git/commitdiff
Add a watchdog action `dump'
authorHu Tao <hutao@cn.fujitsu.com>
Wed, 8 Dec 2010 06:19:17 +0000 (14:19 +0800)
committerEric Blake <eblake@redhat.com>
Thu, 9 Dec 2010 18:59:27 +0000 (11:59 -0700)
`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/conf/domain_conf.c
src/conf/domain_conf.h
src/qemu/libvirtd_qemu.aug
src/qemu/qemu.conf
src/qemu/qemu_conf.c
src/qemu/qemu_conf.h
src/qemu/qemu_driver.c
src/qemu/test_libvirtd_qemu.aug

index 9c54a599879153491dfa3a629f3c949e739474bf..109f6fc78a7d3174e7a36b999cd1408fd7eb9bd0 100644 (file)
@@ -244,6 +244,7 @@ VIR_ENUM_IMPL(virDomainWatchdogAction, VIR_DOMAIN_WATCHDOG_ACTION_LAST,
               "shutdown",
               "poweroff",
               "pause",
+              "dump",
               "none")
 
 VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
index 899b19f3951abd1c09051a6069a58ed3e5700288..7f50b794793194812879d87b1f506fc9d81740cb 100644 (file)
@@ -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
index 78852f36316994ff517d98fe69a0876e5feb445d..2f370158c39a418ae0d0e982ff41d6242872758f 100644 (file)
@@ -37,6 +37,7 @@ module Libvirtd_qemu =
                  | str_array_entry "cgroup_device_acl"
                  | str_entry "save_image_format"
                  | str_entry "dump_image_format"
+                 | str_entry "auto_dump_path"
                  | str_entry "hugetlbfs_mount"
                  | bool_entry "relaxed_acs_check"
                  | bool_entry "vnc_allow_host_audio"
index f4f965ec0c31fb8a5b64f586c9e98bc10ce71794..ba41f80b2358b9f0d33f091bc4e60d517ebea29d 100644 (file)
 # 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 save 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
index de89ea2cf596d54958cd37fc2330650ec2527e98..f46beac69b94374f959c58c5d4dc6300857167c0 100644 (file)
@@ -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) {
@@ -5276,7 +5287,10 @@ qemudBuildCommandLine(virConnectPtr conn,
         virCommandAddArg(cmd, optstr);
         VIR_FREE(optstr);
 
-        const char *action = virDomainWatchdogActionTypeToString(watchdog->action);
+        int act = watchdog->action;
+        if (act == VIR_DOMAIN_WATCHDOG_ACTION_DUMP)
+            act = VIR_DOMAIN_WATCHDOG_ACTION_PAUSE;
+        const char *action = virDomainWatchdogActionTypeToString(act);
         if (!action) {
             qemuReportError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("invalid watchdog action"));
index 2d0314c6a98dfb7f82bce8c2bcaf7ac3c7b27fe0..e6b413debcf95fb221ed0eb9031e3fd97d86eb2d 100644 (file)
@@ -43,6 +43,7 @@
 # include "bitmap.h"
 # include "macvtap.h"
 # include "command.h"
+# include "threadpool.h"
 
 # define QEMUD_CPUMASK_LEN CPU_SETSIZE
 
@@ -108,6 +109,8 @@ enum qemud_cmd_flags {
 struct qemud_driver {
     virMutex lock;
 
+    virThreadPoolPtr workerPool;
+
     int privileged;
 
     uid_t user;
@@ -175,6 +178,8 @@ struct qemud_driver {
     char *saveImageFormat;
     char *dumpImageFormat;
 
+    char *autoDumpPath;
+
     pciDeviceList *activePciHostdevs;
 
     virBitmapPtr reservedVNCPorts;
index d000af23518384b9c4d89a5c8e4db4ea6e626d19..19ce9a64ed88c251241116f0302b982d9b56f52e 100644 (file)
@@ -85,6 +85,7 @@
 #include "files.h"
 #include "fdstream.h"
 #include "configmake.h"
+#include "threadpool.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -138,6 +139,14 @@ struct _qemuDomainObjPrivate {
     int persistentAddrs;
 };
 
+struct watchdogEvent
+{
+    virDomainObjPtr vm;
+    int action;
+};
+
+static void processWatchdogEvent(void *data, void *opaque);
+
 static int qemudShutdown(void);
 
 static void qemuDriverLock(struct qemud_driver *driver)
@@ -1225,6 +1234,17 @@ 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;
+            ignore_value(virThreadPoolSendJob(driver->workerPool, wdEvent));
+        } else
+            virReportOOMError();
+    }
+
     virDomainObjUnlock(vm);
 
     if (watchdogEvent || lifecycleEvent) {
@@ -1808,6 +1828,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);
@@ -1836,6 +1859,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) {
@@ -1868,6 +1893,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).
@@ -1993,6 +2024,10 @@ qemudStartup(int privileged) {
 
     qemudAutostartConfigs(qemu_driver);
 
+    qemu_driver->workerPool = virThreadPoolNew(0, 1, processWatchdogEvent, qemu_driver);
+    if (!qemu_driver->workerPool)
+        goto error;
+
     if (conn)
         virConnectClose(conn);
 
@@ -2099,6 +2134,7 @@ qemudShutdown(void) {
     VIR_FREE(qemu_driver->cacheDir);
     VIR_FREE(qemu_driver->saveDir);
     VIR_FREE(qemu_driver->snapshotDir);
+    VIR_FREE(qemu_driver->autoDumpPath);
     VIR_FREE(qemu_driver->vncTLSx509certdir);
     VIR_FREE(qemu_driver->vncListen);
     VIR_FREE(qemu_driver->vncPassword);
@@ -2134,6 +2170,7 @@ qemudShutdown(void) {
 
     qemuDriverUnlock(qemu_driver);
     virMutexDestroy(&qemu_driver->lock);
+    virThreadPoolFree(qemu_driver->workerPool);
     VIR_FREE(qemu_driver);
 
     return 0;
@@ -6230,6 +6267,65 @@ cleanup:
     return ret;
 }
 
+static void processWatchdogEvent(void *data, void *opaque)
+{
+    int ret;
+    struct watchdogEvent *wdEvent = data;
+    struct qemud_driver *driver = opaque;
+
+    switch (wdEvent->action) {
+    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
+        {
+            char *dumpfile;
+            int i;
+
+            qemuDomainObjPrivatePtr priv = wdEvent->vm->privateData;
+
+            i = virAsprintf(&dumpfile, "%s/%s-%u",
+                            driver->autoDumpPath,
+                            wdEvent->vm->def->name,
+                            (unsigned int)time(NULL));
+
+            qemuDriverLock(driver);
+            virDomainObjLock(wdEvent->vm);
+
+            if (qemuDomainObjBeginJobWithDriver(driver, wdEvent->vm) < 0)
+                break;
+
+            if (!virDomainObjIsActive(wdEvent->vm)) {
+                qemuReportError(VIR_ERR_OPERATION_INVALID,
+                                "%s", _("domain is not running"));
+                break;
+            }
+
+            ret = doCoreDump(driver,
+                             wdEvent->vm,
+                             dumpfile,
+                             getCompressionType(driver));
+            if (ret < 0)
+                qemuReportError(VIR_ERR_OPERATION_FAILED,
+                                "%s", _("Dump failed"));
+
+            qemuDomainObjEnterMonitorWithDriver(driver, wdEvent->vm);
+            ret = qemuMonitorStartCPUs(priv->mon, NULL);
+            qemuDomainObjExitMonitorWithDriver(driver, wdEvent->vm);
+
+            if (ret < 0)
+                qemuReportError(VIR_ERR_OPERATION_FAILED,
+                                "%s", _("Resuming after dump failed"));
+
+            if (qemuDomainObjEndJob(wdEvent->vm) > 0)
+                virDomainObjUnlock(wdEvent->vm);
+
+            qemuDriverUnlock(driver);
+
+            VIR_FREE(dumpfile);
+        }
+        break;
+    }
+
+    VIR_FREE(wdEvent);
+}
 
 static int qemudDomainHotplugVcpus(virDomainObjPtr vm, unsigned int nvcpus)
 {
index d3ae58d4d233a5167ecaa0e9d85ad19d3238a601..b4d8833c7eb3823768600e42e37f0627dc773f2e 100644 (file)
@@ -96,6 +96,8 @@ save_image_format = \"gzip\"
 
 dump_image_format = \"gzip\"
 
+auto_dump_path = \"/var/lib/libvirt/qemu/dump\"
+
 hugetlbfs_mount = \"/dev/hugepages\"
 
 set_process_name = 1
@@ -213,6 +215,8 @@ allow_disk_format_probing = 1
 { "#empty" }
 { "dump_image_format" = "gzip" }
 { "#empty" }
+{ "auto_dump_path" = "/var/lib/libvirt/qemu/dump" }
+{ "#empty" }
 { "hugetlbfs_mount" = "/dev/hugepages" }
 { "#empty" }
 { "set_process_name" = "1" }