Blame view

mm/page_isolation.c 8.74 KB
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
1
2
3
  /*
   * linux/mm/page_isolation.c
   */
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
4
5
6
  #include <linux/mm.h>
  #include <linux/page-isolation.h>
  #include <linux/pageblock-flags.h>
ee6f509c3   Minchan Kim   mm: factor out me...
7
  #include <linux/memory.h>
c8721bbbd   Naoya Horiguchi   mm: memory-hotplu...
8
  #include <linux/hugetlb.h>
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
9
  #include "internal.h"
b023f4681   Wen Congyang   memory-hotplug: s...
10
  int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages)
ee6f509c3   Minchan Kim   mm: factor out me...
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  {
  	struct zone *zone;
  	unsigned long flags, pfn;
  	struct memory_isolate_notify arg;
  	int notifier_ret;
  	int ret = -EBUSY;
  
  	zone = page_zone(page);
  
  	spin_lock_irqsave(&zone->lock, flags);
  
  	pfn = page_to_pfn(page);
  	arg.start_pfn = pfn;
  	arg.nr_pages = pageblock_nr_pages;
  	arg.pages_found = 0;
  
  	/*
  	 * It may be possible to isolate a pageblock even if the
  	 * migratetype is not MIGRATE_MOVABLE. The memory isolation
  	 * notifier chain is used by balloon drivers to return the
  	 * number of pages in a range that are held by the balloon
  	 * driver to shrink memory. If all the pages are accounted for
  	 * by balloons, are free, or on the LRU, isolation can continue.
  	 * Later, for example, when memory hotplug notifier runs, these
  	 * pages reported as "can be isolated" should be isolated(freed)
  	 * by the balloon driver through the memory notifier chain.
  	 */
  	notifier_ret = memory_isolate_notify(MEM_ISOLATE_COUNT, &arg);
  	notifier_ret = notifier_to_errno(notifier_ret);
  	if (notifier_ret)
  		goto out;
  	/*
  	 * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
  	 * We just check MOVABLE pages.
  	 */
b023f4681   Wen Congyang   memory-hotplug: s...
46
47
  	if (!has_unmovable_pages(zone, page, arg.pages_found,
  				 skip_hwpoisoned_pages))
ee6f509c3   Minchan Kim   mm: factor out me...
48
49
50
51
52
53
54
55
56
  		ret = 0;
  
  	/*
  	 * immobile means "not-on-lru" paes. If immobile is larger than
  	 * removable-by-driver pages reported by notifier, we'll fail.
  	 */
  
  out:
  	if (!ret) {
2139cbe62   Bartlomiej Zolnierkiewicz   cma: fix counting...
57
  		unsigned long nr_pages;
d1ce749a0   Bartlomiej Zolnierkiewicz   cma: count free C...
58
  		int migratetype = get_pageblock_migratetype(page);
2139cbe62   Bartlomiej Zolnierkiewicz   cma: fix counting...
59

a458431e1   Bartlomiej Zolnierkiewicz   mm: fix zone_wate...
60
  		set_pageblock_migratetype(page, MIGRATE_ISOLATE);
ad53f92eb   Joonsoo Kim   mm/page_alloc: fi...
61
  		zone->nr_isolate_pageblock++;
2139cbe62   Bartlomiej Zolnierkiewicz   cma: fix counting...
62
  		nr_pages = move_freepages_block(zone, page, MIGRATE_ISOLATE);
d1ce749a0   Bartlomiej Zolnierkiewicz   cma: count free C...
63
  		__mod_zone_freepage_state(zone, -nr_pages, migratetype);
ee6f509c3   Minchan Kim   mm: factor out me...
64
65
66
67
  	}
  
  	spin_unlock_irqrestore(&zone->lock, flags);
  	if (!ret)
ec25af84b   Vlastimil Babka   mm, page_isolatio...
68
  		drain_all_pages(zone);
ee6f509c3   Minchan Kim   mm: factor out me...
69
70
71
72
73
74
  	return ret;
  }
  
  void unset_migratetype_isolate(struct page *page, unsigned migratetype)
  {
  	struct zone *zone;
2139cbe62   Bartlomiej Zolnierkiewicz   cma: fix counting...
75
  	unsigned long flags, nr_pages;
3c605096d   Joonsoo Kim   mm/page_alloc: re...
76
77
78
79
  	struct page *isolated_page = NULL;
  	unsigned int order;
  	unsigned long page_idx, buddy_idx;
  	struct page *buddy;
2139cbe62   Bartlomiej Zolnierkiewicz   cma: fix counting...
80

ee6f509c3   Minchan Kim   mm: factor out me...
81
82
83
84
  	zone = page_zone(page);
  	spin_lock_irqsave(&zone->lock, flags);
  	if (get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
  		goto out;
3c605096d   Joonsoo Kim   mm/page_alloc: re...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  
  	/*
  	 * Because freepage with more than pageblock_order on isolated
  	 * pageblock is restricted to merge due to freepage counting problem,
  	 * it is possible that there is free buddy page.
  	 * move_freepages_block() doesn't care of merge so we need other
  	 * approach in order to merge them. Isolation and free will make
  	 * these pages to be merged.
  	 */
  	if (PageBuddy(page)) {
  		order = page_order(page);
  		if (order >= pageblock_order) {
  			page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);
  			buddy_idx = __find_buddy_index(page_idx, order);
  			buddy = page + (buddy_idx - page_idx);
1ae7013df   Hui Zhu   CMA: page_isolati...
100
101
  			if (pfn_valid_within(page_to_pfn(buddy)) &&
  			    !is_migrate_isolate_page(buddy)) {
3c605096d   Joonsoo Kim   mm/page_alloc: re...
102
  				__isolate_free_page(page, order);
cfa869438   Laura Abbott   mm/page_alloc.c: ...
103
  				kernel_map_pages(page, (1 << order), 1);
3c605096d   Joonsoo Kim   mm/page_alloc: re...
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  				set_page_refcounted(page);
  				isolated_page = page;
  			}
  		}
  	}
  
  	/*
  	 * If we isolate freepage with more than pageblock_order, there
  	 * should be no freepage in the range, so we could avoid costly
  	 * pageblock scanning for freepage moving.
  	 */
  	if (!isolated_page) {
  		nr_pages = move_freepages_block(zone, page, migratetype);
  		__mod_zone_freepage_state(zone, nr_pages, migratetype);
  	}
a458431e1   Bartlomiej Zolnierkiewicz   mm: fix zone_wate...
119
  	set_pageblock_migratetype(page, migratetype);
ad53f92eb   Joonsoo Kim   mm/page_alloc: fi...
120
  	zone->nr_isolate_pageblock--;
ee6f509c3   Minchan Kim   mm: factor out me...
121
122
  out:
  	spin_unlock_irqrestore(&zone->lock, flags);
3c605096d   Joonsoo Kim   mm/page_alloc: re...
123
124
  	if (isolated_page)
  		__free_pages(isolated_page, order);
ee6f509c3   Minchan Kim   mm: factor out me...
125
  }
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  static inline struct page *
  __first_valid_page(unsigned long pfn, unsigned long nr_pages)
  {
  	int i;
  	for (i = 0; i < nr_pages; i++)
  		if (pfn_valid_within(pfn + i))
  			break;
  	if (unlikely(i == nr_pages))
  		return NULL;
  	return pfn_to_page(pfn + i);
  }
  
  /*
   * start_isolate_page_range() -- make page-allocation-type of range of pages
   * to be MIGRATE_ISOLATE.
   * @start_pfn: The lower PFN of the range to be isolated.
   * @end_pfn: The upper PFN of the range to be isolated.
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
143
   * @migratetype: migrate type to set in error recovery.
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
144
145
146
147
148
149
150
151
   *
   * Making page-allocation-type to be MIGRATE_ISOLATE means free pages in
   * the range will never be allocated. Any free pages and pages freed in the
   * future will not be allocated again.
   *
   * start_pfn/end_pfn must be aligned to pageblock_order.
   * Returns 0 on success and -EBUSY if any part of range cannot be isolated.
   */
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
152
  int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
b023f4681   Wen Congyang   memory-hotplug: s...
153
  			     unsigned migratetype, bool skip_hwpoisoned_pages)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
154
155
156
157
158
159
160
161
162
163
164
165
  {
  	unsigned long pfn;
  	unsigned long undo_pfn;
  	struct page *page;
  
  	BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
  	BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
  
  	for (pfn = start_pfn;
  	     pfn < end_pfn;
  	     pfn += pageblock_nr_pages) {
  		page = __first_valid_page(pfn, pageblock_nr_pages);
b023f4681   Wen Congyang   memory-hotplug: s...
166
167
  		if (page &&
  		    set_migratetype_isolate(page, skip_hwpoisoned_pages)) {
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
168
169
170
171
172
173
174
  			undo_pfn = pfn;
  			goto undo;
  		}
  	}
  	return 0;
  undo:
  	for (pfn = start_pfn;
dbc0e4cef   KAMEZAWA Hiroyuki   memory hotremove:...
175
  	     pfn < undo_pfn;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
176
  	     pfn += pageblock_nr_pages)
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
177
  		unset_migratetype_isolate(pfn_to_page(pfn), migratetype);
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
178
179
180
181
182
183
184
  
  	return -EBUSY;
  }
  
  /*
   * Make isolated pages available again.
   */
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
185
186
  int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
  			    unsigned migratetype)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
187
188
189
190
191
192
193
194
195
  {
  	unsigned long pfn;
  	struct page *page;
  	BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
  	BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
  	for (pfn = start_pfn;
  	     pfn < end_pfn;
  	     pfn += pageblock_nr_pages) {
  		page = __first_valid_page(pfn, pageblock_nr_pages);
dbc0e4cef   KAMEZAWA Hiroyuki   memory hotremove:...
196
  		if (!page || get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
197
  			continue;
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
198
  		unset_migratetype_isolate(page, migratetype);
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
199
200
201
202
203
204
205
206
  	}
  	return 0;
  }
  /*
   * Test all pages in the range is free(means isolated) or not.
   * all pages in [start_pfn...end_pfn) must be in the same zone.
   * zone->lock must be held before call this.
   *
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
207
   * Returns 1 if all pages in the range are isolated.
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
208
209
   */
  static int
b023f4681   Wen Congyang   memory-hotplug: s...
210
211
  __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
  				  bool skip_hwpoisoned_pages)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
212
213
214
215
216
217
218
219
220
  {
  	struct page *page;
  
  	while (pfn < end_pfn) {
  		if (!pfn_valid_within(pfn)) {
  			pfn++;
  			continue;
  		}
  		page = pfn_to_page(pfn);
41d575ad4   Minchan Kim   memory-hotplug: b...
221
  		if (PageBuddy(page)) {
435b405c0   Minchan Kim   memory-hotplug: f...
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  			/*
  			 * If race between isolatation and allocation happens,
  			 * some free pages could be in MIGRATE_MOVABLE list
  			 * although pageblock's migratation type of the page
  			 * is MIGRATE_ISOLATE. Catch it and move the page into
  			 * MIGRATE_ISOLATE list.
  			 */
  			if (get_freepage_migratetype(page) != MIGRATE_ISOLATE) {
  				struct page *end_page;
  
  				end_page = page + (1 << page_order(page)) - 1;
  				move_freepages(page_zone(page), page, end_page,
  						MIGRATE_ISOLATE);
  			}
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
236
  			pfn += 1 << page_order(page);
41d575ad4   Minchan Kim   memory-hotplug: b...
237
  		}
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
238
  		else if (page_count(page) == 0 &&
b12c4ad14   Minchan Kim   mm: page_alloc: u...
239
  			get_freepage_migratetype(page) == MIGRATE_ISOLATE)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
240
  			pfn += 1;
b023f4681   Wen Congyang   memory-hotplug: s...
241
242
243
244
245
246
247
248
  		else if (skip_hwpoisoned_pages && PageHWPoison(page)) {
  			/*
  			 * The HWPoisoned page may be not in buddy
  			 * system, and page_count() is not 0.
  			 */
  			pfn++;
  			continue;
  		}
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
249
250
251
252
253
254
255
  		else
  			break;
  	}
  	if (pfn < end_pfn)
  		return 0;
  	return 1;
  }
b023f4681   Wen Congyang   memory-hotplug: s...
256
257
  int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
  			bool skip_hwpoisoned_pages)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
258
  {
6c1b7f680   Gerald Schaefer   memory hotplug: m...
259
  	unsigned long pfn, flags;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
260
  	struct page *page;
6c1b7f680   Gerald Schaefer   memory hotplug: m...
261
262
  	struct zone *zone;
  	int ret;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
263

a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
264
  	/*
85dbe7060   Tang Chen   page_isolation: F...
265
266
267
  	 * Note: pageblock_nr_pages != MAX_ORDER. Then, chunks of free pages
  	 * are not aligned to pageblock_nr_pages.
  	 * Then we just check migratetype first.
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
268
269
270
  	 */
  	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
  		page = __first_valid_page(pfn, pageblock_nr_pages);
dbc0e4cef   KAMEZAWA Hiroyuki   memory hotremove:...
271
  		if (page && get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
272
273
  			break;
  	}
a70dcb969   Gerald Schaefer   memory hotplug: f...
274
275
  	page = __first_valid_page(start_pfn, end_pfn - start_pfn);
  	if ((pfn < end_pfn) || !page)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
276
  		return -EBUSY;
85dbe7060   Tang Chen   page_isolation: F...
277
  	/* Check all pages are free or marked as ISOLATED */
a70dcb969   Gerald Schaefer   memory hotplug: f...
278
  	zone = page_zone(page);
6c1b7f680   Gerald Schaefer   memory hotplug: m...
279
  	spin_lock_irqsave(&zone->lock, flags);
b023f4681   Wen Congyang   memory-hotplug: s...
280
281
  	ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn,
  						skip_hwpoisoned_pages);
6c1b7f680   Gerald Schaefer   memory hotplug: m...
282
283
  	spin_unlock_irqrestore(&zone->lock, flags);
  	return ret ? 0 : -EBUSY;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
284
  }
723a0644a   Minchan Kim   mm/page_alloc: re...
285
286
287
288
289
  
  struct page *alloc_migrate_target(struct page *page, unsigned long private,
  				  int **resultp)
  {
  	gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
c8721bbbd   Naoya Horiguchi   mm: memory-hotplu...
290
291
292
293
294
295
296
297
298
299
300
301
  	/*
  	 * TODO: allocate a destination hugepage from a nearest neighbor node,
  	 * accordance with memory policy of the user process if possible. For
  	 * now as a simple work-around, we use the next node for destination.
  	 */
  	if (PageHuge(page)) {
  		nodemask_t src = nodemask_of_node(page_to_nid(page));
  		nodemask_t dst;
  		nodes_complement(dst, src);
  		return alloc_huge_page_node(page_hstate(compound_head(page)),
  					    next_node(page_to_nid(page), dst));
  	}
723a0644a   Minchan Kim   mm/page_alloc: re...
302
303
304
305
306
  	if (PageHighMem(page))
  		gfp_mask |= __GFP_HIGHMEM;
  
  	return alloc_page(gfp_mask);
  }