Message ID | 20191016195043.31040-2-manoj.iyer@canonical.com |
---|---|
State | New |
Headers | show |
Series | powerpc/mce: Fix MCE handling for huge pages | expand |
On 16.10.19 21:50, Manoj Iyer wrote: > From: Balbir Singh <bsingharora@gmail.com> > > The current code would fail on huge pages addresses, since the shift would > be incorrect. Use the correct page shift value returned by > __find_linux_pte() to get the correct physical address. The code is more > generic and can handle both regular and compound pages. > > BugLink: https://bugs.launchpad.net/bugs/1848127 > > Fixes: ba41e1e1ccb9 ("powerpc/mce: Hookup derror (load/store) UE errors") > Signed-off-by: Balbir Singh <bsingharora@gmail.com> > [arbab@linux.ibm.com: Fixup pseries_do_memory_failure()] > Signed-off-by: Reza Arbab <arbab@linux.ibm.com> > Tested-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> > Signed-off-by: Santosh Sivaraj <santosh@fossix.org> > Cc: stable@vger.kernel.org # v4.15+ > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> > Link: https://lore.kernel.org/r/20190820081352.8641-3-santosh@fossix.org > (cherry picked from commit 99ead78afd1128bfcebe7f88f3b102fb2da09aee) > Signed-off-by: Manoj Iyer <manoj.iyer@canonical.com> Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> > --- > arch/powerpc/kernel/mce_power.c | 19 +++++++++++++------ > 1 file changed, 13 insertions(+), 6 deletions(-) > > diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c > index a814d2dfb5b0..714a98e0927f 100644 > --- a/arch/powerpc/kernel/mce_power.c > +++ b/arch/powerpc/kernel/mce_power.c > @@ -26,6 +26,7 @@ > unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) > { > pte_t *ptep; > + unsigned int shift; > unsigned long flags; > struct mm_struct *mm; > > @@ -35,13 +36,18 @@ unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) > mm = &init_mm; > > local_irq_save(flags); > - if (mm == current->mm) > - ptep = find_current_mm_pte(mm->pgd, addr, NULL, NULL); > - else > - ptep = find_init_mm_pte(addr, NULL); > + 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))); > + } > + > return pte_pfn(*ptep); > } > > @@ -344,7 +350,7 @@ static const struct mce_derror_table mce_p9_derror_table[] = { > MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true }, > { 0, false, 0, 0, 0, 0, 0 } }; > > -static int mce_find_instr_ea_and_pfn(struct pt_regs *regs, uint64_t *addr, > +static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr, > uint64_t *phys_addr) > { > /* > @@ -541,7 +547,8 @@ static int mce_handle_derror(struct pt_regs *regs, > * kernel/exception-64s.h > */ > if (get_paca()->in_mce < MAX_MCE_DEPTH) > - mce_find_instr_ea_and_pfn(regs, addr, phys_addr); > + mce_find_instr_ea_and_phys(regs, addr, > + phys_addr); > } > found = 1; > } >
On 16.10.19 21:50, Manoj Iyer wrote: > From: Balbir Singh <bsingharora@gmail.com> > > The current code would fail on huge pages addresses, since the shift would > be incorrect. Use the correct page shift value returned by > __find_linux_pte() to get the correct physical address. The code is more > generic and can handle both regular and compound pages. > > BugLink: https://bugs.launchpad.net/bugs/1848127 > > Fixes: ba41e1e1ccb9 ("powerpc/mce: Hookup derror (load/store) UE errors") > Signed-off-by: Balbir Singh <bsingharora@gmail.com> > [arbab@linux.ibm.com: Fixup pseries_do_memory_failure()] > Signed-off-by: Reza Arbab <arbab@linux.ibm.com> > Tested-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> > Signed-off-by: Santosh Sivaraj <santosh@fossix.org> > Cc: stable@vger.kernel.org # v4.15+ > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> > Link: https://lore.kernel.org/r/20190820081352.8641-3-santosh@fossix.org > (cherry picked from commit 99ead78afd1128bfcebe7f88f3b102fb2da09aee) > Signed-off-by: Manoj Iyer <manoj.iyer@canonical.com> Acked-by: Stefan Bader <stefan.bader@canonical.com> > --- > arch/powerpc/kernel/mce_power.c | 19 +++++++++++++------ > 1 file changed, 13 insertions(+), 6 deletions(-) > > diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c > index a814d2dfb5b0..714a98e0927f 100644 > --- a/arch/powerpc/kernel/mce_power.c > +++ b/arch/powerpc/kernel/mce_power.c > @@ -26,6 +26,7 @@ > unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) > { > pte_t *ptep; > + unsigned int shift; > unsigned long flags; > struct mm_struct *mm; > > @@ -35,13 +36,18 @@ unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) > mm = &init_mm; > > local_irq_save(flags); > - if (mm == current->mm) > - ptep = find_current_mm_pte(mm->pgd, addr, NULL, NULL); > - else > - ptep = find_init_mm_pte(addr, NULL); > + 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))); > + } > + > return pte_pfn(*ptep); > } > > @@ -344,7 +350,7 @@ static const struct mce_derror_table mce_p9_derror_table[] = { > MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true }, > { 0, false, 0, 0, 0, 0, 0 } }; > > -static int mce_find_instr_ea_and_pfn(struct pt_regs *regs, uint64_t *addr, > +static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr, > uint64_t *phys_addr) > { > /* > @@ -541,7 +547,8 @@ static int mce_handle_derror(struct pt_regs *regs, > * kernel/exception-64s.h > */ > if (get_paca()->in_mce < MAX_MCE_DEPTH) > - mce_find_instr_ea_and_pfn(regs, addr, phys_addr); > + mce_find_instr_ea_and_phys(regs, addr, > + phys_addr); > } > found = 1; > } >
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c index a814d2dfb5b0..714a98e0927f 100644 --- a/arch/powerpc/kernel/mce_power.c +++ b/arch/powerpc/kernel/mce_power.c @@ -26,6 +26,7 @@ unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) { pte_t *ptep; + unsigned int shift; unsigned long flags; struct mm_struct *mm; @@ -35,13 +36,18 @@ unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr) mm = &init_mm; local_irq_save(flags); - if (mm == current->mm) - ptep = find_current_mm_pte(mm->pgd, addr, NULL, NULL); - else - ptep = find_init_mm_pte(addr, NULL); + 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))); + } + return pte_pfn(*ptep); } @@ -344,7 +350,7 @@ static const struct mce_derror_table mce_p9_derror_table[] = { MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true }, { 0, false, 0, 0, 0, 0, 0 } }; -static int mce_find_instr_ea_and_pfn(struct pt_regs *regs, uint64_t *addr, +static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr, uint64_t *phys_addr) { /* @@ -541,7 +547,8 @@ static int mce_handle_derror(struct pt_regs *regs, * kernel/exception-64s.h */ if (get_paca()->in_mce < MAX_MCE_DEPTH) - mce_find_instr_ea_and_pfn(regs, addr, phys_addr); + mce_find_instr_ea_and_phys(regs, addr, + phys_addr); } found = 1; }