diff options
Diffstat (limited to 'kernel/printk.c')
| -rw-r--r-- | kernel/printk.c | 208 |
1 files changed, 138 insertions, 70 deletions
diff --git a/kernel/printk.c b/kernel/printk.c index b4d97b54c1ec..f38b07f78a4e 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. |
| @@ -198,12 +206,11 @@ __setup("log_buf_len=", log_buf_len_setup); | |||
| 198 | #ifdef CONFIG_BOOT_PRINTK_DELAY | 206 | #ifdef CONFIG_BOOT_PRINTK_DELAY |
| 199 | 207 | ||
| 200 | static unsigned int boot_delay; /* msecs delay after each printk during bootup */ | 208 | static unsigned int boot_delay; /* msecs delay after each printk during bootup */ |
| 201 | static unsigned long long printk_delay_msec; /* per msec, based on boot_delay */ | 209 | static unsigned long long loops_per_msec; /* based on boot_delay */ |
| 202 | 210 | ||
| 203 | static int __init boot_delay_setup(char *str) | 211 | static int __init boot_delay_setup(char *str) |
| 204 | { | 212 | { |
| 205 | unsigned long lpj; | 213 | unsigned long lpj; |
| 206 | unsigned long long loops_per_msec; | ||
| 207 | 214 | ||
| 208 | lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */ | 215 | lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */ |
| 209 | loops_per_msec = (unsigned long long)lpj / 1000 * HZ; | 216 | loops_per_msec = (unsigned long long)lpj / 1000 * HZ; |
| @@ -212,10 +219,9 @@ static int __init boot_delay_setup(char *str) | |||
| 212 | if (boot_delay > 10 * 1000) | 219 | if (boot_delay > 10 * 1000) |
| 213 | boot_delay = 0; | 220 | boot_delay = 0; |
| 214 | 221 | ||
| 215 | printk_delay_msec = loops_per_msec; | 222 | pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, " |
| 216 | printk(KERN_DEBUG "boot_delay: %u, preset_lpj: %ld, lpj: %lu, " | 223 | "HZ: %d, loops_per_msec: %llu\n", |
| 217 | "HZ: %d, printk_delay_msec: %llu\n", | 224 | boot_delay, preset_lpj, lpj, HZ, loops_per_msec); |
| 218 | boot_delay, preset_lpj, lpj, HZ, printk_delay_msec); | ||
| 219 | return 1; | 225 | return 1; |
| 220 | } | 226 | } |
| 221 | __setup("boot_delay=", boot_delay_setup); | 227 | __setup("boot_delay=", boot_delay_setup); |
| @@ -228,7 +234,7 @@ static void boot_delay_msec(void) | |||
| 228 | if (boot_delay == 0 || system_state != SYSTEM_BOOTING) | 234 | if (boot_delay == 0 || system_state != SYSTEM_BOOTING) |
| 229 | return; | 235 | return; |
| 230 | 236 | ||
| 231 | k = (unsigned long long)printk_delay_msec * boot_delay; | 237 | k = (unsigned long long)loops_per_msec * boot_delay; |
| 232 | 238 | ||
| 233 | timeout = jiffies + msecs_to_jiffies(boot_delay); | 239 | timeout = jiffies + msecs_to_jiffies(boot_delay); |
| 234 | while (k) { | 240 | while (k) { |
| @@ -372,10 +378,15 @@ int do_syslog(int type, char __user *buf, int len) | |||
| 372 | logged_chars = 0; | 378 | logged_chars = 0; |
| 373 | break; | 379 | break; |
| 374 | case 6: /* Disable logging to console */ | 380 | case 6: /* Disable logging to console */ |
| 381 | if (saved_console_loglevel == -1) | ||
| 382 | saved_console_loglevel = console_loglevel; | ||
| 375 | console_loglevel = minimum_console_loglevel; | 383 | console_loglevel = minimum_console_loglevel; |
| 376 | break; | 384 | break; |
| 377 | case 7: /* Enable logging to console */ | 385 | case 7: /* Enable logging to console */ |
| 378 | console_loglevel = default_console_loglevel; | 386 | if (saved_console_loglevel != -1) { |
| 387 | console_loglevel = saved_console_loglevel; | ||
| 388 | saved_console_loglevel = -1; | ||
| 389 | } | ||
| 379 | break; | 390 | break; |
| 380 | case 8: /* Set level of messages printed to console */ | 391 | case 8: /* Set level of messages printed to console */ |
| 381 | error = -EINVAL; | 392 | error = -EINVAL; |
| @@ -384,6 +395,8 @@ int do_syslog(int type, char __user *buf, int len) | |||
| 384 | if (len < minimum_console_loglevel) | 395 | if (len < minimum_console_loglevel) |
| 385 | len = minimum_console_loglevel; | 396 | len = minimum_console_loglevel; |
| 386 | console_loglevel = len; | 397 | console_loglevel = len; |
| 398 | /* Implicitly re-enable logging to console */ | ||
| 399 | saved_console_loglevel = -1; | ||
| 387 | error = 0; | 400 | error = 0; |
| 388 | break; | 401 | break; |
| 389 | case 9: /* Number of chars in the log buffer */ | 402 | case 9: /* Number of chars in the log buffer */ |
| @@ -412,7 +425,7 @@ static void __call_console_drivers(unsigned start, unsigned end) | |||
| 412 | { | 425 | { |
| 413 | struct console *con; | 426 | struct console *con; |
| 414 | 427 | ||
| 415 | for (con = console_drivers; con; con = con->next) { | 428 | for_each_console(con) { |
| 416 | if ((con->flags & CON_ENABLED) && con->write && | 429 | if ((con->flags & CON_ENABLED) && con->write && |
| 417 | (cpu_online(smp_processor_id()) || | 430 | (cpu_online(smp_processor_id()) || |
| 418 | (con->flags & CON_ANYTIME))) | 431 | (con->flags & CON_ANYTIME))) |
| @@ -544,7 +557,7 @@ static int have_callable_console(void) | |||
| 544 | { | 557 | { |
| 545 | struct console *con; | 558 | struct console *con; |
| 546 | 559 | ||
| 547 | for (con = console_drivers; con; con = con->next) | 560 | for_each_console(con) |
| 548 | if (con->flags & CON_ANYTIME) | 561 | if (con->flags & CON_ANYTIME) |
| 549 | return 1; | 562 | return 1; |
| 550 | 563 | ||
| @@ -640,6 +653,20 @@ static int recursion_bug; | |||
| 640 | static int new_text_line = 1; | 653 | static int new_text_line = 1; |
| 641 | static char printk_buf[1024]; | 654 | static char printk_buf[1024]; |
| 642 | 655 | ||
| 656 | int printk_delay_msec __read_mostly; | ||
| 657 | |||
| 658 | static inline void printk_delay(void) | ||
| 659 | { | ||
| 660 | if (unlikely(printk_delay_msec)) { | ||
| 661 | int m = printk_delay_msec; | ||
| 662 | |||
| 663 | while (m--) { | ||
| 664 | mdelay(1); | ||
| 665 | touch_nmi_watchdog(); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } | ||
| 669 | |||
| 643 | asmlinkage int vprintk(const char *fmt, va_list args) | 670 | asmlinkage int vprintk(const char *fmt, va_list args) |
| 644 | { | 671 | { |
| 645 | int printed_len = 0; | 672 | int printed_len = 0; |
| @@ -649,6 +676,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) | |||
| 649 | char *p; | 676 | char *p; |
| 650 | 677 | ||
| 651 | boot_delay_msec(); | 678 | boot_delay_msec(); |
| 679 | printk_delay(); | ||
| 652 | 680 | ||
| 653 | preempt_disable(); | 681 | preempt_disable(); |
| 654 | /* This stops the holder of console_sem just where we want him */ | 682 | /* This stops the holder of console_sem just where we want him */ |
| @@ -1060,12 +1088,6 @@ void __sched console_conditional_schedule(void) | |||
| 1060 | } | 1088 | } |
| 1061 | EXPORT_SYMBOL(console_conditional_schedule); | 1089 | EXPORT_SYMBOL(console_conditional_schedule); |
| 1062 | 1090 | ||
| 1063 | void console_print(const char *s) | ||
| 1064 | { | ||
| 1065 | printk(KERN_EMERG "%s", s); | ||
| 1066 | } | ||
| 1067 | EXPORT_SYMBOL(console_print); | ||
| 1068 | |||
| 1069 | void console_unblank(void) | 1091 | void console_unblank(void) |
| 1070 | { | 1092 | { |
| 1071 | struct console *c; | 1093 | struct console *c; |
| @@ -1082,7 +1104,7 @@ void console_unblank(void) | |||
| 1082 | 1104 | ||
| 1083 | console_locked = 1; | 1105 | console_locked = 1; |
| 1084 | console_may_schedule = 0; | 1106 | console_may_schedule = 0; |
| 1085 | for (c = console_drivers; c != NULL; c = c->next) | 1107 | for_each_console(c) |
| 1086 | if ((c->flags & CON_ENABLED) && c->unblank) | 1108 | if ((c->flags & CON_ENABLED) && c->unblank) |
| 1087 | c->unblank(); | 1109 | c->unblank(); |
| 1088 | release_console_sem(); | 1110 | release_console_sem(); |
| @@ -1097,7 +1119,7 @@ struct tty_driver *console_device(int *index) | |||
| 1097 | struct tty_driver *driver = NULL; | 1119 | struct tty_driver *driver = NULL; |
| 1098 | 1120 | ||
| 1099 | acquire_console_sem(); | 1121 | acquire_console_sem(); |
| 1100 | for (c = console_drivers; c != NULL; c = c->next) { | 1122 | for_each_console(c) { |
| 1101 | if (!c->device) | 1123 | if (!c->device) |
| 1102 | continue; | 1124 | continue; |
| 1103 | driver = c->device(c, index); | 1125 | driver = c->device(c, index); |
| @@ -1134,25 +1156,49 @@ EXPORT_SYMBOL(console_start); | |||
| 1134 | * to register the console printing procedure with printk() and to | 1156 | * to register the console printing procedure with printk() and to |
| 1135 | * print any messages that were printed by the kernel before the | 1157 | * print any messages that were printed by the kernel before the |
| 1136 | * console driver was initialized. | 1158 | * console driver was initialized. |
| 1159 | * | ||
| 1160 | * This can happen pretty early during the boot process (because of | ||
| 1161 | * early_printk) - sometimes before setup_arch() completes - be careful | ||
| 1162 | * of what kernel features are used - they may not be initialised yet. | ||
| 1163 | * | ||
| 1164 | * There are two types of consoles - bootconsoles (early_printk) and | ||
| 1165 | * "real" consoles (everything which is not a bootconsole) which are | ||
| 1166 | * handled differently. | ||
| 1167 | * - Any number of bootconsoles can be registered at any time. | ||
| 1168 | * - As soon as a "real" console is registered, all bootconsoles | ||
| 1169 | * will be unregistered automatically. | ||
| 1170 | * - Once a "real" console is registered, any attempt to register a | ||
| 1171 | * bootconsoles will be rejected | ||
| 1137 | */ | 1172 | */ |
| 1138 | void register_console(struct console *console) | 1173 | void register_console(struct console *newcon) |
| 1139 | { | 1174 | { |
| 1140 | int i; | 1175 | int i; |
| 1141 | unsigned long flags; | 1176 | unsigned long flags; |
| 1142 | struct console *bootconsole = NULL; | 1177 | struct console *bcon = NULL; |
| 1143 | 1178 | ||
| 1144 | if (console_drivers) { | 1179 | /* |
| 1145 | if (console->flags & CON_BOOT) | 1180 | * before we register a new CON_BOOT console, make sure we don't |
| 1146 | return; | 1181 | * already have a valid console |
| 1147 | if (console_drivers->flags & CON_BOOT) | 1182 | */ |
| 1148 | bootconsole = console_drivers; | 1183 | if (console_drivers && newcon->flags & CON_BOOT) { |
| 1184 | /* find the last or real console */ | ||
| 1185 | for_each_console(bcon) { | ||
| 1186 | if (!(bcon->flags & CON_BOOT)) { | ||
| 1187 | printk(KERN_INFO "Too late to register bootconsole %s%d\n", | ||
| 1188 | newcon->name, newcon->index); | ||
| 1189 | return; | ||
| 1190 | } | ||
| 1191 | } | ||
| 1149 | } | 1192 | } |
| 1150 | 1193 | ||
| 1151 | if (preferred_console < 0 || bootconsole || !console_drivers) | 1194 | if (console_drivers && console_drivers->flags & CON_BOOT) |
| 1195 | bcon = console_drivers; | ||
| 1196 | |||
| 1197 | if (preferred_console < 0 || bcon || !console_drivers) | ||
| 1152 | preferred_console = selected_console; | 1198 | preferred_console = selected_console; |
| 1153 | 1199 | ||
| 1154 | if (console->early_setup) | 1200 | if (newcon->early_setup) |
| 1155 | console->early_setup(); | 1201 | newcon->early_setup(); |
| 1156 | 1202 | ||
| 1157 | /* | 1203 | /* |
| 1158 | * See if we want to use this console driver. If we | 1204 | * See if we want to use this console driver. If we |
| @@ -1160,13 +1206,13 @@ void register_console(struct console *console) | |||
| 1160 | * that registers here. | 1206 | * that registers here. |
| 1161 | */ | 1207 | */ |
| 1162 | if (preferred_console < 0) { | 1208 | if (preferred_console < 0) { |
| 1163 | if (console->index < 0) | 1209 | if (newcon->index < 0) |
| 1164 | console->index = 0; | 1210 | newcon->index = 0; |
| 1165 | if (console->setup == NULL || | 1211 | if (newcon->setup == NULL || |
| 1166 | console->setup(console, NULL) == 0) { | 1212 | newcon->setup(newcon, NULL) == 0) { |
| 1167 | console->flags |= CON_ENABLED; | 1213 | newcon->flags |= CON_ENABLED; |
| 1168 | if (console->device) { | 1214 | if (newcon->device) { |
| 1169 | console->flags |= CON_CONSDEV; | 1215 | newcon->flags |= CON_CONSDEV; |
| 1170 | preferred_console = 0; | 1216 | preferred_console = 0; |
| 1171 | } | 1217 | } |
| 1172 | } | 1218 | } |
| @@ -1178,64 +1224,62 @@ void register_console(struct console *console) | |||
| 1178 | */ | 1224 | */ |
| 1179 | for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; | 1225 | for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; |
| 1180 | i++) { | 1226 | i++) { |
| 1181 | if (strcmp(console_cmdline[i].name, console->name) != 0) | 1227 | if (strcmp(console_cmdline[i].name, newcon->name) != 0) |
| 1182 | continue; | 1228 | continue; |
| 1183 | if (console->index >= 0 && | 1229 | if (newcon->index >= 0 && |
| 1184 | console->index != console_cmdline[i].index) | 1230 | newcon->index != console_cmdline[i].index) |
| 1185 | continue; | 1231 | continue; |
| 1186 | if (console->index < 0) | 1232 | if (newcon->index < 0) |
| 1187 | console->index = console_cmdline[i].index; | 1233 | newcon->index = console_cmdline[i].index; |
| 1188 | #ifdef CONFIG_A11Y_BRAILLE_CONSOLE | 1234 | #ifdef CONFIG_A11Y_BRAILLE_CONSOLE |
| 1189 | if (console_cmdline[i].brl_options) { | 1235 | if (console_cmdline[i].brl_options) { |
| 1190 | console->flags |= CON_BRL; | 1236 | newcon->flags |= CON_BRL; |
| 1191 | braille_register_console(console, | 1237 | braille_register_console(newcon, |
| 1192 | console_cmdline[i].index, | 1238 | console_cmdline[i].index, |
| 1193 | console_cmdline[i].options, | 1239 | console_cmdline[i].options, |
| 1194 | console_cmdline[i].brl_options); | 1240 | console_cmdline[i].brl_options); |
| 1195 | return; | 1241 | return; |
| 1196 | } | 1242 | } |
| 1197 | #endif | 1243 | #endif |
| 1198 | if (console->setup && | 1244 | if (newcon->setup && |
| 1199 | console->setup(console, console_cmdline[i].options) != 0) | 1245 | newcon->setup(newcon, console_cmdline[i].options) != 0) |
| 1200 | break; | 1246 | break; |
| 1201 | console->flags |= CON_ENABLED; | 1247 | newcon->flags |= CON_ENABLED; |
| 1202 | console->index = console_cmdline[i].index; | 1248 | newcon->index = console_cmdline[i].index; |
| 1203 | if (i == selected_console) { | 1249 | if (i == selected_console) { |
| 1204 | console->flags |= CON_CONSDEV; | 1250 | newcon->flags |= CON_CONSDEV; |
| 1205 | preferred_console = selected_console; | 1251 | preferred_console = selected_console; |
| 1206 | } | 1252 | } |
| 1207 | break; | 1253 | break; |
| 1208 | } | 1254 | } |
| 1209 | 1255 | ||
| 1210 | if (!(console->flags & CON_ENABLED)) | 1256 | if (!(newcon->flags & CON_ENABLED)) |
| 1211 | return; | 1257 | return; |
| 1212 | 1258 | ||
| 1213 | if (bootconsole && (console->flags & CON_CONSDEV)) { | 1259 | /* |
| 1214 | printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n", | 1260 | * If we have a bootconsole, and are switching to a real console, |
| 1215 | bootconsole->name, bootconsole->index, | 1261 | * don't print everything out again, since when the boot console, and |
| 1216 | console->name, console->index); | 1262 | * the real console are the same physical device, it's annoying to |
| 1217 | unregister_console(bootconsole); | 1263 | * see the beginning boot messages twice |
| 1218 | console->flags &= ~CON_PRINTBUFFER; | 1264 | */ |
| 1219 | } else { | 1265 | if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) |
| 1220 | printk(KERN_INFO "console [%s%d] enabled\n", | 1266 | newcon->flags &= ~CON_PRINTBUFFER; |
| 1221 | console->name, console->index); | ||
| 1222 | } | ||
| 1223 | 1267 | ||
| 1224 | /* | 1268 | /* |
| 1225 | * Put this console in the list - keep the | 1269 | * Put this console in the list - keep the |
| 1226 | * preferred driver at the head of the list. | 1270 | * preferred driver at the head of the list. |
| 1227 | */ | 1271 | */ |
| 1228 | acquire_console_sem(); | 1272 | acquire_console_sem(); |
| 1229 | if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { | 1273 | if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { |
| 1230 | console->next = console_drivers; | 1274 | newcon->next = console_drivers; |
| 1231 | console_drivers = console; | 1275 | console_drivers = newcon; |
| 1232 | if (console->next) | 1276 | if (newcon->next) |
| 1233 | console->next->flags &= ~CON_CONSDEV; | 1277 | newcon->next->flags &= ~CON_CONSDEV; |
| 1234 | } else { | 1278 | } else { |
| 1235 | console->next = console_drivers->next; | 1279 | newcon->next = console_drivers->next; |
| 1236 | console_drivers->next = console; | 1280 | console_drivers->next = newcon; |
| 1237 | } | 1281 | } |
| 1238 | if (console->flags & CON_PRINTBUFFER) { | 1282 | if (newcon->flags & CON_PRINTBUFFER) { |
| 1239 | /* | 1283 | /* |
| 1240 | * release_console_sem() will print out the buffered messages | 1284 | * release_console_sem() will print out the buffered messages |
| 1241 | * for us. | 1285 | * for us. |
| @@ -1245,6 +1289,28 @@ void register_console(struct console *console) | |||
| 1245 | spin_unlock_irqrestore(&logbuf_lock, flags); | 1289 | spin_unlock_irqrestore(&logbuf_lock, flags); |
| 1246 | } | 1290 | } |
| 1247 | release_console_sem(); | 1291 | release_console_sem(); |
| 1292 | |||
| 1293 | /* | ||
| 1294 | * By unregistering the bootconsoles after we enable the real console | ||
| 1295 | * we get the "console xxx enabled" message on all the consoles - | ||
| 1296 | * boot consoles, real consoles, etc - this is to ensure that end | ||
| 1297 | * users know there might be something in the kernel's log buffer that | ||
| 1298 | * went to the bootconsole (that they do not see on the real console) | ||
| 1299 | */ | ||
| 1300 | if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) { | ||
| 1301 | /* we need to iterate through twice, to make sure we print | ||
| 1302 | * everything out, before we unregister the console(s) | ||
| 1303 | */ | ||
| 1304 | printk(KERN_INFO "console [%s%d] enabled, bootconsole disabled\n", | ||
| 1305 | newcon->name, newcon->index); | ||
| 1306 | for_each_console(bcon) | ||
| 1307 | if (bcon->flags & CON_BOOT) | ||
| 1308 | unregister_console(bcon); | ||
| 1309 | } else { | ||
| 1310 | printk(KERN_INFO "%sconsole [%s%d] enabled\n", | ||
| 1311 | (newcon->flags & CON_BOOT) ? "boot" : "" , | ||
| 1312 | newcon->name, newcon->index); | ||
| 1313 | } | ||
| 1248 | } | 1314 | } |
| 1249 | EXPORT_SYMBOL(register_console); | 1315 | EXPORT_SYMBOL(register_console); |
| 1250 | 1316 | ||
| @@ -1287,11 +1353,13 @@ EXPORT_SYMBOL(unregister_console); | |||
| 1287 | 1353 | ||
| 1288 | static int __init disable_boot_consoles(void) | 1354 | static int __init disable_boot_consoles(void) |
| 1289 | { | 1355 | { |
| 1290 | if (console_drivers != NULL) { | 1356 | struct console *con; |
| 1291 | if (console_drivers->flags & CON_BOOT) { | 1357 | |
| 1358 | for_each_console(con) { | ||
| 1359 | if (con->flags & CON_BOOT) { | ||
| 1292 | printk(KERN_INFO "turn off boot console %s%d\n", | 1360 | printk(KERN_INFO "turn off boot console %s%d\n", |
| 1293 | console_drivers->name, console_drivers->index); | 1361 | con->name, con->index); |
| 1294 | return unregister_console(console_drivers); | 1362 | unregister_console(con); |
| 1295 | } | 1363 | } |
| 1296 | } | 1364 | } |
| 1297 | return 0; | 1365 | return 0; |
