History

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

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.

Andrew Banman committed 10 years ago

Commit 5f0f2881 parent b5a8bc31 file · +19 −12Browse files

Unified · Split

mm/memory_hotplug.c+19−12
@@ -1375,23 +1375,30 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) · 1374 unmodified lines
1375 */1375 */
1376int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)1376int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
1377{1377{
1378 unsigned long pfn;1378 unsigned long pfn, sec_end_pfn;
1379 struct zone *zone = NULL;1379 struct zone *zone = NULL;
1380 struct page *page;1380 struct page *page;
1381 int i;1381 int i;
1382 for (pfn = start_pfn;1382 for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
1383 pfn < end_pfn;1383 pfn < end_pfn;
1384 pfn += MAX_ORDER_NR_PAGES) {1384 pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
1385 i = 0;1385 /* Make sure the memory section is present first */
1386 /* This is just a CONFIG_HOLES_IN_ZONE check.*/1386 if (!present_section_nr(pfn_to_section_nr(pfn)))
1387 while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
1388 i++;
1389 if (i == MAX_ORDER_NR_PAGES)
1390 continue;1387 continue;
1391 page = pfn_to_page(pfn + i);1388 for (; pfn < sec_end_pfn && pfn < end_pfn;
1392 if (zone && page_zone(page) != zone)1389 pfn += MAX_ORDER_NR_PAGES) {
1393 return 0;1390 i = 0;
1394 zone = page_zone(page);1391 /* This is just a CONFIG_HOLES_IN_ZONE check.*/
1392 while ((i < MAX_ORDER_NR_PAGES) &&
1393 !pfn_valid_within(pfn + i))
1394 i++;
1395 if (i == MAX_ORDER_NR_PAGES)
1396 continue;
1397 page = pfn_to_page(pfn + i);
1398 if (zone && page_zone(page) != zone)
1399 return 0;
1400 zone = page_zone(page);
1401 }
1395 }1402 }
1396 return 1;1403 return 1;
1397}1404}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t