diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 533 |
1 files changed, 314 insertions, 219 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6dc4e5ef7a01..2404b59b3097 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -22,12 +22,13 @@ | |||
22 | #include <linux/hardirq.h> | 22 | #include <linux/hardirq.h> |
23 | #include <linux/kthread.h> | 23 | #include <linux/kthread.h> |
24 | #include <linux/uaccess.h> | 24 | #include <linux/uaccess.h> |
25 | #include <linux/kprobes.h> | ||
26 | #include <linux/ftrace.h> | 25 | #include <linux/ftrace.h> |
27 | #include <linux/sysctl.h> | 26 | #include <linux/sysctl.h> |
27 | #include <linux/slab.h> | ||
28 | #include <linux/ctype.h> | 28 | #include <linux/ctype.h> |
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/hash.h> | 30 | #include <linux/hash.h> |
31 | #include <linux/rcupdate.h> | ||
31 | 32 | ||
32 | #include <trace/events/sched.h> | 33 | #include <trace/events/sched.h> |
33 | 34 | ||
@@ -60,6 +61,13 @@ static int last_ftrace_enabled; | |||
60 | /* Quick disabling of function tracer. */ | 61 | /* Quick disabling of function tracer. */ |
61 | int function_trace_stop; | 62 | int function_trace_stop; |
62 | 63 | ||
64 | /* List for set_ftrace_pid's pids. */ | ||
65 | LIST_HEAD(ftrace_pids); | ||
66 | struct ftrace_pid { | ||
67 | struct list_head list; | ||
68 | struct pid *pid; | ||
69 | }; | ||
70 | |||
63 | /* | 71 | /* |
64 | * ftrace_disabled is set when an anomaly is discovered. | 72 | * ftrace_disabled is set when an anomaly is discovered. |
65 | * ftrace_disabled is much stronger than ftrace_enabled. | 73 | * ftrace_disabled is much stronger than ftrace_enabled. |
@@ -78,18 +86,22 @@ ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | |||
78 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; | 86 | ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; |
79 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; | 87 | ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; |
80 | 88 | ||
89 | /* | ||
90 | * Traverse the ftrace_list, invoking all entries. The reason that we | ||
91 | * can use rcu_dereference_raw() is that elements removed from this list | ||
92 | * are simply leaked, so there is no need to interact with a grace-period | ||
93 | * mechanism. The rcu_dereference_raw() calls are needed to handle | ||
94 | * concurrent insertions into the ftrace_list. | ||
95 | * | ||
96 | * Silly Alpha and silly pointer-speculation compiler optimizations! | ||
97 | */ | ||
81 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) | 98 | static void ftrace_list_func(unsigned long ip, unsigned long parent_ip) |
82 | { | 99 | { |
83 | struct ftrace_ops *op = ftrace_list; | 100 | struct ftrace_ops *op = rcu_dereference_raw(ftrace_list); /*see above*/ |
84 | |||
85 | /* in case someone actually ports this to alpha! */ | ||
86 | read_barrier_depends(); | ||
87 | 101 | ||
88 | while (op != &ftrace_list_end) { | 102 | while (op != &ftrace_list_end) { |
89 | /* silly alpha */ | ||
90 | read_barrier_depends(); | ||
91 | op->func(ip, parent_ip); | 103 | op->func(ip, parent_ip); |
92 | op = op->next; | 104 | op = rcu_dereference_raw(op->next); /*see above*/ |
93 | }; | 105 | }; |
94 | } | 106 | } |
95 | 107 | ||
@@ -144,8 +156,7 @@ static int __register_ftrace_function(struct ftrace_ops *ops) | |||
144 | * the ops->next pointer is valid before another CPU sees | 156 | * the ops->next pointer is valid before another CPU sees |
145 | * the ops pointer included into the ftrace_list. | 157 | * the ops pointer included into the ftrace_list. |
146 | */ | 158 | */ |
147 | smp_wmb(); | 159 | rcu_assign_pointer(ftrace_list, ops); |
148 | ftrace_list = ops; | ||
149 | 160 | ||
150 | if (ftrace_enabled) { | 161 | if (ftrace_enabled) { |
151 | ftrace_func_t func; | 162 | ftrace_func_t func; |
@@ -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 | } |
@@ -231,7 +242,7 @@ static void ftrace_update_pid_func(void) | |||
231 | func = __ftrace_trace_function; | 242 | func = __ftrace_trace_function; |
232 | #endif | 243 | #endif |
233 | 244 | ||
234 | if (ftrace_pid_trace) { | 245 | if (!list_empty(&ftrace_pids)) { |
235 | set_ftrace_pid_function(func); | 246 | set_ftrace_pid_function(func); |
236 | func = ftrace_pid_func; | 247 | func = ftrace_pid_func; |
237 | } else { | 248 | } else { |
@@ -821,8 +832,6 @@ static __init void ftrace_profile_debugfs(struct dentry *d_tracer) | |||
821 | } | 832 | } |
822 | #endif /* CONFIG_FUNCTION_PROFILER */ | 833 | #endif /* CONFIG_FUNCTION_PROFILER */ |
823 | 834 | ||
824 | /* set when tracing only a pid */ | ||
825 | struct pid *ftrace_pid_trace; | ||
826 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; | 835 | static struct pid * const ftrace_swapper_pid = &init_struct_pid; |
827 | 836 | ||
828 | #ifdef CONFIG_DYNAMIC_FTRACE | 837 | #ifdef CONFIG_DYNAMIC_FTRACE |
@@ -889,36 +898,6 @@ static struct dyn_ftrace *ftrace_free_records; | |||
889 | } \ | 898 | } \ |
890 | } | 899 | } |
891 | 900 | ||
892 | #ifdef CONFIG_KPROBES | ||
893 | |||
894 | static int frozen_record_count; | ||
895 | |||
896 | static inline void freeze_record(struct dyn_ftrace *rec) | ||
897 | { | ||
898 | if (!(rec->flags & FTRACE_FL_FROZEN)) { | ||
899 | rec->flags |= FTRACE_FL_FROZEN; | ||
900 | frozen_record_count++; | ||
901 | } | ||
902 | } | ||
903 | |||
904 | static inline void unfreeze_record(struct dyn_ftrace *rec) | ||
905 | { | ||
906 | if (rec->flags & FTRACE_FL_FROZEN) { | ||
907 | rec->flags &= ~FTRACE_FL_FROZEN; | ||
908 | frozen_record_count--; | ||
909 | } | ||
910 | } | ||
911 | |||
912 | static inline int record_frozen(struct dyn_ftrace *rec) | ||
913 | { | ||
914 | return rec->flags & FTRACE_FL_FROZEN; | ||
915 | } | ||
916 | #else | ||
917 | # define freeze_record(rec) ({ 0; }) | ||
918 | # define unfreeze_record(rec) ({ 0; }) | ||
919 | # define record_frozen(rec) ({ 0; }) | ||
920 | #endif /* CONFIG_KPROBES */ | ||
921 | |||
922 | static void ftrace_free_rec(struct dyn_ftrace *rec) | 901 | static void ftrace_free_rec(struct dyn_ftrace *rec) |
923 | { | 902 | { |
924 | rec->freelist = ftrace_free_records; | 903 | rec->freelist = ftrace_free_records; |
@@ -1016,6 +995,21 @@ static void ftrace_bug(int failed, unsigned long ip) | |||
1016 | } | 995 | } |
1017 | 996 | ||
1018 | 997 | ||
998 | /* Return 1 if the address range is reserved for ftrace */ | ||
999 | int ftrace_text_reserved(void *start, void *end) | ||
1000 | { | ||
1001 | struct dyn_ftrace *rec; | ||
1002 | struct ftrace_page *pg; | ||
1003 | |||
1004 | do_for_each_ftrace_rec(pg, rec) { | ||
1005 | if (rec->ip <= (unsigned long)end && | ||
1006 | rec->ip + MCOUNT_INSN_SIZE > (unsigned long)start) | ||
1007 | return 1; | ||
1008 | } while_for_each_ftrace_rec(); | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | |||
1019 | static int | 1013 | static int |
1020 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) | 1014 | __ftrace_replace_code(struct dyn_ftrace *rec, int enable) |
1021 | { | 1015 | { |
@@ -1067,14 +1061,6 @@ static void ftrace_replace_code(int enable) | |||
1067 | !(rec->flags & FTRACE_FL_CONVERTED)) | 1061 | !(rec->flags & FTRACE_FL_CONVERTED)) |
1068 | continue; | 1062 | continue; |
1069 | 1063 | ||
1070 | /* ignore updates to this record's mcount site */ | ||
1071 | if (get_kprobe((void *)rec->ip)) { | ||
1072 | freeze_record(rec); | ||
1073 | continue; | ||
1074 | } else { | ||
1075 | unfreeze_record(rec); | ||
1076 | } | ||
1077 | |||
1078 | failed = __ftrace_replace_code(rec, enable); | 1064 | failed = __ftrace_replace_code(rec, enable); |
1079 | if (failed) { | 1065 | if (failed) { |
1080 | rec->flags |= FTRACE_FL_FAILED; | 1066 | rec->flags |= FTRACE_FL_FAILED; |
@@ -1261,12 +1247,34 @@ static int ftrace_update_code(struct module *mod) | |||
1261 | ftrace_new_addrs = p->newlist; | 1247 | ftrace_new_addrs = p->newlist; |
1262 | p->flags = 0L; | 1248 | p->flags = 0L; |
1263 | 1249 | ||
1264 | /* convert record (i.e, patch mcount-call with NOP) */ | 1250 | /* |
1265 | if (ftrace_code_disable(mod, p)) { | 1251 | * Do the initial record convertion from mcount jump |
1266 | p->flags |= FTRACE_FL_CONVERTED; | 1252 | * to the NOP instructions. |
1267 | ftrace_update_cnt++; | 1253 | */ |
1268 | } else | 1254 | if (!ftrace_code_disable(mod, p)) { |
1269 | ftrace_free_rec(p); | 1255 | ftrace_free_rec(p); |
1256 | continue; | ||
1257 | } | ||
1258 | |||
1259 | p->flags |= FTRACE_FL_CONVERTED; | ||
1260 | ftrace_update_cnt++; | ||
1261 | |||
1262 | /* | ||
1263 | * If the tracing is enabled, go ahead and enable the record. | ||
1264 | * | ||
1265 | * The reason not to enable the record immediatelly is the | ||
1266 | * inherent check of ftrace_make_nop/ftrace_make_call for | ||
1267 | * correct previous instructions. Making first the NOP | ||
1268 | * conversion puts the module to the correct state, thus | ||
1269 | * passing the ftrace_make_call check. | ||
1270 | */ | ||
1271 | if (ftrace_start_up) { | ||
1272 | int failed = __ftrace_replace_code(p, 1); | ||
1273 | if (failed) { | ||
1274 | ftrace_bug(failed, p->ip); | ||
1275 | ftrace_free_rec(p); | ||
1276 | } | ||
1277 | } | ||
1270 | } | 1278 | } |
1271 | 1279 | ||
1272 | stop = ftrace_now(raw_smp_processor_id()); | 1280 | stop = ftrace_now(raw_smp_processor_id()); |
@@ -1656,64 +1664,10 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin) | |||
1656 | return ret; | 1664 | return ret; |
1657 | } | 1665 | } |
1658 | 1666 | ||
1659 | enum { | ||
1660 | MATCH_FULL, | ||
1661 | MATCH_FRONT_ONLY, | ||
1662 | MATCH_MIDDLE_ONLY, | ||
1663 | MATCH_END_ONLY, | ||
1664 | }; | ||
1665 | |||
1666 | /* | ||
1667 | * (static function - no need for kernel doc) | ||
1668 | * | ||
1669 | * Pass in a buffer containing a glob and this function will | ||
1670 | * set search to point to the search part of the buffer and | ||
1671 | * return the type of search it is (see enum above). | ||
1672 | * This does modify buff. | ||
1673 | * | ||
1674 | * Returns enum type. | ||
1675 | * search returns the pointer to use for comparison. | ||
1676 | * not returns 1 if buff started with a '!' | ||
1677 | * 0 otherwise. | ||
1678 | */ | ||
1679 | static int | ||
1680 | ftrace_setup_glob(char *buff, int len, char **search, int *not) | ||
1681 | { | ||
1682 | int type = MATCH_FULL; | ||
1683 | int i; | ||
1684 | |||
1685 | if (buff[0] == '!') { | ||
1686 | *not = 1; | ||
1687 | buff++; | ||
1688 | len--; | ||
1689 | } else | ||
1690 | *not = 0; | ||
1691 | |||
1692 | *search = buff; | ||
1693 | |||
1694 | for (i = 0; i < len; i++) { | ||
1695 | if (buff[i] == '*') { | ||
1696 | if (!i) { | ||
1697 | *search = buff + 1; | ||
1698 | type = MATCH_END_ONLY; | ||
1699 | } else { | ||
1700 | if (type == MATCH_END_ONLY) | ||
1701 | type = MATCH_MIDDLE_ONLY; | ||
1702 | else | ||
1703 | type = MATCH_FRONT_ONLY; | ||
1704 | buff[i] = 0; | ||
1705 | break; | ||
1706 | } | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | return type; | ||
1711 | } | ||
1712 | |||
1713 | static int ftrace_match(char *str, char *regex, int len, int type) | 1667 | static int ftrace_match(char *str, char *regex, int len, int type) |
1714 | { | 1668 | { |
1715 | int matched = 0; | 1669 | int matched = 0; |
1716 | char *ptr; | 1670 | int slen; |
1717 | 1671 | ||
1718 | switch (type) { | 1672 | switch (type) { |
1719 | case MATCH_FULL: | 1673 | case MATCH_FULL: |
@@ -1729,8 +1683,8 @@ static int ftrace_match(char *str, char *regex, int len, int type) | |||
1729 | matched = 1; | 1683 | matched = 1; |
1730 | break; | 1684 | break; |
1731 | case MATCH_END_ONLY: | 1685 | case MATCH_END_ONLY: |
1732 | ptr = strstr(str, regex); | 1686 | slen = strlen(str); |
1733 | if (ptr && (ptr[len] == 0)) | 1687 | if (slen >= len && memcmp(str + slen - len, regex, len) == 0) |
1734 | matched = 1; | 1688 | matched = 1; |
1735 | break; | 1689 | break; |
1736 | } | 1690 | } |
@@ -1747,7 +1701,7 @@ ftrace_match_record(struct dyn_ftrace *rec, char *regex, int len, int type) | |||
1747 | return ftrace_match(str, regex, len, type); | 1701 | return ftrace_match(str, regex, len, type); |
1748 | } | 1702 | } |
1749 | 1703 | ||
1750 | static void ftrace_match_records(char *buff, int len, int enable) | 1704 | static int ftrace_match_records(char *buff, int len, int enable) |
1751 | { | 1705 | { |
1752 | unsigned int search_len; | 1706 | unsigned int search_len; |
1753 | struct ftrace_page *pg; | 1707 | struct ftrace_page *pg; |
@@ -1756,9 +1710,10 @@ static void ftrace_match_records(char *buff, int len, int enable) | |||
1756 | char *search; | 1710 | char *search; |
1757 | int type; | 1711 | int type; |
1758 | int not; | 1712 | int not; |
1713 | int found = 0; | ||
1759 | 1714 | ||
1760 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | 1715 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; |
1761 | type = ftrace_setup_glob(buff, len, &search, ¬); | 1716 | type = filter_parse_regex(buff, len, &search, ¬); |
1762 | 1717 | ||
1763 | search_len = strlen(search); | 1718 | search_len = strlen(search); |
1764 | 1719 | ||
@@ -1773,6 +1728,7 @@ static void ftrace_match_records(char *buff, int len, int enable) | |||
1773 | rec->flags &= ~flag; | 1728 | rec->flags &= ~flag; |
1774 | else | 1729 | else |
1775 | rec->flags |= flag; | 1730 | rec->flags |= flag; |
1731 | found = 1; | ||
1776 | } | 1732 | } |
1777 | /* | 1733 | /* |
1778 | * Only enable filtering if we have a function that | 1734 | * Only enable filtering if we have a function that |
@@ -1782,6 +1738,8 @@ static void ftrace_match_records(char *buff, int len, int enable) | |||
1782 | ftrace_filtered = 1; | 1738 | ftrace_filtered = 1; |
1783 | } while_for_each_ftrace_rec(); | 1739 | } while_for_each_ftrace_rec(); |
1784 | mutex_unlock(&ftrace_lock); | 1740 | mutex_unlock(&ftrace_lock); |
1741 | |||
1742 | return found; | ||
1785 | } | 1743 | } |
1786 | 1744 | ||
1787 | static int | 1745 | static int |
@@ -1803,7 +1761,7 @@ ftrace_match_module_record(struct dyn_ftrace *rec, char *mod, | |||
1803 | return 1; | 1761 | return 1; |
1804 | } | 1762 | } |
1805 | 1763 | ||
1806 | static void ftrace_match_module_records(char *buff, char *mod, int enable) | 1764 | static int ftrace_match_module_records(char *buff, char *mod, int enable) |
1807 | { | 1765 | { |
1808 | unsigned search_len = 0; | 1766 | unsigned search_len = 0; |
1809 | struct ftrace_page *pg; | 1767 | struct ftrace_page *pg; |
@@ -1812,6 +1770,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) | |||
1812 | char *search = buff; | 1770 | char *search = buff; |
1813 | unsigned long flag; | 1771 | unsigned long flag; |
1814 | int not = 0; | 1772 | int not = 0; |
1773 | int found = 0; | ||
1815 | 1774 | ||
1816 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | 1775 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; |
1817 | 1776 | ||
@@ -1826,7 +1785,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) | |||
1826 | } | 1785 | } |
1827 | 1786 | ||
1828 | if (strlen(buff)) { | 1787 | if (strlen(buff)) { |
1829 | type = ftrace_setup_glob(buff, strlen(buff), &search, ¬); | 1788 | type = filter_parse_regex(buff, strlen(buff), &search, ¬); |
1830 | search_len = strlen(search); | 1789 | search_len = strlen(search); |
1831 | } | 1790 | } |
1832 | 1791 | ||
@@ -1842,12 +1801,15 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) | |||
1842 | rec->flags &= ~flag; | 1801 | rec->flags &= ~flag; |
1843 | else | 1802 | else |
1844 | rec->flags |= flag; | 1803 | rec->flags |= flag; |
1804 | found = 1; | ||
1845 | } | 1805 | } |
1846 | if (enable && (rec->flags & FTRACE_FL_FILTER)) | 1806 | if (enable && (rec->flags & FTRACE_FL_FILTER)) |
1847 | ftrace_filtered = 1; | 1807 | ftrace_filtered = 1; |
1848 | 1808 | ||
1849 | } while_for_each_ftrace_rec(); | 1809 | } while_for_each_ftrace_rec(); |
1850 | mutex_unlock(&ftrace_lock); | 1810 | mutex_unlock(&ftrace_lock); |
1811 | |||
1812 | return found; | ||
1851 | } | 1813 | } |
1852 | 1814 | ||
1853 | /* | 1815 | /* |
@@ -1876,8 +1838,9 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable) | |||
1876 | if (!strlen(mod)) | 1838 | if (!strlen(mod)) |
1877 | return -EINVAL; | 1839 | return -EINVAL; |
1878 | 1840 | ||
1879 | ftrace_match_module_records(func, mod, enable); | 1841 | if (ftrace_match_module_records(func, mod, enable)) |
1880 | return 0; | 1842 | return 0; |
1843 | return -EINVAL; | ||
1881 | } | 1844 | } |
1882 | 1845 | ||
1883 | static struct ftrace_func_command ftrace_mod_cmd = { | 1846 | static struct ftrace_func_command ftrace_mod_cmd = { |
@@ -1991,7 +1954,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
1991 | int count = 0; | 1954 | int count = 0; |
1992 | char *search; | 1955 | char *search; |
1993 | 1956 | ||
1994 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 1957 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
1995 | len = strlen(search); | 1958 | len = strlen(search); |
1996 | 1959 | ||
1997 | /* we do not support '!' for function probes */ | 1960 | /* we do not support '!' for function probes */ |
@@ -2068,7 +2031,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
2068 | else if (glob) { | 2031 | else if (glob) { |
2069 | int not; | 2032 | int not; |
2070 | 2033 | ||
2071 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 2034 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
2072 | len = strlen(search); | 2035 | len = strlen(search); |
2073 | 2036 | ||
2074 | /* we do not support '!' for function probes */ | 2037 | /* we do not support '!' for function probes */ |
@@ -2174,8 +2137,9 @@ static int ftrace_process_regex(char *buff, int len, int enable) | |||
2174 | func = strsep(&next, ":"); | 2137 | func = strsep(&next, ":"); |
2175 | 2138 | ||
2176 | if (!next) { | 2139 | if (!next) { |
2177 | ftrace_match_records(func, len, enable); | 2140 | if (ftrace_match_records(func, len, enable)) |
2178 | return 0; | 2141 | return 0; |
2142 | return ret; | ||
2179 | } | 2143 | } |
2180 | 2144 | ||
2181 | /* command found */ | 2145 | /* command found */ |
@@ -2221,10 +2185,9 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, | |||
2221 | !trace_parser_cont(parser)) { | 2185 | !trace_parser_cont(parser)) { |
2222 | ret = ftrace_process_regex(parser->buffer, | 2186 | ret = ftrace_process_regex(parser->buffer, |
2223 | parser->idx, enable); | 2187 | parser->idx, enable); |
2188 | trace_parser_clear(parser); | ||
2224 | if (ret) | 2189 | if (ret) |
2225 | goto out_unlock; | 2190 | goto out_unlock; |
2226 | |||
2227 | trace_parser_clear(parser); | ||
2228 | } | 2191 | } |
2229 | 2192 | ||
2230 | ret = read; | 2193 | ret = read; |
@@ -2312,6 +2275,34 @@ static int __init set_ftrace_filter(char *str) | |||
2312 | } | 2275 | } |
2313 | __setup("ftrace_filter=", set_ftrace_filter); | 2276 | __setup("ftrace_filter=", set_ftrace_filter); |
2314 | 2277 | ||
2278 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
2279 | static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata; | ||
2280 | static int ftrace_set_func(unsigned long *array, int *idx, char *buffer); | ||
2281 | |||
2282 | static int __init set_graph_function(char *str) | ||
2283 | { | ||
2284 | strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE); | ||
2285 | return 1; | ||
2286 | } | ||
2287 | __setup("ftrace_graph_filter=", set_graph_function); | ||
2288 | |||
2289 | static void __init set_ftrace_early_graph(char *buf) | ||
2290 | { | ||
2291 | int ret; | ||
2292 | char *func; | ||
2293 | |||
2294 | while (buf) { | ||
2295 | func = strsep(&buf, ","); | ||
2296 | /* we allow only one expression at a time */ | ||
2297 | ret = ftrace_set_func(ftrace_graph_funcs, &ftrace_graph_count, | ||
2298 | func); | ||
2299 | if (ret) | ||
2300 | printk(KERN_DEBUG "ftrace: function %s not " | ||
2301 | "traceable\n", func); | ||
2302 | } | ||
2303 | } | ||
2304 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
2305 | |||
2315 | static void __init set_ftrace_early_filter(char *buf, int enable) | 2306 | static void __init set_ftrace_early_filter(char *buf, int enable) |
2316 | { | 2307 | { |
2317 | char *func; | 2308 | char *func; |
@@ -2328,6 +2319,10 @@ static void __init set_ftrace_early_filters(void) | |||
2328 | set_ftrace_early_filter(ftrace_filter_buf, 1); | 2319 | set_ftrace_early_filter(ftrace_filter_buf, 1); |
2329 | if (ftrace_notrace_buf[0]) | 2320 | if (ftrace_notrace_buf[0]) |
2330 | set_ftrace_early_filter(ftrace_notrace_buf, 0); | 2321 | set_ftrace_early_filter(ftrace_notrace_buf, 0); |
2322 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
2323 | if (ftrace_graph_buf[0]) | ||
2324 | set_ftrace_early_graph(ftrace_graph_buf); | ||
2325 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
2331 | } | 2326 | } |
2332 | 2327 | ||
2333 | static int | 2328 | static int |
@@ -2410,6 +2405,7 @@ static const struct file_operations ftrace_notrace_fops = { | |||
2410 | static DEFINE_MUTEX(graph_lock); | 2405 | static DEFINE_MUTEX(graph_lock); |
2411 | 2406 | ||
2412 | int ftrace_graph_count; | 2407 | int ftrace_graph_count; |
2408 | int ftrace_graph_filter_enabled; | ||
2413 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; | 2409 | unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS] __read_mostly; |
2414 | 2410 | ||
2415 | static void * | 2411 | static void * |
@@ -2432,7 +2428,7 @@ static void *g_start(struct seq_file *m, loff_t *pos) | |||
2432 | mutex_lock(&graph_lock); | 2428 | mutex_lock(&graph_lock); |
2433 | 2429 | ||
2434 | /* Nothing, tell g_show to print all functions are enabled */ | 2430 | /* Nothing, tell g_show to print all functions are enabled */ |
2435 | if (!ftrace_graph_count && !*pos) | 2431 | if (!ftrace_graph_filter_enabled && !*pos) |
2436 | return (void *)1; | 2432 | return (void *)1; |
2437 | 2433 | ||
2438 | return __g_next(m, pos); | 2434 | return __g_next(m, pos); |
@@ -2478,6 +2474,7 @@ ftrace_graph_open(struct inode *inode, struct file *file) | |||
2478 | mutex_lock(&graph_lock); | 2474 | mutex_lock(&graph_lock); |
2479 | if ((file->f_mode & FMODE_WRITE) && | 2475 | if ((file->f_mode & FMODE_WRITE) && |
2480 | (file->f_flags & O_TRUNC)) { | 2476 | (file->f_flags & O_TRUNC)) { |
2477 | ftrace_graph_filter_enabled = 0; | ||
2481 | ftrace_graph_count = 0; | 2478 | ftrace_graph_count = 0; |
2482 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); | 2479 | memset(ftrace_graph_funcs, 0, sizeof(ftrace_graph_funcs)); |
2483 | } | 2480 | } |
@@ -2503,7 +2500,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2503 | struct dyn_ftrace *rec; | 2500 | struct dyn_ftrace *rec; |
2504 | struct ftrace_page *pg; | 2501 | struct ftrace_page *pg; |
2505 | int search_len; | 2502 | int search_len; |
2506 | int found = 0; | 2503 | int fail = 1; |
2507 | int type, not; | 2504 | int type, not; |
2508 | char *search; | 2505 | char *search; |
2509 | bool exists; | 2506 | bool exists; |
@@ -2513,39 +2510,52 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
2513 | return -ENODEV; | 2510 | return -ENODEV; |
2514 | 2511 | ||
2515 | /* decode regex */ | 2512 | /* decode regex */ |
2516 | type = ftrace_setup_glob(buffer, strlen(buffer), &search, ¬); | 2513 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
2517 | if (not) | 2514 | if (!not && *idx >= FTRACE_GRAPH_MAX_FUNCS) |
2518 | return -EINVAL; | 2515 | return -EBUSY; |
2519 | 2516 | ||
2520 | search_len = strlen(search); | 2517 | search_len = strlen(search); |
2521 | 2518 | ||
2522 | mutex_lock(&ftrace_lock); | 2519 | mutex_lock(&ftrace_lock); |
2523 | do_for_each_ftrace_rec(pg, rec) { | 2520 | do_for_each_ftrace_rec(pg, rec) { |
2524 | 2521 | ||
2525 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | ||
2526 | break; | ||
2527 | |||
2528 | if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) | 2522 | if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) |
2529 | continue; | 2523 | continue; |
2530 | 2524 | ||
2531 | if (ftrace_match_record(rec, search, search_len, type)) { | 2525 | if (ftrace_match_record(rec, search, search_len, type)) { |
2532 | /* ensure it is not already in the array */ | 2526 | /* if it is in the array */ |
2533 | exists = false; | 2527 | exists = false; |
2534 | for (i = 0; i < *idx; i++) | 2528 | for (i = 0; i < *idx; i++) { |
2535 | if (array[i] == rec->ip) { | 2529 | if (array[i] == rec->ip) { |
2536 | exists = true; | 2530 | exists = true; |
2537 | break; | 2531 | break; |
2538 | } | 2532 | } |
2539 | if (!exists) { | 2533 | } |
2540 | array[(*idx)++] = rec->ip; | 2534 | |
2541 | found = 1; | 2535 | if (!not) { |
2536 | fail = 0; | ||
2537 | if (!exists) { | ||
2538 | array[(*idx)++] = rec->ip; | ||
2539 | if (*idx >= FTRACE_GRAPH_MAX_FUNCS) | ||
2540 | goto out; | ||
2541 | } | ||
2542 | } else { | ||
2543 | if (exists) { | ||
2544 | array[i] = array[--(*idx)]; | ||
2545 | array[*idx] = 0; | ||
2546 | fail = 0; | ||
2547 | } | ||
2542 | } | 2548 | } |
2543 | } | 2549 | } |
2544 | } while_for_each_ftrace_rec(); | 2550 | } while_for_each_ftrace_rec(); |
2545 | 2551 | out: | |
2546 | mutex_unlock(&ftrace_lock); | 2552 | mutex_unlock(&ftrace_lock); |
2547 | 2553 | ||
2548 | return found ? 0 : -EINVAL; | 2554 | if (fail) |
2555 | return -EINVAL; | ||
2556 | |||
2557 | ftrace_graph_filter_enabled = 1; | ||
2558 | return 0; | ||
2549 | } | 2559 | } |
2550 | 2560 | ||
2551 | static ssize_t | 2561 | static ssize_t |
@@ -2555,16 +2565,11 @@ ftrace_graph_write(struct file *file, const char __user *ubuf, | |||
2555 | struct trace_parser parser; | 2565 | struct trace_parser parser; |
2556 | ssize_t read, ret; | 2566 | ssize_t read, ret; |
2557 | 2567 | ||
2558 | if (!cnt || cnt < 0) | 2568 | if (!cnt) |
2559 | return 0; | 2569 | return 0; |
2560 | 2570 | ||
2561 | mutex_lock(&graph_lock); | 2571 | mutex_lock(&graph_lock); |
2562 | 2572 | ||
2563 | if (ftrace_graph_count >= FTRACE_GRAPH_MAX_FUNCS) { | ||
2564 | ret = -EBUSY; | ||
2565 | goto out_unlock; | ||
2566 | } | ||
2567 | |||
2568 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { | 2573 | if (trace_parser_get_init(&parser, FTRACE_BUFF_MAX)) { |
2569 | ret = -ENOMEM; | 2574 | ret = -ENOMEM; |
2570 | goto out_unlock; | 2575 | goto out_unlock; |
@@ -2624,7 +2629,7 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) | |||
2624 | return 0; | 2629 | return 0; |
2625 | } | 2630 | } |
2626 | 2631 | ||
2627 | static int ftrace_convert_nops(struct module *mod, | 2632 | static int ftrace_process_locs(struct module *mod, |
2628 | unsigned long *start, | 2633 | unsigned long *start, |
2629 | unsigned long *end) | 2634 | unsigned long *end) |
2630 | { | 2635 | { |
@@ -2684,7 +2689,7 @@ static void ftrace_init_module(struct module *mod, | |||
2684 | { | 2689 | { |
2685 | if (ftrace_disabled || start == end) | 2690 | if (ftrace_disabled || start == end) |
2686 | return; | 2691 | return; |
2687 | ftrace_convert_nops(mod, start, end); | 2692 | ftrace_process_locs(mod, start, end); |
2688 | } | 2693 | } |
2689 | 2694 | ||
2690 | static int ftrace_module_notify(struct notifier_block *self, | 2695 | static int ftrace_module_notify(struct notifier_block *self, |
@@ -2745,7 +2750,7 @@ void __init ftrace_init(void) | |||
2745 | 2750 | ||
2746 | last_ftrace_enabled = ftrace_enabled = 1; | 2751 | last_ftrace_enabled = ftrace_enabled = 1; |
2747 | 2752 | ||
2748 | ret = ftrace_convert_nops(NULL, | 2753 | ret = ftrace_process_locs(NULL, |
2749 | __start_mcount_loc, | 2754 | __start_mcount_loc, |
2750 | __stop_mcount_loc); | 2755 | __stop_mcount_loc); |
2751 | 2756 | ||
@@ -2778,23 +2783,6 @@ static inline void ftrace_startup_enable(int command) { } | |||
2778 | # define ftrace_shutdown_sysctl() do { } while (0) | 2783 | # define ftrace_shutdown_sysctl() do { } while (0) |
2779 | #endif /* CONFIG_DYNAMIC_FTRACE */ | 2784 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
2780 | 2785 | ||
2781 | static ssize_t | ||
2782 | ftrace_pid_read(struct file *file, char __user *ubuf, | ||
2783 | size_t cnt, loff_t *ppos) | ||
2784 | { | ||
2785 | char buf[64]; | ||
2786 | int r; | ||
2787 | |||
2788 | if (ftrace_pid_trace == ftrace_swapper_pid) | ||
2789 | r = sprintf(buf, "swapper tasks\n"); | ||
2790 | else if (ftrace_pid_trace) | ||
2791 | r = sprintf(buf, "%u\n", pid_vnr(ftrace_pid_trace)); | ||
2792 | else | ||
2793 | r = sprintf(buf, "no pid\n"); | ||
2794 | |||
2795 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | ||
2796 | } | ||
2797 | |||
2798 | static void clear_ftrace_swapper(void) | 2786 | static void clear_ftrace_swapper(void) |
2799 | { | 2787 | { |
2800 | struct task_struct *p; | 2788 | struct task_struct *p; |
@@ -2845,14 +2833,12 @@ static void set_ftrace_pid(struct pid *pid) | |||
2845 | rcu_read_unlock(); | 2833 | rcu_read_unlock(); |
2846 | } | 2834 | } |
2847 | 2835 | ||
2848 | static void clear_ftrace_pid_task(struct pid **pid) | 2836 | static void clear_ftrace_pid_task(struct pid *pid) |
2849 | { | 2837 | { |
2850 | if (*pid == ftrace_swapper_pid) | 2838 | if (pid == ftrace_swapper_pid) |
2851 | clear_ftrace_swapper(); | 2839 | clear_ftrace_swapper(); |
2852 | else | 2840 | else |
2853 | clear_ftrace_pid(*pid); | 2841 | clear_ftrace_pid(pid); |
2854 | |||
2855 | *pid = NULL; | ||
2856 | } | 2842 | } |
2857 | 2843 | ||
2858 | static void set_ftrace_pid_task(struct pid *pid) | 2844 | static void set_ftrace_pid_task(struct pid *pid) |
@@ -2863,74 +2849,184 @@ static void set_ftrace_pid_task(struct pid *pid) | |||
2863 | set_ftrace_pid(pid); | 2849 | set_ftrace_pid(pid); |
2864 | } | 2850 | } |
2865 | 2851 | ||
2866 | static ssize_t | 2852 | static int ftrace_pid_add(int p) |
2867 | ftrace_pid_write(struct file *filp, const char __user *ubuf, | ||
2868 | size_t cnt, loff_t *ppos) | ||
2869 | { | 2853 | { |
2870 | struct pid *pid; | 2854 | struct pid *pid; |
2871 | char buf[64]; | 2855 | struct ftrace_pid *fpid; |
2872 | long val; | 2856 | int ret = -EINVAL; |
2873 | int ret; | ||
2874 | 2857 | ||
2875 | if (cnt >= sizeof(buf)) | 2858 | mutex_lock(&ftrace_lock); |
2876 | return -EINVAL; | ||
2877 | 2859 | ||
2878 | if (copy_from_user(&buf, ubuf, cnt)) | 2860 | if (!p) |
2879 | return -EFAULT; | 2861 | pid = ftrace_swapper_pid; |
2862 | else | ||
2863 | pid = find_get_pid(p); | ||
2880 | 2864 | ||
2881 | buf[cnt] = 0; | 2865 | if (!pid) |
2866 | goto out; | ||
2882 | 2867 | ||
2883 | ret = strict_strtol(buf, 10, &val); | 2868 | ret = 0; |
2884 | if (ret < 0) | ||
2885 | return ret; | ||
2886 | 2869 | ||
2887 | mutex_lock(&ftrace_lock); | 2870 | list_for_each_entry(fpid, &ftrace_pids, list) |
2888 | if (val < 0) { | 2871 | if (fpid->pid == pid) |
2889 | /* disable pid tracing */ | 2872 | goto out_put; |
2890 | if (!ftrace_pid_trace) | ||
2891 | goto out; | ||
2892 | 2873 | ||
2893 | clear_ftrace_pid_task(&ftrace_pid_trace); | 2874 | ret = -ENOMEM; |
2894 | 2875 | ||
2895 | } else { | 2876 | fpid = kmalloc(sizeof(*fpid), GFP_KERNEL); |
2896 | /* swapper task is special */ | 2877 | if (!fpid) |
2897 | if (!val) { | 2878 | goto out_put; |
2898 | pid = ftrace_swapper_pid; | ||
2899 | if (pid == ftrace_pid_trace) | ||
2900 | goto out; | ||
2901 | } else { | ||
2902 | pid = find_get_pid(val); | ||
2903 | 2879 | ||
2904 | if (pid == ftrace_pid_trace) { | 2880 | list_add(&fpid->list, &ftrace_pids); |
2905 | put_pid(pid); | 2881 | fpid->pid = pid; |
2906 | goto out; | ||
2907 | } | ||
2908 | } | ||
2909 | 2882 | ||
2910 | if (ftrace_pid_trace) | 2883 | set_ftrace_pid_task(pid); |
2911 | clear_ftrace_pid_task(&ftrace_pid_trace); | ||
2912 | 2884 | ||
2913 | if (!pid) | 2885 | ftrace_update_pid_func(); |
2914 | goto out; | 2886 | ftrace_startup_enable(0); |
2887 | |||
2888 | mutex_unlock(&ftrace_lock); | ||
2889 | return 0; | ||
2890 | |||
2891 | out_put: | ||
2892 | if (pid != ftrace_swapper_pid) | ||
2893 | put_pid(pid); | ||
2894 | |||
2895 | out: | ||
2896 | mutex_unlock(&ftrace_lock); | ||
2897 | return ret; | ||
2898 | } | ||
2899 | |||
2900 | static void ftrace_pid_reset(void) | ||
2901 | { | ||
2902 | struct ftrace_pid *fpid, *safe; | ||
2903 | |||
2904 | mutex_lock(&ftrace_lock); | ||
2905 | list_for_each_entry_safe(fpid, safe, &ftrace_pids, list) { | ||
2906 | struct pid *pid = fpid->pid; | ||
2915 | 2907 | ||
2916 | ftrace_pid_trace = pid; | 2908 | clear_ftrace_pid_task(pid); |
2917 | 2909 | ||
2918 | set_ftrace_pid_task(ftrace_pid_trace); | 2910 | list_del(&fpid->list); |
2911 | kfree(fpid); | ||
2919 | } | 2912 | } |
2920 | 2913 | ||
2921 | /* update the function call */ | ||
2922 | ftrace_update_pid_func(); | 2914 | ftrace_update_pid_func(); |
2923 | ftrace_startup_enable(0); | 2915 | ftrace_startup_enable(0); |
2924 | 2916 | ||
2925 | out: | ||
2926 | mutex_unlock(&ftrace_lock); | 2917 | mutex_unlock(&ftrace_lock); |
2918 | } | ||
2927 | 2919 | ||
2928 | return cnt; | 2920 | static void *fpid_start(struct seq_file *m, loff_t *pos) |
2921 | { | ||
2922 | mutex_lock(&ftrace_lock); | ||
2923 | |||
2924 | if (list_empty(&ftrace_pids) && (!*pos)) | ||
2925 | return (void *) 1; | ||
2926 | |||
2927 | return seq_list_start(&ftrace_pids, *pos); | ||
2928 | } | ||
2929 | |||
2930 | static void *fpid_next(struct seq_file *m, void *v, loff_t *pos) | ||
2931 | { | ||
2932 | if (v == (void *)1) | ||
2933 | return NULL; | ||
2934 | |||
2935 | return seq_list_next(v, &ftrace_pids, pos); | ||
2936 | } | ||
2937 | |||
2938 | static void fpid_stop(struct seq_file *m, void *p) | ||
2939 | { | ||
2940 | mutex_unlock(&ftrace_lock); | ||
2941 | } | ||
2942 | |||
2943 | static int fpid_show(struct seq_file *m, void *v) | ||
2944 | { | ||
2945 | const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list); | ||
2946 | |||
2947 | if (v == (void *)1) { | ||
2948 | seq_printf(m, "no pid\n"); | ||
2949 | return 0; | ||
2950 | } | ||
2951 | |||
2952 | if (fpid->pid == ftrace_swapper_pid) | ||
2953 | seq_printf(m, "swapper tasks\n"); | ||
2954 | else | ||
2955 | seq_printf(m, "%u\n", pid_vnr(fpid->pid)); | ||
2956 | |||
2957 | return 0; | ||
2958 | } | ||
2959 | |||
2960 | static const struct seq_operations ftrace_pid_sops = { | ||
2961 | .start = fpid_start, | ||
2962 | .next = fpid_next, | ||
2963 | .stop = fpid_stop, | ||
2964 | .show = fpid_show, | ||
2965 | }; | ||
2966 | |||
2967 | static int | ||
2968 | ftrace_pid_open(struct inode *inode, struct file *file) | ||
2969 | { | ||
2970 | int ret = 0; | ||
2971 | |||
2972 | if ((file->f_mode & FMODE_WRITE) && | ||
2973 | (file->f_flags & O_TRUNC)) | ||
2974 | ftrace_pid_reset(); | ||
2975 | |||
2976 | if (file->f_mode & FMODE_READ) | ||
2977 | ret = seq_open(file, &ftrace_pid_sops); | ||
2978 | |||
2979 | return ret; | ||
2980 | } | ||
2981 | |||
2982 | static ssize_t | ||
2983 | ftrace_pid_write(struct file *filp, const char __user *ubuf, | ||
2984 | size_t cnt, loff_t *ppos) | ||
2985 | { | ||
2986 | char buf[64], *tmp; | ||
2987 | long val; | ||
2988 | int ret; | ||
2989 | |||
2990 | if (cnt >= sizeof(buf)) | ||
2991 | return -EINVAL; | ||
2992 | |||
2993 | if (copy_from_user(&buf, ubuf, cnt)) | ||
2994 | return -EFAULT; | ||
2995 | |||
2996 | buf[cnt] = 0; | ||
2997 | |||
2998 | /* | ||
2999 | * Allow "echo > set_ftrace_pid" or "echo -n '' > set_ftrace_pid" | ||
3000 | * to clean the filter quietly. | ||
3001 | */ | ||
3002 | tmp = strstrip(buf); | ||
3003 | if (strlen(tmp) == 0) | ||
3004 | return 1; | ||
3005 | |||
3006 | ret = strict_strtol(tmp, 10, &val); | ||
3007 | if (ret < 0) | ||
3008 | return ret; | ||
3009 | |||
3010 | ret = ftrace_pid_add(val); | ||
3011 | |||
3012 | return ret ? ret : cnt; | ||
3013 | } | ||
3014 | |||
3015 | static int | ||
3016 | ftrace_pid_release(struct inode *inode, struct file *file) | ||
3017 | { | ||
3018 | if (file->f_mode & FMODE_READ) | ||
3019 | seq_release(inode, file); | ||
3020 | |||
3021 | return 0; | ||
2929 | } | 3022 | } |
2930 | 3023 | ||
2931 | static const struct file_operations ftrace_pid_fops = { | 3024 | static const struct file_operations ftrace_pid_fops = { |
2932 | .read = ftrace_pid_read, | 3025 | .open = ftrace_pid_open, |
2933 | .write = ftrace_pid_write, | 3026 | .write = ftrace_pid_write, |
3027 | .read = seq_read, | ||
3028 | .llseek = seq_lseek, | ||
3029 | .release = ftrace_pid_release, | ||
2934 | }; | 3030 | }; |
2935 | 3031 | ||
2936 | static __init int ftrace_init_debugfs(void) | 3032 | static __init int ftrace_init_debugfs(void) |
@@ -3258,6 +3354,7 @@ void ftrace_graph_init_task(struct task_struct *t) | |||
3258 | { | 3354 | { |
3259 | /* Make sure we do not use the parent ret_stack */ | 3355 | /* Make sure we do not use the parent ret_stack */ |
3260 | t->ret_stack = NULL; | 3356 | t->ret_stack = NULL; |
3357 | t->curr_ret_stack = -1; | ||
3261 | 3358 | ||
3262 | if (ftrace_graph_active) { | 3359 | if (ftrace_graph_active) { |
3263 | struct ftrace_ret_stack *ret_stack; | 3360 | struct ftrace_ret_stack *ret_stack; |
@@ -3267,7 +3364,6 @@ void ftrace_graph_init_task(struct task_struct *t) | |||
3267 | GFP_KERNEL); | 3364 | GFP_KERNEL); |
3268 | if (!ret_stack) | 3365 | if (!ret_stack) |
3269 | return; | 3366 | return; |
3270 | t->curr_ret_stack = -1; | ||
3271 | atomic_set(&t->tracing_graph_pause, 0); | 3367 | atomic_set(&t->tracing_graph_pause, 0); |
3272 | atomic_set(&t->trace_overrun, 0); | 3368 | atomic_set(&t->trace_overrun, 0); |
3273 | t->ftrace_timestamp = 0; | 3369 | t->ftrace_timestamp = 0; |
@@ -3293,4 +3389,3 @@ void ftrace_graph_stop(void) | |||
3293 | ftrace_stop(); | 3389 | ftrace_stop(); |
3294 | } | 3390 | } |
3295 | #endif | 3391 | #endif |
3296 | |||