--- linux-2.6.12-rc3-kdb/include/linux/fileop.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.12-rc3-kdb-zlog/include/linux/fileop.h 2005-05-07 17:29:37.000000000 -0400 @@ -0,0 +1,30 @@ +/* + * fileop.h: provides uniform way to access files in kernel space + * + * Copyright (C) 2003 - www.linuxforum.net + * + * This file is released under the GPL. + */ +#ifndef _KFILEOP_H +#define _KFILEOP_H + +#include +#include +#include +#include +#include + +struct file *klib_fopen(const char *filename, int flags, int mode); +void klib_fclose(struct file *filp); + +int klib_fseek(struct file *filp, int offset, int whence); +int klib_fread(char *buf, int len, struct file *filp); +int klib_fgetc(struct file *filp); +char *klib_fgets(char *str, int size, struct file *filp); + +int klib_fwrite(char *buf, int len, struct file *filp); +int klib_fputc(int ch, struct file *filp); +int klib_fputs(char *str, struct file *filp); +int klib_fprintf(struct file *filp, const char *fmt, ...); + +#endif --- linux-2.6.12-rc3-kdb/include/linux/zlog.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.12-rc3-kdb-zlog/include/linux/zlog.h 2005-05-07 17:54:11.000000000 -0400 @@ -0,0 +1,74 @@ +/* + * zlog.h: provides atomic write access to the kernel log buffer + * no synchronization need to read the buffer + * + * Notice: + * instead of do printk(fmt,....); + * you can do kernel logging in the following 4 ways + * + * a. just replace printk with ztrace_printf + * ztrace_printf(fmt, ....) + * + * b. some times, you want to group multiple prints as a "sentence" + * which means, you want to do "\n" after multiple prints + * Using printk, prints from other thread may mess up your prints + * With zlog, you can print this way: + * -- you get a slot_id first using start_sentence() + * -- you then do zlog_print, with the provided slot_id + * -- in the end, you call end_sentence() + * sample: + * + * slot_id = start_sentence(); + * zlog_print(slot_id,fmt,...); + * ....... + * zlog_print(slot_id,fmt,...); + * end_sentence(slot_id); + * + * + * c. if you want to write in binary format + * you can use: + * slot_id = start_sentence(); + * zlog_write(slot_id,obj,size); + * ....... + * zlog_write(slot_id,obj,size); + * end_sentence(slot_id); + * + * d. if you only write once for the sentence, then you do + * ztrace_write(obj,size) + * + * Copyright (C) 2005 - Haoqiang Zheng + * haoqiang@gmail.com + * + * This file is released under the GPL. + */ +#ifndef _ZHQLOG_H +#define _ZHQLOG_H +#include + +int start_sentence(unsigned long *flags); +void end_sentence(int slot_id,unsigned long* flags); +void zlog_write(int slot_id, void *obj, int size); +void zlog_print(int slot_id, const char *fmt, ...); + +int ztrace_printf(const char *fmt, ...); +void ztrace_write(void *obj, int size); + +/*return true if ztrace is enabled*/ +extern atomic_t enable_zlog; +static inline int ztrace_enabled(void) +{ + return atomic_read(&enable_zlog); +} + +/*useful macros for debugging */ +#define ZASSERT(buf) {\ + ztrace_printf(buf);\ + ztrace_printf("assert at file: %s line: %d \n",__FILE__,__LINE__);\ +} + +#define ZWARN(buf) {\ + ztrace_printf(buf);\ + ztrace_printf("warn at file: %s line: %d \n",__FILE__,__LINE__);\ +} + +#endif --- linux-2.6.12-rc3-kdb/kernel/fileop.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.12-rc3-kdb-zlog/kernel/fileop.c 2005-05-07 17:29:38.000000000 -0400 @@ -0,0 +1,259 @@ +/* + * fileop.c: provides uniform way to access files in kernel space + * + * Copyright (C) 2003 - www.linuxforum.net + * + * This file is released under the GPL. + */ +#include +#include +#include + +/* + file I/O in kernel module +*/ +#define EOF (-1) +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +// Context : User +// Parameter : +// filename : filename to open +// flags : +// O_RDONLY, O_WRONLY, O_RDWR +// O_CREAT, O_EXCL, O_TRUNC, O_APPEND, O_NONBLOCK, O_SYNC, ... +// mode : file creation permission. +// S_IRxxx S_IWxxx S_IXxxx (xxx = USR, GRP, OTH), S_IRWXx (x = U, G, O) +// Return : +// file pointer. if error, return NULL + +struct file *klib_fopen(const char *filename, int flags, int mode) +{ + + struct file *filp = filp_open(filename, flags, mode); +// printk("result = %d\n",(int)filp); + + return (IS_ERR(filp)) ? NULL : filp; +} + +// Context : User +// Parameter : +// filp : file pointer +// Return : +void klib_fclose(struct file *filp) +{ + if (filp) + fput(filp); +} + +// Context : User +// Parameter : +// filp : file pointer +// offset : +// whence : SEEK_SET, SEEK_CUR +// Comment : +// do not support SEEK_END +// no boundary check (file position may exceed file size) +int klib_fseek(struct file *filp, int offset, int whence) +{ + + int pos = filp->f_pos; + + if (filp) { + + if (whence == SEEK_SET) + pos = offset; + else if (whence == SEEK_CUR) + pos += offset; + + if (pos < 0) + pos = 0; + + return (filp->f_pos = pos); + } else + return -ENOENT; + +} + +// Context : User +// Parameter : +// buf : buffer to read into +// len : number of bytes to read +// filp : file pointer +// Return : +// actually read number. 0 = EOF, negative = error +int klib_fread(char *buf, int len, struct file *filp) +{ + int readlen; + + mm_segment_t oldfs; + + if (filp == NULL) + return -ENOENT; + + if (filp->f_op->read == NULL) + return -ENOSYS; + + if (((filp->f_flags & O_ACCMODE) & O_RDONLY) != 0) + return -EACCES; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + + readlen = filp->f_op->read(filp, buf, len, &filp->f_pos); + + set_fs(oldfs); + + return readlen; +} + +// Context : User +// Parameter : +// filp : file pointer +// Return : +// read character, EOF if end of file + +int klib_fgetc(struct file *filp) +{ + + int len; + unsigned char buf[4]; + + len = klib_fread((char *)buf, 1, filp); + + if (len > 0) + return buf[0]; + else if (len == 0) + return EOF; + else + return len; +} + +// Context : User +// Parameter : +// str : string +// size : size of str buffer +// filp : file pointer +// Return : +// read string. NULL if end of file +// Comment : +// Always append trailing null character + +char *klib_fgets(char *str, int size, struct file *filp) +{ + + char *cp; + int len, readlen; + mm_segment_t oldfs; + + if (filp && filp->f_op->read + && ((filp->f_flags & O_ACCMODE) & O_WRONLY) == 0) { + oldfs = get_fs(); + set_fs(KERNEL_DS); + + for (cp = str, len = -1, readlen = 0; readlen < size - 1; + ++cp, ++readlen) { + + if ((len = + filp->f_op->read(filp, cp, 1, &filp->f_pos)) <= 0) + break; + + if (*cp == '\n') { + ++cp; + ++readlen; + break; + + } + } + + *cp = 0; + set_fs(oldfs); + + return (len < 0 || readlen == 0) ? NULL : str; + } else + return NULL; + +} + +// Context : User +// Parameter : +// buf : buffer containing data to write +// len : number of bytes to write +// filp : file pointer +// Return : +// actually written number. 0 = retry, negative = error + +int klib_fwrite(char *buf, int len, struct file *filp) +{ + int writelen; + mm_segment_t oldfs; + + if (filp == NULL) + return -ENOENT; + + if (filp->f_op->write == NULL) + return -ENOSYS; + + if (((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) == 0) + return -EACCES; + + oldfs = get_fs(); + set_fs(KERNEL_DS); + writelen = filp->f_op->write(filp, buf, len, &filp->f_pos); + set_fs(oldfs); + + return writelen; +} + +// Context : User +// Parameter : +// filp : file pointer +// Return : +// written character, EOF if error +int klib_fputc(int ch, struct file *filp) +{ + int len; + unsigned char buf[4]; + + buf[0] = (unsigned char)ch; + len = klib_fwrite(buf, 1, filp); + + if (len > 0) + return buf[0]; + else + return EOF; +} + +// Context : User +// Parameter : +// str : string +// filp : file pointer +// Return : +// count of written characters. 0 = retry, negative = error +int klib_fputs(char *str, struct file *filp) +{ + return klib_fwrite(str, strlen(str), filp); +} + +// Context : User +// Parameter : +// filp : file pointer +// fmt : printf() style formatting string +// Return : +// same as klib_fputs() +int klib_fprintf(struct file *filp, const char *fmt, ...) +{ + static char s_buf[1024]; + + va_list args; + va_start(args, fmt); + vsprintf(s_buf, fmt, args); + va_end(args); + return klib_fputs(s_buf, filp); +} + +EXPORT_SYMBOL(klib_fwrite); +EXPORT_SYMBOL(klib_fprintf); +EXPORT_SYMBOL(klib_fclose); +EXPORT_SYMBOL(klib_fopen); --- linux-2.6.12-rc3-kdb/kernel/zlogger.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.12-rc3-kdb-zlog/kernel/zlogger.c 2005-05-07 18:08:49.000000000 -0400 @@ -0,0 +1,134 @@ +/* + * zlogger.c: write the contents in the log buffer to user space file + * what it does it quite similar to klogd + * call k_start_thread on init_module + * call k_kill_thread on cleanup_module + * + * Copyright (C) 2003 - Haoqiang Zheng + * + * This file is released under the GPL. + */ +#include +#include +#include +#include +#include +#include + +static pid_t ksmart_pid = -1; +static int thread_exit = 0; + +/*change the log file to whatever you like */ +static char *log_file_name = "/tmp/zlog"; + +extern int myprintk_cleanbuf(struct file *filep); +extern int get_lost_log(void); +extern void ztrace_enable(void); /*enable ztrace */ +extern void ztrace_disable(void); /*disable ztrace */ + +/* +Design: + open the file + check if there's anything to read, if not sleep + otherwise, consume and save to the file + on exit, close the file +Task: + */ +static int k_smart_logd(void *nothing) +{ + struct file *filep; + wait_queue_head_t wait; + int len; + int interval = HZ; + + init_waitqueue_head(&wait); + + daemonize("ksmartlogd"); + set_user_nice(current, -15); + + if ((filep = + klib_fopen(log_file_name, O_CREAT | O_WRONLY | O_TRUNC, + 0x777)) == NULL) { + printk("can't open log file: %s\n", log_file_name); + goto out; + } + + for (;;) { + //sleep for sometime before next try + interruptible_sleep_on_timeout(&wait, interval); + len = myprintk_cleanbuf(filep); + + if (thread_exit) { + len = myprintk_cleanbuf(filep); + break; + } + } + klib_fclose(filep); + out: + ksmart_pid = -1; + thread_exit = 2; + printk("ksmartlogd exit, lost= %d\n", get_lost_log()); + return 0; +} + +void k_start_thread(void) +{ + ksmart_pid = kernel_thread(k_smart_logd, 0, CLONE_KERNEL); + if (ksmart_pid < 0) { + printk("ksmartlogd for failed\n"); + } +} + +void k_kill_thread(void) +{ + wait_queue_head_t wait; + init_waitqueue_head(&wait); + + printk("killing process %d\n", ksmart_pid); + if (ksmart_pid > 0) { + thread_exit = 1; + while (thread_exit != 2) { + interruptible_sleep_on_timeout(&wait, HZ); + } + } +} + +/***************************************************/ +/* Loadable Module Support */ +/***************************************************/ +MODULE_AUTHOR("Haoqiang Zheng "); +MODULE_DESCRIPTION("Module used to do some linux kernel tracing"); +MODULE_LICENSE("GPL"); + +static char *MODULE_NAME = "zlog"; + +int zlog_init_module(void) +{ + wait_queue_head_t wait; + + k_start_thread(); + + init_waitqueue_head(&wait); + //make sure the ksmart logd already blocks + interruptible_sleep_on_timeout(&wait, HZ); + + read_lock_irq(&tasklist_lock); + ztrace_enable(); + read_unlock_irq(&tasklist_lock); + + return 0; +} + +void zlog_cleanup_module(void) +{ + read_lock_irq(&tasklist_lock); //make sure no one is writing a tasklist + ztrace_disable(); + read_unlock_irq(&tasklist_lock); + + k_kill_thread(); + + printk("module %s removed successfully\n", MODULE_NAME); +} + +module_init(zlog_init_module); +module_exit(zlog_cleanup_module); --- linux-2.6.12-rc3-kdb/kernel/zlog.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.12-rc3-kdb-zlog/kernel/zlog.c 2005-05-07 21:12:18.000000000 -0400 @@ -0,0 +1,259 @@ +/* + * zlog.c: provides atomic write access to the kernel log buffer + * no synchronization need to read the buffer + * + * + * Copyright (C) 2005 - Haoqiang Zheng + * haoqiang@gmail.com + * + * This file is released under the GPL. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * supports dynamic enable/disable the logging + */ +atomic_t enable_zlog = ATOMIC_INIT(0); +void ztrace_enable(void) +{ + atomic_set(&enable_zlog,1); +} + +void ztrace_disable(void) +{ + atomic_set(&enable_zlog,0); +} + +#define MYPRINTK_SIZE (1024*1024*4) +static char buf[MYPRINTK_SIZE]; + +/* + * a sentence is from start_log to end_log + * a sentence can't be longer than ZLOG_MAX_SENTENCE + * you can't write more than ZLOG_MAX_UNIT bytes in a call to zlog_print + */ +#define ZLOG_MAX_SENTENCE (2*1024) +#define ZLOG_MAX_UNIT 128 +#define START_WRITE_LIMIT (MYPRINTK_SIZE - 1 - ZLOG_MAX_UNIT) + +/* + * start_pos: the start pos of the data + * modified by the buffer reader: clean_buffer + * end_pos: end pos of the data, + * controled by zlog_print, zlog_write + * session_start: the start of the current sentence + * advance on end_log + */ +static int start_pos = 0; +static int end_pos = 0; +static int session_start = 0; + +/*increase when ever log */ +static int next_slot = 0; +/*the logs lost because of not enough buffer*/ +static int lost_log = 0; + +static spinlock_t myprintk_lock = SPIN_LOCK_UNLOCKED; + +static inline char *get_buf_start(int slot_id) +{ + if (slot_id < 0) + return NULL; //do nothing if no slot + + //fill the end of the buffer if the buffer is close to be full + if (end_pos > START_WRITE_LIMIT) { + memset(&buf[end_pos], ' ', MYPRINTK_SIZE - end_pos); + end_pos = 0; + } + return buf + end_pos; + +} + +static inline int un_printed_size(void) +{ + int result; + result = (session_start + MYPRINTK_SIZE - start_pos); + result %= (MYPRINTK_SIZE); + return result; +} + +/* + * the empty space is from session_start .. start_pos + */ +static inline int enough_space(void) +{ + int result; + result = MYPRINTK_SIZE - 1 - un_printed_size(); + return (result > ZLOG_MAX_SENTENCE); +} + +/*************************************************************/ +/* public functions */ +/*************************************************************/ +/* + * if the buffer is full (empty size < ZLOG_MAX_LEN) fail + * return the slot id and hold the lock if succeed + * otherwise return -1 + */ +int start_sentence(unsigned long *flags) +{ + int slot_id = -1; + + if (! ztrace_enabled()) + return slot_id; + + spin_lock_irqsave(&myprintk_lock, *flags); + if (enough_space()) { + slot_id = next_slot; + next_slot++; + } else { + lost_log++; + spin_unlock_irqrestore(&myprintk_lock, *flags); + } + return slot_id; +} + +void end_sentence(int slot_id,unsigned long* flags) +{ + if (slot_id < 0) + return; + + session_start = end_pos; + spin_unlock_irqrestore(&myprintk_lock, *flags); //ok, other guys can go +} + +/* + * it's very slow, use with causion + */ +void zlog_print(int slot_id, const char *fmt, ...) +{ + va_list args; + char *start; + + if (slot_id < 0) + return; //do nothing if no slot + + start = get_buf_start(slot_id); + + if (start) { + va_start(args, fmt); + end_pos += vsprintf(start, fmt, args); + va_end(args); + } +} + +/* + * write the obj to the buffer. + */ +void zlog_write(int slot_id, void *obj, int size) +{ + int remaining; + + if (slot_id < 0) + return; //do nothing if no slot + + remaining = (MYPRINTK_SIZE - end_pos); + if (unlikely(remaining <= size)) { + int left = size - remaining; + //divide the buffer to two trunks + memcpy(buf + end_pos, obj, remaining); + if (left) { + memcpy(buf, obj + remaining, left); + } + end_pos = left; + } else { + memcpy(buf + end_pos, obj, size); + end_pos += size; + } +} + +int ztrace_printf(const char *fmt, ...) +{ + va_list args; + char *start; + int session_id; + unsigned long flags; + + session_id = start_sentence(&flags); + if (session_id < 0) + return 0; + + start = get_buf_start(session_id); + + if (start) { + va_start(args, fmt); + end_pos += vsprintf(start, fmt, args); + va_end(args); + } + + end_sentence(session_id,&flags); + return 0; +} + +void ztrace_write(void *obj, int size) +{ + int session_id; + unsigned long flags; + + session_id = start_sentence(&flags); + if (session_id < 0) + return; + zlog_write(session_id, obj, size); + end_sentence(session_id,&flags); + return; +} + +/*************************************************************/ +/* functions used by zlogger */ +/*************************************************************/ +int get_lost_log(void) +{ + return lost_log; +} + +/* + * write the data 1K by 1K to the log file + * until start_session + */ +int myprintk_cleanbuf(struct file *filep) +{ + int len; + int total = 0; + + //256k +#define FILE_BLOCK_SIZE (1024*256) + while ((len = un_printed_size()) > 0) { + if (len > FILE_BLOCK_SIZE) + len = FILE_BLOCK_SIZE; + if (start_pos + len > MYPRINTK_SIZE) { + len = MYPRINTK_SIZE - start_pos; + } + + len = klib_fwrite(buf + start_pos, len, filep); + start_pos += len; + if (start_pos == MYPRINTK_SIZE) + start_pos = 0; + total += len; + } + return total; +} + +EXPORT_SYMBOL(enable_zlog); +EXPORT_SYMBOL(ztrace_printf); +EXPORT_SYMBOL(ztrace_write); +EXPORT_SYMBOL(start_sentence); +EXPORT_SYMBOL(end_sentence); +EXPORT_SYMBOL(zlog_write); +EXPORT_SYMBOL(zlog_print); +EXPORT_SYMBOL(myprintk_cleanbuf); +EXPORT_SYMBOL(get_lost_log); +EXPORT_SYMBOL(ztrace_enable); +EXPORT_SYMBOL(ztrace_disable); --- linux-2.6.12-rc3-kdb/kernel/Makefile 2005-04-20 20:03:16.000000000 -0400 +++ linux-2.6.12-rc3-kdb-zlog/kernel/Makefile 2005-05-08 11:29:12.000000000 -0400 @@ -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 wait.o kfifo.o sys_ni.o posix-cpu-timers.o + kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o obj-$(CONFIG_FUTEX) += futex.o obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o @@ -28,6 +28,9 @@ obj-$(CONFIG_SYSFS) += ksysfs.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o +obj-y += fileop.o zlog.o +obj-$(CONFIG_ZLOG) += zlogger.o + ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is --- linux-2.6.12-rc3-kdb/init/Kconfig 2005-04-20 20:03:16.000000000 -0400 +++ linux-2.6.12-rc3-kdb-zlog/init/Kconfig 2005-05-08 11:28:01.000000000 -0400 @@ -121,6 +121,13 @@ If unsure, say Y. +config ZLOG + tristate "Support for zlog" + default m + help + enable zlog, which provides an alternative to printk + check http://swap-sched.sf.net for details + config BSD_PROCESS_ACCT bool "BSD Process Accounting" help