diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-10-18 20:39:26 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-19 06:50:48 -0400 |
commit | 8723e1b4ad9be4444423b4d41509ce859a629649 (patch) | |
tree | 00b0121c12e62736807e998b22b8964f1a5e1df9 /net | |
parent | 9e917dca74138cccf398ce8bb924c7fd2980ec1d (diff) |
inet: RCU changes in inetdev_by_index()
Convert inetdev_by_index() to not increment in_dev refcount.
Callers hold RCU or RTNL, and should not decrement in_dev refcount.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/devinet.c | 7 | ||||
-rw-r--r-- | net/ipv4/fib_semantics.c | 25 | ||||
-rw-r--r-- | net/ipv4/igmp.c | 2 | ||||
-rw-r--r-- | net/ipv4/ip_gre.c | 4 |
4 files changed, 16 insertions, 22 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index c2ff48fa18c7..dc94b0316b78 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -403,6 +403,9 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) | |||
403 | return inet_insert_ifa(ifa); | 403 | return inet_insert_ifa(ifa); |
404 | } | 404 | } |
405 | 405 | ||
406 | /* Caller must hold RCU or RTNL : | ||
407 | * We dont take a reference on found in_device | ||
408 | */ | ||
406 | struct in_device *inetdev_by_index(struct net *net, int ifindex) | 409 | struct in_device *inetdev_by_index(struct net *net, int ifindex) |
407 | { | 410 | { |
408 | struct net_device *dev; | 411 | struct net_device *dev; |
@@ -411,7 +414,7 @@ struct in_device *inetdev_by_index(struct net *net, int ifindex) | |||
411 | rcu_read_lock(); | 414 | rcu_read_lock(); |
412 | dev = dev_get_by_index_rcu(net, ifindex); | 415 | dev = dev_get_by_index_rcu(net, ifindex); |
413 | if (dev) | 416 | if (dev) |
414 | in_dev = in_dev_get(dev); | 417 | in_dev = rcu_dereference_rtnl(dev->ip_ptr); |
415 | rcu_read_unlock(); | 418 | rcu_read_unlock(); |
416 | return in_dev; | 419 | return in_dev; |
417 | } | 420 | } |
@@ -453,8 +456,6 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg | |||
453 | goto errout; | 456 | goto errout; |
454 | } | 457 | } |
455 | 458 | ||
456 | __in_dev_put(in_dev); | ||
457 | |||
458 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; | 459 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; |
459 | ifap = &ifa->ifa_next) { | 460 | ifap = &ifa->ifa_next) { |
460 | if (tb[IFA_LOCAL] && | 461 | if (tb[IFA_LOCAL] && |
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 0f80dfc2f7fb..6734c9cab248 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c | |||
@@ -590,32 +590,29 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, | |||
590 | if (!dev) | 590 | if (!dev) |
591 | goto out; | 591 | goto out; |
592 | dev_hold(dev); | 592 | dev_hold(dev); |
593 | err = -ENETDOWN; | 593 | err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; |
594 | if (!(dev->flags & IFF_UP)) | ||
595 | goto out; | ||
596 | err = 0; | ||
597 | out: | ||
598 | rcu_read_unlock(); | ||
599 | return err; | ||
600 | } else { | 594 | } else { |
601 | struct in_device *in_dev; | 595 | struct in_device *in_dev; |
602 | 596 | ||
603 | if (nh->nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) | 597 | if (nh->nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) |
604 | return -EINVAL; | 598 | return -EINVAL; |
605 | 599 | ||
600 | rcu_read_lock(); | ||
601 | err = -ENODEV; | ||
606 | in_dev = inetdev_by_index(net, nh->nh_oif); | 602 | in_dev = inetdev_by_index(net, nh->nh_oif); |
607 | if (in_dev == NULL) | 603 | if (in_dev == NULL) |
608 | return -ENODEV; | 604 | goto out; |
609 | if (!(in_dev->dev->flags & IFF_UP)) { | 605 | err = -ENETDOWN; |
610 | in_dev_put(in_dev); | 606 | if (!(in_dev->dev->flags & IFF_UP)) |
611 | return -ENETDOWN; | 607 | goto out; |
612 | } | ||
613 | nh->nh_dev = in_dev->dev; | 608 | nh->nh_dev = in_dev->dev; |
614 | dev_hold(nh->nh_dev); | 609 | dev_hold(nh->nh_dev); |
615 | nh->nh_scope = RT_SCOPE_HOST; | 610 | nh->nh_scope = RT_SCOPE_HOST; |
616 | in_dev_put(in_dev); | 611 | err = 0; |
617 | } | 612 | } |
618 | return 0; | 613 | out: |
614 | rcu_read_unlock(); | ||
615 | return err; | ||
619 | } | 616 | } |
620 | 617 | ||
621 | static inline unsigned int fib_laddr_hashfn(__be32 val) | 618 | static inline unsigned int fib_laddr_hashfn(__be32 val) |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a525328ec372..c8877c6c7216 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -1429,8 +1429,6 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) | |||
1429 | 1429 | ||
1430 | if (imr->imr_ifindex) { | 1430 | if (imr->imr_ifindex) { |
1431 | idev = inetdev_by_index(net, imr->imr_ifindex); | 1431 | idev = inetdev_by_index(net, imr->imr_ifindex); |
1432 | if (idev) | ||
1433 | __in_dev_put(idev); | ||
1434 | return idev; | 1432 | return idev; |
1435 | } | 1433 | } |
1436 | if (imr->imr_address.s_addr) { | 1434 | if (imr->imr_address.s_addr) { |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 9d421f4cf3ef..d0ffcbe369b7 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -1245,10 +1245,8 @@ static int ipgre_close(struct net_device *dev) | |||
1245 | if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { | 1245 | if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { |
1246 | struct in_device *in_dev; | 1246 | struct in_device *in_dev; |
1247 | in_dev = inetdev_by_index(dev_net(dev), t->mlink); | 1247 | in_dev = inetdev_by_index(dev_net(dev), t->mlink); |
1248 | if (in_dev) { | 1248 | if (in_dev) |
1249 | ip_mc_dec_group(in_dev, t->parms.iph.daddr); | 1249 | ip_mc_dec_group(in_dev, t->parms.iph.daddr); |
1250 | in_dev_put(in_dev); | ||
1251 | } | ||
1252 | } | 1250 | } |
1253 | return 0; | 1251 | return 0; |
1254 | } | 1252 | } |