diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/page_alloc.c | 57 |
1 files changed, 50 insertions, 7 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 74af449b1f1d..998eacc1e4c3 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/page_cgroup.h> | 48 | #include <linux/page_cgroup.h> |
49 | #include <linux/debugobjects.h> | 49 | #include <linux/debugobjects.h> |
50 | #include <linux/kmemleak.h> | 50 | #include <linux/kmemleak.h> |
51 | #include <linux/memory.h> | ||
51 | #include <trace/events/kmem.h> | 52 | #include <trace/events/kmem.h> |
52 | 53 | ||
53 | #include <asm/tlbflush.h> | 54 | #include <asm/tlbflush.h> |
@@ -5008,23 +5009,65 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags, | |||
5008 | int set_migratetype_isolate(struct page *page) | 5009 | int set_migratetype_isolate(struct page *page) |
5009 | { | 5010 | { |
5010 | struct zone *zone; | 5011 | struct zone *zone; |
5011 | unsigned long flags; | 5012 | struct page *curr_page; |
5013 | unsigned long flags, pfn, iter; | ||
5014 | unsigned long immobile = 0; | ||
5015 | struct memory_isolate_notify arg; | ||
5016 | int notifier_ret; | ||
5012 | int ret = -EBUSY; | 5017 | int ret = -EBUSY; |
5013 | int zone_idx; | 5018 | int zone_idx; |
5014 | 5019 | ||
5015 | zone = page_zone(page); | 5020 | zone = page_zone(page); |
5016 | zone_idx = zone_idx(zone); | 5021 | zone_idx = zone_idx(zone); |
5022 | |||
5017 | spin_lock_irqsave(&zone->lock, flags); | 5023 | spin_lock_irqsave(&zone->lock, flags); |
5024 | if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE || | ||
5025 | zone_idx == ZONE_MOVABLE) { | ||
5026 | ret = 0; | ||
5027 | goto out; | ||
5028 | } | ||
5029 | |||
5030 | pfn = page_to_pfn(page); | ||
5031 | arg.start_pfn = pfn; | ||
5032 | arg.nr_pages = pageblock_nr_pages; | ||
5033 | arg.pages_found = 0; | ||
5034 | |||
5018 | /* | 5035 | /* |
5019 | * In future, more migrate types will be able to be isolation target. | 5036 | * It may be possible to isolate a pageblock even if the |
5037 | * migratetype is not MIGRATE_MOVABLE. The memory isolation | ||
5038 | * notifier chain is used by balloon drivers to return the | ||
5039 | * number of pages in a range that are held by the balloon | ||
5040 | * driver to shrink memory. If all the pages are accounted for | ||
5041 | * by balloons, are free, or on the LRU, isolation can continue. | ||
5042 | * Later, for example, when memory hotplug notifier runs, these | ||
5043 | * pages reported as "can be isolated" should be isolated(freed) | ||
5044 | * by the balloon driver through the memory notifier chain. | ||
5020 | */ | 5045 | */ |
5021 | if (get_pageblock_migratetype(page) != MIGRATE_MOVABLE && | 5046 | notifier_ret = memory_isolate_notify(MEM_ISOLATE_COUNT, &arg); |
5022 | zone_idx != ZONE_MOVABLE) | 5047 | notifier_ret = notifier_to_errno(notifier_ret); |
5048 | if (notifier_ret || !arg.pages_found) | ||
5023 | goto out; | 5049 | goto out; |
5024 | set_pageblock_migratetype(page, MIGRATE_ISOLATE); | 5050 | |
5025 | move_freepages_block(zone, page, MIGRATE_ISOLATE); | 5051 | for (iter = pfn; iter < (pfn + pageblock_nr_pages); iter++) { |
5026 | ret = 0; | 5052 | if (!pfn_valid_within(pfn)) |
5053 | continue; | ||
5054 | |||
5055 | curr_page = pfn_to_page(iter); | ||
5056 | if (!page_count(curr_page) || PageLRU(curr_page)) | ||
5057 | continue; | ||
5058 | |||
5059 | immobile++; | ||
5060 | } | ||
5061 | |||
5062 | if (arg.pages_found == immobile) | ||
5063 | ret = 0; | ||
5064 | |||
5027 | out: | 5065 | out: |
5066 | if (!ret) { | ||
5067 | set_pageblock_migratetype(page, MIGRATE_ISOLATE); | ||
5068 | move_freepages_block(zone, page, MIGRATE_ISOLATE); | ||
5069 | } | ||
5070 | |||
5028 | spin_unlock_irqrestore(&zone->lock, flags); | 5071 | spin_unlock_irqrestore(&zone->lock, flags); |
5029 | if (!ret) | 5072 | if (!ret) |
5030 | drain_all_pages(); | 5073 | drain_all_pages(); |