• Benjamin Herrenschmidt's avatar
    printk: Fix preferred console selection with multiple matches · e369d822
    Benjamin Herrenschmidt authored
    In the following circumstances, the rule of selecting the console
    corresponding to the last "console=" entry on the command line as
    the preferred console (CON_CONSDEV, ie, /dev/console) fails. This
    is a specific example, but it could happen with different consoles
    that have a similar name aliasing mechanism.
    
      - The kernel command line has both console=tty0 and console=ttyS0
        in that order (the latter with speed etc... arguments).
        This is common with some cloud setups such as Amazon Linux.
    
      - add_preferred_console is called early to register "uart0". In
        our case that happens from acpi_parse_spcr() on arm64 since the
        "enable_console" argument is true on that architecture. This causes
        "uart0" to become entry 0 of the console_cmdline array.
    
    Now, because of the above, what happens is:
    
      - add_preferred_console is called by the cmdline parsing for tty0
        and ttyS0 respectively, thus occupying entries 1 and 2 of the
        console_cmdline array (since this happens after ACPI SPCR parsing).
        At that point preferred_console is set to 2 as expected.
    
      - When the tty layer kicks in, it will call register_console for tty0.
        This will match entry 1 in console_cmdline array. It isn't our
        preferred console but because it's our only console at this point,
        it will end up "first" in the consoles list.
    
      - When 8250 probes the actual serial port later on, it calls
        register_console for ttyS0. At that point the loop in register_console
        tries to match it with the entries in the console_cmdline array.
        Ideally this should match ttyS0 in entry 2, which is preferred, causing
        it to be inserted first and to replace tty0 as CONSDEV. However, 8250
        provides a "match" hook in its struct console, and that hook will match
        "uart" as an alias to "ttyS". So we match uart0 at entry 0 in the array
        which is not the preferred console and will not match entry 2 which is
        since we break out of the loop on the first match. As a result,
        we don't set CONSDEV and don't insert it first, but second in
        the console list.
    
        As a result, we end up with tty0 remaining first in the array, and thus
        /dev/console going there instead of the last user specified one which
        is ttyS0.
    
    This tentative fix register_console() to scan first for consoles
    specified on the command line, and only if none is found, to then
    scan for consoles specified by the architecture.
    
    Link: https://lore.kernel.org/r/20200213095133.23176-3-pmladek@suse.comSigned-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
    Reviewed-by: default avatarPetr Mladek <pmladek@suse.com>
    Reviewed-by: default avatarSergey Senozhatsky <sergey.senozhatsky@gmail.com>
    Signed-off-by: default avatarPetr Mladek <pmladek@suse.com>
    e369d822
printk.c 85.3 KB