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 MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D35021
This commit is contained in:
parent
15a28c0020
commit
efb8f0b8db
@ -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_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)
|
||||
{
|
||||
write_seqcount_end(&seqlock->seql_count);
|
||||
mtx_unlock(&seqlock->seql_lock);
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user