|
@@ -692,34 +692,28 @@ static inline void __free_one_page(struct page *page,
|
|
|
unsigned long combined_idx;
|
|
|
unsigned long uninitialized_var(buddy_idx);
|
|
|
struct page *buddy;
|
|
|
- unsigned int max_order = MAX_ORDER;
|
|
|
+ unsigned int max_order;
|
|
|
+
|
|
|
+ max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
|
|
|
|
|
|
VM_BUG_ON(!zone_is_initialized(zone));
|
|
|
VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page);
|
|
|
|
|
|
VM_BUG_ON(migratetype == -1);
|
|
|
- if (is_migrate_isolate(migratetype)) {
|
|
|
- /*
|
|
|
- * We restrict max order of merging to prevent merge
|
|
|
- * between freepages on isolate pageblock and normal
|
|
|
- * pageblock. Without this, pageblock isolation
|
|
|
- * could cause incorrect freepage accounting.
|
|
|
- */
|
|
|
- max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1);
|
|
|
- } else {
|
|
|
+ if (likely(!is_migrate_isolate(migratetype)))
|
|
|
__mod_zone_freepage_state(zone, 1 << order, migratetype);
|
|
|
- }
|
|
|
|
|
|
- page_idx = pfn & ((1 << max_order) - 1);
|
|
|
+ page_idx = pfn & ((1 << MAX_ORDER) - 1);
|
|
|
|
|
|
VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page);
|
|
|
VM_BUG_ON_PAGE(bad_range(zone, page), page);
|
|
|
|
|
|
+continue_merging:
|
|
|
while (order < max_order - 1) {
|
|
|
buddy_idx = __find_buddy_index(page_idx, order);
|
|
|
buddy = page + (buddy_idx - page_idx);
|
|
|
if (!page_is_buddy(page, buddy, order))
|
|
|
- break;
|
|
|
+ goto done_merging;
|
|
|
/*
|
|
|
* Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page,
|
|
|
* merge with it and move up one order.
|
|
@@ -736,6 +730,32 @@ static inline void __free_one_page(struct page *page,
|
|
|
page_idx = combined_idx;
|
|
|
order++;
|
|
|
}
|
|
|
+ if (max_order < MAX_ORDER) {
|
|
|
+ /* If we are here, it means order is >= pageblock_order.
|
|
|
+ * We want to prevent merge between freepages on isolate
|
|
|
+ * pageblock and normal pageblock. Without this, pageblock
|
|
|
+ * isolation could cause incorrect freepage or CMA accounting.
|
|
|
+ *
|
|
|
+ * We don't want to hit this code for the more frequent
|
|
|
+ * low-order merging.
|
|
|
+ */
|
|
|
+ if (unlikely(has_isolate_pageblock(zone))) {
|
|
|
+ int buddy_mt;
|
|
|
+
|
|
|
+ buddy_idx = __find_buddy_index(page_idx, order);
|
|
|
+ buddy = page + (buddy_idx - page_idx);
|
|
|
+ buddy_mt = get_pageblock_migratetype(buddy);
|
|
|
+
|
|
|
+ if (migratetype != buddy_mt
|
|
|
+ && (is_migrate_isolate(migratetype) ||
|
|
|
+ is_migrate_isolate(buddy_mt)))
|
|
|
+ goto done_merging;
|
|
|
+ }
|
|
|
+ max_order++;
|
|
|
+ goto continue_merging;
|
|
|
+ }
|
|
|
+
|
|
|
+done_merging:
|
|
|
set_page_order(page, order);
|
|
|
|
|
|
/*
|