Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Feb 2012 15:21:12 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r231587 - in stable/9/sys: kern netgraph
Message-ID:  <201202131521.q1DFLC5q048235@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: glebius
Date: Mon Feb 13 15:21:12 2012
New Revision: 231587
URL: http://svn.freebsd.org/changeset/base/231587

Log:
  Merge from head 226829, 230213, 230480, 230486, 230487, 231585:
  
  r226829 in ng_base:
    - If KDB & NETGRAPH_DEBUG are on, print traces on discovered failed
      invariants.
    - Reduce tautology in NETGRAPH_DEBUG output.
  
  r230213 in ng_socket:
    Remove some disabled NOTYET code. Probability of enabling it is low,
    if anyone wants, he/she can take it from svn.
  
  r230480 in ng_base:
    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.
  
  r230486 in subr_hash.c:
    Convert panic()s to KASSERT()s. This is an optimisation for
    hashdestroy() since in absence of INVARIANTS a compiler
    will drop the entire for() cycle.
  
  230487, 231585 in ng_socket:
    Provide a findhook method for ng_socket(4). The node stores a
    hash with names of its hooks. It starts with size of 16, and
    grows when number of hooks reaches twice the current size. A
    failure to grow (memory is allocated with M_NOWAIT) isn't
    fatal, however.
  
    I used standard hash(9) function for the hash. With 25000
    hooks named in the mpd (ports/net/mpd5) manner of "b%u", the
    distributions is the following: 72.1% entries consist of one
    element, 22.1% consist of two, 5.2% consist of three and
    0.6% of four.
  
    Speedup in a synthetic test that creates 25000 hooks and then
    runs through a long cyclce dereferencing them in a random order
    is over 25 times.
  
  The last merge was done in an ABI preserving manner, the struct
  ngsock is still exposed to userland (unlike in head), but its new
  fields are at its end and under #ifdef _KERNEL.

Modified:
  stable/9/sys/kern/subr_hash.c
  stable/9/sys/netgraph/netgraph.h
  stable/9/sys/netgraph/ng_base.c
  stable/9/sys/netgraph/ng_socket.c
  stable/9/sys/netgraph/ng_socketvar.h
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/kern/subr_hash.c
==============================================================================
--- stable/9/sys/kern/subr_hash.c	Mon Feb 13 14:40:15 2012	(r231586)
+++ stable/9/sys/kern/subr_hash.c	Mon Feb 13 15:21:12 2012	(r231587)
@@ -52,9 +52,7 @@ hashinit_flags(int elements, struct mall
 	LIST_HEAD(generic, generic) *hashtbl;
 	int i;
 
-	if (elements <= 0)
-		panic("hashinit: bad elements");
-
+	KASSERT(elements > 0, ("%s: bad elements", __func__));
 	/* Exactly one of HASH_WAITOK and HASH_NOWAIT must be set. */
 	KASSERT((flags & HASH_WAITOK) ^ (flags & HASH_NOWAIT),
 	    ("Bad flags (0x%x) passed to hashinit_flags", flags));
@@ -95,8 +93,7 @@ hashdestroy(void *vhashtbl, struct mallo
 
 	hashtbl = vhashtbl;
 	for (hp = hashtbl; hp <= &hashtbl[hashmask]; hp++)
-		if (!LIST_EMPTY(hp))
-			panic("hashdestroy: hash not empty");
+		KASSERT(LIST_EMPTY(hp), ("%s: hash not empty", __func__));
 	free(hashtbl, type);
 }
 
@@ -115,8 +112,7 @@ phashinit(int elements, struct malloc_ty
 	LIST_HEAD(generic, generic) *hashtbl;
 	int i;
 
-	if (elements <= 0)
-		panic("phashinit: bad elements");
+	KASSERT(elements > 0, ("%s: bad elements", __func__));
 	for (i = 1, hashsize = primes[1]; hashsize <= elements;) {
 		i++;
 		if (i == NPRIMES)

Modified: stable/9/sys/netgraph/netgraph.h
==============================================================================
--- stable/9/sys/netgraph/netgraph.h	Mon Feb 13 14:40:15 2012	(r231586)
+++ stable/9/sys/netgraph/netgraph.h	Mon Feb 13 15:21:12 2012	(r231587)
@@ -57,6 +57,7 @@
 
 #ifdef HAVE_KERNEL_OPTION_HEADERS
 #include "opt_netgraph.h"
+#include "opt_kdb.h"
 #endif
 
 /* debugging options */
@@ -190,7 +191,7 @@ static __inline void
 _chkhook(hook_p hook, char *file, int line)
 {
 	if (hook->hk_magic != HK_MAGIC) {
-		printf("Accessing freed hook ");
+		printf("Accessing freed ");
 		dumphook(hook, file, line);
 	}
 	hook->lastline = line;
@@ -458,7 +459,7 @@ static __inline void
 _chknode(node_p node, char *file, int line)
 {
 	if (node->nd_magic != ND_MAGIC) {
-		printf("Accessing freed node ");
+		printf("Accessing freed ");
 		dumpnode(node, file, line);
 	}
 	node->lastline = line;

Modified: stable/9/sys/netgraph/ng_base.c
==============================================================================
--- stable/9/sys/netgraph/ng_base.c	Mon Feb 13 14:40:15 2012	(r231586)
+++ stable/9/sys/netgraph/ng_base.c	Mon Feb 13 15:21:12 2012	(r231587)
@@ -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;   /* 
 
 /* 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);
@@ -647,12 +662,12 @@ ng_make_node_common(struct ng_type *type
 	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 */
@@ -665,7 +680,7 @@ ng_make_node_common(struct ng_type *type
 	}
 	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;
@@ -777,14 +792,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);
@@ -798,11 +813,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);
 }
 
@@ -851,10 +866,10 @@ ng_name_node(node_p node, const char *na
 
 	/* 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);
 }
@@ -889,16 +904,15 @@ ng_name2noderef(node_p here, const char 
 
 	/* 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);
 }
 
@@ -1187,10 +1201,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);
 }
 
@@ -1208,9 +1222,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);
 }
 
@@ -1222,12 +1236,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);
 }
 
@@ -2565,7 +2579,7 @@ ng_generic_msg(node_p here, item_p item,
 		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) {
@@ -2575,12 +2589,12 @@ ng_generic_msg(node_p here, item_p item,
 				}
 			}
 		}
-		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;
 		}
@@ -2588,7 +2602,6 @@ ng_generic_msg(node_p here, item_p item,
 
 		/* 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 =
@@ -2598,20 +2611,17 @@ ng_generic_msg(node_p here, item_p item,
 					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;
 	    }
 
@@ -2621,17 +2631,16 @@ ng_generic_msg(node_p here, item_p item,
 		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;
 		}
@@ -2639,20 +2648,15 @@ ng_generic_msg(node_p here, item_p item,
 
 		/* 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;
 	    }
 
@@ -2986,10 +2990,10 @@ ng_mod_event(module_t mod, int event, vo
 		/* 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;
 
@@ -3004,9 +3008,9 @@ ng_mod_event(module_t mod, int event, vo
 				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;
 
@@ -3029,7 +3033,7 @@ vnet_netgraph_uninit(const void *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) {
@@ -3040,7 +3044,7 @@ vnet_netgraph_uninit(const void *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) {
@@ -3078,12 +3082,9 @@ ngb_mod_event(module_t mod, int event, v
 	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
@@ -3143,6 +3144,9 @@ dumphook (hook_p hook, char *file, int l
 		hook->lastfile, hook->lastline);
 	if (line) {
 		printf(" problem discovered at file %s, line %d\n", file, line);
+#ifdef KDB
+		kdb_backtrace();
+#endif
 	}
 }
 
@@ -3157,6 +3161,9 @@ dumpnode(node_p node, char *file, int li
 		node->lastfile, node->lastline);
 	if (line) {
 		printf(" problem discovered at file %s, line %d\n", file, line);
+#ifdef KDB
+		kdb_backtrace();
+#endif
 	}
 }
 

Modified: stable/9/sys/netgraph/ng_socket.c
==============================================================================
--- stable/9/sys/netgraph/ng_socket.c	Mon Feb 13 14:40:15 2012	(r231586)
+++ stable/9/sys/netgraph/ng_socket.c	Mon Feb 13 15:21:12 2012	(r231587)
@@ -51,6 +51,7 @@
 
 #include <sys/param.h>
 #include <sys/domain.h>
+#include <sys/hash.h>
 #include <sys/kernel.h>
 #include <sys/linker.h>
 #include <sys/lock.h>
@@ -64,9 +65,6 @@
 #include <sys/socketvar.h>
 #include <sys/syscallsubr.h>
 #include <sys/sysctl.h>
-#ifdef NOTYET
-#include <sys/vnode.h>
-#endif
 
 #include <net/vnet.h>
 
@@ -115,6 +113,7 @@ static ng_rcvmsg_t	ngs_rcvmsg;
 static ng_shutdown_t	ngs_shutdown;
 static ng_newhook_t	ngs_newhook;
 static ng_connect_t	ngs_connect;
+static ng_findhook_t	ngs_findhook;
 static ng_rcvdata_t	ngs_rcvdata;
 static ng_disconnect_t	ngs_disconnect;
 
@@ -124,9 +123,6 @@ static int	ng_attach_cntl(struct socket 
 static int	ng_attach_common(struct socket *so, int type);
 static void	ng_detach_common(struct ngpcb *pcbp, int type);
 static void	ng_socket_free_priv(struct ngsock *priv);
-#ifdef NOTYET
-static int	ng_internalize(struct mbuf *m, struct thread *p);
-#endif
 static int	ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp);
 static int	ng_bind(struct sockaddr *nam, struct ngpcb *pcbp);
 
@@ -143,6 +139,7 @@ static struct ng_type typestruct = {
 	.shutdown =	ngs_shutdown,
 	.newhook =	ngs_newhook,
 	.connect =	ngs_connect,
+	.findhook =	ngs_findhook,
 	.rcvdata =	ngs_rcvdata,
 	.disconnect =	ngs_disconnect,
 };
@@ -209,19 +206,10 @@ ngc_send(struct socket *so, int flags, s
 	int len, error = 0;
 	struct ng_apply_info apply;
 
-#ifdef	NOTYET
-	if (control && (error = ng_internalize(control, td))) {
-		if (pcbp->sockdata == NULL) {
-			error = ENOTCONN;
-			goto release;
-		}
-	}
-#else	/* NOTYET */
 	if (control) {
 		error = EINVAL;
 		goto release;
 	}
-#endif	/* NOTYET */
 
 	/* Require destination as there may be >= 1 hooks on this node. */
 	if (addr == NULL) {
@@ -539,8 +527,14 @@ ng_attach_cntl(struct socket *so)
 		return (error);
 	}
 
-	/* Allocate node private info */
+	/*
+	 * Allocate node private info and hash. We start
+	 * with 16 hash entries, however we may grow later
+	 * in ngs_newhook(). We can't predict how much hooks
+	 * does this node plan to have.
+	 */
 	priv = malloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO);
+	priv->hash = hashinit(16, M_NETGRAPH_SOCK, &priv->hmask);
 
 	/* Initialize mutex. */
 	mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF);
@@ -646,6 +640,7 @@ ng_socket_free_priv(struct ngsock *priv)
 
 	if (priv->refs == 0) {
 		mtx_destroy(&priv->mtx);
+		hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask);
 		free(priv, M_NETGRAPH_SOCK);
 		return;
 	}
@@ -661,69 +656,6 @@ ng_socket_free_priv(struct ngsock *priv)
 		mtx_unlock(&priv->mtx);
 }
 
-#ifdef NOTYET
-/*
- * File descriptors can be passed into an AF_NETGRAPH socket.
- * Note, that file descriptors cannot be passed OUT.
- * Only character device descriptors are accepted.
- * Character devices are useful to connect a graph to a device,
- * which after all is the purpose of this whole system.
- */
-static int
-ng_internalize(struct mbuf *control, struct thread *td)
-{
-	const struct cmsghdr *cm = mtod(control, const struct cmsghdr *);
-	struct file *fp;
-	struct vnode *vn;
-	int oldfds;
-	int fd;
-
-	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
-	    cm->cmsg_len != control->m_len) {
-		TRAP_ERROR;
-		return (EINVAL);
-	}
-
-	/* Check there is only one FD. XXX what would more than one signify? */
-	oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int);
-	if (oldfds != 1) {
-		TRAP_ERROR;
-		return (EINVAL);
-	}
-
-	/* Check that the FD given is legit. and change it to a pointer to a
-	 * struct file. */
-	fd = CMSG_DATA(cm);
-	if ((error = fget(td, fd, 0, &fp)) != 0)
-		return (error);
-
-	/* Depending on what kind of resource it is, act differently. For
-	 * devices, we treat it as a file. For an AF_NETGRAPH socket,
-	 * shortcut straight to the node. */
-	switch (fp->f_type) {
-	case DTYPE_VNODE:
-		vn = fp->f_data;
-		if (vn && (vn->v_type == VCHR)) {
-			/* for a VCHR, actually reference the FILE */
-			fhold(fp);
-			/* XXX then what :) */
-			/* how to pass on to other modules? */
-		} else {
-			fdrop(fp, td);
-			TRAP_ERROR;
-			return (EINVAL);
-		}
-		break;
-	default:
-		fdrop(fp, td);
-		TRAP_ERROR;
-		return (EINVAL);
-	}
-	fdrop(fp, td);
-	return (0);
-}
-#endif	/* NOTYET */
-
 /*
  * Connect the data socket to a named control socket node.
  */
@@ -817,6 +749,35 @@ ngs_constructor(node_p nodep)
 	return (EINVAL);
 }
 
+static void
+ngs_rehash(node_p node)
+{
+	struct ngsock *priv = NG_NODE_PRIVATE(node);
+	struct ngshash *new;
+	struct hookpriv *hp;
+	hook_p hook;
+	uint32_t h;
+	u_long hmask;
+
+	new = hashinit_flags((priv->hmask + 1) * 2, M_NETGRAPH_SOCK, &hmask,
+	    HASH_NOWAIT);
+	if (new == NULL)
+		return;
+
+	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
+		hp = NG_HOOK_PRIVATE(hook);
+#ifdef INVARIANTS
+		LIST_REMOVE(hp, next);
+#endif
+		h = hash32_str(NG_HOOK_NAME(hook), HASHINIT) & hmask;
+		LIST_INSERT_HEAD(&new[h], hp, next);
+	}
+
+	hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask);
+	priv->hash = new;
+	priv->hmask = hmask;
+}
+
 /*
  * We allow any hook to be connected to the node.
  * There is no per-hook private information though.
@@ -824,7 +785,20 @@ ngs_constructor(node_p nodep)
 static int
 ngs_newhook(node_p node, hook_p hook, const char *name)
 {
-	NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node));
+	struct ngsock *const priv = NG_NODE_PRIVATE(node);
+	struct hookpriv *hp;
+	uint32_t h;
+
+	hp = malloc(sizeof(*hp), M_NETGRAPH_SOCK, M_NOWAIT);
+	if (hp == NULL)
+		return (ENOMEM);
+	if (node->nd_numhooks * 2 > priv->hmask)
+		ngs_rehash(node);
+	hp->hook = hook;
+	h = hash32_str(name, HASHINIT) & priv->hmask;
+	LIST_INSERT_HEAD(&priv->hash[h], hp, next);
+	NG_HOOK_SET_PRIVATE(hook, hp);
+
 	return (0);
 }
 
@@ -846,6 +820,38 @@ ngs_connect(hook_p hook)
 	return (0);
 }
 
+/* Look up hook by name */
+static hook_p
+ngs_findhook(node_p node, const char *name)
+{
+	struct ngsock *priv = NG_NODE_PRIVATE(node);
+	struct hookpriv *hp;
+	uint32_t h;
+
+	/*
+	 * Microoptimisation for an ng_socket with
+	 * a single hook, which is a common case.
+	 */
+	if (node->nd_numhooks == 1) {
+		hook_p hook;
+
+		hook = LIST_FIRST(&node->nd_hooks);
+
+		if (strcmp(NG_HOOK_NAME(hook), name) == 0)
+			return (hook);
+		else
+			return (NULL);
+	}
+
+	h = hash32_str(name, HASHINIT) & priv->hmask;
+
+	LIST_FOREACH(hp, &priv->hash[h], next)
+		if (strcmp(NG_HOOK_NAME(hp->hook), name) == 0)
+			return (hp->hook);
+
+	return (NULL);
+}
+
 /*
  * Incoming messages get passed up to the control socket.
  * Unless they are for us specifically (socket_type)
@@ -1013,6 +1019,10 @@ ngs_disconnect(hook_p hook)
 {
 	node_p node = NG_HOOK_NODE(hook);
 	struct ngsock *const priv = NG_NODE_PRIVATE(node);
+	struct hookpriv *hp = NG_HOOK_PRIVATE(hook);
+
+	LIST_REMOVE(hp, next);
+	free(hp, M_NETGRAPH_SOCK);
 
 	if ((priv->datasock) && (priv->datasock->ng_socket)) {
 		if (NG_NODE_NUMHOOKS(node) == 1)

Modified: stable/9/sys/netgraph/ng_socketvar.h
==============================================================================
--- stable/9/sys/netgraph/ng_socketvar.h	Mon Feb 13 14:40:15 2012	(r231586)
+++ stable/9/sys/netgraph/ng_socketvar.h	Mon Feb 13 15:21:12 2012	(r231587)
@@ -52,6 +52,14 @@ struct ngpcb {
 	int		  type;		/* NG_CONTROL or NG_DATA */
 };
 
+#ifdef _KERNEL
+struct hookpriv {
+	LIST_ENTRY(hookpriv)	next;
+	hook_p			hook;
+};
+LIST_HEAD(ngshash, hookpriv);
+#endif
+
 /* Per-node private data */
 struct ngsock {
 	struct ng_node	*node;		/* the associated netgraph node */
@@ -62,6 +70,10 @@ struct ngsock {
 	struct mtx	mtx;		/* mtx to wait on */
 	int		error;		/* place to store error */
 	ng_ID_t		node_id;	/* a hint for netstat(1) to find the node */
+#ifdef _KERNEL
+	struct ngshash	*hash;		/* hash for hook names */
+	u_long		hmask;		/* hash mask */
+#endif
 };
 #define	NGS_FLAG_NOLINGER	1	/* close with last hook */
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202131521.q1DFLC5q048235>