diff options
author | Cong Wang <amwang@redhat.com> | 2013-08-31 01:44:32 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-31 22:30:00 -0400 |
commit | caf92bc4007036cfac8ee06c845fdfe6496e4fb3 (patch) | |
tree | 822f242d34e00ff36af27c6768761a1ae6a0e03d /net/ipv6 | |
parent | 034dfc5df99eb8d263211524983b1a737b25c06b (diff) |
ipv6: do not call ndisc_send_rs() with write lock
Because vxlan module will call ip6_dst_lookup() in TX path,
which will hold write lock. So we have to release this write lock
before calling ndisc_send_rs(), otherwise could deadlock.
Reviewed-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 619451336bf1..baaaead69ee1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -3090,6 +3090,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
3090 | static void addrconf_rs_timer(unsigned long data) | 3090 | static void addrconf_rs_timer(unsigned long data) |
3091 | { | 3091 | { |
3092 | struct inet6_dev *idev = (struct inet6_dev *)data; | 3092 | struct inet6_dev *idev = (struct inet6_dev *)data; |
3093 | struct net_device *dev = idev->dev; | ||
3093 | struct in6_addr lladdr; | 3094 | struct in6_addr lladdr; |
3094 | 3095 | ||
3095 | write_lock(&idev->lock); | 3096 | write_lock(&idev->lock); |
@@ -3104,12 +3105,14 @@ static void addrconf_rs_timer(unsigned long data) | |||
3104 | goto out; | 3105 | goto out; |
3105 | 3106 | ||
3106 | if (idev->rs_probes++ < idev->cnf.rtr_solicits) { | 3107 | if (idev->rs_probes++ < idev->cnf.rtr_solicits) { |
3107 | if (!__ipv6_get_lladdr(idev, &lladdr, IFA_F_TENTATIVE)) | 3108 | write_unlock(&idev->lock); |
3108 | ndisc_send_rs(idev->dev, &lladdr, | 3109 | if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) |
3110 | ndisc_send_rs(dev, &lladdr, | ||
3109 | &in6addr_linklocal_allrouters); | 3111 | &in6addr_linklocal_allrouters); |
3110 | else | 3112 | else |
3111 | goto out; | 3113 | goto put; |
3112 | 3114 | ||
3115 | write_lock(&idev->lock); | ||
3113 | /* The wait after the last probe can be shorter */ | 3116 | /* The wait after the last probe can be shorter */ |
3114 | addrconf_mod_rs_timer(idev, (idev->rs_probes == | 3117 | addrconf_mod_rs_timer(idev, (idev->rs_probes == |
3115 | idev->cnf.rtr_solicits) ? | 3118 | idev->cnf.rtr_solicits) ? |
@@ -3125,6 +3128,7 @@ static void addrconf_rs_timer(unsigned long data) | |||
3125 | 3128 | ||
3126 | out: | 3129 | out: |
3127 | write_unlock(&idev->lock); | 3130 | write_unlock(&idev->lock); |
3131 | put: | ||
3128 | in6_dev_put(idev); | 3132 | in6_dev_put(idev); |
3129 | } | 3133 | } |
3130 | 3134 | ||