Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 10 Feb 2012 19:56:02 +0000 (UTC)
From:      Michael Tuexen <tuexen@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: r231417 - stable/8/sys/netinet
Message-ID:  <201202101956.q1AJu28J091206@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202101956.q1AJu28J091206>