Skip to content

Commit 2757a4d

Browse files
committed
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: 341f741 ("afs: Refcount the afs_call struct") Fixes: 4521819 ("afs: Trace afs_server usage") Fixes: 977e5f8 ("afs: Split the usage count on struct afs_server") Signed-off-by: David Howells <[email protected]> cc: Marc Dionne <[email protected]> cc: [email protected] Link: https://lore.kernel.org/r/165911278430.3745403.16526310736054780645.stgit@warthog.procyon.org.uk/ # v1
1 parent c56f9ec commit 2757a4d

File tree

4 files changed

+26
-21
lines changed

4 files changed

+26
-21
lines changed

fs/afs/cmservice.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
212212
* to maintain cache coherency.
213213
*/
214214
if (call->server) {
215-
trace_afs_server(call->server,
215+
trace_afs_server(call->server->debug_id,
216216
refcount_read(&call->server->ref),
217217
atomic_read(&call->server->active),
218218
afs_server_trace_callback);

fs/afs/rxrpc.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
152152
call->iter = &call->def_iter;
153153

154154
o = atomic_inc_return(&net->nr_outstanding_calls);
155-
trace_afs_call(call, afs_call_trace_alloc, 1, o,
155+
trace_afs_call(call->debug_id, afs_call_trace_alloc, 1, o,
156156
__builtin_return_address(0));
157157
return call;
158158
}
@@ -163,12 +163,13 @@ static struct afs_call *afs_alloc_call(struct afs_net *net,
163163
void afs_put_call(struct afs_call *call)
164164
{
165165
struct afs_net *net = call->net;
166+
unsigned int debug_id = call->debug_id;
166167
bool zero;
167168
int r, o;
168169

169170
zero = __refcount_dec_and_test(&call->ref, &r);
170171
o = atomic_read(&net->nr_outstanding_calls);
171-
trace_afs_call(call, afs_call_trace_put, r - 1, o,
172+
trace_afs_call(debug_id, afs_call_trace_put, r - 1, o,
172173
__builtin_return_address(0));
173174

174175
if (zero) {
@@ -186,7 +187,7 @@ void afs_put_call(struct afs_call *call)
186187
afs_put_addrlist(call->alist);
187188
kfree(call->request);
188189

189-
trace_afs_call(call, afs_call_trace_free, 0, o,
190+
trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
190191
__builtin_return_address(0));
191192
kfree(call);
192193

@@ -203,7 +204,7 @@ static struct afs_call *afs_get_call(struct afs_call *call,
203204

204205
__refcount_inc(&call->ref, &r);
205206

206-
trace_afs_call(call, why, r + 1,
207+
trace_afs_call(call->debug_id, why, r + 1,
207208
atomic_read(&call->net->nr_outstanding_calls),
208209
__builtin_return_address(0));
209210
return call;
@@ -677,7 +678,7 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall,
677678
call->need_attention = true;
678679

679680
if (__refcount_inc_not_zero(&call->ref, &r)) {
680-
trace_afs_call(call, afs_call_trace_wake, r + 1,
681+
trace_afs_call(call->debug_id, afs_call_trace_wake, r + 1,
681682
atomic_read(&call->net->nr_outstanding_calls),
682683
__builtin_return_address(0));
683684

fs/afs/server.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
243243
server->rtt = UINT_MAX;
244244

245245
afs_inc_servers_outstanding(net);
246-
trace_afs_server(server, 1, 1, afs_server_trace_alloc);
246+
trace_afs_server(server->debug_id, 1, 1, afs_server_trace_alloc);
247247
_leave(" = %p", server);
248248
return server;
249249

@@ -352,10 +352,12 @@ void afs_servers_timer(struct timer_list *timer)
352352
struct afs_server *afs_get_server(struct afs_server *server,
353353
enum afs_server_trace reason)
354354
{
355+
unsigned int a;
355356
int r;
356357

357358
__refcount_inc(&server->ref, &r);
358-
trace_afs_server(server, r + 1, atomic_read(&server->active), reason);
359+
a = atomic_read(&server->active);
360+
trace_afs_server(server->debug_id, r + 1, a, reason);
359361
return server;
360362
}
361363

@@ -372,7 +374,7 @@ static struct afs_server *afs_maybe_use_server(struct afs_server *server,
372374
return NULL;
373375

374376
a = atomic_inc_return(&server->active);
375-
trace_afs_server(server, r + 1, a, reason);
377+
trace_afs_server(server->debug_id, r + 1, a, reason);
376378
return server;
377379
}
378380

@@ -387,7 +389,7 @@ struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_tra
387389
__refcount_inc(&server->ref, &r);
388390
a = atomic_inc_return(&server->active);
389391

390-
trace_afs_server(server, r + 1, a, reason);
392+
trace_afs_server(server->debug_id, r + 1, a, reason);
391393
return server;
392394
}
393395

@@ -397,14 +399,16 @@ struct afs_server *afs_use_server(struct afs_server *server, enum afs_server_tra
397399
void afs_put_server(struct afs_net *net, struct afs_server *server,
398400
enum afs_server_trace reason)
399401
{
402+
unsigned int a, debug_id = server->debug_id;
400403
bool zero;
401404
int r;
402405

403406
if (!server)
404407
return;
405408

409+
a = atomic_inc_return(&server->active);
406410
zero = __refcount_dec_and_test(&server->ref, &r);
407-
trace_afs_server(server, r - 1, atomic_read(&server->active), reason);
411+
trace_afs_server(debug_id, r - 1, a, reason);
408412
if (unlikely(zero))
409413
__afs_put_server(net, server);
410414
}
@@ -441,7 +445,7 @@ static void afs_server_rcu(struct rcu_head *rcu)
441445
{
442446
struct afs_server *server = container_of(rcu, struct afs_server, rcu);
443447

444-
trace_afs_server(server, refcount_read(&server->ref),
448+
trace_afs_server(server->debug_id, refcount_read(&server->ref),
445449
atomic_read(&server->active), afs_server_trace_free);
446450
afs_put_addrlist(rcu_access_pointer(server->addresses));
447451
kfree(server);
@@ -492,7 +496,7 @@ static void afs_gc_servers(struct afs_net *net, struct afs_server *gc_list)
492496

493497
active = atomic_read(&server->active);
494498
if (active == 0) {
495-
trace_afs_server(server, refcount_read(&server->ref),
499+
trace_afs_server(server->debug_id, refcount_read(&server->ref),
496500
active, afs_server_trace_gc);
497501
next = rcu_dereference_protected(
498502
server->uuid_next, lockdep_is_held(&net->fs_lock.lock));
@@ -558,7 +562,7 @@ void afs_manage_servers(struct work_struct *work)
558562
_debug("manage %pU %u", &server->uuid, active);
559563

560564
if (purging) {
561-
trace_afs_server(server, refcount_read(&server->ref),
565+
trace_afs_server(server->debug_id, refcount_read(&server->ref),
562566
active, afs_server_trace_purging);
563567
if (active != 0)
564568
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,
638642

639643
_enter("");
640644

641-
trace_afs_server(server, refcount_read(&server->ref),
645+
trace_afs_server(server->debug_id, refcount_read(&server->ref),
642646
atomic_read(&server->active),
643647
afs_server_trace_update);
644648

include/trace/events/afs.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -727,10 +727,10 @@ TRACE_EVENT(afs_cb_call,
727727
);
728728

729729
TRACE_EVENT(afs_call,
730-
TP_PROTO(struct afs_call *call, enum afs_call_trace op,
730+
TP_PROTO(unsigned int call_debug_id, enum afs_call_trace op,
731731
int ref, int outstanding, const void *where),
732732

733-
TP_ARGS(call, op, ref, outstanding, where),
733+
TP_ARGS(call_debug_id, op, ref, outstanding, where),
734734

735735
TP_STRUCT__entry(
736736
__field(unsigned int, call )
@@ -741,7 +741,7 @@ TRACE_EVENT(afs_call,
741741
),
742742

743743
TP_fast_assign(
744-
__entry->call = call->debug_id;
744+
__entry->call = call_debug_id;
745745
__entry->op = op;
746746
__entry->ref = ref;
747747
__entry->outstanding = outstanding;
@@ -1433,10 +1433,10 @@ TRACE_EVENT(afs_cb_miss,
14331433
);
14341434

14351435
TRACE_EVENT(afs_server,
1436-
TP_PROTO(struct afs_server *server, int ref, int active,
1436+
TP_PROTO(unsigned int server_debug_id, int ref, int active,
14371437
enum afs_server_trace reason),
14381438

1439-
TP_ARGS(server, ref, active, reason),
1439+
TP_ARGS(server_debug_id, ref, active, reason),
14401440

14411441
TP_STRUCT__entry(
14421442
__field(unsigned int, server )
@@ -1446,7 +1446,7 @@ TRACE_EVENT(afs_server,
14461446
),
14471447

14481448
TP_fast_assign(
1449-
__entry->server = server->debug_id;
1449+
__entry->server = server_debug_id;
14501450
__entry->ref = ref;
14511451
__entry->active = active;
14521452
__entry->reason = reason;

0 commit comments

Comments
 (0)