diff options
-rw-r--r-- | net/core/rtnetlink.c | 62 | ||||
-rw-r--r-- | net/ipv4/devinet.c | 4 |
2 files changed, 48 insertions, 18 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index a49cad25e577..20b550d07fe3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -453,7 +453,7 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family) | |||
453 | { | 453 | { |
454 | const struct rtnl_af_ops *ops; | 454 | const struct rtnl_af_ops *ops; |
455 | 455 | ||
456 | list_for_each_entry(ops, &rtnl_af_ops, list) { | 456 | list_for_each_entry_rcu(ops, &rtnl_af_ops, list) { |
457 | if (ops->family == family) | 457 | if (ops->family == family) |
458 | return ops; | 458 | return ops; |
459 | } | 459 | } |
@@ -470,7 +470,7 @@ static const struct rtnl_af_ops *rtnl_af_lookup(const int family) | |||
470 | void rtnl_af_register(struct rtnl_af_ops *ops) | 470 | void rtnl_af_register(struct rtnl_af_ops *ops) |
471 | { | 471 | { |
472 | rtnl_lock(); | 472 | rtnl_lock(); |
473 | list_add_tail(&ops->list, &rtnl_af_ops); | 473 | list_add_tail_rcu(&ops->list, &rtnl_af_ops); |
474 | rtnl_unlock(); | 474 | rtnl_unlock(); |
475 | } | 475 | } |
476 | EXPORT_SYMBOL_GPL(rtnl_af_register); | 476 | EXPORT_SYMBOL_GPL(rtnl_af_register); |
@@ -482,8 +482,10 @@ EXPORT_SYMBOL_GPL(rtnl_af_register); | |||
482 | void rtnl_af_unregister(struct rtnl_af_ops *ops) | 482 | void rtnl_af_unregister(struct rtnl_af_ops *ops) |
483 | { | 483 | { |
484 | rtnl_lock(); | 484 | rtnl_lock(); |
485 | list_del(&ops->list); | 485 | list_del_rcu(&ops->list); |
486 | rtnl_unlock(); | 486 | rtnl_unlock(); |
487 | |||
488 | synchronize_rcu(); | ||
487 | } | 489 | } |
488 | EXPORT_SYMBOL_GPL(rtnl_af_unregister); | 490 | EXPORT_SYMBOL_GPL(rtnl_af_unregister); |
489 | 491 | ||
@@ -496,13 +498,15 @@ static size_t rtnl_link_get_af_size(const struct net_device *dev, | |||
496 | /* IFLA_AF_SPEC */ | 498 | /* IFLA_AF_SPEC */ |
497 | size = nla_total_size(sizeof(struct nlattr)); | 499 | size = nla_total_size(sizeof(struct nlattr)); |
498 | 500 | ||
499 | list_for_each_entry(af_ops, &rtnl_af_ops, list) { | 501 | rcu_read_lock(); |
502 | list_for_each_entry_rcu(af_ops, &rtnl_af_ops, list) { | ||
500 | if (af_ops->get_link_af_size) { | 503 | if (af_ops->get_link_af_size) { |
501 | /* AF_* + nested data */ | 504 | /* AF_* + nested data */ |
502 | size += nla_total_size(sizeof(struct nlattr)) + | 505 | size += nla_total_size(sizeof(struct nlattr)) + |
503 | af_ops->get_link_af_size(dev, ext_filter_mask); | 506 | af_ops->get_link_af_size(dev, ext_filter_mask); |
504 | } | 507 | } |
505 | } | 508 | } |
509 | rcu_read_unlock(); | ||
506 | 510 | ||
507 | return size; | 511 | return size; |
508 | } | 512 | } |
@@ -1393,7 +1397,7 @@ static int rtnl_fill_link_af(struct sk_buff *skb, | |||
1393 | if (!af_spec) | 1397 | if (!af_spec) |
1394 | return -EMSGSIZE; | 1398 | return -EMSGSIZE; |
1395 | 1399 | ||
1396 | list_for_each_entry(af_ops, &rtnl_af_ops, list) { | 1400 | list_for_each_entry_rcu(af_ops, &rtnl_af_ops, list) { |
1397 | struct nlattr *af; | 1401 | struct nlattr *af; |
1398 | int err; | 1402 | int err; |
1399 | 1403 | ||
@@ -1516,12 +1520,16 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
1516 | nla_put_s32(skb, IFLA_NEW_NETNSID, *new_nsid) < 0) | 1520 | nla_put_s32(skb, IFLA_NEW_NETNSID, *new_nsid) < 0) |
1517 | goto nla_put_failure; | 1521 | goto nla_put_failure; |
1518 | 1522 | ||
1523 | rcu_read_lock(); | ||
1519 | if (rtnl_fill_link_af(skb, dev, ext_filter_mask)) | 1524 | if (rtnl_fill_link_af(skb, dev, ext_filter_mask)) |
1520 | goto nla_put_failure; | 1525 | goto nla_put_failure_rcu; |
1526 | rcu_read_unlock(); | ||
1521 | 1527 | ||
1522 | nlmsg_end(skb, nlh); | 1528 | nlmsg_end(skb, nlh); |
1523 | return 0; | 1529 | return 0; |
1524 | 1530 | ||
1531 | nla_put_failure_rcu: | ||
1532 | rcu_read_unlock(); | ||
1525 | nla_put_failure: | 1533 | nla_put_failure: |
1526 | nlmsg_cancel(skb, nlh); | 1534 | nlmsg_cancel(skb, nlh); |
1527 | return -EMSGSIZE; | 1535 | return -EMSGSIZE; |
@@ -1783,17 +1791,27 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) | |||
1783 | nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { | 1791 | nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { |
1784 | const struct rtnl_af_ops *af_ops; | 1792 | const struct rtnl_af_ops *af_ops; |
1785 | 1793 | ||
1786 | if (!(af_ops = rtnl_af_lookup(nla_type(af)))) | 1794 | rcu_read_lock(); |
1795 | af_ops = rtnl_af_lookup(nla_type(af)); | ||
1796 | if (!af_ops) { | ||
1797 | rcu_read_unlock(); | ||
1787 | return -EAFNOSUPPORT; | 1798 | return -EAFNOSUPPORT; |
1799 | } | ||
1788 | 1800 | ||
1789 | if (!af_ops->set_link_af) | 1801 | if (!af_ops->set_link_af) { |
1802 | rcu_read_unlock(); | ||
1790 | return -EOPNOTSUPP; | 1803 | return -EOPNOTSUPP; |
1804 | } | ||
1791 | 1805 | ||
1792 | if (af_ops->validate_link_af) { | 1806 | if (af_ops->validate_link_af) { |
1793 | err = af_ops->validate_link_af(dev, af); | 1807 | err = af_ops->validate_link_af(dev, af); |
1794 | if (err < 0) | 1808 | if (err < 0) { |
1809 | rcu_read_unlock(); | ||
1795 | return err; | 1810 | return err; |
1811 | } | ||
1796 | } | 1812 | } |
1813 | |||
1814 | rcu_read_unlock(); | ||
1797 | } | 1815 | } |
1798 | } | 1816 | } |
1799 | 1817 | ||
@@ -2251,13 +2269,18 @@ static int do_setlink(const struct sk_buff *skb, | |||
2251 | nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { | 2269 | nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { |
2252 | const struct rtnl_af_ops *af_ops; | 2270 | const struct rtnl_af_ops *af_ops; |
2253 | 2271 | ||
2272 | rcu_read_lock(); | ||
2273 | |||
2254 | if (!(af_ops = rtnl_af_lookup(nla_type(af)))) | 2274 | if (!(af_ops = rtnl_af_lookup(nla_type(af)))) |
2255 | BUG(); | 2275 | BUG(); |
2256 | 2276 | ||
2257 | err = af_ops->set_link_af(dev, af); | 2277 | err = af_ops->set_link_af(dev, af); |
2258 | if (err < 0) | 2278 | if (err < 0) { |
2279 | rcu_read_unlock(); | ||
2259 | goto errout; | 2280 | goto errout; |
2281 | } | ||
2260 | 2282 | ||
2283 | rcu_read_unlock(); | ||
2261 | status |= DO_SETLINK_NOTIFY; | 2284 | status |= DO_SETLINK_NOTIFY; |
2262 | } | 2285 | } |
2263 | } | 2286 | } |
@@ -4004,25 +4027,30 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev, | |||
4004 | if (!attr) | 4027 | if (!attr) |
4005 | goto nla_put_failure; | 4028 | goto nla_put_failure; |
4006 | 4029 | ||
4007 | list_for_each_entry(af_ops, &rtnl_af_ops, list) { | 4030 | rcu_read_lock(); |
4031 | list_for_each_entry_rcu(af_ops, &rtnl_af_ops, list) { | ||
4008 | if (af_ops->fill_stats_af) { | 4032 | if (af_ops->fill_stats_af) { |
4009 | struct nlattr *af; | 4033 | struct nlattr *af; |
4010 | int err; | 4034 | int err; |
4011 | 4035 | ||
4012 | af = nla_nest_start(skb, af_ops->family); | 4036 | af = nla_nest_start(skb, af_ops->family); |
4013 | if (!af) | 4037 | if (!af) { |
4038 | rcu_read_unlock(); | ||
4014 | goto nla_put_failure; | 4039 | goto nla_put_failure; |
4015 | 4040 | } | |
4016 | err = af_ops->fill_stats_af(skb, dev); | 4041 | err = af_ops->fill_stats_af(skb, dev); |
4017 | 4042 | ||
4018 | if (err == -ENODATA) | 4043 | if (err == -ENODATA) { |
4019 | nla_nest_cancel(skb, af); | 4044 | nla_nest_cancel(skb, af); |
4020 | else if (err < 0) | 4045 | } else if (err < 0) { |
4046 | rcu_read_unlock(); | ||
4021 | goto nla_put_failure; | 4047 | goto nla_put_failure; |
4048 | } | ||
4022 | 4049 | ||
4023 | nla_nest_end(skb, af); | 4050 | nla_nest_end(skb, af); |
4024 | } | 4051 | } |
4025 | } | 4052 | } |
4053 | rcu_read_unlock(); | ||
4026 | 4054 | ||
4027 | nla_nest_end(skb, attr); | 4055 | nla_nest_end(skb, attr); |
4028 | 4056 | ||
@@ -4091,7 +4119,8 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev, | |||
4091 | /* for IFLA_STATS_AF_SPEC */ | 4119 | /* for IFLA_STATS_AF_SPEC */ |
4092 | size += nla_total_size(0); | 4120 | size += nla_total_size(0); |
4093 | 4121 | ||
4094 | list_for_each_entry(af_ops, &rtnl_af_ops, list) { | 4122 | rcu_read_lock(); |
4123 | list_for_each_entry_rcu(af_ops, &rtnl_af_ops, list) { | ||
4095 | if (af_ops->get_stats_af_size) { | 4124 | if (af_ops->get_stats_af_size) { |
4096 | size += nla_total_size( | 4125 | size += nla_total_size( |
4097 | af_ops->get_stats_af_size(dev)); | 4126 | af_ops->get_stats_af_size(dev)); |
@@ -4100,6 +4129,7 @@ static size_t if_nlmsg_stats_size(const struct net_device *dev, | |||
4100 | size += nla_total_size(0); | 4129 | size += nla_total_size(0); |
4101 | } | 4130 | } |
4102 | } | 4131 | } |
4132 | rcu_read_unlock(); | ||
4103 | } | 4133 | } |
4104 | 4134 | ||
4105 | return size; | 4135 | return size; |
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 7ce22a2c07ce..6d9b072d903b 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -1757,7 +1757,7 @@ static int inet_validate_link_af(const struct net_device *dev, | |||
1757 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; | 1757 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; |
1758 | int err, rem; | 1758 | int err, rem; |
1759 | 1759 | ||
1760 | if (dev && !__in_dev_get_rtnl(dev)) | 1760 | if (dev && !__in_dev_get_rcu(dev)) |
1761 | return -EAFNOSUPPORT; | 1761 | return -EAFNOSUPPORT; |
1762 | 1762 | ||
1763 | err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL); | 1763 | err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL); |
@@ -1781,7 +1781,7 @@ static int inet_validate_link_af(const struct net_device *dev, | |||
1781 | 1781 | ||
1782 | static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla) | 1782 | static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla) |
1783 | { | 1783 | { |
1784 | struct in_device *in_dev = __in_dev_get_rtnl(dev); | 1784 | struct in_device *in_dev = __in_dev_get_rcu(dev); |
1785 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; | 1785 | struct nlattr *a, *tb[IFLA_INET_MAX+1]; |
1786 | int rem; | 1786 | int rem; |
1787 | 1787 | ||