1
0

080-11-fib_trie-Push-rcu_read_lock-unlock-to-callers.patch 10 KB

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