Date: Fri, 11 Jun 2010 03:13:20 +0000 (UTC) From: Randall Stewart <rrs@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org Subject: svn commit: r209028 - stable/8/sys/netinet Message-ID: <201006110313.o5B3DKhQ048446@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: rrs Date: Fri Jun 11 03:13:19 2010 New Revision: 209028 URL: http://svn.freebsd.org/changeset/base/209028 Log: MFC: Fix a number of bugs and race conditions. r208160: Bring back of the iterator thread. It now properly handles VNETS having only one thread. The old timer based code was full of LOR's and other issues. r208852: Cleanup bug. Basically when an un-accepted socket was hanging on a closed listener, we would leak the inp never cleaning it up r208853: Enhance the use under invarients of the audit for locks function and fix a bug where a close collision with a cookie being processed would cause a crash. r208854: Use the proper increment macros when working with the sent_queue_retran_cnt r208855: Align comments properly, Fix a bug where we were NOT looking at the resend markings for control chunks and also not decrementing the retran count which caused extra calls to retransmission. Alos add a valid no locks call to the output routine. r208856: Spacing issues in auth/bsd addr. r208857: Get rid of a windows ifdef that somehow leaked in r208863: Missing error leg returns in some failure cases r208864: LOR fix between the iterator and sctp_inpcb_close r208874: Don't call the sctp_inpcb_free from abort an association since you don't know what locks you hold and a timer will take care of the situation when the gone flag is set r208875: sctp_inpcb_free bug - a socket under the right situation could get stuck (from the accept queue) and never start the proper cleanup timer) r208876: Further enhance invariant lock validation, Fix a bug where a closed socket and a INIT-ACK could collide and cause a crash r208878: Clear up another bug in sctp_inpcb_free where we would end up due to a race in freeing hit a destroy of a contended lock. r208879: Optimize the cleanup and make some additional fixes in the sysctl code so that it won't reference a GONE INP and crash us r208883 & r208891: Fix so we don't open a hole between a sock lock and a call to socantrcvmore.. we could before hit a race that would kill the socket underneath us leading to a crash r208897: CUM-ACK calculation was messed up. So basically large message got broken from the original NR_sack integration. r208902: Make sure that we don't move a bit to the NR array that is behind the cum-ack r208952: Use both bit maps to calculte the cum-ack. r208953: Fix bug having to do with freeing an sctp_inpcb_free(). 1) make sure not to remove the flag until you get the lock again. 2) make sure all log_closing calls hold the lock. 3) Release all the locks when everthing is done and call callout_drain not callout_stop.. r208970: Fix some places on user allocation of a new sctp_inpcb where we run out of resource that we make sure to NULL the so_pcb pointer. Approved by: re - (bz@freebsd.org) Modified: stable/8/sys/netinet/sctp_auth.c stable/8/sys/netinet/sctp_bsd_addr.c stable/8/sys/netinet/sctp_bsd_addr.h stable/8/sys/netinet/sctp_constants.h stable/8/sys/netinet/sctp_indata.c stable/8/sys/netinet/sctp_input.c stable/8/sys/netinet/sctp_lock_bsd.h stable/8/sys/netinet/sctp_output.c stable/8/sys/netinet/sctp_pcb.c stable/8/sys/netinet/sctp_pcb.h stable/8/sys/netinet/sctp_structs.h stable/8/sys/netinet/sctp_sysctl.c stable/8/sys/netinet/sctp_timer.c stable/8/sys/netinet/sctp_usrreq.c stable/8/sys/netinet/sctputil.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/cddl/contrib/opensolaris/ (props changed) stable/8/sys/contrib/dev/acpica/ (props changed) stable/8/sys/contrib/pf/ (props changed) stable/8/sys/dev/xen/xenpci/ (props changed) stable/8/sys/geom/sched/ (props changed) Modified: stable/8/sys/netinet/sctp_auth.c ============================================================================== --- stable/8/sys/netinet/sctp_auth.c Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_auth.c Fri Jun 11 03:13:19 2010 (r209028) @@ -895,9 +895,9 @@ static inline int sctp_get_hmac_block_len(uint16_t hmac_algo) { switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: + case SCTP_AUTH_HMAC_ID_SHA1: #ifdef HAVE_SHA224 - case SCTP_AUTH_HMAC_ID_SHA224: + case SCTP_AUTH_HMAC_ID_SHA224: #endif return (64); #ifdef HAVE_SHA2 @@ -918,7 +918,7 @@ static void sctp_hmac_init(uint16_t hmac_algo, sctp_hash_context_t * ctx) { switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: + case SCTP_AUTH_HMAC_ID_SHA1: SHA1_Init(&ctx->sha1); break; #ifdef HAVE_SHA224 @@ -948,7 +948,7 @@ sctp_hmac_update(uint16_t hmac_algo, sct uint8_t * text, uint32_t textlen) { switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: + case SCTP_AUTH_HMAC_ID_SHA1: SHA1_Update(&ctx->sha1, text, textlen); break; #ifdef HAVE_SHA224 @@ -978,7 +978,7 @@ sctp_hmac_final(uint16_t hmac_algo, sctp uint8_t * digest) { switch (hmac_algo) { - case SCTP_AUTH_HMAC_ID_SHA1: + case SCTP_AUTH_HMAC_ID_SHA1: SHA1_Final(digest, &ctx->sha1); break; #ifdef HAVE_SHA224 Modified: stable/8/sys/netinet/sctp_bsd_addr.c ============================================================================== --- stable/8/sys/netinet/sctp_bsd_addr.c Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_bsd_addr.c Fri Jun 11 03:13:19 2010 (r209028) @@ -49,16 +49,6 @@ __FBSDID("$FreeBSD$"); #include <sys/unistd.h> /* Declare all of our malloc named types */ - -/* Note to Michael/Peter for mac-os, - * I think mac has this too since I - * do see the M_PCB type, so I - * will also put in the mac file the - * MALLOC_DECLARE. If this does not - * work for mac uncomment the defines for - * the strings that we use in Panda, I put - * them in comments in the mac-os file. - */ MALLOC_DEFINE(SCTP_M_MAP, "sctp_map", "sctp asoc map descriptor"); MALLOC_DEFINE(SCTP_M_STRMI, "sctp_stri", "sctp stream in array"); MALLOC_DEFINE(SCTP_M_STRMO, "sctp_stro", "sctp stream out array"); @@ -79,47 +69,77 @@ MALLOC_DEFINE(SCTP_M_MVRF, "sctp_mvrf", MALLOC_DEFINE(SCTP_M_ITER, "sctp_iter", "sctp iterator control"); MALLOC_DEFINE(SCTP_M_SOCKOPT, "sctp_socko", "sctp socket option"); -#if defined(SCTP_USE_THREAD_BASED_ITERATOR) +/* Global NON-VNET structure that controls the iterator */ +struct iterator_control sctp_it_ctl; +static int __sctp_thread_based_iterator_started = 0; + + +static void +sctp_cleanup_itqueue(void) +{ + struct sctp_iterator *it; + + while ((it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead)) != NULL) { + if (it->function_atend != NULL) { + (*it->function_atend) (it->pointer, it->val); + } + TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, it, sctp_nxt_itr); + SCTP_FREE(it, SCTP_M_ITER); + } +} + + void sctp_wakeup_iterator(void) { - wakeup(&SCTP_BASE_INFO(iterator_running)); + wakeup(&sctp_it_ctl.iterator_running); } static void sctp_iterator_thread(void *v) { - CURVNET_SET((struct vnet *)v); SCTP_IPI_ITERATOR_WQ_LOCK(); - SCTP_BASE_INFO(iterator_running) = 0; while (1) { - msleep(&SCTP_BASE_INFO(iterator_running), - &SCTP_BASE_INFO(ipi_iterator_wq_mtx), + msleep(&sctp_it_ctl.iterator_running, + &sctp_it_ctl.ipi_iterator_wq_mtx, 0, "waiting_for_work", 0); - if (SCTP_BASE_INFO(threads_must_exit)) { + if (sctp_it_ctl.iterator_flags & SCTP_ITERATOR_MUST_EXIT) { SCTP_IPI_ITERATOR_WQ_DESTROY(); + SCTP_ITERATOR_LOCK_DESTROY(); + sctp_cleanup_itqueue(); + __sctp_thread_based_iterator_started = 0; kthread_exit(); } sctp_iterator_worker(); } - CURVNET_RESTORE(); } void sctp_startup_iterator(void) { + if (__sctp_thread_based_iterator_started) { + /* You only get one */ + return; + } + /* init the iterator head */ + __sctp_thread_based_iterator_started = 1; + sctp_it_ctl.iterator_running = 0; + sctp_it_ctl.iterator_flags = 0; + sctp_it_ctl.cur_it = NULL; + SCTP_ITERATOR_LOCK_INIT(); + SCTP_IPI_ITERATOR_WQ_INIT(); + TAILQ_INIT(&sctp_it_ctl.iteratorhead); + int ret; ret = kproc_create(sctp_iterator_thread, - (void *)curvnet, - &SCTP_BASE_INFO(thread_proc), + (void *)NULL, + &sctp_it_ctl.thread_proc, RFPROC, SCTP_KTHREAD_PAGES, SCTP_KTRHEAD_NAME); } -#endif - #ifdef INET6 void Modified: stable/8/sys/netinet/sctp_bsd_addr.h ============================================================================== --- stable/8/sys/netinet/sctp_bsd_addr.h Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_bsd_addr.h Fri Jun 11 03:13:19 2010 (r209028) @@ -37,12 +37,11 @@ __FBSDID("$FreeBSD$"); #if defined(_KERNEL) || defined(__Userspace__) -#if defined(SCTP_USE_THREAD_BASED_ITERATOR) +extern struct iterator_control sctp_it_ctl; void sctp_wakeup_iterator(void); void sctp_startup_iterator(void); -#endif #ifdef INET6 void sctp_gather_internal_ifa_flags(struct sctp_ifa *ifa); Modified: stable/8/sys/netinet/sctp_constants.h ============================================================================== --- stable/8/sys/netinet/sctp_constants.h Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_constants.h Fri Jun 11 03:13:19 2010 (r209028) @@ -87,10 +87,6 @@ __FBSDID("$FreeBSD$"); /* #define SCTP_AUDITING_ENABLED 1 used for debug/auditing */ #define SCTP_AUDIT_SIZE 256 -/* temporary disabled since it does not work with VNET. */ -#if 0 -#define SCTP_USE_THREAD_BASED_ITERATOR 1 -#endif #define SCTP_KTRHEAD_NAME "sctp_iterator" #define SCTP_KTHREAD_PAGES 0 @@ -572,7 +568,6 @@ __FBSDID("$FreeBSD$"); #define SCTP_TIMER_TYPE_EVENTWAKE 13 #define SCTP_TIMER_TYPE_STRRESET 14 #define SCTP_TIMER_TYPE_INPKILL 15 -#define SCTP_TIMER_TYPE_ITERATOR 16 #define SCTP_TIMER_TYPE_EARLYFR 17 #define SCTP_TIMER_TYPE_ASOCKILL 18 #define SCTP_TIMER_TYPE_ADDR_WQ 19 @@ -899,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 /* second argument */ #define SCTP_FREE_SHOULD_USE_ABORT 1 #define SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE 0 Modified: stable/8/sys/netinet/sctp_indata.c ============================================================================== --- stable/8/sys/netinet/sctp_indata.c Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_indata.c Fri Jun 11 03:13:19 2010 (r209028) @@ -289,12 +289,20 @@ sctp_build_ctl_cchunk(struct sctp_inpcb static void sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn) { - uint32_t gap, i; + uint32_t gap, i, cumackp1; int fnd = 0; if (SCTP_BASE_SYSCTL(sctp_do_drain) == 0) { return; } + cumackp1 = asoc->cumulative_tsn + 1; + if (compare_with_wrap(cumackp1, tsn, MAX_TSN)) { + /* + * this tsn is behind the cum ack and thus we don't need to + * worry about it being moved from one to the other. + */ + return; + } SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn); if (!SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap)) { printf("gap:%x tsn:%x\n", gap, tsn); @@ -2245,15 +2253,19 @@ sctp_slide_mapping_arrays(struct sctp_tc /* * Now we also need to check the mapping array in a couple of ways. * 1) Did we move the cum-ack point? + * + * When you first glance at this you might think that all entries that + * make up the postion of the cum-ack would be in the nr-mapping + * array only.. i.e. things up to the cum-ack are always + * deliverable. Thats true with one exception, when its a fragmented + * message we may not deliver the data until some threshold (or all + * of it) is in place. So we must OR the nr_mapping_array and + * mapping_array to get a true picture of the cum-ack. */ struct sctp_association *asoc; int at; + uint8_t val; int slide_from, slide_end, lgap, distance; - - /* EY nr_mapping array variables */ - /* int nr_at; */ - /* int nr_last_all_ones = 0; */ - /* int nr_slide_from, nr_slide_end, nr_lgap, nr_distance; */ uint32_t old_cumack, old_base, old_highest, highest_tsn; asoc = &stcb->asoc; @@ -2268,11 +2280,12 @@ sctp_slide_mapping_arrays(struct sctp_tc */ at = 0; for (slide_from = 0; slide_from < stcb->asoc.mapping_array_size; slide_from++) { - if (asoc->nr_mapping_array[slide_from] == 0xff) { + val = asoc->nr_mapping_array[slide_from] | asoc->mapping_array[slide_from]; + if (val == 0xff) { at += 8; } else { /* there is a 0 bit */ - at += sctp_map_lookup_tab[asoc->nr_mapping_array[slide_from]]; + at += sctp_map_lookup_tab[val]; break; } } @@ -3849,7 +3862,8 @@ sctp_window_probe_recovery(struct sctp_t sctp_total_flight_decrease(stcb, tp1); /* Now mark for resend */ tp1->sent = SCTP_DATAGRAM_RESEND; - asoc->sent_queue_retran_cnt++; + sctp_ucount_incr(asoc->sent_queue_retran_cnt); + if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_WP, tp1->whoTo->flight_size, @@ -4262,7 +4276,7 @@ again: sctp_flight_size_increase(tp1); sctp_total_flight_increase(stcb, tp1); } else if (tp1->sent == SCTP_DATAGRAM_RESEND) { - asoc->sent_queue_retran_cnt++; + sctp_ucount_incr(asoc->sent_queue_retran_cnt); } } } @@ -5263,7 +5277,7 @@ again: sctp_flight_size_increase(tp1); sctp_total_flight_increase(stcb, tp1); } else if (tp1->sent == SCTP_DATAGRAM_RESEND) { - asoc->sent_queue_retran_cnt++; + sctp_ucount_incr(asoc->sent_queue_retran_cnt); } } } Modified: stable/8/sys/netinet/sctp_input.c ============================================================================== --- stable/8/sys/netinet/sctp_input.c Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_input.c Fri Jun 11 03:13:19 2010 (r209028) @@ -3067,7 +3067,7 @@ process_chunk_drop(struct sctp_tcb *stcb struct sctp_nets *net, uint8_t flg) { switch (desc->chunk_type) { - case SCTP_DATA: + case SCTP_DATA: /* find the tsn to resend (possibly */ { uint32_t tsn; @@ -4534,7 +4534,8 @@ process_control_chunks: if ((stcb) && (stcb->asoc.total_output_queue_size)) { ; } else { - if (locked_tcb) { + if (locked_tcb != stcb) { + /* Very unlikely */ SCTP_TCB_UNLOCK(locked_tcb); } *offset = length; @@ -4861,6 +4862,10 @@ process_control_chunks: } else { if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) { /* We are not interested anymore */ + abend: + if (stcb) { + SCTP_TCB_UNLOCK(stcb); + } *offset = length; return (NULL); } @@ -4908,6 +4913,11 @@ process_control_chunks: if (linp) { SCTP_ASOC_CREATE_LOCK(linp); + if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE)) { + SCTP_ASOC_CREATE_UNLOCK(linp); + goto abend; + } } if (netp) { ret_buf = @@ -5408,16 +5418,25 @@ sctp_process_ecn_marked_b(struct sctp_tc } #ifdef INVARIANTS -static void -sctp_validate_no_locks(struct sctp_inpcb *inp) +#ifdef __GNUC__ +__attribute__((noinline)) +#endif + void + sctp_validate_no_locks(struct sctp_inpcb *inp) { - struct sctp_tcb *stcb; + struct sctp_tcb *lstcb; - LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { - if (mtx_owned(&stcb->tcb_mtx)) { + LIST_FOREACH(lstcb, &inp->sctp_asoc_list, sctp_tcblist) { + if (mtx_owned(&lstcb->tcb_mtx)) { panic("Own lock on stcb at return from input"); } } + if (mtx_owned(&inp->inp_create_mtx)) { + panic("Own create lock on inp"); + } + if (mtx_owned(&inp->inp_mtx)) { + panic("Own inp lock on inp"); + } } #endif Modified: stable/8/sys/netinet/sctp_lock_bsd.h ============================================================================== --- stable/8/sys/netinet/sctp_lock_bsd.h Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_lock_bsd.h Fri Jun 11 03:13:19 2010 (r209028) @@ -107,42 +107,36 @@ extern int sctp_logoff_stuff; #define SCTP_INP_INFO_WUNLOCK() rw_wunlock(&SCTP_BASE_INFO(ipi_ep_mtx)) -#define SCTP_IPI_ADDR_INIT() \ +#define SCTP_IPI_ADDR_INIT() \ rw_init(&SCTP_BASE_INFO(ipi_addr_mtx), "sctp-addr") - #define SCTP_IPI_ADDR_DESTROY() do { \ if(rw_wowned(&SCTP_BASE_INFO(ipi_addr_mtx))) { \ rw_wunlock(&SCTP_BASE_INFO(ipi_addr_mtx)); \ } \ rw_destroy(&SCTP_BASE_INFO(ipi_addr_mtx)); \ } while (0) - - - #define SCTP_IPI_ADDR_RLOCK() do { \ rw_rlock(&SCTP_BASE_INFO(ipi_addr_mtx)); \ } while (0) - #define SCTP_IPI_ADDR_WLOCK() do { \ rw_wlock(&SCTP_BASE_INFO(ipi_addr_mtx)); \ } while (0) - #define SCTP_IPI_ADDR_RUNLOCK() rw_runlock(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ADDR_WUNLOCK() rw_wunlock(&SCTP_BASE_INFO(ipi_addr_mtx)) #define SCTP_IPI_ITERATOR_WQ_INIT() \ - mtx_init(&SCTP_BASE_INFO(ipi_iterator_wq_mtx), "sctp-it-wq", "sctp_it_wq", MTX_DEF) + mtx_init(&sctp_it_ctl.ipi_iterator_wq_mtx, "sctp-it-wq", "sctp_it_wq", MTX_DEF) #define SCTP_IPI_ITERATOR_WQ_DESTROY() \ - mtx_destroy(&SCTP_BASE_INFO(ipi_iterator_wq_mtx)) + mtx_destroy(&sctp_it_ctl.ipi_iterator_wq_mtx) #define SCTP_IPI_ITERATOR_WQ_LOCK() do { \ - mtx_lock(&SCTP_BASE_INFO(ipi_iterator_wq_mtx)); \ + mtx_lock(&sctp_it_ctl.ipi_iterator_wq_mtx); \ } while (0) -#define SCTP_IPI_ITERATOR_WQ_UNLOCK() mtx_unlock(&SCTP_BASE_INFO(ipi_iterator_wq_mtx)) +#define SCTP_IPI_ITERATOR_WQ_UNLOCK() mtx_unlock(&sctp_it_ctl.ipi_iterator_wq_mtx) #define SCTP_IP_PKTLOG_INIT() \ @@ -191,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) @@ -300,25 +301,45 @@ extern int sctp_logoff_stuff; #endif #define SCTP_ITERATOR_LOCK_INIT() \ - mtx_init(&SCTP_BASE_INFO(it_mtx), "sctp-it", "iterator", MTX_DEF) + mtx_init(&sctp_it_ctl.it_mtx, "sctp-it", "iterator", MTX_DEF) #ifdef INVARIANTS #define SCTP_ITERATOR_LOCK() \ do { \ - if (mtx_owned(&SCTP_BASE_INFO(it_mtx))) \ + if (mtx_owned(&sctp_it_ctl.it_mtx)) \ panic("Iterator Lock"); \ - mtx_lock(&SCTP_BASE_INFO(it_mtx)); \ + mtx_lock(&sctp_it_ctl.it_mtx); \ } while (0) #else #define SCTP_ITERATOR_LOCK() \ do { \ - mtx_lock(&SCTP_BASE_INFO(it_mtx)); \ + mtx_lock(&sctp_it_ctl.it_mtx); \ } while (0) #endif -#define SCTP_ITERATOR_UNLOCK() mtx_unlock(&SCTP_BASE_INFO(it_mtx)) -#define SCTP_ITERATOR_LOCK_DESTROY() mtx_destroy(&SCTP_BASE_INFO(it_mtx)) +#define SCTP_ITERATOR_UNLOCK() mtx_unlock(&sctp_it_ctl.it_mtx) +#define SCTP_ITERATOR_LOCK_DESTROY() mtx_destroy(&sctp_it_ctl.it_mtx) + + +#define SCTP_WQ_ADDR_INIT() do { \ + mtx_init(&SCTP_BASE_INFO(wq_addr_mtx), "sctp-addr-wq","sctp_addr_wq",MTX_DEF); \ + } while (0) + +#define SCTP_WQ_ADDR_DESTROY() do { \ + if(mtx_owned(&SCTP_BASE_INFO(wq_addr_mtx))) { \ + mtx_unlock(&SCTP_BASE_INFO(wq_addr_mtx)); \ + } \ + mtx_destroy(&SCTP_BASE_INFO(wq_addr_mtx)); \ + } while (0) + +#define SCTP_WQ_ADDR_LOCK() do { \ + mtx_lock(&SCTP_BASE_INFO(wq_addr_mtx)); \ +} while (0) +#define SCTP_WQ_ADDR_UNLOCK() do { \ + mtx_unlock(&SCTP_BASE_INFO(wq_addr_mtx)); \ +} while (0) + #define SCTP_INCR_EP_COUNT() \ Modified: stable/8/sys/netinet/sctp_output.c ============================================================================== --- stable/8/sys/netinet/sctp_output.c Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_output.c Fri Jun 11 03:13:19 2010 (r209028) @@ -3053,32 +3053,32 @@ sctp_source_address_selection(struct sct * it out * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz * For V4 - *------------------------------------------ + * ------------------------------------------ * source * dest * result * ----------------------------------------- * <a> Private * Global * NAT * ----------------------------------------- * <b> Private * Private * No problem * ----------------------------------------- - * <c> Global * Private * Huh, How will this work? + * <c> Global * Private * Huh, How will this work? * ----------------------------------------- - * <d> Global * Global * No Problem - *------------------------------------------ + * <d> Global * Global * No Problem + *------------------------------------------ * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz * For V6 - *------------------------------------------ + *------------------------------------------ * source * dest * result * ----------------------------------------- * <a> Linklocal * Global * * ----------------------------------------- * <b> Linklocal * Linklocal * No problem * ----------------------------------------- - * <c> Global * Linklocal * Huh, How will this work? + * <c> Global * Linklocal * Huh, How will this work? * ----------------------------------------- - * <d> Global * Global * No Problem - *------------------------------------------ + * <d> Global * Global * No Problem + *------------------------------------------ * zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz - * + * * And then we add to that what happens if there are multiple addresses * assigned to an interface. Remember the ifa on a ifn is a linked * list of addresses. So one interface can have more than one IP @@ -3091,13 +3091,13 @@ sctp_source_address_selection(struct sct * Decisions: * * - count the number of addresses on the interface. - * - if it is one, no problem except case <c>. - * For <a> we will assume a NAT out there. + * - if it is one, no problem except case <c>. + * For <a> we will assume a NAT out there. * - if there are more than one, then we need to worry about scope P * or G. We should prefer G -> G and P -> P if possible. * Then as a secondary fall back to mixed types G->P being a last * ditch one. - * - The above all works for bound all, but bound specific we need to + * - The above all works for bound all, but bound specific we need to * use the same concept but instead only consider the bound * addresses. If the bound set is NOT assigned to the interface then * we must use rotation amongst the bound addresses.. @@ -8913,6 +8913,9 @@ sctp_chunk_retransmission(struct sctp_in if ((chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) || (chk->rec.chunk_id.id == SCTP_STREAM_RESET) || (chk->rec.chunk_id.id == SCTP_FORWARD_CUM_TSN)) { + if (chk->sent != SCTP_DATAGRAM_RESEND) { + continue; + } if (chk->rec.chunk_id.id == SCTP_STREAM_RESET) { if (chk != asoc->str_reset) { /* @@ -8973,7 +8976,7 @@ sctp_chunk_retransmission(struct sctp_in /* (void)SCTP_GETTIME_TIMEVAL(&chk->whoTo->last_sent_time); */ *cnt_out += 1; chk->sent = SCTP_DATAGRAM_SENT; - /* sctp_ucount_decr(asoc->sent_queue_retran_cnt); */ + sctp_ucount_decr(stcb->asoc.sent_queue_retran_cnt); if (fwd_tsn == 0) { return (0); } else { @@ -13427,6 +13430,13 @@ out_unlocked: } } #endif +#ifdef INVARIANTS + if (inp) { + sctp_validate_no_locks(inp); + } else { + printf("Warning - inp is NULL so cant validate locks\n"); + } +#endif if (top) { sctp_m_freem(top); } Modified: stable/8/sys/netinet/sctp_pcb.c ============================================================================== --- stable/8/sys/netinet/sctp_pcb.c Fri Jun 11 03:00:48 2010 (r209027) +++ stable/8/sys/netinet/sctp_pcb.c Fri Jun 11 03:13:19 2010 (r209028) @@ -692,13 +692,11 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, vo (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); wi->ifa = sctp_ifap; wi->action = SCTP_ADD_IP_ADDRESS; - SCTP_IPI_ITERATOR_WQ_LOCK(); - /* - * Should this really be a tailq? As it is we will process - * the newest first :-0 - */ + + SCTP_WQ_ADDR_LOCK(); LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - SCTP_IPI_ITERATOR_WQ_UNLOCK(); + SCTP_WQ_ADDR_UNLOCK(); + sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, (struct sctp_inpcb *)NULL, (struct sctp_tcb *)NULL, @@ -806,13 +804,13 @@ out_now: (void)SCTP_GETTIME_TIMEVAL(&wi->start_time); wi->ifa = sctp_ifap; wi->action = SCTP_DEL_IP_ADDRESS; - SCTP_IPI_ITERATOR_WQ_LOCK(); + SCTP_WQ_ADDR_LOCK(); /* * Should this really be a tailq? As it is we will process * the newest first :-0 */ LIST_INSERT_HEAD(&SCTP_BASE_INFO(addr_wq), wi, sctp_nxt_addr); - SCTP_IPI_ITERATOR_WQ_UNLOCK(); + SCTP_WQ_ADDR_UNLOCK(); sctp_timer_start(SCTP_TIMER_TYPE_ADDR_WQ, (struct sctp_inpcb *)NULL, @@ -2298,7 +2296,7 @@ sctp_inpcb_alloc(struct socket *so, uint 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 { @@ -2340,6 +2338,7 @@ sctp_inpcb_alloc(struct socket *so, uint * in protosw */ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP); + so->so_pcb = NULL; SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); return (EOPNOTSUPP); } @@ -2358,6 +2357,7 @@ sctp_inpcb_alloc(struct socket *so, uint if (inp->sctp_tcbhash == NULL) { SCTP_PRINTF("Out of SCTP-INPCB->hashinit - no resources\n"); SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS); + so->so_pcb = NULL; SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_ep), inp); return (ENOBUFS); } @@ -3017,57 +3017,68 @@ continue_anyway: static void -sctp_iterator_inp_being_freed(struct sctp_inpcb *inp, struct sctp_inpcb *inp_next) +sctp_iterator_inp_being_freed(struct sctp_inpcb *inp) { - struct sctp_iterator *it; + struct sctp_iterator *it, *nit; /* * We enter with the only the ITERATOR_LOCK in place and a write * lock on the inp_info stuff. */ - + it = sctp_it_ctl.cur_it; + if (it && (it->vn != curvnet)) { + /* Its not looking at our VNET */ + return; + } + if (it && (it->inp == inp)) { + /* + * This is tricky and we hold the iterator lock, but when it + * returns and gets the lock (when we release it) the + * iterator will try to operate on inp. We need to stop that + * from happening. But of course the iterator has a + * reference on the stcb and inp. We can mark it and it will + * stop. + * + * If its a single iterator situation, we set the end iterator + * flag. Otherwise we set the iterator to go to the next + * inp. + * + */ + if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { + sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_STOP_CUR_IT; + } else { + sctp_it_ctl.iterator_flags |= SCTP_ITERATOR_STOP_CUR_INP; + } + } /* - * Go through all iterators, we must do this since it is possible - * that some iterator does NOT have the lock, but is waiting for it. - * And the one that had the lock has either moved in the last - * iteration or we just cleared it above. We need to find all of - * those guys. The list of iterators should never be very big - * though. - */ - TAILQ_FOREACH(it, &SCTP_BASE_INFO(iteratorhead), sctp_nxt_itr) { - if (it == inp->inp_starting_point_for_iterator) - /* skip this guy, he's special */ + * Now go through and remove any single reference to our inp that + * may be still pending on the list + */ + SCTP_IPI_ITERATOR_WQ_LOCK(); + it = TAILQ_FIRST(&sctp_it_ctl.iteratorhead); + while (it) { + nit = TAILQ_NEXT(it, sctp_nxt_itr); + if (it->vn != curvnet) { + it = nit; continue; + } if (it->inp == inp) { - /* - * This is tricky and we DON'T lock the iterator. - * Reason is he's running but waiting for me since - * inp->inp_starting_point_for_iterator has the lock - * on me (the guy above we skipped). This tells us - * its is not running but waiting for - * inp->inp_starting_point_for_iterator to be - * released by the guy that does have our INP in a - * lock. - */ + /* This one points to me is it inp specific? */ if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { - it->inp = NULL; - it->stcb = NULL; + /* Remove and free this one */ + TAILQ_REMOVE(&sctp_it_ctl.iteratorhead, + it, sctp_nxt_itr); + if (it->function_atend != NULL) { + (*it->function_atend) (it->pointer, it->val); + } + SCTP_FREE(it, SCTP_M_ITER); } else { - /* set him up to do the next guy not me */ - it->inp = inp_next; - it->stcb = NULL; + it->inp = LIST_NEXT(it->inp, sctp_list); } } + it = nit; } - it = inp->inp_starting_point_for_iterator; - if (it) { - if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) { - it->inp = NULL; - } else { - it->inp = inp_next; - } - it->stcb = NULL; - } + SCTP_IPI_ITERATOR_WQ_UNLOCK(); } /* release sctp_inpcb unbind the port */ @@ -3083,12 +3094,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, * all associations. d) finally the ep itself. */ struct sctp_pcb *m; - struct sctp_inpcb *inp_save; struct sctp_tcb *asoc, *nasoc; struct sctp_laddr *laddr, *nladdr; struct inpcb *ip_pcb; struct socket *so; - + int being_refed = 0; struct sctp_queued_to_read *sq; @@ -3099,12 +3109,21 @@ sctp_inpcb_free(struct sctp_inpcb *inp, #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 0); #endif - SCTP_ITERATOR_LOCK(); + 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(); + /* 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); - SCTP_ITERATOR_UNLOCK(); #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 1); #endif @@ -3114,19 +3133,15 @@ sctp_inpcb_free(struct sctp_inpcb *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. - */ inp->sctp_flags &= ~SCTP_PCB_FLAGS_CLOSE_IP; /* socket is gone, so no more wakeups allowed */ inp->sctp_flags |= SCTP_PCB_FLAGS_DONT_WAKE; inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; + } + /* 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); @@ -3152,8 +3167,17 @@ sctp_inpcb_free(struct sctp_inpcb *inp, nasoc = LIST_NEXT(asoc, sctp_tcblist); if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { /* Skip guys being freed */ - /* asoc->sctp_socket = NULL; FIXME MT */ cnt_in_sd++; + if (asoc->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) { + /* + * Special case - we did not start a + * kill timer on the asoc due to it + * was not closed. So go ahead and + * start it now. + */ + asoc->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; + sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, asoc, NULL); + } SCTP_TCB_UNLOCK(asoc); continue; } @@ -3314,14 +3338,13 @@ sctp_inpcb_free(struct sctp_inpcb *inp, } /* now is there some left in our SHUTDOWN state? */ if (cnt_in_sd) { - 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 inp->sctp_socket = NULL; + SCTP_INP_WUNLOCK(inp); + SCTP_ASOC_CREATE_UNLOCK(inp); + SCTP_INP_INFO_WUNLOCK(); return; } } @@ -3344,6 +3367,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, asoc = nasoc) { nasoc = LIST_NEXT(asoc, sctp_tcblist); if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { + if (asoc->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE) { + asoc->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; + sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, asoc, NULL); + } cnt++; continue; } @@ -3392,38 +3419,62 @@ sctp_inpcb_free(struct sctp_inpcb *inp, if (cnt) { /* Ok we have someone out there that will kill us */ (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer); - 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 + SCTP_INP_WUNLOCK(inp); + SCTP_ASOC_CREATE_UNLOCK(inp); + SCTP_INP_INFO_WUNLOCK(); return; } - if ((inp->refcount) || (inp->sctp_flags & SCTP_PCB_FLAGS_CLOSE_IP)) { + 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) || + (being_refed) || + (inp->sctp_flags & SCTP_PCB_FLAGS_CLOSE_IP)) { (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer); +#ifdef SCTP_LOG_CLOSING + sctp_log_closing(inp, NULL, 4); +#endif sctp_timer_start(SCTP_TIMER_TYPE_INPKILL, inp, NULL, NULL); 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 return; } - (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer); inp->sctp_ep.signature_change.type = 0; inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_ALLGONE; + /* + * Remove it from the list .. last thing we need a lock for. + */ + LIST_REMOVE(inp, sctp_list); + SCTP_INP_WUNLOCK(inp); + SCTP_ASOC_CREATE_UNLOCK(inp); + SCTP_INP_INFO_WUNLOCK(); + /* + * Now we release all locks. Since this INP cannot be found anymore + * except possbily by the kill timer that might be running. We call + * the drain function here. It should hit the case were it sees the + * ACTIVE flag cleared and exit out freeing us to proceed and + * destroy everything. + */ + if (from != SCTP_CALLED_FROM_INPKILL_TIMER) { + (void)SCTP_OS_TIMER_STOP_DRAIN(&inp->sctp_ep.signature_change.timer); + } else { + /* Probably un-needed */ + (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer); + } #ifdef SCTP_LOG_CLOSING sctp_log_closing(inp, NULL, 5); #endif - (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer); - inp->sctp_ep.signature_change.type = SCTP_TIMER_TYPE_NONE; - /* Clear the read queue */ + if ((inp->sctp_asocidhash) != NULL) { SCTP_HASH_FREE(inp->sctp_asocidhash, inp->hashasocidmark); inp->sctp_asocidhash = NULL; @@ -3494,11 +3545,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, shared_key = LIST_FIRST(&inp->sctp_ep.shared_keys); } - inp_save = LIST_NEXT(inp, sctp_list); - LIST_REMOVE(inp, sctp_list); - - /* fix any iterators only after out of the list */ - sctp_iterator_inp_being_freed(inp, inp_save); /* * if we have an address list the following will free the list of * ifaddr's that are set into this ep. Again macro limitations here, @@ -3531,8 +3577,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, SCTP_INP_LOCK_DESTROY(inp); 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(); } @@ -4581,8 +4625,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, * Someone holds a reference OR the socket is unaccepted * yet. */ - if (stcb->asoc.refcnt) + if ((stcb->asoc.refcnt) || + (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || + (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { + stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL); + } SCTP_TCB_UNLOCK(stcb); if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) @@ -4645,8 +4693,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, SS_ISCONFIRMING | SS_ISCONNECTED); } - SOCK_UNLOCK(so); - socantrcvmore(so); + socantrcvmore_locked(so); sctp_sowwakeup(inp, so); sctp_sorwakeup(inp, so); SCTP_SOWAKEUP(so); @@ -5436,8 +5483,6 @@ sctp_pcb_init() /* init the empty list of (All) Endpoints */ LIST_INIT(&SCTP_BASE_INFO(listhead)); - /* init the iterator head */ - TAILQ_INIT(&SCTP_BASE_INFO(iteratorhead)); /* init the hash table of endpoints */ TUNABLE_INT_FETCH("net.inet.sctp.tcbhashsize", &SCTP_BASE_SYSCTL(sctp_hashtblsize)); @@ -5500,16 +5545,15 @@ sctp_pcb_init() /* Master Lock INIT for info structure */ SCTP_INP_INFO_LOCK_INIT(); SCTP_STATLOG_INIT_LOCK(); - SCTP_ITERATOR_LOCK_INIT(); SCTP_IPI_COUNT_INIT(); SCTP_IPI_ADDR_INIT(); - SCTP_IPI_ITERATOR_WQ_INIT(); #ifdef SCTP_PACKET_LOGGING SCTP_IP_PKTLOG_INIT(); #endif LIST_INIT(&SCTP_BASE_INFO(addr_wq)); + SCTP_WQ_ADDR_INIT(); /* not sure if we need all the counts */ SCTP_BASE_INFO(ipi_count_ep) = 0; /* assoc/tcb zone info */ @@ -5537,11 +5581,7 @@ sctp_pcb_init() LIST_INIT(&SCTP_BASE_INFO(vtag_timewait)[i]); } *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201006110313.o5B3DKhQ048446>