aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-04-29 15:12:32 -0400
committerSteven Rostedt <rostedt@goodmis.org>2011-05-18 15:29:44 -0400
commitb448c4e3ae6d20108dba1d7833f2c0d3dbad87ce (patch)
tree504e5a3640328458e652e41cfd2ed74e4652e5b3 /kernel/trace
parent94692349c4fc1bc74c19a28f9379509361a06a3b (diff)
ftrace: Replace FTRACE_FL_NOTRACE flag with a hash of ignored functions
To prepare for the accounting system that will allow multiple users of the function tracer, having the FTRACE_FL_NOTRACE as a flag in the dyn_trace record does not make sense. All ftrace_ops will soon have a hash of functions they should trace and not trace. By making a global hash of functions not to trace makes this easier for the transition. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/ftrace.c176
1 files changed, 150 insertions, 26 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index d3406346ced6..04c002a491fb 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -57,6 +57,7 @@
57/* hash bits for specific function selection */ 57/* hash bits for specific function selection */
58#define FTRACE_HASH_BITS 7 58#define FTRACE_HASH_BITS 7
59#define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS) 59#define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS)
60#define FTRACE_HASH_MAX_BITS 10
60 61
61/* ftrace_enabled is a method to turn ftrace on or off */ 62/* ftrace_enabled is a method to turn ftrace on or off */
62int ftrace_enabled __read_mostly; 63int ftrace_enabled __read_mostly;
@@ -865,6 +866,22 @@ enum {
865 FTRACE_START_FUNC_RET = (1 << 3), 866 FTRACE_START_FUNC_RET = (1 << 3),
866 FTRACE_STOP_FUNC_RET = (1 << 4), 867 FTRACE_STOP_FUNC_RET = (1 << 4),
867}; 868};
869struct ftrace_func_entry {
870 struct hlist_node hlist;
871 unsigned long ip;
872};
873
874struct ftrace_hash {
875 unsigned long size_bits;
876 struct hlist_head *buckets;
877 unsigned long count;
878};
879
880static struct hlist_head notrace_buckets[1 << FTRACE_HASH_MAX_BITS];
881static struct ftrace_hash notrace_hash = {
882 .size_bits = FTRACE_HASH_MAX_BITS,
883 .buckets = notrace_buckets,
884};
868 885
869static int ftrace_filtered; 886static int ftrace_filtered;
870 887
@@ -889,6 +906,79 @@ static struct ftrace_page *ftrace_pages;
889 906
890static struct dyn_ftrace *ftrace_free_records; 907static struct dyn_ftrace *ftrace_free_records;
891 908
909static struct ftrace_func_entry *
910ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip)
911{
912 unsigned long key;
913 struct ftrace_func_entry *entry;
914 struct hlist_head *hhd;
915 struct hlist_node *n;
916
917 if (!hash->count)
918 return NULL;
919
920 if (hash->size_bits > 0)
921 key = hash_long(ip, hash->size_bits);
922 else
923 key = 0;
924
925 hhd = &hash->buckets[key];
926
927 hlist_for_each_entry_rcu(entry, n, hhd, hlist) {
928 if (entry->ip == ip)
929 return entry;
930 }
931 return NULL;
932}
933
934static int add_hash_entry(struct ftrace_hash *hash, unsigned long ip)
935{
936 struct ftrace_func_entry *entry;
937 struct hlist_head *hhd;
938 unsigned long key;
939
940 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
941 if (!entry)
942 return -ENOMEM;
943
944 if (hash->size_bits)
945 key = hash_long(ip, hash->size_bits);
946 else
947 key = 0;
948
949 entry->ip = ip;
950 hhd = &hash->buckets[key];
951 hlist_add_head(&entry->hlist, hhd);
952 hash->count++;
953
954 return 0;
955}
956
957static void
958remove_hash_entry(struct ftrace_hash *hash,
959 struct ftrace_func_entry *entry)
960{
961 hlist_del(&entry->hlist);
962 kfree(entry);
963 hash->count--;
964}
965
966static void ftrace_hash_clear(struct ftrace_hash *hash)
967{
968 struct hlist_head *hhd;
969 struct hlist_node *tp, *tn;
970 struct ftrace_func_entry *entry;
971 int size = 1 << hash->size_bits;
972 int i;
973
974 for (i = 0; i < size; i++) {
975 hhd = &hash->buckets[i];
976 hlist_for_each_entry_safe(entry, tp, tn, hhd, hlist)
977 remove_hash_entry(hash, entry);
978 }
979 FTRACE_WARN_ON(hash->count);
980}
981
892/* 982/*
893 * This is a double for. Do not use 'break' to break out of the loop, 983 * This is a double for. Do not use 'break' to break out of the loop,
894 * you must use a goto. 984 * you must use a goto.
@@ -1032,7 +1122,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
1032 * If we want to enable it and filtering is on, enable it only if 1122 * If we want to enable it and filtering is on, enable it only if
1033 * it's filtered 1123 * it's filtered
1034 */ 1124 */
1035 if (enable && !(rec->flags & FTRACE_FL_NOTRACE)) { 1125 if (enable && !ftrace_lookup_ip(&notrace_hash, rec->ip)) {
1036 if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER)) 1126 if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER))
1037 flag = FTRACE_FL_ENABLED; 1127 flag = FTRACE_FL_ENABLED;
1038 } 1128 }
@@ -1465,7 +1555,7 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
1465 !(rec->flags & FTRACE_FL_FILTER)) || 1555 !(rec->flags & FTRACE_FL_FILTER)) ||
1466 1556
1467 ((iter->flags & FTRACE_ITER_NOTRACE) && 1557 ((iter->flags & FTRACE_ITER_NOTRACE) &&
1468 !(rec->flags & FTRACE_FL_NOTRACE))) { 1558 !ftrace_lookup_ip(&notrace_hash, rec->ip))) {
1469 rec = NULL; 1559 rec = NULL;
1470 goto retry; 1560 goto retry;
1471 } 1561 }
@@ -1609,14 +1699,15 @@ static void ftrace_filter_reset(int enable)
1609{ 1699{
1610 struct ftrace_page *pg; 1700 struct ftrace_page *pg;
1611 struct dyn_ftrace *rec; 1701 struct dyn_ftrace *rec;
1612 unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
1613 1702
1614 mutex_lock(&ftrace_lock); 1703 mutex_lock(&ftrace_lock);
1615 if (enable) 1704 if (enable) {
1616 ftrace_filtered = 0; 1705 ftrace_filtered = 0;
1617 do_for_each_ftrace_rec(pg, rec) { 1706 do_for_each_ftrace_rec(pg, rec) {
1618 rec->flags &= ~type; 1707 rec->flags &= ~FTRACE_FL_FILTER;
1619 } while_for_each_ftrace_rec(); 1708 } while_for_each_ftrace_rec();
1709 } else
1710 ftrace_hash_clear(&notrace_hash);
1620 mutex_unlock(&ftrace_lock); 1711 mutex_unlock(&ftrace_lock);
1621} 1712}
1622 1713
@@ -1716,13 +1807,36 @@ static int ftrace_match(char *str, char *regex, int len, int type)
1716 return matched; 1807 return matched;
1717} 1808}
1718 1809
1719static void 1810static int
1720update_record(struct dyn_ftrace *rec, unsigned long flag, int not) 1811update_record(struct dyn_ftrace *rec, int enable, int not)
1721{ 1812{
1722 if (not) 1813 struct ftrace_func_entry *entry;
1723 rec->flags &= ~flag; 1814 struct ftrace_hash *hash = &notrace_hash;
1724 else 1815 int ret = 0;
1725 rec->flags |= flag; 1816
1817 if (enable) {
1818 if (not)
1819 rec->flags &= ~FTRACE_FL_FILTER;
1820 else
1821 rec->flags |= FTRACE_FL_FILTER;
1822 } else {
1823 if (not) {
1824 /* Do nothing if it doesn't exist */
1825 entry = ftrace_lookup_ip(hash, rec->ip);
1826 if (!entry)
1827 return 0;
1828
1829 remove_hash_entry(hash, entry);
1830 } else {
1831 /* Do nothing if it exists */
1832 entry = ftrace_lookup_ip(hash, rec->ip);
1833 if (entry)
1834 return 0;
1835
1836 ret = add_hash_entry(hash, rec->ip);
1837 }
1838 }
1839 return ret;
1726} 1840}
1727 1841
1728static int 1842static int
@@ -1754,16 +1868,14 @@ static int match_records(char *buff, int len, char *mod, int enable, int not)
1754 struct dyn_ftrace *rec; 1868 struct dyn_ftrace *rec;
1755 int type = MATCH_FULL; 1869 int type = MATCH_FULL;
1756 char *search = buff; 1870 char *search = buff;
1757 unsigned long flag;
1758 int found = 0; 1871 int found = 0;
1872 int ret;
1759 1873
1760 if (len) { 1874 if (len) {
1761 type = filter_parse_regex(buff, len, &search, &not); 1875 type = filter_parse_regex(buff, len, &search, &not);
1762 search_len = strlen(search); 1876 search_len = strlen(search);
1763 } 1877 }
1764 1878
1765 flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
1766
1767 mutex_lock(&ftrace_lock); 1879 mutex_lock(&ftrace_lock);
1768 1880
1769 if (unlikely(ftrace_disabled)) 1881 if (unlikely(ftrace_disabled))
@@ -1772,7 +1884,11 @@ static int match_records(char *buff, int len, char *mod, int enable, int not)
1772 do_for_each_ftrace_rec(pg, rec) { 1884 do_for_each_ftrace_rec(pg, rec) {
1773 1885
1774 if (ftrace_match_record(rec, mod, search, search_len, type)) { 1886 if (ftrace_match_record(rec, mod, search, search_len, type)) {
1775 update_record(rec, flag, not); 1887 ret = update_record(rec, enable, not);
1888 if (ret < 0) {
1889 found = ret;
1890 goto out_unlock;
1891 }
1776 found = 1; 1892 found = 1;
1777 } 1893 }
1778 /* 1894 /*
@@ -1821,6 +1937,7 @@ static int
1821ftrace_mod_callback(char *func, char *cmd, char *param, int enable) 1937ftrace_mod_callback(char *func, char *cmd, char *param, int enable)
1822{ 1938{
1823 char *mod; 1939 char *mod;
1940 int ret = -EINVAL;
1824 1941
1825 /* 1942 /*
1826 * cmd == 'mod' because we only registered this func 1943 * cmd == 'mod' because we only registered this func
@@ -1832,15 +1949,19 @@ ftrace_mod_callback(char *func, char *cmd, char *param, int enable)
1832 1949
1833 /* we must have a module name */ 1950 /* we must have a module name */
1834 if (!param) 1951 if (!param)
1835 return -EINVAL; 1952 return ret;
1836 1953
1837 mod = strsep(&param, ":"); 1954 mod = strsep(&param, ":");
1838 if (!strlen(mod)) 1955 if (!strlen(mod))
1839 return -EINVAL; 1956 return ret;
1840 1957
1841 if (ftrace_match_module_records(func, mod, enable)) 1958 ret = ftrace_match_module_records(func, mod, enable);
1842 return 0; 1959 if (!ret)
1843 return -EINVAL; 1960 ret = -EINVAL;
1961 if (ret < 0)
1962 return ret;
1963
1964 return 0;
1844} 1965}
1845 1966
1846static struct ftrace_func_command ftrace_mod_cmd = { 1967static struct ftrace_func_command ftrace_mod_cmd = {
@@ -2132,14 +2253,17 @@ static int ftrace_process_regex(char *buff, int len, int enable)
2132{ 2253{
2133 char *func, *command, *next = buff; 2254 char *func, *command, *next = buff;
2134 struct ftrace_func_command *p; 2255 struct ftrace_func_command *p;
2135 int ret = -EINVAL; 2256 int ret;
2136 2257
2137 func = strsep(&next, ":"); 2258 func = strsep(&next, ":");
2138 2259
2139 if (!next) { 2260 if (!next) {
2140 if (ftrace_match_records(func, len, enable)) 2261 ret = ftrace_match_records(func, len, enable);
2141 return 0; 2262 if (!ret)
2142 return ret; 2263 ret = -EINVAL;
2264 if (ret < 0)
2265 return ret;
2266 return 0;
2143 } 2267 }
2144 2268
2145 /* command found */ 2269 /* command found */