tty: Remove tty_wait_until_sent_from_close()
authorPeter Hurley <peter@hurleysoftware.com>
Sat, 10 Oct 2015 20:00:51 +0000 (16:00 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 18 Oct 2015 04:11:29 +0000 (21:11 -0700)
tty_wait_until_sent_from_close() drops the tty lock while waiting
for the tty driver to finish sending previously accepted data (ie.,
data remaining in its write buffer and transmit fifo).

tty_wait_until_sent_from_close() was added by commit a57a7bf3fc7e
("TTY: define tty_wait_until_sent_from_close") to prevent the entire
tty subsystem from being unable to open new ttys while waiting for
one tty to close while output drained.

However, since commit 0911261d4cb6 ("tty: Don't take tty_mutex for tty
count changes"), holding a tty lock while closing does not prevent other
ttys from being opened/closed/hung up, but only prevents lifetime event
changes for the tty under lock.

Holding the tty lock while waiting for output to drain does prevent
parallel non-blocking opens (O_NONBLOCK) from advancing or returning
while the tty lock is held. However, all parallel opens _already_
block even if the tty lock is dropped while closing and the parallel
open advances. Blocking in open has been in mainline since at least 2.6.29
(see tty_port_block_til_ready(); note the test for O_NONBLOCK is _after_
the wait while ASYNC_CLOSING).

IOW, before this patch a non-blocking open will sleep anyway for the
_entire_ duration of a parallel hardware shutdown, and when it wakes, the
error return will cause a release of its tty, and it will restart with
a fresh attempt to open. Similarly with a blocking open that is already
waiting; when it's woken, the hardware shutdown has already completed
to ASYNC_INITIALIZED is not set, which forces a release and restart as
well.

So, holding the tty lock across the _entire_ close (which is what this
patch does), even while waiting for output to drain, is equivalent to
the current outcome wrt parallel opens.

Cc: Alan Cox <alan@linux.intel.com>
Cc: David Laight <David.Laight@aculab.com>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Karsten Keil <isdn@linux-pingi.de>
CC: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/isdn/i4l/isdn_tty.c
drivers/tty/hvc/hvc_console.c
drivers/tty/hvc/hvcs.c
drivers/tty/tty_port.c
include/linux/tty.h

index bc912611fe0974d7cb3c6759158210aafbf9ec02..2175225af74214c925ae1202a5c3771bf0608b7c 100644 (file)
@@ -1582,7 +1582,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
         * line status register.
         */
        if (port->flags & ASYNC_INITIALIZED) {
-               tty_wait_until_sent_from_close(tty, 3000);      /* 30 seconds timeout */
+               tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
                /*
                 * Before we drop DTR, make sure the UART transmitter
                 * has completely drained; this is especially
index 9c30f67c802a80df3a66e860e1bf53ba828e67ff..e46d628998f5cffb9b4be2366c635f0d9ced1b77 100644 (file)
@@ -418,7 +418,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                 * there is no buffered data otherwise sleeps on a wait queue
                 * waking periodically to check chars_in_buffer().
                 */
-               tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
+               tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
        } else {
                if (hp->port.count < 0)
                        printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
index f7ff97c0ad3499677578b7d1b68ff65c11ab74ec..5997b17311113150b93167aaaa4b1e37bb160cb3 100644 (file)
@@ -1230,7 +1230,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
                irq = hvcsd->vdev->irq;
                spin_unlock_irqrestore(&hvcsd->lock, flags);
 
-               tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT);
+               tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
 
                /*
                 * This line is important because it tells hvcs_open that this
index 40b31835f80bc0d8634960a33cc5c3b1ec6d6064..d7d9f9cde964f8b3bcc18f2fe3949c669836df27 100644 (file)
@@ -463,10 +463,7 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
        schedule_timeout_interruptible(timeout);
 }
 
-/* Caller holds tty lock.
- * NB: may drop and reacquire tty lock (in tty_wait_until_sent_from_close())
- * so tty and tty port may have changed state (but not hung up or reopened).
- */
+/* Caller holds tty lock. */
 int tty_port_close_start(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp)
 {
@@ -502,7 +499,7 @@ int tty_port_close_start(struct tty_port *port,
                if (tty->flow_stopped)
                        tty_driver_flush_buffer(tty);
                if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-                       tty_wait_until_sent_from_close(tty, port->closing_wait);
+                       tty_wait_until_sent(tty, port->closing_wait);
                if (port->drain_delay)
                        tty_port_drain_delay(port, tty);
        }
@@ -543,10 +540,6 @@ EXPORT_SYMBOL(tty_port_close_end);
  * tty_port_close
  *
  * Caller holds tty lock
- *
- * NB: may drop and reacquire tty lock (in tty_port_close_start()->
- * tty_wait_until_sent_from_close()) so tty and tty_port may have changed
- * state (but not hung up or reopened).
  */
 void tty_port_close(struct tty_port *port, struct tty_struct *tty,
                                                        struct file *filp)
index d072ded416786631838ec0aefaf6428362b0f291..614c8224c32fd153d8179110b85a9ede781f4c23 100644 (file)
@@ -656,24 +656,6 @@ extern void __lockfunc tty_unlock(struct tty_struct *tty);
 extern void __lockfunc tty_lock_slave(struct tty_struct *tty);
 extern void __lockfunc tty_unlock_slave(struct tty_struct *tty);
 extern void tty_set_lock_subclass(struct tty_struct *tty);
-/*
- * this shall be called only from where BTM is held (like close)
- *
- * We need this to ensure nobody waits for us to finish while we are waiting.
- * Without this we were encountering system stalls.
- *
- * This should be indeed removed with BTM removal later.
- *
- * Locking: BTM required. Nobody is allowed to hold port->mutex.
- */
-static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
-               long timeout)
-{
-       tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
-       tty_wait_until_sent(tty, timeout);
-       tty_lock(tty);
-}
-
 /*
  * wait_event_interruptible_tty -- wait for a condition with the tty lock held
  *