diff options
Diffstat (limited to 'kernel/printk.c')
| -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; |
