summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0195-seqlock-Prevent-rt-starvation.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches-rt/0195-seqlock-Prevent-rt-starvation.patch')
-rw-r--r--debian/patches-rt/0195-seqlock-Prevent-rt-starvation.patch195
1 files changed, 195 insertions, 0 deletions
diff --git a/debian/patches-rt/0195-seqlock-Prevent-rt-starvation.patch b/debian/patches-rt/0195-seqlock-Prevent-rt-starvation.patch
new file mode 100644
index 000000000..6398461d7
--- /dev/null
+++ b/debian/patches-rt/0195-seqlock-Prevent-rt-starvation.patch
@@ -0,0 +1,195 @@
+From d2adc15afeaebd45ad21834295e100c5627a7fa2 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Wed, 22 Feb 2012 12:03:30 +0100
+Subject: [PATCH 195/347] seqlock: Prevent rt starvation
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.246-rt110.tar.xz
+
+If a low prio writer gets preempted while holding the seqlock write
+locked, a high prio reader spins forever on RT.
+
+To prevent this let the reader grab the spinlock, so it blocks and
+eventually boosts the writer. This way the writer can proceed and
+endless spinning is prevented.
+
+For seqcount writers we disable preemption over the update code
+path. Thanks to Al Viro for distangling some VFS code to make that
+possible.
+
+Nicholas Mc Guire:
+- spin_lock+unlock => spin_unlock_wait
+- __write_seqcount_begin => __raw_write_seqcount_begin
+
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+---
+ include/linux/seqlock.h | 57 ++++++++++++++++++++++++++++++++---------
+ include/net/neighbour.h | 6 ++---
+ 2 files changed, 48 insertions(+), 15 deletions(-)
+
+diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
+index a42a29952889..a3768cfce914 100644
+--- a/include/linux/seqlock.h
++++ b/include/linux/seqlock.h
+@@ -221,20 +221,30 @@ static inline int read_seqcount_retry(const seqcount_t *s, unsigned start)
+ return __read_seqcount_retry(s, start);
+ }
+
+-
+-
+-static inline void raw_write_seqcount_begin(seqcount_t *s)
++static inline void __raw_write_seqcount_begin(seqcount_t *s)
+ {
+ s->sequence++;
+ smp_wmb();
+ }
+
+-static inline void raw_write_seqcount_end(seqcount_t *s)
++static inline void raw_write_seqcount_begin(seqcount_t *s)
++{
++ preempt_disable_rt();
++ __raw_write_seqcount_begin(s);
++}
++
++static inline void __raw_write_seqcount_end(seqcount_t *s)
+ {
+ smp_wmb();
+ s->sequence++;
+ }
+
++static inline void raw_write_seqcount_end(seqcount_t *s)
++{
++ __raw_write_seqcount_end(s);
++ preempt_enable_rt();
++}
++
+ /**
+ * raw_write_seqcount_barrier - do a seq write barrier
+ * @s: pointer to seqcount_t
+@@ -435,10 +445,33 @@ typedef struct {
+ /*
+ * Read side functions for starting and finalizing a read side section.
+ */
++#ifndef CONFIG_PREEMPT_RT_FULL
+ static inline unsigned read_seqbegin(const seqlock_t *sl)
+ {
+ return read_seqcount_begin(&sl->seqcount);
+ }
++#else
++/*
++ * Starvation safe read side for RT
++ */
++static inline unsigned read_seqbegin(seqlock_t *sl)
++{
++ unsigned ret;
++
++repeat:
++ ret = READ_ONCE(sl->seqcount.sequence);
++ if (unlikely(ret & 1)) {
++ /*
++ * Take the lock and let the writer proceed (i.e. evtl
++ * boost it), otherwise we could loop here forever.
++ */
++ spin_unlock_wait(&sl->lock);
++ goto repeat;
++ }
++ smp_rmb();
++ return ret;
++}
++#endif
+
+ static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
+ {
+@@ -453,36 +486,36 @@ static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
+ static inline void write_seqlock(seqlock_t *sl)
+ {
+ spin_lock(&sl->lock);
+- write_seqcount_begin(&sl->seqcount);
++ __raw_write_seqcount_begin(&sl->seqcount);
+ }
+
+ static inline void write_sequnlock(seqlock_t *sl)
+ {
+- write_seqcount_end(&sl->seqcount);
++ __raw_write_seqcount_end(&sl->seqcount);
+ spin_unlock(&sl->lock);
+ }
+
+ static inline void write_seqlock_bh(seqlock_t *sl)
+ {
+ spin_lock_bh(&sl->lock);
+- write_seqcount_begin(&sl->seqcount);
++ __raw_write_seqcount_begin(&sl->seqcount);
+ }
+
+ static inline void write_sequnlock_bh(seqlock_t *sl)
+ {
+- write_seqcount_end(&sl->seqcount);
++ __raw_write_seqcount_end(&sl->seqcount);
+ spin_unlock_bh(&sl->lock);
+ }
+
+ static inline void write_seqlock_irq(seqlock_t *sl)
+ {
+ spin_lock_irq(&sl->lock);
+- write_seqcount_begin(&sl->seqcount);
++ __raw_write_seqcount_begin(&sl->seqcount);
+ }
+
+ static inline void write_sequnlock_irq(seqlock_t *sl)
+ {
+- write_seqcount_end(&sl->seqcount);
++ __raw_write_seqcount_end(&sl->seqcount);
+ spin_unlock_irq(&sl->lock);
+ }
+
+@@ -491,7 +524,7 @@ static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl)
+ unsigned long flags;
+
+ spin_lock_irqsave(&sl->lock, flags);
+- write_seqcount_begin(&sl->seqcount);
++ __raw_write_seqcount_begin(&sl->seqcount);
+ return flags;
+ }
+
+@@ -501,7 +534,7 @@ static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl)
+ static inline void
+ write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags)
+ {
+- write_seqcount_end(&sl->seqcount);
++ __raw_write_seqcount_end(&sl->seqcount);
+ spin_unlock_irqrestore(&sl->lock, flags);
+ }
+
+diff --git a/include/net/neighbour.h b/include/net/neighbour.h
+index 5ce035984a4d..1166fc17b757 100644
+--- a/include/net/neighbour.h
++++ b/include/net/neighbour.h
+@@ -451,7 +451,7 @@ static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
+ }
+ #endif
+
+-static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb)
++static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
+ {
+ unsigned int hh_alen = 0;
+ unsigned int seq;
+@@ -493,7 +493,7 @@ static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb
+
+ static inline int neigh_output(struct neighbour *n, struct sk_buff *skb)
+ {
+- const struct hh_cache *hh = &n->hh;
++ struct hh_cache *hh = &n->hh;
+
+ if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
+ return neigh_hh_output(hh, skb);
+@@ -534,7 +534,7 @@ struct neighbour_cb {
+
+ #define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb)
+
+-static inline void neigh_ha_snapshot(char *dst, const struct neighbour *n,
++static inline void neigh_ha_snapshot(char *dst, struct neighbour *n,
+ const struct net_device *dev)
+ {
+ unsigned int seq;
+--
+2.36.1
+