[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