From: Marco Elver <elver@google.com>
To: Caleb Kan <calebkan1106@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>,
linux-mm@kvack.org, linux-kernel@vger.kernel.org,
kasan-dev@googlegroups.com, Vlastimil Babka <vbabka@kernel.org>,
Alexander Potapenko <glider@google.com>,
Dmitry Vyukov <dvyukov@google.com>,
Andrey Konovalov <andreyknvl@gmail.com>,
Oscar Salvador <osalvador@suse.de>,
Caleb Kan <ckan@cloudflare.com>,
kernel-team@cloudflare.com
Subject: Re: [PATCH RFC v2 03/11] mm/page_owner: preserve accounting with countable stack depot records
Date: Tue, 20 Oct 2026 11:11:24 +0000 [thread overview]
Message-ID: <atdMXELJWveehYmX@elver.google.com> (raw)
In-Reply-To: <20260908-stackdepot-trie-v2-3-1996d5cef732@cloudflare.com>
On Tue, Sep 08, 2026 at 02:13PM +0100, Caleb Kan wrote:
> From: Caleb Kan <ckan@cloudflare.com>
>
> page_owner keeps stable struct stack_record pointers in its stack list.
> It uses each record's count with a one-count bias to track live base pages
> and reads the stored entries directly. A later patch adds a trie backend,
> which provides neither a flat record layout nor an independent count field.
>
> Add STACK_DEPOT_FLAG_COUNTABLE to keep these records on the hash backend
> and deduplicate them separately from all non-countable records. Store the
> discriminator in a new u16 flags field and narrow size to u16. This keeps
> the record header size unchanged while covering the configured maximum of
> 256 frames. Do not otherwise split hash-table deduplication: ordinary and
> GET saves can continue to share records. Make COUNTABLE mutually exclusive
> with GET because the two flags assign incompatible meanings to the record
> count. Reject countable records in stack_depot_put() and require COUNTABLE
> in __stack_depot_get_stack_record().
>
> Mark both page_owner save sites countable so its existing accounting and
> reporting continue to use stable hash records. Extend the KUnit coverage to
> verify direct-record access and isolation between countable and
> non-countable records.
>
> Signed-off-by: Caleb Kan <ckan@cloudflare.com>
> ---
> include/linux/stackdepot.h | 28 +++++++++++++++-------
> lib/Kconfig.debug | 3 ++-
> lib/stackdepot.c | 20 +++++++++++++++-
> lib/tests/stackdepot_kunit.c | 55 ++++++++++++++++++++++++++++++++++++++++++++
> mm/page_owner.c | 6 +++--
> 5 files changed, 100 insertions(+), 12 deletions(-)
>
> diff --git a/include/linux/stackdepot.h b/include/linux/stackdepot.h
> index 734529767c8a..7ff67c70d727 100644
> --- a/include/linux/stackdepot.h
> +++ b/include/linux/stackdepot.h
> @@ -53,7 +53,8 @@ union handle_parts {
> struct stack_record {
> struct list_head hash_list; /* Links in the hash table */
> u32 hash; /* Hash in hash table */
> - u32 size; /* Number of stored frames */
> + u16 size; /* Number of stored frames */
> + u16 flags;
> union handle_parts handle; /* Constant after initialization */
> refcount_t count;
> union {
> @@ -84,8 +85,9 @@ typedef u32 depot_flags_t;
> */
> #define STACK_DEPOT_FLAG_CAN_ALLOC ((depot_flags_t)0x0001)
> #define STACK_DEPOT_FLAG_GET ((depot_flags_t)0x0002)
> +#define STACK_DEPOT_FLAG_COUNTABLE ((depot_flags_t)0x0004)
>
> -#define STACK_DEPOT_FLAGS_NUM 2
> +#define STACK_DEPOT_FLAGS_NUM 3
> #define STACK_DEPOT_FLAGS_MASK ((depot_flags_t)((1 << STACK_DEPOT_FLAGS_NUM) - 1))
>
> /*
> @@ -144,6 +146,11 @@ static inline int stack_depot_early_init(void) { return 0; }
> * Users of this flag must also call stack_depot_put() when keeping the stack
> * trace is no longer required to avoid overflowing the refcount.
> *
> + * If STACK_DEPOT_FLAG_COUNTABLE is set in @depot_flags, stack depot stores the
> + * stack in hash-backed storage for callers that need direct stack_record count
> + * access. This flag does not imply %STACK_DEPOT_FLAG_CAN_ALLOC and is mutually
> + * exclusive with %STACK_DEPOT_FLAG_GET.
> + *
> * If the provided stack trace comes from the interrupt context, only the part
> * up to the interrupt entry is saved.
> *
> @@ -178,11 +185,12 @@ depot_stack_handle_t stack_depot_save(unsigned long *entries,
> unsigned int nr_entries, gfp_t alloc_flags);
>
> /**
> - * __stack_depot_get_stack_record - Get a pointer to a stack_record struct
> + * __stack_depot_get_stack_record - Get a hash-backed stack record
> *
> * @handle: Stack depot handle
> *
> - * This function is only for internal purposes.
> + * This function is only for internal purposes. @handle must have been saved
> + * with %STACK_DEPOT_FLAG_COUNTABLE.
> *
> * Return: Returns a pointer to a stack_record struct
> */
> @@ -260,10 +268,14 @@ int stack_depot_snprint(depot_stack_handle_t handle, char *buf, size_t size,
> *
> * @handle: Stack depot handle returned from stack_depot_save()
> *
> - * The stack trace is evicted from stack depot once all references to it have
> - * been dropped (once the number of stack_depot_evict() calls matches the
> - * number of stack_depot_save_flags() calls with STACK_DEPOT_FLAG_GET set for
> - * this stack trace).
> + * Drop a reference acquired by stack_depot_save_flags() with
> + * %STACK_DEPOT_FLAG_GET. Calling this for a handle saved without
> + * %STACK_DEPOT_FLAG_GET is invalid; persistent handles are owned by stack depot
> + * for the lifetime of the system.
> + *
> + * The stack trace is evicted once the number of stack_depot_put() calls matches
> + * the number of successful stack_depot_save_flags() calls with
> + * %STACK_DEPOT_FLAG_GET for this stack trace.
> */
> void stack_depot_put(depot_stack_handle_t handle);
>
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index fcd74edfd93a..3a78c67b6b36 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2792,7 +2792,8 @@ config STACKDEPOT_KUNIT_TEST
> default KUNIT_ALL_TESTS
> help
> Enable this option to test stack depot API behavior at boot.
> - This test is built in, so KUNIT must also be built in.
> + This test is built in because it exercises internal, non-exported
> + stack depot helpers, so KUNIT must also be built in.
>
> KUnit tests run during boot and output the results to the debug log
> in TAP format (https://testanything.org/). Only useful for kernel
> diff --git a/lib/stackdepot.c b/lib/stackdepot.c
> index 4da7279d9f83..66c5e8594566 100644
> --- a/lib/stackdepot.c
> +++ b/lib/stackdepot.c
> @@ -94,6 +94,7 @@ static const char *const counter_names[] = {
> [DEPOT_COUNTER_PERSIST_BYTES] = "persistent_bytes",
> };
> static_assert(ARRAY_SIZE(counter_names) == DEPOT_COUNTER_COUNT);
> +static_assert(CONFIG_STACKDEPOT_MAX_FRAMES <= U16_MAX);
>
> static int __init disable_stack_depot(char *str)
> {
> @@ -467,6 +468,7 @@ depot_alloc_stack(unsigned long *entries, unsigned int nr_entries, u32 hash, dep
> /* Save the stack trace. */
> stack->hash = hash;
> stack->size = nr_entries;
> + stack->flags = flags & STACK_DEPOT_FLAG_COUNTABLE;
> /* stack->handle is already filled in by depot_pop_free_pool(). */
> memcpy(stack->entries, entries, flex_array_size(stack, entries, nr_entries));
>
> @@ -609,6 +611,9 @@ static inline struct stack_record *find_stack(struct list_head *bucket,
> list_for_each_entry_rcu(stack, bucket, hash_list) {
> if (stack->hash != hash || stack->size != size)
> continue;
> + /* Page owner countable records have a distinct count lifetime. */
> + if ((stack->flags ^ flags) & STACK_DEPOT_FLAG_COUNTABLE)
> + continue;
This splits hash deduplication unconditionally even when
stackdepot.trie_enabled=0 (the default), and even for page_owner's
free_handle traces (__reset_page_owner()), which never touch
stack_record->count. Prior to this patch, persistent hash records had
refcount_set(&stack->count, REFCOUNT_SATURATED) and page_owner safely
overwrote it with its 1-biased page count while still sharing records
with non-GET callers.
The interface looks error-prone to me.
next prev parent reply other threads:[~2026-10-20 11:11 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-08 13:13 [PATCH RFC v2 00/11] stackdepot: reduce memory use for persistent stack records with a trie Caleb Kan
2026-09-08 13:13 ` [PATCH RFC v2 01/11] stackdepot: stop preallocating after the final pool Caleb Kan
2026-10-16 16:53 ` Marco Elver
2026-09-08 13:13 ` [PATCH RFC v2 02/11] stackdepot: add caller-owned stack trace fetching Caleb Kan
2026-10-20 11:00 ` Marco Elver
2026-09-08 13:13 ` [PATCH RFC v2 03/11] mm/page_owner: preserve accounting with countable stack depot records Caleb Kan
2026-10-20 11:11 ` Marco Elver [this message]
2026-09-08 13:13 ` [PATCH RFC v2 04/11] mm/kmemleak: print trie-backed stack depot traces Caleb Kan
2026-09-08 13:13 ` [PATCH RFC v2 05/11] kmsan: report " Caleb Kan
2026-10-20 14:53 ` Marco Elver
2026-09-08 13:13 ` [PATCH RFC v2 06/11] mm/slub: materialize " Caleb Kan
2026-09-08 13:13 ` [PATCH RFC v2 07/11] drm/locking: preserve deadlock diagnostics for trie-backed stacks Caleb Kan
2026-09-08 13:13 ` [PATCH RFC v2 08/11] scripts/gdb: reject trie-backed stack depot handles Caleb Kan
2026-09-08 13:13 ` [PATCH RFC v2 09/11] stackdepot: add architecture hooks for compact frame storage Caleb Kan
2026-10-20 14:56 ` Marco Elver
2026-09-08 13:13 ` [PATCH RFC v2 10/11] stackdepot: share persistent stack prefixes with trie storage Caleb Kan
2026-10-20 15:04 ` Marco Elver
2026-09-08 13:13 ` [PATCH RFC v2 11/11] stackdepot: add KUnit tests for " Caleb Kan
2026-10-07 10:34 ` [PATCH RFC v2 00/11] stackdepot: reduce memory use for persistent stack records with a trie Matt Fleming
2026-10-20 15:07 ` Marco Elver
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=atdMXELJWveehYmX@elver.google.com \
--to=elver@google.com \
--cc=akpm@linux-foundation.org \
--cc=andreyknvl@gmail.com \
--cc=calebkan1106@gmail.com \
--cc=ckan@cloudflare.com \
--cc=dvyukov@google.com \
--cc=glider@google.com \
--cc=kasan-dev@googlegroups.com \
--cc=kernel-team@cloudflare.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=osalvador@suse.de \
--cc=vbabka@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox