aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2013-03-12 19:35:13 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-03-15 00:36:04 -0400
commit3cd715de261182413b3487abfffe1b6af41b81b3 (patch)
tree14d9a48d2aa31eb1ad387477376e41f25031238f /kernel/trace
parent417944c4c7a0f657158d0515f3b8e8c043fd788f (diff)
tracing: Add function probe triggers to enable/disable events
Add triggers to function tracer that lets an event get enabled or disabled when a function is called: format is: <function>:enable_event:<system>:<event>[:<count>] <function>:disable_event:<system>:<event>[:<count>] echo 'schedule:enable_event:sched:sched_switch' > /debug/tracing/set_ftrace_filter Every time schedule is called, it will enable the sched_switch event. echo 'schedule:disable_event:sched:sched_switch:2' > /debug/tracing/set_ftrace_filter The first two times schedule is called while the sched_switch event is enabled, it will disable it. It will not count for a time that the event is already disabled (or enabled for enable_event). [ fixed return without mutex_unlock() - thanks to Dan Carpenter and smatch ] Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: Tom Zanussi <tom.zanussi@linux.intel.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace_events.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 106640b0df4a..c636523b1a59 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1798,6 +1798,283 @@ __trace_add_event_dirs(struct trace_array *tr)
1798 } 1798 }
1799} 1799}
1800 1800
1801#ifdef CONFIG_DYNAMIC_FTRACE
1802
1803/* Avoid typos */
1804#define ENABLE_EVENT_STR "enable_event"
1805#define DISABLE_EVENT_STR "disable_event"
1806
1807struct event_probe_data {
1808 struct ftrace_event_file *file;
1809 unsigned long count;
1810 int ref;
1811 bool enable;
1812};
1813
1814static struct ftrace_event_file *
1815find_event_file(struct trace_array *tr, const char *system, const char *event)
1816{
1817 struct ftrace_event_file *file;
1818 struct ftrace_event_call *call;
1819
1820 list_for_each_entry(file, &tr->events, list) {
1821
1822 call = file->event_call;
1823
1824 if (!call->name || !call->class || !call->class->reg)
1825 continue;
1826
1827 if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
1828 continue;
1829
1830 if (strcmp(event, call->name) == 0 &&
1831 strcmp(system, call->class->system) == 0)
1832 return file;
1833 }
1834 return NULL;
1835}
1836
1837static void
1838event_enable_probe(unsigned long ip, unsigned long parent_ip, void **_data)
1839{
1840 struct event_probe_data **pdata = (struct event_probe_data **)_data;
1841 struct event_probe_data *data = *pdata;
1842
1843 if (!data)
1844 return;
1845
1846 if (data->enable)
1847 clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &data->file->flags);
1848 else
1849 set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &data->file->flags);
1850}
1851
1852static void
1853event_enable_count_probe(unsigned long ip, unsigned long parent_ip, void **_data)
1854{
1855 struct event_probe_data **pdata = (struct event_probe_data **)_data;
1856 struct event_probe_data *data = *pdata;
1857
1858 if (!data)
1859 return;
1860
1861 if (!data->count)
1862 return;
1863
1864 /* Skip if the event is in a state we want to switch to */
1865 if (data->enable == !(data->file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
1866 return;
1867
1868 if (data->count != -1)
1869 (data->count)--;
1870
1871 event_enable_probe(ip, parent_ip, _data);
1872}
1873
1874static int
1875event_enable_print(struct seq_file *m, unsigned long ip,
1876 struct ftrace_probe_ops *ops, void *_data)
1877{
1878 struct event_probe_data *data = _data;
1879
1880 seq_printf(m, "%ps:", (void *)ip);
1881
1882 seq_printf(m, "%s:%s:%s",
1883 data->enable ? ENABLE_EVENT_STR : DISABLE_EVENT_STR,
1884 data->file->event_call->class->system,
1885 data->file->event_call->name);
1886
1887 if (data->count == -1)
1888 seq_printf(m, ":unlimited\n");
1889 else
1890 seq_printf(m, ":count=%ld\n", data->count);
1891
1892 return 0;
1893}
1894
1895static int
1896event_enable_init(struct ftrace_probe_ops *ops, unsigned long ip,
1897 void **_data)
1898{
1899 struct event_probe_data **pdata = (struct event_probe_data **)_data;
1900 struct event_probe_data *data = *pdata;
1901
1902 data->ref++;
1903 return 0;
1904}
1905
1906static void
1907event_enable_free(struct ftrace_probe_ops *ops, unsigned long ip,
1908 void **_data)
1909{
1910 struct event_probe_data **pdata = (struct event_probe_data **)_data;
1911 struct event_probe_data *data = *pdata;
1912
1913 if (WARN_ON_ONCE(data->ref <= 0))
1914 return;
1915
1916 data->ref--;
1917 if (!data->ref) {
1918 /* Remove the SOFT_MODE flag */
1919 __ftrace_event_enable_disable(data->file, 0, 1);
1920 module_put(data->file->event_call->mod);
1921 kfree(data);
1922 }
1923 *pdata = NULL;
1924}
1925
1926static struct ftrace_probe_ops event_enable_probe_ops = {
1927 .func = event_enable_probe,
1928 .print = event_enable_print,
1929 .init = event_enable_init,
1930 .free = event_enable_free,
1931};
1932
1933static struct ftrace_probe_ops event_enable_count_probe_ops = {
1934 .func = event_enable_count_probe,
1935 .print = event_enable_print,
1936 .init = event_enable_init,
1937 .free = event_enable_free,
1938};
1939
1940static struct ftrace_probe_ops event_disable_probe_ops = {
1941 .func = event_enable_probe,
1942 .print = event_enable_print,
1943 .init = event_enable_init,
1944 .free = event_enable_free,
1945};
1946
1947static struct ftrace_probe_ops event_disable_count_probe_ops = {
1948 .func = event_enable_count_probe,
1949 .print = event_enable_print,
1950 .init = event_enable_init,
1951 .free = event_enable_free,
1952};
1953
1954static int
1955event_enable_func(struct ftrace_hash *hash,
1956 char *glob, char *cmd, char *param, int enabled)
1957{
1958 struct trace_array *tr = top_trace_array();
1959 struct ftrace_event_file *file;
1960 struct ftrace_probe_ops *ops;
1961 struct event_probe_data *data;
1962 const char *system;
1963 const char *event;
1964 char *number;
1965 bool enable;
1966 int ret;
1967
1968 /* hash funcs only work with set_ftrace_filter */
1969 if (!enabled)
1970 return -EINVAL;
1971
1972 if (!param)
1973 return -EINVAL;
1974
1975 system = strsep(&param, ":");
1976 if (!param)
1977 return -EINVAL;
1978
1979 event = strsep(&param, ":");
1980
1981 mutex_lock(&event_mutex);
1982
1983 ret = -EINVAL;
1984 file = find_event_file(tr, system, event);
1985 if (!file)
1986 goto out;
1987
1988 enable = strcmp(cmd, ENABLE_EVENT_STR) == 0;
1989
1990 if (enable)
1991 ops = param ? &event_enable_count_probe_ops : &event_enable_probe_ops;
1992 else
1993 ops = param ? &event_disable_count_probe_ops : &event_disable_probe_ops;
1994
1995 if (glob[0] == '!') {
1996 unregister_ftrace_function_probe_func(glob+1, ops);
1997 ret = 0;
1998 goto out;
1999 }
2000
2001 ret = -ENOMEM;
2002 data = kzalloc(sizeof(*data), GFP_KERNEL);
2003 if (!data)
2004 goto out;
2005
2006 data->enable = enable;
2007 data->count = -1;
2008 data->file = file;
2009
2010 if (!param)
2011 goto out_reg;
2012
2013 number = strsep(&param, ":");
2014
2015 ret = -EINVAL;
2016 if (!strlen(number))
2017 goto out_free;
2018
2019 /*
2020 * We use the callback data field (which is a pointer)
2021 * as our counter.
2022 */
2023 ret = kstrtoul(number, 0, &data->count);
2024 if (ret)
2025 goto out_free;
2026
2027 out_reg:
2028 /* Don't let event modules unload while probe registered */
2029 ret = try_module_get(file->event_call->mod);
2030 if (!ret)
2031 goto out_free;
2032
2033 ret = __ftrace_event_enable_disable(file, 1, 1);
2034 if (ret < 0)
2035 goto out_put;
2036 ret = register_ftrace_function_probe(glob, ops, data);
2037 if (!ret)
2038 goto out_disable;
2039 out:
2040 mutex_unlock(&event_mutex);
2041 return ret;
2042
2043 out_disable:
2044 __ftrace_event_enable_disable(file, 0, 1);
2045 out_put:
2046 module_put(file->event_call->mod);
2047 out_free:
2048 kfree(data);
2049 goto out;
2050}
2051
2052static struct ftrace_func_command event_enable_cmd = {
2053 .name = ENABLE_EVENT_STR,
2054 .func = event_enable_func,
2055};
2056
2057static struct ftrace_func_command event_disable_cmd = {
2058 .name = DISABLE_EVENT_STR,
2059 .func = event_enable_func,
2060};
2061
2062static __init int register_event_cmds(void)
2063{
2064 int ret;
2065
2066 ret = register_ftrace_command(&event_enable_cmd);
2067 if (WARN_ON(ret < 0))
2068 return ret;
2069 ret = register_ftrace_command(&event_disable_cmd);
2070 if (WARN_ON(ret < 0))
2071 unregister_ftrace_command(&event_enable_cmd);
2072 return ret;
2073}
2074#else
2075static inline int register_event_cmds(void) { return 0; }
2076#endif /* CONFIG_DYNAMIC_FTRACE */
2077
1801/* 2078/*
1802 * The top level array has already had its ftrace_event_file 2079 * The top level array has already had its ftrace_event_file
1803 * descriptors created in order to allow for early events to 2080 * descriptors created in order to allow for early events to
@@ -2058,6 +2335,8 @@ static __init int event_trace_enable(void)
2058 2335
2059 trace_printk_start_comm(); 2336 trace_printk_start_comm();
2060 2337
2338 register_event_cmds();
2339
2061 return 0; 2340 return 0;
2062} 2341}
2063 2342