mirror of https://gitee.com/openkylin/linux.git
oprofile/x86: protect cpu hotplug sections
This patch reworks oprofile cpu hotplug code as follows: Introduce ctr_running variable to check, if counters are running or not. The state must be known for taking a cpu on or offline and when switching counters during counter multiplexing. Protect on_each_cpu() sections with get_online_cpus()/put_online_cpu() functions. This is necessary if notifiers or states are modified. Within these sections the cpu mask may not change. Switch only between counters in nmi_cpu_switch(), if counters are running. Otherwise the switch may restart a counter though they are disabled. Add nmi_cpu_setup() and nmi_cpu_shutdown() to cpu hotplug code. The function must also be called to avoid uninitialzed counter usage. Cc: Andi Kleen <andi@firstfloor.org> Signed-off-by: Robert Richter <robert.richter@amd.com>
This commit is contained in:
parent
216f3d9b4e
commit
6ae56b55bc
|
@ -31,8 +31,9 @@ static struct op_x86_model_spec *model;
|
|||
static DEFINE_PER_CPU(struct op_msrs, cpu_msrs);
|
||||
static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
|
||||
|
||||
/* 0 == registered but off, 1 == registered and on */
|
||||
static int nmi_enabled = 0;
|
||||
/* must be protected with get_online_cpus()/put_online_cpus(): */
|
||||
static int nmi_enabled;
|
||||
static int ctr_running;
|
||||
|
||||
struct op_counter_config counter_config[OP_MAX_COUNTER];
|
||||
|
||||
|
@ -103,7 +104,10 @@ static void nmi_cpu_start(void *dummy)
|
|||
|
||||
static int nmi_start(void)
|
||||
{
|
||||
get_online_cpus();
|
||||
on_each_cpu(nmi_cpu_start, NULL, 1);
|
||||
ctr_running = 1;
|
||||
put_online_cpus();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -118,7 +122,10 @@ static void nmi_cpu_stop(void *dummy)
|
|||
|
||||
static void nmi_stop(void)
|
||||
{
|
||||
get_online_cpus();
|
||||
on_each_cpu(nmi_cpu_stop, NULL, 1);
|
||||
ctr_running = 0;
|
||||
put_online_cpus();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
|
||||
|
@ -258,7 +265,10 @@ static int nmi_switch_event(void)
|
|||
if (nmi_multiplex_on() < 0)
|
||||
return -EINVAL; /* not necessary */
|
||||
|
||||
on_each_cpu(nmi_cpu_switch, NULL, 1);
|
||||
get_online_cpus();
|
||||
if (ctr_running)
|
||||
on_each_cpu(nmi_cpu_switch, NULL, 1);
|
||||
put_online_cpus();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -386,8 +396,11 @@ static int nmi_setup(void)
|
|||
if (err)
|
||||
goto fail;
|
||||
|
||||
get_online_cpus();
|
||||
on_each_cpu(nmi_cpu_setup, NULL, 1);
|
||||
nmi_enabled = 1;
|
||||
put_online_cpus();
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
free_msrs();
|
||||
|
@ -433,8 +446,11 @@ static void nmi_shutdown(void)
|
|||
{
|
||||
struct op_msrs *msrs;
|
||||
|
||||
nmi_enabled = 0;
|
||||
get_online_cpus();
|
||||
on_each_cpu(nmi_cpu_shutdown, NULL, 1);
|
||||
nmi_enabled = 0;
|
||||
ctr_running = 0;
|
||||
put_online_cpus();
|
||||
unregister_die_notifier(&profile_exceptions_nb);
|
||||
msrs = &get_cpu_var(cpu_msrs);
|
||||
model->shutdown(msrs);
|
||||
|
@ -442,6 +458,22 @@ static void nmi_shutdown(void)
|
|||
put_cpu_var(cpu_msrs);
|
||||
}
|
||||
|
||||
static void nmi_cpu_up(void *dummy)
|
||||
{
|
||||
if (nmi_enabled)
|
||||
nmi_cpu_setup(dummy);
|
||||
if (ctr_running)
|
||||
nmi_cpu_start(dummy);
|
||||
}
|
||||
|
||||
static void nmi_cpu_down(void *dummy)
|
||||
{
|
||||
if (ctr_running)
|
||||
nmi_cpu_stop(dummy);
|
||||
if (nmi_enabled)
|
||||
nmi_cpu_shutdown(dummy);
|
||||
}
|
||||
|
||||
static int nmi_create_files(struct super_block *sb, struct dentry *root)
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -478,10 +510,10 @@ static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action,
|
|||
switch (action) {
|
||||
case CPU_DOWN_FAILED:
|
||||
case CPU_ONLINE:
|
||||
smp_call_function_single(cpu, nmi_cpu_start, NULL, 0);
|
||||
smp_call_function_single(cpu, nmi_cpu_up, NULL, 0);
|
||||
break;
|
||||
case CPU_DOWN_PREPARE:
|
||||
smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1);
|
||||
smp_call_function_single(cpu, nmi_cpu_down, NULL, 1);
|
||||
break;
|
||||
}
|
||||
return NOTIFY_DONE;
|
||||
|
@ -699,7 +731,11 @@ int __init op_nmi_init(struct oprofile_operations *ops)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
get_online_cpus();
|
||||
register_cpu_notifier(&oprofile_cpu_nb);
|
||||
nmi_enabled = 0;
|
||||
ctr_running = 0;
|
||||
put_online_cpus();
|
||||
|
||||
/* default values, can be overwritten by model */
|
||||
ops->create_files = nmi_create_files;
|
||||
|
@ -729,7 +765,11 @@ void op_nmi_exit(void)
|
|||
{
|
||||
if (using_nmi) {
|
||||
exit_sysfs();
|
||||
get_online_cpus();
|
||||
unregister_cpu_notifier(&oprofile_cpu_nb);
|
||||
nmi_enabled = 0;
|
||||
ctr_running = 0;
|
||||
put_online_cpus();
|
||||
}
|
||||
if (model->exit)
|
||||
model->exit();
|
||||
|
|
Loading…
Reference in New Issue