patch-2.4.20 linux-2.4.20/arch/parisc/mm/fault.c
Next file: linux-2.4.20/arch/parisc/mm/init.c
Previous file: linux-2.4.20/arch/parisc/mm/extable.c
Back to the patch index
Back to the overall index
- Lines: 153
- Date:
Thu Nov 28 15:53:10 2002
- Orig file:
linux-2.4.19/arch/parisc/mm/fault.c
- Orig date:
Mon Mar 19 12:37:16 2001
diff -urN linux-2.4.19/arch/parisc/mm/fault.c linux-2.4.20/arch/parisc/mm/fault.c
@@ -17,6 +17,10 @@
#include <linux/interrupt.h>
#include <asm/uaccess.h>
+#include <asm/traps.h>
+
+#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
+ /* dumped to the console via printk) */
/* Defines for parisc_acctyp() */
@@ -114,59 +118,31 @@
#undef isGraphicsFlushRead
#undef BITSSET
-/* This is similar to expand_stack(), except that it is for stacks
- * that grow upwards.
- */
-
-static inline int expand_stackup(struct vm_area_struct * vma, unsigned long address)
-{
- unsigned long grow;
-
- address += 4 + PAGE_SIZE - 1;
- address &= PAGE_MASK;
- grow = (address - vma->vm_end) >> PAGE_SHIFT;
- if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur ||
- ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
- return -ENOMEM;
- vma->vm_end = address;
- vma->vm_mm->total_vm += grow;
- if (vma->vm_flags & VM_LOCKED)
- vma->vm_mm->locked_vm += grow;
- return 0;
-}
-
-
-/* This is similar to find_vma(), except that it understands that stacks
- * grow up rather than down.
- * XXX Optimise by making use of cache and avl tree as per find_vma().
- */
-struct vm_area_struct * pa_find_vma(struct mm_struct * mm, unsigned long addr)
-{
- struct vm_area_struct *vma = NULL;
-
- if (mm) {
- vma = mm->mmap;
- if (!vma || addr < vma->vm_start)
- return NULL;
- while (vma->vm_next && addr >= vma->vm_next->vm_start)
- vma = vma->vm_next;
- }
- return vma;
-}
-
-
-/*
- * This routine handles page faults. It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);
+#if 0
+/* This is the treewalk to find a vma which is the highest that has
+ * a start < addr. We're using find_vma_prev instead right now, but
+ * we might want to use this at some point in the future. Probably
+ * not, but I want it committed to CVS so I don't lose it :-)
+ */
+ while (tree != vm_avl_empty) {
+ if (tree->vm_start > addr) {
+ tree = tree->vm_avl_left;
+ } else {
+ prev = tree;
+ if (prev->vm_next == NULL)
+ break;
+ if (prev->vm_next->vm_start > addr)
+ break;
+ tree = tree->vm_avl_right;
+ }
+ }
+#endif
void do_page_fault(struct pt_regs *regs, unsigned long code,
unsigned long address)
{
- struct vm_area_struct * vma;
+ struct vm_area_struct *vma, *prev_vma;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
const struct exception_table_entry *fix;
@@ -176,13 +152,9 @@
goto no_context;
down_read(&mm->mmap_sem);
- vma = pa_find_vma(mm, address);
- if (!vma)
- goto bad_area;
- if (address < vma->vm_end)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSUP) || expand_stackup(vma, address))
- goto bad_area;
+ vma = find_vma_prev(mm, address, &prev_vma);
+ if (!vma || address < vma->vm_start)
+ goto check_expansion;
/*
* Ok, we have a good vm_area for this memory access. We still need to
* check the access permissions.
@@ -221,6 +193,11 @@
up_read(&mm->mmap_sem);
return;
+check_expansion:
+ vma = prev_vma;
+ if (vma && (expand_stack(vma, address) == 0))
+ goto good_area;
+
/*
* Something tried to access memory that isn't in our memory map..
*/
@@ -230,9 +207,16 @@
if (user_mode(regs)) {
struct siginfo si;
- printk("\ndo_page_fault() pid=%d command='%s'\n",
- tsk->pid, tsk->comm);
+#ifdef PRINT_USER_FAULTS
+ printk(KERN_DEBUG "\n");
+ printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n",
+ tsk->pid, tsk->comm, code, address);
+ if (vma) {
+ printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n",
+ vma->vm_start, vma->vm_end);
+ }
show_regs(regs);
+#endif
/* FIXME: actually we need to get the signo and code correct */
si.si_signo = SIGSEGV;
si.si_errno = 0;
@@ -272,11 +256,11 @@
}
}
- parisc_terminate("Bad Address (null pointer deref?)",regs,code,address);
+ parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);
out_of_memory:
up_read(&mm->mmap_sem);
- printk("VM: killing process %s\n", current->comm);
+ printk(KERN_CRIT "VM: killing process %s\n", current->comm);
if (user_mode(regs))
do_exit(SIGKILL);
goto no_context;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)