diff options
author | Lai Jiangshan <laijs@cn.fujitsu.com> | 2012-12-11 19:03:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 20:22:28 -0500 |
commit | e455a9b92d6e19a3f0f7eb6f6241efa566a7e81a (patch) | |
tree | f920832f9e55ecf3e178e498f8894363748bb6c7 /mm/memory_hotplug.c | |
parent | 511c2aba8f07fc45bdcba548cb63f7b8a450c6dc (diff) |
memory_hotplug: handle empty zone when online_movable/online_kernel
Make online_movable/online_kernel can empty a zone or can move memory to a
empty zone.
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Cc: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Cc: Lai Jiangshan <laijs@cn.fujitsu.com>
Cc: Jiang Liu <jiang.liu@huawei.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: David Rientjes <rientjes@google.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 51 |
1 files changed, 45 insertions, 6 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 5c1f4959e6b4..c370491bdb97 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -219,8 +219,17 @@ static void resize_zone(struct zone *zone, unsigned long start_pfn, | |||
219 | { | 219 | { |
220 | zone_span_writelock(zone); | 220 | zone_span_writelock(zone); |
221 | 221 | ||
222 | zone->zone_start_pfn = start_pfn; | 222 | if (end_pfn - start_pfn) { |
223 | zone->spanned_pages = end_pfn - start_pfn; | 223 | zone->zone_start_pfn = start_pfn; |
224 | zone->spanned_pages = end_pfn - start_pfn; | ||
225 | } else { | ||
226 | /* | ||
227 | * make it consist as free_area_init_core(), | ||
228 | * if spanned_pages = 0, then keep start_pfn = 0 | ||
229 | */ | ||
230 | zone->zone_start_pfn = 0; | ||
231 | zone->spanned_pages = 0; | ||
232 | } | ||
224 | 233 | ||
225 | zone_span_writeunlock(zone); | 234 | zone_span_writeunlock(zone); |
226 | } | 235 | } |
@@ -236,10 +245,19 @@ static void fix_zone_id(struct zone *zone, unsigned long start_pfn, | |||
236 | set_page_links(pfn_to_page(pfn), zid, nid, pfn); | 245 | set_page_links(pfn_to_page(pfn), zid, nid, pfn); |
237 | } | 246 | } |
238 | 247 | ||
239 | static int move_pfn_range_left(struct zone *z1, struct zone *z2, | 248 | static int __meminit move_pfn_range_left(struct zone *z1, struct zone *z2, |
240 | unsigned long start_pfn, unsigned long end_pfn) | 249 | unsigned long start_pfn, unsigned long end_pfn) |
241 | { | 250 | { |
251 | int ret; | ||
242 | unsigned long flags; | 252 | unsigned long flags; |
253 | unsigned long z1_start_pfn; | ||
254 | |||
255 | if (!z1->wait_table) { | ||
256 | ret = init_currently_empty_zone(z1, start_pfn, | ||
257 | end_pfn - start_pfn, MEMMAP_HOTPLUG); | ||
258 | if (ret) | ||
259 | return ret; | ||
260 | } | ||
243 | 261 | ||
244 | pgdat_resize_lock(z1->zone_pgdat, &flags); | 262 | pgdat_resize_lock(z1->zone_pgdat, &flags); |
245 | 263 | ||
@@ -253,7 +271,13 @@ static int move_pfn_range_left(struct zone *z1, struct zone *z2, | |||
253 | if (end_pfn <= z2->zone_start_pfn) | 271 | if (end_pfn <= z2->zone_start_pfn) |
254 | goto out_fail; | 272 | goto out_fail; |
255 | 273 | ||
256 | resize_zone(z1, z1->zone_start_pfn, end_pfn); | 274 | /* use start_pfn for z1's start_pfn if z1 is empty */ |
275 | if (z1->spanned_pages) | ||
276 | z1_start_pfn = z1->zone_start_pfn; | ||
277 | else | ||
278 | z1_start_pfn = start_pfn; | ||
279 | |||
280 | resize_zone(z1, z1_start_pfn, end_pfn); | ||
257 | resize_zone(z2, end_pfn, z2->zone_start_pfn + z2->spanned_pages); | 281 | resize_zone(z2, end_pfn, z2->zone_start_pfn + z2->spanned_pages); |
258 | 282 | ||
259 | pgdat_resize_unlock(z1->zone_pgdat, &flags); | 283 | pgdat_resize_unlock(z1->zone_pgdat, &flags); |
@@ -266,10 +290,19 @@ out_fail: | |||
266 | return -1; | 290 | return -1; |
267 | } | 291 | } |
268 | 292 | ||
269 | static int move_pfn_range_right(struct zone *z1, struct zone *z2, | 293 | static int __meminit move_pfn_range_right(struct zone *z1, struct zone *z2, |
270 | unsigned long start_pfn, unsigned long end_pfn) | 294 | unsigned long start_pfn, unsigned long end_pfn) |
271 | { | 295 | { |
296 | int ret; | ||
272 | unsigned long flags; | 297 | unsigned long flags; |
298 | unsigned long z2_end_pfn; | ||
299 | |||
300 | if (!z2->wait_table) { | ||
301 | ret = init_currently_empty_zone(z2, start_pfn, | ||
302 | end_pfn - start_pfn, MEMMAP_HOTPLUG); | ||
303 | if (ret) | ||
304 | return ret; | ||
305 | } | ||
273 | 306 | ||
274 | pgdat_resize_lock(z1->zone_pgdat, &flags); | 307 | pgdat_resize_lock(z1->zone_pgdat, &flags); |
275 | 308 | ||
@@ -283,8 +316,14 @@ static int move_pfn_range_right(struct zone *z1, struct zone *z2, | |||
283 | if (start_pfn >= z1->zone_start_pfn + z1->spanned_pages) | 316 | if (start_pfn >= z1->zone_start_pfn + z1->spanned_pages) |
284 | goto out_fail; | 317 | goto out_fail; |
285 | 318 | ||
319 | /* use end_pfn for z2's end_pfn if z2 is empty */ | ||
320 | if (z2->spanned_pages) | ||
321 | z2_end_pfn = z2->zone_start_pfn + z2->spanned_pages; | ||
322 | else | ||
323 | z2_end_pfn = end_pfn; | ||
324 | |||
286 | resize_zone(z1, z1->zone_start_pfn, start_pfn); | 325 | resize_zone(z1, z1->zone_start_pfn, start_pfn); |
287 | resize_zone(z2, start_pfn, z2->zone_start_pfn + z2->spanned_pages); | 326 | resize_zone(z2, start_pfn, z2_end_pfn); |
288 | 327 | ||
289 | pgdat_resize_unlock(z1->zone_pgdat, &flags); | 328 | pgdat_resize_unlock(z1->zone_pgdat, &flags); |
290 | 329 | ||