summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Howe <ahowe@nvidia.com>2010-07-23 20:00:47 +0300
committerGary King <gking@nvidia.com>2010-07-23 20:41:00 -0700
commitcab2cf99b1e377918629f0b701a438d01f5edefa (patch)
treeb5303584f0bff24d2ee935922cd6d06ac33c80d0
parent477eedc3c9586ca1ca466d1bbcf3c998e33a3746 (diff)
[ARM] Fix race condition 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(). Change-Id: I205a85ebecaedb430860462012d0571b83f08adc Reviewed-on: http://git-master/r/4342 Reviewed-by: Janne Hellsten <jhellsten@nvidia.com> Reviewed-by: Gary King <gking@nvidia.com> Tested-by: Gary King <gking@nvidia.com>
-rw-r--r--arch/arm/mm/highmem.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index 77b030f5ec09..6c5ccecdbbf3 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -154,19 +154,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)) {