diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 83 |
1 files changed, 44 insertions, 39 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 656ad1c65422..833f854eabe5 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -159,17 +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 | return init_currently_empty_zone(zone, phys_start_pfn, | 202 | int ret; |
172 | nr_pages, MEMMAP_HOTPLUG); | 203 | |
204 | ret = init_currently_empty_zone(zone, phys_start_pfn, | ||
205 | nr_pages, MEMMAP_HOTPLUG); | ||
206 | if (ret) | ||
207 | return ret; | ||
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); | ||
173 | memmap_init_zone(nr_pages, nid, zone_type, | 214 | memmap_init_zone(nr_pages, nid, zone_type, |
174 | phys_start_pfn, MEMMAP_HOTPLUG); | 215 | phys_start_pfn, MEMMAP_HOTPLUG); |
175 | return 0; | 216 | return 0; |
@@ -295,36 +336,6 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn, | |||
295 | } | 336 | } |
296 | EXPORT_SYMBOL_GPL(__remove_pages); | 337 | EXPORT_SYMBOL_GPL(__remove_pages); |
297 | 338 | ||
298 | static void grow_zone_span(struct zone *zone, | ||
299 | unsigned long start_pfn, unsigned long end_pfn) | ||
300 | { | ||
301 | unsigned long old_zone_end_pfn; | ||
302 | |||
303 | zone_span_writelock(zone); | ||
304 | |||
305 | old_zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages; | ||
306 | if (start_pfn < zone->zone_start_pfn) | ||
307 | zone->zone_start_pfn = start_pfn; | ||
308 | |||
309 | zone->spanned_pages = max(old_zone_end_pfn, end_pfn) - | ||
310 | zone->zone_start_pfn; | ||
311 | |||
312 | zone_span_writeunlock(zone); | ||
313 | } | ||
314 | |||
315 | static void grow_pgdat_span(struct pglist_data *pgdat, | ||
316 | unsigned long start_pfn, unsigned long end_pfn) | ||
317 | { | ||
318 | unsigned long old_pgdat_end_pfn = | ||
319 | pgdat->node_start_pfn + pgdat->node_spanned_pages; | ||
320 | |||
321 | if (start_pfn < pgdat->node_start_pfn) | ||
322 | pgdat->node_start_pfn = start_pfn; | ||
323 | |||
324 | pgdat->node_spanned_pages = max(old_pgdat_end_pfn, end_pfn) - | ||
325 | pgdat->node_start_pfn; | ||
326 | } | ||
327 | |||
328 | void online_page(struct page *page) | 339 | void online_page(struct page *page) |
329 | { | 340 | { |
330 | totalram_pages++; | 341 | totalram_pages++; |
@@ -363,7 +374,6 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, | |||
363 | 374 | ||
364 | int online_pages(unsigned long pfn, unsigned long nr_pages) | 375 | int online_pages(unsigned long pfn, unsigned long nr_pages) |
365 | { | 376 | { |
366 | unsigned long flags; | ||
367 | unsigned long onlined_pages = 0; | 377 | unsigned long onlined_pages = 0; |
368 | struct zone *zone; | 378 | struct zone *zone; |
369 | int need_zonelists_rebuild = 0; | 379 | int need_zonelists_rebuild = 0; |
@@ -391,11 +401,6 @@ int online_pages(unsigned long pfn, unsigned long nr_pages) | |||
391 | * memory_block->state_mutex. | 401 | * memory_block->state_mutex. |
392 | */ | 402 | */ |
393 | zone = page_zone(pfn_to_page(pfn)); | 403 | zone = page_zone(pfn_to_page(pfn)); |
394 | pgdat_resize_lock(zone->zone_pgdat, &flags); | ||
395 | grow_zone_span(zone, pfn, pfn + nr_pages); | ||
396 | grow_pgdat_span(zone->zone_pgdat, pfn, pfn + nr_pages); | ||
397 | pgdat_resize_unlock(zone->zone_pgdat, &flags); | ||
398 | |||
399 | /* | 404 | /* |
400 | * 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. |
401 | * This means the page allocator ignores this zone. | 406 | * This means the page allocator ignores this zone. |