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