diff options
| -rw-r--r-- | arch/s390/oprofile/init.c | 10 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel.c | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event_intel_lbr.c | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/microcode_core.c | 3 | ||||
| -rw-r--r-- | include/linux/perf_event.h | 4 | ||||
| -rw-r--r-- | kernel/events/core.c | 64 | ||||
| -rw-r--r-- | kernel/events/hw_breakpoint.c | 11 |
7 files changed, 58 insertions, 38 deletions
diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index a1e9d69a9c90..584b93674ea4 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c | |||
| @@ -169,7 +169,7 @@ static ssize_t hw_interval_write(struct file *file, char const __user *buf, | |||
| 169 | if (*offset) | 169 | if (*offset) |
| 170 | return -EINVAL; | 170 | return -EINVAL; |
| 171 | retval = oprofilefs_ulong_from_user(&val, buf, count); | 171 | retval = oprofilefs_ulong_from_user(&val, buf, count); |
| 172 | if (retval) | 172 | if (retval <= 0) |
| 173 | return retval; | 173 | return retval; |
| 174 | if (val < oprofile_min_interval) | 174 | if (val < oprofile_min_interval) |
| 175 | oprofile_hw_interval = oprofile_min_interval; | 175 | oprofile_hw_interval = oprofile_min_interval; |
| @@ -212,7 +212,7 @@ static ssize_t hwsampler_zero_write(struct file *file, char const __user *buf, | |||
| 212 | return -EINVAL; | 212 | return -EINVAL; |
| 213 | 213 | ||
| 214 | retval = oprofilefs_ulong_from_user(&val, buf, count); | 214 | retval = oprofilefs_ulong_from_user(&val, buf, count); |
| 215 | if (retval) | 215 | if (retval <= 0) |
| 216 | return retval; | 216 | return retval; |
| 217 | if (val != 0) | 217 | if (val != 0) |
| 218 | return -EINVAL; | 218 | return -EINVAL; |
| @@ -243,7 +243,7 @@ static ssize_t hwsampler_kernel_write(struct file *file, char const __user *buf, | |||
| 243 | return -EINVAL; | 243 | return -EINVAL; |
| 244 | 244 | ||
| 245 | retval = oprofilefs_ulong_from_user(&val, buf, count); | 245 | retval = oprofilefs_ulong_from_user(&val, buf, count); |
| 246 | if (retval) | 246 | if (retval <= 0) |
| 247 | return retval; | 247 | return retval; |
| 248 | 248 | ||
| 249 | if (val != 0 && val != 1) | 249 | if (val != 0 && val != 1) |
| @@ -278,7 +278,7 @@ static ssize_t hwsampler_user_write(struct file *file, char const __user *buf, | |||
| 278 | return -EINVAL; | 278 | return -EINVAL; |
| 279 | 279 | ||
| 280 | retval = oprofilefs_ulong_from_user(&val, buf, count); | 280 | retval = oprofilefs_ulong_from_user(&val, buf, count); |
| 281 | if (retval) | 281 | if (retval <= 0) |
| 282 | return retval; | 282 | return retval; |
| 283 | 283 | ||
| 284 | if (val != 0 && val != 1) | 284 | if (val != 0 && val != 1) |
| @@ -317,7 +317,7 @@ static ssize_t timer_enabled_write(struct file *file, char const __user *buf, | |||
| 317 | return -EINVAL; | 317 | return -EINVAL; |
| 318 | 318 | ||
| 319 | retval = oprofilefs_ulong_from_user(&val, buf, count); | 319 | retval = oprofilefs_ulong_from_user(&val, buf, count); |
| 320 | if (retval) | 320 | if (retval <= 0) |
| 321 | return retval; | 321 | return retval; |
| 322 | 322 | ||
| 323 | if (val != 0 && val != 1) | 323 | if (val != 0 && val != 1) |
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 7f2739e03e79..0d3d63afa76a 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c | |||
| @@ -2008,6 +2008,7 @@ __init int intel_pmu_init(void) | |||
| 2008 | break; | 2008 | break; |
| 2009 | 2009 | ||
| 2010 | case 28: /* Atom */ | 2010 | case 28: /* Atom */ |
| 2011 | case 54: /* Cedariew */ | ||
| 2011 | memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, | 2012 | memcpy(hw_cache_event_ids, atom_hw_cache_event_ids, |
| 2012 | sizeof(hw_cache_event_ids)); | 2013 | sizeof(hw_cache_event_ids)); |
| 2013 | 2014 | ||
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index 520b4265fcd2..da02e9cc3754 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c | |||
| @@ -686,7 +686,8 @@ void intel_pmu_lbr_init_atom(void) | |||
| 686 | * to have an operational LBR which can freeze | 686 | * to have an operational LBR which can freeze |
| 687 | * on PMU interrupt | 687 | * on PMU interrupt |
| 688 | */ | 688 | */ |
| 689 | if (boot_cpu_data.x86_mask < 10) { | 689 | if (boot_cpu_data.x86_model == 28 |
| 690 | && boot_cpu_data.x86_mask < 10) { | ||
| 690 | pr_cont("LBR disabled due to erratum"); | 691 | pr_cont("LBR disabled due to erratum"); |
| 691 | return; | 692 | return; |
| 692 | } | 693 | } |
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c index 4873e62db6a1..9e5bcf1e2376 100644 --- a/arch/x86/kernel/microcode_core.c +++ b/arch/x86/kernel/microcode_core.c | |||
| @@ -225,6 +225,9 @@ static ssize_t microcode_write(struct file *file, const char __user *buf, | |||
| 225 | if (do_microcode_update(buf, len) == 0) | 225 | if (do_microcode_update(buf, len) == 0) |
| 226 | ret = (ssize_t)len; | 226 | ret = (ssize_t)len; |
| 227 | 227 | ||
| 228 | if (ret > 0) | ||
| 229 | perf_check_microcode(); | ||
| 230 | |||
| 228 | mutex_unlock(µcode_mutex); | 231 | mutex_unlock(µcode_mutex); |
| 229 | put_online_cpus(); | 232 | put_online_cpus(); |
| 230 | 233 | ||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 7602ccb3f40e..33ed9d605f91 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -926,7 +926,7 @@ struct perf_event { | |||
| 926 | struct hw_perf_event hw; | 926 | struct hw_perf_event hw; |
| 927 | 927 | ||
| 928 | struct perf_event_context *ctx; | 928 | struct perf_event_context *ctx; |
| 929 | struct file *filp; | 929 | atomic_long_t refcount; |
| 930 | 930 | ||
| 931 | /* | 931 | /* |
| 932 | * These accumulate total time (in nanoseconds) that children | 932 | * These accumulate total time (in nanoseconds) that children |
| @@ -1296,6 +1296,7 @@ extern int perf_swevent_get_recursion_context(void); | |||
| 1296 | extern void perf_swevent_put_recursion_context(int rctx); | 1296 | extern void perf_swevent_put_recursion_context(int rctx); |
| 1297 | extern void perf_event_enable(struct perf_event *event); | 1297 | extern void perf_event_enable(struct perf_event *event); |
| 1298 | extern void perf_event_disable(struct perf_event *event); | 1298 | extern void perf_event_disable(struct perf_event *event); |
| 1299 | extern int __perf_event_disable(void *info); | ||
| 1299 | extern void perf_event_task_tick(void); | 1300 | extern void perf_event_task_tick(void); |
| 1300 | #else | 1301 | #else |
| 1301 | static inline void | 1302 | static inline void |
| @@ -1334,6 +1335,7 @@ static inline int perf_swevent_get_recursion_context(void) { return -1; } | |||
| 1334 | static inline void perf_swevent_put_recursion_context(int rctx) { } | 1335 | static inline void perf_swevent_put_recursion_context(int rctx) { } |
| 1335 | static inline void perf_event_enable(struct perf_event *event) { } | 1336 | static inline void perf_event_enable(struct perf_event *event) { } |
| 1336 | static inline void perf_event_disable(struct perf_event *event) { } | 1337 | static inline void perf_event_disable(struct perf_event *event) { } |
| 1338 | static inline int __perf_event_disable(void *info) { return -1; } | ||
| 1337 | static inline void perf_event_task_tick(void) { } | 1339 | static inline void perf_event_task_tick(void) { } |
| 1338 | #endif | 1340 | #endif |
| 1339 | 1341 | ||
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); |
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index bb38c4d3ee12..9a7b487c6fe2 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c | |||
| @@ -453,7 +453,16 @@ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *att | |||
| 453 | int old_type = bp->attr.bp_type; | 453 | int old_type = bp->attr.bp_type; |
| 454 | int err = 0; | 454 | int err = 0; |
| 455 | 455 | ||
| 456 | perf_event_disable(bp); | 456 | /* |
| 457 | * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it | ||
| 458 | * will not be possible to raise IPIs that invoke __perf_event_disable. | ||
| 459 | * So call the function directly after making sure we are targeting the | ||
| 460 | * current task. | ||
| 461 | */ | ||
| 462 | if (irqs_disabled() && bp->ctx && bp->ctx->task == current) | ||
| 463 | __perf_event_disable(bp); | ||
| 464 | else | ||
| 465 | perf_event_disable(bp); | ||
| 457 | 466 | ||
| 458 | bp->attr.bp_addr = attr->bp_addr; | 467 | bp->attr.bp_addr = attr->bp_addr; |
| 459 | bp->attr.bp_type = attr->bp_type; | 468 | bp->attr.bp_type = attr->bp_type; |
