]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - kernel/trace/trace_events_filter.c
Merge branch 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / kernel / trace / trace_events_filter.c
index 7ac691085276ac7e93d1eedefd99dcd2c11b377b..936c621bbf462395cc7f814cd6bbe01d7c841514 100644 (file)
@@ -27,8 +27,6 @@
 #include "trace.h"
 #include "trace_output.h"
 
-static DEFINE_MUTEX(filter_mutex);
-
 enum filter_op_ids
 {
        OP_OR,
@@ -151,6 +149,7 @@ static int filter_pred_or(struct filter_pred *pred __attribute((unused)),
        return val1 || val2;
 }
 
+/* Filter predicate for fixed sized arrays of characters */
 static int filter_pred_string(struct filter_pred *pred, void *event,
                              int val1, int val2)
 {
@@ -164,6 +163,30 @@ static int filter_pred_string(struct filter_pred *pred, void *event,
        return match;
 }
 
+/*
+ * Filter predicate for dynamic sized arrays of characters.
+ * These are implemented through a list of strings at the end
+ * of the entry.
+ * Also each of these strings have a field in the entry which
+ * contains its offset from the beginning of the entry.
+ * We have then first to get this field, dereference it
+ * and add it to the address of the entry, and at last we have
+ * the address of the string.
+ */
+static int filter_pred_strloc(struct filter_pred *pred, void *event,
+                             int val1, int val2)
+{
+       unsigned short str_loc = *(unsigned short *)(event + pred->offset);
+       char *addr = (char *)(event + str_loc);
+       int cmp, match;
+
+       cmp = strncmp(addr, pred->str_val, pred->str_len);
+
+       match = (!cmp) ^ pred->not;
+
+       return match;
+}
+
 static int filter_pred_none(struct filter_pred *pred, void *event,
                            int val1, int val2)
 {
@@ -269,12 +292,12 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
 {
        struct event_filter *filter = call->filter;
 
-       mutex_lock(&filter_mutex);
+       mutex_lock(&event_mutex);
        if (filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
                trace_seq_printf(s, "none\n");
-       mutex_unlock(&filter_mutex);
+       mutex_unlock(&event_mutex);
 }
 
 void print_subsystem_event_filter(struct event_subsystem *system,
@@ -282,12 +305,12 @@ void print_subsystem_event_filter(struct event_subsystem *system,
 {
        struct event_filter *filter = system->filter;
 
-       mutex_lock(&filter_mutex);
+       mutex_lock(&event_mutex);
        if (filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
                trace_seq_printf(s, "none\n");
-       mutex_unlock(&filter_mutex);
+       mutex_unlock(&event_mutex);
 }
 
 static struct ftrace_event_field *
@@ -356,6 +379,7 @@ void destroy_preds(struct ftrace_event_call *call)
                        filter_free_pred(filter->preds[i]);
        }
        kfree(filter->preds);
+       kfree(filter->filter_string);
        kfree(filter);
        call->filter = NULL;
 }
@@ -408,7 +432,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system)
                filter->n_preds = 0;
        }
 
-       mutex_lock(&event_mutex);
        list_for_each_entry(call, &ftrace_events, list) {
                if (!call->define_fields)
                        continue;
@@ -418,7 +441,6 @@ static void filter_free_subsystem_preds(struct event_subsystem *system)
                        remove_filter_string(call->filter);
                }
        }
-       mutex_unlock(&event_mutex);
 }
 
 static int filter_add_pred_fn(struct filter_parse_state *ps,
@@ -446,10 +468,18 @@ static int filter_add_pred_fn(struct filter_parse_state *ps,
        return 0;
 }
 
+enum {
+       FILTER_STATIC_STRING = 1,
+       FILTER_DYN_STRING
+};
+
 static int is_string_field(const char *type)
 {
+       if (strstr(type, "__data_loc") && strstr(type, "char"))
+               return FILTER_DYN_STRING;
+
        if (strchr(type, '[') && strstr(type, "char"))
-               return 1;
+               return FILTER_STATIC_STRING;
 
        return 0;
 }
@@ -512,6 +542,8 @@ 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;
 
@@ -536,14 +568,22 @@ static int filter_add_pred(struct filter_parse_state *ps,
                return -EINVAL;
        }
 
-       if (is_string_field(field->type)) {
-               fn = filter_pred_string;
+       string_type = is_string_field(field->type);
+       if (string_type) {
+               if (string_type == FILTER_STATIC_STRING)
+                       fn = filter_pred_string;
+               else
+                       fn = filter_pred_strloc;
                pred->str_len = field->size;
                if (pred->op == OP_NE)
                        pred->not = 1;
                return filter_add_pred_fn(ps, call, pred, fn);
        } else {
-               if (strict_strtoull(pred->str_val, 0, &val)) {
+               if (field->is_signed)
+                       ret = strict_strtoll(pred->str_val, 0, &val);
+               else
+                       ret = strict_strtoull(pred->str_val, 0, &val);
+               if (ret) {
                        parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0);
                        return -EINVAL;
                }
@@ -587,7 +627,6 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps,
        filter->preds[filter->n_preds] = pred;
        filter->n_preds++;
 
-       mutex_lock(&event_mutex);
        list_for_each_entry(call, &ftrace_events, list) {
 
                if (!call->define_fields)
@@ -600,12 +639,11 @@ static int filter_add_subsystem_pred(struct filter_parse_state *ps,
                if (err) {
                        filter_free_subsystem_preds(system);
                        parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0);
-                       break;
+                       goto out;
                }
                replace_filter_string(call->filter, filter_string);
        }
-       mutex_unlock(&event_mutex);
-
+out:
        return err;
 }
 
@@ -697,7 +735,7 @@ static inline void clear_operand_string(struct filter_parse_state *ps)
 
 static inline int append_operand_char(struct filter_parse_state *ps, char c)
 {
-       if (ps->operand.tail == MAX_FILTER_STR_VAL)
+       if (ps->operand.tail == MAX_FILTER_STR_VAL - 1)
                return -EINVAL;
 
        ps->operand.string[ps->operand.tail++] = c;
@@ -813,10 +851,19 @@ static void postfix_clear(struct filter_parse_state *ps)
 
 static int filter_parse(struct filter_parse_state *ps)
 {
+       int in_string = 0;
        int op, top_op;
        char ch;
 
        while ((ch = infix_next(ps))) {
+               if (ch == '"') {
+                       in_string ^= 1;
+                       continue;
+               }
+
+               if (in_string)
+                       goto parse_operand;
+
                if (isspace(ch))
                        continue;
 
@@ -870,6 +917,7 @@ static int filter_parse(struct filter_parse_state *ps)
                        }
                        continue;
                }
+parse_operand:
                if (append_operand_char(ps, ch)) {
                        parse_error(ps, FILT_ERR_OPERAND_TOO_LONG, 0);
                        return -EINVAL;
@@ -1021,18 +1069,19 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
 
        struct filter_parse_state *ps;
 
-       mutex_lock(&filter_mutex);
+       mutex_lock(&event_mutex);
 
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_disable_preds(call);
                remove_filter_string(call->filter);
-               mutex_unlock(&filter_mutex);
+               mutex_unlock(&event_mutex);
                return 0;
        }
 
+       err = -ENOMEM;
        ps = kzalloc(sizeof(*ps), GFP_KERNEL);
        if (!ps)
-               return -ENOMEM;
+               goto out_unlock;
 
        filter_disable_preds(call);
        replace_filter_string(call->filter, filter_string);
@@ -1052,8 +1101,8 @@ out:
        filter_opstack_clear(ps);
        postfix_clear(ps);
        kfree(ps);
-
-       mutex_unlock(&filter_mutex);
+out_unlock:
+       mutex_unlock(&event_mutex);
 
        return err;
 }
@@ -1065,18 +1114,19 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
 
        struct filter_parse_state *ps;
 
-       mutex_lock(&filter_mutex);
+       mutex_lock(&event_mutex);
 
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_free_subsystem_preds(system);
                remove_filter_string(system->filter);
-               mutex_unlock(&filter_mutex);
+               mutex_unlock(&event_mutex);
                return 0;
        }
 
+       err = -ENOMEM;
        ps = kzalloc(sizeof(*ps), GFP_KERNEL);
        if (!ps)
-               return -ENOMEM;
+               goto out_unlock;
 
        filter_free_subsystem_preds(system);
        replace_filter_string(system->filter, filter_string);
@@ -1096,8 +1146,8 @@ out:
        filter_opstack_clear(ps);
        postfix_clear(ps);
        kfree(ps);
-
-       mutex_unlock(&filter_mutex);
+out_unlock:
+       mutex_unlock(&event_mutex);
 
        return err;
 }