[svn-commits] sruffell: linux/trunk r9573 - in /linux/trunk: drivers/dahdi/ include/dahdi/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jan 3 18:25:36 UTC 2011


Author: sruffell
Date: Mon Jan  3 12:25:32 2011
New Revision: 9573

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=9573
Log:
dahdi_dynamic: dynamic drivers should not reference count themselves.

Move the try_module_get/module_put calls from the various dynamic
drivers into the "core" dahdi_dynamic.c file itself.  This way, a
reference count can always be held while calling through the function
pointers.  This is enabled by adding an .owner field to 'struct
dahdi_dynamic_driver'.

Dynamic spans are also unique in dahdi in that they require a "dahdi_cfg
-s" to stop them and release the references on the modules.  This is
counterintuitive. This change makes sure they are reference counted just
like other spans and on driver unload, if there aren't any open handles
from userspace, they will take care of unwinding themselves.

Signed-off-by: Shaun Ruffell <sruffell at digium.com>
Acked-by: Kinsey Moore <kmoore at digium.com>

Modified:
    linux/trunk/drivers/dahdi/dahdi_dynamic.c
    linux/trunk/drivers/dahdi/dahdi_dynamic_eth.c
    linux/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c
    linux/trunk/drivers/dahdi/dahdi_dynamic_loc.c
    linux/trunk/include/dahdi/kernel.h

Modified: linux/trunk/drivers/dahdi/dahdi_dynamic.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/dahdi_dynamic.c?view=diff&rev=9573&r1=9572&r2=9573
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi_dynamic.c (original)
+++ linux/trunk/drivers/dahdi/dahdi_dynamic.c Mon Jan  3 12:25:32 2011
@@ -407,10 +407,13 @@
 	WARN_ON(test_bit(DAHDI_FLAGBIT_REGISTERED, &d->span.flags));
 
 	if (d->pvt) {
-		if (d->driver && d->driver->destroy)
+		if (d->driver && d->driver->destroy) {
+			__module_get(d->driver->owner);
 			d->driver->destroy(d->pvt);
-		else
+			module_put(d->driver->owner);
+		} else {
 			WARN_ON(1);
+		}
 	}
 
 	kfree(d->msgbuf);
@@ -480,8 +483,12 @@
 	if (unlikely(!d))
 		return -EINVAL;
 
-	if (atomic_read(&d->kref.refcount) > 1)
+	/* We shouldn't have more than the two references at this point.  If
+	 * we do, there are probably channels that are still opened. */
+	if (atomic_read(&d->kref.refcount) > 2) {
+		dynamic_put(d);
 		return -EBUSY;
+	}
 
 	dahdi_unregister(&d->span);
 
@@ -506,6 +513,8 @@
 static int dahdi_dynamic_open(struct dahdi_chan *chan)
 {
 	struct dahdi_dynamic *d = dynamic_from_span(chan->span);
+	if (!try_module_get(d->driver->owner))
+		return -ENODEV;
 	dynamic_get(d);
 	return 0;
 }
@@ -518,7 +527,9 @@
 static int dahdi_dynamic_close(struct dahdi_chan *chan)
 {
 	struct dahdi_dynamic *d = dynamic_from_span(chan->span);
+	struct module *owner = d->driver->owner;
 	dynamic_put(d);
+	module_put(owner);
 	return 0;
 }
 
@@ -621,8 +632,6 @@
 	}
 
 
-	/* Another race -- should let the module get unloaded while we
-	   have it here */
 	if (!dtd) {
 		printk(KERN_NOTICE "No such driver '%s' for dynamic span\n",
 			dds->driver);
@@ -630,23 +639,31 @@
 		return -EINVAL;
 	}
 
+	if (!try_module_get(dtd->owner)) {
+		dynamic_put(d);
+		return -ENODEV;
+	}
+
+	/* Remember the driver.  We also give our reference to the driver to
+	 * the dahdi_dyanmic here.  Do not access dtd directly now. */
+	d->driver = dtd;
+
 	/* Create the stuff */
-	d->pvt = dtd->create(&d->span, d->addr);
+	d->pvt = d->driver->create(&d->span, d->addr);
 	if (!d->pvt) {
 		printk(KERN_NOTICE "Driver '%s' (%s) rejected address '%s'\n",
 			dtd->name, dtd->desc, d->addr);
 		dynamic_put(d);
+		module_put(dtd->owner);
 		return -EINVAL;
 	}
-
-	/* Remember the driver */
-	d->driver = dtd;
 
 	/* Whee!  We're created.  Now register the span */
 	if (dahdi_register(&d->span, 0)) {
 		printk(KERN_NOTICE "Unable to register span '%s'\n",
 			d->span.name);
 		dynamic_put(d);
+		module_put(dtd->owner);
 		return -EINVAL;
 	}
 
@@ -660,8 +677,8 @@
 
 	checkmaster();
 
+	module_put(dtd->owner);
 	return x;
-
 }
 
 #ifdef ENABLE_TASKLETS
@@ -719,6 +736,9 @@
 	unsigned long flags;
 	int res = 0;
 
+	if (!dri->owner)
+		return -EINVAL;
+
 	if (find_driver(dri->name)) {
 		res = -1;
 	} else {
@@ -732,16 +752,22 @@
 
 void dahdi_dynamic_unregister_driver(struct dahdi_dynamic_driver *dri)
 {
-	struct dahdi_dynamic *d;
+	struct dahdi_dynamic *d, *n;
 	unsigned long flags;
 
-	spin_lock_irqsave(&driver_lock, flags);
-	list_del_rcu(&dri->list);
-	spin_unlock_irqrestore(&driver_lock, flags);
-	synchronize_rcu();
-
-	list_for_each_entry(d, &dspan_list, list) {
+	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);
+					d->driver->destroy(d->pvt);
+					module_put(d->driver->owner);
+					d->pvt = NULL;
+				} else {
+					WARN_ON(1);
+				}
+			}
+			dahdi_unregister(&d->span);
 			spin_lock_irqsave(&dspan_lock, flags);
 			list_del_rcu(&d->list);
 			spin_unlock_irqrestore(&dspan_lock, flags);
@@ -749,6 +775,11 @@
 			dynamic_put(d);
 		}
 	}
+
+	spin_lock_irqsave(&driver_lock, flags);
+	list_del_rcu(&dri->list);
+	spin_unlock_irqrestore(&driver_lock, flags);
+	synchronize_rcu();
 }
 EXPORT_SYMBOL(dahdi_dynamic_unregister_driver);
 

Modified: linux/trunk/drivers/dahdi/dahdi_dynamic_eth.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/dahdi_dynamic_eth.c?view=diff&rev=9573&r1=9572&r2=9573
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi_dynamic_eth.c (original)
+++ linux/trunk/drivers/dahdi/dahdi_dynamic_eth.c Mon Jan  3 12:25:32 2011
@@ -288,7 +288,6 @@
 	if (cur == z) {	/* Successfully removed */
 		printk(KERN_INFO "TDMoE: Removed interface for %s\n", z->span->name);
 		kfree(z);
-		module_put(THIS_MODULE);
 	}
 }
 
@@ -390,19 +389,18 @@
 		z->next = zdevs;
 		zdevs = z;
 		spin_unlock_irqrestore(&zlock, flags);
-		if(!try_module_get(THIS_MODULE))
-			printk(KERN_DEBUG "TDMoE: Unable to increment module use count\n");
 	}
 	return z;
 }
 
 static struct dahdi_dynamic_driver ztd_eth = {
-	"eth",
-	"Ethernet",
-	ztdeth_create,
-	ztdeth_destroy,
-	ztdeth_transmit,
-	ztdeth_flush
+	.owner = THIS_MODULE,
+	.name = "eth",
+	.desc = "Ethernet",
+	.create = ztdeth_create,
+	.destroy = ztdeth_destroy,
+	.transmit = ztdeth_transmit,
+	.flush = ztdeth_flush,
 };
 
 static struct notifier_block ztdeth_nblock = {

Modified: linux/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c?view=diff&rev=9573&r1=9572&r2=9573
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c (original)
+++ linux/trunk/drivers/dahdi/dahdi_dynamic_ethmf.c Mon Jan  3 12:25:32 2011
@@ -573,7 +573,6 @@
 			z->span->name);
 		kfree(z->msgbuf);
 		kfree(z);
-		module_put(THIS_MODULE);
 	} else {
 		if (z && z->span && z->span->name) {
 			printk(KERN_ERR "Cannot find interface for %s\n",
@@ -660,9 +659,6 @@
 	spin_unlock_irqrestore(&ethmf_lock, flags);
 	atomic_inc(&(ethmf_groups[hashaddr_to_index(z->addr_hash)].spans));
 
-	if (!try_module_get(THIS_MODULE))
-		printk(KERN_ERR "TDMoEmf: Unable to increment module use count\n");
-
 	/* enable the timer for enabling the spans */
 	mod_timer(&timer, jiffies + HZ);
 	atomic_set(&shutdown, 0);
@@ -670,12 +666,13 @@
 }
 
 static struct dahdi_dynamic_driver ztd_ethmf = {
-	"ethmf",
-	"Ethernet",
-	ztdethmf_create,
-	ztdethmf_destroy,
-	ztdethmf_transmit,
-	ztdethmf_flush
+	.owner = THIS_MODULE,
+	.name = "ethmf",
+	.desc = "Ethernet",
+	.create = ztdethmf_create,
+	.destroy = ztdethmf_destroy,
+	.transmit = ztdethmf_transmit,
+	.flush = ztdethmf_flush,
 };
 
 static struct notifier_block ztdethmf_nblock = {

Modified: linux/trunk/drivers/dahdi/dahdi_dynamic_loc.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/dahdi_dynamic_loc.c?view=diff&rev=9573&r1=9572&r2=9573
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi_dynamic_loc.c (original)
+++ linux/trunk/drivers/dahdi/dahdi_dynamic_loc.c Mon Jan  3 12:25:32 2011
@@ -146,7 +146,6 @@
 
 	printk(KERN_INFO "TDMoL: Removed interface for %s, key %d "
 		"id %d\n", d->span->name, d->key, d->id);
-	module_put(THIS_MODULE);
 	kfree(d);
 }
 
@@ -216,9 +215,6 @@
 	list_add(&d->node, &dynamic_local_list);
 	spin_unlock_irqrestore(&local_lock, flags);
 
-	if (!try_module_get(THIS_MODULE))
-		printk(KERN_DEBUG "TDMoL: Unable to increment module use count\n");
-
 	printk(KERN_INFO "TDMoL: Added new interface for %s, "
 	       "key %d id %d\n", span->name, d->key, d->id);
 	return d;
@@ -240,12 +236,12 @@
 }
 
 static struct dahdi_dynamic_driver dahdi_dynamic_local = {
-	"loc",
-	"Local",
-	dahdi_dynamic_local_create,
-	dahdi_dynamic_local_destroy,
-	dahdi_dynamic_local_transmit,
-	NULL	/* flush */
+	.owner = THIS_MODULE,
+	.name = "loc",
+	.desc = "Local",
+	.create = dahdi_dynamic_local_create,
+	.destroy = dahdi_dynamic_local_destroy,
+	.transmit = dahdi_dynamic_local_transmit,
 };
 
 static int __init dahdi_dynamic_local_init(void)

Modified: linux/trunk/include/dahdi/kernel.h
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/include/dahdi/kernel.h?view=diff&rev=9573&r1=9572&r2=9573
==============================================================================
--- linux/trunk/include/dahdi/kernel.h (original)
+++ linux/trunk/include/dahdi/kernel.h Mon Jan  3 12:25:32 2011
@@ -1006,6 +1006,7 @@
 	int (*flush)(void);
 
 	struct list_head list;
+	struct module *owner;
 };
 
 /*! \brief Receive a dynamic span message */




More information about the svn-commits mailing list