lkml.org 
[lkml]   [2020]   [Mar]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 38/99] cgroup: Iterate tasks that did not finish do_exit()
    Date
    From: Michal Koutný <mkoutny@suse.com>

    commit 9c974c77246460fa6a92c18554c3311c8c83c160 upstream.

    PF_EXITING is set earlier than actual removal from css_set when a task
    is exitting. This can confuse cgroup.procs readers who see no PF_EXITING
    tasks, however, rmdir is checking against css_set membership so it can
    transitionally fail with EBUSY.

    Fix this by listing tasks that weren't unlinked from css_set active
    lists.
    It may happen that other users of the task iterator (without
    CSS_TASK_ITER_PROCS) spot a PF_EXITING task before cgroup_exit(). This
    is equal to the state before commit c03cd7738a83 ("cgroup: Include dying
    leaders with live threads in PROCS iterations") but it may be reviewed
    later.

    Reported-by: Suren Baghdasaryan <surenb@google.com>
    Fixes: c03cd7738a83 ("cgroup: Include dying leaders with live threads in PROCS iterations")
    Signed-off-by: Michal Koutný <mkoutny@suse.com>
    Signed-off-by: Tejun Heo <tj@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    include/linux/cgroup.h | 1 +
    kernel/cgroup/cgroup.c | 23 ++++++++++++++++-------
    2 files changed, 17 insertions(+), 7 deletions(-)

    --- a/include/linux/cgroup.h
    +++ b/include/linux/cgroup.h
    @@ -61,6 +61,7 @@ struct css_task_iter {
    struct list_head *mg_tasks_head;
    struct list_head *dying_tasks_head;

    + struct list_head *cur_tasks_head;
    struct css_set *cur_cset;
    struct css_set *cur_dcset;
    struct task_struct *cur_task;
    --- a/kernel/cgroup/cgroup.c
    +++ b/kernel/cgroup/cgroup.c
    @@ -4051,12 +4051,16 @@ static void css_task_iter_advance_css_se
    }
    } while (!css_set_populated(cset) && list_empty(&cset->dying_tasks));

    - if (!list_empty(&cset->tasks))
    + if (!list_empty(&cset->tasks)) {
    it->task_pos = cset->tasks.next;
    - else if (!list_empty(&cset->mg_tasks))
    + it->cur_tasks_head = &cset->tasks;
    + } else if (!list_empty(&cset->mg_tasks)) {
    it->task_pos = cset->mg_tasks.next;
    - else
    + it->cur_tasks_head = &cset->mg_tasks;
    + } else {
    it->task_pos = cset->dying_tasks.next;
    + it->cur_tasks_head = &cset->dying_tasks;
    + }

    it->tasks_head = &cset->tasks;
    it->mg_tasks_head = &cset->mg_tasks;
    @@ -4114,10 +4118,14 @@ repeat:
    else
    it->task_pos = it->task_pos->next;

    - if (it->task_pos == it->tasks_head)
    + if (it->task_pos == it->tasks_head) {
    it->task_pos = it->mg_tasks_head->next;
    - if (it->task_pos == it->mg_tasks_head)
    + it->cur_tasks_head = it->mg_tasks_head;
    + }
    + if (it->task_pos == it->mg_tasks_head) {
    it->task_pos = it->dying_tasks_head->next;
    + it->cur_tasks_head = it->dying_tasks_head;
    + }
    if (it->task_pos == it->dying_tasks_head)
    css_task_iter_advance_css_set(it);
    } else {
    @@ -4136,11 +4144,12 @@ repeat:
    goto repeat;

    /* and dying leaders w/o live member threads */
    - if (!atomic_read(&task->signal->live))
    + if (it->cur_tasks_head == it->dying_tasks_head &&
    + !atomic_read(&task->signal->live))
    goto repeat;
    } else {
    /* skip all dying ones */
    - if (task->flags & PF_EXITING)
    + if (it->cur_tasks_head == it->dying_tasks_head)
    goto repeat;
    }
    }

    \
     
     \ /
      Last update: 2020-03-19 14:17    [W:4.299 / U:0.700 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site