]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jan 2024 10:18:46 +0000 (11:18 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 3 Jan 2024 10:18:46 +0000 (11:18 +0100)
added patches:
ring-buffer-fix-wake-ups-when-buffer_percent-is-set-to-100.patch
tracing-fix-blocked-reader-of-snapshot-buffer.patch

queue-5.10/ring-buffer-fix-wake-ups-when-buffer_percent-is-set-to-100.patch [new file with mode: 0644]
queue-5.10/series
queue-5.10/tracing-fix-blocked-reader-of-snapshot-buffer.patch [new file with mode: 0644]

diff --git a/queue-5.10/ring-buffer-fix-wake-ups-when-buffer_percent-is-set-to-100.patch b/queue-5.10/ring-buffer-fix-wake-ups-when-buffer_percent-is-set-to-100.patch
new file mode 100644 (file)
index 0000000..910dabe
--- /dev/null
@@ -0,0 +1,73 @@
+From 623b1f896fa8a669a277ee5a258307a16c7377a3 Mon Sep 17 00:00:00 2001
+From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
+Date: Tue, 26 Dec 2023 12:59:02 -0500
+Subject: ring-buffer: Fix wake ups when buffer_percent is set to 100
+
+From: Steven Rostedt (Google) <rostedt@goodmis.org>
+
+commit 623b1f896fa8a669a277ee5a258307a16c7377a3 upstream.
+
+The tracefs file "buffer_percent" is to allow user space to set a
+water-mark on how much of the tracing ring buffer needs to be filled in
+order to wake up a blocked reader.
+
+ 0 - is to wait until any data is in the buffer
+ 1 - is to wait for 1% of the sub buffers to be filled
+ 50 - would be half of the sub buffers are filled with data
+ 100 - is not to wake the waiter until the ring buffer is completely full
+
+Unfortunately the test for being full was:
+
+       dirty = ring_buffer_nr_dirty_pages(buffer, cpu);
+       return (dirty * 100) > (full * nr_pages);
+
+Where "full" is the value for "buffer_percent".
+
+There is two issues with the above when full == 100.
+
+1. dirty * 100 > 100 * nr_pages will never be true
+   That is, the above is basically saying that if the user sets
+   buffer_percent to 100, more pages need to be dirty than exist in the
+   ring buffer!
+
+2. The page that the writer is on is never considered dirty, as dirty
+   pages are only those that are full. When the writer goes to a new
+   sub-buffer, it clears the contents of that sub-buffer.
+
+That is, even if the check was ">=" it would still not be equal as the
+most pages that can be considered "dirty" is nr_pages - 1.
+
+To fix this, add one to dirty and use ">=" in the compare.
+
+Link: https://lore.kernel.org/linux-trace-kernel/20231226125902.4a057f1d@gandalf.local.home
+
+Cc: stable@vger.kernel.org
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Fixes: 03329f9939781 ("tracing: Add tracefs file buffer_percentage")
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/ring_buffer.c |    9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/kernel/trace/ring_buffer.c
++++ b/kernel/trace/ring_buffer.c
+@@ -810,9 +810,14 @@ static __always_inline bool full_hit(str
+       if (!nr_pages || !full)
+               return true;
+-      dirty = ring_buffer_nr_dirty_pages(buffer, cpu);
++      /*
++       * Add one as dirty will never equal nr_pages, as the sub-buffer
++       * that the writer is on is not counted as dirty.
++       * This is needed if "buffer_percent" is set to 100.
++       */
++      dirty = ring_buffer_nr_dirty_pages(buffer, cpu) + 1;
+-      return (dirty * 100) > (full * nr_pages);
++      return (dirty * 100) >= (full * nr_pages);
+ }
+ /*
index 185c6972f4066515e7b1c3306f726b01f59a4de0..2aee73b2491a38001ccefc4899189c264a519060 100644 (file)
@@ -65,3 +65,5 @@ scsi-core-make-scsi_get_lba-return-the-lba.patch
 scsi-core-use-scsi_cmd_to_rq-instead-of-scsi_cmnd.re.patch
 scsi-core-use-a-structure-member-to-track-the-scsi-c.patch
 scsi-core-always-send-batch-on-reset-or-error-handli.patch
+ring-buffer-fix-wake-ups-when-buffer_percent-is-set-to-100.patch
+tracing-fix-blocked-reader-of-snapshot-buffer.patch
diff --git a/queue-5.10/tracing-fix-blocked-reader-of-snapshot-buffer.patch b/queue-5.10/tracing-fix-blocked-reader-of-snapshot-buffer.patch
new file mode 100644 (file)
index 0000000..2ce16a8
--- /dev/null
@@ -0,0 +1,103 @@
+From 39a7dc23a1ed0fe81141792a09449d124c5953bd Mon Sep 17 00:00:00 2001
+From: "Steven Rostedt (Google)" <rostedt@goodmis.org>
+Date: Thu, 28 Dec 2023 09:51:49 -0500
+Subject: tracing: Fix blocked reader of snapshot buffer
+
+From: Steven Rostedt (Google) <rostedt@goodmis.org>
+
+commit 39a7dc23a1ed0fe81141792a09449d124c5953bd upstream.
+
+If an application blocks on the snapshot or snapshot_raw files, expecting
+to be woken up when a snapshot occurs, it will not happen. Or it may
+happen with an unexpected result.
+
+That result is that the application will be reading the main buffer
+instead of the snapshot buffer. That is because when the snapshot occurs,
+the main and snapshot buffers are swapped. But the reader has a descriptor
+still pointing to the buffer that it originally connected to.
+
+This is fine for the main buffer readers, as they may be blocked waiting
+for a watermark to be hit, and when a snapshot occurs, the data that the
+main readers want is now on the snapshot buffer.
+
+But for waiters of the snapshot buffer, they are waiting for an event to
+occur that will trigger the snapshot and they can then consume it quickly
+to save the snapshot before the next snapshot occurs. But to do this, they
+need to read the new snapshot buffer, not the old one that is now
+receiving new data.
+
+Also, it does not make sense to have a watermark "buffer_percent" on the
+snapshot buffer, as the snapshot buffer is static and does not receive new
+data except all at once.
+
+Link: https://lore.kernel.org/linux-trace-kernel/20231228095149.77f5b45d@gandalf.local.home
+
+Cc: stable@vger.kernel.org
+Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
+Fixes: debdd57f5145f ("tracing: Make a snapshot feature available from userspace")
+Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/trace/ring_buffer.c |    3 ++-
+ kernel/trace/trace.c       |   20 +++++++++++++++++---
+ 2 files changed, 19 insertions(+), 4 deletions(-)
+
+--- a/kernel/trace/ring_buffer.c
++++ b/kernel/trace/ring_buffer.c
+@@ -866,7 +866,8 @@ void ring_buffer_wake_waiters(struct tra
+       /* make sure the waiters see the new index */
+       smp_wmb();
+-      rb_wake_up_waiters(&rbwork->work);
++      /* This can be called in any context */
++      irq_work_queue(&rbwork->work);
+ }
+ /**
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -1892,17 +1892,31 @@ update_max_tr_single(struct trace_array
+       __update_max_tr(tr, tsk, cpu);
+       arch_spin_unlock(&tr->max_lock);
++
++      /* Any waiters on the old snapshot buffer need to wake up */
++      ring_buffer_wake_waiters(tr->array_buffer.buffer, RING_BUFFER_ALL_CPUS);
+ }
+ #endif /* CONFIG_TRACER_MAX_TRACE */
+ static int wait_on_pipe(struct trace_iterator *iter, int full)
+ {
++      int ret;
++
+       /* Iterators are static, they should be filled or empty */
+       if (trace_buffer_iter(iter, iter->cpu_file))
+               return 0;
+-      return ring_buffer_wait(iter->array_buffer->buffer, iter->cpu_file,
+-                              full);
++      ret = ring_buffer_wait(iter->array_buffer->buffer, iter->cpu_file, full);
++
++#ifdef CONFIG_TRACER_MAX_TRACE
++      /*
++       * Make sure this is still the snapshot buffer, as if a snapshot were
++       * to happen, this would now be the main buffer.
++       */
++      if (iter->snapshot)
++              iter->array_buffer = &iter->tr->max_buffer;
++#endif
++      return ret;
+ }
+ #ifdef CONFIG_FTRACE_STARTUP_TEST
+@@ -7953,7 +7967,7 @@ tracing_buffers_splice_read(struct file
+               if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK))
+                       goto out;
+-              ret = wait_on_pipe(iter, iter->tr->buffer_percent);
++              ret = wait_on_pipe(iter, iter->snapshot ? 0 : iter->tr->buffer_percent);
+               if (ret)
+                       goto out;