--- include/linux/cgroup-defs.h | 2 ++ include/linux/cgroup.h | 32 ++++++++++++++++++++++++-------- kernel/cgroup/cgroup-internal.h | 1 + kernel/cgroup/cgroup-v1.c | 6 ++++-- kernel/cgroup/cgroup.c | 26 ++++++++++++++++++++++---- 5 files changed, 53 insertions(+), 14 deletions(-) diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index f5da2396a809..34a284ef3a78 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -166,6 +166,8 @@ struct cgroup_subsys_state { * fields of the containing structure. */ struct cgroup_subsys_state *parent; + + bool debug; }; /* diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 5708ad663572..72c076920072 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -295,6 +295,8 @@ void css_task_iter_end(struct css_task_iter *it); * Inline functions. */ +extern void css_refcount(struct cgroup_subsys_state *css, const char *op); + /** * css_get - obtain a reference on the specified css * @css: target css @@ -303,8 +305,10 @@ void css_task_iter_end(struct css_task_iter *it); */ static inline void css_get(struct cgroup_subsys_state *css) { - if (!(css->flags & CSS_NO_REF)) + if (!(css->flags & CSS_NO_REF)) { percpu_ref_get(&css->refcnt); + css_refcount(css, "GET"); + } } /** @@ -316,8 +320,10 @@ static inline void css_get(struct cgroup_subsys_state *css) */ static inline void css_get_many(struct cgroup_subsys_state *css, unsigned int n) { - if (!(css->flags & CSS_NO_REF)) + if (!(css->flags & CSS_NO_REF)) { percpu_ref_get_many(&css->refcnt, n); + css_refcount(css, "GETM"); + } } /** @@ -335,8 +341,11 @@ static inline bool css_tryget(struct cgroup_subsys_state *css) { if (css->flags & CSS_CREATING) return false; - if (!(css->flags & CSS_NO_REF)) - return percpu_ref_tryget(&css->refcnt); + if (css->flags & CSS_NO_REF) + return true; + if (!percpu_ref_tryget(&css->refcnt)) + return false; + css_refcount(css, "TRY"); return true; } @@ -354,8 +363,11 @@ static inline bool css_tryget_online(struct cgroup_subsys_state *css) { if (css->flags & CSS_CREATING) return false; - if (!(css->flags & CSS_NO_REF)) - return percpu_ref_tryget_live(&css->refcnt); + if (css->flags & CSS_NO_REF) + return true; + if (!percpu_ref_tryget_live(&css->refcnt)) + return false; + css_refcount(css, "TRYO"); return true; } @@ -387,8 +399,10 @@ 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 (!(css->flags & CSS_NO_REF)) { percpu_ref_put(&css->refcnt); + css_refcount(css, "PUT"); + } } /** @@ -400,8 +414,10 @@ 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 (!(css->flags & CSS_NO_REF)) { percpu_ref_put_many(&css->refcnt, n); + css_refcount(css, "PUTM"); + } } static inline void cgroup_get(struct cgroup *cgrp) diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h index b22c3d95d8eb..afe417c44602 100644 --- a/kernel/cgroup/cgroup-internal.h +++ b/kernel/cgroup/cgroup-internal.h @@ -46,6 +46,7 @@ struct cgroup_fs_context { unsigned int flags; /* CGRP_ROOT_* flags */ /* cgroup1 bits */ + bool debug; bool is_new_root; /* ->root is new and needs refcnt init */ bool cpuset_clone_children; bool none; /* User explicitly requested empty subsystem */ diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c index 0fbbde86a64d..281930390c6f 100644 --- a/kernel/cgroup/cgroup-v1.c +++ b/kernel/cgroup/cgroup-v1.c @@ -1033,6 +1033,8 @@ int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param) return cg_invalf(fc, "cgroup1: name respecified"); ctx->name = param->string; param->string = NULL; + if (strcmp(ctx->name, "xxxxy") == 0) + ctx->debug = true; return 0; } @@ -1174,7 +1176,7 @@ int cgroup1_get_tree(struct fs_context *fc) ss->root == &cgrp_dfl_root) continue; - if (!percpu_ref_tryget_live(&ss->root->cgrp.self.refcnt)) { + if (!css_tryget_online(&ss->root->cgrp.self)) { mutex_unlock(&cgroup_mutex); goto err_restart; } @@ -1227,7 +1229,7 @@ int cgroup1_get_tree(struct fs_context *fc) */ pinned_sb = kernfs_pin_sb(root->kf_root, NULL); if (IS_ERR(pinned_sb) || - !percpu_ref_tryget_live(&root->cgrp.self.refcnt)) { + !css_tryget_online(&root->cgrp.self)) { mutex_unlock(&cgroup_mutex); if (!IS_ERR_OR_NULL(pinned_sb)) deactivate_super(pinned_sb); diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 091e7eca3661..a25c6dee8515 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -1907,6 +1907,8 @@ void init_cgroup_root(struct cgroup_fs_context *ctx) strscpy(root->name, ctx->name, MAX_CGROUP_ROOT_NAMELEN); if (ctx->cpuset_clone_children) set_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags); + if (ctx->debug) + cgrp->self.debug = true; } int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask) @@ -1926,7 +1928,7 @@ int cgroup_setup_root(struct cgroup_root *root, u16 ss_mask) root_cgrp->ancestor_ids[0] = ret; ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, - 0, GFP_KERNEL); + PERCPU_REF_INIT_ATOMIC, GFP_KERNEL); if (ret) goto out; @@ -2025,6 +2027,8 @@ int cgroup_do_get_tree(struct fs_context *fc) struct cgroup_fs_context *ctx = cgroup_fc2context(fc); int ret; + printk("*** cgroup_do_get_tree()\n"); + ctx->kfc.root = ctx->root->kf_root; ctx->kfc.fill_super = cgroup_fill_super; @@ -2072,6 +2076,8 @@ static int cgroup_get_tree(struct fs_context *fc) { struct cgroup_fs_context *ctx = cgroup_fc2context(fc); + printk("*** cgroup_get_tree()\n"); + /* * The first time anyone tries to mount a cgroup, enable the list * linking each css_set to its tasks and fix up all existing tasks. @@ -2169,8 +2175,10 @@ static void cgroup_kill_sb(struct super_block *sb) if (!list_empty(&root->cgrp.self.children) || root == &cgrp_dfl_root) cgroup_put(&root->cgrp); - else + else { + css_refcount(&root->cgrp.self, "KIL"); percpu_ref_kill(&root->cgrp.self.refcnt); + } kernfs_kill_sb(sb); } @@ -4894,7 +4902,7 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, init_and_link_css(css, ss, cgrp); - err = percpu_ref_init(&css->refcnt, css_release, 0, GFP_KERNEL); + err = percpu_ref_init(&css->refcnt, css_release, PERCPU_REF_INIT_ATOMIC, GFP_KERNEL); if (err) goto err_free_css; @@ -4949,7 +4957,7 @@ static struct cgroup *cgroup_create(struct cgroup *parent) if (!cgrp) return ERR_PTR(-ENOMEM); - ret = percpu_ref_init(&cgrp->self.refcnt, css_release, 0, GFP_KERNEL); + ret = percpu_ref_init(&cgrp->self.refcnt, css_release, PERCPU_REF_INIT_ATOMIC, GFP_KERNEL); if (ret) goto out_free_cgrp; @@ -5197,6 +5205,7 @@ static void kill_css(struct cgroup_subsys_state *css) * Use percpu_ref_kill_and_confirm() to get notifications as each * css is confirmed to be seen as killed on all CPUs. */ + css_refcount(css, "KLC"); percpu_ref_kill_and_confirm(&css->refcnt, css_killed_ref_fn); } @@ -5281,6 +5290,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) cgroup1_check_for_release(parent); /* put the base reference */ + css_refcount(&cgrp->self, "KIL"); percpu_ref_kill(&cgrp->self.refcnt); return 0; @@ -6109,3 +6119,11 @@ static int __init cgroup_sysfs_init(void) } subsys_initcall(cgroup_sysfs_init); #endif /* CONFIG_SYSFS */ + +noinline void css_refcount(struct cgroup_subsys_state *css, const char *op) +{ + if (css->debug) + printk("*** %p %s %2ld: %pSR\n", + css, op, atomic_long_read(&css->refcnt.count), + __builtin_return_address(0)); +}