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 | |
| 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')
| -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 | ||
