`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