Commit dcfe378c authored by Suren Baghdasaryan's avatar Suren Baghdasaryan Committed by Andrew Morton

lib: introduce support for page allocation tagging

Introduce helper functions to easily instrument page allocators by storing
a pointer to the allocation tag associated with the code that allocated
the page in a page_ext field.

Link: https://lkml.kernel.org/r/20240321163705.3067592-15-surenb@google.comSigned-off-by: default avatarSuren Baghdasaryan <surenb@google.com>
Co-developed-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
Reviewed-by: default avatarVlastimil Babka <vbabka@suse.cz>
Tested-by: default avatarKees Cook <keescook@chromium.org>
Cc: Alexander Viro <viro@zeniv.linux.org.uk>
Cc: Alex Gaynor <alex.gaynor@gmail.com>
Cc: Alice Ryhl <aliceryhl@google.com>
Cc: Andreas Hindborg <a.hindborg@samsung.com>
Cc: Benno Lossin <benno.lossin@proton.me>
Cc: "Björn Roy Baron" <bjorn3_gh@protonmail.com>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Christoph Lameter <cl@linux.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Gary Guo <gary@garyguo.net>
Cc: Miguel Ojeda <ojeda@kernel.org>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tejun Heo <tj@kernel.org>
Cc: Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 22d407b1
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
#include <linux/stackdepot.h>
struct pglist_data; struct pglist_data;
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* page allocation tagging
*/
#ifndef _LINUX_PGALLOC_TAG_H
#define _LINUX_PGALLOC_TAG_H
#include <linux/alloc_tag.h>
#ifdef CONFIG_MEM_ALLOC_PROFILING
#include <linux/page_ext.h>
extern struct page_ext_operations page_alloc_tagging_ops;
extern struct page_ext *page_ext_get(struct page *page);
extern void page_ext_put(struct page_ext *page_ext);
static inline union codetag_ref *codetag_ref_from_page_ext(struct page_ext *page_ext)
{
return (void *)page_ext + page_alloc_tagging_ops.offset;
}
static inline struct page_ext *page_ext_from_codetag_ref(union codetag_ref *ref)
{
return (void *)ref - page_alloc_tagging_ops.offset;
}
/* Should be called only if mem_alloc_profiling_enabled() */
static inline union codetag_ref *get_page_tag_ref(struct page *page)
{
if (page) {
struct page_ext *page_ext = page_ext_get(page);
if (page_ext)
return codetag_ref_from_page_ext(page_ext);
}
return NULL;
}
static inline void put_page_tag_ref(union codetag_ref *ref)
{
page_ext_put(page_ext_from_codetag_ref(ref));
}
static inline void pgalloc_tag_add(struct page *page, struct task_struct *task,
unsigned int nr)
{
if (mem_alloc_profiling_enabled()) {
union codetag_ref *ref = get_page_tag_ref(page);
if (ref) {
alloc_tag_add(ref, task->alloc_tag, PAGE_SIZE * nr);
put_page_tag_ref(ref);
}
}
}
static inline void pgalloc_tag_sub(struct page *page, unsigned int nr)
{
if (mem_alloc_profiling_enabled()) {
union codetag_ref *ref = get_page_tag_ref(page);
if (ref) {
alloc_tag_sub(ref, PAGE_SIZE * nr);
put_page_tag_ref(ref);
}
}
}
#else /* CONFIG_MEM_ALLOC_PROFILING */
static inline void pgalloc_tag_add(struct page *page, struct task_struct *task,
unsigned int nr) {}
static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {}
#endif /* CONFIG_MEM_ALLOC_PROFILING */
#endif /* _LINUX_PGALLOC_TAG_H */
...@@ -978,6 +978,7 @@ config MEM_ALLOC_PROFILING ...@@ -978,6 +978,7 @@ config MEM_ALLOC_PROFILING
depends on PROC_FS depends on PROC_FS
depends on !DEBUG_FORCE_WEAK_PER_CPU depends on !DEBUG_FORCE_WEAK_PER_CPU
select CODE_TAGGING select CODE_TAGGING
select PAGE_EXTENSION
help help
Track allocation source code and record total allocation size Track allocation source code and record total allocation size
initiated at that code location. The mechanism can be used to track initiated at that code location. The mechanism can be used to track
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/page_ext.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_buf.h> #include <linux/seq_buf.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
...@@ -118,6 +119,22 @@ static bool alloc_tag_module_unload(struct codetag_type *cttype, ...@@ -118,6 +119,22 @@ static bool alloc_tag_module_unload(struct codetag_type *cttype,
return module_unused; return module_unused;
} }
static __init bool need_page_alloc_tagging(void)
{
return true;
}
static __init void init_page_alloc_tagging(void)
{
}
struct page_ext_operations page_alloc_tagging_ops = {
.size = sizeof(union codetag_ref),
.need = need_page_alloc_tagging,
.init = init_page_alloc_tagging,
};
EXPORT_SYMBOL(page_alloc_tagging_ops);
static struct ctl_table memory_allocation_profiling_sysctls[] = { static struct ctl_table memory_allocation_profiling_sysctls[] = {
{ {
.procname = "mem_profiling", .procname = "mem_profiling",
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/page_ext.h> #include <linux/page_ext.h>
#include <linux/pti.h> #include <linux/pti.h>
#include <linux/pgtable.h> #include <linux/pgtable.h>
#include <linux/stackdepot.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/cma.h> #include <linux/cma.h>
#include <linux/crash_dump.h> #include <linux/crash_dump.h>
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <linux/khugepaged.h> #include <linux/khugepaged.h>
#include <linux/delayacct.h> #include <linux/delayacct.h>
#include <linux/cacheinfo.h> #include <linux/cacheinfo.h>
#include <linux/pgalloc_tag.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "internal.h" #include "internal.h"
#include "shuffle.h" #include "shuffle.h"
...@@ -1101,6 +1102,7 @@ __always_inline bool free_pages_prepare(struct page *page, ...@@ -1101,6 +1102,7 @@ __always_inline bool free_pages_prepare(struct page *page,
/* Do not let hwpoison pages hit pcplists/buddy */ /* Do not let hwpoison pages hit pcplists/buddy */
reset_page_owner(page, order); reset_page_owner(page, order);
page_table_check_free(page, order); page_table_check_free(page, order);
pgalloc_tag_sub(page, 1 << order);
return false; return false;
} }
...@@ -1140,6 +1142,7 @@ __always_inline bool free_pages_prepare(struct page *page, ...@@ -1140,6 +1142,7 @@ __always_inline bool free_pages_prepare(struct page *page,
page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP;
reset_page_owner(page, order); reset_page_owner(page, order);
page_table_check_free(page, order); page_table_check_free(page, order);
pgalloc_tag_sub(page, 1 << order);
if (!PageHighMem(page)) { if (!PageHighMem(page)) {
debug_check_no_locks_freed(page_address(page), debug_check_no_locks_freed(page_address(page),
...@@ -1533,6 +1536,7 @@ inline void post_alloc_hook(struct page *page, unsigned int order, ...@@ -1533,6 +1536,7 @@ inline void post_alloc_hook(struct page *page, unsigned int order,
set_page_owner(page, order, gfp_flags); set_page_owner(page, order, gfp_flags);
page_table_check_alloc(page, order); page_table_check_alloc(page, order);
pgalloc_tag_add(page, current, 1 << order);
} }
static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/page_idle.h> #include <linux/page_idle.h>
#include <linux/page_table_check.h> #include <linux/page_table_check.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/pgalloc_tag.h>
/* /*
* struct page extension * struct page extension
...@@ -82,6 +83,9 @@ static struct page_ext_operations *page_ext_ops[] __initdata = { ...@@ -82,6 +83,9 @@ static struct page_ext_operations *page_ext_ops[] __initdata = {
#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT) #if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT)
&page_idle_ops, &page_idle_ops,
#endif #endif
#ifdef CONFIG_MEM_ALLOC_PROFILING
&page_alloc_tagging_ops,
#endif
#ifdef CONFIG_PAGE_TABLE_CHECK #ifdef CONFIG_PAGE_TABLE_CHECK
&page_table_check_ops, &page_table_check_ops,
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment