diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c index e829e6c..47c0d7d 100644 --- a/drivers/dahdi/dahdi-base.c +++ b/drivers/dahdi/dahdi-base.c @@ -121,7 +121,6 @@ EXPORT_SYMBOL(dahdi_qevent_nolock); EXPORT_SYMBOL(dahdi_qevent_lock); EXPORT_SYMBOL(dahdi_hooksig); EXPORT_SYMBOL(dahdi_alarm_notify); -EXPORT_SYMBOL(dahdi_set_dynamic_ioctl); EXPORT_SYMBOL(dahdi_hdlc_abort); EXPORT_SYMBOL(dahdi_hdlc_finish); EXPORT_SYMBOL(dahdi_hdlc_getbuf); @@ -4406,11 +4405,15 @@ static int dahdi_common_ioctl(struct file *file, unsigned int cmd, } static int (*dahdi_dynamic_ioctl)(unsigned int cmd, unsigned long data); +static struct module *dahdi_dynamic_owner; -void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data)) +void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data), + struct module *owner) { dahdi_dynamic_ioctl = func; + dahdi_dynamic_owner = owner; } +EXPORT_SYMBOL(dahdi_set_dynamic_ioctl); static int (*dahdi_hpec_ioctl)(unsigned int cmd, unsigned long data); @@ -5132,6 +5135,7 @@ static int dahdi_ioctl_maint(unsigned long data) static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long data) { + int res; switch (cmd) { case DAHDI_INDIRECT: return dahdi_ioctl_indirect(file, data); @@ -5164,11 +5168,20 @@ dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long data) case DAHDI_DYNAMIC_CREATE: case DAHDI_DYNAMIC_DESTROY: if (dahdi_dynamic_ioctl) { - return dahdi_dynamic_ioctl(cmd, data); + if (!try_module_get(dahdi_dynamic_owner)) + return -ENOSYS; + res = dahdi_dynamic_ioctl(cmd, data); + module_put(dahdi_dynamic_owner); + return res; } else { request_module("dahdi_dynamic"); - if (dahdi_dynamic_ioctl) - return dahdi_dynamic_ioctl(cmd, data); + if (dahdi_dynamic_ioctl) { + if (!try_module_get(dahdi_dynamic_owner)) + return -ENOSYS; + res = dahdi_dynamic_ioctl(cmd, data); + module_put(dahdi_dynamic_owner); + return res; + } } return -ENOSYS; case DAHDI_EC_LICENSE_CHALLENGE: diff --git a/drivers/dahdi/dahdi_dynamic.c b/drivers/dahdi/dahdi_dynamic.c index 79c8bba..fc720ca 100644 --- a/drivers/dahdi/dahdi_dynamic.c +++ b/drivers/dahdi/dahdi_dynamic.c @@ -385,16 +385,6 @@ static void dahdi_dynamic_release(struct kref *kref) WARN_ON(test_bit(DAHDI_FLAGBIT_REGISTERED, &d->span.flags)); - if (d->pvt) { - if (d->driver && d->driver->destroy) { - __module_get(d->driver->owner); - d->driver->destroy(d); - module_put(d->driver->owner); - } else { - WARN_ON(1); - } - } - kfree(d->msgbuf); for (x = 0; x < d->span.channels; x++) @@ -464,6 +454,24 @@ static int _destroy_dynamic(struct dahdi_dynamic_span *dds) dynamic_put(d); return -EBUSY; } + + if (d->pvt) { + if (d->driver && d->driver->destroy) { + if (!try_module_get(d->driver->owner)) { + /* The driver for this device is in the + * process of unloading. Leave this dynamic on + * the list so it's cleaned up when the driver + * unregisters. */ + dynamic_put(d); + return -ENXIO; + } + d->driver->destroy(d); + module_put(d->driver->owner); + } else { + WARN_ON(1); + } + d->pvt = NULL; + } dahdi_unregister_device(d->ddev); @@ -762,19 +770,17 @@ void dahdi_dynamic_unregister_driver(struct dahdi_dynamic_driver *dri) list_for_each_entry_safe(d, n, &dspan_list, list) { if (d->driver == dri) { if (d->pvt) { - if (d->driver && d->driver->destroy) { - __module_get(d->driver->owner); + if (d->driver && d->driver->destroy) d->driver->destroy(d); - module_put(d->driver->owner); - } else { + else WARN_ON(1); - } } dahdi_unregister_device(d->ddev); spin_lock_irqsave(&dspan_lock, flags); list_del_rcu(&d->list); spin_unlock_irqrestore(&dspan_lock, flags); synchronize_rcu(); + d->driver = NULL; dynamic_put(d); } } @@ -820,7 +826,7 @@ static void check_for_red_alarm(unsigned long ignored) static int dahdi_dynamic_init(void) { - dahdi_set_dynamic_ioctl(dahdi_dynamic_ioctl); + dahdi_set_dynamic_ioctl(dahdi_dynamic_ioctl, THIS_MODULE); /* Start process to check for RED ALARM */ init_timer(&alarmcheck); @@ -844,7 +850,7 @@ static void dahdi_dynamic_cleanup(void) tasklet_kill(&dahdi_dynamic_tlet); } #endif - dahdi_set_dynamic_ioctl(NULL); + dahdi_set_dynamic_ioctl(NULL, NULL); del_timer(&alarmcheck); printk(KERN_INFO "DAHDI Dynamic Span support unloaded\n"); } diff --git a/drivers/dahdi/dahdi_dynamic_eth.c b/drivers/dahdi/dahdi_dynamic_eth.c index 5ad0484..fd3a8cd 100644 --- a/drivers/dahdi/dahdi_dynamic_eth.c +++ b/drivers/dahdi/dahdi_dynamic_eth.c @@ -146,7 +146,7 @@ static void ztdeth_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen) spin_lock_irqsave(&zlock, flags); z = dyn->pvt; - if (z->dev) { + if (z && z->dev) { /* Copy fields to local variables to remove spinlock ASAP */ dev = z->dev; memcpy(addr, z->addr, sizeof(z->addr)); @@ -307,11 +307,12 @@ static void ztdeth_destroy(struct dahdi_dynamic *dyn) prev = cur; cur = cur->next; } - spin_unlock_irqrestore(&zlock, flags); if (cur == z) { /* Successfully removed */ + dyn->pvt = NULL; printk(KERN_INFO "TDMoE: Removed interface for %s\n", z->span->name); kfree(z); } + spin_unlock_irqrestore(&zlock, flags); } static int ztdeth_create(struct dahdi_dynamic *dyn, const char *addr) @@ -434,12 +435,12 @@ static struct notifier_block ztdeth_nblock = { static int __init ztdeth_init(void) { + skb_queue_head_init(&skbs); + dev_add_pack(&ztdeth_ptype); register_netdevice_notifier(&ztdeth_nblock); dahdi_dynamic_register_driver(&ztd_eth); - skb_queue_head_init(&skbs); - return 0; } @@ -450,9 +451,11 @@ static void __exit ztdeth_exit(void) #else cancel_work_sync(&dahdi_dynamic_eth_flush_work); #endif - dev_remove_pack(&ztdeth_ptype); - unregister_netdevice_notifier(&ztdeth_nblock); dahdi_dynamic_unregister_driver(&ztd_eth); + unregister_netdevice_notifier(&ztdeth_nblock); + dev_remove_pack(&ztdeth_ptype); + + skb_queue_purge(&skbs); } MODULE_DESCRIPTION("DAHDI Dynamic TDMoE Support"); diff --git a/drivers/dahdi/dahdi_dynamic_loc.c b/drivers/dahdi/dahdi_dynamic_loc.c index 98cb7b1..4086bd8 100644 --- a/drivers/dahdi/dahdi_dynamic_loc.c +++ b/drivers/dahdi/dahdi_dynamic_loc.c @@ -78,10 +78,11 @@ static LIST_HEAD(dynamic_local_list); static void dahdi_dynamic_local_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen) { - struct dahdi_dynamic_local *const d = dyn->pvt; + struct dahdi_dynamic_local *d; unsigned long flags; spin_lock_irqsave(&local_lock, flags); + d = dyn->pvt; if (d && d->peer && d->peer->span) { if (test_bit(DAHDI_FLAGBIT_REGISTERED, &d->peer->span->flags)) dahdi_dynamic_receive(d->peer->span, msg, msglen); @@ -130,11 +131,12 @@ static int digit2int(char d) static void dahdi_dynamic_local_destroy(struct dahdi_dynamic *dyn) { - struct dahdi_dynamic_local *d = dyn->pvt; + struct dahdi_dynamic_local *d; unsigned long flags; struct dahdi_dynamic_local *cur; spin_lock_irqsave(&local_lock, flags); + d = dyn->pvt; list_for_each_entry(cur, &dynamic_local_list, node) { if (cur->peer == d) cur->peer = NULL; diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h index 8097cb3..ce4c01a 100644 --- a/include/dahdi/kernel.h +++ b/include/dahdi/kernel.h @@ -1261,7 +1261,8 @@ extern u_char __dahdi_lin2a[16384]; #endif /*! \brief Used by dynamic DAHDI -- don't use directly */ -void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data)); +void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data), + struct module *owner); /*! \brief Used by DAHDI HPEC module -- don't use directly */ void dahdi_set_hpec_ioctl(int (*func)(unsigned int cmd, unsigned long data));