Skip to contentSkip to conversation

Linux Kernel Markers for 2.6.23-rc6-mm1

PATCH In review Mathieu Desnoyers 9 participants 35 messages Sep 18, 2007 – Nov 11, 2007

Subsystems (9)
lore
Share & tools
lore
#0 lore raw

cover Linux Kernel Markers for 2.6.23-rc6-mm1

Hi Andrew,

Here are the updated Linux Kernel Markers.

It depends on :
Text Edit Lock
Immediate Values
Sorted module list
Merge Kconfig instrumentation menu

It applies to 2.6.23-rc4-mm1, in this order:

linux-kernel-markers-architecture-independent-code.patch linux-kernel-markers-instrumentation-menu.patch linux-kernel-markers-documentation.patch linux-kernel-markers-port-blktrace-to-markers.patch

You can find a tarball of this patch and all its dependencies at:
http://ltt.polymtl.ca/markers/markers-patches-for-2.6.23-rc6-mm1-18-09-2007.tar.bz2

Mathieu

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#1 lore raw

PATCH 1/4 Linux Kernel Markers - Architecture Independent Code

The marker activation functions sits in kernel/marker.c. A hash table is used to keep track of the registered probes and armed markers, so the markers within a newly loaded module that should be active can be activated at module load time.

marker_query has been removed. marker_get_first, marker_get_next and marker_release should be used as iterators on the markers.

Changelog:
- markers_mutex now nests inside module_mutex rather than the opposite.
- Iteration on modules is now done in module.c.
- module_mutex is not exported anymore.

---

 include/asm-generic/vmlinux.lds.h |   11 
 include/linux/marker.h            |  175 ++++++++++
 include/linux/module.h            |   18 +
 kernel/marker.c                   |  608 ++++++++++++++++++++++++++++++++++++++
 kernel/module.c                   |   66 ++++
 5 files changed, 875 insertions(+), 3 deletions(-)
include/asm-generic/vmlinux.lds.h +10 -1
Index: linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================
@@ -12,7 +12,11 @@
 /* .data section */
 #define DATA_DATA							\
 	*(.data)							\
-	*(.data.init.refok)
+	*(.data.init.refok)						\
+	. = ALIGN(8);							\
+	VMLINUX_SYMBOL(__start___markers) = .;				\
+	*(__markers)							\
+	VMLINUX_SYMBOL(__stop___markers) = .;
 
 #define RO_DATA(align)							\
 	. = ALIGN((align));						\
@@ -129,6 +133,11 @@
 		VMLINUX_SYMBOL(__stop___immediate) = .;			\
 	}								\
 									\
+	/* Markers: strings */						\
+        __markers_strings : AT(ADDR(__markers_strings) - LOAD_OFFSET) {	\
+		*(__markers_strings)					\
+ 	}								\
+									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\
include/linux/marker.h new file +175 -0

175 lines not on this page · raw message

include/linux/module.h +18 -0
Index: linux-2.6-lttng/include/linux/module.h
===================================================================
@@ -16,6 +16,7 @@
 #include <linux/kobject.h>
 #include <linux/moduleparam.h>
 #include <linux/immediate.h>
+#include <linux/marker.h>
 #include <asm/local.h>
 
 #include <asm/module.h>
@@ -376,6 +377,10 @@ struct module
 	const struct __immediate *immediate;
 	unsigned int num_immediate;
 #endif
+#ifdef CONFIG_MARKERS
+	struct __mark_marker *markers;
+	unsigned int num_markers;
+#endif
 };
 #ifndef MODULE_ARCH_INIT
 #define MODULE_ARCH_INIT {}
@@ -482,6 +487,9 @@ extern void print_modules(void);
 extern void _module_immediate_update(void);
 extern void module_immediate_update(void);
 
+extern void module_update_markers(struct module *probe_module, int *refcount);
+extern int module_get_iter_markers(struct marker_iter *iter);
+
 #else /* !CONFIG_MODULES... */
 #define EXPORT_SYMBOL(sym)
 #define EXPORT_SYMBOL_GPL(sym)
@@ -589,6 +597,16 @@ static inline void module_immediate_upda
 {
 }
 
+static inline void module_update_markers(struct module *probe_module,
+		int *refcount)
+{
+}
+
+static inline int module_get_iter_markers(struct marker_iter *iter)
+{
+	return 0;
+}
+
 #endif /* CONFIG_MODULES */
 
 struct device_driver;
kernel/module.c +64 -2

97 lines not on this page · raw message

kernel/marker.c new file +608 -0

608 lines not on this page · raw message

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#2 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 13 lines · * Mathieu Desnoyers ([email protected]) wrote:

The marker activation functions sits in kernel/marker.c. A hash table is used to keep track of the registered probes and armed markers, so the markers within a newly loaded module that should be active can be activated at module load time.

marker_query has been removed. marker_get_first, marker_get_next and marker_release should be used as iterators on the markers.

Changelog:
- markers_mutex now nests inside module_mutex rather than the opposite.
- Iteration on modules is now done in module.c.
- module_mutex is not exported anymore.

[...]

Quoted 19 lines

Index: linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================

include/asm-generic/vmlinux.lds.h +5 -1
@@ -12,7 +12,11 @@
 /* .data section */
 #define DATA_DATA							\
 	*(.data)							\
-	*(.data.init.refok)
+	*(.data.init.refok)						\
+	. = ALIGN(8);							\
+	VMLINUX_SYMBOL(__start___markers) = .;				\
+	*(__markers)							\
+	VMLINUX_SYMBOL(__stop___markers) = .;
 
 #define RO_DATA(align)							\
 	. = ALIGN((align));						\
@@ -129,6 +133,11 @@
 		VMLINUX_SYMBOL(__stop___immediate) = .;			\

include/asm-generic/vmlinux.lds.h line 143

Quoted 10 lines
include/asm-generic/vmlinux.lds.h +5 -0
 	}								\
 									\
+	/* Markers: strings */						\
+        __markers_strings : AT(ADDR(__markers_strings) - LOAD_OFFSET) {	\
+		*(__markers_strings)					\
+ 	}								\
+									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\

[...]

Do you think I should also remove the __markers_strings section from here ?

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#3 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 18 lines · Mathieu Desnoyers
Quoted 16 lines

Index: linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================

include/asm-generic/vmlinux.lds.h +5 -0
@@ -129,6 +133,11 @@
 		VMLINUX_SYMBOL(__stop___immediate) = .;			\
 	}								\
 									\
+	/* Markers: strings */						\
+        __markers_strings : AT(ADDR(__markers_strings) - LOAD_OFFSET) {	\
+		*(__markers_strings)					\
+ 	}								\
+									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\

[...]

Quoted 1 line

Do you think I should also remove the __markers_strings section from here ?

Yes.

It will be beneficial if one can read include/asm-generic/vmlinux.lds.h and arch/$ARCH/kernel/vmlinux.lds.S and understand which sections in resulting vmlinux serve what purpose. A comment atop each section explaining its role will be nice. Even more so that not many people are fluent in ld script language.

Currently, one will need to grep around (and not only in kernel tree - you need to read depmod.c source too) in order to understand the role of various sections in vmlinux.

There are dearth of comments in ld scripts, and some sections are created "just because I felt like it". For example, there are ".data.page_aligned" and ".data.percpu" sections - can you easily tell which one has to be a section, and which does not need to be one (can be merged with ".data")? Maybe both must be sections? Or none of them?
--
vda

#4 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 33 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 18 lines · Mathieu Desnoyers
Quoted 16 lines

Index: linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================

include/asm-generic/vmlinux.lds.h +5 -0
@@ -129,6 +133,11 @@
 		VMLINUX_SYMBOL(__stop___immediate) = .;			\
 	}								\
 									\
+	/* Markers: strings */						\
+        __markers_strings : AT(ADDR(__markers_strings) - LOAD_OFFSET) {	\
+		*(__markers_strings)					\
+ 	}								\
+									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\

[...]

Quoted 1 line

Do you think I should also remove the __markers_strings section from here ?

Yes.

It will be beneficial if one can read include/asm-generic/vmlinux.lds.h and arch/$ARCH/kernel/vmlinux.lds.S and understand which sections in resulting vmlinux serve what purpose. A comment atop each section explaining its role will be nice. Even more so that not many people are fluent in ld script language.

Currently, one will need to grep around (and not only in kernel tree - you need to read depmod.c source too) in order to understand the role of various sections in vmlinux.

Quoted 8 lines

There are dearth of comments in ld scripts, and some sections are created "just because I felt like it". For example, there are ".data.page_aligned" and ".data.percpu" sections - can you easily tell which one has to be a section, and which does not need to be one (can be merged with ".data")? Maybe both must be sections? Or none of them?
--
vda

Oh, wait.. I need it in module.c:

immediateindex = find_sec(hdr, sechdrs, secstrings, "__immediate");

I'll leave the section there then.

Mathieu

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#5 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 43 lines · * Mathieu Desnoyers ([email protected]) wrote:
Quoted 33 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 18 lines · Mathieu Desnoyers
Quoted 16 lines

Index: linux-2.6-lttng/include/asm-generic/vmlinux.lds.h
===================================================================

include/asm-generic/vmlinux.lds.h +5 -0
@@ -129,6 +133,11 @@
 		VMLINUX_SYMBOL(__stop___immediate) = .;			\
 	}								\
 									\
+	/* Markers: strings */						\
+        __markers_strings : AT(ADDR(__markers_strings) - LOAD_OFFSET) {	\
+		*(__markers_strings)					\
+ 	}								\
+									\
 	/* Kernel symbol table: strings */				\
         __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) {	\
 		*(__ksymtab_strings)					\

[...]

Quoted 1 line

Do you think I should also remove the __markers_strings section from here ?

Yes.

It will be beneficial if one can read include/asm-generic/vmlinux.lds.h and arch/$ARCH/kernel/vmlinux.lds.S and understand which sections in resulting vmlinux serve what purpose. A comment atop each section explaining its role will be nice. Even more so that not many people are fluent in ld script language.

Currently, one will need to grep around (and not only in kernel tree - you need to read depmod.c source too) in order to understand the role of various sections in vmlinux.

Quoted 8 lines

There are dearth of comments in ld scripts, and some sections are created "just because I felt like it". For example, there are ".data.page_aligned" and ".data.percpu" sections - can you easily tell which one has to be a section, and which does not need to be one (can be merged with ".data")? Maybe both must be sections? Or none of them?
--
vda

Quoted 7 lines

Oh, wait.. I need it in module.c:

immediateindex = find_sec(hdr, sechdrs, secstrings, "__immediate");

I'll leave the section there then.

Mathieu

Sorry, let me take this back. It applies to what is linked in the core image, but I believe it does not apply to the kernel modules.

Mathieu

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#6 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

In reply to Mathieu Desnoyers
Quoted 2 lines · Mathieu Desnoyers

[...] Do you think I should also remove the __markers_strings section from here ?

Current systemtap marker support code relies on the __markers_strings section.

- FChE

#7 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 7 lines · Frank Ch. Eigler
Quoted 2 lines · Mathieu Desnoyers

[...] Do you think I should also remove the __markers_strings section from here ?

Current systemtap marker support code relies on the __markers_strings section.

Let users know that in comment above section definition in ld script.

Thanks!
--
vda

#8 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 11 lines · * Denys Vlasenko ([email protected]) wrote:
Quoted 7 lines · Frank Ch. Eigler
Quoted 2 lines · Mathieu Desnoyers

[...] Do you think I should also remove the __markers_strings section from here ?

Current systemtap marker support code relies on the __markers_strings section.

Let users know that in comment above section definition in ld script.

Ok, I am changing it to:

        /* Markers: strings (used by SystemTAP) */                      \
        __markers_strings : AT(ADDR(__markers_strings) - LOAD_OFFSET) { \
                *(__markers_strings)                                    \
        }                                                               \

Mathieu

Quoted 3 lines

Thanks!
--
vda

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#9 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 1 line · Mathieu Desnoyers

Ok, I am changing it to:

As I mentioned before pleae just kill this gunk entirely as it's not needed at all intree. markers are already getting far too complex, I'd rather want a simple useable version in now than trying to cater for every possible use-case. Once the systemtap people are ready for merging their stuff into the kernel tree we can cater towards their needs.

#10 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

In reply to Mathieu Desnoyers

Hi -

Quoted 7 lines · Mathieu Desnoyers

[...]

Quoted 3 lines
Quoted 2 lines

Current systemtap marker support code relies on the __markers_strings section.

Let users know that in comment above section definition in ld script.

[...]

        /* Markers: strings (used by SystemTAP) */                      \

[...]

I did not mean to imply that this was a necessary state of affairs.

The marker metadata must be stored in at least one place in the kernel image - this just happens to be a convenient one that David Smith's recent systemtap code used. Without it, we'd probably have to do a more complicated search, following the pointers within the __markers structs. That could work, but it hasn't been built/tested.

So, this proposed change (removal of this section) would break systemtap, and we have to jump through more hoops to make it work again. Is the change worth it?

- FChE

#11 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 19 lines · * Frank Ch. Eigler ([email protected]) wrote:

Hi -

Quoted 7 lines · Mathieu Desnoyers

[...]

Quoted 3 lines
Quoted 2 lines

Current systemtap marker support code relies on the __markers_strings section.

Let users know that in comment above section definition in ld script.

[...]

        /* Markers: strings (used by SystemTAP) */                      \

[...]

I did not mean to imply that this was a necessary state of affairs.

The marker metadata must be stored in at least one place in the kernel image - this just happens to be a convenient one that David Smith's recent systemtap code used. Without it, we'd probably have to do a more complicated search, following the pointers within the __markers structs. That could work, but it hasn't been built/tested.

Quoted 4 lines

So, this proposed change (removal of this section) would break systemtap, and we have to jump through more hoops to make it work again. Is the change worth it?

I guess so. Getting the markers as clean as we can is very important for kernel inclusion.

Mathieu

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#12 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Hi -

Quoted 6 lines · I wrote:

[...]

Quoted 5 lines

The marker metadata must be stored in at least one place in the kernel image - this just happens to be a convenient one that David Smith's recent systemtap code used. Without it, we'd probably have to do a more complicated search, following the pointers within the __markers structs. [...]

Our team is farther along adapting to this change against 2.6.23-mm1, and we have run into a complication. It's more of a distribution issue.

We would prefer to retain systemtap's capability to build instrumentation for a kernel other than the currently running one. Such instrumentation can be then copied and run on a distinct machine. This has meant relying on development data: make install_headers + Makefiles (as packaged by Fedora/RHEL), and to a lesser extent separated debugging information.

Markers are attractive partly because they don't require debugging information, so the data needs to be found in an executable image. But we prefer not to force the executable image itself to be installed, for example because /boot is relatively small. So we would prefer something in between: something small that we can put into the development package.

If there exists sympathy to this problem, Roland McGrath supposes we could implement a standardized solution, a file like Module.symvers, containing the marker names & format strings extracted at build time. Any opinions?

PS. I wonder why the marker name/format strings are put into a __markers_strings object section at all, considering that the only place where that is used again appears to be this code in kernel/module.c:

markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");

and the "markersstringsindex" variable is never used.

- FChE

#13 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 29 lines · * Frank Ch. Eigler ([email protected]) wrote:

Hi -

Quoted 6 lines · I wrote:

[...]

Quoted 5 lines

The marker metadata must be stored in at least one place in the kernel image - this just happens to be a convenient one that David Smith's recent systemtap code used. Without it, we'd probably have to do a more complicated search, following the pointers within the __markers structs. [...]

Our team is farther along adapting to this change against 2.6.23-mm1, and we have run into a complication. It's more of a distribution issue.

We would prefer to retain systemtap's capability to build instrumentation for a kernel other than the currently running one. Such instrumentation can be then copied and run on a distinct machine. This has meant relying on development data: make install_headers + Makefiles (as packaged by Fedora/RHEL), and to a lesser extent separated debugging information.

Markers are attractive partly because they don't require debugging information, so the data needs to be found in an executable image. But we prefer not to force the executable image itself to be installed, for example because /boot is relatively small. So we would prefer something in between: something small that we can put into the development package.

Quoted 5 lines

If there exists sympathy to this problem, Roland McGrath supposes we could implement a standardized solution, a file like Module.symvers, containing the marker names & format strings extracted at build time. Any opinions?

Hi Frank,

I think the main issue with the solution you propose is that it doesn't deal with markers in modules, am I right ?

I will soon come with a marker iterator and a module that provides a userspace -and in kernel- interface to enable/disable markers. Actually, I already have the code ready in my LTTng snapshots. I can provide a link if you want to have a look.

Quoted 11 lines

PS. I wonder why the marker name/format strings are put into a __markers_strings object section at all, considering that the only place where that is used again appears to be this code in kernel/module.c:

markersstringsindex = find_sec(hdr, sechdrs, secstrings,
"__markers_strings");

and the "markersstringsindex" variable is never used.

Considering that I want to minimize the impact on the system, I put the marker strings in their own memory location rather than clobbering the memory containing the kernel strings (which will likely be used more often than markers). It makes sure that I don't pollute cachelines otherwise containing useful kernel strings.

Mathieu

Quoted 2 lines

- FChE

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#14 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 2 lines

I think the main issue with the solution you propose is that it doesn't deal with markers in modules, am I right ?

My suggestion applies as well to modules as anything else. What "like Module.symvers" means is something like:

name1 vmlinux %s
name2 fs/nfs/nfs %d

All the modules built by the same kernel build go into this one file.

Modules packaged separately for the same kernel could provide additional files of the same kind.

Quoted 4 lines

I will soon come with a marker iterator and a module that provides a userspace -and in kernel- interface to enable/disable markers. Actually, I already have the code ready in my LTTng snapshots. I can provide a link if you want to have a look.

That's clearly straightforward to do given the basic markers data structures.

It does not address the need for an offline list of markers available in a particular kernel build or set of modules that you are not running right now. The approach now available for that is grovelling through the markers data structures extracted from vmlinux and .ko ELF files offline. That is more work than one should have to do, and has lots of problems with coping with different packaging details, etc.

Thanks,
Roland

#15 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 19 lines · * Roland McGrath ([email protected]) wrote:
Quoted 2 lines

I think the main issue with the solution you propose is that it doesn't deal with markers in modules, am I right ?

My suggestion applies as well to modules as anything else. What "like Module.symvers" means is something like:

name1 vmlinux %s
name2 fs/nfs/nfs %d

All the modules built by the same kernel build go into this one file.

Modules packaged separately for the same kernel could provide additional files of the same kind.

Quoted 4 lines

I will soon come with a marker iterator and a module that provides a userspace -and in kernel- interface to enable/disable markers. Actually, I already have the code ready in my LTTng snapshots. I can provide a link if you want to have a look.

Quoted 9 lines

That's clearly straightforward to do given the basic markers data structures.

It does not address the need for an offline list of markers available in a particular kernel build or set of modules that you are not running right now. The approach now available for that is grovelling through the markers data structures extracted from vmlinux and .ko ELF files offline. That is more work than one should have to do, and has lots of problems with coping with different packaging details, etc.

Since gcc is required to build the systemtap probes on the development marchine, I don't see why it would be much harder to also require prople to install drawf ? Or maybe the "crash" tool ?

I guess you must already need to extract the symbols for your kprobes. Do you use kallsyms for this ? The way I see it, you could maybe extract kallsyms symbols corresponding to the markers data structures quite easily.

I would rather prefer not to implement superfluous built-time data extraction in the kernel build system just to make userspace simpler. If we can leverage what currently exists, that would be better.

Mathieu

Quoted 3 lines

Thanks,
Roland

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#16 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Hi -

Quoted 4 lines · Mathieu Desnoyers

[...]
Since gcc is required to build the systemtap probes on the development marchine, I don't see why it would be much harder to also require prople to install drawf ? Or maybe the "crash" tool ?

The crash tool requires the dwarf data to work. The dwarf data for an entire kernel (including all the modules) is on the order of hundreds of megabytes. The symbol & marker list would be one thousandth the size. You can see the deployment attractiveness of the latter.

Quoted 2 lines

I guess you must already need to extract the symbols for your kprobes. Do you use kallsyms for this?

Nope. /proc/kallsyms is a another run-time-only source of data, and so is not applicable for off-line (ahead-of-time) mapping.

Quoted 3 lines

I would rather prefer not to implement superfluous built-time data extraction in the kernel build system just to make userspace simpler. [...]

It is not superfluous, as it would solve a real distribution problem.

- FChE

#17 lore raw

PATCH 1/1 markers: modpost

This adds some new magic in the MODPOST phase for CONFIG_MARKERS. Analogous to the Module.symvers file, the build will now write a Module.markers file when CONFIG_MARKERS=y is set. This file lists the name, defining module, and format string of each marker, separated by \t characters. This simple text file can be used by offline build procedures for instrumentation code, analogous to how System.map and Module.symvers can be useful to have for kernels other than the one you are running right now.

The method of extracting the strings is somewhat crude, but is very simple and should work fine in practice for the foreseeable future.

---
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  174 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 3 files changed, 187 insertions(+), 1 deletions(-)
scripts/Makefile.modpost +11 -0
index d988f5d..6321870 100644
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
scripts/mod/modpost.c +173 -1

224 lines not on this page · raw message

scripts/mod/modpost.h +3 -0
index 0ffed17..175301a 100644
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;
#18 lore raw

Re: [PATCH] markers: modpost

Quoted 10 lines · * Roland McGrath ([email protected]) wrote:

This adds some new magic in the MODPOST phase for CONFIG_MARKERS. Analogous to the Module.symvers file, the build will now write a Module.markers file when CONFIG_MARKERS=y is set. This file lists the name, defining module, and format string of each marker, separated by \t characters. This simple text file can be used by offline build procedures for instrumentation code, analogous to how System.map and Module.symvers can be useful to have for kernels other than the one you are running right now.

Quoted 3 lines

The method of extracting the strings is somewhat crude, but is very simple and should work fine in practice for the foreseeable future.

Hi Roland,

I'm ok with the idea of extracting such information, but I doubt one can assume the strings will always be layed out in the same order in the __markers_strings section. We also shouldn't assume that a marker name will be a neighbor of its format string.

If we want to do it safely, I think we should iterate from __start___markers to __stop___markers symbols of vmlinux and get the pointers to the name/format string pairs.

The same can then be done with modules using the __markers section.

Or maybe is there some reason not to do that ?

Mathieu

Quoted 307 lines
---
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  174 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 3 files changed, 187 insertions(+), 1 deletions(-)
scripts/Makefile.modpost +11 -0
index d988f5d..6321870 100644
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
scripts/mod/modpost.c +173 -1
index 93ac52a..df80bfc 100644
@@ -11,6 +11,8 @@
  * Usage: modpost vmlinux module1.o module2.o ...
  */
 
+#define _GNU_SOURCE
+#include <stdio.h>
 #include <ctype.h>
 #include "modpost.h"
 #include "../../include/linux/license.h"
@@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
 			info->export_unused_gpl_sec = i;
 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
 			info->export_gpl_future_sec = i;
+		else if (strcmp(secname, "__markers_strings") == 0)
+			info->markers_strings_sec = i;
 
 		if (sechdrs[i].sh_type != SHT_SYMTAB)
 			continue;
@@ -1249,6 +1253,73 @@ static int exit_section_ref_ok(const char *name)
 	return 0;
 }
 
+static size_t strlen_with_padding(const char *start, const char *limit)
+{
+	const char *p = memchr(start, '\0', limit - start);
+	if (p == NULL)
+		return 0;
+	do
+		++p;
+	while (p < limit && *p == '\0');
+	return p - start;
+}
+
+static void get_markers(struct elf_info *info, struct module *mod)
+{
+	const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec];
+	const char *strings;
+	const char *strings_end;
+	const char *p;
+	size_t n, i;
+
+	if (!info->markers_strings_sec)
+		return;
+
+	strings = (const char *) info->hdr + sh->sh_offset;
+	strings_end = strings + sh->sh_size;
+
+	/*
+	 * First count the strings.  They come in pairs of name, format.
+	 */
+	for (n = 0, p = strings; p < strings_end; ++n) {
+		size_t len = strlen_with_padding(p, strings_end);
+		if (len == 0)
+			break;
+		p += len;
+	}
+	if (n % 2 != 0 || p != strings_end) {
+		warn("%s.ko has bad __markers_strings, ignoring it\n",
+		     mod->name);
+		return;
+	}
+
+	if (n == 0)
+		return;
+
+	/*
+	 * Now collect each pair into a formatted line for the output.
+	 * Lines look like:
+	 *	marker_name	vmlinux	marker %s format %d
+	 * The format string after the second \t can use whitespace.
+	 */
+	mod->markers = NOFAIL(malloc(sizeof mod->markers[0] * n / 2));
+	mod->nmarkers = n / 2;
+
+	p = strings;
+	for (i = 0; i < n; i += 2) {
+		const char *name, *fmt;
+		name = p;
+		p += strlen_with_padding(p, strings_end);
+		fmt = p;
+		p += strlen_with_padding(p, strings_end);
+
+		mod->markers[i / 2] = NULL;
+		asprintf(&mod->markers[i / 2], "%s\t%s\t%s\n",
+			 name, mod->name, fmt);
+		NOFAIL(mod->markers[i / 2]);
+	}
+}
+
 static void read_symbols(char *modname)
 {
 	const char *symname;
@@ -1301,6 +1372,8 @@ static void read_symbols(char *modname)
 		get_src_version(modname, mod->srcversion,
 				sizeof(mod->srcversion)-1);
 
+	get_markers(&info, mod);
+
 	parse_elf_finish(&info);
 
 	/* Our trick to get versioning for struct_module - it's
@@ -1649,6 +1722,91 @@ static void write_dump(const char *fname)
 	write_if_changed(&buf, fname);
 }
 
+static void add_marker(struct module *mod, const char *name, const char *fmt)
+{
+	char *line = NULL;
+	asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+	NOFAIL(line);
+
+	mod->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
+						     sizeof mod->markers[0])));
+	mod->markers[mod->nmarkers++] = line;
+}
+
+static void read_markers(const char *fname)
+{
+	unsigned long size, pos = 0;
+	void *file = grab_file(fname, &size);
+	char *line;
+
+        if (!file)
+		/* No old markers, silently ignore */
+		return;
+
+	while ((line = get_next_line(&pos, file, size))) {
+		char *marker, *modname, *fmt;
+		struct module *mod;
+
+		marker = line;
+		if (!(modname = strchr(marker, '\t')))
+			goto fail;
+		*modname++ = '\0';
+		if (!(fmt = strchr(modname, '\t')))
+			goto fail;
+		*fmt++ = '\0';
+		if (*marker == '\0' || *modname == '\0')
+			goto fail;
+
+		if (!(mod = find_module(modname))) {
+			if (is_vmlinux(modname)) {
+				have_vmlinux = 1;
+			}
+			mod = new_module(NOFAIL(strdup(modname)));
+			mod->skip = 1;
+		}
+
+		add_marker(mod, marker, fmt);
+	}
+	return;
+fail:
+	fatal("parse error in markers list file\n");
+}
+
+static int compare_strings(const void *a, const void *b)
+{
+	return strcmp(*(const char **) a, *(const char **) b);
+}
+
+static void write_markers(const char *fname)
+{
+	struct buffer buf = { };
+	struct module *mod;
+	size_t i;
+
+	for (mod = modules; mod; mod = mod->next)
+		if ((!external_module || !mod->skip) && mod->markers != NULL) {
+			/*
+			 * Sort the strings so we can skip duplicates when
+			 * we write them out.
+			 */
+			qsort(mod->markers, mod->nmarkers,
+			      sizeof mod->markers[0], &compare_strings);
+			for (i = 0; i < mod->nmarkers; ++i) {
+				char *line = mod->markers[i];
+				buf_write(&buf, line, strlen(line));
+				while (i + 1 < mod->nmarkers &&
+				       !strcmp(mod->markers[i],
+					       mod->markers[i + 1]))
+					free(mod->markers[i++]);
+				free(mod->markers[i]);
+			}
+			free(mod->markers);
+			mod->markers = NULL;
+		}
+
+	write_if_changed(&buf, fname);
+}
+
 int main(int argc, char **argv)
 {
 	struct module *mod;
@@ -1656,10 +1814,12 @@ int main(int argc, char **argv)
 	char fname[SZ];
 	char *kernel_read = NULL, *module_read = NULL;
 	char *dump_write = NULL;
+	char *markers_read = NULL;
+	char *markers_write = NULL;
 	int opt;
 	int err;
 
-	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
+	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
 		switch(opt) {
 			case 'i':
 				kernel_read = optarg;
@@ -1683,6 +1843,12 @@ int main(int argc, char **argv)
 			case 'w':
 				warn_unresolved = 1;
 				break;
+			case 'M':
+				markers_write = optarg;
+				break;
+			case 'K':
+				markers_read = optarg;
+				break;
 			default:
 				exit(1);
 		}
@@ -1724,5 +1890,11 @@ int main(int argc, char **argv)
 	if (dump_write)
 		write_dump(dump_write);
 
+	if (markers_read)
+		read_markers(markers_read);
+
+	if (markers_write)
+		write_markers(markers_write);
+
 	return err;
 }
scripts/mod/modpost.h +3 -0
index 0ffed17..175301a 100644
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;
Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#19 lore raw

Re: [PATCH] markers: modpost

Quoted 7 lines

If we want to do it safely, I think we should iterate from __start___markers to __stop___markers symbols of vmlinux and get the pointers to the name/format string pairs.

The same can then be done with modules using the __markers section.

Or maybe is there some reason not to do that ?

It's just rather a pain in the ass, a whole lot more fiddly work. cf "somewhat crude" and "foreseeable future" in my patch's log entry. Knock yourself out if you're looking for more tedious hacking to do in modpost.c, but I say fix it when it breaks.

Thanks,
Roland

#20 lore raw

Re: [PATCH] markers: modpost

Quoted 4 lines · * Roland McGrath ([email protected]) wrote:
Quoted 4 lines

If we want to do it safely, I think we should iterate from __start___markers to __stop___markers symbols of vmlinux and get the pointers to the name/format string pairs.

Quoted 9 lines
Quoted 3 lines

The same can then be done with modules using the __markers section.

Or maybe is there some reason not to do that ?

It's just rather a pain in the ass, a whole lot more fiddly work. cf "somewhat crude" and "foreseeable future" in my patch's log entry. Knock yourself out if you're looking for more tedious hacking to do in modpost.c, but I say fix it when it breaks.

Hmmmm, I have rarely seen code go into mainline without addressing valid technical criticism first. Please fix.

I'll look into it if I find the time.

Mathieu

Quoted 3 lines

Thanks,
Roland

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#21 lore raw

Re: [PATCH] markers: modpost

Quoted 14 lines · Mathieu Desnoyers
Quoted 4 lines · * Roland McGrath ([email protected]) wrote:
Quoted 4 lines

If we want to do it safely, I think we should iterate from __start___markers to __stop___markers symbols of vmlinux and get the pointers to the name/format string pairs.

Quoted 8 lines
Quoted 3 lines

The same can then be done with modules using the __markers section.

Or maybe is there some reason not to do that ?

It's just rather a pain in the ass, a whole lot more fiddly work. cf "somewhat crude" and "foreseeable future" in my patch's log entry. Knock yourself out if you're looking for more tedious hacking to do in modpost.c, but I say fix it when it breaks.

Quoted 6 lines

Hmmmm, I have rarely seen code go into mainline without addressing valid technical criticism first. Please fix.

I'll look into it if I find the time.

Mathieu

Mathieu,

Here's an updated patch, written by Roland (that I tested for him), that looks for all marker symbols in the __markers_strings section. It doesn't get the pointers from the __markers section because that is very difficult to do in modpost (having to handle the architecture-dependent relocations applied to those pointers).

See what you think.

---
This adds some new magic in the MODPOST phase for CONFIG_MARKERS. Analogous to the Module.symvers file, the build will now write a Module.markers file when CONFIG_MARKERS=y is set. This file lists the name, defining module, and format string of each marker, separated by \t characters. This simple text file can be used by offline build procedures for instrumentation code, analogous to how System.map and Module.symvers can be useful to have for kernels other than the one you are running right now.

The method of extracting the strings is somewhat crude, but is pretty simple and should work fine in practice for the foreseeable future.

---
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  184 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 3 files changed, 197 insertions(+), 1 deletions(-)
scripts/Makefile.modpost +11 -0
index d988f5d..6321870 100644
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
scripts/mod/modpost.c +183 -1

234 lines not on this page · raw message

scripts/mod/modpost.h +3 -0
index 0ffed17..175301a 100644
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;
#22 lore raw

Re: [PATCH] markers: modpost

Quoted 22 lines · * David Smith ([email protected]) wrote:
Quoted 14 lines · Mathieu Desnoyers
Quoted 4 lines · * Roland McGrath ([email protected]) wrote:
Quoted 4 lines

If we want to do it safely, I think we should iterate from __start___markers to __stop___markers symbols of vmlinux and get the pointers to the name/format string pairs.

Quoted 8 lines
Quoted 3 lines

The same can then be done with modules using the __markers section.

Or maybe is there some reason not to do that ?

It's just rather a pain in the ass, a whole lot more fiddly work. cf "somewhat crude" and "foreseeable future" in my patch's log entry. Knock yourself out if you're looking for more tedious hacking to do in modpost.c, but I say fix it when it breaks.

Quoted 6 lines

Hmmmm, I have rarely seen code go into mainline without addressing valid technical criticism first. Please fix.

I'll look into it if I find the time.

Mathieu

Quoted 8 lines

Mathieu,

Here's an updated patch, written by Roland (that I tested for him), that looks for all marker symbols in the __markers_strings section. It doesn't get the pointers from the __markers section because that is very difficult to do in modpost (having to handle the architecture-dependent relocations applied to those pointers).

Hrm, what would happen if a gcc optimization eventually decides to mix the memory layout of the strings ? Is there something that specifies that they won't ?

Quoted 337 lines

See what you think.

---
This adds some new magic in the MODPOST phase for CONFIG_MARKERS. Analogous to the Module.symvers file, the build will now write a Module.markers file when CONFIG_MARKERS=y is set. This file lists the name, defining module, and format string of each marker, separated by \t characters. This simple text file can be used by offline build procedures for instrumentation code, analogous to how System.map and Module.symvers can be useful to have for kernels other than the one you are running right now.

The method of extracting the strings is somewhat crude, but is pretty simple and should work fine in practice for the foreseeable future.

---
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  184 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 3 files changed, 197 insertions(+), 1 deletions(-)
scripts/Makefile.modpost +11 -0
index d988f5d..6321870 100644
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
scripts/mod/modpost.c +183 -1
index 93ac52a..bbaf26d 100644
@@ -11,6 +11,8 @@
  * Usage: modpost vmlinux module1.o module2.o ...
  */
 
+#define _GNU_SOURCE
+#include <stdio.h>
 #include <ctype.h>
 #include "modpost.h"
 #include "../../include/linux/license.h"
@@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
 			info->export_unused_gpl_sec = i;
 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
 			info->export_gpl_future_sec = i;
+		else if (strcmp(secname, "__markers_strings") == 0)
+			info->markers_strings_sec = i;
 
 		if (sechdrs[i].sh_type != SHT_SYMTAB)
 			continue;
@@ -1249,6 +1253,83 @@ static int exit_section_ref_ok(const char *name)
 	return 0;
 }
 
+static void get_markers(struct elf_info *info, struct module *mod)
+{
+	const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec];
+	const char *strings = (const char *) info->hdr + sh->sh_offset;
+	const Elf_Sym *sym, *first_sym, *last_sym;
+	const char *name;
+	size_t n;
+
+	if (!info->markers_strings_sec)
+		return;
+
+	/*
+	 * First count the strings.  They come in pairs of name, format.
+	 * We look for all the symbols defined in the __markers_strings
+	 * section.  They are named __mstrtab_name_* and __mstrtab_format_*
+	 * in matching pairs.  For these local names, the compiler puts
+	 * a random .NNN suffix on, so the names don't correspond exactly.
+	 */
+	first_sym = last_sym = NULL;
+	n = 0;
+	for (sym = info->symtab_start; sym < info->symtab_stop; sym++)
+		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
+		    sym->st_shndx == info->markers_strings_sec) {
+			if (first_sym == NULL)
+				first_sym = sym;
+			last_sym = sym;
+			++n;
+			name = info->strtab + sym->st_name;
+			if (n % 2 == 0 ?
+			    !strncmp(name, "__mstrtab_name_",
+				     sizeof "__mstrtab_name_" - 1) :
+			    !strncmp(name, "__mstrtab_format_",
+				     sizeof "__mstrtab_format_" - 1)) {
+				warn("%s.ko has unexpected symbol \"%s\"\n",
+				     mod->name, name);
+				first_sym = NULL;
+			}
+		}
+
+	if (n % 2 != 0 || first_sym == NULL) {
+		warn("%s.ko has bad __markers_strings, ignoring it\n",
+		     mod->name);
+		return;
+	}
+
+	if (n == 0)
+		return;
+
+	/*
+	 * Now collect each pair into a formatted line for the output.
+	 * Lines look like:
+	 *	marker_name	vmlinux	marker %s format %d
+	 * The format string after the second \t can use whitespace.
+	 */
+	n /= 2;
+	mod->markers = NOFAIL(malloc(sizeof mod->markers[0] * n));
+	mod->nmarkers = n;
+
+	name = NULL;
+	n = 0;
+	for (sym = first_sym; sym <= last_sym; sym++)
+		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
+		    sym->st_shndx == info->markers_strings_sec) {
+			const char *str = strings + sym->st_value;
+			if (name == NULL)
+				name = str;
+			else {
+				char *line = NULL;
+				asprintf(&line, "%s\t%s\t%s\n",
+					 name, mod->name, str);
+				NOFAIL(line);
+				mod->markers[n++] = line;
+				name = NULL;
+			}
+		}
+}
+
 static void read_symbols(char *modname)
 {
 	const char *symname;
@@ -1301,6 +1382,8 @@ static void read_symbols(char *modname)
 		get_src_version(modname, mod->srcversion,
 				sizeof(mod->srcversion)-1);
 
+	get_markers(&info, mod);
+
 	parse_elf_finish(&info);
 
 	/* Our trick to get versioning for struct_module - it's
@@ -1649,6 +1732,91 @@ static void write_dump(const char *fname)
 	write_if_changed(&buf, fname);
 }
 
+static void add_marker(struct module *mod, const char *name, const char *fmt)
+{
+	char *line = NULL;
+	asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+	NOFAIL(line);
+
+	mod->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
+						     sizeof mod->markers[0])));
+	mod->markers[mod->nmarkers++] = line;
+}
+
+static void read_markers(const char *fname)
+{
+	unsigned long size, pos = 0;
+	void *file = grab_file(fname, &size);
+	char *line;
+
+        if (!file)
+		/* No old markers, silently ignore */
+		return;
+
+	while ((line = get_next_line(&pos, file, size))) {
+		char *marker, *modname, *fmt;
+		struct module *mod;
+
+		marker = line;
+		if (!(modname = strchr(marker, '\t')))
+			goto fail;
+		*modname++ = '\0';
+		if (!(fmt = strchr(modname, '\t')))
+			goto fail;
+		*fmt++ = '\0';
+		if (*marker == '\0' || *modname == '\0')
+			goto fail;
+
+		if (!(mod = find_module(modname))) {
+			if (is_vmlinux(modname)) {
+				have_vmlinux = 1;
+			}
+			mod = new_module(NOFAIL(strdup(modname)));
+			mod->skip = 1;
+		}
+
+		add_marker(mod, marker, fmt);
+	}
+	return;
+fail:
+	fatal("parse error in markers list file\n");
+}
+
+static int compare_strings(const void *a, const void *b)
+{
+	return strcmp(*(const char **) a, *(const char **) b);
+}
+
+static void write_markers(const char *fname)
+{
+	struct buffer buf = { };
+	struct module *mod;
+	size_t i;
+
+	for (mod = modules; mod; mod = mod->next)
+		if ((!external_module || !mod->skip) && mod->markers != NULL) {
+			/*
+			 * Sort the strings so we can skip duplicates when
+			 * we write them out.
+			 */
+			qsort(mod->markers, mod->nmarkers,
+			      sizeof mod->markers[0], &compare_strings);
+			for (i = 0; i < mod->nmarkers; ++i) {
+				char *line = mod->markers[i];
+				buf_write(&buf, line, strlen(line));
+				while (i + 1 < mod->nmarkers &&
+				       !strcmp(mod->markers[i],
+					       mod->markers[i + 1]))
+					free(mod->markers[i++]);
+				free(mod->markers[i]);
+			}
+			free(mod->markers);
+			mod->markers = NULL;
+		}
+
+	write_if_changed(&buf, fname);
+}
+
 int main(int argc, char **argv)
 {
 	struct module *mod;
@@ -1656,10 +1824,12 @@ int main(int argc, char **argv)
 	char fname[SZ];
 	char *kernel_read = NULL, *module_read = NULL;
 	char *dump_write = NULL;
+	char *markers_read = NULL;
+	char *markers_write = NULL;
 	int opt;
 	int err;
 
-	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
+	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
 		switch(opt) {
 			case 'i':
 				kernel_read = optarg;
@@ -1683,6 +1853,12 @@ int main(int argc, char **argv)
 			case 'w':
 				warn_unresolved = 1;
 				break;
+			case 'M':
+				markers_write = optarg;
+				break;
+			case 'K':
+				markers_read = optarg;
+				break;
 			default:
 				exit(1);
 		}
@@ -1724,5 +1900,11 @@ int main(int argc, char **argv)
 	if (dump_write)
 		write_dump(dump_write);
 
+	if (markers_read)
+		read_markers(markers_read);
+
+	if (markers_write)
+		write_markers(markers_write);
+
 	return err;
 }
scripts/mod/modpost.h +3 -0
index 0ffed17..175301a 100644
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;
Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#23 lore raw

Re: [PATCH] markers: modpost

Quoted 30 lines · Mathieu Desnoyers
Quoted 19 lines · * David Smith ([email protected]) wrote:
Quoted 18 lines · Mathieu Desnoyers
Quoted 4 lines · * Roland McGrath ([email protected]) wrote:
Quoted 4 lines

If we want to do it safely, I think we should iterate from __start___markers to __stop___markers symbols of vmlinux and get the pointers to the name/format string pairs.

Quoted 8 lines
Quoted 3 lines

The same can then be done with modules using the __markers section.

Or maybe is there some reason not to do that ?

It's just rather a pain in the ass, a whole lot more fiddly work. cf "somewhat crude" and "foreseeable future" in my patch's log entry. Knock yourself out if you're looking for more tedious hacking to do in modpost.c, but I say fix it when it breaks.

Hmmmm, I have rarely seen code go into mainline without addressing valid technical criticism first. Please fix.

I'll look into it if I find the time.

Quoted 9 lines
Quoted 1 line

Mathieu

Mathieu,

Here's an updated patch, written by Roland (that I tested for him), that looks for all marker symbols in the __markers_strings section. It doesn't get the pointers from the __markers section because that is very difficult to do in modpost (having to handle the architecture-dependent relocations applied to those pointers).

Quoted 3 lines

Hrm, what would happen if a gcc optimization eventually decides to mix the memory layout of the strings ? Is there something that specifies that they won't ?

I don't believe there is anything in gcc that specifies that the strings won't get mixed around. But, I believe this code is good for the foreseeable future. We could fix this code if the future breakage does happen.

Signature · 6 lines
David Smith
[email protected]
Red Hat
http://www.redhat.com
256.217.0141 (direct)
256.837.0057 (fax)
#24 lore raw

Re: [PATCH] markers: modpost

In reply to Mathieu Desnoyers
Quoted 3 lines · Mathieu Desnoyers

Hrm, what would happen if a gcc optimization eventually decides to mix the memory layout of the strings ? Is there something that specifies that they won't ?

Here's another patch that Roland wrote and I tested that attempts to solve the potential problem of string ordering by merging the name and format strings.

---
This adds some new magic in the MODPOST phase for CONFIG_MARKERS. Analogous to the Module.symvers file, the build will now write a Module.markers file when CONFIG_MARKERS=y is set. This file lists the name, defining module, and format string of each marker, separated by \t characters. This simple text file can be used by offline build procedures for instrumentation code, analogous to how System.map and Module.symvers can be useful to have for kernels other than the one you are running right now.

The strings are made easy to extract by having the __trace_mark macro define the name and format together in a single array called __mstrtab_* in the __markers_strings section. This is straightforward and reliable as long as the marker structs are always defined by this macro. It is an unreasonable amount of hairy work to extract the string pointers from the __markers section structs, which entails handling a relocation type for every machine under the sun.

---
 include/linux/marker.h   |    9 +--
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  163 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 4 files changed, 179 insertions(+), 7 deletions(-)
include/linux/marker.h +3 -6
index 5f36cf9..b978bbe 100644
@@ -51,15 +51,12 @@ struct marker {
  */
 #define __trace_mark(generic, name, call_data, format, args...)		\
 	do {								\
-		static const char __mstrtab_name_##name[]		\
+		static const char __mstrtab_##name[]			\
 		__attribute__((section("__markers_strings")))		\
-		= #name;						\
-		static const char __mstrtab_format_##name[]		\
-		__attribute__((section("__markers_strings")))		\
-		= format;						\
+ 		= #name "\0" format;					\
 		static struct marker __mark_##name			\
 		__attribute__((section("__markers"), aligned(8))) =	\
-		{ __mstrtab_name_##name, __mstrtab_format_##name,	\
+		{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)],	\
 		0, __mark_empty_function, NULL };			\
 		__mark_check_format(format, ## args);			\
 		if (!generic) {						\
scripts/Makefile.modpost +11 -0
index d988f5d..6321870 100644
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
scripts/mod/modpost.c +162 -1

213 lines not on this page · raw message

scripts/mod/modpost.h +3 -0
index 0ffed17..175301a 100644
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;
#25 lore raw

Re: [PATCH] markers: modpost

Quoted 9 lines · * David Smith ([email protected]) wrote:
Quoted 3 lines · Mathieu Desnoyers

Hrm, what would happen if a gcc optimization eventually decides to mix the memory layout of the strings ? Is there something that specifies that they won't ?

Here's another patch that Roland wrote and I tested that attempts to solve the potential problem of string ordering by merging the name and format strings.

Yup, it looks good. I'll give it a try.

Thanks!

Mathieu

Quoted 340 lines

---
This adds some new magic in the MODPOST phase for CONFIG_MARKERS. Analogous to the Module.symvers file, the build will now write a Module.markers file when CONFIG_MARKERS=y is set. This file lists the name, defining module, and format string of each marker, separated by \t characters. This simple text file can be used by offline build procedures for instrumentation code, analogous to how System.map and Module.symvers can be useful to have for kernels other than the one you are running right now.

The strings are made easy to extract by having the __trace_mark macro define the name and format together in a single array called __mstrtab_* in the __markers_strings section. This is straightforward and reliable as long as the marker structs are always defined by this macro. It is an unreasonable amount of hairy work to extract the string pointers from the __markers section structs, which entails handling a relocation type for every machine under the sun.

---
 include/linux/marker.h   |    9 +--
 scripts/Makefile.modpost |   11 +++
 scripts/mod/modpost.c    |  163 +++++++++++++++++++++++++++++++++++++++++++++-
 scripts/mod/modpost.h    |    3 +
 4 files changed, 179 insertions(+), 7 deletions(-)
include/linux/marker.h +3 -6
index 5f36cf9..b978bbe 100644
@@ -51,15 +51,12 @@ struct marker {
  */
 #define __trace_mark(generic, name, call_data, format, args...)		\
 	do {								\
-		static const char __mstrtab_name_##name[]		\
+		static const char __mstrtab_##name[]			\
 		__attribute__((section("__markers_strings")))		\
-		= #name;						\
-		static const char __mstrtab_format_##name[]		\
-		__attribute__((section("__markers_strings")))		\
-		= format;						\
+ 		= #name "\0" format;					\
 		static struct marker __mark_##name			\
 		__attribute__((section("__markers"), aligned(8))) =	\
-		{ __mstrtab_name_##name, __mstrtab_format_##name,	\
+		{ __mstrtab_##name, &__mstrtab_##name[sizeof(#name)],	\
 		0, __mark_empty_function, NULL };			\
 		__mark_check_format(format, ## args);			\
 		if (!generic) {						\
scripts/Makefile.modpost +11 -0
index d988f5d..6321870 100644
@@ -13,6 +13,7 @@
 # 2) modpost is then used to
 # 3)  create one <module>.mod.c file pr. module
 # 4)  create one Module.symvers file with CRC for all exported symbols
+# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers
 # 5) compile all <module>.mod.c files
 # 6) final link of the module to a <module.ko> file
 
@@ -45,6 +46,10 @@ include scripts/Makefile.lib
 
 kernelsymfile := $(objtree)/Module.symvers
 modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
+kernelmarkersfile := $(objtree)/Module.markers
+modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers
+
+markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile))
 
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
@@ -62,6 +67,8 @@ modpost = scripts/mod/modpost                    \
  $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
  $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
  $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
+ $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
+ $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
 
 quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
@@ -81,6 +88,10 @@ vmlinux.o: FORCE
 $(symverfile):         __modpost ;
 $(modules:.ko=.mod.c): __modpost ;
 
+ifdef CONFIG_MARKERS
+$(markersfile):	       __modpost ;
+endif
+
 
 # Step 5), compile all *.mod.c files
 
scripts/mod/modpost.c +162 -1
index 93ac52a..53887e8 100644
@@ -11,6 +11,8 @@
  * Usage: modpost vmlinux module1.o module2.o ...
  */
 
+#define _GNU_SOURCE
+#include <stdio.h>
 #include <ctype.h>
 #include "modpost.h"
 #include "../../include/linux/license.h"
@@ -424,6 +426,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
 			info->export_unused_gpl_sec = i;
 		else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
 			info->export_gpl_future_sec = i;
+		else if (strcmp(secname, "__markers_strings") == 0)
+			info->markers_strings_sec = i;
 
 		if (sechdrs[i].sh_type != SHT_SYMTAB)
 			continue;
@@ -1249,6 +1253,62 @@ static int exit_section_ref_ok(const char *name)
 	return 0;
 }
 
+static void get_markers(struct elf_info *info, struct module *mod)
+{
+	const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec];
+	const char *strings = (const char *) info->hdr + sh->sh_offset;
+	const Elf_Sym *sym, *first_sym, *last_sym;
+	size_t n;
+
+	if (!info->markers_strings_sec)
+		return;
+
+	/*
+	 * First count the strings.  We look for all the symbols defined
+	 * in the __markers_strings section named __mstrtab_*.  For
+	 * these local names, the compiler puts a random .NNN suffix on,
+	 * so the names don't correspond exactly.
+	 */
+	first_sym = last_sym = NULL;
+	n = 0;
+	for (sym = info->symtab_start; sym < info->symtab_stop; sym++)
+		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
+		    sym->st_shndx == info->markers_strings_sec &&
+		    !strncmp(info->strtab + sym->st_name,
+			     "__mstrtab_", sizeof "__mstrtab_" - 1)) {
+			if (first_sym == NULL)
+				first_sym = sym;
+			last_sym = sym;
+			++n;
+		}
+
+	if (n == 0)
+		return;
+
+	/*
+	 * Now collect each name and format into a line for the output.
+	 * Lines look like:
+	 *	marker_name	vmlinux	marker %s format %d
+	 * The format string after the second \t can use whitespace.
+	 */
+	mod->markers = NOFAIL(malloc(sizeof mod->markers[0] * n));
+	mod->nmarkers = n;
+
+	n = 0;
+	for (sym = first_sym; sym <= last_sym; sym++)
+		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT &&
+		    sym->st_shndx == info->markers_strings_sec &&
+		    !strncmp(info->strtab + sym->st_name,
+			     "__mstrtab_", sizeof "__mstrtab_" - 1)) {
+			const char *name = strings + sym->st_value;
+			const char *fmt = strchr(name, '\0') + 1;
+			char *line = NULL;
+			asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+			NOFAIL(line);
+			mod->markers[n++] = line;
+		}
+}
+
 static void read_symbols(char *modname)
 {
 	const char *symname;
@@ -1301,6 +1361,8 @@ static void read_symbols(char *modname)
 		get_src_version(modname, mod->srcversion,
 				sizeof(mod->srcversion)-1);
 
+	get_markers(&info, mod);
+
 	parse_elf_finish(&info);
 
 	/* Our trick to get versioning for struct_module - it's
@@ -1649,6 +1711,91 @@ static void write_dump(const char *fname)
 	write_if_changed(&buf, fname);
 }
 
+static void add_marker(struct module *mod, const char *name, const char *fmt)
+{
+	char *line = NULL;
+	asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+	NOFAIL(line);
+
+	mod->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
+						     sizeof mod->markers[0])));
+	mod->markers[mod->nmarkers++] = line;
+}
+
+static void read_markers(const char *fname)
+{
+	unsigned long size, pos = 0;
+	void *file = grab_file(fname, &size);
+	char *line;
+
+        if (!file)
+		/* No old markers, silently ignore */
+		return;
+
+	while ((line = get_next_line(&pos, file, size))) {
+		char *marker, *modname, *fmt;
+		struct module *mod;
+
+		marker = line;
+		if (!(modname = strchr(marker, '\t')))
+			goto fail;
+		*modname++ = '\0';
+		if (!(fmt = strchr(modname, '\t')))
+			goto fail;
+		*fmt++ = '\0';
+		if (*marker == '\0' || *modname == '\0')
+			goto fail;
+
+		if (!(mod = find_module(modname))) {
+			if (is_vmlinux(modname)) {
+				have_vmlinux = 1;
+			}
+			mod = new_module(NOFAIL(strdup(modname)));
+			mod->skip = 1;
+		}
+
+		add_marker(mod, marker, fmt);
+	}
+	return;
+fail:
+	fatal("parse error in markers list file\n");
+}
+
+static int compare_strings(const void *a, const void *b)
+{
+	return strcmp(*(const char **) a, *(const char **) b);
+}
+
+static void write_markers(const char *fname)
+{
+	struct buffer buf = { };
+	struct module *mod;
+	size_t i;
+
+	for (mod = modules; mod; mod = mod->next)
+		if ((!external_module || !mod->skip) && mod->markers != NULL) {
+			/*
+			 * Sort the strings so we can skip duplicates when
+			 * we write them out.
+			 */
+			qsort(mod->markers, mod->nmarkers,
+			      sizeof mod->markers[0], &compare_strings);
+			for (i = 0; i < mod->nmarkers; ++i) {
+				char *line = mod->markers[i];
+				buf_write(&buf, line, strlen(line));
+				while (i + 1 < mod->nmarkers &&
+				       !strcmp(mod->markers[i],
+					       mod->markers[i + 1]))
+					free(mod->markers[i++]);
+				free(mod->markers[i]);
+			}
+			free(mod->markers);
+			mod->markers = NULL;
+		}
+
+	write_if_changed(&buf, fname);
+}
+
 int main(int argc, char **argv)
 {
 	struct module *mod;
@@ -1656,10 +1803,12 @@ int main(int argc, char **argv)
 	char fname[SZ];
 	char *kernel_read = NULL, *module_read = NULL;
 	char *dump_write = NULL;
+	char *markers_read = NULL;
+	char *markers_write = NULL;
 	int opt;
 	int err;
 
-	while ((opt = getopt(argc, argv, "i:I:mso:aw")) != -1) {
+	while ((opt = getopt(argc, argv, "i:I:mso:awM:K:")) != -1) {
 		switch(opt) {
 			case 'i':
 				kernel_read = optarg;
@@ -1683,6 +1832,12 @@ int main(int argc, char **argv)
 			case 'w':
 				warn_unresolved = 1;
 				break;
+			case 'M':
+				markers_write = optarg;
+				break;
+			case 'K':
+				markers_read = optarg;
+				break;
 			default:
 				exit(1);
 		}
@@ -1724,5 +1879,11 @@ int main(int argc, char **argv)
 	if (dump_write)
 		write_dump(dump_write);
 
+	if (markers_read)
+		read_markers(markers_read);
+
+	if (markers_write)
+		write_markers(markers_write);
+
 	return err;
 }
scripts/mod/modpost.h +3 -0
index 0ffed17..175301a 100644
@@ -110,6 +110,8 @@ struct module {
 	int has_init;
 	int has_cleanup;
 	struct buffer dev_table_buf;
+	char **markers;
+	size_t nmarkers;
 	char	     srcversion[25];
 };
 
@@ -124,6 +126,7 @@ struct elf_info {
 	Elf_Section  export_gpl_sec;
 	Elf_Section  export_unused_gpl_sec;
 	Elf_Section  export_gpl_future_sec;
+	Elf_Section  markers_strings_sec;
 	const char   *strtab;
 	char	     *modinfo;
 	unsigned int modinfo_len;
Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#26 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

In reply to Mathieu Desnoyers

kernel/marker.c line 214

Quoted 8 lines · Mathieu Desnoyers
kernel/marker.c new file +8 -0
+/*
+ * Sets the probe callback corresponding to one marker.
+ */
+static int set_marker(struct marker_entry **entry,
+			struct __mark_marker *elem)
+{
+	int ret;
+	BUG_ON(strcmp((*entry)->name, elem->name) != 0);

Can you switch this at least to WARN_ON? Killing a system with X running where the user just sees a freeze is not that nice. But a nasty message in dmesg is very noticable.

-- Steve

Quoted 21 lines
kernel/marker.c new file +21 -0
+
+	if ((*entry)->format) {
+		if (strcmp((*entry)->format, elem->format) != 0) {
+			printk(KERN_NOTICE
+				"Format mismatch for probe %s "
+				"(%s), marker (%s)\n",
+				(*entry)->name,
+				(*entry)->format,
+				elem->format);
+			return -EPERM;
+		}
+	} else {
+		ret = marker_set_format(entry, elem->format);
+		if (ret)
+			return ret;
+	}
+	elem->call = (*entry)->probe;
+	elem->pdata = (*entry)->pdata;
+	_immediate_set(elem->state, 1);
+	return 0;
+}
#27 lore raw

Re: [patch 1/4] Linux Kernel Markers - Architecture Independent Code

Quoted 14 lines · * Steven Rostedt ([email protected]) wrote:

kernel/marker.c line 214

Quoted 8 lines · Mathieu Desnoyers
kernel/marker.c new file +8 -0
+/*
+ * Sets the probe callback corresponding to one marker.
+ */
+static int set_marker(struct marker_entry **entry,
+			struct __mark_marker *elem)
+{
+	int ret;
+	BUG_ON(strcmp((*entry)->name, elem->name) != 0);

Can you switch this at least to WARN_ON? Killing a system with X running where the user just sees a freeze is not that nice. But a nasty message in dmesg is very noticable.

Sure.

Quoted 23 lines

-- Steve

Quoted 21 lines
kernel/marker.c new file +21 -0
+
+	if ((*entry)->format) {
+		if (strcmp((*entry)->format, elem->format) != 0) {
+			printk(KERN_NOTICE
+				"Format mismatch for probe %s "
+				"(%s), marker (%s)\n",
+				(*entry)->name,
+				(*entry)->format,
+				elem->format);
+			return -EPERM;
+		}
+	} else {
+		ret = marker_set_format(entry, elem->format);
+		if (ret)
+			return ret;
+	}
+	elem->call = (*entry)->probe;
+	elem->pdata = (*entry)->pdata;
+	_immediate_set(elem->state, 1);
+	return 0;
+}
Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#28 lore raw

PATCH 2/4 Linux Kernel Markers - Use instrumentation kconfig menu

In reply to Mathieu Desnoyers

With the increasing complexity of today's user-space application and the wide deployment of SMP systems, the users need an increasing understanding of the behavior and performance of a system across multiple processes/different execution contexts/multiple CPUs. In applications such as large clusters (Google, IBM), video acquisition (Autodesk), embedded real-time systems (Wind River, Monta Vista, Sony) or sysadmin/programmer-type tasks (SystemTAP from Redhat), a tool that permits tracing of kernel-user space interaction becomes necessary.

Usage of such tools have been made to successfully pinpoint problems such as:
latency issues in a user-space video acquisition application, slowdown problems in large clusters due to a switch to a different filesystems with a different cache size, abnormal Linux scheduler latency (just to name a few that I have personally investigated).

The currently existing solutions does not give a system-wide overview of what
- and when - things are happening on the system. Ptracing a program works with few processes, but quickly becomes useless when it comes to keeping track of many processes.

Bugs occuring because of bad interaction of such complex systems can be very hard to find due to the fact that they occur rarely (sometimes once a week on hundreds of machines). One can therefore only hope at having the best conditions to statistically reproduce the bug while extracting information from the system. Some bugs have been successfully found at Google using their ktrace tracer only because they could enable it on production machines and therefore recreate the same context where the bug happened.

Therefore, it makes sense to offer an instrumentation set of the most relevant events occurring in the Linux that can have the smallest performance cost possible when not active while not requiring a reboot of a production system to activate. This is essentially what the markers are providing.

Since we cannot limit the growth of the Linux kernel, nor can we pre-determine each and every "interesting" instrumentation within each subsystem and driver, it is sensible to let this task to the persons who knows the best their code. Adding instrumentation should therefore be as easy as adding and maintaining a "printk" in the kernel code from the developer's point of view.

Towards a complete tracing mechanism in the Linux kernel, the markers are only one step forward. The following step is to connect probes to those markers that will record the tracing information in buffers exported to user-space, organized in timestamped "events". Probe callbacks are responsible for serializing the information passed as parameter to the markers (described by the format string) into the events. A control mechanism to activate/stop the tracing is required, as well as a daemon that maps the buffers to write them to disk or send them through the network.

Keeping track of the events also requires a centralized infrastructure : the idea is to assign a unique ID to each event so they can be later recognized in the trace. Keeping in mind that recording the complete instrumentation site name string for each event would be more that inefficient, assigning a numeric unique identifier makes sense.

Finally, support for gathering events coming from user-space, with a minimal performance impact, is very useful to see the interaction between the system's execution contexts.

The last steps are currently implemented in Linux Trace Toolkit Next Generation (LTTng).

The SystemTAP project could clearly benefit from such an infrastructure for tracing. In addition, they would be providing support for dynamic addition of kernel probes through breakpoints/jumps when possible, with the associated restrictions (accessing local variables, reentrancy, speed).

This marker infrastructure is a hook-callback mechanism. It is meant to have an impact as low as possible on the system performances when no callback (probe) is connected so markers (hooks) can be compiled into a production kernel without noticeable slowdown.

Why use the markers instead of kprobes?

The rationale behind this mechanism the following :

1 - It makes sense to have instrumentation (for tracing, profiling)
within the kernel source tree so that it can follow its evolution. Other options, such as kprobes, imply maintaining an external set of instrumentation that must be adapted to each kernel version. Although it may make sense for distributions, it is not well suited for kernel developers, since they rarely work on a major distribution image.
2 - kprobes, although being a very good attempt at providing a dynamic
hooking mechanism that has no impact when disabled, suffers from important limitations :
a - It cannot access local variables of a function at a particular
point within its body that will be consistent thorough the kernel versions without involving a lot of recurrent hair-pulling.
b - Kprobes is slow, since it involves going though a trap each time
a probe site is executed. Even though the djprobes project made a good effort to make things faster, it cannot currently instrument fully-preemptible kernels and does not solve (1), (2a) and (2c).
c - On the reentrancy side, going though a trap (thus playing with
interrupt enable/disable) and taking spinlocks are not suited to some code paths, i.e. :
kernel/lockdep.c, printk (within the lockdep_on()/lockdep_off()). It must be understood that some code paths interesting for instrumentation often present a particular reentrancy challenge.

Some more details :

The probe callback connection to its markers is done dynamically. A predicted branch (see the immediate values infrastructure) is used to skip the hook stack setup and function call when the marker is "disabled" (no probe is connected). Further optimizations can be implemented for each architecture to make this branch faster.

Instrumentation of a subsystem becomes therefore a straightforward task. One has to add instrumentation within the key locations of the kernel code in the following form :

trace_mark(subsystem_event, "%d %p", myint, myptr);

Jim Keniston <[email protected]> adds:

kprobes remains a vital foundation for SystemTap. But markers are attactive as an alternate source of trace/debug info. Here's why:

1. Markers will live in the kernel and presumably be kept up to date by the maintainers of the enclosing code. We have a growing set of tapsets (probe libraries), each of which "knows" the source code for a certain area of the kernel. Whenever the underlying kernel code changes (e.g., a function or one of its args disappears or is renamed), there's a chance that the tapset will become invalid until we bring it back in sync with the kernel. As you can imagine, maintaining tapsets separate from the kernel source is a maintenance headache. Markers could mitigate this.

2. Because the kernel code is highly optimized, the kernel's dwarf info doesn't always accurately reflect which variables have which values on which lines (sometimes even upon entry to a function). A marker is a way to ensure that values of interest are available to SystemTap at marked points.

3. Sometimes the overhead of a kprobe probepoint is too much (either in terms of time or locking) for the particular hotspot we want to probe.

In OLS2006 proceedings, vol. 1
http://www.linuxsymposium.org/2006/linuxsymposium_procv1.pdf

Frank C. Eigler, from SystemTAP, presents its "static probing markers" (pp. 261-268) in his paper "Problem Solving With Systemtap".

He explains the advantages :

"In exchange for this effort, systemtap marker-based probes are faster and
more precise than kprobes. The better precision comes from not having to covet the compiler's favours. Such fickle favours include retaining clean boundaries in the instruction stream between interesting statements, and precisely describing positions of variables in the stack frame. Since markers don't rely on debugging information, neither favour is required, and the compiler can channel its charms into unabated optimization. The speed advantage comes from using direct call instructions rather than int 3 breakpoints to dispatch to the systemtap handlers. We will see below just how big a difference this makes."

He does a comparison of his "simple" marker solution with kprobes (his simple solution looks like my generic markers, but with a major race condition). I also posted numbers about the markers performance impact a few months ago in the initial thread. I can dig into my emails to find them for you if you consider it important for the Changelog.

He concludes with :

"To the extent that is true, we propose that these groups consider using a
shared pool of static markers as the basic kernel-side instrumentation mechanism. If they prove to have as low dormant cost and as high active performance as initial experience suggests, perhaps this could motivate the various tracing efforts and kernel subsystem developers to finally join forces. Let's designate standard trace/probe points once and for all. Tracing backends can attach to these markers the same way systemtap would. There would be no need for them to maintain kernel patches any more. Let's think about it."

This patch:

Add Kconfig menus for the marker code.

[[email protected]: Never ever select MODULES]
CC Christoph Hellwig <[email protected]>
CC Adrian Bunk <[email protected]>
---
 kernel/Kconfig.instrumentation |    6 ++++++
 kernel/Makefile                |    1 +
 2 files changed, 7 insertions(+)
kernel/Kconfig.instrumentation +6 -0
Index: linux-2.6-lttng/kernel/Kconfig.instrumentation
===================================================================
@@ -37,4 +37,10 @@ config KPROBES
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
 
+config MARKERS
+	bool "Activate markers"
+	help
+	  Place an empty function call at each marker site. Can be
+	  dynamically changed for a probe function.
+
 endif # INSTRUMENTATION
kernel/Makefile +1 -0
Index: linux-2.6-lttng/kernel/Makefile
===================================================================
@@ -62,6 +62,7 @@ obj-$(CONFIG_TASK_DELAY_ACCT) += delayac
 obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
 obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o
 obj-$(CONFIG_IMMEDIATE) += immediate.o
+obj-$(CONFIG_MARKERS) += marker.o
 
 ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
 # According to Alan Modra <[email protected]>, the -fno-omit-frame-pointer is
Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#29 lore raw

PATCH 3/4 Linux Kernel Markers - Documentation

In reply to Mathieu Desnoyers

Here is some documentation explaining what is/how to use the Linux Kernel Markers.

---

 Documentation/markers/markers.txt          |   93 +++++++++++++++++++++++++++
 Documentation/markers/src/Makefile         |    7 ++
 Documentation/markers/src/marker-example.c |   55 ++++++++++++++++
 Documentation/markers/src/probe-example.c  |   98 +++++++++++++++++++++++++++++
 4 files changed, 253 insertions(+)
Documentation/markers/markers.txt new file +93 -0
Index: linux-2.6-lttng/Documentation/markers/markers.txt
===================================================================
@@ -0,0 +1,93 @@
+ 	             Using the Linux Kernel Markers
+
+			    Mathieu Desnoyers
+
+
+This document introduces Linux Kernel Markers and their use. It provides
+examples of how to insert markers in the kernel and connect probe functions to
+them and provides some examples of probe functions.
+
+
+* Purpose of markers
+
+A marker placed in code provides a hook to call a function (probe) that you can
+provide at runtime. A marker can be "on" (a probe is connected to it) or "off"
+(no probe is attached). When a marker is "off" it has no effect, except for
+adding a tiny time penalty (checking a condition for a branch) and space
+penalty (adding a few bytes for the function call at the end of the
+instrumented function and adds a data structure in a separate section). The
+immediate values are used to minimize the impact on data cache, encoding the
+condition in the instruction stream. When a marker is "on", the function you
+provide is called each time the marker is executed, in the execution context of
+the caller. When the function provided ends its execution, it returns to the
+caller (continuing from the marker site).
+
+You can put markers at important locations in the code. Markers are
+lightweight hooks that can pass an arbitrary number of parameters,
+described in a printk-like format string, to the attached probe function.
+
+They can be used for tracing and performance accounting.
+
+
+* Usage
+
+In order to use the macro trace_mark, you should include linux/marker.h.
+
+#include <linux/marker.h>
+
+And,
+
+trace_mark(subsystem_event, "%d %s", someint, somestring);
+Where :
+- subsystem_event is an identifier unique to your event
+    - subsystem is the name of your subsystem.
+    - event is the name of the event to mark.
+- "%d %s" is the formatted string for the serializer.
+- someint is an integer.
+- somestring is a char pointer.
+
+Connecting a function (probe) to a marker is done by providing a probe (function
+to call) for the specific marker through marker_probe_register() and can be
+activated by calling marker_arm(). Marker deactivation can be done by calling
+marker_disarm() as many times as marker_arm() has been called. Removing a probe
+is done through marker_probe_unregister(); it will disarm the probe and make
+sure there is no caller left using the probe when it returns. Probe removal is
+preempt-safe because preemption is disabled around the probe call. See the
+"Probe example" section below for a sample probe module.
+
+The marker mechanism supports inserting multiple instances of the same marker.
+Markers can be put in inline functions, inlined static functions, and
+unrolled loops.
+
+The naming scheme "subsystem_event" is suggested here as a convention intended
+to limit collisions. Marker names are global to the kernel: they are considered
+as being the same whether they are in the core kernel image or in modules.
+Conflicting format strings for markers with the same name will cause the markers
+to be detected to have a different format string not to be armed and will output
+a printk warning which identifies the inconsistency:
+
+"Format mismatch for probe probe_name (format), marker (format)"
+
+
+* Optimization for a given architecture
+
+One can implement optimized markers for a given architecture by replacing
+asm-$ARCH/marker.h.
+
+To force use of a non-optimized version of the markers, _trace_mark() should be
+used. It takes the same parameters as the normal markers, but it does not use
+the immediate values based on code patching.
+
+
+* Probe / marker example
+
+See the example provided in Documentation/markers/markers/src
+
+Run, as root :
+
+make
+insmod marker-example.ko (insmod order is not important)
+insmod probe-example.ko
+cat /proc/marker-example (returns an expected error)
+rmmod marker-example probe-example
+dmesg
Documentation/markers/src/Makefile new file +7 -0
Index: linux-2.6-lttng/Documentation/markers/src/Makefile
===================================================================
@@ -0,0 +1,7 @@
+obj-m := probe-example.o marker-example.o
+KDIR := /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+default:
+	$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+clean:
+	rm -f *.mod.c *.ko *.o
Documentation/markers/src/marker-example.c new file +55 -0

55 lines not on this page · raw message

Documentation/markers/src/probe-example.c new file +98 -0

98 lines not on this page · raw message

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#30 lore raw

Re: [patch 3/4] Linux Kernel Markers - Documentation

Quoted 16 lines · On Tue, 18 Sep 2007 17:13:27 -0400 Mathieu Desnoyers wrote:

Here is some documentation explaining what is/how to use the Linux Kernel Markers.

---

 Documentation/markers/markers.txt          |   93 +++++++++++++++++++++++++++
 Documentation/markers/src/Makefile         |    7 ++
 Documentation/markers/src/marker-example.c |   55 ++++++++++++++++
 Documentation/markers/src/probe-example.c  |   98 +++++++++++++++++++++++++++++
 4 files changed, 253 insertions(+)

Index: linux-2.6-lttng/Documentation/markers/markers.txt
===================================================================

Documentation/markers/markers.txt line 60

Quoted 4 lines
Documentation/markers/markers.txt new file +3 -0
@@ -0,0 +1,93 @@
 
+The marker mechanism supports inserting multiple instances of the same marker.
+Markers can be put in inline functions, inlined static functions, and
+unrolled loops.

as well as regular functions ?

Documentation/markers/markers.txt line 84

Quoted 3 lines
Documentation/markers/markers.txt new file +3 -0
+* Probe / marker example
+
+See the example provided in Documentation/markers/markers/src

drop one of ^^^ "markers/"

Documentation/markers/markers.txt line 93

Quoted 8 lines
Documentation/markers/markers.txt new file +8 -0
+Run, as root :
+
+make
+insmod marker-example.ko (insmod order is not important)
+insmod probe-example.ko
+cat /proc/marker-example (returns an expected error)
+rmmod marker-example probe-example
+dmesg

---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

#31 lore raw

Re: [patch 3/4] Linux Kernel Markers - Documentation

Quoted 19 lines · * Randy Dunlap ([email protected]) wrote:
Quoted 16 lines · On Tue, 18 Sep 2007 17:13:27 -0400 Mathieu Desnoyers wrote:

Here is some documentation explaining what is/how to use the Linux Kernel Markers.

---

 Documentation/markers/markers.txt          |   93 +++++++++++++++++++++++++++
 Documentation/markers/src/Makefile         |    7 ++
 Documentation/markers/src/marker-example.c |   55 ++++++++++++++++
 Documentation/markers/src/probe-example.c  |   98 +++++++++++++++++++++++++++++
 4 files changed, 253 insertions(+)

Index: linux-2.6-lttng/Documentation/markers/markers.txt
===================================================================

Documentation/markers/markers.txt new file +0 -0
@@ -0,0 +1,93 @@
Quoted 6 lines

Documentation/markers/markers.txt line 60

Quoted 3 lines
Documentation/markers/markers.txt new file +3 -0
+The marker mechanism supports inserting multiple instances of the same marker.
+Markers can be put in inline functions, inlined static functions, and
+unrolled loops.

as well as regular functions ?

Oh, yes, forgot the trivial case ;)

Quoted 6 lines

Documentation/markers/markers.txt line 84

Quoted 3 lines
Documentation/markers/markers.txt new file +3 -0
+* Probe / marker example
+
+See the example provided in Documentation/markers/markers/src

drop one of ^^^ "markers/"

Ok.

Will fix, thanks!

Mathieu

Quoted 13 lines

Documentation/markers/markers.txt line 93

Quoted 8 lines
Documentation/markers/markers.txt new file +8 -0
+Run, as root :
+
+make
+insmod marker-example.ko (insmod order is not important)
+insmod probe-example.ko
+cat /proc/marker-example (returns an expected error)
+rmmod marker-example probe-example
+dmesg

---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#32 lore raw

PATCH 4/4 Port of blktrace to the Linux Kernel Markers.

In reply to Mathieu Desnoyers

Here is the first stage of a port of blktrace to the Linux Kernel Markers. The advantage of this port is that it minimizes the impact on the running when blktrace is not active.

A few remarks : this patch has the positive effect of removing some code from the block io tracing hot paths, minimizing the i-cache impact in a system where the io tracing is compiled in but inactive.

It also moves the blk tracing code from a header (and therefore from the body of the instrumented functions) to a separate C file.

There, as soon as one device has to be traced, all devices have to execute the tracing function call when they pass by the instrumentation site. This is slower than the previous inline function which tested the condition quickly.

It does not make the code smaller, since I left all the specialized tracing functions for requests, bio, generic, remap, which would go away once a generic infrastructure is in place to serialize the information passed to the marker. This is mostly why I consider it as a step towards the full improvements that could bring the markers.

---

 block/Kconfig                |    1 
 block/blktrace.c             |  343 ++++++++++++++++++++++++++++++++++++++++++-
 block/elevator.c             |    6 
 block/ll_rw_blk.c            |   35 ++--
 drivers/block/cciss.c        |    4 
 drivers/md/dm.c              |   14 -
 fs/bio.c                     |    6 
 include/linux/blktrace_api.h |  145 +-----------------
 mm/bounce.c                  |    4 
 mm/highmem.c                 |    2 
 10 files changed, 388 insertions(+), 172 deletions(-)
block/elevator.c +3 -3
Index: linux-2.6-lttng/block/elevator.c
===================================================================
@@ -32,7 +32,7 @@
 #include <linux/init.h>
 #include <linux/compiler.h>
 #include <linux/delay.h>
-#include <linux/blktrace_api.h>
+#include <linux/marker.h>
 #include <linux/hash.h>
 
 #include <asm/uaccess.h>
@@ -548,7 +548,7 @@ void elv_insert(struct request_queue *q,
 	unsigned ordseq;
 	int unplug_it = 1;
 
-	blk_add_trace_rq(q, rq, BLK_TA_INSERT);
+	trace_mark(blk_request_insert, "%p %p", q, rq);
 
 	rq->q = q;
 
@@ -735,7 +735,7 @@ struct request *elv_next_request(struct 
 			 * not be passed by new incoming requests
 			 */
 			rq->cmd_flags |= REQ_STARTED;
-			blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
+			trace_mark(blk_request_issue, "%p %p", q, rq);
 		}
 
 		if (!q->boundary_rq || q->boundary_rq == rq) {
block/ll_rw_blk.c +19 -16
Index: linux-2.6-lttng/block/ll_rw_blk.c
===================================================================
@@ -28,6 +28,7 @@
 #include <linux/task_io_accounting_ops.h>
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
+#include <linux/marker.h>
 #include <linux/blktrace_api.h>
 #include <linux/fault-inject.h>
 #include <linux/scatterlist.h>
@@ -1570,7 +1571,7 @@ void blk_plug_device(struct request_queu
 
 	if (!test_and_set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) {
 		mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);
-		blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG);
+		trace_mark(blk_plug_device, "%p %p %d", q, NULL, 0);
 	}
 }
 
@@ -1636,7 +1637,7 @@ static void blk_backing_dev_unplug(struc
 	 * devices don't necessarily have an ->unplug_fn defined
 	 */
 	if (q->unplug_fn) {
-		blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL,
+		trace_mark(blk_pdu_unplug_io, "%p %p %d", q, NULL,
 					q->rq.count[READ] + q->rq.count[WRITE]);
 
 		q->unplug_fn(q);
@@ -1648,7 +1649,7 @@ static void blk_unplug_work(struct work_
 	struct request_queue *q =
 		container_of(work, struct request_queue, unplug_work);
 
-	blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL,
+	trace_mark(blk_pdu_unplug_io, "%p %p %d", q, NULL,
 				q->rq.count[READ] + q->rq.count[WRITE]);
 
 	q->unplug_fn(q);
@@ -1658,7 +1659,7 @@ static void blk_unplug_timeout(unsigned 
 {
 	struct request_queue *q = (struct request_queue *)data;
 
-	blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_TIMER, NULL,
+	trace_mark(blk_pdu_unplug_timer, "%p %p %d", q, NULL,
 				q->rq.count[READ] + q->rq.count[WRITE]);
 
 	kblockd_schedule_work(&q->unplug_work);
@@ -2178,7 +2179,7 @@ rq_starved:
 	
 	rq_init(q, rq);
 
-	blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
+	trace_mark(blk_get_request, "%p %p %d", q, bio, rw);
 out:
 	return rq;
 }
@@ -2208,7 +2209,7 @@ static struct request *get_request_wait(
 		if (!rq) {
 			struct io_context *ioc;
 
-			blk_add_trace_generic(q, bio, rw, BLK_TA_SLEEPRQ);
+			trace_mark(blk_sleep_request, "%p %p %d", q, bio, rw);
 
 			__generic_unplug_device(q);
 			spin_unlock_irq(q->queue_lock);
@@ -2282,7 +2283,7 @@ EXPORT_SYMBOL(blk_start_queueing);
  */
 void blk_requeue_request(struct request_queue *q, struct request *rq)
 {
-	blk_add_trace_rq(q, rq, BLK_TA_REQUEUE);
+	trace_mark(blk_requeue, "%p %p", q, rq);
 
 	if (blk_rq_tagged(rq))
 		blk_queue_end_tag(q, rq);
@@ -3005,7 +3006,7 @@ static int __make_request(struct request
 			if (!ll_back_merge_fn(q, req, bio))
 				break;
 
-			blk_add_trace_bio(q, bio, BLK_TA_BACKMERGE);
+			trace_mark(blk_bio_backmerge, "%p %p", q, bio);
 
 			req->biotail->bi_next = bio;
 			req->biotail = bio;
@@ -3022,7 +3023,7 @@ static int __make_request(struct request
 			if (!ll_front_merge_fn(q, req, bio))
 				break;
 
-			blk_add_trace_bio(q, bio, BLK_TA_FRONTMERGE);
+			trace_mark(blk_bio_frontmerge, "%p %p", q, bio);
 
 			bio->bi_next = req->bio;
 			req->bio = bio;
@@ -3105,9 +3106,10 @@ static inline void blk_partition_remap(s
 		bio->bi_sector += p->start_sect;
 		bio->bi_bdev = bdev->bd_contains;
 
-		blk_add_trace_remap(bdev_get_queue(bio->bi_bdev), bio,
-				    bdev->bd_dev, bio->bi_sector,
-				    bio->bi_sector - p->start_sect);
+		trace_mark(blk_remap, "%p %p %llu %llu %llu",
+				    bdev_get_queue(bio->bi_bdev), bio,
+				    (u64)bdev->bd_dev, (u64)bio->bi_sector,
+				    (u64)bio->bi_sector - p->start_sect);
 	}
 }
 
@@ -3272,10 +3274,11 @@ end_io:
 		blk_partition_remap(bio);
 
 		if (old_sector != -1)
-			blk_add_trace_remap(q, bio, old_dev, bio->bi_sector,
-					    old_sector);
+			trace_mark(blk_remap, "%p %p %llu %llu %llu",
+				q, bio, (u64)old_dev,
+				(u64)bio->bi_sector, (u64)old_sector);
 
-		blk_add_trace_bio(q, bio, BLK_TA_QUEUE);
+		trace_mark(blk_bio_queue, "%p %p", q, bio);
 
 		old_sector = bio->bi_sector;
 		old_dev = bio->bi_bdev->bd_dev;
@@ -3464,7 +3467,7 @@ static int __end_that_request_first(stru
 	int total_bytes, bio_nbytes, error, next_idx = 0;
 	struct bio *bio;
 
-	blk_add_trace_rq(req->q, req, BLK_TA_COMPLETE);
+	trace_mark(blk_request_complete, "%p %p", req->q, req);
 
 	/*
 	 * extend uptodate bool to allow < 0 value to be direct io error
block/Kconfig +1 -0
Index: linux-2.6-lttng/block/Kconfig
===================================================================
@@ -32,6 +32,7 @@ config BLK_DEV_IO_TRACE
 	depends on SYSFS
 	select RELAY
 	select DEBUG_FS
+	select MARKERS
 	help
 	  Say Y here, if you want to be able to trace the block layer actions
 	  on a given queue. Tracing allows you to see any traffic happening
block/blktrace.c +341 -2

380 lines not on this page · raw message

include/linux/blktrace_api.h +9 -136

165 lines not on this page · raw message

mm/bounce.c +2 -2
Index: linux-2.6-lttng/mm/bounce.c
===================================================================
@@ -13,7 +13,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
-#include <linux/blktrace_api.h>
+#include <linux/marker.h>
 #include <asm/tlbflush.h>
 
 #define POOL_SIZE	64
@@ -237,7 +237,7 @@ static void __blk_queue_bounce(struct re
 	if (!bio)
 		return;
 
-	blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
+	trace_mark(blk_bio_bounce, "%p %p", q, *bio_orig);
 
 	/*
 	 * at least one page was bounced, fill in possible non-highmem
mm/highmem.c +1 -1
Index: linux-2.6-lttng/mm/highmem.c
===================================================================
@@ -26,7 +26,7 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
-#include <linux/blktrace_api.h>
+#include <linux/marker.h>
 #include <asm/tlbflush.h>
 
 /*
fs/bio.c +3 -3
Index: linux-2.6-lttng/fs/bio.c
===================================================================
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
-#include <linux/blktrace_api.h>
+#include <linux/marker.h>
 #include <scsi/sg.h>		/* for struct sg_iovec */
 
 #define BIO_POOL_SIZE 2
@@ -1072,8 +1072,8 @@ struct bio_pair *bio_split(struct bio *b
 	if (!bp)
 		return bp;
 
-	blk_add_trace_pdu_int(bdev_get_queue(bi->bi_bdev), BLK_TA_SPLIT, bi,
-				bi->bi_sector + first_sectors);
+	trace_mark(blk_pdu_split, "%p %p %llu", bdev_get_queue(bi->bi_bdev), bi,
+				(u64)bi->bi_sector + first_sectors);
 
 	BUG_ON(bi->bi_vcnt != 1);
 	BUG_ON(bi->bi_idx != 0);
drivers/block/cciss.c +2 -2
Index: linux-2.6-lttng/drivers/block/cciss.c
===================================================================
@@ -37,7 +37,7 @@
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
 #include <linux/compat.h>
-#include <linux/blktrace_api.h>
+#include <linux/marker.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
@@ -2545,7 +2545,7 @@ after_error_processing:
 	}
 	cmd->rq->data_len = 0;
 	cmd->rq->completion_data = cmd;
-	blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
+	trace_mark(blk_request_complete, "%p %p", cmd->rq->q, cmd->rq);
 	blk_complete_request(cmd->rq);
 }
 
drivers/md/dm.c +7 -7
Index: linux-2.6-lttng/drivers/md/dm.c
===================================================================
@@ -19,7 +19,7 @@
 #include <linux/slab.h>
 #include <linux/idr.h>
 #include <linux/hdreg.h>
-#include <linux/blktrace_api.h>
+#include <linux/marker.h>
 #include <linux/smp_lock.h>
 
 #define DM_MSG_PREFIX "core"
@@ -481,8 +481,8 @@ static void dec_pending(struct dm_io *io
 			wake_up(&io->md->wait);
 
 		if (io->error != DM_ENDIO_REQUEUE) {
-			blk_add_trace_bio(io->md->queue, io->bio,
-					  BLK_TA_COMPLETE);
+			trace_mark(blk_request_complete, "%p %p",
+				io->md->queue, io->bio);
 
 			bio_endio(io->bio, io->bio->bi_size, io->error);
 		}
@@ -578,10 +578,10 @@ static void __map_bio(struct dm_target *
 	r = ti->type->map(ti, clone, &tio->info);
 	if (r == DM_MAPIO_REMAPPED) {
 		/* the bio has been remapped so dispatch it */
-
-		blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
-				    tio->io->bio->bi_bdev->bd_dev,
-				    clone->bi_sector, sector);
+		trace_mark(blk_remap, "%p %p %llu %llu %llu",
+			bdev_get_queue(clone->bi_bdev), clone,
+			(u64)tio->io->bio->bi_bdev->bd_dev, (u64)sector,
+			(u64)clone->bi_sector);
 
 		generic_make_request(clone);
 	} else if (r < 0 || r == DM_MAPIO_REQUEUE) {
Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68
#33 lore raw

Re: [patch 4/4] Port of blktrace to the Linux Kernel Markers.

block/blktrace.c static void blk_trace_set_ht_offsets(voi · line 889

Quoted 11 lines · Mathieu Desnoyers
block/blktrace.c +11 -0
+void blk_probe_disarm(void)
+{
+	int i, err;
+
+	for (i = 0; i < ARRAY_SIZE(probe_array); i++) {
+		err = marker_disarm(probe_array[i].name);
+		BUG_ON(err);
+		err = IS_ERR(marker_probe_unregister(probe_array[i].name));
+		BUG_ON(err);
+	}
+}

As well as changing these to WARN_ON.

-- Steve

#34 lore raw

Re: [patch 4/4] Port of blktrace to the Linux Kernel Markers.

Quoted 15 lines · * Steven Rostedt ([email protected]) wrote:

block/blktrace.c static void blk_trace_set_ht_offsets(voi · line 889

Quoted 11 lines · Mathieu Desnoyers
block/blktrace.c +11 -0
+void blk_probe_disarm(void)
+{
+	int i, err;
+
+	for (i = 0; i < ARRAY_SIZE(probe_array); i++) {
+		err = marker_disarm(probe_array[i].name);
+		BUG_ON(err);
+		err = IS_ERR(marker_probe_unregister(probe_array[i].name));
+		BUG_ON(err);
+	}
+}

As well as changing these to WARN_ON.

Yep.

Quoted 2 lines

-- Steve

Signature · 3 lines
Mathieu Desnoyers
Computer Engineering Ph.D. Student, Ecole Polytechnique de Montreal
OpenPGP key fingerprint: 8CD5 52C3 8E3C 4140 715F  BA06 3F25 A8FE 3BAE 9A68