From mboxrd@z Thu Jan 1 00:00:00 1970 From: Li Zefan Subject: Re: [PATCH cgroup/for-3.11 1/3] cgroup: fix RCU accesses to task->cgroups Date: Tue, 25 Jun 2013 09:55:44 +0800 Message-ID: <51C8F8A0.1090000@huawei.com> References: <20130621225116.GC3949@htj.dyndns.org> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <20130621225116.GC3949-Gd/HAXX7CRxy/B6EtB590w@public.gmane.org> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: containers-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org Errors-To: containers-bounces-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org To: Tejun Heo Cc: cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org, Fengguang Wu On 2013/6/22 6:51, Tejun Heo wrote: > task->cgroups is a RCU pointer pointing to struct css_set. A task > switches to a different css_set on cgroup migration but a css_set > doesn't change once created and its pointers to cgroup_subsys_states > aren't RCU protected. > > task_subsys_state[_check]() is the macro to acquire css given a task > and subsys_id pair. It RCU-dereferences task->cgroups->subsys[] not > task->cgroups, so the RCU pointer task->cgroups ends up being > dereferenced without read_barrier_depends() after it. It's broken. > > Fix it by introducing task_css_set[_check]() which does > RCU-dereference on task->cgroups. task_subsys_state[_check]() is > reimplemented to directly dereference ->subsys[] of the css_set > returned from task_css_set[_check](). > > This removes some of sparse RCU warnings in cgroup. > > Signed-off-by: Tejun Heo > Reported-by: Fengguang Wu > Cc: stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org > --- > Hello, > > Three RCU fixe patches. The first one fixes an actual bug. The other > two add missing annoations so that sparse doesn't generate spurious > RCU address space warnings. > > Thanks! > > include/linux/cgroup.h | 58 ++++++++++++++++++++++++++++++++++++++++--------- > 1 file changed, 48 insertions(+), 10 deletions(-) > > --- a/include/linux/cgroup.h > +++ b/include/linux/cgroup.h > @@ -638,22 +638,60 @@ static inline struct cgroup_subsys_state > return cgrp->subsys[subsys_id]; > } > > -/* > - * function to get the cgroup_subsys_state which allows for extra > - * rcu_dereference_check() conditions, such as locks used during the > - * cgroup_subsys::attach() methods. > +/** > + * task_css_set_check - obtain a task's css_set with extra access conditions > + * @task: the task to obtain css_set for > + * @__c: extra condition expression to be passed to rcu_dereference_check() > + * > + * A task's css_set is RCU protected, initialized and exited while holding > + * task_lock(), and can only be modified while holding both cgroup_mutex > + * and task_lock() while the task is alive. This macro verifies that the > + * caller is inside proper critical section and returns @task's css_set. > + * > + * The caller can also specify additional allowed conditions via @__c, such > + * as locks used during the cgroup_subsys::attach() methods. > */ > #ifdef CONFIG_PROVE_RCU > extern struct mutex cgroup_mutex; > -#define task_subsys_state_check(task, subsys_id, __c) \ > - rcu_dereference_check((task)->cgroups->subsys[(subsys_id)], \ > - lockdep_is_held(&(task)->alloc_lock) || \ > - lockdep_is_held(&cgroup_mutex) || (__c)) > +#define task_css_set_check(task, __c) \ > + rcu_dereference_check((task)->cgroups, \ > + lockdep_is_held(&(task)->alloc_lock) || \ > + lockdep_is_held(&cgroup_mutex) || (__c)) > #else > -#define task_subsys_state_check(task, subsys_id, __c) \ > - rcu_dereference((task)->cgroups->subsys[(subsys_id)]) > +#define task_css_set_check(task, __c) \ > + rcu_dereference_raw((task)->cgroups parenthesis unmatched. and why not just use rcu_dereference()? I guess it should be equivalent to rcu_derference_raw() if CONFIG_PROVE_RCU=n ? > #endif >