Skip to content

Commit 7724822

Browse files
Steven Rostedtrostedt
authored andcommitted
tracing: Get trace_events kernel command line working again
With the new descriptors used to allow multiple buffers in the tracing directory added, the kernel command line parameter trace_events=... no longer works. This is because the top level (global) trace array now has a list of descriptors associated with the events and the files in the debugfs directory. But in early bootup, when the command line is processed and the events enabled, the trace array list of events has not been set up yet. Without the list of events in the trace array, the setting of events to record will fail because it would not match any events. The solution is to set up the top level array in two stages. The first is to just add the ftrace file descriptors that just point to the events. This will allow events to be enabled and start tracing. The second stage is called after the filesystem is set up, and this stage will create the debugfs event files and directories associated with the trace array events. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
1 parent 0c8916c commit 7724822

File tree

1 file changed

+136
-7
lines changed

1 file changed

+136
-7
lines changed

kernel/trace/trace_events.c

Lines changed: 136 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,28 @@ __trace_add_new_event(struct ftrace_event_call *call,
14731473
return event_create_dir(tr->event_dir, file, id, enable, filter, format);
14741474
}
14751475

1476+
/*
1477+
* Just create a decriptor for early init. A descriptor is required
1478+
* for enabling events at boot. We want to enable events before
1479+
* the filesystem is initialized.
1480+
*/
1481+
static __init int
1482+
__trace_early_add_new_event(struct ftrace_event_call *call,
1483+
struct trace_array *tr)
1484+
{
1485+
struct ftrace_event_file *file;
1486+
1487+
file = kzalloc(sizeof(*file), GFP_KERNEL);
1488+
if (!file)
1489+
return -ENOMEM;
1490+
1491+
file->event_call = call;
1492+
file->tr = tr;
1493+
list_add(&file->list, &tr->events);
1494+
1495+
return 0;
1496+
}
1497+
14761498
struct ftrace_module_file_ops;
14771499
static void __add_event_to_tracers(struct ftrace_event_call *call,
14781500
struct ftrace_module_file_ops *file_ops);
@@ -1709,6 +1731,56 @@ __trace_add_event_dirs(struct trace_array *tr)
17091731
}
17101732
}
17111733

1734+
/*
1735+
* The top level array has already had its ftrace_event_file
1736+
* descriptors created in order to allow for early events to
1737+
* be recorded. This function is called after the debugfs has been
1738+
* initialized, and we now have to create the files associated
1739+
* to the events.
1740+
*/
1741+
static __init void
1742+
__trace_early_add_event_dirs(struct trace_array *tr)
1743+
{
1744+
struct ftrace_event_file *file;
1745+
int ret;
1746+
1747+
1748+
list_for_each_entry(file, &tr->events, list) {
1749+
ret = event_create_dir(tr->event_dir, file,
1750+
&ftrace_event_id_fops,
1751+
&ftrace_enable_fops,
1752+
&ftrace_event_filter_fops,
1753+
&ftrace_event_format_fops);
1754+
if (ret < 0)
1755+
pr_warning("Could not create directory for event %s\n",
1756+
file->event_call->name);
1757+
}
1758+
}
1759+
1760+
/*
1761+
* For early boot up, the top trace array requires to have
1762+
* a list of events that can be enabled. This must be done before
1763+
* the filesystem is set up in order to allow events to be traced
1764+
* early.
1765+
*/
1766+
static __init void
1767+
__trace_early_add_events(struct trace_array *tr)
1768+
{
1769+
struct ftrace_event_call *call;
1770+
int ret;
1771+
1772+
list_for_each_entry(call, &ftrace_events, list) {
1773+
/* Early boot up should not have any modules loaded */
1774+
if (WARN_ON_ONCE(call->mod))
1775+
continue;
1776+
1777+
ret = __trace_early_add_new_event(call, tr);
1778+
if (ret < 0)
1779+
pr_warning("Could not create early event %s\n",
1780+
call->name);
1781+
}
1782+
}
1783+
17121784
/* Remove the event directory structure for a trace directory. */
17131785
static void
17141786
__trace_remove_event_dirs(struct trace_array *tr)
@@ -1763,25 +1835,23 @@ static __init int setup_trace_event(char *str)
17631835
}
17641836
__setup("trace_event=", setup_trace_event);
17651837

1766-
int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
1838+
/* Expects to have event_mutex held when called */
1839+
static int
1840+
create_event_toplevel_files(struct dentry *parent, struct trace_array *tr)
17671841
{
17681842
struct dentry *d_events;
17691843
struct dentry *entry;
17701844

1771-
mutex_lock(&event_mutex);
1772-
17731845
entry = debugfs_create_file("set_event", 0644, parent,
17741846
tr, &ftrace_set_event_fops);
17751847
if (!entry) {
17761848
pr_warning("Could not create debugfs 'set_event' entry\n");
1777-
mutex_unlock(&event_mutex);
17781849
return -ENOMEM;
17791850
}
17801851

17811852
d_events = debugfs_create_dir("events", parent);
17821853
if (!d_events) {
17831854
pr_warning("Could not create debugfs 'events' directory\n");
1784-
mutex_unlock(&event_mutex);
17851855
return -ENOMEM;
17861856
}
17871857

@@ -1798,13 +1868,64 @@ int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
17981868
tr, &ftrace_tr_enable_fops);
17991869

18001870
tr->event_dir = d_events;
1871+
1872+
return 0;
1873+
}
1874+
1875+
/**
1876+
* event_trace_add_tracer - add a instance of a trace_array to events
1877+
* @parent: The parent dentry to place the files/directories for events in
1878+
* @tr: The trace array associated with these events
1879+
*
1880+
* When a new instance is created, it needs to set up its events
1881+
* directory, as well as other files associated with events. It also
1882+
* creates the event hierachry in the @parent/events directory.
1883+
*
1884+
* Returns 0 on success.
1885+
*/
1886+
int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
1887+
{
1888+
int ret;
1889+
1890+
mutex_lock(&event_mutex);
1891+
1892+
ret = create_event_toplevel_files(parent, tr);
1893+
if (ret)
1894+
goto out_unlock;
1895+
18011896
down_write(&trace_event_mutex);
18021897
__trace_add_event_dirs(tr);
18031898
up_write(&trace_event_mutex);
18041899

1900+
out_unlock:
18051901
mutex_unlock(&event_mutex);
18061902

1807-
return 0;
1903+
return ret;
1904+
}
1905+
1906+
/*
1907+
* The top trace array already had its file descriptors created.
1908+
* Now the files themselves need to be created.
1909+
*/
1910+
static __init int
1911+
early_event_add_tracer(struct dentry *parent, struct trace_array *tr)
1912+
{
1913+
int ret;
1914+
1915+
mutex_lock(&event_mutex);
1916+
1917+
ret = create_event_toplevel_files(parent, tr);
1918+
if (ret)
1919+
goto out_unlock;
1920+
1921+
down_write(&trace_event_mutex);
1922+
__trace_early_add_event_dirs(tr);
1923+
up_write(&trace_event_mutex);
1924+
1925+
out_unlock:
1926+
mutex_unlock(&event_mutex);
1927+
1928+
return ret;
18081929
}
18091930

18101931
int event_trace_del_tracer(struct trace_array *tr)
@@ -1842,6 +1963,14 @@ static __init int event_trace_enable(void)
18421963
list_add(&call->list, &ftrace_events);
18431964
}
18441965

1966+
/*
1967+
* We need the top trace array to have a working set of trace
1968+
* points at early init, before the debug files and directories
1969+
* are created. Create the file entries now, and attach them
1970+
* to the actual file dentries later.
1971+
*/
1972+
__trace_early_add_events(tr);
1973+
18451974
while (true) {
18461975
token = strsep(&buf, ",");
18471976

@@ -1882,7 +2011,7 @@ static __init int event_trace_init(void)
18822011
if (trace_define_common_fields())
18832012
pr_warning("tracing: Failed to allocate common fields");
18842013

1885-
ret = event_trace_add_tracer(d_tracer, tr);
2014+
ret = early_event_add_tracer(d_tracer, tr);
18862015
if (ret)
18872016
return ret;
18882017

0 commit comments

Comments
 (0)