1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * RDMA resource limiting controller for cgroups. 4 * 5 * Used to allow a cgroup hierarchy to stop processes from consuming 6 * additional RDMA resources after a certain limit is reached. 7 * 8 * Copyright (C) 2016 Parav Pandit <pandit.parav@gmail.com> 9 */ 10 11 #include <linux/bitops.h> 12 #include <linux/limits.h> 13 #include <linux/slab.h> 14 #include <linux/seq_file.h> 15 #include <linux/cgroup.h> 16 #include <linux/parser.h> 17 #include <linux/cgroup_rdma.h> 18 19 #define RDMACG_MAX_STR "max" 20 21 enum rdmacg_limit_tokens { 22 RDMACG_DEVICE_INDEX, 23 RDMACG_HCA_HANDLE_VAL, 24 RDMACG_HCA_HANDLE_MAX, 25 RDMACG_HCA_OBJECT_VAL, 26 RDMACG_HCA_OBJECT_MAX, 27 NR_RDMACG_LIMIT_TOKENS, 28 }; 29 30 static const match_table_t rdmacg_limit_tokens = { 31 { RDMACG_DEVICE_INDEX, "index=%u" }, 32 { RDMACG_HCA_HANDLE_VAL, "hca_handle=%d" }, 33 { RDMACG_HCA_HANDLE_MAX, "hca_handle=max" }, 34 { RDMACG_HCA_OBJECT_VAL, "hca_object=%d" }, 35 { RDMACG_HCA_OBJECT_MAX, "hca_object=max" }, 36 { NR_RDMACG_LIMIT_TOKENS, NULL }, 37 }; 38 39 /* 40 * Protects list of resource pools maintained on per cgroup basis 41 * and rdma device list. 42 */ 43 static DEFINE_MUTEX(rdmacg_mutex); 44 static LIST_HEAD(rdmacg_devices); 45 46 enum rdmacg_file_type { 47 RDMACG_RESOURCE_TYPE_MAX, 48 RDMACG_RESOURCE_TYPE_STAT, 49 RDMACG_RESOURCE_TYPE_PEAK, 50 }; 51 52 /* 53 * resource table definition as to be seen by the user. 54 * Need to add entries to it when more resources are 55 * added/defined at IB verb/core layer. 56 */ 57 static char const *rdmacg_resource_names[] = { 58 [RDMACG_RESOURCE_HCA_HANDLE] = "hca_handle", 59 [RDMACG_RESOURCE_HCA_OBJECT] = "hca_object", 60 }; 61 62 /* resource tracker for each resource of rdma cgroup */ 63 struct rdmacg_resource { 64 int max; 65 int usage; 66 int peak; 67 }; 68 69 /* 70 * resource pool object which represents per cgroup, per device 71 * resources. There are multiple instances of this object per cgroup, 72 * therefore it cannot be embedded within rdma_cgroup structure. It 73 * is maintained as list. 74 */ 75 struct rdmacg_resource_pool { 76 struct rdmacg_device *device; 77 struct rdmacg_resource resources[RDMACG_RESOURCE_MAX]; 78 79 struct list_head cg_node; 80 struct list_head dev_node; 81 82 /* count active user tasks of this pool */ 83 u64 usage_sum; 84 /* total number counts which are set to max */ 85 int num_max_cnt; 86 87 /* per-resource event counters */ 88 u64 events_max[RDMACG_RESOURCE_MAX]; 89 u64 events_alloc_fail[RDMACG_RESOURCE_MAX]; 90 u64 events_local_max[RDMACG_RESOURCE_MAX]; 91 u64 events_local_alloc_fail[RDMACG_RESOURCE_MAX]; 92 }; 93 94 static struct rdma_cgroup *css_rdmacg(struct cgroup_subsys_state *css) 95 { 96 return container_of(css, struct rdma_cgroup, css); 97 } 98 99 static struct rdma_cgroup *parent_rdmacg(struct rdma_cgroup *cg) 100 { 101 return css_rdmacg(cg->css.parent); 102 } 103 104 static inline struct rdma_cgroup *get_current_rdmacg(void) 105 { 106 return css_rdmacg(task_get_css(current, rdma_cgrp_id)); 107 } 108 109 static void set_resource_limit(struct rdmacg_resource_pool *rpool, 110 int index, int new_max) 111 { 112 if (new_max == S32_MAX) { 113 if (rpool->resources[index].max != S32_MAX) 114 rpool->num_max_cnt++; 115 } else { 116 if (rpool->resources[index].max == S32_MAX) 117 rpool->num_max_cnt--; 118 } 119 rpool->resources[index].max = new_max; 120 } 121 122 static void set_all_resource_max_limit(struct rdmacg_resource_pool *rpool) 123 { 124 int i; 125 126 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) 127 set_resource_limit(rpool, i, S32_MAX); 128 } 129 130 static void free_cg_rpool_locked(struct rdmacg_resource_pool *rpool) 131 { 132 lockdep_assert_held(&rdmacg_mutex); 133 134 list_del(&rpool->cg_node); 135 list_del(&rpool->dev_node); 136 kfree(rpool); 137 } 138 139 static bool rpool_has_persistent_state(struct rdmacg_resource_pool *rpool) 140 { 141 int i; 142 143 /* 144 * Keep the rpool alive if any peak value is non-zero, 145 * so that rdma.peak persists as a historical high- 146 * watermark even after all resources are freed. 147 */ 148 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) { 149 if (rpool->resources[i].peak || 150 rpool->events_max[i] || 151 rpool->events_local_max[i] || 152 rpool->events_alloc_fail[i] || 153 rpool->events_local_alloc_fail[i]) 154 return true; 155 } 156 return false; 157 } 158 159 static struct rdmacg_resource_pool * 160 find_cg_rpool_locked(struct rdma_cgroup *cg, 161 struct rdmacg_device *device) 162 163 { 164 struct rdmacg_resource_pool *pool; 165 166 lockdep_assert_held(&rdmacg_mutex); 167 168 list_for_each_entry(pool, &cg->rpools, cg_node) 169 if (pool->device == device) 170 return pool; 171 172 return NULL; 173 } 174 175 static struct rdmacg_resource_pool * 176 get_cg_rpool_locked(struct rdma_cgroup *cg, struct rdmacg_device *device) 177 { 178 struct rdmacg_resource_pool *rpool; 179 180 rpool = find_cg_rpool_locked(cg, device); 181 if (rpool) 182 return rpool; 183 184 rpool = kzalloc_obj(*rpool); 185 if (!rpool) 186 return ERR_PTR(-ENOMEM); 187 188 rpool->device = device; 189 set_all_resource_max_limit(rpool); 190 191 INIT_LIST_HEAD(&rpool->cg_node); 192 INIT_LIST_HEAD(&rpool->dev_node); 193 list_add_tail(&rpool->cg_node, &cg->rpools); 194 list_add_tail(&rpool->dev_node, &device->rpools); 195 return rpool; 196 } 197 198 /** 199 * uncharge_cg_locked - uncharge resource for rdma cgroup 200 * @cg: pointer to cg to uncharge and all parents in hierarchy 201 * @device: pointer to rdmacg device 202 * @index: index of the resource to uncharge in cg (resource pool) 203 * 204 * It also frees the resource pool which was created as part of 205 * charging operation when there are no resources attached to 206 * resource pool. 207 */ 208 static void 209 uncharge_cg_locked(struct rdma_cgroup *cg, 210 struct rdmacg_device *device, 211 enum rdmacg_resource_type index) 212 { 213 struct rdmacg_resource_pool *rpool; 214 215 rpool = find_cg_rpool_locked(cg, device); 216 217 /* 218 * rpool cannot be null at this stage. Let kernel operate in case 219 * if there a bug in IB stack or rdma controller, instead of crashing 220 * the system. 221 */ 222 if (unlikely(!rpool)) { 223 pr_warn("Invalid device %p or rdma cgroup %p\n", device, cg); 224 return; 225 } 226 227 rpool->resources[index].usage--; 228 229 /* 230 * A negative count (or overflow) is invalid, 231 * it indicates a bug in the rdma controller. 232 */ 233 WARN_ON_ONCE(rpool->resources[index].usage < 0); 234 rpool->usage_sum--; 235 if (rpool->usage_sum == 0 && 236 rpool->num_max_cnt == RDMACG_RESOURCE_MAX) { 237 if (!rpool_has_persistent_state(rpool)) { 238 /* 239 * No user of the rpool and all entries are set to max, so 240 * safe to delete this rpool. 241 */ 242 free_cg_rpool_locked(rpool); 243 } 244 } 245 } 246 247 /** 248 * rdmacg_event_locked - fire event when resource allocation exceeds limit 249 * @cg: requesting cgroup 250 * @over_cg: cgroup whose limit was exceeded 251 * @device: rdma device 252 * @index: resource type index 253 * 254 * Must be called under rdmacg_mutex. Updates event counters in the 255 * resource pools of @cg and @over_cg, propagates hierarchical max 256 * events from @over_cg (including itself) upward, and notifies 257 * userspace via cgroup_file_notify(). 258 */ 259 static void rdmacg_event_locked(struct rdma_cgroup *cg, 260 struct rdma_cgroup *over_cg, 261 struct rdmacg_device *device, 262 enum rdmacg_resource_type index) 263 { 264 struct rdmacg_resource_pool *rpool; 265 struct rdma_cgroup *p; 266 267 lockdep_assert_held(&rdmacg_mutex); 268 269 /* Increment local alloc_fail in requesting cgroup */ 270 rpool = find_cg_rpool_locked(cg, device); 271 if (rpool) { 272 rpool->events_local_alloc_fail[index]++; 273 cgroup_file_notify(&cg->events_local_file); 274 } 275 276 /* Increment local max in the over-limit cgroup */ 277 rpool = find_cg_rpool_locked(over_cg, device); 278 if (rpool) { 279 rpool->events_local_max[index]++; 280 cgroup_file_notify(&over_cg->events_local_file); 281 } 282 283 /* Propagate hierarchical max events upward */ 284 for (p = over_cg; parent_rdmacg(p); p = parent_rdmacg(p)) { 285 rpool = get_cg_rpool_locked(p, device); 286 if (!IS_ERR(rpool)) { 287 rpool->events_max[index]++; 288 cgroup_file_notify(&p->events_file); 289 } 290 } 291 /* Propagate hierarchical alloc_fail from requesting cgroup upward */ 292 for (p = cg; parent_rdmacg(p); p = parent_rdmacg(p)) { 293 rpool = get_cg_rpool_locked(p, device); 294 if (!IS_ERR(rpool)) { 295 rpool->events_alloc_fail[index]++; 296 cgroup_file_notify(&p->events_file); 297 } 298 } 299 } 300 301 /** 302 * rdmacg_uncharge_hierarchy - hierarchically uncharge rdma resource count 303 * @cg: pointer to cg to uncharge and all parents in hierarchy 304 * @device: pointer to rdmacg device 305 * @stop_cg: while traversing hirerchy, when meet with stop_cg cgroup 306 * stop uncharging 307 * @index: index of the resource to uncharge in cg in given resource pool 308 */ 309 static void rdmacg_uncharge_hierarchy(struct rdma_cgroup *cg, 310 struct rdmacg_device *device, 311 struct rdma_cgroup *stop_cg, 312 enum rdmacg_resource_type index) 313 { 314 struct rdma_cgroup *p; 315 316 mutex_lock(&rdmacg_mutex); 317 318 for (p = cg; p != stop_cg; p = parent_rdmacg(p)) 319 uncharge_cg_locked(p, device, index); 320 321 mutex_unlock(&rdmacg_mutex); 322 323 css_put(&cg->css); 324 } 325 326 /** 327 * rdmacg_uncharge - hierarchically uncharge rdma resource count 328 * @cg: pointer to cg to uncharge and all parents in hierarchy 329 * @device: pointer to rdmacg device 330 * @index: index of the resource to uncharge in cgroup in given resource pool 331 */ 332 void rdmacg_uncharge(struct rdma_cgroup *cg, 333 struct rdmacg_device *device, 334 enum rdmacg_resource_type index) 335 { 336 if (index >= RDMACG_RESOURCE_MAX) 337 return; 338 339 rdmacg_uncharge_hierarchy(cg, device, NULL, index); 340 } 341 EXPORT_SYMBOL(rdmacg_uncharge); 342 343 /** 344 * rdmacg_try_charge - hierarchically try to charge the rdma resource 345 * @rdmacg: pointer to rdma cgroup which will own this resource 346 * @device: pointer to rdmacg device 347 * @index: index of the resource to charge in cgroup (resource pool) 348 * 349 * This function follows charging resource in hierarchical way. 350 * It will fail if the charge would cause the new value to exceed the 351 * hierarchical limit. 352 * Returns 0 if the charge succeeded, otherwise -EAGAIN, -ENOMEM or -EINVAL. 353 * Returns pointer to rdmacg for this resource when charging is successful. 354 * 355 * Charger needs to account resources on two criteria. 356 * (a) per cgroup & (b) per device resource usage. 357 * Per cgroup resource usage ensures that tasks of cgroup doesn't cross 358 * the configured limits. Per device provides granular configuration 359 * in multi device usage. It allocates resource pool in the hierarchy 360 * for each parent it come across for first resource. Later on resource 361 * pool will be available. Therefore it will be much faster thereon 362 * to charge/uncharge. 363 */ 364 int rdmacg_try_charge(struct rdma_cgroup **rdmacg, 365 struct rdmacg_device *device, 366 enum rdmacg_resource_type index) 367 { 368 struct rdma_cgroup *cg, *p; 369 struct rdmacg_resource_pool *rpool; 370 s64 new; 371 int ret = 0; 372 373 if (index >= RDMACG_RESOURCE_MAX) 374 return -EINVAL; 375 376 /* 377 * hold on to css, as cgroup can be removed but resource 378 * accounting happens on css. 379 */ 380 cg = get_current_rdmacg(); 381 382 mutex_lock(&rdmacg_mutex); 383 for (p = cg; p; p = parent_rdmacg(p)) { 384 rpool = get_cg_rpool_locked(p, device); 385 if (IS_ERR(rpool)) { 386 ret = PTR_ERR(rpool); 387 goto err; 388 } else { 389 new = (s64)rpool->resources[index].usage + 1; 390 if (new > rpool->resources[index].max) { 391 ret = -EAGAIN; 392 goto err; 393 } else { 394 rpool->resources[index].usage = new; 395 rpool->usage_sum++; 396 } 397 } 398 } 399 /* Update peak only after all charges succeed */ 400 for (p = cg; p; p = parent_rdmacg(p)) { 401 rpool = find_cg_rpool_locked(p, device); 402 if (rpool && rpool->resources[index].usage > rpool->resources[index].peak) 403 rpool->resources[index].peak = rpool->resources[index].usage; 404 } 405 mutex_unlock(&rdmacg_mutex); 406 407 *rdmacg = cg; 408 return 0; 409 410 err: 411 if (ret == -EAGAIN) 412 rdmacg_event_locked(cg, p, device, index); 413 mutex_unlock(&rdmacg_mutex); 414 rdmacg_uncharge_hierarchy(cg, device, p, index); 415 return ret; 416 } 417 EXPORT_SYMBOL(rdmacg_try_charge); 418 419 /** 420 * rdmacg_register_device - register rdmacg device to rdma controller. 421 * @device: pointer to rdmacg device whose resources need to be accounted. 422 * 423 * If IB stack wish a device to participate in rdma cgroup resource 424 * tracking, it must invoke this API to register with rdma cgroup before 425 * any user space application can start using the RDMA resources. 426 */ 427 void rdmacg_register_device(struct rdmacg_device *device) 428 { 429 INIT_LIST_HEAD(&device->dev_node); 430 INIT_LIST_HEAD(&device->rpools); 431 432 mutex_lock(&rdmacg_mutex); 433 list_add_tail(&device->dev_node, &rdmacg_devices); 434 mutex_unlock(&rdmacg_mutex); 435 } 436 EXPORT_SYMBOL(rdmacg_register_device); 437 438 /** 439 * rdmacg_unregister_device - unregister rdmacg device from rdma controller. 440 * @device: pointer to rdmacg device which was previously registered with rdma 441 * controller using rdmacg_register_device(). 442 * 443 * IB stack must invoke this after all the resources of the IB device 444 * are destroyed and after ensuring that no more resources will be created 445 * when this API is invoked. 446 */ 447 void rdmacg_unregister_device(struct rdmacg_device *device) 448 { 449 struct rdmacg_resource_pool *rpool, *tmp; 450 451 /* 452 * Synchronize with any active resource settings, 453 * usage query happening via configfs. 454 */ 455 mutex_lock(&rdmacg_mutex); 456 list_del_init(&device->dev_node); 457 458 /* 459 * Now that this device is off the cgroup list, its safe to free 460 * all the rpool resources. 461 */ 462 list_for_each_entry_safe(rpool, tmp, &device->rpools, dev_node) 463 free_cg_rpool_locked(rpool); 464 465 mutex_unlock(&rdmacg_mutex); 466 } 467 EXPORT_SYMBOL(rdmacg_unregister_device); 468 469 static struct rdmacg_device * 470 rdmacg_get_device_locked(const char *name, bool has_index, u32 index) 471 { 472 struct rdmacg_device *match = NULL; 473 struct rdmacg_device *device; 474 475 lockdep_assert_held(&rdmacg_mutex); 476 477 list_for_each_entry(device, &rdmacg_devices, dev_node) { 478 if (strcmp(name, device->name)) 479 continue; 480 481 if (has_index) { 482 if (device->index == index) 483 return device; 484 continue; 485 } 486 487 if (match) 488 return ERR_PTR(-ENOTUNIQ); 489 match = device; 490 } 491 492 return match ?: ERR_PTR(-ENODEV); 493 } 494 495 static bool 496 rdmacg_device_name_unique_locked(const struct rdmacg_device *device) 497 { 498 struct rdmacg_device *other; 499 500 lockdep_assert_held(&rdmacg_mutex); 501 502 list_for_each_entry(other, &rdmacg_devices, dev_node) 503 if (other != device && !strcmp(other->name, device->name)) 504 return false; 505 506 return true; 507 } 508 509 static void rdmacg_print_device_key(struct seq_file *sf, 510 const struct rdmacg_device *device) 511 { 512 seq_puts(sf, device->name); 513 if (!rdmacg_device_name_unique_locked(device)) 514 seq_printf(sf, " index=%u", device->index); 515 seq_putc(sf, ' '); 516 } 517 518 static ssize_t rdmacg_resource_set_max(struct kernfs_open_file *of, 519 char *buf, size_t nbytes, loff_t off) 520 { 521 struct rdma_cgroup *cg = css_rdmacg(of_css(of)); 522 const char *dev_name; 523 struct rdmacg_resource_pool *rpool; 524 struct rdmacg_device *device; 525 char *options = strstrip(buf); 526 char *p; 527 int *new_limits; 528 unsigned long enables = 0; 529 u32 dev_index = 0; 530 bool has_index = false; 531 int i = 0, ret = 0; 532 533 /* extract the device name first */ 534 dev_name = strsep(&options, " "); 535 if (!dev_name) { 536 ret = -EINVAL; 537 goto err; 538 } 539 540 new_limits = kzalloc_objs(int, RDMACG_RESOURCE_MAX); 541 if (!new_limits) { 542 ret = -ENOMEM; 543 goto err; 544 } 545 546 /* parse the optional device index and resource limit tokens */ 547 while ((p = strsep(&options, " \t\n"))) { 548 substring_t args[MAX_OPT_ARGS]; 549 int tok, intval; 550 551 if (!*p) 552 continue; 553 554 tok = match_token(p, rdmacg_limit_tokens, args); 555 switch (tok) { 556 case RDMACG_DEVICE_INDEX: 557 if (has_index || match_uint(&args[0], &dev_index)) { 558 ret = -EINVAL; 559 goto parse_err; 560 } 561 has_index = true; 562 break; 563 case RDMACG_HCA_HANDLE_VAL: 564 if (match_int(&args[0], &intval) || intval < 0) { 565 ret = -EINVAL; 566 goto parse_err; 567 } 568 new_limits[RDMACG_RESOURCE_HCA_HANDLE] = intval; 569 enables |= BIT(RDMACG_RESOURCE_HCA_HANDLE); 570 break; 571 case RDMACG_HCA_HANDLE_MAX: 572 new_limits[RDMACG_RESOURCE_HCA_HANDLE] = S32_MAX; 573 enables |= BIT(RDMACG_RESOURCE_HCA_HANDLE); 574 break; 575 case RDMACG_HCA_OBJECT_VAL: 576 if (match_int(&args[0], &intval) || intval < 0) { 577 ret = -EINVAL; 578 goto parse_err; 579 } 580 new_limits[RDMACG_RESOURCE_HCA_OBJECT] = intval; 581 enables |= BIT(RDMACG_RESOURCE_HCA_OBJECT); 582 break; 583 case RDMACG_HCA_OBJECT_MAX: 584 new_limits[RDMACG_RESOURCE_HCA_OBJECT] = S32_MAX; 585 enables |= BIT(RDMACG_RESOURCE_HCA_OBJECT); 586 break; 587 default: 588 ret = -EINVAL; 589 goto parse_err; 590 } 591 } 592 593 /* acquire lock to synchronize with hot plug devices */ 594 mutex_lock(&rdmacg_mutex); 595 596 device = rdmacg_get_device_locked(dev_name, has_index, dev_index); 597 if (IS_ERR(device)) { 598 ret = PTR_ERR(device); 599 goto dev_err; 600 } 601 602 rpool = get_cg_rpool_locked(cg, device); 603 if (IS_ERR(rpool)) { 604 ret = PTR_ERR(rpool); 605 goto dev_err; 606 } 607 608 /* now set the new limits of the rpool */ 609 for_each_set_bit(i, &enables, RDMACG_RESOURCE_MAX) 610 set_resource_limit(rpool, i, new_limits[i]); 611 612 if (rpool->usage_sum == 0 && 613 rpool->num_max_cnt == RDMACG_RESOURCE_MAX) { 614 if (!rpool_has_persistent_state(rpool)) { 615 /* 616 * No user of the rpool and all entries are set to max, so 617 * safe to delete this rpool. 618 */ 619 free_cg_rpool_locked(rpool); 620 } 621 } 622 623 dev_err: 624 mutex_unlock(&rdmacg_mutex); 625 626 parse_err: 627 kfree(new_limits); 628 629 err: 630 return ret ?: nbytes; 631 } 632 633 static void print_rpool_values(struct seq_file *sf, 634 struct rdmacg_resource_pool *rpool) 635 { 636 enum rdmacg_file_type sf_type; 637 int i; 638 u32 value; 639 640 sf_type = seq_cft(sf)->private; 641 642 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) { 643 seq_puts(sf, rdmacg_resource_names[i]); 644 seq_putc(sf, '='); 645 if (sf_type == RDMACG_RESOURCE_TYPE_MAX) { 646 if (rpool) 647 value = rpool->resources[i].max; 648 else 649 value = S32_MAX; 650 } else if (sf_type == RDMACG_RESOURCE_TYPE_PEAK) { 651 value = rpool ? rpool->resources[i].peak : 0; 652 } else { 653 if (rpool) 654 value = rpool->resources[i].usage; 655 else 656 value = 0; 657 } 658 659 if (value == S32_MAX) 660 seq_puts(sf, RDMACG_MAX_STR); 661 else 662 seq_printf(sf, "%d", value); 663 seq_putc(sf, ' '); 664 } 665 } 666 667 static int rdmacg_resource_read(struct seq_file *sf, void *v) 668 { 669 struct rdmacg_device *device; 670 struct rdmacg_resource_pool *rpool; 671 struct rdma_cgroup *cg = css_rdmacg(seq_css(sf)); 672 673 mutex_lock(&rdmacg_mutex); 674 675 list_for_each_entry(device, &rdmacg_devices, dev_node) { 676 rdmacg_print_device_key(sf, device); 677 678 rpool = find_cg_rpool_locked(cg, device); 679 print_rpool_values(sf, rpool); 680 681 seq_putc(sf, '\n'); 682 } 683 684 mutex_unlock(&rdmacg_mutex); 685 return 0; 686 } 687 688 static int rdmacg_events_show(struct seq_file *sf, void *v) 689 { 690 struct rdma_cgroup *cg = css_rdmacg(seq_css(sf)); 691 struct rdmacg_resource_pool *rpool; 692 struct rdmacg_device *device; 693 int i; 694 695 mutex_lock(&rdmacg_mutex); 696 697 list_for_each_entry(device, &rdmacg_devices, dev_node) { 698 rpool = find_cg_rpool_locked(cg, device); 699 700 rdmacg_print_device_key(sf, device); 701 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) { 702 seq_printf(sf, "%s.max=%llu %s.alloc_fail=%llu", 703 rdmacg_resource_names[i], 704 rpool ? rpool->events_max[i] : 0ULL, 705 rdmacg_resource_names[i], 706 rpool ? rpool->events_alloc_fail[i] : 0ULL); 707 if (i < RDMACG_RESOURCE_MAX - 1) 708 seq_putc(sf, ' '); 709 } 710 seq_putc(sf, '\n'); 711 } 712 713 mutex_unlock(&rdmacg_mutex); 714 return 0; 715 } 716 717 static int rdmacg_events_local_show(struct seq_file *sf, void *v) 718 { 719 struct rdma_cgroup *cg = css_rdmacg(seq_css(sf)); 720 struct rdmacg_resource_pool *rpool; 721 struct rdmacg_device *device; 722 int i; 723 724 mutex_lock(&rdmacg_mutex); 725 726 list_for_each_entry(device, &rdmacg_devices, dev_node) { 727 rpool = find_cg_rpool_locked(cg, device); 728 729 rdmacg_print_device_key(sf, device); 730 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) { 731 seq_printf(sf, "%s.max=%llu %s.alloc_fail=%llu", 732 rdmacg_resource_names[i], 733 rpool ? rpool->events_local_max[i] : 0ULL, 734 rdmacg_resource_names[i], 735 rpool ? rpool->events_local_alloc_fail[i] : 0ULL); 736 if (i < RDMACG_RESOURCE_MAX - 1) 737 seq_putc(sf, ' '); 738 } 739 seq_putc(sf, '\n'); 740 } 741 742 mutex_unlock(&rdmacg_mutex); 743 return 0; 744 } 745 746 static struct cftype rdmacg_files[] = { 747 { 748 .name = "max", 749 .write = rdmacg_resource_set_max, 750 .seq_show = rdmacg_resource_read, 751 .private = RDMACG_RESOURCE_TYPE_MAX, 752 .flags = CFTYPE_NOT_ON_ROOT, 753 }, 754 { 755 .name = "current", 756 .seq_show = rdmacg_resource_read, 757 .private = RDMACG_RESOURCE_TYPE_STAT, 758 .flags = CFTYPE_NOT_ON_ROOT, 759 }, 760 { 761 .name = "peak", 762 .seq_show = rdmacg_resource_read, 763 .private = RDMACG_RESOURCE_TYPE_PEAK, 764 .flags = CFTYPE_NOT_ON_ROOT, 765 }, 766 { 767 .name = "events", 768 .seq_show = rdmacg_events_show, 769 .file_offset = offsetof(struct rdma_cgroup, events_file), 770 .flags = CFTYPE_NOT_ON_ROOT, 771 }, 772 { 773 .name = "events.local", 774 .seq_show = rdmacg_events_local_show, 775 .file_offset = offsetof(struct rdma_cgroup, events_local_file), 776 .flags = CFTYPE_NOT_ON_ROOT, 777 }, 778 { } /* terminate */ 779 }; 780 781 static struct cgroup_subsys_state * 782 rdmacg_css_alloc(struct cgroup_subsys_state *parent) 783 { 784 struct rdma_cgroup *cg; 785 786 cg = kzalloc_obj(*cg); 787 if (!cg) 788 return ERR_PTR(-ENOMEM); 789 790 INIT_LIST_HEAD(&cg->rpools); 791 return &cg->css; 792 } 793 794 static void rdmacg_css_free(struct cgroup_subsys_state *css) 795 { 796 struct rdma_cgroup *cg = css_rdmacg(css); 797 struct rdmacg_resource_pool *rpool, *tmp; 798 799 /* Clean up rpools kept alive by non-zero peak values */ 800 mutex_lock(&rdmacg_mutex); 801 list_for_each_entry_safe(rpool, tmp, &cg->rpools, cg_node) 802 free_cg_rpool_locked(rpool); 803 mutex_unlock(&rdmacg_mutex); 804 805 kfree(cg); 806 } 807 808 /** 809 * rdmacg_css_offline - cgroup css_offline callback 810 * @css: css of interest 811 * 812 * This function is called when @css is about to go away and responsible 813 * for shooting down all rdmacg associated with @css. As part of that it 814 * marks all the resource pool entries to max value, so that when resources are 815 * uncharged, associated resource pool can be freed as well. 816 */ 817 static void rdmacg_css_offline(struct cgroup_subsys_state *css) 818 { 819 struct rdma_cgroup *cg = css_rdmacg(css); 820 struct rdmacg_resource_pool *rpool; 821 822 mutex_lock(&rdmacg_mutex); 823 824 list_for_each_entry(rpool, &cg->rpools, cg_node) 825 set_all_resource_max_limit(rpool); 826 827 mutex_unlock(&rdmacg_mutex); 828 } 829 830 struct cgroup_subsys rdma_cgrp_subsys = { 831 .css_alloc = rdmacg_css_alloc, 832 .css_free = rdmacg_css_free, 833 .css_offline = rdmacg_css_offline, 834 .legacy_cftypes = rdmacg_files, 835 .dfl_cftypes = rdmacg_files, 836 }; 837