The purpose of the code that commit 623762517e23 ("revert 'mm: vmscan: do
not swap anon pages just because free+file is low'") reintroduces is to
prefer swapping anonymous memory rather than trashing the file lru.

If all anonymous memory is unevictable, however, this insistance on
SCAN_ANON ends up thrashing that lru instead.

Check that enough evictable anon memory is actually on this lruvec before
insisting on SCAN_ANON.  SWAP_CLUSTER_MAX is used as the threshold to
determine if only scanning anon is beneficial.

Otherwise, fallback to balanced reclaim so the file lru doesn't remain
untouched.

Signed-off-by: David Rientjes <rient...@google.com>
---
 mm/vmscan.c | 41 +++++++++++++++++++++++------------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2186,26 +2186,31 @@ static void get_scan_count(struct lruvec *lruvec, 
struct mem_cgroup *memcg,
         * anon pages.  Try to detect this based on file LRU size.
         */
        if (global_reclaim(sc)) {
-               unsigned long pgdatfile;
-               unsigned long pgdatfree;
-               int z;
-               unsigned long total_high_wmark = 0;
-
-               pgdatfree = sum_zone_node_page_state(pgdat->node_id, 
NR_FREE_PAGES);
-               pgdatfile = node_page_state(pgdat, NR_ACTIVE_FILE) +
-                          node_page_state(pgdat, NR_INACTIVE_FILE);
-
-               for (z = 0; z < MAX_NR_ZONES; z++) {
-                       struct zone *zone = &pgdat->node_zones[z];
-                       if (!managed_zone(zone))
-                               continue;
+               anon = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON, 
sc->reclaim_idx) +
+                      lruvec_lru_size(lruvec, LRU_INACTIVE_ANON, 
sc->reclaim_idx);
+               if (likely(anon >= SWAP_CLUSTER_MAX)) {
+                       unsigned long total_high_wmark = 0;
+                       unsigned long pgdatfile;
+                       unsigned long pgdatfree;
+                       int z;
+
+                       pgdatfree = sum_zone_node_page_state(pgdat->node_id,
+                                                            NR_FREE_PAGES);
+                       pgdatfile = node_page_state(pgdat, NR_ACTIVE_FILE) +
+                                   node_page_state(pgdat, NR_INACTIVE_FILE);
+
+                       for (z = 0; z < MAX_NR_ZONES; z++) {
+                               struct zone *zone = &pgdat->node_zones[z];
+                               if (!managed_zone(zone))
+                                       continue;
 
-                       total_high_wmark += high_wmark_pages(zone);
-               }
+                               total_high_wmark += high_wmark_pages(zone);
+                       }
 
-               if (unlikely(pgdatfile + pgdatfree <= total_high_wmark)) {
-                       scan_balance = SCAN_ANON;
-                       goto out;
+                       if (unlikely(pgdatfile + pgdatfree <= 
total_high_wmark)) {
+                               scan_balance = SCAN_ANON;
+                               goto out;
+                       }
                }
        }
 

Reply via email to