Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Thomas Gleixner:
"A bunch of fixes for perf and kprobes:
- revert a commit that caused a perf group regression
- silence dmesg spam
- fix kprobe probing errors on ia64 and ppc64
- filter kprobe faults from userspace
- lockdep fix for perf exit path
- prevent perf #GP in KVM guest
- correct perf event and filters"
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
kprobes: Fix "Failed to find blacklist" probing errors on ia64 and ppc64
kprobes/x86: Don't try to resolve kprobe faults from userspace
perf/x86/intel: Avoid spamming kernel log for BTS buffer failure
perf/x86/intel: Protect LBR and extra_regs against KVM lying
perf: Fix lockdep warning on process exit
perf/x86/intel/uncore: Fix SNB-EP/IVT Cbox filter mappings
perf/x86/intel: Use proper dTLB-load-misses event on IvyBridge
perf: Revert ("perf: Always destroy groups on exit")
This commit is contained in:
+30
-2
@@ -7458,7 +7458,19 @@ __perf_event_exit_task(struct perf_event *child_event,
|
||||
struct perf_event_context *child_ctx,
|
||||
struct task_struct *child)
|
||||
{
|
||||
perf_remove_from_context(child_event, true);
|
||||
/*
|
||||
* Do not destroy the 'original' grouping; because of the context
|
||||
* switch optimization the original events could've ended up in a
|
||||
* random child task.
|
||||
*
|
||||
* If we were to destroy the original group, all group related
|
||||
* operations would cease to function properly after this random
|
||||
* child dies.
|
||||
*
|
||||
* Do destroy all inherited groups, we don't care about those
|
||||
* and being thorough is better.
|
||||
*/
|
||||
perf_remove_from_context(child_event, !!child_event->parent);
|
||||
|
||||
/*
|
||||
* It can happen that the parent exits first, and has events
|
||||
@@ -7474,7 +7486,7 @@ __perf_event_exit_task(struct perf_event *child_event,
|
||||
static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
|
||||
{
|
||||
struct perf_event *child_event, *next;
|
||||
struct perf_event_context *child_ctx;
|
||||
struct perf_event_context *child_ctx, *parent_ctx;
|
||||
unsigned long flags;
|
||||
|
||||
if (likely(!child->perf_event_ctxp[ctxn])) {
|
||||
@@ -7499,6 +7511,15 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
|
||||
raw_spin_lock(&child_ctx->lock);
|
||||
task_ctx_sched_out(child_ctx);
|
||||
child->perf_event_ctxp[ctxn] = NULL;
|
||||
|
||||
/*
|
||||
* In order to avoid freeing: child_ctx->parent_ctx->task
|
||||
* under perf_event_context::lock, grab another reference.
|
||||
*/
|
||||
parent_ctx = child_ctx->parent_ctx;
|
||||
if (parent_ctx)
|
||||
get_ctx(parent_ctx);
|
||||
|
||||
/*
|
||||
* If this context is a clone; unclone it so it can't get
|
||||
* swapped to another process while we're removing all
|
||||
@@ -7508,6 +7529,13 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
|
||||
update_context_time(child_ctx);
|
||||
raw_spin_unlock_irqrestore(&child_ctx->lock, flags);
|
||||
|
||||
/*
|
||||
* Now that we no longer hold perf_event_context::lock, drop
|
||||
* our extra child_ctx->parent_ctx reference.
|
||||
*/
|
||||
if (parent_ctx)
|
||||
put_ctx(parent_ctx);
|
||||
|
||||
/*
|
||||
* Report the task dead after unscheduling the events so that we
|
||||
* won't get any samples after PERF_RECORD_EXIT. We can however still
|
||||
|
||||
+9
-5
@@ -2037,19 +2037,23 @@ static int __init populate_kprobe_blacklist(unsigned long *start,
|
||||
{
|
||||
unsigned long *iter;
|
||||
struct kprobe_blacklist_entry *ent;
|
||||
unsigned long offset = 0, size = 0;
|
||||
unsigned long entry, offset = 0, size = 0;
|
||||
|
||||
for (iter = start; iter < end; iter++) {
|
||||
if (!kallsyms_lookup_size_offset(*iter, &size, &offset)) {
|
||||
pr_err("Failed to find blacklist %p\n", (void *)*iter);
|
||||
entry = arch_deref_entry_point((void *)*iter);
|
||||
|
||||
if (!kernel_text_address(entry) ||
|
||||
!kallsyms_lookup_size_offset(entry, &size, &offset)) {
|
||||
pr_err("Failed to find blacklist at %p\n",
|
||||
(void *)entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
ent = kmalloc(sizeof(*ent), GFP_KERNEL);
|
||||
if (!ent)
|
||||
return -ENOMEM;
|
||||
ent->start_addr = *iter;
|
||||
ent->end_addr = *iter + size;
|
||||
ent->start_addr = entry;
|
||||
ent->end_addr = entry + size;
|
||||
INIT_LIST_HEAD(&ent->list);
|
||||
list_add_tail(&ent->list, &kprobe_blacklist);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user