Merge tag 'mm-hotfixes-stable-2025-07-11-16-16' of git://git.kernel.org/pub/scm/linux...
[linux-block.git] / kernel / cgroup / misc.c
CommitLineData
a72232ea
VS
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Miscellaneous cgroup controller
4 *
5 * Copyright 2020 Google LLC
6 * Author: Vipin Sharma <vipinsh@google.com>
7 */
8
9#include <linux/limits.h>
10#include <linux/cgroup.h>
11#include <linux/errno.h>
12#include <linux/atomic.h>
13#include <linux/slab.h>
14#include <linux/misc_cgroup.h>
15
16#define MAX_STR "max"
32bf85c6 17#define MAX_NUM U64_MAX
a72232ea
VS
18
19/* Miscellaneous res name, keep it in sync with enum misc_res_type */
20static const char *const misc_res_name[] = {
7aef27f0
VS
21#ifdef CONFIG_KVM_AMD_SEV
22 /* AMD SEV ASIDs resource */
23 "sev",
24 /* AMD SEV-ES ASIDs resource */
25 "sev_es",
26#endif
7c035bea
ZH
27#ifdef CONFIG_INTEL_TDX_HOST
28 /* Intel TDX HKIDs resource */
29 "tdx",
30#endif
a72232ea
VS
31};
32
33/* Root misc cgroup */
34static struct misc_cg root_cg;
35
36/*
37 * Miscellaneous resources capacity for the entire machine. 0 capacity means
38 * resource is not initialized or not present in the host.
39 *
40 * root_cg.max and capacity are independent of each other. root_cg.max can be
41 * more than the actual capacity. We are using Limits resource distribution
42 * model of cgroup for miscellaneous controller.
43 */
32bf85c6 44static u64 misc_res_capacity[MISC_CG_RES_TYPES];
a72232ea
VS
45
46/**
47 * parent_misc() - Get the parent of the passed misc cgroup.
48 * @cgroup: cgroup whose parent needs to be fetched.
49 *
50 * Context: Any context.
51 * Return:
52 * * struct misc_cg* - Parent of the @cgroup.
53 * * %NULL - If @cgroup is null or the passed cgroup does not have a parent.
54 */
55static struct misc_cg *parent_misc(struct misc_cg *cgroup)
56{
57 return cgroup ? css_misc(cgroup->css.parent) : NULL;
58}
59
60/**
61 * valid_type() - Check if @type is valid or not.
62 * @type: misc res type.
63 *
64 * Context: Any context.
65 * Return:
66 * * true - If valid type.
67 * * false - If not valid type.
68 */
69static inline bool valid_type(enum misc_res_type type)
70{
71 return type >= 0 && type < MISC_CG_RES_TYPES;
72}
73
a72232ea
VS
74/**
75 * misc_cg_set_capacity() - Set the capacity of the misc cgroup res.
76 * @type: Type of the misc res.
77 * @capacity: Supported capacity of the misc res on the host.
78 *
79 * If capacity is 0 then the charging a misc cgroup fails for that type.
80 *
81 * Context: Any context.
82 * Return:
83 * * %0 - Successfully registered the capacity.
84 * * %-EINVAL - If @type is invalid.
85 */
32bf85c6 86int misc_cg_set_capacity(enum misc_res_type type, u64 capacity)
a72232ea
VS
87{
88 if (!valid_type(type))
89 return -EINVAL;
90
91 WRITE_ONCE(misc_res_capacity[type], capacity);
92 return 0;
93}
94EXPORT_SYMBOL_GPL(misc_cg_set_capacity);
95
96/**
97 * misc_cg_cancel_charge() - Cancel the charge from the misc cgroup.
98 * @type: Misc res type in misc cg to cancel the charge from.
99 * @cg: Misc cgroup to cancel charge from.
100 * @amount: Amount to cancel.
101 *
102 * Context: Any context.
103 */
104static void misc_cg_cancel_charge(enum misc_res_type type, struct misc_cg *cg,
32bf85c6 105 u64 amount)
a72232ea 106{
32bf85c6 107 WARN_ONCE(atomic64_add_negative(-amount, &cg->res[type].usage),
a72232ea
VS
108 "misc cgroup resource %s became less than 0",
109 misc_res_name[type]);
110}
111
1028f391
XJ
112static void misc_cg_update_watermark(struct misc_res *res, u64 new_usage)
113{
114 u64 old;
115
116 while (true) {
117 old = atomic64_read(&res->watermark);
118 if (new_usage <= old)
119 break;
120 if (atomic64_cmpxchg(&res->watermark, old, new_usage) == old)
121 break;
122 }
123}
124
6a26f9c6
XJ
125static void misc_cg_event(enum misc_res_type type, struct misc_cg *cg)
126{
127 atomic64_inc(&cg->res[type].events_local);
128 cgroup_file_notify(&cg->events_local_file);
129
130 for (; parent_misc(cg); cg = parent_misc(cg)) {
131 atomic64_inc(&cg->res[type].events);
132 cgroup_file_notify(&cg->events_file);
133 }
134}
135
a72232ea
VS
136/**
137 * misc_cg_try_charge() - Try charging the misc cgroup.
138 * @type: Misc res type to charge.
139 * @cg: Misc cgroup which will be charged.
140 * @amount: Amount to charge.
141 *
142 * Charge @amount to the misc cgroup. Caller must use the same cgroup during
143 * the uncharge call.
144 *
145 * Context: Any context.
146 * Return:
147 * * %0 - If successfully charged.
148 * * -EINVAL - If @type is invalid or misc res has 0 capacity.
149 * * -EBUSY - If max limit will be crossed or total usage will be more than the
150 * capacity.
151 */
32bf85c6 152int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg, u64 amount)
a72232ea
VS
153{
154 struct misc_cg *i, *j;
155 int ret;
156 struct misc_res *res;
714e08cc 157 u64 new_usage;
a72232ea
VS
158
159 if (!(valid_type(type) && cg && READ_ONCE(misc_res_capacity[type])))
160 return -EINVAL;
161
162 if (!amount)
163 return 0;
164
165 for (i = cg; i; i = parent_misc(i)) {
166 res = &i->res[type];
167
32bf85c6 168 new_usage = atomic64_add_return(amount, &res->usage);
a72232ea
VS
169 if (new_usage > READ_ONCE(res->max) ||
170 new_usage > READ_ONCE(misc_res_capacity[type])) {
a72232ea
VS
171 ret = -EBUSY;
172 goto err_charge;
173 }
1028f391 174 misc_cg_update_watermark(res, new_usage);
a72232ea
VS
175 }
176 return 0;
177
178err_charge:
6a26f9c6 179 misc_cg_event(type, i);
f279294b 180
a72232ea
VS
181 for (j = cg; j != i; j = parent_misc(j))
182 misc_cg_cancel_charge(type, j, amount);
183 misc_cg_cancel_charge(type, i, amount);
184 return ret;
185}
186EXPORT_SYMBOL_GPL(misc_cg_try_charge);
187
188/**
189 * misc_cg_uncharge() - Uncharge the misc cgroup.
190 * @type: Misc res type which was charged.
191 * @cg: Misc cgroup which will be uncharged.
192 * @amount: Charged amount.
193 *
194 * Context: Any context.
195 */
32bf85c6 196void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg, u64 amount)
a72232ea
VS
197{
198 struct misc_cg *i;
199
200 if (!(amount && valid_type(type) && cg))
201 return;
202
203 for (i = cg; i; i = parent_misc(i))
204 misc_cg_cancel_charge(type, i, amount);
205}
206EXPORT_SYMBOL_GPL(misc_cg_uncharge);
207
208/**
209 * misc_cg_max_show() - Show the misc cgroup max limit.
210 * @sf: Interface file
211 * @v: Arguments passed
212 *
213 * Context: Any context.
214 * Return: 0 to denote successful print.
215 */
216static int misc_cg_max_show(struct seq_file *sf, void *v)
217{
218 int i;
219 struct misc_cg *cg = css_misc(seq_css(sf));
32bf85c6 220 u64 max;
a72232ea
VS
221
222 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
223 if (READ_ONCE(misc_res_capacity[i])) {
224 max = READ_ONCE(cg->res[i].max);
225 if (max == MAX_NUM)
226 seq_printf(sf, "%s max\n", misc_res_name[i]);
227 else
32bf85c6 228 seq_printf(sf, "%s %llu\n", misc_res_name[i],
a72232ea
VS
229 max);
230 }
231 }
232
233 return 0;
234}
235
236/**
237 * misc_cg_max_write() - Update the maximum limit of the cgroup.
238 * @of: Handler for the file.
239 * @buf: Data from the user. It should be either "max", 0, or a positive
240 * integer.
241 * @nbytes: Number of bytes of the data.
242 * @off: Offset in the file.
243 *
244 * User can pass data like:
245 * echo sev 23 > misc.max, OR
246 * echo sev max > misc.max
247 *
248 * Context: Any context.
249 * Return:
250 * * >= 0 - Number of bytes processed in the input.
251 * * -EINVAL - If buf is not valid.
32bf85c6 252 * * -ERANGE - If number is bigger than the u64 capacity.
a72232ea
VS
253 */
254static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf,
255 size_t nbytes, loff_t off)
256{
257 struct misc_cg *cg;
32bf85c6 258 u64 max;
a72232ea
VS
259 int ret = 0, i;
260 enum misc_res_type type = MISC_CG_RES_TYPES;
261 char *token;
262
263 buf = strstrip(buf);
264 token = strsep(&buf, " ");
265
266 if (!token || !buf)
267 return -EINVAL;
268
269 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
270 if (!strcmp(misc_res_name[i], token)) {
271 type = i;
272 break;
273 }
274 }
275
276 if (type == MISC_CG_RES_TYPES)
277 return -EINVAL;
278
279 if (!strcmp(MAX_STR, buf)) {
280 max = MAX_NUM;
281 } else {
32bf85c6 282 ret = kstrtou64(buf, 0, &max);
a72232ea
VS
283 if (ret)
284 return ret;
285 }
286
287 cg = css_misc(of_css(of));
288
289 if (READ_ONCE(misc_res_capacity[type]))
290 WRITE_ONCE(cg->res[type].max, max);
291 else
292 ret = -EINVAL;
293
294 return ret ? ret : nbytes;
295}
296
297/**
298 * misc_cg_current_show() - Show the current usage of the misc cgroup.
299 * @sf: Interface file
300 * @v: Arguments passed
301 *
302 * Context: Any context.
303 * Return: 0 to denote successful print.
304 */
305static int misc_cg_current_show(struct seq_file *sf, void *v)
306{
307 int i;
32bf85c6 308 u64 usage;
a72232ea
VS
309 struct misc_cg *cg = css_misc(seq_css(sf));
310
311 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
32bf85c6 312 usage = atomic64_read(&cg->res[i].usage);
a72232ea 313 if (READ_ONCE(misc_res_capacity[i]) || usage)
32bf85c6 314 seq_printf(sf, "%s %llu\n", misc_res_name[i], usage);
a72232ea
VS
315 }
316
317 return 0;
318}
319
1028f391
XJ
320/**
321 * misc_cg_peak_show() - Show the peak usage of the misc cgroup.
322 * @sf: Interface file
323 * @v: Arguments passed
324 *
325 * Context: Any context.
326 * Return: 0 to denote successful print.
327 */
328static int misc_cg_peak_show(struct seq_file *sf, void *v)
329{
330 int i;
331 u64 watermark;
332 struct misc_cg *cg = css_misc(seq_css(sf));
333
334 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
335 watermark = atomic64_read(&cg->res[i].watermark);
336 if (READ_ONCE(misc_res_capacity[i]) || watermark)
337 seq_printf(sf, "%s %llu\n", misc_res_name[i], watermark);
338 }
339
340 return 0;
341}
342
a72232ea
VS
343/**
344 * misc_cg_capacity_show() - Show the total capacity of misc res on the host.
345 * @sf: Interface file
346 * @v: Arguments passed
347 *
348 * Only present in the root cgroup directory.
349 *
350 * Context: Any context.
351 * Return: 0 to denote successful print.
352 */
353static int misc_cg_capacity_show(struct seq_file *sf, void *v)
354{
355 int i;
32bf85c6 356 u64 cap;
a72232ea
VS
357
358 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
359 cap = READ_ONCE(misc_res_capacity[i]);
360 if (cap)
32bf85c6 361 seq_printf(sf, "%s %llu\n", misc_res_name[i], cap);
a72232ea
VS
362 }
363
364 return 0;
365}
366
6a26f9c6 367static int __misc_events_show(struct seq_file *sf, bool local)
f279294b
CX
368{
369 struct misc_cg *cg = css_misc(seq_css(sf));
32bf85c6
HH
370 u64 events;
371 int i;
f279294b
CX
372
373 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
6a26f9c6
XJ
374 if (local)
375 events = atomic64_read(&cg->res[i].events_local);
376 else
377 events = atomic64_read(&cg->res[i].events);
f279294b 378 if (READ_ONCE(misc_res_capacity[i]) || events)
32bf85c6 379 seq_printf(sf, "%s.max %llu\n", misc_res_name[i], events);
f279294b
CX
380 }
381 return 0;
382}
383
6a26f9c6
XJ
384static int misc_events_show(struct seq_file *sf, void *v)
385{
386 return __misc_events_show(sf, false);
387}
388
389static int misc_events_local_show(struct seq_file *sf, void *v)
390{
391 return __misc_events_show(sf, true);
392}
393
a72232ea
VS
394/* Misc cgroup interface files */
395static struct cftype misc_cg_files[] = {
396 {
397 .name = "max",
398 .write = misc_cg_max_write,
399 .seq_show = misc_cg_max_show,
400 .flags = CFTYPE_NOT_ON_ROOT,
401 },
402 {
403 .name = "current",
404 .seq_show = misc_cg_current_show,
a72232ea 405 },
1028f391
XJ
406 {
407 .name = "peak",
408 .seq_show = misc_cg_peak_show,
409 },
a72232ea
VS
410 {
411 .name = "capacity",
412 .seq_show = misc_cg_capacity_show,
413 .flags = CFTYPE_ONLY_ON_ROOT,
414 },
f279294b
CX
415 {
416 .name = "events",
417 .flags = CFTYPE_NOT_ON_ROOT,
418 .file_offset = offsetof(struct misc_cg, events_file),
419 .seq_show = misc_events_show,
420 },
6a26f9c6
XJ
421 {
422 .name = "events.local",
423 .flags = CFTYPE_NOT_ON_ROOT,
424 .file_offset = offsetof(struct misc_cg, events_local_file),
425 .seq_show = misc_events_local_show,
426 },
a72232ea
VS
427 {}
428};
429
430/**
431 * misc_cg_alloc() - Allocate misc cgroup.
432 * @parent_css: Parent cgroup.
433 *
434 * Context: Process context.
435 * Return:
436 * * struct cgroup_subsys_state* - css of the allocated cgroup.
437 * * ERR_PTR(-ENOMEM) - No memory available to allocate.
438 */
439static struct cgroup_subsys_state *
440misc_cg_alloc(struct cgroup_subsys_state *parent_css)
441{
442 enum misc_res_type i;
443 struct misc_cg *cg;
444
445 if (!parent_css) {
446 cg = &root_cg;
447 } else {
448 cg = kzalloc(sizeof(*cg), GFP_KERNEL);
449 if (!cg)
450 return ERR_PTR(-ENOMEM);
451 }
452
453 for (i = 0; i < MISC_CG_RES_TYPES; i++) {
454 WRITE_ONCE(cg->res[i].max, MAX_NUM);
32bf85c6 455 atomic64_set(&cg->res[i].usage, 0);
a72232ea
VS
456 }
457
458 return &cg->css;
459}
460
461/**
462 * misc_cg_free() - Free the misc cgroup.
463 * @css: cgroup subsys object.
464 *
465 * Context: Any context.
466 */
467static void misc_cg_free(struct cgroup_subsys_state *css)
468{
469 kfree(css_misc(css));
470}
471
472/* Cgroup controller callbacks */
473struct cgroup_subsys misc_cgrp_subsys = {
474 .css_alloc = misc_cg_alloc,
475 .css_free = misc_cg_free,
476 .legacy_cftypes = misc_cg_files,
477 .dfl_cftypes = misc_cg_files,
478};