linux-stable/drivers/tty/ttynull.c
Petr Mladek a91bd6223e Revert "init/console: Use ttynull as a fallback when there is no console"
This reverts commit 757055ae8d.

The commit caused that ttynull was used as the default console
on several systems[1][2][3]. As a result, the console was
blank even when a better alternative existed.

It happened when there was no console configured
on the command line and ttynull_init() was the first initcall
calling register_console().

Or it happened when /dev/ did not exist when console_on_rootfs()
was called. It was not able to open /dev/console even though
a console driver was registered. It tried to add ttynull console
but it obviously did not help. But ttynull became the preferred
console and was used by /dev/console when it was available later.

The commit tried to fix a historical problem that have been there
for ages. The primary motivation was the commit 3cffa06aee
("printk/console: Allow to disable console output by using console=""
 or console=null"). It provided a clean solution for a workaround
 that was widely used and worked only by chance.

This revert causes that the console="" or console=null command line
options will again work only by chance. These options will cause that
a particular console will be preferred and the default (tty) ones
will not get enabled. There will be no console registered at
all. As a result there won't be stdin, stdout, and stderr for
the init process. But it worked exactly this way even before.

The proper solution has to fulfill many conditions:

  + Register ttynull only when explicitly required or as
    the ultimate fallback.

  + ttynull should get associated with /dev/console but it must
    not become preferred console when used as a fallback.
    Especially, it must still be possible to replace it
    by a better console later.

Such a change requires clean up of the register_console() code.
Otherwise, it would be even harder to follow. Especially, the use
of has_preferred_console and CON_CONSDEV flag is tricky. The clean
up is risky. The ordering of consoles is not well defined. And
any changes tend to break existing user settings.

Do the revert at the least risky solution for now.

[1] https://lore.kernel.org/linux-kselftest/20201221144302.GR4077@smile.fi.intel.com/
[2] https://lore.kernel.org/lkml/d2a3b3c0-e548-7dd1-730f-59bc5c04e191@synopsys.com/
[3] https://patchwork.ozlabs.org/project/linux-um/patch/20210105120128.10854-1-thomas@m3y3r.de/

Reported-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reported-by: Vineet Gupta <vgupta@synopsys.com>
Reported-by: Thomas Meyer <thomas@m3y3r.de>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2021-01-08 11:02:18 -08:00

109 lines
2.3 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 Axis Communications AB
*
* Based on ttyprintk.c:
* Copyright (C) 2010 Samo Pogacnik
*/
#include <linux/console.h>
#include <linux/module.h>
#include <linux/tty.h>
static const struct tty_port_operations ttynull_port_ops;
static struct tty_driver *ttynull_driver;
static struct tty_port ttynull_port;
static int ttynull_open(struct tty_struct *tty, struct file *filp)
{
return tty_port_open(&ttynull_port, tty, filp);
}
static void ttynull_close(struct tty_struct *tty, struct file *filp)
{
tty_port_close(&ttynull_port, tty, filp);
}
static void ttynull_hangup(struct tty_struct *tty)
{
tty_port_hangup(&ttynull_port);
}
static int ttynull_write(struct tty_struct *tty, const unsigned char *buf,
int count)
{
return count;
}
static int ttynull_write_room(struct tty_struct *tty)
{
return 65536;
}
static const struct tty_operations ttynull_ops = {
.open = ttynull_open,
.close = ttynull_close,
.hangup = ttynull_hangup,
.write = ttynull_write,
.write_room = ttynull_write_room,
};
static struct tty_driver *ttynull_device(struct console *c, int *index)
{
*index = 0;
return ttynull_driver;
}
static struct console ttynull_console = {
.name = "ttynull",
.device = ttynull_device,
};
static int __init ttynull_init(void)
{
struct tty_driver *driver;
int ret;
driver = tty_alloc_driver(1,
TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_UNNUMBERED_NODE);
if (IS_ERR(driver))
return PTR_ERR(driver);
tty_port_init(&ttynull_port);
ttynull_port.ops = &ttynull_port_ops;
driver->driver_name = "ttynull";
driver->name = "ttynull";
driver->type = TTY_DRIVER_TYPE_CONSOLE;
driver->init_termios = tty_std_termios;
driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
tty_set_operations(driver, &ttynull_ops);
tty_port_link_device(&ttynull_port, driver, 0);
ret = tty_register_driver(driver);
if (ret < 0) {
put_tty_driver(driver);
tty_port_destroy(&ttynull_port);
return ret;
}
ttynull_driver = driver;
register_console(&ttynull_console);
return 0;
}
static void __exit ttynull_exit(void)
{
unregister_console(&ttynull_console);
tty_unregister_driver(ttynull_driver);
put_tty_driver(ttynull_driver);
tty_port_destroy(&ttynull_port);
}
module_init(ttynull_init);
module_exit(ttynull_exit);
MODULE_LICENSE("GPL v2");