summaryrefslogtreecommitdiff
path: root/drivers/dahdi/dahdi-base.c
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2011-01-03 18:26:19 +0000
committerShaun Ruffell <sruffell@digium.com>2011-01-03 18:26:19 +0000
commit3b2d520f3613441a1bc735f4c70f92570a09a1be (patch)
tree51764300c64d1021481e0b146be3484ae2299f3d /drivers/dahdi/dahdi-base.c
parent17fca4039fa749829f2eaa980dbc6ad01bcf8633 (diff)
dahdi: Take a reference count on module when operating on spans directly.
Normally, spans are accessed via channels, which increment the reference count on the supporting module as part of the open call. When operating on spans by number we are susceptible to a module_unload while we are accessing the span. Renames find_span to span_find_and_get to indicate that we're both finding the span by number and increasing the reference count on the span. Spans themselves don't currently have reference counts, but we can increment the reference count on the module that owns the spans. This will prevent the module that has the span from unloading in the middle of a span_config call, which in the case of the wcte12xp can take awhile since the VPM firmware is loading. Hopefully in the near future the spans themselves will be reference counted directly. Signed-off-by: Shaun Ruffell <sruffell@digium.com> Acked-by: Kinsey Moore <kmoore@digium.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9583 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/dahdi-base.c')
-rw-r--r--drivers/dahdi/dahdi-base.c96
1 files changed, 75 insertions, 21 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 90d6841..a1ecb8a 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -427,9 +427,30 @@ static inline struct dahdi_chan *chan_from_file(struct file *file)
file->private_data : chan_from_num(UNIT(file));
}
-static struct dahdi_span *find_span(int spanno)
+/**
+ * span_find_and_get() - Search for the span by number, and if found take out
+ * a reference on it.
+ *
+ * When you are no longer using the returned pointer, you must release it with
+ * a put_span call.
+ *
+ */
+static struct dahdi_span *span_find_and_get(int spanno)
{
- return (spanno > 0 && spanno < DAHDI_MAX_SPANS) ? spans[spanno] : NULL;
+ unsigned long flags;
+ struct dahdi_span *span;
+
+ spin_lock_irqsave(&chan_lock, flags);
+ span = (spanno > 0 && spanno < DAHDI_MAX_SPANS) ? spans[spanno] : NULL;
+ if (likely(span && !try_module_get(span->ops->owner)))
+ span = NULL;
+ spin_unlock_irqrestore(&chan_lock, flags);
+ return span;
+}
+
+static void put_span(struct dahdi_span *span)
+{
+ module_put(span->ops->owner);
}
static inline unsigned int span_count(void)
@@ -699,7 +720,7 @@ static int dahdi_proc_read(char *page, char **start, off_t off, int count, int *
if (!spanno)
return 0;
- s = find_span(spanno);
+ s = span_find_and_get(spanno);
if (!s)
return -ENODEV;
@@ -834,6 +855,8 @@ static int dahdi_proc_read(char *page, char **start, off_t off, int count, int *
*eof = 1;
if (len > count)
len = count; /* don't return bytes not asked for */
+
+ put_span(s);
return len;
}
#endif
@@ -3895,10 +3918,12 @@ static int dahdi_ioctl_setparams(struct file *file, unsigned long data)
*/
static int dahdi_ioctl_spanstat(struct file *file, unsigned long data)
{
+ int ret = 0;
struct dahdi_spaninfo spaninfo;
struct dahdi_span *s;
int j;
size_t size_to_copy;
+ bool via_chan = false;
size_to_copy = sizeof(struct dahdi_spaninfo);
if (copy_from_user(&spaninfo, (void __user *)data, size_to_copy))
@@ -3909,8 +3934,9 @@ static int dahdi_ioctl_spanstat(struct file *file, unsigned long data)
return -EINVAL;
s = chan->span;
+ via_chan = true;
} else {
- s = find_span(spaninfo.spanno);
+ s = span_find_and_get(spaninfo.spanno);
}
if (!s)
return -EINVAL;
@@ -3963,8 +3989,12 @@ static int dahdi_ioctl_spanstat(struct file *file, unsigned long data)
}
if (copy_to_user((void __user *)data, &spaninfo, size_to_copy))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+
+ if (!via_chan)
+ put_span(s);
+
+ return ret;
}
/**
@@ -3973,9 +4003,11 @@ static int dahdi_ioctl_spanstat(struct file *file, unsigned long data)
*/
static int dahdi_ioctl_spanstat_v1(struct file *file, unsigned long data)
{
+ int ret = 0;
struct dahdi_spaninfo_v1 spaninfo_v1;
struct dahdi_span *s;
int j;
+ bool via_chan = false;
if (copy_from_user(&spaninfo_v1, (void __user *)data,
sizeof(spaninfo_v1))) {
@@ -3988,8 +4020,9 @@ static int dahdi_ioctl_spanstat_v1(struct file *file, unsigned long data)
return -EINVAL;
s = chan->span;
+ via_chan = true;
} else {
- s = find_span(spaninfo_v1.spanno);
+ s = span_find_and_get(spaninfo_v1.spanno);
}
if (!s)
@@ -4051,9 +4084,11 @@ static int dahdi_ioctl_spanstat_v1(struct file *file, unsigned long data)
if (copy_to_user((void __user *)data, &spaninfo_v1,
sizeof(spaninfo_v1))) {
- return -EFAULT;
+ ret = -EFAULT;
}
- return 0;
+ if (!via_chan)
+ put_span(s);
+ return ret;
}
static int dahdi_common_ioctl(struct file *file, unsigned int cmd,
@@ -4389,33 +4424,40 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da
struct dahdi_lineconfig lc;
struct dahdi_span *s;
+ res = 0;
if (copy_from_user(&lc, (void __user *)data, sizeof(lc)))
return -EFAULT;
- s = find_span(lc.span);
+ s = span_find_and_get(lc.span);
if (!s)
return -ENXIO;
+
if ((lc.lineconfig & 0x1ff0 & s->linecompat) !=
- (lc.lineconfig & 0x1ff0))
+ (lc.lineconfig & 0x1ff0)) {
+ put_span(s);
return -EINVAL;
+ }
if (s->ops->spanconfig) {
s->lineconfig = lc.lineconfig;
s->lbo = lc.lbo;
s->txlevel = lc.lbo;
s->rxlevel = 0;
- return s->ops->spanconfig(s, &lc);
+ res = s->ops->spanconfig(s, &lc);
}
- return 0;
+ put_span(s);
+ return res;
}
case DAHDI_STARTUP:
if (get_user(j, (int __user *)data))
return -EFAULT;
- s = find_span(j);
+ s = span_find_and_get(j);
if (!s)
return -ENXIO;
- if (s->flags & DAHDI_FLAG_RUNNING)
+ if (s->flags & DAHDI_FLAG_RUNNING) {
+ put_span(s);
return 0;
+ }
if (s->ops->startup)
res = s->ops->startup(s);
@@ -4440,11 +4482,12 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da
s->chans[x]->rxhooksig = DAHDI_RXSIG_INITIAL;
}
}
+ put_span(s);
return 0;
case DAHDI_SHUTDOWN:
if (get_user(j, (int __user *)data))
return -EFAULT;
- s = find_span(j);
+ s = span_find_and_get(j);
if (!s)
return -ENXIO;
@@ -4455,6 +4498,7 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da
if (s->ops->shutdown)
res = s->ops->shutdown(s);
s->flags &= ~DAHDI_FLAG_RUNNING;
+ put_span(s);
return 0;
case DAHDI_ATTACH_ECHOCAN:
{
@@ -4628,11 +4672,13 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da
/* get struct from user */
if (copy_from_user(&maint, (void __user *)data, sizeof(maint)))
return -EFAULT;
- s = find_span(maint.spanno);
+ s = span_find_and_get(maint.spanno);
if (!s)
return -EINVAL;
- if (!s->ops->maint)
+ if (!s->ops->maint) {
+ put_span(s);
return -ENOSYS;
+ }
spin_lock_irqsave(&s->lock, flags);
/* save current maint state */
i = s->maintstat;
@@ -4648,8 +4694,10 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da
break;
rv = s->ops->maint(s, maint.command);
spin_unlock_irqrestore(&s->lock, flags);
- if (rv)
+ if (rv) {
+ put_span(s);
return rv;
+ }
spin_lock_irqsave(&s->lock, flags);
break;
case DAHDI_MAINT_LOOPUP:
@@ -4657,8 +4705,10 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da
s->mainttimer = DAHDI_LOOPCODE_TIME * DAHDI_CHUNKSIZE;
rv = s->ops->maint(s, maint.command);
spin_unlock_irqrestore(&s->lock, flags);
- if (rv)
+ if (rv) {
+ put_span(s);
return rv;
+ }
spin_lock_irqsave(&s->lock, flags);
break;
case DAHDI_MAINT_FAS_DEFECT:
@@ -4678,8 +4728,10 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da
rv = s->ops->maint(s, maint.command);
spin_unlock_irqrestore(&s->lock, flags);
- if (rv)
+ if (rv) {
+ put_span(s);
return rv;
+ }
spin_lock_irqsave(&s->lock, flags);
break;
default:
@@ -4687,10 +4739,12 @@ static int dahdi_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long da
module_printk(KERN_NOTICE,
"Unknown maintenance event: %d\n",
maint.command);
+ put_span(s);
return -ENOSYS;
}
dahdi_alarm_notify(s); /* process alarm-related events */
spin_unlock_irqrestore(&s->lock, flags);
+ put_span(s);
break;
}
case DAHDI_DYNAMIC_CREATE: