diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/printk.c | 175 |
1 files changed, 118 insertions, 57 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index b4d97b54c1ec..e10d193a833a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c | |||
@@ -37,6 +37,12 @@ | |||
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * for_each_console() allows you to iterate on each console | ||
41 | */ | ||
42 | #define for_each_console(con) \ | ||
43 | for (con = console_drivers; con != NULL; con = con->next) | ||
44 | |||
45 | /* | ||
40 | * Architectures can override it: | 46 | * Architectures can override it: |
41 | */ | 47 | */ |
42 | void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) | 48 | void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...) |
@@ -61,6 +67,8 @@ int console_printk[4] = { | |||
61 | DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ | 67 | DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ |
62 | }; | 68 | }; |
63 | 69 | ||
70 | static int saved_console_loglevel = -1; | ||
71 | |||
64 | /* | 72 | /* |
65 | * Low level drivers may need that to know if they can schedule in | 73 | * Low level drivers may need that to know if they can schedule in |
66 | * their unblank() callback or not. So let's export it. | 74 | * 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 | logged_chars = 0; | 380 | logged_chars = 0; |
373 | break; | 381 | break; |
374 | case 6: /* Disable logging to console */ | 382 | case 6: /* Disable logging to console */ |
383 | if (saved_console_loglevel == -1) | ||
384 | saved_console_loglevel = console_loglevel; | ||
375 | console_loglevel = minimum_console_loglevel; | 385 | console_loglevel = minimum_console_loglevel; |
376 | break; | 386 | break; |
377 | case 7: /* Enable logging to console */ | 387 | case 7: /* Enable logging to console */ |
378 | console_loglevel = default_console_loglevel; | 388 | if (saved_console_loglevel != -1) { |
389 | console_loglevel = saved_console_loglevel; | ||
390 | saved_console_loglevel = -1; | ||
391 | } | ||
379 | break; | 392 | break; |
380 | case 8: /* Set level of messages printed to console */ | 393 | case 8: /* Set level of messages printed to console */ |
381 | error = -EINVAL; | 394 | error = -EINVAL; |
@@ -384,6 +397,8 @@ int do_syslog(int type, char __user *buf, int len) | |||
384 | if (len < minimum_console_loglevel) | 397 | if (len < minimum_console_loglevel) |
385 | len = minimum_console_loglevel; | 398 | len = minimum_console_loglevel; |
386 | console_loglevel = len; | 399 | console_loglevel = len; |
400 | /* Implicitly re-enable logging to console */ | ||
401 | saved_console_loglevel = -1; | ||
387 | error = 0; | 402 | error = 0; |
388 | break; | 403 | break; |
389 | case 9: /* Number of chars in the log buffer */ | 404 | case 9: /* Number of chars in the log buffer */ |
@@ -412,7 +427,7 @@ static void __call_console_drivers(unsigned start, unsigned end) | |||
412 | { | 427 | { |
413 | struct console *con; | 428 | struct console *con; |
414 | 429 | ||
415 | for (con = console_drivers; con; con = con->next) { | 430 | for_each_console(con) { |
416 | if ((con->flags & CON_ENABLED) && con->write && | 431 | if ((con->flags & CON_ENABLED) && con->write && |
417 | (cpu_online(smp_processor_id()) || | 432 | (cpu_online(smp_processor_id()) || |
418 | (con->flags & CON_ANYTIME))) | 433 | (con->flags & CON_ANYTIME))) |
@@ -544,7 +559,7 @@ static int have_callable_console(void) | |||
544 | { | 559 | { |
545 | struct console *con; | 560 | struct console *con; |
546 | 561 | ||
547 | for (con = console_drivers; con; con = con->next) | 562 | for_each_console(con) |
548 | if (con->flags & CON_ANYTIME) | 563 | if (con->flags & CON_ANYTIME) |
549 | return 1; | 564 | return 1; |
550 | 565 | ||
@@ -1082,7 +1097,7 @@ void console_unblank(void) | |||
1082 | 1097 | ||
1083 | console_locked = 1; | 1098 | console_locked = 1; |
1084 | console_may_schedule = 0; | 1099 | console_may_schedule = 0; |
1085 | for (c = console_drivers; c != NULL; c = c->next) | 1100 | for_each_console(c) |
1086 | if ((c->flags & CON_ENABLED) && c->unblank) | 1101 | if ((c->flags & CON_ENABLED) && c->unblank) |
1087 | c->unblank(); | 1102 | c->unblank(); |
1088 | release_console_sem(); | 1103 | release_console_sem(); |
@@ -1097,7 +1112,7 @@ struct tty_driver *console_device(int *index) | |||
1097 | struct tty_driver *driver = NULL; | 1112 | struct tty_driver *driver = NULL; |
1098 | 1113 | ||
1099 | acquire_console_sem(); | 1114 | acquire_console_sem(); |
1100 | for (c = console_drivers; c != NULL; c = c->next) { | 1115 | for_each_console(c) { |
1101 | if (!c->device) | 1116 | if (!c->device) |
1102 | continue; | 1117 | continue; |
1103 | driver = c->device(c, index); | 1118 | driver = c->device(c, index); |
@@ -1134,25 +1149,49 @@ EXPORT_SYMBOL(console_start); | |||
1134 | * to register the console printing procedure with printk() and to | 1149 | * to register the console printing procedure with printk() and to |
1135 | * print any messages that were printed by the kernel before the | 1150 | * print any messages that were printed by the kernel before the |
1136 | * console driver was initialized. | 1151 | * console driver was initialized. |
1152 | * | ||
1153 | * This can happen pretty early during the boot process (because of | ||
1154 | * early_printk) - sometimes before setup_arch() completes - be careful | ||
1155 | * of what kernel features are used - they may not be initialised yet. | ||
1156 | * | ||
1157 | * There are two types of consoles - bootconsoles (early_printk) and | ||
1158 | * "real" consoles (everything which is not a bootconsole) which are | ||
1159 | * handled differently. | ||
1160 | * - Any number of bootconsoles can be registered at any time. | ||
1161 | * - As soon as a "real" console is registered, all bootconsoles | ||
1162 | * will be unregistered automatically. | ||
1163 | * - Once a "real" console is registered, any attempt to register a | ||
1164 | * bootconsoles will be rejected | ||
1137 | */ | 1165 | */ |
1138 | void register_console(struct console *console) | 1166 | void register_console(struct console *newcon) |
1139 | { | 1167 | { |
1140 | int i; | 1168 | int i; |
1141 | unsigned long flags; | 1169 | unsigned long flags; |
1142 | struct console *bootconsole = NULL; | 1170 | struct console *bcon = NULL; |
1143 | 1171 | ||
1144 | if (console_drivers) { | 1172 | /* |
1145 | if (console->flags & CON_BOOT) | 1173 | * before we register a new CON_BOOT console, make sure we don't |
1146 | return; | 1174 | * already have a valid console |
1147 | if (console_drivers->flags & CON_BOOT) | 1175 | */ |
1148 | bootconsole = console_drivers; | 1176 | if (console_drivers && newcon->flags & CON_BOOT) { |
1177 | /* find the last or real console */ | ||
1178 | for_each_console(bcon) { | ||
1179 | if (!(bcon->flags & CON_BOOT)) { | ||
1180 | printk(KERN_INFO "Too late to register bootconsole %s%d\n", | ||
1181 | newcon->name, newcon->index); | ||
1182 | return; | ||
1183 | } | ||
1184 | } | ||
1149 | } | 1185 | } |
1150 | 1186 | ||
1151 | if (preferred_console < 0 || bootconsole || !console_drivers) | 1187 | if (console_drivers && console_drivers->flags & CON_BOOT) |
1188 | bcon = console_drivers; | ||
1189 | |||
1190 | if (preferred_console < 0 || bcon || !console_drivers) | ||
1152 | preferred_console = selected_console; | 1191 | preferred_console = selected_console; |
1153 | 1192 | ||
1154 | if (console->early_setup) | 1193 | if (newcon->early_setup) |
1155 | console->early_setup(); | 1194 | newcon->early_setup(); |
1156 | 1195 | ||
1157 | /* | 1196 | /* |
1158 | * See if we want to use this console driver. If we | 1197 | * See if we want to use this console driver. If we |
@@ -1160,13 +1199,13 @@ void register_console(struct console *console) | |||
1160 | * that registers here. | 1199 | * that registers here. |
1161 | */ | 1200 | */ |
1162 | if (preferred_console < 0) { | 1201 | if (preferred_console < 0) { |
1163 | if (console->index < 0) | 1202 | if (newcon->index < 0) |
1164 | console->index = 0; | 1203 | newcon->index = 0; |
1165 | if (console->setup == NULL || | 1204 | if (newcon->setup == NULL || |
1166 | console->setup(console, NULL) == 0) { | 1205 | newcon->setup(newcon, NULL) == 0) { |
1167 | console->flags |= CON_ENABLED; | 1206 | newcon->flags |= CON_ENABLED; |
1168 | if (console->device) { | 1207 | if (newcon->device) { |
1169 | console->flags |= CON_CONSDEV; | 1208 | newcon->flags |= CON_CONSDEV; |
1170 | preferred_console = 0; | 1209 | preferred_console = 0; |
1171 | } | 1210 | } |
1172 | } | 1211 | } |
@@ -1178,64 +1217,62 @@ void register_console(struct console *console) | |||
1178 | */ | 1217 | */ |
1179 | for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; | 1218 | for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; |
1180 | i++) { | 1219 | i++) { |
1181 | if (strcmp(console_cmdline[i].name, console->name) != 0) | 1220 | if (strcmp(console_cmdline[i].name, newcon->name) != 0) |
1182 | continue; | 1221 | continue; |
1183 | if (console->index >= 0 && | 1222 | if (newcon->index >= 0 && |
1184 | console->index != console_cmdline[i].index) | 1223 | newcon->index != console_cmdline[i].index) |
1185 | continue; | 1224 | continue; |
1186 | if (console->index < 0) | 1225 | if (newcon->index < 0) |
1187 | console->index = console_cmdline[i].index; | 1226 | newcon->index = console_cmdline[i].index; |
1188 | #ifdef CONFIG_A11Y_BRAILLE_CONSOLE | 1227 | #ifdef CONFIG_A11Y_BRAILLE_CONSOLE |
1189 | if (console_cmdline[i].brl_options) { | 1228 | if (console_cmdline[i].brl_options) { |
1190 | console->flags |= CON_BRL; | 1229 | newcon->flags |= CON_BRL; |
1191 | braille_register_console(console, | 1230 | braille_register_console(newcon, |
1192 | console_cmdline[i].index, | 1231 | console_cmdline[i].index, |
1193 | console_cmdline[i].options, | 1232 | console_cmdline[i].options, |
1194 | console_cmdline[i].brl_options); | 1233 | console_cmdline[i].brl_options); |
1195 | return; | 1234 | return; |
1196 | } | 1235 | } |
1197 | #endif | 1236 | #endif |
1198 | if (console->setup && | 1237 | if (newcon->setup && |
1199 | console->setup(console, console_cmdline[i].options) != 0) | 1238 | newcon->setup(newcon, console_cmdline[i].options) != 0) |
1200 | break; | 1239 | break; |
1201 | console->flags |= CON_ENABLED; | 1240 | newcon->flags |= CON_ENABLED; |
1202 | console->index = console_cmdline[i].index; | 1241 | newcon->index = console_cmdline[i].index; |
1203 | if (i == selected_console) { | 1242 | if (i == selected_console) { |
1204 | console->flags |= CON_CONSDEV; | 1243 | newcon->flags |= CON_CONSDEV; |
1205 | preferred_console = selected_console; | 1244 | preferred_console = selected_console; |
1206 | } | 1245 | } |
1207 | break; | 1246 | break; |
1208 | } | 1247 | } |
1209 | 1248 | ||
1210 | if (!(console->flags & CON_ENABLED)) | 1249 | if (!(newcon->flags & CON_ENABLED)) |
1211 | return; | 1250 | return; |
1212 | 1251 | ||
1213 | if (bootconsole && (console->flags & CON_CONSDEV)) { | 1252 | /* |
1214 | printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n", | 1253 | * If we have a bootconsole, and are switching to a real console, |
1215 | bootconsole->name, bootconsole->index, | 1254 | * don't print everything out again, since when the boot console, and |
1216 | console->name, console->index); | 1255 | * the real console are the same physical device, it's annoying to |
1217 | unregister_console(bootconsole); | 1256 | * see the beginning boot messages twice |
1218 | console->flags &= ~CON_PRINTBUFFER; | 1257 | */ |
1219 | } else { | 1258 | if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) |
1220 | printk(KERN_INFO "console [%s%d] enabled\n", | 1259 | newcon->flags &= ~CON_PRINTBUFFER; |
1221 | console->name, console->index); | ||
1222 | } | ||
1223 | 1260 | ||
1224 | /* | 1261 | /* |
1225 | * Put this console in the list - keep the | 1262 | * Put this console in the list - keep the |
1226 | * preferred driver at the head of the list. | 1263 | * preferred driver at the head of the list. |
1227 | */ | 1264 | */ |
1228 | acquire_console_sem(); | 1265 | acquire_console_sem(); |
1229 | if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { | 1266 | if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { |
1230 | console->next = console_drivers; | 1267 | newcon->next = console_drivers; |
1231 | console_drivers = console; | 1268 | console_drivers = newcon; |
1232 | if (console->next) | 1269 | if (newcon->next) |
1233 | console->next->flags &= ~CON_CONSDEV; | 1270 | newcon->next->flags &= ~CON_CONSDEV; |
1234 | } else { | 1271 | } else { |
1235 | console->next = console_drivers->next; | 1272 | newcon->next = console_drivers->next; |
1236 | console_drivers->next = console; | 1273 | console_drivers->next = newcon; |
1237 | } | 1274 | } |
1238 | if (console->flags & CON_PRINTBUFFER) { | 1275 | if (newcon->flags & CON_PRINTBUFFER) { |
1239 | /* | 1276 | /* |
1240 | * release_console_sem() will print out the buffered messages | 1277 | * release_console_sem() will print out the buffered messages |
1241 | * for us. | 1278 | * for us. |
@@ -1245,6 +1282,28 @@ void register_console(struct console *console) | |||
1245 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1282 | spin_unlock_irqrestore(&logbuf_lock, flags); |
1246 | } | 1283 | } |
1247 | release_console_sem(); | 1284 | release_console_sem(); |
1285 | |||
1286 | /* | ||
1287 | * By unregistering the bootconsoles after we enable the real console | ||
1288 | * we get the "console xxx enabled" message on all the consoles - | ||
1289 | * boot consoles, real consoles, etc - this is to ensure that end | ||
1290 | * users know there might be something in the kernel's log buffer that | ||
1291 | * went to the bootconsole (that they do not see on the real console) | ||
1292 | */ | ||
1293 | if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { | ||
1294 | /* we need to iterate through twice, to make sure we print | ||
1295 | * everything out, before we unregister the console(s) | ||
1296 | */ | ||
1297 | printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n", | ||
1298 | newcon->name, newcon->index); | ||
1299 | for_each_console(bcon) | ||
1300 | if (bcon->flags & CON_BOOT) | ||
1301 | unregister_console(bcon); | ||
1302 | } else { | ||
1303 | printk(KERN_INFO "%sconsole [%s%d] enabled\n", | ||
1304 | (newcon->flags & CON_BOOT) ? "boot" : "" , | ||
1305 | newcon->name, newcon->index); | ||
1306 | } | ||
1248 | } | 1307 | } |
1249 | EXPORT_SYMBOL(register_console); | 1308 | EXPORT_SYMBOL(register_console); |
1250 | 1309 | ||
@@ -1287,11 +1346,13 @@ EXPORT_SYMBOL(unregister_console); | |||
1287 | 1346 | ||
1288 | static int __init disable_boot_consoles(void) | 1347 | static int __init disable_boot_consoles(void) |
1289 | { | 1348 | { |
1290 | if (console_drivers != NULL) { | 1349 | struct console *con; |
1291 | if (console_drivers->flags & CON_BOOT) { | 1350 | |
1351 | for_each_console(con) { | ||
1352 | if (con->flags & CON_BOOT) { | ||
1292 | printk(KERN_INFO "turn off boot console %s%d\n", | 1353 | printk(KERN_INFO "turn off boot console %s%d\n", |
1293 | console_drivers->name, console_drivers->index); | 1354 | con->name, con->index); |
1294 | return unregister_console(console_drivers); | 1355 | unregister_console(con); |
1295 | } | 1356 | } |
1296 | } | 1357 | } |
1297 | return 0; | 1358 | return 0; |