netdev
[Top] [All Lists]

[PATCH 5/5] [bonding] backport 2.6 changes to 2.4

To: fubar@xxxxxxxxxx, jgarzik@xxxxxxxxx
Subject: [PATCH 5/5] [bonding] backport 2.6 changes to 2.4
From: Amir Noam <amir.noam@xxxxxxxxx>
Date: Wed, 30 Jul 2003 20:07:27 +0300
Cc: bonding-devel@xxxxxxxxxxxxxxxxxxxxx, netdev@xxxxxxxxxxx
Sender: netdev-bounce@xxxxxxxxxxx
User-agent: KMail/1.4.3
Backported from 2.6:
Use a linked list to handle numerous bond devices instead of a static
array.

Also, fix handling of errors in bonding_init(): gracefully unregister
and deallocate all previously created bond devices.

Amir

diff -Nuarp linux-2.4.22-pre9/drivers/net/bonding/bond_main.c 
linux-2.4.22-pre9-devel/drivers/net/bonding/bond_main.c
--- linux-2.4.22-pre9/drivers/net/bonding/bond_main.c   Wed Jul 30 19:14:10 2003
+++ linux-2.4.22-pre9-devel/drivers/net/bonding/bond_main.c     Wed Jul 30 
19:14:11 2003
@@ -515,9 +515,7 @@ static struct bond_parm_tbl bond_lacp_tb
 {      NULL,           -1},
 };
 
-static int first_pass  = 1;
-static struct bonding *these_bonds =  NULL;
-static struct net_device *dev_bonds = NULL;
+static LIST_HEAD(bond_dev_list);
 
 MODULE_PARM(max_bonds, "i");
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
@@ -3495,47 +3493,13 @@ static int bond_read_proc(char *buf, cha
 static int bond_event(struct notifier_block *this, unsigned long event, 
                        void *ptr)
 {
-       struct bonding *this_bond = (struct bonding *)these_bonds;
-       struct bonding *last_bond;
        struct net_device *event_dev = (struct net_device *)ptr;
+       struct net_device *master = event_dev->master;
 
-       /* while there are bonds configured */
-       while (this_bond != NULL) {
-               if (this_bond == event_dev->priv ) {
-                       switch (event) {
-                       case NETDEV_UNREGISTER:
-                               /* 
-                                * remove this bond from a linked list of 
-                                * bonds 
-                                */
-                               if (this_bond == these_bonds) {
-                                       these_bonds = this_bond->next_bond;
-                               } else {
-                                       for (last_bond = these_bonds; 
-                                            last_bond != NULL; 
-                                            last_bond = last_bond->next_bond) {
-                                               if (last_bond->next_bond == 
-                                                   this_bond) {
-                                                       last_bond->next_bond = 
-                                                       this_bond->next_bond;
-                                               }
-                                       }
-                               }
-                               return NOTIFY_DONE;
-
-                       default:
-                               return NOTIFY_DONE;
-                       }
-               } else if (this_bond->device == event_dev->master) {
-                       switch (event) {
-                       case NETDEV_UNREGISTER:
-                               bond_release(this_bond->device, event_dev);
-                               break;
-                       }
-                       return NOTIFY_DONE;
-               }
-               this_bond = this_bond->next_bond;
+       if ((event == NETDEV_UNREGISTER) && (master != NULL)) {
+               bond_release(master, event_dev);
        }
+
        return NOTIFY_DONE;
 }
 
@@ -3543,19 +3507,40 @@ static struct notifier_block bond_netdev
        notifier_call: bond_event,
 };
 
+static void bond_deinit(struct net_device *dev)
+{
+       struct bonding *bond = dev->priv;
+
+       list_del(&bond->bond_list);
+
+#ifdef CONFIG_PROC_FS
+       remove_proc_entry("info", bond->bond_proc_dir);
+       remove_proc_entry(dev->name, proc_net);
+#endif
+}
+
+static void bond_free_all(void)
+{
+       struct bonding *bond, *nxt;
+
+       list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
+               struct net_device *dev = bond->device;
+
+               bond_deinit(dev);
+               unregister_netdev(dev);
+               kfree(dev);
+       }
+}
+
 static int __init bond_init(struct net_device *dev)
 {
-       bonding_t *bond, *this_bond, *last_bond;
+       struct bonding *bond;
        int count;
 
 #ifdef BONDING_DEBUG
        printk (KERN_INFO "Begin bond_init for %s\n", dev->name);
 #endif
-       bond = kmalloc(sizeof(struct bonding), GFP_KERNEL);
-       if (bond == NULL) {
-               return -ENOMEM;
-       }
-       memset(bond, 0, sizeof(struct bonding));
+       bond = dev->priv;
 
        /* initialize rwlocks */
        rwlock_init(&bond->lock);
@@ -3565,7 +3550,6 @@ static int __init bond_init(struct net_d
        bond->current_slave = NULL;
        bond->current_arp_slave = NULL;
        bond->device = dev;
-       dev->priv = bond;
 
        /* Initialize the device structure. */
        switch (bond_mode) {
@@ -3590,7 +3574,6 @@ static int __init bond_init(struct net_d
                break;
        default:
                printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode);
-               kfree(bond);
                return -EINVAL;
        }
 
@@ -3599,14 +3582,6 @@ static int __init bond_init(struct net_d
        dev->stop = bond_close;
        dev->set_multicast_list = set_multicast_list;
        dev->do_ioctl = bond_ioctl;
-
-       /* 
-        * Fill in the fields of the device structure with ethernet-generic 
-        * values. 
-        */
-
-       ether_setup(dev);
-
        dev->set_mac_address = bond_set_mac_address;
        dev->tx_queue_len = 0;
        dev->flags |= IFF_MASTER|IFF_MULTICAST;
@@ -3640,7 +3615,6 @@ static int __init bond_init(struct net_d
        if (bond->bond_proc_dir == NULL) {
                printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n", 
                        dev->name, dev->name);
-               kfree(bond);
                return -ENOMEM;
        }
        bond->bond_proc_dir->owner = THIS_MODULE;
@@ -3652,25 +3626,12 @@ static int __init bond_init(struct net_d
                printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n", 
                        dev->name, dev->name);
                remove_proc_entry(dev->name, proc_net);
-               kfree(bond);
                return -ENOMEM;
        }
        bond->bond_proc_info_file->owner = THIS_MODULE;
 #endif /* CONFIG_PROC_FS */
 
-       if (first_pass == 1) {
-               these_bonds = bond;
-               register_netdevice_notifier(&bond_netdev_notifier);
-               first_pass = 0;
-       } else {
-               last_bond = these_bonds;
-               this_bond = these_bonds->next_bond;
-               while (this_bond != NULL) {
-                       last_bond = this_bond;
-                       this_bond = this_bond->next_bond;
-               }
-               last_bond->next_bond = bond;
-       } 
+       list_add_tail(&bond->bond_list, &bond_dev_list);
 
        return 0;
 }
@@ -3710,9 +3671,6 @@ static int __init bonding_init(void)
        int no;
        int err;
 
-       /* Find a name for this unit */
-       static struct net_device *dev_bond = NULL;
-
        printk(KERN_INFO "%s", version);
 
        /*
@@ -3763,12 +3721,6 @@ static int __init bonding_init(void)
                       max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS);
                max_bonds = BOND_DEFAULT_MAX_BONDS;
        }
-       dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), 
-                                       GFP_KERNEL);
-       if (dev_bond == NULL) {
-               return -ENOMEM;
-       }
-       memset(dev_bonds, 0, max_bonds*sizeof(struct net_device));
 
        if (miimon < 0) {
                printk(KERN_WARNING 
@@ -3959,47 +3911,62 @@ static int __init bonding_init(void)
                primary = NULL;
        }
 
+       rtnl_lock();
 
+       err = 0;
        for (no = 0; no < max_bonds; no++) {
-               dev_bond->init = bond_init;
-       
-               err = dev_alloc_name(dev_bond,"bond%d");
+               struct net_device *dev;
+
+               dev = alloc_netdev(sizeof(struct bonding), "", ether_setup);
+               if (!dev) {
+                       err = -ENOMEM;
+                       goto out_err;
+               }
+
+               err = dev_alloc_name(dev, "bond%d");
+               if (err < 0) {
+                       kfree(dev);
+                       goto out_err;
+               }
+
+               /* bond_init() must be called after alloc_net_dev() (for the
+                * /proc files), but before register_netdevice(), because we
+                * need to set function pointers.
+                */
+               err = bond_init(dev);
+               if (err < 0) {
+                       kfree(dev);
+                       goto out_err;
+               }
+
+               SET_MODULE_OWNER(dev);
+
+               err = register_netdevice(dev);
                if (err < 0) {
-                       kfree(dev_bonds);
-                       return err;
+                       bond_deinit(dev);
+                       kfree(dev);
+                       goto out_err;
                }
-               SET_MODULE_OWNER(dev_bond);
-               if (register_netdev(dev_bond) != 0) {
-                       kfree(dev_bonds);
-                       return -EIO;
-               }       
-               dev_bond++;
        }
+
+       rtnl_unlock();
+       register_netdevice_notifier(&bond_netdev_notifier);
+
        return 0;
+
+out_err:
+       rtnl_unlock();
+
+       /* free and unregister all bonds that were successfully added */
+       bond_free_all();
+
+       return err;
 }
 
 static void __exit bonding_exit(void)
 {
-       struct net_device *dev_bond = dev_bonds;
-       struct bonding *bond;
-       int no;
-
        unregister_netdevice_notifier(&bond_netdev_notifier);
-                
-       for (no = 0; no < max_bonds; no++) {
-
-#ifdef CONFIG_PROC_FS
-               bond = (struct bonding *) dev_bond->priv;
-               remove_proc_entry("info", bond->bond_proc_dir);
-               remove_proc_entry(dev_bond->name, proc_net);
-#endif
-               unregister_netdev(dev_bond);
-               kfree(dev_bond->priv);
-
-               dev_bond->priv = NULL;
-               dev_bond++;
-       }
-       kfree(dev_bonds);
+       bond_free_all();
 }
 
 module_init(bonding_init);
diff -Nuarp linux-2.4.22-pre9/drivers/net/bonding/bonding.h 
linux-2.4.22-pre9-devel/drivers/net/bonding/bonding.h
--- linux-2.4.22-pre9/drivers/net/bonding/bonding.h     Wed Jul 30 19:14:10 2003
+++ linux-2.4.22-pre9-devel/drivers/net/bonding/bonding.h       Wed Jul 30 
19:14:11 2003
@@ -104,7 +104,7 @@ typedef struct bonding {
        struct proc_dir_entry *bond_proc_dir;
        struct proc_dir_entry *bond_proc_info_file;
 #endif /* CONFIG_PROC_FS */
-       struct bonding *next_bond;
+       struct list_head bond_list;
        struct net_device *device;
        struct dev_mc_list *mc_list;
        unsigned short flags;


<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH 5/5] [bonding] backport 2.6 changes to 2.4, Amir Noam <=