diff options
| author | Johannes Weiner <hannes@cmpxchg.org> | 2012-05-29 18:06:24 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-29 19:22:20 -0400 |
| commit | 91c63734f6908425903aed69c04035592f18d398 (patch) | |
| tree | 6790827ab915b17c63d5c39d8c72c47f3764f868 | |
| parent | 0ce72d4f7333248efbef1f3309770c7edb1b2625 (diff) | |
kernel: cgroup: push rcu read locking from css_is_ancestor() to callsite
Library functions should not grab locks when the callsites can do it,
even if the lock nests like the rcu read-side lock does.
Push the rcu_read_lock() from css_is_ancestor() to its single user,
mem_cgroup_same_or_subtree() in preparation for another user that may
already hold the rcu read-side lock.
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Konstantin Khlebnikov <khlebnikov@openvz.org>
Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Acked-by: Michal Hocko <mhocko@suse.cz>
Acked-by: Li Zefan <lizf@cn.fujitsu.com>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | kernel/cgroup.c | 20 | ||||
| -rw-r--r-- | mm/memcontrol.c | 14 |
2 files changed, 19 insertions, 15 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a0c6af34d500..0f3527d6184a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -5132,7 +5132,7 @@ EXPORT_SYMBOL_GPL(css_depth); | |||
| 5132 | * @root: the css supporsed to be an ancestor of the child. | 5132 | * @root: the css supporsed to be an ancestor of the child. |
| 5133 | * | 5133 | * |
| 5134 | * Returns true if "root" is an ancestor of "child" in its hierarchy. Because | 5134 | * Returns true if "root" is an ancestor of "child" in its hierarchy. Because |
| 5135 | * this function reads css->id, this use rcu_dereference() and rcu_read_lock(). | 5135 | * this function reads css->id, the caller must hold rcu_read_lock(). |
| 5136 | * But, considering usual usage, the csses should be valid objects after test. | 5136 | * But, considering usual usage, the csses should be valid objects after test. |
| 5137 | * Assuming that the caller will do some action to the child if this returns | 5137 | * Assuming that the caller will do some action to the child if this returns |
| 5138 | * returns true, the caller must take "child";s reference count. | 5138 | * returns true, the caller must take "child";s reference count. |
| @@ -5144,18 +5144,18 @@ bool css_is_ancestor(struct cgroup_subsys_state *child, | |||
| 5144 | { | 5144 | { |
| 5145 | struct css_id *child_id; | 5145 | struct css_id *child_id; |
| 5146 | struct css_id *root_id; | 5146 | struct css_id *root_id; |
| 5147 | bool ret = true; | ||
| 5148 | 5147 | ||
| 5149 | rcu_read_lock(); | ||
| 5150 | child_id = rcu_dereference(child->id); | 5148 | child_id = rcu_dereference(child->id); |
| 5149 | if (!child_id) | ||
| 5150 | return false; | ||
| 5151 | root_id = rcu_dereference(root->id); | 5151 | root_id = rcu_dereference(root->id); |
| 5152 | if (!child_id | 5152 | if (!root_id) |
| 5153 | || !root_id | 5153 | return false; |
| 5154 | || (child_id->depth < root_id->depth) | 5154 | if (child_id->depth < root_id->depth) |
| 5155 | || (child_id->stack[root_id->depth] != root_id->id)) | 5155 | return false; |
| 5156 | ret = false; | 5156 | if (child_id->stack[root_id->depth] != root_id->id) |
| 5157 | rcu_read_unlock(); | 5157 | return false; |
| 5158 | return ret; | 5158 | return true; |
| 5159 | } | 5159 | } |
| 5160 | 5160 | ||
| 5161 | void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css) | 5161 | void free_css_id(struct cgroup_subsys *ss, struct cgroup_subsys_state *css) |
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 92675fe8a2ef..faad98e6d17d 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
| @@ -1152,12 +1152,16 @@ struct lruvec *mem_cgroup_lru_move_lists(struct zone *zone, | |||
| 1152 | static bool mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg, | 1152 | static bool mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg, |
| 1153 | struct mem_cgroup *memcg) | 1153 | struct mem_cgroup *memcg) |
| 1154 | { | 1154 | { |
| 1155 | if (root_memcg != memcg) { | 1155 | bool ret; |
| 1156 | return (root_memcg->use_hierarchy && | ||
| 1157 | css_is_ancestor(&memcg->css, &root_memcg->css)); | ||
| 1158 | } | ||
| 1159 | 1156 | ||
| 1160 | return true; | 1157 | if (root_memcg == memcg) |
| 1158 | return true; | ||
| 1159 | if (!root_memcg->use_hierarchy) | ||
| 1160 | return false; | ||
| 1161 | rcu_read_lock(); | ||
| 1162 | ret = css_is_ancestor(&memcg->css, &root_memcg->css); | ||
| 1163 | rcu_read_unlock(); | ||
| 1164 | return ret; | ||
| 1161 | } | 1165 | } |
| 1162 | 1166 | ||
| 1163 | int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg) | 1167 | int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *memcg) |
