Skip to content

Commit 0da81b6

Browse files
kvaneeshmpe
authored andcommitted
powerpc/mce: Don't reload pte val in addr_to_pfn
A lockless page table walk should be safe against parallel THP collapse, THP split and madvise(MADV_DONTNEED)/parallel fault. This patch makes sure kernel won't reload the pteval when checking for different conditions. The patch also added a check for pte_present to make sure the kernel is indeed operating on a PTE and not a pointer to level 0 table page. The pfn value we find here can be different from the actual pfn on which machine check happened. This can happen if we raced with a parallel update of the page table. In such a scenario we end up isolating a wrong pfn. But that doesn't have any other side effect. Signed-off-by: Aneesh Kumar K.V <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 2f92447 commit 0da81b6

File tree

1 file changed

+9
-5
lines changed

1 file changed

+9
-5
lines changed

arch/powerpc/kernel/mce_power.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
*/
2828
unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
2929
{
30-
pte_t *ptep;
30+
pte_t *ptep, pte;
3131
unsigned int shift;
3232
unsigned long pfn, flags;
3333
struct mm_struct *mm;
@@ -39,19 +39,23 @@ unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
3939

4040
local_irq_save(flags);
4141
ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
42+
if (!ptep) {
43+
pfn = ULONG_MAX;
44+
goto out;
45+
}
46+
pte = READ_ONCE(*ptep);
4247

43-
if (!ptep || pte_special(*ptep)) {
48+
if (!pte_present(pte) || pte_special(pte)) {
4449
pfn = ULONG_MAX;
4550
goto out;
4651
}
4752

4853
if (shift <= PAGE_SHIFT)
49-
pfn = pte_pfn(*ptep);
54+
pfn = pte_pfn(pte);
5055
else {
5156
unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
52-
pfn = pte_pfn(__pte(pte_val(*ptep) | (addr & rpnmask)));
57+
pfn = pte_pfn(__pte(pte_val(pte) | (addr & rpnmask)));
5358
}
54-
5559
out:
5660
local_irq_restore(flags);
5761
return pfn;

0 commit comments

Comments
 (0)