]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
rxrpc: Fix missing locking causing hanging calls
authorDavid Howells <dhowells@redhat.com>
Wed, 6 Nov 2024 13:03:22 +0000 (13:03 +0000)
committerJakub Kicinski <kuba@kernel.org>
Thu, 7 Nov 2024 19:30:34 +0000 (11:30 -0800)
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: David Howells <dhowells@redhat.com>
cc: linux-afs@lists.infradead.org
Reported-by: Marc Dionne <marc.dionne@auristor.com>
Fixes: 9d35d880e0e4 ("rxrpc: Move client call connection to the I/O thread")
Link: https://patch.msgid.link/726660.1730898202@warthog.procyon.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/trace/events/rxrpc.h
net/rxrpc/conn_client.c

index a1b126a6b0d72d36b959e699aea4a2c6125b61e1..cc22596c7250cf62bfffacd5033be0073c62c602 100644 (file)
        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 \
index d25bf1cf36700d9320192400e3171045d8b4ae98..bb11e8289d6dcfbb43c808dd4c23deaa83e71e6a 100644 (file)
@@ -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;
        }