From: James S. <jsi...@us...> - 2001-12-26 17:28:16
|
Update of /cvsroot/linuxconsole/ruby/linux/kernel In directory usw-pr-cvs1:/tmp/cvs-serv5113/kernel Modified Files: printk.c Log Message: Synced to 2.5.0. Don't use. The default 2.5.0 has a nasty bug in it. Index: printk.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/kernel/printk.c,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- printk.c 2001/12/23 04:59:46 1.22 +++ printk.c 2001/12/26 17:28:12 1.23 @@ -14,9 +14,6 @@ * man...@co... * Rewrote bits to get rid of console_lock * 01Mar01 Andrew Morton <an...@uo...> - * Added finer grain locking for the console system. Also made it more - * VT independent. - * 11-28-2001 James Simmons <jsi...@tr...> */ #include <linux/mm.h> @@ -27,10 +24,18 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/interrupt.h> /* For in_interrupt() */ +#include <linux/config.h> #include <asm/uaccess.h> +#ifdef CONFIG_MULTIQUAD +#define LOG_BUF_LEN (65536) +#elif defined(CONFIG_SMP) +#define LOG_BUF_LEN (32768) +#else #define LOG_BUF_LEN (16384) /* This must be a power of two */ +#endif + #define LOG_BUF_MASK (LOG_BUF_LEN-1) /* printk's without a loglevel use this.. */ @@ -51,9 +56,11 @@ int oops_in_progress; /* - * console_lock protects the console_drivers list + * console_sem protects the console_drivers list, and also + * provides serialisation for access to the entire console + * driver system. */ -static spinlock_t console_lock = SPIN_LOCK_UNLOCKED; +static DECLARE_MUTEX(console_sem); struct console *console_drivers; /* @@ -78,6 +85,9 @@ struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; static int preferred_console = -1; +/* Flag: console code may call schedule() */ +static int console_may_schedule; + /* * Setup a list of consoles. Called from init/main.c */ @@ -284,29 +294,28 @@ /* * Call the console drivers on a range of log_buf */ -static void __call_console_drivers(struct console *con, unsigned long start, unsigned long end) +static void __call_console_drivers(unsigned long start, unsigned long end) { - /* Make sure that we print immediately */ - if (oops_in_progress) - init_MUTEX(&con->lock); + struct console *con; - down(&con->lock); - con->write(con, &LOG_BUF(start), end - start); - up(&con->lock); + for (con = console_drivers; con; con = con->next) { + if ((con->flags & CON_ENABLED) && con->write) + con->write(con, &LOG_BUF(start), end - start); + } } /* * Write out chars from start to end - 1 inclusive */ -static void _call_console_drivers(struct console *con, unsigned long start, unsigned long end, int msg_log_level) +static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level) { - if (msg_log_level < console_loglevel && con && start != end) { + if (msg_log_level < console_loglevel && console_drivers && start != end) { if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) { /* wrapped write */ - __call_console_drivers(con, start & LOG_BUF_MASK, LOG_BUF_LEN); - __call_console_drivers(con, 0, end & LOG_BUF_MASK); + __call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN); + __call_console_drivers(0, end & LOG_BUF_MASK); } else { - __call_console_drivers(con, start, end); + __call_console_drivers(start, end); } } } @@ -316,7 +325,7 @@ * log_buf[start] to log_buf[end - 1]. * The console_sem must be held. */ -static void call_console_drivers(struct console *con, unsigned long start, unsigned long end) +static void call_console_drivers(unsigned long start, unsigned long end) { unsigned long cur_index, start_print; static int msg_level = -1; @@ -352,14 +361,14 @@ */ msg_level = default_message_loglevel; } - _call_console_drivers(con, start_print, cur_index, msg_level); + _call_console_drivers(start_print, cur_index, msg_level); msg_level = -1; start_print = cur_index; break; } } } - _call_console_drivers(con, start_print, end, msg_level); + _call_console_drivers(start_print, end, msg_level); } static void emit_log_char(char c) @@ -389,42 +398,33 @@ */ asmlinkage int printk(const char *fmt, ...) { - static struct { - char buf[1024]; - unsigned long semi_random; - } printk_buf; - static int log_level_unknown = 1; - unsigned long sr_copy; - unsigned long flags; - struct console *con; - int printed_len; - va_list args; - char *p; + va_list args; + unsigned long flags; + int printed_len; + char *p; + static char printk_buf[1024]; + static int log_level_unknown = 1; if (oops_in_progress) { /* If a crash is occurring, make sure we can't deadlock */ spin_lock_init(&logbuf_lock); - spin_lock_init(&console_lock); + /* And make sure that we print immediately */ + init_MUTEX(&console_sem); } /* This stops the holder of console_sem just where we want him */ spin_lock_irqsave(&logbuf_lock, flags); /* Emit the output into the temporary buffer */ - printk_buf.semi_random += jiffies; - sr_copy = printk_buf.semi_random; va_start(args, fmt); - printed_len = vsnprintf(printk_buf.buf, sizeof(printk_buf.buf), fmt, args); + printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); va_end(args); - if (sr_copy != printk_buf.semi_random) - panic("buffer overrun in printk()"); - /* * Copy the output into log_buf. If the caller didn't provide * appropriate log level tags, we insert them here */ - for (p = printk_buf.buf; *p; p++) { + for (p = printk_buf; *p; p++) { if (log_level_unknown) { if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') { emit_log_char('<'); @@ -437,22 +437,23 @@ if (*p == '\n') log_level_unknown = 1; } - spin_unlock_irqrestore(&logbuf_lock, flags); - spin_lock(&console_lock); - for (con = console_drivers; con; con = con->next) { + if (!down_trylock(&console_sem)) { /* - * We own the drivers list. We can drop the lock and - * let release_console_sem() print the text + * We own the drivers. We can drop the spinlock and let + * release_console_sem() print the text */ - spin_unlock(&console_lock); - if ((con->flags & CON_ENABLED) && con->write) { - if (!down_trylock(&con->lock)) - release_console_sem(con->device(con)); - } - spin_lock(&console_lock); + spin_unlock_irqrestore(&logbuf_lock, flags); + console_may_schedule = 0; + release_console_sem(); + } else { + /* + * Someone else owns the drivers. We drop the spinlock, which + * allows the semaphore holder to proceed and to call the + * console drivers with the output which we just produced. + */ + spin_unlock_irqrestore(&logbuf_lock, flags); } - spin_unlock(&console_lock); return printed_len; } EXPORT_SYMBOL(printk); @@ -461,41 +462,24 @@ * acquire_console_sem - lock the console system for exclusive use. * * Acquires a semaphore which guarantees that the caller has - * exclusive access to a console system. + * exclusive access to the console system and the console_drivers list. * * Can sleep, returns nothing. */ -void acquire_console_sem(kdev_t device) +void acquire_console_sem(void) { - struct console *con; - if (in_interrupt()) BUG(); - - spin_lock(&console_lock); - /* Look for new messages */ - for (con = console_drivers; con; con = con->next) { - if (con->device(con) == device) - break; - } - spin_unlock(&console_lock); - - if (con) { - down(&con->lock); - //driver->may_schedule = 1; - } + down(&console_sem); + console_may_schedule = 1; } EXPORT_SYMBOL(acquire_console_sem); /** * release_console_sem - unlock the console system * - * Releases the semaphore which the caller holds that is shared between - * the TTY and console system. This function is the most complex. It can - * be called by a driver that only has a console i.e lp console and no - * tty, the tty system that has no console associated with it, or the final - * type which is hardware driven by both a console driver and tty driver. - * We have to handle all 3 cases. + * Releases the semaphore which the caller holds on the console system + * and the console driver list. * * While the semaphore was held, console output may have been buffered * by printk(). If this is the case, release_console_sem() emits @@ -505,48 +489,28 @@ * * release_console_sem() may be called from any context. */ -void release_console_sem(kdev_t device) +void release_console_sem(void) { - struct tty_driver *driver = get_tty_driver(device); + unsigned long flags; unsigned long _con_start, _log_end; unsigned long must_wake_klogd = 0; - unsigned long flags; - struct console *con; - if (driver && driver->console) - con = driver->console; - else { - spin_lock(&console_lock); - for (con = console_drivers; con; con = con->next) { - if (con->device(con) == device) - break; - } - spin_unlock(&console_lock); - } - - if (con) { - for ( ; ; ) { - spin_lock_irqsave(&logbuf_lock, flags); - must_wake_klogd |= log_start - log_end; - if (con_start == log_end) - break; /* Nothing to print */ - _con_start = con_start; - _log_end = log_end; - con_start = log_end; /* Flush */ - spin_unlock_irqrestore(&logbuf_lock, flags); - call_console_drivers(con, _con_start, _log_end); - } + for ( ; ; ) { + spin_lock_irqsave(&logbuf_lock, flags); + must_wake_klogd |= log_start - log_end; + if (con_start == log_end) + break; /* Nothing to print */ + _con_start = con_start; + _log_end = log_end; + con_start = log_end; /* Flush */ spin_unlock_irqrestore(&logbuf_lock, flags); - if (must_wake_klogd && !oops_in_progress) - wake_up_interruptible(&log_wait); - up(&con->lock); - return; - } - - if (driver) { - driver->may_schedule = 0; - up(driver->tty_lock); + call_console_drivers(_con_start, _log_end); } + console_may_schedule = 0; + up(&console_sem); + spin_unlock_irqrestore(&logbuf_lock, flags); + if (must_wake_klogd && !oops_in_progress) + wake_up_interruptible(&log_wait); } /** console_conditional_schedule - yield the CPU if required @@ -557,9 +521,9 @@ * * Must be called within acquire_console_sem(). */ -void console_conditional_schedule(struct tty_driver *driver) +void console_conditional_schedule(void) { - if (driver->may_schedule && current->need_resched) { + if (console_may_schedule && current->need_resched) { set_current_state(TASK_RUNNING); schedule(); } @@ -571,6 +535,18 @@ } EXPORT_SYMBOL(console_print); +void console_unblank(void) +{ + struct console *c; + + acquire_console_sem(); + for (c = console_drivers; c != NULL; c = c->next) + if ((c->flags & CON_ENABLED) && c->unblank) + c->unblank(); + release_console_sem(); +} +EXPORT_SYMBOL(console_unblank); + /* * The console driver calls this routine during kernel initialization * to register the console printing procedure with printk() and to @@ -579,8 +555,8 @@ */ void register_console(struct console * console) { + int i; unsigned long flags; - int i; /* * See if we want to use this console driver. If we @@ -626,7 +602,7 @@ * Put this console in the list - keep the * preferred driver at the head of the list. */ - spin_lock(&console_lock); + acquire_console_sem(); if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { console->next = console_drivers; console_drivers = console; @@ -634,19 +610,15 @@ console->next = console_drivers->next; console_drivers->next = console; } - spin_unlock(&console_lock); - - init_MUTEX(&console->lock); - if (console->flags & CON_PRINTBUFFER) { /* - * release_console_sem() will print out the buffered messages for us. + * release_cosole_sem() will print out the buffered messages for us. */ spin_lock_irqsave(&logbuf_lock, flags); con_start = log_start; spin_unlock_irqrestore(&logbuf_lock, flags); } - release_console_sem(console->device(console)); + release_console_sem(); } EXPORT_SYMBOL(register_console); @@ -655,9 +627,7 @@ struct console *a,*b; int res = 1; - release_console_sem(console->device(console)); - - spin_lock(&console_lock); + acquire_console_sem(); if (console_drivers == console) { console_drivers=console->next; res = 0; @@ -679,7 +649,8 @@ if (console_drivers == NULL) preferred_console = -1; - spin_unlock(&console_lock); + + release_console_sem(); return res; } EXPORT_SYMBOL(unregister_console); |