aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Richter <tmricht@linux.ibm.com>2019-03-18 10:50:27 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2019-03-28 04:28:42 -0400
commitb6ffdf27f3d4f1e9af56effe6f86989170d71e95 (patch)
tree58ec1b0292bad883170e59f7af0b80c9b33cfe0b
parent0d9c038feff6f834ad9e5d88b66715235ab23ff3 (diff)
s390/cpumf: Fix warning from check_processor_id
Function __hw_perf_event_init() used a CPU variable without ensuring CPU preemption has been disabled. This caused the following warning in the kernel log: [ 7.277085] BUG: using smp_processor_id() in preemptible [00000000] code: cf-csdiag/1892 [ 7.277111] caller is cf_diag_event_init+0x13a/0x338 [ 7.277122] CPU: 10 PID: 1892 Comm: cf-csdiag Not tainted 5.0.0-20190318.rc0.git0.9e1a11e0f602.300.fc29.s390x+debug #1 [ 7.277131] Hardware name: IBM 2964 NC9 712 (LPAR) [ 7.277139] Call Trace: [ 7.277150] ([<000000000011385a>] show_stack+0x82/0xd0) [ 7.277161] [<0000000000b7a71a>] dump_stack+0x92/0xd0 [ 7.277174] [<00000000007b7e9c>] check_preemption_disabled+0xe4/0x100 [ 7.277183] [<00000000001228aa>] cf_diag_event_init+0x13a/0x338 [ 7.277195] [<00000000002cf3aa>] perf_try_init_event+0x72/0xf0 [ 7.277204] [<00000000002d0bba>] perf_event_alloc+0x6fa/0xce0 [ 7.277214] [<00000000002dc4a8>] __s390x_sys_perf_event_open+0x398/0xd50 [ 7.277224] [<0000000000b9e8f0>] system_call+0xdc/0x2d8 [ 7.277233] 2 locks held by cf-csdiag/1892: [ 7.277241] #0: 00000000976f5510 (&sig->cred_guard_mutex){+.+.}, at: __s390x_sys_perf_event_open+0xd2e/0xd50 [ 7.277257] #1: 00000000363b11bd (&pmus_srcu){....}, at: perf_event_alloc+0x52e/0xce0 The variable is now accessed in proper context. Use get_cpu_var()/put_cpu_var() pair to disable preemption during access. As the hardware authorization settings apply to all CPUs, it does not matter which CPU is used to check the authorization setting. Remove the event->count assignment. It is not needed as function perf_event_alloc() allocates memory for the event with kzalloc() and thus count is already set to zero. Fixes: fe5908bccc56 ("s390/cpum_cf_diag: Add support for s390 counter facility diagnostic trace") Signed-off-by: Thomas Richter <tmricht@linux.ibm.com> Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/kernel/perf_cpum_cf_diag.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/arch/s390/kernel/perf_cpum_cf_diag.c b/arch/s390/kernel/perf_cpum_cf_diag.c
index c6fad208c2fa..b6854812d2ed 100644
--- a/arch/s390/kernel/perf_cpum_cf_diag.c
+++ b/arch/s390/kernel/perf_cpum_cf_diag.c
@@ -196,23 +196,30 @@ static void cf_diag_perf_event_destroy(struct perf_event *event)
196 */ 196 */
197static int __hw_perf_event_init(struct perf_event *event) 197static int __hw_perf_event_init(struct perf_event *event)
198{ 198{
199 struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events);
200 struct perf_event_attr *attr = &event->attr; 199 struct perf_event_attr *attr = &event->attr;
200 struct cpu_cf_events *cpuhw;
201 enum cpumf_ctr_set i; 201 enum cpumf_ctr_set i;
202 int err = 0; 202 int err = 0;
203 203
204 debug_sprintf_event(cf_diag_dbg, 5, 204 debug_sprintf_event(cf_diag_dbg, 5, "%s event %p cpu %d\n", __func__,
205 "%s event %p cpu %d authorized %#x\n", __func__, 205 event, event->cpu);
206 event, event->cpu, cpuhw->info.auth_ctl);
207 206
208 event->hw.config = attr->config; 207 event->hw.config = attr->config;
209 event->hw.config_base = 0; 208 event->hw.config_base = 0;
210 local64_set(&event->count, 0);
211 209
212 /* Add all authorized counter sets to config_base */ 210 /* Add all authorized counter sets to config_base. The
211 * the hardware init function is either called per-cpu or just once
212 * for all CPUS (event->cpu == -1). This depends on the whether
213 * counting is started for all CPUs or on a per workload base where
214 * the perf event moves from one CPU to another CPU.
215 * Checking the authorization on any CPU is fine as the hardware
216 * applies the same authorization settings to all CPUs.
217 */
218 cpuhw = &get_cpu_var(cpu_cf_events);
213 for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i) 219 for (i = CPUMF_CTR_SET_BASIC; i < CPUMF_CTR_SET_MAX; ++i)
214 if (cpuhw->info.auth_ctl & cpumf_ctr_ctl[i]) 220 if (cpuhw->info.auth_ctl & cpumf_ctr_ctl[i])
215 event->hw.config_base |= cpumf_ctr_ctl[i]; 221 event->hw.config_base |= cpumf_ctr_ctl[i];
222 put_cpu_var(cpu_cf_events);
216 223
217 /* No authorized counter sets, nothing to count/sample */ 224 /* No authorized counter sets, nothing to count/sample */
218 if (!event->hw.config_base) { 225 if (!event->hw.config_base) {