cgroup, memcg: implement css->id and convert css_from_id() to use it
Until now, cgroup->id has been used to identify all the associated csses and css_from_id() takes cgroup ID and returns the matching css by looking up the cgroup and then dereferencing the css associated with it; however, now that the lifetimes of cgroup and css are separate, this is incorrect and breaks on the unified hierarchy when a controller is disabled and enabled back again before the previous instance is released. This patch adds css->id which is a subsystem-unique ID and converts css_from_id() to look up by the new css->id instead. memcg is the only user of css_from_id() and also converted to use css->id instead. For traditional hierarchies, this shouldn't make any functional difference. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Michal Hocko <mhocko@suse.cz> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Jianyu Zhan <nasa4836@gmail.com> Acked-by: Li Zefan <lizefan@huawei.com>
This commit is contained in:
parent
ddfcadab35
commit
15a4c835e4
3 changed files with 49 additions and 23 deletions
|
@ -62,6 +62,12 @@ struct cgroup_subsys_state {
|
||||||
/* the parent css */
|
/* the parent css */
|
||||||
struct cgroup_subsys_state *parent;
|
struct cgroup_subsys_state *parent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Subsys-unique ID. 0 is unused and root is always 1. The
|
||||||
|
* matching css can be looked up using css_from_id().
|
||||||
|
*/
|
||||||
|
int id;
|
||||||
|
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
||||||
/* percpu_ref killing and RCU release */
|
/* percpu_ref killing and RCU release */
|
||||||
|
@ -655,6 +661,9 @@ struct cgroup_subsys {
|
||||||
/* link to parent, protected by cgroup_lock() */
|
/* link to parent, protected by cgroup_lock() */
|
||||||
struct cgroup_root *root;
|
struct cgroup_root *root;
|
||||||
|
|
||||||
|
/* idr for css->id */
|
||||||
|
struct idr css_idr;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of cftypes. Each entry is the first entry of an array
|
* List of cftypes. Each entry is the first entry of an array
|
||||||
* terminated by zero length name.
|
* terminated by zero length name.
|
||||||
|
|
|
@ -100,8 +100,8 @@ static DECLARE_RWSEM(css_set_rwsem);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Protects cgroup_idr so that IDs can be released without grabbing
|
* Protects cgroup_idr and css_idr so that IDs can be released without
|
||||||
* cgroup_mutex.
|
* grabbing cgroup_mutex.
|
||||||
*/
|
*/
|
||||||
static DEFINE_SPINLOCK(cgroup_idr_lock);
|
static DEFINE_SPINLOCK(cgroup_idr_lock);
|
||||||
|
|
||||||
|
@ -1089,12 +1089,6 @@ static void cgroup_put(struct cgroup *cgrp)
|
||||||
if (WARN_ON_ONCE(cgrp->parent && !cgroup_is_dead(cgrp)))
|
if (WARN_ON_ONCE(cgrp->parent && !cgroup_is_dead(cgrp)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX: cgrp->id is only used to look up css's. As cgroup and
|
|
||||||
* css's lifetimes will be decoupled, it should be made
|
|
||||||
* per-subsystem and moved to css->id so that lookups are
|
|
||||||
* successful until the target css is released.
|
|
||||||
*/
|
|
||||||
cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
|
cgroup_idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
|
||||||
cgrp->id = -1;
|
cgrp->id = -1;
|
||||||
|
|
||||||
|
@ -4104,8 +4098,11 @@ static void css_release(struct percpu_ref *ref)
|
||||||
{
|
{
|
||||||
struct cgroup_subsys_state *css =
|
struct cgroup_subsys_state *css =
|
||||||
container_of(ref, struct cgroup_subsys_state, refcnt);
|
container_of(ref, struct cgroup_subsys_state, refcnt);
|
||||||
|
struct cgroup_subsys *ss = css->ss;
|
||||||
|
|
||||||
|
RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL);
|
||||||
|
cgroup_idr_remove(&ss->css_idr, css->id);
|
||||||
|
|
||||||
RCU_INIT_POINTER(css->cgroup->subsys[css->ss->id], NULL);
|
|
||||||
call_rcu(&css->rcu_head, css_free_rcu_fn);
|
call_rcu(&css->rcu_head, css_free_rcu_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4195,9 +4192,17 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss)
|
||||||
if (err)
|
if (err)
|
||||||
goto err_free_css;
|
goto err_free_css;
|
||||||
|
|
||||||
|
err = cgroup_idr_alloc(&ss->css_idr, NULL, 2, 0, GFP_NOWAIT);
|
||||||
|
if (err < 0)
|
||||||
|
goto err_free_percpu_ref;
|
||||||
|
css->id = err;
|
||||||
|
|
||||||
err = cgroup_populate_dir(cgrp, 1 << ss->id);
|
err = cgroup_populate_dir(cgrp, 1 << ss->id);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_free_percpu_ref;
|
goto err_free_id;
|
||||||
|
|
||||||
|
/* @css is ready to be brought online now, make it visible */
|
||||||
|
cgroup_idr_replace(&ss->css_idr, css, css->id);
|
||||||
|
|
||||||
err = online_css(css);
|
err = online_css(css);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -4216,6 +4221,8 @@ static int create_css(struct cgroup *cgrp, struct cgroup_subsys *ss)
|
||||||
|
|
||||||
err_clear_dir:
|
err_clear_dir:
|
||||||
cgroup_clear_dir(css->cgroup, 1 << css->ss->id);
|
cgroup_clear_dir(css->cgroup, 1 << css->ss->id);
|
||||||
|
err_free_id:
|
||||||
|
cgroup_idr_remove(&ss->css_idr, css->id);
|
||||||
err_free_percpu_ref:
|
err_free_percpu_ref:
|
||||||
percpu_ref_cancel_init(&css->refcnt);
|
percpu_ref_cancel_init(&css->refcnt);
|
||||||
err_free_css:
|
err_free_css:
|
||||||
|
@ -4642,7 +4649,7 @@ static struct kernfs_syscall_ops cgroup_kf_syscall_ops = {
|
||||||
.rename = cgroup_rename,
|
.rename = cgroup_rename,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
|
static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
|
||||||
{
|
{
|
||||||
struct cgroup_subsys_state *css;
|
struct cgroup_subsys_state *css;
|
||||||
|
|
||||||
|
@ -4651,6 +4658,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
|
||||||
mutex_lock(&cgroup_tree_mutex);
|
mutex_lock(&cgroup_tree_mutex);
|
||||||
mutex_lock(&cgroup_mutex);
|
mutex_lock(&cgroup_mutex);
|
||||||
|
|
||||||
|
idr_init(&ss->css_idr);
|
||||||
INIT_LIST_HEAD(&ss->cfts);
|
INIT_LIST_HEAD(&ss->cfts);
|
||||||
|
|
||||||
/* Create the root cgroup state for this subsystem */
|
/* Create the root cgroup state for this subsystem */
|
||||||
|
@ -4659,6 +4667,13 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
|
||||||
/* We don't handle early failures gracefully */
|
/* We don't handle early failures gracefully */
|
||||||
BUG_ON(IS_ERR(css));
|
BUG_ON(IS_ERR(css));
|
||||||
init_and_link_css(css, ss, &cgrp_dfl_root.cgrp);
|
init_and_link_css(css, ss, &cgrp_dfl_root.cgrp);
|
||||||
|
if (early) {
|
||||||
|
/* idr_alloc() can't be called safely during early init */
|
||||||
|
css->id = 1;
|
||||||
|
} else {
|
||||||
|
css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, GFP_KERNEL);
|
||||||
|
BUG_ON(css->id < 0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Update the init_css_set to contain a subsys
|
/* Update the init_css_set to contain a subsys
|
||||||
* pointer to this state - since the subsystem is
|
* pointer to this state - since the subsystem is
|
||||||
|
@ -4709,7 +4724,7 @@ int __init cgroup_init_early(void)
|
||||||
ss->name = cgroup_subsys_name[i];
|
ss->name = cgroup_subsys_name[i];
|
||||||
|
|
||||||
if (ss->early_init)
|
if (ss->early_init)
|
||||||
cgroup_init_subsys(ss);
|
cgroup_init_subsys(ss, true);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -4741,8 +4756,16 @@ int __init cgroup_init(void)
|
||||||
mutex_unlock(&cgroup_tree_mutex);
|
mutex_unlock(&cgroup_tree_mutex);
|
||||||
|
|
||||||
for_each_subsys(ss, ssid) {
|
for_each_subsys(ss, ssid) {
|
||||||
if (!ss->early_init)
|
if (ss->early_init) {
|
||||||
cgroup_init_subsys(ss);
|
struct cgroup_subsys_state *css =
|
||||||
|
init_css_set.subsys[ss->id];
|
||||||
|
|
||||||
|
css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2,
|
||||||
|
GFP_KERNEL);
|
||||||
|
BUG_ON(css->id < 0);
|
||||||
|
} else {
|
||||||
|
cgroup_init_subsys(ss, false);
|
||||||
|
}
|
||||||
|
|
||||||
list_add_tail(&init_css_set.e_cset_node[ssid],
|
list_add_tail(&init_css_set.e_cset_node[ssid],
|
||||||
&cgrp_dfl_root.cgrp.e_csets[ssid]);
|
&cgrp_dfl_root.cgrp.e_csets[ssid]);
|
||||||
|
@ -5196,14 +5219,8 @@ struct cgroup_subsys_state *css_tryget_from_dir(struct dentry *dentry,
|
||||||
*/
|
*/
|
||||||
struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
|
struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
|
||||||
{
|
{
|
||||||
struct cgroup *cgrp;
|
|
||||||
|
|
||||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||||
|
return idr_find(&ss->css_idr, id);
|
||||||
cgrp = idr_find(&ss->root->cgroup_idr, id);
|
|
||||||
if (cgrp)
|
|
||||||
return cgroup_css(cgrp, ss);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CGROUP_DEBUG
|
#ifdef CONFIG_CGROUP_DEBUG
|
||||||
|
|
|
@ -527,7 +527,7 @@ static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg)
|
||||||
|
|
||||||
static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
|
static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg)
|
||||||
{
|
{
|
||||||
return memcg->css.cgroup->id;
|
return memcg->css.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
|
static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id)
|
||||||
|
@ -6401,7 +6401,7 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
|
||||||
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
|
||||||
struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(css));
|
struct mem_cgroup *parent = mem_cgroup_from_css(css_parent(css));
|
||||||
|
|
||||||
if (css->cgroup->id > MEM_CGROUP_ID_MAX)
|
if (css->id > MEM_CGROUP_ID_MAX)
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
if (!parent)
|
if (!parent)
|
||||||
|
|
Loading…
Add table
Reference in a new issue