提交 831e8047 编写于 作者: G Gary King 提交者: Russell King

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 <ahowe@nvidia.com>
Signed-off-by: NGary King <gking@nvidia.com>
Acked-by: NNicolas Pitre <nico.as.pitre@linaro.org>
Signed-off-by: NRussell King <rmk+kernel@arm.linux.org.uk>
上级 b92b3612
...@@ -163,19 +163,22 @@ static DEFINE_PER_CPU(int, kmap_high_l1_vipt_depth); ...@@ -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) void *kmap_high_l1_vipt(struct page *page, pte_t *saved_pte)
{ {
unsigned int idx, cpu = smp_processor_id(); unsigned int idx, cpu;
int *depth = &per_cpu(kmap_high_l1_vipt_depth, cpu); int *depth;
unsigned long vaddr, flags; unsigned long vaddr, flags;
pte_t pte, *ptep; 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; idx = KM_L1_CACHE + KM_TYPE_NR * cpu;
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
ptep = TOP_PTE(vaddr); ptep = TOP_PTE(vaddr);
pte = mk_pte(page, kmap_prot); pte = mk_pte(page, kmap_prot);
if (!in_interrupt())
preempt_disable();
raw_local_irq_save(flags); raw_local_irq_save(flags);
(*depth)++; (*depth)++;
if (pte_val(*ptep) == pte_val(pte)) { if (pte_val(*ptep) == pte_val(pte)) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册