Skip to content

Commit

Permalink
Linux Kernel Markers: support multiple probes
Browse files Browse the repository at this point in the history
RCU style multiple probes support for the Linux Kernel Markers.  Common case
(one probe) is still fast and does not require dynamic allocation or a
supplementary pointer dereference on the fast path.

- Move preempt disable from the marker site to the callback.

Since we now have an internal callback, move the preempt disable/enable to the
callback instead of the marker site.

Since the callback change is done asynchronously (passing from a handler that
supports arguments to a handler that does not setup the arguments is no
arguments are passed), we can safely update it even if it is outside the
preempt disable section.

- Move probe arm to probe connection. Now, a connected probe is automatically
  armed.

Remove MARK_MAX_FORMAT_LEN, unused.

This patch modifies the Linux Kernel Markers API : it removes the probe
"arm/disarm" and changes the probe function prototype : it now expects a
va_list * instead of a "...".

If we want to have more than one probe connected to a marker at a given
time (LTTng, or blktrace, ssytemtap) then we need this patch. Without it,
connecting a second probe handler to a marker will fail.

It allow us, for instance, to do interesting combinations :

Do standard tracing with LTTng and, eventually, to compute statistics
with SystemTAP, or to have a special trigger on an event that would call
a systemtap script which would stop flight recorder tracing.

Signed-off-by: Mathieu Desnoyers <[email protected]>
Cc: Christoph Hellwig <[email protected]>
Cc: Mike Mason <[email protected]>
Cc: Dipankar Sarma <[email protected]>
Cc: David Smith <[email protected]>
Cc: "Paul E. McKenney" <[email protected]>
Cc: "Frank Ch. Eigler" <[email protected]>
Cc: Steven Rostedt <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Mathieu Desnoyers authored and Linus Torvalds committed Feb 14, 2008
1 parent 9170d2f commit fb40bd7
Show file tree
Hide file tree
Showing 6 changed files with 565 additions and 236 deletions.
31 changes: 11 additions & 20 deletions arch/powerpc/platforms/cell/spufs/sputrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,34 +146,28 @@ static void sputrace_log_item(const char *name, struct spu_context *ctx,
wake_up(&sputrace_wait);
}

static void spu_context_event(const struct marker *mdata,
void *private, const char *format, ...)
static void spu_context_event(void *probe_private, void *call_data,
const char *format, va_list *args)
{
struct spu_probe *p = mdata->private;
va_list ap;
struct spu_probe *p = probe_private;
struct spu_context *ctx;
struct spu *spu;

va_start(ap, format);
ctx = va_arg(ap, struct spu_context *);
spu = va_arg(ap, struct spu *);
ctx = va_arg(*args, struct spu_context *);
spu = va_arg(*args, struct spu *);

sputrace_log_item(p->name, ctx, spu);
va_end(ap);
}

static void spu_context_nospu_event(const struct marker *mdata,
void *private, const char *format, ...)
static void spu_context_nospu_event(void *probe_private, void *call_data,
const char *format, va_list *args)
{
struct spu_probe *p = mdata->private;
va_list ap;
struct spu_probe *p = probe_private;
struct spu_context *ctx;

va_start(ap, format);
ctx = va_arg(ap, struct spu_context *);
ctx = va_arg(*args, struct spu_context *);

sputrace_log_item(p->name, ctx, NULL);
va_end(ap);
}

struct spu_probe spu_probes[] = {
Expand Down Expand Up @@ -219,10 +213,6 @@ static int __init sputrace_init(void)
if (error)
printk(KERN_INFO "Unable to register probe %s\n",
p->name);

error = marker_arm(p->name);
if (error)
printk(KERN_INFO "Unable to arm probe %s\n", p->name);
}

return 0;
Expand All @@ -238,7 +228,8 @@ static void __exit sputrace_exit(void)
int i;

for (i = 0; i < ARRAY_SIZE(spu_probes); i++)
marker_probe_unregister(spu_probes[i].name);
marker_probe_unregister(spu_probes[i].name,
spu_probes[i].probe_func, &spu_probes[i]);

remove_proc_entry("sputrace", NULL);
kfree(sputrace_log);
Expand Down
59 changes: 36 additions & 23 deletions include/linux/marker.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,35 @@ struct marker;

/**
* marker_probe_func - Type of a marker probe function
* @mdata: pointer of type struct marker
* @private_data: caller site private data
* @probe_private: probe private data
* @call_private: call site private data
* @fmt: format string
* @...: variable argument list
* @args: variable argument list pointer. Use a pointer to overcome C's
* inability to pass this around as a pointer in a portable manner in
* the callee otherwise.
*
* Type of marker probe functions. They receive the mdata and need to parse the
* format string to recover the variable argument list.
*/
typedef void marker_probe_func(const struct marker *mdata,
void *private_data, const char *fmt, ...);
typedef void marker_probe_func(void *probe_private, void *call_private,
const char *fmt, va_list *args);

struct marker_probe_closure {
marker_probe_func *func; /* Callback */
void *probe_private; /* Private probe data */
};

struct marker {
const char *name; /* Marker name */
const char *format; /* Marker format string, describing the
* variable argument list.
*/
char state; /* Marker state. */
marker_probe_func *call;/* Probe handler function pointer */
void *private; /* Private probe data */
char ptype; /* probe type : 0 : single, 1 : multi */
void (*call)(const struct marker *mdata, /* Probe wrapper */
void *call_private, const char *fmt, ...);
struct marker_probe_closure single;
struct marker_probe_closure *multi;
} __attribute__((aligned(8)));

#ifdef CONFIG_MARKERS
Expand All @@ -49,7 +59,7 @@ struct marker {
* not add unwanted padding between the beginning of the section and the
* structure. Force alignment to the same alignment as the section start.
*/
#define __trace_mark(name, call_data, format, args...) \
#define __trace_mark(name, call_private, format, args...) \
do { \
static const char __mstrtab_name_##name[] \
__attribute__((section("__markers_strings"))) \
Expand All @@ -60,24 +70,23 @@ struct marker {
static struct marker __mark_##name \
__attribute__((section("__markers"), aligned(8))) = \
{ __mstrtab_name_##name, __mstrtab_format_##name, \
0, __mark_empty_function, NULL }; \
0, 0, marker_probe_cb, \
{ __mark_empty_function, NULL}, NULL }; \
__mark_check_format(format, ## args); \
if (unlikely(__mark_##name.state)) { \
preempt_disable(); \
(*__mark_##name.call) \
(&__mark_##name, call_data, \
(&__mark_##name, call_private, \
format, ## args); \
preempt_enable(); \
} \
} while (0)

extern void marker_update_probe_range(struct marker *begin,
struct marker *end, struct module *probe_module, int *refcount);
struct marker *end);
#else /* !CONFIG_MARKERS */
#define __trace_mark(name, call_data, format, args...) \
#define __trace_mark(name, call_private, format, args...) \
__mark_check_format(format, ## args)
static inline void marker_update_probe_range(struct marker *begin,
struct marker *end, struct module *probe_module, int *refcount)
struct marker *end)
{ }
#endif /* CONFIG_MARKERS */

Expand All @@ -92,8 +101,6 @@ static inline void marker_update_probe_range(struct marker *begin,
#define trace_mark(name, format, args...) \
__trace_mark(name, NULL, format, ## args)

#define MARK_MAX_FORMAT_LEN 1024

/**
* MARK_NOARGS - Format string for a marker with no argument.
*/
Expand All @@ -106,24 +113,30 @@ static inline void __printf(1, 2) __mark_check_format(const char *fmt, ...)

extern marker_probe_func __mark_empty_function;

extern void marker_probe_cb(const struct marker *mdata,
void *call_private, const char *fmt, ...);
extern void marker_probe_cb_noarg(const struct marker *mdata,
void *call_private, const char *fmt, ...);

/*
* Connect a probe to a marker.
* private data pointer must be a valid allocated memory address, or NULL.
*/
extern int marker_probe_register(const char *name, const char *format,
marker_probe_func *probe, void *private);
marker_probe_func *probe, void *probe_private);

/*
* Returns the private data given to marker_probe_register.
*/
extern void *marker_probe_unregister(const char *name);
extern int marker_probe_unregister(const char *name,
marker_probe_func *probe, void *probe_private);
/*
* Unregister a marker by providing the registered private data.
*/
extern void *marker_probe_unregister_private_data(void *private);
extern int marker_probe_unregister_private_data(marker_probe_func *probe,
void *probe_private);

extern int marker_arm(const char *name);
extern int marker_disarm(const char *name);
extern void *marker_get_private_data(const char *name);
extern void *marker_get_private_data(const char *name, marker_probe_func *probe,
int num);

#endif
2 changes: 1 addition & 1 deletion include/linux/module.h
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ int unregister_module_notifier(struct notifier_block * nb);

extern void print_modules(void);

extern void module_update_markers(struct module *probe_module, int *refcount);
extern void module_update_markers(void);

#else /* !CONFIG_MODULES... */
#define EXPORT_SYMBOL(sym)
Expand Down
Loading

0 comments on commit fb40bd7

Please sign in to comment.