> Make get_user_insn() able to cope with huge PMDs. > > Next, make do_fault_siginfo() more robust when get_user_insn() can't > actually fetch the instruction. In particular, use the MMU announced > fault address when that happens, instead of calling > compute_effective_address() and computing garbage. > > Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx> This patch happens to introduce a compile failure on a computer that has THP diabled: CC arch/sparc/mm/fault_64.o arch/sparc/mm/fault_64.c: In function ʽget_user_insnʼ: arch/sparc/mm/fault_64.c:117:3: error: implicit declaration of function ʽpmd_pfnʼ [-Werror=implicit-function-declaration] arch/sparc/include/asm/pgtable_64.h has pmd_pfn declared only for THP. > --- > arch/sparc/mm/fault_64.c | 75 ++++++++++++++++++++++++++++++------------------ > 1 file changed, 47 insertions(+), 28 deletions(-) > > diff --git a/arch/sparc/mm/fault_64.c b/arch/sparc/mm/fault_64.c > index 69bb818..cf0d05d 100644 > --- a/arch/sparc/mm/fault_64.c > +++ b/arch/sparc/mm/fault_64.c > @@ -96,38 +96,48 @@ static unsigned int get_user_insn(unsigned long tpc) > pte_t *ptep, pte; > unsigned long pa; > u32 insn = 0; > - unsigned long pstate; > > if (pgd_none(*pgdp)) > - goto outret; > + goto out; > pudp = pud_offset(pgdp, tpc); > if (pud_none(*pudp)) > - goto outret; > - pmdp = pmd_offset(pudp, tpc); > - if (pmd_none(*pmdp)) > - goto outret; > + goto out; > > /* This disables preemption for us as well. */ > - __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); > - __asm__ __volatile__("wrpr %0, %1, %%pstate" > - : : "r" (pstate), "i" (PSTATE_IE)); > - ptep = pte_offset_map(pmdp, tpc); > - pte = *ptep; > - if (!pte_present(pte)) > - goto out; > + local_irq_disable(); > + > + pmdp = pmd_offset(pudp, tpc); > + if (pmd_none(*pmdp)) > + goto out_irq_enable; > > - pa = (pte_pfn(pte) << PAGE_SHIFT); > - pa += (tpc & ~PAGE_MASK); > + if (pmd_trans_huge(*pmdp)) { > + if (pmd_trans_splitting(*pmdp)) > + goto out_irq_enable; > > - /* Use phys bypass so we don't pollute dtlb/dcache. */ > - __asm__ __volatile__("lduwa [%1] %2, %0" > - : "=r" (insn) > - : "r" (pa), "i" (ASI_PHYS_USE_EC)); > + pa = pmd_pfn(*pmdp) << PAGE_SHIFT; > + pa += tpc & ~HPAGE_MASK; > > + /* Use phys bypass so we don't pollute dtlb/dcache. */ > + __asm__ __volatile__("lduwa [%1] %2, %0" > + : "=r" (insn) > + : "r" (pa), "i" (ASI_PHYS_USE_EC)); > + } else { > + ptep = pte_offset_map(pmdp, tpc); > + pte = *ptep; > + if (pte_present(pte)) { > + pa = (pte_pfn(pte) << PAGE_SHIFT); > + pa += (tpc & ~PAGE_MASK); > + > + /* Use phys bypass so we don't pollute dtlb/dcache. */ > + __asm__ __volatile__("lduwa [%1] %2, %0" > + : "=r" (insn) > + : "r" (pa), "i" (ASI_PHYS_USE_EC)); > + } > + pte_unmap(ptep); > + } > +out_irq_enable: > + local_irq_enable(); > out: > - pte_unmap(ptep); > - __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); > -outret: > return insn; > } > > @@ -153,7 +163,8 @@ show_signal_msg(struct pt_regs *regs, int sig, int code, > } > > static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, > - unsigned int insn, int fault_code) > + unsigned long fault_addr, unsigned int insn, > + int fault_code) > { > unsigned long addr; > siginfo_t info; > @@ -161,10 +172,18 @@ static void do_fault_siginfo(int code, int sig, struct pt_regs *regs, > info.si_code = code; > info.si_signo = sig; > info.si_errno = 0; > - if (fault_code & FAULT_CODE_ITLB) > + if (fault_code & FAULT_CODE_ITLB) { > addr = regs->tpc; > - else > - addr = compute_effective_address(regs, insn, 0); > + } else { > + /* If we were able to probe the faulting instruction, use it > + * to compute a precise fault address. Otherwise use the fault > + * time provided address which may only have page granularity. > + */ > + if (insn) > + addr = compute_effective_address(regs, insn, 0); > + else > + addr = fault_addr; > + } > info.si_addr = (void __user *) addr; > info.si_trapno = 0; > > @@ -239,7 +258,7 @@ static void __kprobes do_kernel_fault(struct pt_regs *regs, int si_code, > /* The si_code was set to make clear whether > * this was a SEGV_MAPERR or SEGV_ACCERR fault. > */ > - do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code); > + do_fault_siginfo(si_code, SIGSEGV, regs, address, insn, fault_code); > return; > } > > @@ -525,7 +544,7 @@ do_sigbus: > * Send a sigbus, regardless of whether we were in kernel > * or user mode. > */ > - do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code); > + do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, address, insn, fault_code); > > /* Kernel mode? Handle exceptions or die */ > if (regs->tstate & TSTATE_PRIV) > -- Meelis Roos (mroos@xxxxx) http://www.cs.ut.ee/~mroos/ -- To unsubscribe from this list: send the line "unsubscribe sparclinux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html