Fix group event semantics.
Signed-off-by: Ingo Molnar <mingo@kernel.org> -----BEGIN PGP SIGNATURE----- iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmUz7FURHG1pbmdvQGtl cm5lbC5vcmcACgkQEnMQ0APhK1hUMA/+IrkxzylYcir2z1Jv1PKNvCDuPdvz8yMS k0p5FMimGMSN+IPS8XwAEvG9YdFxyjQNbFfFvx0wp1PMPb5+NQYT6rTbOzziwpBn 8EIx/Ebjt1HraaAhGholF5c4UVzmAPzNJO/x2VX5mtqJY8EekbGWtUVuXsVyO1hA E/0C4FWVQ6Y0ig60naZnm2b/Z1nCbIBw9fmIXqrnkdSrQnFb4uRW6owu1JGI0x1H a7i7X7GgUytoZR4z4PLkR+UwtCc/Hza6S/8zkEVUiYUAp1JbzKQn6+3vA58xoOtU zuoJimWA3ofntwiTAtL2qHRSLoPPRqPZRuBceYa5TtZjLHqe8dKgcj2YaqleTFqZ 3NelYg1QMKjs35k2M+vAU5I5fZSU/cgyMK2Z4MFKm+XleDO575vffOSDXgyIs272 7iCLx7VNmT8ubijhFjNCi0xz6HBk/wml41XlzgLg2rzcVmwVjXqp+IfTP7QF4UW8 wmIWV/JZE4DOIuJp/dwQDicVEkr5XxUd39tlyGWD0GqXEQJDIe9Cb8cW+nBesIT7 j2lwHaxxxQB9AhJE3jfK7fBn/+LxqNAsPt6SEvdf1BqHWMSGmdTT3NKw3gwquqru 3OO6utMWPgJ/mGa7exbl/9gB4wIiCVTH1dsDRMBcnxgDg0e3d8UM/PdRys18q7YU g4zAKSFkzCw= =xyU0 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
94be133fb2
@ -704,6 +704,7 @@ struct perf_event {
|
|||||||
/* The cumulative AND of all event_caps for events in this group. */
|
/* The cumulative AND of all event_caps for events in this group. */
|
||||||
int group_caps;
|
int group_caps;
|
||||||
|
|
||||||
|
unsigned int group_generation;
|
||||||
struct perf_event *group_leader;
|
struct perf_event *group_leader;
|
||||||
/*
|
/*
|
||||||
* event->pmu will always point to pmu in which this event belongs.
|
* event->pmu will always point to pmu in which this event belongs.
|
||||||
|
@ -1954,6 +1954,7 @@ static void perf_group_attach(struct perf_event *event)
|
|||||||
|
|
||||||
list_add_tail(&event->sibling_list, &group_leader->sibling_list);
|
list_add_tail(&event->sibling_list, &group_leader->sibling_list);
|
||||||
group_leader->nr_siblings++;
|
group_leader->nr_siblings++;
|
||||||
|
group_leader->group_generation++;
|
||||||
|
|
||||||
perf_event__header_size(group_leader);
|
perf_event__header_size(group_leader);
|
||||||
|
|
||||||
@ -2144,6 +2145,7 @@ static void perf_group_detach(struct perf_event *event)
|
|||||||
if (leader != event) {
|
if (leader != event) {
|
||||||
list_del_init(&event->sibling_list);
|
list_del_init(&event->sibling_list);
|
||||||
event->group_leader->nr_siblings--;
|
event->group_leader->nr_siblings--;
|
||||||
|
event->group_leader->group_generation++;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5440,7 +5442,7 @@ static int __perf_read_group_add(struct perf_event *leader,
|
|||||||
u64 read_format, u64 *values)
|
u64 read_format, u64 *values)
|
||||||
{
|
{
|
||||||
struct perf_event_context *ctx = leader->ctx;
|
struct perf_event_context *ctx = leader->ctx;
|
||||||
struct perf_event *sub;
|
struct perf_event *sub, *parent;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int n = 1; /* skip @nr */
|
int n = 1; /* skip @nr */
|
||||||
int ret;
|
int ret;
|
||||||
@ -5450,6 +5452,33 @@ static int __perf_read_group_add(struct perf_event *leader,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&ctx->lock, flags);
|
raw_spin_lock_irqsave(&ctx->lock, flags);
|
||||||
|
/*
|
||||||
|
* Verify the grouping between the parent and child (inherited)
|
||||||
|
* events is still in tact.
|
||||||
|
*
|
||||||
|
* Specifically:
|
||||||
|
* - leader->ctx->lock pins leader->sibling_list
|
||||||
|
* - parent->child_mutex pins parent->child_list
|
||||||
|
* - parent->ctx->mutex pins parent->sibling_list
|
||||||
|
*
|
||||||
|
* Because parent->ctx != leader->ctx (and child_list nests inside
|
||||||
|
* ctx->mutex), group destruction is not atomic between children, also
|
||||||
|
* see perf_event_release_kernel(). Additionally, parent can grow the
|
||||||
|
* group.
|
||||||
|
*
|
||||||
|
* Therefore it is possible to have parent and child groups in a
|
||||||
|
* different configuration and summing over such a beast makes no sense
|
||||||
|
* what so ever.
|
||||||
|
*
|
||||||
|
* Reject this.
|
||||||
|
*/
|
||||||
|
parent = leader->parent;
|
||||||
|
if (parent &&
|
||||||
|
(parent->group_generation != leader->group_generation ||
|
||||||
|
parent->nr_siblings != leader->nr_siblings)) {
|
||||||
|
ret = -ECHILD;
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we co-schedule groups, {enabled,running} times of siblings
|
* Since we co-schedule groups, {enabled,running} times of siblings
|
||||||
@ -5483,8 +5512,9 @@ static int __perf_read_group_add(struct perf_event *leader,
|
|||||||
values[n++] = atomic64_read(&sub->lost_samples);
|
values[n++] = atomic64_read(&sub->lost_samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unlock:
|
||||||
raw_spin_unlock_irqrestore(&ctx->lock, flags);
|
raw_spin_unlock_irqrestore(&ctx->lock, flags);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_read_group(struct perf_event *event,
|
static int perf_read_group(struct perf_event *event,
|
||||||
@ -5503,10 +5533,6 @@ static int perf_read_group(struct perf_event *event,
|
|||||||
|
|
||||||
values[0] = 1 + leader->nr_siblings;
|
values[0] = 1 + leader->nr_siblings;
|
||||||
|
|
||||||
/*
|
|
||||||
* By locking the child_mutex of the leader we effectively
|
|
||||||
* lock the child list of all siblings.. XXX explain how.
|
|
||||||
*/
|
|
||||||
mutex_lock(&leader->child_mutex);
|
mutex_lock(&leader->child_mutex);
|
||||||
|
|
||||||
ret = __perf_read_group_add(leader, read_format, values);
|
ret = __perf_read_group_add(leader, read_format, values);
|
||||||
@ -13346,6 +13372,7 @@ static int inherit_group(struct perf_event *parent_event,
|
|||||||
!perf_get_aux_event(child_ctr, leader))
|
!perf_get_aux_event(child_ctr, leader))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
leader->group_generation = parent_event->group_generation;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user