aboutsummaryrefslogtreecommitdiffstats
path: root/mm/slub.c
diff options
authorVlastimil Babka <vbabka@suse.cz>2025-03-06 09:46:34 +0100
committerVlastimil Babka <vbabka@suse.cz>2025-03-20 10:33:38 +0100
commitdea2d9221e83ea02b45a60ab88284cd3bb4bb2a4 (patch)
tree0391b6707ca2cd787f5937f285eb715375bda3c1 /mm/slub.c
parent747e2cf137f44058a093d3226bf83974d9d117e7 (diff)
parentc9f8f1242a4c3e48adc6c3cf6b31c1ffbaa49943 (diff)
downloadath-dea2d9221e83ea02b45a60ab88284cd3bb4bb2a4.tar.gz
Merge branch 'slab/for-6.15/kfree_rcu_tiny' into slab/for-next
Merge the slab feature branch kfree_rcu_tiny for 6.15: - Move the TINY_RCU kvfree_rcu() implementation from RCU to SLAB subsystem and cleanup its integration.
Diffstat (limited to 'mm/slub.c')
-rw-r--r--mm/slub.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/mm/slub.c b/mm/slub.c
index 6493b26f08cf5..5eac408e818e4 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -19,6 +19,7 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include "slab.h"
+#include <linux/vmalloc.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/kasan.h>
@@ -4757,6 +4758,51 @@ static void free_large_kmalloc(struct folio *folio, void *object)
folio_put(folio);
}
+/*
+ * Given an rcu_head embedded within an object obtained from kvmalloc at an
+ * offset < 4k, free the object in question.
+ */
+void kvfree_rcu_cb(struct rcu_head *head)
+{
+ void *obj = head;
+ struct folio *folio;
+ struct slab *slab;
+ struct kmem_cache *s;
+ void *slab_addr;
+
+ if (is_vmalloc_addr(obj)) {
+ obj = (void *) PAGE_ALIGN_DOWN((unsigned long)obj);
+ vfree(obj);
+ return;
+ }
+
+ folio = virt_to_folio(obj);
+ if (!folio_test_slab(folio)) {
+ /*
+ * rcu_head offset can be only less than page size so no need to
+ * consider folio order
+ */
+ obj = (void *) PAGE_ALIGN_DOWN((unsigned long)obj);
+ free_large_kmalloc(folio, obj);
+ return;
+ }
+
+ slab = folio_slab(folio);
+ s = slab->slab_cache;
+ slab_addr = folio_address(folio);
+
+ if (is_kfence_address(obj)) {
+ obj = kfence_object_start(obj);
+ } else {
+ unsigned int idx = __obj_to_index(s, slab_addr, obj);
+
+ obj = slab_addr + s->size * idx;
+ obj = fixup_red_left(s, obj);
+ }
+
+ slab_free(s, slab, obj, _RET_IP_);
+}
+
/**
* kfree - free previously allocated memory
* @object: pointer returned by kmalloc() or kmem_cache_alloc()