diff -urN linux/Documentation/Configure.help linux-2.4.0-test10/Documentation/Configure.help
--- linux/Documentation/Configure.help	Mon Oct 30 17:46:05 2000
+++ linux-2.4.0-test10/Documentation/Configure.help	Tue Nov  7 01:53:41 2000
@@ -16892,6 +16892,44 @@
   To use this option, you have to check that the "/proc file system
   support" (CONFIG_PROC_FS) is enabled, too.
 
+Kernel events tracing support
+CONFIG_TRACE
+  It is possible for the kernel to log important events to a tracing
+  driver. Doing so, enables the use of the generated traces in order
+  to reconstruct the dynamic behavior of the kernel, and hence the
+  whole system.
+
+  The tracing process contains 4 parts :
+      1) The logging of events by key parts of the kernel.
+      2) The trace driver that keeps the events in a data buffer.
+      3) A trace daemon that opens the trace driver and is notified
+         every time there is a certain quantity of data to read
+         from the trace driver (using SIG_IO).
+      4) A trace event data decoder that reads the accumulated data
+         and formats it in a human-readable format.
+
+  If you say Y or M here, the first part of the tracing process will
+  always take place. That is, critical parts of the kernel will call
+  upon the kernel tracing function. The data generated doesn't go
+  any further until a trace driver registers himself as such with the
+  kernel. Therefore, if you answer Y, then the driver will be part of
+  the kernel and the events will always proceed onto the driver and
+  if you say M, then the events will only proceed onto the driver when
+  it's module is loaded. Note that event's aren't logged in the driver
+  until the profiling daemon opens the device, configures it and
+  issues the "start" command through ioctl().
+
+  The impact of a fully functionnal system (kernel event logging +
+  driver event copying + active trace daemon) is of 2.5% for core events.
+  This means that for a task that took 100 seconds on a normal system, it
+  will take 102.5 seconds on a traced system. This is very low compared
+  to other profiling or tracing methods.
+
+  For more information on kernel tracing, the trace daemon or the event
+  decoder, please check the following address :
+       http://www.opersys.com/LTT
+
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, 
diff -urN linux/Makefile linux-2.4.0-test10/Makefile
--- linux/Makefile	Fri Oct 27 13:55:48 2000
+++ linux-2.4.0-test10/Makefile	Tue Nov  7 01:53:41 2000
@@ -177,6 +177,7 @@
 DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
 DRIVERS-$(CONFIG_ACPI_INTERPRETER) += drivers/acpi/acpi.o
 DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
+DRIVERS-$(CONFIG_TRACE) += drivers/trace/trace_driver.o
 
 DRIVERS += $(DRIVERS-y)
 
diff -urN linux/arch/i386/config.in linux-2.4.0-test10/arch/i386/config.in
--- linux/arch/i386/config.in	Mon Oct 16 15:32:35 2000
+++ linux-2.4.0-test10/arch/i386/config.in	Tue Nov  7 01:53:41 2000
@@ -357,6 +357,11 @@
 source drivers/usb/Config.in
 
 mainmenu_option next_comment
+comment 'Kernel tracing'
+tristate 'Kernel events tracing support' CONFIG_TRACE
+endmenu
+
+mainmenu_option next_comment
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
diff -urN linux/arch/i386/kernel/entry.S linux-2.4.0-test10/arch/i386/kernel/entry.S
--- linux/arch/i386/kernel/entry.S	Mon Oct 16 15:35:44 2000
+++ linux-2.4.0-test10/arch/i386/kernel/entry.S	Tue Nov  7 01:53:41 2000
@@ -200,8 +200,22 @@
 	jae badsys
 	testb $0x02,tsk_ptrace(%ebx)	# PT_TRACESYS
 	jne tracesys
+
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+	movl %esp, %eax                 # copy the stack pointer
+	pushl %eax                      # pass the stack pointer copy
+	call SYMBOL_NAME(trace_real_syscall_entry)
+	addl $4,%esp                    # return stack to state before pass
+	movl ORIG_EAX(%esp),%eax	# restore eax to it's original content
+#endif
+
 	call *SYMBOL_NAME(sys_call_table)(,%eax,4)
 	movl %eax,EAX(%esp)		# save the return value
+
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+	call SYMBOL_NAME(trace_real_syscall_exit)
+#endif
+
 ENTRY(ret_from_sys_call)
 #ifdef CONFIG_SMP
 	movl processor(%ebx),%eax
diff -urN linux/arch/i386/kernel/irq.c linux-2.4.0-test10/arch/i386/kernel/irq.c
--- linux/arch/i386/kernel/irq.c	Fri Aug  4 19:15:38 2000
+++ linux-2.4.0-test10/arch/i386/kernel/irq.c	Tue Nov  7 01:53:41 2000
@@ -33,6 +33,8 @@
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
 
+#include <linux/trace.h>
+
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/system.h>
@@ -429,6 +431,8 @@
 
 	irq_enter(cpu, irq);
 
+	TRACE_IRQ_ENTRY(irq, !(user_mode(regs)));
+
 	status = 1;	/* Force the "do bottom halves" bit */
 
 	if (!(action->flags & SA_INTERRUPT))
@@ -444,6 +448,8 @@
 	__cli();
 
 	irq_exit(cpu, irq);
+
+	TRACE_EVENT(TRACE_EV_IRQ_EXIT, NULL);
 
 	return status;
 }
diff -urN linux/arch/i386/kernel/process.c linux-2.4.0-test10/arch/i386/kernel/process.c
--- linux/arch/i386/kernel/process.c	Sun Oct  1 23:35:15 2000
+++ linux-2.4.0-test10/arch/i386/kernel/process.c	Tue Nov  7 01:53:41 2000
@@ -33,6 +33,8 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -452,6 +454,10 @@
 		 "r" (arg), "r" (fn),
 		 "b" (flags | CLONE_VM)
 		: "memory");
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+	if (retval > 0)
+	  TRACE_PROCESS(TRACE_EV_PROCESS_KTHREAD, retval, (int) fn);
+#endif
 	return retval;
 }
 
diff -urN linux/arch/i386/kernel/sys_i386.c linux-2.4.0-test10/arch/i386/kernel/sys_i386.c
--- linux/arch/i386/kernel/sys_i386.c	Wed Jul  5 14:31:00 2000
+++ linux-2.4.0-test10/arch/i386/kernel/sys_i386.c	Tue Nov  7 01:53:41 2000
@@ -19,6 +19,8 @@
 #include <linux/file.h>
 #include <linux/utsname.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 
@@ -136,6 +138,8 @@
 
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
+
+	TRACE_IPC(TRACE_EV_IPC_CALL, call, first);
 
 	switch (call) {
 	case SEMOP:
diff -urN linux/arch/i386/kernel/traps.c linux-2.4.0-test10/arch/i386/kernel/traps.c
--- linux/arch/i386/kernel/traps.c	Mon Oct 23 18:54:05 2000
+++ linux-2.4.0-test10/arch/i386/kernel/traps.c	Sat Mar 24 23:57:41 2001
@@ -24,6 +24,8 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 
+#include <linux/trace.h>
+
 #ifdef CONFIG_MCA
 #include <linux/mca.h>
 #include <asm/processor.h>
@@ -203,6 +205,82 @@
 	printk("\n");
 }	
 
+/* Trace related code */
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+asmlinkage void trace_real_syscall_entry(struct pt_regs * regs)
+{
+        int                 use_depth;
+	int                 use_bounds;
+	int                 depth = 0;
+        int                 seek_depth;
+        unsigned long       lower_bound;
+        unsigned long       upper_bound;
+	unsigned long       addr;
+	unsigned long*      stack;
+	trace_syscall_entry trace_syscall_event;
+
+        /* Set the syscall ID */
+        trace_syscall_event.syscall_id = (uint8_t) regs->orig_eax;
+
+	/* Set the address in any case */
+	trace_syscall_event.address  = regs->eip;
+
+	/* Are we in the kernel (This is a kernel thread)? */
+	if(!(regs->xcs & 3))
+	  /* Don't go digining anywhere */
+	  goto trace_syscall_end;
+
+	/* Get the trace configuration */
+	if(trace_get_config(&use_depth,
+			    &use_bounds,
+			    &seek_depth,
+			    (void*)&lower_bound,
+			    (void*)&upper_bound) < 0)
+	  goto trace_syscall_end;
+
+	/* Do we have to search for an eip address range */
+	if((use_depth == 1) || (use_bounds == 1))
+	  {
+	  /* Start at the top of the stack (bottom address since stacks grow downward) */
+	  stack = (unsigned long*) regs->esp;
+
+	  /* Keep on going until we reach the end of the process' stack limit (wherever it may be) */
+	  while(!get_user(addr, stack))
+	    {
+	    /* Does this LOOK LIKE an address in the program */
+	    if((addr > current->mm->start_code)
+             &&(addr < current->mm->end_code))
+	      {
+	      /* Does this address fit the description */
+	      if(((use_depth == 1) && (depth == seek_depth))
+               ||((use_bounds == 1) && (addr > lower_bound) && (addr < upper_bound)))
+		{
+		/* Set the address */
+		trace_syscall_event.address = addr;
+
+		/* We're done */
+		goto trace_syscall_end;
+		}
+	      else
+		/* We're one depth more */
+		depth++;
+	      }
+	    /* Go on to the next address */
+	    stack++;
+	    }
+	  }
+
+trace_syscall_end:
+	/* Trace the event */
+	trace_event(TRACE_EV_SYSCALL_ENTRY, &trace_syscall_event);
+}
+
+asmlinkage void trace_real_syscall_exit(void)
+{
+        trace_event(TRACE_EV_SYSCALL_EXIT, NULL);
+}
+#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */
+
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -239,6 +317,8 @@
 	if (!(regs->xcs & 3))
 		goto kernel_trap;
 
+        TRACE_TRAP_ENTRY(trapnr, regs->eip);
+
 	trap_signal: {
 		struct task_struct *tsk = current;
 		tsk->thread.error_code = error_code;
@@ -247,6 +327,7 @@
 			force_sig_info(signr, info, tsk);
 		else
 			force_sig(signr, tsk);
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
 
@@ -256,12 +337,14 @@
 			regs->eip = fixup;
 		else	
 			die(str, regs, error_code);
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
 
 	vm86_trap: {
 		int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr);
 		if (ret) goto trap_signal;
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
 }
@@ -324,11 +407,15 @@
 
 	current->thread.error_code = error_code;
 	current->thread.trap_no = 13;
+        TRACE_TRAP_ENTRY(13, regs->eip);
 	force_sig(SIGSEGV, current);
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 	return;
 
 gp_in_vm86:
+        TRACE_TRAP_ENTRY(13, regs->eip);
 	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 	return;
 
 gp_in_kernel:
@@ -459,6 +546,10 @@
 {
 	unsigned char reason = inb(0x61);
 
+#ifndef CONFIG_SMP /* On an SMP machine NMIs are used to implement a watchdog and will hang
+                      the machine if traced. */
+        TRACE_TRAP_ENTRY(2, regs->eip);
+#endif
 
 	++nmi_count(smp_processor_id());
 	if (!(reason & 0xc0)) {
@@ -469,14 +560,17 @@
 		 */
 		if (nmi_watchdog) {
 			nmi_watchdog_tick(regs);
+			TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 			return;
 		} else
 			unknown_nmi_error(reason, regs);
 #else
 		unknown_nmi_error(reason, regs);
 #endif
+	        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
+
 	if (reason & 0x80)
 		mem_parity_error(reason, regs);
 	if (reason & 0x40)
@@ -489,6 +583,8 @@
 	inb(0x71);		/* dummy */
 	outb(0x0f, 0x70);
 	inb(0x71);		/* dummy */
+
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
 
 /*
@@ -560,7 +656,9 @@
 	 */
 	info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : 
 	                                        (void *)regs->eip;
+        TRACE_TRAP_ENTRY(1, regs->eip);
 	force_sig_info(SIGTRAP, &info, tsk);
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 
 	/* Disable additional traps. They'll be re-enabled when
 	 * the signal is delivered.
@@ -572,7 +670,9 @@
 	return;
 
 debug_vm86:
+        TRACE_TRAP_ENTRY(1, regs->eip);
 	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 	return;
 
 clear_TF:
@@ -721,10 +821,12 @@
 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
 					  long error_code)
 {
+        TRACE_TRAP_ENTRY(16, regs->eip);
 #if 0
 	/* No need to warn about this any longer. */
 	printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
 #endif
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);	
 }
 
 /*
@@ -752,8 +854,10 @@
 {
 	printk("math-emulation not enabled and no coprocessor found.\n");
 	printk("killing %s.\n",current->comm);
+        TRACE_TRAP_ENTRY(7, 0);
 	force_sig(SIGFPE,current);
 	schedule();
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
 
 #endif /* CONFIG_MATH_EMULATION */
diff -urN linux/arch/i386/mm/fault.c linux-2.4.0-test10/arch/i386/mm/fault.c
--- linux/arch/i386/mm/fault.c	Mon Oct 16 15:26:52 2000
+++ linux-2.4.0-test10/arch/i386/mm/fault.c	Tue Nov  7 01:53:41 2000
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
@@ -121,6 +123,8 @@
 	mm = tsk->mm;
 	info.si_code = SEGV_MAPERR;
 
+	TRACE_TRAP_ENTRY(14, regs->eip);
+
 	/*
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
@@ -202,6 +206,7 @@
 			tsk->thread.screen_bitmap |= 1 << bit;
 	}
 	up(&mm->mmap_sem);
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 	return;
 
 /*
@@ -222,6 +227,7 @@
 		/* info.si_code has been set above */
 		info.si_addr = (void *)address;
 		force_sig_info(SIGSEGV, &info, tsk);
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
 
@@ -235,6 +241,7 @@
 
 		if (nr == 6) {
 			do_invalid_op(regs, 0);
+			TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 			return;
 		}
 	}
@@ -243,6 +250,7 @@
 	/* Are we prepared to handle this kernel fault?  */
 	if ((fixup = search_exception_table(regs->eip)) != 0) {
 		regs->eip = fixup;
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
 
@@ -300,6 +308,7 @@
 	/* Kernel mode? Handle exceptions or die */
 	if (!(error_code & 4))
 		goto no_context;
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 	return;
 
 vmalloc_fault:
@@ -319,6 +328,7 @@
 			if (!pgd_present(*pgd_k))
 				goto bad_area_nosemaphore;
 			set_pgd(pgd, *pgd_k);
+			TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 			return;
 		}
 
@@ -328,6 +338,9 @@
 		if (pmd_present(*pmd) || !pmd_present(*pmd_k))
 			goto bad_area_nosemaphore;
 		set_pmd(pmd, *pmd_k);
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
+
+        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
diff -urN linux/arch/ppc/config.in linux-2.4.0-test10/arch/ppc/config.in
--- linux/arch/ppc/config.in	Mon Oct 16 15:51:16 2000
+++ linux-2.4.0-test10/arch/ppc/config.in	Tue Nov  7 05:32:58 2000
@@ -317,6 +317,11 @@
 source drivers/usb/Config.in
 
 mainmenu_option next_comment
+comment 'Kernel tracing'
+tristate 'Kernel events tracing support' CONFIG_TRACE
+endmenu
+
+mainmenu_option next_comment
 comment 'Kernel hacking'
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
diff -urN linux/arch/ppc/kernel/entry.S linux-2.4.0-test10/arch/ppc/kernel/entry.S
--- linux/arch/ppc/kernel/entry.S	Sun Sep 17 12:48:06 2000
+++ linux-2.4.0-test10/arch/ppc/kernel/entry.S	Tue Nov  7 05:15:53 2000
@@ -41,6 +41,32 @@
 	.long	-1
 #endif
 
+/* LTT stuff */
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+#define TRACE_REAL_ASM_SYSCALL_ENTRY	\
+	addi	r3,r1,STACK_FRAME_OVERHEAD;  	/* Put pointer to registers into r3 */	\
+	mflr	r29;				/* Save LR */ \
+	bl	trace_real_syscall_entry;	/* Call real trace function */ \
+	mtlr	r29;				/* Restore LR */ \
+	lwz	r0,GPR0(r1);			/* Restore original registers */ \
+	lwz	r3,GPR3(r1);	\
+	lwz	r4,GPR4(r1);	\
+	lwz	r5,GPR5(r1);	\
+	lwz	r6,GPR6(r1);	\
+	lwz	r7,GPR7(r1);	\
+	lwz	r8,GPR8(r1);
+#define TRACE_REAL_ASM_SYSCALL_EXIT \
+	bl	trace_real_syscall_exit;	/* Call real trace function */ \
+	lwz	r0,GPR0(r1);			/* Restore original registers */ \
+	lwz	r3,RESULT(r1); \
+	lwz	r4,GPR4(r1); \
+	lwz	r5,GPR5(r1); \
+	lwz	r6,GPR6(r1); \
+	lwz	r7,GPR7(r1); \
+	lwz	r8,GPR8(r1); \
+	addi	r9,r1,STACK_FRAME_OVERHEAD;
+#endif
+	
 /*
  * Handle a system call.
  */
@@ -98,11 +124,17 @@
 	cmpi	0,r10,0
 	beq-	66f
 	mtlr	r10
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+	TRACE_REAL_ASM_SYSCALL_ENTRY ;
+#endif
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 	blrl			/* Call handler */
 	.globl	ret_from_syscall_1
 ret_from_syscall_1:
 20:	stw	r3,RESULT(r1)	/* Save result */
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+	TRACE_REAL_ASM_SYSCALL_EXIT ; 
+#endif
 #ifdef SHOW_SYSCALLS
 #ifdef SHOW_SYSCALLS_TASK
 	cmp	0,r2,r31
@@ -160,11 +192,17 @@
 	cmpi	0,r10,0
 	beq-	66f
 	mtlr	r10
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+	TRACE_REAL_ASM_SYSCALL_ENTRY ;
+#endif
 	addi	r9,r1,STACK_FRAME_OVERHEAD
 	blrl			/* Call handler */
 	.globl	ret_from_syscall_2
 ret_from_syscall_2:
 	stw	r3,RESULT(r1)	/* Save result */	
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+	TRACE_REAL_ASM_SYSCALL_EXIT ; 
+#endif
 	stw	r3,GPR0(r1)	/* temporary gross hack to make strace work */
 	li	r10,-_LAST_ERRNO
 	cmpl	0,r3,r10
diff -urN linux/arch/ppc/kernel/irq.c linux-2.4.0-test10/arch/ppc/kernel/irq.c
--- linux/arch/ppc/kernel/irq.c	Sun Sep 17 12:48:06 2000
+++ linux-2.4.0-test10/arch/ppc/kernel/irq.c	Tue Nov  7 05:18:48 2000
@@ -47,6 +47,8 @@
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/hydra.h>
@@ -276,6 +278,8 @@
 	struct irqaction *action;
 	int cpu = smp_processor_id();
 
+	TRACE_IRQ_ENTRY(irq, !(user_mode(regs)));
+
 	mask_and_ack_irq(irq);
 	status = 0;
 	action = irq_desc[irq].action;
@@ -302,6 +306,8 @@
 		if (irq_desc[irq].handler->end)
 			irq_desc[irq].handler->end(irq);
 	}
+	
+	TRACE_EVENT(TRACE_EV_IRQ_EXIT, NULL);
 }
 
 int do_IRQ(struct pt_regs *regs, int isfake)
diff -urN linux/arch/ppc/kernel/misc.S linux-2.4.0-test10/arch/ppc/kernel/misc.S
--- linux/arch/ppc/kernel/misc.S	Sun Sep 17 12:48:07 2000
+++ linux-2.4.0-test10/arch/ppc/kernel/misc.S	Tue Nov  7 05:16:54 2000
@@ -999,7 +999,11 @@
  * Create a kernel thread
  *   kernel_thread(fn, arg, flags)
  */
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+_GLOBAL(original_kernel_thread)
+#else
 _GLOBAL(kernel_thread)
+#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */
 	mr	r6,r3		/* function */
 	ori	r3,r5,CLONE_VM	/* flags */
 	li	r0,__NR_clone
diff -urN linux/arch/ppc/kernel/process.c linux-2.4.0-test10/arch/ppc/kernel/process.c
--- linux/arch/ppc/kernel/process.c	Sun Sep 17 12:48:07 2000
+++ linux-2.4.0-test10/arch/ppc/kernel/process.c	Tue Nov  7 05:19:53 2000
@@ -34,6 +34,8 @@
 #include <linux/elf.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -287,6 +289,19 @@
 	}
 out:
 }
+
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+long original_kernel_thread(int (*fn) (void *), void* arg, unsigned long flags);
+long kernel_thread(int (*fn) (void *), void* arg, unsigned long flags)
+{
+        long   retval;
+
+	retval = original_kernel_thread(fn, arg, flags);
+	if (retval > 0)
+	        TRACE_PROCESS(TRACE_EV_PROCESS_KTHREAD, retval, (int) fn);
+	return retval;
+}
+#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */
 
 void exit_thread(void)
 {
diff -urN linux/arch/ppc/kernel/syscalls.c linux-2.4.0-test10/arch/ppc/kernel/syscalls.c
--- linux/arch/ppc/kernel/syscalls.c	Sun Sep 17 12:48:07 2000
+++ linux-2.4.0-test10/arch/ppc/kernel/syscalls.c	Tue Nov  7 05:20:56 2000
@@ -36,6 +36,8 @@
 #include <linux/utsname.h>
 #include <linux/file.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 #include <asm/semaphore.h>
@@ -81,6 +83,8 @@
 
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
+
+	TRACE_IPC(TRACE_EV_IPC_CALL, call, first);
 
 	ret = -EINVAL;
 	switch (call) {
diff -urN linux/arch/ppc/kernel/time.c linux-2.4.0-test10/arch/ppc/kernel/time.c
--- linux/arch/ppc/kernel/time.c	Sun Sep 17 12:48:07 2000
+++ linux-2.4.0-test10/arch/ppc/kernel/time.c	Tue Nov  7 05:22:04 2000
@@ -57,6 +57,8 @@
 #include <linux/time.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -108,6 +110,8 @@
 	unsigned long cpu = smp_processor_id();
 	unsigned jiffy_stamp = last_jiffy_stamp(cpu);
 
+	TRACE_TRAP_ENTRY(regs->trap, instruction_pointer(regs));
+
 	hardirq_enter(cpu);
 	
 	do { 
@@ -157,6 +161,9 @@
 		ppc_md.heartbeat();
 	
 	hardirq_exit(cpu);
+
+	TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
+
 	return 1; /* lets ret_from_int know we can do checks */
 }
 
diff -urN linux/arch/ppc/kernel/traps.c linux-2.4.0-test10/arch/ppc/kernel/traps.c
--- linux/arch/ppc/kernel/traps.c	Sun Sep 17 12:48:07 2000
+++ linux-2.4.0-test10/arch/ppc/kernel/traps.c	Tue Nov  7 05:25:23 2000
@@ -30,6 +30,8 @@
 #include <linux/config.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -81,7 +83,9 @@
 		print_backtrace((unsigned long *)regs->gpr[1]);
 		panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
 	}
+	TRACE_TRAP_ENTRY(regs->trap, instruction_pointer(regs));
 	force_sig(signr, current);
+	TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
 
 void
@@ -320,6 +324,89 @@
 	print_backtrace((unsigned long *)regs->gpr[1]);
 	panic("kernel stack overflow");
 }
+
+/* Trace related code */
+#if (CONFIG_TRACE || CONFIG_TRACE_MODULE)
+asmlinkage void trace_real_syscall_entry(struct pt_regs * regs)
+{
+        int                 use_depth;
+	int                 use_bounds;
+	int                 depth = 0;
+        int                 seek_depth;
+        unsigned long       lower_bound;
+        unsigned long       upper_bound;
+	unsigned long       addr;
+	unsigned long*      stack;
+	trace_syscall_entry trace_syscall_event;
+
+        /* Set the syscall ID */
+	trace_syscall_event.syscall_id = (uint8_t) regs->gpr[0];
+
+	/* Set the address in any case */
+	trace_syscall_event.address  = instruction_pointer(regs);
+
+	/* Are we in the kernel (This is a kernel thread)? */
+	if(!user_mode(regs))
+	  /* Don't go digining anywhere */
+	  goto trace_syscall_end;
+
+	/* Get the trace configuration */
+	if(trace_get_config(&use_depth,
+			    &use_bounds,
+			    &seek_depth,
+			    (void*)&lower_bound,
+			    (void*)&upper_bound) < 0)
+	  goto trace_syscall_end;
+
+	/* Do we have to search for an eip address range */
+	if((use_depth == 1) || (use_bounds == 1))
+	  {
+	  /* Start at the top of the stack (bottom address since stacks grow downward) */
+	  stack = (unsigned long*) regs->gpr[1];
+
+	  /* Skip over first stack frame as the return address isn't valid */
+	  if(get_user(addr, stack))
+	    goto trace_syscall_end;
+	  stack = (unsigned long*) addr;
+
+	  /* Keep on going until we reach the end of the process' stack limit (wherever it may be) */
+	  while(!get_user(addr, stack + 1)) /* "stack + 1", since this is where the IP is */
+	    {
+	    /* Does this LOOK LIKE an address in the program */
+	    if((addr > current->mm->start_code)
+             &&(addr < current->mm->end_code))
+	      {
+	      /* Does this address fit the description */
+	      if(((use_depth == 1) && (depth == seek_depth))
+               ||((use_bounds == 1) && (addr > lower_bound) && (addr < upper_bound)))
+		{
+		/* Set the address */
+		trace_syscall_event.address = addr;
+
+		/* We're done */
+		goto trace_syscall_end;
+		}
+	      else
+		/* We're one depth more */
+		depth++;
+	      }
+	    /* Go on to the next address */
+	    if(get_user(addr, stack))
+	      goto trace_syscall_end;
+	    stack = (unsigned long*) addr;
+	    }
+	  }
+
+trace_syscall_end:
+	/* Trace the event */
+	trace_event(TRACE_EV_SYSCALL_ENTRY, &trace_syscall_event);
+}
+
+asmlinkage void trace_real_syscall_exit(void)
+{
+        trace_event(TRACE_EV_SYSCALL_EXIT, NULL);
+}
+#endif /* (CONFIG_TRACE || CONFIG_TRACE_MODULE) */
 
 void
 trace_syscall(struct pt_regs *regs)
diff -urN linux/arch/ppc/mm/fault.c linux-2.4.0-test10/arch/ppc/mm/fault.c
--- linux/arch/ppc/mm/fault.c	Sun Sep 17 12:48:07 2000
+++ linux-2.4.0-test10/arch/ppc/mm/fault.c	Tue Nov  7 05:10:14 2000
@@ -27,6 +27,8 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 
+#include <linux/trace.h>
+
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
@@ -81,22 +83,28 @@
 		is_write = error_code & 0x02000000;
 #endif /* CONFIG_4xx */
 
+	TRACE_TRAP_ENTRY(regs->trap, instruction_pointer(regs));
+
 #if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
 	if (debugger_fault_handler && regs->trap == 0x300) {
 		debugger_fault_handler(regs);
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
 #if !defined(CONFIG_4xx)
 	if (error_code & 0x00400000) {
 		/* DABR match */
-		if (debugger_dabr_match(regs))
+	        if (debugger_dabr_match(regs)){
+		        TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 			return;
+		}
 	}
 #endif /* !CONFIG_4xx */
 #endif /* CONFIG_XMON || CONFIG_KGDB */
 
 	if (in_interrupt() || mm == NULL) {
 		bad_page_fault(regs, address);
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
 	down(&mm->mmap_sem);
@@ -166,6 +174,7 @@
 	 * -- Cort
 	 */
 	pte_misses++;
+	TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 	return;
 
 bad_area:
@@ -179,10 +188,12 @@
 		info.si_code = code;
 		info.si_addr = (void *) address;
 		force_sig_info(SIGSEGV, &info, current);
+		TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 		return;
 	}
 
 	bad_page_fault(regs, address);
+	TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 	return;
 
 /*
@@ -195,6 +206,7 @@
 	if (user_mode(regs))
 		do_exit(SIGKILL);
 	bad_page_fault(regs, address);
+	TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 	return;
 
 do_sigbus:
@@ -206,6 +218,7 @@
 	force_sig_info (SIGBUS, &info, current);
 	if (!user_mode(regs))
 		bad_page_fault(regs, address);
+	TRACE_EVENT(TRACE_EV_TRAP_EXIT, NULL);
 }
 
 /*
diff -urN linux/drivers/Makefile linux-2.4.0-test10/drivers/Makefile
--- linux/drivers/Makefile	Mon Oct  9 17:40:17 2000
+++ linux-2.4.0-test10/drivers/Makefile	Tue Nov  7 01:53:41 2000
@@ -37,6 +37,7 @@
 subdir-$(CONFIG_ISDN)		+= isdn
 subdir-$(CONFIG_ATM)		+= atm
 subdir-$(CONFIG_FC4)		+= fc4
+subdir-$(CONFIG_TRACE)		+= trace
 
 # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set  -- ch
 subdir-$(CONFIG_HAMRADIO)	+= net/hamradio
diff -urN linux/drivers/input/keybdev.c linux-2.4.0-test10/drivers/input/keybdev.c
--- linux/drivers/input/keybdev.c	Thu Jul 27 21:36:54 2000
+++ linux-2.4.0-test10/drivers/input/keybdev.c	Thu Nov 16 00:55:46 2000
@@ -90,7 +90,7 @@
 	return 0;
 }
 
-#elif defined(CONFIG_ADB_KEYBOARD)
+#elif defined(CONFIG_ADB_KEYBOARD)  || defined(CONFIG_MAC_HID)
 
 static unsigned char mac_keycodes[128] =
 	{ 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
@@ -129,9 +129,19 @@
 	}
 }
 
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+extern int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down);
+#endif
+
 void keybdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int down)
 {
 	if (type != EV_KEY) return;
+
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+	/* There should be an if() here to determine whether emulate_raw() is to be called or not.
+	 If the key is caught, emulate_raw() should not be called. K.Y. */
+	mac_hid_mouse_emulate_buttons(1, code, down);
+#endif
 
 	if (emulate_raw(code, down))
 		printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", code);
diff -urN linux/drivers/input/mousedev.c linux-2.4.0-test10/drivers/input/mousedev.c
--- linux/drivers/input/mousedev.c	Tue Aug 22 12:06:31 2000
+++ linux-2.4.0-test10/drivers/input/mousedev.c	Thu Nov 16 00:57:02 2000
@@ -79,6 +79,10 @@
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 static struct mousedev mousedev_mix;
 
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+extern int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down);
+#endif
+
 static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
 	struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
@@ -132,6 +136,9 @@
 						case BTN_MIDDLE: index = 2; break;	
 						default: return;
 					}
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+				        index = mac_hid_mouse_emulate_buttons(2, index, 0);
+#endif
 					switch (value) {
 						case 0: clear_bit(index, &list->buttons); break;
 						case 1: set_bit(index, &list->buttons); break;
diff -urN linux/drivers/trace/Makefile linux-2.4.0-test10/drivers/trace/Makefile
--- linux/drivers/trace/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.4.0-test10/drivers/trace/Makefile	Tue Nov  7 01:53:41 2000
@@ -0,0 +1,23 @@
+#
+# Makefile for the kernel tracing drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+O_TARGET := trace_driver.o
+
+# Is it loaded as a module or as part of the kernel
+ifeq ($(CONFIG_TRACE),y)
+O_OBJS := tracer.o
+else
+  ifeq ($(CONFIG_TRACE),m)
+  M_OBJS := tracer.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -urN linux/drivers/trace/tracer.c linux-2.4.0-test10/drivers/trace/tracer.c
--- linux/drivers/trace/tracer.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.0-test10/drivers/trace/tracer.c	Sun Mar 25 00:02:46 2001
@@ -0,0 +1,1182 @@
+/*****************************************************************
+ * File : tracer.c
+ * Description :
+ *    Contains the code for the kernel tracing driver (tracer
+ *    for short).
+ * Author :
+ *    Karim Yaghmour
+ * Date :
+ *    05/01/01, Modified PPC bit manipulation functions for
+ *              x86 compatibility.  (andy_lowe@mvista.com)
+ *    15/11/00, Finally fixed memory allocation and remapping
+ *              method. Now using BTTV-driver-inspired code.
+ *    13/03/00, Modified tracer so that the daemon mmaps the 
+ *              tracer's buffers in it's address space rather
+ *              than use "read".
+ *    26/01/00, Added support for standardized buffer sizes and
+ *              extensibility of events.
+ *    01/10/99, Modified tracer in order to used double-buffering.
+ *    28/09/99, Adding tracer configuration support.
+ *    09/09/99, Chaging the format of an event record in order to
+ *              reduce the size of the traces.
+ *    04/03/99, Initial typing.
+ * Note :
+ *    The sizes of the variables used to store the details of an
+ *    event are planned for a system who gets at least one clock
+ *    tick every 10milli-seconds. There has to be at least one
+ *    event every 2^32-1 microseconds, otherwise the size of the
+ *    variable holding the time doesn't work anymore.
+ *****************************************************************/
+
+/* Module and initialization stuff */
+#include <linux/module.h>
+#include <linux/init.h>
+
+/* Necessary includes */
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/trace.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+
+/* Local defintions */
+#include "tracer.h"
+
+/* Local variables */
+/*  Driver */
+static int                    sMajorNumber;          /* Major number of the tracer */
+static int                    sOpenCount;            /* Number of times device is open */
+/*  Locking */
+static int                    sTracLock;             /* Tracer lock used to lock primary buffer */
+static spinlock_t             sSpinLock;             /* Spinlock in order to lock kernel */
+/*  Daemon */
+static int                    sSignalSent;           /* A signal has been sent to the daemon */
+static struct task_struct*    sDaemonTaskStruct;     /* Task structure of the tracer daemon */
+/*  Tracer configuration */
+static int                    sTracerStarted;        /* Is the tracer started */
+static trace_event_mask       sTracedEvents;         /* Bit-field of events being traced */
+static trace_event_mask       sLogEventDetailsMask;  /* Log the details of the events mask */
+static int                    sLogCPUID;             /* Log the CPUID associated with each event */
+static int                    sUseSyscallEIPBounds;  /* Use adress bounds to fetch the EIP where call is made */
+static int                    sLowerEIPBoundSet;     /* The lower bound EIP has been set */
+static int                    sUpperEIPBoundSet;     /* The upper bound EIP has been set */
+static void*                  sLowerEIPBound;        /* The lower bound EIP */
+static void*                  sUpperEIPBound;        /* The upper bound EIP */
+static int                    sTracingPID;           /* Tracing only the events for one pid */
+static int                    sTracingPGRP;          /* Tracing only the events for one process group */
+static int                    sTracingGID;           /* Tracing only the events for one gid */
+static int                    sTracingUID;           /* Tracing only the events for one uid */
+static pid_t                  sTracedPID;            /* PID being traced */
+static pid_t                  sTracedPGRP;           /* Process group being traced */
+static gid_t                  sTracedGID;            /* GID being traced */
+static uid_t                  sTracedUID;            /* UID being traced */
+static int                    sSyscallEIPDepthSet;   /* The call depth at which to fetch EIP has been set */
+static int                    sSyscallEIPDepth;      /* The call depth at which to fetch the EIP */
+/*  Event data buffers */
+static int                    sBufReadComplete;      /* Number of buffers completely filled */
+static int                    sSizeReadIncomplete;   /* Quantity of data read from incomplete buffers */
+static int                    sEventsLost;           /* Number of events lost because of lack of buffer space */
+static uint32_t               sBufSize;              /* Buffer sizes */
+static uint32_t               sAllocSize;            /* Size of buffers allocated */
+static uint32_t               sBufferID;             /* Unique buffer ID */
+static char*                  sTracBuf = NULL;       /* Trace buffer */
+static char*                  sWritBuf = NULL;       /* Buffer used for writting */
+static char*                  sReadBuf = NULL;       /* Buffer used for reading */
+static char*                  sWritBufEnd;           /* End of write buffer */
+static char*                  sReadBufEnd;           /* End of read buffer */
+static char*                  sWritPos;              /* Current position for writting */
+static char*                  sReadLimit;            /* Limit at which read should stop */
+static char*                  sWritLimit;            /* Limit at which write should stop */
+/*  Time */
+static struct timeval         sBufferStartTime;      /* The time at which the buffer was started */
+
+/* The size of the structures used to describe the events */
+static int sEventStructSize[TRACE_EV_MAX + 1] =
+{
+  sizeof(trace_start)             /* TRACE_START */,
+  sizeof(trace_syscall_entry)     /* TRACE_SYSCALL_ENTRY */,
+  0                               /* TRACE_SYSCALL_EXIT */,
+  sizeof(trace_trap_entry)        /* TRACE_TRAP_ENTRY */,
+  0                               /* TRACE_TRAP_EXIT */,
+  sizeof(trace_irq_entry)         /* TRACE_IRQ_ENTRY */,
+  0                               /* TRACE_IRQ_EXIT */,
+  sizeof(trace_schedchange)       /* TRACE_SCHEDCHANGE */,
+  0                               /* TRACE_KERNEL_TIMER */,
+  sizeof(trace_soft_irq)          /* TRACE_SOFT_IRQ */,
+  sizeof(trace_process)           /* TRACE_PROCESS */,
+  sizeof(trace_file_system)       /* TRACE_FILE_SYSTEM */,
+  sizeof(trace_timer)             /* TRACE_TIMER */,
+  sizeof(trace_memory)            /* TRACE_MEMORY */,
+  sizeof(trace_socket)            /* TRACE_SOCKET */,
+  sizeof(trace_ipc)               /* TRACE_IPC */,
+  sizeof(trace_network)           /* TRACE_NETWORK */,
+  sizeof(trace_buffer_start)      /* TRACE_BUFFER_START */,
+  0                               /* TRACE_BUFFER_END */,
+  sizeof(trace_new_event)         /* TRACE_NEW_EVENT */,
+  sizeof(trace_custom)            /* TRACE_CUSTOM */
+};
+
+/* The file operations available for the tracer */
+static struct file_operations sTracerFileOps =
+{
+  owner:            THIS_MODULE,
+  ioctl:            tracer_ioctl,
+  mmap:             tracer_mmap,
+  open:             tracer_open,
+  release:          tracer_release,
+  fsync:            tracer_fsync,
+};
+
+/************************************************************************************************************/
+/************************************** Code inspired from BTTV driver **************************************/
+/************************************************************************************************************/
+#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE /* This inspired by rtai/shmem */
+
+/* Given PGD from the address space's page table, return the kernel
+ * virtual mapping of the physical memory mapped at ADR.
+ */
+static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
+{
+        unsigned long ret = 0UL;
+	pmd_t *pmd;
+	pte_t *ptep, pte;
+  
+	if (!pgd_none(*pgd)) {
+                pmd = pmd_offset(pgd, adr);
+                if (!pmd_none(*pmd)) {
+                        ptep = pte_offset(pmd, adr);
+                        pte = *ptep;
+                        if(pte_present(pte)) {
+				ret = (unsigned long) page_address(pte_page(pte));
+                                ret |= (adr & (PAGE_SIZE - 1));
+			}
+                }
+        }
+	return ret;
+}
+
+/* Here we want the physical address of the memory.
+ * This is used when initializing the contents of the
+ * area and marking the pages as reserved.
+ */
+static inline unsigned long kvirt_to_pa(unsigned long adr) 
+{
+        unsigned long va, kva, ret;
+
+        va = VMALLOC_VMADDR(adr);
+        kva = uvirt_to_kva(pgd_offset_k(va), va);
+	ret = __pa(kva);
+        return ret;
+}
+
+static void * rvmalloc(signed long size)
+{
+	void * mem;
+	unsigned long adr, page;
+
+	mem=vmalloc_32(size);
+	if (mem) 
+	{
+		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	        adr=(unsigned long) mem;
+		while (size > 0) 
+                {
+	                page = kvirt_to_pa(adr);
+			mem_map_reserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void * mem, signed long size)
+{
+        unsigned long adr, page;
+        
+	if (mem) 
+	{
+	        adr=(unsigned long) mem;
+		while (size > 0) 
+                {
+	                page = kvirt_to_pa(adr);
+			mem_map_unreserve(virt_to_page(__va(page)));
+			adr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+static int tracer_mmap_region(const char *adr, const char *start_pos, unsigned long size)
+{
+        unsigned long start=(unsigned long) adr;
+	unsigned long page,pos;
+
+	pos=(unsigned long) start_pos;
+	while (size > 0) 
+	{
+	        page = kvirt_to_pa(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		        return -EAGAIN;
+		start+=PAGE_SIZE;
+		pos+=PAGE_SIZE;
+		size-=PAGE_SIZE;    
+	}
+	return 0;
+}
+/************************************************************************************************************/
+/************************************************************************************************************/
+/************************************************************************************************************/
+
+/**************************************************************
+ * Macro : tracer_write_to_buffer()
+ * Description :
+ *     Writes data to the destination buffer and updates the
+ *     begining the buffer write position.
+ **************************************************************/
+#define tracer_write_to_buffer(DEST, SRC, SIZE) \
+do\
+{\
+   memcpy(DEST, SRC, SIZE);\
+   DEST += SIZE;\
+} while(0);
+
+/**************************************************************
+ * Function : trace()
+ * Description : Tracing function per se.
+ * Parameters :
+ *     pmEventID, ID of event as defined in linux/trace.h
+ *     pmEventStruct, struct describing the event
+ * Return values : 
+ *     0, if everything went OK (event got registered)
+ *     -ENODEV, no tracing daemon opened the driver.
+ *     -ENOMEM, no more memory to store events.
+ *     -EBUSY, tracer not started yet.
+ * Note :
+ *     The kernel has to be locked here because trace() could
+ *     be called from an interrupt handling routine and from 
+ *     a process service routine.
+ **************************************************************/
+int trace(uint8_t   pmEventID,
+	  void*     pmEventStruct)
+{
+  int                 lVarDataLen = 0;       /* Length of variable length data to be copied, if any */
+  void*               lVarDataBeg = NULL;    /* Begining of variable length data to be copied */
+  int                 lSendSignal = FALSE;   /* Should the daemon be summoned */
+  uint8_t             lDataSize;             /* Size of tracing data */
+  uint8_t             lCPUID;                /* CPUID of currently runing process */
+  struct siginfo      lSigInfo;              /* Signal information */
+  struct timeval      lTime;                 /* Event time */
+  unsigned long int   lFlags;                /* CPU flags for lock */
+  trace_time_delta    lTimeDelta;            /* The time elapsed between now and the last event */
+
+  /* Is there a tracing daemon */
+  if(sDaemonTaskStruct == NULL)
+    return -ENODEV;
+
+  /* Do we trace the event */
+  if((sTracerStarted == TRUE) || (pmEventID == TRACE_EV_START) || (pmEventID == TRACE_EV_BUFFER_START))
+    goto TraceEvent;
+
+  /* We can't continue */
+  return -EBUSY;
+
+TraceEvent:
+
+  /* Are we monitoring this event */
+  if(!ltt_test_bit(pmEventID, &sTracedEvents))
+    return 0;
+
+  /* Always let the start event pass, whatever the IDs */
+  if((pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START))
+    {
+    /* Are we monitoring a particular process */
+    if((sTracingPID == TRUE) && (current->pid != sTracedPID))
+      return 0;
+
+    /* Are we monitoring a particular process group */
+    if((sTracingPGRP == TRUE) && (current->pgrp != sTracedPGRP))
+      return 0;
+
+    /* Are we monitoring the processes of a given group of users */
+    if((sTracingGID == TRUE) && (current->egid != sTracedGID))
+      return 0;
+
+    /* Are we monitoring the processes of a given user */
+    if((sTracingUID == TRUE) && (current->euid != sTracedUID))
+      return 0;
+    }
+
+  /* Compute size of tracing data */
+  lDataSize = sizeof(pmEventID) + sizeof(lTimeDelta) + sizeof(lDataSize);
+
+  /* Do we log the event details */
+  if(ltt_test_bit(pmEventID, &sLogEventDetailsMask))
+    {
+    /* Update the size of the data entry */
+    lDataSize += sEventStructSize[pmEventID];
+
+    /* Some events have variable length */
+    switch(pmEventID)
+      {
+      /* Is there a file name in this */
+      case TRACE_EV_FILE_SYSTEM:
+	if((((trace_file_system*) pmEventStruct)->event_sub_id == TRACE_EV_FILE_SYSTEM_EXEC)
+	|| (((trace_file_system*) pmEventStruct)->event_sub_id == TRACE_EV_FILE_SYSTEM_OPEN))
+	  {
+	  /* Remember the string's beging and update size variables */
+	  lVarDataBeg = ((trace_file_system*) pmEventStruct)->file_name;
+	  lVarDataLen = ((trace_file_system*) pmEventStruct)->event_data2 + 1;
+	  lDataSize += lVarDataLen;
+	  }
+	break;
+
+      /* Declaration of a new event */
+      case TRACE_EV_NEW_EVENT:
+	lVarDataBeg = ((trace_new_event*) pmEventStruct)->data_description;
+	lVarDataLen = ((trace_new_event*) pmEventStruct)->desc_size;
+	lDataSize += lVarDataLen;
+	break;
+
+      /* Logging of a custom event */
+      case TRACE_EV_CUSTOM:
+	lVarDataBeg = ((trace_custom*) pmEventStruct)->data;
+	lVarDataLen = ((trace_custom*) pmEventStruct)->data_size;
+	lDataSize += lVarDataLen;
+	break;
+      }
+    }
+
+  /* Do we record the CPUID */
+  if((sLogCPUID == TRUE) && (pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START))
+    {
+    /* Remember the CPUID */
+    lCPUID = smp_processor_id();
+
+    /* Update the size of the data entry */
+    lDataSize += sizeof(lCPUID);
+    }
+
+  /* Lock the kernel */
+  spin_lock_irqsave(&sSpinLock, lFlags);
+
+  /* The following time calculations have to be done within the spinlock because
+     otherwise the event order could be inverted. */
+
+  /* Get the time of the event */
+  do_gettimeofday(&lTime);
+
+  /* Compute the time delta between this event and the time at which this buffer was started */
+  lTimeDelta = (lTime.tv_sec - sBufferStartTime.tv_sec) * 1000000
+             + (lTime.tv_usec - sBufferStartTime.tv_usec);
+
+  /* Is there enough space left in the write buffer */
+  if(sWritPos + lDataSize > sWritLimit)
+    {
+    /* Have we already switched buffers and informed the daemon of it */
+    if(sSignalSent == TRUE)
+      {
+      /* We've lost another event */
+      sEventsLost++;
+
+      /* Bye, bye, now */
+      spin_unlock_irqrestore(&sSpinLock, lFlags);
+      return -ENOMEM;
+      }
+
+    /* We need to inform the daemon */
+    lSendSignal = TRUE;
+
+    /* Switch buffers */
+    tracer_switch_buffers(lTime);
+
+    /* Recompute the time delta since sBufferStartTime has changed because of the buffer change */
+    lTimeDelta = (lTime.tv_sec - sBufferStartTime.tv_sec) * 1000000
+               + (lTime.tv_usec - sBufferStartTime.tv_usec);
+    }
+
+  /* Write the CPUID to the tracing buffer, if required */
+  if((sLogCPUID == TRUE)  && (pmEventID != TRACE_EV_START) && (pmEventID != TRACE_EV_BUFFER_START))
+    tracer_write_to_buffer(sWritPos,
+			   &lCPUID,
+			   sizeof(lCPUID));
+
+  /* Write event type to tracing buffer */
+  tracer_write_to_buffer(sWritPos,
+			 &pmEventID,
+			 sizeof(pmEventID));
+
+  /* Write event time delta to tracing buffer */
+  tracer_write_to_buffer(sWritPos,
+			 &lTimeDelta,
+			 sizeof(lTimeDelta));
+
+  /* Do we log event details */
+  if(ltt_test_bit(pmEventID, &sLogEventDetailsMask))
+    {
+    /* Write event structure */
+    tracer_write_to_buffer(sWritPos,
+			   pmEventStruct,
+			   sEventStructSize[pmEventID]);
+
+    /* Write string if any */
+    if(lVarDataLen)
+      tracer_write_to_buffer(sWritPos,
+			     lVarDataBeg,
+			     lVarDataLen);
+    }
+
+  /* Write the length of the event description */
+  tracer_write_to_buffer(sWritPos,
+			 &lDataSize,
+			 sizeof(lDataSize));
+
+  /* Should the tracing daemon be notified  */
+  if(lSendSignal == TRUE)
+    {
+    /* Remember that a signal has been sent */
+    sSignalSent = TRUE;
+
+    /* Unlock the kernel */
+    spin_unlock_irqrestore(&sSpinLock, lFlags);
+
+    /* Setup signal information */
+    lSigInfo.si_signo = SIGIO;
+    lSigInfo.si_errno = 0;
+    lSigInfo.si_code  = SI_KERNEL;
+
+    /* DEBUG */
+#if 0
+    printk("<1> Sending SIGIO to %d \n", sDaemonTaskStruct->pid);
+#endif
+
+    /* Signal the tracing daemon */
+    send_sig_info(SIGIO, &lSigInfo, sDaemonTaskStruct);
+    }
+  else
+    /* Unlock the kernel */
+    spin_unlock_irqrestore(&sSpinLock, lFlags);
+  
+  /* Indicate to the caller that everything is OK */
+  return 0;
+}
+
+/*************************************************************
+ * Function : tracer_switch_buffers()
+ * Description :
+ *     Put the current write buffer to be read and reset put
+ *     the old read buffer to be written to. Set the tracer
+ *     variables in consequence.
+ * Parameters :
+ *     pmTime, current time
+ * Return values :
+ *     NONE
+ * Note :
+ *     This should be called from within a spin_lock.
+ *************************************************************/
+void tracer_switch_buffers(struct timeval pmTime)
+{
+  char*               lTempBuf;              /* Temporary buffer pointer */
+  char*               lTempBufEnd;           /* Temporary buffer end pointer */
+  char*               lInitWritPos;          /* Initial write position */
+  uint8_t             lDataSize;             /* Size of tracing data */
+  uint8_t             lEventID;              /* Event ID of last event */
+  uint8_t             lCPUID;                /* CPUID of currently runing process */
+  uint32_t            lSizeLost;             /* Size delta between last event and end of buffer */
+  trace_time_delta    lTimeDelta;            /* The time elapsed between now and the last event */
+  trace_buffer_start  lStartBufferEvent;     /* Start of the new buffer event */
+
+  /* Remember initial write position */
+  lInitWritPos = sWritPos;
+
+  /* Write the end event at the write of the buffer */
+
+  /* Write the CPUID to the tracing buffer, if required */
+  if(sLogCPUID == TRUE)
+    {
+    lCPUID = smp_processor_id();
+    tracer_write_to_buffer(sWritPos,
+			   &lCPUID,
+			   sizeof(lCPUID));
+    }
+
+  /* Write event type to tracing buffer */
+  lEventID = TRACE_EV_BUFFER_END;
+  tracer_write_to_buffer(sWritPos,
+			 &lEventID,
+			 sizeof(lEventID));
+
+  /* Write event time delta to tracing buffer */
+  lTimeDelta = 0;
+  tracer_write_to_buffer(sWritPos,
+			 &lTimeDelta,
+			 sizeof(lTimeDelta));
+
+  /* Get size lost */
+  lSizeLost = sWritBufEnd - lInitWritPos;
+
+  /* Write size lost at the end of the buffer */
+  *((uint32_t*) (sWritBufEnd - sizeof(lSizeLost))) = lSizeLost;
+
+  /* Switch buffers */
+  lTempBuf = sReadBuf;
+  sReadBuf = sWritBuf;
+  sWritBuf = lTempBuf;
+
+  /* Set buffer ends */
+  lTempBufEnd = sReadBufEnd;
+  sReadBufEnd = sWritBufEnd;
+  sWritBufEnd = lTempBufEnd;
+
+  /* Set read limit */
+  sReadLimit = sReadBufEnd;
+
+  /* Set write limit */
+  sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE;
+
+  /* Set write position */
+  sWritPos = sWritBuf;
+
+  /* Increment buffer ID */
+  sBufferID++;
+
+  /* Set the time of begining of this buffer */
+  sBufferStartTime = pmTime;
+
+  /* Write the start of buffer event */
+  lStartBufferEvent.ID   = sBufferID;
+  lStartBufferEvent.Time = pmTime;
+
+  /* Write event type to tracing buffer */
+  lEventID = TRACE_EV_BUFFER_START;
+  tracer_write_to_buffer(sWritPos,
+			 &lEventID,
+			 sizeof(lEventID));
+
+  /* Write event time delta to tracing buffer */
+  lTimeDelta = 0;
+  tracer_write_to_buffer(sWritPos,
+			 &lTimeDelta,
+			 sizeof(lTimeDelta));
+
+  /* Write event structure */
+  tracer_write_to_buffer(sWritPos,
+			 &lStartBufferEvent,
+			 sizeof(lStartBufferEvent));
+
+  /* Compute the data size */
+  lDataSize = sizeof(lEventID)
+            + sizeof(lTimeDelta)
+            + sizeof(lStartBufferEvent)
+            + sizeof(lDataSize);
+
+  /* Write the length of the event description */
+  tracer_write_to_buffer(sWritPos,
+			 &lDataSize,
+			 sizeof(lDataSize));
+}
+
+/*************************************************************
+ * Function : tracer_ioctl()
+ * Description : "Ioctl" file op
+ * Parameters :
+ *     pmInode, the inode associated with the device
+ *     pmFile, file structure given to the acting process
+ *     pmCmd, command given by the caller
+ *     pmArg, arguments to the command
+ * Return values :
+ *     >0, In case the caller requested the number of events
+ *         lost.
+ *     0, Everything went OK
+ *     -ENOSYS, no such command
+ *     -EINVAL, tracer not properly configured
+ *     -EBUSY, tracer can't be reconfigured while in operation
+ *     -ENOMEM, no more memory
+ * Note :
+ *     In the future, this function should check to make sure
+ *     that it's the server that make thes ioctl.
+ *************************************************************/
+int tracer_ioctl(struct inode* pmInode,
+		 struct file*  pmFile,
+		 unsigned int  pmCmd,
+		 unsigned long pmArg)
+{
+  trace_start            lStartEvent;           /* Event marking the begining of the trace */
+  unsigned long int      lFlags;                /* CPU flags for lock */
+  trace_buffer_start     lStartBufferEvent;     /* Start of the new buffer event */
+
+  /* If the tracer is started, the configuration can't be modified */
+  if((sTracerStarted == TRUE) && (pmCmd != TRACER_STOP) && (pmCmd != TRACER_DATA_COMITTED))
+    return -EBUSY;
+
+  /* Depending on the command executed */
+  switch(pmCmd)
+    {
+    /* Start the tracer */
+    case TRACER_START :
+      /* Check if the device has been properly set up */
+      if(((sUseSyscallEIPBounds == TRUE)
+        &&(sSyscallEIPDepthSet  == TRUE))
+       ||((sUseSyscallEIPBounds == TRUE)
+        &&((sLowerEIPBoundSet != TRUE)
+         ||(sUpperEIPBoundSet != TRUE)))
+       ||((sTracingPID  == TRUE)
+        &&(sTracingPGRP == TRUE)))
+	return -EINVAL;
+
+      /* Set the kernel-side trace configuration */
+      if(trace_set_config(trace,
+			  sSyscallEIPDepthSet,
+			  sUseSyscallEIPBounds,
+			  sSyscallEIPDepth,
+			  sLowerEIPBound,
+			  sUpperEIPBound) < 0)
+	return -EINVAL;
+
+      /* Always log the start event and the buffer start event */
+      ltt_set_bit(TRACE_EV_BUFFER_START, &sTracedEvents);
+      ltt_set_bit(TRACE_EV_BUFFER_START, &sLogEventDetailsMask);
+      ltt_set_bit(TRACE_EV_START, &sTracedEvents);
+      ltt_set_bit(TRACE_EV_START, &sLogEventDetailsMask);
+
+      /* Get the time of start */
+      do_gettimeofday(&sBufferStartTime);
+
+      /* Set the event description */
+      lStartBufferEvent.ID   = sBufferID;
+      lStartBufferEvent.Time = sBufferStartTime;
+
+      /* Set the event description */
+      lStartEvent.MagicNumber   = TRACER_MAGIC_NUMBER;
+#ifdef __i386__
+      lStartEvent.ArchType      = TRACE_ARCH_TYPE_I386;
+#endif
+#ifdef __powerpc__
+      lStartEvent.ArchType      = TRACE_ARCH_TYPE_PPC;
+#endif
+      lStartEvent.SystemType    = TRACE_SYS_TYPE_VANILLA_LINUX;
+      lStartEvent.MajorVersion  = TRACER_VERSION_MAJOR;
+      lStartEvent.MinorVersion  = TRACER_VERSION_MINOR;
+      lStartEvent.BufferSize    = sBufSize;
+      lStartEvent.EventMask     = sTracedEvents;
+      lStartEvent.DetailsMask   = sLogEventDetailsMask;
+      lStartEvent.LogCPUID      = sLogCPUID;
+
+      /* Trace the buffer start event */
+      trace(TRACE_EV_BUFFER_START, &lStartBufferEvent);
+
+      /* Trace the start event */
+      trace(TRACE_EV_START, &lStartEvent);
+
+      /* We can start tracing */
+      sTracerStarted = TRUE;
+      break;
+
+    /* Stop the tracer */
+    case TRACER_STOP :
+      /* Stop tracing */
+      sTracerStarted = FALSE;
+
+      /* Acquire the lock to avoid SMP case of where another CPU is writing a trace
+         while buffer is being switched */
+      spin_lock_irqsave(&sSpinLock, lFlags);
+
+      /* Switch the buffers to ensure that the end of the buffer mark is set (time isn't important) */
+      tracer_switch_buffers(sBufferStartTime);
+
+      /* Release lock */
+      spin_unlock_irqrestore(&sSpinLock, lFlags);
+      break;
+
+    /* Set the tracer to the default configuration */
+    case TRACER_CONFIG_DEFAULT :
+      tracer_set_default_config();
+      break;
+
+    /* Set the memory buffers the daemon wants us to use */
+    case TRACER_CONFIG_MEMORY_BUFFERS :
+      /* Is the given size "reasonnable" */
+      if(pmArg < TRACER_MIN_BUF_SIZE)
+	return -EINVAL;
+
+      /* Set the buffer's size */
+      return tracer_set_buffer_size(pmArg);
+      break;
+
+    /* Trace the given events */
+    case TRACER_CONFIG_EVENTS :
+      if(copy_from_user(&sTracedEvents, (void*) pmArg, sizeof(sTracedEvents)))
+	return -EFAULT;
+      break;
+
+    /* Record the details of the event, or not */
+    case TRACER_CONFIG_DETAILS :
+      if(copy_from_user(&sLogEventDetailsMask, (void*) pmArg, sizeof(sLogEventDetailsMask)))
+	return -EFAULT;
+      break;
+      
+    /* Record the CPUID associated with the event */
+    case TRACER_CONFIG_CPUID :
+      sLogCPUID = TRUE;
+      break;
+
+    /* Trace only one process */
+    case TRACER_CONFIG_PID :
+      sTracingPID = TRUE;
+      sTracedPID  = pmArg;
+      break;
+
+    /* Trace only the given process group */
+    case TRACER_CONFIG_PGRP :
+      sTracingPGRP = TRUE;
+      sTracedPGRP  = pmArg;
+      break;
+
+    /* Trace the processes of a given group of users */
+    case TRACER_CONFIG_GID :
+      sTracingGID = TRUE;
+      sTracedGID  = pmArg;
+      break;
+
+    /* Trace the processes of a given user */
+    case TRACER_CONFIG_UID :
+      sTracingUID = TRUE;
+      sTracedUID  = pmArg;
+      break;
+
+    /* Set the call depth a which the EIP should be fetched on syscall */
+    case TRACER_CONFIG_SYSCALL_EIP_DEPTH :
+      sSyscallEIPDepthSet = TRUE;
+      sSyscallEIPDepth    = pmArg;
+      break;
+
+    /* Set the lowerbound address from which EIP is recorded on syscall */
+    case TRACER_CONFIG_SYSCALL_EIP_LOWER :
+      /* We are using bounds for fetching the EIP where syscall was made */
+      sUseSyscallEIPBounds = TRUE;
+
+      /* Set the lower bound */
+      sLowerEIPBound = (void*) pmArg;
+
+      /* The lower bound has been set */
+      sLowerEIPBoundSet = TRUE;
+      break;
+
+    /* Set the upperbound address from which EIP is recorded on syscall */
+    case TRACER_CONFIG_SYSCALL_EIP_UPPER :
+      /* We are using bounds for fetching the EIP where syscall was made */
+      sUseSyscallEIPBounds = TRUE;
+
+      /* Set the lower bound */
+      sUpperEIPBound = (void*) pmArg;
+
+      /* The lower bound has been set */
+      sUpperEIPBoundSet = TRUE;
+      break;
+
+    /* The daemon has comitted the last trace */
+    case TRACER_DATA_COMITTED :
+#if 0
+      printk("Tracer: Data has been comitted \n");
+#endif
+
+      /* Safely set the signal sent flag to FALSE */
+      spin_lock_irqsave(&sSpinLock, lFlags);
+      sSignalSent = FALSE;
+      spin_unlock_irqrestore(&sSpinLock, lFlags);
+      break;
+
+    /* Get the number of events lost */
+    case TRACER_GET_EVENTS_LOST :
+      return sEventsLost;
+      break;
+
+    /* Unknow command */
+    default :
+      return -ENOSYS;
+    }
+
+  /* Everything went OK */
+  return 0;
+}
+
+/*************************************************************
+ * Function : tracer_mmap()
+ * Description : "Mmap" file op
+ * Parameters :
+ *     pmInode, the inode associated with the device
+ *     pmFile, file structure given to the acting process
+ *     pmVmArea, Virtual memory area description structure
+ * Return values :
+ *     0 if ok
+ *     -EAGAIN, when remap failed
+ ************************************************************/
+int tracer_mmap(struct file*            pmFile,
+		struct vm_area_struct*  pmVmArea)
+{
+  int      lRetValue;     /* Function's return value */
+
+  /* Remap trace buffer into the process's memory space */
+  lRetValue = tracer_mmap_region((char*) pmVmArea->vm_start,
+				 sTracBuf,
+				 pmVmArea->vm_end - pmVmArea->vm_start);
+
+#if 0
+  printk("Tracer: Trace buffer virtual address                  => 0x%08X \n", (uint32_t)sTracBuf);
+  printk("Tracer: Trace buffer physical address                 => 0x%08X \n", (uint32_t)virt_to_phys(sTracBuf));
+  printk("Tracer: Trace buffer virtual address in daemon space  => 0x%08X \n", (uint32_t)pmVmArea->vm_start);
+  printk("Tracer: Trace buffer physical address in daemon space => 0x%08X \n", (uint32_t)virt_to_phys((void*)pmVmArea->vm_start));
+#endif
+
+  /* Tell the caller that the memory mapping worked OK */
+  return lRetValue;
+}
+
+/*************************************************************
+ * Function : tracer_open()
+ * Description : "Open" file op
+ * Parameters : 
+ *     pmInode, the inode associated with the device
+ *     pmFile, file structure given to the acting process
+ * Return values :
+ *     0, everything went OK
+ *     -ENODEV, no such device.
+ *     -EBUSY, the tracer is already in use.
+ ************************************************************/
+int tracer_open(struct inode* pmInode,
+		struct file*  pmFile)
+{
+  int lDevMinor = MINOR(pmInode->i_rdev) & 0xf;  /* Device minor number */
+
+  /* Don't allow more than one device of this type */
+  if(lDevMinor > 0)
+    return -ENODEV;
+
+  /* Don't allow the device to be open more than once */
+  if(sOpenCount)
+    return -EBUSY;
+
+  /* Fetch the task structure of the process that opened the device */
+  sDaemonTaskStruct = current;
+
+#if 0
+  /* DEBUG */
+  printk("<1>Process %d opened the tracing device \n", sDaemonTaskStruct->pid);
+#endif
+
+  /* Lock the device */
+  sOpenCount++;
+
+#ifdef MODULE
+  /* Increment module usage */
+  MOD_INC_USE_COUNT;
+#endif
+
+  /* Everything is OK */
+  return 0;
+}
+
+/*************************************************************
+ * Function : tracer_release()
+ * Description : "Release" file op
+ * Parameters :
+ *     pmInode, the inode associated with the device
+ *     pmFile, file structure given to the acting process
+ * Return values : 
+ *     0, everything went OK
+ * Note :
+ *     It is assumed that if the tracing daemon dies, exits
+ *     or simply stops existing, the kernel or "someone" will
+ *     call tracer_release. Otherwise, we're in trouble ...
+ *************************************************************/
+int tracer_release(struct inode* pmInode,
+		   struct file*  pmFile)
+{
+  /* Did we loose any events */
+  if(sEventsLost > 0)
+    printk("<1>Tracer: Lost %d events \n", sEventsLost);
+
+  /* Reset the daemon PID */
+  sDaemonTaskStruct = NULL;
+
+  /* Free the current buffers, if any */
+  if(sTracBuf != NULL)
+    rvfree(sTracBuf, sAllocSize);
+
+  /* Reset the read and write buffers */
+  sTracBuf    = NULL;
+  sWritBuf    = NULL;
+  sReadBuf    = NULL;
+  sWritBufEnd = NULL;
+  sReadBufEnd = NULL;
+  sWritPos    = NULL;
+  sReadLimit  = NULL;
+  sWritLimit  = NULL;
+
+  /* Reset the tracer's configuration */
+  tracer_set_default_config();
+  sTracerStarted = FALSE;
+
+  /* Reset number of bytes recorded and number of events lost */
+  sBufReadComplete    = 0;
+  sSizeReadIncomplete = 0;
+  sEventsLost         = 0;
+
+  /* Reset signal sent */
+  sSignalSent = FALSE;
+
+  /* Unlock the device */
+  sOpenCount--;
+
+#ifdef MODULE
+  /* Decrement module usage */
+  MOD_DEC_USE_COUNT;
+#endif
+
+  /* Tell the caller that everything is OK */
+  return 0;
+}
+
+/*************************************************************
+ * Function : tracer_fsync()
+ * Description : "Fsync" file op
+ * Parameters :
+ *     pmFile, file structure given to the acting process
+ *     pmDEntry, dentry associated with file
+ * Return values : 
+ *     0, everything went OK
+ * Note :
+ *     We need to look the modifications of the values because
+ *     they are read and written by trace().
+ * Sonia : ne m oublie pas, je suis toujours a toi....
+ *************************************************************/
+int tracer_fsync(struct file*   pmFile,
+		 struct dentry* pmDEntry,
+		 int            pmDataSync)
+{
+  unsigned long int   lFlags;      /* CPU flags for lock */
+
+  /* Lock the kernel */
+  spin_lock_irqsave(&sSpinLock, lFlags);
+  
+  /* Reset the write positions */
+  sWritPos   = sWritBuf;
+
+  /* Reset read limit */
+  sReadLimit = sReadBuf;
+
+  /* Reset bytes recorded */
+  sBufReadComplete    = 0;
+  sSizeReadIncomplete = 0;
+  sEventsLost         = 0;
+
+  /* Reset signal sent */
+  sSignalSent = FALSE;
+
+  /* Unlock the kernel */
+  spin_unlock_irqrestore(&sSpinLock, lFlags);
+
+  /* Tell the caller that everything is OK */
+  return 0;
+}
+
+/*************************************************************
+ * Function : tracer_set_buffer_size()
+ * Description :
+ *     Sets the size of the buffers containing the trace data.
+ * Parameters :
+ *     pmSize, Size of buffers
+ * Return values :
+ *     0, Size setting went OK
+ *     -ENOMEM, unable to get a hold of memory for tracer
+ *************************************************************/
+int tracer_set_buffer_size(int pmSize)
+{
+  int       lSizeAlloc;     /* Size to be allocated */
+
+  /* Set size to allocate (= pmSize * 2) and fix it's size to be on a page boundary */
+  lSizeAlloc = FIX_SIZE(pmSize << 1);
+
+  /* Free the current buffers, if any */
+  if(sTracBuf != NULL)
+    rvfree(sTracBuf, sAllocSize);
+
+  /* Allocate space for the tracing buffers */
+  if((sTracBuf = (char*) rvmalloc(lSizeAlloc)) == NULL)
+    return -ENOMEM;
+
+  /* Remember the size set */
+  sBufSize = pmSize;
+  sAllocSize = lSizeAlloc;
+
+  /* Set the read and write buffers */
+  sWritBuf = sTracBuf;
+  sReadBuf = sTracBuf + sBufSize;
+
+  /* Set end of buffers */
+  sWritBufEnd = sWritBuf + sBufSize;
+  sReadBufEnd = sReadBuf + sBufSize;
+
+  /* Set write position */
+  sWritPos = sWritBuf;
+
+  /* Set read limit */
+  sReadLimit = sReadBuf;
+
+  /* Set write limit */
+  sWritLimit = sWritBufEnd - TRACER_LAST_EVENT_SIZE;
+
+  /* All is OK */
+  return 0;
+}
+
+/*************************************************************
+ * Function : tracer_set_default_config()
+ * Description : Sets the tracer in its default config
+ * Parameters :
+ *     NONE
+ * Return values :
+ *    0, everything went OK
+ *    -ENOMEM, unable to get a hold of memory for tracer
+ *************************************************************/
+int tracer_set_default_config(void)
+{
+  int  i;          /* Generic index */
+  int  lError = 0; /* Error, if any */
+
+  /* Initialize the event mask */
+  sTracedEvents = 0;
+  
+  /* Initialize the event mask with all existing events with their details*/
+  for(i = 0; i <= TRACE_EV_MAX; i++)
+    {
+    ltt_set_bit(i, &sTracedEvents);
+    ltt_set_bit(i, &sLogEventDetailsMask);
+    }
+
+  /* Forget about the CPUID */
+  sLogCPUID = FALSE;
+  
+  /* We aren't tracing any PID or GID in particular */
+  sTracingPID  = FALSE;
+  sTracingPGRP = FALSE;
+  sTracingGID  = FALSE;
+  sTracingUID  = FALSE;
+
+  /* We aren't looking for a particular call depth */
+  sSyscallEIPDepthSet = FALSE;
+
+  /* We aren't going to place bounds on syscall EIP fetching */
+  sUseSyscallEIPBounds = FALSE;
+  sLowerEIPBoundSet = FALSE;
+  sUpperEIPBoundSet = FALSE;
+
+  /* Set the kernel trace configuration to it's basics */
+  trace_set_config(trace,
+		   sSyscallEIPDepthSet,
+		   sUseSyscallEIPBounds,
+		   0,
+		   0,
+		   0);
+
+  /* Return the error code */
+  return lError;
+}
+
+/**************************************************************
+ * Function : tracer_init()
+ * Description : Tracer initialization function.
+ * Parameters :
+ *     NONE
+ * Return values : 
+ *    0, everything went OK
+ *    -ENOMEM, unable to get a hold of memory for tracer
+ **************************************************************/
+int __init tracer_init(void)
+{
+  int  lError = 0; /* Error, if any */
+
+  /* Initialize configuration */
+  if((lError = tracer_set_default_config()) < 0)
+    return lError;
+
+  /* Initialize open count */
+  sOpenCount = 0;
+
+  /* Initialize tracer lock */
+  sTracLock = 0;
+
+  /* Initialize signal sent */
+  sSignalSent = FALSE;
+
+  /* Initialize bytes read and events lost */
+  sBufReadComplete    = 0;
+  sSizeReadIncomplete = 0;
+  sEventsLost         = 0;
+
+  /* Initialize buffer ID */
+  sBufferID    = 0;
+
+  /* Initialize tracing daemon task structure */
+  sDaemonTaskStruct = NULL;
+
+  /* Initialize spin lock */
+  sSpinLock = SPIN_LOCK_UNLOCKED;
+
+  /* Register the tracer as a char device */ 
+  sMajorNumber = register_chrdev(0, TRACER_NAME, &sTracerFileOps);
+
+  /* Register the tracer with the kernel */
+  register_tracer(trace);
+
+  /* Let the user know about it */
+#if 1
+  printk("<1>Tracer: Initialization complete \n");
+#endif
+
+  /* Return error code */
+  return lError;
+}
+
+/* Is this loaded as a module */
+#ifdef MODULE
+/**************************************************************
+ * Function : cleanup_module()
+ * Description : Cleanup of the tracer.
+ * Parameters : NONE
+ * Return values : NONE
+ * Note : The order of the unregesterings is important. First,
+ *        rule out any possibility of getting more trace 
+ *        data. Second, rule out any possibility of being read
+ *        by the tracing daemon. Last, free the tracing
+ *        buffer.
+ **************************************************************/
+void tracer_exit(void)
+{
+  /* Unregister the tracer from the kernel */
+  unregister_tracer(trace);
+
+  /* Unregister the tracer from being a char device */
+  unregister_chrdev(sMajorNumber, TRACER_NAME);
+
+  /* Free the current buffers, if any */
+  if(sTracBuf != NULL)
+    rvfree(sTracBuf, sAllocSize);
+
+  /* Paranoia */
+  sTracBuf = NULL;
+}
+module_exit(tracer_exit);
+#endif /* MODULE */
+
+module_init(tracer_init);
diff -urN linux/drivers/trace/tracer.h linux-2.4.0-test10/drivers/trace/tracer.h
--- linux/drivers/trace/tracer.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.0-test10/drivers/trace/tracer.h	Wed Mar 28 16:01:09 2001
@@ -0,0 +1,217 @@
+/*
+ * drivers/trace/tracer.h
+ *
+ * Copyright (C) 1999, 2000, 2001 Karim Yaghmour
+ *
+ * This contains the necessary definitions the system tracer
+ */
+
+#ifndef _TRACER_H
+#define _TRACER_H
+
+/* Logic values */
+#define FALSE 0
+#define TRUE  1
+
+/* Structure packing within the trace */
+#if LTT_UNPACKED_STRUCTS
+#define LTT_PACKED_STRUCT
+#else  /* if LTT_UNPACKED_STRUCTS */
+#define LTT_PACKED_STRUCT __attribute__ ((packed));
+#endif /* if LTT_UNPACKED_STRUCTS */
+
+/* Tracer properties */
+#define TRACER_NAME      "tracer"     /* Name of the device as seen in /proc/devices */
+
+/* Tracer buffer information */
+#define TRACER_DEFAULT_BUF_SIZE   50000   /* Default size of tracing buffer */
+#define TRACER_MIN_BUF_SIZE        1000   /* Minimum size of tracing buffer */
+#define TRACER_MAX_BUF_SIZE      500000   /* Maximum size of tracing buffer */
+
+/* Local definitions */
+typedef uint32_t    trace_time_delta;    /* The type used to start the time delta between events */
+typedef uint64_t    trace_event_mask;    /* The event mask type */
+
+/* Number of bytes set aside for last event */
+#define TRACER_LAST_EVENT_SIZE   (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(trace_time_delta) + sizeof(uint32_t))
+
+/* Architecture types */
+#define TRACE_ARCH_TYPE_I386                1   /* i386 system */
+#define TRACE_ARCH_TYPE_PPC                 2   /* PPC system */
+
+/* System types */
+#define TRACE_SYS_TYPE_VANILLA_LINUX        1   /* Vanilla linux kernel  */
+
+/* The information logged when the tracing is started */
+#define TRACER_MAGIC_NUMBER     0x00D6B7ED      /* That day marks an important historical event ... */
+#define TRACER_VERSION_MAJOR    1               /* Major version number */
+#define TRACER_VERSION_MINOR    9               /* Minor version number */
+typedef struct _trace_start
+{
+  uint32_t           MagicNumber  LTT_PACKED_STRUCT;  /* Magic number to identify a trace */
+  uint32_t           ArchType     LTT_PACKED_STRUCT;  /* Type of architecture */
+  uint32_t           SystemType   LTT_PACKED_STRUCT;  /* Operating system type */
+  uint8_t            MajorVersion LTT_PACKED_STRUCT;  /* Major version of trace */
+  uint8_t            MinorVersion LTT_PACKED_STRUCT;  /* Minor version of trace */
+
+  uint32_t           BufferSize   LTT_PACKED_STRUCT;  /* Size of buffers */
+  trace_event_mask   EventMask    LTT_PACKED_STRUCT;  /* The event mask */
+  trace_event_mask   DetailsMask  LTT_PACKED_STRUCT;  /* Are the event details logged */
+  uint8_t            LogCPUID     LTT_PACKED_STRUCT;  /* Is the CPUID logged */
+} trace_start;
+
+/* Start and end of trace buffer information */
+typedef struct _trace_buffer_start
+{
+  struct timeval     Time         LTT_PACKED_STRUCT;  /* Time stamp of this buffer */
+  uint32_t           ID           LTT_PACKED_STRUCT;  /* Unique buffer ID */  
+} trace_buffer_start;
+
+/* The configurations possible */
+#define TRACER_START                      0  /* Start tracing events using the current configuration */
+#define TRACER_STOP                       1  /* Stop tracing */
+#define TRACER_CONFIG_DEFAULT             2  /* Set the tracer to the default configuration */
+#define TRACER_CONFIG_MEMORY_BUFFERS      3  /* Set the memory buffers the daemon wants us to use */
+#define TRACER_CONFIG_EVENTS              4  /* Trace the given events */
+#define TRACER_CONFIG_DETAILS             5  /* Record the details of the event, or not */
+#define TRACER_CONFIG_CPUID               6  /* Record the CPUID associated with the event */
+#define TRACER_CONFIG_PID                 7  /* Trace only one process */
+#define TRACER_CONFIG_PGRP                8  /* Trace only the given process group */
+#define TRACER_CONFIG_GID                 9  /* Trace the processes of a given group of users */
+#define TRACER_CONFIG_UID                10  /* Trace the processes of a given user */
+#define TRACER_CONFIG_SYSCALL_EIP_DEPTH  11  /* Set the call depth at which the EIP should be fetched on syscall */
+#define TRACER_CONFIG_SYSCALL_EIP_LOWER  12  /* Set the lowerbound address from which EIP is recorded on syscall */
+#define TRACER_CONFIG_SYSCALL_EIP_UPPER  13  /* Set the upperbound address from which EIP is recorded on syscall */
+#define TRACER_DATA_COMITTED             14  /* The daemon has comitted the last trace */
+#define TRACER_GET_EVENTS_LOST           15  /* Get the number of events lost */
+
+#ifdef __powerpc__
+/* We need to replace the usual PPC kernel bit manipulation functions with
+ * equivalent functions that are cross-platform compatible.  The PPC kernel
+ * functions define bit order as follows:
+ *
+ * bit  0: 0x0000000100000000
+ * bit  1: 0x0000000200000000
+ * .
+ * .
+ * .
+ * bit  7: 0x0000008000000000
+ * bit  8: 0x0000010000000000
+ * bit  9: 0x0000020000000000
+ * .
+ * .
+ * .
+ * bit 31: 0x8000000000000000
+ * bit 32: 0x0000000000000001
+ * bit 33: 0x0000000000000002
+ * .
+ * .
+ * .
+ * bit 63: 0x0000000080000000
+ *
+ * Our redefined functions define bit order the same as the kernel bit functions
+ * for x86 targets:
+ *
+ * bit  0: 0x0100000000000000
+ * bit  1: 0x0200000000000000
+ * .
+ * .
+ * .
+ * bit  7: 0x8000000000000000
+ * bit  8: 0x0001000000000000
+ * bit  9: 0x0002000000000000
+ * .
+ * .
+ * .
+ * bit 31: 0x0000000800000000
+ * bit 32: 0x0000000001000000
+ * bit 33: 0x0000000002000000
+ * .
+ * .
+ * .
+ * bit 63: 0x0000000000000080
+ */
+static inline int ltt_set_bit(int nr, volatile void * addr)
+{
+	unsigned long old, t;
+	unsigned long mask = 1 << (24 - (nr & 0x18) + (nr & 0x7));
+	volatile unsigned long *p = ((volatile unsigned long *)addr) + (nr >> 5);
+	
+	__asm__ __volatile__(
+		"1:lwarx %0,0,%3 \n\t"
+		"or	%1,%0,%2 \n\t"
+		"stwcx.	%1,0,%3 \n\t"
+		"bne	1b \n\t"
+		: "=&r" (old), "=&r" (t)	/*, "=m" (*p)*/
+		: "r" (mask), "r" (p)
+		/*: "cc" */);
+
+	return (old & mask) != 0;
+}
+
+static inline int ltt_clear_bit(unsigned long nr, volatile void *addr)
+{
+	unsigned long old, t;
+	unsigned long mask = 1 << (24 - (nr & 0x18) + (nr & 0x7));
+	volatile unsigned long *p = ((volatile unsigned long *)addr) + (nr >> 5);
+
+	__asm__ __volatile__("\n\
+1:	lwarx	%0,0,%3
+	andc	%1,%0,%2
+	stwcx.	%1,0,%3
+	bne	1b"
+	: "=&r" (old), "=&r" (t)	/*, "=m" (*p)*/
+	: "r" (mask), "r" (p)
+      /*: "cc"*/);
+
+	return (old & mask) != 0;
+}
+
+static inline int ltt_test_bit(int nr, __const__ volatile void *addr)
+{
+	__const__ volatile unsigned int *p = (__const__ volatile unsigned int *) addr;
+
+	return ((p[nr >> 5] >> (24 - (nr & 0x18) + (nr & 0x7))) & 1) != 0;
+}
+#else  /* ifdef __powerpc__ */
+/* For non-powerpc processors we can use the kernel functions. */
+#define ltt_set_bit    set_bit
+#define ltt_clear_bit  clear_bit
+#define ltt_test_bit   test_bit
+#endif /* ifdef __powerpc__ */
+
+/* Function prototypes */
+int     trace
+          (uint8_t,
+	   void*);
+void    tracer_switch_buffers
+          (struct timeval);
+int     tracer_ioctl
+          (struct inode*,
+	   struct file*,
+	   unsigned int,
+	   unsigned long);
+int     tracer_mmap
+	  (struct file*,
+	   struct vm_area_struct*);
+int     tracer_open
+          (struct inode*,
+           struct file*);
+int     tracer_release
+          (struct inode*,
+	   struct file*);
+int     tracer_fsync
+          (struct file*,
+	   struct dentry*,
+	   int);
+#ifdef MODULE
+void    tracer_exit
+          (void);
+#endif
+int     tracer_set_buffer_size
+          (int);
+int     tracer_set_default_config
+          (void);
+int     tracer_init
+          (void);
+#endif /* _TRACER_H */
diff -urN linux/fs/buffer.c linux-2.4.0-test10/fs/buffer.c
--- linux/fs/buffer.c	Thu Oct 12 17:19:32 2000
+++ linux-2.4.0-test10/fs/buffer.c	Tue Nov  7 01:53:41 2000
@@ -46,6 +46,8 @@
 #include <linux/iobuf.h>
 #include <linux/highmem.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
@@ -148,6 +150,7 @@
 	atomic_inc(&bh->b_count);
 	add_wait_queue(&bh->b_wait, &wait);
 	do {
+		TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_BUF_WAIT_START, 0, 0, NULL);
 		run_task_queue(&tq_disk);
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 		if (!buffer_locked(bh))
@@ -155,6 +158,7 @@
 		schedule();
 	} while (buffer_locked(bh));
 	tsk->state = TASK_RUNNING;
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_BUF_WAIT_END, 0, 0, NULL);
 	remove_wait_queue(&bh->b_wait, &wait);
 	atomic_dec(&bh->b_count);
 }
diff -urN linux/fs/exec.c linux-2.4.0-test10/fs/exec.c
--- linux/fs/exec.c	Fri Oct 13 15:10:30 2000
+++ linux-2.4.0-test10/fs/exec.c	Tue Nov  7 01:53:41 2000
@@ -37,6 +37,8 @@
 #define __NO_VERSION__
 #include <linux/module.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
@@ -861,6 +863,11 @@
 	retval = PTR_ERR(file);
 	if (IS_ERR(file))
 		return retval;
+
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_EXEC,
+			  0,
+			  file->f_dentry->d_name.len,
+			  file->f_dentry->d_name.name);
 
 	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
 	memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); 
diff -urN linux/fs/ioctl.c linux-2.4.0-test10/fs/ioctl.c
--- linux/fs/ioctl.c	Sat Aug 12 22:48:04 2000
+++ linux-2.4.0-test10/fs/ioctl.c	Tue Nov  7 01:53:41 2000
@@ -8,6 +8,8 @@
 #include <linux/smp_lock.h>
 #include <linux/file.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
@@ -55,6 +57,10 @@
 	if (!filp)
 		goto out;
 	error = 0;
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_IOCTL,
+			  fd,
+			  cmd,
+			  NULL);
 	lock_kernel();
 	switch (cmd) {
 		case FIOCLEX:
diff -urN linux/fs/open.c linux-2.4.0-test10/fs/open.c
--- linux/fs/open.c	Thu Oct 26 11:11:21 2000
+++ linux-2.4.0-test10/fs/open.c	Tue Nov  7 01:53:41 2000
@@ -14,6 +14,8 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
@@ -757,6 +759,10 @@
 			error = PTR_ERR(f);
 			if (IS_ERR(f))
 				goto out_error;
+			TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_OPEN,
+					  fd,
+					  f->f_dentry->d_name.len,
+					  f->f_dentry->d_name.name); 
 			fd_install(fd, f);
 		}
 out:
@@ -823,6 +829,10 @@
 	filp = files->fd[fd];
 	if (!filp)
 		goto out_unlock;
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_CLOSE,
+			  fd,
+			  0,
+			  NULL);
 	files->fd[fd] = NULL;
 	FD_CLR(fd, files->close_on_exec);
 	__put_unused_fd(files, fd);
diff -urN linux/fs/read_write.c linux-2.4.0-test10/fs/read_write.c
--- linux/fs/read_write.c	Fri Sep 22 17:21:19 2000
+++ linux-2.4.0-test10/fs/read_write.c	Tue Nov  7 01:53:41 2000
@@ -12,6 +12,8 @@
 #include <linux/smp_lock.h>
 #include <linux/dnotify.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 struct file_operations generic_ro_fops = {
@@ -77,6 +79,10 @@
 		if (res != (loff_t)retval)
 			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */
 	}
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SEEK,
+			  fd,
+			  offset,
+			  NULL);
 	fput(file);
 bad:
 	return retval;
@@ -102,6 +108,11 @@
 	offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
 			origin);
 
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SEEK,
+			  fd,
+			  offset,
+			  NULL);
+
 	retval = (int)offset;
 	if (offset >= 0) {
 		retval = -EFAULT;
@@ -129,8 +140,13 @@
 			if (!ret) {
 				ssize_t (*read)(struct file *, char *, size_t, loff_t *);
 				ret = -EINVAL;
-				if (file->f_op && (read = file->f_op->read) != NULL)
+				if (file->f_op && (read = file->f_op->read) != NULL){
+				 	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ,
+							  fd,
+							  count,
+							  NULL); 
 					ret = read(file, buf, count, &file->f_pos);
+				}
 			}
 		}
 		if (ret > 0)
@@ -156,8 +172,13 @@
 			if (!ret) {
 				ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
 				ret = -EINVAL;
-				if (file->f_op && (write = file->f_op->write) != NULL)
+				if (file->f_op && (write = file->f_op->write) != NULL){
+				        TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE,
+							  fd, 
+							  count,
+							  NULL);
 					ret = write(file, buf, count, &file->f_pos);
+				}
 			}
 		}
 		if (ret > 0)
@@ -282,6 +303,10 @@
 	file = fget(fd);
 	if (!file)
 		goto bad_file;
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ,
+			  fd,
+			  count,
+			  NULL);
 	if (file->f_op && (file->f_mode & FMODE_READ) &&
 	    (file->f_op->readv || file->f_op->read))
 		ret = do_readv_writev(VERIFY_WRITE, file, vector, count);
@@ -302,6 +327,10 @@
 	file = fget(fd);
 	if (!file)
 		goto bad_file;
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE,
+			  fd,
+			  count,
+			  NULL);
 	if (file->f_op && (file->f_mode & FMODE_WRITE) &&
 	    (file->f_op->writev || file->f_op->write))
 		ret = do_readv_writev(VERIFY_READ, file, vector, count);
@@ -337,6 +366,12 @@
 		goto out;
 	if (pos < 0)
 		goto out;
+
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_READ,
+			  fd,
+			  count,
+			  NULL);
+
 	ret = read(file, buf, count, &pos);
 	if (ret > 0)
 		inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS);
@@ -368,6 +403,11 @@
 		goto out;
 	if (pos < 0)
 		goto out;
+
+	TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_WRITE,
+			  fd,
+			  count,
+			  NULL);
 
 	ret = write(file, buf, count, &pos);
 	if (ret > 0)
diff -urN linux/fs/select.c linux-2.4.0-test10/fs/select.c
--- linux/fs/select.c	Mon Jul 24 01:39:44 2000
+++ linux-2.4.0-test10/fs/select.c	Tue Nov  7 01:53:41 2000
@@ -19,6 +19,8 @@
 #include <linux/poll.h>
 #include <linux/file.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 #define ROUND_UP(x,y) (((x)+(y)-1)/(y))
@@ -192,6 +194,10 @@
 			file = fget(i);
 			mask = POLLNVAL;
 			if (file) {
+				TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_SELECT,
+						  i /*  The fd*/,
+						  __timeout,
+						  NULL);
 				mask = DEFAULT_POLLMASK;
 				if (file->f_op && file->f_op->poll)
 					mask = file->f_op->poll(file, wait);
@@ -364,6 +370,10 @@
 			struct file * file = fget(fd);
 			mask = POLLNVAL;
 			if (file != NULL) {
+			        TRACE_FILE_SYSTEM(TRACE_EV_FILE_SYSTEM_POLL,
+						  fd,
+						  0,
+						  NULL);
 				mask = DEFAULT_POLLMASK;
 				if (file->f_op && file->f_op->poll)
 					mask = file->f_op->poll(file, *pwait);
diff -urN linux/include/asm-ppc/param.h linux-2.4.0-test10/include/asm-ppc/param.h
--- linux/include/asm-ppc/param.h	Sat Nov 27 18:42:33 1999
+++ linux-2.4.0-test10/include/asm-ppc/param.h	Tue Nov  7 07:11:23 2000
@@ -5,6 +5,8 @@
 #define HZ 100
 #endif
 
+#define CLOCKS_PER_SEC  HZ
+
 #define EXEC_PAGESIZE	4096
 
 #ifndef NGROUPS
diff -urN linux/include/linux/trace.h linux-2.4.0-test10/include/linux/trace.h
--- linux/include/linux/trace.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.0-test10/include/linux/trace.h	Wed Mar 28 16:35:46 2001
@@ -0,0 +1,396 @@
+/*
+ * linux/include/linux/trace.h
+ *
+ * Copyright (C) 1999, Karim Yaghmour
+ *
+ * This contains the necessary definitions for tracing the
+ * the system.
+ */
+
+#ifndef _LINUX_TRACE_H
+#define _LINUX_TRACE_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+/* Is kernel tracing enabled */
+#if defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE)
+
+/* Structure packing within the trace */
+#if LTT_UNPACKED_STRUCTS
+#define LTT_PACKED_STRUCT
+#else  /* if LTT_UNPACKED_STRUCTS */
+#define LTT_PACKED_STRUCT __attribute__ ((packed));
+#endif /* if LTT_UNPACKED_STRUCTS */
+
+/* The prototype of the tracer call (EventID, *EventStruct) */
+typedef int (*tracer_call) (uint8_t, void*);
+
+/* This structure contains all the information needed to be known
+   about the tracing module. */
+struct tracer
+{
+  /* The tracing routine itself */
+  tracer_call trace;
+
+  /* Fetch of eip origin of syscall */
+  int         fetch_syscall_eip_use_depth;  /* Use the given depth */
+  int         fetch_syscall_eip_use_bounds; /* Find eip in bounds */
+  int         syscall_eip_depth;            /* Call depth at which eip is fetched */
+  void*       syscall_lower_eip_bound;      /* Lower eip bound */
+  void*       syscall_upper_eip_bound;      /* Higher eip bound */
+};
+
+/* Maximal size a custom event can have */
+#define CUSTOM_EVENT_MAX_SIZE        8192
+
+/* String length limits for custom events creation */
+#define CUSTOM_EVENT_TYPE_STR_LEN      20
+#define CUSTOM_EVENT_DESC_STR_LEN     100
+#define CUSTOM_EVENT_FINAL_STR_LEN    200
+
+/* Description of custom event's data */
+typedef struct _event_data_desc
+{
+  int         notfixed LTT_PACKED_STRUCT;    /* Does this data have unfixed length? (0=fixed, 1=variable) */
+  int         length   LTT_PACKED_STRUCT;    /* What is the length of this data field */
+} event_data_desc;
+
+/* The functions to the tracer management code */
+int register_tracer
+       (tracer_call   /* The tracer function */);
+int unregister_tracer
+       (tracer_call   /* The tracer function */);
+int trace_set_config
+       (tracer_call   /* The tracer function */,
+	int           /* Use depth to fetch eip */,
+	int           /* Use bounds to fetch eip */,
+	int           /* Detph to fetch eip */,
+	void*         /* Lower bound eip address */,
+	void*         /* Upper bound eip address */);
+int trace_register_callback
+       (tracer_call   /* The callback to add */,
+	uint8_t       /* The event ID targeted */);
+int trace_unregister_callback
+       (tracer_call   /* The callback to remove */,
+	uint8_t       /* The event ID targeted */);
+int trace_get_config
+       (int*          /* Use depth to fetch eip */,
+	int*          /* Use bounds to fetch eip */,
+	int*          /* Detph to fetch eip */,
+	void**        /* Lower bound eip address */,
+	void**        /* Upper bound eip address */);
+int  trace_create_event
+       (char*            /* String describing event type */,
+	char*            /* String to format event description */,
+	event_data_desc* /* Table containing data formatting details */);
+void trace_destroy_event
+       (int           /* The event ID given by trace_create_event() */);
+void trace_reregister_custom_events
+       (void);
+int  trace_formatted_event
+       (int           /* The event ID given by trace_create_event() */,
+	...           /* The parameters to be printed out in the event string */);
+int  trace_raw_event
+       (int           /* The event ID given by trace_create_event() */,
+	int           /* The size of the raw data */,
+	void*         /* Pointer to the raw event data */);
+int  trace_event
+       (uint8_t       /* Event ID (as defined in this header file) */,
+	void*         /* Structure describing the event */);
+
+/* Generic macros */
+#define TRACE_EVENT(ID, DATA) trace_event(ID, DATA)
+
+/* Traced events */
+#define TRACE_EV_START           0    /* This is to mark the trace's start */
+#define TRACE_EV_SYSCALL_ENTRY   1    /* Entry in a given system call */
+#define TRACE_EV_SYSCALL_EXIT    2    /* Exit from a given system call */
+#define TRACE_EV_TRAP_ENTRY      3    /* Entry in a trap */
+#define TRACE_EV_TRAP_EXIT       4    /* Exit from a trap */
+#define TRACE_EV_IRQ_ENTRY       5    /* Entry in an irq */
+#define TRACE_EV_IRQ_EXIT        6    /* Exit from an irq */
+#define TRACE_EV_SCHEDCHANGE     7    /* Scheduling change */
+#define TRACE_EV_KERNEL_TIMER    8    /* The kernel timer routine has been called */
+#define TRACE_EV_SOFT_IRQ        9    /* Hit key part of soft-irq management */
+#define TRACE_EV_PROCESS        10    /* Hit key part of process management */
+#define TRACE_EV_FILE_SYSTEM    11    /* Hit key part of file system */
+#define TRACE_EV_TIMER          12    /* Hit key part of timer management */
+#define TRACE_EV_MEMORY         13    /* Hit key part of memory management */
+#define TRACE_EV_SOCKET         14    /* Hit key part of socket communication */
+#define TRACE_EV_IPC            15    /* Hit key part of System V IPC */
+#define TRACE_EV_NETWORK        16    /* Hit key part of network communication */
+
+#define TRACE_EV_BUFFER_START   17    /* Mark the begining of a trace buffer */
+#define TRACE_EV_BUFFER_END     18    /* Mark the ending of a trace buffer */
+#define TRACE_EV_NEW_EVENT      19    /* New event type */
+#define TRACE_EV_CUSTOM         20    /* Custom event */
+
+/* Number of traced events */
+#define TRACE_EV_MAX           TRACE_EV_CUSTOM
+
+/* Structures and macros for events */
+/*  TRACE_SYSCALL_ENTRY */
+typedef struct _trace_syscall_entry
+{
+  uint8_t   syscall_id LTT_PACKED_STRUCT;  /* Syscall entry number in entry.S */
+  uint32_t  address    LTT_PACKED_STRUCT;  /* Address from which call was made */
+} trace_syscall_entry;
+
+/*  TRACE_TRAP_ENTRY */
+typedef struct _trace_trap_entry
+{
+  uint16_t  trap_id    LTT_PACKED_STRUCT;  /* Trap number */
+  uint32_t  address    LTT_PACKED_STRUCT;  /* Address where trap occured */
+} trace_trap_entry;
+#define TRACE_TRAP_ENTRY(ID, EIP) \
+           do \
+           {\
+           trace_trap_entry trap_event;\
+           trap_event.trap_id = ID;\
+           trap_event.address = EIP;\
+           trace_event(TRACE_EV_TRAP_ENTRY, &trap_event);\
+	   } while(0);
+
+/*  TRACE_IRQ_ENTRY */
+typedef struct _trace_irq_entry
+{
+  uint8_t  irq_id    LTT_PACKED_STRUCT;      /* IRQ number */
+  uint8_t  kernel    LTT_PACKED_STRUCT;      /* Are we executing kernel code */
+} trace_irq_entry;
+#define TRACE_IRQ_ENTRY(ID, KERNEL) \
+           do \
+           {\
+           trace_irq_entry irq_entry;\
+           irq_entry.irq_id = ID;\
+           irq_entry.kernel = KERNEL;\
+           trace_event(TRACE_EV_IRQ_ENTRY, &irq_entry);\
+           } while(0);
+
+/*  TRACE_SCHEDCHANGE */ 
+typedef struct _trace_schedchange
+{
+  pid_t     out        LTT_PACKED_STRUCT;         /* Outgoing process */
+  pid_t     in         LTT_PACKED_STRUCT;         /* Incoming process */
+  uint32_t  out_state  LTT_PACKED_STRUCT;         /* Outgoing process' state */
+} trace_schedchange;
+#define TRACE_SCHEDCHANGE(OUT, IN, OUT_STATE) \
+           do \
+           {\
+           trace_schedchange sched_event;\
+           sched_event.out       = OUT;\
+           sched_event.in        = IN;\
+           sched_event.out_state = OUT_STATE; \
+           trace_event(TRACE_EV_SCHEDCHANGE, &sched_event);\
+           } while(0);
+
+/*  TRACE_SOFT_IRQ */
+#define TRACE_EV_SOFT_IRQ_BOTTOM_HALF        1  /* Conventional bottom-half */
+#define TRACE_EV_SOFT_IRQ_SOFT_IRQ           2  /* Real soft-irq */
+#define TRACE_EV_SOFT_IRQ_TASKLET_ACTION     3  /* Tasklet action */
+#define TRACE_EV_SOFT_IRQ_TASKLET_HI_ACTION  4  /* Tasklet hi-action */
+typedef struct _trace_soft_irq
+{
+  uint8_t   event_sub_id  LTT_PACKED_STRUCT;     /* Soft-irq event Id */
+  uint32_t  event_data    LTT_PACKED_STRUCT;     /* Data associated with event */
+} trace_soft_irq;
+#define TRACE_SOFT_IRQ(ID, DATA) \
+           do \
+           {\
+           trace_soft_irq soft_irq_event;\
+           soft_irq_event.event_sub_id = ID;\
+           soft_irq_event.event_data   = DATA;\
+           trace_event(TRACE_EV_SOFT_IRQ, &soft_irq_event);\
+	   } while(0);
+
+/*  TRACE_PROCESS */
+#define TRACE_EV_PROCESS_KTHREAD     1  /* Creation of a kernel thread */
+#define TRACE_EV_PROCESS_FORK        2  /* A fork or clone occured */
+#define TRACE_EV_PROCESS_EXIT        3  /* An exit occured */
+#define TRACE_EV_PROCESS_WAIT        4  /* A wait occured */
+#define TRACE_EV_PROCESS_SIGNAL      5  /* A signal has been sent */
+#define TRACE_EV_PROCESS_WAKEUP      6  /* Wake up a process */
+typedef struct _trace_process
+{
+  uint8_t   event_sub_id   LTT_PACKED_STRUCT;    /* Process event ID */
+  uint32_t  event_data1    LTT_PACKED_STRUCT;    /* Data associated with event */
+  uint32_t  event_data2    LTT_PACKED_STRUCT; 
+} trace_process;
+#define TRACE_PROCESS(ID, DATA1, DATA2) \
+           do \
+           {\
+           trace_process proc_event;\
+           proc_event.event_sub_id = ID;\
+           proc_event.event_data1 = DATA1;\
+           proc_event.event_data2 = DATA2;\
+           trace_event(TRACE_EV_PROCESS, &proc_event);\
+           } while(0);
+
+/*  TRACE_FILE_SYSTEM */
+#define TRACE_EV_FILE_SYSTEM_BUF_WAIT_START  1  /* Starting to wait for a data buffer */
+#define TRACE_EV_FILE_SYSTEM_BUF_WAIT_END    2  /* End to wait for a data buffer */
+#define TRACE_EV_FILE_SYSTEM_EXEC            3  /* An exec occured */
+#define TRACE_EV_FILE_SYSTEM_OPEN            4  /* An open occured */
+#define TRACE_EV_FILE_SYSTEM_CLOSE           5  /* A close occured */
+#define TRACE_EV_FILE_SYSTEM_READ            6  /* A read occured */
+#define TRACE_EV_FILE_SYSTEM_WRITE           7  /* A write occured */
+#define TRACE_EV_FILE_SYSTEM_SEEK            8  /* A seek occured */
+#define TRACE_EV_FILE_SYSTEM_IOCTL           9  /* An ioctl occured */
+#define TRACE_EV_FILE_SYSTEM_SELECT         10  /* A select occured */
+#define TRACE_EV_FILE_SYSTEM_POLL           11  /* A poll occured */
+typedef struct _trace_file_system
+{
+  uint8_t   event_sub_id   LTT_PACKED_STRUCT;    /* File system event ID */
+  uint32_t  event_data1    LTT_PACKED_STRUCT;    /* Event data */
+  uint32_t  event_data2    LTT_PACKED_STRUCT;    /* Event data 2 */
+  char*     file_name      LTT_PACKED_STRUCT;       /* Name of file operated on */
+} trace_file_system;
+#define TRACE_FILE_SYSTEM(ID, DATA1, DATA2, FILE_NAME) \
+           do \
+           {\
+           trace_file_system fs_event;\
+           fs_event.event_sub_id = ID;\
+           fs_event.event_data1  = DATA1;\
+           fs_event.event_data2  = DATA2;\
+           fs_event.file_name    = (char*)FILE_NAME;\
+           trace_event(TRACE_EV_FILE_SYSTEM, &fs_event);\
+           } while(0);
+
+/*  TRACE_TIMER */
+#define TRACE_EV_TIMER_EXPIRED      1  /* Timer expired */
+#define TRACE_EV_TIMER_SETITIMER    2  /* Setting itimer occurred */
+#define TRACE_EV_TIMER_SETTIMEOUT   3  /* Setting sched timeout occurred */
+typedef struct _trace_timer
+{
+  uint8_t   event_sub_id   LTT_PACKED_STRUCT;    /* Timer event ID */
+  uint8_t   event_sdata    LTT_PACKED_STRUCT;    /* Short data */
+  uint32_t  event_data1    LTT_PACKED_STRUCT;    /* Data associated with event */
+  uint32_t  event_data2    LTT_PACKED_STRUCT;     
+} trace_timer;
+#define TRACE_TIMER(ID, SDATA, DATA1, DATA2) \
+           do \
+           {\
+           trace_timer timer_event;\
+           timer_event.event_sub_id = ID;\
+           timer_event.event_sdata  = SDATA;\
+           timer_event.event_data1  = DATA1;\
+           timer_event.event_data2  = DATA2;\
+           trace_event(TRACE_EV_TIMER, &timer_event);\
+	   } while(0);
+
+/*  TRACE_MEMORY */
+#define TRACE_EV_MEMORY_PAGE_ALLOC        1  /* Allocating pages */
+#define TRACE_EV_MEMORY_PAGE_FREE         2  /* Freing pages */
+#define TRACE_EV_MEMORY_SWAP_IN           3  /* Swaping pages in */
+#define TRACE_EV_MEMORY_SWAP_OUT          4  /* Swaping pages out */
+#define TRACE_EV_MEMORY_PAGE_WAIT_START   5  /* Start to wait for page */
+#define TRACE_EV_MEMORY_PAGE_WAIT_END     6  /* End to wait for page */
+typedef struct _trace_memory
+{
+  uint8_t        event_sub_id   LTT_PACKED_STRUCT;    /* Memory event ID */
+  unsigned long  event_data     LTT_PACKED_STRUCT;    /* Data associated with event */
+} trace_memory;
+#define TRACE_MEMORY(ID, DATA) \
+           do \
+           {\
+           trace_memory memory_event;\
+           memory_event.event_sub_id = ID;\
+           memory_event.event_data   = DATA;\
+           trace_event(TRACE_EV_MEMORY, &memory_event);\
+           } while(0);
+
+/*  TRACE_SOCKET */
+#define TRACE_EV_SOCKET_CALL     1  /* A socket call occured */
+#define TRACE_EV_SOCKET_CREATE   2  /* A socket has been created */
+#define TRACE_EV_SOCKET_SEND     3  /* Data was sent to a socket */
+#define TRACE_EV_SOCKET_RECEIVE  4  /* Data was read from a socket */
+typedef struct _trace_socket
+{
+  uint8_t   event_sub_id   LTT_PACKED_STRUCT;    /* Socket event ID */
+  uint32_t  event_data1    LTT_PACKED_STRUCT;    /* Data associated with event */
+  uint32_t  event_data2    LTT_PACKED_STRUCT;    /* Data associated with event */
+} trace_socket;
+#define TRACE_SOCKET(ID, DATA1, DATA2) \
+           do \
+           {\
+           trace_socket socket_event;\
+           socket_event.event_sub_id = ID;\
+           socket_event.event_data1  = DATA1;\
+           socket_event.event_data2  = DATA2;\
+           trace_event(TRACE_EV_SOCKET, &socket_event);\
+           } while(0);
+
+/*  TRACE_IPC */
+#define TRACE_EV_IPC_CALL            1  /* A System V IPC call occured */
+#define TRACE_EV_IPC_MSG_CREATE      2  /* A message queue has been created */
+#define TRACE_EV_IPC_SEM_CREATE      3  /* A semaphore was created */
+#define TRACE_EV_IPC_SHM_CREATE      4  /* A shared memory segment has been created */
+typedef struct _trace_ipc
+{
+  uint8_t   event_sub_id   LTT_PACKED_STRUCT;    /* IPC event ID */
+  uint32_t  event_data1    LTT_PACKED_STRUCT;    /* Data associated with event */
+  uint32_t  event_data2    LTT_PACKED_STRUCT;    /* Data associated with event */
+} trace_ipc;
+#define TRACE_IPC(ID, DATA1, DATA2) \
+           do \
+           {\
+           trace_ipc ipc_event;\
+           ipc_event.event_sub_id = ID;\
+           ipc_event.event_data1  = DATA1;\
+           ipc_event.event_data2  = DATA2;\
+           trace_event(TRACE_EV_IPC, &ipc_event);\
+           } while(0);
+
+/*  TRACE_NETWORK */
+#define TRACE_EV_NETWORK_PACKET_IN   1  /* A packet came in */
+#define TRACE_EV_NETWORK_PACKET_OUT  2  /* A packet was sent */
+typedef struct _trace_network
+{
+  uint8_t  event_sub_id   LTT_PACKED_STRUCT;   /* Network event ID */
+  uint32_t event_data     LTT_PACKED_STRUCT;   /* Event data */
+} trace_network;
+#define TRACE_NETWORK(ID, DATA) \
+           do \
+           {\
+           trace_network net_event;\
+           net_event.event_sub_id = ID;\
+           net_event.event_data   = DATA;\
+           trace_event(TRACE_EV_NETWORK, &net_event);\
+           } while(0);
+
+/* Custom declared events */
+/* ***WARNING*** These structures should never be used as is, use the provided custom event creation
+                 and logging functions. */
+typedef struct _trace_new_event
+{
+  uint32_t         id                              LTT_PACKED_STRUCT;  /* Custom event ID */
+  char             type[CUSTOM_EVENT_TYPE_STR_LEN] LTT_PACKED_STRUCT;  /* Event type description */
+  char             desc[CUSTOM_EVENT_DESC_STR_LEN] LTT_PACKED_STRUCT;  /* Detailed event description */
+  uint32_t         has_strings                     LTT_PACKED_STRUCT;  /* Does the event description has strings */
+  uint32_t         data_size                       LTT_PACKED_STRUCT;  /* Size of event data, if fixed */
+  uint32_t         desc_size                       LTT_PACKED_STRUCT;  /* Size of the event description table */
+  event_data_desc* data_description                LTT_PACKED_STRUCT;  /* Event data description table */
+} trace_new_event;
+typedef struct _trace_custom
+{
+  uint32_t           id         LTT_PACKED_STRUCT;  /* Event ID */
+  uint32_t           data_size  LTT_PACKED_STRUCT;  /* Size of data recorded by event */
+  void*              data       LTT_PACKED_STRUCT;  /* Data recorded by event */
+} trace_custom;
+
+#else /* Kernel is configured without tracing */
+#define TRACE_EVENT(ID, DATA)
+#define TRACE_TRAP_ENTRY(ID, EIP)
+#define TRACE_IRQ_ENTRY(ID, KERNEL)
+#define TRACE_SCHEDCHANGE(OUT, IN, OUT_STATE)
+#define TRACE_SOFT_IRQ(ID, DATA)
+#define TRACE_PROCESS(ID, DATA1, DATA2)
+#define TRACE_FILE_SYSTEM(ID, DATA1, DATA2, FILE_NAME)
+#define TRACE_TIMER(ID, SDATA, DATA1, DATA2)
+#define TRACE_MEMORY(ID, DATA)
+#define TRACE_SOCKET(ID, DATA1, DATA2)
+#define TRACE_IPC(ID, DATA1, DATA2)
+#define TRACE_NETWORK(ID, DATA)
+#endif /* defined(CONFIG_TRACE) || defined(CONFIG_TRACE_MODULE) */
+
+#endif /* _LINUX_TRACE_H */
diff -urN linux/kernel/Makefile linux-2.4.0-test10/kernel/Makefile
--- linux/kernel/Makefile	Fri Jul 28 17:12:10 2000
+++ linux-2.4.0-test10/kernel/Makefile	Tue Nov  7 01:53:41 2000
@@ -30,6 +30,10 @@
 OX_OBJS += pm.o
 endif
 
+ifdef CONFIG_TRACE
+OX_OBJS += trace.o
+endif
+
 CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer
 
 include $(TOPDIR)/Rules.make
diff -urN linux/kernel/exit.c linux-2.4.0-test10/kernel/exit.c
--- linux/kernel/exit.c	Sun Sep 17 12:51:57 2000
+++ linux-2.4.0-test10/kernel/exit.c	Tue Nov  7 01:53:41 2000
@@ -13,6 +13,8 @@
 #include <linux/acct.h>
 #endif
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
@@ -437,6 +439,9 @@
 #ifdef CONFIG_BSD_PROCESS_ACCT
 	acct_process(code);
 #endif
+
+	TRACE_PROCESS(TRACE_EV_PROCESS_EXIT, 0, 0);
+
 	lock_kernel();
 	sem_exit();
 	__exit_mm(tsk);
@@ -480,6 +485,8 @@
 
 	if (options & ~(WNOHANG|WUNTRACED|__WNOTHREAD|__WCLONE|__WALL))
 		return -EINVAL;
+
+	TRACE_PROCESS(TRACE_EV_PROCESS_WAIT, pid, 0);
 
 	add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
diff -urN linux/kernel/fork.c linux-2.4.0-test10/kernel/fork.c
--- linux/kernel/fork.c	Tue Sep  5 17:48:59 2000
+++ linux-2.4.0-test10/kernel/fork.c	Tue Nov  7 01:53:41 2000
@@ -19,6 +19,8 @@
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 
+#include <linux/trace.h>
+
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
@@ -681,6 +683,9 @@
 
 	if (p->ptrace & PT_PTRACED)
 		send_sig(SIGSTOP, p, 1);
+
+	/* Trace the event  */
+	TRACE_PROCESS(TRACE_EV_PROCESS_FORK, retval, 0);
 
 	wake_up_process(p);		/* do this last */
 	++total_forks;
diff -urN linux/kernel/itimer.c linux-2.4.0-test10/kernel/itimer.c
--- linux/kernel/itimer.c	Thu Jun 29 13:07:36 2000
+++ linux-2.4.0-test10/kernel/itimer.c	Tue Nov  7 01:53:41 2000
@@ -10,6 +10,8 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 /*
@@ -95,6 +97,8 @@
 	struct task_struct * p = (struct task_struct *) __data;
 	unsigned long interval;
 
+	TRACE_TIMER(TRACE_EV_TIMER_EXPIRED, 0, 0, 0);
+
 	send_sig(SIGALRM, p, 1);
 	interval = p->it_real_incr;
 	if (interval) {
@@ -114,6 +118,7 @@
 	j = tvtojiffies(&value->it_value);
 	if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
 		return k;
+	TRACE_TIMER(TRACE_EV_TIMER_SETITIMER, which, i, j);
 	switch (which) {
 		case ITIMER_REAL:
 			del_timer_sync(&current->real_timer);
diff -urN linux/kernel/sched.c linux-2.4.0-test10/kernel/sched.c
--- linux/kernel/sched.c	Tue Oct 24 18:10:32 2000
+++ linux-2.4.0-test10/kernel/sched.c	Tue Nov  7 01:53:41 2000
@@ -26,6 +26,8 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
@@ -334,6 +336,8 @@
 {
 	unsigned long flags;
 
+	TRACE_PROCESS(TRACE_EV_PROCESS_WAKEUP, p->pid, p->state);
+
 	/*
 	 * We want the common case fall through straight, thus the goto.
 	 */
@@ -367,6 +371,7 @@
 {
 	struct task_struct * p = (struct task_struct *) __data;
 
+	TRACE_TIMER(TRACE_EV_TIMER_EXPIRED, 0, 0, 0);
 	wake_up_process(p);
 }
 
@@ -405,6 +410,8 @@
 		}
 	}
 
+	TRACE_TIMER(TRACE_EV_TIMER_SETTIMEOUT, 0, timeout, 0);
+
 	expire = timeout + jiffies;
 
 	init_timer(&timer);
@@ -635,6 +642,8 @@
 			mmdrop(oldmm);
 		}
 	}
+
+	TRACE_SCHEDCHANGE(prev->pid, next->pid, prev->state);
 
 	/*
 	 * This just switches the register state and the
diff -urN linux/kernel/signal.c linux-2.4.0-test10/kernel/signal.c
--- linux/kernel/signal.c	Thu Oct 12 17:19:32 2000
+++ linux-2.4.0-test10/kernel/signal.c	Tue Nov  7 01:53:41 2000
@@ -14,6 +14,8 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 /*
@@ -540,6 +542,8 @@
 	   the signal. */
 	if (sig < SIGRTMIN && sigismember(&t->pending.signal, sig))
 		goto out;
+
+	TRACE_PROCESS(TRACE_EV_PROCESS_SIGNAL, sig, t->pid);
 
 	ret = deliver_signal(sig, info, t);
 out:
diff -urN linux/kernel/softirq.c linux-2.4.0-test10/kernel/softirq.c
--- linux/kernel/softirq.c	Fri Sep 22 17:07:43 2000
+++ linux-2.4.0-test10/kernel/softirq.c	Tue Nov  7 01:53:41 2000
@@ -16,6 +16,8 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
+#include <linux/trace.h>
+
 /*
    - No shared variables, all the data are CPU local.
    - If a softirq needs serialization, let it serialize itself
@@ -73,8 +75,10 @@
 		mask &= ~active;
 
 		do {
-			if (active & 1)
+		  if (active & 1){
+		                TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_SOFT_IRQ, (h - softirq_vec));
 				h->action(h);
+		  }
 			h++;
 			active >>= 1;
 		} while (active);
@@ -139,6 +143,8 @@
 			if (atomic_read(&t->count) == 0) {
 				clear_bit(TASKLET_STATE_SCHED, &t->state);
 
+				TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_TASKLET_ACTION, (unsigned long) (t->func));
+			    
 				t->func(t->data);
 				/*
 				 * talklet_trylock() uses test_and_set_bit that imply
@@ -184,6 +190,8 @@
 			if (atomic_read(&t->count) == 0) {
 				clear_bit(TASKLET_STATE_SCHED, &t->state);
 
+				TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_TASKLET_HI_ACTION, (unsigned long) (t->func));
+
 				t->func(t->data);
 				tasklet_unlock(t);
 				continue;
@@ -252,8 +260,10 @@
 	if (!hardirq_trylock(cpu))
 		goto resched_unlock;
 
-	if (bh_base[nr])
+	if (bh_base[nr]){
+	        TRACE_SOFT_IRQ(TRACE_EV_SOFT_IRQ_BOTTOM_HALF, (nr));
 		bh_base[nr]();
+	}
 
 	hardirq_endlock(cpu);
 	spin_unlock(&global_bh_lock);
diff -urN linux/kernel/timer.c linux-2.4.0-test10/kernel/timer.c
--- linux/kernel/timer.c	Mon Oct 16 15:58:51 2000
+++ linux-2.4.0-test10/kernel/timer.c	Tue Nov  7 01:53:41 2000
@@ -23,6 +23,8 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 
+#include <linux/trace.h>
+
 #include <asm/uaccess.h>
 
 /*
@@ -668,6 +670,7 @@
 
 void timer_bh(void)
 {
+	TRACE_EVENT(TRACE_EV_KERNEL_TIMER, NULL);
 	update_times();
 	run_timer_list();
 }
diff -urN linux/kernel/trace.c linux-2.4.0-test10/kernel/trace.c
--- linux/kernel/trace.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.0-test10/kernel/trace.c	Sun Mar 25 02:31:18 2001
@@ -0,0 +1,633 @@
+/*
+ * linux/kernel/trace.c
+ *
+ * (C) Copyright 1999, 2000 - Karim Yaghmour (karym@opersys.com)
+ *
+ * This code is distributed under the GPL license
+ *
+ * Tracing management
+ *
+ */
+
+#include <linux/init.h>     /* For __init */
+#include <linux/trace.h>    /* Tracing definitions */
+#include <linux/errno.h>    /* Miscellaneous error codes */
+#include <linux/stddef.h>   /* NULL */
+#include <linux/malloc.h>   /* kmalloc() */
+#include <linux/module.h>   /* EXPORT_SYMBOL */
+
+/* Local variables */
+static int        tracer_registered = 0;   /* Is there a tracer registered */
+struct tracer *   tracer = NULL;           /* The registered tracer */
+
+/* Trace callback table entry */
+struct trace_callback_table_entry
+{
+  tracer_call                         Callback;    /* The callback function */
+
+  struct trace_callback_table_entry* Next;        /* Next entry */
+};
+
+/* Trace callback table */
+struct trace_callback_table_entry trace_callback_table[TRACE_EV_MAX];
+
+/* Custom event description */
+struct custom_event_desc
+{
+  /* The event itself */
+  trace_new_event              Event;
+
+  /* List links */
+  struct custom_event_desc*    Next;
+  struct custom_event_desc*    Prev;
+};
+
+/* Next event ID to be used */
+int next_event_id;
+
+/* Circular list of custom events */
+struct custom_event_desc  custom_events_head;
+struct custom_event_desc* custom_events;
+
+/* Circular list lock */
+rwlock_t custom_list_lock = RW_LOCK_UNLOCKED;
+
+/****************************************************
+ * Register the tracer to the kernel
+ * Return values :
+ *   0, all is OK
+ *   -EBUSY, there already is a registered tracer
+ *   -ENOMEM, couldn't allocate memory
+ ****************************************************/
+int register_tracer(tracer_call pmTraceFunction)
+{
+  /* Is there a tracer already registered */
+  if(tracer_registered == 1)
+    return -EBUSY;
+
+  /* Allocate memory for the tracer */
+  if((tracer = (struct tracer *) kmalloc(sizeof(struct tracer), GFP_KERNEL)) == NULL)
+    /* We couldn't allocate any memory */
+    return -ENOMEM;
+
+  /* There is a tracer registered */
+  tracer_registered = 1;
+
+  /* Set the tracer to the one being passed by the caller */
+  tracer->trace = pmTraceFunction;
+
+  /* Initialize the tracer settings */
+  tracer->fetch_syscall_eip_use_bounds = 0;
+  tracer->fetch_syscall_eip_use_depth  = 0;
+
+  /* Tell the caller that everything went fine */
+  return 0;
+}
+
+/***************************************************
+ * Unregister the currently registered tracer
+ * Return values :
+ *   0, all is OK
+ *   -ENOMEDIUM, there isn't a registered tracer
+ *   -ENXIO, unregestering wrong tracer
+ ***************************************************/
+int unregister_tracer(tracer_call pmTraceFunction)
+{
+  /* Is there a tracer already registered */
+  if(tracer_registered == 0)
+    /* Nothing to unregister */
+    return -ENOMEDIUM;
+
+  /* Is it the tracer that was registered */
+  if(tracer->trace == pmTraceFunction)
+    /* There isn't any tracer in here */
+    tracer_registered = 0;
+  else
+    return -ENXIO;
+
+  /* Free the memory used by the tracing structure */
+  kfree(tracer);
+  tracer = NULL;
+
+  /* Tell the caller that everything went OK */
+  return 0;
+}
+
+/*******************************************************
+ * Set the tracing configuration
+ * Parameters :
+ *   pmTraceFunction, the trace function.
+ *   pmFetchSyscallUseDepth, Use depth to fetch eip
+ *   pmFetchSyscallUseBounds, Use bounds to fetch eip
+ *   pmSyscallEipDepth, Detph to fetch eip
+ *   pmSyscallLowerBound, Lower bound eip address
+ *   pmSyscallUpperBound, Upper bound eip address
+ * Return values : 
+ *   0, all is OK 
+ *   -ENOMEDIUM, there isn't a registered tracer
+ *   -ENXIO, wrong tracer
+ *   -EINVAL, invalid configuration
+ *******************************************************/
+int trace_set_config(tracer_call pmTraceFunction,
+		     int         pmFetchSyscallUseDepth,
+		     int         pmFetchSyscallUseBounds,
+		     int         pmSyscallEipDepth,
+		     void*       pmSyscallLowerBound,
+		     void*       pmSyscallUpperBound)
+{
+  /* Is there a tracer already registered */
+  if(tracer_registered == 0)
+    return -ENOMEDIUM;
+
+  /* Is it the tracer that was registered */
+  if(tracer->trace != pmTraceFunction)
+    return -ENXIO;
+
+  /* Is this a valid configuration */
+  if((pmFetchSyscallUseDepth && pmFetchSyscallUseBounds)
+   ||(pmSyscallLowerBound > pmSyscallUpperBound)
+   ||(pmSyscallEipDepth < 0))
+    return -EINVAL;
+
+  /* Set the configuration */
+  tracer->fetch_syscall_eip_use_depth  = pmFetchSyscallUseDepth;
+  tracer->fetch_syscall_eip_use_bounds = pmFetchSyscallUseBounds;
+  tracer->syscall_eip_depth = pmSyscallEipDepth;
+  tracer->syscall_lower_eip_bound = pmSyscallLowerBound;
+  tracer->syscall_upper_eip_bound = pmSyscallUpperBound;
+
+  /* Tell the caller that everything was OK */
+  return 0;
+}
+
+/*******************************************************
+ * Get the tracing configuration
+ * Parameters :
+ *   pmFetchSyscallUseDepth, Use depth to fetch eip
+ *   pmFetchSyscallUseBounds, Use bounds to fetch eip
+ *   pmSyscallEipDepth, Detph to fetch eip
+ *   pmSyscallLowerBound, Lower bound eip address
+ *   pmSyscallUpperBound, Upper bound eip address
+ * Return values :
+ *   0, all is OK 
+ *   -ENOMEDIUM, there isn't a registered tracer
+ *******************************************************/
+int trace_get_config(int*        pmFetchSyscallUseDepth,
+		     int*        pmFetchSyscallUseBounds,
+		     int*        pmSyscallEipDepth,
+		     void**      pmSyscallLowerBound,
+		     void**      pmSyscallUpperBound)
+{
+  /* Is there a tracer already registered */
+  if(tracer_registered == 0)
+    return -ENOMEDIUM;
+
+  /* Get the configuration */
+  *pmFetchSyscallUseDepth  = tracer->fetch_syscall_eip_use_depth;
+  *pmFetchSyscallUseBounds = tracer->fetch_syscall_eip_use_bounds;
+  *pmSyscallEipDepth = tracer->syscall_eip_depth;
+  *pmSyscallLowerBound = tracer->syscall_lower_eip_bound;
+  *pmSyscallUpperBound = tracer->syscall_upper_eip_bound;
+
+  /* Tell the caller that everything was OK */
+  return 0;
+}
+
+/*******************************************************
+ * Register a callback function to be called on occurence
+ * of given event
+ * Parameters :
+ *   pmTraceFunction, the callback function.
+ *   pmEventID, the event ID to be monitored.
+ * Return values :
+ *   0, all is OK
+ *   -ENOMEM, unable to allocate memory for callback
+ *******************************************************/
+int trace_register_callback(tracer_call pmTraceFunction,
+			    uint8_t     pmEventID)
+{
+  struct trace_callback_table_entry*  pTCTEntry;
+
+  /* Search for an empty entry in the callback table */
+  for(pTCTEntry = &(trace_callback_table[pmEventID - 1]);
+      pTCTEntry->Next != NULL;
+      pTCTEntry = pTCTEntry->Next);
+
+  /* Allocate a new callback */
+  if((pTCTEntry->Next = kmalloc(sizeof(struct trace_callback_table_entry), GFP_ATOMIC)) == NULL)
+    return -ENOMEM;
+
+  /* Setup the new callback */
+  pTCTEntry->Next->Callback = pmTraceFunction;
+  pTCTEntry->Next->Next     = NULL;
+
+  /* Tell the caller everything is ok */
+  return 0;
+}
+
+/*******************************************************
+ * UnRegister a callback function.
+ * Parameters :
+ *   pmTraceFunction, the callback function.
+ *   pmEventID, the event ID that had to be monitored.
+ * Return values :
+ *   0, all is OK
+ *   -ENOMEDIUM, no such callback resigtered
+ *******************************************************/
+int trace_unregister_callback(tracer_call pmTraceFunction,
+			      uint8_t     pmEventID)
+{
+  struct trace_callback_table_entry*  pTCTEntry;  /* Pointer to trace callback table entry */
+  struct trace_callback_table_entry*  pTempEntry; /* Pointer to trace callback table entry */
+
+  /* Search for the callback in the callback table */
+  for(pTCTEntry = &(trace_callback_table[pmEventID - 1]);
+      ((pTCTEntry->Next != NULL) && (pTCTEntry->Next->Callback != pmTraceFunction));
+      pTCTEntry = pTCTEntry->Next);
+
+  /* Did we find anything */
+  if(pTCTEntry == NULL)
+    return -ENOMEDIUM;
+
+  /* Free the callback entry */
+  pTempEntry = pTCTEntry->Next->Next;
+  kfree(pTCTEntry->Next);
+  pTCTEntry->Next = pTempEntry;
+
+  /* Tell the caller everything is ok */
+  return 0;
+}
+
+/*******************************************************
+ * Create a new traceable event type
+ * Parameters :
+ *   pmEventType, string describing event type
+ *   pmEventDesc, string used to print out details
+ *   pmEventDataDescTable, Table containing information
+ *                       about each data describing the
+ *                       event.
+ * Return values :
+ *   New Event ID if all is OK
+ *   -ENOMEM, Unable to allocate new event
+ *******************************************************/
+int trace_create_event(char*            pmEventType,
+		       char*            pmEventDesc,
+		       event_data_desc* pmEventDataDescTable)
+{
+  int                       i;                  /* Generic index */
+  int                       lDescTableSize = 0; /* Size of data description table */
+  struct custom_event_desc* pNewEvent;          /* Newly created event */
+
+  /* Create event */
+  if((pNewEvent = (struct custom_event_desc*) kmalloc(sizeof(struct custom_event_desc), GFP_ATOMIC)) == NULL)
+    return -ENOMEM;
+
+  /* Set basic event properties */
+  if(pmEventType != NULL)
+    strncpy(pNewEvent->Event.type, pmEventType, CUSTOM_EVENT_TYPE_STR_LEN);
+  else
+    pNewEvent->Event.type[0] = '\0';
+  if(pmEventDesc != NULL)
+    strncpy(pNewEvent->Event.desc, pmEventDesc, CUSTOM_EVENT_DESC_STR_LEN);
+  else
+    pNewEvent->Event.desc[0] = '\0';
+  pNewEvent->Event.has_strings = 0;
+
+  /* Ensure that strings are bound */
+  pNewEvent->Event.type[CUSTOM_EVENT_TYPE_STR_LEN - 1] = '\0';
+  pNewEvent->Event.type[CUSTOM_EVENT_DESC_STR_LEN - 1] = '\0';
+
+  /* Is there a event data description table */
+  if(pmEventDataDescTable != NULL)
+    {
+    /* Go through description table */
+    for(i = 0;
+	(pmEventDataDescTable[i].notfixed != 0) ||
+	(pmEventDataDescTable[i].length != 0);
+	i++)
+      {
+      /* Is this data type of fixed length */
+      if(pmEventDataDescTable[i].notfixed == 1)
+	pNewEvent->Event.has_strings = 1;
+
+      /* Update the data size */
+      pNewEvent->Event.data_size += pmEventDataDescTable[i].length;
+
+      /* Update data description table size */
+      lDescTableSize += sizeof(event_data_desc);
+      }
+
+    /* Add the size of the terminating entry */
+    lDescTableSize += sizeof(event_data_desc);
+
+    /* Set data description size */
+    pNewEvent->Event.desc_size = lDescTableSize;
+
+    /* Create space to hold data description table */
+    if((pNewEvent->Event.data_description = (event_data_desc*) kmalloc(lDescTableSize, GFP_ATOMIC)) == NULL)
+      {
+      /* Free the already allocated space and return an error */
+      kfree(pNewEvent);
+      return -ENOMEM;
+      }
+
+    /* Copy event description table */
+    memcpy(pNewEvent->Event.data_description, pmEventDataDescTable, lDescTableSize);
+    }
+  else
+    {
+    /* There is no custom data provided with this event */
+    pNewEvent->Event.has_strings = 0;
+    pNewEvent->Event.data_size = 0;
+    pNewEvent->Event.desc_size = 0;
+    pNewEvent->Event.data_description = NULL;
+    }
+
+  /* Give the new event a unique event ID */
+  pNewEvent->Event.id = next_event_id;
+  next_event_id++;
+
+  /* Insert new event in event list */
+  write_lock(&custom_list_lock);
+  pNewEvent->Next = custom_events;
+  pNewEvent->Prev = custom_events->Prev;
+  custom_events->Prev->Next = pNewEvent;
+  custom_events->Prev = pNewEvent;
+  write_unlock(&custom_list_lock);
+
+  /* Log the event creation event */
+  trace_event(TRACE_EV_NEW_EVENT, &(pNewEvent->Event));
+
+  /* Return new event ID */
+  return pNewEvent->Event.id;
+}
+
+/*******************************************************
+ * Destroy a created event type
+ * Parameters :
+ *   pmEventID, the Id returned by trace_create_event()
+ * Return values :
+ *   NONE
+ *******************************************************/
+void trace_destroy_event(int pmEventID)
+{
+  struct custom_event_desc*   pEventDesc;   /* Generic event description pointer */
+
+  /* Lock the table for writting */
+  write_lock(&custom_list_lock);
+
+  /* Go through the event description list */
+  for(pEventDesc = custom_events->Next;
+      pEventDesc != custom_events;
+      pEventDesc = pEventDesc->Next)
+    if(pEventDesc->Event.id == pmEventID)
+      break;
+
+  /* If we found something */
+  if(pEventDesc != custom_events)
+    {
+    /* Remove the event fromt the list */
+    pEventDesc->Next->Prev = pEventDesc->Prev;
+    pEventDesc->Prev->Next = pEventDesc->Next;
+
+    /* Free the memory used by this event */
+    kfree(pEventDesc->Event.data_description);
+    kfree(pEventDesc);
+    }
+
+  /* Unlock the table for writting */
+  write_unlock(&custom_list_lock);
+}
+
+/*******************************************************
+ * Relog the declarations of custom events. This is
+ * necessary to make sure that even though the event
+ * creation might not have taken place during a trace,
+ * that all custom events be part of all traces. Hence,
+ * if a custom event occurs during a trace, we can be
+ * sure that it's definition is part of the trace.
+ * Parameters :
+ *    NONE
+ * Return values :
+ *    NONE
+ *******************************************************/
+void trace_reregister_custom_events(void)
+{
+  struct custom_event_desc*   pEventDesc;   /* Generic event description pointer */
+
+  /* Lock the table for reading */
+  read_lock(&custom_list_lock);
+
+  /* Go through the event description list */
+  for(pEventDesc = custom_events->Next;
+      pEventDesc != custom_events;
+      pEventDesc = pEventDesc->Next)
+    /* Log the event creation event */
+    trace_event(TRACE_EV_NEW_EVENT, &(pEventDesc->Event));
+
+  /* Unlock the table for reading */
+  read_unlock(&custom_list_lock);
+}
+
+/*******************************************************
+ * Trace a formatted event
+ * Parameters :
+ *   pmEventID, the event Id provided upon creation
+ *   ..., printf-like data that will be used to fill the
+ *        event string.
+ * Return values :
+ *   0, all is OK
+ *   -ENOMEDIUM, there isn't a registered tracer or this
+ *               event doesn't exist.
+ *   -EBUSY, tracing hasn't started yet
+ *******************************************************/
+int trace_formatted_event(int pmEventID, ...)
+{
+  int                         lStringSize;  /* Size of the string outputed by vsprintf() */
+  char                        lString[CUSTOM_EVENT_FINAL_STR_LEN];  /* Final formatted string */
+  va_list                     lVarArgList;  /* Variable argument list */
+  trace_custom                lCustom;      /* Custom event */
+  struct custom_event_desc*   pEventDesc;   /* Generic event description pointer */
+
+  /* Lock the table for reading */
+  read_lock(&custom_list_lock);
+
+  /* Go through the event description list */
+  for(pEventDesc = custom_events->Next;
+      pEventDesc != custom_events;
+      pEventDesc = pEventDesc->Next)
+    if(pEventDesc->Event.id == pmEventID)
+      break;
+
+  /* If we haven't found anything */
+  if(pEventDesc == custom_events)
+    {
+    /* Unlock the table for reading */
+    read_unlock(&custom_list_lock);
+
+    /* No such thing */
+    return -ENOMEDIUM;
+    }
+
+  /* Set custom event Id */
+  lCustom.id = pmEventID;
+
+  /* Initialize variable argument list access */
+  va_start(lVarArgList, pmEventID);
+
+  /* Print the description out to the temporary buffer */
+  lStringSize = vsprintf(lString, pEventDesc->Event.desc, lVarArgList);
+
+  /* Unlock the table for reading */
+  read_unlock(&custom_list_lock);
+
+  /* Facilitate return to caller */
+  va_end(lVarArgList);
+
+  /* Set the size of the event */
+  lCustom.data_size = lStringSize + 1;
+
+  /* Set the pointer to the event data */
+  lCustom.data = lString;
+
+  /* Log the custom event */
+  return trace_event(TRACE_EV_CUSTOM, &lCustom);
+}
+
+/*******************************************************
+ * Trace a raw event
+ * Parameters :
+ *   pmEventID, the event Id provided upon creation
+ *   pmEventSize, the size of the data provided
+ *   pmEventData, data buffer describing event
+ * Return values :
+ *   0, all is OK
+ *   -ENOMEDIUM, there isn't a registered tracer or this
+ *               event doesn't exist.
+ *   -EBUSY, tracing hasn't started yet
+ *******************************************************/
+int trace_raw_event(int pmEventID, int pmEventSize, void* pmEventData)
+{
+  trace_custom                lCustom;      /* Custom event */
+  struct custom_event_desc*   pEventDesc;   /* Generic event description pointer */
+
+  /* Lock the table for reading */
+  read_lock(&custom_list_lock);
+
+  /* Go through the event description list */
+  for(pEventDesc = custom_events->Next;
+      pEventDesc != custom_events;
+      pEventDesc = pEventDesc->Next)
+    if(pEventDesc->Event.id == pmEventID)
+      break;
+
+  /* Unlock the table for reading */
+  read_unlock(&custom_list_lock);
+
+  /* If we haven't found anything */
+  if(pEventDesc == custom_events)
+    /* No such thing */
+    return -ENOMEDIUM;
+
+  /* Set custom event Id */
+  lCustom.id = pmEventID;
+
+  /* Set the data size */
+  if(pmEventSize <= CUSTOM_EVENT_MAX_SIZE)
+    lCustom.data_size = pmEventSize;
+  else
+    lCustom.data_size = CUSTOM_EVENT_MAX_SIZE;
+
+  /* Set the pointer to the event data */
+  lCustom.data = pmEventData;
+
+  /* Log the custom event */
+  return trace_event(TRACE_EV_CUSTOM, &lCustom);
+}
+
+/*******************************************************
+ * Trace an event
+ * Parameters :
+ *   pmEventID, the event's ID (check out trace.h)
+ *   pmEventStruct, the structure describing the event
+ * Return values :
+ *   0, all is OK
+ *   -ENOMEDIUM, there isn't a registered tracer
+ *   -EBUSY, tracing hasn't started yet
+ *******************************************************/
+int trace_event(uint8_t  pmEventID, 
+       	        void*    pmEventStruct)
+{
+  int                                 lRetValue; /* The return value */
+  struct trace_callback_table_entry*  pTCTEntry; /* Pointer to trace callback table entry */
+
+  /* Is there a tracer registered */
+  if(tracer_registered != 1)
+    lRetValue = -ENOMEDIUM;
+  else
+    /* Call the tracer */
+    lRetValue = tracer->trace(pmEventID, pmEventStruct);
+
+  /* Is this a native event */
+  if(pmEventID <= TRACE_EV_MAX)
+    {
+    /* Are there any callbacks to call */
+    if(trace_callback_table[pmEventID - 1].Next != NULL)
+      {
+      /* Call all the callbacks linked to this event */
+      for(pTCTEntry = trace_callback_table[pmEventID - 1].Next;
+	  pTCTEntry != NULL;
+	  pTCTEntry = pTCTEntry->Next)
+	pTCTEntry->Callback(pmEventID, pmEventStruct);
+      }
+    }
+
+  /* Give the return value */
+  return lRetValue;
+}
+
+/*******************************************************
+ * Initialize trace facility
+ * Parameters :
+ *    NONE
+ * Return values :
+ *    NONE
+ *******************************************************/
+static int __init trace_init(void)
+{
+  int i;  /* Generic index */
+
+  /* Initialize callback table */
+  for(i = 0; i < TRACE_EV_MAX; i++)
+    {
+    trace_callback_table[i].Callback = NULL;
+    trace_callback_table[i].Next     = NULL;
+    }
+
+  /* Next event ID to be used */
+  next_event_id = TRACE_EV_MAX + 1;
+
+  /* Initialize custom events list */
+  custom_events = &custom_events_head;
+  custom_events->Next = custom_events;
+  custom_events->Prev = custom_events;
+
+  /* Everything is OK */
+  return 0;
+}
+
+module_init(trace_init);
+
+/* Export symbols so that can be visible from outside this file */
+EXPORT_SYMBOL(register_tracer);
+EXPORT_SYMBOL(unregister_tracer);
+EXPORT_SYMBOL(trace_set_config);
+EXPORT_SYMBOL(trace_get_config);
+EXPORT_SYMBOL(trace_register_callback);
+EXPORT_SYMBOL(trace_unregister_callback);
+EXPORT_SYMBOL(trace_create_event);
+EXPORT_SYMBOL(trace_destroy_event);
+EXPORT_SYMBOL(trace_reregister_custom_events);
+EXPORT_SYMBOL(trace_formatted_event);
+EXPORT_SYMBOL(trace_raw_event);
+EXPORT_SYMBOL(trace_event);
diff -urN linux/mm/filemap.c linux-2.4.0-test10/mm/filemap.c
--- linux/mm/filemap.c	Mon Oct 30 18:27:16 2000
+++ linux-2.4.0-test10/mm/filemap.c	Tue Nov  7 01:53:41 2000
@@ -23,6 +23,8 @@
 #include <linux/init.h>
 #include <linux/mm.h>
 
+#include <linux/trace.h>
+
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/mman.h>
@@ -495,10 +497,12 @@
 		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
 		if (!PageLocked(page))
 			break;
+		TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_WAIT_START, 0);
 		run_task_queue(&tq_disk);
 		schedule();
 	} while (PageLocked(page));
 	tsk->state = TASK_RUNNING;
+	TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_WAIT_END, 0);
 	remove_wait_queue(&page->wait, &wait);
 }
 
diff -urN linux/mm/memory.c linux-2.4.0-test10/mm/memory.c
--- linux/mm/memory.c	Mon Oct 30 17:32:57 2000
+++ linux-2.4.0-test10/mm/memory.c	Tue Nov  7 01:53:41 2000
@@ -47,6 +47,7 @@
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 
+#include <linux/trace.h>
 
 unsigned long max_mapnr;
 unsigned long num_physpages;
@@ -1063,6 +1064,7 @@
 	pte_t pte;
 
 	if (!page) {
+	        TRACE_MEMORY(TRACE_EV_MEMORY_SWAP_IN, address);
 		lock_kernel();
 		swapin_readahead(entry);
 		page = read_swap_cache(entry);
diff -urN linux/mm/page_alloc.c linux-2.4.0-test10/mm/page_alloc.c
--- linux/mm/page_alloc.c	Mon Oct 16 18:25:45 2000
+++ linux-2.4.0-test10/mm/page_alloc.c	Tue Nov  7 01:53:41 2000
@@ -17,6 +17,8 @@
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 
+#include <linux/trace.h>
+
 int nr_swap_pages;
 int nr_active_pages;
 int nr_inactive_dirty_pages;
@@ -99,6 +101,8 @@
 	if (PageInactiveClean(page))
 		BUG();
 
+	TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_FREE, order);
+
 	page->flags &= ~(1<<PG_referenced);
 	page->age = PAGE_AGE_START;
 	
@@ -540,6 +544,7 @@
 	page = alloc_pages(gfp_mask, order);
 	if (!page)
 		return 0;
+	TRACE_MEMORY(TRACE_EV_MEMORY_PAGE_ALLOC, order);
 	return (unsigned long) page_address(page);
 }
 
diff -urN linux/mm/vmscan.c linux-2.4.0-test10/mm/vmscan.c
--- linux/mm/vmscan.c	Fri Oct 27 13:59:11 2000
+++ linux-2.4.0-test10/mm/vmscan.c	Tue Nov  7 01:53:41 2000
@@ -22,6 +22,8 @@
 #include <linux/highmem.h>
 #include <linux/file.h>
 
+#include <linux/trace.h>
+
 #include <asm/pgalloc.h>
 
 /*
@@ -198,6 +200,8 @@
 	set_pte(page_table, swp_entry_to_pte(entry));
 	flush_tlb_page(vma, address);
 	spin_unlock(&mm->page_table_lock);
+
+	TRACE_MEMORY(TRACE_EV_MEMORY_SWAP_OUT, (unsigned long) page);
 
 	/* OK, do a physical asynchronous write to swap.  */
 	rw_swap_page(WRITE, page, 0);
diff -urN linux/net/core/dev.c linux-2.4.0-test10/net/core/dev.c
--- linux/net/core/dev.c	Fri Oct 27 14:03:14 2000
+++ linux-2.4.0-test10/net/core/dev.c	Tue Nov  7 01:53:41 2000
@@ -96,6 +96,9 @@
 #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
 #endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+
+#include <linux/trace.h>
+
 #ifdef CONFIG_PLIP
 extern int plip_init(void);
 #endif
@@ -888,6 +891,8 @@
 	struct net_device *dev = skb->dev;
 	struct Qdisc  *q;
 
+	TRACE_NETWORK(TRACE_EV_NETWORK_PACKET_OUT, skb->protocol);
+
 	/* Grab device queue */
 	spin_lock_bh(&dev->queue_lock);
 	q = dev->qdisc;
@@ -1316,6 +1321,8 @@
 			break;
 
 		skb_bond(skb);
+
+		TRACE_NETWORK(TRACE_EV_NETWORK_PACKET_IN, skb->protocol);
 
 #ifdef CONFIG_NET_FASTROUTE
 		if (skb->pkt_type == PACKET_FASTROUTE) {
diff -urN linux/net/socket.c linux-2.4.0-test10/net/socket.c
--- linux/net/socket.c	Tue Oct 24 00:59:04 2000
+++ linux-2.4.0-test10/net/socket.c	Tue Nov  7 01:53:41 2000
@@ -72,6 +72,8 @@
 #include <linux/cache.h>
 #include <linux/module.h>
 
+#include <linux/trace.h>
+
 #if defined(CONFIG_KMOD) && defined(CONFIG_NET)
 #include <linux/kmod.h>
 #endif
@@ -505,6 +507,8 @@
 	int err;
 	struct scm_cookie scm;
 
+	TRACE_SOCKET(TRACE_EV_SOCKET_SEND, sock->type, size);
+
 	err = scm_send(sock, msg, &scm);
 	if (err >= 0) {
 		err = sock->ops->sendmsg(sock, msg, size, &scm);
@@ -519,6 +523,8 @@
 
 	memset(&scm, 0, sizeof(scm));
 
+	TRACE_SOCKET(TRACE_EV_SOCKET_RECEIVE, sock->type, size);
+
 	size = sock->ops->recvmsg(sock, msg, size, flags, &scm);
 	if (size >= 0)
 		scm_recv(sock, msg, &scm, flags);
@@ -901,6 +907,8 @@
 	if (retval < 0)
 		goto out_release;
 
+	TRACE_SOCKET(TRACE_EV_SOCKET_CREATE, retval, type);
+
 out:
 	/* It may be already another descriptor 8) Not kernel problem. */
 	return retval;
@@ -1534,6 +1542,8 @@
 		
 	a0=a[0];
 	a1=a[1];
+
+	TRACE_SOCKET(TRACE_EV_SOCKET_CALL, call, a0);
 	
 	switch(call) 
 	{
