Skip to content

Commit bb18fc7

Browse files
author
Paolo Abeni
committed
Merge branch 'abstract-page-from-net-stack'
Mina Almasry says: ==================== Abstract page from net stack This series is a prerequisite to the devmem TCP series. For a full snapshot of the code which includes these changes, feel free to check: https://github.com/mina/linux/commits/tcpdevmem-rfcv5/ Currently these components in the net stack use the struct page directly: 1. Drivers. 2. Page pool. 3. skb_frag_t. To add support for new (non struct page) memory types to the net stack, we must first abstract the current memory type. Originally the plan was to reuse struct page* for the new memory types, and to set the LSB on the page* to indicate it's not really a page. However, for safe compiler type checking we need to introduce a new type. struct netmem is introduced to abstract the underlying memory type. Currently it's a no-op abstraction that is always a struct page underneath. In parallel there is an undergoing effort to add support for devmem to the net stack: https://lore.kernel.org/netdev/[email protected]/ Cc: Jason Gunthorpe <[email protected]> Cc: Christian König <[email protected]> Cc: Shakeel Butt <[email protected]> Cc: Yunsheng Lin <[email protected]> Cc: Willem de Bruijn <[email protected]> ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 74293ea + 21d2e67 commit bb18fc7

File tree

4 files changed

+143
-39
lines changed

4 files changed

+143
-39
lines changed

include/linux/skbuff.h

Lines changed: 71 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#endif
3838
#include <net/net_debug.h>
3939
#include <net/dropreason-core.h>
40+
#include <net/netmem.h>
4041

4142
/**
4243
* DOC: skb checksums
@@ -359,15 +360,19 @@ extern int sysctl_max_skb_frags;
359360
*/
360361
#define GSO_BY_FRAGS 0xFFFF
361362

362-
typedef struct bio_vec skb_frag_t;
363+
typedef struct skb_frag {
364+
netmem_ref netmem;
365+
unsigned int len;
366+
unsigned int offset;
367+
} skb_frag_t;
363368

364369
/**
365370
* skb_frag_size() - Returns the size of a skb fragment
366371
* @frag: skb fragment
367372
*/
368373
static inline unsigned int skb_frag_size(const skb_frag_t *frag)
369374
{
370-
return frag->bv_len;
375+
return frag->len;
371376
}
372377

373378
/**
@@ -377,7 +382,7 @@ static inline unsigned int skb_frag_size(const skb_frag_t *frag)
377382
*/
378383
static inline void skb_frag_size_set(skb_frag_t *frag, unsigned int size)
379384
{
380-
frag->bv_len = size;
385+
frag->len = size;
381386
}
382387

383388
/**
@@ -387,7 +392,7 @@ static inline void skb_frag_size_set(skb_frag_t *frag, unsigned int size)
387392
*/
388393
static inline void skb_frag_size_add(skb_frag_t *frag, int delta)
389394
{
390-
frag->bv_len += delta;
395+
frag->len += delta;
391396
}
392397

393398
/**
@@ -397,7 +402,7 @@ static inline void skb_frag_size_add(skb_frag_t *frag, int delta)
397402
*/
398403
static inline void skb_frag_size_sub(skb_frag_t *frag, int delta)
399404
{
400-
frag->bv_len -= delta;
405+
frag->len -= delta;
401406
}
402407

403408
/**
@@ -417,7 +422,7 @@ static inline bool skb_frag_must_loop(struct page *p)
417422
* skb_frag_foreach_page - loop over pages in a fragment
418423
*
419424
* @f: skb frag to operate on
420-
* @f_off: offset from start of f->bv_page
425+
* @f_off: offset from start of f->netmem
421426
* @f_len: length from f_off to loop over
422427
* @p: (temp var) current page
423428
* @p_off: (temp var) offset from start of current page,
@@ -2429,22 +2434,37 @@ static inline unsigned int skb_pagelen(const struct sk_buff *skb)
24292434
return skb_headlen(skb) + __skb_pagelen(skb);
24302435
}
24312436

2437+
static inline void skb_frag_fill_netmem_desc(skb_frag_t *frag,
2438+
netmem_ref netmem, int off,
2439+
int size)
2440+
{
2441+
frag->netmem = netmem;
2442+
frag->offset = off;
2443+
skb_frag_size_set(frag, size);
2444+
}
2445+
24322446
static inline void skb_frag_fill_page_desc(skb_frag_t *frag,
24332447
struct page *page,
24342448
int off, int size)
24352449
{
2436-
frag->bv_page = page;
2437-
frag->bv_offset = off;
2438-
skb_frag_size_set(frag, size);
2450+
skb_frag_fill_netmem_desc(frag, page_to_netmem(page), off, size);
2451+
}
2452+
2453+
static inline void __skb_fill_netmem_desc_noacc(struct skb_shared_info *shinfo,
2454+
int i, netmem_ref netmem,
2455+
int off, int size)
2456+
{
2457+
skb_frag_t *frag = &shinfo->frags[i];
2458+
2459+
skb_frag_fill_netmem_desc(frag, netmem, off, size);
24392460
}
24402461

24412462
static inline void __skb_fill_page_desc_noacc(struct skb_shared_info *shinfo,
24422463
int i, struct page *page,
24432464
int off, int size)
24442465
{
2445-
skb_frag_t *frag = &shinfo->frags[i];
2446-
2447-
skb_frag_fill_page_desc(frag, page, off, size);
2466+
__skb_fill_netmem_desc_noacc(shinfo, i, page_to_netmem(page), off,
2467+
size);
24482468
}
24492469

24502470
/**
@@ -2460,10 +2480,10 @@ static inline void skb_len_add(struct sk_buff *skb, int delta)
24602480
}
24612481

24622482
/**
2463-
* __skb_fill_page_desc - initialise a paged fragment in an skb
2483+
* __skb_fill_netmem_desc - initialise a fragment in an skb
24642484
* @skb: buffer containing fragment to be initialised
2465-
* @i: paged fragment index to initialise
2466-
* @page: the page to use for this fragment
2485+
* @i: fragment index to initialise
2486+
* @netmem: the netmem to use for this fragment
24672487
* @off: the offset to the data with @page
24682488
* @size: the length of the data
24692489
*
@@ -2472,18 +2492,33 @@ static inline void skb_len_add(struct sk_buff *skb, int delta)
24722492
*
24732493
* Does not take any additional reference on the fragment.
24742494
*/
2475-
static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
2476-
struct page *page, int off, int size)
2495+
static inline void __skb_fill_netmem_desc(struct sk_buff *skb, int i,
2496+
netmem_ref netmem, int off, int size)
24772497
{
2478-
__skb_fill_page_desc_noacc(skb_shinfo(skb), i, page, off, size);
2498+
struct page *page = netmem_to_page(netmem);
2499+
2500+
__skb_fill_netmem_desc_noacc(skb_shinfo(skb), i, netmem, off, size);
24792501

24802502
/* Propagate page pfmemalloc to the skb if we can. The problem is
24812503
* that not all callers have unique ownership of the page but rely
24822504
* on page_is_pfmemalloc doing the right thing(tm).
24832505
*/
24842506
page = compound_head(page);
24852507
if (page_is_pfmemalloc(page))
2486-
skb->pfmemalloc = true;
2508+
skb->pfmemalloc = true;
2509+
}
2510+
2511+
static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
2512+
struct page *page, int off, int size)
2513+
{
2514+
__skb_fill_netmem_desc(skb, i, page_to_netmem(page), off, size);
2515+
}
2516+
2517+
static inline void skb_fill_netmem_desc(struct sk_buff *skb, int i,
2518+
netmem_ref netmem, int off, int size)
2519+
{
2520+
__skb_fill_netmem_desc(skb, i, netmem, off, size);
2521+
skb_shinfo(skb)->nr_frags = i + 1;
24872522
}
24882523

24892524
/**
@@ -2503,8 +2538,7 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
25032538
static inline void skb_fill_page_desc(struct sk_buff *skb, int i,
25042539
struct page *page, int off, int size)
25052540
{
2506-
__skb_fill_page_desc(skb, i, page, off, size);
2507-
skb_shinfo(skb)->nr_frags = i + 1;
2541+
skb_fill_netmem_desc(skb, i, page_to_netmem(page), off, size);
25082542
}
25092543

25102544
/**
@@ -2528,8 +2562,16 @@ static inline void skb_fill_page_desc_noacc(struct sk_buff *skb, int i,
25282562
shinfo->nr_frags = i + 1;
25292563
}
25302564

2531-
void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
2532-
int size, unsigned int truesize);
2565+
void skb_add_rx_frag_netmem(struct sk_buff *skb, int i, netmem_ref netmem,
2566+
int off, int size, unsigned int truesize);
2567+
2568+
static inline void skb_add_rx_frag(struct sk_buff *skb, int i,
2569+
struct page *page, int off, int size,
2570+
unsigned int truesize)
2571+
{
2572+
skb_add_rx_frag_netmem(skb, i, page_to_netmem(page), off, size,
2573+
truesize);
2574+
}
25332575

25342576
void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size,
25352577
unsigned int truesize);
@@ -3378,7 +3420,7 @@ static inline void skb_propagate_pfmemalloc(const struct page *page,
33783420
*/
33793421
static inline unsigned int skb_frag_off(const skb_frag_t *frag)
33803422
{
3381-
return frag->bv_offset;
3423+
return frag->offset;
33823424
}
33833425

33843426
/**
@@ -3388,7 +3430,7 @@ static inline unsigned int skb_frag_off(const skb_frag_t *frag)
33883430
*/
33893431
static inline void skb_frag_off_add(skb_frag_t *frag, int delta)
33903432
{
3391-
frag->bv_offset += delta;
3433+
frag->offset += delta;
33923434
}
33933435

33943436
/**
@@ -3398,7 +3440,7 @@ static inline void skb_frag_off_add(skb_frag_t *frag, int delta)
33983440
*/
33993441
static inline void skb_frag_off_set(skb_frag_t *frag, unsigned int offset)
34003442
{
3401-
frag->bv_offset = offset;
3443+
frag->offset = offset;
34023444
}
34033445

34043446
/**
@@ -3409,7 +3451,7 @@ static inline void skb_frag_off_set(skb_frag_t *frag, unsigned int offset)
34093451
static inline void skb_frag_off_copy(skb_frag_t *fragto,
34103452
const skb_frag_t *fragfrom)
34113453
{
3412-
fragto->bv_offset = fragfrom->bv_offset;
3454+
fragto->offset = fragfrom->offset;
34133455
}
34143456

34153457
/**
@@ -3420,7 +3462,7 @@ static inline void skb_frag_off_copy(skb_frag_t *fragto,
34203462
*/
34213463
static inline struct page *skb_frag_page(const skb_frag_t *frag)
34223464
{
3423-
return frag->bv_page;
3465+
return netmem_to_page(frag->netmem);
34243466
}
34253467

34263468
/**
@@ -3528,7 +3570,7 @@ static inline void *skb_frag_address_safe(const skb_frag_t *frag)
35283570
static inline void skb_frag_page_copy(skb_frag_t *fragto,
35293571
const skb_frag_t *fragfrom)
35303572
{
3531-
fragto->bv_page = fragfrom->bv_page;
3573+
fragto->netmem = fragfrom->netmem;
35323574
}
35333575

35343576
bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio);

include/net/netmem.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* SPDX-License-Identifier: GPL-2.0
2+
*
3+
* Network memory
4+
*
5+
* Author: Mina Almasry <[email protected]>
6+
*/
7+
8+
#ifndef _NET_NETMEM_H
9+
#define _NET_NETMEM_H
10+
11+
/**
12+
* typedef netmem_ref - a nonexistent type marking a reference to generic
13+
* network memory.
14+
*
15+
* A netmem_ref currently is always a reference to a struct page. This
16+
* abstraction is introduced so support for new memory types can be added.
17+
*
18+
* Use the supplied helpers to obtain the underlying memory pointer and fields.
19+
*/
20+
typedef unsigned long __bitwise netmem_ref;
21+
22+
/* This conversion fails (returns NULL) if the netmem_ref is not struct page
23+
* backed.
24+
*
25+
* Currently struct page is the only possible netmem, and this helper never
26+
* fails.
27+
*/
28+
static inline struct page *netmem_to_page(netmem_ref netmem)
29+
{
30+
return (__force struct page *)netmem;
31+
}
32+
33+
/* Converting from page to netmem is always safe, because a page can always be
34+
* a netmem.
35+
*/
36+
static inline netmem_ref page_to_netmem(struct page *page)
37+
{
38+
return (__force netmem_ref)page;
39+
}
40+
41+
#endif /* _NET_NETMEM_H */

net/core/skbuff.c

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,24 @@ static struct kmem_cache *skb_small_head_cache __ro_after_init;
115115
int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS;
116116
EXPORT_SYMBOL(sysctl_max_skb_frags);
117117

118+
/* kcm_write_msgs() relies on casting paged frags to bio_vec to use
119+
* iov_iter_bvec(). These static asserts ensure the cast is valid is long as the
120+
* netmem is a page.
121+
*/
122+
static_assert(offsetof(struct bio_vec, bv_page) ==
123+
offsetof(skb_frag_t, netmem));
124+
static_assert(sizeof_field(struct bio_vec, bv_page) ==
125+
sizeof_field(skb_frag_t, netmem));
126+
127+
static_assert(offsetof(struct bio_vec, bv_len) == offsetof(skb_frag_t, len));
128+
static_assert(sizeof_field(struct bio_vec, bv_len) ==
129+
sizeof_field(skb_frag_t, len));
130+
131+
static_assert(offsetof(struct bio_vec, bv_offset) ==
132+
offsetof(skb_frag_t, offset));
133+
static_assert(sizeof_field(struct bio_vec, bv_offset) ==
134+
sizeof_field(skb_frag_t, offset));
135+
118136
#undef FN
119137
#define FN(reason) [SKB_DROP_REASON_##reason] = #reason,
120138
static const char * const drop_reasons[] = {
@@ -845,17 +863,17 @@ struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
845863
}
846864
EXPORT_SYMBOL(__napi_alloc_skb);
847865

848-
void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
849-
int size, unsigned int truesize)
866+
void skb_add_rx_frag_netmem(struct sk_buff *skb, int i, netmem_ref netmem,
867+
int off, int size, unsigned int truesize)
850868
{
851869
DEBUG_NET_WARN_ON_ONCE(size > truesize);
852870

853-
skb_fill_page_desc(skb, i, page, off, size);
871+
skb_fill_netmem_desc(skb, i, netmem, off, size);
854872
skb->len += size;
855873
skb->data_len += size;
856874
skb->truesize += truesize;
857875
}
858-
EXPORT_SYMBOL(skb_add_rx_frag);
876+
EXPORT_SYMBOL(skb_add_rx_frag_netmem);
859877

860878
void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size,
861879
unsigned int truesize)
@@ -1999,10 +2017,11 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
19992017

20002018
/* skb frags point to kernel buffers */
20012019
for (i = 0; i < new_frags - 1; i++) {
2002-
__skb_fill_page_desc(skb, i, head, 0, psize);
2020+
__skb_fill_netmem_desc(skb, i, page_to_netmem(head), 0, psize);
20032021
head = (struct page *)page_private(head);
20042022
}
2005-
__skb_fill_page_desc(skb, new_frags - 1, head, 0, d_off);
2023+
__skb_fill_netmem_desc(skb, new_frags - 1, page_to_netmem(head), 0,
2024+
d_off);
20062025
skb_shinfo(skb)->nr_frags = new_frags;
20072026

20082027
release:
@@ -3740,7 +3759,8 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen)
37403759
if (plen) {
37413760
page = virt_to_head_page(from->head);
37423761
offset = from->data - (unsigned char *)page_address(page);
3743-
__skb_fill_page_desc(to, 0, page, offset, plen);
3762+
__skb_fill_netmem_desc(to, 0, page_to_netmem(page),
3763+
offset, plen);
37443764
get_page(page);
37453765
j = 1;
37463766
len -= plen;

net/kcm/kcmsock.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,8 @@ static int kcm_write_msgs(struct kcm_sock *kcm)
627627
skb = txm->frag_skb;
628628
}
629629

630-
if (WARN_ON(!skb_shinfo(skb)->nr_frags)) {
630+
if (WARN_ON(!skb_shinfo(skb)->nr_frags) ||
631+
WARN_ON_ONCE(!skb_frag_page(&skb_shinfo(skb)->frags[0]))) {
631632
ret = -EINVAL;
632633
goto out;
633634
}
@@ -637,8 +638,8 @@ static int kcm_write_msgs(struct kcm_sock *kcm)
637638
msize += skb_frag_size(&skb_shinfo(skb)->frags[i]);
638639

639640
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE,
640-
skb_shinfo(skb)->frags, skb_shinfo(skb)->nr_frags,
641-
msize);
641+
(const struct bio_vec *)skb_shinfo(skb)->frags,
642+
skb_shinfo(skb)->nr_frags, msize);
642643
iov_iter_advance(&msg.msg_iter, txm->frag_offset);
643644

644645
do {

0 commit comments

Comments
 (0)