aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/mm/fault.c')
-rw-r--r--arch/x86_64/mm/fault.c81
1 files changed, 65 insertions, 16 deletions
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 2e7c3c8ffe03..55250593d8c9 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -264,6 +264,8 @@ static int vmalloc_fault(unsigned long address)
264 return -1; 264 return -1;
265 if (pgd_none(*pgd)) 265 if (pgd_none(*pgd))
266 set_pgd(pgd, *pgd_ref); 266 set_pgd(pgd, *pgd_ref);
267 else
268 BUG_ON(pgd_page(*pgd) != pgd_page(*pgd_ref));
267 269
268 /* Below here mismatches are bugs because these lower tables 270 /* Below here mismatches are bugs because these lower tables
269 are shared */ 271 are shared */
@@ -312,21 +314,13 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
312 unsigned long flags; 314 unsigned long flags;
313 siginfo_t info; 315 siginfo_t info;
314 316
317 tsk = current;
318 mm = tsk->mm;
319 prefetchw(&mm->mmap_sem);
320
315 /* get the address */ 321 /* get the address */
316 __asm__("movq %%cr2,%0":"=r" (address)); 322 __asm__("movq %%cr2,%0":"=r" (address));
317 if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
318 SIGSEGV) == NOTIFY_STOP)
319 return;
320
321 if (likely(regs->eflags & X86_EFLAGS_IF))
322 local_irq_enable();
323 323
324 if (unlikely(page_fault_trace))
325 printk("pagefault rip:%lx rsp:%lx cs:%lu ss:%lu address %lx error %lx\n",
326 regs->rip,regs->rsp,regs->cs,regs->ss,address,error_code);
327
328 tsk = current;
329 mm = tsk->mm;
330 info.si_code = SEGV_MAPERR; 324 info.si_code = SEGV_MAPERR;
331 325
332 326
@@ -351,10 +345,12 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
351 */ 345 */
352 if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) && 346 if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
353 ((address >= VMALLOC_START && address < VMALLOC_END))) { 347 ((address >= VMALLOC_START && address < VMALLOC_END))) {
354 if (vmalloc_fault(address) < 0) 348 if (vmalloc_fault(address) >= 0)
355 goto bad_area_nosemaphore; 349 return;
356 return;
357 } 350 }
351 if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
352 SIGSEGV) == NOTIFY_STOP)
353 return;
358 /* 354 /*
359 * Don't take the mm semaphore here. If we fixup a prefetch 355 * Don't take the mm semaphore here. If we fixup a prefetch
360 * fault we could otherwise deadlock. 356 * fault we could otherwise deadlock.
@@ -362,6 +358,17 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
362 goto bad_area_nosemaphore; 358 goto bad_area_nosemaphore;
363 } 359 }
364 360
361 if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
362 SIGSEGV) == NOTIFY_STOP)
363 return;
364
365 if (likely(regs->eflags & X86_EFLAGS_IF))
366 local_irq_enable();
367
368 if (unlikely(page_fault_trace))
369 printk("pagefault rip:%lx rsp:%lx cs:%lu ss:%lu address %lx error %lx\n",
370 regs->rip,regs->rsp,regs->cs,regs->ss,address,error_code);
371
365 if (unlikely(error_code & PF_RSVD)) 372 if (unlikely(error_code & PF_RSVD))
366 pgtable_bad(address, regs, error_code); 373 pgtable_bad(address, regs, error_code);
367 374
@@ -571,9 +578,51 @@ do_sigbus:
571 return; 578 return;
572} 579}
573 580
581DEFINE_SPINLOCK(pgd_lock);
582struct page *pgd_list;
583
584void vmalloc_sync_all(void)
585{
586 /* Note that races in the updates of insync and start aren't
587 problematic:
588 insync can only get set bits added, and updates to start are only
589 improving performance (without affecting correctness if undone). */
590 static DECLARE_BITMAP(insync, PTRS_PER_PGD);
591 static unsigned long start = VMALLOC_START & PGDIR_MASK;
592 unsigned long address;
593
594 for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
595 if (!test_bit(pgd_index(address), insync)) {
596 const pgd_t *pgd_ref = pgd_offset_k(address);
597 struct page *page;
598
599 if (pgd_none(*pgd_ref))
600 continue;
601 spin_lock(&pgd_lock);
602 for (page = pgd_list; page;
603 page = (struct page *)page->index) {
604 pgd_t *pgd;
605 pgd = (pgd_t *)page_address(page) + pgd_index(address);
606 if (pgd_none(*pgd))
607 set_pgd(pgd, *pgd_ref);
608 else
609 BUG_ON(pgd_page(*pgd) != pgd_page(*pgd_ref));
610 }
611 spin_unlock(&pgd_lock);
612 set_bit(pgd_index(address), insync);
613 }
614 if (address == start)
615 start = address + PGDIR_SIZE;
616 }
617 /* Check that there is no need to do the same for the modules area. */
618 BUILD_BUG_ON(!(MODULES_VADDR > __START_KERNEL));
619 BUILD_BUG_ON(!(((MODULES_END - 1) & PGDIR_MASK) ==
620 (__START_KERNEL & PGDIR_MASK)));
621}
622
574static int __init enable_pagefaulttrace(char *str) 623static int __init enable_pagefaulttrace(char *str)
575{ 624{
576 page_fault_trace = 1; 625 page_fault_trace = 1;
577 return 0; 626 return 1;
578} 627}
579__setup("pagefaulttrace", enable_pagefaulttrace); 628__setup("pagefaulttrace", enable_pagefaulttrace);