Commit 807c8d81 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman
Browse files

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: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5604a98e
Loading
Loading
Loading
Loading
+9 −11
Original line number Diff line number Diff line
@@ -1622,7 +1622,7 @@ isdn_tty_hangup(struct tty_struct *tty)
		return;
	isdn_tty_shutdown(info);
	port->count = 0;
	port->flags &= ~ASYNC_NORMAL_ACTIVE;
	tty_port_set_active(port, 0);
	port->tty = NULL;
	wake_up_interruptible(&port->open_wait);
}
@@ -1979,7 +1979,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
#endif
			if (
#ifndef FIX_FILE_TRANSFER
				(info->port.flags & ASYNC_NORMAL_ACTIVE) &&
			    tty_port_active(&info->port) &&
#endif
				(info->isdn_driver == -1) &&
				(info->isdn_channel == -1) &&
@@ -2018,8 +2018,6 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
	return (wret == 2) ? 3 : 0;
}

#define TTY_IS_ACTIVE(info)	(info->port.flags & ASYNC_NORMAL_ACTIVE)

int
isdn_tty_stat_callback(int i, isdn_ctrl *c)
{
@@ -2077,7 +2075,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#ifdef ISDN_TTY_STAT_DEBUG
			printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
#endif
			if (TTY_IS_ACTIVE(info)) {
			if (tty_port_active(&info->port)) {
				if (info->dialing == 1) {
					info->dialing = 2;
					return 1;
@@ -2088,7 +2086,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#ifdef ISDN_TTY_STAT_DEBUG
			printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
#endif
			if (TTY_IS_ACTIVE(info)) {
			if (tty_port_active(&info->port)) {
				if (info->dialing == 1)
					isdn_tty_modem_result(RESULT_BUSY, info);
				if (info->dialing > 1)
@@ -2118,7 +2116,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
			 * waiting for it and
			 * set DCD-bit of its modem-status.
			 */
			if (TTY_IS_ACTIVE(info) ||
			if (tty_port_active(&info->port) ||
			    (info->port.blocked_open &&
			     (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
				info->msr |= UART_MSR_DCD;
@@ -2145,7 +2143,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#ifdef ISDN_TTY_STAT_DEBUG
			printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
#endif
			if (TTY_IS_ACTIVE(info)) {
			if (tty_port_active(&info->port)) {
#ifdef ISDN_DEBUG_MODEM_HUP
				printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
#endif
@@ -2157,7 +2155,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#ifdef ISDN_TTY_STAT_DEBUG
			printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
#endif
			if (TTY_IS_ACTIVE(info)) {
			if (tty_port_active(&info->port)) {
				if (info->dialing) {
					info->dialing = 0;
					info->last_l2 = -1;
@@ -2183,14 +2181,14 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
			return 1;
#ifdef CONFIG_ISDN_TTY_FAX
		case ISDN_STAT_FAXIND:
			if (TTY_IS_ACTIVE(info)) {
			if (tty_port_active(&info->port)) {
				isdn_tty_fax_command(info, c);
			}
			break;
#endif
#ifdef CONFIG_ISDN_AUDIO
		case ISDN_STAT_AUDIO:
			if (TTY_IS_ACTIVE(info)) {
			if (tty_port_active(&info->port)) {
				switch (c->parm.num[0]) {
				case ISDN_AUDIO_DTMF:
					if (info->vonline) {
+1 −1
Original line number Diff line number Diff line
@@ -1493,7 +1493,7 @@ static void rs_hangup(struct tty_struct *tty)
	rs_flush_buffer(tty);
	shutdown(tty, info);
	info->tport.count = 0;
	info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
	tty_port_set_active(&info->tport, 0);
	info->tport.tty = NULL;
	wake_up_interruptible(&info->tport.open_wait);
}
+3 −2
Original line number Diff line number Diff line
@@ -1042,9 +1042,10 @@ static void rp_close(struct tty_struct *tty, struct file *filp)
		}
	}
	spin_lock_irq(&port->lock);
	info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_NORMAL_ACTIVE);
	port->flags &= ~ASYNC_INITIALIZED;
	tty->closing = 0;
	spin_unlock_irq(&port->lock);
	tty_port_set_active(port, 0);
	mutex_unlock(&port->mutex);
	tty_port_tty_set(port, NULL);

@@ -1624,7 +1625,7 @@ static int rp_write(struct tty_struct *tty,
	/*  Write remaining data into the port's xmit_buf */
	while (1) {
		/* Hung up ? */
		if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
		if (!tty_port_active(&info->port))
			goto end;
		c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
		c = min(c, XMIT_BUF_SIZE - info->xmit_head);
+4 −4
Original line number Diff line number Diff line
@@ -3648,8 +3648,8 @@ rs_close(struct tty_struct *tty, struct file * filp)
			schedule_timeout_interruptible(info->port.close_delay);
		wake_up_interruptible(&info->port.open_wait);
	}
	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
	local_irq_restore(flags);
	tty_port_set_active(&info->port, 0);

	/* port closed */

@@ -3732,7 +3732,7 @@ rs_hangup(struct tty_struct *tty)
	shutdown(info);
	info->event = 0;
	info->port.count = 0;
	info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
	tty_port_set_active(&info->port, 0);
	info->port.tty = NULL;
	wake_up_interruptible(&info->port.open_wait);
}
@@ -3756,7 +3756,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
	 * then make the check up front and then exit.
	 */
	if ((filp->f_flags & O_NONBLOCK) || tty_io_error(tty)) {
		info->port.flags |= ASYNC_NORMAL_ACTIVE;
		tty_port_set_active(&info->port, 1);
		return 0;
	}

@@ -3825,7 +3825,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
	if (retval)
		return retval;
	info->port.flags |= ASYNC_NORMAL_ACTIVE;
	tty_port_set_active(&info->port, 1);
	return 0;
}

+4 −4
Original line number Diff line number Diff line
@@ -1418,12 +1418,12 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
		uart_change_pm(state, UART_PM_STATE_OFF);
		spin_lock_irq(&port->lock);
	}
	spin_unlock_irq(&port->lock);
	tty_port_set_active(port, 0);

	/*
	 * Wake up anyone trying to open this port.
	 */
	clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
	spin_unlock_irq(&port->lock);
	wake_up_interruptible(&port->open_wait);

	mutex_unlock(&port->mutex);
@@ -1501,13 +1501,13 @@ static void uart_hangup(struct tty_struct *tty)
	pr_debug("uart_hangup(%d)\n", tty->index);

	mutex_lock(&port->mutex);
	if (port->flags & ASYNC_NORMAL_ACTIVE) {
	if (tty_port_active(port)) {
		uart_flush_buffer(tty);
		uart_shutdown(tty, state);
		spin_lock_irqsave(&port->lock, flags);
		port->count = 0;
		clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags);
		spin_unlock_irqrestore(&port->lock, flags);
		tty_port_set_active(port, 0);
		tty_port_tty_set(port, NULL);
		if (!uart_console(state->uart_port))
			uart_change_pm(state, UART_PM_STATE_OFF);
Loading