Skip to content

Commit 941666c

Browse files
Eric Dumazetdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a2d4b65 commit 941666c

File tree

5 files changed

+27
-27
lines changed

5 files changed

+27
-27
lines changed

include/linux/netdevice.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1360,7 +1360,8 @@ static inline struct net_device *first_net_device(struct net *net)
13601360

13611361
extern int netdev_boot_setup_check(struct net_device *dev);
13621362
extern unsigned long netdev_boot_base(const char *prefix, int unit);
1363-
extern struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *hwaddr);
1363+
extern struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type,
1364+
const char *hwaddr);
13641365
extern struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type);
13651366
extern struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type);
13661367
extern void dev_add_pack(struct packet_type *pt);

net/core/dev.c

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -743,34 +743,31 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
743743
EXPORT_SYMBOL(dev_get_by_index);
744744

745745
/**
746-
* dev_getbyhwaddr - find a device by its hardware address
746+
* dev_getbyhwaddr_rcu - find a device by its hardware address
747747
* @net: the applicable net namespace
748748
* @type: media type of device
749749
* @ha: hardware address
750750
*
751751
* 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
753-
* rtnl semaphore. The returned device has not had its ref count increased
752+
* is not found or a pointer to the device. The caller must hold RCU
753+
* The returned device has not had its ref count increased
754754
* and the caller must therefore be careful about locking
755755
*
756-
* BUGS:
757-
* If the API was consistent this would be __dev_get_by_hwaddr
758756
*/
759757

760-
struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *ha)
758+
struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type,
759+
const char *ha)
761760
{
762761
struct net_device *dev;
763762

764-
ASSERT_RTNL();
765-
766-
for_each_netdev(net, dev)
763+
for_each_netdev_rcu(net, dev)
767764
if (dev->type == type &&
768765
!memcmp(dev->dev_addr, ha, dev->addr_len))
769766
return dev;
770767

771768
return NULL;
772769
}
773-
EXPORT_SYMBOL(dev_getbyhwaddr);
770+
EXPORT_SYMBOL(dev_getbyhwaddr_rcu);
774771

775772
struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type)
776773
{

net/ieee802154/af_ieee802154.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ struct net_device *ieee802154_get_dev(struct net *net,
5252

5353
switch (addr->addr_type) {
5454
case IEEE802154_ADDR_LONG:
55-
rtnl_lock();
56-
dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
55+
rcu_read_lock();
56+
dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr);
5757
if (dev)
5858
dev_hold(dev);
59-
rtnl_unlock();
59+
rcu_read_unlock();
6060
break;
6161
case IEEE802154_ADDR_SHORT:
6262
if (addr->pan_id == 0xffff ||

net/ipv4/arp.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,13 +1017,14 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on)
10171017
IPV4_DEVCONF_ALL(net, PROXY_ARP) = on;
10181018
return 0;
10191019
}
1020-
if (__in_dev_get_rtnl(dev)) {
1021-
IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on);
1020+
if (__in_dev_get_rcu(dev)) {
1021+
IN_DEV_CONF_SET(__in_dev_get_rcu(dev), PROXY_ARP, on);
10221022
return 0;
10231023
}
10241024
return -ENXIO;
10251025
}
10261026

1027+
/* must be called with rcu_read_lock() */
10271028
static int arp_req_set_public(struct net *net, struct arpreq *r,
10281029
struct net_device *dev)
10291030
{
@@ -1033,7 +1034,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
10331034
if (mask && mask != htonl(0xFFFFFFFF))
10341035
return -EINVAL;
10351036
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,
10371038
r->arp_ha.sa_data);
10381039
if (!dev)
10391040
return -ENODEV;
@@ -1225,10 +1226,10 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
12251226
if (!(r.arp_flags & ATF_NETMASK))
12261227
((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
12271228
htonl(0xFFFFFFFFUL);
1228-
rtnl_lock();
1229+
rcu_read_lock();
12291230
if (r.arp_dev[0]) {
12301231
err = -ENODEV;
1231-
dev = __dev_get_by_name(net, r.arp_dev);
1232+
dev = dev_get_by_name_rcu(net, r.arp_dev);
12321233
if (dev == NULL)
12331234
goto out;
12341235

@@ -1252,12 +1253,12 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
12521253
break;
12531254
case SIOCGARP:
12541255
err = arp_req_get(&r, dev);
1255-
if (!err && copy_to_user(arg, &r, sizeof(r)))
1256-
err = -EFAULT;
12571256
break;
12581257
}
12591258
out:
1260-
rtnl_unlock();
1259+
rcu_read_unlock();
1260+
if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
1261+
err = -EFAULT;
12611262
return err;
12621263
}
12631264

net/llc/af_llc.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,9 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
316316
if (unlikely(addr->sllc_family != AF_LLC))
317317
goto out;
318318
rc = -ENODEV;
319-
rtnl_lock();
319+
rcu_read_lock();
320320
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);
322322
if (llc->dev) {
323323
if (!addr->sllc_arphrd)
324324
addr->sllc_arphrd = llc->dev->type;
@@ -329,14 +329,15 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
329329
!llc_mac_match(addr->sllc_mac,
330330
llc->dev->dev_addr)) {
331331
rc = -EINVAL;
332-
dev_put(llc->dev);
333332
llc->dev = NULL;
334333
}
335334
}
336335
} else
337-
llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd,
336+
llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd,
338337
addr->sllc_mac);
339-
rtnl_unlock();
338+
if (llc->dev)
339+
dev_hold(llc->dev);
340+
rcu_read_unlock();
340341
if (!llc->dev)
341342
goto out;
342343
if (!addr->sllc_sap) {

0 commit comments

Comments
 (0)