aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2012-02-22 12:03:30 +0100
committerSteven Rostedt <rostedt@rostedt.homelinux.com>2012-10-26 14:31:51 -0400
commit08ffeaa0eed4198636e5162dca1fbf78bffccfc8 (patch)
treedd5bd4c9c04b78ebf2e5d0aa6a94f14125ad7236
parent5853c397c355b51baef031920a302b94112e5875 (diff)
seqlock: Prevent rt starvation
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. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: stable-rt@vger.kernel.org Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--include/linux/seqlock.h23
-rw-r--r--include/net/neighbour.h2
2 files changed, 24 insertions, 1 deletions
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 9bb7fb735144..b911868e8ab8 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -177,10 +177,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 = 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_lock(&sl->lock);
+ spin_unlock(&sl->lock);
+ goto repeat;
+ }
+ return ret;
+}
+#endif
static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
{
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 4014b623880c..9c1cb97c2750 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -377,7 +377,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;