mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
powerpc/mm/mce: Keep irqs disabled during lockless page table walk
[ Upstream commitd9101bfa6a] __find_linux_mm_pte() returns a page table entry pointer after walking the page table without holding locks. To make it safe against a THP split and/or collapse, we disable interrupts around the lockless page table walk. However we need to keep interrupts disabled as long as we use the page table entry pointer that is returned. Fix addr_to_pfn() to do that. Fixes:ba41e1e1cc("powerpc/mce: Hookup derror (load/store) UE errors") Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com> [mpe: Rearrange code slightly and tweak change log wording] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20190918145328.28602-1-aneesh.kumar@linux.ibm.com Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
12ed084d51
commit
90de8a2f70
@@ -40,7 +40,7 @@ static unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
|
||||
{
|
||||
pte_t *ptep;
|
||||
unsigned int shift;
|
||||
unsigned long flags;
|
||||
unsigned long pfn, flags;
|
||||
struct mm_struct *mm;
|
||||
|
||||
if (user_mode(regs))
|
||||
@@ -50,18 +50,22 @@ static unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
|
||||
|
||||
local_irq_save(flags);
|
||||
ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (!ptep || pte_special(*ptep))
|
||||
return ULONG_MAX;
|
||||
|
||||
if (shift > PAGE_SHIFT) {
|
||||
unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
|
||||
|
||||
return pte_pfn(__pte(pte_val(*ptep) | (addr & rpnmask)));
|
||||
if (!ptep || pte_special(*ptep)) {
|
||||
pfn = ULONG_MAX;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return pte_pfn(*ptep);
|
||||
if (shift <= PAGE_SHIFT)
|
||||
pfn = pte_pfn(*ptep);
|
||||
else {
|
||||
unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
|
||||
pfn = pte_pfn(__pte(pte_val(*ptep) | (addr & rpnmask)));
|
||||
}
|
||||
|
||||
out:
|
||||
local_irq_restore(flags);
|
||||
return pfn;
|
||||
}
|
||||
|
||||
/* flush SLBs and reload */
|
||||
|
||||
Reference in New Issue
Block a user