Commit 4c1295dc authored by David Howells's avatar David Howells

rxrpc: Fix trace-after-put looking at the put connection record

rxrpc_put_*conn() calls trace_rxrpc_conn() after they have done the
decrement of the refcount - which looks at the debug_id in the connection
record.  But unless the refcount was reduced to zero, we no longer have the
right to look in the record and, indeed, it may be deleted by some other
thread.

Fix this by getting the debug_id out before decrementing the refcount and
then passing that into the tracepoint.

Fixes: 363deeab ("rxrpc: Add connection tracepoint and client conn state tracepoint")
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 55f6c98e
...@@ -546,10 +546,10 @@ TRACE_EVENT(rxrpc_peer, ...@@ -546,10 +546,10 @@ TRACE_EVENT(rxrpc_peer,
); );
TRACE_EVENT(rxrpc_conn, TRACE_EVENT(rxrpc_conn,
TP_PROTO(struct rxrpc_connection *conn, enum rxrpc_conn_trace op, TP_PROTO(unsigned int conn_debug_id, enum rxrpc_conn_trace op,
int usage, const void *where), int usage, const void *where),
TP_ARGS(conn, op, usage, where), TP_ARGS(conn_debug_id, op, usage, where),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned int, conn ) __field(unsigned int, conn )
...@@ -559,7 +559,7 @@ TRACE_EVENT(rxrpc_conn, ...@@ -559,7 +559,7 @@ TRACE_EVENT(rxrpc_conn,
), ),
TP_fast_assign( TP_fast_assign(
__entry->conn = conn->debug_id; __entry->conn = conn_debug_id;
__entry->op = op; __entry->op = op;
__entry->usage = usage; __entry->usage = usage;
__entry->where = where; __entry->where = where;
......
...@@ -84,7 +84,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, ...@@ -84,7 +84,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
smp_store_release(&b->conn_backlog_head, smp_store_release(&b->conn_backlog_head,
(head + 1) & (size - 1)); (head + 1) & (size - 1));
trace_rxrpc_conn(conn, rxrpc_conn_new_service, trace_rxrpc_conn(conn->debug_id, rxrpc_conn_new_service,
atomic_read(&conn->usage), here); atomic_read(&conn->usage), here);
} }
......
...@@ -212,7 +212,8 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp) ...@@ -212,7 +212,8 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp)
rxrpc_get_local(conn->params.local); rxrpc_get_local(conn->params.local);
key_get(conn->params.key); key_get(conn->params.key);
trace_rxrpc_conn(conn, rxrpc_conn_new_client, atomic_read(&conn->usage), trace_rxrpc_conn(conn->debug_id, rxrpc_conn_new_client,
atomic_read(&conn->usage),
__builtin_return_address(0)); __builtin_return_address(0));
trace_rxrpc_client(conn, -1, rxrpc_client_alloc); trace_rxrpc_client(conn, -1, rxrpc_client_alloc);
_leave(" = %p", conn); _leave(" = %p", conn);
...@@ -985,11 +986,12 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn) ...@@ -985,11 +986,12 @@ rxrpc_put_one_client_conn(struct rxrpc_connection *conn)
void rxrpc_put_client_conn(struct rxrpc_connection *conn) void rxrpc_put_client_conn(struct rxrpc_connection *conn)
{ {
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
unsigned int debug_id = conn->debug_id;
int n; int n;
do { do {
n = atomic_dec_return(&conn->usage); n = atomic_dec_return(&conn->usage);
trace_rxrpc_conn(conn, rxrpc_conn_put_client, n, here); trace_rxrpc_conn(debug_id, rxrpc_conn_put_client, n, here);
if (n > 0) if (n > 0)
return; return;
ASSERTCMP(n, >=, 0); ASSERTCMP(n, >=, 0);
......
...@@ -269,7 +269,7 @@ bool rxrpc_queue_conn(struct rxrpc_connection *conn) ...@@ -269,7 +269,7 @@ bool rxrpc_queue_conn(struct rxrpc_connection *conn)
if (n == 0) if (n == 0)
return false; return false;
if (rxrpc_queue_work(&conn->processor)) if (rxrpc_queue_work(&conn->processor))
trace_rxrpc_conn(conn, rxrpc_conn_queued, n + 1, here); trace_rxrpc_conn(conn->debug_id, rxrpc_conn_queued, n + 1, here);
else else
rxrpc_put_connection(conn); rxrpc_put_connection(conn);
return true; return true;
...@@ -284,7 +284,7 @@ void rxrpc_see_connection(struct rxrpc_connection *conn) ...@@ -284,7 +284,7 @@ void rxrpc_see_connection(struct rxrpc_connection *conn)
if (conn) { if (conn) {
int n = atomic_read(&conn->usage); int n = atomic_read(&conn->usage);
trace_rxrpc_conn(conn, rxrpc_conn_seen, n, here); trace_rxrpc_conn(conn->debug_id, rxrpc_conn_seen, n, here);
} }
} }
...@@ -296,7 +296,7 @@ void rxrpc_get_connection(struct rxrpc_connection *conn) ...@@ -296,7 +296,7 @@ void rxrpc_get_connection(struct rxrpc_connection *conn)
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
int n = atomic_inc_return(&conn->usage); int n = atomic_inc_return(&conn->usage);
trace_rxrpc_conn(conn, rxrpc_conn_got, n, here); trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, n, here);
} }
/* /*
...@@ -310,7 +310,7 @@ rxrpc_get_connection_maybe(struct rxrpc_connection *conn) ...@@ -310,7 +310,7 @@ rxrpc_get_connection_maybe(struct rxrpc_connection *conn)
if (conn) { if (conn) {
int n = atomic_fetch_add_unless(&conn->usage, 1, 0); int n = atomic_fetch_add_unless(&conn->usage, 1, 0);
if (n > 0) if (n > 0)
trace_rxrpc_conn(conn, rxrpc_conn_got, n + 1, here); trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, n + 1, here);
else else
conn = NULL; conn = NULL;
} }
...@@ -333,10 +333,11 @@ static void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet, ...@@ -333,10 +333,11 @@ static void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet,
void rxrpc_put_service_conn(struct rxrpc_connection *conn) void rxrpc_put_service_conn(struct rxrpc_connection *conn)
{ {
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
unsigned int debug_id = conn->debug_id;
int n; int n;
n = atomic_dec_return(&conn->usage); n = atomic_dec_return(&conn->usage);
trace_rxrpc_conn(conn, rxrpc_conn_put_service, n, here); trace_rxrpc_conn(debug_id, rxrpc_conn_put_service, n, here);
ASSERTCMP(n, >=, 0); ASSERTCMP(n, >=, 0);
if (n == 1) if (n == 1)
rxrpc_set_service_reap_timer(conn->params.local->rxnet, rxrpc_set_service_reap_timer(conn->params.local->rxnet,
...@@ -420,7 +421,7 @@ void rxrpc_service_connection_reaper(struct work_struct *work) ...@@ -420,7 +421,7 @@ void rxrpc_service_connection_reaper(struct work_struct *work)
*/ */
if (atomic_cmpxchg(&conn->usage, 1, 0) != 1) if (atomic_cmpxchg(&conn->usage, 1, 0) != 1)
continue; continue;
trace_rxrpc_conn(conn, rxrpc_conn_reap_service, 0, NULL); trace_rxrpc_conn(conn->debug_id, rxrpc_conn_reap_service, 0, NULL);
if (rxrpc_conn_is_client(conn)) if (rxrpc_conn_is_client(conn))
BUG(); BUG();
......
...@@ -134,7 +134,7 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn ...@@ -134,7 +134,7 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn
list_add_tail(&conn->proc_link, &rxnet->conn_proc_list); list_add_tail(&conn->proc_link, &rxnet->conn_proc_list);
write_unlock(&rxnet->conn_lock); write_unlock(&rxnet->conn_lock);
trace_rxrpc_conn(conn, rxrpc_conn_new_service, trace_rxrpc_conn(conn->debug_id, rxrpc_conn_new_service,
atomic_read(&conn->usage), atomic_read(&conn->usage),
__builtin_return_address(0)); __builtin_return_address(0));
} }
......
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