From 4d10eab759646d0a3941c6b604b5557ea49c1a07 Mon Sep 17 00:00:00 2001 From: Oron Peled Date: Wed, 26 Oct 2011 19:07:59 +0000 Subject: [PATCH] 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 Signed-off-by: Shaun Ruffell git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10285 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- drivers/dahdi/dahdi-base.c | 73 ++++++++++++++++++++++++++++++++------ 1 file 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(®istration_mutex); ret = _dahdi_unassign_span(span); mutex_unlock(®istration_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(®istration_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);