During CPU down operation RCU callbacks are scheduled to finish
off some actions later as soon as CPU is fully dead (the same applies
to CPU up operation in case error path is taken). If in the same grace
period another CPU up operation is performed on the same CPU, RCU callback
will be called later on a CPU in a potentially wrong (already up again
instead of still being down) state leading to eventual state inconsistency
and/or crash.
In order to avoid it - flush RCU callbacks explicitly before starting the
next CPU up/down operation.
Signed-off-by: Igor Druzhinin <igor.druzhinin@citrix.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
cpufreq_add_cpu(0);
enable_cpu:
- rcu_barrier();
mtrr_aps_sync_begin();
enable_nonboot_cpus();
mtrr_aps_sync_end();
unsigned int cpu = (unsigned long)data;
int ret = cpu_up(cpu);
+ /* Have one more go on EBUSY. */
if ( ret == -EBUSY )
- {
- /* On EBUSY, flush RCU work and have one more go. */
- rcu_barrier();
ret = cpu_up(cpu);
- }
if ( !ret && !opt_smt &&
cpu_data[cpu].compute_unit_id == INVALID_CUID &&
{
int cpu = (unsigned long)data;
int ret = cpu_down(cpu);
+ /* Have one more go on EBUSY. */
if ( ret == -EBUSY )
- {
- /* On EBUSY, flush RCU work and have one more go. */
- rcu_barrier();
ret = cpu_down(cpu);
- }
return ret;
}
#include <xen/init.h>
#include <xen/sched.h>
#include <xen/stop_machine.h>
+#include <xen/rcupdate.h>
unsigned int __read_mostly nr_cpu_ids = NR_CPUS;
#ifndef nr_cpumask_bits
void cpu_hotplug_begin(void)
{
+ rcu_barrier();
write_lock(&cpu_add_remove_lock);
}