diff options
Diffstat (limited to 'mm/page_isolation.c')
-rw-r--r-- | mm/page_isolation.c | 43 |
1 files changed, 38 insertions, 5 deletions
diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 247d1f175739..f2f5b4818e94 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c | |||
@@ -76,8 +76,13 @@ int set_migratetype_isolate(struct page *page) | |||
76 | 76 | ||
77 | out: | 77 | out: |
78 | if (!ret) { | 78 | if (!ret) { |
79 | unsigned long nr_pages; | ||
80 | int migratetype = get_pageblock_migratetype(page); | ||
81 | |||
79 | set_pageblock_isolate(page); | 82 | set_pageblock_isolate(page); |
80 | move_freepages_block(zone, page, MIGRATE_ISOLATE); | 83 | nr_pages = move_freepages_block(zone, page, MIGRATE_ISOLATE); |
84 | |||
85 | __mod_zone_freepage_state(zone, -nr_pages, migratetype); | ||
81 | } | 86 | } |
82 | 87 | ||
83 | spin_unlock_irqrestore(&zone->lock, flags); | 88 | spin_unlock_irqrestore(&zone->lock, flags); |
@@ -89,12 +94,14 @@ out: | |||
89 | void unset_migratetype_isolate(struct page *page, unsigned migratetype) | 94 | void unset_migratetype_isolate(struct page *page, unsigned migratetype) |
90 | { | 95 | { |
91 | struct zone *zone; | 96 | struct zone *zone; |
92 | unsigned long flags; | 97 | unsigned long flags, nr_pages; |
98 | |||
93 | zone = page_zone(page); | 99 | zone = page_zone(page); |
94 | spin_lock_irqsave(&zone->lock, flags); | 100 | spin_lock_irqsave(&zone->lock, flags); |
95 | if (get_pageblock_migratetype(page) != MIGRATE_ISOLATE) | 101 | if (get_pageblock_migratetype(page) != MIGRATE_ISOLATE) |
96 | goto out; | 102 | goto out; |
97 | move_freepages_block(zone, page, migratetype); | 103 | nr_pages = move_freepages_block(zone, page, migratetype); |
104 | __mod_zone_freepage_state(zone, nr_pages, migratetype); | ||
98 | restore_pageblock_isolate(page, migratetype); | 105 | restore_pageblock_isolate(page, migratetype); |
99 | out: | 106 | out: |
100 | spin_unlock_irqrestore(&zone->lock, flags); | 107 | spin_unlock_irqrestore(&zone->lock, flags); |
@@ -193,10 +200,25 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn) | |||
193 | continue; | 200 | continue; |
194 | } | 201 | } |
195 | page = pfn_to_page(pfn); | 202 | page = pfn_to_page(pfn); |
196 | if (PageBuddy(page)) | 203 | if (PageBuddy(page)) { |
204 | /* | ||
205 | * If race between isolatation and allocation happens, | ||
206 | * some free pages could be in MIGRATE_MOVABLE list | ||
207 | * although pageblock's migratation type of the page | ||
208 | * is MIGRATE_ISOLATE. Catch it and move the page into | ||
209 | * MIGRATE_ISOLATE list. | ||
210 | */ | ||
211 | if (get_freepage_migratetype(page) != MIGRATE_ISOLATE) { | ||
212 | struct page *end_page; | ||
213 | |||
214 | end_page = page + (1 << page_order(page)) - 1; | ||
215 | move_freepages(page_zone(page), page, end_page, | ||
216 | MIGRATE_ISOLATE); | ||
217 | } | ||
197 | pfn += 1 << page_order(page); | 218 | pfn += 1 << page_order(page); |
219 | } | ||
198 | else if (page_count(page) == 0 && | 220 | else if (page_count(page) == 0 && |
199 | page_private(page) == MIGRATE_ISOLATE) | 221 | get_freepage_migratetype(page) == MIGRATE_ISOLATE) |
200 | pfn += 1; | 222 | pfn += 1; |
201 | else | 223 | else |
202 | break; | 224 | break; |
@@ -233,3 +255,14 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn) | |||
233 | spin_unlock_irqrestore(&zone->lock, flags); | 255 | spin_unlock_irqrestore(&zone->lock, flags); |
234 | return ret ? 0 : -EBUSY; | 256 | return ret ? 0 : -EBUSY; |
235 | } | 257 | } |
258 | |||
259 | struct page *alloc_migrate_target(struct page *page, unsigned long private, | ||
260 | int **resultp) | ||
261 | { | ||
262 | gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE; | ||
263 | |||
264 | if (PageHighMem(page)) | ||
265 | gfp_mask |= __GFP_HIGHMEM; | ||
266 | |||
267 | return alloc_page(gfp_mask); | ||
268 | } | ||