Commit 8723e1b4 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

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: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9e917dca
...@@ -403,6 +403,9 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) ...@@ -403,6 +403,9 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
return inet_insert_ifa(ifa); return inet_insert_ifa(ifa);
} }
/* Caller must hold RCU or RTNL :
* We dont take a reference on found in_device
*/
struct in_device *inetdev_by_index(struct net *net, int ifindex) struct in_device *inetdev_by_index(struct net *net, int ifindex)
{ {
struct net_device *dev; struct net_device *dev;
...@@ -411,7 +414,7 @@ struct in_device *inetdev_by_index(struct net *net, int ifindex) ...@@ -411,7 +414,7 @@ struct in_device *inetdev_by_index(struct net *net, int ifindex)
rcu_read_lock(); rcu_read_lock();
dev = dev_get_by_index_rcu(net, ifindex); dev = dev_get_by_index_rcu(net, ifindex);
if (dev) if (dev)
in_dev = in_dev_get(dev); in_dev = rcu_dereference_rtnl(dev->ip_ptr);
rcu_read_unlock(); rcu_read_unlock();
return in_dev; return in_dev;
} }
...@@ -453,8 +456,6 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg ...@@ -453,8 +456,6 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
goto errout; goto errout;
} }
__in_dev_put(in_dev);
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) { ifap = &ifa->ifa_next) {
if (tb[IFA_LOCAL] && if (tb[IFA_LOCAL] &&
......
...@@ -590,32 +590,29 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, ...@@ -590,32 +590,29 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi,
if (!dev) if (!dev)
goto out; goto out;
dev_hold(dev); dev_hold(dev);
err = -ENETDOWN; err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN;
if (!(dev->flags & IFF_UP))
goto out;
err = 0;
out:
rcu_read_unlock();
return err;
} else { } else {
struct in_device *in_dev; struct in_device *in_dev;
if (nh->nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) if (nh->nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK))
return -EINVAL; return -EINVAL;
rcu_read_lock();
err = -ENODEV;
in_dev = inetdev_by_index(net, nh->nh_oif); in_dev = inetdev_by_index(net, nh->nh_oif);
if (in_dev == NULL) if (in_dev == NULL)
return -ENODEV; goto out;
if (!(in_dev->dev->flags & IFF_UP)) { err = -ENETDOWN;
in_dev_put(in_dev); if (!(in_dev->dev->flags & IFF_UP))
return -ENETDOWN; goto out;
}
nh->nh_dev = in_dev->dev; nh->nh_dev = in_dev->dev;
dev_hold(nh->nh_dev); dev_hold(nh->nh_dev);
nh->nh_scope = RT_SCOPE_HOST; nh->nh_scope = RT_SCOPE_HOST;
in_dev_put(in_dev); err = 0;
} }
return 0; out:
rcu_read_unlock();
return err;
} }
static inline unsigned int fib_laddr_hashfn(__be32 val) static inline unsigned int fib_laddr_hashfn(__be32 val)
......
...@@ -1429,8 +1429,6 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) ...@@ -1429,8 +1429,6 @@ static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr)
if (imr->imr_ifindex) { if (imr->imr_ifindex) {
idev = inetdev_by_index(net, imr->imr_ifindex); idev = inetdev_by_index(net, imr->imr_ifindex);
if (idev)
__in_dev_put(idev);
return idev; return idev;
} }
if (imr->imr_address.s_addr) { if (imr->imr_address.s_addr) {
......
...@@ -1245,10 +1245,8 @@ static int ipgre_close(struct net_device *dev) ...@@ -1245,10 +1245,8 @@ static int ipgre_close(struct net_device *dev)
if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
struct in_device *in_dev; struct in_device *in_dev;
in_dev = inetdev_by_index(dev_net(dev), t->mlink); in_dev = inetdev_by_index(dev_net(dev), t->mlink);
if (in_dev) { if (in_dev)
ip_mc_dec_group(in_dev, t->parms.iph.daddr); ip_mc_dec_group(in_dev, t->parms.iph.daddr);
in_dev_put(in_dev);
}
} }
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment