ftrace: add command interface for function selection
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>
This commit is contained in:
@@ -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(¶m, ":");
|
||||
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, ":");
|
||||
|
||||
@@ -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
|
||||
|
Reference in New Issue
Block a user