]> Pileus Git - ~andy/linux/commitdiff
bridge: multicast port group RCU fix
authorstephen hemminger <shemminger@vyatta.com>
Tue, 27 Apr 2010 15:01:06 +0000 (15:01 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 28 Apr 2010 01:13:54 +0000 (18:13 -0700)
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>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/bridge/br_forward.c
net/bridge/br_multicast.c

index 5b70fc012e40059a8760bb892e62fdeeacdf62c8..5f9988a3f06a62359dfd3cb4bbef43cfe55d836c 100644 (file)
@@ -217,7 +217,7 @@ static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
        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 net_bridge_mdb_entry *mdst,
                        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);
        }
index d63868c9b2c074ab52488affba9f1e067e993279..7128abdce45f1a60546ea970505e9b772af04cc5 100644 (file)
@@ -259,7 +259,7 @@ static void br_multicast_del_pg(struct net_bridge *br,
                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);