diff options
author | melifaro <melifaro@FreeBSD.org> | 2013-10-15 17:44:35 +0000 |
---|---|---|
committer | melifaro <melifaro@FreeBSD.org> | 2013-10-15 17:44:35 +0000 |
commit | fc696057a55de89b500b5f8a8e722524224759aa (patch) | |
tree | 0a89d032a18b03ae05b1573876e98008ab900b22 /sys/netgraph | |
parent | 519a31817b4f252100bd4f7cb52572d9c5865aff (diff) | |
download | FreeBSD-src-fc696057a55de89b500b5f8a8e722524224759aa.zip FreeBSD-src-fc696057a55de89b500b5f8a8e722524224759aa.tar.gz |
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
Diffstat (limited to 'sys/netgraph')
-rw-r--r-- | sys/netgraph/ng_base.c | 48 |
1 files changed, 26 insertions, 22 deletions
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c index a5fcb14..0b974ce 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); } |