diff -Nru linux/include/linux/jstrace.h.orig linux/include/linux/jstrace.h --- linux/include/linux/jstrace.h.orig 2004-03-16 15:00:50.000000000 -0800 +++ linux/include/linux/jstrace.h 2004-03-17 09:16:42.000000000 -0800 @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2003, 2004 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +/* + * Jstrace provide a simple interface to quickly instruement kernel. + * This version is SMP-safe. + * + * Four kernel functions are provided: + * + * jstrace(" /proc/jstrace + * start tracing + * + * echo '0' > /proc/jstrace + * stop tracing + * + * cat /proc/jstrace + * display current log entries. Tracing will be stopped if + * it has not stopped yet. + * + * Compile time options defined in kernel/jstrace.c file: + * + * NUM_EVENT - maximum num of entries + * CUSTOM_LOG_SIZE - number chars allocated for customized log msg + * + * Trace output format: + * time stamp jiffies cpu:pid file:line(func) - custom msg + * + * If in interupt, pid is -1 + */ + +#ifndef _LINUX_JSTRACE_H_ +#define _LINUX_JSTRACE_H_ + +#include +#include +#include + +extern void jstrace_printk(void); + +extern void _jstrace(const char*, int, const char*, const char*, ...); +extern atomic_t jstrace_flag; + +#define jstrace(fmt, arg...) \ + _jstrace(__FILE__, __LINE__, __func__, (const char*)fmt, ##arg) + +#define jstrace_start() \ + do { \ + atomic_set(&jstrace_flag, 1); \ + _jstrace(__FILE__, __LINE__, __func__, "jstrace start"); \ + } while (0) + +#define jstrace_stop() \ + do { \ + _jstrace(__FILE__, __LINE__, __func__, "jstrace stop"); \ + atomic_set(&jstrace_flag, 0); \ + } while (0) + +#endif /* _LINUX_JSTRACE_H_ */ diff -Nru linux/kernel/jstrace.c.orig linux/kernel/jstrace.c --- linux/kernel/jstrace.c.orig 2004-03-16 15:00:50.000000000 -0800 +++ linux/kernel/jstrace.c 2004-03-17 09:16:58.000000000 -0800 @@ -0,0 +1,270 @@ +/* + * kernel run-time trace library. + * + * Copyright (C) 2002, 2003, 2004 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * See change log at the end. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* -------------------- CONFIG ------------------------- */ +#define NUM_EVENT 128 +#define CUSTOM_LOG_SIZE 70 + +#define PROC_FS_PATH "jstrace" + +#define JSTRACE_START_ON_INIT 0 /* do we start logging by default? */ +/* -------------------- CONFIG ------------------------- */ + +#if !defined(CONFIG_PROC_FS) +#error "jstrace needs proc file system!" +#endif + +static struct jstrace_event { + struct timeval ts; + unsigned long jiffies; + int cpu; + int pid; /* -1 : in interrupt context */ + + const char * file; + int line; + const char * function; + + char msg[CUSTOM_LOG_SIZE]; +} log[NUM_EVENT]; +static int index; + +static spinlock_t trace_lock = SPIN_LOCK_UNLOCKED; + +atomic_t jstrace_flag; +static atomic_t tracing_flag[NR_CPUS]; + +void _jstrace(const char *fname, int line, const char *func, const char *fmt, ...) +{ + int cpu = smp_processor_id(); + va_list args; + unsigned long flags; + + if (!atomic_read(&jstrace_flag)) + return; + + + if (atomic_inc_return(&tracing_flag[cpu]) != 1) { + atomic_dec(&tracing_flag[cpu]); + return; + } + + spin_lock_irqsave(&trace_lock, flags); + + va_start(args, fmt); + vsnprintf(log[index].msg, CUSTOM_LOG_SIZE, fmt, args); + va_end(args); + + do_gettimeofday(&log[index].ts); + log[index].jiffies = jiffies; + log[index].cpu = smp_processor_id(); + if (in_interrupt()) + log[index].pid = -1; + else + log[index].pid = current->pid; + log[index].file = fname; + log[index].line = line; + log[index].function = func; + + if (++index == NUM_EVENT) + index = 0; + + spin_unlock_irqrestore(&trace_lock, flags); + + atomic_dec(&tracing_flag[cpu]); +} + +static int +jstrace_input(struct file * file, const char * buf, unsigned long count, void *data) +{ + char c; + + if (copy_from_user(&c, buf, 1)) + return -EFAULT; + + if (c == '1') { + atomic_set(&jstrace_flag, 1); + } else { + atomic_set(&jstrace_flag, 0); + } + return count; +} + +struct proc_write_handle { + char * buf; + int index; + int count; + + int fpos; + int length; +}; + +static void +proc_write_init(struct proc_write_handle *handle, char *buf, int count, int fpos) +{ + handle->buf = buf; + handle->count = count; + handle->fpos = fpos; + handle->index = 0; + handle->length = 0; +} + +/* + * returns: + * -1 : not logged yet due to fpos greater than current output length. + * 0 : logging output + * 1 : overflow, maybe partially logged, future logging stopped. + */ +static int +proc_write(struct proc_write_handle *h, char * fmt, ...) +{ + static char buf[512]; + + va_list args; + int size; + int old_length=h->length; + int start=0; + int overflow=0; + + va_start(args, fmt); + size=vsnprintf(buf, 512, fmt, args); + va_end(args); + + h->length += size; + if (h->length <= h->fpos) + return -1; + + if (h->index == h->count) + return 1; + + if (old_length <= h->fpos) + start = h->fpos - old_length; + + size -= start; + if (size > h->count - h->index) { + overflow=1; + size = h->count - h->index; + } + + strncpy(h->buf+h->index, buf+start, size); + h->index += size; + + if (overflow) + return 1; + else + return 0; +} + +static int +jstrace_output(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int i; + int ret; + struct proc_write_handle h; + + atomic_set(&jstrace_flag, 0); // stop logging first + + proc_write_init(&h, page, count, off); + + proc_write(&h, "gettimeofday\tjiffies\t\tcpu:pid\tfile:line(func) - msg\n"); + for(i=index;;) { + if (!log[i].file) { + ret = proc_write(&h, "(EMPTY)\n"); + } else { + ret = proc_write(&h, "%lu:%lu\t%11lu\t%d:%d\t%s:%d(%s)-%s\n", + log[i].ts.tv_sec&0xffff, + log[i].ts.tv_usec, + log[i].jiffies, + log[i].cpu, log[i].pid, + log[i].file, log[i].line, + log[i].function,log[i].msg); + } + if (++i == NUM_EVENT) + i=0; + if ((i == index) || (ret == 1)) + break; + } + + if (ret != 1) + /* we must have finished all entries, and last print is good */ + *eof = 1; + else + *eof = 0; + + /* fix for user read */ + *start = page; + + return h.index; +} + +void +jstrace_printk(void) +{ +#define BUF_SIZE 512 + static char buf[BUF_SIZE+1]; + int eof; + char *start; + int off; + + buf[BUF_SIZE]=0; + for(off=0, eof=0;!eof;) { + int ret=jstrace_output(buf, &start, off, BUF_SIZE, &eof, NULL); + if (ret>=0) + start[ret]=0; + printk("%s", start); + off+=ret; + } +} + +int __init +jstrace_init(void) +{ + int i; + struct proc_dir_entry *entry; + + entry = create_proc_entry(PROC_FS_PATH, S_IWUSR | S_IRUGO, NULL); + if (entry) { + entry->read_proc = jstrace_output; + entry->write_proc = jstrace_input; + } + + atomic_set(&jstrace_flag, JSTRACE_START_ON_INIT); + + for (i=0; i< NR_CPUS; i++) + atomic_set(&tracing_flag[i], 0); + + return 0; +} + +__initcall(jstrace_init); + +/* + * CHANGE LOG : + * + * 040316 : Convert jstrace_flag to be atomic_t. jstrace_printk() debugged. + * Fix a subtle eof bug in output. + * Change to use "/proc/jstrace" proc entry. + * 040303 : Make SMP safe, tracing_flag needs to be per-cpu and atomic. + * jstrace_printk() is promoted as first-class citizen. + */ diff -Nru linux/kernel/Makefile.orig linux/kernel/Makefile --- linux/kernel/Makefile.orig 2004-03-16 11:04:09.000000000 -0800 +++ linux/kernel/Makefile 2004-03-16 15:01:00.000000000 -0800 @@ -7,7 +7,7 @@ sysctl.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o workqueue.o pid.o \ rcupdate.o intermodule.o extable.o params.o posix-timers.o \ - kthread.o + kthread.o jstrace.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o