Commit f7f1dd31 authored by Marc Dionne's avatar Marc Dionne Committed by David S. Miller

afs: Check for rxrpc call completion in wait loop

Check the state of the rxrpc call backing an afs call in each iteration of
the call wait loop in case the rxrpc call has already been terminated at
the rxrpc layer.

Interrupt the wait loop and mark the afs call as complete if the rxrpc
layer call is complete.

There were cases where rxrpc errors were not passed up to afs, which could
result in this loop waiting forever for an afs call to transition to
AFS_CALL_COMPLETE while the rx call was already complete.
Signed-off-by: default avatarMarc Dionne <marc.dionne@auristor.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8e8715aa
...@@ -610,6 +610,7 @@ static long afs_wait_for_call_to_complete(struct afs_call *call, ...@@ -610,6 +610,7 @@ static long afs_wait_for_call_to_complete(struct afs_call *call,
bool stalled = false; bool stalled = false;
u64 rtt; u64 rtt;
u32 life, last_life; u32 life, last_life;
bool rxrpc_complete = false;
DECLARE_WAITQUEUE(myself, current); DECLARE_WAITQUEUE(myself, current);
...@@ -639,7 +640,12 @@ static long afs_wait_for_call_to_complete(struct afs_call *call, ...@@ -639,7 +640,12 @@ static long afs_wait_for_call_to_complete(struct afs_call *call,
if (afs_check_call_state(call, AFS_CALL_COMPLETE)) if (afs_check_call_state(call, AFS_CALL_COMPLETE))
break; break;
rxrpc_kernel_check_life(call->net->socket, call->rxcall, &life); if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall, &life)) {
/* rxrpc terminated the call. */
rxrpc_complete = true;
break;
}
if (timeout == 0 && if (timeout == 0 &&
life == last_life && signal_pending(current)) { life == last_life && signal_pending(current)) {
if (stalled) if (stalled)
...@@ -663,13 +669,17 @@ static long afs_wait_for_call_to_complete(struct afs_call *call, ...@@ -663,13 +669,17 @@ static long afs_wait_for_call_to_complete(struct afs_call *call,
remove_wait_queue(&call->waitq, &myself); remove_wait_queue(&call->waitq, &myself);
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
/* Kill off the call if it's still live. */
if (!afs_check_call_state(call, AFS_CALL_COMPLETE)) { if (!afs_check_call_state(call, AFS_CALL_COMPLETE)) {
if (rxrpc_complete) {
afs_set_call_complete(call, call->error, call->abort_code);
} else {
/* Kill off the call if it's still live. */
_debug("call interrupted"); _debug("call interrupted");
if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall, if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
RX_USER_ABORT, -EINTR, "KWI")) RX_USER_ABORT, -EINTR, "KWI"))
afs_set_call_complete(call, -EINTR, 0); afs_set_call_complete(call, -EINTR, 0);
} }
}
spin_lock_bh(&call->state_lock); spin_lock_bh(&call->state_lock);
ac->abort_code = call->abort_code; ac->abort_code = call->abort_code;
......
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