Merge branch 'perf/urgent' into perf/core, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
+25
-6
@@ -2497,11 +2497,11 @@ static int __perf_event_stop(void *info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perf_event_restart(struct perf_event *event)
|
||||
static int perf_event_stop(struct perf_event *event, int restart)
|
||||
{
|
||||
struct stop_event_data sd = {
|
||||
.event = event,
|
||||
.restart = 1,
|
||||
.restart = restart,
|
||||
};
|
||||
int ret = 0;
|
||||
|
||||
@@ -4874,6 +4874,19 @@ static void ring_buffer_attach(struct perf_event *event,
|
||||
spin_unlock_irqrestore(&rb->event_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Avoid racing with perf_mmap_close(AUX): stop the event
|
||||
* before swizzling the event::rb pointer; if it's getting
|
||||
* unmapped, its aux_mmap_count will be 0 and it won't
|
||||
* restart. See the comment in __perf_pmu_output_stop().
|
||||
*
|
||||
* Data will inevitably be lost when set_output is done in
|
||||
* mid-air, but then again, whoever does it like this is
|
||||
* not in for the data anyway.
|
||||
*/
|
||||
if (has_aux(event))
|
||||
perf_event_stop(event, 0);
|
||||
|
||||
rcu_assign_pointer(event->rb, rb);
|
||||
|
||||
if (old_rb) {
|
||||
@@ -6150,7 +6163,7 @@ static void perf_event_addr_filters_exec(struct perf_event *event, void *data)
|
||||
raw_spin_unlock_irqrestore(&ifh->lock, flags);
|
||||
|
||||
if (restart)
|
||||
perf_event_restart(event);
|
||||
perf_event_stop(event, 1);
|
||||
}
|
||||
|
||||
void perf_event_exec(void)
|
||||
@@ -6194,7 +6207,13 @@ static void __perf_event_output_stop(struct perf_event *event, void *data)
|
||||
|
||||
/*
|
||||
* In case of inheritance, it will be the parent that links to the
|
||||
* ring-buffer, but it will be the child that's actually using it:
|
||||
* ring-buffer, but it will be the child that's actually using it.
|
||||
*
|
||||
* We are using event::rb to determine if the event should be stopped,
|
||||
* however this may race with ring_buffer_attach() (through set_output),
|
||||
* which will make us skip the event that actually needs to be stopped.
|
||||
* So ring_buffer_attach() has to stop an aux event before re-assigning
|
||||
* its rb pointer.
|
||||
*/
|
||||
if (rcu_dereference(parent->rb) == rb)
|
||||
ro->err = __perf_event_stop(&sd);
|
||||
@@ -6708,7 +6727,7 @@ static void __perf_addr_filters_adjust(struct perf_event *event, void *data)
|
||||
raw_spin_unlock_irqrestore(&ifh->lock, flags);
|
||||
|
||||
if (restart)
|
||||
perf_event_restart(event);
|
||||
perf_event_stop(event, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7897,7 +7916,7 @@ static void perf_event_addr_filters_apply(struct perf_event *event)
|
||||
mmput(mm);
|
||||
|
||||
restart:
|
||||
perf_event_restart(event);
|
||||
perf_event_stop(event, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -330,15 +330,22 @@ void *perf_aux_output_begin(struct perf_output_handle *handle,
|
||||
if (!rb)
|
||||
return NULL;
|
||||
|
||||
if (!rb_has_aux(rb) || !atomic_inc_not_zero(&rb->aux_refcount))
|
||||
if (!rb_has_aux(rb))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* If rb::aux_mmap_count is zero (and rb_has_aux() above went through),
|
||||
* the aux buffer is in perf_mmap_close(), about to get freed.
|
||||
* If aux_mmap_count is zero, the aux buffer is in perf_mmap_close(),
|
||||
* about to get freed, so we leave immediately.
|
||||
*
|
||||
* Checking rb::aux_mmap_count and rb::refcount has to be done in
|
||||
* the same order, see perf_mmap_close. Otherwise we end up freeing
|
||||
* aux pages in this path, which is a bug, because in_atomic().
|
||||
*/
|
||||
if (!atomic_read(&rb->aux_mmap_count))
|
||||
goto err_put;
|
||||
goto err;
|
||||
|
||||
if (!atomic_inc_not_zero(&rb->aux_refcount))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Nesting is not supported for AUX area, make sure nested
|
||||
|
||||
Reference in New Issue
Block a user