Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty: Remove tty_wait_until_sent_from_close()

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>

authored by

Peter Hurley and committed by
Greg Kroah-Hartman
79c1faa4 32ede4a5

+5 -30
+1 -1
drivers/isdn/i4l/isdn_tty.c
··· 1582 1582 * line status register. 1583 1583 */ 1584 1584 if (port->flags & ASYNC_INITIALIZED) { 1585 - tty_wait_until_sent_from_close(tty, 3000); /* 30 seconds timeout */ 1585 + tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ 1586 1586 /* 1587 1587 * Before we drop DTR, make sure the UART transmitter 1588 1588 * has completely drained; this is especially
+1 -1
drivers/tty/hvc/hvc_console.c
··· 418 418 * there is no buffered data otherwise sleeps on a wait queue 419 419 * waking periodically to check chars_in_buffer(). 420 420 */ 421 - tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT); 421 + tty_wait_until_sent(tty, HVC_CLOSE_WAIT); 422 422 } else { 423 423 if (hp->port.count < 0) 424 424 printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
+1 -1
drivers/tty/hvc/hvcs.c
··· 1230 1230 irq = hvcsd->vdev->irq; 1231 1231 spin_unlock_irqrestore(&hvcsd->lock, flags); 1232 1232 1233 - tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT); 1233 + tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); 1234 1234 1235 1235 /* 1236 1236 * This line is important because it tells hvcs_open that this
+2 -9
drivers/tty/tty_port.c
··· 463 463 schedule_timeout_interruptible(timeout); 464 464 } 465 465 466 - /* Caller holds tty lock. 467 - * NB: may drop and reacquire tty lock (in tty_wait_until_sent_from_close()) 468 - * so tty and tty port may have changed state (but not hung up or reopened). 469 - */ 466 + /* Caller holds tty lock. */ 470 467 int tty_port_close_start(struct tty_port *port, 471 468 struct tty_struct *tty, struct file *filp) 472 469 { ··· 499 502 if (tty->flow_stopped) 500 503 tty_driver_flush_buffer(tty); 501 504 if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) 502 - tty_wait_until_sent_from_close(tty, port->closing_wait); 505 + tty_wait_until_sent(tty, port->closing_wait); 503 506 if (port->drain_delay) 504 507 tty_port_drain_delay(port, tty); 505 508 } ··· 540 543 * tty_port_close 541 544 * 542 545 * Caller holds tty lock 543 - * 544 - * NB: may drop and reacquire tty lock (in tty_port_close_start()-> 545 - * tty_wait_until_sent_from_close()) so tty and tty_port may have changed 546 - * state (but not hung up or reopened). 547 546 */ 548 547 void tty_port_close(struct tty_port *port, struct tty_struct *tty, 549 548 struct file *filp)
-18
include/linux/tty.h
··· 657 657 extern void __lockfunc tty_unlock_slave(struct tty_struct *tty); 658 658 extern void tty_set_lock_subclass(struct tty_struct *tty); 659 659 /* 660 - * this shall be called only from where BTM is held (like close) 661 - * 662 - * We need this to ensure nobody waits for us to finish while we are waiting. 663 - * Without this we were encountering system stalls. 664 - * 665 - * This should be indeed removed with BTM removal later. 666 - * 667 - * Locking: BTM required. Nobody is allowed to hold port->mutex. 668 - */ 669 - static inline void tty_wait_until_sent_from_close(struct tty_struct *tty, 670 - long timeout) 671 - { 672 - tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */ 673 - tty_wait_until_sent(tty, timeout); 674 - tty_lock(tty); 675 - } 676 - 677 - /* 678 660 * wait_event_interruptible_tty -- wait for a condition with the tty lock held 679 661 * 680 662 * The condition we are waiting for might take a long time to