Commit 0083d27b authored by Tejun Heo's avatar Tejun Heo

cgroup: Improve cftype add/rm error handling

Let's track whether a cftype is currently added or not using a new flag
__CFTYPE_ADDED so that duplicate operations can be failed safely and
consistently allow using empty cftypes.
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
parent a8c52eba
...@@ -131,6 +131,7 @@ enum { ...@@ -131,6 +131,7 @@ enum {
/* internal flags, do not use outside cgroup core proper */ /* internal flags, do not use outside cgroup core proper */
__CFTYPE_ONLY_ON_DFL = (1 << 16), /* only on default hierarchy */ __CFTYPE_ONLY_ON_DFL = (1 << 16), /* only on default hierarchy */
__CFTYPE_NOT_ON_DFL = (1 << 17), /* not on default hierarchy */ __CFTYPE_NOT_ON_DFL = (1 << 17), /* not on default hierarchy */
__CFTYPE_ADDED = (1 << 18),
}; };
/* /*
......
...@@ -4198,19 +4198,26 @@ static void cgroup_exit_cftypes(struct cftype *cfts) ...@@ -4198,19 +4198,26 @@ static void cgroup_exit_cftypes(struct cftype *cfts)
cft->ss = NULL; cft->ss = NULL;
/* revert flags set by cgroup core while adding @cfts */ /* revert flags set by cgroup core while adding @cfts */
cft->flags &= ~(__CFTYPE_ONLY_ON_DFL | __CFTYPE_NOT_ON_DFL); cft->flags &= ~(__CFTYPE_ONLY_ON_DFL | __CFTYPE_NOT_ON_DFL |
__CFTYPE_ADDED);
} }
} }
static int cgroup_init_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) static int cgroup_init_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
{ {
struct cftype *cft; struct cftype *cft;
int ret = 0;
for (cft = cfts; cft->name[0] != '\0'; cft++) { for (cft = cfts; cft->name[0] != '\0'; cft++) {
struct kernfs_ops *kf_ops; struct kernfs_ops *kf_ops;
WARN_ON(cft->ss || cft->kf_ops); WARN_ON(cft->ss || cft->kf_ops);
if (cft->flags & __CFTYPE_ADDED) {
ret = -EBUSY;
break;
}
if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled()) if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled())
continue; continue;
...@@ -4226,26 +4233,26 @@ static int cgroup_init_cftypes(struct cgroup_subsys *ss, struct cftype *cfts) ...@@ -4226,26 +4233,26 @@ static int cgroup_init_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
if (cft->max_write_len && cft->max_write_len != PAGE_SIZE) { if (cft->max_write_len && cft->max_write_len != PAGE_SIZE) {
kf_ops = kmemdup(kf_ops, sizeof(*kf_ops), GFP_KERNEL); kf_ops = kmemdup(kf_ops, sizeof(*kf_ops), GFP_KERNEL);
if (!kf_ops) { if (!kf_ops) {
cgroup_exit_cftypes(cfts); ret = -ENOMEM;
return -ENOMEM; break;
} }
kf_ops->atomic_write_len = cft->max_write_len; kf_ops->atomic_write_len = cft->max_write_len;
} }
cft->kf_ops = kf_ops; cft->kf_ops = kf_ops;
cft->ss = ss; cft->ss = ss;
cft->flags |= __CFTYPE_ADDED;
} }
return 0; if (ret)
cgroup_exit_cftypes(cfts);
return ret;
} }
static int cgroup_rm_cftypes_locked(struct cftype *cfts) static int cgroup_rm_cftypes_locked(struct cftype *cfts)
{ {
lockdep_assert_held(&cgroup_mutex); lockdep_assert_held(&cgroup_mutex);
if (!cfts || !cfts[0].ss)
return -ENOENT;
list_del(&cfts->node); list_del(&cfts->node);
cgroup_apply_cftypes(cfts, false); cgroup_apply_cftypes(cfts, false);
cgroup_exit_cftypes(cfts); cgroup_exit_cftypes(cfts);
...@@ -4267,6 +4274,12 @@ int cgroup_rm_cftypes(struct cftype *cfts) ...@@ -4267,6 +4274,12 @@ int cgroup_rm_cftypes(struct cftype *cfts)
{ {
int ret; int ret;
if (!cfts || cfts[0].name[0] == '\0')
return 0;
if (!(cfts[0].flags & __CFTYPE_ADDED))
return -ENOENT;
mutex_lock(&cgroup_mutex); mutex_lock(&cgroup_mutex);
ret = cgroup_rm_cftypes_locked(cfts); ret = cgroup_rm_cftypes_locked(cfts);
mutex_unlock(&cgroup_mutex); mutex_unlock(&cgroup_mutex);
......
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