Skip to content

Commit bc5e3a5

Browse files
committed
rxrpc: Use MSG_WAITALL to tell sendmsg() to temporarily ignore signals
Make AF_RXRPC accept MSG_WAITALL as a flag to sendmsg() to tell it to ignore signals whilst loading up the message queue, provided progress is being made in emptying the queue at the other side. Progress is defined as the base of the transmit window having being advanced within 2 RTT periods. If the period is exceeded with no progress, sendmsg() will return anyway, indicating how much data has been copied, if any. Once the supplied buffer is entirely decanted, the sendmsg() will return. Signed-off-by: David Howells <[email protected]>
1 parent f4d15fb commit bc5e3a5

File tree

3 files changed

+119
-31
lines changed

3 files changed

+119
-31
lines changed

Documentation/networking/rxrpc.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,18 @@ Interaction with the user of the RxRPC socket:
280280
nominated by a socket option.
281281

282282

283+
Notes on sendmsg:
284+
285+
(*) MSG_WAITALL can be set to tell sendmsg to ignore signals if the peer is
286+
making progress at accepting packets within a reasonable time such that we
287+
manage to queue up all the data for transmission. This requires the
288+
client to accept at least one packet per 2*RTT time period.
289+
290+
If this isn't set, sendmsg() will return immediately, either returning
291+
EINTR/ERESTARTSYS if nothing was consumed or returning the amount of data
292+
consumed.
293+
294+
283295
Notes on recvmsg:
284296

285297
(*) If there's a sequence of data messages belonging to a particular call on

fs/afs/rxrpc.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
407407
call->request_size);
408408
msg.msg_control = NULL;
409409
msg.msg_controllen = 0;
410-
msg.msg_flags = (call->send_pages ? MSG_MORE : 0);
410+
msg.msg_flags = MSG_WAITALL | (call->send_pages ? MSG_MORE : 0);
411411

412412
/* We have to change the state *before* sending the last packet as
413413
* rxrpc might give us the reply before it returns from sending the
@@ -538,15 +538,26 @@ static void afs_deliver_to_call(struct afs_call *call)
538538
*/
539539
static int afs_wait_for_call_to_complete(struct afs_call *call)
540540
{
541+
signed long rtt2, timeout;
541542
int ret;
543+
u64 rtt;
544+
u32 life, last_life;
542545

543546
DECLARE_WAITQUEUE(myself, current);
544547

545548
_enter("");
546549

550+
rtt = rxrpc_kernel_get_rtt(afs_socket, call->rxcall);
551+
rtt2 = nsecs_to_jiffies64(rtt) * 2;
552+
if (rtt2 < 2)
553+
rtt2 = 2;
554+
555+
timeout = rtt2;
556+
last_life = rxrpc_kernel_check_life(afs_socket, call->rxcall);
557+
547558
add_wait_queue(&call->waitq, &myself);
548559
for (;;) {
549-
set_current_state(TASK_INTERRUPTIBLE);
560+
set_current_state(TASK_UNINTERRUPTIBLE);
550561

551562
/* deliver any messages that are in the queue */
552563
if (call->state < AFS_CALL_COMPLETE && call->need_attention) {
@@ -556,10 +567,20 @@ static int afs_wait_for_call_to_complete(struct afs_call *call)
556567
continue;
557568
}
558569

559-
if (call->state == AFS_CALL_COMPLETE ||
560-
signal_pending(current))
570+
if (call->state == AFS_CALL_COMPLETE)
561571
break;
562-
schedule();
572+
573+
life = rxrpc_kernel_check_life(afs_socket, call->rxcall);
574+
if (timeout == 0 &&
575+
life == last_life && signal_pending(current))
576+
break;
577+
578+
if (life != last_life) {
579+
timeout = rtt2;
580+
last_life = life;
581+
}
582+
583+
timeout = schedule_timeout(timeout);
563584
}
564585

565586
remove_wait_queue(&call->waitq, &myself);

net/rxrpc/sendmsg.c

Lines changed: 81 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,87 @@ struct rxrpc_send_params {
3737
bool upgrade; /* If the connection is upgradeable */
3838
};
3939

40+
/*
41+
* Wait for space to appear in the Tx queue or a signal to occur.
42+
*/
43+
static int rxrpc_wait_for_tx_window_intr(struct rxrpc_sock *rx,
44+
struct rxrpc_call *call,
45+
long *timeo)
46+
{
47+
for (;;) {
48+
set_current_state(TASK_INTERRUPTIBLE);
49+
if (call->tx_top - call->tx_hard_ack <
50+
min_t(unsigned int, call->tx_winsize,
51+
call->cong_cwnd + call->cong_extra))
52+
return 0;
53+
54+
if (call->state >= RXRPC_CALL_COMPLETE)
55+
return call->error;
56+
57+
if (signal_pending(current))
58+
return sock_intr_errno(*timeo);
59+
60+
trace_rxrpc_transmit(call, rxrpc_transmit_wait);
61+
mutex_unlock(&call->user_mutex);
62+
*timeo = schedule_timeout(*timeo);
63+
if (mutex_lock_interruptible(&call->user_mutex) < 0)
64+
return sock_intr_errno(*timeo);
65+
}
66+
}
67+
68+
/*
69+
* Wait for space to appear in the Tx queue uninterruptibly, but with
70+
* a timeout of 2*RTT if no progress was made and a signal occurred.
71+
*/
72+
static int rxrpc_wait_for_tx_window_nonintr(struct rxrpc_sock *rx,
73+
struct rxrpc_call *call)
74+
{
75+
rxrpc_seq_t tx_start, tx_win;
76+
signed long rtt2, timeout;
77+
u64 rtt;
78+
79+
rtt = READ_ONCE(call->peer->rtt);
80+
rtt2 = nsecs_to_jiffies64(rtt) * 2;
81+
if (rtt2 < 1)
82+
rtt2 = 1;
83+
84+
timeout = rtt2;
85+
tx_start = READ_ONCE(call->tx_hard_ack);
86+
87+
for (;;) {
88+
set_current_state(TASK_UNINTERRUPTIBLE);
89+
90+
tx_win = READ_ONCE(call->tx_hard_ack);
91+
if (call->tx_top - tx_win <
92+
min_t(unsigned int, call->tx_winsize,
93+
call->cong_cwnd + call->cong_extra))
94+
return 0;
95+
96+
if (call->state >= RXRPC_CALL_COMPLETE)
97+
return call->error;
98+
99+
if (timeout == 0 &&
100+
tx_win == tx_start && signal_pending(current))
101+
return -EINTR;
102+
103+
if (tx_win != tx_start) {
104+
timeout = rtt2;
105+
tx_start = tx_win;
106+
}
107+
108+
trace_rxrpc_transmit(call, rxrpc_transmit_wait);
109+
timeout = schedule_timeout(timeout);
110+
}
111+
}
112+
40113
/*
41114
* wait for space to appear in the transmit/ACK window
42115
* - caller holds the socket locked
43116
*/
44117
static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx,
45118
struct rxrpc_call *call,
46-
long *timeo)
119+
long *timeo,
120+
bool waitall)
47121
{
48122
DECLARE_WAITQUEUE(myself, current);
49123
int ret;
@@ -53,30 +127,10 @@ static int rxrpc_wait_for_tx_window(struct rxrpc_sock *rx,
53127

54128
add_wait_queue(&call->waitq, &myself);
55129

56-
for (;;) {
57-
set_current_state(TASK_INTERRUPTIBLE);
58-
ret = 0;
59-
if (call->tx_top - call->tx_hard_ack <
60-
min_t(unsigned int, call->tx_winsize,
61-
call->cong_cwnd + call->cong_extra))
62-
break;
63-
if (call->state >= RXRPC_CALL_COMPLETE) {
64-
ret = call->error;
65-
break;
66-
}
67-
if (signal_pending(current)) {
68-
ret = sock_intr_errno(*timeo);
69-
break;
70-
}
71-
72-
trace_rxrpc_transmit(call, rxrpc_transmit_wait);
73-
mutex_unlock(&call->user_mutex);
74-
*timeo = schedule_timeout(*timeo);
75-
if (mutex_lock_interruptible(&call->user_mutex) < 0) {
76-
ret = sock_intr_errno(*timeo);
77-
break;
78-
}
79-
}
130+
if (waitall)
131+
ret = rxrpc_wait_for_tx_window_nonintr(rx, call);
132+
else
133+
ret = rxrpc_wait_for_tx_window_intr(rx, call, timeo);
80134

81135
remove_wait_queue(&call->waitq, &myself);
82136
set_current_state(TASK_RUNNING);
@@ -254,7 +308,8 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
254308
if (msg->msg_flags & MSG_DONTWAIT)
255309
goto maybe_error;
256310
ret = rxrpc_wait_for_tx_window(rx, call,
257-
&timeo);
311+
&timeo,
312+
msg->msg_flags & MSG_WAITALL);
258313
if (ret < 0)
259314
goto maybe_error;
260315
}

0 commit comments

Comments
 (0)