summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>2011-10-26 19:07:59 +0000
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>2011-10-26 19:07:59 +0000
commit464821924efbb2a29229419c32f953a1a6135e10 (patch)
tree62bac5279ecbc1a37f891504914579e9b6986ac8
parent5cf4ddab6a2ef6433b95808d058aa6e20c5876de (diff)
dahdi: Give userspace a chance to respond to surprise removal.
* We try very hard to help asterisk understand that we unassign spans. * Implement disable_span(): - Set span + channels to DAHDI_ALARM_NOTOPEN - qevent DAHDI_EVENT_REMOVED * Use disable_span(): - in dahdi_unassign_span() and dahdi_unregister_device() - with long msleep() so asterisk has a chance to get the message - Out of the registration_mutex so we actually context switch. * Also return more POLLERR variants (POLLRDHUP is not portable, should be tested). * Also improve printk(), fix rate_limit increment (was missing) Signed-off-by: Oron Peled <oron.peled@xorcom.com> Signed-off-by: Shaun Ruffell <sruffell@digium.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10285 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/dahdi-base.c73
1 files changed, 63 insertions, 10 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 041645c..9841cd7 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -2160,7 +2160,9 @@ static void dahdi_chan_unreg(struct dahdi_chan *chan)
* file handles to this channel are disassociated with the actual
* dahdi_chan. */
if (chan->file) {
- module_printk(KERN_NOTICE, "%s: surprise removal\n", __func__);
+ module_printk(KERN_NOTICE,
+ "%s: surprise removal: chan %d\n",
+ __func__, chan->channo);
chan->file->private_data = NULL;
}
@@ -5499,8 +5501,10 @@ static int dahdi_ioctl_iomux(struct file *file, unsigned long data)
if (unlikely(!chan->file->private_data)) {
static int rate_limit;
- if ((rate_limit % 1000) == 0)
- module_printk(KERN_NOTICE, "%s: surprise removal\n", __func__);
+ if ((rate_limit++ % 1000) == 0)
+ module_printk(KERN_NOTICE,
+ "%s: (%d) nodev\n",
+ __func__, rate_limit);
msleep(5);
ret = -ENODEV;
break;
@@ -7022,6 +7026,25 @@ int dahdi_register_device(struct dahdi_device *ddev, struct device *parent)
}
EXPORT_SYMBOL(dahdi_register_device);
+static void disable_span(struct dahdi_span *span)
+{
+ int x;
+ unsigned long flags;
+
+ spin_lock_irqsave(&span->lock, flags);
+ span->alarms = DAHDI_ALARM_NOTOPEN;
+ for (x = 0; x < span->channels; x++) {
+ /*
+ * This event may not make it to user space before the channel
+ * is gone, but let's try.
+ */
+ dahdi_qevent_lock(span->chans[x], DAHDI_EVENT_REMOVED);
+ }
+ dahdi_alarm_notify(span);
+ spin_unlock_irqrestore(&span->lock, flags);
+ module_printk(KERN_INFO, "%s: span %d\n", __func__, span->spanno);
+}
+
/**
* _dahdi_unassign_span() - unassign a DAHDI span
* @span: the DAHDI span
@@ -7088,11 +7111,28 @@ static int _dahdi_unassign_span(struct dahdi_span *span)
return 0;
}
+static int open_channel_count(const struct dahdi_span *span)
+{
+ int i;
+ int open_channels = 0;
+ struct dahdi_chan *chan;
+
+ for (i = 0; i < span->channels; ++i) {
+ chan = span->chans[i];
+ if (test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags))
+ ++open_channels;
+ }
+ return open_channels;
+}
+
int dahdi_unassign_span(struct dahdi_span *span)
{
int ret;
module_printk(KERN_NOTICE, "%s: %s\n", __func__, span->name);
+ disable_span(span);
+ if (open_channel_count(span) > 0)
+ msleep(1000); /* Give user space a chance to read this */
mutex_lock(&registration_mutex);
ret = _dahdi_unassign_span(span);
mutex_unlock(&registration_mutex);
@@ -7111,11 +7151,22 @@ void dahdi_unregister_device(struct dahdi_device *ddev)
{
struct dahdi_span *s;
struct dahdi_span *next;
+ unsigned int spans_with_open_channels = 0;
+
WARN_ON(!ddev);
might_sleep();
if (unlikely(!ddev))
return;
+ list_for_each_entry_safe(s, next, &ddev->spans, device_node) {
+ disable_span(s);
+ if (open_channel_count(s) > 0)
+ ++spans_with_open_channels;
+ }
+
+ if (spans_with_open_channels > 0)
+ msleep(1000); /* give user space a chance to read this */
+
mutex_lock(&registration_mutex);
list_for_each_entry_safe(s, next, &ddev->spans, device_node) {
_dahdi_unassign_span(s);
@@ -9095,10 +9146,11 @@ static unsigned int dahdi_timer_poll(struct file *file, struct poll_table_struct
} else {
static int rate_limit;
- if ((rate_limit % 1000) == 0)
- module_printk(KERN_NOTICE, "%s: nodev\n", __func__);
+ if ((rate_limit++ % 1000) == 0)
+ module_printk(KERN_NOTICE, "%s: (%d) nodev\n",
+ __func__, rate_limit);
msleep(5);
- return POLLERR | POLLHUP;
+ return POLLERR | POLLHUP | POLLRDHUP | POLLNVAL | POLLPRI;
}
return ret;
}
@@ -9114,10 +9166,11 @@ dahdi_chan_poll(struct file *file, struct poll_table_struct *wait_table)
if (unlikely(!c)) {
static int rate_limit;
- if ((rate_limit % 1000) == 0)
- module_printk(KERN_NOTICE, "%s: nodev\n", __func__);
- msleep(5);
- return POLLERR | POLLHUP;
+ if ((rate_limit++ % 1000) == 0)
+ module_printk(KERN_NOTICE, "%s: (%d) nodev\n",
+ __func__, rate_limit);
+ msleep(20);
+ return POLLERR | POLLHUP | POLLRDHUP | POLLNVAL | POLLPRI;
}
poll_wait(file, &c->waitq, wait_table);