diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 1bfcfb1af3524f..8f9620cbc4a7c6 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -182,6 +182,9 @@ struct cgroup_subsys_state { struct work_struct destroy_work; struct rcu_work destroy_rwork; + /* To serialize kill and release paths for the css */ + struct completion complete; + /* * PI: the parent css. Placed here for cache proximity to following * fields of the containing structure. diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 1779ccddb734d0..841f23b4f66904 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -1592,6 +1592,13 @@ void cgroup_kn_unlock(struct kernfs_node *kn) mutex_unlock(&cgroup_mutex); kernfs_unbreak_active_protection(kn); + /* If css_kill started for this css wait for it to finish */ + if (cgrp->self.flags & CSS_DYING) { +printk("!!!! cgroup_kn_unlock WAITING for comp !!! \n"); + WARN(!wait_for_completion_timeout(&cgrp->self.complete, msecs_to_jiffies(1000)), + "Timed out waiting for css_killed_ref_fn to finish"); + } + cgroup_put(cgrp); } @@ -1992,7 +1999,8 @@ int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask) int i, ret; lockdep_assert_held(&cgroup_mutex); - +printk("!!! cgroup_setup_root init_comp %llx !!! \n", &root_cgrp->self); + init_completion(&root_cgrp->self.complete); ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, 0, GFP_KERNEL); if (ret) @@ -5109,6 +5117,7 @@ static void css_free_rwork_fn(struct work_struct *work) struct cgroup_subsys *ss = css->ss; struct cgroup *cgrp = css->cgroup; +printk("!!!!!!!!! css_free_rwork_fn css = %llx !!!!!!\n", css); percpu_ref_exit(&css->refcnt); if (ss) { @@ -5210,6 +5219,7 @@ static void css_release(struct percpu_ref *ref) struct cgroup_subsys_state *css = container_of(ref, struct cgroup_subsys_state, refcnt); +printk("!!!! css_release css = %llx !!!\n", css); INIT_WORK(&css->destroy_work, css_release_work_fn); queue_work(cgroup_destroy_wq, &css->destroy_work); } @@ -5307,6 +5317,8 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, if (IS_ERR(css)) return css; +printk("!!! css_create init_comp %llx !!! \n", css); + init_completion(&css->complete); init_and_link_css(css, ss, cgrp); err = percpu_ref_init(&css->refcnt, css_release, 0, GFP_KERNEL); @@ -5331,6 +5343,7 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, err_list_del: list_del_rcu(&css->sibling); err_free_css: +printk("!!! css_create ERROR init_comp %llx !!! \n", css); list_del_rcu(&css->rstat_css_node); INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn); queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork); @@ -5373,6 +5386,8 @@ static struct cgroup *cgroup_create(struct cgroup *parent, const char *name, } cgrp->kn = kn; +printk("!!! cgroup_create init_comp %llx !!! \n", &cgrp->self); + init_completion(&cgrp->self.complete); init_cgroup_housekeeping(cgrp); cgrp->self.parent = &parent->self; @@ -5549,6 +5564,13 @@ static void css_killed_work_fn(struct work_struct *work) container_of(work, struct cgroup_subsys_state, destroy_work); mutex_lock(&cgroup_mutex); +printk("!!!! css_killed_work_fn css = %llx comp %llx !!!\n", css, &css->complete); + + if (!(css->flags & CSS_RELEASED)) { + complete(&css->complete); + } else { +printk("!!!! css_killed_work_fn css = %llx comp %llx ALREADY RELEASED !!!\n", css, &css->complete); + } do { offline_css(css); @@ -5566,9 +5588,12 @@ static void css_killed_ref_fn(struct percpu_ref *ref) struct cgroup_subsys_state *css = container_of(ref, struct cgroup_subsys_state, refcnt); +printk("!!!! css_killed_ref_fn css = %llx !!!\n", css); 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); + } else { + complete(&css->complete); } } @@ -5588,6 +5613,8 @@ static void kill_css(struct cgroup_subsys_state *css) if (css->flags & CSS_DYING) return; +printk("!!! kill_css reinit_comp %llx !!! \n", css); + init_completion(&css->complete); css->flags |= CSS_DYING; /* @@ -5772,6 +5799,8 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early) * newly registered, all tasks and hence the * init_css_set is in the subsystem's root cgroup. */ init_css_set.subsys[ss->id] = css; +printk("!!! cgroup_init_subsys init_comp %llx !!! \n", css); + init_completion(&css->complete); have_fork_callback |= (bool)ss->fork << ss->id; have_exit_callback |= (bool)ss->exit << ss->id; @@ -5875,6 +5904,8 @@ int __init cgroup_init(void) cgroup_init_subsys(ss, false); } +printk("!!! cgroup_init init_comp %llx !!! \n", &init_css_set.subsys[ssid]); + init_completion(&init_css_set.subsys[ssid]->complete); list_add_tail(&init_css_set.e_cset_node[ssid], &cgrp_dfl_root.cgrp.e_csets[ssid]); diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c index 35f15c26ed54d4..7f1854f6658722 100644 --- a/kernel/sched/completion.c +++ b/kernel/sched/completion.c @@ -28,7 +28,6 @@ void complete(struct completion *x) { unsigned long flags; - raw_spin_lock_irqsave(&x->wait.lock, flags); if (x->done != UINT_MAX)