diff options
| author | David S. Miller <davem@davemloft.net> | 2017-08-10 12:50:22 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-08-10 12:50:22 -0400 |
| commit | 2e2d5d767c9ddb2b10d74f2c20a257101c7070eb (patch) | |
| tree | 0059c050729eacf01ebc6bb3691b46343ddab376 /net/core/rtnetlink.c | |
| parent | 2d5716456404a1ba097d46770f82f23a2457a873 (diff) | |
| parent | 33b01b7b4f19f82198a298936de225eef942fc7c (diff) | |
Merge branch 'rtnetlink-fix-initial-rtnl-pushdown-fallout'
Florian Westphal says:
====================
rtnetlink: fix initial rtnl pushdown fallout
This series fixes various bugs and splats reported since the
allow-handler-to-run-with-no-rtnl series went in.
Last patch adds a script that can be used to add further
tests in case more bugs are reported.
In case you prefer reverting the original series instead of
fixing fallout I can resend this patch on its own.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/rtnetlink.c')
| -rw-r--r-- | net/core/rtnetlink.c | 35 |
1 files changed, 27 insertions, 8 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index dd4e50dfa248..9e9f1419be60 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
| @@ -172,7 +172,7 @@ int __rtnl_register(int protocol, int msgtype, | |||
| 172 | BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX); | 172 | BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX); |
| 173 | msgindex = rtm_msgindex(msgtype); | 173 | msgindex = rtm_msgindex(msgtype); |
| 174 | 174 | ||
| 175 | tab = rcu_dereference(rtnl_msg_handlers[protocol]); | 175 | tab = rcu_dereference_raw(rtnl_msg_handlers[protocol]); |
| 176 | if (tab == NULL) { | 176 | if (tab == NULL) { |
| 177 | tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL); | 177 | tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL); |
| 178 | if (tab == NULL) | 178 | if (tab == NULL) |
| @@ -262,7 +262,7 @@ void rtnl_unregister_all(int protocol) | |||
| 262 | 262 | ||
| 263 | synchronize_net(); | 263 | synchronize_net(); |
| 264 | 264 | ||
| 265 | while (refcount_read(&rtnl_msg_handlers_ref[protocol]) > 0) | 265 | while (refcount_read(&rtnl_msg_handlers_ref[protocol]) > 1) |
| 266 | schedule(); | 266 | schedule(); |
| 267 | kfree(handlers); | 267 | kfree(handlers); |
| 268 | } | 268 | } |
| @@ -402,16 +402,24 @@ static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev) | |||
| 402 | { | 402 | { |
| 403 | struct net_device *master_dev; | 403 | struct net_device *master_dev; |
| 404 | const struct rtnl_link_ops *ops; | 404 | const struct rtnl_link_ops *ops; |
| 405 | size_t size = 0; | ||
| 405 | 406 | ||
| 406 | master_dev = netdev_master_upper_dev_get((struct net_device *) dev); | 407 | rcu_read_lock(); |
| 408 | |||
| 409 | master_dev = netdev_master_upper_dev_get_rcu((struct net_device *)dev); | ||
| 407 | if (!master_dev) | 410 | if (!master_dev) |
| 408 | return 0; | 411 | goto out; |
| 412 | |||
| 409 | ops = master_dev->rtnl_link_ops; | 413 | ops = master_dev->rtnl_link_ops; |
| 410 | if (!ops || !ops->get_slave_size) | 414 | if (!ops || !ops->get_slave_size) |
| 411 | return 0; | 415 | goto out; |
| 412 | /* IFLA_INFO_SLAVE_DATA + nested data */ | 416 | /* IFLA_INFO_SLAVE_DATA + nested data */ |
| 413 | return nla_total_size(sizeof(struct nlattr)) + | 417 | size = nla_total_size(sizeof(struct nlattr)) + |
| 414 | ops->get_slave_size(master_dev, dev); | 418 | ops->get_slave_size(master_dev, dev); |
| 419 | |||
| 420 | out: | ||
| 421 | rcu_read_unlock(); | ||
| 422 | return size; | ||
| 415 | } | 423 | } |
| 416 | 424 | ||
| 417 | static size_t rtnl_link_get_size(const struct net_device *dev) | 425 | static size_t rtnl_link_get_size(const struct net_device *dev) |
| @@ -4167,7 +4175,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 4167 | if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN)) | 4175 | if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN)) |
| 4168 | return -EPERM; | 4176 | return -EPERM; |
| 4169 | 4177 | ||
| 4170 | if (family > ARRAY_SIZE(rtnl_msg_handlers)) | 4178 | if (family >= ARRAY_SIZE(rtnl_msg_handlers)) |
| 4171 | family = PF_UNSPEC; | 4179 | family = PF_UNSPEC; |
| 4172 | 4180 | ||
| 4173 | rcu_read_lock(); | 4181 | rcu_read_lock(); |
| @@ -4196,7 +4204,7 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 4196 | 4204 | ||
| 4197 | refcount_inc(&rtnl_msg_handlers_ref[family]); | 4205 | refcount_inc(&rtnl_msg_handlers_ref[family]); |
| 4198 | 4206 | ||
| 4199 | if (type == RTM_GETLINK) | 4207 | if (type == RTM_GETLINK - RTM_BASE) |
| 4200 | min_dump_alloc = rtnl_calcit(skb, nlh); | 4208 | min_dump_alloc = rtnl_calcit(skb, nlh); |
| 4201 | 4209 | ||
| 4202 | rcu_read_unlock(); | 4210 | rcu_read_unlock(); |
| @@ -4213,6 +4221,12 @@ static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
| 4213 | return err; | 4221 | return err; |
| 4214 | } | 4222 | } |
| 4215 | 4223 | ||
| 4224 | doit = READ_ONCE(handlers[type].doit); | ||
| 4225 | if (!doit) { | ||
| 4226 | family = PF_UNSPEC; | ||
| 4227 | handlers = rcu_dereference(rtnl_msg_handlers[family]); | ||
| 4228 | } | ||
| 4229 | |||
| 4216 | flags = READ_ONCE(handlers[type].flags); | 4230 | flags = READ_ONCE(handlers[type].flags); |
| 4217 | if (flags & RTNL_FLAG_DOIT_UNLOCKED) { | 4231 | if (flags & RTNL_FLAG_DOIT_UNLOCKED) { |
| 4218 | refcount_inc(&rtnl_msg_handlers_ref[family]); | 4232 | refcount_inc(&rtnl_msg_handlers_ref[family]); |
| @@ -4316,6 +4330,11 @@ static struct pernet_operations rtnetlink_net_ops = { | |||
| 4316 | 4330 | ||
| 4317 | void __init rtnetlink_init(void) | 4331 | void __init rtnetlink_init(void) |
| 4318 | { | 4332 | { |
| 4333 | int i; | ||
| 4334 | |||
| 4335 | for (i = 0; i < ARRAY_SIZE(rtnl_msg_handlers_ref); i++) | ||
| 4336 | refcount_set(&rtnl_msg_handlers_ref[i], 1); | ||
| 4337 | |||
| 4319 | if (register_pernet_subsys(&rtnetlink_net_ops)) | 4338 | if (register_pernet_subsys(&rtnetlink_net_ops)) |
| 4320 | panic("rtnetlink_init: cannot initialize rtnetlink\n"); | 4339 | panic("rtnetlink_init: cannot initialize rtnetlink\n"); |
| 4321 | 4340 | ||
