From: Nick Piggin If the zone has a very small number of inactive pages, local variable `ratio' can be huge and we do way too much scanning. So much so that Ingo hit an NMI watchdog expiry, although that was because the zone would have a had a single refcount-zero page in it, and that logic recently got fixed up via get_page_testone(). Nick's patch simply puts a sane-looking upper bound on the number of pages which we'll scan in this round. It hasn't had a lot of thought or testing yet. --- 25-akpm/mm/vmscan.c | 28 +++++++++++++++++++--------- 1 files changed, 19 insertions(+), 9 deletions(-) diff -puN mm/vmscan.c~vm-shrink-zone mm/vmscan.c --- 25/mm/vmscan.c~vm-shrink-zone Tue May 18 15:06:27 2004 +++ 25-akpm/mm/vmscan.c Tue May 18 15:06:27 2004 @@ -742,23 +742,33 @@ static int shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask, int *total_scanned, struct page_state *ps, int do_writepage) { - unsigned long ratio; + unsigned long scan_active; int count; /* * Try to keep the active list 2/3 of the size of the cache. And * make sure that refill_inactive is given a decent number of pages. * - * The "ratio+1" here is important. With pagecache-intensive workloads - * the inactive list is huge, and `ratio' evaluates to zero all the - * time. Which pins the active list memory. So we add one to `ratio' - * just to make sure that the kernel will slowly sift through the - * active list. + * The "scan_active + 1" here is important. With pagecache-intensive + * workloads the inactive list is huge, and `ratio' evaluates to zero + * all the time. Which pins the active list memory. So we add one to + * `scan_active' just to make sure that the kernel will slowly sift + * through the active list. */ - ratio = (unsigned long)SWAP_CLUSTER_MAX * zone->nr_active / - ((zone->nr_inactive | 1) * 2); + if (zone->nr_active >= 4*(zone->nr_inactive*2 + 1)) { + /* Don't scan more than 4 times the inactive list scan size */ + scan_active = 4*max_scan; + } else { + unsigned long long tmp; - atomic_add(ratio+1, &zone->nr_scan_active); + /* Cast to long long so the multiply doesn't overflow */ + + tmp = (unsigned long long)max_scan * zone->nr_active; + do_div(tmp, zone->nr_inactive*2 + 1); + scan_active = (unsigned long)tmp; + } + + atomic_add(scan_active + 1, &zone->nr_scan_active); count = atomic_read(&zone->nr_scan_active); if (count >= SWAP_CLUSTER_MAX) { atomic_set(&zone->nr_scan_active, 0); _