ARM: 6913/1: sparsemem: allow pfn_valid to be overridden when using SPARSEMEM
In commit eb33575c
("[ARM] Double check memmap is actually valid with a
memmap has unexpected holes V2"), a new function, memmap_valid_within,
was introduced to mmzone.h so that holes in the memmap which pass
pfn_valid in SPARSEMEM configurations can be detected and avoided.
The fix to this problem checks that the pfn <-> page linkages are
correct by calculating the page for the pfn and then checking that
page_to_pfn on that page returns the original pfn. Unfortunately, in
SPARSEMEM configurations, this results in reading from the page flags to
determine the correct section. Since the memmap here has been freed,
junk is read from memory and the check is no longer robust.
In the best case, reading from /proc/pagetypeinfo will give you the
wrong answer. In the worst case, you get SEGVs, Kernel OOPses and hung
CPUs. Furthermore, ioremap implementations that use pfn_valid to
disallow the remapping of normal memory will break.
This patch allows architectures to provide their own pfn_valid function
instead of using the default implementation used by sparsemem. The
architecture-specific version is aware of the memmap state and will
return false when passed a pfn for a freed page within a valid section.
Acked-by: Mel Gorman <mgorman@suse.de>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Tested-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
4db70f73e5
commit
7b7bf499f7
|
@ -1516,6 +1516,9 @@ config ARCH_SPARSEMEM_DEFAULT
|
|||
config ARCH_SELECT_MEMORY_MODEL
|
||||
def_bool ARCH_SPARSEMEM_ENABLE
|
||||
|
||||
config HAVE_ARCH_PFN_VALID
|
||||
def_bool ARCH_HAS_HOLES_MEMORYMODEL || !SPARSEMEM
|
||||
|
||||
config HIGHMEM
|
||||
bool "High Memory Support"
|
||||
depends on MMU
|
||||
|
|
|
@ -197,7 +197,7 @@ typedef unsigned long pgprot_t;
|
|||
|
||||
typedef struct page *pgtable_t;
|
||||
|
||||
#ifndef CONFIG_SPARSEMEM
|
||||
#ifdef CONFIG_HAVE_ARCH_PFN_VALID
|
||||
extern int pfn_valid(unsigned long);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -273,13 +273,15 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
|
|||
free_area_init_node(0, zone_size, min, zhole_size);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SPARSEMEM
|
||||
#ifdef CONFIG_HAVE_ARCH_PFN_VALID
|
||||
int pfn_valid(unsigned long pfn)
|
||||
{
|
||||
return memblock_is_memory(pfn << PAGE_SHIFT);
|
||||
}
|
||||
EXPORT_SYMBOL(pfn_valid);
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SPARSEMEM
|
||||
static void arm_memory_present(void)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1056,12 +1056,14 @@ static inline struct mem_section *__pfn_to_section(unsigned long pfn)
|
|||
return __nr_to_section(pfn_to_section_nr(pfn));
|
||||
}
|
||||
|
||||
#ifndef CONFIG_HAVE_ARCH_PFN_VALID
|
||||
static inline int pfn_valid(unsigned long pfn)
|
||||
{
|
||||
if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS)
|
||||
return 0;
|
||||
return valid_section(__nr_to_section(pfn_to_section_nr(pfn)));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int pfn_present(unsigned long pfn)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user