[svn-commits] sruffell: linux/trunk r5811 - /linux/trunk/drivers/dahdi/dahdi-base.c
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Mon Jan 26 01:19:47 CST 2009
Author: sruffell
Date: Mon Jan 26 01:19:47 2009
New Revision: 5811
URL: http://svn.digium.com/svn-view/dahdi?view=rev&rev=5811
Log:
Ensure the channel is in a good state before placing it on the chans arrays.
Also ensure that dahdi_receive holds the chan_lock while iterating over the
chans array to prevent channels from entering or leaving the array while the
interrupt handler is running.
Related to issue #14183 .
Modified:
linux/trunk/drivers/dahdi/dahdi-base.c
Modified: linux/trunk/drivers/dahdi/dahdi-base.c
URL: http://svn.digium.com/svn-view/dahdi/linux/trunk/drivers/dahdi/dahdi-base.c?view=diff&rev=5811&r1=5810&r2=5811
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Mon Jan 26 01:19:47 2009
@@ -1161,6 +1161,14 @@
#endif
}
+/**
+ * close_channel - close the channel, resetting any channel variables
+ * @chan: the dahdi_chan to close
+ *
+ * This function might be called before the channel is placed on the global
+ * array of channels, (chans), and therefore, neither this function nor it's
+ * children should depend on the dahdi_chan.chano member which is not set yet.
+ */
static void close_channel(struct dahdi_chan *chan)
{
unsigned long flags;
@@ -1478,43 +1486,43 @@
static int dahdi_chan_reg(struct dahdi_chan *chan)
{
int x;
- int res = 0;
unsigned long flags;
might_sleep();
+
+ spin_lock_init(&chan->lock);
+ if (!chan->master)
+ chan->master = chan;
+ if (!chan->readchunk)
+ chan->readchunk = chan->sreadchunk;
+ if (!chan->writechunk)
+ chan->writechunk = chan->swritechunk;
+ dahdi_set_law(chan, 0);
+ close_channel(chan);
write_lock_irqsave(&chan_lock, flags);
for (x = 1; x < DAHDI_MAX_CHANNELS; x++) {
if (chans[x])
continue;
- spin_lock_init(&chan->lock);
chans[x] = chan;
if (maxchans < x + 1)
maxchans = x + 1;
chan->channo = x;
- if (!chan->master)
- chan->master = chan;
- if (!chan->readchunk)
- chan->readchunk = chan->sreadchunk;
- if (!chan->writechunk)
- chan->writechunk = chan->swritechunk;
write_unlock_irqrestore(&chan_lock, flags);
- dahdi_set_law(chan, 0);
- close_channel(chan);
/* set this AFTER running close_channel() so that
HDLC channels wont cause hangage */
chan->flags |= DAHDI_FLAG_REGISTERED;
- res = 0;
break;
}
if (DAHDI_MAX_CHANNELS == x) {
write_unlock_irqrestore(&chan_lock, flags);
module_printk(KERN_ERR, "No more channels available\n");
- }
-
- return res;
+ return -ENOMEM;
+ }
+
+ return 0;
}
char *dahdi_lboname(int x)
@@ -7659,7 +7667,7 @@
int dahdi_receive(struct dahdi_span *span)
{
int x,y,z;
- unsigned long flags, flagso;
+ unsigned long flags;
#if 1
#ifdef CONFIG_DAHDI_WATCHDOG
@@ -7744,7 +7752,8 @@
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);
+ spin_lock_irqsave(&bigzaplock, flags);
+ read_lock(&chan_lock);
/* Process any timers */
process_timers();
/* If we have dynamic stuff, call the ioctl with 0,0 parameters to
@@ -7754,12 +7763,12 @@
for (x=1;x<maxchans;x++) {
if (chans[x] && chans[x]->confmode && !(chans[x]->flags & DAHDI_FLAG_PSEUDO)) {
u_char *data;
- spin_lock_irqsave(&chans[x]->lock, flags);
+ spin_lock(&chans[x]->lock);
data = __buf_peek(&chans[x]->confin);
__dahdi_receive_chunk(chans[x], data);
if (data)
__buf_pull(&chans[x]->confin, NULL,chans[x], "confreceive");
- spin_unlock_irqrestore(&chans[x]->lock, flags);
+ spin_unlock(&chans[x]->lock);
}
}
/* This is the master channel, so make things switch over */
@@ -7767,9 +7776,9 @@
/* do all the pseudo and/or conferenced channel receives (getbuf's) */
for (x=1;x<maxchans;x++) {
if (chans[x] && (chans[x]->flags & DAHDI_FLAG_PSEUDO)) {
- spin_lock_irqsave(&chans[x]->lock, flags);
+ spin_lock(&chans[x]->lock);
__dahdi_transmit_chunk(chans[x], NULL);
- spin_unlock_irqrestore(&chans[x]->lock, flags);
+ spin_unlock(&chans[x]->lock);
}
}
if (maxlinks) {
@@ -7792,21 +7801,21 @@
for (x=1;x<maxchans;x++) {
if (chans[x] && (chans[x]->flags & DAHDI_FLAG_PSEUDO)) {
unsigned char tmp[DAHDI_CHUNKSIZE];
- spin_lock_irqsave(&chans[x]->lock, flags);
+ spin_lock(&chans[x]->lock);
__dahdi_getempty(chans[x], tmp);
__dahdi_receive_chunk(chans[x], tmp);
- spin_unlock_irqrestore(&chans[x]->lock, flags);
+ spin_unlock(&chans[x]->lock);
}
}
for (x=1;x<maxchans;x++) {
if (chans[x] && chans[x]->confmode && !(chans[x]->flags & DAHDI_FLAG_PSEUDO)) {
u_char *data;
- spin_lock_irqsave(&chans[x]->lock, flags);
+ spin_lock(&chans[x]->lock);
data = __buf_pushpeek(&chans[x]->confout);
__dahdi_transmit_chunk(chans[x], data);
if (data)
__buf_push(&chans[x]->confout, NULL, "conftransmit");
- spin_unlock_irqrestore(&chans[x]->lock, flags);
+ spin_unlock(&chans[x]->lock);
}
}
#ifdef DAHDI_SYNC_TICK
@@ -7817,7 +7826,8 @@
s->sync_tick(s, s == master);
}
#endif
- spin_unlock_irqrestore(&bigzaplock, flagso);
+ read_unlock(&chan_lock);
+ spin_unlock_irqrestore(&bigzaplock, flags);
}
#endif
return 0;
More information about the svn-commits
mailing list