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]?