Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'uprobes/core' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc into perf/core

Pull uprobes fixes, cleanups and preparation for the ARM port from Oleg Nesterov.

Signed-off-by: Ingo Molnar <mingo@kernel.org>

+65 -56
+1 -3
arch/powerpc/kernel/signal.c
··· 158 158 159 159 void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) 160 160 { 161 - if (thread_info_flags & _TIF_UPROBE) { 162 - clear_thread_flag(TIF_UPROBE); 161 + if (thread_info_flags & _TIF_UPROBE) 163 162 uprobe_notify_resume(regs); 164 - } 165 163 166 164 if (thread_info_flags & _TIF_SIGPENDING) 167 165 do_signal(regs);
+6
arch/powerpc/kernel/uprobes.c
··· 64 64 autask->saved_trap_nr = current->thread.trap_nr; 65 65 current->thread.trap_nr = UPROBE_TRAP_NR; 66 66 regs->nip = current->utask->xol_vaddr; 67 + 68 + user_enable_single_step(current); 67 69 return 0; 68 70 } 69 71 ··· 121 119 * to be executed. 122 120 */ 123 121 regs->nip = utask->vaddr + MAX_UINSN_BYTES; 122 + 123 + user_disable_single_step(current); 124 124 return 0; 125 125 } 126 126 ··· 166 162 167 163 current->thread.trap_nr = utask->autask.saved_trap_nr; 168 164 instruction_pointer_set(regs, utask->vaddr); 165 + 166 + user_disable_single_step(current); 169 167 } 170 168 171 169 /*
+19 -35
arch/x86/kernel/uprobes.c
··· 478 478 regs->ip = current->utask->xol_vaddr; 479 479 pre_xol_rip_insn(auprobe, regs, autask); 480 480 481 + autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); 482 + regs->flags |= X86_EFLAGS_TF; 483 + if (test_tsk_thread_flag(current, TIF_BLOCKSTEP)) 484 + set_task_blockstep(current, false); 485 + 481 486 return 0; 482 487 } 483 488 ··· 608 603 if (auprobe->fixups & UPROBE_FIX_CALL) 609 604 result = adjust_ret_addr(regs->sp, correction); 610 605 606 + /* 607 + * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP 608 + * so we can get an extra SIGTRAP if we do not clear TF. We need 609 + * to examine the opcode to make it right. 610 + */ 611 + if (utask->autask.saved_tf) 612 + send_sig(SIGTRAP, current, 0); 613 + else if (!(auprobe->fixups & UPROBE_FIX_SETF)) 614 + regs->flags &= ~X86_EFLAGS_TF; 615 + 611 616 return result; 612 617 } 613 618 ··· 662 647 current->thread.trap_nr = utask->autask.saved_trap_nr; 663 648 handle_riprel_post_xol(auprobe, regs, NULL); 664 649 instruction_pointer_set(regs, utask->vaddr); 650 + 651 + /* clear TF if it was set by us in arch_uprobe_pre_xol() */ 652 + if (!utask->autask.saved_tf) 653 + regs->flags &= ~X86_EFLAGS_TF; 665 654 } 666 655 667 656 /* ··· 694 675 if (ret && (regs->flags & X86_EFLAGS_TF)) 695 676 send_sig(SIGTRAP, current, 0); 696 677 return ret; 697 - } 698 - 699 - void arch_uprobe_enable_step(struct arch_uprobe *auprobe) 700 - { 701 - struct task_struct *task = current; 702 - struct arch_uprobe_task *autask = &task->utask->autask; 703 - struct pt_regs *regs = task_pt_regs(task); 704 - 705 - autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); 706 - 707 - regs->flags |= X86_EFLAGS_TF; 708 - if (test_tsk_thread_flag(task, TIF_BLOCKSTEP)) 709 - set_task_blockstep(task, false); 710 - } 711 - 712 - void arch_uprobe_disable_step(struct arch_uprobe *auprobe) 713 - { 714 - struct task_struct *task = current; 715 - struct arch_uprobe_task *autask = &task->utask->autask; 716 - bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED); 717 - struct pt_regs *regs = task_pt_regs(task); 718 - /* 719 - * The state of TIF_BLOCKSTEP was not saved so we can get an extra 720 - * SIGTRAP if we do not clear TF. We need to examine the opcode to 721 - * make it right. 722 - */ 723 - if (unlikely(trapped)) { 724 - if (!autask->saved_tf) 725 - regs->flags &= ~X86_EFLAGS_TF; 726 - } else { 727 - if (autask->saved_tf) 728 - send_sig(SIGTRAP, task, 0); 729 - else if (!(auprobe->fixups & UPROBE_FIX_SETF)) 730 - regs->flags &= ~X86_EFLAGS_TF; 731 - } 732 678 }
+8 -2
include/linux/uprobes.h
··· 97 97 extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); 98 98 extern int uprobe_mmap(struct vm_area_struct *vma); 99 99 extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); 100 + extern void uprobe_start_dup_mmap(void); 101 + extern void uprobe_end_dup_mmap(void); 100 102 extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); 101 103 extern void uprobe_free_utask(struct task_struct *t); 102 104 extern void uprobe_copy_process(struct task_struct *t); 103 105 extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); 104 - extern void __weak arch_uprobe_enable_step(struct arch_uprobe *arch); 105 - extern void __weak arch_uprobe_disable_step(struct arch_uprobe *arch); 106 106 extern int uprobe_post_sstep_notifier(struct pt_regs *regs); 107 107 extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); 108 108 extern void uprobe_notify_resume(struct pt_regs *regs); ··· 127 127 } 128 128 static inline void 129 129 uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) 130 + { 131 + } 132 + static inline void uprobe_start_dup_mmap(void) 133 + { 134 + } 135 + static inline void uprobe_end_dup_mmap(void) 130 136 { 131 137 } 132 138 static inline void
+28 -15
kernel/events/uprobes.c
··· 33 33 #include <linux/ptrace.h> /* user_enable_single_step */ 34 34 #include <linux/kdebug.h> /* notifier mechanism */ 35 35 #include "../../mm/internal.h" /* munlock_vma_page */ 36 + #include <linux/percpu-rwsem.h> 36 37 37 38 #include <linux/uprobes.h> 38 39 ··· 71 70 /* serialize uprobe->pending_list */ 72 71 static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; 73 72 #define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) 73 + 74 + static struct percpu_rw_semaphore dup_mmap_sem; 74 75 75 76 /* 76 77 * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe ··· 769 766 struct map_info *info; 770 767 int err = 0; 771 768 769 + percpu_down_write(&dup_mmap_sem); 772 770 info = build_map_info(uprobe->inode->i_mapping, 773 771 uprobe->offset, is_register); 774 - if (IS_ERR(info)) 775 - return PTR_ERR(info); 772 + if (IS_ERR(info)) { 773 + err = PTR_ERR(info); 774 + goto out; 775 + } 776 776 777 777 while (info) { 778 778 struct mm_struct *mm = info->mm; ··· 805 799 mmput(mm); 806 800 info = free_map_info(info); 807 801 } 808 - 802 + out: 803 + percpu_up_write(&dup_mmap_sem); 809 804 return err; 810 805 } 811 806 ··· 1138 1131 kfree(area); 1139 1132 } 1140 1133 1134 + void uprobe_start_dup_mmap(void) 1135 + { 1136 + percpu_down_read(&dup_mmap_sem); 1137 + } 1138 + 1139 + void uprobe_end_dup_mmap(void) 1140 + { 1141 + percpu_up_read(&dup_mmap_sem); 1142 + } 1143 + 1141 1144 void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) 1142 1145 { 1143 1146 newmm->uprobes_state.xol_area = NULL; ··· 1216 1199 vaddr = kmap_atomic(area->page); 1217 1200 memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES); 1218 1201 kunmap_atomic(vaddr); 1202 + /* 1203 + * We probably need flush_icache_user_range() but it needs vma. 1204 + * This should work on supported architectures too. 1205 + */ 1206 + flush_dcache_page(area->page); 1219 1207 1220 1208 return current->utask->xol_vaddr; 1221 1209 } ··· 1452 1430 return uprobe; 1453 1431 } 1454 1432 1455 - void __weak arch_uprobe_enable_step(struct arch_uprobe *arch) 1456 - { 1457 - user_enable_single_step(current); 1458 - } 1459 - 1460 - void __weak arch_uprobe_disable_step(struct arch_uprobe *arch) 1461 - { 1462 - user_disable_single_step(current); 1463 - } 1464 - 1465 1433 /* 1466 1434 * Run handler and ask thread to singlestep. 1467 1435 * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. ··· 1505 1493 goto out; 1506 1494 1507 1495 if (!pre_ssout(uprobe, regs, bp_vaddr)) { 1508 - arch_uprobe_enable_step(&uprobe->arch); 1509 1496 utask->active_uprobe = uprobe; 1510 1497 utask->state = UTASK_SSTEP; 1511 1498 return; ··· 1536 1525 else 1537 1526 WARN_ON_ONCE(1); 1538 1527 1539 - arch_uprobe_disable_step(&uprobe->arch); 1540 1528 put_uprobe(uprobe); 1541 1529 utask->active_uprobe = NULL; 1542 1530 utask->state = UTASK_RUNNING; ··· 1613 1603 mutex_init(&uprobes_mutex[i]); 1614 1604 mutex_init(&uprobes_mmap_mutex[i]); 1615 1605 } 1606 + 1607 + if (percpu_init_rwsem(&dup_mmap_sem)) 1608 + return -ENOMEM; 1616 1609 1617 1610 return register_die_notifier(&uprobe_exception_nb); 1618 1611 }
+2
kernel/fork.c
··· 352 352 unsigned long charge; 353 353 struct mempolicy *pol; 354 354 355 + uprobe_start_dup_mmap(); 355 356 down_write(&oldmm->mmap_sem); 356 357 flush_cache_dup_mm(oldmm); 357 358 uprobe_dup_mmap(oldmm, mm); ··· 470 469 up_write(&mm->mmap_sem); 471 470 flush_tlb_mm(oldmm); 472 471 up_write(&oldmm->mmap_sem); 472 + uprobe_end_dup_mmap(); 473 473 return retval; 474 474 fail_nomem_anon_vma_fork: 475 475 mpol_put(pol);
+1 -1
kernel/trace/trace_uprobe.c
··· 189 189 if (argv[0][0] == '-') 190 190 is_delete = true; 191 191 else if (argv[0][0] != 'p') { 192 - pr_info("Probe definition must be started with 'p', 'r' or" " '-'.\n"); 192 + pr_info("Probe definition must be started with 'p' or '-'.\n"); 193 193 return -EINVAL; 194 194 } 195 195