`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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list