`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 | 69 ++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 93 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 30c27db..6976296 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 7d2d6f5..e01c55c 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 a894837..3ba3737 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) {
@@ -1973,6 +1992,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 +2131,8 @@ qemudShutdown(void) {
qemuDriverUnlock(qemu_driver);
virMutexDestroy(&qemu_driver->lock);
+ if (qemu_driver->workerPool)
+ virWorkerPoolFree(qemu_driver->workerPool);
VIR_FREE(qemu_driver);
return 0;
@@ -4428,6 +4453,50 @@ 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;
+
+ if (!qemu_driver->autoDumpPath) {
+ VIR_WARN0("auto_dump_path is not configured. Guest not
dumped");
+ break;
+ }
+
+ 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