aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2013-06-12 17:05:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-06-12 19:29:46 -0400
commit89dc991f0f5272c307c746fdd57d0bff382b1ba2 (patch)
treef0d71da8f791864e38819b9e576b7fd5ddb217bc /mm
parent7b57976da48e60b66fdbb9e97f5711b5382a49d7 (diff)
mm: memcontrol: fix lockless reclaim hierarchy iterator
The lockless reclaim hierarchy iterator currently has a misplaced barrier that can lead to use-after-free crashes. The reclaim hierarchy iterator consist of a sequence count and a position pointer that are read and written locklessly, with memory barriers enforcing ordering. The write side sets the position pointer first, then updates the sequence count to "publish" the new position. Likewise, the read side must read the sequence count first, then the position. If the sequence count is up to date, it's guaranteed that the position is up to date as well: writer: reader: iter->position = position if iter->sequence == expected: smp_wmb() smp_rmb() iter->sequence = sequence position = iter->position However, the read side barrier is currently misplaced, which can lead to dereferencing stale position pointers that no longer point to valid memory. Fix this. Signed-off-by: Johannes Weiner <hannes@cmpxchg.org> Reported-by: Tejun Heo <tj@kernel.org> Reviewed-by: Tejun Heo <tj@kernel.org> Acked-by: Michal Hocko <mhocko@suse.cz> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Glauber Costa <glommer@parallels.com> Cc: <stable@kernel.org> [3.10+] Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memcontrol.c12
1 files changed, 5 insertions, 7 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 931e38c6f095..194721839cf5 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1199,7 +1199,6 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
1199 1199
1200 mz = mem_cgroup_zoneinfo(root, nid, zid); 1200 mz = mem_cgroup_zoneinfo(root, nid, zid);
1201 iter = &mz->reclaim_iter[reclaim->priority]; 1201 iter = &mz->reclaim_iter[reclaim->priority];
1202 last_visited = iter->last_visited;
1203 if (prev && reclaim->generation != iter->generation) { 1202 if (prev && reclaim->generation != iter->generation) {
1204 iter->last_visited = NULL; 1203 iter->last_visited = NULL;
1205 goto out_unlock; 1204 goto out_unlock;
@@ -1218,13 +1217,12 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
1218 * is alive. 1217 * is alive.
1219 */ 1218 */
1220 dead_count = atomic_read(&root->dead_count); 1219 dead_count = atomic_read(&root->dead_count);
1221 smp_rmb(); 1220 if (dead_count == iter->last_dead_count) {
1222 last_visited = iter->last_visited; 1221 smp_rmb();
1223 if (last_visited) { 1222 last_visited = iter->last_visited;
1224 if ((dead_count != iter->last_dead_count) || 1223 if (last_visited &&
1225 !css_tryget(&last_visited->css)) { 1224 !css_tryget(&last_visited->css))
1226 last_visited = NULL; 1225 last_visited = NULL;
1227 }
1228 } 1226 }
1229 } 1227 }
1230 1228