diff --git a/include/linux/mm.h b/include/linux/mm.h index 7687228..98380ec 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -29,6 +29,7 @@ extern unsigned long num_physpages; extern unsigned long totalram_pages; extern void * high_memory; extern int page_cluster; +extern int min_filelist_kbytes; #ifdef CONFIG_SYSCTL extern int sysctl_legacy_va_layout; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 3a45c22..c61f0c9 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1320,6 +1320,14 @@ static struct ctl_table vm_table[] = { .extra2 = &one, }, #endif + { + .procname = "min_filelist_kbytes", + .data = &min_filelist_kbytes, + .maxlen = sizeof(min_filelist_kbytes), + .mode = 0644, + .proc_handler = &proc_dointvec, + .extra1 = &zero, + }, /* * NOTE: do not add new entries to this table unless you have read diff --git a/mm/vmscan.c b/mm/vmscan.c index c5dfabf..3b0e95d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -130,6 +130,11 @@ struct scan_control { int vm_swappiness = 60; long vm_total_pages; /* The total number of pages which the VM controls */ +/* + * Low watermark used to prevent fscache thrashing during low memory. + * 20M is a arbitrary value. We need more discussion. + */ +int min_filelist_kbytes = 1024 * 20; static LIST_HEAD(shrinker_list); static DECLARE_RWSEM(shrinker_rwsem); @@ -1635,6 +1640,7 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc, u64 fraction[2], denominator; enum lru_list l; int noswap = 0; + int low_pagecache = 0; /* If we have no swap space, do not bother scanning anon pages. */ if (!sc->may_swap || (nr_swap_pages <= 0)) { @@ -1651,6 +1657,7 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc, zone_nr_lru_pages(zone, sc, LRU_INACTIVE_FILE); if (scanning_global_lru(sc)) { + unsigned long pagecache_threshold; free = zone_page_state(zone, NR_FREE_PAGES); /* If we have very few page cache pages, force-scan anon pages. */ @@ -1660,6 +1667,10 @@ static void get_scan_count(struct zone *zone, struct scan_control *sc, denominator = 1; goto out; } + + pagecache_threshold = min_filelist_kbytes >> (PAGE_SHIFT - 10); + if (file < pagecache_threshold) + low_pagecache = 1; } /* @@ -1715,6 +1726,12 @@ out: if (priority || noswap) { scan >>= priority; scan = div64_u64(scan * fraction[file], denominator); + /* + * If the system has low page cache, we slow down + * scanning speed with 1/8 to protect working set. + */ + if (low_pagecache) + scan >>= 3; } nr[l] = nr_scan_try_batch(scan, &reclaim_stat->nr_saved_scan[l]);