aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/base/memory.c6
-rw-r--r--include/linux/memory_hotplug.h1
-rw-r--r--mm/memory_hotplug.c48
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 */
697bool 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);
247extern int arch_add_memory(int nid, u64 start, u64 size); 247extern int arch_add_memory(int nid, u64 start, u64 size);
248extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); 248extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
249extern int offline_memory_block(struct memory_block *mem); 249extern int offline_memory_block(struct memory_block *mem);
250extern bool is_memblock_offlined(struct memory_block *mem);
250extern int remove_memory(u64 start, u64 size); 251extern int remove_memory(u64 start, u64 size);
251extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn, 252extern 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