Linux Documentation
 help / color / mirror / Atom feed
* [PATCH 0/4] mm/slub: preserve previous object lifetime
@ 2026-06-16 14:14 Pengpeng Hou
  2026-06-16 14:14 ` [PATCH 1/4] mm/slub: factor user tracking metadata size calculation Pengpeng Hou
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Pengpeng Hou @ 2026-06-16 14:14 UTC (permalink / raw)
  To: Vlastimil Babka, Andrew Morton, linux-mm
  Cc: Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, David Hildenbrand, Lorenzo Stoakes, liam,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonathan Corbet,
	Shuah Khan, linux-doc, linux-kernel, Pengpeng Hou

SLAB_STORE_USER currently stores one allocation track and one free track
for an object.  Once the object is reused, the next allocation overwrites
the allocation track.  If a stale pointer from the previous lifetime is
later freed or otherwise reported, the report can show the victim
allocation and the stale operation while the previous completed lifetime
has already been lost.

This series keeps one previous completed lifetime in the existing
SLAB_STORE_USER metadata and prints it when available.  It is intended as
diagnostic information for reuse cases only; it does not infer semantic
ownership or identify the root cause of a use-after-free.

This is the non-RFC version of the earlier RFC.  Based on the feedback,
this version does not add a separate slab_debug=H option.  If a user
enables U, the user tracking metadata records the current allocation/free
tracks and one previous completed allocation/free pair.

Changes since RFC:
- extend the existing U option directly instead of adding H/UH
- add KUnit coverage for the previous-lifetime state transition
- document the extra report lines and the diagnostic-only semantics

Pengpeng Hou (4):
  mm/slub: factor user tracking metadata size calculation
  mm/slub: preserve previous object lifetime in user tracking
  mm/slub: test previous lifetime tracking
  Documentation/mm: document SLUB previous lifetime tracking

 Documentation/admin-guide/mm/slab.rst |  12 ++-
 lib/tests/slub_kunit.c                |  33 +++++++++
 mm/slab.h                             |  10 +++
 mm/slub.c                             | 102 +++++++++++++++++++++-----
 4 files changed, 136 insertions(+), 21 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] mm/slub: factor user tracking metadata size calculation
  2026-06-16 14:14 [PATCH 0/4] mm/slub: preserve previous object lifetime Pengpeng Hou
@ 2026-06-16 14:14 ` Pengpeng Hou
  2026-06-17  4:26   ` Hao Li
  2026-06-16 14:14 ` [PATCH 2/4] mm/slub: preserve previous object lifetime in user tracking Pengpeng Hou
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Pengpeng Hou @ 2026-06-16 14:14 UTC (permalink / raw)
  To: Vlastimil Babka, Andrew Morton, linux-mm
  Cc: Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, David Hildenbrand, Lorenzo Stoakes, liam,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonathan Corbet,
	Shuah Khan, linux-doc, linux-kernel, Pengpeng Hou

SLAB_STORE_USER currently stores two struct track records in the per-object
debug metadata.  The size is open-coded as 2 * sizeof(struct track) in
several layout and offset calculations.

Add TRACK_NR and a small helper for the user-tracking metadata size.  This
keeps all offset calculations tied to the number of track records and makes
the following extension less error-prone.

No functional change.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 mm/slub.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/mm/slub.c b/mm/slub.c
index f87e693aca5d..43d4febd5bf2 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -327,7 +327,15 @@ struct track {
 	unsigned long when;	/* When did the operation occur */
 };
 
-enum track_item { TRACK_ALLOC, TRACK_FREE };
+enum track_item { TRACK_ALLOC, TRACK_FREE, TRACK_NR };
+
+static inline unsigned int user_tracking_size(slab_flags_t flags)
+{
+	if (flags & SLAB_STORE_USER)
+		return TRACK_NR * sizeof(struct track);
+
+	return 0;
+}
 
 #ifdef SLAB_SUPPORTS_SYSFS
 static int sysfs_slab_add(struct kmem_cache *);
@@ -751,7 +759,7 @@ static inline void set_orig_size(struct kmem_cache *s,
 		return;
 
 	p += get_info_end(s);
-	p += sizeof(struct track) * 2;
+	p += user_tracking_size(s->flags);
 
 	*(unsigned long *)p = orig_size;
 }
@@ -767,7 +775,7 @@ static inline unsigned long get_orig_size(struct kmem_cache *s, void *object)
 		return s->object_size;
 
 	p += get_info_end(s);
-	p += sizeof(struct track) * 2;
+	p += user_tracking_size(s->flags);
 
 	return *(unsigned long *)p;
 }
@@ -885,7 +893,7 @@ static unsigned int obj_exts_offset_in_object(struct kmem_cache *s)
 	unsigned int offset = get_info_end(s);
 
 	if (kmem_cache_debug_flags(s, SLAB_STORE_USER))
-		offset += sizeof(struct track) * 2;
+		offset += user_tracking_size(s->flags);
 
 	if (slub_debug_orig_size(s))
 		offset += sizeof(unsigned long);
@@ -1088,7 +1096,7 @@ static void init_tracking(struct kmem_cache *s, void *object)
 		return;
 
 	p = get_track(s, object, TRACK_ALLOC);
-	memset(p, 0, 2*sizeof(struct track));
+	memset(p, 0, user_tracking_size(s->flags));
 }
 
 static void print_track(const char *s, struct track *t, unsigned long pr_time)
@@ -1196,8 +1204,7 @@ static void print_trailer(struct kmem_cache *s, struct slab *slab, u8 *p)
 
 	off = get_info_end(s);
 
-	if (s->flags & SLAB_STORE_USER)
-		off += 2 * sizeof(struct track);
+	off += user_tracking_size(s->flags);
 
 	if (slub_debug_orig_size(s))
 		off += sizeof(unsigned long);
@@ -1401,7 +1408,7 @@ static int check_pad_bytes(struct kmem_cache *s, struct slab *slab, u8 *p)
 
 	if (s->flags & SLAB_STORE_USER) {
 		/* We also have user information there */
-		off += 2 * sizeof(struct track);
+		off += user_tracking_size(s->flags);
 
 		if (s->flags & SLAB_KMALLOC)
 			off += sizeof(unsigned long);
@@ -7820,7 +7827,7 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
 		 * Need to store information about allocs and frees after
 		 * the object.
 		 */
-		size += 2 * sizeof(struct track);
+		size += user_tracking_size(flags);
 
 		/* Save the original kmalloc request size */
 		if (flags & SLAB_KMALLOC)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] mm/slub: preserve previous object lifetime in user tracking
  2026-06-16 14:14 [PATCH 0/4] mm/slub: preserve previous object lifetime Pengpeng Hou
  2026-06-16 14:14 ` [PATCH 1/4] mm/slub: factor user tracking metadata size calculation Pengpeng Hou
@ 2026-06-16 14:14 ` Pengpeng Hou
  2026-06-16 14:14 ` [PATCH 3/4] mm/slub: test previous lifetime tracking Pengpeng Hou
  2026-06-16 14:14 ` [PATCH 4/4] Documentation/mm: document SLUB " Pengpeng Hou
  3 siblings, 0 replies; 6+ messages in thread
From: Pengpeng Hou @ 2026-06-16 14:14 UTC (permalink / raw)
  To: Vlastimil Babka, Andrew Morton, linux-mm
  Cc: Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, David Hildenbrand, Lorenzo Stoakes, liam,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonathan Corbet,
	Shuah Khan, linux-doc, linux-kernel, Pengpeng Hou

SLAB_STORE_USER stores one allocation track and one free track for an
object.  When that object is reused, the next allocation overwrites the
allocation track.  If a stale pointer from the previous lifetime is later
freed or otherwise reported, the free/check report can contain the victim
allocation and the stale operation while the previous completed alloc/free
pair has already been overwritten.

Keep one previous completed lifetime in the existing user tracking
metadata.  When an object is allocated and the current allocation/free
tracks both exist, copy that completed lifetime to the previous-lifetime
slots before recording the new allocation.  Clear the current free track
when the new allocation begins so the current lifetime does not continue
to display a free from the old lifetime.

Print the previous object lifetime when it is available.  This is
diagnostic information only; it does not infer semantic ownership or
identify the root cause of a use-after-free.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 mm/slub.c | 66 +++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 55 insertions(+), 11 deletions(-)

diff --git a/mm/slub.c b/mm/slub.c
index 43d4febd5bf2..358f42e92207 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -327,7 +327,13 @@ struct track {
 	unsigned long when;	/* When did the operation occur */
 };
 
-enum track_item { TRACK_ALLOC, TRACK_FREE, TRACK_NR };
+enum track_item {
+	TRACK_ALLOC,
+	TRACK_FREE,
+	TRACK_PREV_ALLOC,
+	TRACK_PREV_FREE,
+	TRACK_NR,
+};
 
 static inline unsigned int user_tracking_size(slab_flags_t flags)
 {
@@ -1080,12 +1086,37 @@ static void set_track_update(struct kmem_cache *s, void *object,
 	p->when = jiffies;
 }
 
-static __always_inline void set_track(struct kmem_cache *s, void *object,
-				      enum track_item alloc, unsigned long addr, gfp_t gfp_flags)
+static bool track_has_record(const struct track *t)
+{
+	return t->addr;
+}
+
+static void clear_track(struct kmem_cache *s, void *object,
+			enum track_item track)
+{
+	memset(get_track(s, object, track), 0, sizeof(struct track));
+}
+
+static void save_previous_lifetime(struct kmem_cache *s, void *object)
+{
+	struct track *alloc = get_track(s, object, TRACK_ALLOC);
+	struct track *free = get_track(s, object, TRACK_FREE);
+
+	if (!track_has_record(alloc) || !track_has_record(free))
+		return;
+
+	*get_track(s, object, TRACK_PREV_ALLOC) = *alloc;
+	*get_track(s, object, TRACK_PREV_FREE) = *free;
+}
+
+static __always_inline void set_alloc_track(struct kmem_cache *s, void *object,
+					    unsigned long addr, gfp_t gfp_flags)
 {
 	depot_stack_handle_t handle = set_track_prepare(gfp_flags);
 
-	set_track_update(s, object, alloc, addr, handle);
+	save_previous_lifetime(s, object);
+	set_track_update(s, object, TRACK_ALLOC, addr, handle);
+	clear_track(s, object, TRACK_FREE);
 }
 
 static void init_tracking(struct kmem_cache *s, void *object)
@@ -1120,11 +1151,22 @@ static void print_track(const char *s, struct track *t, unsigned long pr_time)
 void print_tracking(struct kmem_cache *s, void *object)
 {
 	unsigned long pr_time = jiffies;
+	struct track *prev_alloc;
+	struct track *prev_free;
+
 	if (!(s->flags & SLAB_STORE_USER))
 		return;
 
 	print_track("Allocated", get_track(s, object, TRACK_ALLOC), pr_time);
 	print_track("Freed", get_track(s, object, TRACK_FREE), pr_time);
+
+	prev_alloc = get_track(s, object, TRACK_PREV_ALLOC);
+	prev_free = get_track(s, object, TRACK_PREV_FREE);
+	if (track_has_record(prev_alloc) || track_has_record(prev_free)) {
+		pr_err("Previous object lifetime:\n");
+		print_track("Previously allocated", prev_alloc, pr_time);
+		print_track("Previously freed", prev_free, pr_time);
+	}
 }
 
 static void print_slab_info(const struct slab *slab)
@@ -1371,10 +1413,12 @@ check_bytes_and_report(struct kmem_cache *s, struct slab *slab,
  *
  * [Metadata starts at object + s->inuse]
  *   - A. freelist pointer (if freeptr_outside_object)
- *   - B. alloc tracking (SLAB_STORE_USER)
- *   - C. free tracking (SLAB_STORE_USER)
- *   - D. original request size (SLAB_KMALLOC && SLAB_STORE_USER)
- *   - E. KASAN metadata (if enabled)
+ *   - B. current alloc tracking (SLAB_STORE_USER)
+ *   - C. current free tracking (SLAB_STORE_USER)
+ *   - D. previous alloc tracking (SLAB_STORE_USER)
+ *   - E. previous free tracking (SLAB_STORE_USER)
+ *   - F. original request size (SLAB_KMALLOC && SLAB_STORE_USER)
+ *   - G. KASAN metadata (if enabled)
  *
  * [Mandatory padding] (if CONFIG_SLUB_DEBUG && SLAB_RED_ZONE)
  *   - One mandatory debug word to guarantee a minimum poisoned gap
@@ -2029,8 +2073,8 @@ static inline void slab_pad_check(struct kmem_cache *s, struct slab *slab) {}
 static inline int check_object(struct kmem_cache *s, struct slab *slab,
 			void *object, u8 val) { return 1; }
 static inline depot_stack_handle_t set_track_prepare(gfp_t gfp_flags) { return 0; }
-static inline void set_track(struct kmem_cache *s, void *object,
-			     enum track_item alloc, unsigned long addr, gfp_t gfp_flags) {}
+static inline void set_alloc_track(struct kmem_cache *s, void *object,
+				   unsigned long addr, gfp_t gfp_flags) {}
 static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n,
 					struct slab *slab) {}
 static inline void remove_full(struct kmem_cache *s, struct kmem_cache_node *n,
@@ -4522,7 +4566,7 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
 
 success:
 	if (kmem_cache_debug_flags(s, SLAB_STORE_USER))
-		set_track(s, object, TRACK_ALLOC, addr, gfpflags);
+		set_alloc_track(s, object, addr, gfpflags);
 
 	return object;
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] mm/slub: test previous lifetime tracking
  2026-06-16 14:14 [PATCH 0/4] mm/slub: preserve previous object lifetime Pengpeng Hou
  2026-06-16 14:14 ` [PATCH 1/4] mm/slub: factor user tracking metadata size calculation Pengpeng Hou
  2026-06-16 14:14 ` [PATCH 2/4] mm/slub: preserve previous object lifetime in user tracking Pengpeng Hou
@ 2026-06-16 14:14 ` Pengpeng Hou
  2026-06-16 14:14 ` [PATCH 4/4] Documentation/mm: document SLUB " Pengpeng Hou
  3 siblings, 0 replies; 6+ messages in thread
From: Pengpeng Hou @ 2026-06-16 14:14 UTC (permalink / raw)
  To: Vlastimil Babka, Andrew Morton, linux-mm
  Cc: Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, David Hildenbrand, Lorenzo Stoakes, liam,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonathan Corbet,
	Shuah Khan, linux-doc, linux-kernel, Pengpeng Hou

Add KUnit coverage for the previous-lifetime tracking state transition.

The test allocates an object from a SLAB_STORE_USER cache, frees it and
allocates again from the same cache.  The immediate reuse case should move
the completed alloc/free lifetime into the previous-lifetime slots before
the new allocation track is recorded.

Expose a small KUnit-only helper so the test can check the internal
tracking state without parsing printk output or intentionally triggering a
real use-after-free.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 lib/tests/slub_kunit.c | 33 +++++++++++++++++++++++++++++++++
 mm/slab.h              | 10 ++++++++++
 mm/slub.c              | 13 +++++++++++++
 3 files changed, 56 insertions(+)

diff --git a/lib/tests/slub_kunit.c b/lib/tests/slub_kunit.c
index fa6d31dbca16..debd28c7f7a8 100644
--- a/lib/tests/slub_kunit.c
+++ b/lib/tests/slub_kunit.c
@@ -160,6 +160,37 @@ static void test_kmalloc_redzone_access(struct kunit *test)
 	kmem_cache_destroy(s);
 }
 
+static void test_store_user_previous_lifetime(struct kunit *test)
+{
+	struct kmem_cache *s;
+	void *p;
+	void *q;
+
+	s = test_kmem_cache_create("TestSlub_prev_lifetime", 64,
+				   SLAB_STORE_USER | SLAB_NO_MERGE);
+	KUNIT_ASSERT_NOT_NULL(test, s);
+
+	p = kmem_cache_alloc(s, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, p);
+	KUNIT_EXPECT_FALSE(test, slab_test_has_previous_lifetime(s, p));
+
+	kmem_cache_free(s, p);
+
+	q = kmem_cache_alloc(s, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, q);
+	if (q != p) {
+		KUNIT_FAIL(test, "expected immediate reuse of the freed object");
+		kmem_cache_free(s, q);
+		kmem_cache_destroy(s);
+		return;
+	}
+
+	KUNIT_EXPECT_TRUE(test, slab_test_has_previous_lifetime(s, q));
+
+	kmem_cache_free(s, q);
+	kmem_cache_destroy(s);
+}
+
 struct test_kfree_rcu_struct {
 	struct rcu_head rcu;
 };
@@ -400,6 +431,7 @@ static struct kunit_case test_cases[] = {
 
 	KUNIT_CASE(test_clobber_redzone_free),
 	KUNIT_CASE(test_kmalloc_redzone_access),
+	KUNIT_CASE(test_store_user_previous_lifetime),
 	KUNIT_CASE(test_kfree_rcu),
 	KUNIT_CASE(test_kfree_rcu_wq_destroy),
 	KUNIT_CASE(test_leak_destroy),
@@ -419,3 +451,4 @@ kunit_test_suite(test_suite);
 
 MODULE_DESCRIPTION("Kunit tests for slub allocator");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
diff --git a/mm/slab.h b/mm/slab.h
index 1bf9c3021ae3..0b3813696ca9 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -487,6 +487,16 @@ bool slab_in_kunit_test(void);
 static inline bool slab_in_kunit_test(void) { return false; }
 #endif
 
+#if IS_ENABLED(CONFIG_SLUB_KUNIT_TEST)
+bool slab_test_has_previous_lifetime(struct kmem_cache *s, void *object);
+#else
+static inline bool
+slab_test_has_previous_lifetime(struct kmem_cache *s, void *object)
+{
+	return false;
+}
+#endif
+
 /*
  * slub is about to manipulate internal object metadata.  This memory lies
  * outside the range of the allocated object, so accessing it would normally
diff --git a/mm/slub.c b/mm/slub.c
index 358f42e92207..5e94bd1bed81 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -46,6 +46,7 @@
 #include <linux/prandom.h>
 #include <kunit/test.h>
 #include <kunit/test-bug.h>
+#include <kunit/visibility.h>
 #include <linux/sort.h>
 #include <linux/irq_work.h>
 #include <linux/kprobes.h>
@@ -1169,6 +1170,18 @@ void print_tracking(struct kmem_cache *s, void *object)
 	}
 }
 
+#if IS_ENABLED(CONFIG_SLUB_KUNIT_TEST)
+bool slab_test_has_previous_lifetime(struct kmem_cache *s, void *object)
+{
+	if (!(s->flags & SLAB_STORE_USER))
+		return false;
+
+	return track_has_record(get_track(s, object, TRACK_PREV_ALLOC)) &&
+	       track_has_record(get_track(s, object, TRACK_PREV_FREE));
+}
+EXPORT_SYMBOL_IF_KUNIT(slab_test_has_previous_lifetime);
+#endif
+
 static void print_slab_info(const struct slab *slab)
 {
 	pr_err("Slab 0x%p objects=%u used=%u fp=0x%p flags=%pGp\n",
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] Documentation/mm: document SLUB previous lifetime tracking
  2026-06-16 14:14 [PATCH 0/4] mm/slub: preserve previous object lifetime Pengpeng Hou
                   ` (2 preceding siblings ...)
  2026-06-16 14:14 ` [PATCH 3/4] mm/slub: test previous lifetime tracking Pengpeng Hou
@ 2026-06-16 14:14 ` Pengpeng Hou
  3 siblings, 0 replies; 6+ messages in thread
From: Pengpeng Hou @ 2026-06-16 14:14 UTC (permalink / raw)
  To: Vlastimil Babka, Andrew Morton, linux-mm
  Cc: Harry Yoo, Hao Li, Christoph Lameter, David Rientjes,
	Roman Gushchin, David Hildenbrand, Lorenzo Stoakes, liam,
	Mike Rapoport, Suren Baghdasaryan, Michal Hocko, Jonathan Corbet,
	Shuah Khan, linux-doc, linux-kernel, Pengpeng Hou

Document that the U debug option also records one previous completed object
lifetime.  Also document the extra report lines and explicitly state that
the previous lifetime is diagnostic information, not semantic ownership or
root-cause attribution.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 Documentation/admin-guide/mm/slab.rst | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/Documentation/admin-guide/mm/slab.rst b/Documentation/admin-guide/mm/slab.rst
index 14429ab90611..324edf328c34 100644
--- a/Documentation/admin-guide/mm/slab.rst
+++ b/Documentation/admin-guide/mm/slab.rst
@@ -49,7 +49,8 @@ Possible debug options are::
 			Sorry SLAB legacy issues)
 	Z		Red zoning
 	P		Poisoning (object and padding)
-	U		User tracking (free and alloc)
+	U		User tracking (free and alloc, including one previous
+			completed object lifetime)
 	T		Trace (please only use on single slabs)
 	A		Enable failslab filter mark for the cache
 	O		Switch debugging off for caches that would have
@@ -245,9 +246,16 @@ into the syslog:
 	cpu> pid=<pid of the process>
      INFO: Freed in <kernel function> age=<jiffies since free> cpu=<freed by cpu>
 	pid=<pid of the process>
+     INFO: Previous object lifetime:
+     INFO: Previously allocated in <kernel function> age=<jiffies since alloc>
+	cpu=<allocated by cpu> pid=<pid of the process>
+     INFO: Previously freed in <kernel function> age=<jiffies since free>
+	cpu=<freed by cpu> pid=<pid of the process>
 
    (Object allocation / free information is only available if SLAB_STORE_USER is
-   set for the slab. slab_debug sets that option)
+   set for the slab. slab_debug sets that option. The previous object lifetime
+   is diagnostic information for reuse cases and does not identify semantic
+   ownership or the root cause of a use-after-free.)
 
 2. The object contents if an object was involved.
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/4] mm/slub: factor user tracking metadata size calculation
  2026-06-16 14:14 ` [PATCH 1/4] mm/slub: factor user tracking metadata size calculation Pengpeng Hou
@ 2026-06-17  4:26   ` Hao Li
  0 siblings, 0 replies; 6+ messages in thread
From: Hao Li @ 2026-06-17  4:26 UTC (permalink / raw)
  To: Pengpeng Hou
  Cc: Vlastimil Babka, Andrew Morton, linux-mm, Harry Yoo,
	Christoph Lameter, David Rientjes, Roman Gushchin,
	David Hildenbrand, Lorenzo Stoakes, liam, Mike Rapoport,
	Suren Baghdasaryan, Michal Hocko, Jonathan Corbet, Shuah Khan,
	linux-doc, linux-kernel

On Tue, Jun 16, 2026 at 10:14:07PM +0800, Pengpeng Hou wrote:
> SLAB_STORE_USER currently stores two struct track records in the per-object
> debug metadata.  The size is open-coded as 2 * sizeof(struct track) in
> several layout and offset calculations.
> 
> Add TRACK_NR and a small helper for the user-tracking metadata size.  This
> keeps all offset calculations tied to the number of track records and makes
> the following extension less error-prone.
> 
> No functional change.

Do we really need a user_tracking_size helper? This seems introducing some
redundant checking for SLAB_STORE_USER.

For example in set_orig_size(), obj_exts_offset_in_object() and
check_pad_bytes()

redundant checking may be confused...

> 
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
> ---
>  mm/slub.c | 25 ++++++++++++++++---------
>  1 file changed, 16 insertions(+), 9 deletions(-)
> 
> diff --git a/mm/slub.c b/mm/slub.c
> index f87e693aca5d..43d4febd5bf2 100644
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -327,7 +327,15 @@ struct track {
>  	unsigned long when;	/* When did the operation occur */
>  };
>  
> -enum track_item { TRACK_ALLOC, TRACK_FREE };
> +enum track_item { TRACK_ALLOC, TRACK_FREE, TRACK_NR };
> +
> +static inline unsigned int user_tracking_size(slab_flags_t flags)
> +{
> +	if (flags & SLAB_STORE_USER)
> +		return TRACK_NR * sizeof(struct track);
> +
> +	return 0;
> +}
>  
>  #ifdef SLAB_SUPPORTS_SYSFS
>  static int sysfs_slab_add(struct kmem_cache *);
> @@ -751,7 +759,7 @@ static inline void set_orig_size(struct kmem_cache *s,
>  		return;
>  
>  	p += get_info_end(s);
> -	p += sizeof(struct track) * 2;
> +	p += user_tracking_size(s->flags);
>  
>  	*(unsigned long *)p = orig_size;
>  }
> @@ -767,7 +775,7 @@ static inline unsigned long get_orig_size(struct kmem_cache *s, void *object)
>  		return s->object_size;
>  
>  	p += get_info_end(s);
> -	p += sizeof(struct track) * 2;
> +	p += user_tracking_size(s->flags);
>  
>  	return *(unsigned long *)p;
>  }
> @@ -885,7 +893,7 @@ static unsigned int obj_exts_offset_in_object(struct kmem_cache *s)
>  	unsigned int offset = get_info_end(s);
>  
>  	if (kmem_cache_debug_flags(s, SLAB_STORE_USER))
> -		offset += sizeof(struct track) * 2;
> +		offset += user_tracking_size(s->flags);
>  
>  	if (slub_debug_orig_size(s))
>  		offset += sizeof(unsigned long);
> @@ -1088,7 +1096,7 @@ static void init_tracking(struct kmem_cache *s, void *object)
>  		return;
>  
>  	p = get_track(s, object, TRACK_ALLOC);
> -	memset(p, 0, 2*sizeof(struct track));
> +	memset(p, 0, user_tracking_size(s->flags));
>  }
>  
>  static void print_track(const char *s, struct track *t, unsigned long pr_time)
> @@ -1196,8 +1204,7 @@ static void print_trailer(struct kmem_cache *s, struct slab *slab, u8 *p)
>  
>  	off = get_info_end(s);
>  
> -	if (s->flags & SLAB_STORE_USER)
> -		off += 2 * sizeof(struct track);
> +	off += user_tracking_size(s->flags);
>  
>  	if (slub_debug_orig_size(s))
>  		off += sizeof(unsigned long);
> @@ -1401,7 +1408,7 @@ static int check_pad_bytes(struct kmem_cache *s, struct slab *slab, u8 *p)
>  
>  	if (s->flags & SLAB_STORE_USER) {
>  		/* We also have user information there */
> -		off += 2 * sizeof(struct track);
> +		off += user_tracking_size(s->flags);
>  
>  		if (s->flags & SLAB_KMALLOC)
>  			off += sizeof(unsigned long);
> @@ -7820,7 +7827,7 @@ static int calculate_sizes(struct kmem_cache_args *args, struct kmem_cache *s)
>  		 * Need to store information about allocs and frees after
>  		 * the object.
>  		 */
> -		size += 2 * sizeof(struct track);
> +		size += user_tracking_size(flags);
>  
>  		/* Save the original kmalloc request size */
>  		if (flags & SLAB_KMALLOC)
> -- 
> 2.43.0
> 

-- 
Thanks,
Hao

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-06-17  4:26 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-16 14:14 [PATCH 0/4] mm/slub: preserve previous object lifetime Pengpeng Hou
2026-06-16 14:14 ` [PATCH 1/4] mm/slub: factor user tracking metadata size calculation Pengpeng Hou
2026-06-17  4:26   ` Hao Li
2026-06-16 14:14 ` [PATCH 2/4] mm/slub: preserve previous object lifetime in user tracking Pengpeng Hou
2026-06-16 14:14 ` [PATCH 3/4] mm/slub: test previous lifetime tracking Pengpeng Hou
2026-06-16 14:14 ` [PATCH 4/4] Documentation/mm: document SLUB " Pengpeng Hou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox