History

cgroup/rdma: add rdma.events to track resource limit exhaustion

Add per-device hierarchical event counters to track when RDMA resource limits are exceeded. The rdma.events file reports max event counts propagated upward from the cgroup whose limit was hit to all ancestors. This mirrors the design of pids.events, where events are attributed to the cgroup that imposed the limit, not necessarily the cgroup where the allocation was attempted. Userspace can monitor this file via poll/epoll for real-time notification of resource exhaustion.

Tao Cui committed 6 months ago

Commit 009bcbd1 parent c68095c2 files · +73 −2Browse files

Unified · Split

2 files
  1. include/linux/cgroup_rdma.h +3 −0
  2. kernel/cgroup/rdma.c +70 −2
include/linux/cgroup_rdma.h+3−0
@@ -24,6 +24,9 @@ struct rdma_cgroup { · 23 unmodified lines
24 * that belongs to this cgroup.24 * that belongs to this cgroup.
25 */25 */
26 struct list_head rpools;26 struct list_head rpools;
27
28 /* Handle for rdma.events */
29 struct cgroup_file events_file;
27};30};
28 31
29struct rdmacg_device {32struct rdmacg_device {
kernel/cgroup/rdma.c+70−2
@@ -81,6 +81,9 @@ struct rdmacg_resource_pool { · 80 unmodified lines
81 u64 usage_sum;81 u64 usage_sum;
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
85 /* per-resource hierarchical max event counters */
86 u64 events_max[RDMACG_RESOURCE_MAX];
84};87};
85 88
86static struct rdma_cgroup *css_rdmacg(struct cgroup_subsys_state *css)89static struct rdma_cgroup *css_rdmacg(struct cgroup_subsys_state *css)
@@ -214,7 +217,8 @@ uncharge_cg_locked(struct rdma_cgroup *cg, · 127 unmodified lines
214 * watermark even after all resources are freed.217 * watermark even after all resources are freed.
215 */218 */
216 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {219 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
217 if (rpool->resources[i].peak)220 if (rpool->resources[i].peak ||
221 READ_ONCE(rpool->events_max[i]))
218 return;222 return;
219 }223 }
220 /*224 /*
@@ -225,6 +229,34 @@ uncharge_cg_locked(struct rdma_cgroup *cg, · 4 unmodified lines
225 }229 }
226}230}
227 231
232/**
233 * rdmacg_event_locked - fire hierarchical max event when resource limit is hit
234 * @over_cg: cgroup whose limit was exceeded
235 * @device: rdma device
236 * @index: resource type index
237 *
238 * Must be called under rdmacg_mutex. Propagates max event counts
239 * from @over_cg (including itself) upward to all ancestors with
240 * an rpool and notifies userspace.
241 */
242static void rdmacg_event_locked(struct rdma_cgroup *over_cg,
243 struct rdmacg_device *device,
244 enum rdmacg_resource_type index)
245{
246 struct rdmacg_resource_pool *rpool;
247 struct rdma_cgroup *p;
248
249 lockdep_assert_held(&rdmacg_mutex);
250
251 for (p = over_cg; parent_rdmacg(p); p = parent_rdmacg(p)) {
252 rpool = get_cg_rpool_locked(p, device);
253 if (!IS_ERR(rpool)) {
254 rpool->events_max[index]++;
255 cgroup_file_notify(&p->events_file);
256 }
257 }
258}
259
228/**260/**
229 * rdmacg_uncharge_hierarchy - hierarchically uncharge rdma resource count261 * rdmacg_uncharge_hierarchy - hierarchically uncharge rdma resource count
230 * @cg: pointer to cg to uncharge and all parents in hierarchy262 * @cg: pointer to cg to uncharge and all parents in hierarchy
@@ -335,6 +367,8 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, · 104 unmodified lines
335 return 0;367 return 0;
336 368
337err:369err:
370 if (ret == -EAGAIN)
371 rdmacg_event_locked(p, device, index);
338 mutex_unlock(&rdmacg_mutex);372 mutex_unlock(&rdmacg_mutex);
339 rdmacg_uncharge_hierarchy(cg, device, p, index);373 rdmacg_uncharge_hierarchy(cg, device, p, index);
340 return ret;374 return ret;
@@ -494,7 +528,8 @@ static ssize_t rdmacg_resource_set_max(struct kernfs_open_file *of, · 153 unmodified lines
494 int i;528 int i;
495 529
496 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {530 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
497 if (rpool->resources[i].peak)531 if (rpool->resources[i].peak ||
532 READ_ONCE(rpool->events_max[i]))
498 goto dev_err;533 goto dev_err;
499 }534 }
500 /*535 /*
@@ -569,6 +604,33 @@ static int rdmacg_resource_read(struct seq_file *sf, void *v) · 68 unmodified lines
569 return 0;604 return 0;
570}605}
571 606
607static int rdmacg_events_show(struct seq_file *sf, void *v)
608{
609 struct rdma_cgroup *cg = css_rdmacg(seq_css(sf));
610 struct rdmacg_resource_pool *rpool;
611 struct rdmacg_device *device;
612 int i;
613
614 mutex_lock(&rdmacg_mutex);
615
616 list_for_each_entry(device, &rdmacg_devices, dev_node) {
617 rpool = find_cg_rpool_locked(cg, device);
618
619 seq_printf(sf, "%s ", device->name);
620 for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
621 seq_printf(sf, "%s.max=%llu",
622 rdmacg_resource_names[i],
623 rpool ? READ_ONCE(rpool->events_max[i]) : 0ULL);
624 if (i < RDMACG_RESOURCE_MAX - 1)
625 seq_putc(sf, ' ');
626 }
627 seq_putc(sf, '\n');
628 }
629
630 mutex_unlock(&rdmacg_mutex);
631 return 0;
632}
633
572static struct cftype rdmacg_files[] = {634static struct cftype rdmacg_files[] = {
573 {635 {
574 .name = "max",636 .name = "max",
@@ -589,6 +651,12 @@ static struct cftype rdmacg_files[] = { · 14 unmodified lines
589 .private = RDMACG_RESOURCE_TYPE_PEAK,651 .private = RDMACG_RESOURCE_TYPE_PEAK,
590 .flags = CFTYPE_NOT_ON_ROOT,652 .flags = CFTYPE_NOT_ON_ROOT,
591 },653 },
654 {
655 .name = "events",
656 .seq_show = rdmacg_events_show,
657 .file_offset = offsetof(struct rdma_cgroup, events_file),
658 .flags = CFTYPE_NOT_ON_ROOT,
659 },
592 { } /* terminate */660 { } /* terminate */
593};661};
594 662