This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC][kprobes]Preempt enable kprobe-booster(Re: djprobes status)


Hi,

Here is the patch which enables kprobe-booster on
the preemptive kernel.

When we are unregistering a kprobe-booster, we can't release
its buffer immediately on the preemptive kernel, because
some processes might be preempted on the buffer.
The freeze_processes() and thaw_processes() functions can
clean those processes up from the buffer.
However, the processing of those functions takes long time.
So I introduced a kind of garbage collection(GC) routine into
insn_slots.
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.
Please review it.

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           |   63 ++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 57 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-25 21:46:22.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 void 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,12 @@
 		}
 	}

-	/* 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();
+		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 +132,29 @@
 	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 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();
+#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 +164,48 @@
 				 * 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;
+#if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
+	thaw_processes();
+#endif
+}
+
+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-25 21:44:35.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();


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]