diff options
Diffstat (limited to 'net/rxrpc/input.c')
| -rw-r--r-- | net/rxrpc/input.c | 74 | 
1 files changed, 70 insertions, 4 deletions
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index 1b592073ec96..23a5e61d8f79 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -318,16 +318,18 @@ bad_state:  static bool rxrpc_receiving_reply(struct rxrpc_call *call)  {  	struct rxrpc_ack_summary summary = { 0 }; +	unsigned long now, timo;  	rxrpc_seq_t top = READ_ONCE(call->tx_top);  	if (call->ackr_reason) {  		spin_lock_bh(&call->lock);  		call->ackr_reason = 0; -		call->resend_at = call->expire_at; -		call->ack_at = call->expire_at;  		spin_unlock_bh(&call->lock); -		rxrpc_set_timer(call, rxrpc_timer_init_for_reply, -				ktime_get_real()); +		now = jiffies; +		timo = now + MAX_JIFFY_OFFSET; +		WRITE_ONCE(call->resend_at, timo); +		WRITE_ONCE(call->ack_at, timo); +		trace_rxrpc_timer(call, rxrpc_timer_init_for_reply, now);  	}  	if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) @@ -437,6 +439,19 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,  	if (state >= RXRPC_CALL_COMPLETE)  		return; +	if (call->state == RXRPC_CALL_SERVER_RECV_REQUEST) { +		unsigned long timo = READ_ONCE(call->next_req_timo); +		unsigned long now, expect_req_by; + +		if (timo) { +			now = jiffies; +			expect_req_by = now + timo; +			WRITE_ONCE(call->expect_req_by, expect_req_by); +			rxrpc_reduce_call_timer(call, expect_req_by, now, +						rxrpc_timer_set_for_idle); +		} +	} +  	/* Received data implicitly ACKs all of the request packets we sent  	 * when we're acting as a client.  	 */ @@ -616,6 +631,43 @@ found:  }  /* + * Process the response to a ping that we sent to find out if we lost an ACK. + * + * If we got back a ping response that indicates a lower tx_top than what we + * had at the time of the ping transmission, we adjudge all the DATA packets + * sent between the response tx_top and the ping-time tx_top to have been lost. + */ +static void rxrpc_input_check_for_lost_ack(struct rxrpc_call *call) +{ +	rxrpc_seq_t top, bottom, seq; +	bool resend = false; + +	spin_lock_bh(&call->lock); + +	bottom = call->tx_hard_ack + 1; +	top = call->acks_lost_top; +	if (before(bottom, top)) { +		for (seq = bottom; before_eq(seq, top); seq++) { +			int ix = seq & RXRPC_RXTX_BUFF_MASK; +			u8 annotation = call->rxtx_annotations[ix]; +			u8 anno_type = annotation & RXRPC_TX_ANNO_MASK; + +			if (anno_type != RXRPC_TX_ANNO_UNACK) +				continue; +			annotation &= ~RXRPC_TX_ANNO_MASK; +			annotation |= RXRPC_TX_ANNO_RETRANS; +			call->rxtx_annotations[ix] = annotation; +			resend = true; +		} +	} + +	spin_unlock_bh(&call->lock); + +	if (resend && !test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events)) +		rxrpc_queue_call(call); +} + +/*   * Process a ping response.   */  static void rxrpc_input_ping_response(struct rxrpc_call *call, @@ -630,6 +682,9 @@ static void rxrpc_input_ping_response(struct rxrpc_call *call,  	smp_rmb();  	ping_serial = call->ping_serial; +	if (orig_serial == call->acks_lost_ping) +		rxrpc_input_check_for_lost_ack(call); +  	if (!test_bit(RXRPC_CALL_PINGING, &call->flags) ||  	    before(orig_serial, ping_serial))  		return; @@ -908,9 +963,20 @@ static void rxrpc_input_call_packet(struct rxrpc_call *call,  				    struct sk_buff *skb, u16 skew)  {  	struct rxrpc_skb_priv *sp = rxrpc_skb(skb); +	unsigned long timo;  	_enter("%p,%p", call, skb); +	timo = READ_ONCE(call->next_rx_timo); +	if (timo) { +		unsigned long now = jiffies, expect_rx_by; + +		expect_rx_by = jiffies + timo; +		WRITE_ONCE(call->expect_rx_by, expect_rx_by); +		rxrpc_reduce_call_timer(call, expect_rx_by, now, +					rxrpc_timer_set_for_normal); +	} +	  	switch (sp->hdr.type) {  	case RXRPC_PACKET_TYPE_DATA:  		rxrpc_input_data(call, skb, skew);  | 
