summaryrefslogtreecommitdiff
path: root/drivers/dahdi
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2010-11-04 16:40:44 +0000
committerShaun Ruffell <sruffell@digium.com>2010-11-04 16:40:44 +0000
commitafcff233045372ea585a86eb805a0c76d3afbcfe (patch)
treedf29e2631ae6d39a4ba7ea291e9bc006c81af162 /drivers/dahdi
parent0b997fcebb6654b61eaca5acf4541f7a9797f487 (diff)
dahdi: Close race between checking IOMUX condition and sleeping.
wake_up_interruptible() will change the state of waiting tasks back to TASK_RUNNING, therefore, we want to ensure we set TASK_INTERRUPTIBLE before checking the conditions that we're going to sleep on. In practice, this closes a small window were the caller may be put to sleep when the condition is true, and have to wait for another event to come in order to wake from the sleep. Signed-off-by: Shaun Ruffell <sruffell@digium.com> Acked-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com> git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@9467 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi')
-rw-r--r--drivers/dahdi/dahdi-base.c79
1 files changed, 44 insertions, 35 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c
index 4886671..122c655 100644
--- a/drivers/dahdi/dahdi-base.c
+++ b/drivers/dahdi/dahdi-base.c
@@ -4941,67 +4941,76 @@ static int dahdi_ioctl_getconf(struct file *file, unsigned long data)
/**
* dahdi_ioctl_iomux() - Wait for *something* to happen.
*
+ * This is now basically like the wait_event_interruptible function, but with
+ * a much more involved wait condition.
*/
static int dahdi_ioctl_iomux(struct file *file, unsigned long data)
{
struct dahdi_chan *const chan = chan_from_file(file);
unsigned long flags;
int ret;
+ DEFINE_WAIT(wait);
if (!chan)
return -EINVAL;
- get_user(chan->iomask, (int __user *)data); /* save mask */
- if (!chan->iomask)return(-EINVAL); /* cant wait for nothing */
- for(;;) /* loop forever */
- {
- /* has to have SOME mask */
- ret = 0; /* start with empty return value */
+ get_user(chan->iomask, (int __user *)data);
+ if (!chan->iomask)
+ return -EINVAL;
+
+ while (1) {
+
+ ret = 0;
+ prepare_to_wait(&chan->eventbufq, &wait, TASK_INTERRUPTIBLE);
+
spin_lock_irqsave(&chan->lock, flags);
- /* if looking for read */
- if (chan->iomask & DAHDI_IOMUX_READ)
- {
+ /* if looking for read */
+ if (chan->iomask & DAHDI_IOMUX_READ) {
/* if read available */
if ((chan->outreadbuf > -1) && !chan->rxdisable)
ret |= DAHDI_IOMUX_READ;
- }
- /* if looking for write avail */
- if (chan->iomask & DAHDI_IOMUX_WRITE)
- {
+ }
+
+ /* if looking for write avail */
+ if (chan->iomask & DAHDI_IOMUX_WRITE) {
if (chan->inwritebuf > -1)
ret |= DAHDI_IOMUX_WRITE;
- }
- /* if looking for write empty */
- if (chan->iomask & DAHDI_IOMUX_WRITEEMPTY)
- {
- /* if everything empty -- be sure the transmitter is enabled */
+ }
+ /* if looking for write empty */
+ if (chan->iomask & DAHDI_IOMUX_WRITEEMPTY) {
+ /* if everything empty -- be sure the transmitter is
+ * enabled */
chan->txdisable = 0;
if (chan->outwritebuf < 0)
ret |= DAHDI_IOMUX_WRITEEMPTY;
- }
- /* if looking for signalling event */
- if (chan->iomask & DAHDI_IOMUX_SIGEVENT)
- {
- /* if event */
+ }
+ /* if looking for signalling event */
+ if (chan->iomask & DAHDI_IOMUX_SIGEVENT) {
+ /* if event */
if (chan->eventinidx != chan->eventoutidx)
ret |= DAHDI_IOMUX_SIGEVENT;
- }
+ }
spin_unlock_irqrestore(&chan->lock, flags);
- /* if something to return, or not to wait */
- if (ret || (chan->iomask & DAHDI_IOMUX_NOWAIT))
- {
- /* set return value */
+
+ /* if something to return, or not to wait */
+ if (ret || (chan->iomask & DAHDI_IOMUX_NOWAIT)) {
+ /* set return value */
put_user(ret, (int __user *)data);
break; /* get out of loop */
- }
+ }
- interruptible_sleep_on(&chan->eventbufq);
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
- /* clear IO MUX mask */
+ if (!signal_pending(current)) {
+ schedule();
+ continue;
+ }
+
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ finish_wait(&chan->eventbufq, &wait);
chan->iomask = 0;
- return 0;
+ return ret;
}
static int