aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorAlexander Duyck <alexander.h.duyck@redhat.com>2014-12-31 13:56:24 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-31 18:25:54 -0500
commit345e9b54268ae065520a7252c182d22ef4591718 (patch)
treead4e6c4138028f1ad00d6a2aeeb7fff90f094801 /net
parent98293e8d2f51976d5f790400859a517c0f7cb598 (diff)
fib_trie: Push rcu_read_lock/unlock to callers
This change is to start cleaning up some of the rcu_read_lock/unlock handling. I realized while reviewing the code there are several spots that I don't believe are being handled correctly or are masking warnings by locally calling rcu_read_lock/unlock instead of calling them at the correct level. A common example is a call to fib_get_table followed by fib_table_lookup. The rcu_read_lock/unlock ought to wrap both but there are several spots where they were not wrapped. Signed-off-by: Alexander Duyck <alexander.h.duyck@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/fib_frontend.c27
-rw-r--r--net/ipv4/fib_rules.c22
-rw-r--r--net/ipv4/fib_trie.c137
3 files changed, 85 insertions, 101 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 66890209208f..57be71dd6a9e 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -109,6 +109,7 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
109 return tb; 109 return tb;
110} 110}
111 111
112/* caller must hold either rtnl or rcu read lock */
112struct fib_table *fib_get_table(struct net *net, u32 id) 113struct fib_table *fib_get_table(struct net *net, u32 id)
113{ 114{
114 struct fib_table *tb; 115 struct fib_table *tb;
@@ -119,15 +120,11 @@ struct fib_table *fib_get_table(struct net *net, u32 id)
119 id = RT_TABLE_MAIN; 120 id = RT_TABLE_MAIN;
120 h = id & (FIB_TABLE_HASHSZ - 1); 121 h = id & (FIB_TABLE_HASHSZ - 1);
121 122
122 rcu_read_lock();
123 head = &net->ipv4.fib_table_hash[h]; 123 head = &net->ipv4.fib_table_hash[h];
124 hlist_for_each_entry_rcu(tb, head, tb_hlist) { 124 hlist_for_each_entry_rcu(tb, head, tb_hlist) {
125 if (tb->tb_id == id) { 125 if (tb->tb_id == id)
126 rcu_read_unlock();
127 return tb; 126 return tb;
128 }
129 } 127 }
130 rcu_read_unlock();
131 return NULL; 128 return NULL;
132} 129}
133#endif /* CONFIG_IP_MULTIPLE_TABLES */ 130#endif /* CONFIG_IP_MULTIPLE_TABLES */
@@ -167,16 +164,18 @@ static inline unsigned int __inet_dev_addr_type(struct net *net,
167 if (ipv4_is_multicast(addr)) 164 if (ipv4_is_multicast(addr))
168 return RTN_MULTICAST; 165 return RTN_MULTICAST;
169 166
167 rcu_read_lock();
168
170 local_table = fib_get_table(net, RT_TABLE_LOCAL); 169 local_table = fib_get_table(net, RT_TABLE_LOCAL);
171 if (local_table) { 170 if (local_table) {
172 ret = RTN_UNICAST; 171 ret = RTN_UNICAST;
173 rcu_read_lock();
174 if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) { 172 if (!fib_table_lookup(local_table, &fl4, &res, FIB_LOOKUP_NOREF)) {
175 if (!dev || dev == res.fi->fib_dev) 173 if (!dev || dev == res.fi->fib_dev)
176 ret = res.type; 174 ret = res.type;
177 } 175 }
178 rcu_read_unlock();
179 } 176 }
177
178 rcu_read_unlock();
180 return ret; 179 return ret;
181} 180}
182 181
@@ -919,7 +918,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
919#undef BRD1_OK 918#undef BRD1_OK
920} 919}
921 920
922static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb) 921static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn)
923{ 922{
924 923
925 struct fib_result res; 924 struct fib_result res;
@@ -929,6 +928,11 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
929 .flowi4_tos = frn->fl_tos, 928 .flowi4_tos = frn->fl_tos,
930 .flowi4_scope = frn->fl_scope, 929 .flowi4_scope = frn->fl_scope,
931 }; 930 };
931 struct fib_table *tb;
932
933 rcu_read_lock();
934
935 tb = fib_get_table(net, frn->tb_id_in);
932 936
933 frn->err = -ENOENT; 937 frn->err = -ENOENT;
934 if (tb) { 938 if (tb) {
@@ -945,6 +949,8 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb)
945 } 949 }
946 local_bh_enable(); 950 local_bh_enable();
947 } 951 }
952
953 rcu_read_unlock();
948} 954}
949 955
950static void nl_fib_input(struct sk_buff *skb) 956static void nl_fib_input(struct sk_buff *skb)
@@ -952,7 +958,6 @@ static void nl_fib_input(struct sk_buff *skb)
952 struct net *net; 958 struct net *net;
953 struct fib_result_nl *frn; 959 struct fib_result_nl *frn;
954 struct nlmsghdr *nlh; 960 struct nlmsghdr *nlh;
955 struct fib_table *tb;
956 u32 portid; 961 u32 portid;
957 962
958 net = sock_net(skb->sk); 963 net = sock_net(skb->sk);
@@ -967,9 +972,7 @@ static void nl_fib_input(struct sk_buff *skb)
967 nlh = nlmsg_hdr(skb); 972 nlh = nlmsg_hdr(skb);
968 973
969 frn = (struct fib_result_nl *) nlmsg_data(nlh); 974 frn = (struct fib_result_nl *) nlmsg_data(nlh);
970 tb = fib_get_table(net, frn->tb_id_in); 975 nl_fib_lookup(net, frn);
971
972 nl_fib_lookup(frn, tb);
973 976
974 portid = NETLINK_CB(skb).portid; /* netlink portid */ 977 portid = NETLINK_CB(skb).portid; /* netlink portid */
975 NETLINK_CB(skb).portid = 0; /* from kernel */ 978 NETLINK_CB(skb).portid = 0; /* from kernel */
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 8f7bd56955b0..d3db718be51d 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -81,27 +81,25 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
81 break; 81 break;
82 82
83 case FR_ACT_UNREACHABLE: 83 case FR_ACT_UNREACHABLE:
84 err = -ENETUNREACH; 84 return -ENETUNREACH;
85 goto errout;
86 85
87 case FR_ACT_PROHIBIT: 86 case FR_ACT_PROHIBIT:
88 err = -EACCES; 87 return -EACCES;
89 goto errout;
90 88
91 case FR_ACT_BLACKHOLE: 89 case FR_ACT_BLACKHOLE:
92 default: 90 default:
93 err = -EINVAL; 91 return -EINVAL;
94 goto errout;
95 } 92 }
96 93
94 rcu_read_lock();
95
97 tbl = fib_get_table(rule->fr_net, rule->table); 96 tbl = fib_get_table(rule->fr_net, rule->table);
98 if (!tbl) 97 if (tbl)
99 goto errout; 98 err = fib_table_lookup(tbl, &flp->u.ip4,
99 (struct fib_result *)arg->result,
100 arg->flags);
100 101
101 err = fib_table_lookup(tbl, &flp->u.ip4, (struct fib_result *) arg->result, arg->flags); 102 rcu_read_unlock();
102 if (err > 0)
103 err = -EAGAIN;
104errout:
105 return err; 103 return err;
106} 104}
107 105
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 28a3065470bc..987b06d1effe 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1181,72 +1181,6 @@ err:
1181 return err; 1181 return err;
1182} 1182}
1183 1183
1184/* should be called with rcu_read_lock */
1185static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l,
1186 t_key key, const struct flowi4 *flp,
1187 struct fib_result *res, int fib_flags)
1188{
1189 struct leaf_info *li;
1190 struct hlist_head *hhead = &l->list;
1191
1192 hlist_for_each_entry_rcu(li, hhead, hlist) {
1193 struct fib_alias *fa;
1194
1195 if (l->key != (key & li->mask_plen))
1196 continue;
1197
1198 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
1199 struct fib_info *fi = fa->fa_info;
1200 int nhsel, err;
1201
1202 if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
1203 continue;
1204 if (fi->fib_dead)
1205 continue;
1206 if (fa->fa_info->fib_scope < flp->flowi4_scope)
1207 continue;
1208 fib_alias_accessed(fa);
1209 err = fib_props[fa->fa_type].error;
1210 if (unlikely(err < 0)) {
1211#ifdef CONFIG_IP_FIB_TRIE_STATS
1212 this_cpu_inc(t->stats->semantic_match_passed);
1213#endif
1214 return err;
1215 }
1216 if (fi->fib_flags & RTNH_F_DEAD)
1217 continue;
1218 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
1219 const struct fib_nh *nh = &fi->fib_nh[nhsel];
1220
1221 if (nh->nh_flags & RTNH_F_DEAD)
1222 continue;
1223 if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
1224 continue;
1225
1226#ifdef CONFIG_IP_FIB_TRIE_STATS
1227 this_cpu_inc(t->stats->semantic_match_passed);
1228#endif
1229 res->prefixlen = li->plen;
1230 res->nh_sel = nhsel;
1231 res->type = fa->fa_type;
1232 res->scope = fi->fib_scope;
1233 res->fi = fi;
1234 res->table = tb;
1235 res->fa_head = &li->falh;
1236 if (!(fib_flags & FIB_LOOKUP_NOREF))
1237 atomic_inc(&fi->fib_clntref);
1238 return 0;
1239 }
1240 }
1241
1242#ifdef CONFIG_IP_FIB_TRIE_STATS
1243 this_cpu_inc(t->stats->semantic_match_miss);
1244#endif
1245 }
1246
1247 return 1;
1248}
1249
1250static inline t_key prefix_mismatch(t_key key, struct tnode *n) 1184static inline t_key prefix_mismatch(t_key key, struct tnode *n)
1251{ 1185{
1252 t_key prefix = n->key; 1186 t_key prefix = n->key;
@@ -1254,6 +1188,7 @@ static inline t_key prefix_mismatch(t_key key, struct tnode *n)
1254 return (key ^ prefix) & (prefix | -prefix); 1188 return (key ^ prefix) & (prefix | -prefix);
1255} 1189}
1256 1190
1191/* should be called with rcu_read_lock */
1257int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, 1192int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
1258 struct fib_result *res, int fib_flags) 1193 struct fib_result *res, int fib_flags)
1259{ 1194{
@@ -1263,14 +1198,12 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
1263#endif 1198#endif
1264 const t_key key = ntohl(flp->daddr); 1199 const t_key key = ntohl(flp->daddr);
1265 struct tnode *n, *pn; 1200 struct tnode *n, *pn;
1201 struct leaf_info *li;
1266 t_key cindex; 1202 t_key cindex;
1267 int ret = 1;
1268
1269 rcu_read_lock();
1270 1203
1271 n = rcu_dereference(t->trie); 1204 n = rcu_dereference(t->trie);
1272 if (!n) 1205 if (!n)
1273 goto failed; 1206 return -EAGAIN;
1274 1207
1275#ifdef CONFIG_IP_FIB_TRIE_STATS 1208#ifdef CONFIG_IP_FIB_TRIE_STATS
1276 this_cpu_inc(stats->gets); 1209 this_cpu_inc(stats->gets);
@@ -1350,7 +1283,7 @@ backtrace:
1350 1283
1351 pn = node_parent_rcu(pn); 1284 pn = node_parent_rcu(pn);
1352 if (unlikely(!pn)) 1285 if (unlikely(!pn))
1353 goto failed; 1286 return -EAGAIN;
1354#ifdef CONFIG_IP_FIB_TRIE_STATS 1287#ifdef CONFIG_IP_FIB_TRIE_STATS
1355 this_cpu_inc(stats->backtrack); 1288 this_cpu_inc(stats->backtrack);
1356#endif 1289#endif
@@ -1368,12 +1301,62 @@ backtrace:
1368 1301
1369found: 1302found:
1370 /* Step 3: Process the leaf, if that fails fall back to backtracing */ 1303 /* Step 3: Process the leaf, if that fails fall back to backtracing */
1371 ret = check_leaf(tb, t, n, key, flp, res, fib_flags); 1304 hlist_for_each_entry_rcu(li, &n->list, hlist) {
1372 if (unlikely(ret > 0)) 1305 struct fib_alias *fa;
1373 goto backtrace; 1306
1374failed: 1307 if ((key ^ n->key) & li->mask_plen)
1375 rcu_read_unlock(); 1308 continue;
1376 return ret; 1309
1310 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
1311 struct fib_info *fi = fa->fa_info;
1312 int nhsel, err;
1313
1314 if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos)
1315 continue;
1316 if (fi->fib_dead)
1317 continue;
1318 if (fa->fa_info->fib_scope < flp->flowi4_scope)
1319 continue;
1320 fib_alias_accessed(fa);
1321 err = fib_props[fa->fa_type].error;
1322 if (unlikely(err < 0)) {
1323#ifdef CONFIG_IP_FIB_TRIE_STATS
1324 this_cpu_inc(stats->semantic_match_passed);
1325#endif
1326 return err;
1327 }
1328 if (fi->fib_flags & RTNH_F_DEAD)
1329 continue;
1330 for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) {
1331 const struct fib_nh *nh = &fi->fib_nh[nhsel];
1332
1333 if (nh->nh_flags & RTNH_F_DEAD)
1334 continue;
1335 if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif)
1336 continue;
1337
1338 if (!(fib_flags & FIB_LOOKUP_NOREF))
1339 atomic_inc(&fi->fib_clntref);
1340
1341 res->prefixlen = li->plen;
1342 res->nh_sel = nhsel;
1343 res->type = fa->fa_type;
1344 res->scope = fi->fib_scope;
1345 res->fi = fi;
1346 res->table = tb;
1347 res->fa_head = &li->falh;
1348#ifdef CONFIG_IP_FIB_TRIE_STATS
1349 this_cpu_inc(stats->semantic_match_passed);
1350#endif
1351 return err;
1352 }
1353 }
1354
1355#ifdef CONFIG_IP_FIB_TRIE_STATS
1356 this_cpu_inc(stats->semantic_match_miss);
1357#endif
1358 }
1359 goto backtrace;
1377} 1360}
1378EXPORT_SYMBOL_GPL(fib_table_lookup); 1361EXPORT_SYMBOL_GPL(fib_table_lookup);
1379 1362