From 04a2b747f8e7c716b64f290fe5dd8637940eafda 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 | 21 +++++++++++++++++++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 618838c48313cd..d585e310e986c8 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) || percpu_ref_is_dying(&css->refcnt)) { +printk("!!! css_put is ALREADY zero css or dying %llx !!!\n", css); + return; + } + + if (!(css->flags & CSS_NO_REF || percpu_ref_is_dying(&css->refcnt))) { 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..7bec4dd5594c65 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -1562,6 +1562,8 @@ void cgroup_kn_unlock(struct kernfs_node *kn) mutex_unlock(&cgroup_mutex); kernfs_unbreak_active_protection(kn); +printk("!!!!!!!! cgroup_kn_lock_live: cgrp->self.flags & CSS_NO_REF %d !!\n", cgrp->self.flags & CSS_NO_REF); + cgroup_put(cgrp); } @@ -1597,6 +1599,7 @@ struct cgroup *cgroup_kn_lock_live(struct kernfs_node *kn, bool drain_offline) * protection against removal. Ensure @cgrp stays accessible and * break the active_ref protection. */ +printk("!!!!!!!! cgroup_kn_lock_live: css->flags & CSS_NO_REF %d !!\n", cgrp->self.flags & CSS_NO_REF); if (!cgroup_tryget(cgrp)) return NULL; kernfs_break_active_protection(kn); @@ -2162,6 +2165,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 +3122,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 +3134,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 +5114,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 +5204,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 +5485,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 +5565,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 +5583,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 +5597,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 +5632,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;