On 27/05/2026 09.02, Christoph Hellwig wrote:
The kmem_cache_alloc_bulk return value is weird.  It returns the number
of allocated objects, but that must always be 0 or the requested number
based on the implementations and the handling in the callers, but that
assumption is not actually documented anywhere, which confuses automated
review tools.


I remember, this API behavior was requested by AKPM when I developed
kmem_cache_alloc_bulk.  I trusted AKPM's decision, but I cannot explain
why this choice was made.

I kept the netdev code usage below. The current napi_skb_cache_get_bulk
have a retry logic that assumes that a partial bulk number can be
returned (which it cannot as Hellwig explains).  Cc Alex/Olek please
review the changes below as you added this retry logic.


Fix this by returning a bool if the allocation succeeded and adding a
kerneldoc comment explaining the API.

Signed-off-by: Christoph Hellwig <[email protected]>
---
  drivers/gpu/drm/msm/msm_iommu.c       |  6 +--
  drivers/gpu/drm/panthor/panthor_mmu.c | 12 +++---
  include/linux/slab.h                  |  6 ++-
  io_uring/io_uring.c                   | 23 +++++------
  lib/test_meminit.c                    | 19 +++++----
  mm/kasan/kasan_test_c.c               |  5 +--
  mm/kfence/kfence_test.c               |  9 +++--
  mm/slub.c                             | 58 +++++++++++++++------------
  net/bpf/test_run.c                    |  7 ++--
  net/core/skbuff.c                     | 24 ++++++-----
  tools/include/linux/slab.h            |  2 +-
  tools/testing/shared/linux.c          | 19 ++++-----
  12 files changed, 93 insertions(+), 97 deletions(-)


[...]

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 44ac121cfccb..73045b688385 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -288,11 +288,11 @@ static inline struct sk_buff *napi_skb_cache_get(bool 
alloc)
local_lock_nested_bh(&napi_alloc_cache.bh_lock);
        if (unlikely(!nc->skb_count)) {
-               if (alloc)
-                       nc->skb_count = 
kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
-                                               GFP_ATOMIC | __GFP_NOWARN,
-                                               NAPI_SKB_CACHE_BULK,
-                                               nc->skb_cache);
+               if (alloc && kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
+                                                  GFP_ATOMIC | __GFP_NOWARN,
+                                                  NAPI_SKB_CACHE_BULK,
+                                                  nc->skb_cache))
+                       nc->skb_count = NAPI_SKB_CACHE_BULK;
                if (unlikely(!nc->skb_count)) {
                        local_unlock_nested_bh(&napi_alloc_cache.bh_lock);
                        return NULL;
@@ -353,16 +353,18 @@ u32 napi_skb_cache_get_bulk(void **skbs, u32 n)
/* No enough cached skbs. Try refilling the cache first */
        bulk = min(NAPI_SKB_CACHE_SIZE - nc->skb_count, NAPI_SKB_CACHE_BULK);
-       nc->skb_count += kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
-                                              GFP_ATOMIC | __GFP_NOWARN, bulk,
-                                              &nc->skb_cache[nc->skb_count]);
+       if (kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
+                                 GFP_ATOMIC | __GFP_NOWARN, bulk,
+                                 &nc->skb_cache[nc->skb_count]))
+               nc->skb_count += bulk;
        if (likely(nc->skb_count >= n))
                goto get;
/* Still not enough. Bulk-allocate the missing part directly, zeroed */
-       n -= kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
-                                  GFP_ATOMIC | __GFP_ZERO | __GFP_NOWARN,
-                                  n - nc->skb_count, &skbs[nc->skb_count]);
+       if (kmem_cache_alloc_bulk(net_hotdata.skbuff_cache,
+                                 GFP_ATOMIC | __GFP_ZERO | __GFP_NOWARN,
+                                 n - nc->skb_count, &skbs[nc->skb_count]))
+               n = nc->skb_count;
        if (likely(nc->skb_count >= n))
                goto get;

Reply via email to