summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2012-04-03 19:44:27 +0000
committerShaun Ruffell <sruffell@digium.com>2012-04-03 19:44:27 +0000
commit5a9e9d4f8b7c38a9fff9e4c2c4499dcdee82d2e6 (patch)
tree8614408a2988c4c3c14d3d5bdfc3cbbda44da749
parent6dbace7374c2f27f50762a5445b28960a135c718 (diff)
dahdi_dynamic: Do not call into dahdi_dynamic without holding reference.
Instead of registering a function pointer, register a dahdi_dynamic_ops structure that contains the owner as well as the ioctl callback. This way dahdi.ko can bump up the reference count on dahdi_dynamic.ko before calling the ioctl callback. Also, use the registration mutex to guard against the module being unloaded between the time the structure pointer was checked, and the module reference is taken. Signed-off-by: Shaun Ruffell <sruffell@digium.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10623 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/dahdi-base.c47
-rw-r--r--drivers/dahdi/dahdi_dynamic.c12
-rw-r--r--include/dahdi/kernel.h7
3 files changed, 49 insertions, 17 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index e829e6c..d006799 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);
@@ -4405,12 +4404,14 @@ static int dahdi_common_ioctl(struct file *file, unsigned int cmd,
return 0;
}
-static int (*dahdi_dynamic_ioctl)(unsigned int cmd, unsigned long data);
-
-void dahdi_set_dynamic_ioctl(int (*func)(unsigned int cmd, unsigned long data))
+static const struct dahdi_dynamic_ops *dahdi_dynamic_ops;
+void dahdi_set_dynamic_ops(const struct dahdi_dynamic_ops *ops)
{
- dahdi_dynamic_ioctl = func;
+ mutex_lock(&registration_mutex);
+ dahdi_dynamic_ops = ops;
+ mutex_unlock(&registration_mutex);
}
+EXPORT_SYMBOL(dahdi_set_dynamic_ops);
static int (*dahdi_hpec_ioctl)(unsigned int cmd, unsigned long data);
@@ -5129,6 +5130,33 @@ static int dahdi_ioctl_maint(unsigned long data)
return 0;
}
+static int dahdi_ioctl_dynamic(unsigned int cmd, unsigned long data)
+{
+ bool tried_load = false;
+ int res;
+
+retry_check:
+ mutex_lock(&registration_mutex);
+ if (!dahdi_dynamic_ops) {
+ mutex_unlock(&registration_mutex);
+ if (tried_load)
+ return -ENOSYS;
+
+ request_module("dahdi_dynamic");
+ tried_load = true;
+ goto retry_check;
+ }
+ if (!try_module_get(dahdi_dynamic_ops->owner)) {
+ mutex_unlock(&registration_mutex);
+ return -ENOSYS;
+ }
+ mutex_unlock(&registration_mutex);
+
+ res = dahdi_dynamic_ops->ioctl(cmd, data);
+ module_put(dahdi_dynamic_ops->owner);
+ return res;
+}
+
static int
dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long data)
{
@@ -5163,14 +5191,7 @@ dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long data)
return dahdi_ioctl_maint(data);
case DAHDI_DYNAMIC_CREATE:
case DAHDI_DYNAMIC_DESTROY:
- if (dahdi_dynamic_ioctl) {
- return dahdi_dynamic_ioctl(cmd, data);
- } else {
- request_module("dahdi_dynamic");
- if (dahdi_dynamic_ioctl)
- return dahdi_dynamic_ioctl(cmd, data);
- }
- return -ENOSYS;
+ return dahdi_ioctl_dynamic(cmd, data);
case DAHDI_EC_LICENSE_CHALLENGE:
case DAHDI_EC_LICENSE_RESPONSE:
if (dahdi_hpec_ioctl) {
diff --git a/drivers/dahdi/dahdi_dynamic.c b/drivers/dahdi/dahdi_dynamic.c
index 79c8bba..602ebe9 100644
--- a/drivers/dahdi/dahdi_dynamic.c
+++ b/drivers/dahdi/dahdi_dynamic.c
@@ -818,10 +818,13 @@ static void check_for_red_alarm(unsigned long ignored)
mod_timer(&alarmcheck, jiffies + 1 * HZ);
}
+static const struct dahdi_dynamic_ops dahdi_dynamic_ops = {
+ .owner = THIS_MODULE,
+ .ioctl = dahdi_dynamic_ioctl,
+};
+
static int dahdi_dynamic_init(void)
{
- dahdi_set_dynamic_ioctl(dahdi_dynamic_ioctl);
-
/* Start process to check for RED ALARM */
init_timer(&alarmcheck);
alarmcheck.expires = 0;
@@ -832,19 +835,22 @@ static int dahdi_dynamic_init(void)
#ifdef ENABLE_TASKLETS
tasklet_init(&dahdi_dynamic_tlet, dahdi_dynamic_tasklet, 0);
#endif
+ dahdi_set_dynamic_ops(&dahdi_dynamic_ops);
+
printk(KERN_INFO "DAHDI Dynamic Span support LOADED\n");
return 0;
}
static void dahdi_dynamic_cleanup(void)
{
+ dahdi_set_dynamic_ops(NULL);
+
#ifdef ENABLE_TASKLETS
if (taskletpending) {
tasklet_disable(&dahdi_dynamic_tlet);
tasklet_kill(&dahdi_dynamic_tlet);
}
#endif
- dahdi_set_dynamic_ioctl(NULL);
del_timer(&alarmcheck);
printk(KERN_INFO "DAHDI Dynamic Span support unloaded\n");
}
diff --git a/include/dahdi/kernel.h b/include/dahdi/kernel.h
index 8097cb3..9922f11 100644
--- a/include/dahdi/kernel.h
+++ b/include/dahdi/kernel.h
@@ -1260,8 +1260,13 @@ extern u_char __dahdi_lin2mu[16384];
extern u_char __dahdi_lin2a[16384];
#endif
+struct dahdi_dynamic_ops {
+ struct module *owner;
+ int (*ioctl)(unsigned int cmd, unsigned long data);
+};
+
/*! \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_ops(const struct dahdi_dynamic_ops *ops);
/*! \brief Used by DAHDI HPEC module -- don't use directly */
void dahdi_set_hpec_ioctl(int (*func)(unsigned int cmd, unsigned long data));