summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2017-09-22 10:59:01 +0200
committerSebastian Andrzej Siewior <bigeasy@linutronix.de>2017-09-22 10:59:01 +0200
commitc5c5f525611e97a1aed5670c0d499070ee98163a (patch)
tree46a8e81830047df9bbe17ec3300f089e08b7225c
parent6820d5710a5845455e65c035d99b43bd223c3f9e (diff)
downloadlinux-rt-4.11.12-rt14-patches.tar.gz
[ANNOUNCE] v4.11.12-rt14v4.11.12-rt14-patches
Dear RT folks! I'm pleased to announce the v4.11.12-rt14 patch set. Changes since v4.11.12-rt13: - Update the "Inter-event (e.g. latency) support" patch to v2 as posted by Tom Zanussi on 2017-09-05. Patch 40 from this series has been replaced with Steven Rostedt's version of it (as posted as reply to the original patch) since the original broke some things. - The bluetooth code could deadlock itself on RT. Reported by Mart van de Wege. - The AMD-iommu driver produced "sleeping while atomic" warnings. Reported by Vinod Adhikary. - The local_lock locking around icmp_sk_lock needs to be a try-lock because it may be recursive. With this fixed, the deadlocks as reported by Jacek Konieczny are gone. - Since the futex work, the RT-only fixup needed adaption and was overseen which led to strange errors. Reported by Gusenleitner Klaus. Known issues none The delta patch against v4.11.12-rt13 is appended below and can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.11/incr/patch-4.11.12-rt13-rt14.patch.xz You can get this release via the git tree at: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v4.11.12-rt14 The RT patch against v4.11.12 can be found here: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.11/older/patch-4.11.12-rt14.patch.xz The split quilt queue is available at: https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.11/older/patches-4.11.12-rt14.tar.xz Sebastian Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-rw-r--r--patches/0001-tracing-Exclude-generic-fields-from-histograms.patch37
-rw-r--r--patches/0002-tracing-Add-support-to-detect-and-avoid-duplicates.patch108
-rw-r--r--patches/0003-tracing-Remove-code-which-merges-duplicates.patch187
-rw-r--r--patches/0004-tracing-Add-hist_field_name-accessor.patch (renamed from patches/0001-tracing-Add-hist_field_name-accessor.patch)29
-rw-r--r--patches/0005-tracing-Reimplement-log2.patch (renamed from patches/0002-tracing-Reimplement-log2.patch)14
-rw-r--r--patches/0006-ring-buffer-Add-interface-for-setting-absolute-time-.patch (renamed from patches/0003-ring-buffer-Add-interface-for-setting-absolute-time-.patch)47
-rw-r--r--patches/0007-tracing-Apply-absolute-timestamps-to-instance-max-bu.patch41
-rw-r--r--patches/0008-ring-buffer-Redefine-the-unimplemented-RINGBUF_TIME_.patch (renamed from patches/0004-ring-buffer-Redefine-the-unimplemented-RINGBUF_TIME_.patch)65
-rw-r--r--patches/0009-tracing-Give-event-triggers-access-to-ring_buffer_ev.patch (renamed from patches/0005-tracing-Give-event-triggers-access-to-ring_buffer_ev.patch)20
-rw-r--r--patches/0010-tracing-Add-NO_DISCARD-event-file-flag.patch105
-rw-r--r--patches/0010-tracing-Add-ring-buffer-event-param-to-hist-field-fu.patch (renamed from patches/0006-tracing-Add-ring-buffer-event-param-to-hist-field-fu.patch)14
-rw-r--r--patches/0011-tracing-Add-post-trigger-flag-to-hist-trigger-comman.patch28
-rw-r--r--patches/0011-tracing-Increase-tracing-map-KEYS_MAX-size.patch (renamed from patches/0007-tracing-Increase-tracing-map-KEYS_MAX-size.patch)4
-rw-r--r--patches/0012-tracing-Break-out-hist-trigger-assignment-parsing.patch (renamed from patches/0008-tracing-Break-out-hist-trigger-assignment-parsing.patch)4
-rw-r--r--patches/0013-tracing-Make-traceprobe-parsing-code-reusable.patch (renamed from patches/0009-tracing-Make-traceprobe-parsing-code-reusable.patch)8
-rw-r--r--patches/0014-tracing-Add-hist-trigger-timestamp-support.patch (renamed from patches/0012-tracing-Add-hist-trigger-timestamp-support.patch)43
-rw-r--r--patches/0015-tracing-Add-per-element-variable-support-to-tracing_.patch (renamed from patches/0013-tracing-Add-per-element-variable-support-to-tracing_.patch)32
-rw-r--r--patches/0016-tracing-Add-hist_data-member-to-hist_field.patch (renamed from patches/0014-tracing-Add-hist_data-member-to-hist_field.patch)16
-rw-r--r--patches/0017-tracing-Add-usecs-modifier-for-hist-trigger-timestam.patch (renamed from patches/0015-tracing-Add-usecs-modifier-for-hist-trigger-timestam.patch)12
-rw-r--r--patches/0018-tracing-Add-variable-support-to-hist-triggers.patch (renamed from patches/0016-tracing-Add-variable-support-to-hist-triggers.patch)288
-rw-r--r--patches/0019-tracing-Account-for-variables-in-named-trigger-compa.patch (renamed from patches/0017-tracing-Account-for-variables-in-named-trigger-compa.patch)8
-rw-r--r--patches/0020-tracing-Add-simple-expression-support-to-hist-trigge.patch (renamed from patches/0018-tracing-Add-simple-expression-support-to-hist-trigge.patch)299
-rw-r--r--patches/0020-tracing-Add-support-for-dynamic-tracepoints.patch195
-rw-r--r--patches/0021-tracing-Generalize-per-element-hist-trigger-data.patch143
-rw-r--r--patches/0022-tracing-Pass-tracing_map_elt-to-hist_field-accessor-.patch221
-rw-r--r--patches/0023-tracing-Add-hist_field-type-field.patch113
-rw-r--r--patches/0023-tracing-Add-onmatch-hist-trigger-action-support.patch1268
-rw-r--r--patches/0024-tracing-Add-variable-reference-handling-to-hist-trig.patch (renamed from patches/0019-tracing-Add-variable-reference-handling-to-hist-trig.patch)593
-rw-r--r--patches/0025-tracing-Add-support-for-dynamic-tracepoints.patch78
-rw-r--r--patches/0026-tracing-Add-hist-trigger-action-hook.patch (renamed from patches/0021-tracing-Add-hist-trigger-action-hook.patch)32
-rw-r--r--patches/0026-tracing-Make-duplicate-count-from-tracing_map-availa.patch124
-rw-r--r--patches/0027-tracing-Add-support-for-synthetic-events.patch (renamed from patches/0022-tracing-Add-support-for-synthetic-events.patch)432
-rw-r--r--patches/0028-tracing-Add-support-for-field-variables.patch567
-rw-r--r--patches/0029-tracing-Add-onmatch-hist-trigger-action-support.patch550
-rw-r--r--patches/0030-tracing-Add-onmax-hist-trigger-action-support.patch (renamed from patches/0024-tracing-Add-onmax-hist-trigger-action-support.patch)132
-rw-r--r--patches/0031-tracing-Allow-whitespace-to-surround-hist-trigger-fi.patch (renamed from patches/0025-tracing-Allow-whitespace-to-surround-hist-trigger-fi.patch)14
-rw-r--r--patches/0032-tracing-Add-cpu-field-for-hist-triggers.patch (renamed from patches/0027-tracing-Add-cpu-field-for-hist-triggers.patch)26
-rw-r--r--patches/0033-tracing-Add-hist-trigger-support-for-variable-refere.patch (renamed from patches/0028-tracing-Add-hist-trigger-support-for-variable-refere.patch)80
-rw-r--r--patches/0034-tracing-Add-last-error-error-facility-for-hist-trigg.patch (renamed from patches/0029-tracing-Add-last-error-error-facility-for-hist-trigg.patch)182
-rw-r--r--patches/0035-tracing-Reverse-the-order-event_mutex-trace_types_lo.patch95
-rw-r--r--patches/0036-tracing-Remove-lookups-from-tracing_map-hitcount.patch26
-rw-r--r--patches/0037-tracing-Add-inter-event-hist-trigger-Documentation.patch (renamed from patches/0030-tracing-Add-inter-event-hist-trigger-Documentation.patch)46
-rw-r--r--patches/0038-tracing-Make-tracing_set_clock-non-static.patch (renamed from patches/0031-tracing-Make-tracing_set_clock-non-static.patch)6
-rw-r--r--patches/0039-tracing-Add-a-clock-attribute-for-hist-triggers.patch (renamed from patches/0032-tracing-Add-a-clock-attribute-for-hist-triggers.patch)18
-rw-r--r--patches/0040-tracing-Add-trace_event_buffer_reserve-variant-that-.patch132
-rw-r--r--patches/Bluetooth-avoid-recursive-locking-in-hci_send_to_cha.patch70
-rw-r--r--patches/drivers-zram-fix-zcomp_stream_get-smp_processor_id-u.patch1
-rw-r--r--patches/ftrace-Fix-trace-header-alignment.patch4
-rw-r--r--patches/ftrace-migrate-disable-tracing.patch4
-rw-r--r--patches/futex-rtmutex-Cure-RT-double-blocking-issue.patch4
-rw-r--r--patches/hrtimer-consolidate-hrtimer_init-hrtimer_init_sleepe.patch1
-rw-r--r--patches/iommu-amd-Use-raw_cpu_ptr-instead-of-get_cpu_ptr-for.patch43
-rw-r--r--patches/locallock-add-local_lock_on.patch2
-rw-r--r--patches/localversion.patch2
-rw-r--r--patches/locking-rtmutex-don-t-drop-the-wait_lock-twice.patch29
-rw-r--r--patches/net-use-trylock-in-icmp_sk.patch73
-rw-r--r--patches/ping-sysrq.patch4
-rw-r--r--patches/preempt-lazy-support.patch8
-rw-r--r--patches/rt-add-rt-locks.patch2
-rw-r--r--patches/rt-locking--Consolidate-lock-functions.patch2
-rw-r--r--patches/rt-locking-allow-recursive-local_trylock.patch38
-rw-r--r--patches/rtmutex-add-a-first-shot-of-ww_mutex.patch4
-rw-r--r--patches/series79
63 files changed, 3919 insertions, 2933 deletions
diff --git a/patches/0001-tracing-Exclude-generic-fields-from-histograms.patch b/patches/0001-tracing-Exclude-generic-fields-from-histograms.patch
new file mode 100644
index 000000000000..b0e806b3df2e
--- /dev/null
+++ b/patches/0001-tracing-Exclude-generic-fields-from-histograms.patch
@@ -0,0 +1,37 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:13 -0500
+Subject: [PATCH 01/40] tracing: Exclude 'generic fields' from histograms
+
+There are a small number of 'generic fields' (comm/COMM/cpu/CPU) that
+are found by trace_find_event_field() but are only meant for
+filtering. Specifically, they unlike normal fields, they have a size
+of 0 and thus wreak havoc when used as a histogram key.
+
+Exclude these (return -EINVAL) when used as histogram keys.
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace_events_hist.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -450,7 +450,7 @@ static int create_val_field(struct hist_
+ }
+
+ field = trace_find_event_field(file->event_call, field_name);
+- if (!field) {
++ if (!field || !field->size) {
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -548,7 +548,7 @@ static int create_key_field(struct hist_
+ }
+
+ field = trace_find_event_field(file->event_call, field_name);
+- if (!field) {
++ if (!field || !field->size) {
+ ret = -EINVAL;
+ goto out;
+ }
diff --git a/patches/0002-tracing-Add-support-to-detect-and-avoid-duplicates.patch b/patches/0002-tracing-Add-support-to-detect-and-avoid-duplicates.patch
new file mode 100644
index 000000000000..17e926674fef
--- /dev/null
+++ b/patches/0002-tracing-Add-support-to-detect-and-avoid-duplicates.patch
@@ -0,0 +1,108 @@
+From: Vedang Patel <vedang.patel@intel.com>
+Date: Tue, 5 Sep 2017 16:57:14 -0500
+Subject: [PATCH 02/40] tracing: Add support to detect and avoid duplicates
+
+A duplicate in the tracing_map hash table is when 2 different entries
+have the same key and, as a result, the key_hash. This is possible due
+to a race condition in the algorithm. This race condition is inherent to
+the algorithm and not a bug. This was fine because, until now, we were
+only interested in the sum of all the values related to a particular
+key (the duplicates are dealt with in tracing_map_sort_entries()). But,
+with the inclusion of variables[1], we are interested in individual
+values. So, it will not be clear what value to choose when
+there are duplicates. So, the duplicates need to be removed.
+
+The duplicates can occur in the code in the following scenarios:
+
+- A thread is in the process of adding a new element. It has
+successfully executed cmpxchg() and inserted the key. But, it is still
+not done acquiring the trace_map_elt struct, populating it and storing
+the pointer to the struct in the value field of tracing_map hash table.
+If another thread comes in at this time and wants to add an element with
+the same key, it will not see the current element and add a new one.
+
+- There are multiple threads trying to execute cmpxchg at the same time,
+one of the threads will succeed and the others will fail. The ones which
+fail will go ahead increment 'idx' and add a new element there creating
+a duplicate.
+
+This patch detects and avoids the first condition by asking the thread
+which detects the duplicate to loop one more time. There is also a
+possibility of infinite loop if the thread which is trying to insert
+goes to sleep indefinitely and the one which is trying to insert a new
+element detects a duplicate. Which is why, the thread loops for
+map_size iterations before returning NULL.
+
+The second scenario is avoided by preventing the threads which failed
+cmpxchg() from incrementing idx. This way, they will loop
+around and check if the thread which succeeded in executing cmpxchg()
+had the same key.
+
+[1] - https://lkml.org/lkml/2017/6/26/751
+
+Signed-off-by: Vedang Patel <vedang.patel@intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/tracing_map.c | 37 +++++++++++++++++++++++++++++++++----
+ 1 file changed, 33 insertions(+), 4 deletions(-)
+
+--- a/kernel/trace/tracing_map.c
++++ b/kernel/trace/tracing_map.c
+@@ -411,6 +411,7 @@ static inline struct tracing_map_elt *
+ __tracing_map_insert(struct tracing_map *map, void *key, bool lookup_only)
+ {
+ u32 idx, key_hash, test_key;
++ int dup_try = 0;
+ struct tracing_map_entry *entry;
+
+ key_hash = jhash(key, map->key_size, 0);
+@@ -423,10 +424,31 @@ static inline struct tracing_map_elt *
+ entry = TRACING_MAP_ENTRY(map->map, idx);
+ test_key = entry->key;
+
+- if (test_key && test_key == key_hash && entry->val &&
+- keys_match(key, entry->val->key, map->key_size)) {
+- atomic64_inc(&map->hits);
+- return entry->val;
++ if (test_key && test_key == key_hash) {
++ if (entry->val &&
++ keys_match(key, entry->val->key, map->key_size)) {
++ atomic64_inc(&map->hits);
++ return entry->val;
++ } else if (unlikely(!entry->val)) {
++ /*
++ * The key is present. But, val (pointer to elt
++ * struct) is still NULL. which means some other
++ * thread is in the process of inserting an
++ * element.
++ *
++ * On top of that, it's key_hash is same as the
++ * one being inserted right now. So, it's
++ * possible that the element has the same
++ * key as well.
++ */
++
++ dup_try++;
++ if (dup_try > map->map_size) {
++ atomic64_inc(&map->drops);
++ break;
++ }
++ continue;
++ }
+ }
+
+ if (!test_key) {
+@@ -448,6 +470,13 @@ static inline struct tracing_map_elt *
+ atomic64_inc(&map->hits);
+
+ return entry->val;
++ } else {
++ /*
++ * cmpxchg() failed. Loop around once
++ * more to check what key was inserted.
++ */
++ dup_try++;
++ continue;
+ }
+ }
+
diff --git a/patches/0003-tracing-Remove-code-which-merges-duplicates.patch b/patches/0003-tracing-Remove-code-which-merges-duplicates.patch
new file mode 100644
index 000000000000..9c0b254ac837
--- /dev/null
+++ b/patches/0003-tracing-Remove-code-which-merges-duplicates.patch
@@ -0,0 +1,187 @@
+From: Vedang Patel <vedang.patel@intel.com>
+Date: Tue, 5 Sep 2017 16:57:15 -0500
+Subject: [PATCH 03/40] tracing: Remove code which merges duplicates
+
+We now have the logic to detect and remove duplicates in the
+tracing_map hash table. The code which merges duplicates in the
+histogram is redundant now. So, modify this code just to detect
+duplicates. The duplication detection code is still kept to ensure
+that any rare race condition which might cause duplicates does not go
+unnoticed.
+
+Signed-off-by: Vedang Patel <vedang.patel@intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace_events_hist.c | 11 -----
+ kernel/trace/tracing_map.c | 83 ++-------------------------------------
+ kernel/trace/tracing_map.h | 7 ---
+ 3 files changed, 6 insertions(+), 95 deletions(-)
+
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -315,16 +315,6 @@ static int hist_trigger_elt_comm_alloc(s
+ return 0;
+ }
+
+-static void hist_trigger_elt_comm_copy(struct tracing_map_elt *to,
+- struct tracing_map_elt *from)
+-{
+- char *comm_from = from->private_data;
+- char *comm_to = to->private_data;
+-
+- if (comm_from)
+- memcpy(comm_to, comm_from, TASK_COMM_LEN + 1);
+-}
+-
+ static void hist_trigger_elt_comm_init(struct tracing_map_elt *elt)
+ {
+ char *comm = elt->private_data;
+@@ -335,7 +325,6 @@ static void hist_trigger_elt_comm_init(s
+
+ static const struct tracing_map_ops hist_trigger_elt_comm_ops = {
+ .elt_alloc = hist_trigger_elt_comm_alloc,
+- .elt_copy = hist_trigger_elt_comm_copy,
+ .elt_free = hist_trigger_elt_comm_free,
+ .elt_init = hist_trigger_elt_comm_init,
+ };
+--- a/kernel/trace/tracing_map.c
++++ b/kernel/trace/tracing_map.c
+@@ -841,67 +841,15 @@ create_sort_entry(void *key, struct trac
+ return sort_entry;
+ }
+
+-static struct tracing_map_elt *copy_elt(struct tracing_map_elt *elt)
+-{
+- struct tracing_map_elt *dup_elt;
+- unsigned int i;
+-
+- dup_elt = tracing_map_elt_alloc(elt->map);
+- if (IS_ERR(dup_elt))
+- return NULL;
+-
+- if (elt->map->ops && elt->map->ops->elt_copy)
+- elt->map->ops->elt_copy(dup_elt, elt);
+-
+- dup_elt->private_data = elt->private_data;
+- memcpy(dup_elt->key, elt->key, elt->map->key_size);
+-
+- for (i = 0; i < elt->map->n_fields; i++) {
+- atomic64_set(&dup_elt->fields[i].sum,
+- atomic64_read(&elt->fields[i].sum));
+- dup_elt->fields[i].cmp_fn = elt->fields[i].cmp_fn;
+- }
+-
+- return dup_elt;
+-}
+-
+-static int merge_dup(struct tracing_map_sort_entry **sort_entries,
+- unsigned int target, unsigned int dup)
+-{
+- struct tracing_map_elt *target_elt, *elt;
+- bool first_dup = (target - dup) == 1;
+- int i;
+-
+- if (first_dup) {
+- elt = sort_entries[target]->elt;
+- target_elt = copy_elt(elt);
+- if (!target_elt)
+- return -ENOMEM;
+- sort_entries[target]->elt = target_elt;
+- sort_entries[target]->elt_copied = true;
+- } else
+- target_elt = sort_entries[target]->elt;
+-
+- elt = sort_entries[dup]->elt;
+-
+- for (i = 0; i < elt->map->n_fields; i++)
+- atomic64_add(atomic64_read(&elt->fields[i].sum),
+- &target_elt->fields[i].sum);
+-
+- sort_entries[dup]->dup = true;
+-
+- return 0;
+-}
+-
+-static int merge_dups(struct tracing_map_sort_entry **sort_entries,
++static void detect_dups(struct tracing_map_sort_entry **sort_entries,
+ int n_entries, unsigned int key_size)
+ {
+ unsigned int dups = 0, total_dups = 0;
+- int err, i, j;
++ int i;
+ void *key;
+
+ if (n_entries < 2)
+- return total_dups;
++ return;
+
+ sort(sort_entries, n_entries, sizeof(struct tracing_map_sort_entry *),
+ (int (*)(const void *, const void *))cmp_entries_dup, NULL);
+@@ -910,30 +858,14 @@ static int merge_dups(struct tracing_map
+ for (i = 1; i < n_entries; i++) {
+ if (!memcmp(sort_entries[i]->key, key, key_size)) {
+ dups++; total_dups++;
+- err = merge_dup(sort_entries, i - dups, i);
+- if (err)
+- return err;
+ continue;
+ }
+ key = sort_entries[i]->key;
+ dups = 0;
+ }
+
+- if (!total_dups)
+- return total_dups;
+-
+- for (i = 0, j = 0; i < n_entries; i++) {
+- if (!sort_entries[i]->dup) {
+- sort_entries[j] = sort_entries[i];
+- if (j++ != i)
+- sort_entries[i] = NULL;
+- } else {
+- destroy_sort_entry(sort_entries[i]);
+- sort_entries[i] = NULL;
+- }
+- }
+-
+- return total_dups;
++ WARN_ONCE(total_dups > 0,
++ "Duplicates detected: %d\n", total_dups);
+ }
+
+ static bool is_key(struct tracing_map *map, unsigned int field_idx)
+@@ -1059,10 +991,7 @@ int tracing_map_sort_entries(struct trac
+ return 1;
+ }
+
+- ret = merge_dups(entries, n_entries, map->key_size);
+- if (ret < 0)
+- goto free;
+- n_entries -= ret;
++ detect_dups(entries, n_entries, map->key_size);
+
+ if (is_key(map, sort_keys[0].field_idx))
+ cmp_entries_fn = cmp_entries_key;
+--- a/kernel/trace/tracing_map.h
++++ b/kernel/trace/tracing_map.h
+@@ -214,11 +214,6 @@ struct tracing_map {
+ * Element allocation occurs before tracing begins, when the
+ * tracing_map_init() call is made by client code.
+ *
+- * @elt_copy: At certain points in the lifetime of an element, it may
+- * need to be copied. The copy should include a copy of the
+- * client-allocated data, which can be copied into the 'to'
+- * element from the 'from' element.
+- *
+ * @elt_free: When a tracing_map_elt is freed, this function is called
+ * and allows client-allocated per-element data to be freed.
+ *
+@@ -232,8 +227,6 @@ struct tracing_map {
+ */
+ struct tracing_map_ops {
+ int (*elt_alloc)(struct tracing_map_elt *elt);
+- void (*elt_copy)(struct tracing_map_elt *to,
+- struct tracing_map_elt *from);
+ void (*elt_free)(struct tracing_map_elt *elt);
+ void (*elt_clear)(struct tracing_map_elt *elt);
+ void (*elt_init)(struct tracing_map_elt *elt);
diff --git a/patches/0001-tracing-Add-hist_field_name-accessor.patch b/patches/0004-tracing-Add-hist_field_name-accessor.patch
index f934609d44c0..95d05b5d1e03 100644
--- a/patches/0001-tracing-Add-hist_field_name-accessor.patch
+++ b/patches/0004-tracing-Add-hist_field_name-accessor.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:02 -0500
-Subject: [PATCH 01/32] tracing: Add hist_field_name() accessor
+Date: Tue, 5 Sep 2017 16:57:16 -0500
+Subject: [PATCH 04/40] tracing: Add hist_field_name() accessor
In preparation for hist_fields that won't be strictly based on
trace_event_fields, add a new hist_field_name() accessor to allow that
@@ -9,8 +9,8 @@ flexibility and update associated users.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/trace_events_hist.c | 68 ++++++++++++++++++++++++++-------------
- 1 file changed, 46 insertions(+), 22 deletions(-)
+ kernel/trace/trace_events_hist.c | 67 ++++++++++++++++++++++++++-------------
+ 1 file changed, 45 insertions(+), 22 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -38,7 +38,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static hist_field_fn_t select_value_fn(int field_size, int field_is_signed)
{
hist_field_fn_t fn = NULL;
-@@ -653,7 +670,6 @@ static int is_descending(const char *str
+@@ -642,7 +659,6 @@ static int is_descending(const char *str
static int create_sort_keys(struct hist_trigger_data *hist_data)
{
char *fields_str = hist_data->attrs->sort_key_str;
@@ -46,7 +46,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
struct tracing_map_sort_key *sort_key;
int descending, ret = 0;
unsigned int i, j;
-@@ -670,7 +686,9 @@ static int create_sort_keys(struct hist_
+@@ -659,7 +675,9 @@ static int create_sort_keys(struct hist_
}
for (i = 0; i < TRACING_MAP_SORT_KEYS_MAX; i++) {
@@ -56,7 +56,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
sort_key = &hist_data->sort_keys[i];
-@@ -703,8 +721,11 @@ static int create_sort_keys(struct hist_
+@@ -692,8 +710,10 @@ static int create_sort_keys(struct hist_
}
for (j = 1; j < hist_data->n_fields; j++) {
@@ -64,13 +64,12 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
- if (field && (strcmp(field_name, field->name) == 0)) {
+ hist_field = hist_data->fields[j];
+ 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;
descending = is_descending(field_str);
if (descending < 0) {
-@@ -952,6 +973,7 @@ hist_trigger_entry_print(struct seq_file
+@@ -941,6 +961,7 @@ hist_trigger_entry_print(struct seq_file
struct hist_field *key_field;
char str[KSYM_SYMBOL_LEN];
bool multiline = false;
@@ -78,7 +77,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
unsigned int i;
u64 uval;
-@@ -963,26 +985,27 @@ hist_trigger_entry_print(struct seq_file
+@@ -952,26 +973,27 @@ hist_trigger_entry_print(struct seq_file
if (i > hist_data->n_vals)
seq_puts(m, ", ");
@@ -114,7 +113,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
} else if (key_field->flags & HIST_FIELD_FL_SYSCALL) {
const char *syscall_name;
-@@ -991,8 +1014,8 @@ hist_trigger_entry_print(struct seq_file
+@@ -980,8 +1002,8 @@ hist_trigger_entry_print(struct seq_file
if (!syscall_name)
syscall_name = "unknown_syscall";
@@ -125,7 +124,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
} else if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
seq_puts(m, "stacktrace:\n");
hist_trigger_stacktrace_print(m,
-@@ -1000,15 +1023,14 @@ hist_trigger_entry_print(struct seq_file
+@@ -989,15 +1011,14 @@ hist_trigger_entry_print(struct seq_file
HIST_STACKTRACE_DEPTH);
multiline = true;
} else if (key_field->flags & HIST_FIELD_FL_LOG2) {
@@ -144,7 +143,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
}
-@@ -1021,13 +1043,13 @@ hist_trigger_entry_print(struct seq_file
+@@ -1010,13 +1031,13 @@ hist_trigger_entry_print(struct seq_file
tracing_map_read_sum(elt, HITCOUNT_IDX));
for (i = 1; i < hist_data->n_vals; i++) {
@@ -162,7 +161,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
tracing_map_read_sum(elt, i));
}
}
-@@ -1142,7 +1164,9 @@ static const char *get_hist_field_flags(
+@@ -1131,7 +1152,9 @@ static const char *get_hist_field_flags(
static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
{
diff --git a/patches/0002-tracing-Reimplement-log2.patch b/patches/0005-tracing-Reimplement-log2.patch
index 0d674beb6c9f..a0030142b794 100644
--- a/patches/0002-tracing-Reimplement-log2.patch
+++ b/patches/0005-tracing-Reimplement-log2.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:03 -0500
-Subject: [PATCH 02/32] tracing: Reimplement log2
+Date: Tue, 5 Sep 2017 16:57:17 -0500
+Subject: [PATCH 05/40] tracing: Reimplement log2
log2 as currently implemented applies only to u64 trace_event_field
derived fields, and assumes that anything it's applied to is a u64
@@ -61,7 +61,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (field_name == NULL)
field_name = "";
-@@ -357,8 +365,20 @@ static const struct tracing_map_ops hist
+@@ -346,8 +354,20 @@ static const struct tracing_map_ops hist
.elt_init = hist_trigger_elt_comm_init,
};
@@ -78,12 +78,12 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return;
+
+ for (i = 0; i < HIST_FIELD_OPERANDS_MAX; i++)
-+ destroy_hist_field(hist_field->operands[i], ++level);
++ destroy_hist_field(hist_field->operands[i], level + 1);
+
kfree(hist_field);
}
-@@ -385,7 +405,10 @@ static struct hist_field *create_hist_fi
+@@ -374,7 +394,10 @@ static struct hist_field *create_hist_fi
}
if (flags & HIST_FIELD_FL_LOG2) {
@@ -94,7 +94,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
goto out;
}
-@@ -405,7 +428,7 @@ static struct hist_field *create_hist_fi
+@@ -394,7 +417,7 @@ static struct hist_field *create_hist_fi
hist_field->fn = select_value_fn(field->size,
field->is_signed);
if (!hist_field->fn) {
@@ -103,7 +103,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return NULL;
}
}
-@@ -422,7 +445,7 @@ static void destroy_hist_fields(struct h
+@@ -411,7 +434,7 @@ static void destroy_hist_fields(struct h
for (i = 0; i < TRACING_MAP_FIELDS_MAX; i++) {
if (hist_data->fields[i]) {
diff --git a/patches/0003-ring-buffer-Add-interface-for-setting-absolute-time-.patch b/patches/0006-ring-buffer-Add-interface-for-setting-absolute-time-.patch
index edc0f2f13e65..263313eb3e83 100644
--- a/patches/0003-ring-buffer-Add-interface-for-setting-absolute-time-.patch
+++ b/patches/0006-ring-buffer-Add-interface-for-setting-absolute-time-.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:04 -0500
-Subject: [PATCH 03/32] ring-buffer: Add interface for setting absolute time
+Date: Tue, 5 Sep 2017 16:57:18 -0500
+Subject: [PATCH 06/40] ring-buffer: Add interface for setting absolute time
stamps
Define a new function, tracing_set_time_stamp_abs(), which can be used
@@ -18,9 +18,9 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
include/linux/ring_buffer.h | 2 ++
kernel/trace/ring_buffer.c | 11 +++++++++++
- kernel/trace/trace.c | 25 ++++++++++++++++++++++++-
- kernel/trace/trace.h | 2 ++
- 4 files changed, 39 insertions(+), 1 deletion(-)
+ kernel/trace/trace.c | 40 +++++++++++++++++++++++++++++++++++++++-
+ kernel/trace/trace.h | 3 +++
+ 4 files changed, 55 insertions(+), 1 deletion(-)
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -71,14 +71,30 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
(EVENT_FILE_FL_SOFT_DISABLED | EVENT_FILE_FL_FILTERED)) &&
(entry = this_cpu_read(trace_buffered_event))) {
/* Try to use the per cpu buffer first */
-@@ -5959,6 +5959,29 @@ static int tracing_clock_open(struct ino
+@@ -5958,6 +5958,44 @@ static int tracing_clock_open(struct ino
+
return ret;
}
-
++
+int tracing_set_time_stamp_abs(struct trace_array *tr, bool abs)
+{
++ int ret = 0;
++
+ mutex_lock(&trace_types_lock);
+
++ if (abs && tr->time_stamp_abs_ref++)
++ goto out;
++
++ if (!abs) {
++ if (WARN_ON_ONCE(!tr->time_stamp_abs_ref)) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (--tr->time_stamp_abs_ref)
++ goto out;
++ }
++
+ ring_buffer_set_time_stamp_abs(tr->trace_buffer.buffer, abs);
+
+ /*
@@ -92,18 +108,25 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ ring_buffer_set_time_stamp_abs(tr->max_buffer.buffer, abs);
+ tracing_reset_online_cpus(&tr->max_buffer);
+#endif
-+
++ out:
+ mutex_unlock(&trace_types_lock);
+
-+ return 0;
++ return ret;
+}
-+
+
struct ftrace_buffer_info {
struct trace_iterator iter;
- void *spare;
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
-@@ -278,6 +278,8 @@ extern struct mutex trace_types_lock;
+@@ -265,6 +265,7 @@ struct trace_array {
+ /* function tracing enabled */
+ int function_enabled;
+ #endif
++ int time_stamp_abs_ref;
+ };
+
+ enum {
+@@ -278,6 +279,8 @@ extern struct mutex trace_types_lock;
extern int trace_array_get(struct trace_array *tr);
extern void trace_array_put(struct trace_array *tr);
diff --git a/patches/0007-tracing-Apply-absolute-timestamps-to-instance-max-bu.patch b/patches/0007-tracing-Apply-absolute-timestamps-to-instance-max-bu.patch
new file mode 100644
index 000000000000..cca73e93a23d
--- /dev/null
+++ b/patches/0007-tracing-Apply-absolute-timestamps-to-instance-max-bu.patch
@@ -0,0 +1,41 @@
+From: Baohong Liu <baohong.liu@intel.com>
+Date: Tue, 5 Sep 2017 16:57:19 -0500
+Subject: [PATCH 07/40] tracing: Apply absolute timestamps to instance max
+ buffer
+
+Currently absolute timestamps are applied to both regular and max
+buffers only for global trace. For instance trace, absolute
+timestamps are applied only to regular buffer. But, regular and max
+buffers can be swapped, for example, following a snapshot. So, for
+instance trace, bad timestamps can be seen following a snapshot.
+Let's apply absolute timestamps to instance max buffer as well.
+
+Similarly, buffer clock change is applied to instance max buffer
+as well.
+
+Signed-off-by: Baohong Liu <baohong.liu@intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -5903,7 +5903,7 @@ static int tracing_set_clock(struct trac
+ tracing_reset_online_cpus(&tr->trace_buffer);
+
+ #ifdef CONFIG_TRACER_MAX_TRACE
+- if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
++ if (tr->max_buffer.buffer)
+ ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
+ tracing_reset_online_cpus(&tr->max_buffer);
+ #endif
+@@ -5987,7 +5987,7 @@ int tracing_set_time_stamp_abs(struct tr
+ tracing_reset_online_cpus(&tr->trace_buffer);
+
+ #ifdef CONFIG_TRACER_MAX_TRACE
+- if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
++ if (tr->max_buffer.buffer)
+ ring_buffer_set_time_stamp_abs(tr->max_buffer.buffer, abs);
+ tracing_reset_online_cpus(&tr->max_buffer);
+ #endif
diff --git a/patches/0004-ring-buffer-Redefine-the-unimplemented-RINGBUF_TIME_.patch b/patches/0008-ring-buffer-Redefine-the-unimplemented-RINGBUF_TIME_.patch
index d7ad02d26f16..be733e52ae2c 100644
--- a/patches/0004-ring-buffer-Redefine-the-unimplemented-RINGBUF_TIME_.patch
+++ b/patches/0008-ring-buffer-Redefine-the-unimplemented-RINGBUF_TIME_.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:05 -0500
-Subject: [PATCH 04/32] ring-buffer: Redefine the unimplemented
+Date: Tue, 5 Sep 2017 16:57:20 -0500
+Subject: [PATCH 08/40] ring-buffer: Redefine the unimplemented
RINGBUF_TIME_TIME_STAMP
RINGBUF_TYPE_TIME_STAMP is defined but not used, and from what I can
@@ -23,9 +23,9 @@ previous interface patch.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- include/linux/ring_buffer.h | 12 ++--
- kernel/trace/ring_buffer.c | 107 +++++++++++++++++++++++++++++++-------------
- 2 files changed, 83 insertions(+), 36 deletions(-)
+ include/linux/ring_buffer.h | 12 ++---
+ kernel/trace/ring_buffer.c | 105 +++++++++++++++++++++++++++++++-------------
+ 2 files changed, 83 insertions(+), 34 deletions(-)
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -71,7 +71,14 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
trace_seq_printf(s, "\tdata max type_len == %d\n",
RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
-@@ -147,6 +149,9 @@ enum {
+@@ -141,12 +143,15 @@ int ring_buffer_print_entry_header(struc
+
+ enum {
+ RB_LEN_TIME_EXTEND = 8,
+- RB_LEN_TIME_STAMP = 16,
++ RB_LEN_TIME_STAMP = 8,
+ };
+
#define skip_time_extend(event) \
((struct ring_buffer_event *)((char *)event + RB_LEN_TIME_EXTEND))
@@ -81,19 +88,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static inline int rb_null_event(struct ring_buffer_event *event)
{
return event->type_len == RINGBUF_TYPE_PADDING && !event->time_delta;
-@@ -187,10 +192,8 @@ rb_event_length(struct ring_buffer_event
- return event->array[0] + RB_EVNT_HDR_SIZE;
-
- case RINGBUF_TYPE_TIME_EXTEND:
-- return RB_LEN_TIME_EXTEND;
--
- case RINGBUF_TYPE_TIME_STAMP:
-- return RB_LEN_TIME_STAMP;
-+ return RB_LEN_TIME_EXTEND;
-
- case RINGBUF_TYPE_DATA:
- return rb_event_data_length(event);
-@@ -210,7 +213,7 @@ rb_event_ts_length(struct ring_buffer_ev
+@@ -210,7 +215,7 @@ rb_event_ts_length(struct ring_buffer_ev
{
unsigned len = 0;
@@ -102,7 +97,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
/* time extends include the data event after it */
len = RB_LEN_TIME_EXTEND;
event = skip_time_extend(event);
-@@ -232,7 +235,7 @@ unsigned ring_buffer_event_length(struct
+@@ -232,7 +237,7 @@ unsigned ring_buffer_event_length(struct
{
unsigned length;
@@ -111,7 +106,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
event = skip_time_extend(event);
length = rb_event_length(event);
-@@ -249,7 +252,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_leng
+@@ -249,7 +254,7 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_leng
static __always_inline void *
rb_event_data(struct ring_buffer_event *event)
{
@@ -120,7 +115,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
event = skip_time_extend(event);
BUG_ON(event->type_len > RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
/* If length is in len field, then array[0] has the data */
-@@ -276,6 +279,27 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data
+@@ -276,6 +281,27 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data
#define TS_MASK ((1ULL << TS_SHIFT) - 1)
#define TS_DELTA_TEST (~TS_MASK)
@@ -148,7 +143,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
/* Flag when events were overwritten */
#define RB_MISSED_EVENTS (1 << 31)
/* Missed count stored at end */
-@@ -2219,13 +2243,16 @@ rb_move_tail(struct ring_buffer_per_cpu
+@@ -2219,13 +2245,16 @@ rb_move_tail(struct ring_buffer_per_cpu
}
/* Slow path, do not inline */
@@ -170,7 +165,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
event->time_delta = delta & TS_MASK;
event->array[0] = delta >> TS_SHIFT;
} else {
-@@ -2268,7 +2295,9 @@ rb_update_event(struct ring_buffer_per_c
+@@ -2268,7 +2297,9 @@ rb_update_event(struct ring_buffer_per_c
* add it to the start of the resevered space.
*/
if (unlikely(info->add_timestamp)) {
@@ -181,7 +176,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
length -= RB_LEN_TIME_EXTEND;
delta = 0;
}
-@@ -2456,7 +2485,7 @@ static __always_inline void rb_end_commi
+@@ -2456,7 +2487,7 @@ static __always_inline void rb_end_commi
static inline void rb_event_discard(struct ring_buffer_event *event)
{
@@ -190,7 +185,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
event = skip_time_extend(event);
/* array[0] holds the actual length for the discarded event */
-@@ -2487,6 +2516,10 @@ rb_update_write_stamp(struct ring_buffer
+@@ -2487,6 +2518,10 @@ rb_update_write_stamp(struct ring_buffer
{
u64 delta;
@@ -201,7 +196,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
/*
* The event first in the commit queue updates the
* time stamp.
-@@ -2500,9 +2533,7 @@ rb_update_write_stamp(struct ring_buffer
+@@ -2500,9 +2535,7 @@ rb_update_write_stamp(struct ring_buffer
cpu_buffer->write_stamp =
cpu_buffer->commit_page->page->time_stamp;
else if (event->type_len == RINGBUF_TYPE_TIME_EXTEND) {
@@ -212,7 +207,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
cpu_buffer->write_stamp += delta;
} else
cpu_buffer->write_stamp += event->time_delta;
-@@ -2686,7 +2717,7 @@ static struct ring_buffer_event *
+@@ -2686,7 +2719,7 @@ static struct ring_buffer_event *
* If this is the first commit on the page, then it has the same
* timestamp as the page itself.
*/
@@ -221,7 +216,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
info->delta = 0;
/* See if we shot pass the end of this buffer page */
-@@ -2764,8 +2795,11 @@ rb_reserve_next_event(struct ring_buffer
+@@ -2764,8 +2797,11 @@ rb_reserve_next_event(struct ring_buffer
/* make sure this diff is calculated here */
barrier();
@@ -235,7 +230,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
info.delta = diff;
if (unlikely(test_time_stamp(info.delta)))
rb_handle_timestamp(cpu_buffer, &info);
-@@ -3447,14 +3481,12 @@ rb_update_read_stamp(struct ring_buffer_
+@@ -3447,14 +3483,12 @@ rb_update_read_stamp(struct ring_buffer_
return;
case RINGBUF_TYPE_TIME_EXTEND:
@@ -252,7 +247,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return;
case RINGBUF_TYPE_DATA:
-@@ -3478,14 +3510,12 @@ rb_update_iter_read_stamp(struct ring_bu
+@@ -3478,14 +3512,12 @@ rb_update_iter_read_stamp(struct ring_bu
return;
case RINGBUF_TYPE_TIME_EXTEND:
@@ -269,7 +264,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return;
case RINGBUF_TYPE_DATA:
-@@ -3709,6 +3739,8 @@ rb_buffer_peek(struct ring_buffer_per_cp
+@@ -3709,6 +3741,8 @@ rb_buffer_peek(struct ring_buffer_per_cp
struct buffer_page *reader;
int nr_loops = 0;
@@ -278,7 +273,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
again:
/*
* We repeat when a time extend is encountered.
-@@ -3745,12 +3777,17 @@ rb_buffer_peek(struct ring_buffer_per_cp
+@@ -3745,12 +3779,17 @@ rb_buffer_peek(struct ring_buffer_per_cp
goto again;
case RINGBUF_TYPE_TIME_STAMP:
@@ -298,7 +293,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*ts = cpu_buffer->read_stamp + event->time_delta;
ring_buffer_normalize_time_stamp(cpu_buffer->buffer,
cpu_buffer->cpu, ts);
-@@ -3775,6 +3812,9 @@ rb_iter_peek(struct ring_buffer_iter *it
+@@ -3775,6 +3814,9 @@ rb_iter_peek(struct ring_buffer_iter *it
struct ring_buffer_event *event;
int nr_loops = 0;
@@ -308,7 +303,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
cpu_buffer = iter->cpu_buffer;
buffer = cpu_buffer->buffer;
-@@ -3827,12 +3867,17 @@ rb_iter_peek(struct ring_buffer_iter *it
+@@ -3827,12 +3869,17 @@ rb_iter_peek(struct ring_buffer_iter *it
goto again;
case RINGBUF_TYPE_TIME_STAMP:
diff --git a/patches/0005-tracing-Give-event-triggers-access-to-ring_buffer_ev.patch b/patches/0009-tracing-Give-event-triggers-access-to-ring_buffer_ev.patch
index 5f55d10387c0..840e4441dd87 100644
--- a/patches/0005-tracing-Give-event-triggers-access-to-ring_buffer_ev.patch
+++ b/patches/0009-tracing-Give-event-triggers-access-to-ring_buffer_ev.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:06 -0500
-Subject: [PATCH 05/32] tracing: Give event triggers access to
+Date: Tue, 5 Sep 2017 16:57:21 -0500
+Subject: [PATCH 09/40] tracing: Give event triggers access to
ring_buffer_event
The ring_buffer event can provide a timestamp that may be useful to
@@ -47,7 +47,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (eflags & EVENT_FILE_FL_PID_FILTER)
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
-@@ -1189,7 +1189,7 @@ static inline bool
+@@ -1190,7 +1190,7 @@ static inline bool
unsigned long eflags = file->flags;
if (eflags & EVENT_FILE_FL_TRIGGER_COND)
@@ -56,7 +56,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (test_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags) ||
(unlikely(file->flags & EVENT_FILE_FL_FILTERED) &&
-@@ -1226,7 +1226,7 @@ event_trigger_unlock_commit(struct trace
+@@ -1227,7 +1227,7 @@ event_trigger_unlock_commit(struct trace
trace_buffer_unlock_commit(file->tr, buffer, event, irq_flags, pc);
if (tt)
@@ -65,7 +65,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
/**
-@@ -1259,7 +1259,7 @@ event_trigger_unlock_commit_regs(struct
+@@ -1260,7 +1260,7 @@ event_trigger_unlock_commit_regs(struct
irq_flags, pc, regs);
if (tt)
@@ -74,7 +74,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
#define FILTER_PRED_INVALID ((unsigned short)-1)
-@@ -1482,7 +1482,8 @@ extern int register_trigger_hist_enable_
+@@ -1483,7 +1483,8 @@ extern int register_trigger_hist_enable_
*/
struct event_trigger_ops {
void (*func)(struct event_trigger_data *data,
@@ -86,7 +86,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
void (*free)(struct event_trigger_ops *ops,
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -921,7 +921,8 @@ static inline void add_to_key(char *comp
+@@ -909,7 +909,8 @@ static inline void add_to_key(char *comp
memcpy(compound_key + key_field->offset, key, size);
}
@@ -96,7 +96,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{
struct hist_trigger_data *hist_data = data->private_data;
bool use_compound_key = (hist_data->n_keys > 1);
-@@ -1672,7 +1673,8 @@ static struct event_command trigger_hist
+@@ -1660,7 +1661,8 @@ static struct event_command trigger_hist
}
static void
@@ -106,7 +106,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{
struct enable_trigger_data *enable_data = data->private_data;
struct event_trigger_data *test;
-@@ -1688,7 +1690,8 @@ hist_enable_trigger(struct event_trigger
+@@ -1676,7 +1678,8 @@ hist_enable_trigger(struct event_trigger
}
static void
@@ -116,7 +116,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{
if (!data->count)
return;
-@@ -1696,7 +1699,7 @@ hist_enable_count_trigger(struct event_t
+@@ -1684,7 +1687,7 @@ hist_enable_count_trigger(struct event_t
if (data->count != -1)
(data->count)--;
diff --git a/patches/0010-tracing-Add-NO_DISCARD-event-file-flag.patch b/patches/0010-tracing-Add-NO_DISCARD-event-file-flag.patch
deleted file mode 100644
index c738f5638d1d..000000000000
--- a/patches/0010-tracing-Add-NO_DISCARD-event-file-flag.patch
+++ /dev/null
@@ -1,105 +0,0 @@
-From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:11 -0500
-Subject: [PATCH 10/32] tracing: Add NO_DISCARD event file flag
-
-Whenever an event_command has a post-trigger that needs access to the
-event record, the event record can't be discarded, or the post-trigger
-will eventually see bogus data.
-
-In order to allow the discard check to treat this case separately, add
-an EVENT_FILE_FL_NO_DISCARD flag to the event file flags, along with
-code in the discard check that checks the flag and avoids the discard
-when the flag is set.
-
-Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
----
- include/linux/trace_events.h | 3 +++
- kernel/trace/trace.h | 13 ++++++++++---
- kernel/trace/trace_events_trigger.c | 16 +++++++++++++---
- 3 files changed, 26 insertions(+), 6 deletions(-)
-
---- a/include/linux/trace_events.h
-+++ b/include/linux/trace_events.h
-@@ -306,6 +306,7 @@ enum {
- EVENT_FILE_FL_TRIGGER_MODE_BIT,
- EVENT_FILE_FL_TRIGGER_COND_BIT,
- EVENT_FILE_FL_PID_FILTER_BIT,
-+ EVENT_FILE_FL_NO_DISCARD_BIT,
- };
-
- /*
-@@ -320,6 +321,7 @@ enum {
- * TRIGGER_MODE - When set, invoke the triggers associated with the event
- * TRIGGER_COND - When set, one or more triggers has an associated filter
- * PID_FILTER - When set, the event is filtered based on pid
-+ * NO_DISCARD - When set, do not discard events, something needs them later
- */
- enum {
- EVENT_FILE_FL_ENABLED = (1 << EVENT_FILE_FL_ENABLED_BIT),
-@@ -331,6 +333,7 @@ enum {
- EVENT_FILE_FL_TRIGGER_MODE = (1 << EVENT_FILE_FL_TRIGGER_MODE_BIT),
- EVENT_FILE_FL_TRIGGER_COND = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT),
- EVENT_FILE_FL_PID_FILTER = (1 << EVENT_FILE_FL_PID_FILTER_BIT),
-+ EVENT_FILE_FL_NO_DISCARD = (1 << EVENT_FILE_FL_NO_DISCARD_BIT),
- };
-
- struct trace_event_file {
---- a/kernel/trace/trace.h
-+++ b/kernel/trace/trace.h
-@@ -1191,9 +1191,16 @@ static inline bool
- if (eflags & EVENT_FILE_FL_TRIGGER_COND)
- *tt = event_triggers_call(file, entry, event);
-
-- if (test_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags) ||
-- (unlikely(file->flags & EVENT_FILE_FL_FILTERED) &&
-- !filter_match_preds(file->filter, entry))) {
-+ if (unlikely(file->flags & EVENT_FILE_FL_FILTERED) &&
-+ !filter_match_preds(file->filter, entry)) {
-+ __trace_event_discard_commit(buffer, event);
-+ return true;
-+ }
-+
-+ if (test_bit(EVENT_FILE_FL_NO_DISCARD_BIT, &file->flags))
-+ return false;
-+
-+ if (test_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &file->flags)) {
- __trace_event_discard_commit(buffer, event);
- return true;
- }
---- a/kernel/trace/trace_events_trigger.c
-+++ b/kernel/trace/trace_events_trigger.c
-@@ -505,20 +505,30 @@ clear_event_triggers(struct trace_array
- void update_cond_flag(struct trace_event_file *file)
- {
- struct event_trigger_data *data;
-- bool set_cond = false;
-+ bool set_cond = false, set_no_discard = false;
-
- list_for_each_entry_rcu(data, &file->triggers, list) {
- if (data->filter || event_command_post_trigger(data->cmd_ops) ||
-- event_command_needs_rec(data->cmd_ops)) {
-+ event_command_needs_rec(data->cmd_ops))
- set_cond = true;
-+
-+ if (event_command_post_trigger(data->cmd_ops) &&
-+ event_command_needs_rec(data->cmd_ops))
-+ set_no_discard = true;
-+
-+ if (set_cond && set_no_discard)
- break;
-- }
- }
-
- if (set_cond)
- set_bit(EVENT_FILE_FL_TRIGGER_COND_BIT, &file->flags);
- else
- clear_bit(EVENT_FILE_FL_TRIGGER_COND_BIT, &file->flags);
-+
-+ if (set_no_discard)
-+ set_bit(EVENT_FILE_FL_NO_DISCARD_BIT, &file->flags);
-+ else
-+ clear_bit(EVENT_FILE_FL_NO_DISCARD_BIT, &file->flags);
- }
-
- /**
diff --git a/patches/0006-tracing-Add-ring-buffer-event-param-to-hist-field-fu.patch b/patches/0010-tracing-Add-ring-buffer-event-param-to-hist-field-fu.patch
index 9d2ac71a1928..84a46a8b7074 100644
--- a/patches/0006-tracing-Add-ring-buffer-event-param-to-hist-field-fu.patch
+++ b/patches/0010-tracing-Add-ring-buffer-event-param-to-hist-field-fu.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:07 -0500
-Subject: [PATCH 06/32] tracing: Add ring buffer event param to hist field
+Date: Tue, 5 Sep 2017 16:57:22 -0500
+Subject: [PATCH 10/40] tracing: Add ring buffer event param to hist field
functions
Some events such as timestamps require access to a ring_buffer_event
@@ -90,7 +90,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{ \
type *addr = (type *)(event + hist_field->field->offset); \
\
-@@ -883,8 +892,8 @@ create_hist_data(unsigned int map_bits,
+@@ -871,8 +880,8 @@ create_hist_data(unsigned int map_bits,
}
static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
@@ -101,7 +101,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{
struct hist_field *hist_field;
unsigned int i;
-@@ -892,7 +901,7 @@ static void hist_trigger_elt_update(stru
+@@ -880,7 +889,7 @@ static void hist_trigger_elt_update(stru
for_each_hist_val_field(i, hist_data) {
hist_field = hist_data->fields[i];
@@ -110,7 +110,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
tracing_map_update_sum(elt, i, hist_val);
}
}
-@@ -922,7 +931,7 @@ static inline void add_to_key(char *comp
+@@ -910,7 +919,7 @@ static inline void add_to_key(char *comp
}
static void event_hist_trigger(struct event_trigger_data *data, void *rec,
@@ -119,7 +119,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{
struct hist_trigger_data *hist_data = data->private_data;
bool use_compound_key = (hist_data->n_keys > 1);
-@@ -951,7 +960,7 @@ static void event_hist_trigger(struct ev
+@@ -939,7 +948,7 @@ static void event_hist_trigger(struct ev
key = entries;
} else {
@@ -128,7 +128,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (key_field->flags & HIST_FIELD_FL_STRING) {
key = (void *)(unsigned long)field_contents;
use_compound_key = true;
-@@ -968,7 +977,7 @@ static void event_hist_trigger(struct ev
+@@ -956,7 +965,7 @@ static void event_hist_trigger(struct ev
elt = tracing_map_insert(hist_data->map, key);
if (elt)
diff --git a/patches/0011-tracing-Add-post-trigger-flag-to-hist-trigger-comman.patch b/patches/0011-tracing-Add-post-trigger-flag-to-hist-trigger-comman.patch
deleted file mode 100644
index bb63da5961c2..000000000000
--- a/patches/0011-tracing-Add-post-trigger-flag-to-hist-trigger-comman.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:12 -0500
-Subject: [PATCH 11/32] tracing: Add post-trigger flag to hist trigger command
-
-Add EVENT_CMD_FL_POST_TRIGGER to the hist trigger cmd - it doesn't
-affect the hist trigger results, and allows further events such as
-synthetic events to be generated from a hist trigger.
-
-Without this change, generating an event from a hist trigger will
-cause the generated event to fail a ring buffer trace_recursive_lock()
-check and return without actually logging the event.
-
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
----
- kernel/trace/trace_events_hist.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/kernel/trace/trace_events_hist.c
-+++ b/kernel/trace/trace_events_hist.c
-@@ -1676,7 +1676,7 @@ static int event_hist_trigger_func(struc
- static struct event_command trigger_hist_cmd = {
- .name = "hist",
- .trigger_type = ETT_EVENT_HIST,
-- .flags = EVENT_CMD_FL_NEEDS_REC,
-+ .flags = EVENT_CMD_FL_NEEDS_REC | EVENT_CMD_FL_POST_TRIGGER,
- .func = event_hist_trigger_func,
- .reg = hist_register_trigger,
- .unreg = hist_unregister_trigger,
diff --git a/patches/0007-tracing-Increase-tracing-map-KEYS_MAX-size.patch b/patches/0011-tracing-Increase-tracing-map-KEYS_MAX-size.patch
index f889dff5f484..670eef00a2e4 100644
--- a/patches/0007-tracing-Increase-tracing-map-KEYS_MAX-size.patch
+++ b/patches/0011-tracing-Increase-tracing-map-KEYS_MAX-size.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:08 -0500
-Subject: [PATCH 07/32] tracing: Increase tracing map KEYS_MAX size
+Date: Tue, 5 Sep 2017 16:57:23 -0500
+Subject: [PATCH 11/40] tracing: Increase tracing map KEYS_MAX size
The current default for the number of subkeys in a compound key is 2,
which is too restrictive. Increase it to a more realistic value of 3.
diff --git a/patches/0008-tracing-Break-out-hist-trigger-assignment-parsing.patch b/patches/0012-tracing-Break-out-hist-trigger-assignment-parsing.patch
index 07d771d47db6..d49318f8575c 100644
--- a/patches/0008-tracing-Break-out-hist-trigger-assignment-parsing.patch
+++ b/patches/0012-tracing-Break-out-hist-trigger-assignment-parsing.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:09 -0500
-Subject: [PATCH 08/32] tracing: Break out hist trigger assignment parsing
+Date: Tue, 5 Sep 2017 16:57:24 -0500
+Subject: [PATCH 12/40] tracing: Break out hist trigger assignment parsing
This will make it easier to add variables, and makes the parsing code
cleaner regardless.
diff --git a/patches/0009-tracing-Make-traceprobe-parsing-code-reusable.patch b/patches/0013-tracing-Make-traceprobe-parsing-code-reusable.patch
index 3f91dc611b9d..05a7bbd6da53 100644
--- a/patches/0009-tracing-Make-traceprobe-parsing-code-reusable.patch
+++ b/patches/0013-tracing-Make-traceprobe-parsing-code-reusable.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:10 -0500
-Subject: [PATCH 09/32] tracing: Make traceprobe parsing code reusable
+Date: Tue, 5 Sep 2017 16:57:25 -0500
+Subject: [PATCH 13/40] tracing: Make traceprobe parsing code reusable
traceprobe_probes_write() and traceprobe_command() actually contain
nothing that ties them to kprobes - the code is generically useful for
@@ -24,7 +24,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
-@@ -7907,6 +7907,92 @@ void ftrace_dump(enum ftrace_dump_mode o
+@@ -7922,6 +7922,92 @@ void ftrace_dump(enum ftrace_dump_mode o
}
EXPORT_SYMBOL_GPL(ftrace_dump);
@@ -119,7 +119,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
int ring_buf_size;
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
-@@ -1650,6 +1650,13 @@ void trace_printk_start_comm(void);
+@@ -1651,6 +1651,13 @@ void trace_printk_start_comm(void);
int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled);
diff --git a/patches/0012-tracing-Add-hist-trigger-timestamp-support.patch b/patches/0014-tracing-Add-hist-trigger-timestamp-support.patch
index 3092c4117e9d..c70686bbd64c 100644
--- a/patches/0012-tracing-Add-hist-trigger-timestamp-support.patch
+++ b/patches/0014-tracing-Add-hist-trigger-timestamp-support.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:13 -0500
-Subject: [PATCH 12/32] tracing: Add hist trigger timestamp support
+Date: Tue, 5 Sep 2017 16:57:26 -0500
+Subject: [PATCH 14/40] tracing: Add hist trigger timestamp support
Add support for a timestamp event field. This is actually a 'pseudo-'
event field in that it behaves like it's part of the event record, but
@@ -23,8 +23,8 @@ a histogram makes use of the "$common_timestamp" field.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/trace_events_hist.c | 90 ++++++++++++++++++++++++++++-----------
- 1 file changed, 66 insertions(+), 24 deletions(-)
+ kernel/trace/trace_events_hist.c | 88 ++++++++++++++++++++++++++++-----------
+ 1 file changed, 65 insertions(+), 23 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -66,7 +66,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (field_name == NULL)
field_name = "";
-@@ -435,6 +445,12 @@ static struct hist_field *create_hist_fi
+@@ -424,6 +434,12 @@ static struct hist_field *create_hist_fi
goto out;
}
@@ -79,12 +79,12 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (WARN_ON_ONCE(!field))
goto out;
-@@ -512,10 +528,15 @@ static int create_val_field(struct hist_
+@@ -501,10 +517,15 @@ static int create_val_field(struct hist_
}
}
- field = trace_find_event_field(file->event_call, field_name);
-- if (!field) {
+- if (!field || !field->size) {
- ret = -EINVAL;
- goto out;
+ if (strcmp(field_name, "$common_timestamp") == 0) {
@@ -92,19 +92,19 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ hist_data->enable_timestamps = true;
+ } else {
+ field = trace_find_event_field(file->event_call, field_name);
-+ if (!field) {
++ if (!field || !field->size) {
+ ret = -EINVAL;
+ goto out;
+ }
}
hist_data->fields[val_idx] = create_hist_field(field, flags);
-@@ -610,16 +631,22 @@ static int create_key_field(struct hist_
+@@ -599,16 +620,22 @@ static int create_key_field(struct hist_
}
}
- field = trace_find_event_field(file->event_call, field_name);
-- if (!field) {
+- if (!field || !field->size) {
- ret = -EINVAL;
- goto out;
- }
@@ -114,7 +114,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ key_size = sizeof(u64);
+ } else {
+ field = trace_find_event_field(file->event_call, field_name);
-+ if (!field) {
++ if (!field || !field->size) {
+ ret = -EINVAL;
+ goto out;
+ }
@@ -131,16 +131,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
hist_data->fields[key_idx] = create_hist_field(field, flags);
-@@ -756,7 +783,7 @@ static int create_sort_keys(struct hist_
- break;
- }
-
-- if (strcmp(field_name, "hitcount") == 0) {
-+ if ((strcmp(field_name, "hitcount") == 0)) {
- descending = is_descending(field_str);
- if (descending < 0) {
- ret = descending;
-@@ -816,6 +843,9 @@ static int create_tracing_map_fields(str
+@@ -804,6 +831,9 @@ static int create_tracing_map_fields(str
if (hist_field->flags & HIST_FIELD_FL_STACKTRACE)
cmp_fn = tracing_map_cmp_none;
@@ -150,7 +141,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
else if (is_string_field(field))
cmp_fn = tracing_map_cmp_string;
else
-@@ -1213,7 +1243,11 @@ static void hist_field_print(struct seq_
+@@ -1201,7 +1231,11 @@ static void hist_field_print(struct seq_
{
const char *field_name = hist_field_name(hist_field, 0);
@@ -163,7 +154,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (hist_field->flags) {
const char *flags_str = get_hist_field_flags(hist_field);
-@@ -1264,27 +1298,25 @@ static int event_hist_trigger_print(stru
+@@ -1252,27 +1286,25 @@ static int event_hist_trigger_print(stru
for (i = 0; i < hist_data->n_sort_keys; i++) {
struct tracing_map_sort_key *sort_key;
@@ -198,7 +189,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
if (data->filter_str)
-@@ -1452,6 +1484,10 @@ static bool hist_trigger_match(struct ev
+@@ -1440,6 +1472,10 @@ static bool hist_trigger_match(struct ev
return false;
if (key_field->offset != key_field_test->offset)
return false;
@@ -209,7 +200,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
for (i = 0; i < hist_data->n_sort_keys; i++) {
-@@ -1534,6 +1570,9 @@ static int hist_register_trigger(char *g
+@@ -1522,6 +1558,9 @@ static int hist_register_trigger(char *g
update_cond_flag(file);
@@ -219,7 +210,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (trace_event_trigger_enable_disable(file, 1) < 0) {
list_del_rcu(&data->list);
update_cond_flag(file);
-@@ -1568,6 +1607,9 @@ static void hist_unregister_trigger(char
+@@ -1556,6 +1595,9 @@ static void hist_unregister_trigger(char
if (unregistered && test->ops->free)
test->ops->free(test->ops, test);
diff --git a/patches/0013-tracing-Add-per-element-variable-support-to-tracing_.patch b/patches/0015-tracing-Add-per-element-variable-support-to-tracing_.patch
index 4d05c895072d..6ecb342492fe 100644
--- a/patches/0013-tracing-Add-per-element-variable-support-to-tracing_.patch
+++ b/patches/0015-tracing-Add-per-element-variable-support-to-tracing_.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:14 -0500
-Subject: [PATCH 13/32] tracing: Add per-element variable support to
+Date: Tue, 5 Sep 2017 16:57:27 -0500
+Subject: [PATCH 15/40] tracing: Add per-element variable support to
tracing_map
In order to allow information to be passed between trace events, add
@@ -20,9 +20,9 @@ important for event-matching uses.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/tracing_map.c | 113 +++++++++++++++++++++++++++++++++++++++++++++
+ kernel/trace/tracing_map.c | 108 +++++++++++++++++++++++++++++++++++++++++++++
kernel/trace/tracing_map.h | 11 ++++
- 2 files changed, 124 insertions(+)
+ 2 files changed, 119 insertions(+)
--- a/kernel/trace/tracing_map.c
+++ b/kernel/trace/tracing_map.c
@@ -150,10 +150,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
kfree(elt->key);
kfree(elt);
}
-@@ -330,6 +426,18 @@ static struct tracing_map_elt *tracing_m
+@@ -329,6 +425,18 @@ static struct tracing_map_elt *tracing_m
+ err = -ENOMEM;
goto free;
}
-
++
+ elt->vars = kcalloc(map->n_vars, sizeof(*elt->vars), GFP_KERNEL);
+ if (!elt->vars) {
+ err = -ENOMEM;
@@ -165,21 +166,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ err = -ENOMEM;
+ goto free;
+ }
-+
- tracing_map_elt_init_fields(elt);
-
- if (map->ops && map->ops->elt_alloc) {
-@@ -833,6 +941,11 @@ static struct tracing_map_elt *copy_elt(
- dup_elt->fields[i].cmp_fn = elt->fields[i].cmp_fn;
- }
-+ for (i = 0; i < elt->map->n_vars; i++) {
-+ atomic64_set(&dup_elt->vars[i], atomic64_read(&elt->vars[i]));
-+ dup_elt->var_set[i] = elt->var_set[i];
-+ }
-+
- return dup_elt;
- }
+ tracing_map_elt_init_fields(elt);
--- a/kernel/trace/tracing_map.h
+++ b/kernel/trace/tracing_map.h
@@ -208,7 +196,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
atomic64_t hits;
atomic64_t drops;
};
-@@ -247,6 +251,7 @@ tracing_map_create(unsigned int map_bits
+@@ -240,6 +244,7 @@ tracing_map_create(unsigned int map_bits
extern int tracing_map_init(struct tracing_map *map);
extern int tracing_map_add_sum_field(struct tracing_map *map);
@@ -216,7 +204,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
extern int tracing_map_add_key_field(struct tracing_map *map,
unsigned int offset,
tracing_map_cmp_fn_t cmp_fn);
-@@ -266,7 +271,13 @@ extern int tracing_map_cmp_none(void *va
+@@ -259,7 +264,13 @@ extern int tracing_map_cmp_none(void *va
extern void tracing_map_update_sum(struct tracing_map_elt *elt,
unsigned int i, u64 n);
diff --git a/patches/0014-tracing-Add-hist_data-member-to-hist_field.patch b/patches/0016-tracing-Add-hist_data-member-to-hist_field.patch
index ae3d689550b3..fc725401801b 100644
--- a/patches/0014-tracing-Add-hist_data-member-to-hist_field.patch
+++ b/patches/0016-tracing-Add-hist_data-member-to-hist_field.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:15 -0500
-Subject: [PATCH 14/32] tracing: Add hist_data member to hist_field
+Date: Tue, 5 Sep 2017 16:57:28 -0500
+Subject: [PATCH 16/40] tracing: Add hist_data member to hist_field
Allow hist_data access via hist_field. Some users of hist_fields
require or will require more access to the associated hist_data.
@@ -21,7 +21,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
};
static u64 hist_field_none(struct hist_field *field, void *event,
-@@ -415,7 +416,8 @@ static void destroy_hist_field(struct hi
+@@ -404,7 +405,8 @@ static void destroy_hist_field(struct hi
kfree(hist_field);
}
@@ -31,7 +31,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
unsigned long flags)
{
struct hist_field *hist_field;
-@@ -427,6 +429,8 @@ static struct hist_field *create_hist_fi
+@@ -416,6 +418,8 @@ static struct hist_field *create_hist_fi
if (!hist_field)
return NULL;
@@ -40,7 +40,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (flags & HIST_FIELD_FL_HITCOUNT) {
hist_field->fn = hist_field_counter;
goto out;
-@@ -440,7 +444,7 @@ static struct hist_field *create_hist_fi
+@@ -429,7 +433,7 @@ static struct hist_field *create_hist_fi
if (flags & HIST_FIELD_FL_LOG2) {
unsigned long fl = flags & ~HIST_FIELD_FL_LOG2;
hist_field->fn = hist_field_log2;
@@ -49,7 +49,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
hist_field->size = hist_field->operands[0]->size;
goto out;
}
-@@ -493,7 +497,7 @@ static void destroy_hist_fields(struct h
+@@ -482,7 +486,7 @@ static void destroy_hist_fields(struct h
static int create_hitcount_val(struct hist_trigger_data *hist_data)
{
hist_data->fields[HITCOUNT_IDX] =
@@ -58,7 +58,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (!hist_data->fields[HITCOUNT_IDX])
return -ENOMEM;
-@@ -539,7 +543,7 @@ static int create_val_field(struct hist_
+@@ -528,7 +532,7 @@ static int create_val_field(struct hist_
}
}
@@ -67,7 +67,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (!hist_data->fields[val_idx]) {
ret = -ENOMEM;
goto out;
-@@ -649,7 +653,7 @@ static int create_key_field(struct hist_
+@@ -638,7 +642,7 @@ static int create_key_field(struct hist_
}
}
diff --git a/patches/0015-tracing-Add-usecs-modifier-for-hist-trigger-timestam.patch b/patches/0017-tracing-Add-usecs-modifier-for-hist-trigger-timestam.patch
index b90640f23182..e5232007c2ca 100644
--- a/patches/0015-tracing-Add-usecs-modifier-for-hist-trigger-timestam.patch
+++ b/patches/0017-tracing-Add-usecs-modifier-for-hist-trigger-timestam.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:16 -0500
-Subject: [PATCH 15/32] tracing: Add usecs modifier for hist trigger timestamps
+Date: Tue, 5 Sep 2017 16:57:29 -0500
+Subject: [PATCH 17/40] tracing: Add usecs modifier for hist trigger timestamps
Appending .usecs onto a common_timestamp field will cause the
timestamp value to be in microseconds instead of the default
@@ -40,7 +40,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
*/
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
-@@ -280,6 +280,8 @@ extern void trace_array_put(struct trace
+@@ -281,6 +281,8 @@ extern void trace_array_put(struct trace
extern int tracing_set_time_stamp_abs(struct trace_array *tr, bool abs);
@@ -101,7 +101,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static const char *hist_field_name(struct hist_field *field,
unsigned int level)
{
-@@ -629,6 +639,8 @@ static int create_key_field(struct hist_
+@@ -618,6 +628,8 @@ static int create_key_field(struct hist_
flags |= HIST_FIELD_FL_SYSCALL;
else if (strcmp(field_str, "log2") == 0)
flags |= HIST_FIELD_FL_LOG2;
@@ -110,7 +110,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
else {
ret = -EINVAL;
goto out;
-@@ -638,6 +650,8 @@ static int create_key_field(struct hist_
+@@ -627,6 +639,8 @@ static int create_key_field(struct hist_
if (strcmp(field_name, "$common_timestamp") == 0) {
flags |= HIST_FIELD_FL_TIMESTAMP;
hist_data->enable_timestamps = true;
@@ -119,7 +119,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
key_size = sizeof(u64);
} else {
field = trace_find_event_field(file->event_call, field_name);
-@@ -1239,6 +1253,8 @@ static const char *get_hist_field_flags(
+@@ -1227,6 +1241,8 @@ static const char *get_hist_field_flags(
flags_str = "syscall";
else if (hist_field->flags & HIST_FIELD_FL_LOG2)
flags_str = "log2";
diff --git a/patches/0016-tracing-Add-variable-support-to-hist-triggers.patch b/patches/0018-tracing-Add-variable-support-to-hist-triggers.patch
index 9d046d4a1dfe..bbc4e015e8bb 100644
--- a/patches/0016-tracing-Add-variable-support-to-hist-triggers.patch
+++ b/patches/0018-tracing-Add-variable-support-to-hist-triggers.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:17 -0500
-Subject: [PATCH 16/32] tracing: Add variable support to hist triggers
+Date: Tue, 5 Sep 2017 16:57:30 -0500
+Subject: [PATCH 18/40] tracing: Add variable support to hist triggers
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.
@@ -11,8 +11,8 @@ 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 ...'
+ # echo 'hist:keys=next_pid:vals=$ts0:ts0=common_timestamp ...
+ # echo 'hist:timer_pid=common_pid:key=$timer_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
@@ -22,21 +22,22 @@ as a value:
Multiple variables can be assigned at the same time:
- # echo 'hist:keys=pid:vals=ts0=common_timestamp,b=field1,field2 ...
+ # echo 'hist:keys=pid:vals=$ts0,$b,field2:ts0=common_timestamp,b=field1 ...
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 ...
+ # echo 'hist:keys=pid:vals=$ts0: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>
+Signed-off-by: Baohong Liu <baohong.liu@intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/trace_events_hist.c | 299 ++++++++++++++++++++++++++++++++++-----
- 1 file changed, 264 insertions(+), 35 deletions(-)
+ kernel/trace/trace_events_hist.c | 372 ++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 333 insertions(+), 39 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -62,22 +63,30 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
};
static u64 hist_field_none(struct hist_field *field, void *event,
-@@ -138,6 +146,8 @@ enum hist_field_flags {
+@@ -138,6 +146,14 @@ 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 var_defs {
++ unsigned int n_vars;
++ char *name[TRACING_MAP_VARS_MAX];
++ char *expr[TRACING_MAP_VARS_MAX];
};
struct hist_trigger_attrs {
-@@ -150,13 +160,18 @@ struct hist_trigger_attrs {
+@@ -150,13 +166,20 @@ 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 var_defs var_defs;
};
struct hist_trigger_data {
@@ -91,7 +100,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
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 {
+@@ -164,6 +187,7 @@ struct hist_trigger_data {
struct hist_trigger_attrs *attrs;
struct tracing_map *map;
bool enable_timestamps;
@@ -99,7 +108,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
};
static u64 hist_field_timestamp(struct hist_field *hist_field, void *event,
-@@ -262,9 +278,14 @@ static int parse_map_size(char *str)
+@@ -262,9 +286,14 @@ static int parse_map_size(char *str)
static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs)
{
@@ -114,7 +123,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
kfree(attrs->name);
kfree(attrs->sort_key_str);
kfree(attrs->keys_str);
-@@ -295,8 +316,22 @@ static int parse_assignment(char *str, s
+@@ -295,8 +324,22 @@ static int parse_assignment(char *str, s
goto out;
}
attrs->map_bits = map_bits;
@@ -139,9 +148,9 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
out:
return ret;
}
-@@ -423,12 +458,15 @@ static void destroy_hist_field(struct hi
+@@ -412,12 +455,15 @@ static void destroy_hist_field(struct hi
for (i = 0; i < HIST_FIELD_OPERANDS_MAX; i++)
- destroy_hist_field(hist_field->operands[i], ++level);
+ destroy_hist_field(hist_field->operands[i], level + 1);
+ kfree(hist_field->var.name);
+
@@ -156,7 +165,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{
struct hist_field *hist_field;
-@@ -454,7 +492,7 @@ static struct hist_field *create_hist_fi
+@@ -443,7 +489,7 @@ static struct hist_field *create_hist_fi
if (flags & HIST_FIELD_FL_LOG2) {
unsigned long fl = flags & ~HIST_FIELD_FL_LOG2;
hist_field->fn = hist_field_log2;
@@ -165,7 +174,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
hist_field->size = hist_field->operands[0]->size;
goto out;
}
-@@ -489,14 +527,23 @@ static struct hist_field *create_hist_fi
+@@ -478,14 +524,23 @@ static struct hist_field *create_hist_fi
hist_field->field = field;
hist_field->flags = flags;
@@ -190,7 +199,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
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 h
+@@ -496,11 +551,12 @@ static void destroy_hist_fields(struct h
static int create_hitcount_val(struct hist_trigger_data *hist_data)
{
hist_data->fields[HITCOUNT_IDX] =
@@ -204,10 +213,14 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX))
return -EINVAL;
-@@ -519,19 +567,81 @@ static int create_hitcount_val(struct hi
+@@ -508,19 +564,53 @@ static int create_hitcount_val(struct hi
return 0;
}
+-static int create_val_field(struct hist_trigger_data *hist_data,
+- unsigned int val_idx,
+- struct trace_event_file *file,
+- char *field_str)
+static struct hist_field *find_var_field(struct hist_trigger_data *hist_data,
+ const char *var_name)
+{
@@ -245,51 +258,24 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ 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)
++static int __create_val_field(struct hist_trigger_data *hist_data,
++ unsigned int val_idx,
++ struct trace_event_file *file,
++ char *var_name, char *field_str,
++ unsigned long flags)
{
struct ftrace_event_field *field = NULL;
-+ char *field_name, *var_name;
- unsigned long flags = 0;
-- char *field_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;
-+ }
-+
+- return -EINVAL;
+-
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_
+@@ -542,25 +632,65 @@ static int create_val_field(struct hist_
}
}
@@ -311,7 +297,45 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = -EINVAL;
out:
return ret;
-@@ -571,7 +685,7 @@ static int create_val_fields(struct hist
+ }
+
++static int create_val_field(struct hist_trigger_data *hist_data,
++ unsigned int val_idx,
++ struct trace_event_file *file,
++ char *field_str)
++{
++ if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX))
++ return -EINVAL;
++
++ return __create_val_field(hist_data, val_idx, file, NULL, field_str, 0);
++}
++
++static int create_var_field(struct hist_trigger_data *hist_data,
++ unsigned int val_idx,
++ struct trace_event_file *file,
++ char *var_name, char *expr_str)
++{
++ unsigned long flags = 0;
++
++ if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
++ return -EINVAL;
++
++ if (find_var(file, var_name) && !hist_data->remove) {
++ return -EINVAL;
++ }
++
++ flags |= HIST_FIELD_FL_VAR;
++ hist_data->n_vars++;
++ if (hist_data->n_vars > TRACING_MAP_VARS_MAX) {
++ return -EINVAL;
++ }
++
++ flags |= HIST_FIELD_FL_VAR_ONLY;
++
++ return __create_val_field(hist_data, val_idx, file, var_name, expr_str, flags);
++}
++
+ static int create_val_fields(struct hist_trigger_data *hist_data,
struct trace_event_file *file)
{
char *fields_str, *field_str;
@@ -320,16 +344,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
int ret;
ret = create_hitcount_val(hist_data);
-@@ -591,12 +705,15 @@ static int create_val_fields(struct hist
+@@ -580,12 +710,15 @@ static int create_val_fields(struct hist
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);
+ ret = create_val_field(hist_data, j++, file, field_str);
if (ret)
goto out;
}
@@ -337,14 +360,13 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (fields_str && (strcmp(fields_str, "hitcount") != 0))
ret = -EINVAL;
out:
-@@ -610,18 +727,32 @@ static int create_key_field(struct hist_
+@@ -599,11 +732,12 @@ static int create_key_field(struct hist_
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))
@@ -352,35 +374,24 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
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;
-+ }
-+
+@@ -611,6 +745,7 @@ static int create_key_field(struct hist_
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);
++ hist_field = create_hist_field(hist_data, NULL, flags, NULL);
} else {
char *field_name = strsep(&field_str, ".");
-@@ -667,7 +798,7 @@ static int create_key_field(struct hist_
+@@ -656,7 +791,7 @@ static int create_key_field(struct hist_
}
}
- 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);
++ hist_data->fields[key_idx] = create_hist_field(hist_data, field, flags, NULL);
if (!hist_data->fields[key_idx]) {
ret = -ENOMEM;
goto out;
-@@ -683,6 +814,7 @@ static int create_key_field(struct hist_
+@@ -672,6 +807,7 @@ static int create_key_field(struct hist_
}
hist_data->n_keys++;
@@ -388,37 +399,99 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (WARN_ON(hist_data->n_keys > TRACING_MAP_KEYS_MAX))
return -EINVAL;
-@@ -726,6 +858,29 @@ static int create_key_fields(struct hist
+@@ -715,21 +851,108 @@ static int create_key_fields(struct hist
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;
++ unsigned int i, j = hist_data->n_vals;
++ int ret = 0;
++
++ unsigned int n_vars = hist_data->attrs->var_defs.n_vars;
++
++ for (i = 0; i < n_vars; i++) {
++ char *var_name = hist_data->attrs->var_defs.name[i];
++ char *expr = hist_data->attrs->var_defs.expr[i];
++
++ ret = create_var_field(hist_data, j++, file, var_name, expr);
++ if (ret)
++ goto out;
++ }
++ out:
++ return ret;
++}
++
++static void free_var_defs(struct hist_trigger_data *hist_data)
++{
++ unsigned int i;
++
++ for (i = 0; i < hist_data->attrs->var_defs.n_vars; i++) {
++ kfree(hist_data->attrs->var_defs.name[i]);
++ kfree(hist_data->attrs->var_defs.expr[i]);
++ }
++
++ hist_data->attrs->var_defs.n_vars = 0;
++}
++
++static int parse_var_defs(struct hist_trigger_data *hist_data)
++{
++ char *s, *str, *var_name, *field_str;
++ unsigned int i, j, n_vars = 0;
+ 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;
++
++ var_name = strsep(&field_str, "=");
++ if (!var_name || !field_str) {
++ ret = -EINVAL;
++ goto free;
++ }
++
++ s = kstrdup(var_name, GFP_KERNEL);
++ if (!s) {
++ ret = -ENOMEM;
++ goto free;
++ }
++ hist_data->attrs->var_defs.name[n_vars] = s;
++
++ s = kstrdup(field_str, GFP_KERNEL);
++ if (!s) {
++ ret = -ENOMEM;
++ goto free;
++ }
++ hist_data->attrs->var_defs.expr[n_vars++] = s;
++
++ hist_data->attrs->var_defs.n_vars = n_vars;
++
++ if (n_vars == TRACING_MAP_VARS_MAX)
++ goto free;
+ }
+ }
-+ out:
++
++ return ret;
++ free:
++ free_var_defs(hist_data);
++
+ 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 his
+ int ret;
+
++ ret = parse_var_defs(hist_data);
++ if (ret)
++ goto out;
++
+ ret = create_val_fields(hist_data, file);
if (ret)
goto out;
@@ -432,9 +505,12 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ if (ret)
+ goto out;
out:
++ free_var_defs(hist_data);
++
return ret;
}
-@@ -763,7 +920,7 @@ static int create_sort_keys(struct hist_
+
+@@ -752,7 +975,7 @@ static int create_sort_keys(struct hist_
char *fields_str = hist_data->attrs->sort_key_str;
struct tracing_map_sort_key *sort_key;
int descending, ret = 0;
@@ -443,13 +519,13 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
hist_data->n_sort_keys = 1; /* we always have at least one, hitcount */
-@@ -811,13 +968,21 @@ static int create_sort_keys(struct hist_
+@@ -800,12 +1023,19 @@ static int create_sort_keys(struct hist_
continue;
}
- for (j = 1; j < hist_data->n_fields; j++) {
+ for (j = 1, k = 1; j < hist_data->n_fields; j++) {
-+ unsigned idx;
++ unsigned int idx;
+
hist_field = hist_data->fields[j];
+ if (hist_field->flags & HIST_FIELD_FL_VAR_ONLY)
@@ -458,16 +534,14 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ 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_
+@@ -820,6 +1050,7 @@ static int create_sort_keys(struct hist_
break;
}
}
@@ -475,7 +549,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
hist_data->n_sort_keys = i;
out:
return ret;
-@@ -872,12 +1038,19 @@ static int create_tracing_map_fields(str
+@@ -860,12 +1091,19 @@ static int create_tracing_map_fields(str
idx = tracing_map_add_key_field(map,
hist_field->offset,
cmp_fn);
@@ -497,7 +571,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
return 0;
-@@ -901,7 +1074,8 @@ static bool need_tracing_map_ops(struct
+@@ -889,7 +1127,8 @@ static bool need_tracing_map_ops(struct
static struct hist_trigger_data *
create_hist_data(unsigned int map_bits,
struct hist_trigger_attrs *attrs,
@@ -507,7 +581,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
{
const struct tracing_map_ops *map_ops = NULL;
struct hist_trigger_data *hist_data;
-@@ -912,6 +1086,7 @@ create_hist_data(unsigned int map_bits,
+@@ -900,6 +1139,7 @@ create_hist_data(unsigned int map_bits,
return ERR_PTR(-ENOMEM);
hist_data->attrs = attrs;
@@ -515,7 +589,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = create_hist_fields(hist_data, file);
if (ret)
-@@ -958,14 +1133,29 @@ static void hist_trigger_elt_update(stru
+@@ -946,14 +1186,29 @@ static void hist_trigger_elt_update(stru
struct ring_buffer_event *rbe)
{
struct hist_field *hist_field;
@@ -547,7 +621,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
static inline void add_to_key(char *compound_key, void *key,
-@@ -1140,6 +1330,9 @@ hist_trigger_entry_print(struct seq_file
+@@ -1128,6 +1383,9 @@ hist_trigger_entry_print(struct seq_file
for (i = 1; i < hist_data->n_vals; i++) {
field_name = hist_field_name(hist_data->fields[i], 0);
@@ -557,7 +631,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
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_
+@@ -1251,6 +1509,9 @@ static void hist_field_print(struct seq_
{
const char *field_name = hist_field_name(hist_field, 0);
@@ -567,7 +641,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
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(stru
+@@ -1269,7 +1530,8 @@ static int event_hist_trigger_print(stru
struct event_trigger_data *data)
{
struct hist_trigger_data *hist_data = data->private_data;
@@ -577,7 +651,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
unsigned int i;
seq_puts(m, "hist:");
-@@ -1292,25 +1489,47 @@ static int event_hist_trigger_print(stru
+@@ -1280,25 +1542,47 @@ static int event_hist_trigger_print(stru
seq_puts(m, "keys=");
for_each_hist_key_field(i, hist_data) {
@@ -629,7 +703,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
}
-@@ -1318,7 +1537,10 @@ static int event_hist_trigger_print(stru
+@@ -1306,7 +1590,10 @@ static int event_hist_trigger_print(stru
for (i = 0; i < hist_data->n_sort_keys; i++) {
struct tracing_map_sort_key *sort_key;
@@ -641,7 +715,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
sort_key = &hist_data->sort_keys[i];
idx = sort_key->field_idx;
-@@ -1331,8 +1553,11 @@ static int event_hist_trigger_print(stru
+@@ -1319,8 +1606,11 @@ static int event_hist_trigger_print(stru
if (idx == HITCOUNT_IDX)
seq_puts(m, "hitcount");
@@ -654,7 +728,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (sort_key->descending)
seq_puts(m, ".descending");
-@@ -1656,12 +1881,16 @@ static int event_hist_trigger_func(struc
+@@ -1644,12 +1934,16 @@ static int event_hist_trigger_func(struc
struct hist_trigger_attrs *attrs;
struct event_trigger_ops *trigger_ops;
struct hist_trigger_data *hist_data;
@@ -671,7 +745,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
/* 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(struc
+@@ -1662,7 +1956,7 @@ static int event_hist_trigger_func(struc
if (attrs->map_bits)
hist_trigger_bits = attrs->map_bits;
@@ -680,7 +754,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
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(struc
+@@ -1691,7 +1985,7 @@ static int event_hist_trigger_func(struc
goto out_free;
}
diff --git a/patches/0017-tracing-Account-for-variables-in-named-trigger-compa.patch b/patches/0019-tracing-Account-for-variables-in-named-trigger-compa.patch
index b55236edd88c..8e717ed18ce7 100644
--- a/patches/0017-tracing-Account-for-variables-in-named-trigger-compa.patch
+++ b/patches/0019-tracing-Account-for-variables-in-named-trigger-compa.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:18 -0500
-Subject: [PATCH 17/32] tracing: Account for variables in named trigger
+Date: Tue, 5 Sep 2017 16:57:31 -0500
+Subject: [PATCH 19/40] tracing: Account for variables in named trigger
compatibility
Named triggers must also have the same set of variables in order to be
@@ -18,7 +18,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -1545,7 +1545,7 @@ static int event_hist_trigger_print(stru
+@@ -1598,7 +1598,7 @@ static int event_hist_trigger_print(stru
sort_key = &hist_data->sort_keys[i];
idx = sort_key->field_idx;
@@ -27,7 +27,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return -EINVAL;
if (i > 0)
-@@ -1733,6 +1733,12 @@ static bool hist_trigger_match(struct ev
+@@ -1786,6 +1786,12 @@ static bool hist_trigger_match(struct ev
return false;
if (key_field->is_signed != key_field_test->is_signed)
return false;
diff --git a/patches/0018-tracing-Add-simple-expression-support-to-hist-trigge.patch b/patches/0020-tracing-Add-simple-expression-support-to-hist-trigge.patch
index dd2ae233312b..56b2385fe37f 100644
--- a/patches/0018-tracing-Add-simple-expression-support-to-hist-trigge.patch
+++ b/patches/0020-tracing-Add-simple-expression-support-to-hist-trigge.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:19 -0500
-Subject: [PATCH 18/32] tracing: Add simple expression support to hist triggers
+Date: Tue, 5 Sep 2017 16:57:32 -0500
+Subject: [PATCH 20/40] tracing: Add simple expression support to hist triggers
Add support for simple addition, subtraction, and unary expressions
(-(expr) and expr, where expr = b-a, a+b, a+b+c) to hist triggers, in
@@ -16,8 +16,8 @@ parsing.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/trace_events_hist.c | 457 +++++++++++++++++++++++++++++++++------
- 1 file changed, 390 insertions(+), 67 deletions(-)
+ kernel/trace/trace_events_hist.c | 556 ++++++++++++++++++++++++++++++++-------
+ 1 file changed, 460 insertions(+), 96 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -93,8 +93,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ HIST_FIELD_FL_EXPR = 16384,
};
- struct hist_trigger_attrs {
-@@ -210,6 +255,8 @@ static const char *hist_field_name(struc
+ struct var_defs {
+@@ -218,6 +263,8 @@ static const char *hist_field_name(struc
field_name = hist_field_name(field->operands[0], ++level);
else if (field->flags & HIST_FIELD_FL_TIMESTAMP)
field_name = "$common_timestamp";
@@ -103,15 +103,41 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (field_name == NULL)
field_name = "";
-@@ -444,6 +491,73 @@ static const struct tracing_map_ops hist
+@@ -441,6 +488,115 @@ static const struct tracing_map_ops hist
.elt_init = hist_trigger_elt_comm_init,
};
++static const char *get_hist_field_flags(struct hist_field *hist_field)
++{
++ const char *flags_str = NULL;
++
++ if (hist_field->flags & HIST_FIELD_FL_HEX)
++ flags_str = "hex";
++ else if (hist_field->flags & HIST_FIELD_FL_SYM)
++ flags_str = "sym";
++ else if (hist_field->flags & HIST_FIELD_FL_SYM_OFFSET)
++ flags_str = "sym-offset";
++ else if (hist_field->flags & HIST_FIELD_FL_EXECNAME)
++ flags_str = "execname";
++ else if (hist_field->flags & HIST_FIELD_FL_SYSCALL)
++ flags_str = "syscall";
++ else if (hist_field->flags & HIST_FIELD_FL_LOG2)
++ flags_str = "log2";
++ else if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP_USECS)
++ flags_str = "usecs";
++
++ return flags_str;
++}
++
+static char *expr_str(struct hist_field *field, unsigned int level)
+{
-+ char *expr = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
++ char *expr;
+
-+ if (!expr || level > 1)
++ if (level > 1)
++ return NULL;
++
++ expr = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
++ if (!expr)
+ return NULL;
+
+ if (field->operator == FIELD_OP_UNARY_MINUS) {
@@ -130,6 +156,14 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ }
+
+ strcat(expr, hist_field_name(field->operands[0], 0));
++ if (field->operands[0]->flags) {
++ const char *flags_str = get_hist_field_flags(field->operands[0]);
++
++ if (flags_str) {
++ strcat(expr, ".");
++ strcat(expr, flags_str);
++ }
++ }
+
+ switch (field->operator) {
+ case FIELD_OP_MINUS:
@@ -144,6 +178,14 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ }
+
+ strcat(expr, hist_field_name(field->operands[1], 0));
++ if (field->operands[1]->flags) {
++ const char *flags_str = get_hist_field_flags(field->operands[1]);
++
++ if (flags_str) {
++ strcat(expr, ".");
++ strcat(expr, flags_str);
++ }
++ }
+
+ return expr;
+}
@@ -177,15 +219,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static void destroy_hist_field(struct hist_field *hist_field,
unsigned int level)
{
-@@ -459,6 +573,7 @@ static void destroy_hist_field(struct hi
- destroy_hist_field(hist_field->operands[i], ++level);
+@@ -456,6 +612,7 @@ static void destroy_hist_field(struct hi
+ destroy_hist_field(hist_field->operands[i], level + 1);
kfree(hist_field->var.name);
+ kfree(hist_field->name);
kfree(hist_field);
}
-@@ -479,6 +594,9 @@ static struct hist_field *create_hist_fi
+@@ -476,6 +633,9 @@ static struct hist_field *create_hist_fi
hist_field->hist_data = hist_data;
@@ -195,36 +237,70 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (flags & HIST_FIELD_FL_HITCOUNT) {
hist_field->fn = hist_field_counter;
goto out;
-@@ -551,6 +669,247 @@ static void destroy_hist_fields(struct h
+@@ -548,6 +708,287 @@ static void destroy_hist_fields(struct h
}
}
++static char *field_name_from_var(struct hist_trigger_data *hist_data,
++ char *var_name)
++{
++ char *name, *field;
++ unsigned int i;
++
++ for (i = 0; i < hist_data->attrs->var_defs.n_vars; i++) {
++ name = hist_data->attrs->var_defs.name[i];
++
++ if (strcmp(var_name, name) == 0) {
++ field = hist_data->attrs->var_defs.expr[i];
++ if (contains_operator(field))
++ continue;
++ return field;
++ }
++ }
++
++ return NULL;
++}
++
++static char *local_field_var_ref(struct hist_trigger_data *hist_data,
++ char *var_name)
++{
++ var_name++;
++
++ return field_name_from_var(hist_data, var_name);
++}
++
+static struct ftrace_event_field *
+parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
+ char *field_str, unsigned long *flags)
+{
+ struct ftrace_event_field *field = NULL;
-+ char *field_name;
++ char *field_name, *modifier, *str;
+
-+ field_name = strsep(&field_str, ".");
-+ if (field_str) {
-+ if (strcmp(field_str, "hex") == 0)
++ modifier = str = kstrdup(field_str, GFP_KERNEL);
++ if (!modifier)
++ return ERR_PTR(-ENOMEM);
++
++ field_name = strsep(&modifier, ".");
++ if (modifier) {
++ if (strcmp(modifier, "hex") == 0)
+ *flags |= HIST_FIELD_FL_HEX;
-+ else if (strcmp(field_str, "sym") == 0)
++ else if (strcmp(modifier, "sym") == 0)
+ *flags |= HIST_FIELD_FL_SYM;
-+ else if (strcmp(field_str, "sym-offset") == 0)
++ else if (strcmp(modifier, "sym-offset") == 0)
+ *flags |= HIST_FIELD_FL_SYM_OFFSET;
-+ else if ((strcmp(field_str, "execname") == 0) &&
++ else if ((strcmp(modifier, "execname") == 0) &&
+ (strcmp(field_name, "common_pid") == 0))
+ *flags |= HIST_FIELD_FL_EXECNAME;
-+ else if (strcmp(field_str, "syscall") == 0)
++ else if (strcmp(modifier, "syscall") == 0)
+ *flags |= HIST_FIELD_FL_SYSCALL;
-+ else if (strcmp(field_str, "log2") == 0)
++ else if (strcmp(modifier, "log2") == 0)
+ *flags |= HIST_FIELD_FL_LOG2;
-+ else if (strcmp(field_str, "usecs") == 0)
++ else if (strcmp(modifier, "usecs") == 0)
+ *flags |= HIST_FIELD_FL_TIMESTAMP_USECS;
-+ else
-+ return ERR_PTR(-EINVAL);
++ else {
++ field = ERR_PTR(-EINVAL);
++ goto out;
++ }
+ }
+
+ if (strcmp(field_name, "$common_timestamp") == 0) {
@@ -234,9 +310,13 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ hist_data->attrs->ts_in_usecs = true;
+ } else {
+ field = trace_find_event_field(file->event_call, field_name);
-+ if (!field)
-+ return ERR_PTR(-EINVAL);
++ if (!field || !field->size) {
++ field = ERR_PTR(-EINVAL);
++ goto out;
++ }
+ }
++ out:
++ kfree(str);
+
+ return field;
+}
@@ -245,10 +325,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct trace_event_file *file, char *str,
+ unsigned long *flags, char *var_name)
+{
++ char *s;
+ struct ftrace_event_field *field = NULL;
+ struct hist_field *hist_field = NULL;
+ int ret = 0;
+
++ s = local_field_var_ref(hist_data, str);
++ if (s)
++ str = s;
++
+ field = parse_field(hist_data, file, str, flags);
+ if (IS_ERR(field)) {
+ ret = PTR_ERR(field);
@@ -278,7 +363,6 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+{
+ struct hist_field *operand1, *expr = NULL;
+ unsigned long operand_flags;
-+ char *operand1_str;
+ int ret = 0;
+ char *s;
+
@@ -307,8 +391,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ goto free;
+ }
+
-+ operand1_str = strsep(&str, "(");
-+ if (!operand1_str)
++ strsep(&str, "(");
++ if (!str)
+ goto free;
+
+ flags |= HIST_FIELD_FL_EXPR;
@@ -325,16 +409,6 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ goto free;
+ }
+
-+ if (operand1 == NULL) {
-+ operand_flags = 0;
-+ operand1 = parse_atom(hist_data, file, operand1_str,
-+ &operand_flags, NULL);
-+ if (IS_ERR(operand1)) {
-+ ret = PTR_ERR(operand1);
-+ goto free;
-+ }
-+ }
-+
+ expr->fn = hist_field_unary_minus;
+ expr->operands[0] = operand1;
+ expr->operator = FIELD_OP_UNARY_MINUS;
@@ -345,6 +419,19 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return ERR_PTR(ret);
+}
+
++static int check_expr_operands(struct hist_field *operand1,
++ struct hist_field *operand2)
++{
++ unsigned long operand1_flags = operand1->flags;
++ unsigned long operand2_flags = operand2->flags;
++
++ if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
++ (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS))
++ return -EINVAL;
++
++ return 0;
++}
++
+static struct hist_field *parse_expr(struct hist_trigger_data *hist_data,
+ struct trace_event_file *file,
+ char *str, unsigned long flags,
@@ -356,11 +443,12 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ char *sep, *operand1_str;
+
+ if (level > 2)
-+ return NULL;
++ return ERR_PTR(-EINVAL);
+
+ field_op = contains_operator(str);
++
+ if (field_op == FIELD_OP_NONE)
-+ return NULL;
++ return parse_atom(hist_data, file, str, &flags, var_name);
+
+ if (field_op == FIELD_OP_UNARY_MINUS)
+ return parse_unary(hist_data, file, str, flags, var_name, ++level);
@@ -397,16 +485,10 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ operand2 = NULL;
+ goto free;
+ }
-+ if (!operand2) {
-+ operand_flags = 0;
-+ operand2 = parse_atom(hist_data, file, str,
-+ &operand_flags, NULL);
-+ if (IS_ERR(operand2)) {
-+ ret = PTR_ERR(operand2);
-+ operand2 = NULL;
-+ goto free;
-+ }
-+ }
++
++ ret = check_expr_operands(operand1, operand2);
++ if (ret)
++ goto free;
+
+ flags |= HIST_FIELD_FL_EXPR;
+ expr = create_hist_field(hist_data, NULL, flags, var_name);
@@ -443,22 +525,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static int create_hitcount_val(struct hist_trigger_data *hist_data)
{
hist_data->fields[HITCOUNT_IDX] =
-@@ -609,9 +968,9 @@ static int create_val_field(struct hist_
- struct trace_event_file *file,
- char *field_str, bool var_only)
+@@ -607,41 +1048,21 @@ static int __create_val_field(struct his
+ char *var_name, char *field_str,
+ unsigned long flags)
{
- struct ftrace_event_field *field = NULL;
-- char *field_name, *var_name;
+- char *field_name;
+ struct hist_field *hist_field;
- unsigned long flags = 0;
-+ char *var_name;
int ret = 0;
- if (WARN_ON(!var_only && val_idx >= TRACING_MAP_VALS_MAX))
-@@ -642,37 +1001,27 @@ static int create_val_field(struct hist_
- goto out;
- }
-
- field_name = strsep(&field_str, ".");
- if (field_str) {
- if (strcmp(field_str, "hex") == 0)
@@ -467,35 +542,30 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
- ret = -EINVAL;
- goto out;
- }
-+ hist_field = parse_expr(hist_data, file, field_str, flags, var_name, 0);
-+ if (IS_ERR(hist_field)) {
-+ ret = PTR_ERR(hist_field);
-+ goto out;
- }
-
+- }
+-
- if (strcmp(field_name, "$common_timestamp") == 0) {
- flags |= HIST_FIELD_FL_TIMESTAMP;
- hist_data->enable_timestamps = true;
- } else {
- field = trace_find_event_field(file->event_call, field_name);
-- if (!field) {
+- if (!field || !field->size) {
- ret = -EINVAL;
-+ if (!hist_field) {
-+ hist_field = parse_atom(hist_data, file, field_str,
-+ &flags, var_name);
-+ if (IS_ERR(hist_field)) {
-+ ret = PTR_ERR(hist_field);
- goto out;
- }
- }
-
+- goto out;
+- }
+- }
+-
- 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->fields[val_idx] = hist_field;
++ hist_field = parse_expr(hist_data, file, field_str, flags, var_name, 0);
++ if (IS_ERR(hist_field)) {
++ ret = PTR_ERR(hist_field);
+ goto out;
+ }
++ hist_data->fields[val_idx] = hist_field;
++
++hist_data->n_vals;
++hist_data->n_fields;
@@ -504,7 +574,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
hist_data->n_var_only++;
if (WARN_ON(hist_data->n_vals > TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
-@@ -726,8 +1075,8 @@ static int create_key_field(struct hist_
+@@ -731,8 +1152,8 @@ static int create_key_field(struct hist_
struct trace_event_file *file,
char *field_str)
{
@@ -513,10 +583,10 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
unsigned long flags = 0;
unsigned int key_size;
- char *var_name;
-@@ -754,60 +1103,33 @@ static int create_key_field(struct hist_
+ int ret = 0;
+@@ -747,60 +1168,24 @@ static int create_key_field(struct hist_
key_size = sizeof(unsigned long) * HIST_STACKTRACE_DEPTH;
- hist_field = create_hist_field(hist_data, NULL, flags, var_name);
+ hist_field = create_hist_field(hist_data, NULL, flags, NULL);
} else {
- char *field_name = strsep(&field_str, ".");
-
@@ -541,7 +611,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
- goto out;
- }
+ hist_field = parse_expr(hist_data, file, field_str, flags,
-+ var_name, 0);
++ NULL, 0);
+ if (IS_ERR(hist_field)) {
+ ret = PTR_ERR(hist_field);
+ goto out;
@@ -555,32 +625,26 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
- key_size = sizeof(u64);
- } else {
- field = trace_find_event_field(file->event_call, field_name);
-- if (!field) {
+- if (!field || !field->size) {
- ret = -EINVAL;
-+ if (!hist_field) {
-+ hist_field = parse_atom(hist_data, file, field_str,
-+ &flags, var_name);
-+ if (IS_ERR(hist_field)) {
-+ ret = PTR_ERR(hist_field);
- goto out;
- }
+- goto out;
+- }
-
- if (is_string_field(field))
- key_size = MAX_FILTER_STR_VAL;
- else
- key_size = field->size;
- }
-- }
+- }
++ key_size = hist_field->size;
+ }
-- hist_data->fields[key_idx] = create_hist_field(hist_data, field, flags, var_name);
+- hist_data->fields[key_idx] = create_hist_field(hist_data, field, flags, NULL);
- if (!hist_data->fields[key_idx]) {
- ret = -ENOMEM;
- goto out;
-+ key_size = hist_field->size;
- }
-
+- }
+ hist_data->fields[key_idx] = hist_field;
-+
+
key_size = ALIGN(key_size, sizeof(u64));
hist_data->fields[key_idx]->size = key_size;
hist_data->fields[key_idx]->offset = key_offset;
@@ -590,7 +654,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (hist_data->key_size > HIST_KEY_SIZE_MAX) {
ret = -EINVAL;
goto out;
-@@ -1330,7 +1652,8 @@ hist_trigger_entry_print(struct seq_file
+@@ -1383,7 +1768,8 @@ hist_trigger_entry_print(struct seq_file
for (i = 1; i < hist_data->n_vals; i++) {
field_name = hist_field_name(hist_data->fields[i], 0);
@@ -600,3 +664,32 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
continue;
if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
+@@ -1483,28 +1869,6 @@ const struct file_operations event_hist_
+ .release = single_release,
+ };
+
+-static const char *get_hist_field_flags(struct hist_field *hist_field)
+-{
+- const char *flags_str = NULL;
+-
+- if (hist_field->flags & HIST_FIELD_FL_HEX)
+- flags_str = "hex";
+- else if (hist_field->flags & HIST_FIELD_FL_SYM)
+- flags_str = "sym";
+- else if (hist_field->flags & HIST_FIELD_FL_SYM_OFFSET)
+- flags_str = "sym-offset";
+- else if (hist_field->flags & HIST_FIELD_FL_EXECNAME)
+- flags_str = "execname";
+- else if (hist_field->flags & HIST_FIELD_FL_SYSCALL)
+- flags_str = "syscall";
+- else if (hist_field->flags & HIST_FIELD_FL_LOG2)
+- flags_str = "log2";
+- else if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP_USECS)
+- flags_str = "usecs";
+-
+- return flags_str;
+-}
+-
+ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)
+ {
+ const char *field_name = hist_field_name(hist_field, 0);
diff --git a/patches/0020-tracing-Add-support-for-dynamic-tracepoints.patch b/patches/0020-tracing-Add-support-for-dynamic-tracepoints.patch
deleted file mode 100644
index d7bc190643da..000000000000
--- a/patches/0020-tracing-Add-support-for-dynamic-tracepoints.patch
+++ /dev/null
@@ -1,195 +0,0 @@
-From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:21 -0500
-Subject: [PATCH 20/32] tracing: Add support for dynamic tracepoints
-
-The tracepoint infrastructure assumes statically-defined tracepoints
-and uses static_keys for tracepoint enablement. In order to define
-tracepoints on the fly, we need to have a dynamic counterpart.
-
-Add a dynamic_tracepoint_probe_register() and a dynamic param onto
-tracepoint_probe_unregister() for this purpose.
-
-Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
----
- include/linux/tracepoint.h | 11 +++++++----
- kernel/trace/trace_events.c | 4 ++--
- kernel/tracepoint.c | 42 ++++++++++++++++++++++++++++++------------
- 3 files changed, 39 insertions(+), 18 deletions(-)
-
---- a/include/linux/tracepoint.h
-+++ b/include/linux/tracepoint.h
-@@ -37,9 +37,12 @@ extern int
- tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);
- extern int
- tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data,
-- int prio);
-+ int prio, bool dynamic);
-+extern int dynamic_tracepoint_probe_register(struct tracepoint *tp,
-+ void *probe, void *data);
- extern int
--tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data);
-+tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data,
-+ bool dynamic);
- extern void
- for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv),
- void *priv);
-@@ -206,13 +209,13 @@ extern void syscall_unregfunc(void);
- int prio) \
- { \
- return tracepoint_probe_register_prio(&__tracepoint_##name, \
-- (void *)probe, data, prio); \
-+ (void *)probe, data, prio, false); \
- } \
- static inline int \
- unregister_trace_##name(void (*probe)(data_proto), void *data) \
- { \
- return tracepoint_probe_unregister(&__tracepoint_##name,\
-- (void *)probe, data); \
-+ (void *)probe, data, false); \
- } \
- static inline void \
- check_trace_callback_type_##name(void (*cb)(data_proto)) \
---- a/kernel/trace/trace_events.c
-+++ b/kernel/trace/trace_events.c
-@@ -297,7 +297,7 @@ int trace_event_reg(struct trace_event_c
- case TRACE_REG_UNREGISTER:
- tracepoint_probe_unregister(call->tp,
- call->class->probe,
-- file);
-+ file, false);
- return 0;
-
- #ifdef CONFIG_PERF_EVENTS
-@@ -308,7 +308,7 @@ int trace_event_reg(struct trace_event_c
- case TRACE_REG_PERF_UNREGISTER:
- tracepoint_probe_unregister(call->tp,
- call->class->perf_probe,
-- call);
-+ call, false);
- return 0;
- case TRACE_REG_PERF_OPEN:
- case TRACE_REG_PERF_CLOSE:
---- a/kernel/tracepoint.c
-+++ b/kernel/tracepoint.c
-@@ -192,12 +192,15 @@ static void *func_remove(struct tracepoi
- * Add the probe function to a tracepoint.
- */
- static int tracepoint_add_func(struct tracepoint *tp,
-- struct tracepoint_func *func, int prio)
-+ struct tracepoint_func *func, int prio,
-+ bool dynamic)
- {
- struct tracepoint_func *old, *tp_funcs;
- int ret;
-
-- if (tp->regfunc && !static_key_enabled(&tp->key)) {
-+ if (tp->regfunc &&
-+ ((dynamic && !(atomic_read(&tp->key.enabled) > 0)) ||
-+ !static_key_enabled(&tp->key))) {
- ret = tp->regfunc();
- if (ret < 0)
- return ret;
-@@ -219,7 +222,9 @@ static int tracepoint_add_func(struct tr
- * is used.
- */
- rcu_assign_pointer(tp->funcs, tp_funcs);
-- if (!static_key_enabled(&tp->key))
-+ if (dynamic && !(atomic_read(&tp->key.enabled) > 0))
-+ atomic_inc(&tp->key.enabled);
-+ else if (!dynamic && !static_key_enabled(&tp->key))
- static_key_slow_inc(&tp->key);
- release_probes(old);
- return 0;
-@@ -232,7 +237,7 @@ static int tracepoint_add_func(struct tr
- * by preempt_disable around the call site.
- */
- static int tracepoint_remove_func(struct tracepoint *tp,
-- struct tracepoint_func *func)
-+ struct tracepoint_func *func, bool dynamic)
- {
- struct tracepoint_func *old, *tp_funcs;
-
-@@ -246,10 +251,14 @@ static int tracepoint_remove_func(struct
-
- if (!tp_funcs) {
- /* Removed last function */
-- if (tp->unregfunc && static_key_enabled(&tp->key))
-+ if (tp->unregfunc &&
-+ ((dynamic && (atomic_read(&tp->key.enabled) > 0)) ||
-+ static_key_enabled(&tp->key)))
- tp->unregfunc();
-
-- if (static_key_enabled(&tp->key))
-+ if (dynamic && (atomic_read(&tp->key.enabled) > 0))
-+ atomic_dec(&tp->key.enabled);
-+ else if (!dynamic && static_key_enabled(&tp->key))
- static_key_slow_dec(&tp->key);
- }
- rcu_assign_pointer(tp->funcs, tp_funcs);
-@@ -258,7 +267,7 @@ static int tracepoint_remove_func(struct
- }
-
- /**
-- * tracepoint_probe_register - Connect a probe to a tracepoint
-+ * tracepoint_probe_register_prio - Connect a probe to a tracepoint
- * @tp: tracepoint
- * @probe: probe handler
- * @data: tracepoint data
-@@ -271,7 +280,7 @@ static int tracepoint_remove_func(struct
- * within module exit functions.
- */
- int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe,
-- void *data, int prio)
-+ void *data, int prio, bool dynamic)
- {
- struct tracepoint_func tp_func;
- int ret;
-@@ -280,7 +289,7 @@ int tracepoint_probe_register_prio(struc
- tp_func.func = probe;
- tp_func.data = data;
- tp_func.prio = prio;
-- ret = tracepoint_add_func(tp, &tp_func, prio);
-+ ret = tracepoint_add_func(tp, &tp_func, prio, dynamic);
- mutex_unlock(&tracepoints_mutex);
- return ret;
- }
-@@ -301,10 +310,18 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_regis
- */
- int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data)
- {
-- return tracepoint_probe_register_prio(tp, probe, data, TRACEPOINT_DEFAULT_PRIO);
-+ return tracepoint_probe_register_prio(tp, probe, data, TRACEPOINT_DEFAULT_PRIO, false);
- }
- EXPORT_SYMBOL_GPL(tracepoint_probe_register);
-
-+int dynamic_tracepoint_probe_register(struct tracepoint *tp, void *probe,
-+ void *data)
-+{
-+ return tracepoint_probe_register_prio(tp, probe, data,
-+ TRACEPOINT_DEFAULT_PRIO, true);
-+}
-+EXPORT_SYMBOL_GPL(dynamic_tracepoint_probe_register);
-+
- /**
- * tracepoint_probe_unregister - Disconnect a probe from a tracepoint
- * @tp: tracepoint
-@@ -313,7 +330,8 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_regis
- *
- * Returns 0 if ok, error value on error.
- */
--int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data)
-+int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data,
-+ bool dynamic)
- {
- struct tracepoint_func tp_func;
- int ret;
-@@ -321,7 +339,7 @@ int tracepoint_probe_unregister(struct t
- mutex_lock(&tracepoints_mutex);
- tp_func.func = probe;
- tp_func.data = data;
-- ret = tracepoint_remove_func(tp, &tp_func);
-+ ret = tracepoint_remove_func(tp, &tp_func, dynamic);
- mutex_unlock(&tracepoints_mutex);
- return ret;
- }
diff --git a/patches/0021-tracing-Generalize-per-element-hist-trigger-data.patch b/patches/0021-tracing-Generalize-per-element-hist-trigger-data.patch
new file mode 100644
index 000000000000..1ab8f84aefed
--- /dev/null
+++ b/patches/0021-tracing-Generalize-per-element-hist-trigger-data.patch
@@ -0,0 +1,143 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:33 -0500
+Subject: [PATCH 21/40] tracing: Generalize per-element hist trigger data
+
+Up until now, hist triggers only needed per-element support for saving
+'comm' data, which was saved directly as a private data pointer.
+
+In anticipation of the need to save other data besides 'comm', add a
+new hist_elt_data struct for the purpose, and switch the current
+'comm'-related code over to that.
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace_events_hist.c | 65 +++++++++++++++++++--------------------
+ 1 file changed, 32 insertions(+), 33 deletions(-)
+
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -249,6 +249,10 @@ static u64 hist_field_timestamp(struct h
+ return ts;
+ }
+
++struct hist_elt_data {
++ char *comm;
++};
++
+ static const char *hist_field_name(struct hist_field *field,
+ unsigned int level)
+ {
+@@ -447,26 +451,36 @@ static inline void save_comm(char *comm,
+ memcpy(comm, task->comm, TASK_COMM_LEN);
+ }
+
+-static void hist_trigger_elt_comm_free(struct tracing_map_elt *elt)
++static void hist_trigger_elt_data_free(struct tracing_map_elt *elt)
+ {
+- kfree((char *)elt->private_data);
++ struct hist_elt_data *private_data = elt->private_data;
++
++ kfree(private_data->comm);
++ kfree(private_data);
+ }
+
+-static int hist_trigger_elt_comm_alloc(struct tracing_map_elt *elt)
++static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt)
+ {
+ struct hist_trigger_data *hist_data = elt->map->private_data;
++ unsigned int size = TASK_COMM_LEN + 1;
++ struct hist_elt_data *elt_data;
+ struct hist_field *key_field;
+ unsigned int i;
+
++ elt->private_data = elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL);
++ if (!elt_data)
++ return -ENOMEM;
++
+ for_each_hist_key_field(i, hist_data) {
+ key_field = hist_data->fields[i];
+
+ if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
+- unsigned int size = TASK_COMM_LEN + 1;
+-
+- elt->private_data = kzalloc(size, GFP_KERNEL);
+- if (!elt->private_data)
++ elt_data->comm = kzalloc(size, GFP_KERNEL);
++ if (!elt_data->comm) {
++ kfree(elt_data);
++ elt->private_data = NULL;
+ return -ENOMEM;
++ }
+ break;
+ }
+ }
+@@ -474,18 +488,18 @@ static int hist_trigger_elt_comm_alloc(s
+ return 0;
+ }
+
+-static void hist_trigger_elt_comm_init(struct tracing_map_elt *elt)
++static void hist_trigger_elt_data_init(struct tracing_map_elt *elt)
+ {
+- char *comm = elt->private_data;
++ struct hist_elt_data *private_data = elt->private_data;
+
+- if (comm)
+- save_comm(comm, current);
++ if (private_data->comm)
++ save_comm(private_data->comm, current);
+ }
+
+-static const struct tracing_map_ops hist_trigger_elt_comm_ops = {
+- .elt_alloc = hist_trigger_elt_comm_alloc,
+- .elt_free = hist_trigger_elt_comm_free,
+- .elt_init = hist_trigger_elt_comm_init,
++static const struct tracing_map_ops hist_trigger_elt_data_ops = {
++ .elt_alloc = hist_trigger_elt_data_alloc,
++ .elt_free = hist_trigger_elt_data_free,
++ .elt_init = hist_trigger_elt_data_init,
+ };
+
+ static const char *get_hist_field_flags(struct hist_field *hist_field)
+@@ -1494,21 +1508,6 @@ static int create_tracing_map_fields(str
+ return 0;
+ }
+
+-static bool need_tracing_map_ops(struct hist_trigger_data *hist_data)
+-{
+- struct hist_field *key_field;
+- unsigned int i;
+-
+- for_each_hist_key_field(i, hist_data) {
+- key_field = hist_data->fields[i];
+-
+- if (key_field->flags & HIST_FIELD_FL_EXECNAME)
+- return true;
+- }
+-
+- return false;
+-}
+-
+ static struct hist_trigger_data *
+ create_hist_data(unsigned int map_bits,
+ struct hist_trigger_attrs *attrs,
+@@ -1534,8 +1533,7 @@ create_hist_data(unsigned int map_bits,
+ if (ret)
+ goto free;
+
+- if (need_tracing_map_ops(hist_data))
+- map_ops = &hist_trigger_elt_comm_ops;
++ map_ops = &hist_trigger_elt_data_ops;
+
+ hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
+ map_ops, hist_data);
+@@ -1724,7 +1722,8 @@ hist_trigger_entry_print(struct seq_file
+ seq_printf(m, "%s: [%llx] %-55s", field_name,
+ uval, str);
+ } else if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
+- char *comm = elt->private_data;
++ struct hist_elt_data *elt_data = elt->private_data;
++ char *comm = elt_data->comm;
+
+ uval = *(u64 *)(key + key_field->offset);
+ seq_printf(m, "%s: %-16s[%10llu]", field_name,
diff --git a/patches/0022-tracing-Pass-tracing_map_elt-to-hist_field-accessor-.patch b/patches/0022-tracing-Pass-tracing_map_elt-to-hist_field-accessor-.patch
new file mode 100644
index 000000000000..faa6dd2a0da7
--- /dev/null
+++ b/patches/0022-tracing-Pass-tracing_map_elt-to-hist_field-accessor-.patch
@@ -0,0 +1,221 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:34 -0500
+Subject: [PATCH 22/40] tracing: Pass tracing_map_elt to hist_field accessor
+ functions
+
+Some accessor functions, such as for variable references, require
+access to a corrsponding tracing_map_elt.
+
+Add a tracing_map_elt param to the function signature and update the
+accessor functions accordingly.
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace_events_hist.c | 91 ++++++++++++++++++++++++---------------
+ 1 file changed, 57 insertions(+), 34 deletions(-)
+
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -26,8 +26,10 @@
+
+ struct hist_field;
+
+-typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event,
+- struct ring_buffer_event *rbe);
++typedef u64 (*hist_field_fn_t) (struct hist_field *field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event);
+
+ #define HIST_FIELD_OPERANDS_MAX 2
+ #define HIST_FIELDS_MAX (TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX)
+@@ -59,28 +61,36 @@ struct hist_field {
+ char *name;
+ };
+
+-static u64 hist_field_none(struct hist_field *field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_none(struct hist_field *field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ return 0;
+ }
+
+-static u64 hist_field_counter(struct hist_field *field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_counter(struct hist_field *field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ return 1;
+ }
+
+-static u64 hist_field_string(struct hist_field *hist_field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_string(struct hist_field *hist_field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ char *addr = (char *)(event + hist_field->field->offset);
+
+ return (u64)(unsigned long)addr;
+ }
+
+-static u64 hist_field_dynstring(struct hist_field *hist_field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_dynstring(struct hist_field *hist_field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ u32 str_item = *(u32 *)(event + hist_field->field->offset);
+ int str_loc = str_item & 0xffff;
+@@ -89,54 +99,64 @@ static u64 hist_field_dynstring(struct h
+ return (u64)(unsigned long)addr;
+ }
+
+-static u64 hist_field_pstring(struct hist_field *hist_field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_pstring(struct hist_field *hist_field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ char **addr = (char **)(event + hist_field->field->offset);
+
+ return (u64)(unsigned long)*addr;
+ }
+
+-static u64 hist_field_log2(struct hist_field *hist_field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_log2(struct hist_field *hist_field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ struct hist_field *operand = hist_field->operands[0];
+
+- u64 val = operand->fn(operand, event, rbe);
++ u64 val = operand->fn(operand, elt, rbe, event);
+
+ return (u64) ilog2(roundup_pow_of_two(val));
+ }
+
+-static u64 hist_field_plus(struct hist_field *hist_field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_plus(struct hist_field *hist_field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ struct hist_field *operand1 = hist_field->operands[0];
+ struct hist_field *operand2 = hist_field->operands[1];
+
+- u64 val1 = operand1->fn(operand1, event, rbe);
+- u64 val2 = operand2->fn(operand2, event, rbe);
++ u64 val1 = operand1->fn(operand1, elt, rbe, event);
++ u64 val2 = operand2->fn(operand2, elt, rbe, event);
+
+ return val1 + val2;
+ }
+
+-static u64 hist_field_minus(struct hist_field *hist_field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_minus(struct hist_field *hist_field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ struct hist_field *operand1 = hist_field->operands[0];
+ struct hist_field *operand2 = hist_field->operands[1];
+
+- u64 val1 = operand1->fn(operand1, event, rbe);
+- u64 val2 = operand2->fn(operand2, event, rbe);
++ u64 val1 = operand1->fn(operand1, elt, rbe, event);
++ u64 val2 = operand2->fn(operand2, elt, rbe, event);
+
+ return val1 - val2;
+ }
+
+-static u64 hist_field_unary_minus(struct hist_field *hist_field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_unary_minus(struct hist_field *hist_field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ struct hist_field *operand = hist_field->operands[0];
+
+- s64 sval = (s64)operand->fn(operand, event, rbe);
++ s64 sval = (s64)operand->fn(operand, elt, rbe, event);
+ u64 val = (u64)-sval;
+
+ return val;
+@@ -144,8 +164,9 @@ static u64 hist_field_unary_minus(struct
+
+ #define DEFINE_HIST_FIELD_FN(type) \
+ static u64 hist_field_##type(struct hist_field *hist_field, \
+- void *event, \
+- struct ring_buffer_event *rbe) \
++ struct tracing_map_elt *elt, \
++ struct ring_buffer_event *rbe, \
++ void *event) \
+ { \
+ type *addr = (type *)(event + hist_field->field->offset); \
+ \
+@@ -235,8 +256,10 @@ struct hist_trigger_data {
+ bool remove;
+ };
+
+-static u64 hist_field_timestamp(struct hist_field *hist_field, void *event,
+- struct ring_buffer_event *rbe)
++static u64 hist_field_timestamp(struct hist_field *hist_field,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *event)
+ {
+ struct hist_trigger_data *hist_data = hist_field->hist_data;
+ struct trace_array *tr = hist_data->event_file->tr;
+@@ -1574,7 +1597,7 @@ static void hist_trigger_elt_update(stru
+
+ for_each_hist_val_field(i, hist_data) {
+ hist_field = hist_data->fields[i];
+- hist_val = hist_field->fn(hist_field, rbe, rec);
++ hist_val = hist_field->fn(hist_field, elt, 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);
+@@ -1587,7 +1610,7 @@ static void hist_trigger_elt_update(stru
+ 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);
++ hist_val = hist_field->fn(hist_field, elt, rbe, rec);
+ var_idx = hist_field->var.idx;
+ tracing_map_set_var(elt, var_idx, hist_val);
+ }
+@@ -1625,9 +1648,9 @@ static void event_hist_trigger(struct ev
+ bool use_compound_key = (hist_data->n_keys > 1);
+ unsigned long entries[HIST_STACKTRACE_DEPTH];
+ char compound_key[HIST_KEY_SIZE_MAX];
++ struct tracing_map_elt *elt = NULL;
+ struct stack_trace stacktrace;
+ struct hist_field *key_field;
+- struct tracing_map_elt *elt;
+ u64 field_contents;
+ void *key = NULL;
+ unsigned int i;
+@@ -1648,7 +1671,7 @@ static void event_hist_trigger(struct ev
+
+ key = entries;
+ } else {
+- field_contents = key_field->fn(key_field, rec, rbe);
++ field_contents = key_field->fn(key_field, elt, rbe, rec);
+ if (key_field->flags & HIST_FIELD_FL_STRING) {
+ key = (void *)(unsigned long)field_contents;
+ use_compound_key = true;
diff --git a/patches/0023-tracing-Add-hist_field-type-field.patch b/patches/0023-tracing-Add-hist_field-type-field.patch
new file mode 100644
index 000000000000..63bd58c3f92a
--- /dev/null
+++ b/patches/0023-tracing-Add-hist_field-type-field.patch
@@ -0,0 +1,113 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:35 -0500
+Subject: [PATCH 23/40] tracing: Add hist_field 'type' field
+
+Future support for synthetic events requires hist_field 'type'
+information, so add a field for that.
+
+Also, make other hist_field attribute usage consistent (size,
+is_signed, etc).
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace_events_hist.c | 33 +++++++++++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -54,6 +54,7 @@ struct hist_field {
+ unsigned int size;
+ unsigned int offset;
+ unsigned int is_signed;
++ const char *type;
+ struct hist_field *operands[HIST_FIELD_OPERANDS_MAX];
+ struct hist_trigger_data *hist_data;
+ struct hist_var var;
+@@ -650,6 +651,7 @@ static void destroy_hist_field(struct hi
+
+ kfree(hist_field->var.name);
+ kfree(hist_field->name);
++ kfree(hist_field->type);
+
+ kfree(hist_field);
+ }
+@@ -675,6 +677,10 @@ static struct hist_field *create_hist_fi
+
+ if (flags & HIST_FIELD_FL_HITCOUNT) {
+ hist_field->fn = hist_field_counter;
++ hist_field->size = sizeof(u64);
++ hist_field->type = kstrdup("u64", GFP_KERNEL);
++ if (!hist_field->type)
++ goto free;
+ goto out;
+ }
+
+@@ -688,12 +694,18 @@ static struct hist_field *create_hist_fi
+ hist_field->fn = hist_field_log2;
+ hist_field->operands[0] = create_hist_field(hist_data, field, fl, NULL);
+ hist_field->size = hist_field->operands[0]->size;
++ hist_field->type = kstrdup(hist_field->operands[0]->type, GFP_KERNEL);
++ if (!hist_field->type)
++ goto free;
+ goto out;
+ }
+
+ if (flags & HIST_FIELD_FL_TIMESTAMP) {
+ hist_field->fn = hist_field_timestamp;
+ hist_field->size = sizeof(u64);
++ hist_field->type = kstrdup("u64", GFP_KERNEL);
++ if (!hist_field->type)
++ goto free;
+ goto out;
+ }
+
+@@ -703,6 +715,11 @@ static struct hist_field *create_hist_fi
+ if (is_string_field(field)) {
+ flags |= HIST_FIELD_FL_STRING;
+
++ hist_field->size = MAX_FILTER_STR_VAL;
++ hist_field->type = kstrdup(field->type, GFP_KERNEL);
++ if (!hist_field->type)
++ goto free;
++
+ if (field->filter_type == FILTER_STATIC_STRING)
+ hist_field->fn = hist_field_string;
+ else if (field->filter_type == FILTER_DYN_STRING)
+@@ -710,6 +727,12 @@ static struct hist_field *create_hist_fi
+ else
+ hist_field->fn = hist_field_pstring;
+ } else {
++ hist_field->size = field->size;
++ hist_field->is_signed = field->is_signed;
++ hist_field->type = kstrdup(field->type, GFP_KERNEL);
++ if (!hist_field->type)
++ goto free;
++
+ hist_field->fn = select_value_fn(field->size,
+ field->is_signed);
+ if (!hist_field->fn) {
+@@ -917,6 +940,11 @@ static struct hist_field *parse_unary(st
+ expr->operands[0] = operand1;
+ expr->operator = FIELD_OP_UNARY_MINUS;
+ expr->name = expr_str(expr, 0);
++ expr->type = kstrdup(operand1->type, GFP_KERNEL);
++ if (!expr->type) {
++ ret = -ENOMEM;
++ goto free;
++ }
+
+ return expr;
+ free:
+@@ -1005,6 +1033,11 @@ static struct hist_field *parse_expr(str
+ expr->operands[1] = operand2;
+ expr->operator = field_op;
+ expr->name = expr_str(expr, 0);
++ expr->type = kstrdup(operand1->type, GFP_KERNEL);
++ if (!expr->type) {
++ ret = -ENOMEM;
++ goto free;
++ }
+
+ switch (field_op) {
+ case FIELD_OP_MINUS:
diff --git a/patches/0023-tracing-Add-onmatch-hist-trigger-action-support.patch b/patches/0023-tracing-Add-onmatch-hist-trigger-action-support.patch
deleted file mode 100644
index 8aa665e08a25..000000000000
--- a/patches/0023-tracing-Add-onmatch-hist-trigger-action-support.patch
+++ /dev/null
@@ -1,1268 +0,0 @@
-From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:24 -0500
-Subject: [PATCH 23/32] tracing: Add 'onmatch' hist trigger action support
-
-Add an 'onmatch(matching.event).<synthetic_event_name>(param list)'
-hist trigger action which is invoked with the set of variables or
-event fields named in the 'param list'. The result is the generation
-of a synthetic event that consists of the values contained in those
-variables and/or fields at the time the invoking event was hit.
-
-As an example the below defines a simple synthetic event using a
-variable defined on the sched_wakeup_new event, and shows the event
-definition with unresolved fields, since the sched_wakeup_new event
-with the testpid variable hasn't been defined yet:
-
- # echo 'wakeup_new_test pid_t pid; int prio' >> \
- /sys/kernel/debug/tracing/synthetic_events
-
- # cat /sys/kernel/debug/tracing/synthetic_events
- wakeup_new_test pid_t pid; int prio
-
-The following hist trigger both defines a testpid variable and
-specifies an onmatch() trace action that uses that variable along with
-a non-variable field to generate a wakeup_new_test synthetic event
-whenever a sched_wakeup_new event occurs, which because of the 'if
-comm == "cyclictest"' filter only happens when the executable is
-cyclictest:
-
- # echo 'hist:keys=testpid=pid:\
- onmatch(sched.sched_wakeup_new).wakeup_new_test($testpid, prio) \
- if comm=="cyclictest"' >> \
- /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/trigger
-
-Creating and displaying a histogram based on those events is now just
-a matter of using the fields and new synthetic event in the
-tracing/events/synthetic directory, as usual:
-
- # echo 'hist:keys=pid,prio:sort=pid,prio' >> \
- /sys/kernel/debug/tracing/events/synthetic/wakeup_new_test/trigger
-
-Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
----
- kernel/trace/trace_events_hist.c | 955 ++++++++++++++++++++++++++++++++++++++-
- 1 file changed, 940 insertions(+), 15 deletions(-)
-
---- a/kernel/trace/trace_events_hist.c
-+++ b/kernel/trace/trace_events_hist.c
-@@ -59,6 +59,7 @@ struct hist_field {
- unsigned int size;
- unsigned int offset;
- unsigned int is_signed;
-+ const char *type;
- struct hist_field *operands[HIST_FIELD_OPERANDS_MAX];
- struct hist_trigger_data *hist_data;
- struct hist_var var;
-@@ -243,6 +244,16 @@ struct hist_trigger_attrs {
- unsigned int n_actions;
- };
-
-+struct field_var {
-+ struct hist_field *var;
-+ struct hist_field *val;
-+};
-+
-+struct field_var_hist {
-+ struct hist_trigger_data *hist_data;
-+ char *cmd;
-+};
-+
- struct hist_trigger_data {
- struct hist_field *fields[HIST_FIELDS_MAX];
- unsigned int n_vals;
-@@ -263,6 +274,14 @@ struct hist_trigger_data {
-
- struct action_data *actions[HIST_ACTIONS_MAX];
- unsigned int n_actions;
-+
-+ struct hist_field *synth_var_refs[SYNTH_FIELDS_MAX];
-+ unsigned int n_synth_var_refs;
-+ struct field_var *field_vars[SYNTH_FIELDS_MAX];
-+ unsigned int n_field_vars;
-+ unsigned int n_field_var_str;
-+ struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX];
-+ unsigned int n_field_var_hists;
- };
-
- struct synth_field {
-@@ -291,7 +310,14 @@ typedef void (*action_fn_t) (struct hist
-
- struct action_data {
- action_fn_t fn;
-+ unsigned int n_params;
-+ char *params[SYNTH_FIELDS_MAX];
-+
- unsigned int var_ref_idx;
-+ char *match_event;
-+ char *match_event_system;
-+ char *synth_event_name;
-+ struct synth_event *synth_event;
- };
-
- static LIST_HEAD(synth_event_list);
-@@ -802,6 +828,50 @@ static struct synth_event *alloc_synth_e
- return event;
- }
-
-+static void action_trace(struct hist_trigger_data *hist_data,
-+ struct tracing_map_elt *elt, void *rec,
-+ struct ring_buffer_event *rbe,
-+ struct action_data *data, u64 *var_ref_vals)
-+{
-+ struct synth_event *event = data->synth_event;
-+
-+ trace_synth(event, var_ref_vals, data->var_ref_idx);
-+}
-+
-+static bool check_hist_action_refs(struct hist_trigger_data *hist_data,
-+ struct synth_event *event)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < hist_data->n_actions; i++) {
-+ struct action_data *data = hist_data->actions[i];
-+
-+ if (data->fn == action_trace && data->synth_event == event)
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+static LIST_HEAD(hist_action_list);
-+static LIST_HEAD(hist_var_list);
-+
-+struct hist_var_data {
-+ struct list_head list;
-+ struct hist_trigger_data *hist_data;
-+};
-+
-+static bool check_synth_action_refs(struct synth_event *event)
-+{
-+ struct hist_var_data *var_data;
-+
-+ list_for_each_entry(var_data, &hist_action_list, list)
-+ if (check_hist_action_refs(var_data->hist_data, event))
-+ return true;
-+
-+ return false;
-+}
-+
- static int create_synth_event(int argc, char **argv)
- {
- struct synth_field *fields[SYNTH_FIELDS_MAX];
-@@ -832,15 +902,17 @@ static int create_synth_event(int argc,
- event = find_synth_event(name);
- if (event) {
- if (delete_event) {
-+ if (check_synth_action_refs(event)) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
- remove_synth_event(event);
- goto err;
- } else
- ret = -EEXIST;
- goto out;
-- } else if (delete_event) {
-- ret = -EINVAL;
-+ } else if (delete_event)
- goto out;
-- }
-
- if (argc < 2) {
- ret = -EINVAL;
-@@ -891,11 +963,18 @@ static int release_all_synth_events(void
-
- mutex_lock(&synth_event_mutex);
-
-+ list_for_each_entry(event, &synth_event_list, list) {
-+ if (check_synth_action_refs(event)) {
-+ ret = -EBUSY;
-+ goto out;
-+ }
-+ }
-+
- list_for_each_entry_safe(event, e, &synth_event_list, list) {
- remove_synth_event(event);
- free_synth_event(event);
- }
--
-+ out:
- mutex_unlock(&synth_event_mutex);
-
- return ret;
-@@ -992,13 +1071,6 @@ static u64 hist_field_timestamp(struct h
- return ts;
- }
-
--static LIST_HEAD(hist_var_list);
--
--struct hist_var_data {
-- struct list_head list;
-- struct hist_trigger_data *hist_data;
--};
--
- static struct hist_field *check_var_ref(struct hist_field *hist_field,
- struct hist_trigger_data *var_data,
- unsigned int var_idx)
-@@ -1248,6 +1320,7 @@ static struct hist_field *find_event_var
- struct hist_elt_data {
- char *comm;
- u64 *var_ref_vals;
-+ char *field_var_str[SYNTH_FIELDS_MAX];
- };
-
- static u64 hist_field_var_ref(struct hist_field *hist_field,
-@@ -1415,11 +1488,21 @@ static void destroy_hist_trigger_attrs(s
-
- static int parse_action(char *str, struct hist_trigger_attrs *attrs)
- {
-- int ret = 0;
-+ int ret = -EINVAL;
-
- if (attrs->n_actions >= HIST_ACTIONS_MAX)
- return ret;
-
-+ if ((strncmp(str, "onmatch(", strlen("onmatch(")) == 0)) {
-+ attrs->action_str[attrs->n_actions] = kstrdup(str, GFP_KERNEL);
-+ if (!attrs->action_str[attrs->n_actions]) {
-+ ret = -ENOMEM;
-+ return ret;
-+ }
-+ attrs->n_actions++;
-+ ret = 0;
-+ }
-+
- return ret;
- }
-
-@@ -1525,7 +1608,14 @@ static inline void save_comm(char *comm,
-
- static void hist_trigger_elt_data_free(struct tracing_map_elt *elt)
- {
-+ struct hist_trigger_data *hist_data = elt->map->private_data;
- struct hist_elt_data *private_data = elt->private_data;
-+ unsigned int i, n_str;
-+
-+ n_str = hist_data->n_field_var_str;
-+
-+ for (i = 0; i < n_str; i++)
-+ kfree(private_data->field_var_str[i]);
-
- kfree(private_data->comm);
- kfree(private_data);
-@@ -1537,7 +1627,7 @@ static int hist_trigger_elt_data_alloc(s
- unsigned int size = TASK_COMM_LEN + 1;
- struct hist_elt_data *elt_data;
- struct hist_field *key_field;
-- unsigned int i;
-+ unsigned int i, n_str;
-
- elt->private_data = elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL);
- if (!elt_data)
-@@ -1557,6 +1647,16 @@ static int hist_trigger_elt_data_alloc(s
- }
- }
-
-+ n_str = hist_data->n_field_var_str;
-+
-+ for (i = 0; i < n_str; i++) {
-+ elt_data->field_var_str[i] = kzalloc(size, GFP_KERNEL);
-+ if (!elt_data->field_var_str[i]) {
-+ hist_trigger_elt_data_free(elt);
-+ return -ENOMEM;
-+ }
-+ }
-+
- return 0;
- }
-
-@@ -1674,6 +1774,7 @@ static void destroy_hist_field(struct hi
-
- kfree(hist_field->var.name);
- kfree(hist_field->name);
-+ kfree(hist_field->type);
-
- kfree(hist_field);
- }
-@@ -1704,6 +1805,10 @@ static struct hist_field *create_hist_fi
-
- if (flags & HIST_FIELD_FL_HITCOUNT) {
- hist_field->fn = hist_field_counter;
-+ hist_field->size = sizeof(u64);
-+ hist_field->type = kstrdup("u64", GFP_KERNEL);
-+ if (!hist_field->type)
-+ goto free;
- goto out;
- }
-
-@@ -1717,12 +1822,18 @@ static struct hist_field *create_hist_fi
- hist_field->fn = hist_field_log2;
- hist_field->operands[0] = create_hist_field(hist_data, field, fl, NULL);
- hist_field->size = hist_field->operands[0]->size;
-+ hist_field->type = kstrdup(hist_field->operands[0]->type, GFP_KERNEL);
-+ if (!hist_field->type)
-+ goto free;
- goto out;
- }
-
- if (flags & HIST_FIELD_FL_TIMESTAMP) {
- hist_field->fn = hist_field_timestamp;
- hist_field->size = sizeof(u64);
-+ hist_field->type = kstrdup("u64", GFP_KERNEL);
-+ if (!hist_field->type)
-+ goto free;
- goto out;
- }
-
-@@ -1731,6 +1842,10 @@ static struct hist_field *create_hist_fi
-
- if (is_string_field(field)) {
- flags |= HIST_FIELD_FL_STRING;
-+ hist_field->size = MAX_FILTER_STR_VAL;
-+ hist_field->type = kstrdup(field->type, GFP_KERNEL);
-+ if (!hist_field->type)
-+ goto free;
-
- if (field->filter_type == FILTER_STATIC_STRING)
- hist_field->fn = hist_field_string;
-@@ -1739,6 +1854,12 @@ static struct hist_field *create_hist_fi
- else
- hist_field->fn = hist_field_pstring;
- } else {
-+ hist_field->size = field->size;
-+ hist_field->is_signed = field->is_signed;
-+ hist_field->type = kstrdup(field->type, GFP_KERNEL);
-+ if (!hist_field->type)
-+ goto free;
-+
- hist_field->fn = select_value_fn(field->size,
- field->is_signed);
- if (!hist_field->fn) {
-@@ -1786,7 +1907,10 @@ static struct hist_field *create_var_ref
- ref_field->size = var_field->size;
- ref_field->is_signed = var_field->is_signed;
- ref_field->name = kstrdup(var_field->var.name, GFP_KERNEL);
-- if (!ref_field->name) {
-+ ref_field->type = kstrdup(var_field->type, GFP_KERNEL);
-+ if (!ref_field->name || !ref_field->type) {
-+ kfree(ref_field->name);
-+ kfree(ref_field->type);
- destroy_hist_field(ref_field, 0);
- return NULL;
- }
-@@ -1970,6 +2094,11 @@ static struct hist_field *parse_unary(st
- expr->operands[0] = operand1;
- expr->operator = FIELD_OP_UNARY_MINUS;
- expr->name = expr_str(expr, 0);
-+ expr->type = kstrdup(operand1->type, GFP_KERNEL);
-+ if (!expr->type) {
-+ ret = -ENOMEM;
-+ goto free;
-+ }
-
- return expr;
- free:
-@@ -2053,6 +2182,11 @@ static struct hist_field *parse_expr(str
- expr->operands[1] = operand2;
- expr->operator = field_op;
- expr->name = expr_str(expr, 0);
-+ expr->type = kstrdup(operand1->type, GFP_KERNEL);
-+ if (!expr->type) {
-+ ret = -ENOMEM;
-+ goto free;
-+ }
-
- switch (field_op) {
- case FIELD_OP_MINUS:
-@@ -2074,6 +2208,718 @@ static struct hist_field *parse_expr(str
- return ERR_PTR(ret);
- }
-
-+static struct hist_var_data *find_actions(struct hist_trigger_data *hist_data)
-+{
-+ struct hist_var_data *var_data, *found = NULL;
-+
-+ list_for_each_entry(var_data, &hist_action_list, list) {
-+ if (var_data->hist_data == hist_data) {
-+ found = var_data;
-+ break;
-+ }
-+ }
-+
-+ return found;
-+}
-+
-+static int save_hist_actions(struct hist_trigger_data *hist_data)
-+{
-+ struct hist_var_data *var_data;
-+
-+ var_data = find_actions(hist_data);
-+ if (var_data)
-+ return 0;
-+
-+ var_data = kzalloc(sizeof(*var_data), GFP_KERNEL);
-+ if (!var_data)
-+ return -ENOMEM;
-+
-+ var_data->hist_data = hist_data;
-+ list_add(&var_data->list, &hist_action_list);
-+
-+ return 0;
-+}
-+
-+static void remove_hist_actions(struct hist_trigger_data *hist_data)
-+{
-+ struct hist_var_data *var_data;
-+
-+ var_data = find_actions(hist_data);
-+ if (!var_data)
-+ return;
-+
-+ list_del(&var_data->list);
-+
-+ kfree(var_data);
-+}
-+
-+static char *find_trigger_filter(struct hist_trigger_data *hist_data,
-+ struct trace_event_file *file)
-+{
-+ struct event_trigger_data *test;
-+
-+ list_for_each_entry_rcu(test, &file->triggers, list) {
-+ if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
-+ if (test->private_data == hist_data)
-+ return test->filter_str;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+static struct event_command trigger_hist_cmd;
-+static int event_hist_trigger_func(struct event_command *cmd_ops,
-+ struct trace_event_file *file,
-+ char *glob, char *cmd, char *param);
-+
-+static bool compatible_keys(struct hist_trigger_data *target_hist_data,
-+ struct hist_trigger_data *hist_data,
-+ unsigned int n_keys)
-+{
-+ struct hist_field *target_hist_field, *hist_field;
-+ unsigned int n, i, j;
-+
-+ if (hist_data->n_fields - hist_data->n_vals != n_keys)
-+ return false;
-+
-+ i = hist_data->n_vals;
-+ j = target_hist_data->n_vals;
-+
-+ for (n = 0; n < n_keys; n++) {
-+ hist_field = hist_data->fields[i + n];
-+ target_hist_field = hist_data->fields[j + n];
-+
-+ if (strcmp(hist_field->type, target_hist_field->type) != 0)
-+ return false;
-+ if (hist_field->size != target_hist_field->size)
-+ return false;
-+ if (hist_field->is_signed != target_hist_field->is_signed)
-+ return false;
-+ }
-+
-+ return true;
-+}
-+
-+static struct hist_trigger_data *
-+find_compatible_hist(struct hist_trigger_data *target_hist_data,
-+ struct trace_event_file *file)
-+{
-+ struct hist_trigger_data *hist_data;
-+ struct event_trigger_data *test;
-+ unsigned int n_keys;
-+
-+ n_keys = target_hist_data->n_fields - target_hist_data->n_vals;
-+
-+ list_for_each_entry_rcu(test, &file->triggers, list) {
-+ if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
-+ hist_data = test->private_data;
-+
-+ if (compatible_keys(target_hist_data, hist_data, n_keys))
-+ return hist_data;
-+ }
-+ }
-+
-+ return NULL;
-+}
-+
-+static struct trace_event_file *event_file(char *system, char *event_name)
-+{
-+ struct trace_event_file *file;
-+ struct trace_array *tr;
-+
-+ tr = top_trace_array();
-+ if (!tr)
-+ return ERR_PTR(-ENODEV);
-+
-+ file = find_event_file(tr, system, event_name);
-+ if (!file)
-+ return ERR_PTR(-EINVAL);
-+
-+ return file;
-+}
-+
-+static struct hist_field *
-+create_field_var_hist(struct hist_trigger_data *target_hist_data,
-+ char *system, char *event_name, char *field_name)
-+{
-+ struct hist_field *event_var = ERR_PTR(-EINVAL);
-+ struct hist_trigger_data *hist_data;
-+ unsigned int i, n, first = true;
-+ struct field_var_hist *var_hist;
-+ struct trace_event_file *file;
-+ struct hist_field *key_field;
-+ struct trace_array *tr;
-+ char *saved_filter;
-+ char *cmd;
-+ int ret;
-+
-+ if (target_hist_data->n_field_var_hists >= SYNTH_FIELDS_MAX)
-+ return ERR_PTR(-EINVAL);
-+
-+ tr = top_trace_array();
-+ if (!tr)
-+ return ERR_PTR(-ENODEV);
-+
-+ file = event_file(system, event_name);
-+ if (IS_ERR(file)) {
-+ ret = PTR_ERR(file);
-+ return ERR_PTR(ret);
-+ }
-+
-+ hist_data = find_compatible_hist(target_hist_data, file);
-+ if (!hist_data)
-+ return ERR_PTR(-EINVAL);
-+
-+ var_hist = kzalloc(sizeof(*var_hist), GFP_KERNEL);
-+ if (!var_hist)
-+ return ERR_PTR(-ENOMEM);
-+
-+ cmd = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
-+ if (!cmd) {
-+ kfree(var_hist);
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ strcat(cmd, "keys=");
-+
-+ for_each_hist_key_field(i, hist_data) {
-+ key_field = hist_data->fields[i];
-+ if (!first)
-+ strcat(cmd, ",");
-+ strcat(cmd, key_field->field->name);
-+ first = false;
-+ }
-+
-+ strcat(cmd, ":synthetic_");
-+ strcat(cmd, field_name);
-+ strcat(cmd, "=");
-+ strcat(cmd, field_name);
-+
-+ saved_filter = find_trigger_filter(hist_data, file);
-+ if (saved_filter) {
-+ strcat(cmd, " if ");
-+ strcat(cmd, saved_filter);
-+ }
-+
-+ var_hist->cmd = kstrdup(cmd, GFP_KERNEL);
-+ if (!var_hist->cmd) {
-+ kfree(cmd);
-+ kfree(var_hist);
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ var_hist->hist_data = hist_data;
-+
-+ ret = event_hist_trigger_func(&trigger_hist_cmd, file,
-+ "", "hist", cmd);
-+ if (ret) {
-+ kfree(cmd);
-+ kfree(var_hist->cmd);
-+ kfree(var_hist);
-+ return ERR_PTR(ret);
-+ }
-+
-+ strcpy(cmd, "synthetic_");
-+ strcat(cmd, field_name);
-+
-+ event_var = find_event_var(system, event_name, cmd);
-+ if (!event_var) {
-+ kfree(cmd);
-+ kfree(var_hist->cmd);
-+ kfree(var_hist);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ n = target_hist_data->n_field_var_hists;
-+ target_hist_data->field_var_hists[n] = var_hist;
-+ target_hist_data->n_field_var_hists++;
-+
-+ return event_var;
-+}
-+
-+static struct hist_field *
-+find_target_event_var(struct hist_trigger_data *hist_data,
-+ char *system, char *event_name, char *var_name)
-+{
-+ struct trace_event_file *file = hist_data->event_file;
-+ struct hist_field *hist_field = NULL;
-+
-+ if (system) {
-+ struct trace_event_call *call;
-+
-+ if (!event_name)
-+ return NULL;
-+
-+ call = file->event_call;
-+
-+ if (strcmp(system, call->class->system) != 0)
-+ return NULL;
-+
-+ if (strcmp(event_name, trace_event_name(call)) != 0)
-+ return NULL;
-+ }
-+
-+ hist_field = find_var_field(hist_data, var_name);
-+
-+ return hist_field;
-+}
-+
-+static inline void __update_field_vars(struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *rec,
-+ struct field_var **field_vars,
-+ unsigned int n_field_vars,
-+ unsigned int field_var_str_start)
-+{
-+ struct hist_elt_data *elt_data = elt->private_data;
-+ unsigned int i, j, var_idx;
-+ u64 var_val;
-+
-+ for (i = 0, j = field_var_str_start; i < n_field_vars; i++) {
-+ struct field_var *field_var = field_vars[i];
-+ struct hist_field *var = field_var->var;
-+ struct hist_field *val = field_var->val;
-+
-+ var_val = val->fn(val, elt, rbe, rec);
-+ var_idx = var->var.idx;
-+
-+ if (val->flags & HIST_FIELD_FL_STRING) {
-+ char *str = elt_data->field_var_str[j++];
-+
-+ memcpy(str, (char *)(uintptr_t)var_val,
-+ TASK_COMM_LEN + 1);
-+ var_val = (u64)(uintptr_t)str;
-+ }
-+ tracing_map_set_var(elt, var_idx, var_val);
-+ }
-+}
-+
-+static void update_field_vars(struct hist_trigger_data *hist_data,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *rec)
-+{
-+ __update_field_vars(elt, rbe, rec, hist_data->field_vars,
-+ hist_data->n_field_vars, 0);
-+}
-+
-+static struct hist_field *create_var(struct hist_trigger_data *hist_data,
-+ struct trace_event_file *file,
-+ char *name, int size, const char *type)
-+{
-+ struct hist_field *var;
-+ int idx;
-+
-+ if (find_var(file, name) && !hist_data->remove) {
-+ var = ERR_PTR(-EINVAL);
-+ goto out;
-+ }
-+
-+ var = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
-+ if (!var) {
-+ var = ERR_PTR(-ENOMEM);
-+ goto out;
-+ }
-+
-+ idx = tracing_map_add_var(hist_data->map);
-+ if (idx < 0) {
-+ kfree(var);
-+ var = ERR_PTR(-EINVAL);
-+ goto out;
-+ }
-+
-+ var->flags = HIST_FIELD_FL_VAR;
-+ var->var.idx = idx;
-+ var->var.hist_data = var->hist_data = hist_data;
-+ var->size = size;
-+ var->var.name = kstrdup(name, GFP_KERNEL);
-+ var->type = kstrdup(type, GFP_KERNEL);
-+ if (!var->var.name || !var->type) {
-+ kfree(var->var.name);
-+ kfree(var->type);
-+ kfree(var);
-+ var = ERR_PTR(-ENOMEM);
-+ }
-+ out:
-+ return var;
-+}
-+
-+static struct field_var *create_field_var(struct hist_trigger_data *hist_data,
-+ struct trace_event_file *file,
-+ char *field_name)
-+{
-+ struct hist_field *val = NULL, *var = NULL;
-+ unsigned long flags = HIST_FIELD_FL_VAR;
-+ struct field_var *field_var;
-+ int ret = 0;
-+
-+ if (hist_data->n_field_vars >= SYNTH_FIELDS_MAX) {
-+ ret = -EINVAL;
-+ goto err;
-+ }
-+
-+ val = parse_atom(hist_data, file, field_name, &flags, NULL);
-+ if (IS_ERR(val)) {
-+ ret = PTR_ERR(val);
-+ goto err;
-+ }
-+
-+ var = create_var(hist_data, file, field_name, val->size, val->type);
-+ if (IS_ERR(var)) {
-+ kfree(val);
-+ ret = PTR_ERR(var);
-+ goto err;
-+ }
-+
-+ field_var = kzalloc(sizeof(struct field_var), GFP_KERNEL);
-+ if (!field_var) {
-+ kfree(val);
-+ kfree(var);
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+
-+ field_var->var = var;
-+ field_var->val = val;
-+ out:
-+ return field_var;
-+ err:
-+ field_var = ERR_PTR(ret);
-+ goto out;
-+}
-+
-+static struct field_var *
-+create_target_field_var(struct hist_trigger_data *hist_data,
-+ char *system, char *event_name, char *var_name)
-+{
-+ struct trace_event_file *file = hist_data->event_file;
-+
-+ if (system) {
-+ struct trace_event_call *call;
-+
-+ if (!event_name)
-+ return NULL;
-+
-+ call = file->event_call;
-+
-+ if (strcmp(system, call->class->system) != 0)
-+ return NULL;
-+
-+ if (strcmp(event_name, trace_event_name(call)) != 0)
-+ return NULL;
-+ }
-+
-+ return create_field_var(hist_data, file, var_name);
-+}
-+
-+static void onmatch_destroy(struct action_data *data)
-+{
-+ unsigned int i;
-+
-+ kfree(data->match_event);
-+ kfree(data->match_event_system);
-+ kfree(data->synth_event_name);
-+
-+ for (i = 0; i < data->n_params; i++)
-+ kfree(data->params[i]);
-+
-+ kfree(data);
-+}
-+
-+static void destroy_field_var(struct field_var *field_var)
-+{
-+ if (!field_var)
-+ return;
-+
-+ destroy_hist_field(field_var->var, 0);
-+ destroy_hist_field(field_var->val, 0);
-+
-+ kfree(field_var);
-+}
-+
-+static void destroy_field_vars(struct hist_trigger_data *hist_data)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < hist_data->n_field_vars; i++)
-+ destroy_field_var(hist_data->field_vars[i]);
-+}
-+
-+static void save_field_var(struct hist_trigger_data *hist_data,
-+ struct field_var *field_var)
-+{
-+ hist_data->field_vars[hist_data->n_field_vars++] = field_var;
-+
-+ if (field_var->val->flags & HIST_FIELD_FL_STRING)
-+ hist_data->n_field_var_str++;
-+}
-+
-+static void destroy_synth_var_refs(struct hist_trigger_data *hist_data)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < hist_data->n_synth_var_refs; i++)
-+ destroy_hist_field(hist_data->synth_var_refs[i], 0);
-+}
-+
-+static void save_synth_var_ref(struct hist_trigger_data *hist_data,
-+ struct hist_field *var_ref)
-+{
-+ hist_data->synth_var_refs[hist_data->n_synth_var_refs++] = var_ref;
-+
-+ hist_data->var_refs[hist_data->n_var_refs] = var_ref;
-+ var_ref->var_ref_idx = hist_data->n_var_refs++;
-+}
-+
-+static int check_synth_field(struct synth_event *event,
-+ struct hist_field *hist_field,
-+ unsigned int field_pos)
-+{
-+ struct synth_field *field;
-+
-+ if (field_pos >= event->n_fields)
-+ return -EINVAL;
-+
-+ field = event->fields[field_pos];
-+
-+ if (strcmp(field->type, hist_field->type) != 0)
-+ return -EINVAL;
-+
-+ return 0;
-+}
-+
-+static int parse_action_params(char *params, struct action_data *data)
-+{
-+ char *param, *saved_param;
-+ int ret = 0;
-+
-+ while (params) {
-+ if (data->n_params >= SYNTH_FIELDS_MAX)
-+ goto out;
-+
-+ param = strsep(&params, ",");
-+ if (!param)
-+ goto out;
-+
-+ param = strstrip(param);
-+ if (strlen(param) < 2) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ saved_param = kstrdup(param, GFP_KERNEL);
-+ if (!saved_param) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ data->params[data->n_params++] = saved_param;
-+ }
-+ out:
-+ return ret;
-+}
-+
-+static struct hist_field *
-+onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data,
-+ char *system, char *event, char *var)
-+{
-+ struct hist_field *hist_field;
-+
-+ var++; /* skip '$' */
-+
-+ hist_field = find_target_event_var(hist_data, system, event, var);
-+ if (!hist_field) {
-+ if (!system) {
-+ system = data->match_event_system;
-+ event = data->match_event;
-+ }
-+
-+ hist_field = find_event_var(system, event, var);
-+ }
-+
-+ return hist_field;
-+}
-+
-+static struct hist_field *
-+onmatch_create_field_var(struct hist_trigger_data *hist_data,
-+ struct action_data *data, char *system,
-+ char *event, char *var)
-+{
-+ struct hist_field *hist_field = NULL;
-+ struct field_var *field_var;
-+
-+ field_var = create_target_field_var(hist_data, system, event, var);
-+ if (IS_ERR(field_var))
-+ goto out;
-+
-+ if (field_var) {
-+ save_field_var(hist_data, field_var);
-+ hist_field = field_var->var;
-+ } else {
-+ if (!system) {
-+ system = data->match_event_system;
-+ event = data->match_event;
-+ }
-+
-+ hist_field = create_field_var_hist(hist_data, system, event, var);
-+ if (IS_ERR(hist_field))
-+ goto free;
-+ }
-+ out:
-+ return hist_field;
-+ free:
-+ destroy_field_var(field_var);
-+ hist_field = NULL;
-+ goto out;
-+}
-+
-+static int onmatch_create(struct hist_trigger_data *hist_data,
-+ struct trace_event_file *file,
-+ struct action_data *data)
-+{
-+ char *event_name, *param, *system = NULL;
-+ struct hist_field *hist_field, *var_ref;
-+ unsigned int i, var_ref_idx;
-+ unsigned int field_pos = 0;
-+ struct synth_event *event;
-+ int ret = 0;
-+
-+ mutex_lock(&synth_event_mutex);
-+
-+ event = find_synth_event(data->synth_event_name);
-+ if (!event) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ var_ref_idx = hist_data->n_var_refs;
-+
-+ for (i = 0; i < data->n_params; i++) {
-+ char *p;
-+
-+ p = param = kstrdup(data->params[i], GFP_KERNEL);
-+ if (!param)
-+ goto out;
-+
-+ system = strsep(&param, ".");
-+ if (!param) {
-+ param = (char *)system;
-+ system = event_name = NULL;
-+ } else {
-+ event_name = strsep(&param, ".");
-+ if (!param) {
-+ kfree(p);
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+ }
-+
-+ if (param[0] == '$')
-+ hist_field = onmatch_find_var(hist_data, data, system,
-+ event_name, param);
-+ else
-+ hist_field = onmatch_create_field_var(hist_data, data,
-+ system,
-+ event_name,
-+ param);
-+
-+ if (!hist_field) {
-+ kfree(p);
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (check_synth_field(event, hist_field, field_pos) == 0) {
-+ var_ref = create_var_ref(hist_field);
-+ if (!var_ref) {
-+ kfree(p);
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ save_synth_var_ref(hist_data, var_ref);
-+ field_pos++;
-+ kfree(p);
-+ continue;
-+ }
-+
-+ kfree(p);
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ if (field_pos != event->n_fields) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ data->fn = action_trace;
-+ data->synth_event = event;
-+ data->var_ref_idx = var_ref_idx;
-+ hist_data->actions[hist_data->n_actions++] = data;
-+ save_hist_actions(hist_data);
-+ out:
-+ mutex_unlock(&synth_event_mutex);
-+
-+ return ret;
-+}
-+
-+static struct action_data *onmatch_parse(char *str)
-+{
-+ char *match_event, *match_event_system;
-+ char *synth_event_name, *params;
-+ struct action_data *data;
-+ int ret = -EINVAL;
-+
-+ data = kzalloc(sizeof(*data), GFP_KERNEL);
-+ if (!data)
-+ return ERR_PTR(-ENOMEM);
-+
-+ match_event = strsep(&str, ")");
-+ if (!match_event || !str)
-+ goto free;
-+
-+ match_event_system = strsep(&match_event, ".");
-+ if (!match_event)
-+ goto free;
-+
-+ if (IS_ERR(event_file(match_event_system, match_event)))
-+ goto free;
-+
-+ data->match_event = kstrdup(match_event, GFP_KERNEL);
-+ data->match_event_system = kstrdup(match_event_system, GFP_KERNEL);
-+
-+ strsep(&str, ".");
-+ if (!str)
-+ goto free;
-+
-+ synth_event_name = strsep(&str, "(");
-+ if (!synth_event_name || !str)
-+ goto free;
-+ data->synth_event_name = kstrdup(synth_event_name, GFP_KERNEL);
-+
-+ params = strsep(&str, ")");
-+ if (!params || !str || (str && strlen(str)))
-+ goto free;
-+
-+ ret = parse_action_params(params, data);
-+ if (ret)
-+ goto free;
-+
-+ if (!data->match_event_system || !data->match_event ||
-+ !data->synth_event_name) {
-+ ret = -ENOMEM;
-+ goto free;
-+ }
-+ out:
-+ return data;
-+ free:
-+ onmatch_destroy(data);
-+ data = ERR_PTR(ret);
-+ goto out;
-+}
-+
- static int create_hitcount_val(struct hist_trigger_data *hist_data)
- {
- hist_data->fields[HITCOUNT_IDX] =
-@@ -2465,19 +3311,37 @@ static void destroy_actions(struct hist_
- for (i = 0; i < hist_data->n_actions; i++) {
- struct action_data *data = hist_data->actions[i];
-
-- kfree(data);
-+ if (data->fn == action_trace)
-+ onmatch_destroy(data);
-+ else
-+ kfree(data);
- }
- }
-
- static int create_actions(struct hist_trigger_data *hist_data,
- struct trace_event_file *file)
- {
-+ struct action_data *data;
- unsigned int i;
- int ret = 0;
- char *str;
-
- for (i = 0; i < hist_data->attrs->n_actions; i++) {
- str = hist_data->attrs->action_str[i];
-+
-+ if (strncmp(str, "onmatch(", strlen("onmatch(")) == 0) {
-+ char *action_str = str + strlen("onmatch(");
-+
-+ data = onmatch_parse(action_str);
-+ if (IS_ERR(data))
-+ return PTR_ERR(data);
-+
-+ ret = onmatch_create(hist_data, file, data);
-+ if (ret) {
-+ onmatch_destroy(data);
-+ return ret;
-+ }
-+ }
- }
-
- return ret;
-@@ -2494,6 +3358,26 @@ static void print_actions(struct seq_fil
- }
- }
-
-+static void print_onmatch_spec(struct seq_file *m,
-+ struct hist_trigger_data *hist_data,
-+ struct action_data *data)
-+{
-+ unsigned int i;
-+
-+ seq_printf(m, ":onmatch(%s.%s).", data->match_event_system,
-+ data->match_event);
-+
-+ seq_printf(m, "%s(", data->synth_event->name);
-+
-+ for (i = 0; i < data->n_params; i++) {
-+ if (i)
-+ seq_puts(m, ",");
-+ seq_printf(m, "%s", data->params[i]);
-+ }
-+
-+ seq_puts(m, ")");
-+}
-+
- static void print_actions_spec(struct seq_file *m,
- struct hist_trigger_data *hist_data)
- {
-@@ -2501,6 +3385,19 @@ static void print_actions_spec(struct se
-
- for (i = 0; i < hist_data->n_actions; i++) {
- struct action_data *data = hist_data->actions[i];
-+
-+ if (data->fn == action_trace)
-+ print_onmatch_spec(m, hist_data, data);
-+ }
-+}
-+
-+static void destroy_field_var_hists(struct hist_trigger_data *hist_data)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < hist_data->n_field_var_hists; i++) {
-+ kfree(hist_data->field_var_hists[i]->cmd);
-+ kfree(hist_data->field_var_hists[i]);
- }
- }
-
-@@ -2514,6 +3411,9 @@ static void destroy_hist_data(struct his
- tracing_map_destroy(hist_data->map);
-
- destroy_actions(hist_data);
-+ destroy_field_vars(hist_data);
-+ destroy_field_var_hists(hist_data);
-+ destroy_synth_var_refs(hist_data);
-
- kfree(hist_data);
- }
-@@ -2648,6 +3548,8 @@ static void hist_trigger_elt_update(stru
- tracing_map_set_var(elt, var_idx, hist_val);
- }
- }
-+
-+ update_field_vars(hist_data, elt, rbe, rec);
- }
-
- static inline void add_to_key(char *compound_key, void *key,
-@@ -2861,6 +3763,8 @@ hist_trigger_entry_print(struct seq_file
- }
- }
-
-+ print_actions(m, hist_data, elt);
-+
- seq_puts(m, "\n");
- }
-
-@@ -3128,6 +4032,8 @@ static void event_hist_trigger_free(stru
-
- remove_hist_vars(hist_data);
-
-+ remove_hist_actions(hist_data);
-+
- destroy_hist_data(hist_data);
- }
- }
-@@ -3390,6 +4296,21 @@ static bool hist_trigger_check_refs(stru
- return false;
- }
-
-+static void unregister_field_var_hists(struct hist_trigger_data *hist_data)
-+{
-+ struct trace_event_file *file;
-+ unsigned int i;
-+ char *cmd;
-+ int ret;
-+
-+ for (i = 0; i < hist_data->n_field_var_hists; i++) {
-+ file = hist_data->field_var_hists[i]->hist_data->event_file;
-+ cmd = hist_data->field_var_hists[i]->cmd;
-+ ret = event_hist_trigger_func(&trigger_hist_cmd, file,
-+ "!hist", "hist", cmd);
-+ }
-+}
-+
- static void hist_unregister_trigger(char *glob, struct event_trigger_ops *ops,
- struct event_trigger_data *data,
- struct trace_event_file *file)
-@@ -3405,6 +4326,7 @@ static void hist_unregister_trigger(char
- if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
- if (!hist_trigger_match(data, test, named_data, false))
- continue;
-+ unregister_field_var_hists(test->private_data);
- unregistered = true;
- list_del_rcu(&test->list);
- trace_event_trigger_enable_disable(file, 0);
-@@ -3448,6 +4370,7 @@ static void hist_unreg_all(struct trace_
-
- list_for_each_entry_safe(test, n, &file->triggers, list) {
- if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
-+ unregister_field_var_hists(test->private_data);
- list_del_rcu(&test->list);
- trace_event_trigger_enable_disable(file, 0);
- update_cond_flag(file);
-@@ -3571,6 +4494,8 @@ static int event_hist_trigger_func(struc
-
- remove_hist_vars(hist_data);
-
-+ remove_hist_actions(hist_data);
-+
- kfree(trigger_data);
- destroy_hist_data(hist_data);
-
diff --git a/patches/0019-tracing-Add-variable-reference-handling-to-hist-trig.patch b/patches/0024-tracing-Add-variable-reference-handling-to-hist-trig.patch
index 558d2c2ffd0b..6576aeb1de12 100644
--- a/patches/0019-tracing-Add-variable-reference-handling-to-hist-trig.patch
+++ b/patches/0024-tracing-Add-variable-reference-handling-to-hist-trig.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:20 -0500
-Subject: [PATCH 19/32] tracing: Add variable reference handling to hist
+Date: Tue, 5 Sep 2017 16:57:36 -0500
+Subject: [PATCH 24/40] tracing: Add variable reference handling to hist
triggers
Add the necessary infrastructure to allow the variables defined on one
@@ -24,14 +24,41 @@ be displayed in a latency histogram.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/trace.h | 2
- kernel/trace/trace_events_hist.c | 719 +++++++++++++++++++++++++++++-------
+ kernel/trace/trace.c | 2
+ kernel/trace/trace.h | 3
+ kernel/trace/trace_events_hist.c | 606 ++++++++++++++++++++++++++++++++----
kernel/trace/trace_events_trigger.c | 6
- 3 files changed, 604 insertions(+), 123 deletions(-)
+ 4 files changed, 561 insertions(+), 56 deletions(-)
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -7380,6 +7380,7 @@ static int instance_mkdir(const char *na
+
+ INIT_LIST_HEAD(&tr->systems);
+ INIT_LIST_HEAD(&tr->events);
++ INIT_LIST_HEAD(&tr->hist_vars);
+
+ if (allocate_trace_buffers(tr, trace_buf_size) < 0)
+ goto out_free_tr;
+@@ -8112,6 +8113,7 @@ ssize_t trace_parse_run_command(struct f
+
+ INIT_LIST_HEAD(&global_trace.systems);
+ INIT_LIST_HEAD(&global_trace.events);
++ INIT_LIST_HEAD(&global_trace.hist_vars);
+ list_add(&global_trace.list, &ftrace_trace_arrays);
+
+ apply_trace_boot_options();
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
-@@ -1448,6 +1448,8 @@ extern void pause_named_trigger(struct e
+@@ -266,6 +266,7 @@ struct trace_array {
+ int function_enabled;
+ #endif
+ int time_stamp_abs_ref;
++ struct list_head hist_vars;
+ };
+
+ enum {
+@@ -1442,6 +1443,8 @@ extern void pause_named_trigger(struct e
extern void unpause_named_trigger(struct event_trigger_data *data);
extern void set_named_trigger_data(struct event_trigger_data *data,
struct event_trigger_data *named_data);
@@ -42,20 +69,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
extern int register_trigger_hist_enable_disable_cmds(void);
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -26,8 +26,10 @@
-
- struct hist_field;
-
--typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event,
-- struct ring_buffer_event *rbe);
-+typedef u64 (*hist_field_fn_t) (struct hist_field *field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event);
-
- #define HIST_FIELD_OPERANDS_MAX 2
- #define HIST_FIELDS_MAX (TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX)
-@@ -57,30 +59,41 @@ struct hist_field {
+@@ -60,6 +60,9 @@ struct hist_field {
struct hist_var var;
enum field_op_id operator;
char *name;
@@ -64,149 +78,16 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ bool read_once;
};
--static u64 hist_field_none(struct hist_field *field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_none(struct hist_field *field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- return 0;
- }
-
--static u64 hist_field_counter(struct hist_field *field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_counter(struct hist_field *field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- return 1;
- }
-
--static u64 hist_field_string(struct hist_field *hist_field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_string(struct hist_field *hist_field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- char *addr = (char *)(event + hist_field->field->offset);
-
- return (u64)(unsigned long)addr;
- }
-
--static u64 hist_field_dynstring(struct hist_field *hist_field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_dynstring(struct hist_field *hist_field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- u32 str_item = *(u32 *)(event + hist_field->field->offset);
- int str_loc = str_item & 0xffff;
-@@ -89,54 +102,64 @@ static u64 hist_field_dynstring(struct h
- return (u64)(unsigned long)addr;
- }
-
--static u64 hist_field_pstring(struct hist_field *hist_field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_pstring(struct hist_field *hist_field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- char **addr = (char **)(event + hist_field->field->offset);
-
- return (u64)(unsigned long)*addr;
- }
-
--static u64 hist_field_log2(struct hist_field *hist_field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_log2(struct hist_field *hist_field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- struct hist_field *operand = hist_field->operands[0];
-
-- u64 val = operand->fn(operand, event, rbe);
-+ u64 val = operand->fn(operand, elt, rbe, event);
-
- return (u64) ilog2(roundup_pow_of_two(val));
- }
-
--static u64 hist_field_plus(struct hist_field *hist_field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_plus(struct hist_field *hist_field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- struct hist_field *operand1 = hist_field->operands[0];
- struct hist_field *operand2 = hist_field->operands[1];
-
-- u64 val1 = operand1->fn(operand1, event, rbe);
-- u64 val2 = operand2->fn(operand2, event, rbe);
-+ u64 val1 = operand1->fn(operand1, elt, rbe, event);
-+ u64 val2 = operand2->fn(operand2, elt, rbe, event);
-
- return val1 + val2;
- }
-
--static u64 hist_field_minus(struct hist_field *hist_field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_minus(struct hist_field *hist_field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- struct hist_field *operand1 = hist_field->operands[0];
- struct hist_field *operand2 = hist_field->operands[1];
-
-- u64 val1 = operand1->fn(operand1, event, rbe);
-- u64 val2 = operand2->fn(operand2, event, rbe);
-+ u64 val1 = operand1->fn(operand1, elt, rbe, event);
-+ u64 val2 = operand2->fn(operand2, elt, rbe, event);
-
- return val1 - val2;
- }
-
--static u64 hist_field_unary_minus(struct hist_field *hist_field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_unary_minus(struct hist_field *hist_field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- struct hist_field *operand = hist_field->operands[0];
-
-- s64 sval = (s64)operand->fn(operand, event, rbe);
-+ s64 sval = (s64)operand->fn(operand, elt, rbe, event);
- u64 val = (u64)-sval;
-
- return val;
-@@ -144,8 +167,9 @@ static u64 hist_field_unary_minus(struct
-
- #define DEFINE_HIST_FIELD_FN(type) \
- static u64 hist_field_##type(struct hist_field *hist_field, \
-- void *event, \
-- struct ring_buffer_event *rbe) \
-+ struct tracing_map_elt *elt, \
-+ struct ring_buffer_event *rbe, \
-+ void *event) \
- { \
- type *addr = (type *)(event + hist_field->field->offset); \
- \
-@@ -193,6 +217,7 @@ enum hist_field_flags {
+ static u64 hist_field_none(struct hist_field *field,
+@@ -215,6 +218,7 @@ enum hist_field_flags {
HIST_FIELD_FL_VAR = 4096,
HIST_FIELD_FL_VAR_ONLY = 8192,
HIST_FIELD_FL_EXPR = 16384,
+ HIST_FIELD_FL_VAR_REF = 32768,
};
- struct hist_trigger_attrs {
-@@ -225,10 +250,14 @@ struct hist_trigger_data {
+ struct var_defs {
+@@ -255,6 +259,8 @@ struct hist_trigger_data {
struct tracing_map *map;
bool enable_timestamps;
bool remove;
@@ -214,21 +95,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ unsigned int n_var_refs;
};
--static u64 hist_field_timestamp(struct hist_field *hist_field, void *event,
-- struct ring_buffer_event *rbe)
-+static u64 hist_field_timestamp(struct hist_field *hist_field,
-+ struct tracing_map_elt *elt,
-+ struct ring_buffer_event *rbe,
-+ void *event)
- {
- struct hist_trigger_data *hist_data = hist_field->hist_data;
- struct trace_array *tr = hist_data->event_file->tr;
-@@ -241,6 +270,324 @@ static u64 hist_field_timestamp(struct h
+ static u64 hist_field_timestamp(struct hist_field *hist_field,
+@@ -273,10 +279,344 @@ static u64 hist_field_timestamp(struct h
return ts;
}
-+static LIST_HEAD(hist_var_list);
-+
+struct hist_var_data {
+ struct list_head list;
+ struct hist_trigger_data *hist_data;
@@ -279,10 +150,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+static struct hist_field *find_any_var_ref(struct hist_trigger_data *hist_data,
+ unsigned int var_idx)
+{
++ struct trace_array *tr = hist_data->event_file->tr;
+ struct hist_field *found = NULL;
+ struct hist_var_data *var_data;
+
-+ list_for_each_entry(var_data, &hist_var_list, list) {
++ list_for_each_entry(var_data, &tr->hist_vars, list) {
+ found = find_var_ref(var_data->hist_data, hist_data, var_idx);
+ if (found)
+ break;
@@ -312,9 +184,10 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+static struct hist_var_data *find_hist_vars(struct hist_trigger_data *hist_data)
+{
++ struct trace_array *tr = hist_data->event_file->tr;
+ struct hist_var_data *var_data, *found = NULL;
+
-+ list_for_each_entry(var_data, &hist_var_list, list) {
++ list_for_each_entry(var_data, &tr->hist_vars, list) {
+ if (var_data->hist_data == hist_data) {
+ found = var_data;
+ break;
@@ -327,40 +200,56 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+static bool has_hist_vars(struct hist_trigger_data *hist_data)
+{
+ struct hist_field *hist_field;
-+ bool found = false;
-+ int i;
++ int i, j;
+
+ for_each_hist_field(i, hist_data) {
+ hist_field = hist_data->fields[i];
-+ if (hist_field && hist_field->flags & HIST_FIELD_FL_VAR) {
-+ found = true;
-+ break;
++ if (hist_field &&
++ (hist_field->flags & HIST_FIELD_FL_VAR ||
++ hist_field->flags & HIST_FIELD_FL_VAR_REF))
++ return true;
++
++ for (j = 0; j < HIST_FIELD_OPERANDS_MAX; j++) {
++ struct hist_field *operand;
++
++ operand = hist_field->operands[j];
++ if (operand &&
++ (operand->flags & HIST_FIELD_FL_VAR ||
++ operand->flags & HIST_FIELD_FL_VAR_REF))
++ return true;
+ }
+ }
+
-+ return found;
++ return false;
+}
+
+static int save_hist_vars(struct hist_trigger_data *hist_data)
+{
++ struct trace_array *tr = hist_data->event_file->tr;
+ struct hist_var_data *var_data;
+
+ var_data = find_hist_vars(hist_data);
+ if (var_data)
+ return 0;
+
++ if (trace_array_get(tr) < 0)
++ return -ENODEV;
++
+ var_data = kzalloc(sizeof(*var_data), GFP_KERNEL);
-+ if (!var_data)
++ if (!var_data) {
++ trace_array_put(tr);
+ return -ENOMEM;
++ }
+
+ var_data->hist_data = hist_data;
-+ list_add(&var_data->list, &hist_var_list);
++ list_add(&var_data->list, &tr->hist_vars);
+
+ return 0;
+}
+
+static void remove_hist_vars(struct hist_trigger_data *hist_data)
+{
++ struct trace_array *tr = hist_data->event_file->tr;
+ struct hist_var_data *var_data;
+
+ var_data = find_hist_vars(hist_data);
@@ -373,6 +262,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ list_del(&var_data->list);
+
+ kfree(var_data);
++
++ trace_array_put(tr);
+}
+
+static struct hist_field *find_var_field(struct hist_trigger_data *hist_data,
@@ -412,7 +303,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return NULL;
+}
+
-+static struct trace_event_file *find_var_file(const char *system,
++static struct trace_event_file *find_var_file(struct trace_array *tr,
++ const char *system,
+ const char *event_name,
+ const char *var_name)
+{
@@ -422,7 +314,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct trace_event_file *file;
+ const char *name;
+
-+ list_for_each_entry(var_data, &hist_var_list, list) {
++ list_for_each_entry(var_data, &tr->hist_vars, list) {
+ var_hist_data = var_data->hist_data;
+ file = var_hist_data->event_file;
+ call = file->event_call;
@@ -464,14 +356,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return NULL;
+}
+
-+static struct hist_field *find_event_var(const char *system,
++static struct hist_field *find_event_var(struct trace_array *tr,
++ const char *system,
+ const char *event_name,
+ const char *var_name)
+{
+ struct hist_field *hist_field = NULL;
+ struct trace_event_file *file;
+
-+ file = find_var_file(system, event_name, var_name);
++ file = find_var_file(tr, system, event_name, var_name);
+ if (!file)
+ return NULL;
+
@@ -480,11 +373,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return hist_field;
+}
+
-+struct hist_elt_data {
-+ char *comm;
+ struct hist_elt_data {
+ char *comm;
+ u64 *var_ref_vals;
-+};
-+
+ };
+
+static u64 hist_field_var_ref(struct hist_field *hist_field,
+ struct tracing_map_elt *elt,
+ struct ring_buffer_event *rbe,
@@ -548,7 +441,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static const char *hist_field_name(struct hist_field *field,
unsigned int level)
{
-@@ -255,7 +602,8 @@ static const char *hist_field_name(struc
+@@ -291,7 +631,8 @@ static const char *hist_field_name(struc
field_name = hist_field_name(field->operands[0], ++level);
else if (field->flags & HIST_FIELD_FL_TIMESTAMP)
field_name = "$common_timestamp";
@@ -558,115 +451,25 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
field_name = field->name;
if (field_name == NULL)
-@@ -439,26 +787,36 @@ static inline void save_comm(char *comm,
- memcpy(comm, task->comm, TASK_COMM_LEN);
- }
-
--static void hist_trigger_elt_comm_free(struct tracing_map_elt *elt)
-+static void hist_trigger_elt_data_free(struct tracing_map_elt *elt)
- {
-- kfree((char *)elt->private_data);
-+ struct hist_elt_data *private_data = elt->private_data;
-+
-+ kfree(private_data->comm);
-+ kfree(private_data);
- }
-
--static int hist_trigger_elt_comm_alloc(struct tracing_map_elt *elt)
-+static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt)
- {
- struct hist_trigger_data *hist_data = elt->map->private_data;
-+ unsigned int size = TASK_COMM_LEN + 1;
-+ struct hist_elt_data *elt_data;
- struct hist_field *key_field;
- unsigned int i;
-
-+ elt->private_data = elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL);
-+ if (!elt_data)
-+ return -ENOMEM;
-+
- for_each_hist_key_field(i, hist_data) {
- key_field = hist_data->fields[i];
-
- if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
-- unsigned int size = TASK_COMM_LEN + 1;
--
-- elt->private_data = kzalloc(size, GFP_KERNEL);
-- if (!elt->private_data)
-+ elt_data->comm = kzalloc(size, GFP_KERNEL);
-+ if (!elt_data->comm) {
-+ kfree(elt_data);
-+ elt->private_data = NULL;
- return -ENOMEM;
-+ }
- break;
- }
- }
-@@ -466,29 +824,31 @@ static int hist_trigger_elt_comm_alloc(s
- return 0;
- }
-
--static void hist_trigger_elt_comm_copy(struct tracing_map_elt *to,
-+static void hist_trigger_elt_data_copy(struct tracing_map_elt *to,
- struct tracing_map_elt *from)
- {
-- char *comm_from = from->private_data;
-- char *comm_to = to->private_data;
-+ struct hist_elt_data *from_data = from->private_data;
-+ struct hist_elt_data *to_data = to->private_data;
-+
-+ memcpy(to_data, from_data, sizeof(*to));
-
-- if (comm_from)
-- memcpy(comm_to, comm_from, TASK_COMM_LEN + 1);
-+ if (from_data->comm)
-+ memcpy(to_data->comm, from_data->comm, TASK_COMM_LEN + 1);
- }
-
--static void hist_trigger_elt_comm_init(struct tracing_map_elt *elt)
-+static void hist_trigger_elt_data_init(struct tracing_map_elt *elt)
- {
-- char *comm = elt->private_data;
-+ struct hist_elt_data *private_data = elt->private_data;
-
-- if (comm)
-- save_comm(comm, current);
-+ if (private_data->comm)
-+ save_comm(private_data->comm, current);
- }
-
--static const struct tracing_map_ops hist_trigger_elt_comm_ops = {
-- .elt_alloc = hist_trigger_elt_comm_alloc,
-- .elt_copy = hist_trigger_elt_comm_copy,
-- .elt_free = hist_trigger_elt_comm_free,
-- .elt_init = hist_trigger_elt_comm_init,
-+static const struct tracing_map_ops hist_trigger_elt_data_ops = {
-+ .elt_alloc = hist_trigger_elt_data_alloc,
-+ .elt_copy = hist_trigger_elt_data_copy,
-+ .elt_free = hist_trigger_elt_data_free,
-+ .elt_init = hist_trigger_elt_data_init,
- };
-
- static char *expr_str(struct hist_field *field, unsigned int level)
-@@ -513,6 +873,8 @@ static char *expr_str(struct hist_field
+@@ -574,6 +915,8 @@ static char *expr_str(struct hist_field
return expr;
}
+ if (field->operands[0]->flags & HIST_FIELD_FL_VAR_REF)
+ strcat(expr, "$");
strcat(expr, hist_field_name(field->operands[0], 0));
-
- switch (field->operator) {
-@@ -527,6 +889,8 @@ static char *expr_str(struct hist_field
+ if (field->operands[0]->flags) {
+ const char *flags_str = get_hist_field_flags(field->operands[0]);
+@@ -596,6 +939,8 @@ static char *expr_str(struct hist_field
return NULL;
}
+ if (field->operands[1]->flags & HIST_FIELD_FL_VAR_REF)
+ strcat(expr, "$");
strcat(expr, hist_field_name(field->operands[1], 0));
-
- return expr;
-@@ -597,6 +961,11 @@ static struct hist_field *create_hist_fi
+ if (field->operands[1]->flags) {
+ const char *flags_str = get_hist_field_flags(field->operands[1]);
+@@ -675,6 +1020,11 @@ static struct hist_field *create_hist_fi
if (flags & HIST_FIELD_FL_EXPR)
goto out; /* caller will populate */
@@ -677,11 +480,32 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
if (flags & HIST_FIELD_FL_HITCOUNT) {
hist_field->fn = hist_field_counter;
- goto out;
-@@ -669,6 +1038,44 @@ static void destroy_hist_fields(struct h
+ hist_field->size = sizeof(u64);
+@@ -768,6 +1118,51 @@ static void destroy_hist_fields(struct h
}
}
++static int init_var_ref(struct hist_field *ref_field,
++ struct hist_field *var_field)
++{
++ ref_field->var.idx = var_field->var.idx;
++ ref_field->var.hist_data = var_field->hist_data;
++ ref_field->size = var_field->size;
++ ref_field->is_signed = var_field->is_signed;
++
++ ref_field->name = kstrdup(var_field->var.name, GFP_KERNEL);
++ if (!ref_field->name)
++ return -ENOMEM;
++
++ ref_field->type = kstrdup(var_field->type, GFP_KERNEL);
++ if (!ref_field->type) {
++ kfree(ref_field->name);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
+static struct hist_field *create_var_ref(struct hist_field *var_field)
+{
+ unsigned long flags = HIST_FIELD_FL_VAR_REF;
@@ -689,12 +513,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+ ref_field = create_hist_field(var_field->hist_data, NULL, flags, NULL);
+ if (ref_field) {
-+ ref_field->var.idx = var_field->var.idx;
-+ ref_field->var.hist_data = var_field->hist_data;
-+ ref_field->size = var_field->size;
-+ ref_field->is_signed = var_field->is_signed;
-+ ref_field->name = kstrdup(var_field->var.name, GFP_KERNEL);
-+ if (!ref_field->name) {
++ if (init_var_ref(ref_field, var_field)) {
+ destroy_hist_field(ref_field, 0);
+ return NULL;
+ }
@@ -703,17 +522,50 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return ref_field;
+}
+
-+static struct hist_field *parse_var_ref(char *system, char *event_name,
++static bool is_var_ref(char *var_name)
++{
++ if (!var_name || strlen(var_name) < 2 || var_name[0] != '$')
++ return false;
++
++ return true;
++}
++
+ static char *field_name_from_var(struct hist_trigger_data *hist_data,
+ char *var_name)
+ {
+@@ -779,7 +1174,7 @@ static char *field_name_from_var(struct
+
+ if (strcmp(var_name, name) == 0) {
+ field = hist_data->attrs->var_defs.expr[i];
+- if (contains_operator(field))
++ if (contains_operator(field) || is_var_ref(field))
+ continue;
+ return field;
+ }
+@@ -791,11 +1186,32 @@ static char *field_name_from_var(struct
+ static char *local_field_var_ref(struct hist_trigger_data *hist_data,
+ char *var_name)
+ {
++ if (!is_var_ref(var_name))
++ return NULL;
++
+ var_name++;
+
+ return field_name_from_var(hist_data, var_name);
+ }
+
++static struct hist_field *parse_var_ref(struct trace_array *tr,
++ char *system, char *event_name,
+ char *var_name)
+{
+ struct hist_field *var_field = NULL, *ref_field = NULL;
+
-+ if (!var_name || strlen(var_name) < 2 || var_name[0] != '$')
++ if (!is_var_ref(var_name))
+ return NULL;
+
+ var_name++;
+
-+ var_field = find_event_var(system, event_name, var_name);
++ var_field = find_event_var(tr, system, event_name, var_name);
+ if (var_field)
+ ref_field = create_var_ref(var_field);
+
@@ -723,15 +575,19 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static struct ftrace_event_field *
parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
char *field_str, unsigned long *flags)
-@@ -715,10 +1122,28 @@ struct hist_field *parse_atom(struct his
+@@ -852,13 +1268,31 @@ struct hist_field *parse_atom(struct his
struct trace_event_file *file, char *str,
unsigned long *flags, char *var_name)
{
+- char *s;
+ char *s, *ref_system = NULL, *ref_event = NULL, *ref_var = str;
++ struct trace_array *tr = hist_data->event_file->tr;
struct ftrace_event_field *field = NULL;
struct hist_field *hist_field = NULL;
int ret = 0;
+- s = local_field_var_ref(hist_data, str);
+- if (s)
+ s = strchr(str, '.');
+ if (s) {
+ s = strchr(++s, '.');
@@ -742,17 +598,19 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ }
+ }
+
-+ hist_field = parse_var_ref(ref_system, ref_event, ref_var);
-+ if (hist_field) {
-+ hist_data->var_refs[hist_data->n_var_refs] = hist_field;
-+ hist_field->var_ref_idx = hist_data->n_var_refs++;
-+ return hist_field;
-+ }
-+
++ s = local_field_var_ref(hist_data, ref_var);
++ if (!s) {
++ hist_field = parse_var_ref(tr, ref_system, ref_event, ref_var);
++ if (hist_field) {
++ hist_data->var_refs[hist_data->n_var_refs] = hist_field;
++ hist_field->var_ref_idx = hist_data->n_var_refs++;
++ return hist_field;
++ }
++ } else
+ str = s;
+
field = parse_field(hist_data, file, str, flags);
- if (IS_ERR(field)) {
- ret = PTR_ERR(field);
-@@ -885,6 +1310,9 @@ static struct hist_field *parse_expr(str
+@@ -1029,6 +1463,9 @@ static struct hist_field *parse_expr(str
goto free;
}
@@ -762,7 +620,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
expr->operands[0] = operand1;
expr->operands[1] = operand2;
expr->operator = field_op;
-@@ -926,43 +1354,6 @@ static int create_hitcount_val(struct hi
+@@ -1075,43 +1512,6 @@ static int create_hitcount_val(struct hi
return 0;
}
@@ -803,11 +661,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
- return NULL;
-}
-
- static int create_val_field(struct hist_trigger_data *hist_data,
- unsigned int val_idx,
- struct trace_event_file *file,
-@@ -1119,6 +1510,12 @@ static int create_key_field(struct hist_
- }
+ static int __create_val_field(struct hist_trigger_data *hist_data,
+ unsigned int val_idx,
+ struct trace_event_file *file,
+@@ -1245,6 +1645,12 @@ static int create_key_field(struct hist_
+ goto out;
}
+ if (hist_field->flags & HIST_FIELD_FL_VAR_REF) {
@@ -819,50 +677,28 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
key_size = hist_field->size;
}
-@@ -1378,21 +1775,6 @@ static int create_tracing_map_fields(str
- return 0;
- }
-
--static bool need_tracing_map_ops(struct hist_trigger_data *hist_data)
--{
-- struct hist_field *key_field;
-- unsigned int i;
--
-- for_each_hist_key_field(i, hist_data) {
-- key_field = hist_data->fields[i];
--
-- if (key_field->flags & HIST_FIELD_FL_EXECNAME)
-- return true;
-- }
--
-- return false;
--}
--
- static struct hist_trigger_data *
- create_hist_data(unsigned int map_bits,
- struct hist_trigger_attrs *attrs,
-@@ -1418,8 +1800,7 @@ create_hist_data(unsigned int map_bits,
- if (ret)
- goto free;
+@@ -1580,6 +1986,7 @@ create_hist_data(unsigned int map_bits,
-- if (need_tracing_map_ops(hist_data))
-- map_ops = &hist_trigger_elt_comm_ops;
-+ map_ops = &hist_trigger_elt_data_ops;
+ hist_data->attrs = attrs;
+ hist_data->remove = remove;
++ hist_data->event_file = file;
- hist_data->map = tracing_map_create(map_bits, hist_data->key_size,
- map_ops, hist_data);
-@@ -1433,10 +1814,6 @@ create_hist_data(unsigned int map_bits,
+ ret = create_hist_fields(hist_data, file);
+ if (ret)
+@@ -1602,12 +2009,6 @@ create_hist_data(unsigned int map_bits,
+ ret = create_tracing_map_fields(hist_data);
if (ret)
goto free;
-
+-
- ret = tracing_map_init(hist_data->map);
- if (ret)
- goto free;
-
- hist_data->event_file = file;
+- hist_data->event_file = file;
out:
return hist_data;
-@@ -1452,15 +1829,20 @@ create_hist_data(unsigned int map_bits,
+ free:
+@@ -1622,12 +2023,17 @@ create_hist_data(unsigned int map_bits,
static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
struct tracing_map_elt *elt, void *rec,
@@ -880,43 +716,16 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
for_each_hist_val_field(i, hist_data) {
hist_field = hist_data->fields[i];
-- hist_val = hist_field->fn(hist_field, rbe, rec);
-+ hist_val = hist_field->fn(hist_field, elt, 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);
-@@ -1473,7 +1855,7 @@ static void hist_trigger_elt_update(stru
- 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);
-+ hist_val = hist_field->fn(hist_field, elt, rbe, rec);
- var_idx = hist_field->var.idx;
- tracing_map_set_var(elt, var_idx, hist_val);
- }
-@@ -1510,10 +1892,11 @@ static void event_hist_trigger(struct ev
+ hist_val = hist_field->fn(hist_field, elt, rbe, rec);
+@@ -1680,6 +2086,7 @@ static void event_hist_trigger(struct ev
struct hist_trigger_data *hist_data = data->private_data;
bool use_compound_key = (hist_data->n_keys > 1);
unsigned long entries[HIST_STACKTRACE_DEPTH];
+ u64 var_ref_vals[TRACING_MAP_VARS_MAX];
char compound_key[HIST_KEY_SIZE_MAX];
-+ struct tracing_map_elt *elt = NULL;
+ struct tracing_map_elt *elt = NULL;
struct stack_trace stacktrace;
- struct hist_field *key_field;
-- struct tracing_map_elt *elt;
- u64 field_contents;
- void *key = NULL;
- unsigned int i;
-@@ -1534,7 +1917,7 @@ static void event_hist_trigger(struct ev
-
- key = entries;
- } else {
-- field_contents = key_field->fn(key_field, rec, rbe);
-+ field_contents = key_field->fn(key_field, elt, rbe, rec);
- if (key_field->flags & HIST_FIELD_FL_STRING) {
- key = (void *)(unsigned long)field_contents;
- use_compound_key = true;
-@@ -1549,9 +1932,15 @@ static void event_hist_trigger(struct ev
+@@ -1719,9 +2126,15 @@ static void event_hist_trigger(struct ev
if (use_compound_key)
key = compound_key;
@@ -934,17 +743,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
static void hist_trigger_stacktrace_print(struct seq_file *m,
-@@ -1608,7 +1997,8 @@ hist_trigger_entry_print(struct seq_file
- seq_printf(m, "%s: [%llx] %-55s", field_name,
- uval, str);
- } else if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
-- char *comm = elt->private_data;
-+ struct hist_elt_data *elt_data = elt->private_data;
-+ char *comm = elt_data->comm;
-
- uval = *(u64 *)(key + key_field->offset);
- seq_printf(m, "%s: %-16s[%10llu]", field_name,
-@@ -1653,7 +2043,8 @@ hist_trigger_entry_print(struct seq_file
+@@ -1824,7 +2237,8 @@ hist_trigger_entry_print(struct seq_file
field_name = hist_field_name(hist_data->fields[i], 0);
if (hist_data->fields[i]->flags & HIST_FIELD_FL_VAR ||
@@ -954,7 +753,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
continue;
if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
-@@ -1925,7 +2316,11 @@ static void event_hist_trigger_free(stru
+@@ -2074,7 +2488,11 @@ static void event_hist_trigger_free(stru
if (!data->ref) {
if (data->name)
del_named_trigger(data);
@@ -966,7 +765,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
destroy_hist_data(hist_data);
}
}
-@@ -2139,23 +2534,55 @@ static int hist_register_trigger(char *g
+@@ -2288,23 +2706,55 @@ static int hist_register_trigger(char *g
goto out;
}
@@ -1026,7 +825,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static void hist_unregister_trigger(char *glob, struct event_trigger_ops *ops,
struct event_trigger_data *data,
struct trace_event_file *file)
-@@ -2186,10 +2613,32 @@ static void hist_unregister_trigger(char
+@@ -2335,10 +2785,30 @@ static void hist_unregister_trigger(char
tracing_set_time_stamp_abs(file->tr, false);
}
@@ -1035,8 +834,6 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct hist_trigger_data *hist_data;
+ struct event_trigger_data *test;
+
-+ printk("func: %s\n", __func__);
-+
+ list_for_each_entry_rcu(test, &file->triggers, list) {
+ if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
+ hist_data = test->private_data;
@@ -1054,12 +851,12 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
struct event_trigger_data *test, *n;
+ if (hist_file_check_refs(file))
-+ return;
++ return;
+
list_for_each_entry_safe(test, n, &file->triggers, list) {
if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
list_del_rcu(&test->list);
-@@ -2262,6 +2711,11 @@ static int event_hist_trigger_func(struc
+@@ -2411,6 +2881,11 @@ static int event_hist_trigger_func(struc
}
if (remove) {
@@ -1071,7 +868,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
ret = 0;
goto out_free;
-@@ -2279,14 +2733,33 @@ static int event_hist_trigger_func(struc
+@@ -2428,14 +2903,33 @@ static int event_hist_trigger_func(struc
goto out_free;
} else if (ret < 0)
goto out_free;
@@ -1107,7 +904,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
destroy_hist_data(hist_data);
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
-@@ -919,6 +919,12 @@ void set_named_trigger_data(struct event
+@@ -909,6 +909,12 @@ void set_named_trigger_data(struct event
data->named_data = named_data;
}
diff --git a/patches/0025-tracing-Add-support-for-dynamic-tracepoints.patch b/patches/0025-tracing-Add-support-for-dynamic-tracepoints.patch
new file mode 100644
index 000000000000..153daef07243
--- /dev/null
+++ b/patches/0025-tracing-Add-support-for-dynamic-tracepoints.patch
@@ -0,0 +1,78 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:37 -0500
+Subject: [PATCH 25/40] tracing: Add support for dynamic tracepoints
+
+The tracepoint infrastructure assumes statically-defined tracepoints
+and uses static_keys for tracepoint enablement. In order to define
+tracepoints on the fly, we need to have a dynamic counterpart.
+
+Add a 'dynamic' flag to struct tracepoint along with accompanying
+logic for this purpose.
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ include/linux/tracepoint-defs.h | 1 +
+ kernel/tracepoint.c | 18 +++++++++++++-----
+ 2 files changed, 14 insertions(+), 5 deletions(-)
+
+--- a/include/linux/tracepoint-defs.h
++++ b/include/linux/tracepoint-defs.h
+@@ -32,6 +32,7 @@ struct tracepoint {
+ int (*regfunc)(void);
+ void (*unregfunc)(void);
+ struct tracepoint_func __rcu *funcs;
++ bool dynamic;
+ };
+
+ #endif
+--- a/kernel/tracepoint.c
++++ b/kernel/tracepoint.c
+@@ -197,7 +197,9 @@ static int tracepoint_add_func(struct tr
+ struct tracepoint_func *old, *tp_funcs;
+ int ret;
+
+- if (tp->regfunc && !static_key_enabled(&tp->key)) {
++ if (tp->regfunc &&
++ ((tp->dynamic && !(atomic_read(&tp->key.enabled) > 0)) ||
++ !static_key_enabled(&tp->key))) {
+ ret = tp->regfunc();
+ if (ret < 0)
+ return ret;
+@@ -219,7 +221,9 @@ static int tracepoint_add_func(struct tr
+ * is used.
+ */
+ rcu_assign_pointer(tp->funcs, tp_funcs);
+- if (!static_key_enabled(&tp->key))
++ if (tp->dynamic && !(atomic_read(&tp->key.enabled) > 0))
++ atomic_inc(&tp->key.enabled);
++ else if (!tp->dynamic && !static_key_enabled(&tp->key))
+ static_key_slow_inc(&tp->key);
+ release_probes(old);
+ return 0;
+@@ -246,10 +250,14 @@ static int tracepoint_remove_func(struct
+
+ if (!tp_funcs) {
+ /* Removed last function */
+- if (tp->unregfunc && static_key_enabled(&tp->key))
++ if (tp->unregfunc &&
++ ((tp->dynamic && (atomic_read(&tp->key.enabled) > 0)) ||
++ static_key_enabled(&tp->key)))
+ tp->unregfunc();
+
+- if (static_key_enabled(&tp->key))
++ if (tp->dynamic && (atomic_read(&tp->key.enabled) > 0))
++ atomic_dec(&tp->key.enabled);
++ else if (!tp->dynamic && static_key_enabled(&tp->key))
+ static_key_slow_dec(&tp->key);
+ }
+ rcu_assign_pointer(tp->funcs, tp_funcs);
+@@ -258,7 +266,7 @@ static int tracepoint_remove_func(struct
+ }
+
+ /**
+- * tracepoint_probe_register - Connect a probe to a tracepoint
++ * tracepoint_probe_register_prio - Connect a probe to a tracepoint
+ * @tp: tracepoint
+ * @probe: probe handler
+ * @data: tracepoint data
diff --git a/patches/0021-tracing-Add-hist-trigger-action-hook.patch b/patches/0026-tracing-Add-hist-trigger-action-hook.patch
index e0913ac9216d..5b693de18759 100644
--- a/patches/0021-tracing-Add-hist-trigger-action-hook.patch
+++ b/patches/0026-tracing-Add-hist-trigger-action-hook.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:22 -0500
-Subject: [PATCH 21/32] tracing: Add hist trigger action hook
+Date: Tue, 5 Sep 2017 16:57:38 -0500
+Subject: [PATCH 26/40] tracing: Add hist trigger action hook
Add a hook for executing extra actions whenever a histogram entry is
added or updated.
@@ -29,17 +29,17 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
enum field_op_id {
FIELD_OP_NONE,
-@@ -233,6 +234,9 @@ struct hist_trigger_attrs {
-
+@@ -241,6 +242,9 @@ struct hist_trigger_attrs {
char *assignment_str[TRACING_MAP_VARS_MAX];
unsigned int n_assignments;
-+
+
+ char *action_str[HIST_ACTIONS_MAX];
+ unsigned int n_actions;
++
+ struct var_defs var_defs;
};
- struct hist_trigger_data {
-@@ -252,6 +256,21 @@ struct hist_trigger_data {
+@@ -261,6 +265,21 @@ struct hist_trigger_data {
bool remove;
struct hist_field *var_refs[TRACING_MAP_VARS_MAX];
unsigned int n_var_refs;
@@ -61,7 +61,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
};
static u64 hist_field_timestamp(struct hist_field *hist_field,
-@@ -681,6 +700,9 @@ static void destroy_hist_trigger_attrs(s
+@@ -710,6 +729,9 @@ static void destroy_hist_trigger_attrs(s
for (i = 0; i < attrs->n_assignments; i++)
kfree(attrs->assignment_str[i]);
@@ -71,7 +71,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
kfree(attrs->name);
kfree(attrs->sort_key_str);
kfree(attrs->keys_str);
-@@ -688,6 +710,16 @@ static void destroy_hist_trigger_attrs(s
+@@ -717,6 +739,16 @@ static void destroy_hist_trigger_attrs(s
kfree(attrs);
}
@@ -88,7 +88,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static int parse_assignment(char *str, struct hist_trigger_attrs *attrs)
{
int ret = 0;
-@@ -755,8 +787,9 @@ static struct hist_trigger_attrs *parse_
+@@ -784,8 +816,9 @@ static struct hist_trigger_attrs *parse_
else if (strcmp(str, "clear") == 0)
attrs->clear = true;
else {
@@ -100,7 +100,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
}
-@@ -1722,11 +1755,63 @@ static int create_sort_keys(struct hist_
+@@ -1917,11 +1950,63 @@ static int create_sort_keys(struct hist_
return ret;
}
@@ -164,7 +164,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
kfree(hist_data);
}
-@@ -1886,6 +1971,20 @@ static inline void add_to_key(char *comp
+@@ -2080,6 +2165,20 @@ static inline void add_to_key(char *comp
memcpy(compound_key + key_field->offset, key, size);
}
@@ -185,7 +185,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static void event_hist_trigger(struct event_trigger_data *data, void *rec,
struct ring_buffer_event *rbe)
{
-@@ -1941,6 +2040,9 @@ static void event_hist_trigger(struct ev
+@@ -2135,6 +2234,9 @@ static void event_hist_trigger(struct ev
return;
hist_trigger_elt_update(hist_data, elt, rec, rbe, var_ref_vals);
@@ -195,7 +195,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
static void hist_trigger_stacktrace_print(struct seq_file *m,
-@@ -2278,6 +2380,8 @@ static int event_hist_trigger_print(stru
+@@ -2450,6 +2552,8 @@ static int event_hist_trigger_print(stru
}
seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
@@ -204,7 +204,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (data->filter_str)
seq_printf(m, " if %s", data->filter_str);
-@@ -2740,6 +2844,10 @@ static int event_hist_trigger_func(struc
+@@ -2910,6 +3014,10 @@ static int event_hist_trigger_func(struc
if (has_hist_vars(hist_data))
save_hist_vars(hist_data);
@@ -215,7 +215,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = tracing_map_init(hist_data->map);
if (ret)
goto out_unreg;
-@@ -2761,8 +2869,8 @@ static int event_hist_trigger_func(struc
+@@ -2931,8 +3039,8 @@ static int event_hist_trigger_func(struc
remove_hist_vars(hist_data);
kfree(trigger_data);
diff --git a/patches/0026-tracing-Make-duplicate-count-from-tracing_map-availa.patch b/patches/0026-tracing-Make-duplicate-count-from-tracing_map-availa.patch
deleted file mode 100644
index aeaca9d7c9b2..000000000000
--- a/patches/0026-tracing-Make-duplicate-count-from-tracing_map-availa.patch
+++ /dev/null
@@ -1,124 +0,0 @@
-From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:27 -0500
-Subject: [PATCH 26/32] tracing: Make duplicate count from tracing_map
- available
-
-Though extremely rare, there can be duplicate entries in the tracing
-map. This isn't normally a problem, as the sorting code makes this
-transparent by merging them during the sort.
-
-It's useful to know however, as a check on that assumption - if a
-non-zero duplicate count is seen more than rarely, it might indicate
-an unexpected change to the algorithm, or a pathological data set.
-
-Add an extra param to tracing_map_sort_entries() and use it to display
-the value in the hist trigger output.
-
-Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
-Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
----
- kernel/trace/trace_events_hist.c | 14 ++++++++------
- kernel/trace/tracing_map.c | 12 +++++++++---
- kernel/trace/tracing_map.h | 3 ++-
- 3 files changed, 19 insertions(+), 10 deletions(-)
-
---- a/kernel/trace/trace_events_hist.c
-+++ b/kernel/trace/trace_events_hist.c
-@@ -4011,7 +4011,8 @@ hist_trigger_entry_print(struct seq_file
- }
-
- static int print_entries(struct seq_file *m,
-- struct hist_trigger_data *hist_data)
-+ struct hist_trigger_data *hist_data,
-+ unsigned int *n_dups)
- {
- struct tracing_map_sort_entry **sort_entries = NULL;
- struct tracing_map *map = hist_data->map;
-@@ -4019,7 +4020,7 @@ static int print_entries(struct seq_file
-
- n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
- hist_data->n_sort_keys,
-- &sort_entries);
-+ &sort_entries, n_dups);
- if (n_entries < 0)
- return n_entries;
-
-@@ -4038,6 +4039,7 @@ static void hist_trigger_show(struct seq
- {
- struct hist_trigger_data *hist_data;
- int n_entries, ret = 0;
-+ unsigned int n_dups;
-
- if (n > 0)
- seq_puts(m, "\n\n");
-@@ -4047,15 +4049,15 @@ static void hist_trigger_show(struct seq
- seq_puts(m, "#\n\n");
-
- hist_data = data->private_data;
-- n_entries = print_entries(m, hist_data);
-+ n_entries = print_entries(m, hist_data, &n_dups);
- if (n_entries < 0) {
- ret = n_entries;
- n_entries = 0;
- }
-
-- seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n",
-- (u64)atomic64_read(&hist_data->map->hits),
-- n_entries, (u64)atomic64_read(&hist_data->map->drops));
-+ seq_printf(m, "\nTotals:\n Hits: %llu\n Entries: %u\n Dropped: %llu\n Duplicates: %u\n",
-+ (u64)atomic64_read(&hist_data->map->hits), n_entries,
-+ (u64)atomic64_read(&hist_data->map->drops), n_dups);
- }
-
- static int hist_show(struct seq_file *m, void *v)
---- a/kernel/trace/tracing_map.c
-+++ b/kernel/trace/tracing_map.c
-@@ -1084,6 +1084,7 @@ static void sort_secondary(struct tracin
- * @map: The tracing_map
- * @sort_key: The sort key to use for sorting
- * @sort_entries: outval: pointer to allocated and sorted array of entries
-+ * @n_dups: outval: pointer to variable receiving a count of duplicates found
- *
- * tracing_map_sort_entries() sorts the current set of entries in the
- * map and returns the list of tracing_map_sort_entries containing
-@@ -1100,13 +1101,16 @@ static void sort_secondary(struct tracin
- * The client should not hold on to the returned array but should use
- * it and call tracing_map_destroy_sort_entries() when done.
- *
-- * Return: the number of sort_entries in the struct tracing_map_sort_entry
-- * array, negative on error
-+ * Return: the number of sort_entries in the struct
-+ * tracing_map_sort_entry array, negative on error. If n_dups is
-+ * non-NULL, it will receive the number of duplicate entries found
-+ * (and merged) during the sort.
- */
- int tracing_map_sort_entries(struct tracing_map *map,
- struct tracing_map_sort_key *sort_keys,
- unsigned int n_sort_keys,
-- struct tracing_map_sort_entry ***sort_entries)
-+ struct tracing_map_sort_entry ***sort_entries,
-+ unsigned int *n_dups)
- {
- int (*cmp_entries_fn)(const struct tracing_map_sort_entry **,
- const struct tracing_map_sort_entry **);
-@@ -1147,6 +1151,8 @@ int tracing_map_sort_entries(struct trac
- if (ret < 0)
- goto free;
- n_entries -= ret;
-+ if (n_dups)
-+ *n_dups = ret;
-
- if (is_key(map, sort_keys[0].field_idx))
- cmp_entries_fn = cmp_entries_key;
---- a/kernel/trace/tracing_map.h
-+++ b/kernel/trace/tracing_map.h
-@@ -286,7 +286,8 @@ extern int
- tracing_map_sort_entries(struct tracing_map *map,
- struct tracing_map_sort_key *sort_keys,
- unsigned int n_sort_keys,
-- struct tracing_map_sort_entry ***sort_entries);
-+ struct tracing_map_sort_entry ***sort_entries,
-+ unsigned int *n_dups);
-
- extern void
- tracing_map_destroy_sort_entries(struct tracing_map_sort_entry **entries,
diff --git a/patches/0022-tracing-Add-support-for-synthetic-events.patch b/patches/0027-tracing-Add-support-for-synthetic-events.patch
index 24cf13a45be3..945a4d9c6e19 100644
--- a/patches/0022-tracing-Add-support-for-synthetic-events.patch
+++ b/patches/0027-tracing-Add-support-for-synthetic-events.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:23 -0500
-Subject: [PATCH 22/32] tracing: Add support for 'synthetic' events
+Date: Tue, 5 Sep 2017 16:57:39 -0500
+Subject: [PATCH 27/40] tracing: Add support for 'synthetic' events
Synthetic events are user-defined events generated from hist trigger
variables saved from one or more other events.
@@ -47,12 +47,12 @@ discussed in a subsequent patch.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/trace_events_hist.c | 738 +++++++++++++++++++++++++++++++++++++++
- 1 file changed, 738 insertions(+)
+ kernel/trace/trace_events_hist.c | 863 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 863 insertions(+)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -20,10 +20,14 @@
+@@ -20,10 +20,16 @@
#include <linux/slab.h>
#include <linux/stacktrace.h>
#include <linux/rculist.h>
@@ -64,25 +64,30 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+#define SYNTH_SYSTEM "synthetic"
+#define SYNTH_FIELDS_MAX 16
+
++#define STR_VAR_LEN_MAX 32 /* must be multiple of sizeof(u64) */
++
struct hist_field;
typedef u64 (*hist_field_fn_t) (struct hist_field *field,
-@@ -261,6 +265,23 @@ struct hist_trigger_data {
+@@ -270,6 +276,26 @@ struct hist_trigger_data {
unsigned int n_actions;
};
+struct synth_field {
+ char *type;
+ char *name;
-+ unsigned int size;
++ size_t size;
+ bool is_signed;
++ bool is_string;
+};
+
+struct synth_event {
+ struct list_head list;
++ int ref;
+ char *name;
+ struct synth_field **fields;
+ unsigned int n_fields;
++ unsigned int n_u64;
+ struct trace_event_class class;
+ struct trace_event_call call;
+ struct tracepoint *tp;
@@ -91,7 +96,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
struct action_data;
typedef void (*action_fn_t) (struct hist_trigger_data *hist_data,
-@@ -273,6 +294,688 @@ struct action_data {
+@@ -282,6 +308,798 @@ struct action_data {
unsigned int var_ref_idx;
};
@@ -100,7 +105,6 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+struct synth_trace_event {
+ struct trace_entry ent;
-+ int n_fields;
+ u64 fields[];
+};
+
@@ -109,24 +113,163 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct synth_trace_event trace;
+ int offset = offsetof(typeof(trace), fields);
+ struct synth_event *event = call->data;
-+ unsigned int i, size;
++ unsigned int i, size, n_u64;
+ char *name, *type;
+ bool is_signed;
+ int ret = 0;
+
-+ for (i = 0; i < event->n_fields; i++) {
++ for (i = 0, n_u64 = 0; i < event->n_fields; i++) {
+ size = event->fields[i]->size;
+ is_signed = event->fields[i]->is_signed;
+ type = event->fields[i]->type;
+ name = event->fields[i]->name;
+ ret = trace_define_field(call, type, name, offset, size,
+ is_signed, FILTER_OTHER);
-+ offset += sizeof(u64);
++ if (ret)
++ break;
++
++ if (event->fields[i]->is_string) {
++ offset += STR_VAR_LEN_MAX;
++ n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
++ } else {
++ offset += sizeof(u64);
++ n_u64++;
++ }
+ }
+
++ event->n_u64 = n_u64;
++
+ return ret;
+}
+
++static bool synth_field_signed(char *type)
++{
++ if (strncmp(type, "u", 1) == 0)
++ return false;
++
++ return true;
++}
++
++static int synth_field_is_string(char *type)
++{
++ if (strstr(type, "char[") != NULL)
++ return true;
++
++ return false;
++}
++
++static int synth_field_string_size(char *type)
++{
++ char buf[4], *end, *start;
++ unsigned int len;
++ int size, err;
++
++ start = strstr(type, "char[");
++ if (start == NULL)
++ return -EINVAL;
++ start += strlen("char[");
++
++ end = strchr(type, ']');
++ if (!end || end < start)
++ return -EINVAL;
++
++ len = end - start;
++ if (len > 2)
++ return -EINVAL;
++
++ strncpy(buf, start, len);
++ buf[len] = '\0';
++
++ err = kstrtouint(buf, 0, &size);
++ if (err)
++ return err;
++
++ if (size > STR_VAR_LEN_MAX)
++ return -EINVAL;
++
++ return size;
++}
++
++static int synth_field_size(char *type)
++{
++ int size = 0;
++
++ if (strcmp(type, "s64") == 0)
++ size = sizeof(s64);
++ else if (strcmp(type, "u64") == 0)
++ size = sizeof(u64);
++ else if (strcmp(type, "s32") == 0)
++ size = sizeof(s32);
++ else if (strcmp(type, "u32") == 0)
++ size = sizeof(u32);
++ else if (strcmp(type, "s16") == 0)
++ size = sizeof(s16);
++ else if (strcmp(type, "u16") == 0)
++ size = sizeof(u16);
++ else if (strcmp(type, "s8") == 0)
++ size = sizeof(s8);
++ else if (strcmp(type, "u8") == 0)
++ size = sizeof(u8);
++ else if (strcmp(type, "char") == 0)
++ size = sizeof(char);
++ else if (strcmp(type, "unsigned char") == 0)
++ size = sizeof(unsigned char);
++ else if (strcmp(type, "int") == 0)
++ size = sizeof(int);
++ else if (strcmp(type, "unsigned int") == 0)
++ size = sizeof(unsigned int);
++ else if (strcmp(type, "long") == 0)
++ size = sizeof(long);
++ else if (strcmp(type, "unsigned long") == 0)
++ size = sizeof(unsigned long);
++ else if (strcmp(type, "pid_t") == 0)
++ size = sizeof(pid_t);
++ else if (synth_field_is_string(type))
++ size = synth_field_string_size(type);
++
++ return size;
++}
++
++static const char *synth_field_fmt(char *type)
++{
++ const char *fmt = "%llu";
++
++ if (strcmp(type, "s64") == 0)
++ fmt = "%lld";
++ else if (strcmp(type, "u64") == 0)
++ fmt = "%llu";
++ else if (strcmp(type, "s32") == 0)
++ fmt = "%d";
++ else if (strcmp(type, "u32") == 0)
++ fmt = "%u";
++ else if (strcmp(type, "s16") == 0)
++ fmt = "%d";
++ else if (strcmp(type, "u16") == 0)
++ fmt = "%u";
++ else if (strcmp(type, "s8") == 0)
++ fmt = "%d";
++ else if (strcmp(type, "u8") == 0)
++ fmt = "%u";
++ else if (strcmp(type, "char") == 0)
++ fmt = "%d";
++ else if (strcmp(type, "unsigned char") == 0)
++ fmt = "%u";
++ else if (strcmp(type, "int") == 0)
++ fmt = "%d";
++ else if (strcmp(type, "unsigned int") == 0)
++ fmt = "%u";
++ else if (strcmp(type, "long") == 0)
++ fmt = "%ld";
++ else if (strcmp(type, "unsigned long") == 0)
++ fmt = "%lu";
++ else if (strcmp(type, "pid_t") == 0)
++ fmt = "%d";
++ else if (strstr(type, "[") == 0)
++ fmt = "%s";
++
++ return fmt;
++}
++
+static enum print_line_t print_synth_event(struct trace_iterator *iter,
+ int flags,
+ struct trace_event *event)
@@ -135,25 +278,39 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct trace_seq *s = &iter->seq;
+ struct synth_trace_event *entry;
+ struct synth_event *se;
-+ unsigned int i;
++ unsigned int i, n_u64;
++ char print_fmt[32];
++ const char *fmt;
+
+ entry = (struct synth_trace_event *)iter->ent;
+ se = container_of(event, struct synth_event, call.event);
+
+ trace_seq_printf(s, "%s: ", se->name);
+
-+ for (i = 0; i < entry->n_fields; i++) {
++ for (i = 0, n_u64 = 0; i < se->n_fields; i++) {
+ if (trace_seq_has_overflowed(s))
+ goto end;
+
++ fmt = synth_field_fmt(se->fields[i]->type);
++
+ /* parameter types */
+ if (tr->trace_flags & TRACE_ITER_VERBOSE)
-+ trace_seq_printf(s, "%s ", "u64");
++ trace_seq_printf(s, "%s ", fmt);
++
++ sprintf(print_fmt, "%%s=%s%%s", fmt);
+
+ /* parameter values */
-+ trace_seq_printf(s, "%s=%llu%s", se->fields[i]->name,
-+ entry->fields[i],
-+ i == entry->n_fields - 1 ? "" : ", ");
++ if (se->fields[i]->is_string) {
++ trace_seq_printf(s, print_fmt, se->fields[i]->name,
++ (char *)entry->fields[n_u64],
++ i == se->n_fields - 1 ? "" : " ");
++ n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
++ } else {
++ trace_seq_printf(s, print_fmt, se->fields[i]->name,
++ entry->fields[n_u64],
++ i == se->n_fields - 1 ? "" : " ");
++ n_u64++;
++ }
+ }
+end:
+ trace_seq_putc(s, '\n');
@@ -172,27 +329,34 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct trace_event_file *trace_file = __data;
+ struct synth_trace_event *entry;
+ struct trace_event_buffer fbuffer;
-+ int fields_size;
-+ unsigned int i;
-+
+ struct synth_event *event;
++ unsigned int i, n_u64;
++ int fields_size = 0;
+
+ event = trace_file->event_call->data;
+
+ if (trace_trigger_soft_disabled(trace_file))
+ return;
+
-+ fields_size = event->n_fields * sizeof(u64);
++ fields_size = event->n_u64 * sizeof(u64);
+
+ entry = trace_event_buffer_reserve(&fbuffer, trace_file,
+ sizeof(*entry) + fields_size);
+ if (!entry)
+ return;
+
-+ entry->n_fields = event->n_fields;
++ for (i = 0, n_u64 = 0; i < event->n_fields; i++) {
++ if (event->fields[i]->is_string) {
++ char *str_val = (char *)var_ref_vals[var_ref_idx + i];
++ char *str_field = (char *)&entry->fields[n_u64];
+
-+ for (i = 0; i < event->n_fields; i++)
-+ entry->fields[i] = var_ref_vals[var_ref_idx + i];
++ strncpy(str_field, str_val, STR_VAR_LEN_MAX);
++ n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
++ } else {
++ entry->fields[i] = var_ref_vals[var_ref_idx + i];
++ n_u64++;
++ }
++ }
+
+ trace_event_buffer_commit(&fbuffer);
+}
@@ -206,6 +370,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+static int __set_synth_event_print_fmt(struct synth_event *event,
+ char *buf, int len)
+{
++ const char *fmt;
+ int pos = 0;
+ int i;
+
@@ -214,15 +379,16 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+ pos += snprintf(buf + pos, LEN_OR_ZERO, "\"");
+ for (i = 0; i < event->n_fields; i++) {
-+ pos += snprintf(buf + pos, LEN_OR_ZERO, "%s: 0x%%0%zulx%s",
-+ event->fields[i]->name, sizeof(u64),
++ fmt = synth_field_fmt(event->fields[i]->type);
++ pos += snprintf(buf + pos, LEN_OR_ZERO, "%s=%s%s",
++ event->fields[i]->name, fmt,
+ i == event->n_fields - 1 ? "" : ", ");
+ }
+ pos += snprintf(buf + pos, LEN_OR_ZERO, "\"");
+
+ for (i = 0; i < event->n_fields; i++) {
+ pos += snprintf(buf + pos, LEN_OR_ZERO,
-+ ", ((u64)(REC->%s))", event->fields[i]->name);
++ ", REC->%s", event->fields[i]->name);
+ }
+
+#undef LEN_OR_ZERO
@@ -251,43 +417,6 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return 0;
+}
+
-+int dynamic_trace_event_reg(struct trace_event_call *call,
-+ enum trace_reg type, void *data)
-+{
-+ struct trace_event_file *file = data;
-+
-+ WARN_ON(!(call->flags & TRACE_EVENT_FL_TRACEPOINT));
-+ switch (type) {
-+ case TRACE_REG_REGISTER:
-+ return dynamic_tracepoint_probe_register(call->tp,
-+ call->class->probe,
-+ file);
-+ case TRACE_REG_UNREGISTER:
-+ tracepoint_probe_unregister(call->tp,
-+ call->class->probe,
-+ file, true);
-+ return 0;
-+
-+#ifdef CONFIG_PERF_EVENTS
-+ case TRACE_REG_PERF_REGISTER:
-+ return dynamic_tracepoint_probe_register(call->tp,
-+ call->class->perf_probe,
-+ call);
-+ case TRACE_REG_PERF_UNREGISTER:
-+ tracepoint_probe_unregister(call->tp,
-+ call->class->perf_probe,
-+ call, true);
-+ return 0;
-+ case TRACE_REG_PERF_OPEN:
-+ case TRACE_REG_PERF_CLOSE:
-+ case TRACE_REG_PERF_ADD:
-+ case TRACE_REG_PERF_DEL:
-+ return 0;
-+#endif
-+ }
-+ return 0;
-+}
-+
+static void free_synth_field(struct synth_field *field)
+{
+ kfree(field->type);
@@ -295,54 +424,6 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ kfree(field);
+}
+
-+static bool synth_field_signed(char *type)
-+{
-+ if (strncmp(type, "u", 1) == 0)
-+ return false;
-+
-+ return true;
-+}
-+
-+static unsigned int synth_field_size(char *type)
-+{
-+ unsigned int size = 0;
-+
-+ if (strcmp(type, "s64") == 0)
-+ size = sizeof(s64);
-+ else if (strcmp(type, "u64") == 0)
-+ size = sizeof(u64);
-+ else if (strcmp(type, "s32") == 0)
-+ size = sizeof(s32);
-+ else if (strcmp(type, "u32") == 0)
-+ size = sizeof(u32);
-+ else if (strcmp(type, "s16") == 0)
-+ size = sizeof(s16);
-+ else if (strcmp(type, "u16") == 0)
-+ size = sizeof(u16);
-+ else if (strcmp(type, "s8") == 0)
-+ size = sizeof(s8);
-+ else if (strcmp(type, "u8") == 0)
-+ size = sizeof(u8);
-+ else if (strcmp(type, "char") == 0)
-+ size = sizeof(char);
-+ else if (strcmp(type, "unsigned char") == 0)
-+ size = sizeof(unsigned char);
-+ else if (strcmp(type, "int") == 0)
-+ size = sizeof(int);
-+ else if (strcmp(type, "unsigned int") == 0)
-+ size = sizeof(unsigned int);
-+ else if (strcmp(type, "long") == 0)
-+ size = sizeof(long);
-+ else if (strcmp(type, "unsigned long") == 0)
-+ size = sizeof(unsigned long);
-+ else if (strcmp(type, "pid_t") == 0)
-+ size = sizeof(pid_t);
-+ else if (strstr(type, "[") == 0)
-+ size = sizeof(u64);
-+
-+ return size;
-+}
-+
+static struct synth_field *parse_synth_field(char *field_type,
+ char *field_name)
+{
@@ -371,8 +452,10 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ goto free;
+ }
+ strcat(field->type, field_type);
-+ if (array)
++ if (array) {
+ strcat(field->type, array);
++ *array = '\0';
++ }
+
+ field->size = synth_field_size(field->type);
+ if (!field->size) {
@@ -380,6 +463,9 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ goto free;
+ }
+
++ if (synth_field_is_string(field->type))
++ field->is_string = true;
++
+ field->is_signed = synth_field_signed(field->type);
+
+ field->name = kstrdup(field_name, GFP_KERNEL);
@@ -421,6 +507,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ goto free;
+ }
+
++ tp->dynamic = true;
++
+ return tp;
+ free:
+ free_synth_tracepoint(tp);
@@ -428,26 +516,29 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return ERR_PTR(ret);
+}
+
++typedef void (*synth_probe_func_t) (void *__data, u64 *var_ref_vals,
++ unsigned int var_ref_idx);
++
+static inline void trace_synth(struct synth_event *event, u64 *var_ref_vals,
+ unsigned int var_ref_idx)
+{
+ struct tracepoint *tp = event->tp;
+
+ if (unlikely(atomic_read(&tp->key.enabled) > 0)) {
-+ struct tracepoint_func *it_func_ptr;
-+ void *it_func;
++ struct tracepoint_func *probe_func_ptr;
++ synth_probe_func_t probe_func;
+ void *__data;
+
+ if (!(cpu_online(raw_smp_processor_id())))
+ return;
+
-+ it_func_ptr = rcu_dereference_sched((tp)->funcs);
-+ if (it_func_ptr) {
++ probe_func_ptr = rcu_dereference_sched((tp)->funcs);
++ if (probe_func_ptr) {
+ do {
-+ it_func = (it_func_ptr)->func;
-+ __data = (it_func_ptr)->data;
-+ ((void(*)(void *__data, u64 *var_ref_vals, unsigned int var_ref_idx))(it_func))(__data, var_ref_vals, var_ref_idx);
-+ } while ((++it_func_ptr)->func);
++ probe_func = (probe_func_ptr)->func;
++ __data = (probe_func_ptr)->data;
++ probe_func(__data, var_ref_vals, var_ref_idx);
++ } while ((++probe_func_ptr)->func);
+ }
+ }
+}
@@ -493,11 +584,14 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ goto out;
+ }
+ call->flags = TRACE_EVENT_FL_TRACEPOINT;
-+ call->class->reg = dynamic_trace_event_reg;
++ call->class->reg = trace_event_reg;
+ call->class->probe = trace_event_raw_event_synth;
+ call->data = event;
+ call->tp = event->tp;
++
++ mutex_unlock(&synth_event_mutex);
+ ret = trace_add_event_call(call);
++ mutex_lock(&synth_event_mutex);
+ if (ret) {
+ pr_warn("Failed to register synthetic event: %s\n",
+ trace_event_name(call));
@@ -506,7 +600,9 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+ ret = set_synth_event_print_fmt(call);
+ if (ret < 0) {
++ mutex_unlock(&synth_event_mutex);
+ trace_remove_event_call(call);
++ mutex_lock(&synth_event_mutex);
+ goto err;
+ }
+ out:
@@ -521,7 +617,9 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct trace_event_call *call = &event->call;
+ int ret;
+
++ mutex_unlock(&synth_event_mutex);
+ ret = trace_remove_event_call(call);
++ mutex_lock(&synth_event_mutex);
+ if (ret) {
+ pr_warn("Failed to remove synthetic event: %s\n",
+ trace_event_name(call));
@@ -605,7 +703,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+static int create_synth_event(int argc, char **argv)
+{
-+ struct synth_field *fields[SYNTH_FIELDS_MAX];
++ struct synth_field *field, *fields[SYNTH_FIELDS_MAX];
+ struct synth_event *event = NULL;
+ bool delete_event = false;
+ int i, n_fields = 0, ret = 0;
@@ -621,7 +719,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ */
+ if (argc < 1) {
+ ret = -EINVAL;
-+ goto err;
++ goto out;
+ }
+
+ name = argv[0];
@@ -633,10 +731,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ event = find_synth_event(name);
+ if (event) {
+ if (delete_event) {
++ if (event->ref) {
++ ret = -EBUSY;
++ goto out;
++ }
+ remove_synth_event(event);
-+ goto err;
-+ } else
-+ ret = -EEXIST;
++ free_synth_event(event);
++ goto out;
++ }
++ ret = -EEXIST;
+ goto out;
+ } else if (delete_event) {
+ ret = -EINVAL;
@@ -645,7 +748,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+ if (argc < 2) {
+ ret = -EINVAL;
-+ goto err;
++ goto out;
+ }
+
+ for (i = 1; i < argc - 1; i++) {
@@ -653,16 +756,21 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ continue;
+ if (n_fields == SYNTH_FIELDS_MAX) {
+ ret = -EINVAL;
-+ goto out;
++ goto err;
+ }
-+ fields[n_fields] = parse_synth_field(argv[i], argv[i + 1]);
-+ if (!fields[n_fields])
++
++ field = parse_synth_field(argv[i], argv[i + 1]);
++ if (IS_ERR(field)) {
++ ret = PTR_ERR(field);
+ goto err;
++ }
++ fields[n_fields] = field;
+ i++; n_fields++;
+ }
++
+ if (i < argc) {
+ ret = -EINVAL;
-+ goto out;
++ goto err;
+ }
+
+ event = alloc_synth_event(name, n_fields, fields);
@@ -692,11 +800,18 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+ mutex_lock(&synth_event_mutex);
+
++ list_for_each_entry(event, &synth_event_list, list) {
++ if (event->ref) {
++ ret = -EBUSY;
++ goto out;
++ }
++ }
++
+ list_for_each_entry_safe(event, e, &synth_event_list, list) {
+ remove_synth_event(event);
+ free_synth_event(event);
+ }
-+
++ out:
+ mutex_unlock(&synth_event_mutex);
+
+ return ret;
@@ -780,7 +895,45 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static u64 hist_field_timestamp(struct hist_field *hist_field,
struct tracing_map_elt *elt,
struct ring_buffer_event *rbe,
-@@ -3028,3 +3731,38 @@ static __init void unregister_trigger_hi
+@@ -2933,6 +3751,8 @@ static int event_hist_trigger_func(struc
+ struct hist_trigger_attrs *attrs;
+ struct event_trigger_ops *trigger_ops;
+ struct hist_trigger_data *hist_data;
++ struct synth_event *se;
++ const char *se_name;
+ bool remove = false;
+ char *trigger;
+ int ret = 0;
+@@ -2991,6 +3811,14 @@ static int event_hist_trigger_func(struc
+ }
+
+ cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
++
++ mutex_lock(&synth_event_mutex);
++ se_name = trace_event_name(file->event_call);
++ se = find_synth_event(se_name);
++ if (se)
++ se->ref--;
++ mutex_unlock(&synth_event_mutex);
++
+ ret = 0;
+ goto out_free;
+ }
+@@ -3008,6 +3836,13 @@ static int event_hist_trigger_func(struc
+ } else if (ret < 0)
+ goto out_free;
+
++ mutex_lock(&synth_event_mutex);
++ se_name = trace_event_name(file->event_call);
++ se = find_synth_event(se_name);
++ if (se)
++ se->ref++;
++ mutex_unlock(&synth_event_mutex);
++
+ if (get_named_trigger_data(trigger_data))
+ goto enable;
+
+@@ -3198,3 +4033,31 @@ static __init void unregister_trigger_hi
return ret;
}
@@ -788,16 +941,9 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+static __init int trace_events_hist_init(void)
+{
+ struct dentry *entry = NULL;
-+ struct trace_array *tr;
+ struct dentry *d_tracer;
+ int err = 0;
+
-+ tr = top_trace_array();
-+ if (!tr) {
-+ err = -ENODEV;
-+ goto err;
-+ }
-+
+ d_tracer = tracing_init_dentry();
+ if (IS_ERR(d_tracer)) {
+ err = PTR_ERR(d_tracer);
@@ -805,7 +951,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ }
+
+ entry = tracefs_create_file("synthetic_events", 0644, d_tracer,
-+ tr, &synth_events_fops);
++ NULL, &synth_events_fops);
+ if (!entry) {
+ err = -ENODEV;
+ goto err;
diff --git a/patches/0028-tracing-Add-support-for-field-variables.patch b/patches/0028-tracing-Add-support-for-field-variables.patch
new file mode 100644
index 000000000000..ecadd73b2aaf
--- /dev/null
+++ b/patches/0028-tracing-Add-support-for-field-variables.patch
@@ -0,0 +1,567 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:40 -0500
+Subject: [PATCH 28/40] tracing: Add support for 'field variables'
+
+Users should be able to directly specify event fields in hist trigger
+'actions' rather than being forced to explicitly create a variable for
+that purpose.
+
+Add support allowing fields to be used directly in actions, which
+essentially does just that - creates 'invisible' variables for each
+bare field specified in an action. If a bare field refers to a field
+on another (matching) event, it even creates a special histogram for
+the purpose (since variables can't be defined on an existing histogram
+after histogram creation).
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace_events_hist.c | 452 ++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 451 insertions(+), 1 deletion(-)
+
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -254,6 +254,16 @@ struct hist_trigger_attrs {
+ struct var_defs var_defs;
+ };
+
++struct field_var {
++ struct hist_field *var;
++ struct hist_field *val;
++};
++
++struct field_var_hist {
++ struct hist_trigger_data *hist_data;
++ char *cmd;
++};
++
+ struct hist_trigger_data {
+ struct hist_field *fields[HIST_FIELDS_MAX];
+ unsigned int n_vals;
+@@ -274,6 +284,14 @@ struct hist_trigger_data {
+
+ struct action_data *actions[HIST_ACTIONS_MAX];
+ unsigned int n_actions;
++
++ struct hist_field *synth_var_refs[SYNTH_FIELDS_MAX];
++ unsigned int n_synth_var_refs;
++ struct field_var *field_vars[SYNTH_FIELDS_MAX];
++ unsigned int n_field_vars;
++ unsigned int n_field_var_str;
++ struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX];
++ unsigned int n_field_var_hists;
+ };
+
+ struct synth_field {
+@@ -1392,6 +1410,7 @@ static struct hist_field *find_event_var
+ struct hist_elt_data {
+ char *comm;
+ u64 *var_ref_vals;
++ char *field_var_str[SYNTH_FIELDS_MAX];
+ };
+
+ static u64 hist_field_var_ref(struct hist_field *hist_field,
+@@ -1669,7 +1688,14 @@ static inline void save_comm(char *comm,
+
+ static void hist_trigger_elt_data_free(struct tracing_map_elt *elt)
+ {
++ struct hist_trigger_data *hist_data = elt->map->private_data;
+ struct hist_elt_data *private_data = elt->private_data;
++ unsigned int i, n_str;
++
++ n_str = hist_data->n_field_var_str;
++
++ for (i = 0; i < n_str; i++)
++ kfree(private_data->field_var_str[i]);
+
+ kfree(private_data->comm);
+ kfree(private_data);
+@@ -1681,7 +1707,7 @@ static int hist_trigger_elt_data_alloc(s
+ unsigned int size = TASK_COMM_LEN + 1;
+ struct hist_elt_data *elt_data;
+ struct hist_field *key_field;
+- unsigned int i;
++ unsigned int i, n_str;
+
+ elt->private_data = elt_data = kzalloc(sizeof(*elt_data), GFP_KERNEL);
+ if (!elt_data)
+@@ -1701,6 +1727,18 @@ static int hist_trigger_elt_data_alloc(s
+ }
+ }
+
++ n_str = hist_data->n_field_var_str;
++
++ size = STR_VAR_LEN_MAX;
++
++ for (i = 0; i < n_str; i++) {
++ elt_data->field_var_str[i] = kzalloc(size, GFP_KERNEL);
++ if (!elt_data->field_var_str[i]) {
++ hist_trigger_elt_data_free(elt);
++ return -ENOMEM;
++ }
++ }
++
+ return 0;
+ }
+
+@@ -2347,6 +2385,387 @@ static struct hist_field *parse_expr(str
+ return ERR_PTR(ret);
+ }
+
++static char *find_trigger_filter(struct hist_trigger_data *hist_data,
++ struct trace_event_file *file)
++{
++ struct event_trigger_data *test;
++
++ list_for_each_entry_rcu(test, &file->triggers, list) {
++ if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
++ if (test->private_data == hist_data)
++ return test->filter_str;
++ }
++ }
++
++ return NULL;
++}
++
++static struct event_command trigger_hist_cmd;
++static int event_hist_trigger_func(struct event_command *cmd_ops,
++ struct trace_event_file *file,
++ char *glob, char *cmd, char *param);
++
++static bool compatible_keys(struct hist_trigger_data *target_hist_data,
++ struct hist_trigger_data *hist_data,
++ unsigned int n_keys)
++{
++ struct hist_field *target_hist_field, *hist_field;
++ unsigned int n, i, j;
++
++ if (hist_data->n_fields - hist_data->n_vals != n_keys)
++ return false;
++
++ i = hist_data->n_vals;
++ j = target_hist_data->n_vals;
++
++ for (n = 0; n < n_keys; n++) {
++ hist_field = hist_data->fields[i + n];
++ target_hist_field = hist_data->fields[j + n];
++
++ if (strcmp(hist_field->type, target_hist_field->type) != 0)
++ return false;
++ if (hist_field->size != target_hist_field->size)
++ return false;
++ if (hist_field->is_signed != target_hist_field->is_signed)
++ return false;
++ }
++
++ return true;
++}
++
++static struct hist_trigger_data *
++find_compatible_hist(struct hist_trigger_data *target_hist_data,
++ struct trace_event_file *file)
++{
++ struct hist_trigger_data *hist_data;
++ struct event_trigger_data *test;
++ unsigned int n_keys;
++
++ n_keys = target_hist_data->n_fields - target_hist_data->n_vals;
++
++ list_for_each_entry_rcu(test, &file->triggers, list) {
++ if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
++ hist_data = test->private_data;
++
++ if (compatible_keys(target_hist_data, hist_data, n_keys))
++ return hist_data;
++ }
++ }
++
++ return NULL;
++}
++
++static struct trace_event_file *event_file(struct trace_array *tr,
++ char *system, char *event_name)
++{
++ struct trace_event_file *file;
++
++ file = find_event_file(tr, system, event_name);
++ if (!file)
++ return ERR_PTR(-EINVAL);
++
++ return file;
++}
++
++static struct hist_field *
++create_field_var_hist(struct hist_trigger_data *target_hist_data,
++ char *system, char *event_name, char *field_name)
++{
++ struct trace_array *tr = target_hist_data->event_file->tr;
++ struct hist_field *event_var = ERR_PTR(-EINVAL);
++ struct hist_trigger_data *hist_data;
++ unsigned int i, n, first = true;
++ struct field_var_hist *var_hist;
++ struct trace_event_file *file;
++ struct hist_field *key_field;
++ char *saved_filter;
++ char *cmd;
++ int ret;
++
++ if (target_hist_data->n_field_var_hists >= SYNTH_FIELDS_MAX)
++ return ERR_PTR(-EINVAL);
++
++ file = event_file(tr, system, event_name);
++
++ if (IS_ERR(file)) {
++ ret = PTR_ERR(file);
++ return ERR_PTR(ret);
++ }
++
++ hist_data = find_compatible_hist(target_hist_data, file);
++ if (!hist_data)
++ return ERR_PTR(-EINVAL);
++
++ var_hist = kzalloc(sizeof(*var_hist), GFP_KERNEL);
++ if (!var_hist)
++ return ERR_PTR(-ENOMEM);
++
++ cmd = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
++ if (!cmd) {
++ kfree(var_hist);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ strcat(cmd, "keys=");
++
++ for_each_hist_key_field(i, hist_data) {
++ key_field = hist_data->fields[i];
++ if (!first)
++ strcat(cmd, ",");
++ strcat(cmd, key_field->field->name);
++ first = false;
++ }
++
++ strcat(cmd, ":synthetic_");
++ strcat(cmd, field_name);
++ strcat(cmd, "=");
++ strcat(cmd, field_name);
++
++ saved_filter = find_trigger_filter(hist_data, file);
++ if (saved_filter) {
++ strcat(cmd, " if ");
++ strcat(cmd, saved_filter);
++ }
++
++ var_hist->cmd = kstrdup(cmd, GFP_KERNEL);
++ if (!var_hist->cmd) {
++ kfree(cmd);
++ kfree(var_hist);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ var_hist->hist_data = hist_data;
++
++ ret = event_hist_trigger_func(&trigger_hist_cmd, file,
++ "", "hist", cmd);
++ if (ret) {
++ kfree(cmd);
++ kfree(var_hist->cmd);
++ kfree(var_hist);
++ return ERR_PTR(ret);
++ }
++
++ strcpy(cmd, "synthetic_");
++ strcat(cmd, field_name);
++
++ event_var = find_event_var(tr, system, event_name, cmd);
++ if (!event_var) {
++ kfree(cmd);
++ kfree(var_hist->cmd);
++ kfree(var_hist);
++ return ERR_PTR(-EINVAL);
++ }
++
++ n = target_hist_data->n_field_var_hists;
++ target_hist_data->field_var_hists[n] = var_hist;
++ target_hist_data->n_field_var_hists++;
++
++ return event_var;
++}
++
++static struct hist_field *
++find_target_event_var(struct hist_trigger_data *hist_data,
++ char *system, char *event_name, char *var_name)
++{
++ struct trace_event_file *file = hist_data->event_file;
++ struct hist_field *hist_field = NULL;
++
++ if (system) {
++ struct trace_event_call *call;
++
++ if (!event_name)
++ return NULL;
++
++ call = file->event_call;
++
++ if (strcmp(system, call->class->system) != 0)
++ return NULL;
++
++ if (strcmp(event_name, trace_event_name(call)) != 0)
++ return NULL;
++ }
++
++ hist_field = find_var_field(hist_data, var_name);
++
++ return hist_field;
++}
++
++static inline void __update_field_vars(struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *rec,
++ struct field_var **field_vars,
++ unsigned int n_field_vars,
++ unsigned int field_var_str_start)
++{
++ struct hist_elt_data *elt_data = elt->private_data;
++ unsigned int i, j, var_idx;
++ u64 var_val;
++
++ for (i = 0, j = field_var_str_start; i < n_field_vars; i++) {
++ struct field_var *field_var = field_vars[i];
++ struct hist_field *var = field_var->var;
++ struct hist_field *val = field_var->val;
++
++ var_val = val->fn(val, elt, rbe, rec);
++ var_idx = var->var.idx;
++
++ if (val->flags & HIST_FIELD_FL_STRING) {
++ char *str = elt_data->field_var_str[j++];
++ char *val_str = (char *)(uintptr_t)var_val;
++
++ strncpy(str, val_str, STR_VAR_LEN_MAX);
++ var_val = (u64)(uintptr_t)str;
++ }
++ tracing_map_set_var(elt, var_idx, var_val);
++ }
++}
++
++static void update_field_vars(struct hist_trigger_data *hist_data,
++ struct tracing_map_elt *elt,
++ struct ring_buffer_event *rbe,
++ void *rec)
++{
++ __update_field_vars(elt, rbe, rec, hist_data->field_vars,
++ hist_data->n_field_vars, 0);
++}
++
++static struct hist_field *create_var(struct hist_trigger_data *hist_data,
++ struct trace_event_file *file,
++ char *name, int size, const char *type)
++{
++ struct hist_field *var;
++ int idx;
++
++ if (find_var(file, name) && !hist_data->remove) {
++ var = ERR_PTR(-EINVAL);
++ goto out;
++ }
++
++ var = kzalloc(sizeof(struct hist_field), GFP_KERNEL);
++ if (!var) {
++ var = ERR_PTR(-ENOMEM);
++ goto out;
++ }
++
++ idx = tracing_map_add_var(hist_data->map);
++ if (idx < 0) {
++ kfree(var);
++ var = ERR_PTR(-EINVAL);
++ goto out;
++ }
++
++ var->flags = HIST_FIELD_FL_VAR;
++ var->var.idx = idx;
++ var->var.hist_data = var->hist_data = hist_data;
++ var->size = size;
++ var->var.name = kstrdup(name, GFP_KERNEL);
++ var->type = kstrdup(type, GFP_KERNEL);
++ if (!var->var.name || !var->type) {
++ kfree(var->var.name);
++ kfree(var->type);
++ kfree(var);
++ var = ERR_PTR(-ENOMEM);
++ }
++ out:
++ return var;
++}
++
++static struct field_var *create_field_var(struct hist_trigger_data *hist_data,
++ struct trace_event_file *file,
++ char *field_name)
++{
++ struct hist_field *val = NULL, *var = NULL;
++ unsigned long flags = HIST_FIELD_FL_VAR;
++ struct field_var *field_var;
++ int ret = 0;
++
++ if (hist_data->n_field_vars >= SYNTH_FIELDS_MAX) {
++ ret = -EINVAL;
++ goto err;
++ }
++
++ val = parse_atom(hist_data, file, field_name, &flags, NULL);
++ if (IS_ERR(val)) {
++ ret = PTR_ERR(val);
++ goto err;
++ }
++
++ var = create_var(hist_data, file, field_name, val->size, val->type);
++ if (IS_ERR(var)) {
++ kfree(val);
++ ret = PTR_ERR(var);
++ goto err;
++ }
++
++ field_var = kzalloc(sizeof(struct field_var), GFP_KERNEL);
++ if (!field_var) {
++ kfree(val);
++ kfree(var);
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ field_var->var = var;
++ field_var->val = val;
++ out:
++ return field_var;
++ err:
++ field_var = ERR_PTR(ret);
++ goto out;
++}
++
++static struct field_var *
++create_target_field_var(struct hist_trigger_data *hist_data,
++ char *system, char *event_name, char *var_name)
++{
++ struct trace_event_file *file = hist_data->event_file;
++
++ if (system) {
++ struct trace_event_call *call;
++
++ if (!event_name)
++ return NULL;
++
++ call = file->event_call;
++
++ if (strcmp(system, call->class->system) != 0)
++ return NULL;
++
++ if (strcmp(event_name, trace_event_name(call)) != 0)
++ return NULL;
++ }
++
++ return create_field_var(hist_data, file, var_name);
++}
++
++static void destroy_field_var(struct field_var *field_var)
++{
++ if (!field_var)
++ return;
++
++ destroy_hist_field(field_var->var, 0);
++ destroy_hist_field(field_var->val, 0);
++
++ kfree(field_var);
++}
++
++static void destroy_field_vars(struct hist_trigger_data *hist_data)
++{
++ unsigned int i;
++
++ for (i = 0; i < hist_data->n_field_vars; i++)
++ destroy_field_var(hist_data->field_vars[i]);
++}
++
++static void save_field_var(struct hist_trigger_data *hist_data,
++ struct field_var *field_var)
++{
++ hist_data->field_vars[hist_data->n_field_vars++] = field_var;
++
++ if (field_var->val->flags & HIST_FIELD_FL_STRING)
++ hist_data->n_field_var_str++;
++}
++
+ static int create_hitcount_val(struct hist_trigger_data *hist_data)
+ {
+ hist_data->fields[HITCOUNT_IDX] =
+@@ -2814,6 +3233,16 @@ static void print_actions_spec(struct se
+ }
+ }
+
++static void destroy_field_var_hists(struct hist_trigger_data *hist_data)
++{
++ unsigned int i;
++
++ for (i = 0; i < hist_data->n_field_var_hists; i++) {
++ kfree(hist_data->field_var_hists[i]->cmd);
++ kfree(hist_data->field_var_hists[i]);
++ }
++}
++
+ static void destroy_hist_data(struct hist_trigger_data *hist_data)
+ {
+ if (!hist_data)
+@@ -2824,6 +3253,8 @@ static void destroy_hist_data(struct his
+ tracing_map_destroy(hist_data->map);
+
+ destroy_actions(hist_data);
++ destroy_field_vars(hist_data);
++ destroy_field_var_hists(hist_data);
+
+ kfree(hist_data);
+ }
+@@ -2957,6 +3388,8 @@ static void hist_trigger_elt_update(stru
+ tracing_map_set_var(elt, var_idx, hist_val);
+ }
+ }
++
++ update_field_vars(hist_data, elt, rbe, rec);
+ }
+
+ static inline void add_to_key(char *compound_key, void *key,
+@@ -3677,6 +4110,21 @@ static bool hist_trigger_check_refs(stru
+ return false;
+ }
+
++static void unregister_field_var_hists(struct hist_trigger_data *hist_data)
++{
++ struct trace_event_file *file;
++ unsigned int i;
++ char *cmd;
++ int ret;
++
++ for (i = 0; i < hist_data->n_field_var_hists; i++) {
++ file = hist_data->field_var_hists[i]->hist_data->event_file;
++ cmd = hist_data->field_var_hists[i]->cmd;
++ ret = event_hist_trigger_func(&trigger_hist_cmd, file,
++ "!hist", "hist", cmd);
++ }
++}
++
+ static void hist_unregister_trigger(char *glob, struct event_trigger_ops *ops,
+ struct event_trigger_data *data,
+ struct trace_event_file *file)
+@@ -3692,6 +4140,7 @@ static void hist_unregister_trigger(char
+ if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
+ if (!hist_trigger_match(data, test, named_data, false))
+ continue;
++ unregister_field_var_hists(test->private_data);
+ unregistered = true;
+ list_del_rcu(&test->list);
+ trace_event_trigger_enable_disable(file, 0);
+@@ -3733,6 +4182,7 @@ static void hist_unreg_all(struct trace_
+
+ list_for_each_entry_safe(test, n, &file->triggers, list) {
+ if (test->cmd_ops->trigger_type == ETT_EVENT_HIST) {
++ unregister_field_var_hists(test->private_data);
+ list_del_rcu(&test->list);
+ trace_event_trigger_enable_disable(file, 0);
+ update_cond_flag(file);
diff --git a/patches/0029-tracing-Add-onmatch-hist-trigger-action-support.patch b/patches/0029-tracing-Add-onmatch-hist-trigger-action-support.patch
new file mode 100644
index 000000000000..85b59bde2318
--- /dev/null
+++ b/patches/0029-tracing-Add-onmatch-hist-trigger-action-support.patch
@@ -0,0 +1,550 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:41 -0500
+Subject: [PATCH 29/40] tracing: Add 'onmatch' hist trigger action support
+
+Add an 'onmatch(matching.event).<synthetic_event_name>(param list)'
+hist trigger action which is invoked with the set of variables or
+event fields named in the 'param list'. The result is the generation
+of a synthetic event that consists of the values contained in those
+variables and/or fields at the time the invoking event was hit.
+
+As an example the below defines a simple synthetic event using a
+variable defined on the sched_wakeup_new event, and shows the event
+definition with unresolved fields, since the sched_wakeup_new event
+with the testpid variable hasn't been defined yet:
+
+ # echo 'wakeup_new_test pid_t pid; int prio' >> \
+ /sys/kernel/debug/tracing/synthetic_events
+
+ # cat /sys/kernel/debug/tracing/synthetic_events
+ wakeup_new_test pid_t pid; int prio
+
+The following hist trigger both defines a testpid variable and
+specifies an onmatch() trace action that uses that variable along with
+a non-variable field to generate a wakeup_new_test synthetic event
+whenever a sched_wakeup_new event occurs, which because of the 'if
+comm == "cyclictest"' filter only happens when the executable is
+cyclictest:
+
+ # echo 'hist:testpid=pid:keys=$testpid:\
+ onmatch(sched.sched_wakeup_new).wakeup_new_test($testpid, prio) \
+ if comm=="cyclictest"' >> \
+ /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/trigger
+
+Creating and displaying a histogram based on those events is now just
+a matter of using the fields and new synthetic event in the
+tracing/events/synthetic directory, as usual:
+
+ # echo 'hist:keys=pid,prio:sort=pid,prio' >> \
+ /sys/kernel/debug/tracing/events/synthetic/wakeup_new_test/trigger
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace_events_hist.c | 394 +++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 382 insertions(+), 12 deletions(-)
+
+--- a/kernel/trace/trace_events_hist.c
++++ b/kernel/trace/trace_events_hist.c
+@@ -323,7 +323,18 @@ typedef void (*action_fn_t) (struct hist
+
+ struct action_data {
+ action_fn_t fn;
+- unsigned int var_ref_idx;
++ unsigned int n_params;
++ char *params[SYNTH_FIELDS_MAX];
++
++ union {
++ struct {
++ unsigned int var_ref_idx;
++ char *match_event;
++ char *match_event_system;
++ char *synth_event_name;
++ struct synth_event *synth_event;
++ } onmatch;
++ };
+ };
+
+ static LIST_HEAD(synth_event_list);
+@@ -927,6 +938,21 @@ static struct synth_event *alloc_synth_e
+ return event;
+ }
+
++static void action_trace(struct hist_trigger_data *hist_data,
++ struct tracing_map_elt *elt, void *rec,
++ struct ring_buffer_event *rbe,
++ struct action_data *data, u64 *var_ref_vals)
++{
++ struct synth_event *event = data->onmatch.synth_event;
++
++ trace_synth(event, var_ref_vals, data->onmatch.var_ref_idx);
++}
++
++struct hist_var_data {
++ struct list_head list;
++ struct hist_trigger_data *hist_data;
++};
++
+ static int create_synth_event(int argc, char **argv)
+ {
+ struct synth_field *field, *fields[SYNTH_FIELDS_MAX];
+@@ -967,10 +993,8 @@ static int create_synth_event(int argc,
+ }
+ ret = -EEXIST;
+ goto out;
+- } else if (delete_event) {
+- ret = -EINVAL;
++ } else if (delete_event)
+ goto out;
+- }
+
+ if (argc < 2) {
+ ret = -EINVAL;
+@@ -1134,11 +1158,6 @@ static u64 hist_field_timestamp(struct h
+ return ts;
+ }
+
+-struct hist_var_data {
+- struct list_head list;
+- struct hist_trigger_data *hist_data;
+-};
+-
+ static struct hist_field *check_var_ref(struct hist_field *hist_field,
+ struct hist_trigger_data *var_data,
+ unsigned int var_idx)
+@@ -1578,11 +1597,21 @@ static void destroy_hist_trigger_attrs(s
+
+ static int parse_action(char *str, struct hist_trigger_attrs *attrs)
+ {
+- int ret = 0;
++ int ret = -EINVAL;
+
+ if (attrs->n_actions >= HIST_ACTIONS_MAX)
+ return ret;
+
++ if ((strncmp(str, "onmatch(", strlen("onmatch(")) == 0)) {
++ attrs->action_str[attrs->n_actions] = kstrdup(str, GFP_KERNEL);
++ if (!attrs->action_str[attrs->n_actions]) {
++ ret = -ENOMEM;
++ return ret;
++ }
++ attrs->n_actions++;
++ ret = 0;
++ }
++
+ return ret;
+ }
+
+@@ -2420,7 +2449,7 @@ static bool compatible_keys(struct hist_
+
+ for (n = 0; n < n_keys; n++) {
+ hist_field = hist_data->fields[i + n];
+- target_hist_field = hist_data->fields[j + n];
++ target_hist_field = target_hist_data->fields[j + n];
+
+ if (strcmp(hist_field->type, target_hist_field->type) != 0)
+ return false;
+@@ -2738,6 +2767,27 @@ create_target_field_var(struct hist_trig
+ return create_field_var(hist_data, file, var_name);
+ }
+
++static void onmatch_destroy(struct action_data *data)
++{
++ unsigned int i;
++
++ mutex_lock(&synth_event_mutex);
++
++ kfree(data->onmatch.match_event);
++ kfree(data->onmatch.match_event_system);
++ kfree(data->onmatch.synth_event_name);
++
++ for (i = 0; i < data->n_params; i++)
++ kfree(data->params[i]);
++
++ kfree(data);
++
++ if (data->onmatch.synth_event)
++ data->onmatch.synth_event->ref--;
++
++ mutex_unlock(&synth_event_mutex);
++}
++
+ static void destroy_field_var(struct field_var *field_var)
+ {
+ if (!field_var)
+@@ -2766,6 +2816,281 @@ static void save_field_var(struct hist_t
+ hist_data->n_field_var_str++;
+ }
+
++
++static void destroy_synth_var_refs(struct hist_trigger_data *hist_data)
++{
++ unsigned int i;
++
++ for (i = 0; i < hist_data->n_synth_var_refs; i++)
++ destroy_hist_field(hist_data->synth_var_refs[i], 0);
++}
++
++static void save_synth_var_ref(struct hist_trigger_data *hist_data,
++ struct hist_field *var_ref)
++{
++ hist_data->synth_var_refs[hist_data->n_synth_var_refs++] = var_ref;
++
++ hist_data->var_refs[hist_data->n_var_refs] = var_ref;
++ var_ref->var_ref_idx = hist_data->n_var_refs++;
++}
++
++static int check_synth_field(struct synth_event *event,
++ struct hist_field *hist_field,
++ unsigned int field_pos)
++{
++ struct synth_field *field;
++
++ if (field_pos >= event->n_fields)
++ return -EINVAL;
++
++ field = event->fields[field_pos];
++
++ if (strcmp(field->type, hist_field->type) != 0)
++ return -EINVAL;
++
++ return 0;
++}
++
++static int parse_action_params(char *params, struct action_data *data)
++{
++ char *param, *saved_param;
++ int ret = 0;
++
++ while (params) {
++ if (data->n_params >= SYNTH_FIELDS_MAX)
++ goto out;
++
++ param = strsep(&params, ",");
++ if (!param)
++ goto out;
++
++ param = strstrip(param);
++ if (strlen(param) < 2) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ saved_param = kstrdup(param, GFP_KERNEL);
++ if (!saved_param) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ data->params[data->n_params++] = saved_param;
++ }
++ out:
++ return ret;
++}
++
++static struct hist_field *
++onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data,
++ char *system, char *event, char *var)
++{
++ struct trace_array *tr = hist_data->event_file->tr;
++ struct hist_field *hist_field;
++
++ var++; /* skip '$' */
++
++ hist_field = find_target_event_var(hist_data, system, event, var);
++ if (!hist_field) {
++ if (!system) {
++ system = data->onmatch.match_event_system;
++ event = data->onmatch.match_event;
++ }
++
++ hist_field = find_event_var(tr, system, event, var);
++ }
++
++ return hist_field;
++}
++
++static struct hist_field *
++onmatch_create_field_var(struct hist_trigger_data *hist_data,
++ struct action_data *data, char *system,
++ char *event, char *var)
++{
++ struct hist_field *hist_field = NULL;
++ struct field_var *field_var;
++
++ field_var = create_target_field_var(hist_data, system, event, var);
++ if (IS_ERR(field_var))
++ goto out;
++
++ if (field_var) {
++ save_field_var(hist_data, field_var);
++ hist_field = field_var->var;
++ } else {
++ if (!system) {
++ system = data->onmatch.match_event_system;
++ event = data->onmatch.match_event;
++ }
++
++ hist_field = create_field_var_hist(hist_data, system, event, var);
++ if (IS_ERR(hist_field))
++ goto free;
++ }
++ out:
++ return hist_field;
++ free:
++ destroy_field_var(field_var);
++ hist_field = NULL;
++ goto out;
++}
++
++static int onmatch_create(struct hist_trigger_data *hist_data,
++ struct trace_event_file *file,
++ struct action_data *data)
++{
++ char *event_name, *param, *system = NULL;
++ struct hist_field *hist_field, *var_ref;
++ unsigned int i, var_ref_idx;
++ unsigned int field_pos = 0;
++ struct synth_event *event;
++ int ret = 0;
++
++ mutex_lock(&synth_event_mutex);
++
++ event = find_synth_event(data->onmatch.synth_event_name);
++ if (!event) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ var_ref_idx = hist_data->n_var_refs;
++
++ for (i = 0; i < data->n_params; i++) {
++ char *p;
++
++ p = param = kstrdup(data->params[i], GFP_KERNEL);
++ if (!param)
++ goto out;
++
++ system = strsep(&param, ".");
++ if (!param) {
++ param = (char *)system;
++ system = event_name = NULL;
++ } else {
++ event_name = strsep(&param, ".");
++ if (!param) {
++ kfree(p);
++ ret = -EINVAL;
++ goto out;
++ }
++ }
++
++ if (param[0] == '$')
++ hist_field = onmatch_find_var(hist_data, data, system,
++ event_name, param);
++ else
++ hist_field = onmatch_create_field_var(hist_data, data,
++ system,
++ event_name,
++ param);
++
++ if (!hist_field) {
++ kfree(p);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (check_synth_field(event, hist_field, field_pos) == 0) {
++ var_ref = create_var_ref(hist_field);
++ if (!var_ref) {
++ kfree(p);
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ save_synth_var_ref(hist_data, var_ref);
++ field_pos++;
++ kfree(p);
++ continue;
++ }
++
++ kfree(p);
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (field_pos != event->n_fields) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ data->fn = action_trace;
++ data->onmatch.synth_event = event;
++ data->onmatch.var_ref_idx = var_ref_idx;
++ hist_data->actions[hist_data->n_actions++] = data;
++ event->ref++;
++ out:
++ mutex_unlock(&synth_event_mutex);
++
++ return ret;
++}
++
++static struct action_data *onmatch_parse(struct trace_array *tr, char *str)
++{
++ char *match_event, *match_event_system;
++ char *synth_event_name, *params;
++ struct action_data *data;
++ int ret = -EINVAL;
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return ERR_PTR(-ENOMEM);
++
++ match_event = strsep(&str, ")");
++ if (!match_event || !str)
++ goto free;
++
++ match_event_system = strsep(&match_event, ".");
++ if (!match_event)
++ goto free;
++
++ if (IS_ERR(event_file(tr, match_event_system, match_event)))
++ goto free;
++
++ data->onmatch.match_event = kstrdup(match_event, GFP_KERNEL);
++ if (!data->onmatch.match_event) {
++ ret = -ENOMEM;
++ goto free;
++ }
++
++ data->onmatch.match_event_system = kstrdup(match_event_system, GFP_KERNEL);
++ if (!data->onmatch.match_event_system) {
++ ret = -ENOMEM;
++ goto free;
++ }
++
++ strsep(&str, ".");
++ if (!str)
++ goto free;
++
++ synth_event_name = strsep(&str, "(");
++ if (!synth_event_name || !str)
++ goto free;
++
++ data->onmatch.synth_event_name = kstrdup(synth_event_name, GFP_KERNEL);
++ if (!data->onmatch.synth_event_name) {
++ ret = -ENOMEM;
++ goto free;
++ }
++
++ params = strsep(&str, ")");
++ if (!params || !str || (str && strlen(str)))
++ goto free;
++
++ ret = parse_action_params(params, data);
++ if (ret)
++ goto free;
++ out:
++ return data;
++ free:
++ onmatch_destroy(data);
++ data = ERR_PTR(ret);
++ goto out;
++}
++
+ static int create_hitcount_val(struct hist_trigger_data *hist_data)
+ {
+ hist_data->fields[HITCOUNT_IDX] =
+@@ -3194,19 +3519,38 @@ static void destroy_actions(struct hist_
+ for (i = 0; i < hist_data->n_actions; i++) {
+ struct action_data *data = hist_data->actions[i];
+
+- kfree(data);
++ if (data->fn == action_trace)
++ onmatch_destroy(data);
++ else
++ kfree(data);
+ }
+ }
+
+ static int create_actions(struct hist_trigger_data *hist_data,
+ struct trace_event_file *file)
+ {
++ struct trace_array *tr = hist_data->event_file->tr;
++ struct action_data *data;
+ unsigned int i;
+ int ret = 0;
+ char *str;
+
+ for (i = 0; i < hist_data->attrs->n_actions; i++) {
+ str = hist_data->attrs->action_str[i];
++
++ if (strncmp(str, "onmatch(", strlen("onmatch(")) == 0) {
++ char *action_str = str + strlen("onmatch(");
++
++ data = onmatch_parse(tr, action_str);
++ if (IS_ERR(data))
++ return PTR_ERR(data);
++
++ ret = onmatch_create(hist_data, file, data);
++ if (ret) {
++ onmatch_destroy(data);
++ return ret;
++ }
++ }
+ }
+
+ return ret;
+@@ -3223,6 +3567,26 @@ static void print_actions(struct seq_fil
+ }
+ }
+
++static void print_onmatch_spec(struct seq_file *m,
++ struct hist_trigger_data *hist_data,
++ struct action_data *data)
++{
++ unsigned int i;
++
++ seq_printf(m, ":onmatch(%s.%s).", data->onmatch.match_event_system,
++ data->onmatch.match_event);
++
++ seq_printf(m, "%s(", data->onmatch.synth_event->name);
++
++ for (i = 0; i < data->n_params; i++) {
++ if (i)
++ seq_puts(m, ",");
++ seq_printf(m, "%s", data->params[i]);
++ }
++
++ seq_puts(m, ")");
++}
++
+ static void print_actions_spec(struct seq_file *m,
+ struct hist_trigger_data *hist_data)
+ {
+@@ -3230,6 +3594,9 @@ static void print_actions_spec(struct se
+
+ for (i = 0; i < hist_data->n_actions; i++) {
+ struct action_data *data = hist_data->actions[i];
++
++ if (data->fn == action_trace)
++ print_onmatch_spec(m, hist_data, data);
+ }
+ }
+
+@@ -3255,6 +3622,7 @@ static void destroy_hist_data(struct his
+ destroy_actions(hist_data);
+ destroy_field_vars(hist_data);
+ destroy_field_var_hists(hist_data);
++ destroy_synth_var_refs(hist_data);
+
+ kfree(hist_data);
+ }
+@@ -3603,6 +3971,8 @@ hist_trigger_entry_print(struct seq_file
+ }
+ }
+
++ print_actions(m, hist_data, elt);
++
+ seq_puts(m, "\n");
+ }
+
diff --git a/patches/0024-tracing-Add-onmax-hist-trigger-action-support.patch b/patches/0030-tracing-Add-onmax-hist-trigger-action-support.patch
index 3fe92f608abc..61c4e76e3a7b 100644
--- a/patches/0024-tracing-Add-onmax-hist-trigger-action-support.patch
+++ b/patches/0030-tracing-Add-onmax-hist-trigger-action-support.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:25 -0500
-Subject: [PATCH 24/32] tracing: Add 'onmax' hist trigger action support
+Date: Tue, 5 Sep 2017 16:57:42 -0500
+Subject: [PATCH 30/40] tracing: Add 'onmax' hist trigger action support
Add an 'onmax(var).save(field,...)' hist trigger action which is
invoked whenever an event exceeds the current maximum.
@@ -20,12 +20,12 @@ the timestamp difference is calculated. If the resulting latency
exceeds the current maximum latency, the specified save() values are
saved:
- # echo 'hist:keys=pid:ts0=common_timestamp.usecs \
+ # echo 'hist:keys=pid:ts0=$common_timestamp.usecs \
if comm=="cyclictest"' >> \
/sys/kernel/debug/tracing/events/sched/sched_wakeup/trigger
# echo 'hist:keys=next_pid:\
- wakeup_lat=common_timestamp.usecs-$ts0:\
+ wakeup_lat=$common_timestamp.usecs-$ts0:\
onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) \
if next_comm=="cyclictest"' >> \
/sys/kernel/debug/tracing/events/sched/sched_switch/trigger
@@ -35,28 +35,31 @@ corresponding to the max are displayed following the rest of the
fields:
# cat /sys/kernel/debug/tracing/events/sched/sched_switch/hist
- { next_pid: 2255 } hitcount: 239 \
- common_timestamp-$ts0: 0
- max: 27 next_comm: cyclictest \
- prev_pid: 0 prev_prio: 120 prev_comm: swapper/1 \
- { next_pid: 2256 } hitcount: 2355 common_timestamp-$ts0: 0 \
- max: 49 next_comm: cyclictest \
- prev_pid: 0 prev_prio: 120 prev_comm: swapper/0
+
+ { next_pid: 3728 } hitcount: 199 \
+ max: 123 next_comm: cyclictest prev_pid: 0 \
+ prev_prio: 120 prev_comm: swapper/3
+ { next_pid: 3730 } hitcount: 1321 \
+ max: 15 next_comm: cyclictest prev_pid: 0 \
+ prev_prio: 120 prev_comm: swapper/1
+ { next_pid: 3729 } hitcount: 1973\
+ max: 25 next_comm: cyclictest prev_pid: 0 \
+ prev_prio: 120 prev_comm: swapper/0
Totals:
- Hits: 12970
- Entries: 2
- Dropped: 0
+ Hits: 3493
+ Entries: 3
+ Dropped: 0
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/trace_events_hist.c | 310 ++++++++++++++++++++++++++++++++++-----
- 1 file changed, 276 insertions(+), 34 deletions(-)
+ kernel/trace/trace_events_hist.c | 313 ++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 279 insertions(+), 34 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -282,6 +282,10 @@ struct hist_trigger_data {
+@@ -292,6 +292,10 @@ struct hist_trigger_data {
unsigned int n_field_var_str;
struct field_var_hist *field_var_hists[SYNTH_FIELDS_MAX];
unsigned int n_field_var_hists;
@@ -67,20 +70,22 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
};
struct synth_field {
-@@ -318,6 +322,12 @@ struct action_data {
- char *match_event_system;
- char *synth_event_name;
- struct synth_event *synth_event;
-+
-+ char *onmax_var_str;
-+ char *onmax_fn_name;
-+ unsigned int max_var_ref_idx;
-+ struct hist_field *max_var;
-+ struct hist_field *onmax_var;
+@@ -334,6 +338,14 @@ struct action_data {
+ char *synth_event_name;
+ struct synth_event *synth_event;
+ } onmatch;
++
++ struct {
++ char *var_str;
++ char *fn_name;
++ unsigned int max_var_ref_idx;
++ struct hist_field *max_var;
++ struct hist_field *var;
++ } onmax;
+ };
};
- static LIST_HEAD(synth_event_list);
-@@ -1493,7 +1503,8 @@ static int parse_action(char *str, struc
+@@ -1602,7 +1614,8 @@ static int parse_action(char *str, struc
if (attrs->n_actions >= HIST_ACTIONS_MAX)
return ret;
@@ -90,7 +95,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
attrs->action_str[attrs->n_actions] = kstrdup(str, GFP_KERNEL);
if (!attrs->action_str[attrs->n_actions]) {
ret = -ENOMEM;
-@@ -1612,7 +1623,7 @@ static void hist_trigger_elt_data_free(s
+@@ -1721,7 +1734,7 @@ static void hist_trigger_elt_data_free(s
struct hist_elt_data *private_data = elt->private_data;
unsigned int i, n_str;
@@ -99,16 +104,16 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
for (i = 0; i < n_str; i++)
kfree(private_data->field_var_str[i]);
-@@ -1647,7 +1658,7 @@ static int hist_trigger_elt_data_alloc(s
+@@ -1756,7 +1769,7 @@ static int hist_trigger_elt_data_alloc(s
}
}
- n_str = hist_data->n_field_var_str;
+ n_str = hist_data->n_field_var_str + hist_data->n_max_var_str;
- for (i = 0; i < n_str; i++) {
- elt_data->field_var_str[i] = kzalloc(size, GFP_KERNEL);
-@@ -2504,6 +2515,15 @@ static void update_field_vars(struct his
+ size = STR_VAR_LEN_MAX;
+
+@@ -2658,6 +2671,15 @@ static void update_field_vars(struct his
hist_data->n_field_vars, 0);
}
@@ -124,7 +129,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static struct hist_field *create_var(struct hist_trigger_data *hist_data,
struct trace_event_file *file,
char *name, int size, const char *type)
-@@ -2613,6 +2633,222 @@ create_target_field_var(struct hist_trig
+@@ -2767,6 +2789,223 @@ create_target_field_var(struct hist_trig
return create_field_var(hist_data, file, var_name);
}
@@ -133,7 +138,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct tracing_map_elt *elt,
+ struct action_data *data)
+{
-+ unsigned int i, save_var_idx, max_idx = data->max_var->var.idx;
++ unsigned int i, save_var_idx, max_idx = data->onmax.max_var->var.idx;
+
+ seq_printf(m, "\n\tmax: %10llu", tracing_map_read_var(elt, max_idx));
+
@@ -147,7 +152,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ val = tracing_map_read_var(elt, save_var_idx);
+
+ if (save_val->flags & HIST_FIELD_FL_STRING) {
-+ seq_printf(m, " %s: %-50s", save_var->var.name,
++ seq_printf(m, " %s: %-32s", save_var->var.name,
+ (char *)(uintptr_t)(val));
+ } else
+ seq_printf(m, " %s: %10llu", save_var->var.name, val);
@@ -159,8 +164,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ struct ring_buffer_event *rbe,
+ struct action_data *data, u64 *var_ref_vals)
+{
-+ unsigned int max_idx = data->max_var->var.idx;
-+ unsigned int max_var_ref_idx = data->max_var_ref_idx;
++ unsigned int max_idx = data->onmax.max_var->var.idx;
++ unsigned int max_var_ref_idx = data->onmax.max_var_ref_idx;
+
+ u64 var_val, max_val;
+
@@ -179,11 +184,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+{
+ unsigned int i;
+
-+ destroy_hist_field(data->max_var, 0);
-+ destroy_hist_field(data->onmax_var, 0);
++ destroy_hist_field(data->onmax.max_var, 0);
++ destroy_hist_field(data->onmax.var, 0);
+
-+ kfree(data->onmax_var_str);
-+ kfree(data->onmax_fn_name);
++ kfree(data->onmax.var_str);
++ kfree(data->onmax.fn_name);
+
+ for (i = 0; i < data->n_params; i++)
+ kfree(data->params[i]);
@@ -205,7 +210,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ unsigned int i;
+ int ret = 0;
+
-+ onmax_var_str = data->onmax_var_str;
++ onmax_var_str = data->onmax.var_str;
+ if (onmax_var_str[0] != '$')
+ return -EINVAL;
+ onmax_var_str++;
@@ -220,27 +225,23 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ if (!ref_field)
+ return -ENOMEM;
+
-+ ref_field->var.idx = var_field->var.idx;
-+ ref_field->var.hist_data = hist_data;
-+ ref_field->name = kstrdup(var_field->var.name, GFP_KERNEL);
-+ ref_field->type = kstrdup(var_field->type, GFP_KERNEL);
-+ if (!ref_field->name || !ref_field->type) {
++ if (init_var_ref(ref_field, var_field)) {
+ destroy_hist_field(ref_field, 0);
+ ret = -ENOMEM;
+ goto out;
+ }
+ hist_data->var_refs[hist_data->n_var_refs] = ref_field;
+ ref_field->var_ref_idx = hist_data->n_var_refs++;
-+ data->onmax_var = ref_field;
++ data->onmax.var = ref_field;
+
+ data->fn = onmax_save;
-+ data->max_var_ref_idx = var_ref_idx;
++ data->onmax.max_var_ref_idx = var_ref_idx;
+ max_var = create_var(hist_data, file, "max", sizeof(u64), "u64");
+ if (IS_ERR(max_var)) {
+ ret = PTR_ERR(max_var);
+ goto out;
+ }
-+ data->max_var = max_var;
++ data->onmax.max_var = max_var;
+
+ for (i = 0; i < data->n_params; i++) {
+ param = kstrdup(data->params[i], GFP_KERNEL);
@@ -310,7 +311,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ onmax_var_str = strsep(&str, ")");
+ if (!onmax_var_str || !str)
+ return ERR_PTR(-EINVAL);
-+ data->onmax_var_str = kstrdup(onmax_var_str, GFP_KERNEL);
++ data->onmax.var_str = kstrdup(onmax_var_str, GFP_KERNEL);
++ if (!data->onmax.var_str) {
++ ret = -ENOMEM;
++ goto free;
++ }
+
+ strsep(&str, ".");
+ if (!str)
@@ -329,10 +334,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ ret = parse_action_params(params, data);
+ if (ret)
+ goto free;
-+ }
-+ data->onmax_fn_name = kstrdup(onmax_fn_name, GFP_KERNEL);
++ } else
++ goto free;
+
-+ if (!data->onmax_var_str || !data->onmax_fn_name) {
++ data->onmax.fn_name = kstrdup(onmax_fn_name, GFP_KERNEL);
++ if (!data->onmax.fn_name) {
+ ret = -ENOMEM;
+ goto free;
+ }
@@ -347,7 +353,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static void onmatch_destroy(struct action_data *data)
{
unsigned int i;
-@@ -2689,37 +2925,6 @@ static int check_synth_field(struct synt
+@@ -2851,37 +3090,6 @@ static int check_synth_field(struct synt
return 0;
}
@@ -385,7 +391,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static struct hist_field *
onmatch_find_var(struct hist_trigger_data *hist_data, struct action_data *data,
char *system, char *event, char *var)
-@@ -3313,6 +3518,8 @@ static void destroy_actions(struct hist_
+@@ -3521,6 +3729,8 @@ static void destroy_actions(struct hist_
if (data->fn == action_trace)
onmatch_destroy(data);
@@ -394,7 +400,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
else
kfree(data);
}
-@@ -3341,6 +3548,18 @@ static int create_actions(struct hist_tr
+@@ -3550,6 +3760,18 @@ static int create_actions(struct hist_tr
onmatch_destroy(data);
return ret;
}
@@ -413,7 +419,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
}
-@@ -3355,9 +3574,30 @@ static void print_actions(struct seq_fil
+@@ -3564,9 +3786,30 @@ static void print_actions(struct seq_fil
for (i = 0; i < hist_data->n_actions; i++) {
struct action_data *data = hist_data->actions[i];
@@ -430,8 +436,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ unsigned int i;
+
+ seq_puts(m, ":onmax(");
-+ seq_printf(m, "%s", data->onmax_var_str);
-+ seq_printf(m, ").%s(", data->onmax_fn_name);
++ seq_printf(m, "%s", data->onmax.var_str);
++ seq_printf(m, ").%s(", data->onmax.fn_name);
+
+ for (i = 0; i < hist_data->n_max_vars; i++) {
+ seq_printf(m, "%s", hist_data->max_vars[i]->var->var.name);
@@ -444,7 +450,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static void print_onmatch_spec(struct seq_file *m,
struct hist_trigger_data *hist_data,
struct action_data *data)
-@@ -3388,6 +3628,8 @@ static void print_actions_spec(struct se
+@@ -3597,6 +3840,8 @@ static void print_actions_spec(struct se
if (data->fn == action_trace)
print_onmatch_spec(m, hist_data, data);
diff --git a/patches/0025-tracing-Allow-whitespace-to-surround-hist-trigger-fi.patch b/patches/0031-tracing-Allow-whitespace-to-surround-hist-trigger-fi.patch
index 9c88c398bcdf..1694bb042120 100644
--- a/patches/0025-tracing-Allow-whitespace-to-surround-hist-trigger-fi.patch
+++ b/patches/0031-tracing-Allow-whitespace-to-surround-hist-trigger-fi.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:26 -0500
-Subject: [PATCH 25/32] tracing: Allow whitespace to surround hist trigger
+Date: Tue, 5 Sep 2017 16:57:43 -0500
+Subject: [PATCH 31/40] tracing: Allow whitespace to surround hist trigger
filter
The existing code only allows for one space before and after the 'if'
@@ -15,16 +15,16 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -4632,7 +4632,7 @@ static int event_hist_trigger_func(struc
- struct event_trigger_ops *trigger_ops;
- struct hist_trigger_data *hist_data;
+@@ -4819,7 +4819,7 @@ static int event_hist_trigger_func(struc
+ struct synth_event *se;
+ const char *se_name;
bool remove = false;
- char *trigger;
+ char *trigger, *p;
int ret = 0;
if (!param)
-@@ -4642,9 +4642,19 @@ static int event_hist_trigger_func(struc
+@@ -4829,9 +4829,19 @@ static int event_hist_trigger_func(struc
remove = true;
/* separate the trigger from the filter (k:v [if filter]) */
@@ -47,7 +47,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
attrs = parse_hist_trigger_attrs(trigger);
if (IS_ERR(attrs))
-@@ -4694,6 +4704,7 @@ static int event_hist_trigger_func(struc
+@@ -4889,6 +4899,7 @@ static int event_hist_trigger_func(struc
}
ret = cmd_ops->reg(glob, trigger_ops, trigger_data, file);
diff --git a/patches/0027-tracing-Add-cpu-field-for-hist-triggers.patch b/patches/0032-tracing-Add-cpu-field-for-hist-triggers.patch
index 3312a4c53402..099409f5133f 100644
--- a/patches/0027-tracing-Add-cpu-field-for-hist-triggers.patch
+++ b/patches/0032-tracing-Add-cpu-field-for-hist-triggers.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:28 -0500
-Subject: [PATCH 27/32] tracing: Add cpu field for hist triggers
+Date: Tue, 5 Sep 2017 16:57:44 -0500
+Subject: [PATCH 32/40] tracing: Add cpu field for hist triggers
A common key to use in a histogram is the cpuid - add a new cpu
'synthetic' field for that purpose. This field is named cpu rather
@@ -44,15 +44,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---------------------------
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -224,6 +224,7 @@ enum hist_field_flags {
+@@ -226,6 +226,7 @@ enum hist_field_flags {
HIST_FIELD_FL_VAR_ONLY = 8192,
HIST_FIELD_FL_EXPR = 16384,
HIST_FIELD_FL_VAR_REF = 32768,
+ HIST_FIELD_FL_CPU = 65536,
};
- struct hist_trigger_attrs {
-@@ -1081,6 +1082,16 @@ static u64 hist_field_timestamp(struct h
+ struct var_defs {
+@@ -1170,6 +1171,16 @@ static u64 hist_field_timestamp(struct h
return ts;
}
@@ -69,7 +69,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static struct hist_field *check_var_ref(struct hist_field *hist_field,
struct hist_trigger_data *var_data,
unsigned int var_idx)
-@@ -1407,6 +1418,8 @@ static const char *hist_field_name(struc
+@@ -1518,6 +1529,8 @@ static const char *hist_field_name(struc
field_name = hist_field_name(field->operands[0], ++level);
else if (field->flags & HIST_FIELD_FL_TIMESTAMP)
field_name = "$common_timestamp";
@@ -78,7 +78,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
else if (field->flags & HIST_FIELD_FL_EXPR ||
field->flags & HIST_FIELD_FL_VAR_REF)
field_name = field->name;
-@@ -1848,6 +1861,15 @@ static struct hist_field *create_hist_fi
+@@ -1990,6 +2003,15 @@ static struct hist_field *create_hist_fi
goto out;
}
@@ -94,7 +94,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (WARN_ON_ONCE(!field))
goto out;
-@@ -1980,7 +2002,9 @@ parse_field(struct hist_trigger_data *hi
+@@ -2182,7 +2204,9 @@ parse_field(struct hist_trigger_data *hi
hist_data->enable_timestamps = true;
if (*flags & HIST_FIELD_FL_TIMESTAMP_USECS)
hist_data->attrs->ts_in_usecs = true;
@@ -103,9 +103,9 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *flags |= HIST_FIELD_FL_CPU;
+ else {
field = trace_find_event_field(file->event_call, field_name);
- if (!field)
- return ERR_PTR(-EINVAL);
-@@ -3019,7 +3043,6 @@ static int onmatch_create(struct hist_tr
+ if (!field || !field->size) {
+ field = ERR_PTR(-EINVAL);
+@@ -3185,7 +3209,6 @@ static int onmatch_create(struct hist_tr
goto out;
}
}
@@ -113,7 +113,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (param[0] == '$')
hist_field = onmatch_find_var(hist_data, data, system,
event_name, param);
-@@ -3034,7 +3057,6 @@ static int onmatch_create(struct hist_tr
+@@ -3200,7 +3223,6 @@ static int onmatch_create(struct hist_tr
ret = -EINVAL;
goto out;
}
@@ -121,7 +121,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (check_synth_field(event, hist_field, field_pos) == 0) {
var_ref = create_var_ref(hist_field);
if (!var_ref) {
-@@ -4128,6 +4150,8 @@ static void hist_field_print(struct seq_
+@@ -4315,6 +4337,8 @@ static void hist_field_print(struct seq_
if (hist_field->flags & HIST_FIELD_FL_TIMESTAMP)
seq_puts(m, "$common_timestamp");
diff --git a/patches/0028-tracing-Add-hist-trigger-support-for-variable-refere.patch b/patches/0033-tracing-Add-hist-trigger-support-for-variable-refere.patch
index 6993202a8e00..e6ca275f7f7d 100644
--- a/patches/0028-tracing-Add-hist-trigger-support-for-variable-refere.patch
+++ b/patches/0033-tracing-Add-hist-trigger-support-for-variable-refere.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:29 -0500
-Subject: [PATCH 28/32] tracing: Add hist trigger support for variable
+Date: Tue, 5 Sep 2017 16:57:45 -0500
+Subject: [PATCH 33/40] tracing: Add hist trigger support for variable
reference aliases
Add support for alias=$somevar where alias can be used as
@@ -9,20 +9,20 @@ onmatch($alias).
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- kernel/trace/trace_events_hist.c | 46 ++++++++++++++++++++++++++++++++++++---
- 1 file changed, 43 insertions(+), 3 deletions(-)
+ kernel/trace/trace_events_hist.c | 61 +++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 58 insertions(+), 3 deletions(-)
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -225,6 +225,7 @@ enum hist_field_flags {
+@@ -227,6 +227,7 @@ enum hist_field_flags {
HIST_FIELD_FL_EXPR = 16384,
HIST_FIELD_FL_VAR_REF = 32768,
HIST_FIELD_FL_CPU = 65536,
+ HIST_FIELD_FL_ALIAS = 131072,
};
- struct hist_trigger_attrs {
-@@ -1414,7 +1415,8 @@ static const char *hist_field_name(struc
+ struct var_defs {
+@@ -1525,7 +1526,8 @@ static const char *hist_field_name(struc
if (field->field)
field_name = field->field->name;
@@ -32,7 +32,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
field_name = hist_field_name(field->operands[0], ++level);
else if (field->flags & HIST_FIELD_FL_TIMESTAMP)
field_name = "$common_timestamp";
-@@ -1819,7 +1821,7 @@ static struct hist_field *create_hist_fi
+@@ -1961,7 +1963,7 @@ static struct hist_field *create_hist_fi
hist_field->hist_data = hist_data;
@@ -41,7 +41,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
goto out; /* caller will populate */
if (flags & HIST_FIELD_FL_VAR_REF) {
-@@ -2013,6 +2015,34 @@ parse_field(struct hist_trigger_data *hi
+@@ -2219,6 +2221,29 @@ parse_field(struct hist_trigger_data *hi
return field;
}
@@ -59,13 +59,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+ alias->fn = var_ref->fn;
+ alias->operands[0] = var_ref;
-+ alias->var.idx = var_ref->var.idx;
-+ alias->var.hist_data = var_ref->hist_data;
-+ alias->size = var_ref->size;
-+ alias->is_signed = var_ref->is_signed;
-+ alias->type = kstrdup(var_ref->type, GFP_KERNEL);
-+ if (!alias->type) {
-+ kfree(alias->type);
++
++ if (init_var_ref(alias, var_ref)) {
+ destroy_hist_field(alias, 0);
+ return NULL;
+ }
@@ -76,21 +71,48 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
struct hist_field *parse_atom(struct hist_trigger_data *hist_data,
struct trace_event_file *file, char *str,
unsigned long *flags, char *var_name)
-@@ -2036,6 +2066,13 @@ struct hist_field *parse_atom(struct his
- if (hist_field) {
- hist_data->var_refs[hist_data->n_var_refs] = hist_field;
- hist_field->var_ref_idx = hist_data->n_var_refs++;
-+ if (var_name) {
-+ hist_field = create_alias(hist_data, hist_field, var_name);
-+ if (!hist_field) {
-+ ret = -ENOMEM;
-+ goto out;
+@@ -2245,6 +2270,13 @@ struct hist_field *parse_atom(struct his
+ if (hist_field) {
+ hist_data->var_refs[hist_data->n_var_refs] = hist_field;
+ hist_field->var_ref_idx = hist_data->n_var_refs++;
++ if (var_name) {
++ hist_field = create_alias(hist_data, hist_field, var_name);
++ if (!hist_field) {
++ ret = -ENOMEM;
++ goto out;
++ }
+ }
-+ }
- return hist_field;
- }
+ return hist_field;
+ }
+ } else
+@@ -2346,6 +2378,26 @@ static int check_expr_operands(struct hi
+ unsigned long operand1_flags = operand1->flags;
+ unsigned long operand2_flags = operand2->flags;
-@@ -4152,8 +4189,11 @@ static void hist_field_print(struct seq_
++ if ((operand1_flags & HIST_FIELD_FL_VAR_REF) ||
++ (operand1_flags & HIST_FIELD_FL_ALIAS)) {
++ struct hist_field *var;
++
++ var = find_var_field(operand1->var.hist_data, operand1->name);
++ if (!var)
++ return -EINVAL;
++ operand1_flags = var->flags;
++ }
++
++ if ((operand2_flags & HIST_FIELD_FL_VAR_REF) ||
++ (operand2_flags & HIST_FIELD_FL_ALIAS)) {
++ struct hist_field *var;
++
++ var = find_var_field(operand2->var.hist_data, operand2->name);
++ if (!var)
++ return -EINVAL;
++ operand2_flags = var->flags;
++ }
++
+ if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
+ (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS))
+ return -EINVAL;
+@@ -4339,8 +4391,11 @@ static void hist_field_print(struct seq_
seq_puts(m, "$common_timestamp");
else if (hist_field->flags & HIST_FIELD_FL_CPU)
seq_puts(m, "cpu");
diff --git a/patches/0029-tracing-Add-last-error-error-facility-for-hist-trigg.patch b/patches/0034-tracing-Add-last-error-error-facility-for-hist-trigg.patch
index 325bfb804421..84c5378223de 100644
--- a/patches/0029-tracing-Add-last-error-error-facility-for-hist-trigg.patch
+++ b/patches/0034-tracing-Add-last-error-error-facility-for-hist-trigg.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:30 -0500
-Subject: [PATCH 29/32] tracing: Add 'last error' error facility for hist
+Date: Tue, 5 Sep 2017 16:57:46 -0500
+Subject: [PATCH 34/40] tracing: Add 'last error' error facility for hist
triggers
With the addition of variables and actions, it's become necessary to
@@ -25,9 +25,9 @@ Also add specific error messages for variable and action errors.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- Documentation/trace/events.txt | 19 ++++
- kernel/trace/trace_events_hist.c | 181 ++++++++++++++++++++++++++++++++++++---
- 2 files changed, 188 insertions(+), 12 deletions(-)
+ Documentation/trace/events.txt | 19 +++
+ kernel/trace/trace_events_hist.c | 188 ++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 194 insertions(+), 13 deletions(-)
--- a/Documentation/trace/events.txt
+++ b/Documentation/trace/events.txt
@@ -59,16 +59,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---------------------------
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -288,6 +288,7 @@ struct hist_trigger_data {
- struct field_var *max_vars[SYNTH_FIELDS_MAX];
- unsigned int n_max_vars;
- unsigned int n_max_var_str;
-+ char *last_err;
- };
-
- struct synth_field {
-@@ -332,6 +333,83 @@ struct action_data {
- struct hist_field *onmax_var;
+@@ -351,6 +351,88 @@ struct action_data {
+ };
};
+
@@ -80,9 +72,14 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ int ret = 0;
+
+ last_hist_cmd = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
++ if (!last_hist_cmd)
++ return -ENOMEM;
++
+ hist_err_str = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
-+ if (!last_hist_cmd || !hist_err_str)
++ if (!hist_err_str) {
++ kfree(last_hist_cmd);
+ ret = -ENOMEM;
++ }
+
+ return ret;
+}
@@ -92,7 +89,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ if (!last_hist_cmd || !str)
+ return;
+
-+ if (strlen(last_hist_cmd) > MAX_FILTER_STR_VAL - 1)
++ if (strlen(str) > MAX_FILTER_STR_VAL - 1)
+ return;
+
+ strcpy(last_hist_cmd, str);
@@ -102,10 +99,10 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+{
+ int maxlen = MAX_FILTER_STR_VAL - 1;
+
-+ if (strlen(hist_err_str))
++ if (!hist_err_str || !str)
+ return;
+
-+ if (!hist_err_str || !str)
++ if (strlen(hist_err_str))
+ return;
+
+ if (!var)
@@ -151,7 +148,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static LIST_HEAD(synth_event_list);
static DEFINE_MUTEX(synth_event_mutex);
-@@ -1954,12 +2032,21 @@ static struct hist_field *create_var_ref
+@@ -2110,9 +2192,18 @@ static struct hist_field *create_var_ref
return ref_field;
}
@@ -163,18 +160,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ return false;
+}
+
- static struct hist_field *parse_var_ref(char *system, char *event_name,
- char *var_name)
+ static bool is_var_ref(char *var_name)
{
- struct hist_field *var_field = NULL, *ref_field = NULL;
-
- if (!var_name || strlen(var_name) < 2 || var_name[0] != '$')
+ if (!var_name || strlen(var_name) < 2 || var_name[0] != '$' ||
+ is_common_field(var_name))
- return NULL;
+ return false;
- var_name++;
-@@ -1968,6 +2055,10 @@ static struct hist_field *parse_var_ref(
+ return true;
+@@ -2164,6 +2255,10 @@ static struct hist_field *parse_var_ref(
if (var_field)
ref_field = create_var_ref(var_field);
@@ -185,7 +179,19 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return ref_field;
}
-@@ -2426,8 +2517,11 @@ create_field_var_hist(struct hist_trigge
+@@ -2399,8 +2494,10 @@ static int check_expr_operands(struct hi
+ }
+
+ if ((operand1_flags & HIST_FIELD_FL_TIMESTAMP_USECS) !=
+- (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS))
++ (operand2_flags & HIST_FIELD_FL_TIMESTAMP_USECS)) {
++ hist_err("Timestamp units in expression don't match", NULL);
+ return -EINVAL;
++ }
+
+ return 0;
+ }
+@@ -2600,19 +2697,27 @@ create_field_var_hist(struct hist_trigge
char *cmd;
int ret;
@@ -196,11 +202,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return ERR_PTR(-EINVAL);
+ }
- tr = top_trace_array();
- if (!tr)
-@@ -2435,13 +2529,18 @@ create_field_var_hist(struct hist_trigge
+ file = event_file(tr, system, event_name);
- file = event_file(system, event_name);
if (IS_ERR(file)) {
+ hist_err_event("onmatch: Event file not found: ",
+ system, event_name, field_name);
@@ -218,7 +221,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
var_hist = kzalloc(sizeof(*var_hist), GFP_KERNEL);
if (!var_hist)
-@@ -2489,6 +2588,8 @@ create_field_var_hist(struct hist_trigge
+@@ -2660,6 +2765,8 @@ create_field_var_hist(struct hist_trigge
kfree(cmd);
kfree(var_hist->cmd);
kfree(var_hist);
@@ -227,7 +230,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return ERR_PTR(ret);
}
-@@ -2500,6 +2601,8 @@ create_field_var_hist(struct hist_trigge
+@@ -2671,6 +2778,8 @@ create_field_var_hist(struct hist_trigge
kfree(cmd);
kfree(var_hist->cmd);
kfree(var_hist);
@@ -236,7 +239,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return ERR_PTR(-EINVAL);
}
-@@ -2636,18 +2739,21 @@ static struct field_var *create_field_va
+@@ -2807,18 +2916,21 @@ static struct field_var *create_field_va
int ret = 0;
if (hist_data->n_field_vars >= SYNTH_FIELDS_MAX) {
@@ -258,10 +261,10 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
kfree(val);
ret = PTR_ERR(var);
goto err;
-@@ -2772,14 +2878,18 @@ static int onmax_create(struct hist_trig
+@@ -2943,14 +3055,18 @@ static int onmax_create(struct hist_trig
int ret = 0;
- onmax_var_str = data->onmax_var_str;
+ onmax_var_str = data->onmax.var_str;
- if (onmax_var_str[0] != '$')
+ if (onmax_var_str[0] != '$') {
+ hist_err("onmax: For onmax(x), x must be a variable: ", onmax_var_str);
@@ -279,15 +282,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
flags = HIST_FIELD_FL_VAR_REF;
ref_field = create_hist_field(hist_data, NULL, flags, NULL);
-@@ -2803,6 +2913,7 @@ static int onmax_create(struct hist_trig
- data->max_var_ref_idx = var_ref_idx;
+@@ -2970,6 +3086,7 @@ static int onmax_create(struct hist_trig
+ data->onmax.max_var_ref_idx = var_ref_idx;
max_var = create_var(hist_data, file, "max", sizeof(u64), "u64");
if (IS_ERR(max_var)) {
+ hist_err("onmax: Couldn't create onmax variable: ", "max");
ret = PTR_ERR(max_var);
goto out;
}
-@@ -2815,6 +2926,7 @@ static int onmax_create(struct hist_trig
+@@ -2982,6 +3099,7 @@ static int onmax_create(struct hist_trig
field_var = create_target_field_var(hist_data, NULL, NULL, param);
if (IS_ERR(field_var)) {
@@ -295,7 +298,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = PTR_ERR(field_var);
kfree(param);
goto out;
-@@ -2847,6 +2959,7 @@ static int parse_action_params(char *par
+@@ -3014,6 +3132,7 @@ static int parse_action_params(char *par
param = strstrip(param);
if (strlen(param) < 2) {
@@ -303,8 +306,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = -EINVAL;
goto out;
}
-@@ -3004,6 +3117,9 @@ onmatch_find_var(struct hist_trigger_dat
- hist_field = find_event_var(system, event, var);
+@@ -3185,6 +3304,9 @@ onmatch_find_var(struct hist_trigger_dat
+ hist_field = find_event_var(tr, system, event, var);
}
+ if (!hist_field)
@@ -313,15 +316,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return hist_field;
}
-@@ -3055,6 +3171,7 @@ static int onmatch_create(struct hist_tr
+@@ -3236,6 +3358,7 @@ static int onmatch_create(struct hist_tr
- event = find_synth_event(data->synth_event_name);
+ event = find_synth_event(data->onmatch.synth_event_name);
if (!event) {
-+ hist_err("onmatch: Couldn't find synthetic event: ", data->synth_event_name);
++ hist_err("onmatch: Couldn't find synthetic event: ", data->onmatch.synth_event_name);
ret = -EINVAL;
goto out;
}
-@@ -3094,6 +3211,7 @@ static int onmatch_create(struct hist_tr
+@@ -3275,6 +3398,7 @@ static int onmatch_create(struct hist_tr
ret = -EINVAL;
goto out;
}
@@ -329,7 +332,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (check_synth_field(event, hist_field, field_pos) == 0) {
var_ref = create_var_ref(hist_field);
if (!var_ref) {
-@@ -3108,12 +3226,15 @@ static int onmatch_create(struct hist_tr
+@@ -3289,12 +3413,15 @@ static int onmatch_create(struct hist_tr
continue;
}
@@ -345,7 +348,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = -EINVAL;
goto out;
}
-@@ -3141,31 +3262,44 @@ static struct action_data *onmatch_parse
+@@ -3322,15 +3449,22 @@ static struct action_data *onmatch_parse
return ERR_PTR(-ENOMEM);
match_event = strsep(&str, ")");
@@ -362,15 +365,17 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
goto free;
+ }
-- if (IS_ERR(event_file(match_event_system, match_event)))
-+ if (IS_ERR(event_file(match_event_system, match_event))) {
+- if (IS_ERR(event_file(tr, match_event_system, match_event)))
++ if (IS_ERR(event_file(tr, match_event_system, match_event))) {
+ hist_err_event("onmatch: Invalid subsystem or event name: ",
+ match_event_system, match_event, NULL);
goto free;
+ }
- data->match_event = kstrdup(match_event, GFP_KERNEL);
- data->match_event_system = kstrdup(match_event_system, GFP_KERNEL);
+ data->onmatch.match_event = kstrdup(match_event, GFP_KERNEL);
+ if (!data->onmatch.match_event) {
+@@ -3345,12 +3479,16 @@ static struct action_data *onmatch_parse
+ }
strsep(&str, ".");
- if (!str)
@@ -385,7 +390,11 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ hist_err("onmatch: Missing opening paramlist paren: ", synth_event_name);
goto free;
+ }
- data->synth_event_name = kstrdup(synth_event_name, GFP_KERNEL);
+
+ data->onmatch.synth_event_name = kstrdup(synth_event_name, GFP_KERNEL);
+ if (!data->onmatch.synth_event_name) {
+@@ -3359,8 +3497,10 @@ static struct action_data *onmatch_parse
+ }
params = strsep(&str, ")");
- if (!params || !str || (str && strlen(str)))
@@ -396,39 +405,30 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = parse_action_params(params, data);
if (ret)
-@@ -3217,6 +3351,7 @@ static int create_val_field(struct hist_
- if (field_str && var_name) {
- if (find_var(file, var_name) &&
- !hist_data->remove) {
-+ hist_err("Variable already defined: ", var_name);
- ret = -EINVAL;
- goto out;
- }
-@@ -3224,6 +3359,7 @@ static int create_val_field(struct hist_
- flags |= HIST_FIELD_FL_VAR;
- hist_data->n_vars++;
- if (hist_data->n_vars > TRACING_MAP_VARS_MAX) {
-+ hist_err("Too many variables defined: ", var_name);
- ret = -EINVAL;
- goto out;
- }
-@@ -3234,6 +3370,7 @@ static int create_val_field(struct hist_
- field_str = var_name;
- var_name = NULL;
- } else {
-+ hist_err("Malformed assignment: ", var_name);
- ret = -EINVAL;
- goto out;
+@@ -3440,12 +3580,14 @@ static int create_var_field(struct hist_
+ return -EINVAL;
+
+ if (find_var(file, var_name) && !hist_data->remove) {
++ hist_err("Variable already defined: ", var_name);
+ return -EINVAL;
}
-@@ -3248,6 +3385,7 @@ static int create_val_field(struct hist_
- hist_field = parse_atom(hist_data, file, field_str,
- &flags, var_name);
- if (IS_ERR(hist_field)) {
-+ hist_err("Unable to parse atom: ", field_str);
- ret = PTR_ERR(hist_field);
- goto out;
- }
-@@ -4138,6 +4276,11 @@ static int hist_show(struct seq_file *m,
+
+ flags |= HIST_FIELD_FL_VAR;
+ hist_data->n_vars++;
+ if (hist_data->n_vars > TRACING_MAP_VARS_MAX) {
++ hist_err("Too many variables defined: ", var_name);
+ return -EINVAL;
+ }
+
+@@ -3636,6 +3778,7 @@ static int parse_var_defs(struct hist_tr
+
+ var_name = strsep(&field_str, "=");
+ if (!var_name || !field_str) {
++ hist_err("Malformed assignment: ", var_name);
+ ret = -EINVAL;
+ goto free;
+ }
+@@ -4362,6 +4505,11 @@ static int hist_show(struct seq_file *m,
hist_trigger_show(m, data, n++);
}
@@ -440,7 +440,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
out_unlock:
mutex_unlock(&event_mutex);
-@@ -4509,6 +4652,7 @@ static int hist_register_trigger(char *g
+@@ -4709,6 +4857,7 @@ static int hist_register_trigger(char *g
if (named_data) {
if (!hist_trigger_match(data, named_data, named_data,
true)) {
@@ -448,7 +448,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = -EINVAL;
goto out;
}
-@@ -4528,13 +4672,16 @@ static int hist_register_trigger(char *g
+@@ -4728,13 +4877,16 @@ static int hist_register_trigger(char *g
test->paused = false;
else if (hist_data->attrs->clear)
hist_clear(test);
@@ -466,7 +466,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
ret = -ENOENT;
goto out;
}
-@@ -4701,6 +4848,11 @@ static int event_hist_trigger_func(struc
+@@ -4901,6 +5053,11 @@ static int event_hist_trigger_func(struc
char *trigger, *p;
int ret = 0;
@@ -478,7 +478,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
if (!param)
return -EINVAL;
-@@ -4804,6 +4956,9 @@ static int event_hist_trigger_func(struc
+@@ -5019,6 +5176,9 @@ static int event_hist_trigger_func(struc
/* Just return zero, not the number of registered triggers */
ret = 0;
out:
@@ -488,7 +488,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return ret;
out_unreg:
cmd_ops->unreg(glob+1, trigger_ops, trigger_data, file);
-@@ -5002,6 +5157,8 @@ static __init int trace_events_hist_init
+@@ -5208,6 +5368,8 @@ static __init int trace_events_hist_init
goto err;
}
diff --git a/patches/0035-tracing-Reverse-the-order-event_mutex-trace_types_lo.patch b/patches/0035-tracing-Reverse-the-order-event_mutex-trace_types_lo.patch
new file mode 100644
index 000000000000..400cac857dc7
--- /dev/null
+++ b/patches/0035-tracing-Reverse-the-order-event_mutex-trace_types_lo.patch
@@ -0,0 +1,95 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:47 -0500
+Subject: [PATCH 35/40] tracing: Reverse the order event_mutex/trace_types_lock
+ are taken
+
+Change the order event_mutex and trace_types_lock are taken, to avoid
+circular dependencies and lockdep spew.
+
+Changing the order shouldn't matter to any current code, but does to
+anything that takes the event_mutex first and then trace_types_lock.
+This is the case when calling tracing_set_clock from inside an event
+command, which already holds the event_mutex.
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/trace_events.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -1366,8 +1366,8 @@ static int subsystem_open(struct inode *
+ return -ENODEV;
+
+ /* Make sure the system still exists */
+- mutex_lock(&trace_types_lock);
+ mutex_lock(&event_mutex);
++ mutex_lock(&trace_types_lock);
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ list_for_each_entry(dir, &tr->systems, list) {
+ if (dir == inode->i_private) {
+@@ -1381,8 +1381,8 @@ static int subsystem_open(struct inode *
+ }
+ }
+ exit_loop:
+- mutex_unlock(&event_mutex);
+ mutex_unlock(&trace_types_lock);
++ mutex_unlock(&event_mutex);
+
+ if (!system)
+ return -ENODEV;
+@@ -2250,15 +2250,15 @@ static void __add_event_to_tracers(struc
+ int trace_add_event_call(struct trace_event_call *call)
+ {
+ int ret;
+- mutex_lock(&trace_types_lock);
+ mutex_lock(&event_mutex);
++ mutex_lock(&trace_types_lock);
+
+ ret = __register_event(call, NULL);
+ if (ret >= 0)
+ __add_event_to_tracers(call);
+
+- mutex_unlock(&event_mutex);
+ mutex_unlock(&trace_types_lock);
++ mutex_unlock(&event_mutex);
+ return ret;
+ }
+
+@@ -2312,13 +2312,13 @@ int trace_remove_event_call(struct trace
+ {
+ int ret;
+
+- mutex_lock(&trace_types_lock);
+ mutex_lock(&event_mutex);
++ mutex_lock(&trace_types_lock);
+ down_write(&trace_event_sem);
+ ret = probe_remove_event_call(call);
+ up_write(&trace_event_sem);
+- mutex_unlock(&event_mutex);
+ mutex_unlock(&trace_types_lock);
++ mutex_unlock(&event_mutex);
+
+ return ret;
+ }
+@@ -2385,8 +2385,8 @@ static int trace_module_notify(struct no
+ {
+ struct module *mod = data;
+
+- mutex_lock(&trace_types_lock);
+ mutex_lock(&event_mutex);
++ mutex_lock(&trace_types_lock);
+ switch (val) {
+ case MODULE_STATE_COMING:
+ trace_module_add_events(mod);
+@@ -2395,8 +2395,8 @@ static int trace_module_notify(struct no
+ trace_module_remove_events(mod);
+ break;
+ }
+- mutex_unlock(&event_mutex);
+ mutex_unlock(&trace_types_lock);
++ mutex_unlock(&event_mutex);
+
+ return 0;
+ }
diff --git a/patches/0036-tracing-Remove-lookups-from-tracing_map-hitcount.patch b/patches/0036-tracing-Remove-lookups-from-tracing_map-hitcount.patch
new file mode 100644
index 000000000000..39722e6579c3
--- /dev/null
+++ b/patches/0036-tracing-Remove-lookups-from-tracing_map-hitcount.patch
@@ -0,0 +1,26 @@
+From: Tom Zanussi <tom.zanussi@linux.intel.com>
+Date: Tue, 5 Sep 2017 16:57:48 -0500
+Subject: [PATCH 36/40] tracing: Remove lookups from tracing_map hitcount
+
+Lookups inflate the hitcount, making it essentially useless. Only
+inserts and updates should really affect the hitcount anyway, so
+explicitly filter lookups out.
+
+Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/tracing_map.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/kernel/trace/tracing_map.c
++++ b/kernel/trace/tracing_map.c
+@@ -535,7 +535,8 @@ static inline struct tracing_map_elt *
+ if (test_key && test_key == key_hash) {
+ if (entry->val &&
+ keys_match(key, entry->val->key, map->key_size)) {
+- atomic64_inc(&map->hits);
++ if (!lookup_only)
++ atomic64_inc(&map->hits);
+ return entry->val;
+ } else if (unlikely(!entry->val)) {
+ /*
diff --git a/patches/0030-tracing-Add-inter-event-hist-trigger-Documentation.patch b/patches/0037-tracing-Add-inter-event-hist-trigger-Documentation.patch
index 18c4d2093b18..08fc6d64a9d9 100644
--- a/patches/0030-tracing-Add-inter-event-hist-trigger-Documentation.patch
+++ b/patches/0037-tracing-Add-inter-event-hist-trigger-Documentation.patch
@@ -1,15 +1,16 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:31 -0500
-Subject: [PATCH 30/32] tracing: Add inter-event hist trigger Documentation
+Date: Tue, 5 Sep 2017 16:57:49 -0500
+Subject: [PATCH 37/40] tracing: Add inter-event hist trigger Documentation
Add background and details on inter-event hist triggers, including
hist variables, synthetic events, and actions.
Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+Signed-off-by: Baohong Liu <baohong.liu@intel.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
- Documentation/trace/events.txt | 376 +++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 376 insertions(+)
+ Documentation/trace/events.txt | 385 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 385 insertions(+)
--- a/Documentation/trace/events.txt
+++ b/Documentation/trace/events.txt
@@ -21,7 +22,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Note that in general the semantics of a given field aren't
interpreted when applying a modifier to it, but there are some
-@@ -2101,3 +2102,378 @@ triggers (you have to use '!' for each o
+@@ -2101,3 +2102,387 @@ triggers (you have to use '!' for each o
Hits: 489
Entries: 7
Dropped: 0
@@ -124,14 +125,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+creates a variable named 'ts0' for a histogram entry with the key
+'next_pid':
+
-+ # echo 'hist:keys=next_pid:vals=ts0=$common_timestamp ... >> event/trigger
++ # echo 'hist:keys=next_pid:vals=$ts0:ts0=$common_timestamp ... >> \
++ event/trigger
+
+The ts0 variable can be accessed by any subsequent event having the
+same pid as 'next_pid'.
+
+Variable references are formed by prepending the variable name with
+the '$' sign. Thus for example, the ts0 variable above would be
-+referenced as '$ts0' in subsequent expressions.
++referenced as '$ts0' in expressions.
+
+Because 'vals=' is used, the $common_timestamp variable value above
+will also be summed as a normal histogram value would (though for a
@@ -139,7 +141,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+The below shows that a key value can also be saved in the same way:
+
-+ # echo 'hist:key=timer_pid=common_pid ...' >> event/trigger
++ # echo 'hist:timer_pid=common_pid:key=timer_pid ...' >> event/trigger
+
+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
@@ -151,7 +153,15 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+result in both ts0 and b being created as variables, with both
+common_timestamp and field1 additionally being summed as values:
+
-+ # echo 'hist:keys=pid:vals=ts0=$common_timestamp,b=field1 ... >> event/trigger
++ # echo 'hist:keys=pid:vals=$ts0,$b:ts0=$common_timestamp,b=field1 ... >> \
++ event/trigger
++
++Note that variable assignments can appear either preceding or
++following their use. The command below behaves identically to the
++command above:
++
++ # echo 'hist:keys=pid:ts0=$common_timestamp,b=field1:vals=$ts0,$b ... >> \
++ event/trigger
+
+Any number of variables not bound to a 'vals=' prefix can also be
+assigned by simply separating them with colons. Below is the same
@@ -293,7 +303,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ occurs, which because of the 'if comm == "cyclictest"' filter only
+ happens when the executable is cyclictest:
+
-+ # echo 'hist:keys=testpid=pid:onmatch(sched.sched_wakeup_new).\
++ # echo 'hist:keys=$testpid:testpid=pid:onmatch(sched.sched_wakeup_new).\
+ wakeup_new_test($testpid) if comm=="cyclictest"' >> \
+ /sys/kernel/debug/tracing/events/sched/sched_wakeup_new/trigger
+
@@ -319,12 +329,12 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ # echo 'wakeup_latency u64 lat; pid_t pid; int prio' >> \
+ /sys/kernel/debug/tracing/synthetic_events
+
-+ Next, we specify that whenever we see a sched_wakeup event for a
++ Next, we specify that whenever we see a sched_waking event for a
+ cyclictest thread, save the timestamp in a 'ts0' variable:
+
-+ # echo 'hist:keys=saved_pid=pid:ts0=$common_timestamp.usecs \
++ # echo 'hist:keys=$saved_pid:saved_pid=pid:ts0=$common_timestamp.usecs \
+ if comm=="cyclictest"' >> \
-+ /sys/kernel/debug/tracing/events/sched/sched_wakeup/trigger
++ /sys/kernel/debug/tracing/events/sched/sched_waking/trigger
+
+ Then, when the corresponding thread is actually scheduled onto the
+ CPU by a sched_switch event, calculate the latency and use that
@@ -332,7 +342,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ wakeup_latency synthetic event:
+
+ # echo 'hist:keys=next_pid:wakeup_lat=$common_timestamp.usecs-$ts0:\
-+ onmatch(sched.sched_wakeup).wakeup_latency($wakeup_lat,\
++ onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,\
+ $saved_pid,next_prio) if next_comm=="cyclictest"' >> \
+ /sys/kernel/debug/tracing/events/sched/sched_switch/trigger
+
@@ -348,7 +358,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+ # cat /sys/kernel/debug/tracing/events/synthetic/wakeup_latency/hist
+
-+ - onmax(var).save(field,...)
++ - onmax(var).save(field,.. .)
+
+ The 'onmax(var).save(field,...)' hist trigger action is invoked
+ whenever the value of 'var' associated with a histogram entry
@@ -362,8 +372,8 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ displaying the saved values will be printed.
+
+ As an example the below defines a couple of hist triggers, one for
-+ sched_wakeup and another for sched_switch, keyed on pid. Whenever
-+ a sched_wakeup occurs, the timestamp is saved in the entry
++ sched_waking and another for sched_switch, keyed on pid. Whenever
++ a sched_waking occurs, the timestamp is saved in the entry
+ corresponding to the current pid, and when the scheduler switches
+ back to that pid, the timestamp difference is calculated. If the
+ resulting latency, stored in wakeup_lat, exceeds the current
@@ -372,7 +382,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+ # echo 'hist:keys=pid:ts0=$common_timestamp.usecs \
+ if comm=="cyclictest"' >> \
-+ /sys/kernel/debug/tracing/events/sched/sched_wakeup/trigger
++ /sys/kernel/debug/tracing/events/sched/sched_waking/trigger
+
+ # echo 'hist:keys=next_pid:\
+ wakeup_lat=$common_timestamp.usecs-$ts0:\
diff --git a/patches/0031-tracing-Make-tracing_set_clock-non-static.patch b/patches/0038-tracing-Make-tracing_set_clock-non-static.patch
index 88e35cf67957..a72269254654 100644
--- a/patches/0031-tracing-Make-tracing_set_clock-non-static.patch
+++ b/patches/0038-tracing-Make-tracing_set_clock-non-static.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:32 -0500
-Subject: [PATCH 31/32] tracing: Make tracing_set_clock() non-static
+Date: Tue, 5 Sep 2017 16:57:50 -0500
+Subject: [PATCH 38/40] tracing: Make tracing_set_clock() non-static
Allow tracing code outside of trace.c to access tracing_set_clock().
@@ -29,7 +29,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
-@@ -279,6 +279,7 @@ extern int trace_array_get(struct trace_
+@@ -281,6 +281,7 @@ extern int trace_array_get(struct trace_
extern void trace_array_put(struct trace_array *tr);
extern int tracing_set_time_stamp_abs(struct trace_array *tr, bool abs);
diff --git a/patches/0032-tracing-Add-a-clock-attribute-for-hist-triggers.patch b/patches/0039-tracing-Add-a-clock-attribute-for-hist-triggers.patch
index 71dd2da4d25f..1e23eb9bf4e3 100644
--- a/patches/0032-tracing-Add-a-clock-attribute-for-hist-triggers.patch
+++ b/patches/0039-tracing-Add-a-clock-attribute-for-hist-triggers.patch
@@ -1,6 +1,6 @@
From: Tom Zanussi <tom.zanussi@linux.intel.com>
-Date: Mon, 26 Jun 2017 17:49:33 -0500
-Subject: [PATCH 32/32] tracing: Add a clock attribute for hist triggers
+Date: Tue, 5 Sep 2017 16:57:51 -0500
+Subject: [PATCH 39/40] tracing: Add a clock attribute for hist triggers
The default clock if timestamps are used in a histogram is "global".
If timestamps aren't used, the clock is irrelevant.
@@ -25,7 +25,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+histogram, the trace buffer is automatically switched over to using
+absolute timestamps and the "global" trace clock, in order to avoid
+bogus timestamp differences with other clocks that aren't coherent
-+across CPUs. This can be overriden by specifying one of the other
++across CPUs. This can be overridden by specifying one of the other
+trace clocks instead, using the "clock=XXX" hist trigger attribute,
+where XXX is any of the clocks listed in the tracing/trace_clock
+pseudo-file.
@@ -35,7 +35,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
6.3.1 Histogram Variables
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
-@@ -233,6 +233,7 @@ struct hist_trigger_attrs {
+@@ -241,6 +241,7 @@ struct hist_trigger_attrs {
char *vals_str;
char *sort_key_str;
char *name;
@@ -43,7 +43,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
bool pause;
bool cont;
bool clear;
-@@ -1586,6 +1587,7 @@ static void destroy_hist_trigger_attrs(s
+@@ -1701,6 +1702,7 @@ static void destroy_hist_trigger_attrs(s
kfree(attrs->sort_key_str);
kfree(attrs->keys_str);
kfree(attrs->vals_str);
@@ -51,7 +51,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
kfree(attrs);
}
-@@ -1625,7 +1627,16 @@ static int parse_assignment(char *str, s
+@@ -1740,7 +1742,16 @@ static int parse_assignment(char *str, s
attrs->sort_key_str = kstrdup(str, GFP_KERNEL);
else if (strncmp(str, "name=", strlen("name=")) == 0)
attrs->name = kstrdup(str, GFP_KERNEL);
@@ -69,7 +69,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
int map_bits = parse_map_size(str);
if (map_bits < 0) {
-@@ -1688,6 +1699,12 @@ static struct hist_trigger_attrs *parse_
+@@ -1803,6 +1814,12 @@ static struct hist_trigger_attrs *parse_
goto free;
}
@@ -82,7 +82,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
return attrs;
free:
destroy_hist_trigger_attrs(attrs);
-@@ -4437,6 +4454,8 @@ static int event_hist_trigger_print(stru
+@@ -4644,6 +4661,8 @@ static int event_hist_trigger_print(stru
seq_puts(m, ".descending");
}
seq_printf(m, ":size=%u", (1 << hist_data->map->map_bits));
@@ -91,7 +91,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
print_actions_spec(m, hist_data);
-@@ -4702,10 +4721,19 @@ static int hist_register_trigger(char *g
+@@ -4907,10 +4926,19 @@ static int hist_register_trigger(char *g
goto out;
}
diff --git a/patches/0040-tracing-Add-trace_event_buffer_reserve-variant-that-.patch b/patches/0040-tracing-Add-trace_event_buffer_reserve-variant-that-.patch
new file mode 100644
index 000000000000..18369c5b01cf
--- /dev/null
+++ b/patches/0040-tracing-Add-trace_event_buffer_reserve-variant-that-.patch
@@ -0,0 +1,132 @@
+From: Steven Rostedt <rostedt@goodmis.org>
+Date: Fri, 8 Sep 2017 16:27:56 -0400
+Subject: [PATCH] tracing: Add trace_event_buffer_reserve() variant that allows
+ recursion
+
+On Tue, 5 Sep 2017 16:57:52 -0500
+Tom Zanussi <tom.zanussi@linux.intel.com> wrote:
+
+> Synthetic event generation requires the reservation of a second event
+> while the reservation of a previous event is still in progress. The
+> trace_recursive_lock() check in ring_buffer_lock_reserve() prevents
+> this however.
+>
+> This sets up a special reserve pathway for this particular case,
+> leaving existing pathways untouched, other than an additional check in
+> ring_buffer_lock_reserve() and trace_event_buffer_reserve(). These
+> checks could be gotten rid of as well, with copies of those functions,
+> but for now try to avoid that unless necessary.
+>
+> Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
+
+I've been planing on changing that lock, which may help you here
+without having to mess around with parameters. That is to simply add a
+counter. Would this patch help you. You can add a patch to increment
+the count to 5 with an explanation of handling synthetic events, but
+even getting to 4 is extremely unlikely.
+
+I'll make this into an official patch if this works for you, and then
+you can include it in your series.
+
+-- Steve
+
+Link: https://lkml.kernel.org/r/20170908162756.74c6be8a@gandalf.local.home
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/trace/ring_buffer.c | 64 ++++++++++++----------------------------------
+ 1 file changed, 17 insertions(+), 47 deletions(-)
+
+diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
+index ac34ea2b2a10..29430b81c674 100644
+--- a/kernel/trace/ring_buffer.c
++++ b/kernel/trace/ring_buffer.c
+@@ -2581,61 +2581,29 @@ rb_wakeups(struct ring_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
+ * The lock and unlock are done within a preempt disable section.
+ * The current_context per_cpu variable can only be modified
+ * by the current task between lock and unlock. But it can
+- * be modified more than once via an interrupt. To pass this
+- * information from the lock to the unlock without having to
+- * access the 'in_interrupt()' functions again (which do show
+- * a bit of overhead in something as critical as function tracing,
+- * we use a bitmask trick.
++ * be modified more than once via an interrupt. There are four
++ * different contexts that we need to consider.
+ *
+- * bit 0 = NMI context
+- * bit 1 = IRQ context
+- * bit 2 = SoftIRQ context
+- * bit 3 = normal context.
++ * Normal context.
++ * SoftIRQ context
++ * IRQ context
++ * NMI context
+ *
+- * This works because this is the order of contexts that can
+- * preempt other contexts. A SoftIRQ never preempts an IRQ
+- * context.
+- *
+- * When the context is determined, the corresponding bit is
+- * checked and set (if it was set, then a recursion of that context
+- * happened).
+- *
+- * On unlock, we need to clear this bit. To do so, just subtract
+- * 1 from the current_context and AND it to itself.
+- *
+- * (binary)
+- * 101 - 1 = 100
+- * 101 & 100 = 100 (clearing bit zero)
+- *
+- * 1010 - 1 = 1001
+- * 1010 & 1001 = 1000 (clearing bit 1)
+- *
+- * The least significant bit can be cleared this way, and it
+- * just so happens that it is the same bit corresponding to
+- * the current context.
++ * If for some reason the ring buffer starts to recurse, we
++ * only allow that to happen at most 4 times (one for each
++ * context). If it happens 5 times, then we consider this a
++ * recusive loop and do not let it go further.
+ */
+
+ static __always_inline int
+ trace_recursive_lock(struct ring_buffer_per_cpu *cpu_buffer)
+ {
+- unsigned int val = cpu_buffer->current_context;
+- int bit;
+-
+- if (in_interrupt()) {
+- if (in_nmi())
+- bit = RB_CTX_NMI;
+- else if (in_irq())
+- bit = RB_CTX_IRQ;
+- else
+- bit = RB_CTX_SOFTIRQ;
+- } else
+- bit = RB_CTX_NORMAL;
+-
+- if (unlikely(val & (1 << bit)))
++ if (cpu_buffer->current_context >= 4)
+ return 1;
+
+- val |= (1 << bit);
+- cpu_buffer->current_context = val;
++ cpu_buffer->current_context++;
++ /* Interrupts must see this update */
++ barrier();
+
+ return 0;
+ }
+@@ -2643,7 +2611,9 @@ trace_recursive_lock(struct ring_buffer_per_cpu *cpu_buffer)
+ static __always_inline void
+ trace_recursive_unlock(struct ring_buffer_per_cpu *cpu_buffer)
+ {
+- cpu_buffer->current_context &= cpu_buffer->current_context - 1;
++ /* Don't let the dec leak out */
++ barrier();
++ cpu_buffer->current_context--;
+ }
+
+ /**
+--
+2.14.1
+
diff --git a/patches/Bluetooth-avoid-recursive-locking-in-hci_send_to_cha.patch b/patches/Bluetooth-avoid-recursive-locking-in-hci_send_to_cha.patch
new file mode 100644
index 000000000000..07429dcf638a
--- /dev/null
+++ b/patches/Bluetooth-avoid-recursive-locking-in-hci_send_to_cha.patch
@@ -0,0 +1,70 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Thu, 21 Sep 2017 15:35:57 +0200
+Subject: Bluetooth: avoid recursive locking in
+ hci_send_to_channel()
+
+Mart reported a deadlock in -RT in the call path:
+ hci_send_monitor_ctrl_event() -> hci_send_to_channel()
+
+because both functions acquire the same read lock hci_sk_list.lock. This
+is also a mainline issue because the qrwlock implementation is writer
+fair (the traditional rwlock implementation is reader biased).
+
+To avoid the deadlock there is now __hci_send_to_channel() which expects
+the readlock to be held.
+
+Cc: Marcel Holtmann <marcel@holtmann.org>
+Cc: Johan Hedberg <johan.hedberg@intel.com>
+Cc: rt-stable@vger.kernel.org
+Fixes: 38ceaa00d02d ("Bluetooth: Add support for sending MGMT commands and events to monitor")
+Reported-by: Mart van de Wege <mvdwege@gmail.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ net/bluetooth/hci_sock.c | 17 +++++++++++------
+ 1 file changed, 11 insertions(+), 6 deletions(-)
+
+--- a/net/bluetooth/hci_sock.c
++++ b/net/bluetooth/hci_sock.c
+@@ -251,15 +251,13 @@ void hci_send_to_sock(struct hci_dev *hd
+ }
+
+ /* Send frame to sockets with specific channel */
+-void hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
+- int flag, struct sock *skip_sk)
++static void __hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
++ int flag, struct sock *skip_sk)
+ {
+ struct sock *sk;
+
+ BT_DBG("channel %u len %d", channel, skb->len);
+
+- read_lock(&hci_sk_list.lock);
+-
+ sk_for_each(sk, &hci_sk_list.head) {
+ struct sk_buff *nskb;
+
+@@ -285,6 +283,13 @@ void hci_send_to_channel(unsigned short
+ kfree_skb(nskb);
+ }
+
++}
++
++void hci_send_to_channel(unsigned short channel, struct sk_buff *skb,
++ int flag, struct sock *skip_sk)
++{
++ read_lock(&hci_sk_list.lock);
++ __hci_send_to_channel(channel, skb, flag, skip_sk);
+ read_unlock(&hci_sk_list.lock);
+ }
+
+@@ -388,8 +393,8 @@ void hci_send_monitor_ctrl_event(struct
+ hdr->index = index;
+ hdr->len = cpu_to_le16(skb->len - HCI_MON_HDR_SIZE);
+
+- hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
+- HCI_SOCK_TRUSTED, NULL);
++ __hci_send_to_channel(HCI_CHANNEL_MONITOR, skb,
++ HCI_SOCK_TRUSTED, NULL);
+ kfree_skb(skb);
+ }
+
diff --git a/patches/drivers-zram-fix-zcomp_stream_get-smp_processor_id-u.patch b/patches/drivers-zram-fix-zcomp_stream_get-smp_processor_id-u.patch
index 40ece686ab02..8eabb445eaef 100644
--- a/patches/drivers-zram-fix-zcomp_stream_get-smp_processor_id-u.patch
+++ b/patches/drivers-zram-fix-zcomp_stream_get-smp_processor_id-u.patch
@@ -1,4 +1,3 @@
-From 8b91f086c2492145698727d3d9c1918d97a0e41c Mon Sep 17 00:00:00 2001
From: Mike Galbraith <efault@gmx.de>
Date: Wed, 23 Aug 2017 11:57:29 +0200
Subject: [PATCH] drivers/zram: fix zcomp_stream_get() smp_processor_id() use
diff --git a/patches/ftrace-Fix-trace-header-alignment.patch b/patches/ftrace-Fix-trace-header-alignment.patch
index ba263bd43182..c209ce46a496 100644
--- a/patches/ftrace-Fix-trace-header-alignment.patch
+++ b/patches/ftrace-Fix-trace-header-alignment.patch
@@ -14,7 +14,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
-@@ -3121,17 +3121,17 @@ get_total_entries(struct trace_buffer *b
+@@ -3144,17 +3144,17 @@ get_total_entries(struct trace_buffer *b
static void print_lat_help_header(struct seq_file *m)
{
@@ -43,7 +43,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
}
static void print_event_info(struct trace_buffer *buf, struct seq_file *m)
-@@ -3160,11 +3160,11 @@ static void print_func_help_header_irq(s
+@@ -3183,11 +3183,11 @@ static void print_func_help_header_irq(s
"# |/ _-----=> need-resched_lazy\n"
"# || / _---=> hardirq/softirq\n"
"# ||| / _--=> preempt-depth\n"
diff --git a/patches/ftrace-migrate-disable-tracing.patch b/patches/ftrace-migrate-disable-tracing.patch
index dd2ebfb8e4bc..c59aa3e75d62 100644
--- a/patches/ftrace-migrate-disable-tracing.patch
+++ b/patches/ftrace-migrate-disable-tracing.patch
@@ -23,7 +23,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
#define TRACE_EVENT_TYPE_MAX \
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
-@@ -1954,6 +1954,8 @@ tracing_generic_entry_update(struct trac
+@@ -1955,6 +1955,8 @@ tracing_generic_entry_update(struct trac
((pc & SOFTIRQ_OFFSET) ? TRACE_FLAG_SOFTIRQ : 0) |
(tif_need_resched() ? TRACE_FLAG_NEED_RESCHED : 0) |
(test_preempt_need_resched() ? TRACE_FLAG_PREEMPT_RESCHED : 0);
@@ -32,7 +32,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
}
EXPORT_SYMBOL_GPL(tracing_generic_entry_update);
-@@ -3122,9 +3124,10 @@ static void print_lat_help_header(struct
+@@ -3145,9 +3147,10 @@ static void print_lat_help_header(struct
"# | / _----=> need-resched \n"
"# || / _---=> hardirq/softirq \n"
"# ||| / _--=> preempt-depth \n"
diff --git a/patches/futex-rtmutex-Cure-RT-double-blocking-issue.patch b/patches/futex-rtmutex-Cure-RT-double-blocking-issue.patch
index 551f4789d2e9..831ec3d398f5 100644
--- a/patches/futex-rtmutex-Cure-RT-double-blocking-issue.patch
+++ b/patches/futex-rtmutex-Cure-RT-double-blocking-issue.patch
@@ -25,7 +25,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
-@@ -2407,6 +2407,7 @@ int rt_mutex_wait_proxy_lock(struct rt_m
+@@ -2406,6 +2406,7 @@ int rt_mutex_wait_proxy_lock(struct rt_m
struct hrtimer_sleeper *to,
struct rt_mutex_waiter *waiter)
{
@@ -33,7 +33,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
int ret;
raw_spin_lock_irq(&lock->wait_lock);
-@@ -2418,6 +2419,24 @@ int rt_mutex_wait_proxy_lock(struct rt_m
+@@ -2417,6 +2418,24 @@ int rt_mutex_wait_proxy_lock(struct rt_m
* have to fix that up.
*/
fixup_rt_mutex_waiters(lock);
diff --git a/patches/hrtimer-consolidate-hrtimer_init-hrtimer_init_sleepe.patch b/patches/hrtimer-consolidate-hrtimer_init-hrtimer_init_sleepe.patch
index 3474b406ce5b..4ba25565b78e 100644
--- a/patches/hrtimer-consolidate-hrtimer_init-hrtimer_init_sleepe.patch
+++ b/patches/hrtimer-consolidate-hrtimer_init-hrtimer_init_sleepe.patch
@@ -1,4 +1,3 @@
-From 3c3702c557d49df718523d04ae1393ce05769ef6 Mon Sep 17 00:00:00 2001
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: Mon, 4 Sep 2017 18:31:50 +0200
Subject: [PATCH] hrtimer: consolidate hrtimer_init() + hrtimer_init_sleeper()
diff --git a/patches/iommu-amd-Use-raw_cpu_ptr-instead-of-get_cpu_ptr-for.patch b/patches/iommu-amd-Use-raw_cpu_ptr-instead-of-get_cpu_ptr-for.patch
new file mode 100644
index 000000000000..228c9adf2755
--- /dev/null
+++ b/patches/iommu-amd-Use-raw_cpu_ptr-instead-of-get_cpu_ptr-for.patch
@@ -0,0 +1,43 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Tue, 5 Sep 2017 14:11:41 +0200
+Subject: iommu/amd: Use raw_cpu_ptr() instead of get_cpu_ptr() for
+ ->flush_queue
+
+get_cpu_ptr() disabled preemption and returns the ->flush_queue object
+of the current CPU. raw_cpu_ptr() does the same except that it not
+disable preemption which means the scheduler can move it to another CPU
+after it obtained the per-CPU object.
+In this case this is not bad because the data structure itself is
+protected with a spin_lock. This change shouldn't matter however on RT
+it does because the sleeping lock can't be accessed with disabled
+preemption.
+
+Cc: rt-stable@vger.kernel.org
+Cc: Joerg Roedel <joro@8bytes.org>
+Cc: iommu@lists.linux-foundation.org
+Reported-by: Vinod Adhikary <vinadhy@gmail.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ drivers/iommu/amd_iommu.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/iommu/amd_iommu.c
++++ b/drivers/iommu/amd_iommu.c
+@@ -2289,7 +2289,7 @@ static void queue_add(struct dma_ops_dom
+ pages = __roundup_pow_of_two(pages);
+ address >>= PAGE_SHIFT;
+
+- queue = get_cpu_ptr(&flush_queue);
++ queue = raw_cpu_ptr(&flush_queue);
+ spin_lock_irqsave(&queue->lock, flags);
+
+ if (queue->next == FLUSH_QUEUE_SIZE)
+@@ -2306,8 +2306,6 @@ static void queue_add(struct dma_ops_dom
+
+ if (atomic_cmpxchg(&queue_timer_on, 0, 1) == 0)
+ mod_timer(&queue_timer, jiffies + msecs_to_jiffies(10));
+-
+- put_cpu_ptr(&flush_queue);
+ }
+
+
diff --git a/patches/locallock-add-local_lock_on.patch b/patches/locallock-add-local_lock_on.patch
index 0c714f2192f5..bb3846f205d9 100644
--- a/patches/locallock-add-local_lock_on.patch
+++ b/patches/locallock-add-local_lock_on.patch
@@ -19,7 +19,7 @@ Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
static inline int __local_trylock(struct local_irq_lock *lv)
{
if (lv->owner != current && spin_trylock_local(&lv->lock)) {
-@@ -98,6 +101,9 @@ static inline void __local_unlock(struct
+@@ -101,6 +104,9 @@ static inline void __local_unlock(struct
put_local_var(lvar); \
} while (0)
diff --git a/patches/localversion.patch b/patches/localversion.patch
index 25e5fadbaae8..e1f3b8d87864 100644
--- a/patches/localversion.patch
+++ b/patches/localversion.patch
@@ -10,4 +10,4 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
--- /dev/null
+++ b/localversion-rt
@@ -0,0 +1 @@
-+-rt13
++-rt14
diff --git a/patches/locking-rtmutex-don-t-drop-the-wait_lock-twice.patch b/patches/locking-rtmutex-don-t-drop-the-wait_lock-twice.patch
new file mode 100644
index 000000000000..e5a2346657e8
--- /dev/null
+++ b/patches/locking-rtmutex-don-t-drop-the-wait_lock-twice.patch
@@ -0,0 +1,29 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Thu, 7 Sep 2017 12:38:47 +0200
+Subject: locking/rtmutex: don't drop the wait_lock twice
+
+Since the futex rework, __rt_mutex_start_proxy_lock() does no longer
+acquire the wait_lock so it must not drop it. Otherwise the lock is not
+only unlocked twice but also the preemption counter is underflown.
+
+It is okay to remove that line because this function does not disable
+interrupts nor does it acquire the ->wait_lock. The caller does this so it is
+wrong do it here (after the futex rework).
+
+Cc: rt-stable@vger.kernel.org #v4.9.18-rt14+
+Reported-by: Gusenleitner Klaus <gus@keba.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ kernel/locking/rtmutex.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/kernel/locking/rtmutex.c
++++ b/kernel/locking/rtmutex.c
+@@ -1745,7 +1745,6 @@ int __rt_mutex_start_proxy_lock(struct r
+ raw_spin_lock(&task->pi_lock);
+ if (task->pi_blocked_on) {
+ raw_spin_unlock(&task->pi_lock);
+- raw_spin_unlock_irq(&lock->wait_lock);
+ return -EAGAIN;
+ }
+ task->pi_blocked_on = PI_REQUEUE_INPROGRESS;
diff --git a/patches/net-use-trylock-in-icmp_sk.patch b/patches/net-use-trylock-in-icmp_sk.patch
new file mode 100644
index 000000000000..3e706f3c8ede
--- /dev/null
+++ b/patches/net-use-trylock-in-icmp_sk.patch
@@ -0,0 +1,73 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Thu, 21 Sep 2017 14:42:04 +0200
+Subject: net: use trylock in icmp_sk
+
+The locking path can be recursive (same as for sk->sk_lock.slock) and
+therefore we need a trylock version for the locallock, too.
+
+Cc: rt-stable@vger.kernel.org
+Reported-by: Jacek Konieczny <jajcus@jajcus.net>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ net/ipv4/icmp.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/net/ipv4/icmp.c
++++ b/net/ipv4/icmp.c
+@@ -217,12 +217,16 @@ static inline struct sock *icmp_xmit_loc
+ {
+ struct sock *sk;
+
++ if (!local_trylock(icmp_sk_lock))
++ return NULL;
++
+ sk = icmp_sk(net);
+
+ if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
+ /* This can happen if the output path signals a
+ * dst_link_failure() for an outgoing ICMP packet.
+ */
++ local_unlock(icmp_sk_lock);
+ return NULL;
+ }
+ return sk;
+@@ -231,6 +235,7 @@ static inline struct sock *icmp_xmit_loc
+ static inline void icmp_xmit_unlock(struct sock *sk)
+ {
+ spin_unlock(&sk->sk_lock.slock);
++ local_unlock(icmp_sk_lock);
+ }
+
+ int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
+@@ -420,7 +425,6 @@ static void icmp_reply(struct icmp_bxm *
+
+ /* Needed by both icmp_global_allow and icmp_xmit_lock */
+ local_bh_disable();
+- local_lock(icmp_sk_lock);
+
+ /* global icmp_msgs_per_sec */
+ if (!icmpv4_global_allow(net, type, code))
+@@ -465,7 +469,6 @@ static void icmp_reply(struct icmp_bxm *
+ out_unlock:
+ icmp_xmit_unlock(sk);
+ out_bh_enable:
+- local_unlock(icmp_sk_lock);
+ local_bh_enable();
+ }
+
+@@ -678,7 +681,6 @@ void icmp_send(struct sk_buff *skb_in, i
+
+ /* Needed by both icmp_global_allow and icmp_xmit_lock */
+ local_bh_disable();
+- local_lock(icmp_sk_lock);
+
+ /* Check global sysctl_icmp_msgs_per_sec ratelimit, unless
+ * incoming dev is loopback. If outgoing dev change to not be
+@@ -767,7 +769,6 @@ void icmp_send(struct sk_buff *skb_in, i
+ out_unlock:
+ icmp_xmit_unlock(sk);
+ out_bh_enable:
+- local_unlock(icmp_sk_lock);
+ local_bh_enable();
+ out:;
+ }
diff --git a/patches/ping-sysrq.patch b/patches/ping-sysrq.patch
index f14a905f6d0b..38eaa1ae2caf 100644
--- a/patches/ping-sysrq.patch
+++ b/patches/ping-sysrq.patch
@@ -59,7 +59,7 @@ Signed-off-by: Carsten Emde <C.Emde@osadl.org>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
-@@ -931,6 +932,30 @@ static bool icmp_redirect(struct sk_buff
+@@ -932,6 +933,30 @@ static bool icmp_redirect(struct sk_buff
}
/*
@@ -90,7 +90,7 @@ Signed-off-by: Carsten Emde <C.Emde@osadl.org>
* Handle ICMP_ECHO ("ping") requests.
*
* RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo
-@@ -957,6 +982,11 @@ static bool icmp_echo(struct sk_buff *sk
+@@ -958,6 +983,11 @@ static bool icmp_echo(struct sk_buff *sk
icmp_param.data_len = skb->len;
icmp_param.head_len = sizeof(struct icmphdr);
icmp_reply(&icmp_param, skb);
diff --git a/patches/preempt-lazy-support.patch b/patches/preempt-lazy-support.patch
index e98d84bc008d..89124728466b 100644
--- a/patches/preempt-lazy-support.patch
+++ b/patches/preempt-lazy-support.patch
@@ -492,7 +492,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
-@@ -1942,6 +1942,7 @@ tracing_generic_entry_update(struct trac
+@@ -1943,6 +1943,7 @@ tracing_generic_entry_update(struct trac
struct task_struct *tsk = current;
entry->preempt_count = pc & 0xff;
@@ -500,7 +500,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
entry->pid = (tsk) ? tsk->pid : 0;
entry->flags =
#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
-@@ -1952,7 +1953,8 @@ tracing_generic_entry_update(struct trac
+@@ -1953,7 +1954,8 @@ tracing_generic_entry_update(struct trac
((pc & NMI_MASK ) ? TRACE_FLAG_NMI : 0) |
((pc & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) |
((pc & SOFTIRQ_OFFSET) ? TRACE_FLAG_SOFTIRQ : 0) |
@@ -510,7 +510,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
(test_preempt_need_resched() ? TRACE_FLAG_PREEMPT_RESCHED : 0);
entry->migrate_disable = (tsk) ? __migrate_disabled(tsk) & 0xFF : 0;
-@@ -3119,15 +3121,17 @@ get_total_entries(struct trace_buffer *b
+@@ -3142,15 +3144,17 @@ get_total_entries(struct trace_buffer *b
static void print_lat_help_header(struct seq_file *m)
{
@@ -537,7 +537,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
}
static void print_event_info(struct trace_buffer *buf, struct seq_file *m)
-@@ -3153,11 +3157,14 @@ static void print_func_help_header_irq(s
+@@ -3176,11 +3180,14 @@ static void print_func_help_header_irq(s
print_event_info(buf, m);
seq_puts(m, "# _-----=> irqs-off\n"
"# / _----=> need-resched\n"
diff --git a/patches/rt-add-rt-locks.patch b/patches/rt-add-rt-locks.patch
index e6d1fa49adb3..89e706c8cc53 100644
--- a/patches/rt-add-rt-locks.patch
+++ b/patches/rt-add-rt-locks.patch
@@ -2244,7 +2244,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
debug_rt_mutex_proxy_lock(lock, proxy_owner);
rt_mutex_set_owner(lock, proxy_owner);
}
-@@ -1926,3 +2314,25 @@ bool rt_mutex_cleanup_proxy_lock(struct
+@@ -1925,3 +2313,25 @@ bool rt_mutex_cleanup_proxy_lock(struct
return cleanup;
}
diff --git a/patches/rt-locking--Consolidate-lock-functions.patch b/patches/rt-locking--Consolidate-lock-functions.patch
index 20dd8f7123b6..8340f8ec99a0 100644
--- a/patches/rt-locking--Consolidate-lock-functions.patch
+++ b/patches/rt-locking--Consolidate-lock-functions.patch
@@ -49,7 +49,7 @@ Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
LL_WARN(lv->owner);
LL_WARN(lv->nestcnt);
lv->owner = current;
-@@ -98,7 +82,7 @@ static inline void __local_unlock(struct
+@@ -101,7 +85,7 @@ static inline void __local_unlock(struct
return;
lv->owner = NULL;
diff --git a/patches/rt-locking-allow-recursive-local_trylock.patch b/patches/rt-locking-allow-recursive-local_trylock.patch
new file mode 100644
index 000000000000..82521dd7e4c6
--- /dev/null
+++ b/patches/rt-locking-allow-recursive-local_trylock.patch
@@ -0,0 +1,38 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Thu, 21 Sep 2017 14:39:56 +0200
+Subject: rt/locking: allow recursive local_trylock()
+
+required for following networking patch which does recursive try-lock.
+While at it, add the !RT version of it because it did not yet exist.
+
+Cc: rt-stable@vger.kernel.org
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ include/linux/locallock.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/include/linux/locallock.h
++++ b/include/linux/locallock.h
+@@ -68,6 +68,9 @@ static inline int __local_trylock(struct
+ lv->owner = current;
+ lv->nestcnt = 1;
+ return 1;
++ } else if (lv->owner == current) {
++ lv->nestcnt++;
++ return 1;
+ }
+ return 0;
+ }
+@@ -238,6 +241,12 @@ static inline int __local_unlock_irqrest
+
+ static inline void local_irq_lock_init(int lvar) { }
+
++#define local_trylock(lvar) \
++ ({ \
++ preempt_disable(); \
++ 1; \
++ })
++
+ #define local_lock(lvar) preempt_disable()
+ #define local_unlock(lvar) preempt_enable()
+ #define local_lock_irq(lvar) local_irq_disable()
diff --git a/patches/rtmutex-add-a-first-shot-of-ww_mutex.patch b/patches/rtmutex-add-a-first-shot-of-ww_mutex.patch
index ea217e46dcef..eb991c15e0ef 100644
--- a/patches/rtmutex-add-a-first-shot-of-ww_mutex.patch
+++ b/patches/rtmutex-add-a-first-shot-of-ww_mutex.patch
@@ -323,7 +323,7 @@ Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
rt_mutex_slowlock);
}
EXPORT_SYMBOL_GPL(rt_mutex_timed_lock);
-@@ -2247,7 +2394,7 @@ int rt_mutex_wait_proxy_lock(struct rt_m
+@@ -2246,7 +2393,7 @@ int rt_mutex_wait_proxy_lock(struct rt_m
raw_spin_lock_irq(&lock->wait_lock);
/* sleep on the mutex */
set_current_state(TASK_INTERRUPTIBLE);
@@ -332,7 +332,7 @@ Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
/*
* try_to_take_rt_mutex() sets the waiter bit unconditionally. We might
* have to fix that up.
-@@ -2314,24 +2461,98 @@ bool rt_mutex_cleanup_proxy_lock(struct
+@@ -2313,24 +2460,98 @@ bool rt_mutex_cleanup_proxy_lock(struct
return cleanup;
}
diff --git a/patches/series b/patches/series
index fb207e236f2e..32bfb07ec7d9 100644
--- a/patches/series
+++ b/patches/series
@@ -172,6 +172,8 @@ NFSv4-replace-seqcount_t-with-a-seqlock_t.patch
############################################################
# Submitted on LKML
############################################################
+Bluetooth-avoid-recursive-locking-in-hci_send_to_cha.patch
+iommu-amd-Use-raw_cpu_ptr-instead-of-get_cpu_ptr-for.patch
# SPARC part of erly printk consolidation
sparc64-use-generic-rwsem-spinlocks-rt.patch
@@ -210,39 +212,47 @@ CPUFREQ-Loongson2-drop-set_cpus_allowed_ptr.patch
kernel-sched-Provide-a-pointer-to-the-valid-CPU-mask.patch
add_migrate_disable.patch
-# tracing: Inter-event (e.g. latency) support | 2017-06-27
-0001-tracing-Add-hist_field_name-accessor.patch
-0002-tracing-Reimplement-log2.patch
-0003-ring-buffer-Add-interface-for-setting-absolute-time-.patch
-0004-ring-buffer-Redefine-the-unimplemented-RINGBUF_TIME_.patch
-0005-tracing-Give-event-triggers-access-to-ring_buffer_ev.patch
-0006-tracing-Add-ring-buffer-event-param-to-hist-field-fu.patch
-0007-tracing-Increase-tracing-map-KEYS_MAX-size.patch
-0008-tracing-Break-out-hist-trigger-assignment-parsing.patch
-0009-tracing-Make-traceprobe-parsing-code-reusable.patch
-0010-tracing-Add-NO_DISCARD-event-file-flag.patch
-0011-tracing-Add-post-trigger-flag-to-hist-trigger-comman.patch
-0012-tracing-Add-hist-trigger-timestamp-support.patch
-0013-tracing-Add-per-element-variable-support-to-tracing_.patch
-0014-tracing-Add-hist_data-member-to-hist_field.patch
-0015-tracing-Add-usecs-modifier-for-hist-trigger-timestam.patch
-0016-tracing-Add-variable-support-to-hist-triggers.patch
-0017-tracing-Account-for-variables-in-named-trigger-compa.patch
-0018-tracing-Add-simple-expression-support-to-hist-trigge.patch
-0019-tracing-Add-variable-reference-handling-to-hist-trig.patch
-0020-tracing-Add-support-for-dynamic-tracepoints.patch
-0021-tracing-Add-hist-trigger-action-hook.patch
-0022-tracing-Add-support-for-synthetic-events.patch
-0023-tracing-Add-onmatch-hist-trigger-action-support.patch
-0024-tracing-Add-onmax-hist-trigger-action-support.patch
-0025-tracing-Allow-whitespace-to-surround-hist-trigger-fi.patch
-0026-tracing-Make-duplicate-count-from-tracing_map-availa.patch
-0027-tracing-Add-cpu-field-for-hist-triggers.patch
-0028-tracing-Add-hist-trigger-support-for-variable-refere.patch
-0029-tracing-Add-last-error-error-facility-for-hist-trigg.patch
-0030-tracing-Add-inter-event-hist-trigger-Documentation.patch
-0031-tracing-Make-tracing_set_clock-non-static.patch
-0032-tracing-Add-a-clock-attribute-for-hist-triggers.patch
+# tracing: Inter-event (e.g. latency) support | 2017-09-05
+0001-tracing-Exclude-generic-fields-from-histograms.patch
+0002-tracing-Add-support-to-detect-and-avoid-duplicates.patch
+0003-tracing-Remove-code-which-merges-duplicates.patch
+0004-tracing-Add-hist_field_name-accessor.patch
+0005-tracing-Reimplement-log2.patch
+0006-ring-buffer-Add-interface-for-setting-absolute-time-.patch
+0007-tracing-Apply-absolute-timestamps-to-instance-max-bu.patch
+0008-ring-buffer-Redefine-the-unimplemented-RINGBUF_TIME_.patch
+0009-tracing-Give-event-triggers-access-to-ring_buffer_ev.patch
+0010-tracing-Add-ring-buffer-event-param-to-hist-field-fu.patch
+0011-tracing-Increase-tracing-map-KEYS_MAX-size.patch
+0012-tracing-Break-out-hist-trigger-assignment-parsing.patch
+0013-tracing-Make-traceprobe-parsing-code-reusable.patch
+0014-tracing-Add-hist-trigger-timestamp-support.patch
+0015-tracing-Add-per-element-variable-support-to-tracing_.patch
+0016-tracing-Add-hist_data-member-to-hist_field.patch
+0017-tracing-Add-usecs-modifier-for-hist-trigger-timestam.patch
+0018-tracing-Add-variable-support-to-hist-triggers.patch
+0019-tracing-Account-for-variables-in-named-trigger-compa.patch
+0020-tracing-Add-simple-expression-support-to-hist-trigge.patch
+0021-tracing-Generalize-per-element-hist-trigger-data.patch
+0022-tracing-Pass-tracing_map_elt-to-hist_field-accessor-.patch
+0023-tracing-Add-hist_field-type-field.patch
+0024-tracing-Add-variable-reference-handling-to-hist-trig.patch
+0025-tracing-Add-support-for-dynamic-tracepoints.patch
+0026-tracing-Add-hist-trigger-action-hook.patch
+0027-tracing-Add-support-for-synthetic-events.patch
+0028-tracing-Add-support-for-field-variables.patch
+0029-tracing-Add-onmatch-hist-trigger-action-support.patch
+0030-tracing-Add-onmax-hist-trigger-action-support.patch
+0031-tracing-Allow-whitespace-to-surround-hist-trigger-fi.patch
+0032-tracing-Add-cpu-field-for-hist-triggers.patch
+0033-tracing-Add-hist-trigger-support-for-variable-refere.patch
+0034-tracing-Add-last-error-error-facility-for-hist-trigg.patch
+0035-tracing-Reverse-the-order-event_mutex-trace_types_lo.patch
+0036-tracing-Remove-lookups-from-tracing_map-hitcount.patch
+0037-tracing-Add-inter-event-hist-trigger-Documentation.patch
+0038-tracing-Make-tracing_set_clock-non-static.patch
+0039-tracing-Add-a-clock-attribute-for-hist-triggers.patch
+0040-tracing-Add-trace_event_buffer_reserve-variant-that-.patch
# SCHED BLOCK/WQ
block-shorten-interrupt-disabled-regions.patch
@@ -335,6 +345,7 @@ preempt-nort-rt-variants.patch
# local locks & migrate disable
futex-workaround-migrate_disable-enable-in-different.patch
rt-local-irq-lock.patch
+rt-locking-allow-recursive-local_trylock.patch
locallock-add-local_lock_on.patch
# ANNOTATE local_irq_disable sites
@@ -474,6 +485,7 @@ fs-nfs-turn-rmdir_sem-into-a-semaphore.patch
# FUTEX/RTMUTEX
rtmutex-futex-prepare-rt.patch
futex-requeue-pi-fix.patch
+locking-rtmutex-don-t-drop-the-wait_lock-twice.patch
futex-Ensure-lock-unlock-symetry-versus-pi_lock-and-.patch
# RTMUTEX
@@ -594,6 +606,7 @@ net-Qdisc-use-a-seqlock-instead-seqcount.patch
net-add-back-the-missing-serialization-in-ip_send_un.patch
net-take-the-tcp_sk_lock-lock-with-BH-disabled.patch
net-add-a-lock-around-icmp_sk.patch
+net-use-trylock-in-icmp_sk.patch
net-Have-__napi_schedule_irqoff-disable-interrupts-o.patch
# NETWORK DEBUGGING AID