[PATCH] drivers: memory: check for missing sections in test_pages_in_a_zone

2015-12-11 Thread Andrew Banman
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.

Patch applies cleanly to current mainline (b9d85451ddd) and the stable
branches back to 3.18.y.

Signed-off-by: Andrew Banman 
Acked-by: Alex Thorlton 
Cc: Russ Anderson 
Cc: Alex Thorlton 
Cc: Yinghai Lu 
Cc: Greg KH 
Cc: Seth Jennings 
Cc: 

---
 mm/memory_hotplug.c | 32 
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 67d488a..0c5f876 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1375,23 +1375,30 @@ int is_mem_section_removable(unsigned long start_pfn, 
unsigned long nr_pages)
  */
 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 page *page;
int i;
-   for (pfn = start_pfn;
+   for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
 pfn < end_pfn;
-pfn += MAX_ORDER_NR_PAGES) {
-   i = 0;
-   /* This is just a CONFIG_HOLES_IN_ZONE check.*/
-   while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
-   i++;
-   if (i == MAX_ORDER_NR_PAGES)
+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;
-   page = pfn_to_page(pfn + i);
-   if (zone && page_zone(page) != zone)
-   return 0;
-   zone = page_zone(page);
+   for (; pfn < sec_end_pfn && pfn < end_pfn;
+pfn += MAX_ORDER_NR_PAGES) {
+   i = 0;
+   /* This is just a CONFIG_HOLES_IN_ZONE check.*/
+   while ((i < MAX_ORDER_NR_PAGES) &&
+   !pfn_valid_within(pfn + i))
+   i++;
+   if (i == MAX_ORDER_NR_PAGES)
+   continue;
+   page = pfn_to_page(pfn + i);
+   if (zone && page_zone(page) != zone)
+   return 0;
+   zone = page_zone(page);
+   }
}
return 1;
 }
-- 
1.7.12.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] drivers: memory: check for missing sections in test_pages_in_a_zone

2015-12-11 Thread andrew banman
On Fri, Dec 11, 2015 at 04:21:03PM -0600, Andrew Banman wrote:
> 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.
> 
> ---

Oops, the signed-off-by got absorbed the email headers. I'll resend. The patch
applies cleanly to the current mainline and to the 4.3.2 and 4.2.7 stable
branches. I'll edit the patch description to reflect that as well.

- Andrew
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] drivers: memory: check for missing sections in test_pages_in_a_zone

2015-12-11 Thread Andrew Banman
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.

---
 mm/memory_hotplug.c | 32 
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 67d488a..0c5f876 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1375,23 +1375,30 @@ int is_mem_section_removable(unsigned long start_pfn, 
unsigned long nr_pages)
  */
 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 page *page;
int i;
-   for (pfn = start_pfn;
+   for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
 pfn < end_pfn;
-pfn += MAX_ORDER_NR_PAGES) {
-   i = 0;
-   /* This is just a CONFIG_HOLES_IN_ZONE check.*/
-   while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
-   i++;
-   if (i == MAX_ORDER_NR_PAGES)
+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;
-   page = pfn_to_page(pfn + i);
-   if (zone && page_zone(page) != zone)
-   return 0;
-   zone = page_zone(page);
+   for (; pfn < sec_end_pfn && pfn < end_pfn;
+pfn += MAX_ORDER_NR_PAGES) {
+   i = 0;
+   /* This is just a CONFIG_HOLES_IN_ZONE check.*/
+   while ((i < MAX_ORDER_NR_PAGES) &&
+   !pfn_valid_within(pfn + i))
+   i++;
+   if (i == MAX_ORDER_NR_PAGES)
+   continue;
+   page = pfn_to_page(pfn + i);
+   if (zone && page_zone(page) != zone)
+   return 0;
+   zone = page_zone(page);
+   }
}
return 1;
 }
-- 
1.7.12.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] drivers: memory: check for missing sections in test_pages_in_a_zone

2015-12-11 Thread andrew banman
On Fri, Dec 11, 2015 at 04:21:03PM -0600, Andrew Banman wrote:
> 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.
> 
> ---

Oops, the signed-off-by got absorbed the email headers. I'll resend. The patch
applies cleanly to the current mainline and to the 4.3.2 and 4.2.7 stable
branches. I'll edit the patch description to reflect that as well.

- Andrew
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] drivers: memory: check for missing sections in test_pages_in_a_zone

2015-12-11 Thread Andrew Banman
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.

---
 mm/memory_hotplug.c | 32 
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 67d488a..0c5f876 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1375,23 +1375,30 @@ int is_mem_section_removable(unsigned long start_pfn, 
unsigned long nr_pages)
  */
 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 page *page;
int i;
-   for (pfn = start_pfn;
+   for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
 pfn < end_pfn;
-pfn += MAX_ORDER_NR_PAGES) {
-   i = 0;
-   /* This is just a CONFIG_HOLES_IN_ZONE check.*/
-   while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
-   i++;
-   if (i == MAX_ORDER_NR_PAGES)
+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;
-   page = pfn_to_page(pfn + i);
-   if (zone && page_zone(page) != zone)
-   return 0;
-   zone = page_zone(page);
+   for (; pfn < sec_end_pfn && pfn < end_pfn;
+pfn += MAX_ORDER_NR_PAGES) {
+   i = 0;
+   /* This is just a CONFIG_HOLES_IN_ZONE check.*/
+   while ((i < MAX_ORDER_NR_PAGES) &&
+   !pfn_valid_within(pfn + i))
+   i++;
+   if (i == MAX_ORDER_NR_PAGES)
+   continue;
+   page = pfn_to_page(pfn + i);
+   if (zone && page_zone(page) != zone)
+   return 0;
+   zone = page_zone(page);
+   }
}
return 1;
 }
-- 
1.7.12.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] drivers: memory: check for missing sections in test_pages_in_a_zone

2015-12-11 Thread Andrew Banman
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.

Patch applies cleanly to current mainline (b9d85451ddd) and the stable
branches back to 3.18.y.

Signed-off-by: Andrew Banman 
Acked-by: Alex Thorlton 
Cc: Russ Anderson 
Cc: Alex Thorlton 
Cc: Yinghai Lu 
Cc: Greg KH 
Cc: Seth Jennings 
Cc: 

---
 mm/memory_hotplug.c | 32 
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 67d488a..0c5f876 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1375,23 +1375,30 @@ int is_mem_section_removable(unsigned long start_pfn, 
unsigned long nr_pages)
  */
 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 page *page;
int i;
-   for (pfn = start_pfn;
+   for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
 pfn < end_pfn;
-pfn += MAX_ORDER_NR_PAGES) {
-   i = 0;
-   /* This is just a CONFIG_HOLES_IN_ZONE check.*/
-   while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
-   i++;
-   if (i == MAX_ORDER_NR_PAGES)
+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;
-   page = pfn_to_page(pfn + i);
-   if (zone && page_zone(page) != zone)
-   return 0;
-   zone = page_zone(page);
+   for (; pfn < sec_end_pfn && pfn < end_pfn;
+pfn += MAX_ORDER_NR_PAGES) {
+   i = 0;
+   /* This is just a CONFIG_HOLES_IN_ZONE check.*/
+   while ((i < MAX_ORDER_NR_PAGES) &&
+   !pfn_valid_within(pfn + i))
+   i++;
+   if (i == MAX_ORDER_NR_PAGES)
+   continue;
+   page = pfn_to_page(pfn + i);
+   if (zone && page_zone(page) != zone)
+   return 0;
+   zone = page_zone(page);
+   }
}
return 1;
 }
-- 
1.7.12.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/