summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0036-kcov-Replace-local_irq_save-with-a-local_lock_t.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches-rt/0036-kcov-Replace-local_irq_save-with-a-local_lock_t.patch')
-rw-r--r--debian/patches-rt/0036-kcov-Replace-local_irq_save-with-a-local_lock_t.patch165
1 files changed, 165 insertions, 0 deletions
diff --git a/debian/patches-rt/0036-kcov-Replace-local_irq_save-with-a-local_lock_t.patch b/debian/patches-rt/0036-kcov-Replace-local_irq_save-with-a-local_lock_t.patch
new file mode 100644
index 000000000..5e6d11ac8
--- /dev/null
+++ b/debian/patches-rt/0036-kcov-Replace-local_irq_save-with-a-local_lock_t.patch
@@ -0,0 +1,165 @@
+From 7b2278b28a056115169b0a90c9dae0a537911e25 Mon Sep 17 00:00:00 2001
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Mon, 30 Aug 2021 19:26:27 +0200
+Subject: [PATCH 036/158] kcov: Replace local_irq_save() with a local_lock_t.
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.15/older/patches-5.15.10-rt24.tar.xz
+
+The kcov code mixes local_irq_save() and spin_lock() in
+kcov_remote_{start|end}(). This creates a warning on PREEMPT_RT because
+local_irq_save() disables interrupts and spin_lock_t is turned into a
+sleeping lock which can not be acquired in a section with disabled
+interrupts.
+
+The kcov_remote_lock is used to synchronize the access to the hash-list
+kcov_remote_map. The local_irq_save() block protects access to the
+per-CPU data kcov_percpu_data.
+
+There no compelling reason to change the lock type to raw_spin_lock_t to
+make it work with local_irq_save(). Changing it would require to move
+memory allocation (in kcov_remote_add()) and deallocation outside of the
+locked section.
+Adding an unlimited amount of entries to the hashlist will increase the
+IRQ-off time during lookup. It could be argued that this is debug code
+and the latency does not matter. There is however no need to do so and
+it would allow to use this facility in an RT enabled build.
+
+Using a local_lock_t instead of local_irq_save() has the befit of adding
+a protection scope within the source which makes it obvious what is
+protected. On a !PREEMPT_RT && !LOCKDEP build the local_lock_irqsave()
+maps directly to local_irq_save() so there is overhead at runtime.
+
+Replace the local_irq_save() section with a local_lock_t.
+
+Reported-by: Clark Williams <williams@redhat.com>
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Link: https://lore.kernel.org/r/20210830172627.267989-6-bigeasy@linutronix.de
+---
+ kernel/kcov.c | 30 +++++++++++++++++-------------
+ 1 file changed, 17 insertions(+), 13 deletions(-)
+
+diff --git a/kernel/kcov.c b/kernel/kcov.c
+index 620dc4ffeb68..36ca640c4f8e 100644
+--- a/kernel/kcov.c
++++ b/kernel/kcov.c
+@@ -88,6 +88,7 @@ static struct list_head kcov_remote_areas = LIST_HEAD_INIT(kcov_remote_areas);
+
+ struct kcov_percpu_data {
+ void *irq_area;
++ local_lock_t lock;
+
+ unsigned int saved_mode;
+ unsigned int saved_size;
+@@ -96,7 +97,9 @@ struct kcov_percpu_data {
+ int saved_sequence;
+ };
+
+-static DEFINE_PER_CPU(struct kcov_percpu_data, kcov_percpu_data);
++static DEFINE_PER_CPU(struct kcov_percpu_data, kcov_percpu_data) = {
++ .lock = INIT_LOCAL_LOCK(lock),
++};
+
+ /* Must be called with kcov_remote_lock locked. */
+ static struct kcov_remote *kcov_remote_find(u64 handle)
+@@ -824,7 +827,7 @@ void kcov_remote_start(u64 handle)
+ if (!in_task() && !in_serving_softirq())
+ return;
+
+- local_irq_save(flags);
++ local_lock_irqsave(&kcov_percpu_data.lock, flags);
+
+ /*
+ * Check that kcov_remote_start() is not called twice in background
+@@ -832,7 +835,7 @@ void kcov_remote_start(u64 handle)
+ */
+ mode = READ_ONCE(t->kcov_mode);
+ if (WARN_ON(in_task() && kcov_mode_enabled(mode))) {
+- local_irq_restore(flags);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+ return;
+ }
+ /*
+@@ -841,14 +844,15 @@ void kcov_remote_start(u64 handle)
+ * happened while collecting coverage from a background thread.
+ */
+ if (WARN_ON(in_serving_softirq() && t->kcov_softirq)) {
+- local_irq_restore(flags);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+ return;
+ }
+
+ spin_lock(&kcov_remote_lock);
+ remote = kcov_remote_find(handle);
+ if (!remote) {
+- spin_unlock_irqrestore(&kcov_remote_lock, flags);
++ spin_unlock(&kcov_remote_lock);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+ return;
+ }
+ kcov_debug("handle = %llx, context: %s\n", handle,
+@@ -873,13 +877,13 @@ void kcov_remote_start(u64 handle)
+
+ /* Can only happen when in_task(). */
+ if (!area) {
+- local_irqrestore(flags);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+ area = vmalloc(size * sizeof(unsigned long));
+ if (!area) {
+ kcov_put(kcov);
+ return;
+ }
+- local_irq_save(flags);
++ local_lock_irqsave(&kcov_percpu_data.lock, flags);
+ }
+
+ /* Reset coverage size. */
+@@ -891,7 +895,7 @@ void kcov_remote_start(u64 handle)
+ }
+ kcov_start(t, kcov, size, area, mode, sequence);
+
+- local_irq_restore(flags);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+
+ }
+ EXPORT_SYMBOL(kcov_remote_start);
+@@ -965,12 +969,12 @@ void kcov_remote_stop(void)
+ if (!in_task() && !in_serving_softirq())
+ return;
+
+- local_irq_save(flags);
++ local_lock_irqsave(&kcov_percpu_data.lock, flags);
+
+ mode = READ_ONCE(t->kcov_mode);
+ barrier();
+ if (!kcov_mode_enabled(mode)) {
+- local_irq_restore(flags);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+ return;
+ }
+ /*
+@@ -978,12 +982,12 @@ void kcov_remote_stop(void)
+ * actually found the remote handle and started collecting coverage.
+ */
+ if (in_serving_softirq() && !t->kcov_softirq) {
+- local_irq_restore(flags);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+ return;
+ }
+ /* Make sure that kcov_softirq is only set when in softirq. */
+ if (WARN_ON(!in_serving_softirq() && t->kcov_softirq)) {
+- local_irq_restore(flags);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+ return;
+ }
+
+@@ -1013,7 +1017,7 @@ void kcov_remote_stop(void)
+ spin_unlock(&kcov_remote_lock);
+ }
+
+- local_irq_restore(flags);
++ local_unlock_irqrestore(&kcov_percpu_data.lock, flags);
+
+ /* Get in kcov_remote_start(). */
+ kcov_put(kcov);
+--
+2.33.1
+