History

cgroup/rdma: add rdma.events.local for per-cgroup allocation failure attribution

Add per-cgroup local event counters to track RDMA resource limit exhaustion from the perspective of individual cgroups. The rdma.events.local file reports two per-resource counters: - max: number of times this cgroup's limit was the one that blocked an allocation in the subtree - alloc_fail: number of allocation attempts originating from this cgroup that failed due to an ancestor's limit This mirrors the design of pids.events.local, where events are attributed to the cgroup that imposed the limit, not necessarily the cgroup where the allocation was attempted. Also extend rdma.events with a hierarchical alloc_fail counter that tracks allocation failures propagating upward from the requesting cgroup, complementing the existing max counter, so that rdma.events and rdma.events.local share the same output format.

Tao Cui committed 6 months ago

Commit aefe4841 parent 009bcbd2 files · +109 −37Browse files

Unified · Split

2 files
  1. include/linux/cgroup_rdma.h +2 −1
  2. kernel/cgroup/rdma.c +107 −36
include/linux/cgroup_rdma.h+2−1
@@ -25,8 +25,9 @@ struct rdma_cgroup { · 24 unmodified lines
25 */25 */
26 struct list_head rpools;26 struct list_head rpools;
27 27
28 /* Handle for rdma.events */28 /* Handles for rdma.events[.local] */
29 struct cgroup_file events_file;29 struct cgroup_file events_file;
30 struct cgroup_file events_local_file;
30};31};
31 32
32struct rdmacg_device {33struct rdmacg_device {
kernel/cgroup/rdma.c+107−36
@@ -82,8 +82,11 @@ struct rdmacg_resource_pool { · 81 unmodified lines
82 /* total number counts which are set to max */82 /* total number counts which are set to max */
83 int num_max_cnt;83 int num_max_cnt;
84 84
85 /* per-resource hierarchical max event counters */85 /* per-resource event counters */
86 u64 events_max[RDMACG_RESOURCE_MAX];86 u64 events_max[RDMACG_RESOURCE_MAX];
87 u64 events_alloc_fail[RDMACG_RESOURCE_MAX];
88 u64 events_local_max[RDMACG_RESOURCE_MAX];
89 u64 events_local_alloc_fail[RDMACG_RESOURCE_MAX];
87};90};
88 91
89static struct rdma_cgroup *css_rdmacg(struct cgroup_subsys_state *css)92static struct rdma_cgroup *css_rdmacg(struct cgroup_subsys_state *css)
@@ -131,6 +134,26 @@ static void free_cg_rpool_locked(struct rdmacg_resource_pool *rpool) · 41 unmodified lines
131 kfree(rpool);134 kfree(rpool);
132}135}
133 136
137static bool rpool_has_persistent_state(struct rdmacg_resource_pool *rpool)
138{
139 int i;
140
141 /*
142 * Keep the rpool alive if any peak value is non-zero,
143 * so that rdma.peak persists as a historical high-
144 * watermark even after all resources are freed.
145 */
146 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
147 if (rpool->resources[i].peak ||
148 READ_ONCE(rpool->events_max[i]) ||
149 READ_ONCE(rpool->events_local_max[i]) ||
150 READ_ONCE(rpool->events_alloc_fail[i]) ||
151 READ_ONCE(rpool->events_local_alloc_fail[i]))
152 return true;
153 }
154 return false;
155}
156
134static struct rdmacg_resource_pool *157static struct rdmacg_resource_pool *
135find_cg_rpool_locked(struct rdma_cgroup *cg,158find_cg_rpool_locked(struct rdma_cgroup *cg,
136 struct rdmacg_device *device)159 struct rdmacg_device *device)
@@ -209,37 +232,30 @@ uncharge_cg_locked(struct rdma_cgroup *cg, · 72 unmodified lines
209 rpool->usage_sum--;232 rpool->usage_sum--;
210 if (rpool->usage_sum == 0 &&233 if (rpool->usage_sum == 0 &&
211 rpool->num_max_cnt == RDMACG_RESOURCE_MAX) {234 rpool->num_max_cnt == RDMACG_RESOURCE_MAX) {
212 int i;235 if (!rpool_has_persistent_state(rpool)) {
213 236 /*
214 /*237 * No user of the rpool and all entries are set to max, so
215 * Keep the rpool alive if any peak value is non-zero,238 * safe to delete this rpool.
216 * so that rdma.peak persists as a historical high-239 */
217 * watermark even after all resources are freed.240 free_cg_rpool_locked(rpool);
218 */
219 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
220 if (rpool->resources[i].peak ||
221 READ_ONCE(rpool->events_max[i]))
222 return;
223 }241 }
224 /*
225 * No user of the rpool and all entries are set to max, so
226 * safe to delete this rpool.
227 */
228 free_cg_rpool_locked(rpool);
229 }242 }
230}243}
231 244
232/**245/**
233 * rdmacg_event_locked - fire hierarchical max event when resource limit is hit246 * rdmacg_event_locked - fire event when resource allocation exceeds limit
247 * @cg: requesting cgroup
234 * @over_cg: cgroup whose limit was exceeded248 * @over_cg: cgroup whose limit was exceeded
235 * @device: rdma device249 * @device: rdma device
236 * @index: resource type index250 * @index: resource type index
237 *251 *
238 * Must be called under rdmacg_mutex. Propagates max event counts252 * Must be called under rdmacg_mutex. Updates event counters in the
239 * from @over_cg (including itself) upward to all ancestors with253 * resource pools of @cg and @over_cg, propagates hierarchical max
240 * an rpool and notifies userspace.254 * events from @over_cg (including itself) upward, and notifies
255 * userspace via cgroup_file_notify().
241 */256 */
242static void rdmacg_event_locked(struct rdma_cgroup *over_cg,257static void rdmacg_event_locked(struct rdma_cgroup *cg,
258 struct rdma_cgroup *over_cg,
243 struct rdmacg_device *device,259 struct rdmacg_device *device,
244 enum rdmacg_resource_type index)260 enum rdmacg_resource_type index)
245{261{
@@ -248,6 +264,21 @@ static void rdmacg_event_locked(struct rdma_cgroup *over_cg, · 2 unmodified lines
248 264
249 lockdep_assert_held(&rdmacg_mutex);265 lockdep_assert_held(&rdmacg_mutex);
250 266
267 /* Increment local alloc_fail in requesting cgroup */
268 rpool = find_cg_rpool_locked(cg, device);
269 if (rpool) {
270 rpool->events_local_alloc_fail[index]++;
271 cgroup_file_notify(&cg->events_local_file);
272 }
273
274 /* Increment local max in the over-limit cgroup */
275 rpool = find_cg_rpool_locked(over_cg, device);
276 if (rpool) {
277 rpool->events_local_max[index]++;
278 cgroup_file_notify(&over_cg->events_local_file);
279 }
280
281 /* Propagate hierarchical max events upward */
251 for (p = over_cg; parent_rdmacg(p); p = parent_rdmacg(p)) {282 for (p = over_cg; parent_rdmacg(p); p = parent_rdmacg(p)) {
252 rpool = get_cg_rpool_locked(p, device);283 rpool = get_cg_rpool_locked(p, device);
253 if (!IS_ERR(rpool)) {284 if (!IS_ERR(rpool)) {
@@ -255,6 +286,14 @@ static void rdmacg_event_locked(struct rdma_cgroup *over_cg, · 1 unmodified line
255 cgroup_file_notify(&p->events_file);286 cgroup_file_notify(&p->events_file);
256 }287 }
257 }288 }
289 /* Propagate hierarchical alloc_fail from requesting cgroup upward */
290 for (p = cg; parent_rdmacg(p); p = parent_rdmacg(p)) {
291 rpool = get_cg_rpool_locked(p, device);
292 if (!IS_ERR(rpool)) {
293 rpool->events_alloc_fail[index]++;
294 cgroup_file_notify(&p->events_file);
295 }
296 }
258}297}
259 298
260/**299/**
@@ -368,7 +407,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, · 107 unmodified lines
368 407
369err:408err:
370 if (ret == -EAGAIN)409 if (ret == -EAGAIN)
371 rdmacg_event_locked(p, device, index);410 rdmacg_event_locked(cg, p, device, index);
372 mutex_unlock(&rdmacg_mutex);411 mutex_unlock(&rdmacg_mutex);
373 rdmacg_uncharge_hierarchy(cg, device, p, index);412 rdmacg_uncharge_hierarchy(cg, device, p, index);
374 return ret;413 return ret;
@@ -525,18 +564,13 @@ static ssize_t rdmacg_resource_set_max(struct kernfs_open_file *of, · 150 unmodified lines
525 564
526 if (rpool->usage_sum == 0 &&565 if (rpool->usage_sum == 0 &&
527 rpool->num_max_cnt == RDMACG_RESOURCE_MAX) {566 rpool->num_max_cnt == RDMACG_RESOURCE_MAX) {
528 int i;567 if (!rpool_has_persistent_state(rpool)) {
529 568 /*
530 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {569 * No user of the rpool and all entries are set to max, so
531 if (rpool->resources[i].peak ||570 * safe to delete this rpool.
532 READ_ONCE(rpool->events_max[i]))571 */
533 goto dev_err;572 free_cg_rpool_locked(rpool);
534 }573 }
535 /*
536 * No user of the rpool and all entries are set to max, so
537 * safe to delete this rpool.
538 */
539 free_cg_rpool_locked(rpool);
540 }574 }
541 575
542dev_err:576dev_err:
@@ -618,9 +652,40 @@ static int rdmacg_events_show(struct seq_file *sf, void *v) · 75 unmodified lines
618 652
619 seq_printf(sf, "%s ", device->name);653 seq_printf(sf, "%s ", device->name);
620 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {654 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
621 seq_printf(sf, "%s.max=%llu",655 seq_printf(sf, "%s.max=%llu %s.alloc_fail=%llu",
656 rdmacg_resource_names[i],
657 rpool ? READ_ONCE(rpool->events_max[i]) : 0ULL,
658 rdmacg_resource_names[i],
659 rpool ? READ_ONCE(rpool->events_alloc_fail[i]) : 0ULL);
660 if (i < RDMACG_RESOURCE_MAX - 1)
661 seq_putc(sf, ' ');
662 }
663 seq_putc(sf, '\n');
664 }
665
666 mutex_unlock(&rdmacg_mutex);
667 return 0;
668}
669
670static int rdmacg_events_local_show(struct seq_file *sf, void *v)
671{
672 struct rdma_cgroup *cg = css_rdmacg(seq_css(sf));
673 struct rdmacg_resource_pool *rpool;
674 struct rdmacg_device *device;
675 int i;
676
677 mutex_lock(&rdmacg_mutex);
678
679 list_for_each_entry(device, &rdmacg_devices, dev_node) {
680 rpool = find_cg_rpool_locked(cg, device);
681
682 seq_printf(sf, "%s ", device->name);
683 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
684 seq_printf(sf, "%s.max=%llu %s.alloc_fail=%llu",
685 rdmacg_resource_names[i],
686 rpool ? READ_ONCE(rpool->events_local_max[i]) : 0ULL,
622 rdmacg_resource_names[i],687 rdmacg_resource_names[i],
623 rpool ? READ_ONCE(rpool->events_max[i]) : 0ULL);688 rpool ? READ_ONCE(rpool->events_local_alloc_fail[i]) : 0ULL);
624 if (i < RDMACG_RESOURCE_MAX - 1)689 if (i < RDMACG_RESOURCE_MAX - 1)
625 seq_putc(sf, ' ');690 seq_putc(sf, ' ');
626 }691 }
@@ -657,6 +722,12 @@ static struct cftype rdmacg_files[] = { · 30 unmodified lines
657 .file_offset = offsetof(struct rdma_cgroup, events_file),722 .file_offset = offsetof(struct rdma_cgroup, events_file),
658 .flags = CFTYPE_NOT_ON_ROOT,723 .flags = CFTYPE_NOT_ON_ROOT,
659 },724 },
725 {
726 .name = "events.local",
727 .seq_show = rdmacg_events_local_show,
728 .file_offset = offsetof(struct rdma_cgroup, events_local_file),
729 .flags = CFTYPE_NOT_ON_ROOT,
730 },
660 { } /* terminate */731 { } /* terminate */
661};732};
662 733