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;
...@@ -31,13 +33,13 @@ extern struct ipv4_devconf ipv4_devconf; ...@@ -31,13 +33,13 @@ extern struct ipv4_devconf ipv4_devconf;
struct in_device 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,11 +158,16 @@ __in_dev_get(const struct net_device *dev) ...@@ -157,11 +158,16 @@ __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) {
struct in_device *idev = container_of(head, struct in_device, rcu_head);
in_dev_finish_destroy(idev);
}
static inline void in_dev_put(struct in_device *idev)
{ {
if (atomic_dec_and_test(&idev->refcnt)) if (atomic_dec_and_test(&idev->refcnt))
in_dev_finish_destroy(idev); 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)
......
...@@ -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:;
} }
......
...@@ -487,7 +487,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) ...@@ -487,7 +487,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc)
int type; int type;
if (!pmc) { if (!pmc) {
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
if (pmc->multiaddr == IGMP_ALL_HOSTS) if (pmc->multiaddr == IGMP_ALL_HOSTS)
continue; continue;
...@@ -499,7 +499,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) ...@@ -499,7 +499,7 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc)
skb = add_grec(skb, pmc, type, 0, 0); skb = add_grec(skb, pmc, type, 0, 0);
spin_unlock_bh(&pmc->lock); spin_unlock_bh(&pmc->lock);
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
} else { } else {
spin_lock_bh(&pmc->lock); spin_lock_bh(&pmc->lock);
if (pmc->sfcount[MCAST_EXCLUDE]) if (pmc->sfcount[MCAST_EXCLUDE])
...@@ -541,8 +541,8 @@ static void igmpv3_send_cr(struct in_device *in_dev) ...@@ -541,8 +541,8 @@ static void igmpv3_send_cr(struct in_device *in_dev)
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
int type, dtype; int type, dtype;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
write_lock_bh(&in_dev->mc_lock); spin_lock_bh(&in_dev->mc_tomb_lock);
/* deleted MCA's */ /* deleted MCA's */
pmc_prev = NULL; pmc_prev = NULL;
...@@ -575,7 +575,7 @@ static void igmpv3_send_cr(struct in_device *in_dev) ...@@ -575,7 +575,7 @@ static void igmpv3_send_cr(struct in_device *in_dev)
} else } else
pmc_prev = pmc; pmc_prev = pmc;
} }
write_unlock_bh(&in_dev->mc_lock); spin_unlock_bh(&in_dev->mc_tomb_lock);
/* change recs */ /* change recs */
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
...@@ -601,7 +601,8 @@ static void igmpv3_send_cr(struct in_device *in_dev) ...@@ -601,7 +601,8 @@ static void igmpv3_send_cr(struct in_device *in_dev)
} }
spin_unlock_bh(&pmc->lock); spin_unlock_bh(&pmc->lock);
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
if (!skb) if (!skb)
return; return;
(void) igmpv3_sendpack(skb); (void) igmpv3_sendpack(skb);
...@@ -759,14 +760,14 @@ static void igmp_heard_report(struct in_device *in_dev, u32 group) ...@@ -759,14 +760,14 @@ static void igmp_heard_report(struct in_device *in_dev, u32 group)
if (group == IGMP_ALL_HOSTS) if (group == IGMP_ALL_HOSTS)
return; return;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (im=in_dev->mc_list; im!=NULL; im=im->next) { for (im=in_dev->mc_list; im!=NULL; im=im->next) {
if (im->multiaddr == group) { if (im->multiaddr == group) {
igmp_stop_timer(im); igmp_stop_timer(im);
break; break;
} }
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
} }
static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
...@@ -840,7 +841,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, ...@@ -840,7 +841,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
* - Use the igmp->igmp_code field as the maximum * - Use the igmp->igmp_code field as the maximum
* delay possible * delay possible
*/ */
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (im=in_dev->mc_list; im!=NULL; im=im->next) { for (im=in_dev->mc_list; im!=NULL; im=im->next) {
if (group && group != im->multiaddr) if (group && group != im->multiaddr)
continue; continue;
...@@ -856,7 +857,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, ...@@ -856,7 +857,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
spin_unlock_bh(&im->lock); spin_unlock_bh(&im->lock);
igmp_mod_timer(im, max_delay); igmp_mod_timer(im, max_delay);
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
} }
int igmp_rcv(struct sk_buff *skb) int igmp_rcv(struct sk_buff *skb)
...@@ -982,10 +983,10 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im) ...@@ -982,10 +983,10 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
} }
spin_unlock_bh(&im->lock); spin_unlock_bh(&im->lock);
write_lock_bh(&in_dev->mc_lock); spin_lock_bh(&in_dev->mc_tomb_lock);
pmc->next = in_dev->mc_tomb; pmc->next = in_dev->mc_tomb;
in_dev->mc_tomb = pmc; in_dev->mc_tomb = pmc;
write_unlock_bh(&in_dev->mc_lock); spin_unlock_bh(&in_dev->mc_tomb_lock);
} }
static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr) static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
...@@ -993,7 +994,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr) ...@@ -993,7 +994,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
struct ip_mc_list *pmc, *pmc_prev; struct ip_mc_list *pmc, *pmc_prev;
struct ip_sf_list *psf, *psf_next; struct ip_sf_list *psf, *psf_next;
write_lock_bh(&in_dev->mc_lock); spin_lock_bh(&in_dev->mc_tomb_lock);
pmc_prev = NULL; pmc_prev = NULL;
for (pmc=in_dev->mc_tomb; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_tomb; pmc; pmc=pmc->next) {
if (pmc->multiaddr == multiaddr) if (pmc->multiaddr == multiaddr)
...@@ -1006,7 +1007,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr) ...@@ -1006,7 +1007,7 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
else else
in_dev->mc_tomb = pmc->next; in_dev->mc_tomb = pmc->next;
} }
write_unlock_bh(&in_dev->mc_lock); spin_unlock_bh(&in_dev->mc_tomb_lock);
if (pmc) { if (pmc) {
for (psf=pmc->tomb; psf; psf=psf_next) { for (psf=pmc->tomb; psf; psf=psf_next) {
psf_next = psf->sf_next; psf_next = psf->sf_next;
...@@ -1021,10 +1022,10 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) ...@@ -1021,10 +1022,10 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
{ {
struct ip_mc_list *pmc, *nextpmc; struct ip_mc_list *pmc, *nextpmc;
write_lock_bh(&in_dev->mc_lock); spin_lock_bh(&in_dev->mc_tomb_lock);
pmc = in_dev->mc_tomb; pmc = in_dev->mc_tomb;
in_dev->mc_tomb = NULL; in_dev->mc_tomb = NULL;
write_unlock_bh(&in_dev->mc_lock); spin_unlock_bh(&in_dev->mc_tomb_lock);
for (; pmc; pmc = nextpmc) { for (; pmc; pmc = nextpmc) {
nextpmc = pmc->next; nextpmc = pmc->next;
...@@ -1033,7 +1034,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) ...@@ -1033,7 +1034,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
kfree(pmc); kfree(pmc);
} }
/* clear dead sources, too */ /* clear dead sources, too */
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
struct ip_sf_list *psf, *psf_next; struct ip_sf_list *psf, *psf_next;
...@@ -1046,7 +1047,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev) ...@@ -1046,7 +1047,7 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
kfree(psf); kfree(psf);
} }
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
} }
#endif #endif
...@@ -1167,10 +1168,10 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr) ...@@ -1167,10 +1168,10 @@ void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
im->gsquery = 0; im->gsquery = 0;
#endif #endif
im->loaded = 0; im->loaded = 0;
write_lock_bh(&in_dev->lock); write_lock_bh(&in_dev->mc_list_lock);
im->next=in_dev->mc_list; im->next=in_dev->mc_list;
in_dev->mc_list=im; in_dev->mc_list=im;
write_unlock_bh(&in_dev->lock); write_unlock_bh(&in_dev->mc_list_lock);
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
igmpv3_del_delrec(in_dev, im->multiaddr); igmpv3_del_delrec(in_dev, im->multiaddr);
#endif #endif
...@@ -1194,9 +1195,9 @@ void ip_mc_dec_group(struct in_device *in_dev, u32 addr) ...@@ -1194,9 +1195,9 @@ void ip_mc_dec_group(struct in_device *in_dev, u32 addr)
for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
if (i->multiaddr==addr) { if (i->multiaddr==addr) {
if (--i->users == 0) { if (--i->users == 0) {
write_lock_bh(&in_dev->lock); write_lock_bh(&in_dev->mc_list_lock);
*ip = i->next; *ip = i->next;
write_unlock_bh(&in_dev->lock); write_unlock_bh(&in_dev->mc_list_lock);
igmp_group_dropped(i); igmp_group_dropped(i);
if (!in_dev->dead) if (!in_dev->dead)
...@@ -1251,7 +1252,8 @@ void ip_mc_init_dev(struct in_device *in_dev) ...@@ -1251,7 +1252,8 @@ void ip_mc_init_dev(struct in_device *in_dev)
in_dev->mr_qrv = IGMP_Unsolicited_Report_Count; in_dev->mr_qrv = IGMP_Unsolicited_Report_Count;
#endif #endif
in_dev->mc_lock = RW_LOCK_UNLOCKED; in_dev->mc_list_lock = RW_LOCK_UNLOCKED;
in_dev->mc_tomb_lock = SPIN_LOCK_UNLOCKED;
} }
/* Device going up */ /* Device going up */
...@@ -1281,17 +1283,17 @@ void ip_mc_destroy_dev(struct in_device *in_dev) ...@@ -1281,17 +1283,17 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
/* Deactivate timers */ /* Deactivate timers */
ip_mc_down(in_dev); ip_mc_down(in_dev);
write_lock_bh(&in_dev->lock); write_lock_bh(&in_dev->mc_list_lock);
while ((i = in_dev->mc_list) != NULL) { while ((i = in_dev->mc_list) != NULL) {
in_dev->mc_list = i->next; in_dev->mc_list = i->next;
write_unlock_bh(&in_dev->lock); write_unlock_bh(&in_dev->mc_list_lock);
igmp_group_dropped(i); igmp_group_dropped(i);
ip_ma_put(i); ip_ma_put(i);
write_lock_bh(&in_dev->lock); write_lock_bh(&in_dev->mc_list_lock);
} }
write_unlock_bh(&in_dev->lock); write_unlock_bh(&in_dev->mc_list_lock);
} }
static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr) static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
...@@ -1391,18 +1393,18 @@ int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode, ...@@ -1391,18 +1393,18 @@ int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
if (!in_dev) if (!in_dev)
return -ENODEV; return -ENODEV;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
if (*pmca == pmc->multiaddr) if (*pmca == pmc->multiaddr)
break; break;
} }
if (!pmc) { if (!pmc) {
/* MCA not found?? bug */ /* MCA not found?? bug */
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
return -ESRCH; return -ESRCH;
} }
spin_lock_bh(&pmc->lock); spin_lock_bh(&pmc->lock);
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
sf_markstate(pmc); sf_markstate(pmc);
#endif #endif
...@@ -1527,18 +1529,18 @@ int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode, ...@@ -1527,18 +1529,18 @@ int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
if (!in_dev) if (!in_dev)
return -ENODEV; return -ENODEV;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) { for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {
if (*pmca == pmc->multiaddr) if (*pmca == pmc->multiaddr)
break; break;
} }
if (!pmc) { if (!pmc) {
/* MCA not found?? bug */ /* MCA not found?? bug */
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
return -ESRCH; return -ESRCH;
} }
spin_lock_bh(&pmc->lock); spin_lock_bh(&pmc->lock);
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
sf_markstate(pmc); sf_markstate(pmc);
...@@ -2095,7 +2097,7 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto) ...@@ -2095,7 +2097,7 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
struct ip_sf_list *psf; struct ip_sf_list *psf;
int rv = 0; int rv = 0;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
for (im=in_dev->mc_list; im; im=im->next) { for (im=in_dev->mc_list; im; im=im->next) {
if (im->multiaddr == mc_addr) if (im->multiaddr == mc_addr)
break; break;
...@@ -2117,7 +2119,7 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto) ...@@ -2117,7 +2119,7 @@ int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
} else } else
rv = 1; /* unspecified source; tentatively allow */ rv = 1; /* unspecified source; tentatively allow */
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
return rv; return rv;
} }
...@@ -2141,13 +2143,13 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) ...@@ -2141,13 +2143,13 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
in_dev = in_dev_get(state->dev); in_dev = in_dev_get(state->dev);
if (!in_dev) if (!in_dev)
continue; continue;
read_lock(&in_dev->lock); read_lock(&in_dev->mc_list_lock);
im = in_dev->mc_list; im = in_dev->mc_list;
if (im) { if (im) {
state->in_dev = in_dev; state->in_dev = in_dev;
break; break;
} }
read_unlock(&in_dev->lock); read_unlock(&in_dev->mc_list_lock);
in_dev_put(in_dev); in_dev_put(in_dev);
} }
return im; return im;
...@@ -2159,7 +2161,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li ...@@ -2159,7 +2161,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li
im = im->next; im = im->next;
while (!im) { while (!im) {
if (likely(state->in_dev != NULL)) { if (likely(state->in_dev != NULL)) {
read_unlock(&state->in_dev->lock); read_unlock(&state->in_dev->mc_list_lock);
in_dev_put(state->in_dev); in_dev_put(state->in_dev);
} }
state->dev = state->dev->next; state->dev = state->dev->next;
...@@ -2170,7 +2172,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li ...@@ -2170,7 +2172,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li
state->in_dev = in_dev_get(state->dev); state->in_dev = in_dev_get(state->dev);
if (!state->in_dev) if (!state->in_dev)
continue; continue;
read_lock(&state->in_dev->lock); read_lock(&state->in_dev->mc_list_lock);
im = state->in_dev->mc_list; im = state->in_dev->mc_list;
} }
return im; return im;
...@@ -2206,7 +2208,7 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v) ...@@ -2206,7 +2208,7 @@ static void igmp_mc_seq_stop(struct seq_file *seq, void *v)
{ {
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
if (likely(state->in_dev != NULL)) { if (likely(state->in_dev != NULL)) {
read_unlock(&state->in_dev->lock); read_unlock(&state->in_dev->mc_list_lock);
in_dev_put(state->in_dev); in_dev_put(state->in_dev);
state->in_dev = NULL; state->in_dev = NULL;
} }
...@@ -2304,7 +2306,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) ...@@ -2304,7 +2306,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
idev = in_dev_get(state->dev); idev = in_dev_get(state->dev);
if (unlikely(idev == NULL)) if (unlikely(idev == NULL))
continue; continue;
read_lock_bh(&idev->lock); read_lock(&idev->mc_list_lock);
im = idev->mc_list; im = idev->mc_list;
if (likely(im != NULL)) { if (likely(im != NULL)) {
spin_lock_bh(&im->lock); spin_lock_bh(&im->lock);
...@@ -2316,7 +2318,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) ...@@ -2316,7 +2318,7 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
} }
spin_unlock_bh(&im->lock); spin_unlock_bh(&im->lock);
} }
read_unlock_bh(&idev->lock); read_unlock(&idev->mc_list_lock);
in_dev_put(idev); in_dev_put(idev);
} }
return psf; return psf;
...@@ -2332,7 +2334,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l ...@@ -2332,7 +2334,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l
state->im = state->im->next; state->im = state->im->next;
while (!state->im) { while (!state->im) {
if (likely(state->idev != NULL)) { if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock); read_unlock(&state->idev->mc_list_lock);
in_dev_put(state->idev); in_dev_put(state->idev);
} }
state->dev = state->dev->next; state->dev = state->dev->next;
...@@ -2343,7 +2345,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l ...@@ -2343,7 +2345,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l
state->idev = in_dev_get(state->dev); state->idev = in_dev_get(state->dev);
if (!state->idev) if (!state->idev)
continue; continue;
read_lock_bh(&state->idev->lock); read_lock(&state->idev->mc_list_lock);
state->im = state->idev->mc_list; state->im = state->idev->mc_list;
} }
if (!state->im) if (!state->im)
...@@ -2389,7 +2391,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) ...@@ -2389,7 +2391,7 @@ static void igmp_mcf_seq_stop(struct seq_file *seq, void *v)
state->im = NULL; state->im = NULL;
} }
if (likely(state->idev != NULL)) { if (likely(state->idev != NULL)) {
read_unlock_bh(&state->idev->lock); read_unlock(&state->idev->mc_list_lock);
in_dev_put(state->idev); in_dev_put(state->idev);
state->idev = NULL; state->idev = NULL;
} }
......
...@@ -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