diff options
-rw-r--r-- | include/linux/ftrace.h | 16 | ||||
-rw-r--r-- | kernel/trace/ftrace.c | 106 |
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 | ||
98 | struct 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 { | |||
119 | int ftrace_force_update(void); | 126 | int ftrace_force_update(void); |
120 | void ftrace_set_filter(unsigned char *buf, int len, int reset); | 127 | void ftrace_set_filter(unsigned char *buf, int len, int reset); |
121 | 128 | ||
129 | int register_ftrace_command(struct ftrace_func_command *cmd); | ||
130 | int unregister_ftrace_command(struct ftrace_func_command *cmd); | ||
131 | |||
122 | /* defined in arch */ | 132 | /* defined in arch */ |
123 | extern int ftrace_ip_converted(unsigned long ip); | 133 | extern int ftrace_ip_converted(unsigned long ip); |
124 | extern int ftrace_dyn_arch_init(void *data); | 134 | extern 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) |
204 | static inline void ftrace_release(void *start, unsigned long size) { } | 214 | static inline void ftrace_release(void *start, unsigned long size) { } |
215 | static inline int register_ftrace_command(struct ftrace_func_command *cmd) | ||
216 | { | ||
217 | } | ||
218 | static 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 | |||
1247 | static int | ||
1248 | ftrace_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(¶m, ":"); | ||
1265 | if (!strlen(mod)) | ||
1266 | return -EINVAL; | ||
1267 | |||
1268 | ftrace_match_module_records(func, mod, enable); | ||
1269 | return 0; | ||
1270 | } | ||
1271 | |||
1272 | static struct ftrace_func_command ftrace_mod_cmd = { | ||
1273 | .name = "mod", | ||
1274 | .func = ftrace_mod_callback, | ||
1275 | }; | ||
1276 | |||
1277 | static int __init ftrace_mod_cmd_init(void) | ||
1278 | { | ||
1279 | return register_ftrace_command(&ftrace_mod_cmd); | ||
1280 | } | ||
1281 | device_initcall(ftrace_mod_cmd_init); | ||
1282 | |||
1283 | static LIST_HEAD(ftrace_commands); | ||
1284 | static DEFINE_MUTEX(ftrace_cmd_mutex); | ||
1285 | |||
1286 | int 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 | |||
1305 | int 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 | |||
1242 | static int ftrace_process_regex(char *buff, int len, int enable) | 1324 | static 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 | ||
1270 | static ssize_t | 1354 | static ssize_t |