diff options
author | tanimura <tanimura@FreeBSD.org> | 2002-05-20 05:41:09 +0000 |
---|---|---|
committer | tanimura <tanimura@FreeBSD.org> | 2002-05-20 05:41:09 +0000 |
commit | 92d8381dd544a8237b3fd68c4e7fce9bd0903fb2 (patch) | |
tree | 2465ddbcecac65f96c5c6d5cef1a4fe3f1ac03f8 /sys/kern | |
parent | 969293170b27461145f69a538d5abd15fea34ba1 (diff) | |
download | FreeBSD-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.c | 7 | ||||
-rw-r--r-- | sys/kern/sys_socket.c | 8 | ||||
-rw-r--r-- | sys/kern/uipc_domain.c | 8 | ||||
-rw-r--r-- | sys/kern/uipc_sockbuf.c | 127 | ||||
-rw-r--r-- | sys/kern/uipc_socket.c | 208 | ||||
-rw-r--r-- | sys/kern/uipc_socket2.c | 127 | ||||
-rw-r--r-- | sys/kern/uipc_syscalls.c | 37 | ||||
-rw-r--r-- | sys/kern/uipc_usrreq.c | 35 | ||||
-rw-r--r-- | sys/kern/vfs_aio.c | 3 |
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); } |