summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/memory_hotplug.c72
1 files changed, 15 insertions, 57 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index b1be791f772d..df570e5c71cc 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -436,67 +436,25 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
436 zone_span_writeunlock(zone); 436 zone_span_writeunlock(zone);
437} 437}
438 438
439static void shrink_pgdat_span(struct pglist_data *pgdat, 439static void update_pgdat_span(struct pglist_data *pgdat)
440 unsigned long start_pfn, unsigned long end_pfn)
441{ 440{
442 unsigned long pgdat_start_pfn = pgdat->node_start_pfn; 441 unsigned long node_start_pfn = 0, node_end_pfn = 0;
443 unsigned long p = pgdat_end_pfn(pgdat); /* pgdat_end_pfn namespace clash */ 442 struct zone *zone;
444 unsigned long pgdat_end_pfn = p;
445 unsigned long pfn;
446 int nid = pgdat->node_id;
447
448 if (pgdat_start_pfn == start_pfn) {
449 /*
450 * If the section is smallest section in the pgdat, it need
451 * shrink pgdat->node_start_pfn and pgdat->node_spanned_pages.
452 * In this case, we find second smallest valid mem_section
453 * for shrinking zone.
454 */
455 pfn = find_smallest_section_pfn(nid, NULL, end_pfn,
456 pgdat_end_pfn);
457 if (pfn) {
458 pgdat->node_start_pfn = pfn;
459 pgdat->node_spanned_pages = pgdat_end_pfn - pfn;
460 }
461 } else if (pgdat_end_pfn == end_pfn) {
462 /*
463 * If the section is biggest section in the pgdat, it need
464 * shrink pgdat->node_spanned_pages.
465 * In this case, we find second biggest valid mem_section for
466 * shrinking zone.
467 */
468 pfn = find_biggest_section_pfn(nid, NULL, pgdat_start_pfn,
469 start_pfn);
470 if (pfn)
471 pgdat->node_spanned_pages = pfn - pgdat_start_pfn + 1;
472 }
473
474 /*
475 * If the section is not biggest or smallest mem_section in the pgdat,
476 * it only creates a hole in the pgdat. So in this case, we need not
477 * change the pgdat.
478 * But perhaps, the pgdat has only hole data. Thus it check the pgdat
479 * has only hole or not.
480 */
481 pfn = pgdat_start_pfn;
482 for (; pfn < pgdat_end_pfn; pfn += PAGES_PER_SUBSECTION) {
483 if (unlikely(!pfn_valid(pfn)))
484 continue;
485
486 if (pfn_to_nid(pfn) != nid)
487 continue;
488 443
489 /* Skip range to be removed */ 444 for (zone = pgdat->node_zones;
490 if (pfn >= start_pfn && pfn < end_pfn) 445 zone < pgdat->node_zones + MAX_NR_ZONES; zone++) {
491 continue; 446 unsigned long zone_end_pfn = zone->zone_start_pfn +
447 zone->spanned_pages;
492 448
493 /* If we find valid section, we have nothing to do */ 449 /* No need to lock the zones, they can't change. */
494 return; 450 if (zone_end_pfn > node_end_pfn)
451 node_end_pfn = zone_end_pfn;
452 if (zone->zone_start_pfn < node_start_pfn)
453 node_start_pfn = zone->zone_start_pfn;
495 } 454 }
496 455
497 /* The pgdat has no valid section */ 456 pgdat->node_start_pfn = node_start_pfn;
498 pgdat->node_start_pfn = 0; 457 pgdat->node_spanned_pages = node_end_pfn - node_start_pfn;
499 pgdat->node_spanned_pages = 0;
500} 458}
501 459
502static void __remove_zone(struct zone *zone, unsigned long start_pfn, 460static void __remove_zone(struct zone *zone, unsigned long start_pfn,
@@ -507,7 +465,7 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn,
507 465
508 pgdat_resize_lock(zone->zone_pgdat, &flags); 466 pgdat_resize_lock(zone->zone_pgdat, &flags);
509 shrink_zone_span(zone, start_pfn, start_pfn + nr_pages); 467 shrink_zone_span(zone, start_pfn, start_pfn + nr_pages);
510 shrink_pgdat_span(pgdat, start_pfn, start_pfn + nr_pages); 468 update_pgdat_span(pgdat);
511 pgdat_resize_unlock(zone->zone_pgdat, &flags); 469 pgdat_resize_unlock(zone->zone_pgdat, &flags);
512} 470}
513 471