diff options
Diffstat (limited to 'drivers/tty/tty_port.c')
-rw-r--r-- | drivers/tty/tty_port.c | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 3f746c8eb0d..1b9335796da 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); |