Commit 480fd998 authored by David S. Miller's avatar David S. Miller

Merge tag 'rxrpc-fixes-20190814' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

David Howells says:

====================
rxrpc: Fix local endpoint handling

Here's a pair of patches that fix two issues in the handling of local
endpoints (rxrpc_local structs):

 (1) Use list_replace_init() rather than list_replace() if we're going to
     unconditionally delete the replaced item later, lest the list get
     corrupted.

 (2) Don't access the rxrpc_local object after passing our ref to the
     workqueue, not even to illuminate tracepoints, as the work function
     may cause the object to be freed.  We have to cache the information
     beforehand.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 12ed6015 06d9532f
...@@ -498,10 +498,10 @@ rxrpc_tx_points; ...@@ -498,10 +498,10 @@ rxrpc_tx_points;
#define E_(a, b) { a, b } #define E_(a, b) { a, b }
TRACE_EVENT(rxrpc_local, TRACE_EVENT(rxrpc_local,
TP_PROTO(struct rxrpc_local *local, enum rxrpc_local_trace op, TP_PROTO(unsigned int local_debug_id, enum rxrpc_local_trace op,
int usage, const void *where), int usage, const void *where),
TP_ARGS(local, op, usage, where), TP_ARGS(local_debug_id, op, usage, where),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(unsigned int, local ) __field(unsigned int, local )
...@@ -511,7 +511,7 @@ TRACE_EVENT(rxrpc_local, ...@@ -511,7 +511,7 @@ TRACE_EVENT(rxrpc_local,
), ),
TP_fast_assign( TP_fast_assign(
__entry->local = local->debug_id; __entry->local = local_debug_id;
__entry->op = op; __entry->op = op;
__entry->usage = usage; __entry->usage = usage;
__entry->where = where; __entry->where = where;
......
...@@ -93,7 +93,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet, ...@@ -93,7 +93,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
local->debug_id = atomic_inc_return(&rxrpc_debug_id); local->debug_id = atomic_inc_return(&rxrpc_debug_id);
memcpy(&local->srx, srx, sizeof(*srx)); memcpy(&local->srx, srx, sizeof(*srx));
local->srx.srx_service = 0; local->srx.srx_service = 0;
trace_rxrpc_local(local, rxrpc_local_new, 1, NULL); trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, NULL);
} }
_leave(" = %p", local); _leave(" = %p", local);
...@@ -283,7 +283,7 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net, ...@@ -283,7 +283,7 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
goto sock_error; goto sock_error;
if (cursor != &rxnet->local_endpoints) if (cursor != &rxnet->local_endpoints)
list_replace(cursor, &local->link); list_replace_init(cursor, &local->link);
else else
list_add_tail(&local->link, cursor); list_add_tail(&local->link, cursor);
age = "new"; age = "new";
...@@ -321,7 +321,7 @@ struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *local) ...@@ -321,7 +321,7 @@ struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *local)
int n; int n;
n = atomic_inc_return(&local->usage); n = atomic_inc_return(&local->usage);
trace_rxrpc_local(local, rxrpc_local_got, n, here); trace_rxrpc_local(local->debug_id, rxrpc_local_got, n, here);
return local; return local;
} }
...@@ -335,7 +335,8 @@ struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local) ...@@ -335,7 +335,8 @@ struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local)
if (local) { if (local) {
int n = atomic_fetch_add_unless(&local->usage, 1, 0); int n = atomic_fetch_add_unless(&local->usage, 1, 0);
if (n > 0) if (n > 0)
trace_rxrpc_local(local, rxrpc_local_got, n + 1, here); trace_rxrpc_local(local->debug_id, rxrpc_local_got,
n + 1, here);
else else
local = NULL; local = NULL;
} }
...@@ -343,16 +344,16 @@ struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local) ...@@ -343,16 +344,16 @@ struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local)
} }
/* /*
* Queue a local endpoint unless it has become unreferenced and pass the * Queue a local endpoint and pass the caller's reference to the work item.
* caller's reference to the work item.
*/ */
void rxrpc_queue_local(struct rxrpc_local *local) void rxrpc_queue_local(struct rxrpc_local *local)
{ {
const void *here = __builtin_return_address(0); const void *here = __builtin_return_address(0);
unsigned int debug_id = local->debug_id;
int n = atomic_read(&local->usage);
if (rxrpc_queue_work(&local->processor)) if (rxrpc_queue_work(&local->processor))
trace_rxrpc_local(local, rxrpc_local_queued, trace_rxrpc_local(debug_id, rxrpc_local_queued, n, here);
atomic_read(&local->usage), here);
else else
rxrpc_put_local(local); rxrpc_put_local(local);
} }
...@@ -367,7 +368,7 @@ void rxrpc_put_local(struct rxrpc_local *local) ...@@ -367,7 +368,7 @@ void rxrpc_put_local(struct rxrpc_local *local)
if (local) { if (local) {
n = atomic_dec_return(&local->usage); n = atomic_dec_return(&local->usage);
trace_rxrpc_local(local, rxrpc_local_put, n, here); trace_rxrpc_local(local->debug_id, rxrpc_local_put, n, here);
if (n == 0) if (n == 0)
call_rcu(&local->rcu, rxrpc_local_rcu); call_rcu(&local->rcu, rxrpc_local_rcu);
...@@ -456,7 +457,7 @@ static void rxrpc_local_processor(struct work_struct *work) ...@@ -456,7 +457,7 @@ static void rxrpc_local_processor(struct work_struct *work)
container_of(work, struct rxrpc_local, processor); container_of(work, struct rxrpc_local, processor);
bool again; bool again;
trace_rxrpc_local(local, rxrpc_local_processing, trace_rxrpc_local(local->debug_id, rxrpc_local_processing,
atomic_read(&local->usage), NULL); atomic_read(&local->usage), NULL);
do { do {
......
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