diff options
author | rwatson <rwatson@FreeBSD.org> | 2008-01-31 08:22:24 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2008-01-31 08:22:24 +0000 |
commit | c57fa547596c416598879f29dc61157e959392bd (patch) | |
tree | a5b509ba53675bf270380aa0f227cfd9b595f023 /sys/netinet | |
parent | e57ce2b6e66969617ddf24cf15e2a24e11871b15 (diff) | |
download | FreeBSD-src-c57fa547596c416598879f29dc61157e959392bd.zip FreeBSD-src-c57fa547596c416598879f29dc61157e959392bd.tar.gz |
Correct two problems relating to sorflush(), which is called to flush
read socket buffers in shutdown() and close():
- Call socantrcvmore() before sblock() to dislodge any threads that
might be sleeping (potentially indefinitely) while holding sblock(),
such as a thread blocked in recv().
- Flag the sblock() call as non-interruptible so that a signal
delivered to the thread calling sorflush() doesn't cause sblock() to
fail. The sblock() is required to ensure that all other socket
consumer threads have, in fact, left, and do not enter, the socket
buffer until we're done flushin it.
To implement the latter, change the 'flags' argument to sblock() to
accept two flags, SBL_WAIT and SBL_NOINTR, rather than one M_WAITOK
flag. When SBL_NOINTR is set, it forces a non-interruptible sx
acquisition, regardless of the setting of the disposition of SB_NOINTR
on the socket buffer; without this change it would be possible for
another thread to clear SB_NOINTR between when the socket buffer mutex
is released and sblock() is invoked.
Reviewed by: bz, kmacy
Reported by: Jos Backus <jos at catnook dot com>
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/sctp_input.c | 3 | ||||
-rw-r--r-- | sys/netinet/sctp_peeloff.c | 4 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 2 |
3 files changed, 5 insertions, 4 deletions
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index ea7456f..5bad746 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -2509,7 +2509,8 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, atomic_add_int(&(*stcb)->asoc.refcnt, 1); SCTP_TCB_UNLOCK((*stcb)); - sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, M_NOWAIT); + sctp_pull_off_control_to_new_inp((*inp_p), inp, *stcb, + 0); SCTP_TCB_LOCK((*stcb)); atomic_subtract_int(&(*stcb)->asoc.refcnt, 1); diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c index 424de2c..d49688e 100644 --- a/sys/netinet/sctp_peeloff.c +++ b/sys/netinet/sctp_peeloff.c @@ -134,7 +134,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id) atomic_add_int(&stcb->asoc.refcnt, 1); SCTP_TCB_UNLOCK(stcb); - sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK); + sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT); atomic_subtract_int(&stcb->asoc.refcnt, 1); return (0); @@ -230,7 +230,7 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error) * And now the final hack. We move data in the pending side i.e. * head to the new socket buffer. Let the GRUBBING begin :-0 */ - sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK); + sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, SBL_WAIT); atomic_subtract_int(&stcb->asoc.refcnt, 1); return (newso); } diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 89b5e4f..25b2f92 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -4993,7 +4993,7 @@ sctp_sorecvmsg(struct socket *so, sctp_misc_ints(SCTP_SORECV_ENTERPL, rwnd_req, block_allowed, so->so_rcv.sb_cc, uio->uio_resid); } - error = sblock(&so->so_rcv, (block_allowed ? M_WAITOK : 0)); + error = sblock(&so->so_rcv, (block_allowed ? SBL_WAIT : 0)); sockbuf_lock = 1; if (error) { goto release_unlocked; |