Blame view

mm/page_isolation.c 8.36 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>
83358ece2   Joonsoo Kim   mm/page_owner: in...
9
  #include <linux/page_owner.h>
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
10
  #include "internal.h"
0f0848e51   Joonsoo Kim   mm/page_isolation...
11
12
  #define CREATE_TRACE_POINTS
  #include <trace/events/page_isolation.h>
c5b4e1b02   Naoya Horiguchi   mm, page_isolatio...
13
14
  static int set_migratetype_isolate(struct page *page,
  				bool skip_hwpoisoned_pages)
ee6f509c3   Minchan Kim   mm: factor out me...
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
46
47
48
49
  {
  	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...
50
51
  	if (!has_unmovable_pages(zone, page, arg.pages_found,
  				 skip_hwpoisoned_pages))
ee6f509c3   Minchan Kim   mm: factor out me...
52
53
54
  		ret = 0;
  
  	/*
ac34dcd26   Yisheng Xie   mm/page_isolation...
55
  	 * immobile means "not-on-lru" pages. If immobile is larger than
ee6f509c3   Minchan Kim   mm: factor out me...
56
57
58
59
60
  	 * removable-by-driver pages reported by notifier, we'll fail.
  	 */
  
  out:
  	if (!ret) {
2139cbe62   Bartlomiej Zolnierkiewicz   cma: fix counting...
61
  		unsigned long nr_pages;
d1ce749a0   Bartlomiej Zolnierkiewicz   cma: count free C...
62
  		int migratetype = get_pageblock_migratetype(page);
2139cbe62   Bartlomiej Zolnierkiewicz   cma: fix counting...
63

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

ee6f509c3   Minchan Kim   mm: factor out me...
84
85
86
87
  	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...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  
  	/*
  	 * 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...
103
104
  			if (pfn_valid_within(page_to_pfn(buddy)) &&
  			    !is_migrate_isolate_page(buddy)) {
3c605096d   Joonsoo Kim   mm/page_alloc: re...
105
  				__isolate_free_page(page, order);
e3a2713c3   Joonsoo Kim   mm/page_isolation...
106
  				isolated_page = true;
3c605096d   Joonsoo Kim   mm/page_alloc: re...
107
108
109
110
111
112
113
114
115
116
117
118
119
  			}
  		}
  	}
  
  	/*
  	 * 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...
120
  	set_pageblock_migratetype(page, migratetype);
ad53f92eb   Joonsoo Kim   mm/page_alloc: fi...
121
  	zone->nr_isolate_pageblock--;
ee6f509c3   Minchan Kim   mm: factor out me...
122
123
  out:
  	spin_unlock_irqrestore(&zone->lock, flags);
83358ece2   Joonsoo Kim   mm/page_owner: in...
124
  	if (isolated_page) {
46f24fd85   Joonsoo Kim   mm/page_alloc: in...
125
  		post_alloc_hook(page, order, __GFP_MOVABLE);
e3a2713c3   Joonsoo Kim   mm/page_isolation...
126
  		__free_pages(page, order);
83358ece2   Joonsoo Kim   mm/page_owner: in...
127
  	}
ee6f509c3   Minchan Kim   mm: factor out me...
128
  }
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  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...
146
   * @migratetype: migrate type to set in error recovery.
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
147
148
149
150
151
152
153
154
   *
   * 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...
155
  int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
b023f4681   Wen Congyang   memory-hotplug: s...
156
  			     unsigned migratetype, bool skip_hwpoisoned_pages)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
157
158
159
160
  {
  	unsigned long pfn;
  	unsigned long undo_pfn;
  	struct page *page;
fec174d66   Naoya Horiguchi   mm/page_isolation...
161
162
  	BUG_ON(!IS_ALIGNED(start_pfn, pageblock_nr_pages));
  	BUG_ON(!IS_ALIGNED(end_pfn, pageblock_nr_pages));
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
163
164
165
166
167
  
  	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...
168
169
  		if (page &&
  		    set_migratetype_isolate(page, skip_hwpoisoned_pages)) {
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
170
171
172
173
174
175
176
  			undo_pfn = pfn;
  			goto undo;
  		}
  	}
  	return 0;
  undo:
  	for (pfn = start_pfn;
dbc0e4cef   KAMEZAWA Hiroyuki   memory hotremove:...
177
  	     pfn < undo_pfn;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
178
  	     pfn += pageblock_nr_pages)
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
179
  		unset_migratetype_isolate(pfn_to_page(pfn), migratetype);
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
180
181
182
183
184
185
186
  
  	return -EBUSY;
  }
  
  /*
   * Make isolated pages available again.
   */
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
187
188
  int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
  			    unsigned migratetype)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
189
190
191
  {
  	unsigned long pfn;
  	struct page *page;
6f8d2b8a2   Wang Xiaoqiang   mm/page_isolation...
192
193
194
  
  	BUG_ON(!IS_ALIGNED(start_pfn, pageblock_nr_pages));
  	BUG_ON(!IS_ALIGNED(end_pfn, pageblock_nr_pages));
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
195
196
197
198
  	for (pfn = start_pfn;
  	     pfn < end_pfn;
  	     pfn += pageblock_nr_pages) {
  		page = __first_valid_page(pfn, pageblock_nr_pages);
dbc0e4cef   KAMEZAWA Hiroyuki   memory hotremove:...
199
  		if (!page || get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
200
  			continue;
0815f3d81   Michal Nazarewicz   mm: page_isolatio...
201
  		unset_migratetype_isolate(page, migratetype);
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
202
203
204
205
206
207
208
209
  	}
  	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.
   *
ec3b68825   Neil Zhang   mm/page_isolation...
210
   * Returns the last tested pfn.
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
211
   */
fea85cff1   Joonsoo Kim   mm/page_isolation...
212
  static unsigned long
b023f4681   Wen Congyang   memory-hotplug: s...
213
214
  __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn,
  				  bool skip_hwpoisoned_pages)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
215
216
217
218
219
220
221
222
223
  {
  	struct page *page;
  
  	while (pfn < end_pfn) {
  		if (!pfn_valid_within(pfn)) {
  			pfn++;
  			continue;
  		}
  		page = pfn_to_page(pfn);
aa016d145   Vlastimil Babka   mm, page_isolatio...
224
  		if (PageBuddy(page))
435b405c0   Minchan Kim   memory-hotplug: f...
225
  			/*
aa016d145   Vlastimil Babka   mm, page_isolatio...
226
227
228
  			 * If the page is on a free list, it has to be on
  			 * the correct MIGRATE_ISOLATE freelist. There is no
  			 * simple way to verify that as VM_BUG_ON(), though.
435b405c0   Minchan Kim   memory-hotplug: f...
229
  			 */
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
230
  			pfn += 1 << page_order(page);
aa016d145   Vlastimil Babka   mm, page_isolatio...
231
232
  		else if (skip_hwpoisoned_pages && PageHWPoison(page))
  			/* A HWPoisoned page cannot be also PageBuddy */
b023f4681   Wen Congyang   memory-hotplug: s...
233
  			pfn++;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
234
235
236
  		else
  			break;
  	}
fea85cff1   Joonsoo Kim   mm/page_isolation...
237
238
  
  	return pfn;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
239
  }
b9eb63191   Joonsoo Kim   mm/memory_hotplug...
240
  /* Caller should ensure that requested range is in a single zone */
b023f4681   Wen Congyang   memory-hotplug: s...
241
242
  int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn,
  			bool skip_hwpoisoned_pages)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
243
  {
6c1b7f680   Gerald Schaefer   memory hotplug: m...
244
  	unsigned long pfn, flags;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
245
  	struct page *page;
6c1b7f680   Gerald Schaefer   memory hotplug: m...
246
  	struct zone *zone;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
247

a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
248
  	/*
85dbe7060   Tang Chen   page_isolation: F...
249
250
251
  	 * 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...
252
253
254
  	 */
  	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
  		page = __first_valid_page(pfn, pageblock_nr_pages);
dbc0e4cef   KAMEZAWA Hiroyuki   memory hotremove:...
255
  		if (page && get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
256
257
  			break;
  	}
a70dcb969   Gerald Schaefer   memory hotplug: f...
258
259
  	page = __first_valid_page(start_pfn, end_pfn - start_pfn);
  	if ((pfn < end_pfn) || !page)
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
260
  		return -EBUSY;
85dbe7060   Tang Chen   page_isolation: F...
261
  	/* Check all pages are free or marked as ISOLATED */
a70dcb969   Gerald Schaefer   memory hotplug: f...
262
  	zone = page_zone(page);
6c1b7f680   Gerald Schaefer   memory hotplug: m...
263
  	spin_lock_irqsave(&zone->lock, flags);
fea85cff1   Joonsoo Kim   mm/page_isolation...
264
  	pfn = __test_page_isolated_in_pageblock(start_pfn, end_pfn,
b023f4681   Wen Congyang   memory-hotplug: s...
265
  						skip_hwpoisoned_pages);
6c1b7f680   Gerald Schaefer   memory hotplug: m...
266
  	spin_unlock_irqrestore(&zone->lock, flags);
fea85cff1   Joonsoo Kim   mm/page_isolation...
267

0f0848e51   Joonsoo Kim   mm/page_isolation...
268
  	trace_test_pages_isolated(start_pfn, end_pfn, pfn);
fea85cff1   Joonsoo Kim   mm/page_isolation...
269
  	return pfn < end_pfn ? -EBUSY : 0;
a5d76b54a   KAMEZAWA Hiroyuki   memory unplug: pa...
270
  }
723a0644a   Minchan Kim   mm/page_alloc: re...
271
272
273
274
275
  
  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...
276
277
278
279
280
  	/*
  	 * 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.
  	 */
0edaf86cf   Andrew Morton   include/linux/nod...
281
  	if (PageHuge(page))
c8721bbbd   Naoya Horiguchi   mm: memory-hotplu...
282
  		return alloc_huge_page_node(page_hstate(compound_head(page)),
0edaf86cf   Andrew Morton   include/linux/nod...
283
284
  					    next_node_in(page_to_nid(page),
  							 node_online_map));
c8721bbbd   Naoya Horiguchi   mm: memory-hotplu...
285

723a0644a   Minchan Kim   mm/page_alloc: re...
286
287
288
289
290
  	if (PageHighMem(page))
  		gfp_mask |= __GFP_HIGHMEM;
  
  	return alloc_page(gfp_mask);
  }