Skip to content

Commit 8d6d840

Browse files
committed
Merge branch 'sctp'
Lee A. Roberts says: ==================== This series of patches resolves several SCTP association hangs observed during SCTP stress testing. Observable symptoms include communications hangs with data being held in the association reassembly and/or lobby (ordering) queues. Close examination of reassembly/ordering queues may show either duplicated or missing packets. In version Digilent#2, corrected build failure in initial version of patch series due to wrong calling sequence for sctp_ulpq_partial_delivery() being inserted in sctp_ulpq_renege(). In version #3, adjusted patch documentation to be less repetitive. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 726bc6b + d003b41 commit 8d6d840

2 files changed

Lines changed: 78 additions & 22 deletions

File tree

net/sctp/tsnmap.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
static void sctp_tsnmap_update(struct sctp_tsnmap *map);
5252
static void sctp_tsnmap_find_gap_ack(unsigned long *map, __u16 off,
5353
__u16 len, __u16 *start, __u16 *end);
54-
static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 gap);
54+
static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size);
5555

5656
/* Initialize a block of memory as a tsnmap. */
5757
struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
@@ -124,7 +124,7 @@ int sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn,
124124

125125
gap = tsn - map->base_tsn;
126126

127-
if (gap >= map->len && !sctp_tsnmap_grow(map, gap))
127+
if (gap >= map->len && !sctp_tsnmap_grow(map, gap + 1))
128128
return -ENOMEM;
129129

130130
if (!sctp_tsnmap_has_gap(map) && gap == 0) {
@@ -360,23 +360,24 @@ __u16 sctp_tsnmap_num_gabs(struct sctp_tsnmap *map,
360360
return ngaps;
361361
}
362362

363-
static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 gap)
363+
static int sctp_tsnmap_grow(struct sctp_tsnmap *map, u16 size)
364364
{
365365
unsigned long *new;
366366
unsigned long inc;
367367
u16 len;
368368

369-
if (gap >= SCTP_TSN_MAP_SIZE)
369+
if (size > SCTP_TSN_MAP_SIZE)
370370
return 0;
371371

372-
inc = ALIGN((gap - map->len),BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT;
372+
inc = ALIGN((size - map->len), BITS_PER_LONG) + SCTP_TSN_MAP_INCREMENT;
373373
len = min_t(u16, map->len + inc, SCTP_TSN_MAP_SIZE);
374374

375375
new = kzalloc(len>>3, GFP_ATOMIC);
376376
if (!new)
377377
return 0;
378378

379-
bitmap_copy(new, map->tsn_map, map->max_tsn_seen - map->base_tsn);
379+
bitmap_copy(new, map->tsn_map,
380+
map->max_tsn_seen - map->cumulative_tsn_ack_point);
380381
kfree(map->tsn_map);
381382
map->tsn_map = new;
382383
map->len = len;

net/sctp/ulpqueue.c

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
106106
{
107107
struct sk_buff_head temp;
108108
struct sctp_ulpevent *event;
109+
int event_eor = 0;
109110

110111
/* Create an event from the incoming chunk. */
111112
event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp);
@@ -127,10 +128,12 @@ int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
127128
/* Send event to the ULP. 'event' is the sctp_ulpevent for
128129
* very first SKB on the 'temp' list.
129130
*/
130-
if (event)
131+
if (event) {
132+
event_eor = (event->msg_flags & MSG_EOR) ? 1 : 0;
131133
sctp_ulpq_tail_event(ulpq, event);
134+
}
132135

133-
return 0;
136+
return event_eor;
134137
}
135138

136139
/* Add a new event for propagation to the ULP. */
@@ -540,14 +543,19 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq)
540543
ctsn = cevent->tsn;
541544

542545
switch (cevent->msg_flags & SCTP_DATA_FRAG_MASK) {
546+
case SCTP_DATA_FIRST_FRAG:
547+
if (!first_frag)
548+
return NULL;
549+
goto done;
543550
case SCTP_DATA_MIDDLE_FRAG:
544551
if (!first_frag) {
545552
first_frag = pos;
546553
next_tsn = ctsn + 1;
547554
last_frag = pos;
548-
} else if (next_tsn == ctsn)
555+
} else if (next_tsn == ctsn) {
549556
next_tsn++;
550-
else
557+
last_frag = pos;
558+
} else
551559
goto done;
552560
break;
553561
case SCTP_DATA_LAST_FRAG:
@@ -651,6 +659,14 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq)
651659
} else
652660
goto done;
653661
break;
662+
663+
case SCTP_DATA_LAST_FRAG:
664+
if (!first_frag)
665+
return NULL;
666+
else
667+
goto done;
668+
break;
669+
654670
default:
655671
return NULL;
656672
}
@@ -962,20 +978,43 @@ static __u16 sctp_ulpq_renege_list(struct sctp_ulpq *ulpq,
962978
struct sk_buff_head *list, __u16 needed)
963979
{
964980
__u16 freed = 0;
965-
__u32 tsn;
966-
struct sk_buff *skb;
981+
__u32 tsn, last_tsn;
982+
struct sk_buff *skb, *flist, *last;
967983
struct sctp_ulpevent *event;
968984
struct sctp_tsnmap *tsnmap;
969985

970986
tsnmap = &ulpq->asoc->peer.tsn_map;
971987

972-
while ((skb = __skb_dequeue_tail(list)) != NULL) {
973-
freed += skb_headlen(skb);
988+
while ((skb = skb_peek_tail(list)) != NULL) {
974989
event = sctp_skb2event(skb);
975990
tsn = event->tsn;
976991

992+
/* Don't renege below the Cumulative TSN ACK Point. */
993+
if (TSN_lte(tsn, sctp_tsnmap_get_ctsn(tsnmap)))
994+
break;
995+
996+
/* Events in ordering queue may have multiple fragments
997+
* corresponding to additional TSNs. Sum the total
998+
* freed space; find the last TSN.
999+
*/
1000+
freed += skb_headlen(skb);
1001+
flist = skb_shinfo(skb)->frag_list;
1002+
for (last = flist; flist; flist = flist->next) {
1003+
last = flist;
1004+
freed += skb_headlen(last);
1005+
}
1006+
if (last)
1007+
last_tsn = sctp_skb2event(last)->tsn;
1008+
else
1009+
last_tsn = tsn;
1010+
1011+
/* Unlink the event, then renege all applicable TSNs. */
1012+
__skb_unlink(skb, list);
9771013
sctp_ulpevent_free(event);
978-
sctp_tsnmap_renege(tsnmap, tsn);
1014+
while (TSN_lte(tsn, last_tsn)) {
1015+
sctp_tsnmap_renege(tsnmap, tsn);
1016+
tsn++;
1017+
}
9791018
if (freed >= needed)
9801019
return freed;
9811020
}
@@ -1002,16 +1041,28 @@ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
10021041
struct sctp_ulpevent *event;
10031042
struct sctp_association *asoc;
10041043
struct sctp_sock *sp;
1044+
__u32 ctsn;
1045+
struct sk_buff *skb;
10051046

10061047
asoc = ulpq->asoc;
10071048
sp = sctp_sk(asoc->base.sk);
10081049

10091050
/* If the association is already in Partial Delivery mode
1010-
* we have noting to do.
1051+
* we have nothing to do.
10111052
*/
10121053
if (ulpq->pd_mode)
10131054
return;
10141055

1056+
/* Data must be at or below the Cumulative TSN ACK Point to
1057+
* start partial delivery.
1058+
*/
1059+
skb = skb_peek(&asoc->ulpq.reasm);
1060+
if (skb != NULL) {
1061+
ctsn = sctp_skb2event(skb)->tsn;
1062+
if (!TSN_lte(ctsn, sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map)))
1063+
return;
1064+
}
1065+
10151066
/* If the user enabled fragment interleave socket option,
10161067
* multiple associations can enter partial delivery.
10171068
* Otherwise, we can only enter partial delivery if the
@@ -1054,12 +1105,16 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
10541105
}
10551106
/* If able to free enough room, accept this chunk. */
10561107
if (chunk && (freed >= needed)) {
1057-
__u32 tsn;
1058-
tsn = ntohl(chunk->subh.data_hdr->tsn);
1059-
sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn, chunk->transport);
1060-
sctp_ulpq_tail_data(ulpq, chunk, gfp);
1061-
1062-
sctp_ulpq_partial_delivery(ulpq, gfp);
1108+
int retval;
1109+
retval = sctp_ulpq_tail_data(ulpq, chunk, gfp);
1110+
/*
1111+
* Enter partial delivery if chunk has not been
1112+
* delivered; otherwise, drain the reassembly queue.
1113+
*/
1114+
if (retval <= 0)
1115+
sctp_ulpq_partial_delivery(ulpq, gfp);
1116+
else if (retval == 1)
1117+
sctp_ulpq_reasm_drain(ulpq);
10631118
}
10641119

10651120
sk_mem_reclaim(asoc->base.sk);

0 commit comments

Comments
 (0)