Message ID | 20240821015404.6038-3-haitao.huang@linux.intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add Cgroup support for SGX EPC memory | expand |
On Tue, 2024-08-20 at 18:53 -0700, Haitao Huang wrote: > +/** > + * misc_cg_set_ops() - register resource specific operations. > + * @type: Type of the misc res. > + * @ops: Operations for the given type. > + * > + * The callbacks in @ops will not be invoked if the capacity of @type is 0. > + * > + * Context: Any context. > + * Return: > + * * %0 - Successfully registered the operations. > + * * %-EINVAL - If @type is invalid, or the operations missing any required callbacks. > + */ > +int misc_cg_set_ops(enum misc_res_type type, const struct misc_res_ops *ops) > +{ > + if (!valid_type(type)) > + return -EINVAL; > + > + if (!ops) > + return -EINVAL; > + > + if (!ops->alloc) { > + pr_err("%s: alloc missing\n", __func__); > + return -EINVAL; > + } > + > + if (!ops->free) { > + pr_err("%s: free missing\n", __func__); > + return -EINVAL; > + } > + > + misc_res_ops[type] = ops; > + return 0; > +} > +EXPORT_SYMBOL_GPL(misc_cg_set_ops); As mentioned in another reply, the export isn't mandatory for SGX cgroup support due to SGX driver cannot be a module. But I understand the intention is to treat this in a similar way to misc_cg_set_capacity() etc which are currently exported. I have no hard opinion whether to export this one. But if we export this, I don't quite like the fact that it doesn't accept the NULL ops to allow the caller to unwind. But I'll leave to cgroup maintainers. > + > /** > * misc_cg_cancel_charge() - Cancel the charge from the misc cgroup. > * @type: Misc res type in misc cg to cancel the charge from. > @@ -439,6 +477,36 @@ static struct cftype misc_cg_files[] = { > {} > }; > > +static inline void _misc_cg_res_free(struct misc_cg *cg, enum misc_res_type last) > +{ > + enum misc_res_type i; > + > + for (i = 0; i <= last; i++) > + if (misc_res_ops[i] && READ_ONCE(misc_res_capacity[i])) > + misc_res_ops[i]->free(cg); > +} > + > +static inline int _misc_cg_res_alloc(struct misc_cg *cg) > +{ > + enum misc_res_type i; > + int ret; > + > + for (i = 0; i < MISC_CG_RES_TYPES; i++) { > + WRITE_ONCE(cg->res[i].max, MAX_NUM); > + atomic64_set(&cg->res[i].usage, 0); > + > + if (misc_res_ops[i] && READ_ONCE(misc_res_capacity[i])) { > + ret = misc_res_ops[i]->alloc(cg); > + if (ret) { > + _misc_cg_res_free(cg, i); > + return ret; > + } > + } > + } > + > + return 0; > +} > + I don't fully understand why kernel uses READ_ONCE()/WRITE_ONCE() to access misc_res_capacity[i] and others like 'cg->res[i].max', but it looks weird they are not used when accessing misc_res_ops[i]?
On Tue, 2024-08-20 at 18:53 -0700, Haitao Huang wrote: > /** > * misc_cg_alloc() - Allocate misc cgroup. > * @parent_css: Parent cgroup. > @@ -451,20 +519,25 @@ static struct cftype misc_cg_files[] = { > static struct cgroup_subsys_state * > misc_cg_alloc(struct cgroup_subsys_state *parent_css) > { > - enum misc_res_type i; > - struct misc_cg *cg; > + struct misc_cg *parent_cg, *cg; > + int ret; > > if (!parent_css) { > + parent_cg = &root_cg; > cg = &root_cg; > } else { > cg = kzalloc(sizeof(*cg), GFP_KERNEL); > if (!cg) > return ERR_PTR(-ENOMEM); > + parent_cg = css_misc(parent_css); > } > > - for (i = 0; i < MISC_CG_RES_TYPES; i++) { > - WRITE_ONCE(cg->res[i].max, MAX_NUM); > - atomic64_set(&cg->res[i].usage, 0); > + ret = _misc_cg_res_alloc(cg); > + if (ret) { > + if (likely(parent_css)) > + kfree(cg); > + > + return ERR_PTR(ret); > } > > return &cg->css; What's the purpose of @parent_cg? # make kernel/cgroup/ W=1 ... kernel/cgroup/misc.c: In function ‘misc_cg_alloc’: kernel/cgroup/misc.c:522:25: warning: variable ‘parent_cg’ set but not used [- Wunused-but-set-variable] 522 | struct misc_cg *parent_cg, *cg; | ^~~~~~~~~
diff --git a/include/linux/misc_cgroup.h b/include/linux/misc_cgroup.h index 49eef10c8e59..e5159770a68e 100644 --- a/include/linux/misc_cgroup.h +++ b/include/linux/misc_cgroup.h @@ -28,6 +28,16 @@ struct misc_cg; #include <linux/cgroup.h> +/** + * struct misc_res_ops: per resource type callback ops. + * @alloc: invoked for resource specific initialization when cgroup is allocated. + * @free: invoked for resource specific cleanup when cgroup is deallocated. + */ +struct misc_res_ops { + int (*alloc)(struct misc_cg *cg); + void (*free)(struct misc_cg *cg); +}; + /** * struct misc_res: Per cgroup per misc type resource * @max: Maximum limit on the resource. @@ -62,6 +72,7 @@ struct misc_cg { u64 misc_cg_res_total_usage(enum misc_res_type type); int misc_cg_set_capacity(enum misc_res_type type, u64 capacity); +int misc_cg_set_ops(enum misc_res_type type, const struct misc_res_ops *ops); int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount); void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, u64 amount); diff --git a/kernel/cgroup/misc.c b/kernel/cgroup/misc.c index 0e26068995a6..f3ce896d2c21 100644 --- a/kernel/cgroup/misc.c +++ b/kernel/cgroup/misc.c @@ -39,6 +39,9 @@ static struct misc_cg root_cg; */ static u64 misc_res_capacity[MISC_CG_RES_TYPES]; +/* Resource type specific operations */ +static const struct misc_res_ops *misc_res_ops[MISC_CG_RES_TYPES]; + /** * parent_misc() - Get the parent of the passed misc cgroup. * @cgroup: cgroup whose parent needs to be fetched. @@ -105,6 +108,41 @@ int misc_cg_set_capacity(enum misc_res_type type, u64 capacity) } EXPORT_SYMBOL_GPL(misc_cg_set_capacity); +/** + * misc_cg_set_ops() - register resource specific operations. + * @type: Type of the misc res. + * @ops: Operations for the given type. + * + * The callbacks in @ops will not be invoked if the capacity of @type is 0. + * + * Context: Any context. + * Return: + * * %0 - Successfully registered the operations. + * * %-EINVAL - If @type is invalid, or the operations missing any required callbacks. + */ +int misc_cg_set_ops(enum misc_res_type type, const struct misc_res_ops *ops) +{ + if (!valid_type(type)) + return -EINVAL; + + if (!ops) + return -EINVAL; + + if (!ops->alloc) { + pr_err("%s: alloc missing\n", __func__); + return -EINVAL; + } + + if (!ops->free) { + pr_err("%s: free missing\n", __func__); + return -EINVAL; + } + + misc_res_ops[type] = ops; + return 0; +} +EXPORT_SYMBOL_GPL(misc_cg_set_ops); + /** * misc_cg_cancel_charge() - Cancel the charge from the misc cgroup. * @type: Misc res type in misc cg to cancel the charge from. @@ -439,6 +477,36 @@ static struct cftype misc_cg_files[] = { {} }; +static inline void _misc_cg_res_free(struct misc_cg *cg, enum misc_res_type last) +{ + enum misc_res_type i; + + for (i = 0; i <= last; i++) + if (misc_res_ops[i] && READ_ONCE(misc_res_capacity[i])) + misc_res_ops[i]->free(cg); +} + +static inline int _misc_cg_res_alloc(struct misc_cg *cg) +{ + enum misc_res_type i; + int ret; + + for (i = 0; i < MISC_CG_RES_TYPES; i++) { + WRITE_ONCE(cg->res[i].max, MAX_NUM); + atomic64_set(&cg->res[i].usage, 0); + + if (misc_res_ops[i] && READ_ONCE(misc_res_capacity[i])) { + ret = misc_res_ops[i]->alloc(cg); + if (ret) { + _misc_cg_res_free(cg, i); + return ret; + } + } + } + + return 0; +} + /** * misc_cg_alloc() - Allocate misc cgroup. * @parent_css: Parent cgroup. @@ -451,20 +519,25 @@ static struct cftype misc_cg_files[] = { static struct cgroup_subsys_state * misc_cg_alloc(struct cgroup_subsys_state *parent_css) { - enum misc_res_type i; - struct misc_cg *cg; + struct misc_cg *parent_cg, *cg; + int ret; if (!parent_css) { + parent_cg = &root_cg; cg = &root_cg; } else { cg = kzalloc(sizeof(*cg), GFP_KERNEL); if (!cg) return ERR_PTR(-ENOMEM); + parent_cg = css_misc(parent_css); } - for (i = 0; i < MISC_CG_RES_TYPES; i++) { - WRITE_ONCE(cg->res[i].max, MAX_NUM); - atomic64_set(&cg->res[i].usage, 0); + ret = _misc_cg_res_alloc(cg); + if (ret) { + if (likely(parent_css)) + kfree(cg); + + return ERR_PTR(ret); } return &cg->css; @@ -478,7 +551,10 @@ misc_cg_alloc(struct cgroup_subsys_state *parent_css) */ static void misc_cg_free(struct cgroup_subsys_state *css) { - kfree(css_misc(css)); + struct misc_cg *cg = css_misc(css); + + _misc_cg_res_free(cg, MISC_CG_RES_TYPES - 1); + kfree(cg); } /* Cgroup controller callbacks */