aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Hocko <mhocko@suse.com>2017-02-22 18:45:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-22 19:41:30 -0500
commitfd538803731e50367b7c59ce4ad3454426a3d671 (patch)
treede58ea9fa0765edb9ab42e5145bf1d65245f7f54
parentf0958906cd2bf3730cd7938b8af80a1c23e8ac06 (diff)
mm, vmscan: cleanup lru size claculations
lruvec_lru_size returns the full size of the LRU list while we sometimes need a value reduced only to eligible zones (e.g. for lowmem requests). inactive_list_is_low is one such user. Later patches will add more of them. Add a new parameter to lruvec_lru_size and allow it filter out zones which are not eligible for the given context. Link: http://lkml.kernel.org/r/20170117103702.28542-2-mhocko@kernel.org Signed-off-by: Michal Hocko <mhocko@suse.com> Acked-by: Johannes Weiner <hannes@cmpxchg.org> Acked-by: Hillf Danton <hillf.zj@alibaba-inc.com> Acked-by: Minchan Kim <minchan@kernel.org> Acked-by: Mel Gorman <mgorman@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/mmzone.h2
-rw-r--r--mm/vmscan.c89
-rw-r--r--mm/workingset.c2
3 files changed, 46 insertions, 47 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index f4aac87adcc3..82fc632fd11d 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -779,7 +779,7 @@ static inline struct pglist_data *lruvec_pgdat(struct lruvec *lruvec)
779#endif 779#endif
780} 780}
781 781
782extern unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru); 782extern unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx);
783 783
784#ifdef CONFIG_HAVE_MEMORY_PRESENT 784#ifdef CONFIG_HAVE_MEMORY_PRESENT
785void memory_present(int nid, unsigned long start, unsigned long end); 785void memory_present(int nid, unsigned long start, unsigned long end);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 277e105646a5..e7c75a3c6b53 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -234,22 +234,39 @@ bool pgdat_reclaimable(struct pglist_data *pgdat)
234 pgdat_reclaimable_pages(pgdat) * 6; 234 pgdat_reclaimable_pages(pgdat) * 6;
235} 235}
236 236
237unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru) 237/**
238 * lruvec_lru_size - Returns the number of pages on the given LRU list.
239 * @lruvec: lru vector
240 * @lru: lru to use
241 * @zone_idx: zones to consider (use MAX_NR_ZONES for the whole LRU list)
242 */
243unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru, int zone_idx)
238{ 244{
245 unsigned long lru_size;
246 int zid;
247
239 if (!mem_cgroup_disabled()) 248 if (!mem_cgroup_disabled())
240 return mem_cgroup_get_lru_size(lruvec, lru); 249 lru_size = mem_cgroup_get_lru_size(lruvec, lru);
250 else
251 lru_size = node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
241 252
242 return node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru); 253 for (zid = zone_idx + 1; zid < MAX_NR_ZONES; zid++) {
243} 254 struct zone *zone = &lruvec_pgdat(lruvec)->node_zones[zid];
255 unsigned long size;
244 256
245unsigned long lruvec_zone_lru_size(struct lruvec *lruvec, enum lru_list lru, 257 if (!managed_zone(zone))
246 int zone_idx) 258 continue;
247{ 259
248 if (!mem_cgroup_disabled()) 260 if (!mem_cgroup_disabled())
249 return mem_cgroup_get_zone_lru_size(lruvec, lru, zone_idx); 261 size = mem_cgroup_get_zone_lru_size(lruvec, lru, zid);
262 else
263 size = zone_page_state(&lruvec_pgdat(lruvec)->node_zones[zid],
264 NR_ZONE_LRU_BASE + lru);
265 lru_size -= min(size, lru_size);
266 }
267
268 return lru_size;
250 269
251 return zone_page_state(&lruvec_pgdat(lruvec)->node_zones[zone_idx],
252 NR_ZONE_LRU_BASE + lru);
253} 270}
254 271
255/* 272/*
@@ -2049,11 +2066,10 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
2049 struct scan_control *sc, bool trace) 2066 struct scan_control *sc, bool trace)
2050{ 2067{
2051 unsigned long inactive_ratio; 2068 unsigned long inactive_ratio;
2052 unsigned long total_inactive, inactive; 2069 unsigned long inactive, active;
2053 unsigned long total_active, active; 2070 enum lru_list inactive_lru = file * LRU_FILE;
2071 enum lru_list active_lru = file * LRU_FILE + LRU_ACTIVE;
2054 unsigned long gb; 2072 unsigned long gb;
2055 struct pglist_data *pgdat = lruvec_pgdat(lruvec);
2056 int zid;
2057 2073
2058 /* 2074 /*
2059 * If we don't have swap space, anonymous page deactivation 2075 * If we don't have swap space, anonymous page deactivation
@@ -2062,27 +2078,8 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
2062 if (!file && !total_swap_pages) 2078 if (!file && !total_swap_pages)
2063 return false; 2079 return false;
2064 2080
2065 total_inactive = inactive = lruvec_lru_size(lruvec, file * LRU_FILE); 2081 inactive = lruvec_lru_size(lruvec, inactive_lru, sc->reclaim_idx);
2066 total_active = active = lruvec_lru_size(lruvec, file * LRU_FILE + LRU_ACTIVE); 2082 active = lruvec_lru_size(lruvec, active_lru, sc->reclaim_idx);
2067
2068 /*
2069 * For zone-constrained allocations, it is necessary to check if
2070 * deactivations are required for lowmem to be reclaimed. This
2071 * calculates the inactive/active pages available in eligible zones.
2072 */
2073 for (zid = sc->reclaim_idx + 1; zid < MAX_NR_ZONES; zid++) {
2074 struct zone *zone = &pgdat->node_zones[zid];
2075 unsigned long inactive_zone, active_zone;
2076
2077 if (!managed_zone(zone))
2078 continue;
2079
2080 inactive_zone = lruvec_zone_lru_size(lruvec, file * LRU_FILE, zid);
2081 active_zone = lruvec_zone_lru_size(lruvec, (file * LRU_FILE) + LRU_ACTIVE, zid);
2082
2083 inactive -= min(inactive, inactive_zone);
2084 active -= min(active, active_zone);
2085 }
2086 2083
2087 gb = (inactive + active) >> (30 - PAGE_SHIFT); 2084 gb = (inactive + active) >> (30 - PAGE_SHIFT);
2088 if (gb) 2085 if (gb)
@@ -2091,10 +2088,12 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file,
2091 inactive_ratio = 1; 2088 inactive_ratio = 1;
2092 2089
2093 if (trace) 2090 if (trace)
2094 trace_mm_vmscan_inactive_list_is_low(pgdat->node_id, 2091 trace_mm_vmscan_inactive_list_is_low(lruvec_pgdat(lruvec)->node_id,
2095 sc->reclaim_idx, 2092 sc->reclaim_idx,
2096 total_inactive, inactive, 2093 lruvec_lru_size(lruvec, inactive_lru, MAX_NR_ZONES), inactive,
2097 total_active, active, inactive_ratio, file); 2094 lruvec_lru_size(lruvec, active_lru, MAX_NR_ZONES), active,
2095 inactive_ratio, file);
2096
2098 return inactive * inactive_ratio < active; 2097 return inactive * inactive_ratio < active;
2099} 2098}
2100 2099
@@ -2234,7 +2233,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
2234 * system is under heavy pressure. 2233 * system is under heavy pressure.
2235 */ 2234 */
2236 if (!inactive_list_is_low(lruvec, true, sc, false) && 2235 if (!inactive_list_is_low(lruvec, true, sc, false) &&
2237 lruvec_lru_size(lruvec, LRU_INACTIVE_FILE) >> sc->priority) { 2236 lruvec_lru_size(lruvec, LRU_INACTIVE_FILE, MAX_NR_ZONES) >> sc->priority) {
2238 scan_balance = SCAN_FILE; 2237 scan_balance = SCAN_FILE;
2239 goto out; 2238 goto out;
2240 } 2239 }
@@ -2260,10 +2259,10 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg,
2260 * anon in [0], file in [1] 2259 * anon in [0], file in [1]
2261 */ 2260 */
2262 2261
2263 anon = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON) + 2262 anon = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON, MAX_NR_ZONES) +
2264 lruvec_lru_size(lruvec, LRU_INACTIVE_ANON); 2263 lruvec_lru_size(lruvec, LRU_INACTIVE_ANON, MAX_NR_ZONES);
2265 file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE) + 2264 file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE, MAX_NR_ZONES) +
2266 lruvec_lru_size(lruvec, LRU_INACTIVE_FILE); 2265 lruvec_lru_size(lruvec, LRU_INACTIVE_FILE, MAX_NR_ZONES);
2267 2266
2268 spin_lock_irq(&pgdat->lru_lock); 2267 spin_lock_irq(&pgdat->lru_lock);
2269 if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) { 2268 if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) {
@@ -2301,7 +2300,7 @@ out:
2301 unsigned long size; 2300 unsigned long size;
2302 unsigned long scan; 2301 unsigned long scan;
2303 2302
2304 size = lruvec_lru_size(lruvec, lru); 2303 size = lruvec_lru_size(lruvec, lru, MAX_NR_ZONES);
2305 scan = size >> sc->priority; 2304 scan = size >> sc->priority;
2306 2305
2307 if (!scan && pass && force_scan) 2306 if (!scan && pass && force_scan)
diff --git a/mm/workingset.c b/mm/workingset.c
index abb58ffa3c64..a67f5796b995 100644
--- a/mm/workingset.c
+++ b/mm/workingset.c
@@ -267,7 +267,7 @@ bool workingset_refault(void *shadow)
267 } 267 }
268 lruvec = mem_cgroup_lruvec(pgdat, memcg); 268 lruvec = mem_cgroup_lruvec(pgdat, memcg);
269 refault = atomic_long_read(&lruvec->inactive_age); 269 refault = atomic_long_read(&lruvec->inactive_age);
270 active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE); 270 active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE, MAX_NR_ZONES);
271 rcu_read_unlock(); 271 rcu_read_unlock();
272 272
273 /* 273 /*