linux-next: manual merge of the tty tree with the tty.current tree
From: Mark Brown
Date: Fri Oct 02 2026 - 14:14:10 EST
Hi all,
Today's linux-next merge of the tty tree got a conflict in:
drivers/tty/serial/serial_core.c
between commit:
499485a67fbac ("serial: core: fix NULL pointer dereference in serial_core_unregister_port()")
from the tty.current tree and commit:
b290393074a14 ("serial: core: fix NULL/dangling port_dev on failed re-register")
from the tty tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
diff --combined drivers/tty/serial/serial_core.c
index 6332ed545c899,d811a04d5d25c..0000000000000
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@@ -33,7 -33,6 +33,6 @@@
#include <linux/uaccess.h>
#include "serial_base.h"
- #include "8250/8250.h" /* For hub6_match_port() */
/*
* This is used to lock changes in serial line configuration.
@@@ -247,29 -246,29 +246,29 @@@ static int uart_alloc_xmit_buf(struct t
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
unsigned long flags;
- unsigned long page;
+ u8 *buf;
/*
* Initialise and allocate the transmit and temporary
* buffer.
*/
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
+ buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
return -ENOMEM;
uport = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- state->port.xmit_buf = (unsigned char *)page;
+ state->port.xmit_buf = buf;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
uart_port_unlock_deref(uport, flags);
} else {
uart_port_unlock_deref(uport, flags);
/*
- * Do not free() the page under the port lock, see
+ * Do not free() the buffer under the port lock, see
* uart_free_xmit_buf().
*/
- free_page(page);
+ kfree(buf);
}
return 0;
@@@ -280,10 -279,10 +279,10 @@@ static void uart_free_xmit_buf(struct t
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
unsigned long flags;
- char *xmit_buf;
+ u8 *xmit_buf;
/*
- * Do not free() the transmit buffer page under the port lock since
+ * Do not free() the transmit buffer under the port lock since
* this can create various circular locking scenarios. For instance,
* console driver may need to allocate/free a debug object, which
* can end up in printk() recursion.
@@@ -294,7 -293,7 +293,7 @@@
INIT_KFIFO(port->xmit_fifo);
uart_port_unlock_deref(uport, flags);
- free_page((unsigned long)xmit_buf);
+ kfree(xmit_buf);
}
/*
@@@ -896,7 -895,7 +895,7 @@@ static int uart_set_info(struct tty_str
upf_t old_flags, new_flags;
int retval;
- if (!uport)
+ if (!uport || tty_io_error(tty))
return -EIO;
new_port = new_info->port;
@@@ -1119,7 -1118,7 +1118,7 @@@ static int uart_break_ctl(struct tty_st
guard(mutex)(&port->mutex);
uport = uart_port_check(state);
- if (!uport)
+ if (!uport || tty_io_error(tty))
return -EIO;
if (uport->type != PORT_UNKNOWN && uport->ops->break_ctl)
@@@ -1144,7 -1143,7 +1143,7 @@@ static int uart_do_autoconfig(struct tt
*/
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &port->mutex) {
uport = uart_port_check(state);
- if (!uport)
+ if (!uport || tty_io_error(tty))
return -EIO;
if (tty_port_users(port) != 1)
@@@ -1199,7 -1198,7 +1198,7 @@@ static void uart_enable_ms(struct uart_
* FIXME: This wants extracting into a common all driver implementation
* of TIOCMWAIT using tty_port.
*/
-static int uart_wait_modem_status(struct uart_state *state, unsigned long arg)
+static int uart_wait_modem_status(struct tty_struct *tty, struct uart_state *state, unsigned long arg)
{
struct uart_port *uport;
struct tty_port *port = &state->port;
@@@ -1213,29 -1212,18 +1212,29 @@@
uport = uart_port_ref(state);
if (!uport)
return -EIO;
- scoped_guard(uart_port_lock_irq, uport) {
- memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
- uart_enable_ms(uport);
+
+ mutex_lock(&port->mutex);
+ if (tty_io_error(tty)) {
+ mutex_unlock(&port->mutex);
+ ret = -EIO;
+ goto out_deref;
}
+ uart_port_lock_irq(uport);
+ memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
+ uart_enable_ms(uport);
+ uart_port_unlock_irq(uport);
+
+ mutex_unlock(&port->mutex);
+
add_wait_queue(&port->delta_msr_wait, &wait);
for (;;) {
- scoped_guard(uart_port_lock_irq, uport)
- memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
-
set_current_state(TASK_INTERRUPTIBLE);
+ uart_port_lock_irq(uport);
+ memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
+ uart_port_unlock_irq(uport);
+
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
@@@ -1244,11 -1232,6 +1243,11 @@@
break;
}
+ if (tty_io_error(tty)) {
+ ret = -EIO;
+ break;
+ }
+
schedule();
/* see if a signal did it */
@@@ -1261,7 -1244,6 +1260,7 @@@
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&port->delta_msr_wait, &wait);
+out_deref:
uart_port_deref(uport);
return ret;
@@@ -1584,7 -1566,7 +1583,7 @@@ uart_ioctl(struct tty_struct *tty, unsi
/* This should only be used when the hardware is present. */
if (cmd == TIOCMIWAIT)
- return uart_wait_modem_status(state, arg);
+ return uart_wait_modem_status(tty, state, arg);
/* rs485_config requires more locking than others */
if (cmd == TIOCSRS485)
@@@ -1640,13 -1622,14 +1639,13 @@@ static void uart_set_ldisc(struct tty_s
{
struct uart_state *state = tty->driver_data;
struct uart_port *uport;
- struct tty_port *port = &state->port;
-
- if (!tty_port_initialized(port))
- return;
guard(mutex)(&state->port.mutex);
uport = uart_port_check(state);
- if (uport && uport->ops->set_ldisc)
+ if (!uport || tty_io_error(tty))
+ return;
+
+ if (uport->ops->set_ldisc)
uport->ops->set_ldisc(uport, &tty->termios);
}
@@@ -1662,7 -1645,7 +1661,7 @@@ static void uart_set_termios(struct tty
guard(mutex)(&state->port.mutex);
uport = uart_port_check(state);
- if (!uport)
+ if (!uport || tty_io_error(tty))
return;
/*
@@@ -1814,14 -1797,7 +1813,14 @@@ static void uart_wait_until_sent(struc
* 'timeout' / 'expire' give us the maximum amount of time
* we wait.
*/
- while (!port->ops->tx_empty(port)) {
+ for (;;) {
+ mutex_lock(&state->port.mutex);
+ if (tty_io_error(tty) || port->ops->tx_empty(port)) {
+ mutex_unlock(&state->port.mutex);
+ break;
+ }
+ mutex_unlock(&state->port.mutex);
+
msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
break;
@@@ -2133,7 -2109,8 +2132,8 @@@ EXPORT_SYMBOL_GPL(uart_console_write)
/**
* uart_parse_earlycon - Parse earlycon options
- * @p: ptr to 2nd field (ie., just beyond '<name>,')
+ * @p: ptr to 2nd field (ie., just beyond '<name>,'); %NULL if
+ * no console options were supplied
* @iotype: ptr for decoded iotype (out)
* @addr: ptr for decoded mapbase/iobase (out)
* @options: ptr for <options> field; %NULL if not present (out)
@@@ -2153,6 -2130,9 +2153,9 @@@
int uart_parse_earlycon(char *p, enum uart_iotype *iotype,
resource_size_t *addr, char **options)
{
+ if (!p)
+ return -EINVAL;
+
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
p += 5;
@@@ -3256,32 -3236,6 +3259,6 @@@ static void serial_core_remove_one_port
state->uart_port = NULL;
}
- /**
- * uart_match_port - are the two ports equivalent?
- * @port1: first port
- * @port2: second port
- *
- * This utility function can be used to determine whether two uart_port
- * structures describe the same port.
- */
- bool uart_match_port(const struct uart_port *port1,
- const struct uart_port *port2)
- {
- if (port1->iotype != port2->iotype)
- return false;
- else if (port1->iotype == UPIO_PORT)
- return port1->iobase == port2->iobase;
- else if (port1->iotype == UPIO_HUB6)
- return hub6_match_port(port1, port2);
- else if (uart_iotype_mmio(port1->iotype))
- return port1->mapbase == port2->mapbase;
- else if (port1->iotype == UPIO_BUS)
- return true;
- else
- return false;
- }
- EXPORT_SYMBOL(uart_match_port);
-
static struct serial_ctrl_device *
serial_core_get_ctrl_dev(struct serial_port_device *port_dev)
{
@@@ -3402,12 -3356,7 +3379,12 @@@ void serial_core_unregister_port(struc
guard(mutex)(&port_mutex);
- /* May have never been registered. */
+ /*
+ * A NULL port device means there is no registered port device to
+ * remove: serial_core_remove_one_port() clears port_dev on
+ * teardown, and it is never set if registration failed before
+ * serial_core_port_device_add().
+ */
port_dev = port->port_dev;
if (!port_dev)
return;
Attachment:
signature.asc
Description: PGP signature