]> git.hungrycats.org Git - linux/commitdiff
[PATCH] kswapd lockup fix
authorNick Piggin <nickpiggin@yahoo.com.au>
Sun, 17 Oct 2004 02:20:56 +0000 (19:20 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sun, 17 Oct 2004 02:20:56 +0000 (19:20 -0700)
Fix some bugs in the kswapd logic which can cause kswapd lockups.

The balance_pgdat() logic is supposed to cause kswapd to loop across all zones
in the node until each zone either

a) has enough pages free or

b) is deemed to be in an "all pages unreclaimable" state.

In the latter case, we just give the zone a light scan on each balance_pgdat()
scan and wait for the zone to come back to life again.

But the zone->all_unreclaimable logic is broken - if the zone has no pages on
the LRU at all, we perform no scanning of that zone (of course).  So the
zone->pages_scanned is not incremented and the expression

if (zone->pages_scanned > zone->present_pages * 2)
zone->all_unreclaimable = 1;

never is satisfied.

The patch changes that logic to

if (zone->pages_scanned >= (zone->nr_active +
zone->nr_inactive) * 4)
zone->all_unreclaimable = 1;

so if the zone has no LRU pages it will still enter the all_unreclaimable
state.

Another problem is that if the zone has no LRU pages we will tell
shrink_slab() that we scanned zero LRU pages.  This causes shrink_slab() to
scan zero slab objects, which is obviously wrong.  So change shrink_slab() to
perform a decent chunk of slab scanning in this situation.

And put a cond_resched() into the balance_pgdat() outer loop.  Probably
unnecessary, but that's what Jeff had in place when he confirmed that this
patch fixed the lockup :(

Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
mm/vmscan.c

index a6e04da6154adbe52fd283076177b44c6c8b5f5e..1f0d7fb0396ebf8e52a73dcc968c487f6dafbf8d 100644 (file)
@@ -181,7 +181,7 @@ static int shrink_slab(unsigned long scanned, unsigned int gfp_mask,
        struct shrinker *shrinker;
 
        if (scanned == 0)
-               return 0;
+               scanned = SWAP_CLUSTER_MAX;
 
        if (!down_read_trylock(&shrinker_rwsem))
                return 0;
@@ -1065,7 +1065,8 @@ scan:
                        total_reclaimed += sc.nr_reclaimed;
                        if (zone->all_unreclaimable)
                                continue;
-                       if (zone->pages_scanned > zone->present_pages * 2)
+                       if (zone->pages_scanned >= (zone->nr_active +
+                                                       zone->nr_inactive) * 4)
                                zone->all_unreclaimable = 1;
                        /*
                         * If we've done a decent amount of scanning and
@@ -1102,8 +1103,10 @@ out:
 
                zone->prev_priority = zone->temp_priority;
        }
-       if (!all_zones_ok)
+       if (!all_zones_ok) {
+               cond_resched();
                goto loop_again;
+       }
 
        return total_reclaimed;
 }