public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
From: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
To: "Keshavamurthy, Anil S" <anil.s.keshavamurthy@intel.com>,
		Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
		Prasanna S Panchamukhi <prasanna@in.ibm.com>,
		Ingo Molnar <mingo@redhat.com>
Cc: SystemTAP <systemtap@sources.redhat.com>,
		Satoshi Oshima <soshima@redhat.com>,
	Hideo Aoki <haoki@redhat.com>,
		Yumiko Sugita <yumiko.sugita.yf@hitachi.com>
Subject: [RFC][PATCH][kprobe] enabling booster on the preemptible kernel,  take 2
Date: Mon, 16 Oct 2006 13:14:00 -0000	[thread overview]
Message-ID: <45338593.6090207@hitachi.com> (raw)

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 a long time.
So, this patch introduces the garbage collection mechanism
of insn_slot. It also introduces the "dirty" flag to
free_insn_slot because of efficiency.

The "clean" instruction slots (dirty flag is cleared) are
released immediately. But the "dirty" slots which are used
by boosted kprobes, are marked as garbages.
collect_garbage_slots() will be invoked to release "dirty"
slots if 1) there are more than INSNS_PER_PAGE garbage slots
or 2) there are no unused slots.

Thanks,
-- 
Masami HIRAMATSU
2nd Research Dept.
Hitachi, Ltd., Systems Development Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com


---
 arch/i386/kernel/kprobes.c    |    4 -
 arch/ia64/kernel/kprobes.c    |    2
 arch/powerpc/kernel/kprobes.c |    2
 arch/s390/kernel/kprobes.c    |    2
 arch/x86_64/kernel/kprobes.c  |    2
 include/linux/kprobes.h       |    2
 kernel/kprobes.c              |  101 +++++++++++++++++++++++++++++++++---------
 7 files changed, 87 insertions(+), 28 deletions(-)

Index: linux-2.6.19-rc1-mm1/kernel/kprobes.c
===================================================================
--- linux-2.6.19-rc1-mm1.orig/kernel/kprobes.c	2006-10-16 10:40:02.000000000 +0900
+++ linux-2.6.19-rc1-mm1/kernel/kprobes.c	2006-10-16 21:50:44.000000000 +0900
@@ -38,6 +38,7 @@
 #include <linux/module.h>
 #include <linux/moduleloader.h>
 #include <linux/kallsyms.h>
+#include <linux/sched.h>
 #include <asm-generic/sections.h>
 #include <asm/cacheflush.h>
 #include <asm/errno.h>
@@ -83,9 +84,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.
@@ -96,6 +100,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) {
@@ -112,7 +117,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;
@@ -133,10 +142,70 @@
 	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)
+/* Return 1 if all garbages are collected, otherwise 0. */
+static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx)
+{
+	kip->slot_used[idx] = 0;
+	kip->nused--;
+	if (kip->nused == 0) {
+		/*
+		 * Page is no longer in use.  Free it unless
+		 * it's the last one.  We keep the last one
+		 * so as not to have to set it up again the
+		 * next time somebody inserts a probe.
+		 */
+		hlist_del(&kip->hlist);
+		if (hlist_empty(&kprobe_insn_pages)) {
+			INIT_HLIST_NODE(&kip->hlist);
+			hlist_add_head(&kip->hlist,
+				       &kprobe_insn_pages);
+			return 1;
+		} else {
+			module_free(NULL, kip->insns);
+			kfree(kip);
+		}
+	}
+	return 0;
+}
+
+static int __kprobes collect_garbage_slots(void)
+{
+	struct kprobe_insn_page *kip;
+	struct hlist_node *pos, *next;
+	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_safe(pos, next, &kprobe_insn_pages) {
+		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++) {
+			if (kip->slot_used[i] == -1 &&
+			    collect_one_slot(kip, i))
+				goto collected;
+		}
+	}
+      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, int dirty)
 {
 	struct kprobe_insn_page *kip;
 	struct hlist_node *pos;
@@ -146,28 +215,18 @@
 		if (kip->insns <= slot &&
 		    slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
 			int i = (slot - kip->insns) / MAX_INSN_SIZE;
-			kip->slot_used[i] = 0;
-			kip->nused--;
-			if (kip->nused == 0) {
-				/*
-				 * Page is no longer in use.  Free it unless
-				 * it's the last one.  We keep the last one
-				 * so as not to have to set it up again the
-				 * next time somebody inserts a probe.
-				 */
-				hlist_del(&kip->hlist);
-				if (hlist_empty(&kprobe_insn_pages)) {
-					INIT_HLIST_NODE(&kip->hlist);
-					hlist_add_head(&kip->hlist,
-						&kprobe_insn_pages);
-				} else {
-					module_free(NULL, kip->insns);
-					kfree(kip);
-				}
+			if (dirty) {
+				kip->slot_used[i] = -1;
+				kip->ngarbage++;
+			} else {
+				collect_one_slot(kip, i);
+				break;
 			}
-			return;
 		}
 	}
+	if (dirty && (++kprobe_garbage_slots > INSNS_PER_PAGE)) {
+		collect_garbage_slots();
+	}
 }
 #endif

Index: linux-2.6.19-rc1-mm1/arch/i386/kernel/kprobes.c
===================================================================
--- linux-2.6.19-rc1-mm1.orig/arch/i386/kernel/kprobes.c	2006-10-16 10:40:00.000000000 +0900
+++ linux-2.6.19-rc1-mm1/arch/i386/kernel/kprobes.c	2006-10-16 21:43:03.000000000 +0900
@@ -184,7 +184,7 @@
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
 	mutex_lock(&kprobe_mutex);
-	free_insn_slot(p->ainsn.insn);
+	free_insn_slot(p->ainsn.insn, (p->ainsn.boostable == 1));
 	mutex_unlock(&kprobe_mutex);
 }

@@ -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: linux-2.6.19-rc1-mm1/arch/ia64/kernel/kprobes.c
===================================================================
--- linux-2.6.19-rc1-mm1.orig/arch/ia64/kernel/kprobes.c	2006-10-16 10:40:00.000000000 +0900
+++ linux-2.6.19-rc1-mm1/arch/ia64/kernel/kprobes.c	2006-10-16 10:54:09.000000000 +0900
@@ -481,7 +481,7 @@
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
 	mutex_lock(&kprobe_mutex);
-	free_insn_slot(p->ainsn.insn);
+	free_insn_slot(p->ainsn.insn, 0);
 	mutex_unlock(&kprobe_mutex);
 }
 /*
Index: linux-2.6.19-rc1-mm1/arch/powerpc/kernel/kprobes.c
===================================================================
--- linux-2.6.19-rc1-mm1.orig/arch/powerpc/kernel/kprobes.c	2006-10-16 10:40:00.000000000 +0900
+++ linux-2.6.19-rc1-mm1/arch/powerpc/kernel/kprobes.c	2006-10-16 10:54:09.000000000 +0900
@@ -85,7 +85,7 @@
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
 	mutex_lock(&kprobe_mutex);
-	free_insn_slot(p->ainsn.insn);
+	free_insn_slot(p->ainsn.insn, 0);
 	mutex_unlock(&kprobe_mutex);
 }

Index: linux-2.6.19-rc1-mm1/arch/s390/kernel/kprobes.c
===================================================================
--- linux-2.6.19-rc1-mm1.orig/arch/s390/kernel/kprobes.c	2006-10-16 10:40:00.000000000 +0900
+++ linux-2.6.19-rc1-mm1/arch/s390/kernel/kprobes.c	2006-10-16 10:54:09.000000000 +0900
@@ -200,7 +200,7 @@
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
 	mutex_lock(&kprobe_mutex);
-	free_insn_slot(p->ainsn.insn);
+	free_insn_slot(p->ainsn.insn, 0);
 	mutex_unlock(&kprobe_mutex);
 }

Index: linux-2.6.19-rc1-mm1/arch/x86_64/kernel/kprobes.c
===================================================================
--- linux-2.6.19-rc1-mm1.orig/arch/x86_64/kernel/kprobes.c	2006-10-16 10:40:00.000000000 +0900
+++ linux-2.6.19-rc1-mm1/arch/x86_64/kernel/kprobes.c	2006-10-16 10:54:09.000000000 +0900
@@ -224,7 +224,7 @@
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
 	mutex_lock(&kprobe_mutex);
-	free_insn_slot(p->ainsn.insn);
+	free_insn_slot(p->ainsn.insn, 0);
 	mutex_unlock(&kprobe_mutex);
 }

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 10:40:02.000000000 +0900
+++ linux-2.6.19-rc1-mm1/include/linux/kprobes.h	2006-10-16 21:43:07.000000000 +0900
@@ -165,7 +165,7 @@
 extern int arch_init_kprobes(void);
 extern void show_registers(struct pt_regs *regs);
 extern kprobe_opcode_t *get_insn_slot(void);
-extern void free_insn_slot(kprobe_opcode_t *slot);
+extern void free_insn_slot(kprobe_opcode_t *slot, int dirty);
 extern void kprobes_inc_nmissed_count(struct kprobe *p);

 /* Get the kprobe at this addr (if any) - called with preemption disabled */


             reply	other threads:[~2006-10-16 13:14 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-10-16 13:14 Masami Hiramatsu [this message]
2006-10-19  9:00 ` [PATCH 1/5][djprobe] generalize the length of the instruction slots Masami Hiramatsu
2006-10-19  9:03 ` [PATCH 2/5][djprobe] djprobe core patch Masami Hiramatsu
2006-10-27 23:34   ` Keshavamurthy, Anil S
2006-10-30 14:07     ` Masami Hiramatsu
2006-10-30 14:11       ` Ingo Molnar
2006-10-19  9:03 ` [PATCH 4/5][djprobe] djprobe for i386 architecture code Masami Hiramatsu
2006-10-19  9:03 ` [PATCH 3/5][djprobe] export set_jmp_op() for sharing Masami Hiramatsu
2006-10-19  9:04 ` [PATCH 5/5][djprobe] delayed invoking commit_djprobes() Masami Hiramatsu
2006-10-19  9:04 ` [RFC][djprobe] djprobe examples Masami Hiramatsu
2006-10-30  6:37 ` [RFC][PATCH][kprobe] enabling booster on the preemptible kernel, take 2 bibo,mao
2006-10-30 14:07   ` Masami Hiramatsu
2006-10-31  9:14     ` bibo,mao
2006-10-31 13:47       ` Masami Hiramatsu
2006-10-31 13:49         ` Ingo Molnar
2006-10-31 14:13         ` Ingo Molnar
2006-10-31 16:39           ` Masami Hiramatsu
2006-11-01 17:01 bibo mao
2006-11-02 18:51 ` Masami Hiramatsu
2006-11-03  9:16   ` bibo,mao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=45338593.6090207@hitachi.com \
    --to=masami.hiramatsu.pt@hitachi.com \
    --cc=ananth@in.ibm.com \
    --cc=anil.s.keshavamurthy@intel.com \
    --cc=haoki@redhat.com \
    --cc=mingo@redhat.com \
    --cc=prasanna@in.ibm.com \
    --cc=soshima@redhat.com \
    --cc=systemtap@sources.redhat.com \
    --cc=yumiko.sugita.yf@hitachi.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).