kernel: add and enable MGLRU for Linux 5.15
[openwrt/openwrt.git] / target / linux / generic / pending-5.15 / 020-02-mm-vmscan.c-refactor-shrink_node.patch
1 From a810f8e2f1bdd0707eaf05c8b4ba84a3ff2801bd Mon Sep 17 00:00:00 2001
2 From: Yu Zhao <yuzhao@google.com>
3 Date: Sun, 27 Sep 2020 20:49:08 -0600
4 Subject: [PATCH 03/10] mm/vmscan.c: refactor shrink_node()
5
6 This patch refactors shrink_node(). This will make the upcoming
7 changes to mm/vmscan.c more readable.
8
9 Signed-off-by: Yu Zhao <yuzhao@google.com>
10 Tested-by: Konstantin Kharlamov <Hi-Angel@yandex.ru>
11 Change-Id: Iae734b5b4030205b7db6e8c841f747b6f6ae1a04
12 ---
13 mm/vmscan.c | 186 +++++++++++++++++++++++++++-------------------------
14 1 file changed, 98 insertions(+), 88 deletions(-)
15
16 --- a/mm/vmscan.c
17 +++ b/mm/vmscan.c
18 @@ -2562,6 +2562,103 @@ enum scan_balance {
19 SCAN_FILE,
20 };
21
22 +static void prepare_scan_count(pg_data_t *pgdat, struct scan_control *sc)
23 +{
24 + unsigned long file;
25 + struct lruvec *target_lruvec;
26 +
27 + target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat);
28 +
29 + /*
30 + * Determine the scan balance between anon and file LRUs.
31 + */
32 + spin_lock_irq(&target_lruvec->lru_lock);
33 + sc->anon_cost = target_lruvec->anon_cost;
34 + sc->file_cost = target_lruvec->file_cost;
35 + spin_unlock_irq(&target_lruvec->lru_lock);
36 +
37 + /*
38 + * Target desirable inactive:active list ratios for the anon
39 + * and file LRU lists.
40 + */
41 + if (!sc->force_deactivate) {
42 + unsigned long refaults;
43 +
44 + refaults = lruvec_page_state(target_lruvec,
45 + WORKINGSET_ACTIVATE_ANON);
46 + if (refaults != target_lruvec->refaults[0] ||
47 + inactive_is_low(target_lruvec, LRU_INACTIVE_ANON))
48 + sc->may_deactivate |= DEACTIVATE_ANON;
49 + else
50 + sc->may_deactivate &= ~DEACTIVATE_ANON;
51 +
52 + /*
53 + * When refaults are being observed, it means a new
54 + * workingset is being established. Deactivate to get
55 + * rid of any stale active pages quickly.
56 + */
57 + refaults = lruvec_page_state(target_lruvec,
58 + WORKINGSET_ACTIVATE_FILE);
59 + if (refaults != target_lruvec->refaults[1] ||
60 + inactive_is_low(target_lruvec, LRU_INACTIVE_FILE))
61 + sc->may_deactivate |= DEACTIVATE_FILE;
62 + else
63 + sc->may_deactivate &= ~DEACTIVATE_FILE;
64 + } else
65 + sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE;
66 +
67 + /*
68 + * If we have plenty of inactive file pages that aren't
69 + * thrashing, try to reclaim those first before touching
70 + * anonymous pages.
71 + */
72 + file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE);
73 + if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE))
74 + sc->cache_trim_mode = 1;
75 + else
76 + sc->cache_trim_mode = 0;
77 +
78 + /*
79 + * Prevent the reclaimer from falling into the cache trap: as
80 + * cache pages start out inactive, every cache fault will tip
81 + * the scan balance towards the file LRU. And as the file LRU
82 + * shrinks, so does the window for rotation from references.
83 + * This means we have a runaway feedback loop where a tiny
84 + * thrashing file LRU becomes infinitely more attractive than
85 + * anon pages. Try to detect this based on file LRU size.
86 + */
87 + if (!cgroup_reclaim(sc)) {
88 + unsigned long total_high_wmark = 0;
89 + unsigned long free, anon;
90 + int z;
91 +
92 + free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES);
93 + file = node_page_state(pgdat, NR_ACTIVE_FILE) +
94 + node_page_state(pgdat, NR_INACTIVE_FILE);
95 +
96 + for (z = 0; z < MAX_NR_ZONES; z++) {
97 + struct zone *zone = &pgdat->node_zones[z];
98 +
99 + if (!managed_zone(zone))
100 + continue;
101 +
102 + total_high_wmark += high_wmark_pages(zone);
103 + }
104 +
105 + /*
106 + * Consider anon: if that's low too, this isn't a
107 + * runaway file reclaim problem, but rather just
108 + * extreme pressure. Reclaim as per usual then.
109 + */
110 + anon = node_page_state(pgdat, NR_INACTIVE_ANON);
111 +
112 + sc->file_is_tiny =
113 + file + free <= total_high_wmark &&
114 + !(sc->may_deactivate & DEACTIVATE_ANON) &&
115 + anon >> sc->priority;
116 + }
117 +}
118 +
119 /*
120 * Determine how aggressively the anon and file LRU lists should be
121 * scanned. The relative value of each set of LRU lists is determined
122 @@ -3032,7 +3129,6 @@ static void shrink_node(pg_data_t *pgdat
123 unsigned long nr_reclaimed, nr_scanned;
124 struct lruvec *target_lruvec;
125 bool reclaimable = false;
126 - unsigned long file;
127
128 target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat);
129
130 @@ -3048,93 +3144,7 @@ again:
131 nr_reclaimed = sc->nr_reclaimed;
132 nr_scanned = sc->nr_scanned;
133
134 - /*
135 - * Determine the scan balance between anon and file LRUs.
136 - */
137 - spin_lock_irq(&target_lruvec->lru_lock);
138 - sc->anon_cost = target_lruvec->anon_cost;
139 - sc->file_cost = target_lruvec->file_cost;
140 - spin_unlock_irq(&target_lruvec->lru_lock);
141 -
142 - /*
143 - * Target desirable inactive:active list ratios for the anon
144 - * and file LRU lists.
145 - */
146 - if (!sc->force_deactivate) {
147 - unsigned long refaults;
148 -
149 - refaults = lruvec_page_state(target_lruvec,
150 - WORKINGSET_ACTIVATE_ANON);
151 - if (refaults != target_lruvec->refaults[0] ||
152 - inactive_is_low(target_lruvec, LRU_INACTIVE_ANON))
153 - sc->may_deactivate |= DEACTIVATE_ANON;
154 - else
155 - sc->may_deactivate &= ~DEACTIVATE_ANON;
156 -
157 - /*
158 - * When refaults are being observed, it means a new
159 - * workingset is being established. Deactivate to get
160 - * rid of any stale active pages quickly.
161 - */
162 - refaults = lruvec_page_state(target_lruvec,
163 - WORKINGSET_ACTIVATE_FILE);
164 - if (refaults != target_lruvec->refaults[1] ||
165 - inactive_is_low(target_lruvec, LRU_INACTIVE_FILE))
166 - sc->may_deactivate |= DEACTIVATE_FILE;
167 - else
168 - sc->may_deactivate &= ~DEACTIVATE_FILE;
169 - } else
170 - sc->may_deactivate = DEACTIVATE_ANON | DEACTIVATE_FILE;
171 -
172 - /*
173 - * If we have plenty of inactive file pages that aren't
174 - * thrashing, try to reclaim those first before touching
175 - * anonymous pages.
176 - */
177 - file = lruvec_page_state(target_lruvec, NR_INACTIVE_FILE);
178 - if (file >> sc->priority && !(sc->may_deactivate & DEACTIVATE_FILE))
179 - sc->cache_trim_mode = 1;
180 - else
181 - sc->cache_trim_mode = 0;
182 -
183 - /*
184 - * Prevent the reclaimer from falling into the cache trap: as
185 - * cache pages start out inactive, every cache fault will tip
186 - * the scan balance towards the file LRU. And as the file LRU
187 - * shrinks, so does the window for rotation from references.
188 - * This means we have a runaway feedback loop where a tiny
189 - * thrashing file LRU becomes infinitely more attractive than
190 - * anon pages. Try to detect this based on file LRU size.
191 - */
192 - if (!cgroup_reclaim(sc)) {
193 - unsigned long total_high_wmark = 0;
194 - unsigned long free, anon;
195 - int z;
196 -
197 - free = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES);
198 - file = node_page_state(pgdat, NR_ACTIVE_FILE) +
199 - node_page_state(pgdat, NR_INACTIVE_FILE);
200 -
201 - for (z = 0; z < MAX_NR_ZONES; z++) {
202 - struct zone *zone = &pgdat->node_zones[z];
203 - if (!managed_zone(zone))
204 - continue;
205 -
206 - total_high_wmark += high_wmark_pages(zone);
207 - }
208 -
209 - /*
210 - * Consider anon: if that's low too, this isn't a
211 - * runaway file reclaim problem, but rather just
212 - * extreme pressure. Reclaim as per usual then.
213 - */
214 - anon = node_page_state(pgdat, NR_INACTIVE_ANON);
215 -
216 - sc->file_is_tiny =
217 - file + free <= total_high_wmark &&
218 - !(sc->may_deactivate & DEACTIVATE_ANON) &&
219 - anon >> sc->priority;
220 - }
221 + prepare_scan_count(pgdat, sc);
222
223 shrink_node_memcgs(pgdat, sc);
224