* [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field
@ 2009-08-06 6:05 Li Zefan
2009-08-06 6:06 ` [PATCH 1/3] tracing/filters: Add filter_type to struct ftrace_event_field Li Zefan
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Li Zefan @ 2009-08-06 6:05 UTC (permalink / raw)
To: Frédéric Weisbecker; +Cc: Steven Rostedt, Ingo Molnar, LKML
Currently only static strings and dynamic strings have their
own filter functions, other types of field are treated as
integers.
This patchset allows assigning a specific filter type to a
field, so a field which is defined as:
__field_ext(const char *, str, FILTER_PTR_STR)
will be treated as a string but not a plain pointer, and then
we can set the filter like this:
# echo 'str == foo' > filter
And it's easy to add more filter functions for different types
to turn these into valid operations:
(dev is of type dev_t)
# echo 'dev == 8:0' > filter
(callsite is of type void * or unsigned long)
# echo 'callsite == skb_free' > filter
[PATCH 1/3] tracing/filters: Add filter_type to struct ftrace_event_field
[PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT
[PATCH 3/3] tracing/filters: Support filtering for char * strings
---
include/linux/ftrace_event.h | 12 +++++++-
include/trace/ftrace.h | 28 ++++++++++++++++----
kernel/trace/trace.h | 2 +
kernel/trace/trace_events.c | 9 ++++++-
kernel/trace/trace_events_filter.c | 47 +++++++++++++++++++++++++----------
kernel/trace/trace_export.c | 7 +++--
6 files changed, 79 insertions(+), 26 deletions(-)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/3] tracing/filters: Add filter_type to struct ftrace_event_field
2009-08-06 6:05 [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Li Zefan
@ 2009-08-06 6:06 ` Li Zefan
2009-08-06 6:06 ` [PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT Li Zefan
` (2 subsequent siblings)
3 siblings, 0 replies; 14+ messages in thread
From: Li Zefan @ 2009-08-06 6:06 UTC (permalink / raw)
To: Frédéric Weisbecker; +Cc: Steven Rostedt, Ingo Molnar, LKML
The type of a field is stored as a string in @type, and here
we add @filter_type which is an enum value.
This prepares for later patches, so we can specifically assign
different @filter_type for the same @type.
For example normally a "char *" field is treated as a ptr,
but we may want it to be treated as a string when doing filting.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
kernel/trace/trace.h | 2 ++
kernel/trace/trace_events.c | 2 ++
kernel/trace/trace_events_filter.c | 21 +++++++++++++--------
3 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 3a87d46..b168927 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -759,6 +759,7 @@ struct ftrace_event_field {
struct list_head link;
char *name;
char *type;
+ int filter_type;
int offset;
int size;
int is_signed;
@@ -804,6 +805,7 @@ extern int apply_subsystem_event_filter(struct event_subsystem *system,
char *filter_string);
extern void print_subsystem_event_filter(struct event_subsystem *system,
struct trace_seq *s);
+extern int filter_assign_type(const char *type);
static inline int
filter_check_discard(struct ftrace_event_call *call, void *rec,
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 90cdec5..71b2085 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -44,9 +44,11 @@ int trace_define_field(struct ftrace_event_call *call, char *type,
if (!field->type)
goto err;
+ field->filter_type = filter_assign_type(type);
field->offset = offset;
field->size = size;
field->is_signed = is_signed;
+
list_add(&field->link, &call->fields);
return 0;
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 27c2dbe..4c8c5fd 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -477,10 +477,11 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
enum {
FILTER_STATIC_STRING = 1,
- FILTER_DYN_STRING
+ FILTER_DYN_STRING,
+ FILTER_OTHER,
};
-static int is_string_field(const char *type)
+int filter_assign_type(const char *type)
{
if (strstr(type, "__data_loc") && strstr(type, "char"))
return FILTER_DYN_STRING;
@@ -488,12 +489,18 @@ static int is_string_field(const char *type)
if (strchr(type, '[') && strstr(type, "char"))
return FILTER_STATIC_STRING;
- return 0;
+ return FILTER_OTHER;
+}
+
+static bool is_string_field(struct ftrace_event_field *field)
+{
+ return field->filter_type == FILTER_DYN_STRING ||
+ field->filter_type == FILTER_STATIC_STRING;
}
static int is_legal_op(struct ftrace_event_field *field, int op)
{
- if (is_string_field(field->type) && (op != OP_EQ && op != OP_NE))
+ if (is_string_field(field) && (op != OP_EQ && op != OP_NE))
return 0;
return 1;
@@ -550,7 +557,6 @@ static int filter_add_pred(struct filter_parse_state *ps,
struct ftrace_event_field *field;
filter_pred_fn_t fn;
unsigned long long val;
- int string_type;
int ret;
pred->fn = filter_pred_none;
@@ -578,9 +584,8 @@ static int filter_add_pred(struct filter_parse_state *ps,
return -EINVAL;
}
- string_type = is_string_field(field->type);
- if (string_type) {
- if (string_type == FILTER_STATIC_STRING)
+ if (is_string_field(field)) {
+ if (field->filter_type == FILTER_STATIC_STRING)
fn = filter_pred_string;
else
fn = filter_pred_strloc;
--
1.6.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT
2009-08-06 6:05 [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Li Zefan
2009-08-06 6:06 ` [PATCH 1/3] tracing/filters: Add filter_type to struct ftrace_event_field Li Zefan
@ 2009-08-06 6:06 ` Li Zefan
2009-08-06 14:17 ` Steven Rostedt
2009-08-06 6:06 ` [PATCH 3/3] tracing/filters: Support filtering for char * strings Li Zefan
2009-08-06 14:23 ` [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Steven Rostedt
3 siblings, 1 reply; 14+ messages in thread
From: Li Zefan @ 2009-08-06 6:06 UTC (permalink / raw)
To: Frédéric Weisbecker; +Cc: Steven Rostedt, Ingo Molnar, LKML
Add __field_ext(), so a field can be assigned to a specific
filter_type, which matches a corresponding filter function.
For example, a later patch will allow this:
__field_ext(const char *, str, FILTER_PTR_STR);
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
include/linux/ftrace_event.h | 11 +++++++++--
include/trace/ftrace.h | 28 ++++++++++++++++++++++------
kernel/trace/trace_events.c | 9 +++++++--
kernel/trace/trace_events_filter.c | 6 ------
kernel/trace/trace_export.c | 7 ++++---
5 files changed, 42 insertions(+), 19 deletions(-)
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 26d3673..14c388e 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -138,8 +138,15 @@ extern int filter_current_check_discard(struct ftrace_event_call *call,
void *rec,
struct ring_buffer_event *event);
+enum {
+ FILTER_STATIC_STRING = 1,
+ FILTER_DYN_STRING,
+ FILTER_OTHER,
+};
+
extern int trace_define_field(struct ftrace_event_call *call, char *type,
- char *name, int offset, int size, int is_signed);
+ char *name, int offset, int size,
+ int is_signed, int filter_type);
#define is_signed_type(type) (((type)(-1)) < 0)
@@ -167,7 +174,7 @@ do { \
#define __common_field(type, item, is_signed) \
ret = trace_define_field(event_call, #type, "common_" #item, \
offsetof(typeof(field.ent), item), \
- sizeof(field.ent.item), is_signed); \
+ sizeof(field.ent.item), is_signed, -1);\
if (ret) \
return ret;
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 380b603..8d8518f 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -21,6 +21,9 @@
#undef __field
#define __field(type, item) type item;
+#undef __field_ext
+#define __field_ext(type, item, filter_type) type item;
+
#undef __array
#define __array(type, item, len) type item[len];
@@ -64,6 +67,9 @@
#undef __field
#define __field(type, item);
+#undef __field_ext
+#define __field_ext(type, item, filter_type);
+
#undef __array
#define __array(type, item, len)
@@ -110,6 +116,9 @@
if (!ret) \
return 0;
+#undef __field_ext
+#define __field_ext(type, item, filter_type) __field(type, item)
+
#undef __array
#define __array(type, item, len) \
ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
@@ -264,28 +273,32 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \
#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
-#undef __field
-#define __field(type, item) \
+#undef __field_ext
+#define __field_ext(type, item, filter_type) \
ret = trace_define_field(event_call, #type, #item, \
offsetof(typeof(field), item), \
- sizeof(field.item), is_signed_type(type)); \
+ sizeof(field.item), \
+ is_signed_type(type), filter_type); \
if (ret) \
return ret;
+#undef __field
+#define __field(type, item) __field_ext(type, item, -1)
+
#undef __array
#define __array(type, item, len) \
BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \
ret = trace_define_field(event_call, #type "[" #len "]", #item, \
offsetof(typeof(field), item), \
- sizeof(field.item), 0); \
+ sizeof(field.item), 0, -1); \
if (ret) \
return ret;
#undef __dynamic_array
#define __dynamic_array(type, item, len) \
ret = trace_define_field(event_call, "__data_loc " #type "[]", #item, \
- offsetof(typeof(field), __data_loc_##item), \
- sizeof(field.__data_loc_##item), 0);
+ offsetof(typeof(field), __data_loc_##item), \
+ sizeof(field.__data_loc_##item), 0, -1);
#undef __string
#define __string(item, src) __dynamic_array(char, item, -1)
@@ -322,6 +335,9 @@ ftrace_define_fields_##call(void) \
#undef __field
#define __field(type, item)
+#undef __field_ext
+#define __field_ext(type, item, filter_type)
+
#undef __array
#define __array(type, item, len)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 71b2085..0cbad89 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -28,7 +28,8 @@ DEFINE_MUTEX(event_mutex);
LIST_HEAD(ftrace_events);
int trace_define_field(struct ftrace_event_call *call, char *type,
- char *name, int offset, int size, int is_signed)
+ char *name, int offset, int size,
+ int is_signed, int filter_type)
{
struct ftrace_event_field *field;
@@ -44,7 +45,11 @@ int trace_define_field(struct ftrace_event_call *call, char *type,
if (!field->type)
goto err;
- field->filter_type = filter_assign_type(type);
+ if (filter_type == -1)
+ field->filter_type = filter_assign_type(type);
+ else
+ field->filter_type = filter_type;
+
field->offset = offset;
field->size = size;
field->is_signed = is_signed;
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 4c8c5fd..5e7f031 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -475,12 +475,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
return 0;
}
-enum {
- FILTER_STATIC_STRING = 1,
- FILTER_DYN_STRING,
- FILTER_OTHER,
-};
-
int filter_assign_type(const char *type)
{
if (strstr(type, "__data_loc") && strstr(type, "char"))
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index d06cf89..4a9f273 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -156,7 +156,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
#define TRACE_FIELD(type, item, assign) \
ret = trace_define_field(event_call, #type, #item, \
offsetof(typeof(field), item), \
- sizeof(field.item), is_signed_type(type)); \
+ sizeof(field.item), \
+ is_signed_type(type), -1); \
if (ret) \
return ret;
@@ -164,7 +165,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
#define TRACE_FIELD_SPECIAL(type, item, len, cmd) \
ret = trace_define_field(event_call, #type "[" #len "]", #item, \
offsetof(typeof(field), item), \
- sizeof(field.item), 0); \
+ sizeof(field.item), 0, -1); \
if (ret) \
return ret;
@@ -172,7 +173,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
#define TRACE_FIELD_SIGN(type, item, assign, is_signed) \
ret = trace_define_field(event_call, #type, #item, \
offsetof(typeof(field), item), \
- sizeof(field.item), is_signed); \
+ sizeof(field.item), is_signed, -1); \
if (ret) \
return ret;
--
1.6.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/3] tracing/filters: Support filtering for char * strings
2009-08-06 6:05 [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Li Zefan
2009-08-06 6:06 ` [PATCH 1/3] tracing/filters: Add filter_type to struct ftrace_event_field Li Zefan
2009-08-06 6:06 ` [PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT Li Zefan
@ 2009-08-06 6:06 ` Li Zefan
2009-08-06 14:21 ` Steven Rostedt
2009-08-06 14:23 ` [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Steven Rostedt
3 siblings, 1 reply; 14+ messages in thread
From: Li Zefan @ 2009-08-06 6:06 UTC (permalink / raw)
To: Frédéric Weisbecker; +Cc: Steven Rostedt, Ingo Molnar, LKML
Usually, char * entries are dangerous in traces because the string
can be released whereas a pointer to it can still wait to be read from
the ring buffer.
But sometimes we can assume it's safe, like in case of RO data
(eg: __file__ or __line__, used in bkl trace event). If these RO data
are in a module and so is the call to the trace event, then it's safe,
because the ring buffer will be flushed once this module get unloaded.
To allow char * to be treated as a string:
TRACE_EVENT(...,
TP_STRUCT__entry(
__field_ext(const char *, name, FILTER_PTR_STRING)
...
)
...
);
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
---
include/linux/ftrace_event.h | 1 +
kernel/trace/trace_events_filter.c | 26 +++++++++++++++++++++++---
2 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 14c388e..1a98a61 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -141,6 +141,7 @@ extern int filter_current_check_discard(struct ftrace_event_call *call,
enum {
FILTER_STATIC_STRING = 1,
FILTER_DYN_STRING,
+ FILTER_PTR_STRING,
FILTER_OTHER,
};
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 5e7f031..b16923e 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -163,6 +163,20 @@ static int filter_pred_string(struct filter_pred *pred, void *event,
return match;
}
+/* Filter predicate for char * pointers */
+static int filter_pred_pchar(struct filter_pred *pred, void *event,
+ int val1, int val2)
+{
+ char **addr = (char **)(event + pred->offset);
+ int cmp, match;
+
+ cmp = strncmp(*addr, pred->str_val, pred->str_len);
+
+ match = (!cmp) ^ pred->not;
+
+ return match;
+}
+
/*
* Filter predicate for dynamic sized arrays of characters.
* These are implemented through a list of strings at the end
@@ -489,7 +503,8 @@ int filter_assign_type(const char *type)
static bool is_string_field(struct ftrace_event_field *field)
{
return field->filter_type == FILTER_DYN_STRING ||
- field->filter_type == FILTER_STATIC_STRING;
+ field->filter_type == FILTER_STATIC_STRING ||
+ field->filter_type == FILTER_PTR_STRING;
}
static int is_legal_op(struct ftrace_event_field *field, int op)
@@ -579,11 +594,16 @@ static int filter_add_pred(struct filter_parse_state *ps,
}
if (is_string_field(field)) {
+ pred->str_len = field->size;
+
if (field->filter_type == FILTER_STATIC_STRING)
fn = filter_pred_string;
- else
+ else if (field->filter_type == FILTER_DYN_STRING)
fn = filter_pred_strloc;
- pred->str_len = field->size;
+ else {
+ fn = filter_pred_pchar;
+ pred->str_len = strlen(pred->str_val);
+ }
} else {
if (field->is_signed)
ret = strict_strtoll(pred->str_val, 0, &val);
--
1.6.3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT
2009-08-06 6:06 ` [PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT Li Zefan
@ 2009-08-06 14:17 ` Steven Rostedt
0 siblings, 0 replies; 14+ messages in thread
From: Steven Rostedt @ 2009-08-06 14:17 UTC (permalink / raw)
To: Li Zefan; +Cc: Frédéric Weisbecker, Ingo Molnar, LKML
On Thu, 6 Aug 2009, Li Zefan wrote:
> Add __field_ext(), so a field can be assigned to a specific
> filter_type, which matches a corresponding filter function.
>
> For example, a later patch will allow this:
> __field_ext(const char *, str, FILTER_PTR_STR);
>
> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
> ---
> include/linux/ftrace_event.h | 11 +++++++++--
> include/trace/ftrace.h | 28 ++++++++++++++++++++++------
> kernel/trace/trace_events.c | 9 +++++++--
> kernel/trace/trace_events_filter.c | 6 ------
> kernel/trace/trace_export.c | 7 ++++---
> 5 files changed, 42 insertions(+), 19 deletions(-)
>
> diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
> index 26d3673..14c388e 100644
> --- a/include/linux/ftrace_event.h
> +++ b/include/linux/ftrace_event.h
> @@ -138,8 +138,15 @@ extern int filter_current_check_discard(struct ftrace_event_call *call,
> void *rec,
> struct ring_buffer_event *event);
>
> +enum {
> + FILTER_STATIC_STRING = 1,
> + FILTER_DYN_STRING,
> + FILTER_OTHER,
> +};
What about making FILTER_OTHER = 0?
> +
> extern int trace_define_field(struct ftrace_event_call *call, char *type,
> - char *name, int offset, int size, int is_signed);
> + char *name, int offset, int size,
> + int is_signed, int filter_type);
>
> #define is_signed_type(type) (((type)(-1)) < 0)
>
> @@ -167,7 +174,7 @@ do { \
> #define __common_field(type, item, is_signed) \
> ret = trace_define_field(event_call, #type, "common_" #item, \
> offsetof(typeof(field.ent), item), \
> - sizeof(field.ent.item), is_signed); \
> + sizeof(field.ent.item), is_signed, -1);\
> if (ret) \
> return ret;
>
> diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
> index 380b603..8d8518f 100644
> --- a/include/trace/ftrace.h
> +++ b/include/trace/ftrace.h
> @@ -21,6 +21,9 @@
> #undef __field
> #define __field(type, item) type item;
>
> +#undef __field_ext
> +#define __field_ext(type, item, filter_type) type item;
> +
> #undef __array
> #define __array(type, item, len) type item[len];
>
> @@ -64,6 +67,9 @@
> #undef __field
> #define __field(type, item);
>
> +#undef __field_ext
> +#define __field_ext(type, item, filter_type);
Did you mean to have that ';' in the define?
> +
> #undef __array
> #define __array(type, item, len)
>
> @@ -110,6 +116,9 @@
> if (!ret) \
> return 0;
>
> +#undef __field_ext
> +#define __field_ext(type, item, filter_type) __field(type, item)
> +
> #undef __array
> #define __array(type, item, len) \
> ret = trace_seq_printf(s, "\tfield:" #type " " #item "[" #len "];\t" \
> @@ -264,28 +273,32 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \
>
> #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
>
> -#undef __field
> -#define __field(type, item) \
> +#undef __field_ext
> +#define __field_ext(type, item, filter_type) \
> ret = trace_define_field(event_call, #type, #item, \
> offsetof(typeof(field), item), \
> - sizeof(field.item), is_signed_type(type)); \
> + sizeof(field.item), \
> + is_signed_type(type), filter_type); \
> if (ret) \
> return ret;
>
> +#undef __field
> +#define __field(type, item) __field_ext(type, item, -1)
Why not just set normal fields to be FILTER_OTHER?
> +
> #undef __array
> #define __array(type, item, len) \
> BUILD_BUG_ON(len > MAX_FILTER_STR_VAL); \
> ret = trace_define_field(event_call, #type "[" #len "]", #item, \
> offsetof(typeof(field), item), \
> - sizeof(field.item), 0); \
> + sizeof(field.item), 0, -1); \
> if (ret) \
> return ret;
>
> #undef __dynamic_array
> #define __dynamic_array(type, item, len) \
> ret = trace_define_field(event_call, "__data_loc " #type "[]", #item, \
> - offsetof(typeof(field), __data_loc_##item), \
> - sizeof(field.__data_loc_##item), 0);
> + offsetof(typeof(field), __data_loc_##item), \
> + sizeof(field.__data_loc_##item), 0, -1);
Yeah, I don't like the use of that magic -1 here.
Other than my comments, I like the patches so far.
-- Steve
>
> #undef __string
> #define __string(item, src) __dynamic_array(char, item, -1)
> @@ -322,6 +335,9 @@ ftrace_define_fields_##call(void) \
> #undef __field
> #define __field(type, item)
>
> +#undef __field_ext
> +#define __field_ext(type, item, filter_type)
> +
> #undef __array
> #define __array(type, item, len)
>
> diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
> index 71b2085..0cbad89 100644
> --- a/kernel/trace/trace_events.c
> +++ b/kernel/trace/trace_events.c
> @@ -28,7 +28,8 @@ DEFINE_MUTEX(event_mutex);
> LIST_HEAD(ftrace_events);
>
> int trace_define_field(struct ftrace_event_call *call, char *type,
> - char *name, int offset, int size, int is_signed)
> + char *name, int offset, int size,
> + int is_signed, int filter_type)
> {
> struct ftrace_event_field *field;
>
> @@ -44,7 +45,11 @@ int trace_define_field(struct ftrace_event_call *call, char *type,
> if (!field->type)
> goto err;
>
> - field->filter_type = filter_assign_type(type);
> + if (filter_type == -1)
> + field->filter_type = filter_assign_type(type);
> + else
> + field->filter_type = filter_type;
> +
> field->offset = offset;
> field->size = size;
> field->is_signed = is_signed;
> diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
> index 4c8c5fd..5e7f031 100644
> --- a/kernel/trace/trace_events_filter.c
> +++ b/kernel/trace/trace_events_filter.c
> @@ -475,12 +475,6 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
> return 0;
> }
>
> -enum {
> - FILTER_STATIC_STRING = 1,
> - FILTER_DYN_STRING,
> - FILTER_OTHER,
> -};
> -
> int filter_assign_type(const char *type)
> {
> if (strstr(type, "__data_loc") && strstr(type, "char"))
> diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
> index d06cf89..4a9f273 100644
> --- a/kernel/trace/trace_export.c
> +++ b/kernel/trace/trace_export.c
> @@ -156,7 +156,8 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
> #define TRACE_FIELD(type, item, assign) \
> ret = trace_define_field(event_call, #type, #item, \
> offsetof(typeof(field), item), \
> - sizeof(field.item), is_signed_type(type)); \
> + sizeof(field.item), \
> + is_signed_type(type), -1); \
> if (ret) \
> return ret;
>
> @@ -164,7 +165,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
> #define TRACE_FIELD_SPECIAL(type, item, len, cmd) \
> ret = trace_define_field(event_call, #type "[" #len "]", #item, \
> offsetof(typeof(field), item), \
> - sizeof(field.item), 0); \
> + sizeof(field.item), 0, -1); \
> if (ret) \
> return ret;
>
> @@ -172,7 +173,7 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
> #define TRACE_FIELD_SIGN(type, item, assign, is_signed) \
> ret = trace_define_field(event_call, #type, #item, \
> offsetof(typeof(field), item), \
> - sizeof(field.item), is_signed); \
> + sizeof(field.item), is_signed, -1); \
> if (ret) \
> return ret;
>
> --
> 1.6.3
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] tracing/filters: Support filtering for char * strings
2009-08-06 6:06 ` [PATCH 3/3] tracing/filters: Support filtering for char * strings Li Zefan
@ 2009-08-06 14:21 ` Steven Rostedt
2009-08-07 1:20 ` Li Zefan
0 siblings, 1 reply; 14+ messages in thread
From: Steven Rostedt @ 2009-08-06 14:21 UTC (permalink / raw)
To: Li Zefan; +Cc: Frédéric Weisbecker, Ingo Molnar, LKML
On Thu, 6 Aug 2009, Li Zefan wrote:
> Usually, char * entries are dangerous in traces because the string
> can be released whereas a pointer to it can still wait to be read from
> the ring buffer.
>
> But sometimes we can assume it's safe, like in case of RO data
> (eg: __file__ or __line__, used in bkl trace event). If these RO data
> are in a module and so is the call to the trace event, then it's safe,
> because the ring buffer will be flushed once this module get unloaded.
>
> To allow char * to be treated as a string:
>
> TRACE_EVENT(...,
>
> TP_STRUCT__entry(
> __field_ext(const char *, name, FILTER_PTR_STRING)
> ...
> )
>
> ...
> );
>
> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
> ---
> include/linux/ftrace_event.h | 1 +
> kernel/trace/trace_events_filter.c | 26 +++++++++++++++++++++++---
> 2 files changed, 24 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
> index 14c388e..1a98a61 100644
> --- a/include/linux/ftrace_event.h
> +++ b/include/linux/ftrace_event.h
> @@ -141,6 +141,7 @@ extern int filter_current_check_discard(struct ftrace_event_call *call,
> enum {
> FILTER_STATIC_STRING = 1,
> FILTER_DYN_STRING,
> + FILTER_PTR_STRING,
> FILTER_OTHER,
> };
>
> diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
> index 5e7f031..b16923e 100644
> --- a/kernel/trace/trace_events_filter.c
> +++ b/kernel/trace/trace_events_filter.c
> @@ -163,6 +163,20 @@ static int filter_pred_string(struct filter_pred *pred, void *event,
> return match;
> }
>
> +/* Filter predicate for char * pointers */
> +static int filter_pred_pchar(struct filter_pred *pred, void *event,
> + int val1, int val2)
> +{
> + char **addr = (char **)(event + pred->offset);
> + int cmp, match;
> +
> + cmp = strncmp(*addr, pred->str_val, pred->str_len);
> +
> + match = (!cmp) ^ pred->not;
> +
> + return match;
> +}
> +
> /*
> * Filter predicate for dynamic sized arrays of characters.
> * These are implemented through a list of strings at the end
> @@ -489,7 +503,8 @@ int filter_assign_type(const char *type)
> static bool is_string_field(struct ftrace_event_field *field)
> {
> return field->filter_type == FILTER_DYN_STRING ||
> - field->filter_type == FILTER_STATIC_STRING;
> + field->filter_type == FILTER_STATIC_STRING ||
> + field->filter_type == FILTER_PTR_STRING;
> }
>
> static int is_legal_op(struct ftrace_event_field *field, int op)
> @@ -579,11 +594,16 @@ static int filter_add_pred(struct filter_parse_state *ps,
> }
>
> if (is_string_field(field)) {
> + pred->str_len = field->size;
> +
> if (field->filter_type == FILTER_STATIC_STRING)
> fn = filter_pred_string;
> - else
> + else if (field->filter_type == FILTER_DYN_STRING)
> fn = filter_pred_strloc;
> - pred->str_len = field->size;
> + else {
> + fn = filter_pred_pchar;
> + pred->str_len = strlen(pred->str_val);
> + }
I'm a little dense here, where do we protect against someone making a
tracepoint that points to unsafe data?
-- Steve
> } else {
> if (field->is_signed)
> ret = strict_strtoll(pred->str_val, 0, &val);
> --
> 1.6.3
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field
2009-08-06 6:05 [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Li Zefan
` (2 preceding siblings ...)
2009-08-06 6:06 ` [PATCH 3/3] tracing/filters: Support filtering for char * strings Li Zefan
@ 2009-08-06 14:23 ` Steven Rostedt
2009-08-07 1:08 ` Li Zefan
3 siblings, 1 reply; 14+ messages in thread
From: Steven Rostedt @ 2009-08-06 14:23 UTC (permalink / raw)
To: Li Zefan; +Cc: Frédéric Weisbecker, Ingo Molnar, LKML
On Thu, 6 Aug 2009, Li Zefan wrote:
> Currently only static strings and dynamic strings have their
> own filter functions, other types of field are treated as
> integers.
>
> This patchset allows assigning a specific filter type to a
> field, so a field which is defined as:
>
> __field_ext(const char *, str, FILTER_PTR_STR)
>
> will be treated as a string but not a plain pointer, and then
> we can set the filter like this:
>
> # echo 'str == foo' > filter
>
> And it's easy to add more filter functions for different types
> to turn these into valid operations:
>
> (dev is of type dev_t)
> # echo 'dev == 8:0' > filter
>
> (callsite is of type void * or unsigned long)
> # echo 'callsite == skb_free' > filter
>
> [PATCH 1/3] tracing/filters: Add filter_type to struct ftrace_event_field
> [PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT
> [PATCH 3/3] tracing/filters: Support filtering for char * strings
I like the first two patches, but would like to see a V2 with the updates
I've mentioned. The last patch I do not fully understand its purpose.
I'll wait for V2 to pull it in.
Thanks!
-- Steve
> ---
> include/linux/ftrace_event.h | 12 +++++++-
> include/trace/ftrace.h | 28 ++++++++++++++++----
> kernel/trace/trace.h | 2 +
> kernel/trace/trace_events.c | 9 ++++++-
> kernel/trace/trace_events_filter.c | 47 +++++++++++++++++++++++++----------
> kernel/trace/trace_export.c | 7 +++--
> 6 files changed, 79 insertions(+), 26 deletions(-)
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field
2009-08-06 14:23 ` [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Steven Rostedt
@ 2009-08-07 1:08 ` Li Zefan
0 siblings, 0 replies; 14+ messages in thread
From: Li Zefan @ 2009-08-07 1:08 UTC (permalink / raw)
To: Steven Rostedt; +Cc: Frederic Weisbecker, Ingo Molnar, LKML
>> [PATCH 1/3] tracing/filters: Add filter_type to struct ftrace_event_field
>> [PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT
>> [PATCH 3/3] tracing/filters: Support filtering for char * strings
>
> I like the first two patches, but would like to see a V2 with the updates
> I've mentioned. The last patch I do not fully understand its purpose.
>
The last one is wanted by Frederic in his bkl trace events patchset:
http://lkml.org/lkml/2009/8/1/26
In that patch a ptr_str filter hook is always attached to "char *"
field, which is unsafe.
> I'll wait for V2 to pull it in.
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] tracing/filters: Support filtering for char * strings
2009-08-06 14:21 ` Steven Rostedt
@ 2009-08-07 1:20 ` Li Zefan
2009-08-07 2:54 ` Steven Rostedt
0 siblings, 1 reply; 14+ messages in thread
From: Li Zefan @ 2009-08-07 1:20 UTC (permalink / raw)
To: Steven Rostedt; +Cc: Frédéric Weisbecker, Ingo Molnar, LKML
>> if (is_string_field(field)) {
>> + pred->str_len = field->size;
>> +
>> if (field->filter_type == FILTER_STATIC_STRING)
>> fn = filter_pred_string;
>> - else
>> + else if (field->filter_type == FILTER_DYN_STRING)
>> fn = filter_pred_strloc;
>> - pred->str_len = field->size;
>> + else {
>> + fn = filter_pred_pchar;
>> + pred->str_len = strlen(pred->str_val);
>> + }
>
> I'm a little dense here, where do we protect against someone making a
> tracepoint that points to unsafe data?
>
We can't prevent anyone from doing insane things deliberately, but
we prevent from doing wrong things unconsciously.
Only if a TRACE_EVENT has a field defined as:
__field_ext(char *, name, FILTER_PTR_STR)
Here using FILTER_PTR_STR explicitly, he should know what he's doing.
Anyway, he can make a ptr pointing to unsafe data this way:
TP_STRUCT__entry(
__field(char *, name)
)
TP_printk("%s", name)
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] tracing/filters: Support filtering for char * strings
2009-08-07 1:20 ` Li Zefan
@ 2009-08-07 2:54 ` Steven Rostedt
2009-08-07 3:12 ` Li Zefan
0 siblings, 1 reply; 14+ messages in thread
From: Steven Rostedt @ 2009-08-07 2:54 UTC (permalink / raw)
To: Li Zefan; +Cc: Frédéric Weisbecker, Ingo Molnar, LKML
On Fri, 7 Aug 2009, Li Zefan wrote:
> >> if (is_string_field(field)) {
> >> + pred->str_len = field->size;
> >> +
> >> if (field->filter_type == FILTER_STATIC_STRING)
> >> fn = filter_pred_string;
> >> - else
> >> + else if (field->filter_type == FILTER_DYN_STRING)
> >> fn = filter_pred_strloc;
> >> - pred->str_len = field->size;
> >> + else {
> >> + fn = filter_pred_pchar;
> >> + pred->str_len = strlen(pred->str_val);
> >> + }
> >
> > I'm a little dense here, where do we protect against someone making a
> > tracepoint that points to unsafe data?
> >
>
> We can't prevent anyone from doing insane things deliberately, but
> we prevent from doing wrong things unconsciously.
>
> Only if a TRACE_EVENT has a field defined as:
>
> __field_ext(char *, name, FILTER_PTR_STR)
>
> Here using FILTER_PTR_STR explicitly, he should know what he's doing.
>
> Anyway, he can make a ptr pointing to unsafe data this way:
>
> TP_STRUCT__entry(
> __field(char *, name)
> )
> TP_printk("%s", name)
I guess the thing I'm missing is what's the difference of the two? Why
would a developer use __field_ext instead of doing it the unsafe way of
just __field?
I guess I don't see the developer doing something wrong unconsciously.
Well maybe I don't see this making the developer do it right
unconsciously.
What protection is this giving us?
-- Steve
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] tracing/filters: Support filtering for char * strings
2009-08-07 2:54 ` Steven Rostedt
@ 2009-08-07 3:12 ` Li Zefan
2009-08-07 3:22 ` Steven Rostedt
0 siblings, 1 reply; 14+ messages in thread
From: Li Zefan @ 2009-08-07 3:12 UTC (permalink / raw)
To: Steven Rostedt; +Cc: Frederic Weisbecker, Ingo Molnar, LKML
Steven Rostedt wrote:
> On Fri, 7 Aug 2009, Li Zefan wrote:
>
>>>> if (is_string_field(field)) {
>>>> + pred->str_len = field->size;
>>>> +
>>>> if (field->filter_type == FILTER_STATIC_STRING)
>>>> fn = filter_pred_string;
>>>> - else
>>>> + else if (field->filter_type == FILTER_DYN_STRING)
>>>> fn = filter_pred_strloc;
>>>> - pred->str_len = field->size;
>>>> + else {
>>>> + fn = filter_pred_pchar;
>>>> + pred->str_len = strlen(pred->str_val);
>>>> + }
>>> I'm a little dense here, where do we protect against someone making a
>>> tracepoint that points to unsafe data?
>>>
>> We can't prevent anyone from doing insane things deliberately, but
>> we prevent from doing wrong things unconsciously.
>>
>> Only if a TRACE_EVENT has a field defined as:
>>
>> __field_ext(char *, name, FILTER_PTR_STR)
>>
>> Here using FILTER_PTR_STR explicitly, he should know what he's doing.
>>
>> Anyway, he can make a ptr pointing to unsafe data this way:
>>
>> TP_STRUCT__entry(
>> __field(char *, name)
>> )
>> TP_printk("%s", name)
>
> I guess the thing I'm missing is what's the difference of the two? Why
> would a developer use __field_ext instead of doing it the unsafe way of
> just __field?
>
> I guess I don't see the developer doing something wrong unconsciously.
> Well maybe I don't see this making the developer do it right
> unconsciously.
>
> What protection is this giving us?
>
__field(char *) suggests it should be treated as plain pointer,
while __field_ext(char *, FILTER_PTR_STR) suggests he's aware it's
safe to dereference the pointer, for example the case in Frederic's
blk events.
In Frederic's initial version, "char *" field will always be
attached to ptr_str filter function. This is unsafe, because for
other fields defined as "char *" but not safe to dereference,
a user still can do this:
# echo 'name == abc' > filter
Then we'll deref a pointer that can point to unsafe data.
In this patch, this won't happen, as long as the developer is
aware that his use of __field_ext(char *) is right.
Otherwise, he will just use normal __field(char *) and print
the pointer itself in TP_printk().
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] tracing/filters: Support filtering for char * strings
2009-08-07 3:12 ` Li Zefan
@ 2009-08-07 3:22 ` Steven Rostedt
2009-08-07 3:24 ` Li Zefan
0 siblings, 1 reply; 14+ messages in thread
From: Steven Rostedt @ 2009-08-07 3:22 UTC (permalink / raw)
To: Li Zefan; +Cc: Frederic Weisbecker, Ingo Molnar, LKML
On Fri, 7 Aug 2009, Li Zefan wrote:
> >
> > What protection is this giving us?
> >
>
> __field(char *) suggests it should be treated as plain pointer,
> while __field_ext(char *, FILTER_PTR_STR) suggests he's aware it's
> safe to dereference the pointer, for example the case in Frederic's
> blk events.
>
> In Frederic's initial version, "char *" field will always be
> attached to ptr_str filter function. This is unsafe, because for
> other fields defined as "char *" but not safe to dereference,
> a user still can do this:
>
> # echo 'name == abc' > filter
>
> Then we'll deref a pointer that can point to unsafe data.
>
> In this patch, this won't happen, as long as the developer is
> aware that his use of __field_ext(char *) is right.
>
> Otherwise, he will just use normal __field(char *) and print
> the pointer itself in TP_printk().
Ah, so the answer I'm looking for is:
The filtering will not dereference "char *" unless the developer
explicitly sets FILTER_PTR_STR in __field_ext.
Is this above statement correct?
-- Steve
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] tracing/filters: Support filtering for char * strings
2009-08-07 3:22 ` Steven Rostedt
@ 2009-08-07 3:24 ` Li Zefan
2009-08-07 3:31 ` Steven Rostedt
0 siblings, 1 reply; 14+ messages in thread
From: Li Zefan @ 2009-08-07 3:24 UTC (permalink / raw)
To: Steven Rostedt; +Cc: Frederic Weisbecker, Ingo Molnar, LKML
Steven Rostedt wrote:
> On Fri, 7 Aug 2009, Li Zefan wrote:
>>> What protection is this giving us?
>>>
>> __field(char *) suggests it should be treated as plain pointer,
>> while __field_ext(char *, FILTER_PTR_STR) suggests he's aware it's
>> safe to dereference the pointer, for example the case in Frederic's
>> blk events.
>>
>> In Frederic's initial version, "char *" field will always be
>> attached to ptr_str filter function. This is unsafe, because for
>> other fields defined as "char *" but not safe to dereference,
>> a user still can do this:
>>
>> # echo 'name == abc' > filter
>>
>> Then we'll deref a pointer that can point to unsafe data.
>>
>> In this patch, this won't happen, as long as the developer is
>> aware that his use of __field_ext(char *) is right.
>>
>> Otherwise, he will just use normal __field(char *) and print
>> the pointer itself in TP_printk().
>
> Ah, so the answer I'm looking for is:
>
> The filtering will not dereference "char *" unless the developer
> explicitly sets FILTER_PTR_STR in __field_ext.
>
> Is this above statement correct?
>
Exactly. Sorry that I didn't explain it clearly in the
first place. :)
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/3] tracing/filters: Support filtering for char * strings
2009-08-07 3:24 ` Li Zefan
@ 2009-08-07 3:31 ` Steven Rostedt
0 siblings, 0 replies; 14+ messages in thread
From: Steven Rostedt @ 2009-08-07 3:31 UTC (permalink / raw)
To: Li Zefan; +Cc: Frederic Weisbecker, Ingo Molnar, LKML
On Fri, 7 Aug 2009, Li Zefan wrote:
> Steven Rostedt wrote:
> > Ah, so the answer I'm looking for is:
> >
> > The filtering will not dereference "char *" unless the developer
> > explicitly sets FILTER_PTR_STR in __field_ext.
> >
> > Is this above statement correct?
> >
>
> Exactly. Sorry that I didn't explain it clearly in the
> first place. :)
No problem. It is quite often that things so blatantly obvious to a
developer is totally foreign for the observer, that the simple explanation
is commonly overlooked.
I'll pull in your patches, with the -1 update, as well as adding my
above statement to this patch's change log.
I'll queue it for 32.
Thanks!
-- Steve
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2009-08-07 3:31 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-08-06 6:05 [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Li Zefan
2009-08-06 6:06 ` [PATCH 1/3] tracing/filters: Add filter_type to struct ftrace_event_field Li Zefan
2009-08-06 6:06 ` [PATCH 2/3] tracing/filters: Add __field_ext() to TRACE_EVENT Li Zefan
2009-08-06 14:17 ` Steven Rostedt
2009-08-06 6:06 ` [PATCH 3/3] tracing/filters: Support filtering for char * strings Li Zefan
2009-08-06 14:21 ` Steven Rostedt
2009-08-07 1:20 ` Li Zefan
2009-08-07 2:54 ` Steven Rostedt
2009-08-07 3:12 ` Li Zefan
2009-08-07 3:22 ` Steven Rostedt
2009-08-07 3:24 ` Li Zefan
2009-08-07 3:31 ` Steven Rostedt
2009-08-06 14:23 ` [PATCH 0/3] tracing/filters: Support specifying filter hook to a TRACE_EVENT field Steven Rostedt
2009-08-07 1:08 ` Li Zefan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox