aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-11-25 16:01:42 -0500
committerOleg Nesterov <oleg@redhat.com>2013-02-08 11:47:09 -0500
commit06b7bcd8cbd7eb1af331e437ec3d8f5182ae1b7e (patch)
treead2fc6a39d2c5ecfa45f4cd13fd0140839894b52 /kernel/events
parent441f1eb7db8babe2b6b4bc805f023739dbb70e33 (diff)
uprobes: Introduce uprobe_is_active()
The lifetime of uprobe->rb_node and uprobe->inode is not refcounted, delete_uprobe() is called when we detect that uprobe has no consumers, and it would be deadly wrong to do this twice. Change delete_uprobe() to WARN() if it was already called. We use RB_CLEAR_NODE() to mark uprobe "inactive", then RB_EMPTY_NODE() can be used to detect this case. RB_EMPTY_NODE() is not used directly, we add the trivial helper for the next change. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Anton Arapov <anton@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/events')
-rw-r--r--kernel/events/uprobes.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 5d38b40644b8..358baddc8ac2 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -669,6 +669,10 @@ remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vad
669 return set_orig_insn(&uprobe->arch, mm, vaddr); 669 return set_orig_insn(&uprobe->arch, mm, vaddr);
670} 670}
671 671
672static inline bool uprobe_is_active(struct uprobe *uprobe)
673{
674 return !RB_EMPTY_NODE(&uprobe->rb_node);
675}
672/* 676/*
673 * There could be threads that have already hit the breakpoint. They 677 * There could be threads that have already hit the breakpoint. They
674 * will recheck the current insn and restart if find_uprobe() fails. 678 * will recheck the current insn and restart if find_uprobe() fails.
@@ -676,9 +680,13 @@ remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vad
676 */ 680 */
677static void delete_uprobe(struct uprobe *uprobe) 681static void delete_uprobe(struct uprobe *uprobe)
678{ 682{
683 if (WARN_ON(!uprobe_is_active(uprobe)))
684 return;
685
679 spin_lock(&uprobes_treelock); 686 spin_lock(&uprobes_treelock);
680 rb_erase(&uprobe->rb_node, &uprobes_tree); 687 rb_erase(&uprobe->rb_node, &uprobes_tree);
681 spin_unlock(&uprobes_treelock); 688 spin_unlock(&uprobes_treelock);
689 RB_CLEAR_NODE(&uprobe->rb_node); /* for uprobe_is_active() */
682 iput(uprobe->inode); 690 iput(uprobe->inode);
683 put_uprobe(uprobe); 691 put_uprobe(uprobe);
684} 692}