[for-next][PATCH 22/25] tracing: Add a method to pass in trace_array descriptor to option files

From: Steven Rostedt
Date: Thu Oct 01 2015 - 07:57:49 EST


From: "Steven Rostedt (Red Hat)" <rostedt@xxxxxxxxxxx>

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@xxxxxxxxx>
Signed-off-by: Steven Rostedt <rostedt@xxxxxxxxxxx>
---
kernel/trace/trace.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++------
kernel/trace/trace.h | 3 +++
2 files changed, 63 insertions(+), 7 deletions(-)

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 4e82f4ad68dc..5f481887e98b 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -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";
@@ -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;
@@ -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)
@@ -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;
@@ -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);

@@ -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;
@@ -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 */
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index eda4e6f8159b..423cb48a1d6d 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -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.
@@ -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;
--
2.5.1


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/