lkml.org 
[lkml]   [2014]   [Feb]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.12 015/107] memcg: fix endless loop caused by mem_cgroup_iter
    Date
    3.12-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Michal Hocko <mhocko@suse.cz>

    commit ecc736fc3c71c411a9d201d8588c9e7e049e5d8c upstream.

    Hugh has reported an endless loop when the hardlimit reclaim sees the
    same group all the time. This might happen when the reclaim races with
    the memcg removal.

    shrink_zone
    [rmdir root]
    mem_cgroup_iter(root, NULL, reclaim)
    // prev = NULL
    rcu_read_lock()
    mem_cgroup_iter_load
    last_visited = iter->last_visited // gets root || NULL
    css_tryget(last_visited) // failed
    last_visited = NULL [1]
    memcg = root = __mem_cgroup_iter_next(root, NULL)
    mem_cgroup_iter_update
    iter->last_visited = root;
    reclaim->generation = iter->generation

    mem_cgroup_iter(root, root, reclaim)
    // prev = root
    rcu_read_lock
    mem_cgroup_iter_load
    last_visited = iter->last_visited // gets root
    css_tryget(last_visited) // failed
    [1]

    The issue seemed to be introduced by commit 5f5781619718 ("memcg: relax
    memcg iter caching") which has replaced unconditional css_get/css_put by
    css_tryget/css_put for the cached iterator.

    This patch fixes the issue by skipping css_tryget on the root of the
    tree walk in mem_cgroup_iter_load and symmetrically doesn't release it
    in mem_cgroup_iter_update.

    Signed-off-by: Michal Hocko <mhocko@suse.cz>
    Reported-by: Hugh Dickins <hughd@google.com>
    Tested-by: Hugh Dickins <hughd@google.com>
    Cc: Johannes Weiner <hannes@cmpxchg.org>
    Cc: Greg Thelen <gthelen@google.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    mm/memcontrol.c | 17 ++++++++++++++---
    1 file changed, 14 insertions(+), 3 deletions(-)

    --- a/mm/memcontrol.c
    +++ b/mm/memcontrol.c
    @@ -1120,7 +1120,15 @@ mem_cgroup_iter_load(struct mem_cgroup_r
    if (iter->last_dead_count == *sequence) {
    smp_rmb();
    position = iter->last_visited;
    - if (position && !css_tryget(&position->css))
    +
    + /*
    + * We cannot take a reference to root because we might race
    + * with root removal and returning NULL would end up in
    + * an endless loop on the iterator user level when root
    + * would be returned all the time.
    + */
    + if (position && position != root &&
    + !css_tryget(&position->css))
    position = NULL;
    }
    return position;
    @@ -1129,9 +1137,11 @@ mem_cgroup_iter_load(struct mem_cgroup_r
    static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter,
    struct mem_cgroup *last_visited,
    struct mem_cgroup *new_position,
    + struct mem_cgroup *root,
    int sequence)
    {
    - if (last_visited)
    + /* root reference counting symmetric to mem_cgroup_iter_load */
    + if (last_visited && last_visited != root)
    css_put(&last_visited->css);
    /*
    * We store the sequence count from the time @last_visited was
    @@ -1206,7 +1216,8 @@ struct mem_cgroup *mem_cgroup_iter(struc
    memcg = __mem_cgroup_iter_next(root, last_visited);

    if (reclaim) {
    - mem_cgroup_iter_update(iter, last_visited, memcg, seq);
    + mem_cgroup_iter_update(iter, last_visited, memcg, root,
    + seq);

    if (!memcg)
    iter->generation++;



    \
     
     \ /
      Last update: 2014-02-15 06:01    [W:4.085 / U:0.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site