lkml.org 
[lkml]   [2004]   [Aug]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] PPC64 Better handling of H_ENTER failures
This patch changes the hash insertion routines to return an error 
instead of calling panic() when HV refuses to insert a HPTE (the
hypervisor call to set up a hashtable PTE is H_ENTER).

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.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>

diff -urN linux-2.5/arch/ppc64/kernel/head.S akpm/arch/ppc64/kernel/head.S
--- linux-2.5/arch/ppc64/kernel/head.S 2004-08-24 07:22:47.000000000 +1000
+++ akpm/arch/ppc64/kernel/head.S 2004-08-24 16:51:40.000000000 +1000
@@ -1037,6 +1037,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
@@ -1047,6 +1050,8 @@
b 11f
#else
beq fast_exception_return /* Return from exception on success */
+ ble- 12f /* Failure return from hash_page */
+
/* fall through */
#endif

@@ -1066,6 +1071,15 @@
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 */
_GLOBAL(do_ste_alloc)
bl .ste_allocate /* try to insert stab entry */
diff -urN linux-2.5/arch/ppc64/kernel/pSeries_lpar.c akpm/arch/ppc64/kernel/pSeries_lpar.c
--- linux-2.5/arch/ppc64/kernel/pSeries_lpar.c 2004-07-26 05:20:35.000000000 +1000
+++ akpm/arch/ppc64/kernel/pSeries_lpar.c 2004-08-24 17:29:18.000000000 +1000
@@ -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,7 +385,7 @@
* 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))
return -2;

/* Because of iSeries, we have to pass down the secondary
@@ -415,9 +415,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 +445,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 +464,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 +515,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 +539,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);
}

/*
diff -urN linux-2.5/arch/ppc64/mm/hash_low.S akpm/arch/ppc64/mm/hash_low.S
--- linux-2.5/arch/ppc64/mm/hash_low.S 2004-04-13 09:25:09.000000000 +1000
+++ akpm/arch/ppc64/mm/hash_low.S 2004-08-24 16:49:57.000000000 +1000
@@ -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


diff -urN linux-2.5/arch/ppc64/mm/hash_utils.c akpm/arch/ppc64/mm/hash_utils.c
--- linux-2.5/arch/ppc64/mm/hash_utils.c 2004-07-31 00:40:05.000000000 +1000
+++ akpm/arch/ppc64/mm/hash_utils.c 2004-08-24 16:49:57.000000000 +1000
@@ -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;
@@ -371,6 +369,25 @@
(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)
{
extern unsigned int *htab_call_hpte_insert1;
diff -urN linux-2.5/include/asm-ppc64/system.h akpm/include/asm-ppc64/system.h
--- linux-2.5/include/asm-ppc64/system.h 2004-08-24 07:22:48.000000000 +1000
+++ akpm/include/asm-ppc64/system.h 2004-08-24 16:49:57.000000000 +1000
@@ -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);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2005-03-22 14:05    [W:0.032 / U:0.324 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site