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: Gary King <gking@nvidia.com> Acked-by: Nicolas Pitre <nico.as.pitre@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
b92b361213
commit
831e8047eb
@ -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)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user