[svn-commits] sruffell: linux/trunk r9467 - /linux/trunk/drivers/dahdi/dahdi-base.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Nov 4 11:40:48 CDT 2010


Author: sruffell
Date: Thu Nov  4 11:40:44 2010
New Revision: 9467

URL: http://svnview.digium.com/svn/dahdi?view=rev&rev=9467
Log:
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 at digium.com>
Acked-by: Tzafrir Cohen <tzafrir.cohen at xorcom.com>

Modified:
    linux/trunk/drivers/dahdi/dahdi-base.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=9467&r1=9466&r2=9467
==============================================================================
--- linux/trunk/drivers/dahdi/dahdi-base.c (original)
+++ linux/trunk/drivers/dahdi/dahdi-base.c Thu Nov  4 11:40:44 2010
@@ -4941,67 +4941,76 @@
 /**
  * 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




More information about the svn-commits mailing list