Commit 33966dd0 authored by Willy Tarreau's avatar Willy Tarreau Committed by David S. Miller

tcp: splice as many packets as possible at once

As spotted by Willy Tarreau, current splice() from tcp socket to pipe is not
optimal. It processes at most one segment per call.
This results in low performance and very high overhead due to syscall rate
when splicing from interfaces which do not support LRO.

Willy provided a patch inside tcp_splice_read(), but a better fix
is to let tcp_read_sock() process as many segments as possible, so
that tcp_rcv_space_adjust() and tcp_cleanup_rbuf() are called less
often.

With this change, splice() behaves like tcp_recvmsg(), being able
to consume many skbs in one system call. With typical 1460 bytes
of payload per frame, that means splice(SPLICE_F_NONBLOCK) can return
16*1460 = 23360 bytes.
Signed-off-by: default avatarWilly Tarreau <w@1wt.eu>
Signed-off-by: default avatarEric Dumazet <dada1@cosmosbay.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9a0811ca
...@@ -522,8 +522,12 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, ...@@ -522,8 +522,12 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
unsigned int offset, size_t len) unsigned int offset, size_t len)
{ {
struct tcp_splice_state *tss = rd_desc->arg.data; struct tcp_splice_state *tss = rd_desc->arg.data;
int ret;
return skb_splice_bits(skb, offset, tss->pipe, tss->len, tss->flags); ret = skb_splice_bits(skb, offset, tss->pipe, rd_desc->count, tss->flags);
if (ret > 0)
rd_desc->count -= ret;
return ret;
} }
static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss) static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss)
...@@ -531,6 +535,7 @@ static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss) ...@@ -531,6 +535,7 @@ static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss)
/* Store TCP splice context information in read_descriptor_t. */ /* Store TCP splice context information in read_descriptor_t. */
read_descriptor_t rd_desc = { read_descriptor_t rd_desc = {
.arg.data = tss, .arg.data = tss,
.count = tss->len,
}; };
return tcp_read_sock(sk, &rd_desc, tcp_splice_data_recv); return tcp_read_sock(sk, &rd_desc, tcp_splice_data_recv);
...@@ -611,11 +616,13 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, ...@@ -611,11 +616,13 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
tss.len -= ret; tss.len -= ret;
spliced += ret; spliced += ret;
if (!timeo)
break;
release_sock(sk); release_sock(sk);
lock_sock(sk); lock_sock(sk);
if (sk->sk_err || sk->sk_state == TCP_CLOSE || if (sk->sk_err || sk->sk_state == TCP_CLOSE ||
(sk->sk_shutdown & RCV_SHUTDOWN) || !timeo || (sk->sk_shutdown & RCV_SHUTDOWN) ||
signal_pending(current)) signal_pending(current))
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment