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

tty: Replace ASYNC_NORMAL_ACTIVE bit and update atomically

Replace ASYNC_NORMAL_ACTIVE bit in the tty_port::flags field with
TTY_PORT_ACTIVE bit in the tty_port::iflags field. Introduce helpers
tty_port_set_active() and tty_port_active() to abstract atomic bit ops.

Extract state changes from port lock sections, as this usage is
broken and confused; the state transitions are protected by the
tty lock (which mutually excludes parallel open/close/hangup),
and no user tests the active state while holding the port lock.

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
807c8d81 5604a98e

+53 -42
+9 -11
drivers/isdn/i4l/isdn_tty.c
··· 1622 1622 return; 1623 1623 isdn_tty_shutdown(info); 1624 1624 port->count = 0; 1625 - port->flags &= ~ASYNC_NORMAL_ACTIVE; 1625 + tty_port_set_active(port, 0); 1626 1626 port->tty = NULL; 1627 1627 wake_up_interruptible(&port->open_wait); 1628 1628 } ··· 1979 1979 #endif 1980 1980 if ( 1981 1981 #ifndef FIX_FILE_TRANSFER 1982 - (info->port.flags & ASYNC_NORMAL_ACTIVE) && 1982 + tty_port_active(&info->port) && 1983 1983 #endif 1984 1984 (info->isdn_driver == -1) && 1985 1985 (info->isdn_channel == -1) && ··· 2017 2017 ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2)) ? "rejected" : "ignored"); 2018 2018 return (wret == 2) ? 3 : 0; 2019 2019 } 2020 - 2021 - #define TTY_IS_ACTIVE(info) (info->port.flags & ASYNC_NORMAL_ACTIVE) 2022 2020 2023 2021 int 2024 2022 isdn_tty_stat_callback(int i, isdn_ctrl *c) ··· 2075 2077 #ifdef ISDN_TTY_STAT_DEBUG 2076 2078 printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line); 2077 2079 #endif 2078 - if (TTY_IS_ACTIVE(info)) { 2080 + if (tty_port_active(&info->port)) { 2079 2081 if (info->dialing == 1) { 2080 2082 info->dialing = 2; 2081 2083 return 1; ··· 2086 2088 #ifdef ISDN_TTY_STAT_DEBUG 2087 2089 printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line); 2088 2090 #endif 2089 - if (TTY_IS_ACTIVE(info)) { 2091 + if (tty_port_active(&info->port)) { 2090 2092 if (info->dialing == 1) 2091 2093 isdn_tty_modem_result(RESULT_BUSY, info); 2092 2094 if (info->dialing > 1) ··· 2116 2118 * waiting for it and 2117 2119 * set DCD-bit of its modem-status. 2118 2120 */ 2119 - if (TTY_IS_ACTIVE(info) || 2121 + if (tty_port_active(&info->port) || 2120 2122 (info->port.blocked_open && 2121 2123 (info->emu.mdmreg[REG_DCD] & BIT_DCD))) { 2122 2124 info->msr |= UART_MSR_DCD; ··· 2143 2145 #ifdef ISDN_TTY_STAT_DEBUG 2144 2146 printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line); 2145 2147 #endif 2146 - if (TTY_IS_ACTIVE(info)) { 2148 + if (tty_port_active(&info->port)) { 2147 2149 #ifdef ISDN_DEBUG_MODEM_HUP 2148 2150 printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); 2149 2151 #endif ··· 2155 2157 #ifdef ISDN_TTY_STAT_DEBUG 2156 2158 printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line); 2157 2159 #endif 2158 - if (TTY_IS_ACTIVE(info)) { 2160 + if (tty_port_active(&info->port)) { 2159 2161 if (info->dialing) { 2160 2162 info->dialing = 0; 2161 2163 info->last_l2 = -1; ··· 2181 2183 return 1; 2182 2184 #ifdef CONFIG_ISDN_TTY_FAX 2183 2185 case ISDN_STAT_FAXIND: 2184 - if (TTY_IS_ACTIVE(info)) { 2186 + if (tty_port_active(&info->port)) { 2185 2187 isdn_tty_fax_command(info, c); 2186 2188 } 2187 2189 break; 2188 2190 #endif 2189 2191 #ifdef CONFIG_ISDN_AUDIO 2190 2192 case ISDN_STAT_AUDIO: 2191 - if (TTY_IS_ACTIVE(info)) { 2193 + if (tty_port_active(&info->port)) { 2192 2194 switch (c->parm.num[0]) { 2193 2195 case ISDN_AUDIO_DTMF: 2194 2196 if (info->vonline) {
+1 -1
drivers/tty/amiserial.c
··· 1493 1493 rs_flush_buffer(tty); 1494 1494 shutdown(tty, info); 1495 1495 info->tport.count = 0; 1496 - info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; 1496 + tty_port_set_active(&info->tport, 0); 1497 1497 info->tport.tty = NULL; 1498 1498 wake_up_interruptible(&info->tport.open_wait); 1499 1499 }
+3 -2
drivers/tty/rocket.c
··· 1042 1042 } 1043 1043 } 1044 1044 spin_lock_irq(&port->lock); 1045 - info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE); 1045 + port->flags &= ~ASYNC_INITIALIZED; 1046 1046 tty->closing = 0; 1047 1047 spin_unlock_irq(&port->lock); 1048 + tty_port_set_active(port, 0); 1048 1049 mutex_unlock(&port->mutex); 1049 1050 tty_port_tty_set(port, NULL); 1050 1051 ··· 1625 1624 /* Write remaining data into the port's xmit_buf */ 1626 1625 while (1) { 1627 1626 /* Hung up ? */ 1628 - if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags)) 1627 + if (!tty_port_active(&info->port)) 1629 1628 goto end; 1630 1629 c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); 1631 1630 c = min(c, XMIT_BUF_SIZE - info->xmit_head);
+4 -4
drivers/tty/serial/crisv10.c
··· 3648 3648 schedule_timeout_interruptible(info->port.close_delay); 3649 3649 wake_up_interruptible(&info->port.open_wait); 3650 3650 } 3651 - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; 3652 3651 local_irq_restore(flags); 3652 + tty_port_set_active(&info->port, 0); 3653 3653 3654 3654 /* port closed */ 3655 3655 ··· 3732 3732 shutdown(info); 3733 3733 info->event = 0; 3734 3734 info->port.count = 0; 3735 - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; 3735 + tty_port_set_active(&info->port, 0); 3736 3736 info->port.tty = NULL; 3737 3737 wake_up_interruptible(&info->port.open_wait); 3738 3738 } ··· 3756 3756 * then make the check up front and then exit. 3757 3757 */ 3758 3758 if ((filp->f_flags & O_NONBLOCK) || tty_io_error(tty)) { 3759 - info->port.flags |= ASYNC_NORMAL_ACTIVE; 3759 + tty_port_set_active(&info->port, 1); 3760 3760 return 0; 3761 3761 } 3762 3762 ··· 3825 3825 #endif 3826 3826 if (retval) 3827 3827 return retval; 3828 - info->port.flags |= ASYNC_NORMAL_ACTIVE; 3828 + tty_port_set_active(&info->port, 1); 3829 3829 return 0; 3830 3830 } 3831 3831
+4 -4
drivers/tty/serial/serial_core.c
··· 1418 1418 uart_change_pm(state, UART_PM_STATE_OFF); 1419 1419 spin_lock_irq(&port->lock); 1420 1420 } 1421 + spin_unlock_irq(&port->lock); 1422 + tty_port_set_active(port, 0); 1421 1423 1422 1424 /* 1423 1425 * Wake up anyone trying to open this port. 1424 1426 */ 1425 - clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); 1426 - spin_unlock_irq(&port->lock); 1427 1427 wake_up_interruptible(&port->open_wait); 1428 1428 1429 1429 mutex_unlock(&port->mutex); ··· 1501 1501 pr_debug("uart_hangup(%d)\n", tty->index); 1502 1502 1503 1503 mutex_lock(&port->mutex); 1504 - if (port->flags & ASYNC_NORMAL_ACTIVE) { 1504 + if (tty_port_active(port)) { 1505 1505 uart_flush_buffer(tty); 1506 1506 uart_shutdown(tty, state); 1507 1507 spin_lock_irqsave(&port->lock, flags); 1508 1508 port->count = 0; 1509 - clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); 1510 1509 spin_unlock_irqrestore(&port->lock, flags); 1510 + tty_port_set_active(port, 0); 1511 1511 tty_port_tty_set(port, NULL); 1512 1512 if (!uart_console(state->uart_port)) 1513 1513 uart_change_pm(state, UART_PM_STATE_OFF);
+3 -3
drivers/tty/synclink.c
··· 3201 3201 shutdown(info); 3202 3202 3203 3203 info->port.count = 0; 3204 - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; 3204 + tty_port_set_active(&info->port, 0); 3205 3205 info->port.tty = NULL; 3206 3206 3207 3207 wake_up_interruptible(&info->port.open_wait); ··· 3269 3269 3270 3270 if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { 3271 3271 /* nonblock mode is set or port is not enabled */ 3272 - port->flags |= ASYNC_NORMAL_ACTIVE; 3272 + tty_port_set_active(port, 1); 3273 3273 return 0; 3274 3274 } 3275 3275 ··· 3338 3338 __FILE__,__LINE__, tty->driver->name, port->count ); 3339 3339 3340 3340 if (!retval) 3341 - port->flags |= ASYNC_NORMAL_ACTIVE; 3341 + tty_port_set_active(port, 1); 3342 3342 3343 3343 return retval; 3344 3344
+3 -3
drivers/tty/synclinkmp.c
··· 849 849 850 850 spin_lock_irqsave(&info->port.lock, flags); 851 851 info->port.count = 0; 852 - info->port.flags &= ~ASYNC_NORMAL_ACTIVE; 853 852 info->port.tty = NULL; 854 853 spin_unlock_irqrestore(&info->port.lock, flags); 854 + tty_port_set_active(&info->port, 1); 855 855 mutex_unlock(&info->port.mutex); 856 856 857 857 wake_up_interruptible(&info->port.open_wait); ··· 3285 3285 if (filp->f_flags & O_NONBLOCK || tty_io_error(tty)) { 3286 3286 /* nonblock mode is set or port is not enabled */ 3287 3287 /* just verify that callout device is not active */ 3288 - port->flags |= ASYNC_NORMAL_ACTIVE; 3288 + tty_port_set_active(port, 1); 3289 3289 return 0; 3290 3290 } 3291 3291 ··· 3352 3352 __FILE__,__LINE__, tty->driver->name, port->count ); 3353 3353 3354 3354 if (!retval) 3355 - port->flags |= ASYNC_NORMAL_ACTIVE; 3355 + tty_port_set_active(port, 1); 3356 3356 3357 3357 return retval; 3358 3358 }
+6 -6
drivers/tty/tty_port.c
··· 236 236 237 237 spin_lock_irqsave(&port->lock, flags); 238 238 port->count = 0; 239 - port->flags &= ~ASYNC_NORMAL_ACTIVE; 240 239 tty = port->tty; 241 240 if (tty) 242 241 set_bit(TTY_IO_ERROR, &tty->flags); 243 242 port->tty = NULL; 244 243 spin_unlock_irqrestore(&port->lock, flags); 244 + tty_port_set_active(port, 0); 245 245 tty_port_shutdown(port, tty); 246 246 tty_kref_put(tty); 247 247 wake_up_interruptible(&port->open_wait); ··· 365 365 /* if non-blocking mode is set we can pass directly to open unless 366 366 the port has just hung up or is in another error state */ 367 367 if (tty_io_error(tty)) { 368 - port->flags |= ASYNC_NORMAL_ACTIVE; 368 + tty_port_set_active(port, 1); 369 369 return 0; 370 370 } 371 371 if (filp->f_flags & O_NONBLOCK) { 372 372 /* Indicate we are open */ 373 373 if (C_BAUD(tty)) 374 374 tty_port_raise_dtr_rts(port); 375 - port->flags |= ASYNC_NORMAL_ACTIVE; 375 + tty_port_set_active(port, 1); 376 376 return 0; 377 377 } 378 378 ··· 430 430 if (!tty_hung_up_p(filp)) 431 431 port->count++; 432 432 port->blocked_open--; 433 - if (retval == 0) 434 - port->flags |= ASYNC_NORMAL_ACTIVE; 435 433 spin_unlock_irqrestore(&port->lock, flags); 434 + if (retval == 0) 435 + tty_port_set_active(port, 1); 436 436 return retval; 437 437 } 438 438 EXPORT_SYMBOL(tty_port_block_til_ready); ··· 514 514 spin_lock_irqsave(&port->lock, flags); 515 515 wake_up_interruptible(&port->open_wait); 516 516 } 517 - port->flags &= ~ASYNC_NORMAL_ACTIVE; 518 517 spin_unlock_irqrestore(&port->lock, flags); 518 + tty_port_set_active(port, 0); 519 519 } 520 520 EXPORT_SYMBOL(tty_port_close_end); 521 521
+12
include/linux/tty.h
··· 571 571 clear_bit(TTY_PORT_CTS_FLOW, &port->iflags); 572 572 } 573 573 574 + static inline bool tty_port_active(struct tty_port *port) 575 + { 576 + return test_bit(TTY_PORT_ACTIVE, &port->iflags); 577 + } 578 + 579 + static inline void tty_port_set_active(struct tty_port *port, bool val) 580 + { 581 + if (val) 582 + set_bit(TTY_PORT_ACTIVE, &port->iflags); 583 + else 584 + clear_bit(TTY_PORT_ACTIVE, &port->iflags); 585 + } 574 586 575 587 extern struct tty_struct *tty_port_tty_get(struct tty_port *port); 576 588 extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty);
+5 -5
net/irda/ircomm/ircomm_tty.c
··· 281 281 * then make the check up front and then exit. 282 282 */ 283 283 if (tty_io_error(tty)) { 284 - port->flags |= ASYNC_NORMAL_ACTIVE; 284 + tty_port_set_active(port, 1); 285 285 return 0; 286 286 } 287 287 ··· 289 289 /* nonblock mode is set */ 290 290 if (C_BAUD(tty)) 291 291 tty_port_raise_dtr_rts(port); 292 - port->flags |= ASYNC_NORMAL_ACTIVE; 292 + tty_port_set_active(port, 1); 293 293 pr_debug("%s(), O_NONBLOCK requested!\n", __func__); 294 294 return 0; 295 295 } ··· 365 365 __FILE__, __LINE__, tty->driver->name, port->count); 366 366 367 367 if (!retval) 368 - port->flags |= ASYNC_NORMAL_ACTIVE; 368 + tty_port_set_active(port, 1); 369 369 370 370 return retval; 371 371 } ··· 925 925 ircomm_tty_shutdown(self); 926 926 927 927 spin_lock_irqsave(&port->lock, flags); 928 - port->flags &= ~ASYNC_NORMAL_ACTIVE; 929 928 if (port->tty) { 930 929 set_bit(TTY_IO_ERROR, &port->tty->flags); 931 930 tty_kref_put(port->tty); ··· 932 933 port->tty = NULL; 933 934 port->count = 0; 934 935 spin_unlock_irqrestore(&port->lock, flags); 936 + tty_port_set_active(port, 0); 935 937 936 938 wake_up_interruptible(&port->open_wait); 937 939 } ··· 1267 1267 seq_printf(m, "%cASYNC_LOW_LATENCY", sep); 1268 1268 sep = '|'; 1269 1269 } 1270 - if (self->port.flags & ASYNC_NORMAL_ACTIVE) { 1270 + if (tty_port_active(&self->port)) { 1271 1271 seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep); 1272 1272 sep = '|'; 1273 1273 }