Index: linux-2.6/mm/vmscan.c =================================================================== --- linux-2.6.orig/mm/vmscan.c +++ linux-2.6/mm/vmscan.c @@ -1011,6 +1011,8 @@ static unsigned long shrink_zone(int pri { unsigned long nr_active; unsigned long nr_inactive; + unsigned long scan_active; + unsigned long scan_inactive; unsigned long nr_to_scan; unsigned long nr_reclaimed = 0; @@ -1020,34 +1022,47 @@ static unsigned long shrink_zone(int pri * Add one to `nr_to_scan' just to make sure that the kernel will * slowly sift through the active list. */ - zone->nr_scan_active += - (zone_page_state(zone, NR_ACTIVE) >> priority) + 1; - nr_active = zone->nr_scan_active; - if (nr_active >= sc->swap_cluster_max) + nr_active = zone_page_state(zone, NR_INACTIVE); + nr_inactive = zone_page_state(zone, NR_ACTIVE); + + scan_inactive = (nr_inactive >> priority) + 1; + + if (nr_active >= 4*(nr_inactive*2 + 1)) + scan_active = 4*scan_inactive; + else { + unsigned long long tmp; + + tmp = (unsigned long long)scan_inactive * nr_active; + do_div(tmp, nr_inactive*2 + 1); + scan_active = (unsigned long)tmp + 1; + } + + zone->nr_scan_active += scan_active; + scan_active = zone->nr_scan_active; + if (scan_active >= sc->swap_cluster_max) zone->nr_scan_active = 0; else - nr_active = 0; + scan_active = 0; - zone->nr_scan_inactive += - (zone_page_state(zone, NR_INACTIVE) >> priority) + 1; - nr_inactive = zone->nr_scan_inactive; - if (nr_inactive >= sc->swap_cluster_max) + zone->nr_scan_inactive += scan_inactive; + scan_inactive = zone->nr_scan_inactive; + if (scan_inactive >= sc->swap_cluster_max) zone->nr_scan_inactive = 0; else - nr_inactive = 0; + scan_inactive = 0; - while (nr_active || nr_inactive) { - if (nr_active) { - nr_to_scan = min(nr_active, + while (scan_active || scan_inactive) { + if (scan_active) { + nr_to_scan = min(scan_active, (unsigned long)sc->swap_cluster_max); - nr_active -= nr_to_scan; + scan_active -= nr_to_scan; shrink_active_list(nr_to_scan, zone, sc, priority); } - if (nr_inactive) { - nr_to_scan = min(nr_inactive, + if (scan_inactive) { + nr_to_scan = min(scan_inactive, (unsigned long)sc->swap_cluster_max); - nr_inactive -= nr_to_scan; + scan_inactive -= nr_to_scan; nr_reclaimed += shrink_inactive_list(nr_to_scan, zone, sc); }