[PATCH 2/5] mm/khugepaged: use slab cache instead of normal kmalloc

From: Luka Bai

Date: Sun May 31 2026 - 00:24:32 EST


From: Luka Bai <lukabai@xxxxxxxxxxx>

We added a kmem slab cached called collapse_hint_cache for
khugepaged collapse hint, to improve the performance in allocation
and freeing for the hint structs.

Signed-off-by: Luka Bai <lukabai@xxxxxxxxxxx>
---
mm/khugepaged.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 5090ffae73f3..04cf85ea5557 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -98,6 +98,7 @@ static unsigned int khugepaged_max_ptes_shared __read_mostly;
static DEFINE_READ_MOSTLY_HASHTABLE(mm_slots_hash, MM_SLOTS_HASH_BITS);

static struct kmem_cache *mm_slot_cache __ro_after_init;
+static struct kmem_cache *collapse_hint_cache __ro_after_init;

#define KHUGEPAGED_PRIORITY_QUEUE_MAX_FAIL 10

@@ -555,6 +556,13 @@ int __init khugepaged_init(void)
if (!mm_slot_cache)
return -ENOMEM;

+ collapse_hint_cache = KMEM_CACHE(khugepaged_collapse_hint, 0);
+ if (!collapse_hint_cache) {
+ kmem_cache_destroy(mm_slot_cache);
+ mm_slot_cache = NULL;
+ return -ENOMEM;
+ }
+
for (i = 0; i < NR_KHUGEPAGED_PRIORITY_LEVEL; i++)
INIT_LIST_HEAD(&khugepaged_priority_queue[i]);

@@ -569,6 +577,7 @@ int __init khugepaged_init(void)
void __init khugepaged_destroy(void)
{
kmem_cache_destroy(mm_slot_cache);
+ kmem_cache_destroy(collapse_hint_cache);
}

static inline int collapse_test_exit(struct mm_struct *mm)
@@ -686,7 +695,7 @@ static void khugepaged_release_collapse_hints(

list_for_each_entry_safe(hint, tmp, &req->hints, node) {
list_del(&hint->node);
- kfree(hint);
+ kmem_cache_free(collapse_hint_cache, hint);
}
}

@@ -3013,7 +3022,7 @@ void khugepaged_add_collapse_hint(struct mm_struct *mm,
if (!mm_flags_test(MMF_VM_HUGEPAGE, mm))
return;

- hint = kmalloc_obj(struct khugepaged_collapse_hint);
+ hint = kmem_cache_alloc(collapse_hint_cache, GFP_KERNEL);
if (!hint)
return;

@@ -3025,14 +3034,14 @@ void khugepaged_add_collapse_hint(struct mm_struct *mm,
* just "best-effort" optimization.
*/
if (!spin_trylock(&khugepaged_mm_lock)) {
- kfree(hint);
+ kmem_cache_free(collapse_hint_cache, hint);
return;
}

slot = mm_slot_lookup(mm_slots_hash, mm);
if (!slot) {
spin_unlock(&khugepaged_mm_lock);
- kfree(hint);
+ kmem_cache_free(collapse_hint_cache, hint);
return;
}
khp_mm_slot = mm_slot_entry(slot, struct khugepaged_mm_slot, slot);
@@ -3125,7 +3134,7 @@ static int collapse_scan_one_priority_entry(unsigned int progress_max,
addr = hint->address;

if (unlikely(collapse_test_exit_or_disable(mm))) {
- kfree(hint);
+ kmem_cache_free(collapse_hint_cache, hint);
break;
}

@@ -3149,7 +3158,7 @@ static int collapse_scan_one_priority_entry(unsigned int progress_max,
if (*result != SCAN_SUCCEED)
(*fail_count)++;
skip_hint:
- kfree(hint);
+ kmem_cache_free(collapse_hint_cache, hint);
}

if (!lock_dropped)

--
2.52.0