kernel: split patches folder up into backport, pending and hack folders
[openwrt/staging/chunkeey.git] / target / linux / generic / pending-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 @@ -971,9 +976,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