dahdi_dynamic_eth: Make ztdeth_exit() symetrical with ztdeth_init() and fix race on unload.
Minor change to follow generally recommended practice. Prevents new packets from being queued up for devices when they are about to be cleaned up. Also clean up any skbs that may still be on the queue after unloading. Also closes anoter potential kernel oops on module unload. It was possible to delete the private structure while the master span process was running. The result was an attempt to page memory from interrupt context. Make sure that the pvt function is set and cleared under the zlock. Also do not assume that the pvt pointer is valid in ztdeth_transmit. Signed-off-by: Shaun Ruffell <sruffell@digium.com> Origin: http://svnview.digium.com/svn/dahdi?view=rev&rev=10626 git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/branches/2.6@10631 a0bf4364-ded3-4de4-8d8a-66a801d63aff
This commit is contained in:
parent
05bac84ce8
commit
89ea0430df
@ -154,7 +154,7 @@ static void ztdeth_transmit(struct dahdi_dynamic *dyn, u8 *msg, size_t msglen)
|
|||||||
|
|
||||||
spin_lock_irqsave(&zlock, flags);
|
spin_lock_irqsave(&zlock, flags);
|
||||||
z = dyn->pvt;
|
z = dyn->pvt;
|
||||||
if (z->dev) {
|
if (z && z->dev) {
|
||||||
/* Copy fields to local variables to remove spinlock ASAP */
|
/* Copy fields to local variables to remove spinlock ASAP */
|
||||||
dev = z->dev;
|
dev = z->dev;
|
||||||
memcpy(addr, z->addr, sizeof(z->addr));
|
memcpy(addr, z->addr, sizeof(z->addr));
|
||||||
@ -315,11 +315,12 @@ static void ztdeth_destroy(struct dahdi_dynamic *dyn)
|
|||||||
prev = cur;
|
prev = cur;
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&zlock, flags);
|
|
||||||
if (cur == z) { /* Successfully removed */
|
if (cur == z) { /* Successfully removed */
|
||||||
|
dyn->pvt = NULL;
|
||||||
printk(KERN_INFO "TDMoE: Removed interface for %s\n", z->span->name);
|
printk(KERN_INFO "TDMoE: Removed interface for %s\n", z->span->name);
|
||||||
kfree(z);
|
kfree(z);
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&zlock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ztdeth_create(struct dahdi_dynamic *dyn, const char *addr)
|
static int ztdeth_create(struct dahdi_dynamic *dyn, const char *addr)
|
||||||
@ -442,12 +443,12 @@ static struct notifier_block ztdeth_nblock = {
|
|||||||
|
|
||||||
static int __init ztdeth_init(void)
|
static int __init ztdeth_init(void)
|
||||||
{
|
{
|
||||||
|
skb_queue_head_init(&skbs);
|
||||||
|
|
||||||
dev_add_pack(&ztdeth_ptype);
|
dev_add_pack(&ztdeth_ptype);
|
||||||
register_netdevice_notifier(&ztdeth_nblock);
|
register_netdevice_notifier(&ztdeth_nblock);
|
||||||
dahdi_dynamic_register_driver(&ztd_eth);
|
dahdi_dynamic_register_driver(&ztd_eth);
|
||||||
|
|
||||||
skb_queue_head_init(&skbs);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,9 +459,11 @@ static void __exit ztdeth_exit(void)
|
|||||||
#else
|
#else
|
||||||
cancel_work_sync(&dahdi_dynamic_eth_flush_work);
|
cancel_work_sync(&dahdi_dynamic_eth_flush_work);
|
||||||
#endif
|
#endif
|
||||||
dev_remove_pack(&ztdeth_ptype);
|
|
||||||
unregister_netdevice_notifier(&ztdeth_nblock);
|
|
||||||
dahdi_dynamic_unregister_driver(&ztd_eth);
|
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");
|
MODULE_DESCRIPTION("DAHDI Dynamic TDMoE Support");
|
||||||
|
Loading…
Reference in New Issue
Block a user