Commit f8f1013f authored by Andrew Banman's avatar Andrew Banman Committed by Greg Kroah-Hartman

mm/memory_hotplug.c: check for missing sections in test_pages_in_a_zone()

commit 5f0f2887 upstream.

test_pages_in_a_zone() does not account for the possibility of missing
sections in the given pfn range.  pfn_valid_within always returns 1 when
CONFIG_HOLES_IN_ZONE is not set, allowing invalid pfns from missing
sections to pass the test, leading to a kernel oops.

Wrap an additional pfn loop with PAGES_PER_SECTION granularity to check
for missing sections before proceeding into the zone-check code.

This also prevents a crash from offlining memory devices with missing
sections.  Despite this, it may be a good idea to keep the related patch
'[PATCH 3/3] drivers: memory: prohibit offlining of memory blocks with
missing sections' because missing sections in a memory block may lead to
other problems not covered by the scope of this fix.
Signed-off-by: default avatarAndrew Banman <abanman@sgi.com>
Acked-by: default avatarAlex Thorlton <athorlton@sgi.com>
Cc: Russ Anderson <rja@sgi.com>
Cc: Alex Thorlton <athorlton@sgi.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Greg KH <greg@kroah.com>
Cc: Seth Jennings <sjennings@variantweb.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1631f179
...@@ -1209,16 +1209,22 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) ...@@ -1209,16 +1209,22 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
*/ */
static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
{ {
unsigned long pfn; unsigned long pfn, sec_end_pfn;
struct zone *zone = NULL; struct zone *zone = NULL;
struct page *page; struct page *page;
int i; int i;
for (pfn = start_pfn; for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
pfn < end_pfn; pfn < end_pfn;
pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
/* Make sure the memory section is present first */
if (!present_section_nr(pfn_to_section_nr(pfn)))
continue;
for (; pfn < sec_end_pfn && pfn < end_pfn;
pfn += MAX_ORDER_NR_PAGES) { pfn += MAX_ORDER_NR_PAGES) {
i = 0; i = 0;
/* This is just a CONFIG_HOLES_IN_ZONE check.*/ /* This is just a CONFIG_HOLES_IN_ZONE check.*/
while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i)) while ((i < MAX_ORDER_NR_PAGES) &&
!pfn_valid_within(pfn + i))
i++; i++;
if (i == MAX_ORDER_NR_PAGES) if (i == MAX_ORDER_NR_PAGES)
continue; continue;
...@@ -1227,6 +1233,7 @@ static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn) ...@@ -1227,6 +1233,7 @@ static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
return 0; return 0;
zone = page_zone(page); zone = page_zone(page);
} }
}
return 1; return 1;
} }
......
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