aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r--net/ipv4/fib_semantics.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index ba52f399a89..0f80dfc2f7f 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -148,6 +148,13 @@ static const struct
148 148
149/* Release a nexthop info record */ 149/* Release a nexthop info record */
150 150
151static void free_fib_info_rcu(struct rcu_head *head)
152{
153 struct fib_info *fi = container_of(head, struct fib_info, rcu);
154
155 kfree(fi);
156}
157
151void free_fib_info(struct fib_info *fi) 158void free_fib_info(struct fib_info *fi)
152{ 159{
153 if (fi->fib_dead == 0) { 160 if (fi->fib_dead == 0) {
@@ -161,7 +168,7 @@ void free_fib_info(struct fib_info *fi)
161 } endfor_nexthops(fi); 168 } endfor_nexthops(fi);
162 fib_info_cnt--; 169 fib_info_cnt--;
163 release_net(fi->fib_net); 170 release_net(fi->fib_net);
164 kfree(fi); 171 call_rcu(&fi->rcu, free_fib_info_rcu);
165} 172}
166 173
167void fib_release_info(struct fib_info *fi) 174void fib_release_info(struct fib_info *fi)
@@ -553,6 +560,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
553 nh->nh_scope = RT_SCOPE_LINK; 560 nh->nh_scope = RT_SCOPE_LINK;
554 return 0; 561 return 0;
555 } 562 }
563 rcu_read_lock();
556 { 564 {
557 struct flowi fl = { 565 struct flowi fl = {
558 .nl_u = { 566 .nl_u = {
@@ -568,8 +576,10 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
568 if (fl.fl4_scope < RT_SCOPE_LINK) 576 if (fl.fl4_scope < RT_SCOPE_LINK)
569 fl.fl4_scope = RT_SCOPE_LINK; 577 fl.fl4_scope = RT_SCOPE_LINK;
570 err = fib_lookup(net, &fl, &res); 578 err = fib_lookup(net, &fl, &res);
571 if (err) 579 if (err) {
580 rcu_read_unlock();
572 return err; 581 return err;
582 }
573 } 583 }
574 err = -EINVAL; 584 err = -EINVAL;
575 if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) 585 if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
@@ -585,7 +595,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
585 goto out; 595 goto out;
586 err = 0; 596 err = 0;
587out: 597out:
588 fib_res_put(&res); 598 rcu_read_unlock();
589 return err; 599 return err;
590 } else { 600 } else {
591 struct in_device *in_dev; 601 struct in_device *in_dev;
@@ -879,7 +889,7 @@ failure:
879 889
880/* Note! fib_semantic_match intentionally uses RCU list functions. */ 890/* Note! fib_semantic_match intentionally uses RCU list functions. */
881int fib_semantic_match(struct list_head *head, const struct flowi *flp, 891int fib_semantic_match(struct list_head *head, const struct flowi *flp,
882 struct fib_result *res, int prefixlen) 892 struct fib_result *res, int prefixlen, int fib_flags)
883{ 893{
884 struct fib_alias *fa; 894 struct fib_alias *fa;
885 int nh_sel = 0; 895 int nh_sel = 0;
@@ -943,7 +953,8 @@ out_fill_res:
943 res->type = fa->fa_type; 953 res->type = fa->fa_type;
944 res->scope = fa->fa_scope; 954 res->scope = fa->fa_scope;
945 res->fi = fa->fa_info; 955 res->fi = fa->fa_info;
946 atomic_inc(&res->fi->fib_clntref); 956 if (!(fib_flags & FIB_LOOKUP_NOREF))
957 atomic_inc(&res->fi->fib_clntref);
947 return 0; 958 return 0;
948} 959}
949 960