Enable and disable osnoise/timerlat thread during on CPU hotplug online and offline operations respectivelly. Cc: Jonathan Corbet <corbet@xxxxxxx> Cc: Steven Rostedt <rostedt@xxxxxxxxxxx> Cc: Ingo Molnar <mingo@xxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Cc: Alexandre Chartre <alexandre.chartre@xxxxxxxxxx> Cc: Clark Willaims <williams@xxxxxxxxxx> Cc: John Kacur <jkacur@xxxxxxxxxx> Cc: Juri Lelli <juri.lelli@xxxxxxxxxx> Cc: Borislav Petkov <bp@xxxxxxxxx> Cc: "H. Peter Anvin" <hpa@xxxxxxxxx> Cc: x86@xxxxxxxxxx Cc: linux-doc@xxxxxxxxxxxxxxx Cc: linux-kernel@xxxxxxxxxxxxxxx Signed-off-by: Daniel Bristot de Oliveira <bristot@xxxxxxxxxx> --- kernel/trace/trace_osnoise.c | 165 ++++++++++++++++++++++++++++------- 1 file changed, 135 insertions(+), 30 deletions(-) diff --git a/kernel/trace/trace_osnoise.c b/kernel/trace/trace_osnoise.c index f4b1330ac89d..e8a63af1aeb6 100644 --- a/kernel/trace/trace_osnoise.c +++ b/kernel/trace/trace_osnoise.c @@ -1414,22 +1414,67 @@ static int timerlat_main(void *data) #endif /* CONFIG_TIMERLAT_TRACER */ /* - * stop_per_cpu_kthread - stop per-cpu threads + * stop_kthread - stop a workload thread + */ +static void stop_kthread(unsigned int cpu) +{ + struct task_struct *kthread; + + kthread = per_cpu(per_cpu_osnoise_var, cpu).kthread; + if (kthread) + kthread_stop(kthread); + per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL; +} + +/* + * stop_per_cpu_kthread - Stop per-cpu threads * * Stop the osnoise sampling htread. Use this on unload and at system * shutdown. */ static void stop_per_cpu_kthreads(void) { - struct task_struct *kthread; int cpu; - for_each_online_cpu(cpu) { - kthread = per_cpu(per_cpu_osnoise_var, cpu).kthread; - if (kthread) - kthread_stop(kthread); - per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL; + get_online_cpus(); + + for_each_online_cpu(cpu) + stop_kthread(cpu); + + put_online_cpus(); +} + +/* + * start_kthread - Start a workload tread + */ +static int start_kthread(unsigned int cpu) +{ + struct task_struct *kthread; + void *main = osnoise_main; + char comm[24]; + +#ifdef CONFIG_TIMERLAT_TRACER + if (osnoise_data.timerlat_tracer) { + snprintf(comm, 24, "timerlat/%d", cpu); + main = timerlat_main; + } else { + snprintf(comm, 24, "osnoise/%d", cpu); } +#else + snprintf(comm, 24, "osnoise/%d", cpu); +#endif + kthread = kthread_create_on_cpu(main, NULL, cpu, comm); + + if (IS_ERR(kthread)) { + pr_err(BANNER "could not start sampling thread\n"); + stop_per_cpu_kthreads(); + return -ENOMEM; + } + + per_cpu(per_cpu_osnoise_var, cpu).kthread = kthread; + wake_up_process(kthread); + + return 0; } /* @@ -1441,9 +1486,7 @@ static void stop_per_cpu_kthreads(void) static int start_per_cpu_kthreads(struct trace_array *tr) { struct cpumask *current_mask = &save_cpumask; - struct task_struct *kthread; - char comm[24]; - void *main = osnoise_main; + int retval; int cpu; get_online_cpus(); @@ -1455,37 +1498,91 @@ static int start_per_cpu_kthreads(struct trace_array *tr) * And the CPU is online. */ cpumask_and(current_mask, cpu_online_mask, current_mask); - put_online_cpus(); - for_each_online_cpu(cpu) + for_each_possible_cpu(cpu) per_cpu(per_cpu_osnoise_var, cpu).kthread = NULL; for_each_cpu(cpu, current_mask) { -#ifdef CONFIG_TIMERLAT_TRACER - if (osnoise_data.timerlat_tracer) { - snprintf(comm, 24, "timerlat/%d", cpu); - main = timerlat_main; - } else { - snprintf(comm, 24, "osnoise/%d", cpu); - } -#else - snprintf(comm, 24, "osnoise/%d", cpu); -#endif - kthread = kthread_create_on_cpu(main, NULL, cpu, comm); - - if (IS_ERR(kthread)) { - pr_err(BANNER "could not start sampling thread\n"); + retval = start_kthread(cpu); + if (retval) { stop_per_cpu_kthreads(); - return -ENOMEM; + return retval; } - - per_cpu(per_cpu_osnoise_var, cpu).kthread = kthread; - wake_up_process(kthread); } + put_online_cpus(); + return 0; } +#ifdef CONFIG_HOTPLUG_CPU +static void osnoise_hotplug_workfn(struct work_struct *dummy) +{ + struct trace_array *tr = osnoise_trace; + unsigned int cpu = smp_processor_id(); + + + mutex_lock(&trace_types_lock); + + if (!osnoise_busy) + goto out_unlock_trace; + + mutex_lock(&interface_lock); + get_online_cpus(); + + if (!cpumask_test_cpu(cpu, &osnoise_cpumask)) + goto out_unlock; + + if (!cpumask_test_cpu(cpu, tr->tracing_cpumask)) + goto out_unlock; + + start_kthread(cpu); + +out_unlock: + put_online_cpus(); + mutex_unlock(&interface_lock); +out_unlock_trace: + mutex_unlock(&trace_types_lock); +} + +static DECLARE_WORK(osnoise_hotplug_work, osnoise_hotplug_workfn); + +/* + * osnoise_cpu_init - CPU hotplug online callback function + */ +static int osnoise_cpu_init(unsigned int cpu) +{ + schedule_work_on(cpu, &osnoise_hotplug_work); + return 0; +} + +/* + * osnoise_cpu_die - CPU hotplug offline callback function + */ +static int osnoise_cpu_die(unsigned int cpu) +{ + stop_kthread(cpu); + return 0; +} + +static void osnoise_init_hotplug_support(void) +{ + int ret; + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "trace/osnoise:online", + osnoise_cpu_init, osnoise_cpu_die); + if (ret < 0) + pr_warn(BANNER "Error to init cpu hotplug support\n"); + + return; +} +#else /* CONFIG_HOTPLUG_CPU */ +static void osnoise_init_hotplug_support(void) +{ + return 0; +} +#endif /* CONFIG_HOTPLUG_CPU */ + /* * osnoise_cpus_read - Read function for reading the "cpus" file * @filp: The active open file structure @@ -1581,7 +1678,14 @@ osnoise_cpus_write(struct file *filp, const char __user *ubuf, size_t count, osnoise_tracer_stop(tr); mutex_lock(&interface_lock); + /* + * osnoise_cpumask is read by CPU hotplug operations. + */ + get_online_cpus(); + cpumask_copy(&osnoise_cpumask, osnoise_cpumask_new); + + put_online_cpus(); mutex_unlock(&interface_lock); if (running) @@ -1938,6 +2042,7 @@ __init static int init_osnoise_tracer(void) return ret; } #endif + osnoise_init_hotplug_support(); init_tracefs(); -- 2.31.1