tracing: Add a method to pass in trace_array descriptor to option files
In preparation of having the multi buffer instances having their own trace option flags, the trace option files needs a way to not only pass in the flag they represent, but also the trace_array descriptor. A new field is added to the trace_array descriptor called trace_flags_index, which is a 32 byte character array representing a bit. This array is simply filled with the index of the array, where index_array[n] = n; Then the address of this array is passed to the file callbacks instead of the index of the flag index. Then to retrieve both the flag index and the trace_array descriptor: data is the passed in argument. index = *(unsigned char *)data; data -= index; /* Now data points to the address of the array in the trace_array */ tr = container_of(data, struct trace_array, trace_flags_index); Suggested-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:

committed by
Steven Rostedt

parent
983f938ae6
commit
9a38a8856f
@@ -6186,14 +6186,51 @@ static const struct file_operations trace_options_fops = {
|
|||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In order to pass in both the trace_array descriptor as well as the index
|
||||||
|
* to the flag that the trace option file represents, the trace_array
|
||||||
|
* has a character array of trace_flags_index[], which holds the index
|
||||||
|
* of the bit for the flag it represents. index[0] == 0, index[1] == 1, etc.
|
||||||
|
* The address of this character array is passed to the flag option file
|
||||||
|
* read/write callbacks.
|
||||||
|
*
|
||||||
|
* In order to extract both the index and the trace_array descriptor,
|
||||||
|
* get_tr_index() uses the following algorithm.
|
||||||
|
*
|
||||||
|
* idx = *ptr;
|
||||||
|
*
|
||||||
|
* As the pointer itself contains the address of the index (remember
|
||||||
|
* index[1] == 1).
|
||||||
|
*
|
||||||
|
* Then to get the trace_array descriptor, by subtracting that index
|
||||||
|
* from the ptr, we get to the start of the index itself.
|
||||||
|
*
|
||||||
|
* ptr - idx == &index[0]
|
||||||
|
*
|
||||||
|
* Then a simple container_of() from that pointer gets us to the
|
||||||
|
* trace_array descriptor.
|
||||||
|
*/
|
||||||
|
static void get_tr_index(void *data, struct trace_array **ptr,
|
||||||
|
unsigned int *pindex)
|
||||||
|
{
|
||||||
|
*pindex = *(unsigned char *)data;
|
||||||
|
|
||||||
|
*ptr = container_of(data - *pindex, struct trace_array,
|
||||||
|
trace_flags_index);
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
trace_options_core_read(struct file *filp, char __user *ubuf, size_t cnt,
|
trace_options_core_read(struct file *filp, char __user *ubuf, size_t cnt,
|
||||||
loff_t *ppos)
|
loff_t *ppos)
|
||||||
{
|
{
|
||||||
long index = (long)filp->private_data;
|
void *tr_index = filp->private_data;
|
||||||
|
struct trace_array *tr;
|
||||||
|
unsigned int index;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
if (global_trace.trace_flags & (1 << index))
|
get_tr_index(tr_index, &tr, &index);
|
||||||
|
|
||||||
|
if (tr->trace_flags & (1 << index))
|
||||||
buf = "1\n";
|
buf = "1\n";
|
||||||
else
|
else
|
||||||
buf = "0\n";
|
buf = "0\n";
|
||||||
@@ -6205,11 +6242,14 @@ static ssize_t
|
|||||||
trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
|
||||||
loff_t *ppos)
|
loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct trace_array *tr = &global_trace;
|
void *tr_index = filp->private_data;
|
||||||
long index = (long)filp->private_data;
|
struct trace_array *tr;
|
||||||
|
unsigned int index;
|
||||||
unsigned long val;
|
unsigned long val;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
get_tr_index(tr_index, &tr, &index);
|
||||||
|
|
||||||
ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
|
ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -6339,8 +6379,9 @@ create_trace_option_core_file(struct trace_array *tr,
|
|||||||
if (!t_options)
|
if (!t_options)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return trace_create_file(option, 0644, t_options, (void *)index,
|
return trace_create_file(option, 0644, t_options,
|
||||||
&trace_options_core_fops);
|
(void *)&tr->trace_flags_index[index],
|
||||||
|
&trace_options_core_fops);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __init void create_trace_options_dir(struct trace_array *tr)
|
static __init void create_trace_options_dir(struct trace_array *tr)
|
||||||
@@ -6490,6 +6531,15 @@ static void free_trace_buffers(struct trace_array *tr)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void init_trace_flags_index(struct trace_array *tr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Used by the trace options files */
|
||||||
|
for (i = 0; i < TRACE_FLAGS_MAX_SIZE; i++)
|
||||||
|
tr->trace_flags_index[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
static int instance_mkdir(const char *name)
|
static int instance_mkdir(const char *name)
|
||||||
{
|
{
|
||||||
struct trace_array *tr;
|
struct trace_array *tr;
|
||||||
@@ -6542,6 +6592,7 @@ static int instance_mkdir(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
init_tracer_tracefs(tr, tr->dir);
|
init_tracer_tracefs(tr, tr->dir);
|
||||||
|
init_trace_flags_index(tr);
|
||||||
|
|
||||||
list_add(&tr->list, &ftrace_trace_arrays);
|
list_add(&tr->list, &ftrace_trace_arrays);
|
||||||
|
|
||||||
@@ -7068,7 +7119,7 @@ __init static int tracer_alloc_buffers(void)
|
|||||||
* Make sure we don't accidently add more trace options
|
* Make sure we don't accidently add more trace options
|
||||||
* than we have bits for.
|
* than we have bits for.
|
||||||
*/
|
*/
|
||||||
BUILD_BUG_ON(TRACE_ITER_LAST_BIT > 32);
|
BUILD_BUG_ON(TRACE_ITER_LAST_BIT > TRACE_FLAGS_MAX_SIZE);
|
||||||
|
|
||||||
if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))
|
if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))
|
||||||
goto out;
|
goto out;
|
||||||
@@ -7128,6 +7179,8 @@ __init static int tracer_alloc_buffers(void)
|
|||||||
|
|
||||||
ftrace_init_global_array_ops(&global_trace);
|
ftrace_init_global_array_ops(&global_trace);
|
||||||
|
|
||||||
|
init_trace_flags_index(&global_trace);
|
||||||
|
|
||||||
register_tracer(&nop_trace);
|
register_tracer(&nop_trace);
|
||||||
|
|
||||||
/* All seems OK, enable tracing */
|
/* All seems OK, enable tracing */
|
||||||
|
@@ -168,6 +168,8 @@ struct trace_buffer {
|
|||||||
int cpu;
|
int cpu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define TRACE_FLAGS_MAX_SIZE 32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The trace array - an array of per-CPU trace arrays. This is the
|
* The trace array - an array of per-CPU trace arrays. This is the
|
||||||
* highest level data structure that individual tracers deal with.
|
* highest level data structure that individual tracers deal with.
|
||||||
@@ -218,6 +220,7 @@ struct trace_array {
|
|||||||
int clock_id;
|
int clock_id;
|
||||||
struct tracer *current_trace;
|
struct tracer *current_trace;
|
||||||
unsigned int trace_flags;
|
unsigned int trace_flags;
|
||||||
|
unsigned char trace_flags_index[TRACE_FLAGS_MAX_SIZE];
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
raw_spinlock_t start_lock;
|
raw_spinlock_t start_lock;
|
||||||
struct dentry *dir;
|
struct dentry *dir;
|
||||||
|
Reference in New Issue
Block a user