Convert locks that protect name hash, ID hash and typelist from

mutex(9) to rwlock(9) based locks.

While here remove dropping lock when processing NGM_LISTNODES,
and NGM_LISTTYPES generic commands. We don't need to drop it
since memory allocation is done with M_NOWAIT.
This commit is contained in:
Gleb Smirnoff 2012-01-23 15:17:14 +00:00
parent 07c1584e76
commit c4282b741b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=230480

View File

@ -50,6 +50,7 @@
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/queue.h>
@ -57,6 +58,7 @@
#include <sys/syslog.h>
#include <sys/refcount.h>
#include <sys/proc.h>
#include <sys/rwlock.h>
#include <sys/unistd.h>
#include <sys/kthread.h>
#include <sys/smp.h>
@ -163,19 +165,28 @@ static struct mtx ng_worklist_mtx; /* MUST LOCK NODE FIRST */
/* List of installed types */
static LIST_HEAD(, ng_type) ng_typelist;
static struct mtx ng_typelist_mtx;
static struct rwlock ng_typelist_lock;
#define TYPELIST_RLOCK() rw_rlock(&ng_typelist_lock)
#define TYPELIST_RUNLOCK() rw_runlock(&ng_typelist_lock)
#define TYPELIST_WLOCK() rw_wlock(&ng_typelist_lock)
#define TYPELIST_WUNLOCK() rw_wunlock(&ng_typelist_lock)
/* Hash related definitions */
/* XXX Don't need to initialise them because it's a LIST */
static VNET_DEFINE(LIST_HEAD(, ng_node), ng_ID_hash[NG_ID_HASH_SIZE]);
#define V_ng_ID_hash VNET(ng_ID_hash)
static struct mtx ng_idhash_mtx;
static struct rwlock ng_idhash_lock;
#define IDHASH_RLOCK() rw_rlock(&ng_idhash_lock)
#define IDHASH_RUNLOCK() rw_runlock(&ng_idhash_lock)
#define IDHASH_WLOCK() rw_wlock(&ng_idhash_lock)
#define IDHASH_WUNLOCK() rw_wunlock(&ng_idhash_lock)
/* Method to find a node.. used twice so do it here */
#define NG_IDHASH_FN(ID) ((ID) % (NG_ID_HASH_SIZE))
#define NG_IDHASH_FIND(ID, node) \
do { \
mtx_assert(&ng_idhash_mtx, MA_OWNED); \
rw_assert(&ng_idhash_lock, RA_LOCKED); \
LIST_FOREACH(node, &V_ng_ID_hash[NG_IDHASH_FN(ID)], \
nd_idnodes) { \
if (NG_NODE_IS_VALID(node) \
@ -188,7 +199,6 @@ static struct mtx ng_idhash_mtx;
static VNET_DEFINE(LIST_HEAD(, ng_node), ng_name_hash[NG_NAME_HASH_SIZE]);
#define V_ng_name_hash VNET(ng_name_hash)
static struct mtx ng_namehash_mtx;
#define NG_NAMEHASH(NAME, HASH) \
do { \
u_char h = 0; \
@ -198,6 +208,11 @@ static struct mtx ng_namehash_mtx;
(HASH) = h % (NG_NAME_HASH_SIZE); \
} while (0)
static struct rwlock ng_namehash_lock;
#define NAMEHASH_RLOCK() rw_rlock(&ng_namehash_lock)
#define NAMEHASH_RUNLOCK() rw_runlock(&ng_namehash_lock)
#define NAMEHASH_WLOCK() rw_wlock(&ng_namehash_lock)
#define NAMEHASH_WUNLOCK() rw_wunlock(&ng_namehash_lock)
/* Internal functions */
static int ng_add_hook(node_p node, const char *name, hook_p * hookp);
@ -650,12 +665,12 @@ ng_make_node_common(struct ng_type *type, node_p *nodepp)
LIST_INIT(&node->nd_hooks);
/* Link us into the name hash. */
mtx_lock(&ng_namehash_mtx);
NAMEHASH_WLOCK();
LIST_INSERT_HEAD(&V_ng_name_hash[0], node, nd_nodes);
mtx_unlock(&ng_namehash_mtx);
NAMEHASH_WUNLOCK();
/* get an ID and put us in the hash chain */
mtx_lock(&ng_idhash_mtx);
IDHASH_WLOCK();
for (;;) { /* wrap protection, even if silly */
node_p node2 = NULL;
node->nd_ID = V_nextID++; /* 137/sec for 1 year before wrap */
@ -668,7 +683,7 @@ ng_make_node_common(struct ng_type *type, node_p *nodepp)
}
LIST_INSERT_HEAD(&V_ng_ID_hash[NG_IDHASH_FN(node->nd_ID)], node,
nd_idnodes);
mtx_unlock(&ng_idhash_mtx);
IDHASH_WUNLOCK();
/* Done */
*nodepp = node;
@ -780,14 +795,14 @@ ng_unref_node(node_p node)
if (refcount_release(&node->nd_refs)) { /* we were the last */
mtx_lock(&ng_namehash_mtx);
node->nd_type->refs--; /* XXX maybe should get types lock? */
NAMEHASH_WLOCK();
LIST_REMOVE(node, nd_nodes);
mtx_unlock(&ng_namehash_mtx);
NAMEHASH_WUNLOCK();
mtx_lock(&ng_idhash_mtx);
IDHASH_WLOCK();
LIST_REMOVE(node, nd_idnodes);
mtx_unlock(&ng_idhash_mtx);
IDHASH_WUNLOCK();
mtx_destroy(&node->nd_input_queue.q_mtx);
NG_FREE_NODE(node);
@ -801,11 +816,11 @@ static node_p
ng_ID2noderef(ng_ID_t ID)
{
node_p node;
mtx_lock(&ng_idhash_mtx);
IDHASH_RLOCK();
NG_IDHASH_FIND(ID, node);
if(node)
NG_NODE_REF(node);
mtx_unlock(&ng_idhash_mtx);
IDHASH_RUNLOCK();
return(node);
}
@ -854,10 +869,10 @@ ng_name_node(node_p node, const char *name)
/* Update name hash. */
NG_NAMEHASH(name, hash);
mtx_lock(&ng_namehash_mtx);
NAMEHASH_WLOCK();
LIST_REMOVE(node, nd_nodes);
LIST_INSERT_HEAD(&V_ng_name_hash[hash], node, nd_nodes);
mtx_unlock(&ng_namehash_mtx);
NAMEHASH_WUNLOCK();
return (0);
}
@ -892,16 +907,15 @@ ng_name2noderef(node_p here, const char *name)
/* Find node by name */
NG_NAMEHASH(name, hash);
mtx_lock(&ng_namehash_mtx);
LIST_FOREACH(node, &V_ng_name_hash[hash], nd_nodes) {
NAMEHASH_RLOCK();
LIST_FOREACH(node, &V_ng_name_hash[hash], nd_nodes)
if (NG_NODE_IS_VALID(node) &&
(strcmp(NG_NODE_NAME(node), name) == 0)) {
NG_NODE_REF(node);
break;
}
}
if (node)
NG_NODE_REF(node);
mtx_unlock(&ng_namehash_mtx);
NAMEHASH_RUNLOCK();
return (node);
}
@ -1190,10 +1204,10 @@ ng_newtype(struct ng_type *tp)
/* Link in new type */
mtx_lock(&ng_typelist_mtx);
TYPELIST_WLOCK();
LIST_INSERT_HEAD(&ng_typelist, tp, types);
tp->refs = 1; /* first ref is linked list */
mtx_unlock(&ng_typelist_mtx);
TYPELIST_WUNLOCK();
return (0);
}
@ -1211,9 +1225,9 @@ ng_rmtype(struct ng_type *tp)
}
/* Unlink type */
mtx_lock(&ng_typelist_mtx);
TYPELIST_WLOCK();
LIST_REMOVE(tp, types);
mtx_unlock(&ng_typelist_mtx);
TYPELIST_WUNLOCK();
return (0);
}
@ -1225,12 +1239,12 @@ ng_findtype(const char *typename)
{
struct ng_type *type;
mtx_lock(&ng_typelist_mtx);
TYPELIST_RLOCK();
LIST_FOREACH(type, &ng_typelist, types) {
if (strcmp(type->name, typename) == 0)
break;
}
mtx_unlock(&ng_typelist_mtx);
TYPELIST_RUNLOCK();
return (type);
}
@ -2568,7 +2582,7 @@ ng_generic_msg(node_p here, item_p item, hook_p lasthook)
node_p node;
int num = 0, i;
mtx_lock(&ng_namehash_mtx);
NAMEHASH_RLOCK();
/* Count number of nodes */
for (i = 0; i < NG_NAME_HASH_SIZE; i++) {
LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) {
@ -2578,12 +2592,12 @@ ng_generic_msg(node_p here, item_p item, hook_p lasthook)
}
}
}
mtx_unlock(&ng_namehash_mtx);
/* Get response struct */
NG_MKRESPONSE(resp, msg, sizeof(*nl) +
(num * sizeof(struct nodeinfo)), M_NOWAIT);
if (resp == NULL) {
NAMEHASH_RUNLOCK();
error = ENOMEM;
break;
}
@ -2591,7 +2605,6 @@ ng_generic_msg(node_p here, item_p item, hook_p lasthook)
/* Cycle through the linked list of nodes */
nl->numnames = 0;
mtx_lock(&ng_namehash_mtx);
for (i = 0; i < NG_NAME_HASH_SIZE; i++) {
LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) {
struct nodeinfo *const np =
@ -2601,20 +2614,17 @@ ng_generic_msg(node_p here, item_p item, hook_p lasthook)
continue;
if (!unnamed && (! NG_NODE_HAS_NAME(node)))
continue;
if (nl->numnames >= num) {
log(LOG_ERR, "%s: number of nodes changed\n",
__func__);
break;
}
if (NG_NODE_HAS_NAME(node))
strcpy(np->name, NG_NODE_NAME(node));
strcpy(np->type, node->nd_type->name);
np->id = ng_node2ID(node);
np->hooks = node->nd_numhooks;
KASSERT(nl->numnames < num, ("%s: no space",
__func__));
nl->numnames++;
}
}
mtx_unlock(&ng_namehash_mtx);
NAMEHASH_RUNLOCK();
break;
}
@ -2624,17 +2634,16 @@ ng_generic_msg(node_p here, item_p item, hook_p lasthook)
struct ng_type *type;
int num = 0;
mtx_lock(&ng_typelist_mtx);
TYPELIST_RLOCK();
/* Count number of types */
LIST_FOREACH(type, &ng_typelist, types) {
LIST_FOREACH(type, &ng_typelist, types)
num++;
}
mtx_unlock(&ng_typelist_mtx);
/* Get response struct */
NG_MKRESPONSE(resp, msg, sizeof(*tl) +
(num * sizeof(struct typeinfo)), M_NOWAIT);
if (resp == NULL) {
TYPELIST_RUNLOCK();
error = ENOMEM;
break;
}
@ -2642,20 +2651,15 @@ ng_generic_msg(node_p here, item_p item, hook_p lasthook)
/* Cycle through the linked list of types */
tl->numtypes = 0;
mtx_lock(&ng_typelist_mtx);
LIST_FOREACH(type, &ng_typelist, types) {
struct typeinfo *const tp = &tl->typeinfo[tl->numtypes];
if (tl->numtypes >= num) {
log(LOG_ERR, "%s: number of %s changed\n",
__func__, "types");
break;
}
strcpy(tp->type_name, type->name);
tp->numnodes = type->refs - 1; /* don't count list */
KASSERT(tl->numtypes < num, ("%s: no space", __func__));
tl->numtypes++;
}
mtx_unlock(&ng_typelist_mtx);
TYPELIST_RUNLOCK();
break;
}
@ -2989,10 +2993,10 @@ ng_mod_event(module_t mod, int event, void *data)
/* Call type specific code */
if (type->mod_event != NULL)
if ((error = (*type->mod_event)(mod, event, data))) {
mtx_lock(&ng_typelist_mtx);
TYPELIST_WLOCK();
type->refs--; /* undo it */
LIST_REMOVE(type, types);
mtx_unlock(&ng_typelist_mtx);
TYPELIST_WUNLOCK();
}
break;
@ -3007,9 +3011,9 @@ ng_mod_event(module_t mod, int event, void *data)
if (error != 0) /* type refuses.. */
break;
}
mtx_lock(&ng_typelist_mtx);
TYPELIST_WLOCK();
LIST_REMOVE(type, types);
mtx_unlock(&ng_typelist_mtx);
TYPELIST_WUNLOCK();
}
break;
@ -3032,7 +3036,7 @@ vnet_netgraph_uninit(const void *unused __unused)
do {
/* Find a node to kill */
mtx_lock(&ng_namehash_mtx);
NAMEHASH_RLOCK();
for (i = 0; i < NG_NAME_HASH_SIZE; i++) {
LIST_FOREACH(node, &V_ng_name_hash[i], nd_nodes) {
if (node != &ng_deadnode) {
@ -3043,7 +3047,7 @@ vnet_netgraph_uninit(const void *unused __unused)
if (node != NULL)
break;
}
mtx_unlock(&ng_namehash_mtx);
NAMEHASH_RUNLOCK();
/* Attempt to kill it only if it is a regular node */
if (node != NULL) {
@ -3081,12 +3085,9 @@ ngb_mod_event(module_t mod, int event, void *data)
case MOD_LOAD:
/* Initialize everything. */
NG_WORKLIST_LOCK_INIT();
mtx_init(&ng_typelist_mtx, "netgraph types mutex", NULL,
MTX_DEF);
mtx_init(&ng_idhash_mtx, "netgraph idhash mutex", NULL,
MTX_DEF);
mtx_init(&ng_namehash_mtx, "netgraph namehash mutex", NULL,
MTX_DEF);
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);
#ifdef NETGRAPH_DEBUG