if (virNWFilterDHCPSnoopInit() < 0)
goto err_exit_learnshutdown;
- virNWFilterTechDriversInit(privileged);
+ if (virNWFilterTechDriversInit(privileged) < 0)
+ goto err_dhcpsnoop_shutdown;
if (virNWFilterConfLayerInit(virNWFilterDomainFWUpdateCB,
driverState) < 0)
err_techdrivers_shutdown:
virNWFilterTechDriversShutdown();
+err_dhcpsnoop_shutdown:
virNWFilterDHCPSnoopShutdown();
err_exit_learnshutdown:
virNWFilterLearnShutdown();
if (driverState->privileged) {
virNWFilterConfLayerShutdown();
- virNWFilterTechDriversShutdown();
virNWFilterDHCPSnoopShutdown();
virNWFilterLearnShutdown();
virNWFilterIPAddrMapShutdown();
+ virNWFilterTechDriversShutdown();
nwfilterDriverLock(driverState);
NULL
};
+/* Serializes instantiation of filters. This is necessary
+ * to avoid lock ordering deadlocks. eg __virNWFilterInstantiateFilter
+ * will hold a lock on a virNWFilterObjPtr. This in turn invokes
+ * virNWFilterInstantiate which invokes virNWFilterDetermineMissingVarsRec
+ * which invokes virNWFilterObjFindByName. This iterates over every single
+ * virNWFilterObjPtr in the list. So if 2 threads try to instantiate a
+ * filter in parallel, they'll both hold 1 lock at the top level in
+ * __virNWFilterInstantiateFilter which will cause the other thread
+ * to deadlock in virNWFilterObjFindByName.
+ *
+ * XXX better long term solution is to make virNWFilterObjList use a
+ * hash table as is done for virDomainObjList. You can then get
+ * lockless lookup of objects by name.
+ */
+static virMutex updateMutex;
-void virNWFilterTechDriversInit(bool privileged) {
+int virNWFilterTechDriversInit(bool privileged)
+{
size_t i = 0;
VIR_DEBUG("Initializing NWFilter technology drivers");
+ if (virMutexInitRecursive(&updateMutex) < 0)
+ return -1;
+
while (filter_tech_drivers[i]) {
if (!(filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED))
filter_tech_drivers[i]->init(privileged);
i++;
}
+ return 0;
}
-void virNWFilterTechDriversShutdown(void) {
+void virNWFilterTechDriversShutdown(void)
+{
size_t i = 0;
while (filter_tech_drivers[i]) {
if ((filter_tech_drivers[i]->flags & TECHDRV_FLAG_INITIALIZED))
filter_tech_drivers[i]->shutdown();
i++;
}
+ virMutexDestroy(&updateMutex);
}
virNWFilterTechDriverPtr
-virNWFilterTechDriverForName(const char *name) {
+virNWFilterTechDriverForName(const char *name)
+{
size_t i = 0;
while (filter_tech_drivers[i]) {
if (STREQ(filter_tech_drivers[i]->name, name)) {
int ifindex;
int rc;
+ virMutexLock(&updateMutex);
+
/* after grabbing the filter update lock check for the interface; if
it's not there anymore its filters will be or are being removed
(while holding the lock) and we don't want to build new ones */
foundNewFilter);
cleanup:
+ virMutexUnlock(&updateMutex);
+
return rc;
}
bool foundNewFilter = false;
virNWFilterReadLockFilterUpdates();
+ virMutexLock(&updateMutex);
rc = __virNWFilterInstantiateFilter(driver,
vmuuid,
}
virNWFilterUnlockFilterUpdates();
+ virMutexUnlock(&updateMutex);
return rc;
}
int
virNWFilterTeardownFilter(const virDomainNetDef *net)
{
- return _virNWFilterTeardownFilter(net->ifname);
+ int ret;
+ virMutexLock(&updateMutex);
+ ret = _virNWFilterTeardownFilter(net->ifname);
+ virMutexUnlock(&updateMutex);
+ return ret;
}