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

Commit 4047b371 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman
Browse files

serial: core: Prevent unsafe uart port access, part 1



uart_remove_one_port() may race with every serial core operation
requiring a valid dereference of state->uart_port. In particular,
uart_remove_one_port() may unlink the uart port concurrently with
any serial core operation that may dereference same.

Ensure safe dereference for those operations that already claim
the port->mutex, and extend that guarantee for trivial cases,
such as the ioctl handlers. Introduce the uart_port_check() helper
which asserts port->mutex is held (only when lockdep is on).

For ioctls, return -EIO as if the port has been hung up (since it has).

Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 49c02304
Loading
Loading
Loading
Loading
+104 −53
Original line number Original line Diff line number Diff line
@@ -64,6 +64,14 @@ static int uart_dcd_enabled(struct uart_port *uport)
	return !!(uport->status & UPSTAT_DCD_ENABLE);
	return !!(uport->status & UPSTAT_DCD_ENABLE);
}
}


static inline struct uart_port *uart_port_check(struct uart_state *state)
{
#ifdef CONFIG_LOCKDEP
	WARN_ON(!lockdep_is_held(&state->port.mutex));
#endif
	return state->uart_port;
}

/*
/*
 * This routine is used by the interrupt handler to schedule processing in
 * This routine is used by the interrupt handler to schedule processing in
 * the software interrupt portion of the driver.
 * the software interrupt portion of the driver.
@@ -134,7 +142,7 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
		int init_hw)
		int init_hw)
{
{
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport = uart_port_check(state);
	unsigned long page;
	unsigned long page;
	int retval = 0;
	int retval = 0;


@@ -222,7 +230,7 @@ static int uart_startup(struct tty_struct *tty, struct uart_state *state,
 */
 */
static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
{
{
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport = uart_port_check(state);
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;


	/*
	/*
@@ -443,7 +451,7 @@ EXPORT_SYMBOL(uart_get_divisor);
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
					struct ktermios *old_termios)
					struct ktermios *old_termios)
{
{
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport = uart_port_check(state);
	struct ktermios *termios;
	struct ktermios *termios;
	int hw_stopped;
	int hw_stopped;


@@ -673,10 +681,11 @@ static void uart_unthrottle(struct tty_struct *tty)
		uart_send_xchar(tty, START_CHAR(tty));
		uart_send_xchar(tty, START_CHAR(tty));
}
}


static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
{
{
	struct uart_state *state = container_of(port, struct uart_state, port);
	struct uart_state *state = container_of(port, struct uart_state, port);
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport;
	int ret = -ENODEV;


	memset(retinfo, 0, sizeof(*retinfo));
	memset(retinfo, 0, sizeof(*retinfo));


@@ -685,6 +694,10 @@ static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
	 * occur as we go
	 * occur as we go
	 */
	 */
	mutex_lock(&port->mutex);
	mutex_lock(&port->mutex);
	uport = uart_port_check(state);
	if (!uport)
		goto out;

	retinfo->type	    = uport->type;
	retinfo->type	    = uport->type;
	retinfo->line	    = uport->line;
	retinfo->line	    = uport->line;
	retinfo->port	    = uport->iobase;
	retinfo->port	    = uport->iobase;
@@ -703,7 +716,11 @@ static void uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
	retinfo->io_type         = uport->iotype;
	retinfo->io_type         = uport->iotype;
	retinfo->iomem_reg_shift = uport->regshift;
	retinfo->iomem_reg_shift = uport->regshift;
	retinfo->iomem_base      = (void *)(unsigned long)uport->mapbase;
	retinfo->iomem_base      = (void *)(unsigned long)uport->mapbase;

	ret = 0;
out:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port->mutex);
	return ret;
}
}


static int uart_get_info_user(struct tty_port *port,
static int uart_get_info_user(struct tty_port *port,
@@ -711,7 +728,8 @@ static int uart_get_info_user(struct tty_port *port,
{
{
	struct serial_struct tmp;
	struct serial_struct tmp;


	uart_get_info(port, &tmp);
	if (uart_get_info(port, &tmp) < 0)
		return -EIO;


	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
		return -EFAULT;
		return -EFAULT;
@@ -722,13 +740,16 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
			 struct uart_state *state,
			 struct uart_state *state,
			 struct serial_struct *new_info)
			 struct serial_struct *new_info)
{
{
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport = uart_port_check(state);
	unsigned long new_port;
	unsigned long new_port;
	unsigned int change_irq, change_port, closing_wait;
	unsigned int change_irq, change_port, closing_wait;
	unsigned int old_custom_divisor, close_delay;
	unsigned int old_custom_divisor, close_delay;
	upf_t old_flags, new_flags;
	upf_t old_flags, new_flags;
	int retval = 0;
	int retval = 0;


	if (!uport)
		return -EIO;

	new_port = new_info->port;
	new_port = new_info->port;
	if (HIGH_BITS_OFFSET)
	if (HIGH_BITS_OFFSET)
		new_port += (unsigned long) new_info->port_high << HIGH_BITS_OFFSET;
		new_port += (unsigned long) new_info->port_high << HIGH_BITS_OFFSET;
@@ -938,13 +959,11 @@ static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state,
 *	@tty: tty associated with the UART
 *	@tty: tty associated with the UART
 *	@state: UART being queried
 *	@state: UART being queried
 *	@value: returned modem value
 *	@value: returned modem value
 *
 *	Note: uart_ioctl protects us against hangups.
 */
 */
static int uart_get_lsr_info(struct tty_struct *tty,
static int uart_get_lsr_info(struct tty_struct *tty,
			struct uart_state *state, unsigned int __user *value)
			struct uart_state *state, unsigned int __user *value)
{
{
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport = uart_port_check(state);
	unsigned int result;
	unsigned int result;


	result = uport->ops->tx_empty(uport);
	result = uport->ops->tx_empty(uport);
@@ -967,18 +986,22 @@ static int uart_tiocmget(struct tty_struct *tty)
{
{
	struct uart_state *state = tty->driver_data;
	struct uart_state *state = tty->driver_data;
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport;
	int result = -EIO;
	int result = -EIO;


	mutex_lock(&port->mutex);
	mutex_lock(&port->mutex);
	uport = uart_port_check(state);
	if (!uport)
		goto out;

	if (!tty_io_error(tty)) {
	if (!tty_io_error(tty)) {
		result = uport->mctrl;
		result = uport->mctrl;
		spin_lock_irq(&uport->lock);
		spin_lock_irq(&uport->lock);
		result |= uport->ops->get_mctrl(uport);
		result |= uport->ops->get_mctrl(uport);
		spin_unlock_irq(&uport->lock);
		spin_unlock_irq(&uport->lock);
	}
	}
out:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port->mutex);

	return result;
	return result;
}
}


@@ -986,15 +1009,20 @@ static int
uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
{
{
	struct uart_state *state = tty->driver_data;
	struct uart_state *state = tty->driver_data;
	struct uart_port *uport = state->uart_port;
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;
	struct uart_port *uport;
	int ret = -EIO;
	int ret = -EIO;


	mutex_lock(&port->mutex);
	mutex_lock(&port->mutex);
	uport = uart_port_check(state);
	if (!uport)
		goto out;

	if (!tty_io_error(tty)) {
	if (!tty_io_error(tty)) {
		uart_update_mctrl(uport, set, clear);
		uart_update_mctrl(uport, set, clear);
		ret = 0;
		ret = 0;
	}
	}
out:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port->mutex);
	return ret;
	return ret;
}
}
@@ -1003,21 +1031,26 @@ static int uart_break_ctl(struct tty_struct *tty, int break_state)
{
{
	struct uart_state *state = tty->driver_data;
	struct uart_state *state = tty->driver_data;
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport;
	int ret = -EIO;


	mutex_lock(&port->mutex);
	mutex_lock(&port->mutex);
	uport = uart_port_check(state);
	if (!uport)
		goto out;


	if (uport->type != PORT_UNKNOWN)
	if (uport->type != PORT_UNKNOWN)
		uport->ops->break_ctl(uport, break_state);
		uport->ops->break_ctl(uport, break_state);

	ret = 0;
out:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port->mutex);
	return 0;
	return ret;
}
}


static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
{
{
	struct uart_port *uport = state->uart_port;
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;
	struct uart_port *uport;
	int flags, ret;
	int flags, ret;


	if (!capable(CAP_SYS_ADMIN))
	if (!capable(CAP_SYS_ADMIN))
@@ -1031,6 +1064,12 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
	if (mutex_lock_interruptible(&port->mutex))
	if (mutex_lock_interruptible(&port->mutex))
		return -ERESTARTSYS;
		return -ERESTARTSYS;


	uport = uart_port_check(state);
	if (!uport) {
		ret = -EIO;
		goto out;
	}

	ret = -EBUSY;
	ret = -EBUSY;
	if (tty_port_users(port) == 1) {
	if (tty_port_users(port) == 1) {
		uart_shutdown(tty, state);
		uart_shutdown(tty, state);
@@ -1054,6 +1093,7 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)


		ret = uart_startup(tty, state, 1);
		ret = uart_startup(tty, state, 1);
	}
	}
out:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port->mutex);
	return ret;
	return ret;
}
}
@@ -1202,11 +1242,11 @@ static int uart_set_rs485_config(struct uart_port *port,
 * Called via sys_ioctl.  We can use spin_lock_irq() here.
 * Called via sys_ioctl.  We can use spin_lock_irq() here.
 */
 */
static int
static int
uart_ioctl(struct tty_struct *tty, unsigned int cmd,
uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
	   unsigned long arg)
{
{
	struct uart_state *state = tty->driver_data;
	struct uart_state *state = tty->driver_data;
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;
	struct uart_port *uport;
	void __user *uarg = (void __user *)arg;
	void __user *uarg = (void __user *)arg;
	int ret = -ENOIOCTLCMD;
	int ret = -ENOIOCTLCMD;


@@ -1258,8 +1298,9 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
		goto out;
		goto out;


	mutex_lock(&port->mutex);
	mutex_lock(&port->mutex);
	uport = uart_port_check(state);


	if (tty_io_error(tty)) {
	if (!uport || tty_io_error(tty)) {
		ret = -EIO;
		ret = -EIO;
		goto out_up;
		goto out_up;
	}
	}
@@ -1275,19 +1316,17 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
		break;
		break;


	case TIOCGRS485:
	case TIOCGRS485:
		ret = uart_get_rs485_config(state->uart_port, uarg);
		ret = uart_get_rs485_config(uport, uarg);
		break;
		break;


	case TIOCSRS485:
	case TIOCSRS485:
		ret = uart_set_rs485_config(state->uart_port, uarg);
		ret = uart_set_rs485_config(uport, uarg);
		break;
		break;
	default: {
	default:
		struct uart_port *uport = state->uart_port;
		if (uport->ops->ioctl)
		if (uport->ops->ioctl)
			ret = uport->ops->ioctl(uport, cmd, arg);
			ret = uport->ops->ioctl(uport, cmd, arg);
		break;
		break;
	}
	}
	}
out_up:
out_up:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port->mutex);
out:
out:
@@ -1297,24 +1336,29 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd,
static void uart_set_ldisc(struct tty_struct *tty)
static void uart_set_ldisc(struct tty_struct *tty)
{
{
	struct uart_state *state = tty->driver_data;
	struct uart_state *state = tty->driver_data;
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport;


	if (uport->ops->set_ldisc) {
	mutex_lock(&state->port.mutex);
	mutex_lock(&state->port.mutex);
	uport = uart_port_check(state);
	if (uport && uport->ops->set_ldisc)
		uport->ops->set_ldisc(uport, &tty->termios);
		uport->ops->set_ldisc(uport, &tty->termios);
	mutex_unlock(&state->port.mutex);
	mutex_unlock(&state->port.mutex);
}
}
}


static void uart_set_termios(struct tty_struct *tty,
static void uart_set_termios(struct tty_struct *tty,
						struct ktermios *old_termios)
						struct ktermios *old_termios)
{
{
	struct uart_state *state = tty->driver_data;
	struct uart_state *state = tty->driver_data;
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport;
	unsigned int cflag = tty->termios.c_cflag;
	unsigned int cflag = tty->termios.c_cflag;
	unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
	unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
	bool sw_changed = false;
	bool sw_changed = false;


	mutex_lock(&state->port.mutex);
	uport = uart_port_check(state);
	if (!uport)
		goto out;

	/*
	/*
	 * Drivers doing software flow control also need to know
	 * Drivers doing software flow control also need to know
	 * about changes to these input settings.
	 * about changes to these input settings.
@@ -1337,12 +1381,10 @@ static void uart_set_termios(struct tty_struct *tty,
	    tty->termios.c_ispeed == old_termios->c_ispeed &&
	    tty->termios.c_ispeed == old_termios->c_ispeed &&
	    ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
	    ((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
	    !sw_changed) {
	    !sw_changed) {
		return;
		goto out;
	}
	}


	mutex_lock(&state->port.mutex);
	uart_change_speed(tty, state, old_termios);
	uart_change_speed(tty, state, old_termios);
	mutex_unlock(&state->port.mutex);
	/* reload cflag from termios; port driver may have overriden flags */
	/* reload cflag from termios; port driver may have overriden flags */
	cflag = tty->termios.c_cflag;
	cflag = tty->termios.c_cflag;


@@ -1356,6 +1398,8 @@ static void uart_set_termios(struct tty_struct *tty,
			mask |= TIOCM_RTS;
			mask |= TIOCM_RTS;
		uart_set_mctrl(uport, mask);
		uart_set_mctrl(uport, mask);
	}
	}
out:
	mutex_unlock(&state->port.mutex);
}
}


/*
/*
@@ -1522,7 +1566,7 @@ static void uart_hangup(struct tty_struct *tty)
static void uart_port_shutdown(struct tty_port *port)
static void uart_port_shutdown(struct tty_port *port)
{
{
	struct uart_state *state = container_of(port, struct uart_state, port);
	struct uart_state *state = container_of(port, struct uart_state, port);
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport = uart_port_check(state);


	/*
	/*
	 * clear delta_msr_wait queue to avoid mem leaks: we may free
	 * clear delta_msr_wait queue to avoid mem leaks: we may free
@@ -1585,6 +1629,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
	int retval, line = tty->index;
	int retval, line = tty->index;
	struct uart_state *state = drv->state + line;
	struct uart_state *state = drv->state + line;
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;
	struct uart_port *uport;


	pr_debug("uart_open(%d) called\n", line);
	pr_debug("uart_open(%d) called\n", line);


@@ -1604,15 +1649,15 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
		goto end;
		goto end;
	}
	}


	if (!state->uart_port || state->uart_port->flags & UPF_DEAD) {
	uport = uart_port_check(state);
	if (!uport || uport->flags & UPF_DEAD) {
		retval = -ENXIO;
		retval = -ENXIO;
		goto err_unlock;
		goto err_unlock;
	}
	}


	tty->driver_data = state;
	tty->driver_data = state;
	state->uart_port->state = state;
	uport->state = state;
	state->port.low_latency =
	port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
		(state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
	tty_port_tty_set(port, tty);
	tty_port_tty_set(port, tty);


	/*
	/*
@@ -1651,13 +1696,15 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
	struct uart_state *state = drv->state + i;
	struct uart_state *state = drv->state + i;
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;
	enum uart_pm_state pm_state;
	enum uart_pm_state pm_state;
	struct uart_port *uport = state->uart_port;
	struct uart_port *uport;
	char stat_buf[32];
	char stat_buf[32];
	unsigned int status;
	unsigned int status;
	int mmio;
	int mmio;


	mutex_lock(&port->mutex);
	uport = uart_port_check(state);
	if (!uport)
	if (!uport)
		return;
		goto out;


	mmio = uport->iotype >= UPIO_MEM;
	mmio = uport->iotype >= UPIO_MEM;
	seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
	seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
@@ -1669,11 +1716,10 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)


	if (uport->type == PORT_UNKNOWN) {
	if (uport->type == PORT_UNKNOWN) {
		seq_putc(m, '\n');
		seq_putc(m, '\n');
		return;
		goto out;
	}
	}


	if (capable(CAP_SYS_ADMIN)) {
	if (capable(CAP_SYS_ADMIN)) {
		mutex_lock(&port->mutex);
		pm_state = state->pm_state;
		pm_state = state->pm_state;
		if (pm_state != UART_PM_STATE_ON)
		if (pm_state != UART_PM_STATE_ON)
			uart_change_pm(state, UART_PM_STATE_ON);
			uart_change_pm(state, UART_PM_STATE_ON);
@@ -1682,7 +1728,6 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
		spin_unlock_irq(&uport->lock);
		spin_unlock_irq(&uport->lock);
		if (pm_state != UART_PM_STATE_ON)
		if (pm_state != UART_PM_STATE_ON)
			uart_change_pm(state, pm_state);
			uart_change_pm(state, pm_state);
		mutex_unlock(&port->mutex);


		seq_printf(m, " tx:%d rx:%d",
		seq_printf(m, " tx:%d rx:%d",
				uport->icount.tx, uport->icount.rx);
				uport->icount.tx, uport->icount.rx);
@@ -1720,6 +1765,8 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
	seq_putc(m, '\n');
	seq_putc(m, '\n');
#undef STATBIT
#undef STATBIT
#undef INFOBIT
#undef INFOBIT
out:
	mutex_unlock(&port->mutex);
}
}


static int uart_proc_show(struct seq_file *m, void *v)
static int uart_proc_show(struct seq_file *m, void *v)
@@ -1956,10 +2003,10 @@ EXPORT_SYMBOL_GPL(uart_set_options);
static void uart_change_pm(struct uart_state *state,
static void uart_change_pm(struct uart_state *state,
			   enum uart_pm_state pm_state)
			   enum uart_pm_state pm_state)
{
{
	struct uart_port *port = state->uart_port;
	struct uart_port *port = uart_port_check(state);


	if (state->pm_state != pm_state) {
	if (state->pm_state != pm_state) {
		if (port->ops->pm)
		if (port && port->ops->pm)
			port->ops->pm(port, pm_state, state->pm_state);
			port->ops->pm(port, pm_state, state->pm_state);
		state->pm_state = pm_state;
		state->pm_state = pm_state;
	}
	}
@@ -2244,8 +2291,8 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
	tport = &state->port;
	tport = &state->port;
	mutex_lock(&tport->mutex);
	mutex_lock(&tport->mutex);


	port = state->uart_port;
	port = uart_port_check(state);
	if (!(port->ops->poll_get_char && port->ops->poll_put_char)) {
	if (!port || !(port->ops->poll_get_char && port->ops->poll_put_char)) {
		ret = -1;
		ret = -1;
		goto out;
		goto out;
	}
	}
@@ -2713,15 +2760,12 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
{
{
	struct uart_state *state = drv->state + uport->line;
	struct uart_state *state = drv->state + uport->line;
	struct tty_port *port = &state->port;
	struct tty_port *port = &state->port;
	struct uart_port *uart_port;
	struct tty_struct *tty;
	struct tty_struct *tty;
	int ret = 0;
	int ret = 0;


	BUG_ON(in_interrupt());
	BUG_ON(in_interrupt());


	if (state->uart_port != uport)
		dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
			state->uart_port, uport);

	mutex_lock(&port_mutex);
	mutex_lock(&port_mutex);


	/*
	/*
@@ -2729,7 +2773,12 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
	 * succeeding while we shut down the port.
	 * succeeding while we shut down the port.
	 */
	 */
	mutex_lock(&port->mutex);
	mutex_lock(&port->mutex);
	if (!state->uart_port) {
	uart_port = uart_port_check(state);
	if (uart_port != uport)
		dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
			  uart_port, uport);

	if (!uart_port) {
		mutex_unlock(&port->mutex);
		mutex_unlock(&port->mutex);
		ret = -EINVAL;
		ret = -EINVAL;
		goto out;
		goto out;
@@ -2766,7 +2815,9 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
	 */
	 */
	uport->type = PORT_UNKNOWN;
	uport->type = PORT_UNKNOWN;


	mutex_lock(&port->mutex);
	state->uart_port = NULL;
	state->uart_port = NULL;
	mutex_unlock(&port->mutex);
out:
out:
	mutex_unlock(&port_mutex);
	mutex_unlock(&port_mutex);