git: 097991f8ffd6 - stable/13 - linuxkpi: Mitigate a seqlock livelock
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 09 May 2022 12:32:20 UTC
The branch stable/13 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=097991f8ffd639b38fce65d4acf7b4986bca8dcf commit 097991f8ffd639b38fce65d4acf7b4986bca8dcf Author: Mark Johnston <markj@FreeBSD.org> AuthorDate: 2022-04-25 13:13:03 +0000 Commit: Mark Johnston <markj@FreeBSD.org> CommitDate: 2022-05-09 12:32:09 +0000 linuxkpi: Mitigate a seqlock livelock Disable preemption in seqlock write sections when using the _irqsave variant. This ensures that a writer can't be preempted and subsequently starved by a reader running in a callout handler on the same CPU. This fixes occasional display hangs seen when using the i915 driver. Tested by: emaste, wulf Reviewed by: wulf, hselasky Sponsored by: The FreeBSD Foundation (cherry picked from commit efb8f0b8db8747243f7999b874403d5c86e93b74) --- sys/compat/linuxkpi/common/include/linux/seqlock.h | 32 +++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/sys/compat/linuxkpi/common/include/linux/seqlock.h b/sys/compat/linuxkpi/common/include/linux/seqlock.h index 03d36d89de89..2f4892525e8a 100644 --- a/sys/compat/linuxkpi/common/include/linux/seqlock.h +++ b/sys/compat/linuxkpi/common/include/linux/seqlock.h @@ -30,6 +30,7 @@ #define _LINUXKPI_LINUX_SEQLOCK_H__ #include <sys/param.h> +#include <sys/systm.h> #include <sys/lock.h> #include <sys/mutex.h> #include <sys/seqc.h> @@ -100,29 +101,52 @@ seqlock_init(struct seqlock *seqlock) } static inline void -write_seqlock(struct seqlock *seqlock) +lkpi_write_seqlock(struct seqlock *seqlock, const bool irqsave) { mtx_lock(&seqlock->seql_lock); + if (irqsave) + critical_enter(); write_seqcount_begin(&seqlock->seql_count); } static inline void -write_sequnlock(struct seqlock *seqlock) +write_seqlock(struct seqlock *seqlock) +{ + lkpi_write_seqlock(seqlock, false); +} + +static inline void +lkpi_write_sequnlock(struct seqlock *seqlock, const bool irqsave) { write_seqcount_end(&seqlock->seql_count); + if (irqsave) + critical_exit(); mtx_unlock(&seqlock->seql_lock); } +static inline void +write_sequnlock(struct seqlock *seqlock) +{ + lkpi_write_sequnlock(seqlock, false); +} + +/* + * Disable preemption when the consumer wants to disable interrupts. This + * ensures that the caller won't be starved if it is preempted by a + * higher-priority reader, but assumes that the caller won't perform any + * blocking operations while holding the write lock; probably a safe + * assumption. + */ #define write_seqlock_irqsave(seqlock, flags) do { \ (flags) = 0; \ - write_seqlock(seqlock); \ + lkpi_write_seqlock(seqlock, true); \ } while (0) static inline void write_sequnlock_irqrestore(struct seqlock *seqlock, unsigned long flags __unused) { - write_sequnlock(seqlock); + lkpi_write_sequnlock(seqlock, true); } static inline unsigned