summaryrefslogtreecommitdiff
path: root/drivers/dahdi/dahdi-base.c
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2011-01-03 18:28:24 +0000
committerShaun Ruffell <sruffell@digium.com>2011-01-03 18:28:24 +0000
commit8d131d04b5dad71781a9efc2f6685511c518606c (patch)
treed7bb1bbc0a4b29048895ade8b69e2e0aa385ed67 /drivers/dahdi/dahdi-base.c
parentd1adf4dd4521039444076028a94d72389221763b (diff)
dahdi: Do not locate new master in interrupt context.
When a span goes into alarm it will look for a potential new master span. For dynamic spans that are running their processing in the sync_tick callback, the chan_lock will already be held. Therefore, push the locating of a new master out to the global workqueue. 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@9611 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/dahdi-base.c')
-rw-r--r--drivers/dahdi/dahdi-base.c94
1 files changed, 63 insertions, 31 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 0c9d9f3..3e497f6 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -3681,10 +3681,55 @@ void dahdi_alarm_channel(struct dahdi_chan *chan, int alarms)
spin_unlock_irqrestore(&chan->lock, flags);
}
+static void __dahdi_find_master_span(void)
+{
+ struct dahdi_span *s;
+ unsigned long flags;
+ struct dahdi_span *old_master;
+
+ spin_lock_irqsave(&chan_lock, flags);
+ old_master = master;
+ list_for_each_entry(s, &span_list, node) {
+ if (s->alarms)
+ continue;
+ if (!test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags))
+ continue;
+ if (!can_provide_timing(s))
+ continue;
+ if (master == s)
+ continue;
+
+ master = s;
+ break;
+ }
+ spin_unlock_irqrestore(&chan_lock, flags);
+
+ if ((debug & DEBUG_MAIN) && (old_master != master))
+ module_printk(KERN_NOTICE, "Master changed to %s\n", s->name);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void _dahdi_find_master_span(void *work)
+{
+ __dahdi_find_master_span();
+}
+static DECLARE_WORK(find_master_work, _dahdi_find_master_span, NULL);
+#else
+static void _dahdi_find_master_span(struct work_struct *work)
+{
+ __dahdi_find_master_span();
+}
+static DECLARE_WORK(find_master_work, _dahdi_find_master_span);
+#endif
+
+static void dahdi_find_master_span(void)
+{
+ schedule_work(&find_master_work);
+}
+
void dahdi_alarm_notify(struct dahdi_span *span)
{
int x;
- unsigned long flags;
span->alarms &= ~DAHDI_ALARM_LOOPBACK;
/* Determine maint status */
@@ -3695,32 +3740,13 @@ void dahdi_alarm_notify(struct dahdi_span *span)
as ((!a) != (!b)) */
/* if change in general state */
if ((!span->alarms) != (!span->lastalarms)) {
- struct dahdi_span *s;
span->lastalarms = span->alarms;
for (x = 0; x < span->channels; x++)
dahdi_alarm_channel(span->chans[x], span->alarms);
- /* Switch to other master if current master in alarm */
- spin_lock_irqsave(&chan_lock, flags);
- list_for_each_entry(s, &span_list, node) {
- if (s->alarms)
- continue;
- if (!test_bit(DAHDI_FLAGBIT_RUNNING, &s->flags))
- continue;
- if (!can_provide_timing(s))
- continue;
- if (master == s)
- continue;
-
- if (debug & DEBUG_MAIN) {
- module_printk(KERN_NOTICE,
- "Master changed to %s\n",
- s->name);
- }
- master = s;
- break;
- }
- spin_unlock_irqrestore(&chan_lock, flags);
+ /* If we're going into or out of alarm we should try to find a
+ * new master that may be a better fit. */
+ dahdi_find_master_span();
/* Report more detailed alarms */
if (debug & DEBUG_MAIN) {
@@ -6448,18 +6474,11 @@ static int _dahdi_register(struct dahdi_span *span, int prefmaster)
"%d channels\n", span->spanno, span->name, span->channels);
}
- if (!master && can_provide_timing(span)) {
- master = span;
- if (debug & DEBUG_MAIN) {
- module_printk(KERN_NOTICE, "Span ('%s') is new master\n",
- span->name);
- }
- }
-
spin_lock_irqsave(&chan_lock, flags);
list_add(&span->node, loc);
spin_unlock_irqrestore(&chan_lock, flags);
set_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags);
+ __dahdi_find_master_span();
return 0;
}
@@ -9238,6 +9257,18 @@ static int __init dahdi_init(void)
return res;
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static inline void flush_find_master_work(void)
+{
+ flush_scheduled_work();
+}
+#else
+static inline void flush_find_master_work(void)
+{
+ cancel_work_sync(&find_master_work);
+}
+#endif
+
static void __exit dahdi_cleanup(void)
{
struct dahdi_zone *z;
@@ -9274,6 +9305,7 @@ static void __exit dahdi_cleanup(void)
#ifdef CONFIG_DAHDI_WATCHDOG
watchdog_cleanup();
#endif
+ flush_find_master_work();
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)