diff options
-rwxr-xr-x | zaptel.c | 77 | ||||
-rwxr-xr-x | zaptel.h | 1 |
2 files changed, 41 insertions, 37 deletions
@@ -296,9 +296,7 @@ static struct zt_timer { static spinlock_t zaptimerlock = SPIN_LOCK_UNLOCKED; -static spinlock_t zapfreelock = SPIN_LOCK_UNLOCKED; - -static int zapneedfree = 0; +static spinlock_t bigzaplock = SPIN_LOCK_UNLOCKED; struct zt_zone { char name[40]; /* Informational, only */ @@ -2069,8 +2067,6 @@ static int zt_specchan_open(struct inode *inode, struct file *file, int unit, in /* 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_DEAD) - res = -EBUSY; else if (chans[unit]->flags & ZT_FLAG_NETDEV) res = -EBUSY; else if (chans[unit]->master != chans[unit]) @@ -2138,7 +2134,7 @@ static struct zt_chan *zt_alloc_pseudo(void) return pseudo; } -static void __zt_free_pseudo(struct zt_chan *pseudo) +static void zt_free_pseudo(struct zt_chan *pseudo) { if (pseudo) { zt_chan_unreg(pseudo); @@ -2146,19 +2142,7 @@ static void __zt_free_pseudo(struct zt_chan *pseudo) } } -static void zt_free_pseudo(struct zt_chan *pseudo) -{ - long flags; - if (pseudo) { - /* Mark as dead for later reaping */ - pseudo->flags |= ZT_FLAG_DEAD; - spin_lock_irqsave(&zapfreelock, flags); - zapneedfree = 1; - spin_unlock_irqrestore(&zapfreelock, flags); - } -} - -static int zt_open(struct inode *inode, struct file *file) +static int __zt_open(struct inode *inode, struct file *file) { int unit = UNIT(file); struct zt_chan *chan; @@ -2189,6 +2173,16 @@ static int zt_open(struct inode *inode, struct file *file) return zt_specchan_open(inode, file, unit, 1); } +static int zt_open(struct inode *inode, struct file *file) +{ + int res; + unsigned long flags; + spin_lock_irqsave(&bigzaplock, flags); + res = __zt_open(inode, file); + spin_unlock_irqrestore(&bigzaplock, flags); + return res; +} + static ssize_t zt_read(struct file *file, char *usrbuf, size_t count, loff_t *ppos) { int unit = UNIT(file); @@ -2443,7 +2437,7 @@ static void __do_dtmf(struct zt_chan *chan) __qevent(chan, ZT_EVENT_DIALCOMPLETE); } -static int zt_release(struct inode *inode, struct file *file) +static int __zt_release(struct inode *inode, struct file *file) { int unit = UNIT(file); int res; @@ -2475,6 +2469,17 @@ static int zt_release(struct inode *inode, struct file *file) return zt_specchan_release(inode, file, unit); } +static int zt_release(struct inode *inode, struct file *file) +{ + /* Lock the big zap lock when handling a release */ + unsigned long flags; + int res; + spin_lock_irqsave(&bigzaplock, flags); + res = __zt_release(inode, file); + spin_unlock_irqrestore(&bigzaplock, flags); + return res; +} + void zt_alarm_notify(struct zt_span *span) { int j; @@ -3157,7 +3162,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign struct zt_bufferinfo bi; struct zt_confinfo conf; struct zt_ring_cadence cad; - unsigned long flags; + unsigned long flags, flagso; int i, j, k, rv; int ret, c; @@ -3363,8 +3368,10 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign break; case ZT_CONFMUTE: /* set confmute flag */ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); + spin_lock_irqsave(&bigzaplock, flags); get_user(j,(int *)data); /* get conf # */ chan->confmute = j; + spin_unlock_irqrestore(&bigzaplock, flags); break; case ZT_GETCONFMUTE: /* get confmute flag */ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); @@ -3427,12 +3434,14 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign /* likewise if 0 mode must have no conf */ if ((!conf.confmode) && conf.confno) return (-EINVAL); conf.chan = i; /* return with real channel # */ + spin_lock_irqsave(&bigzaplock, flagso); spin_lock_irqsave(&chan->lock, flags); if (conf.confno == -1) conf.confno = zt_first_empty_conference(); if ((conf.confno < 1) && (conf.confmode)) { /* No more empty conferences */ spin_unlock_irqrestore(&chan->lock, flags); + spin_unlock_irqrestore(&bigzaplock, flagso); return -EBUSY; } /* if changing confs, clear last added info */ @@ -3454,8 +3463,9 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign /* Get alias */ chans[i]->_confn = zt_get_conf_alias(conf.confno); } - copy_to_user((struct zt_confinfo *) data,&conf,sizeof(conf)); spin_unlock_irqrestore(&chan->lock, flags); + spin_unlock_irqrestore(&bigzaplock, flagso); + copy_to_user((struct zt_confinfo *) data,&conf,sizeof(conf)); break; case ZT_CONFLINK: /* do conf link stuff */ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); @@ -3465,6 +3475,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign if ((conf.confno < 0) || (conf.confno > ZT_MAX_CONF)) return(-EINVAL); /* cant listen to self!! */ if (conf.chan && (conf.chan == conf.confno)) return(-EINVAL); + spin_lock_irqsave(&bigzaplock, flagso); spin_lock_irqsave(&chan->lock, flags); /* if to clear all links */ if ((!conf.chan) && (!conf.confno)) @@ -3473,6 +3484,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign memset(conf_links,0,sizeof(conf_links)); recalc_maxlinks(); spin_unlock_irqrestore(&chan->lock, flags); + spin_unlock_irqrestore(&bigzaplock, flagso); break; } rv = 0; /* clear return value */ @@ -3523,6 +3535,7 @@ static int zt_chanandpseudo_ioctl(struct inode *inode, struct file *file, unsign } recalc_maxlinks(); spin_unlock_irqrestore(&chan->lock, flags); + spin_unlock_irqrestore(&bigzaplock, flagso); return(rv); case ZT_CONFDIAG: /* output diagnostic info to console */ if (!(chan->flags & ZT_FLAG_AUDIO)) return (-EINVAL); @@ -5722,7 +5735,7 @@ int zt_transmit(struct zt_span *span) int zt_receive(struct zt_span *span) { int x,y,z; - unsigned long flags; + unsigned long flags, flagso; #if 1 #ifdef CONFIG_ZAPTEL_WATCHDOG @@ -5800,6 +5813,9 @@ int zt_receive(struct zt_span *span) } if (span == master) { + /* Hold the big zap lock for the duration of major + activities which touch all sorts of channels */ + spin_lock_irqsave(&bigzaplock, flagso); /* Process any timers */ process_timers(); /* If we have dynamic stuff, call the ioctl with 0,0 parameters to @@ -5842,7 +5858,7 @@ int zt_receive(struct zt_span *span) #ifdef CONFIG_ZAPTEL_MMX kernel_fpu_end(); #endif - } + } /* do all the pseudo/conferenced channel transmits (putbuf's) */ for (x=1;x<maxchans;x++) { if (chans[x] && (chans[x]->flags & ZT_FLAG_PSEUDO)) { @@ -5864,18 +5880,7 @@ int zt_receive(struct zt_span *span) spin_unlock_irqrestore(&chans[x]->lock, flags); } } - spin_lock_irqsave(&zapfreelock, flags); - if (zapneedfree) { - /* Free any pseudos that might need it */ - for (x=0;x<maxchans;x++) { - if (chans[x] && (chans[x]->flags & ZT_FLAG_DEAD)) { - __zt_free_pseudo(chans[x]); - } - } - zapneedfree = 0; - } - spin_unlock_irqrestore(&zapfreelock, flags); - + spin_unlock_irqrestore(&bigzaplock, flagso); } #endif return 0; @@ -1111,7 +1111,6 @@ typedef enum { #define ZT_FLAG_LINEAR (1 << 13) /* Talk to user space in linear */ #define ZT_FLAG_PPP (1 << 14) /* PPP is available */ #define ZT_FLAG_T1PPP (1 << 15) -#define ZT_FLAG_DEAD (1 << 16) /* Dead, needs to be removed */ struct zt_span { spinlock_t lock; |