From: James S. <jsi...@us...> - 2001-12-26 20:29:26
|
Update of /cvsroot/linuxconsole/ruby/linux/kernel In directory usw-pr-cvs1:/tmp/cvs-serv13145 Modified Files: printk.c Log Message: Hm. Somehow I put the orginal printk.c here. Now we have the proper one. Index: printk.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/kernel/printk.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- printk.c 2001/12/26 17:28:12 1.23 +++ printk.c 2001/12/26 20:29:23 1.24 @@ -14,6 +14,9 @@ * 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> @@ -24,18 +27,10 @@ #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.. */ @@ -56,11 +51,9 @@ int oops_in_progress; /* - * console_sem protects the console_drivers list, and also - * provides serialisation for access to the entire console - * driver system. + * console_lock protects the console_drivers list */ -static DECLARE_MUTEX(console_sem); +static spinlock_t console_lock = SPIN_LOCK_UNLOCKED; struct console *console_drivers; /* @@ -85,9 +78,6 @@ 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 */ @@ -294,28 +284,29 @@ /* * Call the console drivers on a range of log_buf */ -static void __call_console_drivers(unsigned long start, unsigned long end) +static void __call_console_drivers(struct console *con, unsigned long start, unsigned long end) { - struct console *con; + /* Make sure that we print immediately */ + if (oops_in_progress) + init_MUTEX(&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); - } + down(&con->lock); + con->write(con, &LOG_BUF(start), end - start); + up(&con->lock); } /* * Write out chars from start to end - 1 inclusive */ -static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level) +static void _call_console_drivers(struct console *con, unsigned long start, unsigned long end, int msg_log_level) { - if (msg_log_level < console_loglevel && console_drivers && start != end) { + if (msg_log_level < console_loglevel && con && 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); + __call_console_drivers(con, start & LOG_BUF_MASK, LOG_BUF_LEN); + __call_console_drivers(con, 0, end & LOG_BUF_MASK); } else { - __call_console_drivers(start, end); + __call_console_drivers(con, start, end); } } } @@ -325,7 +316,7 @@ * log_buf[start] to log_buf[end - 1]. * The console_sem must be held. */ -static void call_console_drivers(unsigned long start, unsigned long end) +static void call_console_drivers(struct console *con, unsigned long start, unsigned long end) { unsigned long cur_index, start_print; static int msg_level = -1; @@ -361,14 +352,14 @@ */ msg_level = default_message_loglevel; } - _call_console_drivers(start_print, cur_index, msg_level); + _call_console_drivers(con, start_print, cur_index, msg_level); msg_level = -1; start_print = cur_index; break; } } } - _call_console_drivers(start_print, end, msg_level); + _call_console_drivers(con, start_print, end, msg_level); } static void emit_log_char(char c) @@ -398,33 +389,42 @@ */ asmlinkage int printk(const char *fmt, ...) { - va_list args; - unsigned long flags; - int printed_len; - char *p; - static char printk_buf[1024]; - static int log_level_unknown = 1; + 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; if (oops_in_progress) { /* 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); + spin_lock_init(&console_lock); } /* 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, sizeof(printk_buf), fmt, args); + printed_len = vsnprintf(printk_buf.buf, sizeof(printk_buf.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; *p; p++) { + for (p = printk_buf.buf; *p; p++) { if (log_level_unknown) { if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') { emit_log_char('<'); @@ -437,23 +437,22 @@ if (*p == '\n') log_level_unknown = 1; } + spin_unlock_irqrestore(&logbuf_lock, flags); - if (!down_trylock(&console_sem)) { - /* - * We own the drivers. We can drop the spinlock and let - * release_console_sem() print the text - */ - spin_unlock_irqrestore(&logbuf_lock, flags); - console_may_schedule = 0; - release_console_sem(); - } else { + spin_lock(&console_lock); + for (con = console_drivers; con; con = con->next) { /* - * 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. + * We own the drivers list. We can drop the lock and + * let release_console_sem() print the text */ - spin_unlock_irqrestore(&logbuf_lock, flags); + 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(&console_lock); return printed_len; } EXPORT_SYMBOL(printk); @@ -462,24 +461,41 @@ * acquire_console_sem - lock the console system for exclusive use. * * Acquires a semaphore which guarantees that the caller has - * exclusive access to the console system and the console_drivers list. + * exclusive access to a console system. * * Can sleep, returns nothing. */ -void acquire_console_sem(void) +void acquire_console_sem(kdev_t device) { + struct console *con; + if (in_interrupt()) BUG(); - down(&console_sem); - console_may_schedule = 1; + + 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; + } } EXPORT_SYMBOL(acquire_console_sem); /** * release_console_sem - unlock the console system * - * Releases the semaphore which the caller holds on the console system - * and the console driver list. + * 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. * * While the semaphore was held, console output may have been buffered * by printk(). If this is the case, release_console_sem() emits @@ -489,28 +505,48 @@ * * release_console_sem() may be called from any context. */ -void release_console_sem(void) +void release_console_sem(kdev_t device) { - unsigned long flags; + struct tty_driver *driver = get_tty_driver(device); unsigned long _con_start, _log_end; unsigned long must_wake_klogd = 0; + unsigned long flags; + struct console *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 */ + 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); + } spin_unlock_irqrestore(&logbuf_lock, flags); - call_console_drivers(_con_start, _log_end); + if (must_wake_klogd && !oops_in_progress) + wake_up_interruptible(&log_wait); + up(&con->lock); + return; } - 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); + + if (driver) { + driver->may_schedule = 0; + up(driver->tty_lock); + } } /** console_conditional_schedule - yield the CPU if required @@ -521,9 +557,9 @@ * * Must be called within acquire_console_sem(). */ -void console_conditional_schedule(void) +void console_conditional_schedule(struct tty_driver *driver) { - if (console_may_schedule && current->need_resched) { + if (driver->may_schedule && current->need_resched) { set_current_state(TASK_RUNNING); schedule(); } @@ -535,18 +571,6 @@ } 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 @@ -555,8 +579,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 @@ -602,7 +626,7 @@ * Put this console in the list - keep the * preferred driver at the head of the list. */ - acquire_console_sem(); + spin_lock(&console_lock); if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { console->next = console_drivers; console_drivers = console; @@ -610,15 +634,19 @@ console->next = console_drivers->next; console_drivers->next = console; } + spin_unlock(&console_lock); + + init_MUTEX(&console->lock); + if (console->flags & CON_PRINTBUFFER) { /* - * release_cosole_sem() will print out the buffered messages for us. + * release_console_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(); + release_console_sem(console->device(console)); } EXPORT_SYMBOL(register_console); @@ -627,7 +655,9 @@ struct console *a,*b; int res = 1; - acquire_console_sem(); + release_console_sem(console->device(console)); + + spin_lock(&console_lock); if (console_drivers == console) { console_drivers=console->next; res = 0; @@ -649,8 +679,7 @@ if (console_drivers == NULL) preferred_console = -1; - - release_console_sem(); + spin_unlock(&console_lock); return res; } EXPORT_SYMBOL(unregister_console); |