aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-12-05 19:54:00 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-12-05 19:54:00 -0500
commit232ea344550c4a099d35d9df552509d6748a31c0 (patch)
tree2b4a1c351d290537fdf18cc5bed78bf43536f175 /kernel
parent40c043b077c6e377c8440d71563c055d0c4f0f0a (diff)
parentdc440d10e1668b15fe704a23adb9b53fbbb24a44 (diff)
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: perf: Fix loss of notification with multi-event perf, x86: Force IBS LVT offset assignment for family 10h perf, x86: Disable PEBS on SandyBridge chips trace_events_filter: Use rcu_assign_pointer() when setting ftrace_event_call->filter perf session: Fix crash with invalid CPU list perf python: Fix undefined symbol problem perf/x86: Enable raw event access to Intel offcore events perf: Don't use -ENOSPC for out of PMU resources perf: Do not set task_ctx pointer in cpuctx if there are no events in the context perf/x86: Fix PEBS instruction unwind oprofile, x86: Fix crash when unloading module (nmi timer mode) oprofile: Fix crash when unloading module (hr timer mode)
Diffstat (limited to 'kernel')
-rw-r--r--kernel/events/core.c89
-rw-r--r--kernel/events/internal.h3
-rw-r--r--kernel/events/ring_buffer.c3
-rw-r--r--kernel/trace/trace_events_filter.c6
4 files changed, 95 insertions, 6 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 0e8457da6f95..600c1629b64d 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -185,6 +185,9 @@ static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx,
185static void update_context_time(struct perf_event_context *ctx); 185static void update_context_time(struct perf_event_context *ctx);
186static u64 perf_event_time(struct perf_event *event); 186static u64 perf_event_time(struct perf_event *event);
187 187
188static void ring_buffer_attach(struct perf_event *event,
189 struct ring_buffer *rb);
190
188void __weak perf_event_print_debug(void) { } 191void __weak perf_event_print_debug(void) { }
189 192
190extern __weak const char *perf_pmu_name(void) 193extern __weak const char *perf_pmu_name(void)
@@ -2173,7 +2176,8 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx,
2173 2176
2174 perf_event_sched_in(cpuctx, ctx, task); 2177 perf_event_sched_in(cpuctx, ctx, task);
2175 2178
2176 cpuctx->task_ctx = ctx; 2179 if (ctx->nr_events)
2180 cpuctx->task_ctx = ctx;
2177 2181
2178 perf_pmu_enable(ctx->pmu); 2182 perf_pmu_enable(ctx->pmu);
2179 perf_ctx_unlock(cpuctx, ctx); 2183 perf_ctx_unlock(cpuctx, ctx);
@@ -3190,12 +3194,33 @@ static unsigned int perf_poll(struct file *file, poll_table *wait)
3190 struct ring_buffer *rb; 3194 struct ring_buffer *rb;
3191 unsigned int events = POLL_HUP; 3195 unsigned int events = POLL_HUP;
3192 3196
3197 /*
3198 * Race between perf_event_set_output() and perf_poll(): perf_poll()
3199 * grabs the rb reference but perf_event_set_output() overrides it.
3200 * Here is the timeline for two threads T1, T2:
3201 * t0: T1, rb = rcu_dereference(event->rb)
3202 * t1: T2, old_rb = event->rb
3203 * t2: T2, event->rb = new rb
3204 * t3: T2, ring_buffer_detach(old_rb)
3205 * t4: T1, ring_buffer_attach(rb1)
3206 * t5: T1, poll_wait(event->waitq)
3207 *
3208 * To avoid this problem, we grab mmap_mutex in perf_poll()
3209 * thereby ensuring that the assignment of the new ring buffer
3210 * and the detachment of the old buffer appear atomic to perf_poll()
3211 */
3212 mutex_lock(&event->mmap_mutex);
3213
3193 rcu_read_lock(); 3214 rcu_read_lock();
3194 rb = rcu_dereference(event->rb); 3215 rb = rcu_dereference(event->rb);
3195 if (rb) 3216 if (rb) {
3217 ring_buffer_attach(event, rb);
3196 events = atomic_xchg(&rb->poll, 0); 3218 events = atomic_xchg(&rb->poll, 0);
3219 }
3197 rcu_read_unlock(); 3220 rcu_read_unlock();
3198 3221
3222 mutex_unlock(&event->mmap_mutex);
3223
3199 poll_wait(file, &event->waitq, wait); 3224 poll_wait(file, &event->waitq, wait);
3200 3225
3201 return events; 3226 return events;
@@ -3496,6 +3521,49 @@ unlock:
3496 return ret; 3521 return ret;
3497} 3522}
3498 3523
3524static void ring_buffer_attach(struct perf_event *event,
3525 struct ring_buffer *rb)
3526{
3527 unsigned long flags;
3528
3529 if (!list_empty(&event->rb_entry))
3530 return;
3531
3532 spin_lock_irqsave(&rb->event_lock, flags);
3533 if (!list_empty(&event->rb_entry))
3534 goto unlock;
3535
3536 list_add(&event->rb_entry, &rb->event_list);
3537unlock:
3538 spin_unlock_irqrestore(&rb->event_lock, flags);
3539}
3540
3541static void ring_buffer_detach(struct perf_event *event,
3542 struct ring_buffer *rb)
3543{
3544 unsigned long flags;
3545
3546 if (list_empty(&event->rb_entry))
3547 return;
3548
3549 spin_lock_irqsave(&rb->event_lock, flags);
3550 list_del_init(&event->rb_entry);
3551 wake_up_all(&event->waitq);
3552 spin_unlock_irqrestore(&rb->event_lock, flags);
3553}
3554
3555static void ring_buffer_wakeup(struct perf_event *event)
3556{
3557 struct ring_buffer *rb;
3558
3559 rcu_read_lock();
3560 rb = rcu_dereference(event->rb);
3561 list_for_each_entry_rcu(event, &rb->event_list, rb_entry) {
3562 wake_up_all(&event->waitq);
3563 }
3564 rcu_read_unlock();
3565}
3566
3499static void rb_free_rcu(struct rcu_head *rcu_head) 3567static void rb_free_rcu(struct rcu_head *rcu_head)
3500{ 3568{
3501 struct ring_buffer *rb; 3569 struct ring_buffer *rb;
@@ -3521,9 +3589,19 @@ static struct ring_buffer *ring_buffer_get(struct perf_event *event)
3521 3589
3522static void ring_buffer_put(struct ring_buffer *rb) 3590static void ring_buffer_put(struct ring_buffer *rb)
3523{ 3591{
3592 struct perf_event *event, *n;
3593 unsigned long flags;
3594
3524 if (!atomic_dec_and_test(&rb->refcount)) 3595 if (!atomic_dec_and_test(&rb->refcount))
3525 return; 3596 return;
3526 3597
3598 spin_lock_irqsave(&rb->event_lock, flags);
3599 list_for_each_entry_safe(event, n, &rb->event_list, rb_entry) {
3600 list_del_init(&event->rb_entry);
3601 wake_up_all(&event->waitq);
3602 }
3603 spin_unlock_irqrestore(&rb->event_lock, flags);
3604
3527 call_rcu(&rb->rcu_head, rb_free_rcu); 3605 call_rcu(&rb->rcu_head, rb_free_rcu);
3528} 3606}
3529 3607
@@ -3546,6 +3624,7 @@ static void perf_mmap_close(struct vm_area_struct *vma)
3546 atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm); 3624 atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm);
3547 vma->vm_mm->pinned_vm -= event->mmap_locked; 3625 vma->vm_mm->pinned_vm -= event->mmap_locked;
3548 rcu_assign_pointer(event->rb, NULL); 3626 rcu_assign_pointer(event->rb, NULL);
3627 ring_buffer_detach(event, rb);
3549 mutex_unlock(&event->mmap_mutex); 3628 mutex_unlock(&event->mmap_mutex);
3550 3629
3551 ring_buffer_put(rb); 3630 ring_buffer_put(rb);
@@ -3700,7 +3779,7 @@ static const struct file_operations perf_fops = {
3700 3779
3701void perf_event_wakeup(struct perf_event *event) 3780void perf_event_wakeup(struct perf_event *event)
3702{ 3781{
3703 wake_up_all(&event->waitq); 3782 ring_buffer_wakeup(event);
3704 3783
3705 if (event->pending_kill) { 3784 if (event->pending_kill) {
3706 kill_fasync(&event->fasync, SIGIO, event->pending_kill); 3785 kill_fasync(&event->fasync, SIGIO, event->pending_kill);
@@ -5822,6 +5901,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
5822 INIT_LIST_HEAD(&event->group_entry); 5901 INIT_LIST_HEAD(&event->group_entry);
5823 INIT_LIST_HEAD(&event->event_entry); 5902 INIT_LIST_HEAD(&event->event_entry);
5824 INIT_LIST_HEAD(&event->sibling_list); 5903 INIT_LIST_HEAD(&event->sibling_list);
5904 INIT_LIST_HEAD(&event->rb_entry);
5905
5825 init_waitqueue_head(&event->waitq); 5906 init_waitqueue_head(&event->waitq);
5826 init_irq_work(&event->pending, perf_pending_event); 5907 init_irq_work(&event->pending, perf_pending_event);
5827 5908
@@ -6028,6 +6109,8 @@ set:
6028 6109
6029 old_rb = event->rb; 6110 old_rb = event->rb;
6030 rcu_assign_pointer(event->rb, rb); 6111 rcu_assign_pointer(event->rb, rb);
6112 if (old_rb)
6113 ring_buffer_detach(event, old_rb);
6031 ret = 0; 6114 ret = 0;
6032unlock: 6115unlock:
6033 mutex_unlock(&event->mmap_mutex); 6116 mutex_unlock(&event->mmap_mutex);
diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index 09097dd8116c..64568a699375 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -22,6 +22,9 @@ struct ring_buffer {
22 local_t lost; /* nr records lost */ 22 local_t lost; /* nr records lost */
23 23
24 long watermark; /* wakeup watermark */ 24 long watermark; /* wakeup watermark */
25 /* poll crap */
26 spinlock_t event_lock;
27 struct list_head event_list;
25 28
26 struct perf_event_mmap_page *user_page; 29 struct perf_event_mmap_page *user_page;
27 void *data_pages[0]; 30 void *data_pages[0];
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index a2a29205cc0f..7f3011c6b57f 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -209,6 +209,9 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
209 rb->writable = 1; 209 rb->writable = 1;
210 210
211 atomic_set(&rb->refcount, 1); 211 atomic_set(&rb->refcount, 1);
212
213 INIT_LIST_HEAD(&rb->event_list);
214 spin_lock_init(&rb->event_lock);
212} 215}
213 216
214#ifndef CONFIG_PERF_USE_VMALLOC 217#ifndef CONFIG_PERF_USE_VMALLOC
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 816d3d074979..d6e7926dcd26 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -1686,7 +1686,7 @@ static int replace_system_preds(struct event_subsystem *system,
1686 * replace the filter for the call. 1686 * replace the filter for the call.
1687 */ 1687 */
1688 filter = call->filter; 1688 filter = call->filter;
1689 call->filter = filter_item->filter; 1689 rcu_assign_pointer(call->filter, filter_item->filter);
1690 filter_item->filter = filter; 1690 filter_item->filter = filter;
1691 1691
1692 fail = false; 1692 fail = false;
@@ -1741,7 +1741,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
1741 filter = call->filter; 1741 filter = call->filter;
1742 if (!filter) 1742 if (!filter)
1743 goto out_unlock; 1743 goto out_unlock;
1744 call->filter = NULL; 1744 RCU_INIT_POINTER(call->filter, NULL);
1745 /* Make sure the filter is not being used */ 1745 /* Make sure the filter is not being used */
1746 synchronize_sched(); 1746 synchronize_sched();
1747 __free_filter(filter); 1747 __free_filter(filter);
@@ -1782,7 +1782,7 @@ out:
1782 * string 1782 * string
1783 */ 1783 */
1784 tmp = call->filter; 1784 tmp = call->filter;
1785 call->filter = filter; 1785 rcu_assign_pointer(call->filter, filter);
1786 if (tmp) { 1786 if (tmp) {
1787 /* Make sure the call is done with the filter */ 1787 /* Make sure the call is done with the filter */
1788 synchronize_sched(); 1788 synchronize_sched();