summaryrefslogtreecommitdiff
path: root/kernel/zaptel-base.c
diff options
context:
space:
mode:
authormattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-04-19 21:54:03 +0000
committermattf <mattf@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-04-19 21:54:03 +0000
commit7d263bb9b55130b4b58a99ccc2ab092c63136e3b (patch)
tree0d87134854857448f93c05a2a320ed47276ac5e7 /kernel/zaptel-base.c
parent0a591d86a1cc9bdddac044b646f3d5a45222dba3 (diff)
Partial fix for #9379. Fixes potential race condition in open and close routines for zaptel devices
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4183 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'kernel/zaptel-base.c')
-rw-r--r--kernel/zaptel-base.c26
1 files changed, 16 insertions, 10 deletions
diff --git a/kernel/zaptel-base.c b/kernel/zaptel-base.c
index 326a7b1..8e2f41f 100644
--- a/kernel/zaptel-base.c
+++ b/kernel/zaptel-base.c
@@ -2461,18 +2461,20 @@ static int zt_specchan_open(struct inode *inode, struct file *file, int unit, in
if (chans[unit] && chans[unit]->sig) {
/* Make sure we're not already open, a net device, or a slave device */
- if (chans[unit]->flags & ZT_FLAG_OPEN)
- res = -EBUSY;
- else if (chans[unit]->flags & ZT_FLAG_NETDEV)
+ if (chans[unit]->flags & ZT_FLAG_NETDEV)
res = -EBUSY;
else if (chans[unit]->master != chans[unit])
res = -EBUSY;
else if ((chans[unit]->sig & __ZT_SIG_DACS) == __ZT_SIG_DACS)
res = -EBUSY;
- else {
+ else if (!test_and_set_bit(ZT_FLAGBIT_OPEN, &chans[unit]->flags)) {
unsigned long flags;
- /* Assume everything is going to be okay */
res = initialize_channel(chans[unit]);
+ if (res) {
+ /* Reallocbufs must have failed */
+ clear_bit(ZT_FLAGBIT_OPEN, &chans[unit]->flags);
+ return res;
+ }
spin_lock_irqsave(&chans[unit]->lock, flags);
if (chans[unit]->flags & ZT_FLAG_PSEUDO)
chans[unit]->flags |= ZT_FLAG_AUDIO;
@@ -2485,13 +2487,14 @@ static int zt_specchan_open(struct inode *inode, struct file *file, int unit, in
if (inc)
MOD_INC_USE_COUNT;
#endif
- chans[unit]->flags |= ZT_FLAG_OPEN;
spin_unlock_irqrestore(&chans[unit]->lock, flags);
} else {
spin_unlock_irqrestore(&chans[unit]->lock, flags);
close_channel(chans[unit]);
+ clear_bit(ZT_FLAGBIT_OPEN, &chans[unit]->flags);
}
- }
+ } else
+ res = -EBUSY;
} else
res = -ENXIO;
return res;
@@ -2500,15 +2503,18 @@ static int zt_specchan_open(struct inode *inode, struct file *file, int unit, in
static int zt_specchan_release(struct inode *node, struct file *file, int unit)
{
int res=0;
+ unsigned long flags;
+
if (chans[unit]) {
- unsigned long flags;
+ /* Chan lock protects contents against potentially non atomic accesses.
+ * So if the pointer setting is not atomic, we should protect */
spin_lock_irqsave(&chans[unit]->lock, flags);
- chans[unit]->flags &= ~ZT_FLAG_OPEN;
- spin_unlock_irqrestore(&chans[unit]->lock, flags);
chans[unit]->file = NULL;
+ spin_unlock_irqrestore(&chans[unit]->lock, flags);
close_channel(chans[unit]);
if (chans[unit]->span && chans[unit]->span->close)
res = chans[unit]->span->close(chans[unit]);
+ clear_bit(ZT_FLAGBIT_OPEN, &chans[unit]->flags);
} else
res = -ENXIO;
#ifndef LINUX26