Because group consistency is non-atomic between parent (filedesc) and children (inherited) events, it is possible for PERF_FORMAT_GROUP read() to try and sum non-matching counter groups -- with non-sensical results. Add group_generation to distinguish the case where a parent group removes and adds an event and thus has the same number, but a different configuration of events as inherited groups. This became a problem when commit fa8c269353d5 ("perf/core: Invert perf_read_group() loops") flipped the order of child_list and sibling_list. Previously it would iterate the group (sibling_list) first, and for each sibling traverse the child_list. In this order, only the group composition of the parent is relevant. By flipping the order the group composition of the child (inherited) events becomes an issue and the mis-match in group composition becomes evident. That said; even prior to this commit, while reading of a group that is not equally inherited was not broken, it still made no sense. (Ab)use ECHILD as error return to indicate issues with child process group composition.
Showing the changes to kernel (1 of 2 files). Show all
Unified · Split
| @@ -1954,6 +1954,7 @@ static void perf_group_attach(struct perf_event *event) · 1953 unmodified lines | |||
| 1954 | 1954 | ||
| 1955 | list_add_tail(&event->sibling_list, &group_leader->sibling_list); | 1955 | list_add_tail(&event->sibling_list, &group_leader->sibling_list); |
| 1956 | group_leader->nr_siblings++; | 1956 | group_leader->nr_siblings++; |
| 1957 | group_leader->group_generation++; | ||
| 1957 | 1958 | ||
| 1958 | perf_event__header_size(group_leader); | 1959 | perf_event__header_size(group_leader); |
| 1959 | 1960 | ||
| @@ -2144,6 +2145,7 @@ static void perf_group_detach(struct perf_event *event) · 184 unmodified lines | |||
| 2144 | if (leader != event) { | 2145 | if (leader != event) { |
| 2145 | list_del_init(&event->sibling_list); | 2146 | list_del_init(&event->sibling_list); |
| 2146 | event->group_leader->nr_siblings--; | 2147 | event->group_leader->nr_siblings--; |
| 2148 | event->group_leader->group_generation++; | ||
| 2147 | goto out; | 2149 | goto out; |
| 2148 | } | 2150 | } |
| 2149 | 2151 | ||
| @@ -5440,7 +5442,7 @@ static int __perf_read_group_add(struct perf_event *leader, · 3290 unmodified lines | |||
| 5440 | u64 read_format, u64 *values) | 5442 | u64 read_format, u64 *values) |
| 5441 | { | 5443 | { |
| 5442 | struct perf_event_context *ctx = leader->ctx; | 5444 | struct perf_event_context *ctx = leader->ctx; |
| 5443 | struct perf_event *sub; | 5445 | struct perf_event *sub, *parent; |
| 5444 | unsigned long flags; | 5446 | unsigned long flags; |
| 5445 | int n = 1; /* skip @nr */ | 5447 | int n = 1; /* skip @nr */ |
| 5446 | int ret; | 5448 | int ret; |
| @@ -5450,6 +5452,33 @@ static int __perf_read_group_add(struct perf_event *leader, · 3 unmodified lines | |||
| 5450 | return ret; | 5452 | return ret; |
| 5451 | 5453 | ||
| 5452 | raw_spin_lock_irqsave(&ctx->lock, flags); | 5454 | raw_spin_lock_irqsave(&ctx->lock, flags); |
| 5455 | /* | ||
| 5456 | * Verify the grouping between the parent and child (inherited) | ||
| 5457 | * events is still in tact. | ||
| 5458 | * | ||
| 5459 | * Specifically: | ||
| 5460 | * - leader->ctx->lock pins leader->sibling_list | ||
| 5461 | * - parent->child_mutex pins parent->child_list | ||
| 5462 | * - parent->ctx->mutex pins parent->sibling_list | ||
| 5463 | * | ||
| 5464 | * Because parent->ctx != leader->ctx (and child_list nests inside | ||
| 5465 | * ctx->mutex), group destruction is not atomic between children, also | ||
| 5466 | * see perf_event_release_kernel(). Additionally, parent can grow the | ||
| 5467 | * group. | ||
| 5468 | * | ||
| 5469 | * Therefore it is possible to have parent and child groups in a | ||
| 5470 | * different configuration and summing over such a beast makes no sense | ||
| 5471 | * what so ever. | ||
| 5472 | * | ||
| 5473 | * Reject this. | ||
| 5474 | */ | ||
| 5475 | parent = leader->parent; | ||
| 5476 | if (parent && | ||
| 5477 | (parent->group_generation != leader->group_generation || | ||
| 5478 | parent->nr_siblings != leader->nr_siblings)) { | ||
| 5479 | ret = -ECHILD; | ||
| 5480 | goto unlock; | ||
| 5481 | } | ||
| 5453 | 5482 | ||
| 5454 | /* | 5483 | /* |
| 5455 | * Since we co-schedule groups, {enabled,running} times of siblings | 5484 | * Since we co-schedule groups, {enabled,running} times of siblings |
| @@ -5483,8 +5512,9 @@ static int __perf_read_group_add(struct perf_event *leader, · 27 unmodified lines | |||
| 5483 | values[n++] = atomic64_read(&sub->lost_samples); | 5512 | values[n++] = atomic64_read(&sub->lost_samples); |
| 5484 | } | 5513 | } |
| 5485 | 5514 | ||
| 5515 | unlock: | ||
| 5486 | raw_spin_unlock_irqrestore(&ctx->lock, flags); | 5516 | raw_spin_unlock_irqrestore(&ctx->lock, flags); |
| 5487 | return 0; | 5517 | return ret; |
| 5488 | } | 5518 | } |
| 5489 | 5519 | ||
| 5490 | static int perf_read_group(struct perf_event *event, | 5520 | static int perf_read_group(struct perf_event *event, |
| @@ -5503,10 +5533,6 @@ static int perf_read_group(struct perf_event *event, · 12 unmodified lines | |||
| 5503 | 5533 | ||
| 5504 | values[0] = 1 + leader->nr_siblings; | 5534 | values[0] = 1 + leader->nr_siblings; |
| 5505 | 5535 | ||
| 5506 | /* | ||
| 5507 | * By locking the child_mutex of the leader we effectively | ||
| 5508 | * lock the child list of all siblings.. XXX explain how. | ||
| 5509 | */ | ||
| 5510 | mutex_lock(&leader->child_mutex); | 5536 | mutex_lock(&leader->child_mutex); |
| 5511 | 5537 | ||
| 5512 | ret = __perf_read_group_add(leader, read_format, values); | 5538 | ret = __perf_read_group_add(leader, read_format, values); |
| @@ -13346,6 +13372,7 @@ static int inherit_group(struct perf_event *parent_event, · 7833 unmodified lines | |||
| 13346 | !perf_get_aux_event(child_ctr, leader)) | 13372 | !perf_get_aux_event(child_ctr, leader)) |
| 13347 | return -EINVAL; | 13373 | return -EINVAL; |
| 13348 | } | 13374 | } |
| 13375 | leader->group_generation = parent_event->group_generation; | ||
| 13349 | return 0; | 13376 | return 0; |
| 13350 | } | 13377 | } |
| 13351 | 13378 | ||