1 From 00f0ecdf9db5a3d4496655320a6713becf4a0734 Mon Sep 17 00:00:00 2001
2 From: Thomas Gleixner <tglx@linutronix.de>
3 Date: Wed, 22 Feb 2012 12:03:30 +0100
4 Subject: [PATCH 217/366] seqlock: Prevent rt starvation
6 If a low prio writer gets preempted while holding the seqlock write
7 locked, a high prio reader spins forever on RT.
9 To prevent this let the reader grab the spinlock, so it blocks and
10 eventually boosts the writer. This way the writer can proceed and
11 endless spinning is prevented.
13 For seqcount writers we disable preemption over the update code
14 path. Thanks to Al Viro for distangling some VFS code to make that
18 - spin_lock+unlock => spin_unlock_wait
19 - __write_seqcount_begin => __raw_write_seqcount_begin
21 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
23 include/linux/seqlock.h | 56 ++++++++++++++++++++++++++++++++++++++-----------
24 include/net/dst.h | 2 +-
25 include/net/neighbour.h | 4 ++--
26 3 files changed, 47 insertions(+), 15 deletions(-)
28 diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
29 index e058210..b14f4d2 100644
30 --- a/include/linux/seqlock.h
31 +++ b/include/linux/seqlock.h
32 @@ -220,20 +220,30 @@ static inline int read_seqcount_retry(const seqcount_t *s, unsigned start)
33 return __read_seqcount_retry(s, start);
38 -static inline void raw_write_seqcount_begin(seqcount_t *s)
39 +static inline void __raw_write_seqcount_begin(seqcount_t *s)
45 -static inline void raw_write_seqcount_end(seqcount_t *s)
46 +static inline void raw_write_seqcount_begin(seqcount_t *s)
48 + preempt_disable_rt();
49 + __raw_write_seqcount_begin(s);
52 +static inline void __raw_write_seqcount_end(seqcount_t *s)
58 +static inline void raw_write_seqcount_end(seqcount_t *s)
60 + __raw_write_seqcount_end(s);
61 + preempt_enable_rt();
65 * raw_write_seqcount_barrier - do a seq write barrier
66 * @s: pointer to seqcount_t
67 @@ -425,10 +435,32 @@ typedef struct {
69 * Read side functions for starting and finalizing a read side section.
71 +#ifndef CONFIG_PREEMPT_RT_FULL
72 static inline unsigned read_seqbegin(const seqlock_t *sl)
74 return read_seqcount_begin(&sl->seqcount);
78 + * Starvation safe read side for RT
80 +static inline unsigned read_seqbegin(seqlock_t *sl)
85 + ret = ACCESS_ONCE(sl->seqcount.sequence);
86 + if (unlikely(ret & 1)) {
88 + * Take the lock and let the writer proceed (i.e. evtl
89 + * boost it), otherwise we could loop here forever.
91 + spin_unlock_wait(&sl->lock);
98 static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
100 @@ -443,36 +475,36 @@ static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
101 static inline void write_seqlock(seqlock_t *sl)
103 spin_lock(&sl->lock);
104 - write_seqcount_begin(&sl->seqcount);
105 + __raw_write_seqcount_begin(&sl->seqcount);
108 static inline void write_sequnlock(seqlock_t *sl)
110 - write_seqcount_end(&sl->seqcount);
111 + __raw_write_seqcount_end(&sl->seqcount);
112 spin_unlock(&sl->lock);
115 static inline void write_seqlock_bh(seqlock_t *sl)
117 spin_lock_bh(&sl->lock);
118 - write_seqcount_begin(&sl->seqcount);
119 + __raw_write_seqcount_begin(&sl->seqcount);
122 static inline void write_sequnlock_bh(seqlock_t *sl)
124 - write_seqcount_end(&sl->seqcount);
125 + __raw_write_seqcount_end(&sl->seqcount);
126 spin_unlock_bh(&sl->lock);
129 static inline void write_seqlock_irq(seqlock_t *sl)
131 spin_lock_irq(&sl->lock);
132 - write_seqcount_begin(&sl->seqcount);
133 + __raw_write_seqcount_begin(&sl->seqcount);
136 static inline void write_sequnlock_irq(seqlock_t *sl)
138 - write_seqcount_end(&sl->seqcount);
139 + __raw_write_seqcount_end(&sl->seqcount);
140 spin_unlock_irq(&sl->lock);
143 @@ -481,7 +513,7 @@ static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl)
146 spin_lock_irqsave(&sl->lock, flags);
147 - write_seqcount_begin(&sl->seqcount);
148 + __raw_write_seqcount_begin(&sl->seqcount);
152 @@ -491,7 +523,7 @@ static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl)
154 write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags)
156 - write_seqcount_end(&sl->seqcount);
157 + __raw_write_seqcount_end(&sl->seqcount);
158 spin_unlock_irqrestore(&sl->lock, flags);
161 diff --git a/include/net/dst.h b/include/net/dst.h
162 index c7329dc..35c3dba 100644
163 --- a/include/net/dst.h
164 +++ b/include/net/dst.h
165 @@ -437,7 +437,7 @@ static inline void dst_confirm(struct dst_entry *dst)
166 static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
169 - const struct hh_cache *hh;
170 + struct hh_cache *hh;
172 if (dst->pending_confirm) {
173 unsigned long now = jiffies;
174 diff --git a/include/net/neighbour.h b/include/net/neighbour.h
175 index 8b68384..bf65600 100644
176 --- a/include/net/neighbour.h
177 +++ b/include/net/neighbour.h
178 @@ -446,7 +446,7 @@ static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
182 -static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb)
183 +static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
187 @@ -501,7 +501,7 @@ struct neighbour_cb {
189 #define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb)
191 -static inline void neigh_ha_snapshot(char *dst, const struct neighbour *n,
192 +static inline void neigh_ha_snapshot(char *dst, struct neighbour *n,
193 const struct net_device *dev)