Possible deadlock in ipv6?

8 messages, 3 authors, 2012-06-21 · open the first message on its own page

Possible deadlock in ipv6?

From: Vladimir Davydov <hidden>
Date: 2012-06-06 14:49:26

I'm not familiar with the linux net subsystem, so I would appreciate if 
someone could clarify if the following call chain is possible:

addrconf_ifdown() calls neigh_ifdown(nd_tbl) which locks nd_tbl.lock for 
writing and calls

     pneigh_ifdown
     pndisc_destructor
     ipv6_dev_mc_dec
     __ipv6_dev_mc_dec
     igmp6_group_dropped
     igmp6_leave_group
     igmp6_send
     icmp6_dst_alloc
     ip6_neigh_lookup
     neigh_create

and neigh_create() locks nd_tbl.lock for writing again resulting in a 
deadlock.

Thank you.

Re: Possible deadlock in ipv6?

From: Eric Dumazet <hidden>
Date: 2012-06-06 15:53:47

On Wed, 2012-06-06 at 18:49 +0400, Vladimir Davydov wrote:
I'm not familiar with the linux net subsystem, so I would appreciate if 
someone could clarify if the following call chain is possible:

addrconf_ifdown() calls neigh_ifdown(nd_tbl) which locks nd_tbl.lock for 
writing and calls

     pneigh_ifdown
     pndisc_destructor
     ipv6_dev_mc_dec
     __ipv6_dev_mc_dec
     igmp6_group_dropped
     igmp6_leave_group
     igmp6_send
     icmp6_dst_alloc
     ip6_neigh_lookup
     neigh_create

and neigh_create() locks nd_tbl.lock for writing again resulting in a 
deadlock.
It seems a deadlock is possible indeed, good catch !

Re: Possible deadlock in ipv6?

From: Eric Dumazet <hidden>
Date: 2012-06-06 15:58:40

On Wed, 2012-06-06 at 17:53 +0200, Eric Dumazet wrote:
On Wed, 2012-06-06 at 18:49 +0400, Vladimir Davydov wrote:
quoted
I'm not familiar with the linux net subsystem, so I would appreciate if 
someone could clarify if the following call chain is possible:

addrconf_ifdown() calls neigh_ifdown(nd_tbl) which locks nd_tbl.lock for 
writing and calls

     pneigh_ifdown
     pndisc_destructor
     ipv6_dev_mc_dec
     __ipv6_dev_mc_dec
     igmp6_group_dropped
     igmp6_leave_group
     igmp6_send
     icmp6_dst_alloc
     ip6_neigh_lookup
     neigh_create

and neigh_create() locks nd_tbl.lock for writing again resulting in a 
deadlock.
It seems a deadlock is possible indeed, good catch !
And it seems this neigh_down() can be removed, its called later
(after dev->ip6_ptr is cleared)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8f6411c..62c4c00 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2750,7 +2750,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 	ASSERT_RTNL();
 
 	rt6_ifdown(net, dev);
-	neigh_ifdown(&nd_tbl, dev);
 
 	idev = __in6_dev_get(dev);
 	if (idev == NULL)

Re: Possible deadlock in ipv6?

From: Vladimir Davydov <hidden>
Date: 2012-06-06 16:01:43

On Jun 6, 2012, at 7:58 PM, Eric Dumazet wrote:
On Wed, 2012-06-06 at 17:53 +0200, Eric Dumazet wrote:
quoted
On Wed, 2012-06-06 at 18:49 +0400, Vladimir Davydov wrote:
quoted
I'm not familiar with the linux net subsystem, so I would appreciate if 
someone could clarify if the following call chain is possible:

addrconf_ifdown() calls neigh_ifdown(nd_tbl) which locks nd_tbl.lock for 
writing and calls

    pneigh_ifdown
    pndisc_destructor
    ipv6_dev_mc_dec
    __ipv6_dev_mc_dec
    igmp6_group_dropped
    igmp6_leave_group
    igmp6_send
    icmp6_dst_alloc
    ip6_neigh_lookup
    neigh_create

and neigh_create() locks nd_tbl.lock for writing again resulting in a 
deadlock.
It seems a deadlock is possible indeed, good catch !
And it seems this neigh_down() can be removed, its called later
(after dev->ip6_ptr is cleared)
BTW, commit d1ed113f1669390da9898da3beddcc058d938587 did exactly the same, but it was reverted along with a bundle of other commits by 73a8bd74e2618990dbb218c3d82f53e60acd9af0.
quoted hunk
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 8f6411c..62c4c00 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2750,7 +2750,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
	ASSERT_RTNL();

	rt6_ifdown(net, dev);
-	neigh_ifdown(&nd_tbl, dev);

	idev = __in6_dev_get(dev);
	if (idev == NULL)

Re: Possible deadlock in ipv6?

From: Eric Dumazet <hidden>
Date: 2012-06-06 17:02:32

On Wed, 2012-06-06 at 20:01 +0400, Vladimir Davydov wrote:
On Jun 6, 2012, at 7:58 PM, Eric Dumazet wrote:
quoted
On Wed, 2012-06-06 at 17:53 +0200, Eric Dumazet wrote:
quoted
On Wed, 2012-06-06 at 18:49 +0400, Vladimir Davydov wrote:
quoted
I'm not familiar with the linux net subsystem, so I would appreciate if 
someone could clarify if the following call chain is possible:

addrconf_ifdown() calls neigh_ifdown(nd_tbl) which locks nd_tbl.lock for 
writing and calls

    pneigh_ifdown
    pndisc_destructor
    ipv6_dev_mc_dec
    __ipv6_dev_mc_dec
    igmp6_group_dropped
    igmp6_leave_group
    igmp6_send
    icmp6_dst_alloc
    ip6_neigh_lookup
    neigh_create

and neigh_create() locks nd_tbl.lock for writing again resulting in a 
deadlock.
It seems a deadlock is possible indeed, good catch !
And it seems this neigh_down() can be removed, its called later
(after dev->ip6_ptr is cleared)
BTW, commit d1ed113f1669390da9898da3beddcc058d938587 did exactly the same, but it was reverted along with a bundle of other commits by 73a8bd74e2618990dbb218c3d82f53e60acd9af0.
Yes, but the revert was a 'revert a serie', while this particular patch
seems fine, especially if fixing a deadlock ;)

Re: Possible deadlock in ipv6?

From: David Miller <davem@davemloft.net>
Date: 2012-06-12 06:54:56

From: Eric Dumazet <redacted>
Date: Wed, 06 Jun 2012 17:58:34 +0200
And it seems this neigh_down() can be removed, its called later
(after dev->ip6_ptr is cleared)
It is unclear whether we need to do the the neigh_down() in both
the 'how' and '!how' cases.  If so then we can't make this change.

Re: Possible deadlock in ipv6?

From: Eric Dumazet <hidden>
Date: 2012-06-12 09:09:49

On Mon, 2012-06-11 at 23:54 -0700, David Miller wrote:
From: Eric Dumazet <redacted>
Date: Wed, 06 Jun 2012 17:58:34 +0200
quoted
And it seems this neigh_down() can be removed, its called later
(after dev->ip6_ptr is cleared)
It is unclear whether we need to do the the neigh_down() in both
the 'how' and '!how' cases.  If so then we can't make this change.
Hmm...

Is it expected we send traffic on device dismantle ?

If no, we could do :
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index d81d026..16e0ddb 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -681,8 +681,6 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
 		while ((n = *np) != NULL) {
 			if (!dev || n->dev == dev) {
 				*np = n->next;
-				if (tbl->pdestructor)
-					tbl->pdestructor(n);
 				if (n->dev)
 					dev_put(n->dev);
 				release_net(pneigh_net(n));

Re: Possible deadlock in ipv6?

From: David Miller <davem@davemloft.net>
Date: 2012-06-21 04:05:53

From: Eric Dumazet <redacted>
Date: Tue, 12 Jun 2012 11:09:44 +0200
Is it expected we send traffic on device dismantle ?
If we are subscribed to multicast groups we could, to
announce our leaving those groups.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help