From 9f18abea566d0d0ab31b6b13a62e7076ed37bdd9 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Sat, 17 May 2014 23:19:26 +1000 Subject: [PATCH] memcg: allow setting low_limit Export memory.low_limit_in_bytes knob with the same rules as the hard limit represented by limit_in_bytes knob (e.g. no limit to be set for the root cgroup). There is no memsw alternative for low_limit_in_bytes because the primary motivation behind this limit is to protect the working set of the group and so considering swap doesn't make much sense. There is also no kmem variant exported because we do not have any easy way to protect kernel allocations now. Please note that the low limit might exceed the hard limit which basically means that the group is not reclaimable if there is other reclaim target in the hierarchy under pressure. Signed-off-by: Michal Hocko Cc: Johannes Weiner Cc: KAMEZAWA Hiroyuki Cc: KOSAKI Motohiro Cc: Greg Thelen Cc: Michel Lespinasse Cc: Tejun Heo Cc: Hugh Dickins Cc: Roman Gushchin Signed-off-by: Andrew Morton --- include/linux/res_counter.h | 13 +++++++++++++ kernel/res_counter.c | 2 ++ mm/memcontrol.c | 27 ++++++++++++++++++++++++++- 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h index 408724eeec71..b810855024f9 100644 --- a/include/linux/res_counter.h +++ b/include/linux/res_counter.h @@ -93,6 +93,7 @@ enum { RES_LIMIT, RES_FAILCNT, RES_SOFT_LIMIT, + RES_LOW_LIMIT, }; /* @@ -247,4 +248,16 @@ res_counter_set_soft_limit(struct res_counter *cnt, return 0; } +static inline int +res_counter_set_low_limit(struct res_counter *cnt, + unsigned long long low_limit) +{ + unsigned long flags; + + spin_lock_irqsave(&cnt->lock, flags); + cnt->low_limit = low_limit; + spin_unlock_irqrestore(&cnt->lock, flags); + return 0; +} + #endif diff --git a/kernel/res_counter.c b/kernel/res_counter.c index e791130f85a7..85ea94305015 100644 --- a/kernel/res_counter.c +++ b/kernel/res_counter.c @@ -136,6 +136,8 @@ res_counter_member(struct res_counter *counter, int member) return &counter->failcnt; case RES_SOFT_LIMIT: return &counter->soft_limit; + case RES_LOW_LIMIT: + return &counter->low_limit; }; BUG(); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 96fe3a0dcba4..aca2b62e71bd 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1674,8 +1674,9 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) rcu_read_unlock(); - pr_info("memory: usage %llukB, limit %llukB, failcnt %llu\n", + pr_info("memory: usage %llukB, low_limit %llukB limit %llukB, failcnt %llu\n", res_counter_read_u64(&memcg->res, RES_USAGE) >> 10, + res_counter_read_u64(&memcg->res, RES_LOW_LIMIT) >> 10, res_counter_read_u64(&memcg->res, RES_LIMIT) >> 10, res_counter_read_u64(&memcg->res, RES_FAILCNT)); pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %llu\n", @@ -5096,6 +5097,24 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of, else return -EINVAL; break; + case RES_LOW_LIMIT: + if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */ + ret = -EINVAL; + break; + } + ret = res_counter_memparse_write_strategy(buf, &val); + if (ret) + break; + if (type == _MEM) { + ret = res_counter_set_low_limit(&memcg->res, val); + break; + } + /* + * memsw low limit doesn't make any sense and kmem is not + * implemented yet - if ever + */ + return -EINVAL; + case RES_SOFT_LIMIT: ret = res_counter_memparse_write_strategy(buf, &val); if (ret) @@ -6021,6 +6040,12 @@ static struct cftype mem_cgroup_files[] = { .write = mem_cgroup_write, .read_u64 = mem_cgroup_read_u64, }, + { + .name = "low_limit_in_bytes", + .private = MEMFILE_PRIVATE(_MEM, RES_LOW_LIMIT), + .write = mem_cgroup_write, + .read_u64 = mem_cgroup_read_u64, + }, { .name = "soft_limit_in_bytes", .private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT), -- 2.39.5