[PATCH 3/8] tty: don't store semi-state into tty drivers

From: Jiri Slaby
Date: Fri Jul 23 2021 - 03:43:31 EST


When a tty driver pointer is used as a return value of struct
console's device() hook, don't store a semi-state into global variable
which holds the tty driver. It could mean console::device() would return
a bogus value. This is important esp. after the next patch where we
switch from alloc_tty_driver to tty_alloc_driver. tty_alloc_driver
returns ERR_PTR in case of error and that might have unexpected results
as the code doesn't expect this.

Signed-off-by: Jiri Slaby <jslaby@xxxxxxx>
Cc: Geert Uytterhoeven <geert@xxxxxxxxxxxxxx>
Cc: "James E.J. Bottomley" <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx>
Cc: Helge Deller <deller@xxxxxx>
Cc: Chris Zankel <chris@xxxxxxxxxx>
Cc: Max Filippov <jcmvbkbc@xxxxxxxxx>
Cc: Laurentiu Tudor <laurentiu.tudor@xxxxxxx>
Cc: Felipe Balbi <balbi@xxxxxxxxxx>
---
arch/m68k/emu/nfcon.c | 27 +++++++++++---------
arch/parisc/kernel/pdc_cons.c | 28 +++++++++++----------
arch/xtensa/platforms/iss/console.c | 33 +++++++++++++-----------
drivers/tty/amiserial.c | 35 ++++++++++++++------------
drivers/tty/ehv_bytechan.c | 28 ++++++++++++---------
drivers/tty/hvc/hvsi.c | 35 ++++++++++++++------------
drivers/usb/gadget/function/u_serial.c | 32 ++++++++++++-----------
7 files changed, 119 insertions(+), 99 deletions(-)

diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c
index 92636c89d65b..f393af375c90 100644
--- a/arch/m68k/emu/nfcon.c
+++ b/arch/m68k/emu/nfcon.c
@@ -120,35 +120,38 @@ early_param("debug", nf_debug_setup);

static int __init nfcon_init(void)
{
+ struct tty_driver *driver;
int res;

stderr_id = nf_get_id("NF_STDERR");
if (!stderr_id)
return -ENODEV;

- nfcon_tty_driver = alloc_tty_driver(1);
- if (!nfcon_tty_driver)
+ driver = alloc_tty_driver(1);
+ if (!driver)
return -ENOMEM;

tty_port_init(&nfcon_tty_port);

- nfcon_tty_driver->driver_name = "nfcon";
- nfcon_tty_driver->name = "nfcon";
- nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
- nfcon_tty_driver->subtype = SYSTEM_TYPE_TTY;
- nfcon_tty_driver->init_termios = tty_std_termios;
- nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW;
+ driver->driver_name = "nfcon";
+ driver->name = "nfcon";
+ driver->type = TTY_DRIVER_TYPE_SYSTEM;
+ driver->subtype = SYSTEM_TYPE_TTY;
+ driver->init_termios = tty_std_termios;
+ driver->flags = TTY_DRIVER_REAL_RAW;

- tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops);
- tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0);
- res = tty_register_driver(nfcon_tty_driver);
+ tty_set_operations(driver, &nfcon_tty_ops);
+ tty_port_link_device(&nfcon_tty_port, driver, 0);
+ res = tty_register_driver(driver);
if (res) {
pr_err("failed to register nfcon tty driver\n");
- put_tty_driver(nfcon_tty_driver);
+ put_tty_driver(driver);
tty_port_destroy(&nfcon_tty_port);
return res;
}

+ nfcon_tty_driver = driver;
+
if (!(nf_console.flags & CON_ENABLED))
register_console(&nf_console);

diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
index 39ccad063533..650cb01203de 100644
--- a/arch/parisc/kernel/pdc_cons.c
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -138,6 +138,7 @@ static struct tty_driver *pdc_console_tty_driver;

static int __init pdc_console_tty_driver_init(void)
{
+ struct tty_driver *driver;
int err;

/* Check if the console driver is still registered.
@@ -160,31 +161,32 @@ static int __init pdc_console_tty_driver_init(void)
printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n");
pdc_cons.flags &= ~CON_BOOT;

- pdc_console_tty_driver = alloc_tty_driver(1);
-
- if (!pdc_console_tty_driver)
+ driver = alloc_tty_driver(1);
+ if (!driver)
return -ENOMEM;

tty_port_init(&tty_port);

- pdc_console_tty_driver->driver_name = "pdc_cons";
- pdc_console_tty_driver->name = "ttyB";
- pdc_console_tty_driver->major = MUX_MAJOR;
- pdc_console_tty_driver->minor_start = 0;
- pdc_console_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
- pdc_console_tty_driver->init_termios = tty_std_termios;
- pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
+ driver->driver_name = "pdc_cons";
+ driver->name = "ttyB";
+ driver->major = MUX_MAJOR;
+ driver->minor_start = 0;
+ driver->type = TTY_DRIVER_TYPE_SYSTEM;
+ driver->init_termios = tty_std_termios;
+ driver->flags = TTY_DRIVER_REAL_RAW |
TTY_DRIVER_RESET_TERMIOS;
- tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
- tty_port_link_device(&tty_port, pdc_console_tty_driver, 0);
+ tty_set_operations(driver, &pdc_console_tty_ops);
+ tty_port_link_device(&tty_port, driver, 0);

- err = tty_register_driver(pdc_console_tty_driver);
+ err = tty_register_driver(driver);
if (err) {
printk(KERN_ERR "Unable to register the PDC console TTY driver\n");
tty_port_destroy(&tty_port);
return err;
}

+ pdc_console_tty_driver = driver;
+
return 0;
}
device_initcall(pdc_console_tty_driver_init);
diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c
index 0108504dfb45..9c3cf369b7b2 100644
--- a/arch/xtensa/platforms/iss/console.c
+++ b/arch/xtensa/platforms/iss/console.c
@@ -136,39 +136,42 @@ static const struct tty_operations serial_ops = {

static int __init rs_init(void)
{
+ struct tty_driver *driver;
int ret;

- serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES);
- if (!serial_driver)
+ driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES);
+ if (!driver)
return -ENOMEM;

tty_port_init(&serial_port);

/* Initialize the tty_driver structure */

- serial_driver->driver_name = "iss_serial";
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
+ driver->driver_name = "iss_serial";
+ driver->name = "ttyS";
+ driver->major = TTY_MAJOR;
+ driver->minor_start = 64;
+ driver->type = TTY_DRIVER_TYPE_SERIAL;
+ driver->subtype = SERIAL_TYPE_NORMAL;
+ driver->init_termios = tty_std_termios;
+ driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ driver->flags = TTY_DRIVER_REAL_RAW;

- tty_set_operations(serial_driver, &serial_ops);
- tty_port_link_device(&serial_port, serial_driver, 0);
+ tty_set_operations(driver, &serial_ops);
+ tty_port_link_device(&serial_port, driver, 0);

- ret = tty_register_driver(serial_driver);
+ ret = tty_register_driver(driver);
if (ret) {
pr_err("Couldn't register serial driver\n");
- tty_driver_kref_put(serial_driver);
+ tty_driver_kref_put(driver);
tty_port_destroy(&serial_port);

return ret;
}

+ serial_driver = driver;
+
return 0;
}

diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 7ad103e128ac..bfd3acc1ecfa 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1490,34 +1490,35 @@ static const struct tty_port_operations amiga_port_ops = {
static int __init amiga_serial_probe(struct platform_device *pdev)
{
struct serial_state *state = &serial_state;
+ struct tty_driver *driver;
unsigned long flags;
int error;

- serial_driver = alloc_tty_driver(1);
- if (!serial_driver)
+ driver = alloc_tty_driver(1);
+ if (!driver)
return -ENOMEM;

/* Initialize the tty_driver structure */

- serial_driver->driver_name = "amiserial";
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
+ driver->driver_name = "amiserial";
+ driver->name = "ttyS";
+ driver->major = TTY_MAJOR;
+ driver->minor_start = 64;
+ driver->type = TTY_DRIVER_TYPE_SERIAL;
+ driver->subtype = SERIAL_TYPE_NORMAL;
+ driver->init_termios = tty_std_termios;
+ driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &serial_ops);
+ driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(driver, &serial_ops);

memset(state, 0, sizeof(*state));
state->port = (int)&amiga_custom.serdatr; /* Just to give it a value */
tty_port_init(&state->tport);
state->tport.ops = &amiga_port_ops;
- tty_port_link_device(&state->tport, serial_driver, 0);
+ tty_port_link_device(&state->tport, driver, 0);

- error = tty_register_driver(serial_driver);
+ error = tty_register_driver(driver);
if (error)
goto fail_put_tty_driver;

@@ -1558,15 +1559,17 @@ static int __init amiga_serial_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, state);

+ serial_driver = driver;
+
return 0;

fail_free_irq:
free_irq(IRQ_AMIGA_TBE, state);
fail_unregister:
- tty_unregister_driver(serial_driver);
+ tty_unregister_driver(driver);
fail_put_tty_driver:
tty_port_destroy(&state->tport);
- put_tty_driver(serial_driver);
+ put_tty_driver(driver);
return error;
}

diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 445e5ff9b36d..97ae940af478 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -751,6 +751,7 @@ static struct platform_driver ehv_bc_tty_driver = {
*/
static int __init ehv_bc_init(void)
{
+ struct tty_driver *driver;
struct device_node *np;
unsigned int count = 0; /* Number of elements in bcs[] */
int ret;
@@ -773,26 +774,28 @@ static int __init ehv_bc_init(void)
if (!bcs)
return -ENOMEM;

- ehv_bc_driver = alloc_tty_driver(count);
- if (!ehv_bc_driver) {
+ driver = alloc_tty_driver(count);
+ if (!driver) {
ret = -ENOMEM;
goto err_free_bcs;
}

- ehv_bc_driver->driver_name = "ehv-bc";
- ehv_bc_driver->name = ehv_bc_console.name;
- ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE;
- ehv_bc_driver->subtype = SYSTEM_TYPE_CONSOLE;
- ehv_bc_driver->init_termios = tty_std_termios;
- ehv_bc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- tty_set_operations(ehv_bc_driver, &ehv_bc_ops);
+ driver->driver_name = "ehv-bc";
+ driver->name = ehv_bc_console.name;
+ driver->type = TTY_DRIVER_TYPE_CONSOLE;
+ driver->subtype = SYSTEM_TYPE_CONSOLE;
+ driver->init_termios = tty_std_termios;
+ driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty_set_operations(driver, &ehv_bc_ops);

- ret = tty_register_driver(ehv_bc_driver);
+ ret = tty_register_driver(driver);
if (ret) {
pr_err("ehv-bc: could not register tty driver (ret=%i)\n", ret);
goto err_put_tty_driver;
}

+ ehv_bc_driver = driver;
+
ret = platform_driver_register(&ehv_bc_tty_driver);
if (ret) {
pr_err("ehv-bc: could not register platform driver (ret=%i)\n",
@@ -803,9 +806,10 @@ static int __init ehv_bc_init(void)
return 0;

err_deregister_tty_driver:
- tty_unregister_driver(ehv_bc_driver);
+ ehv_bc_driver = NULL;
+ tty_unregister_driver(driver);
err_put_tty_driver:
- put_tty_driver(ehv_bc_driver);
+ put_tty_driver(driver);
err_free_bcs:
kfree(bcs);

diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index f0bc8e780051..bfde7b1936a5 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -1038,29 +1038,30 @@ static const struct tty_operations hvsi_ops = {

static int __init hvsi_init(void)
{
+ struct tty_driver *driver;
int i, ret;

- hvsi_driver = alloc_tty_driver(hvsi_count);
- if (!hvsi_driver)
+ driver = alloc_tty_driver(hvsi_count);
+ if (!driver)
return -ENOMEM;

- hvsi_driver->driver_name = "hvsi";
- hvsi_driver->name = "hvsi";
- hvsi_driver->major = HVSI_MAJOR;
- hvsi_driver->minor_start = HVSI_MINOR;
- hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM;
- hvsi_driver->init_termios = tty_std_termios;
- hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
- hvsi_driver->init_termios.c_ispeed = 9600;
- hvsi_driver->init_termios.c_ospeed = 9600;
- hvsi_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(hvsi_driver, &hvsi_ops);
+ driver->driver_name = "hvsi";
+ driver->name = "hvsi";
+ driver->major = HVSI_MAJOR;
+ driver->minor_start = HVSI_MINOR;
+ driver->type = TTY_DRIVER_TYPE_SYSTEM;
+ driver->init_termios = tty_std_termios;
+ driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+ driver->init_termios.c_ispeed = 9600;
+ driver->init_termios.c_ospeed = 9600;
+ driver->flags = TTY_DRIVER_REAL_RAW;
+ tty_set_operations(driver, &hvsi_ops);

for (i=0; i < hvsi_count; i++) {
struct hvsi_struct *hp = &hvsi_ports[i];
int ret = 1;

- tty_port_link_device(&hp->port, hvsi_driver, i);
+ tty_port_link_device(&hp->port, driver, i);

ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp);
if (ret)
@@ -1069,12 +1070,14 @@ static int __init hvsi_init(void)
}
hvsi_wait = wait_for_state; /* irqs active now */

- ret = tty_register_driver(hvsi_driver);
+ ret = tty_register_driver(driver);
if (ret) {
pr_err("Couldn't register hvsi console driver\n");
goto err_free_irq;
}

+ hvsi_driver = driver;
+
printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count);

return 0;
@@ -1085,7 +1088,7 @@ static int __init hvsi_init(void)

free_irq(hp->virq, hp);
}
- tty_driver_kref_put(hvsi_driver);
+ tty_driver_kref_put(driver);

return ret;
}
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index bffef8e47dac..c99917a07a96 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -1445,51 +1445,53 @@ EXPORT_SYMBOL_GPL(gserial_resume);

static int userial_init(void)
{
+ struct tty_driver *driver;
unsigned i;
int status;

- gs_tty_driver = alloc_tty_driver(MAX_U_SERIAL_PORTS);
- if (!gs_tty_driver)
+ driver = alloc_tty_driver(MAX_U_SERIAL_PORTS);
+ if (!driver)
return -ENOMEM;

- gs_tty_driver->driver_name = "g_serial";
- gs_tty_driver->name = "ttyGS";
+ driver->driver_name = "g_serial";
+ driver->name = "ttyGS";
/* uses dynamically assigned dev_t values */

- gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- gs_tty_driver->init_termios = tty_std_termios;
+ driver->type = TTY_DRIVER_TYPE_SERIAL;
+ driver->subtype = SERIAL_TYPE_NORMAL;
+ driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ driver->init_termios = tty_std_termios;

/* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on
* MS-Windows. Otherwise, most of these flags shouldn't affect
* anything unless we were to actually hook up to a serial line.
*/
- gs_tty_driver->init_termios.c_cflag =
+ driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- gs_tty_driver->init_termios.c_ispeed = 9600;
- gs_tty_driver->init_termios.c_ospeed = 9600;
+ driver->init_termios.c_ispeed = 9600;
+ driver->init_termios.c_ospeed = 9600;

- tty_set_operations(gs_tty_driver, &gs_tty_ops);
+ tty_set_operations(driver, &gs_tty_ops);
for (i = 0; i < MAX_U_SERIAL_PORTS; i++)
mutex_init(&ports[i].lock);

/* export the driver ... */
- status = tty_register_driver(gs_tty_driver);
+ status = tty_register_driver(driver);
if (status) {
pr_err("%s: cannot register, err %d\n",
__func__, status);
goto fail;
}

+ gs_tty_driver = driver;
+
pr_debug("%s: registered %d ttyGS* device%s\n", __func__,
MAX_U_SERIAL_PORTS,
(MAX_U_SERIAL_PORTS == 1) ? "" : "s");

return status;
fail:
- put_tty_driver(gs_tty_driver);
- gs_tty_driver = NULL;
+ put_tty_driver(driver);
return status;
}
module_init(userial_init);
--
2.32.0