From: Gary King Date: Thu, 29 Jul 2010 16:37:20 +0000 (+0100) Subject: ARM: 6279/1: highmem: fix SMP preemption bug in kmap_high_l1_vipt X-Git-Tag: v2.6.35~2^2~4 X-Git-Url: http://bbs.cooldavid.org/git/?p=net-next-2.6.git;a=commitdiff_plain;h=831e8047eb2af310184a9d4d9e749f3de119ae39 ARM: 6279/1: highmem: fix SMP preemption bug in kmap_high_l1_vipt smp_processor_id() must not be called from a preemptible context (this is checked by CONFIG_DEBUG_PREEMPT). kmap_high_l1_vipt() was doing so. This lead to a problem where the wrong per_cpu kmap_high_l1_vipt_depth could be incremented, causing a BUG_ON(*depth <= 0); in kunmap_high_l1_vipt(). The solution is to move the call to smp_processor_id() after the call to preempt_disable(). Originally by: Andrew Howe Signed-off-by: Gary King Acked-by: Nicolas Pitre Signed-off-by: Russell King --- diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c index 086816b205b..6ab244062b4 100644 --- a/arch/arm/mm/highmem.c +++ b/arch/arm/mm/highmem.c @@ -163,19 +163,22 @@ static DEFINE_PER_CPU(int, kmap_high_l1_vipt_depth); void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte) { - unsigned int idx, cpu = smp_processor_id(); - int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu); + unsigned int idx, cpu; + int *depth; unsigned long vaddr, flags; pte_t pte, *ptep; + if (!in_interrupt()) + preempt_disable(); + + cpu = smp_processor_id(); + depth = &per_cpu(kmap_high_l1_vipt_depth, cpu); + idx = KM_L1_CACHE + KM_TYPE_NR * cpu; vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); ptep = TOP_PTE(vaddr); pte = mk_pte(page, kmap_prot); - if (!in_interrupt()) - preempt_disable(); - raw_local_irq_save(flags); (*depth)++; if (pte_val(*ptep) == pte_val(pte)) {