From owner-svn-src-all@FreeBSD.ORG Fri Feb 10 19:56:02 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 813FC106566B; Fri, 10 Feb 2012 19:56:02 +0000 (UTC) (envelope-from tuexen@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 693438FC13; Fri, 10 Feb 2012 19:56:02 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q1AJu2Dj091209; Fri, 10 Feb 2012 19:56:02 GMT (envelope-from tuexen@svn.freebsd.org) Received: (from tuexen@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q1AJu28J091206; Fri, 10 Feb 2012 19:56:02 GMT (envelope-from tuexen@svn.freebsd.org) Message-Id: <201202101956.q1AJu28J091206@svn.freebsd.org> From: Michael Tuexen Date: Fri, 10 Feb 2012 19:56:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org X-SVN-Group: stable-8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r231417 - stable/8/sys/netinet X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 10 Feb 2012 19:56:02 -0000 Author: tuexen Date: Fri Feb 10 19:56:02 2012 New Revision: 231417 URL: http://svn.freebsd.org/changeset/base/231417 Log: MFC r218639: Fix several bugs related to stream scheduling. Obtained from: Robin Seggelmann Modified: stable/8/sys/netinet/sctp_ss_functions.c Directory Properties: stable/8/sys/ (props changed) stable/8/sys/amd64/include/xen/ (props changed) stable/8/sys/boot/ (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/e1000/ (props changed) Modified: stable/8/sys/netinet/sctp_ss_functions.c ============================================================================== --- stable/8/sys/netinet/sctp_ss_functions.c Fri Feb 10 19:54:18 2012 (r231416) +++ stable/8/sys/netinet/sctp_ss_functions.c Fri Feb 10 19:56:02 2012 (r231417) @@ -59,11 +59,9 @@ sctp_ss_default_init(struct sctp_tcb *st * stream queues to the wheel. */ for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - sctp_ss_default_add(stcb, &stcb->asoc, - &stcb->asoc.strmout[i], - NULL, holds_lock); - } + stcb->asoc.ss_functions.sctp_ss_add_to_stream(stcb, &stcb->asoc, + &stcb->asoc.strmout[i], + NULL, holds_lock); } return; } @@ -72,14 +70,19 @@ static void sctp_ss_default_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, int clear_values, int holds_lock) { - uint16_t i; + if (holds_lock == 0) { + SCTP_TCB_SEND_LOCK(stcb); + } + while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { + struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - sctp_ss_default_remove(stcb, &stcb->asoc, - &stcb->asoc.strmout[i], - NULL, holds_lock); - } + TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.rr.next_spoke); + strq->ss_params.rr.next_spoke.tqe_next = NULL; + strq->ss_params.rr.next_spoke.tqe_prev = NULL; + } + asoc->last_out_stream = NULL; + if (holds_lock == 0) { + SCTP_TCB_SEND_UNLOCK(stcb); } return; } @@ -100,7 +103,9 @@ sctp_ss_default_add(struct sctp_tcb *stc if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) && + /* Add to wheel if not already on it and stream queue not empty */ + if (!TAILQ_EMPTY(&strq->outqueue) && + (strq->ss_params.rr.next_spoke.tqe_next == NULL) && (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); @@ -126,11 +131,16 @@ sctp_ss_default_remove(struct sctp_tcb * struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, int holds_lock) { - /* take off and then setup so we know it is not on the wheel */ if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - if (TAILQ_EMPTY(&strq->outqueue)) { + /* + * Remove from wheel if stream queue is empty and actually is on the + * wheel + */ + if (TAILQ_EMPTY(&strq->outqueue) && + (strq->ss_params.rr.next_spoke.tqe_next != NULL || + strq->ss_params.rr.next_spoke.tqe_prev != NULL)) { if (asoc->last_out_stream == strq) { asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead, @@ -244,7 +254,8 @@ sctp_ss_rr_add(struct sctp_tcb *stcb, st if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) && + if (!TAILQ_EMPTY(&strq->outqueue) && + (strq->ss_params.rr.next_spoke.tqe_next == NULL) && (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); @@ -271,48 +282,20 @@ sctp_ss_rr_add(struct sctp_tcb *stcb, st * Always interates the streams in ascending order and * only fills messages of the same stream in a packet. */ -static void -sctp_ss_rrp_add(struct sctp_tcb *stcb, struct sctp_association *asoc, - struct sctp_stream_out *strq, - struct sctp_stream_queue_pending *sp, int holds_lock) +static struct sctp_stream_out * +sctp_ss_rrp_select(struct sctp_tcb *stcb, struct sctp_nets *net, + struct sctp_association *asoc) { - struct sctp_stream_out *strqt; - - if (holds_lock == 0) { - SCTP_TCB_SEND_LOCK(stcb); - } - if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) && - (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { - if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { - TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); - } else { - strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); - while (strqt != NULL && strqt->stream_no < strq->stream_no) { - strqt = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); - } - if (strqt != NULL) { - TAILQ_INSERT_BEFORE(strqt, strq, ss_params.rr.next_spoke); - } else { - TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); - } - } - } - if (holds_lock == 0) { - SCTP_TCB_SEND_UNLOCK(stcb); - } - return; + return asoc->last_out_stream; } -static struct sctp_stream_out * -sctp_ss_rrp_select(struct sctp_tcb *stcb, struct sctp_nets *net, +static void +sctp_ss_rrp_packet_done(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_association *asoc) { struct sctp_stream_out *strq, *strqt; strqt = asoc->last_out_stream; - if (strqt != NULL && !TAILQ_EMPTY(&strqt->outqueue)) { - return (strqt); - } rrp_again: /* Find the next stream to use */ if (strqt == NULL) { @@ -339,53 +322,13 @@ rrp_again: TAILQ_FIRST(&strq->outqueue)->net != NULL && TAILQ_FIRST(&strq->outqueue)->net != net) { if (strq == asoc->last_out_stream) { - return (NULL); + strq = NULL; } else { strqt = strq; goto rrp_again; } } } - return (strq); -} - -static void -sctp_ss_rrp_packet_done(struct sctp_tcb *stcb, struct sctp_nets *net, - struct sctp_association *asoc) -{ - struct sctp_stream_out *strq, *strqt; - - strqt = asoc->last_out_stream; -rrp_pd_again: - /* Find the next stream to use */ - if (strqt == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); - } else { - strq = TAILQ_NEXT(strqt, ss_params.rr.next_spoke); - if (strq == NULL) { - strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); - } - } - - /* - * If CMT is off, we must validate that the stream in question has - * the first item pointed towards are network destination requested - * by the caller. Note that if we turn out to be locked to a stream - * (assigning TSN's then we must stop, since we cannot look for - * another stream with data to send to that destination). In CMT's - * case, by skipping this check, we will send one data packet - * towards the requested net. - */ - if ((strq != NULL) && TAILQ_FIRST(&strq->outqueue) && - (net != NULL && TAILQ_FIRST(&strq->outqueue)->net != net) && - (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0)) { - if (strq == asoc->last_out_stream) { - strq = NULL; - } else { - strqt = strq; - goto rrp_pd_again; - } - } asoc->last_out_stream = strq; return; } @@ -399,14 +342,23 @@ static void sctp_ss_prio_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, int clear_values, int holds_lock) { - uint16_t i; + if (holds_lock == 0) { + SCTP_TCB_SEND_LOCK(stcb); + } + while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { + struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - if (clear_values) - stcb->asoc.strmout[i].ss_params.prio.priority = 0; - sctp_ss_default_remove(stcb, &stcb->asoc, &stcb->asoc.strmout[i], NULL, holds_lock); + if (clear_values) { + strq->ss_params.prio.priority = 0; } + TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.prio.next_spoke); + strq->ss_params.prio.next_spoke.tqe_next = NULL; + strq->ss_params.prio.next_spoke.tqe_prev = NULL; + + } + asoc->last_out_stream = NULL; + if (holds_lock == 0) { + SCTP_TCB_SEND_UNLOCK(stcb); } return; } @@ -434,7 +386,9 @@ sctp_ss_prio_add(struct sctp_tcb *stcb, if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - if ((strq->ss_params.prio.next_spoke.tqe_next == NULL) && + /* Add to wheel if not already on it and stream queue not empty */ + if (!TAILQ_EMPTY(&strq->outqueue) && + (strq->ss_params.prio.next_spoke.tqe_next == NULL) && (strq->ss_params.prio.next_spoke.tqe_prev == NULL)) { if (TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { TAILQ_INSERT_HEAD(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke); @@ -461,11 +415,16 @@ sctp_ss_prio_remove(struct sctp_tcb *stc struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, int holds_lock) { - /* take off and then setup so we know it is not on the wheel */ if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - if (TAILQ_EMPTY(&strq->outqueue)) { + /* + * Remove from wheel if stream queue is empty and actually is on the + * wheel + */ + if (TAILQ_EMPTY(&strq->outqueue) && + (strq->ss_params.prio.next_spoke.tqe_next != NULL || + strq->ss_params.prio.next_spoke.tqe_prev != NULL)) { if (asoc->last_out_stream == strq) { asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead, ss_params.prio.next_spoke); @@ -477,7 +436,7 @@ sctp_ss_prio_remove(struct sctp_tcb *stc asoc->last_out_stream = NULL; } } - TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); + TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.prio.next_spoke); strq->ss_params.prio.next_spoke.tqe_next = NULL; strq->ss_params.prio.next_spoke.tqe_prev = NULL; } @@ -502,7 +461,7 @@ prio_again: strqn = TAILQ_NEXT(strqt, ss_params.prio.next_spoke); if (strqn != NULL && strqn->ss_params.prio.priority == strqt->ss_params.prio.priority) { - strq = TAILQ_NEXT(strqt, ss_params.prio.next_spoke); + strq = strqn; } else { strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); } @@ -565,15 +524,22 @@ static void sctp_ss_fb_clear(struct sctp_tcb *stcb, struct sctp_association *asoc, int clear_values, int holds_lock) { - uint16_t i; + if (holds_lock == 0) { + SCTP_TCB_SEND_LOCK(stcb); + } + while (!TAILQ_EMPTY(&asoc->ss_data.out_wheel)) { + struct sctp_stream_out *strq = TAILQ_FIRST(&asoc->ss_data.out_wheel); - for (i = 0; i < stcb->asoc.streamoutcnt; i++) { - if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { - if (clear_values) { - stcb->asoc.strmout[i].ss_params.fb.rounds = -1; - } - sctp_ss_default_remove(stcb, &stcb->asoc, &stcb->asoc.strmout[i], NULL, holds_lock); + if (clear_values) { + strq->ss_params.fb.rounds = -1; } + TAILQ_REMOVE(&asoc->ss_data.out_wheel, TAILQ_FIRST(&asoc->ss_data.out_wheel), ss_params.fb.next_spoke); + strq->ss_params.fb.next_spoke.tqe_next = NULL; + strq->ss_params.fb.next_spoke.tqe_prev = NULL; + } + asoc->last_out_stream = NULL; + if (holds_lock == 0) { + SCTP_TCB_SEND_UNLOCK(stcb); } return; } @@ -599,11 +565,12 @@ sctp_ss_fb_add(struct sctp_tcb *stcb, st if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - if ((strq->ss_params.rr.next_spoke.tqe_next == NULL) && - (strq->ss_params.rr.next_spoke.tqe_prev == NULL)) { - if (!TAILQ_EMPTY(&strq->outqueue) && strq->ss_params.fb.rounds < 0) + if (!TAILQ_EMPTY(&strq->outqueue) && + (strq->ss_params.fb.next_spoke.tqe_next == NULL) && + (strq->ss_params.fb.next_spoke.tqe_prev == NULL)) { + if (strq->ss_params.fb.rounds < 0) strq->ss_params.fb.rounds = TAILQ_FIRST(&strq->outqueue)->length; - TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.rr.next_spoke); + TAILQ_INSERT_TAIL(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke); } if (holds_lock == 0) { SCTP_TCB_SEND_UNLOCK(stcb); @@ -616,11 +583,16 @@ sctp_ss_fb_remove(struct sctp_tcb *stcb, struct sctp_stream_out *strq, struct sctp_stream_queue_pending *sp, int holds_lock) { - /* take off and then setup so we know it is not on the wheel */ if (holds_lock == 0) { SCTP_TCB_SEND_LOCK(stcb); } - if (TAILQ_EMPTY(&strq->outqueue)) { + /* + * Remove from wheel if stream queue is empty and actually is on the + * wheel + */ + if (TAILQ_EMPTY(&strq->outqueue) && + (strq->ss_params.fb.next_spoke.tqe_next != NULL || + strq->ss_params.fb.next_spoke.tqe_prev != NULL)) { if (asoc->last_out_stream == strq) { asoc->last_out_stream = TAILQ_PREV(asoc->last_out_stream, sctpwheel_listhead, ss_params.fb.next_spoke); @@ -632,7 +604,6 @@ sctp_ss_fb_remove(struct sctp_tcb *stcb, asoc->last_out_stream = NULL; } } - strq->ss_params.fb.rounds = -1; TAILQ_REMOVE(&asoc->ss_data.out_wheel, strq, ss_params.fb.next_spoke); strq->ss_params.fb.next_spoke.tqe_next = NULL; strq->ss_params.fb.next_spoke.tqe_prev = NULL; @@ -649,20 +620,19 @@ sctp_ss_fb_select(struct sctp_tcb *stcb, { struct sctp_stream_out *strq = NULL, *strqt; - if (TAILQ_FIRST(&asoc->ss_data.out_wheel) == TAILQ_LAST(&asoc->ss_data.out_wheel, sctpwheel_listhead)) { + if (asoc->last_out_stream == NULL || + TAILQ_FIRST(&asoc->ss_data.out_wheel) == TAILQ_LAST(&asoc->ss_data.out_wheel, sctpwheel_listhead)) { strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); } else { - if (asoc->last_out_stream != NULL) { - strqt = TAILQ_NEXT(asoc->last_out_stream, ss_params.fb.next_spoke); - } else { - strqt = TAILQ_FIRST(&asoc->ss_data.out_wheel); - } + strqt = TAILQ_NEXT(asoc->last_out_stream, ss_params.fb.next_spoke); } do { - if ((strqt != NULL) && TAILQ_FIRST(&strqt->outqueue) && - TAILQ_FIRST(&strqt->outqueue)->net != NULL && - ((net == NULL || TAILQ_FIRST(&strqt->outqueue)->net == net) || - (SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0))) { + if ((strqt != NULL) && + ((SCTP_BASE_SYSCTL(sctp_cmt_on_off) > 0) || + (SCTP_BASE_SYSCTL(sctp_cmt_on_off) == 0 && + (net == NULL || (TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net == NULL) || + (net != NULL && TAILQ_FIRST(&strqt->outqueue) && TAILQ_FIRST(&strqt->outqueue)->net != NULL && + TAILQ_FIRST(&strqt->outqueue)->net == net))))) { if ((strqt->ss_params.fb.rounds >= 0) && (strq == NULL || strqt->ss_params.fb.rounds < strq->ss_params.fb.rounds)) { strq = strqt; @@ -748,9 +718,15 @@ sctp_ss_fcfs_clear(struct sctp_tcb *stcb int clear_values, int holds_lock) { if (clear_values) { + if (holds_lock == 0) { + SCTP_TCB_SEND_LOCK(stcb); + } while (!TAILQ_EMPTY(&asoc->ss_data.out_list)) { TAILQ_REMOVE(&asoc->ss_data.out_list, TAILQ_FIRST(&asoc->ss_data.out_list), ss_next); } + if (holds_lock == 0) { + SCTP_TCB_SEND_UNLOCK(stcb); + } } return; } @@ -880,7 +856,7 @@ struct sctp_ss_functions sctp_ss_functio .sctp_ss_init = sctp_ss_default_init, .sctp_ss_clear = sctp_ss_default_clear, .sctp_ss_init_stream = sctp_ss_default_init_stream, - .sctp_ss_add_to_stream = sctp_ss_rrp_add, + .sctp_ss_add_to_stream = sctp_ss_rr_add, .sctp_ss_is_empty = sctp_ss_default_is_empty, .sctp_ss_remove_from_stream = sctp_ss_default_remove, .sctp_ss_select_stream = sctp_ss_rrp_select,