summaryrefslogtreecommitdiffstats
path: root/net/rxrpc/conn_client.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2017-08-29 10:19:01 +0100
committerDavid Howells <dhowells@redhat.com>2017-08-29 10:55:20 +0100
commitc038a58ccfd6704d4d7d60ed3d6a0fca13cf13a4 (patch)
tree3848dab9427af484ad93bfef5030fce14c58b117 /net/rxrpc/conn_client.c
parente833251ad813168253fef9915aaf6a8c883337b0 (diff)
downloadlinux-c038a58ccfd6704d4d7d60ed3d6a0fca13cf13a4.tar.bz2
rxrpc: Allow failed client calls to be retried
Allow a client call that failed on network error to be retried, provided that the Tx queue still holds DATA packet 1. This allows an operation to be submitted to another server or another address for the same server without having to repackage and re-encrypt the data so far processed. Two new functions are provided: (1) rxrpc_kernel_check_call() - This is used to find out the completion state of a call to guess whether it can be retried and whether it should be retried. (2) rxrpc_kernel_retry_call() - Disconnect the call from its current connection, reset the state and submit it as a new client call to a new address. The new address need not match the previous address. A call may be retried even if all the data hasn't been loaded into it yet; a partially constructed will be retained at the same point it was at when an error condition was detected. msg_data_left() can be used to find out how much data was packaged before the error occurred. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'net/rxrpc/conn_client.c')
-rw-r--r--net/rxrpc/conn_client.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index eb2157680399..5f9624bd311c 100644
--- a/net/rxrpc/conn_client.c
+++ b/net/rxrpc/conn_client.c
@@ -555,7 +555,10 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn,
trace_rxrpc_client(conn, channel, rxrpc_client_chan_activate);
write_lock_bh(&call->state_lock);
- call->state = RXRPC_CALL_CLIENT_SEND_REQUEST;
+ if (!test_bit(RXRPC_CALL_TX_LASTQ, &call->flags))
+ call->state = RXRPC_CALL_CLIENT_SEND_REQUEST;
+ else
+ call->state = RXRPC_CALL_CLIENT_AWAIT_REPLY;
write_unlock_bh(&call->state_lock);
rxrpc_see_call(call);
@@ -688,15 +691,23 @@ int rxrpc_connect_call(struct rxrpc_call *call,
ret = rxrpc_get_client_conn(call, cp, srx, gfp);
if (ret < 0)
- return ret;
+ goto out;
rxrpc_animate_client_conn(rxnet, call->conn);
rxrpc_activate_channels(call->conn);
ret = rxrpc_wait_for_channel(call, gfp);
- if (ret < 0)
+ if (ret < 0) {
rxrpc_disconnect_client_call(call);
+ goto out;
+ }
+
+ spin_lock_bh(&call->conn->params.peer->lock);
+ hlist_add_head(&call->error_link,
+ &call->conn->params.peer->error_targets);
+ spin_unlock_bh(&call->conn->params.peer->lock);
+out:
_leave(" = %d", ret);
return ret;
}