lkml.org 
[lkml]   [2009]   [Jan]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[RFC][PATCH 4/4] cgroup-memcg fix frequent EBUSY at rmdir
    From: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>

    Experimental. you may think of better fix.

    When trying following test under memcg.

    create memcg under
    /cgroup/A/ use_hierarchy=1, limit=20M
    /B some tasks
    /C empty
    /D empty

    And run make kernel under /B (for example). This will hit limit of 20M and
    hierarchical memory reclaim will scan A->B->C->D.
    (C,D have to be scanned because it may have some page caches.)

    Here, run following scipt.

    while true; do
    rmdir /cgroup/A/C
    mkdir /cgroup/A/C
    done

    You'll see -EBUSY at rmdir very often. This is because of temporal refcnt of
    memory reclaim for safe scanning under hierarchy.

    In usual, considering shell script,
    "please try again if you see -EBUSY at rmdir.
    You may see -EBUSY at rmdir even if it seems you can do it."
    is very unuseful.

    This patch tries to fix -EBUSY behavior. memcg's pre_destroy() works pretty
    fine and retrying rmdir() is O.K.

    Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>

    ---
    include/linux/cgroup.h | 5 +++++
    kernel/cgroup.c | 32 +++++++++++++++++++++++++-------
    mm/memcontrol.c | 9 ++++++---
    3 files changed, 36 insertions(+), 10 deletions(-)

    Index: mmotm-2.6.28-Jan7/include/linux/cgroup.h
    ===================================================================
    --- mmotm-2.6.28-Jan7.orig/include/linux/cgroup.h
    +++ mmotm-2.6.28-Jan7/include/linux/cgroup.h
    @@ -368,6 +368,11 @@ struct cgroup_subsys {
    int disabled;
    int early_init;
    /*
    + * set if subsys may retrun EBUSY while there are no tasks and
    + * subsys knows it's very temporal reference.
    + */
    + int retry_at_rmdir_failure;
    + /*
    * True if this subsys uses ID. ID is not available before cgroup_init()
    * (not available in early_init time.)
    */
    Index: mmotm-2.6.28-Jan7/kernel/cgroup.c
    ===================================================================
    --- mmotm-2.6.28-Jan7.orig/kernel/cgroup.c
    +++ mmotm-2.6.28-Jan7/kernel/cgroup.c
    @@ -2503,15 +2503,17 @@ static int cgroup_has_css_refs(struct cg

    /*
    * Atomically mark all (or else none) of the cgroup's CSS objects as
    - * CSS_REMOVED. Return true on success, or false if the cgroup has
    + * CSS_REMOVED. Return 0 on success, or false error code if the cgroup has
    * busy subsystems. Call with cgroup_mutex held
    */

    static int cgroup_clear_css_refs(struct cgroup *cgrp)
    {
    - struct cgroup_subsys *ss;
    + struct cgroup_subsys *ss, *failedhere;
    unsigned long flags;
    bool failed = false;
    + int err = -EBUSY;
    +
    local_irq_save(flags);
    for_each_subsys(cgrp->root, ss) {
    struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
    @@ -2521,6 +2523,7 @@ static int cgroup_clear_css_refs(struct
    refcnt = atomic_read(&css->refcnt);
    if (refcnt > 1) {
    failed = true;
    + failedhere = ss;
    goto done;
    }
    BUG_ON(!refcnt);
    @@ -2548,7 +2551,13 @@ static int cgroup_clear_css_refs(struct
    }
    }
    local_irq_restore(flags);
    - return !failed;
    +
    + if (failed) {
    + if (failedhere->retry_at_rmdir_failure)
    + err = -EAGAIN;
    + } else
    + err = 0;
    + return err;
    }

    static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
    @@ -2556,9 +2565,10 @@ static int cgroup_rmdir(struct inode *un
    struct cgroup *cgrp = dentry->d_fsdata;
    struct dentry *d;
    struct cgroup *parent;
    + int ret;

    /* the vfs holds both inode->i_mutex already */
    -
    +retry:
    mutex_lock(&cgroup_mutex);
    if (atomic_read(&cgrp->count) != 0) {
    mutex_unlock(&cgroup_mutex);
    @@ -2579,12 +2589,20 @@ static int cgroup_rmdir(struct inode *un
    mutex_lock(&cgroup_mutex);
    parent = cgrp->parent;

    - if (atomic_read(&cgrp->count)
    - || !list_empty(&cgrp->children)
    - || !cgroup_clear_css_refs(cgrp)) {
    + if (atomic_read(&cgrp->count) || !list_empty(&cgrp->children)) {
    mutex_unlock(&cgroup_mutex);
    return -EBUSY;
    }
    + ret = cgroup_clear_css_refs(cgrp);
    + if (ret == -EBUSY) { /* really busy */
    + mutex_unlock(&cgroup_mutex);
    + return ret;
    + }
    + if (ret == -EAGAIN) { /* subsys asks us to retry later */
    + mutex_unlock(&cgroup_mutex);
    + cond_resched();
    + goto retry;
    + }

    spin_lock(&release_list_lock);
    set_bit(CGRP_REMOVED, &cgrp->flags);
    Index: mmotm-2.6.28-Jan7/mm/memcontrol.c
    ===================================================================
    --- mmotm-2.6.28-Jan7.orig/mm/memcontrol.c
    +++ mmotm-2.6.28-Jan7/mm/memcontrol.c
    @@ -723,7 +723,8 @@ static int mem_cgroup_hierarchical_recla
    {
    struct mem_cgroup *victim;
    unsigned long start_age;
    - int ret, total = 0;
    + int ret = 0;
    + int total = 0;
    /*
    * Reclaim memory from cgroups under root_mem in round robin.
    */
    @@ -732,8 +733,9 @@ static int mem_cgroup_hierarchical_recla
    while (time_after((start_age + 2UL), root_mem->scan_age)) {
    victim = mem_cgroup_select_victim(root_mem);
    /* we use swappiness of local cgroup */
    - ret = try_to_free_mem_cgroup_pages(victim, gfp_mask, noswap,
    - get_swappiness(victim));
    + if (victim->res.usage)
    + ret = try_to_free_mem_cgroup_pages(victim, gfp_mask,
    + noswap, get_swappiness(victim));
    css_put(&victim->css);
    total += ret;
    if (mem_cgroup_check_under_limit(root_mem))
    @@ -2261,6 +2263,7 @@ struct cgroup_subsys mem_cgroup_subsys =
    .populate = mem_cgroup_populate,
    .attach = mem_cgroup_move_task,
    .early_init = 0,
    + .retry_at_rmdir_failure = 1,
    .use_id = 1,
    };



    \
     
     \ /
      Last update: 2009-01-08 10:39    [W:0.056 / U:58.156 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site