From: Willem de Bruijn <[email protected]>

This avoids an unnecessary copy of 1-2KB and improves tso_fragment,
which has to fall back to tcp_fragment if skb->len != skb_data_len.

It also avoids a surprising inconsistency in notifications:
Zerocopy packets sent over loopback have their frags copied, so set
SO_EE_CODE_ZEROCOPY_COPIED in the notification. But this currently
does not happen for small packets, because when all data fits in the
linear fragment, data is not copied in skb_orphan_frags_rx.

Reported-by: Tom Deseyn <[email protected]>
Signed-off-by: Willem de Bruijn <[email protected]>
---
 net/ipv4/tcp.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 44102484a76f..947348872c3e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1186,7 +1186,7 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr 
*msg, size_t size)
        int flags, err, copied = 0;
        int mss_now = 0, size_goal, copied_syn = 0;
        bool process_backlog = false;
-       bool sg;
+       bool sg, zc = false;
        long timeo;
 
        flags = msg->msg_flags;
@@ -1204,7 +1204,8 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr 
*msg, size_t size)
                        goto out_err;
                }
 
-               if (!(sk_check_csum_caps(sk) && sk->sk_route_caps & NETIF_F_SG))
+               zc = sk_check_csum_caps(sk) && sk->sk_route_caps & NETIF_F_SG;
+               if (!zc)
                        uarg->zerocopy = 0;
        }
 
@@ -1325,13 +1326,13 @@ int tcp_sendmsg_locked(struct sock *sk, struct msghdr 
*msg, size_t size)
                        copy = msg_data_left(msg);
 
                /* Where to copy to? */
-               if (skb_availroom(skb) > 0) {
+               if (skb_availroom(skb) > 0 && !zc) {
                        /* We have some space in skb head. Superb! */
                        copy = min_t(int, copy, skb_availroom(skb));
                        err = skb_add_data_nocache(sk, skb, &msg->msg_iter, 
copy);
                        if (err)
                                goto do_fault;
-               } else if (!uarg || !uarg->zerocopy) {
+               } else if (!zc) {
                        bool merge = true;
                        int i = skb_shinfo(skb)->nr_frags;
                        struct page_frag *pfrag = sk_page_frag(sk);
-- 
2.15.1.620.gb9897f4670-goog

Reply via email to