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 <[email protected]>
---
 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


Reply via email to