better overflow handling in say() infrastructure

This commit is contained in:
Thomas Schoebel-Theuer 2012-01-12 14:37:06 +01:00 committed by Thomas Schoebel-Theuer
parent 0d4d227dec
commit 1a3a9d2789
1 changed files with 50 additions and 39 deletions

View File

@ -25,6 +25,7 @@
static char *say_buf[NR_CPUS] = {}; static char *say_buf[NR_CPUS] = {};
static int say_index[NR_CPUS] = {}; static int say_index[NR_CPUS] = {};
static int dump_max = 5; static int dump_max = 5;
static atomic_t overflow = ATOMIC_INIT(0);
static struct file *log_file = NULL; static struct file *log_file = NULL;
@ -111,15 +112,13 @@ void say_mark(void)
} }
EXPORT_SYMBOL_GPL(say_mark); EXPORT_SYMBOL_GPL(say_mark);
void say(const char *fmt, ...) static
void _say(unsigned long cpu, va_list args, bool use_args, const char *fmt, ...)
{ {
unsigned long cpu = get_cpu();
char *start; char *start;
int rest; int rest;
int written; int written;
va_list args;
_say_mark(cpu);
if (!say_buf[cpu]) if (!say_buf[cpu])
goto done; goto done;
@ -128,20 +127,53 @@ void say(const char *fmt, ...)
goto done; goto done;
start = say_buf[cpu] + say_index[cpu]; start = say_buf[cpu] + say_index[cpu];
va_start(args, fmt); if (use_args) {
written = vsnprintf(start, rest, fmt, args); /* bug in gcc: use register variable
va_end(args); * shading the parameter
*/
va_list args;
va_start(args, fmt);
written = vsnprintf(start, rest, fmt, args);
va_end(args);
} else {
written = vsnprintf(start, rest, fmt, args);
}
if (likely(rest > written)) { if (likely(rest > written)) {
start[written] = '\0'; start[written] = '\0';
say_index[cpu] += written; say_index[cpu] += written;
} else if (rest > 2) { } else {
// indicate overflow when possible // indicate overflow
start[0] = '@'; atomic_inc(&overflow);
start[1] = '\n';
start[2] = '\0';
say_index[cpu] += 2;
} }
done: ;
}
static inline
void _check_overflow(unsigned long cpu)
{
if (say_index[cpu] < SAY_BUFMAX - 8) {
int count = 0;
atomic_xchg(&overflow, count);
if (unlikely(count > 0)) {
_say(cpu, NULL, true, "#%d#\n", count);
}
}
}
void say(const char *fmt, ...)
{
unsigned long cpu = get_cpu();
va_list args;
_say_mark(cpu);
if (!say_buf[cpu])
goto done;
_check_overflow(cpu);
va_start(args, fmt);
_say(cpu, args, false, fmt);
va_end(args);
_say_mark(cpu); _say_mark(cpu);
done: done:
@ -154,43 +186,22 @@ void brick_say(bool dump, const char *prefix, const char *file, int line, const
struct timespec now = CURRENT_TIME; struct timespec now = CURRENT_TIME;
unsigned long cpu = get_cpu(); unsigned long cpu = get_cpu();
int filelen; int filelen;
char *start;
int rest;
int written;
va_list args; va_list args;
_say_mark(cpu); _say_mark(cpu);
if (!say_buf[cpu]) if (!say_buf[cpu])
goto done; goto done;
_check_overflow(cpu);
// limit the filename // limit the filename
filelen = strlen(file); filelen = strlen(file);
if (filelen > MAX_FILELEN) if (filelen > MAX_FILELEN)
file += filelen - MAX_FILELEN; file += filelen - MAX_FILELEN;
rest = SAY_BUFMAX - say_index[cpu]; _say(cpu, NULL, true, "%ld.%09ld %s %s[%d] %s %d %s(): ", now.tv_sec, now.tv_nsec, prefix, current->comm, (int)cpu, file, line, func);
if (rest <= 0) va_start(args, fmt);
goto done; _say(cpu, args, false, fmt);
va_end(args);
start = say_buf[cpu] + say_index[cpu];
written = snprintf(start, rest, "%ld.%09ld %s %s[%d] %s %d %s(): ", now.tv_sec, now.tv_nsec, prefix, current->comm, (int)cpu, file, line, func);
if (likely(rest > written)) {
va_start(args, fmt);
written += vsnprintf(start + written, rest - written, fmt, args);
va_end(args);
}
if (likely(rest > written)) {
start[written] = '\0';
say_index[cpu] += written;
} else if (rest > 2) {
// indicate overflow when possible
start[0] = '@';
start[1] = '\n';
start[2] = '\0';
say_index[cpu] += 2;
}
_say_mark(cpu); _say_mark(cpu);
#ifdef CONFIG_DEBUG_KERNEL #ifdef CONFIG_DEBUG_KERNEL