diff options
author | David Howells <dhowells@redhat.com> | 2019-01-10 15:40:50 +0000 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-01-17 15:17:28 +0000 |
commit | 34fa47612bfe5d7de7fcaf658a6952b6aeec3b13 (patch) | |
tree | da3d177e153d5cf07192e355bb885d4f9a799279 /include/trace | |
parent | 7a75b0079a1d54e342c502c3c8107ba97e05d3d3 (diff) | |
download | linux-34fa47612bfe5d7de7fcaf658a6952b6aeec3b13.tar.gz linux-34fa47612bfe5d7de7fcaf658a6952b6aeec3b13.tar.bz2 linux-34fa47612bfe5d7de7fcaf658a6952b6aeec3b13.zip |
afs: Fix race in async call refcounting
There's a race between afs_make_call() and afs_wake_up_async_call() in the
case that an error is returned from rxrpc_kernel_send_data() after it has
queued the final packet.
afs_make_call() will try and clean up the mess, but the call state may have
been moved on thereby causing afs_process_async_call() to also try and to
delete the call.
Fix this by:
(1) Getting an extra ref for an asynchronous call for the call itself to
hold. This makes sure the call doesn't evaporate on us accidentally
and will allow the call to be retained by the caller in a future
patch. The ref is released on leaving afs_make_call() or
afs_wait_for_call_to_complete().
(2) In the event of an error from rxrpc_kernel_send_data():
(a) Don't set the call state to AFS_CALL_COMPLETE until *after* the
call has been aborted and ended. This prevents
afs_deliver_to_call() from doing anything with any notifications
it gets.
(b) Explicitly end the call immediately to prevent further callbacks.
(c) Cancel any queued async_work and wait for the work if it's
executing. This allows us to be sure the race won't recur when we
change the state. We put the work queue's ref on the call if we
managed to cancel it.
(d) Put the call's ref that we got in (1). This belongs to us as long
as the call is in state AFS_CALL_CL_REQUESTING.
Fixes: 341f741f04be ("afs: Refcount the afs_call struct")
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'include/trace')
-rw-r--r-- | include/trace/events/afs.h | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 33d291888ba9..e3f005eae1f7 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h @@ -25,6 +25,7 @@ enum afs_call_trace { afs_call_trace_alloc, afs_call_trace_free, + afs_call_trace_get, afs_call_trace_put, afs_call_trace_wake, afs_call_trace_work, @@ -159,6 +160,7 @@ enum afs_file_error { #define afs_call_traces \ EM(afs_call_trace_alloc, "ALLOC") \ EM(afs_call_trace_free, "FREE ") \ + EM(afs_call_trace_get, "GET ") \ EM(afs_call_trace_put, "PUT ") \ EM(afs_call_trace_wake, "WAKE ") \ E_(afs_call_trace_work, "WORK ") |