Merge tag 'printk-for-5.19-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Jun 2022 19:57:42 +0000 (14:57 -0500)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Jun 2022 19:57:42 +0000 (14:57 -0500)
Pull printk fixes from Petr Mladek:
 "Make the global console_sem available for CPU that is handling panic()
  or shutdown.

  This is an old problem when an existing console lock owner might block
  console output, but it became more visible with the kthreads"

* tag 'printk-for-5.19-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux:
  printk: Wait for the global console lock when the system is going down
  printk: Block console kthreads when direct printing will be required

1  2 
kernel/reboot.c

diff --combined kernel/reboot.c
index b5a71d1ff603c36fd61138297fe2e83d1455099e,b44165b1a39925705d9db71c5fca8ac1eb5d9d53..80564ffafabff9b073c07976accb5bc9c2a80fca
@@@ -82,6 -82,7 +82,7 @@@ void kernel_restart_prepare(char *cmd
  {
        blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
        system_state = SYSTEM_RESTART;
+       try_block_console_kthreads(10000);
        usermodehelper_disable();
        device_shutdown();
  }
@@@ -270,6 -271,7 +271,7 @@@ static void kernel_shutdown_prepare(enu
        blocking_notifier_call_chain(&reboot_notifier_list,
                (state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL);
        system_state = state;
+       try_block_console_kthreads(10000);
        usermodehelper_disable();
        device_shutdown();
  }
@@@ -315,43 -317,6 +317,43 @@@ static int sys_off_notify(struct notifi
        return handler->sys_off_cb(&data);
  }
  
 +static struct sys_off_handler platform_sys_off_handler;
 +
 +static struct sys_off_handler *alloc_sys_off_handler(int priority)
 +{
 +      struct sys_off_handler *handler;
 +      gfp_t flags;
 +
 +      /*
 +       * Platforms like m68k can't allocate sys_off handler dynamically
 +       * at the early boot time because memory allocator isn't available yet.
 +       */
 +      if (priority == SYS_OFF_PRIO_PLATFORM) {
 +              handler = &platform_sys_off_handler;
 +              if (handler->cb_data)
 +                      return ERR_PTR(-EBUSY);
 +      } else {
 +              if (system_state > SYSTEM_RUNNING)
 +                      flags = GFP_ATOMIC;
 +              else
 +                      flags = GFP_KERNEL;
 +
 +              handler = kzalloc(sizeof(*handler), flags);
 +              if (!handler)
 +                      return ERR_PTR(-ENOMEM);
 +      }
 +
 +      return handler;
 +}
 +
 +static void free_sys_off_handler(struct sys_off_handler *handler)
 +{
 +      if (handler == &platform_sys_off_handler)
 +              memset(handler, 0, sizeof(*handler));
 +      else
 +              kfree(handler);
 +}
 +
  /**
   *    register_sys_off_handler - Register sys-off handler
   *    @mode: Sys-off mode
@@@ -382,9 -347,9 +384,9 @@@ register_sys_off_handler(enum sys_off_m
        struct sys_off_handler *handler;
        int err;
  
 -      handler = kzalloc(sizeof(*handler), GFP_KERNEL);
 -      if (!handler)
 -              return ERR_PTR(-ENOMEM);
 +      handler = alloc_sys_off_handler(priority);
 +      if (IS_ERR(handler))
 +              return handler;
  
        switch (mode) {
        case SYS_OFF_MODE_POWER_OFF_PREPARE:
                break;
  
        default:
 -              kfree(handler);
 +              free_sys_off_handler(handler);
                return ERR_PTR(-EINVAL);
        }
  
        }
  
        if (err) {
 -              kfree(handler);
 +              free_sys_off_handler(handler);
                return ERR_PTR(err);
        }
  
@@@ -446,7 -411,7 +448,7 @@@ void unregister_sys_off_handler(struct 
  {
        int err;
  
 -      if (!handler)
 +      if (IS_ERR_OR_NULL(handler))
                return;
  
        if (handler->blocking)
        /* sanity check, shall never happen */
        WARN_ON(err);
  
 -      kfree(handler);
 +      free_sys_off_handler(handler);
  }
  EXPORT_SYMBOL_GPL(unregister_sys_off_handler);
  
@@@ -621,23 -586,7 +623,23 @@@ static void do_kernel_power_off_prepare
   */
  void do_kernel_power_off(void)
  {
 +      struct sys_off_handler *sys_off = NULL;
 +
 +      /*
 +       * Register sys-off handlers for legacy PM callback. This allows
 +       * legacy PM callbacks temporary co-exist with the new sys-off API.
 +       *
 +       * TODO: Remove legacy handlers once all legacy PM users will be
 +       *       switched to the sys-off based APIs.
 +       */
 +      if (pm_power_off)
 +              sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
 +                                                 SYS_OFF_PRIO_DEFAULT,
 +                                                 legacy_pm_power_off, NULL);
 +
        atomic_notifier_call_chain(&power_off_handler_list, 0, NULL);
 +
 +      unregister_sys_off_handler(sys_off);
  }
  
  /**
   */
  bool kernel_can_power_off(void)
  {
 -      return !atomic_notifier_call_chain_is_empty(&power_off_handler_list);
 +      return !atomic_notifier_call_chain_is_empty(&power_off_handler_list) ||
 +              pm_power_off;
  }
  EXPORT_SYMBOL_GPL(kernel_can_power_off);
  
@@@ -684,6 -632,7 +686,6 @@@ SYSCALL_DEFINE4(reboot, int, magic1, in
                void __user *, arg)
  {
        struct pid_namespace *pid_ns = task_active_pid_ns(current);
 -      struct sys_off_handler *sys_off = NULL;
        char buffer[256];
        int ret = 0;
  
        if (ret)
                return ret;
  
 -      /*
 -       * Register sys-off handlers for legacy PM callback. This allows
 -       * legacy PM callbacks temporary co-exist with the new sys-off API.
 -       *
 -       * TODO: Remove legacy handlers once all legacy PM users will be
 -       *       switched to the sys-off based APIs.
 -       */
 -      if (pm_power_off) {
 -              sys_off = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
 -                                                 SYS_OFF_PRIO_DEFAULT,
 -                                                 legacy_pm_power_off, NULL);
 -              if (IS_ERR(sys_off))
 -                      return PTR_ERR(sys_off);
 -      }
 -
        /* Instead of trying to make the power_off code look like
         * halt when pm_power_off is not set do it the easy way.
         */
                break;
        }
        mutex_unlock(&system_transition_mutex);
 -      unregister_sys_off_handler(sys_off);
        return ret;
  }