Commit 72f0c6fb authored by David Howells's avatar David Howells

rxrpc: Allocate ACK records at proposal and queue for transmission

Allocate rxrpc_txbuf records for ACKs and put onto a queue for the
transmitter thread to dispatch.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
parent 02a19356
...@@ -34,7 +34,8 @@ ...@@ -34,7 +34,8 @@
EM(rxrpc_local_new, "NEW") \ EM(rxrpc_local_new, "NEW") \
EM(rxrpc_local_processing, "PRO") \ EM(rxrpc_local_processing, "PRO") \
EM(rxrpc_local_put, "PUT") \ EM(rxrpc_local_put, "PUT") \
E_(rxrpc_local_queued, "QUE") EM(rxrpc_local_queued, "QUE") \
E_(rxrpc_local_tx_ack, "TAK")
#define rxrpc_peer_traces \ #define rxrpc_peer_traces \
EM(rxrpc_peer_got, "GOT") \ EM(rxrpc_peer_got, "GOT") \
...@@ -258,7 +259,9 @@ ...@@ -258,7 +259,9 @@
EM(rxrpc_txbuf_free, "FREE ") \ EM(rxrpc_txbuf_free, "FREE ") \
EM(rxrpc_txbuf_get_trans, "GET TRANS ") \ EM(rxrpc_txbuf_get_trans, "GET TRANS ") \
EM(rxrpc_txbuf_get_retrans, "GET RETRANS") \ EM(rxrpc_txbuf_get_retrans, "GET RETRANS") \
EM(rxrpc_txbuf_put_ack_tx, "PUT ACK TX ") \
EM(rxrpc_txbuf_put_cleaned, "PUT CLEANED") \ EM(rxrpc_txbuf_put_cleaned, "PUT CLEANED") \
EM(rxrpc_txbuf_put_nomem, "PUT NOMEM ") \
EM(rxrpc_txbuf_put_rotated, "PUT ROTATED") \ EM(rxrpc_txbuf_put_rotated, "PUT ROTATED") \
EM(rxrpc_txbuf_put_send_aborted, "PUT SEND-X ") \ EM(rxrpc_txbuf_put_send_aborted, "PUT SEND-X ") \
EM(rxrpc_txbuf_see_send_more, "SEE SEND+ ") \ EM(rxrpc_txbuf_see_send_more, "SEE SEND+ ") \
...@@ -1095,19 +1098,16 @@ TRACE_EVENT(rxrpc_rx_lose, ...@@ -1095,19 +1098,16 @@ TRACE_EVENT(rxrpc_rx_lose,
TRACE_EVENT(rxrpc_propose_ack, TRACE_EVENT(rxrpc_propose_ack,
TP_PROTO(struct rxrpc_call *call, enum rxrpc_propose_ack_trace why, TP_PROTO(struct rxrpc_call *call, enum rxrpc_propose_ack_trace why,
u8 ack_reason, rxrpc_serial_t serial, bool immediate, u8 ack_reason, rxrpc_serial_t serial,
bool background, enum rxrpc_propose_ack_outcome outcome), enum rxrpc_propose_ack_outcome outcome),
TP_ARGS(call, why, ack_reason, serial, immediate, background, TP_ARGS(call, why, ack_reason, serial, outcome),
outcome),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned int, call ) __field(unsigned int, call )
__field(enum rxrpc_propose_ack_trace, why ) __field(enum rxrpc_propose_ack_trace, why )
__field(rxrpc_serial_t, serial ) __field(rxrpc_serial_t, serial )
__field(u8, ack_reason ) __field(u8, ack_reason )
__field(bool, immediate )
__field(bool, background )
__field(enum rxrpc_propose_ack_outcome, outcome ) __field(enum rxrpc_propose_ack_outcome, outcome )
), ),
...@@ -1116,21 +1116,44 @@ TRACE_EVENT(rxrpc_propose_ack, ...@@ -1116,21 +1116,44 @@ TRACE_EVENT(rxrpc_propose_ack,
__entry->why = why; __entry->why = why;
__entry->serial = serial; __entry->serial = serial;
__entry->ack_reason = ack_reason; __entry->ack_reason = ack_reason;
__entry->immediate = immediate;
__entry->background = background;
__entry->outcome = outcome; __entry->outcome = outcome;
), ),
TP_printk("c=%08x %s %s r=%08x i=%u b=%u%s", TP_printk("c=%08x %s %s r=%08x%s",
__entry->call, __entry->call,
__print_symbolic(__entry->why, rxrpc_propose_ack_traces), __print_symbolic(__entry->why, rxrpc_propose_ack_traces),
__print_symbolic(__entry->ack_reason, rxrpc_ack_names), __print_symbolic(__entry->ack_reason, rxrpc_ack_names),
__entry->serial, __entry->serial,
__entry->immediate,
__entry->background,
__print_symbolic(__entry->outcome, rxrpc_propose_ack_outcomes)) __print_symbolic(__entry->outcome, rxrpc_propose_ack_outcomes))
); );
TRACE_EVENT(rxrpc_send_ack,
TP_PROTO(struct rxrpc_call *call, enum rxrpc_propose_ack_trace why,
u8 ack_reason, rxrpc_serial_t serial),
TP_ARGS(call, why, ack_reason, serial),
TP_STRUCT__entry(
__field(unsigned int, call )
__field(enum rxrpc_propose_ack_trace, why )
__field(rxrpc_serial_t, serial )
__field(u8, ack_reason )
),
TP_fast_assign(
__entry->call = call->debug_id;
__entry->why = why;
__entry->serial = serial;
__entry->ack_reason = ack_reason;
),
TP_printk("c=%08x %s %s r=%08x",
__entry->call,
__print_symbolic(__entry->why, rxrpc_propose_ack_traces),
__print_symbolic(__entry->ack_reason, rxrpc_ack_names),
__entry->serial)
);
TRACE_EVENT(rxrpc_retransmit, TRACE_EVENT(rxrpc_retransmit,
TP_PROTO(struct rxrpc_call *call, rxrpc_seq_t seq, u8 annotation, TP_PROTO(struct rxrpc_call *call, rxrpc_seq_t seq, u8 annotation,
s64 expiry), s64 expiry),
......
...@@ -292,6 +292,8 @@ struct rxrpc_local { ...@@ -292,6 +292,8 @@ struct rxrpc_local {
struct hlist_node link; struct hlist_node link;
struct socket *socket; /* my UDP socket */ struct socket *socket; /* my UDP socket */
struct work_struct processor; struct work_struct processor;
struct list_head ack_tx_queue; /* List of ACKs that need sending */
spinlock_t ack_tx_lock; /* ACK list lock */
struct rxrpc_sock __rcu *service; /* Service(s) listening on this endpoint */ struct rxrpc_sock __rcu *service; /* Service(s) listening on this endpoint */
struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */ struct rw_semaphore defrag_sem; /* control re-enablement of IP DF bit */
struct sk_buff_head reject_queue; /* packets awaiting rejection */ struct sk_buff_head reject_queue; /* packets awaiting rejection */
...@@ -520,10 +522,8 @@ enum rxrpc_call_flag { ...@@ -520,10 +522,8 @@ enum rxrpc_call_flag {
* Events that can be raised on a call. * Events that can be raised on a call.
*/ */
enum rxrpc_call_event { enum rxrpc_call_event {
RXRPC_CALL_EV_ACK, /* need to generate ACK */
RXRPC_CALL_EV_ABORT, /* need to generate abort */ RXRPC_CALL_EV_ABORT, /* need to generate abort */
RXRPC_CALL_EV_RESEND, /* Tx resend required */ RXRPC_CALL_EV_RESEND, /* Tx resend required */
RXRPC_CALL_EV_PING, /* Ping send required */
RXRPC_CALL_EV_EXPIRED, /* Expiry occurred */ RXRPC_CALL_EV_EXPIRED, /* Expiry occurred */
RXRPC_CALL_EV_ACK_LOST, /* ACK may be lost, send ping */ RXRPC_CALL_EV_ACK_LOST, /* ACK may be lost, send ping */
}; };
...@@ -782,13 +782,20 @@ struct rxrpc_txbuf { ...@@ -782,13 +782,20 @@ struct rxrpc_txbuf {
#define RXRPC_TXBUF_LAST 2 /* Set if last packet in Tx phase */ #define RXRPC_TXBUF_LAST 2 /* Set if last packet in Tx phase */
#define RXRPC_TXBUF_RESENT 3 /* Set if has been resent */ #define RXRPC_TXBUF_RESENT 3 /* Set if has been resent */
#define RXRPC_TXBUF_RETRANS 4 /* Set if should be retransmitted */ #define RXRPC_TXBUF_RETRANS 4 /* Set if should be retransmitted */
u8 /*enum rxrpc_propose_ack_trace*/ ack_why; /* If ack, why */
struct { struct {
/* The packet for encrypting and DMA'ing. We align it such /* The packet for encrypting and DMA'ing. We align it such
* that data[] aligns correctly for any crypto blocksize. * that data[] aligns correctly for any crypto blocksize.
*/ */
u8 pad[64 - sizeof(struct rxrpc_wire_header)]; u8 pad[64 - sizeof(struct rxrpc_wire_header)];
struct rxrpc_wire_header wire; /* Network-ready header */ struct rxrpc_wire_header wire; /* Network-ready header */
u8 data[RXRPC_JUMBO_DATALEN]; /* Data packet */ union {
u8 data[RXRPC_JUMBO_DATALEN]; /* Data packet */
struct {
struct rxrpc_ackpacket ack;
u8 acks[0];
};
};
} __aligned(64); } __aligned(64);
}; };
...@@ -824,8 +831,10 @@ int rxrpc_user_charge_accept(struct rxrpc_sock *, unsigned long); ...@@ -824,8 +831,10 @@ int rxrpc_user_charge_accept(struct rxrpc_sock *, unsigned long);
/* /*
* call_event.c * call_event.c
*/ */
void rxrpc_propose_ACK(struct rxrpc_call *, u8, u32, bool, bool, void rxrpc_propose_ping(struct rxrpc_call *call, u32 serial,
enum rxrpc_propose_ack_trace); enum rxrpc_propose_ack_trace why);
void rxrpc_send_ACK(struct rxrpc_call *, u8, rxrpc_serial_t, enum rxrpc_propose_ack_trace);
void rxrpc_propose_ACK(struct rxrpc_call *, u8, u32, enum rxrpc_propose_ack_trace);
void rxrpc_process_call(struct work_struct *); void rxrpc_process_call(struct work_struct *);
void rxrpc_reduce_call_timer(struct rxrpc_call *call, void rxrpc_reduce_call_timer(struct rxrpc_call *call,
...@@ -1030,7 +1039,7 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net) ...@@ -1030,7 +1039,7 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net)
/* /*
* output.c * output.c
*/ */
int rxrpc_send_ack_packet(struct rxrpc_call *, bool, rxrpc_serial_t *); void rxrpc_transmit_ack_packets(struct rxrpc_local *);
int rxrpc_send_abort_packet(struct rxrpc_call *); int rxrpc_send_abort_packet(struct rxrpc_call *);
int rxrpc_send_data_packet(struct rxrpc_call *, struct sk_buff *, bool); int rxrpc_send_data_packet(struct rxrpc_call *, struct sk_buff *, bool);
void rxrpc_reject_packets(struct rxrpc_local *); void rxrpc_reject_packets(struct rxrpc_local *);
......
...@@ -248,9 +248,8 @@ static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -248,9 +248,8 @@ static void rxrpc_send_ping(struct rxrpc_call *call, struct sk_buff *skb)
if (call->peer->rtt_count < 3 || if (call->peer->rtt_count < 3 ||
ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), now)) ktime_before(ktime_add_ms(call->peer->rtt_last_req, 1000), now))
rxrpc_propose_ACK(call, RXRPC_ACK_PING, sp->hdr.serial, rxrpc_send_ACK(call, RXRPC_ACK_PING, sp->hdr.serial,
true, true, rxrpc_propose_ack_ping_for_params);
rxrpc_propose_ack_ping_for_params);
} }
/* /*
......
...@@ -20,46 +20,39 @@ ...@@ -20,46 +20,39 @@
/* /*
* Propose a PING ACK be sent. * Propose a PING ACK be sent.
*/ */
static void rxrpc_propose_ping(struct rxrpc_call *call, void rxrpc_propose_ping(struct rxrpc_call *call, u32 serial,
bool immediate, bool background) enum rxrpc_propose_ack_trace why)
{ {
if (immediate) { unsigned long now = jiffies;
if (background && unsigned long ping_at = now + rxrpc_idle_ack_delay;
!test_and_set_bit(RXRPC_CALL_EV_PING, &call->events))
rxrpc_queue_call(call);
} else {
unsigned long now = jiffies;
unsigned long ping_at = now + rxrpc_idle_ack_delay;
if (time_before(ping_at, call->ping_at)) { spin_lock_bh(&call->lock);
WRITE_ONCE(call->ping_at, ping_at);
rxrpc_reduce_call_timer(call, ping_at, now, if (time_before(ping_at, call->ping_at)) {
rxrpc_timer_set_for_ping); rxrpc_inc_stat(call->rxnet, stat_tx_acks[RXRPC_ACK_PING]);
} WRITE_ONCE(call->ping_at, ping_at);
rxrpc_reduce_call_timer(call, ping_at, now,
rxrpc_timer_set_for_ping);
trace_rxrpc_propose_ack(call, why, RXRPC_ACK_PING, serial,
rxrpc_propose_ack_use);
} }
spin_unlock_bh(&call->lock);
} }
/* /*
* propose an ACK be sent * propose an ACK be sent
*/ */
static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
u32 serial, bool immediate, bool background, u32 serial, enum rxrpc_propose_ack_trace why)
enum rxrpc_propose_ack_trace why)
{ {
enum rxrpc_propose_ack_outcome outcome = rxrpc_propose_ack_use; enum rxrpc_propose_ack_outcome outcome = rxrpc_propose_ack_use;
unsigned long expiry = rxrpc_soft_ack_delay; unsigned long expiry = rxrpc_soft_ack_delay;
unsigned long now = jiffies, ack_at;
s8 prior = rxrpc_ack_priority[ack_reason]; s8 prior = rxrpc_ack_priority[ack_reason];
rxrpc_inc_stat(call->rxnet, stat_tx_acks[ack_reason]); rxrpc_inc_stat(call->rxnet, stat_tx_acks[ack_reason]);
/* Pings are handled specially because we don't want to accidentally
* lose a ping response by subsuming it into a ping.
*/
if (ack_reason == RXRPC_ACK_PING) {
rxrpc_propose_ping(call, immediate, background);
goto trace;
}
/* Update DELAY, IDLE, REQUESTED and PING_RESPONSE ACK serial /* Update DELAY, IDLE, REQUESTED and PING_RESPONSE ACK serial
* numbers, but we don't alter the timeout. * numbers, but we don't alter the timeout.
*/ */
...@@ -71,8 +64,6 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, ...@@ -71,8 +64,6 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
outcome = rxrpc_propose_ack_update; outcome = rxrpc_propose_ack_update;
call->ackr_serial = serial; call->ackr_serial = serial;
} }
if (!immediate)
goto trace;
} else if (prior > rxrpc_ack_priority[call->ackr_reason]) { } else if (prior > rxrpc_ack_priority[call->ackr_reason]) {
call->ackr_reason = ack_reason; call->ackr_reason = ack_reason;
call->ackr_serial = serial; call->ackr_serial = serial;
...@@ -84,8 +75,6 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, ...@@ -84,8 +75,6 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
case RXRPC_ACK_REQUESTED: case RXRPC_ACK_REQUESTED:
if (rxrpc_requested_ack_delay < expiry) if (rxrpc_requested_ack_delay < expiry)
expiry = rxrpc_requested_ack_delay; expiry = rxrpc_requested_ack_delay;
if (serial == 1)
immediate = false;
break; break;
case RXRPC_ACK_DELAY: case RXRPC_ACK_DELAY:
...@@ -99,52 +88,89 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, ...@@ -99,52 +88,89 @@ static void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,
break; break;
default: default:
immediate = true; WARN_ON(1);
break; return;
} }
if (test_bit(RXRPC_CALL_EV_ACK, &call->events)) {
_debug("already scheduled"); if (call->peer->srtt_us != 0)
} else if (immediate || expiry == 0) { ack_at = usecs_to_jiffies(call->peer->srtt_us >> 3);
_debug("immediate ACK %lx", call->events); else
if (!test_and_set_bit(RXRPC_CALL_EV_ACK, &call->events) && ack_at = expiry;
background)
rxrpc_queue_call(call); ack_at += READ_ONCE(call->tx_backoff);
} else { ack_at += now;
unsigned long now = jiffies, ack_at; if (time_before(ack_at, call->ack_at)) {
WRITE_ONCE(call->ack_at, ack_at);
if (call->peer->srtt_us != 0) rxrpc_reduce_call_timer(call, ack_at, now,
ack_at = usecs_to_jiffies(call->peer->srtt_us >> 3); rxrpc_timer_set_for_ack);
else
ack_at = expiry;
ack_at += READ_ONCE(call->tx_backoff);
ack_at += now;
if (time_before(ack_at, call->ack_at)) {
WRITE_ONCE(call->ack_at, ack_at);
rxrpc_reduce_call_timer(call, ack_at, now,
rxrpc_timer_set_for_ack);
}
} }
trace: trace_rxrpc_propose_ack(call, why, ack_reason, serial, outcome);
trace_rxrpc_propose_ack(call, why, ack_reason, serial, immediate,
background, outcome);
} }
/* /*
* propose an ACK be sent, locking the call structure * propose an ACK be sent, locking the call structure
*/ */
void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, void rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason, u32 serial,
u32 serial, bool immediate, bool background,
enum rxrpc_propose_ack_trace why) enum rxrpc_propose_ack_trace why)
{ {
spin_lock_bh(&call->lock); spin_lock_bh(&call->lock);
__rxrpc_propose_ACK(call, ack_reason, serial, __rxrpc_propose_ACK(call, ack_reason, serial, why);
immediate, background, why);
spin_unlock_bh(&call->lock); spin_unlock_bh(&call->lock);
} }
/*
* Queue an ACK for immediate transmission.
*/
void rxrpc_send_ACK(struct rxrpc_call *call, u8 ack_reason,
rxrpc_serial_t serial, enum rxrpc_propose_ack_trace why)
{
struct rxrpc_local *local = call->conn->params.local;
struct rxrpc_txbuf *txb;
if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
return;
rxrpc_inc_stat(call->rxnet, stat_tx_acks[ack_reason]);
txb = rxrpc_alloc_txbuf(call, RXRPC_PACKET_TYPE_ACK,
in_softirq() ? GFP_ATOMIC | __GFP_NOWARN : GFP_NOFS);
if (!txb) {
kleave(" = -ENOMEM");
return;
}
txb->ack_why = why;
txb->wire.seq = 0;
txb->wire.type = RXRPC_PACKET_TYPE_ACK;
txb->wire.flags |= RXRPC_SLOW_START_OK;
txb->ack.bufferSpace = 0;
txb->ack.maxSkew = 0;
txb->ack.firstPacket = 0;
txb->ack.previousPacket = 0;
txb->ack.serial = htonl(serial);
txb->ack.reason = ack_reason;
txb->ack.nAcks = 0;
if (!rxrpc_try_get_call(call, rxrpc_call_got)) {
rxrpc_put_txbuf(txb, rxrpc_txbuf_put_nomem);
return;
}
spin_lock_bh(&local->ack_tx_lock);
list_add_tail(&txb->tx_link, &local->ack_tx_queue);
spin_unlock_bh(&local->ack_tx_lock);
trace_rxrpc_send_ack(call, why, ack_reason, serial);
if (in_task()) {
rxrpc_transmit_ack_packets(call->peer->local);
} else {
rxrpc_get_local(local);
rxrpc_queue_local(local);
}
}
/* /*
* Handle congestion being detected by the retransmit timeout. * Handle congestion being detected by the retransmit timeout.
*/ */
...@@ -230,9 +256,8 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j) ...@@ -230,9 +256,8 @@ static void rxrpc_resend(struct rxrpc_call *call, unsigned long now_j)
ack_ts = ktime_sub(now, call->acks_latest_ts); ack_ts = ktime_sub(now, call->acks_latest_ts);
if (ktime_to_us(ack_ts) < (call->peer->srtt_us >> 3)) if (ktime_to_us(ack_ts) < (call->peer->srtt_us >> 3))
goto out; goto out;
rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false, rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_lost_ack); rxrpc_propose_ack_ping_for_lost_ack);
rxrpc_send_ack_packet(call, true, NULL);
goto out; goto out;
} }
...@@ -291,9 +316,10 @@ void rxrpc_process_call(struct work_struct *work) ...@@ -291,9 +316,10 @@ void rxrpc_process_call(struct work_struct *work)
{ {
struct rxrpc_call *call = struct rxrpc_call *call =
container_of(work, struct rxrpc_call, processor); container_of(work, struct rxrpc_call, processor);
rxrpc_serial_t *send_ack;
unsigned long now, next, t; unsigned long now, next, t;
unsigned int iterations = 0; unsigned int iterations = 0;
rxrpc_serial_t ackr_serial;
u8 ackr_reason;
rxrpc_see_call(call); rxrpc_see_call(call);
...@@ -342,7 +368,15 @@ void rxrpc_process_call(struct work_struct *work) ...@@ -342,7 +368,15 @@ void rxrpc_process_call(struct work_struct *work)
if (time_after_eq(now, t)) { if (time_after_eq(now, t)) {
trace_rxrpc_timer(call, rxrpc_timer_exp_ack, now); trace_rxrpc_timer(call, rxrpc_timer_exp_ack, now);
cmpxchg(&call->ack_at, t, now + MAX_JIFFY_OFFSET); cmpxchg(&call->ack_at, t, now + MAX_JIFFY_OFFSET);
set_bit(RXRPC_CALL_EV_ACK, &call->events); spin_lock_bh(&call->lock);
ackr_reason = call->ackr_reason;
ackr_serial = call->ackr_serial;
call->ackr_reason = 0;
call->ackr_serial = 0;
spin_unlock_bh(&call->lock);
if (ackr_reason)
rxrpc_send_ACK(call, ackr_reason, ackr_serial,
rxrpc_propose_ack_ping_for_lost_ack);
} }
t = READ_ONCE(call->ack_lost_at); t = READ_ONCE(call->ack_lost_at);
...@@ -356,16 +390,16 @@ void rxrpc_process_call(struct work_struct *work) ...@@ -356,16 +390,16 @@ void rxrpc_process_call(struct work_struct *work)
if (time_after_eq(now, t)) { if (time_after_eq(now, t)) {
trace_rxrpc_timer(call, rxrpc_timer_exp_keepalive, now); trace_rxrpc_timer(call, rxrpc_timer_exp_keepalive, now);
cmpxchg(&call->keepalive_at, t, now + MAX_JIFFY_OFFSET); cmpxchg(&call->keepalive_at, t, now + MAX_JIFFY_OFFSET);
rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, true, rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_keepalive); rxrpc_propose_ack_ping_for_keepalive);
set_bit(RXRPC_CALL_EV_PING, &call->events);
} }
t = READ_ONCE(call->ping_at); t = READ_ONCE(call->ping_at);
if (time_after_eq(now, t)) { if (time_after_eq(now, t)) {
trace_rxrpc_timer(call, rxrpc_timer_exp_ping, now); trace_rxrpc_timer(call, rxrpc_timer_exp_ping, now);
cmpxchg(&call->ping_at, t, now + MAX_JIFFY_OFFSET); cmpxchg(&call->ping_at, t, now + MAX_JIFFY_OFFSET);
set_bit(RXRPC_CALL_EV_PING, &call->events); rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_keepalive);
} }
t = READ_ONCE(call->resend_at); t = READ_ONCE(call->resend_at);
...@@ -388,25 +422,10 @@ void rxrpc_process_call(struct work_struct *work) ...@@ -388,25 +422,10 @@ void rxrpc_process_call(struct work_struct *work)
goto recheck_state; goto recheck_state;
} }
send_ack = NULL;
if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events)) { if (test_and_clear_bit(RXRPC_CALL_EV_ACK_LOST, &call->events)) {
call->acks_lost_top = call->tx_top; call->acks_lost_top = call->tx_top;
rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, true, false, rxrpc_send_ACK(call, RXRPC_ACK_PING, 0,
rxrpc_propose_ack_ping_for_lost_ack); rxrpc_propose_ack_ping_for_lost_ack);
send_ack = &call->acks_lost_ping;
}
if (test_and_clear_bit(RXRPC_CALL_EV_ACK, &call->events) ||
send_ack) {
if (call->ackr_reason) {
rxrpc_send_ack_packet(call, false, send_ack);
goto recheck_state;
}
}
if (test_and_clear_bit(RXRPC_CALL_EV_PING, &call->events)) {
rxrpc_send_ack_packet(call, true, NULL);
goto recheck_state;
} }
if (test_and_clear_bit(RXRPC_CALL_EV_RESEND, &call->events) && if (test_and_clear_bit(RXRPC_CALL_EV_RESEND, &call->events) &&
......
...@@ -398,8 +398,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -398,8 +398,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
unsigned int j, nr_subpackets, nr_unacked = 0; unsigned int j, nr_subpackets, nr_unacked = 0;
rxrpc_serial_t serial = sp->hdr.serial, ack_serial = serial; rxrpc_serial_t serial = sp->hdr.serial, ack_serial = serial;
rxrpc_seq_t seq0 = sp->hdr.seq, hard_ack; rxrpc_seq_t seq0 = sp->hdr.seq, hard_ack;
bool immediate_ack = false, jumbo_bad = false; bool jumbo_bad = false;
u8 ack = 0;
_enter("{%u,%u},{%u,%u}", _enter("{%u,%u},{%u,%u}",
call->rx_hard_ack, call->rx_top, skb->len, seq0); call->rx_hard_ack, call->rx_top, skb->len, seq0);
...@@ -447,9 +446,9 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -447,9 +446,9 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
nr_subpackets = sp->nr_subpackets; nr_subpackets = sp->nr_subpackets;
if (nr_subpackets > 1) { if (nr_subpackets > 1) {
if (call->nr_jumbo_bad > 3) { if (call->nr_jumbo_bad > 3) {
ack = RXRPC_ACK_NOSPACE; rxrpc_send_ACK(call, RXRPC_ACK_NOSPACE, serial,
ack_serial = serial; rxrpc_propose_ack_input_data);
goto ack; goto unlock;
} }
} }
...@@ -459,6 +458,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -459,6 +458,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
unsigned int ix = seq & RXRPC_RXTX_BUFF_MASK; unsigned int ix = seq & RXRPC_RXTX_BUFF_MASK;
bool terminal = (j == nr_subpackets - 1); bool terminal = (j == nr_subpackets - 1);
bool last = terminal && (sp->rx_flags & RXRPC_SKB_INCL_LAST); bool last = terminal && (sp->rx_flags & RXRPC_SKB_INCL_LAST);
bool acked = false;
u8 flags, annotation = j; u8 flags, annotation = j;
_proto("Rx DATA+%u %%%u { #%x t=%u l=%u }", _proto("Rx DATA+%u %%%u { #%x t=%u l=%u }",
...@@ -488,25 +488,22 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -488,25 +488,22 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
trace_rxrpc_rx_data(call->debug_id, seq, serial, flags, annotation); trace_rxrpc_rx_data(call->debug_id, seq, serial, flags, annotation);
if (before_eq(seq, hard_ack)) { if (before_eq(seq, hard_ack)) {
ack = RXRPC_ACK_DUPLICATE; rxrpc_send_ACK(call, RXRPC_ACK_DUPLICATE, serial,
ack_serial = serial; rxrpc_propose_ack_input_data);
continue; continue;
} }
if (call->rxtx_buffer[ix]) { if (call->rxtx_buffer[ix]) {
rxrpc_input_dup_data(call, seq, nr_subpackets > 1, rxrpc_input_dup_data(call, seq, nr_subpackets > 1,
&jumbo_bad); &jumbo_bad);
if (ack != RXRPC_ACK_DUPLICATE) { rxrpc_send_ACK(call, RXRPC_ACK_DUPLICATE, serial,
ack = RXRPC_ACK_DUPLICATE; rxrpc_propose_ack_input_data);
ack_serial = serial;
}
immediate_ack = true;
continue; continue;
} }
if (after(seq, hard_ack + call->rx_winsize)) { if (after(seq, hard_ack + call->rx_winsize)) {
ack = RXRPC_ACK_EXCEEDS_WINDOW; rxrpc_send_ACK(call, RXRPC_ACK_EXCEEDS_WINDOW, serial,
ack_serial = serial; rxrpc_propose_ack_input_data);
if (flags & RXRPC_JUMBO_PACKET) { if (flags & RXRPC_JUMBO_PACKET) {
if (!jumbo_bad) { if (!jumbo_bad) {
call->nr_jumbo_bad++; call->nr_jumbo_bad++;
...@@ -514,12 +511,13 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -514,12 +511,13 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
} }
} }
goto ack; goto unlock;
} }
if (flags & RXRPC_REQUEST_ACK && !ack) { if (flags & RXRPC_REQUEST_ACK) {
ack = RXRPC_ACK_REQUESTED; rxrpc_send_ACK(call, RXRPC_ACK_REQUESTED, serial,
ack_serial = serial; rxrpc_propose_ack_input_data);
acked = true;
} }
if (after(seq0, call->ackr_highest_seq)) if (after(seq0, call->ackr_highest_seq))
...@@ -542,11 +540,11 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -542,11 +540,11 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
smp_store_release(&call->rx_top, seq); smp_store_release(&call->rx_top, seq);
} else if (before(seq, call->rx_top)) { } else if (before(seq, call->rx_top)) {
/* Send an immediate ACK if we fill in a hole */ /* Send an immediate ACK if we fill in a hole */
if (!ack) { if (!acked) {
ack = RXRPC_ACK_DELAY; rxrpc_send_ACK(call, RXRPC_ACK_DELAY, serial,
ack_serial = serial; rxrpc_propose_ack_input_data);
acked = true;
} }
immediate_ack = true;
} }
if (terminal) { if (terminal) {
...@@ -558,14 +556,8 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -558,14 +556,8 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
sp = NULL; sp = NULL;
} }
nr_unacked++;
if (last) { if (last) {
set_bit(RXRPC_CALL_RX_LAST, &call->flags); set_bit(RXRPC_CALL_RX_LAST, &call->flags);
if (!ack) {
ack = RXRPC_ACK_DELAY;
ack_serial = serial;
}
trace_rxrpc_receive(call, rxrpc_receive_queue_last, serial, seq); trace_rxrpc_receive(call, rxrpc_receive_queue_last, serial, seq);
} else { } else {
trace_rxrpc_receive(call, rxrpc_receive_queue, serial, seq); trace_rxrpc_receive(call, rxrpc_receive_queue, serial, seq);
...@@ -574,32 +566,30 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -574,32 +566,30 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb)
if (after_eq(seq, call->rx_expect_next)) { if (after_eq(seq, call->rx_expect_next)) {
if (after(seq, call->rx_expect_next)) { if (after(seq, call->rx_expect_next)) {
_net("OOS %u > %u", seq, call->rx_expect_next); _net("OOS %u > %u", seq, call->rx_expect_next);
ack = RXRPC_ACK_OUT_OF_SEQUENCE; rxrpc_send_ACK(call, RXRPC_ACK_OUT_OF_SEQUENCE, serial,
ack_serial = serial; rxrpc_propose_ack_input_data);
acked = true;
} }
call->rx_expect_next = seq + 1; call->rx_expect_next = seq + 1;
} }
if (!ack)
if (!acked) {
nr_unacked++;
ack_serial = serial; ack_serial = serial;
}
} }
ack: unlock:
if (atomic_add_return(nr_unacked, &call->ackr_nr_unacked) > 2 && !ack) if (atomic_add_return(nr_unacked, &call->ackr_nr_unacked) > 2)
ack = RXRPC_ACK_IDLE; rxrpc_send_ACK(call, RXRPC_ACK_IDLE, ack_serial,
rxrpc_propose_ack_input_data);
if (ack)
rxrpc_propose_ACK(call, ack, ack_serial,
immediate_ack, true,
rxrpc_propose_ack_input_data);
else else
rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial, rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, ack_serial,
false, true,
rxrpc_propose_ack_input_data); rxrpc_propose_ack_input_data);
trace_rxrpc_notify_socket(call->debug_id, serial); trace_rxrpc_notify_socket(call->debug_id, serial);
rxrpc_notify_socket(call); rxrpc_notify_socket(call);
unlock:
spin_unlock(&call->input_lock); spin_unlock(&call->input_lock);
rxrpc_free_skb(skb, rxrpc_skb_freed); rxrpc_free_skb(skb, rxrpc_skb_freed);
_leave(" [queued]"); _leave(" [queued]");
...@@ -893,13 +883,11 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -893,13 +883,11 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
if (buf.ack.reason == RXRPC_ACK_PING) { if (buf.ack.reason == RXRPC_ACK_PING) {
_proto("Rx ACK %%%u PING Request", ack_serial); _proto("Rx ACK %%%u PING Request", ack_serial);
rxrpc_propose_ACK(call, RXRPC_ACK_PING_RESPONSE, rxrpc_send_ACK(call, RXRPC_ACK_PING_RESPONSE, ack_serial,
ack_serial, true, true, rxrpc_propose_ack_respond_to_ping);
rxrpc_propose_ack_respond_to_ping);
} else if (sp->hdr.flags & RXRPC_REQUEST_ACK) { } else if (sp->hdr.flags & RXRPC_REQUEST_ACK) {
rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, rxrpc_send_ACK(call, RXRPC_ACK_REQUESTED, ack_serial,
ack_serial, true, true, rxrpc_propose_ack_respond_to_ack);
rxrpc_propose_ack_respond_to_ack);
} }
/* If we get an EXCEEDS_WINDOW ACK from the server, it probably /* If we get an EXCEEDS_WINDOW ACK from the server, it probably
...@@ -1011,9 +999,8 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) ...@@ -1011,9 +999,8 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
RXRPC_TX_ANNO_LAST && RXRPC_TX_ANNO_LAST &&
summary.nr_acks == call->tx_top - hard_ack && summary.nr_acks == call->tx_top - hard_ack &&
rxrpc_is_client_call(call)) rxrpc_is_client_call(call))
rxrpc_propose_ACK(call, RXRPC_ACK_PING, ack_serial, rxrpc_propose_ping(call, ack_serial,
false, true, rxrpc_propose_ack_ping_for_lost_reply);
rxrpc_propose_ack_ping_for_lost_reply);
rxrpc_congestion_management(call, skb, &summary, acked_serial); rxrpc_congestion_management(call, skb, &summary, acked_serial);
out: out:
......
...@@ -97,6 +97,8 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet, ...@@ -97,6 +97,8 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
local->rxnet = rxnet; local->rxnet = rxnet;
INIT_HLIST_NODE(&local->link); INIT_HLIST_NODE(&local->link);
INIT_WORK(&local->processor, rxrpc_local_processor); INIT_WORK(&local->processor, rxrpc_local_processor);
INIT_LIST_HEAD(&local->ack_tx_queue);
spin_lock_init(&local->ack_tx_lock);
init_rwsem(&local->defrag_sem); init_rwsem(&local->defrag_sem);
skb_queue_head_init(&local->reject_queue); skb_queue_head_init(&local->reject_queue);
skb_queue_head_init(&local->event_queue); skb_queue_head_init(&local->event_queue);
...@@ -432,6 +434,11 @@ static void rxrpc_local_processor(struct work_struct *work) ...@@ -432,6 +434,11 @@ static void rxrpc_local_processor(struct work_struct *work)
break; break;
} }
if (!list_empty(&local->ack_tx_queue)) {
rxrpc_transmit_ack_packets(local);
again = true;
}
if (!skb_queue_empty(&local->reject_queue)) { if (!skb_queue_empty(&local->reject_queue)) {
rxrpc_reject_packets(local); rxrpc_reject_packets(local);
again = true; again = true;
......
...@@ -16,14 +16,6 @@ ...@@ -16,14 +16,6 @@
#include <net/udp.h> #include <net/udp.h>
#include "ar-internal.h" #include "ar-internal.h"
struct rxrpc_ack_buffer {
struct rxrpc_wire_header whdr;
struct rxrpc_ackpacket ack;
u8 acks[255];
u8 pad[3];
struct rxrpc_ackinfo ackinfo;
};
extern int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); extern int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len);
static ssize_t do_udp_sendmsg(struct socket *sk, struct msghdr *msg, size_t len) static ssize_t do_udp_sendmsg(struct socket *sk, struct msghdr *msg, size_t len)
...@@ -82,22 +74,21 @@ static void rxrpc_set_keepalive(struct rxrpc_call *call) ...@@ -82,22 +74,21 @@ static void rxrpc_set_keepalive(struct rxrpc_call *call)
*/ */
static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
struct rxrpc_call *call, struct rxrpc_call *call,
struct rxrpc_ack_buffer *pkt, struct rxrpc_txbuf *txb,
rxrpc_seq_t *_hard_ack, rxrpc_seq_t *_hard_ack,
rxrpc_seq_t *_top, rxrpc_seq_t *_top)
u8 reason)
{ {
rxrpc_serial_t serial; struct rxrpc_ackinfo ackinfo;
unsigned int tmp; unsigned int tmp;
rxrpc_seq_t hard_ack, top, seq; rxrpc_seq_t hard_ack, top, seq;
int ix; int ix;
u32 mtu, jmax; u32 mtu, jmax;
u8 *ackp = pkt->acks; u8 *ackp = txb->acks;
tmp = atomic_xchg(&call->ackr_nr_unacked, 0); tmp = atomic_xchg(&call->ackr_nr_unacked, 0);
tmp |= atomic_xchg(&call->ackr_nr_consumed, 0); tmp |= atomic_xchg(&call->ackr_nr_consumed, 0);
if (!tmp && (reason == RXRPC_ACK_DELAY || if (!tmp && (txb->ack.reason == RXRPC_ACK_DELAY ||
reason == RXRPC_ACK_IDLE)) { txb->ack.reason == RXRPC_ACK_IDLE)) {
rxrpc_inc_stat(call->rxnet, stat_tx_ack_skip); rxrpc_inc_stat(call->rxnet, stat_tx_ack_skip);
return 0; return 0;
} }
...@@ -105,24 +96,16 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, ...@@ -105,24 +96,16 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
rxrpc_inc_stat(call->rxnet, stat_tx_ack_fill); rxrpc_inc_stat(call->rxnet, stat_tx_ack_fill);
/* Barrier against rxrpc_input_data(). */ /* Barrier against rxrpc_input_data(). */
serial = call->ackr_serial;
hard_ack = READ_ONCE(call->rx_hard_ack); hard_ack = READ_ONCE(call->rx_hard_ack);
top = smp_load_acquire(&call->rx_top); top = smp_load_acquire(&call->rx_top);
*_hard_ack = hard_ack; *_hard_ack = hard_ack;
*_top = top; *_top = top;
pkt->ack.bufferSpace = htons(0); txb->ack.firstPacket = htonl(hard_ack + 1);
pkt->ack.maxSkew = htons(0); txb->ack.previousPacket = htonl(call->ackr_highest_seq);
pkt->ack.firstPacket = htonl(hard_ack + 1); txb->ack.nAcks = top - hard_ack;
pkt->ack.previousPacket = htonl(call->ackr_highest_seq);
pkt->ack.serial = htonl(serial);
pkt->ack.reason = reason;
pkt->ack.nAcks = top - hard_ack;
if (reason == RXRPC_ACK_PING)
pkt->whdr.flags |= RXRPC_REQUEST_ACK;
if (after(top, hard_ack)) { if (txb->ack.nAcks) {
seq = hard_ack + 1; seq = hard_ack + 1;
do { do {
ix = seq & RXRPC_RXTX_BUFF_MASK; ix = seq & RXRPC_RXTX_BUFF_MASK;
...@@ -137,15 +120,16 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn, ...@@ -137,15 +120,16 @@ static size_t rxrpc_fill_out_ack(struct rxrpc_connection *conn,
mtu = conn->params.peer->if_mtu; mtu = conn->params.peer->if_mtu;
mtu -= conn->params.peer->hdrsize; mtu -= conn->params.peer->hdrsize;
jmax = (call->nr_jumbo_bad > 3) ? 1 : rxrpc_rx_jumbo_max; jmax = (call->nr_jumbo_bad > 3) ? 1 : rxrpc_rx_jumbo_max;
pkt->ackinfo.rxMTU = htonl(rxrpc_rx_mtu); ackinfo.rxMTU = htonl(rxrpc_rx_mtu);
pkt->ackinfo.maxMTU = htonl(mtu); ackinfo.maxMTU = htonl(mtu);
pkt->ackinfo.rwind = htonl(call->rx_winsize); ackinfo.rwind = htonl(call->rx_winsize);
pkt->ackinfo.jumbo_max = htonl(jmax); ackinfo.jumbo_max = htonl(jmax);
*ackp++ = 0; *ackp++ = 0;
*ackp++ = 0; *ackp++ = 0;
*ackp++ = 0; *ackp++ = 0;
return top - hard_ack + 3; memcpy(ackp, &ackinfo, sizeof(ackinfo));
return top - hard_ack + 3 + sizeof(ackinfo);
} }
/* /*
...@@ -194,26 +178,21 @@ static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call, ...@@ -194,26 +178,21 @@ static void rxrpc_cancel_rtt_probe(struct rxrpc_call *call,
/* /*
* Send an ACK call packet. * Send an ACK call packet.
*/ */
int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping, static int rxrpc_send_ack_packet(struct rxrpc_local *local, struct rxrpc_txbuf *txb)
rxrpc_serial_t *_serial)
{ {
struct rxrpc_connection *conn; struct rxrpc_connection *conn;
struct rxrpc_ack_buffer *pkt; struct rxrpc_ack_buffer *pkt;
struct rxrpc_call *call = txb->call;
struct msghdr msg; struct msghdr msg;
struct kvec iov[2]; struct kvec iov[1];
rxrpc_serial_t serial; rxrpc_serial_t serial;
rxrpc_seq_t hard_ack, top; rxrpc_seq_t hard_ack, top;
size_t len, n; size_t len, n;
int ret, rtt_slot = -1; int ret, rtt_slot = -1;
u8 reason;
if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) if (test_bit(RXRPC_CALL_DISCONNECTED, &call->flags))
return -ECONNRESET; return -ECONNRESET;
pkt = kzalloc(sizeof(*pkt), GFP_KERNEL);
if (!pkt)
return -ENOMEM;
conn = call->conn; conn = call->conn;
msg.msg_name = &call->peer->srx.transport; msg.msg_name = &call->peer->srx.transport;
...@@ -222,85 +201,93 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping, ...@@ -222,85 +201,93 @@ int rxrpc_send_ack_packet(struct rxrpc_call *call, bool ping,
msg.msg_controllen = 0; msg.msg_controllen = 0;
msg.msg_flags = 0; msg.msg_flags = 0;
pkt->whdr.epoch = htonl(conn->proto.epoch); if (txb->ack.reason == RXRPC_ACK_PING)
pkt->whdr.cid = htonl(call->cid); txb->wire.flags |= RXRPC_REQUEST_ACK;
pkt->whdr.callNumber = htonl(call->call_id);
pkt->whdr.seq = 0;
pkt->whdr.type = RXRPC_PACKET_TYPE_ACK;
pkt->whdr.flags = RXRPC_SLOW_START_OK | conn->out_clientflag;
pkt->whdr.userStatus = 0;
pkt->whdr.securityIndex = call->security_ix;
pkt->whdr._rsvd = 0;
pkt->whdr.serviceId = htons(call->service_id);
spin_lock_bh(&call->lock); spin_lock_bh(&call->lock);
if (ping) { n = rxrpc_fill_out_ack(conn, call, txb, &hard_ack, &top);
reason = RXRPC_ACK_PING;
} else {
reason = call->ackr_reason;
if (!call->ackr_reason) {
spin_unlock_bh(&call->lock);
ret = 0;
goto out;
}
call->ackr_reason = 0;
}
n = rxrpc_fill_out_ack(conn, call, pkt, &hard_ack, &top, reason);
spin_unlock_bh(&call->lock); spin_unlock_bh(&call->lock);
if (n == 0) { if (n == 0) {
kfree(pkt); kfree(pkt);
return 0; return 0;
} }
iov[0].iov_base = pkt; iov[0].iov_base = &txb->wire;
iov[0].iov_len = sizeof(pkt->whdr) + sizeof(pkt->ack) + n; iov[0].iov_len = sizeof(txb->wire) + sizeof(txb->ack) + n;
iov[1].iov_base = &pkt->ackinfo; len = iov[0].iov_len;
iov[1].iov_len = sizeof(pkt->ackinfo);
len = iov[0].iov_len + iov[1].iov_len;
serial = atomic_inc_return(&conn->serial); serial = atomic_inc_return(&conn->serial);
pkt->whdr.serial = htonl(serial); txb->wire.serial = htonl(serial);
trace_rxrpc_tx_ack(call->debug_id, serial, trace_rxrpc_tx_ack(call->debug_id, serial,
ntohl(pkt->ack.firstPacket), ntohl(txb->ack.firstPacket),
ntohl(pkt->ack.serial), ntohl(txb->ack.serial), txb->ack.reason, txb->ack.nAcks);
pkt->ack.reason, pkt->ack.nAcks); if (txb->ack_why == rxrpc_propose_ack_ping_for_lost_ack)
if (_serial) call->acks_lost_ping = serial;
*_serial = serial;
if (ping) if (txb->ack.reason == RXRPC_ACK_PING)
rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_ping); rtt_slot = rxrpc_begin_rtt_probe(call, serial, rxrpc_rtt_tx_ping);
rxrpc_inc_stat(call->rxnet, stat_tx_ack_send); rxrpc_inc_stat(call->rxnet, stat_tx_ack_send);
iov_iter_kvec(&msg.msg_iter, WRITE, iov, 2, len); iov_iter_kvec(&msg.msg_iter, WRITE, iov, 1, len);
ret = do_udp_sendmsg(conn->params.local->socket, &msg, len); ret = do_udp_sendmsg(conn->params.local->socket, &msg, len);
call->peer->last_tx_at = ktime_get_seconds(); call->peer->last_tx_at = ktime_get_seconds();
if (ret < 0) if (ret < 0)
trace_rxrpc_tx_fail(call->debug_id, serial, ret, trace_rxrpc_tx_fail(call->debug_id, serial, ret,
rxrpc_tx_point_call_ack); rxrpc_tx_point_call_ack);
else else
trace_rxrpc_tx_packet(call->debug_id, &pkt->whdr, trace_rxrpc_tx_packet(call->debug_id, &txb->wire,
rxrpc_tx_point_call_ack); rxrpc_tx_point_call_ack);
rxrpc_tx_backoff(call, ret); rxrpc_tx_backoff(call, ret);
if (call->state < RXRPC_CALL_COMPLETE) { if (call->state < RXRPC_CALL_COMPLETE) {
if (ret < 0) { if (ret < 0)
rxrpc_cancel_rtt_probe(call, serial, rtt_slot); rxrpc_cancel_rtt_probe(call, serial, rtt_slot);
rxrpc_propose_ACK(call, pkt->ack.reason,
ntohl(pkt->ack.serial),
false, true,
rxrpc_propose_ack_retry_tx);
}
rxrpc_set_keepalive(call); rxrpc_set_keepalive(call);
} }
out:
kfree(pkt); kfree(pkt);
return ret; return ret;
} }
/*
* ACK transmitter for a local endpoint. The UDP socket locks around each
* transmission, so we can only transmit one packet at a time, ACK, DATA or
* otherwise.
*/
void rxrpc_transmit_ack_packets(struct rxrpc_local *local)
{
LIST_HEAD(queue);
int ret;
trace_rxrpc_local(local->debug_id, rxrpc_local_tx_ack,
refcount_read(&local->ref), NULL);
if (list_empty(&local->ack_tx_queue))
return;
spin_lock_bh(&local->ack_tx_lock);
list_splice_tail_init(&local->ack_tx_queue, &queue);
spin_unlock_bh(&local->ack_tx_lock);
while (!list_empty(&queue)) {
struct rxrpc_txbuf *txb =
list_entry(queue.next, struct rxrpc_txbuf, tx_link);
ret = rxrpc_send_ack_packet(local, txb);
if (ret < 0 && ret != -ECONNRESET) {
spin_lock_bh(&local->ack_tx_lock);
list_splice_init(&queue, &local->ack_tx_queue);
spin_unlock_bh(&local->ack_tx_lock);
break;
}
list_del_init(&txb->tx_link);
rxrpc_put_call(txb->call, rxrpc_call_put);
rxrpc_put_txbuf(txb, rxrpc_txbuf_put_ack_tx);
}
}
/* /*
* Send an ABORT call packet. * Send an ABORT call packet.
*/ */
......
...@@ -189,7 +189,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial) ...@@ -189,7 +189,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
ASSERTCMP(call->rx_hard_ack, ==, call->rx_top); ASSERTCMP(call->rx_hard_ack, ==, call->rx_top);
if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) { if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) {
rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, serial, false, true, rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, serial,
rxrpc_propose_ack_terminal_ack); rxrpc_propose_ack_terminal_ack);
//rxrpc_send_ack_packet(call, false, NULL); //rxrpc_send_ack_packet(call, false, NULL);
} }
...@@ -206,7 +206,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial) ...@@ -206,7 +206,7 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call, rxrpc_serial_t serial)
call->state = RXRPC_CALL_SERVER_ACK_REQUEST; call->state = RXRPC_CALL_SERVER_ACK_REQUEST;
call->expect_req_by = jiffies + MAX_JIFFY_OFFSET; call->expect_req_by = jiffies + MAX_JIFFY_OFFSET;
write_unlock_bh(&call->state_lock); write_unlock_bh(&call->state_lock);
rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial, false, true, rxrpc_propose_ACK(call, RXRPC_ACK_DELAY, serial,
rxrpc_propose_ack_processing_op); rxrpc_propose_ack_processing_op);
break; break;
default: default:
...@@ -259,12 +259,11 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call) ...@@ -259,12 +259,11 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call)
rxrpc_end_rx_phase(call, serial); rxrpc_end_rx_phase(call, serial);
} else { } else {
/* Check to see if there's an ACK that needs sending. */ /* Check to see if there's an ACK that needs sending. */
if (atomic_inc_return(&call->ackr_nr_consumed) > 2) if (atomic_inc_return(&call->ackr_nr_consumed) > 2) {
rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, serial, rxrpc_send_ACK(call, RXRPC_ACK_IDLE, serial,
true, false, rxrpc_propose_ack_rotate_rx);
rxrpc_propose_ack_rotate_rx); rxrpc_transmit_ack_packets(call->peer->local);
if (call->ackr_reason && call->ackr_reason != RXRPC_ACK_DELAY) }
rxrpc_send_ack_packet(call, false, NULL);
} }
} }
...@@ -363,10 +362,6 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, ...@@ -363,10 +362,6 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
unsigned int rx_pkt_offset, rx_pkt_len; unsigned int rx_pkt_offset, rx_pkt_len;
int ix, copy, ret = -EAGAIN, ret2; int ix, copy, ret = -EAGAIN, ret2;
if (test_and_clear_bit(RXRPC_CALL_RX_UNDERRUN, &call->flags) &&
call->ackr_reason)
rxrpc_send_ack_packet(call, false, NULL);
rx_pkt_offset = call->rx_pkt_offset; rx_pkt_offset = call->rx_pkt_offset;
rx_pkt_len = call->rx_pkt_len; rx_pkt_len = call->rx_pkt_len;
rx_pkt_last = call->rx_pkt_last; rx_pkt_last = call->rx_pkt_last;
...@@ -389,6 +384,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, ...@@ -389,6 +384,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
if (!skb) { if (!skb) {
trace_rxrpc_recvmsg(call, rxrpc_recvmsg_hole, seq, trace_rxrpc_recvmsg(call, rxrpc_recvmsg_hole, seq,
rx_pkt_offset, rx_pkt_len, 0); rx_pkt_offset, rx_pkt_len, 0);
rxrpc_transmit_ack_packets(call->peer->local);
break; break;
} }
smp_rmb(); smp_rmb();
...@@ -604,6 +600,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, ...@@ -604,6 +600,7 @@ int rxrpc_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (ret == -EAGAIN) if (ret == -EAGAIN)
ret = 0; ret = 0;
rxrpc_transmit_ack_packets(call->peer->local);
if (after(call->rx_top, call->rx_hard_ack) && if (after(call->rx_top, call->rx_hard_ack) &&
call->rxtx_buffer[(call->rx_hard_ack + 1) & RXRPC_RXTX_BUFF_MASK]) call->rxtx_buffer[(call->rx_hard_ack + 1) & RXRPC_RXTX_BUFF_MASK])
rxrpc_notify_socket(call); rxrpc_notify_socket(call);
...@@ -734,17 +731,7 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call, ...@@ -734,17 +731,7 @@ int rxrpc_kernel_recv_data(struct socket *sock, struct rxrpc_call *call,
read_phase_complete: read_phase_complete:
ret = 1; ret = 1;
out: out:
switch (call->ackr_reason) { rxrpc_transmit_ack_packets(call->peer->local);
case RXRPC_ACK_IDLE:
break;
case RXRPC_ACK_DELAY:
if (ret != -EAGAIN)
break;
fallthrough;
default:
rxrpc_send_ack_packet(call, false, NULL);
}
if (_service) if (_service)
*_service = call->service_id; *_service = call->service_id;
mutex_unlock(&call->user_mutex); mutex_unlock(&call->user_mutex);
......
...@@ -332,9 +332,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx, ...@@ -332,9 +332,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
rxrpc_see_skb(skb, rxrpc_skb_seen); rxrpc_see_skb(skb, rxrpc_skb_seen);
do { do {
/* Check to see if there's a ping ACK to reply to. */ rxrpc_transmit_ack_packets(call->peer->local);
if (call->ackr_reason == RXRPC_ACK_PING_RESPONSE)
rxrpc_send_ack_packet(call, false, NULL);
if (!skb) { if (!skb) {
size_t remain, bufsize, chunk, offset; size_t remain, bufsize, chunk, offset;
......
...@@ -33,6 +33,7 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type, ...@@ -33,6 +33,7 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type,
txb->len = 0; txb->len = 0;
txb->offset = 0; txb->offset = 0;
txb->flags = 0; txb->flags = 0;
txb->ack_why = 0;
txb->seq = call->tx_top + 1; txb->seq = call->tx_top + 1;
txb->wire.epoch = htonl(call->conn->proto.epoch); txb->wire.epoch = htonl(call->conn->proto.epoch);
txb->wire.cid = htonl(call->cid); txb->wire.cid = htonl(call->cid);
......
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