diff --git a/mm/memcontrol.c b/mm/memcontrol.c index da07784dde875247dd7b2c47cd25eacb42780921..98f80beeac7f65a1e169d1b15abc9bf0ae09a20a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1117,14 +1117,22 @@ static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root, * skipped and we should continue the tree walk. * last_visited css is safe to use because it is * protected by css_get and the tree walk is rcu safe. + * + * We do not take a reference on the root of the tree walk + * because we might race with the root removal when it would + * be the only node in the iterated hierarchy and mem_cgroup_iter + * would end up in an endless loop because it expects that at + * least one valid node will be returned. Root cannot disappear + * because caller of the iterator should hold it already so + * skipping css reference should be safe. */ if (next_css) { - if ((next_css->flags & CSS_ONLINE) && css_tryget(next_css)) + if ((next_css->flags & CSS_ONLINE) && + (next_css == &root->css || css_tryget(next_css))) return mem_cgroup_from_css(next_css); - else { - prev_css = next_css; - goto skip_node; - } + + prev_css = next_css; + goto skip_node; } return NULL;