diff options
author | Oleg Nesterov <oleg@redhat.com> | 2012-12-27 12:21:11 -0500 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2013-02-08 11:47:10 -0500 |
commit | 806a98bdf2a862fef0fc880399d677b35ba525ff (patch) | |
tree | 5b322a48c4d22d15e8d1a6c8a6a7e28d77ce62a7 /kernel | |
parent | 66d06dffa5ef6f3544997440af63a91ef36a2171 (diff) |
uprobes: Rationalize the usage of filter_chain()
filter_chain() was added into install_breakpoint/remove_breakpoint to
simplify the initial changes but this is sub-optimal.
This patch shifts the callsite to the callers, register_for_each_vma()
and uprobe_mmap(). This way:
- It will be easier to add the new arguments. This is the main reason,
we can do more optimizations later.
- register_for_each_vma(is_register => true) can be optimized, we only
need to consult the new consumer. The previous consumers were already
asked when they called uprobe_register().
This patch also moves the MMF_HAS_UPROBES check from remove_breakpoint(),
this allows to avoid the potentionally costly filter_chain(). Note that
register_for_each_vma(is_register => false) doesn't really need to take
->consumer_rwsem, but I don't think it makes sense to optimize this and
introduce filter_chain_lockless().
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/events/uprobes.c | 44 |
1 files changed, 21 insertions, 23 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index c3b65d1c8443..33912086d54e 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -579,6 +579,11 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file, | |||
579 | return ret; | 579 | return ret; |
580 | } | 580 | } |
581 | 581 | ||
582 | static inline bool consumer_filter(struct uprobe_consumer *uc) | ||
583 | { | ||
584 | return true; /* TODO: !uc->filter || uc->filter(...) */ | ||
585 | } | ||
586 | |||
582 | static bool filter_chain(struct uprobe *uprobe) | 587 | static bool filter_chain(struct uprobe *uprobe) |
583 | { | 588 | { |
584 | struct uprobe_consumer *uc; | 589 | struct uprobe_consumer *uc; |
@@ -586,8 +591,7 @@ static bool filter_chain(struct uprobe *uprobe) | |||
586 | 591 | ||
587 | down_read(&uprobe->consumer_rwsem); | 592 | down_read(&uprobe->consumer_rwsem); |
588 | for (uc = uprobe->consumers; uc; uc = uc->next) { | 593 | for (uc = uprobe->consumers; uc; uc = uc->next) { |
589 | /* TODO: ret = uc->filter(...) */ | 594 | ret = consumer_filter(uc); |
590 | ret = true; | ||
591 | if (ret) | 595 | if (ret) |
592 | break; | 596 | break; |
593 | } | 597 | } |
@@ -603,15 +607,6 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
603 | bool first_uprobe; | 607 | bool first_uprobe; |
604 | int ret; | 608 | int ret; |
605 | 609 | ||
606 | /* | ||
607 | * If probe is being deleted, unregister thread could be done with | ||
608 | * the vma-rmap-walk through. Adding a probe now can be fatal since | ||
609 | * nobody will be able to cleanup. But in this case filter_chain() | ||
610 | * must return false, all consumers have gone away. | ||
611 | */ | ||
612 | if (!filter_chain(uprobe)) | ||
613 | return 0; | ||
614 | |||
615 | ret = prepare_uprobe(uprobe, vma->vm_file, mm, vaddr); | 610 | ret = prepare_uprobe(uprobe, vma->vm_file, mm, vaddr); |
616 | if (ret) | 611 | if (ret) |
617 | return ret; | 612 | return ret; |
@@ -636,12 +631,6 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
636 | static int | 631 | static int |
637 | remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) | 632 | remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) |
638 | { | 633 | { |
639 | if (!test_bit(MMF_HAS_UPROBES, &mm->flags)) | ||
640 | return 0; | ||
641 | |||
642 | if (filter_chain(uprobe)) | ||
643 | return 0; | ||
644 | |||
645 | set_bit(MMF_RECALC_UPROBES, &mm->flags); | 634 | set_bit(MMF_RECALC_UPROBES, &mm->flags); |
646 | return set_orig_insn(&uprobe->arch, mm, vaddr); | 635 | return set_orig_insn(&uprobe->arch, mm, vaddr); |
647 | } | 636 | } |
@@ -781,10 +770,14 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) | |||
781 | vaddr_to_offset(vma, info->vaddr) != uprobe->offset) | 770 | vaddr_to_offset(vma, info->vaddr) != uprobe->offset) |
782 | goto unlock; | 771 | goto unlock; |
783 | 772 | ||
784 | if (is_register) | 773 | if (is_register) { |
785 | err = install_breakpoint(uprobe, mm, vma, info->vaddr); | 774 | /* consult only the "caller", new consumer. */ |
786 | else | 775 | if (consumer_filter(uprobe->consumers)) |
787 | err |= remove_breakpoint(uprobe, mm, info->vaddr); | 776 | err = install_breakpoint(uprobe, mm, vma, info->vaddr); |
777 | } else if (test_bit(MMF_HAS_UPROBES, &mm->flags)) { | ||
778 | if (!filter_chain(uprobe)) | ||
779 | err |= remove_breakpoint(uprobe, mm, info->vaddr); | ||
780 | } | ||
788 | 781 | ||
789 | unlock: | 782 | unlock: |
790 | up_write(&mm->mmap_sem); | 783 | up_write(&mm->mmap_sem); |
@@ -968,9 +961,14 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
968 | 961 | ||
969 | mutex_lock(uprobes_mmap_hash(inode)); | 962 | mutex_lock(uprobes_mmap_hash(inode)); |
970 | build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list); | 963 | build_probe_list(inode, vma, vma->vm_start, vma->vm_end, &tmp_list); |
971 | 964 | /* | |
965 | * We can race with uprobe_unregister(), this uprobe can be already | ||
966 | * removed. But in this case filter_chain() must return false, all | ||
967 | * consumers have gone away. | ||
968 | */ | ||
972 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { | 969 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { |
973 | if (!fatal_signal_pending(current)) { | 970 | if (!fatal_signal_pending(current) && |
971 | filter_chain(uprobe)) { | ||
974 | unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset); | 972 | unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset); |
975 | install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); | 973 | install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); |
976 | } | 974 | } |