cgroup: use a standalone workqueue for killing css

Upstream: pending

A race is observed when V1 and V2 is comounted, queued work on
cgroup_destroy_wq may get over written before get executed, leave cgroup
dying without being offlined, and hung the system. Avoid such problem by
using a standalone queue.

Signed-off-by: Kairui Song <kasong@tencent.com>
This commit is contained in:
Kairui Song 2023-11-02 15:09:26 +08:00
parent d7a3720248
commit 5411485b92
2 changed files with 8 additions and 4 deletions

View File

@ -192,6 +192,7 @@ struct cgroup_subsys_state {
atomic_t online_cnt;
/* percpu_ref killing and RCU release */
struct work_struct kill_work;
struct work_struct destroy_work;
struct rcu_work destroy_rwork;

View File

@ -125,6 +125,7 @@ DEFINE_PERCPU_RWSEM(cgroup_threadgroup_rwsem);
* which may lead to deadlock.
*/
static struct workqueue_struct *cgroup_destroy_wq;
static struct workqueue_struct *cgroup_kill_wq;
/* generate an array of cgroup subsystem pointers */
#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys,
@ -3077,7 +3078,6 @@ restart:
cgroup_get_live(dsct);
prepare_to_wait(&dsct->offline_waitq, &wait,
TASK_UNINTERRUPTIBLE);
cgroup_unlock();
schedule();
finish_wait(&dsct->offline_waitq, &wait);
@ -5511,6 +5511,7 @@ static void offline_css(struct cgroup_subsys_state *css)
ss->css_offline(css);
css->flags &= ~CSS_ONLINE;
RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL);
wake_up_all(&css->cgroup->offline_waitq);
@ -5778,7 +5779,7 @@ out_unlock:
static void css_killed_work_fn(struct work_struct *work)
{
struct cgroup_subsys_state *css =
container_of(work, struct cgroup_subsys_state, destroy_work);
container_of(work, struct cgroup_subsys_state, kill_work);
cgroup_lock();
@ -5799,8 +5800,8 @@ static void css_killed_ref_fn(struct percpu_ref *ref)
container_of(ref, struct cgroup_subsys_state, refcnt);
if (atomic_dec_and_test(&css->online_cnt)) {
INIT_WORK(&css->destroy_work, css_killed_work_fn);
queue_work(cgroup_destroy_wq, &css->destroy_work);
INIT_WORK(&css->kill_work, css_killed_work_fn);
queue_work(cgroup_kill_wq, &css->kill_work);
}
}
@ -6173,6 +6174,8 @@ static int __init cgroup_wq_init(void)
*/
cgroup_destroy_wq = alloc_workqueue("cgroup_destroy", 0, 1);
BUG_ON(!cgroup_destroy_wq);
cgroup_kill_wq = alloc_workqueue("cgroup_kill", 0, 1);
BUG_ON(!cgroup_kill_wq);
return 0;
}
core_initcall(cgroup_wq_init);