aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory_hotplug.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r--mm/memory_hotplug.c86
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
162static 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
179static 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
162static int __add_zone(struct zone *zone, unsigned long phys_start_pfn) 192static 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}
300EXPORT_SYMBOL_GPL(__remove_pages); 337EXPORT_SYMBOL_GPL(__remove_pages);
301 338
302static 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
319static 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
332void online_page(struct page *page) 339void 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
368int online_pages(unsigned long pfn, unsigned long nr_pages) 375int 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