aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c74
1 files changed, 71 insertions, 3 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index aa7e5d2f28a5..d575a3ee8dd8 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -680,6 +680,72 @@ static int fallbacks[MIGRATE_TYPES][MIGRATE_TYPES-1] = {
680 [MIGRATE_MOVABLE] = { MIGRATE_UNMOVABLE }, 680 [MIGRATE_MOVABLE] = { MIGRATE_UNMOVABLE },
681}; 681};
682 682
683/*
684 * Move the free pages in a range to the free lists of the requested type.
685 * Note that start_page and end_pages are not aligned in a MAX_ORDER_NR_PAGES
686 * boundary. If alignment is required, use move_freepages_block()
687 */
688int move_freepages(struct zone *zone,
689 struct page *start_page, struct page *end_page,
690 int migratetype)
691{
692 struct page *page;
693 unsigned long order;
694 int blocks_moved = 0;
695
696#ifndef CONFIG_HOLES_IN_ZONE
697 /*
698 * page_zone is not safe to call in this context when
699 * CONFIG_HOLES_IN_ZONE is set. This bug check is probably redundant
700 * anyway as we check zone boundaries in move_freepages_block().
701 * Remove at a later date when no bug reports exist related to
702 * CONFIG_PAGE_GROUP_BY_MOBILITY
703 */
704 BUG_ON(page_zone(start_page) != page_zone(end_page));
705#endif
706
707 for (page = start_page; page <= end_page;) {
708 if (!pfn_valid_within(page_to_pfn(page))) {
709 page++;
710 continue;
711 }
712
713 if (!PageBuddy(page)) {
714 page++;
715 continue;
716 }
717
718 order = page_order(page);
719 list_del(&page->lru);
720 list_add(&page->lru,
721 &zone->free_area[order].free_list[migratetype]);
722 page += 1 << order;
723 blocks_moved++;
724 }
725
726 return blocks_moved;
727}
728
729int move_freepages_block(struct zone *zone, struct page *page, int migratetype)
730{
731 unsigned long start_pfn, end_pfn;
732 struct page *start_page, *end_page;
733
734 start_pfn = page_to_pfn(page);
735 start_pfn = start_pfn & ~(MAX_ORDER_NR_PAGES-1);
736 start_page = pfn_to_page(start_pfn);
737 end_page = start_page + MAX_ORDER_NR_PAGES - 1;
738 end_pfn = start_pfn + MAX_ORDER_NR_PAGES - 1;
739
740 /* Do not cross zone boundaries */
741 if (start_pfn < zone->zone_start_pfn)
742 start_page = page;
743 if (end_pfn >= zone->zone_start_pfn + zone->spanned_pages)
744 return 0;
745
746 return move_freepages(zone, start_page, end_page, migratetype);
747}
748
683/* Remove an element from the buddy allocator from the fallback list */ 749/* Remove an element from the buddy allocator from the fallback list */
684static struct page *__rmqueue_fallback(struct zone *zone, int order, 750static struct page *__rmqueue_fallback(struct zone *zone, int order,
685 int start_migratetype) 751 int start_migratetype)
@@ -704,11 +770,13 @@ static struct page *__rmqueue_fallback(struct zone *zone, int order,
704 area->nr_free--; 770 area->nr_free--;
705 771
706 /* 772 /*
707 * If breaking a large block of pages, place the buddies 773 * If breaking a large block of pages, move all free
708 * on the preferred allocation list 774 * pages to the preferred allocation list
709 */ 775 */
710 if (unlikely(current_order >= MAX_ORDER / 2)) 776 if (unlikely(current_order >= MAX_ORDER / 2)) {
711 migratetype = start_migratetype; 777 migratetype = start_migratetype;
778 move_freepages_block(zone, page, migratetype);
779 }
712 780
713 /* Remove the page from the freelists */ 781 /* Remove the page from the freelists */
714 list_del(&page->lru); 782 list_del(&page->lru);