Commit 79578621 authored by Tejun Heo's avatar Tejun Heo

cgroup: implement cgroup_rm_cftypes()

Implement cgroup_rm_cftypes() which removes an array of cftypes from a
subsystem.  It can be called whether the target subsys is attached or
not.  cgroup core will remove the specified file from all existing
cgroups.

This will be used to improve sub-subsys modularity and will be helpful
for unified hierarchy.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Acked-by: default avatarLi Zefan <lizf@cn.fujitsu.com>
parent 05ef1d7c
...@@ -406,6 +406,7 @@ struct cgroup_scanner { ...@@ -406,6 +406,7 @@ struct cgroup_scanner {
}; };
int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts); int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
int cgroup_is_removed(const struct cgroup *cgrp); int cgroup_is_removed(const struct cgroup *cgrp);
......
...@@ -2690,17 +2690,20 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys, ...@@ -2690,17 +2690,20 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
return error; return error;
} }
static int cgroup_add_files(struct cgroup *cgrp, struct cgroup_subsys *subsys, static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
const struct cftype cfts[]) const struct cftype cfts[], bool is_add)
{ {
const struct cftype *cft; const struct cftype *cft;
int err, ret = 0; int err, ret = 0;
for (cft = cfts; cft->name[0] != '\0'; cft++) { for (cft = cfts; cft->name[0] != '\0'; cft++) {
err = cgroup_add_file(cgrp, subsys, cft); if (is_add)
err = cgroup_add_file(cgrp, subsys, cft);
else
err = cgroup_rm_file(cgrp, cft);
if (err) { if (err) {
pr_warning("cgroup_add_files: failed to create %s, err=%d\n", pr_warning("cgroup_addrm_files: failed to %s %s, err=%d\n",
cft->name, err); is_add ? "add" : "remove", cft->name, err);
ret = err; ret = err;
} }
} }
...@@ -2724,7 +2727,7 @@ static void cgroup_cfts_prepare(void) ...@@ -2724,7 +2727,7 @@ static void cgroup_cfts_prepare(void)
} }
static void cgroup_cfts_commit(struct cgroup_subsys *ss, static void cgroup_cfts_commit(struct cgroup_subsys *ss,
const struct cftype *cfts) const struct cftype *cfts, bool is_add)
__releases(&cgroup_mutex) __releases(&cgroup_cft_mutex) __releases(&cgroup_mutex) __releases(&cgroup_cft_mutex)
{ {
LIST_HEAD(pending); LIST_HEAD(pending);
...@@ -2750,7 +2753,7 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss, ...@@ -2750,7 +2753,7 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
mutex_lock(&cgroup_mutex); mutex_lock(&cgroup_mutex);
if (!cgroup_is_removed(cgrp)) if (!cgroup_is_removed(cgrp))
cgroup_add_files(cgrp, ss, cfts); cgroup_addrm_files(cgrp, ss, cfts, is_add);
mutex_unlock(&cgroup_mutex); mutex_unlock(&cgroup_mutex);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
...@@ -2786,12 +2789,43 @@ int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts) ...@@ -2786,12 +2789,43 @@ int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts)
cgroup_cfts_prepare(); cgroup_cfts_prepare();
set->cfts = cfts; set->cfts = cfts;
list_add_tail(&set->node, &ss->cftsets); list_add_tail(&set->node, &ss->cftsets);
cgroup_cfts_commit(ss, cfts); cgroup_cfts_commit(ss, cfts, true);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(cgroup_add_cftypes); EXPORT_SYMBOL_GPL(cgroup_add_cftypes);
/**
* cgroup_rm_cftypes - remove an array of cftypes from a subsystem
* @ss: target cgroup subsystem
* @cfts: zero-length name terminated array of cftypes
*
* Unregister @cfts from @ss. Files described by @cfts are removed from
* all existing cgroups to which @ss is attached and all future cgroups
* won't have them either. This function can be called anytime whether @ss
* is attached or not.
*
* Returns 0 on successful unregistration, -ENOENT if @cfts is not
* registered with @ss.
*/
int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts)
{
struct cftype_set *set;
cgroup_cfts_prepare();
list_for_each_entry(set, &ss->cftsets, node) {
if (set->cfts == cfts) {
list_del_init(&set->node);
cgroup_cfts_commit(ss, cfts, false);
return 0;
}
}
cgroup_cfts_commit(ss, NULL, false);
return -ENOENT;
}
/** /**
* cgroup_task_count - count the number of tasks in a cgroup. * cgroup_task_count - count the number of tasks in a cgroup.
* @cgrp: the cgroup in question * @cgrp: the cgroup in question
...@@ -3784,7 +3818,7 @@ static int cgroup_populate_dir(struct cgroup *cgrp) ...@@ -3784,7 +3818,7 @@ static int cgroup_populate_dir(struct cgroup *cgrp)
int err; int err;
struct cgroup_subsys *ss; struct cgroup_subsys *ss;
err = cgroup_add_files(cgrp, NULL, files); err = cgroup_addrm_files(cgrp, NULL, files, true);
if (err < 0) if (err < 0)
return err; return err;
...@@ -3796,7 +3830,7 @@ static int cgroup_populate_dir(struct cgroup *cgrp) ...@@ -3796,7 +3830,7 @@ static int cgroup_populate_dir(struct cgroup *cgrp)
return err; return err;
list_for_each_entry(set, &ss->cftsets, node) list_for_each_entry(set, &ss->cftsets, node)
cgroup_add_files(cgrp, ss, set->cfts); cgroup_addrm_files(cgrp, ss, set->cfts, true);
} }
/* This cgroup is ready now */ /* This cgroup is ready now */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment