diff options
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 68 |
1 files changed, 29 insertions, 39 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 9cd36b822444..616a2c956b4b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -467,29 +467,6 @@ static inline void rmv_page_order(struct page *page) | |||
467 | } | 467 | } |
468 | 468 | ||
469 | /* | 469 | /* |
470 | * Locate the struct page for both the matching buddy in our | ||
471 | * pair (buddy1) and the combined O(n+1) page they form (page). | ||
472 | * | ||
473 | * 1) Any buddy B1 will have an order O twin B2 which satisfies | ||
474 | * the following equation: | ||
475 | * B2 = B1 ^ (1 << O) | ||
476 | * For example, if the starting buddy (buddy2) is #8 its order | ||
477 | * 1 buddy is #10: | ||
478 | * B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10 | ||
479 | * | ||
480 | * 2) Any buddy B will have an order O+1 parent P which | ||
481 | * satisfies the following equation: | ||
482 | * P = B & ~(1 << O) | ||
483 | * | ||
484 | * Assumption: *_mem_map is contiguous at least up to MAX_ORDER | ||
485 | */ | ||
486 | static inline unsigned long | ||
487 | __find_buddy_index(unsigned long page_idx, unsigned int order) | ||
488 | { | ||
489 | return page_idx ^ (1 << order); | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * This function checks whether a page is free && is the buddy | 470 | * This function checks whether a page is free && is the buddy |
494 | * we can do coalesce a page and its buddy if | 471 | * we can do coalesce a page and its buddy if |
495 | * (a) the buddy is not in a hole && | 472 | * (a) the buddy is not in a hole && |
@@ -569,6 +546,7 @@ static inline void __free_one_page(struct page *page, | |||
569 | unsigned long combined_idx; | 546 | unsigned long combined_idx; |
570 | unsigned long uninitialized_var(buddy_idx); | 547 | unsigned long uninitialized_var(buddy_idx); |
571 | struct page *buddy; | 548 | struct page *buddy; |
549 | int max_order = MAX_ORDER; | ||
572 | 550 | ||
573 | VM_BUG_ON(!zone_is_initialized(zone)); | 551 | VM_BUG_ON(!zone_is_initialized(zone)); |
574 | 552 | ||
@@ -577,13 +555,24 @@ static inline void __free_one_page(struct page *page, | |||
577 | return; | 555 | return; |
578 | 556 | ||
579 | VM_BUG_ON(migratetype == -1); | 557 | VM_BUG_ON(migratetype == -1); |
558 | if (is_migrate_isolate(migratetype)) { | ||
559 | /* | ||
560 | * We restrict max order of merging to prevent merge | ||
561 | * between freepages on isolate pageblock and normal | ||
562 | * pageblock. Without this, pageblock isolation | ||
563 | * could cause incorrect freepage accounting. | ||
564 | */ | ||
565 | max_order = min(MAX_ORDER, pageblock_order + 1); | ||
566 | } else { | ||
567 | __mod_zone_freepage_state(zone, 1 << order, migratetype); | ||
568 | } | ||
580 | 569 | ||
581 | page_idx = pfn & ((1 << MAX_ORDER) - 1); | 570 | page_idx = pfn & ((1 << max_order) - 1); |
582 | 571 | ||
583 | VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page); | 572 | VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page); |
584 | VM_BUG_ON_PAGE(bad_range(zone, page), page); | 573 | VM_BUG_ON_PAGE(bad_range(zone, page), page); |
585 | 574 | ||
586 | while (order < MAX_ORDER-1) { | 575 | while (order < max_order - 1) { |
587 | buddy_idx = __find_buddy_index(page_idx, order); | 576 | buddy_idx = __find_buddy_index(page_idx, order); |
588 | buddy = page + (buddy_idx - page_idx); | 577 | buddy = page + (buddy_idx - page_idx); |
589 | if (!page_is_buddy(page, buddy, order)) | 578 | if (!page_is_buddy(page, buddy, order)) |
@@ -594,9 +583,11 @@ static inline void __free_one_page(struct page *page, | |||
594 | */ | 583 | */ |
595 | if (page_is_guard(buddy)) { | 584 | if (page_is_guard(buddy)) { |
596 | clear_page_guard_flag(buddy); | 585 | clear_page_guard_flag(buddy); |
597 | set_page_private(page, 0); | 586 | set_page_private(buddy, 0); |
598 | __mod_zone_freepage_state(zone, 1 << order, | 587 | if (!is_migrate_isolate(migratetype)) { |
599 | migratetype); | 588 | __mod_zone_freepage_state(zone, 1 << order, |
589 | migratetype); | ||
590 | } | ||
600 | } else { | 591 | } else { |
601 | list_del(&buddy->lru); | 592 | list_del(&buddy->lru); |
602 | zone->free_area[order].nr_free--; | 593 | zone->free_area[order].nr_free--; |
@@ -715,14 +706,12 @@ static void free_pcppages_bulk(struct zone *zone, int count, | |||
715 | /* must delete as __free_one_page list manipulates */ | 706 | /* must delete as __free_one_page list manipulates */ |
716 | list_del(&page->lru); | 707 | list_del(&page->lru); |
717 | mt = get_freepage_migratetype(page); | 708 | mt = get_freepage_migratetype(page); |
709 | if (unlikely(has_isolate_pageblock(zone))) | ||
710 | mt = get_pageblock_migratetype(page); | ||
711 | |||
718 | /* MIGRATE_MOVABLE list may include MIGRATE_RESERVEs */ | 712 | /* MIGRATE_MOVABLE list may include MIGRATE_RESERVEs */ |
719 | __free_one_page(page, page_to_pfn(page), zone, 0, mt); | 713 | __free_one_page(page, page_to_pfn(page), zone, 0, mt); |
720 | trace_mm_page_pcpu_drain(page, 0, mt); | 714 | trace_mm_page_pcpu_drain(page, 0, mt); |
721 | if (likely(!is_migrate_isolate_page(page))) { | ||
722 | __mod_zone_page_state(zone, NR_FREE_PAGES, 1); | ||
723 | if (is_migrate_cma(mt)) | ||
724 | __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, 1); | ||
725 | } | ||
726 | } while (--to_free && --batch_free && !list_empty(list)); | 715 | } while (--to_free && --batch_free && !list_empty(list)); |
727 | } | 716 | } |
728 | spin_unlock(&zone->lock); | 717 | spin_unlock(&zone->lock); |
@@ -739,9 +728,11 @@ static void free_one_page(struct zone *zone, | |||
739 | if (nr_scanned) | 728 | if (nr_scanned) |
740 | __mod_zone_page_state(zone, NR_PAGES_SCANNED, -nr_scanned); | 729 | __mod_zone_page_state(zone, NR_PAGES_SCANNED, -nr_scanned); |
741 | 730 | ||
731 | if (unlikely(has_isolate_pageblock(zone) || | ||
732 | is_migrate_isolate(migratetype))) { | ||
733 | migratetype = get_pfnblock_migratetype(page, pfn); | ||
734 | } | ||
742 | __free_one_page(page, pfn, zone, order, migratetype); | 735 | __free_one_page(page, pfn, zone, order, migratetype); |
743 | if (unlikely(!is_migrate_isolate(migratetype))) | ||
744 | __mod_zone_freepage_state(zone, 1 << order, migratetype); | ||
745 | spin_unlock(&zone->lock); | 736 | spin_unlock(&zone->lock); |
746 | } | 737 | } |
747 | 738 | ||
@@ -1484,7 +1475,7 @@ void split_page(struct page *page, unsigned int order) | |||
1484 | } | 1475 | } |
1485 | EXPORT_SYMBOL_GPL(split_page); | 1476 | EXPORT_SYMBOL_GPL(split_page); |
1486 | 1477 | ||
1487 | static int __isolate_free_page(struct page *page, unsigned int order) | 1478 | int __isolate_free_page(struct page *page, unsigned int order) |
1488 | { | 1479 | { |
1489 | unsigned long watermark; | 1480 | unsigned long watermark; |
1490 | struct zone *zone; | 1481 | struct zone *zone; |
@@ -6408,13 +6399,12 @@ int alloc_contig_range(unsigned long start, unsigned long end, | |||
6408 | 6399 | ||
6409 | /* Make sure the range is really isolated. */ | 6400 | /* Make sure the range is really isolated. */ |
6410 | if (test_pages_isolated(outer_start, end, false)) { | 6401 | if (test_pages_isolated(outer_start, end, false)) { |
6411 | pr_warn("alloc_contig_range test_pages_isolated(%lx, %lx) failed\n", | 6402 | pr_info("%s: [%lx, %lx) PFNs busy\n", |
6412 | outer_start, end); | 6403 | __func__, outer_start, end); |
6413 | ret = -EBUSY; | 6404 | ret = -EBUSY; |
6414 | goto done; | 6405 | goto done; |
6415 | } | 6406 | } |
6416 | 6407 | ||
6417 | |||
6418 | /* Grab isolated pages from freelists. */ | 6408 | /* Grab isolated pages from freelists. */ |
6419 | outer_end = isolate_freepages_range(&cc, outer_start, end); | 6409 | outer_end = isolate_freepages_range(&cc, outer_start, end); |
6420 | if (!outer_end) { | 6410 | if (!outer_end) { |