aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-11-23 13:43:50 -0500
committerOleg Nesterov <oleg@redhat.com>2013-02-08 11:47:03 -0500
commit04aab9b2006bbdeff78dc162f206fdfebeca97d9 (patch)
tree380a170734c6d850077e56848df0528f410247be
parent63633cbf82840d972248f11d2122b261d0d4779a (diff)
uprobes: _unregister() should always do register_for_each_vma(false)
uprobe_unregister() removes the breakpoints only if the last consumer goes away. To support the filtering it should do this every time, we want to remove the breakpoints which nobody else want to keep. Note: given that filter_chain() is not actually implemented, this patch itself doesn't change the behaviour yet, register_for_each_vma(false) is a heavy "nop" unless there are no more consumers. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
-rw-r--r--kernel/events/uprobes.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index c38bf37d0aca..940199084639 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -825,12 +825,20 @@ static int __uprobe_register(struct uprobe *uprobe)
825 return register_for_each_vma(uprobe, true); 825 return register_for_each_vma(uprobe, true);
826} 826}
827 827
828static void __uprobe_unregister(struct uprobe *uprobe) 828static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *uc)
829{ 829{
830 if (!register_for_each_vma(uprobe, false)) 830 int err;
831 delete_uprobe(uprobe); 831
832 if (!consumer_del(uprobe, uc)) /* WARN? */
833 return;
832 834
833 /* TODO : cant unregister? schedule a worker thread */ 835 err = register_for_each_vma(uprobe, false);
836 if (!uprobe->consumers) {
837 clear_bit(UPROBE_RUN_HANDLER, &uprobe->flags);
838 /* TODO : cant unregister? schedule a worker thread */
839 if (!err)
840 delete_uprobe(uprobe);
841 }
834} 842}
835 843
836/* 844/*
@@ -868,8 +876,7 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *
868 } else if (!consumer_add(uprobe, uc)) { 876 } else if (!consumer_add(uprobe, uc)) {
869 ret = __uprobe_register(uprobe); 877 ret = __uprobe_register(uprobe);
870 if (ret) { 878 if (ret) {
871 uprobe->consumers = NULL; 879 __uprobe_unregister(uprobe, uc);
872 __uprobe_unregister(uprobe);
873 } else { 880 } else {
874 set_bit(UPROBE_RUN_HANDLER, &uprobe->flags); 881 set_bit(UPROBE_RUN_HANDLER, &uprobe->flags);
875 } 882 }
@@ -897,14 +904,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
897 return; 904 return;
898 905
899 mutex_lock(uprobes_hash(inode)); 906 mutex_lock(uprobes_hash(inode));
900 907 __uprobe_unregister(uprobe, uc);
901 if (consumer_del(uprobe, uc)) {
902 if (!uprobe->consumers) {
903 __uprobe_unregister(uprobe);
904 clear_bit(UPROBE_RUN_HANDLER, &uprobe->flags);
905 }
906 }
907
908 mutex_unlock(uprobes_hash(inode)); 908 mutex_unlock(uprobes_hash(inode));
909 put_uprobe(uprobe); 909 put_uprobe(uprobe);
910} 910}