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
This commit is contained in:
Randall Stewart 2010-06-06 20:34:17 +00:00
parent 0c7dc84076
commit 8ce4a9a255
4 changed files with 28 additions and 7 deletions

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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();