Commit cb93cc5d authored by Marcelo Ricardo Leitner's avatar Marcelo Ricardo Leitner Committed by David S. Miller

sctp: move flushing of data chunks out of sctp_outq_flush

To the new sctp_outq_flush_data. Again, smaller functions and with well
defined objectives.
Signed-off-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 96e0418e
...@@ -1038,46 +1038,17 @@ static bool sctp_outq_flush_rtx(struct sctp_outq *q, ...@@ -1038,46 +1038,17 @@ static bool sctp_outq_flush_rtx(struct sctp_outq *q,
return true; return true;
} }
/*
* Try to flush an outqueue. static void sctp_outq_flush_data(struct sctp_outq *q,
* struct sctp_transport **_transport,
* Description: Send everything in q which we legally can, subject to struct list_head *transport_list,
* congestion limitations. int rtx_timeout, gfp_t gfp)
* * Note: This function can be called from multiple contexts so appropriate
* locking concerns must be made. Today we use the sock lock to protect
* this function.
*/
static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
{ {
struct sctp_packet *packet; struct sctp_transport *transport = *_transport;
struct sctp_packet *packet = transport ? &transport->packet : NULL;
struct sctp_association *asoc = q->asoc; struct sctp_association *asoc = q->asoc;
struct sctp_transport *transport = NULL;
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
enum sctp_xmit status; enum sctp_xmit status;
int error = 0;
/* These transports have chunks to send. */
struct list_head transport_list;
struct list_head *ltransport;
INIT_LIST_HEAD(&transport_list);
packet = NULL;
/*
* 6.10 Bundling
* ...
* When bundling control chunks with DATA chunks, an
* endpoint MUST place control chunks first in the outbound
* SCTP packet. The transmitter MUST transmit DATA chunks
* within a SCTP packet in increasing order of TSN.
* ...
*/
sctp_outq_flush_ctrl(q, &transport, &transport_list, gfp);
packet = &transport->packet;
if (q->asoc->src_out_of_asoc_ok)
goto sctp_flush_out;
/* Is it OK to send data chunks? */ /* Is it OK to send data chunks? */
switch (asoc->state) { switch (asoc->state) {
...@@ -1102,10 +1073,11 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -1102,10 +1073,11 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
* current cwnd). * current cwnd).
*/ */
if (!list_empty(&q->retransmit)) { if (!list_empty(&q->retransmit)) {
if (!sctp_outq_flush_rtx(q, &transport, &transport_list, if (!sctp_outq_flush_rtx(q, _transport, transport_list,
rtx_timeout)) rtx_timeout))
break; break;
/* We may have switched current transport */ /* We may have switched current transport */
transport = *_transport;
packet = &transport->packet; packet = &transport->packet;
} }
...@@ -1131,12 +1103,14 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -1131,12 +1103,14 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) { if (asoc->stream.out[sid].state == SCTP_STREAM_CLOSED) {
sctp_outq_head_data(q, chunk); sctp_outq_head_data(q, chunk);
goto sctp_flush_out; break;
} }
if (sctp_outq_select_transport(chunk, asoc, &transport, if (sctp_outq_select_transport(chunk, asoc, _transport,
&transport_list)) transport_list)) {
transport = *_transport;
packet = &transport->packet; packet = &transport->packet;
}
pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p " pr_debug("%s: outq:%p, chunk:%p[%s], tx-tsn:0x%x skb->head:%p "
"skb->users:%d\n", "skb->users:%d\n",
...@@ -1148,8 +1122,10 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -1148,8 +1122,10 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
/* Add the chunk to the packet. */ /* Add the chunk to the packet. */
status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp); status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp);
switch (status) { switch (status) {
case SCTP_XMIT_OK:
break;
case SCTP_XMIT_PMTU_FULL: case SCTP_XMIT_PMTU_FULL:
case SCTP_XMIT_RWND_FULL: case SCTP_XMIT_RWND_FULL:
case SCTP_XMIT_DELAY: case SCTP_XMIT_DELAY:
...@@ -1161,9 +1137,9 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -1161,9 +1137,9 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
status); status);
sctp_outq_head_data(q, chunk); sctp_outq_head_data(q, chunk);
goto sctp_flush_out; return;
}
case SCTP_XMIT_OK:
/* The sender is in the SHUTDOWN-PENDING state, /* The sender is in the SHUTDOWN-PENDING state,
* The sender MAY set the I-bit in the DATA * The sender MAY set the I-bit in the DATA
* chunk header. * chunk header.
...@@ -1180,22 +1156,6 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -1180,22 +1156,6 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
*/ */
sctp_sched_dequeue_done(q, chunk); sctp_sched_dequeue_done(q, chunk);
break;
default:
BUG();
}
/* BUG: We assume that the sctp_packet_transmit()
* call below will succeed all the time and add the
* chunk to the transmitted list and restart the
* timers.
* It is possible that the call can fail under OOM
* conditions.
*
* Is this really a problem? Won't this behave
* like a lost TSN?
*/
list_add_tail(&chunk->transmitted_list, list_add_tail(&chunk->transmitted_list,
&transport->transmitted); &transport->transmitted);
...@@ -1206,7 +1166,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -1206,7 +1166,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
* COOKIE-ECHO chunk. * COOKIE-ECHO chunk.
*/ */
if (packet->has_cookie_echo) if (packet->has_cookie_echo)
goto sctp_flush_out; break;
} }
break; break;
...@@ -1214,6 +1174,47 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -1214,6 +1174,47 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
/* Do nothing. */ /* Do nothing. */
break; break;
} }
}
/*
* Try to flush an outqueue.
*
* Description: Send everything in q which we legally can, subject to
* congestion limitations.
* * Note: This function can be called from multiple contexts so appropriate
* locking concerns must be made. Today we use the sock lock to protect
* this function.
*/
static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
{
struct sctp_packet *packet;
struct sctp_association *asoc = q->asoc;
struct sctp_transport *transport = NULL;
int error = 0;
/* These transports have chunks to send. */
struct list_head transport_list;
struct list_head *ltransport;
INIT_LIST_HEAD(&transport_list);
packet = NULL;
/*
* 6.10 Bundling
* ...
* When bundling control chunks with DATA chunks, an
* endpoint MUST place control chunks first in the outbound
* SCTP packet. The transmitter MUST transmit DATA chunks
* within a SCTP packet in increasing order of TSN.
* ...
*/
sctp_outq_flush_ctrl(q, &transport, &transport_list, gfp);
if (q->asoc->src_out_of_asoc_ok)
goto sctp_flush_out;
sctp_outq_flush_data(q, &transport, &transport_list, rtx_timeout, gfp);
sctp_flush_out: sctp_flush_out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment