summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authortanimura <tanimura@FreeBSD.org>2002-05-20 05:41:09 +0000
committertanimura <tanimura@FreeBSD.org>2002-05-20 05:41:09 +0000
commit92d8381dd544a8237b3fd68c4e7fce9bd0903fb2 (patch)
tree2465ddbcecac65f96c5c6d5cef1a4fe3f1ac03f8 /sys/kern
parent969293170b27461145f69a538d5abd15fea34ba1 (diff)
downloadFreeBSD-src-92d8381dd544a8237b3fd68c4e7fce9bd0903fb2.zip
FreeBSD-src-92d8381dd544a8237b3fd68c4e7fce9bd0903fb2.tar.gz
Lock down a socket, milestone 1.
o Add a mutex (sb_mtx) to struct sockbuf. This protects the data in a socket buffer. The mutex in the receive buffer also protects the data in struct socket. o Determine the lock strategy for each members in struct socket. o Lock down the following members: - so_count - so_options - so_linger - so_state o Remove *_locked() socket APIs. Make the following socket APIs touching the members above now require a locked socket: - sodisconnect() - soisconnected() - soisconnecting() - soisdisconnected() - soisdisconnecting() - sofree() - soref() - sorele() - sorwakeup() - sotryfree() - sowakeup() - sowwakeup() Reviewed by: alfred
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_descrip.c7
-rw-r--r--sys/kern/sys_socket.c8
-rw-r--r--sys/kern/uipc_domain.c8
-rw-r--r--sys/kern/uipc_sockbuf.c127
-rw-r--r--sys/kern/uipc_socket.c208
-rw-r--r--sys/kern/uipc_socket2.c127
-rw-r--r--sys/kern/uipc_syscalls.c37
-rw-r--r--sys/kern/uipc_usrreq.c35
-rw-r--r--sys/kern/vfs_aio.c3
9 files changed, 402 insertions, 158 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index 15837d3..8a6176d 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1777,19 +1777,22 @@ fgetsock(struct thread *td, int fd, struct socket **spp, u_int *fflagp)
*spp = (struct socket *)fp->f_data;
if (fflagp)
*fflagp = fp->f_flag;
+ SOCK_LOCK(*spp);
soref(*spp);
+ SOCK_UNLOCK(*spp);
}
FILEDESC_UNLOCK(td->td_proc->p_fd);
return(error);
}
/*
- * Drop the reference count on the the socket and XXX release the SX lock in
- * the future. The last reference closes the socket.
+ * Drop the reference count on the the socket and release the lock.
+ * The last reference closes the socket. The socket must be unlocked.
*/
void
fputsock(struct socket *so)
{
+ SOCK_LOCK(so);
sorele(so);
}
diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c
index c8a6198..6c1a23c 100644
--- a/sys/kern/sys_socket.c
+++ b/sys/kern/sys_socket.c
@@ -104,13 +104,16 @@ soo_ioctl(fp, cmd, data, td)
switch (cmd) {
case FIONBIO:
+ SOCK_LOCK(so);
if (*(int *)data)
so->so_state |= SS_NBIO;
else
so->so_state &= ~SS_NBIO;
+ SOCK_UNLOCK(so);
return (0);
case FIOASYNC:
+ SOCK_LOCK(so);
if (*(int *)data) {
so->so_state |= SS_ASYNC;
so->so_rcv.sb_flags |= SB_ASYNC;
@@ -120,6 +123,7 @@ soo_ioctl(fp, cmd, data, td)
so->so_rcv.sb_flags &= ~SB_ASYNC;
so->so_snd.sb_flags &= ~SB_ASYNC;
}
+ SOCK_UNLOCK(so);
return (0);
case FIONREAD:
@@ -141,7 +145,9 @@ soo_ioctl(fp, cmd, data, td)
return (0);
case SIOCATMARK:
+ SOCK_LOCK(so);
*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
+ SOCK_UNLOCK(so);
return (0);
}
/*
@@ -181,11 +187,13 @@ soo_stat(fp, ub, td)
* If SS_CANTRCVMORE is set, but there's still data left in the
* receive buffer, the socket is still readable.
*/
+ SOCK_LOCK(so);
if ((so->so_state & SS_CANTRCVMORE) == 0 ||
so->so_rcv.sb_cc != 0)
ub->st_mode |= S_IRUSR | S_IRGRP | S_IROTH;
if ((so->so_state & SS_CANTSENDMORE) == 0)
ub->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
+ SOCK_UNLOCK(so);
ub->st_size = so->so_rcv.sb_cc;
ub->st_uid = so->so_cred->cr_uid;
ub->st_gid = so->so_cred->cr_gid;
diff --git a/sys/kern/uipc_domain.c b/sys/kern/uipc_domain.c
index b8321eb..cfb7768 100644
--- a/sys/kern/uipc_domain.c
+++ b/sys/kern/uipc_domain.c
@@ -35,11 +35,13 @@
*/
#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/protosw.h>
#include <sys/domain.h>
-#include <sys/mbuf.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/systm.h>
#include <vm/uma.h>
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
index 34779f8..c395d87 100644
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -102,71 +102,56 @@ soisconnecting(so)
register struct socket *so;
{
+ SOCK_ASSERT(so, MA_OWNED);
so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= SS_ISCONNECTING;
}
void
-soisconnected_locked(so)
+soisconnected(so)
struct socket *so;
{
- struct socket *head = so->so_head;
+ struct socket *head;
+ so_upcall_t *upcp;
+ void *upcarg;
+ SOCK_ASSERT(so, MA_OWNED);
+ head = so->so_head;
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
if (head && (so->so_state & SS_INCOMP)) {
if ((so->so_options & SO_ACCEPTFILTER) != 0) {
- so->so_upcall = head->so_accf->so_accept_filter->accf_callback;
- so->so_upcallarg = head->so_accf->so_accept_filter_arg;
+ SOCK_UNLOCK(so);
+ SOCK_LOCK(head);
+ upcp = head->so_accf->so_accept_filter->accf_callback;
+ upcarg = head->so_accf->so_accept_filter_arg;
+ SOCK_UNLOCK(head);
+ SOCK_LOCK(so);
+ so->so_upcall = upcp;
+ so->so_upcallarg = upcarg;
so->so_rcv.sb_flags |= SB_UPCALL;
so->so_options &= ~SO_ACCEPTFILTER;
- so->so_upcall(so, so->so_upcallarg, 0);
+ SOCK_UNLOCK(so);
+ so->so_upcall(so, upcarg, 0);
+ SOCK_LOCK(so);
return;
}
- TAILQ_REMOVE(&head->so_incomp, so, so_list);
- head->so_incqlen--;
so->so_state &= ~SS_INCOMP;
- TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
- head->so_qlen++;
so->so_state |= SS_COMP;
- sorwakeup_locked(head);
- wakeup_one(&head->so_timeo);
- } else {
- wakeup(&so->so_timeo);
- sorwakeup_locked(so);
- sowwakeup_locked(so);
- }
-}
-
-void
-soisconnected(so)
- struct socket *so;
-{
- struct socket *head = so->so_head;
-
- so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
- so->so_state |= SS_ISCONNECTED;
- if (head && (so->so_state & SS_INCOMP)) {
- if ((so->so_options & SO_ACCEPTFILTER) != 0) {
- so->so_upcall = head->so_accf->so_accept_filter->accf_callback;
- so->so_upcallarg = head->so_accf->so_accept_filter_arg;
- so->so_rcv.sb_flags |= SB_UPCALL;
- so->so_options &= ~SO_ACCEPTFILTER;
- so->so_upcall(so, so->so_upcallarg, 0);
- return;
- }
+ SOCK_UNLOCK(so);
+ SOCK_LOCK(head);
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
- so->so_state &= ~SS_INCOMP;
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
head->so_qlen++;
- so->so_state |= SS_COMP;
- sorwakeup_locked(head);
+ sorwakeup(head);
wakeup_one(&head->so_timeo);
+ SOCK_UNLOCK(head);
+ SOCK_LOCK(so);
} else {
wakeup(&so->so_timeo);
- sorwakeup_locked(so);
- sowwakeup_locked(so);
+ sorwakeup(so);
+ sowwakeup(so);
}
}
@@ -175,31 +160,25 @@ soisdisconnecting(so)
register struct socket *so;
{
+ SOCK_ASSERT(so, MA_OWNED);
so->so_state &= ~SS_ISCONNECTING;
so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
wakeup((caddr_t)&so->so_timeo);
- sowwakeup_locked(so);
- sorwakeup_locked(so);
+ sowwakeup(so);
+ sorwakeup(so);
}
void
-soisdisconnected_locked(so)
+soisdisconnected(so)
register struct socket *so;
{
+ SOCK_ASSERT(so, MA_OWNED);
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
wakeup((caddr_t)&so->so_timeo);
- sowwakeup_locked(so);
- sorwakeup_locked(so);
-}
-
-void
-soisdisconnected(so)
- register struct socket *so;
-{
-
- soisdisconnected_locked(so);
+ sowwakeup(so);
+ sorwakeup(so);
}
/*
@@ -224,25 +203,32 @@ sonewconn(head, connstatus)
so = soalloc(0);
if (so == NULL)
return ((struct socket *)0);
+ SOCK_LOCK(head);
if ((head->so_options & SO_ACCEPTFILTER) != 0)
connstatus = 0;
+ SOCK_UNLOCK(head);
so->so_head = head;
so->so_type = head->so_type;
+ SOCK_LOCK(so);
so->so_options = head->so_options &~ SO_ACCEPTCONN;
so->so_linger = head->so_linger;
so->so_state = head->so_state | SS_NOFDREF;
+ SOCK_UNLOCK(so);
so->so_proto = head->so_proto;
so->so_timeo = head->so_timeo;
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)) {
+ SOCK_LOCK(so);
sotryfree(so);
return ((struct socket *)0);
}
if (connstatus) {
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
+ SOCK_LOCK(so);
so->so_state |= SS_COMP;
+ SOCK_UNLOCK(so);
head->so_qlen++;
} else {
if (head->so_incqlen >= head->so_qlimit) {
@@ -251,13 +237,19 @@ sonewconn(head, connstatus)
(void) soabort(sp);
}
TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list);
+ SOCK_LOCK(so);
so->so_state |= SS_INCOMP;
+ SOCK_UNLOCK(so);
head->so_incqlen++;
}
if (connstatus) {
- sorwakeup_locked(head);
+ SOCK_LOCK(head);
+ sorwakeup(head);
wakeup((caddr_t)&head->so_timeo);
+ SOCK_UNLOCK(head);
+ SOCK_LOCK(so);
so->so_state |= connstatus;
+ SOCK_UNLOCK(so);
}
return (so);
}
@@ -277,8 +269,10 @@ socantsendmore(so)
struct socket *so;
{
+ SOCK_LOCK(so);
so->so_state |= SS_CANTSENDMORE;
- sowwakeup_locked(so);
+ sowwakeup(so);
+ SOCK_UNLOCK(so);
}
void
@@ -286,8 +280,10 @@ socantrcvmore(so)
struct socket *so;
{
+ SOCK_LOCK(so);
so->so_state |= SS_CANTRCVMORE;
- sorwakeup_locked(so);
+ sorwakeup(so);
+ SOCK_UNLOCK(so);
}
/*
@@ -336,6 +332,7 @@ sowakeup(so, sb)
register struct socket *so;
register struct sockbuf *sb;
{
+ SOCK_ASSERT(so, MA_OWNED);
selwakeup(&sb->sb_sel);
sb->sb_flags &= ~SB_SEL;
@@ -343,13 +340,23 @@ sowakeup(so, sb)
sb->sb_flags &= ~SB_WAIT;
wakeup((caddr_t)&sb->sb_cc);
}
- if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
+ if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) {
+ SOCK_UNLOCK(so);
pgsigio(&so->so_sigio, SIGIO, 0);
- if (sb->sb_flags & SB_UPCALL)
+ SOCK_LOCK(so);
+ }
+ if (sb->sb_flags & SB_UPCALL) {
+ SOCK_UNLOCK(so);
(*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT);
- if (sb->sb_flags & SB_AIO)
+ SOCK_LOCK(so);
+ }
+ if (sb->sb_flags & SB_AIO) {
+ SOCK_UNLOCK(so);
aio_swake(so, sb);
+ } else
+ SOCK_UNLOCK(so);
KNOTE(&sb->sb_sel.si_note, 0);
+ SOCK_LOCK(so);
}
/*
@@ -959,9 +966,11 @@ sotoxsocket(struct socket *so, struct xsocket *xso)
xso->xso_len = sizeof *xso;
xso->xso_so = so;
xso->so_type = so->so_type;
+ SOCK_LOCK(so);
xso->so_options = so->so_options;
xso->so_linger = so->so_linger;
xso->so_state = so->so_state;
+ SOCK_UNLOCK(so);
xso->so_pcb = so->so_pcb;
xso->xso_protocol = so->so_proto->pr_protocol;
xso->xso_family = so->so_proto->pr_domain->dom_family;
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 4bbc6e2..cc63c31 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -82,6 +82,7 @@ static struct filterops sowrite_filtops =
uma_zone_t socket_zone;
so_gen_t so_gencnt; /* generation count for sockets */
+struct mtx socq_lock;
MALLOC_DEFINE(M_SONAME, "soname", "socket name");
MALLOC_DEFINE(M_PCB, "pcb", "protocol control block");
@@ -129,7 +130,8 @@ soalloc(waitok)
/* XXX race condition for reentrant kernel */
bzero(so, sizeof *so);
so->so_gencnt = ++so_gencnt;
- /* sx_init(&so->so_sxlock, "socket sxlock"); */
+ mtx_init(&so->so_rcv.sb_mtx, "sockbuf rcv", NULL, MTX_DEF);
+ mtx_init(&so->so_snd.sb_mtx, "sockbuf snd", NULL, MTX_DEF);
TAILQ_INIT(&so->so_aiojobq);
++numopensockets;
}
@@ -174,14 +176,17 @@ socreate(dom, aso, type, proto, cred, td)
if (so == 0)
return (ENOBUFS);
+ SOCK_LOCK(so);
TAILQ_INIT(&so->so_incomp);
TAILQ_INIT(&so->so_comp);
so->so_type = type;
so->so_cred = crhold(cred);
so->so_proto = prp;
soref(so);
+ SOCK_UNLOCK(so);
error = (*prp->pr_usrreqs->pru_attach)(so, proto, td);
if (error) {
+ SOCK_LOCK(so);
so->so_state |= SS_NOFDREF;
sorele(so);
return (error);
@@ -208,7 +213,9 @@ static void
sodealloc(struct socket *so)
{
+ SOCK_LOCK(so);
KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count));
+ SOCK_UNLOCK(so);
so->so_gencnt = ++so_gencnt;
if (so->so_rcv.sb_hiwat)
(void)chgsbsize(so->so_cred->cr_uidinfo,
@@ -228,7 +235,8 @@ sodealloc(struct socket *so)
}
#endif
crfree(so->so_cred);
- /* sx_destroy(&so->so_sxlock); */
+ mtx_destroy(&so->so_rcv.sb_mtx);
+ mtx_destroy(&so->so_snd.sb_mtx);
uma_zfree(socket_zone, so);
--numopensockets;
}
@@ -247,8 +255,11 @@ solisten(so, backlog, td)
splx(s);
return (error);
}
- if (TAILQ_EMPTY(&so->so_comp))
+ if (TAILQ_EMPTY(&so->so_comp)) {
+ SOCK_LOCK(so);
so->so_options |= SO_ACCEPTCONN;
+ SOCK_UNLOCK(so);
+ }
if (backlog < 0 || backlog > somaxconn)
backlog = somaxconn;
so->so_qlimit = backlog;
@@ -262,15 +273,21 @@ sofree(so)
{
struct socket *head = so->so_head;
+ SOCK_ASSERT(so, MA_OWNED);
+
KASSERT(so->so_count == 0, ("socket %p so_count not 0", so));
- if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
+ if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) {
+ SOCK_UNLOCK(so);
return;
+ }
if (head != NULL) {
if (so->so_state & SS_INCOMP) {
+ SOCK_UNLOCK(so);
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
} else if (so->so_state & SS_COMP) {
+ SOCK_UNLOCK(so);
/*
* We must not decommission a socket that's
* on the accept(2) queue. If we do, then
@@ -279,11 +296,15 @@ sofree(so)
*/
return;
} else {
+ SOCK_UNLOCK(so);
panic("sofree: not queued");
}
+ SOCK_LOCK(so);
so->so_state &= ~SS_INCOMP;
+ SOCK_UNLOCK(so);
so->so_head = NULL;
- }
+ } else
+ SOCK_UNLOCK(so);
sbrelease(&so->so_snd, so);
sorflush(so);
sodealloc(so);
@@ -306,9 +327,11 @@ soclose(so)
int error = 0;
funsetown(&so->so_sigio);
+ SOCK_LOCK(so);
if (so->so_options & SO_ACCEPTCONN) {
struct socket *sp, *sonext;
+ SOCK_UNLOCK(so);
sp = TAILQ_FIRST(&so->so_incomp);
for (; sp != NULL; sp = sonext) {
sonext = TAILQ_NEXT(sp, so_list);
@@ -319,38 +342,49 @@ soclose(so)
/* Dequeue from so_comp since sofree() won't do it */
TAILQ_REMOVE(&so->so_comp, sp, so_list);
so->so_qlen--;
+ SOCK_LOCK(sp);
sp->so_state &= ~SS_COMP;
+ SOCK_UNLOCK(sp);
sp->so_head = NULL;
(void) soabort(sp);
}
+ SOCK_LOCK(so);
}
if (so->so_pcb == 0)
goto discard;
if (so->so_state & SS_ISCONNECTED) {
if ((so->so_state & SS_ISDISCONNECTING) == 0) {
error = sodisconnect(so);
- if (error)
+ if (error) {
+ SOCK_UNLOCK(so);
goto drop;
+ }
}
if (so->so_options & SO_LINGER) {
if ((so->so_state & SS_ISDISCONNECTING) &&
- (so->so_state & SS_NBIO))
+ (so->so_state & SS_NBIO)) {
+ SOCK_UNLOCK(so);
goto drop;
+ }
while (so->so_state & SS_ISCONNECTED) {
- error = tsleep((caddr_t)&so->so_timeo,
+ error = msleep((caddr_t)&so->so_timeo, SOCK_MTX(so),
PSOCK | PCATCH, "soclos", so->so_linger * hz);
if (error)
break;
}
}
}
+ SOCK_UNLOCK(so);
drop:
+ SOCK_ASSERT(so, MA_NOTOWNED);
if (so->so_pcb) {
int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so);
if (error == 0)
error = error2;
}
+ SOCK_LOCK(so);
discard:
+ SOCK_ASSERT(so, MA_OWNED);
if (so->so_state & SS_NOFDREF)
panic("soclose: NOFDREF");
so->so_state |= SS_NOFDREF;
@@ -370,6 +404,7 @@ soabort(so)
error = (*so->so_proto->pr_usrreqs->pru_abort)(so);
if (error) {
+ SOCK_LOCK(so);
sotryfree(so); /* note: does not decrement the ref count */
return error;
}
@@ -384,9 +419,11 @@ soaccept(so, nam)
int s = splnet();
int error;
+ SOCK_LOCK(so);
if ((so->so_state & SS_NOFDREF) == 0)
panic("soaccept: !NOFDREF");
so->so_state &= ~SS_NOFDREF;
+ SOCK_UNLOCK(so);
error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam);
splx(s);
return (error);
@@ -401,8 +438,11 @@ soconnect(so, nam, td)
int s;
int error;
- if (so->so_options & SO_ACCEPTCONN)
+ SOCK_LOCK(so);
+ if (so->so_options & SO_ACCEPTCONN) {
+ SOCK_UNLOCK(so);
return (EOPNOTSUPP);
+ }
s = splnet();
/*
* If protocol is connection-based, can only connect once.
@@ -410,12 +450,23 @@ soconnect(so, nam, td)
* This allows user to disconnect by connecting to, e.g.,
* a null address.
*/
- if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
- ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
- (error = sodisconnect(so))))
- error = EISCONN;
- else
- error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td);
+ if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
+ if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+ SOCK_UNLOCK(so);
+ error = EISCONN;
+ goto done;
+ } else {
+ error = sodisconnect(so);
+ if (error) {
+ SOCK_UNLOCK(so);
+ error = EISCONN;
+ goto done;
+ }
+ }
+ }
+ SOCK_UNLOCK(so);
+ error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td);
+done:
splx(s);
return (error);
}
@@ -440,6 +491,7 @@ sodisconnect(so)
int s = splnet();
int error;
+ SOCK_ASSERT(so, MA_OWNED);
if ((so->so_state & SS_ISCONNECTED) == 0) {
error = ENOTCONN;
goto bad;
@@ -448,7 +500,9 @@ sodisconnect(so)
error = EALREADY;
goto bad;
}
+ SOCK_UNLOCK(so);
error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so);
+ SOCK_LOCK(so);
bad:
splx(s);
return (error);
@@ -507,14 +561,22 @@ sosend(so, addr, uio, top, control, flags, td)
goto out;
}
+ SOCK_LOCK(so);
dontroute =
(flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
(so->so_proto->pr_flags & PR_ATOMIC);
+ SOCK_UNLOCK(so);
if (td)
td->td_proc->p_stats->p_ru.ru_msgsnd++;
if (control)
clen = control->m_len;
-#define snderr(errno) { error = errno; splx(s); goto release; }
+#define snderr(errno) \
+ do { \
+ error = errno; \
+ SOCK_UNLOCK(so); \
+ splx(s); \
+ goto release; \
+ } while(0);
restart:
error = sblock(&so->so_snd, SBLOCKWAIT(flags));
@@ -522,11 +584,13 @@ restart:
goto out;
do {
s = splnet();
+ SOCK_LOCK(so);
if (so->so_state & SS_CANTSENDMORE)
snderr(EPIPE);
if (so->so_error) {
error = so->so_error;
so->so_error = 0;
+ SOCK_UNLOCK(so);
splx(s);
goto release;
}
@@ -546,16 +610,21 @@ restart:
snderr(so->so_proto->pr_flags & PR_CONNREQUIRED ?
ENOTCONN : EDESTADDRREQ);
}
+ SOCK_UNLOCK(so);
space = sbspace(&so->so_snd);
if (flags & MSG_OOB)
space += 1024;
if ((atomic && resid > so->so_snd.sb_hiwat) ||
- clen > so->so_snd.sb_hiwat)
+ clen > so->so_snd.sb_hiwat) {
+ SOCK_LOCK(so);
snderr(EMSGSIZE);
+ }
if (space < resid + clen &&
(atomic || space < so->so_snd.sb_lowat || space < clen)) {
+ SOCK_LOCK(so);
if (so->so_state & SS_NBIO)
snderr(EWOULDBLOCK);
+ SOCK_UNLOCK(so);
sbunlock(&so->so_snd);
error = sbwait(&so->so_snd);
splx(s);
@@ -623,8 +692,11 @@ nopages:
break;
}
} while (space > 0 && atomic);
- if (dontroute)
+ if (dontroute) {
+ SOCK_LOCK(so);
so->so_options |= SO_DONTROUTE;
+ SOCK_UNLOCK(so);
+ }
s = splnet(); /* XXX */
/*
* XXX all the SS_CANTSENDMORE checks previously
@@ -650,8 +722,11 @@ nopages:
(resid > 0 && space > 0) ? PRUS_MORETOCOME : 0,
top, addr, control, td);
splx(s);
- if (dontroute)
+ if (dontroute) {
+ SOCK_LOCK(so);
so->so_options &= ~SO_DONTROUTE;
+ SOCK_UNLOCK(so);
+ }
clen = 0;
control = 0;
top = 0;
@@ -731,10 +806,15 @@ bad:
}
if (mp)
*mp = (struct mbuf *)0;
- if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
+ SOCK_LOCK(so);
+ if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) {
+ SOCK_UNLOCK(so);
(*pr->pr_usrreqs->pru_rcvd)(so, 0);
+ } else
+ SOCK_UNLOCK(so);
restart:
+ SOCK_ASSERT(so, MA_NOTOWNED);
error = sblock(&so->so_rcv, SBLOCKWAIT(flags));
if (error)
return (error);
@@ -768,28 +848,37 @@ restart:
so->so_error = 0;
goto release;
}
+ SOCK_LOCK(so);
if (so->so_state & SS_CANTRCVMORE) {
+ SOCK_UNLOCK(so);
if (m)
goto dontblock;
else
goto release;
}
+ SOCK_UNLOCK(so);
for (; m; m = m->m_next)
if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) {
m = so->so_rcv.sb_mb;
goto dontblock;
}
+ SOCK_LOCK(so);
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
(so->so_proto->pr_flags & PR_CONNREQUIRED)) {
+ SOCK_UNLOCK(so);
error = ENOTCONN;
goto release;
}
- if (uio->uio_resid == 0)
+ if (uio->uio_resid == 0) {
+ SOCK_UNLOCK(so);
goto release;
+ }
if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
+ SOCK_UNLOCK(so);
error = EWOULDBLOCK;
goto release;
}
+ SOCK_UNLOCK(so);
sbunlock(&so->so_rcv);
error = sbwait(&so->so_rcv);
splx(s);
@@ -859,7 +948,9 @@ dontblock:
else
KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER,
("m->m_type == %d", m->m_type));
+ SOCK_LOCK(so);
so->so_state &= ~SS_RCVATMARK;
+ SOCK_UNLOCK(so);
len = uio->uio_resid;
if (so->so_oobmark && len > so->so_oobmark - offset)
len = so->so_oobmark - offset;
@@ -917,7 +1008,9 @@ dontblock:
if ((flags & MSG_PEEK) == 0) {
so->so_oobmark -= len;
if (so->so_oobmark == 0) {
+ SOCK_LOCK(so);
so->so_state |= SS_RCVATMARK;
+ SOCK_UNLOCK(so);
break;
}
} else {
@@ -937,8 +1030,12 @@ dontblock:
*/
while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
!sosendallatonce(so) && !nextrecord) {
- if (so->so_error || so->so_state & SS_CANTRCVMORE)
+ SOCK_LOCK(so);
+ if (so->so_error || so->so_state & SS_CANTRCVMORE) {
+ SOCK_UNLOCK(so);
break;
+ }
+ SOCK_UNLOCK(so);
/*
* Notify the protocol that some data has been
* drained before blocking.
@@ -968,12 +1065,15 @@ dontblock:
if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
(*pr->pr_usrreqs->pru_rcvd)(so, flags);
}
+ SOCK_LOCK(so);
if (orig_resid == uio->uio_resid && orig_resid &&
(flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
+ SOCK_UNLOCK(so);
sbunlock(&so->so_rcv);
splx(s);
goto restart;
}
+ SOCK_UNLOCK(so);
if (flagsp)
*flagsp |= flags;
@@ -1015,7 +1115,10 @@ sorflush(so)
socantrcvmore(so);
sbunlock(sb);
asb = *sb;
- bzero((caddr_t)sb, sizeof (*sb));
+#define RANGEOF(type, start, end) (offsetof(type, end) - offsetof(type, start))
+ bzero((caddr_t)&sb->sb_startzero,
+ (unsigned) RANGEOF(struct sockbuf, sb_startzero, sb_endzero));
+#undef RANGEOF
splx(s);
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
(*pr->pr_domain->dom_dispose)(asb.sb_mb);
@@ -1034,10 +1137,13 @@ do_setopt_accept_filter(so, sopt)
int error = 0;
/* do not set/remove accept filters on non listen sockets */
+ SOCK_LOCK(so);
if ((so->so_options & SO_ACCEPTCONN) == 0) {
+ SOCK_UNLOCK(so);
error = EINVAL;
goto out;
}
+ SOCK_UNLOCK(so);
/* removing the filter */
if (sopt == NULL) {
@@ -1052,7 +1158,9 @@ do_setopt_accept_filter(so, sopt)
FREE(af, M_ACCF);
so->so_accf = NULL;
}
+ SOCK_LOCK(so);
so->so_options &= ~SO_ACCEPTFILTER;
+ SOCK_UNLOCK(so);
return (0);
}
/* adding a filter */
@@ -1092,7 +1200,9 @@ do_setopt_accept_filter(so, sopt)
}
af->so_accept_filter = afp;
so->so_accf = af;
+ SOCK_LOCK(so);
so->so_options |= SO_ACCEPTFILTER;
+ SOCK_UNLOCK(so);
out:
if (afap != NULL)
FREE(afap, M_TEMP);
@@ -1164,11 +1274,13 @@ sosetopt(so, sopt)
if (error)
goto bad;
+ SOCK_LOCK(so);
so->so_linger = l.l_linger;
if (l.l_onoff)
so->so_options |= SO_LINGER;
else
so->so_options &= ~SO_LINGER;
+ SOCK_UNLOCK(so);
break;
case SO_DEBUG:
@@ -1184,10 +1296,12 @@ sosetopt(so, sopt)
sizeof optval);
if (error)
goto bad;
+ SOCK_LOCK(so);
if (optval)
so->so_options |= sopt->sopt_name;
else
so->so_options &= ~sopt->sopt_name;
+ SOCK_UNLOCK(so);
break;
case SO_SNDBUF:
@@ -1334,23 +1448,30 @@ sogetopt(so, sopt)
switch (sopt->sopt_name) {
#ifdef INET
case SO_ACCEPTFILTER:
- if ((so->so_options & SO_ACCEPTCONN) == 0)
- return (EINVAL);
MALLOC(afap, struct accept_filter_arg *, sizeof(*afap),
M_TEMP, M_WAITOK | M_ZERO);
+ SOCK_LOCK(so);
+ if ((so->so_options & SO_ACCEPTCONN) == 0) {
+ SOCK_UNLOCK(so);
+ FREE(afap, M_TEMP);
+ return (EINVAL);
+ }
if ((so->so_options & SO_ACCEPTFILTER) != 0) {
strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name);
if (so->so_accf->so_accept_filter_str != NULL)
strcpy(afap->af_arg, so->so_accf->so_accept_filter_str);
}
+ SOCK_UNLOCK(so);
error = sooptcopyout(sopt, afap, sizeof(*afap));
FREE(afap, M_TEMP);
break;
#endif
case SO_LINGER:
+ SOCK_LOCK(so);
l.l_onoff = so->so_options & SO_LINGER;
l.l_linger = so->so_linger;
+ SOCK_UNLOCK(so);
error = sooptcopyout(sopt, &l, sizeof l);
break;
@@ -1363,7 +1484,9 @@ sogetopt(so, sopt)
case SO_BROADCAST:
case SO_OOBINLINE:
case SO_TIMESTAMP:
+ SOCK_LOCK(so);
optval = so->so_options & sopt->sopt_name;
+ SOCK_UNLOCK(so);
integer:
error = sooptcopyout(sopt, &optval, sizeof optval);
break;
@@ -1537,22 +1660,31 @@ sopoll(struct socket *so, int events, struct ucred *cred, struct thread *td)
int revents = 0;
int s = splnet();
- if (events & (POLLIN | POLLRDNORM))
+ if (events & (POLLIN | POLLRDNORM)) {
+ SOCK_LOCK(so);
if (soreadable(so))
revents |= events & (POLLIN | POLLRDNORM);
+ SOCK_UNLOCK(so);
+ }
if (events & POLLINIGNEOF)
if (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat ||
!TAILQ_EMPTY(&so->so_comp) || so->so_error)
revents |= POLLINIGNEOF;
- if (events & (POLLOUT | POLLWRNORM))
+ if (events & (POLLOUT | POLLWRNORM)) {
+ SOCK_LOCK(so);
if (sowriteable(so))
revents |= events & (POLLOUT | POLLWRNORM);
+ SOCK_UNLOCK(so);
+ }
- if (events & (POLLPRI | POLLRDBAND))
+ if (events & (POLLPRI | POLLRDBAND)) {
+ SOCK_LOCK(so);
if (so->so_oobmark || (so->so_state & SS_RCVATMARK))
revents |= events & (POLLPRI | POLLRDBAND);
+ SOCK_UNLOCK(so);
+ }
if (revents == 0) {
if (events &
@@ -1581,10 +1713,12 @@ sokqfilter(struct file *fp, struct knote *kn)
switch (kn->kn_filter) {
case EVFILT_READ:
+ SOCK_LOCK(so);
if (so->so_options & SO_ACCEPTCONN)
kn->kn_fop = &solisten_filtops;
else
kn->kn_fop = &soread_filtops;
+ SOCK_UNLOCK(so);
sb = &so->so_rcv;
break;
case EVFILT_WRITE:
@@ -1621,13 +1755,18 @@ filt_soread(struct knote *kn, long hint)
struct socket *so = (struct socket *)kn->kn_fp->f_data;
kn->kn_data = so->so_rcv.sb_cc;
+ SOCK_LOCK(so);
if (so->so_state & SS_CANTRCVMORE) {
+ SOCK_UNLOCK(so);
kn->kn_flags |= EV_EOF;
kn->kn_fflags = so->so_error;
return (1);
}
- if (so->so_error) /* temporary udp error */
+ if (so->so_error) { /* temporary udp error */
+ SOCK_UNLOCK(so);
return (1);
+ }
+ SOCK_UNLOCK(so);
if (kn->kn_sfflags & NOTE_LOWAT)
return (kn->kn_data >= kn->kn_sdata);
return (kn->kn_data >= so->so_rcv.sb_lowat);
@@ -1652,16 +1791,23 @@ filt_sowrite(struct knote *kn, long hint)
struct socket *so = (struct socket *)kn->kn_fp->f_data;
kn->kn_data = sbspace(&so->so_snd);
+ SOCK_LOCK(so);
if (so->so_state & SS_CANTSENDMORE) {
+ SOCK_UNLOCK(so);
kn->kn_flags |= EV_EOF;
kn->kn_fflags = so->so_error;
return (1);
}
- if (so->so_error) /* temporary udp error */
+ if (so->so_error) { /* temporary udp error */
+ SOCK_UNLOCK(so);
return (1);
+ }
if (((so->so_state & SS_ISCONNECTED) == 0) &&
- (so->so_proto->pr_flags & PR_CONNREQUIRED))
+ (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
+ SOCK_UNLOCK(so);
return (0);
+ }
+ SOCK_UNLOCK(so);
if (kn->kn_sfflags & NOTE_LOWAT)
return (kn->kn_data >= kn->kn_sdata);
return (kn->kn_data >= so->so_snd.sb_lowat);
diff --git a/sys/kern/uipc_socket2.c b/sys/kern/uipc_socket2.c
index 34779f8..c395d87 100644
--- a/sys/kern/uipc_socket2.c
+++ b/sys/kern/uipc_socket2.c
@@ -102,71 +102,56 @@ soisconnecting(so)
register struct socket *so;
{
+ SOCK_ASSERT(so, MA_OWNED);
so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= SS_ISCONNECTING;
}
void
-soisconnected_locked(so)
+soisconnected(so)
struct socket *so;
{
- struct socket *head = so->so_head;
+ struct socket *head;
+ so_upcall_t *upcp;
+ void *upcarg;
+ SOCK_ASSERT(so, MA_OWNED);
+ head = so->so_head;
so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
so->so_state |= SS_ISCONNECTED;
if (head && (so->so_state & SS_INCOMP)) {
if ((so->so_options & SO_ACCEPTFILTER) != 0) {
- so->so_upcall = head->so_accf->so_accept_filter->accf_callback;
- so->so_upcallarg = head->so_accf->so_accept_filter_arg;
+ SOCK_UNLOCK(so);
+ SOCK_LOCK(head);
+ upcp = head->so_accf->so_accept_filter->accf_callback;
+ upcarg = head->so_accf->so_accept_filter_arg;
+ SOCK_UNLOCK(head);
+ SOCK_LOCK(so);
+ so->so_upcall = upcp;
+ so->so_upcallarg = upcarg;
so->so_rcv.sb_flags |= SB_UPCALL;
so->so_options &= ~SO_ACCEPTFILTER;
- so->so_upcall(so, so->so_upcallarg, 0);
+ SOCK_UNLOCK(so);
+ so->so_upcall(so, upcarg, 0);
+ SOCK_LOCK(so);
return;
}
- TAILQ_REMOVE(&head->so_incomp, so, so_list);
- head->so_incqlen--;
so->so_state &= ~SS_INCOMP;
- TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
- head->so_qlen++;
so->so_state |= SS_COMP;
- sorwakeup_locked(head);
- wakeup_one(&head->so_timeo);
- } else {
- wakeup(&so->so_timeo);
- sorwakeup_locked(so);
- sowwakeup_locked(so);
- }
-}
-
-void
-soisconnected(so)
- struct socket *so;
-{
- struct socket *head = so->so_head;
-
- so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
- so->so_state |= SS_ISCONNECTED;
- if (head && (so->so_state & SS_INCOMP)) {
- if ((so->so_options & SO_ACCEPTFILTER) != 0) {
- so->so_upcall = head->so_accf->so_accept_filter->accf_callback;
- so->so_upcallarg = head->so_accf->so_accept_filter_arg;
- so->so_rcv.sb_flags |= SB_UPCALL;
- so->so_options &= ~SO_ACCEPTFILTER;
- so->so_upcall(so, so->so_upcallarg, 0);
- return;
- }
+ SOCK_UNLOCK(so);
+ SOCK_LOCK(head);
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
- so->so_state &= ~SS_INCOMP;
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
head->so_qlen++;
- so->so_state |= SS_COMP;
- sorwakeup_locked(head);
+ sorwakeup(head);
wakeup_one(&head->so_timeo);
+ SOCK_UNLOCK(head);
+ SOCK_LOCK(so);
} else {
wakeup(&so->so_timeo);
- sorwakeup_locked(so);
- sowwakeup_locked(so);
+ sorwakeup(so);
+ sowwakeup(so);
}
}
@@ -175,31 +160,25 @@ soisdisconnecting(so)
register struct socket *so;
{
+ SOCK_ASSERT(so, MA_OWNED);
so->so_state &= ~SS_ISCONNECTING;
so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
wakeup((caddr_t)&so->so_timeo);
- sowwakeup_locked(so);
- sorwakeup_locked(so);
+ sowwakeup(so);
+ sorwakeup(so);
}
void
-soisdisconnected_locked(so)
+soisdisconnected(so)
register struct socket *so;
{
+ SOCK_ASSERT(so, MA_OWNED);
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
wakeup((caddr_t)&so->so_timeo);
- sowwakeup_locked(so);
- sorwakeup_locked(so);
-}
-
-void
-soisdisconnected(so)
- register struct socket *so;
-{
-
- soisdisconnected_locked(so);
+ sowwakeup(so);
+ sorwakeup(so);
}
/*
@@ -224,25 +203,32 @@ sonewconn(head, connstatus)
so = soalloc(0);
if (so == NULL)
return ((struct socket *)0);
+ SOCK_LOCK(head);
if ((head->so_options & SO_ACCEPTFILTER) != 0)
connstatus = 0;
+ SOCK_UNLOCK(head);
so->so_head = head;
so->so_type = head->so_type;
+ SOCK_LOCK(so);
so->so_options = head->so_options &~ SO_ACCEPTCONN;
so->so_linger = head->so_linger;
so->so_state = head->so_state | SS_NOFDREF;
+ SOCK_UNLOCK(so);
so->so_proto = head->so_proto;
so->so_timeo = head->so_timeo;
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)) {
+ SOCK_LOCK(so);
sotryfree(so);
return ((struct socket *)0);
}
if (connstatus) {
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
+ SOCK_LOCK(so);
so->so_state |= SS_COMP;
+ SOCK_UNLOCK(so);
head->so_qlen++;
} else {
if (head->so_incqlen >= head->so_qlimit) {
@@ -251,13 +237,19 @@ sonewconn(head, connstatus)
(void) soabort(sp);
}
TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list);
+ SOCK_LOCK(so);
so->so_state |= SS_INCOMP;
+ SOCK_UNLOCK(so);
head->so_incqlen++;
}
if (connstatus) {
- sorwakeup_locked(head);
+ SOCK_LOCK(head);
+ sorwakeup(head);
wakeup((caddr_t)&head->so_timeo);
+ SOCK_UNLOCK(head);
+ SOCK_LOCK(so);
so->so_state |= connstatus;
+ SOCK_UNLOCK(so);
}
return (so);
}
@@ -277,8 +269,10 @@ socantsendmore(so)
struct socket *so;
{
+ SOCK_LOCK(so);
so->so_state |= SS_CANTSENDMORE;
- sowwakeup_locked(so);
+ sowwakeup(so);
+ SOCK_UNLOCK(so);
}
void
@@ -286,8 +280,10 @@ socantrcvmore(so)
struct socket *so;
{
+ SOCK_LOCK(so);
so->so_state |= SS_CANTRCVMORE;
- sorwakeup_locked(so);
+ sorwakeup(so);
+ SOCK_UNLOCK(so);
}
/*
@@ -336,6 +332,7 @@ sowakeup(so, sb)
register struct socket *so;
register struct sockbuf *sb;
{
+ SOCK_ASSERT(so, MA_OWNED);
selwakeup(&sb->sb_sel);
sb->sb_flags &= ~SB_SEL;
@@ -343,13 +340,23 @@ sowakeup(so, sb)
sb->sb_flags &= ~SB_WAIT;
wakeup((caddr_t)&sb->sb_cc);
}
- if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
+ if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL) {
+ SOCK_UNLOCK(so);
pgsigio(&so->so_sigio, SIGIO, 0);
- if (sb->sb_flags & SB_UPCALL)
+ SOCK_LOCK(so);
+ }
+ if (sb->sb_flags & SB_UPCALL) {
+ SOCK_UNLOCK(so);
(*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT);
- if (sb->sb_flags & SB_AIO)
+ SOCK_LOCK(so);
+ }
+ if (sb->sb_flags & SB_AIO) {
+ SOCK_UNLOCK(so);
aio_swake(so, sb);
+ } else
+ SOCK_UNLOCK(so);
KNOTE(&sb->sb_sel.si_note, 0);
+ SOCK_LOCK(so);
}
/*
@@ -959,9 +966,11 @@ sotoxsocket(struct socket *so, struct xsocket *xso)
xso->xso_len = sizeof *xso;
xso->xso_so = so;
xso->so_type = so->so_type;
+ SOCK_LOCK(so);
xso->so_options = so->so_options;
xso->so_linger = so->so_linger;
xso->so_state = so->so_state;
+ SOCK_UNLOCK(so);
xso->so_pcb = so->so_pcb;
xso->xso_protocol = so->so_proto->pr_protocol;
xso->xso_family = so->so_proto->pr_domain->dom_family;
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index f80dcc9..0c00fe5 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -245,12 +245,15 @@ accept1(td, uap, compat)
if (error)
goto done2;
s = splnet();
+ SOCK_LOCK(head);
if ((head->so_options & SO_ACCEPTCONN) == 0) {
+ SOCK_UNLOCK(head);
splx(s);
error = EINVAL;
goto done;
}
if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) {
+ SOCK_UNLOCK(head);
splx(s);
error = EWOULDBLOCK;
goto done;
@@ -260,13 +263,16 @@ accept1(td, uap, compat)
head->so_error = ECONNABORTED;
break;
}
- error = tsleep((caddr_t)&head->so_timeo, PSOCK | PCATCH,
+ error = msleep((caddr_t)&head->so_timeo,
+ SOCK_MTX(head), PSOCK | PCATCH,
"accept", 0);
if (error) {
+ SOCK_UNLOCK(head);
splx(s);
goto done;
}
}
+ SOCK_UNLOCK(head);
if (head->so_error) {
error = head->so_error;
head->so_error = 0;
@@ -305,13 +311,17 @@ accept1(td, uap, compat)
/* connection has been removed from the listen queue */
KNOTE(&head->so_rcv.sb_sel.si_note, 0);
+ SOCK_LOCK(so);
so->so_state &= ~SS_COMP;
+ SOCK_UNLOCK(so);
so->so_head = NULL;
if (head->so_sigio != NULL)
fsetown(fgetown(head->so_sigio), &so->so_sigio);
FILE_LOCK(nfp);
+ SOCK_LOCK(so);
soref(so); /* file descriptor reference */
+ SOCK_UNLOCK(so);
nfp->f_data = (caddr_t)so; /* nfp has ref count from falloc */
nfp->f_flag = fflag;
nfp->f_ops = &socketops;
@@ -432,24 +442,30 @@ connect(td, uap)
mtx_lock(&Giant);
if ((error = fgetsock(td, uap->s, &so, NULL)) != 0)
goto done2;
+ SOCK_LOCK(so);
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
+ SOCK_UNLOCK(so);
error = EALREADY;
goto done1;
}
+ SOCK_UNLOCK(so);
error = getsockaddr(&sa, uap->name, uap->namelen);
if (error)
goto done1;
error = soconnect(so, sa, td);
if (error)
goto bad;
+ SOCK_LOCK(so);
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
+ SOCK_UNLOCK(so);
FREE(sa, M_SONAME);
error = EINPROGRESS;
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 = msleep((caddr_t)&so->so_timeo,
+ SOCK_MTX(so), PSOCK | PCATCH, "connec", 0);
if (error)
break;
}
@@ -457,9 +473,12 @@ connect(td, uap)
error = so->so_error;
so->so_error = 0;
}
+ SOCK_UNLOCK(so);
splx(s);
bad:
+ SOCK_LOCK(so);
so->so_state &= ~SS_ISCONNECTING;
+ SOCK_UNLOCK(so);
FREE(sa, M_SONAME);
if (error == ERESTART)
error = EINTR;
@@ -1412,10 +1431,13 @@ getpeername1(td, uap, compat)
mtx_lock(&Giant);
if ((error = fgetsock(td, uap->fdes, &so, NULL)) != 0)
goto done2;
+ SOCK_LOCK(so);
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
+ SOCK_UNLOCK(so);
error = ENOTCONN;
goto done1;
}
+ SOCK_UNLOCK(so);
error = copyin((caddr_t)uap->alen, (caddr_t)&len, sizeof (len));
if (error)
goto done1;
@@ -1673,10 +1695,13 @@ sendfile(struct thread *td, struct sendfile_args *uap)
error = EINVAL;
goto done;
}
+ SOCK_LOCK(so);
if ((so->so_state & SS_ISCONNECTED) == 0) {
+ SOCK_UNLOCK(so);
error = ENOTCONN;
goto done;
}
+ SOCK_UNLOCK(so);
if (uap->offset < 0) {
error = EINVAL;
goto done;
@@ -1739,14 +1764,17 @@ retry_lookup:
* Optimize the non-blocking case by looking at the socket space
* before going to the extra work of constituting the sf_buf.
*/
+ SOCK_LOCK(so);
if ((so->so_state & SS_NBIO) && sbspace(&so->so_snd) <= 0) {
if (so->so_state & SS_CANTSENDMORE)
error = EPIPE;
else
error = EAGAIN;
+ SOCK_UNLOCK(so);
sbunlock(&so->so_snd);
goto done;
}
+ SOCK_UNLOCK(so);
/*
* Attempt to look up the page.
*
@@ -1869,6 +1897,7 @@ retry_space:
* blocks before the pru_send (or more accurately, any blocking
* results in a loop back to here to re-check).
*/
+ SOCK_LOCK(so);
if ((so->so_state & SS_CANTSENDMORE) || so->so_error) {
if (so->so_state & SS_CANTSENDMORE) {
error = EPIPE;
@@ -1876,6 +1905,7 @@ retry_space:
error = so->so_error;
so->so_error = 0;
}
+ SOCK_UNLOCK(so);
m_freem(m);
sbunlock(&so->so_snd);
splx(s);
@@ -1888,12 +1918,14 @@ retry_space:
*/
if (sbspace(&so->so_snd) < so->so_snd.sb_lowat) {
if (so->so_state & SS_NBIO) {
+ SOCK_UNLOCK(so);
m_freem(m);
sbunlock(&so->so_snd);
splx(s);
error = EAGAIN;
goto done;
}
+ SOCK_UNLOCK(so);
error = sbwait(&so->so_snd);
/*
* An error from sbwait usually indicates that we've
@@ -1908,6 +1940,7 @@ retry_space:
}
goto retry_space;
}
+ SOCK_UNLOCK(so);
error = (*so->so_proto->pr_usrreqs->pru_send)(so, 0, m, 0, 0, td);
splx(s);
if (error) {
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 04d670c..55e7c45 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -104,6 +104,7 @@ uipc_abort(struct socket *so)
return EINVAL;
unp_drop(unp, ECONNABORTED);
unp_detach(unp);
+ SOCK_LOCK(so);
sotryfree(so);
return 0;
}
@@ -249,7 +250,9 @@ uipc_rcvd(struct socket *so, int flags)
(void)chgsbsize(so2->so_cred->cr_uidinfo, &so2->so_snd.sb_hiwat,
newhiwat, RLIM_INFINITY);
unp->unp_cc = so->so_rcv.sb_cc;
+ SOCK_LOCK(so2);
sowwakeup(so2);
+ SOCK_UNLOCK(so2);
break;
default:
@@ -306,7 +309,9 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
else
from = &sun_noname;
if (sbappendaddr(&so2->so_rcv, from, m, control)) {
+ SOCK_LOCK(so2);
sorwakeup(so2);
+ SOCK_UNLOCK(so2);
m = 0;
control = 0;
} else
@@ -322,7 +327,9 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
* Note: A better implementation would complain
* if not equal to the peer's address.
*/
+ SOCK_LOCK(so);
if ((so->so_state & SS_ISCONNECTED) == 0) {
+ SOCK_UNLOCK(so);
if (nam) {
error = unp_connect(so, nam, td);
if (error)
@@ -334,9 +341,11 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
}
if (so->so_state & SS_CANTSENDMORE) {
+ SOCK_UNLOCK(so);
error = EPIPE;
break;
}
+ SOCK_UNLOCK(so);
if (unp->unp_conn == 0)
panic("uipc_send connected but no connection?");
so2 = unp->unp_conn->unp_socket;
@@ -358,7 +367,9 @@ uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
(void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat,
newhiwat, RLIM_INFINITY);
unp->unp_conn->unp_cc = so2->so_rcv.sb_cc;
+ SOCK_LOCK(so2);
sorwakeup(so2);
+ SOCK_UNLOCK(so2);
m = 0;
break;
@@ -563,7 +574,9 @@ unp_detach(unp)
unp_disconnect(unp);
while (!LIST_EMPTY(&unp->unp_refs))
unp_drop(LIST_FIRST(&unp->unp_refs), ECONNRESET);
+ SOCK_LOCK(unp->unp_socket);
soisdisconnected(unp->unp_socket);
+ SOCK_UNLOCK(unp->unp_socket);
unp->unp_socket->so_pcb = 0;
if (unp_rights) {
/*
@@ -697,8 +710,14 @@ unp_connect(so, nam, td)
goto bad;
}
if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
- if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
- (so3 = sonewconn(so2, 0)) == 0) {
+ SOCK_LOCK(so2);
+ if ((so2->so_options & SO_ACCEPTCONN) == 0) {
+ SOCK_UNLOCK(so2);
+ error = ECONNREFUSED;
+ goto bad;
+ }
+ SOCK_UNLOCK(so2);
+ if ((so3 = sonewconn(so2, 0)) == 0) {
error = ECONNREFUSED;
goto bad;
}
@@ -756,13 +775,19 @@ unp_connect2(so, so2)
case SOCK_DGRAM:
LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink);
+ SOCK_LOCK(so);
soisconnected(so);
+ SOCK_UNLOCK(so);
break;
case SOCK_STREAM:
unp2->unp_conn = unp;
+ SOCK_LOCK(so);
soisconnected(so);
+ SOCK_UNLOCK(so);
+ SOCK_LOCK(so2);
soisconnected(so2);
+ SOCK_UNLOCK(so2);
break;
default:
@@ -784,13 +809,19 @@ unp_disconnect(unp)
case SOCK_DGRAM:
LIST_REMOVE(unp, unp_reflink);
+ SOCK_LOCK(unp->unp_socket);
unp->unp_socket->so_state &= ~SS_ISCONNECTED;
+ SOCK_UNLOCK(unp->unp_socket);
break;
case SOCK_STREAM:
+ SOCK_LOCK(unp->unp_socket);
soisdisconnected(unp->unp_socket);
+ SOCK_UNLOCK(unp->unp_socket);
+ SOCK_LOCK(unp2->unp_socket);
unp2->unp_conn = 0;
soisdisconnected(unp2->unp_socket);
+ SOCK_UNLOCK(unp2->unp_socket);
break;
}
}
diff --git a/sys/kern/vfs_aio.c b/sys/kern/vfs_aio.c
index 499d4b7..3e1fe8e 100644
--- a/sys/kern/vfs_aio.c
+++ b/sys/kern/vfs_aio.c
@@ -1440,8 +1440,10 @@ no_kqueue:
*/
so = (struct socket *)fp->f_data;
s = splnet();
+ SOCK_LOCK(so);
if (((opcode == LIO_READ) && (!soreadable(so))) || ((opcode ==
LIO_WRITE) && (!sowriteable(so)))) {
+ SOCK_UNLOCK(so);
TAILQ_INSERT_TAIL(&so->so_aiojobq, aiocbe, list);
TAILQ_INSERT_TAIL(&ki->kaio_sockqueue, aiocbe, plist);
if (opcode == LIO_READ)
@@ -1455,6 +1457,7 @@ no_kqueue:
error = 0;
goto done;
}
+ SOCK_UNLOCK(so);
splx(s);
}
OpenPOWER on IntegriCloud