Skip to content

Commit 180e426

Browse files
Shaun Tancheffintel-lab-lkp
authored andcommitted
memcg-v1: Enable setting memory min, low, high
For users that are unable to update to memcg-v2 this provides a method where memcg-v1 can more effectively apply enough memory pressure to effectively throttle filesystem I/O or otherwise minimize being memcg oom killed at the expense of reduced performance. This patch extends the memcg-v1 legacy sysfs entries with: limit_in_bytes.min, limit_in_bytes.low and limit_in_bytes.high Since old software will need to be updated to take advantage of the new files a secondary method of setting min, low and high based on a percentage of the limit is also provided. The percentages are determined by module parameters. The available module parameters can be set at kernel boot time, for example: memcontrol.memcg_min=10 memcontrol.memcg_low=30 memcontrol.memcg_high=80 Would set min to 10%, low to 30% and high to 80% of the value written to: /sys/fs/cgroup/memory/<grp>/memory.limit_in_bytes Signed-off-by: Shaun Tancheff <shaun.tancheff@hpe.com>
1 parent 7e364e5 commit 180e426

File tree

1 file changed

+83
-1
lines changed

1 file changed

+83
-1
lines changed

mm/memcontrol.c

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@
7373

7474
#include <trace/events/vmscan.h>
7575

76+
static unsigned int memcg_v1_min_default_percent;
77+
module_param_named(memcg_min, memcg_v1_min_default_percent, uint, 0600);
78+
MODULE_PARM_DESC(memcg_min, "memcg v1 min default percent");
79+
80+
static unsigned int memcg_v1_low_default_percent;
81+
module_param_named(memcg_low, memcg_v1_low_default_percent, uint, 0600);
82+
MODULE_PARM_DESC(memcg_low, "memcg v1 low default percent");
83+
84+
static unsigned int memcg_v1_high_default_percent;
85+
module_param_named(memcg_high, memcg_v1_high_default_percent, uint, 0600);
86+
MODULE_PARM_DESC(memcg_high, "memcg v1 high default percent");
87+
7688
struct cgroup_subsys memory_cgrp_subsys __read_mostly;
7789
EXPORT_SYMBOL(memory_cgrp_subsys);
7890

@@ -208,6 +220,7 @@ enum res_type {
208220
_MEMSWAP,
209221
_KMEM,
210222
_TCP,
223+
_MEM_V1,
211224
};
212225

213226
#define MEMFILE_PRIVATE(x, val) ((x) << 16 | (val))
@@ -3689,6 +3702,9 @@ enum {
36893702
RES_MAX_USAGE,
36903703
RES_FAILCNT,
36913704
RES_SOFT_LIMIT,
3705+
RES_LIMIT_MIN,
3706+
RES_LIMIT_LOW,
3707+
RES_LIMIT_HIGH,
36923708
};
36933709

36943710
static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
@@ -3699,6 +3715,7 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
36993715

37003716
switch (MEMFILE_TYPE(cft->private)) {
37013717
case _MEM:
3718+
case _MEM_V1:
37023719
counter = &memcg->memory;
37033720
break;
37043721
case _MEMSWAP:
@@ -3729,6 +3746,12 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
37293746
return counter->failcnt;
37303747
case RES_SOFT_LIMIT:
37313748
return (u64)memcg->soft_limit * PAGE_SIZE;
3749+
case RES_LIMIT_MIN:
3750+
return (u64)READ_ONCE(memcg->memory.min);
3751+
case RES_LIMIT_LOW:
3752+
return (u64)READ_ONCE(memcg->memory.low);
3753+
case RES_LIMIT_HIGH:
3754+
return (u64)READ_ONCE(memcg->memory.high);
37323755
default:
37333756
BUG();
37343757
}
@@ -3828,6 +3851,35 @@ static int memcg_update_tcp_max(struct mem_cgroup *memcg, unsigned long max)
38283851
return ret;
38293852
}
38303853

3854+
static inline void mem_cgroup_v1_set_defaults(struct mem_cgroup *memcg,
3855+
u64 nr_pages)
3856+
{
3857+
u64 max = (u64)(PAGE_COUNTER_MAX * PAGE_SIZE) / PAGE_SIZE;
3858+
u64 min, low, high;
3859+
3860+
if (mem_cgroup_is_root(memcg) || max == nr_pages)
3861+
return;
3862+
3863+
min = READ_ONCE(memcg->memory.min);
3864+
low = READ_ONCE(memcg->memory.low);
3865+
if (min || low)
3866+
return;
3867+
3868+
if (!min && memcg_v1_min_default_percent) {
3869+
min = (nr_pages * memcg_v1_min_default_percent) / 100;
3870+
page_counter_set_min(&memcg->memory, min);
3871+
}
3872+
if (!low && memcg_v1_low_default_percent) {
3873+
low = (nr_pages * memcg_v1_low_default_percent) / 100;
3874+
page_counter_set_low(&memcg->memory, low);
3875+
}
3876+
high = READ_ONCE(memcg->memory.high);
3877+
if (high == PAGE_COUNTER_MAX && memcg_v1_high_default_percent) {
3878+
high = (nr_pages * memcg_v1_high_default_percent) / 100;
3879+
page_counter_set_high(&memcg->memory, high);
3880+
}
3881+
}
3882+
38313883
/*
38323884
* The user of this function is...
38333885
* RES_LIMIT.
@@ -3851,6 +3903,11 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of,
38513903
break;
38523904
}
38533905
switch (MEMFILE_TYPE(of_cft(of)->private)) {
3906+
case _MEM_V1:
3907+
ret = mem_cgroup_resize_max(memcg, nr_pages, false);
3908+
if (!ret)
3909+
mem_cgroup_v1_set_defaults(memcg, nr_pages);
3910+
break;
38543911
case _MEM:
38553912
ret = mem_cgroup_resize_max(memcg, nr_pages, false);
38563913
break;
@@ -4999,6 +5056,13 @@ static int mem_cgroup_slab_show(struct seq_file *m, void *p)
49995056
}
50005057
#endif
50015058

5059+
static ssize_t memory_min_write(struct kernfs_open_file *of,
5060+
char *buf, size_t nbytes, loff_t off);
5061+
static ssize_t memory_low_write(struct kernfs_open_file *of,
5062+
char *buf, size_t nbytes, loff_t off);
5063+
static ssize_t memory_high_write(struct kernfs_open_file *of,
5064+
char *buf, size_t nbytes, loff_t off);
5065+
50025066
static struct cftype mem_cgroup_legacy_files[] = {
50035067
{
50045068
.name = "usage_in_bytes",
@@ -5013,10 +5077,28 @@ static struct cftype mem_cgroup_legacy_files[] = {
50135077
},
50145078
{
50155079
.name = "limit_in_bytes",
5016-
.private = MEMFILE_PRIVATE(_MEM, RES_LIMIT),
5080+
.private = MEMFILE_PRIVATE(_MEM_V1, RES_LIMIT),
50175081
.write = mem_cgroup_write,
50185082
.read_u64 = mem_cgroup_read_u64,
50195083
},
5084+
{
5085+
.name = "limit_in_bytes.min",
5086+
.private = MEMFILE_PRIVATE(_MEM_V1, RES_LIMIT_MIN),
5087+
.write = memory_min_write,
5088+
.read_u64 = mem_cgroup_read_u64,
5089+
},
5090+
{
5091+
.name = "limit_in_bytes.low",
5092+
.private = MEMFILE_PRIVATE(_MEM_V1, RES_LIMIT_LOW),
5093+
.write = memory_low_write,
5094+
.read_u64 = mem_cgroup_read_u64,
5095+
},
5096+
{
5097+
.name = "limit_in_bytes.high",
5098+
.private = MEMFILE_PRIVATE(_MEM_V1, RES_LIMIT_HIGH),
5099+
.write = memory_high_write,
5100+
.read_u64 = mem_cgroup_read_u64,
5101+
},
50205102
{
50215103
.name = "soft_limit_in_bytes",
50225104
.private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT),

0 commit comments

Comments
 (0)