patch-2.2.14 linux/arch/sparc/mm/fault.c

Next file: linux/arch/sparc/mm/iommu.c
Previous file: linux/arch/sparc/mm/asyncd.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.13/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.101.2.2 1999/08/07 10:42:53 davem Exp $
+/* $Id: fault.c,v 1.101.2.5 1999/11/16 06:29:39 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -237,8 +237,14 @@
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	if (!handle_mm_fault(current, vma, address, write))
-		goto do_sigbus;
+survive:
+	{
+		int fault = handle_mm_fault(current, vma, address, write);
+		if (!fault)
+			goto do_sigbus;
+		if (fault < 0)
+			goto out_of_memory;
+	}
 	up(&mm->mmap_sem);
 	return;
 	/*
@@ -288,6 +294,17 @@
 	unhandled_fault (address, tsk, regs);
 	return;
 
+out_of_memory:
+	if (tsk->pid == 1) {
+		tsk->policy |= SCHED_YIELD;
+		schedule();
+		goto survive;
+	}
+	up(&mm->mmap_sem);
+	printk("VM: killing process %s\n", tsk->comm);
+	do_exit(SIGKILL);
+	return;
+
 do_sigbus:
 	up(&mm->mmap_sem);
 	tsk->tss.sig_address = address;
@@ -309,8 +326,18 @@
 	pgd_t *pgdp;
 	pte_t *ptep;
 
-	if (text_fault)
+	if (text_fault) {
 		address = regs->pc;
+	} else if (!write &&
+		   !(regs->psr & PSR_PS)) {
+		unsigned int insn, *ip;
+
+		ip = (unsigned int *)regs->pc;
+		if (! get_user(insn, ip)) {
+			if ((insn & 0xc1680000) == 0xc0680000)
+				write = 1;
+		}
+	}
 
 	pgdp = sun4c_pgd_offset(mm, address);
 	ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
@@ -319,28 +346,36 @@
 	    if (write) {
 		if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
 				   == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
+			unsigned long flags;
 
 			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
 				      _SUN4C_PAGE_MODIFIED |
 				      _SUN4C_PAGE_VALID |
 				      _SUN4C_PAGE_DIRTY);
 
+			save_and_cli(flags);
 			if (sun4c_get_segmap(address) != invalid_segment) {
 				sun4c_put_pte(address, pte_val(*ptep));
+				restore_flags(flags);
 				return;
 			}
+			restore_flags(flags);
 		}
 	    } else {
 		if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
 				   == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
+			unsigned long flags;
 
 			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
 				      _SUN4C_PAGE_VALID);
 
+			save_and_cli(flags);
 			if (sun4c_get_segmap(address) != invalid_segment) {
 				sun4c_put_pte(address, pte_val(*ptep));
+				restore_flags(flags);
 				return;
 			}
+			restore_flags(flags);
 		}
 	    }
 	}
@@ -389,8 +424,14 @@
 		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	if (!handle_mm_fault(current, vma, address, write))
-		goto do_sigbus;
+survive:
+	{
+		int fault = handle_mm_fault(current, vma, address, write);
+		if (!fault)
+			goto do_sigbus;
+		if (fault < 0)
+			goto out_of_memory;
+	}
 	up(&mm->mmap_sem);
 	return;
 bad_area:
@@ -404,6 +445,17 @@
 	send_sig(SIGSEGV, tsk, 1);
 	return;
 
+out_of_memory:
+	if (tsk->pid == 1) {
+		tsk->policy |= SCHED_YIELD;
+		schedule();
+		goto survive;
+	}
+	up(&mm->mmap_sem);
+	printk("VM: killing process %s\n", tsk->comm);
+	do_exit(SIGKILL);
+	return;
+
 do_sigbus:
 	up(&mm->mmap_sem);
 	tsk->tss.sig_address = address;
@@ -415,31 +467,25 @@
 {
 	unsigned long sp;
 
-	lock_kernel();
 	sp = current->tss.rwbuf_stkptrs[0];
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 1);
 	force_user_fault(sp, 1);
-	unlock_kernel();
 }
 
 void window_underflow_fault(unsigned long sp)
 {
-	lock_kernel();
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 0);
 	force_user_fault(sp, 0);
-	unlock_kernel();
 }
 
 void window_ret_fault(struct pt_regs *regs)
 {
 	unsigned long sp;
 
-	lock_kernel();
 	sp = regs->u_regs[UREG_FP];
 	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
 		force_user_fault(sp + 0x38, 0);
 	force_user_fault(sp, 0);
-	unlock_kernel();
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)