The patch in the last message was scrambled. The last two lines
belong to the previous fragment. Here is the correct beast.
Ed Tomlinson <tomlins@cam.org
--- diff -u -r --exclude-from=ex.txt linux.ac28/mm/page_alloc.c linux/mm/page_alloc.c --- linux.ac28/mm/page_alloc.c Sun Apr 1 18:52:22 2001 +++ linux/mm/page_alloc.c Mon Apr 2 07:54:05 2001 @@ -138,11 +138,9 @@ /* * We don't want to protect this variable from race conditions - * since it's nothing important, but we do want to make sure - * it never gets negative. + * since it's nothing important. */ - if (memory_pressure > NR_CPUS) - memory_pressure--; + inactivate_pressure++; } #define MARK_USED(index, order, area) \ diff -u -r --exclude-from=ex.txt linux.ac28/mm/swap.c linux/mm/swap.c --- linux.ac28/mm/swap.c Mon Jan 22 16:30:21 2001 +++ linux/mm/swap.c Thu Mar 29 11:37:47 2001 @@ -47,10 +47,12 @@ * many inactive pages we should have. * * In reclaim_page and __alloc_pages: memory_pressure++ - * In __free_pages_ok: memory_pressure-- + * In __free_pages_ok: inactivate_pressure++ + * In invalidate_pages_scan: inactivate_pressure++ * In recalculate_vm_stats the value is decayed (once a second) */ int memory_pressure; +int inactivate_pressure; /* We track the number of pages currently being asynchronously swapped out, so that we don't try to swap TOO many pages out at once */ @@ -287,6 +289,7 @@ * memory_pressure. */ memory_pressure -= (memory_pressure >> INACTIVE_SHIFT); + inactivate_pressure -= (inactivate_pressure >> INACTIVE_SHIFT); } /* diff -u -r --exclude-from=ex.txt linux.ac28/mm/vmscan.c linux/mm/vmscan.c --- linux.ac28/mm/vmscan.c Sun Apr 1 18:52:22 2001 +++ linux/mm/vmscan.c Mon Apr 2 07:42:55 2001 @@ -759,6 +791,8 @@ } spin_unlock(&pagemap_lru_lock); + inactivate_pressure += nr_deactivated; + return nr_deactivated; } @@ -937,6 +971,76 @@ return ret; } +/* + * Try to shrink the dcache if either its size or free space + * has grown, and it looks like we might get the required pages. + * This function would simplify if the caches tracked how + * many _pages_ were freeable. + */ +int try_shrinking_dcache(int goal, unsigned int gfp_mask) +{ + + /* base - projects the threshold above which we can free pages */ + + static int base, free = 0; + int pages, old, ret; + + old = free; /* save old free space size */ + + pages = (dentry_stat.nr_dentry * sizeof(struct dentry)) >> PAGE_SHIFT; + free = (dentry_stat.nr_unused * sizeof(struct dentry)) >> PAGE_SHIFT; + + if (base > pages) /* If the cache shrunk reset base, The cache + base = pages; * growing applies preasure as does expanding + if (free > old) * free space - even if later shrinks */ + base -= (base>free-old) ? free-old : base; + + /* try free pages... Note that the using inactive_pressure _is_ + * racy. It does not matter, a bad guess will not hurt us. + * Testing free here does not work effectivily. + */ + + if (pages-base >= goal) { + ret = inactivate_pressure; + shrink_dcache_memory(DEF_PRIORITY, gfp_mask); + ret = inactivate_pressure - ret; + base += (!ret) ? pages-base : (ret>goal) ? ret : goal; + } else + ret = 0; + + return ret; +} + +/* + * Same logic as above but for the icache. + */ +int try_shrinking_icache(int goal, unsigned int gfp_mask) +{ + static int base, free = 0; + int pages, old, ret; + + old = free; + + pages = (inodes_stat.nr_inodes * sizeof(struct inode)) >> PAGE_SHIFT; + free = (inodes_stat.nr_unused * sizeof(struct inode)) >> PAGE_SHIFT; + + if (base > pages) + base = pages; + if (free > old) + base -= (base>free-old) ? free-old : base; + + if (pages-base >= goal) { + ret = inactivate_pressure; + shrink_icache_memory(DEF_PRIORITY, gfp_mask); + ret = inactivate_pressure - ret; + base += (!ret) ? pages-base : (ret>goal) ? ret : goal; + } else + ret = 0; + + return ret; +} + + DECLARE_WAIT_QUEUE_HEAD(kswapd_wait); DECLARE_WAIT_QUEUE_HEAD(kswapd_done); struct task_struct *kswapd_task; @@ -984,18 +1088,28 @@ */ for (;;) { static int recalc = 0; + int delta = 0; /* If needed, try to free some memory. */ if (inactive_shortage() || free_shortage()) do_try_to_free_pages(GFP_KSWAPD, 0); /* - * Do some (very minimal) background scanning. This - * will scan all pages on the active list once - * every minute. This clears old referenced bits - * and moves unused pages to the inactive list. + * Try to keep the rate of pages inactivations + * similar to the rate of pages allocations. This + * also perform background page aging, but only + * when there is preasure on the vm. We get the + * pages from the dcache and icache if its likely + * there are enought freeable pages there. */ - refill_inactive_scan(DEF_PRIORITY, 0); + delta = (memory_pressure >> INACTIVE_SHIFT) \ + - (inactivate_pressure >> INACTIVE_SHIFT); + if (delta > 0) + delta -= try_shrinking_dcache(delta,GFP_KSWAPD); + if (delta > 0) + delta -= try_shrinking_icache(delta,GFP_KSWAPD); + if (delta > 0) + refill_inactive_scan(DEF_PRIORITY, delta); /* Once a second, recalculate some VM stats. */ if (time_after(jiffies, recalc + HZ)) { --- linux.ac28/include/linux/swap.h Sun Apr 1 18:52:22 2001 +++ linux/include/linux/swap.h Thu Mar 29 11:31:09 2001 @@ -102,6 +102,7 @@ /* linux/mm/swap.c */ extern int memory_pressure; +extern int inactivate_pressure; extern void age_page_up(struct page *); extern void age_page_up_nolock(struct page *); extern void age_page_down(struct page *);--- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/