diff options
author | Oleg Nesterov <oleg@redhat.com> | 2012-11-25 16:01:42 -0500 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2013-02-08 11:47:09 -0500 |
commit | 06b7bcd8cbd7eb1af331e437ec3d8f5182ae1b7e (patch) | |
tree | ad2fc6a39d2c5ecfa45f4cd13fd0140839894b52 /kernel/events | |
parent | 441f1eb7db8babe2b6b4bc805f023739dbb70e33 (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.c | 8 |
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 | ||
672 | static 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 | */ |
677 | static void delete_uprobe(struct uprobe *uprobe) | 681 | static 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 | } |