mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
rxrpc: Fix connection-level abort handling
[ Upstream commit647530924f] Fix connection-level abort handling to cache the abort and error codes properly so that a new incoming call can be properly aborted if it races with the parent connection being aborted by another CPU. The abort_code and error parameters can then be dropped from rxrpc_abort_calls(). Fixes:f5c17aaeb2("rxrpc: Calls should only have one terminal state") Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
47af9661cc
commit
98154205f7
@@ -446,8 +446,7 @@ struct rxrpc_connection {
|
||||
spinlock_t state_lock; /* state-change lock */
|
||||
enum rxrpc_conn_cache_state cache_state;
|
||||
enum rxrpc_conn_proto_state state; /* current state of connection */
|
||||
u32 local_abort; /* local abort code */
|
||||
u32 remote_abort; /* remote abort code */
|
||||
u32 abort_code; /* Abort code of connection abort */
|
||||
int debug_id; /* debug ID for printks */
|
||||
atomic_t serial; /* packet serial number counter */
|
||||
unsigned int hi_serial; /* highest serial number received */
|
||||
@@ -457,6 +456,7 @@ struct rxrpc_connection {
|
||||
u8 security_size; /* security header size */
|
||||
u8 security_ix; /* security type */
|
||||
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */
|
||||
short error; /* Local error code */
|
||||
};
|
||||
|
||||
static inline bool rxrpc_to_server(const struct rxrpc_skb_priv *sp)
|
||||
|
||||
@@ -422,11 +422,11 @@ found_service:
|
||||
|
||||
case RXRPC_CONN_REMOTELY_ABORTED:
|
||||
rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED,
|
||||
conn->remote_abort, -ECONNABORTED);
|
||||
conn->abort_code, conn->error);
|
||||
break;
|
||||
case RXRPC_CONN_LOCALLY_ABORTED:
|
||||
rxrpc_abort_call("CON", call, sp->hdr.seq,
|
||||
conn->local_abort, -ECONNABORTED);
|
||||
conn->abort_code, conn->error);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
|
||||
+15
-11
@@ -126,7 +126,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
|
||||
|
||||
switch (chan->last_type) {
|
||||
case RXRPC_PACKET_TYPE_ABORT:
|
||||
_proto("Tx ABORT %%%u { %d } [re]", serial, conn->local_abort);
|
||||
_proto("Tx ABORT %%%u { %d } [re]", serial, conn->abort_code);
|
||||
break;
|
||||
case RXRPC_PACKET_TYPE_ACK:
|
||||
trace_rxrpc_tx_ack(NULL, serial, chan->last_seq, 0,
|
||||
@@ -148,13 +148,12 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
|
||||
* pass a connection-level abort onto all calls on that connection
|
||||
*/
|
||||
static void rxrpc_abort_calls(struct rxrpc_connection *conn,
|
||||
enum rxrpc_call_completion compl,
|
||||
u32 abort_code, int error)
|
||||
enum rxrpc_call_completion compl)
|
||||
{
|
||||
struct rxrpc_call *call;
|
||||
int i;
|
||||
|
||||
_enter("{%d},%x", conn->debug_id, abort_code);
|
||||
_enter("{%d},%x", conn->debug_id, conn->abort_code);
|
||||
|
||||
spin_lock(&conn->channel_lock);
|
||||
|
||||
@@ -167,9 +166,11 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn,
|
||||
trace_rxrpc_abort(call->debug_id,
|
||||
"CON", call->cid,
|
||||
call->call_id, 0,
|
||||
abort_code, error);
|
||||
conn->abort_code,
|
||||
conn->error);
|
||||
if (rxrpc_set_call_completion(call, compl,
|
||||
abort_code, error))
|
||||
conn->abort_code,
|
||||
conn->error))
|
||||
rxrpc_notify_socket(call);
|
||||
}
|
||||
}
|
||||
@@ -202,10 +203,12 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
|
||||
return 0;
|
||||
}
|
||||
|
||||
conn->error = error;
|
||||
conn->abort_code = abort_code;
|
||||
conn->state = RXRPC_CONN_LOCALLY_ABORTED;
|
||||
spin_unlock_bh(&conn->state_lock);
|
||||
|
||||
rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED, abort_code, error);
|
||||
rxrpc_abort_calls(conn, RXRPC_CALL_LOCALLY_ABORTED);
|
||||
|
||||
msg.msg_name = &conn->params.peer->srx.transport;
|
||||
msg.msg_namelen = conn->params.peer->srx.transport_len;
|
||||
@@ -224,7 +227,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
|
||||
whdr._rsvd = 0;
|
||||
whdr.serviceId = htons(conn->service_id);
|
||||
|
||||
word = htonl(conn->local_abort);
|
||||
word = htonl(conn->abort_code);
|
||||
|
||||
iov[0].iov_base = &whdr;
|
||||
iov[0].iov_len = sizeof(whdr);
|
||||
@@ -235,7 +238,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
|
||||
|
||||
serial = atomic_inc_return(&conn->serial);
|
||||
whdr.serial = htonl(serial);
|
||||
_proto("Tx CONN ABORT %%%u { %d }", serial, conn->local_abort);
|
||||
_proto("Tx CONN ABORT %%%u { %d }", serial, conn->abort_code);
|
||||
|
||||
ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
|
||||
if (ret < 0) {
|
||||
@@ -308,9 +311,10 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
|
||||
abort_code = ntohl(wtmp);
|
||||
_proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code);
|
||||
|
||||
conn->error = -ECONNABORTED;
|
||||
conn->abort_code = abort_code;
|
||||
conn->state = RXRPC_CONN_REMOTELY_ABORTED;
|
||||
rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED,
|
||||
abort_code, -ECONNABORTED);
|
||||
rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED);
|
||||
return -ECONNABORTED;
|
||||
|
||||
case RXRPC_PACKET_TYPE_CHALLENGE:
|
||||
|
||||
Reference in New Issue
Block a user