From: Greg Kroah-Hartman Date: Fri, 30 Jul 2021 10:50:17 +0000 (+0200) Subject: 4.14-stable patches X-Git-Tag: v5.13.7~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2166541a4a59eb4162ae386311c1eb459639d100;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: gro-ensure-frag0-meets-ip-header-alignment.patch virtio_net-do-not-pull-payload-in-skb-head.patch --- diff --git a/queue-4.14/gro-ensure-frag0-meets-ip-header-alignment.patch b/queue-4.14/gro-ensure-frag0-meets-ip-header-alignment.patch new file mode 100644 index 00000000000..e599e9893be --- /dev/null +++ b/queue-4.14/gro-ensure-frag0-meets-ip-header-alignment.patch @@ -0,0 +1,75 @@ +From 38ec4944b593fd90c5ef42aaaa53e66ae5769d04 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Tue, 13 Apr 2021 05:41:35 -0700 +Subject: gro: ensure frag0 meets IP header alignment + +From: Eric Dumazet + +commit 38ec4944b593fd90c5ef42aaaa53e66ae5769d04 upstream. + +After commit 0f6925b3e8da ("virtio_net: Do not pull payload in skb->head") +Guenter Roeck reported one failure in his tests using sh architecture. + +After much debugging, we have been able to spot silent unaligned accesses +in inet_gro_receive() + +The issue at hand is that upper networking stacks assume their header +is word-aligned. Low level drivers are supposed to reserve NET_IP_ALIGN +bytes before the Ethernet header to make that happen. + +This patch hardens skb_gro_reset_offset() to not allow frag0 fast-path +if the fragment is not properly aligned. + +Some arches like x86, arm64 and powerpc do not care and define NET_IP_ALIGN +as 0, this extra check will be a NOP for them. + +Note that if frag0 is not used, GRO will call pskb_may_pull() +as many times as needed to pull network and transport headers. + +Fixes: 0f6925b3e8da ("virtio_net: Do not pull payload in skb->head") +Fixes: 78a478d0efd9 ("gro: Inline skb_gro_header and cache frag0 virtual address") +Signed-off-by: Eric Dumazet +Reported-by: Guenter Roeck +Cc: Xuan Zhuo +Cc: "Michael S. Tsirkin" +Cc: Jason Wang +Acked-by: Michael S. Tsirkin +Tested-by: Guenter Roeck +Signed-off-by: David S. Miller +Signed-off-by: Matthieu Baerts +Signed-off-by: Greg Kroah-Hartman +--- + include/linux/skbuff.h | 9 +++++++++ + net/core/dev.c | 3 ++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +--- a/include/linux/skbuff.h ++++ b/include/linux/skbuff.h +@@ -2785,6 +2785,15 @@ static inline void skb_propagate_pfmemal + } + + /** ++ * skb_frag_off() - Returns the offset of a skb fragment ++ * @frag: the paged fragment ++ */ ++static inline unsigned int skb_frag_off(const skb_frag_t *frag) ++{ ++ return frag->page_offset; ++} ++ ++/** + * skb_frag_page - retrieve the page referred to by a paged fragment + * @frag: the paged fragment + * +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -4763,7 +4763,8 @@ static void skb_gro_reset_offset(struct + + if (skb_mac_header(skb) == skb_tail_pointer(skb) && + pinfo->nr_frags && +- !PageHighMem(skb_frag_page(frag0))) { ++ !PageHighMem(skb_frag_page(frag0)) && ++ (!NET_IP_ALIGN || !(skb_frag_off(frag0) & 3))) { + NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); + NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int, + skb_frag_size(frag0), diff --git a/queue-4.14/series b/queue-4.14/series index d73549a1f57..78cb0e8cad8 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -11,3 +11,5 @@ hfs-add-missing-clean-up-in-hfs_fill_super.patch hfs-fix-high-memory-mapping-in-hfs_bnode_read.patch hfs-add-lock-nesting-notation-to-hfs_find_init.patch arm-dts-versatile-fix-up-interrupt-controller-node-n.patch +virtio_net-do-not-pull-payload-in-skb-head.patch +gro-ensure-frag0-meets-ip-header-alignment.patch diff --git a/queue-4.14/virtio_net-do-not-pull-payload-in-skb-head.patch b/queue-4.14/virtio_net-do-not-pull-payload-in-skb-head.patch new file mode 100644 index 00000000000..889ce97ee69 --- /dev/null +++ b/queue-4.14/virtio_net-do-not-pull-payload-in-skb-head.patch @@ -0,0 +1,113 @@ +From 0f6925b3e8da0dbbb52447ca8a8b42b371aac7db Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 2 Apr 2021 06:26:02 -0700 +Subject: virtio_net: Do not pull payload in skb->head + +From: Eric Dumazet + +commit 0f6925b3e8da0dbbb52447ca8a8b42b371aac7db upstream. + +Xuan Zhuo reported that commit 3226b158e67c ("net: avoid 32 x truesize +under-estimation for tiny skbs") brought a ~10% performance drop. + +The reason for the performance drop was that GRO was forced +to chain sk_buff (using skb_shinfo(skb)->frag_list), which +uses more memory but also cause packet consumers to go over +a lot of overhead handling all the tiny skbs. + +It turns out that virtio_net page_to_skb() has a wrong strategy : +It allocates skbs with GOOD_COPY_LEN (128) bytes in skb->head, then +copies 128 bytes from the page, before feeding the packet to GRO stack. + +This was suboptimal before commit 3226b158e67c ("net: avoid 32 x truesize +under-estimation for tiny skbs") because GRO was using 2 frags per MSS, +meaning we were not packing MSS with 100% efficiency. + +Fix is to pull only the ethernet header in page_to_skb() + +Then, we change virtio_net_hdr_to_skb() to pull the missing +headers, instead of assuming they were already pulled by callers. + +This fixes the performance regression, but could also allow virtio_net +to accept packets with more than 128bytes of headers. + +Many thanks to Xuan Zhuo for his report, and his tests/help. + +Fixes: 3226b158e67c ("net: avoid 32 x truesize under-estimation for tiny skbs") +Reported-by: Xuan Zhuo +Link: https://www.spinics.net/lists/netdev/msg731397.html +Co-Developed-by: Xuan Zhuo +Signed-off-by: Xuan Zhuo +Signed-off-by: Eric Dumazet +Cc: "Michael S. Tsirkin" +Cc: Jason Wang +Cc: virtualization@lists.linux-foundation.org +Acked-by: Jason Wang +Signed-off-by: David S. Miller +Signed-off-by: Matthieu Baerts +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/virtio_net.c | 10 +++++++--- + include/linux/virtio_net.h | 14 +++++++++----- + 2 files changed, 16 insertions(+), 8 deletions(-) + +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -339,9 +339,13 @@ static struct sk_buff *page_to_skb(struc + offset += hdr_padded_len; + p += hdr_padded_len; + +- copy = len; +- if (copy > skb_tailroom(skb)) +- copy = skb_tailroom(skb); ++ /* Copy all frame if it fits skb->head, otherwise ++ * we let virtio_net_hdr_to_skb() and GRO pull headers as needed. ++ */ ++ if (len <= skb_tailroom(skb)) ++ copy = len; ++ else ++ copy = ETH_HLEN; + skb_put_data(skb, p, copy); + + len -= copy; +--- a/include/linux/virtio_net.h ++++ b/include/linux/virtio_net.h +@@ -65,14 +65,18 @@ static inline int virtio_net_hdr_to_skb( + skb_reset_mac_header(skb); + + if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { +- u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start); +- u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset); ++ u32 start = __virtio16_to_cpu(little_endian, hdr->csum_start); ++ u32 off = __virtio16_to_cpu(little_endian, hdr->csum_offset); ++ u32 needed = start + max_t(u32, thlen, off + sizeof(__sum16)); ++ ++ if (!pskb_may_pull(skb, needed)) ++ return -EINVAL; + + if (!skb_partial_csum_set(skb, start, off)) + return -EINVAL; + + p_off = skb_transport_offset(skb) + thlen; +- if (p_off > skb_headlen(skb)) ++ if (!pskb_may_pull(skb, p_off)) + return -EINVAL; + } else { + /* gso packets without NEEDS_CSUM do not set transport_offset. +@@ -100,14 +104,14 @@ retry: + } + + p_off = keys.control.thoff + thlen; +- if (p_off > skb_headlen(skb) || ++ if (!pskb_may_pull(skb, p_off) || + keys.basic.ip_proto != ip_proto) + return -EINVAL; + + skb_set_transport_header(skb, keys.control.thoff); + } else if (gso_type) { + p_off = thlen; +- if (p_off > skb_headlen(skb)) ++ if (!pskb_may_pull(skb, p_off)) + return -EINVAL; + } + }