diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 603 |
1 files changed, 307 insertions, 296 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8c804e24f96f..b10c0d90a6ff 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -60,6 +60,13 @@ static int last_ftrace_enabled; | |||
60 | /* Quick disabling of function tracer. */ | 60 | /* Quick disabling of function tracer. */ |
61 | int function_trace_stop; | 61 | int function_trace_stop; |
62 | 62 | ||
63 | /* List for set_ftrace_pid's pids. */ | ||
64 | LIST_HEAD(ftrace_pids); | ||
65 | struct ftrace_pid { | ||
66 | struct list_head list; | ||
67 | struct pid *pid; | ||
68 | }; | ||
69 | |||
63 | /* | 70 | /* |
64 | * ftrace_disabled is set when an anomaly is discovered. | 71 | * ftrace_disabled is set when an anomaly is discovered. |
65 | * ftrace_disabled is much stronger than ftrace_enabled. | 72 | * ftrace_disabled is much stronger than ftrace_enabled. |
@@ -78,6 +85,10 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | |||
78 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; | 85 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; |
79 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; | 86 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; |
80 | 87 | ||
88 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
89 | static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); | ||
90 | #endif | ||
91 | |||
81 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) | 92 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) |
82 | { | 93 | { |
83 | struct ftrace_ops *op = ftrace_list; | 94 | struct ftrace_ops *op = ftrace_list; |
@@ -155,7 +166,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
155 | else | 166 | else |
156 | func = ftrace_list_func; | 167 | func = ftrace_list_func; |
157 | 168 | ||
158 | if (ftrace_pid_trace) { | 169 | if (!list_empty(&ftrace_pids)) { |
159 | set_ftrace_pid_function(func); | 170 | set_ftrace_pid_function(func); |
160 | func = ftrace_pid_func; | 171 | func = ftrace_pid_func; |
161 | } | 172 | } |
@@ -203,7 +214,7 @@ static int __unregister_ftrace_function(struct ftrace_ops *ops) | |||
203 | if (ftrace_list->next == &ftrace_list_end) { | 214 | if (ftrace_list->next == &ftrace_list_end) { |
204 | ftrace_func_t func = ftrace_list->func; | 215 | ftrace_func_t func = ftrace_list->func; |
205 | 216 | ||
206 | if (ftrace_pid_trace) { | 217 | if (!list_empty(&ftrace_pids)) { |
207 | set_ftrace_pid_function(func); | 218 | set_ftrace_pid_function(func); |
208 | func = ftrace_pid_func; | 219 | func = ftrace_pid_func; |
209 | } | 220 | } |
@@ -225,9 +236,13 @@ static void ftrace_update_pid_func(void) | |||
225 | if (ftrace_trace_function == ftrace_stub) | 236 | if (ftrace_trace_function == ftrace_stub) |
226 | return; | 237 | return; |
227 | 238 | ||
239 | #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST | ||
228 | func = ftrace_trace_function; | 240 | func = ftrace_trace_function; |
241 | #else | ||
242 | func = __ftrace_trace_function; | ||
243 | #endif | ||
229 | 244 | ||
230 | if (ftrace_pid_trace) { | 245 | if (!list_empty(&ftrace_pids)) { |
231 | set_ftrace_pid_function(func); | 246 | set_ftrace_pid_function(func); |
232 | func = ftrace_pid_func; | 247 | func = ftrace_pid_func; |
233 | } else { | 248 | } else { |
@@ -817,8 +832,6 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer) | |||
817 | } | 832 | } |
818 | #endif /* CONFIG_FUNCTION_PROFILER */ | 833 | #endif /* CONFIG_FUNCTION_PROFILER */ |
819 | 834 | ||
820 | /* set when tracing only a pid */ | ||
821 | struct pid *ftrace_pid_trace; | ||
822 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; | 835 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; |
823 | 836 | ||
824 | #ifdef CONFIG_DYNAMIC_FTRACE | 837 | #ifdef CONFIG_DYNAMIC_FTRACE |
@@ -1074,14 +1087,9 @@ static void ftrace_replace_code(int enable) | |||
1074 | failed = __ftrace_replace_code(rec, enable); | 1087 | failed = __ftrace_replace_code(rec, enable); |
1075 | if (failed) { | 1088 | if (failed) { |
1076 | rec->flags |= FTRACE_FL_FAILED; | 1089 | rec->flags |= FTRACE_FL_FAILED; |
1077 | if ((system_state == SYSTEM_BOOTING) || | 1090 | ftrace_bug(failed, rec->ip); |
1078 | !core_kernel_text(rec->ip)) { | 1091 | /* Stop processing */ |
1079 | ftrace_free_rec(rec); | 1092 | return; |
1080 | } else { | ||
1081 | ftrace_bug(failed, rec->ip); | ||
1082 | /* Stop processing */ | ||
1083 | return; | ||
1084 | } | ||
1085 | } | 1093 | } |
1086 | } while_for_each_ftrace_rec(); | 1094 | } while_for_each_ftrace_rec(); |
1087 | } | 1095 | } |
@@ -1262,12 +1270,34 @@ static int ftrace_update_code(struct module *mod) | |||
1262 | ftrace_new_addrs = p->newlist; | 1270 | ftrace_new_addrs = p->newlist; |
1263 | p->flags = 0L; | 1271 | p->flags = 0L; |
1264 | 1272 | ||
1265 | /* convert record (i.e, patch mcount-call with NOP) */ | 1273 | /* |
1266 | if (ftrace_code_disable(mod, p)) { | 1274 | * Do the initial record convertion from mcount jump |
1267 | p->flags |= FTRACE_FL_CONVERTED; | 1275 | * to the NOP instructions. |
1268 | ftrace_update_cnt++; | 1276 | */ |
1269 | } else | 1277 | if (!ftrace_code_disable(mod, p)) { |
1270 | ftrace_free_rec(p); | 1278 | ftrace_free_rec(p); |
1279 | continue; | ||
1280 | } | ||
1281 | |||
1282 | p->flags |= FTRACE_FL_CONVERTED; | ||
1283 | ftrace_update_cnt++; | ||
1284 | |||
1285 | /* | ||
1286 | * If the tracing is enabled, go ahead and enable the record. | ||
1287 | * | ||
1288 | * The reason not to enable the record immediatelly is the | ||
1289 | * inherent check of ftrace_make_nop/ftrace_make_call for | ||
1290 | * correct previous instructions. Making first the NOP | ||
1291 | * conversion puts the module to the correct state, thus | ||
1292 | * passing the ftrace_make_call check. | ||
1293 | */ | ||
1294 | if (ftrace_start_up) { | ||
1295 | int failed = __ftrace_replace_code(p, 1); | ||
1296 | if (failed) { | ||
1297 | ftrace_bug(failed, p->ip); | ||
1298 | ftrace_free_rec(p); | ||
1299 | } | ||
1300 | } | ||
1271 | } | 1301 | } |
1272 | 1302 | ||
1273 | stop = ftrace_now(raw_smp_processor_id()); | 1303 | stop = ftrace_now(raw_smp_processor_id()); |
@@ -1323,11 +1353,10 @@ static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) | |||
1323 | 1353 | ||
1324 | enum { | 1354 | enum { |
1325 | FTRACE_ITER_FILTER = (1 << 0), | 1355 | FTRACE_ITER_FILTER = (1 << 0), |
1326 | FTRACE_ITER_CONT = (1 << 1), | 1356 | FTRACE_ITER_NOTRACE = (1 << 1), |
1327 | FTRACE_ITER_NOTRACE = (1 << 2), | 1357 | FTRACE_ITER_FAILURES = (1 << 2), |
1328 | FTRACE_ITER_FAILURES = (1 << 3), | 1358 | FTRACE_ITER_PRINTALL = (1 << 3), |
1329 | FTRACE_ITER_PRINTALL = (1 << 4), | 1359 | FTRACE_ITER_HASH = (1 << 4), |
1330 | FTRACE_ITER_HASH = (1 << 5), | ||
1331 | }; | 1360 | }; |
1332 | 1361 | ||
1333 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ | 1362 | #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ |
@@ -1337,8 +1366,7 @@ struct ftrace_iterator { | |||
1337 | int hidx; | 1366 | int hidx; |
1338 | int idx; | 1367 | int idx; |
1339 | unsigned flags; | 1368 | unsigned flags; |
1340 | unsigned char buffer[FTRACE_BUFF_MAX+1]; | 1369 | struct trace_parser parser; |
1341 | unsigned buffer_idx; | ||
1342 | }; | 1370 | }; |
1343 | 1371 | ||
1344 | static void * | 1372 | static void * |
@@ -1407,7 +1435,7 @@ static int t_hash_show(struct seq_file *m, void *v) | |||
1407 | if (rec->ops->print) | 1435 | if (rec->ops->print) |
1408 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); | 1436 | return rec->ops->print(m, rec->ip, rec->ops, rec->data); |
1409 | 1437 | ||
1410 | seq_printf(m, "%pf:%pf", (void *)rec->ip, (void *)rec->ops->func); | 1438 | seq_printf(m, "%ps:%ps", (void *)rec->ip, (void *)rec->ops->func); |
1411 | 1439 | ||
1412 | if (rec->data) | 1440 | if (rec->data) |
1413 | seq_printf(m, ":%p", rec->data); | 1441 | seq_printf(m, ":%p", rec->data); |
@@ -1517,12 +1545,12 @@ static int t_show(struct seq_file *m, void *v) | |||
1517 | if (!rec) | 1545 | if (!rec) |
1518 | return 0; | 1546 | return 0; |
1519 | 1547 | ||
1520 | seq_printf(m, "%pf\n", (void *)rec->ip); | 1548 | seq_printf(m, "%ps\n", (void *)rec->ip); |
1521 | 1549 | ||
1522 | return 0; | 1550 | return 0; |
1523 | } | 1551 | } |
1524 | 1552 | ||
1525 | static struct seq_operations show_ftrace_seq_ops = { | 1553 | static const struct seq_operations show_ftrace_seq_ops = { |
1526 | .start = t_start, | 1554 | .start = t_start, |
1527 | .next = t_next, | 1555 | .next = t_next, |
1528 | .stop = t_stop, | 1556 | .stop = t_stop, |
@@ -1604,6 +1632,11 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable) | |||
1604 | if (!iter) | 1632 | if (!iter) |
1605 | return -ENOMEM; | 1633 | return -ENOMEM; |
1606 | 1634 | ||
1635 | if (trace_parser_get_init(&iter->parser, FTRACE_BUFF_MAX)) { | ||
1636 | kfree(iter); | ||
1637 | return -ENOMEM; | ||
1638 | } | ||
1639 | |||
1607 | mutex_lock(&ftrace_regex_lock); | 1640 | mutex_lock(&ftrace_regex_lock); |
1608 | if ((file->f_mode & FMODE_WRITE) && | 1641 | if ((file->f_mode & FMODE_WRITE) && |
1609 | (file->f_flags & O_TRUNC)) | 1642 | (file->f_flags & O_TRUNC)) |
@@ -1618,8 +1651,10 @@ ftrace_regex_open(struct inode *inode, struct file *file, int enable) | |||
1618 | if (!ret) { | 1651 | if (!ret) { |
1619 | struct seq_file *m = file->private_data; | 1652 | struct seq_file *m = file->private_data; |
1620 | m->private = iter; | 1653 | m->private = iter; |
1621 | } else | 1654 | } else { |
1655 | trace_parser_put(&iter->parser); | ||
1622 | kfree(iter); | 1656 | kfree(iter); |
1657 | } | ||
1623 | } else | 1658 | } else |
1624 | file->private_data = iter; | 1659 | file->private_data = iter; |
1625 | mutex_unlock(&ftrace_regex_lock); | 1660 | mutex_unlock(&ftrace_regex_lock); |
@@ -1652,60 +1687,6 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin) | |||
1652 | return ret; | 1687 | return ret; |
1653 | } | 1688 | } |
1654 | 1689 | ||
1655 | enum { | ||
1656 | MATCH_FULL, | ||
1657 | MATCH_FRONT_ONLY, | ||
1658 | MATCH_MIDDLE_ONLY, | ||
1659 | MATCH_END_ONLY, | ||
1660 | }; | ||
1661 | |||
1662 | /* | ||
1663 | * (static function - no need for kernel doc) | ||
1664 | * | ||
1665 | * Pass in a buffer containing a glob and this function will | ||
1666 | * set search to point to the search part of the buffer and | ||
1667 | * return the type of search it is (see enum above). | ||
1668 | * This does modify buff. | ||
1669 | * | ||
1670 | * Returns enum type. | ||
1671 | * search returns the pointer to use for comparison. | ||
1672 | * not returns 1 if buff started with a '!' | ||
1673 | * 0 otherwise. | ||
1674 | */ | ||
1675 | static int | ||
1676 | ftrace_setup_glob(char *buff, int len, char **search, int *not) | ||
1677 | { | ||
1678 | int type = MATCH_FULL; | ||
1679 | int i; | ||
1680 | |||
1681 | if (buff[0] == '!') { | ||
1682 | *not = 1; | ||
1683 | buff++; | ||
1684 | len--; | ||
1685 | } else | ||
1686 | *not = 0; | ||
1687 | |||
1688 | *search = buff; | ||
1689 | |||
1690 | for (i = 0; i < len; i++) { | ||
1691 | if (buff[i] == '*') { | ||
1692 | if (!i) { | ||
1693 | *search = buff + 1; | ||
1694 | type = MATCH_END_ONLY; | ||
1695 | } else { | ||
1696 | if (type == MATCH_END_ONLY) | ||
1697 | type = MATCH_MIDDLE_ONLY; | ||
1698 | else | ||
1699 | type = MATCH_FRONT_ONLY; | ||
1700 | buff[i] = 0; | ||
1701 | break; | ||
1702 | } | ||
1703 | } | ||
1704 | } | ||
1705 | |||
1706 | return type; | ||
1707 | } | ||
1708 | |||
1709 | static int ftrace_match(char *str, char *regex, int len, int type) | 1690 | static int ftrace_match(char *str, char *regex, int len, int type) |
1710 | { | 1691 | { |
1711 | int matched = 0; | 1692 | int matched = 0; |
@@ -1754,7 +1735,7 @@ static void ftrace_match_records(char *buff, int len, int enable) | |||
1754 | int not; | 1735 | int not; |
1755 | 1736 | ||
1756 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | 1737 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; |
1757 | type = ftrace_setup_glob(buff, len, &search, ¬); | 1738 | type = filter_parse_regex(buff, len, &search, ¬); |
1758 | 1739 | ||
1759 | search_len = strlen(search); | 1740 | search_len = strlen(search); |
1760 | 1741 | ||
@@ -1822,7 +1803,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) | |||
1822 | } | 1803 | } |
1823 | 1804 | ||
1824 | if (strlen(buff)) { | 1805 | if (strlen(buff)) { |
1825 | type = ftrace_setup_glob(buff, strlen(buff), &search, ¬); | 1806 | type = filter_parse_regex(buff, strlen(buff), &search, ¬); |
1826 | search_len = strlen(search); | 1807 | search_len = strlen(search); |
1827 | } | 1808 | } |
1828 | 1809 | ||
@@ -1987,7 +1968,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
1987 | int count = 0; | 1968 | int count = 0; |
1988 | char *search; | 1969 | char *search; |
1989 | 1970 | ||
1990 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 1971 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
1991 | len = strlen(search); | 1972 | len = strlen(search); |
1992 | 1973 | ||
1993 | /* we do not support '!' for function probes */ | 1974 | /* we do not support '!' for function probes */ |
@@ -2059,12 +2040,12 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
2059 | int i, len = 0; | 2040 | int i, len = 0; |
2060 | char *search; | 2041 | char *search; |
2061 | 2042 | ||
2062 | if (glob && (strcmp(glob, "*") || !strlen(glob))) | 2043 | if (glob && (strcmp(glob, "*") == 0 || !strlen(glob))) |
2063 | glob = NULL; | 2044 | glob = NULL; |
2064 | else { | 2045 | else if (glob) { |
2065 | int not; | 2046 | int not; |
2066 | 2047 | ||
2067 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 2048 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
2068 | len = strlen(search); | 2049 | len = strlen(search); |
2069 | 2050 | ||
2070 | /* we do not support '!' for function probes */ | 2051 | /* we do not support '!' for function probes */ |
@@ -2196,11 +2177,10 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
2196 | size_t cnt, loff_t *ppos, int enable) | 2177 | size_t cnt, loff_t *ppos, int enable) |
2197 | { | 2178 | { |
2198 | struct ftrace_iterator *iter; | 2179 | struct ftrace_iterator *iter; |
2199 | char ch; | 2180 | struct trace_parser *parser; |
2200 | size_t read = 0; | 2181 | ssize_t ret, read; |
2201 | ssize_t ret; | ||
2202 | 2182 | ||
2203 | if (!cnt || cnt < 0) | 2183 | if (!cnt) |
2204 | return 0; | 2184 | return 0; |
2205 | 2185 | ||
2206 | mutex_lock(&ftrace_regex_lock); | 2186 | mutex_lock(&ftrace_regex_lock); |
@@ -2211,72 +2191,23 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
2211 | } else | 2191 | } else |
2212 | iter = file->private_data; | 2192 | iter = file->private_data; |
2213 | 2193 | ||
2214 | if (!*ppos) { | 2194 | parser = &iter->parser; |
2215 | iter->flags &= ~FTRACE_ITER_CONT; | 2195 | read = trace_get_user(parser, ubuf, cnt, ppos); |
2216 | iter->buffer_idx = 0; | ||
2217 | } | ||
2218 | |||
2219 | ret = get_user(ch, ubuf++); | ||
2220 | if (ret) | ||
2221 | goto out; | ||
2222 | read++; | ||
2223 | cnt--; | ||
2224 | 2196 | ||
2225 | /* | 2197 | if (read >= 0 && trace_parser_loaded(parser) && |
2226 | * If the parser haven't finished with the last write, | 2198 | !trace_parser_cont(parser)) { |
2227 | * continue reading the user input without skipping spaces. | 2199 | ret = ftrace_process_regex(parser->buffer, |
2228 | */ | 2200 | parser->idx, enable); |
2229 | if (!(iter->flags & FTRACE_ITER_CONT)) { | ||
2230 | /* skip white space */ | ||
2231 | while (cnt && isspace(ch)) { | ||
2232 | ret = get_user(ch, ubuf++); | ||
2233 | if (ret) | ||
2234 | goto out; | ||
2235 | read++; | ||
2236 | cnt--; | ||
2237 | } | ||
2238 | |||
2239 | /* only spaces were written */ | ||
2240 | if (isspace(ch)) { | ||
2241 | *ppos += read; | ||
2242 | ret = read; | ||
2243 | goto out; | ||
2244 | } | ||
2245 | |||
2246 | iter->buffer_idx = 0; | ||
2247 | } | ||
2248 | |||
2249 | while (cnt && !isspace(ch)) { | ||
2250 | if (iter->buffer_idx < FTRACE_BUFF_MAX) | ||
2251 | iter->buffer[iter->buffer_idx++] = ch; | ||
2252 | else { | ||
2253 | ret = -EINVAL; | ||
2254 | goto out; | ||
2255 | } | ||
2256 | ret = get_user(ch, ubuf++); | ||
2257 | if (ret) | 2201 | if (ret) |
2258 | goto out; | 2202 | goto out; |
2259 | read++; | ||
2260 | cnt--; | ||
2261 | } | ||
2262 | 2203 | ||
2263 | if (isspace(ch)) { | 2204 | trace_parser_clear(parser); |
2264 | iter->buffer[iter->buffer_idx] = 0; | ||
2265 | ret = ftrace_process_regex(iter->buffer, | ||
2266 | iter->buffer_idx, enable); | ||
2267 | if (ret) | ||
2268 | goto out; | ||
2269 | iter->buffer_idx = 0; | ||
2270 | } else { | ||
2271 | iter->flags |= FTRACE_ITER_CONT; | ||
2272 | iter->buffer[iter->buffer_idx++] = ch; | ||
2273 | } | 2205 | } |
2274 | 2206 | ||
2275 | *ppos += read; | ||
2276 | ret = read; | 2207 | ret = read; |
2277 | out: | ||
2278 | mutex_unlock(&ftrace_regex_lock); | ||
2279 | 2208 | ||
2209 | mutex_unlock(&ftrace_regex_lock); | ||
2210 | out: | ||
2280 | return ret; | 2211 | return ret; |
2281 | } | 2212 | } |
2282 | 2213 | ||
@@ -2343,6 +2274,7 @@ void ftrace_set_notrace(unsigned char *buf, int len, int reset) | |||
2343 | #define FTRACE_FILTER_SIZE COMMAND_LINE_SIZE | 2274 | #define FTRACE_FILTER_SIZE COMMAND_LINE_SIZE |
2344 | static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; | 2275 | static char ftrace_notrace_buf[FTRACE_FILTER_SIZE] __initdata; |
2345 | static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; | 2276 | static char ftrace_filter_buf[FTRACE_FILTER_SIZE] __initdata; |
2277 | static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; | ||
2346 | 2278 | ||
2347 | static int __init set_ftrace_notrace(char *str) | 2279 | static int __init set_ftrace_notrace(char *str) |
2348 | { | 2280 | { |
@@ -2358,6 +2290,31 @@ static int __init set_ftrace_filter(char *str) | |||
2358 | } | 2290 | } |
2359 | __setup("ftrace_filter=", set_ftrace_filter); | 2291 | __setup("ftrace_filter=", set_ftrace_filter); |
2360 | 2292 | ||
2293 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
2294 | static int __init set_graph_function(char *str) | ||
2295 | { | ||
2296 | strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); | ||
2297 | return 1; | ||
2298 | } | ||
2299 | __setup("ftrace_graph_filter=", set_graph_function); | ||
2300 | |||
2301 | static void __init set_ftrace_early_graph(char *buf) | ||
2302 | { | ||
2303 | int ret; | ||
2304 | char *func; | ||
2305 | |||
2306 | while (buf) { | ||
2307 | func = strsep(&buf, ","); | ||
2308 | /* we allow only one expression at a time */ | ||
2309 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, | ||
2310 | func); | ||
2311 | if (ret) | ||
2312 | printk(KERN_DEBUG "ftrace: function %s not " | ||
2313 | "traceable\n", func); | ||
2314 | } | ||
2315 | } | ||
2316 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
2317 | |||
2361 | static void __init set_ftrace_early_filter(char *buf, int enable) | 2318 | static void __init set_ftrace_early_filter(char *buf, int enable) |
2362 | { | 2319 | { |
2363 | char *func; | 2320 | char *func; |
@@ -2374,6 +2331,10 @@ static void __init set_ftrace_early_filters(void) | |||
2374 | set_ftrace_early_filter(ftrace_filter_buf, 1); | 2331 | set_ftrace_early_filter(ftrace_filter_buf, 1); |
2375 | if (ftrace_notrace_buf[0]) | 2332 | if (ftrace_notrace_buf[0]) |
2376 | set_ftrace_early_filter(ftrace_notrace_buf, 0); | 2333 | set_ftrace_early_filter(ftrace_notrace_buf, 0); |
2334 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
2335 | if (ftrace_graph_buf[0]) | ||
2336 | set_ftrace_early_graph(ftrace_graph_buf); | ||
2337 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
2377 | } | 2338 | } |
2378 | 2339 | ||
2379 | static int | 2340 | static int |
@@ -2381,6 +2342,7 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
2381 | { | 2342 | { |
2382 | struct seq_file *m = (struct seq_file *)file->private_data; | 2343 | struct seq_file *m = (struct seq_file *)file->private_data; |
2383 | struct ftrace_iterator *iter; | 2344 | struct ftrace_iterator *iter; |
2345 | struct trace_parser *parser; | ||
2384 | 2346 | ||
2385 | mutex_lock(&ftrace_regex_lock); | 2347 | mutex_lock(&ftrace_regex_lock); |
2386 | if (file->f_mode & FMODE_READ) { | 2348 | if (file->f_mode & FMODE_READ) { |
@@ -2390,9 +2352,10 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
2390 | } else | 2352 | } else |
2391 | iter = file->private_data; | 2353 | iter = file->private_data; |
2392 | 2354 | ||
2393 | if (iter->buffer_idx) { | 2355 | parser = &iter->parser; |
2394 | iter->buffer[iter->buffer_idx] = 0; | 2356 | if (trace_parser_loaded(parser)) { |
2395 | ftrace_match_records(iter->buffer, iter->buffer_idx, enable); | 2357 | parser->buffer[parser->idx] = 0; |
2358 | ftrace_match_records(parser->buffer, parser->idx, enable); | ||
2396 | } | 2359 | } |
2397 | 2360 | ||
2398 | mutex_lock(&ftrace_lock); | 2361 | mutex_lock(&ftrace_lock); |
@@ -2400,7 +2363,9 @@ ftrace_regex_release(struct inode *inode, struct file *file, int enable) | |||
2400 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); | 2363 | ftrace_run_update_code(FTRACE_ENABLE_CALLS); |
2401 | mutex_unlock(&ftrace_lock); | 2364 | mutex_unlock(&ftrace_lock); |
2402 | 2365 | ||
2366 | trace_parser_put(parser); | ||
2403 | kfree(iter); | 2367 | kfree(iter); |
2368 | |||
2404 | mutex_unlock(&ftrace_regex_lock); | 2369 | mutex_unlock(&ftrace_regex_lock); |
2405 | return 0; | 2370 | return 0; |
2406 | } | 2371 | } |
@@ -2457,11 +2422,9 @@ unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | |||
2457 | static void * | 2422 | static void * |
2458 | __g_next(struct seq_file *m, loff_t *pos) | 2423 | __g_next(struct seq_file *m, loff_t *pos) |
2459 | { | 2424 | { |
2460 | unsigned long *array = m->private; | ||
2461 | |||
2462 | if (*pos >= ftrace_graph_count) | 2425 | if (*pos >= ftrace_graph_count) |
2463 | return NULL; | 2426 | return NULL; |
2464 | return &array[*pos]; | 2427 | return &ftrace_graph_funcs[*pos]; |
2465 | } | 2428 | } |
2466 | 2429 | ||
2467 | static void * | 2430 | static void * |
@@ -2499,12 +2462,12 @@ static int g_show(struct seq_file *m, void *v) | |||
2499 | return 0; | 2462 | return 0; |
2500 | } | 2463 | } |
2501 | 2464 | ||
2502 | seq_printf(m, "%pf\n", v); | 2465 | seq_printf(m, "%ps\n", (void *)*ptr); |
2503 | 2466 | ||
2504 | return 0; | 2467 | return 0; |
2505 | } | 2468 | } |
2506 | 2469 | ||
2507 | static struct seq_operations ftrace_graph_seq_ops = { | 2470 | static const struct seq_operations ftrace_graph_seq_ops = { |
2508 | .start = g_start, | 2471 | .start = g_start, |
2509 | .next = g_next, | 2472 | .next = g_next, |
2510 | .stop = g_stop, | 2473 | .stop = g_stop, |
@@ -2525,16 +2488,10 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
2525 | ftrace_graph_count = 0; | 2488 | ftrace_graph_count = 0; |
2526 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | 2489 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); |
2527 | } | 2490 | } |
2491 | mutex_unlock(&graph_lock); | ||
2528 | 2492 | ||
2529 | if (file->f_mode & FMODE_READ) { | 2493 | if (file->f_mode & FMODE_READ) |
2530 | ret = seq_open(file, &ftrace_graph_seq_ops); | 2494 | ret = seq_open(file, &ftrace_graph_seq_ops); |
2531 | if (!ret) { | ||
2532 | struct seq_file *m = file->private_data; | ||
2533 | m->private = ftrace_graph_funcs; | ||
2534 | } | ||
2535 | } else | ||
2536 | file->private_data = ftrace_graph_funcs; | ||
2537 | mutex_unlock(&graph_lock); | ||
2538 | 2495 | ||
2539 | return ret; | 2496 | return ret; |
2540 | } | 2497 | } |
@@ -2563,7 +2520,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2563 | return -ENODEV; | 2520 | return -ENODEV; |
2564 | 2521 | ||
2565 | /* decode regex */ | 2522 | /* decode regex */ |
2566 | type = ftrace_setup_glob(buffer, strlen(buffer), &search, ¬); | 2523 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
2567 | if (not) | 2524 | if (not) |
2568 | return -EINVAL; | 2525 | return -EINVAL; |
2569 | 2526 | ||
@@ -2602,12 +2559,8 @@ static ssize_t | |||
2602 | ftrace_graph_write(struct file *file, const char __user *ubuf, | 2559 | ftrace_graph_write(struct file *file, const char __user *ubuf, |
2603 | size_t cnt, loff_t *ppos) | 2560 | size_t cnt, loff_t *ppos) |
2604 | { | 2561 | { |
2605 | unsigned char buffer[FTRACE_BUFF_MAX+1]; | 2562 | struct trace_parser parser; |
2606 | unsigned long *array; | 2563 | ssize_t read, ret; |
2607 | size_t read = 0; | ||
2608 | ssize_t ret; | ||
2609 | int index = 0; | ||
2610 | char ch; | ||
2611 | 2564 | ||
2612 | if (!cnt || cnt < 0) | 2565 | if (!cnt || cnt < 0) |
2613 | return 0; | 2566 | return 0; |
@@ -2616,60 +2569,31 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
2616 | 2569 | ||
2617 | if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) { | 2570 | if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) { |
2618 | ret = -EBUSY; | 2571 | ret = -EBUSY; |
2619 | goto out; | 2572 | goto out_unlock; |
2620 | } | 2573 | } |
2621 | 2574 | ||
2622 | if (file->f_mode & FMODE_READ) { | 2575 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { |
2623 | struct seq_file *m = file->private_data; | 2576 | ret = -ENOMEM; |
2624 | array = m->private; | 2577 | goto out_unlock; |
2625 | } else | ||
2626 | array = file->private_data; | ||
2627 | |||
2628 | ret = get_user(ch, ubuf++); | ||
2629 | if (ret) | ||
2630 | goto out; | ||
2631 | read++; | ||
2632 | cnt--; | ||
2633 | |||
2634 | /* skip white space */ | ||
2635 | while (cnt && isspace(ch)) { | ||
2636 | ret = get_user(ch, ubuf++); | ||
2637 | if (ret) | ||
2638 | goto out; | ||
2639 | read++; | ||
2640 | cnt--; | ||
2641 | } | 2578 | } |
2642 | 2579 | ||
2643 | if (isspace(ch)) { | 2580 | read = trace_get_user(&parser, ubuf, cnt, ppos); |
2644 | *ppos += read; | ||
2645 | ret = read; | ||
2646 | goto out; | ||
2647 | } | ||
2648 | 2581 | ||
2649 | while (cnt && !isspace(ch)) { | 2582 | if (read >= 0 && trace_parser_loaded((&parser))) { |
2650 | if (index < FTRACE_BUFF_MAX) | 2583 | parser.buffer[parser.idx] = 0; |
2651 | buffer[index++] = ch; | 2584 | |
2652 | else { | 2585 | /* we allow only one expression at a time */ |
2653 | ret = -EINVAL; | 2586 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, |
2654 | goto out; | 2587 | parser.buffer); |
2655 | } | ||
2656 | ret = get_user(ch, ubuf++); | ||
2657 | if (ret) | 2588 | if (ret) |
2658 | goto out; | 2589 | goto out_free; |
2659 | read++; | ||
2660 | cnt--; | ||
2661 | } | 2590 | } |
2662 | buffer[index] = 0; | ||
2663 | |||
2664 | /* we allow only one expression at a time */ | ||
2665 | ret = ftrace_set_func(array, &ftrace_graph_count, buffer); | ||
2666 | if (ret) | ||
2667 | goto out; | ||
2668 | |||
2669 | file->f_pos += read; | ||
2670 | 2591 | ||
2671 | ret = read; | 2592 | ret = read; |
2672 | out: | 2593 | |
2594 | out_free: | ||
2595 | trace_parser_put(&parser); | ||
2596 | out_unlock: | ||
2673 | mutex_unlock(&graph_lock); | 2597 | mutex_unlock(&graph_lock); |
2674 | 2598 | ||
2675 | return ret; | 2599 | return ret; |
@@ -2707,7 +2631,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) | |||
2707 | return 0; | 2631 | return 0; |
2708 | } | 2632 | } |
2709 | 2633 | ||
2710 | static int ftrace_convert_nops(struct module *mod, | 2634 | static int ftrace_process_locs(struct module *mod, |
2711 | unsigned long *start, | 2635 | unsigned long *start, |
2712 | unsigned long *end) | 2636 | unsigned long *end) |
2713 | { | 2637 | { |
@@ -2740,19 +2664,17 @@ static int ftrace_convert_nops(struct module *mod, | |||
2740 | } | 2664 | } |
2741 | 2665 | ||
2742 | #ifdef CONFIG_MODULES | 2666 | #ifdef CONFIG_MODULES |
2743 | void ftrace_release(void *start, void *end) | 2667 | void ftrace_release_mod(struct module *mod) |
2744 | { | 2668 | { |
2745 | struct dyn_ftrace *rec; | 2669 | struct dyn_ftrace *rec; |
2746 | struct ftrace_page *pg; | 2670 | struct ftrace_page *pg; |
2747 | unsigned long s = (unsigned long)start; | ||
2748 | unsigned long e = (unsigned long)end; | ||
2749 | 2671 | ||
2750 | if (ftrace_disabled || !start || start == end) | 2672 | if (ftrace_disabled) |
2751 | return; | 2673 | return; |
2752 | 2674 | ||
2753 | mutex_lock(&ftrace_lock); | 2675 | mutex_lock(&ftrace_lock); |
2754 | do_for_each_ftrace_rec(pg, rec) { | 2676 | do_for_each_ftrace_rec(pg, rec) { |
2755 | if ((rec->ip >= s) && (rec->ip < e)) { | 2677 | if (within_module_core(rec->ip, mod)) { |
2756 | /* | 2678 | /* |
2757 | * rec->ip is changed in ftrace_free_rec() | 2679 | * rec->ip is changed in ftrace_free_rec() |
2758 | * It should not between s and e if record was freed. | 2680 | * It should not between s and e if record was freed. |
@@ -2769,7 +2691,7 @@ static void ftrace_init_module(struct module *mod, | |||
2769 | { | 2691 | { |
2770 | if (ftrace_disabled || start == end) | 2692 | if (ftrace_disabled || start == end) |
2771 | return; | 2693 | return; |
2772 | ftrace_convert_nops(mod, start, end); | 2694 | ftrace_process_locs(mod, start, end); |
2773 | } | 2695 | } |
2774 | 2696 | ||
2775 | static int ftrace_module_notify(struct notifier_block *self, | 2697 | static int ftrace_module_notify(struct notifier_block *self, |
@@ -2784,9 +2706,7 @@ static int ftrace_module_notify(struct notifier_block *self, | |||
2784 | mod->num_ftrace_callsites); | 2706 | mod->num_ftrace_callsites); |
2785 | break; | 2707 | break; |
2786 | case MODULE_STATE_GOING: | 2708 | case MODULE_STATE_GOING: |
2787 | ftrace_release(mod->ftrace_callsites, | 2709 | ftrace_release_mod(mod); |
2788 | mod->ftrace_callsites + | ||
2789 | mod->num_ftrace_callsites); | ||
2790 | break; | 2710 | break; |
2791 | } | 2711 | } |
2792 | 2712 | ||
@@ -2832,7 +2752,7 @@ void __init ftrace_init(void) | |||
2832 | 2752 | ||
2833 | last_ftrace_enabled = ftrace_enabled = 1; | 2753 | last_ftrace_enabled = ftrace_enabled = 1; |
2834 | 2754 | ||
2835 | ret = ftrace_convert_nops(NULL, | 2755 | ret = ftrace_process_locs(NULL, |
2836 | __start_mcount_loc, | 2756 | __start_mcount_loc, |
2837 | __stop_mcount_loc); | 2757 | __stop_mcount_loc); |
2838 | 2758 | ||
@@ -2865,23 +2785,6 @@ static inline void ftrace_startup_enable(int command) { } | |||
2865 | # define ftrace_shutdown_sysctl() do { } while (0) | 2785 | # define ftrace_shutdown_sysctl() do { } while (0) |
2866 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 2786 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
2867 | 2787 | ||
2868 | static ssize_t | ||
2869 | ftrace_pid_read(struct file *file, char __user *ubuf, | ||
2870 | size_t cnt, loff_t *ppos) | ||
2871 | { | ||
2872 | char buf[64]; | ||
2873 | int r; | ||
2874 | |||
2875 | if (ftrace_pid_trace == ftrace_swapper_pid) | ||
2876 | r = sprintf(buf, "swapper tasks\n"); | ||
2877 | else if (ftrace_pid_trace) | ||
2878 | r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace)); | ||
2879 | else | ||
2880 | r = sprintf(buf, "no pid\n"); | ||
2881 | |||
2882 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
2883 | } | ||
2884 | |||
2885 | static void clear_ftrace_swapper(void) | 2788 | static void clear_ftrace_swapper(void) |
2886 | { | 2789 | { |
2887 | struct task_struct *p; | 2790 | struct task_struct *p; |
@@ -2932,14 +2835,12 @@ static void set_ftrace_pid(struct pid *pid) | |||
2932 | rcu_read_unlock(); | 2835 | rcu_read_unlock(); |
2933 | } | 2836 | } |
2934 | 2837 | ||
2935 | static void clear_ftrace_pid_task(struct pid **pid) | 2838 | static void clear_ftrace_pid_task(struct pid *pid) |
2936 | { | 2839 | { |
2937 | if (*pid == ftrace_swapper_pid) | 2840 | if (pid == ftrace_swapper_pid) |
2938 | clear_ftrace_swapper(); | 2841 | clear_ftrace_swapper(); |
2939 | else | 2842 | else |
2940 | clear_ftrace_pid(*pid); | 2843 | clear_ftrace_pid(pid); |
2941 | |||
2942 | *pid = NULL; | ||
2943 | } | 2844 | } |
2944 | 2845 | ||
2945 | static void set_ftrace_pid_task(struct pid *pid) | 2846 | static void set_ftrace_pid_task(struct pid *pid) |
@@ -2950,11 +2851,140 @@ static void set_ftrace_pid_task(struct pid *pid) | |||
2950 | set_ftrace_pid(pid); | 2851 | set_ftrace_pid(pid); |
2951 | } | 2852 | } |
2952 | 2853 | ||
2854 | static int ftrace_pid_add(int p) | ||
2855 | { | ||
2856 | struct pid *pid; | ||
2857 | struct ftrace_pid *fpid; | ||
2858 | int ret = -EINVAL; | ||
2859 | |||
2860 | mutex_lock(&ftrace_lock); | ||
2861 | |||
2862 | if (!p) | ||
2863 | pid = ftrace_swapper_pid; | ||
2864 | else | ||
2865 | pid = find_get_pid(p); | ||
2866 | |||
2867 | if (!pid) | ||
2868 | goto out; | ||
2869 | |||
2870 | ret = 0; | ||
2871 | |||
2872 | list_for_each_entry(fpid, &ftrace_pids, list) | ||
2873 | if (fpid->pid == pid) | ||
2874 | goto out_put; | ||
2875 | |||
2876 | ret = -ENOMEM; | ||
2877 | |||
2878 | fpid = kmalloc(sizeof(*fpid), GFP_KERNEL); | ||
2879 | if (!fpid) | ||
2880 | goto out_put; | ||
2881 | |||
2882 | list_add(&fpid->list, &ftrace_pids); | ||
2883 | fpid->pid = pid; | ||
2884 | |||
2885 | set_ftrace_pid_task(pid); | ||
2886 | |||
2887 | ftrace_update_pid_func(); | ||
2888 | ftrace_startup_enable(0); | ||
2889 | |||
2890 | mutex_unlock(&ftrace_lock); | ||
2891 | return 0; | ||
2892 | |||
2893 | out_put: | ||
2894 | if (pid != ftrace_swapper_pid) | ||
2895 | put_pid(pid); | ||
2896 | |||
2897 | out: | ||
2898 | mutex_unlock(&ftrace_lock); | ||
2899 | return ret; | ||
2900 | } | ||
2901 | |||
2902 | static void ftrace_pid_reset(void) | ||
2903 | { | ||
2904 | struct ftrace_pid *fpid, *safe; | ||
2905 | |||
2906 | mutex_lock(&ftrace_lock); | ||
2907 | list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) { | ||
2908 | struct pid *pid = fpid->pid; | ||
2909 | |||
2910 | clear_ftrace_pid_task(pid); | ||
2911 | |||
2912 | list_del(&fpid->list); | ||
2913 | kfree(fpid); | ||
2914 | } | ||
2915 | |||
2916 | ftrace_update_pid_func(); | ||
2917 | ftrace_startup_enable(0); | ||
2918 | |||
2919 | mutex_unlock(&ftrace_lock); | ||
2920 | } | ||
2921 | |||
2922 | static void *fpid_start(struct seq_file *m, loff_t *pos) | ||
2923 | { | ||
2924 | mutex_lock(&ftrace_lock); | ||
2925 | |||
2926 | if (list_empty(&ftrace_pids) && (!*pos)) | ||
2927 | return (void *) 1; | ||
2928 | |||
2929 | return seq_list_start(&ftrace_pids, *pos); | ||
2930 | } | ||
2931 | |||
2932 | static void *fpid_next(struct seq_file *m, void *v, loff_t *pos) | ||
2933 | { | ||
2934 | if (v == (void *)1) | ||
2935 | return NULL; | ||
2936 | |||
2937 | return seq_list_next(v, &ftrace_pids, pos); | ||
2938 | } | ||
2939 | |||
2940 | static void fpid_stop(struct seq_file *m, void *p) | ||
2941 | { | ||
2942 | mutex_unlock(&ftrace_lock); | ||
2943 | } | ||
2944 | |||
2945 | static int fpid_show(struct seq_file *m, void *v) | ||
2946 | { | ||
2947 | const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list); | ||
2948 | |||
2949 | if (v == (void *)1) { | ||
2950 | seq_printf(m, "no pid\n"); | ||
2951 | return 0; | ||
2952 | } | ||
2953 | |||
2954 | if (fpid->pid == ftrace_swapper_pid) | ||
2955 | seq_printf(m, "swapper tasks\n"); | ||
2956 | else | ||
2957 | seq_printf(m, "%u\n", pid_vnr(fpid->pid)); | ||
2958 | |||
2959 | return 0; | ||
2960 | } | ||
2961 | |||
2962 | static const struct seq_operations ftrace_pid_sops = { | ||
2963 | .start = fpid_start, | ||
2964 | .next = fpid_next, | ||
2965 | .stop = fpid_stop, | ||
2966 | .show = fpid_show, | ||
2967 | }; | ||
2968 | |||
2969 | static int | ||
2970 | ftrace_pid_open(struct inode *inode, struct file *file) | ||
2971 | { | ||
2972 | int ret = 0; | ||
2973 | |||
2974 | if ((file->f_mode & FMODE_WRITE) && | ||
2975 | (file->f_flags & O_TRUNC)) | ||
2976 | ftrace_pid_reset(); | ||
2977 | |||
2978 | if (file->f_mode & FMODE_READ) | ||
2979 | ret = seq_open(file, &ftrace_pid_sops); | ||
2980 | |||
2981 | return ret; | ||
2982 | } | ||
2983 | |||
2953 | static ssize_t | 2984 | static ssize_t |
2954 | ftrace_pid_write(struct file *filp, const char __user *ubuf, | 2985 | ftrace_pid_write(struct file *filp, const char __user *ubuf, |
2955 | size_t cnt, loff_t *ppos) | 2986 | size_t cnt, loff_t *ppos) |
2956 | { | 2987 | { |
2957 | struct pid *pid; | ||
2958 | char buf[64]; | 2988 | char buf[64]; |
2959 | long val; | 2989 | long val; |
2960 | int ret; | 2990 | int ret; |
@@ -2967,57 +2997,38 @@ ftrace_pid_write(struct file *filp, const char __user *ubuf, | |||
2967 | 2997 | ||
2968 | buf[cnt] = 0; | 2998 | buf[cnt] = 0; |
2969 | 2999 | ||
3000 | /* | ||
3001 | * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid" | ||
3002 | * to clean the filter quietly. | ||
3003 | */ | ||
3004 | strstrip(buf); | ||
3005 | if (strlen(buf) == 0) | ||
3006 | return 1; | ||
3007 | |||
2970 | ret = strict_strtol(buf, 10, &val); | 3008 | ret = strict_strtol(buf, 10, &val); |
2971 | if (ret < 0) | 3009 | if (ret < 0) |
2972 | return ret; | 3010 | return ret; |
2973 | 3011 | ||
2974 | mutex_lock(&ftrace_lock); | 3012 | ret = ftrace_pid_add(val); |
2975 | if (val < 0) { | ||
2976 | /* disable pid tracing */ | ||
2977 | if (!ftrace_pid_trace) | ||
2978 | goto out; | ||
2979 | |||
2980 | clear_ftrace_pid_task(&ftrace_pid_trace); | ||
2981 | |||
2982 | } else { | ||
2983 | /* swapper task is special */ | ||
2984 | if (!val) { | ||
2985 | pid = ftrace_swapper_pid; | ||
2986 | if (pid == ftrace_pid_trace) | ||
2987 | goto out; | ||
2988 | } else { | ||
2989 | pid = find_get_pid(val); | ||
2990 | |||
2991 | if (pid == ftrace_pid_trace) { | ||
2992 | put_pid(pid); | ||
2993 | goto out; | ||
2994 | } | ||
2995 | } | ||
2996 | |||
2997 | if (ftrace_pid_trace) | ||
2998 | clear_ftrace_pid_task(&ftrace_pid_trace); | ||
2999 | |||
3000 | if (!pid) | ||
3001 | goto out; | ||
3002 | 3013 | ||
3003 | ftrace_pid_trace = pid; | 3014 | return ret ? ret : cnt; |
3004 | 3015 | } | |
3005 | set_ftrace_pid_task(ftrace_pid_trace); | ||
3006 | } | ||
3007 | |||
3008 | /* update the function call */ | ||
3009 | ftrace_update_pid_func(); | ||
3010 | ftrace_startup_enable(0); | ||
3011 | 3016 | ||
3012 | out: | 3017 | static int |
3013 | mutex_unlock(&ftrace_lock); | 3018 | ftrace_pid_release(struct inode *inode, struct file *file) |
3019 | { | ||
3020 | if (file->f_mode & FMODE_READ) | ||
3021 | seq_release(inode, file); | ||
3014 | 3022 | ||
3015 | return cnt; | 3023 | return 0; |
3016 | } | 3024 | } |
3017 | 3025 | ||
3018 | static const struct file_operations ftrace_pid_fops = { | 3026 | static const struct file_operations ftrace_pid_fops = { |
3019 | .read = ftrace_pid_read, | 3027 | .open = ftrace_pid_open, |
3020 | .write = ftrace_pid_write, | 3028 | .write = ftrace_pid_write, |
3029 | .read = seq_read, | ||
3030 | .llseek = seq_lseek, | ||
3031 | .release = ftrace_pid_release, | ||
3021 | }; | 3032 | }; |
3022 | 3033 | ||
3023 | static __init int ftrace_init_debugfs(void) | 3034 | static __init int ftrace_init_debugfs(void) |
@@ -3100,7 +3111,7 @@ int unregister_ftrace_function(struct ftrace_ops *ops) | |||
3100 | 3111 | ||
3101 | int | 3112 | int |
3102 | ftrace_enable_sysctl(struct ctl_table *table, int write, | 3113 | ftrace_enable_sysctl(struct ctl_table *table, int write, |
3103 | struct file *file, void __user *buffer, size_t *lenp, | 3114 | void __user *buffer, size_t *lenp, |
3104 | loff_t *ppos) | 3115 | loff_t *ppos) |
3105 | { | 3116 | { |
3106 | int ret; | 3117 | int ret; |
@@ -3110,7 +3121,7 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, | |||
3110 | 3121 | ||
3111 | mutex_lock(&ftrace_lock); | 3122 | mutex_lock(&ftrace_lock); |
3112 | 3123 | ||
3113 | ret = proc_dointvec(table, write, file, buffer, lenp, ppos); | 3124 | ret = proc_dointvec(table, write, buffer, lenp, ppos); |
3114 | 3125 | ||
3115 | if (ret || !write || (last_ftrace_enabled == !!ftrace_enabled)) | 3126 | if (ret || !write || (last_ftrace_enabled == !!ftrace_enabled)) |
3116 | goto out; | 3127 | goto out; |