Thread (50 messages) 50 messages, 5 authors, 2012-01-26

Re: [RFC] [PATCH 2/7 v2] memcg: add memory barrier for checking account move.

From: Ying Han <hidden>
Date: 2012-01-24 19:04:18
Also in: linux-mm

On Mon, Jan 23, 2012 at 1:04 AM, Michal Hocko [off-list ref] wrote:
On Fri 20-01-12 10:08:44, Ying Han wrote:
quoted
On Wed, Jan 18, 2012 at 6:17 PM, KAMEZAWA Hiroyuki
[off-list ref] wrote:
quoted
On Wed, 18 Jan 2012 13:37:59 +0100
Michal Hocko [off-list ref] wrote:
quoted
On Wed 18-01-12 09:06:56, KAMEZAWA Hiroyuki wrote:
quoted
On Tue, 17 Jan 2012 16:26:35 +0100
Michal Hocko [off-list ref] wrote:
quoted
On Fri 13-01-12 17:33:47, KAMEZAWA Hiroyuki wrote:
quoted
I think this bugfix is needed before going ahead. thoughts?
==
From 2cb491a41782b39aae9f6fe7255b9159ac6c1563 Mon Sep 17 00:00:00 2001
From: KAMEZAWA Hiroyuki <redacted>
Date: Fri, 13 Jan 2012 14:27:20 +0900
Subject: [PATCH 2/7] memcg: add memory barrier for checking account move.

At starting move_account(), source memcg's per-cpu variable
MEM_CGROUP_ON_MOVE is set. The page status update
routine check it under rcu_read_lock(). But there is no memory
barrier. This patch adds one.
OK this would help to enforce that the CPU would see the current value
but what prevents us from the race with the value update without the
lock? This is as racy as it was before AFAICS.
Hm, do I misunderstand ?
==
   update                     reference

   CPU A                        CPU B
  set value                rcu_read_lock()
  smp_wmb()                smp_rmb()
                           read_value
                           rcu_read_unlock()
  synchronize_rcu().
==
I expect
If synchronize_rcu() is called before rcu_read_lock() => move_lock_xxx will be held.
If synchronize_rcu() is called after rcu_read_lock() => update will be delayed.
Ahh, OK I can see it now. Readers are not that important because it is
actually the updater who is delayed until all preexisting rcu read
sections are finished.

In that case. Why do we need both barriers? spin_unlock is a full
barrier so maybe we just need smp_rmb before we read value to make sure
that we do not get stalled value when we start rcu_read section after
synchronize_rcu?
I doubt .... If no barrier, this case happens

==
       update                  reference
       CPU A                   CPU B
       set value
       synchronize_rcu()       rcu_read_lock()
                               read_value <= find old value
                               rcu_read_unlock()
                               do no lock
==
Hi Kame,

Can you help to clarify a bit more on the example above? Why
read_value got the old value after synchronize_rcu().
AFAIU it is because rcu_read_unlock doesn't force any memory barrier
and we synchronize only the updater (with synchronize_rcu), so nothing
guarantees that the value set on CPUA is visible to CPUB.
Thanks, and i might have found similar comment on the
documentation/rcu/checklist.txt:
"
The various RCU read-side primitives do -not- necessarily contain
memory barriers.
"

So, the read barrier here is to make sure no reordering between the
reader and the rcu_read_lock. The same for the write barrier which
makes sure no reordering between the updater and synchronize_rcu. The
the rcu here is to synchronize between the updater and reader. If so,
why not the change like :

       for_each_online_cpu(cpu)
               per_cpu(memcg->stat->count[MEM_CGROUP_ON_MOVE], cpu) += 1;
+      smp_wmb();

Sorry, the use of per-cpu variable MEM_CGROUP_ON_MOVE does confuse me.

--Ying
--
Michal Hocko
SUSE Labs
SUSE LINUX s.r.o.
Lihovarska 1060/12
190 00 Praha 9
Czech Republic
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help