afs: Fix client call Rx-phase signal handling

Fix the handling of signals in client rxrpc calls made by the afs
filesystem.  Ignore signals completely, leaving call abandonment or
connection loss to be detected by timeouts inside AF_RXRPC.

Allowing a filesystem call to be interrupted after the entire request has
been transmitted and an abort sent means that the server may or may not
have done the action - and we don't know.  It may even be worse than that
for older servers.

Fixes: bc5e3a546d ("rxrpc: Use MSG_WAITALL to tell sendmsg() to temporarily ignore signals")
Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
David Howells 2020-03-12 21:40:06 +00:00
Родитель dde9f09558
Коммит 7d7587db0d
5 изменённых файлов: 6 добавлений и 67 удалений

Просмотреть файл

@ -604,11 +604,7 @@ call_complete:
long afs_wait_for_call_to_complete(struct afs_call *call,
struct afs_addr_cursor *ac)
{
signed long rtt2, timeout;
long ret;
bool stalled = false;
u64 rtt;
u32 life, last_life;
bool rxrpc_complete = false;
DECLARE_WAITQUEUE(myself, current);
@ -619,14 +615,6 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
if (ret < 0)
goto out;
rtt = rxrpc_kernel_get_rtt(call->net->socket, call->rxcall);
rtt2 = nsecs_to_jiffies64(rtt) * 2;
if (rtt2 < 2)
rtt2 = 2;
timeout = rtt2;
rxrpc_kernel_check_life(call->net->socket, call->rxcall, &last_life);
add_wait_queue(&call->waitq, &myself);
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
@ -637,37 +625,19 @@ long afs_wait_for_call_to_complete(struct afs_call *call,
call->need_attention = false;
__set_current_state(TASK_RUNNING);
afs_deliver_to_call(call);
timeout = rtt2;
continue;
}
if (afs_check_call_state(call, AFS_CALL_COMPLETE))
break;
if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall, &life)) {
if (!rxrpc_kernel_check_life(call->net->socket, call->rxcall)) {
/* rxrpc terminated the call. */
rxrpc_complete = true;
break;
}
if (call->intr && timeout == 0 &&
life == last_life && signal_pending(current)) {
if (stalled)
break;
__set_current_state(TASK_RUNNING);
rxrpc_kernel_probe_life(call->net->socket, call->rxcall);
timeout = rtt2;
stalled = true;
continue;
}
if (life != last_life) {
timeout = rtt2;
last_life = life;
stalled = false;
}
timeout = schedule_timeout(timeout);
schedule();
}
remove_wait_queue(&call->waitq, &myself);

Просмотреть файл

@ -64,9 +64,7 @@ int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,
rxrpc_user_attach_call_t, unsigned long, gfp_t,
unsigned int);
void rxrpc_kernel_set_tx_length(struct socket *, struct rxrpc_call *, s64);
bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *,
u32 *);
void rxrpc_kernel_probe_life(struct socket *, struct rxrpc_call *);
bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *);
u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *);
bool rxrpc_kernel_get_reply_time(struct socket *, struct rxrpc_call *,
ktime_t *);

Просмотреть файл

@ -371,44 +371,17 @@ EXPORT_SYMBOL(rxrpc_kernel_end_call);
* rxrpc_kernel_check_life - Check to see whether a call is still alive
* @sock: The socket the call is on
* @call: The call to check
* @_life: Where to store the life value
*
* Allow a kernel service to find out whether a call is still alive - ie. we're
* getting ACKs from the server. Passes back in *_life a number representing
* the life state which can be compared to that returned by a previous call and
* return true if the call is still alive.
*
* If the life state stalls, rxrpc_kernel_probe_life() should be called and
* then 2RTT waited.
* Allow a kernel service to find out whether a call is still alive -
* ie. whether it has completed.
*/
bool rxrpc_kernel_check_life(const struct socket *sock,
const struct rxrpc_call *call,
u32 *_life)
const struct rxrpc_call *call)
{
*_life = call->acks_latest;
return call->state != RXRPC_CALL_COMPLETE;
}
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, 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.
* @sock: The socket the call is on

Просмотреть файл

@ -675,7 +675,6 @@ struct rxrpc_call {
/* transmission-phase ACK management */
ktime_t acks_latest_ts; /* Timestamp of latest ACK received */
rxrpc_serial_t acks_latest; /* serial number of latest ACK received */
rxrpc_seq_t acks_lowest_nak; /* Lowest NACK in the buffer (or ==tx_hard_ack) */
rxrpc_seq_t acks_lost_top; /* tx_top at the time lost-ack ping sent */
rxrpc_serial_t acks_lost_ping; /* Serial number of probe ACK */

Просмотреть файл

@ -882,7 +882,6 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb)
before(prev_pkt, call->ackr_prev_seq))
goto out;
call->acks_latest_ts = skb->tstamp;
call->acks_latest = sp->hdr.serial;
call->ackr_first_seq = first_soft_ack;
call->ackr_prev_seq = prev_pkt;