summaryrefslogtreecommitdiff
path: root/drivers/dahdi/dahdi-base.c
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2011-01-05 15:52:10 +0000
committerShaun Ruffell <sruffell@digium.com>2011-01-05 15:52:10 +0000
commit67535a6f4cec2be2aa77e5750a2ee34b664bced6 (patch)
tree564413e1b00266fd67c4655e504152bc1fac29f3 /drivers/dahdi/dahdi-base.c
parent8daf097eb584c934e742eb69bcf6fd199cc3f2b9 (diff)
dahdi: Ensure we have room to keep all span channels contiguous.
This fixes a regression from r9609 that Tzafrir reported. If you register multiple spans, then remove the first span and try to register a new span with more channels then the old span, you could end up with multiple channels with the same number. This change ensures that spans are ordered and that channels on a span are always contiguous and ordered in relation to the spans. In previous released versions of DAHDI (2.4.0 and below) this condition would result in spans that may not have contiguous blocks of channels. So it fixes both a recent regression and improves the behavior. Signed-off-by: Shaun Ruffell <sruffell@digium.com> Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9617 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/dahdi-base.c')
-rw-r--r--drivers/dahdi/dahdi-base.c99
1 files changed, 79 insertions, 20 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 1ff5089..8c32f7c 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -6442,17 +6442,89 @@ static long dahdi_ioctl_compat(struct file *file, unsigned int cmd,
}
#endif
+/**
+ * _get_next_channo - Return the next taken channel number from the span list.
+ * @span: The span with which to start the search.
+ *
+ * Returns -1 if there aren't any channels on span or any of the following
+ * spans, otherwise, returns the channel number of the first channel.
+ *
+ * Must be callled with registration_mutex held.
+ *
+ */
+static int _get_next_channo(const struct dahdi_span *span)
+{
+ const struct list_head *pos = &span->node;
+ while (pos != &span_list) {
+ span = list_entry(pos, struct dahdi_span, node);
+ if (span->channels)
+ return span->chans[0]->channo;
+ pos = pos->next;
+ }
+ return -1;
+}
+
+/**
+ * _find_spanno_and_channo - Find the next available span and channel number.
+ *
+ * Must be called with registration_mutex held.
+ *
+ */
+static struct list_head *_find_spanno_and_channo(const struct dahdi_span *span,
+ int *spanno, int *channo,
+ struct list_head *loc)
+{
+ struct dahdi_span *pos;
+ int next_channo;
+
+ *spanno = 1;
+ *channo = 1;
+
+ list_for_each_entry(pos, &span_list, node) {
+ bool skip_span;
+
+ loc = &pos->node;
+ next_channo = _get_next_channo(pos);
+
+ skip_span = (pos->spanno == *spanno) ||
+ ((next_channo > 1) &&
+ ((*channo + span->channels) > next_channo));
+
+ if (!skip_span)
+ break;
+
+ *spanno = pos->spanno + 1;
+ if (pos->channels)
+ *channo = next_channo + pos->channels;
+
+ }
+
+ return loc;
+}
+
+/**
+ * _dahdi_register - Register the span.
+ *
+ * NOTE: Must be called with the registration_mutex held.
+ *
+ */
static int _dahdi_register(struct dahdi_span *span, int prefmaster)
{
unsigned int spanno;
unsigned int x;
struct list_head *loc = &span_list;
unsigned long flags;
- unsigned int next_channo = 1;
+ unsigned int channo;
if (!span || !span->ops || !span->ops->owner)
return -EINVAL;
+ if (!list_empty(&pseudo_chans)) {
+ module_printk(KERN_ERR, "Cannot register spans while psuedo "
+ "chans are open.\n");
+ return -EINVAL;
+ }
+
if (!span->deflaw) {
module_printk(KERN_NOTICE, "Span %s didn't specify default law. "
"Assuming mulaw, please fix driver!\n", span->name);
@@ -6462,32 +6534,16 @@ static int _dahdi_register(struct dahdi_span *span, int prefmaster)
spin_lock_init(&span->lock);
- spanno = 1;
-
/* Look through the span list to find the first available span number.
* 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;
- }
- }
+ loc = _find_spanno_and_channo(span, &spanno, &channo, loc);
span->spanno = spanno;
for (x = 0; x < span->channels; x++) {
span->chans[x]->span = span;
- span->chans[x]->channo = next_channo + x;
+ span->chans[x]->channo = channo + x;
dahdi_chan_reg(span->chans[x]);
}
@@ -6517,7 +6573,10 @@ static int _dahdi_register(struct dahdi_span *span, int prefmaster)
}
spin_lock_irqsave(&chan_lock, flags);
- list_add(&span->node, loc);
+ if (loc == &span_list)
+ list_add_tail(&span->node, &span_list);
+ else
+ list_add(&span->node, loc);
spin_unlock_irqrestore(&chan_lock, flags);
set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
__dahdi_find_master_span();