dahdi: Remove arbitrary limit on number of spans in the kernel.

Spans are no longer added to a static array, but they are chained
together in a list.  DAHDI_MAX_SPANS, while no longer used in the
kernel, is still in include/dahdi/user.h since dahdi tools is currently
using it.

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

git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9598 a0bf4364-ded3-4de4-8d8a-66a801d63aff
This commit is contained in:
Shaun Ruffell 2011-01-03 18:27:27 +00:00
parent 7a6d71f35c
commit 800c356cf3
2 changed files with 145 additions and 147 deletions

View File

@ -471,11 +471,10 @@ static bool valid_channo(const int channo)
false : true; false : true;
} }
/* Protected by chan_lock. */ static DEFINE_MUTEX(registration_mutex);
static struct dahdi_span *spans[DAHDI_MAX_SPANS]; static LIST_HEAD(span_list);
static struct dahdi_chan *chans[DAHDI_MAX_CHANNELS];
static int maxspans = 0; static struct dahdi_chan *chans[DAHDI_MAX_CHANNELS];
static inline struct dahdi_chan *chan_from_num(unsigned int channo) static inline struct dahdi_chan *chan_from_num(unsigned int channo)
{ {
@ -488,6 +487,22 @@ static inline struct dahdi_chan *chan_from_file(struct file *file)
file->private_data : chan_from_num(UNIT(file)); file->private_data : chan_from_num(UNIT(file));
} }
/**
* _find_span() - Find a span by span number.
*
* Must be called with registration_lock held.
*
*/
static struct dahdi_span *_find_span(int spanno)
{
struct dahdi_span *s;
list_for_each_entry(s, &span_list, node) {
if (s->spanno == spanno) {
return s;
}
}
return NULL;
}
/** /**
* span_find_and_get() - Search for the span by number, and if found take out * span_find_and_get() - Search for the span by number, and if found take out
* a reference on it. * a reference on it.
@ -498,15 +513,14 @@ static inline struct dahdi_chan *chan_from_file(struct file *file)
*/ */
static struct dahdi_span *span_find_and_get(int spanno) static struct dahdi_span *span_find_and_get(int spanno)
{ {
unsigned long flags; struct dahdi_span *found;
struct dahdi_span *span;
spin_lock_irqsave(&chan_lock, flags); mutex_lock(&registration_mutex);
span = (spanno > 0 && spanno < DAHDI_MAX_SPANS) ? spans[spanno] : NULL; found = _find_span(spanno);
if (likely(span && !try_module_get(span->ops->owner))) if (found && !try_module_get(found->ops->owner))
span = NULL; found = NULL;
spin_unlock_irqrestore(&chan_lock, flags); mutex_unlock(&registration_mutex);
return span; return found;
} }
static void put_span(struct dahdi_span *span) static void put_span(struct dahdi_span *span)
@ -514,9 +528,16 @@ static void put_span(struct dahdi_span *span)
module_put(span->ops->owner); module_put(span->ops->owner);
} }
static inline unsigned int span_count(void) static unsigned int span_count(void)
{ {
return maxspans; unsigned int count = 0;
struct dahdi_span *s;
unsigned long flags;
spin_lock_irqsave(&chan_lock, flags);
list_for_each_entry(s, &span_list, node)
++count;
spin_unlock_irqrestore(&chan_lock, flags);
return count;
} }
static inline bool can_provide_timing(const struct dahdi_span *const s) static inline bool can_provide_timing(const struct dahdi_span *const s)
@ -2905,7 +2926,7 @@ static int can_open_timer(void)
#ifdef CONFIG_DAHDI_CORE_TIMER #ifdef CONFIG_DAHDI_CORE_TIMER
return 1; return 1;
#else #else
return maxspans > 0; return (list_empty(&span_list)) ? 0 : 1;
#endif #endif
} }
@ -3551,6 +3572,7 @@ void dahdi_alarm_channel(struct dahdi_chan *chan, int alarms)
void dahdi_alarm_notify(struct dahdi_span *span) void dahdi_alarm_notify(struct dahdi_span *span)
{ {
int x; int x;
unsigned long flags;
span->alarms &= ~DAHDI_ALARM_LOOPBACK; span->alarms &= ~DAHDI_ALARM_LOOPBACK;
/* Determine maint status */ /* Determine maint status */
@ -3561,15 +3583,14 @@ void dahdi_alarm_notify(struct dahdi_span *span)
as ((!a) != (!b)) */ as ((!a) != (!b)) */
/* if change in general state */ /* if change in general state */
if ((!span->alarms) != (!span->lastalarms)) { if ((!span->alarms) != (!span->lastalarms)) {
struct dahdi_span *s;
span->lastalarms = span->alarms; span->lastalarms = span->alarms;
for (x = 0; x < span->channels; x++) for (x = 0; x < span->channels; x++)
dahdi_alarm_channel(span->chans[x], span->alarms); dahdi_alarm_channel(span->chans[x], span->alarms);
/* Switch to other master if current master in alarm */ /* Switch to other master if current master in alarm */
for (x=1; x<maxspans; x++) { spin_lock_irqsave(&chan_lock, flags);
struct dahdi_span *const s = spans[x]; list_for_each_entry(s, &span_list, node) {
if (!s)
continue;
if (s->alarms) if (s->alarms)
continue; continue;
if (!test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags)) if (!test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags))
@ -3587,6 +3608,7 @@ void dahdi_alarm_notify(struct dahdi_span *span)
master = s; master = s;
break; break;
} }
spin_unlock_irqrestore(&chan_lock, flags);
/* Report more detailed alarms */ /* Report more detailed alarms */
if (debug & DEBUG_MAIN) { if (debug & DEBUG_MAIN) {
@ -6220,70 +6242,43 @@ static long dahdi_ioctl_compat(struct file *file, unsigned int cmd,
} }
#endif #endif
/** static int _dahdi_register(struct dahdi_span *span, int prefmaster)
* dahdi_register() - unregister a new DAHDI span
* @span: the DAHDI span
* @prefmaster: will the new span be preferred as a master?
*
* Registers a span for usage with DAHDI. All the channel numbers in it
* will get the lowest available channel numbers.
*
* If prefmaster is set to anything > 0, span will attempt to become the
* master DAHDI span at registration time. If 0: it will only become
* master if no other span is currently the master (i.e.: it is the
* first one).
*/
int dahdi_register(struct dahdi_span *span, int prefmaster)
{ {
int x; unsigned int spanno;
unsigned int x;
int res = 0; int res = 0;
int spanno; struct list_head *loc = &span_list;
unsigned long flags; unsigned long flags;
if (!span) if (!span || !span->ops || !span->ops->owner)
return -EINVAL; return -EINVAL;
if (!span->ops)
return -EINVAL;
if (!span->ops->owner)
return -EINVAL;
if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) {
module_printk(KERN_ERR, "Span %s already appears to be registered\n", span->name);
return -EBUSY;
}
for (x = 1; x < maxspans; x++) {
if (spans[x] == span) {
module_printk(KERN_ERR, "Span %s already in list\n", span->name);
return -EBUSY;
}
}
for (x = 1; x < DAHDI_MAX_SPANS; x++) {
if (!spans[x])
break;
}
if (x < DAHDI_MAX_SPANS) {
spanno = x;
} else {
module_printk(KERN_ERR, "Too many DAHDI spans registered\n");
return -EBUSY;
}
span->spanno = x;
spin_lock_init(&span->lock);
if (!span->deflaw) { if (!span->deflaw) {
module_printk(KERN_NOTICE, "Span %s didn't specify default law. " module_printk(KERN_NOTICE, "Span %s didn't specify default law. "
"Assuming mulaw, please fix driver!\n", span->name); "Assuming mulaw, please fix driver!\n", span->name);
span->deflaw = DAHDI_LAW_MULAW; span->deflaw = DAHDI_LAW_MULAW;
} }
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. */
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;
continue;
}
break;
}
}
span->spanno = spanno;
for (x = 0; x < span->channels; x++) { for (x = 0; x < span->channels; x++) {
span->chans[x]->span = span; span->chans[x]->span = span;
res = dahdi_chan_reg(span->chans[x]); res = dahdi_chan_reg(span->chans[x]);
@ -6297,9 +6292,9 @@ int dahdi_register(struct dahdi_span *span, int prefmaster)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
{ {
char tempfile[17]; char tempfile[17];
snprintf(tempfile, sizeof(tempfile), "dahdi/%d", span->spanno); snprintf(tempfile, sizeof(tempfile), "%d", span->spanno);
span->proc_entry = create_proc_read_entry(tempfile, 0444, span->proc_entry = create_proc_read_entry(tempfile, 0444,
NULL, dahdi_proc_read, root_proc_entry, dahdi_proc_read,
(int *) (long) span->spanno); (int *) (long) span->spanno);
} }
#endif #endif
@ -6328,61 +6323,64 @@ int dahdi_register(struct dahdi_span *span, int prefmaster)
} }
spin_lock_irqsave(&chan_lock, flags); spin_lock_irqsave(&chan_lock, flags);
spans[spanno] = span; list_add(&span->node, loc);
if (maxspans < x + 1)
maxspans = x + 1;
spin_unlock_irqrestore(&chan_lock, flags); spin_unlock_irqrestore(&chan_lock, flags);
set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags); set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
return 0; return 0;
unreg_channels: unreg_channels:
spans[span->spanno] = NULL;
return res; return res;
} }
/** /**
* dahdi_unregister() - unregister a DAHDI span * dahdi_register() - unregister a new DAHDI span
* @span: the DAHDI span * @span: the DAHDI span
* @prefmaster: will the new span be preferred as a master?
*
* Registers a span for usage with DAHDI. All the channel numbers in it
* will get the lowest available channel numbers.
*
* If prefmaster is set to anything > 0, span will attempt to become the
* master DAHDI span at registration time. If 0: it will only become
* master if no other span is currently the master (i.e.: it is the
* first one).
* *
* Unregisters a span that has been previously registered with
* dahdi_register().
*/ */
int dahdi_unregister(struct dahdi_span *span) int dahdi_register(struct dahdi_span *span, int prefmaster)
{
int ret;
mutex_lock(&registration_mutex);
ret = _dahdi_register(span, prefmaster);
mutex_unlock(&registration_mutex);
return ret;
}
static int _dahdi_unregister(struct dahdi_span *span)
{ {
int x; int x;
struct dahdi_span *new_master, *s;
unsigned long flags; unsigned long flags;
#ifdef CONFIG_PROC_FS if (span != _find_span(span->spanno)) {
char tempfile[17];
#endif /* CONFIG_PROC_FS */
if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) {
module_printk(KERN_ERR, "Span %s does not appear to be registered\n", span->name); module_printk(KERN_ERR, "Span %s does not appear to be registered\n", span->name);
return -1; return -1;
} }
/* Shutdown the span if it's running */
if (span->flags & DAHDI_FLAG_RUNNING)
if (span->ops->shutdown)
span->ops->shutdown(span);
if (spans[span->spanno] != span) {
module_printk(KERN_ERR, "Span %s has spanno %d which is something else\n", span->name, span->spanno);
return -1;
}
clear_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
spin_lock_irqsave(&chan_lock, flags); spin_lock_irqsave(&chan_lock, flags);
spans[span->spanno] = NULL; list_del_init(&span->node);
spin_unlock_irqrestore(&chan_lock, flags); spin_unlock_irqrestore(&chan_lock, flags);
span->spanno = 0;
clear_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
/* Shutdown the span if it's running */
if ((span->flags & DAHDI_FLAG_RUNNING) && span->ops->shutdown)
span->ops->shutdown(span);
if (debug & DEBUG_MAIN) if (debug & DEBUG_MAIN)
module_printk(KERN_NOTICE, "Unregistering Span '%s' with %d channels\n", span->name, span->channels); module_printk(KERN_NOTICE, "Unregistering Span '%s' with %d channels\n", span->name, span->channels);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
snprintf(tempfile, sizeof(tempfile)-1, "dahdi/%d", span->spanno); remove_proc_entry(span->proc_entry->name, root_proc_entry);
remove_proc_entry(tempfile, NULL);
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
for (x = 0; x < span->channels; x++) { for (x = 0; x < span->channels; x++) {
@ -6393,37 +6391,44 @@ int dahdi_unregister(struct dahdi_span *span)
for (x=0;x<span->channels;x++) for (x=0;x<span->channels;x++)
dahdi_chan_unreg(span->chans[x]); dahdi_chan_unreg(span->chans[x]);
if (master == span) { new_master = master; /* FIXME: locking */
struct dahdi_span *new_master = NULL; if (master == span)
int new_maxspans = 0; new_master = NULL;
spin_lock_irqsave(&chan_lock, flags); spin_lock_irqsave(&chan_lock, flags);
for (x = 1; x < DAHDI_MAX_SPANS; x++) { list_for_each_entry(s, &span_list, node) {
struct dahdi_span *const cur = spans[x]; if ((s == new_master) || !can_provide_timing(s))
if (!cur)
continue; continue;
new_master = s;
new_maxspans = x;
if (can_provide_timing(cur)) {
new_master = cur;
break; break;
} }
}
maxspans = new_maxspans;
spin_unlock_irqrestore(&chan_lock, flags); spin_unlock_irqrestore(&chan_lock, flags);
if (master != new_master) {
if (debug & DEBUG_MAIN) { if (debug & DEBUG_MAIN) {
module_printk(KERN_NOTICE, "%s: Span ('%s') is new " module_printk(KERN_NOTICE, "%s: Span ('%s') is new master\n", __FUNCTION__,
"master\n", __func__, (new_master)? new_master->name: "no master");
(new_master) ? new_master->name : }
"no master");
} }
master = new_master; master = new_master;
}
span->spanno = 0;
return 0; return 0;
} }
/**
* dahdi_unregister() - unregister a DAHDI span
* @span: the DAHDI span
*
* Unregisters a span that has been previously registered with
* dahdi_register().
*/
int dahdi_unregister(struct dahdi_span *span)
{
int ret;
mutex_lock(&registration_mutex);
ret = _dahdi_unregister(span);
mutex_unlock(&registration_mutex);
return ret;
}
/* /*
** This routine converts from linear to ulaw ** This routine converts from linear to ulaw
** **
@ -8631,8 +8636,7 @@ static inline void dahdi_sync_tick(struct dahdi_span *const s)
static void process_masterspan(void) static void process_masterspan(void)
{ {
unsigned long flags; unsigned long flags;
int x, y; int x;
struct dahdi_chan *chan;
struct pseudo_chan *pseudo; struct pseudo_chan *pseudo;
struct dahdi_span *s; struct dahdi_span *s;
u_char *data; u_char *data;
@ -8651,12 +8655,9 @@ static void process_masterspan(void)
/* Process any timers */ /* Process any timers */
process_timers(); process_timers();
for (y = 1; y < maxspans; ++y) { list_for_each_entry(s, &span_list, node) {
s = spans[y]; for (x = 0; x < s->channels; ++x) {
if (!s) struct dahdi_chan *const chan = s->chans[x];
continue;
for (x = 0; x < s->channels; x++) {
chan = s->chans[x];
if (!chan->confmode) if (!chan->confmode)
continue; continue;
spin_lock(&chan->lock); spin_lock(&chan->lock);
@ -8684,12 +8685,9 @@ static void process_masterspan(void)
pseudo_rx_audio(&pseudo->chan); pseudo_rx_audio(&pseudo->chan);
} }
for (y = 1; y < maxspans; ++y) { list_for_each_entry(s, &span_list, node) {
s = spans[y];
if (!s)
continue;
for (x = 0; x < s->channels; x++) { for (x = 0; x < s->channels; x++) {
chan = s->chans[x]; struct dahdi_chan *const chan = s->chans[x];
if (!chan->confmode) if (!chan->confmode)
continue; continue;
spin_lock(&chan->lock); spin_lock(&chan->lock);
@ -8979,14 +8977,13 @@ static struct timer_list watchdogtimer;
static void watchdog_check(unsigned long ignored) static void watchdog_check(unsigned long ignored)
{ {
int x;
unsigned long flags; unsigned long flags;
static int wdcheck=0; static int wdcheck=0;
struct dahdi_span *s;
local_irq_save(flags); spin_lock_irqsave(&span_list_lock, flags);
for (x=0;x<maxspans;x++) { list_for_each_entry(s, &span_list, node) {
s = spans[x]; if (s->flags & DAHDI_FLAG_RUNNING) {
if (s && (s->flags & DAHDI_FLAG_RUNNING)) {
if (s->watchcounter == DAHDI_WATCHDOG_INIT) { if (s->watchcounter == DAHDI_WATCHDOG_INIT) {
/* Whoops, dead card */ /* Whoops, dead card */
if ((s->watchstate == DAHDI_WATCHSTATE_OK) || if ((s->watchstate == DAHDI_WATCHSTATE_OK) ||
@ -9009,7 +9006,7 @@ static void watchdog_check(unsigned long ignored)
s->watchcounter = DAHDI_WATCHDOG_INIT; s->watchcounter = DAHDI_WATCHDOG_INIT;
} }
} }
local_irq_restore(flags); spin_unlock_irqrestore(&span_list_lock, flags);
if (!wdcheck) { if (!wdcheck) {
module_printk(KERN_NOTICE, "watchdog on duty!\n"); module_printk(KERN_NOTICE, "watchdog on duty!\n");
wdcheck=1; wdcheck=1;
@ -9137,7 +9134,7 @@ static void __exit dahdi_cleanup(void)
unregister_chrdev(DAHDI_MAJOR, "dahdi"); unregister_chrdev(DAHDI_MAJOR, "dahdi");
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
remove_proc_entry("dahdi", NULL); remove_proc_entry(root_proc_entry->name, NULL);
#endif #endif
module_printk(KERN_INFO, "Telephony Interface Unloaded\n"); module_printk(KERN_INFO, "Telephony Interface Unloaded\n");

View File

@ -898,6 +898,7 @@ struct dahdi_span {
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry; struct proc_dir_entry *proc_entry;
#endif #endif
struct list_head node;
}; };
struct dahdi_transcoder_channel { struct dahdi_transcoder_channel {