[svn-commits] sruffell: linux/trunk r9609 - /linux/trunk/drivers/dahdi/dahdi-base.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jan 3 18:28:19 UTC 2011


Author: sruffell
Date: Mon Jan  3 12:28:15 2011
New Revision: 9609

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=9609
Log:
dahdi: Remove 'chans' array from reg/unreg. Now completely removed.

Remove the remaining locations the 'chans' array was referenced but keep
the observable behavior the same.  Namely, channels are numbered in
registration order.  Only now it's possible to renumber channels easily
since their number is not also their implied location in the 'chans'
array.

Signed-off-by: Shaun Ruffell <sruffell at digium.com>
Acked-by: Kinsey Moore <kmoore at digium.com>

Modified:
    linux/trunk/drivers/dahdi/dahdi-base.c

Modified: linux/trunk/drivers/dahdi/dahdi-base.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/dahdi-base.c?view=diff&rev=9609&r1=9608&r2=9609
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Mon Jan  3 12:28:15 2011
@@ -442,6 +442,9 @@
 /* The first zone on the list is the default zone. */
 static LIST_HEAD(tone_zones);
 
+/* Protects the span_list and pseudo_chans lists from concurrent access in
+ * process context.  The spin_lock is needed to synchronize with the interrupt
+ * handler. */
 static DEFINE_SPINLOCK(chan_lock);
 
 struct pseudo_chan {
@@ -454,11 +457,11 @@
 	return container_of(chan, struct pseudo_chan, chan);
 }
 
-/* This is protected by the chan_lock. */
+/* This list is protected by the chan_lock. */
 static LIST_HEAD(pseudo_chans);
 
 /**
- * is_pseudo_chan() - By definition psuedo channels are not on a span.
+ * is_pseudo_chan() - By definition pseudo channels are not on a span.
  */
 static inline bool is_pseudo_chan(const struct dahdi_chan *chan)
 {
@@ -467,14 +470,11 @@
 
 static bool valid_channo(const int channo)
 {
-	return ((channo >= DAHDI_MAX_CHANNELS) || (channo < 1)) ?
-			false : true;
+	return (channo < 1) ?  false : true;
 }
 
 static DEFINE_MUTEX(registration_mutex);
 static LIST_HEAD(span_list);
-
-static struct dahdi_chan *chans[DAHDI_MAX_CHANNELS];
 
 static unsigned long
 __for_each_channel(unsigned long (*func)(struct dahdi_chan *chan,
@@ -503,15 +503,19 @@
 	return 0;
 }
 
-static struct dahdi_chan *chan_from_num(unsigned int channo)
+/**
+ * _chan_from_num - Lookup a channel
+ *
+ * Must be called with the registration_mutex held.
+ *
+ */
+static struct dahdi_chan *_chan_from_num(unsigned int channo)
 {
 	struct dahdi_span *s;
 	struct pseudo_chan *pseudo;
 
 	if (!unlikely(valid_channo(channo)))
 		return NULL;
-
-	mutex_lock(&registration_mutex);
 
 	/* When searching for the channel amongst the spans, we can use the
 	 * fact that channels on a span must be numbered consecutively to skip
@@ -527,30 +531,34 @@
 		if (channo >= (basechan + s->channels))
 			continue;
 
-		if (unlikely(channo < basechan)) {
-			/* Looks like they are asking for a channel that has
-			 * already been removed. */
-			mutex_unlock(&registration_mutex);
+		/* Since all the spans should be on the list in sorted order,
+		 * if channo is less than base chan, the caller must be
+		 * looking for a channel that has already been removed. */
+		if (unlikely(channo < basechan))
 			return NULL;
-		}
 
 		chan = s->chans[channo - basechan];
 		WARN_ON(chan->channo != channo);
-		mutex_unlock(&registration_mutex);
 		return chan;
 	}
 
 	/* If we didn't find the channel on the list of real channels, then
 	 * it's most likely a pseudo channel. */
 	list_for_each_entry(pseudo, &pseudo_chans, node) {
-		if (pseudo->chan.channo == channo) {
-			mutex_unlock(&registration_mutex);
+		if (pseudo->chan.channo == channo)
 			return &pseudo->chan;
-		}
-	}
-
+	}
+
+	return NULL;
+}
+
+static struct dahdi_chan *chan_from_num(unsigned int channo)
+{
+	struct dahdi_chan *chan;
+	mutex_lock(&registration_mutex);
+	chan = _chan_from_num(channo);
 	mutex_unlock(&registration_mutex);
-	return NULL;
+	return chan;
 }
 
 static inline struct dahdi_chan *chan_from_file(struct file *file)
@@ -617,8 +625,7 @@
 	return !s->cannot_provide_timing;
 }
 
-static int maxchans = 0;
-static int maxconfs = 0;
+static int maxconfs;
 
 short __dahdi_mulaw[256];
 short __dahdi_alaw[256];
@@ -1431,9 +1438,10 @@
  * 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.channo member which is not set yet.
+ * This function is called before either the parent span is linked into the
+ * span list, or for pseudos, place on the psuedo_list.  Therefore, this
+ * function nor it's callers should depend on the channel being findable
+ * via those methods.
  */
 static void close_channel(struct dahdi_chan *chan)
 {
@@ -1739,11 +1747,8 @@
 	}
 }
 
-static int dahdi_chan_reg(struct dahdi_chan *chan)
-{
-	int x;
-	unsigned long flags;
-
+static void dahdi_chan_reg(struct dahdi_chan *chan)
+{
 	might_sleep();
 
 	spin_lock_init(&chan->lock);
@@ -1760,27 +1765,9 @@
 	dahdi_set_law(chan, DAHDI_LAW_DEFAULT);
 	close_channel(chan);
 
-	spin_lock_irqsave(&chan_lock, flags);
-	for (x = 1; x < DAHDI_MAX_CHANNELS; x++) {
-		if (chans[x])
-			continue;
-
-		chans[x] = chan;
-		if (maxchans < x + 1)
-			maxchans = x + 1;
-		chan->channo = x;
-		/* set this AFTER running close_channel() so that
-		   HDLC channels wont cause hangage */
-		set_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags);
-		break;
-	}
-	spin_unlock_irqrestore(&chan_lock, flags);
-	if (DAHDI_MAX_CHANNELS == x) {
-		module_printk(KERN_ERR, "No more channels available\n");
-		return -ENOMEM;
-	}
-
-	return 0;
+	/* set this AFTER running close_channel() so that
+	   HDLC channels wont cause hangage */
+	set_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags);
 }
 
 /**
@@ -2133,9 +2120,6 @@
 {
 	unsigned long flags;
 	struct dahdi_chan *const chan = (struct dahdi_chan *)data;
-
-	++maxchans;
-
 	/* Remove anyone pointing to us as master
 	   and make them their own thing */
 	if (pos->master == chan)
@@ -2187,16 +2171,14 @@
 		chan->hdlcnetdev = NULL;
 	}
 #endif
-	spin_lock_irqsave(&chan_lock, flags);
-	if (test_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags)) {
-		chans[chan->channo] = NULL;
-		clear_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags);
-	}
+	clear_bit(DAHDI_FLAGBIT_REGISTERED, &chan->flags);
+
 #ifdef CONFIG_DAHDI_PPP
 	if (chan->ppp) {
 		module_printk(KERN_NOTICE, "HUH???  PPP still attached??\n");
 	}
 #endif
+	spin_lock_irqsave(&chan_lock, flags);
 	__for_each_channel(_chan_cleanup, (unsigned long)chan);
 	spin_unlock_irqrestore(&chan_lock, flags);
 
@@ -3025,33 +3007,65 @@
 {
 	struct pseudo_chan *pseudo;
 	unsigned long flags;
+	unsigned int channo;
+	struct list_head *pos = &pseudo_chans;
+	static unsigned int first_pseudo_channo;
 
 	/* Don't allow /dev/dahdi/pseudo to open if there is not a timing
 	 * source. */
 	if (!can_open_timer())
 		return NULL;
 
-	if (!(pseudo = kzalloc(sizeof(*pseudo), GFP_KERNEL)))
+	pseudo = kzalloc(sizeof(*pseudo), GFP_KERNEL);
+	if (NULL == pseudo)
 		return NULL;
-
-	INIT_LIST_HEAD(&pseudo->node);
 
 	pseudo->chan.sig = DAHDI_SIG_CLEAR;
 	pseudo->chan.sigcap = DAHDI_SIG_CLEAR;
 	pseudo->chan.flags = DAHDI_FLAG_AUDIO;
 	pseudo->chan.span = NULL; /* No span == psuedo channel */
 
-	if (dahdi_chan_reg(&pseudo->chan)) {
-		kfree(pseudo);
-		return NULL;
-	}
-
-	spin_lock_irqsave(&chan_lock, flags);
-	list_add_tail(&pseudo->node, &pseudo_chans);
-	spin_unlock_irqrestore(&chan_lock, flags);
+	mutex_lock(&registration_mutex);
+
+	if (list_empty(&pseudo_chans)) {
+		/* If there aren't any pseudo channels allocated, we need to
+		 * take the next channel number after all the 'real' channels
+		 * on the spans. */
+		struct dahdi_span *span;
+		channo = 1;
+		list_for_each_entry_reverse(span, &span_list, node) {
+			if (unlikely(!span->channels))
+				continue;
+			channo = span->chans[0]->channo + span->channels;
+			break;
+		}
+		first_pseudo_channo = channo;
+	} else {
+		struct pseudo_chan *p;
+		/* Otherwise, we'll find the first available channo in the list
+		 * of pseudo chans. */
+		channo = first_pseudo_channo;
+		list_for_each_entry(p, &pseudo_chans, node) {
+			if (channo != p->chan.channo)
+				break;
+			pos = &p->node;
+			++channo;
+		}
+	}
+
+	pseudo->chan.channo = channo;
+	dahdi_chan_reg(&pseudo->chan);
 
 	snprintf(pseudo->chan.name, sizeof(pseudo->chan.name)-1,
 		 "Pseudo/%d", pseudo->chan.channo);
+
+	/* Once we place the pseudo chan on the list...it's registered and
+	 * live. */
+	spin_lock_irqsave(&chan_lock, flags);
+	list_add(&pseudo->node, pos);
+	spin_unlock_irqrestore(&chan_lock, flags);
+
+	mutex_unlock(&registration_mutex);
 
 	return &pseudo->chan;
 }
@@ -6357,9 +6371,9 @@
 {
 	unsigned int spanno;
 	unsigned int x;
-	int res = 0;
 	struct list_head *loc = &span_list;
 	unsigned long flags;
+	unsigned int next_channo = 1;
 
 	if (!span || !span->ops || !span->ops->owner)
 		return -EINVAL;
@@ -6376,13 +6390,19 @@
 	spanno = 1;
 
 	/* Look through the span list to find the first available span number.
-	 * The spans are kept on this list in sorted order. */
+	 * The spans are kept on this list in sorted order. We'll also save
+	 * off the next available channel number to use. */
+
 	if (!list_empty(&span_list)) {
 		struct dahdi_span *pos;
 		list_for_each_entry(pos, &span_list, node) {
 			loc = &pos->node;
 			if (pos->spanno == spanno) {
 				++spanno;
+				if (pos->channels) {
+					next_channo = pos->chans[0]->channo +
+							pos->channels;
+				}
 				continue;
 			}
 			break;
@@ -6392,12 +6412,8 @@
 	span->spanno = spanno;
 	for (x = 0; x < span->channels; x++) {
 		span->chans[x]->span = span;
-		res = dahdi_chan_reg(span->chans[x]);
-		if (res) {
-			for (x--; x >= 0; x--)
-				dahdi_chan_unreg(span->chans[x]);
-			goto unreg_channels;
-		}
+		span->chans[x]->channo = next_channo + x;
+		dahdi_chan_reg(span->chans[x]);
 	}
 
 #ifdef CONFIG_PROC_FS
@@ -6439,9 +6455,6 @@
 	set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
 
 	return 0;
-
-unreg_channels:
-	return res;
 }
 
 /**




More information about the svn-commits mailing list