diff options
Diffstat (limited to 'kernel/trace/trace_events.c')
| -rw-r--r-- | kernel/trace/trace_events.c | 116 |
1 files changed, 78 insertions, 38 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 29111da1d100..d608d09d08c0 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -1199,6 +1199,31 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 1199 | return 0; | 1199 | return 0; |
| 1200 | } | 1200 | } |
| 1201 | 1201 | ||
| 1202 | static void event_remove(struct ftrace_event_call *call) | ||
| 1203 | { | ||
| 1204 | ftrace_event_enable_disable(call, 0); | ||
| 1205 | if (call->event.funcs) | ||
| 1206 | __unregister_ftrace_event(&call->event); | ||
| 1207 | list_del(&call->list); | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | static int event_init(struct ftrace_event_call *call) | ||
| 1211 | { | ||
| 1212 | int ret = 0; | ||
| 1213 | |||
| 1214 | if (WARN_ON(!call->name)) | ||
| 1215 | return -EINVAL; | ||
| 1216 | |||
| 1217 | if (call->class->raw_init) { | ||
| 1218 | ret = call->class->raw_init(call); | ||
| 1219 | if (ret < 0 && ret != -ENOSYS) | ||
| 1220 | pr_warn("Could not initialize trace events/%s\n", | ||
| 1221 | call->name); | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | return ret; | ||
| 1225 | } | ||
| 1226 | |||
| 1202 | static int | 1227 | static int |
| 1203 | __trace_add_event_call(struct ftrace_event_call *call, struct module *mod, | 1228 | __trace_add_event_call(struct ftrace_event_call *call, struct module *mod, |
| 1204 | const struct file_operations *id, | 1229 | const struct file_operations *id, |
| @@ -1209,19 +1234,9 @@ __trace_add_event_call(struct ftrace_event_call *call, struct module *mod, | |||
| 1209 | struct dentry *d_events; | 1234 | struct dentry *d_events; |
| 1210 | int ret; | 1235 | int ret; |
| 1211 | 1236 | ||
| 1212 | /* The linker may leave blanks */ | 1237 | ret = event_init(call); |
| 1213 | if (!call->name) | 1238 | if (ret < 0) |
| 1214 | return -EINVAL; | 1239 | return ret; |
| 1215 | |||
| 1216 | if (call->class->raw_init) { | ||
| 1217 | ret = call->class->raw_init(call); | ||
| 1218 | if (ret < 0) { | ||
| 1219 | if (ret != -ENOSYS) | ||
| 1220 | pr_warning("Could not initialize trace events/%s\n", | ||
| 1221 | call->name); | ||
| 1222 | return ret; | ||
| 1223 | } | ||
| 1224 | } | ||
| 1225 | 1240 | ||
| 1226 | d_events = event_trace_events_dir(); | 1241 | d_events = event_trace_events_dir(); |
| 1227 | if (!d_events) | 1242 | if (!d_events) |
| @@ -1272,13 +1287,10 @@ static void remove_subsystem_dir(const char *name) | |||
| 1272 | */ | 1287 | */ |
| 1273 | static void __trace_remove_event_call(struct ftrace_event_call *call) | 1288 | static void __trace_remove_event_call(struct ftrace_event_call *call) |
| 1274 | { | 1289 | { |
| 1275 | ftrace_event_enable_disable(call, 0); | 1290 | event_remove(call); |
| 1276 | if (call->event.funcs) | ||
| 1277 | __unregister_ftrace_event(&call->event); | ||
| 1278 | debugfs_remove_recursive(call->dir); | ||
| 1279 | list_del(&call->list); | ||
| 1280 | trace_destroy_fields(call); | 1291 | trace_destroy_fields(call); |
| 1281 | destroy_preds(call); | 1292 | destroy_preds(call); |
| 1293 | debugfs_remove_recursive(call->dir); | ||
| 1282 | remove_subsystem_dir(call->class->system); | 1294 | remove_subsystem_dir(call->class->system); |
| 1283 | } | 1295 | } |
| 1284 | 1296 | ||
| @@ -1450,15 +1462,43 @@ static __init int setup_trace_event(char *str) | |||
| 1450 | } | 1462 | } |
| 1451 | __setup("trace_event=", setup_trace_event); | 1463 | __setup("trace_event=", setup_trace_event); |
| 1452 | 1464 | ||
| 1465 | static __init int event_trace_enable(void) | ||
| 1466 | { | ||
| 1467 | struct ftrace_event_call **iter, *call; | ||
| 1468 | char *buf = bootup_event_buf; | ||
| 1469 | char *token; | ||
| 1470 | int ret; | ||
| 1471 | |||
| 1472 | for_each_event(iter, __start_ftrace_events, __stop_ftrace_events) { | ||
| 1473 | |||
| 1474 | call = *iter; | ||
| 1475 | ret = event_init(call); | ||
| 1476 | if (!ret) | ||
| 1477 | list_add(&call->list, &ftrace_events); | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | while (true) { | ||
| 1481 | token = strsep(&buf, ","); | ||
| 1482 | |||
| 1483 | if (!token) | ||
| 1484 | break; | ||
| 1485 | if (!*token) | ||
| 1486 | continue; | ||
| 1487 | |||
| 1488 | ret = ftrace_set_clr_event(token, 1); | ||
| 1489 | if (ret) | ||
| 1490 | pr_warn("Failed to enable trace event: %s\n", token); | ||
| 1491 | } | ||
| 1492 | return 0; | ||
| 1493 | } | ||
| 1494 | |||
| 1453 | static __init int event_trace_init(void) | 1495 | static __init int event_trace_init(void) |
| 1454 | { | 1496 | { |
| 1455 | struct ftrace_event_call **call; | 1497 | struct ftrace_event_call *call; |
| 1456 | struct dentry *d_tracer; | 1498 | struct dentry *d_tracer; |
| 1457 | struct dentry *entry; | 1499 | struct dentry *entry; |
| 1458 | struct dentry *d_events; | 1500 | struct dentry *d_events; |
| 1459 | int ret; | 1501 | int ret; |
| 1460 | char *buf = bootup_event_buf; | ||
| 1461 | char *token; | ||
| 1462 | 1502 | ||
| 1463 | d_tracer = tracing_init_dentry(); | 1503 | d_tracer = tracing_init_dentry(); |
| 1464 | if (!d_tracer) | 1504 | if (!d_tracer) |
| @@ -1497,24 +1537,19 @@ static __init int event_trace_init(void) | |||
| 1497 | if (trace_define_common_fields()) | 1537 | if (trace_define_common_fields()) |
| 1498 | pr_warning("tracing: Failed to allocate common fields"); | 1538 | pr_warning("tracing: Failed to allocate common fields"); |
| 1499 | 1539 | ||
| 1500 | for_each_event(call, __start_ftrace_events, __stop_ftrace_events) { | 1540 | /* |
| 1501 | __trace_add_event_call(*call, NULL, &ftrace_event_id_fops, | 1541 | * Early initialization already enabled ftrace event. |
| 1542 | * Now it's only necessary to create the event directory. | ||
| 1543 | */ | ||
| 1544 | list_for_each_entry(call, &ftrace_events, list) { | ||
| 1545 | |||
| 1546 | ret = event_create_dir(call, d_events, | ||
| 1547 | &ftrace_event_id_fops, | ||
| 1502 | &ftrace_enable_fops, | 1548 | &ftrace_enable_fops, |
| 1503 | &ftrace_event_filter_fops, | 1549 | &ftrace_event_filter_fops, |
| 1504 | &ftrace_event_format_fops); | 1550 | &ftrace_event_format_fops); |
| 1505 | } | 1551 | if (ret < 0) |
| 1506 | 1552 | event_remove(call); | |
| 1507 | while (true) { | ||
| 1508 | token = strsep(&buf, ","); | ||
| 1509 | |||
| 1510 | if (!token) | ||
| 1511 | break; | ||
| 1512 | if (!*token) | ||
| 1513 | continue; | ||
| 1514 | |||
| 1515 | ret = ftrace_set_clr_event(token, 1); | ||
| 1516 | if (ret) | ||
| 1517 | pr_warning("Failed to enable trace event: %s\n", token); | ||
| 1518 | } | 1553 | } |
| 1519 | 1554 | ||
| 1520 | ret = register_module_notifier(&trace_module_nb); | 1555 | ret = register_module_notifier(&trace_module_nb); |
| @@ -1523,6 +1558,7 @@ static __init int event_trace_init(void) | |||
| 1523 | 1558 | ||
| 1524 | return 0; | 1559 | return 0; |
| 1525 | } | 1560 | } |
| 1561 | core_initcall(event_trace_enable); | ||
| 1526 | fs_initcall(event_trace_init); | 1562 | fs_initcall(event_trace_init); |
| 1527 | 1563 | ||
| 1528 | #ifdef CONFIG_FTRACE_STARTUP_TEST | 1564 | #ifdef CONFIG_FTRACE_STARTUP_TEST |
| @@ -1646,9 +1682,11 @@ static __init void event_trace_self_tests(void) | |||
| 1646 | event_test_stuff(); | 1682 | event_test_stuff(); |
| 1647 | 1683 | ||
| 1648 | ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0); | 1684 | ret = __ftrace_set_clr_event(NULL, system->name, NULL, 0); |
| 1649 | if (WARN_ON_ONCE(ret)) | 1685 | if (WARN_ON_ONCE(ret)) { |
| 1650 | pr_warning("error disabling system %s\n", | 1686 | pr_warning("error disabling system %s\n", |
| 1651 | system->name); | 1687 | system->name); |
| 1688 | continue; | ||
| 1689 | } | ||
| 1652 | 1690 | ||
| 1653 | pr_cont("OK\n"); | 1691 | pr_cont("OK\n"); |
| 1654 | } | 1692 | } |
| @@ -1681,7 +1719,8 @@ static __init void event_trace_self_tests(void) | |||
| 1681 | static DEFINE_PER_CPU(atomic_t, ftrace_test_event_disable); | 1719 | static DEFINE_PER_CPU(atomic_t, ftrace_test_event_disable); |
| 1682 | 1720 | ||
| 1683 | static void | 1721 | static void |
| 1684 | function_test_events_call(unsigned long ip, unsigned long parent_ip) | 1722 | function_test_events_call(unsigned long ip, unsigned long parent_ip, |
| 1723 | struct ftrace_ops *op, struct pt_regs *pt_regs) | ||
| 1685 | { | 1724 | { |
| 1686 | struct ring_buffer_event *event; | 1725 | struct ring_buffer_event *event; |
| 1687 | struct ring_buffer *buffer; | 1726 | struct ring_buffer *buffer; |
| @@ -1720,6 +1759,7 @@ function_test_events_call(unsigned long ip, unsigned long parent_ip) | |||
| 1720 | static struct ftrace_ops trace_ops __initdata = | 1759 | static struct ftrace_ops trace_ops __initdata = |
| 1721 | { | 1760 | { |
| 1722 | .func = function_test_events_call, | 1761 | .func = function_test_events_call, |
| 1762 | .flags = FTRACE_OPS_FL_RECURSION_SAFE, | ||
| 1723 | }; | 1763 | }; |
| 1724 | 1764 | ||
| 1725 | static __init void event_trace_self_test_with_function(void) | 1765 | static __init void event_trace_self_test_with_function(void) |
