diff options
author | Steven Rostedt <srostedt@redhat.com> | 2009-02-14 00:40:25 -0500 |
---|---|---|
committer | Steven Rostedt <srostedt@redhat.com> | 2009-02-16 17:06:02 -0500 |
commit | f6180773d90595650e11de0118bb112018290915 (patch) | |
tree | ccf8642d7ac584f73e7820fae64fc4daf4546f6b /kernel/trace/ftrace.c | |
parent | e68746a271eb3393a2183840be9e903caddf765b (diff) |
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>
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 106 |
1 files changed, 95 insertions, 11 deletions
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 |