Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'skb-frag-kmap_atomic-fixes'

Willem de Bruijn says:

====================
skb frag: kmap_atomic fixes

skb frags may be backed by highmem and/or compound pages. Various
code calls kmap_atomic to safely access highmem pages. But this
needs additional care for compound pages. Fix a few issues:

patch 1 expect kmap mappings with CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP
patch 2 fixes kmap_atomic + compound page support in skb_seq_read
patch 3 fixes kmap_atomic + compound page support in esp
====================

Link: https://lore.kernel.org/r/20210109221834.3459768-1-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+28 -19
+2 -1
include/linux/skbuff.h
··· 366 366 static inline bool skb_frag_must_loop(struct page *p) 367 367 { 368 368 #if defined(CONFIG_HIGHMEM) 369 - if (PageHighMem(p)) 369 + if (IS_ENABLED(CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP) || PageHighMem(p)) 370 370 return true; 371 371 #endif 372 372 return false; ··· 1203 1203 struct sk_buff *root_skb; 1204 1204 struct sk_buff *cur_skb; 1205 1205 __u8 *frag_data; 1206 + __u32 frag_off; 1206 1207 }; 1207 1208 1208 1209 void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,
+24 -6
net/core/skbuff.c
··· 3442 3442 st->root_skb = st->cur_skb = skb; 3443 3443 st->frag_idx = st->stepped_offset = 0; 3444 3444 st->frag_data = NULL; 3445 + st->frag_off = 0; 3445 3446 } 3446 3447 EXPORT_SYMBOL(skb_prepare_seq_read); 3447 3448 ··· 3497 3496 st->stepped_offset += skb_headlen(st->cur_skb); 3498 3497 3499 3498 while (st->frag_idx < skb_shinfo(st->cur_skb)->nr_frags) { 3500 - frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx]; 3501 - block_limit = skb_frag_size(frag) + st->stepped_offset; 3499 + unsigned int pg_idx, pg_off, pg_sz; 3502 3500 3501 + frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx]; 3502 + 3503 + pg_idx = 0; 3504 + pg_off = skb_frag_off(frag); 3505 + pg_sz = skb_frag_size(frag); 3506 + 3507 + if (skb_frag_must_loop(skb_frag_page(frag))) { 3508 + pg_idx = (pg_off + st->frag_off) >> PAGE_SHIFT; 3509 + pg_off = offset_in_page(pg_off + st->frag_off); 3510 + pg_sz = min_t(unsigned int, pg_sz - st->frag_off, 3511 + PAGE_SIZE - pg_off); 3512 + } 3513 + 3514 + block_limit = pg_sz + st->stepped_offset; 3503 3515 if (abs_offset < block_limit) { 3504 3516 if (!st->frag_data) 3505 - st->frag_data = kmap_atomic(skb_frag_page(frag)); 3517 + st->frag_data = kmap_atomic(skb_frag_page(frag) + pg_idx); 3506 3518 3507 - *data = (u8 *) st->frag_data + skb_frag_off(frag) + 3519 + *data = (u8 *)st->frag_data + pg_off + 3508 3520 (abs_offset - st->stepped_offset); 3509 3521 3510 3522 return block_limit - abs_offset; ··· 3528 3514 st->frag_data = NULL; 3529 3515 } 3530 3516 3531 - st->frag_idx++; 3532 - st->stepped_offset += skb_frag_size(frag); 3517 + st->stepped_offset += pg_sz; 3518 + st->frag_off += pg_sz; 3519 + if (st->frag_off == skb_frag_size(frag)) { 3520 + st->frag_off = 0; 3521 + st->frag_idx++; 3522 + } 3533 3523 } 3534 3524 3535 3525 if (st->frag_data) {
+1 -6
net/ipv4/esp4.c
··· 443 443 int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) 444 444 { 445 445 u8 *tail; 446 - u8 *vaddr; 447 446 int nfrags; 448 447 int esph_offset; 449 448 struct page *page; ··· 484 485 page = pfrag->page; 485 486 get_page(page); 486 487 487 - vaddr = kmap_atomic(page); 488 - 489 - tail = vaddr + pfrag->offset; 488 + tail = page_address(page) + pfrag->offset; 490 489 491 490 esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto); 492 - 493 - kunmap_atomic(vaddr); 494 491 495 492 nfrags = skb_shinfo(skb)->nr_frags; 496 493
+1 -6
net/ipv6/esp6.c
··· 478 478 int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) 479 479 { 480 480 u8 *tail; 481 - u8 *vaddr; 482 481 int nfrags; 483 482 int esph_offset; 484 483 struct page *page; ··· 518 519 page = pfrag->page; 519 520 get_page(page); 520 521 521 - vaddr = kmap_atomic(page); 522 - 523 - tail = vaddr + pfrag->offset; 522 + tail = page_address(page) + pfrag->offset; 524 523 525 524 esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto); 526 - 527 - kunmap_atomic(vaddr); 528 525 529 526 nfrags = skb_shinfo(skb)->nr_frags; 530 527