1a72232eaSVipin Sharma // SPDX-License-Identifier: GPL-2.0
2a72232eaSVipin Sharma /*
3a72232eaSVipin Sharma * Miscellaneous cgroup controller
4a72232eaSVipin Sharma *
5a72232eaSVipin Sharma * Copyright 2020 Google LLC
6a72232eaSVipin Sharma * Author: Vipin Sharma <[email protected]>
7a72232eaSVipin Sharma */
8a72232eaSVipin Sharma
9a72232eaSVipin Sharma #include <linux/limits.h>
10a72232eaSVipin Sharma #include <linux/cgroup.h>
11a72232eaSVipin Sharma #include <linux/errno.h>
12a72232eaSVipin Sharma #include <linux/atomic.h>
13a72232eaSVipin Sharma #include <linux/slab.h>
14a72232eaSVipin Sharma #include <linux/misc_cgroup.h>
15a72232eaSVipin Sharma
16a72232eaSVipin Sharma #define MAX_STR "max"
1732bf85c6SHaitao Huang #define MAX_NUM U64_MAX
18a72232eaSVipin Sharma
19a72232eaSVipin Sharma /* Miscellaneous res name, keep it in sync with enum misc_res_type */
20a72232eaSVipin Sharma static const char *const misc_res_name[] = {
217aef27f0SVipin Sharma #ifdef CONFIG_KVM_AMD_SEV
227aef27f0SVipin Sharma /* AMD SEV ASIDs resource */
237aef27f0SVipin Sharma "sev",
247aef27f0SVipin Sharma /* AMD SEV-ES ASIDs resource */
257aef27f0SVipin Sharma "sev_es",
267aef27f0SVipin Sharma #endif
27a72232eaSVipin Sharma };
28a72232eaSVipin Sharma
29a72232eaSVipin Sharma /* Root misc cgroup */
30a72232eaSVipin Sharma static struct misc_cg root_cg;
31a72232eaSVipin Sharma
32a72232eaSVipin Sharma /*
33a72232eaSVipin Sharma * Miscellaneous resources capacity for the entire machine. 0 capacity means
34a72232eaSVipin Sharma * resource is not initialized or not present in the host.
35a72232eaSVipin Sharma *
36a72232eaSVipin Sharma * root_cg.max and capacity are independent of each other. root_cg.max can be
37a72232eaSVipin Sharma * more than the actual capacity. We are using Limits resource distribution
38a72232eaSVipin Sharma * model of cgroup for miscellaneous controller.
39a72232eaSVipin Sharma */
4032bf85c6SHaitao Huang static u64 misc_res_capacity[MISC_CG_RES_TYPES];
41a72232eaSVipin Sharma
42a72232eaSVipin Sharma /**
43a72232eaSVipin Sharma * parent_misc() - Get the parent of the passed misc cgroup.
44a72232eaSVipin Sharma * @cgroup: cgroup whose parent needs to be fetched.
45a72232eaSVipin Sharma *
46a72232eaSVipin Sharma * Context: Any context.
47a72232eaSVipin Sharma * Return:
48a72232eaSVipin Sharma * * struct misc_cg* - Parent of the @cgroup.
49a72232eaSVipin Sharma * * %NULL - If @cgroup is null or the passed cgroup does not have a parent.
50a72232eaSVipin Sharma */
parent_misc(struct misc_cg * cgroup)51a72232eaSVipin Sharma static struct misc_cg *parent_misc(struct misc_cg *cgroup)
52a72232eaSVipin Sharma {
53a72232eaSVipin Sharma return cgroup ? css_misc(cgroup->css.parent) : NULL;
54a72232eaSVipin Sharma }
55a72232eaSVipin Sharma
56a72232eaSVipin Sharma /**
57a72232eaSVipin Sharma * valid_type() - Check if @type is valid or not.
58a72232eaSVipin Sharma * @type: misc res type.
59a72232eaSVipin Sharma *
60a72232eaSVipin Sharma * Context: Any context.
61a72232eaSVipin Sharma * Return:
62a72232eaSVipin Sharma * * true - If valid type.
63a72232eaSVipin Sharma * * false - If not valid type.
64a72232eaSVipin Sharma */
valid_type(enum misc_res_type type)65a72232eaSVipin Sharma static inline bool valid_type(enum misc_res_type type)
66a72232eaSVipin Sharma {
67a72232eaSVipin Sharma return type >= 0 && type < MISC_CG_RES_TYPES;
68a72232eaSVipin Sharma }
69a72232eaSVipin Sharma
70a72232eaSVipin Sharma /**
71a72232eaSVipin Sharma * misc_cg_set_capacity() - Set the capacity of the misc cgroup res.
72a72232eaSVipin Sharma * @type: Type of the misc res.
73a72232eaSVipin Sharma * @capacity: Supported capacity of the misc res on the host.
74a72232eaSVipin Sharma *
75a72232eaSVipin Sharma * If capacity is 0 then the charging a misc cgroup fails for that type.
76a72232eaSVipin Sharma *
77a72232eaSVipin Sharma * Context: Any context.
78a72232eaSVipin Sharma * Return:
79a72232eaSVipin Sharma * * %0 - Successfully registered the capacity.
80a72232eaSVipin Sharma * * %-EINVAL - If @type is invalid.
81a72232eaSVipin Sharma */
misc_cg_set_capacity(enum misc_res_type type,u64 capacity)8232bf85c6SHaitao Huang int misc_cg_set_capacity(enum misc_res_type type, u64 capacity)
83a72232eaSVipin Sharma {
84a72232eaSVipin Sharma if (!valid_type(type))
85a72232eaSVipin Sharma return -EINVAL;
86a72232eaSVipin Sharma
87a72232eaSVipin Sharma WRITE_ONCE(misc_res_capacity[type], capacity);
88a72232eaSVipin Sharma return 0;
89a72232eaSVipin Sharma }
90a72232eaSVipin Sharma EXPORT_SYMBOL_GPL(misc_cg_set_capacity);
91a72232eaSVipin Sharma
92a72232eaSVipin Sharma /**
93a72232eaSVipin Sharma * misc_cg_cancel_charge() - Cancel the charge from the misc cgroup.
94a72232eaSVipin Sharma * @type: Misc res type in misc cg to cancel the charge from.
95a72232eaSVipin Sharma * @cg: Misc cgroup to cancel charge from.
96a72232eaSVipin Sharma * @amount: Amount to cancel.
97a72232eaSVipin Sharma *
98a72232eaSVipin Sharma * Context: Any context.
99a72232eaSVipin Sharma */
misc_cg_cancel_charge(enum misc_res_type type,struct misc_cg * cg,u64 amount)100a72232eaSVipin Sharma static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg,
10132bf85c6SHaitao Huang u64 amount)
102a72232eaSVipin Sharma {
10332bf85c6SHaitao Huang WARN_ONCE(atomic64_add_negative(-amount, &cg->res[type].usage),
104a72232eaSVipin Sharma "misc cgroup resource %s became less than 0",
105a72232eaSVipin Sharma misc_res_name[type]);
106a72232eaSVipin Sharma }
107a72232eaSVipin Sharma
misc_cg_update_watermark(struct misc_res * res,u64 new_usage)1081028f391SXiu Jianfeng static void misc_cg_update_watermark(struct misc_res *res, u64 new_usage)
1091028f391SXiu Jianfeng {
1101028f391SXiu Jianfeng u64 old;
1111028f391SXiu Jianfeng
1121028f391SXiu Jianfeng while (true) {
1131028f391SXiu Jianfeng old = atomic64_read(&res->watermark);
1141028f391SXiu Jianfeng if (new_usage <= old)
1151028f391SXiu Jianfeng break;
1161028f391SXiu Jianfeng if (atomic64_cmpxchg(&res->watermark, old, new_usage) == old)
1171028f391SXiu Jianfeng break;
1181028f391SXiu Jianfeng }
1191028f391SXiu Jianfeng }
1201028f391SXiu Jianfeng
misc_cg_event(enum misc_res_type type,struct misc_cg * cg)121*6a26f9c6SXiu Jianfeng static void misc_cg_event(enum misc_res_type type, struct misc_cg *cg)
122*6a26f9c6SXiu Jianfeng {
123*6a26f9c6SXiu Jianfeng atomic64_inc(&cg->res[type].events_local);
124*6a26f9c6SXiu Jianfeng cgroup_file_notify(&cg->events_local_file);
125*6a26f9c6SXiu Jianfeng
126*6a26f9c6SXiu Jianfeng for (; parent_misc(cg); cg = parent_misc(cg)) {
127*6a26f9c6SXiu Jianfeng atomic64_inc(&cg->res[type].events);
128*6a26f9c6SXiu Jianfeng cgroup_file_notify(&cg->events_file);
129*6a26f9c6SXiu Jianfeng }
130*6a26f9c6SXiu Jianfeng }
131*6a26f9c6SXiu Jianfeng
132a72232eaSVipin Sharma /**
133a72232eaSVipin Sharma * misc_cg_try_charge() - Try charging the misc cgroup.
134a72232eaSVipin Sharma * @type: Misc res type to charge.
135a72232eaSVipin Sharma * @cg: Misc cgroup which will be charged.
136a72232eaSVipin Sharma * @amount: Amount to charge.
137a72232eaSVipin Sharma *
138a72232eaSVipin Sharma * Charge @amount to the misc cgroup. Caller must use the same cgroup during
139a72232eaSVipin Sharma * the uncharge call.
140a72232eaSVipin Sharma *
141a72232eaSVipin Sharma * Context: Any context.
142a72232eaSVipin Sharma * Return:
143a72232eaSVipin Sharma * * %0 - If successfully charged.
144a72232eaSVipin Sharma * * -EINVAL - If @type is invalid or misc res has 0 capacity.
145a72232eaSVipin Sharma * * -EBUSY - If max limit will be crossed or total usage will be more than the
146a72232eaSVipin Sharma * capacity.
147a72232eaSVipin Sharma */
misc_cg_try_charge(enum misc_res_type type,struct misc_cg * cg,u64 amount)14832bf85c6SHaitao Huang int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount)
149a72232eaSVipin Sharma {
150a72232eaSVipin Sharma struct misc_cg *i, *j;
151a72232eaSVipin Sharma int ret;
152a72232eaSVipin Sharma struct misc_res *res;
153714e08ccSHaitao Huang u64 new_usage;
154a72232eaSVipin Sharma
155a72232eaSVipin Sharma if (!(valid_type(type) && cg && READ_ONCE(misc_res_capacity[type])))
156a72232eaSVipin Sharma return -EINVAL;
157a72232eaSVipin Sharma
158a72232eaSVipin Sharma if (!amount)
159a72232eaSVipin Sharma return 0;
160a72232eaSVipin Sharma
161a72232eaSVipin Sharma for (i = cg; i; i = parent_misc(i)) {
162a72232eaSVipin Sharma res = &i->res[type];
163a72232eaSVipin Sharma
16432bf85c6SHaitao Huang new_usage = atomic64_add_return(amount, &res->usage);
165a72232eaSVipin Sharma if (new_usage > READ_ONCE(res->max) ||
166a72232eaSVipin Sharma new_usage > READ_ONCE(misc_res_capacity[type])) {
167a72232eaSVipin Sharma ret = -EBUSY;
168a72232eaSVipin Sharma goto err_charge;
169a72232eaSVipin Sharma }
1701028f391SXiu Jianfeng misc_cg_update_watermark(res, new_usage);
171a72232eaSVipin Sharma }
172a72232eaSVipin Sharma return 0;
173a72232eaSVipin Sharma
174a72232eaSVipin Sharma err_charge:
175*6a26f9c6SXiu Jianfeng misc_cg_event(type, i);
176f279294bSChunguang Xu
177a72232eaSVipin Sharma for (j = cg; j != i; j = parent_misc(j))
178a72232eaSVipin Sharma misc_cg_cancel_charge(type, j, amount);
179a72232eaSVipin Sharma misc_cg_cancel_charge(type, i, amount);
180a72232eaSVipin Sharma return ret;
181a72232eaSVipin Sharma }
182a72232eaSVipin Sharma EXPORT_SYMBOL_GPL(misc_cg_try_charge);
183a72232eaSVipin Sharma
184a72232eaSVipin Sharma /**
185a72232eaSVipin Sharma * misc_cg_uncharge() - Uncharge the misc cgroup.
186a72232eaSVipin Sharma * @type: Misc res type which was charged.
187a72232eaSVipin Sharma * @cg: Misc cgroup which will be uncharged.
188a72232eaSVipin Sharma * @amount: Charged amount.
189a72232eaSVipin Sharma *
190a72232eaSVipin Sharma * Context: Any context.
191a72232eaSVipin Sharma */
misc_cg_uncharge(enum misc_res_type type,struct misc_cg * cg,u64 amount)19232bf85c6SHaitao Huang void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, u64 amount)
193a72232eaSVipin Sharma {
194a72232eaSVipin Sharma struct misc_cg *i;
195a72232eaSVipin Sharma
196a72232eaSVipin Sharma if (!(amount && valid_type(type) && cg))
197a72232eaSVipin Sharma return;
198a72232eaSVipin Sharma
199a72232eaSVipin Sharma for (i = cg; i; i = parent_misc(i))
200a72232eaSVipin Sharma misc_cg_cancel_charge(type, i, amount);
201a72232eaSVipin Sharma }
202a72232eaSVipin Sharma EXPORT_SYMBOL_GPL(misc_cg_uncharge);
203a72232eaSVipin Sharma
204a72232eaSVipin Sharma /**
205a72232eaSVipin Sharma * misc_cg_max_show() - Show the misc cgroup max limit.
206a72232eaSVipin Sharma * @sf: Interface file
207a72232eaSVipin Sharma * @v: Arguments passed
208a72232eaSVipin Sharma *
209a72232eaSVipin Sharma * Context: Any context.
210a72232eaSVipin Sharma * Return: 0 to denote successful print.
211a72232eaSVipin Sharma */
misc_cg_max_show(struct seq_file * sf,void * v)212a72232eaSVipin Sharma static int misc_cg_max_show(struct seq_file *sf, void *v)
213a72232eaSVipin Sharma {
214a72232eaSVipin Sharma int i;
215a72232eaSVipin Sharma struct misc_cg *cg = css_misc(seq_css(sf));
21632bf85c6SHaitao Huang u64 max;
217a72232eaSVipin Sharma
218a72232eaSVipin Sharma for (i = 0; i < MISC_CG_RES_TYPES; i++) {
219a72232eaSVipin Sharma if (READ_ONCE(misc_res_capacity[i])) {
220a72232eaSVipin Sharma max = READ_ONCE(cg->res[i].max);
221a72232eaSVipin Sharma if (max == MAX_NUM)
222a72232eaSVipin Sharma seq_printf(sf, "%s max\n", misc_res_name[i]);
223a72232eaSVipin Sharma else
22432bf85c6SHaitao Huang seq_printf(sf, "%s %llu\n", misc_res_name[i],
225a72232eaSVipin Sharma max);
226a72232eaSVipin Sharma }
227a72232eaSVipin Sharma }
228a72232eaSVipin Sharma
229a72232eaSVipin Sharma return 0;
230a72232eaSVipin Sharma }
231a72232eaSVipin Sharma
232a72232eaSVipin Sharma /**
233a72232eaSVipin Sharma * misc_cg_max_write() - Update the maximum limit of the cgroup.
234a72232eaSVipin Sharma * @of: Handler for the file.
235a72232eaSVipin Sharma * @buf: Data from the user. It should be either "max", 0, or a positive
236a72232eaSVipin Sharma * integer.
237a72232eaSVipin Sharma * @nbytes: Number of bytes of the data.
238a72232eaSVipin Sharma * @off: Offset in the file.
239a72232eaSVipin Sharma *
240a72232eaSVipin Sharma * User can pass data like:
241a72232eaSVipin Sharma * echo sev 23 > misc.max, OR
242a72232eaSVipin Sharma * echo sev max > misc.max
243a72232eaSVipin Sharma *
244a72232eaSVipin Sharma * Context: Any context.
245a72232eaSVipin Sharma * Return:
246a72232eaSVipin Sharma * * >= 0 - Number of bytes processed in the input.
247a72232eaSVipin Sharma * * -EINVAL - If buf is not valid.
24832bf85c6SHaitao Huang * * -ERANGE - If number is bigger than the u64 capacity.
249a72232eaSVipin Sharma */
misc_cg_max_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)250a72232eaSVipin Sharma static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf,
251a72232eaSVipin Sharma size_t nbytes, loff_t off)
252a72232eaSVipin Sharma {
253a72232eaSVipin Sharma struct misc_cg *cg;
25432bf85c6SHaitao Huang u64 max;
255a72232eaSVipin Sharma int ret = 0, i;
256a72232eaSVipin Sharma enum misc_res_type type = MISC_CG_RES_TYPES;
257a72232eaSVipin Sharma char *token;
258a72232eaSVipin Sharma
259a72232eaSVipin Sharma buf = strstrip(buf);
260a72232eaSVipin Sharma token = strsep(&buf, " ");
261a72232eaSVipin Sharma
262a72232eaSVipin Sharma if (!token || !buf)
263a72232eaSVipin Sharma return -EINVAL;
264a72232eaSVipin Sharma
265a72232eaSVipin Sharma for (i = 0; i < MISC_CG_RES_TYPES; i++) {
266a72232eaSVipin Sharma if (!strcmp(misc_res_name[i], token)) {
267a72232eaSVipin Sharma type = i;
268a72232eaSVipin Sharma break;
269a72232eaSVipin Sharma }
270a72232eaSVipin Sharma }
271a72232eaSVipin Sharma
272a72232eaSVipin Sharma if (type == MISC_CG_RES_TYPES)
273a72232eaSVipin Sharma return -EINVAL;
274a72232eaSVipin Sharma
275a72232eaSVipin Sharma if (!strcmp(MAX_STR, buf)) {
276a72232eaSVipin Sharma max = MAX_NUM;
277a72232eaSVipin Sharma } else {
27832bf85c6SHaitao Huang ret = kstrtou64(buf, 0, &max);
279a72232eaSVipin Sharma if (ret)
280a72232eaSVipin Sharma return ret;
281a72232eaSVipin Sharma }
282a72232eaSVipin Sharma
283a72232eaSVipin Sharma cg = css_misc(of_css(of));
284a72232eaSVipin Sharma
285a72232eaSVipin Sharma if (READ_ONCE(misc_res_capacity[type]))
286a72232eaSVipin Sharma WRITE_ONCE(cg->res[type].max, max);
287a72232eaSVipin Sharma else
288a72232eaSVipin Sharma ret = -EINVAL;
289a72232eaSVipin Sharma
290a72232eaSVipin Sharma return ret ? ret : nbytes;
291a72232eaSVipin Sharma }
292a72232eaSVipin Sharma
293a72232eaSVipin Sharma /**
294a72232eaSVipin Sharma * misc_cg_current_show() - Show the current usage of the misc cgroup.
295a72232eaSVipin Sharma * @sf: Interface file
296a72232eaSVipin Sharma * @v: Arguments passed
297a72232eaSVipin Sharma *
298a72232eaSVipin Sharma * Context: Any context.
299a72232eaSVipin Sharma * Return: 0 to denote successful print.
300a72232eaSVipin Sharma */
misc_cg_current_show(struct seq_file * sf,void * v)301a72232eaSVipin Sharma static int misc_cg_current_show(struct seq_file *sf, void *v)
302a72232eaSVipin Sharma {
303a72232eaSVipin Sharma int i;
30432bf85c6SHaitao Huang u64 usage;
305a72232eaSVipin Sharma struct misc_cg *cg = css_misc(seq_css(sf));
306a72232eaSVipin Sharma
307a72232eaSVipin Sharma for (i = 0; i < MISC_CG_RES_TYPES; i++) {
30832bf85c6SHaitao Huang usage = atomic64_read(&cg->res[i].usage);
309a72232eaSVipin Sharma if (READ_ONCE(misc_res_capacity[i]) || usage)
31032bf85c6SHaitao Huang seq_printf(sf, "%s %llu\n", misc_res_name[i], usage);
311a72232eaSVipin Sharma }
312a72232eaSVipin Sharma
313a72232eaSVipin Sharma return 0;
314a72232eaSVipin Sharma }
315a72232eaSVipin Sharma
316a72232eaSVipin Sharma /**
3171028f391SXiu Jianfeng * misc_cg_peak_show() - Show the peak usage of the misc cgroup.
3181028f391SXiu Jianfeng * @sf: Interface file
3191028f391SXiu Jianfeng * @v: Arguments passed
3201028f391SXiu Jianfeng *
3211028f391SXiu Jianfeng * Context: Any context.
3221028f391SXiu Jianfeng * Return: 0 to denote successful print.
3231028f391SXiu Jianfeng */
misc_cg_peak_show(struct seq_file * sf,void * v)3241028f391SXiu Jianfeng static int misc_cg_peak_show(struct seq_file *sf, void *v)
3251028f391SXiu Jianfeng {
3261028f391SXiu Jianfeng int i;
3271028f391SXiu Jianfeng u64 watermark;
3281028f391SXiu Jianfeng struct misc_cg *cg = css_misc(seq_css(sf));
3291028f391SXiu Jianfeng
3301028f391SXiu Jianfeng for (i = 0; i < MISC_CG_RES_TYPES; i++) {
3311028f391SXiu Jianfeng watermark = atomic64_read(&cg->res[i].watermark);
3321028f391SXiu Jianfeng if (READ_ONCE(misc_res_capacity[i]) || watermark)
3331028f391SXiu Jianfeng seq_printf(sf, "%s %llu\n", misc_res_name[i], watermark);
3341028f391SXiu Jianfeng }
3351028f391SXiu Jianfeng
3361028f391SXiu Jianfeng return 0;
3371028f391SXiu Jianfeng }
3381028f391SXiu Jianfeng
3391028f391SXiu Jianfeng /**
340a72232eaSVipin Sharma * misc_cg_capacity_show() - Show the total capacity of misc res on the host.
341a72232eaSVipin Sharma * @sf: Interface file
342a72232eaSVipin Sharma * @v: Arguments passed
343a72232eaSVipin Sharma *
344a72232eaSVipin Sharma * Only present in the root cgroup directory.
345a72232eaSVipin Sharma *
346a72232eaSVipin Sharma * Context: Any context.
347a72232eaSVipin Sharma * Return: 0 to denote successful print.
348a72232eaSVipin Sharma */
misc_cg_capacity_show(struct seq_file * sf,void * v)349a72232eaSVipin Sharma static int misc_cg_capacity_show(struct seq_file *sf, void *v)
350a72232eaSVipin Sharma {
351a72232eaSVipin Sharma int i;
35232bf85c6SHaitao Huang u64 cap;
353a72232eaSVipin Sharma
354a72232eaSVipin Sharma for (i = 0; i < MISC_CG_RES_TYPES; i++) {
355a72232eaSVipin Sharma cap = READ_ONCE(misc_res_capacity[i]);
356a72232eaSVipin Sharma if (cap)
35732bf85c6SHaitao Huang seq_printf(sf, "%s %llu\n", misc_res_name[i], cap);
358a72232eaSVipin Sharma }
359a72232eaSVipin Sharma
360a72232eaSVipin Sharma return 0;
361a72232eaSVipin Sharma }
362a72232eaSVipin Sharma
__misc_events_show(struct seq_file * sf,bool local)363*6a26f9c6SXiu Jianfeng static int __misc_events_show(struct seq_file *sf, bool local)
364f279294bSChunguang Xu {
365f279294bSChunguang Xu struct misc_cg *cg = css_misc(seq_css(sf));
36632bf85c6SHaitao Huang u64 events;
36732bf85c6SHaitao Huang int i;
368f279294bSChunguang Xu
369f279294bSChunguang Xu for (i = 0; i < MISC_CG_RES_TYPES; i++) {
370*6a26f9c6SXiu Jianfeng if (local)
371*6a26f9c6SXiu Jianfeng events = atomic64_read(&cg->res[i].events_local);
372*6a26f9c6SXiu Jianfeng else
37332bf85c6SHaitao Huang events = atomic64_read(&cg->res[i].events);
374f279294bSChunguang Xu if (READ_ONCE(misc_res_capacity[i]) || events)
37532bf85c6SHaitao Huang seq_printf(sf, "%s.max %llu\n", misc_res_name[i], events);
376f279294bSChunguang Xu }
377f279294bSChunguang Xu return 0;
378f279294bSChunguang Xu }
379f279294bSChunguang Xu
misc_events_show(struct seq_file * sf,void * v)380*6a26f9c6SXiu Jianfeng static int misc_events_show(struct seq_file *sf, void *v)
381*6a26f9c6SXiu Jianfeng {
382*6a26f9c6SXiu Jianfeng return __misc_events_show(sf, false);
383*6a26f9c6SXiu Jianfeng }
384*6a26f9c6SXiu Jianfeng
misc_events_local_show(struct seq_file * sf,void * v)385*6a26f9c6SXiu Jianfeng static int misc_events_local_show(struct seq_file *sf, void *v)
386*6a26f9c6SXiu Jianfeng {
387*6a26f9c6SXiu Jianfeng return __misc_events_show(sf, true);
388*6a26f9c6SXiu Jianfeng }
389*6a26f9c6SXiu Jianfeng
390a72232eaSVipin Sharma /* Misc cgroup interface files */
391a72232eaSVipin Sharma static struct cftype misc_cg_files[] = {
392a72232eaSVipin Sharma {
393a72232eaSVipin Sharma .name = "max",
394a72232eaSVipin Sharma .write = misc_cg_max_write,
395a72232eaSVipin Sharma .seq_show = misc_cg_max_show,
396a72232eaSVipin Sharma .flags = CFTYPE_NOT_ON_ROOT,
397a72232eaSVipin Sharma },
398a72232eaSVipin Sharma {
399a72232eaSVipin Sharma .name = "current",
400a72232eaSVipin Sharma .seq_show = misc_cg_current_show,
401a72232eaSVipin Sharma },
402a72232eaSVipin Sharma {
4031028f391SXiu Jianfeng .name = "peak",
4041028f391SXiu Jianfeng .seq_show = misc_cg_peak_show,
4051028f391SXiu Jianfeng },
4061028f391SXiu Jianfeng {
407a72232eaSVipin Sharma .name = "capacity",
408a72232eaSVipin Sharma .seq_show = misc_cg_capacity_show,
409a72232eaSVipin Sharma .flags = CFTYPE_ONLY_ON_ROOT,
410a72232eaSVipin Sharma },
411f279294bSChunguang Xu {
412f279294bSChunguang Xu .name = "events",
413f279294bSChunguang Xu .flags = CFTYPE_NOT_ON_ROOT,
414f279294bSChunguang Xu .file_offset = offsetof(struct misc_cg, events_file),
415f279294bSChunguang Xu .seq_show = misc_events_show,
416f279294bSChunguang Xu },
417*6a26f9c6SXiu Jianfeng {
418*6a26f9c6SXiu Jianfeng .name = "events.local",
419*6a26f9c6SXiu Jianfeng .flags = CFTYPE_NOT_ON_ROOT,
420*6a26f9c6SXiu Jianfeng .file_offset = offsetof(struct misc_cg, events_local_file),
421*6a26f9c6SXiu Jianfeng .seq_show = misc_events_local_show,
422*6a26f9c6SXiu Jianfeng },
423a72232eaSVipin Sharma {}
424a72232eaSVipin Sharma };
425a72232eaSVipin Sharma
426a72232eaSVipin Sharma /**
427a72232eaSVipin Sharma * misc_cg_alloc() - Allocate misc cgroup.
428a72232eaSVipin Sharma * @parent_css: Parent cgroup.
429a72232eaSVipin Sharma *
430a72232eaSVipin Sharma * Context: Process context.
431a72232eaSVipin Sharma * Return:
432a72232eaSVipin Sharma * * struct cgroup_subsys_state* - css of the allocated cgroup.
433a72232eaSVipin Sharma * * ERR_PTR(-ENOMEM) - No memory available to allocate.
434a72232eaSVipin Sharma */
435a72232eaSVipin Sharma static struct cgroup_subsys_state *
misc_cg_alloc(struct cgroup_subsys_state * parent_css)436a72232eaSVipin Sharma misc_cg_alloc(struct cgroup_subsys_state *parent_css)
437a72232eaSVipin Sharma {
438a72232eaSVipin Sharma enum misc_res_type i;
439a72232eaSVipin Sharma struct misc_cg *cg;
440a72232eaSVipin Sharma
441a72232eaSVipin Sharma if (!parent_css) {
442a72232eaSVipin Sharma cg = &root_cg;
443a72232eaSVipin Sharma } else {
444a72232eaSVipin Sharma cg = kzalloc(sizeof(*cg), GFP_KERNEL);
445a72232eaSVipin Sharma if (!cg)
446a72232eaSVipin Sharma return ERR_PTR(-ENOMEM);
447a72232eaSVipin Sharma }
448a72232eaSVipin Sharma
449a72232eaSVipin Sharma for (i = 0; i < MISC_CG_RES_TYPES; i++) {
450a72232eaSVipin Sharma WRITE_ONCE(cg->res[i].max, MAX_NUM);
45132bf85c6SHaitao Huang atomic64_set(&cg->res[i].usage, 0);
452a72232eaSVipin Sharma }
453a72232eaSVipin Sharma
454a72232eaSVipin Sharma return &cg->css;
455a72232eaSVipin Sharma }
456a72232eaSVipin Sharma
457a72232eaSVipin Sharma /**
458a72232eaSVipin Sharma * misc_cg_free() - Free the misc cgroup.
459a72232eaSVipin Sharma * @css: cgroup subsys object.
460a72232eaSVipin Sharma *
461a72232eaSVipin Sharma * Context: Any context.
462a72232eaSVipin Sharma */
misc_cg_free(struct cgroup_subsys_state * css)463a72232eaSVipin Sharma static void misc_cg_free(struct cgroup_subsys_state *css)
464a72232eaSVipin Sharma {
465a72232eaSVipin Sharma kfree(css_misc(css));
466a72232eaSVipin Sharma }
467a72232eaSVipin Sharma
468a72232eaSVipin Sharma /* Cgroup controller callbacks */
469a72232eaSVipin Sharma struct cgroup_subsys misc_cgrp_subsys = {
470a72232eaSVipin Sharma .css_alloc = misc_cg_alloc,
471a72232eaSVipin Sharma .css_free = misc_cg_free,
472a72232eaSVipin Sharma .legacy_cftypes = misc_cg_files,
473a72232eaSVipin Sharma .dfl_cftypes = misc_cg_files,
474a72232eaSVipin Sharma };
475