diff options
Diffstat (limited to 'kernel/events/ring_buffer.c')
| -rw-r--r-- | kernel/events/ring_buffer.c | 27 |
1 files changed, 25 insertions, 2 deletions
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index 96472824a752..b2be01b1aa9d 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c | |||
| @@ -221,6 +221,8 @@ void perf_output_end(struct perf_output_handle *handle) | |||
| 221 | rcu_read_unlock(); | 221 | rcu_read_unlock(); |
| 222 | } | 222 | } |
| 223 | 223 | ||
| 224 | static void rb_irq_work(struct irq_work *work); | ||
| 225 | |||
| 224 | static void | 226 | static void |
| 225 | ring_buffer_init(struct ring_buffer *rb, long watermark, int flags) | 227 | ring_buffer_init(struct ring_buffer *rb, long watermark, int flags) |
| 226 | { | 228 | { |
| @@ -241,6 +243,16 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags) | |||
| 241 | 243 | ||
| 242 | INIT_LIST_HEAD(&rb->event_list); | 244 | INIT_LIST_HEAD(&rb->event_list); |
| 243 | spin_lock_init(&rb->event_lock); | 245 | spin_lock_init(&rb->event_lock); |
| 246 | init_irq_work(&rb->irq_work, rb_irq_work); | ||
| 247 | } | ||
| 248 | |||
| 249 | static void ring_buffer_put_async(struct ring_buffer *rb) | ||
| 250 | { | ||
| 251 | if (!atomic_dec_and_test(&rb->refcount)) | ||
| 252 | return; | ||
| 253 | |||
| 254 | rb->rcu_head.next = (void *)rb; | ||
| 255 | irq_work_queue(&rb->irq_work); | ||
| 244 | } | 256 | } |
| 245 | 257 | ||
| 246 | /* | 258 | /* |
| @@ -319,7 +331,7 @@ err_put: | |||
| 319 | rb_free_aux(rb); | 331 | rb_free_aux(rb); |
| 320 | 332 | ||
| 321 | err: | 333 | err: |
| 322 | ring_buffer_put(rb); | 334 | ring_buffer_put_async(rb); |
| 323 | handle->event = NULL; | 335 | handle->event = NULL; |
| 324 | 336 | ||
| 325 | return NULL; | 337 | return NULL; |
| @@ -370,7 +382,7 @@ void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size, | |||
| 370 | 382 | ||
| 371 | local_set(&rb->aux_nest, 0); | 383 | local_set(&rb->aux_nest, 0); |
| 372 | rb_free_aux(rb); | 384 | rb_free_aux(rb); |
| 373 | ring_buffer_put(rb); | 385 | ring_buffer_put_async(rb); |
| 374 | } | 386 | } |
| 375 | 387 | ||
| 376 | /* | 388 | /* |
| @@ -557,7 +569,18 @@ static void __rb_free_aux(struct ring_buffer *rb) | |||
| 557 | void rb_free_aux(struct ring_buffer *rb) | 569 | void rb_free_aux(struct ring_buffer *rb) |
| 558 | { | 570 | { |
| 559 | if (atomic_dec_and_test(&rb->aux_refcount)) | 571 | if (atomic_dec_and_test(&rb->aux_refcount)) |
| 572 | irq_work_queue(&rb->irq_work); | ||
| 573 | } | ||
| 574 | |||
| 575 | static void rb_irq_work(struct irq_work *work) | ||
| 576 | { | ||
| 577 | struct ring_buffer *rb = container_of(work, struct ring_buffer, irq_work); | ||
| 578 | |||
| 579 | if (!atomic_read(&rb->aux_refcount)) | ||
| 560 | __rb_free_aux(rb); | 580 | __rb_free_aux(rb); |
| 581 | |||
| 582 | if (rb->rcu_head.next == (void *)rb) | ||
| 583 | call_rcu(&rb->rcu_head, rb_free_rcu); | ||
| 561 | } | 584 | } |
| 562 | 585 | ||
| 563 | #ifndef CONFIG_PERF_USE_VMALLOC | 586 | #ifndef CONFIG_PERF_USE_VMALLOC |
