diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2009-11-04 08:43:23 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-04 08:43:23 -0500 |
commit | c6d14c84566d6b70ad9dc1618db0dec87cca9300 (patch) | |
tree | 5ec75245cfda4d61e6b4506b6217f047ff4af01a /net/ipv4/devinet.c | |
parent | d0075634cf9d288988f57392a1f132d2053af961 (diff) |
net: Introduce for_each_netdev_rcu() iterator
Adds RCU management to the list of netdevices.
Convert some for_each_netdev() users to RCU version, if
it can avoid read_lock-ing dev_base_lock
Ie:
read_lock(&dev_base_loack);
for_each_netdev(net, dev)
some_action();
read_unlock(&dev_base_lock);
becomes :
rcu_read_lock();
for_each_netdev_rcu(net, dev)
some_action();
rcu_read_unlock();
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/devinet.c')
-rw-r--r-- | net/ipv4/devinet.c | 30 |
1 files changed, 11 insertions, 19 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index ccccaae50b20..8aa7a134c1f1 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -876,19 +876,16 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) | |||
876 | if (!addr) | 876 | if (!addr) |
877 | addr = ifa->ifa_local; | 877 | addr = ifa->ifa_local; |
878 | } endfor_ifa(in_dev); | 878 | } endfor_ifa(in_dev); |
879 | no_in_dev: | ||
880 | rcu_read_unlock(); | ||
881 | 879 | ||
880 | no_in_dev: | ||
882 | if (addr) | 881 | if (addr) |
883 | goto out; | 882 | goto out_unlock; |
884 | 883 | ||
885 | /* Not loopback addresses on loopback should be preferred | 884 | /* Not loopback addresses on loopback should be preferred |
886 | in this case. It is importnat that lo is the first interface | 885 | in this case. It is importnat that lo is the first interface |
887 | in dev_base list. | 886 | in dev_base list. |
888 | */ | 887 | */ |
889 | read_lock(&dev_base_lock); | 888 | for_each_netdev_rcu(net, dev) { |
890 | rcu_read_lock(); | ||
891 | for_each_netdev(net, dev) { | ||
892 | if ((in_dev = __in_dev_get_rcu(dev)) == NULL) | 889 | if ((in_dev = __in_dev_get_rcu(dev)) == NULL) |
893 | continue; | 890 | continue; |
894 | 891 | ||
@@ -896,12 +893,11 @@ no_in_dev: | |||
896 | if (ifa->ifa_scope != RT_SCOPE_LINK && | 893 | if (ifa->ifa_scope != RT_SCOPE_LINK && |
897 | ifa->ifa_scope <= scope) { | 894 | ifa->ifa_scope <= scope) { |
898 | addr = ifa->ifa_local; | 895 | addr = ifa->ifa_local; |
899 | goto out_unlock_both; | 896 | goto out_unlock; |
900 | } | 897 | } |
901 | } endfor_ifa(in_dev); | 898 | } endfor_ifa(in_dev); |
902 | } | 899 | } |
903 | out_unlock_both: | 900 | out_unlock: |
904 | read_unlock(&dev_base_lock); | ||
905 | rcu_read_unlock(); | 901 | rcu_read_unlock(); |
906 | out: | 902 | out: |
907 | return addr; | 903 | return addr; |
@@ -962,9 +958,8 @@ __be32 inet_confirm_addr(struct in_device *in_dev, | |||
962 | return confirm_addr_indev(in_dev, dst, local, scope); | 958 | return confirm_addr_indev(in_dev, dst, local, scope); |
963 | 959 | ||
964 | net = dev_net(in_dev->dev); | 960 | net = dev_net(in_dev->dev); |
965 | read_lock(&dev_base_lock); | ||
966 | rcu_read_lock(); | 961 | rcu_read_lock(); |
967 | for_each_netdev(net, dev) { | 962 | for_each_netdev_rcu(net, dev) { |
968 | if ((in_dev = __in_dev_get_rcu(dev))) { | 963 | if ((in_dev = __in_dev_get_rcu(dev))) { |
969 | addr = confirm_addr_indev(in_dev, dst, local, scope); | 964 | addr = confirm_addr_indev(in_dev, dst, local, scope); |
970 | if (addr) | 965 | if (addr) |
@@ -972,7 +967,6 @@ __be32 inet_confirm_addr(struct in_device *in_dev, | |||
972 | } | 967 | } |
973 | } | 968 | } |
974 | rcu_read_unlock(); | 969 | rcu_read_unlock(); |
975 | read_unlock(&dev_base_lock); | ||
976 | 970 | ||
977 | return addr; | 971 | return addr; |
978 | } | 972 | } |
@@ -1240,18 +1234,18 @@ static void devinet_copy_dflt_conf(struct net *net, int i) | |||
1240 | { | 1234 | { |
1241 | struct net_device *dev; | 1235 | struct net_device *dev; |
1242 | 1236 | ||
1243 | read_lock(&dev_base_lock); | 1237 | rcu_read_lock(); |
1244 | for_each_netdev(net, dev) { | 1238 | for_each_netdev_rcu(net, dev) { |
1245 | struct in_device *in_dev; | 1239 | struct in_device *in_dev; |
1246 | rcu_read_lock(); | 1240 | |
1247 | in_dev = __in_dev_get_rcu(dev); | 1241 | in_dev = __in_dev_get_rcu(dev); |
1248 | if (in_dev && !test_bit(i, in_dev->cnf.state)) | 1242 | if (in_dev && !test_bit(i, in_dev->cnf.state)) |
1249 | in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i]; | 1243 | in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i]; |
1250 | rcu_read_unlock(); | ||
1251 | } | 1244 | } |
1252 | read_unlock(&dev_base_lock); | 1245 | rcu_read_unlock(); |
1253 | } | 1246 | } |
1254 | 1247 | ||
1248 | /* called with RTNL locked */ | ||
1255 | static void inet_forward_change(struct net *net) | 1249 | static void inet_forward_change(struct net *net) |
1256 | { | 1250 | { |
1257 | struct net_device *dev; | 1251 | struct net_device *dev; |
@@ -1260,7 +1254,6 @@ static void inet_forward_change(struct net *net) | |||
1260 | IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on; | 1254 | IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on; |
1261 | IPV4_DEVCONF_DFLT(net, FORWARDING) = on; | 1255 | IPV4_DEVCONF_DFLT(net, FORWARDING) = on; |
1262 | 1256 | ||
1263 | read_lock(&dev_base_lock); | ||
1264 | for_each_netdev(net, dev) { | 1257 | for_each_netdev(net, dev) { |
1265 | struct in_device *in_dev; | 1258 | struct in_device *in_dev; |
1266 | if (on) | 1259 | if (on) |
@@ -1271,7 +1264,6 @@ static void inet_forward_change(struct net *net) | |||
1271 | IN_DEV_CONF_SET(in_dev, FORWARDING, on); | 1264 | IN_DEV_CONF_SET(in_dev, FORWARDING, on); |
1272 | rcu_read_unlock(); | 1265 | rcu_read_unlock(); |
1273 | } | 1266 | } |
1274 | read_unlock(&dev_base_lock); | ||
1275 | } | 1267 | } |
1276 | 1268 | ||
1277 | static int devinet_conf_proc(ctl_table *ctl, int write, | 1269 | static int devinet_conf_proc(ctl_table *ctl, int write, |