The problem was that the br_add_bridge ended up calling register_netdev
that did a rtnl_lock.  This fixes that, and gets rid of the bridge_list,
there is no need to keep a separate device list of just bridges.  By not
having multiple lists, races are avoided. 

Signed-off-by: Stephen Hemminger <[EMAIL PROTECTED]>


diff -urNp -X dontdiff linux-2.4/net/bridge/br_if.c bridge-2.4/net/bridge/br_if.c
--- linux-2.4/net/bridge/br_if.c        2004-08-02 10:22:45.331010728 -0700
+++ bridge-2.4/net/bridge/br_if.c       2004-08-02 12:57:58.405208248 -0700
@@ -23,8 +23,6 @@
 #include <asm/uaccess.h>
 #include "br_private.h"
 
-static struct net_bridge *bridge_list;
-
 static int br_initial_port_cost(struct net_device *dev)
 {
        if (!strncmp(dev->name, "lec", 3))
@@ -70,22 +68,6 @@ static int __br_del_if(struct net_bridge
        return 0;
 }
 
-static struct net_bridge **__find_br(char *name)
-{
-       struct net_bridge **b;
-       struct net_bridge *br;
-
-       b = &bridge_list;
-       while ((br = *b) != NULL) {
-               if (!strncmp(br->dev.name, name, IFNAMSIZ))
-                       return b;
-
-               b = &(br->next);
-       }
-
-       return NULL;
-}
-
 static void del_ifs(struct net_bridge *br)
 {
        br_write_lock_bh(BR_NETPROTO_LOCK);
@@ -178,42 +160,48 @@ static struct net_bridge_port *new_nbp(s
 int br_add_bridge(char *name)
 {
        struct net_bridge *br;
+       struct net_device *dev;
+       int err;
 
        if ((br = new_nb(name)) == NULL)
                return -ENOMEM;
 
-       if (__dev_get_by_name(name) != NULL) {
-               kfree(br);
-               return -EEXIST;
+       dev = &br->dev;
+       if (strchr(dev->name, '%')) {
+               err = dev_alloc_name(dev, dev->name);
+               if (err < 0)
+                       goto  out;
        }
 
-       br->next = bridge_list;
-       bridge_list = br;
+       err = register_netdevice(dev);
+       if (err == 0)
+               br_inc_use_count();
 
-       br_inc_use_count();
-       register_netdev(&br->dev);
-
-       return 0;
+ out:
+       return err;
 }
 
 int br_del_bridge(char *name)
 {
-       struct net_bridge **b;
+       struct net_device *dev;
        struct net_bridge *br;
 
-       if ((b = __find_br(name)) == NULL)
+       dev = __dev_get_by_name(name);
+       if (!dev)
                return -ENXIO;
 
-       br = *b;
+       if (dev->hard_start_xmit != br_dev_xmit)
+               return -EPERM;
 
-       if (br->dev.flags & IFF_UP)
+       if (dev->flags & IFF_UP)
                return -EBUSY;
 
-       del_ifs(br);
+       br = dev->priv;
+       BUG_ON(&br->dev != dev);
 
-       *b = br->next;
+       del_ifs(br);
 
-       unregister_netdev(&br->dev);
+       unregister_netdevice(dev);
        kfree(br);
        br_dec_use_count();
 
@@ -271,16 +259,12 @@ int br_del_if(struct net_bridge *br, str
 
 int br_get_bridge_ifindices(int *indices, int num)
 {
-       struct net_bridge *br;
-       int i;
-
-       br = bridge_list;
-       for (i=0;i<num;i++) {
-               if (br == NULL)
-                       break;
+       struct net_device *dev;
+       int i = 0;
 
-               indices[i] = br->dev.ifindex;
-               br = br->next;
+       for (dev = dev_base; i < num && dev != NULL; dev = dev->next) {
+               if (dev->hard_start_xmit == br_dev_xmit)
+                       indices[i++] = dev->ifindex;
        }
 
        return i;
diff -urNp -X dontdiff linux-2.4/net/bridge/br_ioctl.c bridge-2.4/net/bridge/br_ioctl.c
--- linux-2.4/net/bridge/br_ioctl.c     2004-08-02 10:22:45.332010576 -0700
+++ bridge-2.4/net/bridge/br_ioctl.c    2004-08-02 12:57:58.407207944 -0700
@@ -250,14 +250,9 @@ int br_ioctl_deviceless_stub(unsigned lo
 
 int br_ioctl(struct net_bridge *br, unsigned int cmd, unsigned long arg0, unsigned 
long arg1, unsigned long arg2)
 {
-       int err;
-
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
        ASSERT_RTNL();
-       err = br_ioctl_deviceless(cmd, arg0, arg1);
-       if (err == -EOPNOTSUPP)
-               err = br_ioctl_device(br, cmd, arg0, arg1, arg2);
-       return err;
+       return br_ioctl_device(br, cmd, arg0, arg1, arg2);
 }
diff -urNp -X dontdiff linux-2.4/net/bridge/br_private.h 
bridge-2.4/net/bridge/br_private.h
--- linux-2.4/net/bridge/br_private.h   2004-08-02 10:22:45.333010424 -0700
+++ bridge-2.4/net/bridge/br_private.h  2004-08-02 10:39:09.582381776 -0700
@@ -79,7 +79,6 @@ struct net_bridge_port
 
 struct net_bridge
 {
-       struct net_bridge               *next;
        rwlock_t                        lock;
        struct net_bridge_port          *port_list;
        struct net_device               dev;
_______________________________________________
Bridge mailing list
[EMAIL PROTECTED]
http://lists.osdl.org/mailman/listinfo/bridge

Reply via email to