linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] 2/8 LTT for 2.5.34: Trace driver
@ 2002-09-10 18:16 Karim Yaghmour
  0 siblings, 0 replies; only message in thread
From: Karim Yaghmour @ 2002-09-10 18:16 UTC (permalink / raw)
  To: linux-kernel; +Cc: LTT-Dev


This is LTT's trace driver. This patch adds the following files:
drivers/trace/Config.help
drivers/trace/Config.in
drivers/trace/tracer.c
drivers/trace/tracer.h

The trace driver uses the rvmalloc/rvfree couple to allocate a mem
region it can remap to the daemon's address space.

diff -urN linux-2.5.34/drivers/Makefile linux-2.5.34-ltt/drivers/Makefile
--- linux-2.5.34/drivers/Makefile	Mon Sep  9 13:35:15 2002
+++ linux-2.5.34-ltt/drivers/Makefile	Mon Sep  9 19:06:34 2002
@@ -41,5 +41,6 @@
 obj-$(CONFIG_BLUEZ)		+= bluetooth/
 obj-$(CONFIG_HOTPLUG_PCI)	+= hotplug/
 obj-$(CONFIG_ISDN_BOOL)		+= isdn/
+obj-$(CONFIG_TRACE)		+= trace/
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.5.34/drivers/trace/Config.help linux-2.5.34-ltt/drivers/trace/Config.help
--- linux-2.5.34/drivers/trace/Config.help	Wed Dec 31 19:00:00 1969
+++ linux-2.5.34-ltt/drivers/trace/Config.help	Mon Sep  9 19:06:34 2002
@@ -0,0 +1,36 @@
+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
diff -urN linux-2.5.34/drivers/trace/Config.in linux-2.5.34-ltt/drivers/trace/Config.in
--- linux-2.5.34/drivers/trace/Config.in	Wed Dec 31 19:00:00 1969
+++ linux-2.5.34-ltt/drivers/trace/Config.in	Mon Sep  9 19:06:34 2002
@@ -0,0 +1,4 @@
+mainmenu_option next_comment
+comment 'Kernel tracing'
+tristate 'Kernel events tracing support' CONFIG_TRACE
+endmenu
diff -urN linux-2.5.34/drivers/trace/Makefile linux-2.5.34-ltt/drivers/trace/Makefile
--- linux-2.5.34/drivers/trace/Makefile	Wed Dec 31 19:00:00 1969
+++ linux-2.5.34-ltt/drivers/trace/Makefile	Mon Sep  9 19:06:34 2002
@@ -0,0 +1,17 @@
+#
+# 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 := built-in.o
+
+# Is it loaded as a module or as part of the kernel
+obj-$(CONFIG_TRACE) = tracer.o
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.5.34/drivers/trace/tracer.c linux-2.5.34-ltt/drivers/trace/tracer.c
--- linux-2.5.34/drivers/trace/tracer.c	Wed Dec 31 19:00:00 1969
+++ linux-2.5.34-ltt/drivers/trace/tracer.c	Tue Sep 10 01:18:53 2002
@@ -0,0 +1,1308 @@
+/*
+ * linux/drivers/trace/tracer.c
+ *
+ * (C) Copyright, 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * Contains the code for the kernel tracing driver (tracer for short).
+ *
+ * Author:
+ *    Karim Yaghmour (karim@opersys.com)
+ *
+ * Changelog:
+ *    03/12/01, Added user event support.
+ *    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 10 
+ *    milli-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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/trace.h>
+#include <linux/wrapper.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+
+#include <asm/io.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/trace.h>
+
+#include "tracer.h"
+
+/* Module information */
+MODULE_AUTHOR("Karim Yaghmour (karim@opersys.com)");
+MODULE_DESCRIPTION("Linux Trace Toolkit (LTT) kernel tracing driver");
+MODULE_LICENSE("GPL");
+
+/*  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 u32		sBufSize;		/* Buffer sizes */
+static u32		sAllocSize;		/* Size of buffers allocated */
+static u32		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 */
+
+/*  Large data components allocated at load time */
+static char *sUserEventData = NULL;		/* The data associated with a user event */
+
+
+/* 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 */ ,
+	sizeof(trace_change_mask)	/* TRACE_CHANGE_MASK */
+};
+
+/* 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,
+};
+
+/* This inspired by rtai/shmem */
+#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE
+
+/* \begin{Code inspired from BTTV driver} */
+
+/* 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 kva, ret;
+
+	kva = (unsigned long) page_address(vmalloc_to_page((void *) adr));
+	kva |= adr & (PAGE_SIZE - 1);	/* restore the offset */
+	ret = __pa(kva);
+	return ret;
+}
+
+static void *rvmalloc(unsigned long size)
+{
+	void *mem;
+	unsigned long adr;
+
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size);	/* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		mem_map_reserve(vmalloc_to_page((void *) adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+
+	return mem;
+}
+
+static void rvfree(void *mem, unsigned long size)
+{
+	unsigned long adr;
+
+	if (!mem)
+		return;
+
+	adr = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *) adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vfree(mem);
+}
+
+static int tracer_mmap_region(struct vm_area_struct *vma,
+			      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(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+			return -EAGAIN;
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	return 0;
+}
+/* \end{Code inspired from BTTV driver} */
+
+/**
+ *	tracer_write_to_buffer: - Write data to destination buffer
+ *
+ *	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);
+
+/**
+ *	trace: - Tracing function per se.
+ *	@pmEventID: ID of event as defined in linux/trace.h
+ *	@pmEventStruct: struct describing the event
+ *
+ *	Returns: 
+ *	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 process service routine.
+ */
+int trace(u8 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 */
+	u8 lCPUID;			/* CPUID of currently runing process */
+	uint16_t lDataSize;		/* Size of tracing data */
+	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 */
+	struct task_struct *pIncomingProcess = NULL;	/* Pointer to incoming process */
+
+	/* Is there a tracing daemon */
+	if (sDaemonTaskStruct == NULL)
+		return -ENODEV;
+
+	/* Is this the exit of a process? */
+	if ((pmEventID == TRACE_EV_PROCESS) &&
+	    (pmEventStruct != NULL) &&
+	    ((((trace_process *) pmEventStruct)->event_sub_id) == TRACE_EV_PROCESS_EXIT))
+		trace_destroy_owners_events(current->pid);
+
+	/* Do we trace the event */
+	if ((sTracerStarted == TRUE) || (pmEventID == TRACE_EV_START) || (pmEventID == TRACE_EV_BUFFER_START))
+		goto TraceEvent;
+
+	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)) {
+		/* Is this a scheduling change */
+		if (pmEventID == TRACE_EV_SCHEDCHANGE) {
+			/* Get pointer to incoming process */
+			pIncomingProcess = (struct task_struct *) (((trace_schedchange *) pmEventStruct)->in);
+
+			/* Set PID information in schedchange event */
+			(((trace_schedchange *) pmEventStruct)->in) = pIncomingProcess->pid;
+		}
+		/* Are we monitoring a particular process */
+		if ((sTracingPID == TRUE) && (current->pid != sTracedPID)) {
+			/* Record this event if it is the scheduling change bringing in the traced PID */
+			if (pIncomingProcess == NULL)
+				return 0;
+			else if (pIncomingProcess->pid != sTracedPID)
+				return 0;
+		}
+		/* Are we monitoring a particular process group */
+		if ((sTracingPGRP == TRUE) && (current->pgrp != sTracedPGRP)) {
+			/* Record this event if it is the scheduling change bringing in a process of the traced PGRP */
+			if (pIncomingProcess == NULL)
+				return 0;
+			else if (pIncomingProcess->pgrp != sTracedPGRP)
+				return 0;
+		}
+		/* Are we monitoring the processes of a given group of users */
+		if ((sTracingGID == TRUE) && (current->egid != sTracedGID)) {
+			/* Record this event if it is the scheduling change bringing in a process of the traced GID */
+			if (pIncomingProcess == NULL)
+				return 0;
+			else if (pIncomingProcess->egid != sTracedGID)
+				return 0;
+		}
+		/* Are we monitoring the processes of a given user */
+		if ((sTracingUID == TRUE) && (current->euid != sTracedUID)) {
+			/* Record this event if it is the scheduling change bringing in a process of the traced UID */
+			if (pIncomingProcess == NULL)
+				return 0;
+			else if (pIncomingProcess->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 begining and update size variables */
+				lVarDataBeg = ((trace_file_system *) pmEventStruct)->file_name;
+				lVarDataLen = ((trace_file_system *) pmEventStruct)->event_data2 + 1;
+				lDataSize += (uint16_t) lVarDataLen;
+			}
+			break;
+
+		/* Logging of a custom event */
+		case TRACE_EV_CUSTOM:
+			lVarDataBeg = ((trace_custom *) pmEventStruct)->data;
+			lVarDataLen = ((trace_custom *) pmEventStruct)->data_size;
+			lDataSize += (uint16_t) 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);
+
+	return 0;
+}
+
+/**
+ *	tracer_switch_buffers: - Switches between read and write buffers.
+ *	@pmTime: current time.
+ *
+ *	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.
+ *
+ *	No return values.
+ *
+ *	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 */
+	u8 lEventID;			/* Event ID of last event */
+	u8 lCPUID;			/* CPUID of currently runing process */
+	uint16_t lDataSize;		/* Size of tracing data */
+	u32 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 */
+	*((u32 *) (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));
+}
+
+/**
+ *	tracer_ioctl: - "Ioctl" file op
+ *
+ *	@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
+ *
+ *	Returns:
+ *	>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
+ *	-EFAULT, unable to access user space 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)
+{
+	int lRetValue;			/* Function return value */
+	int lDevMinor;			/* Device minor number */
+	int lNewUserEventID;		/* ID of newly created user event */
+	trace_start lStartEvent;	/* Event marking the begining of the trace */
+	unsigned long int lFlags;	/* CPU flags for lock */
+	trace_custom lUserEvent;	/* The user event to be logged */
+	trace_change_mask lTraceMask;	/* Event mask */
+	trace_new_event lNewUserEvent;	/* The event to be created for the user */
+	trace_buffer_start lStartBufferEvent;	/* Start of the new buffer event */
+
+#if 0
+	printk("Tracer: Command %d \n", pmCmd);
+#endif
+
+	/* Get device's minor number */
+	lDevMinor = minor(pmInode->i_rdev) & 0x0f;
+
+	/* If the tracer is started, the daemon can't modify the configuration */
+	if ((lDevMinor == 0)
+	    && (sTracerStarted == TRUE) && (pmCmd != TRACER_STOP) && (pmCmd != TRACER_DATA_COMITTED))
+		return -EBUSY;
+
+	/* Only some operations are permitted to user processes trying to log events */
+	if ((lDevMinor == 1)
+	    && (pmCmd != TRACER_CREATE_USER_EVENT)
+	    && (pmCmd != TRACER_DESTROY_USER_EVENT)
+	    && (pmCmd != TRACER_TRACE_USER_EVENT)
+	    && (pmCmd != TRACER_SET_EVENT_MASK)
+	    && (pmCmd != TRACER_GET_EVENT_MASK))
+		return -ENOSYS;
+
+	/* 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);
+		ltt_set_bit(TRACE_EV_CHANGE_MASK, &sTracedEvents);
+		ltt_set_bit(TRACE_EV_CHANGE_MASK, &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;
+		lStartEvent.ArchType = TRACE_ARCH_TYPE;
+		lStartEvent.ArchVariant = TRACE_ARCH_VARIANT;
+		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);
+
+		/* Start tapping into Linux's syscall flow */
+		syscall_entry_trace_active = ltt_test_bit(TRACE_EV_SYSCALL_ENTRY, &sTracedEvents);
+		syscall_exit_trace_active  = ltt_test_bit(TRACE_EV_SYSCALL_EXIT, &sTracedEvents);
+
+		/* We can start tracing */
+		sTracerStarted = TRUE;
+
+		/* Reregister custom trace events created earlier */
+		trace_reregister_custom_events();
+		break;
+
+	/* Stop the tracer */
+	case TRACER_STOP:
+		/* Stop tracing */
+		sTracerStarted = FALSE;
+
+		/* Stop interrupting the normal flow of system calls */
+		syscall_entry_trace_active = 0;
+		syscall_exit_trace_active  = 0;
+
+		/* 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 upper bound */
+		sUpperEIPBound = (void *) pmArg;
+
+		/* The upper 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;
+
+	/* Create a user event */
+	case TRACER_CREATE_USER_EVENT:
+		/* Copy the information from user space */
+		if (copy_from_user(&lNewUserEvent, (void *) pmArg, sizeof(lNewUserEvent)))
+			return -EFAULT;
+
+		/* Create the event */
+		lNewUserEventID = trace_create_owned_event(lNewUserEvent.type,
+							   lNewUserEvent.desc,
+							   lNewUserEvent.format_type,
+							   lNewUserEvent.form,
+							   current->pid);
+
+		/* Has the operation succeded */
+		if (lNewUserEventID >= 0) {
+			/* Set the event ID */
+			lNewUserEvent.id = lNewUserEventID;
+
+			/* Copy the event information back to user space */
+			if (copy_to_user((void *) pmArg, &lNewUserEvent, sizeof(lNewUserEvent))) {
+				/* Since we were unable to tell the user about the event, destroy it */
+				trace_destroy_event(lNewUserEventID);
+				return -EFAULT;
+			}
+		} else
+			/* Forward trace_create_event()'s error code */
+			return lNewUserEventID;
+		break;
+
+	/* Destroy a user event */
+	case TRACER_DESTROY_USER_EVENT:
+		/* Pass on the user's request */
+		trace_destroy_event((int) pmArg);
+		break;
+
+	/* Trace a user event */
+	case TRACER_TRACE_USER_EVENT:
+		/* Copy the information from user space */
+		if (copy_from_user(&lUserEvent, (void *) pmArg, sizeof(lUserEvent)))
+			return -EFAULT;
+
+		/* Copy the user event data */
+		if (copy_from_user(sUserEventData, lUserEvent.data, lUserEvent.data_size))
+			return -EFAULT;
+
+		/* Log the raw event */
+		lRetValue = trace_raw_event(lUserEvent.id,
+					    lUserEvent.data_size,
+					    sUserEventData);
+
+		/* Has the operation failed */
+		if (lRetValue < 0)
+			/* Forward trace_create_event()'s error code */
+			return lRetValue;
+		break;
+
+	/* Set event mask */
+	case TRACER_SET_EVENT_MASK:
+		/* Copy the information from user space */
+		if (copy_from_user(&(lTraceMask.mask), (void *) pmArg, sizeof(lTraceMask.mask)))
+			return -EFAULT;
+
+		/* Trace the event */
+		lRetValue = trace(TRACE_EV_CHANGE_MASK, &lTraceMask);
+
+		/* Change the event mask. (This has to be done second or else may loose the
+		   information if the user decides to stop logging "change mask" events) */
+		memcpy(&sTracedEvents, &(lTraceMask.mask), sizeof(lTraceMask.mask));
+		syscall_entry_trace_active = ltt_test_bit(TRACE_EV_SYSCALL_ENTRY, &sTracedEvents);
+		syscall_exit_trace_active  = ltt_test_bit(TRACE_EV_SYSCALL_EXIT, &sTracedEvents);
+
+		/* Always trace the buffer start, the trace start and the change mask */
+		ltt_set_bit(TRACE_EV_BUFFER_START, &sTracedEvents);
+		ltt_set_bit(TRACE_EV_START, &sTracedEvents);
+		ltt_set_bit(TRACE_EV_CHANGE_MASK, &sTracedEvents);
+
+		/* Forward trace()'s error code */
+		return lRetValue;
+		break;
+
+	/* Get event mask */
+	case TRACER_GET_EVENT_MASK:
+		/* Copy the information to user space */
+		if (copy_to_user((void *) pmArg, &sTracedEvents, sizeof(sTracedEvents)))
+			return -EFAULT;
+		break;
+
+	/* Unknow command */
+	default:
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
+/**
+ *	tracer_mmap: - "Mmap" file op
+ *	@pmInode: the inode associated with the device
+ *	@pmFile: file structure given to the acting process
+ *	@pmVmArea: Virtual memory area description structure
+ *
+ *	Returns:
+ *	0 if ok
+ *	-EAGAIN, when remap failed
+ *	-EACCESS, permission denied
+ */
+int tracer_mmap(struct file *pmFile,
+		struct vm_area_struct *pmVmArea)
+{
+	int lRetValue;		/* Function's return value */
+
+	/* Only the trace daemon is allowed access to mmap */
+	if (current != sDaemonTaskStruct)
+		return -EACCES;
+
+	/* Remap trace buffer into the process's memory space */
+	lRetValue = tracer_mmap_region(pmVmArea,
+				       (char *) pmVmArea->vm_start,
+				       sTracBuf,
+				  pmVmArea->vm_end - pmVmArea->vm_start);
+
+#if 0
+	printk("Tracer: Trace buffer virtual address                  => 0x%08X \n", (u32) sTracBuf);
+	printk("Tracer: Trace buffer physical address                 => 0x%08X \n", (u32) virt_to_phys(sTracBuf));
+	printk("Tracer: Trace buffer virtual address in daemon space  => 0x%08X \n", (u32) pmVmArea->vm_start);
+	printk("Tracer: Trace buffer physical address in daemon space => 0x%08X \n", (u32) virt_to_phys((void *) pmVmArea->vm_start));
+#endif
+
+	return lRetValue;
+}
+
+/**
+ *	tracer_open(): - "Open" file op
+ *	@pmInode: the inode associated with the device
+ *	@pmFile: file structure given to the acting process
+ *
+ *	Returns:
+ *	0, everything went OK
+ *	-ENODEV, no such device.
+ *	-EBUSY, daemon channel (minor number 0) already in use.
+ */
+int tracer_open(struct inode *pmInode,
+		struct file *pmFile)
+{
+	int lDevMinor = minor(pmInode->i_rdev) & 0x0f;	/* Device minor number */
+
+	/* Only minor number 0 and 1 are used */
+	if ((lDevMinor > 0) && (lDevMinor != 1))
+		return -ENODEV;
+
+	/* If the device has already been opened */
+	if (sOpenCount) {
+		/* Is there another process trying to open the daemon's channel (minor number 0) */
+		if (lDevMinor == 0)
+			return -EBUSY;
+		else
+			/* Only increment use, this is just another user process trying to log user events */
+			goto IncrementUse;
+	}
+	/* Fetch the task structure of the process that opened the device */
+	sDaemonTaskStruct = current;
+
+	/* Reset the default configuration since this is the daemon and he will complete the setup */
+	tracer_set_default_config();
+
+#if 0
+	/* DEBUG */
+	printk("<1>Process %d opened the tracing device \n", sDaemonTaskStruct->pid);
+#endif
+
+IncrementUse:
+	/* Lock the device */
+	sOpenCount++;
+
+#ifdef MODULE
+	/* Increment module usage */
+	MOD_INC_USE_COUNT;
+#endif
+
+	return 0;
+}
+
+/**
+ *	tracer_release: - "Release" file op
+ *	@pmInode: the inode associated with the device
+ *	@pmFile: file structure given to the acting process
+ *
+ *	Returns: 
+ *	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)
+{
+	int lDevMinor = minor(pmInode->i_rdev) & 0x0f;	/* Device minor number */
+
+	/* Is this a simple user process exiting? */
+	if (lDevMinor != 0)
+		goto DecrementUse;
+
+	/* Did we loose any events */
+	if (sEventsLost > 0)
+		printk(KERN_ALERT "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;
+
+DecrementUse:
+	/* Unlock the device */
+	sOpenCount--;
+
+#ifdef MODULE
+	/* Decrement module usage */
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return 0;
+}
+
+/**
+ *	tracer_fsync: - "Fsync" file op
+ *	@pmFile: file structure given to the acting process
+ *	@pmDEntry: dentry associated with file
+ *
+ *	Returns:
+ *	0, everything went OK
+ *	-EACCESS, permission denied
+ *
+ *	Note:
+ *	We need to look the modifications of the values because they are read
+ *	and written by trace().
+ */
+int tracer_fsync(struct file *pmFile,
+		 struct dentry *pmDEntry,
+		 int pmDataSync)
+{
+	unsigned long int lFlags;
+
+	/* Only the trace daemon is allowed access to fsync */
+	if (current != sDaemonTaskStruct)
+		return -EACCES;
+
+	/* 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);
+
+	return 0;
+}
+
+/**
+ *	tracer_set_buffer_size: - Sets the size of the buffers.
+ *	@pmSize: Size of buffers
+ *
+ *	Returns:
+ *	0, Size setting went OK
+ *	-ENOMEM, unable to get a hold of memory for tracer
+ */
+int tracer_set_buffer_size(int pmSize)
+{
+	int lSizeAlloc;
+
+	/* 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;
+
+	return 0;
+}
+
+/**
+ *	tracer_set_default_config: - Sets the tracer in its default config
+ *
+ *	Returns:
+ *	0, everything went OK
+ *	-ENOMEM, unable to get a hold of memory for tracer
+ */
+int tracer_set_default_config(void)
+{
+	int i;
+	int lError = 0;
+
+	/* 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);
+	}
+
+	/* Do not interfere with Linux's syscall flow until we actually start tracing */
+	syscall_entry_trace_active = 0;
+	syscall_exit_trace_active  = 0;
+
+	/* 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 lError;
+}
+
+/**
+ *	tracer_init: - Tracer initialization function.
+ *
+ *	Returns:
+ *	0, everything went OK
+ *	-ENONMEM, incapable of allocating necessary memory
+ *	Forwarded error code otherwise
+ */
+int __init tracer_init(void)
+{
+	int lError = 0;
+
+	/* 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;
+
+	/* Allocate memory for large data components */
+	if ((sUserEventData = vmalloc(CUSTOM_EVENT_MAX_SIZE)) < 0)
+		return -ENOMEM;
+
+	/* 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 */
+	if ((lError = register_tracer(trace)) < 0) {
+		/* Tell the user about the problem */
+		printk(KERN_ALERT "Tracer: Unable to register tracer with kernel, tracer disabled \n");
+
+		/* Make sure no one can open this device */
+		sOpenCount = 1;
+	} else
+		printk(KERN_INFO "Tracer: Initialization complete \n");
+
+	return lError;
+}
+
+/* Is this loaded as a module */
+#ifdef MODULE
+/**
+ *	cleanup_module: - Cleanup of the tracer.
+ *
+ *	No return values.
+ *
+ *	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				/* #ifdef MODULE */
+
+module_init(tracer_init);
diff -urN linux-2.5.34/drivers/trace/tracer.h linux-2.5.34-ltt/drivers/trace/tracer.h
--- linux-2.5.34/drivers/trace/tracer.h	Wed Dec 31 19:00:00 1969
+++ linux-2.5.34-ltt/drivers/trace/tracer.h	Mon Sep  9 19:06:34 2002
@@ -0,0 +1,160 @@
+/*
+ * drivers/trace/tracer.h
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002 Karim Yaghmour (karim@opersys.com)
+ * Portions contributed by T. Halloran: (C) Copyright 2002 IBM Poughkeepsie, IBM Corporation
+ *
+ * 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 */
+#ifndef LTT_PACKED_STRUCT
+#if LTT_UNPACKED_STRUCTS
+#define LTT_PACKED_STRUCT
+#else				/* if LTT_UNPACKED_STRUCTS */
+#define LTT_PACKED_STRUCT __attribute__ ((packed));
+#endif				/* if LTT_UNPACKED_STRUCTS */
+#endif				/* if LTT_PACKED_STRUCT */
+
+/* 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 u32 trace_time_delta;	/* The type used to start the time delta between events */
+
+/* Number of bytes set aside for last event */
+#define TRACER_LAST_EVENT_SIZE   (sizeof(u8) + sizeof(u8) + sizeof(trace_time_delta) + sizeof(u32))
+
+/* 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   14	/* Minor version number */
+typedef struct _trace_start {
+	u32 MagicNumber;	/* Magic number to identify a trace */
+	u32 ArchType;		/* Type of architecture */
+	u32 ArchVariant;	/* Variant of the given type of architecture */
+	u32 SystemType;		/* Operating system type */
+	u8 MajorVersion;	/* Major version of trace */
+	u8 MinorVersion;	/* Minor version of trace */
+
+	u32 BufferSize;		/* Size of buffers */
+	trace_event_mask EventMask;	/* The event mask */
+	trace_event_mask DetailsMask;	/* Are the event details logged */
+	u8 LogCPUID;		/* Is the CPUID logged */
+} LTT_PACKED_STRUCT trace_start;
+
+/* Start and end of trace buffer information */
+typedef struct _trace_buffer_start {
+	struct timeval Time;	/* Time stamp of this buffer */
+	u32 ID;			/* Unique buffer ID */
+} LTT_PACKED_STRUCT trace_buffer_start;
+
+/* The configurations possible */
+#define TRACER_START                      TRACER_MAGIC_NUMBER + 0	/* Start tracing events using the current configuration */
+#define TRACER_STOP                       TRACER_MAGIC_NUMBER + 1	/* Stop tracing */
+#define TRACER_CONFIG_DEFAULT             TRACER_MAGIC_NUMBER + 2	/* Set the tracer to the default configuration */
+#define TRACER_CONFIG_MEMORY_BUFFERS      TRACER_MAGIC_NUMBER + 3	/* Set the memory buffers the daemon wants us to use */
+#define TRACER_CONFIG_EVENTS              TRACER_MAGIC_NUMBER + 4	/* Trace the given events */
+#define TRACER_CONFIG_DETAILS             TRACER_MAGIC_NUMBER + 5	/* Record the details of the event, or not */
+#define TRACER_CONFIG_CPUID               TRACER_MAGIC_NUMBER + 6	/* Record the CPUID associated with the event */
+#define TRACER_CONFIG_PID                 TRACER_MAGIC_NUMBER + 7	/* Trace only one process */
+#define TRACER_CONFIG_PGRP                TRACER_MAGIC_NUMBER + 8	/* Trace only the given process group */
+#define TRACER_CONFIG_GID                 TRACER_MAGIC_NUMBER + 9	/* Trace the processes of a given group of users */
+#define TRACER_CONFIG_UID                 TRACER_MAGIC_NUMBER + 10	/* Trace the processes of a given user */
+#define TRACER_CONFIG_SYSCALL_EIP_DEPTH   TRACER_MAGIC_NUMBER + 11	/* Set the call depth at which the EIP should be fetched on syscall */
+#define TRACER_CONFIG_SYSCALL_EIP_LOWER   TRACER_MAGIC_NUMBER + 12	/* Set the lowerbound address from which EIP is recorded on syscall */
+#define TRACER_CONFIG_SYSCALL_EIP_UPPER   TRACER_MAGIC_NUMBER + 13	/* Set the upperbound address from which EIP is recorded on syscall */
+#define TRACER_DATA_COMITTED              TRACER_MAGIC_NUMBER + 14	/* The daemon has comitted the last trace */
+#define TRACER_GET_EVENTS_LOST            TRACER_MAGIC_NUMBER + 15	/* Get the number of events lost */
+#define TRACER_CREATE_USER_EVENT          TRACER_MAGIC_NUMBER + 16	/* Create a user tracable event */
+#define TRACER_DESTROY_USER_EVENT         TRACER_MAGIC_NUMBER + 17	/* Destroy a user tracable event */
+#define TRACER_TRACE_USER_EVENT           TRACER_MAGIC_NUMBER + 18	/* Trace a user event */
+#define TRACER_SET_EVENT_MASK             TRACER_MAGIC_NUMBER + 19	/* Set the trace event mask */
+#define TRACER_GET_EVENT_MASK             TRACER_MAGIC_NUMBER + 20	/* Get the trace event mask */
+
+extern __inline__ int ltt_set_bit(int nr, void *addr)
+{
+	unsigned char *p = addr;
+	unsigned char mask = 1 << (nr & 7);
+	unsigned char old;
+
+	p += nr >> 3;
+	old = *p;
+	*p |= mask;
+
+	return ((old & mask) != 0);
+}
+
+extern __inline__ int ltt_clear_bit(int nr, void *addr)
+{
+	unsigned char *p = addr;
+	unsigned char mask = 1 << (nr & 7);
+	unsigned char old;
+
+	p += nr >> 3;
+	old = *p;
+	*p &= ~mask;
+
+	return ((old & mask) != 0);
+}
+
+extern __inline__ int ltt_test_bit(int nr, void *addr)
+{
+	unsigned char *p = addr;
+	unsigned char mask = 1 << (nr & 7);
+
+	p += nr >> 3;
+
+	return ((*p & mask) != 0);
+}
+
+/* Function prototypes */
+int trace
+ (u8,
+  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 /* #ifdef MODULE */
+int tracer_set_buffer_size
+ (int);
+int tracer_set_default_config
+ (void);
+int tracer_init
+ (void);
+#endif				/* _TRACER_H */

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-09-10 18:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-10 18:16 [PATCH] 2/8 LTT for 2.5.34: Trace driver Karim Yaghmour

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).