mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-02-15 04:42:02 +00:00
163 lines
5.4 KiB
Diff
163 lines
5.4 KiB
Diff
From 4340d175b89896d069c1e875f5b98c80a408f680 Mon Sep 17 00:00:00 2001
|
|
From: Tejun Heo <tj@kernel.org>
|
|
Date: Fri, 31 May 2019 10:38:58 -0700
|
|
Subject: [PATCH 809/826] cgroup: Include dying leaders with live threads in
|
|
PROCS iterations
|
|
|
|
commit c03cd7738a83b13739f00546166969342c8ff014 upstream.
|
|
|
|
CSS_TASK_ITER_PROCS currently iterates live group leaders; however,
|
|
this means that a process with dying leader and live threads will be
|
|
skipped. IOW, cgroup.procs might be empty while cgroup.threads isn't,
|
|
which is confusing to say the least.
|
|
|
|
Fix it by making cset track dying tasks and include dying leaders with
|
|
live threads in PROCS iteration.
|
|
|
|
Signed-off-by: Tejun Heo <tj@kernel.org>
|
|
Reported-and-tested-by: Topi Miettinen <toiwoton@gmail.com>
|
|
Cc: Oleg Nesterov <oleg@redhat.com>
|
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
---
|
|
include/linux/cgroup-defs.h | 1 +
|
|
include/linux/cgroup.h | 1 +
|
|
kernel/cgroup/cgroup.c | 44 +++++++++++++++++++++++++++++++------
|
|
3 files changed, 39 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
|
|
index a6090154b2ab..a01ebb630abc 100644
|
|
--- a/include/linux/cgroup-defs.h
|
|
+++ b/include/linux/cgroup-defs.h
|
|
@@ -207,6 +207,7 @@ struct css_set {
|
|
*/
|
|
struct list_head tasks;
|
|
struct list_head mg_tasks;
|
|
+ struct list_head dying_tasks;
|
|
|
|
/* all css_task_iters currently walking this cset */
|
|
struct list_head task_iters;
|
|
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
|
|
index f85e65b248b7..b4854b48a4f3 100644
|
|
--- a/include/linux/cgroup.h
|
|
+++ b/include/linux/cgroup.h
|
|
@@ -60,6 +60,7 @@ struct css_task_iter {
|
|
struct list_head *task_pos;
|
|
struct list_head *tasks_head;
|
|
struct list_head *mg_tasks_head;
|
|
+ struct list_head *dying_tasks_head;
|
|
|
|
struct css_set *cur_cset;
|
|
struct css_set *cur_dcset;
|
|
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
|
|
index c093e187f6a6..89dd464f6862 100644
|
|
--- a/kernel/cgroup/cgroup.c
|
|
+++ b/kernel/cgroup/cgroup.c
|
|
@@ -673,6 +673,7 @@ struct css_set init_css_set = {
|
|
.dom_cset = &init_css_set,
|
|
.tasks = LIST_HEAD_INIT(init_css_set.tasks),
|
|
.mg_tasks = LIST_HEAD_INIT(init_css_set.mg_tasks),
|
|
+ .dying_tasks = LIST_HEAD_INIT(init_css_set.dying_tasks),
|
|
.task_iters = LIST_HEAD_INIT(init_css_set.task_iters),
|
|
.threaded_csets = LIST_HEAD_INIT(init_css_set.threaded_csets),
|
|
.cgrp_links = LIST_HEAD_INIT(init_css_set.cgrp_links),
|
|
@@ -1145,6 +1146,7 @@ static struct css_set *find_css_set(struct css_set *old_cset,
|
|
cset->dom_cset = cset;
|
|
INIT_LIST_HEAD(&cset->tasks);
|
|
INIT_LIST_HEAD(&cset->mg_tasks);
|
|
+ INIT_LIST_HEAD(&cset->dying_tasks);
|
|
INIT_LIST_HEAD(&cset->task_iters);
|
|
INIT_LIST_HEAD(&cset->threaded_csets);
|
|
INIT_HLIST_NODE(&cset->hlist);
|
|
@@ -4152,15 +4154,18 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it)
|
|
it->task_pos = NULL;
|
|
return;
|
|
}
|
|
- } while (!css_set_populated(cset));
|
|
+ } while (!css_set_populated(cset) && !list_empty(&cset->dying_tasks));
|
|
|
|
if (!list_empty(&cset->tasks))
|
|
it->task_pos = cset->tasks.next;
|
|
- else
|
|
+ else if (!list_empty(&cset->mg_tasks))
|
|
it->task_pos = cset->mg_tasks.next;
|
|
+ else
|
|
+ it->task_pos = cset->dying_tasks.next;
|
|
|
|
it->tasks_head = &cset->tasks;
|
|
it->mg_tasks_head = &cset->mg_tasks;
|
|
+ it->dying_tasks_head = &cset->dying_tasks;
|
|
|
|
/*
|
|
* We don't keep css_sets locked across iteration steps and thus
|
|
@@ -4199,6 +4204,8 @@ static void css_task_iter_skip(struct css_task_iter *it,
|
|
|
|
static void css_task_iter_advance(struct css_task_iter *it)
|
|
{
|
|
+ struct task_struct *task;
|
|
+
|
|
lockdep_assert_held(&css_set_lock);
|
|
repeat:
|
|
if (it->task_pos) {
|
|
@@ -4215,17 +4222,32 @@ static void css_task_iter_advance(struct css_task_iter *it)
|
|
if (it->task_pos == it->tasks_head)
|
|
it->task_pos = it->mg_tasks_head->next;
|
|
if (it->task_pos == it->mg_tasks_head)
|
|
+ it->task_pos = it->dying_tasks_head->next;
|
|
+ if (it->task_pos == it->dying_tasks_head)
|
|
css_task_iter_advance_css_set(it);
|
|
} else {
|
|
/* called from start, proceed to the first cset */
|
|
css_task_iter_advance_css_set(it);
|
|
}
|
|
|
|
- /* if PROCS, skip over tasks which aren't group leaders */
|
|
- if ((it->flags & CSS_TASK_ITER_PROCS) && it->task_pos &&
|
|
- !thread_group_leader(list_entry(it->task_pos, struct task_struct,
|
|
- cg_list)))
|
|
- goto repeat;
|
|
+ if (!it->task_pos)
|
|
+ return;
|
|
+
|
|
+ task = list_entry(it->task_pos, struct task_struct, cg_list);
|
|
+
|
|
+ if (it->flags & CSS_TASK_ITER_PROCS) {
|
|
+ /* if PROCS, skip over tasks which aren't group leaders */
|
|
+ if (!thread_group_leader(task))
|
|
+ goto repeat;
|
|
+
|
|
+ /* and dying leaders w/o live member threads */
|
|
+ if (!atomic_read(&task->signal->live))
|
|
+ goto repeat;
|
|
+ } else {
|
|
+ /* skip all dying ones */
|
|
+ if (task->flags & PF_EXITING)
|
|
+ goto repeat;
|
|
+ }
|
|
}
|
|
|
|
/**
|
|
@@ -5682,6 +5704,7 @@ void cgroup_exit(struct task_struct *tsk)
|
|
if (!list_empty(&tsk->cg_list)) {
|
|
spin_lock_irq(&css_set_lock);
|
|
css_set_move_task(tsk, cset, NULL, false);
|
|
+ list_add_tail(&tsk->cg_list, &cset->dying_tasks);
|
|
cset->nr_tasks--;
|
|
spin_unlock_irq(&css_set_lock);
|
|
} else {
|
|
@@ -5702,6 +5725,13 @@ void cgroup_release(struct task_struct *task)
|
|
do_each_subsys_mask(ss, ssid, have_release_callback) {
|
|
ss->release(task);
|
|
} while_each_subsys_mask();
|
|
+
|
|
+ if (use_task_css_set_links) {
|
|
+ spin_lock_irq(&css_set_lock);
|
|
+ css_set_skip_task_iters(task_css_set(task), task);
|
|
+ list_del_init(&task->cg_list);
|
|
+ spin_unlock_irq(&css_set_lock);
|
|
+ }
|
|
}
|
|
|
|
void cgroup_free(struct task_struct *task)
|
|
--
|
|
2.22.0
|
|
|