summaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_port.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/tty_port.c')
-rw-r--r--drivers/tty/tty_port.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 3f746c8eb0dd..1b9335796da4 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -227,6 +227,8 @@ out:
*
* Perform port level tty hangup flag and count changes. Drop the tty
* reference.
+ *
+ * Caller holds tty lock.
*/
void tty_port_hangup(struct tty_port *port)
@@ -348,6 +350,11 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
* do carrier detect and the dtr_rts method if it supports software
* management of these lines. Note that the dtr/rts raise is done each
* iteration as a hangup may have previously dropped them while we wait.
+ *
+ * Caller holds tty lock.
+ *
+ * NB: May drop and reacquire tty lock when blocking, so tty and tty_port
+ * may have changed state (eg., may have been hung up).
*/
int tty_port_block_til_ready(struct tty_port *port,
@@ -358,7 +365,7 @@ int tty_port_block_til_ready(struct tty_port *port,
DEFINE_WAIT(wait);
/* block if port is in the process of being closed */
- if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+ if (port->flags & ASYNC_CLOSING) {
wait_event_interruptible_tty(tty, port->close_wait,
!(port->flags & ASYNC_CLOSING));
if (port->flags & ASYNC_HUP_NOTIFY)
@@ -392,8 +399,7 @@ int tty_port_block_til_ready(struct tty_port *port,
/* The port lock protects the port counts */
spin_lock_irqsave(&port->lock, flags);
- if (!tty_hung_up_p(filp))
- port->count--;
+ port->count--;
port->blocked_open++;
spin_unlock_irqrestore(&port->lock, flags);
@@ -458,6 +464,10 @@ 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).
+ */
int tty_port_close_start(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{
@@ -486,9 +496,10 @@ int tty_port_close_start(struct tty_port *port,
return 0;
}
set_bit(ASYNCB_CLOSING, &port->flags);
- tty->closing = 1;
spin_unlock_irqrestore(&port->lock, flags);
+ tty->closing = 1;
+
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
/* Don't block on a stalled port, just pull the chain */
if (tty->flow_stopped)
@@ -506,13 +517,15 @@ int tty_port_close_start(struct tty_port *port,
}
EXPORT_SYMBOL(tty_port_close_start);
+/* Caller holds tty lock */
void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
+ spin_lock_irqsave(&port->lock, flags);
+
if (port->blocked_open) {
spin_unlock_irqrestore(&port->lock, flags);
if (port->close_delay) {
@@ -528,6 +541,15 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
}
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)
{
@@ -558,12 +580,19 @@ int tty_port_install(struct tty_port *port, struct tty_driver *driver,
}
EXPORT_SYMBOL_GPL(tty_port_install);
+/**
+ * tty_port_open
+ *
+ * Caller holds tty lock.
+ *
+ * NB: may drop and reacquire tty lock (in tty_port_block_til_ready()) so
+ * tty and tty_port may have changed state (eg., may be hung up now)
+ */
int tty_port_open(struct tty_port *port, struct tty_struct *tty,
struct file *filp)
{
spin_lock_irq(&port->lock);
- if (!tty_hung_up_p(filp))
- ++port->count;
+ ++port->count;
spin_unlock_irq(&port->lock);
tty_port_tty_set(port, tty);