Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 92821687 authored by Vinayak Menon's avatar Vinayak Menon
Browse files

mm: enable page poisoning early at boot

On SPARSEMEM systems page poisoning is enabled after buddy is up, because
of the dependency on page extension init.  This causes the pages released
by free_all_bootmem not to be poisoned.  This either delays or misses the
identification of some issues because the pages have to undergo another
cycle of alloc-free-alloc for any corruption to be detected.

Enable page poisoning early by getting rid of the PAGE_EXT_DEBUG_POISON
flag.  Since all the free pages will now be poisoned, the flag need not be
verified before checking the poison during an alloc.

Link: http://lkml.kernel.org/r/1490358246-11001-1-git-send-email-vinmenon@codeaurora.org


Acked-by: default avatarLaura Abbott <labbott@redhat.com>
Tested-by: default avatarLaura Abbott <labbott@redhat.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Akinobu Mita <akinobu.mita@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
[vinmenon@codeaurora.org: resolve trivial merge conflicts.
 Remove the redundant free pages RO feature from the
 page_poison.c file which is the reason for conflicts +
 squash the addendum commit 40961ef8d65f51093bc94de110b97b590b6b9275
 ('mm-enable-page-poisoning-early-at-boot-v2')]
Git-commit: c5b7cd344fd6341e6db79e55c0f1f4d1d9c67a7e
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git


Change-Id: I1bb1f99d3a2e1135131911905e0916c837ba9d8a
Signed-off-by: default avatarVinayak Menon <vinmenon@codeaurora.org>
parent ca917719
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -2407,7 +2407,6 @@ extern void copy_user_huge_page(struct page *dst, struct page *src,
#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */

extern struct page_ext_operations debug_guardpage_ops;
extern struct page_ext_operations page_poisoning_ops;

#ifdef CONFIG_DEBUG_PAGEALLOC
extern unsigned int _debug_guardpage_minorder;
+3 −10
Original line number Diff line number Diff line
@@ -1706,10 +1706,10 @@ static inline int check_new_page(struct page *page)
	return 1;
}

static inline bool free_pages_prezeroed(bool poisoned)
static inline bool free_pages_prezeroed(void)
{
	return IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) &&
		page_poisoning_enabled() && poisoned;
		page_poisoning_enabled();
}

#ifdef CONFIG_DEBUG_VM
@@ -1763,17 +1763,10 @@ static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags
							unsigned int alloc_flags)
{
	int i;
	bool poisoned = true;

	for (i = 0; i < (1 << order); i++) {
		struct page *p = page + i;
		if (poisoned)
			poisoned &= page_is_poisoned(p);
	}

	post_alloc_hook(page, order, gfp_flags);

	if (!free_pages_prezeroed(poisoned) && (gfp_flags & __GFP_ZERO))
	if (!free_pages_prezeroed() && (gfp_flags & __GFP_ZERO))
		for (i = 0; i < (1 << order); i++)
			clear_highpage(page + i);

+0 −3
Original line number Diff line number Diff line
@@ -59,9 +59,6 @@

static struct page_ext_operations *page_ext_ops[] = {
	&debug_guardpage_ops,
#ifdef CONFIG_PAGE_POISONING
	&page_poisoning_ops,
#endif
#ifdef CONFIG_PAGE_OWNER
	&page_owner_ops,
#endif
+12 −65
Original line number Diff line number Diff line
@@ -6,7 +6,6 @@
#include <linux/poison.h>
#include <linux/ratelimit.h>

static bool __page_poisoning_enabled __read_mostly;
static bool want_page_poisoning __read_mostly;

static int early_page_poison_param(char *buf)
@@ -18,75 +17,22 @@ static int early_page_poison_param(char *buf)
early_param("page_poison", early_page_poison_param);

bool page_poisoning_enabled(void)
{
	return __page_poisoning_enabled;
}

static bool need_page_poisoning(void)
{
	return want_page_poisoning;
}

static void init_page_poisoning(void)
{
	/*
	 * page poisoning is debug page alloc for some arches. If either
	 * of those options are enabled, enable poisoning
	 * Assumes that debug_pagealloc_enabled is set before
	 * free_all_bootmem.
	 * Page poisoning is debug page alloc for some arches. If
	 * either of those options are enabled, enable poisoning.
	 */
	if (!IS_ENABLED(CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC)) {
		if (!want_page_poisoning && !debug_pagealloc_enabled())
			return;
	} else {
		if (!want_page_poisoning)
			return;
	}

	__page_poisoning_enabled = true;
}

struct page_ext_operations page_poisoning_ops = {
	.need = need_page_poisoning,
	.init = init_page_poisoning,
};

static inline void set_page_poison(struct page *page)
{
	struct page_ext *page_ext;

	page_ext = lookup_page_ext(page);
	if (unlikely(!page_ext))
		return;

	__set_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
}

static inline void clear_page_poison(struct page *page)
{
	struct page_ext *page_ext;

	page_ext = lookup_page_ext(page);
	if (unlikely(!page_ext))
		return;

	__clear_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
}

bool page_is_poisoned(struct page *page)
{
	struct page_ext *page_ext;

	page_ext = lookup_page_ext(page);
	if (unlikely(!page_ext))
		return false;

	return test_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
	return (want_page_poisoning ||
		(!IS_ENABLED(CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC) &&
		debug_pagealloc_enabled()));
}

static void poison_page(struct page *page)
{
	void *addr = kmap_atomic(page);

	set_page_poison(page);
	memset(addr, PAGE_POISON, PAGE_SIZE);
	kunmap_atomic(addr);
}
@@ -144,12 +90,13 @@ static void unpoison_page(struct page *page)
{
	void *addr;

	if (!page_is_poisoned(page))
		return;

	addr = kmap_atomic(page);
	/*
	 * Page poisoning when enabled poisons each and every page
	 * that is freed to buddy. Thus no extra check is done to
	 * see if a page was posioned.
	 */
	check_poison_mem(page, addr, PAGE_SIZE);
	clear_page_poison(page);
	kunmap_atomic(addr);
}