summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Dionne <marc.dionne@auristor.com>2019-04-12 16:34:02 +0100
committerDavid S. Miller <davem@davemloft.net>2019-04-12 16:57:23 -0700
commitf7f1dd3162efc7ffdbcdb9da1ad1599f8ab51296 (patch)
treef17c43fc45eef23ab994a6063f2a1ae617e43a86
parent8e8715aaa905f6593f610f950d513e81fab5006a (diff)
downloadlwn-f7f1dd3162efc7ffdbcdb9da1ad1599f8ab51296.tar.gz
lwn-f7f1dd3162efc7ffdbcdb9da1ad1599f8ab51296.zip
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: Marc Dionne <marc.dionne@auristor.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--fs/afs/rxrpc.c22
1 files changed, 16 insertions, 6 deletions
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 5cb11aff9298..c14001b42d20 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -610,6 +610,7 @@ static long afs_wait_for_call_to_complete(struct afs_call *call,
bool stalled = false;
u64 rtt;
u32 life, last_life;
+ bool rxrpc_complete = false;
DECLARE_WAITQUEUE(myself, current);
@@ -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))
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 &&
life == last_life && signal_pending(current)) {
if (stalled)
@@ -663,12 +669,16 @@ static long afs_wait_for_call_to_complete(struct afs_call *call,
remove_wait_queue(&call->waitq, &myself);
__set_current_state(TASK_RUNNING);
- /* Kill off the call if it's still live. */
if (!afs_check_call_state(call, AFS_CALL_COMPLETE)) {
- _debug("call interrupted");
- if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
- RX_USER_ABORT, -EINTR, "KWI"))
- afs_set_call_complete(call, -EINTR, 0);
+ 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");
+ if (rxrpc_kernel_abort_call(call->net->socket, call->rxcall,
+ RX_USER_ABORT, -EINTR, "KWI"))
+ afs_set_call_complete(call, -EINTR, 0);
+ }
}
spin_lock_bh(&call->state_lock);