Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 22a668d7 authored by KAMEZAWA Hiroyuki's avatar KAMEZAWA Hiroyuki Committed by Linus Torvalds
Browse files

memcg: fix behavior under memory.limit equals to memsw.limit



A user can set memcg.limit_in_bytes == memcg.memsw.limit_in_bytes when the
user just want to limit the total size of applications, in other words,
not very interested in memory usage itself.  In this case, swap-out will
be done only by global-LRU.

But, under current implementation, memory.limit_in_bytes is checked at
first and try_to_free_page() may do swap-out.  But, that swap-out is
useless for memsw.limit_in_bytes and the thread may hit limit again.

This patch tries to fix the current behavior at memory.limit ==
memsw.limit case.  And documentation is updated to explain the behavior of
this special case.

Signed-off-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: Dhaval Giani <dhaval@linux.vnet.ibm.com>
Cc: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8a9478ca
Loading
Loading
Loading
Loading
+11 −6
Original line number Original line Diff line number Diff line
@@ -152,14 +152,19 @@ When swap is accounted, following files are added.


usage of mem+swap is limited by memsw.limit_in_bytes.
usage of mem+swap is limited by memsw.limit_in_bytes.


Note: why 'mem+swap' rather than swap.
* why 'mem+swap' rather than swap.
The global LRU(kswapd) can swap out arbitrary pages. Swap-out means
The global LRU(kswapd) can swap out arbitrary pages. Swap-out means
to move account from memory to swap...there is no change in usage of
to move account from memory to swap...there is no change in usage of
mem+swap.
mem+swap. In other words, when we want to limit the usage of swap without

affecting global LRU, mem+swap limit is better than just limiting swap from
In other words, when we want to limit the usage of swap without affecting
OS point of view.
global LRU, mem+swap limit is better than just limiting swap from OS point

of view.
* What happens when a cgroup hits memory.memsw.limit_in_bytes
When a cgroup his memory.memsw.limit_in_bytes, it's useless to do swap-out
in this cgroup. Then, swap-out will not be done by cgroup routine and file
caches are dropped. But as mentioned above, global LRU can do swapout memory
from it for sanity of the system's memory management state. You can't forbid
it by cgroup.


2.5 Reclaim
2.5 Reclaim


+19 −0
Original line number Original line Diff line number Diff line
@@ -177,6 +177,9 @@ struct mem_cgroup {


	unsigned int	swappiness;
	unsigned int	swappiness;


	/* set when res.limit == memsw.limit */
	bool		memsw_is_minimum;

	/*
	/*
	 * statistics. This must be placed at the end of memcg.
	 * statistics. This must be placed at the end of memcg.
	 */
	 */
@@ -847,6 +850,10 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem,
	int ret, total = 0;
	int ret, total = 0;
	int loop = 0;
	int loop = 0;


	/* If memsw_is_minimum==1, swap-out is of-no-use. */
	if (root_mem->memsw_is_minimum)
		noswap = true;

	while (loop < 2) {
	while (loop < 2) {
		victim = mem_cgroup_select_victim(root_mem);
		victim = mem_cgroup_select_victim(root_mem);
		if (victim == root_mem)
		if (victim == root_mem)
@@ -1752,6 +1759,12 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
			break;
			break;
		}
		}
		ret = res_counter_set_limit(&memcg->res, val);
		ret = res_counter_set_limit(&memcg->res, val);
		if (!ret) {
			if (memswlimit == val)
				memcg->memsw_is_minimum = true;
			else
				memcg->memsw_is_minimum = false;
		}
		mutex_unlock(&set_limit_mutex);
		mutex_unlock(&set_limit_mutex);


		if (!ret)
		if (!ret)
@@ -1799,6 +1812,12 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
			break;
			break;
		}
		}
		ret = res_counter_set_limit(&memcg->memsw, val);
		ret = res_counter_set_limit(&memcg->memsw, val);
		if (!ret) {
			if (memlimit == val)
				memcg->memsw_is_minimum = true;
			else
				memcg->memsw_is_minimum = false;
		}
		mutex_unlock(&set_limit_mutex);
		mutex_unlock(&set_limit_mutex);


		if (!ret)
		if (!ret)