| From 25217145d6c725e5ba6b09f672bafd117ba61098 Mon Sep 17 00:00:00 2001 |
| From: Stephane Eranian <eranian@google.com> |
| Date: Thu, 10 Jan 2019 17:17:16 -0800 |
| Subject: perf core: Fix perf_proc_update_handler() bug |
| |
| [ Upstream commit 1a51c5da5acc6c188c917ba572eebac5f8793432 ] |
| |
| The perf_proc_update_handler() handles /proc/sys/kernel/perf_event_max_sample_rate |
| syctl variable. When the PMU IRQ handler timing monitoring is disabled, i.e, |
| when /proc/sys/kernel/perf_cpu_time_max_percent is equal to 0 or 100, |
| then no modification to sysctl_perf_event_sample_rate is allowed to prevent |
| possible hang from wrong values. |
| |
| The problem is that the test to prevent modification is made after the |
| sysctl variable is modified in perf_proc_update_handler(). |
| |
| You get an error: |
| |
| $ echo 10001 >/proc/sys/kernel/perf_event_max_sample_rate |
| echo: write error: invalid argument |
| |
| But the value is still modified causing all sorts of inconsistencies: |
| |
| $ cat /proc/sys/kernel/perf_event_max_sample_rate |
| 10001 |
| |
| This patch fixes the problem by moving the parsing of the value after |
| the test. |
| |
| Committer testing: |
| |
| # echo 100 > /proc/sys/kernel/perf_cpu_time_max_percent |
| # echo 10001 > /proc/sys/kernel/perf_event_max_sample_rate |
| -bash: echo: write error: Invalid argument |
| # cat /proc/sys/kernel/perf_event_max_sample_rate |
| 10001 |
| # |
| |
| Signed-off-by: Stephane Eranian <eranian@google.com> |
| Reviewed-by: Andi Kleen <ak@linux.intel.com> |
| Reviewed-by: Jiri Olsa <jolsa@kernel.org> |
| Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Cc: Kan Liang <kan.liang@linux.intel.com> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Link: http://lkml.kernel.org/r/1547169436-6266-1-git-send-email-eranian@google.com |
| Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| kernel/events/core.c | 14 +++++++------- |
| 1 file changed, 7 insertions(+), 7 deletions(-) |
| |
| diff --git a/kernel/events/core.c b/kernel/events/core.c |
| index 4fb9d5054618..aa996a0854b9 100644 |
| --- a/kernel/events/core.c |
| +++ b/kernel/events/core.c |
| @@ -436,18 +436,18 @@ int perf_proc_update_handler(struct ctl_table *table, int write, |
| void __user *buffer, size_t *lenp, |
| loff_t *ppos) |
| { |
| - int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); |
| - |
| - if (ret || !write) |
| - return ret; |
| - |
| + int ret; |
| + int perf_cpu = sysctl_perf_cpu_time_max_percent; |
| /* |
| * If throttling is disabled don't allow the write: |
| */ |
| - if (sysctl_perf_cpu_time_max_percent == 100 || |
| - sysctl_perf_cpu_time_max_percent == 0) |
| + if (write && (perf_cpu == 100 || perf_cpu == 0)) |
| return -EINVAL; |
| |
| + ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); |
| + if (ret || !write) |
| + return ret; |
| + |
| max_samples_per_tick = DIV_ROUND_UP(sysctl_perf_event_sample_rate, HZ); |
| perf_sample_period_ns = NSEC_PER_SEC / sysctl_perf_event_sample_rate; |
| update_perf_cpu_limits(); |
| -- |
| 2.19.1 |
| |