netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 0/4] Bridge IGMP cleanup and fixes
@ 2010-04-28  1:01 Stephen Hemminger
  2010-04-28  1:01 ` [PATCH net-next 1/4] bridge: simplify multicast_add_router Stephen Hemminger
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Stephen Hemminger @ 2010-04-28  1:01 UTC (permalink / raw)
  To: David S. Miller, Herbert Xu; +Cc: netdev

-- 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH net-next 1/4] bridge: simplify multicast_add_router
  2010-04-28  1:01 [PATCH net-next 0/4] Bridge IGMP cleanup and fixes Stephen Hemminger
@ 2010-04-28  1:01 ` Stephen Hemminger
  2010-04-28  1:01 ` [PATCH net-next 2/4] bridge: multicast flood Stephen Hemminger
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Stephen Hemminger @ 2010-04-28  1:01 UTC (permalink / raw)
  To: David S. Miller, Herbert Xu; +Cc: netdev

[-- Attachment #1: br-mcast-list2.patch --]
[-- Type: text/plain, Size: 1172 bytes --]

By coding slightly differently, there are only two cases
to deal with: add at head and add after previous entry.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


--- a/net/bridge/br_multicast.c	2010-04-27 17:02:06.720839467 -0700
+++ b/net/bridge/br_multicast.c	2010-04-27 17:11:06.518933878 -0700
@@ -1039,22 +1039,25 @@ static int br_ip6_multicast_mld2_report(
 }
 #endif
 
+/*
+ * Add port to rotuer_list
+ *  list is maintained ordered by pointer value
+ *  and locked by br->multicast_lock and RCU
+ */
 static void br_multicast_add_router(struct net_bridge *br,
 				    struct net_bridge_port *port)
 {
 	struct net_bridge_port *p;
-	struct hlist_node *n, *last = NULL;
+	struct hlist_node *n, *slot = NULL;
 
 	hlist_for_each_entry(p, n, &br->router_list, rlist) {
-		if ((unsigned long) port >= (unsigned long) p) {
-			hlist_add_before_rcu(n, &port->rlist);
-			return;
-		}
-		last = n;
+		if ((unsigned long) port >= (unsigned long) p)
+			break;
+		slot = n;
 	}
 
-	if (last)
-		hlist_add_after_rcu(last, &port->rlist);
+	if (slot)
+		hlist_add_after_rcu(slot, &port->rlist);
 	else
 		hlist_add_head_rcu(&port->rlist, &br->router_list);
 }

-- 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH net-next 2/4] bridge: multicast flood
  2010-04-28  1:01 [PATCH net-next 0/4] Bridge IGMP cleanup and fixes Stephen Hemminger
  2010-04-28  1:01 ` [PATCH net-next 1/4] bridge: simplify multicast_add_router Stephen Hemminger
@ 2010-04-28  1:01 ` Stephen Hemminger
  2010-04-28  1:01 ` [PATCH net-next 3/4] bridge: multicast port group RCU fix Stephen Hemminger
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Stephen Hemminger @ 2010-04-28  1:01 UTC (permalink / raw)
  To: David S. Miller, Herbert Xu; +Cc: netdev

[-- Attachment #1: br-router-list-rcu.patch --]
[-- Type: text/plain, Size: 786 bytes --]

Fix unsafe usage of RCU. Would never work on Alpha SMP because
of lack of rcu_dereference()

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/bridge/br_forward.c	2010-04-27 17:11:52.008626080 -0700
+++ b/net/bridge/br_forward.c	2010-04-27 17:23:46.388602995 -0700
@@ -216,7 +216,7 @@ static void br_multicast_flood(struct ne
 
 	prev = NULL;
 
-	rp = br->router_list.first;
+	rp = rcu_dereference(br->router_list.first);
 	p = mdst ? mdst->ports : NULL;
 	while (p || rp) {
 		lport = p ? p->port : NULL;
@@ -233,7 +233,7 @@ static void br_multicast_flood(struct ne
 		if ((unsigned long)lport >= (unsigned long)port)
 			p = p->next;
 		if ((unsigned long)rport >= (unsigned long)port)
-			rp = rp->next;
+			rp = rcu_dereference(rp->next);
 	}
 
 	if (!prev)

-- 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH net-next 3/4] bridge: multicast port group RCU fix
  2010-04-28  1:01 [PATCH net-next 0/4] Bridge IGMP cleanup and fixes Stephen Hemminger
  2010-04-28  1:01 ` [PATCH net-next 1/4] bridge: simplify multicast_add_router Stephen Hemminger
  2010-04-28  1:01 ` [PATCH net-next 2/4] bridge: multicast flood Stephen Hemminger
@ 2010-04-28  1:01 ` Stephen Hemminger
  2010-04-28  3:07   ` Herbert Xu
  2010-04-28  1:01 ` [PATCH net-next 4/4] bridge: multicast_flood cleanup Stephen Hemminger
  2010-04-28  1:14 ` [PATCH net-next 0/4] Bridge IGMP cleanup and fixes David Miller
  4 siblings, 1 reply; 8+ messages in thread
From: Stephen Hemminger @ 2010-04-28  1:01 UTC (permalink / raw)
  To: David S. Miller, Herbert Xu; +Cc: netdev

[-- Attachment #1: br-portlist-rcu.patch --]
[-- Type: text/plain, Size: 1463 bytes --]

The recently introduced bridge mulitcast port group list was only
partially using RCU correctly. It was missing rcu_dereference()
and missing the necessary barrier on deletion.

The code should have used one of the standard list methods (list or hlist)
instead of open coding a RCU based link list.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/bridge/br_forward.c	2010-04-27 17:51:27.909588950 -0700
+++ b/net/bridge/br_forward.c	2010-04-27 17:53:18.790721091 -0700
@@ -217,7 +217,7 @@ static void br_multicast_flood(struct ne
 	prev = NULL;
 
 	rp = rcu_dereference(br->router_list.first);
-	p = mdst ? mdst->ports : NULL;
+	p = mdst ? rcu_dereference(mdst->ports) : NULL;
 	while (p || rp) {
 		lport = p ? p->port : NULL;
 		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
@@ -231,7 +231,7 @@ static void br_multicast_flood(struct ne
 			goto out;
 
 		if ((unsigned long)lport >= (unsigned long)port)
-			p = p->next;
+			p = rcu_dereference(p->next);
 		if ((unsigned long)rport >= (unsigned long)port)
 			rp = rcu_dereference(rp->next);
 	}
--- a/net/bridge/br_multicast.c	2010-04-27 17:51:31.509593914 -0700
+++ b/net/bridge/br_multicast.c	2010-04-27 17:52:48.209243982 -0700
@@ -259,7 +259,7 @@ static void br_multicast_del_pg(struct n
 		if (p != pg)
 			continue;
 
-		*pp = p->next;
+		rcu_assign_pointer(*pp, p->next);
 		hlist_del_init(&p->mglist);
 		del_timer(&p->timer);
 		del_timer(&p->query_timer);

-- 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH net-next 4/4] bridge: multicast_flood cleanup
  2010-04-28  1:01 [PATCH net-next 0/4] Bridge IGMP cleanup and fixes Stephen Hemminger
                   ` (2 preceding siblings ...)
  2010-04-28  1:01 ` [PATCH net-next 3/4] bridge: multicast port group RCU fix Stephen Hemminger
@ 2010-04-28  1:01 ` Stephen Hemminger
  2010-04-28  1:14 ` [PATCH net-next 0/4] Bridge IGMP cleanup and fixes David Miller
  4 siblings, 0 replies; 8+ messages in thread
From: Stephen Hemminger @ 2010-04-28  1:01 UTC (permalink / raw)
  To: David S. Miller, Herbert Xu; +Cc: netdev

[-- Attachment #1: br-flood-clean.patch --]
[-- Type: text/plain, Size: 958 bytes --]

Move some declarations around to make it clearer which variables
are being used inside loop.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

--- a/net/bridge/br_forward.c	2010-04-27 17:58:25.739592056 -0700
+++ b/net/bridge/br_forward.c	2010-04-27 17:59:17.182654034 -0700
@@ -208,17 +208,15 @@ static void br_multicast_flood(struct ne
 {
 	struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
 	struct net_bridge *br = netdev_priv(dev);
-	struct net_bridge_port *port;
-	struct net_bridge_port *lport, *rport;
-	struct net_bridge_port *prev;
+	struct net_bridge_port *prev = NULL;
 	struct net_bridge_port_group *p;
 	struct hlist_node *rp;
 
-	prev = NULL;
-
 	rp = rcu_dereference(br->router_list.first);
 	p = mdst ? rcu_dereference(mdst->ports) : NULL;
 	while (p || rp) {
+		struct net_bridge_port *port, *lport, *rport;
+
 		lport = p ? p->port : NULL;
 		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
 			     NULL;

-- 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next 0/4] Bridge IGMP cleanup and fixes
  2010-04-28  1:01 [PATCH net-next 0/4] Bridge IGMP cleanup and fixes Stephen Hemminger
                   ` (3 preceding siblings ...)
  2010-04-28  1:01 ` [PATCH net-next 4/4] bridge: multicast_flood cleanup Stephen Hemminger
@ 2010-04-28  1:14 ` David Miller
  4 siblings, 0 replies; 8+ messages in thread
From: David Miller @ 2010-04-28  1:14 UTC (permalink / raw)
  To: shemminger; +Cc: herbert, netdev


All looks good, I'll apply to net-next-2.6 and build test.

Thanks Stephen.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next 3/4] bridge: multicast port group RCU fix
  2010-04-28  1:01 ` [PATCH net-next 3/4] bridge: multicast port group RCU fix Stephen Hemminger
@ 2010-04-28  3:07   ` Herbert Xu
  2010-04-28  3:47     ` Stephen Hemminger
  0 siblings, 1 reply; 8+ messages in thread
From: Herbert Xu @ 2010-04-28  3:07 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David S. Miller, netdev

On Tue, Apr 27, 2010 at 06:01:06PM -0700, Stephen Hemminger wrote:
> The recently introduced bridge mulitcast port group list was only
> partially using RCU correctly. It was missing rcu_dereference()
> and missing the necessary barrier on deletion.
> 
> The code should have used one of the standard list methods (list or hlist)
> instead of open coding a RCU based link list.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> 
> --- a/net/bridge/br_forward.c	2010-04-27 17:51:27.909588950 -0700
> +++ b/net/bridge/br_forward.c	2010-04-27 17:53:18.790721091 -0700
> @@ -217,7 +217,7 @@ static void br_multicast_flood(struct ne
>  	prev = NULL;
>  
>  	rp = rcu_dereference(br->router_list.first);
> -	p = mdst ? mdst->ports : NULL;
> +	p = mdst ? rcu_dereference(mdst->ports) : NULL;
>  	while (p || rp) {
>  		lport = p ? p->port : NULL;
>  		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
> @@ -231,7 +231,7 @@ static void br_multicast_flood(struct ne
>  			goto out;
>  
>  		if ((unsigned long)lport >= (unsigned long)port)
> -			p = p->next;
> +			p = rcu_dereference(p->next);
>  		if ((unsigned long)rport >= (unsigned long)port)
>  			rp = rcu_dereference(rp->next);
>  	}

Thanks for catching this!

> --- a/net/bridge/br_multicast.c	2010-04-27 17:51:31.509593914 -0700
> +++ b/net/bridge/br_multicast.c	2010-04-27 17:52:48.209243982 -0700
> @@ -259,7 +259,7 @@ static void br_multicast_del_pg(struct n
>  		if (p != pg)
>  			continue;
>  
> -		*pp = p->next;
> +		rcu_assign_pointer(*pp, p->next);

But this is bogus.  br_multicast_del_pg is removing an entry from
the RCU list.

You only need write barriers when you're putting a new entry in
it, and only if there is no other barrier between the code filling
in the new entry and the line adding it to the RCU list.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net-next 3/4] bridge: multicast port group RCU fix
  2010-04-28  3:07   ` Herbert Xu
@ 2010-04-28  3:47     ` Stephen Hemminger
  0 siblings, 0 replies; 8+ messages in thread
From: Stephen Hemminger @ 2010-04-28  3:47 UTC (permalink / raw)
  To: Herbert Xu; +Cc: David S. Miller, netdev

On Wed, 28 Apr 2010 11:07:09 +0800
Herbert Xu <herbert@gondor.apana.org.au> wrote:

> On Tue, Apr 27, 2010 at 06:01:06PM -0700, Stephen Hemminger wrote:
> > The recently introduced bridge mulitcast port group list was only
> > partially using RCU correctly. It was missing rcu_dereference()
> > and missing the necessary barrier on deletion.
> > 
> > The code should have used one of the standard list methods (list or hlist)
> > instead of open coding a RCU based link list.
> > 
> > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> > 
> > --- a/net/bridge/br_forward.c	2010-04-27 17:51:27.909588950 -0700
> > +++ b/net/bridge/br_forward.c	2010-04-27 17:53:18.790721091 -0700
> > @@ -217,7 +217,7 @@ static void br_multicast_flood(struct ne
> >  	prev = NULL;
> >  
> >  	rp = rcu_dereference(br->router_list.first);
> > -	p = mdst ? mdst->ports : NULL;
> > +	p = mdst ? rcu_dereference(mdst->ports) : NULL;
> >  	while (p || rp) {
> >  		lport = p ? p->port : NULL;
> >  		rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
> > @@ -231,7 +231,7 @@ static void br_multicast_flood(struct ne
> >  			goto out;
> >  
> >  		if ((unsigned long)lport >= (unsigned long)port)
> > -			p = p->next;
> > +			p = rcu_dereference(p->next);
> >  		if ((unsigned long)rport >= (unsigned long)port)
> >  			rp = rcu_dereference(rp->next);
> >  	}
> 
> Thanks for catching this!
> 
> > --- a/net/bridge/br_multicast.c	2010-04-27 17:51:31.509593914 -0700
> > +++ b/net/bridge/br_multicast.c	2010-04-27 17:52:48.209243982 -0700
> > @@ -259,7 +259,7 @@ static void br_multicast_del_pg(struct n
> >  		if (p != pg)
> >  			continue;
> >  
> > -		*pp = p->next;
> > +		rcu_assign_pointer(*pp, p->next);
> 
> But this is bogus.  br_multicast_del_pg is removing an entry from
> the RCU list.
> 
> You only need write barriers when you're putting a new entry in
> it, and only if there is no other barrier between the code filling
> in the new entry and the line adding it to the RCU list.

Yeah, it is extra barrier (one more reason to stick to hlist_del_rcu)




-- 

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-04-28  3:47 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-28  1:01 [PATCH net-next 0/4] Bridge IGMP cleanup and fixes Stephen Hemminger
2010-04-28  1:01 ` [PATCH net-next 1/4] bridge: simplify multicast_add_router Stephen Hemminger
2010-04-28  1:01 ` [PATCH net-next 2/4] bridge: multicast flood Stephen Hemminger
2010-04-28  1:01 ` [PATCH net-next 3/4] bridge: multicast port group RCU fix Stephen Hemminger
2010-04-28  3:07   ` Herbert Xu
2010-04-28  3:47     ` Stephen Hemminger
2010-04-28  1:01 ` [PATCH net-next 4/4] bridge: multicast_flood cleanup Stephen Hemminger
2010-04-28  1:14 ` [PATCH net-next 0/4] Bridge IGMP cleanup and fixes David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).