diff options
author | wollman <wollman@FreeBSD.org> | 1998-05-15 20:11:40 +0000 |
---|---|---|
committer | wollman <wollman@FreeBSD.org> | 1998-05-15 20:11:40 +0000 |
commit | bbc4497adab2d7702eab9a609897b2e5f672289e (patch) | |
tree | 10594c024ae545493609ccaa7de3d90faf27616a /sys/kern | |
parent | be2e5ffcfc349cb4483b536bd57048eca466e0c9 (diff) | |
download | FreeBSD-src-bbc4497adab2d7702eab9a609897b2e5f672289e.zip FreeBSD-src-bbc4497adab2d7702eab9a609897b2e5f672289e.tar.gz |
Convert socket structures to be type-stable and add a version number.
Define a parameter which indicates the maximum number of sockets in a
system, and use this to size the zone allocators used for sockets and
for certain PCBs.
Convert PF_LOCAL PCB structures to be type-stable and add a version number.
Define an external format for infomation about socket structures and use
it in several places.
Define a mechanism to get all PF_LOCAL and PF_INET PCB lists through
sysctl(3) without blocking network interrupts for an unreasonable
length of time. This probably still has some bugs and/or race
conditions, but it seems to work well enough on my machines.
It is now possible for `netstat' to get almost all of its information
via the sysctl(3) interface rather than reading kmem (changes to follow).
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/subr_param.c | 9 | ||||
-rw-r--r-- | sys/kern/uipc_domain.c | 33 | ||||
-rw-r--r-- | sys/kern/uipc_proto.c | 5 | ||||
-rw-r--r-- | sys/kern/uipc_sockbuf.c | 59 | ||||
-rw-r--r-- | sys/kern/uipc_socket.c | 54 | ||||
-rw-r--r-- | sys/kern/uipc_socket2.c | 59 | ||||
-rw-r--r-- | sys/kern/uipc_usrreq.c | 161 |
7 files changed, 324 insertions, 56 deletions
diff --git a/sys/kern/subr_param.c b/sys/kern/subr_param.c index b38edcc..b78a292 100644 --- a/sys/kern/subr_param.c +++ b/sys/kern/subr_param.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)param.c 8.3 (Berkeley) 8/20/94 - * $Id: param.c,v 1.25 1997/06/14 11:38:46 bde Exp $ + * $Id: param.c,v 1.26 1998/02/27 19:58:29 guido Exp $ */ #include "opt_sysvipc.h" @@ -85,6 +85,13 @@ int ncallout = 16 + NPROC + MAXFILES; /* maximum # of timer events */ #endif int nmbclusters = NMBCLUSTERS; +#if MAXFILES > NMBCLUSTERS +#define MAXSOCKETS MAXFILES +#else +#define MAXSOCKETS NMBCLUSTERS +#endif +int maxsockets = MAXSOCKETS; + /* allocate 1/4th amount of virtual address space for mbufs XXX */ int nmbufs = NMBCLUSTERS * 4; diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c index 69d6bf8..22078b1 100644 --- a/sys/kern/uipc_domain.c +++ b/sys/kern/uipc_domain.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)uipc_domain.c 8.2 (Berkeley) 10/18/93 - * $Id: uipc_domain.c,v 1.17 1997/04/27 20:00:42 wollman Exp $ + * $Id: uipc_domain.c,v 1.18 1997/09/16 11:43:36 bde Exp $ */ #include <sys/param.h> @@ -40,7 +40,9 @@ #include <sys/domain.h> #include <sys/mbuf.h> #include <sys/kernel.h> +#include <sys/socketvar.h> #include <sys/systm.h> +#include <vm/vm_zone.h> /* * System initialization @@ -85,6 +87,21 @@ domaininit(dummy) register struct protosw *pr; /* + * Before we do any setup, make sure to initialize the + * zone allocator we get struct sockets from. The obvious + * maximum number of sockets is `maxfiles', but it is possible + * to have a socket without an open file (e.g., a connection waiting + * to be accept(2)ed). Rather than think up and define a + * better value, we just use nmbclusters, since that's what people + * are told to increase first when the network runs out of memory. + * Perhaps we should have two pools, one of unlimited size + * for use during socreate(), and one ZONE_INTERRUPT pool for + * use in sonewconn(). + */ + socket_zone = zinit("socket", sizeof(struct socket), maxsockets, + ZONE_INTERRUPT, 0); + + /* * NB - local domain is always present. */ ADDDOMAIN(local); @@ -94,26 +111,14 @@ domaininit(dummy) domains = *dpp; } -/* - not in our sources -#ifdef ISDN - ADDDOMAIN(isdn); -#endif -*/ - for (dp = domains; dp; dp = dp->dom_next) { if (dp->dom_init) (*dp->dom_init)(); for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++){ -#ifdef PRU_OLDSTYLE - /* See comments in uipc_socket2.c. */ - if (pr->pr_usrreqs == 0 && pr->pr_ousrreq) - pr->pr_usrreqs = &pru_oldstyle; -#else if (pr->pr_usrreqs == 0) panic("domaininit: %ssw[%d] has no usrreqs!", dp->dom_name, (int)(pr - dp->dom_protosw)); -#endif if (pr->pr_init) (*pr->pr_init)(); } @@ -151,7 +156,7 @@ kludge_splx(udata) { int *savesplp = udata; - splx( *savesplp); + splx(*savesplp); } diff --git a/sys/kern/uipc_proto.c b/sys/kern/uipc_proto.c index 6e2ef5d..ec2b9f0 100644 --- a/sys/kern/uipc_proto.c +++ b/sys/kern/uipc_proto.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)uipc_proto.c 8.1 (Berkeley) 6/10/93 - * $Id: uipc_proto.c,v 1.13 1997/08/02 14:31:42 bde Exp $ + * $Id: uipc_proto.c,v 1.14 1998/02/20 13:11:48 bde Exp $ */ #include <sys/param.h> @@ -41,6 +41,7 @@ #include <sys/socket.h> #include <sys/sysctl.h> #include <sys/un.h> +#include <sys/unpcb.h> #include <net/raw_cb.h> @@ -70,7 +71,7 @@ static struct protosw localsw[] = { }; struct domain localdomain = - { AF_LOCAL, "local", 0, unp_externalize, unp_dispose, + { AF_LOCAL, "local", unp_init, unp_externalize, unp_dispose, localsw, &localsw[sizeof(localsw)/sizeof(localsw[0])] }; SYSCTL_NODE(_net, PF_LOCAL, local, CTLFLAG_RW, 0, "Local domain"); diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 40c8f19..8ad3522 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -31,11 +31,12 @@ * SUCH DAMAGE. * * @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 - * $Id: uipc_socket2.c,v 1.32 1998/04/04 13:25:40 phk Exp $ + * $Id: uipc_socket2.c,v 1.33 1998/04/24 04:15:18 dg Exp $ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/domain.h> #include <sys/kernel.h> #include <sys/proc.h> #include <sys/malloc.h> @@ -202,10 +203,9 @@ sonewconn(head, connstatus) if (head->so_qlen > 3 * head->so_qlimit / 2) return ((struct socket *)0); - MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT); + so = soalloc(0); if (so == NULL) return ((struct socket *)0); - bzero((caddr_t)so, sizeof(*so)); so->so_head = head; so->so_type = head->so_type; so->so_options = head->so_options &~ SO_ACCEPTCONN; @@ -218,7 +218,7 @@ sonewconn(head, connstatus) (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) { - (void) free((caddr_t)so, M_SOCKET); + sodealloc(so); return ((struct socket *)0); } @@ -890,6 +890,56 @@ dup_sockaddr(sa, canwait) } /* + * Create an external-format (``xsocket'') structure using the information + * in the kernel-format socket structure pointed to by so. This is done + * to reduce the spew of irrelevant information over this interface, + * to isolate user code from changes in the kernel structure, and + * potentially to provide information-hiding if we decide that + * some of this information should be hidden from users. + */ +void +sotoxsocket(struct socket *so, struct xsocket *xso) +{ + xso->xso_len = sizeof *xso; + xso->xso_so = so; + xso->so_type = so->so_type; + xso->so_options = so->so_options; + xso->so_linger = so->so_linger; + xso->so_state = so->so_state; + xso->so_pcb = so->so_pcb; + xso->xso_protocol = so->so_proto->pr_protocol; + xso->xso_family = so->so_proto->pr_domain->dom_family; + xso->so_qlen = so->so_qlen; + xso->so_incqlen = so->so_incqlen; + xso->so_qlimit = so->so_qlimit; + xso->so_timeo = so->so_timeo; + xso->so_error = so->so_error; + xso->so_pgid = so->so_pgid; + xso->so_oobmark = so->so_oobmark; + sbtoxsockbuf(&so->so_snd, &xso->so_snd); + sbtoxsockbuf(&so->so_rcv, &xso->so_rcv); + xso->so_uid = so->so_uid; +} + +/* + * This does the same for sockbufs. Note that the xsockbuf structure, + * since it is always embedded in a socket, does not include a self + * pointer nor a length. We make this entry point public in case + * some other mechanism needs it. + */ +void +sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb) +{ + xsb->sb_cc = sb->sb_cc; + xsb->sb_hiwat = sb->sb_hiwat; + xsb->sb_mbcnt = sb->sb_mbcnt; + xsb->sb_mbmax = sb->sb_mbmax; + xsb->sb_lowat = sb->sb_lowat; + xsb->sb_flags = sb->sb_flags; + xsb->sb_timeo = sb->sb_timeo; +} + +/* * Here is the definition of some of the basic objects in the kern.ipc * branch of the MIB. */ @@ -900,6 +950,7 @@ static int dummy; SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0, ""); SYSCTL_INT(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, &sb_max, 0, ""); +SYSCTL_INT(_kern_ipc, OID_AUTO, maxsockets, CTLFLAG_RD, &maxsockets, 0, ""); SYSCTL_INT(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW, &sb_efficiency, 0, ""); SYSCTL_INT(_kern_ipc, KIPC_NMBCLUSTERS, nmbclusters, CTLFLAG_RD, &nmbclusters, 0, ""); diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 58e309a..2ca79fc 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 - * $Id: uipc_socket.c,v 1.38 1998/03/01 19:39:17 guido Exp $ + * $Id: uipc_socket.c,v 1.39 1998/03/28 10:33:08 bde Exp $ */ #include <sys/param.h> @@ -50,10 +50,13 @@ #include <sys/signalvar.h> #include <sys/sysctl.h> #include <sys/uio.h> +#include <vm/vm_zone.h> #include <machine/limits.h> -MALLOC_DEFINE(M_SOCKET, "socket", "socket structure"); +struct vm_zone *socket_zone; +so_gen_t so_gencnt; /* generation count for sockets */ + MALLOC_DEFINE(M_SONAME, "soname", "socket name"); MALLOC_DEFINE(M_PCB, "pcb", "protocol control block"); @@ -68,7 +71,30 @@ SYSCTL_INT(_kern_ipc, KIPC_SOMAXCONN, somaxconn, CTLFLAG_RW, &somaxconn, * implement the semantics of socket operations by * switching out to the protocol specific routines. */ -/*ARGSUSED*/ + +/* + * Get a socket structure from our zone, and initialize it. + * We don't implement `waitok' yet (see comments in uipc_domain.c). + * Note that it would probably be better to allocate socket + * and PCB at the same time, but I'm not convinced that all + * the protocols can be easily modified to do this. + */ +struct socket * +soalloc(waitok) + int waitok; +{ + struct socket *so; + + so = zalloci(socket_zone); + if (so) { + /* XXX race condition for reentrant kernel */ + bzero(so, sizeof *so); + so->so_gencnt = ++so_gencnt; + so->so_zone = socket_zone; + } + return so; +} + int socreate(dom, aso, type, proto, p) int dom; @@ -89,12 +115,15 @@ socreate(dom, aso, type, proto, p) return (EPROTONOSUPPORT); if (prp->pr_type != type) return (EPROTOTYPE); - MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); - bzero((caddr_t)so, sizeof(*so)); + so = soalloc(p != 0); + if (so == 0) + return (ENOBUFS); + TAILQ_INIT(&so->so_incomp); TAILQ_INIT(&so->so_comp); so->so_type = type; - so->so_uid = p->p_ucred->cr_uid;; + if (p != 0) + so->so_uid = p->p_ucred->cr_uid; so->so_proto = prp; error = (*prp->pr_usrreqs->pru_attach)(so, proto, p); if (error) { @@ -120,14 +149,23 @@ sobind(so, nam, p) return (error); } +void +sodealloc(so) + struct socket *so; +{ + so->so_gencnt = ++so_gencnt; + zfreei(so->so_zone, so); +} + int solisten(so, backlog, p) register struct socket *so; int backlog; struct proc *p; { - int s = splnet(), error; + int s, error; + s = splnet(); error = (*so->so_proto->pr_usrreqs->pru_listen)(so, p); if (error) { splx(s); @@ -165,7 +203,7 @@ sofree(so) } sbrelease(&so->so_snd); sorflush(so); - FREE(so, M_SOCKET); + sodealloc(so); } /* diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c index 40c8f19..8ad3522 100644 --- a/sys/kern/uipc_socket2.c +++ b/sys/kern/uipc_socket2.c @@ -31,11 +31,12 @@ * SUCH DAMAGE. * * @(#)uipc_socket2.c 8.1 (Berkeley) 6/10/93 - * $Id: uipc_socket2.c,v 1.32 1998/04/04 13:25:40 phk Exp $ + * $Id: uipc_socket2.c,v 1.33 1998/04/24 04:15:18 dg Exp $ */ #include <sys/param.h> #include <sys/systm.h> +#include <sys/domain.h> #include <sys/kernel.h> #include <sys/proc.h> #include <sys/malloc.h> @@ -202,10 +203,9 @@ sonewconn(head, connstatus) if (head->so_qlen > 3 * head->so_qlimit / 2) return ((struct socket *)0); - MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_DONTWAIT); + so = soalloc(0); if (so == NULL) return ((struct socket *)0); - bzero((caddr_t)so, sizeof(*so)); so->so_head = head; so->so_type = head->so_type; so->so_options = head->so_options &~ SO_ACCEPTCONN; @@ -218,7 +218,7 @@ sonewconn(head, connstatus) (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) { - (void) free((caddr_t)so, M_SOCKET); + sodealloc(so); return ((struct socket *)0); } @@ -890,6 +890,56 @@ dup_sockaddr(sa, canwait) } /* + * Create an external-format (``xsocket'') structure using the information + * in the kernel-format socket structure pointed to by so. This is done + * to reduce the spew of irrelevant information over this interface, + * to isolate user code from changes in the kernel structure, and + * potentially to provide information-hiding if we decide that + * some of this information should be hidden from users. + */ +void +sotoxsocket(struct socket *so, struct xsocket *xso) +{ + xso->xso_len = sizeof *xso; + xso->xso_so = so; + xso->so_type = so->so_type; + xso->so_options = so->so_options; + xso->so_linger = so->so_linger; + xso->so_state = so->so_state; + xso->so_pcb = so->so_pcb; + xso->xso_protocol = so->so_proto->pr_protocol; + xso->xso_family = so->so_proto->pr_domain->dom_family; + xso->so_qlen = so->so_qlen; + xso->so_incqlen = so->so_incqlen; + xso->so_qlimit = so->so_qlimit; + xso->so_timeo = so->so_timeo; + xso->so_error = so->so_error; + xso->so_pgid = so->so_pgid; + xso->so_oobmark = so->so_oobmark; + sbtoxsockbuf(&so->so_snd, &xso->so_snd); + sbtoxsockbuf(&so->so_rcv, &xso->so_rcv); + xso->so_uid = so->so_uid; +} + +/* + * This does the same for sockbufs. Note that the xsockbuf structure, + * since it is always embedded in a socket, does not include a self + * pointer nor a length. We make this entry point public in case + * some other mechanism needs it. + */ +void +sbtoxsockbuf(struct sockbuf *sb, struct xsockbuf *xsb) +{ + xsb->sb_cc = sb->sb_cc; + xsb->sb_hiwat = sb->sb_hiwat; + xsb->sb_mbcnt = sb->sb_mbcnt; + xsb->sb_mbmax = sb->sb_mbmax; + xsb->sb_lowat = sb->sb_lowat; + xsb->sb_flags = sb->sb_flags; + xsb->sb_timeo = sb->sb_timeo; +} + +/* * Here is the definition of some of the basic objects in the kern.ipc * branch of the MIB. */ @@ -900,6 +950,7 @@ static int dummy; SYSCTL_INT(_kern, KERN_DUMMY, dummy, CTLFLAG_RW, &dummy, 0, ""); SYSCTL_INT(_kern_ipc, KIPC_MAXSOCKBUF, maxsockbuf, CTLFLAG_RW, &sb_max, 0, ""); +SYSCTL_INT(_kern_ipc, OID_AUTO, maxsockets, CTLFLAG_RD, &maxsockets, 0, ""); SYSCTL_INT(_kern_ipc, KIPC_SOCKBUF_WASTE, sockbuf_waste_factor, CTLFLAG_RW, &sb_efficiency, 0, ""); SYSCTL_INT(_kern_ipc, KIPC_NMBCLUSTERS, nmbclusters, CTLFLAG_RD, &nmbclusters, 0, ""); diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index b225c7c..3921513 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 - * $Id: uipc_usrreq.c,v 1.33 1998/04/17 22:36:50 des Exp $ + * $Id: uipc_usrreq.c,v 1.34 1998/05/07 04:58:21 msmith Exp $ */ #include <sys/param.h> @@ -42,6 +42,7 @@ #include <sys/malloc.h> /* XXX must be before <sys/file.h> */ #include <sys/file.h> #include <sys/filedesc.h> +#include <sys/lock.h> #include <sys/mbuf.h> #include <sys/namei.h> #include <sys/proc.h> @@ -51,8 +52,17 @@ #include <sys/stat.h> #include <sys/sysctl.h> #include <sys/un.h> +#include <sys/unpcb.h> #include <sys/vnode.h> +#include <vm/vm_zone.h> + +struct vm_zone *unp_zone; +static unp_gen_t unp_gencnt; +static u_int unp_count; + +static struct unp_head unp_shead, unp_dhead; + /* * Unix communications domain. * @@ -60,6 +70,7 @@ * SEQPACKET, RDM * rethink name space problems * need a proper out-of-band + * lock pushdown */ static struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; static ino_t unp_ino; /* prototype for fake inode numbers */ @@ -468,12 +479,17 @@ unp_attach(so) if (error) return (error); } - MALLOC(unp, struct unpcb *, sizeof *unp, M_PCB, M_NOWAIT); + unp = zalloc(unp_zone); if (unp == NULL) return (ENOBUFS); bzero(unp, sizeof *unp); - so->so_pcb = (caddr_t)unp; + unp->unp_gencnt = ++unp_gencnt; + unp_count++; + LIST_INIT(&unp->unp_refs); unp->unp_socket = so; + LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead + : &unp_shead, unp, unp_link); + so->so_pcb = (caddr_t)unp; return (0); } @@ -481,6 +497,9 @@ static void unp_detach(unp) register struct unpcb *unp; { + LIST_REMOVE(unp, unp_link); + unp->unp_gencnt = ++unp_gencnt; + --unp_count; if (unp->unp_vnode) { unp->unp_vnode->v_socket = 0; vrele(unp->unp_vnode); @@ -488,8 +507,8 @@ unp_detach(unp) } if (unp->unp_conn) unp_disconnect(unp); - while (unp->unp_refs) - unp_drop(unp->unp_refs, ECONNRESET); + while (unp->unp_refs.lh_first) + unp_drop(unp->unp_refs.lh_first, ECONNRESET); soisdisconnected(unp->unp_socket); unp->unp_socket->so_pcb = 0; if (unp_rights) { @@ -505,7 +524,7 @@ unp_detach(unp) } if (unp->unp_addr) FREE(unp->unp_addr, M_SONAME); - FREE(unp, M_PCB); + zfree(unp_zone, unp); } static int @@ -637,8 +656,7 @@ unp_connect2(so, so2) switch (so->so_type) { case SOCK_DGRAM: - unp->unp_nextref = unp2->unp_refs; - unp2->unp_refs = unp; + LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink); soisconnected(so); break; @@ -666,20 +684,7 @@ unp_disconnect(unp) switch (unp->unp_socket->so_type) { case SOCK_DGRAM: - if (unp2->unp_refs == unp) - unp2->unp_refs = unp->unp_nextref; - else { - unp2 = unp2->unp_refs; - for (;;) { - if (unp2 == 0) - panic("unp_disconnect"); - if (unp2->unp_nextref == unp) - break; - unp2 = unp2->unp_nextref; - } - unp2->unp_nextref = unp->unp_nextref; - } - unp->unp_nextref = 0; + LIST_REMOVE(unp, unp_reflink); unp->unp_socket->so_state &= ~SS_ISCONNECTED; break; @@ -701,6 +706,103 @@ unp_abort(unp) } #endif +static int +unp_pcblist SYSCTL_HANDLER_ARGS +{ + int error, i, n, s; + struct unpcb *unp, **unp_list; + unp_gen_t gencnt; + struct xunpgen xug; + struct unp_head *head; + + head = ((long)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead); + + /* + * The process of preparing the PCB list is too time-consuming and + * resource-intensive to repeat twice on every request. + */ + if (req->oldptr == 0) { + n = unp_count; + req->oldidx = 2 * (sizeof xug) + + (n + n/8) * sizeof(struct xunpcb); + return 0; + } + + if (req->newptr != 0) + return EPERM; + + /* + * OK, now we're committed to doing something. + */ + gencnt = unp_gencnt; + n = unp_count; + + xug.xug_len = sizeof xug; + xug.xug_count = n; + xug.xug_gen = gencnt; + xug.xug_sogen = so_gencnt; + error = SYSCTL_OUT(req, &xug, sizeof xug); + if (error) + return error; + + unp_list = malloc(n * sizeof *unp_list, M_TEMP, M_WAITOK); + if (unp_list == 0) + return ENOMEM; + + for (unp = head->lh_first, i = 0; unp && i < n; + unp = unp->unp_link.le_next) { + if (unp->unp_gencnt <= gencnt) + unp_list[i++] = unp; + } + n = i; /* in case we lost some during malloc */ + + error = 0; + for (i = 0; i < n; i++) { + unp = unp_list[i]; + if (unp->unp_gencnt <= gencnt) { + struct xunpcb xu; + xu.xu_len = sizeof xu; + xu.xu_unpp = unp; + /* + * XXX - need more locking here to protect against + * connect/disconnect races for SMP. + */ + if (unp->unp_addr) + bcopy(unp->unp_addr, &xu.xu_addr, + unp->unp_addr->sun_len); + if (unp->unp_conn && unp->unp_conn->unp_addr) + bcopy(unp->unp_conn->unp_addr, + &xu.xu_caddr, + unp->unp_conn->unp_addr->sun_len); + bcopy(unp, &xu.xu_unp, sizeof *unp); + sotoxsocket(unp->unp_socket, &xu.xu_socket); + error = SYSCTL_OUT(req, &xu, sizeof xu); + } + } + if (!error) { + /* + * Give the user an updated idea of our state. + * If the generation differs from what we told + * her before, she knows that something happened + * while we were processing this request, and it + * might be necessary to retry. + */ + xug.xug_gen = unp_gencnt; + xug.xug_sogen = so_gencnt; + xug.xug_count = unp_count; + error = SYSCTL_OUT(req, &xug, sizeof xug); + } + free(unp_list, M_TEMP); + return error; +} + +SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD, + (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb", + "List of active local datagram sockets"); +SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD, + (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb", + "List of active local stream sockets"); + static void unp_shutdown(unp) struct unpcb *unp; @@ -722,10 +824,13 @@ unp_drop(unp, errno) so->so_error = errno; unp_disconnect(unp); if (so->so_head) { + LIST_REMOVE(unp, unp_link); + unp->unp_gencnt = ++unp_gencnt; + unp_count--; so->so_pcb = (caddr_t) 0; if (unp->unp_addr) FREE(unp->unp_addr, M_SONAME); - FREE(unp, M_PCB); + zfree(unp_zone, unp); sofree(so); } } @@ -779,6 +884,16 @@ unp_externalize(rights) return (0); } +void +unp_init(void) +{ + unp_zone = zinit("unpcb", sizeof(struct unpcb), nmbclusters, 0, 0); + if (unp_zone == 0) + panic("unp_init"); + LIST_INIT(&unp_dhead); + LIST_INIT(&unp_shead); +} + #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif |