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
2424 * that belongs to this cgroup.
2525 */
2626 struct list_head rpools;
27+
28+ /* Handle for rdma.events */
29+ struct cgroup_file events_file;
2730 };
2831
2932 struct rdmacg_device {
kernel/cgroup/rdma.c+70−2
@@ -81,6 +81,9 @@ struct rdmacg_resource_pool { · 80 unmodified lines
8181 u64 usage_sum;
8282 /* total number counts which are set to max */
8383 int num_max_cnt;
84+
85+ /* per-resource hierarchical max event counters */
86+ u64 events_max[RDMACG_RESOURCE_MAX];
8487 };
8588
8689 static struct rdma_cgroup *css_rdmacg(struct cgroup_subsys_state *css)
@@ -214,7 +217,8 @@ uncharge_cg_locked(struct rdma_cgroup *cg, · 127 unmodified lines
214217 * watermark even after all resources are freed.
215218 */
216219 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]))
218222 return;
219223 }
220224 /*
@@ -225,6 +229,34 @@ uncharge_cg_locked(struct rdma_cgroup *cg, · 4 unmodified lines
225229 }
226230 }
227231
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+ */
242+static 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+
228260 /**
229261 * rdmacg_uncharge_hierarchy - hierarchically uncharge rdma resource count
230262 * @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
335367 return 0;
336368
337369 err:
370+ if (ret == -EAGAIN)
371+ rdmacg_event_locked(p, device, index);
338372 mutex_unlock(&rdmacg_mutex);
339373 rdmacg_uncharge_hierarchy(cg, device, p, index);
340374 return ret;
@@ -494,7 +528,8 @@ static ssize_t rdmacg_resource_set_max(struct kernfs_open_file *of, · 153 unmodified lines
494528 int i;
495529
496530 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]))
498533 goto dev_err;
499534 }
500535 /*
@@ -569,6 +604,33 @@ static int rdmacg_resource_read(struct seq_file *sf, void *v) · 68 unmodified lines
569604 return 0;
570605 }
571606
607+static 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+
572634 static struct cftype rdmacg_files[] = {
573635 {
574636 .name = "max",
@@ -589,6 +651,12 @@ static struct cftype rdmacg_files[] = { · 14 unmodified lines
589651 .private = RDMACG_RESOURCE_TYPE_PEAK,
590652 .flags = CFTYPE_NOT_ON_ROOT,
591653 },
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+ },
592660 { } /* terminate */
593661 };
594662