@@ -1224,6 +1224,7 @@ static void autoconfig(struct uart_8250_port *up)
unsigned char status1, scratch, scratch2, scratch3;
unsigned char save_lcr, save_mcr;
struct uart_port *port = &up->port;
+ unsigned long cs_flags;
unsigned long flags;
unsigned int old_capabilities;
bool is_console;
@@ -1244,8 +1245,6 @@ static void autoconfig(struct uart_8250_port *up)
up->bugs = 0;
if (!(port->flags & UPF_BUGGY_UART)) {
- unsigned long cs_flags;
-
is_console = uart_console(port);
if (is_console)
@@ -137,7 +137,6 @@ static inline int con_debug_leave(void)
#define CON_ANYTIME (16) /* Safe to call when cpu is offline */
#define CON_BRL (32) /* Used for a braille device */
#define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */
-#define CON_THD_BLOCKED (128) /* Thread blocked because console is locked */
#ifdef CONFIG_HAVE_ATOMIC_CONSOLE
struct console_atomic_data {
@@ -169,12 +168,13 @@ struct console {
struct console_atomic_data *atomic_data;
#endif
struct task_struct *thread;
+ bool blocked;
/*
* The per-console lock is used by printing kthreads to synchronize
* this console with callers of console_lock(). This is necessary in
* order to allow printing kthreads to run in parallel to each other,
- * while each safely accessing their own @flags and synchronizing
+ * while each safely accessing the @blocked field and synchronizing
* against direct printing via console_lock/console_unlock.
*
* Note: For synchronizing against direct printing via
@@ -301,7 +301,7 @@ static bool panic_in_progress(void)
/*
* Tracks whether kthread printers are all blocked. A value of true implies
* that the console is locked via console_lock() or the console is suspended.
- * Reading and writing to this variable requires holding @console_sem.
+ * Writing to this variable requires holding @console_sem.
*/
static bool console_kthreads_blocked;
@@ -316,7 +316,7 @@ static void console_kthreads_block(void)
for_each_console(con) {
mutex_lock(&con->lock);
- con->flags |= CON_THD_BLOCKED;
+ con->blocked = true;
mutex_unlock(&con->lock);
}
@@ -334,7 +334,7 @@ static void console_kthreads_unblock(void)
for_each_console(con) {
mutex_lock(&con->lock);
- con->flags &= ~CON_THD_BLOCKED;
+ con->blocked = false;
mutex_unlock(&con->lock);
}
@@ -2756,7 +2756,11 @@ static int console_cpu_notify(unsigned int cpu)
if (console_trylock())
console_unlock();
else {
- /* Some kthread printers may have become usable. */
+ /*
+ * If a new CPU comes online, the conditions for
+ * printer_should_wake() may have changed for some
+ * kthread printer with !CON_ANYTIME.
+ */
wake_up_klogd();
}
}
@@ -2783,25 +2787,6 @@ void console_lock(void)
}
EXPORT_SYMBOL(console_lock);
-/*
- * Lock the console_lock, but rather than blocking all the kthread printers,
- * lock a specified kthread printer and hold the lock. This is useful if
- * console flags for a particular console need to be updated.
- */
-static void console_lock_single_hold(struct console *con)
-{
- might_sleep();
- down_console_sem();
- mutex_lock(&con->lock);
- console_may_schedule = 1;
-}
-
-static void console_unlock_single_release(struct console *con)
-{
- mutex_unlock(&con->lock);
- up_console_sem();
-}
-
/**
* console_trylock - try to lock the console system for exclusive use.
*
@@ -2885,7 +2870,7 @@ static inline bool __console_is_usable(short flags)
* Check if the given console is currently capable and allowed to print
* records.
*
- * Requires holding the console_lock or con->lock.
+ * Requires holding the console_lock.
*/
static inline bool console_is_usable(struct console *con, bool atomic_printing)
{
@@ -3008,6 +2993,7 @@ static void write_console_seq(struct console *con, u64 val, bool atomic_printing
* true.
*
* Requires the console_lock if @handover is non-NULL.
+ * Requires con->lock otherwise.
*/
static bool __console_emit_next_record(struct console *con, char *text, char *ext_text,
char *dropped_text, bool atomic_printing,
@@ -3197,13 +3183,12 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
return any_usable;
}
-#ifdef CONFIG_HAVE_ATOMIC_CONSOLE
+#if defined(CONFIG_HAVE_ATOMIC_CONSOLE) && defined(CONFIG_PRINTK)
static bool console_emit_next_record(struct console *con, char *text, char *ext_text,
char *dropped_text, bool atomic_printing);
static void atomic_console_flush_all(void)
{
- bool any_usable = false;
unsigned long flags;
struct console *con;
bool any_progress;
@@ -3227,7 +3212,6 @@ static void atomic_console_flush_all(void)
if (!console_is_usable(con, true))
continue;
- any_usable = true;
if (con->flags & CON_EXTENDED) {
/* Extended consoles do not print "dropped messages". */
@@ -3257,7 +3241,7 @@ static void atomic_console_flush_all(void)
printk_cpu_sync_put_irqrestore(flags);
}
-#else /* CONFIG_HAVE_ATOMIC_CONSOLE */
+#else /* CONFIG_HAVE_ATOMIC_CONSOLE && CONFIG_PRINTK */
#define atomic_console_flush_all()
#endif
@@ -3430,20 +3414,17 @@ struct tty_driver *console_device(int *index)
void console_stop(struct console *console)
{
__pr_flush(console, 1000, true);
- console_lock_single_hold(console);
+ console_lock();
console->flags &= ~CON_ENABLED;
- console_unlock_single_release(console);
+ console_unlock();
}
EXPORT_SYMBOL(console_stop);
-
void console_start(struct console *console)
{
- console_lock_single_hold(console);
+ console_lock();
console->flags |= CON_ENABLED;
- console_unlock_single_release(console);
- /* Wake the newly enabled kthread printer. */
- wake_up_klogd();
+ console_unlock();
__pr_flush(console, 1000, true);
}
EXPORT_SYMBOL(console_start);
@@ -3645,7 +3626,7 @@ void register_console(struct console *newcon)
atomic_long_set(&newcon->dropped, 0);
newcon->thread = NULL;
- newcon->flags |= CON_THD_BLOCKED;
+ newcon->blocked = true;
mutex_init(&newcon->lock);
#ifdef CONFIG_HAVE_ATOMIC_CONSOLE
newcon->atomic_data = NULL;
@@ -3703,7 +3684,7 @@ int unregister_console(struct console *console)
return 0;
res = -ENODEV;
- console_lock_single_hold(console);
+ console_lock();
if (console_drivers == console) {
console_drivers=console->next;
res = 0;
@@ -3733,14 +3714,14 @@ int unregister_console(struct console *console)
console->flags &= ~CON_ENABLED;
/*
- * console->thread can only be cleared while holding con->lock. But
- * stopping the thread must be done without con->lock. The task that
- * clears @thread is the task that stops the kthread.
+ * console->thread can only be cleared under the console lock. But
+ * stopping the thread must be done without the console lock. The
+ * task that clears @thread is the task that stops the kthread.
*/
thd = console->thread;
console->thread = NULL;
- console_unlock_single_release(console);
+ console_unlock();
if (thd)
kthread_stop(thd);
@@ -3758,7 +3739,7 @@ int unregister_console(struct console *console)
out_disable_unlock:
console->flags &= ~CON_ENABLED;
- console_unlock_single_release(console);
+ console_unlock();
return res;
}
@@ -3975,6 +3956,11 @@ static bool printer_should_wake(struct console *con, u64 seq)
if (kthread_should_stop() || !printk_kthreads_available)
return true;
+ if (con->blocked ||
+ console_kthreads_atomically_blocked()) {
+ return false;
+ }
+
/*
* This is an unsafe read from con->flags, but a false positive is
* not a problem. Worst case it would allow the printer to wake up
@@ -3986,11 +3972,6 @@ static bool printer_should_wake(struct console *con, u64 seq)
if (!__console_is_usable(flags))
return false;
- if ((flags & CON_THD_BLOCKED) ||
- console_kthreads_atomically_blocked()) {
- return false;
- }
-
return prb_read_valid(prb, seq, NULL);
}
@@ -4057,13 +4038,22 @@ static int printk_kthread_func(void *data)
if (error)
continue;
- if (!console_is_usable(con, false)) {
+ if (con->blocked ||
+ !console_kthread_printing_tryenter()) {
+ /* Another context has locked the console_lock. */
mutex_unlock(&con->lock);
continue;
}
- if ((con->flags & CON_THD_BLOCKED) ||
- !console_kthread_printing_tryenter()) {
+ /*
+ * Although this context has not locked the console_lock, it
+ * is known that the console_lock is not locked and it is not
+ * possible for any other context to lock the console_lock.
+ * Therefore it is safe to read con->flags.
+ */
+
+ if (!__console_is_usable(con->flags)) {
+ console_kthread_printing_exit();
mutex_unlock(&con->lock);
continue;
}
@@ -4092,14 +4082,14 @@ static int printk_kthread_func(void *data)
kfree(ext_text);
kfree(text);
- mutex_lock(&con->lock);
+ console_lock();
/*
* If this kthread is being stopped by another task, con->thread will
* already be NULL. That is fine. The important thing is that it is
* NULL after the kthread exits.
*/
con->thread = NULL;
- mutex_unlock(&con->lock);
+ console_unlock();
return 0;
}
@@ -1 +1 @@
--rt2
+-rt3