diff options
-rw-r--r-- | kernel/printk/printk.c | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 20c39505f5aa..4cd2c50dd06d 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -3548,9 +3548,11 @@ static int unregister_console_locked(struct console *console); */ void register_console(struct console *newcon) { - struct console *con; + bool use_device_lock = (newcon->flags & CON_NBCON) && newcon->write_atomic; bool bootcon_registered = false; bool realcon_registered = false; + struct console *con; + unsigned long flags; u64 init_seq; int err; @@ -3638,6 +3640,19 @@ void register_console(struct console *newcon) } /* + * If another context is actively using the hardware of this new + * console, it will not be aware of the nbcon synchronization. This + * is a risk that two contexts could access the hardware + * simultaneously if this new console is used for atomic printing + * and the other context is still using the hardware. + * + * Use the driver synchronization to ensure that the hardware is not + * in use while this new console transitions to being registered. + */ + if (use_device_lock) + newcon->device_lock(newcon, &flags); + + /* * Put this console in the list - keep the * preferred driver at the head of the list. */ @@ -3661,6 +3676,10 @@ void register_console(struct console *newcon) * register_console() completes. */ + /* This new console is now registered. */ + if (use_device_lock) + newcon->device_unlock(newcon, flags); + console_sysfs_notify(); /* @@ -3689,6 +3708,8 @@ EXPORT_SYMBOL(register_console); /* Must be called under console_list_lock(). */ static int unregister_console_locked(struct console *console) { + bool use_device_lock = (console->flags & CON_NBCON) && console->write_atomic; + unsigned long flags; int res; lockdep_assert_console_list_lock_held(); @@ -3707,8 +3728,18 @@ static int unregister_console_locked(struct console *console) if (!console_is_registered_locked(console)) return -ENODEV; + /* + * Use the driver synchronization to ensure that the hardware is not + * in use while this console transitions to being unregistered. + */ + if (use_device_lock) + console->device_lock(console, &flags); + hlist_del_init_rcu(&console->node); + if (use_device_lock) + console->device_unlock(console, flags); + /* * <HISTORICAL> * If this isn't the last console and it has CON_CONSDEV set, we |