Skip to content

Commit 03f45c8

Browse files
Eric Dumazetdavem330
authored andcommitted
tcp: avoid extra wakeups for SO_RCVLOWAT users
SO_RCVLOWAT is properly handled in tcp_poll(), so that POLLIN is only generated when enough bytes are available in receive queue, after David change (commit c700448 "tcp: Respect SO_RCVLOWAT in tcp_poll().") But TCP still calls sk->sk_data_ready() for each chunk added in receive queue, meaning thread is awaken, and goes back to sleep shortly after. Tested: tcp_mmap test program, receiving 32768 MB of data with SO_RCVLOWAT set to 512KB -> Should get ~2 wakeups (c-switches) per MB, regardless of how many (tiny or big) packets were received. High speed (mostly full size GRO packets) received 32768 MB (100 % mmap'ed) in 8.03112 s, 34.2266 Gbit, cpu usage user:0.037 sys:1.404, 43.9758 usec per MB, 65497 c-switches received 32768 MB (99.9954 % mmap'ed) in 7.98453 s, 34.4263 Gbit, cpu usage user:0.03 sys:1.422, 44.3115 usec per MB, 65485 c-switches Low speed (sender is ratelimited and sends 1-MSS at a time, so GRO is not helping) received 22474.5 MB (100 % mmap'ed) in 6015.35 s, 0.0313414 Gbit, cpu usage user:0.05 sys:1.586, 72.7952 usec per MB, 44950 c-switches Signed-off-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 796f82e commit 03f45c8

File tree

3 files changed

+18
-2
lines changed

3 files changed

+18
-2
lines changed

include/net/tcp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ void tcp_syn_ack_timeout(const struct request_sock *req);
403403
int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
404404
int flags, int *addr_len);
405405
int tcp_set_rcvlowat(struct sock *sk, int val);
406+
void tcp_data_ready(struct sock *sk);
406407
void tcp_parse_options(const struct net *net, const struct sk_buff *skb,
407408
struct tcp_options_received *opt_rx,
408409
int estab, struct tcp_fastopen_cookie *foc);

net/ipv4/tcp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,6 +1705,10 @@ EXPORT_SYMBOL(tcp_peek_len);
17051705
int tcp_set_rcvlowat(struct sock *sk, int val)
17061706
{
17071707
sk->sk_rcvlowat = val ? : 1;
1708+
1709+
/* Check if we need to signal EPOLLIN right now */
1710+
tcp_data_ready(sk);
1711+
17081712
if (sk->sk_userlocks & SOCK_RCVBUF_LOCK)
17091713
return 0;
17101714

net/ipv4/tcp_input.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4576,6 +4576,17 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
45764576

45774577
}
45784578

4579+
void tcp_data_ready(struct sock *sk)
4580+
{
4581+
const struct tcp_sock *tp = tcp_sk(sk);
4582+
int avail = tp->rcv_nxt - tp->copied_seq;
4583+
4584+
if (avail < sk->sk_rcvlowat && !sock_flag(sk, SOCK_DONE))
4585+
return;
4586+
4587+
sk->sk_data_ready(sk);
4588+
}
4589+
45794590
static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
45804591
{
45814592
struct tcp_sock *tp = tcp_sk(sk);
@@ -4633,7 +4644,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
46334644
if (eaten > 0)
46344645
kfree_skb_partial(skb, fragstolen);
46354646
if (!sock_flag(sk, SOCK_DEAD))
4636-
sk->sk_data_ready(sk);
4647+
tcp_data_ready(sk);
46374648
return;
46384649
}
46394650

@@ -5434,7 +5445,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
54345445
no_ack:
54355446
if (eaten)
54365447
kfree_skb_partial(skb, fragstolen);
5437-
sk->sk_data_ready(sk);
5448+
tcp_data_ready(sk);
54385449
return;
54395450
}
54405451
}

0 commit comments

Comments
 (0)