Commit 4387d6d6 authored by Ingo Molnar's avatar Ingo Molnar

Merge branch 'tracing/ftrace' into tracing/core

parents f701d354 da74ff0f
......@@ -1684,23 +1684,20 @@ static struct seq_operations tracer_seq_ops = {
};
static struct trace_iterator *
__tracing_open(struct inode *inode, struct file *file, int *ret)
__tracing_open(struct inode *inode, struct file *file)
{
long cpu_file = (long) inode->i_private;
void *fail_ret = ERR_PTR(-ENOMEM);
struct trace_iterator *iter;
struct seq_file *m;
int cpu;
int cpu, ret;
if (tracing_disabled) {
*ret = -ENODEV;
return NULL;
}
if (tracing_disabled)
return ERR_PTR(-ENODEV);
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
if (!iter) {
*ret = -ENOMEM;
goto out;
}
if (!iter)
return ERR_PTR(-ENOMEM);
/*
* We make a copy of the current tracer to avoid concurrent
......@@ -1708,10 +1705,9 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
*/
mutex_lock(&trace_types_lock);
iter->trace = kzalloc(sizeof(*iter->trace), GFP_KERNEL);
if (!iter->trace) {
*ret = -ENOMEM;
if (!iter->trace)
goto fail;
}
if (current_trace)
*iter->trace = *current_trace;
......@@ -1750,9 +1746,11 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
}
/* TODO stop tracer */
*ret = seq_open(file, &tracer_seq_ops);
if (*ret)
ret = seq_open(file, &tracer_seq_ops);
if (ret < 0) {
fail_ret = ERR_PTR(ret);
goto fail_buffer;
}
m = file->private_data;
m->private = iter;
......@@ -1762,7 +1760,6 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
mutex_unlock(&trace_types_lock);
out:
return iter;
fail_buffer:
......@@ -1775,7 +1772,7 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
kfree(iter->trace);
kfree(iter);
return ERR_PTR(-ENOMEM);
return fail_ret;
}
int tracing_open_generic(struct inode *inode, struct file *filp)
......@@ -1815,9 +1812,12 @@ static int tracing_release(struct inode *inode, struct file *file)
static int tracing_open(struct inode *inode, struct file *file)
{
int ret;
struct trace_iterator *iter;
int ret = 0;
__tracing_open(inode, file, &ret);
iter = __tracing_open(inode, file);
if (IS_ERR(iter))
ret = PTR_ERR(iter);
return ret;
}
......@@ -1825,11 +1825,13 @@ static int tracing_open(struct inode *inode, struct file *file)
static int tracing_lt_open(struct inode *inode, struct file *file)
{
struct trace_iterator *iter;
int ret;
int ret = 0;
iter = __tracing_open(inode, file, &ret);
iter = __tracing_open(inode, file);
if (!ret)
if (IS_ERR(iter))
ret = PTR_ERR(iter);
else
iter->iter_flags |= TRACE_FILE_LAT_FMT;
return ret;
......@@ -2024,57 +2026,62 @@ static ssize_t
tracing_trace_options_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
int i;
struct tracer_opt *trace_opts;
u32 tracer_flags;
int len = 0;
char *buf;
int r = 0;
int len = 0;
u32 tracer_flags = current_trace->flags->val;
struct tracer_opt *trace_opts = current_trace->flags->opts;
int i;
/* calculate max size */
for (i = 0; trace_options[i]; i++) {
len += strlen(trace_options[i]);
len += 3; /* "no" and space */
len += 3; /* "no" and newline */
}
mutex_lock(&trace_types_lock);
tracer_flags = current_trace->flags->val;
trace_opts = current_trace->flags->opts;
/*
* Increase the size with names of options specific
* of the current tracer.
*/
for (i = 0; trace_opts[i].name; i++) {
len += strlen(trace_opts[i].name);
len += 3; /* "no" and space */
len += 3; /* "no" and newline */
}
/* +2 for \n and \0 */
buf = kmalloc(len + 2, GFP_KERNEL);
if (!buf)
if (!buf) {
mutex_unlock(&trace_types_lock);
return -ENOMEM;
}
for (i = 0; trace_options[i]; i++) {
if (trace_flags & (1 << i))
r += sprintf(buf + r, "%s ", trace_options[i]);
r += sprintf(buf + r, "%s\n", trace_options[i]);
else
r += sprintf(buf + r, "no%s ", trace_options[i]);
r += sprintf(buf + r, "no%s\n", trace_options[i]);
}
for (i = 0; trace_opts[i].name; i++) {
if (tracer_flags & trace_opts[i].bit)
r += sprintf(buf + r, "%s ",
r += sprintf(buf + r, "%s\n",
trace_opts[i].name);
else
r += sprintf(buf + r, "no%s ",
r += sprintf(buf + r, "no%s\n",
trace_opts[i].name);
}
mutex_unlock(&trace_types_lock);
r += sprintf(buf + r, "\n");
WARN_ON(r >= len + 2);
r = simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
kfree(buf);
return r;
}
......@@ -2149,7 +2156,9 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
/* If no option could be set, test the specific tracer options */
if (!trace_options[i]) {
mutex_lock(&trace_types_lock);
ret = set_tracer_option(current_trace, cmp, neg);
mutex_unlock(&trace_types_lock);
if (ret)
return ret;
}
......@@ -2275,8 +2284,17 @@ int tracer_init(struct tracer *t, struct trace_array *tr)
return t->init(tr);
}
struct trace_option_dentry;
static struct trace_option_dentry *
create_trace_option_files(struct tracer *tracer);
static void
destroy_trace_option_files(struct trace_option_dentry *topts);
static int tracing_set_tracer(const char *buf)
{
static struct trace_option_dentry *topts;
struct trace_array *tr = &global_trace;
struct tracer *t;
int ret = 0;
......@@ -2297,7 +2315,12 @@ static int tracing_set_tracer(const char *buf)
if (current_trace && current_trace->reset)
current_trace->reset(tr);
destroy_trace_option_files(topts);
current_trace = t;
topts = create_trace_option_files(current_trace);
if (t->init) {
ret = tracer_init(t, tr);
if (ret)
......@@ -3093,6 +3116,279 @@ static void tracing_init_debugfs_percpu(long cpu)
#include "trace_selftest.c"
#endif
struct trace_option_dentry {
struct tracer_opt *opt;
struct tracer_flags *flags;
struct dentry *entry;
};
static ssize_t
trace_options_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{
struct trace_option_dentry *topt = filp->private_data;
char *buf;
if (topt->flags->val & topt->opt->bit)
buf = "1\n";
else
buf = "0\n";
return simple_read_from_buffer(ubuf, cnt, ppos, buf, 2);
}
static ssize_t
trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
struct trace_option_dentry *topt = filp->private_data;
unsigned long val;
char buf[64];
int ret;
if (cnt >= sizeof(buf))
return -EINVAL;
if (copy_from_user(&buf, ubuf, cnt))
return -EFAULT;
buf[cnt] = 0;
ret = strict_strtoul(buf, 10, &val);
if (ret < 0)
return ret;
ret = 0;
switch (val) {
case 0:
/* do nothing if already cleared */
if (!(topt->flags->val & topt->opt->bit))
break;
mutex_lock(&trace_types_lock);
if (current_trace->set_flag)
ret = current_trace->set_flag(topt->flags->val,
topt->opt->bit, 0);
mutex_unlock(&trace_types_lock);
if (ret)
return ret;
topt->flags->val &= ~topt->opt->bit;
break;
case 1:
/* do nothing if already set */
if (topt->flags->val & topt->opt->bit)
break;
mutex_lock(&trace_types_lock);
if (current_trace->set_flag)
ret = current_trace->set_flag(topt->flags->val,
topt->opt->bit, 1);
mutex_unlock(&trace_types_lock);
if (ret)
return ret;
topt->flags->val |= topt->opt->bit;
break;
default:
return -EINVAL;
}
*ppos += cnt;
return cnt;
}
static const struct file_operations trace_options_fops = {
.open = tracing_open_generic,
.read = trace_options_read,
.write = trace_options_write,
};
static ssize_t
trace_options_core_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{
long index = (long)filp->private_data;
char *buf;
if (trace_flags & (1 << index))
buf = "1\n";
else
buf = "0\n";
return simple_read_from_buffer(ubuf, cnt, ppos, buf, 2);
}
static ssize_t
trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
long index = (long)filp->private_data;
char buf[64];
unsigned long val;
int ret;
if (cnt >= sizeof(buf))
return -EINVAL;
if (copy_from_user(&buf, ubuf, cnt))
return -EFAULT;
buf[cnt] = 0;
ret = strict_strtoul(buf, 10, &val);
if (ret < 0)
return ret;
switch (val) {
case 0:
trace_flags &= ~(1 << index);
break;
case 1:
trace_flags |= 1 << index;
break;
default:
return -EINVAL;
}
*ppos += cnt;
return cnt;
}
static const struct file_operations trace_options_core_fops = {
.open = tracing_open_generic,
.read = trace_options_core_read,
.write = trace_options_core_write,
};
static struct dentry *trace_options_init_dentry(void)
{
struct dentry *d_tracer;
static struct dentry *t_options;
if (t_options)
return t_options;
d_tracer = tracing_init_dentry();
if (!d_tracer)
return NULL;
t_options = debugfs_create_dir("options", d_tracer);
if (!t_options) {
pr_warning("Could not create debugfs directory 'options'\n");
return NULL;
}
return t_options;
}
static void
create_trace_option_file(struct trace_option_dentry *topt,
struct tracer_flags *flags,
struct tracer_opt *opt)
{
struct dentry *t_options;
struct dentry *entry;
t_options = trace_options_init_dentry();
if (!t_options)
return;
topt->flags = flags;
topt->opt = opt;
entry = debugfs_create_file(opt->name, 0644, t_options, topt,
&trace_options_fops);
topt->entry = entry;
}
static struct trace_option_dentry *
create_trace_option_files(struct tracer *tracer)
{
struct trace_option_dentry *topts;
struct tracer_flags *flags;
struct tracer_opt *opts;
int cnt;
if (!tracer)
return NULL;
flags = tracer->flags;
if (!flags || !flags->opts)
return NULL;
opts = flags->opts;
for (cnt = 0; opts[cnt].name; cnt++)
;
topts = kzalloc(sizeof(*topts) * (cnt + 1), GFP_KERNEL);
if (!topts)
return NULL;
for (cnt = 0; opts[cnt].name; cnt++)
create_trace_option_file(&topts[cnt], flags,
&opts[cnt]);
return topts;
}
static void
destroy_trace_option_files(struct trace_option_dentry *topts)
{
int cnt;
if (!topts)
return;
for (cnt = 0; topts[cnt].opt; cnt++) {
if (topts[cnt].entry)
debugfs_remove(topts[cnt].entry);
}
kfree(topts);
}
static struct dentry *
create_trace_option_core_file(const char *option, long index)
{
struct dentry *t_options;
struct dentry *entry;
t_options = trace_options_init_dentry();
if (!t_options)
return NULL;
entry = debugfs_create_file(option, 0644, t_options, (void *)index,
&trace_options_core_fops);
return entry;
}
static __init void create_trace_options_dir(void)
{
struct dentry *t_options;
struct dentry *entry;
int i;
t_options = trace_options_init_dentry();
if (!t_options)
return;
for (i = 0; trace_options[i]; i++) {
entry = create_trace_option_core_file(trace_options[i], i);
if (!entry)
pr_warning("Could not create debugfs %s entry\n",
trace_options[i]);
}
}
static __init int tracer_init_debugfs(void)
{
struct dentry *d_tracer;
......@@ -3111,6 +3407,8 @@ static __init int tracer_init_debugfs(void)
if (!entry)
pr_warning("Could not create debugfs 'trace_options' entry\n");
create_trace_options_dir();
entry = debugfs_create_file("tracing_cpumask", 0644, d_tracer,
NULL, &tracing_cpumask_fops);
if (!entry)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment