diff options
-rw-r--r-- | drivers/base/memory.c | 6 | ||||
-rw-r--r-- | include/linux/memory_hotplug.h | 1 | ||||
-rw-r--r-- | mm/memory_hotplug.c | 48 |
3 files changed, 55 insertions, 0 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 83d0b17ba1c2..a51007b79032 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -693,6 +693,12 @@ int offline_memory_block(struct memory_block *mem) | |||
693 | return ret; | 693 | return ret; |
694 | } | 694 | } |
695 | 695 | ||
696 | /* return true if the memory block is offlined, otherwise, return false */ | ||
697 | bool is_memblock_offlined(struct memory_block *mem) | ||
698 | { | ||
699 | return mem->state == MEM_OFFLINE; | ||
700 | } | ||
701 | |||
696 | /* | 702 | /* |
697 | * Initialize the sysfs support for memory devices... | 703 | * Initialize the sysfs support for memory devices... |
698 | */ | 704 | */ |
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 4a45c4e50025..8dd0950a6a7a 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h | |||
@@ -247,6 +247,7 @@ extern int add_memory(int nid, u64 start, u64 size); | |||
247 | extern int arch_add_memory(int nid, u64 start, u64 size); | 247 | extern int arch_add_memory(int nid, u64 start, u64 size); |
248 | extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); | 248 | extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); |
249 | extern int offline_memory_block(struct memory_block *mem); | 249 | extern int offline_memory_block(struct memory_block *mem); |
250 | extern bool is_memblock_offlined(struct memory_block *mem); | ||
250 | extern int remove_memory(u64 start, u64 size); | 251 | extern int remove_memory(u64 start, u64 size); |
251 | extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, | 252 | extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, |
252 | int nr_pages); | 253 | int nr_pages); |
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 6a82972aeae5..5d350f5c68e5 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -1429,6 +1429,54 @@ repeat: | |||
1429 | goto repeat; | 1429 | goto repeat; |
1430 | } | 1430 | } |
1431 | 1431 | ||
1432 | lock_memory_hotplug(); | ||
1433 | |||
1434 | /* | ||
1435 | * we have offlined all memory blocks like this: | ||
1436 | * 1. lock memory hotplug | ||
1437 | * 2. offline a memory block | ||
1438 | * 3. unlock memory hotplug | ||
1439 | * | ||
1440 | * repeat step1-3 to offline the memory block. All memory blocks | ||
1441 | * must be offlined before removing memory. But we don't hold the | ||
1442 | * lock in the whole operation. So we should check whether all | ||
1443 | * memory blocks are offlined. | ||
1444 | */ | ||
1445 | |||
1446 | mem = NULL; | ||
1447 | for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) { | ||
1448 | section_nr = pfn_to_section_nr(pfn); | ||
1449 | if (!present_section_nr(section_nr)) | ||
1450 | continue; | ||
1451 | |||
1452 | section = __nr_to_section(section_nr); | ||
1453 | /* same memblock? */ | ||
1454 | if (mem) | ||
1455 | if ((section_nr >= mem->start_section_nr) && | ||
1456 | (section_nr <= mem->end_section_nr)) | ||
1457 | continue; | ||
1458 | |||
1459 | mem = find_memory_block_hinted(section, mem); | ||
1460 | if (!mem) | ||
1461 | continue; | ||
1462 | |||
1463 | ret = is_memblock_offlined(mem); | ||
1464 | if (!ret) { | ||
1465 | pr_warn("removing memory fails, because memory " | ||
1466 | "[%#010llx-%#010llx] is onlined\n", | ||
1467 | PFN_PHYS(section_nr_to_pfn(mem->start_section_nr)), | ||
1468 | PFN_PHYS(section_nr_to_pfn(mem->end_section_nr + 1)) - 1); | ||
1469 | |||
1470 | kobject_put(&mem->dev.kobj); | ||
1471 | unlock_memory_hotplug(); | ||
1472 | return ret; | ||
1473 | } | ||
1474 | } | ||
1475 | |||
1476 | if (mem) | ||
1477 | kobject_put(&mem->dev.kobj); | ||
1478 | unlock_memory_hotplug(); | ||
1479 | |||
1432 | return 0; | 1480 | return 0; |
1433 | } | 1481 | } |
1434 | #else | 1482 | #else |