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][PATCH 1/4][kprobe](djprobe) generalize the length of the instruction


Hi,

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

Thanks,

---
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-rc5-mm2/include/linux/kprobes.h
===================================================================
--- linux-2.6.19-rc5-mm2.orig/include/linux/kprobes.h
+++ linux-2.6.19-rc5-mm2/include/linux/kprobes.h
@@ -157,6 +157,12 @@ struct kretprobe_instance {
 	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-rc5-mm2/kernel/kprobes.c
===================================================================
--- linux-2.6.19-rc5-mm2.orig/kernel/kprobes.c
+++ linux-2.6.19-rc5-mm2/kernel/kprobes.c
@@ -77,19 +77,23 @@ static struct notifier_block kprobe_page
  * 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);

 static int __kprobes check_safety(void)
 {
@@ -116,37 +120,41 @@ loop_end:
 }

 /**
- * 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;
 	}
@@ -162,8 +170,8 @@ kprobe_opcode_t __kprobes *get_insn_slot
 		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;
@@ -171,7 +179,8 @@ kprobe_opcode_t __kprobes *get_insn_slot
 }

 /* 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--;
@@ -183,10 +192,10 @@ static int __kprobes collect_one_slot(st
 		 * 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);
 		} else {
 			module_free(NULL, kip->insns);
 			kfree(kip);
@@ -196,54 +205,68 @@ static int __kprobes collect_one_slot(st
 	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);

 	/* Ensure no-one is preepmted on the garbages */
 	if (check_safety() != 0)
 		return -EAGAIN;

-	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))
 				break;
 		}
 	}
-	kprobe_garbage_slots = 0;
+	plist->nr_garbage = 0;
 	return 0;
 }

-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]