diff options
Diffstat (limited to 'mm/page_isolation.c')
-rw-r--r-- | mm/page_isolation.c | 53 |
1 files changed, 22 insertions, 31 deletions
diff --git a/mm/page_isolation.c b/mm/page_isolation.c index f2f5b4818e94..383bdbb98b04 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c | |||
@@ -8,29 +8,7 @@ | |||
8 | #include <linux/memory.h> | 8 | #include <linux/memory.h> |
9 | #include "internal.h" | 9 | #include "internal.h" |
10 | 10 | ||
11 | /* called while holding zone->lock */ | 11 | int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages) |
12 | static void set_pageblock_isolate(struct page *page) | ||
13 | { | ||
14 | if (get_pageblock_migratetype(page) == MIGRATE_ISOLATE) | ||
15 | return; | ||
16 | |||
17 | set_pageblock_migratetype(page, MIGRATE_ISOLATE); | ||
18 | page_zone(page)->nr_pageblock_isolate++; | ||
19 | } | ||
20 | |||
21 | /* called while holding zone->lock */ | ||
22 | static void restore_pageblock_isolate(struct page *page, int migratetype) | ||
23 | { | ||
24 | struct zone *zone = page_zone(page); | ||
25 | if (WARN_ON(get_pageblock_migratetype(page) != MIGRATE_ISOLATE)) | ||
26 | return; | ||
27 | |||
28 | BUG_ON(zone->nr_pageblock_isolate <= 0); | ||
29 | set_pageblock_migratetype(page, migratetype); | ||
30 | zone->nr_pageblock_isolate--; | ||
31 | } | ||
32 | |||
33 | int set_migratetype_isolate(struct page *page) | ||
34 | { | 12 | { |
35 | struct zone *zone; | 13 | struct zone *zone; |
36 | unsigned long flags, pfn; | 14 | unsigned long flags, pfn; |
@@ -66,7 +44,8 @@ int set_migratetype_isolate(struct page *page) | |||
66 | * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself. | 44 | * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself. |
67 | * We just check MOVABLE pages. | 45 | * We just check MOVABLE pages. |
68 | */ | 46 | */ |
69 | if (!has_unmovable_pages(zone, page, arg.pages_found)) | 47 | if (!has_unmovable_pages(zone, page, arg.pages_found, |
48 | skip_hwpoisoned_pages)) | ||
70 | ret = 0; | 49 | ret = 0; |
71 | 50 | ||
72 | /* | 51 | /* |
@@ -79,7 +58,7 @@ out: | |||
79 | unsigned long nr_pages; | 58 | unsigned long nr_pages; |
80 | int migratetype = get_pageblock_migratetype(page); | 59 | int migratetype = get_pageblock_migratetype(page); |
81 | 60 | ||
82 | set_pageblock_isolate(page); | 61 | set_pageblock_migratetype(page, MIGRATE_ISOLATE); |
83 | nr_pages = move_freepages_block(zone, page, MIGRATE_ISOLATE); | 62 | nr_pages = move_freepages_block(zone, page, MIGRATE_ISOLATE); |
84 | 63 | ||
85 | __mod_zone_freepage_state(zone, -nr_pages, migratetype); | 64 | __mod_zone_freepage_state(zone, -nr_pages, migratetype); |
@@ -102,7 +81,7 @@ void unset_migratetype_isolate(struct page *page, unsigned migratetype) | |||
102 | goto out; | 81 | goto out; |
103 | nr_pages = move_freepages_block(zone, page, migratetype); | 82 | nr_pages = move_freepages_block(zone, page, migratetype); |
104 | __mod_zone_freepage_state(zone, nr_pages, migratetype); | 83 | __mod_zone_freepage_state(zone, nr_pages, migratetype); |
105 | restore_pageblock_isolate(page, migratetype); | 84 | set_pageblock_migratetype(page, migratetype); |
106 | out: | 85 | out: |
107 | spin_unlock_irqrestore(&zone->lock, flags); | 86 | spin_unlock_irqrestore(&zone->lock, flags); |
108 | } | 87 | } |
@@ -134,7 +113,7 @@ __first_valid_page(unsigned long pfn, unsigned long nr_pages) | |||
134 | * Returns 0 on success and -EBUSY if any part of range cannot be isolated. | 113 | * Returns 0 on success and -EBUSY if any part of range cannot be isolated. |
135 | */ | 114 | */ |
136 | int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn, | 115 | int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn, |
137 | unsigned migratetype) | 116 | unsigned migratetype, bool skip_hwpoisoned_pages) |
138 | { | 117 | { |
139 | unsigned long pfn; | 118 | unsigned long pfn; |
140 | unsigned long undo_pfn; | 119 | unsigned long undo_pfn; |
@@ -147,7 +126,8 @@ int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn, | |||
147 | pfn < end_pfn; | 126 | pfn < end_pfn; |
148 | pfn += pageblock_nr_pages) { | 127 | pfn += pageblock_nr_pages) { |
149 | page = __first_valid_page(pfn, pageblock_nr_pages); | 128 | page = __first_valid_page(pfn, pageblock_nr_pages); |
150 | if (page && set_migratetype_isolate(page)) { | 129 | if (page && |
130 | set_migratetype_isolate(page, skip_hwpoisoned_pages)) { | ||
151 | undo_pfn = pfn; | 131 | undo_pfn = pfn; |
152 | goto undo; | 132 | goto undo; |
153 | } | 133 | } |
@@ -190,7 +170,8 @@ int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn, | |||
190 | * Returns 1 if all pages in the range are isolated. | 170 | * Returns 1 if all pages in the range are isolated. |
191 | */ | 171 | */ |
192 | static int | 172 | static int |
193 | __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn) | 173 | __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn, |
174 | bool skip_hwpoisoned_pages) | ||
194 | { | 175 | { |
195 | struct page *page; | 176 | struct page *page; |
196 | 177 | ||
@@ -220,6 +201,14 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn) | |||
220 | else if (page_count(page) == 0 && | 201 | else if (page_count(page) == 0 && |
221 | get_freepage_migratetype(page) == MIGRATE_ISOLATE) | 202 | get_freepage_migratetype(page) == MIGRATE_ISOLATE) |
222 | pfn += 1; | 203 | pfn += 1; |
204 | else if (skip_hwpoisoned_pages && PageHWPoison(page)) { | ||
205 | /* | ||
206 | * The HWPoisoned page may be not in buddy | ||
207 | * system, and page_count() is not 0. | ||
208 | */ | ||
209 | pfn++; | ||
210 | continue; | ||
211 | } | ||
223 | else | 212 | else |
224 | break; | 213 | break; |
225 | } | 214 | } |
@@ -228,7 +217,8 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn) | |||
228 | return 1; | 217 | return 1; |
229 | } | 218 | } |
230 | 219 | ||
231 | int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn) | 220 | int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn, |
221 | bool skip_hwpoisoned_pages) | ||
232 | { | 222 | { |
233 | unsigned long pfn, flags; | 223 | unsigned long pfn, flags; |
234 | struct page *page; | 224 | struct page *page; |
@@ -251,7 +241,8 @@ int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn) | |||
251 | /* Check all pages are free or Marked as ISOLATED */ | 241 | /* Check all pages are free or Marked as ISOLATED */ |
252 | zone = page_zone(page); | 242 | zone = page_zone(page); |
253 | spin_lock_irqsave(&zone->lock, flags); | 243 | spin_lock_irqsave(&zone->lock, flags); |
254 | ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn); | 244 | ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn, |
245 | skip_hwpoisoned_pages); | ||
255 | spin_unlock_irqrestore(&zone->lock, flags); | 246 | spin_unlock_irqrestore(&zone->lock, flags); |
256 | return ret ? 0 : -EBUSY; | 247 | return ret ? 0 : -EBUSY; |
257 | } | 248 | } |