Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79c1faa4 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman
Browse files

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 a57a7bf3
("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 0911261d ("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: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 32ede4a5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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",
+1 −1
Original line number Diff line number Diff line
@@ -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
+2 −9
Original line number Diff line number Diff line
@@ -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)
+0 −18
Original line number Diff line number Diff line
@@ -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
 *