Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64753092 authored by David Howells's avatar David Howells
Browse files

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
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -442,8 +442,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 */
@@ -453,6 +452,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)
+2 −2
Original line number Diff line number Diff line
@@ -405,11 +405,11 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,

	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
Original line number Diff line number Diff line
@@ -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(chan->call_debug_id, serial,
@@ -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
 */
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);

@@ -172,9 +171,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);
		}
	}
@@ -207,10 +208,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;
@@ -229,7 +232,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);
@@ -240,7 +243,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) {
@@ -315,9 +318,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: