diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-11-27 02:40:02 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-11-27 02:40:02 +0000 |
commit | a9d7bff9a84dba79609a0002e5321b74c4d64c64 (patch) | |
tree | 367fc99c77ad8679039867a7e864f63d9a1f0a3f /arch/mips | |
parent | 681da38cd51623972fce0f22d20000d004f423b7 (diff) |
Fix vmalloc which got broken by test10. Still fishy, dunno why.
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/mm/fault.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 1d9308848..5d9ecbc4d 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -49,6 +49,18 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write, unsigned long fixup; siginfo_t info; + /* + * We fault-in kernel-space virtual memory on-demand. The + * 'reference' page table is init_mm.pgd. + * + * NOTE! We MUST NOT take any locks for this case. We may + * be in an interrupt or a critical region, and should + * only copy the information from the master page table, + * nothing more. + */ + if (address >= TASK_SIZE) + goto vmalloc_fault; + info.si_code = SEGV_MAPERR; /* * If we're in an interrupt or have no user @@ -113,6 +125,8 @@ good_area: bad_area: up(&mm->mmap_sem); +bad_area_nosemaphore: + /* User mode accesses just cause a SIGSEGV */ if (user_mode(regs)) { tsk->thread.cp0_badvaddr = address; tsk->thread.error_code = write; @@ -186,4 +200,26 @@ do_sigbus: /* Kernel mode? Handle exceptions or die */ if (!user_mode(regs)) goto no_context; + + return; + +vmalloc_fault: + { + /* + * Synchronize this task's top level page-table + * with the 'reference' page table. + */ + int offset = pgd_index(address); + pgd_t *pgd, *pgd_k; + pmd_t *pmd, *pmd_k; + + pgd = tsk->active_mm->pgd + offset; + pgd_k = init_mm.pgd + offset; + + if (!pgd_present(*pgd)) { + if (!pgd_present(*pgd_k)) + goto bad_area_nosemaphore; + set_pgd(pgd, *pgd_k); + } + } } |