aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-12-04 20:23:53 -0500
committerDavid S. Miller <davem@davemloft.net>2010-12-08 13:07:24 -0500
commit941666c2e3e0f9f6a1cb5808d02352d445bd702c (patch)
tree389a773580ef22908391cc71f98982b03de62804
parenta2d4b65d477aad1fe8c7218781a031fa9cf5abfc (diff)
net: RCU conversion of dev_getbyhwaddr() and arp_ioctl()
Le dimanche 05 décembre 2010 à 09:19 +0100, Eric Dumazet a écrit : > Hmm.. > > If somebody can explain why RTNL is held in arp_ioctl() (and therefore > in arp_req_delete()), we might first remove RTNL use in arp_ioctl() so > that your patch can be applied. > > Right now it is not good, because RTNL wont be necessarly held when you > are going to call arp_invalidate() ? While doing this analysis, I found a refcount bug in llc, I'll send a patch for net-2.6 Meanwhile, here is the patch for net-next-2.6 Your patch then can be applied after mine. Thanks [PATCH] net: RCU conversion of dev_getbyhwaddr() and arp_ioctl() dev_getbyhwaddr() was called under RTNL. Rename it to dev_getbyhwaddr_rcu() and change all its caller to now use RCU locking instead of RTNL. Change arp_ioctl() to use RCU instead of RTNL locking. Note: this fix a dev refcount bug in llc Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--net/core/dev.c17
-rw-r--r--net/ieee802154/af_ieee802154.c6
-rw-r--r--net/ipv4/arp.c17
-rw-r--r--net/llc/af_llc.c11
5 files changed, 27 insertions, 27 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a9ac5dc26e3c..d31bc3c94717 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1360,7 +1360,8 @@ static inline struct net_device *first_net_device(struct net *net)
1360 1360
1361extern int netdev_boot_setup_check(struct net_device *dev); 1361extern int netdev_boot_setup_check(struct net_device *dev);
1362extern unsigned long netdev_boot_base(const char *prefix, int unit); 1362extern unsigned long netdev_boot_base(const char *prefix, int unit);
1363extern struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *hwaddr); 1363extern struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type,
1364 const char *hwaddr);
1364extern struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type); 1365extern struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type);
1365extern struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type); 1366extern struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type);
1366extern void dev_add_pack(struct packet_type *pt); 1367extern void dev_add_pack(struct packet_type *pt);
diff --git a/net/core/dev.c b/net/core/dev.c
index ee605c0867e7..822b15b8d11c 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -743,34 +743,31 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
743EXPORT_SYMBOL(dev_get_by_index); 743EXPORT_SYMBOL(dev_get_by_index);
744 744
745/** 745/**
746 * dev_getbyhwaddr - find a device by its hardware address 746 * dev_getbyhwaddr_rcu - find a device by its hardware address
747 * @net: the applicable net namespace 747 * @net: the applicable net namespace
748 * @type: media type of device 748 * @type: media type of device
749 * @ha: hardware address 749 * @ha: hardware address
750 * 750 *
751 * Search for an interface by MAC address. Returns NULL if the device 751 * Search for an interface by MAC address. Returns NULL if the device
752 * is not found or a pointer to the device. The caller must hold the 752 * is not found or a pointer to the device. The caller must hold RCU
753 * rtnl semaphore. The returned device has not had its ref count increased 753 * The returned device has not had its ref count increased
754 * and the caller must therefore be careful about locking 754 * and the caller must therefore be careful about locking
755 * 755 *
756 * BUGS:
757 * If the API was consistent this would be __dev_get_by_hwaddr
758 */ 756 */
759 757
760struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *ha) 758struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type,
759 const char *ha)
761{ 760{
762 struct net_device *dev; 761 struct net_device *dev;
763 762
764 ASSERT_RTNL(); 763 for_each_netdev_rcu(net, dev)
765
766 for_each_netdev(net, dev)
767 if (dev->type == type && 764 if (dev->type == type &&
768 !memcmp(dev->dev_addr, ha, dev->addr_len)) 765 !memcmp(dev->dev_addr, ha, dev->addr_len))
769 return dev; 766 return dev;
770 767
771 return NULL; 768 return NULL;
772} 769}
773EXPORT_SYMBOL(dev_getbyhwaddr); 770EXPORT_SYMBOL(dev_getbyhwaddr_rcu);
774 771
775struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) 772struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type)
776{ 773{
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
index 93c91b633a56..6df6ecf49708 100644
--- a/net/ieee802154/af_ieee802154.c
+++ b/net/ieee802154/af_ieee802154.c
@@ -52,11 +52,11 @@ struct net_device *ieee802154_get_dev(struct net *net,
52 52
53 switch (addr->addr_type) { 53 switch (addr->addr_type) {
54 case IEEE802154_ADDR_LONG: 54 case IEEE802154_ADDR_LONG:
55 rtnl_lock(); 55 rcu_read_lock();
56 dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr); 56 dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr);
57 if (dev) 57 if (dev)
58 dev_hold(dev); 58 dev_hold(dev);
59 rtnl_unlock(); 59 rcu_read_unlock();
60 break; 60 break;
61 case IEEE802154_ADDR_SHORT: 61 case IEEE802154_ADDR_SHORT:
62 if (addr->pan_id == 0xffff || 62 if (addr->pan_id == 0xffff ||
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 10af759f2630..a2fc7b961dbc 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1017,13 +1017,14 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on)
1017 IPV4_DEVCONF_ALL(net, PROXY_ARP) = on; 1017 IPV4_DEVCONF_ALL(net, PROXY_ARP) = on;
1018 return 0; 1018 return 0;
1019 } 1019 }
1020 if (__in_dev_get_rtnl(dev)) { 1020 if (__in_dev_get_rcu(dev)) {
1021 IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on); 1021 IN_DEV_CONF_SET(__in_dev_get_rcu(dev), PROXY_ARP, on);
1022 return 0; 1022 return 0;
1023 } 1023 }
1024 return -ENXIO; 1024 return -ENXIO;
1025} 1025}
1026 1026
1027/* must be called with rcu_read_lock() */
1027static int arp_req_set_public(struct net *net, struct arpreq *r, 1028static int arp_req_set_public(struct net *net, struct arpreq *r,
1028 struct net_device *dev) 1029 struct net_device *dev)
1029{ 1030{
@@ -1033,7 +1034,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
1033 if (mask && mask != htonl(0xFFFFFFFF)) 1034 if (mask && mask != htonl(0xFFFFFFFF))
1034 return -EINVAL; 1035 return -EINVAL;
1035 if (!dev && (r->arp_flags & ATF_COM)) { 1036 if (!dev && (r->arp_flags & ATF_COM)) {
1036 dev = dev_getbyhwaddr(net, r->arp_ha.sa_family, 1037 dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family,
1037 r->arp_ha.sa_data); 1038 r->arp_ha.sa_data);
1038 if (!dev) 1039 if (!dev)
1039 return -ENODEV; 1040 return -ENODEV;
@@ -1225,10 +1226,10 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
1225 if (!(r.arp_flags & ATF_NETMASK)) 1226 if (!(r.arp_flags & ATF_NETMASK))
1226 ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr = 1227 ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
1227 htonl(0xFFFFFFFFUL); 1228 htonl(0xFFFFFFFFUL);
1228 rtnl_lock(); 1229 rcu_read_lock();
1229 if (r.arp_dev[0]) { 1230 if (r.arp_dev[0]) {
1230 err = -ENODEV; 1231 err = -ENODEV;
1231 dev = __dev_get_by_name(net, r.arp_dev); 1232 dev = dev_get_by_name_rcu(net, r.arp_dev);
1232 if (dev == NULL) 1233 if (dev == NULL)
1233 goto out; 1234 goto out;
1234 1235
@@ -1252,12 +1253,12 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
1252 break; 1253 break;
1253 case SIOCGARP: 1254 case SIOCGARP:
1254 err = arp_req_get(&r, dev); 1255 err = arp_req_get(&r, dev);
1255 if (!err && copy_to_user(arg, &r, sizeof(r)))
1256 err = -EFAULT;
1257 break; 1256 break;
1258 } 1257 }
1259out: 1258out:
1260 rtnl_unlock(); 1259 rcu_read_unlock();
1260 if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
1261 err = -EFAULT;
1261 return err; 1262 return err;
1262} 1263}
1263 1264
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 582612998211..dfd3a648a551 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -316,9 +316,9 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
316 if (unlikely(addr->sllc_family != AF_LLC)) 316 if (unlikely(addr->sllc_family != AF_LLC))
317 goto out; 317 goto out;
318 rc = -ENODEV; 318 rc = -ENODEV;
319 rtnl_lock(); 319 rcu_read_lock();
320 if (sk->sk_bound_dev_if) { 320 if (sk->sk_bound_dev_if) {
321 llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); 321 llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if);
322 if (llc->dev) { 322 if (llc->dev) {
323 if (!addr->sllc_arphrd) 323 if (!addr->sllc_arphrd)
324 addr->sllc_arphrd = llc->dev->type; 324 addr->sllc_arphrd = llc->dev->type;
@@ -329,14 +329,15 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
329 !llc_mac_match(addr->sllc_mac, 329 !llc_mac_match(addr->sllc_mac,
330 llc->dev->dev_addr)) { 330 llc->dev->dev_addr)) {
331 rc = -EINVAL; 331 rc = -EINVAL;
332 dev_put(llc->dev);
333 llc->dev = NULL; 332 llc->dev = NULL;
334 } 333 }
335 } 334 }
336 } else 335 } else
337 llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd, 336 llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd,
338 addr->sllc_mac); 337 addr->sllc_mac);
339 rtnl_unlock(); 338 if (llc->dev)
339 dev_hold(llc->dev);
340 rcu_read_unlock();
340 if (!llc->dev) 341 if (!llc->dev)
341 goto out; 342 goto out;
342 if (!addr->sllc_sap) { 343 if (!addr->sllc_sap) {