aboutsummaryrefslogtreecommitdiff
path: root/kernel/events
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-11-23 19:43:50 +0100
committerOleg Nesterov <oleg@redhat.com>2013-02-08 17:47:03 +0100
commit04aab9b2006bbdeff78dc162f206fdfebeca97d9 (patch)
tree380a170734c6d850077e56848df0528f410247be /kernel/events
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>
Diffstat (limited to 'kernel/events')
-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 c38bf37d0ac..94019908463 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -825,12 +825,20 @@ static int __uprobe_register(struct uprobe *uprobe)
return register_for_each_vma(uprobe, true);
}
-static void __uprobe_unregister(struct uprobe *uprobe)
+static void __uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *uc)
{
- if (!register_for_each_vma(uprobe, false))
- delete_uprobe(uprobe);
+ int err;
+
+ if (!consumer_del(uprobe, uc)) /* WARN? */
+ return;
- /* TODO : cant unregister? schedule a worker thread */
+ err = register_for_each_vma(uprobe, false);
+ if (!uprobe->consumers) {
+ clear_bit(UPROBE_RUN_HANDLER, &uprobe->flags);
+ /* TODO : cant unregister? schedule a worker thread */
+ if (!err)
+ delete_uprobe(uprobe);
+ }
}
/*
@@ -868,8 +876,7 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *
} else if (!consumer_add(uprobe, uc)) {
ret = __uprobe_register(uprobe);
if (ret) {
- uprobe->consumers = NULL;
- __uprobe_unregister(uprobe);
+ __uprobe_unregister(uprobe, uc);
} else {
set_bit(UPROBE_RUN_HANDLER, &uprobe->flags);
}
@@ -897,14 +904,7 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
return;
mutex_lock(uprobes_hash(inode));
-
- if (consumer_del(uprobe, uc)) {
- if (!uprobe->consumers) {
- __uprobe_unregister(uprobe);
- clear_bit(UPROBE_RUN_HANDLER, &uprobe->flags);
- }
- }
-
+ __uprobe_unregister(uprobe, uc);
mutex_unlock(uprobes_hash(inode));
put_uprobe(uprobe);
}