misc.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  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 ULONG_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 unsigned long 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. unsigned long misc_cg_res_total_usage(enum misc_res_type type)
  70. {
  71. if (valid_type(type))
  72. return atomic_long_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, unsigned long 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. unsigned long amount)
  106. {
  107. WARN_ONCE(atomic_long_add_negative(-amount, &cg->res[type].usage),
  108. "misc cgroup resource %s became less than 0",
  109. misc_res_name[type]);
  110. }
  111. /**
  112. * misc_cg_try_charge() - Try charging the misc cgroup.
  113. * @type: Misc res type to charge.
  114. * @cg: Misc cgroup which will be charged.
  115. * @amount: Amount to charge.
  116. *
  117. * Charge @amount to the misc cgroup. Caller must use the same cgroup during
  118. * the uncharge call.
  119. *
  120. * Context: Any context.
  121. * Return:
  122. * * %0 - If successfully charged.
  123. * * -EINVAL - If @type is invalid or misc res has 0 capacity.
  124. * * -EBUSY - If max limit will be crossed or total usage will be more than the
  125. * capacity.
  126. */
  127. int misc_cg_try_charge(enum misc_res_type type, struct misc_cg *cg,
  128. unsigned long amount)
  129. {
  130. struct misc_cg *i, *j;
  131. int ret;
  132. struct misc_res *res;
  133. int new_usage;
  134. if (!(valid_type(type) && cg && READ_ONCE(misc_res_capacity[type])))
  135. return -EINVAL;
  136. if (!amount)
  137. return 0;
  138. for (i = cg; i; i = parent_misc(i)) {
  139. res = &i->res[type];
  140. new_usage = atomic_long_add_return(amount, &res->usage);
  141. if (new_usage > READ_ONCE(res->max) ||
  142. new_usage > READ_ONCE(misc_res_capacity[type])) {
  143. ret = -EBUSY;
  144. goto err_charge;
  145. }
  146. }
  147. return 0;
  148. err_charge:
  149. for (j = i; j; j = parent_misc(j)) {
  150. atomic_long_inc(&j->res[type].events);
  151. cgroup_file_notify(&j->events_file);
  152. }
  153. for (j = cg; j != i; j = parent_misc(j))
  154. misc_cg_cancel_charge(type, j, amount);
  155. misc_cg_cancel_charge(type, i, amount);
  156. return ret;
  157. }
  158. EXPORT_SYMBOL_GPL(misc_cg_try_charge);
  159. /**
  160. * misc_cg_uncharge() - Uncharge the misc cgroup.
  161. * @type: Misc res type which was charged.
  162. * @cg: Misc cgroup which will be uncharged.
  163. * @amount: Charged amount.
  164. *
  165. * Context: Any context.
  166. */
  167. void misc_cg_uncharge(enum misc_res_type type, struct misc_cg *cg,
  168. unsigned long amount)
  169. {
  170. struct misc_cg *i;
  171. if (!(amount && valid_type(type) && cg))
  172. return;
  173. for (i = cg; i; i = parent_misc(i))
  174. misc_cg_cancel_charge(type, i, amount);
  175. }
  176. EXPORT_SYMBOL_GPL(misc_cg_uncharge);
  177. /**
  178. * misc_cg_max_show() - Show the misc cgroup max limit.
  179. * @sf: Interface file
  180. * @v: Arguments passed
  181. *
  182. * Context: Any context.
  183. * Return: 0 to denote successful print.
  184. */
  185. static int misc_cg_max_show(struct seq_file *sf, void *v)
  186. {
  187. int i;
  188. struct misc_cg *cg = css_misc(seq_css(sf));
  189. unsigned long max;
  190. for (i = 0; i < MISC_CG_RES_TYPES; i++) {
  191. if (READ_ONCE(misc_res_capacity[i])) {
  192. max = READ_ONCE(cg->res[i].max);
  193. if (max == MAX_NUM)
  194. seq_printf(sf, "%s max\n", misc_res_name[i]);
  195. else
  196. seq_printf(sf, "%s %lu\n", misc_res_name[i],
  197. max);
  198. }
  199. }
  200. return 0;
  201. }
  202. /**
  203. * misc_cg_max_write() - Update the maximum limit of the cgroup.
  204. * @of: Handler for the file.
  205. * @buf: Data from the user. It should be either "max", 0, or a positive
  206. * integer.
  207. * @nbytes: Number of bytes of the data.
  208. * @off: Offset in the file.
  209. *
  210. * User can pass data like:
  211. * echo sev 23 > misc.max, OR
  212. * echo sev max > misc.max
  213. *
  214. * Context: Any context.
  215. * Return:
  216. * * >= 0 - Number of bytes processed in the input.
  217. * * -EINVAL - If buf is not valid.
  218. * * -ERANGE - If number is bigger than the unsigned long capacity.
  219. */
  220. static ssize_t misc_cg_max_write(struct kernfs_open_file *of, char *buf,
  221. size_t nbytes, loff_t off)
  222. {
  223. struct misc_cg *cg;
  224. unsigned long max;
  225. int ret = 0, i;
  226. enum misc_res_type type = MISC_CG_RES_TYPES;
  227. char *token;
  228. buf = strstrip(buf);
  229. token = strsep(&buf, " ");
  230. if (!token || !buf)
  231. return -EINVAL;
  232. for (i = 0; i < MISC_CG_RES_TYPES; i++) {
  233. if (!strcmp(misc_res_name[i], token)) {
  234. type = i;
  235. break;
  236. }
  237. }
  238. if (type == MISC_CG_RES_TYPES)
  239. return -EINVAL;
  240. if (!strcmp(MAX_STR, buf)) {
  241. max = MAX_NUM;
  242. } else {
  243. ret = kstrtoul(buf, 0, &max);
  244. if (ret)
  245. return ret;
  246. }
  247. cg = css_misc(of_css(of));
  248. if (READ_ONCE(misc_res_capacity[type]))
  249. WRITE_ONCE(cg->res[type].max, max);
  250. else
  251. ret = -EINVAL;
  252. return ret ? ret : nbytes;
  253. }
  254. /**
  255. * misc_cg_current_show() - Show the current usage of the misc cgroup.
  256. * @sf: Interface file
  257. * @v: Arguments passed
  258. *
  259. * Context: Any context.
  260. * Return: 0 to denote successful print.
  261. */
  262. static int misc_cg_current_show(struct seq_file *sf, void *v)
  263. {
  264. int i;
  265. unsigned long usage;
  266. struct misc_cg *cg = css_misc(seq_css(sf));
  267. for (i = 0; i < MISC_CG_RES_TYPES; i++) {
  268. usage = atomic_long_read(&cg->res[i].usage);
  269. if (READ_ONCE(misc_res_capacity[i]) || usage)
  270. seq_printf(sf, "%s %lu\n", misc_res_name[i], usage);
  271. }
  272. return 0;
  273. }
  274. /**
  275. * misc_cg_capacity_show() - Show the total capacity of misc res on the host.
  276. * @sf: Interface file
  277. * @v: Arguments passed
  278. *
  279. * Only present in the root cgroup directory.
  280. *
  281. * Context: Any context.
  282. * Return: 0 to denote successful print.
  283. */
  284. static int misc_cg_capacity_show(struct seq_file *sf, void *v)
  285. {
  286. int i;
  287. unsigned long cap;
  288. for (i = 0; i < MISC_CG_RES_TYPES; i++) {
  289. cap = READ_ONCE(misc_res_capacity[i]);
  290. if (cap)
  291. seq_printf(sf, "%s %lu\n", misc_res_name[i], cap);
  292. }
  293. return 0;
  294. }
  295. static int misc_events_show(struct seq_file *sf, void *v)
  296. {
  297. struct misc_cg *cg = css_misc(seq_css(sf));
  298. unsigned long events, i;
  299. for (i = 0; i < MISC_CG_RES_TYPES; i++) {
  300. events = atomic_long_read(&cg->res[i].events);
  301. if (READ_ONCE(misc_res_capacity[i]) || events)
  302. seq_printf(sf, "%s.max %lu\n", misc_res_name[i], events);
  303. }
  304. return 0;
  305. }
  306. /* Misc cgroup interface files */
  307. static struct cftype misc_cg_files[] = {
  308. {
  309. .name = "max",
  310. .write = misc_cg_max_write,
  311. .seq_show = misc_cg_max_show,
  312. .flags = CFTYPE_NOT_ON_ROOT,
  313. },
  314. {
  315. .name = "current",
  316. .seq_show = misc_cg_current_show,
  317. .flags = CFTYPE_NOT_ON_ROOT,
  318. },
  319. {
  320. .name = "capacity",
  321. .seq_show = misc_cg_capacity_show,
  322. .flags = CFTYPE_ONLY_ON_ROOT,
  323. },
  324. {
  325. .name = "events",
  326. .flags = CFTYPE_NOT_ON_ROOT,
  327. .file_offset = offsetof(struct misc_cg, events_file),
  328. .seq_show = misc_events_show,
  329. },
  330. {}
  331. };
  332. /**
  333. * misc_cg_alloc() - Allocate misc cgroup.
  334. * @parent_css: Parent cgroup.
  335. *
  336. * Context: Process context.
  337. * Return:
  338. * * struct cgroup_subsys_state* - css of the allocated cgroup.
  339. * * ERR_PTR(-ENOMEM) - No memory available to allocate.
  340. */
  341. static struct cgroup_subsys_state *
  342. misc_cg_alloc(struct cgroup_subsys_state *parent_css)
  343. {
  344. enum misc_res_type i;
  345. struct misc_cg *cg;
  346. if (!parent_css) {
  347. cg = &root_cg;
  348. } else {
  349. cg = kzalloc(sizeof(*cg), GFP_KERNEL);
  350. if (!cg)
  351. return ERR_PTR(-ENOMEM);
  352. }
  353. for (i = 0; i < MISC_CG_RES_TYPES; i++) {
  354. WRITE_ONCE(cg->res[i].max, MAX_NUM);
  355. atomic_long_set(&cg->res[i].usage, 0);
  356. }
  357. return &cg->css;
  358. }
  359. /**
  360. * misc_cg_free() - Free the misc cgroup.
  361. * @css: cgroup subsys object.
  362. *
  363. * Context: Any context.
  364. */
  365. static void misc_cg_free(struct cgroup_subsys_state *css)
  366. {
  367. kfree(css_misc(css));
  368. }
  369. /* Cgroup controller callbacks */
  370. struct cgroup_subsys misc_cgrp_subsys = {
  371. .css_alloc = misc_cg_alloc,
  372. .css_free = misc_cg_free,
  373. .legacy_cftypes = misc_cg_files,
  374. .dfl_cftypes = misc_cg_files,
  375. };