xref: /openbmc/linux/kernel/cgroup/misc.c (revision 714e08cc)
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 <vipinsh@google.com>
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_res_total_usage() - Get the current total usage of the resource.
72a72232eaSVipin Sharma  * @type: misc res type.
73a72232eaSVipin Sharma  *
74a72232eaSVipin Sharma  * Context: Any context.
75a72232eaSVipin Sharma  * Return: Current total usage of the resource.
76a72232eaSVipin Sharma  */
misc_cg_res_total_usage(enum misc_res_type type)7732bf85c6SHaitao Huang u64 misc_cg_res_total_usage(enum misc_res_type type)
78a72232eaSVipin Sharma {
79a72232eaSVipin Sharma 	if (valid_type(type))
8032bf85c6SHaitao Huang 		return atomic64_read(&root_cg.res[type].usage);
81a72232eaSVipin Sharma 
82a72232eaSVipin Sharma 	return 0;
83a72232eaSVipin Sharma }
84a72232eaSVipin Sharma EXPORT_SYMBOL_GPL(misc_cg_res_total_usage);
85a72232eaSVipin Sharma 
86a72232eaSVipin Sharma /**
87a72232eaSVipin Sharma  * misc_cg_set_capacity() - Set the capacity of the misc cgroup res.
88a72232eaSVipin Sharma  * @type: Type of the misc res.
89a72232eaSVipin Sharma  * @capacity: Supported capacity of the misc res on the host.
90a72232eaSVipin Sharma  *
91a72232eaSVipin Sharma  * If capacity is 0 then the charging a misc cgroup fails for that type.
92a72232eaSVipin Sharma  *
93a72232eaSVipin Sharma  * Context: Any context.
94a72232eaSVipin Sharma  * Return:
95a72232eaSVipin Sharma  * * %0 - Successfully registered the capacity.
96a72232eaSVipin Sharma  * * %-EINVAL - If @type is invalid.
97a72232eaSVipin Sharma  */
misc_cg_set_capacity(enum misc_res_type type,u64 capacity)9832bf85c6SHaitao Huang int misc_cg_set_capacity(enum misc_res_type type, u64 capacity)
99a72232eaSVipin Sharma {
100a72232eaSVipin Sharma 	if (!valid_type(type))
101a72232eaSVipin Sharma 		return -EINVAL;
102a72232eaSVipin Sharma 
103a72232eaSVipin Sharma 	WRITE_ONCE(misc_res_capacity[type], capacity);
104a72232eaSVipin Sharma 	return 0;
105a72232eaSVipin Sharma }
106a72232eaSVipin Sharma EXPORT_SYMBOL_GPL(misc_cg_set_capacity);
107a72232eaSVipin Sharma 
108a72232eaSVipin Sharma /**
109a72232eaSVipin Sharma  * misc_cg_cancel_charge() - Cancel the charge from the misc cgroup.
110a72232eaSVipin Sharma  * @type: Misc res type in misc cg to cancel the charge from.
111a72232eaSVipin Sharma  * @cg: Misc cgroup to cancel charge from.
112a72232eaSVipin Sharma  * @amount: Amount to cancel.
113a72232eaSVipin Sharma  *
114a72232eaSVipin Sharma  * Context: Any context.
115a72232eaSVipin Sharma  */
misc_cg_cancel_charge(enum misc_res_type type,struct misc_cg * cg,u64 amount)116a72232eaSVipin Sharma static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg,
11732bf85c6SHaitao Huang 				  u64 amount)
118a72232eaSVipin Sharma {
11932bf85c6SHaitao Huang 	WARN_ONCE(atomic64_add_negative(-amount, &cg->res[type].usage),
120a72232eaSVipin Sharma 		  "misc cgroup resource %s became less than 0",
121a72232eaSVipin Sharma 		  misc_res_name[type]);
122a72232eaSVipin Sharma }
123a72232eaSVipin Sharma 
124a72232eaSVipin Sharma /**
125a72232eaSVipin Sharma  * misc_cg_try_charge() - Try charging the misc cgroup.
126a72232eaSVipin Sharma  * @type: Misc res type to charge.
127a72232eaSVipin Sharma  * @cg: Misc cgroup which will be charged.
128a72232eaSVipin Sharma  * @amount: Amount to charge.
129a72232eaSVipin Sharma  *
130a72232eaSVipin Sharma  * Charge @amount to the misc cgroup. Caller must use the same cgroup during
131a72232eaSVipin Sharma  * the uncharge call.
132a72232eaSVipin Sharma  *
133a72232eaSVipin Sharma  * Context: Any context.
134a72232eaSVipin Sharma  * Return:
135a72232eaSVipin Sharma  * * %0 - If successfully charged.
136a72232eaSVipin Sharma  * * -EINVAL - If @type is invalid or misc res has 0 capacity.
137a72232eaSVipin Sharma  * * -EBUSY - If max limit will be crossed or total usage will be more than the
138a72232eaSVipin Sharma  *	      capacity.
139a72232eaSVipin Sharma  */
misc_cg_try_charge(enum misc_res_type type,struct misc_cg * cg,u64 amount)14032bf85c6SHaitao Huang int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount)
141a72232eaSVipin Sharma {
142a72232eaSVipin Sharma 	struct misc_cg *i, *j;
143a72232eaSVipin Sharma 	int ret;
144a72232eaSVipin Sharma 	struct misc_res *res;
145*714e08ccSHaitao Huang 	u64 new_usage;
146a72232eaSVipin Sharma 
147a72232eaSVipin Sharma 	if (!(valid_type(type) && cg && READ_ONCE(misc_res_capacity[type])))
148a72232eaSVipin Sharma 		return -EINVAL;
149a72232eaSVipin Sharma 
150a72232eaSVipin Sharma 	if (!amount)
151a72232eaSVipin Sharma 		return 0;
152a72232eaSVipin Sharma 
153a72232eaSVipin Sharma 	for (i = cg; i; i = parent_misc(i)) {
154a72232eaSVipin Sharma 		res = &i->res[type];
155a72232eaSVipin Sharma 
15632bf85c6SHaitao Huang 		new_usage = atomic64_add_return(amount, &res->usage);
157a72232eaSVipin Sharma 		if (new_usage > READ_ONCE(res->max) ||
158a72232eaSVipin Sharma 		    new_usage > READ_ONCE(misc_res_capacity[type])) {
159a72232eaSVipin Sharma 			ret = -EBUSY;
160a72232eaSVipin Sharma 			goto err_charge;
161a72232eaSVipin Sharma 		}
162a72232eaSVipin Sharma 	}
163a72232eaSVipin Sharma 	return 0;
164a72232eaSVipin Sharma 
165a72232eaSVipin Sharma err_charge:
166f279294bSChunguang Xu 	for (j = i; j; j = parent_misc(j)) {
16732bf85c6SHaitao Huang 		atomic64_inc(&j->res[type].events);
168f279294bSChunguang Xu 		cgroup_file_notify(&j->events_file);
169f279294bSChunguang Xu 	}
170f279294bSChunguang Xu 
171a72232eaSVipin Sharma 	for (j = cg; j != i; j = parent_misc(j))
172a72232eaSVipin Sharma 		misc_cg_cancel_charge(type, j, amount);
173a72232eaSVipin Sharma 	misc_cg_cancel_charge(type, i, amount);
174a72232eaSVipin Sharma 	return ret;
175a72232eaSVipin Sharma }
176a72232eaSVipin Sharma EXPORT_SYMBOL_GPL(misc_cg_try_charge);
177a72232eaSVipin Sharma 
178a72232eaSVipin Sharma /**
179a72232eaSVipin Sharma  * misc_cg_uncharge() - Uncharge the misc cgroup.
180a72232eaSVipin Sharma  * @type: Misc res type which was charged.
181a72232eaSVipin Sharma  * @cg: Misc cgroup which will be uncharged.
182a72232eaSVipin Sharma  * @amount: Charged amount.
183a72232eaSVipin Sharma  *
184a72232eaSVipin Sharma  * Context: Any context.
185a72232eaSVipin Sharma  */
misc_cg_uncharge(enum misc_res_type type,struct misc_cg * cg,u64 amount)18632bf85c6SHaitao Huang void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, u64 amount)
187a72232eaSVipin Sharma {
188a72232eaSVipin Sharma 	struct misc_cg *i;
189a72232eaSVipin Sharma 
190a72232eaSVipin Sharma 	if (!(amount && valid_type(type) && cg))
191a72232eaSVipin Sharma 		return;
192a72232eaSVipin Sharma 
193a72232eaSVipin Sharma 	for (i = cg; i; i = parent_misc(i))
194a72232eaSVipin Sharma 		misc_cg_cancel_charge(type, i, amount);
195a72232eaSVipin Sharma }
196a72232eaSVipin Sharma EXPORT_SYMBOL_GPL(misc_cg_uncharge);
197a72232eaSVipin Sharma 
198a72232eaSVipin Sharma /**
199a72232eaSVipin Sharma  * misc_cg_max_show() - Show the misc cgroup max limit.
200a72232eaSVipin Sharma  * @sf: Interface file
201a72232eaSVipin Sharma  * @v: Arguments passed
202a72232eaSVipin Sharma  *
203a72232eaSVipin Sharma  * Context: Any context.
204a72232eaSVipin Sharma  * Return: 0 to denote successful print.
205a72232eaSVipin Sharma  */
misc_cg_max_show(struct seq_file * sf,void * v)206a72232eaSVipin Sharma static int misc_cg_max_show(struct seq_file *sf, void *v)
207a72232eaSVipin Sharma {
208a72232eaSVipin Sharma 	int i;
209a72232eaSVipin Sharma 	struct misc_cg *cg = css_misc(seq_css(sf));
21032bf85c6SHaitao Huang 	u64 max;
211a72232eaSVipin Sharma 
212a72232eaSVipin Sharma 	for (i = 0; i < MISC_CG_RES_TYPES; i++) {
213a72232eaSVipin Sharma 		if (READ_ONCE(misc_res_capacity[i])) {
214a72232eaSVipin Sharma 			max = READ_ONCE(cg->res[i].max);
215a72232eaSVipin Sharma 			if (max == MAX_NUM)
216a72232eaSVipin Sharma 				seq_printf(sf, "%s max\n", misc_res_name[i]);
217a72232eaSVipin Sharma 			else
21832bf85c6SHaitao Huang 				seq_printf(sf, "%s %llu\n", misc_res_name[i],
219a72232eaSVipin Sharma 					   max);
220a72232eaSVipin Sharma 		}
221a72232eaSVipin Sharma 	}
222a72232eaSVipin Sharma 
223a72232eaSVipin Sharma 	return 0;
224a72232eaSVipin Sharma }
225a72232eaSVipin Sharma 
226a72232eaSVipin Sharma /**
227a72232eaSVipin Sharma  * misc_cg_max_write() - Update the maximum limit of the cgroup.
228a72232eaSVipin Sharma  * @of: Handler for the file.
229a72232eaSVipin Sharma  * @buf: Data from the user. It should be either "max", 0, or a positive
230a72232eaSVipin Sharma  *	 integer.
231a72232eaSVipin Sharma  * @nbytes: Number of bytes of the data.
232a72232eaSVipin Sharma  * @off: Offset in the file.
233a72232eaSVipin Sharma  *
234a72232eaSVipin Sharma  * User can pass data like:
235a72232eaSVipin Sharma  * echo sev 23 > misc.max, OR
236a72232eaSVipin Sharma  * echo sev max > misc.max
237a72232eaSVipin Sharma  *
238a72232eaSVipin Sharma  * Context: Any context.
239a72232eaSVipin Sharma  * Return:
240a72232eaSVipin Sharma  * * >= 0 - Number of bytes processed in the input.
241a72232eaSVipin Sharma  * * -EINVAL - If buf is not valid.
24232bf85c6SHaitao Huang  * * -ERANGE - If number is bigger than the u64 capacity.
243a72232eaSVipin Sharma  */
misc_cg_max_write(struct kernfs_open_file * of,char * buf,size_t nbytes,loff_t off)244a72232eaSVipin Sharma static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf,
245a72232eaSVipin Sharma 				 size_t nbytes, loff_t off)
246a72232eaSVipin Sharma {
247a72232eaSVipin Sharma 	struct misc_cg *cg;
24832bf85c6SHaitao Huang 	u64 max;
249a72232eaSVipin Sharma 	int ret = 0, i;
250a72232eaSVipin Sharma 	enum misc_res_type type = MISC_CG_RES_TYPES;
251a72232eaSVipin Sharma 	char *token;
252a72232eaSVipin Sharma 
253a72232eaSVipin Sharma 	buf = strstrip(buf);
254a72232eaSVipin Sharma 	token = strsep(&buf, " ");
255a72232eaSVipin Sharma 
256a72232eaSVipin Sharma 	if (!token || !buf)
257a72232eaSVipin Sharma 		return -EINVAL;
258a72232eaSVipin Sharma 
259a72232eaSVipin Sharma 	for (i = 0; i < MISC_CG_RES_TYPES; i++) {
260a72232eaSVipin Sharma 		if (!strcmp(misc_res_name[i], token)) {
261a72232eaSVipin Sharma 			type = i;
262a72232eaSVipin Sharma 			break;
263a72232eaSVipin Sharma 		}
264a72232eaSVipin Sharma 	}
265a72232eaSVipin Sharma 
266a72232eaSVipin Sharma 	if (type == MISC_CG_RES_TYPES)
267a72232eaSVipin Sharma 		return -EINVAL;
268a72232eaSVipin Sharma 
269a72232eaSVipin Sharma 	if (!strcmp(MAX_STR, buf)) {
270a72232eaSVipin Sharma 		max = MAX_NUM;
271a72232eaSVipin Sharma 	} else {
27232bf85c6SHaitao Huang 		ret = kstrtou64(buf, 0, &max);
273a72232eaSVipin Sharma 		if (ret)
274a72232eaSVipin Sharma 			return ret;
275a72232eaSVipin Sharma 	}
276a72232eaSVipin Sharma 
277a72232eaSVipin Sharma 	cg = css_misc(of_css(of));
278a72232eaSVipin Sharma 
279a72232eaSVipin Sharma 	if (READ_ONCE(misc_res_capacity[type]))
280a72232eaSVipin Sharma 		WRITE_ONCE(cg->res[type].max, max);
281a72232eaSVipin Sharma 	else
282a72232eaSVipin Sharma 		ret = -EINVAL;
283a72232eaSVipin Sharma 
284a72232eaSVipin Sharma 	return ret ? ret : nbytes;
285a72232eaSVipin Sharma }
286a72232eaSVipin Sharma 
287a72232eaSVipin Sharma /**
288a72232eaSVipin Sharma  * misc_cg_current_show() - Show the current usage of the misc cgroup.
289a72232eaSVipin Sharma  * @sf: Interface file
290a72232eaSVipin Sharma  * @v: Arguments passed
291a72232eaSVipin Sharma  *
292a72232eaSVipin Sharma  * Context: Any context.
293a72232eaSVipin Sharma  * Return: 0 to denote successful print.
294a72232eaSVipin Sharma  */
misc_cg_current_show(struct seq_file * sf,void * v)295a72232eaSVipin Sharma static int misc_cg_current_show(struct seq_file *sf, void *v)
296a72232eaSVipin Sharma {
297a72232eaSVipin Sharma 	int i;
29832bf85c6SHaitao Huang 	u64 usage;
299a72232eaSVipin Sharma 	struct misc_cg *cg = css_misc(seq_css(sf));
300a72232eaSVipin Sharma 
301a72232eaSVipin Sharma 	for (i = 0; i < MISC_CG_RES_TYPES; i++) {
30232bf85c6SHaitao Huang 		usage = atomic64_read(&cg->res[i].usage);
303a72232eaSVipin Sharma 		if (READ_ONCE(misc_res_capacity[i]) || usage)
30432bf85c6SHaitao Huang 			seq_printf(sf, "%s %llu\n", misc_res_name[i], usage);
305a72232eaSVipin Sharma 	}
306a72232eaSVipin Sharma 
307a72232eaSVipin Sharma 	return 0;
308a72232eaSVipin Sharma }
309a72232eaSVipin Sharma 
310a72232eaSVipin Sharma /**
311a72232eaSVipin Sharma  * misc_cg_capacity_show() - Show the total capacity of misc res on the host.
312a72232eaSVipin Sharma  * @sf: Interface file
313a72232eaSVipin Sharma  * @v: Arguments passed
314a72232eaSVipin Sharma  *
315a72232eaSVipin Sharma  * Only present in the root cgroup directory.
316a72232eaSVipin Sharma  *
317a72232eaSVipin Sharma  * Context: Any context.
318a72232eaSVipin Sharma  * Return: 0 to denote successful print.
319a72232eaSVipin Sharma  */
misc_cg_capacity_show(struct seq_file * sf,void * v)320a72232eaSVipin Sharma static int misc_cg_capacity_show(struct seq_file *sf, void *v)
321a72232eaSVipin Sharma {
322a72232eaSVipin Sharma 	int i;
32332bf85c6SHaitao Huang 	u64 cap;
324a72232eaSVipin Sharma 
325a72232eaSVipin Sharma 	for (i = 0; i < MISC_CG_RES_TYPES; i++) {
326a72232eaSVipin Sharma 		cap = READ_ONCE(misc_res_capacity[i]);
327a72232eaSVipin Sharma 		if (cap)
32832bf85c6SHaitao Huang 			seq_printf(sf, "%s %llu\n", misc_res_name[i], cap);
329a72232eaSVipin Sharma 	}
330a72232eaSVipin Sharma 
331a72232eaSVipin Sharma 	return 0;
332a72232eaSVipin Sharma }
333a72232eaSVipin Sharma 
misc_events_show(struct seq_file * sf,void * v)334f279294bSChunguang Xu static int misc_events_show(struct seq_file *sf, void *v)
335f279294bSChunguang Xu {
336f279294bSChunguang Xu 	struct misc_cg *cg = css_misc(seq_css(sf));
33732bf85c6SHaitao Huang 	u64 events;
33832bf85c6SHaitao Huang 	int i;
339f279294bSChunguang Xu 
340f279294bSChunguang Xu 	for (i = 0; i < MISC_CG_RES_TYPES; i++) {
34132bf85c6SHaitao Huang 		events = atomic64_read(&cg->res[i].events);
342f279294bSChunguang Xu 		if (READ_ONCE(misc_res_capacity[i]) || events)
34332bf85c6SHaitao Huang 			seq_printf(sf, "%s.max %llu\n", misc_res_name[i], events);
344f279294bSChunguang Xu 	}
345f279294bSChunguang Xu 	return 0;
346f279294bSChunguang Xu }
347f279294bSChunguang Xu 
348a72232eaSVipin Sharma /* Misc cgroup interface files */
349a72232eaSVipin Sharma static struct cftype misc_cg_files[] = {
350a72232eaSVipin Sharma 	{
351a72232eaSVipin Sharma 		.name = "max",
352a72232eaSVipin Sharma 		.write = misc_cg_max_write,
353a72232eaSVipin Sharma 		.seq_show = misc_cg_max_show,
354a72232eaSVipin Sharma 		.flags = CFTYPE_NOT_ON_ROOT,
355a72232eaSVipin Sharma 	},
356a72232eaSVipin Sharma 	{
357a72232eaSVipin Sharma 		.name = "current",
358a72232eaSVipin Sharma 		.seq_show = misc_cg_current_show,
359a72232eaSVipin Sharma 	},
360a72232eaSVipin Sharma 	{
361a72232eaSVipin Sharma 		.name = "capacity",
362a72232eaSVipin Sharma 		.seq_show = misc_cg_capacity_show,
363a72232eaSVipin Sharma 		.flags = CFTYPE_ONLY_ON_ROOT,
364a72232eaSVipin Sharma 	},
365f279294bSChunguang Xu 	{
366f279294bSChunguang Xu 		.name = "events",
367f279294bSChunguang Xu 		.flags = CFTYPE_NOT_ON_ROOT,
368f279294bSChunguang Xu 		.file_offset = offsetof(struct misc_cg, events_file),
369f279294bSChunguang Xu 		.seq_show = misc_events_show,
370f279294bSChunguang Xu 	},
371a72232eaSVipin Sharma 	{}
372a72232eaSVipin Sharma };
373a72232eaSVipin Sharma 
374a72232eaSVipin Sharma /**
375a72232eaSVipin Sharma  * misc_cg_alloc() - Allocate misc cgroup.
376a72232eaSVipin Sharma  * @parent_css: Parent cgroup.
377a72232eaSVipin Sharma  *
378a72232eaSVipin Sharma  * Context: Process context.
379a72232eaSVipin Sharma  * Return:
380a72232eaSVipin Sharma  * * struct cgroup_subsys_state* - css of the allocated cgroup.
381a72232eaSVipin Sharma  * * ERR_PTR(-ENOMEM) - No memory available to allocate.
382a72232eaSVipin Sharma  */
383a72232eaSVipin Sharma static struct cgroup_subsys_state *
misc_cg_alloc(struct cgroup_subsys_state * parent_css)384a72232eaSVipin Sharma misc_cg_alloc(struct cgroup_subsys_state *parent_css)
385a72232eaSVipin Sharma {
386a72232eaSVipin Sharma 	enum misc_res_type i;
387a72232eaSVipin Sharma 	struct misc_cg *cg;
388a72232eaSVipin Sharma 
389a72232eaSVipin Sharma 	if (!parent_css) {
390a72232eaSVipin Sharma 		cg = &root_cg;
391a72232eaSVipin Sharma 	} else {
392a72232eaSVipin Sharma 		cg = kzalloc(sizeof(*cg), GFP_KERNEL);
393a72232eaSVipin Sharma 		if (!cg)
394a72232eaSVipin Sharma 			return ERR_PTR(-ENOMEM);
395a72232eaSVipin Sharma 	}
396a72232eaSVipin Sharma 
397a72232eaSVipin Sharma 	for (i = 0; i < MISC_CG_RES_TYPES; i++) {
398a72232eaSVipin Sharma 		WRITE_ONCE(cg->res[i].max, MAX_NUM);
39932bf85c6SHaitao Huang 		atomic64_set(&cg->res[i].usage, 0);
400a72232eaSVipin Sharma 	}
401a72232eaSVipin Sharma 
402a72232eaSVipin Sharma 	return &cg->css;
403a72232eaSVipin Sharma }
404a72232eaSVipin Sharma 
405a72232eaSVipin Sharma /**
406a72232eaSVipin Sharma  * misc_cg_free() - Free the misc cgroup.
407a72232eaSVipin Sharma  * @css: cgroup subsys object.
408a72232eaSVipin Sharma  *
409a72232eaSVipin Sharma  * Context: Any context.
410a72232eaSVipin Sharma  */
misc_cg_free(struct cgroup_subsys_state * css)411a72232eaSVipin Sharma static void misc_cg_free(struct cgroup_subsys_state *css)
412a72232eaSVipin Sharma {
413a72232eaSVipin Sharma 	kfree(css_misc(css));
414a72232eaSVipin Sharma }
415a72232eaSVipin Sharma 
416a72232eaSVipin Sharma /* Cgroup controller callbacks */
417a72232eaSVipin Sharma struct cgroup_subsys misc_cgrp_subsys = {
418a72232eaSVipin Sharma 	.css_alloc = misc_cg_alloc,
419a72232eaSVipin Sharma 	.css_free = misc_cg_free,
420a72232eaSVipin Sharma 	.legacy_cftypes = misc_cg_files,
421a72232eaSVipin Sharma 	.dfl_cftypes = misc_cg_files,
422a72232eaSVipin Sharma };
423