aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/rtnetlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/rtnetlink.c')
-rw-r--r--net/core/rtnetlink.c35
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
420out:
421 rcu_read_unlock();
422 return size;
415} 423}
416 424
417static size_t rtnl_link_get_size(const struct net_device *dev) 425static 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
4317void __init rtnetlink_init(void) 4331void __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