projects/linux·blob master · refs

836 lines · 21.4 KiB

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 <[email protected]>
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
21enum 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
30static 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 */
43static DEFINE_MUTEX(rdmacg_mutex);
44static LIST_HEAD(rdmacg_devices);
45
46enum 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 */
57static 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 */
63struct 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 */
75struct 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
94static struct rdma_cgroup *css_rdmacg(struct cgroup_subsys_state *css)
95{
96 return container_of(css, struct rdma_cgroup, css);
97}
98
99static struct rdma_cgroup *parent_rdmacg(struct rdma_cgroup *cg)
100{
101 return css_rdmacg(cg->css.parent);
102}
103
104static inline struct rdma_cgroup *get_current_rdmacg(void)
105{
106 return css_rdmacg(task_get_css(current, rdma_cgrp_id));
107}
108
109static 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
122static 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
130static 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
139static 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
159static struct rdmacg_resource_pool *
160find_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
175static struct rdmacg_resource_pool *
176get_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 */
208static void
209uncharge_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 */
259static 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 */
309static 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 */
332void 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}
341EXPORT_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 */
364int 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
410err:
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}
417EXPORT_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 */
427void 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}
436EXPORT_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 */
447void 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}
467EXPORT_SYMBOL(rdmacg_unregister_device);
468
469static struct rdmacg_device *
470rdmacg_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
495static bool
496rdmacg_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
509static 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
518static 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
623dev_err:
624 mutex_unlock(&rdmacg_mutex);
625
626parse_err:
627 kfree(new_limits);
628
629err:
630 return ret ?: nbytes;
631}
632
633static 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
667static 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
688static 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
717static 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
746static 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
781static struct cgroup_subsys_state *
782rdmacg_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
794static 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 */
817static 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
830struct 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};