All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tom Zanussi <tom.zanussi@linux.intel.com>
To: rostedt@goodmis.org
Cc: tglx@linutronix.de, mhiramat@kernel.org, namhyung@kernel.org,
	vedang.patel@intel.com, linux-kernel@vger.kernel.org,
	linux-rt-users@vger.kernel.org,
	Tom Zanussi <tom.zanussi@linux.intel.com>
Subject: [PATCH 16/32] tracing: Add variable support to hist triggers
Date: Mon, 26 Jun 2017 17:49:17 -0500	[thread overview]
Message-ID: <990cbe4e75a04b81e94220751501d8adeec26804.1498510759.git.tom.zanussi@linux.intel.com> (raw)
In-Reply-To: <cover.1498510759.git.tom.zanussi@linux.intel.com>
In-Reply-To: <cover.1498510759.git.tom.zanussi@linux.intel.com>

Add support for saving the value of a current event's event field by
assigning it to a variable that can be read by a subsequent event.

The basic syntax for saving a variable is to simply prefix a unique
variable name not corresponding to any keyword along with an '=' sign
to any event field.

Both keys and values can be saved and retrieved in this way:

    # echo 'hist:keys=next_pid:vals=ts0=common_timestamp ...
    # echo 'hist:key=timer_pid=common_pid ...'

If a variable isn't a key variable or prefixed with 'vals=', the
associated event field will be saved in a variable but won't be summed
as a value:

    # echo 'hist:keys=next_pid:ts1=common_timestamp:...

Multiple variables can be assigned at the same time:

    # echo 'hist:keys=pid:vals=ts0=common_timestamp,b=field1,field2 ...

Multiple (or single) variables can also be assigned at the same time
using separate assignments:

    # echo 'hist:keys=pid:vals=ts0=common_timestamp:b=field1:c=field2 ...

Variables set as above can be used by being referenced from another
event, as described in a subsequent patch.

Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
---
 kernel/trace/trace_events_hist.c | 299 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 264 insertions(+), 35 deletions(-)

diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 5c351d7..75cac76 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -30,6 +30,13 @@ typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event,
 				struct ring_buffer_event *rbe);
 
 #define HIST_FIELD_OPERANDS_MAX	2
+#define HIST_FIELDS_MAX		(TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX)
+
+struct hist_var {
+	char				*name;
+	struct hist_trigger_data	*hist_data;
+	unsigned int			idx;
+};
 
 struct hist_field {
 	struct ftrace_event_field	*field;
@@ -40,6 +47,7 @@ struct hist_field {
 	unsigned int                    is_signed;
 	struct hist_field		*operands[HIST_FIELD_OPERANDS_MAX];
 	struct hist_trigger_data	*hist_data;
+	struct hist_var			var;
 };
 
 static u64 hist_field_none(struct hist_field *field, void *event,
@@ -138,6 +146,8 @@ enum hist_field_flags {
 	HIST_FIELD_FL_LOG2		= 512,
 	HIST_FIELD_FL_TIMESTAMP		= 1024,
 	HIST_FIELD_FL_TIMESTAMP_USECS	= 2048,
+	HIST_FIELD_FL_VAR		= 4096,
+	HIST_FIELD_FL_VAR_ONLY		= 8192,
 };
 
 struct hist_trigger_attrs {
@@ -150,13 +160,18 @@ struct hist_trigger_attrs {
 	bool		clear;
 	bool		ts_in_usecs;
 	unsigned int	map_bits;
+
+	char		*assignment_str[TRACING_MAP_VARS_MAX];
+	unsigned int	n_assignments;
 };
 
 struct hist_trigger_data {
-	struct hist_field               *fields[TRACING_MAP_FIELDS_MAX];
+	struct hist_field               *fields[HIST_FIELDS_MAX];
 	unsigned int			n_vals;
 	unsigned int			n_keys;
 	unsigned int			n_fields;
+	unsigned int			n_vars;
+	unsigned int			n_var_only;
 	unsigned int			key_size;
 	struct tracing_map_sort_key	sort_keys[TRACING_MAP_SORT_KEYS_MAX];
 	unsigned int			n_sort_keys;
@@ -164,6 +179,7 @@ struct hist_trigger_data {
 	struct hist_trigger_attrs	*attrs;
 	struct tracing_map		*map;
 	bool				enable_timestamps;
+	bool				remove;
 };
 
 static u64 hist_field_timestamp(struct hist_field *hist_field, void *event,
@@ -262,9 +278,14 @@ static int parse_map_size(char *str)
 
 static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs)
 {
+	unsigned int i;
+
 	if (!attrs)
 		return;
 
+	for (i = 0; i < attrs->n_assignments; i++)
+		kfree(attrs->assignment_str[i]);
+
 	kfree(attrs->name);
 	kfree(attrs->sort_key_str);
 	kfree(attrs->keys_str);
@@ -295,8 +316,22 @@ static int parse_assignment(char *str, struct hist_trigger_attrs *attrs)
 			goto out;
 		}
 		attrs->map_bits = map_bits;
-	} else
-		ret = -EINVAL;
+	} else {
+		char *assignment;
+
+		if (attrs->n_assignments == TRACING_MAP_VARS_MAX) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		assignment = kstrdup(str, GFP_KERNEL);
+		if (!assignment) {
+			ret = -ENOMEM;
+			goto out;
+		}
+
+		attrs->assignment_str[attrs->n_assignments++] = assignment;
+	}
  out:
 	return ret;
 }
@@ -423,12 +458,15 @@ static void destroy_hist_field(struct hist_field *hist_field,
 	for (i = 0; i < HIST_FIELD_OPERANDS_MAX; i++)
 		destroy_hist_field(hist_field->operands[i], ++level);
 
+	kfree(hist_field->var.name);
+
 	kfree(hist_field);
 }
 
 static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
 					    struct ftrace_event_field *field,
-					    unsigned long flags)
+					    unsigned long flags,
+					    char *var_name)
 {
 	struct hist_field *hist_field;
 
@@ -454,7 +492,7 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
 	if (flags & HIST_FIELD_FL_LOG2) {
 		unsigned long fl = flags & ~HIST_FIELD_FL_LOG2;
 		hist_field->fn = hist_field_log2;
-		hist_field->operands[0] = create_hist_field(hist_data, field, fl);
+		hist_field->operands[0] = create_hist_field(hist_data, field, fl, NULL);
 		hist_field->size = hist_field->operands[0]->size;
 		goto out;
 	}
@@ -489,14 +527,23 @@ static struct hist_field *create_hist_field(struct hist_trigger_data *hist_data,
 	hist_field->field = field;
 	hist_field->flags = flags;
 
+	if (var_name) {
+		hist_field->var.name = kstrdup(var_name, GFP_KERNEL);
+		if (!hist_field->var.name)
+			goto free;
+	}
+
 	return hist_field;
+ free:
+	destroy_hist_field(hist_field, 0);
+	return NULL;
 }
 
 static void destroy_hist_fields(struct hist_trigger_data *hist_data)
 {
 	unsigned int i;
 
-	for (i = 0; i < TRACING_MAP_FIELDS_MAX; i++) {
+	for (i = 0; i < HIST_FIELDS_MAX; i++) {
 		if (hist_data->fields[i]) {
 			destroy_hist_field(hist_data->fields[i], 0);
 			hist_data->fields[i] = NULL;
@@ -507,11 +554,12 @@ static void destroy_hist_fields(struct hist_trigger_data *hist_data)
 static int create_hitcount_val(struct hist_trigger_data *hist_data)
 {
 	hist_data->fields[HITCOUNT_IDX] =
-		create_hist_field(hist_data, NULL, HIST_FIELD_FL_HITCOUNT);
+		create_hist_field(hist_data, NULL, HIST_FIELD_FL_HITCOUNT, NULL);
 	if (!hist_data->fields[HITCOUNT_IDX])
 		return -ENOMEM;
 
 	hist_data->n_vals++;
+	hist_data->n_fields++;
 
 	if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
 		return -EINVAL;
@@ -519,19 +567,81 @@ static int create_hitcount_val(struct hist_trigger_data *hist_data)
 	return 0;
 }
 
+static struct hist_field *find_var_field(struct hist_trigger_data *hist_data,
+					 const char *var_name)
+{
+	struct hist_field *hist_field, *found = NULL;
+	int i;
+
+	for_each_hist_field(i, hist_data) {
+		hist_field = hist_data->fields[i];
+		if (hist_field && hist_field->flags & HIST_FIELD_FL_VAR &&
+		    strcmp(hist_field->var.name, var_name) == 0) {
+			found = hist_field;
+			break;
+		}
+	}
+
+	return found;
+}
+
+static struct hist_field *find_var(struct trace_event_file *file,
+				   const char *var_name)
+{
+	struct hist_trigger_data *hist_data;
+	struct event_trigger_data *test;
+	struct hist_field *hist_field;
+
+	list_for_each_entry_rcu(test, &file->triggers, list) {
+		if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
+			hist_data = test->private_data;
+			hist_field = find_var_field(hist_data, var_name);
+			if (hist_field)
+				return hist_field;
+		}
+	}
+
+	return NULL;
+}
+
 static int create_val_field(struct hist_trigger_data *hist_data,
 			    unsigned int val_idx,
 			    struct trace_event_file *file,
-			    char *field_str)
+			    char *field_str, bool var_only)
 {
 	struct ftrace_event_field *field = NULL;
+	char *field_name, *var_name;
 	unsigned long flags = 0;
-	char *field_name;
 	int ret = 0;
 
-	if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX))
+	if (WARN_ON(!var_only && val_idx >= TRACING_MAP_VALS_MAX))
 		return -EINVAL;
 
+	var_name = strsep(&field_str, "=");
+	if (field_str && var_name) {
+		if (find_var(file, var_name) &&
+		    !hist_data->remove) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		flags |= HIST_FIELD_FL_VAR;
+		hist_data->n_vars++;
+		if (hist_data->n_vars > TRACING_MAP_VARS_MAX) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		if (var_only)
+			flags |= HIST_FIELD_FL_VAR_ONLY;
+	} else if (!var_only && var_name != NULL && field_str == NULL) {
+		field_str = var_name;
+		var_name = NULL;
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
 	field_name = strsep(&field_str, ".");
 	if (field_str) {
 		if (strcmp(field_str, "hex") == 0)
@@ -553,15 +663,19 @@ static int create_val_field(struct hist_trigger_data *hist_data,
 		}
 	}
 
-	hist_data->fields[val_idx] = create_hist_field(hist_data, field, flags);
+	hist_data->fields[val_idx] = create_hist_field(hist_data, field, flags, var_name);
 	if (!hist_data->fields[val_idx]) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
 	++hist_data->n_vals;
+	++hist_data->n_fields;
 
-	if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
+	if (hist_data->fields[val_idx]->flags & HIST_FIELD_FL_VAR_ONLY)
+		hist_data->n_var_only++;
+
+	if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
 		ret = -EINVAL;
  out:
 	return ret;
@@ -571,7 +685,7 @@ static int create_val_fields(struct hist_trigger_data *hist_data,
 			     struct trace_event_file *file)
 {
 	char *fields_str, *field_str;
-	unsigned int i, j;
+	unsigned int i, j = 1;
 	int ret;
 
 	ret = create_hitcount_val(hist_data);
@@ -591,12 +705,15 @@ static int create_val_fields(struct hist_trigger_data *hist_data,
 		field_str = strsep(&fields_str, ",");
 		if (!field_str)
 			break;
+
 		if (strcmp(field_str, "hitcount") == 0)
 			continue;
-		ret = create_val_field(hist_data, j++, file, field_str);
+
+		ret = create_val_field(hist_data, j++, file, field_str, false);
 		if (ret)
 			goto out;
 	}
+
 	if (fields_str && (strcmp(fields_str, "hitcount") != 0))
 		ret = -EINVAL;
  out:
@@ -610,18 +727,32 @@ static int create_key_field(struct hist_trigger_data *hist_data,
 			    char *field_str)
 {
 	struct ftrace_event_field *field = NULL;
+	struct hist_field *hist_field = NULL;
 	unsigned long flags = 0;
 	unsigned int key_size;
+	char *var_name;
 	int ret = 0;
 
-	if (WARN_ON(key_idx >= TRACING_MAP_FIELDS_MAX))
+	if (WARN_ON(key_idx >= HIST_FIELDS_MAX))
 		return -EINVAL;
 
 	flags |= HIST_FIELD_FL_KEY;
 
+	var_name = strsep(&field_str, "=");
+	if (field_str) {
+		if (find_var(file, var_name) &&
+		    !hist_data->remove)
+			return -EINVAL;
+		flags |= HIST_FIELD_FL_VAR;
+	} else {
+		field_str = var_name;
+		var_name = NULL;
+	}
+
 	if (strcmp(field_str, "stacktrace") == 0) {
 		flags |= HIST_FIELD_FL_STACKTRACE;
 		key_size = sizeof(unsigned long) * HIST_STACKTRACE_DEPTH;
+		hist_field = create_hist_field(hist_data, NULL, flags, var_name);
 	} else {
 		char *field_name = strsep(&field_str, ".");
 
@@ -667,7 +798,7 @@ static int create_key_field(struct hist_trigger_data *hist_data,
 		}
 	}
 
-	hist_data->fields[key_idx] = create_hist_field(hist_data, field, flags);
+	hist_data->fields[key_idx] = create_hist_field(hist_data, field, flags, var_name);
 	if (!hist_data->fields[key_idx]) {
 		ret = -ENOMEM;
 		goto out;
@@ -683,6 +814,7 @@ static int create_key_field(struct hist_trigger_data *hist_data,
 	}
 
 	hist_data->n_keys++;
+	hist_data->n_fields++;
 
 	if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
 		return -EINVAL;
@@ -726,6 +858,29 @@ static int create_key_fields(struct hist_trigger_data *hist_data,
 	return ret;
 }
 
+static int create_var_fields(struct hist_trigger_data *hist_data,
+			     struct trace_event_file *file)
+{
+	unsigned int i, j, k = hist_data->n_vals;
+	char *str, *field_str;
+	int ret = 0;
+
+	for (i = 0; i < hist_data->attrs->n_assignments; i++) {
+		str = hist_data->attrs->assignment_str[i];
+
+		for (j = 0; j < TRACING_MAP_VARS_MAX; j++) {
+			field_str = strsep(&str, ",");
+			if (!field_str)
+				break;
+			ret = create_val_field(hist_data, k++, file, field_str, true);
+			if (ret)
+				goto out;
+		}
+	}
+ out:
+	return ret;
+}
+
 static int create_hist_fields(struct hist_trigger_data *hist_data,
 			      struct trace_event_file *file)
 {
@@ -735,11 +890,13 @@ static int create_hist_fields(struct hist_trigger_data *hist_data,
 	if (ret)
 		goto out;
 
-	ret = create_key_fields(hist_data, file);
+	ret = create_var_fields(hist_data, file);
 	if (ret)
 		goto out;
 
-	hist_data->n_fields = hist_data->n_vals + hist_data->n_keys;
+	ret = create_key_fields(hist_data, file);
+	if (ret)
+		goto out;
  out:
 	return ret;
 }
@@ -763,7 +920,7 @@ static int create_sort_keys(struct hist_trigger_data *hist_data)
 	char *fields_str = hist_data->attrs->sort_key_str;
 	struct tracing_map_sort_key *sort_key;
 	int descending, ret = 0;
-	unsigned int i, j;
+	unsigned int i, j, k;
 
 	hist_data->n_sort_keys = 1; /* we always have at least one, hitcount */
 
@@ -811,13 +968,21 @@ static int create_sort_keys(struct hist_trigger_data *hist_data)
 			continue;
 		}
 
-		for (j = 1; j < hist_data->n_fields; j++) {
+		for (j = 1, k = 1; j < hist_data->n_fields; j++) {
+			unsigned idx;
+
 			hist_field = hist_data->fields[j];
+			if (hist_field->flags & HIST_FIELD_FL_VAR_ONLY)
+				continue;
+
+			idx = k++;
+
 			test_name = hist_field_name(hist_field, 0);
+
 			if (test_name == NULL)
 				continue;
 			if (strcmp(field_name, test_name) == 0) {
-				sort_key->field_idx = j;
+				sort_key->field_idx = idx;
 				descending = is_descending(field_str);
 				if (descending < 0) {
 					ret = descending;
@@ -832,6 +997,7 @@ static int create_sort_keys(struct hist_trigger_data *hist_data)
 			break;
 		}
 	}
+
 	hist_data->n_sort_keys = i;
  out:
 	return ret;
@@ -872,12 +1038,19 @@ static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
 			idx = tracing_map_add_key_field(map,
 							hist_field->offset,
 							cmp_fn);
-
-		} else
+		} else if (!(hist_field->flags & HIST_FIELD_FL_VAR))
 			idx = tracing_map_add_sum_field(map);
 
 		if (idx < 0)
 			return idx;
+
+		if (hist_field->flags & HIST_FIELD_FL_VAR) {
+			idx = tracing_map_add_var(map);
+			if (idx < 0)
+				return idx;
+			hist_field->var.idx = idx;
+			hist_field->var.hist_data = hist_data;
+		}
 	}
 
 	return 0;
@@ -901,7 +1074,8 @@ static bool need_tracing_map_ops(struct hist_trigger_data *hist_data)
 static struct hist_trigger_data *
 create_hist_data(unsigned int map_bits,
 		 struct hist_trigger_attrs *attrs,
-		 struct trace_event_file *file)
+		 struct trace_event_file *file,
+		 bool remove)
 {
 	const struct tracing_map_ops *map_ops = NULL;
 	struct hist_trigger_data *hist_data;
@@ -912,6 +1086,7 @@ static bool need_tracing_map_ops(struct hist_trigger_data *hist_data)
 		return ERR_PTR(-ENOMEM);
 
 	hist_data->attrs = attrs;
+	hist_data->remove = remove;
 
 	ret = create_hist_fields(hist_data, file);
 	if (ret)
@@ -958,14 +1133,29 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
 				    struct ring_buffer_event *rbe)
 {
 	struct hist_field *hist_field;
-	unsigned int i;
+	unsigned int i, var_idx;
 	u64 hist_val;
 
 	for_each_hist_val_field(i, hist_data) {
 		hist_field = hist_data->fields[i];
-		hist_val = hist_field->fn(hist_field, rec, rbe);
+		hist_val = hist_field->fn(hist_field, rbe, rec);
+		if (hist_field->flags & HIST_FIELD_FL_VAR) {
+			var_idx = hist_field->var.idx;
+			tracing_map_set_var(elt, var_idx, hist_val);
+			if (hist_field->flags & HIST_FIELD_FL_VAR_ONLY)
+				continue;
+		}
 		tracing_map_update_sum(elt, i, hist_val);
 	}
+
+	for_each_hist_key_field(i, hist_data) {
+		hist_field = hist_data->fields[i];
+		if (hist_field->flags & HIST_FIELD_FL_VAR) {
+			hist_val = hist_field->fn(hist_field, rbe, rec);
+			var_idx = hist_field->var.idx;
+			tracing_map_set_var(elt, var_idx, hist_val);
+		}
+	}
 }
 
 static inline void add_to_key(char *compound_key, void *key,
@@ -1140,6 +1330,9 @@ static void hist_trigger_stacktrace_print(struct seq_file *m,
 	for (i = 1; i < hist_data->n_vals; i++) {
 		field_name = hist_field_name(hist_data->fields[i], 0);
 
+		if (hist_data->fields[i]->flags & HIST_FIELD_FL_VAR)
+			continue;
+
 		if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
 			seq_printf(m, "  %s: %10llx", field_name,
 				   tracing_map_read_sum(elt, i));
@@ -1263,6 +1456,9 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
 {
 	const char *field_name = hist_field_name(hist_field, 0);
 
+	if (hist_field->var.name)
+		seq_printf(m, "%s=", hist_field->var.name);
+
 	if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP)
 		seq_puts(m, "$common_timestamp");
 	else if (field_name)
@@ -1281,7 +1477,8 @@ static int event_hist_trigger_print(struct seq_file *m,
 				    struct event_trigger_data *data)
 {
 	struct hist_trigger_data *hist_data = data->private_data;
-	struct hist_field *key_field;
+	bool have_var_only = false;
+	struct hist_field *field;
 	unsigned int i;
 
 	seq_puts(m, "hist:");
@@ -1292,25 +1489,47 @@ static int event_hist_trigger_print(struct seq_file *m,
 	seq_puts(m, "keys=");
 
 	for_each_hist_key_field(i, hist_data) {
-		key_field = hist_data->fields[i];
+		field = hist_data->fields[i];
 
 		if (i > hist_data->n_vals)
 			seq_puts(m, ",");
 
-		if (key_field->flags & HIST_FIELD_FL_STACKTRACE)
+		if (field->flags & HIST_FIELD_FL_STACKTRACE)
 			seq_puts(m, "stacktrace");
 		else
-			hist_field_print(m, key_field);
+			hist_field_print(m, field);
 	}
 
 	seq_puts(m, ":vals=");
 
 	for_each_hist_val_field(i, hist_data) {
+		field = hist_data->fields[i];
+		if (field->flags & HIST_FIELD_FL_VAR_ONLY) {
+			have_var_only = true;
+			continue;
+		}
+
 		if (i == HITCOUNT_IDX)
 			seq_puts(m, "hitcount");
 		else {
 			seq_puts(m, ",");
-			hist_field_print(m, hist_data->fields[i]);
+			hist_field_print(m, field);
+		}
+	}
+
+	if (have_var_only) {
+		unsigned int n = 0;
+
+		seq_puts(m, ":");
+
+		for_each_hist_val_field(i, hist_data) {
+			field = hist_data->fields[i];
+
+			if (field->flags & HIST_FIELD_FL_VAR_ONLY) {
+				if (n++)
+					seq_puts(m, ",");
+				hist_field_print(m, field);
+			}
 		}
 	}
 
@@ -1318,7 +1537,10 @@ static int event_hist_trigger_print(struct seq_file *m,
 
 	for (i = 0; i < hist_data->n_sort_keys; i++) {
 		struct tracing_map_sort_key *sort_key;
-		unsigned int idx;
+		unsigned int idx, first_key_idx;
+
+		/* skip VAR_ONLY vals */
+		first_key_idx = hist_data->n_vals - hist_data->n_var_only;
 
 		sort_key = &hist_data->sort_keys[i];
 		idx = sort_key->field_idx;
@@ -1331,8 +1553,11 @@ static int event_hist_trigger_print(struct seq_file *m,
 
 		if (idx == HITCOUNT_IDX)
 			seq_puts(m, "hitcount");
-		else
+		else {
+			if (idx >= first_key_idx)
+				idx += hist_data->n_var_only;
 			hist_field_print(m, hist_data->fields[idx]);
+		}
 
 		if (sort_key->descending)
 			seq_puts(m, ".descending");
@@ -1656,12 +1881,16 @@ static int event_hist_trigger_func(struct event_command *cmd_ops,
 	struct hist_trigger_attrs *attrs;
 	struct event_trigger_ops *trigger_ops;
 	struct hist_trigger_data *hist_data;
+	bool remove = false;
 	char *trigger;
 	int ret = 0;
 
 	if (!param)
 		return -EINVAL;
 
+	if (glob[0] == '!')
+		remove = true;
+
 	/* separate the trigger from the filter (k:v [if filter]) */
 	trigger = strsep(&param, " \t");
 	if (!trigger)
@@ -1674,7 +1903,7 @@ static int event_hist_trigger_func(struct event_command *cmd_ops,
 	if (attrs->map_bits)
 		hist_trigger_bits = attrs->map_bits;
 
-	hist_data = create_hist_data(hist_trigger_bits, attrs, file);
+	hist_data = create_hist_data(hist_trigger_bits, attrs, file, remove);
 	if (IS_ERR(hist_data)) {
 		destroy_hist_trigger_attrs(attrs);
 		return PTR_ERR(hist_data);
@@ -1703,7 +1932,7 @@ static int event_hist_trigger_func(struct event_command *cmd_ops,
 			goto out_free;
 	}
 
-	if (glob[0] == '!') {
+	if (remove) {
 		cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
 		ret = 0;
 		goto out_free;
-- 
1.9.3

  parent reply	other threads:[~2017-06-26 22:53 UTC|newest]

Thread overview: 66+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-26 22:49 [PATCH 00/32] tracing: Inter-event (e.g. latency) support Tom Zanussi
2017-06-26 22:49 ` [PATCH 01/32] tracing: Add hist_field_name() accessor Tom Zanussi
2017-07-13  6:49   ` Piotr Gregor
2017-07-13 14:41     ` Tom Zanussi
2017-07-14  2:19   ` Namhyung Kim
2017-06-26 22:49 ` [PATCH 02/32] tracing: Reimplement log2 Tom Zanussi
2017-07-14  2:33   ` Namhyung Kim
2017-07-14 16:13     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 03/32] ring-buffer: Add interface for setting absolute time stamps Tom Zanussi
2017-07-14  5:25   ` Namhyung Kim
2017-07-14 16:14     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 04/32] ring-buffer: Redefine the unimplemented RINGBUF_TIME_TIME_STAMP Tom Zanussi
2017-07-02  8:51   ` Joel Fernandes (Google)
2017-06-26 22:49 ` [PATCH 05/32] tracing: Give event triggers access to ring_buffer_event Tom Zanussi
2017-06-26 22:49 ` [PATCH 06/32] tracing: Add ring buffer event param to hist field functions Tom Zanussi
2017-06-26 22:49 ` [PATCH 07/32] tracing: Increase tracing map KEYS_MAX size Tom Zanussi
2017-06-26 22:49 ` [PATCH 08/32] tracing: Break out hist trigger assignment parsing Tom Zanussi
2017-06-26 22:49 ` [PATCH 09/32] tracing: Make traceprobe parsing code reusable Tom Zanussi
2017-06-26 22:49 ` [PATCH 10/32] tracing: Add NO_DISCARD event file flag Tom Zanussi
2017-06-26 22:49 ` [PATCH 11/32] tracing: Add post-trigger flag to hist trigger command Tom Zanussi
2017-06-26 22:49 ` [PATCH 12/32] tracing: Add hist trigger timestamp support Tom Zanussi
2017-07-17  6:00   ` Namhyung Kim
2017-07-17 16:57     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 13/32] tracing: Add per-element variable support to tracing_map Tom Zanussi
2017-06-26 22:49 ` [PATCH 14/32] tracing: Add hist_data member to hist_field Tom Zanussi
2017-06-26 22:49 ` [PATCH 15/32] tracing: Add usecs modifier for hist trigger timestamps Tom Zanussi
2017-06-26 22:49 ` Tom Zanussi [this message]
2017-07-19  1:07   ` [PATCH 16/32] tracing: Add variable support to hist triggers Namhyung Kim
2017-07-19 15:40     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 17/32] tracing: Account for variables in named trigger compatibility Tom Zanussi
2017-06-26 22:49 ` [PATCH 18/32] tracing: Add simple expression support to hist triggers Tom Zanussi
2017-07-21  2:02   ` Namhyung Kim
2017-07-21 16:29     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 19/32] tracing: Add variable reference handling " Tom Zanussi
2017-07-21  3:31   ` Namhyung Kim
2017-07-21 16:41     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 20/32] tracing: Add support for dynamic tracepoints Tom Zanussi
2017-06-26 22:49 ` [PATCH 21/32] tracing: Add hist trigger action hook Tom Zanussi
2017-06-26 22:49 ` [PATCH 22/32] tracing: Add support for 'synthetic' events Tom Zanussi
2017-07-23 12:00   ` Namhyung Kim
2017-07-24 16:11     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 23/32] tracing: Add 'onmatch' hist trigger action support Tom Zanussi
2017-07-23 15:12   ` Namhyung Kim
2017-07-24 16:17     ` Tom Zanussi
2017-07-26  2:40   ` Namhyung Kim
2017-07-26 16:38     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 24/32] tracing: Add 'onmax' " Tom Zanussi
2017-07-26  3:04   ` Namhyung Kim
2017-07-26 16:45     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 25/32] tracing: Allow whitespace to surround hist trigger filter Tom Zanussi
2017-06-26 22:49 ` [PATCH 26/32] tracing: Make duplicate count from tracing_map available Tom Zanussi
2017-06-26 22:49 ` [PATCH 27/32] tracing: Add cpu field for hist triggers Tom Zanussi
2017-06-26 22:49 ` [PATCH 28/32] tracing: Add hist trigger support for variable reference aliases Tom Zanussi
2017-06-26 22:49 ` [PATCH 29/32] tracing: Add 'last error' error facility for hist triggers Tom Zanussi
2017-07-26  4:39   ` Namhyung Kim
2017-07-26 16:47     ` Tom Zanussi
2017-06-26 22:49 ` [PATCH 30/32] tracing: Add inter-event hist trigger Documentation Tom Zanussi
2017-06-26 22:49 ` [PATCH 31/32] tracing: Make tracing_set_clock() non-static Tom Zanussi
2017-06-26 22:49 ` [PATCH 32/32] tracing: Add a clock attribute for hist triggers Tom Zanussi
2017-06-27 14:58 ` [PATCH 00/32] tracing: Inter-event (e.g. latency) support Steven Rostedt
2017-06-28 14:21 ` Masami Hiramatsu
2017-06-28 19:09   ` Tom Zanussi
2017-07-01  7:01 ` Joel Fernandes (Google)
2017-07-12 19:17   ` Tom Zanussi
2017-07-04 16:12 ` Sebastian Andrzej Siewior
2017-07-12 19:20   ` Tom Zanussi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=990cbe4e75a04b81e94220751501d8adeec26804.1498510759.git.tom.zanussi@linux.intel.com \
    --to=tom.zanussi@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-users@vger.kernel.org \
    --cc=mhiramat@kernel.org \
    --cc=namhyung@kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=tglx@linutronix.de \
    --cc=vedang.patel@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.