diff -uNrp linux-2.6.9/Documentation/adeos.txt linux-2.6.9-ltt-r12/Documentation/adeos.txt
--- linux-2.6.9/Documentation/adeos.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/Documentation/adeos.txt	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,176 @@
+
+The Adeos nanokernel is based on research and publications made in the
+early '90s on the subject of nanokernels. Our basic method was to
+reverse the approach described in most of the papers on the subject.
+Instead of first building the nanokernel and then building the client
+OSes, we started from a live and known-to-be-functional OS, Linux, and
+inserted a nanokernel beneath it. Starting from Adeos, other client
+OSes can now be put side-by-side with the Linux kernel.
+
+To this end, Adeos enables multiple domains to exist simultaneously on
+the same hardware. None of these domains see each other, but all of
+them see Adeos. A domain is most probably a complete OS, but there is
+no assumption being made regarding the sophistication of what's in
+a domain.
+
+To share the hardware among the different OSes, Adeos implements an
+interrupt pipeline (ipipe). Every OS domain has an entry in the ipipe.
+Each interrupt that comes in the ipipe is passed on to every domain
+in the ipipe. Instead of disabling/enabling interrupts, each domain
+in the pipeline only needs to stall/unstall his pipeline stage. If
+an ipipe stage is stalled, then the interrupts do not progress in the
+ipipe until that stage has been unstalled. Each stage of the ipipe
+can, of course, decide to do a number of things with an interrupt.
+Among other things, it can decide that it's the last recipient of the
+interrupt. In that case, the ipipe does not propagate the interrupt
+to the rest of the domains in the ipipe.
+
+Regardless of the operations being done in the ipipe, the Adeos code
+does __not__ play with the interrupt masks. The only case where the
+hardware masks are altered is during the addition/removal of a domain
+from the ipipe. This also means that no OS is allowed to use the real
+hardware cli/sti. But this is OK, since the stall/unstall calls
+achieve the same functionality.
+
+Our approach is based on the following papers (links to these
+papers are provided at the bottom of this message):
+[1] D. Probert, J. Bruno, and M. Karzaorman. "Space: a new approach to
+operating system abstraction." In: International Workshop on Object
+Orientation in Operating Systems, pages 133-137, October 1991.
+[2] D. Probert, J. Bruno. "Building fundamentally extensible application-
+specific operating systems in Space", March 1995.
+[3] D. Cheriton, K. Duda. "A caching model of operating system kernel
+functionality". In: Proc. Symp. on Operating Systems Design and
+Implementation, pages 179-194, Monterey CA (USA), 1994.
+[4] D. Engler, M. Kaashoek, and J. O'Toole Jr. "Exokernel: an operating
+system architecture for application-specific resource management",
+December 1995.
+
+If you don't want to go fetch the complete papers, here's a summary.
+The first 2 discuss the Space nanokernel, the 3rd discussed the cache
+nanokernel, and the last discusses exokernel.
+
+The complete Adeos approach has been thoroughly documented in a whitepaper
+published more than a year ago entitled "Adaptive Domain Environment
+for Operating Systems" and available here: http://www.opersys.com/adeos
+The current implementation is slightly different. Mainly, we do not
+implement the functionality to move Linux out of ring 0. Although of
+interest, this approach is not very portable.
+
+Instead, our patch taps right into Linux's main source of control
+over the hardware, the interrupt dispatching code, and inserts an
+interrupt pipeline which can then serve all the nanokernel's clients,
+including Linux.
+
+This is not a novelty in itself. Other OSes have been modified in such
+a way for a wide range of purposes. One of the most interesting
+examples is described by Stodolsky, Chen, and Bershad in a paper
+entitled "Fast Interrupt Priority Management in Operating System
+Kernels" published in 1993 as part of the Usenix Microkernels and
+Other Kernel Architectures Symposium. In that case, cli/sti were
+replaced by virtual cli/sti which did not modify the real interrupt
+mask in any way. Instead, interrupts were defered and delivered to
+the OS upon a call to the virtualized sti.
+
+Mainly, this resulted in increased performance for the OS. Although
+we haven't done any measurements on Linux's interrupt handling
+performance with Adeos, our nanokernel includes by definition the
+code implementing the technique described in the abovementioned
+Stodolsky paper, which we use to redirect the hardware interrupt flow
+to the pipeline.
+
+i386 and armnommu are currently supported. Most of the
+architecture-dependent code is easily portable to other architectures.
+
+Aside of adding the Adeos module (driver/adeos), we also modified some
+files to tap into Linux interrupt and system event dispatching (all
+the modifications are encapsulated in #ifdef CONFIG_ADEOS_*/#endif).
+
+We modified the idle task so it gives control back to Adeos in order for
+the ipipe to continue propagation.
+
+We modified init/main.c to initialize Adeos very early in the startup.
+
+Of course, we also added the appropriate makefile modifications and
+config options so that you can choose to enable/disable Adeos as
+part of the kernel build configuration.
+
+Adeos' public API is fully documented here:
+http://www.freesoftware.fsf.org/adeos/doc/api/index.html.
+
+In Linux's case, adeos_register_domain() is called very early during
+system startup.
+
+To add your domain to the ipipe, you need to:
+1) Register your domain with Adeos using adeos_register_domain()
+2) Call adeos_virtualize_irq() for all the IRQs you wish to be
+notified about in the ipipe.
+
+That's it. Provided you gave Adeos appropriate handlers in step
+#2, your interrupts will be delivered via the ipipe.
+
+During runtime, you may change your position in the ipipe using
+adeos_renice_domain(). You may also stall/unstall the pipeline
+and change the ipipe's handling of the interrupts according to your
+needs.
+
+Adeos supports SMP, and APIC support on UP.
+
+Here are some of the possible uses for Adeos (this list is far
+from complete):
+1) Much like User-Mode Linux, it should now be possible to have 2
+Linux kernels living side-by-side on the same hardware. In contrast
+to UML, this would not be 2 kernels one ontop of the other, but
+really side-by-side. Since Linux can be told at boot time to use
+only one portion of the available RAM, on a 128MB machine this
+would mean that the first could be made to use the 0-64MB space and
+the second would use the 64-128MB space. We realize that many
+modifications are required. Among other things, one of the 2 kernels
+will not need to conduct hardware initialization. Nevertheless, this
+possibility should be studied closer.
+
+2) It follows from #1 that adding other kernels beside Linux should
+be feasible. BSD is a prime candidate, but it would also be nice to
+see what virtualizers such as VMWare and Plex86 could do with Adeos.
+Proprietary operating systems could potentially also be accomodated.
+
+3) All the previous work that has been done on nanokernels should now
+be easily ported to Linux. Mainly, we would be very interested to
+hear about extensions to Adeos. Primarily, we have no mechanisms
+currently enabling multiple domains to share information. The papers
+mentioned earlier provide such mechanisms, but we'd like to see
+actual practical examples.
+
+4) Kernel debuggers' main problem (tapping into the kernel's
+interrupts) is solved and it should then be possible to provide
+patchless kernel debuggers. They would then become loadable kernel
+modules.
+
+5) Drivers who require absolute priority and dislike other kernel
+portions who use cli/sti can now create a domain of their own
+and place themselves before Linux in the ipipe. This provides a
+mechanism for the implementation of systems that can provide guaranteed
+realtime response.
+
+Philippe Gerum <rpm@xenomai.org>
+Karim Yaghmour <karim@opersys.com>
+
+----------------------------------------------------------------------
+Links to papers:
+1-
+http://citeseer.nj.nec.com/probert91space.html
+ftp://ftp.cs.ucsb.edu/pub/papers/space/iwooos91.ps.gz (not working)
+http://www4.informatik.uni-erlangen.de/~tsthiel/Papers/Space-iwooos91.ps.gz
+
+2-
+http://www.cs.ucsb.edu/research/trcs/abstracts/1995-06.shtml
+http://www4.informatik.uni-erlangen.de/~tsthiel/Papers/Space-trcs95-06.ps.gz
+
+3-
+http://citeseer.nj.nec.com/kenneth94caching.html
+http://guir.cs.berkeley.edu/projects/osprelims/papers/cachmodel-OSkernel.ps.gz
+
+4-
+http://citeseer.nj.nec.com/engler95exokernel.html
+ftp://ftp.cag.lcs.mit.edu/multiscale/exokernel.ps.Z
+----------------------------------------------------------------------
diff -uNrp linux-2.6.9/Documentation/filesystems/relayfs.txt linux-2.6.9-ltt-r12/Documentation/filesystems/relayfs.txt
--- linux-2.6.9/Documentation/filesystems/relayfs.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/Documentation/filesystems/relayfs.txt	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,812 @@
+
+relayfs - a high-speed data relay filesystem
+============================================
+
+relayfs is a filesystem designed to provide an efficient mechanism for
+tools and facilities to relay large amounts of data from kernel space
+to user space.
+
+The main idea behind relayfs is that every data flow is put into a
+separate "channel" and each channel is a file.  In practice, each
+channel is a separate memory buffer allocated from within kernel space
+upon channel instantiation. Software needing to relay data to user
+space would open a channel or a number of channels, depending on its
+needs, and would log data to that channel. All the buffering and
+locking mechanics are taken care of by relayfs.  The actual format and
+protocol used for each channel is up to relayfs' clients.
+
+relayfs makes no provisions for copying the same data to more than a
+single channel. This is for the clients of the relay to take care of,
+and so is any form of data filtering. The purpose is to keep relayfs
+as simple as possible.
+
+
+Usage
+=====
+
+In addition to the relayfs kernel API described below, relayfs
+implements basic file operations.  Here are the file operations that
+are available and some comments regarding their behavior:
+
+open()	 enables user to open an _existing_ channel.  A channel can be
+	 opened in blocking or non-blocking mode, and can be opened
+	 for reading as well as for writing.  Readers will by default
+	 be auto-consuming.
+
+mmap()	 results in channel's memory buffer being mmapped into the
+	 caller's memory space.
+
+read()	 since we are dealing with circular buffers, the user is only
+	 allowed to read forward.  Some apps may want to loop around
+	 read() waiting for incoming data - if there is no data
+	 available, read will put the reader on a wait queue until
+	 data is available (blocking mode).  Non-blocking reads return
+	 -EAGAIN if data is not available.
+
+
+write()	 writing from user space operates exactly as relay_write() does
+	 (described below).
+
+poll()	POLLIN/POLLRDNORM/POLLOUT/POLLWRNORM/POLLERR supported.
+
+close()  decrements the channel's refcount.  When the refcount reaches
+	 0 i.e. when no process or kernel client has the file open
+	 (see relay_close() below), the channel buffer is freed.
+
+
+In order for a user application to make use of relayfs files, the
+relayfs filesystem must be mounted.  For example,
+
+	mount -t relayfs relayfs /mountpoint
+
+
+The relayfs kernel API
+======================
+
+relayfs channels are implemented as circular buffers subdivided into
+'sub-buffers'.  kernel clients write data into the channel using
+relay_write(), and are notified via a set of callbacks when
+significant events occur within the channel.  'Significant events'
+include:
+
+- a sub-buffer has been filled i.e. the current write won't fit into the
+  current sub-buffer, and a 'buffer-switch' is triggered, after which
+  the data is written into the next buffer (if the next buffer is
+  empty).  The client is notified of this condition via two callbacks,
+  one providing an opportunity to perform start-of-buffer tasks, the
+  other end-of-buffer tasks.
+
+- data is ready for the client to process.  The client can choose to
+  be notified either on a per-sub-buffer basis (bulk delivery) or
+  per-write basis (packet delivery).
+
+- data has been written to the channel from user space.  The client can
+  use this notification to accept and process 'commands' sent to the
+  channel via write(2).
+
+- the channel has been opened/closed/mapped/unmapped from user space.
+  The client can use this notification to trigger actions within the
+  kernel application, such as enabling/disabling logging to the
+  channel.  It can also return result codes from the callback,
+  indicating that the operation should fail e.g. in order to restrict
+  more than one user space open or mmap.
+
+- the channel needs resizing, or needs to update its
+  state based on the results of the resize.  Resizing the channel is
+  up to the kernel client to actually perform.  If the channel is
+  configured for resizing, the client is notified when the unread data
+  in the channel passes a preset threshold, giving it the opportunity
+  to allocate a new channel buffer and replace the old one.
+
+Reader objects
+--------------
+
+Channel readers use an opaque rchan_reader object to read from
+channels.  For VFS readers (those using read(2) to read from a
+channel), these objects are automatically created and used internally;
+only kernel clients that need to directly read from channels, or whose
+userspace applications use mmap to access channel data, need to know
+anything about rchan_readers - others may skip this section.
+
+A relay channel can have any number of readers, each represented by an
+rchan_reader instance, which is used to encapsulate reader settings
+and state.  rchan_reader objects should be treated as opaque by kernel
+clients.  To create a reader object for directly accessing a channel
+from kernel space, call the add_rchan_reader() kernel API function:
+
+rchan_reader *add_rchan_reader(rchan_id, auto_consume)
+
+This function returns an rchan_reader instance if successful, which
+should then be passed to relay_read() when the kernel client is
+interested in reading from the channel.
+
+The auto_consume parameter indicates whether a read done by this
+reader will automatically 'consume' that portion of the unread channel
+buffer when relay_read() is called (see below for more details).
+
+To close the reader, call
+
+remove_rchan_reader(reader)
+
+which will remove the reader from the list of current readers.
+
+
+To create a reader object representing a userspace mmap reader in the
+kernel application, call the add_map_reader() kernel API function:
+
+rchan_reader *add_map_reader(rchan_id)
+
+This function returns an rchan_reader instance if successful, whose
+main purpose is as an argument to be passed into
+relay_buffers_consumed() when the kernel client becomes aware that
+data has been read by a user application using mmap to read from the
+channel buffer.  There is no auto_consume option in this case, since
+only the kernel client/user application knows when data has been read.
+
+To close the map reader, call
+
+remove_map_reader(reader)
+
+which will remove the reader from the list of current readers.
+
+Consumed count
+--------------
+
+A relayfs channel is a circular buffer, which means that if there is
+no reader reading from it or a reader reading too slowly, at some
+point the channel writer will 'lap' the reader and data will be lost.
+In normal use, readers will always be able to keep up with writers and
+the buffer is thus never in danger of becoming full.  In many
+applications, it's sufficient to ensure that this is practically
+speaking always the case, by making the buffers large enough.  These
+types of applications can basically open the channel as
+RELAY_MODE_CONTINOUS (the default anyway) and not worry about the
+meaning of 'consume' and skip the rest of this section.
+
+If it's important for the application that a kernel client never allow
+writers to overwrite unread data, the channel should be opened using
+RELAY_MODE_NO_OVERWRITE and must be kept apprised of the count of
+bytes actually read by the (typically) user-space channel readers.
+This count is referred to as the 'consumed count'.  read(2) channel
+readers automatically update the channel's 'consumed count' as they
+read.  If the usage mode is to have only read(2) readers, which is
+typically the case, the kernel client doesn't need to worry about any
+of the relayfs functions having to do with 'bytes consumed' and can
+skip the rest of this section.  (Note that it is possible to have
+multiple read(2) or auto-consuming readers, but like having multiple
+readers on a pipe, these readers will race with each other i.e. it's
+supported, but doesn't make much sense).
+
+If the kernel client cannot rely on an auto-consuming reader to keep
+the 'consumed count' up-to-date, then it must do so manually, by
+making the appropriate calls to relay_buffers_consumed() or
+relay_bytes_consumed().  In most cases, this should only be necessary
+for bulk mmap clients - almost all packet clients should be covered by
+having auto-consuming read(2) readers.  For mmapped bulk clients, for
+instance, there are no auto-consuming VFS readers, so the kernel
+client needs to make the call to relay_buffers_consumed() after
+sub-buffers are read.
+
+Kernel API
+----------
+
+Here's a summary of the API relayfs provides to in-kernel clients:
+
+int    relay_open(channel_path, bufsize, nbufs, channel_flags,
+		  channel_callbacks, start_reserve, end_reserve,
+		  rchan_start_reserve, resize_min, resize_max, mode,
+		  init_buf, init_buf_size)
+int    relay_write(channel_id, *data_ptr, count, time_delta_offset, **wrote)
+rchan_reader *add_rchan_reader(channel_id, auto_consume)
+int    remove_rchan_reader(rchan_reader *reader)
+rchan_reader *add_map_reader(channel_id)
+int    remove_map_reader(rchan_reader *reader)
+int    relay_read(reader, buf, count, wait, *actual_read_offset)
+void   relay_buffers_consumed(reader, buffers_consumed)
+void   relay_bytes_consumed(reader, bytes_consumed, read_offset)
+int    relay_bytes_avail(reader)
+int    rchan_full(reader)
+int    rchan_empty(reader)
+int    relay_info(channel_id, *channel_info)
+int    relay_close(channel_id)
+int    relay_realloc_buffer(channel_id, nbufs, async)
+int    relay_replace_buffer(channel_id)
+int    relay_reset(int rchan_id)
+
+----------
+int relay_open(channel_path, bufsize, nbufs, 
+	 channel_flags, channel_callbacks, start_reserve,
+	 end_reserve, rchan_start_reserve, resize_min, resize_max, mode)
+
+relay_open() is used to create a new entry in relayfs.  This new entry
+is created according to channel_path.  channel_path contains the
+absolute path to the channel file on relayfs.  If, for example, the
+caller sets channel_path to "/xlog/9", a "xlog/9" entry will appear
+within relayfs automatically and the "xlog" directory will be created
+in the filesystem's root.  relayfs does not implement any policy on
+its content, except to disallow the opening of two channels using the
+same file. There are, nevertheless a set of guidelines for using
+relayfs. Basically, each facility using relayfs should use a top-level
+directory identifying it. The entry created above, for example,
+presumably belongs to the "xlog" software.
+
+The remaining parameters for relay_open() are as follows:
+
+- channel_flags - an ORed combination of attribute values controlling
+  common channel characteristics:
+
+	- logging scheme - relayfs use 2 mutually exclusive schemes
+	  for logging data to a channel.  The 'lockless scheme'
+	  reserves and writes data to a channel without the need of
+	  any type of locking on the channel.  This is the preferred
+	  scheme, but may not be available on a given architecture (it
+	  relies on the presence of a cmpxchg instruction).  It's
+	  specified by the RELAY_SCHEME_LOCKLESS flag.  The 'locking
+	  scheme' either obtains a lock on the channel for writing or
+	  disables interrupts, depending on whether the channel was
+	  opened for SMP or global usage (see below).  It's specified
+	  by the RELAY_SCHEME_LOCKING flag.  While a client may want
+	  to explicitly specify a particular scheme to use, it's more
+	  convenient to specify RELAY_SCHEME_ANY for this flag, which
+	  will allow relayfs to choose the best available scheme i.e.
+	  lockless if supported.
+
+       - overwrite mode (default is RELAY_MODE_CONTINUOUS) -
+	 If RELAY_MODE_CONTINUOUS is specified, writes to the channel
+	 will succeed regardless of whether there are up-to-date
+	 consumers or not.  If RELAY_MODE_NO_OVERWRITE is specified,
+	 the channel becomes 'full' when the total amount of buffer
+	 space unconsumed by readers equals or exceeds the total
+	 buffer size.  With the buffer in this state, writes to the
+	 buffer will fail - clients need to check the return code from
+	 relay_write() to determine if this is the case and act
+	 accordingly - 0 or a negative value indicate the write failed.
+
+       - SMP usage - this applies only when the locking scheme is in
+	 use.  If RELAY_USAGE_SMP is specified, it's assumed that the
+	 channel will be used in a per-CPU fashion and consequently,
+	 the only locking that will be done for writes is to disable
+	 local irqs.  If RELAY_USAGE_GLOBAL is specified, it's assumed
+	 that writes to the buffer can occur within any CPU context,
+	 and spinlock_irq_save will be used to lock the buffer.
+
+       - delivery mode - if RELAY_DELIVERY_BULK is specified, the
+	 client will be notified via its deliver() callback whenever a
+	 sub-buffer has been filled.  Alternatively,
+	 RELAY_DELIVERY_PACKET will cause delivery to occur after the
+	 completion of each write.  See the description of the channel
+	 callbacks below for more details.
+
+       - timestamping - if RELAY_TIMESTAMP_TSC is specified and the
+	 architecture supports it, efficient TSC 'timestamps' can be
+	 associated with each write, otherwise more expensive
+	 gettimeofday() timestamping is used.  At the beginning of
+	 each sub-buffer, a gettimeofday() timestamp and the current
+	 TSC, if supported, are read, and are passed on to the client
+	 via the buffer_start() callback.  This allows correlation of
+	 the current time with the current TSC for subsequent writes.
+	 Each subsequent write is associated with a 'time delta',
+	 which is either the current TSC, if the channel is using
+	 TSCs, or the difference between the buffer_start gettimeofday
+	 timestamp and the gettimeofday time read for the current
+	 write.  Note that relayfs never writes either a timestamp or
+	 time delta into the buffer unless explicitly asked to (see
+	 the description of relay_write() for details).
+ 
+- bufsize - the size of the 'sub-buffers' making up the circular channel
+  buffer.  For the lockless scheme, this must be a power of 2.
+
+- nbufs - the number of 'sub-buffers' making up the circular
+  channel buffer.  This must be a power of 2.
+
+  The total size of the channel buffer is bufsize * nbufs rounded up 
+  to the next kernel page size.  If the lockless scheme is used, both
+  bufsize and nbufs must be a power of 2.  If the locking scheme is
+  used, the bufsize can be anything and nbufs must be a power of 2.  If
+  RELAY_SCHEME_ANY is used, the bufsize and nbufs should be a power of 2.
+
+  NOTE: if nbufs is 1, relayfs will bypass the normal size
+  checks and will allocate an rvmalloced buffer of size bufsize.
+  This buffer will be freed when relay_close() is called, if the channel
+  isn't still being referenced.
+
+- callbacks - a table of callback functions called when events occur
+  within the data relay that clients need to know about:
+          
+	  - int buffer_start(channel_id, current_write_pos, buffer_id,
+	    start_time, start_tsc, using_tsc) -
+
+	    called at the beginning of a new sub-buffer, the
+	    buffer_start() callback gives the client an opportunity to
+	    write data into space reserved at the beginning of a
+	    sub-buffer.  The client should only write into the buffer
+	    if it specified a value for start_reserve and/or
+	    channel_start_reserve (see below) when the channel was
+	    opened.  In the latter case, the client can determine
+	    whether to write its one-time rchan_start_reserve data by
+	    examining the value of buffer_id, which will be 0 for the
+	    first sub-buffer.  The address that the client can write
+	    to is contained in current_write_pos (the client by
+	    definition knows how much it can write i.e. the value it
+	    passed to relay_open() for start_reserve/
+	    channel_start_reserve).  start_time contains the
+	    gettimeofday() value for the start of the buffer and start
+	    TSC contains the TSC read at the same time.  The using_tsc
+	    param indicates whether or not start_tsc is valid (it
+	    wouldn't be if TSC timestamping isn't being used).
+
+	    The client should return the number of bytes it wrote to
+	    the channel, 0 if none.
+
+	  - int buffer_end(channel_id, current_write_pos, end_of_buffer,
+	    end_time, end_tsc, using_tsc)
+
+	    called at the end of a sub-buffer, the buffer_end()
+	    callback gives the client an opportunity to perform
+	    end-of-buffer processing.  Note that the current_write_pos
+	    is the position where the next write would occur, but
+	    since the current write wouldn't fit (which is the trigger
+	    for the buffer_end event), the buffer is considered full
+	    even though there may be unused space at the end.  The
+	    end_of_buffer param pointer value can be used to determine
+	    exactly the size of the unused space.  The client should
+	    only write into the buffer if it specified a value for
+	    end_reserve when the channel was opened.  If the client
+	    doesn't write anything i.e. returns 0, the unused space at
+	    the end of the sub-buffer is available via relay_info() -
+	    this data may be needed by the client later if it needs to
+	    process raw sub-buffers (an alternative would be to save
+	    the unused bytes count value in end_reserve space at the
+	    end of each sub-buffer during buffer_end processing and
+	    read it when needed at a later time.  The other
+	    alternative would be to use read(2), which makes the
+	    unused count invisible to the caller).  end_time contains
+	    the gettimeofday() value for the end of the buffer and end
+	    TSC contains the TSC read at the same time.  The using_tsc
+	    param indicates whether or not end_tsc is valid (it
+	    wouldn't be if TSC timestamping isn't being used).
+
+	    The client should return the number of bytes it wrote to
+	    the channel, 0 if none.
+
+	  - void deliver(channel_id, from, len)
+
+	    called when data is ready for the client.  This callback
+	    is used to notify a client when a sub-buffer is complete
+	    (in the case of bulk delivery) or a single write is
+	    complete (packet delivery).  A bulk delivery client might
+	    wish to then signal a daemon that a sub-buffer is ready.
+	    A packet delivery client might wish to process the packet
+	    or send it elsewhere.  The from param is a pointer to the
+	    delivered data and len specifies how many bytes are ready.
+
+	  - void user_deliver(channel_id, from, len)
+
+	    called when data has been written to the channel from user
+	    space.  This callback is used to notify a client when a
+	    successful write from userspace has occurred, independent
+	    of whether bulk or packet delivery is in use.  This can be
+	    used to allow userspace programs to communicate with the
+	    kernel client through the channel via out-of-band write(2)
+	    'commands' instead of via ioctls, for instance.  The from
+	    param is a pointer to the delivered data and len specifies
+	    how many bytes are ready.  Note that this callback occurs
+	    after the bytes have been successfully written into the
+	    channel, which means that channel readers must be able to
+	    deal with the 'command' data which will appear in the
+	    channel data stream just as any other userspace or
+	    non-userspace write would.
+
+	  - int needs_resize(channel_id, resize_type,
+	                     suggested_buf_size, suggested_n_bufs)
+
+	    called when a channel's buffers are in danger of becoming
+	    full i.e. the number of unread bytes in the channel passes
+	    a preset threshold, or when the current capacity of a
+	    channel's buffer is no longer needed.  Also called to
+	    notify the client when a channel's buffer has been
+	    replaced.  If resize_type is RELAY_RESIZE_EXPAND or
+	    RELAY_RESIZE_SHRINK, the kernel client should arrange to
+	    call relay_realloc_buffer() with the suggested buffer size
+	    and buffer count, which will allocate (but will not
+	    replace the old one) a new buffer of the recommended size
+	    for the channel.  When the allocation has completed,
+	    needs_resize() is again called, this time with a
+	    resize_type of RELAY_RESIZE_REPLACE.  The kernel client
+	    should then arrange to call relay_replace_buffer() to
+	    actually replace the old channel buffer with the newly
+	    allocated buffer.  Finally, once the buffer replacement
+	    has completed, needs_resize() is again called, this time
+	    with a resize_type of RELAY_RESIZE_REPLACED, to inform the
+	    client that the replacement is complete and additionally
+	    confirming the current sub-buffer size and number of
+	    sub-buffers.  Note that a resize can be canceled if
+	    relay_realloc_buffer() is called with the async param
+	    non-zero and the resize conditions no longer hold.  In
+	    this case, the RELAY_RESIZE_REPLACED suggested number of
+	    sub-buffers will be the same as the number of sub-buffers
+	    that existed before the RELAY_RESIZE_SHRINK or EXPAND i.e.
+	    values indicating that the resize didn't actually occur.
+
+	  - int fileop_notify(channel_id, struct file *filp, enum relay_fileop)
+
+	    called when a userspace file operation has occurred or
+	    will occur on a relayfs channel file.  These notifications
+	    can be used by the kernel client to trigger actions within
+	    the kernel client when the corresponding event occurs,
+	    such as enabling logging only when a userspace application
+	    opens or mmaps a relayfs file and disabling it again when
+	    the file is closed or unmapped.  The kernel client can
+	    also return its own return value, which can affect the
+	    outcome of file operation - returning 0 indicates that the
+	    operation should succeed, and returning a negative value
+	    indicates that the operation should be failed, and that
+	    the returned value should be returned to the ultimate
+	    caller e.g. returning -EPERM from the open fileop will
+	    cause the open to fail with -EPERM.  Among other things,
+	    the return value can be used to restrict a relayfs file
+	    from being opened or mmap'ed more than once.  The currently
+	    implemented fileops are:
+
+	    RELAY_FILE_OPEN - a relayfs file is being opened.  Return
+			      0 to allow it to succeed, negative to
+			      have it fail.  A negative return value will
+			      be passed on unmodified to the open fileop.
+	    RELAY_FILE_CLOSE- a relayfs file is being closed.  The return
+			      value is ignored.
+	    RELAY_FILE_MAP - a relayfs file is being mmap'ed.  Return 0
+			     to allow it to succeed, negative to have
+			     it fail.  A negative return value will be
+			     passed on unmodified to the mmap fileop.
+	    RELAY_FILE_UNMAP- a relayfs file is being unmapped.  The return
+			      value is ignored.
+
+	  - void ioctl(rchan_id, cmd, arg)
+
+  	    called when an ioctl call is made using a relayfs file
+	    descriptor.  The cmd and arg are passed along to this
+	    callback unmodified for it to do as it wishes with.  The
+	    return value from this callback is used as the return value
+	    of the ioctl call.
+
+  If the callbacks param passed to relay_open() is NULL, a set of
+  default do-nothing callbacks will be defined for the channel.
+  Likewise, any NULL rchan_callback function contained in a non-NULL
+  callbacks struct will be filled in with a default callback function
+  that does nothing.
+
+- start_reserve - the number of bytes to be reserved at the start of
+  each sub-buffer.  The client can do what it wants with this number
+  of bytes when the buffer_start() callback is invoked.  Typically
+  clients would use this to write per-sub-buffer header data.
+
+- end_reserve - the number of bytes to be reserved at the end of each
+  sub-buffer.  The client can do what it wants with this number of
+  bytes when the buffer_end() callback is invoked.  Typically clients
+  would use this to write per-sub-buffer footer data.
+
+- channel_start_reserve - the number of bytes to be reserved, in
+  addition to start_reserve, at the beginning of the first sub-buffer
+  in the channel.  The client can do what it wants with this number of
+  bytes when the buffer_start() callback is invoked.  Typically
+  clients would use this to write per-channel header data.
+
+- resize_min - if set, this signifies that the channel is
+  auto-resizeable.  The value specifies the size that the channel will
+  try to maintain as a normal working size, and that it won't go
+  below.  The client makes use of the resizing callbacks and
+  relay_realloc_buffer() and relay_replace_buffer() to actually effect
+  the resize.
+
+- resize_max - if set, this signifies that the channel is
+  auto-resizeable.  The value specifies the maximum size the channel
+  can have as a result of resizing.
+
+- mode - if non-zero, specifies the file permissions that will be given
+  to the channel file.  If 0, the default rw user perms will be used.
+
+- init_buf - if non-NULL, rather than allocating the channel buffer,
+  this buffer will be used as the initial channel buffer.  The kernel
+  API function relay_discard_init_buf() can later be used to have
+  relayfs allocate a normal mmappable channel buffer and switch over
+  to using it after copying the init_buf contents into it.  Currently,
+  the size of init_buf must be exactly buf_size * n_bufs.  The caller
+  is responsible for managing the init_buf memory.  This feature is
+  typically used for init-time channel use and should normally be
+  specified as NULL.
+
+- init_buf_size - the total size of init_buf, if init_buf is specified
+  as non-NULL.  Currently, the size of init_buf must be exactly
+  buf_size * n_bufs.
+
+Upon successful completion, relay_open() returns a channel id
+to be used for all other operations with the relay. All buffers
+managed by the relay are allocated using rvmalloc/rvfree to allow
+for easy mmapping to user-space.
+
+----------
+int relay_write(channel_id, *data_ptr, count, time_delta_offset, **wrote_pos)
+
+relay_write() reserves space in the channel and writes count bytes of
+data pointed to by data_ptr to it.  Automatically performs any
+necessary locking, depending on the scheme and SMP usage in effect (no
+locking is done for the lockless scheme regardless of usage).  It
+returns the number of bytes written, or 0/negative on failure.  If
+time_delta_offset is >= 0, the internal time delta, the internal time
+delta calculated when the slot was reserved will be written at that
+offset.  This is the TSC or gettimeofday() delta between the current
+write and the beginning of the buffer, whichever method is being used
+by the channel.  Trying to write a count larger than the bufsize
+specified to relay_open() (taking into account the reserved
+start-of-buffer and end-of-buffer space as well) will fail.  If
+wrote_pos is non-NULL, it will receive the location the data was
+written to, which may be needed for some applications but is not
+normally interesting.  Most applications should pass in NULL for this
+param.
+
+----------
+struct rchan_reader *add_rchan_reader(int rchan_id, int auto_consume)
+
+add_rchan_reader creates and initializes a reader object for a
+channel.  An opaque rchan_reader object is returned on success, and is
+passed to relay_read() when reading the channel.  If the boolean
+auto_consume parameter is 1, the reader is defined to be
+auto-consuming.  auto-consuming reader objects are automatically
+created and used for VFS read(2) readers.
+
+----------
+void remove_rchan_reader(struct rchan_reader *reader)
+
+remove_rchan_reader finds and removes the given reader from the
+channel.  This function is used only by non-VFS read(2) readers.  VFS
+read(2) readers are automatically removed when the corresponding file
+object is closed.
+
+----------
+reader add_map_reader(int rchan_id)
+
+Creates and initializes an rchan_reader object for channel map
+readers, and is needed for updating relay_bytes/buffers_consumed()
+when kernel clients become aware of the need to do so by their mmap
+user clients.
+
+----------
+int remove_map_reader(reader)
+
+Finds and removes the given map reader from the channel.  This function
+is useful only for map readers.
+
+----------
+int relay_read(reader, buf, count, wait, *actual_read_offset)
+
+Reads count bytes from the channel, or as much as is available within
+the sub-buffer currently being read.  The read offset that will be
+read from is the position contained within the reader object.  If the
+wait flag is set, buf is non-NULL, and there is nothing available, it
+will wait until there is.  If the wait flag is 0 and there is nothing
+available, -EAGAIN is returned.  If buf is NULL, the value returned is
+the number of bytes that would have been read.  actual_read_offset is
+the value that should be passed as the read offset to
+relay_bytes_consumed, needed only if the reader is not auto-consuming
+and the channel is MODE_NO_OVERWRITE, but in any case, it must not be
+NULL.
+
+---------- 
+
+int relay_bytes_avail(reader)
+
+Returns the number of bytes available relative to the reader's current
+read position within the corresponding sub-buffer, 0 if there is
+nothing available.  Note that this doesn't return the total bytes
+available in the channel buffer - this is enough though to know if
+anything is available, however, or how many bytes might be returned
+from the next read.
+
+----------
+void relay_buffers_consumed(reader, buffers_consumed)
+
+Adds to the channel's consumed buffer count.  buffers_consumed should
+be the number of buffers newly consumed, not the total number
+consumed.  NOTE: kernel clients don't need to call this function if
+the reader is auto-consuming or the channel is MODE_CONTINUOUS.
+
+In order for the relay to detect the 'buffers full' condition for a
+channel, it must be kept up-to-date with respect to the number of
+buffers consumed by the client.  If the addition of the value of the
+bufs_consumed param to the current bufs_consumed count for the channel
+would exceed the bufs_produced count for the channel, the channel's
+bufs_consumed count will be set to the bufs_produced count for the
+channel.  This allows clients to 'catch up' if necessary.
+
+----------
+void relay_bytes_consumed(reader, bytes_consumed, read_offset)
+
+Adds to the channel's consumed count.  bytes_consumed should be the
+number of bytes actually read e.g. return value of relay_read() and
+the read_offset should be the actual offset the bytes were read from
+e.g. the actual_read_offset set by relay_read().  NOTE: kernel clients
+don't need to call this function if the reader is auto-consuming or
+the channel is MODE_CONTINUOUS.
+
+In order for the relay to detect the 'buffers full' condition for a
+channel, it must be kept up-to-date with respect to the number of
+bytes consumed by the client.  For packet clients, it makes more sense
+to update after each read rather than after each complete sub-buffer
+read.  The bytes_consumed count updates bufs_consumed when a buffer
+has been consumed so this count remains consistent.
+
+----------
+int relay_info(channel_id, *channel_info)
+
+relay_info() fills in an rchan_info struct with channel status and
+attribute information such as usage modes, sub-buffer size and count,
+the allocated size of the entire buffer, buffers produced and
+consumed, current buffer id, count of writes lost due to buffers full
+condition.
+
+The virtual address of the channel buffer is also available here, for
+those clients that need it.
+
+Clients may need to know how many 'unused' bytes there are at the end
+of a given sub-buffer.  This would only be the case if the client 1)
+didn't either write this count to the end of the sub-buffer or
+otherwise note it (it's available as the difference between the buffer
+end and current write pos params in the buffer_end callback) (if the
+client returned 0 from the buffer_end callback, it's assumed that this
+is indeed the case) 2) isn't using the read() system call to read the
+buffer.  In other words, if the client isn't annotating the stream and
+is reading the buffer by mmaping it, this information would be needed
+in order for the client to 'skip over' the unused bytes at the ends of
+sub-buffers.
+
+Additionally, for the lockless scheme, clients may need to know
+whether a particular sub-buffer is actually complete.  An array of
+boolean values, one per sub-buffer, contains non-zero if the buffer is
+complete, non-zero otherwise.
+
+----------
+int relay_close(channel_id)
+
+relay_close() is used to close the channel.  It finalizes the last
+sub-buffer (the one currently being written to) and marks the channel
+as finalized.  The channel buffer and channel data structure are then
+freed automatically when the last reference to the channel is given
+up.
+
+----------
+int relay_realloc_buffer(channel_id, nbufs, async)
+
+Allocates a new channel buffer using the specified sub-buffer count
+(note that resizing can't change sub-buffer sizes).  If async is
+non-zero, the allocation is done in the background using a work queue.
+When the allocation has completed, the needs_resize() callback is
+called with a resize_type of RELAY_RESIZE_REPLACE.  This function
+doesn't replace the old buffer with the new - see
+relay_replace_buffer().
+
+This function is called by kernel clients in response to a
+needs_resize() callback call with a resize type of RELAY_RESIZE_EXPAND
+or RELAY_RESIZE_SHRINK.  That callback also includes a suggested
+new_bufsize and new_nbufs which should be used when calling this
+function.
+
+Returns 0 on success, or errcode if the channel is busy or if
+the allocation couldn't happen for some reason.
+
+NOTE: if async is not set, this function should not be called with a
+lock held, as it may sleep.
+
+----------
+int relay_replace_buffer(channel_id)
+
+Replaces the current channel buffer with the new buffer allocated by
+relay_realloc_buffer and contained in the channel struct.  When the
+replacement is complete, the needs_resize() callback is called with
+RELAY_RESIZE_REPLACED.  This function is called by kernel clients in
+response to a needs_resize() callback having a resize type of
+RELAY_RESIZE_REPLACE.
+
+Returns 0 on success, or errcode if the channel is busy or if the
+replacement or previous allocation didn't happen for some reason.
+
+NOTE: This function will not sleep, so can called in any context and
+with locks held.  The client should, however, ensure that the channel
+isn't actively being read from or written to.
+
+----------
+int relay_reset(rchan_id)
+
+relay_reset() has the effect of erasing all data from the buffer and
+restarting the channel in its initial state.  The buffer itself is not
+freed, so any mappings are still in effect.  NOTE: Care should be
+taken that the channnel isn't actually being used by anything when
+this call is made.
+
+----------
+int rchan_full(reader)
+
+returns 1 if the channel is full with respect to the reader, 0 if not.
+
+----------
+int rchan_empty(reader)
+
+returns 1 if the channel is empty with respect to the reader, 0 if not.
+
+----------
+int relay_discard_init_buf(rchan_id)
+
+allocates an mmappable channel buffer, copies the contents of init_buf
+into it, and sets the current channel buffer to the newly allocated
+buffer.  This function is used only in conjunction with the init_buf
+and init_buf_size params to relay_open(), and is typically used when
+the ability to write into the channel at init-time is needed.  The
+basic usage is to specify an init_buf and init_buf_size to relay_open,
+then call this function when it's safe to switch over to a normally
+allocated channel buffer.  'Safe' means that the caller is in a
+context that can sleep and that nothing is actively writing to the
+channel.  Returns 0 if successful, negative otherwise.
+
+
+Writing directly into the channel
+=================================
+
+Using the relay_write() API function as described above is the
+preferred means of writing into a channel.  In some cases, however,
+in-kernel clients might want to write directly into a relay channel
+rather than have relay_write() copy it into the buffer on the client's
+behalf.  Clients wishing to do this should follow the model used to
+implement relay_write itself.  The general sequence is:
+
+- get a pointer to the channel via rchan_get().  This increments the
+  channel's reference count.
+- call relay_lock_channel().  This will perform the proper locking for
+  the channel given the scheme in use and the SMP usage.
+- reserve a slot in the channel via relay_reserve()
+- write directly to the reserved address
+- call relay_commit() to commit the write
+- call relay_unlock_channel()
+- call rchan_put() to release the channel reference
+
+In particular, clients should make sure they call rchan_get() and
+rchan_put() and not hold on to references to the channel pointer.
+Also, forgetting to use relay_lock_channel()/relay_unlock_channel()
+has no effect if the lockless scheme is being used, but could result
+in corrupted buffer contents if the locking scheme is used.
+
+
+Limitations
+===========
+
+Writes made via the write() system call are currently limited to 2
+pages worth of data.  There is no such limit on the in-kernel API
+function relay_write().
+
+User applications can currently only mmap the complete buffer (it
+doesn't really make sense to mmap only part of it, given its purpose).
+
+
+Latest version
+==============
+
+The latest version can be found at:
+
+http://www.opersys.com/relayfs
+
+Example relayfs clients, such as dynamic printk and the Linux Trace
+Toolkit, can also be found there.
+
+
+Credits
+=======
+
+The ideas and specs for relayfs came about as a result of discussions
+on tracing involving the following:
+
+Michel Dagenais		<michel.dagenais@polymtl.ca>
+Richard Moore		<richardj_moore@uk.ibm.com>
+Bob Wisniewski		<bob@watson.ibm.com>
+Karim Yaghmour		<karim@opersys.com>
+Tom Zanussi		<zanussi@us.ibm.com>
+
+Also thanks to Hubertus Franke for a lot of useful suggestions and bug
+reports, and for contributing the klog code.
diff -uNrp linux-2.6.9/MAINTAINERS linux-2.6.9-ltt-r12/MAINTAINERS
--- linux-2.6.9/MAINTAINERS	2004-10-18 23:54:37.000000000 +0200
+++ linux-2.6.9-ltt-r12/MAINTAINERS	2005-08-15 10:51:46.000000000 +0200
@@ -1354,6 +1354,13 @@ L:	linux-security-module@wirex.com
 W:	http://lsm.immunix.org
 S:	Supported
 
+LINUX TRACE TOOLKIT
+P:	Karim Yaghmour
+M:	karim@opersys.com
+W:	http://www.opersys.com/LTT
+L:	ltt-dev@listserv.shafik.org
+S:	Maintained
+
 LM83 HARDWARE MONITOR DRIVER
 P:	Jean Delvare
 M:	khali@linux-fr.org
diff -uNrp linux-2.6.9/Makefile linux-2.6.9-ltt-r12/Makefile
--- linux-2.6.9/Makefile	2004-10-18 23:54:38.000000000 +0200
+++ linux-2.6.9-ltt-r12/Makefile	2005-08-15 10:31:45.000000000 +0200
@@ -511,7 +511,7 @@ export KBUILD_IMAGE ?= vmlinux
 # images.  Uncomment if you want to place them anywhere other than root.
 #
 
-#export	INSTALL_PATH=/boot
+export	INSTALL_PATH=/boot
 
 #
 # INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory
@@ -526,6 +526,8 @@ export MODLIB
 ifeq ($(KBUILD_EXTMOD),)
 core-y		+= kernel/ mm/ fs/ ipc/ security/ crypto/
 
+core-$(CONFIG_ADEOS) += adeos/
+
 vmlinux-dirs	:= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
 		     $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
 		     $(net-y) $(net-m) $(libs-y) $(libs-m)))
diff -uNrp linux-2.6.9/adeos/Kconfig linux-2.6.9-ltt-r12/adeos/Kconfig
--- linux-2.6.9/adeos/Kconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/adeos/Kconfig	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,40 @@
+menu "Adeos support"
+
+config ADEOS
+	tristate "Adeos support"
+	default y
+	---help---
+	  Activate this option if you want the Adeos nanokernel to be
+	  compiled in.
+
+config ADEOS_CORE
+	def_bool ADEOS
+
+config ADEOS_THREADS
+	bool "Threaded domains"
+	depends on ADEOS
+	default y
+	---help---
+	  This option causes the domains to run as lightweight
+	  threads, which is useful for having seperate stacks
+	  for domains. Enabling this option is the safest setting for
+	  now; disabling it causes an experimental mode to be used
+	  where interrupts/events are directly processed on behalf of
+	  the preempted context. Say Y if unsure.
+
+config ADEOS_NOTHREADS
+	def_bool !ADEOS_THREADS
+
+config ADEOS_PROFILING
+	bool "Pipeline profiling"
+	depends on ADEOS
+	default n
+	---help---
+	  This option activates the profiling code which collects the
+	  timestamps needed to measure the propagation time of
+	  interrupts through the pipeline. Say N if unsure.
+
+config ADEOS_PREEMPT_RT
+	def_bool PREEMPT_NONE || PREEMPT_VOLUNTARY || PREEMPT_DESKTOP || PREEMPT_RT
+
+endmenu
diff -uNrp linux-2.6.9/adeos/Makefile linux-2.6.9-ltt-r12/adeos/Makefile
--- linux-2.6.9/adeos/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/adeos/Makefile	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,13 @@
+#
+# Makefile for the Adeos layer.
+#
+
+obj-$(CONFIG_ADEOS)	+= adeos.o
+
+adeos-objs		:= generic.o
+
+adeos-$(CONFIG_X86)	+= x86.o
+
+adeos-$(CONFIG_IA64)	+= ia64.o
+
+adeos-$(CONFIG_PPC)	+= ppc.o
diff -uNrp linux-2.6.9/adeos/generic.c linux-2.6.9-ltt-r12/adeos/generic.c
--- linux-2.6.9/adeos/generic.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/adeos/generic.c	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,638 @@
+/*
+ *   linux/adeos/generic.c
+ *
+ *   Copyright (C) 2002 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *   Architecture-independent ADEOS services.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+
+MODULE_DESCRIPTION("Adeos nanokernel");
+MODULE_AUTHOR("Philippe Gerum");
+MODULE_LICENSE("GPL");
+
+/* adeos_register_domain() -- Add a new domain to the system. All
+   client domains must call this routine to register themselves to
+   ADEOS before using its services. */
+
+int adeos_register_domain (adomain_t *adp, adattr_t *attr)
+
+{
+    struct list_head *pos;
+    unsigned long flags;
+    int n;
+
+    if (adp_current != adp_root)
+	{
+	printk(KERN_WARNING "Adeos: Only the root domain may register a new domain.\n");
+	return -EPERM;
+	}
+
+    flags = adeos_critical_enter(NULL);
+
+    list_for_each(pos,&__adeos_pipeline) {
+    	adomain_t *_adp = list_entry(pos,adomain_t,p_link);
+	if (_adp->domid == attr->domid)
+            break;
+    }
+
+    adeos_critical_exit(flags);
+
+    if (pos != &__adeos_pipeline)
+	/* A domain with the given id already exists -- fail. */
+	return -EBUSY;
+
+    for (n = 0; n < ADEOS_NR_CPUS; n++)
+	{
+	/* Each domain starts in sleeping state on every CPU. */
+	adp->cpudata[n].status = (1 << IPIPE_SLEEP_FLAG);
+#ifdef CONFIG_ADEOS_THREADS
+	adp->estackbase[n] = 0;
+#endif /* CONFIG_ADEOS_THREADS */
+	}
+
+    adp->name = attr->name;
+    adp->priority = attr->priority;
+    adp->domid = attr->domid;
+    adp->dswitch = attr->dswitch;
+    adp->flags = 0;
+    adp->ptd_setfun = attr->ptdset;
+    adp->ptd_getfun = attr->ptdget;
+    adp->ptd_keymap = 0;
+    adp->ptd_keycount = 0;
+    adp->ptd_keymax = attr->nptdkeys;
+
+    for (n = 0; n < ADEOS_NR_EVENTS; n++)
+	/* Event handlers must be cleared before the i-pipe stage is
+	   inserted since an exception may occur on behalf of the new
+	   emerging domain. */
+	adp->events[n].handler = NULL;
+
+    if (attr->entry != NULL)
+	__adeos_init_domain(adp,attr);
+
+    /* Insert the domain in the interrupt pipeline last, so it won't
+       be resumed for processing interrupts until it has a valid stack
+       context. */
+
+    __adeos_init_stage(adp);
+
+    INIT_LIST_HEAD(&adp->p_link);
+
+    flags = adeos_critical_enter(NULL);
+
+    list_for_each(pos,&__adeos_pipeline) {
+    	adomain_t *_adp = list_entry(pos,adomain_t,p_link);
+	if (adp->priority > _adp->priority)
+            break;
+    }
+
+    list_add_tail(&adp->p_link,pos);
+
+    adeos_critical_exit(flags);
+
+    printk(KERN_WARNING "Adeos: Domain %s registered.\n",adp->name);
+
+    /* Finally, allow the new domain to perform its initialization
+       chores. */
+
+    if (attr->entry != NULL)
+	{
+	adeos_declare_cpuid;
+
+	adeos_lock_cpu(flags);
+
+#ifdef CONFIG_ADEOS_THREADS
+	__adeos_switch_to(adp_root,adp,cpuid);
+#else /* !CONFIG_ADEOS_THREADS */
+	adp_cpu_current[cpuid] = adp;
+	attr->entry(1);
+	adp_cpu_current[cpuid] = adp_root;
+#endif /* CONFIG_ADEOS_THREADS */
+
+	adeos_load_cpuid();	/* Processor might have changed. */
+
+	if (adp_root->cpudata[cpuid].irq_pending_hi != 0 &&
+	    !test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status))
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+	adeos_unlock_cpu(flags);
+	}
+
+    return 0;
+}
+
+/* adeos_unregister_domain() -- Remove a domain from the system. All
+   client domains must call this routine to unregister themselves from
+   the ADEOS layer. */
+
+int adeos_unregister_domain (adomain_t *adp)
+
+{
+    unsigned long flags;
+    unsigned event;
+
+    if (adp_current != adp_root)
+	{
+	printk(KERN_WARNING "Adeos: Only the root domain may unregister a domain.\n");
+	return -EPERM;
+	}
+
+    if (adp == adp_root)
+	{
+	printk(KERN_WARNING "Adeos: Cannot unregister the root domain.\n");
+	return -EPERM;
+	}
+
+    for (event = 0; event < ADEOS_NR_EVENTS; event++)
+	/* Need this to update the monitor count. */
+	adeos_catch_event_from(adp,event,NULL);
+
+#ifdef CONFIG_SMP
+    {
+    int nr_cpus = num_online_cpus(), _cpuid;
+    unsigned irq;
+
+    /* In the SMP case, wait for the logged events to drain on other
+       processors before eventually removing the domain from the
+       pipeline. */
+
+    adeos_unstall_pipeline_from(adp);
+
+    flags = adeos_critical_enter(NULL);
+
+    for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+	{
+	clear_bit(IPIPE_HANDLE_FLAG,&adp->irqs[irq].control);
+	clear_bit(IPIPE_STICKY_FLAG,&adp->irqs[irq].control);
+	set_bit(IPIPE_PASS_FLAG,&adp->irqs[irq].control);
+	}
+
+    adeos_critical_exit(flags);
+
+    for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+	{
+	for (irq = 0; irq < IPIPE_NR_IRQS; irq++)
+	    while (adp->cpudata[_cpuid].irq_hits[irq] > 0)
+		cpu_relax();
+
+	while (test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[_cpuid].status))
+	    cpu_relax();
+
+	while (!test_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[_cpuid].status))
+	     cpu_relax();
+	}
+    }
+#endif /* CONFIG_SMP */
+
+    /* Simply remove the domain from the pipeline and we are almost
+       done. */
+
+    flags = adeos_critical_enter(NULL);
+    list_del_init(&adp->p_link);
+    adeos_critical_exit(flags);
+
+    __adeos_cleanup_domain(adp);
+
+    printk(KERN_WARNING "Adeos: Domain %s unregistered.\n",adp->name);
+
+    return 0;
+}
+
+/* adeos_propagate_irq() -- Force a given IRQ propagation on behalf of
+   a running interrupt handler to the next domain down the pipeline.
+   Returns non-zero if a domain has received the interrupt
+   notification, zero otherwise.
+   This call is useful for handling shared interrupts among domains.
+   e.g. pipeline = [domain-A]---[domain-B]...
+   Both domains share IRQ #X.
+   - domain-A handles IRQ #X but does not pass it down (i.e. Terminate
+   or Dynamic interrupt control mode)
+   - domain-B handles IRQ #X (i.e. Terminate or Accept interrupt
+   control modes).
+   When IRQ #X is raised, domain-A's handler determines whether it
+   should process the interrupt by identifying its source. If not,
+   adeos_propagate_irq() is called so that the next domain down the
+   pipeline which handles IRQ #X is given a chance to process it. This
+   process can be repeated until the end of the pipeline is
+   reached. */
+
+/* adeos_schedule_irq() -- Almost the same as adeos_propagate_irq(),
+   but attempts to pend the interrupt for the current domain first. */
+
+int fastcall __adeos_schedule_irq (unsigned irq, struct list_head *head)
+
+{
+    struct list_head *ln;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    if (irq >= IPIPE_NR_IRQS ||
+	(adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)))
+	return -EINVAL;
+
+    adeos_lock_cpu(flags);
+
+    ln = head;
+
+    while (ln != &__adeos_pipeline)
+	{
+	adomain_t *adp = list_entry(ln,adomain_t,p_link);
+
+	if (test_bit(IPIPE_HANDLE_FLAG,&adp->irqs[irq].control))
+	    {
+	    adp->cpudata[cpuid].irq_hits[irq]++;
+	    __adeos_set_irq_bit(adp,cpuid,irq);
+	    adeos_unlock_cpu(flags);
+	    return 1;
+	    }
+
+	ln = adp->p_link.next;
+	}
+
+    adeos_unlock_cpu(flags);
+
+    return 0;
+}
+
+/* adeos_free_irq() -- Return a previously allocated virtual/soft
+   pipelined interrupt to the pool of allocatable interrupts. */
+
+int adeos_free_irq (unsigned irq)
+
+{
+    if (irq >= IPIPE_NR_IRQS)
+	return -EINVAL;
+
+    clear_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map);
+
+    return 0;
+}
+
+cpumask_t adeos_set_irq_affinity (unsigned irq, cpumask_t cpumask)
+
+{
+#ifdef CONFIG_SMP
+     if (irq >= IPIPE_NR_XIRQS)
+	 /* Allow changing affinity of external IRQs only. */
+	 return CPU_MASK_NONE;
+
+     if (num_online_cpus() > 1)
+	 /* Allow changing affinity of external IRQs only. */
+	 return __adeos_set_irq_affinity(irq,cpumask);
+#endif /* CONFIG_SMP */
+
+    return CPU_MASK_NONE;
+}
+
+/* adeos_catch_event_from() -- Interpose an event handler starting
+   from a given domain. */
+
+int adeos_catch_event_from (adomain_t *adp, unsigned event, void (*handler)(adevinfo_t *))
+
+{
+    if (event >= ADEOS_NR_EVENTS)
+	return -EINVAL;
+
+    if (!xchg(&adp->events[event].handler,handler))
+	{
+	if (handler)
+	    __adeos_event_monitors[event]++;
+	}
+    else if (!handler)
+	__adeos_event_monitors[event]--;
+
+    return 0;
+}
+
+void adeos_init_attr (adattr_t *attr)
+
+{
+    attr->name = "Anonymous";
+    attr->domid = 1;
+    attr->entry = NULL;
+    attr->estacksz = 0;	/* Let ADEOS choose a reasonable stack size */
+    attr->priority = ADEOS_ROOT_PRI;
+    attr->dswitch = NULL;
+    attr->nptdkeys = 0;
+    attr->ptdset = NULL;
+    attr->ptdget = NULL;
+}
+
+int adeos_alloc_ptdkey (void)
+
+{
+    unsigned long flags;
+    int key = -1;
+
+    spin_lock_irqsave_hw(&__adeos_pipelock,flags);
+
+    if (adp_current->ptd_keycount < adp_current->ptd_keymax)
+	{
+	key = ffz(adp_current->ptd_keymap);
+	set_bit(key,&adp_current->ptd_keymap);
+	adp_current->ptd_keycount++;
+	}
+
+    spin_unlock_irqrestore_hw(&__adeos_pipelock,flags);
+
+    return key;
+}
+
+int adeos_free_ptdkey (int key)
+
+{
+    unsigned long flags; 
+
+    if (key < 0 || key >= adp_current->ptd_keymax)
+	return -EINVAL;
+
+    spin_lock_irqsave_hw(&__adeos_pipelock,flags);
+
+    if (test_and_clear_bit(key,&adp_current->ptd_keymap))
+	adp_current->ptd_keycount--;
+
+    spin_unlock_irqrestore_hw(&__adeos_pipelock,flags);
+
+    return 0;
+}
+
+int adeos_set_ptd (int key, void *value)
+
+{
+    if (key < 0 || key >= adp_current->ptd_keymax)
+	return -EINVAL;
+
+    if (!adp_current->ptd_setfun)
+	{
+	printk(KERN_WARNING "Adeos: No ptdset hook for %s\n",adp_current->name);
+	return -EINVAL;
+	}
+
+    adp_current->ptd_setfun(key,value);
+
+    return 0;
+}
+
+void *adeos_get_ptd (int key)
+
+{
+    if (key < 0 || key >= adp_current->ptd_keymax)
+	return NULL;
+
+    if (!adp_current->ptd_getfun)
+	{
+	printk(KERN_WARNING "Adeos: No ptdget hook for %s\n",adp_current->name);
+	return NULL;
+	}
+
+    return adp_current->ptd_getfun(key);
+}
+
+int adeos_init_mutex (admutex_t *mutex)
+
+{
+    admutex_t initm = ADEOS_MUTEX_UNLOCKED;
+    *mutex = initm;
+    return 0;
+}
+
+#ifdef CONFIG_ADEOS_THREADS
+
+int adeos_destroy_mutex (admutex_t *mutex)
+
+{
+    if (!adeos_spin_trylock(&mutex->lock) &&
+	adp_current != adp_root &&
+	mutex->owner != adp_current)
+	return -EBUSY;
+
+    return 0;
+}
+
+static inline void __adeos_sleepon_mutex (admutex_t *mutex, adomain_t *sleeper, int cpuid)
+
+{
+    adomain_t *owner = mutex->owner;
+
+    /* Make the current domain (== sleeper) wait for the mutex to be
+       released. Adeos' pipelined scheme guarantees that the new
+       sleeper _is_ higher priority than any aslept domain since we
+       have stalled each sleeper's stage. Must be called with local hw
+       interrupts off. */
+
+    sleeper->m_link = mutex->sleepq;
+    mutex->sleepq = sleeper;
+    __adeos_switch_to(adp_cpu_current[cpuid],owner,cpuid);
+    mutex->owner = sleeper;
+    adeos_spin_unlock(&mutex->lock);
+}
+
+unsigned long fastcall adeos_lock_mutex (admutex_t *mutex)
+
+{
+    unsigned long flags, hwflags;
+    adeos_declare_cpuid;
+    adomain_t *adp;
+
+    if (!adp_pipelined)
+	{
+	adeos_hw_local_irq_save(hwflags);
+	flags = !adeos_hw_test_iflag(hwflags);
+	adeos_spin_lock(&mutex->lock);
+	return flags;
+	}
+
+    adeos_lock_cpu(hwflags);
+
+    adp = adp_cpu_current[cpuid];
+
+    flags = __test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+    /* Two cases to handle here on SMP systems, only one for UP: 1) in
+       case of a conflicting access from a higher priority domain
+       running on the same cpu, make this domain sleep on the mutex,
+       and resume the current owner so it can release the lock asap.
+       2) in case of a conflicting access from any domain on a
+       different cpu than the current owner's, simply enter a spinning
+       loop. Note that testing mutex->owncpu is safe since it is only
+       changed by the current owner, and set to -1 when the mutex is
+       unlocked. */
+
+#ifdef CONFIG_SMP
+    while (!adeos_spin_trylock(&mutex->lock))
+	{
+	if (mutex->owncpu == cpuid)
+	    {
+	    __adeos_sleepon_mutex(mutex,adp,cpuid);
+	    adeos_load_cpuid();
+	    }
+	}
+
+    mutex->owncpu = cpuid;
+#else  /* !CONFIG_SMP */
+    while (mutex->owner != NULL && mutex->owner != adp)
+	__adeos_sleepon_mutex(mutex,adp,cpuid);
+#endif /* CONFIG_SMP */
+
+    mutex->owner = adp;
+
+    adeos_unlock_cpu(hwflags);
+
+    return flags;
+}
+
+void fastcall adeos_unlock_mutex (admutex_t *mutex, unsigned long flags)
+
+{
+    unsigned long hwflags;
+    adeos_declare_cpuid;
+    adomain_t *adp;
+
+    if (!adp_pipelined)
+	{
+	adeos_spin_unlock(&mutex->lock);
+
+	if (flags)
+	    adeos_hw_cli();
+	else
+	    adeos_hw_sti();
+
+	return;
+	}
+
+#ifdef CONFIG_SMP
+    mutex->owncpu = -1;
+#endif /* CONFIG_SMP */
+
+    if (!flags)
+	adeos_hw_sti();	/* Absolutely needed. */
+	
+    adeos_lock_cpu(hwflags);
+
+    if (mutex->sleepq != NULL)
+	{
+	adomain_t *sleeper = mutex->sleepq;
+	/* Wake up the highest priority sleeper. */
+	mutex->sleepq = sleeper->m_link;
+	__adeos_switch_to(adp_cpu_current[cpuid],sleeper,cpuid);
+	adeos_load_cpuid();
+	}
+    else
+	{
+	mutex->owner = NULL;
+	adeos_spin_unlock(&mutex->lock);
+	}
+
+    adp = adp_cpu_current[cpuid];
+
+    if (flags)
+	__set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    else
+	{
+	__clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+	
+	if (adp->cpudata[cpuid].irq_pending_hi != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	}
+
+    adeos_unlock_cpu(hwflags);
+}
+
+#else /* !CONFIG_ADEOS_THREADS */
+
+int adeos_destroy_mutex (admutex_t *mutex)
+
+{
+    if (!adeos_spin_trylock(&mutex->lock) &&
+	adp_current != adp_root)
+	return -EBUSY;
+
+    return 0;
+}
+
+unsigned long fastcall adeos_lock_mutex (admutex_t *mutex)
+
+{
+    unsigned long flags; /* FIXME: won't work on SPARC */
+    spin_lock_irqsave_hw(&mutex->lock,flags);
+    return flags;
+}
+
+void fastcall adeos_unlock_mutex (admutex_t *mutex, unsigned long flags)
+
+{
+    spin_unlock_irqrestore_hw(&mutex->lock,flags);
+}
+
+#endif /* CONFIG_ADEOS_THREADS */
+
+void __adeos_takeover (void)
+
+{
+    __adeos_enable_pipeline();
+    printk(KERN_WARNING "Adeos: Pipelining started.\n");
+}
+
+#ifdef MODULE
+
+static int __init adeos_init_module (void)
+
+{
+    __adeos_takeover();
+    return 0;
+}
+
+static void __exit adeos_exit_module (void)
+
+{
+    __adeos_disable_pipeline();
+    printk(KERN_WARNING "Adeos: Pipelining stopped.\n");
+}
+
+module_init(adeos_init_module);
+module_exit(adeos_exit_module);
+
+#endif /* MODULE */
+
+EXPORT_SYMBOL(adeos_register_domain);
+EXPORT_SYMBOL(adeos_unregister_domain);
+EXPORT_SYMBOL(adeos_virtualize_irq_from);
+EXPORT_SYMBOL(adeos_control_irq);
+EXPORT_SYMBOL(__adeos_schedule_irq);
+EXPORT_SYMBOL(adeos_free_irq);
+EXPORT_SYMBOL(adeos_send_ipi);
+EXPORT_SYMBOL(adeos_catch_event_from);
+EXPORT_SYMBOL(adeos_init_attr);
+EXPORT_SYMBOL(adeos_get_sysinfo);
+EXPORT_SYMBOL(adeos_tune_timer);
+EXPORT_SYMBOL(adeos_alloc_ptdkey);
+EXPORT_SYMBOL(adeos_free_ptdkey);
+EXPORT_SYMBOL(adeos_set_ptd);
+EXPORT_SYMBOL(adeos_get_ptd);
+EXPORT_SYMBOL(adeos_set_irq_affinity);
+EXPORT_SYMBOL(adeos_init_mutex);
+EXPORT_SYMBOL(adeos_destroy_mutex);
+EXPORT_SYMBOL(adeos_lock_mutex);
+EXPORT_SYMBOL(adeos_unlock_mutex);
diff -uNrp linux-2.6.9/adeos/x86.c linux-2.6.9-ltt-r12/adeos/x86.c
--- linux-2.6.9/adeos/x86.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/adeos/x86.c	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,778 @@
+/*
+ *   linux/adeos/x86.c
+ *
+ *   Copyright (C) 2002 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *   Architecture-dependent ADEOS support for x86.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/desc.h>
+#include <asm/io.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/fixmap.h>
+#include <asm/bitops.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif /* CONFIG_X86_IO_APIC */
+#include <asm/apic.h>
+#include <mach_ipi.h>
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+extern struct desc_struct idt_table[];
+
+extern void (*__adeos_irq_trampolines[])(void); /* in entry.S */
+
+static void (*__adeos_std_vector_table[256])(void);
+
+/* Lifted from arch/i386/kernel/traps.c */ 
+#define __adeos_set_gate(gate_addr,type,dpl,addr)  \
+do { \
+  int __d0, __d1; \
+  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+	"movw %4,%%dx\n\t" \
+	"movl %%eax,%0\n\t" \
+	"movl %%edx,%1" \
+	:"=m" (*((long *) (gate_addr))), \
+	 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
+	:"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+	 "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
+} while (0)
+
+#define __adeos_get_gate_addr(v) \
+	((void *)((idt_table[v].b & 0xffff0000)|(idt_table[v].a & 0xffff)))
+
+#define __adeos_set_irq_gate(vector,addr) \
+__adeos_set_gate(idt_table+vector,14,0,addr)
+
+#define __adeos_set_trap_gate(vector,addr) \
+__adeos_set_gate(idt_table+vector,15,0,addr)
+
+#define __adeos_set_sys_gate(vector,addr) \
+__adeos_set_gate(idt_table+vector,15,3,addr)
+
+#define BUILD_TRAP_PROTO(trapnr)  __adeos_trap_##trapnr(void)
+
+#define BUILD_TRAP_ERRCODE(trapnr) \
+asmlinkage void BUILD_TRAP_PROTO(trapnr); \
+__asm__ ( \
+	"\n" __ALIGN_STR"\n\t" \
+        SYMBOL_NAME_STR(__adeos_trap_) #trapnr ":\n\t" \
+        "cld\n\t" \
+        "pushl %es\n\t" \
+        "pushl %ds\n\t" \
+        "pushl %eax\n\t" \
+        "pushl %ebp\n\t" \
+        "pushl %edi\n\t" \
+        "pushl %esi\n\t" \
+        "pushl %edx\n\t" \
+        "pushl %ecx\n\t" \
+        "pushl %ebx\n\t" \
+        "movl $" STR(__USER_DS) ",%edx\n\t" \
+	"mov %dx,%ds\n\t" \
+	"mov %dx,%es\n\t" \
+        "movl ("SYMBOL_NAME_STR(__adeos_event_monitors + 4 * trapnr)"),%eax\n\t" \
+	"testl %eax,%eax\n\t" \
+	"jz 1f\n\t" \
+	"movl %esp,%eax\n\t" \
+        "pushl %eax\n\t" \
+	"pushl $"#trapnr"\n\t" \
+        "call " SYMBOL_NAME_STR(__adeos_handle_event) "\n\t" \
+	"addl $8,%esp\n\t" \
+	"testl %eax,%eax\n\t" \
+"1:      popl %ebx\n\t" \
+        "popl %ecx\n\t" \
+	"popl %edx\n\t" \
+        "popl %esi\n\t" \
+        "popl %edi\n\t" \
+	"popl %ebp\n\t" \
+	"jz 2f\n\t" \
+	"popl %eax\n\t" \
+	"popl %ds\n\t" \
+	"popl %es\n\t" \
+	"addl $4,%esp\n\t" \
+	"iret\n" \
+"2:      movl ("SYMBOL_NAME_STR(__adeos_std_vector_table + 4 * trapnr)"),%eax\n\t" \
+	"mov 8(%esp),%es\n\t" \
+	"movl %eax,8(%esp)\n\t" \
+	"popl %eax\n\t" \
+	"popl %ds\n\t" \
+	"ret\n");
+
+#define BUILD_TRAP_NOERRCODE(trapnr) \
+asmlinkage void BUILD_TRAP_PROTO(trapnr); \
+__asm__ ( \
+	"\n" __ALIGN_STR"\n\t" \
+        SYMBOL_NAME_STR(__adeos_trap_) #trapnr ":\n\t" \
+        "cld\n\t" \
+        "pushl $0\n\t" \
+        "pushl %es\n\t" \
+        "pushl %ds\n\t" \
+        "pushl %eax\n\t" \
+        "pushl %ebp\n\t" \
+        "pushl %edi\n\t" \
+        "pushl %esi\n\t" \
+        "pushl %edx\n\t" \
+        "pushl %ecx\n\t" \
+        "pushl %ebx\n\t" \
+        "movl $" STR(__USER_DS) ",%edx\n\t" \
+	"mov %dx,%ds\n\t" \
+	"mov %dx,%es\n\t" \
+        "movl ("SYMBOL_NAME_STR(__adeos_event_monitors + 4 * trapnr)"),%eax\n\t" \
+	"testl %eax,%eax\n\t" \
+	"jz 1f\n\t" \
+	"movl %esp,%eax\n\t" \
+        "pushl %eax\n\t" \
+	"pushl $"#trapnr"\n\t" \
+        "call " SYMBOL_NAME_STR(__adeos_handle_event) "\n\t" \
+	"addl $8,%esp\n\t" \
+	"testl %eax,%eax\n\t" \
+"1:      popl %ebx\n\t" \
+        "popl %ecx\n\t" \
+	"popl %edx\n\t" \
+        "popl %esi\n\t" \
+        "popl %edi\n\t" \
+	"popl %ebp\n\t" \
+	"jz 2f\n\t" \
+	"popl %eax\n\t" \
+	"popl %ds\n\t" \
+	"popl %es\n\t" \
+	"addl $4,%esp\n\t" \
+	"iret\n" \
+"2:      movl ("SYMBOL_NAME_STR(__adeos_std_vector_table + 4 * trapnr)"),%eax\n\t" \
+	"mov %eax,12(%esp)\n\t" \
+	"popl %eax\n\t" \
+	"popl %ds\n\t" \
+	"popl %es\n\t" \
+	"ret\n");
+
+BUILD_TRAP_NOERRCODE(0x0)   BUILD_TRAP_NOERRCODE(0x1)   BUILD_TRAP_NOERRCODE(0x2)
+BUILD_TRAP_NOERRCODE(0x3)   BUILD_TRAP_NOERRCODE(0x4)   BUILD_TRAP_NOERRCODE(0x5)
+BUILD_TRAP_NOERRCODE(0x6)   BUILD_TRAP_NOERRCODE(0x7)   BUILD_TRAP_ERRCODE(0x8)
+BUILD_TRAP_NOERRCODE(0x9)   BUILD_TRAP_ERRCODE(0xa)     BUILD_TRAP_ERRCODE(0xb)
+BUILD_TRAP_ERRCODE(0xc)     BUILD_TRAP_ERRCODE(0xd)     BUILD_TRAP_ERRCODE(0xe)
+BUILD_TRAP_NOERRCODE(0xf)   BUILD_TRAP_NOERRCODE(0x10)  BUILD_TRAP_ERRCODE(0x11)
+BUILD_TRAP_NOERRCODE(0x12)  BUILD_TRAP_NOERRCODE(0x13)  BUILD_TRAP_ERRCODE(0x14)
+BUILD_TRAP_ERRCODE(0x15)    BUILD_TRAP_ERRCODE(0x16)    BUILD_TRAP_ERRCODE(0x17)
+BUILD_TRAP_ERRCODE(0x18)    BUILD_TRAP_ERRCODE(0x19)    BUILD_TRAP_ERRCODE(0x1a)
+BUILD_TRAP_ERRCODE(0x1b)    BUILD_TRAP_ERRCODE(0x1c)    BUILD_TRAP_ERRCODE(0x1d)
+BUILD_TRAP_ERRCODE(0x1e)    BUILD_TRAP_ERRCODE(0x1f)
+
+#define LIST_TRAP(trapnr) &__adeos_trap_ ## trapnr
+
+static void (*__adeos_trap_trampolines[])(void) = {
+    LIST_TRAP(0x0), LIST_TRAP(0x1), LIST_TRAP(0x2), LIST_TRAP(0x3),
+    LIST_TRAP(0x4), LIST_TRAP(0x5), LIST_TRAP(0x6), LIST_TRAP(0x7),
+    LIST_TRAP(0x8), LIST_TRAP(0x9), LIST_TRAP(0xa), LIST_TRAP(0xb),
+    LIST_TRAP(0xc), LIST_TRAP(0xd), LIST_TRAP(0xe), LIST_TRAP(0xf),
+    LIST_TRAP(0x10), LIST_TRAP(0x11), LIST_TRAP(0x12), LIST_TRAP(0x13),
+    LIST_TRAP(0x14), LIST_TRAP(0x15), LIST_TRAP(0x16), LIST_TRAP(0x17),
+    LIST_TRAP(0x18), LIST_TRAP(0x19), LIST_TRAP(0x1a), LIST_TRAP(0x1b),
+    LIST_TRAP(0x1c), LIST_TRAP(0x1d), LIST_TRAP(0x1e), LIST_TRAP(0x1f)
+};
+
+static int __adeos_ack_common_irq (unsigned irq)
+
+{
+    irq_desc_t *desc = irq_desc + irq;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_load_cpuid();		/* hw interrupts are off. */
+    flags = adeos_test_and_stall_pipeline();
+    preempt_disable();
+    desc->handler->ack(irq);
+    preempt_enable_no_resched();
+    adeos_restore_pipeline_nosync(adp_cpu_current[cpuid],flags,cpuid);
+
+    return 1;
+}
+
+/* __adeos_enable_pipeline() -- Take over the interrupt control from
+   the root domain (i.e. Linux). After this routine has returned, all
+   interrupts go through the pipeline. */
+
+void __adeos_enable_pipeline (void)
+
+{
+    unsigned vector, irq, rirq;
+    unsigned long flags;
+
+    /* Collect the original vector table. */
+
+    for (vector = 0; vector < 256; vector++)
+	__adeos_std_vector_table[vector] = __adeos_get_gate_addr(vector);
+
+#ifdef CONFIG_SMP
+
+    /* This vector must be set up prior to call
+       adeos_critical_enter(). */
+
+    __adeos_set_irq_gate(ADEOS_CRITICAL_VECTOR,
+		       __adeos_irq_trampolines[ADEOS_CRITICAL_IPI]);
+
+#endif /* CONFIG_SMP */
+
+    flags = adeos_critical_enter(NULL);
+
+    /* First, grab the ISA and IO-APIC interrupts. */
+
+    for (irq = 0; irq < NR_IRQS && irq + FIRST_EXTERNAL_VECTOR < FIRST_SYSTEM_VECTOR; irq++)
+	{
+	rirq = irq;
+
+#ifdef CONFIG_X86_IO_APIC
+	if (IO_APIC_IRQ(irq))
+	    {
+	    vector = IO_APIC_VECTOR(irq);
+
+	    if (vector == 0)
+		continue;
+
+#ifdef CONFIG_PCI_MSI
+	    /* Account specifically for MSI routing. */
+	    if (!platform_legacy_irq(irq))
+		rirq = vector;
+#endif /* CONFIG_PCI_MSI */
+	    }
+	else
+#endif /* CONFIG_X86_IO_APIC */
+	    {
+	    vector = irq + FIRST_EXTERNAL_VECTOR;
+
+	    if (vector == SYSCALL_VECTOR)
+		continue;
+	    }
+
+	/* Fails for ADEOS_CRITICAL_IPI but that's ok. */
+
+	adeos_virtualize_irq(rirq,
+			     (void (*)(unsigned))__adeos_std_vector_table[vector],
+			     &__adeos_ack_common_irq,
+			     IPIPE_CALLASM_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK);
+
+	__adeos_set_irq_gate(vector,__adeos_irq_trampolines[rirq]);
+	}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+    /* Map the APIC system vectors including the unused ones so that
+       client domains can virtualize the corresponding IRQs. */
+
+    for (vector = FIRST_SYSTEM_VECTOR; vector < CALL_FUNCTION_VECTOR; vector++)
+      {
+      adeos_virtualize_irq(vector - FIRST_EXTERNAL_VECTOR,
+			   (void (*)(unsigned))__adeos_std_vector_table[vector],
+			   &__adeos_ack_system_irq,
+			   IPIPE_CALLASM_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK);
+      
+      __adeos_set_irq_gate(vector,
+			   __adeos_irq_trampolines[vector - FIRST_EXTERNAL_VECTOR]);
+      }
+
+    __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR0,
+			 __adeos_irq_trampolines[ADEOS_SERVICE_IPI0]);
+
+    __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR1,
+			 __adeos_irq_trampolines[ADEOS_SERVICE_IPI1]);
+
+    __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR2,
+			 __adeos_irq_trampolines[ADEOS_SERVICE_IPI2]);
+
+    __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR3,
+			 __adeos_irq_trampolines[ADEOS_SERVICE_IPI3]);
+
+    __adeos_tick_irq = using_apic_timer ? LOCAL_TIMER_VECTOR - FIRST_EXTERNAL_VECTOR : 0;
+
+#else  /* !CONFIG_X86_LOCAL_APIC */
+
+    __adeos_tick_irq = 0;
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_SMP
+
+    /* All interrupts must be pipelined, but the spurious one since we
+       don't even want to acknowledge it. */
+
+    for (vector = CALL_FUNCTION_VECTOR; vector < SPURIOUS_APIC_VECTOR; vector++)
+      {
+      adeos_virtualize_irq(vector - FIRST_EXTERNAL_VECTOR,
+			   (void (*)(unsigned))__adeos_std_vector_table[vector],
+			   &__adeos_ack_system_irq,
+			   IPIPE_CALLASM_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK);
+      
+      __adeos_set_irq_gate(vector,
+			   __adeos_irq_trampolines[vector - FIRST_EXTERNAL_VECTOR]);
+      }
+
+#endif /* CONFIG_SMP */
+
+    /* Redirect traps and exceptions (except NMI). */
+
+    __adeos_set_trap_gate(0,__adeos_trap_trampolines[0]);
+    __adeos_set_trap_gate(1,__adeos_trap_trampolines[1]);
+    __adeos_set_sys_gate(3,__adeos_trap_trampolines[3]);
+    __adeos_set_sys_gate(4,__adeos_trap_trampolines[4]);
+    __adeos_set_sys_gate(5,__adeos_trap_trampolines[5]);
+    __adeos_set_trap_gate(6,__adeos_trap_trampolines[6]);
+    __adeos_set_trap_gate(7,__adeos_trap_trampolines[7]);
+    __adeos_set_trap_gate(8,__adeos_trap_trampolines[8]);
+    __adeos_set_trap_gate(9,__adeos_trap_trampolines[9]);
+    __adeos_set_trap_gate(10,__adeos_trap_trampolines[10]);
+    __adeos_set_trap_gate(11,__adeos_trap_trampolines[11]);
+    __adeos_set_trap_gate(12,__adeos_trap_trampolines[12]);
+    __adeos_set_trap_gate(13,__adeos_trap_trampolines[13]);
+    __adeos_set_irq_gate(14,__adeos_trap_trampolines[14]);
+    __adeos_set_trap_gate(15,__adeos_trap_trampolines[15]);
+    __adeos_set_trap_gate(16,__adeos_trap_trampolines[16]);
+    __adeos_set_trap_gate(17,__adeos_trap_trampolines[17]);
+    __adeos_set_trap_gate(18,__adeos_trap_trampolines[18]);
+    __adeos_set_trap_gate(19,__adeos_trap_trampolines[19]);
+
+    adp_pipelined = 1;
+
+    adeos_critical_exit(flags);
+}
+
+/* __adeos_disable_pipeline() -- Disengage the pipeline. */
+
+void __adeos_disable_pipeline (void)
+
+{
+    unsigned vector, irq;
+    unsigned long flags;
+
+    flags = adeos_critical_enter(NULL);
+
+    /* Restore original IDT settings. */
+
+    for (irq = 0; irq < NR_IRQS && irq + FIRST_EXTERNAL_VECTOR < FIRST_SYSTEM_VECTOR; irq++)
+	{
+#ifdef CONFIG_X86_IO_APIC
+	if (IO_APIC_IRQ(irq))
+	    {
+	    vector = IO_APIC_VECTOR(irq);
+
+	    if (vector == 0)
+		continue;
+	    }
+	else
+#endif /* CONFIG_X86_IO_APIC */
+	    {
+	    vector = irq + FIRST_EXTERNAL_VECTOR;
+
+	    if (vector == SYSCALL_VECTOR)
+		continue;
+	    }
+
+	__adeos_set_irq_gate(vector,__adeos_std_vector_table[vector]);
+	}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+    for (vector = FIRST_SYSTEM_VECTOR; vector < CALL_FUNCTION_VECTOR; vector++)
+      __adeos_set_irq_gate(vector,__adeos_std_vector_table[vector]);
+
+    __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR0,__adeos_std_vector_table[ADEOS_SERVICE_VECTOR0]);
+    __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR1,__adeos_std_vector_table[ADEOS_SERVICE_VECTOR1]);
+    __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR2,__adeos_std_vector_table[ADEOS_SERVICE_VECTOR2]);
+    __adeos_set_irq_gate(ADEOS_SERVICE_VECTOR3,__adeos_std_vector_table[ADEOS_SERVICE_VECTOR3]);
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_SMP
+
+    for (vector = CALL_FUNCTION_VECTOR; vector < SPURIOUS_APIC_VECTOR; vector++)
+	__adeos_set_irq_gate(vector,__adeos_std_vector_table[vector]);
+
+    __adeos_set_irq_gate(ADEOS_CRITICAL_VECTOR,__adeos_std_vector_table[ADEOS_CRITICAL_VECTOR]);
+
+#endif /* CONFIG_SMP */
+
+    __adeos_set_trap_gate(0,__adeos_std_vector_table[0]);
+    __adeos_set_trap_gate(1,__adeos_std_vector_table[1]);
+    __adeos_set_sys_gate(3,__adeos_std_vector_table[3]);
+    __adeos_set_sys_gate(4,__adeos_std_vector_table[4]);
+    __adeos_set_sys_gate(5,__adeos_std_vector_table[5]);
+    __adeos_set_trap_gate(6,__adeos_std_vector_table[6]);
+    __adeos_set_trap_gate(7,__adeos_std_vector_table[7]);
+    __adeos_set_trap_gate(8,__adeos_std_vector_table[8]);
+    __adeos_set_trap_gate(9,__adeos_std_vector_table[9]);
+    __adeos_set_trap_gate(10,__adeos_std_vector_table[10]);
+    __adeos_set_trap_gate(11,__adeos_std_vector_table[11]);
+    __adeos_set_trap_gate(12,__adeos_std_vector_table[12]);
+    __adeos_set_trap_gate(13,__adeos_std_vector_table[13]);
+    __adeos_set_irq_gate(14,__adeos_std_vector_table[14]);
+    __adeos_set_trap_gate(15,__adeos_std_vector_table[15]);
+    __adeos_set_trap_gate(16,__adeos_std_vector_table[16]);
+    __adeos_set_trap_gate(17,__adeos_std_vector_table[17]);
+    __adeos_set_trap_gate(18,__adeos_std_vector_table[18]);
+    __adeos_set_trap_gate(19,__adeos_std_vector_table[19]);
+
+    adp_pipelined = 0;
+
+    adeos_critical_exit(flags);
+}
+
+/* adeos_virtualize_irq_from() -- Attach a handler (and optionally a
+   hw acknowledge routine) to an interrupt for the given domain. */
+
+int adeos_virtualize_irq_from (adomain_t *adp,
+			       unsigned irq,
+			       void (*handler)(unsigned irq),
+			       int (*acknowledge)(unsigned irq),
+			       unsigned modemask)
+{
+    unsigned long flags;
+    int err;
+
+    if (irq >= IPIPE_NR_IRQS)
+	return -EINVAL;
+
+    if (adp->irqs[irq].control & IPIPE_SYSTEM_MASK)
+	return -EPERM;
+	
+    spin_lock_irqsave_hw(&__adeos_pipelock,flags);
+
+    if (handler != NULL)
+	{
+	/* A bit of hack here: if we are re-virtualizing an IRQ just
+	   to change the acknowledge routine by passing the special
+	   ADEOS_SAME_HANDLER value, then allow to recycle the current
+	   handler for the IRQ. This allows Linux device drivers
+	   managing shared IRQ lines to call adeos_virtualize_irq() in
+	   addition to request_irq() just for the purpose of
+	   interposing their own shared acknowledge routine. */
+
+	if (handler == ADEOS_SAME_HANDLER)
+	    {
+	    handler = adp->irqs[irq].handler;
+
+	    if (handler == NULL)
+		{
+		err = -EINVAL;
+		goto unlock_and_exit;
+		}
+	    }
+	else if ((modemask & IPIPE_EXCLUSIVE_MASK) != 0 &&
+		 adp->irqs[irq].handler != NULL)
+	    {
+	    err = -EBUSY;
+	    goto unlock_and_exit;
+	    }
+	
+	if ((modemask & (IPIPE_SHARED_MASK|IPIPE_PASS_MASK)) == IPIPE_SHARED_MASK)
+	    {
+	    err = -EINVAL;
+	    goto unlock_and_exit;
+	    }
+
+	if ((modemask & IPIPE_STICKY_MASK) != 0)
+	    modemask |= IPIPE_HANDLE_MASK;
+	}
+    else
+	modemask &= ~(IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SHARED_MASK);
+
+    if (acknowledge == NULL)
+	{
+	if ((modemask & IPIPE_SHARED_MASK) == 0)
+	    /* Acknowledge handler unspecified -- this is ok in
+	       non-shared management mode, but we will force the use
+	       of the Linux-defined handler instead. */
+	    acknowledge = adp_root->irqs[irq].acknowledge;
+	else
+	    {
+	    /* A valid acknowledge handler to be called in shared mode
+	       is required when declaring a shared IRQ. */
+	    err = -EINVAL;
+	    goto unlock_and_exit;
+	    }
+	}
+
+    adp->irqs[irq].handler = handler;
+    adp->irqs[irq].acknowledge = acknowledge;
+    adp->irqs[irq].control = modemask;
+
+    if (irq < NR_IRQS &&
+	handler != NULL &&
+	!adeos_virtual_irq_p(irq) &&
+	(modemask & IPIPE_ENABLE_MASK) != 0)
+	{
+	if (adp != adp_current)
+	    {
+	    /* IRQ enable/disable state is domain-sensitive, so we may
+	       not change it for another domain. What is allowed
+	       however is forcing some domain to handle an interrupt
+	       source, by passing the proper 'adp' descriptor which
+	       thus may be different from adp_current. */
+	    err = -EPERM;
+	    goto unlock_and_exit;
+	    }
+
+	irq_desc[irq].handler->enable(irq);
+	}
+
+    err = 0;
+
+unlock_and_exit:
+
+    spin_unlock_irqrestore_hw(&__adeos_pipelock,flags);
+
+    return err;
+}
+
+/* adeos_control_irq() -- Change an interrupt mode. This affects the
+   way a given interrupt is handled by ADEOS for the current
+   domain. setmask is a bitmask telling whether:
+   - the interrupt should be passed to the domain (IPIPE_HANDLE_MASK),
+     and/or
+   - the interrupt should be passed down to the lower priority domain(s)
+     in the pipeline (IPIPE_PASS_MASK).
+   This leads to four possibilities:
+   - PASS only => Ignore the interrupt
+   - HANDLE only => Terminate the interrupt (process but don't pass down)
+   - PASS + HANDLE => Accept the interrupt (process and pass down)
+   - <none> => Discard the interrupt
+   - DYNAMIC is currently an alias of HANDLE since it marks an interrupt
+   which is processed by the current domain but not implicitely passed
+   down to the pipeline, letting the domain's handler choose on a case-
+   by-case basis whether the interrupt propagation should be forced
+   using adeos_propagate_irq().
+   clrmask clears the corresponding bits from the control field before
+   setmask is applied.
+*/
+
+int adeos_control_irq (unsigned irq,
+		       unsigned clrmask,
+		       unsigned setmask)
+{
+    unsigned long flags;
+    irq_desc_t *desc;
+
+    if (irq >= IPIPE_NR_IRQS)
+	return -EINVAL;
+
+    if (adp_current->irqs[irq].control & IPIPE_SYSTEM_MASK)
+	return -EPERM;
+	
+    if (((setmask|clrmask) & IPIPE_SHARED_MASK) != 0)
+	return -EINVAL;
+
+    desc = irq_desc + irq;
+
+    if (adp_current->irqs[irq].handler == NULL)
+	setmask &= ~(IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK);
+
+    if ((setmask & IPIPE_STICKY_MASK) != 0)
+	setmask |= IPIPE_HANDLE_MASK;
+
+    if ((clrmask & (IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK)) != 0)	/* If one goes, both go. */
+	clrmask |= (IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK);
+
+    spin_lock_irqsave_hw(&__adeos_pipelock,flags);
+
+    adp_current->irqs[irq].control &= ~clrmask;
+    adp_current->irqs[irq].control |= setmask;
+
+    if ((setmask & IPIPE_ENABLE_MASK) != 0)
+	desc->handler->enable(irq);
+    else if ((clrmask & IPIPE_ENABLE_MASK) != 0)
+	desc->handler->disable(irq);
+
+    spin_unlock_irqrestore_hw(&__adeos_pipelock,flags);
+
+    return 0;
+}
+
+#ifdef CONFIG_ADEOS_THREADS
+
+asmlinkage static void __adeos_domain_trampoline (void (*entry)(int), int iflag)
+/* asmlinkage is there just in case CONFIG_REGPARM is enabled... */
+{
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_get_cpu(flags);
+    clear_bit(IPIPE_SLEEP_FLAG,&adp_current->cpudata[cpuid].status);
+    adeos_put_cpu(flags);
+    entry(iflag);
+}
+
+void __adeos_init_domain (adomain_t *adp, adattr_t *attr)
+
+{
+    int estacksz = attr->estacksz > 0 ? attr->estacksz : 8192, _cpuid;
+    int nr_cpus = num_online_cpus();
+    adeos_declare_cpuid;
+
+    /* Here we don't care if a CPU migration occurs since we do not
+       use the cpuid for accessing per-CPU data, but we don't want
+       more than one CPU to be passed iflag == 1. */
+
+    adeos_load_cpuid();
+
+    for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+	{
+	int **psp = &adp->esp[_cpuid];
+
+	adp->estackbase[_cpuid] = (int *)kmalloc(estacksz,GFP_KERNEL);
+    
+	if (adp->estackbase[_cpuid] == NULL)
+	    panic("Adeos: No memory for domain stack on CPU #%d",_cpuid);
+
+	adp->esp[_cpuid] = adp->estackbase[_cpuid];
+	**psp = 0;
+	*psp = (int *)(((unsigned long)*psp + estacksz - 0x10) & ~0xf);
+	*--(*psp) = (_cpuid == cpuid); /* iflag */
+	*--(*psp) = (int)attr->entry;
+	*--(*psp) = 0;
+	*--(*psp) = (int)&__adeos_domain_trampoline;
+	}
+}
+
+#else /* !CONFIG_ADEOS_THREADS */
+
+void __adeos_init_domain (adomain_t *adp, adattr_t *attr)
+
+{}
+
+#endif /* CONFIG_ADEOS_THREADS */
+
+void __adeos_cleanup_domain (adomain_t *adp)
+
+{
+    int nr_cpus = num_online_cpus();
+    int _cpuid;
+
+    adeos_unstall_pipeline_from(adp);
+
+    for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+	{
+#ifdef CONFIG_SMP
+	while (adp->cpudata[_cpuid].irq_pending_hi != 0)
+	    cpu_relax();
+
+	while (test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[_cpuid].status))
+	    cpu_relax();
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_ADEOS_THREADS
+	if (adp->estackbase[_cpuid] != NULL)
+	    kfree(adp->estackbase[_cpuid]);
+#endif /* CONFIG_ADEOS_THREADS */
+	}
+}
+
+int adeos_get_sysinfo (adsysinfo_t *info)
+
+{
+    info->ncpus = num_online_cpus();
+    info->cpufreq = adeos_cpu_freq();
+    info->archdep.tmirq = __adeos_tick_irq;
+#ifdef CONFIG_X86_TSC
+    info->archdep.tmfreq = adeos_cpu_freq();
+#else /* !CONFIG_X86_TSC */
+    info->archdep.tmfreq = CLOCK_TICK_RATE;
+#endif /* CONFIG_X86_TSC */
+
+    return 0;
+}
+
+int adeos_tune_timer (unsigned long ns, int flags)
+
+{
+    unsigned hz, latch;
+    unsigned long x;
+
+    if (flags & ADEOS_RESET_TIMER)
+	latch = LATCH;
+    else
+	{
+	hz = 1000000000 / ns;
+
+	if (hz < HZ)
+	    return -EINVAL;
+
+	latch = (CLOCK_TICK_RATE + hz/2) / hz;
+	}
+
+    x = adeos_critical_enter(NULL); /* Sync with all CPUs */
+
+    /* Shamelessly lifted from init_IRQ() in i8259.c */
+    outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
+    outb_p(latch & 0xff,0x40);	/* LSB */
+    outb(latch >> 8,0x40);	/* MSB */
+
+    adeos_critical_exit(x);
+
+    return 0;
+}
+
+/* adeos_send_ipi() -- Send a specified service IPI to a set of
+   processors. */
+
+int fastcall adeos_send_ipi (unsigned ipi, cpumask_t cpumask)
+
+{
+#ifdef CONFIG_SMP
+    unsigned long flags;
+    adeos_declare_cpuid;
+    int self;
+
+    switch (ipi)
+	{
+	case ADEOS_SERVICE_IPI0:
+	case ADEOS_SERVICE_IPI1:
+	case ADEOS_SERVICE_IPI2:
+	case ADEOS_SERVICE_IPI3:
+
+	    break;
+
+	default:
+
+	    return -EINVAL;
+	}
+
+    adeos_lock_cpu(flags);
+
+    self = cpu_isset(cpuid,cpumask);
+    cpu_clear(cpuid,cpumask);
+
+    if (!cpus_empty(cpumask))
+	send_IPI_mask(cpumask,ipi + FIRST_EXTERNAL_VECTOR);
+
+    if (self)
+	adeos_trigger_irq(ipi);
+
+    adeos_unlock_cpu(flags);
+
+#endif /* CONFIG_SMP */
+
+    return 0;
+}
diff -uNrp linux-2.6.9/arch/i386/Kconfig linux-2.6.9-ltt-r12/arch/i386/Kconfig
--- linux-2.6.9/arch/i386/Kconfig	2004-10-18 23:53:22.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/Kconfig	2005-08-15 10:31:45.000000000 +0200
@@ -870,6 +870,7 @@ config REGPARM
 
 endmenu
 
+source "adeos/Kconfig"
 
 menu "Power management options (ACPI, APM)"
 	depends on !X86_VOYAGER
diff -uNrp linux-2.6.9/arch/i386/kernel/Makefile linux-2.6.9-ltt-r12/arch/i386/kernel/Makefile
--- linux-2.6.9/arch/i386/kernel/Makefile	2004-10-18 23:53:25.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/Makefile	2005-08-15 10:31:45.000000000 +0200
@@ -11,6 +11,7 @@ obj-y	:= process.o semaphore.o signal.o 
 
 obj-y				+= cpu/
 obj-y				+= timers/
+obj-$(CONFIG_ADEOS_CORE)	+= adeos.o
 obj-$(CONFIG_ACPI_BOOT)		+= acpi/
 obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
diff -uNrp linux-2.6.9/arch/i386/kernel/adeos.c linux-2.6.9-ltt-r12/arch/i386/kernel/adeos.c
--- linux-2.6.9/arch/i386/kernel/adeos.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/adeos.c	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,780 @@
+/*
+ *   linux/arch/i386/kernel/adeos.c
+ *
+ *   Copyright (C) 2002 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *   Architecture-dependent ADEOS core support for x86.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/hw_irq.h>
+#include <asm/irq.h>
+#include <asm/desc.h>
+#include <asm/io.h>
+#ifdef CONFIG_X86_LOCAL_APIC
+#include <asm/fixmap.h>
+#include <asm/bitops.h>
+#include <asm/mpspec.h>
+#ifdef CONFIG_X86_IO_APIC
+#include <asm/io_apic.h>
+#endif /* CONFIG_X86_IO_APIC */
+#include <asm/apic.h>
+#include <mach_ipi.h>
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+struct pt_regs __adeos_tick_regs[ADEOS_NR_CPUS];
+
+int __adeos_tick_irq;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+/* Ugly hack allowing 1) to run portions of early kernel init code
+   which make use of smp_processor_id(), 2) to run SMP kernels on UP
+   boxen without APIC. See asm-i386/adeos.h */
+int __adeos_apic_mapped;
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_SMP
+
+volatile u8 __adeos_apicid_2_cpuid[MAX_APICID];
+
+static cpumask_t __adeos_cpu_sync_map;
+
+static cpumask_t __adeos_cpu_lock_map;
+
+static raw_spinlock_t __adeos_cpu_barrier = RAW_SPIN_LOCK_UNLOCKED;
+
+static atomic_t __adeos_critical_count = ATOMIC_INIT(0);
+
+static void (*__adeos_cpu_sync)(void);
+
+#endif /* CONFIG_SMP */
+
+#define __adeos_call_asm_irq_handler(adp,irq) \
+   __asm__ __volatile__ ("pushfl\n\t" \
+                         "push %%cs\n\t" \
+                         "call *%1\n" \
+			 : /* no output */ \
+			 : "a" (irq), "m" ((adp)->irqs[irq].handler))
+
+/* Since 2.6, ret_from_intr might identify a need for rescheduling
+   (raised by the C handler) even from kernel space if the preemption
+   is enabled, so we should branch to this routine on our return
+   path. Native (i.e. ASM) handlers do the same. */
+
+#define __adeos_call_c_root_irq_handler(adp,irq) \
+   __asm__ __volatile__ ("pushfl\n\t" \
+                         "pushl %%cs\n\t" \
+                         "pushl $1f\n\t" \
+	                 "pushl $-1\n\t" /* Negative (fake) orig_eax. */ \
+	                 "pushl %%es\n\t" \
+	                 "pushl %%ds\n\t" \
+	                 "pushl %%eax\n\t" \
+	                 "pushl %%ebp\n\t" \
+	                 "pushl %%edi\n\t" \
+	                 "pushl %%esi\n\t" \
+	                 "pushl %%edx\n\t" \
+	                 "pushl %%ecx\n\t" \
+	                 "pushl %%ebx\n\t" \
+                         "pushl %%eax\n\t" \
+                         "call *%1\n\t" \
+			 "addl $4,%%esp\n\t" \
+	                 "jmp ret_from_intr\n\t" \
+	                 "1:\n" \
+			 : /* no output */ \
+			 : "a" (irq), "m" ((adp)->irqs[irq].handler))
+
+/* Do _not_ forcibly re-enable hw IRQs in the following trampoline
+   used for non-root domains; unlike Linux handlers, non-root domain
+   handlers are fully in control of the hw masking state. */
+
+#define __adeos_call_c_irq_handler(adp,irq) \
+   __asm__ __volatile__ ("pushl %%ebp\n\t" \
+	                 "pushl %%edi\n\t" \
+                      	 "pushl %%esi\n\t" \
+	                 "pushl %%edx\n\t" \
+                         "pushl %%ecx\n\t" \
+	                 "pushl %%ebx\n\t" \
+                         "pushl %%eax\n\t" \
+                         "call *%1\n\t" \
+                         "addl $4,%%esp\n\t" \
+                         "popl %%ebx\n\t" \
+                         "popl %%ecx\n\t" \
+	                 "popl %%edx\n\t" \
+	                 "popl %%esi\n\t" \
+	                 "popl %%edi\n\t" \
+	                 "popl %%ebp\n" \
+			 : /* no output */ \
+			 : "a" (irq), "m" ((adp)->irqs[irq].handler))
+
+static __inline__ unsigned long flnz (unsigned long word) {
+    __asm__("bsrl %1, %0"
+	    : "=r" (word)
+	    : "r"  (word));
+    return word;
+}
+
+int __adeos_ack_system_irq (unsigned irq) {
+#ifdef CONFIG_X86_LOCAL_APIC
+    __ack_APIC_irq();		/* Takes no spin lock, right? */
+#endif /* CONFIG_X86_LOCAL_APIC */
+    return 1;
+}
+
+#ifdef CONFIG_SMP
+
+/* Always called with hw interrupts off. */
+
+static void __adeos_do_critical_sync (unsigned irq)
+
+{
+    adeos_declare_cpuid;
+
+    adeos_load_cpuid();
+
+    cpu_set(cpuid,__adeos_cpu_sync_map);
+
+    /* Now we are in sync with the lock requestor running on another
+       CPU. Enter a spinning wait until he releases the global
+       lock. */
+    adeos_spin_lock(&__adeos_cpu_barrier);
+
+    /* Got it. Now get out. */
+
+    if (__adeos_cpu_sync)
+	/* Call the sync routine if any. */
+	__adeos_cpu_sync();
+
+    adeos_spin_unlock(&__adeos_cpu_barrier);
+
+    cpu_clear(cpuid,__adeos_cpu_sync_map);
+}
+
+int __adeos_hw_cpuid (void)
+
+{
+    unsigned long flags;
+    int cpuid;
+
+    if (!__adeos_apic_mapped)
+	return 0;
+    
+    adeos_hw_local_irq_save(flags);
+    cpuid = __adeos_apicid_2_cpuid[adeos_smp_apic_id()];
+    adeos_hw_local_irq_restore(flags);
+
+    return cpuid;
+}
+
+#endif /* CONFIG_SMP */
+
+/* adeos_critical_enter() -- Grab the superlock excluding all CPUs
+   but the current one from a critical section. This lock is used when
+   we must enforce a global critical section for a single CPU in a
+   possibly SMP system whichever context the CPUs are running
+   (i.e. interrupt handler or regular thread). */
+
+unsigned long adeos_critical_enter (void (*syncfn)(void))
+
+{
+    unsigned long flags;
+
+    adeos_hw_local_irq_save(flags);
+
+#ifdef CONFIG_SMP
+    if (num_online_cpus() > 1) /* We might be running a SMP-kernel on a UP box... */
+	{
+	adeos_declare_cpuid;
+	cpumask_t lock_map;
+
+	adeos_load_cpuid();
+
+	if (!cpu_test_and_set(cpuid,__adeos_cpu_lock_map))
+	    {
+	    while (cpu_test_and_set(BITS_PER_LONG - 1,__adeos_cpu_lock_map))
+		{
+		/* Refer to the explanations found in
+		   linux/arch/asm-i386/irq.c about
+		   SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND for more about
+		   this strange loop. */
+		int n = 0;
+		do { cpu_relax(); } while (++n < cpuid);
+		}
+
+	    adeos_spin_lock(&__adeos_cpu_barrier);
+
+	    __adeos_cpu_sync = syncfn;
+
+	    /* Send the sync IPI to all processors but the current one. */
+	    send_IPI_allbutself(ADEOS_CRITICAL_VECTOR);
+
+#ifdef cpus_andnot
+	    cpus_andnot(lock_map,cpu_online_map,__adeos_cpu_lock_map);
+#else /* !cpus_andnot */
+	    {
+	    cpumask_t not_lock_map = __adeos_cpu_lock_map;
+	    cpus_complement(not_lock_map);
+	    cpus_and(lock_map,cpu_online_map,not_lock_map);
+	    }
+#endif /* cpus_andnot */
+
+	    while (!cpus_equal(__adeos_cpu_sync_map,lock_map))
+		cpu_relax();
+	    }
+
+	atomic_inc(&__adeos_critical_count);
+	}
+#endif /* CONFIG_SMP */
+
+    return flags;
+}
+
+/* adeos_critical_exit() -- Release the superlock. */
+
+void adeos_critical_exit (unsigned long flags)
+
+{
+#ifdef CONFIG_SMP
+    if (num_online_cpus() > 1) /* We might be running a SMP-kernel on a UP box... */
+	{
+	adeos_declare_cpuid;
+
+	adeos_load_cpuid();
+
+	if (atomic_dec_and_test(&__adeos_critical_count))
+	    {
+	    adeos_spin_unlock(&__adeos_cpu_barrier);
+
+	    while (!cpus_empty(__adeos_cpu_sync_map))
+		cpu_relax();
+
+	    cpu_clear(cpuid,__adeos_cpu_lock_map);
+	    cpu_clear(BITS_PER_LONG - 1,__adeos_cpu_lock_map);
+	    }
+	}
+#endif /* CONFIG_SMP */
+
+    adeos_hw_local_irq_restore(flags);
+}
+
+void __adeos_init_stage (adomain_t *adp)
+
+{
+    int cpuid, n;
+
+    for (cpuid = 0; cpuid < ADEOS_NR_CPUS; cpuid++)
+	{
+	adp->cpudata[cpuid].irq_pending_hi = 0;
+
+	for (n = 0; n < IPIPE_IRQ_IWORDS; n++)
+	    adp->cpudata[cpuid].irq_pending_lo[n] = 0;
+
+	for (n = 0; n < IPIPE_NR_IRQS; n++)
+	    adp->cpudata[cpuid].irq_hits[n] = 0;
+	}
+
+    for (n = 0; n < IPIPE_NR_IRQS; n++)
+	{
+	adp->irqs[n].acknowledge = NULL;
+	adp->irqs[n].handler = NULL;
+	adp->irqs[n].control = IPIPE_PASS_MASK;	/* Pass but don't handle */
+	}
+
+#ifdef CONFIG_SMP
+    adp->irqs[ADEOS_CRITICAL_IPI].acknowledge = &__adeos_ack_system_irq;
+    adp->irqs[ADEOS_CRITICAL_IPI].handler = &__adeos_do_critical_sync;
+    /* Immediately handle in the current domain but *never* pass */
+    adp->irqs[ADEOS_CRITICAL_IPI].control = IPIPE_HANDLE_MASK|IPIPE_STICKY_MASK|IPIPE_SYSTEM_MASK;
+#endif /* CONFIG_SMP */
+}
+
+/* __adeos_sync_stage() -- Flush the pending IRQs for the current
+   domain (and processor).  This routine flushes the interrupt log
+   (see "Optimistic interrupt protection" from D. Stodolsky et al. for
+   more on the deferred interrupt scheme). Every interrupt that
+   occurred while the pipeline was stalled gets played.  WARNING:
+   callers on SMP boxen should always check for CPU migration on
+   return of this routine. One can control the kind of interrupts
+   which are going to be sync'ed using the syncmask
+   parameter. IPIPE_IRQMASK_ANY plays them all, IPIPE_IRQMASK_VIRT
+   plays virtual interrupts only. This routine must be called with hw
+   interrupts off. */
+
+void fastcall __adeos_sync_stage (unsigned long syncmask)
+
+{
+    unsigned long mask, submask;
+    struct adcpudata *cpudata;
+    int level, rank, sync;
+    adeos_declare_cpuid;
+    adomain_t *adp;
+    unsigned irq;
+
+    adeos_load_cpuid();
+    adp = adp_cpu_current[cpuid];
+    cpudata = &adp->cpudata[cpuid];
+
+    sync = __test_and_set_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+
+    /* The policy here is to keep the dispatching code interrupt-free
+       by stalling the current stage. If the upper domain handler
+       (which we call) wants to re-enable interrupts while in a safe
+       portion of the code (e.g. SA_INTERRUPT flag unset for Linux's
+       sigaction()), it will have to unstall (then stall again before
+       returning to us!) the stage when it sees fit. */
+
+    while ((mask = (cpudata->irq_pending_hi & syncmask)) != 0)
+	{
+	/* Give a slight priority advantage to high-numbered IRQs
+	   like the virtual ones. */
+	level = flnz(mask);
+	__clear_bit(level,&cpudata->irq_pending_hi);
+
+	while ((submask = cpudata->irq_pending_lo[level]) != 0)
+	    {
+	    rank = flnz(submask);
+	    irq = (level << IPIPE_IRQ_ISHIFT) + rank;
+
+	    if (test_bit(IPIPE_LOCK_FLAG,&adp->irqs[irq].control))
+		{
+		__clear_bit(rank,&cpudata->irq_pending_lo[level]);
+		continue;
+		}
+
+	    if (--cpudata->irq_hits[irq] == 0)
+		__clear_bit(rank,&cpudata->irq_pending_lo[level]);
+
+	    __set_bit(IPIPE_STALL_FLAG,&cpudata->status);
+
+#ifdef CONFIG_ADEOS_PROFILING
+	    __adeos_profile_data[cpuid].irqs[irq].n_synced++;
+	    adeos_hw_tsc(__adeos_profile_data[cpuid].irqs[irq].t_synced);
+#endif /* CONFIG_ADEOS_PROFILING */
+
+	    if (adp == adp_root)
+		{
+		/* Make sure to re-enable hw interrupts to reduce
+		   preemption latency by higher priority domains when
+		   calling the Linux handlers in the next two
+		   trampolines. Additionally, this ensures that the
+		   forged interrupt frame will allow the final check
+		   for a rescheduling opportunity in ret_from_intr. */
+
+		adeos_hw_sti();
+
+		if (test_bit(IPIPE_CALLASM_FLAG,&adp->irqs[irq].control))
+		    __adeos_call_asm_irq_handler(adp,irq);
+		else
+		    {
+		    irq_enter();
+		    __adeos_call_c_root_irq_handler(adp,irq);
+		    irq_exit();
+		    }
+		}
+	    else
+		__adeos_call_c_irq_handler(adp,irq);
+
+	    adeos_hw_cli();
+
+#ifdef CONFIG_SMP
+	    {
+	    int _cpuid = adeos_processor_id();
+
+	    if (_cpuid != cpuid) /* Handle CPU migration. */
+		{
+		/* We expect any domain to clear the SYNC bit each
+		   time it switches in a new task, so that preemptions
+		   and/or CPU migrations (in the SMP case) over the
+		   ISR do not lock out the log syncer for some
+		   indefinite amount of time. In the Linux case,
+		   schedule() handles this (see kernel/sched.c). For
+		   this reason, we don't bother clearing it here for
+		   the source CPU in the migration handling case,
+		   since it must have scheduled another task in by
+		   now. */
+		cpuid = _cpuid;
+		cpudata = &adp->cpudata[cpuid];
+		__set_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+		}
+	    }
+#endif /* CONFIG_SMP */
+
+	    __clear_bit(IPIPE_STALL_FLAG,&cpudata->status);
+	    }
+	}
+
+    if (!sync)
+	__clear_bit(IPIPE_SYNC_FLAG,&cpudata->status);
+}
+
+/* __adeos_walk_pipeline(): Must be called with local interrupts
+   disabled. */
+
+static inline void __adeos_walk_pipeline (struct list_head *pos, int cpuid)
+
+{
+    adomain_t *this_domain = adp_cpu_current[cpuid];
+
+    while (pos != &__adeos_pipeline)
+	{
+    	adomain_t *next_domain = list_entry(pos,adomain_t,p_link);
+
+	if (test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status))
+	    break; /* Stalled stage -- do not go further. */
+
+	if (next_domain->cpudata[cpuid].irq_pending_hi != 0)
+	    {
+	    /* Since the critical IPI might be dispatched by the
+	       following actions, the current domain might not be
+	       linked to the pipeline anymore after its handler
+	       returns on SMP boxes, even if the domain remains valid
+	       (see adeos_unregister_domain()), so don't make any
+	       dangerous assumptions here. */
+
+	    if (next_domain == this_domain)
+		__adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	    else
+		{
+		__adeos_switch_to(this_domain,next_domain,cpuid);
+
+		adeos_load_cpuid(); /* Processor might have changed. */
+
+		if (this_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+		    !test_bit(IPIPE_SYNC_FLAG,&this_domain->cpudata[cpuid].status) &&
+		    !test_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status))
+		    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+		}
+
+	    break;
+	    }
+	else if (next_domain == this_domain)
+	    break;
+
+	pos = next_domain->p_link.next;
+	}
+}
+
+/* __adeos_handle_irq() -- ADEOS's generic IRQ handler. An optimistic
+   interrupt protection log is maintained here for each domain.
+   Interrupts are off on entry. */
+
+int __adeos_handle_irq (struct pt_regs regs)
+
+{
+    int hw_gen = regs.orig_eax < 0, m_ack = !hw_gen, s_ack;
+    unsigned irq = regs.orig_eax & 0xff;
+    struct list_head *head, *pos;
+    adomain_t *this_domain;
+    adeos_declare_cpuid;
+
+    adeos_load_cpuid();
+
+    this_domain = adp_cpu_current[cpuid];
+
+#ifdef CONFIG_ADEOS_PROFILING
+    __adeos_profile_data[cpuid].irqs[irq].n_handled++;
+    adeos_hw_tsc(__adeos_profile_data[cpuid].irqs[irq].t_handled);
+#endif /* CONFIG_ADEOS_PROFILING */
+
+    s_ack = m_ack;
+
+    if (test_bit(IPIPE_STICKY_FLAG,&this_domain->irqs[irq].control))
+	head = &this_domain->p_link;
+    else
+	head = __adeos_pipeline.next;
+
+    /* Ack the interrupt. */
+
+    pos = head;
+
+    while (pos != &__adeos_pipeline)
+	{
+    	adomain_t *next_domain = list_entry(pos,adomain_t,p_link);
+
+	/* For each domain handling the incoming IRQ, mark it as
+           pending in its log. */
+
+	if (test_bit(IPIPE_HANDLE_FLAG,&next_domain->irqs[irq].control))
+	    {
+	    /* Domains that handle this IRQ are polled for
+	       acknowledging it by decreasing priority order. The
+	       interrupt must be made pending _first_ in the domain's
+	       status flags before the PIC is unlocked. */
+
+	    next_domain->cpudata[cpuid].irq_hits[irq]++;
+	    __adeos_set_irq_bit(next_domain,cpuid,irq);
+
+	    /* Always get the first master acknowledge available. Once
+	       we've got it, allow slave acknowledge handlers to run
+	       (until one of them stops us). */
+
+	    if (!m_ack)
+		m_ack = next_domain->irqs[irq].acknowledge(irq);
+	    else if (test_bit(IPIPE_SHARED_FLAG,&next_domain->irqs[irq].control) && !s_ack)
+		s_ack = next_domain->irqs[irq].acknowledge(irq);
+	    }
+
+	/* If the domain does not want the IRQ to be passed down the
+	   interrupt pipe, exit the loop now. */
+
+	if (!test_bit(IPIPE_PASS_FLAG,&next_domain->irqs[irq].control))
+	    break;
+
+	pos = next_domain->p_link.next;
+	}
+
+    if (irq == __adeos_tick_irq)
+	{
+	__adeos_tick_regs[cpuid].eflags = regs.eflags;
+	__adeos_tick_regs[cpuid].eip = regs.eip;
+	__adeos_tick_regs[cpuid].xcs = regs.xcs;
+#if defined(CONFIG_SMP) && defined(CONFIG_FRAME_POINTER)
+	/* Linux profiling code needs this. */
+	__adeos_tick_regs[cpuid].ebp = regs.ebp;
+#endif /* CONFIG_SMP && CONFIG_FRAME_POINTER */
+	}
+
+    /* Now walk the pipeline, yielding control to the highest priority
+       domain that has pending interrupt(s) or immediately to the
+       current domain if the interrupt has been marked as
+       'sticky'. This search does not go beyond the current domain in
+       the pipeline. To understand this code properly, one must keep
+       in mind that domains having a higher priority than the current
+       one are sleeping on the adeos_suspend_domain() service. In
+       addition, domains having a lower priority have been preempted
+       by an interrupt dispatched to a higher priority domain. Once
+       the first and highest priority stage has been selected here,
+       the subsequent stages will be activated in turn when each
+       visited domain calls adeos_suspend_domain() to wake up its
+       neighbour down the pipeline. */
+
+    __adeos_walk_pipeline(head,cpuid);
+
+    adeos_load_cpuid();
+
+    if (adp_cpu_current[cpuid] != adp_root ||
+	test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status))
+	return 0;
+
+#ifdef CONFIG_SMP
+    /* Prevent a spurious rescheduling from being triggered on
+       preemptible kernels along the way out through ret_from_intr. */
+    if (hw_gen)
+	__set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+#endif /* CONFIG_SMP */
+
+    return 1;
+}
+
+/* adeos_trigger_irq() -- Push the interrupt to the pipeline entry
+   just like if it has been actually received from a hw source. This
+   both works for real and virtual interrupts. This also means that
+   the current domain might be immediately preempted by a higher
+   priority domain who happens to handle this interrupt. */
+
+int fastcall adeos_trigger_irq (unsigned irq)
+
+{
+    struct pt_regs regs;
+    unsigned long flags;
+
+    if (irq >= IPIPE_NR_IRQS ||
+	(adeos_virtual_irq_p(irq) &&
+	 !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)))
+	return -EINVAL;
+
+    adeos_hw_local_irq_save(flags);
+
+    regs.orig_eax = irq; /* Won't be acked */
+    regs.xcs = __KERNEL_CS;
+    regs.eflags = flags;
+
+    __adeos_handle_irq(regs);
+
+    adeos_hw_local_irq_restore(flags);
+
+    return 1;
+}
+
+static inline void __fixup_if (struct pt_regs *regs)
+
+{
+    adeos_declare_cpuid;
+    unsigned long flags;
+ 
+    adeos_get_cpu(flags);
+
+    if (adp_cpu_current[cpuid] == adp_root)
+	{
+	/* Have the saved hw state look like the domain stall bit, so
+	   that __adeos_unstall_iret_root() restores the proper
+	   pipeline state for the root stage upon exit. */
+
+	if (test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status))
+	    regs->eflags &= ~0x200;
+	else
+	    regs->eflags |= 0x200;
+	}
+
+    adeos_put_cpu(flags);
+}
+
+asmlinkage void __adeos_if_fixup_root (struct pt_regs regs)
+
+{
+    if (adp_pipelined)
+	__fixup_if(&regs);
+}
+
+/*  Check the interrupt flag to make sure the existing preemption
+    opportunity upon in-kernel resumption could be exploited. If
+    pipelining is active, the stall bit of the root domain is checked,
+    otherwise, the EFLAGS register from the stacked interrupt frame is
+    tested. In case a rescheduling could take place in pipelined mode,
+    the root stage is stalled before the hw interrupts are
+    re-enabled. This routine must be called with hw interrupts off. */
+
+asmlinkage int __adeos_kpreempt_root (struct pt_regs regs)
+
+{
+    adeos_declare_cpuid;
+    unsigned long flags;
+
+    if (!adp_pipelined)
+	return !!(regs.eflags & 0x200);
+
+    adeos_get_cpu(flags);
+
+    if (test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status))
+	{
+	adeos_put_cpu(flags);
+	return 0; /* Root stage is stalled: rescheduling denied. */
+	}
+
+    __adeos_stall_root();
+    adeos_hw_sti();
+
+    return 1;	/* Ok, may reschedule now. */
+}
+
+asmlinkage int __adeos_enter_syscall (struct pt_regs regs)
+
+{
+    adeos_declare_cpuid;
+    unsigned long flags;
+
+    /* This routine either returns:
+       0 -- if the syscall is to be passed to Linux;
+       1 -- if the syscall should not be passed to Linux, and no
+       tail work should be performed;
+       -1 -- if the syscall should not be passed to Linux but the
+       tail work has to be performed. */
+
+    if (__adeos_event_monitors[ADEOS_SYSCALL_PROLOGUE] > 0 &&
+	__adeos_handle_event(ADEOS_SYSCALL_PROLOGUE,&regs) > 0)
+	{
+	/* We might enter here over a non-root domain and exit over
+	   the root one as a result of the issued syscall (i.e. by
+	   recycling the register set of the current context across
+	   the migration), so we need to fixup the interrupt flag upon
+	   return too, so that __adeos_unstall_iret_root() resets the
+	   correct stall bit on exit. */
+	__fixup_if(&regs);
+
+	if (adp_current == adp_root && !in_atomic())
+	    {
+	    /* Sync pending VIRQs before _TIF_NEED_RESCHED is
+	     * tested. */
+
+	    adeos_lock_cpu(flags);
+
+	    if ((adp_root->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+		__adeos_sync_stage(IPIPE_IRQMASK_VIRT);
+
+	    adeos_unlock_cpu(flags);
+
+	    return -1;
+	    }
+
+	return 1;
+	}
+
+    return 0;
+}
+
+asmlinkage int __adeos_exit_syscall (void)
+
+{
+    if (__adeos_event_monitors[ADEOS_SYSCALL_EPILOGUE] > 0)
+	return __adeos_handle_event(ADEOS_SYSCALL_EPILOGUE,NULL);
+
+    return 0;
+}
+
+asmlinkage void __adeos_unstall_iret_root (struct pt_regs regs)
+
+{
+    adeos_declare_cpuid;
+
+    if (!adp_pipelined)
+	return;
+
+    /* Emulate a software IRET. */
+
+    adeos_hw_cli();
+
+    adeos_load_cpuid();
+
+    /* Restore the software state as it used to be on kernel entry. */
+
+    if (!(regs.eflags & 0x200))
+	{
+	__set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+	regs.eflags |= 0x200;
+	}
+    else
+	{
+	__clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	/* Only sync virtual IRQs here, so that we don't recurse
+	   indefinitely in case of an external interrupt flood. */
+    
+	if ((adp_root->cpudata[cpuid].irq_pending_hi & IPIPE_IRQMASK_VIRT) != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_VIRT);
+	}
+}
+
+EXPORT_SYMBOL(__adeos_init_stage);
+EXPORT_SYMBOL(__adeos_sync_stage);
+EXPORT_SYMBOL(__adeos_ack_system_irq);
+EXPORT_SYMBOL(__adeos_handle_irq);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__adeos_hw_cpuid);
+#endif /* CONFIG_SMP */
+EXPORT_SYMBOL(__adeos_tick_irq);
+EXPORT_SYMBOL(adeos_critical_enter);
+EXPORT_SYMBOL(adeos_critical_exit);
+EXPORT_SYMBOL(adeos_trigger_irq);
diff -uNrp linux-2.6.9/arch/i386/kernel/apic.c linux-2.6.9-ltt-r12/arch/i386/kernel/apic.c
--- linux-2.6.9/arch/i386/kernel/apic.c	2004-10-18 23:55:35.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/apic.c	2005-08-15 10:31:45.000000000 +0200
@@ -759,6 +759,9 @@ void __init init_apic_mappings(void)
 		apic_phys = mp_lapic_addr;
 
 	set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_apic_mapped = 1;
+#endif /* CONFIG_ADEOS_CORE */
 	apic_printk(APIC_DEBUG, "mapped APIC to %08lx (%08lx)\n", APIC_BASE,
 			apic_phys);
 
@@ -1126,6 +1129,9 @@ inline void smp_local_timer_interrupt(st
 void smp_apic_timer_interrupt(struct pt_regs regs)
 {
 	int cpu = smp_processor_id();
+#ifdef CONFIG_ADEOS_CORE
+        struct pt_regs *_regs = adp_pipelined ? __adeos_tick_regs + cpu : &regs;
+#endif /* CONFIG_ADEOS_CORE */
 
 	/*
 	 * the NMI deadlock-detector uses this.
@@ -1143,7 +1149,11 @@ void smp_apic_timer_interrupt(struct pt_
 	 * interrupt lock, which is the WrongThing (tm) to do.
 	 */
 	irq_enter();
+#ifdef CONFIG_ADEOS_CORE
+	smp_local_timer_interrupt(_regs);
+#else /* !CONFIG_ADEOS_CORE */
 	smp_local_timer_interrupt(&regs);
+#endif /* CONFIG_ADEOS_CORE */
 	irq_exit();
 }
 
@@ -1162,7 +1172,7 @@ asmlinkage void smp_spurious_interrupt(v
 	 */
 	v = apic_read(APIC_ISR + ((SPURIOUS_APIC_VECTOR & ~0x1f) >> 1));
 	if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
-		ack_APIC_irq();
+		__ack_APIC_irq();
 
 	/* see sw-dev-man vol 3, chapter 7.4.13.5 */
 	printk(KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n",
diff -uNrp linux-2.6.9/arch/i386/kernel/cpu/mcheck/p4.c linux-2.6.9-ltt-r12/arch/i386/kernel/cpu/mcheck/p4.c
--- linux-2.6.9/arch/i386/kernel/cpu/mcheck/p4.c	2004-10-18 23:54:37.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/cpu/mcheck/p4.c	2005-08-15 10:31:45.000000000 +0200
@@ -49,6 +49,9 @@ static void intel_thermal_interrupt(stru
 	unsigned int cpu = smp_processor_id();
 	static unsigned long next[NR_CPUS];
 
+#ifdef CONFIG_ADEOS_CORE
+	if (!adp_pipelined)
+#endif /* CONFIG_ADEOS_CORE */
 	ack_APIC_irq();
 
 	if (time_after(next[cpu], jiffies))
diff -uNrp linux-2.6.9/arch/i386/kernel/cpu/mtrr/cyrix.c linux-2.6.9-ltt-r12/arch/i386/kernel/cpu/mtrr/cyrix.c
--- linux-2.6.9/arch/i386/kernel/cpu/mtrr/cyrix.c	2004-10-18 23:54:31.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/cpu/mtrr/cyrix.c	2005-08-15 10:31:45.000000000 +0200
@@ -118,6 +118,11 @@ static void prepare_set(void)
 {
 	u32 cr0;
 
+#ifdef CONFIG_ADEOS_CORE
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*  Save value of CR4 and clear Page Global Enable (bit 7)  */
 	if ( cpu_has_pge ) {
 		cr4 = read_cr4();
@@ -137,10 +142,18 @@ static void prepare_set(void)
 	/* Cyrix ARRs - everything else were excluded at the top */
 	setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10);
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 static void post_set(void)
 {
+#ifdef CONFIG_ADEOS_CORE
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*  Flush caches and TLBs  */
 	wbinvd();
 
@@ -153,6 +166,10 @@ static void post_set(void)
 	/*  Restore value of CR4  */
 	if ( cpu_has_pge )
 		write_cr4(cr4);
+
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 static void cyrix_set_arr(unsigned int reg, unsigned long base,
diff -uNrp linux-2.6.9/arch/i386/kernel/cpu/mtrr/generic.c linux-2.6.9-ltt-r12/arch/i386/kernel/cpu/mtrr/generic.c
--- linux-2.6.9/arch/i386/kernel/cpu/mtrr/generic.c	2004-10-18 23:54:32.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/cpu/mtrr/generic.c	2005-08-15 10:31:45.000000000 +0200
@@ -242,6 +242,11 @@ static void prepare_set(void)
 	   more invasive changes to the way the kernel boots  */
 	spin_lock(&set_atomicity_lock);
 
+#ifdef CONFIG_ADEOS_CORE
+	{
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
 	/*  Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */
 	cr0 = read_cr0() | 0x40000000;	/* set CD flag */
 	wbinvd();
@@ -262,10 +267,18 @@ static void prepare_set(void)
 
 	/*  Disable MTRRs, and set the default type to uncached  */
 	wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi);
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+	}
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 static void post_set(void)
 {
+#ifdef CONFIG_ADEOS_CORE
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
 	/*  Flush caches and TLBs  */
 	wbinvd();
 	__flush_tlb();
@@ -280,6 +293,9 @@ static void post_set(void)
 	if ( cpu_has_pge )
 		write_cr4(cr4);
 	spin_unlock(&set_atomicity_lock);
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 static void generic_set_all(void)
diff -uNrp linux-2.6.9/arch/i386/kernel/cpu/mtrr/state.c linux-2.6.9-ltt-r12/arch/i386/kernel/cpu/mtrr/state.c
--- linux-2.6.9/arch/i386/kernel/cpu/mtrr/state.c	2004-10-18 23:53:06.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/cpu/mtrr/state.c	2005-08-15 10:31:45.000000000 +0200
@@ -12,7 +12,11 @@ void set_mtrr_prepare_save(struct set_mt
 	unsigned int cr0;
 
 	/*  Disable interrupts locally  */
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_save(ctxt->flags);
+#else /* !CONFIG_ADEOS_CORE */
 	local_irq_save(ctxt->flags);
+#endif /* CONFIG_ADEOS_CORE */
 
 	if (use_intel() || is_cpu(CYRIX)) {
 
@@ -73,6 +77,10 @@ void set_mtrr_done(struct set_mtrr_conte
 			write_cr4(ctxt->cr4val);
 	}
 	/*  Re-enable interrupts locally (if enabled previously)  */
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(ctxt->flags);
+#else /* !CONFIG_ADEOS_CORE */
 	local_irq_restore(ctxt->flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
diff -uNrp linux-2.6.9/arch/i386/kernel/entry.S linux-2.6.9-ltt-r12/arch/i386/kernel/entry.S
--- linux-2.6.9/arch/i386/kernel/entry.S	2004-10-18 23:53:44.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/entry.S	2005-08-15 10:52:33.000000000 +0200
@@ -81,6 +81,11 @@ VM_MASK		= 0x00020000
 #define resume_kernel		restore_all
 #endif
 
+#ifdef CONFIG_ADEOS_CORE
+#define	cli          call __adeos_stall_root
+#define restore_all .adeos_unstall_and_restore_all
+#endif /* CONFIG_ADEOS_CORE */
+
 #define SAVE_ALL \
 	cld; \
 	pushl %es; \
@@ -127,7 +132,7 @@ VM_MASK		= 0x00020000
 	addl $4, %esp;	\
 1:	iret;		\
 .section .fixup,"ax";   \
-2:	sti;		\
+2:	sti; \
 	movl $(__USER_DS), %edx; \
 	movl %edx, %ds; \
 	movl %edx, %es; \
@@ -192,14 +197,18 @@ ENTRY(ret_from_fork)
 	ALIGN
 ret_from_exception:
 	preempt_stop
+#ifdef CONFIG_ADEOS_CORE
+ENTRY(ret_from_intr)
+#else /* !CONFIG_ADEOS_CORE */
 ret_from_intr:
+#endif /* CONFIG_ADEOS_CORE */
 	GET_THREAD_INFO(%ebp)
 	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
 	movb CS(%esp), %al
 	testl $(VM_MASK | 3), %eax
 	jz resume_kernel		# returning to kernel or vm86-space
 ENTRY(resume_userspace)
- 	cli				# make sure we don't miss an interrupt
+	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
@@ -216,10 +225,19 @@ need_resched:
 	movl TI_flags(%ebp), %ecx	# need_resched set ?
 	testb $_TIF_NEED_RESCHED, %cl
 	jz restore_all
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_kpreempt_root	# prepare for kernel preemption opportunity
+	testl %eax,%eax
+#else /* !CONFIG_ADEOS_CORE */
 	testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
+#endif /* CONFIG_ADEOS_CORE */
 	jz restore_all
 	movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp)
-	sti
+#ifdef CONFIG_ADEOS_CORE
+ 	call __adeos_unstall_root
+#else /* CONFIG_ADEOS_CORE */
+  	sti
+#endif /* CONFIG_ADEOS_CORE */
 	call schedule
 	movl $0,TI_preempt_count(%ebp)
 	cli
@@ -233,7 +251,7 @@ need_resched:
 ENTRY(sysenter_entry)
 	movl TSS_sysenter_esp0(%esp),%esp
 sysenter_past_esp:
-	sti
+  	sti
 	pushl $(__USER_DS)
 	pushl %ebp
 	pushfl
@@ -255,6 +273,14 @@ sysenter_past_esp:
 	pushl %eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_if_fixup_root
+	call __adeos_enter_syscall
+	testl  %eax,%eax
+	js    .adeos_syswork
+	jne   .adeos_sysdone
+	movl ORIG_EAX(%esp),%eax
+#endif /* CONFIG_ADEOS_CORE */
 
 	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
 	jnz syscall_trace_entry
@@ -262,11 +288,22 @@ sysenter_past_esp:
 	jae syscall_badsys
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_exit_syscall
+ 	testl %eax,%eax
+ 	jne   .adeos_sysdone
+.adeos_syswork:	
+#endif /* CONFIG_ADEOS_CORE */
 	cli
 	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx
 	jne syscall_exit_work
 /* if something modifies registers it must also disable sysexit */
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_unstall_iret_root
+.adeos_sysdone:
+ 	movl EAX(%esp),%eax
+#endif /* CONFIG_ADEOS_CORE */
 	movl EIP(%esp), %edx
 	movl OLDESP(%esp), %ecx
 	sti
@@ -278,22 +315,59 @@ ENTRY(system_call)
 	pushl %eax			# save orig_eax
 	SAVE_ALL
 	GET_THREAD_INFO(%ebp)
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_if_fixup_root
+	call __adeos_enter_syscall
+	testl %eax,%eax
+	js    syscall_exit
+	jne   .adeos_restore_all
+	movl ORIG_EAX(%esp),%eax
+#endif /* CONFIG_ADEOS_CORE */
 					# system call tracing in operation
 	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
 	jnz syscall_trace_entry
 	cmpl $(nr_syscalls), %eax
 	jae syscall_badsys
 syscall_call:
+#if (CONFIG_LTT)
+ 	movl syscall_entry_trace_active, %eax
+ 	cmpl $1, %eax                   # are we tracing system call entries
+ 	jne no_syscall_entry_trace
+ 	movl %esp, %eax                 # copy the stack pointer
+ 	pushl %eax                      # pass the stack pointer copy
+ 	call trace_real_syscall_entry
+ 	addl $4,%esp                    # return stack to state before pass
+no_syscall_entry_trace:
+ 	movl ORIG_EAX(%esp),%eax	# restore eax to it's original content
+#endif
 	call *sys_call_table(,%eax,4)
 	movl %eax,EAX(%esp)		# store the return value
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_exit_syscall
+	testl %eax,%eax
+	jne   .adeos_restore_all
+#endif /* CONFIG_ADEOS_CORE */
 syscall_exit:
+#if (CONFIG_LTT)
+	movl syscall_exit_trace_active, %eax
+ 	cmpl $1, %eax                   # are we tracing system call exits
+ 	jne no_syscall_exit_trace
+ 	call trace_real_syscall_exit
+no_syscall_exit_trace:	
+#endif
 	cli				# make sure we don't miss an interrupt
 					# setting need_resched or sigpending
 					# between sampling and the iret
 	movl TI_flags(%ebp), %ecx
 	testw $_TIF_ALLWORK_MASK, %cx	# current->work
 	jne syscall_exit_work
+#ifdef CONFIG_ADEOS_CORE
+.adeos_unstall_and_restore_all:
+	call __adeos_unstall_iret_root
+.adeos_restore_all:
+#else /* !CONFIG_ADEOS_CORE */
 restore_all:
+#endif /* CONFIG_ADEOS_CORE */
 	RESTORE_ALL
 
 	# perform work that needs to be done immediately before resumption
@@ -350,7 +424,11 @@ syscall_trace_entry:
 syscall_exit_work:
 	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
 	jz work_pending
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_unstall_root
+#else /* CONFIG_ADEOS_CORE */
 	sti				# could let do_syscall_trace() call
+#endif /* CONFIG_ADEOS_CORE */
 					# schedule() instead
 	movl %esp, %eax
 	movl $1, %edx
@@ -380,7 +458,11 @@ ENTRY(interrupt)
 
 vector=0
 ENTRY(irq_entries_start)
+#ifdef CONFIG_ADEOS_CORE
+.rept 224
+#else
 .rept NR_IRQS
+#endif
 	ALIGN
 1:	pushl $vector-256
 	jmp common_interrupt
@@ -406,6 +488,34 @@ ENTRY(name)				\
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
 
+#ifdef CONFIG_ADEOS_CORE
+
+.data
+ENTRY(__adeos_irq_trampolines)
+.text
+
+vector=0
+ENTRY(__adeos_irq_entries)
+.rept 224
+	ALIGN
+1:	pushl $vector-256
+	jmp __adeos_irq_common
+.data
+	.long 1b
+.text
+vector=vector+1
+.endr
+
+	ALIGN
+__adeos_irq_common:
+	SAVE_ALL
+	call __adeos_handle_irq
+	testl %eax,%eax
+	jnz  ret_from_intr
+	RESTORE_ALL
+
+#endif /* !CONFIG_ADEOS_CORE */
+
 ENTRY(divide_error)
 	pushl $0			# no error code
 	pushl $do_divide_error
@@ -435,6 +545,9 @@ error_code:
 	movl %edx, %es
 	call *%edi
 	addl $8, %esp
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_if_fixup_root
+#endif /* CONFIG_ADEOS_CORE */
 	jmp ret_from_exception
 
 ENTRY(coprocessor_error)
@@ -450,6 +563,9 @@ ENTRY(simd_coprocessor_error)
 ENTRY(device_not_available)
 	pushl $-1			# mark this as an int
 	SAVE_ALL
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_if_fixup_root
+#endif /* CONFIG_ADEOS_CORE */
 	movl %cr0, %eax
 	testl $0x4, %eax		# EM (math emulation bit)
 	jne device_not_available_emulate
diff -uNrp linux-2.6.9/arch/i386/kernel/entry.S~ linux-2.6.9-ltt-r12/arch/i386/kernel/entry.S~
--- linux-2.6.9/arch/i386/kernel/entry.S~	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/entry.S~	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,1019 @@
+/*
+ *  linux/arch/i386/entry.S
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * entry.S contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all interrupts
+ * and faults that can result in a task-switch.
+ *
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ *
+ * I changed all the .align's to 4 (16 byte alignment), as that's faster
+ * on a 486.
+ *
+ * Stack layout in 'ret_from_system_call':
+ * 	ptrace needs to have all regs on the stack.
+ *	if the order here is changed, it needs to be
+ *	updated in fork.c:copy_process, signal.c:do_signal,
+ *	ptrace.c and ptrace.h
+ *
+ *	 0(%esp) - %ebx
+ *	 4(%esp) - %ecx
+ *	 8(%esp) - %edx
+ *       C(%esp) - %esi
+ *	10(%esp) - %edi
+ *	14(%esp) - %ebp
+ *	18(%esp) - %eax
+ *	1C(%esp) - %ds
+ *	20(%esp) - %es
+ *	24(%esp) - orig_eax
+ *	28(%esp) - %eip
+ *	2C(%esp) - %cs
+ *	30(%esp) - %eflags
+ *	34(%esp) - %oldesp
+ *	38(%esp) - %oldss
+ *
+ * "current" is in register %ebx during any slow entries.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/segment.h>
+#include <asm/smp.h>
+#include <asm/page.h>
+#include "irq_vectors.h"
+
+#define nr_syscalls ((syscall_table_size)/4)
+
+EBX		= 0x00
+ECX		= 0x04
+EDX		= 0x08
+ESI		= 0x0C
+EDI		= 0x10
+EBP		= 0x14
+EAX		= 0x18
+DS		= 0x1C
+ES		= 0x20
+ORIG_EAX	= 0x24
+EIP		= 0x28
+CS		= 0x2C
+EFLAGS		= 0x30
+OLDESP		= 0x34
+OLDSS		= 0x38
+
+CF_MASK		= 0x00000001
+TF_MASK		= 0x00000100
+IF_MASK		= 0x00000200
+DF_MASK		= 0x00000400 
+NT_MASK		= 0x00004000
+VM_MASK		= 0x00020000
+
+#ifdef CONFIG_PREEMPT
+#define preempt_stop		cli
+#else
+#define preempt_stop
+#define resume_kernel		restore_all
+#endif
+
+#ifdef CONFIG_ADEOS_CORE
+#define	cli          call __adeos_stall_root
+#define restore_all .adeos_unstall_and_restore_all
+#endif /* CONFIG_ADEOS_CORE */
+
+#define SAVE_ALL \
+	cld; \
+	pushl %es; \
+	pushl %ds; \
+	pushl %eax; \
+	pushl %ebp; \
+	pushl %edi; \
+	pushl %esi; \
+	pushl %edx; \
+	pushl %ecx; \
+	pushl %ebx; \
+	movl $(__USER_DS), %edx; \
+	movl %edx, %ds; \
+	movl %edx, %es;
+
+#define RESTORE_INT_REGS \
+	popl %ebx;	\
+	popl %ecx;	\
+	popl %edx;	\
+	popl %esi;	\
+	popl %edi;	\
+	popl %ebp;	\
+	popl %eax
+
+#define RESTORE_REGS	\
+	RESTORE_INT_REGS; \
+1:	popl %ds;	\
+2:	popl %es;	\
+.section .fixup,"ax";	\
+3:	movl $0,(%esp);	\
+	jmp 1b;		\
+4:	movl $0,(%esp);	\
+	jmp 2b;		\
+.previous;		\
+.section __ex_table,"a";\
+	.align 4;	\
+	.long 1b,3b;	\
+	.long 2b,4b;	\
+.previous
+
+
+#define RESTORE_ALL	\
+	RESTORE_REGS	\
+	addl $4, %esp;	\
+1:	iret;		\
+.section .fixup,"ax";   \
+2:	sti; \
+	movl $(__USER_DS), %edx; \
+	movl %edx, %ds; \
+	movl %edx, %es; \
+	pushl $11;	\
+	call do_exit;	\
+.previous;		\
+.section __ex_table,"a";\
+	.align 4;	\
+	.long 1b,2b;	\
+.previous
+
+
+
+ENTRY(lcall7)
+	pushfl			# We get a different stack layout with call
+				# gates, which has to be cleaned up later..
+	pushl %eax
+	SAVE_ALL
+	movl %esp, %ebp
+	pushl %ebp
+	pushl $0x7
+do_lcall:
+	movl EIP(%ebp), %eax	# due to call gates, this is eflags, not eip..
+	movl CS(%ebp), %edx	# this is eip..
+	movl EFLAGS(%ebp), %ecx	# and this is cs..
+	movl %eax,EFLAGS(%ebp)	#
+	movl %edx,EIP(%ebp)	# Now we move them to their "normal" places
+	movl %ecx,CS(%ebp)	#
+	GET_THREAD_INFO_WITH_ESP(%ebp)	# GET_THREAD_INFO
+	movl TI_exec_domain(%ebp), %edx	# Get the execution domain
+	call *EXEC_DOMAIN_handler(%edx)	# Call the handler for the domain
+	addl $4, %esp
+	popl %eax
+	jmp resume_userspace
+
+ENTRY(lcall27)
+	pushfl			# We get a different stack layout with call
+				# gates, which has to be cleaned up later..
+	pushl %eax
+	SAVE_ALL
+	movl %esp, %ebp
+	pushl %ebp
+	pushl $0x27
+	jmp do_lcall
+
+
+ENTRY(ret_from_fork)
+	pushl %eax
+	call schedule_tail
+	GET_THREAD_INFO(%ebp)
+	popl %eax
+	jmp syscall_exit
+
+/*
+ * Return to user mode is not as complex as all this looks,
+ * but we want the default path for a system call return to
+ * go as quickly as possible which is why some of this is
+ * less clear than it otherwise should be.
+ */
+
+	# userspace resumption stub bypassing syscall exit tracing
+	ALIGN
+ret_from_exception:
+	preempt_stop
+#ifdef CONFIG_ADEOS_CORE
+ENTRY(ret_from_intr)
+#else /* !CONFIG_ADEOS_CORE */
+ret_from_intr:
+#endif /* CONFIG_ADEOS_CORE */
+	GET_THREAD_INFO(%ebp)
+	movl EFLAGS(%esp), %eax		# mix EFLAGS and CS
+	movb CS(%esp), %al
+	testl $(VM_MASK | 3), %eax
+	jz resume_kernel		# returning to kernel or vm86-space
+ENTRY(resume_userspace)
+	cli				# make sure we don't miss an interrupt
+					# setting need_resched or sigpending
+					# between sampling and the iret
+	movl TI_flags(%ebp), %ecx
+	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done on
+					# int/exception return?
+	jne work_pending
+	jmp restore_all
+
+#ifdef CONFIG_PREEMPT
+ENTRY(resume_kernel)
+	cmpl $0,TI_preempt_count(%ebp)	# non-zero preempt_count ?
+	jnz restore_all
+need_resched:
+	movl TI_flags(%ebp), %ecx	# need_resched set ?
+	testb $_TIF_NEED_RESCHED, %cl
+	jz restore_all
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_kpreempt_root	# prepare for kernel preemption opportunity
+	testl %eax,%eax
+#else /* !CONFIG_ADEOS_CORE */
+	testl $IF_MASK,EFLAGS(%esp)     # interrupts off (exception path) ?
+#endif /* CONFIG_ADEOS_CORE */
+	jz restore_all
+	movl $PREEMPT_ACTIVE,TI_preempt_count(%ebp)
+#ifdef CONFIG_ADEOS_CORE
+ 	call __adeos_unstall_root
+#else /* CONFIG_ADEOS_CORE */
+  	sti
+#endif /* CONFIG_ADEOS_CORE */
+	call schedule
+	movl $0,TI_preempt_count(%ebp)
+	cli
+	jmp need_resched
+#endif
+
+/* SYSENTER_RETURN points to after the "sysenter" instruction in
+   the vsyscall page.  See vsyscall-sysentry.S, which defines the symbol.  */
+
+	# sysenter call handler stub
+ENTRY(sysenter_entry)
+	movl TSS_sysenter_esp0(%esp),%esp
+sysenter_past_esp:
+  	sti
+	pushl $(__USER_DS)
+	pushl %ebp
+	pushfl
+	pushl $(__USER_CS)
+	pushl $SYSENTER_RETURN
+
+/*
+ * Load the potential sixth argument from user stack.
+ * Careful about security.
+ */
+	cmpl $__PAGE_OFFSET-3,%ebp
+	jae syscall_fault
+1:	movl (%ebp),%ebp
+.section __ex_table,"a"
+	.align 4
+	.long 1b,syscall_fault
+.previous
+
+	pushl %eax
+	SAVE_ALL
+	GET_THREAD_INFO(%ebp)
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_if_fixup_root
+	call __adeos_enter_syscall
+	testl  %eax,%eax
+	js    .adeos_syswork
+	jne   .adeos_sysdone
+	movl ORIG_EAX(%esp),%eax
+#endif /* CONFIG_ADEOS_CORE */
+
+	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+	jnz syscall_trace_entry
+	cmpl $(nr_syscalls), %eax
+	jae syscall_badsys
+	call *sys_call_table(,%eax,4)
+	movl %eax,EAX(%esp)
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_exit_syscall
+ 	testl %eax,%eax
+ 	jne   .adeos_sysdone
+.adeos_syswork:	
+#endif /* CONFIG_ADEOS_CORE */
+	cli
+	movl TI_flags(%ebp), %ecx
+	testw $_TIF_ALLWORK_MASK, %cx
+	jne syscall_exit_work
+/* if something modifies registers it must also disable sysexit */
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_unstall_iret_root
+.adeos_sysdone:
+ 	movl EAX(%esp),%eax
+#endif /* CONFIG_ADEOS_CORE */
+	movl EIP(%esp), %edx
+	movl OLDESP(%esp), %ecx
+	sti
+	sysexit
+
+
+	# system call handler stub
+ENTRY(system_call)
+	pushl %eax			# save orig_eax
+	SAVE_ALL
+	GET_THREAD_INFO(%ebp)
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_if_fixup_root
+	call __adeos_enter_syscall
+	testl %eax,%eax
+	js    syscall_exit
+	jne   .adeos_restore_all
+	movl ORIG_EAX(%esp),%eax
+#endif /* CONFIG_ADEOS_CORE */
+					# system call tracing in operation
+	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp)
+	jnz syscall_trace_entry
+	cmpl $(nr_syscalls), %eax
+	jae syscall_badsys
+syscall_call:
+#if (CONFIG_LTT)
+ 	movl syscall_entry_trace_active, %eax
+ 	cmpl $1, %eax                   # are we tracing system call entries
+ 	jne no_syscall_entry_trace
+ 	movl %esp, %eax                 # copy the stack pointer
+ 	pushl %eax                      # pass the stack pointer copy
+ 	call trace_real_syscall_entry
+ 	addl $4,%esp                    # return stack to state before pass
+no_syscall_entry_trace:
+ 	movl ORIG_EAX(%esp),%eax	# restore eax to it's original content
+#endif
+	call *sys_call_table(,%eax,4)
+	movl %eax,EAX(%esp)		# store the return value
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_exit_syscall
+	testl %eax,%eax
+	jne   .adeos_restore_all
+#endif /* CONFIG_ADEOS_CORE */
+syscall_exit:
+#if (CONFIG_LTT)
+	movl syscall_exit_trace_active, %eax
+ 	cmpl $1, %eax                   # are we tracing system call exits
+ 	jne no_syscall_exit_trace
+ 	call trace_real_syscall_exit
+no_syscall_exit_trace:	
+#endif
+	cli				# make sure we don't miss an interrupt
+					# setting need_resched or sigpending
+					# between sampling and the iret
+	movl TI_flags(%ebp), %ecx
+	testw $_TIF_ALLWORK_MASK, %cx	# current->work
+	jne syscall_exit_work
+#ifdef CONFIG_ADEOS_CORE
+.adeos_unstall_and_restore_all:
+	call __adeos_unstall_iret_root
+.adeos_restore_all:
+#else /* !CONFIG_ADEOS_CORE */
+restore_all:
+#endif /* CONFIG_ADEOS_CORE */
+	RESTORE_ALL
+
+	# perform work that needs to be done immediately before resumption
+	ALIGN
+work_pending:
+	testb $_TIF_NEED_RESCHED, %cl
+	jz work_notifysig
+work_resched:
+	call schedule
+	cli				# make sure we don't miss an interrupt
+					# setting need_resched or sigpending
+					# between sampling and the iret
+	movl TI_flags(%ebp), %ecx
+	andl $_TIF_WORK_MASK, %ecx	# is there any work to be done other
+					# than syscall tracing?
+	jz restore_all
+	testb $_TIF_NEED_RESCHED, %cl
+	jnz work_resched
+
+work_notifysig:				# deal with pending signals and
+					# notify-resume requests
+	testl $VM_MASK, EFLAGS(%esp)
+	movl %esp, %eax
+	jne work_notifysig_v86		# returning to kernel-space or
+					# vm86-space
+	xorl %edx, %edx
+	call do_notify_resume
+	jmp restore_all
+
+	ALIGN
+work_notifysig_v86:
+	pushl %ecx
+	call save_v86_state
+	popl %ecx
+	movl %eax, %esp
+	xorl %edx, %edx
+	call do_notify_resume
+	jmp restore_all
+
+	# perform syscall exit tracing
+	ALIGN
+syscall_trace_entry:
+	movl $-ENOSYS,EAX(%esp)
+	movl %esp, %eax
+	xorl %edx,%edx
+	call do_syscall_trace
+	movl ORIG_EAX(%esp), %eax
+	cmpl $(nr_syscalls), %eax
+	jnae syscall_call
+	jmp syscall_exit
+
+	# perform syscall exit tracing
+	ALIGN
+syscall_exit_work:
+	testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP), %cl
+	jz work_pending
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_unstall_root
+#else /* CONFIG_ADEOS_CORE */
+	sti				# could let do_syscall_trace() call
+#endif /* CONFIG_ADEOS_CORE */
+					# schedule() instead
+	movl %esp, %eax
+	movl $1, %edx
+	call do_syscall_trace
+	jmp resume_userspace
+
+	ALIGN
+syscall_fault:
+	pushl %eax			# save orig_eax
+	SAVE_ALL
+	GET_THREAD_INFO(%ebp)
+	movl $-EFAULT,EAX(%esp)
+	jmp resume_userspace
+
+	ALIGN
+syscall_badsys:
+	movl $-ENOSYS,EAX(%esp)
+	jmp resume_userspace
+
+/*
+ * Build the entry stubs and pointer table with
+ * some assembler magic.
+ */
+.data
+ENTRY(interrupt)
+.text
+
+vector=0
+ENTRY(irq_entries_start)
+#ifdef CONFIG_ADEOS_CORE
+.rept 224
+#else
+.rept NR_IRQS
+#endif
+	ALIGN
+1:	pushl $vector-256
+	jmp common_interrupt
+.data
+	.long 1b
+.text
+vector=vector+1
+.endr
+
+	ALIGN
+common_interrupt:
+	SAVE_ALL
+	call do_IRQ
+	jmp ret_from_intr
+
+#define BUILD_INTERRUPT(name, nr)	\
+ENTRY(name)				\
+	pushl $nr-256;			\
+	SAVE_ALL			\
+	call smp_/**/name;	\
+	jmp ret_from_intr;
+
+/* The include is where all of the SMP etc. interrupts come from */
+#include "entry_arch.h"
+
+#ifdef CONFIG_ADEOS_CORE
+
+.data
+ENTRY(__adeos_irq_trampolines)
+.text
+
+vector=0
+ENTRY(__adeos_irq_entries)
+.rept 224
+	ALIGN
+1:	pushl $vector-256
+	jmp __adeos_irq_common
+.data
+	.long 1b
+.text
+vector=vector+1
+.endr
+
+	ALIGN
+__adeos_irq_common:
+	SAVE_ALL
+	call __adeos_handle_irq
+	RESTORE_ALL
+
+#endif /* !CONFIG_ADEOS_CORE */
+	
+ENTRY(divide_error)
+	pushl $0			# no error code
+	pushl $do_divide_error
+	ALIGN
+error_code:
+	pushl %ds
+	pushl %eax
+	xorl %eax, %eax
+	pushl %ebp
+	pushl %edi
+	pushl %esi
+	pushl %edx
+	decl %eax			# eax = -1
+	pushl %ecx
+	pushl %ebx
+	cld
+	movl %es, %ecx
+	movl ORIG_EAX(%esp), %esi	# get the error code
+	movl ES(%esp), %edi		# get the function address
+	movl %eax, ORIG_EAX(%esp)
+	movl %ecx, ES(%esp)
+	movl %esp, %edx
+	pushl %esi			# push the error code
+	pushl %edx			# push the pt_regs pointer
+	movl $(__USER_DS), %edx
+	movl %edx, %ds
+	movl %edx, %es
+	call *%edi
+	addl $8, %esp
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_if_fixup_root
+#endif /* CONFIG_ADEOS_CORE */
+	jmp ret_from_exception
+
+ENTRY(coprocessor_error)
+	pushl $0
+	pushl $do_coprocessor_error
+	jmp error_code
+
+ENTRY(simd_coprocessor_error)
+	pushl $0
+	pushl $do_simd_coprocessor_error
+	jmp error_code
+
+ENTRY(device_not_available)
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+#ifdef CONFIG_ADEOS_CORE
+	call __adeos_if_fixup_root
+#endif /* CONFIG_ADEOS_CORE */
+	movl %cr0, %eax
+	testl $0x4, %eax		# EM (math emulation bit)
+	jne device_not_available_emulate
+	preempt_stop
+	call math_state_restore
+	jmp ret_from_exception
+device_not_available_emulate:
+	pushl $0			# temporary storage for ORIG_EIP
+	call math_emulate
+	addl $4, %esp
+	jmp ret_from_exception
+
+/*
+ * Debug traps and NMI can happen at the one SYSENTER instruction
+ * that sets up the real kernel stack. Check here, since we can't
+ * allow the wrong stack to be used.
+ *
+ * "TSS_sysenter_esp0+12" is because the NMI/debug handler will have
+ * already pushed 3 words if it hits on the sysenter instruction:
+ * eflags, cs and eip.
+ *
+ * We just load the right stack, and push the three (known) values
+ * by hand onto the new stack - while updating the return eip past
+ * the instruction that would have done it for sysenter.
+ */
+#define FIX_STACK(offset, ok, label)		\
+	cmpw $__KERNEL_CS,4(%esp);		\
+	jne ok;					\
+label:						\
+	movl TSS_sysenter_esp0+offset(%esp),%esp;	\
+	pushfl;					\
+	pushl $__KERNEL_CS;			\
+	pushl $sysenter_past_esp
+
+ENTRY(debug)
+	cmpl $sysenter_entry,(%esp)
+	jne debug_stack_correct
+	FIX_STACK(12, debug_stack_correct, debug_esp_fix_insn)
+debug_stack_correct:
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+	movl %esp,%edx
+  	pushl $0
+	pushl %edx
+	call do_debug
+	addl $8,%esp
+	testl %eax,%eax
+	jnz restore_all
+	jmp ret_from_exception
+
+/*
+ * NMI is doubly nasty. It can happen _while_ we're handling
+ * a debug fault, and the debug fault hasn't yet been able to
+ * clear up the stack. So we first check whether we got  an
+ * NMI on the sysenter entry path, but after that we need to
+ * check whether we got an NMI on the debug path where the debug
+ * fault happened on the sysenter path.
+ */
+ENTRY(nmi)
+	cmpl $sysenter_entry,(%esp)
+	je nmi_stack_fixup
+	pushl %eax
+	movl %esp,%eax
+	/* Do not access memory above the end of our stack page,
+	 * it might not exist.
+	 */
+	andl $(THREAD_SIZE-1),%eax
+	cmpl $(THREAD_SIZE-20),%eax
+	popl %eax
+	jae nmi_stack_correct
+	cmpl $sysenter_entry,12(%esp)
+	je nmi_debug_stack_check
+nmi_stack_correct:
+	pushl %eax
+	SAVE_ALL
+	movl %esp, %edx
+	pushl $0
+	pushl %edx
+	call do_nmi
+	addl $8, %esp
+	RESTORE_ALL
+
+nmi_stack_fixup:
+	FIX_STACK(12,nmi_stack_correct, 1)
+	jmp nmi_stack_correct
+nmi_debug_stack_check:
+	cmpw $__KERNEL_CS,16(%esp)
+	jne nmi_stack_correct
+	cmpl $debug - 1,(%esp)
+	jle nmi_stack_correct
+	cmpl $debug_esp_fix_insn,(%esp)
+	jle nmi_debug_stack_fixup
+nmi_debug_stack_fixup:
+	FIX_STACK(24,nmi_stack_correct, 1)
+	jmp nmi_stack_correct
+
+ENTRY(int3)
+	pushl $-1			# mark this as an int
+	SAVE_ALL
+	movl %esp,%edx
+	pushl $0
+	pushl %edx
+	call do_int3
+	addl $8,%esp
+	testl %eax,%eax
+	jnz restore_all
+	jmp ret_from_exception
+
+ENTRY(overflow)
+	pushl $0
+	pushl $do_overflow
+	jmp error_code
+
+ENTRY(bounds)
+	pushl $0
+	pushl $do_bounds
+	jmp error_code
+
+ENTRY(invalid_op)
+	pushl $0
+	pushl $do_invalid_op
+	jmp error_code
+
+ENTRY(coprocessor_segment_overrun)
+	pushl $0
+	pushl $do_coprocessor_segment_overrun
+	jmp error_code
+
+ENTRY(invalid_TSS)
+	pushl $do_invalid_TSS
+	jmp error_code
+
+ENTRY(segment_not_present)
+	pushl $do_segment_not_present
+	jmp error_code
+
+ENTRY(stack_segment)
+	pushl $do_stack_segment
+	jmp error_code
+
+ENTRY(general_protection)
+	pushl $do_general_protection
+	jmp error_code
+
+ENTRY(alignment_check)
+	pushl $do_alignment_check
+	jmp error_code
+
+ENTRY(page_fault)
+	pushl $do_page_fault
+	jmp error_code
+
+#ifdef CONFIG_X86_MCE
+ENTRY(machine_check)
+	pushl $0
+	pushl machine_check_vector
+	jmp error_code
+#endif
+
+ENTRY(spurious_interrupt_bug)
+	pushl $0
+	pushl $do_spurious_interrupt_bug
+	jmp error_code
+
+.data
+ENTRY(sys_call_table)
+	.long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */
+	.long sys_exit
+	.long sys_fork
+	.long sys_read
+	.long sys_write
+	.long sys_open		/* 5 */
+	.long sys_close
+	.long sys_waitpid
+	.long sys_creat
+	.long sys_link
+	.long sys_unlink	/* 10 */
+	.long sys_execve
+	.long sys_chdir
+	.long sys_time
+	.long sys_mknod
+	.long sys_chmod		/* 15 */
+	.long sys_lchown16
+	.long sys_ni_syscall	/* old break syscall holder */
+	.long sys_stat
+	.long sys_lseek
+	.long sys_getpid	/* 20 */
+	.long sys_mount
+	.long sys_oldumount
+	.long sys_setuid16
+	.long sys_getuid16
+	.long sys_stime		/* 25 */
+	.long sys_ptrace
+	.long sys_alarm
+	.long sys_fstat
+	.long sys_pause
+	.long sys_utime		/* 30 */
+	.long sys_ni_syscall	/* old stty syscall holder */
+	.long sys_ni_syscall	/* old gtty syscall holder */
+	.long sys_access
+	.long sys_nice
+	.long sys_ni_syscall	/* 35 - old ftime syscall holder */
+	.long sys_sync
+	.long sys_kill
+	.long sys_rename
+	.long sys_mkdir
+	.long sys_rmdir		/* 40 */
+	.long sys_dup
+	.long sys_pipe
+	.long sys_times
+	.long sys_ni_syscall	/* old prof syscall holder */
+	.long sys_brk		/* 45 */
+	.long sys_setgid16
+	.long sys_getgid16
+	.long sys_signal
+	.long sys_geteuid16
+	.long sys_getegid16	/* 50 */
+	.long sys_acct
+	.long sys_umount	/* recycled never used phys() */
+	.long sys_ni_syscall	/* old lock syscall holder */
+	.long sys_ioctl
+	.long sys_fcntl		/* 55 */
+	.long sys_ni_syscall	/* old mpx syscall holder */
+	.long sys_setpgid
+	.long sys_ni_syscall	/* old ulimit syscall holder */
+	.long sys_olduname
+	.long sys_umask		/* 60 */
+	.long sys_chroot
+	.long sys_ustat
+	.long sys_dup2
+	.long sys_getppid
+	.long sys_getpgrp	/* 65 */
+	.long sys_setsid
+	.long sys_sigaction
+	.long sys_sgetmask
+	.long sys_ssetmask
+	.long sys_setreuid16	/* 70 */
+	.long sys_setregid16
+	.long sys_sigsuspend
+	.long sys_sigpending
+	.long sys_sethostname
+	.long sys_setrlimit	/* 75 */
+	.long sys_old_getrlimit
+	.long sys_getrusage
+	.long sys_gettimeofday
+	.long sys_settimeofday
+	.long sys_getgroups16	/* 80 */
+	.long sys_setgroups16
+	.long old_select
+	.long sys_symlink
+	.long sys_lstat
+	.long sys_readlink	/* 85 */
+	.long sys_uselib
+	.long sys_swapon
+	.long sys_reboot
+	.long old_readdir
+	.long old_mmap		/* 90 */
+	.long sys_munmap
+	.long sys_truncate
+	.long sys_ftruncate
+	.long sys_fchmod
+	.long sys_fchown16	/* 95 */
+	.long sys_getpriority
+	.long sys_setpriority
+	.long sys_ni_syscall	/* old profil syscall holder */
+	.long sys_statfs
+	.long sys_fstatfs	/* 100 */
+	.long sys_ioperm
+	.long sys_socketcall
+	.long sys_syslog
+	.long sys_setitimer
+	.long sys_getitimer	/* 105 */
+	.long sys_newstat
+	.long sys_newlstat
+	.long sys_newfstat
+	.long sys_uname
+	.long sys_iopl		/* 110 */
+	.long sys_vhangup
+	.long sys_ni_syscall	/* old "idle" system call */
+	.long sys_vm86old
+	.long sys_wait4
+	.long sys_swapoff	/* 115 */
+	.long sys_sysinfo
+	.long sys_ipc
+	.long sys_fsync
+	.long sys_sigreturn
+	.long sys_clone		/* 120 */
+	.long sys_setdomainname
+	.long sys_newuname
+	.long sys_modify_ldt
+	.long sys_adjtimex
+	.long sys_mprotect	/* 125 */
+	.long sys_sigprocmask
+	.long sys_ni_syscall	/* old "create_module" */ 
+	.long sys_init_module
+	.long sys_delete_module
+	.long sys_ni_syscall	/* 130:	old "get_kernel_syms" */
+	.long sys_quotactl
+	.long sys_getpgid
+	.long sys_fchdir
+	.long sys_bdflush
+	.long sys_sysfs		/* 135 */
+	.long sys_personality
+	.long sys_ni_syscall	/* reserved for afs_syscall */
+	.long sys_setfsuid16
+	.long sys_setfsgid16
+	.long sys_llseek	/* 140 */
+	.long sys_getdents
+	.long sys_select
+	.long sys_flock
+	.long sys_msync
+	.long sys_readv		/* 145 */
+	.long sys_writev
+	.long sys_getsid
+	.long sys_fdatasync
+	.long sys_sysctl
+	.long sys_mlock		/* 150 */
+	.long sys_munlock
+	.long sys_mlockall
+	.long sys_munlockall
+	.long sys_sched_setparam
+	.long sys_sched_getparam   /* 155 */
+	.long sys_sched_setscheduler
+	.long sys_sched_getscheduler
+	.long sys_sched_yield
+	.long sys_sched_get_priority_max
+	.long sys_sched_get_priority_min  /* 160 */
+	.long sys_sched_rr_get_interval
+	.long sys_nanosleep
+	.long sys_mremap
+	.long sys_setresuid16
+	.long sys_getresuid16	/* 165 */
+	.long sys_vm86
+	.long sys_ni_syscall	/* Old sys_query_module */
+	.long sys_poll
+	.long sys_nfsservctl
+	.long sys_setresgid16	/* 170 */
+	.long sys_getresgid16
+	.long sys_prctl
+	.long sys_rt_sigreturn
+	.long sys_rt_sigaction
+	.long sys_rt_sigprocmask	/* 175 */
+	.long sys_rt_sigpending
+	.long sys_rt_sigtimedwait
+	.long sys_rt_sigqueueinfo
+	.long sys_rt_sigsuspend
+	.long sys_pread64	/* 180 */
+	.long sys_pwrite64
+	.long sys_chown16
+	.long sys_getcwd
+	.long sys_capget
+	.long sys_capset	/* 185 */
+	.long sys_sigaltstack
+	.long sys_sendfile
+	.long sys_ni_syscall	/* reserved for streams1 */
+	.long sys_ni_syscall	/* reserved for streams2 */
+	.long sys_vfork		/* 190 */
+	.long sys_getrlimit
+	.long sys_mmap2
+	.long sys_truncate64
+	.long sys_ftruncate64
+	.long sys_stat64	/* 195 */
+	.long sys_lstat64
+	.long sys_fstat64
+	.long sys_lchown
+	.long sys_getuid
+	.long sys_getgid	/* 200 */
+	.long sys_geteuid
+	.long sys_getegid
+	.long sys_setreuid
+	.long sys_setregid
+	.long sys_getgroups	/* 205 */
+	.long sys_setgroups
+	.long sys_fchown
+	.long sys_setresuid
+	.long sys_getresuid
+	.long sys_setresgid	/* 210 */
+	.long sys_getresgid
+	.long sys_chown
+	.long sys_setuid
+	.long sys_setgid
+	.long sys_setfsuid	/* 215 */
+	.long sys_setfsgid
+	.long sys_pivot_root
+	.long sys_mincore
+	.long sys_madvise
+	.long sys_getdents64	/* 220 */
+	.long sys_fcntl64
+	.long sys_ni_syscall	/* reserved for TUX */
+	.long sys_ni_syscall
+	.long sys_gettid
+	.long sys_readahead	/* 225 */
+	.long sys_setxattr
+	.long sys_lsetxattr
+	.long sys_fsetxattr
+	.long sys_getxattr
+	.long sys_lgetxattr	/* 230 */
+	.long sys_fgetxattr
+	.long sys_listxattr
+	.long sys_llistxattr
+	.long sys_flistxattr
+	.long sys_removexattr	/* 235 */
+	.long sys_lremovexattr
+	.long sys_fremovexattr
+	.long sys_tkill
+	.long sys_sendfile64
+	.long sys_futex		/* 240 */
+	.long sys_sched_setaffinity
+	.long sys_sched_getaffinity
+	.long sys_set_thread_area
+	.long sys_get_thread_area
+	.long sys_io_setup	/* 245 */
+	.long sys_io_destroy
+	.long sys_io_getevents
+	.long sys_io_submit
+	.long sys_io_cancel
+	.long sys_fadvise64	/* 250 */
+	.long sys_ni_syscall
+	.long sys_exit_group
+	.long sys_lookup_dcookie
+	.long sys_epoll_create
+	.long sys_epoll_ctl	/* 255 */
+	.long sys_epoll_wait
+ 	.long sys_remap_file_pages
+ 	.long sys_set_tid_address
+ 	.long sys_timer_create
+ 	.long sys_timer_settime		/* 260 */
+ 	.long sys_timer_gettime
+ 	.long sys_timer_getoverrun
+ 	.long sys_timer_delete
+ 	.long sys_clock_settime
+ 	.long sys_clock_gettime		/* 265 */
+ 	.long sys_clock_getres
+ 	.long sys_clock_nanosleep
+	.long sys_statfs64
+	.long sys_fstatfs64	
+	.long sys_tgkill	/* 270 */
+	.long sys_utimes
+ 	.long sys_fadvise64_64
+	.long sys_ni_syscall	/* sys_vserver */
+	.long sys_mbind
+	.long sys_get_mempolicy
+	.long sys_set_mempolicy
+	.long sys_mq_open
+	.long sys_mq_unlink
+	.long sys_mq_timedsend
+	.long sys_mq_timedreceive	/* 280 */
+	.long sys_mq_notify
+	.long sys_mq_getsetattr
+	.long sys_ni_syscall		/* reserved for kexec */
+	.long sys_waitid
+
+syscall_table_size=(.-sys_call_table)
diff -uNrp linux-2.6.9/arch/i386/kernel/i386_ksyms.c linux-2.6.9-ltt-r12/arch/i386/kernel/i386_ksyms.c
--- linux-2.6.9/arch/i386/kernel/i386_ksyms.c	2004-10-18 23:55:29.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/i386_ksyms.c	2005-08-15 10:31:45.000000000 +0200
@@ -36,6 +36,49 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
 
+#ifdef CONFIG_ADEOS_CORE
+extern int __adeos_irq_trampolines;
+EXPORT_SYMBOL(__adeos_irq_trampolines);
+#ifdef CONFIG_ADEOS_MODULE
+#ifdef CONFIG_X86_LOCAL_APIC
+extern int using_apic_timer;
+EXPORT_SYMBOL(using_apic_timer);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__adeos_set_irq_affinity);
+#include <mach_ipi.h>
+EXPORT_SYMBOL(send_IPI_mask_bitmask);
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_X86_LOCAL_APIC */
+#endif /* CONFIG_ADEOS_MODULE */
+/* The following are per-platform convenience exports which are needed
+   by some Adeos domains loaded as kernel modules. */
+extern irq_desc_t irq_desc[];
+EXPORT_SYMBOL(irq_desc);
+extern struct desc_struct idt_table[];
+EXPORT_SYMBOL(idt_table);
+extern void ret_from_intr(void);
+EXPORT_SYMBOL(ret_from_intr);
+#ifdef CONFIG_SMP
+EXPORT_PER_CPU_SYMBOL(cpu_tlbstate);
+#endif /* CONFIG_SMP */
+#if defined(CONFIG_ADEOS_MODULE) && defined(CONFIG_X86_IO_APIC)
+EXPORT_SYMBOL(io_apic_irqs);
+EXPORT_SYMBOL(irq_vector);
+#endif /* CONFIG_ADEOS_MODULE && CONFIG_X86_IO_APIC */
+EXPORT_SYMBOL(set_ldt_desc);
+EXPORT_SYMBOL(default_ldt);
+EXPORT_PER_CPU_SYMBOL(init_tss);
+EXPORT_SYMBOL(__switch_to);
+extern void show_stack(struct task_struct *task, unsigned long *esp);
+EXPORT_SYMBOL(show_stack);
+extern void show_registers(struct pt_regs *regs);
+EXPORT_SYMBOL(show_registers);
+void show_trace(struct task_struct *task, unsigned long *stack);
+EXPORT_SYMBOL(show_trace);
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code);
+EXPORT_SYMBOL(do_page_fault);
+#endif /* CONFIG_ADEOS_CORE */
+
 /* This is definitely a GPL-only symbol */
 EXPORT_SYMBOL_GPL(cpu_gdt_table);
 
diff -uNrp linux-2.6.9/arch/i386/kernel/i8259.c linux-2.6.9-ltt-r12/arch/i386/kernel/i8259.c
--- linux-2.6.9/arch/i386/kernel/i8259.c	2004-10-18 23:55:18.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/i8259.c	2005-08-15 10:31:45.000000000 +0200
@@ -93,13 +93,14 @@ void disable_8259A_irq(unsigned int irq)
 	unsigned int mask = 1 << irq;
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
+	pic_irq_lock(irq);
 	cached_irq_mask |= mask;
 	if (irq & 8)
 		outb(cached_slave_mask, PIC_SLAVE_IMR);
 	else
 		outb(cached_master_mask, PIC_MASTER_IMR);
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 }
 
 void enable_8259A_irq(unsigned int irq)
@@ -107,13 +108,14 @@ void enable_8259A_irq(unsigned int irq)
 	unsigned int mask = ~(1 << irq);
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 	cached_irq_mask &= mask;
 	if (irq & 8)
 		outb(cached_slave_mask, PIC_SLAVE_IMR);
 	else
 		outb(cached_master_mask, PIC_MASTER_IMR);
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	pic_irq_unlock(irq);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 }
 
 int i8259A_irq_pending(unsigned int irq)
@@ -122,12 +124,12 @@ int i8259A_irq_pending(unsigned int irq)
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 	if (irq < 8)
 		ret = inb(PIC_MASTER_CMD) & mask;
 	else
 		ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 
 	return ret;
 }
@@ -174,7 +176,7 @@ void mask_and_ack_8259A(unsigned int irq
 	unsigned int irqmask = 1 << irq;
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 	/*
 	 * Lightweight spurious IRQ detection. We do not want
 	 * to overdo spurious IRQ handling - it's usually a sign
@@ -192,6 +194,15 @@ void mask_and_ack_8259A(unsigned int irq
 	 */
 	if (cached_irq_mask & irqmask)
 		goto spurious_8259A_irq;
+#ifdef CONFIG_ADEOS_CORE
+	if (irq == 0) {
+	    /* Fast timer ack -- don't mask
+	      (unless supposedly spurious) */
+	    outb(0x20,PIC_MASTER_CMD);
+	    spin_unlock_irqrestore_hw(&i8259A_lock,flags);
+	    return;
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	cached_irq_mask |= irqmask;
 
 handle_real_irq:
@@ -205,7 +216,7 @@ handle_real_irq:
 		outb(cached_master_mask, PIC_MASTER_IMR);
 		outb(0x60+irq,PIC_MASTER_CMD);	/* 'Specific EOI to master */
 	}
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 	return;
 
 spurious_8259A_irq:
@@ -294,7 +305,7 @@ void init_8259A(int auto_eoi)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&i8259A_lock, flags);
+	spin_lock_irqsave_hw(&i8259A_lock, flags);
 
 	outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
 	outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-2 */
@@ -328,7 +339,7 @@ void init_8259A(int auto_eoi)
 	outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
 	outb(cached_slave_mask, PIC_SLAVE_IMR);	  /* restore slave IRQ mask */
 
-	spin_unlock_irqrestore(&i8259A_lock, flags);
+	spin_unlock_irqrestore_hw(&i8259A_lock, flags);
 }
 
 /*
diff -uNrp linux-2.6.9/arch/i386/kernel/io_apic.c linux-2.6.9-ltt-r12/arch/i386/kernel/io_apic.c
--- linux-2.6.9/arch/i386/kernel/io_apic.c	2004-10-18 23:53:46.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/io_apic.c	2005-08-15 10:31:45.000000000 +0200
@@ -171,18 +171,20 @@ static void mask_IO_APIC_irq (unsigned i
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	__mask_IO_APIC_irq(irq);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	pic_irq_lock(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 }
 
 static void unmask_IO_APIC_irq (unsigned int irq)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	__unmask_IO_APIC_irq(irq);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	pic_irq_unlock(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 }
 
 void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
@@ -191,10 +193,10 @@ void clear_IO_APIC_pin(unsigned int apic
 	unsigned long flags;
 	
 	/* Check delivery_mode to be sure we're not clearing an SMI pin */
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	*(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
 	*(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 	if (entry.delivery_mode == dest_SMI)
 		return;
 
@@ -203,10 +205,10 @@ void clear_IO_APIC_pin(unsigned int apic
 	 */
 	memset(&entry, 0, sizeof(entry));
 	entry.mask = 1;
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
 	io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 }
 
 static void clear_IO_APIC (void)
@@ -228,7 +230,7 @@ static void set_ioapic_affinity_irq(unsi
 	apicid_value = cpu_mask_to_apicid(cpumask);
 	/* Prepare to do the io_apic_write */
 	apicid_value = apicid_value << 24;
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	for (;;) {
 		pin = entry->pin;
 		if (pin == -1)
@@ -238,7 +240,7 @@ static void set_ioapic_affinity_irq(unsi
 			break;
 		entry = irq_2_pin + entry->next;
 	}
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 }
 
 #if defined(CONFIG_IRQBALANCE)
@@ -1800,14 +1802,15 @@ static unsigned int startup_edge_ioapic_
 	int was_pending = 0;
 	unsigned long flags;
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	if (irq < 16) {
 		disable_8259A_irq(irq);
 		if (i8259A_irq_pending(irq))
 			was_pending = 1;
 	}
 	__unmask_IO_APIC_irq(irq);
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	pic_irq_unlock(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	return was_pending;
 }
@@ -1817,6 +1820,27 @@ static unsigned int startup_edge_ioapic_
  * interrupt for real. This prevents IRQ storms from unhandled
  * devices.
  */
+
+#ifdef CONFIG_ADEOS_CORE
+
+static void ack_edge_ioapic_irq (unsigned irq)
+
+{
+    move_irq(irq);
+
+    if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED))
+	{
+	unsigned long flags;
+	spin_lock_irqsave_hw(&ioapic_lock,flags);
+	__mask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock,flags);
+	}
+
+    __ack_APIC_irq();
+}
+
+#else /* !CONFIG_ADEOS_CORE */
+
 static void ack_edge_ioapic_irq(unsigned int irq)
 {
 	move_irq(irq);
@@ -1826,6 +1850,8 @@ static void ack_edge_ioapic_irq(unsigned
 	ack_APIC_irq();
 }
 
+#endif /* CONFIG_ADEOS_CORE */
+
 /*
  * Level triggered interrupts can just be masked,
  * and shutting down and starting up the interrupt
@@ -1847,6 +1873,83 @@ static unsigned int startup_level_ioapic
 	return 0; /* don't check for pending */
 }
 
+#ifdef CONFIG_ADEOS_CORE
+
+/* The standard Linux implementation for acknowledging IO-APIC
+   interrupts has been changed in order to guarantee that low priority
+   IRQs won't be delayed waiting for a high priority interrupt handler
+   to call end_level_ioapic_irq(). Therefore we immediately ack in
+   mask_and_ack_level_ioapic_irq(), still handling the 82093AA bugous
+   edge case. */
+
+static unsigned long bugous_edge_triggers;
+
+static void end_level_ioapic_irq (unsigned irq)
+
+{
+    unsigned long flags;
+
+    move_irq(irq);
+
+    if (test_and_clear_bit(irq,&bugous_edge_triggers))
+	{
+#ifdef APIC_MISMATCH_DEBUG
+	atomic_inc(&irq_mis_count);
+#endif
+	spin_lock_irqsave_hw(&ioapic_lock,flags);
+	__unmask_and_level_IO_APIC_irq(irq);
+	pic_irq_unlock(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock,flags);
+	}
+    else
+	{
+	spin_lock_irqsave_hw(&ioapic_lock,flags);
+	__unmask_IO_APIC_irq(irq);
+	pic_irq_unlock(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock,flags);
+	}
+}
+
+static void mask_and_ack_level_ioapic_irq (unsigned irq)
+
+{
+    unsigned long flags, v;
+    int i;
+
+    i = IO_APIC_VECTOR(irq);
+    v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
+
+    if (!(v & (1 << (i & 0x1f))))
+	{
+	set_bit(irq,&bugous_edge_triggers);
+	spin_lock_irqsave_hw(&ioapic_lock,flags);
+	__mask_and_edge_IO_APIC_irq(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock,flags);
+	}
+    else
+	{
+	spin_lock_irqsave_hw(&ioapic_lock,flags);
+	__mask_IO_APIC_irq(irq);
+	spin_unlock_irqrestore_hw(&ioapic_lock,flags);
+	}
+
+    __ack_APIC_irq();
+}
+
+#ifdef CONFIG_PCI_MSI
+
+static inline void mask_and_ack_level_ioapic_vector(unsigned int vector)
+
+{
+	int irq = vector_to_irq(vector);
+
+	mask_and_ack_level_ioapic_irq(irq);
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+#else /* !CONFIG_ADEOS_CORE */
+
 static void end_level_ioapic_irq (unsigned int irq)
 {
 	unsigned long v;
@@ -1889,6 +1992,8 @@ static void end_level_ioapic_irq (unsign
 	}
 }
 
+#endif /* CONFIG_ADEOS_CORE */
+
 #ifdef CONFIG_PCI_MSI
 static unsigned int startup_edge_ioapic_vector(unsigned int vector)
 {
@@ -2026,7 +2131,7 @@ static void disable_lapic_irq (unsigned 
 
 static void ack_lapic_irq (unsigned int irq)
 {
-	ack_APIC_irq();
+	__ack_APIC_irq();
 }
 
 static void end_lapic_irq (unsigned int i) { /* nothing */ }
@@ -2299,12 +2404,12 @@ static int ioapic_suspend(struct sys_dev
 	
 	data = container_of(dev, struct sysfs_ioapic_data, dev);
 	entry = data->entry;
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
 		*(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i);
 		*(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i);
 	}
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	return 0;
 }
@@ -2320,7 +2425,7 @@ static int ioapic_resume(struct sys_devi
 	data = container_of(dev, struct sysfs_ioapic_data, dev);
 	entry = data->entry;
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	reg_00.raw = io_apic_read(dev->id, 0);
 	if (reg_00.bits.ID != mp_ioapics[dev->id].mpc_apicid) {
 		reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
@@ -2330,7 +2435,7 @@ static int ioapic_resume(struct sys_devi
 		io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1));
 		io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0));
 	}
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	return 0;
 }
@@ -2525,10 +2630,10 @@ int io_apic_set_pci_routing (int ioapic,
 	if (!ioapic && (irq < 16))
 		disable_8259A_irq(irq);
 
-	spin_lock_irqsave(&ioapic_lock, flags);
+	spin_lock_irqsave_hw(&ioapic_lock, flags);
 	io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
 	io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
-	spin_unlock_irqrestore(&ioapic_lock, flags);
+	spin_unlock_irqrestore_hw(&ioapic_lock, flags);
 
 	return 0;
 }
diff -uNrp linux-2.6.9/arch/i386/kernel/irq.c linux-2.6.9-ltt-r12/arch/i386/kernel/irq.c
--- linux-2.6.9/arch/i386/kernel/irq.c	2004-10-18 23:53:11.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/irq.c	2005-08-15 10:51:46.000000000 +0200
@@ -34,6 +34,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/kallsyms.h>
+#include <linux/ltt-events.h>
 
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -222,6 +223,8 @@ asmlinkage int handle_IRQ_event(unsigned
 	int status = 1;	/* Force the "do bottom halves" bit */
 	int ret, retval = 0;
 
+ 	ltt_ev_irq_entry(irq, !(user_mode(regs)));
+
 	if (!(action->flags & SA_INTERRUPT))
 		local_irq_enable();
 
@@ -235,6 +238,9 @@ asmlinkage int handle_IRQ_event(unsigned
 	if (status & SA_SAMPLE_RANDOM)
 		add_interrupt_randomness(irq);
 	local_irq_disable();
+
+ 	ltt_ev_irq_exit();
+
 	return retval;
 }
 
@@ -450,6 +456,9 @@ asmlinkage unsigned int do_IRQ(struct pt
 #endif
 	kstat_this_cpu.irqs[irq]++;
 	spin_lock(&desc->lock);
+#ifdef CONFIG_ADEOS_CORE
+	if (!adp_pipelined)
+#endif /* CONFIG_ADEOS_CORE */
 	desc->handler->ack(irq);
 	/*
 	   REPLAY is when Linux resends an IRQ that was dropped earlier
@@ -509,6 +518,43 @@ asmlinkage unsigned int do_IRQ(struct pt
 		 * after all)
 		 */
 
+#ifdef CONFIG_ADEOS_CORE
+		{
+		struct pt_regs *_regs = __adeos_tick_regs + smp_processor_id();
+
+		/* If processing a timer tick, pass the original regs
+		   as collected during preemption and not our phony -
+		   always kernel-originated - frame, so that we don't
+		   wreck the profiling code. */
+
+		if (!adp_pipelined || __adeos_tick_irq != irq)
+		    _regs = &regs;
+
+		if (curctx == irqctx)
+			action_ret = handle_IRQ_event(irq, _regs, action);
+		else {
+			/* build the stack frame on the IRQ stack */
+			isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
+			irqctx->tinfo.task = curctx->tinfo.task;
+			irqctx->tinfo.previous_esp = current_stack_pointer();
+
+			*--isp = (u32) action;
+			*--isp = (u32) _regs;
+			*--isp = (u32) irq;
+
+			asm volatile(
+				"       xchgl   %%ebx,%%esp     \n"
+				"       call    handle_IRQ_event \n"
+				"       xchgl   %%ebx,%%esp     \n"
+				: "=a"(action_ret)
+				: "b"(isp)
+				: "memory", "cc", "edx", "ecx"
+			);
+
+
+		   }
+		}
+#else /* CONFIG_ADEOS_CORE */
 		if (curctx == irqctx)
 			action_ret = handle_IRQ_event(irq, &regs, action);
 		else {
@@ -532,6 +578,8 @@ asmlinkage unsigned int do_IRQ(struct pt
 
 
 		}
+#endif /* CONFIG_ADEOS_CORE */
+
 		spin_lock(&desc->lock);
 		if (!noirqdebug)
 			note_interrupt(irq, desc, action_ret);
@@ -549,6 +597,16 @@ asmlinkage unsigned int do_IRQ(struct pt
 
 		spin_unlock(&desc->lock);
 
+#ifdef CONFIG_ADEOS_CORE
+		/* If processing a timer tick, pass the original regs
+		   as collected during preemption and not our phony -
+		   always kernel-originated - frame, so that we don't
+		   wreck the profiling code. */
+
+		if (adp_pipelined && __adeos_tick_irq == irq)
+		    action_ret = handle_IRQ_event(irq,__adeos_tick_regs + smp_processor_id(),action);
+		else
+#endif /* CONFIG_ADEOS_CORE */
 		action_ret = handle_IRQ_event(irq, &regs, action);
 
 		spin_lock(&desc->lock);
@@ -1026,6 +1084,32 @@ static int irq_affinity_write_proc(struc
 	return full_count;
 }
 
+#ifdef CONFIG_ADEOS_CORE
+
+cpumask_t __adeos_set_irq_affinity (unsigned irq, cpumask_t cpumask)
+
+{
+    cpumask_t oldmask = irq_affinity[irq];
+
+    if (irq_desc[irq].handler->set_affinity == NULL)
+	return CPU_MASK_NONE;
+
+    if (cpus_empty(cpumask))
+	return oldmask; /* Return mask value -- no change. */
+
+    cpus_and(cpumask,cpumask,cpu_online_map);
+
+    if (cpus_empty(cpumask) || irq_desc[irq].handler->set_affinity == NULL)
+	return CPU_MASK_NONE;	/* Error -- bad mask value or non-routable IRQ. */
+
+    irq_affinity[irq] = cpumask;
+    irq_desc[irq].handler->set_affinity(irq,cpumask);
+
+    return oldmask;
+}
+
+#endif /* CONFIG_ADEOS_CORE */
+
 #endif
 #define MAX_NAMELEN 10
 
diff -uNrp linux-2.6.9/arch/i386/kernel/process.c linux-2.6.9-ltt-r12/arch/i386/kernel/process.c
--- linux-2.6.9/arch/i386/kernel/process.c	2004-10-18 23:53:05.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/process.c	2005-08-15 10:51:46.000000000 +0200
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
+#include <linux/ltt-events.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -155,6 +156,9 @@ void cpu_idle (void)
 				idle = default_idle;
 
 			irq_stat[smp_processor_id()].idle_timestamp = jiffies;
+#ifdef CONFIG_ADEOS_CORE
+			adeos_suspend_domain();
+#endif /* CONFIG_ADEOS_CORE */
 			idle();
 			rcu_read_unlock();
 		}
@@ -263,6 +267,10 @@ __asm__(".section .text\n"
 	"kernel_thread_helper:\n\t"
 	"movl %edx,%eax\n\t"
 	"pushl %edx\n\t"
+#ifdef CONFIG_ADEOS_CORE
+	"call __adeos_unstall_root\n\t"
+	"movl (%esp),%eax\n\t"
+#endif /* CONFIG_ADEOS_CORE */
 	"call *%ebx\n\t"
 	"pushl %eax\n\t"
 	"call do_exit\n"
@@ -274,6 +282,7 @@ __asm__(".section .text\n"
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
 	struct pt_regs regs;
+	long pid;
 
 	memset(&regs, 0, sizeof(regs));
 
@@ -288,7 +297,12 @@ int kernel_thread(int (*fn)(void *), voi
 	regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
 
 	/* Ok, create the new process.. */
-	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+	pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+#if (CONFIG_LTT)
+	if(pid >= 0)
+		ltt_ev_process(LTT_EV_PROCESS_KTHREAD, pid, (int) fn);
+#endif
+	return pid;
 }
 
 /*
diff -uNrp linux-2.6.9/arch/i386/kernel/smp.c linux-2.6.9-ltt-r12/arch/i386/kernel/smp.c
--- linux-2.6.9/arch/i386/kernel/smp.c	2004-10-18 23:53:12.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/smp.c	2005-08-15 10:31:45.000000000 +0200
@@ -132,6 +132,11 @@ void __send_IPI_shortcut(unsigned int sh
 	 */
 	unsigned int cfg;
 
+#ifdef CONFIG_ADEOS_CORE
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* !CONFIG_ADEOS_CORE */
+
 	/*
 	 * Wait for idle.
 	 */
@@ -146,6 +151,10 @@ void __send_IPI_shortcut(unsigned int sh
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
 	apic_write_around(APIC_ICR, cfg);
+
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#endif /* !CONFIG_ADEOS_CORE */
 }
 
 void fastcall send_IPI_self(int vector)
@@ -162,7 +171,11 @@ void send_IPI_mask_bitmask(cpumask_t cpu
 	unsigned long cfg;
 	unsigned long flags;
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_save(flags);
+#else  /* !CONFIG_ADEOS_CORE */
 	local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
 		
 	/*
 	 * Wait for idle.
@@ -185,7 +198,11 @@ void send_IPI_mask_bitmask(cpumask_t cpu
 	 */
 	apic_write_around(APIC_ICR, cfg);
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#else  /* !CONFIG_ADEOS_CORE */
 	local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
@@ -199,7 +216,11 @@ inline void send_IPI_mask_sequence(cpuma
 	 * should be modified to do 1 message per cluster ID - mbligh
 	 */ 
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_save(flags);
+#else /* !CONFIG_ADEOS_CORE */
 	local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
 
 	for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
 		if (cpu_isset(query_cpu, mask)) {
@@ -226,7 +247,11 @@ inline void send_IPI_mask_sequence(cpuma
 			apic_write_around(APIC_ICR, cfg);
 		}
 	}
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#else /* !CONFIG_ADEOS_CORE */
 	local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 #include <mach_ipi.h> /* must come after the send_IPI functions above for inlining */
@@ -311,6 +336,10 @@ static inline void leave_mm (unsigned lo
 asmlinkage void smp_invalidate_interrupt (void)
 {
 	unsigned long cpu;
+#ifdef CONFIG_ADEOS_CORE
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
 
 	cpu = get_cpu();
 
@@ -340,6 +369,9 @@ asmlinkage void smp_invalidate_interrupt
 	smp_mb__after_clear_bit();
 out:
 	put_cpu_no_resched();
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
@@ -400,6 +432,10 @@ void flush_tlb_current_task(void)
 {
 	struct mm_struct *mm = current->mm;
 	cpumask_t cpu_mask;
+#ifdef CONFIG_ADEOS_CORE
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
 
 	preempt_disable();
 	cpu_mask = mm->cpu_vm_mask;
@@ -408,6 +444,9 @@ void flush_tlb_current_task(void)
 	local_flush_tlb();
 	if (!cpus_empty(cpu_mask))
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
 	preempt_enable();
 }
 
@@ -435,6 +474,10 @@ void flush_tlb_page(struct vm_area_struc
 {
 	struct mm_struct *mm = vma->vm_mm;
 	cpumask_t cpu_mask;
+#ifdef CONFIG_ADEOS_CORE
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
 
 	preempt_disable();
 	cpu_mask = mm->cpu_vm_mask;
@@ -447,6 +490,10 @@ void flush_tlb_page(struct vm_area_struc
 		 	leave_mm(smp_processor_id());
 	}
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
+
 	if (!cpus_empty(cpu_mask))
 		flush_tlb_others(cpu_mask, mm, va);
 
@@ -609,4 +656,3 @@ asmlinkage void smp_call_function_interr
 		atomic_inc(&call_data->finished);
 	}
 }
-
diff -uNrp linux-2.6.9/arch/i386/kernel/smpboot.c linux-2.6.9-ltt-r12/arch/i386/kernel/smpboot.c
--- linux-2.6.9/arch/i386/kernel/smpboot.c	2004-10-18 23:54:08.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/smpboot.c	2005-08-15 10:31:45.000000000 +0200
@@ -760,6 +760,11 @@ static int __init do_boot_cpu(int apicid
 	unsigned short nmi_high = 0, nmi_low = 0;
 
 	cpu = ++cpucount;
+
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_apicid_2_cpuid[apicid] = cpu;
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*
 	 * We can't use kernel_thread since we must avoid to
 	 * reschedule the child.
@@ -905,6 +910,10 @@ static void __init smp_boot_cpus(unsigne
 	int apicid, cpu, bit, kicked;
 	unsigned long bogosum = 0;
 
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_apicid_2_cpuid[adeos_smp_apic_id()] = 0;
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*
 	 * Setup boot CPU information
 	 */
diff -uNrp linux-2.6.9/arch/i386/kernel/sys_i386.c linux-2.6.9-ltt-r12/arch/i386/kernel/sys_i386.c
--- linux-2.6.9/arch/i386/kernel/sys_i386.c	2004-10-18 23:55:28.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/sys_i386.c	2005-08-15 10:51:46.000000000 +0200
@@ -19,6 +19,7 @@
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
+#include <linux/ltt-events.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -136,6 +137,8 @@ asmlinkage int sys_ipc (uint call, int f
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
+	ltt_ev_ipc(LTT_EV_IPC_CALL, call, first);
+
 	switch (call) {
 	case SEMOP:
 		return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
diff -uNrp linux-2.6.9/arch/i386/kernel/time.c linux-2.6.9-ltt-r12/arch/i386/kernel/time.c
--- linux-2.6.9/arch/i386/kernel/time.c	2004-10-18 23:54:08.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/time.c	2005-08-15 10:31:45.000000000 +0200
@@ -228,11 +228,12 @@ static inline void do_timer_interrupt(in
 		 * This will also deassert NMI lines for the watchdog if run
 		 * on an 82489DX-based system.
 		 */
-		spin_lock(&i8259A_lock);
+		unsigned long flags;
+		spin_lock_irqsave_hw_cond(&i8259A_lock,flags);
 		outb(0x0c, PIC_MASTER_OCW3);
 		/* Ack the IRQ; AEOI will end it automatically. */
 		inb(PIC_MASTER_POLL);
-		spin_unlock(&i8259A_lock);
+		spin_unlock_irqrestore_hw_cond(&i8259A_lock,flags);
 	}
 #endif
 
diff -uNrp linux-2.6.9/arch/i386/kernel/timers/timer_pit.c linux-2.6.9-ltt-r12/arch/i386/kernel/timers/timer_pit.c
--- linux-2.6.9/arch/i386/kernel/timers/timer_pit.c	2004-10-18 23:55:06.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/timers/timer_pit.c	2005-08-15 10:31:45.000000000 +0200
@@ -100,6 +100,10 @@ static unsigned long get_offset_pit(void
 	 */
 	unsigned long jiffies_t;
 
+#ifdef CONFIG_ADEOS_CORE
+	if (!__adeos_pipeline_head_p(adp_root))
+		return 0;	/* We don't really own the PIT. */
+#endif /* CONFIG_ADEOS_CORE */
 	spin_lock_irqsave(&i8253_lock, flags);
 	/* timer count may underflow right here */
 	outb_p(0x00, PIT_MODE);	/* latch the count ASAP */
diff -uNrp linux-2.6.9/arch/i386/kernel/timers/timer_tsc.c linux-2.6.9-ltt-r12/arch/i386/kernel/timers/timer_tsc.c
--- linux-2.6.9/arch/i386/kernel/timers/timer_tsc.c	2004-10-18 23:54:38.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/timers/timer_tsc.c	2005-08-15 10:31:45.000000000 +0200
@@ -349,6 +349,12 @@ static void mark_offset_tsc(void)
 	rdtsc(last_tsc_low, last_tsc_high);
 
 	spin_lock(&i8253_lock);
+#ifdef CONFIG_ADEOS_CORE
+	if (!__adeos_pipeline_head_p(adp_root)) {
+		count = 0;
+		goto noadj;	/* We don't really own the PIT. */
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	outb_p(0x00, PIT_MODE);     /* latch the count ASAP */
 
 	count = inb_p(PIT_CH0);    /* read the latched count */
@@ -365,6 +371,9 @@ static void mark_offset_tsc(void)
 		count = LATCH - 1;
 	}
 
+#ifdef CONFIG_ADEOS_CORE
+ noadj:
+#endif /* CONFIG_ADEOS_CORE */
 	spin_unlock(&i8253_lock);
 
 	if (pit_latch_buggy) {
@@ -420,9 +429,11 @@ static void mark_offset_tsc(void)
 	monotonic_base += cycles_2_ns(this_offset - last_offset);
 	write_sequnlock(&monotonic_lock);
 
+#ifndef CONFIG_ADEOS_CORE
 	/* calculate delay_at_last_interrupt */
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+#endif /* CONFIG_ADEOS_CORE */
 
 	/* catch corner case where tick rollover occured
 	 * between tsc and pit reads (as noted when
diff -uNrp linux-2.6.9/arch/i386/kernel/traps.c linux-2.6.9-ltt-r12/arch/i386/kernel/traps.c
--- linux-2.6.9/arch/i386/kernel/traps.c	2004-10-18 23:53:23.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/kernel/traps.c	2005-08-15 10:51:46.000000000 +0200
@@ -25,6 +25,7 @@
 #include <linux/highmem.h>
 #include <linux/kallsyms.h>
 #include <linux/ptrace.h>
+#include <linux/ltt-events.h>
 #include <linux/version.h>
 #include <linux/kprobes.h>
 
@@ -151,6 +152,13 @@ void show_trace(struct task_struct *task
 {
 	unsigned long ebp;
 
+#ifdef CONFIG_ADEOS_CORE
+	if (!task && adp_current != adp_root)
+	    {
+	    printk("Not executing in the root domain, no trace available\n");
+	    return;
+	    }
+#endif /* CONFIG_ADEOS_CORE */
 	if (!task)
 		task = current;
 
@@ -241,6 +249,11 @@ void show_registers(struct pt_regs *regs
 		regs->esi, regs->edi, regs->ebp, esp);
 	printk("ds: %04x   es: %04x   ss: %04x\n",
 		regs->xds & 0xffff, regs->xes & 0xffff, ss);
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_current != adp_root)
+	    printk("Adeos domain %s",adp_current->name);
+	else
+#endif /* CONFIG_ADEOS_CORE */
 	printk("Process %s (pid: %d, threadinfo=%p task=%p)",
 		current->comm, current->pid, current_thread_info(), current);
 	/*
@@ -308,6 +321,76 @@ bug:
 	printk("Kernel BUG\n");
 }
 
+/* Trace related code */
+#if (CONFIG_LTT)
+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;
+	ltt_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 (ltt_get_trace_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 */
+	ltt_log_event(LTT_EV_SYSCALL_ENTRY, &trace_syscall_event);
+}
+
+asmlinkage void trace_real_syscall_exit(void)
+{
+	ltt_log_event(LTT_EV_SYSCALL_EXIT, NULL);
+}
+#endif				/* (CONFIG_LTT) */
+
 void die(const char * str, struct pt_regs * regs, long err)
 {
 	static struct {
@@ -321,6 +404,11 @@ void die(const char * str, struct pt_reg
 	};
 	static int die_counter;
 
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_current != adp_root)
+	    adeos_set_printk_sync(adp_current);
+#endif /* CONFIG_ADEOS_CORE */
+
 	if (die.lock_owner != smp_processor_id()) {
 		console_verbose();
 		spin_lock_irq(&die.lock);
@@ -385,6 +473,8 @@ static inline unsigned long get_cr2(void
 static inline void do_trap(int trapnr, int signr, char *str, int vm86,
 			   struct pt_regs * regs, long error_code, siginfo_t *info)
 {
+        ltt_ev_trap_entry(trapnr, regs->eip);
+
 	if (regs->eflags & VM_MASK) {
 		if (vm86)
 			goto vm86_trap;
@@ -402,20 +492,24 @@ static inline void do_trap(int trapnr, i
 			force_sig_info(signr, info, tsk);
 		else
 			force_sig(signr, tsk);
+		ltt_ev_trap_exit();
 		return;
 	}
 
 	kernel_trap: {
 		if (!fixup_exception(regs))
 			die(str, regs, error_code);
+		ltt_ev_trap_exit();
 		return;
 	}
 
 	vm86_trap: {
 		int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr);
 		if (ret) goto trap_signal;
+		ltt_ev_trap_exit();
 		return;
 	}
+	ltt_ev_trap_exit();
 }
 
 #define DO_ERROR(trapnr, signr, str, name) \
@@ -517,12 +611,16 @@ asmlinkage void do_general_protection(st
 
 	current->thread.error_code = error_code;
 	current->thread.trap_no = 13;
+        ltt_ev_trap_entry(13, regs->eip);
 	force_sig(SIGSEGV, current);
+        ltt_ev_trap_exit();
 	return;
 
 gp_in_vm86:
 	local_irq_enable();
+        ltt_ev_trap_entry(13, regs->eip);
 	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+        ltt_ev_trap_exit();
 	return;
 
 gp_in_kernel:
@@ -579,6 +677,9 @@ static spinlock_t nmi_print_lock = SPIN_
 
 void die_nmi (struct pt_regs *regs, const char *msg)
 {
+#ifdef CONFIG_ADEOS_CORE
+	adeos_set_printk_sync(adp_current);
+#endif /* CONFIG_ADEOS_CORE */
 	spin_lock(&nmi_print_lock);
 	/*
 	* We are in trouble anyway, lets at least try
@@ -589,6 +690,9 @@ void die_nmi (struct pt_regs *regs, cons
 	printk(" on CPU%d, eip %08lx, registers:\n",
 		smp_processor_id(), regs->eip);
 	show_registers(regs);
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_dump_state();
+#endif /* CONFIG_ADEOS_CORE */
 	printk("console shuts up ...\n");
 	console_silent();
 	spin_unlock(&nmi_print_lock);
@@ -600,6 +704,12 @@ static void default_do_nmi(struct pt_reg
 {
 	unsigned char reason = get_nmi_reason();
  
+#ifndef CONFIG_X86_LOCAL_APIC
+/* On an machines with APIC enabled, NMIs are used to implement a watchdog
+and will hang the machine if traced. */
+	ltt_ev_trap_entry(2, regs->eip);
+#endif
+
 	if (!(reason & 0xc0)) {
 		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
 							== NOTIFY_STOP)
@@ -615,6 +725,9 @@ static void default_do_nmi(struct pt_reg
 		}
 #endif
 		unknown_nmi_error(reason, regs);
+#ifndef CONFIG_X86_LOCAL_APIC
+	        ltt_ev_trap_exit();
+#endif
 		return;
 	}
 	if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP)
@@ -628,6 +741,10 @@ static void default_do_nmi(struct pt_reg
 	 * as it's edge-triggered.
 	 */
 	reassert_nmi();
+
+#ifndef CONFIG_X86_LOCAL_APIC
+        ltt_ev_trap_exit();
+#endif
 }
 
 static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
@@ -641,6 +758,9 @@ asmlinkage void do_nmi(struct pt_regs * 
 {
 	int cpu;
 
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_current == adp_root)
+#endif /* CONFIG_ADEOS_CORE */
 	nmi_enter();
 
 	cpu = smp_processor_id();
@@ -649,6 +769,9 @@ asmlinkage void do_nmi(struct pt_regs * 
 	if (!nmi_callback(regs, cpu))
 		default_do_nmi(regs);
 
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_current == adp_root)
+#endif /* CONFIG_ADEOS_CORE */
 	nmi_exit();
 }
 
@@ -754,7 +877,9 @@ asmlinkage void do_debug(struct pt_regs 
 	 */
 	info.si_addr = ((regs->xcs & 3) == 0) ? (void __user *)tsk->thread.eip
 	                                      : (void __user *)regs->eip;
+        ltt_ev_trap_entry(1, regs->eip);
 	force_sig_info(SIGTRAP, &info, tsk);
+        ltt_ev_trap_exit();
 
 	/* Disable additional traps. They'll be re-enabled when
 	 * the signal is delivered.
@@ -766,7 +891,9 @@ clear_dr7:
 	return;
 
 debug_vm86:
+        ltt_ev_trap_entry(1, regs->eip);
 	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+        ltt_ev_trap_exit();
 	return;
 
 clear_TF_reenable:
@@ -918,10 +1045,12 @@ asmlinkage void do_simd_coprocessor_erro
 asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
 					  long error_code)
 {
+        ltt_ev_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
+        ltt_ev_trap_exit();	
 }
 
 /*
@@ -939,11 +1068,18 @@ asmlinkage void math_state_restore(struc
 	struct thread_info *thread = current_thread_info();
 	struct task_struct *tsk = thread->task;
 
+#ifdef CONFIG_ADEOS_CORE
+	unsigned long flags;
+	adeos_hw_local_irq_save(flags);
+#endif /* CONFIG_ADEOS_CORE */
 	clts();		/* Allow maths ops (or we recurse) */
 	if (!tsk->used_math)
 		init_fpu(tsk);
 	restore_fpu(tsk);
 	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_local_irq_restore(flags);
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 #ifndef CONFIG_MATH_EMULATION
@@ -952,8 +1088,10 @@ asmlinkage void math_emulate(long arg)
 {
 	printk("math-emulation not enabled and no coprocessor found.\n");
 	printk("killing %s.\n",current->comm);
+        ltt_ev_trap_entry(7, 0);
 	force_sig(SIGFPE,current);
 	schedule();
+        ltt_ev_trap_exit();
 }
 
 #endif /* CONFIG_MATH_EMULATION */
@@ -985,7 +1123,6 @@ do { \
 	 "3" ((char *) (addr)),"2" ((seg) << 16)); \
 } while (0)
 
-
 /*
  * This needs to use 'idt_table' rather than 'idt', and
  * thus use the _nonmapped_ version of the IDT, as the
diff -uNrp linux-2.6.9/arch/i386/mm/fault.c linux-2.6.9-ltt-r12/arch/i386/mm/fault.c
--- linux-2.6.9/arch/i386/mm/fault.c	2004-10-18 23:53:06.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/mm/fault.c	2005-08-15 10:51:46.000000000 +0200
@@ -21,6 +21,7 @@
 #include <linux/vt_kern.h>		/* For unblank_screen() */
 #include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/ltt-events.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -226,12 +227,16 @@ asmlinkage void do_page_fault(struct pt_
 	/* get the address */
 	__asm__("movl %%cr2,%0":"=r" (address));
 
+#ifdef CONFIG_ADEOS_CORE
+	adeos_hw_sti();
+#endif /* CONFIG_ADEOS_CORE */
+
 	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
 					SIGSEGV) == NOTIFY_STOP)
 		return;
 	/* It's safe to allow irq's after cr2 has been saved */
 	if (regs->eflags & (X86_EFLAGS_IF|VM_MASK))
-		local_irq_enable();
+	    local_irq_enable();
 
 	tsk = current;
 
@@ -269,6 +274,8 @@ asmlinkage void do_page_fault(struct pt_
 	if (in_atomic() || !mm)
 		goto bad_area_nosemaphore;
 
+	ltt_ev_trap_entry(14, regs->eip);
+
 	/* When running in the kernel we expect faults to occur only to
 	 * addresses in user space.  All other faults represent errors in the
 	 * kernel and should generate an OOPS.  Unfortunatly, in the case of an
@@ -366,6 +373,7 @@ good_area:
 			tsk->thread.screen_bitmap |= 1 << bit;
 	}
 	up_read(&mm->mmap_sem);
+        ltt_ev_trap_exit();
 	return;
 
 /*
@@ -408,6 +416,7 @@ bad_area_nosemaphore:
 
 		if (nr == 6) {
 			do_invalid_op(regs, 0);
+			ltt_ev_trap_exit();
 			return;
 		}
 	}
@@ -415,16 +424,20 @@ bad_area_nosemaphore:
 
 no_context:
 	/* Are we prepared to handle this kernel fault?  */
-	if (fixup_exception(regs))
+	if (fixup_exception(regs)) {
+		ltt_ev_trap_exit();
 		return;
+	}
 
 	/* 
 	 * Valid to do another page fault here, because if this fault
 	 * had been triggered by is_prefetch fixup_exception would have 
 	 * handled it.
 	 */
- 	if (is_prefetch(regs, address, error_code))
+ 	if (is_prefetch(regs, address, error_code)) {
+		ltt_ev_trap_exit();
  		return;
+	}
 
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
@@ -493,8 +506,10 @@ do_sigbus:
 		goto no_context;
 
 	/* User space => ok to do another page fault */
-	if (is_prefetch(regs, address, error_code))
+	if (is_prefetch(regs, address, error_code)) {
+		ltt_ev_trap_exit();
 		return;
+	}
 
 	tsk->thread.cr2 = address;
 	tsk->thread.error_code = error_code;
@@ -504,6 +519,7 @@ do_sigbus:
 	info.si_code = BUS_ADRERR;
 	info.si_addr = (void __user *)address;
 	force_sig_info(SIGBUS, &info, tsk);
+        ltt_ev_trap_exit();
 	return;
 
 vmalloc_fault:
@@ -542,6 +558,9 @@ vmalloc_fault:
 		pte_k = pte_offset_kernel(pmd_k, address);
 		if (!pte_present(*pte_k))
 			goto no_context;
+		ltt_ev_trap_entry(14, regs->eip);
+		ltt_ev_trap_exit();
 		return;
 	}
+	ltt_ev_trap_exit();
 }
diff -uNrp linux-2.6.9/arch/i386/mm/ioremap.c linux-2.6.9-ltt-r12/arch/i386/mm/ioremap.c
--- linux-2.6.9/arch/i386/mm/ioremap.c	2004-10-18 23:53:44.000000000 +0200
+++ linux-2.6.9-ltt-r12/arch/i386/mm/ioremap.c	2005-08-15 10:31:45.000000000 +0200
@@ -16,6 +16,9 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/pgtable.h>
+#ifdef CONFIG_ADEOS_CORE
+#include <asm/pgalloc.h>
+#endif /* CONFIG_ADEOS_CORE */
 
 static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
 	unsigned long phys_addr, unsigned long flags)
@@ -88,6 +91,9 @@ static int remap_area_pages(unsigned lon
 		if (remap_area_pmd(pmd, address, end - address,
 					 phys_addr + address, flags))
 			break;
+#ifdef CONFIG_ADEOS_CORE
+		set_pgdir(address, *dir);
+#endif /* CONFIG_ADEOS_CORE */
 		error = 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
diff -uNrp linux-2.6.9/fs/Kconfig linux-2.6.9-ltt-r12/fs/Kconfig
--- linux-2.6.9/fs/Kconfig	2004-10-18 23:54:32.000000000 +0200
+++ linux-2.6.9-ltt-r12/fs/Kconfig	2005-08-15 10:51:46.000000000 +0200
@@ -940,6 +940,57 @@ config RAMFS
 	  To compile this as a module, choose M here: the module will be called
 	  ramfs.
 
+config RELAYFS_FS
+	tristate "Relayfs file system support"
+	---help---
+	  Relayfs is a high-speed data relay filesystem designed to provide
+	  an efficient mechanism for tools and facilities to relay large
+	  amounts of data from kernel space to user space.  It's not useful
+	  on its own, and should only be enabled if other facilities that
+	  need it are enabled, such as for example klog or the Linux Trace
+	  Toolkit.
+
+	  See <file:Documentation/filesystems/relayfs.txt> for further
+	  information.
+
+	  This file system is also available as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module is called relayfs.  If you want to compile it as a
+	  module, say M here and read <file:Documentation/modules.txt>.
+
+	  If unsure, say N.
+
+config KLOG_CHANNEL
+	bool "Enable klog debugging support"
+	depends on RELAYFS_FS
+	default n
+	help
+	  If you say Y to this, a relayfs channel named klog will be created
+	  in the root of the relayfs file system.  You can write to the klog
+	  channel using klog() or klog_raw() from within the kernel or
+	  kernel modules, and read from the klog channel by mounting relayfs
+	  and using read(2) to read from it (or using cat).  If you're not  
+	  sure, say N.
+
+config KLOG_CHANNEL_AUTOENABLE
+	bool "Enable klog logging on startup"
+	depends on KLOG_CHANNEL
+	default y
+	help
+	  If you say Y to this, the klog channel will be automatically enabled
+	  on startup.  Otherwise, to turn klog logging on, you need use
+	  sysctl (fs.relayfs.klog_enabled).  This option is used in cases where
+	  you don't actually want the channel to be written to until it's
+	  enabled.  If you're not sure, say Y.
+
+config KLOG_CHANNEL_SHIFT
+	depends on KLOG_CHANNEL
+	int "klog debugging channel size (14 => 16KB, 22 => 4MB)"
+	range 14 22
+	default 21
+	help
+	  Select klog debugging channel size as a power of 2.
+
 endmenu
 
 menu "Miscellaneous filesystems"
@@ -1265,8 +1316,6 @@ config HPFS_FS
 	  To compile this file system support as a module, choose M here: the
 	  module will be called hpfs.  If unsure, say N.
 
-
-
 config QNX4FS_FS
 	tristate "QNX4 file system support (read only)"
 	help
@@ -1292,8 +1341,6 @@ config QNX4FS_RW
 	  It's currently broken, so for now:
 	  answer N.
 
-
-
 config SYSV_FS
 	tristate "System V/Xenix/V7/Coherent file system support"
 	help
@@ -1330,8 +1377,6 @@ config SYSV_FS
 
 	  If you haven't heard about all of this before, it's safe to say N.
 
-
-
 config UFS_FS
 	tristate "UFS file system support (read only)"
 	help
diff -uNrp linux-2.6.9/fs/Makefile linux-2.6.9-ltt-r12/fs/Makefile
--- linux-2.6.9/fs/Makefile	2004-10-18 23:54:32.000000000 +0200
+++ linux-2.6.9-ltt-r12/fs/Makefile	2005-08-15 10:51:46.000000000 +0200
@@ -52,6 +52,7 @@ obj-$(CONFIG_EXT2_FS)		+= ext2/
 obj-$(CONFIG_CRAMFS)		+= cramfs/
 obj-$(CONFIG_RAMFS)		+= ramfs/
 obj-$(CONFIG_HUGETLBFS)		+= hugetlbfs/
+obj-$(CONFIG_RELAYFS_FS)	+= relayfs/
 obj-$(CONFIG_CODA_FS)		+= coda/
 obj-$(CONFIG_MINIX_FS)		+= minix/
 obj-$(CONFIG_FAT_FS)		+= fat/
diff -uNrp linux-2.6.9/fs/buffer.c linux-2.6.9-ltt-r12/fs/buffer.c
--- linux-2.6.9/fs/buffer.c	2004-10-18 23:54:32.000000000 +0200
+++ linux-2.6.9-ltt-r12/fs/buffer.c	2005-08-15 10:51:46.000000000 +0200
@@ -37,6 +37,7 @@
 #include <linux/bio.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
+#include <linux/ltt-events.h>
 #include <asm/bitops.h>
 
 static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
@@ -157,12 +158,14 @@ void __wait_on_buffer(struct buffer_head
 	DEFINE_BH_WAIT(wait, bh);
 
 	do {
+		ltt_ev_file_system(LTT_EV_FILE_SYSTEM_BUF_WAIT_START, 0, 0, NULL);
 		prepare_to_wait(wqh, &wait.wait, TASK_UNINTERRUPTIBLE);
 		if (buffer_locked(bh)) {
 			sync_buffer(bh);
 			io_schedule();
 		}
 	} while (buffer_locked(bh));
+	ltt_ev_file_system(LTT_EV_FILE_SYSTEM_BUF_WAIT_END, 0, 0, NULL);
 	finish_wait(wqh, &wait.wait);
 }
 
diff -uNrp linux-2.6.9/fs/exec.c linux-2.6.9-ltt-r12/fs/exec.c
--- linux-2.6.9/fs/exec.c	2004-10-18 23:53:51.000000000 +0200
+++ linux-2.6.9-ltt-r12/fs/exec.c	2005-08-15 10:51:46.000000000 +0200
@@ -46,6 +46,7 @@
 #include <linux/security.h>
 #include <linux/syscalls.h>
 #include <linux/rmap.h>
+#include <linux/ltt-events.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1107,6 +1108,11 @@ int do_execve(char * filename,
 
 	sched_exec();
 
+	ltt_ev_file_system(LTT_EV_FILE_SYSTEM_EXEC,
+			   0,
+			   file->f_dentry->d_name.len,
+			   file->f_dentry->d_name.name);
+
 	retval = -ENOMEM;
 	bprm = kmalloc(sizeof(*bprm), GFP_KERNEL);
 	if (!bprm)
diff -uNrp linux-2.6.9/fs/ioctl.c linux-2.6.9-ltt-r12/fs/ioctl.c
--- linux-2.6.9/fs/ioctl.c	2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-ltt-r12/fs/ioctl.c	2005-08-15 10:51:46.000000000 +0200
@@ -10,6 +10,7 @@
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/security.h>
+#include <linux/ltt-events.h>
 #include <linux/module.h>
 
 #include <asm/uaccess.h>
@@ -67,6 +68,11 @@ asmlinkage long sys_ioctl(unsigned int f
                 goto out;
         }
 
+	ltt_ev_file_system(LTT_EV_FILE_SYSTEM_IOCTL,
+			   fd,
+			   cmd,
+			   NULL);
+
 	lock_kernel();
 	switch (cmd) {
 		case FIOCLEX:
diff -uNrp linux-2.6.9/fs/open.c linux-2.6.9-ltt-r12/fs/open.c
--- linux-2.6.9/fs/open.c	2004-10-18 23:53:08.000000000 +0200
+++ linux-2.6.9-ltt-r12/fs/open.c	2005-08-15 10:51:46.000000000 +0200
@@ -19,6 +19,8 @@
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
+#include <linux/ltt-events.h>
+
 #include <asm/uaccess.h>
 #include <linux/fs.h>
 #include <linux/pagemap.h>
@@ -955,6 +957,10 @@ asmlinkage long sys_open(const char __us
 			error = PTR_ERR(f);
 			if (IS_ERR(f))
 				goto out_error;
+			ltt_ev_file_system(LTT_EV_FILE_SYSTEM_OPEN,
+					   fd,
+					   f->f_dentry->d_name.len,
+					   f->f_dentry->d_name.name); 
 			fd_install(fd, f);
 		}
 out:
@@ -1030,6 +1036,10 @@ asmlinkage long sys_close(unsigned int f
 	filp = files->fd[fd];
 	if (!filp)
 		goto out_unlock;
+	ltt_ev_file_system(LTT_EV_FILE_SYSTEM_CLOSE,
+			   fd,
+			   0,
+			   NULL);
 	files->fd[fd] = NULL;
 	FD_CLR(fd, files->close_on_exec);
 	__put_unused_fd(files, fd);
diff -uNrp linux-2.6.9/fs/read_write.c linux-2.6.9-ltt-r12/fs/read_write.c
--- linux-2.6.9/fs/read_write.c	2004-10-18 23:54:37.000000000 +0200
+++ linux-2.6.9-ltt-r12/fs/read_write.c	2005-08-15 10:51:46.000000000 +0200
@@ -13,6 +13,7 @@
 #include <linux/dnotify.h>
 #include <linux/security.h>
 #include <linux/module.h>
+#include <linux/ltt-events.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -141,6 +142,12 @@ asmlinkage off_t sys_lseek(unsigned int 
 		if (res != (loff_t)retval)
 			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */
 	}
+
+	ltt_ev_file_system(LTT_EV_FILE_SYSTEM_SEEK,
+			   fd,
+			   offset,
+			   NULL);
+
 	fput_light(file, fput_needed);
 bad:
 	return retval;
@@ -169,6 +176,11 @@ asmlinkage long sys_llseek(unsigned int 
 	offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
 			origin);
 
+	ltt_ev_file_system(LTT_EV_FILE_SYSTEM_SEEK,
+			   fd,
+			   offset,
+			   NULL);
+
 	retval = (int)offset;
 	if (offset >= 0) {
 		retval = -EFAULT;
@@ -289,6 +301,10 @@ asmlinkage ssize_t sys_read(unsigned int
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		loff_t pos = file_pos_read(file);
+ 	 	ltt_ev_file_system(LTT_EV_FILE_SYSTEM_READ,
+ 				   fd,
+ 				   count,
+ 				   NULL); 
 		ret = vfs_read(file, buf, count, &pos);
 		file_pos_write(file, pos);
 		fput_light(file, fput_needed);
@@ -307,6 +323,10 @@ asmlinkage ssize_t sys_write(unsigned in
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		loff_t pos = file_pos_read(file);
+ 	        ltt_ev_file_system(LTT_EV_FILE_SYSTEM_WRITE,
+ 				   fd, 
+ 				   count,
+ 				   NULL);
 		ret = vfs_write(file, buf, count, &pos);
 		file_pos_write(file, pos);
 		fput_light(file, fput_needed);
@@ -328,8 +348,14 @@ asmlinkage ssize_t sys_pread64(unsigned 
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = -ESPIPE;
-		if (file->f_mode & FMODE_PREAD)
+		if (file->f_mode & FMODE_PREAD) {
+ 	 		ltt_ev_file_system(LTT_EV_FILE_SYSTEM_READ,
+ 					   fd,
+ 					   count,
+ 					   NULL);
 			ret = vfs_read(file, buf, count, &pos);
+		}
+
 		fput_light(file, fput_needed);
 	}
 
@@ -349,8 +375,13 @@ asmlinkage ssize_t sys_pwrite64(unsigned
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = -ESPIPE;
-		if (file->f_mode & FMODE_PWRITE)  
+		if (file->f_mode & FMODE_PWRITE) {
+ 			ltt_ev_file_system(LTT_EV_FILE_SYSTEM_WRITE,
+ 					   fd,
+ 					   count,
+ 					   NULL);
 			ret = vfs_write(file, buf, count, &pos);
+		}
 		fput_light(file, fput_needed);
 	}
 
@@ -535,6 +566,10 @@ sys_readv(unsigned long fd, const struct
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		loff_t pos = file_pos_read(file);
+ 		ltt_ev_file_system(LTT_EV_FILE_SYSTEM_READ,
+ 				   fd,
+ 				   vlen,
+ 				   NULL);
 		ret = vfs_readv(file, vec, vlen, &pos);
 		file_pos_write(file, pos);
 		fput_light(file, fput_needed);
@@ -553,6 +588,10 @@ sys_writev(unsigned long fd, const struc
 	file = fget_light(fd, &fput_needed);
 	if (file) {
 		loff_t pos = file_pos_read(file);
+	 	ltt_ev_file_system(LTT_EV_FILE_SYSTEM_WRITE,
+ 				   fd,
+ 				   vlen,
+ 				   NULL);
 		ret = vfs_writev(file, vec, vlen, &pos);
 		file_pos_write(file, pos);
 		fput_light(file, fput_needed);
diff -uNrp linux-2.6.9/fs/relayfs/Makefile linux-2.6.9-ltt-r12/fs/relayfs/Makefile
--- linux-2.6.9/fs/relayfs/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/Makefile	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,8 @@
+#
+# relayfs Makefile
+#
+
+obj-$(CONFIG_RELAYFS_FS) += relayfs.o
+
+relayfs-y := relay.o relay_lockless.o relay_locking.o inode.o resize.o
+relayfs-$(CONFIG_KLOG_CHANNEL) += klog.o
diff -uNrp linux-2.6.9/fs/relayfs/inode.c linux-2.6.9-ltt-r12/fs/relayfs/inode.c
--- linux-2.6.9/fs/relayfs/inode.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/inode.c	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,651 @@
+/*
+ * VFS-related code for RelayFS, a high-speed data relay filesystem.
+ *
+ * Copyright (C) 2003 - Tom Zanussi <zanussi@us.ibm.com>, IBM Corp
+ * Copyright (C) 2003 - Karim Yaghmour <karim@opersys.com>
+ *
+ * Based on ramfs, Copyright (C) 2002 - Linus Torvalds
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
+#include <linux/namei.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <asm/relay.h>
+
+#define RELAYFS_MAGIC			0x26F82121
+
+static struct super_operations		relayfs_ops;
+static struct address_space_operations	relayfs_aops;
+static struct inode_operations		relayfs_file_inode_operations;
+static struct file_operations		relayfs_file_operations;
+static struct inode_operations		relayfs_dir_inode_operations;
+
+static struct vfsmount *		relayfs_mount;
+static int				relayfs_mount_count;
+
+static struct backing_dev_info		relayfs_backing_dev_info = {
+	.ra_pages	= 0,	/* No readahead */
+	.memory_backed	= 1,	/* Does not contribute to dirty memory */
+};
+
+static struct inode *
+relayfs_get_inode(struct super_block *sb, int mode, dev_t dev)
+{
+	struct inode * inode;
+	
+	inode = new_inode(sb);
+
+	if (inode) {
+		inode->i_mode = mode;
+		inode->i_uid = current->fsuid;
+		inode->i_gid = current->fsgid;
+		inode->i_blksize = PAGE_CACHE_SIZE;
+		inode->i_blocks = 0;
+		inode->i_mapping->a_ops = &relayfs_aops;
+		inode->i_mapping->backing_dev_info = &relayfs_backing_dev_info;
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		switch (mode & S_IFMT) {
+		default:
+			init_special_inode(inode, mode, dev);
+			break;
+		case S_IFREG:
+			inode->i_op = &relayfs_file_inode_operations;
+			inode->i_fop = &relayfs_file_operations;
+			break;
+		case S_IFDIR:
+			inode->i_op = &relayfs_dir_inode_operations;
+			inode->i_fop = &simple_dir_operations;
+
+			/* directory inodes start off with i_nlink == 2 (for "." entry) */
+			inode->i_nlink++;
+			break;
+		case S_IFLNK:
+			inode->i_op = &page_symlink_inode_operations;
+			break;
+		}
+	}
+	return inode;
+}
+
+/*
+ * File creation. Allocate an inode, and we're done..
+ */
+/* SMP-safe */
+static int 
+relayfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+	struct inode * inode;
+	int error = -ENOSPC;
+
+	inode = relayfs_get_inode(dir->i_sb, mode, dev);
+
+	if (inode) {
+		d_instantiate(dentry, inode);
+		dget(dentry);	/* Extra count - pin the dentry in core */
+		error = 0;
+	}
+	return error;
+}
+
+static int 
+relayfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+	int retval;
+
+	retval = relayfs_mknod(dir, dentry, mode | S_IFDIR, 0);
+
+	if (!retval)
+		dir->i_nlink++;
+	return retval;
+}
+
+static int 
+relayfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+{
+	return relayfs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+static int 
+relayfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
+{
+	struct inode *inode;
+	int error = -ENOSPC;
+
+	inode = relayfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
+
+	if (inode) {
+		int l = strlen(symname)+1;
+		error = page_symlink(inode, symname, l);
+		if (!error) {
+			d_instantiate(dentry, inode);
+			dget(dentry);
+		} else
+			iput(inode);
+	}
+	return error;
+}
+
+/**
+ *	relayfs_create_entry - create a relayfs directory or file
+ *	@name: the name of the file to create
+ *	@parent: parent directory
+ *	@dentry: result dentry
+ *	@entry_type: type of file to create (S_IFREG, S_IFDIR)
+ *	@mode: mode
+ *	@data: data to associate with the file
+ *
+ *	Creates a file or directory with the specifed permissions.
+ */
+static int 
+relayfs_create_entry(const char * name, struct dentry * parent, struct dentry **dentry, int entry_type, int mode, void * data)
+{
+	struct qstr qname;
+	struct dentry * d;
+	
+	int error = 0;
+
+	error = simple_pin_fs("relayfs", &relayfs_mount, &relayfs_mount_count);
+	if (error) {
+		printk(KERN_ERR "Couldn't mount relayfs: errcode %d\n", error);
+		return error;
+	}
+
+	qname.name = name;
+	qname.len = strlen(name);
+	qname.hash = full_name_hash(name, qname.len);
+
+	if (parent == NULL)
+		if (relayfs_mount && relayfs_mount->mnt_sb)
+			parent = relayfs_mount->mnt_sb->s_root;
+
+	if (parent == NULL) {
+		simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+ 		return -EINVAL;
+	}
+
+	parent = dget(parent);
+	down(&parent->d_inode->i_sem);
+	d = lookup_hash(&qname, parent);
+	if (IS_ERR(d)) {
+		error = PTR_ERR(d);
+		goto release_mount;
+	}
+	
+	if (d->d_inode) {
+		error = -EEXIST;
+		goto release_mount;
+	}
+
+	if (entry_type == S_IFREG)
+		error = relayfs_create(parent->d_inode, d, entry_type | mode, NULL);
+	else
+		error = relayfs_mkdir(parent->d_inode, d, entry_type | mode);
+	if (error)
+		goto release_mount;
+
+	if ((entry_type == S_IFREG) && data) {
+		d->d_inode->u.generic_ip = data;
+		goto exit; /* don't release mount for regular files */
+	}
+
+release_mount:
+	simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+exit:	
+	*dentry = d;
+	up(&parent->d_inode->i_sem);
+	dput(parent);
+
+	return error;
+}
+
+/**
+ *	relayfs_create_file - create a file in the relay filesystem
+ *	@name: the name of the file to create
+ *	@parent: parent directory
+ *	@dentry: result dentry
+ *	@data: data to associate with the file
+ *	@mode: mode, if not specied the default perms are used
+ *
+ *	The file will be created user rw on behalf of current user.
+ */
+int 
+relayfs_create_file(const char * name, struct dentry * parent, struct dentry **dentry, void * data, int mode)
+{
+	if (!mode)
+		mode = S_IRUSR | S_IWUSR;
+	
+	return relayfs_create_entry(name, parent, dentry, S_IFREG,
+				    mode, data);
+}
+
+/**
+ *	relayfs_create_dir - create a directory in the relay filesystem
+ *	@name: the name of the directory to create
+ *	@parent: parent directory
+ *	@dentry: result dentry
+ *
+ *	The directory will be created world rwx on behalf of current user.
+ */
+int 
+relayfs_create_dir(const char * name, struct dentry * parent, struct dentry **dentry)
+{
+	return relayfs_create_entry(name, parent, dentry, S_IFDIR,
+				    S_IRWXU | S_IRUGO | S_IXUGO, NULL);
+}
+
+/**
+ *	relayfs_remove_file - remove a file in the relay filesystem
+ *	@dentry: file dentry
+ *
+ *	Remove a file previously created by relayfs_create_file.
+ */
+int 
+relayfs_remove_file(struct dentry *dentry)
+{
+	struct dentry *parent;
+	int is_reg;
+	
+	parent = dentry->d_parent;
+	if (parent == NULL)
+		return -EINVAL;
+
+	is_reg = S_ISREG(dentry->d_inode->i_mode);
+
+	parent = dget(parent);
+	down(&parent->d_inode->i_sem);
+	if (dentry->d_inode) {
+		simple_unlink(parent->d_inode, dentry);
+		d_delete(dentry);
+	}
+	dput(dentry);
+	up(&parent->d_inode->i_sem);
+	dput(parent);
+
+	if(is_reg)
+		simple_release_fs(&relayfs_mount, &relayfs_mount_count);
+
+	return 0;
+}
+
+/**
+ *	relayfs_open - open file op for relayfs files
+ *	@inode: the inode
+ *	@filp: the file
+ *
+ *	Associates the channel with the file, and increments the
+ *	channel refcount.  Reads will be 'auto-consuming'.
+ */
+int
+relayfs_open(struct inode *inode, struct file *filp)
+{
+	struct rchan *rchan;
+	struct rchan_reader *reader;
+	int retval = 0;
+
+	if (inode->u.generic_ip) {
+		rchan = (struct rchan *)inode->u.generic_ip;
+		if (rchan == NULL)
+			return -EACCES;
+		reader = __add_rchan_reader(rchan, filp, 1, 0);
+		if (reader == NULL)
+			return -ENOMEM;
+		filp->private_data = reader;
+		retval = rchan->callbacks->fileop_notify(rchan->id, filp,
+							 RELAY_FILE_OPEN);
+		if (retval == 0)
+			/* Inc relay channel refcount for file */
+			rchan_get(rchan->id);
+		else {
+			__remove_rchan_reader(reader);
+			retval = -EPERM;
+		}
+	}
+
+	return retval;
+}
+
+/**
+ *	relayfs_mmap - mmap file op for relayfs files
+ *	@filp: the file
+ *	@vma: the vma describing what to map
+ *
+ *	Calls upon relay_mmap_buffer to map the file into user space.
+ */
+int 
+relayfs_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct rchan *rchan;
+	
+	rchan = ((struct rchan_reader *)filp->private_data)->rchan;
+
+	return __relay_mmap_buffer(rchan, vma);
+}
+
+/**
+ *	relayfs_file_read - read file op for relayfs files
+ *	@filp: the file
+ *	@buf: user buf to read into
+ *	@count: bytes requested
+ *	@offset: offset into file
+ *
+ *	Reads count bytes from the channel, or as much as is available within
+ *	the sub-buffer currently being read.  Reads are 'auto-consuming'.
+ *	See relay_read() for details.
+ *
+ *	Returns bytes read on success, 0 or -EAGAIN if nothing available,
+ *	negative otherwise.
+ */
+ssize_t 
+relayfs_file_read(struct file *filp, char * buf, size_t count, loff_t *offset)
+{
+	size_t read_count;
+	struct rchan_reader *reader;
+	u32 dummy; /* all VFS readers are auto-consuming */
+
+	if (count == 0)
+		return 0;
+
+	reader = (struct rchan_reader *)filp->private_data;
+	read_count = relay_read(reader, buf, count,
+		filp->f_flags & (O_NDELAY | O_NONBLOCK) ? 0 : 1, &dummy, (u32 *)offset);
+
+	return read_count;
+}
+
+/**
+ *	relayfs_file_write - write file op for relayfs files
+ *	@filp: the file
+ *	@buf: user buf to write from
+ *	@count: bytes to write
+ *	@offset: offset into file
+ *
+ *	Reserves a slot in the relay buffer and writes count bytes
+ *	into it.  The current limit for a single write is 2 pages
+ *	worth.  The user_deliver() channel callback will be invoked on
+ *	
+ *	Returns bytes written on success, 0 or -EAGAIN if nothing available,
+ *	negative otherwise.
+ */
+ssize_t 
+relayfs_file_write(struct file *filp, const char *buf, size_t count, loff_t *offset)
+{
+	int write_count;
+	char * write_buf;
+	struct rchan *rchan;
+	int err = 0;
+	void *wrote_pos;
+	struct rchan_reader *reader;
+
+	reader = (struct rchan_reader *)filp->private_data;
+	if (reader == NULL)
+		return -EPERM;
+
+	rchan = reader->rchan;
+	if (rchan == NULL)
+		return -EPERM;
+
+	if (count == 0)
+		return 0;
+
+	/* Change this if need to write more than 2 pages at once */
+	if (count > 2 * PAGE_SIZE)
+		return -EINVAL;
+	
+	write_buf = (char *)__get_free_pages(GFP_KERNEL, 1);
+	if (write_buf == NULL)
+		return -ENOMEM;
+
+	if (copy_from_user(write_buf, buf, count))
+		return -EFAULT;
+
+	if (filp->f_flags & (O_NDELAY | O_NONBLOCK)) {
+		write_count = relay_write(rchan->id, write_buf, count, -1, &wrote_pos);
+		if (write_count == 0)
+			return -EAGAIN;
+	} else {
+		err = wait_event_interruptible(rchan->write_wait,
+	         (write_count = relay_write(rchan->id, write_buf, count, -1, &wrote_pos)));
+		if (err)
+			return err;
+	}
+	
+	free_pages((unsigned long)write_buf, 1);
+	
+        rchan->callbacks->user_deliver(rchan->id, wrote_pos, write_count);
+
+	*offset += write_count;
+	
+	return write_count;
+}
+
+/**
+ *	relayfs_ioctl - ioctl file op for relayfs files
+ *	@inode: the inode
+ *	@filp: the file
+ *	@cmd: the command
+ *	@arg: command arg
+ *
+ *	Passes the specified cmd/arg to the kernel client.  arg may be a 
+ *	pointer to user-space data, in which case the kernel client is 
+ *	responsible for copying the data to/from user space appropriately.
+ *	The kernel client is also responsible for returning a meaningful
+ *	return value for ioctl calls.
+ *	
+ *	Returns result of relay channel callback, -EPERM if unsuccessful.
+ */
+int
+relayfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct rchan *rchan;
+	struct rchan_reader *reader;
+
+	reader = (struct rchan_reader *)filp->private_data;
+	if (reader == NULL)
+		return -EPERM;
+
+	rchan = reader->rchan;
+	if (rchan == NULL)
+		return -EPERM;
+
+	return rchan->callbacks->ioctl(rchan->id, cmd, arg);
+}
+
+/**
+ *	relayfs_poll - poll file op for relayfs files
+ *	@filp: the file
+ *	@wait: poll table
+ *
+ *	Poll implemention.
+ */
+static unsigned int
+relayfs_poll(struct file *filp, poll_table *wait)
+{
+	struct rchan_reader *reader;
+	unsigned int mask = 0;
+	
+	reader = (struct rchan_reader *)filp->private_data;
+
+	if (reader->rchan->finalized)
+		return POLLERR;
+
+	if (filp->f_mode & FMODE_READ) {
+		poll_wait(filp, &reader->rchan->read_wait, wait);
+		if (!rchan_empty(reader))
+			mask |= POLLIN | POLLRDNORM;
+	}
+	
+	if (filp->f_mode & FMODE_WRITE) {
+		poll_wait(filp, &reader->rchan->write_wait, wait);
+		if (!rchan_full(reader))
+			mask |= POLLOUT | POLLWRNORM;
+	}
+	
+	return mask;
+}
+
+/**
+ *	relayfs_release - release file op for relayfs files
+ *	@inode: the inode
+ *	@filp: the file
+ *
+ *	Decrements the channel refcount, as the filesystem is
+ *	no longer using it.
+ */
+int
+relayfs_release(struct inode *inode, struct file *filp)
+{
+	struct rchan_reader *reader;
+	struct rchan *rchan;
+
+	reader = (struct rchan_reader *)filp->private_data;
+	if (reader == NULL || reader->rchan == NULL)
+		return 0;
+	rchan = reader->rchan;
+	
+        rchan->callbacks->fileop_notify(reader->rchan->id, filp,
+					RELAY_FILE_CLOSE);
+	__remove_rchan_reader(reader);
+	/* The channel is no longer in use as far as this file is concerned */
+	rchan_put(rchan);
+
+	return 0;
+}
+
+static struct address_space_operations relayfs_aops = {
+	.readpage	= simple_readpage,
+	.prepare_write	= simple_prepare_write,
+	.commit_write	= simple_commit_write
+};
+
+static struct file_operations relayfs_file_operations = {
+	.open		= relayfs_open,
+	.llseek		= no_llseek,
+	.read		= relayfs_file_read,
+	.write		= relayfs_file_write,
+	.ioctl		= relayfs_ioctl,
+	.poll		= relayfs_poll,
+	.mmap		= relayfs_mmap,
+	.fsync		= simple_sync_file,
+	.release	= relayfs_release,
+};
+
+static struct inode_operations relayfs_file_inode_operations = {
+	.getattr	= simple_getattr,
+};
+
+static struct inode_operations relayfs_dir_inode_operations = {
+	.create		= relayfs_create,
+	.lookup		= simple_lookup,
+	.link		= simple_link,
+	.unlink		= simple_unlink,
+	.symlink	= relayfs_symlink,
+	.mkdir		= relayfs_mkdir,
+	.rmdir		= simple_rmdir,
+	.mknod		= relayfs_mknod,
+	.rename		= simple_rename,
+};
+
+static struct super_operations relayfs_ops = {
+	.statfs		= simple_statfs,
+	.drop_inode	= generic_delete_inode,
+};
+
+static int 
+relayfs_fill_super(struct super_block * sb, void * data, int silent)
+{
+	struct inode * inode;
+	struct dentry * root;
+
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = RELAYFS_MAGIC;
+	sb->s_op = &relayfs_ops;
+	inode = relayfs_get_inode(sb, S_IFDIR | 0755, 0);
+
+	if (!inode)
+		return -ENOMEM;
+
+	root = d_alloc_root(inode);
+	if (!root) {
+		iput(inode);
+		return -ENOMEM;
+	}
+	sb->s_root = root;
+
+	return 0;
+}
+
+static struct super_block *
+relayfs_get_sb(struct file_system_type *fs_type,
+	int flags, const char *dev_name, void *data)
+{
+	return get_sb_single(fs_type, flags, data, relayfs_fill_super);
+}
+
+static struct file_system_type relayfs_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "relayfs",
+	.get_sb		= relayfs_get_sb,
+	.kill_sb	= kill_litter_super,
+};
+
+#ifdef CONFIG_ADEOS_CORE
+extern unsigned relay_wakeup_virq;
+void relay_wakeup_trampoline(unsigned virq);
+#endif /* CONFIG_ADEOS_CORE */
+
+static int __init 
+init_relayfs_fs(void)
+{
+	int err = register_filesystem(&relayfs_fs_type);
+#ifdef CONFIG_KLOG_CHANNEL
+	if (!err)
+		create_klog_channel();
+#endif
+#ifdef CONFIG_ADEOS_CORE
+	relay_wakeup_virq = adeos_alloc_irq();
+
+	if (!relay_wakeup_virq) {
+	    printk(KERN_ERR "relayfs: no virtual interrupt available.\n");
+	    err = -EBUSY;
+	}
+	else
+	    err = adeos_virtualize_irq(relay_wakeup_virq,
+				       &relay_wakeup_trampoline,
+				       NULL,
+				       IPIPE_HANDLE_MASK);
+#endif /* CONFIG_ADEOS_CORE */
+	return err;
+}
+
+static void __exit 
+exit_relayfs_fs(void)
+{
+#ifdef CONFIG_ADEOS_CORE
+    adeos_virtualize_irq(relay_wakeup_virq,NULL,NULL,0);
+    adeos_free_irq(relay_wakeup_virq);
+#endif /* CONFIG_ADEOS_CORE */
+#ifdef CONFIG_KLOG_CHANNEL
+	remove_klog_channel();
+#endif
+	unregister_filesystem(&relayfs_fs_type);
+}
+
+module_init(init_relayfs_fs)
+module_exit(exit_relayfs_fs)
+
+MODULE_AUTHOR("Tom Zanussi <zanussi@us.ibm.com> and Karim Yaghmour <karim@opersys.com>");
+MODULE_DESCRIPTION("Relay Filesystem");
+MODULE_LICENSE("GPL");
+
diff -uNrp linux-2.6.9/fs/relayfs/klog.c linux-2.6.9-ltt-r12/fs/relayfs/klog.c
--- linux-2.6.9/fs/relayfs/klog.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/klog.c	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,206 @@
+/*
+ * KLOG		Generic Logging facility built upon the relayfs infrastructure
+ *
+ * Authors:	Hubertus Franke  (frankeh@us.ibm.com)
+ *		Tom Zanussi  (zanussi@us.ibm.com)
+ *
+ *		Please direct all questions/comments to zanussi@us.ibm.com
+ *
+ *		Copyright (C) 2003, IBM Corp
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <linux/sysctl.h>
+#include <linux/relayfs_fs.h>
+#include <linux/klog.h>
+
+/* klog channel id */
+static int klog_channel = -1;
+
+/* maximum size of klog formatting buffer beyond which truncation will occur */
+#define KLOG_BUF_SIZE (512)
+/* per-cpu klog formatting buffer */
+static char buf[NR_CPUS][KLOG_BUF_SIZE];
+
+/*
+ *	klog_enabled determines whether klog()/klog_raw() actually do write
+ *	to the klog channel at any given time. If klog_enabled == 1 they do,
+ *	otherwise they don't.  Settable using sysctl fs.relayfs.klog_enabled.
+ */
+#ifdef CONFIG_KLOG_CHANNEL_AUTOENABLE
+static int klog_enabled = 1;
+#else
+static int klog_enabled = 0;
+#endif
+
+/**
+ *	klog - write a formatted string into the klog channel
+ *	@fmt: format string
+ *
+ *	Returns number of bytes written, negative number on failure.
+ */
+int klog(const char *fmt, ...)
+{
+	va_list args;
+	int len, err;
+	char *cbuf;
+	unsigned long flags;
+
+	if (!klog_enabled || klog_channel < 0) 
+		return 0;
+
+	local_irq_save(flags);
+	cbuf = buf[smp_processor_id()];
+
+	va_start(args, fmt);
+	len = vsnprintf(cbuf, KLOG_BUF_SIZE, fmt, args);
+	va_end(args);
+	
+	err = relay_write(klog_channel, cbuf, len, -1, NULL);
+	local_irq_restore(flags);
+
+	return err;
+}
+
+/**
+ *	klog_raw - directly write into the klog channel
+ *	@buf: buffer containing data to write
+ *	@len: # bytes to write
+ *
+ *	Returns number of bytes written, negative number on failure.
+ */
+int klog_raw(const char *buf,int len)
+{
+	int err = 0;
+	
+	if (klog_enabled && klog_channel >= 0)
+		err = relay_write(klog_channel, buf, len, -1, NULL);
+
+	return err;
+}
+
+/**
+ *	relayfs sysctl data
+ *
+ *	Only sys/fs/relayfs/klog_enabled for now.
+ */
+#define CTL_ENABLE_KLOG		100
+#define CTL_RELAYFS		100
+
+static struct ctl_table_header *relayfs_ctl_table_header;
+
+static struct ctl_table relayfs_table[] =
+{
+	{
+		.ctl_name	= CTL_ENABLE_KLOG,
+		.procname	= "klog_enabled",
+		.data		= &klog_enabled,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		0
+	}
+};
+
+static struct ctl_table relayfs_dir_table[] =
+{
+	{
+		.ctl_name	= CTL_RELAYFS,
+		.procname	= "relayfs",
+		.data		= NULL,
+		.maxlen		= 0,
+		.mode		= 0555,
+		.child		= relayfs_table,
+	},
+	{
+		0
+	}
+};
+
+static struct ctl_table relayfs_root_table[] =
+{
+	{
+		.ctl_name	= CTL_FS,
+		.procname	= "fs",
+		.data		= NULL,
+		.maxlen		= 0,
+		.mode		= 0555,
+		.child		= relayfs_dir_table,
+	},
+	{
+		0
+	}
+};
+
+/**
+ *	create_klog_channel - creates channel /mnt/relay/klog
+ *
+ *	Returns channel id on success, negative otherwise.
+ */
+int 
+create_klog_channel(void)
+{
+	u32 bufsize, nbufs;
+	u32 channel_flags;
+
+	channel_flags = RELAY_DELIVERY_PACKET | RELAY_USAGE_GLOBAL;
+	channel_flags |= RELAY_SCHEME_ANY | RELAY_TIMESTAMP_ANY;
+
+	bufsize = 1 << (CONFIG_KLOG_CHANNEL_SHIFT - 2);
+	nbufs = 4;
+
+	klog_channel = relay_open("klog",
+				  bufsize,
+				  nbufs,
+				  channel_flags,
+				  NULL,
+				  0,
+				  0,
+				  0,
+				  0,
+				  0,
+				  0,
+				  NULL,
+				  0);
+
+	if (klog_channel < 0)
+		printk("klog channel creation failed, errcode: %d\n", klog_channel);
+	else {
+		printk("klog channel created (%u bytes)\n", 1 << CONFIG_KLOG_CHANNEL_SHIFT);
+		relayfs_ctl_table_header = register_sysctl_table(relayfs_root_table, 1);
+	}
+
+	return klog_channel;
+}
+
+/**
+ *	remove_klog_channel - destroys channel /mnt/relay/klog
+ *
+ *	Returns 0, negative otherwise.
+ */
+int
+remove_klog_channel(void)
+{
+	if (relayfs_ctl_table_header)
+		unregister_sysctl_table(relayfs_ctl_table_header);
+	
+	return relay_close(klog_channel);
+}
+
+EXPORT_SYMBOL(klog);
+EXPORT_SYMBOL(klog_raw);
+
diff -uNrp linux-2.6.9/fs/relayfs/relay.c linux-2.6.9-ltt-r12/fs/relayfs/relay.c
--- linux-2.6.9/fs/relayfs/relay.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/relay.c	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,2014 @@
+/*
+ * Public API and common code for RelayFS.
+ *
+ * Please see Documentation/filesystems/relayfs.txt for API description.
+ * 
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/page-flags.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/relay.h>
+#include <asm/hardirq.h>
+
+#include "relay_lockless.h"
+#include "relay_locking.h"
+#include "resize.h"
+
+#ifdef CONFIG_ADEOS_CORE
+LIST_HEAD(relay_wakeup_queue);
+unsigned relay_wakeup_virq;
+spinlock_t relay_wakeup_spinlock = SPIN_LOCK_UNLOCKED;
+#endif /* CONFIG_ADEOS_CORE */
+
+/* Relay channel table, indexed by channel id */
+static struct rchan *	rchan_table[RELAY_MAX_CHANNELS];
+static rwlock_t		rchan_table_lock = RW_LOCK_UNLOCKED;
+
+/* Relay operation structs, one per scheme */
+static struct relay_ops lockless_ops = {
+	.reserve = lockless_reserve,
+	.commit = lockless_commit,
+	.get_offset = lockless_get_offset,
+	.finalize = lockless_finalize,
+	.reset = lockless_reset,
+	.reset_index = lockless_reset_index
+};
+
+static struct relay_ops locking_ops = {
+	.reserve = locking_reserve,
+	.commit = locking_commit,
+	.get_offset = locking_get_offset,
+	.finalize = locking_finalize,
+	.reset = locking_reset,
+	.reset_index = locking_reset_index
+};
+
+/*
+ * Low-level relayfs kernel API.  These functions should not normally be 
+ * used by clients.  See high-level kernel API below.
+ */
+
+/**
+ *	rchan_get - get channel associated with id, incrementing refcount 
+ *	@rchan_id: the channel id
+ *
+ *	Returns channel if successful, NULL otherwise.
+ */
+struct rchan *
+rchan_get(int rchan_id)
+{
+	struct rchan *rchan;
+	
+	if ((rchan_id < 0) || (rchan_id >= RELAY_MAX_CHANNELS))
+		return NULL;
+	
+	read_lock(&rchan_table_lock);
+	rchan = rchan_table[rchan_id];
+	if (rchan)
+		atomic_inc(&rchan->refcount);
+	read_unlock(&rchan_table_lock);
+
+	return rchan;
+}
+
+/**
+ *	clear_readers - clear non-VFS readers
+ *	@rchan: the channel
+ *
+ *	Clear the channel pointers of all non-VFS readers open on the channel.
+ */
+static inline void
+clear_readers(struct rchan *rchan)
+{
+	struct list_head *p;
+	struct rchan_reader *reader;
+	
+	read_lock(&rchan->open_readers_lock);
+	list_for_each(p, &rchan->open_readers) {
+		reader = list_entry(p, struct rchan_reader, list);
+		if (!reader->vfs_reader)
+			reader->rchan = NULL;
+	}
+	read_unlock(&rchan->open_readers_lock);
+}
+
+/**
+ *	rchan_alloc_id - reserve a channel id and store associated channel
+ *	@rchan: the channel
+ *
+ *	Returns channel id if successful, -1 otherwise.
+ */
+static inline int
+rchan_alloc_id(struct rchan *rchan)
+{
+	int i;
+	int rchan_id = -1;
+	
+	if (rchan == NULL)
+		return -1;
+
+	write_lock(&rchan_table_lock);
+	for (i = 0; i < RELAY_MAX_CHANNELS; i++) {
+		if (rchan_table[i] == NULL) {
+			rchan_table[i] = rchan;
+			rchan_id = rchan->id = i;
+			break;
+		}
+	}
+	if (rchan_id != -1)
+		atomic_inc(&rchan->refcount);
+	write_unlock(&rchan_table_lock);
+	
+	return rchan_id;
+}
+
+/**
+ *	rchan_free_id - revoke a channel id and remove associated channel
+ *	@rchan_id: the channel id
+ */
+static inline void
+rchan_free_id(int rchan_id)
+{
+	struct rchan *rchan;
+
+	if ((rchan_id < 0) || (rchan_id >= RELAY_MAX_CHANNELS))
+		return;
+
+	write_lock(&rchan_table_lock);
+	rchan = rchan_table[rchan_id];
+	rchan_table[rchan_id] = NULL;
+	write_unlock(&rchan_table_lock);
+}
+
+/**
+ *	rchan_destroy_buf - destroy the current channel buffer
+ *	@rchan: the channel
+ */
+static inline int
+rchan_destroy_buf(struct rchan *rchan)
+{
+	int err = 0;
+	
+	if (rchan->buf && !rchan->init_buf)
+		err = free_rchan_buf(rchan->buf,
+				     rchan->buf_page_array,
+				     rchan->buf_page_count);
+
+	return err;
+}
+
+/**
+ *     remove_rchan_file - remove the channel file
+ *     @private: pointer to the channel struct
+ *
+ *     Internal - manages the removal of old channel file
+ */
+static void
+remove_rchan_file(void *private)
+{
+	struct rchan *rchan = (struct rchan *)private;
+
+	relayfs_remove_file(rchan->dentry);
+}
+ 
+
+/**
+ *	relay_release - perform end-of-buffer processing for last buffer
+ *	@rchan: the channel
+ *
+ *	Returns 0 if successful, negative otherwise.
+ *
+ *	Releases the channel buffer, destroys the channel, and removes the
+ *	relay file from the relayfs filesystem.  Should only be called from 
+ *	rchan_put().  If we're here, it means by definition refcount is 0.
+ */
+static int 
+relay_release(struct rchan *rchan)
+{
+	int err = 0;
+	
+	if (rchan == NULL) {
+		err = -EBADF;
+		goto exit;
+	}
+
+	err = rchan_destroy_buf(rchan);
+	if (err)
+		goto exit;
+
+	rchan_free_id(rchan->id);
+
+	INIT_WORK(&rchan->work, remove_rchan_file, rchan);
+	schedule_delayed_work(&rchan->work, 1);
+
+	clear_readers(rchan);
+	kfree(rchan);
+exit:
+	return err;
+}
+
+/**
+ *	rchan_get - decrement channel refcount, releasing it if 0
+ *	@rchan: the channel
+ *
+ *	If the refcount reaches 0, the channel will be destroyed.
+ */
+void 
+rchan_put(struct rchan *rchan)
+{
+	if (atomic_dec_and_test(&rchan->refcount))
+		relay_release(rchan);
+}
+
+/**
+ *	relay_reserve -  reserve a slot in the channel buffer
+ *	@rchan: the channel
+ *	@len: the length of the slot to reserve
+ *	@td: the time delta between buffer start and current write, or TSC
+ *	@err: receives the result flags
+ *	@interrupting: 1 if interrupting previous, used only in locking scheme
+ *
+ *	Returns pointer to the beginning of the reserved slot, NULL if error.
+ *
+ *	The errcode value contains the result flags and is an ORed combination 
+ *	of the following:
+ *
+ *	RELAY_BUFFER_SWITCH_NONE - no buffer switch occurred
+ *	RELAY_EVENT_DISCARD_NONE - event should not be discarded
+ *	RELAY_BUFFER_SWITCH - buffer switch occurred
+ *	RELAY_EVENT_DISCARD - event should be discarded (all buffers are full)
+ *	RELAY_EVENT_TOO_LONG - event won't fit into even an empty buffer
+ *
+ *	buffer_start and buffer_end callbacks are triggered at this point
+ *	if applicable.
+ */
+char *
+relay_reserve(struct rchan *rchan,
+	      u32 len,
+	      struct timeval *ts,
+	      u32 *td,
+	      int *err,
+	      int *interrupting)
+{
+	if (rchan == NULL)
+		return NULL;
+	
+	*interrupting = 0;
+
+	return rchan->relay_ops->reserve(rchan, len, ts, td, err, interrupting);
+}
+
+
+/**
+ *	wakeup_readers - wake up VFS readers waiting on a channel
+ *	@private: the channel
+ *
+ *	This is the work function used to defer reader waking.  The
+ *	reason waking is deferred is that calling directly from commit
+ *	causes problems if you're writing from say the scheduler.
+ */
+static void 
+wakeup_readers(void *private)
+{
+	struct rchan *rchan = (struct rchan *)private;
+
+	wake_up_interruptible(&rchan->read_wait);
+}
+
+
+#ifdef CONFIG_ADEOS_CORE
+
+void relay_wakeup_trampoline (unsigned virq)
+{
+    struct list_head *pos, *npos;
+    unsigned long flags;
+
+    relay_spin_lock_irqsave(&relay_wakeup_spinlock,flags);
+
+    list_for_each_safe(pos,npos,&relay_wakeup_queue) {
+        struct rchan *rchan = list_entry(pos,struct rchan,wake_link);
+	list_del(&rchan->wake_link);
+	relay_spin_unlock_irqrestore(&relay_wakeup_spinlock,flags);
+	PREPARE_WORK(&rchan->wake_readers, wakeup_readers, rchan);
+	clear_bit(0,&rchan->wake_posted);
+	schedule_delayed_work(&rchan->wake_readers, 1);
+	relay_spin_lock_irqsave(&relay_wakeup_spinlock,flags);
+    }
+
+    relay_spin_unlock_irqrestore(&relay_wakeup_spinlock,flags);
+}
+
+#endif /* CONFIG_ADEOS_CORE */
+
+/**
+ *	relay_commit - commit a reserved slot in the buffer
+ *	@rchan: the channel
+ *	@from: commit the length starting here
+ *	@len: length committed
+ *	@interrupting: 1 if interrupting previous, used only in locking scheme
+ *
+ *      After the write into the reserved buffer has been complted, this
+ *      function must be called in order for the relay to determine whether 
+ *      buffers are complete and to wake up VFS readers.
+ *
+ *	delivery callback is triggered at this point if applicable.
+ */
+void
+relay_commit(struct rchan *rchan,
+	     char *from,
+	     u32 len,
+	     int reserve_code,
+	     int interrupting)
+{
+	int deliver;
+
+	if (rchan == NULL)
+		return;
+	
+	deliver = packet_delivery(rchan) || 
+		   (reserve_code & RELAY_BUFFER_SWITCH);
+
+	rchan->relay_ops->commit(rchan, from, len, deliver, interrupting);
+
+	/* The params are always the same, so no worry about re-queuing */
+	if (deliver && 	waitqueue_active(&rchan->read_wait)) {
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_current != adp_root) {
+	    if (!test_and_set_bit(0,&rchan->wake_posted)) {
+	        unsigned long flags;
+		relay_spin_lock_irqsave(&relay_wakeup_spinlock,flags);
+		list_add_tail(&rchan->wake_link,&relay_wakeup_queue);
+		relay_spin_unlock_irqrestore(&relay_wakeup_spinlock,flags);
+		adeos_propagate_irq(relay_wakeup_virq);
+	    }
+	    return;
+	}
+#endif /* CONFIG_ADEOS_CORE */
+		PREPARE_WORK(&rchan->wake_readers, wakeup_readers, rchan);
+		schedule_delayed_work(&rchan->wake_readers, 1);
+	}
+}
+
+/**
+ *	relay_get_offset - get current and max channel buffer offsets
+ *	@rchan: the channel
+ *	@max_offset: maximum channel offset
+ *
+ *	Returns the current and maximum channel buffer offsets.
+ */
+u32
+relay_get_offset(struct rchan *rchan, u32 *max_offset)
+{
+	return rchan->relay_ops->get_offset(rchan, max_offset);
+}
+
+/**
+ *	reset_index - try once to reset the current channel index
+ *	@rchan: the channel
+ *	@old_index: the index read before reset
+ *
+ *	Attempts to reset the channel index to 0.  It tries once, and
+ *	if it fails, returns negative, 0 otherwise.
+ */
+int
+reset_index(struct rchan *rchan, u32 old_index)
+{
+	return rchan->relay_ops->reset_index(rchan, old_index);
+}
+
+/*
+ * close() vm_op implementation for relayfs file mapping.
+ */
+static void
+relay_file_mmap_close(struct vm_area_struct *vma)
+{
+	struct file *filp = vma->vm_file;
+	struct rchan_reader *reader;
+	struct rchan *rchan;
+
+	reader = (struct rchan_reader *)filp->private_data;
+	rchan = reader->rchan;
+
+	atomic_dec(&rchan->mapped);
+
+	rchan->callbacks->fileop_notify(reader->rchan->id, filp,
+					RELAY_FILE_UNMAP);
+}
+
+/*
+ * vm_ops for relay file mappings.
+ */
+static struct vm_operations_struct relay_file_mmap_ops = {
+	.close = relay_file_mmap_close
+};
+
+/* \begin{Code inspired from BTTV driver} */
+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);
+	ret = __pa(kva);
+	return ret;
+}
+
+static int
+relay_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} */
+
+/**
+ *	relay_mmap_buffer: - mmap buffer to process address space
+ *	@rchan_id: relay channel id
+ *	@vma: vm_area_struct describing memory to be mapped
+ *
+ *	Returns:
+ *	0 if ok
+ *	-EAGAIN, when remap failed
+ *	-EINVAL, invalid requested length
+ *
+ *	Caller should already have grabbed mmap_sem.
+ */
+int 
+__relay_mmap_buffer(struct rchan *rchan,
+		    struct vm_area_struct *vma)
+{
+	int err = 0;
+	unsigned long length = vma->vm_end - vma->vm_start;
+	struct file *filp = vma->vm_file;
+
+	if (rchan == NULL) {
+		err = -EBADF;
+		goto exit;
+	}
+
+	if (rchan->init_buf) {
+		err = -EPERM;
+		goto exit;
+	}
+	
+	if (length != (unsigned long)rchan->alloc_size) {
+		err = -EINVAL;
+		goto exit;
+	}
+
+	err = relay_mmap_region(vma,
+				(char *)vma->vm_start,
+				rchan->buf,
+				rchan->alloc_size);
+
+	if (err == 0) {
+		vma->vm_ops = &relay_file_mmap_ops;
+		err = rchan->callbacks->fileop_notify(rchan->id, filp,
+						      RELAY_FILE_MAP);
+		if (err == 0)
+			atomic_inc(&rchan->mapped);
+	}
+exit:	
+	return err;
+}
+
+/*
+ * High-level relayfs kernel API.  See Documentation/filesystems/relafys.txt.
+ */
+
+/*
+ * rchan_callback implementations defining default channel behavior.  Used
+ * in place of corresponding NULL values in client callback struct.
+ */
+
+/*
+ * buffer_end() default callback.  Does nothing.
+ */
+static int 
+buffer_end_default_callback(int rchan_id,
+			    char *current_write_pos,
+			    char *end_of_buffer,
+			    struct timeval end_time,
+			    u32 end_tsc,
+			    int using_tsc) 
+{
+	return 0;
+}
+
+/*
+ * buffer_start() default callback.  Does nothing.
+ */
+static int 
+buffer_start_default_callback(int rchan_id,
+			      char *current_write_pos,
+			      u32 buffer_id,
+			      struct timeval start_time,
+			      u32 start_tsc,
+			      int using_tsc)
+{
+	return 0;
+}
+
+/*
+ * deliver() default callback.  Does nothing.
+ */
+static void 
+deliver_default_callback(int rchan_id, char *from, u32 len)
+{
+}
+
+/*
+ * user_deliver() default callback.  Does nothing.
+ */
+static void 
+user_deliver_default_callback(int rchan_id, char *from, u32 len)
+{
+}
+
+/*
+ * needs_resize() default callback.  Does nothing.
+ */
+static void
+needs_resize_default_callback(int rchan_id,
+			      int resize_type,
+			      u32 suggested_buf_size,
+			      u32 suggested_n_bufs)
+{
+}
+
+/*
+ * fileop_notify() default callback.  Does nothing.
+ */
+static int
+fileop_notify_default_callback(int rchan_id,
+			       struct file *filp,
+			       enum relay_fileop fileop)
+{
+	return 0;
+}
+
+/*
+ * ioctl() default callback.  Does nothing.
+ */
+static int
+ioctl_default_callback(int rchan_id,
+		       unsigned int cmd,
+		       unsigned long arg)
+{
+	return 0;
+}
+
+/* relay channel default callbacks */
+static struct rchan_callbacks default_channel_callbacks = {
+	.buffer_start = buffer_start_default_callback,
+	.buffer_end = buffer_end_default_callback,
+	.deliver = deliver_default_callback,
+	.user_deliver = user_deliver_default_callback,
+	.needs_resize = needs_resize_default_callback,
+	.fileop_notify = fileop_notify_default_callback,
+	.ioctl = ioctl_default_callback,
+};
+
+/**
+ *	check_attribute_flags - check sanity of channel attributes
+ *	@flags: channel attributes
+ *	@resizeable: 1 if true
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+static int
+check_attribute_flags(u32 *attribute_flags, int resizeable)
+{
+	u32 flags = *attribute_flags;
+	
+	if (!(flags & RELAY_DELIVERY_BULK) && !(flags & RELAY_DELIVERY_PACKET))
+		return -EINVAL; /* Delivery mode must be specified */
+	
+	if (!(flags & RELAY_USAGE_SMP) && !(flags & RELAY_USAGE_GLOBAL))
+		return -EINVAL; /* Usage must be specified */
+	
+	if (resizeable) {  /* Resizeable can never be continuous */
+		*attribute_flags &= ~RELAY_MODE_CONTINUOUS;
+		*attribute_flags |= RELAY_MODE_NO_OVERWRITE;
+	}
+	
+	if ((flags & RELAY_MODE_CONTINUOUS) &&
+	    (flags & RELAY_MODE_NO_OVERWRITE))
+		return -EINVAL; /* Can't have it both ways */
+	
+	if (!(flags & RELAY_MODE_CONTINUOUS) &&
+	    !(flags & RELAY_MODE_NO_OVERWRITE))
+		*attribute_flags |= RELAY_MODE_CONTINUOUS; /* Default to continuous */
+	
+	if (!(flags & RELAY_SCHEME_ANY))
+		return -EINVAL; /* One or both must be specified */
+	else if (flags & RELAY_SCHEME_LOCKLESS) {
+		if (have_cmpxchg())
+			*attribute_flags &= ~RELAY_SCHEME_LOCKING;
+		else if (flags & RELAY_SCHEME_LOCKING)
+			*attribute_flags &= ~RELAY_SCHEME_LOCKLESS;
+		else
+			return -EINVAL; /* Locking scheme not an alternative */
+	}
+	
+	if (!(flags & RELAY_TIMESTAMP_ANY))
+		return -EINVAL; /* One or both must be specified */
+	else if (flags & RELAY_TIMESTAMP_TSC) {
+		if (have_tsc())
+			*attribute_flags &= ~RELAY_TIMESTAMP_GETTIMEOFDAY;
+		else if (flags & RELAY_TIMESTAMP_GETTIMEOFDAY)
+			*attribute_flags &= ~RELAY_TIMESTAMP_TSC;
+		else
+			return -EINVAL; /* gettimeofday not an alternative */
+	}
+
+	return 0;
+}
+
+/*
+ * High-level API functions.
+ */
+
+/**
+ *	__relay_reset - internal reset function
+ *	@rchan: the channel
+ *	@init: 1 if this is a first-time channel initialization
+ *
+ *	See relay_reset for description of effect.
+ */
+void
+__relay_reset(struct rchan *rchan, int init)
+{
+	int i;
+	
+	if (init) {
+		rchan->version = RELAYFS_CHANNEL_VERSION;
+		init_MUTEX(&rchan->resize_sem);
+		init_waitqueue_head(&rchan->read_wait);
+		init_waitqueue_head(&rchan->write_wait);
+		atomic_set(&rchan->refcount, 0);
+		INIT_LIST_HEAD(&rchan->open_readers);
+		rchan->open_readers_lock = RW_LOCK_UNLOCKED;
+	}
+	
+	rchan->buf_id = rchan->buf_idx = 0;
+	atomic_set(&rchan->suspended, 0);
+	atomic_set(&rchan->mapped, 0);
+	rchan->half_switch = 0;
+	rchan->bufs_produced = 0;
+	rchan->bufs_consumed = 0;
+	rchan->bytes_consumed = 0;
+	rchan->read_start = 0;
+	rchan->initialized = 0;
+	rchan->finalized = 0;
+	rchan->resize_min = rchan->resize_max = 0;
+	rchan->resizing = 0;
+	rchan->replace_buffer = 0;
+	rchan->resize_buf = NULL;
+	rchan->resize_buf_size = 0;
+	rchan->resize_alloc_size = 0;
+	rchan->resize_n_bufs = 0;
+	rchan->resize_err = 0;
+	rchan->resize_failures = 0;
+	rchan->resize_order = 0;
+
+	rchan->expand_page_array = NULL;
+	rchan->expand_page_count = 0;
+	rchan->shrink_page_array = NULL;
+	rchan->shrink_page_count = 0;
+	rchan->resize_page_array = NULL;
+	rchan->resize_page_count = 0;
+	rchan->old_buf_page_array = NULL;
+	rchan->expand_buf_id = 0;
+
+	INIT_WORK(&rchan->wake_readers, NULL, NULL);
+	INIT_WORK(&rchan->wake_writers, NULL, NULL);
+
+	for (i = 0; i < RELAY_MAX_BUFS; i++)
+		rchan->unused_bytes[i] = 0;
+
+#ifdef CONFIG_ADEOS_CORE
+	INIT_LIST_HEAD(&rchan->wake_link);
+	rchan->wake_posted = 0;
+#endif /* CONFIG_ADEOS_CORE */
+	
+	rchan->relay_ops->reset(rchan, init);
+}
+
+/**
+ *	relay_reset - reset the channel
+ *	@rchan: the channel
+ *
+ *	Returns 0 if successful, negative if not.
+ *
+ *	This has the effect of erasing all data from the buffer and
+ *	restarting the channel in its initial state.  The buffer itself
+ *	is not freed, so any mappings are still in effect.
+ *
+ *	NOTE: Care should be taken that the channel isn't actually
+ *	being used by anything when this call is made.
+ */
+int
+relay_reset(int rchan_id)
+{
+	struct rchan *rchan;
+
+	rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return -EBADF;
+
+	__relay_reset(rchan, 0);
+	update_readers_consumed(rchan, 0, 0);
+
+	rchan_put(rchan);
+
+	return 0;
+}
+
+/**
+ *	check_init_buf - check the sanity of init_buf, if present
+ *	@init_buf: the initbuf
+ *	@init_buf_size: the total initbuf size
+ *	@bufsize: the channel's sub-buffer size
+ *	@nbufs: the number of sub-buffers in the channel
+ *
+ *	Returns 0 if ok, negative otherwise.
+ */
+static int
+check_init_buf(char *init_buf, u32 init_buf_size, u32 bufsize, u32 nbufs)
+{
+	int err = 0;
+	
+	if (init_buf && nbufs == 1) /* 1 sub-buffer makes no sense */
+		err = -EINVAL;
+
+	if (init_buf && (bufsize * nbufs != init_buf_size))
+		err = -EINVAL;
+
+	return err;
+}
+
+/**
+ *	rchan_create_buf - allocate the initial channel buffer
+ *	@rchan: the channel
+ *	@size_alloc: the total size of the channel buffer
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+static inline int
+rchan_create_buf(struct rchan *rchan, int size_alloc)
+{
+	struct page **page_array;
+	int page_count;
+
+	if ((rchan->buf = (char *)alloc_rchan_buf(size_alloc, &page_array, &page_count)) == NULL) {
+		rchan->buf_page_array = NULL;
+		rchan->buf_page_count = 0;
+		return -ENOMEM;
+	}
+
+	rchan->buf_page_array = page_array;
+	rchan->buf_page_count = page_count;
+
+	return 0;
+}
+
+/**
+ *	rchan_create - allocate and initialize a channel, including buffer
+ *	@chanpath: path specifying the relayfs channel file to create
+ *	@bufsize: the size of the sub-buffers within the channel buffer
+ *	@nbufs: the number of sub-buffers within the channel buffer
+ *	@rchan_flags: flags specifying buffer attributes
+ *	@err: err code
+ *
+ *	Returns channel if successful, NULL otherwise, err receives errcode.
+ *
+ *	Allocates a struct rchan representing a relay channel, according
+ *	to the attributes passed in via rchan_flags.  Does some basic sanity
+ *	checking but doesn't try to do anything smart.  In particular, the
+ *	number of buffers must be a power of 2, and if the lockless scheme
+ *	is being used, the sub-buffer size must also be a power of 2.  The
+ *	locking scheme can use buffers of any size.
+ */
+static struct rchan *
+rchan_create(const char *chanpath, 
+	     int bufsize, 
+	     int nbufs, 
+	     u32 rchan_flags,
+	     char *init_buf,
+	     u32 init_buf_size,
+	     int *err)
+{
+	int size_alloc;
+	struct rchan *rchan = NULL;
+
+	*err = 0;
+
+	rchan = (struct rchan *)kmalloc(sizeof(struct rchan), GFP_KERNEL);
+	if (rchan == NULL) {
+		*err = -ENOMEM;
+		return NULL;
+	}
+	rchan->buf = rchan->init_buf = NULL;
+
+	*err = check_init_buf(init_buf, init_buf_size, bufsize, nbufs);
+	if (*err)
+		goto exit;
+	
+	if (nbufs == 1 && bufsize) {
+		rchan->n_bufs = nbufs;
+		rchan->buf_size = bufsize;
+		size_alloc = bufsize;
+		goto alloc;
+	}
+	
+	if (bufsize <= 0 ||
+	    (rchan_flags & RELAY_SCHEME_LOCKLESS && hweight32(bufsize) != 1) ||
+	    hweight32(nbufs) != 1 ||
+	    nbufs < RELAY_MIN_BUFS ||
+	    nbufs > RELAY_MAX_BUFS) {
+		*err = -EINVAL;
+		goto exit;
+	}
+
+	size_alloc = FIX_SIZE(bufsize * nbufs);
+	if (size_alloc > RELAY_MAX_BUF_SIZE) {
+		*err = -EINVAL;
+		goto exit;
+	}
+	rchan->n_bufs = nbufs;
+	rchan->buf_size = bufsize;
+
+	if (rchan_flags & RELAY_SCHEME_LOCKLESS) {
+		offset_bits(rchan) = ffs(bufsize) - 1;
+		offset_mask(rchan) =  RELAY_BUF_OFFSET_MASK(offset_bits(rchan));
+		bufno_bits(rchan) = ffs(nbufs) - 1;
+	}
+alloc:
+	if (rchan_alloc_id(rchan) == -1) {
+		*err = -ENOMEM;
+		goto exit;
+	}
+
+	if (init_buf == NULL) {
+		*err = rchan_create_buf(rchan, size_alloc);
+		if (*err) {
+			rchan_free_id(rchan->id);
+			goto exit;
+		}
+	} else
+		rchan->buf = rchan->init_buf = init_buf;
+	
+	rchan->alloc_size = size_alloc;
+
+	if (rchan_flags & RELAY_SCHEME_LOCKLESS)
+		rchan->relay_ops = &lockless_ops;
+	else
+		rchan->relay_ops = &locking_ops;
+
+exit:
+	if (*err) {
+		kfree(rchan);
+		rchan = NULL;
+	}
+
+	return rchan;
+}
+
+
+static char tmpname[NAME_MAX];
+
+/**
+ *	rchan_create_dir - create directory for file
+ *	@chanpath: path to file, including filename
+ *	@residual: filename remaining after parse
+ *	@topdir: the directory filename should be created in
+ *
+ *	Returns 0 if successful, negative otherwise.
+ *
+ *	Inspired by xlate_proc_name() in procfs.  Given a file path which
+ *	includes the filename, creates any and all directories necessary 
+ *	to create the file.
+ */
+static int 
+rchan_create_dir(const char * chanpath, 
+		 const char **residual, 
+		 struct dentry **topdir)
+{
+	const char *cp = chanpath, *next;
+	struct dentry *parent = NULL;
+	int len, err = 0;
+	
+	while (1) {
+		next = strchr(cp, '/');
+		if (!next)
+			break;
+
+		len = next - cp;
+
+		strncpy(tmpname, cp, len);
+		tmpname[len] = '\0';
+		err = relayfs_create_dir(tmpname, parent, &parent);
+		if (err && (err != -EEXIST))
+			return err;
+		cp += len + 1;
+	}
+
+	*residual = cp;
+	*topdir = parent;
+
+	return err;
+}
+
+/**
+ *	rchan_create_file - create file, including parent directories
+ *	@chanpath: path to file, including filename
+ *	@dentry: result dentry
+ *	@data: data to associate with the file
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+static int 
+rchan_create_file(const char * chanpath, 
+		  struct dentry **dentry, 
+		  struct rchan * data,
+		  int mode)
+{
+	int err;
+	const char * fname;
+	struct dentry *topdir;
+
+	err = rchan_create_dir(chanpath, &fname, &topdir);
+	if (err && (err != -EEXIST))
+		return err;
+
+	err = relayfs_create_file(fname, topdir, dentry, (void *)data, mode);
+
+	return err;
+}
+
+/**
+ *	relay_open - create a new file/channel buffer in relayfs
+ *	@chanpath: name of file to create, including path
+ *	@bufsize: size of sub-buffers
+ *	@nbufs: number of sub-buffers
+ *	@flags: channel attributes
+ *	@callbacks: client callback functions
+ *	@start_reserve: number of bytes to reserve at start of each sub-buffer
+ *	@end_reserve: number of bytes to reserve at end of each sub-buffer
+ *	@rchan_start_reserve: additional reserve at start of first sub-buffer
+ *	@resize_min: minimum total buffer size, if set
+ *	@resize_max: maximum total buffer size, if set
+ *	@mode: the perms to be given to the relayfs file, 0 to accept defaults
+ *	@init_buf: initial memory buffer to start out with, NULL if N/A
+ *	@init_buf_size: initial memory buffer size to start out with, 0 if N/A
+ *
+ *	Returns channel id if successful, negative otherwise.
+ *
+ *	Creates a relay channel using the sizes and attributes specified.
+ *	The default permissions, used if mode == 0 are S_IRUSR | S_IWUSR.  See
+ *	Documentation/filesystems/relayfs.txt for details.
+ */
+int
+relay_open(const char *chanpath,
+	   int bufsize,
+	   int nbufs,
+	   u32 flags,
+	   struct rchan_callbacks *channel_callbacks,
+	   u32 start_reserve,
+	   u32 end_reserve,
+	   u32 rchan_start_reserve,
+	   u32 resize_min,
+	   u32 resize_max,
+	   int mode,
+	   char *init_buf,
+	   u32 init_buf_size)
+{
+	int err;
+	struct rchan *rchan;
+	struct dentry *dentry;
+	struct rchan_callbacks *callbacks = NULL;
+
+	if (chanpath == NULL)
+		return -EINVAL;
+
+	if (nbufs != 1) {
+		err = check_attribute_flags(&flags, resize_min ? 1 : 0);
+		if (err)
+			return err;
+	}
+
+	rchan = rchan_create(chanpath, bufsize, nbufs, flags, init_buf, init_buf_size, &err);
+
+	if (err < 0)
+		return err;
+
+	/* Create file in fs */
+	if ((err = rchan_create_file(chanpath, &dentry, rchan, mode)) < 0) {
+		rchan_destroy_buf(rchan);
+		rchan_free_id(rchan->id);
+		kfree(rchan);
+		return err;
+	}
+
+	rchan->dentry = dentry;
+
+	if (channel_callbacks == NULL)
+		callbacks = &default_channel_callbacks;
+	else
+		callbacks = channel_callbacks;
+
+	if (callbacks->buffer_end == NULL)
+		callbacks->buffer_end = buffer_end_default_callback;
+	if (callbacks->buffer_start == NULL)
+		callbacks->buffer_start = buffer_start_default_callback;
+	if (callbacks->deliver == NULL)
+		callbacks->deliver = deliver_default_callback;
+	if (callbacks->user_deliver == NULL)
+		callbacks->user_deliver = user_deliver_default_callback;
+	if (callbacks->needs_resize == NULL)
+		callbacks->needs_resize = needs_resize_default_callback;
+	if (callbacks->fileop_notify == NULL)
+		callbacks->fileop_notify = fileop_notify_default_callback;
+	if (callbacks->ioctl == NULL)
+		callbacks->ioctl = ioctl_default_callback;
+	rchan->callbacks = callbacks;
+
+	/* Just to let the client know the sizes used */
+	rchan->callbacks->needs_resize(rchan->id,
+				       RELAY_RESIZE_REPLACED,
+				       rchan->buf_size,
+				       rchan->n_bufs);
+
+	rchan->flags = flags;
+	rchan->start_reserve = start_reserve;
+	rchan->end_reserve = end_reserve;
+	rchan->rchan_start_reserve = rchan_start_reserve;
+
+	__relay_reset(rchan, 1);
+
+	if (resize_min > 0 && resize_max > 0 && 
+	   resize_max < RELAY_MAX_TOTAL_BUF_SIZE) {
+		rchan->resize_min = resize_min;
+		rchan->resize_max = resize_max;
+		init_shrink_timer(rchan);
+	}
+
+	rchan_get(rchan->id);
+
+	return rchan->id;
+}
+
+/**
+ *	relay_discard_init_buf - alloc channel buffer and copy init_buf into it
+ *	@rchan_id: the channel id
+ *
+ *	Returns 0 if successful, negative otherwise.
+ *
+ *	NOTE: May sleep.  Should also be called only when the channel isn't
+ *	actively being written into.
+ */
+int
+relay_discard_init_buf(int rchan_id)
+{
+	struct rchan *rchan;
+	int err = 0;
+	
+	rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return -EBADF;
+
+	if (rchan->init_buf == NULL) {
+		err = -EINVAL;
+		goto out;
+	}
+	
+	err = rchan_create_buf(rchan, rchan->alloc_size);
+	if (err)
+		goto out;
+	
+	memcpy(rchan->buf, rchan->init_buf, rchan->n_bufs * rchan->buf_size);
+	rchan->init_buf = NULL;
+out:
+	rchan_put(rchan);
+	
+	return err;
+}
+
+/**
+ *	relay_finalize - perform end-of-buffer processing for last buffer
+ *	@rchan_id: the channel id
+ *	@releasing: true if called when releasing file
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+static int 
+relay_finalize(int rchan_id)
+{
+	struct rchan *rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return -EBADF;
+
+	if (rchan->finalized == 0) {
+		rchan->relay_ops->finalize(rchan);
+		rchan->finalized = 1;
+	}
+
+	if (waitqueue_active(&rchan->read_wait)) {
+		PREPARE_WORK(&rchan->wake_readers, wakeup_readers, rchan);
+		schedule_delayed_work(&rchan->wake_readers, 1);
+	}
+
+	rchan_put(rchan);
+
+	return 0;
+}
+
+/**
+ *	restore_callbacks - restore default channel callbacks
+ *	@rchan: the channel
+ *
+ *	Restore callbacks to the default versions.
+ */
+static inline void
+restore_callbacks(struct rchan *rchan)
+{
+	if (rchan->callbacks != &default_channel_callbacks)
+		rchan->callbacks = &default_channel_callbacks;
+}
+
+/**
+ *	relay_close - close the channel
+ *	@rchan_id: relay channel id
+ *	
+ *	Finalizes the last sub-buffer and marks the channel as finalized.
+ *	The channel buffer and channel data structure are then freed
+ *	automatically when the last reference to the channel is given up.
+ */
+int 
+relay_close(int rchan_id)
+{
+	int err;
+	struct rchan *rchan;
+
+	if ((rchan_id < 0) || (rchan_id >= RELAY_MAX_CHANNELS))
+		return -EBADF;
+
+	err = relay_finalize(rchan_id);
+
+	if (!err) {
+		read_lock(&rchan_table_lock);
+		rchan = rchan_table[rchan_id];
+		read_unlock(&rchan_table_lock);
+
+		if (rchan) {
+			restore_callbacks(rchan);
+			if (rchan->resize_min)
+				del_timer(&rchan->shrink_timer);
+			rchan_put(rchan);
+		}
+	}
+	
+	return err;
+}
+
+/**
+ *	relay_write - reserve a slot in the channel and write data into it
+ *	@rchan_id: relay channel id
+ *	@data_ptr: data to be written into reserved slot
+ *	@count: number of bytes to write
+ *	@td_offset: optional offset where time delta should be written
+ *	@wrote_pos: optional ptr returning buf pos written to, ignored if NULL 
+ *
+ *	Returns the number of bytes written, 0 or negative on failure.
+ *
+ *	Reserves space in the channel and writes count bytes of data_ptr
+ *	to it.  Automatically performs any necessary locking, depending
+ *	on the scheme and SMP usage in effect (no locking is done for the
+ *	lockless scheme regardless of usage). 
+ *
+ *	If td_offset is >= 0, the internal time delta calculated when
+ *	slot was reserved will be written at that offset.
+ *
+ *	If wrote_pos is non-NULL, it will receive the location the data
+ *	was written to, which may be needed for some applications but is not
+ *	normally interesting.
+ */
+int
+relay_write(int rchan_id, 
+	    const void *data_ptr, 
+	    size_t count,
+	    int td_offset,
+	    void **wrote_pos)
+{
+	unsigned long flags;
+	char *reserved, *write_pos;
+	int bytes_written = 0;
+	int reserve_code, interrupting;
+	struct timeval ts;
+	u32 td;
+	struct rchan *rchan;
+	
+	rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return -EBADF;
+
+	relay_lock_channel(rchan, flags); /* nop for lockless */
+
+	write_pos = reserved = relay_reserve(rchan, count, &ts, &td, 
+					     &reserve_code, &interrupting);
+
+	if (reserved != NULL) {
+		relay_write_direct(write_pos, data_ptr, count);
+		if ((td_offset >= 0) && (td_offset < count - sizeof(td)))
+			*((u32 *)(reserved + td_offset)) = td;
+		bytes_written = count;
+	} else if (reserve_code == RELAY_WRITE_TOO_LONG)
+		bytes_written = -EINVAL;
+
+	if (bytes_written > 0)
+		relay_commit(rchan, reserved, bytes_written, reserve_code, interrupting);
+
+	relay_unlock_channel(rchan, flags); /* nop for lockless */
+
+	rchan_put(rchan);
+
+	if (wrote_pos)
+		*wrote_pos = reserved;
+	
+	return bytes_written;
+}
+
+/**
+ *	wakeup_writers - wake up VFS writers waiting on a channel
+ *	@private: the channel
+ *
+ *	This is the work function used to defer writer waking.  The
+ *	reason waking is deferred is that calling directly from 
+ *	buffers_consumed causes problems if you're writing from say 
+ *	the scheduler.
+ */
+static void 
+wakeup_writers(void *private)
+{
+	struct rchan *rchan = (struct rchan *)private;
+	
+	wake_up_interruptible(&rchan->write_wait);
+}
+
+
+/**
+ *	__relay_buffers_consumed - internal version of relay_buffers_consumed
+ *	@rchan: the relay channel
+ *	@bufs_consumed: number of buffers to add to current count for channel
+ *	
+ *	Internal - updates the channel's consumed buffer count.
+ */
+static void
+__relay_buffers_consumed(struct rchan *rchan, u32 bufs_consumed)
+{
+	rchan->bufs_consumed += bufs_consumed;
+	
+	if (rchan->bufs_consumed > rchan->bufs_produced)
+		rchan->bufs_consumed = rchan->bufs_produced;
+
+	if(atomic_read(&rchan->suspended)==1)
+	{
+	    int __i;
+	    for(__i = 1; __i < bufs_consumed+1 ; __i++)
+	    {
+		u8 offset_bits = offset_bits(rchan);
+		u32 start_reserve = rchan->start_reserve;
+		atomic_sub_volatile(&fill_count(rchan,(rchan->bufs_consumed-__i)%4),
+				    RELAY_BUF_SIZE(offset_bits) - start_reserve);
+		if (atomic_read(&fill_count(rchan,(rchan->bufs_consumed-__i)%4)) < start_reserve)
+		    atomic_set_volatile(&fill_count(rchan,(rchan->bufs_consumed-__i)%4), 
+					start_reserve);		
+	    }
+	}	
+	atomic_set(&rchan->suspended, 0);
+
+	PREPARE_WORK(&rchan->wake_writers, wakeup_writers, rchan);
+	schedule_delayed_work(&rchan->wake_writers, 1);
+}
+
+/**
+ *	__reader_buffers_consumed - update reader/channel consumed buffer count
+ *	@reader: channel reader
+ *	@bufs_consumed: number of buffers to add to current count for channel
+ *	
+ *	Internal - updates the reader's consumed buffer count.  If the reader's
+ *	resulting total is greater than the channel's, update the channel's.
+*/
+static void
+__reader_buffers_consumed(struct rchan_reader *reader, u32 bufs_consumed)
+{
+	reader->bufs_consumed += bufs_consumed;
+	
+	if (reader->bufs_consumed > reader->rchan->bufs_consumed)
+		__relay_buffers_consumed(reader->rchan, bufs_consumed);
+}
+
+/**
+ *	relay_buffers_consumed - add to the # buffers consumed for the channel
+ *	@reader: channel reader
+ *	@bufs_consumed: number of buffers to add to current count for channel
+ *	
+ *	Adds to the channel's consumed buffer count.  buffers_consumed should
+ *	be the number of buffers newly consumed, not the total number consumed.
+ *
+ *	NOTE: kernel clients don't need to call this function if the reader
+ *	is auto-consuming or the channel is MODE_CONTINUOUS.
+ */
+void 
+relay_buffers_consumed(struct rchan_reader *reader, u32 bufs_consumed)
+{
+	if (reader && reader->rchan)
+		__reader_buffers_consumed(reader, bufs_consumed);
+}
+
+/**
+ *	__relay_bytes_consumed - internal version of relay_bytes_consumed 
+ *	@rchan: the relay channel
+ *	@bytes_consumed: number of bytes to add to current count for channel
+ *	@read_offset: where the bytes were consumed from
+ *	
+ *	Internal - updates the channel's consumed count.
+*/
+static void
+__relay_bytes_consumed(struct rchan *rchan, u32 bytes_consumed, u32 read_offset)
+{
+	u32 consuming_idx;
+	u32 unused;
+
+	consuming_idx = read_offset / rchan->buf_size;
+
+	if (consuming_idx >= rchan->n_bufs)
+		consuming_idx = rchan->n_bufs - 1;
+	rchan->bytes_consumed += bytes_consumed;
+
+	unused = rchan->unused_bytes[consuming_idx];
+	
+	if (rchan->bytes_consumed + unused >= rchan->buf_size) {
+		__relay_buffers_consumed(rchan, 1);
+		rchan->bytes_consumed = 0;
+	}
+}
+
+/**
+ *	__reader_bytes_consumed - update reader/channel consumed count
+ *	@reader: channel reader
+ *	@bytes_consumed: number of bytes to add to current count for channel
+ *	@read_offset: where the bytes were consumed from
+ *	
+ *	Internal - updates the reader's consumed count.  If the reader's
+ *	resulting total is greater than the channel's, update the channel's.
+*/
+static void
+__reader_bytes_consumed(struct rchan_reader *reader, u32 bytes_consumed, u32 read_offset)
+{
+	u32 consuming_idx;
+	u32 unused;
+
+	consuming_idx = read_offset / reader->rchan->buf_size;
+
+	if (consuming_idx >= reader->rchan->n_bufs)
+		consuming_idx = reader->rchan->n_bufs - 1;
+
+	reader->bytes_consumed += bytes_consumed;
+	
+	unused = reader->rchan->unused_bytes[consuming_idx];
+	
+	if (reader->bytes_consumed + unused >= reader->rchan->buf_size) {
+		reader->bufs_consumed++;
+		reader->bytes_consumed = 0;
+	}
+
+	if ((reader->bufs_consumed > reader->rchan->bufs_consumed) ||
+	    ((reader->bufs_consumed == reader->rchan->bufs_consumed) &&
+	     (reader->bytes_consumed > reader->rchan->bytes_consumed)))
+		__relay_bytes_consumed(reader->rchan, bytes_consumed, read_offset);
+}
+
+/**
+ *	relay_bytes_consumed - add to the # bytes consumed for the channel
+ *	@reader: channel reader
+ *	@bytes_consumed: number of bytes to add to current count for channel
+ *	@read_offset: where the bytes were consumed from
+ *	
+ *	Adds to the channel's consumed count.  bytes_consumed should be the
+ *	number of bytes actually read e.g. return value of relay_read() and
+ *	the read_offset should be the actual offset the bytes were read from
+ *	e.g. the actual_read_offset set by relay_read(). See
+ *	Documentation/filesystems/relayfs.txt for more details.
+ *
+ *	NOTE: kernel clients don't need to call this function if the reader
+ *	is auto-consuming or the channel is MODE_CONTINUOUS.
+ */
+void
+relay_bytes_consumed(struct rchan_reader *reader, u32 bytes_consumed, u32 read_offset)
+{
+	if (reader && reader->rchan)
+		__reader_bytes_consumed(reader, bytes_consumed, read_offset);
+}
+
+/**
+ *	update_readers_consumed - apply offset change to reader
+ *	@rchan: the channel
+ *
+ *	Apply the consumed counts to all readers open on the channel.
+ */
+void
+update_readers_consumed(struct rchan *rchan, u32 bufs_consumed, u32 bytes_consumed)
+{
+	struct list_head *p;
+	struct rchan_reader *reader;
+	
+	read_lock(&rchan->open_readers_lock);
+	list_for_each(p, &rchan->open_readers) {
+		reader = list_entry(p, struct rchan_reader, list);
+		reader->bufs_consumed = bufs_consumed;
+		reader->bytes_consumed = bytes_consumed;
+		if (reader->vfs_reader)
+			reader->pos.file->f_pos = 0;
+		else
+			reader->pos.f_pos = 0;
+		reader->offset_changed = 1;
+	}
+	read_unlock(&rchan->open_readers_lock);
+	rchan->read_start = 0;
+}
+
+/**
+ *	do_read - utility function to do the actual read to user
+ *	@rchan: the channel
+ *	@buf: user buf to read into, NULL if just getting info
+ *	@count: bytes requested
+ *	@read_offset: offset into channel
+ *	@new_offset: new offset into channel after read
+ *	@actual_read_offset: read offset actually used
+ *
+ *	Returns the number of bytes read, 0 if none.
+ */
+static ssize_t
+do_read(struct rchan *rchan, char *buf, size_t count, u32 read_offset, u32 *new_offset, u32 *actual_read_offset)
+{
+	u32 read_bufno, cur_bufno;
+	u32 avail_offset, cur_idx, max_offset, buf_end_offset;
+	u32 avail_count, buf_size;
+	int unused_bytes = 0;
+	size_t read_count = 0;
+	u32 last_buf_byte_offset;
+
+	*actual_read_offset = read_offset;
+	
+	buf_size = rchan->buf_size;
+	if (unlikely(!buf_size)) BUG();
+
+	read_bufno = read_offset / buf_size;
+	if (unlikely(read_bufno >= RELAY_MAX_BUFS)) BUG();
+	unused_bytes = rchan->unused_bytes[read_bufno];
+
+	avail_offset = cur_idx = relay_get_offset(rchan, &max_offset);
+
+	if (cur_idx == read_offset) {
+		if (atomic_read(&rchan->suspended) == 1) {
+			read_offset += 1;
+			if (read_offset >= max_offset)
+				read_offset = 0;
+			*actual_read_offset = read_offset;
+		} else {
+			*new_offset = read_offset;
+			return 0;
+		}
+	} else {
+		last_buf_byte_offset = (read_bufno + 1) * buf_size - 1;
+		if (read_offset == last_buf_byte_offset) {
+			if (unused_bytes != 1) {
+				read_offset += 1;
+				if (read_offset >= max_offset)
+					read_offset = 0;
+				*actual_read_offset = read_offset;
+			}
+		}
+	}
+
+	read_bufno = read_offset / buf_size;
+	if (unlikely(read_bufno >= RELAY_MAX_BUFS)) BUG();
+	unused_bytes = rchan->unused_bytes[read_bufno];
+
+	cur_bufno = cur_idx / buf_size;
+
+	buf_end_offset = (read_bufno + 1) * buf_size - unused_bytes;
+	if (avail_offset > buf_end_offset)
+		avail_offset = buf_end_offset;
+	else if (avail_offset < read_offset)
+		avail_offset = buf_end_offset;
+	avail_count = avail_offset - read_offset;
+	read_count = avail_count >= count ? count : avail_count;
+
+	if (read_count && buf != NULL)
+		if (copy_to_user(buf, rchan->buf + read_offset, read_count))
+			return -EFAULT;
+
+	if (read_bufno == cur_bufno)
+		if (read_count && (read_offset + read_count >= buf_end_offset) && (read_offset + read_count <= cur_idx)) {
+			*new_offset = cur_idx;
+			return read_count;
+		}
+
+	if (read_offset + read_count + unused_bytes > max_offset)
+		*new_offset = 0;
+	else if (read_offset + read_count >= buf_end_offset)
+		*new_offset = read_offset + read_count + unused_bytes;
+	else
+		*new_offset = read_offset + read_count;
+
+	return read_count;
+}
+
+/**
+ *	__relay_read - read bytes from channel, relative to current reader pos
+ *	@reader: channel reader
+ *	@buf: user buf to read into, NULL if just getting info
+ *	@count: bytes requested
+ *	@read_offset: offset into channel
+ *	@new_offset: new offset into channel after read
+ *	@actual_read_offset: read offset actually used
+ *	@wait: if non-zero, wait for something to read
+ *
+ *	Internal - see relay_read() for details.
+ *
+ *	Returns the number of bytes read, 0 if none, negative on failure.
+ */
+static ssize_t
+__relay_read(struct rchan_reader *reader, char *buf, size_t count, u32 read_offset, u32 *new_offset, u32 *actual_read_offset, int wait)
+{
+	int err = 0;
+	size_t read_count = 0;
+	struct rchan *rchan = reader->rchan;
+
+	if (!wait && !rchan->initialized)
+		return -EAGAIN;
+
+	if (using_lockless(rchan))
+		read_offset &= idx_mask(rchan);
+
+	if (read_offset >= rchan->n_bufs * rchan->buf_size) {
+		*new_offset = 0;
+		if (!wait)
+			return -EAGAIN;
+		else
+			return -EINTR;
+	}
+	
+	if (buf != NULL && wait) {
+		err = wait_event_interruptible(rchan->read_wait,
+		       ((rchan->finalized == 1) ||
+			(atomic_read(&rchan->suspended) == 1) ||
+			(relay_get_offset(rchan, NULL) != read_offset)));
+
+		if (rchan->finalized)
+			return 0;
+
+		if (reader->offset_changed) {
+			reader->offset_changed = 0;
+			return -EINTR;
+		}
+		
+		if (err)
+			return err;
+	}
+
+	read_count = do_read(rchan, buf, count, read_offset, new_offset, actual_read_offset);
+
+	if (read_count < 0)
+		err = read_count;
+	
+	if (err)
+		return err;
+	else
+		return read_count;
+}
+
+/**
+ *	relay_read - read bytes from channel, relative to current reader pos
+ *	@reader: channel reader
+ *	@buf: user buf to read into, NULL if just getting info
+ *	@count: bytes requested
+ *	@wait: if non-zero, wait for something to read
+ *	@actual_read_offset: set read offset actually used, must not be NULL
+ *
+ *	Reads count bytes from the channel, or as much as is available within
+ *	the sub-buffer currently being read.  The read offset that will be
+ *	read from is the position contained within the reader object.  If the
+ *	wait flag is set, buf is non-NULL, and there is nothing available,
+ *	it will wait until there is.  If the wait flag is 0 and there is
+ *	nothing available, -EAGAIN is returned.  If buf is NULL, the value
+ *	returned is the number of bytes that would have been read.
+ *	actual_read_offset is the value that should be passed as the read
+ *	offset to relay_bytes_consumed, needed only if the reader is not
+ *	auto-consuming and the channel is MODE_NO_OVERWRITE, but in any case,
+ *	it must not be NULL.  See Documentation/filesystems/relayfs.txt for
+ *	more details.
+ */
+ssize_t
+relay_read(struct rchan_reader *reader, char *buf, size_t count, int wait, u32 *actual_read_offset, u32 *new_offset)
+{
+	u32 read_offset;
+	ssize_t read_count;
+	
+	if (reader == NULL || reader->rchan == NULL)
+		return -EBADF;
+
+	if (actual_read_offset == NULL)
+		return -EINVAL;
+
+	if (reader->vfs_reader)
+		read_offset = (u32)(reader->pos.file->f_pos);
+	else
+		read_offset = reader->pos.f_pos;
+	*actual_read_offset = read_offset;
+	
+	read_count = __relay_read(reader, buf, count, read_offset,
+				  new_offset, actual_read_offset, wait);
+
+	if (read_count < 0)
+		return read_count;
+
+	if (reader->vfs_reader) {
+		down(&reader->rchan->resize_sem);
+		if (!(reader->rchan->flags & RELAY_MODE_START_AT_ZERO))
+			reader->rchan->read_start = *new_offset;
+		up(&reader->rchan->resize_sem);
+	} else
+		reader->pos.f_pos = *new_offset;
+
+	if (reader->auto_consume && ((read_count) || (*new_offset != read_offset)))
+		__reader_bytes_consumed(reader, read_count, *actual_read_offset);
+
+	if (read_count == 0 && !wait)
+		return -EAGAIN;
+	
+	return read_count;
+}
+
+/**
+ *	relay_bytes_avail - number of bytes available in current sub-buffer
+ *	@reader: channel reader
+ *	
+ *	Returns the number of bytes available relative to the reader's
+ *	current read position within the corresponding sub-buffer, 0 if
+ *	there is nothing available.  See Documentation/filesystems/relayfs.txt
+ *	for more details.
+ */
+ssize_t
+relay_bytes_avail(struct rchan_reader *reader)
+{
+	u32 f_pos;
+	u32 new_offset;
+	u32 actual_read_offset;
+	ssize_t bytes_read;
+	
+	if (reader == NULL || reader->rchan == NULL)
+		return -EBADF;
+	
+	if (reader->vfs_reader)
+		f_pos = (u32)reader->pos.file->f_pos;
+	else
+		f_pos = reader->pos.f_pos;
+	new_offset = f_pos;
+
+	bytes_read = __relay_read(reader, NULL, reader->rchan->buf_size,
+				  f_pos, &new_offset, &actual_read_offset, 0);
+
+	if ((new_offset != f_pos) &&
+	    ((bytes_read == -EINTR) || (bytes_read == 0)))
+		bytes_read = -EAGAIN;
+	else if ((bytes_read < 0) && (bytes_read != -EAGAIN))
+		bytes_read = 0;
+
+	return bytes_read;
+}
+
+/**
+ *	rchan_empty - boolean, is the channel empty wrt reader?
+ *	@reader: channel reader
+ *	
+ *	Returns 1 if the channel is empty, 0 otherwise.
+ */
+int
+rchan_empty(struct rchan_reader *reader)
+{
+	ssize_t avail_count;
+	u32 buffers_ready;
+	struct rchan *rchan = reader->rchan;
+	u32 cur_idx, curbuf_bytes;
+	int mapped;
+
+	if (atomic_read(&rchan->suspended) == 1)
+		return 0;
+
+	mapped = atomic_read(&rchan->mapped);
+	
+	if (mapped && bulk_delivery(rchan)) {
+		buffers_ready = rchan->bufs_produced - rchan->bufs_consumed;
+		return buffers_ready ? 0 : 1;
+	}
+
+	if (mapped && packet_delivery(rchan)) {
+		buffers_ready = rchan->bufs_produced - rchan->bufs_consumed;
+		if (buffers_ready)
+			return 0;
+		else {
+			cur_idx = relay_get_offset(rchan, NULL);
+			curbuf_bytes = cur_idx % rchan->buf_size;
+			return curbuf_bytes == rchan->bytes_consumed ? 1 : 0;
+		}
+	}
+
+	avail_count = relay_bytes_avail(reader);
+
+	return avail_count ? 0 : 1;
+}
+
+/**
+ *	rchan_full - boolean, is the channel full wrt consuming reader?
+ *	@reader: channel reader
+ *	
+ *	Returns 1 if the channel is full, 0 otherwise.
+ */
+int
+rchan_full(struct rchan_reader *reader)
+{
+	u32 buffers_ready;
+	struct rchan *rchan = reader->rchan;
+
+	if (mode_continuous(rchan))
+		return 0;
+
+	buffers_ready = rchan->bufs_produced - rchan->bufs_consumed;
+
+	return buffers_ready > reader->rchan->n_bufs - 1 ? 1 : 0;
+}
+
+/**
+ *	relay_info - get status and other information about a relay channel
+ *	@rchan_id: relay channel id
+ *	@rchan_info: pointer to the rchan_info struct to be filled in
+ *	
+ *	Fills in an rchan_info struct with channel status and attribute 
+ *	information.  See Documentation/filesystems/relayfs.txt for details.
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+int 
+relay_info(int rchan_id, struct rchan_info *rchan_info)
+{
+	int i;
+	struct rchan *rchan;
+
+	rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return -EBADF;
+
+	rchan_info->flags = rchan->flags;
+	rchan_info->buf_size = rchan->buf_size;
+	rchan_info->buf_addr = rchan->buf;
+	rchan_info->alloc_size = rchan->alloc_size;
+	rchan_info->n_bufs = rchan->n_bufs;
+	rchan_info->cur_idx = relay_get_offset(rchan, NULL);
+	rchan_info->bufs_produced = rchan->bufs_produced;
+	rchan_info->bufs_consumed = rchan->bufs_consumed;
+	rchan_info->buf_id = rchan->buf_id;
+
+	for (i = 0; i < rchan->n_bufs; i++) {
+		rchan_info->unused_bytes[i] = rchan->unused_bytes[i];
+		if (using_lockless(rchan))
+			rchan_info->buffer_complete[i] = (atomic_read(&fill_count(rchan, i)) == rchan->buf_size);
+		else
+			rchan_info->buffer_complete[i] = 0;
+	}
+
+	rchan_put(rchan);
+
+	return 0;
+}
+
+/**
+ *	__add_rchan_reader - creates and adds a reader to a channel
+ *	@rchan: relay channel
+ *	@filp: the file associated with rchan, if applicable
+ *	@auto_consume: boolean, whether reader's reads automatically consume
+ *	@map_reader: boolean, whether reader's reading via a channel mapping
+ *
+ *	Returns a pointer to the reader object create, NULL if unsuccessful
+ *
+ *	Creates and initializes an rchan_reader object for reading the channel.
+ *	If filp is non-NULL, the reader is a VFS reader, otherwise not.
+ *
+ *	If the reader is a map reader, it isn't considered a VFS reader for
+ *	our purposes.  Also, map_readers can't be auto-consuming.
+ */
+struct rchan_reader *
+__add_rchan_reader(struct rchan *rchan, struct file *filp, int auto_consume, int map_reader)
+{
+	struct rchan_reader *reader;
+	u32 will_read;
+	
+	reader = kmalloc(sizeof(struct rchan_reader), GFP_KERNEL);
+
+	if (reader) {
+		reader->rchan = rchan;
+		if (filp) {
+			reader->vfs_reader = 1;
+			down(&rchan->resize_sem);
+			filp->f_pos = rchan->read_start;
+			up(&rchan->resize_sem);
+			reader->pos.file = filp;
+		} else {
+			reader->vfs_reader = 0;
+			reader->pos.f_pos = 0;
+		}
+		reader->map_reader = map_reader;
+		reader->auto_consume = auto_consume;
+
+		if (!map_reader) {
+			will_read = rchan->bufs_produced % rchan->n_bufs;
+			if (!will_read && atomic_read(&rchan->suspended))
+				will_read = rchan->n_bufs;
+			reader->bufs_consumed = rchan->bufs_produced - will_read;
+			rchan->bufs_consumed = reader->bufs_consumed;
+			rchan->bytes_consumed = reader->bytes_consumed = 0;
+			reader->offset_changed = 0;
+		}
+		
+		write_lock(&rchan->open_readers_lock);
+		list_add(&reader->list, &rchan->open_readers);
+		write_unlock(&rchan->open_readers_lock);
+	}
+
+	return reader;
+}
+
+/**
+ *	add_rchan_reader - create a reader for a channel
+ *	@rchan_id: relay channel handle
+ *	@auto_consume: boolean, whether reader's reads automatically consume
+ *
+ *	Returns a pointer to the reader object created, NULL if unsuccessful
+ *
+ *	Creates and initializes an rchan_reader object for reading the channel.
+ *	This function is useful only for non-VFS readers.
+ */
+struct rchan_reader *
+add_rchan_reader(int rchan_id, int auto_consume)
+{
+	struct rchan *rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return NULL;
+
+	return __add_rchan_reader(rchan, NULL, auto_consume, 0);
+}
+
+/**
+ *	add_map_reader - create a map reader for a channel
+ *	@rchan_id: relay channel handle
+ *
+ *	Returns a pointer to the reader object created, NULL if unsuccessful
+ *
+ *	Creates and initializes an rchan_reader object for reading the channel.
+ *	This function is useful only for map readers.
+ */
+struct rchan_reader *
+add_map_reader(int rchan_id)
+{
+	struct rchan *rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return NULL;
+
+	return __add_rchan_reader(rchan, NULL, 0, 1);
+}
+
+/**
+ *	__remove_rchan_reader - destroy a channel reader
+ *	@reader: channel reader
+ *
+ *	Internal - removes reader from the open readers list, and frees it.
+ */
+void
+__remove_rchan_reader(struct rchan_reader *reader)
+{
+	struct list_head *p;
+	struct rchan_reader *found_reader = NULL;
+	
+	write_lock(&reader->rchan->open_readers_lock);
+	list_for_each(p, &reader->rchan->open_readers) {
+		found_reader = list_entry(p, struct rchan_reader, list);
+		if (found_reader == reader) {
+			list_del(&found_reader->list);
+			break;
+		}
+	}
+	write_unlock(&reader->rchan->open_readers_lock);
+
+	if (found_reader)
+		kfree(found_reader);
+}
+
+/**
+ *	remove_rchan_reader - destroy a channel reader
+ *	@reader: channel reader
+ *
+ *	Finds and removes the given reader from the channel.  This function
+ *	is useful only for non-VFS readers.
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+int 
+remove_rchan_reader(struct rchan_reader *reader)
+{
+	int err = 0;
+	
+	if (reader) {
+		rchan_put(reader->rchan);
+		__remove_rchan_reader(reader);
+	} else
+		err = -EINVAL;
+
+	return err;
+}
+
+/**
+ *	remove_map_reader - destroy a map reader
+ *	@reader: channel reader
+ *
+ *	Finds and removes the given map reader from the channel.  This function
+ *	is useful only for map readers.
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+int 
+remove_map_reader(struct rchan_reader *reader)
+{
+	return remove_rchan_reader(reader);
+}
+
+EXPORT_SYMBOL(relay_open);
+EXPORT_SYMBOL(relay_close);
+EXPORT_SYMBOL(relay_reset);
+EXPORT_SYMBOL(relay_reserve);
+EXPORT_SYMBOL(relay_commit);
+EXPORT_SYMBOL(relay_read);
+EXPORT_SYMBOL(relay_write);
+EXPORT_SYMBOL(relay_bytes_avail);
+EXPORT_SYMBOL(relay_buffers_consumed);
+EXPORT_SYMBOL(relay_bytes_consumed);
+EXPORT_SYMBOL(relay_info);
+EXPORT_SYMBOL(relay_discard_init_buf);
+EXPORT_SYMBOL(add_rchan_reader);
+EXPORT_SYMBOL(remove_rchan_reader);
+EXPORT_SYMBOL(add_map_reader);
+EXPORT_SYMBOL(remove_map_reader);
+EXPORT_SYMBOL(rchan_empty);
+EXPORT_SYMBOL(rchan_full);
+
+
diff -uNrp linux-2.6.9/fs/relayfs/relay_locking.c linux-2.6.9-ltt-r12/fs/relayfs/relay_locking.c
--- linux-2.6.9/fs/relayfs/relay_locking.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/relay_locking.c	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,322 @@
+/*
+ * RelayFS locking scheme implementation.
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ *
+ * This file is released under the GPL.
+ */
+
+#include <asm/relay.h>
+#include "relay_locking.h"
+#include "resize.h"
+
+/**
+ *	switch_buffers - switches between read and write buffers.
+ *	@cur_time: current time.
+ *	@cur_tsc: the TSC associated with current_time, if applicable
+ *	@rchan: the channel
+ *	@finalizing: if true, don't start a new buffer 
+ *	@resetting: if true, 
+ *
+ *	This should be called from with interrupts disabled.
+ */
+static void 
+switch_buffers(struct timeval cur_time,
+	       u32 cur_tsc,
+	       struct rchan *rchan,
+	       int finalizing,
+	       int resetting,
+	       int finalize_buffer_only)
+{
+	char *chan_buf_end;
+	int bytes_written;
+
+	if (!rchan->half_switch) {
+		bytes_written = rchan->callbacks->buffer_end(rchan->id,
+			     cur_write_pos(rchan), write_buf_end(rchan),
+			     cur_time, cur_tsc, using_tsc(rchan));
+		if (bytes_written == 0)
+			rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = 
+				write_buf_end(rchan) - cur_write_pos(rchan);
+	}
+
+	if (finalize_buffer_only) {
+		rchan->bufs_produced++;
+		return;
+	}
+	
+	chan_buf_end = rchan->buf + rchan->n_bufs * rchan->buf_size;
+	if((write_buf(rchan) + rchan->buf_size >= chan_buf_end) || resetting)
+		write_buf(rchan) = rchan->buf;
+	else
+		write_buf(rchan) += rchan->buf_size;
+	write_buf_end(rchan) = write_buf(rchan) + rchan->buf_size;
+	write_limit(rchan) = write_buf_end(rchan) - rchan->end_reserve;
+	cur_write_pos(rchan) = write_buf(rchan);
+
+	rchan->buf_start_time = cur_time;
+	rchan->buf_start_tsc = cur_tsc;
+
+	if (resetting)
+		rchan->buf_idx = 0;
+	else
+		rchan->buf_idx++;
+	rchan->buf_id++;
+
+	if (!packet_delivery(rchan))
+		rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = 0;
+
+	if (resetting) {
+		rchan->bufs_produced = rchan->bufs_produced + rchan->n_bufs;
+		rchan->bufs_produced -= rchan->bufs_produced % rchan->n_bufs;
+		rchan->bufs_consumed = rchan->bufs_produced;
+		rchan->bytes_consumed = 0;
+		update_readers_consumed(rchan, rchan->bufs_consumed, rchan->bytes_consumed);
+	} else if (!rchan->half_switch)
+		rchan->bufs_produced++;
+
+	rchan->half_switch = 0;
+	
+	if (!finalizing) {
+		bytes_written = rchan->callbacks->buffer_start(rchan->id, cur_write_pos(rchan), rchan->buf_id, cur_time, cur_tsc, using_tsc(rchan));
+		cur_write_pos(rchan) += bytes_written;
+	}
+}
+
+/**
+ *	locking_reserve - reserve a slot in the buffer for an event.
+ *	@rchan: the channel
+ *	@slot_len: the length of the slot to reserve
+ *	@ts: variable that will receive the time the slot was reserved
+ *	@tsc: the timestamp counter associated with time
+ *	@err: receives the result flags
+ *	@interrupting: if this write is interrupting another, set to non-zero 
+ *
+ *	Returns pointer to the beginning of the reserved slot, NULL if error.
+ *
+ *	The err value contains the result flags and is an ORed combination 
+ *	of the following:
+ *
+ *	RELAY_BUFFER_SWITCH_NONE - no buffer switch occurred
+ *	RELAY_EVENT_DISCARD_NONE - event should not be discarded
+ *	RELAY_BUFFER_SWITCH - buffer switch occurred
+ *	RELAY_EVENT_DISCARD - event should be discarded (all buffers are full)
+ *	RELAY_EVENT_TOO_LONG - event won't fit into even an empty buffer
+ */
+inline char *
+locking_reserve(struct rchan *rchan,
+		u32 slot_len,
+		struct timeval *ts,
+		u32 *tsc,
+		int *err,
+		int *interrupting)
+{
+	u32 buffers_ready;
+	int bytes_written;
+
+	*err = RELAY_BUFFER_SWITCH_NONE;
+
+	if (slot_len >= rchan->buf_size) {
+		*err = RELAY_WRITE_DISCARD | RELAY_WRITE_TOO_LONG;
+		return NULL;
+	}
+
+	if (rchan->initialized == 0) {
+		rchan->initialized = 1;
+		get_timestamp(&rchan->buf_start_time, 
+			      &rchan->buf_start_tsc, rchan);
+		rchan->unused_bytes[0] = 0;
+		bytes_written = rchan->callbacks->buffer_start(
+			rchan->id, cur_write_pos(rchan), 
+			rchan->buf_id, rchan->buf_start_time, 
+			rchan->buf_start_tsc, using_tsc(rchan));
+		cur_write_pos(rchan) += bytes_written;
+		*tsc = get_time_delta(ts, rchan);
+		return cur_write_pos(rchan);
+	}
+
+	*tsc = get_time_delta(ts, rchan);
+
+	if (in_progress_event_size(rchan)) {
+		interrupted_pos(rchan) = cur_write_pos(rchan);
+		cur_write_pos(rchan) = in_progress_event_pos(rchan) 
+			+ in_progress_event_size(rchan) 
+			+ interrupting_size(rchan);
+		*interrupting = 1;
+	} else {
+		in_progress_event_pos(rchan) = cur_write_pos(rchan);
+		in_progress_event_size(rchan) = slot_len;
+		interrupting_size(rchan) = 0;
+	}
+
+	if (cur_write_pos(rchan) + slot_len > write_limit(rchan)) {
+		if (atomic_read(&rchan->suspended) == 1) {
+			in_progress_event_pos(rchan) = NULL;
+			in_progress_event_size(rchan) = 0;
+			interrupting_size(rchan) = 0;
+			*err = RELAY_WRITE_DISCARD;
+			return NULL;
+		}
+
+		buffers_ready = rchan->bufs_produced - rchan->bufs_consumed;
+		if (buffers_ready == rchan->n_bufs - 1) {
+			if (!mode_continuous(rchan)) {
+				atomic_set(&rchan->suspended, 1);
+				in_progress_event_pos(rchan) = NULL;
+				in_progress_event_size(rchan) = 0;
+				interrupting_size(rchan) = 0;
+				get_timestamp(ts, tsc, rchan);
+				switch_buffers(*ts, *tsc, rchan, 0, 0, 1);
+				recalc_time_delta(ts, tsc, rchan);
+				rchan->half_switch = 1;
+
+				cur_write_pos(rchan) = write_buf_end(rchan) - 1;
+				*err = RELAY_BUFFER_SWITCH | RELAY_WRITE_DISCARD;
+				return NULL;
+			}
+		}
+
+		get_timestamp(ts, tsc, rchan);
+		switch_buffers(*ts, *tsc, rchan, 0, 0, 0);
+		recalc_time_delta(ts, tsc, rchan);
+		*err = RELAY_BUFFER_SWITCH;
+	}
+
+	return cur_write_pos(rchan);
+}
+
+/**
+ *	locking_commit - commit a reserved slot in the buffer
+ *	@rchan: the channel
+ *	@from: commit the length starting here
+ *	@len: length committed
+ *	@deliver: length committed
+ *	@interrupting: not used
+ *
+ *      Commits len bytes and calls deliver callback if applicable.
+ */
+inline void
+locking_commit(struct rchan *rchan,
+	       char *from,
+	       u32 len, 
+	       int deliver, 
+	       int interrupting)
+{
+	cur_write_pos(rchan) += len;
+	
+	if (interrupting) {
+		cur_write_pos(rchan) = interrupted_pos(rchan);
+		interrupting_size(rchan) += len;
+	} else {
+		in_progress_event_size(rchan) = 0;
+		if (interrupting_size(rchan)) {
+			cur_write_pos(rchan) += interrupting_size(rchan);
+			interrupting_size(rchan) = 0;
+		}
+	}
+
+	if (deliver) {
+		if (bulk_delivery(rchan)) {
+			u32 cur_idx = cur_write_pos(rchan) - rchan->buf;
+			u32 cur_bufno = cur_idx / rchan->buf_size;
+			from = rchan->buf + cur_bufno * rchan->buf_size;
+			len = cur_idx - cur_bufno * rchan->buf_size;
+		}
+		rchan->callbacks->deliver(rchan->id, from, len);
+		expand_check(rchan);
+	}
+}
+
+/**
+ *	locking_finalize: - finalize last buffer at end of channel use
+ *	@rchan: the channel
+ */
+inline void 
+locking_finalize(struct rchan *rchan)
+{
+	unsigned long int flags;
+	struct timeval time;
+	u32 tsc;
+
+	relay_irq_save(flags);
+	get_timestamp(&time, &tsc, rchan);
+	switch_buffers(time, tsc, rchan, 1, 0, 0);
+	relay_irq_restore(flags);
+}
+
+/**
+ *	locking_get_offset - get current and max 'file' offsets for VFS
+ *	@rchan: the channel
+ *	@max_offset: maximum channel offset
+ *
+ *	Returns the current and maximum buffer offsets in VFS terms.
+ */
+u32
+locking_get_offset(struct rchan *rchan,
+		   u32 *max_offset)
+{
+	if (max_offset)
+		*max_offset = rchan->buf_size * rchan->n_bufs - 1;
+
+	return cur_write_pos(rchan) - rchan->buf;
+}
+
+/**
+ *	locking_reset - reset the channel
+ *	@rchan: the channel
+ *	@init: 1 if this is a first-time channel initialization
+ */
+void locking_reset(struct rchan *rchan, int init)
+{
+	if (init)
+		channel_lock(rchan) = SPIN_LOCK_UNLOCKED;
+	write_buf(rchan) = rchan->buf;
+	write_buf_end(rchan) = write_buf(rchan) + rchan->buf_size;
+	cur_write_pos(rchan) = write_buf(rchan);
+	write_limit(rchan) = write_buf_end(rchan) - rchan->end_reserve;
+	in_progress_event_pos(rchan) = NULL;
+	in_progress_event_size(rchan) = 0;
+	interrupted_pos(rchan) = NULL;
+	interrupting_size(rchan) = 0;
+}
+
+/**
+ *	locking_reset_index - atomically set channel index to the beginning
+ *	@rchan: the channel
+ *
+ *	If this fails, it means that something else just logged something
+ *	and therefore we probably no longer want to do this.  It's up to the
+ *	caller anyway...
+ *
+ *	Returns 0 if the index was successfully set, negative otherwise
+ */
+int
+locking_reset_index(struct rchan *rchan, u32 old_idx)
+{
+	unsigned long flags;
+	struct timeval time;
+	u32 tsc;
+	u32 cur_idx;
+	
+	relay_lock_channel(rchan, flags);
+	cur_idx = locking_get_offset(rchan, NULL);
+	if (cur_idx != old_idx) {
+		relay_unlock_channel(rchan, flags);
+		return -1;
+	}
+
+	get_timestamp(&time, &tsc, rchan);
+	switch_buffers(time, tsc, rchan, 0, 1, 0);
+
+	relay_unlock_channel(rchan, flags);
+
+	return 0;
+}
+
+
+
+
+
+
+
diff -uNrp linux-2.6.9/fs/relayfs/relay_locking.h linux-2.6.9-ltt-r12/fs/relayfs/relay_locking.h
--- linux-2.6.9/fs/relayfs/relay_locking.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/relay_locking.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,34 @@
+#ifndef _RELAY_LOCKING_H
+#define _RELAY_LOCKING_H
+
+extern char *
+locking_reserve(struct rchan *rchan,
+		u32 slot_len, 
+		struct timeval *time_stamp,
+		u32 *tsc,
+		int *err,
+		int *interrupting);
+
+extern void 
+locking_commit(struct rchan *rchan,
+	       char *from,
+	       u32 len, 
+	       int deliver, 
+	       int interrupting);
+
+extern void 
+locking_resume(struct rchan *rchan);
+
+extern void 
+locking_finalize(struct rchan *rchan);
+
+extern u32 
+locking_get_offset(struct rchan *rchan, u32 *max_offset);
+
+extern void 
+locking_reset(struct rchan *rchan, int init);
+
+extern int
+locking_reset_index(struct rchan *rchan, u32 old_idx);
+
+#endif	/* _RELAY_LOCKING_H */
diff -uNrp linux-2.6.9/fs/relayfs/relay_lockless.c linux-2.6.9-ltt-r12/fs/relayfs/relay_lockless.c
--- linux-2.6.9/fs/relayfs/relay_lockless.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/relay_lockless.c	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,541 @@
+/*
+ * RelayFS lockless scheme implementation.
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 2002, 2003 - Bob Wisniewski (bob@watson.ibm.com), IBM Corp
+ *
+ * This file is released under the GPL.
+ */
+
+#include <asm/relay.h>
+#include "relay_lockless.h"
+#include "resize.h"
+
+/**
+ *	compare_and_store_volatile - self-explicit
+ *	@ptr: ptr to the word that will receive the new value
+ *	@oval: the value we think is currently in *ptr
+ *	@nval: the value *ptr will get if we were right
+ */
+inline int 
+compare_and_store_volatile(volatile u32 *ptr, 
+			   u32 oval,
+			   u32 nval)
+{
+	u32 prev;
+
+	barrier();
+	prev = cmpxchg(ptr, oval, nval);
+	barrier();
+
+	return (prev == oval);
+}
+
+/**
+ *	atomic_set_volatile - atomically set the value in ptr to nval.
+ *	@ptr: ptr to the word that will receive the new value
+ *	@nval: the new value
+ */
+inline void 
+atomic_set_volatile(atomic_t *ptr,
+		    u32 nval)
+{
+	barrier();
+	atomic_set(ptr, (int)nval);
+	barrier();
+}
+
+/**
+ *	atomic_add_volatile - atomically add val to the value at ptr.
+ *	@ptr: ptr to the word that will receive the addition
+ *	@val: the value to add to *ptr
+ */
+inline void 
+atomic_add_volatile(atomic_t *ptr, u32 val)
+{
+	barrier();
+	atomic_add((int)val, ptr);
+	barrier();
+}
+
+/**
+ *	atomic_sub_volatile - atomically substract val from the value at ptr.
+ *	@ptr: ptr to the word that will receive the subtraction
+ *	@val: the value to subtract from *ptr
+ */
+inline void 
+atomic_sub_volatile(atomic_t *ptr, s32 val)
+{
+	barrier();
+	atomic_sub((int)val, ptr);
+	barrier();
+}
+
+/**
+ *	lockless_commit - commit a reserved slot in the buffer
+ *	@rchan: the channel
+ *	@from: commit the length starting here
+ *	@len: length committed
+ *	@deliver: length committed
+ *	@interrupting: not used
+ *
+ *      Commits len bytes and calls deliver callback if applicable.
+ */
+inline void 
+lockless_commit(struct rchan *rchan,
+		char *from,
+		u32 len, 
+		int deliver, 
+		int interrupting)
+{
+	u32 bufno, idx;
+	
+	idx = from - rchan->buf;
+
+	if (len > 0) {
+		bufno = RELAY_BUFNO_GET(idx, offset_bits(rchan));
+		atomic_add_volatile(&fill_count(rchan, bufno), len);
+	}
+
+	if (deliver) {
+		u32 mask = offset_mask(rchan);
+		if (bulk_delivery(rchan)) {
+			from = rchan->buf + RELAY_BUF_OFFSET_CLEAR(idx, mask);
+			len += RELAY_BUF_OFFSET_GET(idx, mask);
+		}
+		rchan->callbacks->deliver(rchan->id, from, len);
+		expand_check(rchan);
+	}
+}
+
+/**
+ *	get_buffer_end - get the address of the end of buffer 
+ *	@rchan: the channel
+ *	@buf_idx: index into channel corresponding to address
+ */
+static inline char * 
+get_buffer_end(struct rchan *rchan, u32 buf_idx)
+{
+	return rchan->buf
+		+ RELAY_BUF_OFFSET_CLEAR(buf_idx, offset_mask(rchan))
+		+ RELAY_BUF_SIZE(offset_bits(rchan));
+}
+
+
+/**
+ *	finalize_buffer - utility function consolidating end-of-buffer tasks.
+ *	@rchan: the channel
+ *	@end_idx: index into buffer to write the end-buffer event at
+ *	@size_lost: number of unused bytes at the end of the buffer
+ *	@time_stamp: the time of the end-buffer event
+ *	@tsc: the timestamp counter associated with time
+ *	@resetting: are we resetting the channel?
+ *
+ *	This function must be called with local irqs disabled.
+ */
+static inline void 
+finalize_buffer(struct rchan *rchan,
+		u32 end_idx,
+		u32 size_lost, 
+		struct timeval *time_stamp,
+		u32 *tsc, 
+		int resetting)
+{
+	char* cur_write_pos;
+	char* write_buf_end;
+	u32 bufno;
+	int bytes_written;
+	
+	cur_write_pos = rchan->buf + end_idx;
+	write_buf_end = get_buffer_end(rchan, end_idx - 1);
+
+	bytes_written = rchan->callbacks->buffer_end(rchan->id, cur_write_pos, 
+		     write_buf_end, *time_stamp, *tsc, using_tsc(rchan));
+	if (bytes_written == 0)
+		rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = size_lost;
+	
+        bufno = RELAY_BUFNO_GET(end_idx, offset_bits(rchan));
+        atomic_add_volatile(&fill_count(rchan, bufno), size_lost);
+	if (resetting) {
+		rchan->bufs_produced = rchan->bufs_produced + rchan->n_bufs;
+		rchan->bufs_produced -= rchan->bufs_produced % rchan->n_bufs;
+		rchan->bufs_consumed = rchan->bufs_produced;
+		rchan->bytes_consumed = 0;
+		update_readers_consumed(rchan, rchan->bufs_consumed, rchan->bytes_consumed);
+	} else
+		rchan->bufs_produced++;
+}
+
+/**
+ *	lockless_finalize: - finalize last buffer at end of channel use
+ *	@rchan: the channel
+ */
+inline void
+lockless_finalize(struct rchan *rchan)
+{
+	u32 event_end_idx;
+	u32 size_lost;
+	unsigned long int flags;
+	struct timeval time;
+	u32 tsc;
+
+	event_end_idx = RELAY_BUF_OFFSET_GET(idx(rchan), offset_mask(rchan));
+	size_lost = RELAY_BUF_SIZE(offset_bits(rchan)) - event_end_idx;
+
+	relay_irq_save(flags);
+	get_timestamp(&time, &tsc, rchan);
+	finalize_buffer(rchan, idx(rchan) & idx_mask(rchan), size_lost, 
+			&time, &tsc, 0);
+	relay_irq_restore(flags);
+}
+
+/**
+ *	discard_check: - determine whether a write should be discarded
+ *	@rchan: the channel
+ *	@old_idx: index into buffer where check for space should begin
+ *	@write_len: the length of the write to check
+ *	@time_stamp: the time of the end-buffer event
+ *	@tsc: the timestamp counter associated with time
+ *
+ *	The return value contains the result flags and is an ORed combination 
+ *	of the following:
+ *
+ *	RELAY_WRITE_DISCARD_NONE - write should not be discarded
+ *	RELAY_BUFFER_SWITCH - buffer switch occurred
+ *	RELAY_WRITE_DISCARD - write should be discarded (all buffers are full)
+ *	RELAY_WRITE_TOO_LONG - write won't fit into even an empty buffer
+ */
+static inline int
+discard_check(struct rchan *rchan,
+	      u32 old_idx,
+	      u32 write_len, 
+	      struct timeval *time_stamp,
+	      u32 *tsc)
+{
+	u32 buffers_ready;
+	u32 offset_mask = offset_mask(rchan);
+	u8 offset_bits = offset_bits(rchan);
+	u32 idx_mask = idx_mask(rchan);
+	u32 size_lost;
+	unsigned long int flags;
+
+	if (write_len > RELAY_BUF_SIZE(offset_bits))
+		return RELAY_WRITE_DISCARD | RELAY_WRITE_TOO_LONG;
+
+	if (mode_continuous(rchan))
+		return RELAY_WRITE_DISCARD_NONE;
+	
+	relay_irq_save(flags);
+	if (atomic_read(&rchan->suspended) == 1) {
+		relay_irq_restore(flags);
+		return RELAY_WRITE_DISCARD;
+	}
+	if (rchan->half_switch) {
+		relay_irq_restore(flags);
+		return RELAY_WRITE_DISCARD_NONE;
+	}
+	buffers_ready = rchan->bufs_produced - rchan->bufs_consumed;
+	if (buffers_ready == rchan->n_bufs - 1) {
+		atomic_set(&rchan->suspended, 1);
+		size_lost = RELAY_BUF_SIZE(offset_bits)
+			- RELAY_BUF_OFFSET_GET(old_idx, offset_mask);
+		finalize_buffer(rchan, old_idx & idx_mask, size_lost, 
+				time_stamp, tsc, 0);
+		rchan->half_switch = 1;
+		idx(rchan) = RELAY_BUF_OFFSET_CLEAR((old_idx & idx_mask), offset_mask(rchan)) + RELAY_BUF_SIZE(offset_bits) - 1;
+		relay_irq_restore(flags);
+
+		return RELAY_BUFFER_SWITCH | RELAY_WRITE_DISCARD;
+	}
+	relay_irq_restore(flags);
+
+	return RELAY_WRITE_DISCARD_NONE;
+}
+
+/**
+ *	switch_buffers - switch over to a new sub-buffer
+ *	@rchan: the channel
+ *	@slot_len: the length of the slot needed for the current write
+ *	@offset: the offset calculated for the new index
+ *	@ts: timestamp
+ *	@tsc: the timestamp counter associated with time
+ *	@old_idx: the value of the buffer control index when we were called
+ *	@old_idx: the new calculated value of the buffer control index
+ *	@resetting: are we resetting the channel?
+ */
+static inline void
+switch_buffers(struct rchan *rchan,
+	       u32 slot_len,
+	       u32 offset,
+	       struct timeval *ts,
+	       u32 *tsc,
+	       u32 new_idx,
+	       u32 old_idx,
+	       int resetting)
+{
+	u32 size_lost = rchan->end_reserve;
+	unsigned long int flags;
+	u32 idx_mask = idx_mask(rchan);
+	u8 offset_bits = offset_bits(rchan);
+	char *cur_write_pos;
+	u32 new_buf_no;
+	u32 start_reserve = rchan->start_reserve;
+	
+	if (resetting)
+		size_lost = RELAY_BUF_SIZE(offset_bits(rchan)) - old_idx % rchan->buf_size;
+
+	if (offset > 0)
+		size_lost += slot_len - offset;
+	else
+		old_idx += slot_len;
+
+	relay_irq_save(flags);
+	if (!rchan->half_switch)
+		finalize_buffer(rchan, old_idx & idx_mask, size_lost,
+				ts, tsc, resetting);
+	rchan->half_switch = 0;
+	rchan->buf_start_time = *ts;
+	rchan->buf_start_tsc = *tsc;
+	relay_irq_restore(flags);
+
+	cur_write_pos = rchan->buf + RELAY_BUF_OFFSET_CLEAR((new_idx
+					     & idx_mask), offset_mask(rchan));
+	if (resetting)
+		rchan->buf_idx = 0;
+	else
+		rchan->buf_idx++;
+	rchan->buf_id++;
+	
+	rchan->unused_bytes[rchan->buf_idx % rchan->n_bufs] = 0;
+
+	rchan->callbacks->buffer_start(rchan->id, cur_write_pos, 
+			       rchan->buf_id, *ts, *tsc, using_tsc(rchan));
+	new_buf_no = RELAY_BUFNO_GET(new_idx & idx_mask, offset_bits);
+	atomic_sub_volatile(&fill_count(rchan, new_buf_no),
+			    RELAY_BUF_SIZE(offset_bits) - start_reserve);
+	if (atomic_read(&fill_count(rchan, new_buf_no)) < start_reserve)
+		atomic_set_volatile(&fill_count(rchan, new_buf_no), 
+				    start_reserve);
+}
+
+/**
+ *	lockless_reserve_slow - the slow reserve path in the lockless scheme
+ *	@rchan: the channel
+ *	@slot_len: the length of the slot to reserve
+ *	@ts: variable that will receive the time the slot was reserved
+ *	@tsc: the timestamp counter associated with time
+ *	@old_idx: the value of the buffer control index when we were called
+ *	@err: receives the result flags
+ *
+ *	Returns pointer to the beginning of the reserved slot, NULL if error.
+
+ *	err values same as for lockless_reserve.
+ */
+static inline char *
+lockless_reserve_slow(struct rchan *rchan,
+		      u32 slot_len,
+		      struct timeval *ts,
+		      u32 *tsc,
+		      u32 old_idx,
+		      int *err)
+{
+	u32 new_idx, offset;
+	unsigned long int flags;
+	u32 offset_mask = offset_mask(rchan);
+	u32 idx_mask = idx_mask(rchan);
+	u32 start_reserve = rchan->start_reserve;
+	u32 end_reserve = rchan->end_reserve;
+	int discard_event;
+	u32 reserved_idx;
+	char *cur_write_pos;
+	int initializing = 0;
+
+	*err = RELAY_BUFFER_SWITCH_NONE;
+
+	discard_event = discard_check(rchan, old_idx, slot_len, ts, tsc);
+	if (discard_event != RELAY_WRITE_DISCARD_NONE) {
+		*err = discard_event;
+		return NULL;
+	}
+
+	relay_irq_save(flags);
+	if (rchan->initialized == 0) {
+		rchan->initialized = initializing = 1;
+		idx(rchan) = rchan->start_reserve + rchan->rchan_start_reserve;
+	}
+	relay_irq_restore(flags);
+
+	do {
+		old_idx = idx(rchan);
+		new_idx = old_idx + slot_len;
+
+		offset = RELAY_BUF_OFFSET_GET(new_idx + end_reserve,
+					      offset_mask);
+		if ((offset < slot_len) && (offset > 0)) {
+			reserved_idx = RELAY_BUF_OFFSET_CLEAR(new_idx 
+				+ end_reserve, offset_mask) + start_reserve;
+			new_idx = reserved_idx + slot_len;
+		} else if (offset < slot_len) {
+			reserved_idx = old_idx;
+			new_idx = RELAY_BUF_OFFSET_CLEAR(new_idx
+			      + end_reserve, offset_mask) + start_reserve;
+		} else
+			reserved_idx = old_idx;
+		get_timestamp(ts, tsc, rchan);
+	} while (!compare_and_store_volatile(&idx(rchan), old_idx, new_idx));
+
+	reserved_idx &= idx_mask;
+
+	if (initializing == 1) {
+		cur_write_pos = rchan->buf 
+			+ RELAY_BUF_OFFSET_CLEAR((old_idx & idx_mask),
+						 offset_mask(rchan));
+		rchan->buf_start_time = *ts;
+		rchan->buf_start_tsc = *tsc;
+		rchan->unused_bytes[0] = 0;
+
+		rchan->callbacks->buffer_start(rchan->id, cur_write_pos, 
+			       rchan->buf_id, *ts, *tsc, using_tsc(rchan));
+	}
+
+	if (offset < slot_len) {
+		switch_buffers(rchan, slot_len, offset, ts, tsc, new_idx,
+			       old_idx, 0);
+		*err = RELAY_BUFFER_SWITCH;
+	}
+
+	/* If not using TSC, need to calc time delta */
+	recalc_time_delta(ts, tsc, rchan);
+
+	return rchan->buf + reserved_idx;
+}
+
+/**
+ *	lockless_reserve - reserve a slot in the buffer for an event.
+ *	@rchan: the channel
+ *	@slot_len: the length of the slot to reserve
+ *	@ts: variable that will receive the time the slot was reserved
+ *	@tsc: the timestamp counter associated with time
+ *	@err: receives the result flags
+ *	@interrupting: not used
+ *
+ *	Returns pointer to the beginning of the reserved slot, NULL if error.
+ *
+ *	The err value contains the result flags and is an ORed combination 
+ *	of the following:
+ *
+ *	RELAY_BUFFER_SWITCH_NONE - no buffer switch occurred
+ *	RELAY_EVENT_DISCARD_NONE - event should not be discarded
+ *	RELAY_BUFFER_SWITCH - buffer switch occurred
+ *	RELAY_EVENT_DISCARD - event should be discarded (all buffers are full)
+ *	RELAY_EVENT_TOO_LONG - event won't fit into even an empty buffer
+ */
+inline char * 
+lockless_reserve(struct rchan *rchan,
+		 u32 slot_len,
+		 struct timeval *ts,
+		 u32 *tsc,
+		 int *err,
+		 int *interrupting)
+{
+	u32 old_idx, new_idx, offset;
+	u32 offset_mask = offset_mask(rchan);
+
+	do {
+		old_idx = idx(rchan);
+		new_idx = old_idx + slot_len;
+
+		offset = RELAY_BUF_OFFSET_GET(new_idx + rchan->end_reserve, 
+					      offset_mask);
+		if (offset < slot_len || atomic_read(&(rchan->suspended)) == 1)
+			return lockless_reserve_slow(rchan, slot_len, 
+				     ts, tsc, old_idx, err);
+		get_time_or_tsc(ts, tsc, rchan);
+	} while (!compare_and_store_volatile(&idx(rchan), old_idx, new_idx));
+
+	/* If not using TSC, need to calc time delta */
+	recalc_time_delta(ts, tsc, rchan);
+
+	*err = RELAY_BUFFER_SWITCH_NONE;
+
+	return rchan->buf + (old_idx & idx_mask(rchan));
+}
+
+/**
+ *	lockless_get_offset - get current and max channel offsets
+ *	@rchan: the channel
+ *	@max_offset: maximum channel offset
+ *
+ *	Returns the current and maximum channel offsets.
+ */
+u32 
+lockless_get_offset(struct rchan *rchan,
+			u32 *max_offset)
+{
+	if (max_offset)
+		*max_offset = rchan->buf_size * rchan->n_bufs - 1;
+
+	return rchan->initialized ? idx(rchan) & idx_mask(rchan) : 0;
+}
+
+/**
+ *	lockless_reset - reset the channel
+ *	@rchan: the channel
+ *	@init: 1 if this is a first-time channel initialization
+ */
+void lockless_reset(struct rchan *rchan, int init)
+{
+	int i;
+	
+	/* Start first buffer at 0 - (end_reserve + 1) so that it
+	   gets initialized via buffer_start callback as well. */
+	idx(rchan) =  0UL - (rchan->end_reserve + 1);
+	idx_mask(rchan) =
+		(1UL << (bufno_bits(rchan) + offset_bits(rchan))) - 1;
+	atomic_set(&fill_count(rchan, 0), 
+		   (int)rchan->start_reserve + 
+		   (int)rchan->rchan_start_reserve);
+	for (i = 1; i < rchan->n_bufs; i++)
+		atomic_set(&fill_count(rchan, i),
+			   (int)RELAY_BUF_SIZE(offset_bits(rchan)));
+}
+
+/**
+ *	lockless_reset_index - atomically set channel index to the beginning
+ *	@rchan: the channel
+ *	@old_idx: the current index
+ *
+ *	If this fails, it means that something else just logged something
+ *	and therefore we probably no longer want to do this.  It's up to the
+ *	caller anyway...
+ *
+ *	Returns 0 if the index was successfully set, negative otherwise
+ */
+int
+lockless_reset_index(struct rchan *rchan, u32 old_idx)
+{
+	struct timeval ts;
+	u32 tsc;
+	u32 new_idx;
+
+	if (compare_and_store_volatile(&idx(rchan), old_idx, 0)) {
+		new_idx = rchan->start_reserve;
+		switch_buffers(rchan, 0, 0, &ts, &tsc, new_idx, old_idx, 1);
+		return 0;
+	} else
+		return -1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -uNrp linux-2.6.9/fs/relayfs/relay_lockless.h linux-2.6.9-ltt-r12/fs/relayfs/relay_lockless.h
--- linux-2.6.9/fs/relayfs/relay_lockless.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/relay_lockless.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,34 @@
+#ifndef _RELAY_LOCKLESS_H
+#define _RELAY_LOCKLESS_H
+
+extern char *
+lockless_reserve(struct rchan *rchan,
+		 u32 slot_len,
+		 struct timeval *time_stamp,
+		 u32 *tsc,
+		 int * interrupting,
+		 int * errcode);
+
+extern void 
+lockless_commit(struct rchan *rchan,
+		char * from,
+		u32 len, 
+		int deliver, 
+		int interrupting);
+
+extern void 
+lockless_resume(struct rchan *rchan);
+
+extern void 
+lockless_finalize(struct rchan *rchan);
+
+extern u32 
+lockless_get_offset(struct rchan *rchan, u32 *max_offset);
+
+extern void
+lockless_reset(struct rchan *rchan, int init);
+
+extern int
+lockless_reset_index(struct rchan *rchan, u32 old_idx);
+
+#endif/* _RELAY_LOCKLESS_H */
diff -uNrp linux-2.6.9/fs/relayfs/resize.c linux-2.6.9-ltt-r12/fs/relayfs/resize.c
--- linux-2.6.9/fs/relayfs/resize.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/resize.c	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,1105 @@
+/*
+ * RelayFS buffer management and resizing code.
+ *
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <asm/relay.h>
+#include "resize.h"
+
+/**
+ *	alloc_page_array - alloc array to hold pages, but not pages
+ *	@size: the total size of the memory represented by the page array
+ *	@page_count: the number of pages the array can hold
+ *	@err: 0 on success, negative otherwise
+ *
+ *	Returns a pointer to the page array if successful, NULL otherwise.
+ */
+static struct page **
+alloc_page_array(int size, int *page_count, int *err)
+{
+	int n_pages;
+	struct page **page_array;
+	int page_array_size;
+
+	*err = 0;
+	
+	size = PAGE_ALIGN(size);
+	n_pages = size >> PAGE_SHIFT;
+	page_array_size = n_pages * sizeof(struct page *);
+	page_array = kmalloc(page_array_size, GFP_KERNEL);
+	if (page_array == NULL) {
+		*err = -ENOMEM;
+		return NULL;
+	}
+	*page_count = n_pages;
+	memset(page_array, 0, page_array_size);
+
+	return page_array;
+}
+
+/**
+ *	free_page_array - free array to hold pages, but not pages
+ *	@page_array: pointer to the page array
+ */
+static inline void
+free_page_array(struct page **page_array)
+{
+	kfree(page_array);
+}
+
+/**
+ *	depopulate_page_array - free and unreserve all pages in the array
+ *	@page_array: pointer to the page array
+ *	@page_count: number of pages to free
+ */
+static void
+depopulate_page_array(struct page **page_array, int page_count)
+{
+	int i;
+	
+	for (i = 0; i < page_count; i++) {
+		ClearPageReserved(page_array[i]);
+		__free_page(page_array[i]);
+	}
+}
+
+/**
+ *	populate_page_array - allocate and reserve pages
+ *	@page_array: pointer to the page array
+ *	@page_count: number of pages to allocate
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+static int
+populate_page_array(struct page **page_array, int page_count)
+{
+	int i;
+	
+	for (i = 0; i < page_count; i++) {
+		page_array[i] = alloc_page(GFP_KERNEL);
+		if (unlikely(!page_array[i])) {
+			depopulate_page_array(page_array, i);
+			return -ENOMEM;
+		}
+		SetPageReserved(page_array[i]);
+	}
+	return 0;
+}
+
+/**
+ *	alloc_rchan_buf - allocate the initial channel buffer
+ *	@size: total size of the buffer
+ *	@page_array: receives a pointer to the buffer's page array
+ *	@page_count: receives the number of pages allocated
+ *
+ *	Returns a pointer to the resulting buffer, NULL if unsuccessful
+ */
+void *
+alloc_rchan_buf(unsigned long size, struct page ***page_array, int *page_count)
+{
+	void *mem;
+	int err;
+
+	*page_array = alloc_page_array(size, page_count, &err);
+	if (!*page_array)
+		return NULL;
+
+	err = populate_page_array(*page_array, *page_count);
+	if (err) {
+		free_page_array(*page_array);
+		*page_array = NULL;
+		return NULL;
+	}
+
+	mem = vmap(*page_array, *page_count, GFP_KERNEL, PAGE_KERNEL);
+	if (!mem) {
+		depopulate_page_array(*page_array, *page_count);
+		free_page_array(*page_array);
+		*page_array = NULL;
+		return NULL;
+	}
+	memset(mem, 0, size);
+
+	return mem;
+}
+
+/**
+ *	expand_check - check whether the channel needs expanding
+ *	@rchan: the channel
+ *
+ *	If the channel needs expanding, the needs_resize callback is
+ *	called with RELAY_RESIZE_EXPAND.
+ *
+ *	Returns the suggested number of sub-buffers for the new
+ *	buffer.
+ */
+void
+expand_check(struct rchan *rchan)
+{
+	u32 active_bufs;
+	u32 new_n_bufs = 0;
+	u32 threshold = rchan->n_bufs * RESIZE_THRESHOLD;
+
+	if (rchan->init_buf)
+		return;
+
+	if (rchan->resize_min == 0)
+		return;
+
+	if (rchan->resizing || rchan->replace_buffer)
+		return;
+	
+	active_bufs = rchan->bufs_produced - rchan->bufs_consumed + 1;
+
+	if (rchan->resize_max && active_bufs == threshold) {
+		new_n_bufs = rchan->n_bufs * 2;
+	}
+
+	if (new_n_bufs && (new_n_bufs * rchan->buf_size <= rchan->resize_max))
+		rchan->callbacks->needs_resize(rchan->id,
+					       RELAY_RESIZE_EXPAND,
+					       rchan->buf_size, 
+					       new_n_bufs);
+}
+
+/**
+ *	can_shrink - check whether the channel can shrink
+ *	@rchan: the channel
+ *	@cur_idx: the current channel index
+ *
+ *	Returns the suggested number of sub-buffers for the new
+ *	buffer, 0 if the buffer is not shrinkable.
+ */
+static inline u32
+can_shrink(struct rchan *rchan, u32 cur_idx)
+{
+	u32 active_bufs = rchan->bufs_produced - rchan->bufs_consumed + 1;
+	u32 new_n_bufs = 0;
+	u32 cur_bufno_bytes = cur_idx % rchan->buf_size;
+
+	if (rchan->resize_min == 0 ||
+	    rchan->resize_min >= rchan->n_bufs * rchan->buf_size)
+		goto out;
+	
+	if (active_bufs > 1)
+		goto out;
+
+	if (cur_bufno_bytes != rchan->bytes_consumed)
+		goto out;
+	
+	new_n_bufs = rchan->resize_min / rchan->buf_size;
+out:
+	return new_n_bufs;
+}
+
+/**
+ *	shrink_check: - timer function checking whether the channel can shrink
+ *	@data: unused
+ *
+ *	Every SHRINK_TIMER_SECS, check whether the channel is shrinkable.
+ *	If so, we attempt to atomically reset the channel to the beginning.
+ *	The needs_resize callback is then called with RELAY_RESIZE_SHRINK.
+ *	If the reset fails, it means we really shouldn't be shrinking now
+ *	and need to wait until the next time around.
+ */
+static void
+shrink_check(unsigned long data)
+{
+	struct rchan *rchan = (struct rchan *)data;
+	u32 shrink_to_nbufs, cur_idx;
+	
+	del_timer(&rchan->shrink_timer);
+	rchan->shrink_timer.expires = jiffies + SHRINK_TIMER_SECS * HZ;
+	add_timer(&rchan->shrink_timer);
+
+	if (rchan->init_buf)
+		return;
+
+	if (rchan->resizing || rchan->replace_buffer)
+		return;
+
+	if (using_lockless(rchan))
+		cur_idx = idx(rchan);
+	else
+		cur_idx = relay_get_offset(rchan, NULL);
+
+	shrink_to_nbufs = can_shrink(rchan, cur_idx);
+	if (shrink_to_nbufs != 0 && reset_index(rchan, cur_idx) == 0) {
+		update_readers_consumed(rchan, rchan->bufs_consumed, 0);
+		rchan->callbacks->needs_resize(rchan->id,
+					       RELAY_RESIZE_SHRINK,
+					       rchan->buf_size, 
+					       shrink_to_nbufs);
+	}
+}
+
+/**
+ *	init_shrink_timer: - Start timer used to check shrinkability.
+ *	@rchan: the channel
+ */
+void
+init_shrink_timer(struct rchan *rchan)
+{
+	if (rchan->resize_min) {
+		init_timer(&rchan->shrink_timer);
+		rchan->shrink_timer.function = shrink_check;
+		rchan->shrink_timer.data = (unsigned long)rchan;
+		rchan->shrink_timer.expires = jiffies + SHRINK_TIMER_SECS * HZ;
+		add_timer(&rchan->shrink_timer);
+	}
+}
+
+
+/**
+ *	alloc_new_pages - allocate new pages for expanding buffer
+ *	@rchan: the channel
+ *
+ *	Returns 0 on success, negative otherwise.
+ */
+static int
+alloc_new_pages(struct rchan *rchan)
+{
+	int new_pages_size, err;
+
+	if (unlikely(rchan->expand_page_array))	BUG();
+
+	new_pages_size = rchan->resize_alloc_size - rchan->alloc_size;
+	rchan->expand_page_array = alloc_page_array(new_pages_size,
+					    &rchan->expand_page_count, &err);
+	if (rchan->expand_page_array == NULL) {
+		rchan->resize_err = -ENOMEM;
+		return -ENOMEM;
+	}
+	
+	err = populate_page_array(rchan->expand_page_array,
+				  rchan->expand_page_count);
+	if (err) {
+		rchan->resize_err = -ENOMEM;
+		free_page_array(rchan->expand_page_array);
+		rchan->expand_page_array = NULL;
+	}
+
+	return err;
+}
+
+/**
+ *	clear_resize_offset - helper function for buffer resizing
+ *	@rchan: the channel
+ *
+ *	Clear the saved offset change.
+ */
+static inline void
+clear_resize_offset(struct rchan *rchan)
+{
+	rchan->resize_offset.ge = 0UL;
+	rchan->resize_offset.le = 0UL;
+	rchan->resize_offset.delta = 0;
+}
+
+/**
+ *	save_resize_offset - helper function for buffer resizing
+ *	@rchan: the channel
+ *	@ge: affected region ge this
+ *	@le: affected region le this
+ *	@delta: apply this delta
+ *
+ *	Save a resize offset.
+ */
+static inline void
+save_resize_offset(struct rchan *rchan, u32 ge, u32 le, int delta)
+{
+	rchan->resize_offset.ge = ge;
+	rchan->resize_offset.le = le;
+	rchan->resize_offset.delta = delta;
+}
+
+/**
+ *	update_file_offset - apply offset change to reader
+ *	@reader: the channel reader
+ *	@change_idx: the offset index into the offsets array
+ *
+ *	Returns non-zero if the offset was applied.
+ *
+ *	Apply the offset delta saved in change_idx to the reader's
+ *	current read position.
+ */
+static inline int
+update_file_offset(struct rchan_reader *reader)
+{
+	int applied = 0;
+	struct rchan *rchan = reader->rchan;
+	u32 f_pos;
+	int delta = reader->rchan->resize_offset.delta;
+
+	if (reader->vfs_reader)
+		f_pos = (u32)reader->pos.file->f_pos;
+	else
+		f_pos = reader->pos.f_pos;
+
+	if (f_pos == relay_get_offset(rchan, NULL))
+		return 0;
+
+	if ((f_pos >= rchan->resize_offset.ge - 1) &&
+	    (f_pos <= rchan->resize_offset.le)) {
+		if (reader->vfs_reader) {
+			if (reader->rchan->read_start == f_pos)
+				if (!(rchan->flags & RELAY_MODE_START_AT_ZERO))
+					reader->rchan->read_start += delta;
+			reader->pos.file->f_pos += delta;
+		} else
+			reader->pos.f_pos += delta;
+		applied = 1;
+	}
+
+	return applied;
+}
+
+/**
+ *	update_file_offsets - apply offset change to readers
+ *	@rchan: the channel
+ *
+ *	Apply the saved offset deltas to all files open on the channel.
+ */
+static inline void
+update_file_offsets(struct rchan *rchan)
+{
+	struct list_head *p;
+	struct rchan_reader *reader;
+	
+	read_lock(&rchan->open_readers_lock);
+	list_for_each(p, &rchan->open_readers) {
+		reader = list_entry(p, struct rchan_reader, list);
+		if (update_file_offset(reader))
+			reader->offset_changed = 1;
+	}
+	read_unlock(&rchan->open_readers_lock);
+}
+
+/**
+ *	setup_expand_buf - setup expand buffer for replacement
+ *	@rchan: the channel
+ *	@newsize: the size of the new buffer
+ *	@oldsize: the size of the old buffer
+ *	@old_n_bufs: the number of sub-buffers in the old buffer
+ *
+ *	Inserts new pages into the old buffer to create a larger
+ *	new channel buffer, splitting them at old_cur_idx, the bottom
+ *	half of the old buffer going to the bottom of the new, likewise
+ *	for the top half.
+ */
+static void
+setup_expand_buf(struct rchan *rchan, int newsize, int oldsize, u32 old_n_bufs)
+{
+	u32 cur_idx;
+	int cur_bufno, delta, i, j;
+	u32 ge, le;
+	int cur_pageno;
+	u32 free_bufs, free_pages;
+	u32 free_pages_in_cur_buf;
+	u32 free_bufs_to_end;
+	u32 cur_pages = rchan->alloc_size >> PAGE_SHIFT;
+	u32 pages_per_buf = cur_pages / rchan->n_bufs;
+	u32 bufs_ready = rchan->bufs_produced - rchan->bufs_consumed;
+
+	if (!rchan->resize_page_array || !rchan->expand_page_array ||
+	    !rchan->buf_page_array)
+		return;
+
+	if (bufs_ready >= rchan->n_bufs) {
+		bufs_ready = rchan->n_bufs;
+		free_bufs = 0;
+	} else
+		free_bufs = rchan->n_bufs - bufs_ready - 1;
+
+	cur_idx = relay_get_offset(rchan, NULL);
+	cur_pageno = cur_idx / PAGE_SIZE;
+	cur_bufno = cur_idx / rchan->buf_size;
+
+	free_pages_in_cur_buf = (pages_per_buf - 1) - (cur_pageno % pages_per_buf);
+	free_pages = free_bufs * pages_per_buf + free_pages_in_cur_buf;
+	free_bufs_to_end = (rchan->n_bufs - 1) - cur_bufno;
+	if (free_bufs >= free_bufs_to_end) {
+		free_pages = free_bufs_to_end * pages_per_buf + free_pages_in_cur_buf;
+		free_bufs = free_bufs_to_end;
+	}
+		
+	for (i = 0, j = 0; i <= cur_pageno + free_pages; i++, j++)
+		rchan->resize_page_array[j] = rchan->buf_page_array[i];
+	for (i = 0; i < rchan->expand_page_count; i++, j++)
+		rchan->resize_page_array[j] = rchan->expand_page_array[i];
+	for (i = cur_pageno + free_pages + 1; i < rchan->buf_page_count; i++, j++)
+		rchan->resize_page_array[j] = rchan->buf_page_array[i];
+
+	delta = newsize - oldsize;
+	ge = (cur_pageno + 1 + free_pages) * PAGE_SIZE;
+	le = oldsize;
+	save_resize_offset(rchan, ge, le, delta);
+
+	rchan->expand_buf_id = rchan->buf_id + 1 + free_bufs;
+}
+
+/**
+ *	setup_shrink_buf - setup shrink buffer for replacement
+ *	@rchan: the channel
+ *
+ *	Removes pages from the old buffer to create a smaller
+ *	new channel buffer.
+ */
+static void
+setup_shrink_buf(struct rchan *rchan)
+{
+	int i;
+	int copy_end_page;
+
+	if (!rchan->resize_page_array || !rchan->shrink_page_array || 
+	    !rchan->buf_page_array)
+		return;
+	
+	copy_end_page = rchan->resize_alloc_size / PAGE_SIZE;
+
+	for (i = 0; i < copy_end_page; i++)
+		rchan->resize_page_array[i] = rchan->buf_page_array[i];
+}
+
+/**
+ *	cleanup_failed_alloc - relaybuf_alloc helper
+ */
+static void
+cleanup_failed_alloc(struct rchan *rchan)
+{
+	if (rchan->expand_page_array) {
+		depopulate_page_array(rchan->expand_page_array,
+				      rchan->expand_page_count);
+		free_page_array(rchan->expand_page_array);
+		rchan->expand_page_array = NULL;
+		rchan->expand_page_count = 0;
+	} else if (rchan->shrink_page_array) {
+		free_page_array(rchan->shrink_page_array);
+		rchan->shrink_page_array = NULL;
+		rchan->shrink_page_count = 0;
+	}
+
+	if (rchan->resize_page_array) {
+		free_page_array(rchan->resize_page_array);
+		rchan->resize_page_array = NULL;
+		rchan->resize_page_count = 0;
+	}
+}
+
+/**
+ *	relaybuf_alloc - allocate a new resized channel buffer
+ *	@private: pointer to the channel struct
+ *
+ *	Internal - manages the allocation and remapping of new channel
+ *	buffers.
+ */
+static void 
+relaybuf_alloc(void *private)
+{
+	struct rchan *rchan = (struct rchan *)private;
+	int i, j, err;
+	u32 old_cur_idx;
+	int free_size;
+	int free_start_page, free_end_page;
+	u32 newsize, oldsize;
+
+	if (rchan->resize_alloc_size > rchan->alloc_size) {
+		err = alloc_new_pages(rchan);
+		if (err) goto cleanup;
+	} else {
+		free_size = rchan->alloc_size - rchan->resize_alloc_size;
+		BUG_ON(free_size <= 0);
+		rchan->shrink_page_array = alloc_page_array(free_size,
+					    &rchan->shrink_page_count, &err);
+		if (rchan->shrink_page_array == NULL)
+			goto cleanup;
+		free_start_page = rchan->resize_alloc_size / PAGE_SIZE;
+		free_end_page = rchan->alloc_size / PAGE_SIZE;
+		for (i = 0, j = free_start_page; j < free_end_page; i++, j++)
+			rchan->shrink_page_array[i] = rchan->buf_page_array[j];
+	}
+
+	rchan->resize_page_array = alloc_page_array(rchan->resize_alloc_size,
+					    &rchan->resize_page_count, &err);
+	if (rchan->resize_page_array == NULL)
+		goto cleanup;
+
+	old_cur_idx = relay_get_offset(rchan, NULL);
+	clear_resize_offset(rchan);
+	newsize = rchan->resize_alloc_size;
+	oldsize = rchan->alloc_size;
+	if (newsize > oldsize)
+		setup_expand_buf(rchan, newsize, oldsize, rchan->n_bufs);
+	else
+		setup_shrink_buf(rchan);
+
+	rchan->resize_buf = vmap(rchan->resize_page_array, rchan->resize_page_count, GFP_KERNEL, PAGE_KERNEL);
+
+	if (rchan->resize_buf == NULL)
+		goto cleanup;
+
+	rchan->replace_buffer = 1;
+	rchan->resizing = 0;
+
+	rchan->callbacks->needs_resize(rchan->id, RELAY_RESIZE_REPLACE, 0, 0);
+	return;
+
+cleanup:
+	cleanup_failed_alloc(rchan);
+	rchan->resize_err = -ENOMEM;
+	return;
+}
+
+/**
+ *	relaybuf_free - free a resized channel buffer
+ *	@private: pointer to the channel struct
+ *
+ *	Internal - manages the de-allocation and unmapping of old channel
+ *	buffers.
+ */
+static void
+relaybuf_free(void *private)
+{
+	struct free_rchan_buf *free_buf = (struct free_rchan_buf *)private;
+	int i;
+
+	if (free_buf->unmap_buf)
+		vunmap(free_buf->unmap_buf);
+
+	for (i = 0; i < 3; i++) {
+		if (!free_buf->page_array[i].array)
+			continue;
+		if (free_buf->page_array[i].count)
+			depopulate_page_array(free_buf->page_array[i].array,
+					      free_buf->page_array[i].count);
+		free_page_array(free_buf->page_array[i].array);
+	}
+
+	kfree(free_buf);
+}
+
+/**
+ *	calc_order - determine the power-of-2 order of a resize
+ *	@high: the larger size
+ *	@low: the smaller size
+ *
+ *	Returns order
+ */
+static inline int
+calc_order(u32 high, u32 low)
+{
+	int order = 0;
+	
+	if (!high || !low || high <= low)
+		return 0;
+	
+	while (high > low) {
+		order++;
+		high /= 2;
+	}
+	
+	return order;
+}
+
+/**
+ *	check_size - check the sanity of the requested channel size
+ *	@rchan: the channel
+ *	@nbufs: the new number of sub-buffers
+ *	@err: return code
+ *
+ *	Returns the non-zero total buffer size if ok, otherwise 0 and
+ *	sets errcode if not.
+ */
+static inline u32
+check_size(struct rchan *rchan, u32 nbufs, int *err)
+{
+	u32 new_channel_size = 0;
+
+	*err = 0;
+	
+	if (nbufs > rchan->n_bufs) {
+		rchan->resize_order = calc_order(nbufs, rchan->n_bufs);
+		if (!rchan->resize_order) {
+			*err = -EINVAL;
+			goto out;
+		}
+
+		new_channel_size = rchan->buf_size * nbufs;
+		if (new_channel_size > rchan->resize_max) {
+			*err = -EINVAL;
+			goto out;
+		}
+	} else if (nbufs < rchan->n_bufs) {
+		if (rchan->n_bufs < 2) {
+			*err = -EINVAL;
+			goto out;
+		}
+		rchan->resize_order = -calc_order(rchan->n_bufs, nbufs);
+		if (!rchan->resize_order) {
+			*err = -EINVAL;
+			goto out;
+		}
+		
+		new_channel_size = rchan->buf_size * nbufs;
+		if (new_channel_size < rchan->resize_min) {
+			*err = -EINVAL;
+			goto out;
+		}
+	} else
+		*err = -EINVAL;
+out:
+	return new_channel_size;
+}
+
+/**
+ *	__relay_realloc_buffer - allocate a new channel buffer
+ *	@rchan: the channel
+ *	@new_nbufs: the new number of sub-buffers
+ *	@async: do the allocation using a work queue
+ *
+ *	Internal - see relay_realloc_buffer() for details.
+ */
+static int
+__relay_realloc_buffer(struct rchan *rchan, u32 new_nbufs, int async)
+{
+	u32 new_channel_size;
+	int err = 0;
+	
+	if (new_nbufs == rchan->n_bufs)
+		return -EINVAL;
+		
+	if (down_trylock(&rchan->resize_sem))
+		return -EBUSY;
+
+	if (rchan->init_buf) {
+		err = -EPERM;
+		goto out;
+	}
+
+	if (rchan->replace_buffer) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if (rchan->resizing) {
+		err = -EBUSY;
+		goto out;
+	} else
+		rchan->resizing = 1;
+
+	if (rchan->resize_failures > MAX_RESIZE_FAILURES) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	new_channel_size = check_size(rchan, new_nbufs, &err);
+	if (err)
+		goto out;
+	
+	rchan->resize_n_bufs = new_nbufs;
+	rchan->resize_buf_size = rchan->buf_size;
+	rchan->resize_alloc_size = FIX_SIZE(new_channel_size);
+	
+	if (async) {
+		INIT_WORK(&rchan->work, relaybuf_alloc, rchan);
+		schedule_delayed_work(&rchan->work, 1);
+	} else
+		relaybuf_alloc((void *)rchan);
+out:
+	up(&rchan->resize_sem);
+	
+	return err;
+}
+
+/**
+ *	relay_realloc_buffer - allocate a new channel buffer
+ *	@rchan_id: the channel id
+ *	@bufsize: the new sub-buffer size
+ *	@nbufs: the new number of sub-buffers
+ *
+ *	Allocates a new channel buffer using the specified sub-buffer size
+ *	and count.  If async is non-zero, the allocation is done in the
+ *	background using a work queue.  When the allocation has completed,
+ *	the needs_resize() callback is called with a resize_type of
+ *	RELAY_RESIZE_REPLACE.  This function doesn't replace the old buffer
+ *	with the new - see relay_replace_buffer().  See
+ *	Documentation/filesystems/relayfs.txt for more details.
+ *
+ *	Returns 0 on success, or errcode if the channel is busy or if
+ *	the allocation couldn't happen for some reason.
+ */
+int
+relay_realloc_buffer(int rchan_id, u32 new_nbufs, int async)
+{
+	int err;
+	
+	struct rchan *rchan;
+
+	rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return -EBADF;
+
+	err = __relay_realloc_buffer(rchan, new_nbufs, async);
+	
+	rchan_put(rchan);
+
+	return err;
+}
+
+/**
+ *	expand_cancel_check - check whether the current expand needs canceling
+ *	@rchan: the channel
+ *
+ *	Returns 1 if the expand should be canceled, 0 otherwise.
+ */
+static int
+expand_cancel_check(struct rchan *rchan)
+{
+	if (rchan->buf_id >= rchan->expand_buf_id)
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ *	shrink_cancel_check - check whether the current shrink needs canceling
+ *	@rchan: the channel
+ *
+ *	Returns 1 if the shrink should be canceled, 0 otherwise.
+ */
+static int
+shrink_cancel_check(struct rchan *rchan, u32 newsize)
+{
+	u32 active_bufs = rchan->bufs_produced - rchan->bufs_consumed + 1;
+	u32 cur_idx = relay_get_offset(rchan, NULL);
+
+	if (cur_idx >= newsize)
+		return 1;
+
+	if (active_bufs > 1)
+		return 1;
+
+	return 0;
+}
+
+/**
+ *	switch_rchan_buf - do_replace_buffer helper
+ */
+static void
+switch_rchan_buf(struct rchan *rchan,
+		 int newsize,
+		 int oldsize,
+		 u32 old_nbufs,
+		 u32 cur_idx)
+{
+	u32 newbufs, cur_bufno;
+	int i;
+
+	cur_bufno = cur_idx / rchan->buf_size;
+
+	rchan->buf = rchan->resize_buf;
+	rchan->alloc_size = rchan->resize_alloc_size;
+	rchan->n_bufs = rchan->resize_n_bufs;
+
+	if (newsize > oldsize) {
+		u32 ge = rchan->resize_offset.ge;
+		u32 moved_buf = ge / rchan->buf_size;
+
+		newbufs = (newsize - oldsize) / rchan->buf_size;
+		for (i = moved_buf; i < old_nbufs; i++) {
+			if (using_lockless(rchan))
+				atomic_set(&fill_count(rchan, i + newbufs), 
+					   atomic_read(&fill_count(rchan, i)));
+			rchan->unused_bytes[i + newbufs] = rchan->unused_bytes[i];
+ 		}
+		for (i = moved_buf; i < moved_buf + newbufs; i++) {
+			if (using_lockless(rchan))
+				atomic_set(&fill_count(rchan, i),
+					   (int)RELAY_BUF_SIZE(offset_bits(rchan)));
+			rchan->unused_bytes[i] = 0;
+		}
+	}
+
+	rchan->buf_idx = cur_bufno;
+
+	if (!using_lockless(rchan)) {
+		cur_write_pos(rchan) = rchan->buf + cur_idx;
+		write_buf(rchan) = rchan->buf + cur_bufno * rchan->buf_size;
+		write_buf_end(rchan) = write_buf(rchan) + rchan->buf_size;
+		write_limit(rchan) = write_buf_end(rchan) - rchan->end_reserve;
+	} else {
+		idx(rchan) &= idx_mask(rchan);
+		bufno_bits(rchan) += rchan->resize_order;
+		idx_mask(rchan) =
+			(1UL << (bufno_bits(rchan) + offset_bits(rchan))) - 1;
+	}
+}
+
+/**
+ *	do_replace_buffer - does the work of channel buffer replacement
+ *	@rchan: the channel
+ *	@newsize: new channel buffer size
+ *	@oldsize: old channel buffer size
+ *	@old_n_bufs: old channel sub-buffer count
+ *
+ *	Returns 0 if replacement happened, 1 if canceled
+ *
+ *	Does the work of switching buffers and fixing everything up
+ *	so the channel can continue with a new size.
+ */
+static int
+do_replace_buffer(struct rchan *rchan,
+		  int newsize,
+		  int oldsize,
+		  u32 old_nbufs)
+{
+	u32 cur_idx;
+	int err = 0;
+	int canceled;
+
+	cur_idx = relay_get_offset(rchan, NULL);
+
+	if (newsize > oldsize)
+		canceled = expand_cancel_check(rchan);
+	else
+		canceled = shrink_cancel_check(rchan, newsize);
+
+	if (canceled) {
+		err = -EAGAIN;
+		goto out;
+	}
+
+	switch_rchan_buf(rchan, newsize, oldsize, old_nbufs, cur_idx);
+
+	if (rchan->resize_offset.delta)
+		update_file_offsets(rchan);
+
+	atomic_set(&rchan->suspended, 0);
+
+	rchan->old_buf_page_array = rchan->buf_page_array;
+	rchan->buf_page_array = rchan->resize_page_array;
+	rchan->buf_page_count = rchan->resize_page_count;
+	rchan->resize_page_array = NULL;
+	rchan->resize_page_count = 0;
+	rchan->resize_buf = NULL;
+	rchan->resize_buf_size = 0;
+	rchan->resize_alloc_size = 0;
+	rchan->resize_n_bufs = 0;
+	rchan->resize_err = 0;
+	rchan->resize_order = 0;
+out:
+	rchan->callbacks->needs_resize(rchan->id,
+				       RELAY_RESIZE_REPLACED,
+				       rchan->buf_size,
+				       rchan->n_bufs);
+	return err;
+}
+
+/**
+ *	add_free_page_array - add a page_array to be freed
+ *	@free_rchan_buf: the free_rchan_buf struct
+ *	@page_array: the page array to free
+ *	@page_count: the number of pages to free, 0 to free the array only
+ *
+ *	Internal - Used add page_arrays to be freed asynchronously.
+ */
+static inline void
+add_free_page_array(struct free_rchan_buf *free_rchan_buf,
+		    struct page **page_array, int page_count)
+{
+	int cur = free_rchan_buf->cur++;
+	
+	free_rchan_buf->page_array[cur].array = page_array;
+	free_rchan_buf->page_array[cur].count = page_count;
+}
+
+/**
+ *	free_rchan_buf - free a channel buffer
+ *	@buf: pointer to the buffer to free
+ *	@page_array: pointer to the buffer's page array
+ *	@page_count: number of pages in page array
+ */
+int
+free_rchan_buf(void *buf, struct page **page_array, int page_count)
+{
+	struct free_rchan_buf *free_buf;
+
+	free_buf = kmalloc(sizeof(struct free_rchan_buf), GFP_ATOMIC);
+	if (!free_buf)
+		return -ENOMEM;
+	memset(free_buf, 0, sizeof(struct free_rchan_buf));
+
+	free_buf->unmap_buf = buf;
+	add_free_page_array(free_buf, page_array, page_count);
+
+	INIT_WORK(&free_buf->work, relaybuf_free, free_buf);
+	schedule_delayed_work(&free_buf->work, 1);
+
+	return 0;
+}
+
+/**
+ *	free_replaced_buffer - free a channel's old buffer
+ *	@rchan: the channel
+ *	@oldbuf: the old buffer
+ *	@oldsize: old buffer size
+ *
+ *	Frees a channel buffer via work queue.
+ */
+static int
+free_replaced_buffer(struct rchan *rchan, char *oldbuf, int oldsize)
+{
+	struct free_rchan_buf *free_buf;
+
+	free_buf = kmalloc(sizeof(struct free_rchan_buf), GFP_ATOMIC);
+	if (!free_buf)
+		return -ENOMEM;
+	memset(free_buf, 0, sizeof(struct free_rchan_buf));
+
+	free_buf->unmap_buf = oldbuf;
+	add_free_page_array(free_buf, rchan->old_buf_page_array, 0);
+	rchan->old_buf_page_array = NULL;
+	add_free_page_array(free_buf, rchan->expand_page_array, 0);
+	add_free_page_array(free_buf, rchan->shrink_page_array, rchan->shrink_page_count);
+
+	rchan->expand_page_array = NULL;
+	rchan->expand_page_count = 0;
+	rchan->shrink_page_array = NULL;
+	rchan->shrink_page_count = 0;
+
+	INIT_WORK(&free_buf->work, relaybuf_free, free_buf);
+	schedule_delayed_work(&free_buf->work, 1);
+
+	return 0;
+}
+
+/**
+ *	free_canceled_resize - free buffers allocated for a canceled resize
+ *	@rchan: the channel
+ *
+ *	Frees canceled buffers via work queue.
+ */
+static int
+free_canceled_resize(struct rchan *rchan)
+{
+	struct free_rchan_buf *free_buf;
+
+	free_buf = kmalloc(sizeof(struct free_rchan_buf), GFP_ATOMIC);
+	if (!free_buf)
+		return -ENOMEM;
+	memset(free_buf, 0, sizeof(struct free_rchan_buf));
+
+	if (rchan->resize_alloc_size > rchan->alloc_size)
+		add_free_page_array(free_buf, rchan->expand_page_array, rchan->expand_page_count);
+	else
+		add_free_page_array(free_buf, rchan->shrink_page_array, 0);
+	
+	add_free_page_array(free_buf, rchan->resize_page_array, 0);
+	free_buf->unmap_buf = rchan->resize_buf;
+
+	rchan->expand_page_array = NULL;
+	rchan->expand_page_count = 0;
+	rchan->shrink_page_array = NULL;
+	rchan->shrink_page_count = 0;
+	rchan->resize_page_array = NULL;
+	rchan->resize_page_count = 0;
+	rchan->resize_buf = NULL;
+
+	INIT_WORK(&free_buf->work, relaybuf_free, free_buf);
+	schedule_delayed_work(&free_buf->work, 1);
+
+	return 0;
+}
+
+/**
+ *	__relay_replace_buffer - replace channel buffer with new buffer
+ *	@rchan: the channel
+ *
+ *	Internal - see relay_replace_buffer() for details.
+ *
+ *	Returns 0 if successful, negative otherwise.
+ */
+static int
+__relay_replace_buffer(struct rchan *rchan)
+{
+	int oldsize;
+	int err = 0;
+	char *oldbuf;
+	
+	if (down_trylock(&rchan->resize_sem))
+		return -EBUSY;
+
+	if (rchan->init_buf) {
+		err = -EPERM;
+		goto out;
+	}
+
+	if (!rchan->replace_buffer)
+		goto out;
+
+	if (rchan->resizing) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if (rchan->resize_buf == NULL) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	oldbuf = rchan->buf;
+	oldsize = rchan->alloc_size;
+
+	err = do_replace_buffer(rchan, rchan->resize_alloc_size,
+				oldsize, rchan->n_bufs);
+	if (err == 0)
+		err = free_replaced_buffer(rchan, oldbuf, oldsize);
+	else
+		err = free_canceled_resize(rchan);
+out:
+	rchan->replace_buffer = 0;
+	up(&rchan->resize_sem);
+	
+	return err;
+}
+
+/**
+ *	relay_replace_buffer - replace channel buffer with new buffer
+ *	@rchan_id: the channel id
+ *
+ *	Replaces the current channel buffer with the new buffer allocated
+ *	by relay_alloc_buffer and contained in the channel struct.  When the
+ *	replacement is complete, the needs_resize() callback is called with
+ *	RELAY_RESIZE_REPLACED.
+ *
+ *	Returns 0 on success, or errcode if the channel is busy or if
+ *	the replacement or previous allocation didn't happen for some reason.
+ */
+int
+relay_replace_buffer(int rchan_id)
+{
+	int err;
+	
+	struct rchan *rchan;
+
+	rchan = rchan_get(rchan_id);
+	if (rchan == NULL)
+		return -EBADF;
+
+	err = __relay_replace_buffer(rchan);
+	
+	rchan_put(rchan);
+
+	return err;
+}
+
+EXPORT_SYMBOL(relay_realloc_buffer);
+EXPORT_SYMBOL(relay_replace_buffer);
+
diff -uNrp linux-2.6.9/fs/relayfs/resize.h linux-2.6.9-ltt-r12/fs/relayfs/resize.h
--- linux-2.6.9/fs/relayfs/resize.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/fs/relayfs/resize.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,51 @@
+#ifndef _RELAY_RESIZE_H
+#define _RELAY_RESIZE_H
+
+/* 
+ * If the channel usage has been below the low water mark for more than
+ * this amount of time, we can shrink the buffer if necessary.
+ */
+#define SHRINK_TIMER_SECS	60
+
+/* This inspired by rtai/shmem */
+#define FIX_SIZE(x) (((x) - 1) & PAGE_MASK) + PAGE_SIZE
+
+/* Don't attempt resizing again after this many failures */
+#define MAX_RESIZE_FAILURES	1
+
+/* Trigger resizing if a resizable channel is this full */
+#define RESIZE_THRESHOLD	3 / 4
+
+/*
+ * Used for deferring resized channel free
+ */
+struct free_rchan_buf
+{
+	char *unmap_buf;
+	struct 
+	{
+		struct page **array;
+		int count;
+	} page_array[3];
+	
+	int cur;
+	struct work_struct work;	/* resize de-allocation work struct */
+};
+
+extern void *
+alloc_rchan_buf(unsigned long size,
+		struct page ***page_array,
+		int *page_count);
+
+extern int
+free_rchan_buf(void *buf,
+	       struct page **page_array,
+	       int page_count);
+
+extern void
+expand_check(struct rchan *rchan);
+
+extern void
+init_shrink_timer(struct rchan *rchan);
+
+#endif/* _RELAY_RESIZE_H */
diff -uNrp linux-2.6.9/fs/select.c linux-2.6.9-ltt-r12/fs/select.c
--- linux-2.6.9/fs/select.c	2004-10-18 23:53:07.000000000 +0200
+++ linux-2.6.9-ltt-r12/fs/select.c	2005-08-15 10:51:46.000000000 +0200
@@ -21,6 +21,7 @@
 #include <linux/personality.h> /* for STICKY_TIMEOUTS */
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/ltt-events.h>
 
 #include <asm/uaccess.h>
 
@@ -222,6 +223,10 @@ int do_select(int n, fd_set_bits *fds, l
 				file = fget(i);
 				if (file) {
 					f_op = file->f_op;
+					ltt_ev_file_system(LTT_EV_FILE_SYSTEM_SELECT,
+							   i /*  The fd*/,
+							   __timeout,
+							   NULL);
 					mask = DEFAULT_POLLMASK;
 					if (f_op && f_op->poll)
 						mask = (*f_op->poll)(file, retval ? NULL : wait);
@@ -409,6 +414,10 @@ static void do_pollfd(unsigned int num, 
 			struct file * file = fget(fd);
 			mask = POLLNVAL;
 			if (file != NULL) {
+			        ltt_ev_file_system(LTT_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 -uNrp linux-2.6.9/include/asm-generic/relay.h linux-2.6.9-ltt-r12/include/asm-generic/relay.h
--- linux-2.6.9/include/asm-generic/relay.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/asm-generic/relay.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,76 @@
+#ifndef _ASM_GENERIC_RELAY_H
+#define _ASM_GENERIC_RELAY_H
+/*
+ * linux/include/asm-generic/relay.h
+ *
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * Architecture-independent definitions for relayfs
+ */
+
+#include <linux/relayfs_fs.h>
+
+/**
+ *	get_time_delta - utility function for getting time delta
+ *	@now: pointer to a timeval struct that may be given current time
+ *	@rchan: the channel
+ *
+ *	Returns the time difference between the current time and the buffer
+ *	start time.
+ */
+static inline u32
+get_time_delta(struct timeval *now, struct rchan *rchan)
+{
+	u32 time_delta;
+
+	do_gettimeofday(now);
+	time_delta = calc_time_delta(now, &rchan->buf_start_time);
+
+	return time_delta;
+}
+
+/**
+ *	get_timestamp - utility function for getting a time and TSC pair
+ *	@now: current time
+ *	@tsc: the TSC associated with now
+ *	@rchan: the channel
+ *
+ *	Sets the value pointed to by now to the current time. Value pointed to
+ *	by tsc is not set since there is no generic TSC support.
+ */
+static inline void 
+get_timestamp(struct timeval *now, 
+	      u32 *tsc,
+	      struct rchan *rchan)
+{
+	do_gettimeofday(now);
+}
+
+/**
+ *	get_time_or_tsc: - Utility function for getting a time or a TSC.
+ *	@now: current time
+ *	@tsc: current TSC
+ *	@rchan: the channel
+ *
+ *	Sets the value pointed to by now to the current time.
+ */
+static inline void 
+get_time_or_tsc(struct timeval *now, 
+		u32 *tsc,
+		struct rchan *rchan)
+{
+	do_gettimeofday(now);
+}
+
+/**
+ *	have_tsc - does this platform have a useable TSC?
+ *
+ *	Returns 0.
+ */
+static inline int 
+have_tsc(void)
+{
+	return 0;
+}
+#endif
diff -uNrp linux-2.6.9/include/asm-i386/adeos.h linux-2.6.9-ltt-r12/include/asm-i386/adeos.h
--- linux-2.6.9/include/asm-i386/adeos.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/asm-i386/adeos.h	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,514 @@
+/*
+ *   include/asm-i386/adeos.h
+ *
+ *   Copyright (C) 2002 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __I386_ADEOS_H
+#define __I386_ADEOS_H
+
+#include <irq_vectors.h>
+#include <asm/ptrace.h>
+#include <linux/cpumask.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+
+#define ADEOS_ARCH_STRING   "r12/x86"
+#define ADEOS_MAJOR_NUMBER  12
+#define ADEOS_MINOR_NUMBER  255
+
+extern int adp_pipelined;
+
+#ifdef CONFIG_SMP
+
+#include <asm/fixmap.h>
+#include <asm/mpspec.h>
+#include <mach_apicdef.h>
+
+#define ADEOS_NR_CPUS          NR_CPUS
+#define ADEOS_CRITICAL_VECTOR  0xf9 /* Used by adeos_critical_enter/exit() */
+#define ADEOS_CRITICAL_IPI     (ADEOS_CRITICAL_VECTOR - FIRST_EXTERNAL_VECTOR)
+
+static __inline int adeos_smp_apic_id(void) {
+    return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
+}
+
+extern volatile u8 __adeos_apicid_2_cpuid[];
+
+int __adeos_hw_cpuid(void);
+
+cpumask_t __adeos_set_irq_affinity(unsigned irq,
+				   cpumask_t cpumask);
+
+#define adeos_processor_id()   __adeos_hw_cpuid()
+
+#define adeos_declare_cpuid    int cpuid
+#define adeos_load_cpuid()     do { \
+                                  (cpuid) = adeos_processor_id();	\
+                               } while(0)
+#define adeos_lock_cpu(flags)  do { \
+                                  adeos_hw_local_irq_save(flags); \
+                                  (cpuid) = adeos_processor_id(); \
+                               } while(0)
+#define adeos_unlock_cpu(flags) adeos_hw_local_irq_restore(flags)
+#define adeos_get_cpu(flags)    adeos_lock_cpu(flags)
+#define adeos_put_cpu(flags)    adeos_unlock_cpu(flags)
+#define adp_current             (adp_cpu_current[adeos_processor_id()])
+
+#else  /* !CONFIG_SMP */
+
+#define ADEOS_NR_CPUS          1
+#define adeos_processor_id()   0
+/* Array references using this index should be optimized out. */
+#define adeos_declare_cpuid    const int cpuid = 0
+#define adeos_load_cpuid()      /* nop */
+#define adeos_lock_cpu(flags)   adeos_hw_local_irq_save(flags)
+#define adeos_unlock_cpu(flags) adeos_hw_local_irq_restore(flags)
+#define adeos_get_cpu(flags)    do { flags = flags; } while(0)
+#define adeos_put_cpu(flags)    /* nop */
+#define adp_current             (adp_cpu_current[0])
+
+#endif /* CONFIG_SMP */
+
+ /* IDT fault vectors */
+#define ADEOS_NR_FAULTS         32
+/* Pseudo-vectors used for kernel events */
+#define ADEOS_FIRST_KEVENT      ADEOS_NR_FAULTS
+#define ADEOS_SYSCALL_PROLOGUE  (ADEOS_FIRST_KEVENT)
+#define ADEOS_SYSCALL_EPILOGUE  (ADEOS_FIRST_KEVENT + 1)
+#define ADEOS_SCHEDULE_HEAD     (ADEOS_FIRST_KEVENT + 2)
+#define ADEOS_SCHEDULE_TAIL     (ADEOS_FIRST_KEVENT + 3)
+#define ADEOS_ENTER_PROCESS     (ADEOS_FIRST_KEVENT + 4)
+#define ADEOS_EXIT_PROCESS      (ADEOS_FIRST_KEVENT + 5)
+#define ADEOS_SIGNAL_PROCESS    (ADEOS_FIRST_KEVENT + 6)
+#define ADEOS_KICK_PROCESS      (ADEOS_FIRST_KEVENT + 7)
+#define ADEOS_RENICE_PROCESS    (ADEOS_FIRST_KEVENT + 8)
+#define ADEOS_USER_EVENT        (ADEOS_FIRST_KEVENT + 9)
+#define ADEOS_LAST_KEVENT       (ADEOS_USER_EVENT)
+
+#define ADEOS_NR_EVENTS         (ADEOS_LAST_KEVENT + 1)
+
+typedef struct adevinfo {
+
+    unsigned domid;
+    unsigned event;
+    void *evdata;
+
+    volatile int propagate;	/* Private */
+
+} adevinfo_t;
+
+typedef struct adsysinfo {
+
+    int ncpus;			/* Number of CPUs on board */
+
+    u64 cpufreq;		/* CPU frequency (in Hz) */
+
+    /* Arch-dependent block */
+
+    struct {
+	unsigned tmirq;		/* Timer tick IRQ */
+	u64 tmfreq;		/* Timer frequency */
+    } archdep;
+
+} adsysinfo_t;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+/* We must cover the whole IRQ space to map the local timer interrupt
+   (#207). */
+#ifdef CONFIG_PCI_MSI
+#define IPIPE_NR_XIRQS NR_IRQS
+#else /* CONFIG_PCI_MSI */
+#define IPIPE_NR_XIRQS   224
+#endif /* CONFIG_PCI_MSI */
+/* If the APIC is enabled, then we expose four service vectors in the
+   APIC space which are freely available to domains. */
+#define ADEOS_SERVICE_VECTOR0  0xf5
+#define ADEOS_SERVICE_IPI0     (ADEOS_SERVICE_VECTOR0 - FIRST_EXTERNAL_VECTOR)
+#define ADEOS_SERVICE_VECTOR1  0xf6
+#define ADEOS_SERVICE_IPI1     (ADEOS_SERVICE_VECTOR1 - FIRST_EXTERNAL_VECTOR)
+#define ADEOS_SERVICE_VECTOR2  0xf7
+#define ADEOS_SERVICE_IPI2     (ADEOS_SERVICE_VECTOR2 - FIRST_EXTERNAL_VECTOR)
+#define ADEOS_SERVICE_VECTOR3  0xf8
+#define ADEOS_SERVICE_IPI3     (ADEOS_SERVICE_VECTOR3 - FIRST_EXTERNAL_VECTOR)
+#else /* !CONFIG_X86_LOCAL_APIC */
+#define IPIPE_NR_XIRQS   NR_IRQS
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+/* Number of virtual IRQs */
+#define IPIPE_NR_VIRQS   BITS_PER_LONG
+/* First virtual IRQ # */
+#define IPIPE_VIRQ_BASE  (((IPIPE_NR_XIRQS + BITS_PER_LONG - 1) / BITS_PER_LONG) * BITS_PER_LONG)
+/* Total number of IRQ slots */
+#define IPIPE_NR_IRQS     (IPIPE_VIRQ_BASE + IPIPE_NR_VIRQS)
+/* Number of indirect words needed to map the whole IRQ space. */
+#define IPIPE_IRQ_IWORDS  ((IPIPE_NR_IRQS + BITS_PER_LONG - 1) / BITS_PER_LONG)
+#define IPIPE_IRQ_IMASK   (BITS_PER_LONG - 1)
+#define IPIPE_IRQ_ISHIFT  5	/* 2^5 for 32bits arch. */
+
+#define IPIPE_IRQMASK_ANY   (~0L)
+#define IPIPE_IRQMASK_VIRT  (IPIPE_IRQMASK_ANY << (IPIPE_VIRQ_BASE / BITS_PER_LONG))
+
+typedef struct adomain {
+
+    /* -- Section: offset-based references are made on these fields
+       from inline assembly code. Please don't move or reorder. */
+    void (*dswitch)(void);	/* Domain switch hook */
+#ifdef CONFIG_ADEOS_THREADS
+    int *esp[ADEOS_NR_CPUS];	/* Domain stack pointers */
+#endif /* CONFIG_ADEOS_THREADS */
+    /* -- End of section. */
+
+    struct list_head p_link;	/* Link in pipeline */
+
+    struct adcpudata {
+	volatile unsigned long status;
+	volatile unsigned long irq_pending_hi;
+	volatile unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
+	volatile unsigned irq_hits[IPIPE_NR_IRQS];
+#ifdef CONFIG_ADEOS_THREADS
+	adevinfo_t event_info;
+#endif /* CONFIG_ADEOS_THREADS */
+    } cpudata[ADEOS_NR_CPUS];
+
+    struct {
+	int (*acknowledge)(unsigned irq);
+	void (*handler)(unsigned irq);
+	unsigned long control;
+    } irqs[IPIPE_NR_IRQS];
+
+    struct {
+	void (*handler)(adevinfo_t *evinfo);
+    } events[ADEOS_NR_EVENTS];
+
+    struct adomain *m_link;	/* Link in mutex sleep queue */
+
+    unsigned long flags;
+
+    unsigned domid;
+
+    const char *name;
+
+    int priority;
+
+    int ptd_keymax;
+    int ptd_keycount;
+    unsigned long ptd_keymap;
+    void (*ptd_setfun)(int, void *);
+    void *(*ptd_getfun)(int);
+
+#ifdef CONFIG_ADEOS_THREADS
+    int *estackbase[ADEOS_NR_CPUS];
+#endif /* CONFIG_ADEOS_THREADS */
+
+} adomain_t;
+
+/* The following macros must be used hw interrupts off. */
+
+#define __adeos_set_irq_bit(adp,cpuid,irq) \
+do { \
+    if (!test_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) { \
+        __set_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+        __set_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[cpuid].irq_pending_hi); \
+       } \
+} while(0)
+
+#define __adeos_clear_pend(adp,cpuid,irq) \
+do { \
+    __clear_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+    if ((adp)->cpudata[cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT] == 0) \
+        __clear_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[cpuid].irq_pending_hi); \
+} while(0)
+
+#define __adeos_lock_irq(adp,cpuid,irq) \
+do { \
+    if (!test_and_set_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) \
+	__adeos_clear_pend(adp,cpuid,irq); \
+} while(0)
+
+#define __adeos_unlock_irq(adp,irq) \
+do { \
+    int __cpuid, __nr_cpus = num_online_cpus();			       \
+    if (test_and_clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control)) \
+	for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++)      \
+         if ((adp)->cpudata[__cpuid].irq_hits[irq] > 0) { /* We need atomic ops next. */ \
+           set_bit(irq & IPIPE_IRQ_IMASK,&(adp)->cpudata[__cpuid].irq_pending_lo[irq >> IPIPE_IRQ_ISHIFT]); \
+           set_bit(irq >> IPIPE_IRQ_ISHIFT,&(adp)->cpudata[__cpuid].irq_pending_hi); \
+         } \
+} while(0)
+
+#define __adeos_clear_irq(adp,irq) \
+do { \
+    int __cpuid, __nr_cpus = num_online_cpus(); \
+    clear_bit(IPIPE_LOCK_FLAG,&(adp)->irqs[irq].control); \
+    for (__cpuid = 0; __cpuid < __nr_cpus; __cpuid++) {	\
+       (adp)->cpudata[__cpuid].irq_hits[irq] = 0; \
+       __adeos_clear_pend(adp,__cpuid,irq); \
+    } \
+} while(0)
+
+#define adeos_virtual_irq_p(irq) ((irq) >= IPIPE_VIRQ_BASE && \
+				  (irq) < IPIPE_NR_IRQS)
+
+#define adeos_hw_save_flags_and_sti(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
+#define adeos_hw_cli() 			__asm__ __volatile__("cli": : :"memory")
+#define adeos_hw_sti()			__asm__ __volatile__("sti": : :"memory")
+#define adeos_hw_local_irq_save(x)    __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define adeos_hw_local_irq_restore(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
+#define adeos_hw_local_irq_flags(x)   __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
+#define adeos_hw_test_iflag(x)        ((x) & (1<<9))
+#define adeos_hw_irqs_disabled()	\
+({					\
+	unsigned long flags;		\
+	adeos_hw_local_irq_flags(flags);	\
+	!adeos_hw_test_iflag(flags);	\
+})
+
+#define adeos_hw_tsc(t)  __asm__ __volatile__("rdtsc" : "=A" (t))
+#define adeos_cpu_freq() ({ unsigned long long __freq = cpu_has_tsc?(1000LL * cpu_khz):CLOCK_TICK_RATE; __freq; })
+
+#ifdef CONFIG_ADEOS_PREEMPT_RT
+/* We are over a combo Adeos+PREEMPT_RT _patched_ kernel, but
+   CONFIG_PREEMPT_RT is not necessarily enabled; use the raw spinlock
+   support for Adeos. */
+#define adeos_spin_lock(x)     __raw_spin_lock(x)
+#define adeos_spin_unlock(x)   __raw_spin_unlock(x)
+#define adeos_spin_trylock(x)  __raw_spin_trylock(x)
+#define adeos_write_lock(x)    __raw_write_lock(x)
+#define adeos_write_unlock(x)  __raw_write_unlock(x)
+#define adeos_write_trylock(x) __raw_write_trylock(x)
+#define adeos_read_lock(x)     __raw_read_lock(x)
+#define adeos_read_unlock(x)   __raw_read_unlock(x)
+#else /* !CONFIG_ADEOS_PREEMPT_RT */
+#define adeos_spin_lock(x)     _spin_lock(x)
+#define adeos_spin_unlock(x)   _spin_unlock(x)
+#define adeos_spin_trylock(x)  _spin_trylock(x)
+#define adeos_write_lock(x)    _write_lock(x)
+#define adeos_write_unlock(x)  _write_unlock(x)
+#define adeos_write_trylock(x) _write_trylock(x)
+#define adeos_read_lock(x)     _read_lock(x)
+#define adeos_read_unlock(x)   _read_unlock(x)
+#define raw_spinlock_t         spinlock_t
+#define RAW_SPIN_LOCK_UNLOCKED SPIN_LOCK_UNLOCKED
+#define raw_rwlock_t           rwlock_t
+#define RAW_RW_LOCK_UNLOCKED   RW_LOCK_UNLOCKED
+#endif /* CONFIG_ADEOS_PREEMPT_RT */
+
+#define spin_lock_irqsave_hw(lock,flags)      adeos_spin_lock_irqsave(lock, flags)
+#define spin_unlock_irqrestore_hw(lock,flags) adeos_spin_unlock_irqrestore(lock, flags)
+
+#define adeos_spin_lock_irqsave(x,flags)  \
+do { \
+   adeos_hw_local_irq_save(flags); \
+   adeos_spin_lock(x); \
+} while (0)
+
+#define adeos_spin_unlock_irqrestore(x,flags)  \
+do { \
+   adeos_spin_unlock(x); \
+   adeos_hw_local_irq_restore(flags); \
+} while (0)
+
+#define adeos_spin_lock_disable(x)  \
+do { \
+   adeos_hw_cli(); \
+   adeos_spin_lock(x); \
+} while (0)
+
+#define adeos_spin_unlock_enable(x)  \
+do { \
+   adeos_spin_unlock(x); \
+   adeos_hw_sti(); \
+} while (0)
+
+#define adeos_read_lock_irqsave(lock, flags) \
+do { \
+   adeos_hw_local_irq_save(flags); \
+   adeos_read_lock(lock); \
+} while (0)
+
+#define adeos_read_unlock_irqrestore(lock, flags) \
+do { \
+   adeos_read_unlock(lock); \
+   adeos_hw_local_irq_restore(flags); \
+} while (0)
+
+#define adeos_write_lock_irqsave(lock, flags) \
+do { \
+   adeos_hw_local_irq_save(flags); \
+   adeos_write_lock(lock); \
+} while (0)
+
+#define adeos_write_unlock_irqrestore(lock, flags) \
+do { \
+   adeos_write_unlock(lock); \
+   adeos_hw_local_irq_restore(flags); \
+} while (0)
+
+#ifndef STR
+#define __STR(x) #x
+#define STR(x) __STR(x)
+#endif
+
+#ifndef SYMBOL_NAME_STR
+#define SYMBOL_NAME_STR(X) #X
+#endif
+
+/* Private interface -- Internal use only */
+
+struct adattr;
+
+void __adeos_init(void);
+
+void __adeos_init_domain(adomain_t *adp,
+			 struct adattr *attr);
+
+void __adeos_cleanup_domain(adomain_t *adp);
+
+void __adeos_send_IPI_mask(cpumask_t mask,
+			   int vector);
+
+void __adeos_send_IPI_allbutself(int vector);
+
+#ifdef CONFIG_ADEOS_THREADS
+
+#ifdef CONFIG_SMP
+
+/*
+ * __adeos_switch_to() -- Switch domain contexts. The current domain
+ * ("out") is switched out while the domain pointed by "in" is
+ * switched in. The current cpu identifier which is always known from
+ * callers is also passed to save a few cycles.  This code works out
+ * the following tasks: - build a resume frame for the suspended
+ * domain, - save it's stack pointer, - load the incoming domain's
+ * stack pointer, - update the global domain descriptor pointer, -
+ * then finally activate the resume frame of the incoming domain.
+ *
+ * SMP version also provides for safe CPU migration (i.e. the domain
+ * may be switched back in on behalf of a different CPU than the one
+ * which switched it out).
+ *
+ * NOTE: dswitch() takes no argument, so there is no specific handling
+ * of CONFIG_REGPARM needed. This routine must be called with hw
+ * interrupts off.
+ */
+
+static inline void __adeos_switch_to (adomain_t *out, adomain_t *in, int cpuid)
+
+{
+    __asm__ __volatile__( \
+	"pushl %%ebp\n\t" \
+	"pushl %%ecx\n\t" \
+	"pushl %%ebx\n\t" \
+	"pushl %%edi\n\t" \
+	"pushl %%esi\n\t" \
+	"movl %%eax, %%ecx\n\t" \
+	"leal adp_cpu_current(,%%eax,4),%%eax\n\t" \
+	"xchg (%%eax), %%edx\n\t" \
+	"pushl %%edx\n\t" \
+	"pushl $1f\n\t" \
+	"sall $2,%%ecx\n\t" \
+	"addl $4,%%ecx\n\t" \
+	"movl %%esp, (%%ecx,%%edx)\n\t" \
+	"movl (%%eax), %%eax\n\t" \
+	"movl (%%ecx,%%eax), %%esp\n\t" \
+	"ret\n\t" \
+	  /* Call domain switch hook (if any) */
+"1:      popl %%eax\n\t" \
+	"movl (%%eax), %%eax\n\t" \
+	"testl %%eax,%%eax\n\t" \
+	"je 2f\n\t" \
+	"call *%%eax\n\t" \
+	  /* Domain resume point */
+"2:      popl %%esi\n\t" \
+	"popl %%edi\n\t" \
+	"popl %%ebx\n\t" \
+	"popl %%ecx\n\t" \
+	"popl %%ebp\n\t" \
+	: /* no output */ \
+	: "a" (cpuid), "d" (in) \
+	: "memory", "cc");
+
+    barrier();
+}
+
+#else /* !CONFIG_SMP */
+
+static inline void __adeos_switch_to (adomain_t *out, adomain_t *in, int cpuid)
+
+{
+    __asm__ __volatile__( \
+	"pushl %%ebp\n\t" \
+	"pushl %%edx\n\t" \
+	"pushl %%ecx\n\t" \
+	"pushl %%ebx\n\t" \
+	"pushl %%edi\n\t" \
+	"pushl %%esi\n\t" \
+	"movl "SYMBOL_NAME_STR(adp_cpu_current)", %%edx\n\t" \
+	"pushl %%edx\n\t" \
+	"pushl $1f\n\t" \
+	"movl %%esp, 4(%%edx)\n\t" \
+	"movl 4(%%eax), %%esp\n\t" \
+	"movl %%eax, "SYMBOL_NAME_STR(adp_cpu_current)"\n\t" \
+	"ret\n\t" \
+	  /* Call domain switch hook (if any) */
+"1:      popl %%eax\n\t" \
+	"movl (%%eax),%%eax\n\t" \
+	"testl %%eax,%%eax\n\t" \
+	"je 2f\n\t" \
+	"call *%%eax\n\t" \
+	  /* Domain resume point */
+"2:      popl %%esi\n\t" \
+	"popl %%edi\n\t" \
+	"popl %%ebx\n\t" \
+	"popl %%ecx\n\t" \
+	"popl %%edx\n\t" \
+	"popl %%ebp\n\t" \
+	: /* no output */ \
+        : "a" (in));
+}
+
+#endif /* CONFIG_SMP */
+
+#endif /* CONFIG_ADEOS_THREADS */
+
+#define __adeos_check_platform() do { } while(0)
+
+#define __adeos_init_platform() do { } while(0)
+
+void __adeos_enable_pipeline(void);
+
+void __adeos_disable_pipeline(void);
+
+void __adeos_init_stage(adomain_t *adp);
+
+void fastcall __adeos_sync_stage(unsigned long syncmask);
+
+int __adeos_ack_system_irq(unsigned irq);
+
+int __adeos_handle_irq(struct pt_regs regs);
+
+extern struct pt_regs __adeos_tick_regs[];
+
+extern int __adeos_tick_irq;
+
+#ifdef CONFIG_X86_LOCAL_APIC
+extern int __adeos_apic_mapped;
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#endif /* !__I386_ADEOS_H */
diff -uNrp linux-2.6.9/include/asm-i386/apic.h linux-2.6.9-ltt-r12/include/asm-i386/apic.h
--- linux-2.6.9/include/asm-i386/apic.h	2004-10-18 23:55:29.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/asm-i386/apic.h	2005-08-15 10:31:45.000000000 +0200
@@ -68,7 +68,13 @@ int get_physical_broadcast(void);
 # define apic_write_around(x,y) apic_write_atomic((x),(y))
 #endif
 
+#ifdef CONFIG_ADEOS_CORE
+#define ack_APIC_irq() do { if (!adp_pipelined) __ack_APIC_irq(); } while(0)
+static inline void __ack_APIC_irq(void)
+#else /* !CONFIG_ADEOS_CORE */
+#define __ack_APIC_irq() ack_APIC_irq()
 static inline void ack_APIC_irq(void)
+#endif /* CONFIG_ADEOS_CORE */
 {
 	/*
 	 * ack_APIC_irq() actually gets compiled as a single instruction:
diff -uNrp linux-2.6.9/include/asm-i386/io_apic.h linux-2.6.9-ltt-r12/include/asm-i386/io_apic.h
--- linux-2.6.9/include/asm-i386/io_apic.h	2004-10-18 23:54:38.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/asm-i386/io_apic.h	2005-08-15 10:31:45.000000000 +0200
@@ -16,7 +16,9 @@
 #ifdef CONFIG_PCI_MSI
 static inline int use_pci_vector(void)	{return 1;}
 static inline void disable_edge_ioapic_vector(unsigned int vector) { }
+#ifndef CONFIG_ADEOS_CORE
 static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
+#endif /* !CONFIG_ADEOS_CORE */
 static inline void end_edge_ioapic_vector (unsigned int vector) { }
 #define startup_level_ioapic	startup_level_ioapic_vector
 #define shutdown_level_ioapic	mask_IO_APIC_vector
@@ -35,7 +37,9 @@ static inline void end_edge_ioapic_vecto
 #else
 static inline int use_pci_vector(void)	{return 0;}
 static inline void disable_edge_ioapic_irq(unsigned int irq) { }
+#ifndef CONFIG_ADEOS_CORE
 static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
+#endif /* !CONFIG_ADEOS_CORE */
 static inline void end_edge_ioapic_irq (unsigned int irq) { }
 #define startup_level_ioapic	startup_level_ioapic_irq
 #define shutdown_level_ioapic	mask_IO_APIC_irq
diff -uNrp linux-2.6.9/include/asm-i386/ltt.h linux-2.6.9-ltt-r12/include/asm-i386/ltt.h
--- linux-2.6.9/include/asm-i386/ltt.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/asm-i386/ltt.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,15 @@
+/*
+ * linux/include/asm-i386/ltt.h
+ *
+ * Copyright (C) 2002, Karim Yaghmour
+ *
+ * i386 definitions for tracing system
+ */
+
+#include <linux/ltt-events.h>
+
+/* Current arch type */
+#define LTT_ARCH_TYPE LTT_ARCH_TYPE_I386
+
+/* Current variant type */
+#define LTT_ARCH_VARIANT LTT_ARCH_VARIANT_NONE
diff -uNrp linux-2.6.9/include/asm-i386/mach-default/do_timer.h linux-2.6.9-ltt-r12/include/asm-i386/mach-default/do_timer.h
--- linux-2.6.9/include/asm-i386/mach-default/do_timer.h	2004-10-18 23:55:07.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/asm-i386/mach-default/do_timer.h	2005-08-15 10:31:45.000000000 +0200
@@ -45,15 +45,16 @@ static inline void do_timer_interrupt_ho
  **/
 static inline int do_timer_overflow(int count)
 {
+	unsigned long flags;
 	int i;
 
-	spin_lock(&i8259A_lock);
+	spin_lock_irqsave_hw_cond(&i8259A_lock, flags);
 	/*
 	 * This is tricky when I/O APICs are used;
 	 * see do_timer_interrupt().
 	 */
 	i = inb(0x20);
-	spin_unlock(&i8259A_lock);
+	spin_unlock_irqrestore_hw_cond(&i8259A_lock, flags);
 	
 	/* assumption about timer being IRQ0 */
 	if (i & 0x01) {
diff -uNrp linux-2.6.9/include/asm-i386/mach-visws/do_timer.h linux-2.6.9-ltt-r12/include/asm-i386/mach-visws/do_timer.h
--- linux-2.6.9/include/asm-i386/mach-visws/do_timer.h	2004-10-18 23:53:46.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/asm-i386/mach-visws/do_timer.h	2005-08-15 10:31:45.000000000 +0200
@@ -24,15 +24,16 @@ static inline void do_timer_interrupt_ho
 
 static inline int do_timer_overflow(int count)
 {
+	unsigned long flags;
 	int i;
 
-	spin_lock(&i8259A_lock);
+	spin_lock_irqsave_hw_cond(&i8259A_lock, flags);
 	/*
 	 * This is tricky when I/O APICs are used;
 	 * see do_timer_interrupt().
 	 */
 	i = inb(0x20);
-	spin_unlock(&i8259A_lock);
+	spin_unlock_irqrestore_hw_cond(&i8259A_lock, flags);
 	
 	/* assumption about timer being IRQ0 */
 	if (i & 0x01) {
diff -uNrp linux-2.6.9/include/asm-i386/pgalloc.h linux-2.6.9-ltt-r12/include/asm-i386/pgalloc.h
--- linux-2.6.9/include/asm-i386/pgalloc.h	2004-10-18 23:53:10.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/asm-i386/pgalloc.h	2005-08-15 10:31:45.000000000 +0200
@@ -52,4 +52,28 @@ static inline void pte_free(struct page 
 
 #define check_pgt_cache()	do { } while (0)
 
+#ifdef CONFIG_ADEOS_CORE
+static inline void set_pgdir(unsigned long address, pgd_t entry)
+{
+
+	struct task_struct * p;
+	pgd_t *pgd;
+	struct page *page;
+	
+	read_lock(&tasklist_lock);
+
+	for_each_process(p) {
+		if(p->mm) 
+		    *pgd_offset(p->mm,address) = entry;
+	}
+
+	read_unlock(&tasklist_lock);
+
+	for (page = pgd_list; page; page = (struct page *)page->index) {
+		pgd = (pgd_t *)page_address(page);
+		pgd[address >> PGDIR_SHIFT] = entry;
+	}
+}
+#endif /* CONFIG_ADEOS_CORE */
+
 #endif /* _I386_PGALLOC_H */
diff -uNrp linux-2.6.9/include/asm-i386/relay.h linux-2.6.9-ltt-r12/include/asm-i386/relay.h
--- linux-2.6.9/include/asm-i386/relay.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/asm-i386/relay.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,101 @@
+#ifndef _ASM_I386_RELAY_H
+#define _ASM_I386_RELAY_H
+/*
+ * linux/include/asm-i386/relay.h
+ *
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * i386 definitions for relayfs
+ */
+
+#include <linux/relayfs_fs.h>
+
+#ifdef CONFIG_X86_TSC
+#include <asm/msr.h>
+
+/**
+ *	get_time_delta - utility function for getting time delta
+ *	@now: pointer to a timeval struct that may be given current time
+ *	@rchan: the channel
+ *
+ *	Returns either the TSC if TSCs are being used, or the time and the
+ *	time difference between the current time and the buffer start time 
+ *	if TSCs are not being used.
+ */
+static inline u32
+get_time_delta(struct timeval *now, struct rchan *rchan)
+{
+	u32 time_delta;
+
+	if ((using_tsc(rchan) == 1) && cpu_has_tsc)
+		rdtscl(time_delta);
+	else {
+		do_gettimeofday(now);
+		time_delta = calc_time_delta(now, &rchan->buf_start_time);
+	}
+
+	return time_delta;
+}
+
+/**
+ *	get_timestamp - utility function for getting a time and TSC pair
+ *	@now: current time
+ *	@tsc: the TSC associated with now
+ *	@rchan: the channel
+ *
+ *	Sets the value pointed to by now to the current time and the value
+ *	pointed to by tsc to the tsc associated with that time, if the 
+ *	platform supports TSC.
+ */
+static inline void 
+get_timestamp(struct timeval *now,
+	      u32 *tsc,
+	      struct rchan *rchan)
+{
+	do_gettimeofday(now);
+
+	if ((using_tsc(rchan) == 1) && cpu_has_tsc)
+		rdtscl(*tsc);
+}
+
+/**
+ *	get_time_or_tsc - utility function for getting a time or a TSC
+ *	@now: current time
+ *	@tsc: current TSC
+ *	@rchan: the channel
+ *
+ *	Sets the value pointed to by now to the current time or the value
+ *	pointed to by tsc to the current tsc, depending on whether we're
+ *	using TSCs or not.
+ */
+static inline void 
+get_time_or_tsc(struct timeval *now,
+		u32 *tsc,
+		struct rchan *rchan)
+{
+	if ((using_tsc(rchan) == 1) && cpu_has_tsc)
+		rdtscl(*tsc);
+	else
+		do_gettimeofday(now);
+}
+
+/**
+ *	have_tsc - does this platform have a useable TSC?
+ *
+ *	Returns 1 if this platform has a useable TSC counter for
+ *	timestamping purposes, 0 otherwise.
+ */
+static inline int
+have_tsc(void)
+{
+	if (cpu_has_tsc)
+		return 1;
+	else
+		return 0;
+}
+
+#else /* No TSC support (#ifdef CONFIG_X86_TSC) */
+#include <asm-generic/relay.h>
+#endif /* #ifdef CONFIG_X86_TSC */
+#endif
diff -uNrp linux-2.6.9/include/asm-i386/smp.h linux-2.6.9-ltt-r12/include/asm-i386/smp.h
--- linux-2.6.9/include/asm-i386/smp.h	2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/asm-i386/smp.h	2005-08-15 10:31:45.000000000 +0200
@@ -50,7 +50,12 @@ extern u8 x86_cpu_to_apicid[];
  * from the initial startup. We map APIC_BASE very early in page_setup(),
  * so this is correct in the x86 case.
  */
-#define smp_processor_id() (current_thread_info()->cpu)
+#ifdef CONFIG_ADEOS_CORE
+#include <asm/adeos.h>
+#define smp_processor_id()      adeos_processor_id()
+#else /* !CONFIG_ADEOS_CORE */
+#define smp_processor_id()	(current_thread_info()->cpu)
+#endif /* CONFIG_ADEOS_CORE */
 
 extern cpumask_t cpu_callout_map;
 #define cpu_possible_map cpu_callout_map
diff -uNrp linux-2.6.9/include/asm-i386/spinlock.h linux-2.6.9-ltt-r12/include/asm-i386/spinlock.h
--- linux-2.6.9/include/asm-i386/spinlock.h	2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/asm-i386/spinlock.h	2005-08-15 10:31:45.000000000 +0200
@@ -54,6 +54,9 @@ typedef struct {
 	"jmp 1b\n" \
 	"3:\n\t"
 
+#ifdef CONFIG_ADEOS_CORE
+#define spin_lock_string_flags spin_lock_string
+#else /* !CONFIG_ADEOS_CORE */
 #define spin_lock_string_flags \
 	"\n1:\t" \
 	"lock ; decb %0\n\t" \
@@ -69,6 +72,7 @@ typedef struct {
 	"cli\n\t" \
 	"jmp 1b\n" \
 	"4:\n\t"
+#endif /* CONFIG_ADEOS_CORE */
 
 /*
  * This works. Despite all the confusion.
diff -uNrp linux-2.6.9/include/asm-i386/system.h linux-2.6.9-ltt-r12/include/asm-i386/system.h
--- linux-2.6.9/include/asm-i386/system.h	2004-10-18 23:53:06.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/asm-i386/system.h	2005-08-15 10:31:45.000000000 +0200
@@ -441,6 +441,33 @@ struct alt_instr { 
 #define set_wmb(var, value) do { var = value; wmb(); } while (0)
 
 /* interrupt control.. */
+#ifdef CONFIG_ADEOS_CORE
+
+#include <linux/linkage.h>
+
+void __adeos_stall_root(void);
+
+void __adeos_unstall_root(void);
+
+unsigned long __adeos_test_root(void);
+
+unsigned long __adeos_test_and_stall_root(void);
+
+void fastcall __adeos_restore_root(unsigned long flags);
+
+#define local_save_flags(x)	((x) = __adeos_test_root())
+#define local_irq_save(x)	((x) = __adeos_test_and_stall_root())
+#define local_irq_restore(x)	__adeos_restore_root(x)
+#define local_irq_disable()	__adeos_stall_root()
+#define local_irq_enable()	__adeos_unstall_root()
+
+#define irqs_disabled()		__adeos_test_root()
+
+#define safe_halt() \
+__asm__ __volatile__("call __adeos_unstall_root; hlt": : :"memory")
+
+#else /* !CONFIG_ADEOS_CORE */
+
 #define local_save_flags(x)	do { typecheck(unsigned long,x); __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */); } while (0)
 #define local_irq_restore(x) 	do { typecheck(unsigned long,x); __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc"); } while (0)
 #define local_irq_disable() 	__asm__ __volatile__("cli": : :"memory")
@@ -458,6 +485,8 @@ struct alt_instr { 
 /* For spinlocks etc */
 #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
 
+#endif /* CONFIG_ADEOS_CORE */
+
 /*
  * disable hlt during certain critical i/o operations
  */
diff -uNrp linux-2.6.9/include/linux/adeos.h linux-2.6.9-ltt-r12/include/linux/adeos.h
--- linux-2.6.9/include/linux/adeos.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/linux/adeos.h	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,551 @@
+/*
+ *   include/linux/adeos.h
+ *
+ *   Copyright (C) 2002,2003,2004 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_ADEOS_H
+#define __LINUX_ADEOS_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_ADEOS_CORE
+
+#include <linux/spinlock.h>
+#include <asm/adeos.h>
+
+#define ADEOS_VERSION_PREFIX  "2.6"
+#define ADEOS_VERSION_STRING  (ADEOS_VERSION_PREFIX ADEOS_ARCH_STRING)
+#define ADEOS_RELEASE_NUMBER  (0x02060000|((ADEOS_MAJOR_NUMBER&0xff)<<8)|(ADEOS_MINOR_NUMBER&0xff))
+
+#define ADEOS_ROOT_PRI       100
+#define ADEOS_ROOT_ID        0
+#define ADEOS_ROOT_NPTDKEYS  4	/* Must be <= 32 */
+
+#define ADEOS_RESET_TIMER  0x1
+#define ADEOS_SAME_HANDLER ((void (*)(unsigned))(-1))
+
+/* Global domain flags */
+#define ADEOS_SPRINTK_FLAG 0	/* Synchronous printk() allowed */
+#define ADEOS_PPRINTK_FLAG 1	/* Asynchronous printk() request pending */
+
+/* Per-cpu pipeline flags.
+   WARNING: some implementation might refer to those flags
+   non-symbolically in assembly portions (e.g. x86). */
+#define IPIPE_STALL_FLAG   0	/* Stalls a pipeline stage */
+#define IPIPE_XPEND_FLAG   1	/* Exception notification is pending */
+#define IPIPE_SLEEP_FLAG   2	/* Domain has self-suspended */
+#define IPIPE_SYNC_FLAG    3	/* The interrupt syncer is running for the domain */
+
+#define IPIPE_HANDLE_FLAG    0
+#define IPIPE_PASS_FLAG      1
+#define IPIPE_ENABLE_FLAG    2
+#define IPIPE_DYNAMIC_FLAG   IPIPE_HANDLE_FLAG
+#define IPIPE_EXCLUSIVE_FLAG 3
+#define IPIPE_STICKY_FLAG    4
+#define IPIPE_SYSTEM_FLAG    5
+#define IPIPE_LOCK_FLAG      6
+#define IPIPE_SHARED_FLAG    7
+#define IPIPE_CALLASM_FLAG   8	/* Arch-dependent -- might be unused. */
+
+#define IPIPE_HANDLE_MASK    (1 << IPIPE_HANDLE_FLAG)
+#define IPIPE_PASS_MASK      (1 << IPIPE_PASS_FLAG)
+#define IPIPE_ENABLE_MASK    (1 << IPIPE_ENABLE_FLAG)
+#define IPIPE_DYNAMIC_MASK   IPIPE_HANDLE_MASK
+#define IPIPE_EXCLUSIVE_MASK (1 << IPIPE_EXCLUSIVE_FLAG)
+#define IPIPE_STICKY_MASK    (1 << IPIPE_STICKY_FLAG)
+#define IPIPE_SYSTEM_MASK    (1 << IPIPE_SYSTEM_FLAG)
+#define IPIPE_LOCK_MASK      (1 << IPIPE_LOCK_FLAG)
+#define IPIPE_SHARED_MASK    (1 << IPIPE_SHARED_FLAG)
+#define IPIPE_SYNC_MASK      (1 << IPIPE_SYNC_FLAG)
+#define IPIPE_CALLASM_MASK   (1 << IPIPE_CALLASM_FLAG)
+
+#define IPIPE_DEFAULT_MASK  (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK)
+
+typedef struct adattr {
+
+    unsigned domid;		/* Domain identifier -- Magic value set by caller */
+    const char *name;		/* Domain name -- Warning: won't be dup'ed! */
+    int priority;		/* Priority in interrupt pipeline */
+    void (*entry)(int);		/* Domain entry point */
+    int estacksz;		/* Stack size for entry context -- 0 means unspec */
+    void (*dswitch)(void);	/* Handler called each time the domain is switched in */
+    int nptdkeys;		/* Max. number of per-thread data keys */
+    void (*ptdset)(int,void *);	/* Routine to set pt values */
+    void *(*ptdget)(int);	/* Routine to get pt values */
+
+} adattr_t;
+
+typedef struct admutex {
+
+    raw_spinlock_t lock;
+
+#ifdef CONFIG_ADEOS_THREADS
+    adomain_t *sleepq, /* Pending domain queue */
+	      *owner;	/* Domain owning the mutex */
+#ifdef CONFIG_SMP
+    volatile int owncpu;
+#define ADEOS_MUTEX_UNLOCKED { RAW_SPIN_LOCK_UNLOCKED, NULL, NULL, -1 }
+#else  /* !CONFIG_SMP */
+#define ADEOS_MUTEX_UNLOCKED { RAW_SPIN_LOCK_UNLOCKED, NULL, NULL }
+#endif /* CONFIG_SMP */
+#else /* !CONFIG_ADEOS_THREADS */
+#define ADEOS_MUTEX_UNLOCKED { RAW_SPIN_LOCK_UNLOCKED }
+#endif /* CONFIG_ADEOS_THREADS */
+
+} admutex_t;
+
+extern int adp_pipelined;
+
+extern adomain_t *adp_cpu_current[],
+                 *adp_root;
+
+extern int __adeos_event_monitors[];
+
+extern unsigned __adeos_printk_virq;
+
+extern unsigned long __adeos_virtual_irq_map;
+
+extern struct list_head __adeos_pipeline;
+
+extern raw_spinlock_t __adeos_pipelock;
+
+#ifdef CONFIG_ADEOS_PROFILING
+
+typedef struct adprofdata {
+
+    struct {
+	unsigned long long t_handled;
+	unsigned long long t_synced;
+	unsigned long n_handled;
+	unsigned long n_synced;
+    } irqs[IPIPE_NR_IRQS];
+
+} adprofdata_t;
+
+extern adprofdata_t __adeos_profile_data[ADEOS_NR_CPUS];
+
+#endif /* CONFIG_ADEOS_PROFILING */
+
+/* Private interface */
+
+#ifdef CONFIG_PROC_FS
+void __adeos_init_proc(void);
+#endif /* CONFIG_PROC_FS */
+
+void __adeos_takeover(void);
+
+asmlinkage int __adeos_handle_event(unsigned event,
+				    void *evdata);
+
+void __adeos_flush_printk(unsigned irq);
+
+void __adeos_dump_state(void);
+
+static inline void __adeos_schedule_head(void *evdata) {
+
+    if (__adeos_event_monitors[ADEOS_SCHEDULE_HEAD] > 0)
+	__adeos_handle_event(ADEOS_SCHEDULE_HEAD,evdata);
+}
+
+static inline int __adeos_schedule_tail(void *evdata) {
+
+    if (__adeos_event_monitors[ADEOS_SCHEDULE_TAIL] > 0)
+	return __adeos_handle_event(ADEOS_SCHEDULE_TAIL,evdata);
+
+    return 0;
+}
+
+static inline void __adeos_enter_process(void) {
+
+    if (__adeos_event_monitors[ADEOS_ENTER_PROCESS] > 0)
+	__adeos_handle_event(ADEOS_ENTER_PROCESS,NULL);
+}
+
+static inline void __adeos_exit_process(void *evdata) {
+
+    if (__adeos_event_monitors[ADEOS_EXIT_PROCESS] > 0)
+	__adeos_handle_event(ADEOS_EXIT_PROCESS,evdata);
+}
+
+static inline int __adeos_signal_process(void *evdata) {
+
+    if (__adeos_event_monitors[ADEOS_SIGNAL_PROCESS] > 0)
+	return __adeos_handle_event(ADEOS_SIGNAL_PROCESS,evdata);
+
+    return 0;
+}
+
+static inline void __adeos_kick_process(void *evdata) {
+
+    if (__adeos_event_monitors[ADEOS_KICK_PROCESS] > 0)
+	__adeos_handle_event(ADEOS_KICK_PROCESS,evdata);
+}
+
+static inline int __adeos_renice_process(void *evdata) {
+
+    if (__adeos_event_monitors[ADEOS_RENICE_PROCESS] > 0)
+	return __adeos_handle_event(ADEOS_RENICE_PROCESS,evdata);
+
+    return 0;
+}
+
+void __adeos_stall_root(void);
+
+void __adeos_unstall_root(void);
+
+unsigned long __adeos_test_root(void);
+
+unsigned long __adeos_test_and_stall_root(void);
+
+void fastcall __adeos_restore_root(unsigned long flags);
+
+void __adeos_schedule_back_root(struct task_struct *prev);
+
+int __adeos_setscheduler_root(struct task_struct *p,
+			      int policy,
+			      int prio);
+
+void __adeos_reenter_root(struct task_struct *prev,
+			  int policy,
+			  int prio);
+
+int fastcall __adeos_schedule_irq(unsigned irq,
+				  struct list_head *head);
+
+#define __adeos_pipeline_head_p(adp) (&(adp)->p_link == __adeos_pipeline.next)
+
+#ifdef CONFIG_ADEOS_THREADS
+
+static inline int __adeos_domain_work_p (adomain_t *adp, int cpuid)
+
+{
+    return (!test_bit(IPIPE_SLEEP_FLAG,&adp->cpudata[cpuid].status) ||
+	    (!test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status) &&
+	     adp->cpudata[cpuid].irq_pending_hi != 0) ||
+	    test_bit(IPIPE_XPEND_FLAG,&adp->cpudata[cpuid].status));
+}
+
+#else /* !CONFIG_ADEOS_THREADS */
+
+static inline int __adeos_domain_work_p (adomain_t *adp, int cpuid)
+
+{
+    return (!test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status) &&
+	    adp->cpudata[cpuid].irq_pending_hi != 0);
+}
+
+static inline void __adeos_switch_to (adomain_t *out, adomain_t *in, int cpuid)
+
+{
+    void adeos_suspend_domain(void);
+
+    /* "in" is guaranteed to be closer than "out" from the head of the
+       pipeline (and obviously different). */
+
+    adp_cpu_current[cpuid] = in;
+
+    if (in->dswitch)
+	in->dswitch();
+
+    adeos_suspend_domain(); /* Sync stage and propagate interrupts. */
+    adeos_load_cpuid(); /* Processor might have changed. */
+
+    if (adp_cpu_current[cpuid] == in)
+	/* Otherwise, something has changed the current domain under
+	   our feet recycling the register set; do not override. */
+	adp_cpu_current[cpuid] = out;
+}
+
+#endif /* CONFIG_ADEOS_THREADS */
+
+/* Public interface */
+
+int adeos_register_domain(adomain_t *adp,
+			  adattr_t *attr);
+
+int adeos_unregister_domain(adomain_t *adp);
+
+void adeos_suspend_domain(void);
+
+int adeos_virtualize_irq_from(adomain_t *adp,
+			      unsigned irq,
+			      void (*handler)(unsigned irq),
+			      int (*acknowledge)(unsigned irq),
+			      unsigned modemask);
+
+static inline int adeos_virtualize_irq(unsigned irq,
+				       void (*handler)(unsigned irq),
+				       int (*acknowledge)(unsigned irq),
+				       unsigned modemask) {
+
+    return adeos_virtualize_irq_from(adp_current,
+				     irq,
+				     handler,
+				     acknowledge,
+				     modemask);
+}
+
+int adeos_control_irq(unsigned irq,
+		      unsigned clrmask,
+		      unsigned setmask);
+
+cpumask_t adeos_set_irq_affinity(unsigned irq,
+				 cpumask_t cpumask);
+
+static inline int adeos_share_irq (unsigned irq, int (*acknowledge)(unsigned irq)) {
+
+    return adeos_virtualize_irq(irq,
+				ADEOS_SAME_HANDLER,
+				acknowledge,
+				IPIPE_SHARED_MASK|IPIPE_HANDLE_MASK|IPIPE_PASS_MASK);
+}
+
+unsigned adeos_alloc_irq(void);
+
+int adeos_free_irq(unsigned irq);
+
+int fastcall adeos_trigger_irq(unsigned irq);
+
+static inline int adeos_propagate_irq(unsigned irq) {
+
+    return __adeos_schedule_irq(irq,adp_current->p_link.next);
+}
+
+static inline int adeos_schedule_irq(unsigned irq) {
+
+    return __adeos_schedule_irq(irq,&adp_current->p_link);
+}
+
+int fastcall adeos_send_ipi(unsigned ipi,
+			    cpumask_t cpumask);
+
+static inline void adeos_stall_pipeline_from (adomain_t *adp)
+
+{
+    adeos_declare_cpuid;
+#ifdef CONFIG_SMP
+    unsigned long flags;
+
+    adeos_lock_cpu(flags);
+
+    __set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+    if (!__adeos_pipeline_head_p(adp))
+	adeos_unlock_cpu(flags);
+#else /* CONFIG_SMP */
+    set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+    if (__adeos_pipeline_head_p(adp))
+	adeos_hw_cli();
+#endif /* CONFIG_SMP */
+}
+
+static inline unsigned long adeos_test_pipeline_from (adomain_t *adp)
+
+{
+    unsigned long flags, s;
+    adeos_declare_cpuid;
+    
+    adeos_get_cpu(flags);
+    s = test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    adeos_put_cpu(flags);
+
+    return s;
+}
+
+static inline unsigned long adeos_test_and_stall_pipeline_from (adomain_t *adp)
+
+{
+    adeos_declare_cpuid;
+    unsigned long s;
+#ifdef CONFIG_SMP
+    unsigned long flags;
+
+    adeos_lock_cpu(flags);
+
+    s = __test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+    if (!__adeos_pipeline_head_p(adp))
+	adeos_unlock_cpu(flags);
+#else /* CONFIG_SMP */
+    s = test_and_set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+    if (__adeos_pipeline_head_p(adp))
+	adeos_hw_cli();
+#endif /* CONFIG_SMP */
+    
+    return s;
+}
+
+void fastcall adeos_unstall_pipeline_from(adomain_t *adp);
+
+static inline unsigned long adeos_test_and_unstall_pipeline_from(adomain_t *adp)
+
+{
+    unsigned long flags, s;
+    adeos_declare_cpuid;
+    
+    adeos_get_cpu(flags);
+    s = test_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    adeos_unstall_pipeline_from(adp);
+    adeos_put_cpu(flags);
+
+    return s;
+}
+
+static inline void adeos_unstall_pipeline(void)
+
+{
+    adeos_unstall_pipeline_from(adp_current);
+}
+
+static inline unsigned long adeos_test_and_unstall_pipeline(void)
+
+{
+    return adeos_test_and_unstall_pipeline_from(adp_current);
+}
+
+static inline unsigned long adeos_test_pipeline (void)
+
+{
+    return adeos_test_pipeline_from(adp_current);
+}
+
+static inline unsigned long adeos_test_and_stall_pipeline (void)
+
+{
+    return adeos_test_and_stall_pipeline_from(adp_current);
+}
+
+static inline void adeos_restore_pipeline_from (adomain_t *adp, unsigned long flags)
+
+{
+    if (flags)
+	adeos_stall_pipeline_from(adp);
+    else
+	adeos_unstall_pipeline_from(adp);
+}
+
+static inline void adeos_stall_pipeline (void)
+
+{
+    adeos_stall_pipeline_from(adp_current);
+}
+
+static inline void adeos_restore_pipeline (unsigned long flags)
+
+{
+    adeos_restore_pipeline_from(adp_current,flags);
+}
+
+static inline void adeos_restore_pipeline_nosync (adomain_t *adp, unsigned long flags, int cpuid)
+
+{
+    /* If cpuid is current, then it must be held on entry
+       (adeos_get_cpu/adeos_hw_local_irq_save/adeos_hw_cli). */
+
+    if (flags)
+	__set_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+    else
+	__clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+}
+
+int adeos_catch_event_from(adomain_t *adp,
+			   unsigned event,
+			   void (*handler)(adevinfo_t *));
+
+static inline int adeos_catch_event (unsigned event, void (*handler)(adevinfo_t *))
+
+{
+    return adeos_catch_event_from(adp_current,event,handler);
+}
+
+static inline void adeos_propagate_event(adevinfo_t *evinfo)
+
+{
+    evinfo->propagate = 1;
+}
+
+void adeos_init_attr(adattr_t *attr);
+
+int adeos_get_sysinfo(adsysinfo_t *sysinfo);
+
+int adeos_tune_timer(unsigned long ns,
+		     int flags);
+
+int adeos_alloc_ptdkey(void);
+
+int adeos_free_ptdkey(int key);
+
+int adeos_set_ptd(int key,
+		  void *value);
+
+void *adeos_get_ptd(int key);
+
+unsigned long adeos_critical_enter(void (*syncfn)(void));
+
+void adeos_critical_exit(unsigned long flags);
+
+int adeos_init_mutex(admutex_t *mutex);
+
+int adeos_destroy_mutex(admutex_t *mutex);
+
+unsigned long fastcall adeos_lock_mutex(admutex_t *mutex);
+
+void fastcall adeos_unlock_mutex(admutex_t *mutex,
+				 unsigned long flags);
+
+static inline void adeos_set_printk_sync (adomain_t *adp) {
+    set_bit(ADEOS_SPRINTK_FLAG,&adp->flags);
+}
+
+static inline void adeos_set_printk_async (adomain_t *adp) {
+    clear_bit(ADEOS_SPRINTK_FLAG,&adp->flags);
+}
+
+#define spin_lock_irqsave_hw_cond(lock,flags)      spin_lock_irqsave_hw(lock,flags)
+#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock_irqrestore_hw(lock,flags)
+
+#define pic_irq_lock(irq)	\
+	do {		\
+		adeos_declare_cpuid; \
+		adeos_load_cpuid();		\
+		__adeos_lock_irq(adp_cpu_current[cpuid], cpuid, irq); \
+	} while(0)
+
+#define pic_irq_unlock(irq)	\
+	do {		\
+		adeos_declare_cpuid; \
+		adeos_load_cpuid();	     \
+		__adeos_unlock_irq(adp_cpu_current[cpuid], irq); \
+	} while(0)
+
+#else	/* !CONFIG_ADEOS_CORE */
+
+#define spin_lock_irqsave_hw(lock,flags)      spin_lock_irqsave(lock, flags)
+#define spin_unlock_irqrestore_hw(lock,flags) spin_unlock_irqrestore(lock, flags)
+#define spin_lock_irqsave_hw_cond(lock,flags)      do { flags = 0; spin_lock(lock); } while(0)
+#define spin_unlock_irqrestore_hw_cond(lock,flags) spin_unlock(lock)
+
+#define pic_irq_lock(irq)	do { } while(0)
+#define pic_irq_unlock(irq)	do { } while(0)
+
+#endif	/* CONFIG_ADEOS_CORE */
+
+#endif /* !__LINUX_ADEOS_H */
diff -uNrp linux-2.6.9/include/linux/init_task.h linux-2.6.9-ltt-r12/include/linux/init_task.h
--- linux-2.6.9/include/linux/init_task.h	2004-10-18 23:53:13.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/linux/init_task.h	2005-08-15 10:31:45.000000000 +0200
@@ -64,6 +64,9 @@ extern struct group_info init_groups;
  *  INIT_TASK is used to set up the first task table, touch at
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
  */
+
+#ifdef CONFIG_ADEOS_CORE
+
 #define INIT_TASK(tsk)	\
 {									\
 	.state		= 0,						\
@@ -112,8 +115,61 @@ extern struct group_info init_groups;
 	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
 	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
 	.journal_info	= NULL,						\
+        .ptd            = { [ 0 ... ADEOS_ROOT_NPTDKEYS - 1] = 0 }      \
 }
 
+#else /* !CONFIG_ADEOS_CORE */
+
+#define INIT_TASK(tsk)	\
+{									\
+	.state		= 0,						\
+	.thread_info	= &init_thread_info,				\
+	.usage		= ATOMIC_INIT(2),				\
+	.flags		= 0,						\
+	.lock_depth	= -1,						\
+	.prio		= MAX_PRIO-20,					\
+	.static_prio	= MAX_PRIO-20,					\
+	.policy		= SCHED_NORMAL,					\
+	.cpus_allowed	= CPU_MASK_ALL,					\
+	.mm		= NULL,						\
+	.active_mm	= &init_mm,					\
+	.run_list	= LIST_HEAD_INIT(tsk.run_list),			\
+	.time_slice	= HZ,						\
+	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
+	.ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children),		\
+	.ptrace_list	= LIST_HEAD_INIT(tsk.ptrace_list),		\
+	.real_parent	= &tsk,						\
+	.parent		= &tsk,						\
+	.children	= LIST_HEAD_INIT(tsk.children),			\
+	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
+	.group_leader	= &tsk,						\
+	.wait_chldexit	= __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
+	.real_timer	= {						\
+		.function	= it_real_fn				\
+	},								\
+	.group_info	= &init_groups,					\
+	.cap_effective	= CAP_INIT_EFF_SET,				\
+	.cap_inheritable = CAP_INIT_INH_SET,				\
+	.cap_permitted	= CAP_FULL_SET,					\
+	.keep_capabilities = 0,						\
+	.rlim		= INIT_RLIMITS,					\
+	.user		= INIT_USER,					\
+	.comm		= "swapper",					\
+	.thread		= INIT_THREAD,					\
+	.fs		= &init_fs,					\
+	.files		= &init_files,					\
+	.signal		= &init_signals,				\
+	.sighand	= &init_sighand,				\
+	.pending	= {						\
+		.list = LIST_HEAD_INIT(tsk.pending.list),		\
+		.signal = {{0}}},					\
+	.blocked	= {{0}},					\
+	.alloc_lock	= SPIN_LOCK_UNLOCKED,				\
+	.proc_lock	= SPIN_LOCK_UNLOCKED,				\
+	.switch_lock	= SPIN_LOCK_UNLOCKED,				\
+	.journal_info	= NULL,						\
+}
 
+#endif /* CONFIG_ADEOS_CORE */
 
 #endif
diff -uNrp linux-2.6.9/include/linux/klog.h linux-2.6.9-ltt-r12/include/linux/klog.h
--- linux-2.6.9/include/linux/klog.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/linux/klog.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,24 @@
+/*
+ * KLOG		Generic Logging facility built upon the relayfs infrastructure
+ *
+ * Authors:	Hubertus Frankeh  (frankeh@us.ibm.com)
+ *		Tom Zanussi  (zanussi@us.ibm.com)
+ *
+ *		Please direct all questions/comments to zanussi@us.ibm.com
+ *
+ *		Copyright (C) 2003, IBM Corp
+ *
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_KLOG_H
+#define _LINUX_KLOG_H
+
+extern int klog(const char *fmt, ...);
+extern int klog_raw(const char *buf,int len); 
+
+#endif	/* _LINUX_KLOG_H */
diff -uNrp linux-2.6.9/include/linux/ltt-core.h linux-2.6.9-ltt-r12/include/linux/ltt-core.h
--- linux-2.6.9/include/linux/ltt-core.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/linux/ltt-core.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,433 @@
+/*
+ * linux/include/linux/ltt-core.h
+ *
+ * Copyright (C) 1999-2004 Karim Yaghmour (karim@opersys.com)
+ *
+ * This contains the core definitions for the Linux Trace Toolkit.
+ */
+
+#ifndef _LTT_CORE_H
+#define _LTT_CORE_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+#include <linux/relayfs_fs.h>
+
+/* Is kernel tracing enabled */
+#if defined(CONFIG_LTT)
+
+#define LTT_CUSTOM_EV_MAX_SIZE		8192
+#define LTT_CUSTOM_EV_TYPE_STR_LEN	20
+#define LTT_CUSTOM_EV_DESC_STR_LEN	100
+#define LTT_CUSTOM_EV_FORM_STR_LEN	256
+#define LTT_CUSTOM_EV_FINAL_STR_LEN	200
+
+#define LTT_CUSTOM_EV_FORMAT_TYPE_NONE	0
+#define LTT_CUSTOM_EV_FORMAT_TYPE_STR	1
+#define LTT_CUSTOM_EV_FORMAT_TYPE_HEX	2
+#define LTT_CUSTOM_EV_FORMAT_TYPE_XML	3
+#define LTT_CUSTOM_EV_FORMAT_TYPE_IBM	4
+
+#define LTT_MAX_HANDLES			256
+
+/* In the ltt root directory lives the trace control file, used for
+   kernel-user communication. */
+#define LTT_RELAYFS_ROOT		"ltt"
+#define LTT_CONTROL_FILE		"control"
+
+/* We currently support 2 traces, normal trace and flight recorder */
+#define NR_TRACES			2
+#define TRACE_HANDLE			0
+#define FLIGHT_HANDLE			1
+
+/* System types */
+#define LTT_SYS_TYPE_VANILLA_LINUX	1
+
+/* Architecture types */
+#define LTT_ARCH_TYPE_I386			1
+#define LTT_ARCH_TYPE_PPC			2
+#define LTT_ARCH_TYPE_SH			3
+#define LTT_ARCH_TYPE_S390			4
+#define LTT_ARCH_TYPE_MIPS			5
+#define LTT_ARCH_TYPE_ARM			6
+
+/* Standard definitions for variants */
+#define LTT_ARCH_VARIANT_NONE             0   /* Main architecture implementation */
+
+/* The maximum number of CPUs the kernel might run on */
+#define LTT_MAX_NR_CPUS 32
+
+typedef u64 ltt_event_mask;
+
+/* Per-CPU channel information */
+struct ltt_channel_data
+{
+	int channel_handle;
+	struct rchan_reader *reader;
+	atomic_t waiting_for_cpu_async;
+	u32 events_lost;
+};
+
+/* Per-trace status info */
+struct ltt_trace_info
+{
+	int			active;
+	unsigned int		trace_handle;
+	int			paused;
+	int			flight_recorder;
+	int			use_locking;
+	int			using_tsc;
+	u32			n_buffers;
+	u32			buf_size;
+	ltt_event_mask		traced_events;
+	ltt_event_mask		log_event_details_mask;
+	u32			buffers_produced[LTT_MAX_NR_CPUS];
+};
+
+/* Status info for all traces */
+struct ltt_tracer_status
+{
+	int num_cpus;
+	struct ltt_trace_info traces[NR_TRACES];
+};
+
+/* Per-trace information - each trace/flight recorder represented by one */
+struct ltt_trace_struct
+{
+	unsigned int		trace_handle;	/* For convenience */
+	struct ltt_trace_struct	*active;	/* 'this' if active, or NULL */
+	int			paused;		/* Not currently logging */
+	struct ltt_channel_data relay_data[NR_CPUS];/* Relayfs handles, by CPU */
+	int			flight_recorder;/* i.e. this is not a trace */
+	struct task_struct	*daemon_task_struct;/* Daemon associated with trace */
+	struct _ltt_trace_start	*trace_start_data; /* Trace start event data, for flight recorder */
+	int			tracer_started;
+	int			tracer_stopping;
+	struct proc_dir_entry	*proc_dir_entry;	/* proc/ltt/0..1 */
+	ltt_event_mask		traced_events;
+	ltt_event_mask		log_event_details_mask;
+	u32			n_buffers;	/* Number of sub-buffers */
+	u32			buf_size;	/* Size of sub-buffer */
+	int			use_locking;
+	int			using_tsc;
+	int			log_cpuid;
+	int			tracing_pid;
+	int			tracing_pgrp;
+	int			tracing_gid;
+	int			tracing_uid;
+	pid_t			traced_pid;
+	pid_t			traced_pgrp;
+	gid_t			traced_gid;
+	uid_t			traced_uid;
+	unsigned long		buffer_switches_pending;/* For trace */
+	struct work_struct	work;	/* stop work struct */
+};
+
+extern int ltt_set_trace_config(
+	int		do_syscall_depth,
+	int		do_syscall_bounds,
+	int		eip_depth,
+	void		*eip_lower_bound,
+	void		*eip_upper_bound);
+extern void ltt_set_flight_recorder_config(
+	struct ltt_trace_struct	*trace);
+extern int ltt_get_trace_config(
+	int		*do_syscall_depth,
+	int		*do_syscall_bounds,
+	int		*eip_depth,
+	void		**eip_lower_bound,
+	void		**eip_upper_bound);
+extern int ltt_get_status(
+	struct ltt_tracer_status	*tracer_status);
+extern int ltt_create_event(
+	char		*event_type,
+	char		*event_desc,
+	int		format_type,
+	char		*format_data);
+extern int ltt_create_owned_event(
+	char		*event_type,
+	char		*event_desc,
+	int		format_type,
+	char		*format_data,
+	pid_t		owner_pid);
+extern void ltt_destroy_event(
+	int		event_id);
+extern void ltt_destroy_owners_events(
+	pid_t		owner_pid);
+extern void ltt_reregister_custom_events(void);
+extern int ltt_log_std_formatted_event(
+	int		event_id,
+	...);
+extern int ltt_log_raw_event(
+	int		event_id,
+	int		event_size,
+	void		*event_data);
+extern int _ltt_log_event(
+	struct ltt_trace_struct	*trace,
+	u8			event_id,
+	void			*event_struct,
+	u8			cpu_id);
+extern int ltt_log_event(
+	u8		event_id,
+	void		*event_struct);
+extern int ltt_valid_trace_handle(
+	unsigned int	tracer_handle);
+extern int ltt_alloc_trace_handle(
+	unsigned int	tracer_handle);
+extern int ltt_free_trace_handle(
+	unsigned int	tracer_handle);
+extern int ltt_free_daemon_handle(
+	struct ltt_trace_struct *trace);
+extern void ltt_free_all_handles(
+	struct task_struct*	task_ptr);
+extern int ltt_set_buffer_size(
+	struct ltt_trace_struct	*trace,
+	int			buffers_size, 
+	char			*dirname);
+extern int ltt_set_n_buffers(
+	struct ltt_trace_struct	*trace,
+	int			no_buffers);
+extern int ltt_set_default_config(
+	struct ltt_trace_struct	*trace);
+extern int ltt_syscall_active(
+	int syscall_type);
+extern void ltt_flight_pause(
+	void);
+extern void ltt_flight_unpause(
+	void);
+
+/* Tracer properties */
+#define LTT_TRACER_DEFAULT_BUF_SIZE   50000
+#define LTT_TRACER_MIN_BUF_SIZE        1000
+#define LTT_TRACER_MAX_BUF_SIZE      500000
+#define LTT_TRACER_MIN_BUFFERS            2
+#define LTT_TRACER_MAX_BUFFERS          256
+#define LTT_TRACER_MAGIC_NUMBER     0x00D6B7ED
+#define LTT_TRACER_VERSION_MAJOR    2
+#define LTT_TRACER_VERSION_MINOR    2
+
+#define LTT_TRACER_FIRST_EVENT_SIZE   (sizeof(u8) + sizeof(u32) + sizeof(ltt_buffer_start) + sizeof(uint16_t))
+#define LTT_TRACER_START_TRACE_EVENT_SIZE   (sizeof(u8) + sizeof(u32) + sizeof(ltt_trace_start) + sizeof(uint16_t))
+#define LTT_TRACER_LAST_EVENT_SIZE   (sizeof(u8) \
+				  + sizeof(u8) \
+				  + sizeof(u32) \
+				  + sizeof(ltt_buffer_end) \
+				  + sizeof(uint16_t) \
+				  + sizeof(u32))
+
+/* The configurations possible */
+enum {
+	LTT_TRACER_START = LTT_TRACER_MAGIC_NUMBER,	/* Start tracing events using the current configuration */
+	LTT_TRACER_STOP,				/* Stop tracing */
+	LTT_TRACER_CONFIG_DEFAULT,			/* Set the tracer to the default configuration */
+	LTT_TRACER_CONFIG_MEMORY_BUFFERS,		/* Set the memory buffers the daemon wants us to use */
+	LTT_TRACER_CONFIG_EVENTS,			/* Trace the given events */
+	LTT_TRACER_CONFIG_DETAILS,			/* Record the details of the event, or not */
+	LTT_TRACER_CONFIG_CPUID,			/* Record the CPUID associated with the event */
+	LTT_TRACER_CONFIG_PID,				/* Trace only one process */
+	LTT_TRACER_CONFIG_PGRP,				/* Trace only the given process group */
+	LTT_TRACER_CONFIG_GID,				/* Trace the processes of a given group of users */
+	LTT_TRACER_CONFIG_UID,				/* Trace the processes of a given user */
+	LTT_TRACER_CONFIG_SYSCALL_EIP_DEPTH,		/* Set the call depth at which the EIP should be fetched on syscall */
+	LTT_TRACER_CONFIG_SYSCALL_EIP_LOWER,		/* Set the lowerbound address from which EIP is recorded on syscall */
+	LTT_TRACER_CONFIG_SYSCALL_EIP_UPPER,		/* Set the upperbound address from which EIP is recorded on syscall */
+	LTT_TRACER_DATA_COMITTED,			/* The daemon has comitted the last trace */
+	LTT_TRACER_GET_EVENTS_LOST,			/* Get the number of events lost */
+	LTT_TRACER_CREATE_USER_EVENT,			/* Create a user tracable event */
+	LTT_TRACER_DESTROY_USER_EVENT,			/* Destroy a user tracable event */
+	LTT_TRACER_TRACE_USER_EVENT,			/* Trace a user event */
+	LTT_TRACER_SET_EVENT_MASK,			/* Set the trace event mask */
+	LTT_TRACER_GET_EVENT_MASK,			/* Get the trace event mask */
+	LTT_TRACER_GET_BUFFER_CONTROL,			/* Get the buffer control data for the lockless schem*/
+	LTT_TRACER_CONFIG_N_MEMORY_BUFFERS,		/* Set the number of memory buffers the daemon wants us to use */
+	LTT_TRACER_CONFIG_USE_LOCKING,			/* Set the locking scheme to use */
+	LTT_TRACER_CONFIG_TIMESTAMP,			/* Set the timestamping method to use */
+	LTT_TRACER_GET_ARCH_INFO,			/* Get information about the CPU configuration */
+	LTT_TRACER_ALLOC_HANDLE,			/* Allocate a tracer handle */
+	LTT_TRACER_FREE_HANDLE,				/* Free a single handle */
+	LTT_TRACER_FREE_DAEMON_HANDLE,			/* Free the daemon's handle */
+	LTT_TRACER_FREE_ALL_HANDLES,			/* Free all handles */
+	LTT_TRACER_MAP_BUFFER,				/* Map buffer to process-space */
+	LTT_TRACER_PAUSE,				/* Pause tracing */
+	LTT_TRACER_UNPAUSE,				/* Unpause tracing */
+	LTT_TRACER_GET_START_INFO,			/* trace start data */
+	LTT_TRACER_GET_STATUS				/* status of traces */
+};
+
+/* Lockless scheme definitions */
+#define LTT_TRACER_LOCKLESS_MIN_BUF_SIZE LTT_CUSTOM_EV_MAX_SIZE + 8192
+#define LTT_TRACER_LOCKLESS_MAX_BUF_SIZE 0x1000000
+
+/* Flags used for per-CPU tasks */
+#define LTT_NOTHING_TO_DO      0x00
+#define LTT_FINALIZE_TRACE     0x02
+#define LTT_TRACE_HEARTBEAT    0x08
+
+/* How often the LTT per-CPU timers fire */
+#define LTT_PERCPU_TIMER_FREQ  (HZ/10);
+
+/* Convenience accessors */
+#define waiting_for_cpu_async(trace_handle, cpu) (current_traces[trace_handle].relay_data[cpu].waiting_for_cpu_async)
+#define trace_channel_handle(trace_handle, cpu) (current_traces[trace_handle].relay_data[cpu].channel_handle)
+#define trace_channel_reader(trace_handle, cpu) (current_traces[trace_handle].relay_data[cpu].reader)
+#define trace_buffers_full(cpu) (daemon_relay_data[cpu].buffers_full)
+#define events_lost(trace_handle, cpu) (current_traces[trace_handle].relay_data[cpu].events_lost)
+
+/* Used for sharing per-buffer information between driver and daemon */
+struct ltt_buf_control_info
+{
+	s16 cpu_id;
+	u32 buffer_switches_pending;
+	u32 buffer_control_valid;
+
+	u32 buf_size;
+	u32 n_buffers;
+	u32 cur_idx;
+	u32 buffers_produced;
+	u32 buffers_consumed;
+	int buffer_complete[LTT_TRACER_MAX_BUFFERS];
+};
+
+/* Used for sharing buffer-commit information between driver and daemon */
+struct ltt_buffers_committed
+{
+	u8 cpu_id;
+	u32 buffers_consumed;
+};
+
+/* Used for specifying size/cpu id pair between driver and daemon */
+struct ltt_cpu_mmap_data
+{
+	u8 cpu_id;
+	unsigned long map_size;
+};
+
+/* Used for sharing architecture-specific info between driver and daemon */
+struct ltt_arch_info
+{
+	int n_cpus;
+	int page_shift;
+};
+
+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);
+}
+
+#if !defined(CONFIG_X86)
+# define cpu_has_tsc 0 /* FIXME: cpu_has_tsc isn't set except on x86 */
+#endif
+
+/**
+ *	switch_time_delta: - Utility function getting buffer switch time delta.
+ *	@time_delta: previously calculated or retrieved time delta 
+ *
+ *	Returns the time_delta passed in if we're using TSC or 0 otherwise.
+ */
+static inline u32 switch_time_delta(u32 time_delta,
+				    int using_tsc)
+{
+	if((using_tsc == 1) && cpu_has_tsc)
+		return time_delta;
+	else
+		return 0;
+}
+
+#else /* defined(CONFIG_LTT) */
+static inline int ltt_create_event(char	*event_type,
+		    char	*event_desc,
+		    int		format_type,
+		    char	*format_data)
+{
+	return 0;
+}
+
+static inline int ltt_create_owned_event(char		*event_type,
+			   char		*event_desc,
+			   int		format_type,
+			   char		*format_data,
+			   pid_t	owner_pid)
+{
+	return 0;
+}
+
+static inline void ltt_destroy_event(int event_id)
+{
+}
+
+static inline void ltt_destroy_owners_events(pid_t owner_pid)
+{
+}
+
+static inline void ltt_reregister_custom_events(void)
+{
+}
+
+static inline int ltt_log_std_formatted_event(int event_id, ...)
+{
+	return 0;
+}
+
+
+static inline  int ltt_log_raw_event(int	event_id,
+				     int	event_size,
+				     void	*event_data)
+{
+	return 0;
+}
+
+static inline  int _ltt_log_event(u8	event_id,
+				  void	*event_struct,
+				  u8	cpu_id)
+{
+	return 0;
+}
+
+static inline int ltt_log_event(u8	event_id,
+				void	*event_struct)
+{
+	return 0;
+}
+
+static inline void ltt_flight_pause(void)
+{
+}
+
+static inline void ltt_flight_unpause(void)
+{
+}
+
+#endif /* defined(CONFIG_LTT) */
+#endif /* _LTT_CORE_H */
diff -uNrp linux-2.6.9/include/linux/ltt-events.h linux-2.6.9-ltt-r12/include/linux/ltt-events.h
--- linux-2.6.9/include/linux/ltt-events.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/linux/ltt-events.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,424 @@
+/*
+ * linux/include/linux/ltt-events.h
+ *
+ * Copyright (C) 1999-2004 Karim Yaghmour (karim@opersys.com)
+ *
+ * This contains the event definitions for the Linux Trace Toolkit.
+ */
+
+#ifndef _LTT_EVENTS_H
+#define _LTT_EVENTS_H
+
+#include <linux/ltt-core.h>
+#include <linux/sched.h>
+
+/* Is kernel tracing enabled */
+#if defined(CONFIG_LTT)
+
+/* Don't set this to "1" unless you really know what you're doing */
+#define LTT_UNPACKED_STRUCTS	0
+
+/* Structure packing within the trace */
+#if LTT_UNPACKED_STRUCTS
+#define LTT_PACKED_STRUCT
+#else
+#define LTT_PACKED_STRUCT __attribute__ ((packed))
+#endif
+
+extern unsigned int ltt_syscall_entry_trace_active;
+extern unsigned int ltt_syscall_exit_trace_active;
+
+static inline void ltt_ev(u8 event_id, void* data)
+{
+	ltt_log_event(event_id, data);
+}
+
+/* Traced events */
+enum {
+	LTT_EV_START = 0,	/* This is to mark the trace's start */
+	LTT_EV_SYSCALL_ENTRY,	/* Entry in a given system call */
+	LTT_EV_SYSCALL_EXIT,	/* Exit from a given system call */
+	LTT_EV_TRAP_ENTRY,	/* Entry in a trap */
+	LTT_EV_TRAP_EXIT,	/* Exit from a trap */
+	LTT_EV_IRQ_ENTRY,	/* Entry in an irq */
+	LTT_EV_IRQ_EXIT,	/* Exit from an irq */
+	LTT_EV_SCHEDCHANGE,	/* Scheduling change */
+	LTT_EV_KERNEL_TIMER,	/* The kernel timer routine has been called */
+	LTT_EV_SOFT_IRQ,	/* Hit key part of soft-irq management */
+	LTT_EV_PROCESS,	/* Hit key part of process management */
+	LTT_EV_FILE_SYSTEM,	/* Hit key part of file system */
+	LTT_EV_TIMER,		/* Hit key part of timer management */
+	LTT_EV_MEMORY,	/* Hit key part of memory management */
+	LTT_EV_SOCKET,	/* Hit key part of socket communication */
+	LTT_EV_IPC,		/* Hit key part of System V IPC */
+	LTT_EV_NETWORK,	/* Hit key part of network communication */
+	LTT_EV_BUFFER_START,	/* Mark the begining of a trace buffer */
+	LTT_EV_BUFFER_END,	/* Mark the ending of a trace buffer */
+	LTT_EV_NEW_EVENT,	/* New event type */
+	LTT_EV_CUSTOM,	/* Custom event */
+	LTT_EV_CHANGE_MASK,	/* Change in event mask */
+	LTT_EV_HEARTBEAT	/* Heartbeat event */
+};
+
+/* Number of traced events */
+#define LTT_EV_MAX           LTT_EV_HEARTBEAT
+
+/* Information logged when a trace is started */
+typedef struct _ltt_trace_start {
+	u32 magic_number;
+	u32 arch_type;
+	u32 arch_variant;
+	u32 system_type;
+	u8 major_version;
+	u8 minor_version;
+
+	u32 buffer_size;
+	ltt_event_mask event_mask;
+	ltt_event_mask details_mask;
+	u8 log_cpuid;
+	u8 use_tsc;
+	u8 flight_recorder;
+} LTT_PACKED_STRUCT ltt_trace_start;
+
+/*  LTT_SYSCALL_ENTRY */
+typedef struct _ltt_syscall_entry {
+	u8 syscall_id;		/* Syscall entry number in entry.S */
+	u32 address;		/* Address from which call was made */
+} LTT_PACKED_STRUCT ltt_syscall_entry;
+
+/*  LTT_TRAP_ENTRY */
+#ifndef __s390__
+typedef struct _ltt_trap_entry {
+	u16 trap_id;		/* Trap number */
+	u32 address;		/* Address where trap occured */
+} LTT_PACKED_STRUCT ltt_trap_entry;
+static inline void ltt_ev_trap_entry(u16 trap_id, u32 address)
+#else
+typedef u64 trapid_t;
+typedef struct _ltt_trap_entry {
+	trapid_t trap_id;	/* Trap number */
+	u32 address;		/* Address where trap occured */
+} LTT_PACKED_STRUCT ltt_trap_entry;
+static inline void ltt_ev_trap_entry(trapid_t trap_id, u32 address)
+#endif
+{
+	ltt_trap_entry trap_event;
+
+	trap_event.trap_id = trap_id;
+	trap_event.address = address;
+
+	ltt_log_event(LTT_EV_TRAP_ENTRY, &trap_event);
+}
+
+/*  LTT_TRAP_EXIT */
+static inline void ltt_ev_trap_exit(void)
+{
+	ltt_log_event(LTT_EV_TRAP_EXIT, NULL);
+}
+
+/*  LTT_IRQ_ENTRY */
+typedef struct _ltt_irq_entry {
+	u8 irq_id;		/* IRQ number */
+	u8 kernel;		/* Are we executing kernel code */
+} LTT_PACKED_STRUCT ltt_irq_entry;
+static inline void ltt_ev_irq_entry(u8 irq_id, u8 in_kernel)
+{
+	ltt_irq_entry irq_entry;
+
+	irq_entry.irq_id = irq_id;
+	irq_entry.kernel = in_kernel;
+
+	ltt_log_event(LTT_EV_IRQ_ENTRY, &irq_entry);
+}
+
+/*  LTT_IRQ_EXIT */
+static inline void ltt_ev_irq_exit(void)
+{
+	ltt_log_event(LTT_EV_IRQ_EXIT, NULL);
+}
+
+/*  LTT_SCHEDCHANGE */
+typedef struct _ltt_schedchange {
+	u32 out;		/* Outgoing process */
+	u32 in;			/* Incoming process */
+	u32 out_state;		/* Outgoing process' state */
+} LTT_PACKED_STRUCT ltt_schedchange;
+static inline void ltt_ev_schedchange(task_t * task_out, task_t * task_in)
+{
+	ltt_schedchange sched_event;
+
+	sched_event.out = (u32) task_out->pid;
+	sched_event.in = (u32) task_in;
+	sched_event.out_state = (u32) task_out->state;
+
+	ltt_log_event(LTT_EV_SCHEDCHANGE, &sched_event);
+}
+
+/*  LTT_SOFT_IRQ */
+enum {
+	LTT_EV_SOFT_IRQ_BOTTOM_HALF = 1,	/* Conventional bottom-half */
+	LTT_EV_SOFT_IRQ_SOFT_IRQ,		/* Real soft-irq */
+	LTT_EV_SOFT_IRQ_TASKLET_ACTION,		/* Tasklet action */
+	LTT_EV_SOFT_IRQ_TASKLET_HI_ACTION	/* Tasklet hi-action */
+};
+typedef struct _ltt_soft_irq {
+	u8 event_sub_id;	/* Soft-irq event Id */
+	u32 event_data;
+} LTT_PACKED_STRUCT ltt_soft_irq;
+static inline void ltt_ev_soft_irq(u8 ev_id, u32 data)
+{
+	ltt_soft_irq soft_irq_event;
+
+	soft_irq_event.event_sub_id = ev_id;
+	soft_irq_event.event_data = data;
+
+	ltt_log_event(LTT_EV_SOFT_IRQ, &soft_irq_event);
+}
+
+/*  LTT_PROCESS */
+enum {
+	LTT_EV_PROCESS_KTHREAD = 1,	/* Creation of a kernel thread */
+	LTT_EV_PROCESS_FORK,		/* A fork or clone occured */
+	LTT_EV_PROCESS_EXIT,		/* An exit occured */
+	LTT_EV_PROCESS_WAIT,		/* A wait occured */
+	LTT_EV_PROCESS_SIGNAL,		/* A signal has been sent */
+	LTT_EV_PROCESS_WAKEUP		/* Wake up a process */
+};
+typedef struct _ltt_process {
+	u8 event_sub_id;	/* Process event ID */
+	u32 event_data1;
+	u32 event_data2;
+} LTT_PACKED_STRUCT ltt_process;
+static inline void ltt_ev_process(u8 ev_id, u32 data1, u32 data2)
+{
+	ltt_process proc_event;
+
+	proc_event.event_sub_id = ev_id;
+	proc_event.event_data1 = data1;
+	proc_event.event_data2 = data2;
+
+	ltt_log_event(LTT_EV_PROCESS, &proc_event);
+}
+static inline void ltt_ev_process_exit(u32 data1, u32 data2)
+{
+	ltt_process proc_event;
+
+	proc_event.event_sub_id = LTT_EV_PROCESS_EXIT;
+
+	/**** WARNING ****/
+	/* Regardless of whether this trace statement is active or not, these
+	two function must be called, otherwise there will be inconsistencies
+	in the kernel's structures. */
+	ltt_destroy_owners_events(current->pid);
+	ltt_free_all_handles(current);
+
+	ltt_log_event(LTT_EV_PROCESS, &proc_event);
+}
+
+/*  LTT_FILE_SYSTEM */
+enum {
+	LTT_EV_FILE_SYSTEM_BUF_WAIT_START = 1,	/* Starting to wait for a data buffer */
+	LTT_EV_FILE_SYSTEM_BUF_WAIT_END,	/* End to wait for a data buffer */
+	LTT_EV_FILE_SYSTEM_EXEC,		/* An exec occured */
+	LTT_EV_FILE_SYSTEM_OPEN,		/* An open occured */
+	LTT_EV_FILE_SYSTEM_CLOSE,		/* A close occured */
+	LTT_EV_FILE_SYSTEM_READ,		/* A read occured */
+	LTT_EV_FILE_SYSTEM_WRITE,		/* A write occured */
+	LTT_EV_FILE_SYSTEM_SEEK,		/* A seek occured */
+	LTT_EV_FILE_SYSTEM_IOCTL,		/* An ioctl occured */
+	LTT_EV_FILE_SYSTEM_SELECT,		/* A select occured */
+	LTT_EV_FILE_SYSTEM_POLL			/* A poll occured */
+};
+typedef struct _ltt_file_system {
+	u8 event_sub_id;	/* File system event ID */
+	u32 event_data1;
+	u32 event_data2;
+	char *file_name;	/* Name of file operated on */
+} LTT_PACKED_STRUCT ltt_file_system;
+static inline void ltt_ev_file_system(u8 ev_id, u32 data1, u32 data2, const unsigned char *file_name)
+{
+	ltt_file_system fs_event;
+
+	fs_event.event_sub_id = ev_id;
+	fs_event.event_data1 = data1;
+	fs_event.event_data2 = data2;
+	fs_event.file_name = (char*) file_name;
+
+	ltt_log_event(LTT_EV_FILE_SYSTEM, &fs_event);
+}
+
+/*  LTT_TIMER */
+enum {
+	LTT_EV_TIMER_EXPIRED = 1,	/* Timer expired */
+	LTT_EV_TIMER_SETITIMER,		/* Setting itimer occurred */
+	LTT_EV_TIMER_SETTIMEOUT		/* Setting sched timeout occurred */
+};
+typedef struct _ltt_timer {
+	u8 event_sub_id;	/* Timer event ID */
+	u8 event_sdata;		/* Short data */
+	u32 event_data1;
+	u32 event_data2;
+} LTT_PACKED_STRUCT ltt_timer;
+static inline void ltt_ev_timer(u8 ev_id, u8 sdata, u32 data1, u32 data2)
+{
+	ltt_timer timer_event;
+
+	timer_event.event_sub_id = ev_id;
+	timer_event.event_sdata = sdata;
+	timer_event.event_data1 = data1;
+	timer_event.event_data2 = data2;
+
+	ltt_log_event(LTT_EV_TIMER, &timer_event);
+}
+
+/*  LTT_MEMORY */
+enum {
+	LTT_EV_MEMORY_PAGE_ALLOC = 1,	/* Allocating pages */
+	LTT_EV_MEMORY_PAGE_FREE,	/* Freing pages */
+	LTT_EV_MEMORY_SWAP_IN,		/* Swaping pages in */
+	LTT_EV_MEMORY_SWAP_OUT,		/* Swaping pages out */
+	LTT_EV_MEMORY_PAGE_WAIT_START,	/* Start to wait for page */
+	LTT_EV_MEMORY_PAGE_WAIT_END	/* End to wait for page */
+};
+typedef struct _ltt_memory {
+	u8 event_sub_id;	/* Memory event ID */
+	u32 event_data;
+} LTT_PACKED_STRUCT ltt_memory;
+static inline void ltt_ev_memory(u8 ev_id, u32 data)
+{
+	ltt_memory memory_event;
+
+	memory_event.event_sub_id = ev_id;
+	memory_event.event_data = data;
+
+	ltt_log_event(LTT_EV_MEMORY, &memory_event);
+}
+
+/*  LTT_SOCKET */
+enum {
+	LTT_EV_SOCKET_CALL = 1,	/* A socket call occured */
+	LTT_EV_SOCKET_CREATE,	/* A socket has been created */
+	LTT_EV_SOCKET_SEND,	/* Data was sent to a socket */
+	LTT_EV_SOCKET_RECEIVE	/* Data was read from a socket */
+};
+typedef struct _ltt_socket {
+	u8 event_sub_id;	/* Socket event ID */
+	u32 event_data1;
+	u32 event_data2;
+} LTT_PACKED_STRUCT ltt_socket;
+static inline void ltt_ev_socket(u8 ev_id, u32 data1, u32 data2)
+{
+	ltt_socket socket_event;
+
+	socket_event.event_sub_id = ev_id;
+	socket_event.event_data1 = data1;
+	socket_event.event_data2 = data2;
+
+	ltt_log_event(LTT_EV_SOCKET, &socket_event);
+}
+
+/*  LTT_IPC */
+enum {
+	LTT_EV_IPC_CALL = 1,	/* A System V IPC call occured */
+	LTT_EV_IPC_MSG_CREATE,	/* A message queue has been created */
+	LTT_EV_IPC_SEM_CREATE,	/* A semaphore was created */
+	LTT_EV_IPC_SHM_CREATE	/* A shared memory segment has been created */
+};
+typedef struct _ltt_ipc {
+	u8 event_sub_id;	/* IPC event ID */
+	u32 event_data1;
+	u32 event_data2;
+} LTT_PACKED_STRUCT ltt_ipc;
+static inline void ltt_ev_ipc(u8 ev_id, u32 data1, u32 data2)
+{
+	ltt_ipc ipc_event;
+
+	ipc_event.event_sub_id = ev_id;
+	ipc_event.event_data1 = data1;
+	ipc_event.event_data2 = data2;
+
+	ltt_log_event(LTT_EV_IPC, &ipc_event);
+}
+
+/*  LTT_NETWORK */
+enum {
+	LTT_EV_NETWORK_PACKET_IN = 1,	/* A packet came in */
+	LTT_EV_NETWORK_PACKET_OUT	/* A packet was sent */
+};
+typedef struct _ltt_network {
+	u8 event_sub_id;	/* Network event ID */
+	u32 event_data;
+} LTT_PACKED_STRUCT ltt_network;
+static inline void ltt_ev_network(u8 ev_id, u32 data)
+{
+	ltt_network net_event;
+
+	net_event.event_sub_id = ev_id;
+	net_event.event_data = data;
+
+	ltt_log_event(LTT_EV_NETWORK, &net_event);
+}
+
+/* Start of trace buffer information */
+typedef struct _ltt_buffer_start {
+	struct timeval time;	/* Time stamp of this buffer */
+	u32 tsc;   		/* TSC of this buffer, if applicable */
+	u32 id;			/* Unique buffer ID */
+} LTT_PACKED_STRUCT ltt_buffer_start;
+
+/* End of trace buffer information */
+typedef struct _ltt_buffer_end {
+	struct timeval time;	/* Time stamp of this buffer */
+	u32 tsc;   		/* TSC of this buffer, if applicable */
+} LTT_PACKED_STRUCT ltt_buffer_end;
+
+/* Custom declared events */
+/* ***WARNING*** These structures should never be used as is, use the 
+   provided custom event creation and logging functions. */
+typedef struct _ltt_new_event {
+	/* Basics */
+	u32 id;					/* Custom event ID */
+	char type[LTT_CUSTOM_EV_TYPE_STR_LEN];	/* Event type description */
+	char desc[LTT_CUSTOM_EV_DESC_STR_LEN];	/* Detailed event description */
+
+	/* Custom formatting */
+	u32 format_type;			/* Type of formatting */
+	char form[LTT_CUSTOM_EV_FORM_STR_LEN];	/* Data specific to format */
+} LTT_PACKED_STRUCT ltt_new_event;
+typedef struct _ltt_custom {
+	u32 id;			/* Event ID */
+	u32 data_size;		/* Size of data recorded by event */
+	void *data;		/* Data recorded by event */
+} LTT_PACKED_STRUCT ltt_custom;
+
+/* LTT_CHANGE_MASK */
+typedef struct _ltt_change_mask {
+	ltt_event_mask mask;	/* Event mask */
+} LTT_PACKED_STRUCT ltt_change_mask;
+
+
+/*  LTT_HEARTBEAT */
+static inline void ltt_ev_heartbeat(void)
+{
+	ltt_log_event(LTT_EV_HEARTBEAT, NULL);
+}
+
+#else /* defined(CONFIG_LTT) */
+#define ltt_ev(ID, DATA)
+#define ltt_ev_trap_entry(ID, EIP)
+#define ltt_ev_trap_exit()
+#define ltt_ev_irq_entry(ID, KERNEL)
+#define ltt_ev_irq_exit()
+#define ltt_ev_schedchange(OUT, IN)
+#define ltt_ev_soft_irq(ID, DATA)
+#define ltt_ev_process(ID, DATA1, DATA2)
+#define ltt_ev_process_exit(DATA1, DATA2)
+#define ltt_ev_file_system(ID, DATA1, DATA2, FILE_NAME)
+#define ltt_ev_timer(ID, SDATA, DATA1, DATA2)
+#define ltt_ev_memory(ID, DATA)
+#define ltt_ev_socket(ID, DATA1, DATA2)
+#define ltt_ev_ipc(ID, DATA1, DATA2)
+#define ltt_ev_network(ID, DATA)
+#define ltt_ev_heartbeat()
+#endif /* defined(CONFIG_LTT) */
+#endif /* _LTT_EVENTS_H */
diff -uNrp linux-2.6.9/include/linux/preempt.h linux-2.6.9-ltt-r12/include/linux/preempt.h
--- linux-2.6.9/include/linux/preempt.h	2004-10-18 23:53:44.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/linux/preempt.h	2005-08-15 10:31:45.000000000 +0200
@@ -25,6 +25,47 @@ do { \
 
 asmlinkage void preempt_schedule(void);
 
+#ifdef CONFIG_ADEOS_CORE
+
+#include <asm/adeos.h>
+
+extern adomain_t *adp_cpu_current[],
+                 *adp_root;
+
+#define preempt_disable() \
+do { \
+	if (adp_current == adp_root) { \
+   	    inc_preempt_count();       \
+	    barrier(); \
+        } \
+} while (0)
+
+#define preempt_enable_no_resched() \
+do { \
+        if (adp_current == adp_root) { \
+	    barrier(); \
+	    dec_preempt_count(); \
+        } \
+} while (0)
+
+#define preempt_check_resched() \
+do { \
+        if (adp_current == adp_root) { \
+	    if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \
+		preempt_schedule(); \
+        } \
+} while (0)
+
+#define preempt_enable() \
+do { \
+	if (adp_current == adp_root) { \
+	    preempt_enable_no_resched(); \
+	    preempt_check_resched(); \
+        } \
+} while (0)
+
+#else /* !CONFIG_ADEOS_CORE */
+
 #define preempt_disable() \
 do { \
 	inc_preempt_count(); \
@@ -49,6 +90,8 @@ do { \
 	preempt_check_resched(); \
 } while (0)
 
+#endif /* CONFIG_ADEOS_CORE */
+
 #else
 
 #define preempt_disable()		do { } while (0)
diff -uNrp linux-2.6.9/include/linux/relayfs_fs.h linux-2.6.9-ltt-r12/include/linux/relayfs_fs.h
--- linux-2.6.9/include/linux/relayfs_fs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/include/linux/relayfs_fs.h	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,705 @@
+/*
+ * linux/include/linux/relayfs_fs.h
+ *
+ * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp
+ * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com)
+ *
+ * RelayFS definitions and declarations
+ *
+ * Please see Documentation/filesystems/relayfs.txt for more info.
+ */
+
+#ifndef _LINUX_RELAYFS_FS_H
+#define _LINUX_RELAYFS_FS_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+
+#ifdef CONFIG_ADEOS_CORE
+#define relay_irq_save(x)    adeos_hw_local_irq_save(x)
+#define relay_irq_restore(x) adeos_hw_local_irq_restore(x)
+#define relay_spin_lock_irqsave(x,flags)      adeos_spin_lock_irqsave(x,flags)
+#define relay_spin_unlock_irqrestore(x,flags) adeos_spin_unlock_irqrestore(x,flags)
+#else /* !CONFIG_ADEOS_CORE */
+#define relay_irq_save(x)    local_irq_save(x)
+#define relay_irq_restore(x) local_irq_restore(x)
+#define relay_spin_lock_irqsave(x,flags)      spin_lock_irqsave(x,flags)
+#define relay_spin_unlock_irqrestore(x,flags) spin_unlock_irqrestore(x,flags)
+#endif /* CONFIG_ADEOS_CORE */
+
+/*
+ * Tracks changes to rchan struct
+ */
+#define RELAYFS_CHANNEL_VERSION		1
+
+/*
+ * Maximum number of simultaneously open channels
+ */
+#define RELAY_MAX_CHANNELS		256
+
+/*
+ * Relay properties
+ */
+#define RELAY_MIN_BUFS			2
+#define RELAY_MIN_BUFSIZE		4096
+#define RELAY_MAX_BUFS			256
+#define RELAY_MAX_BUF_SIZE		0x1000000
+#define RELAY_MAX_TOTAL_BUF_SIZE	0x8000000
+
+/*
+ * Lockless scheme utility macros
+ */
+#define RELAY_MAX_BUFNO(bufno_bits) (1UL << (bufno_bits))
+#define RELAY_BUF_SIZE(offset_bits) (1UL << (offset_bits))
+#define RELAY_BUF_OFFSET_MASK(offset_bits) (RELAY_BUF_SIZE(offset_bits) - 1)
+#define RELAY_BUFNO_GET(index, offset_bits) ((index) >> (offset_bits))
+#define RELAY_BUF_OFFSET_GET(index, mask) ((index) & (mask))
+#define RELAY_BUF_OFFSET_CLEAR(index, mask) ((index) & ~(mask))
+
+/*
+ * Flags returned by relay_reserve()
+ */
+#define RELAY_BUFFER_SWITCH_NONE	0x0
+#define RELAY_WRITE_DISCARD_NONE	0x0
+#define RELAY_BUFFER_SWITCH		0x1
+#define RELAY_WRITE_DISCARD		0x2
+#define RELAY_WRITE_TOO_LONG		0x4
+
+/*
+ * Relay attribute flags
+ */
+#define RELAY_DELIVERY_BULK		0x1
+#define RELAY_DELIVERY_PACKET		0x2
+#define RELAY_SCHEME_LOCKLESS		0x4
+#define RELAY_SCHEME_LOCKING		0x8
+#define RELAY_SCHEME_ANY		0xC
+#define RELAY_TIMESTAMP_TSC		0x10
+#define RELAY_TIMESTAMP_GETTIMEOFDAY	0x20
+#define RELAY_TIMESTAMP_ANY		0x30
+#define RELAY_USAGE_SMP			0x40
+#define RELAY_USAGE_GLOBAL		0x80
+#define RELAY_MODE_CONTINUOUS		0x100
+#define RELAY_MODE_NO_OVERWRITE		0x200
+#define RELAY_MODE_START_AT_ZERO	0x400
+
+/*
+ * Flags for needs_resize() callback
+ */
+#define RELAY_RESIZE_NONE	0x0
+#define RELAY_RESIZE_EXPAND	0x1
+#define RELAY_RESIZE_SHRINK	0x2
+#define RELAY_RESIZE_REPLACE	0x4
+#define RELAY_RESIZE_REPLACED	0x8
+
+/*
+ * Values for fileop_notify() callback
+ */
+enum relay_fileop
+{
+	RELAY_FILE_OPEN,
+	RELAY_FILE_CLOSE,
+	RELAY_FILE_MAP,
+	RELAY_FILE_UNMAP
+};
+
+/*
+ * Data structure returned by relay_info()
+ */
+struct rchan_info
+{
+	u32 flags;		/* relay attribute flags for channel */
+	u32 buf_size;		/* channel's sub-buffer size */
+	char *buf_addr;		/* address of channel start */
+	u32 alloc_size;		/* total buffer size actually allocated */
+	u32 n_bufs;		/* number of sub-buffers in channel */
+	u32 cur_idx;		/* current write index into channel */
+	u32 bufs_produced;	/* current count of sub-buffers produced */
+	u32 bufs_consumed;	/* current count of sub-buffers consumed */
+	u32 buf_id;		/* buf_id of current sub-buffer */
+	int buffer_complete[RELAY_MAX_BUFS];	/* boolean per sub-buffer */
+	int unused_bytes[RELAY_MAX_BUFS];	/* count per sub-buffer */
+};
+
+/*
+ * Relay channel client callbacks
+ */
+struct rchan_callbacks
+{
+	/*
+	 * buffer_start - called at the beginning of a new sub-buffer
+	 * @rchan_id: the channel id
+	 * @current_write_pos: position in sub-buffer client should write to
+	 * @buffer_id: the id of the new sub-buffer
+	 * @start_time: the timestamp associated with the start of sub-buffer
+	 * @start_tsc: the TSC associated with the timestamp, if using_tsc
+	 * @using_tsc: boolean, indicates whether start_tsc is valid
+	 *
+	 * Return value should be the number of bytes written by the client.
+	 *
+	 * See Documentation/filesystems/relayfs.txt for details.
+	 */
+	int (*buffer_start) (int rchan_id,
+			     char *current_write_pos,
+			     u32 buffer_id,
+			     struct timeval start_time,
+			     u32 start_tsc,
+			     int using_tsc);
+
+	/*
+	 * buffer_end - called at the end of a sub-buffer
+	 * @rchan_id: the channel id
+	 * @current_write_pos: position in sub-buffer of end of data
+	 * @end_of_buffer: the position of the end of the sub-buffer
+	 * @end_time: the timestamp associated with the end of the sub-buffer
+	 * @end_tsc: the TSC associated with the end_time, if using_tsc
+	 * @using_tsc: boolean, indicates whether end_tsc is valid
+	 *
+	 * Return value should be the number of bytes written by the client.
+	 *
+	 * See Documentation/filesystems/relayfs.txt for details.
+	 */
+	int (*buffer_end) (int rchan_id,
+			   char *current_write_pos,
+			   char *end_of_buffer,
+			   struct timeval end_time,
+			   u32 end_tsc,
+			   int using_tsc);
+
+	/*
+	 * deliver - called when data is ready for the client
+	 * @rchan_id: the channel id
+	 * @from: the start of the delivered data
+	 * @len: the length of the delivered data
+	 *
+	 * See Documentation/filesystems/relayfs.txt for details.
+	 */
+	void (*deliver) (int rchan_id, char *from, u32 len);
+
+	/*
+	 * user_deliver - called when data has been written from userspace
+	 * @rchan_id: the channel id
+	 * @from: the start of the delivered data
+	 * @len: the length of the delivered data
+	 *
+	 * See Documentation/filesystems/relayfs.txt for details.
+	 */
+	void (*user_deliver) (int rchan_id, char *from, u32 len);
+
+	/*
+	 * needs_resize - called when a resizing event occurs
+	 * @rchan_id: the channel id
+	 * @resize_type: the type of resizing event
+	 * @suggested_buf_size: the suggested new sub-buffer size
+	 * @suggested_buf_size: the suggested new number of sub-buffers
+	 *
+	 * See Documentation/filesystems/relayfs.txt for details.
+	 */
+	void (*needs_resize)(int rchan_id,
+			     int resize_type,
+			     u32 suggested_buf_size,
+			     u32 suggested_n_bufs);
+
+	/*
+	 * fileop_notify - called on open/close/mmap/munmap of a relayfs file
+	 * @rchan_id: the channel id
+	 * @filp: relayfs file pointer
+	 * @fileop: which file operation is in progress
+	 *
+	 * The return value can direct the outcome of the operation.
+	 *
+	 * See Documentation/filesystems/relayfs.txt for details.
+	 */
+        int (*fileop_notify)(int rchan_id,
+			     struct file *filp,
+			     enum relay_fileop fileop);
+
+	/*
+	 * ioctl - called in ioctl context from userspace
+	 * @rchan_id: the channel id
+	 * @cmd: ioctl cmd
+	 * @arg: ioctl cmd arg
+	 *
+	 * The return value is returned as the value from the ioctl call.
+	 *
+	 * See Documentation/filesystems/relayfs.txt for details.
+	 */
+	int (*ioctl) (int rchan_id, unsigned int cmd, unsigned long arg);
+};
+
+/*
+ * Lockless scheme-specific data
+ */
+struct lockless_rchan
+{
+	u8 bufno_bits;		/* # bits used for sub-buffer id */
+	u8 offset_bits;		/* # bits used for offset within sub-buffer */
+	u32 index;		/* current index = sub-buffer id and offset */
+	u32 offset_mask;	/* used to obtain offset portion of index */
+	u32 index_mask;		/* used to mask off unused bits index */
+	atomic_t fill_count[RELAY_MAX_BUFS];	/* fill count per sub-buffer */
+};
+
+/*
+ * Locking scheme-specific data
+ */
+struct locking_rchan
+{
+	char *write_buf;		/* start of write sub-buffer */
+	char *write_buf_end;		/* end of write sub-buffer */
+	char *current_write_pos;	/* current write pointer */
+	char *write_limit;		/* takes reserves into account */
+	char *in_progress_event_pos;	/* used for interrupted writes */
+	u16 in_progress_event_size;	/* used for interrupted writes */
+	char *interrupted_pos;		/* used for interrupted writes */
+	u16 interrupting_size;		/* used for interrupted writes */
+	spinlock_t lock;		/* channel lock for locking scheme */
+};
+
+struct relay_ops;
+
+/*
+ * Offset resizing data structure
+ */
+struct resize_offset
+{
+	u32 ge;
+	u32 le;
+	int delta;
+};
+
+/*
+ * Relay channel data structure
+ */
+struct rchan
+{
+	u32 version;			/* the version of this struct */
+	char *buf;			/* the channel buffer */
+	union
+	{
+		struct lockless_rchan lockless;
+		struct locking_rchan locking;
+	} scheme;			/* scheme-specific channel data */
+
+	int id;				/* the channel id */
+	struct rchan_callbacks *callbacks;	/* client callbacks */
+	u32 flags;			/* relay channel attributes */
+	u32 buf_id;			/* current sub-buffer id */
+	u32 buf_idx;			/* current sub-buffer index */
+
+	atomic_t mapped;		/* map count */
+
+	atomic_t suspended;		/* channel suspended i.e full? */
+	int half_switch;		/* used internally for suspend */
+
+	struct timeval  buf_start_time;	/* current sub-buffer start time */
+	u32 buf_start_tsc;		/* current sub-buffer start TSC */
+	
+	u32 buf_size;			/* sub-buffer size */
+	u32 alloc_size;			/* total buffer size allocated */
+	u32 n_bufs;			/* number of sub-buffers */
+
+	u32 bufs_produced;		/* count of sub-buffers produced */
+	u32 bufs_consumed;		/* count of sub-buffers consumed */
+	u32 bytes_consumed;		/* bytes consumed in cur sub-buffer */
+	u32 read_start;			/* start VFS readers here */
+
+	int initialized;		/* first buffer initialized? */
+	int finalized;			/* channel finalized? */
+
+	u32 start_reserve;		/* reserve at start of sub-buffers */
+	u32 end_reserve;		/* reserve at end of sub-buffers */
+	u32 rchan_start_reserve;	/* additional reserve sub-buffer 0 */
+	
+	struct dentry *dentry;		/* channel file dentry */
+
+	wait_queue_head_t read_wait;	/* VFS read wait queue */
+	wait_queue_head_t write_wait;	/* VFS write wait queue */
+	struct work_struct wake_readers; /* reader wake-up work struct */
+	struct work_struct wake_writers; /* reader wake-up work struct */
+	atomic_t refcount;		/* channel refcount */
+
+	struct relay_ops *relay_ops;	/* scheme-specific channel ops */
+
+	int unused_bytes[RELAY_MAX_BUFS]; /* unused count per sub-buffer */
+
+	struct semaphore resize_sem;	/* serializes alloc/repace */
+	struct work_struct work;	/* resize allocation work struct */
+
+	struct list_head open_readers;	/* open readers for this channel */
+	rwlock_t open_readers_lock;	/* protection for open_readers list */
+
+	char *init_buf;			/* init channel buffer, if non-NULL */
+	
+	u32 resize_min;			/* minimum resized total buffer size */
+	u32 resize_max;			/* maximum resized total buffer size */
+	char *resize_buf;		/* for autosize alloc/free */
+	u32 resize_buf_size;		/* resized sub-buffer size */
+	u32 resize_n_bufs;		/* resized number of sub-buffers */
+	u32 resize_alloc_size;		/* resized actual total size */
+	int resizing;			/* is resizing in progress? */
+	int resize_err;			/* resizing err code */
+	int resize_failures;		/* number of resize failures */
+	int replace_buffer;		/* is the alloced buffer ready?  */
+	struct resize_offset resize_offset; /* offset change */
+	struct timer_list shrink_timer;	/* timer used for shrinking */
+	int resize_order;		/* size of last resize */
+	u32 expand_buf_id;		/* subbuf id expand will occur at */
+
+	struct page **buf_page_array;	/* array of current buffer pages */
+	int buf_page_count;		/* number of current buffer pages */
+	struct page **expand_page_array;/* new pages to be inserted */
+	int expand_page_count;		/* number of new pages */
+	struct page **shrink_page_array;/* old pages to be freed */
+	int shrink_page_count;		/* number of old pages */
+	struct page **resize_page_array;/* will become current pages */
+	int resize_page_count;		/* number of resize pages */
+	struct page **old_buf_page_array; /* hold for freeing */
+#ifdef CONFIG_ADEOS_CORE
+        struct list_head wake_link;
+        unsigned long wake_posted;
+#endif /* CONFIG_ADEOS_CORE */
+} ____cacheline_aligned;
+
+/*
+ * Relay channel reader struct
+ */
+struct rchan_reader
+{
+	struct list_head list;		/* for list inclusion */
+	struct rchan *rchan;		/* the channel we're reading from */
+	int auto_consume;		/* does this reader auto-consume? */
+	u32 bufs_consumed;		/* buffers this reader has consumed */
+	u32 bytes_consumed;		/* bytes consumed in cur sub-buffer */
+	int offset_changed;		/* have channel offsets changed? */
+	int vfs_reader;			/* are we a VFS reader? */
+	int map_reader;			/* are we an mmap reader? */
+
+	union
+	{
+		struct file *file;
+		u32 f_pos;
+	} pos;				/* current read offset */
+};
+
+/*
+ * These help make union member access less tedious
+ */
+#define channel_buffer(rchan) ((rchan)->buf)
+#define idx(rchan) ((rchan)->scheme.lockless.index)
+#define bufno_bits(rchan) ((rchan)->scheme.lockless.bufno_bits)
+#define offset_bits(rchan) ((rchan)->scheme.lockless.offset_bits)
+#define offset_mask(rchan) ((rchan)->scheme.lockless.offset_mask)
+#define idx_mask(rchan) ((rchan)->scheme.lockless.index_mask)
+#define bulk_delivery(rchan) (((rchan)->flags & RELAY_DELIVERY_BULK) ? 1 : 0)
+#define packet_delivery(rchan) (((rchan)->flags & RELAY_DELIVERY_PACKET) ? 1 : 0)
+#define using_lockless(rchan) (((rchan)->flags & RELAY_SCHEME_LOCKLESS) ? 1 : 0)
+#define using_locking(rchan) (((rchan)->flags & RELAY_SCHEME_LOCKING) ? 1 : 0)
+#define using_tsc(rchan) (((rchan)->flags & RELAY_TIMESTAMP_TSC) ? 1 : 0)
+#define using_gettimeofday(rchan) (((rchan)->flags & RELAY_TIMESTAMP_GETTIMEOFDAY) ? 1 : 0)
+#define usage_smp(rchan) (((rchan)->flags & RELAY_USAGE_SMP) ? 1 : 0)
+#define usage_global(rchan) (((rchan)->flags & RELAY_USAGE_GLOBAL) ? 1 : 0)
+#define mode_continuous(rchan) (((rchan)->flags & RELAY_MODE_CONTINUOUS) ? 1 : 0)
+#define fill_count(rchan, i) ((rchan)->scheme.lockless.fill_count[(i)])
+#define write_buf(rchan) ((rchan)->scheme.locking.write_buf)
+#define read_buf(rchan) ((rchan)->scheme.locking.read_buf)
+#define write_buf_end(rchan) ((rchan)->scheme.locking.write_buf_end)
+#define read_buf_end(rchan) ((rchan)->scheme.locking.read_buf_end)
+#define cur_write_pos(rchan) ((rchan)->scheme.locking.current_write_pos)
+#define read_limit(rchan) ((rchan)->scheme.locking.read_limit)
+#define write_limit(rchan) ((rchan)->scheme.locking.write_limit)
+#define in_progress_event_pos(rchan) ((rchan)->scheme.locking.in_progress_event_pos)
+#define in_progress_event_size(rchan) ((rchan)->scheme.locking.in_progress_event_size)
+#define interrupted_pos(rchan) ((rchan)->scheme.locking.interrupted_pos)
+#define interrupting_size(rchan) ((rchan)->scheme.locking.interrupting_size)
+#define channel_lock(rchan) ((rchan)->scheme.locking.lock)
+
+
+/**
+ *	calc_time_delta - utility function for time delta calculation
+ *	@now: current time
+ *	@start: start time
+ *
+ *	Returns the time delta produced by subtracting start time from now.
+ */
+static inline u32
+calc_time_delta(struct timeval *now, 
+		struct timeval *start)
+{
+	return (now->tv_sec - start->tv_sec) * 1000000
+		+ (now->tv_usec - start->tv_usec);
+}
+
+/**
+ *	recalc_time_delta - utility function for time delta recalculation
+ *	@now: current time
+ *	@new_delta: the new time delta calculated
+ *	@cpu: the associated CPU id
+ */
+static inline void 
+recalc_time_delta(struct timeval *now,
+		  u32 *new_delta,
+		  struct rchan *rchan)
+{
+	if (using_tsc(rchan) == 0)
+		*new_delta = calc_time_delta(now, &rchan->buf_start_time);
+}
+
+/**
+ *	have_cmpxchg - does this architecture have a cmpxchg?
+ *
+ *	Returns 1 if this architecture has a cmpxchg useable by 
+ *	the lockless scheme, 0 otherwise.
+ */
+static inline int 
+have_cmpxchg(void)
+{
+#if defined(__HAVE_ARCH_CMPXCHG)
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+/**
+ *	relay_write_direct - write data directly into destination buffer
+ */
+#define relay_write_direct(DEST, SRC, SIZE) \
+do\
+{\
+   memcpy(DEST, SRC, SIZE);\
+   DEST += SIZE;\
+} while (0);
+
+/**
+ *	relay_lock_channel - lock the relay channel if applicable
+ *
+ *	This macro only affects the locking scheme.  If the locking scheme
+ *	is in use and the channel usage is SMP, does a local_irq_save.  If the 
+ *	locking sheme is in use and the channel usage is GLOBAL, uses 
+ *	spin_lock_irqsave.  FLAGS is initialized to 0 since we know that
+ *	it is being initialized prior to use and we avoid the compiler warning.
+ */
+#define relay_lock_channel(RCHAN, FLAGS) \
+do\
+{\
+   FLAGS = 0;\
+   if (using_locking(RCHAN)) {\
+      if (usage_smp(RCHAN)) {\
+         relay_irq_save(FLAGS); \
+      } else {\
+         relay_spin_lock_irqsave(&(RCHAN)->scheme.locking.lock, FLAGS); \
+      }\
+   }\
+} while (0);
+
+/**
+ *	relay_unlock_channel - unlock the relay channel if applicable
+ *
+ *	This macro only affects the locking scheme.  See relay_lock_channel.
+ */
+#define relay_unlock_channel(RCHAN, FLAGS) \
+do\
+{\
+   if (using_locking(RCHAN)) {\
+      if (usage_smp(RCHAN)) {\
+         relay_irq_restore(FLAGS); \
+      } else {\
+         relay_spin_unlock_irqrestore(&(RCHAN)->scheme.locking.lock, FLAGS); \
+      }\
+   }\
+} while (0);
+
+/*
+ * Define cmpxchg if we don't have it
+ */
+#ifndef __HAVE_ARCH_CMPXCHG
+#define cmpxchg(p,o,n) 0
+#endif
+
+/*
+ * High-level relayfs kernel API, fs/relayfs/relay.c
+ */
+extern int
+relay_open(const char *chanpath,
+	   int bufsize,
+	   int nbufs,
+	   u32 flags,
+	   struct rchan_callbacks *channel_callbacks,
+	   u32 start_reserve,
+	   u32 end_reserve,
+	   u32 rchan_start_reserve,
+	   u32 resize_min,
+	   u32 resize_max,
+	   int mode,
+	   char *init_buf,
+	   u32 init_buf_size);
+
+extern int
+relay_close(int rchan_id);
+
+extern int
+relay_write(int rchan_id,
+	    const void *data_ptr, 
+	    size_t count,
+	    int td_offset,
+	    void **wrote_pos);
+
+extern ssize_t
+relay_read(struct rchan_reader *reader,
+	   char *buf,
+	   size_t count,
+	   int wait,
+	   u32 *actual_read_offset,
+	   u32 *new_offset);
+
+extern int
+relay_discard_init_buf(int rchan_id);
+
+extern struct rchan_reader *
+add_rchan_reader(int rchan_id, int autoconsume);
+
+extern int
+remove_rchan_reader(struct rchan_reader *reader);
+
+extern struct rchan_reader *
+add_map_reader(int rchan_id);
+
+extern int
+remove_map_reader(struct rchan_reader *reader);
+
+extern int 
+relay_info(int rchan_id, struct rchan_info *rchan_info);
+
+extern void 
+relay_buffers_consumed(struct rchan_reader *reader, u32 buffers_consumed);
+
+extern void
+relay_bytes_consumed(struct rchan_reader *reader, u32 bytes_consumed, u32 read_offset);
+
+extern ssize_t
+relay_bytes_avail(struct rchan_reader *reader);
+
+extern int
+relay_realloc_buffer(int rchan_id, u32 new_nbufs, int in_background);
+
+extern int
+relay_replace_buffer(int rchan_id);
+
+extern int
+rchan_empty(struct rchan_reader *reader);
+
+extern int
+rchan_full(struct rchan_reader *reader);
+
+extern void
+update_readers_consumed(struct rchan *rchan, u32 bufs_consumed, u32 bytes_consumed);
+
+extern int 
+__relay_mmap_buffer(struct rchan *rchan, struct vm_area_struct *vma);
+
+extern struct rchan_reader *
+__add_rchan_reader(struct rchan *rchan, struct file *filp, int auto_consume, int map_reader);
+
+extern void
+__remove_rchan_reader(struct rchan_reader *reader);
+
+/*
+ * Low-level relayfs kernel API, fs/relayfs/relay.c
+ */
+extern struct rchan *
+rchan_get(int rchan_id);
+
+extern void
+rchan_put(struct rchan *rchan);
+
+extern char *
+relay_reserve(struct rchan *rchan,
+	      u32 data_len,
+	      struct timeval *time_stamp,
+	      u32 *time_delta,
+	      int *errcode,
+	      int *interrupting);
+
+extern void 
+relay_commit(struct rchan *rchan,
+	     char *from, 
+	     u32 len, 
+	     int reserve_code,
+	     int interrupting);
+
+extern u32 
+relay_get_offset(struct rchan *rchan, u32 *max_offset);
+
+extern int
+relay_reset(int rchan_id);
+
+/*
+ * VFS functions, fs/relayfs/inode.c
+ */
+extern int 
+relayfs_create_dir(const char *name, 
+		   struct dentry *parent, 
+		   struct dentry **dentry);
+
+extern int
+relayfs_create_file(const char * name,
+		    struct dentry *parent, 
+		    struct dentry **dentry,
+		    void * data,
+		    int mode);
+
+extern int 
+relayfs_remove_file(struct dentry *dentry);
+
+extern int
+reset_index(struct rchan *rchan, u32 old_index);
+
+
+/*
+ * klog functions, fs/relayfs/klog.c
+ */
+extern int
+create_klog_channel(void);
+
+extern int
+remove_klog_channel(void);
+
+/*
+ * Scheme-specific channel ops
+ */
+struct relay_ops
+{
+	char * (*reserve) (struct rchan *rchan,
+			   u32 slot_len,
+			   struct timeval *time_stamp,
+			   u32 *tsc,
+			   int * errcode,
+			   int * interrupting);
+	
+	void (*commit) (struct rchan *rchan,
+			char *from,
+			u32 len, 
+			int deliver, 
+			int interrupting);
+
+	u32 (*get_offset) (struct rchan *rchan,
+			   u32 *max_offset);
+	
+	void (*resume) (struct rchan *rchan);
+	void (*finalize) (struct rchan *rchan);
+	void (*reset) (struct rchan *rchan,
+		       int init);
+	int (*reset_index) (struct rchan *rchan,
+			    u32 old_index);
+};
+
+#endif /* _LINUX_RELAYFS_FS_H */
+
+
+
+
+
diff -uNrp linux-2.6.9/include/linux/sched.h linux-2.6.9-ltt-r12/include/linux/sched.h
--- linux-2.6.9/include/linux/sched.h	2004-10-18 23:53:13.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/linux/sched.h	2005-08-15 10:31:45.000000000 +0200
@@ -4,6 +4,9 @@
 #include <asm/param.h>	/* for HZ */
 
 #include <linux/config.h>
+#ifdef CONFIG_ADEOS_CORE
+#include <linux/adeos.h>
+#endif /* CONFIG_ADEOS_CORE */
 #include <linux/capability.h>
 #include <linux/threads.h>
 #include <linux/kernel.h>
@@ -584,6 +587,10 @@ struct task_struct {
   	struct mempolicy *mempolicy;
   	short il_next;		/* could be shared with used_math */
 #endif
+
+#ifdef CONFIG_ADEOS_CORE
+        void *ptd[ADEOS_ROOT_NPTDKEYS];
+#endif /* CONFIG_ADEOS_CORE */
 };
 
 static inline pid_t process_group(struct task_struct *tsk)
diff -uNrp linux-2.6.9/include/linux/seqlock.h linux-2.6.9-ltt-r12/include/linux/seqlock.h
--- linux-2.6.9/include/linux/seqlock.h	2004-10-18 23:54:07.000000000 +0200
+++ linux-2.6.9-ltt-r12/include/linux/seqlock.h	2005-08-15 10:51:46.000000000 +0200
@@ -30,6 +30,10 @@
 #include <linux/spinlock.h>
 #include <linux/preempt.h>
 
+#ifdef CONFIG_ADEOS_CORE
+#include <asm/adeos.h>
+#endif /* CONFIG_ADEOS_CORE */
+
 typedef struct {
 	unsigned sequence;
 	spinlock_t lock;
@@ -49,6 +53,9 @@ typedef struct {
  */
 static inline void write_seqlock(seqlock_t *sl)
 {
+#ifdef CONFIG_ADEOS_CORE
+        adeos_hw_cli();
+#endif /* CONFIG_ADEOS_CORE */
 	spin_lock(&sl->lock);
 	++sl->sequence;
 	smp_wmb();			
@@ -59,16 +66,27 @@ static inline void write_sequnlock(seqlo
 	smp_wmb();
 	sl->sequence++;
 	spin_unlock(&sl->lock);
+#ifdef CONFIG_ADEOS_CORE
+        adeos_hw_sti();
+#endif /* CONFIG_ADEOS_CORE */	
 }
 
 static inline int write_tryseqlock(seqlock_t *sl)
 {
-	int ret = spin_trylock(&sl->lock);
-
+        int ret;
+#ifdef CONFIG_ADEOS_CORE
+        adeos_hw_cli();
+#endif /* CONFIG_ADEOS_CORE */    
+	ret = spin_trylock(&sl->lock);
+	
 	if (ret) {
 		++sl->sequence;
 		smp_wmb();			
 	}
+	else
+#ifdef CONFIG_ADEOS_CORE
+	    adeos_hw_sti();
+#endif /* CONFIG_ADEOS_CORE */    	    
 	return ret;
 }
 
@@ -148,6 +166,32 @@ static inline void write_seqcount_end(se
 /*
  * Possible sw/hw IRQ protected versions of the interfaces.
  */
+#ifdef CONFIG_ADEOS_CORE
+
+#define write_seqlock_irqsave(lock, flags)				\
+    do { adeos_hw_local_irq_save(flags);				\
+	write_seqlock(lock); } while (0)
+#define write_seqlock_irq(lock)						\
+    do { adeos_hw_cli();						\
+	write_seqlock(lock); } while (0)
+#define write_seqlock_bh(lock)						\
+    do { adeos_hw_cli();						\
+	local_bh_disable();						\
+	write_seqlock(lock); } while (0)
+
+#define write_sequnlock_irqrestore(lock, flags)				\
+    do { write_sequnlock(lock);						\
+	adeos_hw_local_irq_restore(flags); } while(0)
+#define write_sequnlock_irq(lock)					\
+    do { write_sequnlock(lock);						\
+	adeos_hw_sti(); } while(0)
+#define write_sequnlock_bh(lock)					\
+    do { write_sequnlock(lock);						\
+	local_bh_enable();						\
+	adeos_hw_sti(); } while(0)
+
+#else /* !CONFIG_ADEOS_CORE */
+
 #define write_seqlock_irqsave(lock, flags)				\
 	do { local_irq_save(flags); write_seqlock(lock); } while (0)
 #define write_seqlock_irq(lock)						\
@@ -162,6 +206,8 @@ static inline void write_seqcount_end(se
 #define write_sequnlock_bh(lock)					\
 	do { write_sequnlock(lock); local_bh_enable(); } while(0)
 
+#endif /* CONFIG_ADEOS_CORE */
+
 #define read_seqbegin_irqsave(lock, flags)				\
 	({ local_irq_save(flags);   read_seqbegin(lock); })
 
diff -uNrp linux-2.6.9/init/Kconfig linux-2.6.9-ltt-r12/init/Kconfig
--- linux-2.6.9/init/Kconfig	2004-10-18 23:54:55.000000000 +0200
+++ linux-2.6.9-ltt-r12/init/Kconfig	2005-08-15 10:51:46.000000000 +0200
@@ -56,6 +56,7 @@ menu "General setup"
 
 config LOCALVERSION
 	string "Local version - append to kernel release"
+	default "-adeos"
 	help
 	  Append an extra string to the end of your kernel version.
 	  This will show up when you type uname, for example.
@@ -293,6 +294,38 @@ config CC_OPTIMIZE_FOR_SIZE
 
 	  If unsure, say N.
 
+config LTT
+	bool "Linux Trace Toolkit support"
+	depends on RELAYFS_FS=y
+	default n
+	---help---
+	  It is possible for the kernel to log important events to a trace
+	  facility. 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 tracer that keeps the events in a data buffer (uses
+	         relayfs).
+	      3) A trace daemon that interacts with the tracer and is
+	         notified every time there is a certain quantity of data to
+	         read from the tracer.
+	      4) A trace event data decoder that reads the accumulated data
+	         and formats it in a human-readable format.
+
+	  If you say Y, the first two components will be built into the kernel.
+	  Critical parts of the kernel will call upon the kernel tracing
+	  function. The data is then recorded by the tracer if a trace daemon
+	  is running in user-space and has issued a "start" command.
+
+	  In order to enable LTT support you must first select relayfs as
+	  built-in.
+
+	  For more information on kernel tracing, the trace daemon or the event
+	  decoder, please check the following address :
+	       http://www.opersys.com/ltt
+
 config SHMEM
 	default y
 	bool "Use full shmem filesystem" if EMBEDDED && MMU
diff -uNrp linux-2.6.9/init/main.c linux-2.6.9-ltt-r12/init/main.c
--- linux-2.6.9/init/main.c	2004-10-18 23:53:23.000000000 +0200
+++ linux-2.6.9-ltt-r12/init/main.c	2005-08-15 10:31:45.000000000 +0200
@@ -513,6 +513,9 @@ asmlinkage void __init start_kernel(void
 	trap_init();
 	rcu_init();
 	init_IRQ();
+#ifdef CONFIG_ADEOS_CORE
+ 	__adeos_init();
+#endif /* CONFIG_ADEOS_CORE */
 	pidhash_init();
 	init_timers();
 	softirq_init();
@@ -643,6 +646,10 @@ static void __init do_basic_setup(void)
 	sock_init();
 
 	do_initcalls();
+
+#ifdef CONFIG_ADEOS
+	__adeos_takeover();
+#endif /* CONFIG_ADEOS */
 }
 
 static void do_pre_smp_initcalls(void)
diff -uNrp linux-2.6.9/ipc/msg.c linux-2.6.9-ltt-r12/ipc/msg.c
--- linux-2.6.9/ipc/msg.c	2004-10-18 23:53:06.000000000 +0200
+++ linux-2.6.9-ltt-r12/ipc/msg.c	2005-08-15 10:51:46.000000000 +0200
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/security.h>
 #include <linux/sched.h>
+#include <linux/ltt-events.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include "util.h"
@@ -228,6 +229,7 @@ asmlinkage long sys_msgget (key_t key, i
 		msg_unlock(msq);
 	}
 	up(&msg_ids.sem);
+	ltt_ev_ipc(LTT_EV_IPC_MSG_CREATE, ret, msgflg);
 	return ret;
 }
 
diff -uNrp linux-2.6.9/ipc/sem.c linux-2.6.9-ltt-r12/ipc/sem.c
--- linux-2.6.9/ipc/sem.c	2004-10-18 23:53:50.000000000 +0200
+++ linux-2.6.9-ltt-r12/ipc/sem.c	2005-08-15 10:51:46.000000000 +0200
@@ -71,10 +71,10 @@
 #include <linux/time.h>
 #include <linux/smp_lock.h>
 #include <linux/security.h>
+#include <linux/ltt-events.h>
 #include <asm/uaccess.h>
 #include "util.h"
 
-
 #define sem_lock(id)	((struct sem_array*)ipc_lock(&sem_ids,id))
 #define sem_unlock(sma)	ipc_unlock(&(sma)->sem_perm)
 #define sem_rmid(id)	((struct sem_array*)ipc_rmid(&sem_ids,id))
@@ -238,6 +238,7 @@ asmlinkage long sys_semget (key_t key, i
 	}
 
 	up(&sem_ids.sem);
+	ltt_ev_ipc(LTT_EV_IPC_SEM_CREATE, err, semflg);
 	return err;
 }
 
diff -uNrp linux-2.6.9/ipc/shm.c linux-2.6.9-ltt-r12/ipc/shm.c
--- linux-2.6.9/ipc/shm.c	2004-10-18 23:54:08.000000000 +0200
+++ linux-2.6.9-ltt-r12/ipc/shm.c	2005-08-15 10:51:46.000000000 +0200
@@ -26,6 +26,7 @@
 #include <linux/proc_fs.h>
 #include <linux/shmem_fs.h>
 #include <linux/security.h>
+#include <linux/ltt-events.h>
 #include <asm/uaccess.h>
 
 #include "util.h"
@@ -276,7 +277,7 @@ asmlinkage long sys_shmget (key_t key, s
 		shm_unlock(shp);
 	}
 	up(&shm_ids.sem);
-
+	ltt_ev_ipc(LTT_EV_IPC_SHM_CREATE, err, shmflg);
 	return err;
 }
 
diff -uNrp linux-2.6.9/kernel/Makefile linux-2.6.9-ltt-r12/kernel/Makefile
--- linux-2.6.9/kernel/Makefile	2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/Makefile	2005-08-15 10:51:46.000000000 +0200
@@ -9,6 +9,7 @@ obj-y     = sched.o fork.o exec_domain.o
 	    rcupdate.o intermodule.o extable.o params.o posix-timers.o \
 	    kthread.o
 
+obj-$(CONFIG_ADEOS_CORE) += adeos.o
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o spinlock.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+obj-$(CONFIG_LTT) += ltt-core.o
 obj-$(CONFIG_COMPAT) += compat.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_IKCONFIG_PROC) += configs.o
diff -uNrp linux-2.6.9/kernel/adeos.c linux-2.6.9-ltt-r12/kernel/adeos.c
--- linux-2.6.9/kernel/adeos.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/kernel/adeos.c	2005-08-15 10:31:45.000000000 +0200
@@ -0,0 +1,799 @@
+/*
+ *   linux/kernel/adeos.c
+ *
+ *   Copyright (C) 2002,2003,2004 Philippe Gerum.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *   Architecture-independent ADEOS core support.
+ */
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif /* CONFIG_PROC_FS */
+
+/* The pre-defined domain slot for the root domain. */
+static adomain_t adeos_root_domain;
+
+/* A constant pointer to the root domain. */
+adomain_t *adp_root = &adeos_root_domain;
+
+/* A pointer to the current domain. */
+adomain_t *adp_cpu_current[ADEOS_NR_CPUS] = { [ 0 ... ADEOS_NR_CPUS - 1] = &adeos_root_domain };
+
+/* The spinlock protecting from races while modifying the pipeline. */
+raw_spinlock_t __adeos_pipelock = RAW_SPIN_LOCK_UNLOCKED;
+
+/* The pipeline data structure. Enqueues adomain_t objects by priority. */
+struct list_head __adeos_pipeline;
+
+/* A global flag telling whether Adeos pipelining is engaged. */
+int adp_pipelined;
+
+/* An array of global counters tracking domains monitoring events. */
+int __adeos_event_monitors[ADEOS_NR_EVENTS] = { [ 0 ... ADEOS_NR_EVENTS - 1] = 0 };
+
+/* The allocated VIRQ map. */
+unsigned long __adeos_virtual_irq_map = 0;
+
+/* A VIRQ to kick printk() output out when the root domain is in control. */
+unsigned __adeos_printk_virq;
+
+#ifdef CONFIG_ADEOS_PROFILING
+adprofdata_t __adeos_profile_data[ADEOS_NR_CPUS];
+#endif /* CONFIG_ADEOS_PROFILING */
+
+static void __adeos_set_root_ptd (int key, void *value) {
+
+    current->ptd[key] = value;
+}
+
+static void *__adeos_get_root_ptd (int key) {
+
+    return current->ptd[key];
+}
+
+/* adeos_init() -- Initialization routine of the ADEOS layer. Called
+   by the host kernel early during the boot procedure. */
+
+void __adeos_init (void)
+
+{
+    adomain_t *adp = &adeos_root_domain;
+
+    __adeos_check_platform();	/* Do platform dependent checks first. */
+
+    /*
+      A lightweight registration code for the root domain. Current
+      assumptions are:
+      - We are running on the boot CPU, and secondary CPUs are still
+      lost in space.
+      - adeos_root_domain has been zero'ed.
+    */
+
+    INIT_LIST_HEAD(&__adeos_pipeline);
+
+    adp->name = "Linux";
+    adp->domid = ADEOS_ROOT_ID;
+    adp->priority = ADEOS_ROOT_PRI;
+    adp->ptd_setfun = &__adeos_set_root_ptd;
+    adp->ptd_getfun = &__adeos_get_root_ptd;
+    adp->ptd_keymax = ADEOS_ROOT_NPTDKEYS;
+
+    __adeos_init_stage(adp);
+
+    INIT_LIST_HEAD(&adp->p_link);
+    list_add_tail(&adp->p_link,&__adeos_pipeline);
+
+    __adeos_init_platform();
+
+    __adeos_printk_virq = adeos_alloc_irq(); /* Cannot fail here. */
+    adp->irqs[__adeos_printk_virq].handler = &__adeos_flush_printk; 
+    adp->irqs[__adeos_printk_virq].acknowledge = NULL; 
+    adp->irqs[__adeos_printk_virq].control = IPIPE_HANDLE_MASK; 
+
+    printk(KERN_INFO "Adeos %s: Root domain %s registered.\n",
+	   ADEOS_VERSION_STRING,
+	   adp->name);
+}
+
+/* adeos_handle_event() -- Adeos' generic event handler. This routine
+   calls the per-domain handlers registered for a given
+   exception/event. Each domain before the one which raised the event
+   in the pipeline will get a chance to process the event. The latter
+   will eventually be allowed to process its own event too if a valid
+   handler exists for it.  Handler executions are always scheduled by
+   the domain which raised the event for the higher priority domains
+   wanting to be notified of such event.  Note: evdata might be
+   NULL. */
+
+#ifdef CONFIG_ADEOS_THREADS
+
+asmlinkage int __adeos_handle_event (unsigned event, void *evdata)
+/* asmlinkage is there just in case CONFIG_REGPARM is enabled... */
+{
+    struct list_head *pos, *npos;
+    adomain_t *this_domain;
+    unsigned long flags;
+    adeos_declare_cpuid;
+    adevinfo_t evinfo;
+    int propagate = 1;
+
+    adeos_lock_cpu(flags);
+
+    this_domain = adp_cpu_current[cpuid];
+
+    list_for_each_safe(pos,npos,&__adeos_pipeline) {
+
+    	adomain_t *next_domain = list_entry(pos,adomain_t,p_link);
+
+	if (next_domain->events[event].handler != NULL)
+	    {
+	    if (next_domain == this_domain)
+		{
+		adeos_unlock_cpu(flags);
+		evinfo.domid = this_domain->domid;
+		evinfo.event = event;
+		evinfo.evdata = evdata;
+		evinfo.propagate = 0;
+		this_domain->events[event].handler(&evinfo);
+		propagate = evinfo.propagate;
+		goto done;
+		}
+
+	    next_domain->cpudata[cpuid].event_info.domid = this_domain->domid;
+	    next_domain->cpudata[cpuid].event_info.event = event;
+	    next_domain->cpudata[cpuid].event_info.evdata = evdata;
+	    next_domain->cpudata[cpuid].event_info.propagate = 0;
+	    __set_bit(IPIPE_XPEND_FLAG,&next_domain->cpudata[cpuid].status);
+
+	    /* Let the higher priority domain process the event. */
+	    __adeos_switch_to(this_domain,next_domain,cpuid);
+	    
+	    adeos_load_cpuid();	/* Processor might have changed. */
+
+	    if (!next_domain->cpudata[cpuid].event_info.propagate)
+		{
+		propagate = 0;
+		break;
+		}
+	    }
+
+	if (next_domain == this_domain)
+	    break;
+    }
+
+    adeos_unlock_cpu(flags);
+
+ done:
+
+    return !propagate;
+}
+
+#else /* !CONFIG_ADEOS_THREADS */
+
+asmlinkage int __adeos_handle_event (unsigned event, void *evdata)
+/* asmlinkage is there just in case CONFIG_REGPARM is enabled... */
+{
+    adomain_t *start_domain, *this_domain, *next_domain;
+    struct list_head *pos, *npos;
+    unsigned long flags;
+    adeos_declare_cpuid;
+    adevinfo_t evinfo;
+    int propagate = 1;
+
+    adeos_lock_cpu(flags);
+
+    start_domain = this_domain = adp_cpu_current[cpuid];
+
+    list_for_each_safe(pos,npos,&__adeos_pipeline) {
+
+    	next_domain = list_entry(pos,adomain_t,p_link);
+
+	if (next_domain->events[event].handler != NULL)
+	    {
+	    adp_cpu_current[cpuid] = next_domain;
+	    evinfo.domid = start_domain->domid;
+	    adeos_unlock_cpu(flags);
+	    evinfo.event = event;
+	    evinfo.evdata = evdata;
+	    evinfo.propagate = 0;
+	    next_domain->events[event].handler(&evinfo);
+	    adeos_lock_cpu(flags);
+
+	    if (adp_cpu_current[cpuid] != next_domain)
+		/* Something has changed the current domain under our
+		   feet recycling the register set; take note. */
+		this_domain = adp_cpu_current[cpuid];
+
+	    propagate = evinfo.propagate;
+	    }
+
+	if (next_domain == this_domain || !propagate)
+	    break;
+    }
+
+    adp_cpu_current[cpuid] = this_domain;
+
+    adeos_unlock_cpu(flags);
+
+    return !propagate;
+}
+
+#endif /* CONFIG_ADEOS_THREADS */
+
+void __adeos_stall_root (void)
+
+{
+    if (adp_pipelined)
+	{
+	adeos_declare_cpuid;
+
+#ifdef CONFIG_SMP
+	unsigned long flags;
+	adeos_lock_cpu(flags);
+	__set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+	adeos_unlock_cpu(flags);
+#else /* !CONFIG_SMP */
+	set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+#endif /* CONFIG_SMP */
+	}
+    else
+	adeos_hw_cli();
+}
+
+void __adeos_unstall_root (void)
+
+{
+    if (adp_pipelined)
+	{
+	adeos_declare_cpuid;
+
+	adeos_hw_cli();
+
+	adeos_load_cpuid();
+
+	__clear_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+
+	if (adp_root->cpudata[cpuid].irq_pending_hi != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	}
+
+    adeos_hw_sti();	/* Needed in both cases. */
+}
+
+unsigned long __adeos_test_root (void)
+
+{
+    if (adp_pipelined)
+	{
+	adeos_declare_cpuid;
+	unsigned long s;
+
+#ifdef CONFIG_SMP
+	unsigned long flags;
+	adeos_lock_cpu(flags);
+	s = test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+	adeos_unlock_cpu(flags);
+#else /* !CONFIG_SMP */
+	s = test_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+#endif /* CONFIG_SMP */
+
+	return s;
+	}
+
+    return adeos_hw_irqs_disabled();
+}
+
+unsigned long __adeos_test_and_stall_root (void)
+
+{
+    unsigned long flags;
+
+    if (adp_pipelined)
+	{
+	adeos_declare_cpuid;
+	unsigned long s;
+
+#ifdef CONFIG_SMP
+	adeos_lock_cpu(flags);
+	s = __test_and_set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+	adeos_unlock_cpu(flags);
+#else /* !CONFIG_SMP */
+	s = test_and_set_bit(IPIPE_STALL_FLAG,&adp_root->cpudata[cpuid].status);
+#endif /* CONFIG_SMP */
+
+	return s;
+	}
+
+    adeos_hw_local_irq_save(flags);
+
+    return !adeos_hw_test_iflag(flags);
+}
+
+void fastcall __adeos_restore_root (unsigned long flags)
+
+{
+    if (flags)
+	__adeos_stall_root();
+    else
+	__adeos_unstall_root();
+}
+
+/* adeos_unstall_pipeline_from() -- Unstall the interrupt pipeline and
+   synchronize pending events from a given domain. */
+
+void fastcall adeos_unstall_pipeline_from (adomain_t *adp)
+
+{
+    adomain_t *this_domain;
+    struct list_head *pos;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(flags);
+
+    __clear_bit(IPIPE_STALL_FLAG,&adp->cpudata[cpuid].status);
+
+    this_domain = adp_cpu_current[cpuid];
+
+    if (adp == this_domain)
+	{
+	if (adp->cpudata[cpuid].irq_pending_hi != 0)
+	    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+	goto release_cpu_and_exit;
+	}
+
+    /* Attempt to flush all events that might be pending at the
+       unstalled domain level. This code is roughly lifted from
+       __adeos_walk_pipeline(). */
+
+    list_for_each(pos,&__adeos_pipeline) {
+
+    	adomain_t *next_domain = list_entry(pos,adomain_t,p_link);
+
+	if (test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status))
+	    break; /* Stalled stage -- do not go further. */
+
+	if (next_domain->cpudata[cpuid].irq_pending_hi != 0)
+	    {
+	    /* Since the critical IPI might be triggered by the
+	       following actions, the current domain might not be
+	       linked to the pipeline anymore after its handler
+	       returns on SMP boxen, even if the domain remains valid
+	       (see adeos_unregister_domain()), so don't make any
+	       hazardous assumptions here. */
+
+	    if (next_domain == this_domain)
+		__adeos_sync_stage(IPIPE_IRQMASK_ANY);
+	    else
+		{
+		__adeos_switch_to(this_domain,next_domain,cpuid);
+
+		adeos_load_cpuid(); /* Processor might have changed. */
+
+		if (this_domain->cpudata[cpuid].irq_pending_hi != 0 &&
+		    !test_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status))
+		    __adeos_sync_stage(IPIPE_IRQMASK_ANY);
+		}
+	    
+	    break;
+	    }
+	else if (next_domain == this_domain)
+	    break;
+    }
+
+release_cpu_and_exit:
+
+    if (__adeos_pipeline_head_p(adp))
+	adeos_hw_sti();
+    else
+	adeos_unlock_cpu(flags);
+}
+
+/* adeos_suspend_domain() -- tell the ADEOS layer that the current
+   domain is now dormant. The calling domain is switched out, while
+   the next domain with work in progress or pending in the pipeline is
+   switched in. */
+
+#ifdef CONFIG_ADEOS_THREADS
+
+#define __flush_pipeline_stage() \
+do { \
+    if (!test_bit(IPIPE_STALL_FLAG,&cpudata->status) && \
+	cpudata->irq_pending_hi != 0) \
+	{ \
+	__adeos_sync_stage(IPIPE_IRQMASK_ANY); \
+	adeos_load_cpuid(); \
+	cpudata = &this_domain->cpudata[cpuid]; \
+	} \
+} while(0)
+
+void adeos_suspend_domain (void)
+
+{
+    adomain_t *this_domain, *next_domain;
+    struct adcpudata *cpudata;
+    struct list_head *ln;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(flags);
+
+    this_domain = next_domain = adp_cpu_current[cpuid];
+    cpudata = &this_domain->cpudata[cpuid];
+
+    /* A suspending domain implicitely unstalls the pipeline. */
+    __clear_bit(IPIPE_STALL_FLAG,&cpudata->status);
+
+    /* Make sure that no event remains stuck in the pipeline. This
+       could happen with emerging SMP instances, or domains which
+       forget to unstall their stage before calling us. */
+    __flush_pipeline_stage();
+
+    for (;;)
+	{
+	ln = next_domain->p_link.next;
+
+	if (ln == &__adeos_pipeline)	/* End of pipeline reached? */
+	    /* Caller should loop on its idle task on return. */
+	    goto release_cpu_and_exit;
+
+	next_domain = list_entry(ln,adomain_t,p_link);
+
+	/* Make sure the domain was preempted (i.e. not sleeping) or
+	   has some event to process before switching to it. */
+
+	if (__adeos_domain_work_p(next_domain,cpuid))
+	    break;
+	}
+
+    /* Mark the outgoing domain as aslept (i.e. not preempted). */
+    __set_bit(IPIPE_SLEEP_FLAG,&cpudata->status);
+
+    /* Suspend the calling domain, switching to the next one. */
+    __adeos_switch_to(this_domain,next_domain,cpuid);
+
+#ifdef CONFIG_SMP
+    adeos_load_cpuid();	/* Processor might have changed. */
+    cpudata = &this_domain->cpudata[cpuid];
+#endif /* CONFIG_SMP */
+
+    /* Clear the sleep bit for the incoming domain. */
+    __clear_bit(IPIPE_SLEEP_FLAG,&cpudata->status);
+
+    /* Now, we are back into the calling domain. Flush the interrupt
+       log and fire the event interposition handler if needed.  CPU
+       migration is allowed in SMP-mode on behalf of an event handler
+       provided that the current domain raised it. Otherwise, it's
+       not. */
+
+    __flush_pipeline_stage();
+
+    if (__test_and_clear_bit(IPIPE_XPEND_FLAG,&cpudata->status))
+	{
+	adeos_unlock_cpu(flags);
+	this_domain->events[cpudata->event_info.event].handler(&cpudata->event_info);
+	return;
+	}
+
+release_cpu_and_exit:
+
+    adeos_unlock_cpu(flags);
+
+    /* Return to the point of suspension in the calling domain. */
+}
+
+#else /* !CONFIG_ADEOS_THREADS */
+
+void adeos_suspend_domain (void)
+
+{
+    adomain_t *this_domain, *next_domain;
+    struct list_head *ln;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(flags);
+
+    this_domain = next_domain = adp_cpu_current[cpuid];
+
+    __clear_bit(IPIPE_STALL_FLAG,&this_domain->cpudata[cpuid].status);
+
+    if (this_domain->cpudata[cpuid].irq_pending_hi != 0)
+	goto sync_stage;
+
+    for (;;)
+	{
+	ln = next_domain->p_link.next;
+
+	if (ln == &__adeos_pipeline)
+	    break;
+
+	next_domain = list_entry(ln,adomain_t,p_link);
+
+	if (test_bit(IPIPE_STALL_FLAG,&next_domain->cpudata[cpuid].status))
+	    break;
+
+	if (next_domain->cpudata[cpuid].irq_pending_hi == 0)
+	    continue;
+
+	adp_cpu_current[cpuid] = next_domain;
+
+	if (next_domain->dswitch)
+	    next_domain->dswitch();
+
+ sync_stage:
+
+	__adeos_sync_stage(IPIPE_IRQMASK_ANY);
+
+	adeos_load_cpuid();	/* Processor might have changed. */
+
+	if (adp_cpu_current[cpuid] != next_domain)
+	    /* Something has changed the current domain under our feet
+	       recycling the register set; take note. */
+	    this_domain = adp_cpu_current[cpuid];
+	}
+
+    adp_cpu_current[cpuid] = this_domain;
+
+    adeos_unlock_cpu(flags);
+}
+
+#endif /* CONFIG_ADEOS_THREADS */
+
+/* adeos_alloc_irq() -- Allocate a virtual/soft pipelined interrupt.
+   Virtual interrupts are handled in exactly the same way than their
+   hw-generated counterparts. This is a very basic, one-way only,
+   inter-domain communication system (see adeos_trigger_irq()).  Note:
+   it is not necessary for a domain to allocate a virtual interrupt to
+   trap it using adeos_virtualize_irq(). The newly allocated VIRQ
+   number which can be passed to other IRQ-related services is
+   returned on success, zero otherwise (i.e. no more virtual interrupt
+   channel is available). We need this service as part of the Adeos
+   bootstrap code, hence it must reside in a built-in area. */
+
+unsigned adeos_alloc_irq (void)
+
+{
+    unsigned long flags, irq = 0;
+    int ipos;
+
+    spin_lock_irqsave_hw(&__adeos_pipelock,flags);
+
+    if (__adeos_virtual_irq_map != ~0)
+	{
+	ipos = ffz(__adeos_virtual_irq_map);
+	set_bit(ipos,&__adeos_virtual_irq_map);
+	irq = ipos + IPIPE_VIRQ_BASE;
+	}
+
+    spin_unlock_irqrestore_hw(&__adeos_pipelock,flags);
+
+    return irq;
+}
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry *adeos_proc_entry;
+
+static int __adeos_read_proc (char *page,
+			      char **start,
+			      off_t off,
+			      int count,
+			      int *eof,
+			      void *data)
+{
+    unsigned long ctlbits;
+    struct list_head *pos;
+    unsigned irq, _irq;
+    char *p = page;
+    int len;
+
+#ifdef CONFIG_ADEOS_MODULE
+    p += sprintf(p,"Adeos %s -- Pipelining: %s",ADEOS_VERSION_STRING,adp_pipelined ? "active" : "stopped");
+#else /* !CONFIG_ADEOS_MODULE */
+    p += sprintf(p,"Adeos %s -- Pipelining: permanent",ADEOS_VERSION_STRING);
+#endif /* CONFIG_ADEOS_MODULE */
+#ifdef CONFIG_ADEOS_THREADS
+    p += sprintf(p, " (threaded)\n\n");
+#else				/* CONFIG_ADEOS_THREADS */
+    p += sprintf(p, "\n\n");
+#endif				/* CONFIG_ADEOS_THREADS */
+
+    spin_lock(&__adeos_pipelock);
+
+    list_for_each(pos,&__adeos_pipeline) {
+
+    	adomain_t *adp = list_entry(pos,adomain_t,p_link);
+
+	p += sprintf(p,"%8s: priority=%d, id=0x%.8x, ptdkeys=%d/%d\n",
+		     adp->name,
+		     adp->priority,
+		     adp->domid,
+		     adp->ptd_keycount,
+		     adp->ptd_keymax);
+	irq = 0;
+
+	while (irq < IPIPE_NR_IRQS)
+	    {
+	    ctlbits = (adp->irqs[irq].control & (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_STICKY_MASK));
+
+	    if (irq >= IPIPE_NR_XIRQS && !adeos_virtual_irq_p(irq))
+		{
+		/* There might be a hole between the last external IRQ
+		   and the first virtual one; skip it. */
+		irq++;
+		continue;
+		}
+
+	    if (adeos_virtual_irq_p(irq) && !test_bit(irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map))
+		{
+		/* Non-allocated virtual IRQ; skip it. */
+		irq++;
+		continue;
+		}
+
+	    /* Attempt to group consecutive IRQ numbers having the
+	       same virtualization settings in a single line. */
+
+	    _irq = irq;
+
+	    while (++_irq < IPIPE_NR_IRQS)
+		{
+		if (adeos_virtual_irq_p(_irq) != adeos_virtual_irq_p(irq) ||
+		    (adeos_virtual_irq_p(_irq) &&
+		     !test_bit(_irq - IPIPE_VIRQ_BASE,&__adeos_virtual_irq_map)) ||
+		    ctlbits != (adp->irqs[_irq].control & (IPIPE_HANDLE_MASK|IPIPE_PASS_MASK|IPIPE_STICKY_MASK)))
+		    break;
+		}
+
+	    if (_irq == irq + 1)
+		p += sprintf(p,"\tirq%u: ",irq);
+	    else
+		p += sprintf(p,"\tirq%u-%u: ",irq,_irq - 1);
+
+	    /* Statuses are as follows:
+	       o "accepted" means handled _and_ passed down the
+	       pipeline.
+	       o "grabbed" means handled, but the interrupt might be
+	       terminated _or_ passed down the pipeline depending on
+	       what the domain handler asks for to Adeos.
+	       o "passed" means unhandled by the domain but passed
+	       down the pipeline.
+	       o "discarded" means unhandled and _not_ passed down the
+	       pipeline. The interrupt merely disappears from the
+	       current domain down to the end of the pipeline. */
+
+	    if (ctlbits & IPIPE_HANDLE_MASK)
+		{
+		if (ctlbits & IPIPE_PASS_MASK)
+		    p += sprintf(p,"accepted");
+		else
+		    p += sprintf(p,"grabbed");
+		}
+	    else if (ctlbits & IPIPE_PASS_MASK)
+		p += sprintf(p,"passed");
+	    else
+		p += sprintf(p,"discarded");
+
+	    if (ctlbits & IPIPE_STICKY_MASK)
+		p += sprintf(p,", sticky");
+
+	    if (adeos_virtual_irq_p(irq))
+		p += sprintf(p,", virtual");
+
+	    p += sprintf(p,"\n");
+
+	    irq = _irq;
+	    }
+    }
+
+    spin_unlock(&__adeos_pipelock);
+
+    len = p - page;
+
+    if (len <= off + count)
+	*eof = 1;
+
+    *start = page + off;
+
+    len -= off;
+
+    if (len > count)
+	len = count;
+
+    if (len < 0)
+	len = 0;
+
+    return len;
+}
+
+void __adeos_init_proc (void) {
+
+    adeos_proc_entry = create_proc_read_entry("adeos",
+					      0444,
+					      NULL,
+					      &__adeos_read_proc,
+					      NULL);
+}
+
+#endif /* CONFIG_PROC_FS */
+
+void __adeos_dump_state (void)
+
+{
+    int _cpuid, nr_cpus = num_online_cpus();
+    struct list_head *pos;
+    unsigned long flags;
+    adeos_declare_cpuid;
+
+    adeos_lock_cpu(flags);
+
+    printk(KERN_WARNING "Adeos: Current domain=%s on CPU #%d [stackbase=%p]\n",
+	   adp_current->name,
+	   cpuid,
+#ifdef CONFIG_ADEOS_THREADS
+	   (void *)adp_current->estackbase[cpuid]
+#else /* !CONFIG_ADEOS_THREADS */
+	   current
+#endif /* CONFIG_ADEOS_THREADS */
+	   );
+
+    list_for_each(pos,&__adeos_pipeline) {
+
+        adomain_t *adp = list_entry(pos,adomain_t,p_link);
+
+        for (_cpuid = 0; _cpuid < nr_cpus; _cpuid++)
+            printk(KERN_WARNING "%8s[cpuid=%d]: priority=%d, status=0x%lx, pending_hi=0x%lx\n",
+                   adp->name,
+                   _cpuid,
+                   adp->priority,
+                   adp->cpudata[_cpuid].status,
+                   adp->cpudata[_cpuid].irq_pending_hi);
+    }
+
+    adeos_unlock_cpu(flags);
+}
+
+EXPORT_SYMBOL(adeos_suspend_domain);
+EXPORT_SYMBOL(adeos_alloc_irq);
+EXPORT_SYMBOL(adp_cpu_current);
+EXPORT_SYMBOL(adp_root);
+EXPORT_SYMBOL(adp_pipelined);
+EXPORT_SYMBOL(__adeos_handle_event);
+EXPORT_SYMBOL(__adeos_unstall_root);
+EXPORT_SYMBOL(__adeos_stall_root);
+EXPORT_SYMBOL(__adeos_restore_root);
+EXPORT_SYMBOL(__adeos_test_and_stall_root);
+EXPORT_SYMBOL(__adeos_test_root);
+EXPORT_SYMBOL(__adeos_dump_state);
+EXPORT_SYMBOL(__adeos_pipeline);
+EXPORT_SYMBOL(__adeos_pipelock);
+EXPORT_SYMBOL(__adeos_virtual_irq_map);
+EXPORT_SYMBOL(__adeos_event_monitors);
+EXPORT_SYMBOL(adeos_unstall_pipeline_from);
+#ifdef CONFIG_ADEOS_PROFILING
+EXPORT_SYMBOL(__adeos_profile_data);
+#endif /* CONFIG_ADEOS_PROFILING */
+/* The following are convenience exports which are needed by some
+   Adeos domains loaded as kernel modules. */
+EXPORT_SYMBOL(do_exit);
diff -uNrp linux-2.6.9/kernel/exit.c linux-2.6.9-ltt-r12/kernel/exit.c
--- linux-2.6.9/kernel/exit.c	2004-10-18 23:55:06.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/exit.c	2005-08-15 10:51:46.000000000 +0200
@@ -23,6 +23,7 @@
 #include <linux/profile.h>
 #include <linux/mount.h>
 #include <linux/proc_fs.h>
+#include <linux/ltt-events.h>
 #include <linux/mempolicy.h>
 
 #include <asm/uaccess.h>
@@ -808,8 +809,13 @@ asmlinkage NORET_TYPE void do_exit(long 
 	}
 
 	acct_process(code);
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_exit_process(tsk);
+#endif /* CONFIG_ADEOS_CORE */
 	__exit_mm(tsk);
 
+	ltt_ev_process_exit(0, 0);
+
 	exit_sem(tsk);
 	__exit_files(tsk);
 	__exit_fs(tsk);
@@ -1235,6 +1241,8 @@ static long do_wait(pid_t pid, int optio
 	struct task_struct *tsk;
 	int flag, retval;
 
+	ltt_ev_process(LTT_EV_PROCESS_WAIT, pid, 0);
+
 	add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
 	flag = 0;
diff -uNrp linux-2.6.9/kernel/fork.c linux-2.6.9-ltt-r12/kernel/fork.c
--- linux-2.6.9/kernel/fork.c	2004-10-18 23:53:13.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/fork.c	2005-08-15 10:51:46.000000000 +0200
@@ -38,6 +38,7 @@
 #include <linux/audit.h>
 #include <linux/profile.h>
 #include <linux/rmap.h>
+#include <linux/ltt-events.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -1136,6 +1137,14 @@ static task_t *copy_process(unsigned lon
 
 	nr_threads++;
 	write_unlock_irq(&tasklist_lock);
+#ifdef CONFIG_ADEOS_CORE
+	{
+	int k;
+
+	for (k = 0; k < ADEOS_ROOT_NPTDKEYS; k++)
+	    p->ptd[k] = NULL;
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	retval = 0;
 
 fork_out:
@@ -1272,6 +1281,8 @@ long do_fork(unsigned long clone_flags,
 			ptrace_notify ((trace << 8) | SIGTRAP);
 		}
 
+		ltt_ev_process(LTT_EV_PROCESS_FORK, p->pid, 0);
+
 		if (clone_flags & CLONE_VFORK) {
 			wait_for_completion(&vfork);
 			if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
diff -uNrp linux-2.6.9/kernel/itimer.c linux-2.6.9-ltt-r12/kernel/itimer.c
--- linux-2.6.9/kernel/itimer.c	2004-10-18 23:53:51.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/itimer.c	2005-08-15 10:51:46.000000000 +0200
@@ -10,6 +10,7 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
+#include <linux/ltt-events.h>
 
 #include <asm/uaccess.h>
 
@@ -68,6 +69,8 @@ void it_real_fn(unsigned long __data)
 	struct task_struct * p = (struct task_struct *) __data;
 	unsigned long interval;
 
+	ltt_ev_timer(LTT_EV_TIMER_EXPIRED, 0, 0, 0);
+
 	send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
 	interval = p->it_real_incr;
 	if (interval) {
@@ -87,6 +90,7 @@ int do_setitimer(int which, struct itime
 	j = timeval_to_jiffies(&value->it_value);
 	if (ovalue && (k = do_getitimer(which, ovalue)) < 0)
 		return k;
+	ltt_ev_timer(LTT_EV_TIMER_SETITIMER, which, i, j);
 	switch (which) {
 		case ITIMER_REAL:
 			del_timer_sync(&current->real_timer);
diff -uNrp linux-2.6.9/kernel/ltt-core.c linux-2.6.9-ltt-r12/kernel/ltt-core.c
--- linux-2.6.9/kernel/ltt-core.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.9-ltt-r12/kernel/ltt-core.c	2005-08-15 10:51:46.000000000 +0200
@@ -0,0 +1,2589 @@
+/*
+ * ltt-core.c
+ *
+ * (C) Copyright, 1999, 2000, 2001, 2002, 2003, 2004 -
+ *              Karim Yaghmour (karim@opersys.com)
+ *
+ * Contains the kernel code for the Linux Trace Toolkit.
+ *
+ * Author:
+ *	Karim Yaghmour (karim@opersys.com)
+ *
+ * Changelog:
+ *	14/12/04, Renamed trace macros and variables to avoid namespace
+ *		pollution (i.e. TRACE_XXX is now ltt_ev_xxx, etc.)
+ *	24/01/04, Revamped tracer to rely entirely on relayfs, no sys_trace.
+ *		Renamed all relevant files and functions from trace* to ltt*.
+ *	14/03/03, Modified to use relayfs (zanussi@us.ibm.com)
+ *	15/10/02, Changed tracer from device to kernel subsystem and added
+ *		custom trace system call (sys_trace).
+ *	01/10/02, Coding style change to fit with kernel coding style.
+ *	16/02/02, Added Tom Zanussi's implementation of K42's lockless logging.
+ *		K42 tracing guru Robert Wisniewski participated in the
+ *		discussions surrounding this implementation. A big thanks to
+ *		the IBM folks.
+ *	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, Changing 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/init.h>
+#include <linux/ltt-core.h>
+#include <linux/ltt-events.h>
+#include <linux/errno.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/relay.h>
+#include <asm/ltt.h>
+
+/* Tracer configuration */
+static int		num_cpus;
+
+/* System call tracing behavior */
+unsigned int		syscall_entry_trace_active = 0;
+unsigned int		syscall_exit_trace_active = 0;
+static int		use_syscall_eip_bounds;
+static int		lower_eip_bound_set;
+static int		upper_eip_bound_set;
+static void*		lower_eip_bound;
+static void*		upper_eip_bound;
+static int		fetch_syscall_eip_use_depth;
+static int		fetch_syscall_eip_use_bounds;
+static void*		syscall_lower_eip_bound;
+static void*		syscall_upper_eip_bound;
+static int		syscall_eip_depth;
+static int		syscall_eip_depth_set;
+
+/* Data buffer management */
+static struct ltt_trace_struct	current_traces[NR_TRACES];
+static u32			start_reserve = LTT_TRACER_FIRST_EVENT_SIZE;
+static u32			end_reserve = LTT_TRACER_LAST_EVENT_SIZE;
+static u32			trace_start_reserve = LTT_TRACER_START_TRACE_EVENT_SIZE;
+static struct ltt_arch_info	ltt_arch_info;
+static struct ltt_buf_control_info	shared_buf_ctl;
+static char *			user_event_data = NULL;
+
+/* Relayfs interaction */
+static struct rchan_callbacks	ltt_callbacks;			/* relayfs callbacks */
+static char			relay_file_name[PATH_MAX];	/* scratch area */
+
+/* Timer management */
+static struct timer_list	heartbeat_timer;
+static struct timer_list	percpu_timer[NR_CPUS] __cacheline_aligned;
+
+/* /proc variables */
+static struct proc_dir_entry *	ltt_proc_root_entry; /* proc/ltt */
+static int			tmp_rchan_handles[NR_CPUS];
+static char			relayfs_path[PATH_MAX];	/* path to attribs */
+static int			control_channel; /* LTT control channel */
+
+/* Forward declarations */
+static struct proc_dir_entry *create_handle_proc_dir(unsigned trace_handle);
+static void remove_handle_proc_dir(struct proc_dir_entry *handle_dir,
+				   unsigned trace_handle);
+
+/* Size of statically defined events */
+int event_struct_size[LTT_EV_MAX + 1] =
+{
+	sizeof(ltt_trace_start),
+	sizeof(ltt_syscall_entry),
+	0,				/* LTT_SYSCALL_EXIT */
+	sizeof(ltt_trap_entry),
+	0,				/* LTT_TRAP_EXIT */
+	sizeof(ltt_irq_entry),
+	0,				/* LTT_IRQ_EXIT */
+	sizeof(ltt_schedchange),
+	0,				/* LTT_KERNEL_TIMER */
+	sizeof(ltt_soft_irq),
+	sizeof(ltt_process),
+	sizeof(ltt_file_system),
+	sizeof(ltt_timer),
+	sizeof(ltt_memory),
+	sizeof(ltt_socket),
+	sizeof(ltt_ipc),
+	sizeof(ltt_network),
+	sizeof(ltt_buffer_start),
+	sizeof(ltt_buffer_end),
+	sizeof(ltt_new_event),
+	sizeof(ltt_custom),
+	sizeof(ltt_change_mask),
+	0				/* LTT_HEARTBEAT */
+};
+
+/* Custom event description */
+struct custom_event_desc {
+	ltt_new_event event;
+
+	pid_t owner_pid;
+
+	struct custom_event_desc *next;
+	struct custom_event_desc *prev;
+};
+
+/* Custom event management */
+static int			next_event_id = LTT_EV_MAX + 1;
+static rwlock_t			custom_list_lock = RW_LOCK_UNLOCKED;
+static rwlock_t			trace_handle_table_lock = RW_LOCK_UNLOCKED;
+static struct custom_event_desc	custom_events_head;
+static struct custom_event_desc	*custom_events = NULL;
+
+/* Handle management */
+struct trace_handle_struct{
+	struct task_struct	*owner;
+};
+static struct trace_handle_struct trace_handle_table[LTT_MAX_HANDLES];
+
+/*
+ * Helper functions
+ */
+
+/**
+ *	set_waiting_for_cpu_async: - Utility function for setting wait flags
+ *	@cpu_id: which CPU to set flag on
+ *	@bit: which bit to set
+ */
+static inline void set_waiting_for_cpu_async(unsigned int trace_handle, u8 cpu_id, int bit)
+{
+	atomic_set(&waiting_for_cpu_async(trace_handle, cpu_id), 
+		   atomic_read(&waiting_for_cpu_async(trace_handle, cpu_id)) | bit);
+}
+
+/**
+ *	clear_waiting_for_cpu_async: - Utility function for clearing wait flags
+ *	@cpu_id: which CPU to clear flag on
+ *	@bit: which bit to clear
+ */
+static inline void clear_waiting_for_cpu_async(unsigned int trace_handle, u8 cpu_id, int bit)
+{
+	atomic_set(&waiting_for_cpu_async(trace_handle, cpu_id), 
+		   atomic_read(&waiting_for_cpu_async(trace_handle, cpu_id)) & ~bit);
+}
+
+/*
+ * Trace heartbeat
+ */
+
+/**
+ *	write_heartbeat_event: - Timer function generating hearbeat event.
+ *	@data: unused
+ *
+ *	Guarantees at least 1 event is logged before low word of TSC wraps.
+ */
+static void write_heartbeat_event(unsigned long data)
+{
+	unsigned long int flags;
+	int i, j;
+	
+	local_irq_save(flags);
+	for (i = 0; i < NR_TRACES; i++) {
+		if (current_traces[i].active && current_traces[i].using_tsc) {
+			for (j =  0; j < num_cpus; j++)
+				set_waiting_for_cpu_async(i, j, LTT_TRACE_HEARTBEAT);
+		}
+	}
+	local_irq_restore(flags);
+
+	del_timer(&heartbeat_timer);
+	heartbeat_timer.expires = jiffies + 0xffffffffUL/loops_per_jiffy - 1;
+	add_timer(&heartbeat_timer);
+}
+
+/**
+ *	need_heartbeat: - If any active trace uses TSC timestamping, return 1
+ *
+ *	Returns the number of active traces using TSC timestamping
+ *
+ *	Needed for starting/stopping the heartbeat timer depending on whether
+ *	any trace needs it or not.
+ */
+int need_heartbeat(void)
+{
+	int i, retval = 0;
+	struct ltt_trace_struct *trace;
+	
+	for (i = 0; i < NR_TRACES; i++) {
+		trace = &current_traces[i];
+		if(trace->active && trace->using_tsc)
+			retval++;
+	}
+
+	return retval;
+}
+
+/**
+ *	init_heartbeat_timer: - Start timer generating hearbeat events.
+ */
+static void init_heartbeat_timer(void)
+{
+	if (loops_per_jiffy > 0) {
+		init_timer(&heartbeat_timer);
+		heartbeat_timer.function = write_heartbeat_event;
+		heartbeat_timer.expires = jiffies 
+			+ 0xffffffffUL/loops_per_jiffy - 1;
+		add_timer(&heartbeat_timer);
+	}
+	else
+		printk(KERN_ALERT "LTT: No TSC for heartbeat timer - continuing without one \n");
+}
+
+/**
+ *	delete_heartbeat_timer: - Stop timer generating hearbeat events.
+ */
+static void delete_heartbeat_timer(void)
+{
+	if (loops_per_jiffy > 0)
+		del_timer(&heartbeat_timer);
+}
+
+/*
+ * Tasks and timers for trace finalization
+ */
+
+/**
+ *	all_channels_finalized: - Verify that all channels have been finalized.
+ *	@trace_handle: the trace containing the channels to be tested
+ *
+ *	Returns 1 if channels on all CPUs are complete, 0 otherwise.
+ */
+static int all_channels_finalized(unsigned int trace_handle)
+{
+	int i;
+	
+	for (i = 0; i < num_cpus; i++)
+		if (atomic_read(&waiting_for_cpu_async(trace_handle, i)) & LTT_FINALIZE_TRACE)
+			return 0;
+
+	return 1;
+}
+
+/**
+ *	active_traces: - The number of currently active traces
+ *
+ *	Returns the number of active traces
+ */
+static inline int active_traces(void)
+{
+	int i, nr_active = 0;
+
+	for (i = 0; i < NR_TRACES; i++)
+		if (current_traces[i].active)
+			nr_active++;
+
+	return nr_active;
+}
+
+/**
+ *	del_percpu_timers: - Delete all per_cpu timers.
+ */
+static inline void del_percpu_timers(void)
+{
+	int i;
+
+	for (i =  0; i < num_cpus; i++)
+		del_timer_sync(&percpu_timer[i]);
+}
+
+/**
+ *	remove_readers_async: - Remove all map readers asynchronously.
+ *	@private: the trace_handle containing the readers to be removed
+ */
+static void remove_readers_async(void *private)
+{
+	int i;
+	unsigned int trace_handle = (unsigned int)private;
+
+	for (i = 0; i < num_cpus; i++) {
+		remove_map_reader(trace_channel_reader(trace_handle, i));
+		trace_channel_reader(trace_handle, i) = NULL;
+	}
+}
+
+/**
+ *	remove_readers: - Remove all map readers.
+ *	@trace_handle: the trace containing the readers to be removed
+ */
+static inline void remove_readers(unsigned int trace_handle)
+{
+	int i;
+	
+	for (i = 0; i < num_cpus; i++) {
+		remove_map_reader(trace_channel_reader(trace_handle, i));
+		trace_channel_reader(trace_handle, i) = NULL;
+	}
+}
+
+/**
+ *	do_waiting_async_tasks: - perform asynchronous per-CPU tasks.
+ *	@trace_handle: the trace handle
+ *	@cpu_id: the CPU the tasks should be executed on
+ */
+static void do_waiting_async_tasks(unsigned int trace_handle, u8 cpu_id)
+{
+	unsigned long int flags;
+	int tasks;
+	struct ltt_trace_struct *trace;
+	
+	trace = &current_traces[trace_handle];
+
+	local_irq_save(flags);
+	tasks = atomic_read(&waiting_for_cpu_async(trace_handle, cpu_id));
+
+	if (tasks == 0) {
+		local_irq_restore(flags);
+		return;
+	}
+
+	if (trace->using_tsc && trace->tracer_started && (tasks & LTT_TRACE_HEARTBEAT)) {
+                clear_waiting_for_cpu_async(trace_handle, cpu_id, LTT_TRACE_HEARTBEAT);
+		ltt_ev_heartbeat();
+	}
+
+	if (trace->tracer_stopping && (tasks & LTT_FINALIZE_TRACE)) {
+                clear_waiting_for_cpu_async(trace_handle, cpu_id, LTT_FINALIZE_TRACE);
+		if (relay_close(trace_channel_handle(trace_handle, cpu_id)) != 0)
+			printk(KERN_ALERT "LTT: Couldn't close trace channel %d\n", trace_channel_handle(trace_handle, cpu_id));
+
+		set_bit(cpu_id, &trace->buffer_switches_pending);
+
+		if (all_channels_finalized(trace_handle)) {
+			PREPARE_WORK(&trace->work, remove_readers_async, (void *)trace_handle);
+			schedule_work(&trace->work);
+
+			trace->tracer_stopping = 0;
+		}
+	}
+
+	local_irq_restore(flags);
+}
+
+/**
+ *	check_waiting_async_tasks: - Timer function checking for async tasks.
+ *	@data: unused
+ */
+static void check_waiting_async_tasks(unsigned long data)
+{
+	int i;
+	int cpu = smp_processor_id();
+
+	for (i = 0; i < NR_TRACES; i++) {
+		if (atomic_read(&waiting_for_cpu_async(i, cpu)) != 0)
+			do_waiting_async_tasks(i, cpu);
+	}
+
+	del_timer(&percpu_timer[cpu]);
+	percpu_timer[cpu].expires = jiffies + LTT_PERCPU_TIMER_FREQ;
+	add_timer(&percpu_timer[cpu]);
+}
+
+/**
+ *	_init_percpu_timer: - Start timer checking for async tasks.
+ */
+void _init_percpu_timer(void * dummy)
+{
+	int cpu = smp_processor_id();
+
+	init_timer(&percpu_timer[cpu]);
+	percpu_timer[cpu].function = check_waiting_async_tasks;
+	percpu_timer[cpu].expires = jiffies + LTT_PERCPU_TIMER_FREQ;
+	add_timer(&percpu_timer[cpu]);
+}
+
+static inline void init_percpu_timers(void)
+{
+	_init_percpu_timer(NULL);
+
+	if (smp_call_function(_init_percpu_timer, NULL, 1, 1) != 0)
+		printk(KERN_ALERT "LTT: Couldn't initialize all per-CPU timers\n");
+}
+
+/*
+ * User-kernel interface for tracer
+ */
+
+/**
+ *	update_shared_buffer_control: - prepare for GET_BUFFER_CONTROL ioctl
+ *	@trace: the trace instance
+ *	@cpu_id: the CPU associated with the ioctl
+ */
+static inline void update_shared_buffer_control(struct ltt_trace_struct *trace, u8 cpu_id)
+{
+	struct rchan_info channel_info;
+	int i;
+	int channel_handle = trace_channel_handle(trace->trace_handle, cpu_id);
+	
+	if (relay_info(channel_handle, &channel_info) == -1) {
+		shared_buf_ctl.buffer_control_valid = 0;
+		return;
+	}
+
+	shared_buf_ctl.cpu_id =				cpu_id;
+	shared_buf_ctl.buffer_switches_pending =	trace->buffer_switches_pending & ~(1UL << cpu_id);
+	shared_buf_ctl.buffer_control_valid =		1;
+	shared_buf_ctl.buf_size =			channel_info.buf_size;
+	shared_buf_ctl.n_buffers =			channel_info.n_bufs;
+	shared_buf_ctl.cur_idx =			channel_info.cur_idx;
+	shared_buf_ctl.buffers_produced =		channel_info.bufs_produced;
+	shared_buf_ctl.buffers_consumed =		channel_info.bufs_consumed;
+
+	if (channel_info.flags & RELAY_SCHEME_LOCKLESS) {
+		for (i = 0; i < channel_info.n_bufs; i++) {
+			shared_buf_ctl.buffer_complete[i] = 
+				channel_info.buffer_complete[i];
+		}
+	}
+}
+
+/**
+ *	ltt_flight_pause: - pause the flight recorder
+ *
+ *	Allows for external control of flight recorder e.g. for crashdump
+ */
+void ltt_flight_pause(void)
+{
+	struct ltt_trace_struct *trace;
+
+	trace = &current_traces[FLIGHT_HANDLE];
+	if (!trace->active)
+		return;
+	
+	trace->paused = 1;
+}
+
+/**
+ *	ltt_flight_unpause: - unpause the flight recorder
+ *
+ *	Allows for external control of flight recorder e.g. for crashdump
+ */
+void ltt_flight_unpause(void)
+{
+	struct ltt_trace_struct *trace;
+
+	trace = &current_traces[FLIGHT_HANDLE];
+	if (!trace->active)
+		return;
+	
+	trace->paused = 0;
+}
+
+/**
+ *      ltt_ioctl: - Tracing kernel-user control interface
+ *      @rchan_id: rchan id ioctl occurred on
+ *      @tracer_command: command given by the caller
+ *      @command_arg: argument 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
+ *      -EACCES, invalid tracer handle
+ */
+static int ltt_ioctl(int rchan_id,
+		     unsigned int tracer_command,
+		     unsigned long arg)
+{
+	int retval;
+	int new_user_event_id;
+	unsigned long int flags;
+	u8 cpu_id;
+	u8 i;
+	u32 buffers_consumed;
+	ltt_custom user_event;
+	ltt_change_mask trace_mask;
+	ltt_new_event new_user_event;
+	struct ltt_buffers_committed buffers_committed;
+	struct ltt_trace_struct *trace = NULL;
+	struct ltt_tracer_status tracer_status;
+	unsigned int tracer_handle;
+	unsigned long command_arg;
+
+	if (copy_from_user(&tracer_handle, (void *)arg, sizeof(unsigned int)))
+		return -EFAULT;
+
+	if (copy_from_user(&command_arg, (void*)(arg + sizeof(tracer_handle)), sizeof(unsigned long)))
+		return -EFAULT;
+
+	if (tracer_command == LTT_TRACER_ALLOC_HANDLE)
+		return ltt_alloc_trace_handle(tracer_handle);
+
+	if (!ltt_valid_trace_handle(tracer_handle))
+		return -EACCES;
+
+	if (tracer_handle < NR_TRACES)
+		trace = &current_traces[tracer_handle];
+	else if (tracer_handle >= NR_TRACES) {
+		if (current_traces[TRACE_HANDLE].active)
+			trace = &current_traces[TRACE_HANDLE];
+		if (trace == NULL && tracer_command != LTT_TRACER_GET_STATUS)
+			return -EACCES;
+	}
+
+	if ((tracer_handle < NR_TRACES)
+	    && (trace->tracer_started == 1)
+	    && (tracer_command != LTT_TRACER_STOP)
+	    && (tracer_command != LTT_TRACER_PAUSE)
+	    && (tracer_command != LTT_TRACER_UNPAUSE)
+	    && (tracer_command != LTT_TRACER_DATA_COMITTED)
+	    && (tracer_command != LTT_TRACER_GET_ARCH_INFO)
+	    && (tracer_command != LTT_TRACER_GET_BUFFER_CONTROL)
+	    && (tracer_command != LTT_TRACER_GET_START_INFO))
+		return -EBUSY;
+
+	if ((tracer_handle >= NR_TRACES)
+	    && (tracer_command != LTT_TRACER_CREATE_USER_EVENT)
+	    && (tracer_command != LTT_TRACER_DESTROY_USER_EVENT)
+	    && (tracer_command != LTT_TRACER_TRACE_USER_EVENT)
+	    && (tracer_command != LTT_TRACER_FREE_HANDLE)
+	    && (tracer_command != LTT_TRACER_GET_STATUS)
+	    && (tracer_command != LTT_TRACER_SET_EVENT_MASK)
+	    && (tracer_command != LTT_TRACER_GET_EVENT_MASK))
+		return -ENOSYS;
+
+	switch (tracer_command) {
+	case LTT_TRACER_START:
+		if (trace->using_tsc && (need_heartbeat() == 1))
+			init_heartbeat_timer();
+		if (active_traces() == 1)
+			init_percpu_timers();
+
+		if (((use_syscall_eip_bounds == 1)
+		     && (syscall_eip_depth_set == 1))
+		    || ((use_syscall_eip_bounds == 1)
+			&& ((lower_eip_bound_set != 1)
+			    || (upper_eip_bound_set != 1)))
+		    || ((trace->tracing_pid == 1)
+			&& (trace->tracing_pgrp == 1)))
+			return -EINVAL;
+
+		if (ltt_set_trace_config(syscall_eip_depth_set,
+					 use_syscall_eip_bounds,
+					 syscall_eip_depth,
+					 lower_eip_bound,
+					 upper_eip_bound) < 0)
+			return -EINVAL;
+
+		if (trace->flight_recorder)
+			ltt_set_flight_recorder_config(trace);
+		
+		ltt_set_bit(LTT_EV_BUFFER_START, &trace->traced_events);
+		ltt_set_bit(LTT_EV_BUFFER_START, &trace->log_event_details_mask);
+		ltt_set_bit(LTT_EV_START, &trace->traced_events);
+		ltt_set_bit(LTT_EV_START, &trace->log_event_details_mask);
+		ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->traced_events);
+		ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->log_event_details_mask);
+
+		syscall_entry_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_ENTRY);
+		syscall_exit_trace_active  = ltt_syscall_active(LTT_EV_SYSCALL_EXIT);
+
+		trace->tracer_stopping = 0;
+		trace->tracer_started = 1;
+
+		ltt_reregister_custom_events();
+		break;
+
+	case LTT_TRACER_STOP:
+		if (trace->flight_recorder) {
+			for (i = 0; i < num_cpus; i++)
+				tmp_rchan_handles[i] = trace_channel_handle(tracer_handle, i);
+			ltt_free_all_handles(NULL);
+		} else {
+			trace->tracer_stopping = 1;
+			trace->tracer_started = 0;
+		}
+
+		syscall_entry_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_ENTRY);
+		syscall_exit_trace_active  = ltt_syscall_active(LTT_EV_SYSCALL_EXIT);
+
+		if (trace->flight_recorder) {
+			for (i = 0; i < num_cpus; i++) {
+				if (relay_close(tmp_rchan_handles[i]) != 0)
+					printk(KERN_ALERT "LTT: Couldn't close trace channel %d\n", trace_channel_handle(tracer_handle, i));
+			}
+			remove_readers(tracer_handle);
+		} else {
+			for (i = 0; i < num_cpus; i++)
+				set_waiting_for_cpu_async(tracer_handle, i, LTT_FINALIZE_TRACE);
+		}
+		break;
+
+	case LTT_TRACER_PAUSE:
+		trace->paused = 1;
+		break;
+
+	case LTT_TRACER_UNPAUSE:
+		trace->paused = 0;
+		break;
+
+	case LTT_TRACER_CONFIG_DEFAULT:
+		ltt_set_default_config(trace);
+		break;
+
+	case LTT_TRACER_CONFIG_MEMORY_BUFFERS:
+		if (trace->use_locking == 1) {
+			if (command_arg < LTT_TRACER_MIN_BUF_SIZE)
+				return -EINVAL;
+		}
+		else {
+			if ((command_arg < LTT_TRACER_LOCKLESS_MIN_BUF_SIZE) || 
+			    (command_arg > LTT_TRACER_LOCKLESS_MAX_BUF_SIZE))
+				return -EINVAL;
+		}
+
+		return ltt_set_buffer_size(trace, command_arg, relayfs_path);
+		break;
+
+	case LTT_TRACER_CONFIG_N_MEMORY_BUFFERS:
+		if (command_arg < LTT_TRACER_MIN_BUFFERS || 
+		    command_arg > LTT_TRACER_MAX_BUFFERS)
+			return -EINVAL;
+
+		return ltt_set_n_buffers(trace, command_arg);
+		break;
+
+	case LTT_TRACER_CONFIG_USE_LOCKING:
+		trace->use_locking = command_arg;
+
+		if ((trace->use_locking == 0) && (have_cmpxchg() == 0))
+			return -EINVAL;
+		break;
+
+	case LTT_TRACER_CONFIG_EVENTS:
+		if (copy_from_user(&trace->traced_events, (void *) command_arg, sizeof(trace->traced_events)))
+			return -EFAULT;
+		break;
+
+	case LTT_TRACER_CONFIG_TIMESTAMP:
+		trace->using_tsc = command_arg;
+
+		if ((trace->using_tsc == 1) && (have_tsc() == 0)) {
+			trace->using_tsc = 0;
+			return -EINVAL;
+		}
+
+		break;
+
+	case LTT_TRACER_CONFIG_DETAILS:
+		if (copy_from_user(&trace->log_event_details_mask, (void *) command_arg, sizeof(trace->log_event_details_mask)))
+			return -EFAULT;
+		break;
+
+	case LTT_TRACER_CONFIG_CPUID:
+		trace->log_cpuid = 0; /* disabled*/
+		break;
+
+	case LTT_TRACER_CONFIG_PID:
+		trace->tracing_pid = 1;
+		trace->traced_pid = command_arg;
+		break;
+
+	case LTT_TRACER_CONFIG_PGRP:
+		trace->tracing_pgrp = 1;
+		trace->traced_pgrp = command_arg;
+		break;
+
+	case LTT_TRACER_CONFIG_GID:
+		trace->tracing_gid = 1;
+		trace->traced_gid = command_arg;
+		break;
+
+	case LTT_TRACER_CONFIG_UID:
+		trace->tracing_uid = 1;
+		trace->traced_uid = command_arg;
+		break;
+
+	case LTT_TRACER_CONFIG_SYSCALL_EIP_DEPTH:
+		syscall_eip_depth_set = 1;
+		syscall_eip_depth = command_arg;
+		break;
+
+	case LTT_TRACER_CONFIG_SYSCALL_EIP_LOWER:
+		use_syscall_eip_bounds = 1;
+		lower_eip_bound = (void *) command_arg;
+		lower_eip_bound_set = 1;
+		break;
+
+	case LTT_TRACER_CONFIG_SYSCALL_EIP_UPPER:
+		use_syscall_eip_bounds = 1;
+		upper_eip_bound = (void *) command_arg;
+		upper_eip_bound_set = 1;
+		break;
+
+	case LTT_TRACER_DATA_COMITTED:
+		if (copy_from_user(&buffers_committed, (void *)command_arg, 
+				   sizeof(buffers_committed)))
+			return -EFAULT;
+
+		cpu_id = buffers_committed.cpu_id;
+		buffers_consumed = buffers_committed.buffers_consumed;
+		clear_bit(cpu_id, &trace->buffer_switches_pending);
+
+		local_irq_save(flags);
+		relay_buffers_consumed(trace_channel_reader(tracer_handle, cpu_id), 
+				       buffers_consumed);
+		local_irq_restore(flags);
+
+		break;
+
+	case LTT_TRACER_GET_EVENTS_LOST:
+		return events_lost(tracer_handle, command_arg);
+		break;
+
+	case LTT_TRACER_CREATE_USER_EVENT:
+		if (copy_from_user(&new_user_event, (void *) command_arg, sizeof(new_user_event)))
+			return -EFAULT;
+
+		new_user_event_id = ltt_create_owned_event(new_user_event.type,
+							     new_user_event.desc,
+							     new_user_event.format_type,
+							     new_user_event.form,
+							     current->pid);
+		if (new_user_event_id >= 0) {
+			new_user_event.id = new_user_event_id;
+			if (copy_to_user((void *) command_arg, &new_user_event, sizeof(new_user_event))) {
+				ltt_destroy_event(new_user_event_id);
+				return -EFAULT;
+			}
+		}
+		else
+			return new_user_event_id;
+		break;
+
+	case LTT_TRACER_DESTROY_USER_EVENT:
+		ltt_destroy_event((int) command_arg);
+		break;
+
+	case LTT_TRACER_TRACE_USER_EVENT:
+		if (copy_from_user(&user_event, (void *) command_arg, sizeof(user_event)))
+			return -EFAULT;
+
+		if ((user_event_data == NULL) 
+		    && (user_event_data = vmalloc(LTT_CUSTOM_EV_MAX_SIZE)) < 0)
+			return -ENOMEM;
+
+		if (copy_from_user(user_event_data, user_event.data, user_event.data_size))
+			return -EFAULT;
+
+		retval = ltt_log_raw_event(user_event.id,
+					   user_event.data_size,
+					   user_event_data);
+
+		if (retval < 0)
+			return retval;
+		break;
+
+	case LTT_TRACER_SET_EVENT_MASK:
+		if (copy_from_user(&(trace_mask.mask), (void *) command_arg, sizeof(trace_mask.mask)))
+			return -EFAULT;
+
+		retval = _ltt_log_event(trace,
+					LTT_EV_CHANGE_MASK,
+					&trace_mask,
+					smp_processor_id());
+
+		memcpy(&trace->traced_events, &(trace_mask.mask), sizeof(trace_mask.mask));
+
+		syscall_entry_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_ENTRY);
+		syscall_exit_trace_active  = ltt_syscall_active(LTT_EV_SYSCALL_EXIT);
+
+		ltt_set_bit(LTT_EV_BUFFER_START, &trace->traced_events);
+		ltt_set_bit(LTT_EV_START, &trace->traced_events);
+		ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->traced_events);
+
+		return retval;
+		break;
+
+	case LTT_TRACER_GET_EVENT_MASK:
+		if (copy_to_user((void *) command_arg, &trace->traced_events, sizeof(trace->traced_events)))
+			return -EFAULT;
+		break;
+
+	case LTT_TRACER_GET_ARCH_INFO:
+		ltt_arch_info.n_cpus = num_cpus;
+		ltt_arch_info.page_shift = PAGE_SHIFT;
+
+		if (copy_to_user((void *) command_arg, 
+				&ltt_arch_info, 
+				sizeof(ltt_arch_info)))
+			return -EFAULT;
+		break;
+
+	case LTT_TRACER_GET_START_INFO:
+		if (trace->trace_start_data) {
+			if (copy_to_user((void *)command_arg,
+					 trace->trace_start_data,
+					 sizeof(ltt_trace_start)))
+				return -EFAULT;
+		} else
+			return -EINVAL;
+		break;
+
+	case LTT_TRACER_GET_STATUS:
+		if (ltt_get_status(&tracer_status))
+			return -EINVAL;
+		
+		if (copy_to_user((void *)command_arg, 
+				 &tracer_status,
+				 sizeof(struct ltt_tracer_status)))
+			return -EFAULT;
+		break;
+
+	case LTT_TRACER_GET_BUFFER_CONTROL:
+		if (copy_from_user(&shared_buf_ctl, (void *)command_arg, sizeof(shared_buf_ctl)))
+			return -EFAULT;
+
+		if (shared_buf_ctl.cpu_id == -1) {
+			for (i = 0; i < num_cpus; i++) {
+				if (trace->buffer_switches_pending & (1UL << i)) {
+					update_shared_buffer_control(trace, i);
+					if (copy_to_user((void *)command_arg,
+							 &shared_buf_ctl,
+							 sizeof(struct ltt_buf_control_info)))
+						return -EFAULT;
+					return 0;
+				}
+			}
+		}
+		else {
+			update_shared_buffer_control(trace, (u8)shared_buf_ctl.cpu_id);
+			if (copy_to_user((void *)command_arg,
+					 &shared_buf_ctl,
+					 sizeof(struct ltt_buf_control_info)))
+				return -EFAULT;
+			return 0;
+		}
+
+		shared_buf_ctl.cpu_id = 0;
+		shared_buf_ctl.buffer_control_valid = 0;
+
+		if (copy_to_user((void *) command_arg,
+				&shared_buf_ctl,
+				sizeof(struct ltt_buf_control_info)))
+			return -EFAULT;
+		break;
+
+	case LTT_TRACER_FREE_HANDLE:
+		return ltt_free_trace_handle(tracer_handle);
+		break;
+
+	case LTT_TRACER_FREE_DAEMON_HANDLE:
+		return ltt_free_daemon_handle(trace);
+		break;
+
+	case LTT_TRACER_FREE_ALL_HANDLES:
+		ltt_free_all_handles(current);
+		break;
+
+	case LTT_TRACER_MAP_BUFFER:
+		return -EFAULT;
+		break;
+
+	default:
+		return -ENOSYS;
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Trace Handles
+ */
+
+/**
+ *	ltt_valid_trace_handle: - Validate tracer handle.
+ *	@tracer_handle: handle to be validated
+ *
+ *	Returns:
+ *	1, if handle is valid
+ *	0, if handle is invalid
+ */
+int ltt_valid_trace_handle(unsigned int tracer_handle)
+{
+	int retval = 0;
+	struct ltt_trace_struct *trace;
+
+	if (tracer_handle < NR_TRACES) {
+		trace = &current_traces[tracer_handle];
+		if (!trace->active)
+			retval = 0;
+		else if (!trace->flight_recorder) {
+			if (trace->daemon_task_struct == current)
+				retval = 1;
+		} else
+			retval = 1;
+	} else {
+		read_lock(&trace_handle_table_lock);
+		if (trace_handle_table[tracer_handle - NR_TRACES].owner == current)
+			retval = 1;
+		else
+			retval = 0;
+		read_unlock(&trace_handle_table_lock);
+	}
+
+	return retval;
+}
+
+/**
+ *	ltt_alloc_trace_handle: - Allocate trace handle to caller.
+ *	@tracer_handle: handle requested by process
+ *
+ *	Returns:
+ *	Handle ID, everything went OK
+ *	-ENODEV, no more free handles.
+ *	-EBUSY, daemon handle already in use.
+ */
+int ltt_alloc_trace_handle(unsigned int tracer_handle)
+{
+	int i;
+	int retval;
+	struct ltt_trace_struct *trace = NULL;
+	
+	if (tracer_handle < NR_TRACES) {
+		trace = &current_traces[tracer_handle];
+		if (trace == NULL)
+			return -ENODEV;
+		if (trace->active)
+			return -EBUSY;
+	}
+
+	if (tracer_handle >= NR_TRACES) {
+		write_lock(&trace_handle_table_lock);
+		for (i = 0; i < LTT_MAX_HANDLES; i++)
+			if (trace_handle_table[i].owner == NULL) {
+				trace_handle_table[i].owner = current;
+				break;
+			}
+		write_unlock(&trace_handle_table_lock);
+		if (i == LTT_MAX_HANDLES)
+			retval = -ENODEV;
+		else
+			retval = (i + NR_TRACES);
+	}
+	else {
+		trace->active = trace;
+		trace->tracer_started = 0;
+		trace->tracer_stopping = 0;
+		if (tracer_handle == TRACE_HANDLE) {
+			trace->flight_recorder = 0;
+			trace->daemon_task_struct = current;
+		} else {
+			if ((trace->trace_start_data = (struct _ltt_trace_start *) kmalloc(sizeof(struct _ltt_trace_start), GFP_ATOMIC)) == NULL)
+				return -ENOMEM;
+		}
+ 
+		trace->proc_dir_entry = create_handle_proc_dir(tracer_handle);
+		ltt_set_default_config(trace);
+		retval = trace->trace_handle = tracer_handle;
+	}
+
+	return retval;
+}
+
+/**
+ *	ltt_free_trace_handle: - Free a single handle.
+ *	tracer_handle: handle to be freed.
+ *
+ *	Returns: 
+ *	0, everything went OK
+ *	-ENODEV, no such handle.
+ *	-EACCES, handle doesn't belong to caller.
+ */
+int ltt_free_trace_handle(unsigned int tracer_handle)
+{
+	int retval;
+
+	if ((tracer_handle < NR_TRACES) || (tracer_handle >= LTT_MAX_HANDLES))
+		return -ENODEV;
+
+	write_lock(&trace_handle_table_lock);
+
+	if (trace_handle_table[tracer_handle - NR_TRACES].owner == current) {
+		trace_handle_table[tracer_handle - NR_TRACES].owner = NULL;
+		retval = 0;
+	}
+	else
+		retval = -EACCES;
+
+	write_unlock(&trace_handle_table_lock);
+
+	return retval;
+}
+
+/**
+ *	ltt_free_daemon_handle: - Free the daemon's handle.
+ *	@trace: the trace instance
+ *
+ *	Returns: 
+ *	0, everything went OK
+ *	-EACCES, handle doesn't belong to caller.
+ *	-EBUSY, there are still event writes in progress so the buffer can't
+ *	be released.
+ */
+int ltt_free_daemon_handle(struct ltt_trace_struct *trace)
+{
+	int i;
+
+	if (!trace->flight_recorder) {
+		if (trace->daemon_task_struct != current)
+			return -EACCES;
+
+		for (i = 0; i < num_cpus; i++) {
+			if (events_lost(trace->trace_handle, i) > 0)
+				printk(KERN_ALERT "LTT: Lost %d events on cpu %d\n",
+				       events_lost(trace->trace_handle, i), i);
+		}
+		trace->daemon_task_struct = NULL;
+	}
+	
+	trace->active = NULL;
+
+	if (!active_traces())
+		del_percpu_timers();
+
+	if(trace->using_tsc && !need_heartbeat()) 
+		delete_heartbeat_timer();
+
+	for (i = 0; i < num_cpus; i++) {
+		if (trace_channel_handle(trace->trace_handle, i) != -1) {
+				trace_channel_handle(trace->trace_handle, i) = -1;
+				trace_channel_reader(trace->trace_handle, i) = NULL;
+		}
+	}
+
+	remove_handle_proc_dir(trace->proc_dir_entry, 0);
+
+	trace->use_locking = 1;
+	ltt_set_default_config(trace);
+	trace->tracer_started = 0;
+	trace->tracer_stopping = 0;
+	if (trace->trace_start_data)
+		kfree(trace->trace_start_data);
+
+	return 0;
+}
+
+/**
+ *	ltt_free_all_handles: - Free all handles taken.
+ *	@task_ptr: pointer to exiting task.
+ *
+ *	Free all handles taken against a given channel.  If task_ptr is NULL,
+ *	it means there is no daemon, i.e. free all handles taken agains the
+ *	flight recorder channel, otherwise task_ptr refers to a trace daemon.
+ */
+void ltt_free_all_handles(struct task_struct* task_ptr)
+{
+	int i;
+	struct ltt_trace_struct *trace;
+
+	if (task_ptr == NULL) {
+		if (current_traces[FLIGHT_HANDLE].active) {
+			ltt_free_daemon_handle(&current_traces[FLIGHT_HANDLE]);
+			return;
+		}
+	}
+	else {
+		trace = &current_traces[TRACE_HANDLE];
+		if (trace->active && trace->daemon_task_struct == task_ptr)
+			ltt_free_daemon_handle(trace);
+	}
+
+	write_lock(&trace_handle_table_lock);
+	for (i = 0; i < LTT_MAX_HANDLES; i++)
+		if (trace_handle_table[i].owner == current)
+			trace_handle_table[i].owner = NULL;
+	write_unlock(&trace_handle_table_lock);
+}
+
+/*
+ * Tracer Configuration
+ */
+
+/**
+ *	init_trace: - Initialize a trace/flight recorder instance
+ *	@trace_struct: trace/flight recorder struct
+ *
+ *	Initialize a trace instance to default values.
+ */
+static void init_trace(struct ltt_trace_struct *trace)
+{
+	trace->trace_handle = 0;
+	
+	trace->active = NULL;
+	trace->paused = 0;
+	trace->flight_recorder = 1;
+	trace->daemon_task_struct = NULL;
+	trace->trace_start_data = NULL;
+	
+	trace->tracer_started = 0;
+	trace->tracer_stopping = 0;
+	trace->proc_dir_entry = NULL;
+	trace->traced_events = 0;
+	trace->log_event_details_mask = 0;
+	trace->log_cpuid = 0;
+	trace->tracing_pid = 0;
+	trace->tracing_pgrp = 0;
+	trace->tracing_gid = 0;
+	trace->tracing_uid = 0;
+	trace->traced_pid = 0;
+	trace->traced_pgrp = 0;
+	trace->traced_gid = 0;
+	trace->traced_uid = 0;
+	trace->use_locking = 1;
+	trace->n_buffers = 0;
+	trace->buf_size = 0;
+	trace->using_tsc = 0;
+
+	trace->buffer_switches_pending = 0;
+	INIT_WORK(&trace->work, NULL, NULL);
+}
+
+/**
+ *	ltt_syscall_active: - If any active trace is logging syscalls, return 1
+ *	@syscall_type: either SYSCALL_ENTRY or SYSCALL_EXIT
+ *
+ *	Returns 1 if any channel is tracing syscalls, 0 otherwise
+ *
+ *	Needed for setting/clearing the global syscall...active variables
+ *	in order to reflect the needs of all traces.
+ */
+int ltt_syscall_active(int syscall_type)
+{
+	int i, retval = 0;
+	struct ltt_trace_struct *trace;
+	
+	for (i = 0; i < NR_TRACES; i++) {
+		trace = &current_traces[i];
+		if (!trace->active)
+			continue;
+		if(ltt_test_bit(syscall_type, &trace->traced_events))
+			retval = 1;
+	}
+
+	return retval;
+}
+
+/**
+ *	init_channel_data: - Init channel-associated data for new tracing run.
+ *	@trace: the trace to be initialized
+ */
+static void init_channel_data(struct ltt_trace_struct *trace)
+{
+	unsigned i;
+	
+	trace->buffer_switches_pending = 0;
+
+	for (i = 0; i < num_cpus; i++) {
+		trace_channel_handle(trace->trace_handle, i) = -1;
+		trace_channel_reader(trace->trace_handle, i) = NULL;
+		atomic_set(&waiting_for_cpu_async(trace->trace_handle, i), LTT_NOTHING_TO_DO);
+		events_lost(trace->trace_handle, i) = 0;
+	}
+}
+
+/**
+ *	ltt_set_n_buffers: - Sets the number of buffers.
+ *      @trace: the trace instance
+ *	@no_buffers: number of buffers
+ *
+ *	For lockless only, must be a power of 2.
+ *
+ *	Returns:
+ *
+ *	0, Size setting went OK
+ *	-EINVAL, not a power of 2
+ */
+int ltt_set_n_buffers(struct ltt_trace_struct *trace, int no_buffers)
+{
+	if (hweight32(no_buffers) != 1)
+		return -EINVAL;
+
+	trace->n_buffers = no_buffers;
+
+	return 0;
+}
+
+/**
+ *	ltt_set_buffer_size: - Sets size of and creates buffers.
+ *	@buf_size: Size of sub-buffers
+ *	@dirname: name of the relayfs directory to contain trace files
+ *
+ *	Note: dirname should be well-formed before it gets here e.g.
+ *	trailing slashes should be removed.
+ *
+ *	Returns:
+ *	0, Size setting went OK
+ *	-ENOMEM, unable to get a hold of memory for tracer
+ *	-EINVAL, tracer not properly configured
+ */
+int ltt_set_buffer_size(struct ltt_trace_struct *trace, int buffer_size, char * dirname)
+{
+	int i;
+	u32 flags;
+
+	if (trace->flight_recorder)
+		flags = RELAY_DELIVERY_BULK | RELAY_USAGE_SMP | RELAY_MODE_CONTINUOUS;
+	else
+		flags = RELAY_DELIVERY_BULK | RELAY_USAGE_SMP | RELAY_MODE_NO_OVERWRITE;
+
+	if ((dirname == NULL) || (strlen(dirname) == 0))
+		return  -EINVAL;
+
+	if (trace->using_tsc)
+		flags |= RELAY_TIMESTAMP_TSC;
+	else
+		flags |= RELAY_TIMESTAMP_GETTIMEOFDAY;
+	
+	if (trace->use_locking)
+		flags |= RELAY_SCHEME_LOCKING;
+	else
+		flags |= RELAY_SCHEME_LOCKLESS;
+	
+	num_cpus = num_online_cpus();
+
+	init_channel_data(trace);
+
+	trace->buf_size = buffer_size;
+
+	for (i = 0; i < num_cpus; i++) {
+		sprintf(relay_file_name, "%s/cpu%d", dirname, i);
+		trace_channel_handle(trace->trace_handle, i) = relay_open(relay_file_name,
+							  buffer_size,
+							  trace->n_buffers,
+							  flags,
+							  &ltt_callbacks,
+							  start_reserve,
+							  end_reserve,
+							  trace_start_reserve,
+							  0,
+							  0,
+							  0,
+							  NULL,
+							  0);
+		if (trace_channel_handle(trace->trace_handle, i) < 0)
+			return -ENOMEM;
+	}
+	
+	return 0;
+}
+
+/**
+ *	ltt_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 ltt_set_default_config(struct ltt_trace_struct *trace)
+{
+	int i;
+	int retval = 0;
+
+	trace->traced_events = 0;
+
+	for (i = 0; i <= LTT_EV_MAX; i++) {
+		ltt_set_bit(i, &trace->traced_events);
+		ltt_set_bit(i, &trace->log_event_details_mask);
+	}
+
+	syscall_entry_trace_active = ltt_syscall_active(LTT_EV_SYSCALL_ENTRY);
+	syscall_exit_trace_active  = ltt_syscall_active(LTT_EV_SYSCALL_EXIT);
+
+	trace->log_cpuid = 0;
+	trace->tracing_pid = 0;
+	trace->tracing_pgrp = 0;
+	trace->tracing_gid = 0;
+	trace->tracing_uid = 0;
+	trace->using_tsc = 0;
+
+	syscall_eip_depth_set = 0;
+	use_syscall_eip_bounds = 0;
+	lower_eip_bound_set = 0;
+	upper_eip_bound_set = 0;
+
+	ltt_set_trace_config(syscall_eip_depth_set,
+			 use_syscall_eip_bounds,
+			 0,
+			 0,
+			 0);
+
+	return retval;
+}
+
+/**
+ *	ltt_set_trace_config: - Set the tracing configuration
+ *	@do_syscall_depth: Use depth to fetch eip
+ *	@do_syscall_bounds: Use bounds to fetch eip
+ *	@eip_depth: Detph to fetch eip
+ *	@eip_lower_bound: Lower bound eip address
+ *	@eip_upper_bound: Upper bound eip address
+ *
+ *	Returns: 
+ *	0, all is OK 
+ *	-ENOMEDIUM, there isn't a registered tracer
+ *	-ENXIO, wrong tracer
+ *	-EINVAL, invalid configuration
+ */
+int ltt_set_trace_config(int do_syscall_depth,
+		     int do_syscall_bounds,
+		     int eip_depth,
+		     void *eip_lower_bound,
+		     void *eip_upper_bound)
+{
+	if ((do_syscall_depth && do_syscall_bounds)
+	    || (eip_lower_bound > eip_upper_bound)
+	    || (eip_depth < 0))
+		return -EINVAL;
+
+	fetch_syscall_eip_use_depth = do_syscall_depth;
+	fetch_syscall_eip_use_bounds = do_syscall_bounds;
+
+	syscall_eip_depth = eip_depth;
+	syscall_lower_eip_bound = eip_lower_bound;
+	syscall_upper_eip_bound = eip_upper_bound;
+
+	return 0;
+}
+
+/**
+ *	ltt_get_trace_config: - Get the tracing configuration
+ *	@do_syscall_depth: Use depth to fetch eip
+ *	@do_syscall_bounds: Use bounds to fetch eip
+ *	@eip_depth: Detph to fetch eip
+ *	@eip_lower_bound: Lower bound eip address
+ *	@eip_upper_bound: Upper bound eip address
+ *
+ *	Returns:
+ *	0, all is OK 
+ *	-ENOMEDIUM, there isn't a registered tracer
+ */
+int ltt_get_trace_config(int *do_syscall_depth,
+		     int *do_syscall_bounds,
+		     int *eip_depth,
+		     void **eip_lower_bound,
+		     void **eip_upper_bound)
+{
+	*do_syscall_depth = fetch_syscall_eip_use_depth;
+	*do_syscall_bounds = fetch_syscall_eip_use_bounds;
+	*eip_depth = syscall_eip_depth;
+	*eip_lower_bound = syscall_lower_eip_bound;
+	*eip_upper_bound = syscall_upper_eip_bound;
+
+	return 0;
+}
+
+/**
+ *	ltt_set_flight_recorder_config: - set flight recorder defaults
+ *	@trace: the trace struct
+ */
+void ltt_set_flight_recorder_config(struct ltt_trace_struct *trace)
+{
+	trace->traced_events = 0;
+	trace->log_event_details_mask = 0;
+	
+	ltt_set_bit(LTT_EV_BUFFER_START, &trace->traced_events);
+	ltt_set_bit(LTT_EV_BUFFER_START, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_START, &trace->traced_events);
+	ltt_set_bit(LTT_EV_START, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->traced_events);
+	ltt_set_bit(LTT_EV_CHANGE_MASK, &trace->log_event_details_mask);
+
+	ltt_set_bit(LTT_EV_SYSCALL_ENTRY, &trace->traced_events);
+	ltt_set_bit(LTT_EV_SYSCALL_ENTRY, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_SYSCALL_EXIT, &trace->traced_events);
+	ltt_set_bit(LTT_EV_SYSCALL_EXIT, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_TRAP_ENTRY, &trace->traced_events);
+	ltt_set_bit(LTT_EV_TRAP_ENTRY, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_TRAP_EXIT, &trace->traced_events);
+	ltt_set_bit(LTT_EV_TRAP_EXIT, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_IRQ_ENTRY, &trace->traced_events);
+	ltt_set_bit(LTT_EV_IRQ_ENTRY, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_IRQ_EXIT, &trace->traced_events);
+	ltt_set_bit(LTT_EV_IRQ_EXIT, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_SCHEDCHANGE, &trace->traced_events);
+	ltt_set_bit(LTT_EV_SCHEDCHANGE, &trace->log_event_details_mask);
+
+	ltt_set_bit(LTT_EV_KERNEL_TIMER, &trace->traced_events);
+	ltt_set_bit(LTT_EV_KERNEL_TIMER, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_SOFT_IRQ, &trace->traced_events);
+	ltt_set_bit(LTT_EV_SOFT_IRQ, &trace->log_event_details_mask);
+	ltt_set_bit(LTT_EV_PROCESS, &trace->traced_events);
+	ltt_set_bit(LTT_EV_PROCESS, &trace->log_event_details_mask);
+}
+
+/**
+ *	ltt_get_status: - fill in a status struct covering all traces
+ *	@tracer_status: the tracer_status struct
+ */
+int ltt_get_status(struct ltt_tracer_status *tracer_status)
+{
+	int i, j, rchan_handle, retval = 0;
+	struct ltt_trace_struct *trace;
+	struct ltt_trace_info *info;
+	struct rchan_info rchan_info;
+	
+	tracer_status->num_cpus = num_cpus;
+
+	for (i = 0; i < NR_TRACES; i++) {
+		trace = &current_traces[i];
+		info = &tracer_status->traces[i];
+		info->active = trace->active && trace->tracer_started ? 1 : 0;
+		if (!info->active)
+			continue;
+		info->trace_handle = trace->trace_handle;
+		info->paused = trace->paused;
+		info->flight_recorder = trace->flight_recorder;
+		info->use_locking = trace->use_locking;
+		info->using_tsc = trace->using_tsc;
+		info->n_buffers = trace->n_buffers;
+		info->buf_size = trace->buf_size;
+		info->traced_events = trace->traced_events;
+		info->log_event_details_mask = trace->log_event_details_mask;
+		for (j = 0; j < num_cpus; j++) {
+			rchan_handle = trace_channel_handle(trace->trace_handle, j);
+			retval = relay_info(rchan_handle, &rchan_info);
+			if (retval)
+				return retval;
+			info->buffers_produced[j] = rchan_info.bufs_produced;
+		}
+	}
+
+	return retval;
+}
+
+/*
+ * Custom Events
+ */
+
+/**
+ *	init_custom_events: - Initialize custom events
+ */
+static inline void init_custom_events(void)
+{
+	custom_events = &custom_events_head;
+	custom_events->next = custom_events;
+	custom_events->prev = custom_events;
+}
+
+/**
+ *	_ltt_create_event: - Create a new traceable event type
+ *	@event_type: string describing event type
+ *	@event_desc: string used for standard formatting
+ *	@format_type: type of formatting used to log event data
+ *	@format_data: data specific to format
+ *	@owner_pid: PID of event's owner (0 if none)
+ *
+ *	Returns:
+ *	New Event ID if all is OK
+ *	-ENOMEM, Unable to allocate new event
+ */
+int _ltt_create_event(char *event_type,
+		      char *event_desc,
+		      int format_type,
+		      char *format_data,
+		      pid_t owner_pid)
+{
+	ltt_new_event *new_event;
+	struct custom_event_desc *new_event_desc;
+
+	if ((new_event_desc = (struct custom_event_desc *) kmalloc(sizeof(struct custom_event_desc), GFP_ATOMIC)) == NULL)
+		 return -ENOMEM;
+
+	new_event = &(new_event_desc->event);
+	new_event->type[0] = '\0';
+	new_event->desc[0] = '\0';
+	new_event->form[0] = '\0';
+
+	if (event_type != NULL)
+		strncpy(new_event->type, event_type, LTT_CUSTOM_EV_TYPE_STR_LEN);
+	if (event_desc != NULL)
+		strncpy(new_event->desc, event_desc, LTT_CUSTOM_EV_DESC_STR_LEN);
+	if (format_data != NULL)
+		strncpy(new_event->form, format_data, LTT_CUSTOM_EV_FORM_STR_LEN);
+
+	new_event->type[LTT_CUSTOM_EV_TYPE_STR_LEN - 1] = '\0';
+	new_event->desc[LTT_CUSTOM_EV_DESC_STR_LEN - 1] = '\0';
+	new_event->form[LTT_CUSTOM_EV_FORM_STR_LEN - 1] = '\0';
+
+	new_event->format_type = format_type;
+	new_event->id = next_event_id;
+
+	next_event_id++;
+
+	new_event_desc->owner_pid = owner_pid;
+
+	write_lock(&custom_list_lock);
+
+	if (custom_events == NULL)
+		init_custom_events();
+
+	new_event_desc->next = custom_events;
+	new_event_desc->prev = custom_events->prev;
+	custom_events->prev->next = new_event_desc;
+	custom_events->prev = new_event_desc;
+	write_unlock(&custom_list_lock);
+
+	ltt_log_event(LTT_EV_NEW_EVENT, &(new_event_desc->event));
+
+	return new_event->id;
+}
+
+int ltt_create_event(char *event_type,
+		     char *event_desc,
+		     int format_type,
+		     char *format_data)
+{
+	return _ltt_create_event(event_type, event_desc, format_type, format_data, 0);
+}
+
+int ltt_create_owned_event(char *event_type,
+			   char *event_desc,
+			   int format_type,
+			   char *format_data,
+			   pid_t owner_pid)
+{
+	return _ltt_create_event(event_type, event_desc, format_type, format_data, owner_pid);
+}
+
+/**
+ *	ltt_destroy_event: - Destroy a created event type
+ *	@event_id, the Id returned by ltt_create_event()
+ */
+void ltt_destroy_event(int event_id)
+{
+	struct custom_event_desc *event_desc;
+
+	write_lock(&custom_list_lock);
+
+	if (custom_events == NULL)
+		init_custom_events();
+
+	for (event_desc = custom_events->next;
+	     event_desc != custom_events;
+	     event_desc = event_desc->next)
+		if (event_desc->event.id == event_id)
+			break;
+
+	if (event_desc != custom_events) {
+		event_desc->next->prev = event_desc->prev;
+		event_desc->prev->next = event_desc->next;
+		kfree(event_desc);
+	}
+
+	write_unlock(&custom_list_lock);
+}
+
+/**
+ *	ltt_destroy_owners_events: Destroy an owner's events
+ *	@owner_pid: the PID of the owner who's events are to be deleted.
+ */
+void ltt_destroy_owners_events(pid_t owner_pid)
+{
+	struct custom_event_desc *temp_event;
+	struct custom_event_desc *event_desc;
+
+	write_lock(&custom_list_lock);
+
+	if (custom_events == NULL)
+		init_custom_events();
+
+	event_desc = custom_events->next;
+
+	while (event_desc != custom_events) {
+		temp_event = event_desc->next;
+		if (event_desc->owner_pid == owner_pid) {
+			event_desc->next->prev = event_desc->prev;
+			event_desc->prev->next = event_desc->next;
+			kfree(event_desc);
+		}
+		event_desc = temp_event;
+	}
+
+	write_unlock(&custom_list_lock);
+}
+
+/**
+ *	ltt_reregister_custom_events: - Relogs event creations.
+ */
+void ltt_reregister_custom_events(void)
+{
+	struct custom_event_desc *event_desc;
+
+	read_lock(&custom_list_lock);
+
+	if (custom_events == NULL)
+		init_custom_events();
+
+	for (event_desc = custom_events->next;
+	     event_desc != custom_events;
+	     event_desc = event_desc->next)
+		ltt_log_event(LTT_EV_NEW_EVENT, &(event_desc->event));
+
+	read_unlock(&custom_list_lock);
+}
+
+/*
+ * Event logging primitives
+ */
+
+/**
+ *	_ltt_log_event: - Tracing function per se.
+ *	@trace: the trace instance
+ *	@event_id: ID of event as defined in linux/ltt.h
+ *	@event_struct: struct describing the event
+ *	@cpu_id: the CPU associated with 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.
+ */
+int _ltt_log_event(struct ltt_trace_struct *trace,
+		   u8 event_id,
+		   void *event_struct,
+		   u8 cpu_id)
+{
+	int var_data_len = 0;
+	void *var_data_beg = NULL;
+	uint16_t data_size;
+	struct task_struct *incoming_process = NULL;
+	unsigned long flags;
+	char * reserved;
+	int bytes_written = 0;
+	int reserve_code, interrupting;
+	struct timeval time_stamp;
+	u32 time_delta;
+	int channel_handle;
+	struct rchan *rchan;
+	unsigned int tracer_handle;
+	
+	if (!trace)
+		return -ENOMEDIUM;
+
+	if (trace->paused)
+		return -EBUSY;
+
+	tracer_handle = trace->trace_handle;
+	
+	if (!trace->flight_recorder && (trace->daemon_task_struct == NULL))
+		return -ENODEV;
+
+	channel_handle = trace_channel_handle(tracer_handle, cpu_id);
+
+	if ((trace->tracer_started == 1) || (event_id == LTT_EV_START) || (event_id == LTT_EV_BUFFER_START))
+		goto trace_event;
+
+	return -EBUSY;
+
+trace_event:
+	if (!ltt_test_bit(event_id, &trace->traced_events))
+		return 0;
+
+	if ((event_id != LTT_EV_START) && (event_id != LTT_EV_BUFFER_START)) {
+		if (event_id == LTT_EV_SCHEDCHANGE)
+			incoming_process = (struct task_struct *) (((ltt_schedchange *) event_struct)->in);
+		if ((trace->tracing_pid == 1) && (current->pid != trace->traced_pid)) {
+			if (incoming_process == NULL)
+				return 0;
+			else if (incoming_process->pid != trace->traced_pid)
+				return 0;
+		}
+		if ((trace->tracing_pgrp == 1) && (process_group(current) != trace->traced_pgrp)) {
+			if (incoming_process == NULL)
+				return 0;
+			else if (process_group(incoming_process) != trace->traced_pgrp)
+				return 0;
+		}
+		if ((trace->tracing_gid == 1) && (current->egid != trace->traced_gid)) {
+			if (incoming_process == NULL)
+				return 0;
+			else if (incoming_process->egid != trace->traced_gid)
+				return 0;
+		}
+		if ((trace->tracing_uid == 1) && (current->euid != trace->traced_uid)) {
+			if (incoming_process == NULL)
+				return 0;
+			else if (incoming_process->euid != trace->traced_uid)
+				return 0;
+		}
+		if (event_id == LTT_EV_SCHEDCHANGE)
+			(((ltt_schedchange *) event_struct)->in) = incoming_process->pid;
+	}
+
+	data_size = sizeof(event_id) + sizeof(time_delta) + sizeof(data_size);
+
+	if (ltt_test_bit(event_id, &trace->log_event_details_mask)) {
+		data_size += event_struct_size[event_id];
+		switch (event_id) {
+		case LTT_EV_FILE_SYSTEM:
+			if ((((ltt_file_system *) event_struct)->event_sub_id == LTT_EV_FILE_SYSTEM_EXEC)
+			    || (((ltt_file_system *) event_struct)->event_sub_id == LTT_EV_FILE_SYSTEM_OPEN)) {
+				var_data_beg = ((ltt_file_system *) event_struct)->file_name;
+				var_data_len = ((ltt_file_system *) event_struct)->event_data2 + 1;
+				data_size += (uint16_t) var_data_len;
+			}
+			break;
+		case LTT_EV_CUSTOM:
+			var_data_beg = ((ltt_custom *) event_struct)->data;
+			var_data_len = ((ltt_custom *) event_struct)->data_size;
+			data_size += (uint16_t) var_data_len;
+			break;
+		}
+	}
+
+	if ((trace->log_cpuid == 1) && (event_id != LTT_EV_START) && (event_id != LTT_EV_BUFFER_START))
+		data_size += sizeof(cpu_id);
+
+	rchan = rchan_get(channel_handle);
+	if (rchan == NULL)
+		return -ENODEV;
+ 
+	relay_lock_channel(rchan, flags); /* nop for lockless */
+	reserved = relay_reserve(rchan, data_size, &time_stamp, &time_delta, &reserve_code, &interrupting);
+	
+	if (reserve_code & RELAY_WRITE_DISCARD) {
+		events_lost(trace->trace_handle, cpu_id)++;
+		bytes_written = 0;
+		goto check_buffer_switch;
+	}
+
+	if ((trace->log_cpuid == 1) && (event_id != LTT_EV_START) 
+	    && (event_id != LTT_EV_BUFFER_START))
+		relay_write_direct(reserved,
+				   &cpu_id,
+				   sizeof(cpu_id));
+
+	relay_write_direct(reserved,
+			   &event_id,
+			   sizeof(event_id));
+
+	relay_write_direct(reserved,
+			   &time_delta,
+			   sizeof(time_delta));
+
+	if (ltt_test_bit(event_id, &trace->log_event_details_mask)) {
+		relay_write_direct(reserved,
+				   event_struct,
+				   event_struct_size[event_id]);
+		if (var_data_len)
+			relay_write_direct(reserved,
+					   var_data_beg,
+					   var_data_len);
+	}
+
+	relay_write_direct(reserved,
+			   &data_size,
+			   sizeof(data_size));
+
+	bytes_written = data_size;
+
+check_buffer_switch:
+	if ((event_id == LTT_EV_SCHEDCHANGE) && (tracer_handle == TRACE_HANDLE) && current_traces[FLIGHT_HANDLE].active)
+		(((ltt_schedchange *) event_struct)->in) = (u32)incoming_process;
+	
+	/* We need to commit even if we didn't write anything because
+	   that's how the deliver callback is invoked. */
+	relay_commit(rchan, reserved, bytes_written, reserve_code, interrupting);
+
+	relay_unlock_channel(rchan, flags);
+	rchan_put(rchan);
+
+	return 0;
+}
+
+/**
+ *	ltt_log_event: - Trace an event
+ *	@event_id, the event's ID (check out ltt.h)
+ *	@event_struct, the structure describing the event
+ *
+ *	Returns:
+ *	Trace fct return code if OK.
+ *	-ENOMEDIUM, there is no registered tracer
+ *	-ENOMEM, couldn't access ltt_info
+ */
+int ltt_log_event(u8 event_id,
+		void *event_struct)
+{
+	int i;
+	static int err[NR_TRACES];
+	struct ltt_trace_struct *trace;
+	u32 cpu = smp_processor_id();
+
+	for (i = 0; i < NR_TRACES; i++) {
+		trace = current_traces[i].active;
+		err[i] = _ltt_log_event(trace,
+				     event_id,
+				     event_struct, 
+				     cpu);
+	}
+
+	return err[0] == -ENOMEDIUM ? err[1] : err[0];
+}
+
+/**
+ *	ltt_log_std_formatted_event: - Trace a formatted event
+ *	@event_id: the event Id provided upon creation
+ *	@...: printf-like data that will be used to fill the event string.
+ *
+ *	Returns:
+ *	Trace fct return code if OK.
+ *	-ENOMEDIUM, there is no registered tracer or event doesn't exist.
+ */
+int ltt_log_std_formatted_event(int event_id,...)
+{
+	int string_size;
+	char final_string[LTT_CUSTOM_EV_FINAL_STR_LEN];
+	va_list vararg_list;
+        ltt_custom custom_event;
+	struct custom_event_desc *event_desc;
+
+	read_lock(&custom_list_lock);
+
+	if (custom_events == NULL)
+		init_custom_events();
+
+	for (event_desc = custom_events->next;
+	     event_desc != custom_events;
+	     event_desc = event_desc->next)
+		if (event_desc->event.id == event_id)
+			break;
+
+	if (event_desc == custom_events) {
+		read_unlock(&custom_list_lock);
+		return -ENOMEDIUM;
+	}
+
+	custom_event.id = event_id;
+
+	va_start(vararg_list, event_id);
+	string_size = vsprintf(final_string, event_desc->event.desc, vararg_list);
+	read_unlock(&custom_list_lock);
+	va_end(vararg_list);
+
+	custom_event.data_size = (u32) (string_size + 1);
+	custom_event.data = final_string;
+
+	return ltt_log_event(LTT_EV_CUSTOM, &custom_event);
+}
+
+/**
+ *	ltt_log_raw_event: - Trace a raw event
+ *	@event_id, the event Id provided upon creation
+ *	@event_size, the size of the data provided
+ *	@event_data, data buffer describing event
+ *
+ *	Returns:
+ *	Trace fct return code if OK.
+ *	-ENOMEDIUM, there is no registered tracer or event doesn't exist.
+ */
+int ltt_log_raw_event(int event_id, int event_size, void *event_data)
+{
+	ltt_custom custom_event;
+	struct custom_event_desc *event_desc;
+
+	read_lock(&custom_list_lock);
+
+	if (custom_events == NULL)
+		init_custom_events();
+
+	for (event_desc = custom_events->next;
+	     event_desc != custom_events;
+	     event_desc = event_desc->next)
+		if (event_desc->event.id == event_id)
+			break;
+
+	read_unlock(&custom_list_lock);
+
+	if (event_desc == custom_events)
+		return -ENOMEDIUM;
+
+	custom_event.id = event_id;
+
+	if (event_size <= LTT_CUSTOM_EV_MAX_SIZE)
+		custom_event.data_size = (u32) event_size;
+	else
+		custom_event.data_size = (u32) LTT_CUSTOM_EV_MAX_SIZE;
+
+	custom_event.data = event_data;
+
+	return ltt_log_event(LTT_EV_CUSTOM, &custom_event);
+}
+
+/*
+ * Relayfs callback implementations.
+ */
+
+/**
+ *	_ltt_channel_cpuid: - Get CPU id given channel handle, for given trace.
+ *	@tracer_handle: trace handle.
+ *	@channel_handle: relay channel handle.
+ *
+ *	Returns:
+ *
+ *	CPU id
+ *	-1, channel_handle, thus CPU id, not found
+ */
+static int _ltt_channel_cpuid(int tracer_handle, int channel_handle)
+{
+	int i;
+	
+	for (i = 0; i < num_cpus; i++)
+		if (trace_channel_handle(tracer_handle, i) == channel_handle)
+			return i;
+	
+	return -1;
+}
+
+/**
+ *	ltt_channel_cpuid: - Get CPU id given channel handle.
+ *	@channel_handle: relay channel handle.
+ *
+ *	Returns:
+ *
+ *	CPU id
+ *	-1, channel_handle, thus CPU id, not found
+ */
+static int ltt_channel_cpuid(int channel_handle)
+{
+	int i, cpuid;
+	
+	for (i = 0; i < NR_TRACES; i++) {
+		cpuid = _ltt_channel_cpuid(i, channel_handle);
+		if (cpuid != -1)
+			return cpuid;
+	}
+	
+	return -1;
+}
+
+/**
+ *	ltt_channel_trace: - Get trace struct given channel handle.
+ *	@channel_handle: relay channel handle.
+ *
+ *	Returns:
+ *
+ *	trace struct *
+ *	NULL, channel_handle, thus trace_struct *, not found
+ */
+static struct ltt_trace_struct *ltt_channel_trace(int channel_handle)
+{
+	int i;
+	
+	for (i = 0; i < NR_TRACES; i++) {
+		if (_ltt_channel_cpuid(i, channel_handle) != -1)
+			return &current_traces[i];
+	}
+	
+	return NULL;
+}
+
+/**
+ *	ltt_channel_trace_handle: - Get trace handle given channel handle.
+ *	@channel_handle: relay channel handle.
+ *
+ *	Returns:
+ *
+ *	trace handle
+ *	-1, channel_handle, thus trace handle, not found
+ */
+static int ltt_channel_trace_handle(int channel_handle)
+{
+	unsigned int i;
+	
+	for (i = 0; i < NR_TRACES; i++)
+		if (_ltt_channel_cpuid(i, channel_handle) != -1)
+			return i;
+	
+	return -1;
+}
+
+/**
+ *	write_start_event: - Initialize a trace session for a given CPU.
+ *	@cpu_id: the CPU id to initialize a trace for
+ */
+static inline int write_start_event(struct ltt_trace_struct *trace,
+				    int channel, 
+				    char * current_write_pos,
+				    u32 start_tsc,
+				    int using_tsc)
+{
+	struct rchan_info channel_info;
+	u32 time_delta;
+        ltt_trace_start start_event;
+	u8 event_id;
+	uint16_t data_size;
+
+	relay_info(channel, &channel_info);
+
+	start_event.magic_number =	LTT_TRACER_MAGIC_NUMBER;
+	start_event.arch_type =		LTT_ARCH_TYPE;
+	start_event.arch_variant =	LTT_ARCH_VARIANT;
+	start_event.system_type =	LTT_SYS_TYPE_VANILLA_LINUX;
+	start_event.major_version =	LTT_TRACER_VERSION_MAJOR;
+	start_event.minor_version =	LTT_TRACER_VERSION_MINOR;
+	start_event.buffer_size =	channel_info.buf_size;
+	start_event.event_mask = 	trace->traced_events;
+	start_event.details_mask =	trace->log_event_details_mask;
+	start_event.log_cpuid =		trace->log_cpuid;
+	start_event.use_tsc =		trace->using_tsc;
+	start_event.flight_recorder =	trace->flight_recorder;
+
+	event_id = LTT_EV_START;
+	relay_write_direct(current_write_pos,
+			   &event_id,
+			   sizeof(event_id));
+
+	time_delta = switch_time_delta(start_tsc, using_tsc);
+	relay_write_direct(current_write_pos,
+			   &time_delta,
+			   sizeof(time_delta));
+
+	relay_write_direct(current_write_pos,
+			   &start_event,
+			   sizeof(ltt_trace_start));
+
+	data_size = sizeof(event_id)
+		+ sizeof(time_delta)
+		+ sizeof(ltt_trace_start)
+		+ sizeof(data_size);
+
+	relay_write_direct(current_write_pos,
+			   &data_size,
+			   sizeof(data_size));
+
+	if (trace->trace_start_data)
+		memcpy(trace->trace_start_data, &start_event, sizeof(start_event));
+
+	return (int)data_size;
+}
+
+/**
+ *	buffer_start_callback: - Write start-buffer event to start of buffer.
+ *	@channel_handle: the channel id
+ *	@current_write_pos: position in sub-buffer client should write to
+ *	@buffer_id: the id of the new sub-buffer
+ *	@start_time: the timestamp associated with the start of sub-buffer
+ *	@start_tsc: the TSC associated with the timestamp, if using_tsc
+ *	@using_tsc: boolean, indicates whether start_tsc is valid
+ *
+ *	This is the relayfs buffer_start() callback implementation for
+ *	the tracer.  We write the start event directly to the address
+ *	contained in the current_write_pos param.  If this is the first
+ *	sub-buffer, we also write the start event.  Of course we reserved
+ *	the number of bytes we're writing when we opened the channel, which
+ *	is the number we return.
+ */
+static int buffer_start_callback(int channel_handle,
+				 char * current_write_pos,
+				 u32 buffer_id,
+				 struct timeval start_time,
+				 u32 start_tsc,
+				 int using_tsc) 
+{
+	ltt_buffer_start start_buffer_event;
+	u8 event_id;
+	u32 time_delta;
+	uint16_t data_size;
+	struct ltt_trace_struct *trace = ltt_channel_trace(channel_handle);
+
+	if (!trace)
+		return 0;
+	
+	start_buffer_event.id = buffer_id;
+	start_buffer_event.time = start_time;
+	start_buffer_event.tsc = start_tsc;
+
+	event_id = LTT_EV_BUFFER_START;
+	relay_write_direct(current_write_pos,
+			   &event_id,
+			   sizeof(event_id));
+
+	time_delta = switch_time_delta(start_tsc, using_tsc);
+	relay_write_direct(current_write_pos,
+			   &time_delta,
+			   sizeof(time_delta));
+
+	relay_write_direct(current_write_pos,
+			   &start_buffer_event,
+			   sizeof(start_buffer_event));
+
+	data_size = sizeof(event_id)
+	    + sizeof(time_delta)
+	    + sizeof(start_buffer_event)
+	    + sizeof(data_size);
+
+	relay_write_direct(current_write_pos,
+			   &data_size,
+			   sizeof(data_size));
+
+	if (buffer_id == 0) /* first buffer */
+		data_size += write_start_event(trace, channel_handle, current_write_pos, start_tsc, using_tsc);
+	
+	return (int)data_size;
+}
+
+/**
+ *	buffer_end_callback - called at the end of a sub-buffer
+ *	@channel_handle: the channel id
+ *	@current_write_pos: position in sub-buffer of end of data
+ *	@end_of_buffer: the position of the end of the sub-buffer
+ *	@end_time: the timestamp associated with the end of the sub-buffer
+ *	@end_tsc: the TSC associated with the end_time, if using_tsc
+ *	@using_tsc: boolean, indicates whether end_tsc is valid
+ *
+ *	This is the relayfs buffer_end() callback implementation for
+ *	the tracer.  We write the end event directly to the address
+ *	contained in the current_write_pos param.  We also calculate
+ *	the 'size_lost' or unused bytes at the end of the sub-buffer
+ *	and write that value to the very end of the sub-buffer for
+ *	post-processing.  Of course we reserved	the number of bytes
+ *	we're writing when we opened the channel, which is the number
+ *	we return.
+ */
+static int buffer_end_callback(int channel_handle,
+			       char * current_write_pos,
+			       char * end_of_buffer,
+			       struct timeval end_time,
+			       u32 end_tsc,
+			       int using_tsc) 
+{
+ 	ltt_buffer_end end_buffer_event;
+	u8 event_id;
+	u32 time_delta;
+	char* init_write_pos = current_write_pos;
+	uint16_t data_size;
+	u32 size_lost;
+	u8 cpu_id;
+	struct ltt_trace_struct *trace;
+
+	end_buffer_event.time = end_time;
+	end_buffer_event.tsc = end_tsc;
+
+	cpu_id = (u8)ltt_channel_cpuid(channel_handle);
+	trace = ltt_channel_trace(channel_handle);
+	if (!trace)
+		return 0;
+
+	if (trace->log_cpuid == 1)
+		relay_write_direct(current_write_pos,
+				   &cpu_id,
+				   sizeof(cpu_id));
+
+	event_id = LTT_EV_BUFFER_END;
+	relay_write_direct(current_write_pos,
+			   &event_id,
+			   sizeof(event_id));
+
+	time_delta = switch_time_delta(end_tsc, using_tsc);
+	relay_write_direct(current_write_pos,
+			   &time_delta,
+			   sizeof(time_delta));
+
+	relay_write_direct(current_write_pos,
+			   &end_buffer_event,
+			   sizeof(end_buffer_event));
+
+	data_size = sizeof(event_id)
+		+ sizeof(time_delta)
+		+ sizeof(end_buffer_event)
+		+ sizeof(data_size);
+
+	relay_write_direct(current_write_pos,
+			   &data_size,
+			   sizeof(data_size));
+
+	/* size lost includes size of end buffer event */
+	size_lost = end_of_buffer - init_write_pos;
+	*((u32 *) (end_of_buffer - sizeof(size_lost))) = size_lost;
+
+	return (int)data_size;
+}
+
+/**
+ *	deliver_callback - called when data is ready for the tracer
+ *	@channel_handle: the channel id
+ *	@from: the start of the delivered data
+ *	@len: the length of the delivered data
+ *
+ *	This is the relayfs deliver() callback implementation for
+ *	the tracer.  We simply set the send_signal flag, which will
+ *	be checked when the current write is finished, at which 
+ *	point the daemon will be signaled to read the buffer.
+ */
+void deliver_callback(int channel_handle,
+		      char * from,
+		      u32 len)
+{
+	struct ltt_trace_struct *trace;
+	int cpu_id;
+
+	trace = ltt_channel_trace(channel_handle);
+	if (!trace)
+		return;
+	
+	cpu_id = ltt_channel_cpuid(channel_handle);
+	if (cpu_id == -1)
+		return;
+
+	set_bit(cpu_id, &trace->buffer_switches_pending);
+}
+
+/**
+ *	fileop_notify - called when change to trace file status 
+ *	@rchan_id: the rchan id
+ *	@filp: the file
+ *	@fileop: the file operation
+ *
+ *	This is the relayfs fileop_notify() callback implementation for
+ *	the tracer.  We use it to take care of trace file mapping and
+ *	unmapping tasks.
+ */
+static int fileop_notify (int rchan_id,
+			  struct file *filp,
+			  enum relay_fileop fileop)
+{
+	struct rchan_reader *map_reader;
+	struct rchan_reader *open_file_reader;
+	struct rchan *rchan;
+	u8 cpu_id;
+	int trace_handle;
+
+	trace_handle = ltt_channel_trace_handle(rchan_id);
+	if (trace_handle == -1)
+		return 0;
+	
+	if (fileop == RELAY_FILE_MAP) {
+		cpu_id = (u8)ltt_channel_cpuid(rchan_id);
+		open_file_reader = (struct rchan_reader *)filp->private_data;
+		rchan = open_file_reader->rchan;
+		if (atomic_read(&rchan->mapped))
+			return -EBUSY;
+		map_reader = add_map_reader(rchan_id);
+		trace_channel_reader(trace_handle, cpu_id) = map_reader;
+	}
+	else if (fileop == RELAY_FILE_UNMAP) {
+		cpu_id = (u8)ltt_channel_cpuid(rchan_id);
+		remove_map_reader(trace_channel_reader(trace_handle, cpu_id));
+		trace_channel_reader(trace_handle, cpu_id) = NULL;
+	}
+
+	return 0;
+}
+
+static struct rchan_callbacks ltt_callbacks = {
+	.buffer_start = buffer_start_callback,
+	.buffer_end = buffer_end_callback,
+	.deliver = deliver_callback,
+	.fileop_notify = fileop_notify,
+	.ioctl = ltt_ioctl,
+};
+
+/*
+ * Procfs kernel-user interface
+ */
+
+/**
+ *	proc_read_relayfs_path - procfs read callback for relayfs_path attr 
+ */
+static int proc_read_relayfs_path(char *page, char **start, off_t off, 
+				  int count, int *eof, void *data)
+{
+	return sprintf(page, "%s", relayfs_path);
+}
+
+/**
+ *	proc_write_relayfs_path - procfs write callback for relayfs_path attr 
+ *
+ *	Sets the path to the trace files within relayfs for the current trace.
+ */
+static int proc_write_relayfs_path(struct file *filp, const char *buffer,
+				   unsigned long count, void *data)
+{
+	unsigned long len;
+
+	if (count > PATH_MAX)
+		len = PATH_MAX;
+	else
+		len = count;
+	
+	if (copy_from_user(relayfs_path, buffer, len))
+		return -EFAULT;
+
+	if (len != PATH_MAX)
+		relayfs_path[len] = '\0';
+
+	return len;
+}
+
+/**
+ *	populate_handle_proc_dir - populate proc dir with trace attributes
+ *	@trace_handle: the trace handle for this trace run
+ *	@handle_dir: the directory to populate
+ *
+ *	This function populates the handle dir with attribute files.
+ *
+ *	Returns 0 if successful, negative if not.
+ */
+static int populate_handle_proc_dir(unsigned int trace_handle,
+				    struct proc_dir_entry *handle_dir)
+{
+	struct proc_dir_entry * file_entry;
+	int err = 0;
+
+	file_entry = create_proc_entry("relayfs_path", 0666, handle_dir);
+
+	if (file_entry == NULL) {
+		err = -ENOMEM;
+		return err;
+	}
+
+	file_entry->read_proc = proc_read_relayfs_path;
+	file_entry->write_proc = proc_write_relayfs_path;
+	file_entry->data = (void *)trace_handle;
+	file_entry->owner = THIS_MODULE;
+
+	return err;
+}
+
+/**
+ *	create_handle_proc_dir - create proc dir for trace attributes
+ *	@trace_handle: the trace handle for this trace run
+ *
+ *	This function creates a proc dir to communicate trace attribute
+ *	values between the daemon and the tracer.  It also populates the
+ *	new dir with the attribute files.
+ *
+ *	Retruns the proc dir entry if successful, NULL otherwise.
+ */
+static struct proc_dir_entry *create_handle_proc_dir(unsigned int trace_handle)
+{
+	char handle_dir_name[22];
+	struct proc_dir_entry *handle_dir;
+
+	sprintf(handle_dir_name, "%u", trace_handle);
+
+	handle_dir = proc_mkdir(handle_dir_name, ltt_proc_root_entry);
+
+	if (handle_dir == NULL)
+		return NULL;
+	else
+		handle_dir->owner = THIS_MODULE;
+
+	if (populate_handle_proc_dir(trace_handle, handle_dir)) {
+		remove_proc_entry(handle_dir_name, ltt_proc_root_entry);
+		handle_dir = NULL;
+	}
+		
+	return handle_dir;
+}
+
+/**
+ *	depopulate_handle_proc_dir - remove proc dir entries for handle_dir
+ *	@handle_dir: the directory to depopulate
+ *
+ *	This function removes the attribute files from the handle dir.
+ */
+static void depopulate_handle_proc_dir(struct proc_dir_entry *handle_dir)
+{
+	remove_proc_entry("relayfs_path", handle_dir);
+}
+
+/**
+ *	remove_handle_proc_dir - remove proc dir for trace attributes
+ *	@handle_dir: the directory
+ *	@trace_handle: the trace handle for this trace run
+ *
+ *	This function removes a trace handle's proc dir.  It first
+ *	depopulates the dir of attribute files.
+ */
+static void remove_handle_proc_dir(struct proc_dir_entry *handle_dir, 
+				   unsigned int trace_handle)
+{
+	char handle_dir_name[22];
+
+	depopulate_handle_proc_dir(handle_dir);
+	
+	sprintf(handle_dir_name, "%u", trace_handle);
+	remove_proc_entry(handle_dir_name, ltt_proc_root_entry);
+}
+
+
+/*
+ * Initialization and finalization
+ */
+
+static struct rchan_callbacks control_callbacks = {
+	.ioctl = ltt_ioctl,
+};
+
+/**
+ *	create_control_channel - creates channel /mnt/relay/ltt/control
+ *
+ *	Returns channel id on success, negative otherwise.
+ */
+static int create_control_channel(void)
+{
+	u32 bufsize, nbufs;
+	u32 channel_flags;
+	int control;
+
+	sprintf(relay_file_name, "%s/%s", LTT_RELAYFS_ROOT, LTT_CONTROL_FILE);
+
+	channel_flags = RELAY_DELIVERY_PACKET | RELAY_USAGE_GLOBAL;
+	channel_flags |= RELAY_SCHEME_ANY | RELAY_TIMESTAMP_ANY;
+
+	bufsize = 4096;
+	nbufs = 4;
+
+	control = relay_open(relay_file_name,
+			     bufsize,
+			     nbufs,
+			     channel_flags,
+			     &control_callbacks,
+			     0,
+			     0,
+			     0,
+			     0,
+			     0,
+			     0,
+			     NULL,
+			     0);
+
+	return control;
+}
+
+/**
+ *	proc_read_init_ltt - procfs read callback for init attr 
+ */
+static int proc_read_init_ltt(char *page, char **start, off_t off, 
+			      int count, int *eof, void *data)
+{
+	return sprintf(page, "%d", control_channel == -1 ? 0 : 1);
+}
+
+/**
+ *	proc_write_init_ltt - procfs write callback for init attr 
+ */
+static int proc_write_init_ltt(struct file *filp, const char *buffer,
+			       unsigned long count, void *data)
+{
+	if (control_channel == -1) {
+		control_channel = create_control_channel();
+	
+		if (control_channel < 0)
+			printk("LTT control channel creation failed, errcode: %d\n", control_channel);
+		else
+			printk("LTT control channel created\n");
+	}
+
+	return 1;
+}
+
+/**
+ *	remove_control_channel - destroys channel /mnt/relay/ltt/control
+ *
+ *	Returns 0, negative otherwise.
+ */
+static int remove_control_channel(void)
+{
+	if (control_channel != -1)
+		return relay_close(control_channel);
+
+	return -ENODEV;
+}
+
+static int __init init_ltt(void)
+{
+	int i;
+	int err = 0;
+	struct proc_dir_entry *init_entry;
+
+	ltt_proc_root_entry = proc_mkdir("ltt", NULL);
+
+	if (ltt_proc_root_entry == NULL)
+		err = -ENOMEM;
+	else
+		ltt_proc_root_entry->owner = THIS_MODULE;
+
+	control_channel = -1;
+	
+	init_entry = create_proc_entry("init", 0666, ltt_proc_root_entry);
+	if (init_entry == NULL) {
+		err = -ENOMEM;
+		return err;
+	}
+
+	init_entry->read_proc = proc_read_init_ltt;
+	init_entry->write_proc = proc_write_init_ltt;
+	init_entry->owner = THIS_MODULE;
+
+	for (i = 0; i < NR_TRACES; i++)
+		init_trace(&current_traces[i]);
+		
+	return err;
+}
+
+static void __exit exit_ltt(void)
+{
+	remove_proc_entry("init", ltt_proc_root_entry);
+	remove_proc_entry("ltt", NULL);
+
+	remove_control_channel();
+}
+
+module_init(init_ltt)
+module_exit(exit_ltt)
+
+EXPORT_SYMBOL(ltt_set_trace_config);
+EXPORT_SYMBOL(ltt_get_trace_config);
+EXPORT_SYMBOL(ltt_create_event);
+EXPORT_SYMBOL(ltt_create_owned_event);
+EXPORT_SYMBOL(ltt_destroy_event);
+EXPORT_SYMBOL(ltt_destroy_owners_events);
+EXPORT_SYMBOL(ltt_log_std_formatted_event);
+EXPORT_SYMBOL(ltt_log_raw_event);
+EXPORT_SYMBOL(ltt_log_event);
+EXPORT_SYMBOL(syscall_entry_trace_active);
+EXPORT_SYMBOL(syscall_exit_trace_active);
+EXPORT_SYMBOL(ltt_flight_pause);
+EXPORT_SYMBOL(ltt_flight_unpause);
+
+MODULE_AUTHOR("Karim Yaghmour, Tom Zanussi, Bob Wisniewski")
+MODULE_DESCRIPTION("Linux Trace Toolkit kernel core") 
+MODULE_LICENSE("GPL");
diff -uNrp linux-2.6.9/kernel/panic.c linux-2.6.9-ltt-r12/kernel/panic.c
--- linux-2.6.9/kernel/panic.c	2004-10-18 23:55:28.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/panic.c	2005-08-15 10:31:45.000000000 +0200
@@ -61,6 +61,9 @@ NORET_TYPE void panic(const char * fmt, 
 	va_end(args);
 	printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
 	bust_spinlocks(0);
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_dump_state();
+#endif /* CONFIG_ADEOS_CORE */
 
 #ifdef CONFIG_SMP
 	smp_send_stop();
diff -uNrp linux-2.6.9/kernel/printk.c linux-2.6.9-ltt-r12/kernel/printk.c
--- linux-2.6.9/kernel/printk.c	2004-10-18 23:55:35.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/printk.c	2005-08-15 10:31:45.000000000 +0200
@@ -507,6 +507,66 @@ static void zap_locks(void)
  * then changes console_loglevel may break. This is because console_loglevel
  * is inspected when the actual printing occurs.
  */
+#ifdef CONFIG_ADEOS_CORE
+
+static raw_spinlock_t __adeos_printk_lock = RAW_SPIN_LOCK_UNLOCKED;
+
+static int __adeos_printk_fill;
+
+static char __adeos_printk_buf[__LOG_BUF_LEN];
+
+void __adeos_flush_printk (unsigned virq)
+{
+	char *p = __adeos_printk_buf;
+	int out = 0, len;
+
+	clear_bit(ADEOS_PPRINTK_FLAG,&adp_root->flags);
+
+	while (out < __adeos_printk_fill) {
+		len = strlen(p) + 1;
+		printk("%s",p);
+		p += len;
+		out += len;
+	}
+	__adeos_printk_fill = 0;
+}
+
+asmlinkage int printk(const char *fmt, ...)
+{
+	unsigned long flags;
+	int r, fbytes;
+	va_list args;
+
+	va_start(args, fmt);
+
+	if (adp_current == adp_root ||
+	    test_bit(ADEOS_SPRINTK_FLAG,&adp_current->flags) ||
+	    oops_in_progress) {
+		r = vprintk(fmt, args);
+		goto out;
+	}
+
+	spin_lock_irqsave_hw(&__adeos_printk_lock,flags);
+
+	fbytes = __LOG_BUF_LEN - __adeos_printk_fill;
+
+	if (fbytes > 1)	{
+		r = vscnprintf(__adeos_printk_buf + __adeos_printk_fill,
+			       fbytes, fmt, args) + 1; /* account for the null byte */
+		__adeos_printk_fill += r;
+	} else
+		r = 0;
+	
+	spin_unlock_irqrestore_hw(&__adeos_printk_lock,flags);
+
+	if (!test_and_set_bit(ADEOS_PPRINTK_FLAG,&adp_root->flags))
+		adeos_trigger_irq(__adeos_printk_virq);
+out: 
+	va_end(args);
+
+	return r;
+}
+#else /* !CONFIG_ADEOS_CORE */
 asmlinkage int printk(const char *fmt, ...)
 {
 	va_list args;
@@ -518,6 +578,7 @@ asmlinkage int printk(const char *fmt, .
 
 	return r;
 }
+#endif /* CONFIG_ADEOS_CORE */
 
 asmlinkage int vprintk(const char *fmt, va_list args)
 {
diff -uNrp linux-2.6.9/kernel/sched.c linux-2.6.9-ltt-r12/kernel/sched.c
--- linux-2.6.9/kernel/sched.c	2004-10-18 23:54:55.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/sched.c	2005-08-15 11:08:27.000000000 +0200
@@ -43,6 +43,7 @@
 #include <linux/kthread.h>
 #include <linux/seq_file.h>
 #include <linux/times.h>
+#include <linux/ltt-events.h>
 #include <asm/tlb.h>
 
 #include <asm/unistd.h>
@@ -436,7 +437,16 @@ struct sched_domain {
  * Default context-switch locking:
  */
 #ifndef prepare_arch_switch
+#ifdef CONFIG_ADEOS_CORE
+#define prepare_arch_switch(rq,prev,next) \
+do { \
+    struct { struct task_struct *prev, *next; } arg = { (prev), (next) }; \
+    __adeos_schedule_head(&arg); \
+    adeos_hw_cli(); \
+} while(0)
+#else /* !CONFIG_ADEOS_CORE */
 # define prepare_arch_switch(rq, next)	do { } while (0)
+#endif /* CONFIG_ADEOS_CORE */
 # define finish_arch_switch(rq, next)	spin_unlock_irq(&(rq)->lock)
 # define task_running(rq, p)		((rq)->curr == (p))
 #endif
@@ -450,6 +460,8 @@ static runqueue_t *task_rq_lock(task_t *
 {
 	struct runqueue *rq;
 
+	ltt_ev_process(LTT_EV_PROCESS_WAKEUP, p->pid, p->state);
+
 repeat_lock_task:
 	local_irq_save(*flags);
 	rq = task_rq(p);
@@ -1499,6 +1511,10 @@ asmlinkage void schedule_tail(task_t *pr
 
 	if (current->set_child_tid)
 		put_user(current->pid, current->set_child_tid);
+
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_enter_process();
+#endif /* CONFIG_ADEOS_CORE */
 }
 
 /*
@@ -2635,6 +2651,11 @@ asmlinkage void __sched schedule(void)
 	unsigned long run_time;
 	int cpu, idx;
 
+#ifdef CONFIG_ADEOS_CORE
+	if (adp_current != adp_root) /* Let's be helpful and	conservative. */
+	    return;
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*
 	 * Test if we are atomic.  Since do_exit() needs to call into
 	 * schedule() atomically, we ignore that path for now.
@@ -2774,10 +2795,31 @@ switch_tasks:
 		rq->curr = next;
 		++*switch_count;
 
-		prepare_arch_switch(rq, next);
+#ifdef CONFIG_ADEOS_CORE
+		prepare_arch_switch(rq, prev, next);
+#else /* !CONFIG_ADEOS_CORE */
+  		prepare_arch_switch(rq, next);
+#endif /* CONFIG_ADEOS_CORE */
+ 		ltt_ev_schedchange(prev, next);
 		prev = context_switch(rq, prev, next);
 		barrier();
 
+#ifdef CONFIG_ADEOS_CORE
+		if (adp_pipelined)
+		    {
+		    __clear_bit(IPIPE_SYNC_FLAG,&adp_root->cpudata[task_cpu(prev)].status);
+		    adeos_hw_sti();
+		    }
+
+		if (__adeos_schedule_tail(prev) > 0 || adp_current != adp_root)
+		    /* Someone has just recycled the register set of
+		       prev for running over a non-root domain, or
+		       some event handler in the pipeline asked for a
+		       truncated scheduling tail. Don't perform the
+		       Linux housekeeping chores, at least not now. */
+		    return;
+#endif /* CONFIG_ADEOS_CORE */
+
 		finish_task_switch(prev);
 	} else
 		spin_unlock_irq(&rq->lock);
@@ -3246,6 +3288,16 @@ static int setscheduler(pid_t pid, int p
 	if (retval)
 		goto out_unlock;
 
+#ifdef CONFIG_ADEOS_CORE
+	{
+	struct { struct task_struct *task; int policy; struct sched_param *param; } evdata = { p, policy, &lp };
+	if (__adeos_renice_process(&evdata))
+	    {
+	    retval = 0;
+	    goto out_unlock;
+	    }
+	}
+#endif /* CONFIG_ADEOS_CORE */
 	array = p->array;
 	if (array)
 		deactivate_task(p, task_rq(p));
@@ -4767,3 +4819,61 @@ void __might_sleep(char *file, int line)
 }
 EXPORT_SYMBOL(__might_sleep);
 #endif
+
+#ifdef CONFIG_ADEOS_CORE
+
+int __adeos_setscheduler_root (struct task_struct *p, int policy, int prio)
+{
+	prio_array_t *array;
+	unsigned long flags;
+	runqueue_t *rq;
+	int oldprio;
+
+	if (prio < 1 || prio > MAX_RT_PRIO-1)
+	    return -EINVAL;
+
+	read_lock_irq(&tasklist_lock);
+	rq = task_rq_lock(p, &flags);
+	array = p->array;
+	if (array)
+		deactivate_task(p, rq);
+	oldprio = p->prio;
+	__setscheduler(p, policy, prio);
+	if (array) {
+		__activate_task(p, rq);
+		if (task_running(rq, p)) {
+			if (p->prio > oldprio)
+				resched_task(rq->curr);
+		} else if (TASK_PREEMPTS_CURR(p, rq))
+			resched_task(rq->curr);
+	}
+	task_rq_unlock(rq, &flags);
+	read_unlock_irq(&tasklist_lock);
+
+	return 0;
+}
+
+EXPORT_SYMBOL(__adeos_setscheduler_root);
+
+void __adeos_reenter_root (struct task_struct *prev,
+			   int policy,
+			   int prio)
+{
+    	finish_task_switch(prev);
+	reacquire_kernel_lock(current);
+	preempt_enable_no_resched();
+
+	if (current->policy != policy || current->rt_priority != prio)
+	    __adeos_setscheduler_root(current,policy,prio);
+}
+
+EXPORT_SYMBOL(__adeos_reenter_root);
+
+void __adeos_schedule_back_root (struct task_struct *prev)
+{
+    __adeos_reenter_root(prev,current->policy,current->rt_priority);
+}
+
+EXPORT_SYMBOL(__adeos_schedule_back_root);
+
+#endif /* CONFIG_ADEOS_CORE */
diff -uNrp linux-2.6.9/kernel/signal.c linux-2.6.9-ltt-r12/kernel/signal.c
--- linux-2.6.9/kernel/signal.c	2004-10-18 23:53:51.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/signal.c	2005-08-15 10:51:46.000000000 +0200
@@ -21,6 +21,7 @@
 #include <linux/binfmts.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/ltt-events.h>
 #include <asm/param.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -575,6 +576,13 @@ void signal_wake_up(struct task_struct *
 
 	set_tsk_thread_flag(t, TIF_SIGPENDING);
 
+#ifdef CONFIG_ADEOS_CORE
+	{
+	struct { struct task_struct *t; } evdata = { t };
+	__adeos_kick_process(&evdata);
+	}
+#endif /* CONFIG_ADEOS_CORE */
+
 	/*
 	 * If resume is set, we want to wake it up in the TASK_STOPPED case.
 	 * We don't check for TASK_STOPPED because there is a race with it
@@ -828,6 +836,17 @@ specific_send_sig_info(int sig, struct s
 		BUG();
 #endif
 
+#ifdef CONFIG_ADEOS_CORE
+	/* If some domain handler in the pipeline doesn't ask for
+	   propagation, return success pretending that 'sig' was
+	   delivered. */
+	{
+	struct { struct task_struct *task; int sig; } evdata = { t, sig };
+	if (__adeos_signal_process(&evdata))
+	    goto out;
+	}
+#endif /* CONFIG_ADEOS_CORE */
+
 	if (((unsigned long)info > 2) && (info->si_code == SI_TIMER))
 		/*
 		 * Set up a return to indicate that we dropped the signal.
@@ -838,6 +857,8 @@ specific_send_sig_info(int sig, struct s
 	if (sig_ignored(t, sig))
 		goto out;
 
+	ltt_ev_process(LTT_EV_PROCESS_SIGNAL, sig, t->pid);
+
 	/* Support queueing exactly one non-rt signal, so that we
 	   can get more detailed information about the cause of
 	   the signal. */
diff -uNrp linux-2.6.9/kernel/softirq.c linux-2.6.9-ltt-r12/kernel/softirq.c
--- linux-2.6.9/kernel/softirq.c	2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/softirq.c	2005-08-15 10:51:46.000000000 +0200
@@ -16,6 +16,7 @@
 #include <linux/cpu.h>
 #include <linux/kthread.h>
 #include <linux/rcupdate.h>
+#include <linux/ltt-events.h>
 
 #include <asm/irq.h>
 /*
@@ -92,6 +93,7 @@ restart:
 
 	do {
 		if (pending & 1) {
+			ltt_ev_soft_irq(LTT_EV_SOFT_IRQ_SOFT_IRQ, (h - softirq_vec));
 			h->action(h);
 			rcu_bh_qsctr_inc(cpu);
 		}
@@ -242,6 +244,9 @@ static void tasklet_action(struct softir
 			if (!atomic_read(&t->count)) {
 				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
 					BUG();
+
+				ltt_ev_soft_irq(LTT_EV_SOFT_IRQ_TASKLET_ACTION, (unsigned long) (t->func));
+
 				t->func(t->data);
 				tasklet_unlock(t);
 				continue;
@@ -275,6 +280,9 @@ static void tasklet_hi_action(struct sof
 			if (!atomic_read(&t->count)) {
 				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
 					BUG();
+
+				ltt_ev_soft_irq(LTT_EV_SOFT_IRQ_TASKLET_HI_ACTION, (unsigned long) (t->func));
+
 				t->func(t->data);
 				tasklet_unlock(t);
 				continue;
diff -uNrp linux-2.6.9/kernel/sysctl.c linux-2.6.9-ltt-r12/kernel/sysctl.c
--- linux-2.6.9/kernel/sysctl.c	2004-10-18 23:53:13.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/sysctl.c	2005-08-15 10:31:45.000000000 +0200
@@ -928,6 +928,9 @@ void __init sysctl_init(void)
 #ifdef CONFIG_PROC_FS
 	register_proc_table(root_table, proc_sys_root);
 	init_irq_proc();
+#ifdef CONFIG_ADEOS_CORE
+	__adeos_init_proc();
+#endif /* CONFIG_ADEOS_CORE */
 #endif
 }
 
diff -uNrp linux-2.6.9/kernel/time.c linux-2.6.9-ltt-r12/kernel/time.c
--- linux-2.6.9/kernel/time.c	2004-10-18 23:53:43.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/time.c	2005-08-15 10:51:46.000000000 +0200
@@ -31,6 +31,7 @@
 #include <linux/timex.h>
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
+#include <linux/ltt-events.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
diff -uNrp linux-2.6.9/kernel/timer.c linux-2.6.9-ltt-r12/kernel/timer.c
--- linux-2.6.9/kernel/timer.c	2004-10-18 23:54:55.000000000 +0200
+++ linux-2.6.9-ltt-r12/kernel/timer.c	2005-08-15 10:51:46.000000000 +0200
@@ -31,6 +31,7 @@
 #include <linux/time.h>
 #include <linux/jiffies.h>
 #include <linux/cpu.h>
+#include <linux/ltt-events.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -921,6 +922,8 @@ static void run_timer_softirq(struct sof
 {
 	tvec_base_t *base = &__get_cpu_var(tvec_bases);
 
+	ltt_ev(LTT_EV_KERNEL_TIMER, NULL);
+
 	if (time_after_eq(jiffies, base->timer_jiffies))
 		__run_timers(base);
 }
@@ -1084,6 +1087,7 @@ asmlinkage long sys_getegid(void)
 
 static void process_timeout(unsigned long __data)
 {
+	ltt_ev_timer(LTT_EV_TIMER_EXPIRED, 0, 0, 0);
 	wake_up_process((task_t *)__data);
 }
 
diff -uNrp linux-2.6.9/mm/filemap.c linux-2.6.9-ltt-r12/mm/filemap.c
--- linux-2.6.9/mm/filemap.c	2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-ltt-r12/mm/filemap.c	2005-08-15 10:51:46.000000000 +0200
@@ -27,6 +27,7 @@
 #include <linux/pagevec.h>
 #include <linux/blkdev.h>
 #include <linux/security.h>
+#include <linux/ltt-events.h>
 /*
  * This is needed for the following functions:
  *  - try_to_release_page
@@ -415,6 +416,7 @@ void fastcall wait_on_page_bit(struct pa
 	DEFINE_PAGE_WAIT(wait, page, bit_nr);
 
 	do {
+		ltt_ev_memory(LTT_EV_MEMORY_PAGE_WAIT_START, 0);
 		prepare_to_wait(waitqueue, &wait.wait, TASK_UNINTERRUPTIBLE);
 		if (test_bit(bit_nr, &page->flags)) {
 			sync_page(page);
diff -uNrp linux-2.6.9/mm/memory.c linux-2.6.9-ltt-r12/mm/memory.c
--- linux-2.6.9/mm/memory.c	2004-10-18 23:54:07.000000000 +0200
+++ linux-2.6.9-ltt-r12/mm/memory.c	2005-08-15 10:51:46.000000000 +0200
@@ -47,6 +47,9 @@
 #include <linux/module.h>
 #include <linux/init.h>
 
+#include <linux/module.h>
+#include <linux/ltt-events.h>
+
 #include <asm/pgalloc.h>
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
@@ -1330,6 +1333,7 @@ static int do_swap_page(struct mm_struct
 	spin_unlock(&mm->page_table_lock);
 	page = lookup_swap_cache(entry);
 	if (!page) {
+	        ltt_ev_memory(LTT_EV_MEMORY_SWAP_IN, address);
  		swapin_readahead(entry, address, vma);
  		page = read_swap_cache_async(entry, vma, address);
 		if (!page) {
diff -uNrp linux-2.6.9/mm/page_alloc.c linux-2.6.9-ltt-r12/mm/page_alloc.c
--- linux-2.6.9/mm/page_alloc.c	2004-10-18 23:53:11.000000000 +0200
+++ linux-2.6.9-ltt-r12/mm/page_alloc.c	2005-08-15 10:51:46.000000000 +0200
@@ -31,6 +31,7 @@
 #include <linux/topology.h>
 #include <linux/sysctl.h>
 #include <linux/cpu.h>
+#include <linux/ltt-events.h>
 
 #include <asm/tlbflush.h>
 
@@ -275,6 +276,8 @@ void __free_pages_ok(struct page *page, 
 	LIST_HEAD(list);
 	int i;
 
+	ltt_ev_memory(LTT_EV_MEMORY_PAGE_FREE, order);
+
 	arch_free_page(page, order);
 
 	mod_page_state(pgfree, 1 << order);
@@ -749,6 +752,7 @@ fastcall unsigned long __get_free_pages(
 	page = alloc_pages(gfp_mask, order);
 	if (!page)
 		return 0;
+	ltt_ev_memory(LTT_EV_MEMORY_PAGE_ALLOC, order);
 	return (unsigned long) page_address(page);
 }
 
diff -uNrp linux-2.6.9/mm/page_io.c linux-2.6.9-ltt-r12/mm/page_io.c
--- linux-2.6.9/mm/page_io.c	2004-10-18 23:53:21.000000000 +0200
+++ linux-2.6.9-ltt-r12/mm/page_io.c	2005-08-15 10:51:46.000000000 +0200
@@ -17,6 +17,7 @@
 #include <linux/bio.h>
 #include <linux/swapops.h>
 #include <linux/writeback.h>
+#include <linux/ltt-events.h>
 #include <asm/pgtable.h>
 
 static struct bio *get_swap_bio(int gfp_flags, pgoff_t index,
@@ -103,6 +104,7 @@ int swap_writepage(struct page *page, st
 	inc_page_state(pswpout);
 	set_page_writeback(page);
 	unlock_page(page);
+	ltt_ev_memory(LTT_EV_MEMORY_SWAP_OUT, (unsigned long) page);
 	submit_bio(rw, bio);
 out:
 	return ret;
diff -uNrp linux-2.6.9/mm/vmalloc.c linux-2.6.9-ltt-r12/mm/vmalloc.c
--- linux-2.6.9/mm/vmalloc.c	2004-10-18 23:54:32.000000000 +0200
+++ linux-2.6.9-ltt-r12/mm/vmalloc.c	2005-08-15 10:31:45.000000000 +0200
@@ -18,6 +18,9 @@
 
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
+#ifdef CONFIG_ADEOS_CORE
+#include <asm/pgalloc.h>
+#endif /* CONFIG_ADEOS_CORE */
 
 
 rwlock_t vmlist_lock = RW_LOCK_UNLOCKED;
@@ -160,6 +163,9 @@ int map_vm_area(struct vm_struct *area, 
 	dir = pgd_offset_k(address);
 	spin_lock(&init_mm.page_table_lock);
 	do {
+#ifdef CONFIG_ADEOS_CORE
+		pgd_t olddir = *dir;
+#endif /* CONFIG_ADEOS_CORE */
 		pmd_t *pmd = pmd_alloc(&init_mm, dir, address);
 		if (!pmd) {
 			err = -ENOMEM;
@@ -170,6 +176,10 @@ int map_vm_area(struct vm_struct *area, 
 			break;
 		}
 
+#ifdef CONFIG_ADEOS_CORE
+		if (pgd_val(olddir) != pgd_val(*dir))
+			set_pgdir(address, *dir);
+#endif /* CONFIG_ADEOS_CORE */
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
diff -uNrp linux-2.6.9/net/core/dev.c linux-2.6.9-ltt-r12/net/core/dev.c
--- linux-2.6.9/net/core/dev.c	2004-10-18 23:54:08.000000000 +0200
+++ linux-2.6.9-ltt-r12/net/core/dev.c	2005-08-15 10:51:46.000000000 +0200
@@ -107,6 +107,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/netpoll.h>
+#include <linux/ltt-events.h>
 #include <linux/rcupdate.h>
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
@@ -1285,6 +1286,7 @@ int dev_queue_xmit(struct sk_buff *skb)
 	      	if (skb_checksum_help(&skb, 0))
 	      		goto out_kfree_skb;
 
+	ltt_ev_network(LTT_EV_NETWORK_PACKET_OUT, skb->protocol);
 
 	/* Disable soft irqs for various locks below. Also 
 	 * stops preemption for RCU. 
@@ -1734,6 +1736,8 @@ int netif_receive_skb(struct sk_buff *sk
 
 	__get_cpu_var(netdev_rx_stat).total++;
 
+ 	ltt_ev_network(LTT_EV_NETWORK_PACKET_IN, skb->protocol);
+
 	skb->h.raw = skb->nh.raw = skb->data;
 	skb->mac_len = skb->nh.raw - skb->mac.raw;
 
diff -uNrp linux-2.6.9/net/socket.c linux-2.6.9-ltt-r12/net/socket.c
--- linux-2.6.9/net/socket.c	2004-10-18 23:53:50.000000000 +0200
+++ linux-2.6.9-ltt-r12/net/socket.c	2005-08-15 10:51:46.000000000 +0200
@@ -81,6 +81,7 @@
 #include <linux/syscalls.h>
 #include <linux/compat.h>
 #include <linux/kmod.h>
+#include <linux/ltt-events.h>
 
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
@@ -551,6 +552,8 @@ int sock_sendmsg(struct socket *sock, st
 	struct sock_iocb siocb;
 	int ret;
 
+	ltt_ev_socket(LTT_EV_SOCKET_SEND, sock->type, size);
+
 	init_sync_kiocb(&iocb, NULL);
 	iocb.private = &siocb;
 	ret = __sock_sendmsg(&iocb, sock, msg, size);
@@ -603,6 +606,8 @@ int sock_recvmsg(struct socket *sock, st
 	struct sock_iocb siocb;
 	int ret;
 
+	ltt_ev_socket(LTT_EV_SOCKET_RECEIVE, sock->type, size);
+
         init_sync_kiocb(&iocb, NULL);
 	iocb.private = &siocb;
 	ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
@@ -1197,6 +1202,8 @@ asmlinkage long sys_socket(int family, i
 	if (retval < 0)
 		goto out_release;
 
+	ltt_ev_socket(LTT_EV_SOCKET_CREATE, retval, type);
+
 out:
 	/* It may be already another descriptor 8) Not kernel problem. */
 	return retval;
@@ -1916,6 +1923,8 @@ asmlinkage long sys_socketcall(int call,
 		
 	a0=a[0];
 	a1=a[1];
+
+	ltt_ev_socket(LTT_EV_SOCKET_CALL, call, a0);
 	
 	switch(call) 
 	{
