[RFC][PATCH] ppc64: better handling of H_ENTER failures
Benjamin Herrenschmidt
benh at kernel.crashing.org
Fri Jul 30 15:22:32 EST 2004
Hi !
This patch changes the hash insertion routines to return an error
instead of calling panic() when HV refuses to insert a HPTE.
The error is now propagated upstream, and either bad_page_fault() is
called (kernel mode) or a SIGBUS signal is forced (user mode). Some
other panic() cases are also turned into BUG_ON.
Overall, this should provide us with better debugging data if the
problem happens, and avoids errors from userland mapping /dev/mem and
trying to use forbidden IOs (XFree ?) to bring the whole kernel down.
Any comment ?
Ben.
===== arch/ppc64/kernel/head.S 1.61 vs edited =====
--- 1.61/arch/ppc64/kernel/head.S 2004-06-17 00:46:06 -05:00
+++ edited/arch/ppc64/kernel/head.S 2004-06-23 15:03:55 -05:00
@@ -1015,6 +1015,9 @@
* interrupts if necessary.
*/
beq .ret_from_except_lite
+ /* For a hash failure, we don't bother re-enabling interrupts */
+ ble- 12f
+
/*
* hash_page couldn't handle it, set soft interrupt enable back
* to what it was before the trap. Note that .local_irq_restore
@@ -1025,6 +1028,8 @@
b 11f
#else
beq+ fast_exception_return /* Return from exception on success */
+ ble- 12f /* Failure return from hash_page */
+
/* fall through */
#endif
@@ -1042,6 +1047,15 @@
addi r3,r1,STACK_FRAME_OVERHEAD
lwz r4,_DAR(r1)
bl .bad_page_fault
+ b .ret_from_except
+
+/* We have a page fault that hash_page could handle but HV refused
+ * the PTE insertion
+ */
+12: bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ lwz r4,_DAR(r1)
+ bl .low_hash_fault
b .ret_from_except
/* here we have a segment miss */
===== arch/ppc64/kernel/pSeries_lpar.c 1.36 vs edited =====
--- 1.36/arch/ppc64/kernel/pSeries_lpar.c 2004-04-12 12:54:09 -05:00
+++ edited/arch/ppc64/kernel/pSeries_lpar.c 2004-06-23 15:00:53 -05:00
@@ -377,7 +377,7 @@
lpar_rc = plpar_hcall(H_ENTER, flags, hpte_group, lhpte.dw0.dword0,
lhpte.dw1.dword1, &slot, &dummy0, &dummy1);
- if (lpar_rc == H_PTEG_Full)
+ if (unlikely(lpar_rc == H_PTEG_Full))
return -1;
/*
@@ -385,8 +385,13 @@
* will fail. However we must catch the failure in hash_page
* or we will loop forever, so return -2 in this case.
*/
- if (lpar_rc != H_Success)
+ if (unlikely(lpar_rc != H_Success)) {
+ printk(KERN_WARNING
+ "MMU fault ! H_ENTER failed, rc: %lx, va: %016lx, prpn: %lx,"
+ " hpteflags: %lx, secondary: %d, bolted: %d, large: %d\n",
+ lpar_rc, va, prpn, hpteflags, secondary, bolted, large);
return -2;
+ }
/* Because of iSeries, we have to pass down the secondary
* bucket bit here as well
@@ -415,9 +420,7 @@
if (lpar_rc == H_Success)
return i;
- if (lpar_rc != H_Not_Found)
- panic("Bad return code from pte remove rc = %lx\n",
- lpar_rc);
+ BUG_ON(lpar_rc != H_Not_Found);
slot_offset++;
slot_offset &= 0x7;
@@ -447,8 +450,7 @@
if (lpar_rc == H_Not_Found)
return -1;
- if (lpar_rc != H_Success)
- panic("bad return code from pte protect rc = %lx\n", lpar_rc);
+ BUG_ON(lpar_rc != H_Success);
return 0;
}
@@ -467,8 +469,7 @@
lpar_rc = plpar_pte_read(flags, slot, &dword0, &dummy_word1);
- if (lpar_rc != H_Success)
- panic("Error on pte read in get_hpte0 rc = %lx\n", lpar_rc);
+ BUG_ON(lpar_rc != H_Success);
return dword0;
}
@@ -519,15 +520,12 @@
vpn = va >> PAGE_SHIFT;
slot = pSeries_lpar_hpte_find(vpn);
- if (slot == -1)
- panic("updateboltedpp: Could not find page to bolt\n");
+ BUG_ON(slot == -1);
flags = newpp & 3;
lpar_rc = plpar_pte_protect(flags, slot, 0);
- if (lpar_rc != H_Success)
- panic("Bad return code from pte bolted protect rc = %lx\n",
- lpar_rc);
+ BUG_ON(lpar_rc != H_Success);
}
static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
@@ -546,8 +544,7 @@
if (lpar_rc == H_Not_Found)
return;
- if (lpar_rc != H_Success)
- panic("Bad return code from invalidate rc = %lx\n", lpar_rc);
+ BUG_ON(lpar_rc != H_Success);
}
/*
===== arch/ppc64/mm/hash_low.S 1.5 vs edited =====
--- 1.5/arch/ppc64/mm/hash_low.S 2004-04-12 12:54:08 -05:00
+++ edited/arch/ppc64/mm/hash_low.S 2004-06-22 16:14:22 -05:00
@@ -278,6 +278,10 @@
b bail
htab_pte_insert_failure:
- b .htab_insert_failure
+ /* Bail out restoring old PTE */
+ ld r6,STK_PARM(r6)(r1)
+ std r31,0(r6)
+ li r3,-1
+ b bail
===== arch/ppc64/mm/hash_utils.c 1.47 vs edited =====
--- 1.47/arch/ppc64/mm/hash_utils.c 2004-06-10 01:21:41 -05:00
+++ edited/arch/ppc64/mm/hash_utils.c 2004-06-23 15:08:29 -05:00
@@ -28,6 +28,7 @@
#include <linux/ctype.h>
#include <linux/cache.h>
#include <linux/init.h>
+#include <linux/signal.h>
#include <asm/ppcdebug.h>
#include <asm/processor.h>
@@ -236,14 +237,11 @@
return pp;
}
-/*
- * Called by asm hashtable.S in case of critical insert failure
+/* Result code is:
+ * 0 - handled
+ * 1 - normal page fault
+ * -1 - critical hash insertion error
*/
-void htab_insert_failure(void)
-{
- panic("hash_page: pte_insert failed\n");
-}
-
int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
{
void *pgdir;
@@ -374,6 +372,25 @@
*insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc));
flush_icache_range((unsigned long)insn_addr, 4+
(unsigned long)insn_addr);
+}
+
+/*
+ * low_hash_fault is called when we the low level hash code failed
+ * to instert a PTE due to an hypervisor error
+ */
+void low_hash_fault(struct pt_regs *regs, unsigned long address)
+{
+ if (user_mode(regs)) {
+ siginfo_t info;
+
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+ force_sig_info(SIGBUS, &info, current);
+ return;
+ }
+ bad_page_fault(regs, address, SIGBUS);
}
void __init htab_finish_init(void)
===== include/asm-ppc64/system.h 1.32 vs edited =====
--- 1.32/include/asm-ppc64/system.h 2004-06-20 20:15:35 -05:00
+++ edited/include/asm-ppc64/system.h 2004-06-23 15:08:01 -05:00
@@ -105,6 +105,7 @@
extern void bad_page_fault(struct pt_regs *regs, unsigned long address,
int sig);
extern void show_regs(struct pt_regs * regs);
+extern void low_hash_fault(struct pt_regs *regs, unsigned long address);
extern int die(const char *str, struct pt_regs *regs, long err);
extern void flush_instruction_cache(void);
** Sent via the linuxppc64-dev mail list. See http://lists.linuxppc.org/
More information about the Linuxppc64-dev
mailing list