Commit a9e4c8a9 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

[NET]: Use alloc_netdev in bonding driver.

parent 2ca95755
...@@ -497,9 +497,7 @@ static struct bond_parm_tbl bond_lacp_tbl[] = { ...@@ -497,9 +497,7 @@ static struct bond_parm_tbl bond_lacp_tbl[] = {
{ NULL, -1}, { NULL, -1},
}; };
static int first_pass = 1; static LIST_HEAD(bond_dev_list);
static struct bonding *these_bonds = NULL;
static struct net_device *dev_bonds = NULL;
MODULE_PARM(max_bonds, "i"); MODULE_PARM(max_bonds, "i");
MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
...@@ -3408,7 +3406,7 @@ static struct net_device_stats *bond_get_stats(struct net_device *dev) ...@@ -3408,7 +3406,7 @@ static struct net_device_stats *bond_get_stats(struct net_device *dev)
static int bond_get_info(char *buf, char **start, off_t offset, int length) static int bond_get_info(char *buf, char **start, off_t offset, int length)
{ {
bonding_t *bond = these_bonds; bonding_t *bond;
int len = 0; int len = 0;
off_t begin = 0; off_t begin = 0;
u16 link; u16 link;
...@@ -3416,7 +3414,8 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) ...@@ -3416,7 +3414,8 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length)
len += sprintf(buf + len, "%s\n", version); len += sprintf(buf + len, "%s\n", version);
while (bond != NULL) { read_lock(&dev_base_lock);
list_for_each_entry(bond, &bond_dev_list, bond_list) {
/* /*
* This function locks the mutex, so we can't lock it until * This function locks the mutex, so we can't lock it until
* afterwards * afterwards
...@@ -3526,93 +3525,48 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length) ...@@ -3526,93 +3525,48 @@ static int bond_get_info(char *buf, char **start, off_t offset, int length)
len = 0; len = 0;
} }
bond = bond->next_bond;
} }
read_unlock(&dev_base_lock);
return len; return len;
} }
static int bond_event(struct notifier_block *this, unsigned long event, static int bond_event(struct notifier_block *this, unsigned long event,
void *ptr) 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 *event_dev = (struct net_device *)ptr;
struct net_device *master = event_dev->master;
/* while there are bonds configured */ if (event == NETDEV_UNREGISTER && master != NULL)
while (this_bond != NULL) { bond_release(master, event_dev);
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;
}
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static struct notifier_block bond_netdev_notifier = { static struct notifier_block bond_netdev_notifier = {
notifier_call: bond_event, .notifier_call = bond_event,
}; };
static int __init bond_init(struct net_device *dev) static int __init bond_init(struct net_device *dev)
{ {
bonding_t *bond, *this_bond, *last_bond; bonding_t *bond;
int count; int count;
#ifdef BONDING_DEBUG #ifdef BONDING_DEBUG
printk (KERN_INFO "Begin bond_init for %s\n", dev->name); printk (KERN_INFO "Begin bond_init for %s\n", dev->name);
#endif #endif
bond = kmalloc(sizeof(struct bonding), GFP_KERNEL); bond = dev->priv;
if (bond == NULL) {
return -ENOMEM;
}
memset(bond, 0, sizeof(struct bonding));
/* initialize rwlocks */ /* initialize rwlocks */
rwlock_init(&bond->lock); rwlock_init(&bond->lock);
rwlock_init(&bond->ptrlock); rwlock_init(&bond->ptrlock);
bond->stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); /* space is reserved for stats in alloc_netdev call. */
if (bond->stats == NULL) { bond->stats = (struct net_device_stats *)(bond + 1);
kfree(bond);
return -ENOMEM;
}
memset(bond->stats, 0, sizeof(struct net_device_stats));
bond->next = bond->prev = (slave_t *)bond; bond->next = bond->prev = (slave_t *)bond;
bond->current_slave = NULL; bond->current_slave = NULL;
bond->current_arp_slave = NULL; bond->current_arp_slave = NULL;
bond->device = dev; bond->device = dev;
dev->priv = bond;
/* Initialize the device structure. */ /* Initialize the device structure. */
switch (bond_mode) { switch (bond_mode) {
...@@ -3637,8 +3591,6 @@ static int __init bond_init(struct net_device *dev) ...@@ -3637,8 +3591,6 @@ static int __init bond_init(struct net_device *dev)
break; break;
default: default:
printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode);
kfree(bond->stats);
kfree(bond);
return -EINVAL; return -EINVAL;
} }
...@@ -3648,13 +3600,6 @@ static int __init bond_init(struct net_device *dev) ...@@ -3648,13 +3600,6 @@ static int __init bond_init(struct net_device *dev)
dev->set_multicast_list = set_multicast_list; dev->set_multicast_list = set_multicast_list;
dev->do_ioctl = bond_ioctl; dev->do_ioctl = bond_ioctl;
/*
* Fill in the fields of the device structure with ethernet-generic
* values.
*/
ether_setup(dev);
dev->tx_queue_len = 0; dev->tx_queue_len = 0;
dev->flags |= IFF_MASTER|IFF_MULTICAST; dev->flags |= IFF_MASTER|IFF_MULTICAST;
#ifdef CONFIG_NET_FASTROUTE #ifdef CONFIG_NET_FASTROUTE
...@@ -3687,8 +3632,6 @@ static int __init bond_init(struct net_device *dev) ...@@ -3687,8 +3632,6 @@ static int __init bond_init(struct net_device *dev)
if (bond->bond_proc_dir == NULL) { if (bond->bond_proc_dir == NULL) {
printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n", printk(KERN_ERR "%s: Cannot init /proc/net/%s/\n",
dev->name, dev->name); dev->name, dev->name);
kfree(bond->stats);
kfree(bond);
return -ENOMEM; return -ENOMEM;
} }
bond->bond_proc_dir->owner = THIS_MODULE; bond->bond_proc_dir->owner = THIS_MODULE;
...@@ -3700,27 +3643,13 @@ static int __init bond_init(struct net_device *dev) ...@@ -3700,27 +3643,13 @@ static int __init bond_init(struct net_device *dev)
printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n", printk(KERN_ERR "%s: Cannot init /proc/net/%s/info\n",
dev->name, dev->name); dev->name, dev->name);
remove_proc_entry(dev->name, proc_net); remove_proc_entry(dev->name, proc_net);
kfree(bond->stats);
kfree(bond);
return -ENOMEM; return -ENOMEM;
} }
bond->bond_proc_info_file->owner = THIS_MODULE; bond->bond_proc_info_file->owner = THIS_MODULE;
#endif /* CONFIG_PROC_FS */ #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; return 0;
} }
...@@ -3753,15 +3682,11 @@ bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) ...@@ -3753,15 +3682,11 @@ bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl)
return -1; return -1;
} }
static int __init bonding_init(void) static int __init bonding_init(void)
{ {
int no; int no;
int err; int err;
/* Find a name for this unit */
static struct net_device *dev_bond = NULL;
printk(KERN_INFO "%s", version); printk(KERN_INFO "%s", version);
/* /*
...@@ -3812,12 +3737,6 @@ static int __init bonding_init(void) ...@@ -3812,12 +3737,6 @@ static int __init bonding_init(void)
max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS);
max_bonds = 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) { if (miimon < 0) {
printk(KERN_WARNING printk(KERN_WARNING
...@@ -4005,48 +3924,50 @@ static int __init bonding_init(void) ...@@ -4005,48 +3924,50 @@ static int __init bonding_init(void)
primary = NULL; primary = NULL;
} }
register_netdevice_notifier(&bond_netdev_notifier);
for (no = 0; no < max_bonds; no++) { for (no = 0; no < max_bonds; no++) {
dev_bond->init = bond_init; struct net_device *dev;
char name[IFNAMSIZ];
err = dev_alloc_name(dev_bond,"bond%d");
if (err < 0) { snprintf(name, IFNAMSIZ, "bond%d", no);
kfree(dev_bonds);
dev = alloc_netdev(sizeof(bonding_t)
+ sizeof(struct net_device_stats),
name, ether_setup);
if (!dev)
return -ENOMEM;
dev->init = bond_init;
SET_MODULE_OWNER(dev);
if ( (err = register_netdev(dev)) ) {
#ifdef BONDING_DEBUG
printk(KERN_INFO "%s: register_netdev failed %d\n",
dev->name, err);
#endif
kfree(dev);
return err; return err;
}
SET_MODULE_OWNER(dev_bond);
if (register_netdev(dev_bond) != 0) {
kfree(dev_bonds);
return -EIO;
} }
dev_bond++;
} }
return 0; return 0;
} }
static void __exit bonding_exit(void) static void __exit bonding_exit(void)
{ {
struct net_device *dev_bond = dev_bonds; struct bonding *bond, *nxt;
struct bonding *bond;
int no;
unregister_netdevice_notifier(&bond_netdev_notifier); unregister_netdevice_notifier(&bond_netdev_notifier);
for (no = 0; no < max_bonds; no++) { list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
struct net_device *dev = bond->device;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
bond = (struct bonding *) dev_bond->priv;
remove_proc_entry("info", bond->bond_proc_dir); remove_proc_entry("info", bond->bond_proc_dir);
remove_proc_entry(dev_bond->name, proc_net); remove_proc_entry(dev->name, proc_net);
#endif #endif
unregister_netdev(dev_bond); unregister_netdev(dev);
kfree(bond->stats); kfree(dev);
kfree(dev_bond->priv);
dev_bond->priv = NULL;
dev_bond++;
} }
kfree(dev_bonds);
} }
module_init(bonding_init); module_init(bonding_init);
......
...@@ -104,7 +104,7 @@ typedef struct bonding { ...@@ -104,7 +104,7 @@ typedef struct bonding {
struct proc_dir_entry *bond_proc_dir; struct proc_dir_entry *bond_proc_dir;
struct proc_dir_entry *bond_proc_info_file; struct proc_dir_entry *bond_proc_info_file;
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
struct bonding *next_bond; struct list_head bond_list;
struct net_device *device; struct net_device *device;
struct dev_mc_list *mc_list; struct dev_mc_list *mc_list;
unsigned short flags; unsigned short flags;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment