* [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* 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
* [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