diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-14 20:43:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-09-14 20:43:45 -0400 |
commit | 7ef6e97380a1cb0f38cab795fe696f43c71d3ae9 (patch) | |
tree | 0557d01616fb4a41bfc98e6908ace912fa6d717c /kernel/events/core.c | |
parent | 7076cca9a700af5ccb0bd5eb7261dcfd7356dc5a (diff) | |
parent | e4390fa632d7c592e68e8106b7daea923ac995f5 (diff) |
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf fixes from Ingo Molnar:
"This tree includes various fixes"
Ingo really needs to improve on the whole "explain git pull" part.
"Various fixes" indeed.
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
perf/hwpb: Invoke __perf_event_disable() if interrupts are already disabled
perf/x86: Enable Intel Cedarview Atom suppport
perf_event: Switch to internal refcount, fix race with close()
oprofile, s390: Fix uninitialized memory access when writing to oprofilefs
perf/x86: Fix microcode revision check for SNB-PEBS
Diffstat (limited to 'kernel/events/core.c')
-rw-r--r-- | kernel/events/core.c | 64 |
1 files changed, 34 insertions, 30 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index b7935fcec7d9..7fee567153f0 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -1253,7 +1253,7 @@ retry: | |||
1253 | /* | 1253 | /* |
1254 | * Cross CPU call to disable a performance event | 1254 | * Cross CPU call to disable a performance event |
1255 | */ | 1255 | */ |
1256 | static int __perf_event_disable(void *info) | 1256 | int __perf_event_disable(void *info) |
1257 | { | 1257 | { |
1258 | struct perf_event *event = info; | 1258 | struct perf_event *event = info; |
1259 | struct perf_event_context *ctx = event->ctx; | 1259 | struct perf_event_context *ctx = event->ctx; |
@@ -2935,12 +2935,12 @@ EXPORT_SYMBOL_GPL(perf_event_release_kernel); | |||
2935 | /* | 2935 | /* |
2936 | * Called when the last reference to the file is gone. | 2936 | * Called when the last reference to the file is gone. |
2937 | */ | 2937 | */ |
2938 | static int perf_release(struct inode *inode, struct file *file) | 2938 | static void put_event(struct perf_event *event) |
2939 | { | 2939 | { |
2940 | struct perf_event *event = file->private_data; | ||
2941 | struct task_struct *owner; | 2940 | struct task_struct *owner; |
2942 | 2941 | ||
2943 | file->private_data = NULL; | 2942 | if (!atomic_long_dec_and_test(&event->refcount)) |
2943 | return; | ||
2944 | 2944 | ||
2945 | rcu_read_lock(); | 2945 | rcu_read_lock(); |
2946 | owner = ACCESS_ONCE(event->owner); | 2946 | owner = ACCESS_ONCE(event->owner); |
@@ -2975,7 +2975,13 @@ static int perf_release(struct inode *inode, struct file *file) | |||
2975 | put_task_struct(owner); | 2975 | put_task_struct(owner); |
2976 | } | 2976 | } |
2977 | 2977 | ||
2978 | return perf_event_release_kernel(event); | 2978 | perf_event_release_kernel(event); |
2979 | } | ||
2980 | |||
2981 | static int perf_release(struct inode *inode, struct file *file) | ||
2982 | { | ||
2983 | put_event(file->private_data); | ||
2984 | return 0; | ||
2979 | } | 2985 | } |
2980 | 2986 | ||
2981 | u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) | 2987 | u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) |
@@ -3227,7 +3233,7 @@ unlock: | |||
3227 | 3233 | ||
3228 | static const struct file_operations perf_fops; | 3234 | static const struct file_operations perf_fops; |
3229 | 3235 | ||
3230 | static struct perf_event *perf_fget_light(int fd, int *fput_needed) | 3236 | static struct file *perf_fget_light(int fd, int *fput_needed) |
3231 | { | 3237 | { |
3232 | struct file *file; | 3238 | struct file *file; |
3233 | 3239 | ||
@@ -3241,7 +3247,7 @@ static struct perf_event *perf_fget_light(int fd, int *fput_needed) | |||
3241 | return ERR_PTR(-EBADF); | 3247 | return ERR_PTR(-EBADF); |
3242 | } | 3248 | } |
3243 | 3249 | ||
3244 | return file->private_data; | 3250 | return file; |
3245 | } | 3251 | } |
3246 | 3252 | ||
3247 | static int perf_event_set_output(struct perf_event *event, | 3253 | static int perf_event_set_output(struct perf_event *event, |
@@ -3273,19 +3279,21 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
3273 | 3279 | ||
3274 | case PERF_EVENT_IOC_SET_OUTPUT: | 3280 | case PERF_EVENT_IOC_SET_OUTPUT: |
3275 | { | 3281 | { |
3282 | struct file *output_file = NULL; | ||
3276 | struct perf_event *output_event = NULL; | 3283 | struct perf_event *output_event = NULL; |
3277 | int fput_needed = 0; | 3284 | int fput_needed = 0; |
3278 | int ret; | 3285 | int ret; |
3279 | 3286 | ||
3280 | if (arg != -1) { | 3287 | if (arg != -1) { |
3281 | output_event = perf_fget_light(arg, &fput_needed); | 3288 | output_file = perf_fget_light(arg, &fput_needed); |
3282 | if (IS_ERR(output_event)) | 3289 | if (IS_ERR(output_file)) |
3283 | return PTR_ERR(output_event); | 3290 | return PTR_ERR(output_file); |
3291 | output_event = output_file->private_data; | ||
3284 | } | 3292 | } |
3285 | 3293 | ||
3286 | ret = perf_event_set_output(event, output_event); | 3294 | ret = perf_event_set_output(event, output_event); |
3287 | if (output_event) | 3295 | if (output_event) |
3288 | fput_light(output_event->filp, fput_needed); | 3296 | fput_light(output_file, fput_needed); |
3289 | 3297 | ||
3290 | return ret; | 3298 | return ret; |
3291 | } | 3299 | } |
@@ -5950,6 +5958,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, | |||
5950 | 5958 | ||
5951 | mutex_init(&event->mmap_mutex); | 5959 | mutex_init(&event->mmap_mutex); |
5952 | 5960 | ||
5961 | atomic_long_set(&event->refcount, 1); | ||
5953 | event->cpu = cpu; | 5962 | event->cpu = cpu; |
5954 | event->attr = *attr; | 5963 | event->attr = *attr; |
5955 | event->group_leader = group_leader; | 5964 | event->group_leader = group_leader; |
@@ -6260,12 +6269,12 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6260 | return event_fd; | 6269 | return event_fd; |
6261 | 6270 | ||
6262 | if (group_fd != -1) { | 6271 | if (group_fd != -1) { |
6263 | group_leader = perf_fget_light(group_fd, &fput_needed); | 6272 | group_file = perf_fget_light(group_fd, &fput_needed); |
6264 | if (IS_ERR(group_leader)) { | 6273 | if (IS_ERR(group_file)) { |
6265 | err = PTR_ERR(group_leader); | 6274 | err = PTR_ERR(group_file); |
6266 | goto err_fd; | 6275 | goto err_fd; |
6267 | } | 6276 | } |
6268 | group_file = group_leader->filp; | 6277 | group_leader = group_file->private_data; |
6269 | if (flags & PERF_FLAG_FD_OUTPUT) | 6278 | if (flags & PERF_FLAG_FD_OUTPUT) |
6270 | output_event = group_leader; | 6279 | output_event = group_leader; |
6271 | if (flags & PERF_FLAG_FD_NO_GROUP) | 6280 | if (flags & PERF_FLAG_FD_NO_GROUP) |
@@ -6402,7 +6411,6 @@ SYSCALL_DEFINE5(perf_event_open, | |||
6402 | put_ctx(gctx); | 6411 | put_ctx(gctx); |
6403 | } | 6412 | } |
6404 | 6413 | ||
6405 | event->filp = event_file; | ||
6406 | WARN_ON_ONCE(ctx->parent_ctx); | 6414 | WARN_ON_ONCE(ctx->parent_ctx); |
6407 | mutex_lock(&ctx->mutex); | 6415 | mutex_lock(&ctx->mutex); |
6408 | 6416 | ||
@@ -6496,7 +6504,6 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, | |||
6496 | goto err_free; | 6504 | goto err_free; |
6497 | } | 6505 | } |
6498 | 6506 | ||
6499 | event->filp = NULL; | ||
6500 | WARN_ON_ONCE(ctx->parent_ctx); | 6507 | WARN_ON_ONCE(ctx->parent_ctx); |
6501 | mutex_lock(&ctx->mutex); | 6508 | mutex_lock(&ctx->mutex); |
6502 | perf_install_in_context(ctx, event, cpu); | 6509 | perf_install_in_context(ctx, event, cpu); |
@@ -6578,7 +6585,7 @@ static void sync_child_event(struct perf_event *child_event, | |||
6578 | * Release the parent event, if this was the last | 6585 | * Release the parent event, if this was the last |
6579 | * reference to it. | 6586 | * reference to it. |
6580 | */ | 6587 | */ |
6581 | fput(parent_event->filp); | 6588 | put_event(parent_event); |
6582 | } | 6589 | } |
6583 | 6590 | ||
6584 | static void | 6591 | static void |
@@ -6654,9 +6661,8 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn) | |||
6654 | * | 6661 | * |
6655 | * __perf_event_exit_task() | 6662 | * __perf_event_exit_task() |
6656 | * sync_child_event() | 6663 | * sync_child_event() |
6657 | * fput(parent_event->filp) | 6664 | * put_event() |
6658 | * perf_release() | 6665 | * mutex_lock(&ctx->mutex) |
6659 | * mutex_lock(&ctx->mutex) | ||
6660 | * | 6666 | * |
6661 | * But since its the parent context it won't be the same instance. | 6667 | * But since its the parent context it won't be the same instance. |
6662 | */ | 6668 | */ |
@@ -6724,7 +6730,7 @@ static void perf_free_event(struct perf_event *event, | |||
6724 | list_del_init(&event->child_list); | 6730 | list_del_init(&event->child_list); |
6725 | mutex_unlock(&parent->child_mutex); | 6731 | mutex_unlock(&parent->child_mutex); |
6726 | 6732 | ||
6727 | fput(parent->filp); | 6733 | put_event(parent); |
6728 | 6734 | ||
6729 | perf_group_detach(event); | 6735 | perf_group_detach(event); |
6730 | list_del_event(event, ctx); | 6736 | list_del_event(event, ctx); |
@@ -6804,6 +6810,12 @@ inherit_event(struct perf_event *parent_event, | |||
6804 | NULL, NULL); | 6810 | NULL, NULL); |
6805 | if (IS_ERR(child_event)) | 6811 | if (IS_ERR(child_event)) |
6806 | return child_event; | 6812 | return child_event; |
6813 | |||
6814 | if (!atomic_long_inc_not_zero(&parent_event->refcount)) { | ||
6815 | free_event(child_event); | ||
6816 | return NULL; | ||
6817 | } | ||
6818 | |||
6807 | get_ctx(child_ctx); | 6819 | get_ctx(child_ctx); |
6808 | 6820 | ||
6809 | /* | 6821 | /* |
@@ -6845,14 +6857,6 @@ inherit_event(struct perf_event *parent_event, | |||
6845 | raw_spin_unlock_irqrestore(&child_ctx->lock, flags); | 6857 | raw_spin_unlock_irqrestore(&child_ctx->lock, flags); |
6846 | 6858 | ||
6847 | /* | 6859 | /* |
6848 | * Get a reference to the parent filp - we will fput it | ||
6849 | * when the child event exits. This is safe to do because | ||
6850 | * we are in the parent and we know that the filp still | ||
6851 | * exists and has a nonzero count: | ||
6852 | */ | ||
6853 | atomic_long_inc(&parent_event->filp->f_count); | ||
6854 | |||
6855 | /* | ||
6856 | * Link this into the parent event's child list | 6860 | * Link this into the parent event's child list |
6857 | */ | 6861 | */ |
6858 | WARN_ON_ONCE(parent_event->ctx->parent_ctx); | 6862 | WARN_ON_ONCE(parent_event->ctx->parent_ctx); |