summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2010-06-06 02:33:46 +0000
committerrrs <rrs@FreeBSD.org>2010-06-06 02:33:46 +0000
commit13d687dbf66620423ec1b3094aed3e81068e8a1d (patch)
tree761f0f630bcf460af5f98c12e3a153f1dffe6876
parent923bc21fb4b430222e6ddbb17eb50bd4ab524ba8 (diff)
downloadFreeBSD-src-13d687dbf66620423ec1b3094aed3e81068e8a1d.zip
FreeBSD-src-13d687dbf66620423ec1b3094aed3e81068e8a1d.tar.gz
Hopefully this fixes a LOR by making
so we only hold the iterator lock during updates to the iterators work. MFC after: 1 week
-rw-r--r--sys/netinet/sctp_pcb.c39
1 files changed, 17 insertions, 22 deletions
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index cccd8c50..5115460 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -2296,7 +2296,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
if (inp->sctp_asocidhash == NULL) {
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
SCTP_INP_INFO_WUNLOCK();
- return error;
+ return (ENOBUFS);
}
#ifdef IPSEC
{
@@ -3107,29 +3107,13 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 0);
#endif
- SCTP_ITERATOR_LOCK();
-
- so = inp->sctp_socket;
- if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
- /* been here before.. eeks.. get out of here */
- SCTP_PRINTF("This conflict in free SHOULD not be happening! from %d, imm %d\n", from, immediate);
- SCTP_ITERATOR_UNLOCK();
-#ifdef SCTP_LOG_CLOSING
- sctp_log_closing(inp, NULL, 1);
-#endif
- return;
- }
- SCTP_ASOC_CREATE_LOCK(inp);
- SCTP_INP_INFO_WLOCK();
-
- SCTP_INP_WLOCK(inp);
- /* First time through we have the socket lock, after that no more. */
if (from == SCTP_CALLED_AFTER_CMPSET_OFCLOSE) {
/*
* Once we are in we can remove the flag from = 1 is only
* passed from the actual closing routines that are called
* via the sockets layer.
*/
+ SCTP_ITERATOR_LOCK();
inp->sctp_flags &= ~SCTP_PCB_FLAGS_CLOSE_IP;
/* socket is gone, so no more wakeups allowed */
inp->sctp_flags |= SCTP_PCB_FLAGS_DONT_WAKE;
@@ -3138,7 +3122,22 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
/* mark any iterators on the list or being processed */
sctp_iterator_inp_being_freed(inp);
+ SCTP_ITERATOR_UNLOCK();
+ }
+ so = inp->sctp_socket;
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
+ /* been here before.. eeks.. get out of here */
+ SCTP_PRINTF("This conflict in free SHOULD not be happening! from %d, imm %d\n", from, immediate);
+#ifdef SCTP_LOG_CLOSING
+ sctp_log_closing(inp, NULL, 1);
+#endif
+ return;
}
+ SCTP_ASOC_CREATE_LOCK(inp);
+ SCTP_INP_INFO_WLOCK();
+
+ SCTP_INP_WLOCK(inp);
+ /* First time through we have the socket lock, after that no more. */
sctp_timer_stop(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL,
SCTP_FROM_SCTP_PCB + SCTP_LOC_1);
@@ -3338,7 +3337,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_INP_WUNLOCK(inp);
SCTP_ASOC_CREATE_UNLOCK(inp);
SCTP_INP_INFO_WUNLOCK();
- SCTP_ITERATOR_UNLOCK();
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 2);
#endif
@@ -3416,7 +3414,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_INP_WUNLOCK(inp);
SCTP_ASOC_CREATE_UNLOCK(inp);
SCTP_INP_INFO_WUNLOCK();
- SCTP_ITERATOR_UNLOCK();
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 3);
#endif
@@ -3428,7 +3425,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_INP_WUNLOCK(inp);
SCTP_ASOC_CREATE_UNLOCK(inp);
SCTP_INP_INFO_WUNLOCK();
- SCTP_ITERATOR_UNLOCK();
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 4);
#endif
@@ -3550,7 +3546,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_INP_READ_DESTROY(inp);
SCTP_ASOC_CREATE_LOCK_DESTROY(inp);
SCTP_INP_INFO_WUNLOCK();
- SCTP_ITERATOR_UNLOCK();
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp);
SCTP_DECR_EP_COUNT();
}
OpenPOWER on IntegriCloud