tty: introduce wait_event_interruptible_tty
Arnd Bergmann [Tue, 1 Jun 2010 20:53:05 +0000 (22:53 +0200)]
Calling wait_event_interruptible implicitly
releases the BKL when it sleeps, but we need
to do this explcitly when we have converted
it to a mutex.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

drivers/char/cyclades.c
drivers/char/istallion.c
drivers/char/n_r3964.c
drivers/char/tty_port.c
drivers/char/vt_ioctl.c
drivers/serial/crisv10.c
include/linux/tty.h

index 51acfe3..27aad94 100644 (file)
@@ -1607,7 +1607,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
         * If the port is the middle of closing, bail out now
         */
        if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
-               wait_event_interruptible(info->port.close_wait,
+               wait_event_interruptible_tty(info->port.close_wait,
                                !(info->port.flags & ASYNC_CLOSING));
                return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
        }
index 5e9a81d..be28391 100644 (file)
@@ -954,7 +954,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l
  *     order of opens and closes may not be preserved across shared
  *     memory, so we must wait until it is complete.
  */
-       wait_event_interruptible(portp->raw_wait,
+       wait_event_interruptible_tty(portp->raw_wait,
                        !test_bit(ST_CLOSING, &portp->state));
        if (signal_pending(current)) {
                return -ERESTARTSYS;
@@ -989,7 +989,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l
        set_bit(ST_OPENING, &portp->state);
        spin_unlock_irqrestore(&brd_lock, flags);
 
-       wait_event_interruptible(portp->raw_wait,
+       wait_event_interruptible_tty(portp->raw_wait,
                        !test_bit(ST_OPENING, &portp->state));
        if (signal_pending(current))
                rc = -ERESTARTSYS;
@@ -1020,7 +1020,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned
  *     occurs on this port.
  */
        if (wait) {
-               wait_event_interruptible(portp->raw_wait,
+               wait_event_interruptible_tty(portp->raw_wait,
                                !test_bit(ST_CLOSING, &portp->state));
                if (signal_pending(current)) {
                        return -ERESTARTSYS;
@@ -1052,7 +1052,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned
  *     to come back.
  */
        rc = 0;
-       wait_event_interruptible(portp->raw_wait,
+       wait_event_interruptible_tty(portp->raw_wait,
                        !test_bit(ST_CLOSING, &portp->state));
        if (signal_pending(current))
                rc = -ERESTARTSYS;
@@ -1073,6 +1073,10 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned
 
 static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
 {
+       /*
+        * no need for wait_event_tty because clearing ST_CMDING cannot block
+        * on BTM
+        */
        wait_event_interruptible(portp->raw_wait,
                        !test_bit(ST_CMDING, &portp->state));
        if (signal_pending(current))
index f4bd259..a98290d 100644 (file)
@@ -1079,7 +1079,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
                                goto unlock;
                        }
                        /* block until there is a message: */
-                       wait_event_interruptible(pInfo->read_wait,
+                       wait_event_interruptible_tty(pInfo->read_wait,
                                        (pMsg = remove_msg(pInfo, pClient)));
                }
 
index a3bd1d0..35eb304 100644 (file)
@@ -231,7 +231,7 @@ int tty_port_block_til_ready(struct tty_port *port,
 
        /* block if port is in the process of being closed */
        if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-               wait_event_interruptible(port->close_wait,
+               wait_event_interruptible_tty(port->close_wait,
                                !(port->flags & ASYNC_CLOSING));
                if (port->flags & ASYNC_HUP_NOTIFY)
                        return -EAGAIN;
index cf87c53..2bbeaae 100644 (file)
@@ -133,7 +133,7 @@ static void vt_event_wait(struct vt_event_wait *vw)
        list_add(&vw->list, &vt_events);
        spin_unlock_irqrestore(&vt_event_lock, flags);
        /* Wait for it to pass */
-       wait_event_interruptible(vt_event_waitqueue, vw->done);
+       wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
        /* Dequeue it */
        spin_lock_irqsave(&vt_event_lock, flags);
        list_del(&vw->list);
@@ -1761,10 +1761,13 @@ int vt_move_to_console(unsigned int vt, int alloc)
                return -EIO;
        }
        release_console_sem();
+       tty_lock();
        if (vt_waitactive(vt + 1)) {
                pr_debug("Suspend: Can't switch VCs.");
+               tty_unlock();
                return -EINTR;
        }
+       tty_unlock();
        return prev;
 }
 
index f848e18..94bfb9f 100644 (file)
@@ -3992,7 +3992,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
         */
        if (tty_hung_up_p(filp) ||
            (info->flags & ASYNC_CLOSING)) {
-               wait_event_interruptible(info->close_wait,
+               wait_event_interruptible_tty(info->close_wait,
                        !(info->flags & ASYNC_CLOSING));
 #ifdef SERIAL_DO_RESTART
                if (info->flags & ASYNC_HUP_NOTIFY)
@@ -4150,7 +4150,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
         */
        if (tty_hung_up_p(filp) ||
            (info->flags & ASYNC_CLOSING)) {
-               wait_event_interruptible(info->close_wait,
+               wait_event_interruptible_tty(info->close_wait,
                        !(info->flags & ASYNC_CLOSING));
 #ifdef SERIAL_DO_RESTART
                return ((info->flags & ASYNC_HUP_NOTIFY) ?
index 6ead6b6..955d72e 100644 (file)
@@ -607,5 +607,47 @@ static inline void tty_unlock(void) __releases(kernel_lock)
 }
 #define tty_locked()           (kernel_locked())
 
+/*
+ * wait_event_interruptible_tty -- wait for a condition with the tty lock held
+ *
+ * The condition we are waiting for might take a long time to
+ * become true, or might depend on another thread taking the
+ * BTM. In either case, we need to drop the BTM to guarantee
+ * forward progress. This is a leftover from the conversion
+ * from the BKL and should eventually get removed as the BTM
+ * falls out of use.
+ *
+ * Do not use in new code.
+ */
+#define wait_event_interruptible_tty(wq, condition)                    \
+({                                                                     \
+       int __ret = 0;                                                  \
+       if (!(condition)) {                                             \
+               __wait_event_interruptible_tty(wq, condition, __ret);   \
+       }                                                               \
+       __ret;                                                          \
+})
+
+#define __wait_event_interruptible_tty(wq, condition, ret)             \
+do {                                                                   \
+       DEFINE_WAIT(__wait);                                            \
+                                                                       \
+       for (;;) {                                                      \
+               prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE);      \
+               if (condition)                                          \
+                       break;                                          \
+               if (!signal_pending(current)) {                         \
+                       tty_unlock();                                   \
+                       schedule();                                     \
+                       tty_lock();                                     \
+                       continue;                                       \
+               }                                                       \
+               ret = -ERESTARTSYS;                                     \
+               break;                                                  \
+       }                                                               \
+       finish_wait(&wq, &__wait);                                      \
+} while (0)
+
+
 #endif /* __KERNEL__ */
 #endif