git: f37224f02626 - stable/13 - sctp: cleanup sctp_lower_sosend
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 23 Feb 2022 00:18:54 UTC
The branch stable/13 has been updated by tuexen:
URL: https://cgit.FreeBSD.org/src/commit/?id=f37224f02626ec4f066c586e1d5fe772151e5f0c
commit f37224f02626ec4f066c586e1d5fe772151e5f0c
Author: Michael Tuexen <tuexen@FreeBSD.org>
AuthorDate: 2022-02-20 00:09:30 +0000
Commit: Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2022-02-23 00:17:25 +0000
sctp: cleanup sctp_lower_sosend
This is a preparation for retiring the tcp send lock in the
next step.
(cherry picked from commit a4a31271cc7a018b0a7120bf7d8fa40c39264914)
---
sys/netinet/sctp_output.c | 481 +++++++++++++++++++++++-----------------------
1 file changed, 242 insertions(+), 239 deletions(-)
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 35a0406a5a9d..3d81fb2b4288 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -12502,7 +12502,7 @@ sctp_lower_sosend(struct socket *so,
int error;
struct mbuf *top = NULL;
int queue_only = 0, queue_only_for_init = 0;
- int free_cnt_applied = 0;
+ bool free_cnt_applied = false;
int un_sent;
int now_filled = 0;
unsigned int inqueue_bytes = 0;
@@ -12514,11 +12514,11 @@ sctp_lower_sosend(struct socket *so,
struct sctp_association *asoc;
struct sctp_inpcb *t_inp;
int user_marks_eor;
- int create_lock_applied = 0;
+ bool create_lock_applied = false;
int nagle_applies = 0;
int some_on_control = 0;
int got_all_of_the_send = 0;
- int hold_tcblock = 0;
+ bool hold_tcblock = false;
int non_blocking = 0;
ssize_t local_soresv = 0;
uint16_t port;
@@ -12534,7 +12534,7 @@ sctp_lower_sosend(struct socket *so,
if (inp == NULL) {
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EINVAL);
error = EINVAL;
- if (i_pak) {
+ if (i_pak != NULL) {
SCTP_RELEASE_PKT(i_pak);
}
return (error);
@@ -12545,7 +12545,7 @@ sctp_lower_sosend(struct socket *so,
}
user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR);
atomic_add_int(&inp->total_sends, 1);
- if (uio) {
+ if (uio != NULL) {
if (uio->uio_resid < 0) {
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
return (EINVAL);
@@ -12569,7 +12569,7 @@ sctp_lower_sosend(struct socket *so,
* Pre-screen address, if one is given the sin-len
* must be set correctly!
*/
- if (addr) {
+ if (addr != NULL) {
union sctp_sockstore *raddr = (union sctp_sockstore *)addr;
switch (raddr->sa.sa_family) {
@@ -12598,10 +12598,11 @@ sctp_lower_sosend(struct socket *so,
error = EAFNOSUPPORT;
goto out_unlocked;
}
- } else
+ } else {
port = 0;
+ }
- if (srcv) {
+ if (srcv != NULL) {
sinfo_flags = srcv->sinfo_flags;
sinfo_assoc_id = srcv->sinfo_assoc_id;
if (INVALID_SINFO_FLAG(sinfo_flags) ||
@@ -12610,7 +12611,7 @@ sctp_lower_sosend(struct socket *so,
error = EINVAL;
goto out_unlocked;
}
- if (srcv->sinfo_flags)
+ if (srcv->sinfo_flags != 0)
SCTP_STAT_INCR(sctps_sends_with_flags);
} else {
sinfo_flags = inp->def_send.sinfo_flags;
@@ -12638,17 +12639,23 @@ sctp_lower_sosend(struct socket *so,
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
SCTP_INP_RLOCK(inp);
stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
+ if (stcb != NULL) {
SCTP_TCB_LOCK(stcb);
- hold_tcblock = 1;
+ hold_tcblock = true;
+ if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ SCTP_INP_RUNLOCK(inp);
+ error = ENOTCONN;
+ goto out_unlocked;
+ }
}
SCTP_INP_RUNLOCK(inp);
- } else if (sinfo_assoc_id) {
+ } else if (sinfo_assoc_id > SCTP_ALL_ASSOC) {
stcb = sctp_findassociation_ep_asocid(inp, sinfo_assoc_id, 1);
if (stcb != NULL) {
- hold_tcblock = 1;
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ hold_tcblock = true;
}
- } else if (addr) {
+ } else if (addr != NULL) {
/*-
* Since we did not use findep we must
* increment it, and if we don't find a tcb
@@ -12663,13 +12670,22 @@ sctp_lower_sosend(struct socket *so,
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
} else {
- hold_tcblock = 1;
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ hold_tcblock = true;
}
}
- if ((stcb == NULL) && (addr)) {
+#ifdef INVARIANTS
+ if (stcb != NULL) {
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ KASSERT(hold_tcblock, ("tcb lock hold, hold_tcblock is false"));
+ } else {
+ KASSERT(!hold_tcblock, ("hold_tcblock is true, but stcb is NULL"));
+ }
+#endif
+ if ((stcb == NULL) && (addr != NULL)) {
/* Possible implicit send? */
SCTP_ASOC_CREATE_LOCK(inp);
- create_lock_applied = 1;
+ create_lock_applied = true;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) {
/* Should I really unlock ? */
@@ -12698,7 +12714,8 @@ sctp_lower_sosend(struct socket *so,
SCTP_INP_DECR_REF(inp);
SCTP_INP_WUNLOCK(inp);
} else {
- hold_tcblock = 1;
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ hold_tcblock = true;
}
if (error) {
goto out_unlocked;
@@ -12730,11 +12747,7 @@ sctp_lower_sosend(struct socket *so,
}
/* get an asoc/stcb struct */
vrf_id = inp->def_vrf_id;
-#ifdef INVARIANTS
- if (create_lock_applied == 0) {
- panic("Error, should hold create lock and I don't?");
- }
-#endif
+ KASSERT(create_lock_applied, ("create_lock_applied is false"));
stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id,
inp->sctp_ep.pre_open_stream_count,
inp->sctp_ep.port,
@@ -12744,27 +12757,22 @@ sctp_lower_sosend(struct socket *so,
/* Error is setup for us in the call */
goto out_unlocked;
}
- hold_tcblock = 1;
- if (create_lock_applied) {
- SCTP_ASOC_CREATE_UNLOCK(inp);
- create_lock_applied = 0;
- } else {
- SCTP_PRINTF("Huh-3? create lock should have been on??\n");
- }
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ hold_tcblock = true;
+ SCTP_ASOC_CREATE_UNLOCK(inp);
+ create_lock_applied = false;
/*
* Turn on queue only flag to prevent data from
* being sent
*/
queue_only = 1;
- asoc = &stcb->asoc;
SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT);
- (void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
-
- if (control) {
+ (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
+ if (control != NULL) {
if (sctp_process_cmsgs_for_init(stcb, control, &error)) {
sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
- hold_tcblock = 0;
+ hold_tcblock = false;
stcb = NULL;
goto out_unlocked;
}
@@ -12778,8 +12786,19 @@ sctp_lower_sosend(struct socket *so,
* change it BEFORE we append the message.
*/
}
- } else
- asoc = &stcb->asoc;
+ }
+
+ KASSERT(!create_lock_applied, ("create_lock_applied is true"));
+ KASSERT(stcb != NULL, ("stcb is NULL"));
+ KASSERT(hold_tcblock, ("hold_tcblock is false"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ asoc = &stcb->asoc;
+ KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0,
+ ("Association about to be freed"));
+ /* Keep the stcb from being freed under our feet. */
+ atomic_add_int(&asoc->refcnt, 1);
+ free_cnt_applied = true;
+
if (srcv == NULL) {
srcv = (struct sctp_sndrcvinfo *)&asoc->def_send;
sinfo_flags = srcv->sinfo_flags;
@@ -12791,7 +12810,7 @@ sctp_lower_sosend(struct socket *so,
}
}
if (sinfo_flags & SCTP_ADDR_OVER) {
- if (addr)
+ if (addr != NULL)
net = sctp_findnet(stcb, addr);
else
net = NULL;
@@ -12802,16 +12821,13 @@ sctp_lower_sosend(struct socket *so,
goto out_unlocked;
}
} else {
- if (stcb->asoc.alternate) {
- net = stcb->asoc.alternate;
+ if (asoc->alternate != NULL) {
+ net = asoc->alternate;
} else {
- net = stcb->asoc.primary_destination;
+ net = asoc->primary_destination;
}
}
atomic_add_int(&stcb->total_sends, 1);
- /* Keep the stcb from being freed under our feet */
- atomic_add_int(&asoc->refcnt, 1);
- free_cnt_applied = 1;
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT)) {
if (sndlen > (ssize_t)asoc->smallest_mtu) {
@@ -12829,18 +12845,14 @@ sctp_lower_sosend(struct socket *so,
if (non_blocking) {
ssize_t amount;
- if (hold_tcblock == 0) {
- SCTP_TCB_LOCK(stcb);
- hold_tcblock = 1;
- }
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
if (user_marks_eor == 0) {
amount = sndlen;
} else {
amount = 1;
}
- if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + stcb->asoc.sb_send_resv)) ||
- (stcb->asoc.chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
+ if ((SCTP_SB_LIMIT_SND(so) < (amount + inqueue_bytes + asoc->sb_send_resv)) ||
+ (asoc->chunks_on_out_queue >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK);
if (sndlen > (ssize_t)SCTP_SB_LIMIT_SND(so))
error = EMSGSIZE;
@@ -12848,22 +12860,16 @@ sctp_lower_sosend(struct socket *so,
error = EWOULDBLOCK;
goto out_unlocked;
}
- stcb->asoc.sb_send_resv += (uint32_t)sndlen;
- SCTP_TCB_UNLOCK(stcb);
- hold_tcblock = 0;
+ asoc->sb_send_resv += (uint32_t)sndlen;
} else {
- atomic_add_int(&stcb->asoc.sb_send_resv, (int)sndlen);
+ atomic_add_int(&asoc->sb_send_resv, (int)sndlen);
}
local_soresv = sndlen;
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
error = ECONNRESET;
goto out_unlocked;
}
- if (create_lock_applied) {
- SCTP_ASOC_CREATE_UNLOCK(inp);
- create_lock_applied = 0;
- }
/* Is the stream no. valid? */
if (srcv->sinfo_stream >= asoc->streamoutcnt) {
/* Invalid stream number */
@@ -12906,12 +12912,20 @@ sctp_lower_sosend(struct socket *so,
}
}
/* Ok, we will attempt a msgsnd :> */
- if (p) {
+ if (p != NULL) {
p->td_ru.ru_msgsnd++;
}
+
+ KASSERT(stcb != NULL, ("stcb is NULL"));
+ KASSERT(hold_tcblock, ("hold_tcblock is false"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0,
+ ("Association about to be freed"));
+
/* Are we aborting? */
if (sinfo_flags & SCTP_ABORT) {
struct mbuf *mm;
+ struct sctp_paramhdr *ph;
ssize_t tot_demand, tot_out = 0, max_out;
SCTP_STAT_INCR(sctps_sends_with_abort);
@@ -12923,19 +12937,15 @@ sctp_lower_sosend(struct socket *so,
error = EINVAL;
goto out;
}
- if (hold_tcblock) {
- SCTP_TCB_UNLOCK(stcb);
- hold_tcblock = 0;
- }
- if (top) {
- struct mbuf *cntm = NULL;
+ if (top != NULL) {
+ struct mbuf *cntm;
- mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_WAITOK, 1, MT_DATA);
if (sndlen != 0) {
for (cntm = top; cntm; cntm = SCTP_BUF_NEXT(cntm)) {
tot_out += SCTP_BUF_LEN(cntm);
}
}
+ mm = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA);
} else {
/* Must fit in a MTU */
tot_out = sndlen;
@@ -12946,7 +12956,7 @@ sctp_lower_sosend(struct socket *so,
error = EMSGSIZE;
goto out;
}
- mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_WAITOK, 1, MT_DATA);
+ mm = sctp_get_mbuf_for_msg((unsigned int)tot_demand, 0, M_NOWAIT, 1, MT_DATA);
}
if (mm == NULL) {
SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOMEM);
@@ -12958,43 +12968,41 @@ sctp_lower_sosend(struct socket *so,
if (tot_out > max_out) {
tot_out = max_out;
}
- if (mm) {
- struct sctp_paramhdr *ph;
-
- /* now move forward the data pointer */
- ph = mtod(mm, struct sctp_paramhdr *);
- ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
- ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out));
- ph++;
- SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr));
- if (top == NULL) {
- error = uiomove((caddr_t)ph, (int)tot_out, uio);
- if (error) {
- /*-
- * Here if we can't get his data we
- * still abort we just don't get to
- * send the users note :-0
- */
- sctp_m_freem(mm);
- mm = NULL;
- }
- } else {
- if (sndlen != 0) {
- SCTP_BUF_NEXT(mm) = top;
- }
- }
- }
- if (hold_tcblock == 0) {
+ ph = mtod(mm, struct sctp_paramhdr *);
+ ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
+ ph->param_length = htons((uint16_t)(sizeof(struct sctp_paramhdr) + tot_out));
+ ph++;
+ SCTP_BUF_LEN(mm) = (int)(tot_out + sizeof(struct sctp_paramhdr));
+ if (top == NULL) {
+ SCTP_TCB_UNLOCK(stcb);
+ hold_tcblock = false;
+ error = uiomove((caddr_t)ph, (int)tot_out, uio);
SCTP_TCB_LOCK(stcb);
+ hold_tcblock = true;
+ if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ sctp_m_freem(mm);
+ goto out_unlocked;
+ }
+ if (error != 0) {
+ /*-
+ * Here if we can't get his data we
+ * still abort we just don't get to
+ * send the users note :-0
+ */
+ sctp_m_freem(mm);
+ mm = NULL;
+ }
+ } else {
+ if (sndlen != 0) {
+ SCTP_BUF_NEXT(mm) = top;
+ }
}
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
- free_cnt_applied = 0;
+ atomic_subtract_int(&asoc->refcnt, 1);
+ free_cnt_applied = false;
/* release this lock, otherwise we hang on ourselves */
NET_EPOCH_ENTER(et);
sctp_abort_an_association(stcb->sctp_ep, stcb, mm, false, SCTP_SO_LOCKED);
NET_EPOCH_EXIT(et);
- /* now relock the stcb so everything is sane */
- hold_tcblock = 0;
stcb = NULL;
/*
* In this case top is already chained to mm avoid double
@@ -13006,24 +13014,20 @@ sctp_lower_sosend(struct socket *so,
}
goto out_unlocked;
}
+
+ KASSERT(stcb != NULL, ("stcb is NULL"));
+ KASSERT(hold_tcblock, ("hold_tcblock is false"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0,
+ ("Association about to be freed"));
+
/* Calculate the maximum we can send */
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) {
max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
} else {
max_len = 0;
}
- if (hold_tcblock) {
- SCTP_TCB_UNLOCK(stcb);
- hold_tcblock = 0;
- }
- if (asoc->strmout == NULL) {
- /* huh? software error */
- SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EFAULT);
- error = EFAULT;
- goto out_unlocked;
- }
-
/* Unless E_EOR mode is on, we must make a send FIT in one call. */
if ((user_marks_eor == 0) &&
(sndlen > (ssize_t)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) {
@@ -13057,25 +13061,33 @@ sctp_lower_sosend(struct socket *so,
if (((max_len <= local_add_more) &&
((ssize_t)SCTP_SB_LIMIT_SND(so) >= local_add_more)) ||
(max_len == 0) ||
- ((stcb->asoc.chunks_on_out_queue + stcb->asoc.stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
+ ((asoc->chunks_on_out_queue + asoc->stream_queue_cnt) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
/* No room right now ! */
SOCKBUF_LOCK(&so->so_snd);
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
while ((SCTP_SB_LIMIT_SND(so) < (inqueue_bytes + local_add_more)) ||
- ((stcb->asoc.stream_queue_cnt + stcb->asoc.chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
+ ((asoc->stream_queue_cnt + asoc->chunks_on_out_queue) >= SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue))) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "pre_block limit:%u <(inq:%d + %zd) || (%d+%d > %d)\n",
(unsigned int)SCTP_SB_LIMIT_SND(so),
inqueue_bytes,
local_add_more,
- stcb->asoc.stream_queue_cnt,
- stcb->asoc.chunks_on_out_queue,
+ asoc->stream_queue_cnt,
+ asoc->chunks_on_out_queue,
SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue));
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, asoc, sndlen);
}
be.error = 0;
stcb->block_entry = &be;
+ SCTP_TCB_UNLOCK(stcb);
+ hold_tcblock = false;
error = sbwait(&so->so_snd);
+ SCTP_TCB_LOCK(stcb);
+ hold_tcblock = true;
+ if (asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ SOCKBUF_UNLOCK(&so->so_snd);
+ goto out_unlocked;
+ }
stcb->block_entry = NULL;
if (error || so->so_error || be.error) {
if (error == 0) {
@@ -13090,13 +13102,9 @@ sctp_lower_sosend(struct socket *so,
}
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK,
- asoc, stcb->asoc.total_output_queue_size);
+ asoc, asoc->total_output_queue_size);
}
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
- SOCKBUF_UNLOCK(&so->so_snd);
- goto out_unlocked;
- }
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
}
if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes) {
max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
@@ -13107,9 +13115,12 @@ sctp_lower_sosend(struct socket *so,
}
skip_preblock:
- if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
- goto out_unlocked;
- }
+ KASSERT(stcb != NULL, ("stcb is NULL"));
+ KASSERT(hold_tcblock, ("hold_tcblock is false"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0,
+ ("Association about to be freed"));
+
/*
* sndlen covers for mbuf case uio_resid covers for the non-mbuf
* case NOTE: uio will be null when top/mbuf is passed
@@ -13129,6 +13140,12 @@ skip_preblock:
struct sctp_stream_out *strm;
uint32_t sndout;
+ /*
+ * XXX: This will change soon, when the TCP send lock is
+ * retired.
+ */
+ SCTP_TCB_UNLOCK(stcb);
+ hold_tcblock = false;
SCTP_TCB_SEND_LOCK(stcb);
if ((asoc->stream_locked) &&
(asoc->stream_locked_on != srcv->sinfo_stream)) {
@@ -13137,7 +13154,7 @@ skip_preblock:
error = EINVAL;
goto out;
}
- strm = &stcb->asoc.strmout[srcv->sinfo_stream];
+ strm = &asoc->strmout[srcv->sinfo_stream];
if (strm->last_msg_incomplete == 0) {
do_a_copy_in:
SCTP_TCB_SEND_UNLOCK(stcb);
@@ -13147,7 +13164,7 @@ skip_preblock:
}
SCTP_TCB_SEND_LOCK(stcb);
/* The out streams might be reallocated. */
- strm = &stcb->asoc.strmout[srcv->sinfo_stream];
+ strm = &asoc->strmout[srcv->sinfo_stream];
if (sp->msg_is_complete) {
strm->last_msg_incomplete = 0;
asoc->stream_locked = 0;
@@ -13157,7 +13174,7 @@ skip_preblock:
* interrupt.
*/
strm->last_msg_incomplete = 1;
- if (stcb->asoc.idata_supported == 0) {
+ if (asoc->idata_supported == 0) {
asoc->stream_locked = 1;
asoc->stream_locked_on = srcv->sinfo_stream;
}
@@ -13170,7 +13187,7 @@ skip_preblock:
}
sp->processing = 1;
TAILQ_INSERT_TAIL(&strm->outqueue, sp, next);
- stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp);
+ asoc->ss_functions.sctp_ss_add_to_stream(stcb, asoc, strm, sp);
} else {
sp = TAILQ_LAST(&strm->outqueue, sctp_streamhead);
if (sp == NULL) {
@@ -13197,7 +13214,7 @@ skip_preblock:
/* How much room do we have? */
struct mbuf *new_tail, *mm;
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes)
max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
else
@@ -13210,7 +13227,7 @@ skip_preblock:
new_tail = NULL;
if (hold_tcblock) {
SCTP_TCB_UNLOCK(stcb);
- hold_tcblock = 0;
+ hold_tcblock = false;
}
mm = sctp_copy_resume(uio, (int)max_len, user_marks_eor, &error, &sndout, &new_tail);
if ((mm == NULL) || error) {
@@ -13218,8 +13235,8 @@ skip_preblock:
sctp_m_freem(mm);
}
SCTP_TCB_SEND_LOCK(stcb);
- if (((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
- ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) == 0) &&
+ if (((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
+ ((asoc->state & SCTP_STATE_WAS_ABORTED) == 0) &&
(sp != NULL)) {
sp->processing = 0;
}
@@ -13228,14 +13245,14 @@ skip_preblock:
}
/* Update the mbuf and count */
SCTP_TCB_SEND_LOCK(stcb);
- if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
- (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
+ if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
+ (asoc->state & SCTP_STATE_WAS_ABORTED)) {
/*
* we need to get out. Peer probably
* aborted.
*/
sctp_m_freem(mm);
- if (stcb->asoc.state & SCTP_STATE_WAS_ABORTED) {
+ if (asoc->state & SCTP_STATE_WAS_ABORTED) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
error = ECONNRESET;
}
@@ -13278,12 +13295,12 @@ skip_preblock:
* This is ugly but we must assure locking
* order
*/
- if (hold_tcblock == 0) {
+ if (!hold_tcblock) {
SCTP_TCB_LOCK(stcb);
- hold_tcblock = 1;
+ hold_tcblock = true;
}
sctp_prune_prsctp(stcb, asoc, srcv, (int)sndlen);
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
if (SCTP_SB_LIMIT_SND(so) > inqueue_bytes)
max_len = SCTP_SB_LIMIT_SND(so) - inqueue_bytes;
else
@@ -13292,7 +13309,7 @@ skip_preblock:
continue;
}
SCTP_TCB_UNLOCK(stcb);
- hold_tcblock = 0;
+ hold_tcblock = false;
}
/* wait for space now */
if (non_blocking) {
@@ -13306,9 +13323,9 @@ skip_preblock:
}
/* What about the INIT, send it maybe */
if (queue_only_for_init) {
- if (hold_tcblock == 0) {
+ if (!hold_tcblock) {
SCTP_TCB_LOCK(stcb);
- hold_tcblock = 1;
+ hold_tcblock = true;
}
if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
/* a collision took us forward? */
@@ -13332,11 +13349,11 @@ skip_preblock:
}
asoc->ifp_had_enobuf = 0;
}
- un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
+ un_sent = asoc->total_output_queue_size - asoc->total_flight;
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
- (stcb->asoc.total_flight > 0) &&
- (stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
- (un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))) {
+ (asoc->total_flight > 0) &&
+ (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
+ (un_sent < (int)(asoc->smallest_mtu - SCTP_MIN_OVERHEAD))) {
/*-
* Ok, Nagle is set on and we have data outstanding.
* Don't send anything and let SACKs drive out the
@@ -13358,9 +13375,9 @@ skip_preblock:
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only,
nagle_applies, un_sent);
- sctp_misc_ints(SCTP_CWNDLOG_PRESEND, stcb->asoc.total_output_queue_size,
- stcb->asoc.total_flight,
- stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count);
+ sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size,
+ asoc->total_flight,
+ asoc->chunks_on_out_queue, asoc->total_flight_count);
}
if (queue_only_for_init)
queue_only_for_init = 0;
@@ -13373,9 +13390,9 @@ skip_preblock:
* and I don't need to start output :-D
*/
NET_EPOCH_ENTER(et);
- if (hold_tcblock == 0) {
+ if (!hold_tcblock) {
if (SCTP_TCB_TRYLOCK(stcb)) {
- hold_tcblock = 1;
+ hold_tcblock = true;
sctp_chunk_output(inp,
stcb,
SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
@@ -13387,9 +13404,9 @@ skip_preblock:
}
NET_EPOCH_EXIT(et);
}
- if (hold_tcblock == 1) {
+ if (hold_tcblock) {
SCTP_TCB_UNLOCK(stcb);
- hold_tcblock = 0;
+ hold_tcblock = false;
}
SOCKBUF_LOCK(&so->so_snd);
/*-
@@ -13406,7 +13423,7 @@ skip_preblock:
* size we KNOW we will get to sleep safely with the
* wakeup flag in place.
*/
- inqueue_bytes = stcb->asoc.total_output_queue_size - (stcb->asoc.chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
+ inqueue_bytes = asoc->total_output_queue_size - (asoc->chunks_on_out_queue * SCTP_DATA_CHUNK_OVERHEAD(stcb));
if (SCTP_SB_LIMIT_SND(so) <= (inqueue_bytes +
min(SCTP_BASE_SYSCTL(sctp_add_more_threshold), SCTP_SB_LIMIT_SND(so)))) {
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
@@ -13428,8 +13445,8 @@ skip_preblock:
}
SOCKBUF_UNLOCK(&so->so_snd);
SCTP_TCB_SEND_LOCK(stcb);
- if (((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
- ((stcb->asoc.state & SCTP_STATE_WAS_ABORTED) == 0) &&
+ if (((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0) &&
+ ((asoc->state & SCTP_STATE_WAS_ABORTED) == 0) &&
(sp != NULL)) {
sp->processing = 0;
}
@@ -13439,28 +13456,28 @@ skip_preblock:
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
sctp_log_block(SCTP_BLOCK_LOG_OUTOF_BLK,
- asoc, stcb->asoc.total_output_queue_size);
+ asoc, asoc->total_output_queue_size);
}
}
SOCKBUF_UNLOCK(&so->so_snd);
SCTP_TCB_SEND_LOCK(stcb);
- if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
- (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
+ if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
+ (asoc->state & SCTP_STATE_WAS_ABORTED)) {
SCTP_TCB_SEND_UNLOCK(stcb);
goto out_unlocked;
}
SCTP_TCB_SEND_UNLOCK(stcb);
}
SCTP_TCB_SEND_LOCK(stcb);
- if ((stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
- (stcb->asoc.state & SCTP_STATE_WAS_ABORTED)) {
+ if ((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
+ (asoc->state & SCTP_STATE_WAS_ABORTED)) {
SCTP_TCB_SEND_UNLOCK(stcb);
goto out_unlocked;
}
if (sp) {
if (sp->msg_is_complete == 0) {
strm->last_msg_incomplete = 1;
- if (stcb->asoc.idata_supported == 0) {
+ if (asoc->idata_supported == 0) {
asoc->stream_locked = 1;
asoc->stream_locked_on = srcv->sinfo_stream;
}
@@ -13479,27 +13496,34 @@ skip_preblock:
if (uio->uio_resid == 0) {
got_all_of_the_send = 1;
}
+ if (!hold_tcblock) {
+ SCTP_TCB_LOCK(stcb);
+ hold_tcblock = true;
+ }
} else {
- /* We send in a 0, since we do NOT have any locks */
- error = sctp_msg_append(stcb, net, top, srcv, 0);
+ /* We send in a 1, since we do have the stcb lock. */
+ error = sctp_msg_append(stcb, net, top, srcv, 1);
top = NULL;
if (sinfo_flags & SCTP_EOF) {
got_all_of_the_send = 1;
}
}
- if (error) {
+ if (error != 0) {
goto out;
}
dataless_eof:
+
+ KASSERT(stcb != NULL, ("stcb is NULL"));
+ KASSERT(hold_tcblock, ("hold_tcblock is false"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0,
+ ("Association about to be freed"));
+
/* EOF thing ? */
if ((sinfo_flags & SCTP_EOF) &&
(got_all_of_the_send == 1)) {
SCTP_STAT_INCR(sctps_sends_with_eof);
error = 0;
- if (hold_tcblock == 0) {
- SCTP_TCB_LOCK(stcb);
- hold_tcblock = 1;
- }
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue) &&
sctp_is_there_unsent_data(stcb, SCTP_SO_LOCKED) == 0) {
@@ -13518,10 +13542,10 @@ dataless_eof:
}
SCTP_SET_STATE(stcb, SCTP_STATE_SHUTDOWN_SENT);
sctp_stop_timers_for_shutdown(stcb);
- if (stcb->asoc.alternate) {
- netp = stcb->asoc.alternate;
+ if (asoc->alternate != NULL) {
+ netp = asoc->alternate;
} else {
- netp = stcb->asoc.primary_destination;
+ netp = asoc->primary_destination;
}
sctp_send_shutdown(stcb, netp);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb,
@@ -13543,10 +13567,6 @@ dataless_eof:
if ((SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_SENT) &&
(SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_RECEIVED) &&
(SCTP_GET_STATE(stcb) != SCTP_STATE_SHUTDOWN_ACK_SENT)) {
- if (hold_tcblock == 0) {
- SCTP_TCB_LOCK(stcb);
- hold_tcblock = 1;
- }
if ((*asoc->ss_functions.sctp_ss_is_user_msgs_incomplete) (stcb, asoc)) {
SCTP_ADD_SUBSTATE(stcb, SCTP_STATE_PARTIAL_MSG_LEFT);
}
@@ -13559,8 +13579,8 @@ dataless_eof:
abort_anyway:
if (free_cnt_applied) {
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
- free_cnt_applied = 0;
+ atomic_subtract_int(&asoc->refcnt, 1);
+ free_cnt_applied = false;
}
SCTP_SNPRINTF(msg, sizeof(msg),
"%s:%d at %s", __FILE__, __LINE__, __func__);
@@ -13570,11 +13590,7 @@ dataless_eof:
sctp_abort_an_association(stcb->sctp_ep, stcb,
op_err, false, SCTP_SO_LOCKED);
NET_EPOCH_EXIT(et);
- /*
- * now relock the stcb so everything
- * is sane
- */
- hold_tcblock = 0;
+ hold_tcblock = false;
stcb = NULL;
goto out;
}
@@ -13585,14 +13601,16 @@ dataless_eof:
}
}
skip_out_eof:
- if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue)) {
+ KASSERT(stcb != NULL, ("stcb is NULL"));
+ KASSERT(hold_tcblock, ("hold_tcblock is false"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0,
+ ("Association about to be freed"));
+
+ if (!TAILQ_EMPTY(&asoc->control_send_queue)) {
some_on_control = 1;
}
if (queue_only_for_init) {
- if (hold_tcblock == 0) {
- SCTP_TCB_LOCK(stcb);
- hold_tcblock = 1;
- }
if (SCTP_GET_STATE(stcb) == SCTP_STATE_OPEN) {
/* a collision took us forward? */
queue_only = 0;
@@ -13605,7 +13623,7 @@ skip_out_eof:
}
}
if ((net->flight_size > net->cwnd) &&
- (stcb->asoc.sctp_cmt_on_off == 0)) {
+ (asoc->sctp_cmt_on_off == 0)) {
SCTP_STAT_INCR(sctps_send_cwnd_avoid);
queue_only = 1;
} else if (asoc->ifp_had_enobuf) {
@@ -13615,11 +13633,11 @@ skip_out_eof:
}
asoc->ifp_had_enobuf = 0;
}
- un_sent = stcb->asoc.total_output_queue_size - stcb->asoc.total_flight;
+ un_sent = asoc->total_output_queue_size - asoc->total_flight;
if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_NODELAY)) &&
- (stcb->asoc.total_flight > 0) &&
- (stcb->asoc.stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
- (un_sent < (int)(stcb->asoc.smallest_mtu - SCTP_MIN_OVERHEAD))) {
+ (asoc->total_flight > 0) &&
+ (asoc->stream_queue_cnt < SCTP_MAX_DATA_BUNDLING) &&
+ (un_sent < (int)(asoc->smallest_mtu - SCTP_MIN_OVERHEAD))) {
/*-
* Ok, Nagle is set on and we have data outstanding.
* Don't send anything and let SACKs drive out the
@@ -13641,82 +13659,67 @@ skip_out_eof:
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_BLK_LOGGING_ENABLE) {
sctp_misc_ints(SCTP_CWNDLOG_PRESEND, queue_only_for_init, queue_only,
nagle_applies, un_sent);
- sctp_misc_ints(SCTP_CWNDLOG_PRESEND, stcb->asoc.total_output_queue_size,
- stcb->asoc.total_flight,
- stcb->asoc.chunks_on_out_queue, stcb->asoc.total_flight_count);
+ sctp_misc_ints(SCTP_CWNDLOG_PRESEND, asoc->total_output_queue_size,
+ asoc->total_flight,
+ asoc->chunks_on_out_queue, asoc->total_flight_count);
}
NET_EPOCH_ENTER(et);
- if ((queue_only == 0) && (nagle_applies == 0) && (stcb->asoc.peers_rwnd && un_sent)) {
- /* we can attempt to send too. */
- if (hold_tcblock == 0) {
- /*
- * If there is activity recv'ing sacks no need to
- * send
- */
- if (SCTP_TCB_TRYLOCK(stcb)) {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
- hold_tcblock = 1;
- }
- } else {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
- }
+ if ((queue_only == 0) && (nagle_applies == 0) && (asoc->peers_rwnd && un_sent)) {
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
} else if ((queue_only == 0) &&
- (stcb->asoc.peers_rwnd == 0) &&
- (stcb->asoc.total_flight == 0)) {
+ (asoc->peers_rwnd == 0) &&
+ (asoc->total_flight == 0)) {
/* We get to have a probe outstanding */
- if (hold_tcblock == 0) {
- hold_tcblock = 1;
- SCTP_TCB_LOCK(stcb);
- }
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
} else if (some_on_control) {
int num_out, reason;
/* Here we do control only */
- if (hold_tcblock == 0) {
- hold_tcblock = 1;
- SCTP_TCB_LOCK(stcb);
- }
- (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out,
+ (void)sctp_med_chunk_output(inp, stcb, asoc, &num_out,
&reason, 1, 1, &now, &now_filled,
sctp_get_frag_point(stcb),
SCTP_SO_LOCKED);
}
NET_EPOCH_EXIT(et);
SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d\n",
- queue_only, stcb->asoc.peers_rwnd, un_sent,
- stcb->asoc.total_flight, stcb->asoc.chunks_on_out_queue,
- stcb->asoc.total_output_queue_size, error);
+ queue_only, asoc->peers_rwnd, un_sent,
+ asoc->total_flight, asoc->chunks_on_out_queue,
+ asoc->total_output_queue_size, error);
+
+ KASSERT(stcb != NULL, ("stcb is NULL"));
+ KASSERT(hold_tcblock, ("hold_tcblock is false"));
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ KASSERT((asoc->state & SCTP_STATE_ABOUT_TO_BE_FREED) == 0,
+ ("Association about to be freed"));
*** 45 LINES SKIPPED ***