PERFORCE change 40701 for review
Sam Leffler
sam at FreeBSD.org
Tue Oct 28 16:32:44 PST 2003
http://perforce.freebsd.org/chv.cgi?CH=40701
Change 40701 by sam at sam_ebb on 2003/10/28 16:32:15
checkpoint: multiuser and ping works; tcp locks up; a
couple of LOR's to deal with
Affected files ...
.. //depot/projects/netperf+sockets/sys/kern/sys_socket.c#2 edit
.. //depot/projects/netperf+sockets/sys/kern/uipc_socket.c#2 edit
.. //depot/projects/netperf+sockets/sys/kern/uipc_socket2.c#2 edit
.. //depot/projects/netperf+sockets/sys/kern/uipc_syscalls.c#2 edit
.. //depot/projects/netperf+sockets/sys/kern/uipc_usrreq.c#2 edit
.. //depot/projects/netperf+sockets/sys/kern/vfs_aio.c#3 edit
.. //depot/projects/netperf+sockets/sys/net/raw_usrreq.c#2 edit
.. //depot/projects/netperf+sockets/sys/netatalk/ddp_usrreq.c#2 edit
.. //depot/projects/netperf+sockets/sys/netinet6/in6_proto.c#2 edit
.. //depot/projects/netperf+sockets/sys/netinet6/in6_rmx.c#2 edit
.. //depot/projects/netperf+sockets/sys/netipx/ipx_pcb.c#2 edit
.. //depot/projects/netperf+sockets/sys/netipx/spx_usrreq.c#2 edit
.. //depot/projects/netperf+sockets/sys/netnatm/natm.c#2 edit
.. //depot/projects/netperf+sockets/sys/netsmb/smb_conn.c#2 edit
.. //depot/projects/netperf+sockets/sys/netsmb/smb_trantcp.c#2 edit
.. //depot/projects/netperf+sockets/sys/nfsclient/nfs_vfsops.c#2 edit
.. //depot/projects/netperf+sockets/sys/nfsserver/nfs_srvcache.c#2 edit
.. //depot/projects/netperf+sockets/sys/sys/socketvar.h#2 edit
.. //depot/projects/netperf+sockets/sys/sys/unpcb.h#2 edit
Differences ...
==== //depot/projects/netperf+sockets/sys/kern/sys_socket.c#2 (text+ko) ====
@@ -77,19 +77,12 @@
int flags;
{
struct socket *so = fp->f_data;
- int error;
-
- mtx_lock(&Giant);
#ifdef MAC
- error = mac_check_socket_receive(active_cred, so);
- if (error) {
- mtx_unlock(&Giant);
+ int error = mac_check_socket_receive(active_cred, so);
+ if (error)
return (error);
- }
#endif
- error = so->so_proto->pr_usrreqs->pru_soreceive(so, 0, uio, 0, 0, 0);
- mtx_unlock(&Giant);
- return (error);
+ return (so->so_proto->pr_usrreqs->pru_soreceive(so, 0, uio, 0, 0, 0));
}
/* ARGSUSED */
@@ -102,20 +95,13 @@
int flags;
{
struct socket *so = fp->f_data;
- int error;
-
- mtx_lock(&Giant);
#ifdef MAC
- error = mac_check_socket_send(active_cred, so);
- if (error) {
- mtx_unlock(&Giant);
+ int error = mac_check_socket_send(active_cred, so);
+ if (error)
return (error);
- }
#endif
- error = so->so_proto->pr_usrreqs->pru_sosend(so, 0, uio, 0, 0, 0,
- uio->uio_td);
- mtx_unlock(&Giant);
- return (error);
+ return (so->so_proto->pr_usrreqs->pru_sosend(so, 0, uio, 0, 0, 0,
+ uio->uio_td));
}
int
==== //depot/projects/netperf+sockets/sys/kern/uipc_socket.c#2 (text+ko) ====
@@ -128,21 +128,14 @@
* soalloc() returns a socket with a ref count of 0.
*/
struct socket *
-soalloc(waitok)
- int waitok;
+soalloc(int mflags)
{
struct socket *so;
#ifdef MAC
int error;
#endif
- int flag;
- if (waitok == 1)
- flag = M_WAITOK;
- else
- flag = M_NOWAIT;
- flag |= M_ZERO;
- so = uma_zalloc(socket_zone, flag);
+ so = uma_zalloc(socket_zone, mflags | M_ZERO);
if (so) {
#ifdef MAC
error = mac_init_socket(so, flag);
@@ -152,6 +145,8 @@
return so;
}
#endif
+ SOCKBUF_LOCK_INIT(&so->so_snd, "so_snd");
+ SOCKBUF_LOCK_INIT(&so->so_rcv, "so_rcv");
/* XXX race condition for reentrant kernel */
so->so_gencnt = ++so_gencnt;
/* sx_init(&so->so_sxlock, "socket sxlock"); */
@@ -195,7 +190,7 @@
if (prp->pr_type != type)
return (EPROTOTYPE);
- so = soalloc(1);
+ so = soalloc(M_WAITOK);
if (so == NULL)
return (ENOBUFS);
@@ -210,6 +205,7 @@
soref(so);
error = (*prp->pr_usrreqs->pru_attach)(so, proto, td);
if (error) {
+ SOCK_LOCK(so);
so->so_state |= SS_NOFDREF;
sorele(so);
return (error);
@@ -253,6 +249,8 @@
mac_destroy_socket(so);
#endif
crfree(so->so_cred);
+ SOCKBUF_LOCK_DESTROY(&so->so_snd);
+ SOCKBUF_LOCK_DESTROY(&so->so_rcv);
/* sx_destroy(&so->so_sxlock); */
uma_zfree(socket_zone, so);
--numopensockets;
@@ -277,11 +275,13 @@
splx(s);
return (error);
}
+ SOCKBUF_LOCK(&so->so_rcv);
if (TAILQ_EMPTY(&so->so_comp))
so->so_options |= SO_ACCEPTCONN;
if (backlog < 0 || backlog > somaxconn)
backlog = somaxconn;
so->so_qlimit = backlog;
+ SOCKBUF_UNLOCK(&so->so_rcv);
splx(s);
return (0);
}
@@ -290,13 +290,16 @@
sofree(so)
struct socket *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)
+ if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) {
+ SOCK_UNLOCK(so);
return;
- if (head != NULL) {
+ }
+ SOCK_UNLOCK(so);
+ SOCKBUF_LOCK(&so->so_rcv);
+ if (so->so_head != NULL) {
+ struct socket *head = so->so_head;
if (so->so_state & SS_INCOMP) {
TAILQ_REMOVE(&head->so_incomp, so, so_list);
head->so_incqlen--;
@@ -307,6 +310,7 @@
* accept(2) may hang after select(2) indicated
* that the listening socket was ready.
*/
+ /* XXX SOCKBUF_UNLOCK(&so->so_rcv); */
return;
} else {
panic("sofree: not queued");
@@ -314,7 +318,10 @@
so->so_state &= ~SS_INCOMP;
so->so_head = NULL;
}
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ SOCKBUF_LOCK(&so->so_snd);
sbrelease(&so->so_snd, so);
+ SOCKBUF_UNLOCK(&so->so_snd);
sorflush(so);
sodealloc(so);
}
@@ -354,11 +361,14 @@
(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) {
+ SOCK_UNLOCK(so);
error = sodisconnect(so);
+ SOCK_LOCK(so);
if (error)
goto drop;
}
@@ -376,7 +386,10 @@
}
drop:
if (so->so_pcb) {
- int error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so);
+ int error2;
+ SOCK_UNLOCK(so);
+ error2 = (*so->so_proto->pr_usrreqs->pru_detach)(so);
+ SOCK_LOCK(so);
if (error == 0)
error = error2;
}
@@ -411,14 +424,12 @@
struct socket *so;
struct sockaddr **nam;
{
- int s = splnet();
int error;
if ((so->so_state & SS_NOFDREF) == 0)
panic("soaccept: !NOFDREF");
so->so_state &= ~SS_NOFDREF;
error = (*so->so_proto->pr_usrreqs->pru_accept)(so, nam);
- splx(s);
return (error);
}
@@ -428,12 +439,10 @@
struct sockaddr *nam;
struct thread *td;
{
- int s;
int error;
if (so->so_options & SO_ACCEPTCONN)
return (EOPNOTSUPP);
- s = splnet();
/*
* If protocol is connection-based, can only connect once.
* Otherwise, if connected, try to disconnect first.
@@ -446,7 +455,6 @@
error = EISCONN;
else
error = (*so->so_proto->pr_usrreqs->pru_connect)(so, nam, td);
- splx(s);
return (error);
}
@@ -455,11 +463,9 @@
struct socket *so1;
struct socket *so2;
{
- int s = splnet();
int error;
error = (*so1->so_proto->pr_usrreqs->pru_connect2)(so1, so2);
- splx(s);
return (error);
}
@@ -467,20 +473,13 @@
sodisconnect(so)
struct socket *so;
{
- int s = splnet();
int error;
- if ((so->so_state & SS_ISCONNECTED) == 0) {
- error = ENOTCONN;
- goto bad;
- }
- if (so->so_state & SS_ISDISCONNECTING) {
- error = EALREADY;
- goto bad;
- }
+ if ((so->so_state & SS_ISCONNECTED) == 0)
+ return ENOTCONN;
+ if (so->so_state & SS_ISDISCONNECTING)
+ return EALREADY;
error = (*so->so_proto->pr_usrreqs->pru_disconnect)(so);
-bad:
- splx(s);
return (error);
}
@@ -565,7 +564,7 @@
clen = control->m_len;
#define snderr(errno) { error = (errno); splx(s); goto release; }
-restart:
+ SOCKBUF_LOCK(&so->so_snd);
error = sblock(&so->so_snd, SBLOCKWAIT(flags));
if (error)
goto out;
@@ -605,12 +604,11 @@
(atomic || space < so->so_snd.sb_lowat || space < clen)) {
if (so->so_state & SS_NBIO)
snderr(EWOULDBLOCK);
- sbunlock(&so->so_snd);
error = sbwait(&so->so_snd);
splx(s);
if (error)
- goto out;
- goto restart;
+ goto release;
+ continue;
}
splx(s);
mp = ⊤
@@ -627,10 +625,12 @@
#ifdef ZERO_COPY_SOCKETS
cow_send = 0;
#endif /* ZERO_COPY_SOCKETS */
+ SOCKBUF_UNLOCK(&so->so_snd);
if (top == 0) {
MGETHDR(m, M_TRYWAIT, MT_DATA);
if (m == NULL) {
error = ENOBUFS;
+ SOCKBUF_LOCK(&so->so_snd); /* XXX */
goto release;
}
mlen = MHLEN;
@@ -640,6 +640,7 @@
MGET(m, M_TRYWAIT, MT_DATA);
if (m == NULL) {
error = ENOBUFS;
+ SOCKBUF_LOCK(&so->so_snd); /* XXX */
goto release;
}
mlen = MLEN;
@@ -687,6 +688,7 @@
else
#endif /* ZERO_COPY_SOCKETS */
error = uiomove(mtod(m, void *), (int)len, uio);
+ SOCKBUF_LOCK(&so->so_snd);
resid = uio->uio_resid;
m->m_len = len;
*mp = m;
@@ -741,6 +743,7 @@
release:
sbunlock(&so->so_snd);
out:
+ SOCKBUF_UNLOCK(&so->so_snd);
if (top)
m_freem(top);
if (control)
@@ -832,12 +835,13 @@
if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
(*pr->pr_usrreqs->pru_rcvd)(so, 0);
-restart:
+ SOCKBUF_LOCK(&so->so_rcv);
error = sblock(&so->so_rcv, SBLOCKWAIT(flags));
if (error)
- return (error);
+ goto out;
s = splnet();
+restart:
m = so->so_rcv.sb_mb;
/*
* If we have less data than requested, block awaiting more
@@ -855,9 +859,8 @@
(so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) {
- KASSERT(m != 0 || !so->so_rcv.sb_cc,
- ("receive: m == %p so->so_rcv.sb_cc == %u",
- m, so->so_rcv.sb_cc));
+ KASSERT(!(m == 0 && so->so_rcv.sb_cc),
+ ("m %p so->so_rcv.sb_cc %u", m, so->so_rcv.sb_cc));
if (so->so_error) {
if (m)
goto dontblock;
@@ -890,11 +893,10 @@
}
SBLASTRECORDCHK(&so->so_rcv);
SBLASTMBUFCHK(&so->so_rcv);
- sbunlock(&so->so_rcv);
error = sbwait(&so->so_rcv);
splx(s);
if (error)
- return (error);
+ goto out;
goto restart;
}
dontblock:
@@ -908,8 +910,8 @@
("m->m_type == %d", m->m_type));
orig_resid = 0;
if (psa)
- *psa = dup_sockaddr(mtod(m, struct sockaddr *),
- mp0 == 0);
+ *psa = sodupsockaddr(mtod(m, struct sockaddr *),
+ M_NOWAIT); /* XXX */
if (flags & MSG_PEEK) {
m = m->m_next;
} else {
@@ -998,6 +1000,7 @@
SBLASTRECORDCHK(&so->so_rcv);
SBLASTMBUFCHK(&so->so_rcv);
splx(s);
+ SOCKBUF_UNLOCK(&so->so_rcv);
#ifdef ZERO_COPY_SOCKETS
if (so_zero_copy_receive) {
vm_page_t pg;
@@ -1021,6 +1024,7 @@
} else
#endif /* ZERO_COPY_SOCKETS */
error = uiomove(mtod(m, char *) + moff, (int)len, uio);
+ SOCKBUF_LOCK(&so->so_rcv);
s = splnet();
if (error)
goto release;
@@ -1102,9 +1106,8 @@
SBLASTMBUFCHK(&so->so_rcv);
error = sbwait(&so->so_rcv);
if (error) {
- sbunlock(&so->so_rcv);
- splx(s);
- return (0);
+ error = 0;
+ goto release;
}
m = so->so_rcv.sb_mb;
if (m)
@@ -1148,6 +1151,8 @@
release:
sbunlock(&so->so_rcv);
splx(s);
+out:
+ SOCKBUF_UNLOCK(&so->so_rcv);
return (error);
}
@@ -1174,22 +1179,21 @@
{
struct sockbuf *sb = &so->so_rcv;
struct protosw *pr = so->so_proto;
- int s;
struct sockbuf asb;
+ SOCKBUF_LOCK(sb);
sb->sb_flags |= SB_NOINTR;
(void) sblock(sb, M_WAITOK);
- s = splimp();
- socantrcvmore(so);
+ socantrcvmore_locked(so);
sbunlock(sb);
asb = *sb;
/*
- * Invalidate/clear most of the sockbuf structure, but keep
- * its selinfo structure valid.
+ * Invalidate/clear most of the sockbuf structure, but leave
+ * selinfo and mutex data unchanged.
*/
bzero(&sb->sb_startzero,
sizeof(*sb) - offsetof(struct sockbuf, sb_startzero));
- splx(s);
+ SOCKBUF_UNLOCK(sb);
if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
(*pr->pr_domain->dom_dispose)(asb.sb_mb);
@@ -1207,6 +1211,7 @@
struct so_accf *af = so->so_accf;
int error = 0;
+/* XXX locking */
/* do not set/remove accept filters on non listen sockets */
if ((so->so_options & SO_ACCEPTCONN) == 0) {
error = EINVAL;
@@ -1794,7 +1799,6 @@
{
struct socket *so = kn->kn_fp->f_data;
struct sockbuf *sb;
- int s;
switch (kn->kn_filter) {
case EVFILT_READ:
@@ -1812,10 +1816,10 @@
return (1);
}
- s = splnet();
+ SOCKBUF_LOCK(sb);
SLIST_INSERT_HEAD(&sb->sb_sel.si_note, kn, kn_selnext);
sb->sb_flags |= SB_KNOTE;
- splx(s);
+ SOCKBUF_UNLOCK(sb);
return (0);
}
@@ -1823,12 +1827,12 @@
filt_sordetach(struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
- int s = splnet();
+ SOCKBUF_LOCK(&so->so_rcv);
SLIST_REMOVE(&so->so_rcv.sb_sel.si_note, kn, knote, kn_selnext);
if (SLIST_EMPTY(&so->so_rcv.sb_sel.si_note))
so->so_rcv.sb_flags &= ~SB_KNOTE;
- splx(s);
+ SOCKBUF_UNLOCK(&so->so_rcv);
}
/*ARGSUSED*/
@@ -1836,30 +1840,35 @@
filt_soread(struct knote *kn, long hint)
{
struct socket *so = kn->kn_fp->f_data;
+ int result;
+ SOCKBUF_LOCK(&so->so_rcv); /* XXX too conservative? */
kn->kn_data = so->so_rcv.sb_cc - so->so_rcv.sb_ctl;
if (so->so_state & SS_CANTRCVMORE) {
kn->kn_flags |= EV_EOF;
kn->kn_fflags = so->so_error;
- return (1);
+ result = 1;
+ } else if (so->so_error) { /* temporary udp error */
+ result = 1;
+ } else if (kn->kn_sfflags & NOTE_LOWAT) {
+ result = (kn->kn_data >= kn->kn_sdata);
+ } else {
+ result = (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat);
}
- if (so->so_error) /* temporary udp error */
- return (1);
- if (kn->kn_sfflags & NOTE_LOWAT)
- return (kn->kn_data >= kn->kn_sdata);
- return (so->so_rcv.sb_cc >= so->so_rcv.sb_lowat);
+ SOCKBUF_UNLOCK(&so->so_rcv);
+ return (result);
}
static void
filt_sowdetach(struct knote *kn)
{
struct socket *so = kn->kn_fp->f_data;
- int s = splnet();
+ SOCKBUF_LOCK(&so->so_snd);
SLIST_REMOVE(&so->so_snd.sb_sel.si_note, kn, knote, kn_selnext);
if (SLIST_EMPTY(&so->so_snd.sb_sel.si_note))
so->so_snd.sb_flags &= ~SB_KNOTE;
- splx(s);
+ SOCKBUF_UNLOCK(&so->so_snd);
}
/*ARGSUSED*/
@@ -1867,21 +1876,26 @@
filt_sowrite(struct knote *kn, long hint)
{
struct socket *so = kn->kn_fp->f_data;
+ int result;
+ SOCKBUF_LOCK(&so->so_snd); /* XXX too conservative? */
kn->kn_data = sbspace(&so->so_snd);
if (so->so_state & SS_CANTSENDMORE) {
kn->kn_flags |= EV_EOF;
kn->kn_fflags = so->so_error;
- return (1);
+ result = 1;
+ } else if (so->so_error) { /* temporary udp error */
+ result = 1;
+ } else if (((so->so_state & SS_ISCONNECTED) == 0) &&
+ (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
+ result = 0;
+ } else if (kn->kn_sfflags & NOTE_LOWAT) {
+ result = (kn->kn_data >= kn->kn_sdata);
+ } else {
+ result = (kn->kn_data >= so->so_snd.sb_lowat);
}
- if (so->so_error) /* temporary udp error */
- return (1);
- if (((so->so_state & SS_ISCONNECTED) == 0) &&
- (so->so_proto->pr_flags & PR_CONNREQUIRED))
- return (0);
- if (kn->kn_sfflags & NOTE_LOWAT)
- return (kn->kn_data >= kn->kn_sdata);
- return (kn->kn_data >= so->so_snd.sb_lowat);
+ SOCKBUF_UNLOCK(&so->so_snd);
+ return (result);
}
/*ARGSUSED*/
==== //depot/projects/netperf+sockets/sys/kern/uipc_socket2.c#2 (text+ko) ====
@@ -108,9 +108,14 @@
soisconnecting(so)
register struct socket *so;
{
+ int need_lock = !SOCK_OWNED(so);
+ if (need_lock)
+ SOCK_LOCK(so);
so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= SS_ISCONNECTING;
+ if (need_lock)
+ SOCK_UNLOCK(so);
}
void
@@ -118,56 +123,79 @@
struct socket *so;
{
struct socket *head = so->so_head;
+ int need_lock = !SOCK_OWNED(so);
+ if (need_lock)
+ SOCK_LOCK(so);
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) {
+ if ((so->so_options & SO_ACCEPTFILTER) == 0) {
+ if (need_lock)
+ 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);
+ wakeup_one(&head->so_timeo);
+ SOCK_UNLOCK(head);
+ } else {
+/* XXX locking */
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, M_TRYWAIT);
- 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(head);
- wakeup_one(&head->so_timeo);
} else {
wakeup(&so->so_timeo);
+ SOCK_UNLOCK(so);
sorwakeup(so);
sowwakeup(so);
}
+ if (!need_lock)
+ SOCK_LOCK(so);
}
void
soisdisconnecting(so)
register struct socket *so;
{
+ int need_lock = !SOCK_OWNED(so);
+ if (need_lock)
+ SOCK_LOCK(so);
so->so_state &= ~SS_ISCONNECTING;
so->so_state |= (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE);
wakeup(&so->so_timeo);
+ SOCK_UNLOCK(so);
sowwakeup(so);
sorwakeup(so);
+ if (!need_lock)
+ SOCK_LOCK(so);
}
void
soisdisconnected(so)
register struct socket *so;
{
+ int need_lock = !SOCK_OWNED(so);
+ if (need_lock)
+ SOCK_LOCK(so);
so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
wakeup(&so->so_timeo);
+ SOCK_UNLOCK(so);
sbdrop(&so->so_snd, so->so_snd.sb_cc);
sowwakeup(so);
sorwakeup(so);
+ if (!need_lock)
+ SOCK_LOCK(so);
}
/*
@@ -186,10 +214,14 @@
int connstatus;
{
register struct socket *so;
+ int over;
- if (head->so_qlen > 3 * head->so_qlimit / 2)
+ SOCK_LOCK(head);
+ over = (head->so_qlen > 3 * head->so_qlimit / 2);
+ SOCK_UNLOCK(head);
+ if (over)
return ((struct socket *)0);
- so = soalloc(0);
+ so = soalloc(M_NOWAIT);
if (so == NULL)
return ((struct socket *)0);
if ((head->so_options & SO_ACCEPTFILTER) != 0)
@@ -205,12 +237,13 @@
#ifdef MAC
mac_create_socket_from_socket(head, so);
#endif
+
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);
return ((struct socket *)0);
}
-
+ SOCKBUF_LOCK(&head->so_rcv);
if (connstatus) {
TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
so->so_state |= SS_COMP;
@@ -225,10 +258,11 @@
so->so_state |= SS_INCOMP;
head->so_incqlen++;
}
+ SOCKBUF_UNLOCK(&head->so_rcv);
if (connstatus) {
+ so->so_state |= connstatus;
sorwakeup(head);
wakeup(&head->so_timeo);
- so->so_state |= connstatus;
}
return (so);
}
@@ -253,6 +287,16 @@
}
void
+socantsendmore_locked(so)
+ struct socket *so;
+{
+ SOCKBUF_LOCK_ASSERT(&so->so_snd);
+
+ so->so_state |= SS_CANTSENDMORE;
+ sowwakeup(so);
+}
+
+void
socantrcvmore(so)
struct socket *so;
{
@@ -261,6 +305,16 @@
sorwakeup(so);
}
+void
+socantrcvmore_locked(so)
+ struct socket *so;
+{
+ SOCKBUF_LOCK_ASSERT(&so->so_rcv);
+
+ so->so_state |= SS_CANTRCVMORE;
+ sorwakeup_locked(so);
+}
+
/*
* Wait for data to arrive at/drain from a socket buffer.
*/
@@ -268,9 +322,10 @@
sbwait(sb)
struct sockbuf *sb;
{
+ SOCKBUF_LOCK_ASSERT(sb);
sb->sb_flags |= SB_WAIT;
- return (tsleep(&sb->sb_cc,
+ return (msleep(&sb->sb_cc, &sb->sb_mtx,
(sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait",
sb->sb_timeo));
}
@@ -285,9 +340,11 @@
{
int error;
+ SOCKBUF_LOCK_ASSERT(sb);
+
while (sb->sb_flags & SB_LOCK) {
sb->sb_flags |= SB_WANT;
- error = tsleep(&sb->sb_flags,
+ error = msleep(&sb->sb_flags, &sb->sb_mtx,
(sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK|PCATCH,
"sblock", 0);
if (error)
@@ -298,29 +355,71 @@
}
/*
+ * The part of sowakeup that must be done while
+ * holding the sockbuf lock.
+ */
+static __inline void
+sowakeup_under_lock(struct socket *so, struct sockbuf *sb)
+{
+ SOCKBUF_LOCK_ASSERT(sb);
+
+ selwakeup(&sb->sb_sel);
+ sb->sb_flags &= ~SB_SEL;
+ if (sb->sb_flags & SB_WAIT) {
+ sb->sb_flags &= ~SB_WAIT;
+ wakeup(&sb->sb_cc);
+ }
+}
+
+/*
* Wakeup processes waiting on a socket buffer.
* Do asynchronous notification via SIGIO
* if the socket has the SS_ASYNC flag set.
+ *
+ * The caller is assumed to hold the necessary
+ * sockbuf lock.
*/
void
+sowakeup_locked(so, sb)
+ register struct socket *so;
+ register struct sockbuf *sb;
+{
+
+ sowakeup_under_lock(so, sb);
+
+ if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
+ pgsigio(&so->so_sigio, SIGIO, 0);
+ if (sb->sb_flags & SB_UPCALL)
+ (*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT);
+ if (sb->sb_flags & SB_AIO) /* XXX locking */
+ aio_swake(so, sb);
+ KNOTE(&sb->sb_sel.si_note, 0); /* XXX locking? */
+}
+
+/*
+ * Wakeup processes waiting on a socket buffer.
+ * Do asynchronous notification via SIGIO
+ * if the socket has the SS_ASYNC flag set.
+ *
+ * The caller does not hold the sockbuf lock.
+ */
+void
sowakeup(so, sb)
register struct socket *so;
register struct sockbuf *sb;
{
- selwakeup(&sb->sb_sel);
- sb->sb_flags &= ~SB_SEL;
- if (sb->sb_flags & SB_WAIT) {
- sb->sb_flags &= ~SB_WAIT;
- wakeup(&sb->sb_cc);
- }
+ SOCKBUF_LOCK(sb);
+ sowakeup_under_lock(so, sb);
+ SOCKBUF_UNLOCK(sb);
+
if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
pgsigio(&so->so_sigio, SIGIO, 0);
if (sb->sb_flags & SB_UPCALL)
(*so->so_upcall)(so, so->so_upcallarg, M_DONTWAIT);
- if (sb->sb_flags & SB_AIO)
+ if (sb->sb_flags & SB_AIO) /* XXX locking */
aio_swake(so, sb);
- KNOTE(&sb->sb_sel.si_note, 0);
+ KNOTE(&sb->sb_sel.si_note, 0); /* XXX locking? */
}
/*
@@ -474,6 +573,8 @@
{
struct mbuf *m = sb->sb_mb;
+ SOCKBUF_LOCK_ASSERT(sb);
+
while (m && m->m_nextpkt)
m = m->m_nextpkt;
@@ -493,6 +594,8 @@
struct mbuf *m = sb->sb_mb;
struct mbuf *n;
+ SOCKBUF_LOCK_ASSERT(sb);
+
while (m && m->m_nextpkt)
m = m->m_nextpkt;
@@ -529,7 +632,7 @@
* discarded and mbufs are compacted where possible.
*/
void
-sbappend(sb, m)
+sbappend_locked(sb, m)
struct sockbuf *sb;
struct mbuf *m;
{
@@ -537,6 +640,9 @@
if (m == 0)
return;
+
+ SOCKBUF_LOCK_ASSERT(sb);
+
SBLASTRECORDCHK(sb);
n = sb->sb_mb;
if (n) {
@@ -544,7 +650,7 @@
n = n->m_nextpkt;
do {
if (n->m_flags & M_EOR) {
- sbappendrecord(sb, m); /* XXXXXX!!!! */
+ sbappendrecord_locked(sb, m); /* XXXXXX!!!! */
return;
}
} while (n->m_next && (n = n->m_next));
@@ -557,7 +663,7 @@
if ((n = sb->sb_lastrecord) != NULL) {
do {
if (n->m_flags & M_EOR) {
- sbappendrecord(sb, m); /* XXXXXX!!!! */
+ sbappendrecord_locked(sb, m); /* XXXXXX!!!! */
return;
}
} while (n->m_next && (n = n->m_next));
@@ -574,13 +680,33 @@
}
/*
+ * Append mbuf chain m to the last record in the
+ * socket buffer sb. The additional space associated
+ * the mbuf chain is recorded in sb. Empty mbufs are
+ * discarded and mbufs are compacted where possible.
+ */
+void
+sbappend(sb, m)
+ struct sockbuf *sb;
+ struct mbuf *m;
+{
+ if (!SOCKBUF_OWNED(sb)) {
+ SOCKBUF_LOCK(sb);
+ sbappend_locked(sb, m);
+ SOCKBUF_UNLOCK(sb);
+ } else
+ sbappend_locked(sb, m);
+}
+
+/*
* This version of sbappend() should only be used when the caller
* absolutely knows that there will never be more than one record
* in the socket buffer, that is, a stream protocol (such as TCP).
*/
void
-sbappendstream(struct sockbuf *sb, struct mbuf *m)
+sbappendstream_locked(struct sockbuf *sb, struct mbuf *m)
{
+ SOCKBUF_LOCK_ASSERT(sb);
KASSERT(m->m_nextpkt == NULL,("sbappendstream 0"));
KASSERT(sb->sb_mb == sb->sb_lastrecord,("sbappendstream 1"));
@@ -590,13 +716,28 @@
#ifdef MBUFTRACE
m_claim(m, sb->sb_mowner);
#endif
-
sbcompress(sb, m, sb->sb_mbtail);
sb->sb_lastrecord = sb->sb_mb;
SBLASTRECORDCHK(sb);
}
+/*
+ * This version of sbappend() should only be used when the caller
+ * absolutely knows that there will never be more than one record
+ * in the socket buffer, that is, a stream protocol (such as TCP).
+ */
+void
+sbappendstream(struct sockbuf *sb, struct mbuf *m)
+{
+ if (!SOCKBUF_OWNED(sb)) {
+ SOCKBUF_LOCK(sb);
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list