| From foo@baz Fri Jan 22 01:21:57 PM CET 2021 |
| From: Willem de Bruijn <willemb@google.com> |
| Date: Sat, 9 Jan 2021 17:18:34 -0500 |
| Subject: esp: avoid unneeded kmap_atomic call |
| |
| From: Willem de Bruijn <willemb@google.com> |
| |
| [ Upstream commit 9bd6b629c39e3fa9e14243a6d8820492be1a5b2e ] |
| |
| esp(6)_output_head uses skb_page_frag_refill to allocate a buffer for |
| the esp trailer. |
| |
| It accesses the page with kmap_atomic to handle highmem. But |
| skb_page_frag_refill can return compound pages, of which |
| kmap_atomic only maps the first underlying page. |
| |
| skb_page_frag_refill does not return highmem, because flag |
| __GFP_HIGHMEM is not set. ESP uses it in the same manner as TCP. |
| That also does not call kmap_atomic, but directly uses page_address, |
| in skb_copy_to_page_nocache. Do the same for ESP. |
| |
| This issue has become easier to trigger with recent kmap local |
| debugging feature CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP. |
| |
| Fixes: cac2661c53f3 ("esp4: Avoid skb_cow_data whenever possible") |
| Fixes: 03e2a30f6a27 ("esp6: Avoid skb_cow_data whenever possible") |
| Signed-off-by: Willem de Bruijn <willemb@google.com> |
| Acked-by: Steffen Klassert <steffen.klassert@secunet.com> |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv4/esp4.c | 7 +------ |
| net/ipv6/esp6.c | 7 +------ |
| 2 files changed, 2 insertions(+), 12 deletions(-) |
| |
| --- a/net/ipv4/esp4.c |
| +++ b/net/ipv4/esp4.c |
| @@ -270,7 +270,6 @@ static int esp_output_udp_encap(struct x |
| int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) |
| { |
| u8 *tail; |
| - u8 *vaddr; |
| int nfrags; |
| int esph_offset; |
| struct page *page; |
| @@ -312,14 +311,10 @@ int esp_output_head(struct xfrm_state *x |
| page = pfrag->page; |
| get_page(page); |
| |
| - vaddr = kmap_atomic(page); |
| - |
| - tail = vaddr + pfrag->offset; |
| + tail = page_address(page) + pfrag->offset; |
| |
| esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto); |
| |
| - kunmap_atomic(vaddr); |
| - |
| nfrags = skb_shinfo(skb)->nr_frags; |
| |
| __skb_fill_page_desc(skb, nfrags, page, pfrag->offset, |
| --- a/net/ipv6/esp6.c |
| +++ b/net/ipv6/esp6.c |
| @@ -237,7 +237,6 @@ static void esp_output_fill_trailer(u8 * |
| int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) |
| { |
| u8 *tail; |
| - u8 *vaddr; |
| int nfrags; |
| struct page *page; |
| struct sk_buff *trailer; |
| @@ -270,14 +269,10 @@ int esp6_output_head(struct xfrm_state * |
| page = pfrag->page; |
| get_page(page); |
| |
| - vaddr = kmap_atomic(page); |
| - |
| - tail = vaddr + pfrag->offset; |
| + tail = page_address(page) + pfrag->offset; |
| |
| esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto); |
| |
| - kunmap_atomic(vaddr); |
| - |
| nfrags = skb_shinfo(skb)->nr_frags; |
| |
| __skb_fill_page_desc(skb, nfrags, page, pfrag->offset, |