Commit 56e49d218890f49b0057710a4b6fef31f5ffbfec

Authored by Rik van Riel
Committed by Linus Torvalds
1 parent 35efa5e993

vmscan: evict use-once pages first

When the file LRU lists are dominated by streaming IO pages, evict those
pages first, before considering evicting other pages.

This should be safe from deadlocks or performance problems
because only three things can happen to an inactive file page:

1) referenced twice and promoted to the active list
2) evicted by the pageout code
3) under IO, after which it will get evicted or promoted

The pages freed in this way can either be reused for streaming IO, or
allocated for something else.  If the pages are used for streaming IO,
this pageout pattern continues.  Otherwise, we will fall back to the
normal pageout pattern.

Signed-off-by: Rik van Riel <riel@redhat.com>
Reported-by: Elladan <elladan@eskimo.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Lee Schermerhorn <lee.schermerhorn@hp.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 55 additions and 1 deletions Side-by-side Diff

include/linux/memcontrol.h
... ... @@ -94,6 +94,7 @@
94 94 extern void mem_cgroup_record_reclaim_priority(struct mem_cgroup *mem,
95 95 int priority);
96 96 int mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg);
  97 +int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg);
97 98 unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg,
98 99 struct zone *zone,
99 100 enum lru_list lru);
... ... @@ -235,6 +236,12 @@
235 236  
236 237 static inline int
237 238 mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg)
  239 +{
  240 + return 1;
  241 +}
  242 +
  243 +static inline int
  244 +mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg)
238 245 {
239 246 return 1;
240 247 }
... ... @@ -570,6 +570,17 @@
570 570 return 0;
571 571 }
572 572  
  573 +int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg)
  574 +{
  575 + unsigned long active;
  576 + unsigned long inactive;
  577 +
  578 + inactive = mem_cgroup_get_local_zonestat(memcg, LRU_INACTIVE_FILE);
  579 + active = mem_cgroup_get_local_zonestat(memcg, LRU_ACTIVE_FILE);
  580 +
  581 + return (active > inactive);
  582 +}
  583 +
573 584 unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg,
574 585 struct zone *zone,
575 586 enum lru_list lru)
... ... @@ -1351,12 +1351,48 @@
1351 1351 return low;
1352 1352 }
1353 1353  
  1354 +static int inactive_file_is_low_global(struct zone *zone)
  1355 +{
  1356 + unsigned long active, inactive;
  1357 +
  1358 + active = zone_page_state(zone, NR_ACTIVE_FILE);
  1359 + inactive = zone_page_state(zone, NR_INACTIVE_FILE);
  1360 +
  1361 + return (active > inactive);
  1362 +}
  1363 +
  1364 +/**
  1365 + * inactive_file_is_low - check if file pages need to be deactivated
  1366 + * @zone: zone to check
  1367 + * @sc: scan control of this context
  1368 + *
  1369 + * When the system is doing streaming IO, memory pressure here
  1370 + * ensures that active file pages get deactivated, until more
  1371 + * than half of the file pages are on the inactive list.
  1372 + *
  1373 + * Once we get to that situation, protect the system's working
  1374 + * set from being evicted by disabling active file page aging.
  1375 + *
  1376 + * This uses a different ratio than the anonymous pages, because
  1377 + * the page cache uses a use-once replacement algorithm.
  1378 + */
  1379 +static int inactive_file_is_low(struct zone *zone, struct scan_control *sc)
  1380 +{
  1381 + int low;
  1382 +
  1383 + if (scanning_global_lru(sc))
  1384 + low = inactive_file_is_low_global(zone);
  1385 + else
  1386 + low = mem_cgroup_inactive_file_is_low(sc->mem_cgroup);
  1387 + return low;
  1388 +}
  1389 +
1354 1390 static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
1355 1391 struct zone *zone, struct scan_control *sc, int priority)
1356 1392 {
1357 1393 int file = is_file_lru(lru);
1358 1394  
1359   - if (lru == LRU_ACTIVE_FILE) {
  1395 + if (lru == LRU_ACTIVE_FILE && inactive_file_is_low(zone, sc)) {
1360 1396 shrink_active_list(nr_to_scan, zone, sc, priority, file);
1361 1397 return 0;
1362 1398 }