diff -urN 2.3.47pre7/arch/alpha/mm/fault.c oom/arch/alpha/mm/fault.c --- 2.3.47pre7/arch/alpha/mm/fault.c Wed Nov 24 18:22:03 1999 +++ oom/arch/alpha/mm/fault.c Mon Feb 21 01:21:29 2000 @@ -130,13 +130,13 @@ * make sure we exit gracefully rather than endlessly redo * the fault. */ +survive: fault = handle_mm_fault(current, vma, address, cause > 0); - up(&mm->mmap_sem); - if (fault < 0) goto out_of_memory; if (fault == 0) goto do_sigbus; + up(&mm->mmap_sem); return; @@ -177,13 +177,23 @@ * us unable to handle the page fault gracefully. */ out_of_memory: - printk(KERN_ALERT "VM: killing process %s(%d)\n", - current->comm, current->pid); - if (!user_mode(regs)) - goto no_context; - do_exit(SIGKILL); + if (current->pid == 1) + { + current->policy |= SCHED_YIELD; + schedule(); + goto survive; + } + up(&mm->mmap_sem); + if (user_mode(regs)) + { + printk(KERN_ALERT "VM: killing process %s(%d)\n", + current->comm, current->pid); + do_exit(SIGKILL); + } + goto no_context; do_sigbus: + up(&mm->mmap_sem); /* * Send a sigbus, regardless of whether we were in kernel * or user mode. diff -urN 2.3.47pre7/arch/i386/mm/fault.c oom/arch/i386/mm/fault.c --- 2.3.47pre7/arch/i386/mm/fault.c Sun Jan 30 15:43:27 2000 +++ oom/arch/i386/mm/fault.c Mon Feb 21 01:21:29 2000 @@ -32,6 +32,7 @@ { struct vm_area_struct * vma; unsigned long start = (unsigned long) addr; + int fault; if (!size) return 1; @@ -51,8 +52,12 @@ start &= PAGE_MASK; for (;;) { - if (handle_mm_fault(current, vma, start, 1) <= 0) - goto bad_area; +survive: + fault = handle_mm_fault(current, vma, start, 1); + if (!fault) + goto do_sigbus; + if (fault < 0) + goto out_of_memory; if (!size) break; size--; @@ -75,6 +80,19 @@ bad_area: return 0; + +do_sigbus: + force_sig(SIGBUS, current); + goto bad_area; + +out_of_memory: + if (current->pid == 1) + { + current->policy |= SCHED_YIELD; + schedule(); + goto survive; + } + goto bad_area; } static void __init handle_wp_test (void) @@ -192,6 +210,7 @@ * make sure we exit gracefully rather than endlessly redo * the fault. */ +survive: { int fault = handle_mm_fault(tsk, vma, address, write); if (fault < 0) @@ -288,10 +307,39 @@ * 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); - printk("VM: killing process %s\n", tsk->comm); if (error_code & 4) - do_exit(SIGKILL); + { + if (tsk->oom_kill_try++ > 10 || + !((regs->eflags >> 12) & 3)) + { + printk(KERN_ALERT "VM: killing process %s\n", + tsk->comm); + do_exit(SIGKILL); + } + else + { + /* + * The task is running with privilegies and so we + * trust it and we give it a chance to die gracefully. + */ + printk(KERN_ALERT "VM: terminating process %s\n", + tsk->comm); + force_sig(SIGTERM, current); + if (tsk->oom_kill_try > 1) + { + tsk->policy |= SCHED_YIELD; + schedule(); + } + return; + } + } goto no_context; do_sigbus: diff -urN 2.3.47pre7/include/linux/sched.h oom/include/linux/sched.h --- 2.3.47pre7/include/linux/sched.h Mon Feb 21 01:02:36 2000 +++ oom/include/linux/sched.h Mon Feb 21 01:22:23 2000 @@ -356,6 +356,9 @@ u32 self_exec_id; /* Protection of fields allocatio/deallocation */ struct semaphore exit_sem; + +/* oom handling, left at the end since it's not critical info */ + int oom_kill_try; }; /* @@ -425,7 +428,8 @@ blocked: {{0}}, \ sigqueue: NULL, \ sigqueue_tail: &tsk.sigqueue, \ - exit_sem: __MUTEX_INITIALIZER(tsk.exit_sem) \ + exit_sem: __MUTEX_INITIALIZER(tsk.exit_sem), \ + oom_kill_try: 0, \ } diff -urN 2.3.47pre7/kernel/ptrace.c oom/kernel/ptrace.c --- 2.3.47pre7/kernel/ptrace.c Tue Feb 15 03:06:49 2000 +++ oom/kernel/ptrace.c Mon Feb 21 01:21:29 2000 @@ -26,6 +26,7 @@ unsigned long mapnr; unsigned long maddr; struct page *page; + int fault; repeat: pgdir = pgd_offset(vma->vm_mm, addr); @@ -65,8 +66,12 @@ fault_in_page: /* -1: out of memory. 0 - unmapped page */ - if (handle_mm_fault(tsk, vma, addr, write) > 0) + fault = handle_mm_fault(tsk, vma, addr, write); + if (fault > 0) goto repeat; + if (fault < 0) + /* the out of memory is been triggered by the current task. */ + force_sig(SIGKILL, current); return 0; bad_pgd: