Commit 64753092 authored by David Howells's avatar David Howells

rxrpc: Fix connection-level abort handling

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: f5c17aae ("rxrpc: Calls should only have one terminal state")
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 298bc15b
...@@ -442,8 +442,7 @@ struct rxrpc_connection { ...@@ -442,8 +442,7 @@ struct rxrpc_connection {
spinlock_t state_lock; /* state-change lock */ spinlock_t state_lock; /* state-change lock */
enum rxrpc_conn_cache_state cache_state; enum rxrpc_conn_cache_state cache_state;
enum rxrpc_conn_proto_state state; /* current state of connection */ enum rxrpc_conn_proto_state state; /* current state of connection */
u32 local_abort; /* local abort code */ u32 abort_code; /* Abort code of connection abort */
u32 remote_abort; /* remote abort code */
int debug_id; /* debug ID for printks */ int debug_id; /* debug ID for printks */
atomic_t serial; /* packet serial number counter */ atomic_t serial; /* packet serial number counter */
unsigned int hi_serial; /* highest serial number received */ unsigned int hi_serial; /* highest serial number received */
...@@ -453,6 +452,7 @@ struct rxrpc_connection { ...@@ -453,6 +452,7 @@ struct rxrpc_connection {
u8 security_size; /* security header size */ u8 security_size; /* security header size */
u8 security_ix; /* security type */ u8 security_ix; /* security type */
u8 out_clientflag; /* RXRPC_CLIENT_INITIATED if we are client */ 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) static inline bool rxrpc_to_server(const struct rxrpc_skb_priv *sp)
......
...@@ -405,11 +405,11 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local, ...@@ -405,11 +405,11 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
case RXRPC_CONN_REMOTELY_ABORTED: case RXRPC_CONN_REMOTELY_ABORTED:
rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED, rxrpc_set_call_completion(call, RXRPC_CALL_REMOTELY_ABORTED,
conn->remote_abort, -ECONNABORTED); conn->abort_code, conn->error);
break; break;
case RXRPC_CONN_LOCALLY_ABORTED: case RXRPC_CONN_LOCALLY_ABORTED:
rxrpc_abort_call("CON", call, sp->hdr.seq, rxrpc_abort_call("CON", call, sp->hdr.seq,
conn->local_abort, -ECONNABORTED); conn->abort_code, conn->error);
break; break;
default: default:
BUG(); BUG();
......
...@@ -126,7 +126,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, ...@@ -126,7 +126,7 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
switch (chan->last_type) { switch (chan->last_type) {
case RXRPC_PACKET_TYPE_ABORT: 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; break;
case RXRPC_PACKET_TYPE_ACK: case RXRPC_PACKET_TYPE_ACK:
trace_rxrpc_tx_ack(chan->call_debug_id, serial, trace_rxrpc_tx_ack(chan->call_debug_id, serial,
...@@ -153,13 +153,12 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn, ...@@ -153,13 +153,12 @@ static void rxrpc_conn_retransmit_call(struct rxrpc_connection *conn,
* pass a connection-level abort onto all calls on that connection * pass a connection-level abort onto all calls on that connection
*/ */
static void rxrpc_abort_calls(struct rxrpc_connection *conn, static void rxrpc_abort_calls(struct rxrpc_connection *conn,
enum rxrpc_call_completion compl, enum rxrpc_call_completion compl)
u32 abort_code, int error)
{ {
struct rxrpc_call *call; struct rxrpc_call *call;
int i; int i;
_enter("{%d},%x", conn->debug_id, abort_code); _enter("{%d},%x", conn->debug_id, conn->abort_code);
spin_lock(&conn->channel_lock); spin_lock(&conn->channel_lock);
...@@ -172,9 +171,11 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn, ...@@ -172,9 +171,11 @@ static void rxrpc_abort_calls(struct rxrpc_connection *conn,
trace_rxrpc_abort(call->debug_id, trace_rxrpc_abort(call->debug_id,
"CON", call->cid, "CON", call->cid,
call->call_id, 0, call->call_id, 0,
abort_code, error); conn->abort_code,
conn->error);
if (rxrpc_set_call_completion(call, compl, if (rxrpc_set_call_completion(call, compl,
abort_code, error)) conn->abort_code,
conn->error))
rxrpc_notify_socket(call); rxrpc_notify_socket(call);
} }
} }
...@@ -207,10 +208,12 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn, ...@@ -207,10 +208,12 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
return 0; return 0;
} }
conn->error = error;
conn->abort_code = abort_code;
conn->state = RXRPC_CONN_LOCALLY_ABORTED; conn->state = RXRPC_CONN_LOCALLY_ABORTED;
spin_unlock_bh(&conn->state_lock); 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_name = &conn->params.peer->srx.transport;
msg.msg_namelen = conn->params.peer->srx.transport_len; msg.msg_namelen = conn->params.peer->srx.transport_len;
...@@ -229,7 +232,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn, ...@@ -229,7 +232,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
whdr._rsvd = 0; whdr._rsvd = 0;
whdr.serviceId = htons(conn->service_id); whdr.serviceId = htons(conn->service_id);
word = htonl(conn->local_abort); word = htonl(conn->abort_code);
iov[0].iov_base = &whdr; iov[0].iov_base = &whdr;
iov[0].iov_len = sizeof(whdr); iov[0].iov_len = sizeof(whdr);
...@@ -240,7 +243,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn, ...@@ -240,7 +243,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn,
serial = atomic_inc_return(&conn->serial); serial = atomic_inc_return(&conn->serial);
whdr.serial = htonl(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); ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
if (ret < 0) { if (ret < 0) {
...@@ -315,9 +318,10 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, ...@@ -315,9 +318,10 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
abort_code = ntohl(wtmp); abort_code = ntohl(wtmp);
_proto("Rx ABORT %%%u { ac=%d }", sp->hdr.serial, abort_code); _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; conn->state = RXRPC_CONN_REMOTELY_ABORTED;
rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED, rxrpc_abort_calls(conn, RXRPC_CALL_REMOTELY_ABORTED);
abort_code, -ECONNABORTED);
return -ECONNABORTED; return -ECONNABORTED;
case RXRPC_PACKET_TYPE_CHALLENGE: case RXRPC_PACKET_TYPE_CHALLENGE:
......
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