Commit fc9de52d authored by David Howells's avatar David Howells Committed by Jakub Kicinski
Browse files

rxrpc: Fix missing locking causing hanging calls



If a call gets aborted (e.g. because kafs saw a signal) between it being
queued for connection and the I/O thread picking up the call, the abort
will be prioritised over the connection and it will be removed from
local->new_client_calls by rxrpc_disconnect_client_call() without a lock
being held.  This may cause other calls on the list to disappear if a race
occurs.

Fix this by taking the client_call_lock when removing a call from whatever
list its ->wait_link happens to be on.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: linux-afs@lists.infradead.org
Reported-by: default avatarMarc Dionne <marc.dionne@auristor.com>
Fixes: 9d35d880 ("rxrpc: Move client call connection to the I/O thread")
Link: https://patch.msgid.link/726660.1730898202@warthog.procyon.org.uk


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent de88df01
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -287,6 +287,7 @@
	EM(rxrpc_call_see_input,		"SEE input   ") \
	EM(rxrpc_call_see_release,		"SEE release ") \
	EM(rxrpc_call_see_userid_exists,	"SEE u-exists") \
	EM(rxrpc_call_see_waiting_call,		"SEE q-conn  ") \
	E_(rxrpc_call_see_zap,			"SEE zap     ")

#define rxrpc_txqueue_traces \
+4 −0
Original line number Diff line number Diff line
@@ -516,6 +516,7 @@ void rxrpc_connect_client_calls(struct rxrpc_local *local)

		spin_lock(&local->client_call_lock);
		list_move_tail(&call->wait_link, &bundle->waiting_calls);
		rxrpc_see_call(call, rxrpc_call_see_waiting_call);
		spin_unlock(&local->client_call_lock);

		if (rxrpc_bundle_has_space(bundle))
@@ -586,7 +587,10 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
		_debug("call is waiting");
		ASSERTCMP(call->call_id, ==, 0);
		ASSERT(!test_bit(RXRPC_CALL_EXPOSED, &call->flags));
		/* May still be on ->new_client_calls. */
		spin_lock(&local->client_call_lock);
		list_del_init(&call->wait_link);
		spin_unlock(&local->client_call_lock);
		return;
	}