]> rtime.felk.cvut.cz Git - hercules2020/nv-tegra/linux-4.4.git/blob - rt-patches/0217-seqlock-Prevent-rt-starvation.patch
rt_patches: required rebase due to printk change
[hercules2020/nv-tegra/linux-4.4.git] / rt-patches / 0217-seqlock-Prevent-rt-starvation.patch
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
5
6 If a low prio writer gets preempted while holding the seqlock write
7 locked, a high prio reader spins forever on RT.
8
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.
12
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
15 possible.
16
17 Nicholas Mc Guire:
18 - spin_lock+unlock => spin_unlock_wait
19 - __write_seqcount_begin => __raw_write_seqcount_begin
20
21 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
22 ---
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(-)
27
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);
34  }
35  
36 -
37 -
38 -static inline void raw_write_seqcount_begin(seqcount_t *s)
39 +static inline void __raw_write_seqcount_begin(seqcount_t *s)
40  {
41         s->sequence++;
42         smp_wmb();
43  }
44  
45 -static inline void raw_write_seqcount_end(seqcount_t *s)
46 +static inline void raw_write_seqcount_begin(seqcount_t *s)
47 +{
48 +       preempt_disable_rt();
49 +       __raw_write_seqcount_begin(s);
50 +}
51 +
52 +static inline void __raw_write_seqcount_end(seqcount_t *s)
53  {
54         smp_wmb();
55         s->sequence++;
56  }
57  
58 +static inline void raw_write_seqcount_end(seqcount_t *s)
59 +{
60 +       __raw_write_seqcount_end(s);
61 +       preempt_enable_rt();
62 +}
63 +
64  /**
65   * raw_write_seqcount_barrier - do a seq write barrier
66   * @s: pointer to seqcount_t
67 @@ -425,10 +435,32 @@ typedef struct {
68  /*
69   * Read side functions for starting and finalizing a read side section.
70   */
71 +#ifndef CONFIG_PREEMPT_RT_FULL
72  static inline unsigned read_seqbegin(const seqlock_t *sl)
73  {
74         return read_seqcount_begin(&sl->seqcount);
75  }
76 +#else
77 +/*
78 + * Starvation safe read side for RT
79 + */
80 +static inline unsigned read_seqbegin(seqlock_t *sl)
81 +{
82 +       unsigned ret;
83 +
84 +repeat:
85 +       ret = ACCESS_ONCE(sl->seqcount.sequence);
86 +       if (unlikely(ret & 1)) {
87 +               /*
88 +                * Take the lock and let the writer proceed (i.e. evtl
89 +                * boost it), otherwise we could loop here forever.
90 +                */
91 +               spin_unlock_wait(&sl->lock);
92 +               goto repeat;
93 +       }
94 +       return ret;
95 +}
96 +#endif
97  
98  static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start)
99  {
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)
102  {
103         spin_lock(&sl->lock);
104 -       write_seqcount_begin(&sl->seqcount);
105 +       __raw_write_seqcount_begin(&sl->seqcount);
106  }
107  
108  static inline void write_sequnlock(seqlock_t *sl)
109  {
110 -       write_seqcount_end(&sl->seqcount);
111 +       __raw_write_seqcount_end(&sl->seqcount);
112         spin_unlock(&sl->lock);
113  }
114  
115  static inline void write_seqlock_bh(seqlock_t *sl)
116  {
117         spin_lock_bh(&sl->lock);
118 -       write_seqcount_begin(&sl->seqcount);
119 +       __raw_write_seqcount_begin(&sl->seqcount);
120  }
121  
122  static inline void write_sequnlock_bh(seqlock_t *sl)
123  {
124 -       write_seqcount_end(&sl->seqcount);
125 +       __raw_write_seqcount_end(&sl->seqcount);
126         spin_unlock_bh(&sl->lock);
127  }
128  
129  static inline void write_seqlock_irq(seqlock_t *sl)
130  {
131         spin_lock_irq(&sl->lock);
132 -       write_seqcount_begin(&sl->seqcount);
133 +       __raw_write_seqcount_begin(&sl->seqcount);
134  }
135  
136  static inline void write_sequnlock_irq(seqlock_t *sl)
137  {
138 -       write_seqcount_end(&sl->seqcount);
139 +       __raw_write_seqcount_end(&sl->seqcount);
140         spin_unlock_irq(&sl->lock);
141  }
142  
143 @@ -481,7 +513,7 @@ static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl)
144         unsigned long flags;
145  
146         spin_lock_irqsave(&sl->lock, flags);
147 -       write_seqcount_begin(&sl->seqcount);
148 +       __raw_write_seqcount_begin(&sl->seqcount);
149         return flags;
150  }
151  
152 @@ -491,7 +523,7 @@ static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl)
153  static inline void
154  write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags)
155  {
156 -       write_seqcount_end(&sl->seqcount);
157 +       __raw_write_seqcount_end(&sl->seqcount);
158         spin_unlock_irqrestore(&sl->lock, flags);
159  }
160  
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,
167                                    struct sk_buff *skb)
168  {
169 -       const struct hh_cache *hh;
170 +       struct hh_cache *hh;
171  
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)
179  }
180  #endif
181  
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)
184  {
185         unsigned int seq;
186         int hh_len;
187 @@ -501,7 +501,7 @@ struct neighbour_cb {
188  
189  #define NEIGH_CB(skb)  ((struct neighbour_cb *)(skb)->cb)
190  
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)
194  {
195         unsigned int seq;
196 -- 
197 1.9.1
198