📄 printk.c
字号:
return 0;}early_param("ignore_loglevel", ignore_loglevel_setup);/* * Write out chars from start to end - 1 inclusive */static void _call_console_drivers(unsigned start, unsigned end, int msg_log_level){ if ((msg_log_level < console_loglevel || ignore_loglevel) && console_drivers && start != end) { if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) { /* wrapped write */ __call_console_drivers(start & LOG_BUF_MASK, log_buf_len); __call_console_drivers(0, end & LOG_BUF_MASK); } else { __call_console_drivers(start, end); } }}/* * Call the console drivers, asking them to write out * log_buf[start] to log_buf[end - 1]. * The console_sem must be held. */static void call_console_drivers(unsigned start, unsigned end){ unsigned cur_index, start_print; static int msg_level = -1; BUG_ON(((int)(start - end)) > 0); cur_index = start; start_print = start; while (cur_index != end) { if (msg_level < 0 && ((end - cur_index) > 2) && LOG_BUF(cur_index + 0) == '<' && LOG_BUF(cur_index + 1) >= '0' && LOG_BUF(cur_index + 1) <= '7' && LOG_BUF(cur_index + 2) == '>') { msg_level = LOG_BUF(cur_index + 1) - '0'; cur_index += 3; start_print = cur_index; } while (cur_index != end) { char c = LOG_BUF(cur_index); cur_index++; if (c == '\n') { if (msg_level < 0) { /* * printk() has already given us loglevel tags in * the buffer. This code is here in case the * log buffer has wrapped right round and scribbled * on those tags */ msg_level = default_message_loglevel; } _call_console_drivers(start_print, cur_index, msg_level); msg_level = -1; start_print = cur_index; break; } } } _call_console_drivers(start_print, end, msg_level);}static void emit_log_char(char c){ LOG_BUF(log_end) = c; log_end++; if (log_end - log_start > log_buf_len) log_start = log_end - log_buf_len; if (log_end - con_start > log_buf_len) con_start = log_end - log_buf_len; if (logged_chars < log_buf_len) logged_chars++;}/* * Zap console related locks when oopsing. Only zap at most once * every 10 seconds, to leave time for slow consoles to print a * full oops. */static void zap_locks(void){ static unsigned long oops_timestamp; if (time_after_eq(jiffies, oops_timestamp) && !time_after(jiffies, oops_timestamp + 30 * HZ)) return; oops_timestamp = jiffies; /* If a crash is occurring, make sure we can't deadlock */ spin_lock_init(&logbuf_lock); /* And make sure that we print immediately */ init_MUTEX(&console_sem);}#if defined(CONFIG_PRINTK_TIME)static int printk_time = 1;#elsestatic int printk_time = 0;#endifmodule_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);/* Check if we have any console registered that can be called early in boot. */static int have_callable_console(void){ struct console *con; for (con = console_drivers; con; con = con->next) if (con->flags & CON_ANYTIME) return 1; return 0;}/** * printk - print a kernel message * @fmt: format string * * This is printk(). It can be called from any context. We want it to work. * Be aware of the fact that if oops_in_progress is not set, we might try to * wake klogd up which could deadlock on runqueue lock if printk() is called * from scheduler code. * * We try to grab the console_sem. If we succeed, it's easy - we log the output and * call the console drivers. If we fail to get the semaphore we place the output * into the log buffer and return. The current holder of the console_sem will * notice the new output in release_console_sem() and will send it to the * consoles before releasing the semaphore. * * One effect of this deferred printing is that code which calls printk() and * then changes console_loglevel may break. This is because console_loglevel * is inspected when the actual printing occurs. * * See also: * printf(3) */asmlinkage int printk(const char *fmt, ...){ va_list args; int r; va_start(args, fmt); r = vprintk(fmt, args); va_end(args); return r;}/* cpu currently holding logbuf_lock */static volatile unsigned int printk_cpu = UINT_MAX;/* * Can we actually use the console at this time on this cpu? * * Console drivers may assume that per-cpu resources have * been allocated. So unless they're explicitly marked as * being able to cope (CON_ANYTIME) don't call them until * this CPU is officially up. */static inline int can_use_console(unsigned int cpu){ return cpu_online(cpu) || have_callable_console();}/* * Try to get console ownership to actually show the kernel * messages from a 'printk'. Return true (and with the * console_semaphore held, and 'console_locked' set) if it * is successful, false otherwise. * * This gets called with the 'logbuf_lock' spinlock held and * interrupts disabled. It should return with 'lockbuf_lock' * released but interrupts still disabled. */static int acquire_console_semaphore_for_printk(unsigned int cpu){ int retval = 0; if (!try_acquire_console_sem()) { retval = 1; /* * If we can't use the console, we need to release * the console semaphore by hand to avoid flushing * the buffer. We need to hold the console semaphore * in order to do this test safely. */ if (!can_use_console(cpu)) { console_locked = 0; up(&console_sem); retval = 0; } } printk_cpu = UINT_MAX; spin_unlock(&logbuf_lock); return retval;}static const char recursion_bug_msg [] = KERN_CRIT "BUG: recent printk recursion!\n";static int recursion_bug; static int new_text_line = 1;static char printk_buf[1024];asmlinkage int vprintk(const char *fmt, va_list args){ int printed_len = 0; int current_log_level = default_message_loglevel; unsigned long flags; int this_cpu; char *p; boot_delay_msec(); preempt_disable(); /* This stops the holder of console_sem just where we want him */ raw_local_irq_save(flags); this_cpu = smp_processor_id(); /* * Ouch, printk recursed into itself! */ if (unlikely(printk_cpu == this_cpu)) { /* * If a crash is occurring during printk() on this CPU, * then try to get the crash message out but make sure * we can't deadlock. Otherwise just return to avoid the * recursion and return - but flag the recursion so that * it can be printed at the next appropriate moment: */ if (!oops_in_progress) { recursion_bug = 1; goto out_restore_irqs; } zap_locks(); } lockdep_off(); spin_lock(&logbuf_lock); printk_cpu = this_cpu; if (recursion_bug) { recursion_bug = 0; strcpy(printk_buf, recursion_bug_msg); printed_len = sizeof(recursion_bug_msg); } /* Emit the output into the temporary buffer */ printed_len += vscnprintf(printk_buf + printed_len, sizeof(printk_buf) - printed_len, fmt, args); /* * Copy the output into log_buf. If the caller didn't provide * appropriate log level tags, we insert them here */ for (p = printk_buf; *p; p++) { if (new_text_line) { /* If a token, set current_log_level and skip over */ if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' && p[2] == '>') { current_log_level = p[1] - '0'; p += 3; printed_len -= 3; } /* Always output the token */ emit_log_char('<'); emit_log_char(current_log_level + '0'); emit_log_char('>'); printed_len += 3; new_text_line = 0; if (printk_time) { /* Follow the token with the time */ char tbuf[50], *tp; unsigned tlen; unsigned long long t; unsigned long nanosec_rem; t = cpu_clock(printk_cpu); nanosec_rem = do_div(t, 1000000000); tlen = sprintf(tbuf, "[%5lu.%06lu] ", (unsigned long) t, nanosec_rem / 1000); for (tp = tbuf; tp < tbuf + tlen; tp++) emit_log_char(*tp); printed_len += tlen; } if (!*p) break; } emit_log_char(*p); if (*p == '\n') new_text_line = 1; } /* * Try to acquire and then immediately release the * console semaphore. The release will do all the * actual magic (print out buffers, wake up klogd, * etc). * * The acquire_console_semaphore_for_printk() function * will release 'logbuf_lock' regardless of whether it * actually gets the semaphore or not. */ if (acquire_console_semaphore_for_printk(this_cpu)) release_console_sem(); lockdep_on();out_restore_irqs: raw_local_irq_restore(flags); preempt_enable(); return printed_len;}EXPORT_SYMBOL(printk);EXPORT_SYMBOL(vprintk);#elseasmlinkage long sys_syslog(int type, char __user *buf, int len){ return -ENOSYS;}static void call_console_drivers(unsigned start, unsigned end){}#endifstatic int __add_preferred_console(char *name, int idx, char *options, char *brl_options){ struct console_cmdline *c; int i; /* * See if this tty is not yet registered, and * if we have a slot free. */ for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) if (strcmp(console_cmdline[i].name, name) == 0 && console_cmdline[i].index == idx) { if (!brl_options) selected_console = i; return 0; } if (i == MAX_CMDLINECONSOLES) return -E2BIG; if (!brl_options) selected_console = i; c = &console_cmdline[i]; strlcpy(c->name, name, sizeof(c->name)); c->options = options;#ifdef CONFIG_A11Y_BRAILLE_CONSOLE c->brl_options = brl_options;#endif c->index = idx; return 0;}/* * Set up a list of consoles. Called from init/main.c */static int __init console_setup(char *str){ char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */ char *s, *options, *brl_options = NULL; int idx;#ifdef CONFIG_A11Y_BRAILLE_CONSOLE if (!memcmp(str, "brl,", 4)) { brl_options = ""; str += 4; } else if (!memcmp(str, "brl=", 4)) { brl_options = str + 4; str = strchr(brl_options, ','); if (!str) { printk(KERN_ERR "need port name after brl=\n"); return 1; } *(str++) = 0; }#endif /* * Decode str into name, index, options. */ if (str[0] >= '0' && str[0] <= '9') { strcpy(buf, "ttyS"); strncpy(buf + 4, str, sizeof(buf) - 5); } else { strncpy(buf, str, sizeof(buf) - 1); } buf[sizeof(buf) - 1] = 0; if ((options = strchr(str, ',')) != NULL) *(options++) = 0;#ifdef __sparc__ if (!strcmp(str, "ttya")) strcpy(buf, "ttyS0"); if (!strcmp(str, "ttyb")) strcpy(buf, "ttyS1");#endif for (s = buf; *s; s++) if ((*s >= '0' && *s <= '9') || *s == ',') break; idx = simple_strtoul(s, NULL, 10); *s = 0; __add_preferred_console(buf, idx, options, brl_options); console_set_on_cmdline = 1; return 1;}__setup("console=", console_setup);/** * add_preferred_console - add a device to the list of preferred consoles. * @name: device name * @idx: device index * @options: options for this console * * The last preferred console added will be used for kernel messages * and stdin/out/err for init. Normally this is used by console_setup * above to handle user-supplied console arguments; however it can also * be used by arch-specific code either to override the user or more * commonly to provide a default console (ie from PROM variables) when * the user has not supplied one. */int add_preferred_console(char *name, int idx, char *options){ return __add_preferred_console(name, idx, options, NULL);}int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -