|
@@ -108,14 +108,15 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
|
|
*/
|
|
*/
|
|
static void
|
|
static void
|
|
__do_user_fault(struct task_struct *tsk, unsigned long addr,
|
|
__do_user_fault(struct task_struct *tsk, unsigned long addr,
|
|
- unsigned int fsr, int code, struct pt_regs *regs)
|
|
|
|
|
|
+ unsigned int fsr, unsigned int sig, int code,
|
|
|
|
+ struct pt_regs *regs)
|
|
{
|
|
{
|
|
struct siginfo si;
|
|
struct siginfo si;
|
|
|
|
|
|
#ifdef CONFIG_DEBUG_USER
|
|
#ifdef CONFIG_DEBUG_USER
|
|
if (user_debug & UDBG_SEGV) {
|
|
if (user_debug & UDBG_SEGV) {
|
|
- printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n",
|
|
|
|
- tsk->comm, addr, fsr);
|
|
|
|
|
|
+ printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
|
|
|
|
+ tsk->comm, sig, addr, fsr);
|
|
show_pte(tsk->mm, addr);
|
|
show_pte(tsk->mm, addr);
|
|
show_regs(regs);
|
|
show_regs(regs);
|
|
}
|
|
}
|
|
@@ -124,11 +125,11 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
|
|
tsk->thread.address = addr;
|
|
tsk->thread.address = addr;
|
|
tsk->thread.error_code = fsr;
|
|
tsk->thread.error_code = fsr;
|
|
tsk->thread.trap_no = 14;
|
|
tsk->thread.trap_no = 14;
|
|
- si.si_signo = SIGSEGV;
|
|
|
|
|
|
+ si.si_signo = sig;
|
|
si.si_errno = 0;
|
|
si.si_errno = 0;
|
|
si.si_code = code;
|
|
si.si_code = code;
|
|
si.si_addr = (void __user *)addr;
|
|
si.si_addr = (void __user *)addr;
|
|
- force_sig_info(SIGSEGV, &si, tsk);
|
|
|
|
|
|
+ force_sig_info(sig, &si, tsk);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
void
|
|
@@ -140,7 +141,7 @@ do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
|
|
* have no context to handle this fault with.
|
|
* have no context to handle this fault with.
|
|
*/
|
|
*/
|
|
if (user_mode(regs))
|
|
if (user_mode(regs))
|
|
- __do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs);
|
|
|
|
|
|
+ __do_user_fault(tsk, addr, fsr, SIGSEGV, SEGV_MAPERR, regs);
|
|
else
|
|
else
|
|
__do_kernel_fault(mm, addr, fsr, regs);
|
|
__do_kernel_fault(mm, addr, fsr, regs);
|
|
}
|
|
}
|
|
@@ -201,10 +202,11 @@ survive:
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
/*
|
|
/*
|
|
- * If we are out of memory for pid1,
|
|
|
|
- * sleep for a while and retry
|
|
|
|
|
|
+ * If we are out of memory for pid1, sleep for a while and retry
|
|
*/
|
|
*/
|
|
|
|
+ up_read(&mm->mmap_sem);
|
|
yield();
|
|
yield();
|
|
|
|
+ down_read(&mm->mmap_sem);
|
|
goto survive;
|
|
goto survive;
|
|
|
|
|
|
check_stack:
|
|
check_stack:
|
|
@@ -219,7 +221,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|
{
|
|
{
|
|
struct task_struct *tsk;
|
|
struct task_struct *tsk;
|
|
struct mm_struct *mm;
|
|
struct mm_struct *mm;
|
|
- int fault;
|
|
|
|
|
|
+ int fault, sig, code;
|
|
|
|
|
|
tsk = current;
|
|
tsk = current;
|
|
mm = tsk->mm;
|
|
mm = tsk->mm;
|
|
@@ -241,13 +243,6 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|
if (fault > 0)
|
|
if (fault > 0)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- /*
|
|
|
|
- * We had some memory, but were unable to
|
|
|
|
- * successfully fix up this page fault.
|
|
|
|
- */
|
|
|
|
- if (fault == 0)
|
|
|
|
- goto do_sigbus;
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* If we are in kernel mode at this point, we
|
|
* If we are in kernel mode at this point, we
|
|
* have no context to handle this fault with.
|
|
* have no context to handle this fault with.
|
|
@@ -255,42 +250,39 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|
if (!user_mode(regs))
|
|
if (!user_mode(regs))
|
|
goto no_context;
|
|
goto no_context;
|
|
|
|
|
|
- if (fault == VM_FAULT_OOM) {
|
|
|
|
|
|
+ switch (fault) {
|
|
|
|
+ case VM_FAULT_OOM:
|
|
/*
|
|
/*
|
|
- * We ran out of memory, or some other thing happened to
|
|
|
|
- * us that made us unable to handle the page fault gracefully.
|
|
|
|
|
|
+ * We ran out of memory, or some other thing
|
|
|
|
+ * happened to us that made us unable to handle
|
|
|
|
+ * the page fault gracefully.
|
|
*/
|
|
*/
|
|
printk("VM: killing process %s\n", tsk->comm);
|
|
printk("VM: killing process %s\n", tsk->comm);
|
|
do_exit(SIGKILL);
|
|
do_exit(SIGKILL);
|
|
- } else
|
|
|
|
- __do_user_fault(tsk, addr, fsr, fault == VM_FAULT_BADACCESS ?
|
|
|
|
- SEGV_ACCERR : SEGV_MAPERR, regs);
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
+ case 0:
|
|
|
|
+ /*
|
|
|
|
+ * We had some memory, but were unable to
|
|
|
|
+ * successfully fix up this page fault.
|
|
|
|
+ */
|
|
|
|
+ sig = SIGBUS;
|
|
|
|
+ code = BUS_ADRERR;
|
|
|
|
+ break;
|
|
|
|
|
|
-/*
|
|
|
|
- * We ran out of memory, or some other thing happened to us that made
|
|
|
|
- * us unable to handle the page fault gracefully.
|
|
|
|
- */
|
|
|
|
-do_sigbus:
|
|
|
|
- /*
|
|
|
|
- * Send a sigbus, regardless of whether we were in kernel
|
|
|
|
- * or user mode.
|
|
|
|
- */
|
|
|
|
- tsk->thread.address = addr;
|
|
|
|
- tsk->thread.error_code = fsr;
|
|
|
|
- tsk->thread.trap_no = 14;
|
|
|
|
- force_sig(SIGBUS, tsk);
|
|
|
|
-#ifdef CONFIG_DEBUG_USER
|
|
|
|
- if (user_debug & UDBG_BUS) {
|
|
|
|
- printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n",
|
|
|
|
- current->comm, addr, instruction_pointer(regs));
|
|
|
|
|
|
+ default:
|
|
|
|
+ /*
|
|
|
|
+ * Something tried to access memory that
|
|
|
|
+ * isn't in our memory map..
|
|
|
|
+ */
|
|
|
|
+ sig = SIGSEGV;
|
|
|
|
+ code = fault == VM_FAULT_BADACCESS ?
|
|
|
|
+ SEGV_ACCERR : SEGV_MAPERR;
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
|
|
|
|
- /* Kernel mode? Handle exceptions or die */
|
|
|
|
- if (user_mode(regs))
|
|
|
|
- return 0;
|
|
|
|
|
|
+ __do_user_fault(tsk, addr, fsr, sig, code, regs);
|
|
|
|
+ return 0;
|
|
|
|
|
|
no_context:
|
|
no_context:
|
|
__do_kernel_fault(mm, addr, fsr, regs);
|
|
__do_kernel_fault(mm, addr, fsr, regs);
|