Commit 619a60ee authored by Vlad Yasevich's avatar Vlad Yasevich Committed by David S. Miller

sctp: Remove outqueue empty state

The SCTP outqueue structure maintains a data chunks
that are pending transmission, the list of chunks that
are pending a retransmission and a length of data in
flight.  It also tries to keep the emtpy state so that
it can performe shutdown sequence or notify user.

The problem is that the empy state is inconsistently
tracked.  It is possible to completely drain the queue
without sending anything when using PR-SCTP.  In this
case, the empty state will not be correctly state as
report by Jamal Hadi Salim <jhs@mojatatu.com>.  This
can cause an association to be perminantly stuck in the
SHUTDOWN_PENDING state.

Additionally, SCTP is incredibly inefficient when setting
the empty state.  Even though all the data is availaible
in the outqueue structure, we ignore it and walk a list
of trasnports.

In the end, we can completely remove the extra empty
state and figure out if the queue is empty by looking
at 3 things:  length of pending data, length of in-flight
data, and exisiting of retransmit data.  All of these
are already in the strucutre.
Reported-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarVlad Yasevich <vyasevich@gmail.com>
Acked-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Tested-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f3e3ccf8
...@@ -1046,9 +1046,6 @@ struct sctp_outq { ...@@ -1046,9 +1046,6 @@ struct sctp_outq {
/* Corked? */ /* Corked? */
char cork; char cork;
/* Is this structure empty? */
char empty;
}; };
void sctp_outq_init(struct sctp_association *, struct sctp_outq *); void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
......
...@@ -208,8 +208,6 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) ...@@ -208,8 +208,6 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
INIT_LIST_HEAD(&q->retransmit); INIT_LIST_HEAD(&q->retransmit);
INIT_LIST_HEAD(&q->sacked); INIT_LIST_HEAD(&q->sacked);
INIT_LIST_HEAD(&q->abandoned); INIT_LIST_HEAD(&q->abandoned);
q->empty = 1;
} }
/* Free the outqueue structure and any related pending chunks. /* Free the outqueue structure and any related pending chunks.
...@@ -332,7 +330,6 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk) ...@@ -332,7 +330,6 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS); SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS);
else else
SCTP_INC_STATS(net, SCTP_MIB_OUTORDERCHUNKS); SCTP_INC_STATS(net, SCTP_MIB_OUTORDERCHUNKS);
q->empty = 0;
break; break;
} }
} else { } else {
...@@ -654,7 +651,6 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, ...@@ -654,7 +651,6 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
if (chunk->fast_retransmit == SCTP_NEED_FRTX) if (chunk->fast_retransmit == SCTP_NEED_FRTX)
chunk->fast_retransmit = SCTP_DONT_FRTX; chunk->fast_retransmit = SCTP_DONT_FRTX;
q->empty = 0;
q->asoc->stats.rtxchunks++; q->asoc->stats.rtxchunks++;
break; break;
} }
...@@ -1065,8 +1061,6 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) ...@@ -1065,8 +1061,6 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
sctp_transport_reset_timers(transport); sctp_transport_reset_timers(transport);
q->empty = 0;
/* Only let one DATA chunk get bundled with a /* Only let one DATA chunk get bundled with a
* COOKIE-ECHO chunk. * COOKIE-ECHO chunk.
*/ */
...@@ -1275,29 +1269,17 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk) ...@@ -1275,29 +1269,17 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
"advertised peer ack point:0x%x\n", __func__, asoc, ctsn, "advertised peer ack point:0x%x\n", __func__, asoc, ctsn,
asoc->adv_peer_ack_point); asoc->adv_peer_ack_point);
/* See if all chunks are acked. return sctp_outq_is_empty(q);
* Make sure the empty queue handler will get run later.
*/
q->empty = (list_empty(&q->out_chunk_list) &&
list_empty(&q->retransmit));
if (!q->empty)
goto finish;
list_for_each_entry(transport, transport_list, transports) {
q->empty = q->empty && list_empty(&transport->transmitted);
if (!q->empty)
goto finish;
}
pr_debug("%s: sack queue is empty\n", __func__);
finish:
return q->empty;
} }
/* Is the outqueue empty? */ /* Is the outqueue empty?
* The queue is empty when we have not pending data, no in-flight data
* and nothing pending retransmissions.
*/
int sctp_outq_is_empty(const struct sctp_outq *q) int sctp_outq_is_empty(const struct sctp_outq *q)
{ {
return q->empty; return q->out_qlen == 0 && q->outstanding_bytes == 0 &&
list_empty(&q->retransmit);
} }
/******************************************************************** /********************************************************************
......
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