Commit efb377f6 authored by Stephen Hemminger's avatar Stephen Hemminger

[PATCH] (3/4) dlci locking and registration changes

Change the locking for the dlci device list and registration.
- use RTNL instead of a private lock (needed for net notifier in next patch).
- reorder the checks in the dlci_add to avoid complicated unwinds
- use dev->destructor to free
- hold RTNL around deassoc to protect callback from races
parent 344332f5
...@@ -58,7 +58,6 @@ ...@@ -58,7 +58,6 @@
static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org"; static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org";
static LIST_HEAD(dlci_devs); static LIST_HEAD(dlci_devs);
static spinlock_t dlci_dev_lock = SPIN_LOCK_UNLOCKED;
static void dlci_setup(struct net_device *); static void dlci_setup(struct net_device *);
...@@ -360,34 +359,38 @@ static int dlci_add(struct dlci_add *dlci) ...@@ -360,34 +359,38 @@ static int dlci_add(struct dlci_add *dlci)
struct net_device *master, *slave; struct net_device *master, *slave;
struct dlci_local *dlp; struct dlci_local *dlp;
struct frad_local *flp; struct frad_local *flp;
int err; int err = -EINVAL;
/* validate slave device */ /* validate slave device */
slave = dev_get_by_name(dlci->devname); slave = dev_get_by_name(dlci->devname);
if (!slave) if (!slave)
return(-ENODEV); return -ENODEV;
if (slave->type != ARPHRD_FRAD) { if (slave->type != ARPHRD_FRAD || slave->priv == NULL)
dev_put(slave); goto err1;
return(-EINVAL);
}
/* create device name */ /* create device name */
master = alloc_netdev( sizeof(struct dlci_local), "dlci%d", master = alloc_netdev( sizeof(struct dlci_local), "dlci%d",
dlci_setup); dlci_setup);
if (!master) { if (!master) {
dev_put(slave); err = -ENOMEM;
return(-ENOMEM); goto err1;
} }
err = register_netdev(master); /* make sure same slave not already registered */
if (err < 0) { rtnl_lock();
dev_put(slave); list_for_each_entry(dlp, &dlci_devs, list) {
kfree(master); if (dlp->slave == slave) {
return(err); err = -EBUSY;
goto err2;
}
} }
err = dev_alloc_name(master, master->name);
if (err < 0)
goto err2;
*(short *)(master->dev_addr) = dlci->dlci; *(short *)(master->dev_addr) = dlci->dlci;
dlp = (struct dlci_local *) master->priv; dlp = (struct dlci_local *) master->priv;
...@@ -395,22 +398,27 @@ static int dlci_add(struct dlci_add *dlci) ...@@ -395,22 +398,27 @@ static int dlci_add(struct dlci_add *dlci)
dlp->master = master; dlp->master = master;
flp = slave->priv; flp = slave->priv;
err = flp ? (*flp->assoc)(slave, master) : -EINVAL; err = (*flp->assoc)(slave, master);
if (err < 0) if (err < 0)
{ goto err2;
unregister_netdev(master);
dev_put(slave); err = register_netdevice(master);
free_netdev(master); if (err < 0)
return(err); goto err2;
}
strcpy(dlci->devname, master->name); strcpy(dlci->devname, master->name);
spin_lock_bh(&dlci_dev_lock);
list_add(&dlp->list, &dlci_devs); list_add(&dlp->list, &dlci_devs);
spin_unlock_bh(&dlci_dev_lock); rtnl_unlock();
return(0); return(0);
err2:
rtnl_unlock();
kfree(master);
err1:
dev_put(slave);
return(err);
} }
static int dlci_del(struct dlci_add *dlci) static int dlci_del(struct dlci_add *dlci)
...@@ -433,21 +441,18 @@ static int dlci_del(struct dlci_add *dlci) ...@@ -433,21 +441,18 @@ static int dlci_del(struct dlci_add *dlci)
slave = dlp->slave; slave = dlp->slave;
flp = slave->priv; flp = slave->priv;
rtnl_lock();
err = (*flp->deassoc)(slave, master); err = (*flp->deassoc)(slave, master);
if (err) if (!err) {
return(err);
spin_lock_bh(&dlci_dev_lock);
list_del(&dlp->list); list_del(&dlp->list);
spin_unlock_bh(&dlci_dev_lock);
unregister_netdev(master); unregister_netdevice(master);
dev_put(slave); dev_put(slave);
free_netdev(master); }
rtnl_unlock();
return(0); return(err);
} }
static int dlci_ioctl(unsigned int cmd, void *arg) static int dlci_ioctl(unsigned int cmd, void *arg)
...@@ -494,6 +499,7 @@ static void dlci_setup(struct net_device *dev) ...@@ -494,6 +499,7 @@ static void dlci_setup(struct net_device *dev)
dev->hard_header = dlci_header; dev->hard_header = dlci_header;
dev->get_stats = dlci_get_stats; dev->get_stats = dlci_get_stats;
dev->change_mtu = dlci_change_mtu; dev->change_mtu = dlci_change_mtu;
dev->destructor = free_netdev;
dlp->receive = dlci_receive; dlp->receive = dlci_receive;
...@@ -518,12 +524,12 @@ void __exit dlci_exit(void) ...@@ -518,12 +524,12 @@ void __exit dlci_exit(void)
dlci_ioctl_set(NULL); dlci_ioctl_set(NULL);
rtnl_lock();
list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) { list_for_each_entry_safe(dlp, nxt, &dlci_devs, list) {
unregister_netdev(dlp->master); unregister_netdevice(dlp->master);
dev_put(dlp->slave); dev_put(dlp->slave);
free_netdev(dlp->master);
} }
rtnl_unlock();
} }
module_init(init_dlci); module_init(init_dlci);
......
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