Skip to content

Commit 9750be9

Browse files
dhowellsbrauner
authored andcommitted
afs: Fix cleanup of immediately failed async calls
If we manage to begin an async call, but fail to transmit any data on it due to a signal, we then abort it which causes a race between the notification of call completion from rxrpc and our attempt to cancel the notification. The notification will be necessary, however, for async FetchData to terminate the netfs subrequest. However, since we get a notification from rxrpc upon completion of a call (aborted or otherwise), we can just leave it to that. This leads to calls not getting cleaned up, but appearing in /proc/net/rxrpc/calls as being aborted with code 6. Fix this by making the "error_do_abort:" case of afs_make_call() abort the call and then abandon it to the notification handler. Fixes: 34fa476 ("afs: Fix race in async call refcounting") Reported-by: Marc Dionne <[email protected]> Signed-off-by: David Howells <[email protected]> Link: https://lore.kernel.org/r/[email protected] cc: [email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent f28fc20 commit 9750be9

File tree

3 files changed

+20
-3
lines changed

3 files changed

+20
-3
lines changed

fs/afs/internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,15 @@ extern void afs_send_simple_reply(struct afs_call *, const void *, size_t);
13361336
extern int afs_extract_data(struct afs_call *, bool);
13371337
extern int afs_protocol_error(struct afs_call *, enum afs_eproto_cause);
13381338

1339+
static inline void afs_see_call(struct afs_call *call, enum afs_call_trace why)
1340+
{
1341+
int r = refcount_read(&call->ref);
1342+
1343+
trace_afs_call(call->debug_id, why, r,
1344+
atomic_read(&call->net->nr_outstanding_calls),
1345+
__builtin_return_address(0));
1346+
}
1347+
13391348
static inline void afs_make_op_call(struct afs_operation *op, struct afs_call *call,
13401349
gfp_t gfp)
13411350
{

fs/afs/rxrpc.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,11 +430,16 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
430430
return;
431431

432432
error_do_abort:
433-
if (ret != -ECONNABORTED) {
433+
if (ret != -ECONNABORTED)
434434
rxrpc_kernel_abort_call(call->net->socket, rxcall,
435435
RX_USER_ABORT, ret,
436436
afs_abort_send_data_error);
437-
} else {
437+
if (call->async) {
438+
afs_see_call(call, afs_call_trace_async_abort);
439+
return;
440+
}
441+
442+
if (ret == -ECONNABORTED) {
438443
len = 0;
439444
iov_iter_kvec(&msg.msg_iter, ITER_DEST, NULL, 0, 0);
440445
rxrpc_kernel_recv_data(call->net->socket, rxcall,
@@ -445,6 +450,8 @@ void afs_make_call(struct afs_call *call, gfp_t gfp)
445450
call->error = ret;
446451
trace_afs_call_done(call);
447452
error_kill_call:
453+
if (call->async)
454+
afs_see_call(call, afs_call_trace_async_kill);
448455
if (call->type->done)
449456
call->type->done(call);
450457

@@ -602,7 +609,6 @@ static void afs_deliver_to_call(struct afs_call *call)
602609
abort_code = 0;
603610
call_complete:
604611
afs_set_call_complete(call, ret, remote_abort);
605-
state = AFS_CALL_COMPLETE;
606612
goto done;
607613
}
608614

include/trace/events/afs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ enum yfs_cm_operation {
118118
*/
119119
#define afs_call_traces \
120120
EM(afs_call_trace_alloc, "ALLOC") \
121+
EM(afs_call_trace_async_abort, "ASYAB") \
122+
EM(afs_call_trace_async_kill, "ASYKL") \
121123
EM(afs_call_trace_free, "FREE ") \
122124
EM(afs_call_trace_get, "GET ") \
123125
EM(afs_call_trace_put, "PUT ") \

0 commit comments

Comments
 (0)