diff options
Diffstat (limited to 'include/linux/slab.h')
| -rw-r--r-- | include/linux/slab.h | 115 |
1 files changed, 74 insertions, 41 deletions
diff --git a/include/linux/slab.h b/include/linux/slab.h index ed9cbddeb4a6..11b45f7ae405 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -295,11 +295,42 @@ static inline void __check_heap_object(const void *ptr, unsigned long n, #define SLAB_OBJ_MIN_SIZE (KMALLOC_MIN_SIZE < 16 ? \ (KMALLOC_MIN_SIZE) : 16) +/* + * Whenever changing this, take care of that kmalloc_type() and + * create_kmalloc_caches() still work as intended. + */ +enum kmalloc_cache_type { + KMALLOC_NORMAL = 0, + KMALLOC_RECLAIM, +#ifdef CONFIG_ZONE_DMA + KMALLOC_DMA, +#endif + NR_KMALLOC_TYPES +}; + #ifndef CONFIG_SLOB -extern struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1]; +extern struct kmem_cache * +kmalloc_caches[NR_KMALLOC_TYPES][KMALLOC_SHIFT_HIGH + 1]; + +static __always_inline enum kmalloc_cache_type kmalloc_type(gfp_t flags) +{ #ifdef CONFIG_ZONE_DMA -extern struct kmem_cache *kmalloc_dma_caches[KMALLOC_SHIFT_HIGH + 1]; + /* + * The most common case is KMALLOC_NORMAL, so test for it + * with a single branch for both flags. + */ + if (likely((flags & (__GFP_DMA | __GFP_RECLAIMABLE)) == 0)) + return KMALLOC_NORMAL; + + /* + * At least one of the flags has to be set. If both are, __GFP_DMA + * is more important. + */ + return flags & __GFP_DMA ? KMALLOC_DMA : KMALLOC_RECLAIM; +#else + return flags & __GFP_RECLAIMABLE ? KMALLOC_RECLAIM : KMALLOC_NORMAL; #endif +} /* * Figure out which kmalloc slab an allocation of a certain size @@ -413,7 +444,7 @@ static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s, { void *ret = kmem_cache_alloc(s, flags); - kasan_kmalloc(s, ret, size, flags); + ret = kasan_kmalloc(s, ret, size, flags); return ret; } @@ -424,7 +455,7 @@ kmem_cache_alloc_node_trace(struct kmem_cache *s, { void *ret = kmem_cache_alloc_node(s, gfpflags, node); - kasan_kmalloc(s, ret, size, gfpflags); + ret = kasan_kmalloc(s, ret, size, gfpflags); return ret; } #endif /* CONFIG_TRACING */ @@ -455,64 +486,65 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags) * kmalloc is the normal method of allocating memory * for objects smaller than page size in the kernel. * - * The @flags argument may be one of: - * - * %GFP_USER - Allocate memory on behalf of user. May sleep. - * - * %GFP_KERNEL - Allocate normal kernel ram. May sleep. - * - * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools. - * For example, use this inside interrupt handlers. + * The @flags argument may be one of the GFP flags defined at + * include/linux/gfp.h and described at + * :ref:`Documentation/core-api/mm-api.rst <mm-api-gfp-flags>` * - * %GFP_HIGHUSER - Allocate pages from high memory. + * The recommended usage of the @flags is described at + * :ref:`Documentation/core-api/memory-allocation.rst <memory-allocation>` * - * %GFP_NOIO - Do not do any I/O at all while trying to get memory. + * Below is a brief outline of the most useful GFP flags * - * %GFP_NOFS - Do not make any fs calls while trying to get memory. + * %GFP_KERNEL + * Allocate normal kernel ram. May sleep. * - * %GFP_NOWAIT - Allocation will not sleep. + * %GFP_NOWAIT + * Allocation will not sleep. * - * %__GFP_THISNODE - Allocate node-local memory only. + * %GFP_ATOMIC + * Allocation will not sleep. May use emergency pools. * - * %GFP_DMA - Allocation suitable for DMA. - * Should only be used for kmalloc() caches. Otherwise, use a - * slab created with SLAB_DMA. + * %GFP_HIGHUSER + * Allocate memory from high memory on behalf of user. * * Also it is possible to set different flags by OR'ing * in one or more of the following additional @flags: * - * %__GFP_HIGH - This allocation has high priority and may use emergency pools. + * %__GFP_HIGH + * This allocation has high priority and may use emergency pools. * - * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail - * (think twice before using). + * %__GFP_NOFAIL + * Indicate that this allocation is in no way allowed to fail + * (think twice before using). * - * %__GFP_NORETRY - If memory is not immediately available, - * then give up at once. + * %__GFP_NORETRY + * If memory is not immediately available, + * then give up at once. * - * %__GFP_NOWARN - If allocation fails, don't issue any warnings. + * %__GFP_NOWARN + * If allocation fails, don't issue any warnings. * - * %__GFP_RETRY_MAYFAIL - Try really hard to succeed the allocation but fail - * eventually. - * - * There are other flags available as well, but these are not intended - * for general use, and so are not documented here. For a full list of - * potential flags, always refer to linux/gfp.h. + * %__GFP_RETRY_MAYFAIL + * Try really hard to succeed the allocation but fail + * eventually. */ static __always_inline void *kmalloc(size_t size, gfp_t flags) { if (__builtin_constant_p(size)) { +#ifndef CONFIG_SLOB + unsigned int index; +#endif if (size > KMALLOC_MAX_CACHE_SIZE) return kmalloc_large(size, flags); #ifndef CONFIG_SLOB - if (!(flags & GFP_DMA)) { - unsigned int index = kmalloc_index(size); + index = kmalloc_index(size); - if (!index) - return ZERO_SIZE_PTR; + if (!index) + return ZERO_SIZE_PTR; - return kmem_cache_alloc_trace(kmalloc_caches[index], - flags, size); - } + return kmem_cache_alloc_trace( + kmalloc_caches[kmalloc_type(flags)][index], + flags, size); #endif } return __kmalloc(size, flags); @@ -542,13 +574,14 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) { #ifndef CONFIG_SLOB if (__builtin_constant_p(size) && - size <= KMALLOC_MAX_CACHE_SIZE && !(flags & GFP_DMA)) { + size <= KMALLOC_MAX_CACHE_SIZE) { unsigned int i = kmalloc_index(size); if (!i) return ZERO_SIZE_PTR; - return kmem_cache_alloc_node_trace(kmalloc_caches[i], + return kmem_cache_alloc_node_trace( + kmalloc_caches[kmalloc_type(flags)][i], flags, node, size); } #endif |