This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
Re: [RFC][kprobes]Preempt enable kprobe-booster(Re: djprobes status)
Hi Anil,
Thank you for the advice.
Keshavamurthy Anil S wrote:
> On Mon, Sep 25, 2006 at 06:03:06AM -0700, Masami Hiramatsu wrote:
> Masami,
> Overall the code looks good and I just have a very
> minor comments.
>
>> Currently, this GC is invoked if 1) there are more than
>> INSNS_PER_PAGE garbage slots or 2) there are no unused slots.
>> Would you have any better idea about these timings? I'd like to
>> receive feedbacks.
> Invoking GC looks good to me.
Thanks.
>> -void __kprobes free_insn_slot(kprobe_opcode_t *slot)
>> +static void collect_garbage_slots(void)
>> {
>> struct kprobe_insn_page *kip;
>> struct hlist_node *pos;
>> +#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
>> + /* Ensure no-one is preepmted on the garbages */
>> + freeze_processes();
> I think you need to check for freeze_processes() return value.
> If the return value indicates failure, then you must NOT
> continue collecting garbage slots, instead call
> thaw_processes() and return.
OK, I'll check its return value.
>> +#endif
>
> [.....]
>
>> Index: linux-2.6.18/arch/i386/kernel/kprobes.c
>> ===================================================================
>> --- linux-2.6.18.orig/arch/i386/kernel/kprobes.c 2006-09-25
>> 21:44:22.000000000 +0900
>> +++ linux-2.6.18/arch/i386/kernel/kprobes.c 2006-09-25
>> 21:44:35.000000000 +0900
>> @@ -333,7 +333,7 @@
>> return 1;
>> ss_probe:
>> -#ifndef CONFIG_PREEMPT
>> +#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
>
> Now you are supporting booster probes independent of CONFIG_PREEMPT (i.e
> you are supporting booster probes for CONFIG_PREEMPT defined and for NOT defined cases),
> so just defined(CONFIG_PM) should be fine I think.
There is another case; Both of CONFIG_PREEMPT and CONFIG_PM are NOT
defined. In this case, the kprobe-booster should be enabled. But
if we check only CONFIG_PM, we can not enable that in this case.
Thanks,
--
Masami HIRAMATSU
2nd Research Dept.
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com
---
arch/i386/kernel/kprobes.c | 2 -
kernel/kprobes.c | 67 ++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 61 insertions(+), 8 deletions(-)
Index: linux-2.6.18/kernel/kprobes.c
===================================================================
--- linux-2.6.18.orig/kernel/kprobes.c 2006-09-25 21:44:22.000000000 +0900
+++ linux-2.6.18/kernel/kprobes.c 2006-09-26 17:59:04.000000000 +0900
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleloader.h>
+#include <linux/sched.h>
#include <asm-generic/sections.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
@@ -72,9 +73,12 @@
kprobe_opcode_t *insns; /* Page of instruction slots */
char slot_used[INSNS_PER_PAGE];
int nused;
+ int ngarbage;
};
static struct hlist_head kprobe_insn_pages;
+static int kprobe_garbage_slots;
+static int collect_garbage_slots(void);
/**
* get_insn_slot() - Find a slot on an executable page for an instruction.
@@ -85,6 +89,7 @@
struct kprobe_insn_page *kip;
struct hlist_node *pos;
+ retry:
hlist_for_each(pos, &kprobe_insn_pages) {
kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
if (kip->nused < INSNS_PER_PAGE) {
@@ -101,7 +106,11 @@
}
}
- /* All out of space. Need to allocate a new page. Use slot 0.*/
+ /* If there are any garbage slots, collect it and try again. */
+ if (kprobe_garbage_slots && collect_garbage_slots() == 0) {
+ goto retry;
+ }
+ /* All out of space. Need to allocate a new page. Use slot 0. */
kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
if (!kip) {
return NULL;
@@ -122,19 +131,31 @@
memset(kip->slot_used, 0, INSNS_PER_PAGE);
kip->slot_used[0] = 1;
kip->nused = 1;
+ kip->ngarbage = 0;
return kip->insns;
}
-void __kprobes free_insn_slot(kprobe_opcode_t *slot)
+static int collect_garbage_slots(void)
{
struct kprobe_insn_page *kip;
struct hlist_node *pos;
+ int ret = -1;
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+ /* Ensure no-one is preepmted on the garbages */
+ if (freeze_processes() != 0)
+ goto thaw_all;
+#endif
hlist_for_each(pos, &kprobe_insn_pages) {
+ int i;
+ next:
kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
- if (kip->insns <= slot &&
- slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
- int i = (slot - kip->insns) / MAX_INSN_SIZE;
+ if (kip->ngarbage == 0)
+ continue;
+ kip->ngarbage = 0; /* we will collect all garbages */
+ for (i = 0; i < INSNS_PER_PAGE; i++) {
+ if (kip->slot_used[i] != -1)
+ continue;
kip->slot_used[i] = 0;
kip->nused--;
if (kip->nused == 0) {
@@ -144,19 +165,51 @@
* so as not to have to set it up again the
* next time somebody inserts a probe.
*/
+ pos = pos->next;
hlist_del(&kip->hlist);
if (hlist_empty(&kprobe_insn_pages)) {
INIT_HLIST_NODE(&kip->hlist);
hlist_add_head(&kip->hlist,
- &kprobe_insn_pages);
+ &kprobe_insn_pages);
} else {
module_free(NULL, kip->insns);
kfree(kip);
}
+ if (pos == NULL)
+ goto collected;
+ else
+ goto next;
}
- return;
}
}
+ collected:
+ kprobe_garbage_slots = 0;
+ ret = 0;
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+ thaw_all:
+ thaw_processes();
+#endif
+ return ret;
+}
+
+void __kprobes free_insn_slot(kprobe_opcode_t * slot)
+{
+ struct kprobe_insn_page *kip;
+ struct hlist_node *pos;
+
+ hlist_for_each(pos, &kprobe_insn_pages) {
+ kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+ if (kip->insns <= slot &&
+ slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
+ kip->slot_used[(slot - kip->insns) / MAX_INSN_SIZE] =
+ -1;
+ kip->ngarbage++;
+ break;
+ }
+ }
+ if (++kprobe_garbage_slots > INSNS_PER_PAGE) {
+ collect_garbage_slots();
+ }
}
#endif
Index: linux-2.6.18/arch/i386/kernel/kprobes.c
===================================================================
--- linux-2.6.18.orig/arch/i386/kernel/kprobes.c 2006-09-25 21:44:22.000000000 +0900
+++ linux-2.6.18/arch/i386/kernel/kprobes.c 2006-09-26 16:39:15.000000000 +0900
@@ -333,7 +333,7 @@
return 1;
ss_probe:
-#ifndef CONFIG_PREEMPT
+#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PM)
if (p->ainsn.boostable == 1 && !p->post_handler){
/* Boost up -- we can execute copied instructions directly */
reset_current_kprobe();