diff options
Diffstat (limited to 'net/ipv4/fib_semantics.c')
-rw-r--r-- | net/ipv4/fib_semantics.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index da449ddb8cc1..ad9ad4aab5da 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -203,6 +203,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp) | |||
203 | static void free_fib_info_rcu(struct rcu_head *head) | 203 | static void free_fib_info_rcu(struct rcu_head *head) |
204 | { | 204 | { |
205 | struct fib_info *fi = container_of(head, struct fib_info, rcu); | 205 | struct fib_info *fi = container_of(head, struct fib_info, rcu); |
206 | struct dst_metrics *m; | ||
206 | 207 | ||
207 | change_nexthops(fi) { | 208 | change_nexthops(fi) { |
208 | if (nexthop_nh->nh_dev) | 209 | if (nexthop_nh->nh_dev) |
@@ -213,8 +214,9 @@ static void free_fib_info_rcu(struct rcu_head *head) | |||
213 | rt_fibinfo_free(&nexthop_nh->nh_rth_input); | 214 | rt_fibinfo_free(&nexthop_nh->nh_rth_input); |
214 | } endfor_nexthops(fi); | 215 | } endfor_nexthops(fi); |
215 | 216 | ||
216 | if (fi->fib_metrics != (u32 *) dst_default_metrics) | 217 | m = fi->fib_metrics; |
217 | kfree(fi->fib_metrics); | 218 | if (m != &dst_default_metrics && atomic_dec_and_test(&m->refcnt)) |
219 | kfree(m); | ||
218 | kfree(fi); | 220 | kfree(fi); |
219 | } | 221 | } |
220 | 222 | ||
@@ -971,11 +973,11 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) | |||
971 | val = 255; | 973 | val = 255; |
972 | if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) | 974 | if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) |
973 | return -EINVAL; | 975 | return -EINVAL; |
974 | fi->fib_metrics[type - 1] = val; | 976 | fi->fib_metrics->metrics[type - 1] = val; |
975 | } | 977 | } |
976 | 978 | ||
977 | if (ecn_ca) | 979 | if (ecn_ca) |
978 | fi->fib_metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA; | 980 | fi->fib_metrics->metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA; |
979 | 981 | ||
980 | return 0; | 982 | return 0; |
981 | } | 983 | } |
@@ -1033,11 +1035,12 @@ struct fib_info *fib_create_info(struct fib_config *cfg) | |||
1033 | goto failure; | 1035 | goto failure; |
1034 | fib_info_cnt++; | 1036 | fib_info_cnt++; |
1035 | if (cfg->fc_mx) { | 1037 | if (cfg->fc_mx) { |
1036 | fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL); | 1038 | fi->fib_metrics = kzalloc(sizeof(*fi->fib_metrics), GFP_KERNEL); |
1037 | if (!fi->fib_metrics) | 1039 | if (!fi->fib_metrics) |
1038 | goto failure; | 1040 | goto failure; |
1041 | atomic_set(&fi->fib_metrics->refcnt, 1); | ||
1039 | } else | 1042 | } else |
1040 | fi->fib_metrics = (u32 *) dst_default_metrics; | 1043 | fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics; |
1041 | 1044 | ||
1042 | fi->fib_net = net; | 1045 | fi->fib_net = net; |
1043 | fi->fib_protocol = cfg->fc_protocol; | 1046 | fi->fib_protocol = cfg->fc_protocol; |
@@ -1238,7 +1241,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, | |||
1238 | if (fi->fib_priority && | 1241 | if (fi->fib_priority && |
1239 | nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority)) | 1242 | nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority)) |
1240 | goto nla_put_failure; | 1243 | goto nla_put_failure; |
1241 | if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0) | 1244 | if (rtnetlink_put_metrics(skb, fi->fib_metrics->metrics) < 0) |
1242 | goto nla_put_failure; | 1245 | goto nla_put_failure; |
1243 | 1246 | ||
1244 | if (fi->fib_prefsrc && | 1247 | if (fi->fib_prefsrc && |