From 3a523f5b6b4f8ca82412cb45f2d2ad9c44e7d249 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sun, 2 Sep 2012 12:33:09 -0700 Subject: [PATCH] Support for linux kernels 2.6.32 through 2.6.37 Signed-off-by: Mathieu Desnoyers --- .gitignore | 1 - Makefile | 2 +- README | 19 +- instrumentation/events/lttng-module/irq.h | 65 +++ instrumentation/events/lttng-module/sched.h | 36 ++ instrumentation/events/lttng-module/timer.h | 3 + .../backport-kallsym-sym-2.6.32.patch | 37 ++ .../backport-splice-sym-2.6.32-34.patch | 71 +++ .../backport-tp-2.6.34-tracepoint-data.patch | 545 ++++++++++++++++++ .../backport-tracepoint-data-2.6.32-33.patch | 541 +++++++++++++++++ lttng-events.c | 5 +- lttng-events.h | 3 +- lttng-statedump-impl.c | 5 +- lttng-syscalls.c | 21 +- probes/Makefile | 7 +- probes/define_trace.h | 1 - probes/lttng-probe-irq.c | 1 + probes/lttng-probe-sched.c | 1 + probes/lttng-probe-timer.c | 2 + wrapper/perf.h | 26 +- wrapper/spinlock.h | 7 + wrapper/tracepoint.h | 44 ++ 22 files changed, 1417 insertions(+), 26 deletions(-) create mode 100644 linux-patches/backport-kallsym-sym-2.6.32.patch create mode 100644 linux-patches/backport-splice-sym-2.6.32-34.patch create mode 100644 linux-patches/backport-tp-2.6.34-tracepoint-data.patch create mode 100644 linux-patches/backport-tracepoint-data-2.6.32-33.patch create mode 100644 wrapper/tracepoint.h diff --git a/.gitignore b/.gitignore index 8faa6c02..7a1e643c 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,6 @@ modules.builtin *.bz2 *.lzma *.lzo -*.patch *.gcno # diff --git a/Makefile b/Makefile index d4b09bbe..4cc8b6bf 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ endif ifneq ($(CONFIG_PERF_EVENTS),) lttng-tracer-objs += $(shell \ if [ $(VERSION) -ge 3 \ - -o \( $(VERSION) -eq 2 -a $(PATCHLEVEL) -ge 6 -a $(SUBLEVEL) -ge 33 \) ] ; then \ + -o \( $(VERSION) -eq 2 -a $(PATCHLEVEL) -ge 6 -a $(SUBLEVEL) -ge 34 \) ] ; then \ echo "lttng-context-perf-counters.o" ; fi;) endif diff --git a/README b/README index 30f13386..1bcd5b2d 100644 --- a/README +++ b/README @@ -38,15 +38,16 @@ http://lttng.org/lttng2.0 So far, it has been tested on vanilla Linux kernels 2.6.38, 2.6.39, 3.0, 3.1, 3.2, 3.3 (on x86 32/64-bit, and powerpc 32-bit at the moment, build -tested on ARM). It should work fine with newer kernels and other -architectures, but expect build issues with kernels older than 2.6.36. -The clock source currently used is the standard gettimeofday (slower, -less scalable and less precise than the LTTng 0.x clocks). Support for -LTTng 0.x clocks will be added back soon into LTTng 2.0. Please note -that lttng-modules 2.0 can build on a Linux kernel patched with the -LTTng 0.x patchset, but the lttng-modules 2.0 replace the lttng-modules -0.x, so both tracers cannot be installed at the same time for a given -kernel version. +tested on ARM). Kernels 2.6.32 to 2.6.34 need up to 3 patches applied +(refer to linux-patches within the lttng-modules tree). It should work +fine with newer kernels and other architectures, but expect build issues +with kernels older than 2.6.36. The clock source currently used is the +standard gettimeofday (slower, less scalable and less precise than the +LTTng 0.x clocks). Support for LTTng 0.x clocks will be added back soon +into LTTng 2.0. Please note that lttng-modules 2.0 can build on a Linux +kernel patched with the LTTng 0.x patchset, but the lttng-modules 2.0 +replace the lttng-modules 0.x, so both tracers cannot be installed at +the same time for a given kernel version. * Kernel config options required diff --git a/instrumentation/events/lttng-module/irq.h b/instrumentation/events/lttng-module/irq.h index 344015d4..e766326d 100644 --- a/instrumentation/events/lttng-module/irq.h +++ b/instrumentation/events/lttng-module/irq.h @@ -89,6 +89,7 @@ TRACE_EVENT(irq_handler_exit, __entry->irq, __entry->ret ? "handled" : "unhandled") ) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) DECLARE_EVENT_CLASS(softirq, TP_PROTO(unsigned int vec_nr), @@ -148,6 +149,70 @@ DEFINE_EVENT(softirq, softirq_raise, TP_ARGS(vec_nr) ) +#else /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) */ +DECLARE_EVENT_CLASS(softirq, + + TP_PROTO(struct softirq_action *h, struct softirq_action *vec), + + TP_ARGS(h, vec), + + TP_STRUCT__entry( + __field( unsigned int, vec ) + ), + + TP_fast_assign( + tp_assign(vec, (int)(h - vec)) + ), + + TP_printk("vec=%u [action=%s]", __entry->vec, + show_softirq_name(__entry->vec)) +) + +/** + * softirq_entry - called immediately before the softirq handler + * @h: pointer to struct softirq_action + * @vec: pointer to first struct softirq_action in softirq_vec array + * + * When used in combination with the softirq_exit tracepoint + * we can determine the softirq handler runtine. + */ +DEFINE_EVENT(softirq, softirq_entry, + + TP_PROTO(struct softirq_action *h, struct softirq_action *vec), + + TP_ARGS(h, vec) +) + +/** + * softirq_exit - called immediately after the softirq handler returns + * @h: pointer to struct softirq_action + * @vec: pointer to first struct softirq_action in softirq_vec array + * + * When used in combination with the softirq_entry tracepoint + * we can determine the softirq handler runtine. + */ +DEFINE_EVENT(softirq, softirq_exit, + + TP_PROTO(struct softirq_action *h, struct softirq_action *vec), + + TP_ARGS(h, vec) +) + +/** + * softirq_raise - called immediately when a softirq is raised + * @h: pointer to struct softirq_action + * @vec: pointer to first struct softirq_action in softirq_vec array + * + * When used in combination with the softirq_entry tracepoint + * we can determine the softirq raise to run latency. + */ +DEFINE_EVENT(softirq, softirq_raise, + + TP_PROTO(struct softirq_action *h, struct softirq_action *vec), + + TP_ARGS(h, vec) +) +#endif /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) */ #endif /* _TRACE_IRQ_H */ diff --git a/instrumentation/events/lttng-module/sched.h b/instrumentation/events/lttng-module/sched.h index 33f69213..b68616e0 100644 --- a/instrumentation/events/lttng-module/sched.h +++ b/instrumentation/events/lttng-module/sched.h @@ -74,9 +74,15 @@ TRACE_EVENT(sched_kthread_stop_ret, */ DECLARE_EVENT_CLASS(sched_wakeup_template, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) TP_PROTO(struct task_struct *p, int success), TP_ARGS(p, success), +#else + TP_PROTO(struct rq *rq, struct task_struct *p, int success), + + TP_ARGS(rq, p, success), +#endif TP_STRUCT__entry( __array_text( char, comm, TASK_COMM_LEN ) @@ -99,6 +105,8 @@ DECLARE_EVENT_CLASS(sched_wakeup_template, __entry->success, __entry->target_cpu) ) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) + DEFINE_EVENT(sched_wakeup_template, sched_wakeup, TP_PROTO(struct task_struct *p, int success), TP_ARGS(p, success)) @@ -110,15 +118,37 @@ DEFINE_EVENT(sched_wakeup_template, sched_wakeup_new, TP_PROTO(struct task_struct *p, int success), TP_ARGS(p, success)) +#else /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) */ + +DEFINE_EVENT(sched_wakeup_template, sched_wakeup, + TP_PROTO(struct rq *rq, struct task_struct *p, int success), + TP_ARGS(rq, p, success)) + +/* + * Tracepoint for waking up a new task: + */ +DEFINE_EVENT(sched_wakeup_template, sched_wakeup_new, + TP_PROTO(struct rq *rq, struct task_struct *p, int success), + TP_ARGS(rq, p, success)) + +#endif /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) */ + /* * Tracepoint for task switches, performed by the scheduler: */ TRACE_EVENT(sched_switch, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) TP_PROTO(struct task_struct *prev, struct task_struct *next), TP_ARGS(prev, next), +#else /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) */ + TP_PROTO(struct rq *rq, struct task_struct *prev, + struct task_struct *next), + + TP_ARGS(rq, prev, next), +#endif /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) */ TP_STRUCT__entry( __array_text( char, prev_comm, TASK_COMM_LEN ) @@ -220,9 +250,15 @@ DEFINE_EVENT(sched_process_template, sched_process_exit, /* * Tracepoint for waiting on task to unschedule: */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) DEFINE_EVENT(sched_process_template, sched_wait_task, TP_PROTO(struct task_struct *p), TP_ARGS(p)) +#else /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) */ +DEFINE_EVENT(sched_process_template, sched_wait_task, + TP_PROTO(struct rq *rq, struct task_struct *p), + TP_ARGS(rq, p)) +#endif /* #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) */ /* * Tracepoint for a waiting task: diff --git a/instrumentation/events/lttng-module/timer.h b/instrumentation/events/lttng-module/timer.h index fa89f663..dd27838e 100644 --- a/instrumentation/events/lttng-module/timer.h +++ b/instrumentation/events/lttng-module/timer.h @@ -10,6 +10,9 @@ #define _TRACE_TIMER_DEF_ #include #include + +struct timer_list; + #endif /* _TRACE_TIMER_DEF_ */ DECLARE_EVENT_CLASS(timer_class, diff --git a/linux-patches/backport-kallsym-sym-2.6.32.patch b/linux-patches/backport-kallsym-sym-2.6.32.patch new file mode 100644 index 00000000..2e72124a --- /dev/null +++ b/linux-patches/backport-kallsym-sym-2.6.32.patch @@ -0,0 +1,37 @@ +commit e6b48d720e39d17f06a4462be4164e1a358817de +Author: Mathieu Desnoyers +Date: Sat Sep 1 17:51:33 2012 -0700 + + kallsyms: Re-enable export of kallsyms_lookup (backport) + + Backport of part of commit: + + commit f60d24d2ad04977b0bd9e3eb35dba2d2fa569af9 + Author: Frederic Weisbecker + Date: Tue Nov 10 10:17:07 2009 +0100 + + hw-breakpoints: Fix broken hw-breakpoint sample module + + The hw-breakpoint sample module has been broken during the + hw-breakpoint internals refactoring. Propagate the changes + to it. + + Reported-by: "K. Prasad" + Signed-off-by: Frederic Weisbecker + + for kernel 2.6.32.x. (just the symbol export) + + Signed-off-by: Mathieu Desnoyers + +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index 8b6b8b6..8e5288a 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -181,6 +181,7 @@ unsigned long kallsyms_lookup_name(const char *name) + } + return module_kallsyms_lookup_name(name); + } ++EXPORT_SYMBOL_GPL(kallsyms_lookup_name); + + int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, + unsigned long), diff --git a/linux-patches/backport-splice-sym-2.6.32-34.patch b/linux-patches/backport-splice-sym-2.6.32-34.patch new file mode 100644 index 00000000..00be3b5c --- /dev/null +++ b/linux-patches/backport-splice-sym-2.6.32-34.patch @@ -0,0 +1,71 @@ +commit f0d902f497ee2fb747086322a31925c7fb351d7a +Author: Mathieu Desnoyers +Date: Sat Sep 1 17:47:36 2012 -0700 + + mm: export generic_pipe_buf_*() to modules (backport) + + Backport for 2.6.32.x to 2.6.34.x of commits: + + commit 51921cb746f56983db5a373ca68deb2b0d3ddf01 + Author: Miklos Szeredi + Date: Wed May 26 08:44:22 2010 +0200 + + mm: export generic_pipe_buf_*() to modules + + This is needed by fuse device code which wants to create pipe buffers. + Signed-off-by: Miklos Szeredi + + Signed-off-by: Mathieu Desnoyers + +diff --git a/fs/pipe.c b/fs/pipe.c +index d0cc080..0eb6f53 100644 +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -222,6 +222,7 @@ void *generic_pipe_buf_map(struct pipe_inode_info *pipe, + + return kmap(buf->page); + } ++EXPORT_SYMBOL(generic_pipe_buf_map); + + /** + * generic_pipe_buf_unmap - unmap a previously mapped pipe buffer +@@ -241,6 +242,7 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *pipe, + } else + kunmap(buf->page); + } ++EXPORT_SYMBOL(generic_pipe_buf_unmap); + + /** + * generic_pipe_buf_steal - attempt to take ownership of a &pipe_buffer +@@ -271,6 +273,7 @@ int generic_pipe_buf_steal(struct pipe_inode_info *pipe, + + return 1; + } ++EXPORT_SYMBOL(generic_pipe_buf_steal); + + /** + * generic_pipe_buf_get - get a reference to a &struct pipe_buffer +@@ -286,6 +289,7 @@ void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) + { + page_cache_get(buf->page); + } ++EXPORT_SYMBOL(generic_pipe_buf_get); + + /** + * generic_pipe_buf_confirm - verify contents of the pipe buffer +@@ -301,6 +305,7 @@ int generic_pipe_buf_confirm(struct pipe_inode_info *info, + { + return 0; + } ++EXPORT_SYMBOL(generic_pipe_buf_confirm); + + /** + * generic_pipe_buf_release - put a reference to a &struct pipe_buffer +@@ -315,6 +320,7 @@ void generic_pipe_buf_release(struct pipe_inode_info *pipe, + { + page_cache_release(buf->page); + } ++EXPORT_SYMBOL(generic_pipe_buf_release); + + static const struct pipe_buf_operations anon_pipe_buf_ops = { + .can_merge = 1, diff --git a/linux-patches/backport-tp-2.6.34-tracepoint-data.patch b/linux-patches/backport-tp-2.6.34-tracepoint-data.patch new file mode 100644 index 00000000..385e87e5 --- /dev/null +++ b/linux-patches/backport-tp-2.6.34-tracepoint-data.patch @@ -0,0 +1,545 @@ +commit 2c2a566b64b4254c530fb0c2222b30e8a739bac9 +Author: Mathieu Desnoyers +Date: Sat Sep 1 17:45:09 2012 -0700 + + tracing: Let tracepoints have data passed to tracepoint callbacks (backport) + + Backport of commit 38516ab59fbc5b3bb278cf5e1fe2867c70cff32e for + 2.6.34.x. Keeping kABI compatibility. + + Signed-off-by: Mathieu Desnoyers + +--- + include/linux/tracepoint.h | 149 ++++++++++++++++++++++++++++++++++----------- + kernel/tracepoint.c | 144 +++++++++++++++++++++++++++++++------------ + 2 files changed, 219 insertions(+), 74 deletions(-) + +Index: linux/include/linux/tracepoint.h +=================================================================== +--- linux.orig/include/linux/tracepoint.h ++++ linux/include/linux/tracepoint.h +@@ -20,12 +20,20 @@ + struct module; + struct tracepoint; + ++#define HAVE_KABI_2635_TRACEPOINT ++ ++struct tracepoint_func { ++ void *func; ++ void *data; ++ bool kabi_2635; ++}; ++ + struct tracepoint { + const char *name; /* Tracepoint name */ + int state; /* State. */ + void (*regfunc)(void); + void (*unregfunc)(void); +- void **funcs; ++ struct tracepoint_func *funcs; + } __attribute__((aligned(32))); /* + * Aligned on 32 bytes because it is + * globally visible and gcc happily +@@ -43,17 +51,33 @@ struct tracepoint { + /* + * it_func[0] is never NULL because there is at least one element in the array + * when the array itself is non NULL. +- */ +-#define __DO_TRACE(tp, proto, args) \ +- do { \ +- void **it_func; \ ++ * ++ * Note, the proto and args passed in includes "__data" as the first parameter. ++ * The reason for this is to handle the "void" prototype. If a tracepoint ++ * has a "void" prototype, then it is invalid to declare a function ++ * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just ++ * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". ++ */ ++#define __DO_TRACE(tp, data_proto, data_args, proto, args) \ ++ do { \ ++ struct tracepoint_func *it_func_ptr; \ ++ void *it_func; \ ++ \ ++ rcu_read_lock_sched_notrace(); \ ++ it_func_ptr = rcu_dereference_sched((tp)->funcs); \ ++ if (it_func_ptr) { \ ++ do { \ ++ if (it_func_ptr->kabi_2635) { \ ++ void *__data; \ + \ +- rcu_read_lock_sched_notrace(); \ +- it_func = rcu_dereference_sched((tp)->funcs); \ +- if (it_func) { \ +- do { \ +- ((void(*)(proto))(*it_func))(args); \ +- } while (*(++it_func)); \ ++ it_func = (it_func_ptr)->func; \ ++ __data = (it_func_ptr)->data; \ ++ ((void(*)(data_proto))(it_func))(data_args); \ ++ } else { \ ++ it_func = (it_func_ptr)->func; \ ++ ((void(*)(proto))(it_func))(args); \ ++ } \ ++ } while ((++it_func_ptr)->func); \ + } \ + rcu_read_unlock_sched_notrace(); \ + } while (0) +@@ -63,22 +87,39 @@ struct tracepoint { + * not add unwanted padding between the beginning of the section and the + * structure. Force alignment to the same alignment as the section start. + */ +-#define DECLARE_TRACE(name, proto, args) \ ++#define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \ + extern struct tracepoint __tracepoint_##name; \ + static inline void trace_##name(proto) \ + { \ + if (unlikely(__tracepoint_##name.state)) \ + __DO_TRACE(&__tracepoint_##name, \ +- TP_PROTO(proto), TP_ARGS(args)); \ ++ TP_PROTO(data_proto), \ ++ TP_ARGS(data_args), \ ++ TP_PROTO(proto), \ ++ TP_ARGS(args)); \ + } \ +- static inline int register_trace_##name(void (*probe)(proto)) \ +- { \ ++ static inline int \ ++ register_trace_##name(void (*probe)(proto)) \ ++ { \ + return tracepoint_probe_register(#name, (void *)probe); \ +- } \ +- static inline int unregister_trace_##name(void (*probe)(proto)) \ +- { \ +- return tracepoint_probe_unregister(#name, (void *)probe);\ +- } ++ } \ ++ static inline int \ ++ unregister_trace_##name(void (*probe)(proto)) \ ++ { \ ++ return tracepoint_probe_unregister(#name, (void *)probe); \ ++ } \ ++ static inline int \ ++ kabi_2635_register_trace_##name(void (*probe)(data_proto), void *data) \ ++ { \ ++ return kabi_2635_tracepoint_probe_register(#name, (void *)probe, \ ++ data); \ ++ } \ ++ static inline int \ ++ kabi_2635_unregister_trace_##name(void (*probe)(data_proto), void *data) \ ++ { \ ++ return kabi_2635_tracepoint_probe_unregister(#name, (void *)probe, \ ++ data); \ ++ } + + + #define DEFINE_TRACE_FN(name, reg, unreg) \ +@@ -100,19 +141,29 @@ extern void tracepoint_update_probe_rang + struct tracepoint *end); + + #else /* !CONFIG_TRACEPOINTS */ +-#define DECLARE_TRACE(name, proto, args) \ +- static inline void _do_trace_##name(struct tracepoint *tp, proto) \ +- { } \ +- static inline void trace_##name(proto) \ +- { } \ +- static inline int register_trace_##name(void (*probe)(proto)) \ +- { \ +- return -ENOSYS; \ +- } \ +- static inline int unregister_trace_##name(void (*probe)(proto)) \ +- { \ +- return -ENOSYS; \ +- } ++#define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \ ++ static inline void trace_##name(proto) \ ++ { } \ ++ static inline int \ ++ register_trace_##name(void (*probe)(proto)) \ ++ { \ ++ return -ENOSYS; \ ++ } \ ++ static inline int \ ++ unregister_trace_##name(void (*probe)(proto)) \ ++ { \ ++ return -ENOSYS; \ ++ } \ ++ static inline int \ ++ kabi_2635_register_trace_##name(void (*probe)(data_proto), void *data) \ ++ { \ ++ return -ENOSYS; \ ++ } \ ++ static inline int \ ++ kabi_2635_unregister_trace_##name(void (*probe)(data_proto), void *data) \ ++ { \ ++ return -ENOSYS; \ ++ } + + #define DEFINE_TRACE_FN(name, reg, unreg) + #define DEFINE_TRACE(name) +@@ -123,6 +174,28 @@ static inline void tracepoint_update_pro + struct tracepoint *end) + { } + #endif /* CONFIG_TRACEPOINTS */ ++ ++/* ++ * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype ++ * (void). "void" is a special value in a function prototype and can ++ * not be combined with other arguments. Since the DECLARE_TRACE() ++ * macro adds a data element at the beginning of the prototype, ++ * we need a way to differentiate "(void *data, proto)" from ++ * "(void *data, void)". The second prototype is invalid. ++ * ++ * DECLARE_TRACE_NOARGS() passes "void" as the tracepoint prototype ++ * and "void *__data" as the callback prototype. ++ * ++ * DECLARE_TRACE() passes "proto" as the tracepoint protoype and ++ * "void *__data, proto" as the callback prototype. ++ */ ++#define DECLARE_TRACE_NOARGS(name) \ ++ __DECLARE_TRACE(name, void, , void *__data, __data) ++#define DECLARE_TRACE(name, proto, args) \ ++ __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ ++ PARAMS(void *__data, proto), \ ++ PARAMS(__data, args)) ++ + #endif /* DECLARE_TRACE */ + + /* +@@ -130,15 +203,23 @@ static inline void tracepoint_update_pro + * Internal API, should not be used directly. + */ + extern int tracepoint_probe_register(const char *name, void *probe); ++extern int kabi_2635_tracepoint_probe_register(const char *name, void *probe, void *data); + + /* + * Disconnect a probe from a tracepoint. + * Internal API, should not be used directly. + */ +-extern int tracepoint_probe_unregister(const char *name, void *probe); ++extern int ++tracepoint_probe_unregister(const char *name, void *probe); ++extern int ++kabi_2635_tracepoint_probe_unregister(const char *name, void *probe, void *data); + + extern int tracepoint_probe_register_noupdate(const char *name, void *probe); ++extern int kabi_2635_tracepoint_probe_register_noupdate(const char *name, void *probe, ++ void *data); + extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe); ++extern int kabi_2635_tracepoint_probe_unregister_noupdate(const char *name, void *probe, ++ void *data); + extern void tracepoint_probe_update_all(void); + + struct tracepoint_iter { +Index: linux/kernel/tracepoint.c +=================================================================== +--- linux.orig/kernel/tracepoint.c ++++ linux/kernel/tracepoint.c +@@ -54,7 +54,7 @@ static struct hlist_head tracepoint_tabl + */ + struct tracepoint_entry { + struct hlist_node hlist; +- void **funcs; ++ struct tracepoint_func *funcs; + int refcount; /* Number of times armed. 0 if disarmed. */ + char name[0]; + }; +@@ -64,12 +64,12 @@ struct tp_probes { + struct rcu_head rcu; + struct list_head list; + } u; +- void *probes[0]; ++ struct tracepoint_func probes[0]; + }; + + static inline void *allocate_probes(int count) + { +- struct tp_probes *p = kmalloc(count * sizeof(void *) ++ struct tp_probes *p = kmalloc(count * sizeof(struct tracepoint_func) + + sizeof(struct tp_probes), GFP_KERNEL); + return p == NULL ? NULL : p->probes; + } +@@ -79,7 +79,7 @@ static void rcu_free_old_probes(struct r + kfree(container_of(head, struct tp_probes, u.rcu)); + } + +-static inline void release_probes(void *old) ++static inline void release_probes(struct tracepoint_func *old) + { + if (old) { + struct tp_probes *tp_probes = container_of(old, +@@ -95,15 +95,16 @@ static void debug_print_probes(struct tr + if (!tracepoint_debug || !entry->funcs) + return; + +- for (i = 0; entry->funcs[i]; i++) +- printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i]); ++ for (i = 0; entry->funcs[i].func; i++) ++ printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i].func); + } + +-static void * +-tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe) ++static struct tracepoint_func * ++tracepoint_entry_add_probe(struct tracepoint_entry *entry, ++ void *probe, void *data, bool kabi_2635) + { + int nr_probes = 0; +- void **old, **new; ++ struct tracepoint_func *old, *new; + + WARN_ON(!probe); + +@@ -111,8 +112,9 @@ tracepoint_entry_add_probe(struct tracep + old = entry->funcs; + if (old) { + /* (N -> N+1), (N != 0, 1) probes */ +- for (nr_probes = 0; old[nr_probes]; nr_probes++) +- if (old[nr_probes] == probe) ++ for (nr_probes = 0; old[nr_probes].func; nr_probes++) ++ if (old[nr_probes].func == probe && ++ old[nr_probes].data == data) + return ERR_PTR(-EEXIST); + } + /* + 2 : one for new probe, one for NULL func */ +@@ -120,9 +122,11 @@ tracepoint_entry_add_probe(struct tracep + if (new == NULL) + return ERR_PTR(-ENOMEM); + if (old) +- memcpy(new, old, nr_probes * sizeof(void *)); +- new[nr_probes] = probe; +- new[nr_probes + 1] = NULL; ++ memcpy(new, old, nr_probes * sizeof(struct tracepoint_func)); ++ new[nr_probes].func = probe; ++ new[nr_probes].data = data; ++ new[nr_probes].kabi_2635 = kabi_2635; ++ new[nr_probes + 1].func = NULL; + entry->refcount = nr_probes + 1; + entry->funcs = new; + debug_print_probes(entry); +@@ -130,10 +134,11 @@ tracepoint_entry_add_probe(struct tracep + } + + static void * +-tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe) ++tracepoint_entry_remove_probe(struct tracepoint_entry *entry, ++ void *probe, void *data) + { + int nr_probes = 0, nr_del = 0, i; +- void **old, **new; ++ struct tracepoint_func *old, *new; + + old = entry->funcs; + +@@ -142,8 +147,10 @@ tracepoint_entry_remove_probe(struct tra + + debug_print_probes(entry); + /* (N -> M), (N > 1, M >= 0) probes */ +- for (nr_probes = 0; old[nr_probes]; nr_probes++) { +- if ((!probe || old[nr_probes] == probe)) ++ for (nr_probes = 0; old[nr_probes].func; nr_probes++) { ++ if (!probe || ++ (old[nr_probes].func == probe && ++ old[nr_probes].data == data)) + nr_del++; + } + +@@ -160,10 +167,11 @@ tracepoint_entry_remove_probe(struct tra + new = allocate_probes(nr_probes - nr_del + 1); + if (new == NULL) + return ERR_PTR(-ENOMEM); +- for (i = 0; old[i]; i++) +- if ((probe && old[i] != probe)) ++ for (i = 0; old[i].func; i++) ++ if (probe && ++ (old[i].func != probe || old[i].data != data)) + new[j++] = old[i]; +- new[nr_probes - nr_del] = NULL; ++ new[nr_probes - nr_del].func = NULL; + entry->refcount = nr_probes - nr_del; + entry->funcs = new; + } +@@ -315,18 +323,19 @@ static void tracepoint_update_probes(voi + module_update_tracepoints(); + } + +-static void *tracepoint_add_probe(const char *name, void *probe) ++static struct tracepoint_func * ++tracepoint_add_probe(const char *name, void *probe, void *data, bool kabi_2635) + { + struct tracepoint_entry *entry; +- void *old; ++ struct tracepoint_func *old; + + entry = get_tracepoint(name); + if (!entry) { + entry = add_tracepoint(name); + if (IS_ERR(entry)) +- return entry; ++ return (struct tracepoint_func *)entry; + } +- old = tracepoint_entry_add_probe(entry, probe); ++ old = tracepoint_entry_add_probe(entry, probe, data, kabi_2635); + if (IS_ERR(old) && !entry->refcount) + remove_tracepoint(entry); + return old; +@@ -340,12 +349,14 @@ static void *tracepoint_add_probe(const + * Returns 0 if ok, error value on error. + * The probe address must at least be aligned on the architecture pointer size. + */ +-int tracepoint_probe_register(const char *name, void *probe) ++static ++int ___tracepoint_probe_register(const char *name, void *probe, void *data, ++ bool kabi_2635) + { +- void *old; ++ struct tracepoint_func *old; + + mutex_lock(&tracepoints_mutex); +- old = tracepoint_add_probe(name, probe); ++ old = tracepoint_add_probe(name, probe, data, kabi_2635); + mutex_unlock(&tracepoints_mutex); + if (IS_ERR(old)) + return PTR_ERR(old); +@@ -354,17 +365,30 @@ int tracepoint_probe_register(const char + release_probes(old); + return 0; + } ++ ++int kabi_2635_tracepoint_probe_register(const char *name, void *probe, void *data) ++{ ++ return ___tracepoint_probe_register(name, probe, data, 1); ++} ++EXPORT_SYMBOL_GPL(kabi_2635_tracepoint_probe_register); ++ ++ ++int tracepoint_probe_register(const char *name, void *probe) ++{ ++ return ___tracepoint_probe_register(name, probe, NULL, 0); ++} + EXPORT_SYMBOL_GPL(tracepoint_probe_register); + +-static void *tracepoint_remove_probe(const char *name, void *probe) ++static struct tracepoint_func * ++tracepoint_remove_probe(const char *name, void *probe, void *data) + { + struct tracepoint_entry *entry; +- void *old; ++ struct tracepoint_func *old; + + entry = get_tracepoint(name); + if (!entry) + return ERR_PTR(-ENOENT); +- old = tracepoint_entry_remove_probe(entry, probe); ++ old = tracepoint_entry_remove_probe(entry, probe, data); + if (IS_ERR(old)) + return old; + if (!entry->refcount) +@@ -382,12 +406,13 @@ static void *tracepoint_remove_probe(con + * itself uses stop_machine(), which insures that every preempt disabled section + * have finished. + */ +-int tracepoint_probe_unregister(const char *name, void *probe) ++static ++int ___tracepoint_probe_unregister(const char *name, void *probe, void *data) + { +- void *old; ++ struct tracepoint_func *old; + + mutex_lock(&tracepoints_mutex); +- old = tracepoint_remove_probe(name, probe); ++ old = tracepoint_remove_probe(name, probe, data); + mutex_unlock(&tracepoints_mutex); + if (IS_ERR(old)) + return PTR_ERR(old); +@@ -396,6 +421,17 @@ int tracepoint_probe_unregister(const ch + release_probes(old); + return 0; + } ++ ++int kabi_2635_tracepoint_probe_unregister(const char *name, void *probe, void *data) ++{ ++ return ___tracepoint_probe_unregister(name, probe, data); ++} ++EXPORT_SYMBOL_GPL(kabi_2635_tracepoint_probe_unregister); ++ ++int tracepoint_probe_unregister(const char *name, void *probe) ++{ ++ return ___tracepoint_probe_unregister(name, probe, NULL); ++} + EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); + + static LIST_HEAD(old_probes); +@@ -418,12 +454,14 @@ static void tracepoint_add_old_probes(vo + * + * caller must call tracepoint_probe_update_all() + */ +-int tracepoint_probe_register_noupdate(const char *name, void *probe) ++static ++int ___tracepoint_probe_register_noupdate(const char *name, void *probe, ++ void *data, bool kabi_2635) + { +- void *old; ++ struct tracepoint_func *old; + + mutex_lock(&tracepoints_mutex); +- old = tracepoint_add_probe(name, probe); ++ old = tracepoint_add_probe(name, probe, data, kabi_2635); + if (IS_ERR(old)) { + mutex_unlock(&tracepoints_mutex); + return PTR_ERR(old); +@@ -432,6 +470,18 @@ int tracepoint_probe_register_noupdate(c + mutex_unlock(&tracepoints_mutex); + return 0; + } ++ ++int kabi_2635_tracepoint_probe_register_noupdate(const char *name, void *probe, ++ void *data) ++{ ++ return ___tracepoint_probe_register_noupdate(name, probe, data, 1); ++} ++EXPORT_SYMBOL_GPL(kabi_2635_tracepoint_probe_register_noupdate); ++ ++int tracepoint_probe_register_noupdate(const char *name, void *probe) ++{ ++ return ___tracepoint_probe_register_noupdate(name, probe, NULL, 0); ++} + EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate); + + /** +@@ -441,12 +491,14 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_regis + * + * caller must call tracepoint_probe_update_all() + */ +-int tracepoint_probe_unregister_noupdate(const char *name, void *probe) ++static ++int ___tracepoint_probe_unregister_noupdate(const char *name, void *probe, ++ void *data) + { +- void *old; ++ struct tracepoint_func *old; + + mutex_lock(&tracepoints_mutex); +- old = tracepoint_remove_probe(name, probe); ++ old = tracepoint_remove_probe(name, probe, data); + if (IS_ERR(old)) { + mutex_unlock(&tracepoints_mutex); + return PTR_ERR(old); +@@ -455,6 +507,18 @@ int tracepoint_probe_unregister_noupdate + mutex_unlock(&tracepoints_mutex); + return 0; + } ++ ++int kabi_2635_tracepoint_probe_unregister_noupdate(const char *name, void *probe, ++ void *data) ++{ ++ return ___tracepoint_probe_unregister_noupdate(name, probe, data); ++} ++EXPORT_SYMBOL_GPL(kabi_2635_tracepoint_probe_unregister_noupdate); ++ ++int tracepoint_probe_unregister_noupdate(const char *name, void *probe) ++{ ++ return ___tracepoint_probe_unregister_noupdate(name, probe, NULL); ++} + EXPORT_SYMBOL_GPL(tracepoint_probe_unregister_noupdate); + + /** diff --git a/linux-patches/backport-tracepoint-data-2.6.32-33.patch b/linux-patches/backport-tracepoint-data-2.6.32-33.patch new file mode 100644 index 00000000..e344bac5 --- /dev/null +++ b/linux-patches/backport-tracepoint-data-2.6.32-33.patch @@ -0,0 +1,541 @@ +commit 2c2a566b64b4254c530fb0c2222b30e8a739bac9 +Author: Mathieu Desnoyers +Date: Sat Sep 1 17:45:09 2012 -0700 + + tracing: Let tracepoints have data passed to tracepoint callbacks (backport) + + Backport of commit 38516ab59fbc5b3bb278cf5e1fe2867c70cff32e for + 2.6.32.x and 2.6.33.x. Keeping kABI compatibility. + + Signed-off-by: Mathieu Desnoyers + +--- + include/linux/tracepoint.h | 141 ++++++++++++++++++++++++++++++++++---------- + kernel/tracepoint.c | 144 ++++++++++++++++++++++++++++++++------------- + 2 files changed, 215 insertions(+), 70 deletions(-) + +Index: linux/include/linux/tracepoint.h +=================================================================== +--- linux.orig/include/linux/tracepoint.h ++++ linux/include/linux/tracepoint.h +@@ -20,12 +20,20 @@ + struct module; + struct tracepoint; + ++#define HAVE_KABI_2635_TRACEPOINT ++ ++struct tracepoint_func { ++ void *func; ++ void *data; ++ bool kabi_2635; ++}; ++ + struct tracepoint { + const char *name; /* Tracepoint name */ + int state; /* State. */ + void (*regfunc)(void); + void (*unregfunc)(void); +- void **funcs; ++ struct tracepoint_func *funcs; + } __attribute__((aligned(32))); /* + * Aligned on 32 bytes because it is + * globally visible and gcc happily +@@ -43,17 +51,33 @@ struct tracepoint { + /* + * it_func[0] is never NULL because there is at least one element in the array + * when the array itself is non NULL. ++ * ++ * Note, the proto and args passed in includes "__data" as the first parameter. ++ * The reason for this is to handle the "void" prototype. If a tracepoint ++ * has a "void" prototype, then it is invalid to declare a function ++ * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just ++ * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". + */ +-#define __DO_TRACE(tp, proto, args) \ ++#define __DO_TRACE(tp, data_proto, data_args, proto, args) \ + do { \ +- void **it_func; \ ++ struct tracepoint_func *it_func_ptr; \ ++ void *it_func; \ + \ + rcu_read_lock_sched_notrace(); \ +- it_func = rcu_dereference((tp)->funcs); \ +- if (it_func) { \ ++ it_func_ptr = rcu_dereference((tp)->funcs); \ ++ if (it_func_ptr) { \ + do { \ +- ((void(*)(proto))(*it_func))(args); \ +- } while (*(++it_func)); \ ++ if (it_func_ptr->kabi_2635) { \ ++ void *__data; \ ++ \ ++ it_func = (it_func_ptr)->func; \ ++ __data = (it_func_ptr)->data; \ ++ ((void(*)(data_proto))(it_func))(data_args); \ ++ } else { \ ++ it_func = (it_func_ptr)->func; \ ++ ((void(*)(proto))(it_func))(args); \ ++ } \ ++ } while ((++it_func_ptr)->func); \ + } \ + rcu_read_unlock_sched_notrace(); \ + } while (0) +@@ -63,22 +87,39 @@ struct tracepoint { + * not add unwanted padding between the beginning of the section and the + * structure. Force alignment to the same alignment as the section start. + */ +-#define DECLARE_TRACE(name, proto, args) \ ++#define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \ + extern struct tracepoint __tracepoint_##name; \ + static inline void trace_##name(proto) \ + { \ + if (unlikely(__tracepoint_##name.state)) \ + __DO_TRACE(&__tracepoint_##name, \ +- TP_PROTO(proto), TP_ARGS(args)); \ ++ TP_PROTO(data_proto), \ ++ TP_ARGS(data_args), \ ++ TP_PROTO(proto), \ ++ TP_ARGS(args)); \ + } \ +- static inline int register_trace_##name(void (*probe)(proto)) \ +- { \ ++ static inline int \ ++ register_trace_##name(void (*probe)(proto)) \ ++ { \ + return tracepoint_probe_register(#name, (void *)probe); \ +- } \ +- static inline int unregister_trace_##name(void (*probe)(proto)) \ +- { \ +- return tracepoint_probe_unregister(#name, (void *)probe);\ +- } ++ } \ ++ static inline int \ ++ unregister_trace_##name(void (*probe)(proto)) \ ++ { \ ++ return tracepoint_probe_unregister(#name, (void *)probe); \ ++ } \ ++ static inline int \ ++ kabi_2635_register_trace_##name(void (*probe)(data_proto), void *data) \ ++ { \ ++ return kabi_2635_tracepoint_probe_register(#name, (void *)probe, \ ++ data); \ ++ } \ ++ static inline int \ ++ kabi_2635_unregister_trace_##name(void (*probe)(data_proto), void *data) \ ++ { \ ++ return kabi_2635_tracepoint_probe_unregister(#name, (void *)probe, \ ++ data); \ ++ } + + + #define DEFINE_TRACE_FN(name, reg, unreg) \ +@@ -100,19 +141,29 @@ extern void tracepoint_update_probe_rang + struct tracepoint *end); + + #else /* !CONFIG_TRACEPOINTS */ +-#define DECLARE_TRACE(name, proto, args) \ +- static inline void _do_trace_##name(struct tracepoint *tp, proto) \ +- { } \ +- static inline void trace_##name(proto) \ +- { } \ +- static inline int register_trace_##name(void (*probe)(proto)) \ +- { \ +- return -ENOSYS; \ +- } \ +- static inline int unregister_trace_##name(void (*probe)(proto)) \ +- { \ +- return -ENOSYS; \ +- } ++#define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \ ++ static inline void trace_##name(proto) \ ++ { } \ ++ static inline int \ ++ register_trace_##name(void (*probe)(proto)) \ ++ { \ ++ return -ENOSYS; \ ++ } \ ++ static inline int \ ++ unregister_trace_##name(void (*probe)(proto)) \ ++ { \ ++ return -ENOSYS; \ ++ } \ ++ static inline int \ ++ kabi_2635_register_trace_##name(void (*probe)(data_proto), void *data) \ ++ { \ ++ return -ENOSYS; \ ++ } \ ++ static inline int \ ++ kabi_2635_unregister_trace_##name(void (*probe)(data_proto), void *data) \ ++ { \ ++ return -ENOSYS; \ ++ } + + #define DEFINE_TRACE_FN(name, reg, unreg) + #define DEFINE_TRACE(name) +@@ -123,6 +174,28 @@ static inline void tracepoint_update_pro + struct tracepoint *end) + { } + #endif /* CONFIG_TRACEPOINTS */ ++ ++/* ++ * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype ++ * (void). "void" is a special value in a function prototype and can ++ * not be combined with other arguments. Since the DECLARE_TRACE() ++ * macro adds a data element at the beginning of the prototype, ++ * we need a way to differentiate "(void *data, proto)" from ++ * "(void *data, void)". The second prototype is invalid. ++ * ++ * DECLARE_TRACE_NOARGS() passes "void" as the tracepoint prototype ++ * and "void *__data" as the callback prototype. ++ * ++ * DECLARE_TRACE() passes "proto" as the tracepoint protoype and ++ * "void *__data, proto" as the callback prototype. ++ */ ++#define DECLARE_TRACE_NOARGS(name) \ ++ __DECLARE_TRACE(name, void, , void *__data, __data) ++#define DECLARE_TRACE(name, proto, args) \ ++ __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ ++ PARAMS(void *__data, proto), \ ++ PARAMS(__data, args)) ++ + #endif /* DECLARE_TRACE */ + + /* +@@ -130,15 +203,23 @@ static inline void tracepoint_update_pro + * Internal API, should not be used directly. + */ + extern int tracepoint_probe_register(const char *name, void *probe); ++extern int kabi_2635_tracepoint_probe_register(const char *name, void *probe, void *data); + + /* + * Disconnect a probe from a tracepoint. + * Internal API, should not be used directly. + */ +-extern int tracepoint_probe_unregister(const char *name, void *probe); ++extern int ++tracepoint_probe_unregister(const char *name, void *probe); ++extern int ++kabi_2635_tracepoint_probe_unregister(const char *name, void *probe, void *data); + + extern int tracepoint_probe_register_noupdate(const char *name, void *probe); ++extern int kabi_2635_tracepoint_probe_register_noupdate(const char *name, void *probe, ++ void *data); + extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe); ++extern int kabi_2635_tracepoint_probe_unregister_noupdate(const char *name, void *probe, ++ void *data); + extern void tracepoint_probe_update_all(void); + + struct tracepoint_iter { +Index: linux/kernel/tracepoint.c +=================================================================== +--- linux.orig/kernel/tracepoint.c ++++ linux/kernel/tracepoint.c +@@ -54,7 +54,7 @@ static struct hlist_head tracepoint_tabl + */ + struct tracepoint_entry { + struct hlist_node hlist; +- void **funcs; ++ struct tracepoint_func *funcs; + int refcount; /* Number of times armed. 0 if disarmed. */ + char name[0]; + }; +@@ -64,12 +64,12 @@ struct tp_probes { + struct rcu_head rcu; + struct list_head list; + } u; +- void *probes[0]; ++ struct tracepoint_func probes[0]; + }; + + static inline void *allocate_probes(int count) + { +- struct tp_probes *p = kmalloc(count * sizeof(void *) ++ struct tp_probes *p = kmalloc(count * sizeof(struct tracepoint_func) + + sizeof(struct tp_probes), GFP_KERNEL); + return p == NULL ? NULL : p->probes; + } +@@ -79,7 +79,7 @@ static void rcu_free_old_probes(struct r + kfree(container_of(head, struct tp_probes, u.rcu)); + } + +-static inline void release_probes(void *old) ++static inline void release_probes(struct tracepoint_func *old) + { + if (old) { + struct tp_probes *tp_probes = container_of(old, +@@ -95,15 +95,16 @@ static void debug_print_probes(struct tr + if (!tracepoint_debug || !entry->funcs) + return; + +- for (i = 0; entry->funcs[i]; i++) +- printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i]); ++ for (i = 0; entry->funcs[i].func; i++) ++ printk(KERN_DEBUG "Probe %d : %p\n", i, entry->funcs[i].func); + } + +-static void * +-tracepoint_entry_add_probe(struct tracepoint_entry *entry, void *probe) ++static struct tracepoint_func * ++tracepoint_entry_add_probe(struct tracepoint_entry *entry, ++ void *probe, void *data, bool kabi_2635) + { + int nr_probes = 0; +- void **old, **new; ++ struct tracepoint_func *old, *new; + + WARN_ON(!probe); + +@@ -111,8 +112,9 @@ tracepoint_entry_add_probe(struct tracep + old = entry->funcs; + if (old) { + /* (N -> N+1), (N != 0, 1) probes */ +- for (nr_probes = 0; old[nr_probes]; nr_probes++) +- if (old[nr_probes] == probe) ++ for (nr_probes = 0; old[nr_probes].func; nr_probes++) ++ if (old[nr_probes].func == probe && ++ old[nr_probes].data == data) + return ERR_PTR(-EEXIST); + } + /* + 2 : one for new probe, one for NULL func */ +@@ -120,9 +122,11 @@ tracepoint_entry_add_probe(struct tracep + if (new == NULL) + return ERR_PTR(-ENOMEM); + if (old) +- memcpy(new, old, nr_probes * sizeof(void *)); +- new[nr_probes] = probe; +- new[nr_probes + 1] = NULL; ++ memcpy(new, old, nr_probes * sizeof(struct tracepoint_func)); ++ new[nr_probes].func = probe; ++ new[nr_probes].data = data; ++ new[nr_probes].kabi_2635 = kabi_2635; ++ new[nr_probes + 1].func = NULL; + entry->refcount = nr_probes + 1; + entry->funcs = new; + debug_print_probes(entry); +@@ -130,10 +134,11 @@ tracepoint_entry_add_probe(struct tracep + } + + static void * +-tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe) ++tracepoint_entry_remove_probe(struct tracepoint_entry *entry, ++ void *probe, void *data) + { + int nr_probes = 0, nr_del = 0, i; +- void **old, **new; ++ struct tracepoint_func *old, *new; + + old = entry->funcs; + +@@ -142,8 +147,10 @@ tracepoint_entry_remove_probe(struct tra + + debug_print_probes(entry); + /* (N -> M), (N > 1, M >= 0) probes */ +- for (nr_probes = 0; old[nr_probes]; nr_probes++) { +- if ((!probe || old[nr_probes] == probe)) ++ for (nr_probes = 0; old[nr_probes].func; nr_probes++) { ++ if (!probe || ++ (old[nr_probes].func == probe && ++ old[nr_probes].data == data)) + nr_del++; + } + +@@ -160,10 +167,11 @@ tracepoint_entry_remove_probe(struct tra + new = allocate_probes(nr_probes - nr_del + 1); + if (new == NULL) + return ERR_PTR(-ENOMEM); +- for (i = 0; old[i]; i++) +- if ((probe && old[i] != probe)) ++ for (i = 0; old[i].func; i++) ++ if (probe && ++ (old[i].func != probe || old[i].data != data)) + new[j++] = old[i]; +- new[nr_probes - nr_del] = NULL; ++ new[nr_probes - nr_del].func = NULL; + entry->refcount = nr_probes - nr_del; + entry->funcs = new; + } +@@ -315,18 +323,19 @@ static void tracepoint_update_probes(voi + module_update_tracepoints(); + } + +-static void *tracepoint_add_probe(const char *name, void *probe) ++static struct tracepoint_func * ++tracepoint_add_probe(const char *name, void *probe, void *data, bool kabi_2635) + { + struct tracepoint_entry *entry; +- void *old; ++ struct tracepoint_func *old; + + entry = get_tracepoint(name); + if (!entry) { + entry = add_tracepoint(name); + if (IS_ERR(entry)) +- return entry; ++ return (struct tracepoint_func *)entry; + } +- old = tracepoint_entry_add_probe(entry, probe); ++ old = tracepoint_entry_add_probe(entry, probe, data, kabi_2635); + if (IS_ERR(old) && !entry->refcount) + remove_tracepoint(entry); + return old; +@@ -340,12 +349,14 @@ static void *tracepoint_add_probe(const + * Returns 0 if ok, error value on error. + * The probe address must at least be aligned on the architecture pointer size. + */ +-int tracepoint_probe_register(const char *name, void *probe) ++static ++int ___tracepoint_probe_register(const char *name, void *probe, void *data, ++ bool kabi_2635) + { +- void *old; ++ struct tracepoint_func *old; + + mutex_lock(&tracepoints_mutex); +- old = tracepoint_add_probe(name, probe); ++ old = tracepoint_add_probe(name, probe, data, kabi_2635); + mutex_unlock(&tracepoints_mutex); + if (IS_ERR(old)) + return PTR_ERR(old); +@@ -354,17 +365,30 @@ int tracepoint_probe_register(const char + release_probes(old); + return 0; + } ++ ++int kabi_2635_tracepoint_probe_register(const char *name, void *probe, void *data) ++{ ++ return ___tracepoint_probe_register(name, probe, data, 1); ++} ++EXPORT_SYMBOL_GPL(kabi_2635_tracepoint_probe_register); ++ ++ ++int tracepoint_probe_register(const char *name, void *probe) ++{ ++ return ___tracepoint_probe_register(name, probe, NULL, 0); ++} + EXPORT_SYMBOL_GPL(tracepoint_probe_register); + +-static void *tracepoint_remove_probe(const char *name, void *probe) ++static struct tracepoint_func * ++tracepoint_remove_probe(const char *name, void *probe, void *data) + { + struct tracepoint_entry *entry; +- void *old; ++ struct tracepoint_func *old; + + entry = get_tracepoint(name); + if (!entry) + return ERR_PTR(-ENOENT); +- old = tracepoint_entry_remove_probe(entry, probe); ++ old = tracepoint_entry_remove_probe(entry, probe, data); + if (IS_ERR(old)) + return old; + if (!entry->refcount) +@@ -382,12 +406,13 @@ static void *tracepoint_remove_probe(con + * itself uses stop_machine(), which insures that every preempt disabled section + * have finished. + */ +-int tracepoint_probe_unregister(const char *name, void *probe) ++static ++int ___tracepoint_probe_unregister(const char *name, void *probe, void *data) + { +- void *old; ++ struct tracepoint_func *old; + + mutex_lock(&tracepoints_mutex); +- old = tracepoint_remove_probe(name, probe); ++ old = tracepoint_remove_probe(name, probe, data); + mutex_unlock(&tracepoints_mutex); + if (IS_ERR(old)) + return PTR_ERR(old); +@@ -396,6 +421,17 @@ int tracepoint_probe_unregister(const ch + release_probes(old); + return 0; + } ++ ++int kabi_2635_tracepoint_probe_unregister(const char *name, void *probe, void *data) ++{ ++ return ___tracepoint_probe_unregister(name, probe, data); ++} ++EXPORT_SYMBOL_GPL(kabi_2635_tracepoint_probe_unregister); ++ ++int tracepoint_probe_unregister(const char *name, void *probe) ++{ ++ return ___tracepoint_probe_unregister(name, probe, NULL); ++} + EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); + + static LIST_HEAD(old_probes); +@@ -418,12 +454,14 @@ static void tracepoint_add_old_probes(vo + * + * caller must call tracepoint_probe_update_all() + */ +-int tracepoint_probe_register_noupdate(const char *name, void *probe) ++static ++int ___tracepoint_probe_register_noupdate(const char *name, void *probe, ++ void *data, bool kabi_2635) + { +- void *old; ++ struct tracepoint_func *old; + + mutex_lock(&tracepoints_mutex); +- old = tracepoint_add_probe(name, probe); ++ old = tracepoint_add_probe(name, probe, data, kabi_2635); + if (IS_ERR(old)) { + mutex_unlock(&tracepoints_mutex); + return PTR_ERR(old); +@@ -432,6 +470,18 @@ int tracepoint_probe_register_noupdate(c + mutex_unlock(&tracepoints_mutex); + return 0; + } ++ ++int kabi_2635_tracepoint_probe_register_noupdate(const char *name, void *probe, ++ void *data) ++{ ++ return ___tracepoint_probe_register_noupdate(name, probe, data, 1); ++} ++EXPORT_SYMBOL_GPL(kabi_2635_tracepoint_probe_register_noupdate); ++ ++int tracepoint_probe_register_noupdate(const char *name, void *probe) ++{ ++ return ___tracepoint_probe_register_noupdate(name, probe, NULL, 0); ++} + EXPORT_SYMBOL_GPL(tracepoint_probe_register_noupdate); + + /** +@@ -441,12 +491,14 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_regis + * + * caller must call tracepoint_probe_update_all() + */ +-int tracepoint_probe_unregister_noupdate(const char *name, void *probe) ++static ++int ___tracepoint_probe_unregister_noupdate(const char *name, void *probe, ++ void *data) + { +- void *old; ++ struct tracepoint_func *old; + + mutex_lock(&tracepoints_mutex); +- old = tracepoint_remove_probe(name, probe); ++ old = tracepoint_remove_probe(name, probe, data); + if (IS_ERR(old)) { + mutex_unlock(&tracepoints_mutex); + return PTR_ERR(old); +@@ -455,6 +507,18 @@ int tracepoint_probe_unregister_noupdate + mutex_unlock(&tracepoints_mutex); + return 0; + } ++ ++int kabi_2635_tracepoint_probe_unregister_noupdate(const char *name, void *probe, ++ void *data) ++{ ++ return ___tracepoint_probe_unregister_noupdate(name, probe, data); ++} ++EXPORT_SYMBOL_GPL(kabi_2635_tracepoint_probe_unregister_noupdate); ++ ++int tracepoint_probe_unregister_noupdate(const char *name, void *probe) ++{ ++ return ___tracepoint_probe_unregister_noupdate(name, probe, NULL); ++} + EXPORT_SYMBOL_GPL(tracepoint_probe_unregister_noupdate); + + /** diff --git a/lttng-events.c b/lttng-events.c index 220178f7..168c3b26 100644 --- a/lttng-events.c +++ b/lttng-events.c @@ -30,6 +30,7 @@ #include "wrapper/uuid.h" #include "wrapper/vmalloc.h" /* for wrapper_vmalloc_sync_all() */ #include "wrapper/random.h" +#include "wrapper/tracepoint.h" #include "lttng-events.h" #include "lttng-tracer.h" @@ -316,7 +317,7 @@ struct lttng_event *lttng_event_create(struct lttng_channel *chan, event->desc = lttng_event_get(event_param->name); if (!event->desc) goto register_error; - ret = tracepoint_probe_register(event_param->name, + ret = kabi_2635_tracepoint_probe_register(event_param->name, event->desc->probe_callback, event); if (ret) @@ -420,7 +421,7 @@ int _lttng_event_unregister(struct lttng_event *event) switch (event->instrumentation) { case LTTNG_KERNEL_TRACEPOINT: - ret = tracepoint_probe_unregister(event->desc->name, + ret = kabi_2635_tracepoint_probe_unregister(event->desc->name, event->desc->probe_callback, event); if (ret) diff --git a/lttng-events.h b/lttng-events.h index be3979ad..af5aa65b 100644 --- a/lttng-events.h +++ b/lttng-events.h @@ -23,6 +23,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include "wrapper/uuid.h" @@ -320,7 +321,7 @@ void lttng_event_put(const struct lttng_event_desc *desc); int lttng_probes_init(void); void lttng_probes_exit(void); -#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS +#if defined(CONFIG_HAVE_SYSCALL_TRACEPOINTS) int lttng_syscalls_register(struct lttng_channel *chan, void *filter); int lttng_syscalls_unregister(struct lttng_channel *chan); #else diff --git a/lttng-statedump-impl.c b/lttng-statedump-impl.c index c92c331b..be498acc 100644 --- a/lttng-statedump-impl.c +++ b/lttng-statedump-impl.c @@ -48,6 +48,7 @@ #include "lttng-events.h" #include "wrapper/irqdesc.h" +#include "wrapper/spinlock.h" #ifdef CONFIG_GENERIC_HARDIRQS #include @@ -255,12 +256,12 @@ void lttng_list_interrupts(struct lttng_session *session) irq_desc_get_chip(desc)->name ? : "unnamed_irq_chip"; local_irq_save(flags); - raw_spin_lock(&desc->lock); + wrapper_desc_spin_lock(&desc->lock); for (action = desc->action; action; action = action->next) { trace_lttng_statedump_interrupt(session, irq, irq_chip_name, action); } - raw_spin_unlock(&desc->lock); + wrapper_desc_spin_unlock(&desc->lock); local_irq_restore(flags); } #undef irq_to_desc diff --git a/lttng-syscalls.c b/lttng-syscalls.c index a1bc9d42..62ed24aa 100644 --- a/lttng-syscalls.c +++ b/lttng-syscalls.c @@ -26,6 +26,7 @@ #include #include +#include "wrapper/tracepoint.h" #include "lttng-events.h" #ifndef CONFIG_COMPAT @@ -37,6 +38,16 @@ static void syscall_entry_probe(void *__data, struct pt_regs *regs, long id); +/* + * Forward declarations for old kernels. + */ +struct mmsghdr; +struct rlimit64; +struct oldold_utsname; +struct old_utsname; +struct sel_arg_struct; +struct mmap_arg_struct; + /* * Take care of NOARGS not supported by mainline. */ @@ -403,7 +414,7 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) if (ret) return ret; #endif - ret = tracepoint_probe_register("sys_enter", + ret = kabi_2635_tracepoint_probe_register("sys_enter", (void *) syscall_entry_probe, chan); if (ret) return ret; @@ -411,11 +422,11 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) * We change the name of sys_exit tracepoint due to namespace * conflict with sys_exit syscall entry. */ - ret = tracepoint_probe_register("sys_exit", + ret = kabi_2635_tracepoint_probe_register("sys_exit", (void *) __event_probe__exit_syscall, chan->sc_exit); if (ret) { - WARN_ON_ONCE(tracepoint_probe_unregister("sys_enter", + WARN_ON_ONCE(kabi_2635_tracepoint_probe_unregister("sys_enter", (void *) syscall_entry_probe, chan)); } return ret; @@ -430,12 +441,12 @@ int lttng_syscalls_unregister(struct lttng_channel *chan) if (!chan->sc_table) return 0; - ret = tracepoint_probe_unregister("sys_exit", + ret = kabi_2635_tracepoint_probe_unregister("sys_exit", (void *) __event_probe__exit_syscall, chan->sc_exit); if (ret) return ret; - ret = tracepoint_probe_unregister("sys_enter", + ret = kabi_2635_tracepoint_probe_unregister("sys_enter", (void *) syscall_entry_probe, chan); if (ret) return ret; diff --git a/probes/Makefile b/probes/Makefile index 698a9c9c..6efd6ad1 100644 --- a/probes/Makefile +++ b/probes/Makefile @@ -9,10 +9,8 @@ ccflags-y += -I$(PWD)/probes obj-m += lttng-types.o obj-m += lttng-probe-lttng.o - obj-m += lttng-probe-sched.o obj-m += lttng-probe-irq.o -obj-m += lttng-probe-signal.o obj-m += lttng-probe-timer.o obj-m += lttng-probe-statedump.o @@ -21,6 +19,11 @@ ifneq ($(CONFIG_KVM),) obj-m += lttng-probe-kvm.o endif +obj-m += $(shell \ + if [ $(VERSION) -ge 3 \ + -o \( $(VERSION) -eq 2 -a $(PATCHLEVEL) -ge 6 -a $(SUBLEVEL) -ge 35 \) ] ; then \ + echo "lttng-probe-signal.o" ; fi;) + ifneq ($(CONFIG_BLOCK),) ifneq ($(CONFIG_EVENT_TRACING),) # need blk_cmd_buf_len obj-m += $(shell \ diff --git a/probes/define_trace.h b/probes/define_trace.h index e9031031..a518390b 100644 --- a/probes/define_trace.h +++ b/probes/define_trace.h @@ -125,7 +125,6 @@ #undef DEFINE_EVENT_PRINT #undef DEFINE_EVENT_CONDITION #undef TRACE_HEADER_MULTI_READ -#undef DECLARE_TRACE /* Only undef what we defined in this file */ #ifdef UNDEF_TRACE_INCLUDE_FILE diff --git a/probes/lttng-probe-irq.c b/probes/lttng-probe-irq.c index 8f5bcd20..afcd1d21 100644 --- a/probes/lttng-probe-irq.c +++ b/probes/lttng-probe-irq.c @@ -22,6 +22,7 @@ #include #include +#include "../wrapper/tracepoint.h" /* * Create the tracepoint static inlines from the kernel to validate that our diff --git a/probes/lttng-probe-sched.c b/probes/lttng-probe-sched.c index 9b3ca5d6..caef6f70 100644 --- a/probes/lttng-probe-sched.c +++ b/probes/lttng-probe-sched.c @@ -21,6 +21,7 @@ */ #include +#include "../wrapper/tracepoint.h" /* * Create the tracepoint static inlines from the kernel to validate that our diff --git a/probes/lttng-probe-timer.c b/probes/lttng-probe-timer.c index 3368bd80..9cf7492a 100644 --- a/probes/lttng-probe-timer.c +++ b/probes/lttng-probe-timer.c @@ -21,11 +21,13 @@ */ #include +#include "../wrapper/tracepoint.h" /* * Create the tracepoint static inlines from the kernel to validate that our * trace event macros match the kernel we run on. */ + #include #include diff --git a/wrapper/perf.h b/wrapper/perf.h index 2caf308a..5dfa84b3 100644 --- a/wrapper/perf.h +++ b/wrapper/perf.h @@ -32,7 +32,9 @@ wrapper_perf_event_create_kernel_counter(struct perf_event_attr *attr, { return perf_event_create_kernel_counter(attr, cpu, task, callback, NULL); } -#else +#else /* defined(CONFIG_PERF_EVENTS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,99)) */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) static inline struct perf_event * wrapper_perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, @@ -41,6 +43,26 @@ wrapper_perf_event_create_kernel_counter(struct perf_event_attr *attr, { return perf_event_create_kernel_counter(attr, cpu, task, callback); } -#endif +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) */ +static inline struct perf_event * +wrapper_perf_event_create_kernel_counter(struct perf_event_attr *attr, + int cpu, + struct task_struct *task, + perf_overflow_handler_t callback) +{ + pid_t pid; + + if (!task) + pid = -1; + else + pid = task->pid; + + return perf_event_create_kernel_counter(attr, cpu, pid, callback); +} + +#define local64_read(l) atomic64_read(l) +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)) */ + +#endif /* defined(CONFIG_PERF_EVENTS) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,99)) */ #endif /* _LTTNG_WRAPPER_PERF_H */ diff --git a/wrapper/spinlock.h b/wrapper/spinlock.h index fdeb91a4..bc71b4f4 100644 --- a/wrapper/spinlock.h +++ b/wrapper/spinlock.h @@ -35,6 +35,13 @@ #define raw_spin_is_locked(lock) __raw_spin_is_locked(lock) +#define wrapper_desc_spin_lock(lock) spin_lock(lock) +#define wrapper_desc_spin_unlock(lock) spin_unlock(lock) + +#else + +#define wrapper_desc_spin_lock(lock) raw_spin_lock(lock) +#define wrapper_desc_spin_unlock(lock) raw_spin_unlock(lock) #endif #endif /* _LTTNG_WRAPPER_SPINLOCK_H */ diff --git a/wrapper/tracepoint.h b/wrapper/tracepoint.h new file mode 100644 index 00000000..798d785b --- /dev/null +++ b/wrapper/tracepoint.h @@ -0,0 +1,44 @@ +#ifndef _LTTNG_WRAPPER_TRACEPOINT_H +#define _LTTNG_WRAPPER_TRACEPOINT_H + +/* + * wrapper/tracepoint.h + * + * wrapper around DECLARE_EVENT_CLASS. + * + * Copyright (C) 2011-2012 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)) + +#define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) + +#endif + +#ifndef HAVE_KABI_2635_TRACEPOINT + +#define kabi_2635_tracepoint_probe_register tracepoint_probe_register +#define kabi_2635_tracepoint_probe_unregister tracepoint_probe_unregister +#define kabi_2635_tracepoint_probe_register_noupdate tracepoint_probe_register_noupdate +#define kabi_2635_tracepoint_probe_unregister_noupdate tracepoint_probe_unregister_noupdate + +#endif /* HAVE_KABI_2635_TRACEPOINT */ + +#endif /* _LTTNG_WRAPPER_TRACEPOINT_H */ -- 2.34.1