aboutsummaryrefslogtreecommitdiff
path: root/sys/netgraph
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2013-10-15 17:44:35 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2013-10-15 17:44:35 +0000
commitd2fd078832ecf127d74fe062a3961efd17012dbd (patch)
tree0a89d032a18b03ae05b1573876e98008ab900b22 /sys/netgraph
parent6ef5a07e279d15744bd98205974c3f5ee2ca3bef (diff)
downloadsrc-d2fd078832ecf127d74fe062a3961efd17012dbd.tar.gz
src-d2fd078832ecf127d74fe062a3961efd17012dbd.zip
Improve locking model used to protect netgraph topology:
use rwlocks instead of mutexes on node traversal. Reviewed by: glebius Tested by: Eugene Grosbein <egrosbein@rdtc.ru> MFC after: 2 weeks Sponsored by: Yandex LLC
Notes
Notes: svn path=/head/; revision=256550
Diffstat (limited to 'sys/netgraph')
-rw-r--r--sys/netgraph/ng_base.c48
1 files changed, 26 insertions, 22 deletions
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
index a5fcb1432758..0b974ce4fd5b 100644
--- a/sys/netgraph/ng_base.c
+++ b/sys/netgraph/ng_base.c
@@ -74,7 +74,12 @@
MODULE_VERSION(netgraph, NG_ABI_VERSION);
/* Mutex to protect topology events. */
-static struct mtx ng_topo_mtx;
+static struct rwlock ng_topo_lock;
+#define TOPOLOGY_RLOCK() rw_rlock(&ng_topo_lock)
+#define TOPOLOGY_RUNLOCK() rw_runlock(&ng_topo_lock)
+#define TOPOLOGY_WLOCK() rw_wlock(&ng_topo_lock)
+#define TOPOLOGY_WUNLOCK() rw_wunlock(&ng_topo_lock)
+#define TOPOLOGY_NOTOWNED() rw_assert(&ng_topo_lock, RA_UNLOCKED)
#ifdef NETGRAPH_DEBUG
static struct mtx ng_nodelist_mtx; /* protects global node/hook lists */
@@ -1162,7 +1167,7 @@ ng_destroy_hook(hook_p hook)
* Protect divorce process with mutex, to avoid races on
* simultaneous disconnect.
*/
- mtx_lock(&ng_topo_mtx);
+ TOPOLOGY_WLOCK();
hook->hk_flags |= HK_INVALID;
@@ -1182,17 +1187,17 @@ ng_destroy_hook(hook_p hook)
* If it's already divorced from a node,
* just free it.
*/
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
} else {
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
ng_rmhook_self(peer); /* Send it a surprise */
}
NG_HOOK_UNREF(peer); /* account for peer link */
NG_HOOK_UNREF(hook); /* account for peer link */
} else
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
- mtx_assert(&ng_topo_mtx, MA_NOTOWNED);
+ TOPOLOGY_NOTOWNED();
/*
* Remove the hook from the node's list to avoid possible recursion
@@ -1233,9 +1238,9 @@ ng_bypass(hook_p hook1, hook_p hook2)
TRAP_ERROR();
return (EINVAL);
}
- mtx_lock(&ng_topo_mtx);
+ TOPOLOGY_WLOCK();
if (NG_HOOK_NOT_VALID(hook1) || NG_HOOK_NOT_VALID(hook2)) {
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
return (EINVAL);
}
hook1->hk_peer->hk_peer = hook2->hk_peer;
@@ -1243,7 +1248,7 @@ ng_bypass(hook_p hook1, hook_p hook2)
hook1->hk_peer = &ng_deadhook;
hook2->hk_peer = &ng_deadhook;
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
NG_HOOK_UNREF(hook1);
NG_HOOK_UNREF(hook2);
@@ -1440,15 +1445,15 @@ ng_con_part2(node_p node, item_p item, hook_p hook)
/*
* Acquire topo mutex to avoid race with ng_destroy_hook().
*/
- mtx_lock(&ng_topo_mtx);
+ TOPOLOGY_RLOCK();
peer = hook->hk_peer;
if (peer == &ng_deadhook) {
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_RUNLOCK();
printf("failed in ng_con_part2(B)\n");
ng_destroy_hook(hook);
ERROUT(ENOENT);
}
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_RUNLOCK();
if ((error = ng_send_fn2(peer->hk_node, peer, item, &ng_con_part3,
NULL, 0, NG_REUSE_ITEM))) {
@@ -1793,14 +1798,14 @@ ng_path2noderef(node_p here, const char *address, node_p *destp,
/* We have a segment, so look for a hook by that name */
hook = ng_findhook(node, segment);
- mtx_lock(&ng_topo_mtx);
+ TOPOLOGY_WLOCK();
/* Can't get there from here... */
if (hook == NULL || NG_HOOK_PEER(hook) == NULL ||
NG_HOOK_NOT_VALID(hook) ||
NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))) {
TRAP_ERROR();
NG_NODE_UNREF(node);
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
return (ENOENT);
}
@@ -1817,7 +1822,7 @@ ng_path2noderef(node_p here, const char *address, node_p *destp,
NG_NODE_UNREF(oldnode); /* XXX another race */
if (NG_NODE_NOT_VALID(node)) {
NG_NODE_UNREF(node); /* XXX more races */
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
TRAP_ERROR();
return (ENXIO);
}
@@ -1830,11 +1835,11 @@ ng_path2noderef(node_p here, const char *address, node_p *destp,
} else
*lasthook = NULL;
}
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
*destp = node;
return (0);
}
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_WUNLOCK();
}
}
@@ -3202,8 +3207,7 @@ ngb_mod_event(module_t mod, int event, void *data)
rw_init(&ng_typelist_lock, "netgraph types");
rw_init(&ng_idhash_lock, "netgraph idhash");
rw_init(&ng_namehash_lock, "netgraph namehash");
- mtx_init(&ng_topo_mtx, "netgraph topology mutex", NULL,
- MTX_DEF);
+ rw_init(&ng_topo_lock, "netgraph topology mutex");
#ifdef NETGRAPH_DEBUG
mtx_init(&ng_nodelist_mtx, "netgraph nodelist mutex", NULL,
MTX_DEF);
@@ -3579,13 +3583,13 @@ ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr)
* that the peer is still connected (even if invalid,) we know
* that the peer node is present, though maybe invalid.
*/
- mtx_lock(&ng_topo_mtx);
+ TOPOLOGY_RLOCK();
if ((hook == NULL) || NG_HOOK_NOT_VALID(hook) ||
NG_HOOK_NOT_VALID(peer = NG_HOOK_PEER(hook)) ||
NG_NODE_NOT_VALID(peernode = NG_PEER_NODE(hook))) {
NG_FREE_ITEM(item);
TRAP_ERROR();
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_RUNLOCK();
return (ENETDOWN);
}
@@ -3598,7 +3602,7 @@ ng_address_hook(node_p here, item_p item, hook_p hook, ng_ID_t retaddr)
NGI_SET_NODE(item, peernode);
SET_RETADDR(item, here, retaddr);
- mtx_unlock(&ng_topo_mtx);
+ TOPOLOGY_RUNLOCK();
return (0);
}