mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
Merge tag 'slab-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab
Pull slab updates from Vlastimil Babka: - Support for "allocation tokens" (currently available in Clang 22+) for smarter partitioning of kmalloc caches based on the allocated object type, which can be enabled instead of the "random" per-caller-address-hash partitioning. It should be able to deterministically separate types containing a pointer from those that do not (Marco Elver) - Improvements and simplification of the kmem_cache_alloc_bulk() and mempool_alloc_bulk() API. This includes adaptation of callers (Christoph Hellwig) - Performance improvements and cleanups related mostly to sheaves refill (Hao Li, Shengming Hu, Vlastimil Babka) - Several fixups for the slabinfo tool (Xuewen Wang) * tag 'slab-for-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab: mm/slab: do not limit zeroing to orig_size when only red zoning is enabled mm/slub: preserve original size in _kmalloc_nolock_noprof retry path mm: simplify the mempool_alloc_bulk API mm/slab: improve kmem_cache_alloc_bulk mm/slub: detach and reattach partial slabs in batch mm/slub: introduce helpers for node partial slab state mm/slub: use empty sheaf helpers for oversized sheaves tools/mm/slabinfo: remove redundant slab->partial assignment tools/mm/slabinfo: remove dead assignment in get_obj_and_str() tools/mm/slabinfo: Fix trace disable logic inversion MAINTAINERS: add slab-related scripts and tools to SLAB ALLOCATOR mm/slub: fix typo in sheaves comment mm, slab: simplify returning slab in __refill_objects_node() mm, slab: add an optimistic __slab_try_return_freelist() slab: fix kernel-docs for mm-api slab: improve KMALLOC_PARTITION_RANDOM randomness slab: support for compiler-assisted type-based slab cache partitioning mm/slub: defer freelist construction until after bulk allocation from a new slab
This commit is contained in:
@@ -24702,6 +24702,12 @@ F: mm/mempool.c
|
||||
F: mm/slab.h
|
||||
F: mm/slab_common.c
|
||||
F: mm/slub.c
|
||||
F: scripts/gdb/linux/slab.py
|
||||
F: tools/cgroup/memcg_slabinfo.py
|
||||
F: tools/include/linux/slab.h
|
||||
F: tools/lib/slab.c
|
||||
F: tools/mm/slabinfo-gnuplot.sh
|
||||
F: tools/mm/slabinfo.c
|
||||
|
||||
SLCAN CAN NETWORK DRIVER
|
||||
M: Dario Binacchi <dario.binacchi@amarulasolutions.com>
|
||||
|
||||
5
Makefile
5
Makefile
@@ -995,6 +995,11 @@ KBUILD_CFLAGS += $(CC_AUTO_VAR_INIT_ZERO_ENABLER)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef CONFIG_KMALLOC_PARTITION_TYPED
|
||||
# KMALLOC_PARTITION_CACHES_NR + 1
|
||||
KBUILD_CFLAGS += -falloc-token-max=16
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_IS_CLANG
|
||||
ifdef CONFIG_CC_HAS_COUNTED_BY_PTR
|
||||
KBUILD_CFLAGS += -fexperimental-late-parse-attributes
|
||||
|
||||
@@ -199,8 +199,8 @@ static struct bio *blk_crypto_alloc_enc_bio(struct bio *bio_src,
|
||||
pages += nr_segs * (PAGE_PTRS_PER_BVEC - 1);
|
||||
|
||||
/*
|
||||
* Try a bulk allocation first. This could leave random pages in the
|
||||
* array unallocated, but we'll fix that up later in mempool_alloc_bulk.
|
||||
* Try a bulk allocation first. This might not fill all allocated
|
||||
* pages, but we'll fix that up later in mempool_alloc_bulk.
|
||||
*
|
||||
* Note: alloc_pages_bulk needs the array to be zeroed, as it assumes
|
||||
* any non-zero slot already contains a valid allocation.
|
||||
@@ -208,8 +208,9 @@ static struct bio *blk_crypto_alloc_enc_bio(struct bio *bio_src,
|
||||
memset(pages, 0, sizeof(struct page *) * nr_segs);
|
||||
nr_allocated = alloc_pages_bulk(GFP_KERNEL, nr_segs, pages);
|
||||
if (nr_allocated < nr_segs)
|
||||
mempool_alloc_bulk(blk_crypto_bounce_page_pool, (void **)pages,
|
||||
nr_segs, nr_allocated);
|
||||
mempool_alloc_bulk(blk_crypto_bounce_page_pool,
|
||||
(void **)pages + nr_allocated,
|
||||
nr_segs - nr_allocated);
|
||||
memalloc_noio_restore(memflags);
|
||||
*pages_ret = pages;
|
||||
return bio;
|
||||
|
||||
@@ -330,17 +330,20 @@ static int
|
||||
msm_iommu_pagetable_prealloc_allocate(struct msm_mmu *mmu, struct msm_mmu_prealloc *p)
|
||||
{
|
||||
struct kmem_cache *pt_cache = get_pt_cache(mmu);
|
||||
int ret;
|
||||
|
||||
if (!p->count) {
|
||||
p->pages = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->pages = kvmalloc_objs(*p->pages, p->count);
|
||||
if (!p->pages)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, p->count, p->pages);
|
||||
if (ret != p->count) {
|
||||
kfree(p->pages);
|
||||
if (!kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, p->count, p->pages)) {
|
||||
kvfree(p->pages);
|
||||
p->pages = NULL;
|
||||
p->count = ret;
|
||||
p->count = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
@@ -1274,13 +1274,13 @@ static int panthor_vm_prepare_map_op_ctx(struct panthor_vm_op_ctx *op_ctx,
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count,
|
||||
op_ctx->rsvd_page_tables.pages);
|
||||
op_ctx->rsvd_page_tables.count = ret;
|
||||
if (ret != pt_count) {
|
||||
if (!kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count,
|
||||
op_ctx->rsvd_page_tables.pages)) {
|
||||
op_ctx->rsvd_page_tables.count = 0;
|
||||
ret = -ENOMEM;
|
||||
goto err_cleanup;
|
||||
}
|
||||
op_ctx->rsvd_page_tables.count = pt_count;
|
||||
|
||||
/* Insert BO into the extobj list last, when we know nothing can fail. */
|
||||
dma_resv_lock(panthor_vm_resv(vm), NULL);
|
||||
@@ -1328,9 +1328,8 @@ static int panthor_vm_prepare_unmap_op_ctx(struct panthor_vm_op_ctx *op_ctx,
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
ret = kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count,
|
||||
op_ctx->rsvd_page_tables.pages);
|
||||
if (ret != pt_count) {
|
||||
if (!kmem_cache_alloc_bulk(pt_cache, GFP_KERNEL, pt_count,
|
||||
op_ctx->rsvd_page_tables.pages)) {
|
||||
ret = -ENOMEM;
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,30 @@
|
||||
|
||||
#ifndef _THIS_IP_
|
||||
#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
|
||||
/*
|
||||
* The current generic definition of _THIS_IP_ is considered broken by GCC [1]
|
||||
* and Clang [2]. In particular, the address of a label is only expected to be
|
||||
* used with a computed goto.
|
||||
*
|
||||
* [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120071
|
||||
* [2] https://github.com/llvm/llvm-project/issues/138272
|
||||
*
|
||||
* Mark it as broken, so that appropriate fallback options can be implemented
|
||||
* for architectures that do not define their own _THIS_IP_.
|
||||
*/
|
||||
#define HAS_BROKEN_THIS_IP
|
||||
#endif
|
||||
|
||||
/*
|
||||
* _CODE_LOCATION_ provides a unique identifier for the current code location.
|
||||
* When _THIS_IP_ is broken (generic version), we fall back to a static marker
|
||||
* which guarantees uniqueness and resolves to a constant address at link time,
|
||||
* avoiding runtime overhead and compiler optimizations breaking it.
|
||||
*/
|
||||
#ifdef HAS_BROKEN_THIS_IP
|
||||
#define _CODE_LOCATION_ ({ static const char __here; (unsigned long)&__here; })
|
||||
#else
|
||||
#define _CODE_LOCATION_ _THIS_IP_
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_INSTRUCTION_POINTER_H */
|
||||
|
||||
@@ -66,7 +66,7 @@ void *mempool_alloc_noprof(struct mempool *pool, gfp_t gfp_mask) __malloc;
|
||||
#define mempool_alloc(...) \
|
||||
alloc_hooks(mempool_alloc_noprof(__VA_ARGS__))
|
||||
int mempool_alloc_bulk_noprof(struct mempool *pool, void **elem,
|
||||
unsigned int count, unsigned int allocated);
|
||||
unsigned int count);
|
||||
#define mempool_alloc_bulk(...) \
|
||||
alloc_hooks(mempool_alloc_bulk_noprof(__VA_ARGS__))
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#define PCPU_BITMAP_BLOCK_BITS (PCPU_BITMAP_BLOCK_SIZE >> \
|
||||
PCPU_MIN_ALLOC_SHIFT)
|
||||
|
||||
#ifdef CONFIG_RANDOM_KMALLOC_CACHES
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_CACHES
|
||||
# if defined(CONFIG_LOCKDEP) && !defined(CONFIG_PAGE_SIZE_4KB)
|
||||
# define PERCPU_DYNAMIC_SIZE_SHIFT 13
|
||||
# else
|
||||
|
||||
@@ -499,14 +499,80 @@ int kmem_cache_shrink(struct kmem_cache *s);
|
||||
.usersize = sizeof_field(struct __struct, __field), \
|
||||
}, (__flags))
|
||||
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_CACHES
|
||||
typedef struct { unsigned long v; } kmalloc_token_t;
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_RANDOM
|
||||
extern unsigned long random_kmalloc_seed;
|
||||
#define __kmalloc_token(...) ((kmalloc_token_t){ .v = _CODE_LOCATION_ })
|
||||
#elif defined(CONFIG_KMALLOC_PARTITION_TYPED)
|
||||
#define __kmalloc_token(...) ((kmalloc_token_t){ .v = __builtin_infer_alloc_token(__VA_ARGS__) })
|
||||
#endif
|
||||
#define DECL_TOKEN_PARAM(_token) , kmalloc_token_t (_token)
|
||||
#define _PASS_TOKEN_PARAM(_token) , (_token)
|
||||
#define PASS_TOKEN_PARAM(_token) (_token)
|
||||
#define DECL_TOKEN_PARAMS(_size, _token) size_t (_size), kmalloc_token_t (_token)
|
||||
#define PASS_TOKEN_PARAMS(_size, _token) (_size), (_token)
|
||||
#else /* !CONFIG_KMALLOC_PARTITION_CACHES */
|
||||
typedef struct {} kmalloc_token_t;
|
||||
#define __kmalloc_token(...) ((kmalloc_token_t){}) /* no-op */
|
||||
#define DECL_TOKEN_PARAM(_token)
|
||||
#define _PASS_TOKEN_PARAM(_token)
|
||||
#define PASS_TOKEN_PARAM(_token) ((kmalloc_token_t){})
|
||||
#define DECL_TOKEN_PARAMS(_size, _token) size_t (_size)
|
||||
#define PASS_TOKEN_PARAMS(_size, _token) (_size)
|
||||
#endif /* CONFIG_KMALLOC_PARTITION_CACHES */
|
||||
|
||||
/*
|
||||
* Common kmalloc functions provided by all allocators
|
||||
*/
|
||||
void * __must_check krealloc_node_align_noprof(const void *objp, size_t new_size,
|
||||
void * __must_check krealloc_node_align_noprof(const void *objp,
|
||||
DECL_TOKEN_PARAMS(new_size, token),
|
||||
unsigned long align,
|
||||
gfp_t flags, int nid) __realloc_size(2);
|
||||
#define krealloc_noprof(_o, _s, _f) krealloc_node_align_noprof(_o, _s, 1, _f, NUMA_NO_NODE)
|
||||
#define krealloc_node_align(...) alloc_hooks(krealloc_node_align_noprof(__VA_ARGS__))
|
||||
#define krealloc_noprof(_o, _s, _f) krealloc_node_align_noprof(_o, PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), 1, _f, NUMA_NO_NODE)
|
||||
#if 0 /* kernel-doc */
|
||||
/**
|
||||
* krealloc_node_align - reallocate memory. The contents will remain unchanged.
|
||||
* @p: object to reallocate memory for.
|
||||
* @new_size: how many bytes of memory are required.
|
||||
* @align: desired alignment.
|
||||
* @flags: the type of memory to allocate.
|
||||
* @nid: NUMA node or NUMA_NO_NODE
|
||||
*
|
||||
* If @p is %NULL, krealloc() behaves exactly like kmalloc(). If @new_size
|
||||
* is 0 and @p is not a %NULL pointer, the object pointed to is freed.
|
||||
*
|
||||
* Only alignments up to those guaranteed by kmalloc() will be honored. Please see
|
||||
* Documentation/core-api/memory-allocation.rst for more details.
|
||||
*
|
||||
* If __GFP_ZERO logic is requested, callers must ensure that, starting with the
|
||||
* initial memory allocation, every subsequent call to this API for the same
|
||||
* memory allocation is flagged with __GFP_ZERO. Otherwise, it is possible that
|
||||
* __GFP_ZERO is not fully honored by this API.
|
||||
*
|
||||
* When slub_debug_orig_size() is off, krealloc() only knows about the bucket
|
||||
* size of an allocation (but not the exact size it was allocated with) and
|
||||
* hence implements the following semantics for shrinking and growing buffers
|
||||
* with __GFP_ZERO::
|
||||
*
|
||||
* new bucket
|
||||
* 0 size size
|
||||
* |--------|----------------|
|
||||
* | keep | zero |
|
||||
*
|
||||
* Otherwise, the original allocation size 'orig_size' could be used to
|
||||
* precisely clear the requested size, and the new size will also be stored
|
||||
* as the new 'orig_size'.
|
||||
*
|
||||
* In any case, the contents of the object pointed to are preserved up to the
|
||||
* lesser of the new and old sizes.
|
||||
*
|
||||
* Return: pointer to the allocated memory or %NULL in case of error
|
||||
*/
|
||||
void *krealloc_node_align(const void *p, size_t new_size, unsigned long align, gfp_t flags, int nid);
|
||||
#endif
|
||||
#define krealloc_node_align(p, new_size, align, flags, nid) \
|
||||
alloc_hooks(krealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(new_size, __kmalloc_token(new_size)), align, flags, nid))
|
||||
#define krealloc_node(_o, _s, _f, _n) krealloc_node_align(_o, _s, 1, _f, _n)
|
||||
#define krealloc(...) krealloc_node(__VA_ARGS__, NUMA_NO_NODE)
|
||||
|
||||
@@ -612,10 +678,10 @@ static inline unsigned int arch_slab_minalign(void)
|
||||
#define SLAB_OBJ_MIN_SIZE (KMALLOC_MIN_SIZE < 16 ? \
|
||||
(KMALLOC_MIN_SIZE) : 16)
|
||||
|
||||
#ifdef CONFIG_RANDOM_KMALLOC_CACHES
|
||||
#define RANDOM_KMALLOC_CACHES_NR 15 // # of cache copies
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_CACHES
|
||||
#define KMALLOC_PARTITION_CACHES_NR 15 // # of cache copies
|
||||
#else
|
||||
#define RANDOM_KMALLOC_CACHES_NR 0
|
||||
#define KMALLOC_PARTITION_CACHES_NR 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -634,8 +700,8 @@ enum kmalloc_cache_type {
|
||||
#ifndef CONFIG_MEMCG
|
||||
KMALLOC_CGROUP = KMALLOC_NORMAL,
|
||||
#endif
|
||||
KMALLOC_RANDOM_START = KMALLOC_NORMAL,
|
||||
KMALLOC_RANDOM_END = KMALLOC_RANDOM_START + RANDOM_KMALLOC_CACHES_NR,
|
||||
KMALLOC_PARTITION_START = KMALLOC_NORMAL,
|
||||
KMALLOC_PARTITION_END = KMALLOC_PARTITION_START + KMALLOC_PARTITION_CACHES_NR,
|
||||
#ifdef CONFIG_SLUB_TINY
|
||||
KMALLOC_RECLAIM = KMALLOC_NORMAL,
|
||||
#else
|
||||
@@ -662,19 +728,19 @@ extern kmem_buckets kmalloc_caches[NR_KMALLOC_TYPES];
|
||||
(IS_ENABLED(CONFIG_ZONE_DMA) ? __GFP_DMA : 0) | \
|
||||
(IS_ENABLED(CONFIG_MEMCG) ? __GFP_ACCOUNT : 0))
|
||||
|
||||
extern unsigned long random_kmalloc_seed;
|
||||
|
||||
static __always_inline enum kmalloc_cache_type kmalloc_type(gfp_t flags, unsigned long caller)
|
||||
static __always_inline enum kmalloc_cache_type kmalloc_type(gfp_t flags, kmalloc_token_t token)
|
||||
{
|
||||
/*
|
||||
* The most common case is KMALLOC_NORMAL, so test for it
|
||||
* with a single branch for all the relevant flags.
|
||||
*/
|
||||
if (likely((flags & KMALLOC_NOT_NORMAL_BITS) == 0))
|
||||
#ifdef CONFIG_RANDOM_KMALLOC_CACHES
|
||||
/* RANDOM_KMALLOC_CACHES_NR (=15) copies + the KMALLOC_NORMAL */
|
||||
return KMALLOC_RANDOM_START + hash_64(caller ^ random_kmalloc_seed,
|
||||
ilog2(RANDOM_KMALLOC_CACHES_NR + 1));
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_RANDOM
|
||||
/* KMALLOC_PARTITION_CACHES_NR (=15) copies + the KMALLOC_NORMAL */
|
||||
return KMALLOC_PARTITION_START + hash_64(token.v ^ random_kmalloc_seed,
|
||||
ilog2(KMALLOC_PARTITION_CACHES_NR + 1));
|
||||
#elif defined(CONFIG_KMALLOC_PARTITION_TYPED)
|
||||
return KMALLOC_PARTITION_START + token.v;
|
||||
#else
|
||||
return KMALLOC_NORMAL;
|
||||
#endif
|
||||
@@ -815,8 +881,10 @@ kmem_buckets *kmem_buckets_create(const char *name, slab_flags_t flags,
|
||||
*/
|
||||
void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p);
|
||||
|
||||
int kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags, size_t size, void **p);
|
||||
#define kmem_cache_alloc_bulk(...) alloc_hooks(kmem_cache_alloc_bulk_noprof(__VA_ARGS__))
|
||||
bool kmem_cache_alloc_bulk_noprof(struct kmem_cache *s, gfp_t flags,
|
||||
size_t size, void **p);
|
||||
#define kmem_cache_alloc_bulk(...) \
|
||||
alloc_hooks(kmem_cache_alloc_bulk_noprof(__VA_ARGS__))
|
||||
|
||||
static __always_inline void kfree_bulk(size_t size, void **p)
|
||||
{
|
||||
@@ -858,16 +926,22 @@ unsigned int kmem_cache_sheaf_size(struct slab_sheaf *sheaf);
|
||||
#define PASS_BUCKET_PARAM(_b) NULL
|
||||
#endif
|
||||
|
||||
#define DECL_KMALLOC_PARAMS(_size, _b, _token) DECL_BUCKET_PARAMS(_size, _b) \
|
||||
DECL_TOKEN_PARAM(_token)
|
||||
|
||||
#define PASS_KMALLOC_PARAMS(_size, _b, _token) PASS_BUCKET_PARAMS(_size, _b) \
|
||||
_PASS_TOKEN_PARAM(_token)
|
||||
|
||||
/*
|
||||
* The following functions are not to be used directly and are intended only
|
||||
* for internal use from kmalloc() and kmalloc_node()
|
||||
* with the exception of kunit tests
|
||||
*/
|
||||
|
||||
void *__kmalloc_noprof(size_t size, gfp_t flags)
|
||||
void *__kmalloc_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t flags)
|
||||
__assume_kmalloc_alignment __alloc_size(1);
|
||||
|
||||
void *__kmalloc_node_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flags, int node)
|
||||
void *__kmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), gfp_t flags, int node)
|
||||
__assume_kmalloc_alignment __alloc_size(1);
|
||||
|
||||
void *__kmalloc_cache_noprof(struct kmem_cache *s, gfp_t flags, size_t size)
|
||||
@@ -883,6 +957,23 @@ void *__kmalloc_large_noprof(size_t size, gfp_t flags)
|
||||
void *__kmalloc_large_node_noprof(size_t size, gfp_t flags, int node)
|
||||
__assume_page_alignment __alloc_size(1);
|
||||
|
||||
static __always_inline __alloc_size(1) void *_kmalloc_noprof(size_t size, gfp_t flags, kmalloc_token_t token)
|
||||
{
|
||||
if (__builtin_constant_p(size) && size) {
|
||||
unsigned int index;
|
||||
|
||||
if (size > KMALLOC_MAX_CACHE_SIZE)
|
||||
return __kmalloc_large_noprof(size, flags);
|
||||
|
||||
index = kmalloc_index(size);
|
||||
return __kmalloc_cache_noprof(
|
||||
kmalloc_caches[kmalloc_type(flags, token)][index],
|
||||
flags, size);
|
||||
}
|
||||
return __kmalloc_noprof(PASS_TOKEN_PARAMS(size, token), flags);
|
||||
}
|
||||
#define kmalloc_noprof(...) _kmalloc_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
|
||||
#if 0 /* kernel-doc */
|
||||
/**
|
||||
* kmalloc - allocate kernel memory
|
||||
* @size: how many bytes of memory are required.
|
||||
@@ -938,25 +1029,27 @@ void *__kmalloc_large_node_noprof(size_t size, gfp_t flags, int node)
|
||||
* Try really hard to succeed the allocation but fail
|
||||
* eventually.
|
||||
*/
|
||||
static __always_inline __alloc_size(1) void *kmalloc_noprof(size_t size, gfp_t flags)
|
||||
{
|
||||
if (__builtin_constant_p(size) && size) {
|
||||
unsigned int index;
|
||||
void *kmalloc(size_t size, gfp_t flags);
|
||||
#endif
|
||||
#define kmalloc(size, flags) alloc_hooks(kmalloc_noprof(size, flags))
|
||||
|
||||
if (size > KMALLOC_MAX_CACHE_SIZE)
|
||||
return __kmalloc_large_noprof(size, flags);
|
||||
|
||||
index = kmalloc_index(size);
|
||||
return __kmalloc_cache_noprof(
|
||||
kmalloc_caches[kmalloc_type(flags, _RET_IP_)][index],
|
||||
flags, size);
|
||||
}
|
||||
return __kmalloc_noprof(size, flags);
|
||||
}
|
||||
#define kmalloc(...) alloc_hooks(kmalloc_noprof(__VA_ARGS__))
|
||||
|
||||
void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node);
|
||||
#define kmalloc_nolock(...) alloc_hooks(kmalloc_nolock_noprof(__VA_ARGS__))
|
||||
void *_kmalloc_nolock_noprof(DECL_TOKEN_PARAMS(size, token), gfp_t gfp_flags, int node);
|
||||
#define kmalloc_nolock_noprof(_s, _f, _n) _kmalloc_nolock_noprof(PASS_TOKEN_PARAMS(_s, __kmalloc_token(_s)), _f, _n)
|
||||
#if 0 /* kernel-doc */
|
||||
/**
|
||||
* kmalloc_nolock - Allocate an object of given size from any context.
|
||||
* @size: size to allocate
|
||||
* @gfp_flags: GFP flags. Only __GFP_ACCOUNT, __GFP_ZERO, __GFP_NO_OBJ_EXT
|
||||
* allowed.
|
||||
* @node: node number of the target node.
|
||||
*
|
||||
* Return: pointer to the new object or NULL in case of error.
|
||||
* NULL does not mean EBUSY or EAGAIN. It means ENOMEM.
|
||||
* There is no reason to call it again and expect !NULL.
|
||||
*/
|
||||
void *kmalloc_nolock(size_t size, gfp_t gfp_flags, int node);
|
||||
#endif
|
||||
#define kmalloc_nolock(size, gfp_flags, node) alloc_hooks(kmalloc_nolock_noprof(size, gfp_flags, node))
|
||||
|
||||
/**
|
||||
* __alloc_objs - Allocate objects of a given type using
|
||||
@@ -1060,12 +1153,12 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node);
|
||||
__alloc_flex(kvzalloc, default_gfp(__VA_ARGS__), typeof(P), FAM, COUNT)
|
||||
|
||||
#define kmem_buckets_alloc(_b, _size, _flags) \
|
||||
alloc_hooks(__kmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE))
|
||||
alloc_hooks(__kmalloc_node_noprof(PASS_KMALLOC_PARAMS(_size, _b, __kmalloc_token(_size)), _flags, NUMA_NO_NODE))
|
||||
|
||||
#define kmem_buckets_alloc_track_caller(_b, _size, _flags) \
|
||||
alloc_hooks(__kmalloc_node_track_caller_noprof(PASS_BUCKET_PARAMS(_size, _b), _flags, NUMA_NO_NODE, _RET_IP_))
|
||||
alloc_hooks(__kmalloc_node_track_caller_noprof(PASS_KMALLOC_PARAMS(_size, _b, __kmalloc_token(_size)), _flags, NUMA_NO_NODE, _RET_IP_))
|
||||
|
||||
static __always_inline __alloc_size(1) void *kmalloc_node_noprof(size_t size, gfp_t flags, int node)
|
||||
static __always_inline __alloc_size(1) void *_kmalloc_node_noprof(size_t size, gfp_t flags, int node, kmalloc_token_t token)
|
||||
{
|
||||
if (__builtin_constant_p(size) && size) {
|
||||
unsigned int index;
|
||||
@@ -1075,29 +1168,48 @@ static __always_inline __alloc_size(1) void *kmalloc_node_noprof(size_t size, gf
|
||||
|
||||
index = kmalloc_index(size);
|
||||
return __kmalloc_cache_node_noprof(
|
||||
kmalloc_caches[kmalloc_type(flags, _RET_IP_)][index],
|
||||
kmalloc_caches[kmalloc_type(flags, token)][index],
|
||||
flags, node, size);
|
||||
}
|
||||
return __kmalloc_node_noprof(PASS_BUCKET_PARAMS(size, NULL), flags, node);
|
||||
return __kmalloc_node_noprof(PASS_KMALLOC_PARAMS(size, NULL, token), flags, node);
|
||||
}
|
||||
#define kmalloc_node_noprof(...) _kmalloc_node_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
|
||||
#define kmalloc_node(...) alloc_hooks(kmalloc_node_noprof(__VA_ARGS__))
|
||||
|
||||
static inline __alloc_size(1, 2) void *_kmalloc_array_noprof(size_t n, size_t size, gfp_t flags, kmalloc_token_t token)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (unlikely(check_mul_overflow(n, size, &bytes)))
|
||||
return NULL;
|
||||
return _kmalloc_noprof(bytes, flags, token);
|
||||
}
|
||||
#define kmalloc_array_noprof(...) _kmalloc_array_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
|
||||
#if 0 /* kernel-doc */
|
||||
/**
|
||||
* kmalloc_array - allocate memory for an array.
|
||||
* @n: number of elements.
|
||||
* @size: element size.
|
||||
* @flags: the type of memory to allocate (see kmalloc).
|
||||
*/
|
||||
static inline __alloc_size(1, 2) void *kmalloc_array_noprof(size_t n, size_t size, gfp_t flags)
|
||||
void *kmalloc_array(size_t n, size_t size, gfp_t flags);
|
||||
#endif
|
||||
#define kmalloc_array(n, size, flags) alloc_hooks(kmalloc_array_noprof(n, size, flags))
|
||||
|
||||
static inline __realloc_size(2, 3) void * __must_check _krealloc_array_noprof(void *p,
|
||||
size_t new_n,
|
||||
size_t new_size,
|
||||
gfp_t flags, kmalloc_token_t token)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (unlikely(check_mul_overflow(n, size, &bytes)))
|
||||
if (unlikely(check_mul_overflow(new_n, new_size, &bytes)))
|
||||
return NULL;
|
||||
return kmalloc_noprof(bytes, flags);
|
||||
}
|
||||
#define kmalloc_array(...) alloc_hooks(kmalloc_array_noprof(__VA_ARGS__))
|
||||
|
||||
return krealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(bytes, token), 1, flags, NUMA_NO_NODE);
|
||||
}
|
||||
#define krealloc_array_noprof(...) _krealloc_array_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
|
||||
#if 0 /* kernel-doc */
|
||||
/**
|
||||
* krealloc_array - reallocate memory for an array.
|
||||
* @p: pointer to the memory chunk to reallocate
|
||||
@@ -1115,19 +1227,9 @@ static inline __alloc_size(1, 2) void *kmalloc_array_noprof(size_t n, size_t siz
|
||||
* In any case, the contents of the object pointed to are preserved up to the
|
||||
* lesser of the new and old sizes.
|
||||
*/
|
||||
static inline __realloc_size(2, 3) void * __must_check krealloc_array_noprof(void *p,
|
||||
size_t new_n,
|
||||
size_t new_size,
|
||||
gfp_t flags)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (unlikely(check_mul_overflow(new_n, new_size, &bytes)))
|
||||
return NULL;
|
||||
|
||||
return krealloc_noprof(p, bytes, flags);
|
||||
}
|
||||
#define krealloc_array(...) alloc_hooks(krealloc_array_noprof(__VA_ARGS__))
|
||||
void *krealloc_array(void *p, size_t new_n, size_t new_size, gfp_t flags);
|
||||
#endif
|
||||
#define krealloc_array(p, new_n, new_size, flags) alloc_hooks(krealloc_array_noprof(p, new_n, new_size, flags))
|
||||
|
||||
/**
|
||||
* kcalloc - allocate memory for an array. The memory is set to zero.
|
||||
@@ -1137,10 +1239,10 @@ static inline __realloc_size(2, 3) void * __must_check krealloc_array_noprof(voi
|
||||
*/
|
||||
#define kcalloc(n, size, flags) kmalloc_array(n, size, (flags) | __GFP_ZERO)
|
||||
|
||||
void *__kmalloc_node_track_caller_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flags, int node,
|
||||
void *__kmalloc_node_track_caller_noprof(DECL_KMALLOC_PARAMS(size, b, token), gfp_t flags, int node,
|
||||
unsigned long caller) __alloc_size(1);
|
||||
#define kmalloc_node_track_caller_noprof(size, flags, node, caller) \
|
||||
__kmalloc_node_track_caller_noprof(PASS_BUCKET_PARAMS(size, NULL), flags, node, caller)
|
||||
__kmalloc_node_track_caller_noprof(PASS_KMALLOC_PARAMS(size, NULL, __kmalloc_token(size)), flags, node, caller)
|
||||
#define kmalloc_node_track_caller(...) \
|
||||
alloc_hooks(kmalloc_node_track_caller_noprof(__VA_ARGS__, _RET_IP_))
|
||||
|
||||
@@ -1157,17 +1259,18 @@ void *__kmalloc_node_track_caller_noprof(DECL_BUCKET_PARAMS(size, b), gfp_t flag
|
||||
#define kmalloc_track_caller_noprof(...) \
|
||||
kmalloc_node_track_caller_noprof(__VA_ARGS__, NUMA_NO_NODE, _RET_IP_)
|
||||
|
||||
static inline __alloc_size(1, 2) void *kmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags,
|
||||
int node)
|
||||
static inline __alloc_size(1, 2) void *_kmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags,
|
||||
int node, kmalloc_token_t token)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (unlikely(check_mul_overflow(n, size, &bytes)))
|
||||
return NULL;
|
||||
if (__builtin_constant_p(n) && __builtin_constant_p(size))
|
||||
return kmalloc_node_noprof(bytes, flags, node);
|
||||
return __kmalloc_node_noprof(PASS_BUCKET_PARAMS(bytes, NULL), flags, node);
|
||||
return _kmalloc_node_noprof(bytes, flags, node, token);
|
||||
return __kmalloc_node_noprof(PASS_KMALLOC_PARAMS(bytes, NULL, token), flags, node);
|
||||
}
|
||||
#define kmalloc_array_node_noprof(...) _kmalloc_array_node_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
|
||||
#define kmalloc_array_node(...) alloc_hooks(kmalloc_array_node_noprof(__VA_ARGS__))
|
||||
|
||||
#define kcalloc_node(_n, _size, _flags, _node) \
|
||||
@@ -1178,44 +1281,73 @@ static inline __alloc_size(1, 2) void *kmalloc_array_node_noprof(size_t n, size_
|
||||
*/
|
||||
#define kmem_cache_zalloc(_k, _flags) kmem_cache_alloc(_k, (_flags)|__GFP_ZERO)
|
||||
|
||||
static inline __alloc_size(1) void *_kzalloc_noprof(size_t size, gfp_t flags, kmalloc_token_t token)
|
||||
{
|
||||
return _kmalloc_noprof(size, flags | __GFP_ZERO, token);
|
||||
}
|
||||
#define kzalloc_noprof(...) _kzalloc_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
|
||||
#if 0 /* kernel-doc */
|
||||
/**
|
||||
* kzalloc - allocate memory. The memory is set to zero.
|
||||
* @size: how many bytes of memory are required.
|
||||
* @flags: the type of memory to allocate (see kmalloc).
|
||||
*/
|
||||
static inline __alloc_size(1) void *kzalloc_noprof(size_t size, gfp_t flags)
|
||||
{
|
||||
return kmalloc_noprof(size, flags | __GFP_ZERO);
|
||||
}
|
||||
#define kzalloc(...) alloc_hooks(kzalloc_noprof(__VA_ARGS__))
|
||||
void *kzalloc(size_t size, gfp_t flags);
|
||||
#endif
|
||||
#define kzalloc(size, flags) alloc_hooks(kzalloc_noprof(size, flags))
|
||||
#define kzalloc_node(_size, _flags, _node) kmalloc_node(_size, (_flags)|__GFP_ZERO, _node)
|
||||
|
||||
void *__kvmalloc_node_noprof(DECL_BUCKET_PARAMS(size, b), unsigned long align,
|
||||
void *__kvmalloc_node_noprof(DECL_KMALLOC_PARAMS(size, b, token), unsigned long align,
|
||||
gfp_t flags, int node) __alloc_size(1);
|
||||
#define kvmalloc_node_align_noprof(_size, _align, _flags, _node) \
|
||||
__kvmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, NULL), _align, _flags, _node)
|
||||
__kvmalloc_node_noprof(PASS_KMALLOC_PARAMS(_size, NULL, __kmalloc_token(_size)), _align, _flags, _node)
|
||||
#define kvmalloc_node_align(...) \
|
||||
alloc_hooks(kvmalloc_node_align_noprof(__VA_ARGS__))
|
||||
#define kvmalloc_node(_s, _f, _n) kvmalloc_node_align(_s, 1, _f, _n)
|
||||
#if 0 /* kernel-doc */
|
||||
/**
|
||||
* kvmalloc_node - attempt to allocate physically contiguous memory, but upon
|
||||
* failure, fall back to non-contiguous (vmalloc) allocation.
|
||||
* @size: size of the request.
|
||||
* @flags: gfp mask for the allocation - must be compatible (superset) with GFP_KERNEL.
|
||||
* @node: numa node to allocate from
|
||||
*
|
||||
* Only alignments up to those guaranteed by kmalloc() will be honored. Please see
|
||||
* Documentation/core-api/memory-allocation.rst for more details.
|
||||
*
|
||||
* Uses kmalloc to get the memory but if the allocation fails then falls back
|
||||
* to the vmalloc allocator. Use kvfree for freeing the memory.
|
||||
*
|
||||
* GFP_NOWAIT and GFP_ATOMIC are supported, the __GFP_NORETRY modifier is not.
|
||||
* __GFP_RETRY_MAYFAIL is supported, and it should be used only if kmalloc is
|
||||
* preferable to the vmalloc fallback, due to visible performance drawbacks.
|
||||
*
|
||||
* Return: pointer to the allocated memory of %NULL in case of failure
|
||||
*/
|
||||
void *kvmalloc_node(size_t size, gfp_t flags, int node);
|
||||
#endif
|
||||
#define kvmalloc_node(size, flags, node) kvmalloc_node_align(size, 1, flags, node)
|
||||
#define kvmalloc_node_noprof(size, flags, node) \
|
||||
kvmalloc_node_align_noprof(size, 1, flags, node)
|
||||
#define kvmalloc(...) kvmalloc_node(__VA_ARGS__, NUMA_NO_NODE)
|
||||
#define kvmalloc_noprof(_size, _flags) kvmalloc_node_noprof(_size, _flags, NUMA_NO_NODE)
|
||||
#define kvzalloc(_size, _flags) kvmalloc(_size, (_flags)|__GFP_ZERO)
|
||||
|
||||
#define kvzalloc_node(_size, _flags, _node) kvmalloc_node(_size, (_flags)|__GFP_ZERO, _node)
|
||||
|
||||
#define kmem_buckets_valloc(_b, _size, _flags) \
|
||||
alloc_hooks(__kvmalloc_node_noprof(PASS_BUCKET_PARAMS(_size, _b), 1, _flags, NUMA_NO_NODE))
|
||||
alloc_hooks(__kvmalloc_node_noprof(PASS_KMALLOC_PARAMS(_size, _b, __kmalloc_token(_size)), 1, _flags, NUMA_NO_NODE))
|
||||
|
||||
static inline __alloc_size(1, 2) void *
|
||||
kvmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, int node)
|
||||
_kvmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, int node, kmalloc_token_t token)
|
||||
{
|
||||
size_t bytes;
|
||||
|
||||
if (unlikely(check_mul_overflow(n, size, &bytes)))
|
||||
return NULL;
|
||||
|
||||
return kvmalloc_node_align_noprof(bytes, 1, flags, node);
|
||||
return __kvmalloc_node_noprof(PASS_KMALLOC_PARAMS(bytes, NULL, token), 1, flags, node);
|
||||
}
|
||||
|
||||
#define kvmalloc_array_node_noprof(...) _kvmalloc_array_node_noprof(__VA_ARGS__, __kmalloc_token(__VA_ARGS__))
|
||||
#define kvmalloc_array_noprof(...) kvmalloc_array_node_noprof(__VA_ARGS__, NUMA_NO_NODE)
|
||||
#define kvcalloc_node_noprof(_n,_s,_f,_node) kvmalloc_array_node_noprof(_n,_s,(_f)|__GFP_ZERO,_node)
|
||||
#define kvcalloc_noprof(...) kvcalloc_node_noprof(__VA_ARGS__, NUMA_NO_NODE)
|
||||
@@ -1224,10 +1356,40 @@ kvmalloc_array_node_noprof(size_t n, size_t size, gfp_t flags, int node)
|
||||
#define kvcalloc_node(...) alloc_hooks(kvcalloc_node_noprof(__VA_ARGS__))
|
||||
#define kvcalloc(...) alloc_hooks(kvcalloc_noprof(__VA_ARGS__))
|
||||
|
||||
void *kvrealloc_node_align_noprof(const void *p, size_t size, unsigned long align,
|
||||
void *kvrealloc_node_align_noprof(const void *p, DECL_TOKEN_PARAMS(size, token), unsigned long align,
|
||||
gfp_t flags, int nid) __realloc_size(2);
|
||||
#define kvrealloc_node_align(...) \
|
||||
alloc_hooks(kvrealloc_node_align_noprof(__VA_ARGS__))
|
||||
#if 0 /* kernel-doc */
|
||||
/**
|
||||
* kvrealloc_node_align - reallocate memory; contents remain unchanged
|
||||
* @p: object to reallocate memory for
|
||||
* @size: the size to reallocate
|
||||
* @align: desired alignment
|
||||
* @flags: the flags for the page level allocator
|
||||
* @nid: NUMA node id
|
||||
*
|
||||
* If @p is %NULL, kvrealloc() behaves exactly like kvmalloc(). If @size is 0
|
||||
* and @p is not a %NULL pointer, the object pointed to is freed.
|
||||
*
|
||||
* Only alignments up to those guaranteed by kmalloc() will be honored. Please see
|
||||
* Documentation/core-api/memory-allocation.rst for more details.
|
||||
*
|
||||
* If __GFP_ZERO logic is requested, callers must ensure that, starting with the
|
||||
* initial memory allocation, every subsequent call to this API for the same
|
||||
* memory allocation is flagged with __GFP_ZERO. Otherwise, it is possible that
|
||||
* __GFP_ZERO is not fully honored by this API.
|
||||
*
|
||||
* In any case, the contents of the object pointed to are preserved up to the
|
||||
* lesser of the new and old sizes.
|
||||
*
|
||||
* This function must not be called concurrently with itself or kvfree() for the
|
||||
* same memory allocation.
|
||||
*
|
||||
* Return: pointer to the allocated memory or %NULL in case of error
|
||||
*/
|
||||
void *kvrealloc_node_align(const void *p, size_t size, unsigned long align, gfp_t flags, int nid);
|
||||
#endif
|
||||
#define kvrealloc_node_align(p, size, align, flags, nid) \
|
||||
alloc_hooks(kvrealloc_node_align_noprof(p, PASS_TOKEN_PARAMS(size, __kmalloc_token(size)), align, flags, nid))
|
||||
#define kvrealloc_node(_p, _s, _f, _n) kvrealloc_node_align(_p, _s, 1, _f, _n)
|
||||
#define kvrealloc(...) kvrealloc_node(__VA_ARGS__, NUMA_NO_NODE)
|
||||
|
||||
|
||||
@@ -167,6 +167,9 @@ config CC_HAS_BROKEN_COUNTED_BY_REF
|
||||
# https://github.com/llvm/llvm-project/issues/182575
|
||||
default y if CC_IS_CLANG && CLANG_VERSION < 220100
|
||||
|
||||
config CC_HAS_ALLOC_TOKEN
|
||||
def_bool $(cc-option,-falloc-token-max=123)
|
||||
|
||||
config CC_HAS_MULTIDIMENSIONAL_NONSTRING
|
||||
def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror)
|
||||
|
||||
|
||||
@@ -978,29 +978,24 @@ __cold bool __io_alloc_req_refill(struct io_ring_ctx *ctx)
|
||||
{
|
||||
gfp_t gfp = GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO;
|
||||
void *reqs[IO_REQ_ALLOC_BATCH];
|
||||
int ret;
|
||||
|
||||
ret = kmem_cache_alloc_bulk(req_cachep, gfp, ARRAY_SIZE(reqs), reqs);
|
||||
int nr_reqs = ARRAY_SIZE(reqs);
|
||||
|
||||
/*
|
||||
* Bulk alloc is all-or-nothing. If we fail to get a batch,
|
||||
* retry single alloc to be on the safe side.
|
||||
* Bulk alloc is all-or-nothing. If we fail to get a batch, retry a
|
||||
* single allocation to be on the safe side.
|
||||
*/
|
||||
if (unlikely(ret <= 0)) {
|
||||
if (!kmem_cache_alloc_bulk(req_cachep, gfp, nr_reqs, reqs)) {
|
||||
reqs[0] = kmem_cache_alloc(req_cachep, gfp);
|
||||
if (!reqs[0])
|
||||
return false;
|
||||
ret = 1;
|
||||
nr_reqs = 1;
|
||||
}
|
||||
|
||||
percpu_ref_get_many(&ctx->refs, ret);
|
||||
ctx->nr_req_allocated += ret;
|
||||
percpu_ref_get_many(&ctx->refs, nr_reqs);
|
||||
ctx->nr_req_allocated += nr_reqs;
|
||||
|
||||
while (ret--) {
|
||||
struct io_kiocb *req = reqs[ret];
|
||||
|
||||
io_req_add_to_cache(req, ctx);
|
||||
}
|
||||
while (nr_reqs--)
|
||||
io_req_add_to_cache(reqs[nr_reqs], ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y
|
||||
CONFIG_SLAB_FREELIST_HARDENED=y
|
||||
CONFIG_SLAB_BUCKETS=y
|
||||
CONFIG_SHUFFLE_PAGE_ALLOCATOR=y
|
||||
CONFIG_RANDOM_KMALLOC_CACHES=y
|
||||
CONFIG_KMALLOC_PARTITION_CACHES=y
|
||||
|
||||
# Sanity check userspace page table mappings.
|
||||
CONFIG_PAGE_TABLE_CHECK=y
|
||||
|
||||
@@ -229,16 +229,14 @@ static int __init do_kmem_cache_size(size_t size, bool want_ctor,
|
||||
for (iter = 0; iter < 10; iter++) {
|
||||
/* Do a test of bulk allocations */
|
||||
if (!want_rcu && !want_ctor) {
|
||||
int ret;
|
||||
|
||||
ret = kmem_cache_alloc_bulk(c, alloc_mask, BULK_SIZE, bulk_array);
|
||||
if (!ret) {
|
||||
if (!kmem_cache_alloc_bulk(c, alloc_mask, BULK_SIZE,
|
||||
bulk_array)) {
|
||||
fail = true;
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < ret; i++)
|
||||
for (i = 0; i < BULK_SIZE; i++)
|
||||
fail |= check_buf(bulk_array[i], size, want_ctor, want_rcu, want_zero);
|
||||
kmem_cache_free_bulk(c, ret, bulk_array);
|
||||
kmem_cache_free_bulk(c, BULK_SIZE, bulk_array);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,23 +346,24 @@ static int __init do_kmem_cache_size_bulk(int size, int *total_failures)
|
||||
{
|
||||
struct kmem_cache *c;
|
||||
int i, iter, maxiter = 1024;
|
||||
int num, bytes;
|
||||
int bytes;
|
||||
bool fail = false;
|
||||
void *objects[10];
|
||||
|
||||
c = kmem_cache_create("test_cache", size, size, 0, NULL);
|
||||
for (iter = 0; (iter < maxiter) && !fail; iter++) {
|
||||
num = kmem_cache_alloc_bulk(c, GFP_KERNEL, ARRAY_SIZE(objects),
|
||||
objects);
|
||||
for (i = 0; i < num; i++) {
|
||||
if (!kmem_cache_alloc_bulk(c, GFP_KERNEL, ARRAY_SIZE(objects),
|
||||
objects))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(objects); i++) {
|
||||
bytes = count_nonzero_bytes(objects[i], size);
|
||||
if (bytes)
|
||||
fail = true;
|
||||
fill_with_garbage(objects[i], size);
|
||||
}
|
||||
|
||||
if (num)
|
||||
kmem_cache_free_bulk(c, num, objects);
|
||||
kmem_cache_free_bulk(c, ARRAY_SIZE(objects), objects);
|
||||
}
|
||||
kmem_cache_destroy(c);
|
||||
*total_failures += fail;
|
||||
|
||||
73
mm/Kconfig
73
mm/Kconfig
@@ -248,22 +248,75 @@ config SLUB_STATS
|
||||
out which slabs are relevant to a particular load.
|
||||
Try running: slabinfo -DA
|
||||
|
||||
config RANDOM_KMALLOC_CACHES
|
||||
default n
|
||||
config KMALLOC_PARTITION_CACHES
|
||||
depends on !SLUB_TINY
|
||||
bool "Randomize slab caches for normal kmalloc"
|
||||
bool "Partitioned slab caches for normal kmalloc"
|
||||
default RANDOM_KMALLOC_CACHES
|
||||
help
|
||||
A hardening feature that creates multiple copies of slab caches for
|
||||
normal kmalloc allocation and makes kmalloc randomly pick one based
|
||||
on code address, which makes the attackers more difficult to spray
|
||||
vulnerable memory objects on the heap for the purpose of exploiting
|
||||
memory vulnerabilities.
|
||||
A hardening feature that creates multiple isolated copies of slab
|
||||
caches for normal kmalloc allocations. This makes it more difficult
|
||||
to exploit memory-safety vulnerabilities by attacking vulnerable
|
||||
co-located memory objects. Several modes are provided.
|
||||
|
||||
Currently the number of copies is set to 16, a reasonably large value
|
||||
that effectively diverges the memory objects allocated for different
|
||||
subsystems or modules into different caches, at the expense of a
|
||||
limited degree of memory and CPU overhead that relates to hardware and
|
||||
system workload.
|
||||
limited degree of memory and CPU overhead that relates to hardware
|
||||
and system workload.
|
||||
|
||||
choice
|
||||
prompt "Partitioned slab cache mode"
|
||||
depends on KMALLOC_PARTITION_CACHES
|
||||
default KMALLOC_PARTITION_TYPED if CC_HAS_ALLOC_TOKEN
|
||||
default KMALLOC_PARTITION_RANDOM
|
||||
help
|
||||
Selects the slab cache partitioning mode.
|
||||
|
||||
config KMALLOC_PARTITION_RANDOM
|
||||
bool "Randomize slab caches for normal kmalloc"
|
||||
help
|
||||
Randomly pick a slab cache based on code address and a per-boot
|
||||
random seed.
|
||||
|
||||
This makes it harder for attackers to predict object co-location.
|
||||
The placement is random: while attackers don't know which kmalloc
|
||||
cache an object will be allocated from, they might circumvent
|
||||
the randomization by retrying attacks across multiple machines until
|
||||
the target objects are co-located.
|
||||
|
||||
config KMALLOC_PARTITION_TYPED
|
||||
bool "Type based slab cache selection for normal kmalloc"
|
||||
depends on CC_HAS_ALLOC_TOKEN
|
||||
help
|
||||
Rely on Clang's allocation tokens to choose a slab cache, where token
|
||||
IDs are derived from the allocated type.
|
||||
|
||||
Unlike KMALLOC_PARTITION_RANDOM, cache assignment is deterministic based
|
||||
on type, which guarantees that objects of certain types are not
|
||||
placed in the same cache. This effectively mitigates certain classes
|
||||
of exploits that probabilistic defenses like KMALLOC_PARTITION_RANDOM
|
||||
only make harder but not impossible. However, this also means the
|
||||
cache assignment is predictable.
|
||||
|
||||
Clang's default token ID calculation returns a bounded hash with
|
||||
disjoint ranges for pointer-containing and pointerless objects: when
|
||||
used as the slab cache index, this prevents buffer overflows on
|
||||
primitive buffers from directly corrupting pointer-containing
|
||||
objects.
|
||||
|
||||
The current effectiveness of Clang's type inference can be judged by
|
||||
-Rpass=alloc-token, which provides diagnostics where (after dead-code
|
||||
elimination) type inference failed.
|
||||
|
||||
Requires Clang 22 or later.
|
||||
|
||||
endchoice
|
||||
|
||||
config RANDOM_KMALLOC_CACHES
|
||||
bool
|
||||
transitional
|
||||
help
|
||||
Transitional config for migration to KMALLOC_PARTITION_CACHES.
|
||||
|
||||
endmenu # Slab allocator options
|
||||
|
||||
|
||||
@@ -1215,14 +1215,13 @@ static void kmem_cache_bulk(struct kunit *test)
|
||||
struct kmem_cache *cache;
|
||||
size_t size = 200;
|
||||
char *p[10];
|
||||
bool ret;
|
||||
int i;
|
||||
|
||||
cache = kmem_cache_create("test_cache", size, 0, 0, NULL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cache);
|
||||
|
||||
ret = kmem_cache_alloc_bulk(cache, GFP_KERNEL, ARRAY_SIZE(p), (void **)&p);
|
||||
if (!ret) {
|
||||
if (!kmem_cache_alloc_bulk(cache, GFP_KERNEL, ARRAY_SIZE(p),
|
||||
(void **)&p)) {
|
||||
kunit_err(test, "Allocation failed: %s\n", __func__);
|
||||
kmem_cache_destroy(cache);
|
||||
return;
|
||||
|
||||
@@ -214,7 +214,7 @@ static void test_cache_destroy(void)
|
||||
static inline size_t kmalloc_cache_alignment(size_t size)
|
||||
{
|
||||
/* just to get ->align so no need to pass in the real caller */
|
||||
enum kmalloc_cache_type type = kmalloc_type(GFP_KERNEL, 0);
|
||||
enum kmalloc_cache_type type = kmalloc_type(GFP_KERNEL, __kmalloc_token(0));
|
||||
return kmalloc_caches[type][__kmalloc_index(size, false)]->align;
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ static void *test_alloc(struct kunit *test, size_t size, gfp_t gfp, enum allocat
|
||||
|
||||
if (is_kfence_address(alloc)) {
|
||||
struct slab *slab = virt_to_slab(alloc);
|
||||
enum kmalloc_cache_type type = kmalloc_type(GFP_KERNEL, _RET_IP_);
|
||||
enum kmalloc_cache_type type = kmalloc_type(GFP_KERNEL, __kmalloc_token(size));
|
||||
struct kmem_cache *s = test_cache ?:
|
||||
kmalloc_caches[type][__kmalloc_index(size, false)];
|
||||
|
||||
@@ -761,9 +761,10 @@ static void test_memcache_alloc_bulk(struct kunit *test)
|
||||
timeout = jiffies + msecs_to_jiffies(100 * kfence_sample_interval);
|
||||
do {
|
||||
void *objects[100];
|
||||
int i, num = kmem_cache_alloc_bulk(test_cache, GFP_ATOMIC, ARRAY_SIZE(objects),
|
||||
objects);
|
||||
if (!num)
|
||||
int i;
|
||||
|
||||
if (!kmem_cache_alloc_bulk(test_cache, GFP_ATOMIC,
|
||||
ARRAY_SIZE(objects), objects))
|
||||
continue;
|
||||
for (i = 0; i < ARRAY_SIZE(objects); i++) {
|
||||
if (is_kfence_address(objects[i])) {
|
||||
@@ -771,7 +772,7 @@ static void test_memcache_alloc_bulk(struct kunit *test)
|
||||
break;
|
||||
}
|
||||
}
|
||||
kmem_cache_free_bulk(test_cache, num, objects);
|
||||
kmem_cache_free_bulk(test_cache, ARRAY_SIZE(objects), objects);
|
||||
/*
|
||||
* kmem_cache_alloc_bulk() disables interrupts, and calling it
|
||||
* in a tight loop may not give KFENCE a chance to switch the
|
||||
|
||||
27
mm/mempool.c
27
mm/mempool.c
@@ -419,12 +419,8 @@ static unsigned int mempool_alloc_from_pool(struct mempool *pool, void **elems,
|
||||
spin_lock_irqsave(&pool->lock, flags);
|
||||
if (unlikely(pool->curr_nr < count - allocated))
|
||||
goto fail;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!elems[i]) {
|
||||
elems[i] = remove_element(pool);
|
||||
allocated++;
|
||||
}
|
||||
}
|
||||
while (allocated < count)
|
||||
elems[allocated++] = remove_element(pool);
|
||||
spin_unlock_irqrestore(&pool->lock, flags);
|
||||
|
||||
/* Paired with rmb in mempool_free(), read comment there. */
|
||||
@@ -479,22 +475,21 @@ static inline gfp_t mempool_adjust_gfp(gfp_t *gfp_mask)
|
||||
* @pool: pointer to the memory pool
|
||||
* @elems: partially or fully populated elements array
|
||||
* @count: number of entries in @elem that need to be allocated
|
||||
* @allocated: number of entries in @elem already allocated
|
||||
*
|
||||
* Allocate elements for each slot in @elem that is non-%NULL. This is done by
|
||||
* first calling into the alloc_fn supplied at pool initialization time, and
|
||||
* dipping into the reserved pool when alloc_fn fails to allocate an element.
|
||||
* Allocate @count elements into @elems. This is done by first calling into the
|
||||
* alloc_fn supplied at pool initialization time, and dipping into the reserved
|
||||
* pool when alloc_fn fails to allocate an element.
|
||||
*
|
||||
* On return all @count elements in @elems will be populated.
|
||||
*
|
||||
* Return: Always 0. If it wasn't for %$#^$ alloc tags, it would return void.
|
||||
*/
|
||||
int mempool_alloc_bulk_noprof(struct mempool *pool, void **elems,
|
||||
unsigned int count, unsigned int allocated)
|
||||
unsigned int count)
|
||||
{
|
||||
gfp_t gfp_mask = GFP_KERNEL;
|
||||
gfp_t gfp_temp = mempool_adjust_gfp(&gfp_mask);
|
||||
unsigned int i = 0;
|
||||
unsigned int allocated = 0;
|
||||
|
||||
VM_WARN_ON_ONCE(count > pool->min_nr);
|
||||
might_alloc(gfp_mask);
|
||||
@@ -514,11 +509,9 @@ int mempool_alloc_bulk_noprof(struct mempool *pool, void **elems,
|
||||
* Try to allocate the elements using the allocation callback first as
|
||||
* that might succeed even when the caller's bulk allocation did not.
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
if (elems[i])
|
||||
continue;
|
||||
elems[i] = pool->alloc(gfp_temp, pool->pool_data);
|
||||
if (unlikely(!elems[i]))
|
||||
while (allocated < count) {
|
||||
elems[allocated] = pool->alloc(gfp_temp, pool->pool_data);
|
||||
if (unlikely(!elems[allocated]))
|
||||
goto use_pool;
|
||||
allocated++;
|
||||
}
|
||||
|
||||
@@ -362,12 +362,12 @@ static inline unsigned int size_index_elem(unsigned int bytes)
|
||||
* KMALLOC_MAX_CACHE_SIZE and the caller must check that.
|
||||
*/
|
||||
static inline struct kmem_cache *
|
||||
kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, unsigned long caller)
|
||||
kmalloc_slab(size_t size, kmem_buckets *b, gfp_t flags, kmalloc_token_t token)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
if (!b)
|
||||
b = &kmalloc_caches[kmalloc_type(flags, caller)];
|
||||
b = &kmalloc_caches[kmalloc_type(flags, token)];
|
||||
if (size <= 192)
|
||||
index = kmalloc_size_index[size_index_elem(size)];
|
||||
else
|
||||
|
||||
@@ -742,7 +742,7 @@ kmem_buckets kmalloc_caches[NR_KMALLOC_TYPES] __ro_after_init =
|
||||
{ /* initialization for https://llvm.org/pr42570 */ };
|
||||
EXPORT_SYMBOL(kmalloc_caches);
|
||||
|
||||
#ifdef CONFIG_RANDOM_KMALLOC_CACHES
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_RANDOM
|
||||
unsigned long random_kmalloc_seed __ro_after_init;
|
||||
EXPORT_SYMBOL(random_kmalloc_seed);
|
||||
#endif
|
||||
@@ -787,7 +787,7 @@ size_t kmalloc_size_roundup(size_t size)
|
||||
* The flags don't matter since size_index is common to all.
|
||||
* Neither does the caller for just getting ->object_size.
|
||||
*/
|
||||
return kmalloc_slab(size, NULL, GFP_KERNEL, 0)->object_size;
|
||||
return kmalloc_slab(size, NULL, GFP_KERNEL, __kmalloc_token(0))->object_size;
|
||||
}
|
||||
|
||||
/* Above the smaller buckets, size is a multiple of page size. */
|
||||
@@ -821,26 +821,26 @@ EXPORT_SYMBOL(kmalloc_size_roundup);
|
||||
#define KMALLOC_RCL_NAME(sz)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RANDOM_KMALLOC_CACHES
|
||||
#define __KMALLOC_RANDOM_CONCAT(a, b) a ## b
|
||||
#define KMALLOC_RANDOM_NAME(N, sz) __KMALLOC_RANDOM_CONCAT(KMA_RAND_, N)(sz)
|
||||
#define KMA_RAND_1(sz) .name[KMALLOC_RANDOM_START + 1] = "kmalloc-rnd-01-" #sz,
|
||||
#define KMA_RAND_2(sz) KMA_RAND_1(sz) .name[KMALLOC_RANDOM_START + 2] = "kmalloc-rnd-02-" #sz,
|
||||
#define KMA_RAND_3(sz) KMA_RAND_2(sz) .name[KMALLOC_RANDOM_START + 3] = "kmalloc-rnd-03-" #sz,
|
||||
#define KMA_RAND_4(sz) KMA_RAND_3(sz) .name[KMALLOC_RANDOM_START + 4] = "kmalloc-rnd-04-" #sz,
|
||||
#define KMA_RAND_5(sz) KMA_RAND_4(sz) .name[KMALLOC_RANDOM_START + 5] = "kmalloc-rnd-05-" #sz,
|
||||
#define KMA_RAND_6(sz) KMA_RAND_5(sz) .name[KMALLOC_RANDOM_START + 6] = "kmalloc-rnd-06-" #sz,
|
||||
#define KMA_RAND_7(sz) KMA_RAND_6(sz) .name[KMALLOC_RANDOM_START + 7] = "kmalloc-rnd-07-" #sz,
|
||||
#define KMA_RAND_8(sz) KMA_RAND_7(sz) .name[KMALLOC_RANDOM_START + 8] = "kmalloc-rnd-08-" #sz,
|
||||
#define KMA_RAND_9(sz) KMA_RAND_8(sz) .name[KMALLOC_RANDOM_START + 9] = "kmalloc-rnd-09-" #sz,
|
||||
#define KMA_RAND_10(sz) KMA_RAND_9(sz) .name[KMALLOC_RANDOM_START + 10] = "kmalloc-rnd-10-" #sz,
|
||||
#define KMA_RAND_11(sz) KMA_RAND_10(sz) .name[KMALLOC_RANDOM_START + 11] = "kmalloc-rnd-11-" #sz,
|
||||
#define KMA_RAND_12(sz) KMA_RAND_11(sz) .name[KMALLOC_RANDOM_START + 12] = "kmalloc-rnd-12-" #sz,
|
||||
#define KMA_RAND_13(sz) KMA_RAND_12(sz) .name[KMALLOC_RANDOM_START + 13] = "kmalloc-rnd-13-" #sz,
|
||||
#define KMA_RAND_14(sz) KMA_RAND_13(sz) .name[KMALLOC_RANDOM_START + 14] = "kmalloc-rnd-14-" #sz,
|
||||
#define KMA_RAND_15(sz) KMA_RAND_14(sz) .name[KMALLOC_RANDOM_START + 15] = "kmalloc-rnd-15-" #sz,
|
||||
#else // CONFIG_RANDOM_KMALLOC_CACHES
|
||||
#define KMALLOC_RANDOM_NAME(N, sz)
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_CACHES
|
||||
#define __KMALLOC_PARTITION_CONCAT(a, b) a ## b
|
||||
#define KMALLOC_PARTITION_NAME(N, sz) __KMALLOC_PARTITION_CONCAT(KMA_PART_, N)(sz)
|
||||
#define KMA_PART_1(sz) .name[KMALLOC_PARTITION_START + 1] = "kmalloc-part-01-" #sz,
|
||||
#define KMA_PART_2(sz) KMA_PART_1(sz) .name[KMALLOC_PARTITION_START + 2] = "kmalloc-part-02-" #sz,
|
||||
#define KMA_PART_3(sz) KMA_PART_2(sz) .name[KMALLOC_PARTITION_START + 3] = "kmalloc-part-03-" #sz,
|
||||
#define KMA_PART_4(sz) KMA_PART_3(sz) .name[KMALLOC_PARTITION_START + 4] = "kmalloc-part-04-" #sz,
|
||||
#define KMA_PART_5(sz) KMA_PART_4(sz) .name[KMALLOC_PARTITION_START + 5] = "kmalloc-part-05-" #sz,
|
||||
#define KMA_PART_6(sz) KMA_PART_5(sz) .name[KMALLOC_PARTITION_START + 6] = "kmalloc-part-06-" #sz,
|
||||
#define KMA_PART_7(sz) KMA_PART_6(sz) .name[KMALLOC_PARTITION_START + 7] = "kmalloc-part-07-" #sz,
|
||||
#define KMA_PART_8(sz) KMA_PART_7(sz) .name[KMALLOC_PARTITION_START + 8] = "kmalloc-part-08-" #sz,
|
||||
#define KMA_PART_9(sz) KMA_PART_8(sz) .name[KMALLOC_PARTITION_START + 9] = "kmalloc-part-09-" #sz,
|
||||
#define KMA_PART_10(sz) KMA_PART_9(sz) .name[KMALLOC_PARTITION_START + 10] = "kmalloc-part-10-" #sz,
|
||||
#define KMA_PART_11(sz) KMA_PART_10(sz) .name[KMALLOC_PARTITION_START + 11] = "kmalloc-part-11-" #sz,
|
||||
#define KMA_PART_12(sz) KMA_PART_11(sz) .name[KMALLOC_PARTITION_START + 12] = "kmalloc-part-12-" #sz,
|
||||
#define KMA_PART_13(sz) KMA_PART_12(sz) .name[KMALLOC_PARTITION_START + 13] = "kmalloc-part-13-" #sz,
|
||||
#define KMA_PART_14(sz) KMA_PART_13(sz) .name[KMALLOC_PARTITION_START + 14] = "kmalloc-part-14-" #sz,
|
||||
#define KMA_PART_15(sz) KMA_PART_14(sz) .name[KMALLOC_PARTITION_START + 15] = "kmalloc-part-15-" #sz,
|
||||
#else // CONFIG_KMALLOC_PARTITION_CACHES
|
||||
#define KMALLOC_PARTITION_NAME(N, sz)
|
||||
#endif
|
||||
|
||||
#define INIT_KMALLOC_INFO(__size, __short_size) \
|
||||
@@ -849,7 +849,7 @@ EXPORT_SYMBOL(kmalloc_size_roundup);
|
||||
KMALLOC_RCL_NAME(__short_size) \
|
||||
KMALLOC_CGROUP_NAME(__short_size) \
|
||||
KMALLOC_DMA_NAME(__short_size) \
|
||||
KMALLOC_RANDOM_NAME(RANDOM_KMALLOC_CACHES_NR, __short_size) \
|
||||
KMALLOC_PARTITION_NAME(KMALLOC_PARTITION_CACHES_NR, __short_size) \
|
||||
.size = __size, \
|
||||
}
|
||||
|
||||
@@ -961,8 +961,8 @@ new_kmalloc_cache(int idx, enum kmalloc_cache_type type)
|
||||
flags |= SLAB_CACHE_DMA;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RANDOM_KMALLOC_CACHES
|
||||
if (type >= KMALLOC_RANDOM_START && type <= KMALLOC_RANDOM_END)
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_CACHES
|
||||
if (type >= KMALLOC_PARTITION_START && type <= KMALLOC_PARTITION_END)
|
||||
flags |= SLAB_NO_MERGE;
|
||||
#endif
|
||||
|
||||
@@ -1010,7 +1010,7 @@ void __init create_kmalloc_caches(void)
|
||||
for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++)
|
||||
new_kmalloc_cache(i, type);
|
||||
}
|
||||
#ifdef CONFIG_RANDOM_KMALLOC_CACHES
|
||||
#ifdef CONFIG_KMALLOC_PARTITION_RANDOM
|
||||
random_kmalloc_seed = get_random_u64();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -243,12 +243,11 @@ static int xdp_recv_frames(struct xdp_frame **frames, int nframes,
|
||||
struct net_device *dev)
|
||||
{
|
||||
gfp_t gfp = __GFP_ZERO | GFP_ATOMIC;
|
||||
int i, n;
|
||||
int i;
|
||||
LIST_HEAD(list);
|
||||
|
||||
n = kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, gfp, nframes,
|
||||
(void **)skbs);
|
||||
if (unlikely(n == 0)) {
|
||||
if (unlikely(!kmem_cache_alloc_bulk(net_hotdata.skbuff_cache, gfp,
|
||||
nframes, (void **)skbs))) {
|
||||
for (i = 0; i < nframes; i++)
|
||||
xdp_return_frame(frames[i]);
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ __kmem_cache_create(const char *name, unsigned int size, unsigned int align,
|
||||
default: __kmem_cache_create)(__name, __object_size, __args, __VA_ARGS__)
|
||||
|
||||
void kmem_cache_free_bulk(struct kmem_cache *cachep, size_t size, void **list);
|
||||
int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
|
||||
bool kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
|
||||
void **list);
|
||||
struct slab_sheaf *
|
||||
kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size);
|
||||
|
||||
@@ -193,10 +193,9 @@ static unsigned long get_obj_and_str(const char *name, char **x)
|
||||
|
||||
*x = NULL;
|
||||
|
||||
if (!read_obj(name)) {
|
||||
x = NULL;
|
||||
if (!read_obj(name))
|
||||
return 0;
|
||||
}
|
||||
|
||||
result = strtoul(buffer, &p, 10);
|
||||
while (*p == ' ')
|
||||
p++;
|
||||
@@ -798,7 +797,7 @@ static void slab_debug(struct slabinfo *s)
|
||||
fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
|
||||
}
|
||||
if (!tracing && s->trace)
|
||||
set_obj(s, "trace", 1);
|
||||
set_obj(s, "trace", 0);
|
||||
}
|
||||
|
||||
static void totals(void)
|
||||
@@ -1266,7 +1265,6 @@ static void read_slab_dir(void)
|
||||
slab->objects_total = get_obj("objects_total");
|
||||
slab->objs_per_slab = get_obj("objs_per_slab");
|
||||
slab->order = get_obj("order");
|
||||
slab->partial = get_obj("partial");
|
||||
slab->partial = get_obj_and_str("partial", &t);
|
||||
decode_numa_list(slab->numa_partial, t);
|
||||
free(t);
|
||||
|
||||
@@ -154,7 +154,7 @@ void kmem_cache_shrink(struct kmem_cache *cachep)
|
||||
{
|
||||
}
|
||||
|
||||
int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
|
||||
bool kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
|
||||
void **p)
|
||||
{
|
||||
size_t i;
|
||||
@@ -213,7 +213,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
|
||||
pthread_mutex_unlock(&cachep->lock);
|
||||
if (cachep->callback)
|
||||
cachep->exec_callback = true;
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
@@ -224,7 +224,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *cachep, gfp_t gfp, size_t size,
|
||||
printf("Allocating %p from slab\n", p[i]);
|
||||
}
|
||||
|
||||
return size;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct kmem_cache *
|
||||
@@ -271,8 +271,8 @@ kmem_cache_prefill_sheaf(struct kmem_cache *s, gfp_t gfp, unsigned int size)
|
||||
|
||||
sheaf->cache = s;
|
||||
sheaf->capacity = capacity;
|
||||
sheaf->size = kmem_cache_alloc_bulk(s, gfp, size, sheaf->objects);
|
||||
if (!sheaf->size) {
|
||||
sheaf->size = size;
|
||||
if (!kmem_cache_alloc_bulk(s, gfp, size, sheaf->objects)) {
|
||||
free(sheaf);
|
||||
return NULL;
|
||||
}
|
||||
@@ -284,7 +284,6 @@ int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp,
|
||||
struct slab_sheaf **sheafp, unsigned int size)
|
||||
{
|
||||
struct slab_sheaf *sheaf = *sheafp;
|
||||
int refill;
|
||||
|
||||
if (sheaf->size >= size)
|
||||
return 0;
|
||||
@@ -299,12 +298,10 @@ int kmem_cache_refill_sheaf(struct kmem_cache *s, gfp_t gfp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
refill = kmem_cache_alloc_bulk(s, gfp, size - sheaf->size,
|
||||
&sheaf->objects[sheaf->size]);
|
||||
if (!refill)
|
||||
if (!kmem_cache_alloc_bulk(s, gfp, size - sheaf->size,
|
||||
&sheaf->objects[sheaf->size]))
|
||||
return -ENOMEM;
|
||||
|
||||
sheaf->size += refill;
|
||||
sheaf->size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user