Commit eb0ef8ad authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'perf_urgent_for_v6.1_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf fixes from Borislav Petkov:

 - Fix an intel PT erratum where CPUs do not support single range output
   for more than 4K

 - Fix a NULL ptr dereference which can happen after an NMI interferes
   with the event enabling dance in amd_pmu_enable_all()

 - Free the events array too when freeing uncore contexts on CPU online,
   thereby fixing a memory leak

 - Improve the pending SIGTRAP check

* tag 'perf_urgent_for_v6.1_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/x86/intel/pt: Fix sampling using single range output
  perf/x86/amd: Fix crash due to race between amd_pmu_enable_all, perf NMI and throttling
  perf/x86/amd/uncore: Fix memory leak for events array
  perf: Improve missing SIGTRAP checking
parents 6a211a75 ce0d998b
...@@ -861,8 +861,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs) ...@@ -861,8 +861,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
pmu_enabled = cpuc->enabled; pmu_enabled = cpuc->enabled;
cpuc->enabled = 0; cpuc->enabled = 0;
/* stop everything (includes BRS) */ amd_brs_disable_all();
amd_pmu_disable_all();
/* Drain BRS is in use (could be inactive) */ /* Drain BRS is in use (could be inactive) */
if (cpuc->lbr_users) if (cpuc->lbr_users)
...@@ -873,7 +872,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs) ...@@ -873,7 +872,7 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
cpuc->enabled = pmu_enabled; cpuc->enabled = pmu_enabled;
if (pmu_enabled) if (pmu_enabled)
amd_pmu_enable_all(0); amd_brs_enable_all();
return amd_pmu_adjust_nmi_window(handled); return amd_pmu_adjust_nmi_window(handled);
} }
......
...@@ -553,6 +553,7 @@ static void uncore_clean_online(void) ...@@ -553,6 +553,7 @@ static void uncore_clean_online(void)
hlist_for_each_entry_safe(uncore, n, &uncore_unused_list, node) { hlist_for_each_entry_safe(uncore, n, &uncore_unused_list, node) {
hlist_del(&uncore->node); hlist_del(&uncore->node);
kfree(uncore->events);
kfree(uncore); kfree(uncore);
} }
} }
......
...@@ -1263,6 +1263,15 @@ static int pt_buffer_try_single(struct pt_buffer *buf, int nr_pages) ...@@ -1263,6 +1263,15 @@ static int pt_buffer_try_single(struct pt_buffer *buf, int nr_pages)
if (1 << order != nr_pages) if (1 << order != nr_pages)
goto out; goto out;
/*
* Some processors cannot always support single range for more than
* 4KB - refer errata TGL052, ADL037 and RPL017. Future processors might
* also be affected, so for now rather than trying to keep track of
* which ones, just disable it for all.
*/
if (nr_pages > 1)
goto out;
buf->single = true; buf->single = true;
buf->nr_pages = nr_pages; buf->nr_pages = nr_pages;
ret = 0; ret = 0;
......
...@@ -9306,14 +9306,27 @@ static int __perf_event_overflow(struct perf_event *event, ...@@ -9306,14 +9306,27 @@ static int __perf_event_overflow(struct perf_event *event,
} }
if (event->attr.sigtrap) { if (event->attr.sigtrap) {
/* unsigned int pending_id = 1;
* Should not be able to return to user space without processing
* pending_sigtrap (kernel events can overflow multiple times). if (regs)
*/ pending_id = hash32_ptr((void *)instruction_pointer(regs)) ?: 1;
WARN_ON_ONCE(event->pending_sigtrap && event->attr.exclude_kernel);
if (!event->pending_sigtrap) { if (!event->pending_sigtrap) {
event->pending_sigtrap = 1; event->pending_sigtrap = pending_id;
local_inc(&event->ctx->nr_pending); local_inc(&event->ctx->nr_pending);
} else if (event->attr.exclude_kernel) {
/*
* Should not be able to return to user space without
* consuming pending_sigtrap; with exceptions:
*
* 1. Where !exclude_kernel, events can overflow again
* in the kernel without returning to user space.
*
* 2. Events that can overflow again before the IRQ-
* work without user space progress (e.g. hrtimer).
* To approximate progress (with false negatives),
* check 32-bit hash of the current IP.
*/
WARN_ON_ONCE(event->pending_sigtrap != pending_id);
} }
event->pending_addr = data->addr; event->pending_addr = data->addr;
irq_work_queue(&event->pending_irq); irq_work_queue(&event->pending_irq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment