Skip to content

Commit d6a7164

Browse files
hygonitehcaster
authored andcommitted
mm/slab: kmalloc: pass requests larger than order-1 page to page allocator
There is not much benefit for serving large objects in kmalloc(). Let's pass large requests to page allocator like SLUB for better maintenance of common code. Signed-off-by: Hyeonggon Yoo <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Signed-off-by: Vlastimil Babka <[email protected]>
1 parent c4cab55 commit d6a7164

File tree

5 files changed

+68
-62
lines changed

5 files changed

+68
-62
lines changed

include/linux/slab.h

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -243,27 +243,17 @@ static inline unsigned int arch_slab_minalign(void)
243243

244244
#ifdef CONFIG_SLAB
245245
/*
246-
* The largest kmalloc size supported by the SLAB allocators is
247-
* 32 megabyte (2^25) or the maximum allocatable page order if that is
248-
* less than 32 MB.
249-
*
250-
* WARNING: Its not easy to increase this value since the allocators have
251-
* to do various tricks to work around compiler limitations in order to
252-
* ensure proper constant folding.
246+
* SLAB and SLUB directly allocates requests fitting in to an order-1 page
247+
* (PAGE_SIZE*2). Larger requests are passed to the page allocator.
253248
*/
254-
#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \
255-
(MAX_ORDER + PAGE_SHIFT - 1) : 25)
256-
#define KMALLOC_SHIFT_MAX KMALLOC_SHIFT_HIGH
249+
#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)
250+
#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1)
257251
#ifndef KMALLOC_SHIFT_LOW
258252
#define KMALLOC_SHIFT_LOW 5
259253
#endif
260254
#endif
261255

262256
#ifdef CONFIG_SLUB
263-
/*
264-
* SLUB directly allocates requests fitting in to an order-1 page
265-
* (PAGE_SIZE*2). Larger requests are passed to the page allocator.
266-
*/
267257
#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)
268258
#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1)
269259
#ifndef KMALLOC_SHIFT_LOW
@@ -415,10 +405,6 @@ static __always_inline unsigned int __kmalloc_index(size_t size,
415405
if (size <= 512 * 1024) return 19;
416406
if (size <= 1024 * 1024) return 20;
417407
if (size <= 2 * 1024 * 1024) return 21;
418-
if (size <= 4 * 1024 * 1024) return 22;
419-
if (size <= 8 * 1024 * 1024) return 23;
420-
if (size <= 16 * 1024 * 1024) return 24;
421-
if (size <= 32 * 1024 * 1024) return 25;
422408

423409
if (!IS_ENABLED(CONFIG_PROFILE_ALL_BRANCHES) && size_is_constant)
424410
BUILD_BUG_ON_MSG(1, "unexpected size in kmalloc_index()");
@@ -428,6 +414,7 @@ static __always_inline unsigned int __kmalloc_index(size_t size,
428414
/* Will never be reached. Needed because the compiler may complain */
429415
return -1;
430416
}
417+
static_assert(PAGE_SHIFT <= 20);
431418
#define kmalloc_index(s) __kmalloc_index(s, true)
432419
#endif /* !CONFIG_SLOB */
433420

mm/slab.c

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3585,11 +3585,19 @@ __do_kmalloc_node(size_t size, gfp_t flags, int node, unsigned long caller)
35853585
struct kmem_cache *cachep;
35863586
void *ret;
35873587

3588-
if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))
3589-
return NULL;
3588+
if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) {
3589+
ret = kmalloc_large_node_notrace(size, flags, node);
3590+
3591+
trace_kmalloc_node(caller, ret, NULL, size,
3592+
PAGE_SIZE << get_order(size),
3593+
flags, node);
3594+
return ret;
3595+
}
3596+
35903597
cachep = kmalloc_slab(size, flags);
35913598
if (unlikely(ZERO_OR_NULL_PTR(cachep)))
35923599
return cachep;
3600+
35933601
ret = kmem_cache_alloc_node_trace(cachep, flags, node, size);
35943602
ret = kasan_kmalloc(cachep, ret, size, flags);
35953603

@@ -3664,17 +3672,27 @@ EXPORT_SYMBOL(kmem_cache_free);
36643672

36653673
void kmem_cache_free_bulk(struct kmem_cache *orig_s, size_t size, void **p)
36663674
{
3667-
struct kmem_cache *s;
3668-
size_t i;
36693675

36703676
local_irq_disable();
3671-
for (i = 0; i < size; i++) {
3677+
for (int i = 0; i < size; i++) {
36723678
void *objp = p[i];
3679+
struct kmem_cache *s;
36733680

3674-
if (!orig_s) /* called via kfree_bulk */
3675-
s = virt_to_cache(objp);
3676-
else
3681+
if (!orig_s) {
3682+
struct folio *folio = virt_to_folio(objp);
3683+
3684+
/* called via kfree_bulk */
3685+
if (!folio_test_slab(folio)) {
3686+
local_irq_enable();
3687+
free_large_kmalloc(folio, objp);
3688+
local_irq_disable();
3689+
continue;
3690+
}
3691+
s = folio_slab(folio)->slab_cache;
3692+
} else {
36773693
s = cache_from_obj(orig_s, objp);
3694+
}
3695+
36783696
if (!s)
36793697
continue;
36803698

@@ -3703,20 +3721,24 @@ void kfree(const void *objp)
37033721
{
37043722
struct kmem_cache *c;
37053723
unsigned long flags;
3724+
struct folio *folio;
37063725

37073726
trace_kfree(_RET_IP_, objp);
37083727

37093728
if (unlikely(ZERO_OR_NULL_PTR(objp)))
37103729
return;
3711-
local_irq_save(flags);
3712-
kfree_debugcheck(objp);
3713-
c = virt_to_cache(objp);
3714-
if (!c) {
3715-
local_irq_restore(flags);
3730+
3731+
folio = virt_to_folio(objp);
3732+
if (!folio_test_slab(folio)) {
3733+
free_large_kmalloc(folio, (void *)objp);
37163734
return;
37173735
}
3718-
debug_check_no_locks_freed(objp, c->object_size);
37193736

3737+
c = folio_slab(folio)->slab_cache;
3738+
3739+
local_irq_save(flags);
3740+
kfree_debugcheck(objp);
3741+
debug_check_no_locks_freed(objp, c->object_size);
37203742
debug_check_no_obj_freed(objp, c->object_size);
37213743
__cache_free(c, (void *)objp, _RET_IP_);
37223744
local_irq_restore(flags);
@@ -4138,15 +4160,17 @@ void __check_heap_object(const void *ptr, unsigned long n,
41384160
size_t __ksize(const void *objp)
41394161
{
41404162
struct kmem_cache *c;
4141-
size_t size;
4163+
struct folio *folio;
41424164

41434165
BUG_ON(!objp);
41444166
if (unlikely(objp == ZERO_SIZE_PTR))
41454167
return 0;
41464168

4147-
c = virt_to_cache(objp);
4148-
size = c ? c->object_size : 0;
4169+
folio = virt_to_folio(objp);
4170+
if (!folio_test_slab(folio))
4171+
return folio_size(folio);
41494172

4150-
return size;
4173+
c = folio_slab(folio)->slab_cache;
4174+
return c->object_size;
41514175
}
41524176
EXPORT_SYMBOL(__ksize);

mm/slab.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,9 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x)
660660
print_tracking(cachep, x);
661661
return cachep;
662662
}
663+
664+
void free_large_kmalloc(struct folio *folio, void *object);
665+
663666
#endif /* CONFIG_SLOB */
664667

665668
static inline size_t slab_ksize(const struct kmem_cache *s)

mm/slab_common.c

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -744,8 +744,8 @@ struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
744744

745745
/*
746746
* kmalloc_info[] is to make slub_debug=,kmalloc-xx option work at boot time.
747-
* kmalloc_index() supports up to 2^25=32MB, so the final entry of the table is
748-
* kmalloc-32M.
747+
* kmalloc_index() supports up to 2^21=2MB, so the final entry of the table is
748+
* kmalloc-2M.
749749
*/
750750
const struct kmalloc_info_struct kmalloc_info[] __initconst = {
751751
INIT_KMALLOC_INFO(0, 0),
@@ -769,11 +769,7 @@ const struct kmalloc_info_struct kmalloc_info[] __initconst = {
769769
INIT_KMALLOC_INFO(262144, 256k),
770770
INIT_KMALLOC_INFO(524288, 512k),
771771
INIT_KMALLOC_INFO(1048576, 1M),
772-
INIT_KMALLOC_INFO(2097152, 2M),
773-
INIT_KMALLOC_INFO(4194304, 4M),
774-
INIT_KMALLOC_INFO(8388608, 8M),
775-
INIT_KMALLOC_INFO(16777216, 16M),
776-
INIT_KMALLOC_INFO(33554432, 32M)
772+
INIT_KMALLOC_INFO(2097152, 2M)
777773
};
778774

779775
/*
@@ -886,6 +882,21 @@ void __init create_kmalloc_caches(slab_flags_t flags)
886882
/* Kmalloc array is now usable */
887883
slab_state = UP;
888884
}
885+
886+
void free_large_kmalloc(struct folio *folio, void *object)
887+
{
888+
unsigned int order = folio_order(folio);
889+
890+
if (WARN_ON_ONCE(order == 0))
891+
pr_warn_once("object pointer: 0x%p\n", object);
892+
893+
kmemleak_free(object);
894+
kasan_kfree_large(object);
895+
896+
mod_lruvec_page_state(folio_page(folio, 0), NR_SLAB_UNRECLAIMABLE_B,
897+
-(PAGE_SIZE << order));
898+
__free_pages(folio_page(folio, 0), order);
899+
}
889900
#endif /* !CONFIG_SLOB */
890901

891902
gfp_t kmalloc_fix_flags(gfp_t flags)

mm/slub.c

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,12 +1704,6 @@ static bool freelist_corrupted(struct kmem_cache *s, struct slab *slab,
17041704
* Hooks for other subsystems that check memory allocations. In a typical
17051705
* production configuration these hooks all should produce no code at all.
17061706
*/
1707-
static __always_inline void kfree_hook(void *x)
1708-
{
1709-
kmemleak_free(x);
1710-
kasan_kfree_large(x);
1711-
}
1712-
17131707
static __always_inline bool slab_free_hook(struct kmem_cache *s,
17141708
void *x, bool init)
17151709
{
@@ -3550,19 +3544,6 @@ struct detached_freelist {
35503544
struct kmem_cache *s;
35513545
};
35523546

3553-
static inline void free_large_kmalloc(struct folio *folio, void *object)
3554-
{
3555-
unsigned int order = folio_order(folio);
3556-
3557-
if (WARN_ON_ONCE(order == 0))
3558-
pr_warn_once("object pointer: 0x%p\n", object);
3559-
3560-
kfree_hook(object);
3561-
mod_lruvec_page_state(folio_page(folio, 0), NR_SLAB_UNRECLAIMABLE_B,
3562-
-(PAGE_SIZE << order));
3563-
__free_pages(folio_page(folio, 0), order);
3564-
}
3565-
35663547
/*
35673548
* This function progressively scans the array with free objects (with
35683549
* a limited look ahead) and extract objects belonging to the same

0 commit comments

Comments
 (0)