diff options
author | sruffell <sruffell@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2008-01-23 23:02:05 +0000 |
---|---|---|
committer | sruffell <sruffell@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2008-01-23 23:02:05 +0000 |
commit | 9eacf130605d24c216e69cfc9b3a71957220c3a7 (patch) | |
tree | 16d6318af57aac2e9de525a78447d69473c492c6 | |
parent | 53734aba61b6c2a22d110289268f4d45d010b868 (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.c | 12 |
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); |