aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-06-25 14:48:32 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-21 21:21:25 -0400
commitb6891ed4e66b65e5d6bb36964af0d65a08590018 (patch)
treee076e3ab8dd110873fe714af8e27c2e6d395b617 /include
parent83d0eb79752482bb888fb6d86ceed8971272f8b4 (diff)
cgroup: fix RCU accesses to task->cgroups
commit 14611e51a57df10240817d8ada510842faf0ec51 upstream. 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. v2: Fixed unbalanced parenthsis and there's no need to use rcu_dereference_raw() when !CONFIG_PROVE_RCU. Both spotted by Li. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Fengguang Wu <fengguang.wu@intel.com> Acked-by: Li Zefan <lizefan@huawei.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/cgroup.h58
1 files changed, 48 insertions, 10 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 8bda1294c035..8852d370c720 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -646,22 +646,60 @@ static inline struct cgroup_subsys_state *cgroup_subsys_state(
646 return cgrp->subsys[subsys_id]; 646 return cgrp->subsys[subsys_id];
647} 647}
648 648
649/* 649/**
650 * function to get the cgroup_subsys_state which allows for extra 650 * task_css_set_check - obtain a task's css_set with extra access conditions
651 * rcu_dereference_check() conditions, such as locks used during the 651 * @task: the task to obtain css_set for
652 * cgroup_subsys::attach() methods. 652 * @__c: extra condition expression to be passed to rcu_dereference_check()
653 *
654 * A task's css_set is RCU protected, initialized and exited while holding
655 * task_lock(), and can only be modified while holding both cgroup_mutex
656 * and task_lock() while the task is alive. This macro verifies that the
657 * caller is inside proper critical section and returns @task's css_set.
658 *
659 * The caller can also specify additional allowed conditions via @__c, such
660 * as locks used during the cgroup_subsys::attach() methods.
653 */ 661 */
654#ifdef CONFIG_PROVE_RCU 662#ifdef CONFIG_PROVE_RCU
655extern struct mutex cgroup_mutex; 663extern struct mutex cgroup_mutex;
656#define task_subsys_state_check(task, subsys_id, __c) \ 664#define task_css_set_check(task, __c) \
657 rcu_dereference_check((task)->cgroups->subsys[(subsys_id)], \ 665 rcu_dereference_check((task)->cgroups, \
658 lockdep_is_held(&(task)->alloc_lock) || \ 666 lockdep_is_held(&(task)->alloc_lock) || \
659 lockdep_is_held(&cgroup_mutex) || (__c)) 667 lockdep_is_held(&cgroup_mutex) || (__c))
660#else 668#else
661#define task_subsys_state_check(task, subsys_id, __c) \ 669#define task_css_set_check(task, __c) \
662 rcu_dereference((task)->cgroups->subsys[(subsys_id)]) 670 rcu_dereference((task)->cgroups)
663#endif 671#endif
664 672
673/**
674 * task_subsys_state_check - obtain css for (task, subsys) w/ extra access conds
675 * @task: the target task
676 * @subsys_id: the target subsystem ID
677 * @__c: extra condition expression to be passed to rcu_dereference_check()
678 *
679 * Return the cgroup_subsys_state for the (@task, @subsys_id) pair. The
680 * synchronization rules are the same as task_css_set_check().
681 */
682#define task_subsys_state_check(task, subsys_id, __c) \
683 task_css_set_check((task), (__c))->subsys[(subsys_id)]
684
685/**
686 * task_css_set - obtain a task's css_set
687 * @task: the task to obtain css_set for
688 *
689 * See task_css_set_check().
690 */
691static inline struct css_set *task_css_set(struct task_struct *task)
692{
693 return task_css_set_check(task, false);
694}
695
696/**
697 * task_subsys_state - obtain css for (task, subsys)
698 * @task: the target task
699 * @subsys_id: the target subsystem ID
700 *
701 * See task_subsys_state_check().
702 */
665static inline struct cgroup_subsys_state * 703static inline struct cgroup_subsys_state *
666task_subsys_state(struct task_struct *task, int subsys_id) 704task_subsys_state(struct task_struct *task, int subsys_id)
667{ 705{