|
@@ -269,11 +269,6 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
|
|
|
trace_rxrpc_call(call, rxrpc_call_connected, atomic_read(&call->usage),
|
|
|
here, NULL);
|
|
|
|
|
|
- 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);
|
|
|
-
|
|
|
rxrpc_start_call_timer(call);
|
|
|
|
|
|
_net("CALL new %d on CONN %d", call->debug_id, call->conn->debug_id);
|
|
@@ -303,6 +298,48 @@ error:
|
|
|
return ERR_PTR(ret);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Retry a call to a new address. It is expected that the Tx queue of the call
|
|
|
+ * will contain data previously packaged for an old call.
|
|
|
+ */
|
|
|
+int rxrpc_retry_client_call(struct rxrpc_sock *rx,
|
|
|
+ struct rxrpc_call *call,
|
|
|
+ struct rxrpc_conn_parameters *cp,
|
|
|
+ struct sockaddr_rxrpc *srx,
|
|
|
+ gfp_t gfp)
|
|
|
+{
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /* Set up or get a connection record and set the protocol parameters,
|
|
|
+ * including channel number and call ID.
|
|
|
+ */
|
|
|
+ ret = rxrpc_connect_call(call, cp, srx, gfp);
|
|
|
+ if (ret < 0)
|
|
|
+ goto error;
|
|
|
+
|
|
|
+ trace_rxrpc_call(call, rxrpc_call_connected, atomic_read(&call->usage),
|
|
|
+ here, NULL);
|
|
|
+
|
|
|
+ rxrpc_start_call_timer(call);
|
|
|
+
|
|
|
+ _net("CALL new %d on CONN %d", call->debug_id, call->conn->debug_id);
|
|
|
+
|
|
|
+ if (!test_and_set_bit(RXRPC_CALL_EV_RESEND, &call->events))
|
|
|
+ rxrpc_queue_call(call);
|
|
|
+
|
|
|
+ _leave(" = 0");
|
|
|
+ return 0;
|
|
|
+
|
|
|
+error:
|
|
|
+ rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR,
|
|
|
+ RX_CALL_DEAD, ret);
|
|
|
+ trace_rxrpc_call(call, rxrpc_call_error, atomic_read(&call->usage),
|
|
|
+ here, ERR_PTR(ret));
|
|
|
+ _leave(" = %d", ret);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Set up an incoming call. call->conn points to the connection.
|
|
|
* This is called in BH context and isn't allowed to fail.
|
|
@@ -470,6 +507,61 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
|
|
|
_leave("");
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Prepare a kernel service call for retry.
|
|
|
+ */
|
|
|
+int rxrpc_prepare_call_for_retry(struct rxrpc_sock *rx, struct rxrpc_call *call)
|
|
|
+{
|
|
|
+ const void *here = __builtin_return_address(0);
|
|
|
+ int i;
|
|
|
+ u8 last = 0;
|
|
|
+
|
|
|
+ _enter("{%d,%d}", call->debug_id, atomic_read(&call->usage));
|
|
|
+
|
|
|
+ trace_rxrpc_call(call, rxrpc_call_release, atomic_read(&call->usage),
|
|
|
+ here, (const void *)call->flags);
|
|
|
+
|
|
|
+ ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);
|
|
|
+ ASSERTCMP(call->completion, !=, RXRPC_CALL_REMOTELY_ABORTED);
|
|
|
+ ASSERTCMP(call->completion, !=, RXRPC_CALL_LOCALLY_ABORTED);
|
|
|
+ ASSERT(list_empty(&call->recvmsg_link));
|
|
|
+
|
|
|
+ del_timer_sync(&call->timer);
|
|
|
+
|
|
|
+ _debug("RELEASE CALL %p (%d CONN %p)", call, call->debug_id, call->conn);
|
|
|
+
|
|
|
+ if (call->conn)
|
|
|
+ rxrpc_disconnect_call(call);
|
|
|
+
|
|
|
+ if (rxrpc_is_service_call(call) ||
|
|
|
+ !call->tx_phase ||
|
|
|
+ call->tx_hard_ack != 0 ||
|
|
|
+ call->rx_hard_ack != 0 ||
|
|
|
+ call->rx_top != 0)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ call->state = RXRPC_CALL_UNINITIALISED;
|
|
|
+ call->completion = RXRPC_CALL_SUCCEEDED;
|
|
|
+ call->call_id = 0;
|
|
|
+ call->cid = 0;
|
|
|
+ call->cong_cwnd = 0;
|
|
|
+ call->cong_extra = 0;
|
|
|
+ call->cong_ssthresh = 0;
|
|
|
+ call->cong_mode = 0;
|
|
|
+ call->cong_dup_acks = 0;
|
|
|
+ call->cong_cumul_acks = 0;
|
|
|
+ call->acks_lowest_nak = 0;
|
|
|
+
|
|
|
+ for (i = 0; i < RXRPC_RXTX_BUFF_SIZE; i++) {
|
|
|
+ last |= call->rxtx_annotations[i];
|
|
|
+ call->rxtx_annotations[i] &= RXRPC_TX_ANNO_LAST;
|
|
|
+ call->rxtx_annotations[i] |= RXRPC_TX_ANNO_RETRANS;
|
|
|
+ }
|
|
|
+
|
|
|
+ _leave(" = 0");
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* release all the calls associated with a socket
|
|
|
*/
|