Commit 8723e1b4ad9be4444423b4d41509ce859a629649
Committed by
David S. Miller
1 parent
9e917dca74
Exists in
master
and in
7 other branches
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>
Showing 4 changed files with 16 additions and 22 deletions Side-by-side Diff
net/ipv4/devinet.c
... | ... | @@ -403,6 +403,9 @@ |
403 | 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 | 409 | struct in_device *inetdev_by_index(struct net *net, int ifindex) |
407 | 410 | { |
408 | 411 | struct net_device *dev; |
... | ... | @@ -411,7 +414,7 @@ |
411 | 414 | rcu_read_lock(); |
412 | 415 | dev = dev_get_by_index_rcu(net, ifindex); |
413 | 416 | if (dev) |
414 | - in_dev = in_dev_get(dev); | |
417 | + in_dev = rcu_dereference_rtnl(dev->ip_ptr); | |
415 | 418 | rcu_read_unlock(); |
416 | 419 | return in_dev; |
417 | 420 | } |
... | ... | @@ -452,8 +455,6 @@ |
452 | 455 | err = -ENODEV; |
453 | 456 | goto errout; |
454 | 457 | } |
455 | - | |
456 | - __in_dev_put(in_dev); | |
457 | 458 | |
458 | 459 | for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; |
459 | 460 | ifap = &ifa->ifa_next) { |
net/ipv4/fib_semantics.c
... | ... | @@ -590,32 +590,29 @@ |
590 | 590 | if (!dev) |
591 | 591 | goto out; |
592 | 592 | dev_hold(dev); |
593 | - err = -ENETDOWN; | |
594 | - if (!(dev->flags & IFF_UP)) | |
595 | - goto out; | |
596 | - err = 0; | |
597 | -out: | |
598 | - rcu_read_unlock(); | |
599 | - return err; | |
593 | + err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; | |
600 | 594 | } else { |
601 | 595 | struct in_device *in_dev; |
602 | 596 | |
603 | 597 | if (nh->nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) |
604 | 598 | return -EINVAL; |
605 | 599 | |
600 | + rcu_read_lock(); | |
601 | + err = -ENODEV; | |
606 | 602 | in_dev = inetdev_by_index(net, nh->nh_oif); |
607 | 603 | if (in_dev == NULL) |
608 | - return -ENODEV; | |
609 | - if (!(in_dev->dev->flags & IFF_UP)) { | |
610 | - in_dev_put(in_dev); | |
611 | - return -ENETDOWN; | |
612 | - } | |
604 | + goto out; | |
605 | + err = -ENETDOWN; | |
606 | + if (!(in_dev->dev->flags & IFF_UP)) | |
607 | + goto out; | |
613 | 608 | nh->nh_dev = in_dev->dev; |
614 | 609 | dev_hold(nh->nh_dev); |
615 | 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 | 618 | static inline unsigned int fib_laddr_hashfn(__be32 val) |
net/ipv4/igmp.c
net/ipv4/ip_gre.c
... | ... | @@ -1245,10 +1245,8 @@ |
1245 | 1245 | if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { |
1246 | 1246 | struct in_device *in_dev; |
1247 | 1247 | in_dev = inetdev_by_index(dev_net(dev), t->mlink); |
1248 | - if (in_dev) { | |
1248 | + if (in_dev) | |
1249 | 1249 | ip_mc_dec_group(in_dev, t->parms.iph.daddr); |
1250 | - in_dev_put(in_dev); | |
1251 | - } | |
1252 | 1250 | } |
1253 | 1251 | return 0; |
1254 | 1252 | } |