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

Showing the changes to kernel (1 of 2 files). Show all

Unified · Split

kernel/cgroup/rdma.c+107−36
@@ -82,8 +82,11 @@ struct rdmacg_resource_pool { · 81 unmodified lines
8282 /* total number counts which are set to max */
8383 int num_max_cnt;
8484
85− /* per-resource hierarchical max event counters */
85+ /* per-resource event counters */
8686 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];
8790 };
8891
8992 static 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
131134 kfree(rpool);
132135 }
133136
137+static 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+
134157 static struct rdmacg_resource_pool *
135158 find_cg_rpool_locked(struct rdma_cgroup *cg,
136159 struct rdmacg_device *device)
@@ -209,37 +232,30 @@ uncharge_cg_locked(struct rdma_cgroup *cg, · 72 unmodified lines
209232 rpool->usage_sum--;
210233 if (rpool->usage_sum == 0 &&
211234 rpool->num_max_cnt == RDMACG_RESOURCE_MAX) {
212− int i;
213−
214− /*
215− * Keep the rpool alive if any peak value is non-zero,
216− * so that rdma.peak persists as a historical high-
217− * watermark even after all resources are freed.
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;
235+ if (!rpool_has_persistent_state(rpool)) {
236+ /*
237+ * No user of the rpool and all entries are set to max, so
238+ * safe to delete this rpool.
239+ */
240+ free_cg_rpool_locked(rpool);
223241 }
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);
229242 }
230243 }
231244
232245 /**
233− * rdmacg_event_locked - fire hierarchical max event when resource limit is hit
246+ * rdmacg_event_locked - fire event when resource allocation exceeds limit
247+ * @cg: requesting cgroup
234248 * @over_cg: cgroup whose limit was exceeded
235249 * @device: rdma device
236250 * @index: resource type index
237251 *
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.
252+ * Must be called under rdmacg_mutex. Updates event counters in the
253+ * resource pools of @cg and @over_cg, propagates hierarchical max
254+ * events from @over_cg (including itself) upward, and notifies
255+ * userspace via cgroup_file_notify().
241256 */
242−static void rdmacg_event_locked(struct rdma_cgroup *over_cg,
257+static void rdmacg_event_locked(struct rdma_cgroup *cg,
258+ struct rdma_cgroup *over_cg,
243259 struct rdmacg_device *device,
244260 enum rdmacg_resource_type index)
245261 {
@@ -248,6 +264,21 @@ static void rdmacg_event_locked(struct rdma_cgroup *over_cg, · 2 unmodified lines
248264
249265 lockdep_assert_held(&rdmacg_mutex);
250266
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 */
251282 for (p = over_cg; parent_rdmacg(p); p = parent_rdmacg(p)) {
252283 rpool = get_cg_rpool_locked(p, device);
253284 if (!IS_ERR(rpool)) {
@@ -255,6 +286,14 @@ static void rdmacg_event_locked(struct rdma_cgroup *over_cg, · 1 unmodified line
255286 cgroup_file_notify(&p->events_file);
256287 }
257288 }
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+ }
258297 }
259298
260299 /**
@@ -368,7 +407,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, · 107 unmodified lines
368407
369408 err:
370409 if (ret == -EAGAIN)
371− rdmacg_event_locked(p, device, index);
410+ rdmacg_event_locked(cg, p, device, index);
372411 mutex_unlock(&rdmacg_mutex);
373412 rdmacg_uncharge_hierarchy(cg, device, p, index);
374413 return ret;
@@ -525,18 +564,13 @@ static ssize_t rdmacg_resource_set_max(struct kernfs_open_file *of, · 150 unmodified lines
525564
526565 if (rpool->usage_sum == 0 &&
527566 rpool->num_max_cnt == RDMACG_RESOURCE_MAX) {
528− int i;
529−
530− for (i = 0; i < RDMACG_RESOURCE_MAX; i++) {
531− if (rpool->resources[i].peak ||
532− READ_ONCE(rpool->events_max[i]))
533− goto dev_err;
567+ if (!rpool_has_persistent_state(rpool)) {
568+ /*
569+ * No user of the rpool and all entries are set to max, so
570+ * safe to delete this rpool.
571+ */
572+ free_cg_rpool_locked(rpool);
534573 }
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);
540574 }
541575
542576 dev_err:
@@ -618,9 +652,40 @@ static int rdmacg_events_show(struct seq_file *sf, void *v) · 75 unmodified lines
618652
619653 seq_printf(sf, "%s ", device->name);
620654 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+
670+static 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,
622687 rdmacg_resource_names[i],
623− rpool ? READ_ONCE(rpool->events_max[i]) : 0ULL);
688+ rpool ? READ_ONCE(rpool->events_local_alloc_fail[i]) : 0ULL);
624689 if (i < RDMACG_RESOURCE_MAX - 1)
625690 seq_putc(sf, ' ');
626691 }
@@ -657,6 +722,12 @@ static struct cftype rdmacg_files[] = { · 30 unmodified lines
657722 .file_offset = offsetof(struct rdma_cgroup, events_file),
658723 .flags = CFTYPE_NOT_ON_ROOT,
659724 },
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+ },
660731 { } /* terminate */
661732 };
662733