rxrpc: Fix life check
The life-checking function, which is used by kAFS to make sure that a call is still live in the event of a pending signal, only samples the received packet serial number counter; it doesn't actually provoke a change in the counter, rather relying on the server to happen to give us a packet in the time window. Fix this by adding a function to force a ping to be transmitted. kAFS then keeps track of whether there's been a stall, and if so, uses the new function to ping the server, resetting the timeout to allow the reply to come back. If there's a stall, a ping and the call is *still* stalled in the same place after another period, then the call will be aborted. Fixes:bc5e3a546d
("rxrpc: Use MSG_WAITALL to tell sendmsg() to temporarily ignore signals") Fixes:f4d15fb6f9
("rxrpc: Provide functions for allowing cleaner handling of signals") Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
ebcd210e93
Коммит
7150ceaacb
|
@ -1056,18 +1056,23 @@ The kernel interface functions are as follows:
|
||||||
|
|
||||||
u32 rxrpc_kernel_check_life(struct socket *sock,
|
u32 rxrpc_kernel_check_life(struct socket *sock,
|
||||||
struct rxrpc_call *call);
|
struct rxrpc_call *call);
|
||||||
|
void rxrpc_kernel_probe_life(struct socket *sock,
|
||||||
|
struct rxrpc_call *call);
|
||||||
|
|
||||||
This returns a number that is updated when ACKs are received from the peer
|
The first function returns a number that is updated when ACKs are received
|
||||||
(notably including PING RESPONSE ACKs which we can elicit by sending PING
|
from the peer (notably including PING RESPONSE ACKs which we can elicit by
|
||||||
ACKs to see if the call still exists on the server). The caller should
|
sending PING ACKs to see if the call still exists on the server). The
|
||||||
compare the numbers of two calls to see if the call is still alive after
|
caller should compare the numbers of two calls to see if the call is still
|
||||||
waiting for a suitable interval.
|
alive after waiting for a suitable interval.
|
||||||
|
|
||||||
This allows the caller to work out if the server is still contactable and
|
This allows the caller to work out if the server is still contactable and
|
||||||
if the call is still alive on the server whilst waiting for the server to
|
if the call is still alive on the server whilst waiting for the server to
|
||||||
process a client operation.
|
process a client operation.
|
||||||
|
|
||||||
This function may transmit a PING ACK.
|
The second function causes a ping ACK to be transmitted to try to provoke
|
||||||
|
the peer into responding, which would then cause the value returned by the
|
||||||
|
first function to change. Note that this must be called in TASK_RUNNING
|
||||||
|
state.
|
||||||
|
|
||||||
(*) Get reply timestamp.
|
(*) Get reply timestamp.
|
||||||
|
|
||||||
|
|
|
@ -576,6 +576,7 @@ static long afs_wait_for_call_to_complete(struct afs_call *call,
|
||||||
{
|
{
|
||||||
signed long rtt2, timeout;
|
signed long rtt2, timeout;
|
||||||
long ret;
|
long ret;
|
||||||
|
bool stalled = false;
|
||||||
u64 rtt;
|
u64 rtt;
|
||||||
u32 life, last_life;
|
u32 life, last_life;
|
||||||
|
|
||||||
|
@ -609,12 +610,20 @@ static long afs_wait_for_call_to_complete(struct afs_call *call,
|
||||||
|
|
||||||
life = rxrpc_kernel_check_life(call->net->socket, call->rxcall);
|
life = rxrpc_kernel_check_life(call->net->socket, call->rxcall);
|
||||||
if (timeout == 0 &&
|
if (timeout == 0 &&
|
||||||
life == last_life && signal_pending(current))
|
life == last_life && signal_pending(current)) {
|
||||||
|
if (stalled)
|
||||||
break;
|
break;
|
||||||
|
__set_current_state(TASK_RUNNING);
|
||||||
|
rxrpc_kernel_probe_life(call->net->socket, call->rxcall);
|
||||||
|
timeout = rtt2;
|
||||||
|
stalled = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (life != last_life) {
|
if (life != last_life) {
|
||||||
timeout = rtt2;
|
timeout = rtt2;
|
||||||
last_life = life;
|
last_life = life;
|
||||||
|
stalled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout = schedule_timeout(timeout);
|
timeout = schedule_timeout(timeout);
|
||||||
|
|
|
@ -77,7 +77,8 @@ int rxrpc_kernel_retry_call(struct socket *, struct rxrpc_call *,
|
||||||
struct sockaddr_rxrpc *, struct key *);
|
struct sockaddr_rxrpc *, struct key *);
|
||||||
int rxrpc_kernel_check_call(struct socket *, struct rxrpc_call *,
|
int rxrpc_kernel_check_call(struct socket *, struct rxrpc_call *,
|
||||||
enum rxrpc_call_completion *, u32 *);
|
enum rxrpc_call_completion *, u32 *);
|
||||||
u32 rxrpc_kernel_check_life(struct socket *, struct rxrpc_call *);
|
u32 rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *);
|
||||||
|
void rxrpc_kernel_probe_life(struct socket *, struct rxrpc_call *);
|
||||||
u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *);
|
u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *);
|
||||||
bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *,
|
bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *,
|
||||||
ktime_t *);
|
ktime_t *);
|
||||||
|
|
|
@ -181,6 +181,7 @@ enum rxrpc_timer_trace {
|
||||||
enum rxrpc_propose_ack_trace {
|
enum rxrpc_propose_ack_trace {
|
||||||
rxrpc_propose_ack_client_tx_end,
|
rxrpc_propose_ack_client_tx_end,
|
||||||
rxrpc_propose_ack_input_data,
|
rxrpc_propose_ack_input_data,
|
||||||
|
rxrpc_propose_ack_ping_for_check_life,
|
||||||
rxrpc_propose_ack_ping_for_keepalive,
|
rxrpc_propose_ack_ping_for_keepalive,
|
||||||
rxrpc_propose_ack_ping_for_lost_ack,
|
rxrpc_propose_ack_ping_for_lost_ack,
|
||||||
rxrpc_propose_ack_ping_for_lost_reply,
|
rxrpc_propose_ack_ping_for_lost_reply,
|
||||||
|
@ -380,6 +381,7 @@ enum rxrpc_tx_point {
|
||||||
#define rxrpc_propose_ack_traces \
|
#define rxrpc_propose_ack_traces \
|
||||||
EM(rxrpc_propose_ack_client_tx_end, "ClTxEnd") \
|
EM(rxrpc_propose_ack_client_tx_end, "ClTxEnd") \
|
||||||
EM(rxrpc_propose_ack_input_data, "DataIn ") \
|
EM(rxrpc_propose_ack_input_data, "DataIn ") \
|
||||||
|
EM(rxrpc_propose_ack_ping_for_check_life, "ChkLife") \
|
||||||
EM(rxrpc_propose_ack_ping_for_keepalive, "KeepAlv") \
|
EM(rxrpc_propose_ack_ping_for_keepalive, "KeepAlv") \
|
||||||
EM(rxrpc_propose_ack_ping_for_lost_ack, "LostAck") \
|
EM(rxrpc_propose_ack_ping_for_lost_ack, "LostAck") \
|
||||||
EM(rxrpc_propose_ack_ping_for_lost_reply, "LostRpl") \
|
EM(rxrpc_propose_ack_ping_for_lost_reply, "LostRpl") \
|
||||||
|
|
|
@ -375,16 +375,35 @@ EXPORT_SYMBOL(rxrpc_kernel_end_call);
|
||||||
* getting ACKs from the server. Returns a number representing the life state
|
* getting ACKs from the server. Returns a number representing the life state
|
||||||
* which can be compared to that returned by a previous call.
|
* which can be compared to that returned by a previous call.
|
||||||
*
|
*
|
||||||
* If this is a client call, ping ACKs will be sent to the server to find out
|
* If the life state stalls, rxrpc_kernel_probe_life() should be called and
|
||||||
* whether it's still responsive and whether the call is still alive on the
|
* then 2RTT waited.
|
||||||
* server.
|
|
||||||
*/
|
*/
|
||||||
u32 rxrpc_kernel_check_life(struct socket *sock, struct rxrpc_call *call)
|
u32 rxrpc_kernel_check_life(const struct socket *sock,
|
||||||
|
const struct rxrpc_call *call)
|
||||||
{
|
{
|
||||||
return call->acks_latest;
|
return call->acks_latest;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rxrpc_kernel_check_life);
|
EXPORT_SYMBOL(rxrpc_kernel_check_life);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rxrpc_kernel_probe_life - Poke the peer to see if it's still alive
|
||||||
|
* @sock: The socket the call is on
|
||||||
|
* @call: The call to check
|
||||||
|
*
|
||||||
|
* In conjunction with rxrpc_kernel_check_life(), allow a kernel service to
|
||||||
|
* find out whether a call is still alive by pinging it. This should cause the
|
||||||
|
* life state to be bumped in about 2*RTT.
|
||||||
|
*
|
||||||
|
* The must be called in TASK_RUNNING state on pain of might_sleep() objecting.
|
||||||
|
*/
|
||||||
|
void rxrpc_kernel_probe_life(struct socket *sock, struct rxrpc_call *call)
|
||||||
|
{
|
||||||
|
rxrpc_propose_ACK(call, RXRPC_ACK_PING, 0, 0, true, false,
|
||||||
|
rxrpc_propose_ack_ping_for_check_life);
|
||||||
|
rxrpc_send_ack_packet(call, true, NULL);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rxrpc_kernel_probe_life);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rxrpc_kernel_get_epoch - Retrieve the epoch value from a call.
|
* rxrpc_kernel_get_epoch - Retrieve the epoch value from a call.
|
||||||
* @sock: The socket the call is on
|
* @sock: The socket the call is on
|
||||||
|
|
Загрузка…
Ссылка в новой задаче