diff options
author | Michal Hocko <mhocko@suse.com> | 2017-02-22 18:45:58 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-12 00:41:43 -0500 |
commit | 710531320af876192d76b2c1f68190a1df941b02 (patch) | |
tree | cefd9265906ea0559a1530ec3226484bbc274381 | |
parent | 8f6620e391a43d5da24fa09f98d9b51016545470 (diff) |
mm, vmscan: cleanup lru size claculations
commit fd538803731e50367b7c59ce4ad3454426a3d671 upstream.
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | include/linux/mmzone.h | 2 | ||||
-rw-r--r-- | mm/vmscan.c | 81 | ||||
-rw-r--r-- | mm/workingset.c | 2 |
3 files changed, 41 insertions, 44 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index f99c993dd500..7e273e243a13 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 | ||
782 | extern unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru); | 782 | extern 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 |
785 | void memory_present(int nid, unsigned long start, unsigned long end); | 785 | void memory_present(int nid, unsigned long start, unsigned long end); |
diff --git a/mm/vmscan.c b/mm/vmscan.c index fa30010a5277..cd516c632e8f 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 | ||
237 | unsigned 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 | */ | ||
243 | unsigned 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 | ||
245 | unsigned 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 | /* |
@@ -2028,11 +2045,10 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file, | |||
2028 | struct scan_control *sc) | 2045 | struct scan_control *sc) |
2029 | { | 2046 | { |
2030 | unsigned long inactive_ratio; | 2047 | unsigned long inactive_ratio; |
2031 | unsigned long inactive; | 2048 | unsigned long inactive, active; |
2032 | unsigned long active; | 2049 | enum lru_list inactive_lru = file * LRU_FILE; |
2050 | enum lru_list active_lru = file * LRU_FILE + LRU_ACTIVE; | ||
2033 | unsigned long gb; | 2051 | unsigned long gb; |
2034 | struct pglist_data *pgdat = lruvec_pgdat(lruvec); | ||
2035 | int zid; | ||
2036 | 2052 | ||
2037 | /* | 2053 | /* |
2038 | * If we don't have swap space, anonymous page deactivation | 2054 | * If we don't have swap space, anonymous page deactivation |
@@ -2041,27 +2057,8 @@ static bool inactive_list_is_low(struct lruvec *lruvec, bool file, | |||
2041 | if (!file && !total_swap_pages) | 2057 | if (!file && !total_swap_pages) |
2042 | return false; | 2058 | return false; |
2043 | 2059 | ||
2044 | inactive = lruvec_lru_size(lruvec, file * LRU_FILE); | 2060 | inactive = lruvec_lru_size(lruvec, inactive_lru, sc->reclaim_idx); |
2045 | active = lruvec_lru_size(lruvec, file * LRU_FILE + LRU_ACTIVE); | 2061 | active = lruvec_lru_size(lruvec, active_lru, sc->reclaim_idx); |
2046 | |||
2047 | /* | ||
2048 | * For zone-constrained allocations, it is necessary to check if | ||
2049 | * deactivations are required for lowmem to be reclaimed. This | ||
2050 | * calculates the inactive/active pages available in eligible zones. | ||
2051 | */ | ||
2052 | for (zid = sc->reclaim_idx + 1; zid < MAX_NR_ZONES; zid++) { | ||
2053 | struct zone *zone = &pgdat->node_zones[zid]; | ||
2054 | unsigned long inactive_zone, active_zone; | ||
2055 | |||
2056 | if (!managed_zone(zone)) | ||
2057 | continue; | ||
2058 | |||
2059 | inactive_zone = lruvec_zone_lru_size(lruvec, file * LRU_FILE, zid); | ||
2060 | active_zone = lruvec_zone_lru_size(lruvec, (file * LRU_FILE) + LRU_ACTIVE, zid); | ||
2061 | |||
2062 | inactive -= min(inactive, inactive_zone); | ||
2063 | active -= min(active, active_zone); | ||
2064 | } | ||
2065 | 2062 | ||
2066 | gb = (inactive + active) >> (30 - PAGE_SHIFT); | 2063 | gb = (inactive + active) >> (30 - PAGE_SHIFT); |
2067 | if (gb) | 2064 | if (gb) |
@@ -2208,7 +2205,7 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, | |||
2208 | * system is under heavy pressure. | 2205 | * system is under heavy pressure. |
2209 | */ | 2206 | */ |
2210 | if (!inactive_list_is_low(lruvec, true, sc) && | 2207 | if (!inactive_list_is_low(lruvec, true, sc) && |
2211 | lruvec_lru_size(lruvec, LRU_INACTIVE_FILE) >> sc->priority) { | 2208 | lruvec_lru_size(lruvec, LRU_INACTIVE_FILE, MAX_NR_ZONES) >> sc->priority) { |
2212 | scan_balance = SCAN_FILE; | 2209 | scan_balance = SCAN_FILE; |
2213 | goto out; | 2210 | goto out; |
2214 | } | 2211 | } |
@@ -2234,10 +2231,10 @@ static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, | |||
2234 | * anon in [0], file in [1] | 2231 | * anon in [0], file in [1] |
2235 | */ | 2232 | */ |
2236 | 2233 | ||
2237 | anon = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON) + | 2234 | anon = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON, MAX_NR_ZONES) + |
2238 | lruvec_lru_size(lruvec, LRU_INACTIVE_ANON); | 2235 | lruvec_lru_size(lruvec, LRU_INACTIVE_ANON, MAX_NR_ZONES); |
2239 | file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE) + | 2236 | file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE, MAX_NR_ZONES) + |
2240 | lruvec_lru_size(lruvec, LRU_INACTIVE_FILE); | 2237 | lruvec_lru_size(lruvec, LRU_INACTIVE_FILE, MAX_NR_ZONES); |
2241 | 2238 | ||
2242 | spin_lock_irq(&pgdat->lru_lock); | 2239 | spin_lock_irq(&pgdat->lru_lock); |
2243 | if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) { | 2240 | if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) { |
@@ -2275,7 +2272,7 @@ out: | |||
2275 | unsigned long size; | 2272 | unsigned long size; |
2276 | unsigned long scan; | 2273 | unsigned long scan; |
2277 | 2274 | ||
2278 | size = lruvec_lru_size(lruvec, lru); | 2275 | size = lruvec_lru_size(lruvec, lru, MAX_NR_ZONES); |
2279 | scan = size >> sc->priority; | 2276 | scan = size >> sc->priority; |
2280 | 2277 | ||
2281 | if (!scan && pass && force_scan) | 2278 | if (!scan && pass && force_scan) |
diff --git a/mm/workingset.c b/mm/workingset.c index fb1f9183d89a..33f6f4db32fd 100644 --- a/mm/workingset.c +++ b/mm/workingset.c | |||
@@ -266,7 +266,7 @@ bool workingset_refault(void *shadow) | |||
266 | } | 266 | } |
267 | lruvec = mem_cgroup_lruvec(pgdat, memcg); | 267 | lruvec = mem_cgroup_lruvec(pgdat, memcg); |
268 | refault = atomic_long_read(&lruvec->inactive_age); | 268 | refault = atomic_long_read(&lruvec->inactive_age); |
269 | active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE); | 269 | active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE, MAX_NR_ZONES); |
270 | rcu_read_unlock(); | 270 | rcu_read_unlock(); |
271 | 271 | ||
272 | /* | 272 | /* |