diff options
author | David Howells <dhowells@redhat.com> | 2022-07-06 12:26:14 +0200 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2022-08-02 19:21:29 +0200 |
commit | 2757a4dc184997c66ef1de32636f73b9f21aac14 (patch) | |
tree | e5d3b2a1c35bc3d8126b6b6d4b0c32a19e3fdc6d /fs/afs/server.c | |
parent | afs: Use refcount_t rather than atomic_t (diff) | |
download | linux-2757a4dc184997c66ef1de32636f73b9f21aac14.tar.xz linux-2757a4dc184997c66ef1de32636f73b9f21aac14.zip |
afs: Fix access after dec in put functions
Reference-putting functions should not access the object being put after
decrementing the refcount unless they reduce the refcount to zero.
Fix a couple of instances of this in afs by copying the information to be
logged by tracepoint to local variables before doing the decrement.
[Fixed a bit in afs_put_server() that I'd missed but Marc caught]
Fixes: 341f741f04be ("afs: Refcount the afs_call struct")
Fixes: 452181936931 ("afs: Trace afs_server usage")
Fixes: 977e5f8ed0ab ("afs: Split the usage count on struct afs_server")
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
Link: https://lore.kernel.org/r/165911278430.3745403.16526310736054780645.stgit@warthog.procyon.org.uk/ # v1
Diffstat (limited to 'fs/afs/server.c')
-rw-r--r-- | fs/afs/server.c | 22 |
1 files changed, 13 insertions, 9 deletions
diff --git a/fs/afs/server.c b/fs/afs/server.c index ffed828622b6..4981baf97835 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c @@ -243,7 +243,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell, server->rtt = UINT_MAX; afs_inc_servers_outstanding(net); - trace_afs_server(server, 1, 1, afs_server_trace_alloc); + trace_afs_server(server->debug_id, 1, 1, afs_server_trace_alloc); _leave(" = %p", server); return server; @@ -352,10 +352,12 @@ void afs_servers_timer(struct timer_list *timer) struct afs_server *afs_get_server(struct afs_server *server, enum afs_server_trace reason) { + unsigned int a; int r; __refcount_inc(&server->ref, &r); - trace_afs_server(server, r + 1, atomic_read(&server->active), reason); + a = atomic_read(&server->active); + trace_afs_server(server->debug_id, r + 1, a, reason); return server; } @@ -372,7 +374,7 @@ static struct afs_server *afs_maybe_use_server(struct afs_server *server, return NULL; a = atomic_inc_return(&server->active); - trace_afs_server(server, r + 1, a, reason); + trace_afs_server(server->debug_id, r + 1, a, reason); return server; } @@ -387,7 +389,7 @@ struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_tra __refcount_inc(&server->ref, &r); a = atomic_inc_return(&server->active); - trace_afs_server(server, r + 1, a, reason); + trace_afs_server(server->debug_id, r + 1, a, reason); return server; } @@ -397,14 +399,16 @@ struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_tra void afs_put_server(struct afs_net *net, struct afs_server *server, enum afs_server_trace reason) { + unsigned int a, debug_id = server->debug_id; bool zero; int r; if (!server) return; + a = atomic_inc_return(&server->active); zero = __refcount_dec_and_test(&server->ref, &r); - trace_afs_server(server, r - 1, atomic_read(&server->active), reason); + trace_afs_server(debug_id, r - 1, a, reason); if (unlikely(zero)) __afs_put_server(net, server); } @@ -441,7 +445,7 @@ static void afs_server_rcu(struct rcu_head *rcu) { struct afs_server *server = container_of(rcu, struct afs_server, rcu); - trace_afs_server(server, refcount_read(&server->ref), + trace_afs_server(server->debug_id, refcount_read(&server->ref), atomic_read(&server->active), afs_server_trace_free); afs_put_addrlist(rcu_access_pointer(server->addresses)); kfree(server); @@ -492,7 +496,7 @@ static void afs_gc_servers(struct afs_net *net, struct afs_server *gc_list) active = atomic_read(&server->active); if (active == 0) { - trace_afs_server(server, refcount_read(&server->ref), + trace_afs_server(server->debug_id, refcount_read(&server->ref), active, afs_server_trace_gc); next = rcu_dereference_protected( server->uuid_next, lockdep_is_held(&net->fs_lock.lock)); @@ -558,7 +562,7 @@ void afs_manage_servers(struct work_struct *work) _debug("manage %pU %u", &server->uuid, active); if (purging) { - trace_afs_server(server, refcount_read(&server->ref), + trace_afs_server(server->debug_id, refcount_read(&server->ref), active, afs_server_trace_purging); if (active != 0) pr_notice("Can't purge s=%08x\n", server->debug_id); @@ -638,7 +642,7 @@ static noinline bool afs_update_server_record(struct afs_operation *op, _enter(""); - trace_afs_server(server, refcount_read(&server->ref), + trace_afs_server(server->debug_id, refcount_read(&server->ref), atomic_read(&server->active), afs_server_trace_update); |