diff options
author | Alexander Duyck <alexander.h.duyck@redhat.com> | 2014-12-31 10:56:24 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-12-31 18:25:54 -0500 |
commit | 345e9b54268ae065520a7252c182d22ef4591718 (patch) | |
tree | ad4e6c4138028f1ad00d6a2aeeb7fff90f094801 /net/ipv4/fib_trie.c | |
parent | 98293e8d2f51976d5f790400859a517c0f7cb598 (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/ipv4/fib_trie.c')
-rw-r--r-- | net/ipv4/fib_trie.c | 137 |
1 files changed, 60 insertions, 77 deletions
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: return err; } -/* should be called with rcu_read_lock */ -static int check_leaf(struct fib_table *tb, struct trie *t, struct tnode *l, - t_key key, const struct flowi4 *flp, - struct fib_result *res, int fib_flags) -{ - struct leaf_info *li; - struct hlist_head *hhead = &l->list; - - hlist_for_each_entry_rcu(li, hhead, hlist) { - struct fib_alias *fa; - - if (l->key != (key & li->mask_plen)) - continue; - - list_for_each_entry_rcu(fa, &li->falh, fa_list) { - struct fib_info *fi = fa->fa_info; - int nhsel, err; - - if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) - continue; - if (fi->fib_dead) - continue; - if (fa->fa_info->fib_scope < flp->flowi4_scope) - continue; - fib_alias_accessed(fa); - err = fib_props[fa->fa_type].error; - if (unlikely(err < 0)) { -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(t->stats->semantic_match_passed); -#endif - return err; - } - if (fi->fib_flags & RTNH_F_DEAD) - continue; - for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { - const struct fib_nh *nh = &fi->fib_nh[nhsel]; - - if (nh->nh_flags & RTNH_F_DEAD) - continue; - if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) - continue; - -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(t->stats->semantic_match_passed); -#endif - res->prefixlen = li->plen; - res->nh_sel = nhsel; - res->type = fa->fa_type; - res->scope = fi->fib_scope; - res->fi = fi; - res->table = tb; - res->fa_head = &li->falh; - if (!(fib_flags & FIB_LOOKUP_NOREF)) - atomic_inc(&fi->fib_clntref); - return 0; - } - } - -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(t->stats->semantic_match_miss); -#endif - } - - return 1; -} - static inline t_key prefix_mismatch(t_key key, struct tnode *n) { t_key prefix = n->key; @@ -1254,6 +1188,7 @@ static inline t_key prefix_mismatch(t_key key, struct tnode *n) return (key ^ prefix) & (prefix | -prefix); } +/* should be called with rcu_read_lock */ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, struct fib_result *res, int fib_flags) { @@ -1263,14 +1198,12 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, #endif const t_key key = ntohl(flp->daddr); struct tnode *n, *pn; + struct leaf_info *li; t_key cindex; - int ret = 1; - - rcu_read_lock(); n = rcu_dereference(t->trie); if (!n) - goto failed; + return -EAGAIN; #ifdef CONFIG_IP_FIB_TRIE_STATS this_cpu_inc(stats->gets); @@ -1350,7 +1283,7 @@ backtrace: pn = node_parent_rcu(pn); if (unlikely(!pn)) - goto failed; + return -EAGAIN; #ifdef CONFIG_IP_FIB_TRIE_STATS this_cpu_inc(stats->backtrack); #endif @@ -1368,12 +1301,62 @@ backtrace: found: /* Step 3: Process the leaf, if that fails fall back to backtracing */ - ret = check_leaf(tb, t, n, key, flp, res, fib_flags); - if (unlikely(ret > 0)) - goto backtrace; -failed: - rcu_read_unlock(); - return ret; + hlist_for_each_entry_rcu(li, &n->list, hlist) { + struct fib_alias *fa; + + if ((key ^ n->key) & li->mask_plen) + continue; + + list_for_each_entry_rcu(fa, &li->falh, fa_list) { + struct fib_info *fi = fa->fa_info; + int nhsel, err; + + if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) + continue; + if (fi->fib_dead) + continue; + if (fa->fa_info->fib_scope < flp->flowi4_scope) + continue; + fib_alias_accessed(fa); + err = fib_props[fa->fa_type].error; + if (unlikely(err < 0)) { +#ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(stats->semantic_match_passed); +#endif + return err; + } + if (fi->fib_flags & RTNH_F_DEAD) + continue; + for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { + const struct fib_nh *nh = &fi->fib_nh[nhsel]; + + if (nh->nh_flags & RTNH_F_DEAD) + continue; + if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif) + continue; + + if (!(fib_flags & FIB_LOOKUP_NOREF)) + atomic_inc(&fi->fib_clntref); + + res->prefixlen = li->plen; + res->nh_sel = nhsel; + res->type = fa->fa_type; + res->scope = fi->fib_scope; + res->fi = fi; + res->table = tb; + res->fa_head = &li->falh; +#ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(stats->semantic_match_passed); +#endif + return err; + } + } + +#ifdef CONFIG_IP_FIB_TRIE_STATS + this_cpu_inc(stats->semantic_match_miss); +#endif + } + goto backtrace; } EXPORT_SYMBOL_GPL(fib_table_lookup); |