diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index 342388f921105bd8ee8509cfd1dea64f46f9d59b..2c86a6cffd885c844e5355183bc19da5f79ea8c0 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -1084,6 +1084,38 @@ PAGE_SIZE multiple when read back. high limit is used and monitored properly, this limit's utility is limited to providing the final safety net. + memory.wmark_ratio + A read-write single value file which exists on non-root + cgroups. The default is 0. + + Memory usage water mark. Valid value is from 0 to 100, which + represents percentage of max limit or high limit if high is setup. + The wmark_low and wmark_high would be calculated by max limit and + wmark_ratio. 0 means water mark is disabled, both wmark_low and + wmark_high would be max, which is the default value. + + Once water mark is setup correctly, when charging pages to memcg, + if the usage exceeds wmark_high, which means available memory is low, + a work would be scheduled to reclaim pages in background to try to + reduce memory usage to wmark_low if possible. + + If memory.low is greater than memory.wmark_high, back ground reclaim + may not take effect at all due to low protection. + + memory.wmark_high + A read-only single value file which exists on non-root cgroups. + The default is max. + + Memory usage high water mark, which means the available memory is low. + For details, please refer to the above wmark_ratio section. + + memory.wmark_low + A read-only single value file which exists on non-root cgroups. + The default is max. + + Memory usage low water mark, which means the available memory is ok. + For details, please refer to the above wmark_ratio section. + memory.oom.group A read-write single value file which exists on non-root cgroups. The default value is "0". diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d516877c2f6e52830a3243ef006c6091f374c314..ad8d304edcf5a045e032c029fc7e3b8a2fa58563 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2945,7 +2945,8 @@ static void setup_memcg_wmark(struct mem_cgroup *memcg) { unsigned long high_wmark; unsigned long low_wmark; - unsigned long max = memcg->memory.max; + unsigned long max = memcg->high > memcg->memory.max ? + memcg->memory.max : memcg->high; unsigned int wmark_ratio = memcg->wmark_ratio; if (wmark_ratio) { @@ -5791,10 +5792,41 @@ static ssize_t memory_high_write(struct kernfs_open_file *of, try_to_free_mem_cgroup_pages(memcg, nr_pages - high, GFP_KERNEL, true); + setup_memcg_wmark(memcg); + + if (!is_wmark_ok(memcg, true)) + queue_work(memcg_wmark_wq, &memcg->wmark_work); + memcg_wb_domain_size_changed(memcg); return nbytes; } +static int memory_wmark_low_show(struct seq_file *m, void *v) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); + unsigned long wmark_low = READ_ONCE(memcg->memory.wmark_low); + + if (wmark_low == PAGE_COUNTER_MAX) + seq_puts(m, "max\n"); + else + seq_printf(m, "%llu\n", (u64)wmark_low * PAGE_SIZE); + + return 0; +} + +static int memory_wmark_high_show(struct seq_file *m, void *v) +{ + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); + unsigned long wmark_high = READ_ONCE(memcg->memory.wmark_high); + + if (wmark_high == PAGE_COUNTER_MAX) + seq_puts(m, "max\n"); + else + seq_printf(m, "%llu\n", (u64)wmark_high * PAGE_SIZE); + + return 0; +} + static int memory_max_show(struct seq_file *m, void *v) { struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); @@ -5853,6 +5885,11 @@ static ssize_t memory_max_write(struct kernfs_open_file *of, break; } + setup_memcg_wmark(memcg); + + if (!is_wmark_ok(memcg, true)) + queue_work(memcg_wmark_wq, &memcg->wmark_work); + memcg_wb_domain_size_changed(memcg); return nbytes; } @@ -6013,6 +6050,22 @@ static struct cftype memory_files[] = { .seq_show = memory_max_show, .write = memory_max_write, }, + { + .name = "wmark_ratio", + .flags = CFTYPE_NOT_ON_ROOT, + .seq_show = memory_wmark_ratio_show, + .write = memory_wmark_ratio_write, + }, + { + .name = "wmark_high", + .flags = CFTYPE_NOT_ON_ROOT, + .seq_show = memory_wmark_high_show, + }, + { + .name = "wmark_low", + .flags = CFTYPE_NOT_ON_ROOT, + .seq_show = memory_wmark_low_show, + }, { .name = "events", .flags = CFTYPE_NOT_ON_ROOT,