[PATCH 09/13] mm/page_reporting: account for unaccepted memory
From: Kevin Loughlin
Date: Mon Oct 26 2026 - 23:02:39 EST
When lazy unaccepted memory is active, pages on zone->unaccepted_pages
are counted in NR_FREE_PAGES (MIGRATE_MOVABLE) as well as NR_UNACCEPTED.
Without accounting for NR_UNACCEPTED in free page reporting watermarks,
page_reporting_process_zone() and __isolate_free_page() treat
unaccepted pages as already-accepted free buddy pages and can over-drain
accepted free lists.
Account for zone_page_state(zone, NR_UNACCEPTED) in
__isolate_free_page(), page_reporting_cycle(), and
page_reporting_process_zone() (using promo_wmark_pages(zone) for free
page reporting watermarks and skipping non-mergeable migratetypes when
has_unaccepted_memory() is active), and enforce
unaccepted_memory_order() as the minimum page_reporting_order.
Signed-off-by: Kevin Loughlin <kevinloughlin@xxxxxxxxxx>
---
mm/page_alloc.c | 3 +++
mm/page_reporting.c | 34 +++++++++++++++++++++++++++++++++-
2 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index c10b77304633..541b2eaf34a4 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3183,6 +3183,9 @@ int __isolate_free_page(struct page *page, unsigned int order)
* exists.
*/
watermark = zone->_watermark[WMARK_MIN] + (1UL << order);
+#ifdef CONFIG_UNACCEPTED_MEMORY
+ watermark += zone_page_state(zone, NR_UNACCEPTED);
+#endif
if (!zone_watermark_ok(zone, 0, watermark, 0, ALLOC_CMA))
return 0;
}
diff --git a/mm/page_reporting.c b/mm/page_reporting.c
index de587be17801..adacdb015b55 100644
--- a/mm/page_reporting.c
+++ b/mm/page_reporting.c
@@ -17,11 +17,14 @@ unsigned int page_reporting_order = PAGE_REPORTING_ORDER_UNSPECIFIED;
static int page_order_update_notify(const char *val, const struct kernel_param *kp)
{
+ unsigned int min_order = has_unaccepted_memory() ?
+ unaccepted_memory_order() : 0;
+
/*
* If param is set beyond this limit, order is set to default
* pageblock_order value
*/
- return param_set_uint_minmax(val, kp, 0, MAX_PAGE_ORDER);
+ return param_set_uint_minmax(val, kp, min_order, MAX_PAGE_ORDER);
}
static const struct kernel_param_ops page_reporting_param_ops = {
@@ -206,6 +209,21 @@ page_reporting_cycle(struct page_reporting_dev_info *prdev, struct zone *zone,
/* Attempt to pull page from list and place in scatterlist */
if (*offset) {
+#ifdef CONFIG_UNACCEPTED_MEMORY
+ if (has_unaccepted_memory() ||
+ !list_empty(&zone->unaccepted_pages)) {
+ unsigned long watermark;
+
+ watermark = promo_wmark_pages(zone) +
+ zone_page_state(zone, NR_UNACCEPTED) +
+ (1UL << order);
+ if (!zone_watermark_ok(zone, 0, watermark, 0,
+ ALLOC_CMA)) {
+ next = page;
+ break;
+ }
+ }
+#endif
if (!__isolate_free_page(page, order)) {
next = page;
break;
@@ -275,6 +293,12 @@ page_reporting_process_zone(struct page_reporting_dev_info *prdev,
/* Generate minimum watermark to be able to guarantee progress */
watermark = low_wmark_pages(zone) +
(prdev->capacity << page_reporting_order);
+#ifdef CONFIG_UNACCEPTED_MEMORY
+ if (has_unaccepted_memory() || !list_empty(&zone->unaccepted_pages))
+ watermark = promo_wmark_pages(zone) +
+ zone_page_state(zone, NR_UNACCEPTED) +
+ (prdev->capacity << page_reporting_order);
+#endif
/*
* Cancel request if insufficient free memory or if we failed
@@ -289,6 +313,11 @@ page_reporting_process_zone(struct page_reporting_dev_info *prdev,
/* We do not pull pages from the isolate free list */
if (is_migrate_isolate(mt))
continue;
+#ifdef CONFIG_UNACCEPTED_MEMORY
+ if (has_unaccepted_memory() &&
+ !migratetype_is_mergeable(mt))
+ continue;
+#endif
err = page_reporting_cycle(prdev, zone, order, mt,
sgl, &offset);
@@ -384,6 +413,9 @@ int page_reporting_register(struct page_reporting_dev_info *prdev)
else
page_reporting_order = pageblock_order;
}
+ if (has_unaccepted_memory() &&
+ page_reporting_order < unaccepted_memory_order())
+ page_reporting_order = unaccepted_memory_order();
if (!prdev->capacity || prdev->capacity > PAGE_REPORTING_CAPACITY)
prdev->capacity = PAGE_REPORTING_CAPACITY;
--
2.56.0.307.g5fe7bd680c-goog