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)
This commit is contained in:
175
kernel/printk.c
175
kernel/printk.c
@@ -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] = {
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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);
|
|||||||
* 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)
|
|||||||
* 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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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);
|
|||||||
|
|
||||||
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;
|
||||||
|
Reference in New Issue
Block a user