Skip to content

Commit

Permalink
tracing: Add a method to pass in trace_array descriptor to option files
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Steven Rostedt (Red Hat) committed Sep 30, 2015
1 parent 983f938 commit 9a38a88
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 7 deletions.
67 changes: 60 additions & 7 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -6186,14 +6186,51 @@ static const struct file_operations trace_options_fops = {
.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
trace_options_core_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{
long index = (long)filp->private_data;
void *tr_index = filp->private_data;
struct trace_array *tr;
unsigned int index;
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";
else
buf = "0\n";
Expand All @@ -6205,11 +6242,14 @@ static ssize_t
trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
loff_t *ppos)
{
struct trace_array *tr = &global_trace;
long index = (long)filp->private_data;
void *tr_index = filp->private_data;
struct trace_array *tr;
unsigned int index;
unsigned long val;
int ret;

get_tr_index(tr_index, &tr, &index);

ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
if (ret)
return ret;
Expand Down Expand Up @@ -6339,8 +6379,9 @@ create_trace_option_core_file(struct trace_array *tr,
if (!t_options)
return NULL;

return trace_create_file(option, 0644, t_options, (void *)index,
&trace_options_core_fops);
return trace_create_file(option, 0644, t_options,
(void *)&tr->trace_flags_index[index],
&trace_options_core_fops);
}

static __init void create_trace_options_dir(struct trace_array *tr)
Expand Down Expand Up @@ -6490,6 +6531,15 @@ static void free_trace_buffers(struct trace_array *tr)
#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)
{
struct trace_array *tr;
Expand Down Expand Up @@ -6542,6 +6592,7 @@ static int instance_mkdir(const char *name)
}

init_tracer_tracefs(tr, tr->dir);
init_trace_flags_index(tr);

list_add(&tr->list, &ftrace_trace_arrays);

Expand Down Expand Up @@ -7068,7 +7119,7 @@ __init static int tracer_alloc_buffers(void)
* Make sure we don't accidently add more trace options
* 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))
goto out;
Expand Down Expand Up @@ -7128,6 +7179,8 @@ __init static int tracer_alloc_buffers(void)

ftrace_init_global_array_ops(&global_trace);

init_trace_flags_index(&global_trace);

register_tracer(&nop_trace);

/* All seems OK, enable tracing */
Expand Down
3 changes: 3 additions & 0 deletions kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ struct trace_buffer {
int cpu;
};

#define TRACE_FLAGS_MAX_SIZE 32

/*
* The trace array - an array of per-CPU trace arrays. This is the
* highest level data structure that individual tracers deal with.
Expand Down Expand Up @@ -218,6 +220,7 @@ struct trace_array {
int clock_id;
struct tracer *current_trace;
unsigned int trace_flags;
unsigned char trace_flags_index[TRACE_FLAGS_MAX_SIZE];
unsigned int flags;
raw_spinlock_t start_lock;
struct dentry *dir;
Expand Down

0 comments on commit 9a38a88

Please sign in to comment.