@@ -87,10 +87,28 @@ static inline bool is_migrate_movable(int mt)
get_pfnblock_flags_mask(page, page_to_pfn(page), \
PB_migrate_end, MIGRATETYPE_MASK)
+/*
+ * The treatment state indicates the current state of the region pointed to
+ * by the treatment_mt and the membrane pointer. The general idea is that
+ * when we are in the "SETTLING" state the treatment area is contiguous and
+ * it is safe to move on to treating another migratetype. If we are in the
+ * "AERATING" state then the region is being actively processed and we
+ * would cause issues such as potentially isolating a section of raw pages
+ * between two sections of treated pages if we were to move onto another
+ * migratetype.
+ */
+enum treatment_state {
+ TREATMENT_SETTLING,
+ TREATMENT_AERATING,
+};
+
struct free_area {
struct list_head free_list[MIGRATE_TYPES];
unsigned long nr_free_raw;
unsigned long nr_free_treated;
+ struct list_head *membrane;
+ u8 treatment_mt;
+ u8 treatment_state;
};
/* Used for pages not on another list */
@@ -113,6 +131,19 @@ static inline void add_to_free_area_tail(struct page *page, struct free_area *ar
list_add_tail(&page->lru, &area->free_list[migratetype]);
}
+static inline void
+add_to_free_area_treated(struct page *page, struct free_area *area,
+ int migratetype)
+{
+ area->nr_free_treated++;
+
+ BUG_ON(area->treatment_mt != migratetype);
+
+ /* Insert page above membrane, then move membrane to the page */
+ list_add_tail(&page->lru, area->membrane);
+ area->membrane = &page->lru;
+}
+
/* Used for pages which are on another list */
static inline void move_to_free_area(struct page *page, struct free_area *area,
int migratetype)
@@ -135,6 +166,10 @@ static inline void move_to_free_area(struct page *page, struct free_area *area,
area->nr_free_raw++;
}
+ /* push membrane back if we removed the upper boundary */
+ if (area->membrane == &page->lru)
+ area->membrane = page->lru.next;
+
list_move(&page->lru, &area->free_list[migratetype]);
}
@@ -153,6 +188,9 @@ static inline void del_page_from_free_area(struct page *page,
else
area->nr_free_raw--;
+ if (area->membrane == &page->lru)
+ area->membrane = page->lru.next;
+
list_del(&page->lru);
__ClearPageBuddy(page);
__ResetPageTreated(page);
@@ -989,6 +989,11 @@ static inline void __free_one_page(struct page *page,
set_page_order(page, order);
area = &zone->free_area[order];
+ if (PageTreated(page)) {
+ add_to_free_area_treated(page, area, migratetype);
+ return;
+ }
+
if (buddy_merge_likely(pfn, buddy_pfn, page, order) ||
is_shuffle_tail_page(order))
add_to_free_area_tail(page, area, migratetype);
@@ -5961,8 +5966,13 @@ static void __meminit zone_init_free_lists(struct zone *zone)
INIT_LIST_HEAD(&zone->free_area[order].free_list[t]);
for (order = MAX_ORDER; order--; ) {
- zone->free_area[order].nr_free_raw = 0;
- zone->free_area[order].nr_free_treated = 0;
+ struct free_area *area = &zone->free_area[order];
+
+ area->nr_free_raw = 0;
+ area->nr_free_treated = 0;
+ area->treatment_mt = 0;
+ area->treatment_state = TREATMENT_SETTLING;
+ area->membrane = &area->free_list[0];
}
}