Commit 1bffa251 authored by David S. Miller's avatar David S. Miller Committed by James Morris

[IPV4]: Move inetdev/ifa locking over to RCU.

Multicast ipv4 address handling still uses rwlock
and spinlock synchronization.
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent d98e8833
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/rcupdate.h>
struct ipv4_devconf struct ipv4_devconf
{ {
int accept_redirects; int accept_redirects;
...@@ -33,11 +35,11 @@ struct in_device ...@@ -33,11 +35,11 @@ struct in_device
{ {
struct net_device *dev; struct net_device *dev;
atomic_t refcnt; atomic_t refcnt;
rwlock_t lock;
int dead; int dead;
struct in_ifaddr *ifa_list; /* IP ifaddr chain */ struct in_ifaddr *ifa_list; /* IP ifaddr chain */
rwlock_t mc_list_lock;
struct ip_mc_list *mc_list; /* IP multicast filter chain */ struct ip_mc_list *mc_list; /* IP multicast filter chain */
rwlock_t mc_lock; /* for mc_tomb */ spinlock_t mc_tomb_lock;
struct ip_mc_list *mc_tomb; struct ip_mc_list *mc_tomb;
unsigned long mr_v1_seen; unsigned long mr_v1_seen;
unsigned long mr_v2_seen; unsigned long mr_v2_seen;
...@@ -50,6 +52,7 @@ struct in_device ...@@ -50,6 +52,7 @@ struct in_device
struct neigh_parms *arp_parms; struct neigh_parms *arp_parms;
struct ipv4_devconf cnf; struct ipv4_devconf cnf;
struct rcu_head rcu_head;
}; };
#define IN_DEV_FORWARD(in_dev) ((in_dev)->cnf.forwarding) #define IN_DEV_FORWARD(in_dev) ((in_dev)->cnf.forwarding)
...@@ -80,6 +83,7 @@ struct in_ifaddr ...@@ -80,6 +83,7 @@ struct in_ifaddr
{ {
struct in_ifaddr *ifa_next; struct in_ifaddr *ifa_next;
struct in_device *ifa_dev; struct in_device *ifa_dev;
struct rcu_head rcu_head;
u32 ifa_local; u32 ifa_local;
u32 ifa_address; u32 ifa_address;
u32 ifa_mask; u32 ifa_mask;
...@@ -133,19 +137,16 @@ static __inline__ int bad_mask(u32 mask, u32 addr) ...@@ -133,19 +137,16 @@ static __inline__ int bad_mask(u32 mask, u32 addr)
#define endfor_ifa(in_dev) } #define endfor_ifa(in_dev) }
extern rwlock_t inetdev_lock;
static __inline__ struct in_device * static __inline__ struct in_device *
in_dev_get(const struct net_device *dev) in_dev_get(const struct net_device *dev)
{ {
struct in_device *in_dev; struct in_device *in_dev;
read_lock(&inetdev_lock); rcu_read_lock();
in_dev = dev->ip_ptr; in_dev = dev->ip_ptr;
if (in_dev) if (in_dev)
atomic_inc(&in_dev->refcnt); atomic_inc(&in_dev->refcnt);
read_unlock(&inetdev_lock); rcu_read_unlock();
return in_dev; return in_dev;
} }
...@@ -157,13 +158,18 @@ __in_dev_get(const struct net_device *dev) ...@@ -157,13 +158,18 @@ __in_dev_get(const struct net_device *dev)
extern void in_dev_finish_destroy(struct in_device *idev); extern void in_dev_finish_destroy(struct in_device *idev);
static __inline__ void static inline void in_dev_rcu_destroy(struct rcu_head *head)
in_dev_put(struct in_device *idev)
{ {
if (atomic_dec_and_test(&idev->refcnt)) struct in_device *idev = container_of(head, struct in_device, rcu_head);
in_dev_finish_destroy(idev); in_dev_finish_destroy(idev);
} }
static inline void in_dev_put(struct in_device *idev)
{
if (atomic_dec_and_test(&idev->refcnt))
call_rcu(&idev->rcu_head, in_dev_rcu_destroy);
}
#define __in_dev_put(idev) atomic_dec(&(idev)->refcnt) #define __in_dev_put(idev) atomic_dec(&(idev)->refcnt)
#define in_dev_hold(idev) atomic_inc(&(idev)->refcnt) #define in_dev_hold(idev) atomic_inc(&(idev)->refcnt)
......
...@@ -88,12 +88,9 @@ static void devinet_sysctl_register(struct in_device *in_dev, ...@@ -88,12 +88,9 @@ static void devinet_sysctl_register(struct in_device *in_dev,
static void devinet_sysctl_unregister(struct ipv4_devconf *p); static void devinet_sysctl_unregister(struct ipv4_devconf *p);
#endif #endif
int inet_ifa_count;
int inet_dev_count;
/* Locks all the inet devices. */ /* Locks all the inet devices. */
rwlock_t inetdev_lock = RW_LOCK_UNLOCKED; static spinlock_t inetdev_lock = SPIN_LOCK_UNLOCKED;
static struct in_ifaddr *inet_alloc_ifa(void) static struct in_ifaddr *inet_alloc_ifa(void)
{ {
...@@ -101,18 +98,24 @@ static struct in_ifaddr *inet_alloc_ifa(void) ...@@ -101,18 +98,24 @@ static struct in_ifaddr *inet_alloc_ifa(void)
if (ifa) { if (ifa) {
memset(ifa, 0, sizeof(*ifa)); memset(ifa, 0, sizeof(*ifa));
inet_ifa_count++; INIT_RCU_HEAD(&ifa->rcu_head);
} }
return ifa; return ifa;
} }
static __inline__ void inet_free_ifa(struct in_ifaddr *ifa) static inline void inet_free_ifa(struct in_ifaddr *ifa)
{ {
if (ifa->ifa_dev) if (ifa->ifa_dev)
__in_dev_put(ifa->ifa_dev); in_dev_put(ifa->ifa_dev);
kfree(ifa); kfree(ifa);
inet_ifa_count--; }
static void inet_rcu_free_ifa(struct rcu_head *head)
{
struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head);
inet_free_ifa(ifa);
} }
void in_dev_finish_destroy(struct in_device *idev) void in_dev_finish_destroy(struct in_device *idev)
...@@ -129,7 +132,6 @@ void in_dev_finish_destroy(struct in_device *idev) ...@@ -129,7 +132,6 @@ void in_dev_finish_destroy(struct in_device *idev)
if (!idev->dead) if (!idev->dead)
printk("Freeing alive in_device %p\n", idev); printk("Freeing alive in_device %p\n", idev);
else { else {
inet_dev_count--;
kfree(idev); kfree(idev);
} }
} }
...@@ -144,24 +146,23 @@ struct in_device *inetdev_init(struct net_device *dev) ...@@ -144,24 +146,23 @@ struct in_device *inetdev_init(struct net_device *dev)
if (!in_dev) if (!in_dev)
goto out; goto out;
memset(in_dev, 0, sizeof(*in_dev)); memset(in_dev, 0, sizeof(*in_dev));
in_dev->lock = RW_LOCK_UNLOCKED; INIT_RCU_HEAD(&in_dev->rcu_head);
memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf)); memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
in_dev->cnf.sysctl = NULL; in_dev->cnf.sysctl = NULL;
in_dev->dev = dev; in_dev->dev = dev;
if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
goto out_kfree; goto out_kfree;
inet_dev_count++;
/* Reference in_dev->dev */ /* Reference in_dev->dev */
dev_hold(dev); dev_hold(dev);
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
NET_IPV4_NEIGH, "ipv4", NULL); NET_IPV4_NEIGH, "ipv4", NULL);
#endif #endif
write_lock_bh(&inetdev_lock); spin_lock_bh(&inetdev_lock);
dev->ip_ptr = in_dev; dev->ip_ptr = in_dev;
/* Account for reference dev->ip_ptr */ /* Account for reference dev->ip_ptr */
in_dev_hold(in_dev); in_dev_hold(in_dev);
write_unlock_bh(&inetdev_lock); spin_unlock_bh(&inetdev_lock);
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
devinet_sysctl_register(in_dev, &in_dev->cnf); devinet_sysctl_register(in_dev, &in_dev->cnf);
#endif #endif
...@@ -188,16 +189,16 @@ static void inetdev_destroy(struct in_device *in_dev) ...@@ -188,16 +189,16 @@ static void inetdev_destroy(struct in_device *in_dev)
while ((ifa = in_dev->ifa_list) != NULL) { while ((ifa = in_dev->ifa_list) != NULL) {
inet_del_ifa(in_dev, &in_dev->ifa_list, 0); inet_del_ifa(in_dev, &in_dev->ifa_list, 0);
inet_free_ifa(ifa); call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
} }
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
devinet_sysctl_unregister(&in_dev->cnf); devinet_sysctl_unregister(&in_dev->cnf);
#endif #endif
write_lock_bh(&inetdev_lock); spin_lock_bh(&inetdev_lock);
in_dev->dev->ip_ptr = NULL; in_dev->dev->ip_ptr = NULL;
/* in_dev_put following below will kill the in_device */ /* in_dev_put following below will kill the in_device */
write_unlock_bh(&inetdev_lock); spin_unlock_bh(&inetdev_lock);
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
neigh_sysctl_unregister(in_dev->arp_parms); neigh_sysctl_unregister(in_dev->arp_parms);
...@@ -208,16 +209,16 @@ static void inetdev_destroy(struct in_device *in_dev) ...@@ -208,16 +209,16 @@ static void inetdev_destroy(struct in_device *in_dev)
int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
{ {
read_lock(&in_dev->lock); rcu_read_lock();
for_primary_ifa(in_dev) { for_primary_ifa(in_dev) {
if (inet_ifa_match(a, ifa)) { if (inet_ifa_match(a, ifa)) {
if (!b || inet_ifa_match(b, ifa)) { if (!b || inet_ifa_match(b, ifa)) {
read_unlock(&in_dev->lock); rcu_read_unlock();
return 1; return 1;
} }
} }
} endfor_ifa(in_dev); } endfor_ifa(in_dev);
read_unlock(&in_dev->lock); rcu_read_unlock();
return 0; return 0;
} }
...@@ -241,21 +242,21 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, ...@@ -241,21 +242,21 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
ifap1 = &ifa->ifa_next; ifap1 = &ifa->ifa_next;
continue; continue;
} }
write_lock_bh(&in_dev->lock); spin_lock_bh(&inetdev_lock);
*ifap1 = ifa->ifa_next; *ifap1 = ifa->ifa_next;
write_unlock_bh(&in_dev->lock); spin_unlock_bh(&inetdev_lock);
rtmsg_ifa(RTM_DELADDR, ifa); rtmsg_ifa(RTM_DELADDR, ifa);
notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
inet_free_ifa(ifa); call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
} }
} }
/* 2. Unlink it */ /* 2. Unlink it */
write_lock_bh(&in_dev->lock); spin_lock_bh(&inetdev_lock);
*ifap = ifa1->ifa_next; *ifap = ifa1->ifa_next;
write_unlock_bh(&in_dev->lock); spin_unlock_bh(&inetdev_lock);
/* 3. Announce address deletion */ /* 3. Announce address deletion */
...@@ -270,7 +271,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, ...@@ -270,7 +271,7 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
rtmsg_ifa(RTM_DELADDR, ifa1); rtmsg_ifa(RTM_DELADDR, ifa1);
notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
if (destroy) { if (destroy) {
inet_free_ifa(ifa1); call_rcu(&ifa1->rcu_head, inet_rcu_free_ifa);
if (!in_dev->ifa_list) if (!in_dev->ifa_list)
inetdev_destroy(in_dev); inetdev_destroy(in_dev);
...@@ -285,7 +286,7 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) ...@@ -285,7 +286,7 @@ static int inet_insert_ifa(struct in_ifaddr *ifa)
ASSERT_RTNL(); ASSERT_RTNL();
if (!ifa->ifa_local) { if (!ifa->ifa_local) {
inet_free_ifa(ifa); call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
return 0; return 0;
} }
...@@ -300,11 +301,11 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) ...@@ -300,11 +301,11 @@ static int inet_insert_ifa(struct in_ifaddr *ifa)
if (ifa1->ifa_mask == ifa->ifa_mask && if (ifa1->ifa_mask == ifa->ifa_mask &&
inet_ifa_match(ifa1->ifa_address, ifa)) { inet_ifa_match(ifa1->ifa_address, ifa)) {
if (ifa1->ifa_local == ifa->ifa_local) { if (ifa1->ifa_local == ifa->ifa_local) {
inet_free_ifa(ifa); call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
return -EEXIST; return -EEXIST;
} }
if (ifa1->ifa_scope != ifa->ifa_scope) { if (ifa1->ifa_scope != ifa->ifa_scope) {
inet_free_ifa(ifa); call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
return -EINVAL; return -EINVAL;
} }
ifa->ifa_flags |= IFA_F_SECONDARY; ifa->ifa_flags |= IFA_F_SECONDARY;
...@@ -317,9 +318,9 @@ static int inet_insert_ifa(struct in_ifaddr *ifa) ...@@ -317,9 +318,9 @@ static int inet_insert_ifa(struct in_ifaddr *ifa)
} }
ifa->ifa_next = *ifap; ifa->ifa_next = *ifap;
write_lock_bh(&in_dev->lock); spin_lock_bh(&inetdev_lock);
*ifap = ifa; *ifap = ifa;
write_unlock_bh(&in_dev->lock); spin_unlock_bh(&inetdev_lock);
/* Send message first, then call notifier. /* Send message first, then call notifier.
Notifier will trigger FIB update, so that Notifier will trigger FIB update, so that
...@@ -339,7 +340,7 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) ...@@ -339,7 +340,7 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
if (!in_dev) { if (!in_dev) {
in_dev = inetdev_init(dev); in_dev = inetdev_init(dev);
if (!in_dev) { if (!in_dev) {
inet_free_ifa(ifa); call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
return -ENOBUFS; return -ENOBUFS;
} }
} }
...@@ -771,12 +772,11 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) ...@@ -771,12 +772,11 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
u32 addr = 0; u32 addr = 0;
struct in_device *in_dev; struct in_device *in_dev;
read_lock(&inetdev_lock); rcu_read_lock();
in_dev = __in_dev_get(dev); in_dev = __in_dev_get(dev);
if (!in_dev) if (!in_dev)
goto out_unlock_inetdev; goto out_unlock_inetdev;
read_lock(&in_dev->lock);
for_primary_ifa(in_dev) { for_primary_ifa(in_dev) {
if (ifa->ifa_scope > scope) if (ifa->ifa_scope > scope)
continue; continue;
...@@ -787,8 +787,7 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) ...@@ -787,8 +787,7 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
if (!addr) if (!addr)
addr = ifa->ifa_local; addr = ifa->ifa_local;
} endfor_ifa(in_dev); } endfor_ifa(in_dev);
read_unlock(&in_dev->lock); rcu_read_unlock();
read_unlock(&inetdev_lock);
if (addr) if (addr)
goto out; goto out;
...@@ -798,30 +797,25 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope) ...@@ -798,30 +797,25 @@ u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
in dev_base list. in dev_base list.
*/ */
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
read_lock(&inetdev_lock); rcu_read_lock();
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
if ((in_dev = __in_dev_get(dev)) == NULL) if ((in_dev = __in_dev_get(dev)) == NULL)
continue; continue;
read_lock(&in_dev->lock);
for_primary_ifa(in_dev) { for_primary_ifa(in_dev) {
if (ifa->ifa_scope != RT_SCOPE_LINK && if (ifa->ifa_scope != RT_SCOPE_LINK &&
ifa->ifa_scope <= scope) { ifa->ifa_scope <= scope) {
read_unlock(&in_dev->lock);
addr = ifa->ifa_local; addr = ifa->ifa_local;
goto out_unlock_both; goto out_unlock_both;
} }
} endfor_ifa(in_dev); } endfor_ifa(in_dev);
read_unlock(&in_dev->lock);
} }
out_unlock_both: out_unlock_both:
read_unlock(&inetdev_lock);
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
out_unlock_inetdev:
rcu_read_unlock();
out: out:
return addr; return addr;
out_unlock_inetdev:
read_unlock(&inetdev_lock);
goto out;
} }
static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst, static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
...@@ -874,29 +868,24 @@ u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scop ...@@ -874,29 +868,24 @@ u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scop
struct in_device *in_dev; struct in_device *in_dev;
if (dev) { if (dev) {
read_lock(&inetdev_lock); rcu_read_lock();
if ((in_dev = __in_dev_get(dev))) { if ((in_dev = __in_dev_get(dev)))
read_lock(&in_dev->lock);
addr = confirm_addr_indev(in_dev, dst, local, scope); addr = confirm_addr_indev(in_dev, dst, local, scope);
read_unlock(&in_dev->lock); rcu_read_unlock();
}
read_unlock(&inetdev_lock);
return addr; return addr;
} }
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
read_lock(&inetdev_lock); rcu_read_lock();
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
if ((in_dev = __in_dev_get(dev))) { if ((in_dev = __in_dev_get(dev))) {
read_lock(&in_dev->lock);
addr = confirm_addr_indev(in_dev, dst, local, scope); addr = confirm_addr_indev(in_dev, dst, local, scope);
read_unlock(&in_dev->lock);
if (addr) if (addr)
break; break;
} }
} }
read_unlock(&inetdev_lock); rcu_read_unlock();
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
return addr; return addr;
...@@ -1065,12 +1054,12 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1065,12 +1054,12 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
continue; continue;
if (idx > s_idx) if (idx > s_idx)
s_ip_idx = 0; s_ip_idx = 0;
read_lock(&inetdev_lock); rcu_read_lock();
if ((in_dev = __in_dev_get(dev)) == NULL) { if ((in_dev = __in_dev_get(dev)) == NULL) {
read_unlock(&inetdev_lock); rcu_read_unlock();
continue; continue;
} }
read_lock(&in_dev->lock);
for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
ifa = ifa->ifa_next, ip_idx++) { ifa = ifa->ifa_next, ip_idx++) {
if (ip_idx < s_ip_idx) if (ip_idx < s_ip_idx)
...@@ -1078,13 +1067,11 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -1078,13 +1067,11 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
RTM_NEWADDR) <= 0) { RTM_NEWADDR) <= 0) {
read_unlock(&in_dev->lock); rcu_read_unlock();
read_unlock(&inetdev_lock);
goto done; goto done;
} }
} }
read_unlock(&in_dev->lock); rcu_read_unlock();
read_unlock(&inetdev_lock);
} }
done: done:
...@@ -1138,11 +1125,11 @@ void inet_forward_change(void) ...@@ -1138,11 +1125,11 @@ void inet_forward_change(void)
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
struct in_device *in_dev; struct in_device *in_dev;
read_lock(&inetdev_lock); rcu_read_lock();
in_dev = __in_dev_get(dev); in_dev = __in_dev_get(dev);
if (in_dev) if (in_dev)
in_dev->cnf.forwarding = on; in_dev->cnf.forwarding = on;
read_unlock(&inetdev_lock); rcu_read_unlock();
} }
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
...@@ -1508,6 +1495,5 @@ EXPORT_SYMBOL(devinet_ioctl); ...@@ -1508,6 +1495,5 @@ EXPORT_SYMBOL(devinet_ioctl);
EXPORT_SYMBOL(in_dev_finish_destroy); EXPORT_SYMBOL(in_dev_finish_destroy);
EXPORT_SYMBOL(inet_select_addr); EXPORT_SYMBOL(inet_select_addr);
EXPORT_SYMBOL(inetdev_by_index); EXPORT_SYMBOL(inetdev_by_index);
EXPORT_SYMBOL(inetdev_lock);
EXPORT_SYMBOL(register_inetaddr_notifier); EXPORT_SYMBOL(register_inetaddr_notifier);
EXPORT_SYMBOL(unregister_inetaddr_notifier); EXPORT_SYMBOL(unregister_inetaddr_notifier);
...@@ -172,13 +172,13 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, ...@@ -172,13 +172,13 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
int ret; int ret;
no_addr = rpf = 0; no_addr = rpf = 0;
read_lock(&inetdev_lock); rcu_read_lock();
in_dev = __in_dev_get(dev); in_dev = __in_dev_get(dev);
if (in_dev) { if (in_dev) {
no_addr = in_dev->ifa_list == NULL; no_addr = in_dev->ifa_list == NULL;
rpf = IN_DEV_RPFILTER(in_dev); rpf = IN_DEV_RPFILTER(in_dev);
} }
read_unlock(&inetdev_lock); rcu_read_unlock();
if (in_dev == NULL) if (in_dev == NULL)
goto e_inval; goto e_inval;
......
...@@ -878,7 +878,7 @@ static void icmp_address_reply(struct sk_buff *skb) ...@@ -878,7 +878,7 @@ static void icmp_address_reply(struct sk_buff *skb)
in_dev = in_dev_get(dev); in_dev = in_dev_get(dev);
if (!in_dev) if (!in_dev)
goto out; goto out;
read_lock(&in_dev->lock); rcu_read_lock();
if (in_dev->ifa_list && if (in_dev->ifa_list &&
IN_DEV_LOG_MARTIANS(in_dev) && IN_DEV_LOG_MARTIANS(in_dev) &&
IN_DEV_FORWARD(in_dev)) { IN_DEV_FORWARD(in_dev)) {
...@@ -895,7 +895,7 @@ static void icmp_address_reply(struct sk_buff *skb) ...@@ -895,7 +895,7 @@ static void icmp_address_reply(struct sk_buff *skb)
NIPQUAD(mask), dev->name, NIPQUAD(rt->rt_src)); NIPQUAD(mask), dev->name, NIPQUAD(rt->rt_src));
} }
} }
read_unlock(&in_dev->lock); rcu_read_unlock();
in_dev_put(in_dev); in_dev_put(in_dev);
out:; out:;
} }
......
This diff is collapsed.
...@@ -1855,7 +1855,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1855,7 +1855,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
if (MULTICAST(daddr)) { if (MULTICAST(daddr)) {
struct in_device *in_dev; struct in_device *in_dev;
read_lock(&inetdev_lock); rcu_read_lock();
if ((in_dev = __in_dev_get(dev)) != NULL) { if ((in_dev = __in_dev_get(dev)) != NULL) {
int our = ip_check_mc(in_dev, daddr, saddr, int our = ip_check_mc(in_dev, daddr, saddr,
skb->nh.iph->protocol); skb->nh.iph->protocol);
...@@ -1864,12 +1864,12 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, ...@@ -1864,12 +1864,12 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
|| (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev)) || (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))
#endif #endif
) { ) {
read_unlock(&inetdev_lock); rcu_read_unlock();
return ip_route_input_mc(skb, daddr, saddr, return ip_route_input_mc(skb, daddr, saddr,
tos, dev, our); tos, dev, our);
} }
} }
read_unlock(&inetdev_lock); rcu_read_unlock();
return -EINVAL; return -EINVAL;
} }
return ip_route_input_slow(skb, daddr, saddr, tos, dev); return ip_route_input_slow(skb, daddr, saddr, tos, dev);
......
...@@ -306,7 +306,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev) ...@@ -306,7 +306,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev)
in_dev = in_dev_get(dev); in_dev = in_dev_get(dev);
if (in_dev == NULL) if (in_dev == NULL)
return; return;
read_lock(&in_dev->lock); rcu_read_lock();
if (in_dev->ifa_list) if (in_dev->ifa_list)
arp_send(ARPOP_REQUEST, ETH_P_ARP, arp_send(ARPOP_REQUEST, ETH_P_ARP,
...@@ -314,7 +314,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev) ...@@ -314,7 +314,7 @@ void irlan_eth_send_gratuitous_arp(struct net_device *dev)
dev, dev,
in_dev->ifa_list->ifa_address, in_dev->ifa_list->ifa_address,
NULL, dev->dev_addr, NULL); NULL, dev->dev_addr, NULL);
read_unlock(&in_dev->lock); rcu_read_unlock();
in_dev_put(in_dev); in_dev_put(in_dev);
#endif /* CONFIG_INET */ #endif /* CONFIG_INET */
} }
......
...@@ -148,13 +148,12 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -148,13 +148,12 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
struct sctp_sockaddr_entry *addr; struct sctp_sockaddr_entry *addr;
read_lock(&inetdev_lock); rcu_read_lock();
if ((in_dev = __in_dev_get(dev)) == NULL) { if ((in_dev = __in_dev_get(dev)) == NULL) {
read_unlock(&inetdev_lock); rcu_read_unlock();
return; return;
} }
read_lock(&in_dev->lock);
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
/* Add the address to the local list. */ /* Add the address to the local list. */
addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC); addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
...@@ -166,8 +165,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -166,8 +165,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
} }
} }
read_unlock(&in_dev->lock); rcu_read_unlock();
read_unlock(&inetdev_lock);
} }
/* Extract our IP addresses from the system and stash them in the /* Extract our IP addresses from the system and stash them in the
......
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