Skip to content

Commit 8e27473

Browse files
jognesspmladek
authored andcommitted
printk: extend console_lock for per-console locking
Currently threaded console printers synchronize against each other using console_lock(). However, different console drivers are unrelated and do not require any synchronization between each other. Removing the synchronization between the threaded console printers will allow each console to print at its own speed. But the threaded consoles printers do still need to synchronize against console_lock() callers. Introduce a per-console mutex and a new console boolean field @Blocked to provide this synchronization. console_lock() is modified so that it must acquire the mutex of each console in order to set the @Blocked field. Console printing threads will acquire their mutex while printing a record. If @Blocked was set, the thread will go back to sleep instead of printing. The reason for the @Blocked boolean field is so that console_lock() callers do not need to acquire multiple console mutexes simultaneously, which would introduce unnecessary complexity due to nested mutex locking. Also, a new field was chosen instead of adding a new @flags value so that the blocked status could be checked without concern of reading inconsistent values due to @flags updates from other contexts. Threaded console printers also need to synchronize against console_trylock() callers. Since console_trylock() may be called from any context, the per-console mutex cannot be used for this synchronization. (mutex_trylock() cannot be called from atomic contexts.) Introduce a global atomic counter to identify if any threaded printers are active. The threaded printers will also check the atomic counter to identify if the console has been locked by another task via console_trylock(). Note that @console_sem is still used to provide synchronization between console_lock() and console_trylock() callers. A locking overview for console_lock(), console_trylock(), and the threaded printers is as follows (pseudo code): console_lock() { down(&console_sem); for_each_console(con) { mutex_lock(&con->lock); con->blocked = true; mutex_unlock(&con->lock); } /* console_lock acquired */ } console_trylock() { if (down_trylock(&console_sem) == 0) { if (atomic_cmpxchg(&console_kthreads_active, 0, -1) == 0) { /* console_lock acquired */ } } } threaded_printer() { mutex_lock(&con->lock); if (!con->blocked) { /* console_lock() callers blocked */ if (atomic_inc_unless_negative(&console_kthreads_active)) { /* console_trylock() callers blocked */ con->write(); atomic_dec(&console_lock_count); } } mutex_unlock(&con->lock); } The console owner and waiter logic now only applies between contexts that have taken the console_lock via console_trylock(). Threaded printers never take the console_lock, so they do not have a console_lock to handover. Tasks that have used console_lock() will block the threaded printers using a mutex and if the console_lock is handed over to an atomic context, it would be unable to unblock the threaded printers. However, the console_trylock() case is really the only scenario that is interesting for handovers anyway. @panic_console_dropped must change to atomic_t since it is no longer protected exclusively by the console_lock. Since threaded printers remain asleep if they see that the console is locked, they now must be explicitly woken in __console_unlock(). This means wake_up_klogd() calls following a console_unlock() are no longer necessary and are removed. Also note that threaded printers no longer need to check @console_suspended. The check for the @Blocked field implicitly covers the suspended console case. Signed-off-by: John Ogness <john.ogness@linutronix.de> Reviewed-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Petr Mladek <pmladek@suse.com> Link: https://lore.kernel.org/r/878rrs6ft7.fsf@jogness.linutronix.de
1 parent 09c5ba0 commit 8e27473

File tree

2 files changed

+220
-56
lines changed

2 files changed

+220
-56
lines changed

include/linux/console.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <linux/atomic.h>
1818
#include <linux/types.h>
19+
#include <linux/mutex.h>
1920

2021
struct vc_data;
2122
struct console_font_op;
@@ -154,6 +155,20 @@ struct console {
154155
u64 seq;
155156
unsigned long dropped;
156157
struct task_struct *thread;
158+
bool blocked;
159+
160+
/*
161+
* The per-console lock is used by printing kthreads to synchronize
162+
* this console with callers of console_lock(). This is necessary in
163+
* order to allow printing kthreads to run in parallel to each other,
164+
* while each safely accessing the @blocked field and synchronizing
165+
* against direct printing via console_lock/console_unlock.
166+
*
167+
* Note: For synchronizing against direct printing via
168+
* console_trylock/console_unlock, see the static global
169+
* variable @console_kthreads_active.
170+
*/
171+
struct mutex lock;
157172

158173
void *data;
159174
struct console *next;

0 commit comments

Comments
 (0)