• Petr Mladek's avatar
    printk/console: Clean up boot console handling in register_console() · 5e8ba485
    Petr Mladek authored
    The variable @bcon has two meanings. It is used several times for iterating
    the list of registered consoles. In the meantime, it holds the information
    whether a boot console is first in @console_drivers list.
    
    The information about the 1st console driver used to be important for
    the decision whether to install the new console by default or not.
    It allowed to re-evaluate the variable @need_default_console when
    a real console with tty binding has been unregistered in the meantime.
    
    The decision about the default console is not longer affected by @bcon
    variable. The current code checks whether the first driver is real
    and has tty binding directly.
    
    The information about the first console is still used for two more
    decisions:
    
      1. It prevents duplicate output on non-boot consoles with
         CON_CONSDEV flag set.
    
      2. Early/boot consoles are unregistered when a real console with
         CON_CONSDEV is registered and @keep_bootcon is not set.
    
    The behavior in the real life is far from obvious. @bcon is set according
    to the first console @console_drivers list. But the first position in
    the list is special:
    
      1. Consoles with CON_CONSDEV flag are put at the beginning of
         the list. It is either the preferred console or any console
         with tty binding registered by default.
    
      2. Another console might become the first in the list when
         the first console in the list is unregistered. It might
         happen either explicitly or automatically when boot
         consoles are unregistered.
    
    There is one more important rule:
    
      + Boot consoles can't be registered when any real console
        is already registered.
    
    It is a puzzle. The main complication is the dependency on the first
    position is the list and the complicated rules around it.
    
    Let's try to make it easier:
    
    1. Add variable @bootcon_enabled and set it by iterating all registered
       consoles. The variable has obvious meaning and more predictable
       behavior. Any speed optimization and other tricks are not worth it.
    
    2. Use a generic name for the variable that is used to iterate
       the list on registered console drivers.
    
    Behavior change:
    
    No, maybe surprisingly, there is _no_ behavior change!
    
    Let's provide the proof by contradiction. Both operations, duplicate
    output prevention and boot consoles removal, are done only when
    the newly added console has CON_CONSDEV flag set. The behavior
    would change when the new @bootcon_enabled has different value
    than the original @bcon.
    
    By other words, the behavior would change when the following conditions
    are true:
    
       + a console with CON_CONSDEV flag is added
       + a real (non-boot) console is the first in the list
       + a boot console is later in the list
    
    Now, a real console might be first in the list only when:
    
       + It was the first registered console. In this case, there can't be
         any boot console because any later ones were rejected.
    
       + It was put at the first position because it had CON_CONSDEV flag
         set. It was either the preferred console or it was a console with
         tty binding registered by default. We are interested only in
         a real consoles here. And real console with tty binding fulfills
         conditions of the default console.
    
         Now, there is always only one console that is either preferred
         or fulfills conditions of the default console. It can't be already
         in the list and being registered at the same time.
    
    As a result, the above three conditions could newer be "true" at
    the same time. Therefore the behavior can't change.
    
    Final dilemma:
    
    OK, the new code has the same behavior. But is the change in the right
    direction? What if the handling of @console_drivers is updated in
    the future?
    
    OK, let's look at it from another angle:
    
    1. The ordering of @console_drivers list is important only in
       console_device() function. The first console driver with tty
       binding gets associated with /dev/console.
    
    2. CON_CONSDEV flag is shown in /proc/consoles. And it should be set
       for the driver that is returned by console_device().
    
    3. A boot console is removed and the duplicated output is prevented
       when the real console with CON_CONSDEV flag is registered.
    
    Now, in the ideal world:
    
    + The driver associated with /dev/console should be either a console
      preferred via the command line, device tree, or SPCR. Or it should
      be the first real console with tty binding registered by default.
    
    + The code should match the related boot and real console drivers.
      It should unregister only the obsolete boot driver. And the duplicated
      output should be prevented only on the related real driver.
    
    It is clear that it is not guaranteed by the current code. Instead,
    the current code looks like a maze of heuristics that try to achieve
    the above.
    
    It is result of adding several features over last few decades. For example,
    a possibility to register more consoles, unregister consoles, boot
    consoles, consoles without tty binding, device tree, SPCR, braille
    consoles.
    
    Anyway, there is no reason why the decision, about removing boot consoles
    and preventing duplicated output, should depend on the first console
    in the list. The current code does the decisions primary by CON_CONSDEV
    flag that is used for the preferred console. It looks like a
    good compromise. And the change seems to be in the right direction.
    Signed-off-by: default avatarPetr Mladek <pmladek@suse.com>
    Link: https://lore.kernel.org/r/20211122132649.12737-6-pmladek@suse.com
    5e8ba485
printk.c 94.2 KB