--- /dev/null
+From 5b590160d2cf776b304eb054afafea2bd55e3620 Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <adrian.hunter@intel.com>
+Date: Tue, 22 Oct 2024 18:59:07 +0300
+Subject: perf/x86/intel/pt: Fix buffer full but size is 0 case
+
+From: Adrian Hunter <adrian.hunter@intel.com>
+
+commit 5b590160d2cf776b304eb054afafea2bd55e3620 upstream.
+
+If the trace data buffer becomes full, a truncated flag [T] is reported
+in PERF_RECORD_AUX. In some cases, the size reported is 0, even though
+data must have been added to make the buffer full.
+
+That happens when the buffer fills up from empty to full before the
+Intel PT driver has updated the buffer position. Then the driver
+calculates the new buffer position before calculating the data size.
+If the old and new positions are the same, the data size is reported
+as 0, even though it is really the whole buffer size.
+
+Fix by detecting when the buffer position is wrapped, and adjust the
+data size calculation accordingly.
+
+Example
+
+ Use a very small buffer size (8K) and observe the size of truncated [T]
+ data. Before the fix, it is possible to see records of 0 size.
+
+ Before:
+
+ $ perf record -m,8K -e intel_pt// uname
+ Linux
+ [ perf record: Woken up 2 times to write data ]
+ [ perf record: Captured and wrote 0.105 MB perf.data ]
+ $ perf script -D --no-itrace | grep AUX | grep -F '[T]'
+ Warning:
+ AUX data lost 2 times out of 3!
+
+ 5 19462712368111 0x19710 [0x40]: PERF_RECORD_AUX offset: 0 size: 0 flags: 0x1 [T]
+ 5 19462712700046 0x19ba8 [0x40]: PERF_RECORD_AUX offset: 0x170 size: 0xe90 flags: 0x1 [T]
+
+ After:
+
+ $ perf record -m,8K -e intel_pt// uname
+ Linux
+ [ perf record: Woken up 3 times to write data ]
+ [ perf record: Captured and wrote 0.040 MB perf.data ]
+ $ perf script -D --no-itrace | grep AUX | grep -F '[T]'
+ Warning:
+ AUX data lost 2 times out of 3!
+
+ 1 113720802995 0x4948 [0x40]: PERF_RECORD_AUX offset: 0 size: 0x2000 flags: 0x1 [T]
+ 1 113720979812 0x6b10 [0x40]: PERF_RECORD_AUX offset: 0x2000 size: 0x2000 flags: 0x1 [T]
+
+Fixes: 52ca9ced3f70 ("perf/x86/intel/pt: Add Intel PT PMU driver")
+Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: stable@vger.kernel.org
+Link: https://lkml.kernel.org/r/20241022155920.17511-2-adrian.hunter@intel.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/x86/events/intel/pt.c | 11 ++++++++---
+ arch/x86/events/intel/pt.h | 2 ++
+ 2 files changed, 10 insertions(+), 3 deletions(-)
+
+--- a/arch/x86/events/intel/pt.c
++++ b/arch/x86/events/intel/pt.c
+@@ -782,11 +782,13 @@ static void pt_buffer_advance(struct pt_
+ buf->cur_idx++;
+
+ if (buf->cur_idx == buf->cur->last) {
+- if (buf->cur == buf->last)
++ if (buf->cur == buf->last) {
+ buf->cur = buf->first;
+- else
++ buf->wrapped = true;
++ } else {
+ buf->cur = list_entry(buf->cur->list.next, struct topa,
+ list);
++ }
+ buf->cur_idx = 0;
+ }
+ }
+@@ -800,8 +802,11 @@ static void pt_buffer_advance(struct pt_
+ static void pt_update_head(struct pt *pt)
+ {
+ struct pt_buffer *buf = perf_get_aux(&pt->handle);
++ bool wrapped = buf->wrapped;
+ u64 topa_idx, base, old;
+
++ buf->wrapped = false;
++
+ /* offset of the first region in this table from the beginning of buf */
+ base = buf->cur->offset + buf->output_off;
+
+@@ -814,7 +819,7 @@ static void pt_update_head(struct pt *pt
+ } else {
+ old = (local64_xchg(&buf->head, base) &
+ ((buf->nr_pages << PAGE_SHIFT) - 1));
+- if (base < old)
++ if (base < old || (base == old && wrapped))
+ base += buf->nr_pages << PAGE_SHIFT;
+
+ local_add(base - old, &buf->data_size);
+--- a/arch/x86/events/intel/pt.h
++++ b/arch/x86/events/intel/pt.h
+@@ -64,6 +64,7 @@ struct pt_pmu {
+ * @lost: if data was lost/truncated
+ * @head: logical write offset inside the buffer
+ * @snapshot: if this is for a snapshot/overwrite counter
++ * @wrapped: buffer advance wrapped back to the first topa table
+ * @stop_pos: STOP topa entry index
+ * @intr_pos: INT topa entry index
+ * @stop_te: STOP topa entry pointer
+@@ -80,6 +81,7 @@ struct pt_buffer {
+ local_t data_size;
+ local64_t head;
+ bool snapshot;
++ bool wrapped;
+ long stop_pos, intr_pos;
+ struct topa_entry *stop_te, *intr_te;
+ void **data_pages;