summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2010-06-06 20:34:17 +0000
committerrrs <rrs@FreeBSD.org>2010-06-06 20:34:17 +0000
commit3bcf4834bbfb8c8c8023e0c832e654f827c1ff0d (patch)
treec75fb516496af43a786e1c0f886c80957c2cdcf8
parent6bf375889db714097da8272c8ad55ea17dc466ae (diff)
downloadFreeBSD-src-3bcf4834bbfb8c8c8023e0c832e654f827c1ff0d.zip
FreeBSD-src-3bcf4834bbfb8c8c8023e0c832e654f827c1ff0d.tar.gz
1) Optimize the cleanup and don't always depend on
the timer. This is done by considering the locks we will destroy and if they are contended we consider it the same as a reference count being up. Fixing this appears to cleanup another crash that was appearing with all the timers where the socket buf lock got corrupted. 2) Fix the sysctl code to take a lot more care when looking at INP's that are in the GONE or ALLGONE state. MFC after: 1 week
-rw-r--r--sys/netinet/sctp_constants.h2
-rw-r--r--sys/netinet/sctp_lock_bsd.h7
-rw-r--r--sys/netinet/sctp_pcb.c13
-rw-r--r--sys/netinet/sctp_sysctl.c13
4 files changed, 28 insertions, 7 deletions
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index abf5826..078981d 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -894,7 +894,7 @@ __FBSDID("$FreeBSD$");
/* third argument */
#define SCTP_CALLED_DIRECTLY_NOCMPSET 0
#define SCTP_CALLED_AFTER_CMPSET_OFCLOSE 1
-#define SCTP_CALLED_FROM_INPKILL_TIMER 2
+#define SCTP_CALLED_FROM_INPKILL_TIMER 2
/* second argument */
#define SCTP_FREE_SHOULD_USE_ABORT 1
#define SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE 0
diff --git a/sys/netinet/sctp_lock_bsd.h b/sys/netinet/sctp_lock_bsd.h
index 75c382b..dd9c2ce 100644
--- a/sys/netinet/sctp_lock_bsd.h
+++ b/sys/netinet/sctp_lock_bsd.h
@@ -185,6 +185,13 @@ extern int sctp_logoff_stuff;
#define SCTP_INP_LOCK_DESTROY(_inp) \
mtx_destroy(&(_inp)->inp_mtx)
+#define SCTP_INP_LOCK_CONTENDED(_inp) ((_inp)->inp_mtx.mtx_lock & MTX_CONTESTED)
+
+#define SCTP_INP_READ_CONTENDED(_inp) ((_inp)->inp_rdata_mtx.mtx_lock & MTX_CONTESTED)
+
+#define SCTP_ASOC_CREATE_LOCK_CONTENDED(_inp) ((_inp)->inp_create_mtx.mtx_lock & MTX_CONTESTED)
+
+
#define SCTP_ASOC_CREATE_LOCK_DESTROY(_inp) \
mtx_destroy(&(_inp)->inp_create_mtx)
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index f9e029a..8547584 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -3096,7 +3096,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
struct sctp_laddr *laddr, *nladdr;
struct inpcb *ip_pcb;
struct socket *so;
-
+ int being_refed = 0;
struct sctp_queued_to_read *sq;
@@ -3423,9 +3423,16 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
#endif
return;
}
+ if (SCTP_INP_LOCK_CONTENDED(inp))
+ being_refed++;
+ if (SCTP_INP_READ_CONTENDED(inp))
+ being_refed++;
+ if (SCTP_ASOC_CREATE_LOCK_CONTENDED(inp))
+ being_refed++;
+
if ((inp->refcount) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_CLOSE_IP) ||
- (from != SCTP_CALLED_FROM_INPKILL_TIMER)) {
+ (being_refed) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_CLOSE_IP)) {
(void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer);
sctp_timer_start(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL);
SCTP_INP_WUNLOCK(inp);
diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c
index c9967ea..9ba7dd4 100644
--- a/sys/netinet/sctp_sysctl.c
+++ b/sys/netinet/sctp_sysctl.c
@@ -331,6 +331,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
struct xsctp_inpcb xinpcb;
struct xsctp_tcb xstcb;
struct xsctp_raddr xraddr;
+ struct socket *so;
number_of_endpoints = 0;
number_of_local_addresses = 0;
@@ -369,6 +370,10 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
}
LIST_FOREACH(inp, &SCTP_BASE_INFO(listhead), sctp_list) {
SCTP_INP_RLOCK(inp);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
+ /* if its allgone it is being freed - skip it */
+ goto skip;
+ }
xinpcb.last = 0;
xinpcb.local_port = ntohs(inp->sctp_lport);
xinpcb.flags = inp->sctp_flags;
@@ -377,13 +382,14 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xinpcb.total_recvs = inp->total_recvs;
xinpcb.total_nospaces = inp->total_nospaces;
xinpcb.fragmentation_point = inp->sctp_frag_point;
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
+ so = inp->sctp_socket;
+ if ((so == NULL) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
xinpcb.qlen = 0;
xinpcb.maxqlen = 0;
} else {
- xinpcb.qlen = inp->sctp_socket->so_qlen;
- xinpcb.maxqlen = inp->sctp_socket->so_qlimit;
+ xinpcb.qlen = so->so_qlen;
+ xinpcb.maxqlen = so->so_qlimit;
}
SCTP_INP_INCR_REF(inp);
SCTP_INP_RUNLOCK(inp);
@@ -501,6 +507,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
if (error) {
return error;
}
+skip:
SCTP_INP_INFO_RLOCK();
}
SCTP_INP_INFO_RUNLOCK();
OpenPOWER on IntegriCloud