[svn-commits] tzafrir: linux/trunk r10270 - in /linux/trunk/drivers/dahdi: ./ xpp/
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Wed Oct 26 13:56:47 CDT 2011
Author: tzafrir
Date: Wed Oct 26 13:56:43 2011
New Revision: 10270
URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=10270
Log:
dahdi: start handling "surprise device removal".
This patch contains interim results while trying to make
device removal work correctly:
* XPP has protections to prevent dahdi unregistration while
channels are open -- they are now removed, so we can
unregister immediately.
* Handle processes in poll_wait():
- Wake them during dahdi_chan_unreg() after the channel
is gone (chan->channo = -1 or chan->file->private_data == NULL)
- Test in every wait_event_interruptible() that the channel
was not gone (chan->file->private_data)
- Return correct values (POLLERR | POLLHUP) instead of
some errno (would be important in the future if we
modify asterisk to respond correctly to this condition.
* Other issues:
- If unregistered channel is being polled, than call msleep() before
returning, to give other processes a chance (normally, asterisk
has RT priority)
- Call close_channel() from dahdi_chan_unreg() so it releases
related tonezone
* There is still a horrible race hidden by msleep(20) in
dahdi_chan_unreg()
force close channels from dahdi_chan_unreg():
* Mark them via DAHDI_FLAGBIT_OPEN
* Call low-level driver close() method if available
* What about other closing activities?
Signed-off-by: Oron Peled <oron.peled at xorcom.com>
Signed-off-by: Shaun Ruffell <sruffell at digium.com>
Modified:
linux/trunk/drivers/dahdi/dahdi-base.c
linux/trunk/drivers/dahdi/xpp/xpp_dahdi.c
Modified: linux/trunk/drivers/dahdi/dahdi-base.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/dahdi-base.c?view=diff&rev=10270&r1=10269&r2=10270
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Wed Oct 26 13:56:43 2011
@@ -2151,9 +2151,8 @@
* file handles to this channel are disassociated with the actual
* dahdi_chan. */
if (chan->file) {
+ module_printk(KERN_NOTICE, "%s: surprise removal\n", __func__);
chan->file->private_data = NULL;
- if (chan->span)
- module_put(chan->span->ops->owner);
}
release_echocan(chan->ec_factory);
@@ -2178,6 +2177,40 @@
spin_unlock_irqrestore(&chan_lock, flags);
chan->channo = -1;
+
+ /* Let processeses out of their poll_wait() */
+ wake_up_interruptible(&chan->waitq);
+
+ /* release tone_zone */
+ close_channel(chan);
+
+ if (chan->file) {
+ if (test_bit(DAHDI_FLAGBIT_OPEN, &chan->flags)) {
+ clear_bit(DAHDI_FLAGBIT_OPEN, &chan->flags);
+ if (chan->span) {
+ if (chan->span->ops->close) {
+ int res;
+
+ res = chan->span->ops->close(chan);
+ if (res)
+ module_printk(KERN_NOTICE,
+ "%s: close() failed: %d\n",
+ __func__, res);
+ }
+ }
+ }
+ msleep(20);
+ /*
+ * FIXME: THE BIG SLEEP above, is hiding a terrible
+ * race condition:
+ * - the module_put() ahead, would allow the low-level driver
+ * to free the channel.
+ * - We should make sure no-one reference this channel
+ * from now on.
+ */
+ if (chan->span)
+ put_span(chan->span);
+ }
}
static ssize_t dahdi_chan_read(struct file *file, char __user *usrbuf,
@@ -2221,10 +2254,15 @@
break;
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
+
+ /* Wake up when data is available or when the board driver
+ * unregistered the channel. */
rv = wait_event_interruptible(chan->waitq,
- (chan->outreadbuf > -1));
+ (!chan->file->private_data || chan->outreadbuf > -1));
if (rv)
return rv;
+ if (unlikely(!chan->file->private_data))
+ return -ENODEV;
}
amnt = count;
if (chan->flags & DAHDI_FLAG_LINEAR) {
@@ -2348,11 +2386,15 @@
#endif
return -EAGAIN;
}
- /* Wait for something to be available */
+
+ /* Wake up when room in the write queue is available or when
+ * the board driver unregistered the channel. */
rv = wait_event_interruptible(chan->waitq,
- (chan->inwritebuf >= 0));
+ (!chan->file->private_data || chan->inwritebuf > -1));
if (rv)
return rv;
+ if (unlikely(!chan->file->private_data))
+ return -ENODEV;
}
amnt = count;
@@ -5411,6 +5453,7 @@
struct dahdi_chan *const chan = chan_from_file(file);
unsigned long flags;
unsigned int iomask;
+ int ret = 0;
DEFINE_WAIT(wait);
if (get_user(iomask, (int __user *)data))
@@ -5424,6 +5467,15 @@
wait_result = 0;
prepare_to_wait(&chan->waitq, &wait, TASK_INTERRUPTIBLE);
+ if (unlikely(!chan->file->private_data)) {
+ static int rate_limit;
+
+ if ((rate_limit % 1000) == 0)
+ module_printk(KERN_NOTICE, "%s: surprise removal\n", __func__);
+ msleep(5);
+ ret = -ENODEV;
+ break;
+ }
spin_lock_irqsave(&chan->lock, flags);
chan->iomask = iomask;
@@ -5465,7 +5517,7 @@
spin_lock_irqsave(&chan->lock, flags);
chan->iomask = 0;
spin_unlock_irqrestore(&chan->lock, flags);
- return 0;
+ return ret;
}
#ifdef CONFIG_DAHDI_MIRROR
@@ -5680,9 +5732,11 @@
if (!i)
break; /* skip if none */
rv = wait_event_interruptible(chan->waitq,
- (chan->outwritebuf > -1));
+ (!chan->file->private_data || chan->outwritebuf > -1));
if (rv)
return rv;
+ if (unlikely(!chan->file->private_data))
+ return -ENODEV;
}
break;
case DAHDI_IOMUX: /* wait for something to happen */
@@ -6355,7 +6409,9 @@
if (file->f_flags & O_NONBLOCK)
return -EINPROGRESS;
wait_event_interruptible(chan->waitq,
- is_txstate(chan, DAHDI_TXSIG_ONHOOK));
+ !chan->file->private_data || is_txstate(chan, DAHDI_TXSIG_ONHOOK));
+ if (unlikely(!chan->file->private_data))
+ return -ENODEV;
if (signal_pending(current))
return -ERESTARTSYS;
break;
@@ -6370,7 +6426,9 @@
if (file->f_flags & O_NONBLOCK)
return -EINPROGRESS;
wait_event_interruptible(chan->waitq,
- is_txstate(chan, DAHDI_TXSIG_OFFHOOK));
+ !chan->file->private_data || is_txstate(chan, DAHDI_TXSIG_OFFHOOK));
+ if (unlikely(!chan->file->private_data))
+ return -ENODEV;
if (signal_pending(current))
return -ERESTARTSYS;
break;
@@ -8743,8 +8801,14 @@
if (timer->tripped || timer->ping)
ret |= POLLPRI;
spin_unlock_irqrestore(&dahdi_timer_lock, flags);
- } else
- ret = -EINVAL;
+ } else {
+ static int rate_limit;
+
+ if ((rate_limit % 1000) == 0)
+ module_printk(KERN_NOTICE, "%s: nodev\n", __func__);
+ msleep(5);
+ return POLLERR | POLLHUP;
+ }
return ret;
}
@@ -8756,8 +8820,14 @@
int ret = 0;
unsigned long flags;
- if (unlikely(!c))
- return -EINVAL;
+ 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;
+ }
poll_wait(file, &c->waitq, wait_table);
Modified: linux/trunk/drivers/dahdi/xpp/xpp_dahdi.c
URL: http://svnview.digium.com/svn/dahdi/linux/trunk/drivers/dahdi/xpp/xpp_dahdi.c?view=diff&rev=10270&r1=10269&r2=10270
==============================================================================
--- linux/trunk/drivers/dahdi/xpp/xpp_dahdi.c (original)
+++ linux/trunk/drivers/dahdi/xpp/xpp_dahdi.c Wed Oct 26 13:56:43 2011
@@ -734,7 +734,6 @@
return -EINVAL;
}
xpd = chan->pvt;
- xpd = get_xpd(__FUNCTION__, xpd); /* Returned in xpp_close() */
if (!xpd) {
NOTICE("open called on a chan with no pvt (xpd)\n");
BUG();
@@ -776,7 +775,6 @@
current->comm, current->pid,
atomic_read(&PHONEDEV(xpd).open_counter));
atomic_dec(&PHONEDEV(xpd).open_counter); /* from xpp_open() */
- put_xpd(__FUNCTION__, xpd); /* from xpp_open() */
return 0;
}
@@ -1024,12 +1022,6 @@
return -EIDRM;
}
update_xpd_status(xpd, DAHDI_ALARM_NOTOPEN);
- /* We should now have only a ref from the xbus (from create_xpd()) */
- if(atomic_read(&PHONEDEV(xpd).open_counter)) {
- XPD_NOTICE(xpd, "Busy (open_counter=%d). Skipping.\n", atomic_read(&PHONEDEV(xpd).open_counter));
- spin_unlock_irqrestore(&xpd->lock, flags);
- return -EBUSY;
- }
mdelay(2); // FIXME: This is to give chance for transmit/receiveprep to finish.
spin_unlock_irqrestore(&xpd->lock, flags);
if(xpd->card_present)
More information about the svn-commits
mailing list