Skip to content

Commit 961c391

Browse files
James-A-ClarkPeter Zijlstra
authored andcommitted
perf: Always wake the parent event
When using per-process mode and event inheritance is set to true, forked processes will create a new perf events via inherit_event() -> perf_event_alloc(). But these events will not have ring buffers assigned to them. Any call to wakeup will be dropped if it's called on an event with no ring buffer assigned because that's the object that holds the wakeup list. If the child event is disabled due to a call to perf_aux_output_begin() or perf_aux_output_end(), the wakeup is dropped leaving userspace hanging forever on the poll. Normally the event is explicitly re-enabled by userspace after it wakes up to read the aux data, but in this case it does not get woken up so the event remains disabled. This can be reproduced when using Arm SPE and 'stress' which forks once before running the workload. By looking at the list of aux buffers read, it's apparent that they stop after the fork: perf record -e arm_spe// -vvv -- stress -c 1 With this patch applied they continue to be printed. This behaviour doesn't happen when using systemwide or per-cpu mode. Reported-by: Ruben Ayrapetyan <[email protected]> Signed-off-by: James Clark <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 8c16dc0 commit 961c391

File tree

1 file changed

+10
-2
lines changed

1 file changed

+10
-2
lines changed

kernel/events/core.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5985,6 +5985,8 @@ static void ring_buffer_attach(struct perf_event *event,
59855985
struct perf_buffer *old_rb = NULL;
59865986
unsigned long flags;
59875987

5988+
WARN_ON_ONCE(event->parent);
5989+
59885990
if (event->rb) {
59895991
/*
59905992
* Should be impossible, we set this when removing
@@ -6042,6 +6044,9 @@ static void ring_buffer_wakeup(struct perf_event *event)
60426044
{
60436045
struct perf_buffer *rb;
60446046

6047+
if (event->parent)
6048+
event = event->parent;
6049+
60456050
rcu_read_lock();
60466051
rb = rcu_dereference(event->rb);
60476052
if (rb) {
@@ -6055,6 +6060,9 @@ struct perf_buffer *ring_buffer_get(struct perf_event *event)
60556060
{
60566061
struct perf_buffer *rb;
60576062

6063+
if (event->parent)
6064+
event = event->parent;
6065+
60586066
rcu_read_lock();
60596067
rb = rcu_dereference(event->rb);
60606068
if (rb) {
@@ -6763,7 +6771,7 @@ static unsigned long perf_prepare_sample_aux(struct perf_event *event,
67636771
if (WARN_ON_ONCE(READ_ONCE(sampler->oncpu) != smp_processor_id()))
67646772
goto out;
67656773

6766-
rb = ring_buffer_get(sampler->parent ? sampler->parent : sampler);
6774+
rb = ring_buffer_get(sampler);
67676775
if (!rb)
67686776
goto out;
67696777

@@ -6829,7 +6837,7 @@ static void perf_aux_sample_output(struct perf_event *event,
68296837
if (WARN_ON_ONCE(!sampler || !data->aux_size))
68306838
return;
68316839

6832-
rb = ring_buffer_get(sampler->parent ? sampler->parent : sampler);
6840+
rb = ring_buffer_get(sampler);
68336841
if (!rb)
68346842
return;
68356843

0 commit comments

Comments
 (0)