diff options
Diffstat (limited to 'debian/patches-rt/0005_kcov_replace_local_irq_save_with_a_local_lock_t.patch')
-rw-r--r-- | debian/patches-rt/0005_kcov_replace_local_irq_save_with_a_local_lock_t.patch | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/debian/patches-rt/0005_kcov_replace_local_irq_save_with_a_local_lock_t.patch b/debian/patches-rt/0005_kcov_replace_local_irq_save_with_a_local_lock_t.patch new file mode 100644 index 000000000..d3f0ab63d --- /dev/null +++ b/debian/patches-rt/0005_kcov_replace_local_irq_save_with_a_local_lock_t.patch @@ -0,0 +1,159 @@ +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Subject: kcov: Replace local_irq_save() with a local_lock_t. +Date: Mon, 30 Aug 2021 19:26:27 +0200 +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.15/older/patches-5.15.3-rt21.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(-) + +--- a/kernel/kcov.c ++++ b/kernel/kcov.c +@@ -88,6 +88,7 @@ static struct list_head kcov_remote_area + + 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); |