[PATCH net-next v3 3/3] net: devmem: batch net_iov allocations into the page_pool cache
From: Stanislav Fomichev <hidden>
Date: 2026-09-17 18:11:21
Also in:
lkml
Subsystem:
networking [general], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Rename net_devmem_alloc_dmabuf() into net_devmem_alloc_dmabuf_bulk() and make it refill page pool with up to PP_ALLOC_CACHE_REFILL NIOVs, similar to io_pp_zc_alloc_netmems(). That should amortize recently introduced freelist_lock. Reviewed-by: Mina Almasry <redacted> Signed-off-by: Stanislav Fomichev <sdf@fomichev.me> --- net/core/devmem.c | 57 ++++++++++++++++++++++++++++++----------------- net/core/devmem.h | 8 ------- 2 files changed, 36 insertions(+), 29 deletions(-)
diff --git a/net/core/devmem.c b/net/core/devmem.c
index 7cac0dab8ea8..a9d86b5a5588 100644
--- a/net/core/devmem.c
+++ b/net/core/devmem.c@@ -59,24 +59,24 @@ void __net_devmem_dmabuf_binding_free(struct work_struct *wq) kfree(binding); } -struct net_iov * -net_devmem_alloc_dmabuf(struct net_devmem_dmabuf_binding *binding) +static unsigned int +net_devmem_alloc_dmabuf_bulk(struct net_devmem_dmabuf_binding *binding, + netmem_ref *netmems, unsigned int count) { - struct net_iov *niov; + unsigned int i; + spin_lock_bh(&binding->freelist_lock); - if (unlikely(!binding->free_count)) { - spin_unlock_bh(&binding->freelist_lock); - return NULL; + + count = min_t(size_t, count, binding->free_count); + for (i = 0; i < count; i++) { + struct net_iov *niov = binding->freelist[--binding->free_count]; + + netmems[i] = net_iov_to_netmem(niov); } - niov = binding->freelist[--binding->free_count]; spin_unlock_bh(&binding->freelist_lock); - niov->desc.pp_magic = 0; - niov->desc.pp = NULL; - atomic_long_set(&niov->desc.pp_ref_count, 0); - - return niov; + return count; } void net_devmem_free_dmabuf(struct net_iov *niov)
@@ -428,20 +428,35 @@ int mp_dmabuf_devmem_init(struct page_pool *pool) netmem_ref mp_dmabuf_devmem_alloc_netmems(struct page_pool *pool, gfp_t gfp) { struct net_devmem_dmabuf_binding *binding = pool->mp_priv; - struct net_iov *niov; - netmem_ref netmem; + netmem_ref *netmems = pool->alloc.cache; + unsigned int allocated, i; + + if (WARN_ON_ONCE(pool->alloc.count)) + return 0; - niov = net_devmem_alloc_dmabuf(binding); - if (!niov) + allocated = net_devmem_alloc_dmabuf_bulk(binding, netmems, + PP_ALLOC_CACHE_REFILL); + if (unlikely(!allocated)) return 0; - netmem = net_iov_to_netmem(niov); + for (i = 0; i < allocated; i++) { + struct net_iov *niov = netmem_to_net_iov(netmems[i]); - page_pool_set_pp_info(pool, netmem); + niov->desc.pp_magic = 0; + niov->desc.pp = NULL; + atomic_long_set(&niov->desc.pp_ref_count, 0); + + page_pool_set_pp_info(pool, netmems[i]); + + pool->pages_state_hold_cnt++; + trace_page_pool_state_hold(pool, netmems[i], + pool->pages_state_hold_cnt); + } - pool->pages_state_hold_cnt++; - trace_page_pool_state_hold(pool, netmem, pool->pages_state_hold_cnt); - return netmem; + /* Return the last one, the rest stay in the page_pool cache. */ + allocated--; + pool->alloc.count = allocated; + return netmems[allocated]; } void mp_dmabuf_devmem_destroy(struct page_pool *pool)
diff --git a/net/core/devmem.h b/net/core/devmem.h
index 6ed16b4b4687..f71d9a2bcb3d 100644
--- a/net/core/devmem.h
+++ b/net/core/devmem.h@@ -131,8 +131,6 @@ net_devmem_dmabuf_binding_put(struct net_devmem_dmabuf_binding *binding) void net_devmem_get_net_iov(struct net_iov *niov); void net_devmem_put_net_iov(struct net_iov *niov); -struct net_iov * -net_devmem_alloc_dmabuf(struct net_devmem_dmabuf_binding *binding); void net_devmem_free_dmabuf(struct net_iov *ppiov);
@@ -189,12 +187,6 @@ net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx, return -EOPNOTSUPP; } -static inline struct net_iov * -net_devmem_alloc_dmabuf(struct net_devmem_dmabuf_binding *binding) -{ - return NULL; -} - static inline void net_devmem_free_dmabuf(struct net_iov *ppiov) { }
--
2.53.0-Meta