patch-2.2.18 linux/arch/arm/mm/fault-common.c
Next file: linux/arch/arm/mm/init.c
Previous file: linux/arch/arm/mm/fault-armv.c
Back to the patch index
Back to the overall index
- Lines: 131
- Date:
Fri Sep 15 23:28:37 2000
- Orig file:
v2.2.17/arch/arm/mm/fault-common.c
- Orig date:
Fri Apr 21 12:45:45 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
@@ -26,25 +26,14 @@
set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
}
-static void
-kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
- struct task_struct *tsk, struct mm_struct *mm)
+/*
+ * This is useful to dump out the page tables associated with
+ * 'addr' in mm 'mm'.
+ */
+void show_pte(struct mm_struct *mm, unsigned long addr)
{
- char *reason;
- /*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
pgd_t *pgd;
- if (addr < PAGE_SIZE)
- reason = "NULL pointer dereference";
- else
- reason = "paging request";
-
- printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
- reason, addr);
- printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd);
pgd = pgd_offset(mm, addr);
printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd));
@@ -73,11 +62,34 @@
pte = pte_offset(pmd, addr);
printk(", *pte = %08lx", pte_val(*pte));
+#ifdef CONFIG_CPU_32
printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE]));
+#endif
} while(0);
printk("\n");
- die("Oops", regs, mode);
+}
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+static void
+kernel_page_fault(unsigned long addr, int write_access, struct pt_regs *regs,
+ struct task_struct *tsk, struct mm_struct *mm)
+{
+ char *reason;
+
+ if (addr < PAGE_SIZE)
+ reason = "NULL pointer dereference";
+ else
+ reason = "paging request";
+
+ printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
+ reason, addr);
+ printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd);
+ show_pte(mm, addr);
+ die("Oops", regs, write_access);
do_exit(SIGKILL);
}
@@ -88,6 +100,7 @@
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long fixup;
+ int fault;
tsk = current;
mm = tsk->mm;
@@ -126,8 +139,12 @@
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode)))
+survive:
+ fault = handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode));
+ if (!fault)
goto do_sigbus;
+ if (fault < 0)
+ goto out_of_memory;
up(&mm->mmap_sem);
return;
@@ -140,7 +157,7 @@
up(&mm->mmap_sem);
/* User mode accesses just cause a SIGSEGV */
- if (mode & FAULT_CODE_USER) {
+ if (user_mode(regs)) {
tsk->tss.error_code = mode;
tsk->tss.trap_no = 14;
#ifdef CONFIG_DEBUG_USER
@@ -165,6 +182,23 @@
kernel_page_fault(addr, mode, regs, tsk, mm);
return;
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+ if (tsk->pid == 1) {
+ tsk->policy |= SCHED_YIELD;
+ schedule();
+ goto survive;
+ }
+ up(&mm->mmap_sem);
+ if (user_mode(regs)) {
+ printk("VM: killing process %s\n", tsk->comm);
+ do_exit(SIGKILL);
+ }
+ goto no_context;
+
do_sigbus:
/*
* We ran out of memory, or some other thing happened to us that made
@@ -181,7 +215,7 @@
force_sig(SIGBUS, tsk);
/* Kernel mode? Handle exceptions or die */
- if (!(mode & FAULT_CODE_USER))
+ if (!user_mode(regs))
goto no_context;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)