diff options
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a6326c71b663..596180fedd3a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -475,6 +475,8 @@ static inline void __free_one_page(struct page *page, | |||
475 | int migratetype) | 475 | int migratetype) |
476 | { | 476 | { |
477 | unsigned long page_idx; | 477 | unsigned long page_idx; |
478 | unsigned long combined_idx; | ||
479 | struct page *buddy; | ||
478 | 480 | ||
479 | if (unlikely(PageCompound(page))) | 481 | if (unlikely(PageCompound(page))) |
480 | if (unlikely(destroy_compound_page(page, order))) | 482 | if (unlikely(destroy_compound_page(page, order))) |
@@ -488,9 +490,6 @@ static inline void __free_one_page(struct page *page, | |||
488 | VM_BUG_ON(bad_range(zone, page)); | 490 | VM_BUG_ON(bad_range(zone, page)); |
489 | 491 | ||
490 | while (order < MAX_ORDER-1) { | 492 | while (order < MAX_ORDER-1) { |
491 | unsigned long combined_idx; | ||
492 | struct page *buddy; | ||
493 | |||
494 | buddy = __page_find_buddy(page, page_idx, order); | 493 | buddy = __page_find_buddy(page, page_idx, order); |
495 | if (!page_is_buddy(page, buddy, order)) | 494 | if (!page_is_buddy(page, buddy, order)) |
496 | break; | 495 | break; |
@@ -505,8 +504,29 @@ static inline void __free_one_page(struct page *page, | |||
505 | order++; | 504 | order++; |
506 | } | 505 | } |
507 | set_page_order(page, order); | 506 | set_page_order(page, order); |
508 | list_add(&page->lru, | 507 | |
509 | &zone->free_area[order].free_list[migratetype]); | 508 | /* |
509 | * If this is not the largest possible page, check if the buddy | ||
510 | * of the next-highest order is free. If it is, it's possible | ||
511 | * that pages are being freed that will coalesce soon. In case, | ||
512 | * that is happening, add the free page to the tail of the list | ||
513 | * so it's less likely to be used soon and more likely to be merged | ||
514 | * as a higher order page | ||
515 | */ | ||
516 | if ((order < MAX_ORDER-1) && pfn_valid_within(page_to_pfn(buddy))) { | ||
517 | struct page *higher_page, *higher_buddy; | ||
518 | combined_idx = __find_combined_index(page_idx, order); | ||
519 | higher_page = page + combined_idx - page_idx; | ||
520 | higher_buddy = __page_find_buddy(higher_page, combined_idx, order + 1); | ||
521 | if (page_is_buddy(higher_page, higher_buddy, order + 1)) { | ||
522 | list_add_tail(&page->lru, | ||
523 | &zone->free_area[order].free_list[migratetype]); | ||
524 | goto out; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | list_add(&page->lru, &zone->free_area[order].free_list[migratetype]); | ||
529 | out: | ||
510 | zone->free_area[order].nr_free++; | 530 | zone->free_area[order].nr_free++; |
511 | } | 531 | } |
512 | 532 | ||