Make processor module unloading safe
PATCH 1/1 Make processor module unloading safe
Hi,pm_idle isn’t a per-cpu data. In MP case, it is possible one CPU (eg. the boot CPU) changed pm_idle, but other CPUs it’s not ready for it. The ACPI module is such a case, CPU 0 changed pm_idle, which caused all CPUs start using pm_idle, but other CPUs actually aren’t ready (their idle information isn't initialized). The worse case is unloading ACPI module. If non-boot CPU first freed their idle information, current code doesn’t know it, and the CPUs possibly will use the freed memory again till boot cpu restore pm_idle. This patch tries to fix the gaps.
Makes pm_idle a per-cpu data might be a better idea, but it’s platform independent, so I didn't touch it but just fix the ACPI issue.
Thanks,
Shaohua
---
linux-2.6.13-root/arch/i386/kernel/apm.c | 2 - linux-2.6.13-root/arch/i386/kernel/process.c | 4 +-- linux-2.6.13-root/arch/ia64/kernel/process.c | 4 +-- linux-2.6.13-root/arch/x86_64/kernel/process.c | 4 +-- linux-2.6.13-root/drivers/acpi/processor_idle.c | 26 +++++++++++++++++++----- linux-2.6.13-root/include/asm-i386/system.h | 3 +- linux-2.6.13-root/include/asm-ia64/system.h | 3 +- linux-2.6.13-root/include/asm-x86_64/system.h | 3 +- linux-2.6.13-root/kernel/sched.c | 1 9 files changed, 35 insertions(+), 15 deletions(-)
drivers/acpi/processor_idle.c renamed from drivers/acpi/processor_idle.c~remove_cpu_idle_save +21 -5
@@ -75,6 +75,8 @@ module_param(bm_history, uint, 0644);Power Management -------------------------------------------------------------------------- */ +static void acpi_processor_idle (void ); +static DEFINE_PER_CPU(void (*)(void), acpi_cpu_idle);/* * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. * For now disable this. Probably a bug somewhere else.
@@ -170,7 +172,7 @@ acpi_processor_power_activate (static atomic_t c3_cpu_count; -static void acpi_processor_idle (void ) +static void __acpi_processor_idle (void ) {struct acpi_processor *pr =NULL ;struct acpi_processor_cx *cx =NULL ;
@@ -891,13 +893,13 @@ int acpi_processor_cst_has_changed (strureturn_VALUE (-ENODEV );/* Fall back to the default idle loop */ - pm_idle = pm_idle_save; -synchronize_sched ();/* Relies on interrupts forcing exit from idle. */ +per_cpu (acpi_cpu_idle, pr->id) =NULL ; +cpu_idle_wait (cpumask_of_cpu (pr->id)); pr->flags.power =0 ; result =acpi_processor_get_power_info (pr);if ((pr->flags.power ==1 ) && (pr->flags.power_setup_done)) - pm_idle = acpi_processor_idle; +per_cpu (acpi_cpu_idle, pr->id) = __acpi_processor_idle;return_VALUE (result); }
@@ -983,6 +985,17 @@ static struct file_operations acpi_proce .release = single_release, }; +static void acpi_processor_idle (void ) +{ +int cpu =raw_smp_processor_id (); +if (per_cpu (acpi_cpu_idle, cpu)) +per_cpu (acpi_cpu_idle, cpu)(); +else if (pm_idle_save) +pm_idle_save (); +else +safe_halt (); +} +int acpi_processor_power_init (struct acpi_processor *pr,struct acpi_device *device) {acpi_status status =0 ;
@@ -1046,6 +1059,7 @@ int acpi_processor_power_init(struct acp } pr->flags.power_setup_done =1 ; +per_cpu (acpi_cpu_idle, pr->id) = __acpi_processor_idle;return_VALUE (0 ); }
@@ -1055,6 +1069,8 @@ int acpi_processor_power_exit(struct acpACPI_FUNCTION_TRACE ("acpi_processor_power_exit" ); pr->flags.power_setup_done =0 ; +per_cpu (acpi_cpu_idle, pr->id) =NULL ; +cpu_idle_wait (cpumask_of_cpu (pr->id));if (acpi_device_dir (device))remove_proc_entry (ACPI_PROCESSOR_FILE_POWER ,acpi_device_dir (device));
@@ -1068,7 +1084,7 @@ int acpi_processor_power_exit(struct acp* (pm_idle), Wait for all processors to update cached/local * copies of pm_idle before proceeding. */ -cpu_idle_wait (); +cpu_idle_wait (cpu_online_map); }return_VALUE (0 );
arch/i386/kernel/process.c renamed from arch/i386/kernel/process.c~remove_cpu_idle_save +2 -2
@@ -207,7 +207,7 @@ void cpu_idle(void) } } -void cpu_idle_wait (void ) +void cpu_idle_wait (cpumask_t wait) {unsigned int cpu, this_cpu =get_cpu ();cpumask_t map;
@@ -216,7 +216,7 @@ void cpu_idle_wait(void)put_cpu ();cpus_clear (map); -for_each_online_cpu (cpu) { +for_each_cpu_mask (cpu, wait) {per_cpu (cpu_idle_state, cpu) =1 ;cpu_set (cpu, map); }
arch/x86_64/kernel/process.c renamed from arch/x86_64/kernel/process.c~remove_cpu_idle_save +2 -2
@@ -128,7 +128,7 @@ static void poll_idle (void) } } -void cpu_idle_wait (void ) +void cpu_idle_wait (cpumask_t wait) {unsigned int cpu, this_cpu =get_cpu ();cpumask_t map;
@@ -137,7 +137,7 @@ void cpu_idle_wait(void)put_cpu ();cpus_clear (map); -for_each_online_cpu (cpu) { +for_each_cpu_mask (cpu, wait) {per_cpu (cpu_idle_state, cpu) =1 ;cpu_set (cpu, map); }
arch/ia64/kernel/process.c renamed from arch/ia64/kernel/process.c~remove_cpu_idle_save +2 -2
@@ -231,7 +231,7 @@ static inline void play_dead(void) }#endif /* CONFIG_HOTPLUG_CPU */ -void cpu_idle_wait (void ) +void cpu_idle_wait (cpumask_t wait) {unsigned int cpu, this_cpu =get_cpu ();cpumask_t map;
@@ -240,7 +240,7 @@ void cpu_idle_wait(void)put_cpu ();cpus_clear (map); -for_each_online_cpu (cpu) { +for_each_cpu_mask (cpu, wait) {per_cpu (cpu_idle_state, cpu) =1 ;cpu_set (cpu, map); }
include/asm-x86_64/system.h renamed from include/asm-x86_64/system.h~remove_cpu_idle_save +2 -1
@@ -326,7 +326,8 @@ static inline unsigned long __cmpxchg(vo/* For spinlocks etc */ #define local_irq_save(x) do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0) -void cpu_idle_wait (void ); +#include <linux/cpumask.h> +void cpu_idle_wait (cpumask_t wait);/* * disable hlt during certain critical i/o operations
include/asm-i386/system.h renamed from include/asm-i386/system.h~remove_cpu_idle_save +2 -1
@@ -466,7 +466,8 @@ void disable_hlt(void);void enable_hlt (void );extern int es7000_plat; -void cpu_idle_wait (void ); +#include <linux/cpumask.h> +void cpu_idle_wait (cpumask_t wait);extern unsigned long arch_align_stack (unsigned long sp);
include/asm-ia64/system.h renamed from include/asm-ia64/system.h~remove_cpu_idle_save +2 -1
@@ -276,7 +276,8 @@ extern void ia64_load_extra (struct task#define ia64_platform_is (x) (strcmp(x, platform_name) == 0) -void cpu_idle_wait (void ); +#include <linux/cpumask.h> +void cpu_idle_wait (cpumask_t wait);#define arch_align_stack (x) (x)
arch/i386/kernel/apm.c renamed from arch/i386/kernel/apm.c~remove_cpu_idle_save +1 -1
@@ -2370,7 +2370,7 @@ static void __exit apm_exit(void)* (pm_idle), Wait for all processors to update cached/local * copies of pm_idle before proceeding. */ -cpu_idle_wait (); +cpu_idle_wait (cpu_online_map); }if (((apm_info.bios.flags &APM_BIOS_DISENGAGED ) ==0 ) && (apm_info.connection_version >0x0100 )) {
kernel/sched.c renamed from kernel/sched.c~remove_cpu_idle_save +1 -0
@@ -3771,6 +3771,7 @@ EXPORT_SYMBOL(cpu_present_map);#ifndef CONFIG_SMP cpumask_t cpu_online_map =CPU_MASK_ALL ; +EXPORT_SYMBOL (cpu_online_map);cpumask_t cpu_possible_map =CPU_MASK_ALL ;#endif
_
-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf