summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorwollman <wollman@FreeBSD.org>1998-05-15 20:11:40 +0000
committerwollman <wollman@FreeBSD.org>1998-05-15 20:11:40 +0000
commitbbc4497adab2d7702eab9a609897b2e5f672289e (patch)
tree10594c024ae545493609ccaa7de3d90faf27616a /sys/kern
parentbe2e5ffcfc349cb4483b536bd57048eca466e0c9 (diff)
downloadFreeBSD-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.c9
-rw-r--r--sys/kern/uipc_domain.c33
-rw-r--r--sys/kern/uipc_proto.c5
-rw-r--r--sys/kern/uipc_sockbuf.c59
-rw-r--r--sys/kern/uipc_socket.c54
-rw-r--r--sys/kern/uipc_socket2.c59
-rw-r--r--sys/kern/uipc_usrreq.c161
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
OpenPOWER on IntegriCloud