aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/sctp_pcb.c
diff options
context:
space:
mode:
authorRandall Stewart <rrs@FreeBSD.org>2010-06-11 03:54:00 +0000
committerRandall Stewart <rrs@FreeBSD.org>2010-06-11 03:54:00 +0000
commitec4c19fcf04f84d4c36f23c80256b56a38a8c9bc (patch)
treebc2f77a15894862273148f516ec9102392038cd4 /sys/netinet/sctp_pcb.c
parentf635c047c5ea4a959b5979e017ef19633ed0f9cf (diff)
downloadsrc-ec4c19fcf04f84d4c36f23c80256b56a38a8c9bc.tar.gz
src-ec4c19fcf04f84d4c36f23c80256b56a38a8c9bc.zip
3 Fixes -
a) There was a case where a ICMP message could cause us to return leaving a stuck lock on an stcb. b) The iterator needed some tweaks to fix its lock ordering. c) The ITERATOR_LOCK is no longer needed in the freeing of a stcb. Now that the timer based one is gone we don't have a multiple resume situation. Add to that that there was somewhere a path out of the freeing of an assoc that did NOT release the iterator_lock.. it was time to clean this old code up and in the process fix the lock bug. MFC after: 1 week
Notes
Notes: svn path=/head/; revision=209029
Diffstat (limited to 'sys/netinet/sctp_pcb.c')
-rw-r--r--sys/netinet/sctp_pcb.c50
1 files changed, 11 insertions, 39 deletions
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index b5ca4b530755..5b12d768e588 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -3075,6 +3075,11 @@ sctp_iterator_inp_being_freed(struct sctp_inpcb *inp)
} else {
it->inp = LIST_NEXT(it->inp, sctp_list);
}
+ /*
+ * When its put in the refcnt is incremented so decr
+ * it
+ */
+ SCTP_INP_DECR_REF(inp);
}
it = nit;
}
@@ -4428,38 +4433,6 @@ sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time, uint16_t lport, uint16_t
}
-static void
-sctp_iterator_asoc_being_freed(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
-{
- struct sctp_iterator *it;
-
- /*
- * Unlock the tcb lock we do this so we avoid a dead lock scenario
- * where the iterator is waiting on the TCB lock and the TCB lock is
- * waiting on the iterator lock.
- */
- it = stcb->asoc.stcb_starting_point_for_iterator;
- if (it == NULL) {
- return;
- }
- if (it->inp != stcb->sctp_ep) {
- /* hmm, focused on the wrong one? */
- return;
- }
- if (it->stcb != stcb) {
- return;
- }
- it->stcb = LIST_NEXT(stcb, sctp_tcblist);
- if (it->stcb == NULL) {
- /* done with all asoc's in this assoc */
- if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
- it->inp = NULL;
- } else {
- it->inp = LIST_NEXT(inp, sctp_list);
- }
- }
-}
-
/*-
* Free the association after un-hashing the remote port. This
@@ -4665,7 +4638,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
SCTP_TCB_UNLOCK(stcb);
- SCTP_ITERATOR_LOCK();
SCTP_INP_INFO_WLOCK();
SCTP_INP_WLOCK(inp);
SCTP_TCB_LOCK(stcb);
@@ -4704,7 +4676,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
* Make it invalid too, that way if its about to run it will abort
* and return.
*/
- sctp_iterator_asoc_being_freed(inp, stcb);
/* re-increment the lock */
if (from_inpcbfree == SCTP_NORMAL_PROC) {
atomic_add_int(&stcb->asoc.refcnt, -1);
@@ -4721,7 +4692,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
if (from_inpcbfree == SCTP_NORMAL_PROC) {
SCTP_INP_INCR_REF(inp);
SCTP_INP_WUNLOCK(inp);
- SCTP_ITERATOR_UNLOCK();
}
/* pull from vtag hash */
LIST_REMOVE(stcb, sctp_asocs);
@@ -6694,20 +6664,22 @@ sctp_initiate_iterator(inp_func inpf,
it->no_chunk_output = chunk_output_off;
it->vn = curvnet;
if (s_inp) {
+ /* Assume lock is held here */
it->inp = s_inp;
+ SCTP_INP_INCR_REF(it->inp);
it->iterator_flags = SCTP_ITERATOR_DO_SINGLE_INP;
} else {
SCTP_INP_INFO_RLOCK();
it->inp = LIST_FIRST(&SCTP_BASE_INFO(listhead));
-
+ if (it->inp) {
+ SCTP_INP_INCR_REF(it->inp);
+ }
SCTP_INP_INFO_RUNLOCK();
it->iterator_flags = SCTP_ITERATOR_DO_ALL_INP;
}
SCTP_IPI_ITERATOR_WQ_LOCK();
- if (it->inp) {
- SCTP_INP_INCR_REF(it->inp);
- }
+
TAILQ_INSERT_TAIL(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr);
if (sctp_it_ctl.iterator_running == 0) {
sctp_wakeup_iterator();