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