mm, debug_pagelloc: use static keys to enable debugging
Patch series "debug_pagealloc improvements".
I have been recently debugging some pcplist corruptions, where it would be
useful to perform struct page checks immediately as pages are allocated
from and freed to pcplists, which is now only possible by rebuilding the
kernel with CONFIG_DEBUG_VM (details in Patch 2 changelog).
To make this kind of debugging simpler in future on a distro kernel, I
have improved CONFIG_DEBUG_PAGEALLOC so that it has even smaller overhead
when not enabled at boot time (Patch 1) and also when enabled (Patch 3),
and extended it to perform the struct page checks more often when enabled
(Patch 2). Now it can be configured in when building a distro kernel
without extra overhead, and debugging page use after free or double free
can be enabled simply by rebooting with debug_pagealloc=on.
This patch (of 3):
CONFIG_DEBUG_PAGEALLOC has been redesigned by 031bc5743f
("mm/debug-pagealloc: make debug-pagealloc boottime configurable") to
allow being always enabled in a distro kernel, but only perform its
expensive functionality when booted with debug_pagelloc=on. We can
further reduce the overhead when not boot-enabled (including page
allocator fast paths) using static keys. This patch introduces one for
debug_pagealloc core functionality, and another for the optional guard
page functionality (enabled by booting with debug_guardpage_minorder=X).
Link: http://lkml.kernel.org/r/20190603143451.27353-2-vbabka@suse.cz
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
a9659476d4
commit
96a2b03f28
|
@ -2701,11 +2701,18 @@ static inline void kernel_poison_pages(struct page *page, int numpages,
|
||||||
int enable) { }
|
int enable) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern bool _debug_pagealloc_enabled;
|
#ifdef CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT
|
||||||
|
DECLARE_STATIC_KEY_TRUE(_debug_pagealloc_enabled);
|
||||||
|
#else
|
||||||
|
DECLARE_STATIC_KEY_FALSE(_debug_pagealloc_enabled);
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline bool debug_pagealloc_enabled(void)
|
static inline bool debug_pagealloc_enabled(void)
|
||||||
{
|
{
|
||||||
return IS_ENABLED(CONFIG_DEBUG_PAGEALLOC) && _debug_pagealloc_enabled;
|
if (!IS_ENABLED(CONFIG_DEBUG_PAGEALLOC))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return static_branch_unlikely(&_debug_pagealloc_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP)
|
#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_ARCH_HAS_SET_DIRECT_MAP)
|
||||||
|
@ -2859,7 +2866,7 @@ extern struct page_ext_operations debug_guardpage_ops;
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_PAGEALLOC
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||||
extern unsigned int _debug_guardpage_minorder;
|
extern unsigned int _debug_guardpage_minorder;
|
||||||
extern bool _debug_guardpage_enabled;
|
DECLARE_STATIC_KEY_FALSE(_debug_guardpage_enabled);
|
||||||
|
|
||||||
static inline unsigned int debug_guardpage_minorder(void)
|
static inline unsigned int debug_guardpage_minorder(void)
|
||||||
{
|
{
|
||||||
|
@ -2868,7 +2875,7 @@ static inline unsigned int debug_guardpage_minorder(void)
|
||||||
|
|
||||||
static inline bool debug_guardpage_enabled(void)
|
static inline bool debug_guardpage_enabled(void)
|
||||||
{
|
{
|
||||||
return _debug_guardpage_enabled;
|
return static_branch_unlikely(&_debug_guardpage_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool page_is_guard(struct page *page)
|
static inline bool page_is_guard(struct page *page)
|
||||||
|
|
|
@ -644,16 +644,27 @@ void prep_compound_page(struct page *page, unsigned int order)
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_PAGEALLOC
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
||||||
unsigned int _debug_guardpage_minorder;
|
unsigned int _debug_guardpage_minorder;
|
||||||
bool _debug_pagealloc_enabled __read_mostly
|
|
||||||
= IS_ENABLED(CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT);
|
#ifdef CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT
|
||||||
|
DEFINE_STATIC_KEY_TRUE(_debug_pagealloc_enabled);
|
||||||
|
#else
|
||||||
|
DEFINE_STATIC_KEY_FALSE(_debug_pagealloc_enabled);
|
||||||
|
#endif
|
||||||
EXPORT_SYMBOL(_debug_pagealloc_enabled);
|
EXPORT_SYMBOL(_debug_pagealloc_enabled);
|
||||||
bool _debug_guardpage_enabled __read_mostly;
|
|
||||||
|
DEFINE_STATIC_KEY_FALSE(_debug_guardpage_enabled);
|
||||||
|
|
||||||
static int __init early_debug_pagealloc(char *buf)
|
static int __init early_debug_pagealloc(char *buf)
|
||||||
{
|
{
|
||||||
if (!buf)
|
bool enable = false;
|
||||||
|
|
||||||
|
if (kstrtobool(buf, &enable))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return kstrtobool(buf, &_debug_pagealloc_enabled);
|
|
||||||
|
if (enable)
|
||||||
|
static_branch_enable(&_debug_pagealloc_enabled);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
early_param("debug_pagealloc", early_debug_pagealloc);
|
early_param("debug_pagealloc", early_debug_pagealloc);
|
||||||
|
|
||||||
|
@ -677,7 +688,7 @@ static void init_debug_guardpage(void)
|
||||||
if (!debug_guardpage_minorder())
|
if (!debug_guardpage_minorder())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_debug_guardpage_enabled = true;
|
static_branch_enable(&_debug_guardpage_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct page_ext_operations debug_guardpage_ops = {
|
struct page_ext_operations debug_guardpage_ops = {
|
||||||
|
|
Loading…
Reference in New Issue