Commit 53e16fbd authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-printk-for-linus' of...

Merge branch 'core-printk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'core-printk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  printk: Fix "printk: Enable the use of more than one CON_BOOT (early console)"
  printk: Restore previous console_loglevel when re-enabling logging
  printk: Ensure that "console enabled" messages are printed on the console
  printk: Enable the use of more than one CON_BOOT (early console)
parents 4e3408d9 42c2c8c8
...@@ -36,6 +36,12 @@ ...@@ -36,6 +36,12 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
/*
* for_each_console() allows you to iterate on each console
*/
#define for_each_console(con) \
for (con = console_drivers; con != NULL; con = con->next)
/* /*
* Architectures can override it: * Architectures can override it:
*/ */
...@@ -61,6 +67,8 @@ int console_printk[4] = { ...@@ -61,6 +67,8 @@ int console_printk[4] = {
DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
}; };
static int saved_console_loglevel = -1;
/* /*
* Low level drivers may need that to know if they can schedule in * Low level drivers may need that to know if they can schedule in
* their unblank() callback or not. So let's export it. * their unblank() callback or not. So let's export it.
...@@ -372,10 +380,15 @@ int do_syslog(int type, char __user *buf, int len) ...@@ -372,10 +380,15 @@ int do_syslog(int type, char __user *buf, int len)
logged_chars = 0; logged_chars = 0;
break; break;
case 6: /* Disable logging to console */ case 6: /* Disable logging to console */
if (saved_console_loglevel == -1)
saved_console_loglevel = console_loglevel;
console_loglevel = minimum_console_loglevel; console_loglevel = minimum_console_loglevel;
break; break;
case 7: /* Enable logging to console */ case 7: /* Enable logging to console */
console_loglevel = default_console_loglevel; if (saved_console_loglevel != -1) {
console_loglevel = saved_console_loglevel;
saved_console_loglevel = -1;
}
break; break;
case 8: /* Set level of messages printed to console */ case 8: /* Set level of messages printed to console */
error = -EINVAL; error = -EINVAL;
...@@ -384,6 +397,8 @@ int do_syslog(int type, char __user *buf, int len) ...@@ -384,6 +397,8 @@ int do_syslog(int type, char __user *buf, int len)
if (len < minimum_console_loglevel) if (len < minimum_console_loglevel)
len = minimum_console_loglevel; len = minimum_console_loglevel;
console_loglevel = len; console_loglevel = len;
/* Implicitly re-enable logging to console */
saved_console_loglevel = -1;
error = 0; error = 0;
break; break;
case 9: /* Number of chars in the log buffer */ case 9: /* Number of chars in the log buffer */
...@@ -412,7 +427,7 @@ static void __call_console_drivers(unsigned start, unsigned end) ...@@ -412,7 +427,7 @@ static void __call_console_drivers(unsigned start, unsigned end)
{ {
struct console *con; struct console *con;
for (con = console_drivers; con; con = con->next) { for_each_console(con) {
if ((con->flags & CON_ENABLED) && con->write && if ((con->flags & CON_ENABLED) && con->write &&
(cpu_online(smp_processor_id()) || (cpu_online(smp_processor_id()) ||
(con->flags & CON_ANYTIME))) (con->flags & CON_ANYTIME)))
...@@ -544,7 +559,7 @@ static int have_callable_console(void) ...@@ -544,7 +559,7 @@ static int have_callable_console(void)
{ {
struct console *con; struct console *con;
for (con = console_drivers; con; con = con->next) for_each_console(con)
if (con->flags & CON_ANYTIME) if (con->flags & CON_ANYTIME)
return 1; return 1;
...@@ -1082,7 +1097,7 @@ void console_unblank(void) ...@@ -1082,7 +1097,7 @@ void console_unblank(void)
console_locked = 1; console_locked = 1;
console_may_schedule = 0; console_may_schedule = 0;
for (c = console_drivers; c != NULL; c = c->next) for_each_console(c)
if ((c->flags & CON_ENABLED) && c->unblank) if ((c->flags & CON_ENABLED) && c->unblank)
c->unblank(); c->unblank();
release_console_sem(); release_console_sem();
...@@ -1097,7 +1112,7 @@ struct tty_driver *console_device(int *index) ...@@ -1097,7 +1112,7 @@ struct tty_driver *console_device(int *index)
struct tty_driver *driver = NULL; struct tty_driver *driver = NULL;
acquire_console_sem(); acquire_console_sem();
for (c = console_drivers; c != NULL; c = c->next) { for_each_console(c) {
if (!c->device) if (!c->device)
continue; continue;
driver = c->device(c, index); driver = c->device(c, index);
...@@ -1134,25 +1149,49 @@ EXPORT_SYMBOL(console_start); ...@@ -1134,25 +1149,49 @@ EXPORT_SYMBOL(console_start);
* to register the console printing procedure with printk() and to * to register the console printing procedure with printk() and to
* print any messages that were printed by the kernel before the * print any messages that were printed by the kernel before the
* console driver was initialized. * console driver was initialized.
*
* This can happen pretty early during the boot process (because of
* early_printk) - sometimes before setup_arch() completes - be careful
* of what kernel features are used - they may not be initialised yet.
*
* There are two types of consoles - bootconsoles (early_printk) and
* "real" consoles (everything which is not a bootconsole) which are
* handled differently.
* - Any number of bootconsoles can be registered at any time.
* - As soon as a "real" console is registered, all bootconsoles
* will be unregistered automatically.
* - Once a "real" console is registered, any attempt to register a
* bootconsoles will be rejected
*/ */
void register_console(struct console *console) void register_console(struct console *newcon)
{ {
int i; int i;
unsigned long flags; unsigned long flags;
struct console *bootconsole = NULL; struct console *bcon = NULL;
if (console_drivers) { /*
if (console->flags & CON_BOOT) * before we register a new CON_BOOT console, make sure we don't
return; * already have a valid console
if (console_drivers->flags & CON_BOOT) */
bootconsole = console_drivers; if (console_drivers && newcon->flags & CON_BOOT) {
/* find the last or real console */
for_each_console(bcon) {
if (!(bcon->flags & CON_BOOT)) {
printk(KERN_INFO "Too late to register bootconsole %s%d\n",
newcon->name, newcon->index);
return;
}
}
} }
if (preferred_console < 0 || bootconsole || !console_drivers) if (console_drivers && console_drivers->flags & CON_BOOT)
bcon = console_drivers;
if (preferred_console < 0 || bcon || !console_drivers)
preferred_console = selected_console; preferred_console = selected_console;
if (console->early_setup) if (newcon->early_setup)
console->early_setup(); newcon->early_setup();
/* /*
* See if we want to use this console driver. If we * See if we want to use this console driver. If we
...@@ -1160,13 +1199,13 @@ void register_console(struct console *console) ...@@ -1160,13 +1199,13 @@ void register_console(struct console *console)
* that registers here. * that registers here.
*/ */
if (preferred_console < 0) { if (preferred_console < 0) {
if (console->index < 0) if (newcon->index < 0)
console->index = 0; newcon->index = 0;
if (console->setup == NULL || if (newcon->setup == NULL ||
console->setup(console, NULL) == 0) { newcon->setup(newcon, NULL) == 0) {
console->flags |= CON_ENABLED; newcon->flags |= CON_ENABLED;
if (console->device) { if (newcon->device) {
console->flags |= CON_CONSDEV; newcon->flags |= CON_CONSDEV;
preferred_console = 0; preferred_console = 0;
} }
} }
...@@ -1178,64 +1217,62 @@ void register_console(struct console *console) ...@@ -1178,64 +1217,62 @@ void register_console(struct console *console)
*/ */
for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
i++) { i++) {
if (strcmp(console_cmdline[i].name, console->name) != 0) if (strcmp(console_cmdline[i].name, newcon->name) != 0)
continue; continue;
if (console->index >= 0 && if (newcon->index >= 0 &&
console->index != console_cmdline[i].index) newcon->index != console_cmdline[i].index)
continue; continue;
if (console->index < 0) if (newcon->index < 0)
console->index = console_cmdline[i].index; newcon->index = console_cmdline[i].index;
#ifdef CONFIG_A11Y_BRAILLE_CONSOLE #ifdef CONFIG_A11Y_BRAILLE_CONSOLE
if (console_cmdline[i].brl_options) { if (console_cmdline[i].brl_options) {
console->flags |= CON_BRL; newcon->flags |= CON_BRL;
braille_register_console(console, braille_register_console(newcon,
console_cmdline[i].index, console_cmdline[i].index,
console_cmdline[i].options, console_cmdline[i].options,
console_cmdline[i].brl_options); console_cmdline[i].brl_options);
return; return;
} }
#endif #endif
if (console->setup && if (newcon->setup &&
console->setup(console, console_cmdline[i].options) != 0) newcon->setup(newcon, console_cmdline[i].options) != 0)
break; break;
console->flags |= CON_ENABLED; newcon->flags |= CON_ENABLED;
console->index = console_cmdline[i].index; newcon->index = console_cmdline[i].index;
if (i == selected_console) { if (i == selected_console) {
console->flags |= CON_CONSDEV; newcon->flags |= CON_CONSDEV;
preferred_console = selected_console; preferred_console = selected_console;
} }
break; break;
} }
if (!(console->flags & CON_ENABLED)) if (!(newcon->flags & CON_ENABLED))
return; return;
if (bootconsole && (console->flags & CON_CONSDEV)) { /*
printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n", * If we have a bootconsole, and are switching to a real console,
bootconsole->name, bootconsole->index, * don't print everything out again, since when the boot console, and
console->name, console->index); * the real console are the same physical device, it's annoying to
unregister_console(bootconsole); * see the beginning boot messages twice
console->flags &= ~CON_PRINTBUFFER; */
} else { if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV))
printk(KERN_INFO "console [%s%d] enabled\n", newcon->flags &= ~CON_PRINTBUFFER;
console->name, console->index);
}
/* /*
* Put this console in the list - keep the * Put this console in the list - keep the
* preferred driver at the head of the list. * preferred driver at the head of the list.
*/ */
acquire_console_sem(); acquire_console_sem();
if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) {
console->next = console_drivers; newcon->next = console_drivers;
console_drivers = console; console_drivers = newcon;
if (console->next) if (newcon->next)
console->next->flags &= ~CON_CONSDEV; newcon->next->flags &= ~CON_CONSDEV;
} else { } else {
console->next = console_drivers->next; newcon->next = console_drivers->next;
console_drivers->next = console; console_drivers->next = newcon;
} }
if (console->flags & CON_PRINTBUFFER) { if (newcon->flags & CON_PRINTBUFFER) {
/* /*
* release_console_sem() will print out the buffered messages * release_console_sem() will print out the buffered messages
* for us. * for us.
...@@ -1245,6 +1282,28 @@ void register_console(struct console *console) ...@@ -1245,6 +1282,28 @@ void register_console(struct console *console)
spin_unlock_irqrestore(&logbuf_lock, flags); spin_unlock_irqrestore(&logbuf_lock, flags);
} }
release_console_sem(); release_console_sem();
/*
* By unregistering the bootconsoles after we enable the real console
* we get the "console xxx enabled" message on all the consoles -
* boot consoles, real consoles, etc - this is to ensure that end
* users know there might be something in the kernel's log buffer that
* went to the bootconsole (that they do not see on the real console)
*/
if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) {
/* we need to iterate through twice, to make sure we print
* everything out, before we unregister the console(s)
*/
printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n",
newcon->name, newcon->index);
for_each_console(bcon)
if (bcon->flags & CON_BOOT)
unregister_console(bcon);
} else {
printk(KERN_INFO "%sconsole [%s%d] enabled\n",
(newcon->flags & CON_BOOT) ? "boot" : "" ,
newcon->name, newcon->index);
}
} }
EXPORT_SYMBOL(register_console); EXPORT_SYMBOL(register_console);
...@@ -1287,11 +1346,13 @@ EXPORT_SYMBOL(unregister_console); ...@@ -1287,11 +1346,13 @@ EXPORT_SYMBOL(unregister_console);
static int __init disable_boot_consoles(void) static int __init disable_boot_consoles(void)
{ {
if (console_drivers != NULL) { struct console *con;
if (console_drivers->flags & CON_BOOT) {
for_each_console(con) {
if (con->flags & CON_BOOT) {
printk(KERN_INFO "turn off boot console %s%d\n", printk(KERN_INFO "turn off boot console %s%d\n",
console_drivers->name, console_drivers->index); con->name, con->index);
return unregister_console(console_drivers); unregister_console(con);
} }
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment