[PATCH] mm: prevent page thrashing for non-swap

From: Minchan Kim
Date: Wed Jan 28 2015 - 00:01:57 EST


Josh reported

"I have no swap configured. I have 16GB RAM. If Chrome or Gimp or some
other stupid program goes off the deep end and eats up my RAM, I hit
some 15.5GB or 15.75GB usage and stay there for about 40 minutes. Every
time the program tries to do something to eat more RAM, it cranks disk
hard; the disk starts thrashing, the mouse pointer stops moving, and
nothing goes on. It's like swapping like crazy, except you're reading
library files instead of paged anonymous RAM."

With swap enable, get_scan_count has a logic to prevent cache thrasing
but it doesn't with no swap case. This patch adds the check for
non-swap case so that we shouldn't drop all of page cache in non-swap
case, either to prevent cache thrashing.

Reported-by: John Moser <john.r.moser@xxxxxxxxx>
Signed-off-by: Minchan Kim <minchan@xxxxxxxxxx>
---
mm/vmscan.c | 42 ++++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
index 671e47edb584..2a2236fceaee 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1957,6 +1957,22 @@ enum scan_balance {
SCAN_FILE,
};

+bool enough_file_pages(struct zone *zone)
+{
+ bool ret = true;
+ unsigned long zonefile;
+ unsigned long zonefree;
+
+ zonefree = zone_page_state(zone, NR_FREE_PAGES);
+ zonefile = zone_page_state(zone, NR_ACTIVE_FILE) +
+ zone_page_state(zone, NR_INACTIVE_FILE);
+
+ if (unlikely(zonefile + zonefree <= high_wmark_pages(zone)))
+ ret = false;
+
+ return ret;
+}
+
/*
* Determine how aggressively the anon and file LRU lists should be
* scanned. The relative value of each set of LRU lists is determined
@@ -2039,18 +2055,9 @@ static void get_scan_count(struct lruvec *lruvec, int swappiness,
* thrashing file LRU becomes infinitely more attractive than
* anon pages. Try to detect this based on file LRU size.
*/
- if (global_reclaim(sc)) {
- unsigned long zonefile;
- unsigned long zonefree;
-
- zonefree = zone_page_state(zone, NR_FREE_PAGES);
- zonefile = zone_page_state(zone, NR_ACTIVE_FILE) +
- zone_page_state(zone, NR_INACTIVE_FILE);
-
- if (unlikely(zonefile + zonefree <= high_wmark_pages(zone))) {
- scan_balance = SCAN_ANON;
- goto out;
- }
+ if (global_reclaim(sc) && !enough_file_pages(zone)) {
+ scan_balance = SCAN_ANON;
+ goto out;
}

/*
@@ -2143,6 +2150,17 @@ out:
denominator);
break;
case SCAN_FILE:
+ /*
+ * If there isn't enough page cache to prevent
+ * cache thrashing, OOM is better than long time
+ * unresponsible system.
+ */
+ if (global_reclaim(sc) && file &&
+ !enough_file_pages(zone)) {
+ size = 0;
+ scan = 0;
+ break;
+ }
case SCAN_ANON:
/* Scan one type exclusively */
if ((scan_balance == SCAN_FILE) != file) {
--
1.9.1

--
Kind regards,
Minchan Kim
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/