diff options
-rw-r--r-- | include/linux/mmzone.h | 4 | ||||
-rw-r--r-- | mm/compaction.c | 63 | ||||
-rw-r--r-- | mm/internal.h | 6 | ||||
-rw-r--r-- | mm/page_alloc.c | 5 |
4 files changed, 73 insertions, 5 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 1495d952e641..1aeadce4d56e 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
@@ -368,6 +368,10 @@ struct zone { | |||
368 | */ | 368 | */ |
369 | spinlock_t lock; | 369 | spinlock_t lock; |
370 | int all_unreclaimable; /* All pages pinned */ | 370 | int all_unreclaimable; /* All pages pinned */ |
371 | #if defined CONFIG_COMPACTION || defined CONFIG_CMA | ||
372 | /* pfn where the last incremental compaction isolated free pages */ | ||
373 | unsigned long compact_cached_free_pfn; | ||
374 | #endif | ||
371 | #ifdef CONFIG_MEMORY_HOTPLUG | 375 | #ifdef CONFIG_MEMORY_HOTPLUG |
372 | /* see spanned/present_pages for more description */ | 376 | /* see spanned/present_pages for more description */ |
373 | seqlock_t span_seqlock; | 377 | seqlock_t span_seqlock; |
diff --git a/mm/compaction.c b/mm/compaction.c index 2f42d9528539..e78cb9688421 100644 --- a/mm/compaction.c +++ b/mm/compaction.c | |||
@@ -422,6 +422,17 @@ static void isolate_freepages(struct zone *zone, | |||
422 | pfn -= pageblock_nr_pages) { | 422 | pfn -= pageblock_nr_pages) { |
423 | unsigned long isolated; | 423 | unsigned long isolated; |
424 | 424 | ||
425 | /* | ||
426 | * Skip ahead if another thread is compacting in the area | ||
427 | * simultaneously. If we wrapped around, we can only skip | ||
428 | * ahead if zone->compact_cached_free_pfn also wrapped to | ||
429 | * above our starting point. | ||
430 | */ | ||
431 | if (cc->order > 0 && (!cc->wrapped || | ||
432 | zone->compact_cached_free_pfn > | ||
433 | cc->start_free_pfn)) | ||
434 | pfn = min(pfn, zone->compact_cached_free_pfn); | ||
435 | |||
425 | if (!pfn_valid(pfn)) | 436 | if (!pfn_valid(pfn)) |
426 | continue; | 437 | continue; |
427 | 438 | ||
@@ -461,8 +472,11 @@ static void isolate_freepages(struct zone *zone, | |||
461 | * looking for free pages, the search will restart here as | 472 | * looking for free pages, the search will restart here as |
462 | * page migration may have returned some pages to the allocator | 473 | * page migration may have returned some pages to the allocator |
463 | */ | 474 | */ |
464 | if (isolated) | 475 | if (isolated) { |
465 | high_pfn = max(high_pfn, pfn); | 476 | high_pfn = max(high_pfn, pfn); |
477 | if (cc->order > 0) | ||
478 | zone->compact_cached_free_pfn = high_pfn; | ||
479 | } | ||
466 | } | 480 | } |
467 | 481 | ||
468 | /* split_free_page does not map the pages */ | 482 | /* split_free_page does not map the pages */ |
@@ -556,6 +570,20 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, | |||
556 | return ISOLATE_SUCCESS; | 570 | return ISOLATE_SUCCESS; |
557 | } | 571 | } |
558 | 572 | ||
573 | /* | ||
574 | * Returns the start pfn of the last page block in a zone. This is the starting | ||
575 | * point for full compaction of a zone. Compaction searches for free pages from | ||
576 | * the end of each zone, while isolate_freepages_block scans forward inside each | ||
577 | * page block. | ||
578 | */ | ||
579 | static unsigned long start_free_pfn(struct zone *zone) | ||
580 | { | ||
581 | unsigned long free_pfn; | ||
582 | free_pfn = zone->zone_start_pfn + zone->spanned_pages; | ||
583 | free_pfn &= ~(pageblock_nr_pages-1); | ||
584 | return free_pfn; | ||
585 | } | ||
586 | |||
559 | static int compact_finished(struct zone *zone, | 587 | static int compact_finished(struct zone *zone, |
560 | struct compact_control *cc) | 588 | struct compact_control *cc) |
561 | { | 589 | { |
@@ -565,8 +593,26 @@ static int compact_finished(struct zone *zone, | |||
565 | if (fatal_signal_pending(current)) | 593 | if (fatal_signal_pending(current)) |
566 | return COMPACT_PARTIAL; | 594 | return COMPACT_PARTIAL; |
567 | 595 | ||
568 | /* Compaction run completes if the migrate and free scanner meet */ | 596 | /* |
569 | if (cc->free_pfn <= cc->migrate_pfn) | 597 | * A full (order == -1) compaction run starts at the beginning and |
598 | * end of a zone; it completes when the migrate and free scanner meet. | ||
599 | * A partial (order > 0) compaction can start with the free scanner | ||
600 | * at a random point in the zone, and may have to restart. | ||
601 | */ | ||
602 | if (cc->free_pfn <= cc->migrate_pfn) { | ||
603 | if (cc->order > 0 && !cc->wrapped) { | ||
604 | /* We started partway through; restart at the end. */ | ||
605 | unsigned long free_pfn = start_free_pfn(zone); | ||
606 | zone->compact_cached_free_pfn = free_pfn; | ||
607 | cc->free_pfn = free_pfn; | ||
608 | cc->wrapped = 1; | ||
609 | return COMPACT_CONTINUE; | ||
610 | } | ||
611 | return COMPACT_COMPLETE; | ||
612 | } | ||
613 | |||
614 | /* We wrapped around and ended up where we started. */ | ||
615 | if (cc->wrapped && cc->free_pfn <= cc->start_free_pfn) | ||
570 | return COMPACT_COMPLETE; | 616 | return COMPACT_COMPLETE; |
571 | 617 | ||
572 | /* | 618 | /* |
@@ -664,8 +710,15 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) | |||
664 | 710 | ||
665 | /* Setup to move all movable pages to the end of the zone */ | 711 | /* Setup to move all movable pages to the end of the zone */ |
666 | cc->migrate_pfn = zone->zone_start_pfn; | 712 | cc->migrate_pfn = zone->zone_start_pfn; |
667 | cc->free_pfn = cc->migrate_pfn + zone->spanned_pages; | 713 | |
668 | cc->free_pfn &= ~(pageblock_nr_pages-1); | 714 | if (cc->order > 0) { |
715 | /* Incremental compaction. Start where the last one stopped. */ | ||
716 | cc->free_pfn = zone->compact_cached_free_pfn; | ||
717 | cc->start_free_pfn = cc->free_pfn; | ||
718 | } else { | ||
719 | /* Order == -1 starts at the end of the zone. */ | ||
720 | cc->free_pfn = start_free_pfn(zone); | ||
721 | } | ||
669 | 722 | ||
670 | migrate_prep_local(); | 723 | migrate_prep_local(); |
671 | 724 | ||
diff --git a/mm/internal.h b/mm/internal.h index 2ba87fbfb75b..da6b9b2ed3fc 100644 --- a/mm/internal.h +++ b/mm/internal.h | |||
@@ -118,8 +118,14 @@ struct compact_control { | |||
118 | unsigned long nr_freepages; /* Number of isolated free pages */ | 118 | unsigned long nr_freepages; /* Number of isolated free pages */ |
119 | unsigned long nr_migratepages; /* Number of pages to migrate */ | 119 | unsigned long nr_migratepages; /* Number of pages to migrate */ |
120 | unsigned long free_pfn; /* isolate_freepages search base */ | 120 | unsigned long free_pfn; /* isolate_freepages search base */ |
121 | unsigned long start_free_pfn; /* where we started the search */ | ||
121 | unsigned long migrate_pfn; /* isolate_migratepages search base */ | 122 | unsigned long migrate_pfn; /* isolate_migratepages search base */ |
122 | bool sync; /* Synchronous migration */ | 123 | bool sync; /* Synchronous migration */ |
124 | bool wrapped; /* Order > 0 compactions are | ||
125 | incremental, once free_pfn | ||
126 | and migrate_pfn meet, we restart | ||
127 | from the top of the zone; | ||
128 | remember we wrapped around. */ | ||
123 | 129 | ||
124 | int order; /* order a direct compactor needs */ | 130 | int order; /* order a direct compactor needs */ |
125 | int migratetype; /* MOVABLE, RECLAIMABLE etc */ | 131 | int migratetype; /* MOVABLE, RECLAIMABLE etc */ |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index fba2a1223f14..94fc475c3f94 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -4397,6 +4397,11 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat, | |||
4397 | 4397 | ||
4398 | zone->spanned_pages = size; | 4398 | zone->spanned_pages = size; |
4399 | zone->present_pages = realsize; | 4399 | zone->present_pages = realsize; |
4400 | #if defined CONFIG_COMPACTION || defined CONFIG_CMA | ||
4401 | zone->compact_cached_free_pfn = zone->zone_start_pfn + | ||
4402 | zone->spanned_pages; | ||
4403 | zone->compact_cached_free_pfn &= ~(pageblock_nr_pages-1); | ||
4404 | #endif | ||
4400 | #ifdef CONFIG_NUMA | 4405 | #ifdef CONFIG_NUMA |
4401 | zone->node = nid; | 4406 | zone->node = nid; |
4402 | zone->min_unmapped_pages = (realsize*sysctl_min_unmapped_ratio) | 4407 | zone->min_unmapped_pages = (realsize*sysctl_min_unmapped_ratio) |