Re: [PATCH 1/2] memcg: make oom_lock 0 and 1 based rather thancoutner

From: Michal Hocko
Date: Thu Jul 14 2011 - 08:56:10 EST


On Thu 14-07-11 20:50:12, KAMEZAWA Hiroyuki wrote:
> On Thu, 14 Jul 2011 13:30:09 +0200
> Michal Hocko <mhocko@xxxxxxx> wrote:
[...]
> > static bool mem_cgroup_oom_lock(struct mem_cgroup *mem)
> > {
> > - int x, lock_count = 0;
> > - struct mem_cgroup *iter;
> > + int x, lock_count = -1;
> > + struct mem_cgroup *iter, *failed = NULL;
> > + bool cond = true;
> >
> > - for_each_mem_cgroup_tree(iter, mem) {
> > - x = atomic_inc_return(&iter->oom_lock);
> > - lock_count = max(x, lock_count);
> > + for_each_mem_cgroup_tree_cond(iter, mem, cond) {
> > + x = !!atomic_add_unless(&iter->oom_lock, 1, 1);
> > + if (lock_count == -1)
> > + lock_count = x;
> > + else if (lock_count != x) {
> > + /*
> > + * this subtree of our hierarchy is already locked
> > + * so we cannot give a lock.
> > + */
> > + lock_count = 0;
> > + failed = iter;
> > + cond = false;
> > + }
> > }
>
> Hm ? assuming B-C-D is locked and a new thread tries a lock on A-B-C-D-E.
> And for_each_mem_cgroup_tree will find groups in order of A->B->C->D->E.
> Before lock
> A 0
> B 1
> C 1
> D 1
> E 0
>
> After lock
> A 1
> B 1
> C 1
> D 1
> E 0
>
> here, failed = B, cond = false. Undo routine will unlock A.
> Hmm, seems to work in this case.
>
> But....A's oom_lock==0 and memcg_oom_wakeup() at el will not able to
> know "A" is in OOM. wakeup processes in A which is waiting for oom recover..

Hohm, we need to have 2 different states. lock and mark_oom.
oom_recovert would check only the under_oom.

>
> Will this work ?

No it won't because the rest of the world has no idea that A is
under_oom as well.

> ==
> # cgcreate -g memory:A
> # cgset -r memory.use_hierarchy=1 A
> # cgset -r memory.oom_control=1 A
> # cgset -r memory.limit_in_bytes= 100M
> # cgset -r memory.memsw.limit_in_bytes= 100M
> # cgcreate -g memory:A/B
> # cgset -r memory.oom_control=1 A/B
> # cgset -r memory.limit_in_bytes=20M
> # cgset -r memory.memsw.limit_in_bytes=20M
>
> Assume malloc XXX is a program allocating XXX Megabytes of memory.
>
> # cgexec -g memory:A/B malloc 30 & #->this will be blocked by OOM of group B
> # cgexec -g memory:A malloc 80 & #->this will be blocked by OOM of group A
>
>
> Here, 2 procs are blocked by OOM. Here, relax A's limitation and clear OOM.
>
> # cgset -r memory.memsw.limit_in_bytes=300M A
> # cgset -r memory.limit_in_bytes=300M A
>
> malloc 80 will end.

What about yet another approach? Very similar what you proposed, I
guess. Again not tested and needs some cleanup just to illustrate.
What do you think?
---