summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0005-perf-Move-swevent_htable-recursion-into-task_struct.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches-rt/0005-perf-Move-swevent_htable-recursion-into-task_struct.patch')
-rw-r--r--debian/patches-rt/0005-perf-Move-swevent_htable-recursion-into-task_struct.patch121
1 files changed, 121 insertions, 0 deletions
diff --git a/debian/patches-rt/0005-perf-Move-swevent_htable-recursion-into-task_struct.patch b/debian/patches-rt/0005-perf-Move-swevent_htable-recursion-into-task_struct.patch
new file mode 100644
index 0000000000..5070c10a30
--- /dev/null
+++ b/debian/patches-rt/0005-perf-Move-swevent_htable-recursion-into-task_struct.patch
@@ -0,0 +1,121 @@
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Thu, 4 Jul 2024 19:03:39 +0200
+Subject: [PATCH 5/7] perf: Move swevent_htable::recursion into task_struct.
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/6.10/older/patches-6.10.2-rt14.tar.xz
+
+The swevent_htable::recursion counter is used to avoid creating an
+swevent while an event is processed to avoid recursion. The counter is
+per-CPU and preemption must be disabled to have a stable counter.
+perf_pending_task() disables preemption to access the counter and then
+signal. This is problematic on PREEMPT_RT because sending a signal uses
+a spinlock_t which must not be acquired in atomic on PREEMPT_RT because
+it becomes a sleeping lock.
+
+The atomic context can be avoided by moving the counter into the
+task_struct. There is a 4 byte hole between futex_state (usually always
+on) and the following perf pointer (perf_event_ctxp). After the
+recursion lost some weight it fits perfectly.
+
+Move swevent_htable::recursion into task_struct.
+
+Tested-by: Marco Elver <elver@google.com>
+Link: https://lore.kernel.org/r/20240704170424.1466941-6-bigeasy@linutronix.de
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+---
+ include/linux/perf_event.h | 6 ------
+ include/linux/sched.h | 7 +++++++
+ kernel/events/core.c | 13 +++----------
+ kernel/events/internal.h | 2 +-
+ 4 files changed, 11 insertions(+), 17 deletions(-)
+
+--- a/include/linux/perf_event.h
++++ b/include/linux/perf_event.h
+@@ -970,12 +970,6 @@ struct perf_event_context {
+ local_t nr_pending;
+ };
+
+-/*
+- * Number of contexts where an event can trigger:
+- * task, softirq, hardirq, nmi.
+- */
+-#define PERF_NR_CONTEXTS 4
+-
+ struct perf_cpu_pmu_context {
+ struct perf_event_pmu_context epc;
+ struct perf_event_pmu_context *task_epc;
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -734,6 +734,12 @@ enum perf_event_task_context {
+ perf_nr_task_contexts,
+ };
+
++/*
++ * Number of contexts where an event can trigger:
++ * task, softirq, hardirq, nmi.
++ */
++#define PERF_NR_CONTEXTS 4
++
+ struct wake_q_node {
+ struct wake_q_node *next;
+ };
+@@ -1256,6 +1262,7 @@ struct task_struct {
+ unsigned int futex_state;
+ #endif
+ #ifdef CONFIG_PERF_EVENTS
++ u8 perf_recursion[PERF_NR_CONTEXTS];
+ struct perf_event_context *perf_event_ctxp;
+ struct mutex perf_event_mutex;
+ struct list_head perf_event_list;
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -9774,11 +9774,7 @@ struct swevent_htable {
+ struct swevent_hlist *swevent_hlist;
+ struct mutex hlist_mutex;
+ int hlist_refcount;
+-
+- /* Recursion avoidance in each contexts */
+- u8 recursion[PERF_NR_CONTEXTS];
+ };
+-
+ static DEFINE_PER_CPU(struct swevent_htable, swevent_htable);
+
+ /*
+@@ -9976,17 +9972,13 @@ DEFINE_PER_CPU(struct pt_regs, __perf_re
+
+ int perf_swevent_get_recursion_context(void)
+ {
+- struct swevent_htable *swhash = this_cpu_ptr(&swevent_htable);
+-
+- return get_recursion_context(swhash->recursion);
++ return get_recursion_context(current->perf_recursion);
+ }
+ EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context);
+
+ void perf_swevent_put_recursion_context(int rctx)
+ {
+- struct swevent_htable *swhash = this_cpu_ptr(&swevent_htable);
+-
+- put_recursion_context(swhash->recursion, rctx);
++ put_recursion_context(current->perf_recursion, rctx);
+ }
+
+ void ___perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr)
+@@ -13653,6 +13645,7 @@ int perf_event_init_task(struct task_str
+ {
+ int ret;
+
++ memset(child->perf_recursion, 0, sizeof(child->perf_recursion));
+ child->perf_event_ctxp = NULL;
+ mutex_init(&child->perf_event_mutex);
+ INIT_LIST_HEAD(&child->perf_event_list);
+--- a/kernel/events/internal.h
++++ b/kernel/events/internal.h
+@@ -221,7 +221,7 @@ static inline int get_recursion_context(
+ return rctx;
+ }
+
+-static inline void put_recursion_context(u8 *recursion, int rctx)
++static inline void put_recursion_context(u8 *recursion, unsigned char rctx)
+ {
+ barrier();
+ recursion[rctx]--;