From 1ce0c625d4b9816588101c69d7c4aa33763c1a27 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 27 May 2022 10:49:56 -0700 Subject: [PATCH] cgroup: test css_put imbalance Signed-off-by: Tadeusz Struk Change-Id: I0d3d27cdff508b2bb9ae2411d406f272ca46d410 --- include/linux/cgroup.h | 25 +++++++++++++++++++++++-- kernel/cgroup/cgroup.c | 18 ++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 618838c48313cd..b886d3d41bdf53 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -400,8 +400,19 @@ static inline bool css_is_dying(struct cgroup_subsys_state *css) */ static inline void css_put(struct cgroup_subsys_state *css) { - if (!(css->flags & CSS_NO_REF)) + + if (percpu_ref_is_zero(&css->refcnt)) { +printk("!!! css_put is ALREADY zero css %llx !!!\n", css); + } + + if (!(css->flags & CSS_NO_REF)) { percpu_ref_put(&css->refcnt); + + if (percpu_ref_is_zero(&css->refcnt)) { +printk("!!! css_put is zero set CSS_NO_REF css %llx !!!\n", css); + css->flags |= CSS_NO_REF; + } + } } /** @@ -413,8 +424,18 @@ static inline void css_put(struct cgroup_subsys_state *css) */ static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int n) { - if (!(css->flags & CSS_NO_REF)) + if (percpu_ref_is_zero(&css->refcnt)) { +printk("!!! css_put_many is ALREADY zero css %llx !!!\n", css); + } + + if (!(css->flags & CSS_NO_REF)) { percpu_ref_put_many(&css->refcnt, n); + + if (percpu_ref_is_zero(&css->refcnt)) { +printk("!!! css_put_many is zero set CSS_NO_REF css %llx !!!\n", css); + css->flags |= CSS_NO_REF; + } + } } static inline void cgroup_get(struct cgroup *cgrp) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 0853289d321a53..9a62dc8146a1a6 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -2162,6 +2162,7 @@ static void cgroup_kill_sb(struct super_block *sb) struct kernfs_root *kf_root = kernfs_root_from_sb(sb); struct cgroup_root *root = cgroup_root_from_kf(kf_root); +printk("!!! cgroup_kill_sb killing css %llx !!!\n", root->cgrp.self); /* * If @root doesn't have any children, start killing it. * This prevents new mounts by disabling percpu_ref_tryget_live(). @@ -3118,6 +3119,7 @@ static void cgroup_apply_control_disable(struct cgroup *cgrp) struct cgroup_subsys *ss; int ssid; +printk("!!! cgroup_apply_control_disable\n"); cgroup_for_each_live_descendant_post(dsct, d_css, cgrp) { for_each_subsys(ss, ssid) { struct cgroup_subsys_state *css = cgroup_css(dsct, ss); @@ -3129,6 +3131,7 @@ static void cgroup_apply_control_disable(struct cgroup *cgrp) if (css->parent && !(cgroup_ss_mask(dsct) & (1 << ss->id))) { +printk("!!! cgroup_apply_control_disable kill_css %llx\n", css); kill_css(css); } else if (!css_visible(css)) { css_clear_dir(css); @@ -5108,6 +5111,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); } @@ -5197,6 +5201,7 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, struct cgroup_subsys_state *css; int err; +printk("!!! css_create !!!\n"); lockdep_assert_held(&cgroup_mutex); css = ss->css_alloc(parent_css); @@ -5477,6 +5482,7 @@ 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)) { +printk("!!! css_killed_ref_fn css %llx !!!\n", css); INIT_WORK(&css->destroy_work, css_killed_work_fn); queue_work(cgroup_destroy_wq, &css->destroy_work); } @@ -5556,6 +5562,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) struct cgroup_subsys_state *css; struct cgrp_cset_link *link; int ssid; +printk("!!! cgroup_destroy_locked !!!\n"); lockdep_assert_held(&cgroup_mutex); @@ -5573,7 +5580,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) */ if (css_has_online_children(&cgrp->self)) return -EBUSY; - /* * Mark @cgrp and the associated csets dead. The former prevents * further task migration and child creation by disabling @@ -5588,8 +5594,15 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) spin_unlock_irq(&css_set_lock); /* initiate massacre of all css's */ - for_each_css(css, ssid, cgrp) + for_each_css(css, ssid, cgrp) { +printk("!!! cgroup_destroy_locked kill all css'es !!!\n"); + if (css == &cgrp->self) { +printk("!!! cgroup_destroy_locked skipping css %llx !!!\n", css); + continue; + } + kill_css(css); + } /* clear and remove @cgrp dir, @cgrp has an extra ref on its kn */ css_clear_dir(&cgrp->self); @@ -5616,6 +5629,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) cgroup_bpf_offline(cgrp); /* put the base reference */ +printk("!!! cgroup_destroy_locked killing css %llx !!!\n", &cgrp->self); percpu_ref_kill(&cgrp->self.refcnt); return 0;