summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>2001-11-17 03:07:11 +0000
committerdillon <dillon@FreeBSD.org>2001-11-17 03:07:11 +0000
commit86ed17d675cb503ddb3f71f8b6f7c3af530bb29a (patch)
treed5160b5791cda1a8cfbbcd3f5e1bd7ea97561c8f /sys
parentfe91520d395f7879be049a289cbac3389fed1749 (diff)
downloadFreeBSD-src-86ed17d675cb503ddb3f71f8b6f7c3af530bb29a.zip
FreeBSD-src-86ed17d675cb503ddb3f71f8b6f7c3af530bb29a.tar.gz
Give struct socket structures a ref counting interface similar to
vnodes. This will hopefully serve as a base from which we can expand the MP code. We currently do not attempt to obtain any mutex or SX locks, but the door is open to add them when we nail down exactly how that part of it is going to work.
Diffstat (limited to 'sys')
-rw-r--r--sys/compat/svr4/svr4_stream.c30
-rw-r--r--sys/kern/kern_descrip.c47
-rw-r--r--sys/kern/sys_socket.c14
-rw-r--r--sys/kern/uipc_sockbuf.c4
-rw-r--r--sys/kern/uipc_socket.c33
-rw-r--r--sys/kern/uipc_socket2.c4
-rw-r--r--sys/kern/uipc_syscalls.c205
-rw-r--r--sys/kern/uipc_usrreq.c2
-rw-r--r--sys/net/raw_cb.c2
-rw-r--r--sys/net/raw_usrreq.c4
-rw-r--r--sys/netatalk/ddp_pcb.c2
-rw-r--r--sys/netatalk/ddp_usrreq.c2
-rw-r--r--sys/netatm/atm_socket.c2
-rw-r--r--sys/netinet/in_pcb.c2
-rw-r--r--sys/netinet6/in6_pcb.c2
-rw-r--r--sys/netipx/ipx_pcb.c2
-rw-r--r--sys/netipx/ipx_usrreq.c2
-rw-r--r--sys/netnatm/natm.c4
-rw-r--r--sys/netns/idp_usrreq.c4
-rw-r--r--sys/netns/ns_pcb.c2
-rw-r--r--sys/nfsserver/nfs_syscalls.c7
-rw-r--r--sys/sys/file.h4
-rw-r--r--sys/sys/socketvar.h25
23 files changed, 223 insertions, 182 deletions
diff --git a/sys/compat/svr4/svr4_stream.c b/sys/compat/svr4/svr4_stream.c
index cb19305..bf1c15a 100644
--- a/sys/compat/svr4/svr4_stream.c
+++ b/sys/compat/svr4/svr4_stream.c
@@ -150,7 +150,6 @@ svr4_sendit(td, s, mp, flags)
register struct msghdr *mp;
int flags;
{
- struct file *fp;
struct uio auio;
register struct iovec *iov;
register int i;
@@ -163,8 +162,7 @@ svr4_sendit(td, s, mp, flags)
struct uio ktruio;
#endif
- error = holdsock(td->td_proc->p_fd, s, &fp);
- if (error)
+ if ((error = fgetsock(td, s, &so, NULL)) != 0)
return (error);
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
@@ -176,16 +174,14 @@ svr4_sendit(td, s, mp, flags)
iov = mp->msg_iov;
for (i = 0; i < mp->msg_iovlen; i++, iov++) {
if ((auio.uio_resid += iov->iov_len) < 0) {
- fdrop(fp, td);
- return (EINVAL);
+ error = EINVAL;
+ goto done1;
}
}
if (mp->msg_name) {
error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
- if (error) {
- fdrop(fp, td);
- return (error);
- }
+ if (error)
+ goto done1;
} else {
to = 0;
}
@@ -211,7 +207,6 @@ svr4_sendit(td, s, mp, flags)
}
#endif
len = auio.uio_resid;
- so = (struct socket *)fp->f_data;
error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control,
flags, td);
if (error) {
@@ -239,7 +234,8 @@ svr4_sendit(td, s, mp, flags)
bad:
if (to)
FREE(to, M_SONAME);
- fdrop(fp, td);
+done1:
+ fputsock(so);
return (error);
}
@@ -250,7 +246,6 @@ svr4_recvit(td, s, mp, namelenp)
register struct msghdr *mp;
caddr_t namelenp;
{
- struct file *fp;
struct uio auio;
register struct iovec *iov;
register int i;
@@ -264,8 +259,7 @@ svr4_recvit(td, s, mp, namelenp)
struct uio ktruio;
#endif
- error = holdsock(td->td_proc->p_fd, s, &fp);
- if (error)
+ if ((error = fgetsock(td, s, &so, NULL)) != 0)
return (error);
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
@@ -277,8 +271,8 @@ svr4_recvit(td, s, mp, namelenp)
iov = mp->msg_iov;
for (i = 0; i < mp->msg_iovlen; i++, iov++) {
if ((auio.uio_resid += iov->iov_len) < 0) {
- fdrop(fp, td);
- return (EINVAL);
+ error = EINVAL;
+ goto done1;
}
}
#ifdef KTRACE
@@ -291,7 +285,6 @@ svr4_recvit(td, s, mp, namelenp)
}
#endif
len = auio.uio_resid;
- so = (struct socket *)fp->f_data;
error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio,
(struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
&mp->msg_flags);
@@ -365,7 +358,8 @@ out:
FREE(fromsa, M_SONAME);
if (control)
m_freem(control);
- fdrop(fp, td);
+done1:
+ fputsock(so);
return (error);
}
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 1d8d038..d5febf7 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -60,6 +60,8 @@
#include <sys/unistd.h>
#include <sys/resourcevar.h>
#include <sys/event.h>
+#include <sys/sx.h>
+#include <sys/socketvar.h>
#include <machine/limits.h>
@@ -1425,6 +1427,51 @@ fgetvp_write(struct thread *td, int fd, struct vnode **vpp)
return(_fgetvp(td, fd, vpp, FWRITE));
}
+/*
+ * Like fget() but loads the underlying socket, or returns an error if
+ * the descriptor does not represent a socket.
+ *
+ * We bump the ref count on the returned socket. XXX Also obtain the SX lock in
+ * the future.
+ */
+int
+fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp)
+{
+ struct filedesc *fdp;
+ struct file *fp;
+ struct socket *so;
+
+ GIANT_REQUIRED;
+ fdp = td->td_proc->p_fd;
+ *spp = NULL;
+ if (fflagp)
+ *fflagp = 0;
+ if ((u_int)fd >= fdp->fd_nfiles)
+ return(EBADF);
+ if ((fp = fdp->fd_ofiles[fd]) == NULL)
+ return(EBADF);
+ if (fp->f_type != DTYPE_SOCKET)
+ return(ENOTSOCK);
+ if (fp->f_data == NULL)
+ return(EINVAL);
+ so = (struct socket *)fp->f_data;
+ if (fflagp)
+ *fflagp = fp->f_flag;
+ soref(so);
+ *spp = so;
+ return(0);
+}
+
+/*
+ * Drop the reference count on the the socket and XXX release the SX lock in
+ * the future. The last reference closes the socket.
+ */
+void
+fputsock(struct socket *so)
+{
+ sorele(so);
+}
+
int
fdrop(fp, td)
struct file *fp;
diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c
index 8822fcb..04a419a 100644
--- a/sys/kern/sys_socket.c
+++ b/sys/kern/sys_socket.c
@@ -182,6 +182,12 @@ soo_stat(fp, ub, td)
return ((*so->so_proto->pr_usrreqs->pru_sense)(so, ub));
}
+/*
+ * API socket close on file pointer. We call soclose() to close the
+ * socket (including initiating closing protocols). soclose() will
+ * sorele() the file reference but the actual socket will not go away
+ * until the socket's ref count hits 0.
+ */
/* ARGSUSED */
int
soo_close(fp, td)
@@ -189,10 +195,12 @@ soo_close(fp, td)
struct thread *td;
{
int error = 0;
+ struct socket *so;
fp->f_ops = &badfileops;
- if (fp->f_data)
- error = soclose((struct socket *)fp->f_data);
- fp->f_data = 0;
+ if ((so = (struct socket *)fp->f_data) != NULL) {
+ fp->f_data = NULL;
+ error = soclose(so);
+ }
return (error);
}
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
index c969e7d..122fcda 100644
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -210,6 +210,8 @@ sodropablereq(head)
* then we allocate a new structure, propoerly linked into the
* data structure of the original socket, and return this.
* Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED.
+ *
+ * note: the ref count on the socket is 0 on return
*/
struct socket *
sonewconn(head, connstatus)
@@ -246,7 +248,7 @@ sonewconn3(head, connstatus, td)
so->so_cred = crhold(head->so_cred);
if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) ||
(*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
- sodealloc(so);
+ sotryfree(so);
return ((struct socket *)0);
}
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 10c8585..caae630c 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -91,6 +91,10 @@ SYSCTL_DECL(_kern_ipc);
static int somaxconn = SOMAXCONN;
SYSCTL_INT(_kern_ipc, KIPC_SOMAXCONN, somaxconn, CTLFLAG_RW,
&somaxconn, 0, "Maximum pending socket connection queue size");
+static int numopensockets;
+SYSCTL_INT(_kern_ipc, OID_AUTO, numopensockets, CTLFLAG_RD,
+ &numopensockets, 0, "Number of open sockets");
+
/*
* Socket operation routines.
@@ -106,6 +110,8 @@ SYSCTL_INT(_kern_ipc, KIPC_SOMAXCONN, somaxconn, CTLFLAG_RW,
* 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.
+ *
+ * soalloc() returns a socket with a ref count of 0.
*/
struct socket *
soalloc(waitok)
@@ -119,11 +125,17 @@ soalloc(waitok)
bzero(so, sizeof *so);
so->so_gencnt = ++so_gencnt;
so->so_zone = socket_zone;
+ /* sx_init(&so->so_sxlock, "socket sxlock"); */
TAILQ_INIT(&so->so_aiojobq);
+ ++numopensockets;
}
return so;
}
+/*
+ * socreate returns a socket with a ref count of 1. The socket should be
+ * closed with soclose().
+ */
int
socreate(dom, aso, type, proto, td)
int dom;
@@ -162,10 +174,11 @@ socreate(dom, aso, type, proto, td)
so->so_type = type;
so->so_cred = crhold(td->td_proc->p_ucred);
so->so_proto = prp;
+ soref(so);
error = (*prp->pr_usrreqs->pru_attach)(so, proto, td);
if (error) {
so->so_state |= SS_NOFDREF;
- sofree(so);
+ sorele(so);
return (error);
}
*aso = so;
@@ -186,11 +199,11 @@ sobind(so, nam, td)
return (error);
}
-void
-sodealloc(so)
- struct socket *so;
+static void
+sodealloc(struct socket *so)
{
+ KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count));
so->so_gencnt = ++so_gencnt;
if (so->so_rcv.sb_hiwat)
(void)chgsbsize(so->so_cred->cr_uidinfo,
@@ -210,7 +223,9 @@ sodealloc(so)
}
#endif
crfree(so->so_cred);
+ /* sx_destroy(&so->so_sxlock); */
zfree(so->so_zone, so);
+ --numopensockets;
}
int
@@ -242,6 +257,8 @@ sofree(so)
{
struct socket *head = so->so_head;
+ KASSERT(so->so_count == 0, ("socket %p so_count not 0", so));
+
if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
return;
if (head != NULL) {
@@ -272,6 +289,10 @@ sofree(so)
* Close a socket on last file table reference removal.
* Initiate disconnect if connected.
* Free socket when disconnect complete.
+ *
+ * This function will sorele() the socket. Note that soclose() may be
+ * called prior to the ref count reaching zero. The actual socket
+ * structure will not be freed until the ref count reaches zero.
*/
int
soclose(so)
@@ -329,7 +350,7 @@ discard:
if (so->so_state & SS_NOFDREF)
panic("soclose: NOFDREF");
so->so_state |= SS_NOFDREF;
- sofree(so);
+ sorele(so);
splx(s);
return (error);
}
@@ -345,7 +366,7 @@ soabort(so)
error = (*so->so_proto->pr_usrreqs->pru_abort)(so);
if (error) {
- sofree(so);
+ sotryfree(so); /* note: does not decrement the ref count */
return error;
}
return (0);
diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c
index c969e7d..122fcda 100644
--- a/sys/kern/uipc_socket2.c
+++ b/sys/kern/uipc_socket2.c
@@ -210,6 +210,8 @@ sodropablereq(head)
* then we allocate a new structure, propoerly linked into the
* data structure of the original socket, and return this.
* Connstatus may be 0, or SO_ISCONFIRMING, or SO_ISCONNECTED.
+ *
+ * note: the ref count on the socket is 0 on return
*/
struct socket *
sonewconn(head, connstatus)
@@ -246,7 +248,7 @@ sonewconn3(head, connstatus, td)
so->so_cred = crhold(head->so_cred);
if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat) ||
(*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) {
- sodealloc(so);
+ sotryfree(so);
return ((struct socket *)0);
}
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index a0ca7cc..ee68cfe 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -139,7 +139,7 @@ socket(td, uap)
fdrop(fp, td);
}
} else {
- fp->f_data = (caddr_t)so;
+ fp->f_data = (caddr_t)so; /* already has ref count */
fp->f_flag = FREAD|FWRITE;
fp->f_ops = &socketops;
fp->f_type = DTYPE_SOCKET;
@@ -164,22 +164,19 @@ bind(td, uap)
int namelen;
} */ *uap;
{
- struct file *fp;
struct sockaddr *sa;
+ struct socket *sp;
int error;
mtx_lock(&Giant);
- error = holdsock(td->td_proc->p_fd, uap->s, &fp);
- if (error)
- goto done2;
- error = getsockaddr(&sa, uap->name, uap->namelen);
- if (error) {
- fdrop(fp, td);
+ if ((error = fgetsock(td, uap->s, &sp, NULL)) != 0)
goto done2;
- }
- error = sobind((struct socket *)fp->f_data, sa, td);
+ if ((error = getsockaddr(&sa, uap->name, uap->namelen)) != 0)
+ goto done1;
+ error = sobind(sp, sa, td);
FREE(sa, M_SONAME);
- fdrop(fp, td);
+done1:
+ fputsock(sp);
done2:
mtx_unlock(&Giant);
return (error);
@@ -197,14 +194,13 @@ listen(td, uap)
int backlog;
} */ *uap;
{
- struct file *fp;
+ struct socket *sp;
int error;
mtx_lock(&Giant);
- error = holdsock(td->td_proc->p_fd, uap->s, &fp);
- if (error == 0) {
- error = solisten((struct socket *)fp->f_data, uap->backlog, td);
- fdrop(fp, td);
+ if ((error = fgetsock(td, uap->s, &sp, NULL)) == 0) {
+ error = solisten(sp, uap->backlog, td);
+ fputsock(sp);
}
mtx_unlock(&Giant);
return(error);
@@ -225,13 +221,12 @@ accept1(td, uap, compat)
int compat;
{
struct filedesc *fdp;
- struct file *lfp = NULL;
struct file *nfp = NULL;
struct sockaddr *sa;
int namelen, error, s;
struct socket *head, *so;
int fd;
- short fflag; /* type must match fp->f_flag */
+ u_int fflag;
mtx_lock(&Giant);
fdp = td->td_proc->p_fd;
@@ -241,11 +236,10 @@ accept1(td, uap, compat)
if(error)
goto done2;
}
- error = holdsock(fdp, uap->s, &lfp);
+ error = fgetsock(td, uap->s, &head, &fflag);
if (error)
goto done2;
s = splnet();
- head = (struct socket *)lfp->f_data;
if ((head->so_options & SO_ACCEPTCONN) == 0) {
splx(s);
error = EINVAL;
@@ -286,7 +280,6 @@ accept1(td, uap, compat)
TAILQ_REMOVE(&head->so_comp, so, so_list);
head->so_qlen--;
- fflag = lfp->f_flag;
error = falloc(td, &nfp, &fd);
if (error) {
/*
@@ -312,7 +305,8 @@ accept1(td, uap, compat)
if (head->so_sigio != NULL)
fsetown(fgetown(head->so_sigio), &so->so_sigio);
- nfp->f_data = (caddr_t)so;
+ soref(so); /* file descriptor reference */
+ nfp->f_data = (caddr_t)so; /* nfp has ref count from falloc */
nfp->f_flag = fflag;
nfp->f_ops = &socketops;
nfp->f_type = DTYPE_SOCKET;
@@ -375,7 +369,7 @@ noconnection:
done:
if (nfp != NULL)
fdrop(nfp, td);
- fdrop(lfp, td);
+ fputsock(head);
done2:
mtx_unlock(&Giant);
return (error);
@@ -420,35 +414,31 @@ connect(td, uap)
int namelen;
} */ *uap;
{
- struct file *fp;
- register struct socket *so;
+ struct socket *so;
struct sockaddr *sa;
int error, s;
mtx_lock(&Giant);
- error = holdsock(td->td_proc->p_fd, uap->s, &fp);
- if (error)
+ if ((error = fgetsock(td, uap->s, &so, NULL)) != 0)
goto done2;
- so = (struct socket *)fp->f_data;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
error = EALREADY;
- goto done;
+ goto done1;
}
error = getsockaddr(&sa, uap->name, uap->namelen);
if (error)
- goto done;
+ goto done1;
error = soconnect(so, sa, td);
if (error)
goto bad;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
FREE(sa, M_SONAME);
error = EINPROGRESS;
- goto done;
+ goto done1;
}
s = splnet();
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
- error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
- "connec", 0);
+ error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH, "connec", 0);
if (error)
break;
}
@@ -462,8 +452,8 @@ bad:
FREE(sa, M_SONAME);
if (error == ERESTART)
error = EINTR;
-done:
- fdrop(fp, td);
+done1:
+ fputsock(so);
done2:
mtx_unlock(&Giant);
return (error);
@@ -499,12 +489,12 @@ socketpair(td, uap)
goto free2;
fhold(fp1);
sv[0] = fd;
- fp1->f_data = (caddr_t)so1;
+ fp1->f_data = (caddr_t)so1; /* so1 already has ref count */
error = falloc(td, &fp2, &fd);
if (error)
goto free3;
fhold(fp2);
- fp2->f_data = (caddr_t)so2;
+ fp2->f_data = (caddr_t)so2; /* so2 already has ref count */
sv[1] = fd;
error = soconnect2(so1, so2);
if (error)
@@ -552,12 +542,11 @@ sendit(td, s, mp, flags)
register struct msghdr *mp;
int flags;
{
- struct file *fp;
struct uio auio;
register struct iovec *iov;
register int i;
struct mbuf *control;
- struct sockaddr *to;
+ struct sockaddr *to = NULL;
int len, error;
struct socket *so;
#ifdef KTRACE
@@ -565,8 +554,7 @@ sendit(td, s, mp, flags)
struct uio ktruio;
#endif
- error = holdsock(td->td_proc->p_fd, s, &fp);
- if (error)
+ if ((error = fgetsock(td, s, &so, NULL)) != 0)
return (error);
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
@@ -578,18 +566,14 @@ sendit(td, s, mp, flags)
iov = mp->msg_iov;
for (i = 0; i < mp->msg_iovlen; i++, iov++) {
if ((auio.uio_resid += iov->iov_len) < 0) {
- fdrop(fp, td);
- return (EINVAL);
+ error = EINVAL;
+ goto bad;
}
}
if (mp->msg_name) {
error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
- if (error) {
- fdrop(fp, td);
- return (error);
- }
- } else {
- to = 0;
+ if (error)
+ goto bad;
}
if (mp->msg_control) {
if (mp->msg_controllen < sizeof(struct cmsghdr)
@@ -633,7 +617,6 @@ sendit(td, s, mp, flags)
}
#endif
len = auio.uio_resid;
- so = (struct socket *)fp->f_data;
error = so->so_proto->pr_usrreqs->pru_sosend(so, to, &auio, 0, control,
flags, td);
if (error) {
@@ -659,7 +642,7 @@ sendit(td, s, mp, flags)
}
#endif
bad:
- fdrop(fp, td);
+ fputsock(so);
if (to)
FREE(to, M_SONAME);
return (error);
@@ -834,7 +817,6 @@ recvit(td, s, mp, namelenp)
register struct msghdr *mp;
caddr_t namelenp;
{
- struct file *fp;
struct uio auio;
register struct iovec *iov;
register int i;
@@ -848,8 +830,7 @@ recvit(td, s, mp, namelenp)
struct uio ktruio;
#endif
- error = holdsock(td->td_proc->p_fd, s, &fp);
- if (error)
+ if ((error = fgetsock(td, s, &so, NULL)) != 0)
return (error);
auio.uio_iov = mp->msg_iov;
auio.uio_iovcnt = mp->msg_iovlen;
@@ -861,7 +842,7 @@ recvit(td, s, mp, namelenp)
iov = mp->msg_iov;
for (i = 0; i < mp->msg_iovlen; i++, iov++) {
if ((auio.uio_resid += iov->iov_len) < 0) {
- fdrop(fp, td);
+ fputsock(so);
return (EINVAL);
}
}
@@ -875,7 +856,6 @@ recvit(td, s, mp, namelenp)
}
#endif
len = auio.uio_resid;
- so = (struct socket *)fp->f_data;
error = so->so_proto->pr_usrreqs->pru_soreceive(so, &fromsa, &auio,
(struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0,
&mp->msg_flags);
@@ -975,7 +955,7 @@ recvit(td, s, mp, namelenp)
mp->msg_controllen = ctlbuf - (caddr_t)mp->msg_control;
}
out:
- fdrop(fp, td);
+ fputsock(so);
if (fromsa)
FREE(fromsa, M_SONAME);
if (control)
@@ -1196,14 +1176,13 @@ shutdown(td, uap)
int how;
} */ *uap;
{
- struct file *fp;
+ struct socket *so;
int error;
mtx_lock(&Giant);
- error = holdsock(td->td_proc->p_fd, uap->s, &fp);
- if (error == 0) {
- error = soshutdown((struct socket *)fp->f_data, uap->how);
- fdrop(fp, td);
+ if ((error = fgetsock(td, uap->s, &so, NULL)) == 0) {
+ error = soshutdown(so, uap->how);
+ fputsock(so);
}
mtx_unlock(&Giant);
return(error);
@@ -1224,7 +1203,7 @@ setsockopt(td, uap)
int valsize;
} */ *uap;
{
- struct file *fp;
+ struct socket *so;
struct sockopt sopt;
int error;
@@ -1234,16 +1213,15 @@ setsockopt(td, uap)
return (EINVAL);
mtx_lock(&Giant);
- error = holdsock(td->td_proc->p_fd, uap->s, &fp);
- if (error == 0) {
+ if ((error = fgetsock(td, uap->s, &so, NULL)) == 0) {
sopt.sopt_dir = SOPT_SET;
sopt.sopt_level = uap->level;
sopt.sopt_name = uap->name;
sopt.sopt_val = uap->val;
sopt.sopt_valsize = uap->valsize;
sopt.sopt_td = td;
- error = sosetopt((struct socket *)fp->f_data, &sopt);
- fdrop(fp, td);
+ error = sosetopt(so, &sopt);
+ fputsock(so);
}
mtx_unlock(&Giant);
return(error);
@@ -1265,24 +1243,20 @@ getsockopt(td, uap)
} */ *uap;
{
int valsize, error;
- struct file *fp;
+ struct socket *so;
struct sockopt sopt;
mtx_lock(&Giant);
- error = holdsock(td->td_proc->p_fd, uap->s, &fp);
- if (error)
+ if ((error = fgetsock(td, uap->s, &so, NULL)) != 0)
goto done2;
if (uap->val) {
error = copyin((caddr_t)uap->avalsize, (caddr_t)&valsize,
sizeof (valsize));
- if (error) {
- fdrop(fp, td);
- goto done2;
- }
+ if (error)
+ goto done1;
if (valsize < 0) {
- fdrop(fp, td);
error = EINVAL;
- goto done2;
+ goto done1;
}
} else {
valsize = 0;
@@ -1295,13 +1269,14 @@ getsockopt(td, uap)
sopt.sopt_valsize = (size_t)valsize; /* checked non-negative above */
sopt.sopt_td = td;
- error = sogetopt((struct socket *)fp->f_data, &sopt);
+ error = sogetopt(so, &sopt);
if (error == 0) {
valsize = sopt.sopt_valsize;
error = copyout((caddr_t)&valsize,
(caddr_t)uap->avalsize, sizeof (valsize));
}
- fdrop(fp, td);
+done1:
+ fputsock(so);
done2:
mtx_unlock(&Giant);
return (error);
@@ -1323,21 +1298,16 @@ getsockname1(td, uap, compat)
} */ *uap;
int compat;
{
- struct file *fp;
- register struct socket *so;
+ struct socket *so;
struct sockaddr *sa;
int len, error;
mtx_lock(&Giant);
- error = holdsock(td->td_proc->p_fd, uap->fdes, &fp);
- if (error)
+ if ((error = fgetsock(td, uap->fdes, &so, NULL)) != 0)
goto done2;
error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
- if (error) {
- fdrop(fp, td);
- goto done2;
- }
- so = (struct socket *)fp->f_data;
+ if (error)
+ goto done1;
sa = 0;
error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &sa);
if (error)
@@ -1360,7 +1330,8 @@ gotnothing:
bad:
if (sa)
FREE(sa, M_SONAME);
- fdrop(fp, td);
+done1:
+ fputsock(so);
done2:
mtx_unlock(&Giant);
return (error);
@@ -1408,26 +1379,20 @@ getpeername1(td, uap, compat)
} */ *uap;
int compat;
{
- struct file *fp;
- register struct socket *so;
+ struct socket *so;
struct sockaddr *sa;
int len, error;
mtx_lock(&Giant);
- error = holdsock(td->td_proc->p_fd, uap->fdes, &fp);
- if (error)
+ if ((error = fgetsock(td, uap->fdes, &so, NULL)) != 0)
goto done2;
- so = (struct socket *)fp->f_data;
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
- fdrop(fp, td);
error = ENOTCONN;
- goto done2;
+ goto done1;
}
error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
- if (error) {
- fdrop(fp, td);
- goto done2;
- }
+ if (error)
+ goto done1;
sa = 0;
error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa);
if (error)
@@ -1450,7 +1415,8 @@ gotnothing:
bad:
if (sa)
FREE(sa, M_SONAME);
- fdrop(fp, td);
+done1:
+ fputsock(so);
done2:
mtx_unlock(&Giant);
return (error);
@@ -1550,33 +1516,6 @@ getsockaddr(namp, uaddr, len)
}
/*
- * holdsock() - load the struct file pointer associated
- * with a socket into *fpp. If an error occurs, non-zero
- * will be returned and *fpp will be set to NULL.
- */
-int
-holdsock(fdp, fdes, fpp)
- struct filedesc *fdp;
- int fdes;
- struct file **fpp;
-{
- register struct file *fp = NULL;
- int error = 0;
-
- if ((unsigned)fdes >= fdp->fd_nfiles ||
- (fp = fdp->fd_ofiles[fdes]) == NULL) {
- error = EBADF;
- } else if (fp->f_type != DTYPE_SOCKET) {
- error = ENOTSOCK;
- fp = NULL;
- } else {
- fhold(fp);
- }
- *fpp = fp;
- return(error);
-}
-
-/*
* Allocate a pool of sf_bufs (sendfile(2) or "super-fast" if you prefer. :-))
* XXX - The sf_buf functions are currently private to sendfile(2), so have
* been made static, but may be useful in the future for doing zero-copy in
@@ -1678,10 +1617,9 @@ sf_buf_free(caddr_t addr, void *args)
int
sendfile(struct thread *td, struct sendfile_args *uap)
{
- struct file *fp = NULL;
struct vnode *vp;
struct vm_object *obj;
- struct socket *so;
+ struct socket *so = NULL;
struct mbuf *m;
struct sf_buf *sf;
struct vm_page *pg;
@@ -1701,10 +1639,8 @@ sendfile(struct thread *td, struct sendfile_args *uap)
error = EINVAL;
goto done;
}
- error = holdsock(td->td_proc->p_fd, uap->s, &fp);
- if (error)
+ if ((error = fgetsock(td, uap->s, &so, NULL)) != 0)
goto done;
- so = (struct socket *)fp->f_data;
if (so->so_type != SOCK_STREAM) {
error = EINVAL;
goto done;
@@ -1988,8 +1924,9 @@ done:
}
if (vp)
vrele(vp);
- if (fp)
- fdrop(fp, td);
+ if (so)
+ fputsock(so);
mtx_unlock(&Giant);
return (error);
}
+
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index b8b7044..0cd408f 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -935,7 +935,7 @@ unp_drop(unp, errno)
if (unp->unp_addr)
FREE(unp->unp_addr, M_SONAME);
zfree(unp_zone, unp);
- sofree(so);
+ sotryfree(so);
}
}
diff --git a/sys/net/raw_cb.c b/sys/net/raw_cb.c
index 97dbc10..0dac2e5 100644
--- a/sys/net/raw_cb.c
+++ b/sys/net/raw_cb.c
@@ -97,7 +97,7 @@ raw_detach(rp)
struct socket *so = rp->rcb_socket;
so->so_pcb = 0;
- sofree(so);
+ sotryfree(so);
LIST_REMOVE(rp, list);
#ifdef notdef
if (rp->rcb_laddr)
diff --git a/sys/net/raw_usrreq.c b/sys/net/raw_usrreq.c
index 555bd3f..3138b10 100644
--- a/sys/net/raw_usrreq.c
+++ b/sys/net/raw_usrreq.c
@@ -142,8 +142,8 @@ raw_uabort(struct socket *so)
if (rp == 0)
return EINVAL;
raw_disconnect(rp);
- sofree(so);
- soisdisconnected(so);
+ sotryfree(so);
+ soisdisconnected(so); /* XXX huh? called after the sofree()? */
return 0;
}
diff --git a/sys/netatalk/ddp_pcb.c b/sys/netatalk/ddp_pcb.c
index 2dbf0f9..7c5f857 100644
--- a/sys/netatalk/ddp_pcb.c
+++ b/sys/netatalk/ddp_pcb.c
@@ -441,7 +441,7 @@ at_pcbdetach( struct socket *so, struct ddpcb *ddp)
{
soisdisconnected( so );
so->so_pcb = 0;
- sofree( so );
+ sotryfree(so);
/* remove ddp from ddp_ports list */
if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
diff --git a/sys/netatalk/ddp_usrreq.c b/sys/netatalk/ddp_usrreq.c
index 2dbf0f9..7c5f857 100644
--- a/sys/netatalk/ddp_usrreq.c
+++ b/sys/netatalk/ddp_usrreq.c
@@ -441,7 +441,7 @@ at_pcbdetach( struct socket *so, struct ddpcb *ddp)
{
soisdisconnected( so );
so->so_pcb = 0;
- sofree( so );
+ sotryfree(so);
/* remove ddp from ddp_ports list */
if ( ddp->ddp_lsat.sat_port != ATADDR_ANYPORT &&
diff --git a/sys/netatm/atm_socket.c b/sys/netatm/atm_socket.c
index 6d87791..534fec5 100644
--- a/sys/netatm/atm_socket.c
+++ b/sys/netatm/atm_socket.c
@@ -176,7 +176,7 @@ atm_sock_detach(so)
* Break links and free control blocks
*/
so->so_pcb = NULL;
- sofree(so);
+ sotryfree(so);
atm_free((caddr_t)atp);
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 4ee4b0d..4fecd6a 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -563,7 +563,7 @@ in_pcbdetach(inp)
inp->inp_gencnt = ++ipi->ipi_gencnt;
in_pcbremlists(inp);
so->so_pcb = 0;
- sofree(so);
+ sotryfree(so);
if (inp->inp_options)
(void)m_free(inp->inp_options);
if (rt) {
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index a82ab84..6612848 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -606,7 +606,7 @@ in6_pcbdetach(inp)
inp->inp_gencnt = ++ipi->ipi_gencnt;
in_pcbremlists(inp);
sotoinpcb(so) = 0;
- sofree(so);
+ sotryfree(so);
if (inp->in6p_options)
m_freem(inp->in6p_options);
diff --git a/sys/netipx/ipx_pcb.c b/sys/netipx/ipx_pcb.c
index fc0c6dd..ea038fe 100644
--- a/sys/netipx/ipx_pcb.c
+++ b/sys/netipx/ipx_pcb.c
@@ -268,7 +268,7 @@ ipx_pcbdetach(ipxp)
struct socket *so = ipxp->ipxp_socket;
so->so_pcb = 0;
- sofree(so);
+ sotryfree(so);
if (ipxp->ipxp_route.ro_rt != NULL)
rtfree(ipxp->ipxp_route.ro_rt);
remque(ipxp);
diff --git a/sys/netipx/ipx_usrreq.c b/sys/netipx/ipx_usrreq.c
index fdd6917..7cddcfc 100644
--- a/sys/netipx/ipx_usrreq.c
+++ b/sys/netipx/ipx_usrreq.c
@@ -426,7 +426,7 @@ ipx_usr_abort(so)
s = splnet();
ipx_pcbdetach(ipxp);
splx(s);
- sofree(so);
+ sotryfree(so);
soisdisconnected(so);
return (0);
}
diff --git a/sys/netnatm/natm.c b/sys/netnatm/natm.c
index 257aa76..af80e11 100644
--- a/sys/netnatm/natm.c
+++ b/sys/netnatm/natm.c
@@ -133,7 +133,7 @@ natm_usr_detach(struct socket *so)
*/
npcb_free(npcb, NPCB_DESTROY); /* drain */
so->so_pcb = NULL;
- sofree(so);
+ sotryfree(so);
out:
splx(s);
return (error);
@@ -481,7 +481,7 @@ struct proc *p;
npcb_free(npcb, NPCB_DESTROY); /* drain */
so->so_pcb = NULL;
- sofree(so);
+ sotryfree(so);
break;
diff --git a/sys/netns/idp_usrreq.c b/sys/netns/idp_usrreq.c
index a03770f0..5203961 100644
--- a/sys/netns/idp_usrreq.c
+++ b/sys/netns/idp_usrreq.c
@@ -491,8 +491,8 @@ idp_usrreq(so, req, m, nam, control)
case PRU_ABORT:
ns_pcbdetach(nsp);
- sofree(so);
- soisdisconnected(so);
+ sotryfree(so);
+ soisdisconnected(so); /* XXX huh, called after sofree()? */
break;
case PRU_SOCKADDR:
diff --git a/sys/netns/ns_pcb.c b/sys/netns/ns_pcb.c
index 85f7548..01301c0 100644
--- a/sys/netns/ns_pcb.c
+++ b/sys/netns/ns_pcb.c
@@ -232,7 +232,7 @@ ns_pcbdetach(nsp)
struct socket *so = nsp->nsp_socket;
so->so_pcb = 0;
- sofree(so);
+ sotryfree(so);
if (nsp->nsp_route.ro_rt)
rtfree(nsp->nsp_route.ro_rt);
remque(nsp);
diff --git a/sys/nfsserver/nfs_syscalls.c b/sys/nfsserver/nfs_syscalls.c
index 17f90f7..73935f8 100644
--- a/sys/nfsserver/nfs_syscalls.c
+++ b/sys/nfsserver/nfs_syscalls.c
@@ -143,9 +143,12 @@ nfssvc(struct thread *td, struct nfssvc_args *uap)
error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg));
if (error)
goto done2;
- error = holdsock(td->td_proc->p_fd, nfsdarg.sock, &fp);
- if (error)
+ if ((error = fget(td, nfsdarg.sock, &fp)) != 0)
+ goto done2;
+ if (fp->f_type != DTYPE_SOCKET) {
+ fdrop(fp, td);
goto done2;
+ }
/*
* Get the client address for connected sockets.
*/
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 589bffd..f552167 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -50,6 +50,7 @@ struct thread;
struct uio;
struct knote;
struct vnode;
+struct socket;
/*
* Kernel descriptor table.
@@ -119,6 +120,9 @@ int fgetvp __P((struct thread *td, int fd, struct vnode **vpp));
int fgetvp_read __P((struct thread *td, int fd, struct vnode **vpp));
int fgetvp_write __P((struct thread *td, int fd, struct vnode **vpp));
+int fgetsock __P((struct thread *td, int fd, struct socket **spp, u_int *fflagp));
+void fputsock __P((struct socket *sp));
+
static __inline void
fhold(fp)
struct file *fp;
diff --git a/sys/sys/socketvar.h b/sys/sys/socketvar.h
index ec22fa7..f868dcd 100644
--- a/sys/sys/socketvar.h
+++ b/sys/sys/socketvar.h
@@ -38,6 +38,7 @@
#define _SYS_SOCKETVAR_H_
#include <sys/queue.h> /* for TAILQ macros */
+#include <sys/sx.h> /* SX locks */
#include <sys/selinfo.h> /* for struct selinfo */
/*
@@ -52,6 +53,7 @@ struct accept_filter;
struct socket {
struct vm_zone *so_zone; /* zone we were allocated from */
+ int so_count; /* reference count */
short so_type; /* generic type, see socket.h */
short so_options; /* from socket call, see socket.h */
short so_linger; /* time to linger while closing */
@@ -244,6 +246,28 @@ struct xsocket {
} \
}
+/*
+ * soref()/sorele() ref-count the socket structure. Note that you must
+ * still explicitly close the socket, but the last ref count will free
+ * the structure.
+ */
+
+#define soref(so) do { \
+ ++so->so_count; \
+ } while (0)
+
+#define sorele(so) do { \
+ if (so->so_count <= 0) \
+ panic("sorele");\
+ if (--so->so_count == 0)\
+ sofree(so); \
+ } while (0)
+
+#define sotryfree(so) do { \
+ if (so->so_count == 0) \
+ sofree(so); \
+ } while(0)
+
#define sorwakeup(so) do { \
if (sb_notify(&(so)->so_rcv)) \
sowakeup((so), &(so)->so_rcv); \
@@ -360,7 +384,6 @@ int soconnect __P((struct socket *so, struct sockaddr *nam, struct thread *td));
int soconnect2 __P((struct socket *so1, struct socket *so2));
int socreate __P((int dom, struct socket **aso, int type, int proto,
struct thread *td));
-void sodealloc __P((struct socket *so));
int sodisconnect __P((struct socket *so));
void sofree __P((struct socket *so));
int sogetopt __P((struct socket *so, struct sockopt *sopt));
OpenPOWER on IntegriCloud