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
This commit is contained in:
parent
8f4a626087
commit
4d10eab759
@ -2160,7 +2160,9 @@ static void dahdi_chan_unreg(struct dahdi_chan *chan)
|
|||||||
* file handles to this channel are disassociated with the actual
|
* file handles to this channel are disassociated with the actual
|
||||||
* dahdi_chan. */
|
* dahdi_chan. */
|
||||||
if (chan->file) {
|
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;
|
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)) {
|
if (unlikely(!chan->file->private_data)) {
|
||||||
static int rate_limit;
|
static int rate_limit;
|
||||||
|
|
||||||
if ((rate_limit % 1000) == 0)
|
if ((rate_limit++ % 1000) == 0)
|
||||||
module_printk(KERN_NOTICE, "%s: surprise removal\n", __func__);
|
module_printk(KERN_NOTICE,
|
||||||
|
"%s: (%d) nodev\n",
|
||||||
|
__func__, rate_limit);
|
||||||
msleep(5);
|
msleep(5);
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
break;
|
break;
|
||||||
@ -7022,6 +7026,25 @@ int dahdi_register_device(struct dahdi_device *ddev, struct device *parent)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(dahdi_register_device);
|
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
|
* _dahdi_unassign_span() - unassign a DAHDI span
|
||||||
* @span: the DAHDI span
|
* @span: the DAHDI span
|
||||||
@ -7088,11 +7111,28 @@ static int _dahdi_unassign_span(struct dahdi_span *span)
|
|||||||
return 0;
|
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 dahdi_unassign_span(struct dahdi_span *span)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
module_printk(KERN_NOTICE, "%s: %s\n", __func__, span->name);
|
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);
|
mutex_lock(®istration_mutex);
|
||||||
ret = _dahdi_unassign_span(span);
|
ret = _dahdi_unassign_span(span);
|
||||||
mutex_unlock(®istration_mutex);
|
mutex_unlock(®istration_mutex);
|
||||||
@ -7111,11 +7151,22 @@ void dahdi_unregister_device(struct dahdi_device *ddev)
|
|||||||
{
|
{
|
||||||
struct dahdi_span *s;
|
struct dahdi_span *s;
|
||||||
struct dahdi_span *next;
|
struct dahdi_span *next;
|
||||||
|
unsigned int spans_with_open_channels = 0;
|
||||||
|
|
||||||
WARN_ON(!ddev);
|
WARN_ON(!ddev);
|
||||||
might_sleep();
|
might_sleep();
|
||||||
if (unlikely(!ddev))
|
if (unlikely(!ddev))
|
||||||
return;
|
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);
|
mutex_lock(®istration_mutex);
|
||||||
list_for_each_entry_safe(s, next, &ddev->spans, device_node) {
|
list_for_each_entry_safe(s, next, &ddev->spans, device_node) {
|
||||||
_dahdi_unassign_span(s);
|
_dahdi_unassign_span(s);
|
||||||
@ -9095,10 +9146,11 @@ static unsigned int dahdi_timer_poll(struct file *file, struct poll_table_struct
|
|||||||
} else {
|
} else {
|
||||||
static int rate_limit;
|
static int rate_limit;
|
||||||
|
|
||||||
if ((rate_limit % 1000) == 0)
|
if ((rate_limit++ % 1000) == 0)
|
||||||
module_printk(KERN_NOTICE, "%s: nodev\n", __func__);
|
module_printk(KERN_NOTICE, "%s: (%d) nodev\n",
|
||||||
|
__func__, rate_limit);
|
||||||
msleep(5);
|
msleep(5);
|
||||||
return POLLERR | POLLHUP;
|
return POLLERR | POLLHUP | POLLRDHUP | POLLNVAL | POLLPRI;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -9114,10 +9166,11 @@ dahdi_chan_poll(struct file *file, struct poll_table_struct *wait_table)
|
|||||||
if (unlikely(!c)) {
|
if (unlikely(!c)) {
|
||||||
static int rate_limit;
|
static int rate_limit;
|
||||||
|
|
||||||
if ((rate_limit % 1000) == 0)
|
if ((rate_limit++ % 1000) == 0)
|
||||||
module_printk(KERN_NOTICE, "%s: nodev\n", __func__);
|
module_printk(KERN_NOTICE, "%s: (%d) nodev\n",
|
||||||
msleep(5);
|
__func__, rate_limit);
|
||||||
return POLLERR | POLLHUP;
|
msleep(20);
|
||||||
|
return POLLERR | POLLHUP | POLLRDHUP | POLLNVAL | POLLPRI;
|
||||||
}
|
}
|
||||||
|
|
||||||
poll_wait(file, &c->waitq, wait_table);
|
poll_wait(file, &c->waitq, wait_table);
|
||||||
|
Loading…
Reference in New Issue
Block a user