aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ftrace.h16
-rw-r--r--kernel/trace/ftrace.c106
2 files changed, 111 insertions, 11 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 106b7909d500..f0a0ecc63b5c 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -95,6 +95,13 @@ stack_trace_sysctl(struct ctl_table *table, int write,
95 loff_t *ppos); 95 loff_t *ppos);
96#endif 96#endif
97 97
98struct ftrace_func_command {
99 struct list_head list;
100 char *name;
101 int (*func)(char *func, char *cmd,
102 char *params, int enable);
103};
104
98#ifdef CONFIG_DYNAMIC_FTRACE 105#ifdef CONFIG_DYNAMIC_FTRACE
99/* asm/ftrace.h must be defined for archs supporting dynamic ftrace */ 106/* asm/ftrace.h must be defined for archs supporting dynamic ftrace */
100#include <asm/ftrace.h> 107#include <asm/ftrace.h>
@@ -119,6 +126,9 @@ struct dyn_ftrace {
119int ftrace_force_update(void); 126int ftrace_force_update(void);
120void ftrace_set_filter(unsigned char *buf, int len, int reset); 127void ftrace_set_filter(unsigned char *buf, int len, int reset);
121 128
129int register_ftrace_command(struct ftrace_func_command *cmd);
130int unregister_ftrace_command(struct ftrace_func_command *cmd);
131
122/* defined in arch */ 132/* defined in arch */
123extern int ftrace_ip_converted(unsigned long ip); 133extern int ftrace_ip_converted(unsigned long ip);
124extern int ftrace_dyn_arch_init(void *data); 134extern int ftrace_dyn_arch_init(void *data);
@@ -202,6 +212,12 @@ extern void ftrace_enable_daemon(void);
202# define ftrace_disable_daemon() do { } while (0) 212# define ftrace_disable_daemon() do { } while (0)
203# define ftrace_enable_daemon() do { } while (0) 213# define ftrace_enable_daemon() do { } while (0)
204static inline void ftrace_release(void *start, unsigned long size) { } 214static inline void ftrace_release(void *start, unsigned long size) { }
215static inline int register_ftrace_command(struct ftrace_func_command *cmd)
216{
217}
218static inline int unregister_ftrace_command(char *cmd_name)
219{
220}
205#endif /* CONFIG_DYNAMIC_FTRACE */ 221#endif /* CONFIG_DYNAMIC_FTRACE */
206 222
207/* totally disable ftrace - can not re-enable after this */ 223/* totally disable ftrace - can not re-enable after this */
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 340f88b68d9e..45a44c402566 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1239,9 +1239,93 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable)
1239 spin_unlock(&ftrace_lock); 1239 spin_unlock(&ftrace_lock);
1240} 1240}
1241 1241
1242/*
1243 * We register the module command as a template to show others how
1244 * to register the a command as well.
1245 */
1246
1247static int
1248ftrace_mod_callback(char *func, char *cmd, char *param, int enable)
1249{
1250 char *mod;
1251
1252 /*
1253 * cmd == 'mod' because we only registered this func
1254 * for the 'mod' ftrace_func_command.
1255 * But if you register one func with multiple commands,
1256 * you can tell which command was used by the cmd
1257 * parameter.
1258 */
1259
1260 /* we must have a module name */
1261 if (!param)
1262 return -EINVAL;
1263
1264 mod = strsep(&param, ":");
1265 if (!strlen(mod))
1266 return -EINVAL;
1267
1268 ftrace_match_module_records(func, mod, enable);
1269 return 0;
1270}
1271
1272static struct ftrace_func_command ftrace_mod_cmd = {
1273 .name = "mod",
1274 .func = ftrace_mod_callback,
1275};
1276
1277static int __init ftrace_mod_cmd_init(void)
1278{
1279 return register_ftrace_command(&ftrace_mod_cmd);
1280}
1281device_initcall(ftrace_mod_cmd_init);
1282
1283static LIST_HEAD(ftrace_commands);
1284static DEFINE_MUTEX(ftrace_cmd_mutex);
1285
1286int register_ftrace_command(struct ftrace_func_command *cmd)
1287{
1288 struct ftrace_func_command *p;
1289 int ret = 0;
1290
1291 mutex_lock(&ftrace_cmd_mutex);
1292 list_for_each_entry(p, &ftrace_commands, list) {
1293 if (strcmp(cmd->name, p->name) == 0) {
1294 ret = -EBUSY;
1295 goto out_unlock;
1296 }
1297 }
1298 list_add(&cmd->list, &ftrace_commands);
1299 out_unlock:
1300 mutex_unlock(&ftrace_cmd_mutex);
1301
1302 return ret;
1303}
1304
1305int unregister_ftrace_command(struct ftrace_func_command *cmd)
1306{
1307 struct ftrace_func_command *p, *n;
1308 int ret = -ENODEV;
1309
1310 mutex_lock(&ftrace_cmd_mutex);
1311 list_for_each_entry_safe(p, n, &ftrace_commands, list) {
1312 if (strcmp(cmd->name, p->name) == 0) {
1313 ret = 0;
1314 list_del_init(&p->list);
1315 goto out_unlock;
1316 }
1317 }
1318 out_unlock:
1319 mutex_unlock(&ftrace_cmd_mutex);
1320
1321 return ret;
1322}
1323
1242static int ftrace_process_regex(char *buff, int len, int enable) 1324static int ftrace_process_regex(char *buff, int len, int enable)
1243{ 1325{
1244 char *func, *mod, *command, *next = buff; 1326 struct ftrace_func_command *p;
1327 char *func, *command, *next = buff;
1328 int ret = -EINVAL;
1245 1329
1246 func = strsep(&next, ":"); 1330 func = strsep(&next, ":");
1247 1331
@@ -1250,21 +1334,21 @@ static int ftrace_process_regex(char *buff, int len, int enable)
1250 return 0; 1334 return 0;
1251 } 1335 }
1252 1336
1253 /* command fonud */ 1337 /* command found */
1254 1338
1255 command = strsep(&next, ":"); 1339 command = strsep(&next, ":");
1256 1340
1257 if (strcmp(command, "mod") == 0) { 1341 mutex_lock(&ftrace_cmd_mutex);
1258 /* only match modules */ 1342 list_for_each_entry(p, &ftrace_commands, list) {
1259 if (!next) 1343 if (strcmp(p->name, command) == 0) {
1260 return -EINVAL; 1344 ret = p->func(func, command, next, enable);
1261 1345 goto out_unlock;
1262 mod = strsep(&next, ":"); 1346 }
1263 ftrace_match_module_records(func, mod, enable);
1264 return 0;
1265 } 1347 }
1348 out_unlock:
1349 mutex_unlock(&ftrace_cmd_mutex);
1266 1350
1267 return -EINVAL; 1351 return ret;
1268} 1352}
1269 1353
1270static ssize_t 1354static ssize_t