misc.c 11 KB

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