summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsruffell <sruffell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-01-23 23:02:05 +0000
committersruffell <sruffell@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-01-23 23:02:05 +0000
commit9eacf130605d24c216e69cfc9b3a71957220c3a7 (patch)
tree16d6318af57aac2e9de525a78447d69473c492c6
parent53734aba61b6c2a22d110289268f4d45d010b868 (diff)
Ensure that the zone lock is always acquired before the channel lock.
(issue #7620) git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3733 5390a7c7-147a-4af0-8ec9-7488f05a26cb
-rw-r--r--zaptel-base.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/zaptel-base.c b/zaptel-base.c
index 310ea17..cc78b54 100644
--- a/zaptel-base.c
+++ b/zaptel-base.c
@@ -1179,8 +1179,9 @@ static int set_tone_zone(struct zt_chan *chan, int zone)
{
int res = 0;
struct zt_zone *z;
+ unsigned long flags;
- /* Assumes channel is already locked */
+ /* Do not call with the channel locked. */
if (zone == -1)
zone = default_zone;
@@ -1191,6 +1192,7 @@ static int set_tone_zone(struct zt_chan *chan, int zone)
read_lock(&zone_lock);
if ((z = tone_zones[zone])) {
+ spin_lock_irqsave(&chan->lock, flags);
if (chan->curzone)
atomic_dec(&chan->curzone->refcount);
@@ -1198,6 +1200,7 @@ static int set_tone_zone(struct zt_chan *chan, int zone)
chan->curzone = z;
chan->tonezone = zone;
memcpy(chan->ringcadence, z->ringcadence, sizeof(chan->ringcadence));
+ spin_unlock_irqrestore(&chan->lock, flags);
} else {
res = -ENODATA;
}
@@ -2266,7 +2269,6 @@ static int initialize_channel(struct zt_chan *chan)
chan->curtone = NULL;
chan->tonep = 0;
chan->pdialcount = 0;
- set_tone_zone(chan, -1);
if (chan->gainalloc && chan->rxgain)
rxgain = chan->rxgain;
chan->rxgain = defgain;
@@ -2295,6 +2297,7 @@ static int initialize_channel(struct zt_chan *chan)
}
spin_unlock_irqrestore(&chan->lock, flags);
+ set_tone_zone(chan, -1);
if (chan->span && chan->span->echocan)
chan->span->echocan(chan, 0);
@@ -2382,8 +2385,9 @@ static int zt_specchan_open(struct inode *inode, struct file *file, int unit, in
spin_lock_irqsave(&chans[unit]->lock, flags);
if (chans[unit]->flags & ZT_FLAG_PSEUDO)
chans[unit]->flags |= ZT_FLAG_AUDIO;
- if (chans[unit]->span && chans[unit]->span->open)
+ if (chans[unit]->span && chans[unit]->span->open) {
res = chans[unit]->span->open(chans[unit]);
+ }
if (!res) {
chans[unit]->file = file;
#ifndef LINUX26
@@ -4017,9 +4021,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign
break;
case ZT_SETTONEZONE:
get_user(j, (int *) data);
- spin_lock_irqsave(&chan->lock, flags);
rv = set_tone_zone(chan, j);
- spin_unlock_irqrestore(&chan->lock, flags);
return rv;
case ZT_GETTONEZONE:
spin_lock_irqsave(&chan->lock, flags);