On -rt we protect per-cpu state by locks instead of disabling preemption/irqs. This keeps all the code preemptible at the cost of possible remote memory access. The race was that cpu-hotplug - which assumes to be cpu local and non- preemptible, didn't take the per-cpu lock. This also means that the normal lock acquire needs to be aware of cpus getting off-lined while its waiting. Signed-off-by: Peter Zijlstra --- mm/page_alloc.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) Index: linux-2.6.24.7.noarch/mm/page_alloc.c =================================================================== --- linux-2.6.24.7.noarch.orig/mm/page_alloc.c +++ linux-2.6.24.7.noarch/mm/page_alloc.c @@ -176,7 +176,19 @@ static inline void __lock_cpu_pcp(unsign static inline void lock_cpu_pcp(unsigned long *flags, int *this_cpu) { #ifdef CONFIG_PREEMPT_RT - (void)get_cpu_var_locked(pcp_locks, this_cpu); + spinlock_t *lock; + int cpu; + +again: + cpu = raw_smp_processor_id(); + lock = &__get_cpu_lock(pcp_locks, cpu); + + spin_lock(lock); + if (unlikely(!cpu_online(cpu))) { + spin_unlock(lock); + goto again; + } + *this_cpu = cpu; flags = 0; #else local_irq_save(*flags); @@ -2781,12 +2793,17 @@ static inline void free_zone_pagesets(in struct zone *zone; for_each_zone(zone) { - struct per_cpu_pageset *pset = zone_pcp(zone, cpu); + struct per_cpu_pageset *pset; + unsigned long flags; + + __lock_cpu_pcp(&flags, cpu); + pset = zone_pcp(zone, cpu); + zone_pcp(zone, cpu) = NULL; + unlock_cpu_pcp(flags, cpu); /* Free per_cpu_pageset if it is slab allocated */ if (pset != &boot_pageset[cpu]) kfree(pset); - zone_pcp(zone, cpu) = NULL; } } @@ -2812,6 +2829,7 @@ static int __cpuinit pageset_cpuup_callb default: break; } + return ret; } -- -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/