Skip to content

Commit

Permalink
ftrace: add command interface for function selection
Browse files Browse the repository at this point in the history
Allow for other tracers to add their own commands for function
selection. This interface gives a trace the ability to name a
command for function selection. Right now it is pretty limited
in what it offers, but this is a building step for more features.

The :mod: command is converted to this interface and also serves
as a template for other implementations.

Signed-off-by: Steven Rostedt <srostedt@redhat.com>
  • Loading branch information
Steven Rostedt committed Feb 16, 2009
1 parent e68746a commit f618077
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 11 deletions.
16 changes: 16 additions & 0 deletions include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ stack_trace_sysctl(struct ctl_table *table, int write,
loff_t *ppos);
#endif

struct ftrace_func_command {
struct list_head list;
char *name;
int (*func)(char *func, char *cmd,
char *params, int enable);
};

#ifdef CONFIG_DYNAMIC_FTRACE
/* asm/ftrace.h must be defined for archs supporting dynamic ftrace */
#include <asm/ftrace.h>
Expand All @@ -119,6 +126,9 @@ struct dyn_ftrace {
int ftrace_force_update(void);
void ftrace_set_filter(unsigned char *buf, int len, int reset);

int register_ftrace_command(struct ftrace_func_command *cmd);
int unregister_ftrace_command(struct ftrace_func_command *cmd);

/* defined in arch */
extern int ftrace_ip_converted(unsigned long ip);
extern int ftrace_dyn_arch_init(void *data);
Expand Down Expand Up @@ -202,6 +212,12 @@ extern void ftrace_enable_daemon(void);
# define ftrace_disable_daemon() do { } while (0)
# define ftrace_enable_daemon() do { } while (0)
static inline void ftrace_release(void *start, unsigned long size) { }
static inline int register_ftrace_command(struct ftrace_func_command *cmd)
{
}
static inline int unregister_ftrace_command(char *cmd_name)
{
}
#endif /* CONFIG_DYNAMIC_FTRACE */

/* totally disable ftrace - can not re-enable after this */
Expand Down
106 changes: 95 additions & 11 deletions kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1239,9 +1239,93 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable)
spin_unlock(&ftrace_lock);
}

/*
* We register the module command as a template to show others how
* to register the a command as well.
*/

static int
ftrace_mod_callback(char *func, char *cmd, char *param, int enable)
{
char *mod;

/*
* cmd == 'mod' because we only registered this func
* for the 'mod' ftrace_func_command.
* But if you register one func with multiple commands,
* you can tell which command was used by the cmd
* parameter.
*/

/* we must have a module name */
if (!param)
return -EINVAL;

mod = strsep(&param, ":");
if (!strlen(mod))
return -EINVAL;

ftrace_match_module_records(func, mod, enable);
return 0;
}

static struct ftrace_func_command ftrace_mod_cmd = {
.name = "mod",
.func = ftrace_mod_callback,
};

static int __init ftrace_mod_cmd_init(void)
{
return register_ftrace_command(&ftrace_mod_cmd);
}
device_initcall(ftrace_mod_cmd_init);

static LIST_HEAD(ftrace_commands);
static DEFINE_MUTEX(ftrace_cmd_mutex);

int register_ftrace_command(struct ftrace_func_command *cmd)
{
struct ftrace_func_command *p;
int ret = 0;

mutex_lock(&ftrace_cmd_mutex);
list_for_each_entry(p, &ftrace_commands, list) {
if (strcmp(cmd->name, p->name) == 0) {
ret = -EBUSY;
goto out_unlock;
}
}
list_add(&cmd->list, &ftrace_commands);
out_unlock:
mutex_unlock(&ftrace_cmd_mutex);

return ret;
}

int unregister_ftrace_command(struct ftrace_func_command *cmd)
{
struct ftrace_func_command *p, *n;
int ret = -ENODEV;

mutex_lock(&ftrace_cmd_mutex);
list_for_each_entry_safe(p, n, &ftrace_commands, list) {
if (strcmp(cmd->name, p->name) == 0) {
ret = 0;
list_del_init(&p->list);
goto out_unlock;
}
}
out_unlock:
mutex_unlock(&ftrace_cmd_mutex);

return ret;
}

static int ftrace_process_regex(char *buff, int len, int enable)
{
char *func, *mod, *command, *next = buff;
struct ftrace_func_command *p;
char *func, *command, *next = buff;
int ret = -EINVAL;

func = strsep(&next, ":");

Expand All @@ -1250,21 +1334,21 @@ static int ftrace_process_regex(char *buff, int len, int enable)
return 0;
}

/* command fonud */
/* command found */

command = strsep(&next, ":");

if (strcmp(command, "mod") == 0) {
/* only match modules */
if (!next)
return -EINVAL;

mod = strsep(&next, ":");
ftrace_match_module_records(func, mod, enable);
return 0;
mutex_lock(&ftrace_cmd_mutex);
list_for_each_entry(p, &ftrace_commands, list) {
if (strcmp(p->name, command) == 0) {
ret = p->func(func, command, next, enable);
goto out_unlock;
}
}
out_unlock:
mutex_unlock(&ftrace_cmd_mutex);

return -EINVAL;
return ret;
}

static ssize_t
Expand Down

0 comments on commit f618077

Please sign in to comment.