LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 00/05] Linux Kernel Markers
@ 2007-01-12  0:02 Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 01/05] Linux Kernel Markers : Kconfig menus Mathieu Desnoyers
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12  0:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Greg Kroah-Hartman,
	Christoph Hellwig, ltt-dev, systemtap, Douglas Niehaus,
	Thomas Gleixner

Hi,

You will find, in the following posts, the latest revision of the Linux Kernel
Markers. Due to the need some tracing projects (LTTng, SystemTAP) has of this
kind of mechanism, it could be nice to consider it for mainstream inclusion.

The following patches apply on 2.6.20-rc4-git3.

Signed-off-by : Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 01/05] Linux Kernel Markers : Kconfig menus
  2007-01-12  0:02 [PATCH 00/05] Linux Kernel Markers Mathieu Desnoyers
@ 2007-01-12  0:02 ` Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 02/05] Linux Kernel Markers, architecture independant code Mathieu Desnoyers
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12  0:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Greg Kroah-Hartman,
	Christoph Hellwig, ltt-dev, systemtap, Douglas Niehaus,
	Thomas Gleixner, Mathieu Desnoyers

Linux Kernel Markers : Kconfig menus

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

--- /dev/null
+++ b/kernel/Kconfig.marker
@@ -0,0 +1,17 @@
+# Code markers configuration
+
+config MARKERS
+	bool "Activate markers"
+	select MODULES
+	default n
+	help
+	  Place an empty function call at each marker site. Can be
+	  dynamically changed for a probe function.
+
+config MARKERS_DISABLE_OPTIMIZATION
+	bool "Disable architecture specific marker optimization"
+	depends EMBEDDED
+	default n
+	help
+	  Disable code replacement jump optimisations. Especially useful if your
+	  code is in a read-only rom/flash.
--- a/Makefile
+++ b/Makefile
@@ -308,7 +308,8 @@ AFLAGS_KERNEL	=
 # Needed to be compatible with the O= option
 LINUXINCLUDE    := -Iinclude \
                    $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) \
-		   -include include/linux/autoconf.h
+		   -include include/linux/autoconf.h \
+		   -include linux/marker.h
 
 CPPFLAGS        := -D__KERNEL__ $(LINUXINCLUDE)
 
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -638,6 +638,12 @@ source "fs/Kconfig"
 
 source "arch/alpha/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/alpha/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -191,6 +191,12 @@ source "sound/Kconfig"
 
 source "drivers/usb/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/cris/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -375,6 +375,12 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/frv/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -205,6 +205,12 @@ endmenu
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/h8300/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -1210,6 +1210,9 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
 endmenu
 
 source "arch/i386/Kconfig.debug"
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -564,6 +564,9 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
 endmenu
 
 source "arch/ia64/Kconfig.debug"
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -394,6 +394,12 @@ source "fs/Kconfig"
 
 source "arch/m32r/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/m32r/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -660,6 +660,12 @@ endmenu
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/m68k/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -669,6 +669,12 @@ source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/m68knommu/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -1443,8 +1443,18 @@ source "lib/Kconfig"
 
 source "arch/powerpc/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/ppc/Kconfig.debug"
 
 source "security/Kconfig"
 
 source "crypto/Kconfig"
+
+menu "Instrumentation Support"
+
+endmenu
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -1185,6 +1185,9 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
 endmenu
 
 source "arch/powerpc/Kconfig.debug"
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -263,6 +263,12 @@ source "fs/Kconfig"
 
 source "arch/parisc/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/parisc/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -968,6 +968,12 @@ source "fs/Kconfig"
 
 source "arch/arm/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/arm/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -240,6 +240,12 @@ source "drivers/misc/Kconfig"
 
 source "drivers/usb/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/arm26/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -2068,6 +2068,12 @@ source "fs/Kconfig"
 
 source "arch/mips/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/mips/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -518,6 +518,8 @@ config KPROBES
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
 
+source "kernel/Kconfig.marker"
+
 endmenu
 
 source "arch/s390/Kconfig.debug"
--- a/arch/sh64/Kconfig
+++ b/arch/sh64/Kconfig
@@ -284,6 +284,12 @@ source "fs/Kconfig"
 
 source "arch/sh64/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/sh64/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -707,6 +707,12 @@ source "fs/Kconfig"
 
 source "arch/sh/oprofile/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/sh/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -443,6 +443,9 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
 endmenu
 
 source "arch/sparc64/Kconfig.debug"
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -302,6 +302,8 @@ menu "Instrumentation Support"
 
 source "arch/sparc/oprofile/Kconfig"
 
+source "kernel/Kconfig.marker"
+
 endmenu
 
 source "arch/sparc/Kconfig.debug"
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -344,4 +344,10 @@ config INPUT
 	bool
 	default n
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/um/Kconfig.debug"
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -332,6 +332,12 @@ source "sound/Kconfig"
 
 source "drivers/usb/Kconfig"
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/v850/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -244,6 +244,12 @@ config EMBEDDED_RAMDISK_IMAGE
 	  provide one yourself.
 endmenu
 
+menu "Instrumentation Support"
+
+source "kernel/Kconfig.marker"
+
+endmenu
+
 source "arch/xtensa/Kconfig.debug"
 
 source "security/Kconfig"
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -731,6 +731,9 @@ config KPROBES
 	  a probepoint and specifies the callback.  Kprobes is useful
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
+
+source "kernel/Kconfig.marker"
+
 endmenu
 
 source "arch/x86_64/Kconfig.debug"

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 02/05] Linux Kernel Markers, architecture independant code.
  2007-01-12  0:02 [PATCH 00/05] Linux Kernel Markers Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 01/05] Linux Kernel Markers : Kconfig menus Mathieu Desnoyers
@ 2007-01-12  0:02 ` Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 03/05] Linux Kernel Markers : powerpc optimisation Mathieu Desnoyers
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12  0:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Greg Kroah-Hartman,
	Christoph Hellwig, ltt-dev, systemtap, Douglas Niehaus,
	Thomas Gleixner, Mathieu Desnoyers

Linux Kernel Markers, architecture independant code.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -121,6 +121,14 @@
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\
 	}								\
+	/* Kernel markers : pointers */					\
+	.markers : AT(ADDR(.markers) - LOAD_OFFSET) {			\
+		VMLINUX_SYMBOL(__start___markers) = .;			\
+		*(.markers)						\
+		VMLINUX_SYMBOL(__stop___markers) = .;			\
+	}								\
+	__end_rodata = .;						\
+	. = ALIGN(4096);						\
 									\
 	/* Built-in module parameters. */				\
 	__param : AT(ADDR(__param) - LOAD_OFFSET) {			\
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -356,6 +356,9 @@ struct module
 	/* The command line arguments (may be mangled).  People like
 	   keeping pointers to this stuff */
 	char *args;
+
+	const struct __mark_marker *markers;
+	unsigned int num_markers;
 };
 
 /* FIXME: It'd be nice to isolate modules during init, too, so they
@@ -469,6 +472,7 @@ extern void print_modules(void);
 struct device_driver;
 void module_add_driver(struct module *, struct device_driver *);
 void module_remove_driver(struct device_driver *);
+extern void list_modules(void);
 
 #else /* !CONFIG_MODULES... */
 #define EXPORT_SYMBOL(sym)
--- /dev/null
+++ b/include/linux/marker.h
@@ -0,0 +1,67 @@
+#ifndef _LINUX_MARKER_H
+#define _LINUX_MARKER_H
+
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing.
+ *
+ * Example :
+ *
+ * MARK(subsystem_event, "%d %s %p[struct task_struct *]",
+ *   someint, somestring, current);
+ * Where :
+ * - Subsystem is the name of your subsystem.
+ * - event is the name of the event to mark.
+ * - "%d %s %p[struct task_struct *]" is the formatted string for printk.
+ * - someint is an integer.
+ * - somestring is a char pointer.
+ * - current is a pointer to a struct task_struct.
+ *
+ * - Dynamically overridable function call based on marker mechanism
+ *   from Frank Ch. Eigler <fche@redhat.com>.
+ * - Thanks to Jeremy Fitzhardinge <jeremy@goop.org> for his constructive
+ *   criticism about gcc optimization related issues.
+ *
+ * The marker mechanism supports multiple instances of the same marker.
+ * Markers can be put in inline functions, inlined static functions and
+ * unrolled loops.
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#ifndef __ASSEMBLY__
+
+typedef void marker_probe_func(const char *fmt, ...);
+
+#ifndef CONFIG_MARKERS_DISABLE_OPTIMIZATION
+#include <asm/marker.h>
+#else
+#include <asm-generic/marker.h>
+#endif
+
+#define MARK_NOARGS " "
+#define MARK_MAX_FORMAT_LEN	1024
+
+#ifndef CONFIG_MARKERS
+#define MARK(name, format, args...) \
+		__mark_check_format(format, ## args)
+#endif
+
+static inline __attribute__ ((format (printf, 1, 2)))
+void __mark_check_format(const char *fmt, ...)
+{ }
+
+extern marker_probe_func __mark_empty_function;
+
+extern int marker_set_probe(const char *name, const char *format,
+				marker_probe_func *probe);
+
+extern int marker_remove_probe(marker_probe_func *probe);
+extern int marker_list_probe(marker_probe_func *probe);
+
+#endif
+#endif
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -138,6 +138,8 @@ extern const unsigned long __start___kcrctab_gpl[];
 extern const unsigned long __start___kcrctab_gpl_future[];
 extern const unsigned long __start___kcrctab_unused[];
 extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const struct __mark_marker __start___markers[];
+extern const struct __mark_marker __stop___markers[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -298,6 +300,189 @@ static struct module *find_module(const char *name)
 	return NULL;
 }
 
+#ifdef CONFIG_MARKERS
+void __mark_empty_function(const char *fmt, ...)
+{
+}
+EXPORT_SYMBOL(__mark_empty_function);
+
+#define MARK_ENABLE_OFFSET(a) \
+	(typeof(a))((char*)a+MARK_ENABLE_IMMEDIATE_OFFSET)
+
+static int marker_set_probe_range(const char *name, 
+	const char *format,
+	marker_probe_func *probe,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (strcmp(name, iter->cmark->name) == 0) {
+			if (format
+				&& strcmp(format, iter->cmark->format) != 0) {
+				printk(KERN_NOTICE
+					"Format mismatch for probe %s "
+					"(%s), marker (%s)\n",
+					name,
+					format,
+					iter->cmark->format);
+				continue;
+			}
+			if (probe == __mark_empty_function) {
+				if (*iter->cmark->call
+					!= __mark_empty_function) {
+					*iter->cmark->call =
+						__mark_empty_function;
+				}
+				/* Can have many enables for one function */
+				*MARK_ENABLE_OFFSET(iter->enable) = 0;
+#ifdef MARK_POLYMORPHIC
+				flush_icache_range(
+					MARK_ENABLE_OFFSET(iter->enable),
+					sizeof(*(iter->enable)));
+#endif
+			} else {
+				if (*iter->cmark->call
+					!= __mark_empty_function) {
+					if (*iter->cmark->call != probe) {
+						printk(KERN_NOTICE
+							"Marker %s busy, "
+							"probe %p already "
+							"installed\n",
+							name,
+							*iter->cmark->call);
+						continue;
+					}
+				} else {
+					found++;
+					*iter->cmark->call = probe;
+				}
+				/* Can have many enables for one function */
+				*MARK_ENABLE_OFFSET(iter->enable) = 1;
+#ifdef MARK_POLYMORPHIC
+				flush_icache_range(
+					MARK_ENABLE_OFFSET(iter->enable),
+					sizeof(*(iter->enable)));
+#endif
+			}
+			found++;
+		}
+	}
+	return found;
+}
+
+static int marker_remove_probe_range(marker_probe_func *probe,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (*iter->cmark->call == probe) {
+			*MARK_ENABLE_OFFSET(iter->enable) = 0;
+#ifdef MARK_POLYMORPHIC
+				flush_icache_range(
+					MARK_ENABLE_OFFSET(iter->enable),
+					sizeof(*(iter->enable)));
+#endif
+			*iter->cmark->call = __mark_empty_function;
+			found++;
+		}
+	}
+	return found;
+}
+
+static int marker_list_probe_range(marker_probe_func *probe,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (probe)
+			if (probe != *iter->cmark->call) continue;
+		printk("name %s \n", iter->cmark->name);
+		printk("  enable %u ", *MARK_ENABLE_OFFSET(iter->enable));
+		printk("  func 0x%p format \"%s\"\n",
+			*iter->cmark->call, iter->cmark->format);
+		found++;
+	}
+	return found;
+}
+/* markers use the modlist_lock to to synchronise */
+int marker_set_probe(const char *name, const char *format,
+				marker_probe_func *probe)
+{
+	struct module *mod;
+	int found = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&modlist_lock, flags);
+	/* Core kernel markers */
+	found += marker_set_probe_range(name, format, probe,
+			__start___markers, __stop___markers);
+	/* Markers in modules. */ 
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints)
+			found += marker_set_probe_range(name, format, probe,
+				mod->markers, mod->markers+mod->num_markers);
+	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return found;
+}
+EXPORT_SYMBOL(marker_set_probe);
+
+int marker_remove_probe(marker_probe_func *probe)
+{
+	struct module *mod;
+	int found = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&modlist_lock, flags);
+	/* Core kernel markers */
+	found += marker_remove_probe_range(probe,
+			__start___markers, __stop___markers);
+	/* Markers in modules. */ 
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints)
+			found += marker_remove_probe_range(probe,
+				mod->markers, mod->markers+mod->num_markers);
+	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return found;
+}
+EXPORT_SYMBOL(marker_remove_probe);
+
+int marker_list_probe(marker_probe_func *probe)
+{
+	struct module *mod;
+	int found = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&modlist_lock, flags);
+	/* Core kernel markers */
+	printk("Listing kernel markers\n");
+	found += marker_list_probe_range(probe,
+			__start___markers, __stop___markers);
+	/* Markers in modules. */ 
+	printk("Listing module markers\n");
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints) {
+			printk("Listing markers for module %s\n", mod->name);
+			found += marker_list_probe_range(probe,
+				mod->markers, mod->markers+mod->num_markers);
+		}
+	}
+	spin_unlock_irqrestore(&modlist_lock, flags);
+	return found;
+}
+EXPORT_SYMBOL(marker_list_probe);
+#endif
+
 #ifdef CONFIG_SMP
 /* Number of blocks used and allocated. */
 static unsigned int pcpu_num_used, pcpu_num_allocated;
@@ -1561,6 +1746,7 @@ static struct module *load_module(void __user *umod,
 	unsigned int unusedcrcindex;
 	unsigned int unusedgplindex;
 	unsigned int unusedgplcrcindex;
+	unsigned int markersindex;
 	struct module *mod;
 	long err = 0;
 	void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1657,6 +1843,7 @@ static struct module *load_module(void __user *umod,
 #ifdef ARCH_UNWIND_SECTION_NAME
 	unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
 #endif
+	markersindex = find_sec(hdr, sechdrs, secstrings, ".markers");
 
 	/* Don't keep modinfo section */
 	sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1667,6 +1854,13 @@ static struct module *load_module(void __user *umod,
 #endif
 	if (unwindex)
 		sechdrs[unwindex].sh_flags |= SHF_ALLOC;
+#ifdef CONFIG_MARKERS
+	if (markersindex)
+		sechdrs[markersindex].sh_flags |= SHF_ALLOC;
+#else
+	if (markersindex)
+		sechdrs[markersindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+#endif
 
 	/* Check module struct version now, before we try to use module. */
 	if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1803,6 +1997,11 @@ static struct module *load_module(void __user *umod,
 	mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
 	if (gplfuturecrcindex)
 		mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
+	if (markersindex) {
+		mod->markers = (void *)sechdrs[markersindex].sh_addr;
+		mod->num_markers =
+			sechdrs[markersindex].sh_size / sizeof(*mod->markers);
+	}
 
 	mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
 	if (unusedcrcindex)
@@ -2243,6 +2442,26 @@ const struct seq_operations modules_op = {
 	.show	= m_show
 };
 
+void list_modules(void)
+{
+	/* Enumerate loaded modules */
+	struct list_head	*i;
+	struct module		*mod;
+	unsigned long refcount = 0;
+	
+	mutex_lock(&module_mutex);
+	list_for_each(i, &modules) {
+		mod = list_entry(i, struct module, list);
+#ifdef CONFIG_MODULE_UNLOAD
+		refcount = local_read(&mod->ref[0].count);
+#endif //CONFIG_MODULE_UNLOAD
+		MARK(list_modules, "%s %d[enum module_state] %lu",
+				mod->name, mod->state, refcount);
+	}
+	mutex_unlock(&module_mutex);
+}
+EXPORT_SYMBOL(list_modules);
+
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_extables(unsigned long addr)
 {

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 03/05] Linux Kernel Markers : powerpc optimisation
  2007-01-12  0:02 [PATCH 00/05] Linux Kernel Markers Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 01/05] Linux Kernel Markers : Kconfig menus Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 02/05] Linux Kernel Markers, architecture independant code Mathieu Desnoyers
@ 2007-01-12  0:02 ` Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 04/05] Linux Kernel Markers : i386 optimisation Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 05/05] Linux Kernel Markers, non optimised architectures Mathieu Desnoyers
  4 siblings, 0 replies; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12  0:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Greg Kroah-Hartman,
	Christoph Hellwig, ltt-dev, systemtap, Douglas Niehaus,
	Thomas Gleixner, Mathieu Desnoyers

Linux Kernel Markers : powerpc optimisation

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

--- /dev/null
+++ b/include/asm-powerpc/marker.h
@@ -0,0 +1,58 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. PowerPC architecture
+ * optimisations.
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm/asm-compat.h>
+
+struct __mark_marker_c {
+	const char *name;
+	marker_probe_func **call;
+	const char *format;
+} __attribute__((packed));
+
+struct __mark_marker {
+	struct __mark_marker_c *cmark;
+	volatile short *enable;
+} __attribute__((packed));
+
+#ifdef CONFIG_MARKERS
+
+#define MARK(name, format, args...) \
+	do { \
+		static marker_probe_func *__mark_call_##name = \
+					__mark_empty_function; \
+		static const struct __mark_marker_c __mark_c_##name \
+			__attribute__((section(".markers.c"))) = \
+			{ #name, &__mark_call_##name, format } ; \
+		char condition; \
+		asm volatile(	".section .markers, \"a\";\n\t" \
+					PPC_LONG "%1, 0f;\n\t" \
+					".previous;\n\t" \
+					".align 4\n\t" \
+					"0:\n\t" \
+					"li %0,0;\n\t" \
+				: "=r" (condition) \
+				: "i" (&__mark_c_##name)); \
+		__mark_check_format(format, ## args); \
+		if (unlikely(condition)) { \
+			preempt_disable(); \
+			(*__mark_call_##name)(format, ## args); \
+			preempt_enable_no_resched(); \
+		} \
+	} while (0)
+
+
+/* Offset of the immediate value from the start of the addi instruction (result
+ * of the li mnemonic), in bytes. */
+#define MARK_ENABLE_IMMEDIATE_OFFSET 2
+#define MARK_POLYMORPHIC
+
+#endif

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 04/05] Linux Kernel Markers : i386 optimisation
  2007-01-12  0:02 [PATCH 00/05] Linux Kernel Markers Mathieu Desnoyers
                   ` (2 preceding siblings ...)
  2007-01-12  0:02 ` [PATCH 03/05] Linux Kernel Markers : powerpc optimisation Mathieu Desnoyers
@ 2007-01-12  0:02 ` Mathieu Desnoyers
  2007-01-12  0:02 ` [PATCH 05/05] Linux Kernel Markers, non optimised architectures Mathieu Desnoyers
  4 siblings, 0 replies; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12  0:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Greg Kroah-Hartman,
	Christoph Hellwig, ltt-dev, systemtap, Douglas Niehaus,
	Thomas Gleixner, Mathieu Desnoyers

Linux Kernel Markers : i386 optimisation

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

--- /dev/null
+++ b/include/asm-i386/marker.h
@@ -0,0 +1,54 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. i386 architecture optimisations.
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+
+struct __mark_marker_c {
+	const char *name;
+	marker_probe_func **call;
+	const char *format;
+} __attribute__((packed));
+
+struct __mark_marker {
+	struct __mark_marker_c *cmark;
+	volatile char *enable;
+} __attribute__((packed));
+
+#ifdef CONFIG_MARKERS
+#define MARK(name, format, args...) \
+	do { \
+		static marker_probe_func *__mark_call_##name = \
+					__mark_empty_function; \
+		static const struct __mark_marker_c __mark_c_##name \
+			__attribute__((section(".markers.c"))) = \
+			{ #name, &__mark_call_##name, format } ; \
+		char condition; \
+		asm volatile(	".section .markers, \"a\";\n\t" \
+					".long %1, 0f;\n\t" \
+					".previous;\n\t" \
+					".align 2\n\t" \
+					"0:\n\t" \
+					"movb $0,%0;\n\t" \
+				: "=r" (condition) \
+				: "m" (__mark_c_##name)); \
+		__mark_check_format(format, ## args); \
+		if (unlikely(condition)) { \
+			preempt_disable(); \
+			(*__mark_call_##name)(format, ## args); \
+			preempt_enable_no_resched(); \
+		} \
+	} while (0)
+
+/* Offset of the immediate value from the start of the movb instruction, in
+ * bytes. */
+#define MARK_ENABLE_IMMEDIATE_OFFSET 1
+#define MARK_POLYMORPHIC
+
+#endif

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 05/05] Linux Kernel Markers, non optimised architectures
  2007-01-12  0:02 [PATCH 00/05] Linux Kernel Markers Mathieu Desnoyers
                   ` (3 preceding siblings ...)
  2007-01-12  0:02 ` [PATCH 04/05] Linux Kernel Markers : i386 optimisation Mathieu Desnoyers
@ 2007-01-12  0:02 ` Mathieu Desnoyers
  2007-01-12  4:39   ` Nick Piggin
  4 siblings, 1 reply; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12  0:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Greg Kroah-Hartman,
	Christoph Hellwig, ltt-dev, systemtap, Douglas Niehaus,
	Thomas Gleixner, Mathieu Desnoyers

Linux Kernel Markers, non optimised architectures

This patch also includes marker code for non optimised architectures.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

--- /dev/null
+++ b/include/asm-arm/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-cris/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-frv/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-generic/marker.h
@@ -0,0 +1,49 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Generic header.
+ * 
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ *
+ * Note : the empty asm volatile with read constraint is used here instead of a
+ * "used" attribute to fix a gcc 4.1.x bug.
+ */
+
+struct __mark_marker_c {
+	const char *name;
+	marker_probe_func **call;
+	const char *format;
+} __attribute__((packed));
+
+struct __mark_marker {
+	const struct __mark_marker_c *cmark;
+	volatile char *enable;
+} __attribute__((packed));
+
+#ifdef CONFIG_MARKERS
+
+#define MARK(name, format, args...) \
+	do { \
+		static marker_probe_func *__mark_call_##name = \
+					__mark_empty_function; \
+		volatile static char __marker_enable_##name = 0; \
+		static const struct __mark_marker_c __mark_c_##name \
+			__attribute__((section(".markers.c"))) = \
+			{ #name, &__mark_call_##name, format } ; \
+		static const struct __mark_marker __mark_##name \
+			__attribute__((section(".markers"))) = \
+			{ &__mark_c_##name, &__marker_enable_##name } ; \
+		asm volatile ( "" : : "i" (&__mark_##name)); \
+		__mark_check_format(format, ## args); \
+		if (unlikely(__marker_enable_##name)) { \
+			preempt_disable(); \
+			(*__mark_call_##name)(format, ## args); \
+			preempt_enable_no_resched(); \
+		} \
+	} while (0)
+
+
+#define MARK_ENABLE_IMMEDIATE_OFFSET 0
+
+#endif
--- /dev/null
+++ b/include/asm-h8300/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-ia64/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-m32r/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-m68k/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-m68knommu/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-mips/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-parisc/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-ppc/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-s390/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-sh64/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-sh/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-sparc64/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-sparc/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-um/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-v850/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-x86_64/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>
--- /dev/null
+++ b/include/asm-xtensa/marker.h
@@ -0,0 +1,13 @@
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing. Architecture specific
+ * optimisations.
+ * 
+ * No optimisation implemented.
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#include <asm-generic/marker.h>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 05/05] Linux Kernel Markers, non optimised architectures
  2007-01-12  0:02 ` [PATCH 05/05] Linux Kernel Markers, non optimised architectures Mathieu Desnoyers
@ 2007-01-12  4:39   ` Nick Piggin
  2007-01-12  5:00     ` Mathieu Desnoyers
  0 siblings, 1 reply; 15+ messages in thread
From: Nick Piggin @ 2007-01-12  4:39 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: linux-kernel, Linus Torvalds, Andrew Morton, Ingo Molnar,
	Greg Kroah-Hartman, Christoph Hellwig, ltt-dev, systemtap,
	Douglas Niehaus, Thomas Gleixner

Mathieu Desnoyers wrote:

> +#define MARK(name, format, args...) \
> +	do { \
> +		static marker_probe_func *__mark_call_##name = \
> +					__mark_empty_function; \
> +		volatile static char __marker_enable_##name = 0; \
> +		static const struct __mark_marker_c __mark_c_##name \
> +			__attribute__((section(".markers.c"))) = \
> +			{ #name, &__mark_call_##name, format } ; \
> +		static const struct __mark_marker __mark_##name \
> +			__attribute__((section(".markers"))) = \
> +			{ &__mark_c_##name, &__marker_enable_##name } ; \
> +		asm volatile ( "" : : "i" (&__mark_##name)); \
> +		__mark_check_format(format, ## args); \
> +		if (unlikely(__marker_enable_##name)) { \
> +			preempt_disable(); \
> +			(*__mark_call_##name)(format, ## args); \
> +			preempt_enable_no_resched(); \

Why not just preempt_enable() here?

-- 
SUSE Labs, Novell Inc.
Send instant messages to your online friends http://au.messenger.yahoo.com 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 05/05] Linux Kernel Markers, non optimised architectures
  2007-01-12  4:39   ` Nick Piggin
@ 2007-01-12  5:00     ` Mathieu Desnoyers
  2007-01-12  5:09       ` Nick Piggin
  0 siblings, 1 reply; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12  5:00 UTC (permalink / raw)
  To: Nick Piggin
  Cc: linux-kernel, Linus Torvalds, Andrew Morton, Ingo Molnar,
	Greg Kroah-Hartman, Christoph Hellwig, ltt-dev, systemtap,
	Douglas Niehaus, Thomas Gleixner

* Nick Piggin (nickpiggin@yahoo.com.au) wrote:
> Mathieu Desnoyers wrote:
> 
> >+#define MARK(name, format, args...) \
> >+	do { \
> >+		static marker_probe_func *__mark_call_##name = \
> >+					__mark_empty_function; \
> >+		volatile static char __marker_enable_##name = 0; \
> >+		static const struct __mark_marker_c __mark_c_##name \
> >+			__attribute__((section(".markers.c"))) = \
> >+			{ #name, &__mark_call_##name, format } ; \
> >+		static const struct __mark_marker __mark_##name \
> >+			__attribute__((section(".markers"))) = \
> >+			{ &__mark_c_##name, &__marker_enable_##name } ; \
> >+		asm volatile ( "" : : "i" (&__mark_##name)); \
> >+		__mark_check_format(format, ## args); \
> >+		if (unlikely(__marker_enable_##name)) { \
> >+			preempt_disable(); \
> >+			(*__mark_call_##name)(format, ## args); \
> >+			preempt_enable_no_resched(); \
> 
> Why not just preempt_enable() here?
> 

Because the preempt_enable() macro contains preempt_check_resched(), which
may call preempt_schedule() which leads us to a call to schedule(). Therefore,
all those very interesting scheduler functions would cause an infinite
recursive scheduler call if we marked schedule() and used preempt_enable() in
the marker.

The primary goal for the markers (and the probes that attaches to them) is to
have the fewest side-effects possible : any kernel method called from an
instrumentation site adds this precise kernel method to the "cannot be
instrumented" list, which I want to keep as small possible.

Mathieu

-- 
OpenPGP public key:              http://krystal.dyndns.org:8080/key/compudj.gpg
Key fingerprint:     8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 05/05] Linux Kernel Markers, non optimised architectures
  2007-01-12  5:00     ` Mathieu Desnoyers
@ 2007-01-12  5:09       ` Nick Piggin
  2007-01-12 17:15         ` Mathieu Desnoyers
  2007-01-12 18:23         ` [PATCH 05/05] update - " Mathieu Desnoyers
  0 siblings, 2 replies; 15+ messages in thread
From: Nick Piggin @ 2007-01-12  5:09 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: linux-kernel, Linus Torvalds, Andrew Morton, Ingo Molnar,
	Greg Kroah-Hartman, Christoph Hellwig, ltt-dev, systemtap,
	Douglas Niehaus, Thomas Gleixner

Mathieu Desnoyers wrote:
> * Nick Piggin (nickpiggin@yahoo.com.au) wrote:
> 
>>Mathieu Desnoyers wrote:
>>
>>
>>>+#define MARK(name, format, args...) \
>>>+	do { \
>>>+		static marker_probe_func *__mark_call_##name = \
>>>+					__mark_empty_function; \
>>>+		volatile static char __marker_enable_##name = 0; \
>>>+		static const struct __mark_marker_c __mark_c_##name \
>>>+			__attribute__((section(".markers.c"))) = \
>>>+			{ #name, &__mark_call_##name, format } ; \
>>>+		static const struct __mark_marker __mark_##name \
>>>+			__attribute__((section(".markers"))) = \
>>>+			{ &__mark_c_##name, &__marker_enable_##name } ; \
>>>+		asm volatile ( "" : : "i" (&__mark_##name)); \
>>>+		__mark_check_format(format, ## args); \
>>>+		if (unlikely(__marker_enable_##name)) { \
>>>+			preempt_disable(); \
>>>+			(*__mark_call_##name)(format, ## args); \
>>>+			preempt_enable_no_resched(); \
>>
>>Why not just preempt_enable() here?
>>
> 
> 
> Because the preempt_enable() macro contains preempt_check_resched(), which
> may call preempt_schedule() which leads us to a call to schedule(). Therefore,
> all those very interesting scheduler functions would cause an infinite
> recursive scheduler call if we marked schedule() and used preempt_enable() in
> the marker.

The vast majority of schedule() has preempt turned off, so that shouldn't
be a problem, if you provide a comment.

> The primary goal for the markers (and the probes that attaches to them) is to
> have the fewest side-effects possible : any kernel method called from an
> instrumentation site adds this precise kernel method to the "cannot be
> instrumented" list, which I want to keep as small possible.

OK, well one problem is that it can cause a resched event to be lost, so
you might say it has more side-effects without checking resched.

-- 
SUSE Labs, Novell Inc.
Send instant messages to your online friends http://au.messenger.yahoo.com 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 05/05] Linux Kernel Markers, non optimised architectures
  2007-01-12  5:09       ` Nick Piggin
@ 2007-01-12 17:15         ` Mathieu Desnoyers
  2007-01-12 17:43           ` Mathieu Desnoyers
  2007-01-12 18:23         ` [PATCH 05/05] update - " Mathieu Desnoyers
  1 sibling, 1 reply; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12 17:15 UTC (permalink / raw)
  To: Nick Piggin
  Cc: linux-kernel, Linus Torvalds, Andrew Morton, Ingo Molnar,
	Greg Kroah-Hartman, Christoph Hellwig, ltt-dev, systemtap,
	Douglas Niehaus, Thomas Gleixner

* Nick Piggin (nickpiggin@yahoo.com.au) wrote:
> Mathieu Desnoyers wrote:
> >* Nick Piggin (nickpiggin@yahoo.com.au) wrote:
> >
> >>Mathieu Desnoyers wrote:
> >>
> >>
> >>>+#define MARK(name, format, args...) \
> >>>+	do { \
> >>>+		static marker_probe_func *__mark_call_##name = \
> >>>+					__mark_empty_function; \
> >>>+		volatile static char __marker_enable_##name = 0; \
> >>>+		static const struct __mark_marker_c __mark_c_##name \
> >>>+			__attribute__((section(".markers.c"))) = \
> >>>+			{ #name, &__mark_call_##name, format } ; \
> >>>+		static const struct __mark_marker __mark_##name \
> >>>+			__attribute__((section(".markers"))) = \
> >>>+			{ &__mark_c_##name, &__marker_enable_##name } ; \
> >>>+		asm volatile ( "" : : "i" (&__mark_##name)); \
> >>>+		__mark_check_format(format, ## args); \
> >>>+		if (unlikely(__marker_enable_##name)) { \
> >>>+			preempt_disable(); \
> >>>+			(*__mark_call_##name)(format, ## args); \
> >>>+			preempt_enable_no_resched(); \
> >>
> >>Why not just preempt_enable() here?
> >>
> >
> >
> >Because the preempt_enable() macro contains preempt_check_resched(), which
> >may call preempt_schedule() which leads us to a call to schedule(). 
> >Therefore,
> >all those very interesting scheduler functions would cause an infinite
> >recursive scheduler call if we marked schedule() and used preempt_enable() 
> >in
> >the marker.
> 
> The vast majority of schedule() has preempt turned off, so that shouldn't
> be a problem, if you provide a comment.
> 
> >The primary goal for the markers (and the probes that attaches to them) is 
> >to
> >have the fewest side-effects possible : any kernel method called from an
> >instrumentation site adds this precise kernel method to the "cannot be
> >instrumented" list, which I want to keep as small possible.
> 
> OK, well one problem is that it can cause a resched event to be lost, so
> you might say it has more side-effects without checking resched.
> 

I agree : this a side-effect I pointed out in my LTTng presentation last
summer at OLS.

Here is a quick idea of the potentially problematic instrumentation points
(i386 example) :

- with the task_rq_lock held (therefore preemption is disabled, so it's not a
  problem)
sched.c wait_task_inactive()
sched.c try_to_wake_up()
sched.c wake_up_new_task()
sched.c sched_migrate_task()

sched.c schedule() after prepare_task_switch call, before context_switch call.
  Surrounded by preempt_disable(), preempt_enable_no_resched(), should be ok.

- IRQs : irq_enter()/irq_exit() calls in do_IRQ makes sure that the
  preempt_count is incremented. irq_enter() is called with interrupts still
  disabled.
kernel/irq/handle.c handle_IRQ_event()

- NMIs : nmi_enter() -> irq_enter() -> add_preempt_count(HARDIRQ_OFFSET) called
  with interrupts still disabled.
  Therefore, preemption is disabled within trace points in do_nmi.

- traps : GPF, do_trap, do_page_fault, do_debug, spurious_interrupt,
  math_emulate.
  It is not uncommon for these trap handlers to reenable interrupts very soon.
  They do not increment the preemption count.
  Therefore, preemption must be expected when these handlers run : we cannot
  rely of the fact that hard IRQs would be disabled to prevent the scheduler
  from running, as markers becomes a new source of scheduler events.

- local_irq_enable()/local_irq_disable() :
  It can call trace_hardirqs_on()/trace_hardirqs_off(). These macros are
  sprinkled in _every_ possible context cited above, from trap handlers to
  preemptible code.

Other contexts or code location are not a problem (process context, softirq).

If we are sure that we expect calls to preempt_schedule() from each of these
contexts, then it's ok to put preempt_enable(). It is important to note that a
marker would then act as a source of scheduler events in code paths where
disabling interrupts is expected to disable the scheduler.

Mathieu

-- 
OpenPGP public key:              http://krystal.dyndns.org:8080/key/compudj.gpg
Key fingerprint:     8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 05/05] Linux Kernel Markers, non optimised architectures
  2007-01-12 17:15         ` Mathieu Desnoyers
@ 2007-01-12 17:43           ` Mathieu Desnoyers
  0 siblings, 0 replies; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12 17:43 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Andrew Morton, Greg Kroah-Hartman, linux-kernel,
	Christoph Hellwig, Linus Torvalds, Ingo Molnar, ltt-dev,
	systemtap, Thomas Gleixner, Douglas Niehaus

* Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) wrote:
> > 
> > OK, well one problem is that it can cause a resched event to be lost, so
> > you might say it has more side-effects without checking resched.
> > 
[...]
> If we are sure that we expect calls to preempt_schedule() from each of these
> contexts, then it's ok to put preempt_enable(). It is important to note that a
> marker would then act as a source of scheduler events in code paths where
> disabling interrupts is expected to disable the scheduler.
> 

Sorry for self-reply, but the above mentioned issue is dealt by the
irqs_disabled() check at the beginning of preempt_schedule().

Mathieu


-- 
OpenPGP public key:              http://krystal.dyndns.org:8080/key/compudj.gpg
Key fingerprint:     8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 05/05] update - Linux Kernel Markers, non optimised architectures
  2007-01-12  5:09       ` Nick Piggin
  2007-01-12 17:15         ` Mathieu Desnoyers
@ 2007-01-12 18:23         ` Mathieu Desnoyers
  1 sibling, 0 replies; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-01-12 18:23 UTC (permalink / raw)
  To: Nick Piggin
  Cc: linux-kernel, Linus Torvalds, Andrew Morton, Ingo Molnar,
	Greg Kroah-Hartman, Christoph Hellwig, ltt-dev, systemtap,
	Douglas Niehaus, Thomas Gleixner

* Nick Piggin (nickpiggin@yahoo.com.au) wrote:
> OK, well one problem is that it can cause a resched event to be lost, so
> you might say it has more side-effects without checking resched.
> 

Here is the patch that implements this. I also did a cosmetic change to
linux/marker.h. Preliminary tests of running the markers with preempt_enable()
with LTTng 0.6.56 instrumentation shows no problem.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

--- a/include/asm-generic/marker.h
+++ b/include/asm-generic/marker.h
@@ -39,7 +39,7 @@ struct __mark_marker {
 		if (unlikely(__marker_enable_##name)) { \
 			preempt_disable(); \
 			(*__mark_call_##name)(format, ## args); \
-			preempt_enable_no_resched(); \
+			preempt_enable(); \
 		} \
 	} while (0)
 
--- a/include/asm-i386/marker.h
+++ b/include/asm-i386/marker.h
@@ -42,7 +42,7 @@ struct __mark_marker {
 		if (unlikely(condition)) { \
 			preempt_disable(); \
 			(*__mark_call_##name)(format, ## args); \
-			preempt_enable_no_resched(); \
+			preempt_enable(); \
 		} \
 	} while (0)
 
--- a/include/asm-powerpc/marker.h
+++ b/include/asm-powerpc/marker.h
@@ -45,7 +45,7 @@ struct __mark_marker {
 		if (unlikely(condition)) { \
 			preempt_disable(); \
 			(*__mark_call_##name)(format, ## args); \
-			preempt_enable_no_resched(); \
+			preempt_enable(); \
 		} \
 	} while (0)
 
--- a/include/linux/marker.h
+++ b/include/linux/marker.h
@@ -8,12 +8,12 @@
  *
  * Example :
  *
- * MARK(subsystem_event, "%d %s %p[struct task_struct *]",
+ * MARK(subsystem_event, "%d %s %p[struct task_struct]",
  *   someint, somestring, current);
  * Where :
  * - Subsystem is the name of your subsystem.
  * - event is the name of the event to mark.
- * - "%d %s %p[struct task_struct *]" is the formatted string for printk.
+ * - "%d %s %p[struct task_struct]" is the formatted string for printk.
  * - someint is an integer.
  * - somestring is a char pointer.
  * - current is a pointer to a struct task_struct.
@@ -27,6 +27,9 @@
  * Markers can be put in inline functions, inlined static functions and
  * unrolled loops.
  *
+ * Note : It is safe to put markers within preempt-safe code : preempt_enable()
+ * will not call the scheduler due to the tests in preempt_schedule().
+ *
  * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
  *
  * This file is released under the GPLv2.
-- 
OpenPGP public key:              http://krystal.dyndns.org:8080/key/compudj.gpg
Key fingerprint:     8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68 

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 02/05] Linux Kernel Markers, architecture independant code.
  2007-02-15  7:21   ` Andrew Morton
@ 2007-02-15 19:12     ` Mathieu Desnoyers
  0 siblings, 0 replies; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-02-15 19:12 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, Christoph Hellwig, Ingo Molnar, systemtap, ltt-dev

* Andrew Morton (akpm@linux-foundation.org) wrote:
> On Sun, 11 Feb 2007 15:03:24 -0500 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> wrote:
> 
> > Linux Kernel Markers, architecture independant code.
> > 
> > Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
> > 
> > ...
> >
> > +
> > +#ifndef MARK
> > +#define MARK GEN_MARK
> > +#define MARK_ENABLE_TYPE GEN_MARK_ENABLE_TYPE
> > +#define MARK_ENABLE_IMMEDIATE_OFFSET GEN_MARK_ENABLE_IMMEDIATE_OFFSET
> > +#endif
> 
> Also perhaps this nastiness can go away once each architecture has
> asm/marker.h?
> 
Yes, absolutely.

> > +#ifdef MARK_POLYMORPHIC
> 
> What's this?  Is it commented somewhere?  (It should be...)
> 

No, but should be : it is defined by the architecture's marker.h when
the marker flavor has to do code motification when the marker state is
modified.


> > +static int marker_set_ins_enable(void *address, char enable)
> > +{
> > +#ifdef CONFIG_X86_32
> > +	return arch_marker_set_ins_enable(address, enable);
> > +#else
> > +	char newi[MARK_ENABLE_IMMEDIATE_OFFSET+1];
> > +	int size = MARK_ENABLE_IMMEDIATE_OFFSET+sizeof(MARK_ENABLE_TYPE);
> > +
> > +	memcpy(newi, address, size);
> > +	MARK_ENABLE(&newi[0]) = enable;
> > +	memcpy(address, newi, size);
> > +	flush_icache_range((unsigned long)address, size);
> > +	return 0;
> > +#endif //CONFIG_X86_32
> > +}
> 
> eww.  Can we put a suitable arch_marker_set_ins_enable() into each arch's
> marker.h?
> 

Or maybe put that in asm-generic so we do not duplicate code.

> > +#else
> > +static int marker_set_ins_enable(void *address, char enable)
> > +{
> > +	return -EPERM;
> > +}
> > +#endif //MARK_POLYMORPHIC
> > +
> >
> > ...
> >
> 

-- 
Mathieu Desnoyers
Computer Engineering Ph.D. Candidate, École Polytechnique de Montréal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 02/05] Linux Kernel Markers, architecture independant code.
  2007-02-11 20:03 ` [PATCH 02/05] Linux Kernel Markers, architecture independant code Mathieu Desnoyers
@ 2007-02-15  7:21   ` Andrew Morton
  2007-02-15 19:12     ` Mathieu Desnoyers
  0 siblings, 1 reply; 15+ messages in thread
From: Andrew Morton @ 2007-02-15  7:21 UTC (permalink / raw)
  To: Mathieu Desnoyers
  Cc: linux-kernel, Christoph Hellwig, Ingo Molnar, systemtap, ltt-dev

On Sun, 11 Feb 2007 15:03:24 -0500 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> wrote:

> Linux Kernel Markers, architecture independant code.
> 
> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
> 
> ...
>
> +
> +#ifndef MARK
> +#define MARK GEN_MARK
> +#define MARK_ENABLE_TYPE GEN_MARK_ENABLE_TYPE
> +#define MARK_ENABLE_IMMEDIATE_OFFSET GEN_MARK_ENABLE_IMMEDIATE_OFFSET
> +#endif

Also perhaps this nastiness can go away once each architecture has
asm/marker.h?

> +#ifdef MARK_POLYMORPHIC

What's this?  Is it commented somewhere?  (It should be...)

> +static int marker_set_ins_enable(void *address, char enable)
> +{
> +#ifdef CONFIG_X86_32
> +	return arch_marker_set_ins_enable(address, enable);
> +#else
> +	char newi[MARK_ENABLE_IMMEDIATE_OFFSET+1];
> +	int size = MARK_ENABLE_IMMEDIATE_OFFSET+sizeof(MARK_ENABLE_TYPE);
> +
> +	memcpy(newi, address, size);
> +	MARK_ENABLE(&newi[0]) = enable;
> +	memcpy(address, newi, size);
> +	flush_icache_range((unsigned long)address, size);
> +	return 0;
> +#endif //CONFIG_X86_32
> +}

eww.  Can we put a suitable arch_marker_set_ins_enable() into each arch's
marker.h?

> +#else
> +static int marker_set_ins_enable(void *address, char enable)
> +{
> +	return -EPERM;
> +}
> +#endif //MARK_POLYMORPHIC
> +
>
> ...
>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 02/05] Linux Kernel Markers, architecture independant code.
  2007-02-11 20:03 [PATCH 00/05] Linux Kernel Markers - kernel 2.6.20 Mathieu Desnoyers
@ 2007-02-11 20:03 ` Mathieu Desnoyers
  2007-02-15  7:21   ` Andrew Morton
  0 siblings, 1 reply; 15+ messages in thread
From: Mathieu Desnoyers @ 2007-02-11 20:03 UTC (permalink / raw)
  To: linux-kernel
  Cc: Andrew Morton, Mathieu Desnoyers, Christoph Hellwig, Ingo Molnar,
	systemtap, ltt-dev

Linux Kernel Markers, architecture independant code.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>

--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -121,6 +121,19 @@
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\
 	}								\
+	/* Kernel markers : pointers */					\
+	.markers : AT(ADDR(.markers) - LOAD_OFFSET) {			\
+		VMLINUX_SYMBOL(__start___markers) = .;			\
+		*(.markers)						\
+		VMLINUX_SYMBOL(__stop___markers) = .;			\
+	}								\
+	.markers.c : AT(ADDR(.markers.c) - LOAD_OFFSET) {		\
+		VMLINUX_SYMBOL(__start___markers_c) = .;		\
+		*(.markers.c)						\
+		VMLINUX_SYMBOL(__stop___markers_c) = .;			\
+	}								\
+	__end_rodata = .;						\
+	. = ALIGN(4096);						\
 									\
 	/* Built-in module parameters. */				\
 	__param : AT(ADDR(__param) - LOAD_OFFSET) {			\
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -356,6 +356,9 @@ struct module
 	/* The command line arguments (may be mangled).  People like
 	   keeping pointers to this stuff */
 	char *args;
+
+	const struct __mark_marker *markers;
+	unsigned int num_markers;
 };
 
 /* FIXME: It'd be nice to isolate modules during init, too, so they
@@ -469,6 +472,7 @@ extern void print_modules(void);
 struct device_driver;
 void module_add_driver(struct module *, struct device_driver *);
 void module_remove_driver(struct device_driver *);
+extern void list_modules(void);
 
 #else /* !CONFIG_MODULES... */
 #define EXPORT_SYMBOL(sym)
--- /dev/null
+++ b/include/linux/marker.h
@@ -0,0 +1,97 @@
+#ifndef _LINUX_MARKER_H
+#define _LINUX_MARKER_H
+
+/*
+ * marker.h
+ *
+ * Code markup for dynamic and static tracing.
+ *
+ * Example :
+ *
+ * MARK(subsystem_event, "%d %s %p[struct task_struct]",
+ *   someint, somestring, current);
+ * Where :
+ * - Subsystem is the name of your subsystem.
+ * - event is the name of the event to mark.
+ * - "%d %s %p[struct task_struct]" is the formatted string for printk.
+ * - someint is an integer.
+ * - somestring is a char pointer.
+ * - current is a pointer to a struct task_struct.
+ *
+ * - Dynamically overridable function call based on marker mechanism
+ *   from Frank Ch. Eigler <fche@redhat.com>.
+ * - Thanks to Jeremy Fitzhardinge <jeremy@goop.org> for his constructive
+ *   criticism about gcc optimization related issues.
+ *
+ * The marker mechanism supports multiple instances of the same marker.
+ * Markers can be put in inline functions, inlined static functions and
+ * unrolled loops.
+ *
+ * Note : It is safe to put markers within preempt-safe code : preempt_enable()
+ * will not call the scheduler due to the tests in preempt_schedule().
+ *
+ * (C) Copyright 2006 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
+ *
+ * This file is released under the GPLv2.
+ * See the file COPYING for more details.
+ */
+
+#ifndef __ASSEMBLY__
+
+typedef void marker_probe_func(const char *fmt, ...);
+
+enum marker_type { MARKER_GENERIC, MARKER_OPTIMIZED };
+
+struct __mark_marker_c {
+	const char *name;
+	marker_probe_func **call;
+	const char *format;
+	enum marker_type type;
+} __attribute__((packed));
+
+struct __mark_marker {
+	const struct __mark_marker_c *cmark;
+	void *enable;
+} __attribute__((packed));
+
+#ifdef CONFIG_MARKERS_ENABLE_OPTIMIZATION
+#include <asm/marker.h>
+#endif
+
+#include <asm-generic/marker.h>
+
+#define MARK_NOARGS " "
+#define MARK_MAX_FORMAT_LEN	1024
+
+#ifndef CONFIG_MARKERS
+#define GEN_MARK(name, format, args...) \
+		__mark_check_format(format, ## args)
+#endif
+
+#ifndef MARK
+#define MARK GEN_MARK
+#define MARK_ENABLE_TYPE GEN_MARK_ENABLE_TYPE
+#define MARK_ENABLE_IMMEDIATE_OFFSET GEN_MARK_ENABLE_IMMEDIATE_OFFSET
+#endif
+
+/* Dereference enable as lvalue from a pointer to its instruction */
+#define MARK_ENABLE(a) \
+	*(MARK_ENABLE_TYPE*)((char*)a+MARK_ENABLE_IMMEDIATE_OFFSET)
+
+#define GEN_MARK_ENABLE(a) \
+	*(GEN_MARK_ENABLE_TYPE*)((char*)a+GEN_MARK_ENABLE_IMMEDIATE_OFFSET)
+
+static inline __attribute__ ((format (printf, 1, 2)))
+void __mark_check_format(const char *fmt, ...)
+{ }
+
+extern marker_probe_func __mark_empty_function;
+
+extern int marker_set_probe(const char *name, const char *format,
+				marker_probe_func *probe);
+
+extern int marker_remove_probe(marker_probe_func *probe);
+extern int marker_list_probe(marker_probe_func *probe);
+
+#endif
+#endif
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -138,6 +138,8 @@ extern const unsigned long __start___kcrctab_gpl[];
 extern const unsigned long __start___kcrctab_gpl_future[];
 extern const unsigned long __start___kcrctab_unused[];
 extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const struct __mark_marker __start___markers[];
+extern const struct __mark_marker __stop___markers[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -298,6 +300,214 @@ static struct module *find_module(const char *name)
 	return NULL;
 }
 
+#ifdef CONFIG_MARKERS
+void __mark_empty_function(const char *fmt, ...)
+{
+}
+EXPORT_SYMBOL(__mark_empty_function);
+
+#ifdef MARK_POLYMORPHIC
+static int marker_set_ins_enable(void *address, char enable)
+{
+#ifdef CONFIG_X86_32
+	return arch_marker_set_ins_enable(address, enable);
+#else
+	char newi[MARK_ENABLE_IMMEDIATE_OFFSET+1];
+	int size = MARK_ENABLE_IMMEDIATE_OFFSET+sizeof(MARK_ENABLE_TYPE);
+
+	memcpy(newi, address, size);
+	MARK_ENABLE(&newi[0]) = enable;
+	memcpy(address, newi, size);
+	flush_icache_range((unsigned long)address, size);
+	return 0;
+#endif //CONFIG_X86_32
+}
+#else
+static int marker_set_ins_enable(void *address, char enable)
+{
+	return -EPERM;
+}
+#endif //MARK_POLYMORPHIC
+
+static int marker_set_gen_enable(void *address, char enable)
+{
+	GEN_MARK_ENABLE(address) = enable;
+	return 0;
+}
+
+static int marker_set_enable(void *address, char enable, enum marker_type type)
+{
+	if (type == MARKER_OPTIMIZED)
+		return marker_set_ins_enable(address, enable);
+	else
+		return marker_set_gen_enable(address, enable);
+}
+	
+/* enable and function address are set out of order, and it's ok :
+ * the state is always coherent. */
+static int marker_set_probe_range(const char *name, 
+	const char *format,
+	marker_probe_func *probe,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (strcmp(name, iter->cmark->name) == 0) {
+			if (format
+				&& strcmp(format, iter->cmark->format) != 0) {
+				printk(KERN_NOTICE
+					"Format mismatch for probe %s "
+					"(%s), marker (%s)\n",
+					name,
+					format,
+					iter->cmark->format);
+				continue;
+			}
+			if (probe == __mark_empty_function) {
+				if (*iter->cmark->call
+					!= __mark_empty_function) {
+					*iter->cmark->call =
+						__mark_empty_function;
+				}
+				marker_set_enable(iter->enable, 0,
+					iter->cmark->type);
+			} else {
+				if (*iter->cmark->call
+					!= __mark_empty_function) {
+					if (*iter->cmark->call != probe) {
+						printk(KERN_NOTICE
+							"Marker %s busy, "
+							"probe %p already "
+							"installed\n",
+							name,
+							*iter->cmark->call);
+						continue;
+					}
+				} else {
+					found++;
+					*iter->cmark->call = probe;
+				}
+				/* Can have many enables for one function */
+				marker_set_enable(iter->enable, 1,
+					iter->cmark->type);
+			}
+			found++;
+		}
+	}
+	return found;
+}
+
+static int marker_remove_probe_range(marker_probe_func *probe,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (*iter->cmark->call == probe) {
+			marker_set_enable(iter->enable, 0,
+				iter->cmark->type);
+			*iter->cmark->call = __mark_empty_function;
+			found++;
+		}
+	}
+	return found;
+}
+
+static int marker_list_probe_range(marker_probe_func *probe,
+	const struct __mark_marker *begin,
+	const struct __mark_marker *end)
+{
+	const struct __mark_marker *iter;
+	int found = 0;
+
+	for (iter = begin; iter < end; iter++) {
+		if (probe)
+			if (probe != *iter->cmark->call) continue;
+		printk("name %s \n", iter->cmark->name);
+		if (iter->cmark->type == MARKER_OPTIMIZED)
+			printk("  enable %u optimized ",
+				MARK_ENABLE(iter->enable));
+		else
+			printk("  enable %u generic ",
+				GEN_MARK_ENABLE(iter->enable));
+		printk("  func 0x%p format \"%s\"\n",
+			*iter->cmark->call, iter->cmark->format);
+		found++;
+	}
+	return found;
+}
+/* markers use the modlist_lock to to synchronise */
+int marker_set_probe(const char *name, const char *format,
+				marker_probe_func *probe)
+{
+	struct module *mod;
+	int found = 0;
+
+	mutex_lock(&module_mutex);
+	/* Core kernel markers */
+	found += marker_set_probe_range(name, format, probe,
+			__start___markers, __stop___markers);
+	/* Markers in modules. */ 
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints)
+			found += marker_set_probe_range(name, format, probe,
+				mod->markers, mod->markers+mod->num_markers);
+	}
+	mutex_unlock(&module_mutex);
+	return found;
+}
+EXPORT_SYMBOL(marker_set_probe);
+
+int marker_remove_probe(marker_probe_func *probe)
+{
+	struct module *mod;
+	int found = 0;
+
+	mutex_lock(&module_mutex);
+	/* Core kernel markers */
+	found += marker_remove_probe_range(probe,
+			__start___markers, __stop___markers);
+	/* Markers in modules. */ 
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints)
+			found += marker_remove_probe_range(probe,
+				mod->markers, mod->markers+mod->num_markers);
+	}
+	mutex_unlock(&module_mutex);
+	return found;
+}
+EXPORT_SYMBOL(marker_remove_probe);
+
+int marker_list_probe(marker_probe_func *probe)
+{
+	struct module *mod;
+	int found = 0;
+
+	mutex_lock(&module_mutex);
+	/* Core kernel markers */
+	printk("Listing kernel markers\n");
+	found += marker_list_probe_range(probe,
+			__start___markers, __stop___markers);
+	/* Markers in modules. */ 
+	printk("Listing module markers\n");
+	list_for_each_entry(mod, &modules, list) {
+		if (!mod->taints) {
+			printk("Listing markers for module %s\n", mod->name);
+			found += marker_list_probe_range(probe,
+				mod->markers, mod->markers+mod->num_markers);
+		}
+	}
+	mutex_unlock(&module_mutex);
+	return found;
+}
+EXPORT_SYMBOL(marker_list_probe);
+#endif
+
 #ifdef CONFIG_SMP
 /* Number of blocks used and allocated. */
 static unsigned int pcpu_num_used, pcpu_num_allocated;
@@ -1561,6 +1773,7 @@ static struct module *load_module(void __user *umod,
 	unsigned int unusedcrcindex;
 	unsigned int unusedgplindex;
 	unsigned int unusedgplcrcindex;
+	unsigned int markersindex;
 	struct module *mod;
 	long err = 0;
 	void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1657,6 +1870,7 @@ static struct module *load_module(void __user *umod,
 #ifdef ARCH_UNWIND_SECTION_NAME
 	unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
 #endif
+	markersindex = find_sec(hdr, sechdrs, secstrings, ".markers");
 
 	/* Don't keep modinfo section */
 	sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1667,6 +1881,13 @@ static struct module *load_module(void __user *umod,
 #endif
 	if (unwindex)
 		sechdrs[unwindex].sh_flags |= SHF_ALLOC;
+#ifdef CONFIG_MARKERS
+	if (markersindex)
+		sechdrs[markersindex].sh_flags |= SHF_ALLOC;
+#else
+	if (markersindex)
+		sechdrs[markersindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+#endif
 
 	/* Check module struct version now, before we try to use module. */
 	if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1803,6 +2024,11 @@ static struct module *load_module(void __user *umod,
 	mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
 	if (gplfuturecrcindex)
 		mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
+	if (markersindex) {
+		mod->markers = (void *)sechdrs[markersindex].sh_addr;
+		mod->num_markers =
+			sechdrs[markersindex].sh_size / sizeof(*mod->markers);
+	}
 
 	mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
 	if (unusedcrcindex)
@@ -2243,6 +2471,26 @@ const struct seq_operations modules_op = {
 	.show	= m_show
 };
 
+void list_modules(void)
+{
+	/* Enumerate loaded modules */
+	struct list_head	*i;
+	struct module		*mod;
+	unsigned long refcount = 0;
+	
+	mutex_lock(&module_mutex);
+	list_for_each(i, &modules) {
+		mod = list_entry(i, struct module, list);
+#ifdef CONFIG_MODULE_UNLOAD
+		refcount = local_read(&mod->ref[0].count);
+#endif //CONFIG_MODULE_UNLOAD
+		MARK(list_modules, "%s %d[enum module_state] %lu",
+				mod->name, mod->state, refcount);
+	}
+	mutex_unlock(&module_mutex);
+}
+EXPORT_SYMBOL(list_modules);
+
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_extables(unsigned long addr)
 {

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2007-02-15 19:12 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-01-12  0:02 [PATCH 00/05] Linux Kernel Markers Mathieu Desnoyers
2007-01-12  0:02 ` [PATCH 01/05] Linux Kernel Markers : Kconfig menus Mathieu Desnoyers
2007-01-12  0:02 ` [PATCH 02/05] Linux Kernel Markers, architecture independant code Mathieu Desnoyers
2007-01-12  0:02 ` [PATCH 03/05] Linux Kernel Markers : powerpc optimisation Mathieu Desnoyers
2007-01-12  0:02 ` [PATCH 04/05] Linux Kernel Markers : i386 optimisation Mathieu Desnoyers
2007-01-12  0:02 ` [PATCH 05/05] Linux Kernel Markers, non optimised architectures Mathieu Desnoyers
2007-01-12  4:39   ` Nick Piggin
2007-01-12  5:00     ` Mathieu Desnoyers
2007-01-12  5:09       ` Nick Piggin
2007-01-12 17:15         ` Mathieu Desnoyers
2007-01-12 17:43           ` Mathieu Desnoyers
2007-01-12 18:23         ` [PATCH 05/05] update - " Mathieu Desnoyers
2007-02-11 20:03 [PATCH 00/05] Linux Kernel Markers - kernel 2.6.20 Mathieu Desnoyers
2007-02-11 20:03 ` [PATCH 02/05] Linux Kernel Markers, architecture independant code Mathieu Desnoyers
2007-02-15  7:21   ` Andrew Morton
2007-02-15 19:12     ` Mathieu Desnoyers

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 NNTP newsgroup(s).