提交 64519440 编写于 作者: X Xin Long 提交者: David S. Miller

sctp: save transmit error to sk_err in sctp_outq_flush

Every time when sctp calls sctp_outq_flush, it sends out the chunks of
control queue, retransmit queue and data queue. Even if some trunks are
failed to transmit, it still has to flush all the transports, as it's
the only chance to clean that transmit_list.

So the latest transmit error here should be returned back. This transmit
error is an internal error of sctp stack.

I checked all the places where it uses the transmit error (the return
value of sctp_outq_flush), most of them are actually just save it to
sk_err.

Except for sctp_assoc/endpoint_bh_rcv, they will drop the chunk if
it's failed to send a REPLY, which is actually incorrect, as we can't
be sure the error that sctp_outq_flush returns is from sending that
REPLY.

So it's meaningless for sctp_outq_flush to return error back.

This patch is to save transmit error to sk_err in sctp_outq_flush, the
new error can update the old value. Eventually, sctp_wait_for_* would
check for it.
Signed-off-by: NXin Long <lucien.xin@gmail.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 b61c654f
...@@ -180,7 +180,6 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, ...@@ -180,7 +180,6 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
int one_packet, gfp_t gfp) int one_packet, gfp_t gfp)
{ {
sctp_xmit_t retval; sctp_xmit_t retval;
int error = 0;
pr_debug("%s: packet:%p size:%Zu chunk:%p size:%d\n", __func__, pr_debug("%s: packet:%p size:%Zu chunk:%p size:%d\n", __func__,
packet, packet->size, chunk, chunk->skb ? chunk->skb->len : -1); packet, packet->size, chunk, chunk->skb ? chunk->skb->len : -1);
...@@ -188,6 +187,8 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, ...@@ -188,6 +187,8 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) { switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) {
case SCTP_XMIT_PMTU_FULL: case SCTP_XMIT_PMTU_FULL:
if (!packet->has_cookie_echo) { if (!packet->has_cookie_echo) {
int error = 0;
error = sctp_packet_transmit(packet, gfp); error = sctp_packet_transmit(packet, gfp);
if (error < 0) if (error < 0)
chunk->skb->sk->sk_err = -error; chunk->skb->sk->sk_err = -error;
......
...@@ -533,7 +533,6 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, ...@@ -533,7 +533,6 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
sctp_retransmit_reason_t reason) sctp_retransmit_reason_t reason)
{ {
struct net *net = sock_net(q->asoc->base.sk); struct net *net = sock_net(q->asoc->base.sk);
int error = 0;
switch (reason) { switch (reason) {
case SCTP_RTXR_T3_RTX: case SCTP_RTXR_T3_RTX:
...@@ -577,10 +576,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, ...@@ -577,10 +576,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
* will be flushed at the end. * will be flushed at the end.
*/ */
if (reason != SCTP_RTXR_FAST_RTX) if (reason != SCTP_RTXR_FAST_RTX)
error = sctp_outq_flush(q, /* rtx_timeout */ 1, GFP_ATOMIC); sctp_outq_flush(q, /* rtx_timeout */ 1, GFP_ATOMIC);
if (error)
q->asoc->base.sk->sk_err = -error;
} }
/* /*
...@@ -893,8 +889,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -893,8 +889,10 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
sctp_packet_config(&singleton, vtag, 0); sctp_packet_config(&singleton, vtag, 0);
sctp_packet_append_chunk(&singleton, chunk); sctp_packet_append_chunk(&singleton, chunk);
error = sctp_packet_transmit(&singleton, gfp); error = sctp_packet_transmit(&singleton, gfp);
if (error < 0) if (error < 0) {
return error; asoc->base.sk->sk_err = -error;
return 0;
}
break; break;
case SCTP_CID_ABORT: case SCTP_CID_ABORT:
...@@ -992,6 +990,8 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -992,6 +990,8 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
retran: retran:
error = sctp_outq_flush_rtx(q, packet, error = sctp_outq_flush_rtx(q, packet,
rtx_timeout, &start_timer); rtx_timeout, &start_timer);
if (error < 0)
asoc->base.sk->sk_err = -error;
if (start_timer) { if (start_timer) {
sctp_transport_reset_t3_rtx(transport); sctp_transport_reset_t3_rtx(transport);
...@@ -1166,14 +1166,17 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp) ...@@ -1166,14 +1166,17 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
struct sctp_transport, struct sctp_transport,
send_ready); send_ready);
packet = &t->packet; packet = &t->packet;
if (!sctp_packet_empty(packet)) if (!sctp_packet_empty(packet)) {
error = sctp_packet_transmit(packet, gfp); error = sctp_packet_transmit(packet, gfp);
if (error < 0)
asoc->base.sk->sk_err = -error;
}
/* Clear the burst limited state, if any */ /* Clear the burst limited state, if any */
sctp_transport_burst_reset(t); sctp_transport_burst_reset(t);
} }
return error; return 0;
} }
/* Update unack_data based on the incoming SACK chunk */ /* Update unack_data based on the incoming SACK chunk */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册