|
@@ -2216,7 +2216,11 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype)
|
|
|
int fallback_mt;
|
|
|
bool can_steal;
|
|
|
|
|
|
- /* Find the largest possible block of pages in the other list */
|
|
|
+ /*
|
|
|
+ * Find the largest available free page in the other list. This roughly
|
|
|
+ * approximates finding the pageblock with the most free pages, which
|
|
|
+ * would be too costly to do exactly.
|
|
|
+ */
|
|
|
for (current_order = MAX_ORDER-1;
|
|
|
current_order >= order && current_order <= MAX_ORDER-1;
|
|
|
--current_order) {
|
|
@@ -2226,19 +2230,50 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype)
|
|
|
if (fallback_mt == -1)
|
|
|
continue;
|
|
|
|
|
|
- page = list_first_entry(&area->free_list[fallback_mt],
|
|
|
- struct page, lru);
|
|
|
+ /*
|
|
|
+ * We cannot steal all free pages from the pageblock and the
|
|
|
+ * requested migratetype is movable. In that case it's better to
|
|
|
+ * steal and split the smallest available page instead of the
|
|
|
+ * largest available page, because even if the next movable
|
|
|
+ * allocation falls back into a different pageblock than this
|
|
|
+ * one, it won't cause permanent fragmentation.
|
|
|
+ */
|
|
|
+ if (!can_steal && start_migratetype == MIGRATE_MOVABLE
|
|
|
+ && current_order > order)
|
|
|
+ goto find_smallest;
|
|
|
|
|
|
- steal_suitable_fallback(zone, page, start_migratetype,
|
|
|
- can_steal);
|
|
|
+ goto do_steal;
|
|
|
+ }
|
|
|
|
|
|
- trace_mm_page_alloc_extfrag(page, order, current_order,
|
|
|
- start_migratetype, fallback_mt);
|
|
|
+ return false;
|
|
|
|
|
|
- return true;
|
|
|
+find_smallest:
|
|
|
+ for (current_order = order; current_order < MAX_ORDER;
|
|
|
+ current_order++) {
|
|
|
+ area = &(zone->free_area[current_order]);
|
|
|
+ fallback_mt = find_suitable_fallback(area, current_order,
|
|
|
+ start_migratetype, false, &can_steal);
|
|
|
+ if (fallback_mt != -1)
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- return false;
|
|
|
+ /*
|
|
|
+ * This should not happen - we already found a suitable fallback
|
|
|
+ * when looking for the largest page.
|
|
|
+ */
|
|
|
+ VM_BUG_ON(current_order == MAX_ORDER);
|
|
|
+
|
|
|
+do_steal:
|
|
|
+ page = list_first_entry(&area->free_list[fallback_mt],
|
|
|
+ struct page, lru);
|
|
|
+
|
|
|
+ steal_suitable_fallback(zone, page, start_migratetype, can_steal);
|
|
|
+
|
|
|
+ trace_mm_page_alloc_extfrag(page, order, current_order,
|
|
|
+ start_migratetype, fallback_mt);
|
|
|
+
|
|
|
+ return true;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/*
|