diff options
-rw-r--r-- | include/linux/memory_hotplug.h | 4 | ||||
-rw-r--r-- | mm/memory_hotplug.c | 17 | ||||
-rw-r--r-- | mm/page_alloc.c | 87 |
3 files changed, 72 insertions, 36 deletions
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 864035fb8f8a..4307231bd22f 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h | |||
@@ -70,6 +70,10 @@ extern void online_page(struct page *page); | |||
70 | extern int online_pages(unsigned long, unsigned long); | 70 | extern int online_pages(unsigned long, unsigned long); |
71 | extern void __offline_isolated_pages(unsigned long, unsigned long); | 71 | extern void __offline_isolated_pages(unsigned long, unsigned long); |
72 | 72 | ||
73 | #ifdef CONFIG_MEMORY_HOTREMOVE | ||
74 | extern bool is_pageblock_removable_nolock(struct page *page); | ||
75 | #endif /* CONFIG_MEMORY_HOTREMOVE */ | ||
76 | |||
73 | /* reasonably generic interface to expand the physical pages in a zone */ | 77 | /* reasonably generic interface to expand the physical pages in a zone */ |
74 | extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn, | 78 | extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn, |
75 | unsigned long nr_pages); | 79 | unsigned long nr_pages); |
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 4821338b4e4b..b0dc65452973 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -602,27 +602,14 @@ static struct page *next_active_pageblock(struct page *page) | |||
602 | /* Checks if this range of memory is likely to be hot-removable. */ | 602 | /* Checks if this range of memory is likely to be hot-removable. */ |
603 | int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) | 603 | int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages) |
604 | { | 604 | { |
605 | int type; | ||
606 | struct page *page = pfn_to_page(start_pfn); | 605 | struct page *page = pfn_to_page(start_pfn); |
607 | struct page *end_page = page + nr_pages; | 606 | struct page *end_page = page + nr_pages; |
608 | 607 | ||
609 | /* Check the starting page of each pageblock within the range */ | 608 | /* Check the starting page of each pageblock within the range */ |
610 | for (; page < end_page; page = next_active_pageblock(page)) { | 609 | for (; page < end_page; page = next_active_pageblock(page)) { |
611 | type = get_pageblock_migratetype(page); | 610 | if (!is_pageblock_removable_nolock(page)) |
612 | |||
613 | /* | ||
614 | * A pageblock containing MOVABLE or free pages is considered | ||
615 | * removable | ||
616 | */ | ||
617 | if (type != MIGRATE_MOVABLE && !pageblock_free(page)) | ||
618 | return 0; | ||
619 | |||
620 | /* | ||
621 | * A pageblock starting with a PageReserved page is not | ||
622 | * considered removable. | ||
623 | */ | ||
624 | if (PageReserved(page)) | ||
625 | return 0; | 611 | return 0; |
612 | cond_resched(); | ||
626 | } | 613 | } |
627 | 614 | ||
628 | /* All pageblocks in the memory block are likely to be hot-removable */ | 615 | /* All pageblocks in the memory block are likely to be hot-removable */ |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 099790052bfe..6a683f819439 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -5297,12 +5297,65 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags, | |||
5297 | * page allocater never alloc memory from ISOLATE block. | 5297 | * page allocater never alloc memory from ISOLATE block. |
5298 | */ | 5298 | */ |
5299 | 5299 | ||
5300 | static int | ||
5301 | __count_immobile_pages(struct zone *zone, struct page *page, int count) | ||
5302 | { | ||
5303 | unsigned long pfn, iter, found; | ||
5304 | /* | ||
5305 | * For avoiding noise data, lru_add_drain_all() should be called | ||
5306 | * If ZONE_MOVABLE, the zone never contains immobile pages | ||
5307 | */ | ||
5308 | if (zone_idx(zone) == ZONE_MOVABLE) | ||
5309 | return true; | ||
5310 | |||
5311 | if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE) | ||
5312 | return true; | ||
5313 | |||
5314 | pfn = page_to_pfn(page); | ||
5315 | for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) { | ||
5316 | unsigned long check = pfn + iter; | ||
5317 | |||
5318 | if (!pfn_valid_within(check)) { | ||
5319 | iter++; | ||
5320 | continue; | ||
5321 | } | ||
5322 | page = pfn_to_page(check); | ||
5323 | if (!page_count(page)) { | ||
5324 | if (PageBuddy(page)) | ||
5325 | iter += (1 << page_order(page)) - 1; | ||
5326 | continue; | ||
5327 | } | ||
5328 | if (!PageLRU(page)) | ||
5329 | found++; | ||
5330 | /* | ||
5331 | * If there are RECLAIMABLE pages, we need to check it. | ||
5332 | * But now, memory offline itself doesn't call shrink_slab() | ||
5333 | * and it still to be fixed. | ||
5334 | */ | ||
5335 | /* | ||
5336 | * If the page is not RAM, page_count()should be 0. | ||
5337 | * we don't need more check. This is an _used_ not-movable page. | ||
5338 | * | ||
5339 | * The problematic thing here is PG_reserved pages. PG_reserved | ||
5340 | * is set to both of a memory hole page and a _used_ kernel | ||
5341 | * page at boot. | ||
5342 | */ | ||
5343 | if (found > count) | ||
5344 | return false; | ||
5345 | } | ||
5346 | return true; | ||
5347 | } | ||
5348 | |||
5349 | bool is_pageblock_removable_nolock(struct page *page) | ||
5350 | { | ||
5351 | struct zone *zone = page_zone(page); | ||
5352 | return __count_immobile_pages(zone, page, 0); | ||
5353 | } | ||
5354 | |||
5300 | int set_migratetype_isolate(struct page *page) | 5355 | int set_migratetype_isolate(struct page *page) |
5301 | { | 5356 | { |
5302 | struct zone *zone; | 5357 | struct zone *zone; |
5303 | struct page *curr_page; | 5358 | unsigned long flags, pfn; |
5304 | unsigned long flags, pfn, iter; | ||
5305 | unsigned long immobile = 0; | ||
5306 | struct memory_isolate_notify arg; | 5359 | struct memory_isolate_notify arg; |
5307 | int notifier_ret; | 5360 | int notifier_ret; |
5308 | int ret = -EBUSY; | 5361 | int ret = -EBUSY; |
@@ -5312,11 +5365,6 @@ int set_migratetype_isolate(struct page *page) | |||
5312 | zone_idx = zone_idx(zone); | 5365 | zone_idx = zone_idx(zone); |
5313 | 5366 | ||
5314 | spin_lock_irqsave(&zone->lock, flags); | 5367 | spin_lock_irqsave(&zone->lock, flags); |
5315 | if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE || | ||
5316 | zone_idx == ZONE_MOVABLE) { | ||
5317 | ret = 0; | ||
5318 | goto out; | ||
5319 | } | ||
5320 | 5368 | ||
5321 | pfn = page_to_pfn(page); | 5369 | pfn = page_to_pfn(page); |
5322 | arg.start_pfn = pfn; | 5370 | arg.start_pfn = pfn; |
@@ -5338,21 +5386,18 @@ int set_migratetype_isolate(struct page *page) | |||
5338 | notifier_ret = notifier_to_errno(notifier_ret); | 5386 | notifier_ret = notifier_to_errno(notifier_ret); |
5339 | if (notifier_ret) | 5387 | if (notifier_ret) |
5340 | goto out; | 5388 | goto out; |
5341 | 5389 | /* | |
5342 | for (iter = pfn; iter < (pfn + pageblock_nr_pages); iter++) { | 5390 | * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself. |
5343 | if (!pfn_valid_within(pfn)) | 5391 | * We just check MOVABLE pages. |
5344 | continue; | 5392 | */ |
5345 | 5393 | if (__count_immobile_pages(zone, page, arg.pages_found)) | |
5346 | curr_page = pfn_to_page(iter); | ||
5347 | if (!page_count(curr_page) || PageLRU(curr_page)) | ||
5348 | continue; | ||
5349 | |||
5350 | immobile++; | ||
5351 | } | ||
5352 | |||
5353 | if (arg.pages_found == immobile) | ||
5354 | ret = 0; | 5394 | ret = 0; |
5355 | 5395 | ||
5396 | /* | ||
5397 | * immobile means "not-on-lru" paes. If immobile is larger than | ||
5398 | * removable-by-driver pages reported by notifier, we'll fail. | ||
5399 | */ | ||
5400 | |||
5356 | out: | 5401 | out: |
5357 | if (!ret) { | 5402 | if (!ret) { |
5358 | set_pageblock_migratetype(page, MIGRATE_ISOLATE); | 5403 | set_pageblock_migratetype(page, MIGRATE_ISOLATE); |