From owner-svn-src-stable@FreeBSD.ORG Mon Feb 13 15:21:12 2012 Return-Path: Delivered-To: svn-src-stable@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D6FF91065670; Mon, 13 Feb 2012 15:21:12 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id C3E348FC0C; Mon, 13 Feb 2012 15:21:12 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q1DFLCMH048241; Mon, 13 Feb 2012 15:21:12 GMT (envelope-from glebius@svn.freebsd.org) Received: (from glebius@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q1DFLC5q048235; Mon, 13 Feb 2012 15:21:12 GMT (envelope-from glebius@svn.freebsd.org) Message-Id: <201202131521.q1DFLC5q048235@svn.freebsd.org> From: Gleb Smirnoff Date: Mon, 13 Feb 2012 15:21:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r231587 - in stable/9/sys: kern netgraph X-BeenThere: svn-src-stable@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for all the -stable branches of the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 13 Feb 2012 15:21:13 -0000 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 #include #include +#include #include #include #include @@ -57,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -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 #include +#include #include #include #include @@ -64,9 +65,6 @@ #include #include #include -#ifdef NOTYET -#include -#endif #include @@ -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 */