patch-2.0.19 linux/arch/i386/mm/fault.c

Next file: linux/drivers/block/ide-tape.c
Previous file: linux/arch/i386/lib/semaphore.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.18/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
@@ -33,13 +33,21 @@
  */
 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
+	void (*handler)(struct task_struct *,
+			struct vm_area_struct *,
+			unsigned long,
+			int);
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->mm;
 	struct vm_area_struct * vma;
 	unsigned long address;
 	unsigned long page;
+	int write;
 
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
-	vma = find_vma(current, address);
+	down(&mm->mmap_sem);
+	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
 	if (vma->vm_start <= address)
@@ -63,36 +71,37 @@
  * we can handle it..
  */
 good_area:
-	/*
-	 * was it a write?
-	 */
-	if (error_code & 2) {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
-	} else {
-		/* read with protection fault? */
-		if (error_code & 1)
-			goto bad_area;
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+	write = 0;
+	handler = do_no_page;
+	switch (error_code & 3) {
+		default:	/* 3: write, present */
+			handler = do_wp_page;
+#ifdef TEST_VERIFY_AREA
+			if (regs->cs == KERNEL_CS)
+				printk("WP fault at %08lx\n", regs->eip);
+#endif
+			/* fall through */
+		case 2:		/* write, not present */
+			if (!(vma->vm_flags & VM_WRITE))
+				goto bad_area;
+			write++;
+			break;
+		case 1:		/* read, present */
 			goto bad_area;
+		case 0:		/* read, not present */
+			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+				goto bad_area;
 	}
+	handler(tsk, vma, address, write);
+	up(&mm->mmap_sem);
 	/*
 	 * Did it hit the DOS screen memory VA from vm86 mode?
 	 */
 	if (regs->eflags & VM_MASK) {
 		unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
 		if (bit < 32)
-			current->tss.screen_bitmap |= 1 << bit;
-	}
-	if (error_code & 1) {
-#ifdef TEST_VERIFY_AREA
-		if (regs->cs == KERNEL_CS)
-			printk("WP fault at %08lx\n", regs->eip);
-#endif
-		do_wp_page(current, vma, address, error_code & 2);
-		return;
+			tsk->tss.screen_bitmap |= 1 << bit;
 	}
-	do_no_page(current, vma, address, error_code & 2);
 	return;
 
 /*
@@ -100,11 +109,12 @@
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
+	up(&mm->mmap_sem);
 	if (error_code & 4) {
-		current->tss.cr2 = address;
-		current->tss.error_code = error_code;
-		current->tss.trap_no = 14;
-		force_sig(SIGSEGV, current);
+		tsk->tss.cr2 = address;
+		tsk->tss.error_code = error_code;
+		tsk->tss.trap_no = 14;
+		force_sig(SIGSEGV, tsk);
 		return;
 	}
 /*
@@ -128,7 +138,7 @@
 	printk(" at virtual address %08lx\n",address);
 	__asm__("movl %%cr3,%0" : "=r" (page));
 	printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
-		current->tss.cr3, page);
+		tsk->tss.cr3, page);
 	page = ((unsigned long *) page)[address >> 22];
 	printk(KERN_ALERT "*pde = %08lx\n", page);
 	if (page & 1) {

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov