diff options
Diffstat (limited to 'net/rxrpc/input.c')
| -rw-r--r-- | net/rxrpc/input.c | 27 | 
1 files changed, 19 insertions, 8 deletions
diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c index 9f4cfa25af7c..18b2ad8be8e2 100644 --- a/net/rxrpc/input.c +++ b/net/rxrpc/input.c @@ -420,6 +420,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,  			     u16 skew)  {  	struct rxrpc_skb_priv *sp = rxrpc_skb(skb); +	enum rxrpc_call_state state;  	unsigned int offset = sizeof(struct rxrpc_wire_header);  	unsigned int ix;  	rxrpc_serial_t serial = sp->hdr.serial, ack_serial = 0; @@ -434,14 +435,15 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb,  	_proto("Rx DATA %%%u { #%u f=%02x }",  	       sp->hdr.serial, seq, sp->hdr.flags); -	if (call->state >= RXRPC_CALL_COMPLETE) +	state = READ_ONCE(call->state); +	if (state >= RXRPC_CALL_COMPLETE)  		return;  	/* Received data implicitly ACKs all of the request packets we sent  	 * when we're acting as a client.  	 */ -	if ((call->state == RXRPC_CALL_CLIENT_SEND_REQUEST || -	     call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY) && +	if ((state == RXRPC_CALL_CLIENT_SEND_REQUEST || +	     state == RXRPC_CALL_CLIENT_AWAIT_REPLY) &&  	    !rxrpc_receiving_reply(call))  		return; @@ -650,6 +652,7 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,  	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);  	struct rxrpc_peer *peer;  	unsigned int mtu; +	bool wake = false;  	u32 rwind = ntohl(ackinfo->rwind);  	_proto("Rx ACK %%%u Info { rx=%u max=%u rwin=%u jm=%u }", @@ -657,9 +660,14 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,  	       ntohl(ackinfo->rxMTU), ntohl(ackinfo->maxMTU),  	       rwind, ntohl(ackinfo->jumbo_max)); -	if (rwind > RXRPC_RXTX_BUFF_SIZE - 1) -		rwind = RXRPC_RXTX_BUFF_SIZE - 1; -	call->tx_winsize = rwind; +	if (call->tx_winsize != rwind) { +		if (rwind > RXRPC_RXTX_BUFF_SIZE - 1) +			rwind = RXRPC_RXTX_BUFF_SIZE - 1; +		if (rwind > call->tx_winsize) +			wake = true; +		call->tx_winsize = rwind; +	} +  	if (call->cong_ssthresh > rwind)  		call->cong_ssthresh = rwind; @@ -673,6 +681,9 @@ static void rxrpc_input_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,  		spin_unlock_bh(&peer->lock);  		_net("Net MTU %u (maxdata %u)", peer->mtu, peer->maxdata);  	} + +	if (wake) +		wake_up(&call->waitq);  }  /* @@ -799,7 +810,7 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb,  		return rxrpc_proto_abort("AK0", call, 0);  	/* Ignore ACKs unless we are or have just been transmitting. */ -	switch (call->state) { +	switch (READ_ONCE(call->state)) {  	case RXRPC_CALL_CLIENT_SEND_REQUEST:  	case RXRPC_CALL_CLIENT_AWAIT_REPLY:  	case RXRPC_CALL_SERVER_SEND_REPLY: @@ -940,7 +951,7 @@ static void rxrpc_input_call_packet(struct rxrpc_call *call,  static void rxrpc_input_implicit_end_call(struct rxrpc_connection *conn,  					  struct rxrpc_call *call)  { -	switch (call->state) { +	switch (READ_ONCE(call->state)) {  	case RXRPC_CALL_SERVER_AWAIT_ACK:  		rxrpc_call_completed(call);  		break;  | 
