Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 223881
b: refs/heads/master
c: 6f0f1dd
h: refs/heads/master
i:
  223879: dca78b2
v: v3
  • Loading branch information
Masami Hiramatsu authored and Ingo Molnar committed Dec 6, 2010
1 parent 12a6d9d commit 0b839d8
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 57 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6d8e40a85ef72a0514ebd00748eb18cab432b200
refs/heads/master: 6f0f1dd71953d4243c11e490dd49ef24ebaf6c0b
128 changes: 72 additions & 56 deletions trunk/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,23 +1039,6 @@ static int __kprobes register_aggr_kprobe(struct kprobe *orig_p,
return add_new_kprobe(ap, p);
}

/* Try to disable aggr_kprobe, and return 1 if succeeded.*/
static int __kprobes try_to_disable_aggr_kprobe(struct kprobe *p)
{
struct kprobe *kp;

list_for_each_entry_rcu(kp, &p->list, list) {
if (!kprobe_disabled(kp))
/*
* There is an active probe on the list.
* We can't disable aggr_kprobe.
*/
return 0;
}
p->flags |= KPROBE_FLAG_DISABLED;
return 1;
}

static int __kprobes in_kprobes_functions(unsigned long addr)
{
struct kprobe_blackpoint *kb;
Expand Down Expand Up @@ -1228,29 +1211,74 @@ int __kprobes register_kprobe(struct kprobe *p)
}
EXPORT_SYMBOL_GPL(register_kprobe);

/* Check if all probes on the aggrprobe are disabled */
static int __kprobes aggr_kprobe_disabled(struct kprobe *ap)
{
struct kprobe *kp;

list_for_each_entry_rcu(kp, &ap->list, list)
if (!kprobe_disabled(kp))
/*
* There is an active probe on the list.
* We can't disable this ap.
*/
return 0;

return 1;
}

/* Disable one kprobe: Make sure called under kprobe_mutex is locked */
static struct kprobe *__kprobes __disable_kprobe(struct kprobe *p)
{
struct kprobe *orig_p;

/* Get an original kprobe for return */
orig_p = __get_valid_kprobe(p);
if (unlikely(orig_p == NULL))
return NULL;

if (!kprobe_disabled(p)) {
/* Disable probe if it is a child probe */
if (p != orig_p)
p->flags |= KPROBE_FLAG_DISABLED;

/* Try to disarm and disable this/parent probe */
if (p == orig_p || aggr_kprobe_disabled(orig_p)) {
disarm_kprobe(orig_p);
orig_p->flags |= KPROBE_FLAG_DISABLED;
}
}

return orig_p;
}

/*
* Unregister a kprobe without a scheduler synchronization.
*/
static int __kprobes __unregister_kprobe_top(struct kprobe *p)
{
struct kprobe *ap, *list_p;

ap = __get_valid_kprobe(p);
/* Disable kprobe. This will disarm it if needed. */
ap = __disable_kprobe(p);
if (ap == NULL)
return -EINVAL;

if (ap == p ||
(kprobe_aggrprobe(ap) &&
list_is_singular(&ap->list))) {
if (ap == p)
/*
* Only probe on the hash list. Disarm only if kprobes are
* enabled and not gone - otherwise, the breakpoint would
* already have been removed. We save on flushing icache.
* This probe is an independent(and non-optimized) kprobe
* (not an aggrprobe). Remove from the hash list.
*/
if (!kprobes_all_disarmed && !kprobe_disabled(ap))
disarm_kprobe(ap);
hlist_del_rcu(&ap->hlist);
} else {
goto disarmed;

/* Following process expects this probe is an aggrprobe */
WARN_ON(!kprobe_aggrprobe(ap));

if (list_is_singular(&ap->list))
/* This probe is the last child of aggrprobe */
goto disarmed;
else {
/* If disabling probe has special handlers, update aggrprobe */
if (p->break_handler && !kprobe_gone(p))
ap->break_handler = NULL;
if (p->post_handler && !kprobe_gone(p)) {
Expand All @@ -1261,19 +1289,23 @@ static int __kprobes __unregister_kprobe_top(struct kprobe *p)
ap->post_handler = NULL;
}
noclean:
/*
* Remove from the aggrprobe: this path will do nothing in
* __unregister_kprobe_bottom().
*/
list_del_rcu(&p->list);
if (!kprobe_disabled(ap)) {
try_to_disable_aggr_kprobe(ap);
if (!kprobes_all_disarmed) {
if (kprobe_disabled(ap))
disarm_kprobe(ap);
else
/* Try to optimize this probe again */
optimize_kprobe(ap);
}
}
if (!kprobe_disabled(ap) && !kprobes_all_disarmed)
/*
* Try to optimize this probe again, because post
* handler may have been changed.
*/
optimize_kprobe(ap);
}
return 0;

disarmed:
hlist_del_rcu(&ap->hlist);
return 0;
}

static void __kprobes __unregister_kprobe_bottom(struct kprobe *p)
Expand Down Expand Up @@ -1606,29 +1638,13 @@ static void __kprobes kill_kprobe(struct kprobe *p)
int __kprobes disable_kprobe(struct kprobe *kp)
{
int ret = 0;
struct kprobe *p;

mutex_lock(&kprobe_mutex);

/* Check whether specified probe is valid. */
p = __get_valid_kprobe(kp);
if (unlikely(p == NULL)) {
/* Disable this kprobe */
if (__disable_kprobe(kp) == NULL)
ret = -EINVAL;
goto out;
}

/* If the probe is already disabled (or gone), just return */
if (kprobe_disabled(kp))
goto out;

kp->flags |= KPROBE_FLAG_DISABLED;
if (p != kp)
/* When kp != p, p is always enabled. */
try_to_disable_aggr_kprobe(p);

if (!kprobes_all_disarmed && kprobe_disabled(p))
disarm_kprobe(p);
out:
mutex_unlock(&kprobe_mutex);
return ret;
}
Expand Down

0 comments on commit 0b839d8

Please sign in to comment.