diff --git a/include/linux/page_cache_limit.h b/include/linux/page_cache_limit.h new file mode 100644 index 0000000000000000000000000000000000000000..98f12734114b82eae962b33f18c17de73cb44230 --- /dev/null +++ b/include/linux/page_cache_limit.h @@ -0,0 +1,14 @@ +#ifndef _PAGECACHE_H +#define _PAGECACHE_H + +#ifdef CONFIG_SHRINK_PAGECACHE +extern int pagecache_reclaim_enable; +extern int pagecache_limit_ratio; +extern int pagecache_reclaim_ratio; + +int proc_page_cache_limit(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos); +#else +#endif + +#endif diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 3ab6ea7853badc51b82b9b08cf0212a555c636c1..b3ee0deaa8dd30de066d85a398d4886bb32cae2f 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -103,6 +103,9 @@ #ifdef CONFIG_LOCKUP_DETECTOR #include #endif +#ifdef CONFIG_SHRINK_PAGECACHE +#include +#endif #if defined(CONFIG_SYSCTL) @@ -3192,6 +3195,35 @@ static struct ctl_table vm_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, +#endif +#ifdef CONFIG_SHRINK_PAGECACHE + { + .procname = "cache_reclaim_enable", + .data = &pagecache_reclaim_enable, + .maxlen = sizeof(pagecache_reclaim_enable), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + { + .procname = "cache_limit_ratio", + .data = &pagecache_limit_ratio, + .maxlen = sizeof(pagecache_limit_ratio), + .mode = 0600, + .proc_handler = proc_page_cache_limit, + .extra1 = SYSCTL_ZERO, + .extra2 = (void *)&one_hundred, + }, + { + .procname = "cache_reclaim_ratio", + .data = &pagecache_reclaim_ratio, + .maxlen = sizeof(pagecache_reclaim_ratio), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = (void *)&one_hundred, + }, #endif { } }; diff --git a/mm/Kconfig b/mm/Kconfig index 59fdace319fd279aa84c5a98db62c801a1b0973b..f565fc82c200ec65976d8d0ae51b7196ede4e203 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -486,6 +486,18 @@ config FRONTSWAP If unsure, say Y to enable frontswap. +config SHRINK_PAGECACHE + bool "Enable shrinking the page cache" + depends on MMU + default n + help + SHRINK_PAGECACHE means that we do not want to keep the large number + of page cache in the system, even though page cache can greatly improve + the performance of the machine. Large number of page cache may result + in short of memory, which will result OOM at the same time, so in order + to keep page cache in a reasonable range, the number of page cache + should be limited, and that is what SHRINK_PAGECACHE does. + config MEMCG_QOS bool "Enable Memory Cgroup Priority" depends on MEMCG diff --git a/mm/Makefile b/mm/Makefile index 4d07adb6061913ee7dd2406655d1b4388bd61b0e..c14522bd17edf481883a6f7156db56710bf45434 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -125,3 +125,4 @@ obj-$(CONFIG_PTDUMP_CORE) += ptdump.o obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o obj-$(CONFIG_HAVE_BOOTMEM_INFO_NODE) += bootmem_info.o obj-$(CONFIG_PIN_MEMORY) += pin_mem.o +obj-$(CONFIG_SHRINK_PAGECACHE) += page_cache_limit.o diff --git a/mm/page_cache_limit.c b/mm/page_cache_limit.c new file mode 100644 index 0000000000000000000000000000000000000000..55fdea0878048ccca7a16703daeda9d6b90b5707 --- /dev/null +++ b/mm/page_cache_limit.c @@ -0,0 +1,51 @@ +#include +#include + +int pagecache_reclaim_enable; +int pagecache_limit_ratio; +int pagecache_reclaim_ratio; + +static unsigned long pagecache_limit_pages; +static unsigned long node_pagecache_limit_pages[MAX_NUMNODES]; + +static unsigned long get_node_total_pages(int nid) +{ + int zone_type; + unsigned long managed_pages = 0; + pg_data_t *pgdat = NODE_DATA(nid); + + if (!pgdat) + return 0; + + for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) + managed_pages += zone_managed_pages(&pgdat->node_zones[zone_type]); + + return managed_pages; +} + +static void setup_pagecache_limit(void) +{ + int i; + unsigned long node_total_pages; + + pagecache_limit_pages = pagecache_limit_ratio * totalram_pages() / 100; + + for (i = 0; i < MAX_NUMNODES; i++) { + node_total_pages = get_node_total_pages(i); + node_pagecache_limit_pages[i] = node_total_pages * + pagecache_limit_ratio / 100; + } +} + +int proc_page_cache_limit(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + int ret; + + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); + + if (write && !ret) + setup_pagecache_limit(); + + return ret; +}