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:
committed by
Rafael J. Wysocki
parent
22e7551eb6
commit
b9d10be7a8
@@ -178,14 +178,17 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
|
|||||||
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
|
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
cpu_maps_update_begin();
|
||||||
|
cpu_hotplug_begin();
|
||||||
|
|
||||||
ret = acpi_map_lsapic(pr->handle, &pr->id);
|
ret = acpi_map_lsapic(pr->handle, &pr->id);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
ret = arch_register_cpu(pr->id);
|
ret = arch_register_cpu(pr->id);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
acpi_unmap_lsapic(pr->id);
|
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_info("CPU%d has been hot-added\n", pr->id);
|
||||||
pr->flags.need_hotplug_init = 1;
|
pr->flags.need_hotplug_init = 1;
|
||||||
return 0;
|
|
||||||
|
out:
|
||||||
|
cpu_hotplug_done();
|
||||||
|
cpu_maps_update_done();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline int acpi_processor_hotadd_init(struct acpi_processor *pr)
|
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(processor_device_array, pr->id) = NULL;
|
||||||
per_cpu(processors, pr->id) = NULL;
|
per_cpu(processors, pr->id) = NULL;
|
||||||
|
|
||||||
|
cpu_maps_update_begin();
|
||||||
|
cpu_hotplug_begin();
|
||||||
|
|
||||||
/* Remove the CPU. */
|
/* Remove the CPU. */
|
||||||
get_online_cpus();
|
|
||||||
arch_unregister_cpu(pr->id);
|
arch_unregister_cpu(pr->id);
|
||||||
acpi_unmap_lsapic(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));
|
try_offline_node(cpu_to_node(pr->id));
|
||||||
|
|
||||||
|
@@ -172,6 +172,8 @@ extern struct bus_type cpu_subsys;
|
|||||||
#ifdef CONFIG_HOTPLUG_CPU
|
#ifdef CONFIG_HOTPLUG_CPU
|
||||||
/* Stop CPUs going up and down. */
|
/* 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 get_online_cpus(void);
|
||||||
extern void put_online_cpus(void);
|
extern void put_online_cpus(void);
|
||||||
extern void cpu_hotplug_disable(void);
|
extern void cpu_hotplug_disable(void);
|
||||||
@@ -197,6 +199,8 @@ static inline void cpu_hotplug_driver_unlock(void)
|
|||||||
|
|
||||||
#else /* CONFIG_HOTPLUG_CPU */
|
#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 get_online_cpus() do { } while (0)
|
||||||
#define put_online_cpus() do { } while (0)
|
#define put_online_cpus() do { } while (0)
|
||||||
#define cpu_hotplug_disable() 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.
|
* 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;
|
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;
|
cpu_hotplug.active_writer = NULL;
|
||||||
mutex_unlock(&cpu_hotplug.lock);
|
mutex_unlock(&cpu_hotplug.lock);
|
||||||
@@ -154,10 +154,7 @@ void cpu_hotplug_enable(void)
|
|||||||
cpu_maps_update_done();
|
cpu_maps_update_done();
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* #if CONFIG_HOTPLUG_CPU */
|
#endif /* CONFIG_HOTPLUG_CPU */
|
||||||
static void cpu_hotplug_begin(void) {}
|
|
||||||
static void cpu_hotplug_done(void) {}
|
|
||||||
#endif /* #else #if CONFIG_HOTPLUG_CPU */
|
|
||||||
|
|
||||||
/* Need to know about CPUs going up/down? */
|
/* Need to know about CPUs going up/down? */
|
||||||
int __ref register_cpu_notifier(struct notifier_block *nb)
|
int __ref register_cpu_notifier(struct notifier_block *nb)
|
||||||
|
Reference in New Issue
Block a user