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]

[PATCH 1/5][djprobe] generalize the length of the instruction slots.


Hi,

This patch generalizes get/free_insn_slot() to manage multiple length
instruction slots, because the djprobe needs longer instruction slots
than kprobes.

NOTE: This patch depends on my previous patch which enables
kprobe-booster on the preemptible kernel.
http://sources.redhat.com/ml/systemtap/2006-q4/msg00126.html

-- 
Masami HIRAMATSU
Linux Technology Center
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com

---
 include/linux/kprobes.h |    6 +++
 kernel/kprobes.c        |   85 ++++++++++++++++++++++++++++++------------------
 2 files changed, 60 insertions(+), 31 deletions(-)

Index: linux-2.6.19-rc1-mm1/include/linux/kprobes.h
===================================================================
--- linux-2.6.19-rc1-mm1.orig/include/linux/kprobes.h	2006-10-16 21:43:07.000000000 +0900
+++ linux-2.6.19-rc1-mm1/include/linux/kprobes.h	2006-10-16 22:10:18.000000000 +0900
@@ -157,6 +157,12 @@
 	struct task_struct *task;
 };

+struct kprobe_insn_page_list {
+	struct hlist_head list;
+	int insn_size;		/* size of an instruction slot */
+	int nr_garbage;
+};
+
 extern spinlock_t kretprobe_lock;
 extern struct mutex kprobe_mutex;
 extern int arch_prepare_kprobe(struct kprobe *p);
Index: linux-2.6.19-rc1-mm1/kernel/kprobes.c
===================================================================
--- linux-2.6.19-rc1-mm1.orig/kernel/kprobes.c	2006-10-16 21:50:44.000000000 +0900
+++ linux-2.6.19-rc1-mm1/kernel/kprobes.c	2006-10-16 22:10:39.000000000 +0900
@@ -77,52 +77,60 @@
  * stepping on the instruction on a vmalloced/kmalloced/data page
  * is a recipe for disaster
  */
-#define INSNS_PER_PAGE	(PAGE_SIZE/(MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
+#define INSNS_PER_PAGE(size)	(PAGE_SIZE/(size * sizeof(kprobe_opcode_t)))

 struct kprobe_insn_page {
 	struct hlist_node hlist;
 	kprobe_opcode_t *insns;		/* Page of instruction slots */
-	char slot_used[INSNS_PER_PAGE];
 	int nused;
 	int ngarbage;
+	char slot_used[1];
 };

-static struct hlist_head kprobe_insn_pages;
-static int kprobe_garbage_slots;
-static int collect_garbage_slots(void);
+static struct kprobe_insn_page_list kprobe_insn_pages = {
+	.list = HLIST_HEAD_INIT,
+	.insn_size = MAX_INSN_SIZE,
+	.nr_garbage = 0,
+};
+
+static int collect_garbage_slots(struct kprobe_insn_page_list *plist);

 /**
- * get_insn_slot() - Find a slot on an executable page for an instruction.
+ * __get_insn_slot() - Find a slot on an executable page for an instruction.
  * We allocate an executable page if there's no room on existing ones.
  */
-kprobe_opcode_t __kprobes *get_insn_slot(void)
+kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_page_list *plist)
 {
 	struct kprobe_insn_page *kip;
 	struct hlist_node *pos;
+	int max_insn = INSNS_PER_PAGE(plist->insn_size);

       retry:
-	hlist_for_each(pos, &kprobe_insn_pages) {
+	hlist_for_each(pos, &plist->list) {
 		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
-		if (kip->nused < INSNS_PER_PAGE) {
+		if (kip->nused < max_insn) {
 			int i;
-			for (i = 0; i < INSNS_PER_PAGE; i++) {
+			for (i = 0; i < max_insn; i++) {
 				if (!kip->slot_used[i]) {
 					kip->slot_used[i] = 1;
 					kip->nused++;
-					return kip->insns + (i * MAX_INSN_SIZE);
+					return kip->insns +
+						(i * plist->insn_size);
 				}
 			}
 			/* Surprise!  No unused slots.  Fix kip->nused. */
-			kip->nused = INSNS_PER_PAGE;
+			kip->nused = max_insn;
 		}
 	}

 	/* If there are any garbage slots, collect it and try again. */
-	if (kprobe_garbage_slots && collect_garbage_slots() == 0) {
+	if (plist->nr_garbage > 0 && collect_garbage_slots(plist) == 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);
+	kip = kmalloc(sizeof(struct kprobe_insn_page) +
+		      sizeof(char) * (max_insn - 1),
+		      GFP_KERNEL);
 	if (!kip) {
 		return NULL;
 	}
@@ -138,8 +146,8 @@
 		return NULL;
 	}
 	INIT_HLIST_NODE(&kip->hlist);
-	hlist_add_head(&kip->hlist, &kprobe_insn_pages);
-	memset(kip->slot_used, 0, INSNS_PER_PAGE);
+	hlist_add_head(&kip->hlist, &plist->list);
+	memset(kip->slot_used, 0, max_insn);
 	kip->slot_used[0] = 1;
 	kip->nused = 1;
 	kip->ngarbage = 0;
@@ -147,7 +155,8 @@
 }

 /* Return 1 if all garbages are collected, otherwise 0. */
-static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx)
+static int __kprobes collect_one_slot(struct kprobe_insn_page_list *plist,
+				      struct kprobe_insn_page *kip, int idx)
 {
 	kip->slot_used[idx] = 0;
 	kip->nused--;
@@ -159,10 +168,10 @@
 		 * next time somebody inserts a probe.
 		 */
 		hlist_del(&kip->hlist);
-		if (hlist_empty(&kprobe_insn_pages)) {
+		if (hlist_empty(&plist->list)) {
 			INIT_HLIST_NODE(&kip->hlist);
 			hlist_add_head(&kip->hlist,
-				       &kprobe_insn_pages);
+				       &plist->list);
 			return 1;
 		} else {
 			module_free(NULL, kip->insns);
@@ -172,10 +181,12 @@
 	return 0;
 }

-static int __kprobes collect_garbage_slots(void)
+static int __kprobes
+	collect_garbage_slots(struct kprobe_insn_page_list *plist)
 {
 	struct kprobe_insn_page *kip;
 	struct hlist_node *pos, *next;
+	int max_insn = INSNS_PER_PAGE(plist->insn_size);
 	int ret = -1;

 #if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
@@ -183,20 +194,20 @@
 	if (freeze_processes() != 0)
 		goto thaw_all;
 #endif
-	hlist_for_each_safe(pos, next, &kprobe_insn_pages) {
+	hlist_for_each_safe(pos, next, &plist->list) {
 		int i;
 		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
 		if (kip->ngarbage == 0)
 			continue;
 		kip->ngarbage = 0;	/* we will collect all garbages */
-		for (i = 0; i < INSNS_PER_PAGE; i++) {
+		for (i = 0; i < max_insn; i++) {
 			if (kip->slot_used[i] == -1 &&
-			    collect_one_slot(kip, i))
+			    collect_one_slot(plist, kip, i))
 				goto collected;
 		}
 	}
       collected:
-	kprobe_garbage_slots = 0;
+	plist->nr_garbage = 0;
 	ret = 0;
 #if defined(CONFIG_PREEMPT) && defined(CONFIG_PM)
       thaw_all:
@@ -205,29 +216,41 @@
 	return ret;
 }

-void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty)
+void __kprobes __free_insn_slot(struct kprobe_insn_page_list *plist,
+				kprobe_opcode_t * slot, int dirty)
 {
 	struct kprobe_insn_page *kip;
 	struct hlist_node *pos;
+	int max_insn = INSNS_PER_PAGE(plist->insn_size);

-	hlist_for_each(pos, &kprobe_insn_pages) {
+	hlist_for_each(pos, &plist->list) {
 		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;
+		    slot < kip->insns + (max_insn * plist->insn_size)) {
+			int i = (slot - kip->insns) / plist->insn_size;
 			if (dirty) {
 				kip->slot_used[i] = -1;
 				kip->ngarbage++;
 			} else {
-				collect_one_slot(kip, i);
+				collect_one_slot(plist, kip, i);
 				break;
 			}
 		}
 	}
-	if (dirty && (++kprobe_garbage_slots > INSNS_PER_PAGE)) {
-		collect_garbage_slots();
+	if (dirty && (++plist->nr_garbage > max_insn)) {
+		collect_garbage_slots(plist);
 	}
 }
+
+kprobe_opcode_t __kprobes *get_insn_slot(void)
+{
+	return __get_insn_slot(&kprobe_insn_pages);
+}
+
+void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty)
+{
+	__free_insn_slot(&kprobe_insn_pages, slot, dirty);
+}
 #endif

 /* We have preemption disabled.. so it is safe to use __ versions */






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