History

Merge tag 'perf-urgent-2023-10-21' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf events fix from Ingo Molnar: "Fix group event semantics" * tag 'perf-urgent-2023-10-21' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: perf: Disallow mis-matched inherited group reads

Linus Torvalds committed 3 years ago

Commit 94be1332 parents 023cc83 32671e32 files · +34 −6Browse files

Unified · Split

2 files
  1. include/linux/perf_event.h +1 −0
  2. kernel/events/core.c +33 −6
include/linux/perf_event.h+1−0
@@ -704,6 +704,7 @@ struct perf_event { · 703 unmodified lines
704 /* The cumulative AND of all event_caps for events in this group. */704 /* The cumulative AND of all event_caps for events in this group. */
705 int group_caps;705 int group_caps;
706 706
707 unsigned int group_generation;
707 struct perf_event *group_leader;708 struct perf_event *group_leader;
708 /*709 /*
709 * event->pmu will always point to pmu in which this event belongs.710 * event->pmu will always point to pmu in which this event belongs.
kernel/events/core.c+33−6
@@ -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 siblings5484 * 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
5515unlock:
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
5490static int perf_read_group(struct perf_event *event,5520static 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