Skip to content

Commit 9c974c7

Browse files
Werkovhtejun
authored andcommitted
cgroup: Iterate tasks that did not finish do_exit()
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 c03cd77 ("cgroup: Include dying leaders with live threads in PROCS iterations") but it may be reviewed later. Reported-by: Suren Baghdasaryan <[email protected]> Fixes: c03cd77 ("cgroup: Include dying leaders with live threads in PROCS iterations") Signed-off-by: Michal Koutný <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent 2d4ecb0 commit 9c974c7

File tree

2 files changed

+17
-7
lines changed

2 files changed

+17
-7
lines changed

include/linux/cgroup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct css_task_iter {
6262
struct list_head *mg_tasks_head;
6363
struct list_head *dying_tasks_head;
6464

65+
struct list_head *cur_tasks_head;
6566
struct css_set *cur_cset;
6667
struct css_set *cur_dcset;
6768
struct task_struct *cur_task;

kernel/cgroup/cgroup.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4400,12 +4400,16 @@ static void css_task_iter_advance_css_set(struct css_task_iter *it)
44004400
}
44014401
} while (!css_set_populated(cset) && list_empty(&cset->dying_tasks));
44024402

4403-
if (!list_empty(&cset->tasks))
4403+
if (!list_empty(&cset->tasks)) {
44044404
it->task_pos = cset->tasks.next;
4405-
else if (!list_empty(&cset->mg_tasks))
4405+
it->cur_tasks_head = &cset->tasks;
4406+
} else if (!list_empty(&cset->mg_tasks)) {
44064407
it->task_pos = cset->mg_tasks.next;
4407-
else
4408+
it->cur_tasks_head = &cset->mg_tasks;
4409+
} else {
44084410
it->task_pos = cset->dying_tasks.next;
4411+
it->cur_tasks_head = &cset->dying_tasks;
4412+
}
44094413

44104414
it->tasks_head = &cset->tasks;
44114415
it->mg_tasks_head = &cset->mg_tasks;
@@ -4463,10 +4467,14 @@ static void css_task_iter_advance(struct css_task_iter *it)
44634467
else
44644468
it->task_pos = it->task_pos->next;
44654469

4466-
if (it->task_pos == it->tasks_head)
4470+
if (it->task_pos == it->tasks_head) {
44674471
it->task_pos = it->mg_tasks_head->next;
4468-
if (it->task_pos == it->mg_tasks_head)
4472+
it->cur_tasks_head = it->mg_tasks_head;
4473+
}
4474+
if (it->task_pos == it->mg_tasks_head) {
44694475
it->task_pos = it->dying_tasks_head->next;
4476+
it->cur_tasks_head = it->dying_tasks_head;
4477+
}
44704478
if (it->task_pos == it->dying_tasks_head)
44714479
css_task_iter_advance_css_set(it);
44724480
} else {
@@ -4485,11 +4493,12 @@ static void css_task_iter_advance(struct css_task_iter *it)
44854493
goto repeat;
44864494

44874495
/* and dying leaders w/o live member threads */
4488-
if (!atomic_read(&task->signal->live))
4496+
if (it->cur_tasks_head == it->dying_tasks_head &&
4497+
!atomic_read(&task->signal->live))
44894498
goto repeat;
44904499
} else {
44914500
/* skip all dying ones */
4492-
if (task->flags & PF_EXITING)
4501+
if (it->cur_tasks_head == it->dying_tasks_head)
44934502
goto repeat;
44944503
}
44954504
}

0 commit comments

Comments
 (0)