diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 86 |
1 files changed, 47 insertions, 39 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index b17dca7249f8..833f854eabe5 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -159,21 +159,58 @@ void register_page_bootmem_info_node(struct pglist_data *pgdat) | |||
159 | } | 159 | } |
160 | #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ | 160 | #endif /* !CONFIG_SPARSEMEM_VMEMMAP */ |
161 | 161 | ||
162 | static void grow_zone_span(struct zone *zone, unsigned long start_pfn, | ||
163 | unsigned long end_pfn) | ||
164 | { | ||
165 | unsigned long old_zone_end_pfn; | ||
166 | |||
167 | zone_span_writelock(zone); | ||
168 | |||
169 | old_zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; | ||
170 | if (start_pfn < zone->zone_start_pfn) | ||
171 | zone->zone_start_pfn = start_pfn; | ||
172 | |||
173 | zone->spanned_pages = max(old_zone_end_pfn, end_pfn) - | ||
174 | zone->zone_start_pfn; | ||
175 | |||
176 | zone_span_writeunlock(zone); | ||
177 | } | ||
178 | |||
179 | static void grow_pgdat_span(struct pglist_data *pgdat, unsigned long start_pfn, | ||
180 | unsigned long end_pfn) | ||
181 | { | ||
182 | unsigned long old_pgdat_end_pfn = | ||
183 | pgdat->node_start_pfn + pgdat->node_spanned_pages; | ||
184 | |||
185 | if (start_pfn < pgdat->node_start_pfn) | ||
186 | pgdat->node_start_pfn = start_pfn; | ||
187 | |||
188 | pgdat->node_spanned_pages = max(old_pgdat_end_pfn, end_pfn) - | ||
189 | pgdat->node_start_pfn; | ||
190 | } | ||
191 | |||
162 | static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) | 192 | static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) |
163 | { | 193 | { |
164 | struct pglist_data *pgdat = zone->zone_pgdat; | 194 | struct pglist_data *pgdat = zone->zone_pgdat; |
165 | int nr_pages = PAGES_PER_SECTION; | 195 | int nr_pages = PAGES_PER_SECTION; |
166 | int nid = pgdat->node_id; | 196 | int nid = pgdat->node_id; |
167 | int zone_type; | 197 | int zone_type; |
198 | unsigned long flags; | ||
168 | 199 | ||
169 | zone_type = zone - pgdat->node_zones; | 200 | zone_type = zone - pgdat->node_zones; |
170 | if (!zone->wait_table) { | 201 | if (!zone->wait_table) { |
171 | int ret = 0; | 202 | int ret; |
203 | |||
172 | ret = init_currently_empty_zone(zone, phys_start_pfn, | 204 | ret = init_currently_empty_zone(zone, phys_start_pfn, |
173 | nr_pages, MEMMAP_HOTPLUG); | 205 | nr_pages, MEMMAP_HOTPLUG); |
174 | if (ret < 0) | 206 | if (ret) |
175 | return ret; | 207 | return ret; |
176 | } | 208 | } |
209 | pgdat_resize_lock(zone->zone_pgdat, &flags); | ||
210 | grow_zone_span(zone, phys_start_pfn, phys_start_pfn + nr_pages); | ||
211 | grow_pgdat_span(zone->zone_pgdat, phys_start_pfn, | ||
212 | phys_start_pfn + nr_pages); | ||
213 | pgdat_resize_unlock(zone->zone_pgdat, &flags); | ||
177 | memmap_init_zone(nr_pages, nid, zone_type, | 214 | memmap_init_zone(nr_pages, nid, zone_type, |
178 | phys_start_pfn, MEMMAP_HOTPLUG); | 215 | phys_start_pfn, MEMMAP_HOTPLUG); |
179 | return 0; | 216 | return 0; |
@@ -299,36 +336,6 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn, | |||
299 | } | 336 | } |
300 | EXPORT_SYMBOL_GPL(__remove_pages); | 337 | EXPORT_SYMBOL_GPL(__remove_pages); |
301 | 338 | ||
302 | static void grow_zone_span(struct zone *zone, | ||
303 | unsigned long start_pfn, unsigned long end_pfn) | ||
304 | { | ||
305 | unsigned long old_zone_end_pfn; | ||
306 | |||
307 | zone_span_writelock(zone); | ||
308 | |||
309 | old_zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; | ||
310 | if (start_pfn < zone->zone_start_pfn) | ||
311 | zone->zone_start_pfn = start_pfn; | ||
312 | |||
313 | zone->spanned_pages = max(old_zone_end_pfn, end_pfn) - | ||
314 | zone->zone_start_pfn; | ||
315 | |||
316 | zone_span_writeunlock(zone); | ||
317 | } | ||
318 | |||
319 | static void grow_pgdat_span(struct pglist_data *pgdat, | ||
320 | unsigned long start_pfn, unsigned long end_pfn) | ||
321 | { | ||
322 | unsigned long old_pgdat_end_pfn = | ||
323 | pgdat->node_start_pfn + pgdat->node_spanned_pages; | ||
324 | |||
325 | if (start_pfn < pgdat->node_start_pfn) | ||
326 | pgdat->node_start_pfn = start_pfn; | ||
327 | |||
328 | pgdat->node_spanned_pages = max(old_pgdat_end_pfn, end_pfn) - | ||
329 | pgdat->node_start_pfn; | ||
330 | } | ||
331 | |||
332 | void online_page(struct page *page) | 339 | void online_page(struct page *page) |
333 | { | 340 | { |
334 | totalram_pages++; | 341 | totalram_pages++; |
@@ -367,7 +374,6 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, | |||
367 | 374 | ||
368 | int online_pages(unsigned long pfn, unsigned long nr_pages) | 375 | int online_pages(unsigned long pfn, unsigned long nr_pages) |
369 | { | 376 | { |
370 | unsigned long flags; | ||
371 | unsigned long onlined_pages = 0; | 377 | unsigned long onlined_pages = 0; |
372 | struct zone *zone; | 378 | struct zone *zone; |
373 | int need_zonelists_rebuild = 0; | 379 | int need_zonelists_rebuild = 0; |
@@ -395,11 +401,6 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) | |||
395 | * memory_block->state_mutex. | 401 | * memory_block->state_mutex. |
396 | */ | 402 | */ |
397 | zone = page_zone(pfn_to_page(pfn)); | 403 | zone = page_zone(pfn_to_page(pfn)); |
398 | pgdat_resize_lock(zone->zone_pgdat, &flags); | ||
399 | grow_zone_span(zone, pfn, pfn + nr_pages); | ||
400 | grow_pgdat_span(zone->zone_pgdat, pfn, pfn + nr_pages); | ||
401 | pgdat_resize_unlock(zone->zone_pgdat, &flags); | ||
402 | |||
403 | /* | 404 | /* |
404 | * If this zone is not populated, then it is not in zonelist. | 405 | * If this zone is not populated, then it is not in zonelist. |
405 | * This means the page allocator ignores this zone. | 406 | * This means the page allocator ignores this zone. |
@@ -408,8 +409,15 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) | |||
408 | if (!populated_zone(zone)) | 409 | if (!populated_zone(zone)) |
409 | need_zonelists_rebuild = 1; | 410 | need_zonelists_rebuild = 1; |
410 | 411 | ||
411 | walk_memory_resource(pfn, nr_pages, &onlined_pages, | 412 | ret = walk_memory_resource(pfn, nr_pages, &onlined_pages, |
412 | online_pages_range); | 413 | online_pages_range); |
414 | if (ret) { | ||
415 | printk(KERN_DEBUG "online_pages %lx at %lx failed\n", | ||
416 | nr_pages, pfn); | ||
417 | memory_notify(MEM_CANCEL_ONLINE, &arg); | ||
418 | return ret; | ||
419 | } | ||
420 | |||
413 | zone->present_pages += onlined_pages; | 421 | zone->present_pages += onlined_pages; |
414 | zone->zone_pgdat->node_present_pages += onlined_pages; | 422 | zone->zone_pgdat->node_present_pages += onlined_pages; |
415 | 423 | ||