diff options
-rw-r--r-- | drivers/base/memory.c | 13 | ||||
-rw-r--r-- | mm/memory_hotplug.c | 28 |
2 files changed, 21 insertions, 20 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 40cac122ec73..0e5985682642 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -228,7 +228,6 @@ static bool pages_correctly_probed(unsigned long start_pfn) | |||
228 | /* | 228 | /* |
229 | * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is | 229 | * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is |
230 | * OK to have direct references to sparsemem variables in here. | 230 | * OK to have direct references to sparsemem variables in here. |
231 | * Must already be protected by mem_hotplug_begin(). | ||
232 | */ | 231 | */ |
233 | static int | 232 | static int |
234 | memory_block_action(unsigned long phys_index, unsigned long action, int online_type) | 233 | memory_block_action(unsigned long phys_index, unsigned long action, int online_type) |
@@ -294,7 +293,6 @@ static int memory_subsys_online(struct device *dev) | |||
294 | if (mem->online_type < 0) | 293 | if (mem->online_type < 0) |
295 | mem->online_type = MMOP_ONLINE_KEEP; | 294 | mem->online_type = MMOP_ONLINE_KEEP; |
296 | 295 | ||
297 | /* Already under protection of mem_hotplug_begin() */ | ||
298 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); | 296 | ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE); |
299 | 297 | ||
300 | /* clear online_type */ | 298 | /* clear online_type */ |
@@ -341,19 +339,11 @@ store_mem_state(struct device *dev, | |||
341 | goto err; | 339 | goto err; |
342 | } | 340 | } |
343 | 341 | ||
344 | /* | ||
345 | * Memory hotplug needs to hold mem_hotplug_begin() for probe to find | ||
346 | * the correct memory block to online before doing device_online(dev), | ||
347 | * which will take dev->mutex. Take the lock early to prevent an | ||
348 | * inversion, memory_subsys_online() callbacks will be implemented by | ||
349 | * assuming it's already protected. | ||
350 | */ | ||
351 | mem_hotplug_begin(); | ||
352 | |||
353 | switch (online_type) { | 342 | switch (online_type) { |
354 | case MMOP_ONLINE_KERNEL: | 343 | case MMOP_ONLINE_KERNEL: |
355 | case MMOP_ONLINE_MOVABLE: | 344 | case MMOP_ONLINE_MOVABLE: |
356 | case MMOP_ONLINE_KEEP: | 345 | case MMOP_ONLINE_KEEP: |
346 | /* mem->online_type is protected by device_hotplug_lock */ | ||
357 | mem->online_type = online_type; | 347 | mem->online_type = online_type; |
358 | ret = device_online(&mem->dev); | 348 | ret = device_online(&mem->dev); |
359 | break; | 349 | break; |
@@ -364,7 +354,6 @@ store_mem_state(struct device *dev, | |||
364 | ret = -EINVAL; /* should never happen */ | 354 | ret = -EINVAL; /* should never happen */ |
365 | } | 355 | } |
366 | 356 | ||
367 | mem_hotplug_done(); | ||
368 | err: | 357 | err: |
369 | unlock_device_hotplug(); | 358 | unlock_device_hotplug(); |
370 | 359 | ||
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 39cc887bbdcc..61972da38d93 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -838,7 +838,6 @@ static struct zone * __meminit move_pfn_range(int online_type, int nid, | |||
838 | return zone; | 838 | return zone; |
839 | } | 839 | } |
840 | 840 | ||
841 | /* Must be protected by mem_hotplug_begin() or a device_lock */ | ||
842 | int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_type) | 841 | int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_type) |
843 | { | 842 | { |
844 | unsigned long flags; | 843 | unsigned long flags; |
@@ -850,6 +849,8 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ | |||
850 | struct memory_notify arg; | 849 | struct memory_notify arg; |
851 | struct memory_block *mem; | 850 | struct memory_block *mem; |
852 | 851 | ||
852 | mem_hotplug_begin(); | ||
853 | |||
853 | /* | 854 | /* |
854 | * We can't use pfn_to_nid() because nid might be stored in struct page | 855 | * We can't use pfn_to_nid() because nid might be stored in struct page |
855 | * which is not yet initialized. Instead, we find nid from memory block. | 856 | * which is not yet initialized. Instead, we find nid from memory block. |
@@ -914,6 +915,7 @@ int __ref online_pages(unsigned long pfn, unsigned long nr_pages, int online_typ | |||
914 | 915 | ||
915 | if (onlined_pages) | 916 | if (onlined_pages) |
916 | memory_notify(MEM_ONLINE, &arg); | 917 | memory_notify(MEM_ONLINE, &arg); |
918 | mem_hotplug_done(); | ||
917 | return 0; | 919 | return 0; |
918 | 920 | ||
919 | failed_addition: | 921 | failed_addition: |
@@ -921,6 +923,7 @@ failed_addition: | |||
921 | (unsigned long long) pfn << PAGE_SHIFT, | 923 | (unsigned long long) pfn << PAGE_SHIFT, |
922 | (((unsigned long long) pfn + nr_pages) << PAGE_SHIFT) - 1); | 924 | (((unsigned long long) pfn + nr_pages) << PAGE_SHIFT) - 1); |
923 | memory_notify(MEM_CANCEL_ONLINE, &arg); | 925 | memory_notify(MEM_CANCEL_ONLINE, &arg); |
926 | mem_hotplug_done(); | ||
924 | return ret; | 927 | return ret; |
925 | } | 928 | } |
926 | #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ | 929 | #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */ |
@@ -1125,20 +1128,20 @@ int __ref add_memory_resource(int nid, struct resource *res, bool online) | |||
1125 | /* create new memmap entry */ | 1128 | /* create new memmap entry */ |
1126 | firmware_map_add_hotplug(start, start + size, "System RAM"); | 1129 | firmware_map_add_hotplug(start, start + size, "System RAM"); |
1127 | 1130 | ||
1131 | /* device_online() will take the lock when calling online_pages() */ | ||
1132 | mem_hotplug_done(); | ||
1133 | |||
1128 | /* online pages if requested */ | 1134 | /* online pages if requested */ |
1129 | if (online) | 1135 | if (online) |
1130 | walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), | 1136 | walk_memory_range(PFN_DOWN(start), PFN_UP(start + size - 1), |
1131 | NULL, online_memory_block); | 1137 | NULL, online_memory_block); |
1132 | 1138 | ||
1133 | goto out; | 1139 | return ret; |
1134 | |||
1135 | error: | 1140 | error: |
1136 | /* rollback pgdat allocation and others */ | 1141 | /* rollback pgdat allocation and others */ |
1137 | if (new_node) | 1142 | if (new_node) |
1138 | rollback_node_hotadd(nid); | 1143 | rollback_node_hotadd(nid); |
1139 | memblock_remove(start, size); | 1144 | memblock_remove(start, size); |
1140 | |||
1141 | out: | ||
1142 | mem_hotplug_done(); | 1145 | mem_hotplug_done(); |
1143 | return ret; | 1146 | return ret; |
1144 | } | 1147 | } |
@@ -1555,10 +1558,16 @@ static int __ref __offline_pages(unsigned long start_pfn, | |||
1555 | return -EINVAL; | 1558 | return -EINVAL; |
1556 | if (!IS_ALIGNED(end_pfn, pageblock_nr_pages)) | 1559 | if (!IS_ALIGNED(end_pfn, pageblock_nr_pages)) |
1557 | return -EINVAL; | 1560 | return -EINVAL; |
1561 | |||
1562 | mem_hotplug_begin(); | ||
1563 | |||
1558 | /* This makes hotplug much easier...and readable. | 1564 | /* This makes hotplug much easier...and readable. |
1559 | we assume this for now. .*/ | 1565 | we assume this for now. .*/ |
1560 | if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end)) | 1566 | if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, |
1567 | &valid_end)) { | ||
1568 | mem_hotplug_done(); | ||
1561 | return -EINVAL; | 1569 | return -EINVAL; |
1570 | } | ||
1562 | 1571 | ||
1563 | zone = page_zone(pfn_to_page(valid_start)); | 1572 | zone = page_zone(pfn_to_page(valid_start)); |
1564 | node = zone_to_nid(zone); | 1573 | node = zone_to_nid(zone); |
@@ -1567,8 +1576,10 @@ static int __ref __offline_pages(unsigned long start_pfn, | |||
1567 | /* set above range as isolated */ | 1576 | /* set above range as isolated */ |
1568 | ret = start_isolate_page_range(start_pfn, end_pfn, | 1577 | ret = start_isolate_page_range(start_pfn, end_pfn, |
1569 | MIGRATE_MOVABLE, true); | 1578 | MIGRATE_MOVABLE, true); |
1570 | if (ret) | 1579 | if (ret) { |
1580 | mem_hotplug_done(); | ||
1571 | return ret; | 1581 | return ret; |
1582 | } | ||
1572 | 1583 | ||
1573 | arg.start_pfn = start_pfn; | 1584 | arg.start_pfn = start_pfn; |
1574 | arg.nr_pages = nr_pages; | 1585 | arg.nr_pages = nr_pages; |
@@ -1639,6 +1650,7 @@ repeat: | |||
1639 | writeback_set_ratelimit(); | 1650 | writeback_set_ratelimit(); |
1640 | 1651 | ||
1641 | memory_notify(MEM_OFFLINE, &arg); | 1652 | memory_notify(MEM_OFFLINE, &arg); |
1653 | mem_hotplug_done(); | ||
1642 | return 0; | 1654 | return 0; |
1643 | 1655 | ||
1644 | failed_removal: | 1656 | failed_removal: |
@@ -1648,10 +1660,10 @@ failed_removal: | |||
1648 | memory_notify(MEM_CANCEL_OFFLINE, &arg); | 1660 | memory_notify(MEM_CANCEL_OFFLINE, &arg); |
1649 | /* pushback to free area */ | 1661 | /* pushback to free area */ |
1650 | undo_isolate_page_range(start_pfn, end_pfn, MIGRATE_MOVABLE); | 1662 | undo_isolate_page_range(start_pfn, end_pfn, MIGRATE_MOVABLE); |
1663 | mem_hotplug_done(); | ||
1651 | return ret; | 1664 | return ret; |
1652 | } | 1665 | } |
1653 | 1666 | ||
1654 | /* Must be protected by mem_hotplug_begin() or a device_lock */ | ||
1655 | int offline_pages(unsigned long start_pfn, unsigned long nr_pages) | 1667 | int offline_pages(unsigned long start_pfn, unsigned long nr_pages) |
1656 | { | 1668 | { |
1657 | return __offline_pages(start_pfn, start_pfn + nr_pages); | 1669 | return __offline_pages(start_pfn, start_pfn + nr_pages); |