ACPI / processor: Acquire writer lock to update CPU maps
CPU system maps are protected with reader/writer locks. The reader lock, get_online_cpus(), assures that the maps are not updated while holding the lock. The writer lock, cpu_hotplug_begin(), is used to udpate the cpu maps along with cpu_maps_update_begin(). However, the ACPI processor handler updates the cpu maps without holding the the writer lock. acpi_map_lsapic() is called from acpi_processor_hotadd_init() to update cpu_possible_mask and cpu_present_mask. acpi_unmap_lsapic() is called from acpi_processor_remove() to update cpu_possible_mask. Currently, they are either unprotected or protected with the reader lock, which is not correct. For example, the get_online_cpus() below is supposed to assure that cpu_possible_mask is not changed while the code is iterating with for_each_possible_cpu(). get_online_cpus(); for_each_possible_cpu(cpu) { : } put_online_cpus(); However, this lock has no protection with CPU hotplug since the ACPI processor handler does not use the writer lock when it updates cpu_possible_mask. The reader lock does not serialize within the readers. This patch protects them with the writer lock with cpu_hotplug_begin() along with cpu_maps_update_begin(), which must be held before calling cpu_hotplug_begin(). It also protects arch_register_cpu() / arch_unregister_cpu(), which creates / deletes a sysfs cpu device interface. For this purpose it changes cpu_hotplug_begin() and cpu_hotplug_done() to global and exports them in cpu.h. Signed-off-by: Toshi Kani <toshi.kani@hp.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
22e7551eb6
commit
b9d10be7a8
3 changed files with 23 additions and 11 deletions
|
@ -178,14 +178,17 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
|
|||
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
|
||||
return -ENODEV;
|
||||
|
||||
cpu_maps_update_begin();
|
||||
cpu_hotplug_begin();
|
||||
|
||||
ret = acpi_map_lsapic(pr->handle, &pr->id);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
ret = arch_register_cpu(pr->id);
|
||||
if (ret) {
|
||||
acpi_unmap_lsapic(pr->id);
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -195,7 +198,11 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
|
|||
*/
|
||||
pr_info("CPU%d has been hot-added\n", pr->id);
|
||||
pr->flags.need_hotplug_init = 1;
|
||||
return 0;
|
||||
|
||||
out:
|
||||
cpu_hotplug_done();
|
||||
cpu_maps_update_done();
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static inline int acpi_processor_hotadd_init(struct acpi_processor *pr)
|
||||
|
@ -452,11 +459,15 @@ static void acpi_processor_remove(struct acpi_device *device)
|
|||
per_cpu(processor_device_array, pr->id) = NULL;
|
||||
per_cpu(processors, pr->id) = NULL;
|
||||
|
||||
cpu_maps_update_begin();
|
||||
cpu_hotplug_begin();
|
||||
|
||||
/* Remove the CPU. */
|
||||
get_online_cpus();
|
||||
arch_unregister_cpu(pr->id);
|
||||
acpi_unmap_lsapic(pr->id);
|
||||
put_online_cpus();
|
||||
|
||||
cpu_hotplug_done();
|
||||
cpu_maps_update_done();
|
||||
|
||||
try_offline_node(cpu_to_node(pr->id));
|
||||
|
||||
|
|
|
@ -172,6 +172,8 @@ extern struct bus_type cpu_subsys;
|
|||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/* Stop CPUs going up and down. */
|
||||
|
||||
extern void cpu_hotplug_begin(void);
|
||||
extern void cpu_hotplug_done(void);
|
||||
extern void get_online_cpus(void);
|
||||
extern void put_online_cpus(void);
|
||||
extern void cpu_hotplug_disable(void);
|
||||
|
@ -197,6 +199,8 @@ static inline void cpu_hotplug_driver_unlock(void)
|
|||
|
||||
#else /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
static inline void cpu_hotplug_begin(void) {}
|
||||
static inline void cpu_hotplug_done(void) {}
|
||||
#define get_online_cpus() do { } while (0)
|
||||
#define put_online_cpus() do { } while (0)
|
||||
#define cpu_hotplug_disable() do { } while (0)
|
||||
|
|
|
@ -113,7 +113,7 @@ EXPORT_SYMBOL_GPL(put_online_cpus);
|
|||
* get_online_cpus() not an api which is called all that often.
|
||||
*
|
||||
*/
|
||||
static void cpu_hotplug_begin(void)
|
||||
void cpu_hotplug_begin(void)
|
||||
{
|
||||
cpu_hotplug.active_writer = current;
|
||||
|
||||
|
@ -127,7 +127,7 @@ static void cpu_hotplug_begin(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void cpu_hotplug_done(void)
|
||||
void cpu_hotplug_done(void)
|
||||
{
|
||||
cpu_hotplug.active_writer = NULL;
|
||||
mutex_unlock(&cpu_hotplug.lock);
|
||||
|
@ -154,10 +154,7 @@ void cpu_hotplug_enable(void)
|
|||
cpu_maps_update_done();
|
||||
}
|
||||
|
||||
#else /* #if CONFIG_HOTPLUG_CPU */
|
||||
static void cpu_hotplug_begin(void) {}
|
||||
static void cpu_hotplug_done(void) {}
|
||||
#endif /* #else #if CONFIG_HOTPLUG_CPU */
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
/* Need to know about CPUs going up/down? */
|
||||
int __ref register_cpu_notifier(struct notifier_block *nb)
|
||||
|
|
Loading…
Reference in a new issue