Merge pull request #580 from wigyori/cc-libpcap
[15.05/openwrt.git] / target / linux / generic / patches-3.18 / 080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch
1 From: Alexander Duyck <alexander.h.duyck@redhat.com>
2 Date: Wed, 31 Dec 2014 10:56:24 -0800
3 Subject: [PATCH] fib_trie: Push rcu_read_lock/unlock to callers
4
5 This change is to start cleaning up some of the rcu_read_lock/unlock
6 handling.  I realized while reviewing the code there are several spots that
7 I don't believe are being handled correctly or are masking warnings by
8 locally calling rcu_read_lock/unlock instead of calling them at the correct
9 level.
10
11 A common example is a call to fib_get_table followed by fib_table_lookup.
12 The rcu_read_lock/unlock ought to wrap both but there are several spots where
13 they were not wrapped.
14
15 Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com>
16 Signed-off-by: David S. Miller <davem@davemloft.net>
17 ---
18
19 --- a/include/net/ip_fib.h
20 +++ b/include/net/ip_fib.h
21 @@ -222,16 +222,19 @@ static inline struct fib_table *fib_new_
22  static inline int fib_lookup(struct net *net, const struct flowi4 *flp,
23                              struct fib_result *res)
24  {
25 -       struct fib_table *table;
26 +       int err = -ENETUNREACH;
27  
28 -       table = fib_get_table(net, RT_TABLE_LOCAL);
29 -       if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
30 -               return 0;
31 -
32 -       table = fib_get_table(net, RT_TABLE_MAIN);
33 -       if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF))
34 -               return 0;
35 -       return -ENETUNREACH;
36 +       rcu_read_lock();
37 +
38 +       if (!fib_table_lookup(fib_get_table(net, RT_TABLE_LOCAL), flp, res,
39 +                             FIB_LOOKUP_NOREF) ||
40 +           !fib_table_lookup(fib_get_table(net, RT_TABLE_MAIN), flp, res,
41 +                             FIB_LOOKUP_NOREF))
42 +               err = 0;
43 +
44 +       rcu_read_unlock();
45 +
46 +       return err;
47  }
48  
49  #else /* CONFIG_IP_MULTIPLE_TABLES */
50 @@ -247,20 +250,25 @@ static inline int fib_lookup(struct net
51                              struct fib_result *res)
52  {
53         if (!net->ipv4.fib_has_custom_rules) {
54 +               int err = -ENETUNREACH;
55 +
56 +               rcu_read_lock();
57 +
58                 res->tclassid = 0;
59 -               if (net->ipv4.fib_local &&
60 -                   !fib_table_lookup(net->ipv4.fib_local, flp, res,
61 -                                     FIB_LOOKUP_NOREF))
62 -                       return 0;
63 -               if (net->ipv4.fib_main &&
64 -                   !fib_table_lookup(net->ipv4.fib_main, flp, res,
65 -                                     FIB_LOOKUP_NOREF))
66 -                       return 0;
67 -               if (net->ipv4.fib_default &&
68 -                   !fib_table_lookup(net->ipv4.fib_default, flp, res,
69 -                                     FIB_LOOKUP_NOREF))
70 -                       return 0;
71 -               return -ENETUNREACH;
72 +               if ((net->ipv4.fib_local &&
73 +                    !fib_table_lookup(net->ipv4.fib_local, flp, res,
74 +                                      FIB_LOOKUP_NOREF)) ||
75 +                   (net->ipv4.fib_main &&
76 +                    !fib_table_lookup(net->ipv4.fib_main, flp, res,
77 +                                      FIB_LOOKUP_NOREF)) ||
78 +                   (net->ipv4.fib_default &&
79 +                    !fib_table_lookup(net->ipv4.fib_default, flp, res,
80 +                                      FIB_LOOKUP_NOREF)))
81 +                       err = 0;
82 +
83 +               rcu_read_unlock();
84 +
85 +               return err;
86         }
87         return __fib_lookup(net, flp, res);
88  }
89 --- a/net/ipv4/fib_frontend.c
90 +++ b/net/ipv4/fib_frontend.c
91 @@ -109,6 +109,7 @@ struct fib_table *fib_new_table(struct n
92         return tb;
93  }
94  
95 +/* caller must hold either rtnl or rcu read lock */
96  struct fib_table *fib_get_table(struct net *net, u32 id)
97  {
98         struct fib_table *tb;
99 @@ -119,15 +120,11 @@ struct fib_table *fib_get_table(struct n
100                 id = RT_TABLE_MAIN;
101         h = id & (FIB_TABLE_HASHSZ - 1);
102  
103 -       rcu_read_lock();
104         head = &net->ipv4.fib_table_hash[h];
105         hlist_for_each_entry_rcu(tb, head, tb_hlist) {
106 -               if (tb->tb_id == id) {
107 -                       rcu_read_unlock();
108 +               if (tb->tb_id == id)
109                         return tb;
110 -               }
111         }
112 -       rcu_read_unlock();
113         return NULL;
114  }
115  #endif /* CONFIG_IP_MULTIPLE_TABLES */
116 @@ -167,16 +164,18 @@ static inline unsigned int __inet_dev_ad
117         if (ipv4_is_multicast(addr))
118                 return RTN_MULTICAST;
119  
120 +       rcu_read_lock();
121 +
122         local_table = fib_get_table(net, RT_TABLE_LOCAL);
123         if (local_table) {
124                 ret = RTN_UNICAST;
125 -               rcu_read_lock();
126                 if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) {
127                         if (!dev || dev == res.fi->fib_dev)
128                                 ret = res.type;
129                 }
130 -               rcu_read_unlock();
131         }
132 +
133 +       rcu_read_unlock();
134         return ret;
135  }
136  
137 @@ -923,7 +922,7 @@ no_promotions:
138  #undef BRD1_OK
139  }
140  
141 -static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
142 +static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn)
143  {
144  
145         struct fib_result       res;
146 @@ -933,6 +932,11 @@ static void nl_fib_lookup(struct fib_res
147                 .flowi4_tos = frn->fl_tos,
148                 .flowi4_scope = frn->fl_scope,
149         };
150 +       struct fib_table *tb;
151 +
152 +       rcu_read_lock();
153 +
154 +       tb = fib_get_table(net, frn->tb_id_in);
155  
156         frn->err = -ENOENT;
157         if (tb) {
158 @@ -949,6 +953,8 @@ static void nl_fib_lookup(struct fib_res
159                 }
160                 local_bh_enable();
161         }
162 +
163 +       rcu_read_unlock();
164  }
165  
166  static void nl_fib_input(struct sk_buff *skb)
167 @@ -956,7 +962,6 @@ static void nl_fib_input(struct sk_buff
168         struct net *net;
169         struct fib_result_nl *frn;
170         struct nlmsghdr *nlh;
171 -       struct fib_table *tb;
172         u32 portid;
173  
174         net = sock_net(skb->sk);
175 @@ -972,9 +977,7 @@ static void nl_fib_input(struct sk_buff
176         nlh = nlmsg_hdr(skb);
177  
178         frn = (struct fib_result_nl *) nlmsg_data(nlh);
179 -       tb = fib_get_table(net, frn->tb_id_in);
180 -
181 -       nl_fib_lookup(frn, tb);
182 +       nl_fib_lookup(net, frn);
183  
184         portid = NETLINK_CB(skb).portid;      /* netlink portid */
185         NETLINK_CB(skb).portid = 0;        /* from kernel */
186 --- a/net/ipv4/fib_rules.c
187 +++ b/net/ipv4/fib_rules.c
188 @@ -81,27 +81,25 @@ static int fib4_rule_action(struct fib_r
189                 break;
190  
191         case FR_ACT_UNREACHABLE:
192 -               err = -ENETUNREACH;
193 -               goto errout;
194 +               return -ENETUNREACH;
195  
196         case FR_ACT_PROHIBIT:
197 -               err = -EACCES;
198 -               goto errout;
199 +               return -EACCES;
200  
201         case FR_ACT_BLACKHOLE:
202         default:
203 -               err = -EINVAL;
204 -               goto errout;
205 +               return -EINVAL;
206         }
207  
208 +       rcu_read_lock();
209 +
210         tbl = fib_get_table(rule->fr_net, rule->table);
211 -       if (!tbl)
212 -               goto errout;
213 +       if (tbl)
214 +               err = fib_table_lookup(tbl, &flp->u.ip4,
215 +                                      (struct fib_result *)arg->result,
216 +                                      arg->flags);
217  
218 -       err = fib_table_lookup(tbl, &flp->u.ip4, (struct fib_result *) arg->result, arg->flags);
219 -       if (err > 0)
220 -               err = -EAGAIN;
221 -errout:
222 +       rcu_read_unlock();
223         return err;
224  }
225  
226 --- a/net/ipv4/fib_trie.c
227 +++ b/net/ipv4/fib_trie.c
228 @@ -1181,72 +1181,6 @@ err:
229         return err;
230  }
231  
232 -/* should be called with rcu_read_lock */
233 -static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l,
234 -                     t_key key,  const struct flowi4 *flp,
235 -                     struct fib_result *res, int fib_flags)
236 -{
237 -       struct leaf_info *li;
238 -       struct hlist_head *hhead = &l->list;
239 -
240 -       hlist_for_each_entry_rcu(li, hhead, hlist) {
241 -               struct fib_alias *fa;
242 -
243 -               if (l->key != (key & li->mask_plen))
244 -                       continue;
245 -
246 -               list_for_each_entry_rcu(fa, &li->falh, fa_list) {
247 -                       struct fib_info *fi = fa->fa_info;
248 -                       int nhsel, err;
249 -
250 -                       if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
251 -                               continue;
252 -                       if (fi->fib_dead)
253 -                               continue;
254 -                       if (fa->fa_info->fib_scope < flp->flowi4_scope)
255 -                               continue;
256 -                       fib_alias_accessed(fa);
257 -                       err = fib_props[fa->fa_type].error;
258 -                       if (unlikely(err < 0)) {
259 -#ifdef CONFIG_IP_FIB_TRIE_STATS
260 -                               this_cpu_inc(t->stats->semantic_match_passed);
261 -#endif
262 -                               return err;
263 -                       }
264 -                       if (fi->fib_flags & RTNH_F_DEAD)
265 -                               continue;
266 -                       for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
267 -                               const struct fib_nh *nh = &fi->fib_nh[nhsel];
268 -
269 -                               if (nh->nh_flags & RTNH_F_DEAD)
270 -                                       continue;
271 -                               if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
272 -                                       continue;
273 -
274 -#ifdef CONFIG_IP_FIB_TRIE_STATS
275 -                               this_cpu_inc(t->stats->semantic_match_passed);
276 -#endif
277 -                               res->prefixlen = li->plen;
278 -                               res->nh_sel = nhsel;
279 -                               res->type = fa->fa_type;
280 -                               res->scope = fi->fib_scope;
281 -                               res->fi = fi;
282 -                               res->table = tb;
283 -                               res->fa_head = &li->falh;
284 -                               if (!(fib_flags & FIB_LOOKUP_NOREF))
285 -                                       atomic_inc(&fi->fib_clntref);
286 -                               return 0;
287 -                       }
288 -               }
289 -
290 -#ifdef CONFIG_IP_FIB_TRIE_STATS
291 -               this_cpu_inc(t->stats->semantic_match_miss);
292 -#endif
293 -       }
294 -
295 -       return 1;
296 -}
297 -
298  static inline t_key prefix_mismatch(t_key key, struct tnode *n)
299  {
300         t_key prefix = n->key;
301 @@ -1254,6 +1188,7 @@ static inline t_key prefix_mismatch(t_ke
302         return (key ^ prefix) & (prefix | -prefix);
303  }
304  
305 +/* should be called with rcu_read_lock */
306  int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
307                      struct fib_result *res, int fib_flags)
308  {
309 @@ -1263,14 +1198,12 @@ int fib_table_lookup(struct fib_table *t
310  #endif
311         const t_key key = ntohl(flp->daddr);
312         struct tnode *n, *pn;
313 +       struct leaf_info *li;
314         t_key cindex;
315 -       int ret = 1;
316 -
317 -       rcu_read_lock();
318  
319         n = rcu_dereference(t->trie);
320         if (!n)
321 -               goto failed;
322 +               return -EAGAIN;
323  
324  #ifdef CONFIG_IP_FIB_TRIE_STATS
325         this_cpu_inc(stats->gets);
326 @@ -1350,7 +1283,7 @@ backtrace:
327  
328                                 pn = node_parent_rcu(pn);
329                                 if (unlikely(!pn))
330 -                                       goto failed;
331 +                                       return -EAGAIN;
332  #ifdef CONFIG_IP_FIB_TRIE_STATS
333                                 this_cpu_inc(stats->backtrack);
334  #endif
335 @@ -1368,12 +1301,62 @@ backtrace:
336  
337  found:
338         /* Step 3: Process the leaf, if that fails fall back to backtracing */
339 -       ret = check_leaf(tb, t, n, key, flp, res, fib_flags);
340 -       if (unlikely(ret > 0))
341 -               goto backtrace;
342 -failed:
343 -       rcu_read_unlock();
344 -       return ret;
345 +       hlist_for_each_entry_rcu(li, &n->list, hlist) {
346 +               struct fib_alias *fa;
347 +
348 +               if ((key ^ n->key) & li->mask_plen)
349 +                       continue;
350 +
351 +               list_for_each_entry_rcu(fa, &li->falh, fa_list) {
352 +                       struct fib_info *fi = fa->fa_info;
353 +                       int nhsel, err;
354 +
355 +                       if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
356 +                               continue;
357 +                       if (fi->fib_dead)
358 +                               continue;
359 +                       if (fa->fa_info->fib_scope < flp->flowi4_scope)
360 +                               continue;
361 +                       fib_alias_accessed(fa);
362 +                       err = fib_props[fa->fa_type].error;
363 +                       if (unlikely(err < 0)) {
364 +#ifdef CONFIG_IP_FIB_TRIE_STATS
365 +                               this_cpu_inc(stats->semantic_match_passed);
366 +#endif
367 +                               return err;
368 +                       }
369 +                       if (fi->fib_flags & RTNH_F_DEAD)
370 +                               continue;
371 +                       for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
372 +                               const struct fib_nh *nh = &fi->fib_nh[nhsel];
373 +
374 +                               if (nh->nh_flags & RTNH_F_DEAD)
375 +                                       continue;
376 +                               if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
377 +                                       continue;
378 +
379 +                               if (!(fib_flags & FIB_LOOKUP_NOREF))
380 +                                       atomic_inc(&fi->fib_clntref);
381 +
382 +                               res->prefixlen = li->plen;
383 +                               res->nh_sel = nhsel;
384 +                               res->type = fa->fa_type;
385 +                               res->scope = fi->fib_scope;
386 +                               res->fi = fi;
387 +                               res->table = tb;
388 +                               res->fa_head = &li->falh;
389 +#ifdef CONFIG_IP_FIB_TRIE_STATS
390 +                               this_cpu_inc(stats->semantic_match_passed);
391 +#endif
392 +                               return err;
393 +                       }
394 +               }
395 +
396 +#ifdef CONFIG_IP_FIB_TRIE_STATS
397 +               this_cpu_inc(stats->semantic_match_miss);
398 +#endif
399 +       }
400 +       goto backtrace;
401  }
402  EXPORT_SYMBOL_GPL(fib_table_lookup);
403