[RFC v2 PATCH 1/4] mm: make page reporing worker works better for low order page

From: Liang Li
Date: Mon Dec 21 2020 - 13:05:23 EST


'page_reporting_cycle' may take the zone lock for too long when scan
a low order free page list, because the low order page free list may
have a lot iterms and very few pages without the PG_report flag.
Current implementation limits the mini reported order to pageblock_order,
it's ok for most case. If we want to report low order pages, we should
prevent zone lock from being taken too long by the reporting worker, or it
may affect system performance, this patch try to make 'page_reporting_cycle'
work better for low order pages, the zone lock was released periodicly
and cup was yielded voluntarily if needed.

Cc: Alexander Duyck <alexander.h.duyck@xxxxxxxxxxxxxxx>
Cc: Mel Gorman <mgorman@xxxxxxxxxxxxxxxxxxx>
Cc: Andrea Arcangeli <aarcange@xxxxxxxxxx>
Cc: Dan Williams <dan.j.williams@xxxxxxxxx>
Cc: Dave Hansen <dave.hansen@xxxxxxxxx>
Cc: David Hildenbrand <david@xxxxxxxxxx>
Cc: Michal Hocko <mhocko@xxxxxxxx>
Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
Cc: Alex Williamson <alex.williamson@xxxxxxxxxx>
Cc: Michael S. Tsirkin <mst@xxxxxxxxxx>
Signed-off-by: Liang Li <liliang324@xxxxxxxxx>

---
mm/page_reporting.c | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/mm/page_reporting.c b/mm/page_reporting.c
index cd8e13d41df4..0b22db94ce2a 100644
--- a/mm/page_reporting.c
+++ b/mm/page_reporting.c
@@ -6,11 +6,14 @@
#include <linux/export.h>
#include <linux/delay.h>
#include <linux/scatterlist.h>
+#include <linux/sched.h>

#include "page_reporting.h"
#include "internal.h"

#define PAGE_REPORTING_DELAY (2 * HZ)
+#define MAX_SCAN_NUM 1024
+
static struct page_reporting_dev_info __rcu *pr_dev_info __read_mostly;

enum {
@@ -115,7 +118,7 @@ page_reporting_cycle(struct page_reporting_dev_info *prdev, struct zone *zone,
unsigned int page_len = PAGE_SIZE << order;
struct page *page, *next;
long budget;
- int err = 0;
+ int err = 0, scan_cnt = 0;

/*
* Perform early check, if free area is empty there is
@@ -145,8 +148,14 @@ page_reporting_cycle(struct page_reporting_dev_info *prdev, struct zone *zone,
/* loop through free list adding unreported pages to sg list */
list_for_each_entry_safe(page, next, list, lru) {
/* We are going to skip over the reported pages. */
- if (PageReported(page))
+ if (PageReported(page)) {
+ if (++scan_cnt >= MAX_SCAN_NUM) {
+ err = scan_cnt;
+ break;
+ }
continue;
+ }
+

/*
* If we fully consumed our budget then update our
@@ -219,6 +228,26 @@ page_reporting_cycle(struct page_reporting_dev_info *prdev, struct zone *zone,
return err;
}

+static int
+reporting_order_type(struct page_reporting_dev_info *prdev, struct zone *zone,
+ unsigned int order, unsigned int mt,
+ struct scatterlist *sgl, unsigned int *offset)
+{
+ int ret = 0;
+ unsigned long total = 0;
+
+ might_sleep();
+ do {
+ cond_resched();
+ ret = page_reporting_cycle(prdev, zone, order, mt,
+ sgl, offset);
+ if (ret > 0)
+ total += ret;
+ } while (ret > 0 && total < zone->free_area[order].nr_free);
+
+ return ret;
+}
+
static int
page_reporting_process_zone(struct page_reporting_dev_info *prdev,
struct scatterlist *sgl, struct zone *zone)
@@ -245,7 +274,7 @@ page_reporting_process_zone(struct page_reporting_dev_info *prdev,
if (is_migrate_isolate(mt))
continue;

- err = page_reporting_cycle(prdev, zone, order, mt,
+ err = reporting_order_type(prdev, zone, order, mt,
sgl, &offset);
if (err)
return err;
--
2.18.2