diff -rupN /usr/src/linux-2.4.9/Documentation/Configure.help linux-kgdb/Documentation/Configure.help
--- /usr/src/linux-2.4.9/Documentation/Configure.help	Fri Aug 24 00:12:45 2001
+++ linux-kgdb/Documentation/Configure.help	Sun Aug 26 18:21:41 2001
@@ -2494,6 +2494,13 @@ CONFIG_PCMCIA_SERIAL_CS
   a module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
+Asynchronous I/O support
+CONFIG_AIO
+  Enables support for Posix Asynchronous I/O Facilities. AIO is supported
+  on all filesystems, including those that have enabled Raw I/O
+  (see "Support raw access to SCSI disk devices" under
+  "SCSI support").
+
 /dev/agpgart (AGP Support) (EXPERIMENTAL)
 CONFIG_AGP
   AGP (Accelerated Graphics Port) is a bus system mainly used to
@@ -11725,6 +11732,12 @@ CONFIG_REISERFS_CHECK
   report, say yes and you might get a useful error message.  Almost
   everyone should say no.
 
+CONFIG_REISERFS_RAW
+  Setting this to yes will enable a set of ioctls that provide raw
+  interface to reiserfs tree, bypassing directories, and automatically
+  removing aged files.  This is an experimental feature disigned for
+  squid cache directories. See Documentation/filesystems/reiserfs_raw.txt
+
 Second extended fs support
 CONFIG_EXT2_FS
   This is the de facto standard Linux file system (method to organize
@@ -15753,6 +15766,39 @@ CONFIG_REMOTE_DEBUG
   several megabytes and requires a machine with more than 16 MB,
   better 32 MB RAM to avoid excessive linking time. This is only
   useful for kernel hackers. If unsure, say N.
+
+KGDB: Remote (serial) kernel debugging with gdb
+CONFIG_X86_REMOTE_DEBUG
+  If you say Y here, it will be possible to remotely debug the x86
+  kernel using gdb. This enlarges your kernel image disk size by
+  several megabytes and requires a machine with more than 16 MB,
+  better 32 MB RAM to avoid excessive linking time. 
+  To use this feature you need to perform some basic setup described
+  briefly in Documentation/i386/gdb-serial.txt.
+  This is only useful for kernel hackers. If unsure, say N.
+
+KGDB: Thread analysis
+CONFIG_KGDB_THREAD
+  With thread analysis enabled, gdb can talk to kgdb stub to list
+  threads and to get stack trace for a thread. This option also enables
+  some code which helps gdb get exact status of thread. Thread analysis
+  adds some overhead to schedule and down functions. You can disable this
+  option if you do not want to compromise on speed.
+
+KGDB: Console messagegs through gdb
+CONFIG_GDB_CONSOLE
+  If you say Y here, console messages will appear through gdb.
+  Other consoles such as tty or ttyS will continue to work as usual.
+  
+KGDB: Enable kernel asserts
+CONFIG_KERNEL_ASSERTS
+  This option enables kernel asserts. A kernel assert is a condition,
+  which if turnes out to be false during an execution path, then kgdb
+  is called. Kernel assertions help in modifying the kernel or writing
+  drivers. Bugs can be traced sooner with kernel asserts because invalid
+  conditions caused by bugs are checked at various places. Kernel asserts
+  add the overhead of checking asserted conditions. You can disable this
+  option if you do not want the overhead.
 
 Magic System Request Key support
 CONFIG_MAGIC_SYSRQ
diff -rupN /usr/src/linux-2.4.9/Documentation/i386/gdb-serial.txt linux-kgdb/Documentation/i386/gdb-serial.txt
--- /usr/src/linux-2.4.9/Documentation/i386/gdb-serial.txt	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/Documentation/i386/gdb-serial.txt	Sun Aug 26 18:21:41 2001
@@ -0,0 +1,386 @@
+Version
+=======
+
+This version of the gdbstub package was developed and tested on
+kernel version 2.3.48.  It will not install on a 2.2 kernel.  It may
+not work on earlier versions of 2.3 kernels.  It is possible that
+it will continue to work on later versions of 2.3 and then
+versions of 2.4 (I hope).
+
+
+Debugging Setup
+===============
+
+Designate one machine as the "development" machine.  This is the
+machine on which you run your compiles and which has your source
+code for the kernel.  Designate a second machine as the "target"
+machine.  This is the machine that will run your experimental
+kernel.
+
+The two machines will be connected together via a serial line out
+one or the other of the COM ports of the PC.  You will need a modem
+eliminator and the appropriate cables.
+
+On the DEVELOPMENT machine you need to apply the patch for the gdb
+hooks.  You have probably already done that if you are reading this
+file.
+
+On your DEVELOPMENT machine, go to your kernel source directory and
+do "make menuconfig".  Go down to the kernel hacking menu item and
+open it up.  Enable the kernel gdb stub code by selecting that item.
+
+Save and exit the menuconfig program.  Then do "make clean" and
+"make bzImage" (or whatever target you want to make).  This gets
+the kernel compiled with the "-g" option set -- necessary for
+debugging.
+
+You have just built the kernel on your DEVELOPMENT machine that you
+intend to run on our TARGET machine.
+
+To install this new kernel, use the following installation procedure.
+Remember, you are on the DEVELOPMENT machine patching the kernel source
+for the kernel that you intend to run on the TARGET machine.
+
+Copy this kernel to your target machine using your usual procedures.
+I usually arrange to copy development:/usr/src/linux/arch/i386/boot/zImage
+to /vmlinuz on the TARGET machine via a LAN based NFS access.  That is,
+I run the cp command on the target and copy from the development machine
+via the LAN.  Run Lilo on the new kernel on the target machine so that it
+will boot!  Then boot the kernel on the target machine.
+
+There is an utility program named "gdbstart" in the
+development:/usr/src/linux/arch/i386/kernel directory.
+You should copy this program over to your target machine, probably into
+/sbin.  This utility program is run on the target machine to
+activate the kernel hooks for the debugger.  It is invoked as follows:
+
+    gdbstart [-s speed] [-t tty-dev]
+    defaults:  /dev/ttyS0 with speed unmodified by gdbstart
+
+Don't run the program just yet.  We'll get to that in a bit.
+
+Decide on which tty port you want the machines to communicate, then
+cable them up back-to-back using the null modem.  COM1 is /dev/ttyS0
+and COM2 is /dev/ttyS1.
+
+On the DEVELOPMENT machine, create a file called .gdbinit in the
+directory /usr/src/linux.  An example .gdbinit file looks like this:
+
+define rmt
+set remotebaud 38400
+target remote /dev/ttyS0
+end
+
+Assuming that you added my gdbinit stuff to your .gdbinit, edit .gdbinit
+and find the section that looks like this:
+
+	define rmt
+	set remotebaud 38400
+	target remote /dev/ttyS0
+	end
+
+Change the "target" definition so that it specifies the tty port that
+you intend to use.  Change the "remotebaud" definition to match the
+data rate that you are going to use for the com line.
+
+On the TARGET machine I find it helpful to create shell script file
+named "debug" in the root home directory with the following contents:
+
+	gdbstart -s 38400 -t /dev/ttyS0 <<EOF
+	<blank line>
+	EOF
+
+This runs the gdbstart program and gives it the carriage return that
+it prompts for.  This sets the data rate from the target machine's side.
+
+You are now ready to try it out.
+
+On your TARGET machine, freshly rebooted with your gdbstub-equipped
+kernel, type "debug" in the root home directory.  The system will appear
+to hang with some messages on the screen from the debug stub.  What
+it is doing is waiting for contact from the development machine.
+
+On your DEVELOPMENT machine, cd /usr/src/linux and enter "gdb vmlinux".
+When gdb gets the symbols loaded and prompts you, enter "rmt" (that's
+the macro from the .gdbinit file that you just edited).  If everything
+is working correctly you should see gdb print out a few lines indicating
+that a breakpoint has been taken.  It will actually show a line of
+code in the target kernel inside the gdbstub activation code.
+
+The gdb interaction should look something like this:
+
+    linux-dev:/usr/src/linux# gdb vmlinux
+    GDB is free software and you are welcome to distribute copies of it
+     under certain conditions; type "show copying" to see the conditions.
+    There is absolutely no warranty for GDB; type "show warranty" for details.
+    GDB 4.15.1 (i486-slackware-linux), 
+    Copyright 1995 Free Software Foundation, Inc...
+    (gdb) rmt
+    breakpoint () at i386-stub.c:750
+    750     }
+    (gdb) 
+
+
+You can now use whatever gdb commands you like to set breakpoints.
+Enter "continue" to start your target machine executing again.  At this
+point the target system will run at full speed until it encounters
+your breakpoint or gets a segment violation in the kernel, or whatever.
+
+
+Triggering gdbstub at Kernel Boot Time
+======================================
+
+The gdbstub patch now has the ability for gdb to connect to the kernel during
+bootup (as opposed to waiting for the system to come all the way up and then
+running the gdbstart program on the target machine).  This new functionality was
+added by Scott Foehner <sfoehner@engr.sgi.com> at SGI.
+
+To force a kernel that has been compiled with gdbstub to pause during the boot
+process and wait for a connection from gdb, the paramter "gdb" should be passed
+to the kernel. This can be done by typing "gdb" after the name of the kernel
+on the LILO command line.  The patch defaults to use ttyS1 at a baud rate of
+38400. These parameters can be changed by using "gdbttyS=<port number>" and
+"gdbbaud=<baud rate>" on the command line.
+
+Example:
+
+LILO boot: linux gdb gdbttyS=1 gdbbaud=38400
+
+Note that this command is entered on the TARGET machine as it is booting
+the kernel that was compiled on the DEVELOPMENT machine.
+
+An alternate approach is to place a line in the /etc/lilo.conf file on
+your TARGET machine.  Under the heading for the kernel that you intend
+to boot, place a line that looks like this:
+
+    append = "gdb gdbttyS=1 gdbbaud=38400"
+
+This will cause the kernel to enter the gdbstub automatically at boot
+time.
+
+BE SURE to run "lilo" after changing the /etc/lilo.conf file.
+
+
+The "gdbstart" Program
+=====================
+
+This utility program is used to set up the com port and data rate
+for the connection from the target system to the development system.
+Its usage has been described above.
+
+This version of the patch uses the same tty ioctl for kernel versions
+2.0.30 onwards.  Thus, the gdbstart utility does not need to be re-compiled
+to install the patch in a later version of the kernel.  The ioctl added
+to the kernel for this purpose is far enough "off the end" of existing
+ioctls (as of 2.1.120) that it should not interfere with any new kernel
+tty ioctls for quite some time (famous last words).
+
+The source for the gdbstart program resides in the arch/i386/kernel directory.
+
+
+Debugging hints
+===============
+
+You can break into the target machine at any time from the development
+machine by typing ^C.  If the target machine has interrupts enabled
+this will stop it in the kernel and enter the debugger.
+
+There is unfortunately no way of breaking into the kernel if it is
+in a loop with interrupts disabled, so if this happens to you then
+you need to place exploratory breakpoints or printk's into the kernel
+to find out where it is looping.
+
+There is a copy of an e-mail in the kgdb distribution directory which
+describes how to create an NMI on an ISA bus machine using a paper
+clip.  I have a sophisticated version of this made by wiring a push
+button switch into a PC104/ISA bus adapter card.  The adapter card
+nicely furnishes wire wrap pins for all the ISA bus signals.
+
+When you are done debugging the kernel on the target machine it is
+a good idea to leave it in a running state.  This makes reboots
+faster, bypassing the fsck.  So do a gdb "continue" as the last gdb
+command if this is possible.  To terminate gdb itself on the development
+machine and leave the target machine running, type ^Z to suspend gdb
+and then kill it with "kill %1" or something similar.
+
+If gdbstub Does Not Work
+========================
+
+If it doesn't work, you will have to troubleshoot it.  Do the easy things
+first like double checking your cabling and data rates.  You might
+try some non-kernel based programs to see if the back-to-back connection
+works properly.  Just something simple like cat /etc/hosts >/dev/ttyS0
+on one machine and cat /dev/ttyS0 on the other will tell you if you
+can send data from one machine to the other.  There is no point in tearing
+out your hair in the kernel if the line doesn't work.
+
+All of the real action takes place in the file
+/usr/src/linux/arch/i386/kernel/gdbstub.c.  That is the code on the target
+machine that interacts with gdb on the development machine.  In gdb you can
+turn on a debug switch with the following command:
+
+	set remotedebug
+
+This will print out the protocol messages that gdb is exchanging with
+the target machine.
+
+Another place to look is /usr/src/linux/drivers/char/gdbserial.c
+That is the code that talks to the serial port on the target side.
+There might be a problem there.
+
+If you are really desperate you can use printk debugging in the
+gdbstub code in the target kernel until you get it working.  In particular,
+there is a global variable in /usr/src/linux/arch/i386/kernel/gdbstub.c
+named "remote_debug".  Compile your kernel with this set to 1, rather
+than 0 and the debug stub will print out lots of stuff as it does
+what it does.
+
+
+Debugging Loadable Modules
+==========================
+
+This technique comes courtesy of Edouard Parmelan
+<Edouard.Parmelan@quadratec.fr>
+
+When you run gdb, enter the command
+
+source gdbinit-modules
+
+This will read in a file of gdb macros that was installed in your
+kernel source directory with kgdb was installed.  This file implements
+the following commands:
+
+mod-list
+    Lists the loaded modules in the form <module-address> <module-name>
+
+mod-print-symbols <module-address>
+    Prints all the symbols in the indicated module.
+
+mod-add-symbols <module-address> <object-file-path-name>
+    Loads the symbols from the object file and associates them
+    with the indicated module.
+
+After you have loaded the module that you want to debug, use the command
+mod-list to find the <module-address> of your module.  Then use that
+address in the mod-add-symbols command to load your module's symbols.
+From that point onward you can debug your module as if it were a part
+of the kernel.
+
+The file gdbinit-modules also contains a command named mod-add-lis as
+an example of how to construct a command of your own to load your
+favorite module.  The idea is to "can" the pathname of the module
+in the command so you don't have to type so much.
+
+Threads
+=======
+
+Each process in a target machine is seen as a gdb thread. gdb thread related
+commands (info threads, thread n) can be used. 
+
+ia-32 hardware breakpoints
+==========================
+
+gdb stub contains support for hardware breakpoints using debugging features
+of ia-32(x86) processors. These breakpoints do not need code modification.
+They use debugging registers. 4 hardware breakpoints are available in ia-32
+processors.
+
+Each hardware breakpoint can be of one of the following three types.
+1. Execution breakpoint - An Execution breakpoint is triggered when code at the
+	breakpoint address is executed.
+
+	As limited number of hardware breakpoints are available, it is advisable
+	to use software breakpoints ( break command ) instead of execution
+	hardware breakpoints, unless modification of code is to be avoided.
+
+2. Write breakpoint - A write breakpoint is triggered when memory location at the
+	breakpoint address is written.
+
+	A write or can be placed for data of variable length. Length of a write
+	breakpoint indicates length of the datatype to be watched. Length is 1
+	for 1 byte data , 2 for 2 byte data, 3 for 4 byte data.
+
+3. Access breakpoint - An access breakpoint is triggered when memory location at
+	the breakpoint address is either read or written.
+
+	Access breakpoints also have lengths similar to write breakpoints.
+
+IO breakpoints in ia-32 are not supported.
+
+Since gdb stub at present does not use the protocol used by gdb for hardware
+breakpoints, hardware breakpoints are accessed through gdb macros. gdb macros
+for hardware breakpoints are described below.
+
+hwebrk	- Places an execution breakpoint
+	hwebrk breakpointno address
+hwwbrk	- Places a write breakpoint
+	hwwbrk breakpointno length address
+hwabrk	- Places an access breakpoint
+	hwabrk breakpointno length address
+hwrmbrk	- Removes a breakpoint
+	hwrmbrk breakpointno
+exinfo	- Tells whether a software or hardware breakpoint has occured.
+	Prints number of the hardware breakpoint if a hardware breakpoint has
+	occured.
+
+Arguments required by these commands are as follows
+breakpointno	- 0 to 3
+length		- 1 to 3
+address		- Memory location in hex digits ( without 0x ) e.g c015e9bc
+
+MP support
+==========
+
+When a breakpoint occurs or user issues a break ( Ctrl + C ) to gdb client,
+all the processors are forced to enter the debugger. Current thread
+corresponds to the thread running on the processor where breakpoint occured.
+Threads running on other processor(s) appear similar to other non running
+threads in the 'info threads' output.
+
+ia-32 hardware debugging registers on all processors are set to same values.
+Hence any hardware breakpoints may occur on any processor.
+
+gdb troubleshooting
+===================
+
+1. gdb hangs
+Kill it. restart gdb. Connect to target machine.
+
+2. gdb cannot connect to target machine (after killing a gdb and restarting
+another)
+If the target machine was not inside debugger when you killed gdb, gdb cannot
+connect because the target machine won't respond.
+In this case echo "Ctrl+C"(ascii 3) in the serial line.
+e.g. echo -e "\003" > /dev/ttyS1 
+This forces that target machine into debugger after which you can connect.
+
+3. gdb cannot connect even after echoing Ctrl+C into serial line
+Try changing serial line settings min to 1 and time to 0
+e.g. stty min 1 time 0 < /dev/ttyS1
+Try echoing again
+
+check serial line speed and set it to correct value if required
+e.g. stty ispeed 115200 ospeed 115200 < /dev/ttyS1
+
+Final Items
+===========
+
+I picked up this code from Dave Grothe and enhanced it.
+
+If you make some really cool modification to this stuff, or if you 
+fix a bug, please let me know.
+
+Amit S. Kale
+<akale@veritas.com>
+
+(First kgdb by David Grothe <dave@gcom.com>)
+
+(modified by Tigran Aivazian <tigran@sco.com>)
+    Putting gdbstub into the kernel config menu.
+
+(modified by Scott Foehner <sfoehner@engr.sgi.com>)
+    Hooks for entering gdbstub at boot time.
+
+(modified by Amit S. Kale <akale@veritas.com>)
+    Threads, ia-32 hw debugging, mp support, console support,
+    nmi watchdog handling.
diff -rupN /usr/src/linux-2.4.9/Documentation/reiserfs-raw.txt linux-kgdb/Documentation/reiserfs-raw.txt
--- /usr/src/linux-2.4.9/Documentation/reiserfs-raw.txt	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/Documentation/reiserfs-raw.txt	Sat Aug 25 17:14:13 2001
@@ -0,0 +1,205 @@
+
+Here is a quick intoduction to REISERFS-RAW.
+
+$Revision: 1.1.2.3 $
+$Date: 2000/11/08 05:46:45 $
+
+
+1. What it is?
+~~~~~~~~~~~~~~
+
+Reiserfs-raw is a "raw" interface to reiserfs.  Its purpose is to gain
+speed and ease of implementation for some applications, notably the
+Squid Internet Object Cache (http://www.squid-cache.org).  (The squid
+version that uses reiserfs-raw can be found at squidng.sourceforge.net,
+see also http://www.swelltech.com/pengies/joe/squidng.html and
+ftp://ftp.botik.ru/pub/local/sizif/squid).
+
+In reiserfs-raw view, files on the disk are named by 64-bit numbers.
+There are no directories, so you cannot structure the namespace.  (For
+now, you cannot even read the list of files on the disk.)  On the
+other hand, there is no directory overhead and there's less locking in
+the kernel on file creation/deletion.
+
+Another feature of reiserfs-raw is its support for file aging and
+removal.  Reiserfs-raw keeps track of file age distrubution, and keeps
+disk usage within specified bounds by removing the files older than
+certain age when disk space becomes tight.  This critical age is
+termed "age threshold".
+
+We use a file removal technique that we call Passive Garbage
+Collection (PGC).  It is "passive" because it never scans the disk
+looking for aged files; instead, it monitors filesystem meta-data that
+filesystem code examines as part of its normal operation, and removes
+the files that are both aged and convenient to remove at the moment.
+The file age distribution is maintained in the form of "class LRU" table.
+You can see its current state in /proc/fs/reiserfs/DEVICE/age_class.
+See include/linux/age_class.h for further info.
+
+** WARNING: Reiserfs-raw is an experimental feature, not conforming to
+** any standards.  The description below simply describes the current
+** implementation, not a proposed standard.  Both implementation and
+** interface may well be changed in the future.  So if you use it, be
+** prepared to rewrite your application code on upgrade.
+
+** SECURITY WARNING: Reiserfs_raw has working but unusual security
+** model.  Please see the section "Access permissions" below to make
+** sure you understand the security model right and don't compromise
+** security of your system by using reiserfs_raw improperly.
+
+
+
+2. Syscalls and data structures
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+/* For those who prefer studying examples, not specifications: you can
+   use the test program fs/reiserfs/utils/test-raw/raw.c as an example
+   application code. */
+
+The interface is implemented as a set of ioctls.  The file descriptor
+that the ioctls are applied to should be obtained from open(2) of the
+root firectory of the reiserfs-raw filesystem, like this:
+
+    int dir = open ("/cache1", O_RDONLY);
+
+The following structure is used as argument for all reiserfs-raw
+ioctls:
+
+struct reiserfs_raw_ioctl_arg {
+    __u32  id1;         /* object id of the obj to operate on (low part) */
+    __u32  id2;         /* object id of the obj to operate on (high part) */
+    __u32  lastref;     /* last reference date (a la atime) */
+    __u32  expires;     /* expiration date */
+    __u32  user1;       /* user attribute, not used by the kernel */
+    loff_t size;        /* file size returned by RAWOPEN */
+};
+
+The 'id1' and 'id2' together form the 64-bit numeric id (the filename
+equivalent) to operate on.
+
+The 'lastref' field is used by PGC.  It is similar in spirit to atime,
+but is only affected by CREAT and OPEN, not by read and write.  Also,
+it is set not to current time but to some coarse-grained derivation of
+it; this reduces the need for lastref updates when you frequently
+access one file.
+
+The 'expires' field is set by the user to order file removal by PGC
+after the current time gets beyond the expiration date.  To expiration
+is not desired, be careful set it to end-of-epoch (~0) in CREAT and
+SETATTR operations.
+
+The 'user1' field is an opaque (for the kernel) attribute set in CREAT
+and SETATTR and retreived by OPEN.  Application may use it at will.
+
+The 'size' field is the file size.  It is only valid upon return from
+OPEN operation.  We could get the size using fstat(2) on the file
+descriptor returned by OPEN, so it's there only to save us the
+overhead of an extra fstat(2) syscall.
+
+
+Now to the syscalls.
+
+fd = ioctl (dir, REISERFS_IOC_RAWCREAT, &raw_ioctl_arg);
+
+Creates raw file with the id and attributes specified in
+&raw_ioctl_arg, and returns descriptor of the file open for
+read/write.  Returns EEXIST if the file id1:id2 already exists.
+
+fd = ioctl (dir, REISERFS_IOC_RAWOPEN, &raw_ioctl_arg);
+
+Opens raw file with the id specified in &raw_ioctl_arg, and returns
+descriptor of the file open for read/write.  The attribute fields in
+&raw_ioctl_arg are filled actual file's attributes.
+
+error = ioctl (dir, REISERFS_IOC_RAWUNLINK, &raw_ioctl_arg);
+
+Removes the file with the id specified in &raw_ioctl_arg.
+
+fd = ioctl (dir, REISERFS_IOC_RAWSETATTR, &raw_ioctl_arg);
+fd = ioctl (fd, REISERFS_IOC_RAWSETATTR, &raw_ioctl_arg);
+
+Setts attributes of the raw file with the id specified in
+raw_ioctl_arg, and fills raw_ioctl_arg with old file's attributes.
+
+This ioctl can as well be applied to file discriptor of an open raw
+file, in which case that file's attribues are set, the id in
+raw_ioctl_arg is not used.
+
+That's all new syscalls.  You get file descriptor, and can apply
+normal syscalls to them: read/write/sendfile/lseek,
+fstat/fchown/fchmod, whatever.
+
+
+3. Access permissions
+~~~~~~~~~~~~~~~~~~~~~
+
+The reiserfs-raw syscalls do not work unless you mount the
+filesystem with -o raw (see the "Mount flags" section below).
+
+The permission to create or open files on a reiserfs-raw disk is
+governed by the ownership and premission bits of the root directory of
+the reiserfs-raw filesystem (O_WRITE is requered for CREAT, O_EXEC for
+OPEN).  Permission bits and ownership of the files proper are
+_IGNORED_ (yes, IGNORED) by the reiserfs_raw interface, for speed.
+
+UNLINK permission is also governed by the mode of the root directory
+of the raw filesystem.  However, UNLINK operation fill refuse to
+remove a non-raw file (a file that wasn't created using RAWCREAT),
+because doing so would damage the filesystem structure.
+
+Security clarification:
+
+1) The simplified security model described in this section only
+applies to filesystems mounted with -o raw.  Filesystems mounted
+without -o raw behave as usual, and are safe from this all.
+
+2) If you mount a filesystem with -o raw, and you have O_EXEC access
+to the root directory of the filesystem, you can open *ANY* file on
+this filesystem, regardless of access permissions of the file.  So, to
+protect the files on reiserfs_raw partition from users, put
+restrictive mode on the root directory of the filesystem.  Example:
+
+  mkreiserfs /dev/sdb1
+  mount -o raw /dev/sdb1 /cache
+  chmod 700 /cache
+  chown squid /cache
+
+3) Reiserfs_raw is secure if used right.  Rule of thumb: don't have
+any regular (named) files on raw partitions, don't mount regular
+partitions with -o raw, chose ownership & permission of the root
+directory of the raw filesystem properly, and you are safe.
+
+
+4. Mount flags
+~~~~~~~~~~~~~~
+
+The raw reiserfs is not a valid filesystem from the viewpoint of
+reiserfsck.  Therefore, to avoid messing up "normal" reiserfs disks,
+the reiserfs-raw interface will work with a disk only if you mount the
+disk with -o raw.
+
+To specify the desired disk usage limit that PGC will try to maintain,
+use the -o pgc=L,H mount option.  L and H are lower and upper
+thresholds in per cents, 0 < L <= H <= 100.  PGC does nothing until
+disk usage reaches L.  When disk usage reaches L, PGC starts mildly
+removing most aged files, and stops when disk usage falls below L.  If
+mild removal doesn't help and disk usage continues growing, PGC sets
+threshold more and more aggressively as disk usage approaches H, the
+goal being to keep disk usage below H at any price.
+
+Example mount command:
+
+mount -t reiserfs -onotail,noatime,raw,pgc=50,70 /dev/sdb1 /cache1
+
+
+5. Credits
+~~~~~~~~~~
+
+The original idea of the raw resierfs interface comes from Nikita
+Danilov <nikitadanilov@yahoo.com>.  PGC has been proposed by Yury
+Shevchuk <sizif@botik.ru> and prototyped by Nikita Danilov.  The
+complete code of reiserfs-raw+PGC has been written by Yury Shevchuk.
+
+The work has been done as a part of the ReiserFS project led by Hans
+Reiser <hans@reiser.to>, under the sponsorship from Intergrated Linux
+(http://www.integratedlinux.com).  Thanks!
diff -rupN /usr/src/linux-2.4.9/Makefile linux-kgdb/Makefile
--- /usr/src/linux-2.4.9/Makefile	Fri Aug 24 00:12:45 2001
+++ linux-kgdb/Makefile	Sun Aug 26 18:23:43 2001
@@ -88,7 +88,12 @@ export MODLIB
 CPPFLAGS := -D__KERNEL__ -I$(HPATH)
 
 CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
-	  -fomit-frame-pointer -fno-strict-aliasing -fno-common
+	  -fno-strict-aliasing -fno-common
+ifeq ($(CONFIG_X86_REMOTE_DEBUG),y)
+CFLAGS += -g
+else
+CFLAGS += -fomit-frame-pointer
+endif
 AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
 
 #
diff -rupN /usr/src/linux-2.4.9/arch/i386/Makefile linux-kgdb/arch/i386/Makefile
--- /usr/src/linux-2.4.9/arch/i386/Makefile	Thu Apr 12 22:20:31 2001
+++ linux-kgdb/arch/i386/Makefile	Sun Aug 26 18:21:41 2001
@@ -105,6 +105,11 @@ arch/i386/mm: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/i386/mm
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+ifeq ($(CONFIG_X86_REMOTE_DEBUG),y)
+CLEANKERNEL = $(MAKE) -C arch/$(ARCH)/kernel kernelclean
+else
+CLEANKERNEL =
+endif
 
 vmlinux: arch/i386/vmlinux.lds
 
@@ -140,6 +145,7 @@ install: vmlinux
 
 archclean:
 	@$(MAKEBOOT) clean
+	@$(CLEANKERNEL)
 
 archmrproper:
 
diff -rupN /usr/src/linux-2.4.9/arch/i386/config.in linux-kgdb/arch/i386/config.in
--- /usr/src/linux-2.4.9/arch/i386/config.in	Sat Jul 21 20:20:34 2001
+++ linux-kgdb/arch/i386/config.in	Sun Aug 26 18:21:41 2001
@@ -185,6 +185,11 @@ endmenu
 mainmenu_option next_comment
 comment 'General setup'
 
+bool 'Asynchronous I/O support' CONFIG_AIO
+if [ "$CONFIG_AIO" = "y" ]; then
+	int  'System-wide limit on outstanding I/Os' CONFIG_AIO_MAX 4096
+fi
+
 bool 'Networking support' CONFIG_NET
 bool 'SGI Visual Workstation support' CONFIG_VISWS
 if [ "$CONFIG_VISWS" = "y" ]; then
@@ -390,4 +395,10 @@ comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'KGDB: Remote (serial) kernel debugging with gdb' CONFIG_X86_REMOTE_DEBUG
+if [ "$CONFIG_X86_REMOTE_DEBUG" != "n" ]; then
+	bool 'KGDB: Thread analysis' CONFIG_KGDB_THREAD
+	bool 'KGDB: Console messages through gdb' CONFIG_GDB_CONSOLE
+	bool 'KGDB: Enable kernel asserts' CONFIG_KERNEL_ASSERTS
+fi
 endmenu
diff -rupN /usr/src/linux-2.4.9/arch/i386/kernel/Makefile linux-kgdb/arch/i386/kernel/Makefile
--- /usr/src/linux-2.4.9/arch/i386/kernel/Makefile	Sat Dec 30 00:35:47 2000
+++ linux-kgdb/arch/i386/kernel/Makefile	Sun Aug 26 18:21:41 2001
@@ -10,7 +10,15 @@
 .S.o:
 	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
 
-all: kernel.o head.o init_task.o
+ifeq ($(CONFIG_X86_REMOTE_DEBUG),y)
+GDBSTART=gdbstart
+GDBCLEAN= -rm -f gdbstart /sbin/gdbstart
+else
+GDBSTART=
+GDBCLEAN=
+endif
+
+all: kernel.o head.o init_task.o $(GDBSTART)
 
 O_TARGET := kernel.o
 
@@ -31,6 +39,7 @@ endif
 endif
 
 obj-$(CONFIG_MCA)	+= mca.o
+obj-$(CONFIG_X86_REMOTE_DEBUG) += gdbstub.o
 obj-$(CONFIG_MTRR)	+= mtrr.o
 obj-$(CONFIG_X86_MSR)	+= msr.o
 obj-$(CONFIG_X86_CPUID)	+= cpuid.o
@@ -40,5 +49,10 @@ obj-$(CONFIG_SMP)	+= smp.o smpboot.o tra
 obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o mpparse.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
+
+gdbstart:	gdbstart.o
+		${HOSTCC} -o gdbstart gdbstart.o
+
+kernelclean:	dummy
 
 include $(TOPDIR)/Rules.make
diff -rupN /usr/src/linux-2.4.9/arch/i386/kernel/entry.S linux-kgdb/arch/i386/kernel/entry.S
--- /usr/src/linux-2.4.9/arch/i386/kernel/entry.S	Sat Jul 21 20:19:26 2001
+++ linux-kgdb/arch/i386/kernel/entry.S	Sun Aug 26 18:21:41 2001
@@ -257,7 +257,7 @@ ret_from_exception:
 
 	ALIGN
 reschedule:
-	call SYMBOL_NAME(schedule)    # test
+	call SYMBOL_NAME(user_schedule)    # test
 	jmp ret_from_sys_call
 
 ENTRY(divide_error)
@@ -395,6 +395,31 @@ ENTRY(spurious_interrupt_bug)
 	pushl $ SYMBOL_NAME(do_spurious_interrupt_bug)
 	jmp error_code
 
+#ifdef CONFIG_KGDB_THREAD
+ENTRY(kern_schedule)
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ss		
+	pushl	%ebp
+	pushfl
+	pushl	%cs
+	pushl	4(%ebp)
+	pushl	%eax		
+	pushl	%es
+	pushl	%ds
+	pushl	%eax
+	pushl	(%ebp)
+	pushl	%edi
+	pushl	%esi
+	pushl	%edx
+	pushl	%ecx
+	pushl	%ebx
+	call	kern_do_schedule
+	movl	%ebp, %esp
+	pop	%ebp
+	ret
+#endif
+
 .data
 ENTRY(sys_call_table)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 0  -  old "setup()" system call*/
@@ -620,6 +645,39 @@ ENTRY(sys_call_table)
 	.long SYMBOL_NAME(sys_getdents64)	/* 220 */
 	.long SYMBOL_NAME(sys_fcntl64)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for TUX */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 225 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 230 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 235 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 245 */
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* 250 */
+#if defined(CONFIG_AIO)
+	.long SYMBOL_NAME(sys_aio)		/* 251 */
+#else
+	.long SYMBOL_NAME(sys_ni_syscall)
+#endif
 
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
Binary files /usr/src/linux-2.4.9/arch/i386/kernel/gdbstart and linux-kgdb/arch/i386/kernel/gdbstart differ
diff -rupN /usr/src/linux-2.4.9/arch/i386/kernel/gdbstart.c linux-kgdb/arch/i386/kernel/gdbstart.c
--- /usr/src/linux-2.4.9/arch/i386/kernel/gdbstart.c	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/arch/i386/kernel/gdbstart.c	Sun Aug 26 18:21:41 2001
@@ -0,0 +1,146 @@
+/*
+ * This program opens a tty file and issues the GDB stub activating
+ * ioctl on it.
+ */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <asm/ioctls.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+
+char		*tty_name = "/dev/ttyS0" ;	/* COM1 port */
+int		 speed = 9600 ;			/* default speed */
+struct termios	 save_ts ;			/* original term struct */
+
+void print_usage(void)
+{
+    printf("gdbstub [-s speed] [-t tty-dev]\n") ;
+    printf("  defaults:  /dev/ttyS0 with speed unmodified by this program\n");
+
+} /* print_usage */
+
+void tty_err(char *msg)
+{
+    char	buf[100] ;
+
+    strcpy(buf, msg) ;
+    strcat(buf, ": ") ;
+    strcat(buf, tty_name) ;
+    perror(buf) ;
+    exit(1) ;
+
+} /* tty_err */
+
+
+void setup_term(int fd)
+{
+    struct termios	ts ;
+    int			speed_code ;
+
+    if (tcgetattr(fd, &ts) < 0) tty_err("tcgetattr") ;
+
+    save_ts = ts ;
+    switch (speed)
+    {
+    case 4800:
+	speed_code = B4800 ;
+	break ;
+    case 9600:
+	speed_code = B9600 ;
+	break ;
+    case 19200:
+	speed_code = B19200 ;
+	break ;
+    case 38400:
+	speed_code = B38400 ;
+	break ;
+    case 57600:
+	speed_code = B57600 ;
+	break ;
+    case 115200:
+	speed_code = B115200 ;
+	break ;
+    case 230400:
+	speed_code = B230400 ;
+	break ;
+    default:
+	printf("Invalid speed: %d\n", speed) ;
+	exit(1) ;
+    }
+
+    ts.c_cflag = CS8 | CREAD | CLOCAL ;
+    if (cfsetospeed(&ts, speed_code) < 0) tty_err("cfsetospeed") ;
+    if (cfsetispeed(&ts, speed_code) < 0) tty_err("cfsetispeed") ;
+
+    if (tcsetattr(fd, TCSANOW, &ts) < 0) tty_err("tcsetattr") ;
+
+} /* setup_term */
+
+void main(int argc, char **argv)
+{
+    int		opt ;
+    int		fil ;
+    int		rslt ;
+
+    while ((opt = getopt(argc, argv, "hs:t:")) > 0)
+    {
+	switch (opt)
+	{
+	case 's':
+	    speed = atol(optarg) ;
+	    break ;
+	case 't':
+	    tty_name = optarg ;
+	    break ;
+	case ':':
+	    printf("Invalid option\n") ;
+	    break ;
+	case '?':
+	case 'h':
+	default:
+	    print_usage() ;
+	    return ;
+	}
+    }
+
+    fil = open(tty_name, O_RDWR) ;
+    if (fil < 0)
+    {
+	perror(tty_name) ;
+	return ;
+    }
+
+
+    setup_term(fil) ;
+
+    /*
+     * When we issue this ioctl, control will not return until
+     * the debugger running on the remote host machine says "go".
+     */
+    printf("\nAbout to activate GDB stub in the kernel on %s\n", tty_name) ;
+    printf("Hit CR to continue, kill program to abort -- ") ;
+    getchar() ;
+    sync() ;
+    rslt = ioctl(fil, TIOCGDB, 0) ;
+    if (rslt < 0)
+    {
+	perror("TIOCGDB ioctl") ;
+	return ;
+    }
+
+    printf("\nGDB stub successfully activated\n") ;
+
+    for (;;)
+    {
+	pause() ;
+    }
+
+    if (tcsetattr(fil, TCSANOW, &save_ts) < 0) tty_err("tcsetattr") ;
+
+} /* main */
diff -rupN /usr/src/linux-2.4.9/arch/i386/kernel/gdbstub.c linux-kgdb/arch/i386/kernel/gdbstub.c
--- /usr/src/linux-2.4.9/arch/i386/kernel/gdbstub.c	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/arch/i386/kernel/gdbstub.c	Sun Aug 26 18:21:41 2001
@@ -0,0 +1,1218 @@
+/*
+ *
+ * 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, 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.
+ *
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ */
+/****************************************************************************
+ *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ *  Module name: remcom.c $
+ *  Revision: 1.34 $
+ *  Date: 91/03/09 12:29:49 $
+ *  Contributor:     Lake Stevens Instrument Division$
+ *
+ *  Description:     low level support for gdb debugger. $
+ *
+ *  Considerations:  only works on target hardware $
+ *
+ *  Written by:      Glenn Engel $
+ *  Updated by:	     Amit Kale<akale@veritas.com>
+ *  ModuleState:     Experimental $
+ *
+ *  NOTES:           See Below $
+ *
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ *  Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com>
+ *      thread support,
+ *      support for multiple processors,
+ *  	support for ia-32(x86) hardware debugging,
+ *  	Console support,
+ *  	handling nmi watchdog
+ *  	Amit S. Kale ( akale@veritas.com )
+ *
+ *
+ *  To enable debugger support, two things need to happen.  One, a
+ *  call to set_debug_traps() is necessary in order to allow any breakpoints
+ *  or error conditions to be properly intercepted and reported to gdb.
+ *  Two, a breakpoint needs to be generated to begin communication.  This
+ *  is most easily accomplished by a call to breakpoint().  Breakpoint()
+ *  simulates a breakpoint by executing an int 3.
+ *
+ *************
+ *
+ *    The following gdb commands are supported:
+ *
+ * command          function                               Return value
+ *
+ *    g             return the value of the CPU registers  hex data or ENN
+ *    G             set the value of the CPU registers     OK or ENN
+ *
+ *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
+ *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
+ *
+ *    c             Resume at current address              SNN   ( signal NN)
+ *    cAA..AA       Continue at address AA..AA             SNN
+ *
+ *    s             Step one instruction                   SNN
+ *    sAA..AA       Step one instruction from AA..AA       SNN
+ *
+ *    k             kill
+ *
+ *    ?             What was the last sigval ?             SNN   (signal NN)
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum.  A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer.  '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host:                  Reply:
+ * $m0,10#2a               +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/vm86.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>			/* for linux pt_regs struct */
+#include <linux/gdb.h>
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/console.h>
+#endif
+#include <linux/init.h>
+
+/************************************************************************
+ *
+ * external low-level support routines
+ */
+typedef void (*Function)(void);           /* pointer to a function */
+
+/* Thread reference */
+typedef unsigned char threadref[8];
+
+extern int putDebugChar(int);   /* write a single character      */
+extern int getDebugChar(void);   /* read and return a single char */
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 1024
+
+static char initialized;  /* boolean flag. != 0 means we've been initialized */
+
+static const char hexchars[]="0123456789abcdef";
+
+/* Number of bytes of registers.  */
+#define NUMREGBYTES 64
+/*
+ * Note that this register image is in a different order than
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ * Just why GDB uses a different order is a historical mystery.
+ */
+enum regnames {_EAX,		/* 0 */
+	       _ECX,		/* 1 */
+	       _EDX,		/* 2 */
+	       _EBX,		/* 3 */
+	       _ESP,		/* 4 */
+	       _EBP,		/* 5 */
+	       _ESI,		/* 6 */
+	       _EDI,		/* 7 */
+	       _PC 		/* 8 also known as eip */,
+	       _PS		/* 9 also known as eflags */,
+	       _CS,		/* 10 */
+	       _SS,		/* 11 */
+	       _DS,		/* 12 */
+	       _ES,		/* 13 */
+	       _FS,		/* 14 */
+	       _GS};		/* 15 */
+
+
+
+/***************************  ASSEMBLY CODE MACROS *************************/
+/* 									   */
+
+#define BREAKPOINT() asm("   int $3");
+
+/* Put the error code here just in case the user cares.  */
+int gdb_i386errcode;
+/* Likewise, the vector number here (since GDB only gets the signal
+   number through the usual means, and that's not very specific).  */
+int gdb_i386vector = -1;
+
+static spinlock_t slavecpulocks[KGDB_MAX_NO_CPUS];
+volatile int procindebug[KGDB_MAX_NO_CPUS];
+
+#ifdef CONFIG_SMP
+spinlock_t kgdb_spinlock = SPIN_LOCK_UNLOCKED;
+spinlock_t kgdb_nmispinlock = SPIN_LOCK_UNLOCKED;
+#else 
+unsigned kgdb_spinlock = 0;
+unsigned kgdb_nmispinlock = 0;
+#endif
+
+static void kgdb_usercode (void)
+{
+}
+
+int hex(char ch)
+{
+  if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
+  if ((ch >= '0') && (ch <= '9')) return (ch-'0');
+  if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
+  return (-1);
+}
+
+
+/* scan for the sequence $<data>#<checksum>     */
+void getpacket(char * buffer)
+{
+  unsigned char checksum;
+  unsigned char xmitcsum;
+  int  i;
+  int  count;
+  char ch;
+
+  do {
+    /* wait around for the start character, ignore all other characters */
+    while ((ch = (getDebugChar() & 0x7f)) != '$');
+    checksum = 0;
+    xmitcsum = -1;
+
+    count = 0;
+
+    /* now, read until a # or end of buffer is found */
+    while (count < BUFMAX) {
+      ch = getDebugChar() & 0x7f;
+      if (ch == '#') break;
+      checksum = checksum + ch;
+      buffer[count] = ch;
+      count = count + 1;
+      }
+    buffer[count] = 0;
+
+    if (ch == '#') {
+      xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+      xmitcsum += hex(getDebugChar() & 0x7f);
+
+      if (checksum != xmitcsum) putDebugChar('-');  /* failed checksum */
+      else {
+	 putDebugChar('+');  /* successful transfer */
+	 /* if a sequence char is present, reply the sequence ID */
+	 if (buffer[2] == ':') {
+	    putDebugChar( buffer[0] );
+	    putDebugChar( buffer[1] );
+	    /* remove sequence chars from buffer */
+	    count = strlen(buffer);
+	    for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
+	 }
+      }
+    }
+  } while (checksum != xmitcsum);
+
+}
+
+/* send the packet in buffer.  */
+
+
+void putpacket(char * buffer)
+{
+  unsigned char checksum;
+  int  count;
+  char ch;
+
+  /*  $<packet info>#<checksum>. */
+  do {
+  putDebugChar('$');
+  checksum = 0;
+  count    = 0;
+
+  while ((ch=buffer[count])) {
+    if (! putDebugChar(ch)) return;
+    checksum += ch;
+    count += 1;
+  }
+
+  putDebugChar('#');
+  putDebugChar(hexchars[checksum >> 4]);
+  putDebugChar(hexchars[checksum % 16]);
+
+  } while ((getDebugChar() & 0x7f) != '+');
+
+}
+
+static char  remcomInBuffer[BUFMAX];
+static char  remcomOutBuffer[BUFMAX];
+static short error;
+
+static void regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs)
+{
+    gdb_regs[_EAX] =  regs->eax;
+    gdb_regs[_EBX] =  regs->ebx;
+    gdb_regs[_ECX] =  regs->ecx;
+    gdb_regs[_EDX] =  regs->edx;
+    gdb_regs[_ESI] =  regs->esi;
+    gdb_regs[_EDI] =  regs->edi;
+    gdb_regs[_EBP] =  regs->ebp;
+    gdb_regs[ _DS] =  regs->xds;
+    gdb_regs[ _ES] =  regs->xes;
+    gdb_regs[ _PS] =  regs->eflags;
+    gdb_regs[ _CS] =  regs->xcs;
+    gdb_regs[ _PC] =  regs->eip;
+    gdb_regs[_ESP] =  (int) (&regs->esp) ;
+    gdb_regs[ _SS] =  __KERNEL_DS;
+    gdb_regs[ _FS] =  0xFFFF;
+    gdb_regs[ _GS] =  0xFFFF;
+} /* regs_to_gdb_regs */
+
+static void gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs)
+{
+    regs->eax	=     gdb_regs[_EAX] ;
+    regs->ebx	=     gdb_regs[_EBX] ;
+    regs->ecx	=     gdb_regs[_ECX] ;
+    regs->edx	=     gdb_regs[_EDX] ;
+    regs->esi	=     gdb_regs[_ESI] ;
+    regs->edi	=     gdb_regs[_EDI] ;
+    regs->ebp	=     gdb_regs[_EBP] ;
+    regs->xds	=     gdb_regs[ _DS] ;
+    regs->xes	=     gdb_regs[ _ES] ;
+    regs->eflags=     gdb_regs[ _PS] ;
+    regs->xcs	=     gdb_regs[ _CS] ;
+    regs->eip	=     gdb_regs[ _PC] ;
+#if 0					/* can't change these */
+    regs->esp	=     gdb_regs[_ESP] ;
+    regs->xss	=     gdb_regs[ _SS] ;
+    regs->fs	=     gdb_regs[ _FS] ;
+    regs->gs	=     gdb_regs[ _GS] ;
+#endif
+
+} /* gdb_regs_to_regs */
+
+/* Indicate to caller of mem2hex or hex2mem that there has been an
+   error.  */
+static volatile int kgdb_memerr = 0;
+volatile int kgdb_memerr_expected = 0;
+static volatile int kgdb_memerr_cnt = 0;
+static          int garbage_loc = -1 ;
+
+int
+get_char (char *addr)
+{
+  return *addr;
+}
+
+void
+set_char ( char *addr, int val)
+{
+  *addr = val;
+}
+
+/* convert the memory pointed to by mem into hex, placing result in buf */
+/* return a pointer to the last char put in buf (null) */
+/* If MAY_FAULT is non-zero, then we should set kgdb_memerr in response to
+   a fault; if zero treat a fault like any other fault in the stub.  */
+char* mem2hex( char* mem,
+	       char* buf,
+	       int   count,
+	       int may_fault)
+{
+      int i;
+      unsigned char ch;
+
+      if (may_fault)
+      {
+          kgdb_memerr_expected = 1 ;
+          kgdb_memerr = 0 ;
+      }
+      for (i=0;i<count;i++) {
+
+	  ch = get_char (mem++);
+
+	  if (may_fault && kgdb_memerr)
+	  {
+	    *buf = 0 ;				/* truncate buffer */
+	    return (buf);
+	  }
+          *buf++ = hexchars[ch >> 4];
+          *buf++ = hexchars[ch % 16];
+      }
+      *buf = 0;
+      if (may_fault)
+	  kgdb_memerr_expected = 0 ;
+      return(buf);
+}
+
+/* convert the hex array pointed to by buf into binary to be placed in mem */
+/* return a pointer to the character AFTER the last byte written */
+char* hex2mem( char* buf,
+	       char* mem,
+	       int   count,
+	       int may_fault)
+{
+      int i;
+      unsigned char ch;
+
+      if (may_fault)
+      {
+          kgdb_memerr_expected = 1 ;
+          kgdb_memerr = 0 ;
+      }
+      for (i=0;i<count;i++) {
+          ch = hex(*buf++) << 4;
+          ch = ch + hex(*buf++);
+	  set_char (mem++, ch);
+
+	  if (may_fault && kgdb_memerr)
+	  {
+	    return (mem);
+	  }
+      }
+      if (may_fault)
+	  kgdb_memerr_expected = 0 ;
+      return(mem);
+}
+
+
+/**********************************************/
+/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
+/* RETURN NUMBER OF CHARS PROCESSED           */
+/**********************************************/
+int hexToInt(char **ptr, int *intValue)
+{
+    int numChars = 0;
+    int hexValue;
+
+    *intValue = 0;
+
+    while (**ptr)
+    {
+        hexValue = hex(**ptr);
+        if (hexValue >=0)
+        {
+            *intValue = (*intValue <<4) | hexValue;
+            numChars ++;
+        }
+        else
+            break;
+
+        (*ptr)++;
+    }
+
+    return (numChars);
+}
+
+#ifdef CONFIG_KGDB_THREAD
+static int
+stubhex (
+     int ch)
+{
+  if (ch >= 'a' && ch <= 'f')
+    return ch - 'a' + 10;
+  if (ch >= '0' && ch <= '9')
+    return ch - '0';
+  if (ch >= 'A' && ch <= 'F')
+    return ch - 'A' + 10;
+  return -1;
+}
+
+
+static int
+stub_unpack_int (
+     char *buff,
+     int fieldlength)
+{
+  int nibble;
+  int retval = 0;
+
+  while (fieldlength)
+    {
+      nibble = stubhex (*buff++);
+      retval |= nibble;
+      fieldlength--;
+      if (fieldlength)
+	retval = retval << 4;
+    }
+  return retval;
+}
+#endif
+
+static char *
+pack_hex_byte (
+     char *pkt,
+     int byte)
+{
+  *pkt++ = hexchars[(byte >> 4) & 0xf];
+  *pkt++ = hexchars[(byte & 0xf)];
+  return pkt;
+}
+
+#define BUF_THREAD_ID_SIZE 16
+
+#ifdef CONFIG_KGDB_THREAD
+static char *
+pack_threadid (
+     char *pkt,
+     threadref *id)
+{
+  char *limit;
+  unsigned char *altid;
+
+  altid = (unsigned char *) id;
+  limit = pkt + BUF_THREAD_ID_SIZE;
+  while (pkt < limit)
+    pkt = pack_hex_byte (pkt, *altid++);
+  return pkt;
+}
+
+static char *
+unpack_byte (
+     char *buf,
+     int *value)
+{
+  *value = stub_unpack_int (buf, 2);
+  return buf + 2;
+}
+
+static char *
+unpack_threadid (
+     char *inbuf,
+     threadref *id)
+{
+  char *altref;
+  char *limit = inbuf + BUF_THREAD_ID_SIZE;
+  int x, y;
+
+  altref = (char *) id;
+
+  while (inbuf < limit)
+    {
+      x = stubhex (*inbuf++);
+      y = stubhex (*inbuf++);
+      *altref++ = (x << 4) | y;
+    }
+  return inbuf;
+}
+#endif
+
+void
+int_to_threadref (
+     threadref *id,
+     int value)
+{
+  unsigned char *scan;
+
+  scan = (unsigned char *) id;
+  {
+    int i = 4;
+    while (i--)
+      *scan++ = 0;
+  }
+  *scan++ = (value >> 24) & 0xff;
+  *scan++ = (value >> 16) & 0xff;
+  *scan++ = (value >> 8) & 0xff;
+  *scan++ = (value & 0xff);
+}
+
+#ifdef CONFIG_KGDB_THREAD
+static int
+threadref_to_int (
+     threadref *ref)
+{
+  int i, value = 0;
+  unsigned char *scan;
+
+  scan = (char *) ref;
+  scan += 4;
+  i = 4;
+  while (i-- > 0)
+    value = (value << 8) | ((*scan++) & 0xff);
+  return value;
+}
+
+
+struct task_struct *
+getthread (
+	int pid)
+{
+	struct task_struct *thread;
+	thread = find_task_by_pid(pid);
+	if (thread) {
+		return thread;
+	}
+	thread = init_tasks[0];
+	do {
+		if (thread->pid == pid) {
+			return thread;
+		}
+		thread = thread->next_task;
+	} while (thread != init_tasks[0]);
+	return NULL;
+}
+#endif
+
+struct hw_breakpoint {
+	unsigned enabled;
+	unsigned type;
+	unsigned len;
+	unsigned addr;
+} breakinfo[4] = { { enabled:0 }, { enabled:0 }, { enabled:0 }, { enabled:0 }};
+
+void correct_hw_break( void )
+{
+	int breakno;
+	int correctit;
+	int breakbit;
+	unsigned dr7;
+
+	asm volatile ( 
+		"movl %%db7, %0\n"
+		: "=r" (dr7)
+		: );
+	do
+	{
+		unsigned addr0, addr1, addr2, addr3;
+		asm volatile (
+			"movl %%db0, %0\n"
+			"movl %%db1, %1\n"
+			"movl %%db2, %2\n"
+			"movl %%db3, %3\n"
+			: "=r" (addr0), "=r" (addr1), "=r" (addr2),
+			"=r" (addr3) : );
+	} while (0);
+	correctit = 0;
+	for (breakno = 0; breakno < 3; breakno++) {
+		breakbit = 2 << (breakno << 1);
+		if (!(dr7 & breakbit) && breakinfo[breakno].enabled) {
+			correctit = 1;
+			dr7 |= breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+			dr7 |= (((breakinfo[breakno].len << 2) |
+			       breakinfo[breakno].type) << 16) <<
+			       (breakno << 2);
+			switch (breakno) {
+			case 0:
+				asm volatile ("movl %0, %%dr0\n"
+					: 
+					: "r" (breakinfo[breakno].addr) );
+				break;
+
+			case 1:
+				asm volatile ("movl %0, %%dr1\n"
+					: 
+					: "r" (breakinfo[breakno].addr) );
+				break;
+
+			case 2:
+				asm volatile ("movl %0, %%dr2\n"
+					: 
+					: "r" (breakinfo[breakno].addr) );
+				break;
+
+			case 3:
+				asm volatile ("movl %0, %%dr3\n"
+					: 
+					: "r" (breakinfo[breakno].addr) );
+				break;
+			}
+		} else if ((dr7 & breakbit) && !breakinfo[breakno].enabled){
+			correctit = 1;
+			dr7 &= ~breakbit;
+			dr7 &= ~(0xf0000 << (breakno << 2));
+		}
+	}
+	if (correctit) {
+		asm volatile ( "movl %0, %%db7\n"
+			       :
+			       : "r" (dr7));
+	}
+}
+
+int remove_hw_break(
+	unsigned breakno)
+{
+	if (!breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 0;
+	return 0;
+}
+
+int set_hw_break(
+	unsigned breakno,
+	unsigned type,
+	unsigned len,
+	unsigned addr)
+{
+	if (breakinfo[breakno].enabled) {
+		return -1;
+	}
+	breakinfo[breakno].enabled = 1;
+	breakinfo[breakno].type = type;
+	breakinfo[breakno].len = len;
+	breakinfo[breakno].addr = addr;
+	return 0;
+}
+
+void
+gdb_wait(
+	void *arg,
+	struct pt_regs	*regs)
+{
+	unsigned flags;
+	int processor;
+	
+	local_irq_save(flags);
+	processor = smp_processor_id();
+	procindebug[processor] = 1;
+	current->thread.kgdbregs = regs;
+	spin_lock(slavecpulocks + processor);
+	correct_hw_break();
+	procindebug[processor] = 0;
+	local_irq_restore(flags);
+}
+
+void
+printexceptioninfo(
+	int exceptionNo,
+	int errorcode,
+	char *buffer)
+{
+	unsigned dr6;
+	int i;
+	switch (exceptionNo) {
+	case 1:			/* debug exception */
+		break;
+	case 3:			/* breakpoint */
+		sprintf(buffer, "Software breakpoint");
+		return;
+	default:
+		sprintf(buffer, "Details not available");
+		return;
+	}
+	asm volatile ("movl %%db6, %0\n"
+		      : "=r" (dr6)
+		      : );
+	if (dr6 & 0x4000) {
+		sprintf(buffer, "Single step");
+		return;
+	}
+	for (i = 0; i < 4; ++i) {
+		if (dr6 & (1 << i)) {
+			sprintf(buffer, "Hardware breakpoint %d", i);
+			return;
+		}
+	}
+	sprintf(buffer, "Unknown trap");
+	return;
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb.
+ *
+ * NOTE:  The INT nn instruction leaves the state of the interrupt
+ *        enable flag UNCHANGED.  That means that when this routine
+ *        is entered via a breakpoint (INT 3) instruction from code
+ *        that has interrupts enabled, then interrupts will STILL BE
+ *        enabled when this routine is entered.  The first thing that
+ *        we do here is disable interrupts so as to prevent recursive
+ *        entries and bothersome serial interrupts while we are
+ *        trying to run the serial port in polled mode.
+ *
+ * For kernel version 2.1.xx the cli() actually gets a spin lock so
+ * it is always necessary to do a restore_flags before returning
+ * so as to let go of that lock.
+ */
+int handle_exception(int exceptionVector,
+		     int signo,
+		     int err_code,
+		     struct pt_regs *linux_regs)
+{
+	struct task_struct	*usethread = NULL;
+	int			addr, length;
+	int			breakno, breaktype;
+	char			*ptr;
+	int			newPC;
+	unsigned long		flags;
+	int 			gdb_regs[NUMREGBYTES/4];
+	int			i;
+	int			dr6;
+	struct pt_regs		tempregs;
+#ifdef CONFIG_KGDB_THREAD
+	int			nothreads;
+	int			maxthreads;
+	int			threadid;
+	threadref		thref;
+	struct task_struct	*thread = NULL;
+#endif
+#define	regs	(*linux_regs)
+
+	/*
+	 * If the entry is not from the kernel then return to the Linux
+	 * trap handler and let it process the interrupt normally.
+	 */
+	if ((linux_regs->eflags & VM_MASK) || (3 & linux_regs->xcs)) {
+		return(0);
+	}
+
+	if (kgdb_memerr_expected)
+	{
+		/*
+		 * This fault occured because of the get_char or set_char
+		 * routines.  These two routines use either eax of edx to
+		 * indirectly reference the location in memory that they
+		 * are working with.  For a page fault, when we return
+		 * the instruction will be retried, so we have to make
+		 * sure that these registers point to valid memory.
+		 */
+		kgdb_memerr = 1 ;		/* set mem error flag */
+		kgdb_memerr_expected = 0 ;
+		kgdb_memerr_cnt++ ;	/* helps in debugging */
+		regs.eax = (long) &garbage_loc ;	/* make valid address */
+		regs.edx = (long) &garbage_loc ;	/* make valid address */
+		return(0) ;
+	}
+
+#ifdef CONFIG_SMP
+	if (!spin_is_locked(&kgdb_nmispinlock))
+#else
+	if (!kgdb_nmispinlock)
+#endif
+	{
+
+		/* Get kgdb spinlock */
+#ifdef CONFIG_SMP
+		spin_lock(&kgdb_spinlock);
+#else
+		kgdb_spinlock = 1;
+#endif
+
+		local_irq_save(flags);
+
+		/* Disable hardware debugging while we are in kgdb */
+		__asm__("movl %0,%%db7"
+			: /* no output */
+			: "r" (0));
+
+		for (i = 0; i < smp_num_cpus; i++) {
+			spin_lock_init(&slavecpulocks[i]);
+			spin_lock(&slavecpulocks[i]);
+		}
+
+		/* Force other cpus in debugger */
+		if (smp_call_function(gdb_wait, NULL, 0, 0) != 0 ){
+			return(1);
+		}
+
+		procindebug[smp_processor_id()] = 1;
+	}
+
+	gdb_i386vector  = exceptionVector;
+	gdb_i386errcode = err_code ;
+
+	/* reply to host that an exception has occurred */
+	remcomOutBuffer[0] = 'S';
+	remcomOutBuffer[1] =  hexchars[signo >> 4];
+	remcomOutBuffer[2] =  hexchars[signo % 16];
+	remcomOutBuffer[3] = 0;
+
+	putpacket(remcomOutBuffer);
+
+	while (1==1) {
+		error = 0;
+		remcomOutBuffer[0] = 0;
+		getpacket(remcomInBuffer);
+		switch (remcomInBuffer[0]) {
+		case '?' : 
+			remcomOutBuffer[0] = 'S';
+			remcomOutBuffer[1] =  hexchars[signo >> 4];
+			remcomOutBuffer[2] =  hexchars[signo % 16];
+			remcomOutBuffer[3] = 0;
+			break;
+		case 'g' : /* return the value of the CPU registers */
+			if (!usethread || usethread == current) {
+				regs_to_gdb_regs(gdb_regs, &regs) ;
+			} else {
+				memset(gdb_regs, 0, NUMREGBYTES);
+				if (usethread->thread.kgdbregs) {
+					for (i = 0; i < sizeof (struct pt_regs); i++) {
+						kgdb_memerr_expected = 1 ;
+						kgdb_memerr = 0;
+						*(((char *)&tempregs) + i) = 
+						get_char(((char *)usethread->thread.kgdbregs) + i);
+						kgdb_memerr_expected = 0;
+						if (kgdb_memerr) {
+							*(((char *)&tempregs) + i) = '\0';
+							break;
+						}
+					}
+					regs_to_gdb_regs(gdb_regs, &tempregs);
+				} else {
+					gdb_regs[_PC] = kgdb_usercode;
+				}
+			}
+			mem2hex((char*) gdb_regs, remcomOutBuffer, NUMREGBYTES, 0);
+			break;
+		case 'G' : /* set the value of the CPU registers - return OK */
+			hex2mem(&remcomInBuffer[1], (char*) gdb_regs, NUMREGBYTES, 0);
+			if (!usethread || usethread == current) {
+				gdb_regs_to_regs(gdb_regs, &regs) ;
+				strcpy(remcomOutBuffer,"OK");
+			} else {
+				strcpy(remcomOutBuffer,"E00");
+			}
+			break;
+
+		/* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
+		case 'm' :
+			/* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr,&addr))
+			if (*(ptr++) == ',')
+			if (hexToInt(&ptr,&length))
+			{
+				ptr = 0;
+				mem2hex((char*) addr, remcomOutBuffer, length, 1);
+				if (kgdb_memerr) {
+					strcpy (remcomOutBuffer, "E03");
+				}
+			}
+
+			if (ptr)
+			{
+				strcpy(remcomOutBuffer,"E01");
+			}
+			break;
+
+	      /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
+	      case 'M' :
+				/* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
+				ptr = &remcomInBuffer[1];
+				if (hexToInt(&ptr,&addr))
+				if (*(ptr++) == ',')
+					if (hexToInt(&ptr,&length))
+						if (*(ptr++) == ':')
+						{
+							hex2mem(ptr, (char*) addr, length, 1);
+
+							if (kgdb_memerr) {
+								strcpy (remcomOutBuffer, "E03");
+							} else {
+								strcpy(remcomOutBuffer,"OK");
+							}
+
+							ptr = 0;
+						}
+				if (ptr)
+				{
+					strcpy(remcomOutBuffer,"E02");
+				}
+				break;
+
+	     /* cAA..AA    Continue at address AA..AA(optional) */
+	     /* sAA..AA   Step one instruction from AA..AA(optional) */
+	     case 'c' :
+	     case 's' :
+#ifdef CONFIG_SMP
+			if (spin_is_locked(&kgdb_nmispinlock))
+#else
+			if (kgdb_nmispinlock)
+#endif
+			{
+				strcpy(remcomOutBuffer,"E01");
+				break;
+			}
+
+			/* try to read optional parameter, pc unchanged if no parm */
+			ptr = &remcomInBuffer[1];
+			if (hexToInt(&ptr,&addr))
+			{
+				regs.eip = addr;
+			}
+
+			newPC = regs.eip ;
+
+			/* clear the trace bit */
+			regs.eflags &= 0xfffffeff;
+
+			/* set the trace bit if we're stepping */
+			if (remcomInBuffer[0] == 's') regs.eflags |= 0x100;
+
+			asm volatile ("movl %%db6, %0\n"
+				: "=r" (dr6)
+				: );
+			if (!(dr6 & 0x4000)) {
+				for (breakno = 0; breakno < 4; ++breakno) {
+					if (dr6 & (1 << breakno)) {
+						if (breakinfo[breakno].type == 0) {
+							/* Set restore flag */
+							regs.eflags |= 0x10000;
+							break;
+						}
+					}
+				}
+			}
+			correct_hw_break();
+			asm volatile ( 
+				"movl %0, %%db6\n"
+				: 
+				: "r" (0) );
+			for (i = 0; i < smp_num_cpus; i++) {
+				spin_unlock(&slavecpulocks[i]);
+			}
+
+			procindebug[smp_processor_id()] = 0;
+			/* Release kgdb spinlock */
+#ifdef CONFIG_SMP
+			spin_unlock(&kgdb_spinlock);
+#else
+			kgdb_spinlock = 0;
+#endif
+			local_irq_restore(flags) ;
+			return(0) ;
+
+		/* kill the program */
+		case 'k' :  /* do nothing */
+		break;
+
+		/* query */
+		case 'q' :
+			switch (remcomInBuffer[1]) {
+#ifdef CONFIG_KGDB_THREAD
+			case 'L':	
+				/* List threads */
+				unpack_byte(remcomInBuffer+3, &maxthreads);
+				unpack_threadid(remcomInBuffer+5, &thref);
+
+				remcomOutBuffer[0] = 'q';
+				remcomOutBuffer[1] = 'M';
+				remcomOutBuffer[4] = '0';
+				pack_threadid(remcomOutBuffer+5, &thref);	
+
+				threadid = threadref_to_int(&thref);
+				for (nothreads = 0;
+					nothreads < maxthreads && threadid< PID_MAX;
+					threadid++ )
+				{
+					read_lock(&tasklist_lock);
+					thread = getthread(threadid);
+					read_unlock(&tasklist_lock);
+					if (thread) {
+						int_to_threadref(&thref, threadid);
+						pack_threadid(remcomOutBuffer+21+nothreads*16,
+							      &thref);
+						nothreads++;
+					}
+				}
+				if (threadid == PID_MAX) {
+					remcomOutBuffer[4] = '1';
+				}
+				pack_hex_byte(remcomOutBuffer+2, nothreads);
+				remcomOutBuffer[21+nothreads*16] = '\0';
+				break;
+
+			case 'C':
+				/* Current thread id */
+				remcomOutBuffer[0] = 'Q';
+				remcomOutBuffer[1] = 'C';
+				threadid = current->pid;
+				int_to_threadref(&thref, threadid);
+				pack_threadid(remcomOutBuffer+2, &thref);	
+				remcomOutBuffer[18] = '\0';
+				break;
+#endif
+
+			case 'E':
+				/* Print exception info */
+				printexceptioninfo(exceptionVector, err_code, remcomOutBuffer);
+				break;
+			}
+			break;
+
+#ifdef CONFIG_KGDB_THREAD
+		/* task related */
+		case 'H' :	 
+			switch (remcomInBuffer[1]) {
+				case 'g':
+					ptr = &remcomInBuffer[2];
+					hexToInt(&ptr, &threadid);
+					thread = getthread(threadid);
+					if (!thread) {
+						remcomOutBuffer[0] = 'E';
+						remcomOutBuffer[1] = '\0';
+						break;
+					}
+					usethread = thread;
+					/* follow through */
+				case 'c':
+					remcomOutBuffer[0] = 'O';
+					remcomOutBuffer[1] = 'K';
+					remcomOutBuffer[2] = '\0';
+				break;
+			}
+			break;
+
+		/* Query thread status */
+		case 'T':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &threadid);
+			thread = getthread(threadid);
+			if (thread) {
+				remcomOutBuffer[0] = 'O';
+				remcomOutBuffer[1] = 'K';
+				remcomOutBuffer[2] = '\0';
+			} else {
+				remcomOutBuffer[0] = 'E';
+				remcomOutBuffer[1] = '\0';
+			}
+			break;
+#endif
+
+		case 'Y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			ptr++;
+			hexToInt(&ptr, &breaktype);
+			ptr++;
+			hexToInt(&ptr, &length);
+			ptr++;
+			hexToInt(&ptr, &addr);
+			if (set_hw_break(breakno & 0x3, breaktype & 0x3 , length & 0x3, addr)
+				== 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		/* Remove hardware breakpoint */      
+		case 'y':
+			ptr = &remcomInBuffer[1];
+			hexToInt(&ptr, &breakno);
+			if (remove_hw_break(breakno & 0x3) == 0) {
+				strcpy(remcomOutBuffer, "OK");
+			} else {
+				strcpy(remcomOutBuffer, "ERROR");
+			}
+			break;
+
+		} /* switch */
+
+		/* reply to the request */
+		putpacket(remcomOutBuffer);
+	}
+}
+
+/* this function is used to set up exception handlers for tracing and
+   breakpoints */
+void set_debug_traps(void)
+{
+	/*
+	 * linux_debug_hook is defined in traps.c.  We store a pointer
+	 * to our own exception handler into it.
+	 */
+	linux_debug_hook = handle_exception ;
+
+	/*
+	 * In case GDB is started before us, ack any packets (presumably
+	 * "$?#xx") sitting there.  */
+	putDebugChar ('+');
+
+	initialized = 1;
+}
+
+/* This function will generate a breakpoint exception.  It is used at the
+   beginning of a program to sync up with a debugger and can be used
+   otherwise as a quick means to stop program execution and "break" into
+   the debugger. */
+
+void breakpoint(void)
+{
+	if (initialized)
+		BREAKPOINT();
+}
+
+#ifdef CONFIG_GDB_CONSOLE
+char	gdbconbuf[BUFMAX];
+
+void gdb_console_write(struct console *co, const char *s,
+				unsigned count)
+{
+	int	i;
+	int	wcount;
+	char	*bufptr;
+
+	if (!gdb_initialized) {
+		return;
+	}
+	gdbconbuf[0] = 'O';
+	bufptr = gdbconbuf + 1;
+	while (count > 0) {
+		if ((count << 1) > (BUFMAX - 2)) {
+			wcount = (BUFMAX - 2) >> 1;
+		} else {
+			wcount = count;
+		}
+		count -= wcount;
+		for (i = 0; i < wcount; i++) {
+			bufptr = pack_hex_byte(bufptr, s[i]);
+		}
+		*bufptr = '\0';
+		s += wcount;
+
+		putpacket(gdbconbuf);
+
+	}
+}
+#endif
+static int __init kgdb_opt_gdb(void)
+{
+	gdb_enter = 1;
+	return 1;
+}
+static int __init kgdb_opt_gdbttyS(char *str)
+{
+	gdb_ttyS = simple_strtoul(str,NULL,10);
+	return 1;
+}
+static int __init kgdb_opt_gdbbaud(char *str)
+{
+	gdb_baud = simple_strtoul(str,NULL,10);
+	return 1;
+}
+
+/*
+ * Sequence of these lines has to be maintained because gdb option is a prefix
+ * of the other two options
+ */
+
+__setup("gdbttyS=", kgdb_opt_gdbttyS);
+__setup("gdbbaud=", kgdb_opt_gdbbaud);
+__setup("gdb", kgdb_opt_gdb);
diff -rupN /usr/src/linux-2.4.9/arch/i386/kernel/smp.c linux-kgdb/arch/i386/kernel/smp.c
--- /usr/src/linux-2.4.9/arch/i386/kernel/smp.c	Fri Aug 24 00:12:50 2001
+++ linux-kgdb/arch/i386/kernel/smp.c	Sun Aug 26 18:21:41 2001
@@ -520,9 +520,9 @@ asmlinkage void smp_reschedule_interrupt
 	ack_APIC_irq();
 }
 
-asmlinkage void smp_call_function_interrupt(void)
+asmlinkage void smp_call_function_interrupt(struct pt_regs regs)
 {
-	void (*func) (void *info) = call_data->func;
+	void (*func) (void *info, struct pt_regs *) = (void (*)(void *, struct pt_regs*))call_data->func;
 	void *info = call_data->info;
 	int wait = call_data->wait;
 
@@ -535,7 +535,7 @@ asmlinkage void smp_call_function_interr
 	/*
 	 * At this point the info structure may be out of scope unless wait==1
 	 */
-	(*func)(info);
+	(*func)(info, &regs);
 	if (wait)
 		atomic_inc(&call_data->finished);
 }
diff -rupN /usr/src/linux-2.4.9/arch/i386/kernel/traps.c linux-kgdb/arch/i386/kernel/traps.c
--- /usr/src/linux-2.4.9/arch/i386/kernel/traps.c	Fri Aug 24 00:12:50 2001
+++ linux-kgdb/arch/i386/kernel/traps.c	Sun Aug 26 18:25:26 2001
@@ -50,6 +50,24 @@
 #include <linux/irq.h>
 #include <linux/module.h>
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+gdb_debug_hook * linux_debug_hook;
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)		\
+    {									\
+	if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs)) \
+	{								\
+		(*linux_debug_hook)(trapnr, signr, error_code, regs) ;	\
+		after;							\
+	}								\
+    }
+#else
+#define	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)	
+#endif
+
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
 asmlinkage void lcall27(void);
@@ -246,6 +264,7 @@ void die(const char * str, struct pt_reg
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	printk("%s: %04lx\n", str, err & 0xffff);
+	CHK_REMOTE_DEBUG(1,SIGTRAP,err,regs,)
 	show_registers(regs);
 
 	spin_unlock_irq(&die_lock);
@@ -305,6 +324,7 @@ static void inline do_trap(int trapnr, i
 #define DO_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,)\
 	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
 }
 
@@ -322,7 +342,10 @@ asmlinkage void do_##name(struct pt_regs
 #define DO_VM86_ERROR(trapnr, signr, str, name) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
+	CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,goto skip_trap)\
 	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+skip_trap: \
+	return; \
 }
 
 #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -374,6 +397,7 @@ gp_in_kernel:
 			regs->eip = fixup;
 			return;
 		}
+		CHK_REMOTE_DEBUG(13,SIGSEGV,error_code,regs,)
 		die("general protection fault", regs, error_code);
 	}
 }
@@ -462,12 +486,60 @@ inline void nmi_watchdog_tick(struct pt_
 	sum = apic_timer_irqs[cpu];
 
 	if (last_irq_sums[cpu] == sum) {
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_SMP
+		if (spin_is_locked(&kgdb_spinlock))
+#else
+		if (kgdb_spinlock) 
+#endif
+		{
+			/* We are inside kgdb, this isn't a stuck cpu */
+			alert_counter[cpu] = 0;
+		} else {
+#ifdef CONFIG_SMP
+			if (spin_is_locked(&kgdb_nmispinlock))
+#else
+			if (kgdb_nmispinlock) 
+#endif
+			{
+				if (!procindebug[cpu]) {
+					procindebug[cpu] = 1;
+					current->thread.kgdbregs = regs;
+					while (1) {
+						/* nothing */
+					}
+				}
+				return;
+			}
+		}
+#endif
 		/*
 		 * Ayiee, looks like this CPU is stuck ...
 		 * wait a few IRQs (5 seconds) before doing the oops ...
 		 */
 		alert_counter[cpu]++;
 		if (alert_counter[cpu] == 5*HZ) {
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_SMP
+			if (spin_trylock(&kgdb_nmispinlock))
+#else
+			kgdb_nmispinlock = 1;
+#endif
+			{
+				procindebug[cpu] = 1;
+				CHK_REMOTE_DEBUG(2,SIGSEGV,0,regs,)
+			} 
+#ifdef CONFIG_SMP
+			else {
+				procindebug[cpu] = 1;
+				current->thread.kgdbregs = regs;
+				while (1) {
+					/* nothing */
+				}
+			}
+#endif
+#endif
 			spin_lock(&nmi_print_lock);
 			/*
 			 * We are in trouble anyway, lets at least try
@@ -588,11 +660,13 @@ asmlinkage void do_debug(struct pt_regs 
 	info.si_errno = 0;
 	info.si_code = TRAP_BRKPT;
 	
-	/* If this is a kernel mode trap, save the user PC on entry to 
-	 * the kernel, that's what the debugger can make sense of.
-	 */
-	info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : 
-	                                        (void *)regs->eip;
+
+	/* If this is a kernel mode trap, we need to reset db7 to allow us
+	 * to continue sanely */
+	if ((regs->xcs & 3) == 0)
+		goto clear_dr7;
+
+	info.si_addr = (void *)regs->eip;
 	force_sig_info(SIGTRAP, &info, tsk);
 
 	/* Disable additional traps. They'll be re-enabled when
@@ -602,6 +676,7 @@ clear_dr7:
 	__asm__("movl %0,%%db7"
 		: /* no output */
 		: "r" (0));
+	CHK_REMOTE_DEBUG(1,SIGTRAP,error_code,regs,)
 	return;
 
 debug_vm86:
diff -rupN /usr/src/linux-2.4.9/arch/i386/mm/fault.c linux-kgdb/arch/i386/mm/fault.c
--- /usr/src/linux-2.4.9/arch/i386/mm/fault.c	Tue May 15 10:16:51 2001
+++ linux-kgdb/arch/i386/mm/fault.c	Sun Aug 26 18:21:41 2001
@@ -2,6 +2,11 @@
  *  linux/arch/i386/mm/fault.c
  *
  *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Change History
+ *
+ *	Tigran Aivazian <tigran@sco.com>	Remote debugging support.
+ *
  */
 
 #include <linux/signal.h>
@@ -17,6 +22,9 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -149,6 +157,15 @@ asmlinkage void do_page_fault(struct pt_
 	if (in_interrupt() || !mm)
 		goto no_context;
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (kgdb_memerr_expected) {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs) ;
+			return;            /* return w/modified regs */
+		}
+	}
+#endif
+
 	down_read(&mm->mmap_sem);
 
 	vma = find_vma(mm, address);
@@ -273,6 +290,18 @@ no_context:
 
 	bust_spinlocks();
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (kgdb_memerr_expected) {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs);
+			return; /* Return with modified registers */
+		}
+	} else {
+		if (linux_debug_hook != (gdb_debug_hook *) NULL) {
+			(*linux_debug_hook)(14, SIGSEGV, error_code, regs);
+		}
+	}
+#endif
 	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 	else
diff -rupN /usr/src/linux-2.4.9/drivers/char/Makefile linux-kgdb/drivers/char/Makefile
--- /usr/src/linux-2.4.9/drivers/char/Makefile	Sat Jul 21 20:20:38 2001
+++ linux-kgdb/drivers/char/Makefile	Sun Aug 26 18:21:41 2001
@@ -122,7 +122,7 @@ ifneq ($(CONFIG_SUN_SERIAL),)
   SERIAL   =
 endif
 
-
+obj-$(CONFIG_X86_REMOTE_DEBUG) += gdbserial.o
 obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
 obj-$(CONFIG_SERIAL) += $(SERIAL)
 obj-$(CONFIG_SERIAL_21285) += serial_21285.o
diff -rupN /usr/src/linux-2.4.9/drivers/char/gdbserial.c linux-kgdb/drivers/char/gdbserial.c
--- /usr/src/linux-2.4.9/drivers/char/gdbserial.c	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/drivers/char/gdbserial.c	Sun Aug 26 18:21:41 2001
@@ -0,0 +1,280 @@
+/*
+ * Serial interface GDB stub
+ *
+ * Written (hacked together) by David Grothe (dave@gcom.com)
+ *
+ * Modified by Scott Foehner (sfoehner@engr.sgi.com) to allow connect
+ * on boot-up
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/serialP.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>
+#include <linux/gdb.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+
+#undef	PRNT				/* define for debug printing */
+
+#define	GDB_BUF_SIZE	512		/* power of 2, please */
+
+static char	gdb_buf[GDB_BUF_SIZE] ;
+static int	gdb_buf_in_inx ;
+static atomic_t	gdb_buf_in_cnt ;
+static int	gdb_buf_out_inx ;
+
+extern void	set_debug_traps(void) ;		/* GDB routine */
+extern struct serial_state *	gdb_serial_setup(int ttyS, int baud);
+extern void	shutdown_for_gdb(struct async_struct * info) ;
+						/* in serial.c */
+
+int gdb_irq;
+int gdb_port;
+int gdb_ttyS = 1;	/* Default: ttyS1 */
+int gdb_baud = 38400; 
+int gdb_enter = 0;	/* Default: do not do gdb_hook on boot */
+int gdb_initialized = 0;
+
+static int initialized = -1;
+
+/*
+ * Get a byte from the hardware data buffer and return it
+ */
+static int	read_data_bfr(void)
+{
+    if (inb(gdb_port + UART_LSR) & UART_LSR_DR)
+	return(inb(gdb_port + UART_RX));
+
+    return( -1 ) ;
+
+} /* read_data_bfr */
+
+
+/*
+ * Get a char if available, return -1 if nothing available.
+ * Empty the receive buffer first, then look at the interface hardware.
+ */
+static int	read_char(void)
+{
+    if (atomic_read(&gdb_buf_in_cnt) != 0)	/* intr routine has q'd chars */
+    {
+	int		chr ;
+
+	chr = gdb_buf[gdb_buf_out_inx++] ;
+	gdb_buf_out_inx &= (GDB_BUF_SIZE - 1) ;
+	atomic_dec(&gdb_buf_in_cnt) ;
+	return(chr) ;
+    }
+
+    return(read_data_bfr()) ;	/* read from hardware */
+
+} /* read_char */
+
+/*
+ * Wait until the interface can accept a char, then write it.
+ */
+static void	write_char(int chr)
+{
+    while ( !(inb(gdb_port + UART_LSR) & UART_LSR_THRE) ) ;
+
+    outb(chr, gdb_port+UART_TX);
+
+} /* write_char */
+
+/*
+ * This is the receiver interrupt routine for the GDB stub.
+ * It will receive a limited number of characters of input
+ * from the gdb  host machine and save them up in a buffer.
+ *
+ * When the gdb stub routine getDebugChar() is called it
+ * draws characters out of the buffer until it is empty and
+ * then reads directly from the serial port.
+ *
+ * We do not attempt to write chars from the interrupt routine
+ * since the stubs do all of that via putDebugChar() which
+ * writes one byte after waiting for the interface to become
+ * ready.
+ *
+ * The debug stubs like to run with interrupts disabled since,
+ * after all, they run as a consequence of a breakpoint in
+ * the kernel.
+ *
+ * Perhaps someone who knows more about the tty driver than I
+ * care to learn can make this work for any low level serial
+ * driver.
+ */
+static void gdb_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+    int			 chr ;
+    int			 iir ;
+
+    do
+    {
+	chr = read_data_bfr() ;
+	iir = inb(gdb_port + UART_IIR) ;
+#ifdef PRNT
+	printk("gdb_interrupt: chr=%02x '%c'  after read iir=%02x\n", chr,
+		chr > ' ' && chr < 0x7F ? chr : ' ', iir) ;
+#endif
+	if (chr < 0) continue ;
+
+        if (chr == 3)                   /* Ctrl-C means remote interrupt */
+        {
+            breakpoint();
+            continue ;
+        }
+
+	if (atomic_read(&gdb_buf_in_cnt) >= GDB_BUF_SIZE)
+	{				/* buffer overflow, clear it */
+	    gdb_buf_in_inx = 0 ;
+	    atomic_set(&gdb_buf_in_cnt, 0) ;
+	    gdb_buf_out_inx = 0 ;
+	    break ;
+	}
+
+	gdb_buf[gdb_buf_in_inx++] = chr ;
+	gdb_buf_in_inx &= (GDB_BUF_SIZE - 1) ;
+	atomic_inc(&gdb_buf_in_cnt) ;
+    }
+    while (iir & UART_IIR_RDI);
+
+} /* gdb_interrupt */
+
+/*
+ * Just a NULL routine for testing.
+ */
+void gdb_null(void)
+{
+} /* gdb_null */
+
+
+int     gdb_hook(void)
+{
+    int         retval ;
+    struct serial_state *ser;
+
+#ifdef CONFIG_SMP
+    if (smp_num_cpus > KGDB_MAX_NO_CPUS) { 
+        printk("kgdb: too manu cpus. Cannot enable debugger with more than 8 cpus\n");
+	return (-1);
+    }
+#endif
+
+    /*
+     * Call first time just to get the ser ptr
+     */
+    if((ser = gdb_serial_setup(gdb_ttyS, gdb_baud)) == 0) {
+        printk ("gdb_serial_setup() error");
+        return(-1);
+    }
+
+    gdb_port = ser->port;
+    gdb_irq = ser->irq;
+
+    if (ser->info != NULL)
+    {
+	shutdown_for_gdb(ser->info) ;
+	/*
+	 * Call second time to do the setup now that we have
+	 * shut down the previous user of the interface.
+	 */
+	gdb_serial_setup(gdb_ttyS, gdb_baud) ;
+    }
+
+    retval = request_irq(gdb_irq,
+                         gdb_interrupt,
+                         SA_INTERRUPT,
+                         "GDB-stub", NULL);
+    if (retval == 0)
+        initialized = 1;
+    else
+    {
+        initialized = 0;
+	printk("gdb_hook: request_irq(irq=%d) failed: %d\n", gdb_irq, retval);
+    }
+
+    /*
+     * Call GDB routine to setup the exception vectors for the debugger
+     */
+    set_debug_traps() ;
+
+    /*
+     * Call the breakpoint() routine in GDB to start the debugging
+     * session.
+     */
+    printk("Waiting for connection from remote gdb... ") ;
+    breakpoint() ;
+    gdb_null() ;
+
+    printk("Connected.\n");
+
+    gdb_initialized = 1;
+    return(0) ;
+
+} /* gdb_hook_interrupt2 */
+
+/*
+ * getDebugChar
+ *
+ * This is a GDB stub routine.  It waits for a character from the
+ * serial interface and then returns it.  If there is no serial
+ * interface connection then it returns a bogus value which will
+ * almost certainly cause the system to hang.
+ */
+int	getDebugChar(void)
+{
+    volatile int	chr ;
+
+#ifdef PRNT
+    printk("getDebugChar: ") ;
+#endif
+
+    while ( (chr = read_char()) < 0 ) ;
+
+
+#ifdef PRNT
+    printk("%c\n", chr > ' ' && chr < 0x7F ? chr : ' ') ;
+#endif
+    return(chr) ;
+
+} /* getDebugChar */
+
+/*
+ * putDebugChar
+ *
+ * This is a GDB stub routine.  It waits until the interface is ready
+ * to transmit a char and then sends it.  If there is no serial
+ * interface connection then it simply returns to its caller, having
+ * pretended to send the char.
+ */
+void	putDebugChar(int chr)
+{
+#ifdef PRNT
+    printk("putDebugChar: chr=%02x '%c'\n", chr,
+		chr > ' ' && chr < 0x7F ? chr : ' ') ;
+#endif
+
+    write_char(chr) ;	/* this routine will wait */
+
+} /* putDebugChar */
+
diff -rupN /usr/src/linux-2.4.9/drivers/char/serial.c linux-kgdb/drivers/char/serial.c
--- /usr/src/linux-2.4.9/drivers/char/serial.c	Fri Aug 24 00:12:56 2001
+++ linux-kgdb/drivers/char/serial.c	Sun Aug 26 18:21:41 2001
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
  * 		1998, 1999  Theodore Ts'o
+ *  Copyright (C) 2000 VERITAS Software Corporation.
  *
  *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
  *  much more extensible to support other serial cards based on the
@@ -34,6 +35,10 @@
  *  4/98: Added changes to support the ARM architecture proposed by
  * 	  Russell King
  *
+ *  3/99: Added TIOCGDB for remote debugging with gdb if compiled with
+ *        CONFIG_X86_REMOTE_DEBUG
+ * 	  Tigran Aivazian
+ *
  *  5/99: Updated to include support for the XR16C850 and ST16C654
  *        uarts.  Stuart MacDonald <stuartm@connecttech.com>
  *
@@ -57,6 +62,8 @@
  * 10/00: add in optional software flow control for serial console.
  *	  Kanoj Sarcar <kanoj@sgi.com>  (Modified by Theodore Ts'o)
  *
+ * 10/00: added console support for kgdb. Amit Kale <akale@veritas.com>
+ *
  */
 
 static char *serial_version = "5.05c";
@@ -196,7 +203,7 @@ static char *serial_revdate = "2001-07-0
 #include <asm/uaccess.h>
 #endif
 #include <linux/delay.h>
-#ifdef CONFIG_SERIAL_CONSOLE
+#if defined(CONFIG_SERIAL_CONSOLE) || defined (CONFIG_GDB_CONSOLE)
 #include <linux/console.h>
 #endif
 #ifdef ENABLE_SERIAL_PCI
@@ -216,6 +223,9 @@ static char *serial_revdate = "2001-07-0
 #if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
 #include "serial_compat.h"
 #endif
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -1568,6 +1578,12 @@ static void shutdown(struct async_struct
 	info->flags &= ~ASYNC_INITIALIZED;
 	restore_flags(flags);
 }
+#ifdef CONFIG_X86_REMOTE_DEBUG
+void shutdown_for_gdb(struct async_struct * info)
+{
+    shutdown(info) ;
+}
+#endif
 
 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
 static int baud_table[] = {
@@ -2679,6 +2695,12 @@ static int rs_ioctl(struct tty_struct *t
 			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
 			return 0;
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+		case TIOCGDB:
+			gdb_ttyS = MINOR(tty->device) & 0x03F ;
+			gdb_baud = tty_get_baud_rate(tty) ;
+			return gdb_hook();
+#endif
 		default:
 			return -ENOIOCTLCMD;
 		}
@@ -5985,6 +6007,136 @@ void __init serial_console_init(void)
 	register_console(&sercons);
 }
 #endif
+
+/*
+ * ------------------------------------------------------------
+ * Serial GDB driver (most in gdbserial.c)
+ * ------------------------------------------------------------
+ */
+
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#ifdef CONFIG_GDB_CONSOLE
+static struct console gdbcons = {
+	"gdb",
+	gdb_console_write,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	CON_PRINTBUFFER | CON_ENABLED,
+	-1,
+	0,
+	NULL
+};
+#endif
+
+
+/* 
+ *  Takes:
+ *	ttyS - integer specifying which serial port to use for debugging
+ *	baud - baud rate of specified serial port
+ *  Returns:
+ *	port for use by the gdb serial driver
+ */
+struct serial_state *
+gdb_serial_setup(int ttyS, int baud)
+{
+        struct serial_state *ser;
+        unsigned cval;
+        int     bits = 8;
+        int     parity = 'n';
+        int     cflag = CREAD | HUPCL | CLOCAL;
+        int     quot = 0;
+
+        /*
+         *      Now construct a cflag setting.
+         */
+        switch(baud) {
+                case 1200:
+                        cflag |= B1200;
+                        break;
+                case 2400:
+                        cflag |= B2400;
+                        break;
+                case 4800:
+                        cflag |= B4800;
+                        break;
+                case 19200:
+                        cflag |= B19200;
+                        break;
+                case 38400:
+                        cflag |= B38400;
+                        break;
+                case 57600:
+                        cflag |= B57600;
+                        break;
+                case 115200:
+                        cflag |= B115200;
+                        break;
+                case 9600:
+                default:
+                        cflag |= B9600;
+                        break;
+        }
+        switch(bits) {
+                case 7:
+                        cflag |= CS7;
+                        break;
+                default:
+                case 8:
+                        cflag |= CS8;
+                        break;
+        }
+        switch(parity) {
+                case 'o': case 'O':
+                        cflag |= PARODD;
+                        break;
+                case 'e': case 'E':
+                        cflag |= PARENB;
+                        break;
+        }
+
+        /*
+         *      Divisor, bytesize and parity
+         */
+
+        ser = rs_table + ttyS;
+	ser->flags &= ~ASYNC_BOOT_AUTOCONF;
+        quot = ser->baud_base / baud;
+        cval = cflag & (CSIZE | CSTOPB);
+        cval >>= 4;
+        if (cflag & PARENB)
+                cval |= UART_LCR_PARITY;
+        if (!(cflag & PARODD))
+                cval |= UART_LCR_EPAR;
+
+        /*
+         *      Disable UART interrupts, set DTR and RTS high
+         *      and set speed.
+         */
+	cval = 0x3;
+        outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);       /* set DLAB */
+        outb(quot & 0xff, ser->port + UART_DLL);         /* LS of divisor */
+        outb(quot >> 8, ser->port + UART_DLM);           /* MS of divisor */
+        outb(cval, ser->port + UART_LCR);                /* reset DLAB */
+        outb(UART_IER_RDI, ser->port + UART_IER);        /* turn on interrupts*/
+        outb(UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
+
+        /*
+         *      If we read 0xff from the LSR, there is no UART here.
+         */
+        if (inb(ser->port + UART_LSR) == 0xff)
+                return 0;
+        return ser;
+}
+#ifdef CONFIG_GDB_CONSOLE
+void __init gdb_console_init(void)
+{
+	register_console(&gdbcons);
+}
+#endif
+#endif /* CONFIG_X86_REMOTE_DEBUG */
 
 /*
   Local variables:
diff -rupN /usr/src/linux-2.4.9/drivers/char/tty_io.c linux-kgdb/drivers/char/tty_io.c
--- /usr/src/linux-2.4.9/drivers/char/tty_io.c	Fri Aug 24 00:12:56 2001
+++ linux-kgdb/drivers/char/tty_io.c	Sun Aug 26 18:21:42 2001
@@ -90,6 +90,9 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
+#ifdef CONFIG_GDB_CONSOLE
+#include <linux/gdb.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -2183,6 +2186,9 @@ void __init console_init(void)
 	 */
 #ifdef CONFIG_VT
 	con_init();
+#endif
+#ifdef CONFIG_GDB_CONSOLE
+	gdb_console_init();
 #endif
 #ifdef CONFIG_SERIAL_CONSOLE
 #if (defined(CONFIG_8xx) || defined(CONFIG_8260))
diff -rupN /usr/src/linux-2.4.9/drivers/scsi/sd.c linux-kgdb/drivers/scsi/sd.c
--- /usr/src/linux-2.4.9/drivers/scsi/sd.c	Sat Aug 11 15:52:42 2001
+++ linux-kgdb/drivers/scsi/sd.c	Sat Aug 25 01:18:48 2001
@@ -42,6 +42,9 @@
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#if defined(CONFIG_RAW) && defined(CONFIG_AIO)
+#include <linux/aio.h>
+#endif
 
 #include <linux/smp.h>
 
@@ -661,6 +664,31 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
 	 */
 	scsi_io_completion(SCpnt, good_sectors, block_sectors);
 }
+
+#if defined(CONFIG_RAW) && defined(CONFIG_AIO)
+/*
+ * XXX Interfaces for AIO; ideally done through fops.
+ */
+int
+kaio_is_raw(struct file *filp)
+{
+	return(filp->f_op == &sd_raw_fops);
+}
+
+int
+kaio_raw_wait(void *handle, struct kiobuf *kb)
+{
+	return(sd_raw_wait(handle, kb));
+}
+
+void *
+kaio_raw_rw(int rw, struct file *filp, char *buf, size_t count, loff_t *ppos, 
+	  int *error, struct semaphore *semp, struct kiobuf *iobufp)
+{
+	return(sd_raw_rw(rw, filp, buf, count, ppos, error, semp, iobufp));
+}
+#endif	/* CONFIG_AIO */
+
 /*
  * requeue_sd_request() is the request handler function for the sd driver.
  * Its function in life is to take block device requests, and translate
diff -rupN /usr/src/linux-2.4.9/fs/Config.in linux-kgdb/fs/Config.in
--- /usr/src/linux-2.4.9/fs/Config.in	Sat Jul 21 20:19:58 2001
+++ linux-kgdb/fs/Config.in	Sat Aug 25 17:16:00 2001
@@ -10,6 +10,7 @@ tristate 'Kernel automounter version 4 s
 
 dep_tristate 'Reiserfs support' CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL
 dep_mbool '  Have reiserfs do extra internal checking' CONFIG_REISERFS_CHECK $CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL
+dep_mbool '  Enable reiserfs_raw interface' CONFIG_REISERFS_RAW $CONFIG_REISERFS_FS $CONFIG_EXPERIMENTAL
 
 dep_tristate 'ADFS file system support' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
 dep_mbool '  ADFS write support (DANGEROUS)' CONFIG_ADFS_FS_RW $CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL
diff -rupN /usr/src/linux-2.4.9/fs/namei.c linux-kgdb/fs/namei.c
--- /usr/src/linux-2.4.9/fs/namei.c	Sat Jul 21 20:20:55 2001
+++ linux-kgdb/fs/namei.c	Sun Aug 26 18:21:42 2001
@@ -2,6 +2,8 @@
  *  linux/fs/namei.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Copyright (C) 2001	Amit S. Kale
  */
 
 /*
@@ -279,6 +281,8 @@ static struct dentry * real_lookup(struc
 		if (dentry) {
 			lock_kernel();
 			result = dir->i_op->lookup(dir, dentry);
+			KERNEL_ASSERT("lookup return value invalid",
+					KA_VALID_PTRORERR(result));
 			unlock_kernel();
 			if (result)
 				dput(dentry);
@@ -684,6 +688,8 @@ int path_init(const char *name, unsigned
 	if (*name=='/')
 		return walk_init_root(name,nd);
 	read_lock(&current->fs->lock);
+	KERNEL_ASSERT("no fs", current->fs);
+	KERNEL_ASSERT("no pwd", current->fs->pwdmnt);
 	nd->mnt = mntget(current->fs->pwdmnt);
 	nd->dentry = dget(current->fs->pwd);
 	read_unlock(&current->fs->lock);
@@ -726,6 +732,8 @@ struct dentry * lookup_hash(struct qstr 
 			goto out;
 		lock_kernel();
 		dentry = inode->i_op->lookup(inode, new);
+		KERNEL_ASSERT("lookup return value invalid",
+				KA_VALID_PTRORERR(dentry));
 		unlock_kernel();
 		if (!dentry)
 			dentry = new;
diff -rupN /usr/src/linux-2.4.9/fs/read_write.c linux-kgdb/fs/read_write.c
--- /usr/src/linux-2.4.9/fs/read_write.c	Sat Aug 11 15:52:46 2001
+++ linux-kgdb/fs/read_write.c	Sat Aug 25 22:13:25 2001
@@ -2,6 +2,12 @@
  *  linux/fs/read_write.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ * KAIO modifications:
+ * 	Copyright 1999, Silicon Graphics, Inc.
+ *
+ * 	Written October 1999 by Rajagopal Ananthanarayanan (ananth)
+ *                      at Silicon Graphics, Inc.
  */
 
 #include <linux/slab.h> 
@@ -13,6 +19,9 @@
 #include <linux/dnotify.h>
 
 #include <asm/uaccess.h>
+#if defined(CONFIG_AIO)
+#include <linux/aio.h>
+#endif
 
 struct file_operations generic_ro_fops = {
 	llseek:		generic_file_llseek,
@@ -406,3 +415,92 @@ out:
 bad_file:
 	return ret;
 }
+
+#if defined(CONFIG_AIO)
+
+#ifdef DEBUG
+#define dprintk(x) printk x
+#else
+#define dprintk(x)
+#endif
+
+asmlinkage int sys_aio(int cmd,
+			unsigned long arg1,
+			unsigned long arg2,
+			unsigned long arg3,
+			unsigned long arg4)
+{
+	int ret = 0;
+
+
+	if (!current->kaio_info) {
+		lock_kernel();
+		if (!current->kaio_info && cmd != AIOCMD_SLAVE) {
+			kaio_q_create(current);
+			unlock_kernel();
+			return -ENOTCONN;
+		}
+		unlock_kernel();
+	}
+
+	switch (cmd) {
+	case AIOCMD_READ:
+	case AIOCMD_WRITE:
+	{
+		return(kaio_rw(cmd, (aiocb_t *)arg1, 0));
+	}
+        case AIOCMD_IOCTL:
+        case AIOCMD_CLOSE:
+        {
+                return(kaio_syscall(cmd, (aiocb_t *)arg1));
+        }
+	case AIOCMD_SUSPEND:
+	{
+		/* aio_suspend(aiocb_t *list[], nent, timeout) */
+		return (kaio_suspend((aiocb_t **)arg1, arg2,
+				(struct timespec *)arg3, 1));
+	}
+	case AIOCMD_CANCEL:
+	{
+		/* aio_cancel(int fd, aiocb_t *aiocb); */
+		kaio_key_t kkey;
+
+		if (arg2 && copy_from_user(&kkey, &((aiocb_t *)arg2)->aio_key, sizeof(kaio_key_t))) {
+			ret = -EFAULT;
+			break;
+		}
+		return(kaio_cancel((int)arg1, arg2 ?  &kkey : 0));
+	}
+	case AIOCMD_LIST_IO:
+	{
+		/*
+		 * lio_listio(int mode, aiocb_t *const list[],
+		 * 		int nent, sigevent_t *sig);
+		 */
+		return (kaio_list_io((int)arg1, (struct aiocb **)arg2,
+				   (int)arg3, (sigevent_t *)arg4));
+	}
+	case AIOCMD_PCINVALIDATE:
+	{
+		struct file * file;
+
+		if (!(file = fget(arg1))) {
+			ret = -EINVAL;
+			break;
+		}
+		lock_kernel();
+		truncate_inode_pages(file->f_dentry->d_inode->i_mapping, 0);
+		fput(file);
+		break;
+	}
+	case AIOCMD_SLAVE:
+		lock_kernel();
+		kaio_slave();
+		return 0;
+	default:
+		ret = -EINVAL;
+	}
+	unlock_kernel();
+	return ret;
+}
+#endif /* CONFIG_AIO */
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/Makefile linux-kgdb/fs/reiserfs/Makefile
--- /usr/src/linux-2.4.9/fs/reiserfs/Makefile	Mon Jan 15 22:42:32 2001
+++ linux-kgdb/fs/reiserfs/Makefile	Sat Aug 25 17:18:11 2001
@@ -11,6 +11,10 @@ O_TARGET := reiserfs.o
 obj-y   := bitmap.o do_balan.o namei.o inode.o file.o dir.o fix_node.o super.o prints.o objectid.o \
 lbalance.o ibalance.o stree.o hashes.o buffer2.o tail_conversion.o journal.o resize.o tail_conversion.o version.o item_ops.o ioctl.o
 
+ifdef CONFIG_REISERFS_RAW
+obj-y += raw.o pgc.o age_class.o
+endif
+
 obj-m   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/age_class.c linux-kgdb/fs/reiserfs/age_class.c
--- /usr/src/linux-2.4.9/fs/reiserfs/age_class.c	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/fs/reiserfs/age_class.c	Sat Aug 25 17:18:36 2001
@@ -0,0 +1,211 @@
+/*
+ * fs/reiserfs/age_class.c
+ *
+ * Class LRU routines for file aging and replacement.
+ *
+ * Written by Yury Shevchuk <sizif@botik.ru>
+ *
+ * Changes:
+ *      20000826 Linear interpolation for threshold calculation
+ *      proposed by Nikita Danilov <nikitadanilov@yahoo.com>
+ *
+ * Copyright 2000 Hans Reiser, see reiserfs/README for licensing and copyright details
+ *
+ * $Id: age_class.c,v 1.1.2.6 2000/09/08 14:42:45 sizif Exp $
+ */
+
+#include <linux/age_class.h>
+
+#define DUMMY(ARGS...)
+#define debug(N,M)	DUMMY
+
+#ifdef __KERNEL__
+#  include <linux/sched.h>
+#  include <linux/reiserfs_fs.h>
+#  include <linux/smp_lock.h>
+#  define assert(X)	BUG();
+#  define snprintf(STR, N, FMT, ARGS...)  sprintf (STR, FMT, ## ARGS)
+#  define SAFETY_MARGIN 100
+#else
+#  define SAFETY_MARGIN 0	/* not needed if snprintf is available */
+#endif
+
+
+void
+age_class_init (age_class *a, time_t curtime)
+{
+    int i = AGE_CLASS_COUNT;
+    while (--i >= 0) {
+	a->class[i].c = 0;
+	a->class[i].t = curtime;
+    }
+    a->total = 0;
+}
+
+
+/* count object with timestamp TIME in appropriate class (INC=1 for
+   arrival, INC=-1 for departure) */
+
+void
+age_class_update (age_class *a, time_t time, int inc)
+{
+    int n = age_class_find (a, time);
+    unsigned old = a->class[n].c;
+    unsigned new = a->class[n].c + inc;
+
+    if ((old^new) & 0x80000000) {
+	/* Counter overflow can occur if you have too many (>> 4G)
+	   objects -- use 64 bit counters then, while underflow means
+	   an error somewhere (missing positive update) */
+	debug(86, 1)
+	  ("age_class_update: class[%u].c = %u + (%d) would overflow, refusing\n",
+	   n, old, inc);
+	return;
+    }
+
+    a->class[n].c = new;
+    a->total += inc;
+}
+
+
+/* find age class where timestamp TIME currently belongs */
+
+int
+age_class_find (age_class *a, time_t time)
+{
+    int i;
+    for (i = 0; i < AGE_CLASS_COUNT; i++) {
+	if (time >= a->class[i].t)
+	    return i;
+    }
+    assert (0);
+    return 0;
+}
+
+
+/* The periodical shift procedure.  Returns 0 if shift isn't done
+   because class0 isn't big enough */
+
+int
+age_class_shift (age_class *a, time_t curtime)
+{
+    unsigned long min;
+    int i, chosen;
+
+    /* Don't shift unless class[0].c is big enough, and time interval
+       is wider than zero. */
+    if (a->class[0].c <= a->total/AGE_CLASS_COUNT
+	|| a->class[0].t >= curtime)
+	return 0;
+
+    /* Consider all neighbouring class pairs to find the pair to
+       merge.  We will merge the pair for which the sum of the
+       counters is minimal. */
+
+    min = ULONG_MAX;
+    chosen = 1;
+
+    for (i = 1; i < AGE_CLASS_COUNT; i++) {
+	int sum = a->class[i-1].c + a->class[i].c;
+	if (sum < min) {
+	    min = sum;
+	    chosen = i;
+	}
+    }
+
+    debug(86, 5) ("age_class_shift: shift up to class[%u]\n", chosen);
+
+    i = chosen-1;
+    a->class[i+1].c += a->class[i].c;
+    a->class[i].t = a->class[i-1].t;
+    while (--i > 0) {
+        a->class[i+1].c = a->class[i].c;
+	a->class[i].t = a->class[i-1].t;
+    }
+    a->class[1].c = a->class[0].c;
+    a->class[0].c = 0;
+    a->class[0].t = curtime;
+
+    return 1;
+}
+
+
+/* dump age_class for debugging purposes */
+
+char *
+age_class_dump (age_class *a, time_t curtime, char *buf, int bufsz)
+{
+    char *p = buf;
+    int room_left = bufsz - SAFETY_MARGIN;
+    time_t t = curtime;
+    int i;
+
+    for (i = 0; i < AGE_CLASS_COUNT; i++) {
+	int n = snprintf (p, room_left, 
+			  "  class %02d: files %-12u span %10ld..%-10ld = %-10ld\n",
+			  i, a->class[i].c, a->class[i].t+1, t, t-a->class[i].t);
+	p += n;
+	if ((room_left -= n) <= 0)
+	    break;
+	t = a->class[i].t;
+    }
+    if (room_left > 0) {
+	int n = snprintf (p, room_left, 
+			  "  total     files %-12u\n", a->total);
+	p += n;
+	room_left -= n;
+    }
+    return buf;
+}
+
+
+/* Compute age threshold based on desired file ratio.  The ratio is
+   defined as M/N*100 where M is the count of files above threshold, N
+   is the total number of files.  For example, for ratio=20 threshold
+   will be chosen so that every 5th file will be above the threshold. */
+
+time_t
+age_class_threshold (age_class *a, unsigned ratio, time_t curtime)
+{
+    unsigned long aged = 0;
+    unsigned long r1, r2 = 0;
+    time_t t1, t2;
+    int i = AGE_CLASS_COUNT;
+
+    /* We should never be called if there are no files,
+       but let's play safe */
+    if (! a->total)
+	return 0;
+
+    t1 = t2 = r1 = 0;   /* only to avoid incorrect warning */
+
+    while (--i > 0) {
+	aged += a->class[i].c;
+	if (aged == 0)
+	    continue;
+	r1 = r2;
+	r2 = aged*100/a->total;
+	if (r2 >= ratio) {
+	    t1 = a->class[i].t;
+	    t2 = a->class[i-1].t;
+	    break;
+	}
+    }
+
+    if (i == 0) {
+	r1 = r2;
+	r2 = 100;
+	t1 = a->class[0].t;
+	t2 = curtime;
+    }
+
+    /* Now the threshold is within class i, r1 <= ratio <= r2, (r1 != r2),
+       t1 <= age_threshold <= t2.  Interpolate to find the threshold  */
+
+    return t1 + (t2-t1)*(ratio - r1)/(r2-r1);
+}
+
+/*
+  ;;; Local Variables: ***
+  ;;; tab-width:8 ***
+*/
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/dir.c linux-kgdb/fs/reiserfs/dir.c
--- /usr/src/linux-2.4.9/fs/reiserfs/dir.c	Sat Jul 21 20:20:56 2001
+++ linux-kgdb/fs/reiserfs/dir.c	Sat Aug 25 17:48:44 2001
@@ -28,6 +28,7 @@ struct file_operations reiserfs_dir_oper
     read:	generic_read_dir,
     readdir:	reiserfs_readdir,
     fsync:	reiserfs_dir_fsync,
+    ioctl:      reiserfs_dir_ioctl,
 };
 
 /*
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/inode.c linux-kgdb/fs/reiserfs/inode.c
--- /usr/src/linux-2.4.9/fs/reiserfs/inode.c	Sat Jul 21 20:20:56 2001
+++ linux-kgdb/fs/reiserfs/inode.c	Sun Aug 26 02:44:30 2001
@@ -58,7 +58,7 @@ void reiserfs_delete_inode (struct inode
     unlock_kernel() ;
 }
 
-static void _make_cpu_key (struct cpu_key * key, int version, __u32 dirid, __u32 objectid, 
+void _make_cpu_key (struct cpu_key * key, int version, __u32 dirid, __u32 objectid, 
 			   loff_t offset, int type, int length)
 {
   key->version = version;
@@ -923,6 +923,17 @@ static void init_inode (struct inode * i
 	    inode->i_generation = INODE_PKEY (inode)->k_dir_id;
 	else
 	    inode->i_generation = le32_to_cpu( sd->u.sd_generation );
+#ifdef CONFIG_REISERFS_RAW
+        if (ih->ih_item_len == RAW_SD_SIZE) {
+            inode->u.reiserfs_i.lastref = le32_to_cpu (ATTR_LASTREF (sd));
+            inode->u.reiserfs_i.expires = le32_to_cpu (ATTR_EXPIRES (sd));
+            inode->u.reiserfs_i.user1   = le32_to_cpu (ATTR_USER1 (sd));
+        }
+        else {
+            /* make raw/non-raw inodes clearly distinguishable */
+            inode->u.reiserfs_i.lastref = 0;
+        }
+#endif
     }
 
     /* nopack = 0, by default */
@@ -947,7 +958,7 @@ static void init_inode (struct inode * i
 
 
 // update new stat data with inode fields
-static void inode2sd (void * sd, struct inode * inode)
+void inode2sd (void * sd, struct inode * inode)
 {
     struct stat_data * sd_v2 = (struct stat_data *)sd;
 
@@ -1010,7 +1021,15 @@ static void update_stat_data (struct pat
 	// path points to old stat data
 	inode2sd_v1 (B_I_PITEM (bh, ih), inode);
     } else {
-	inode2sd (B_I_PITEM (bh, ih), inode);
+        struct stat_data *sd = (struct stat_data *)B_I_PITEM (bh, ih);
+        inode2sd (sd, inode);
+#ifdef CONFIG_REISERFS_RAW
+        if (ih->ih_item_len == RAW_SD_SIZE) {
+            ATTR_LASTREF(sd) = cpu_to_le32 (inode->u.reiserfs_i.lastref);
+            ATTR_EXPIRES(sd) = cpu_to_le32 (inode->u.reiserfs_i.expires);
+            ATTR_USER1(sd)   = cpu_to_le32 (inode->u.reiserfs_i.user1);
+        }
+#endif
     }
 
     return;
@@ -1131,21 +1150,61 @@ void reiserfs_read_inode2 (struct inode 
 }
 
 
+/*
+ * For fs mounted in raw mode, we want 64bit inode numbers (in raw
+ * mode they serve as filenames, and we want to minimize collision
+ * probability).  Hence the need for find_actor.  For non-raw fs it
+ * is not used, so no harm to efficiency.
+ */
+static int
+reiserfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
+{
+    struct reiserfs_iget4_args *args = opaque;
+    __u32 dir_id = args->objectid;
+
+    return (dir_id == INODE_PKEY(inode)->k_dir_id);
+}
+
 struct inode * reiserfs_iget (struct super_block * s, struct cpu_key * key)
 {
     struct inode * inode;
     struct reiserfs_iget4_args args ;
+    find_inode_t find_actor = reiserfs_raw(s)? reiserfs_find_actor : NULL;
 
     args.objectid = key->on_disk_key.k_dir_id ;
+    inode = iget4 (s, key->on_disk_key.k_objectid, find_actor, &args);
+#if 0
     inode = iget4 (s, key->on_disk_key.k_objectid, 0, (void *)(&args));
     if (!inode) 
       return inode ;
-
+    
     if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) {
-	/* either due to i/o error or a stale NFS handle */
-	iput (inode);
-	inode = 0;
+      /* either due to i/o error or a stale NFS handle */
+      iput (inode);
+      inode = 0;
     }
+#endif
+    if (inode && is_bad_inode (inode)) {
+        if (reiserfs_raw (inode->i_sb)) 
+            /* In RAW mode, query for nonexistent inode is part of
+               normal operation -- just like attempts to open
+               nonexistent file in normal mode.  If we iput() the
+               resulting bad inode as is, the inode will stay in
+               i-cache, which results in cluttering i-cache with bad
+               inodes.  To avoid that, we drop i_nlink so iput can
+               destroy the inode at once */
+            inode->i_nlink = 0;
+        else
+          /* In normal mode, bad inodes are rare exception */
+            reiserfs_warning ("vs-13048: reiserfs_iget: "
+                              "bad_inode. Stat data of (%lu %lu) not found\n",
+                              key->on_disk_key.k_dir_id, key->on_disk_key.k_objectid);
+        iput (inode);
+        inode = 0;
+    }
+    if (! inode)
+        inode = ERR_PTR (-ENOENT);
+    
     return inode;
 }
 
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/ioctl.c linux-kgdb/fs/reiserfs/ioctl.c
--- /usr/src/linux-2.4.9/fs/reiserfs/ioctl.c	Thu Mar 22 06:28:56 2001
+++ linux-kgdb/fs/reiserfs/ioctl.c	Sat Aug 25 20:21:43 2001
@@ -27,14 +27,73 @@
 int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
 		unsigned long arg)
 {
+    struct reiserfs_raw_ioctl_arg ra;
+    struct reiserfs_raw_ioctl_arg *user_ra = (struct reiserfs_raw_ioctl_arg *)arg;
+
 	switch (cmd) {
 	    case REISERFS_IOC_UNPACK:
 		if (arg)
 		    return reiserfs_unpack (inode, filp);
-			
+                return -ENOTTY;
+
+#ifdef CONFIG_REISERFS_RAW
+            case REISERFS_IOC_RAWSETATTR:
+                if (copy_from_user (&ra, user_ra, sizeof ra))
+                    return -EFAULT;
+                return reiserfs_rawsetattr_f (inode, &ra);
+#endif /* CONFIG_REISERFS_RAW */
+            
 	    default:
 		return -ENOTTY;
 	}
+}
+
+int reiserfs_dir_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
+                        unsigned long arg)
+{
+    struct reiserfs_raw_ioctl_arg ra;
+    struct reiserfs_raw_ioctl_arg *user_ra = (struct reiserfs_raw_ioctl_arg *)arg;
+    int r;
+
+    switch (cmd) {
+#ifdef CONFIG_REISERFS_RAW
+    case REISERFS_IOC_RAWOPEN:
+        if (copy_from_user (&ra, user_ra, sizeof ra))
+            return -EFAULT;
+        if ((r = reiserfs_rawopen (inode, filp->f_vfsmnt, &ra)) < 0)
+            return r;
+        if (copy_to_user (user_ra, &ra, sizeof ra))
+            return -EFAULT;
+        return r;               /* fd */
+
+    case REISERFS_IOC_RAWCREAT:
+        if (copy_from_user (&ra, user_ra, sizeof ra))
+            return -EFAULT;
+        return reiserfs_rawcreat (inode, filp->f_vfsmnt, &ra);
+
+    case REISERFS_IOC_RAWUNLINK:
+        if (copy_from_user (&ra, user_ra, sizeof ra))
+            return -EFAULT;
+        return reiserfs_rawunlink (inode, &ra);
+
+    case REISERFS_IOC_RAWSETATTR:
+        if (copy_from_user (&ra, user_ra, sizeof ra))
+            return -EFAULT;
+        return reiserfs_rawsetattr (inode, &ra);
+    case REISERFS_IOC_TIMEDWAIT:
+          {
+                struct reiserfs_sigtimedwait_arg sa;
+                if( copy_from_user
+                        ( &sa, 
+                          ( struct reiserfs_sigtimedwait_arg * ) arg, sizeof sa ) )
+                  return -EFAULT;
+                return reiserfs_sigtimedwait( inode, &sa );
+          }
+#endif /* CONFIG_REISERFS_RAW */
+
+    default:
+        return -EINVAL;
+    }
 }
 
 /*
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/objectid.c linux-kgdb/fs/reiserfs/objectid.c
--- /usr/src/linux-2.4.9/fs/reiserfs/objectid.c	Sat Apr 28 00:18:08 2001
+++ linux-kgdb/fs/reiserfs/objectid.c	Sat Aug 25 18:36:21 2001
@@ -170,9 +170,9 @@ void reiserfs_release_objectid (struct r
 	}
 	i += 2;
     }
-
-    reiserfs_warning ("vs-15010: reiserfs_release_objectid: tried to free free object id (%lu)", 
-		      objectid_to_release);
+    if (! reiserfs_raw (s))
+        reiserfs_warning ("vs-15010: reiserfs_release_objectid: tried to free free object id (%lu)", 
+                          objectid_to_release);
 }
 
 
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/pgc.c linux-kgdb/fs/reiserfs/pgc.c
--- /usr/src/linux-2.4.9/fs/reiserfs/pgc.c	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/fs/reiserfs/pgc.c	Sat Aug 25 19:50:45 2001
@@ -0,0 +1,459 @@
+/*
+ * fs/reiserfs/pgc.c
+ *
+ * "Passive garbage collector"
+ *
+ * Keeps disk usage within the bounds specified with pgc=L,H mount option
+ * by unlinking aged files from the blocks that pass through search_by_key.
+ * We never do any active disk scan to find aged files, we just remove them
+ * as they pass by, thus avoiding extra disk activity.
+
+   We might find it to be best to have all read-ahead reach memory
+   rather than staying in just the disk cache, so that PGC can occur
+   on it.  This would involve turning off disk read-ahead and doing it
+   in the FS.. -Hans
+
+ *
+ * Prototype by Nikita Danilov <nikitadanilov@yahoo.com>
+ * Rewritten for use with reiserfs_raw by Yury Shevchuk <sizif@botik.ru>
+ *
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ *
+ * $Id: pgc.c,v 1.1.4.14 2000/12/22 08:52:04 sizif Exp $ */
+
+#include <linux/fs.h>
+#include <linux/reiserfs_fs.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
+
+
+#define PGC_DEBUG_LEVEL 1
+#define pgc_debug(N, X) \
+  do { if ((N) <= PGC_DEBUG_LEVEL) reiserfs_warning X; } while (0)
+
+/* how often to re-calculate PGC threshold (in seconds) */
+#define PGC_THRESHOLD_PERIOD	 	1
+
+/* The size of the unlink queue.  It should be big enough to contain
+   max number of unlinks we can reap from a single reiserfs node, so
+   we did't lose unlinks.  Note that the q is processed on exit from
+   reiserfs_raw syscalls, and we should account for the possibility
+   of several concurrent processes filling it...  We can make it
+   considerably big, as they are few (one unlinkq per fs mount.) */
+#define PGC_UNLINKQ_SZ			(50 + PAGE_SIZE/RAW_SD_SIZE*50)
+
+/* Size of the rescan protection store */
+#define PGC_SCAN_RECENT_SZ	(MAX_HEIGHT*6 + 2)
+
+struct pgc {
+    unsigned long lo;			/* low water mark, blocks */
+    unsigned long hi;			/* high water mark, blocks */
+    time_t age_threshold;		/* remove files older than this */
+    unsigned long age_threshold_last;   /* last recalculation time (jiffies) */
+    struct age_class age;		/* age class table */
+    struct key unlinkq[PGC_UNLINKQ_SZ];	/* keys queued for unlink */
+    int unlinkq_count;			/* unlinkq filled slot count */
+    int scan_buffer_lock;		/* flag to inhibit scan_buffer
+                                           while processing unlinkq */
+    struct buffer_head *scan_recent[PGC_SCAN_RECENT_SZ];
+    int scan_recent_idx;
+};
+
+
+
+//static read_proc_t pgc_proc_read_age_class;
+static void pgc_shift_if_nec (struct reiserfs_transaction_handle *th);
+static time_t pgc_recalc_threshold_if_nec (struct super_block *sb);
+static void pgc_save_age_class (struct reiserfs_transaction_handle *th);
+static void pgc_restore_age_class (struct super_block *sb);
+static int  pgc_push_unlinkq (struct super_block *sb, struct key *);
+
+
+
+int
+pgc_init (struct super_block *sb)
+{
+    struct reiserfs_sb_info *rsi = &sb->u.reiserfs_sb;
+
+    rsi->pgc = reiserfs_kmalloc (sizeof (struct pgc), GFP_KERNEL, sb);
+    if (! rsi->pgc) {
+	pgc_debug (1, ("pgc_init: no mem for PGC control data for %s\n",
+		       bdevname (sb->s_dev)));
+	return -1;
+    }
+    rsi->pgc->unlinkq_count = 0;
+    rsi->pgc->scan_buffer_lock = 0;
+    rsi->pgc->scan_recent_idx = 0;
+    rsi->pgc->age_threshold = 0;
+    rsi->pgc->age_threshold_last = jiffies;
+
+    pgc_restore_age_class (sb);
+    if (! rsi->pgc->age.total)
+        age_class_init (&rsi->pgc->age, CURRENT_TIME);
+  //reiserfs_proc_register (sb, "age_class", pgc_proc_read_age_class);
+    return 0;
+}
+
+void
+pgc_cleanup (struct super_block *sb, struct reiserfs_transaction_handle *th)
+{
+    struct reiserfs_sb_info *rsi = &sb->u.reiserfs_sb;
+
+  //reiserfs_proc_unregister(sb, "age_class");
+    pgc_save_age_class (th);
+    reiserfs_kfree (rsi->pgc, sizeof (struct pgc), sb);
+}
+
+
+/* Convers PGC thresholds from per cents to block counts and store
+   them in the pgc info structure */
+
+void
+pgc_set_thresholds (struct super_block * s, int lo, int hi)
+{
+    struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
+    struct pgc *pgc = s->u.reiserfs_sb.pgc;
+
+    if (!pgc)
+	return;
+
+    pgc->lo = le32_to_cpu (rs->s_block_count)/100 * lo;
+    pgc->hi = le32_to_cpu (rs->s_block_count)/100 * hi;
+}
+
+
+
+/* The main function of PGC.  Scan reiserfs formatted node looking for
+   aged stat data; if found, unlink the files */
+
+void
+pgc_scan_buffer (struct super_block *sb, struct buffer_head *bh)
+{
+    struct reiserfs_sb_info *rsi = &sb->u.reiserfs_sb;
+    struct pgc *pgc = rsi->pgc;
+    time_t age_threshold;
+    int i;
+
+    if (! pgc) /* PGC disabled */
+	return;
+
+    /* not sure if we have the lock already.  Get it just in case. */
+    lock_kernel ();
+
+    /* Do nothing if called from pgc_process_unlinkq: these buffers
+       are likely scanned and all unlinkables in them are queued already */
+    if (++pgc->scan_buffer_lock > 1)
+	goto out;
+
+    /* When reiserfs_get_block works, we get the same buffer
+       repeatedly.  Remember the last buffer seen and don't rescan it.
+       More than that, remember several recently scanned buffers.  Or
+       else we get substantial number of repetitions in unlinkq, which
+       result in needless reiserfs_iget for already deleted inodes in
+       pgc_process_unlinkq */
+    i = PGC_SCAN_RECENT_SZ;
+    while (--i >= 0) {
+	if (bh == pgc->scan_recent[i])
+	    goto out;
+    }
+    if (--pgc->scan_recent_idx < 0)
+	pgc->scan_recent_idx = PGC_SCAN_RECENT_SZ-1;
+    pgc->scan_recent[pgc->scan_recent_idx] = bh;
+
+    age_threshold = pgc_recalc_threshold_if_nec (sb);
+    if (! age_threshold)
+	goto out;
+
+    for (i = 0; i < B_NR_ITEMS (bh); i++) {
+	struct item_head *ih = B_N_PITEM_HEAD (bh,i);
+
+	if (ih_item_len (ih) == RAW_SD_SIZE
+	    && ih_version (ih) == ITEM_VERSION_2
+	    && le16_to_cpu (ih->ih_key.u.k_offset_v2.k_type) == TYPE_STAT_DATA) {
+
+	    struct stat_data *sd = B_I_STAT_DATA (bh, ih);
+
+	    if (le32_to_cpu (ATTR_LASTREF (sd)) < age_threshold
+		|| le32_to_cpu (ATTR_EXPIRES (sd)) < CURRENT_TIME) {
+		/* Aged file, remove. */
+		pgc_debug (3, ("%s:%u: queuing unlink %k\n",
+			       __FILE__, __LINE__, &ih->ih_key));
+		/* However tempting it is to call reiserfs_rawunlink2
+		   right now, we will not.  It will attempt to create
+		   a transaction, while we are most likely inside an
+		   open transaction already.  If that open transaction
+		   is not joinable, journal_begin will sleep to let it
+		   finish, which means deadlock.  So queue it and
+		   remove later when we are for sure in user context. */
+		if (pgc_push_unlinkq (sb, &ih->ih_key) < 0)
+		    break;	/* queue overflow */
+	    }
+	}
+    }
+ out:
+    pgc->scan_buffer_lock--;
+    unlock_kernel ();
+}
+
+
+static int
+pgc_push_unlinkq (struct super_block *sb, struct key *kp)
+{
+    struct reiserfs_sb_info *rsi = &sb->u.reiserfs_sb;
+    struct pgc *pgc = rsi->pgc;
+
+    if (pgc->unlinkq_count >= PGC_UNLINKQ_SZ) {
+	reiserfs_warning ("pgc_push_unlinkq: queue full (%u), dropping victim\n",
+			  pgc->unlinkq_count);
+	return -1;
+    }
+
+    pgc->unlinkq[pgc->unlinkq_count++] = *kp;
+    return 0;
+}
+
+void
+pgc_process_unlinkq (struct super_block *sb)
+{
+    struct reiserfs_sb_info *rsi = &sb->u.reiserfs_sb;
+    struct pgc *pgc = rsi->pgc;
+    time_t age_threshold;
+    unsigned long starttime;
+
+    if (! pgc)			/* PGC disabled */
+	return;
+    if (! pgc->unlinkq_count)	/* nothing queued for unlink */
+	return;
+    if (pgc->scan_buffer_lock)	/* another pgc_process_unlinkq is active */
+	return;
+
+    age_threshold = pgc_recalc_threshold_if_nec (sb);
+    if (! age_threshold) {
+	/* No need for space anymore?  You're free, victims! */
+	pgc->unlinkq_count = 0;
+	return;
+    }
+
+    pgc->scan_buffer_lock++;
+    starttime = jiffies;
+
+    /* Process queue in LIFO order, so we hopefully use recently
+       cached things in CPU cache. */
+
+    while (pgc->unlinkq_count) {
+	struct key *kp = &pgc->unlinkq[--pgc->unlinkq_count];
+	struct cpu_key key;
+	struct inode *inode;
+
+				/* this is an indirect measure, we
+                                   should code to more directly avoid
+                                   doing disk I/O, and this should
+                                   become a debugging check we never
+                                   see, once you have the time to code
+                                   it....:-) -Hans */
+	if (jiffies - starttime > HZ/4) {
+	    /* Looks like the queue grew so long that the least recent
+	       keys got pushed from caches and unlinking them isn't
+	       cheap (probably involves disk access).  Purge the queue
+	       and go pick fresh victims */
+	    pgc_debug (2, ("pgc_process_unlinkq: 0.25s spent in unlinkq\n"));
+	    pgc->unlinkq_count = 0;
+	    break;
+	}
+
+	_make_cpu_key (&key, ITEM_VERSION_2,
+		       le32_to_cpu (kp->k_dir_id),
+		       le32_to_cpu (kp->k_objectid),
+		       SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
+				/* need an iget that refuses to read
+                                   disk if reading disk is necessary */
+	inode = reiserfs_iget (sb, &key);
+	if (IS_ERR (inode)) {	/* already deleted.  Was in the queue twice? */
+	    static int i = 0;
+	    i++;
+	    if ((i & (i-1)) == 0)
+		reiserfs_warning ("pgc_process_unlinkq: %u overunlinks total\n", i);
+	    continue;
+	}
+	/* check to make sure it didn't get accessed while sitting on
+	   the unlinkq, since if it did we should not unlink it. */
+	if (inode->u.reiserfs_i.lastref < age_threshold 
+	    || inode->u.reiserfs_i.expires < CURRENT_TIME) {
+	    reiserfs_rawunlink2 (inode);
+	}
+	else {
+	    /* someone referenced the file in the last second...
+	       let it go free */
+	    iput (inode);
+	}
+    }
+
+    pgc->scan_buffer_lock--;
+}
+
+
+/* Return the coarse-grained current time for use as lastref. */
+
+time_t
+pgc_current_time (struct super_block *sb)
+{
+    struct pgc *pgc = sb->u.reiserfs_sb.pgc;
+
+    if (! pgc)
+	return CURRENT_TIME;
+    return pgc->age.class[0].t + 1;
+}
+
+
+/* Update age class counters, and schedule the update to disk in the
+   same transaction which will write updated stat data of the inode
+   that caused the update */
+
+void
+pgc_age_class_update (struct reiserfs_transaction_handle *th,
+		      time_t old_lastref,
+		      time_t new_lastref)
+{
+    struct super_block *sb = th->t_super;
+    struct pgc *pgc = sb->u.reiserfs_sb.pgc;
+
+    if (! pgc)			/* PGC disabled */
+	return;
+    if (sb->s_flags & MS_RDONLY)
+	return;
+
+    pgc_shift_if_nec (th);
+    if (old_lastref) age_class_update (&pgc->age, old_lastref, -1);
+    if (new_lastref) age_class_update (&pgc->age, new_lastref, +1);
+    pgc_save_age_class (th);
+}
+
+
+/* Periodic class counter shift procedure.  First implementation
+   attempt used timers, but that implies the need for extensive
+   locking, so we'll better do this in user context. */
+
+static void
+pgc_shift_if_nec (struct reiserfs_transaction_handle *th)
+{
+    struct super_block *sb = th->t_super;
+    struct age_class *age = &sb->u.reiserfs_sb.pgc->age;
+
+    if (age->class[0].t >= CURRENT_TIME) /* recently shifted */
+	return;
+
+    if (age_class_shift (age, CURRENT_TIME))
+	pgc_save_age_class (th);
+}
+
+
+/* Periodic age threshold update procedure: calculates age_threshold
+   for GC based on current disk usage */
+
+static time_t
+pgc_recalc_threshold_if_nec (struct super_block *sb)
+{
+    struct reiserfs_sb_info *rsi = &sb->u.reiserfs_sb;
+    struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK (sb);
+    struct pgc *pgc = rsi->pgc;
+    unsigned long du = (le32_to_cpu (rs->s_block_count)
+			- le32_to_cpu (rs->s_free_blocks));
+    unsigned unlink_ratio;
+
+    if ((jiffies - pgc->age_threshold_last) < PGC_THRESHOLD_PERIOD*HZ)
+	goto out; /* don't recalculate too often. */
+
+    pgc_debug (2, ("%s:%u: used=%lu pgclo=%lu pgchi=%lu j=%lu, last=%lu\n",
+		   __FILE__, __LINE__, du, pgc->lo, pgc->hi,
+		   jiffies, pgc->age_threshold_last));
+
+    if (du < pgc->lo) {
+	/* low disk usage, no need to clean anything yet */
+	unlink_ratio = 0;
+	pgc->age_threshold = 0;
+    }
+    else {
+	/* When disk usage exceeds pgclo, we start removing; the
+	   closer to pgchi, the more aggressive.  At pgclo, we want to
+	   remove 5 files of 100 on the average, at pgchi we want to
+	   remove 95 files of 100.  TODO: see if the numbers are
+	   chosen well.  Make them configurable via /proc? */
+#define LO_RATIO 5
+#define HI_RATIO 95
+	unlink_ratio = (LO_RATIO
+			+ ((du - pgc->lo)
+			   * (HI_RATIO - LO_RATIO)
+			   / (pgc->hi - pgc->lo + 1/*avoid div by 0*/)));
+	if (unlink_ratio > HI_RATIO)
+	    unlink_ratio = HI_RATIO;
+
+	pgc->age_threshold =
+	    age_class_threshold (&pgc->age, unlink_ratio, CURRENT_TIME);
+    }
+
+    pgc->age_threshold_last = jiffies;
+
+    pgc_debug (2, ("%s:%u: unlink_ratio=%lu, set age_threshold=%lu\n",
+		   __FILE__, __LINE__,
+		   unlink_ratio, pgc->age_threshold));
+ out:
+    return pgc->age_threshold;
+}
+
+
+
+/* proc read routine for /proc/fs/reiserfs/XXX/age_class */
+/*
+static int
+pgc_proc_read_age_class (char *buffer, char **start, off_t offset,
+			 int count, int *eof, void *data)
+{
+    struct super_block *sb = (void *) data;
+    struct reiserfs_sb_info *rsi = &sb->u.reiserfs_sb;
+    int len = 0;
+
+    len += sprintf (&buffer[len], "Age threshold: %lu\n",
+		    rsi->pgc->age_threshold);
+
+    age_class_dump (&rsi->pgc->age, CURRENT_TIME, &buffer[len], PAGE_SIZE-len);
+    len = strlen (buffer);
+
+    if (offset >= len) {
+	*start = buffer;
+	*eof = 1;
+	return 0;
+    }
+    *start = buffer + offset;
+    if ((len -= offset) > count)
+	return count;
+    *eof = 1;
+    return len;
+}
+*/
+
+static void
+pgc_save_age_class (struct reiserfs_transaction_handle *th)
+{
+    struct super_block *sb = th->t_super;
+    struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK (sb);
+    struct age_class *age = &sb->u.reiserfs_sb.pgc->age;
+    struct buffer_head *sbh = SB_BUFFER_WITH_SB (sb);
+
+    if (sb->s_flags & MS_RDONLY)
+	return;
+    reiserfs_prepare_for_journal (sb, sbh, 1) ;
+    /* update super block. TODO: should use cpu_to_le32 */
+    memcpy (rs->s_unused, age, sizeof (struct age_class));
+    journal_mark_dirty (th, sb, sbh);
+}
+
+static void
+pgc_restore_age_class (struct super_block *sb)
+{
+    struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK (sb);
+    struct age_class *age = &sb->u.reiserfs_sb.pgc->age;
+
+    /* TODO: should use le32_to_cpu */
+    memcpy (age, rs->s_unused, sizeof (struct age_class));
+}
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/raw.c linux-kgdb/fs/reiserfs/raw.c
--- /usr/src/linux-2.4.9/fs/reiserfs/raw.c	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/fs/reiserfs/raw.c	Sat Aug 25 17:18:42 2001
@@ -0,0 +1,639 @@
+/*
+ * fs/reiserfs/raw.c
+ *
+ * "Raw" reiserfs tree interface: access files by their objectid,
+ * bypassing directories.
+ *
+ * The primary target of this is Squid proxy cache acceleration,
+ * but it may have other uses, who knows.
+ *
+ * See Documentation/filesystems/reiserfs_raw.txt for more details.
+ *
+ * Idea from Nikita Danilov <nikitadanilov@yahoo.com>
+ * Written by Yury Shevchuk <sizif@botik.ru>
+ *
+ * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
+ *
+ * $Id: raw.c,v 1.1.2.16 2000/12/22 08:52:04 sizif Exp $
+ */
+
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/reiserfs_fs.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+
+static struct inode * reiserfs_raw_new_inode (struct reiserfs_transaction_handle *th,
+					      struct inode *dir,
+					      struct cpu_key *key,
+					      struct inode *inode,
+					      struct reiserfs_raw_ioctl_arg *ra,
+					      int * err);
+static void reiserfs_raw_id_correct (struct reiserfs_raw_ioctl_arg *ra);
+
+
+/* Create raw file.  Arguments are a directory inode (used only to
+   find superblock, so you can opendir() any directory on the fs), and
+   the user arguments structure (see reiserfs_fs.h) */
+
+int
+reiserfs_rawcreat (struct inode * dir, struct vfsmount *mnt,
+		   struct reiserfs_raw_ioctl_arg *ra)
+{
+    struct super_block *sb = dir->i_sb;
+    struct file *filp;
+    struct inode *inode;
+    struct dentry *dentry;
+    struct cpu_key key;
+    struct reiserfs_transaction_handle th;
+    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2;
+    int windex;
+    int error;
+    int fd;
+
+    if (! reiserfs_raw (sb))
+	return -EPERM;
+    if (INODE_PKEY(dir)->k_objectid != REISERFS_ROOT_OBJECTID ||
+	INODE_PKEY(dir)->k_dir_id != REISERFS_ROOT_PARENT_OBJECTID)
+	return -EPERM;
+    if ((error = permission (dir, MAY_WRITE)))
+	return error;
+
+    fd = get_unused_fd();
+    if (fd < 0)
+	return fd;
+
+    /*
+     * Along the lines of reiserfs_create, but don't reiserfs_add_entry
+     */
+
+    inode = get_empty_inode() ;
+    if (!inode) {
+	error = -ENOMEM;
+	goto cleanup_fd;
+    }
+
+    journal_begin (&th, sb, jbegin_count) ;
+    windex = push_journal_writer("rawcreat") ;
+
+    /* make key for new stat data */
+    reiserfs_raw_id_correct (ra);
+    _make_cpu_key (&key, ITEM_VERSION_2,
+		   le32_to_cpu (ra->id1),
+		   le32_to_cpu (ra->id2),
+		   SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
+    inode = reiserfs_raw_new_inode (&th, dir, &key, inode, ra, &error);
+    if (!inode)
+	goto cleanup_journal;	/* reiserfs_new_inode iput()s on error */
+	
+    inode->i_op = &reiserfs_file_inode_operations;
+    inode->i_fop = &reiserfs_file_operations;
+    inode->i_mapping->a_ops = &reiserfs_address_space_operations ;
+
+    /* Now we need to build the file structure.  This is normally done
+       using filp_open(), but that would go through namei and require
+       a filename which we don't have.  So we create a dummy dentry,
+       which is very conveniently done using d_alloc_root().  We don't
+       put the dentry in the dentry hash: it has no name and is
+       useless there.  It will be freed on file close: fput -> __fput
+       -> dput */
+
+    dentry = d_alloc_root(inode);
+    if (! dentry)
+	goto cleanup_inode;
+
+    filp = dentry_open(dentry, mntget(mnt), O_RDWR);
+    error = PTR_ERR(filp);
+    if (IS_ERR(filp))
+	goto cleanup_inode;
+
+    pop_journal_writer(windex) ;
+    journal_end(&th, sb, jbegin_count) ;
+
+    pgc_process_unlinkq (sb);
+    fd_install(fd, filp);
+    return fd;
+
+ cleanup_inode:
+    iput (inode);
+ cleanup_journal:
+    pop_journal_writer(windex) ;
+    journal_end(&th, sb, jbegin_count) ;
+    pgc_process_unlinkq (sb);
+ cleanup_fd:
+    put_unused_fd (fd);
+    return error;
+}
+
+/* Open raw file.  rawopen opens a file by key (not filename), and also
+   returns some of the file attributes (the ones squid wants).  This
+   choice of attributes is squid specific optimization, and users are
+   encouraged to ask us to generalize this interface for other
+   applications.  
+
+   Arguments are a directory inode (must be the root directory of the
+   fs mounted with -o raw), and the user arguments structure (see
+   reiserfs_fs.h) */
+
+int
+reiserfs_rawopen (struct inode * dir, struct vfsmount *mnt,
+		  struct reiserfs_raw_ioctl_arg *ra)
+{
+    int error;
+    struct cpu_key key;
+    struct file *filp;
+    struct inode *inode;
+    struct dentry *dentry;
+    struct super_block *sb = dir->i_sb;
+    int fd;
+
+    if (! reiserfs_raw (sb))
+	return -EPERM;
+    if (INODE_PKEY(dir)->k_objectid != REISERFS_ROOT_OBJECTID ||
+	INODE_PKEY(dir)->k_dir_id != REISERFS_ROOT_PARENT_OBJECTID)
+	return -EPERM;
+    if ((error = permission (dir, MAY_EXEC)))
+	return error;
+
+    fd = get_unused_fd();
+    if (fd < 0)
+	return fd;
+
+    reiserfs_raw_id_correct (ra);
+    _make_cpu_key (&key, ITEM_VERSION_2,
+		   le32_to_cpu (ra->id1),
+		   le32_to_cpu (ra->id2),
+		   SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
+    inode = reiserfs_iget (sb, &key);
+    if (IS_ERR (inode)) {
+	error = PTR_ERR (inode);
+	goto cleanup_fd;
+    }
+    if (!inode->i_nlink) {	/* unlinked */
+	/* reiserfs_read_inode2 should have caught such inode */
+	reiserfs_warning ("sizif-174: iget fetched unlinked file?\n");
+	goto cleanup_inode;
+    }
+
+    dentry = d_alloc_root(inode);
+    if (! dentry) {
+        error = -ENOMEM;
+	goto cleanup_inode;
+    }
+
+    filp = dentry_open(dentry, mntget(mnt), O_RDWR);
+    error = PTR_ERR(filp);
+    if (IS_ERR(filp))
+	goto cleanup_inode;
+
+    ra->lastref = inode->u.reiserfs_i.lastref;
+    ra->expires	= inode->u.reiserfs_i.expires;
+    ra->user1	= inode->u.reiserfs_i.user1;
+    ra->size    = inode->i_size;
+
+    /* lastref update is relatively expensive.  Don't do it if not
+       using PGC. */
+    if (sb->u.reiserfs_sb.pgc) {
+	time_t _pgc_current_time = pgc_current_time (sb);
+	if (inode->u.reiserfs_i.lastref != _pgc_current_time) {
+	    /*
+	     * Write out stat data and age counters in one transaction
+	     */
+	    int windex ;
+	    struct reiserfs_transaction_handle th ;
+	    int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
+	
+	    journal_begin (&th, sb, jbegin_count) ;
+	    windex = push_journal_writer("rawopen");
+	    inode->u.reiserfs_i.lastref = _pgc_current_time;
+	    pgc_age_class_update (&th, ra->lastref, inode->u.reiserfs_i.lastref);
+	    reiserfs_update_sd (&th, inode);
+	    pop_journal_writer (windex) ;
+	    journal_end (&th, sb, jbegin_count) ;
+	}
+    }
+
+    pgc_process_unlinkq (sb);
+    fd_install(fd, filp);
+    return fd;
+
+ cleanup_inode:
+    iput (inode);
+ cleanup_fd:
+    pgc_process_unlinkq (sb);
+    put_unused_fd (fd);
+    return error;
+}
+
+
+/* Set attributes for raw file. */
+
+int
+reiserfs_rawsetattr (struct inode * dir, struct reiserfs_raw_ioctl_arg *ra)
+{
+    struct super_block * sb = dir->i_sb;
+    struct cpu_key key;
+    struct inode *inode;
+    int ret;
+
+    if (! reiserfs_raw (sb))
+	return -EPERM;
+    if ((current->fsuid != dir->i_uid) && !capable(CAP_FOWNER))
+	return -EACCES;
+    if (! ra->lastref)
+	return -EINVAL;	/* 0 is special for pgc_age_class_update */
+    if (INODE_PKEY(dir)->k_objectid != REISERFS_ROOT_OBJECTID ||
+	INODE_PKEY(dir)->k_dir_id != REISERFS_ROOT_PARENT_OBJECTID)
+	return -EPERM;
+
+    reiserfs_raw_id_correct (ra);
+    _make_cpu_key (&key, ITEM_VERSION_2,
+		   le32_to_cpu (ra->id1),
+		   le32_to_cpu (ra->id2),
+		   SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
+    inode = reiserfs_iget (sb, &key);
+    if (IS_ERR (inode))
+	return PTR_ERR (inode);
+
+    ret = reiserfs_rawsetattr2 (inode, ra);
+
+    iput (inode);
+    return ret;
+}
+
+	
+/* Set attributes for open raw file. */
+
+int
+reiserfs_rawsetattr_f (struct inode * inode, struct reiserfs_raw_ioctl_arg *ra)
+{
+    struct super_block * sb = inode->i_sb;
+
+    if (! reiserfs_raw (sb))
+	return -EPERM;
+    if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+	return -EACCES;
+    if (! ra->lastref)
+	return -EINVAL;	/* 0 is special for pgc_age_class_update */
+    if (! inode->u.reiserfs_i.lastref) /* not a raw file */
+	return -EPERM;
+
+    return reiserfs_rawsetattr2 (inode, ra);
+}
+
+
+/* Common part of reiserfs_rawsetattr{,_f} */
+
+int
+reiserfs_rawsetattr2 (struct inode * inode, struct reiserfs_raw_ioctl_arg *ra)
+{
+    struct super_block * sb = inode->i_sb;
+    int dirty = 0;
+    int lastref_dirty = 0;
+    unsigned old_lastref = 0;
+
+    if (inode->u.reiserfs_i.lastref != ra->lastref) {
+	old_lastref = inode->u.reiserfs_i.lastref;
+	inode->u.reiserfs_i.lastref = ra->lastref;
+	lastref_dirty = 1;
+    }
+    if (inode->u.reiserfs_i.expires != ra->expires) {
+	inode->u.reiserfs_i.expires = ra->expires;
+	dirty = 1;
+    }
+    if (inode->u.reiserfs_i.user1 != ra->user1) {
+	inode->u.reiserfs_i.user1 = ra->user1;
+	dirty = 1;
+    }
+
+    if (lastref_dirty) {
+	/*
+	 * Write out stat data and age counters in one transaction
+	 */
+	int windex ;
+	struct reiserfs_transaction_handle th ;
+	int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
+	
+	journal_begin (&th, sb, jbegin_count) ;
+	windex = push_journal_writer("rawsetattr");
+	pgc_age_class_update (&th, old_lastref, inode->u.reiserfs_i.lastref);
+	reiserfs_update_sd (&th, inode);
+	pop_journal_writer (windex) ;
+	journal_end (&th, sb, jbegin_count) ;
+    }
+    else if (dirty) {
+	/* lastref unchanged -- no age class update.  Somebody else
+           will take care of it. */
+	mark_inode_dirty(inode);
+    }
+
+    pgc_process_unlinkq (sb);
+    return 0;
+}
+
+
+
+/* Unlink raw file. */
+
+int
+reiserfs_rawunlink (struct inode * dir, struct reiserfs_raw_ioctl_arg *ra)
+{
+    struct super_block *sb = dir->i_sb;
+    struct cpu_key key;
+    int error;
+
+    if (! reiserfs_raw (sb))
+	return -EPERM;
+    if (INODE_PKEY(dir)->k_objectid != REISERFS_ROOT_OBJECTID ||
+	INODE_PKEY(dir)->k_dir_id != REISERFS_ROOT_PARENT_OBJECTID)
+	return -EPERM;
+    if ((error = permission (dir, MAY_WRITE)))
+	return error;
+
+    reiserfs_raw_id_correct (ra);
+    _make_cpu_key (&key, ITEM_VERSION_2,
+		   le32_to_cpu (ra->id1),
+		   le32_to_cpu (ra->id2),
+		   SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
+    error = reiserfs_rawunlink2 (reiserfs_iget (sb, &key));
+
+    pgc_process_unlinkq (sb);
+    return error;
+}
+
+
+/* The bottom part of reiserfs_rawunlink, also used by pgc_process_unlinkq */
+
+int
+reiserfs_rawunlink2 (struct inode * inode)
+{
+    if (IS_ERR (inode))
+	return PTR_ERR (inode);
+    if (!inode->u.reiserfs_i.lastref) {
+	/* Not a raw file.  Unlinking it the way we do would leave
+           dangling directory entry, so disallow that */
+	iput (inode);
+	return -EINVAL;
+    }
+    if (!inode->i_nlink) {
+        reiserfs_warning ("sizif-380: iget fetched unlinked file? (from %p)\n",
+			  __builtin_return_address(0));
+	goto iput_and_out;	/* already deleted */
+    }
+    inode->i_nlink--;
+    if (inode->i_nlink != 0) {
+	reiserfs_warning ("sizif-385: raw file with i_nlink=%d?\n", inode->i_nlink+1);
+	goto iput_and_out;
+    }
+
+    /* Actually we need more work here.  Suppose process P1 has a file
+       open.  Another process (P2) tries to create a file with the
+       same id, gets EEXIST, and responds as squid/butterfly would by
+       issuing unlink() to get the file out of the way.  This will
+       result in i_nlink going to zero, but inode will still be in
+       inode cache, and its stat data on the disk will be intact until
+       P1 closes the file.  So if P2 retries its file creation attempt
+       right after the unlink(), it will still get EEXIST!  This
+       weirdness is due to the absence of directories.  One solution
+       might be to sleep in create() waiting for file to be removed,
+       but that's smelling like Windows... */
+
+    /*
+     * Write out stat data and age counters in one transaction
+     */
+    {
+	int windex ;
+	struct reiserfs_transaction_handle th ;
+	int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3; 
+	struct super_block *sb = inode->i_sb;
+
+	journal_begin (&th, sb, jbegin_count) ;
+	windex = push_journal_writer("rawunlink2");
+	pgc_age_class_update (&th, inode->u.reiserfs_i.lastref, 0);
+	reiserfs_update_sd (&th, inode);
+	pop_journal_writer (windex) ;
+	journal_end (&th, sb, jbegin_count) ;
+    }
+
+ iput_and_out:
+    iput (inode);
+    return 0;
+}
+
+
+/* Our simplified reiserfs_new_inode ().  The differences are:
+ *  * we accept pre-generated SD key
+ *  * we only create regular files, so skipping directory/symlink handling
+ *  * we set inode attributes from supplied data
+
+This needs to be changed to use its own stat data item type with fewer
+fields, but this is not a priority.  There are hacks in here that will
+become cleaner code if we use a new item type instead of engaging in
+some pretense of using an older stat data item type. -Hans
+
+  */
+static struct inode *
+reiserfs_raw_new_inode (struct reiserfs_transaction_handle *th,
+			struct inode *dir,
+			struct cpu_key *key,
+			struct inode *inode,
+			struct reiserfs_raw_ioctl_arg *ra,
+			int * err)
+{
+    struct super_block *sb = dir->i_sb;
+    INITIALIZE_PATH (path_to_key);
+    char sdbuf[RAW_SD_SIZE];
+    struct stat_data *sd = (void *)sdbuf;
+    struct item_head ih;
+    int retval;
+
+    /* We only work with new format */
+    if (old_format_only (sb)) {
+        /* "cannot happen": we should have caught this when mounting
+           in raw mode */
+	reiserfs_warning ("sizif-453: 3.5 superblock?\n");
+	*err = -EFAULT;
+	iput(inode) ;
+	return NULL;
+    }
+
+    inode->i_sb = sb;
+    inode->i_flags = 0;
+
+    /* item head of new item */
+    ih.ih_key.k_dir_id = key->on_disk_key.k_dir_id;
+    ih.ih_key.k_objectid = key->on_disk_key.k_objectid;
+    make_le_item_head (&ih, 0, ITEM_VERSION_2, SD_OFFSET, TYPE_STAT_DATA,
+		       RAW_SD_SIZE, MAX_US_INT);
+
+    retval = search_item (sb, key, &path_to_key);
+    if (retval == IO_ERROR) {
+	iput (inode);
+	*err = -EIO;
+	return NULL;
+    }
+    if (retval == ITEM_FOUND) {
+	pathrelse (&path_to_key);
+	iput (inode);
+	*err = -EEXIST;
+	return NULL;
+    }
+
+    /* fill stat data */
+    inode->i_mode = S_IFREG|0600;
+    inode->i_nlink = 1;
+    inode->i_uid = current->fsuid;
+    inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid: current->fsgid;
+
+    inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+    inode->i_size = 0;
+    inode->i_blocks = 0;
+    inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;
+    inode2sd (sd, inode);
+
+    inode->u.reiserfs_i.lastref = pgc_current_time (sb);
+    inode->u.reiserfs_i.expires = ra->expires;
+    inode->u.reiserfs_i.user1   = ra->user1;
+    ATTR_LASTREF(sd) = cpu_to_le32 (inode->u.reiserfs_i.lastref);
+    ATTR_EXPIRES(sd) = cpu_to_le32 (ra->expires);
+    ATTR_USER1(sd)   = cpu_to_le32 (ra->user1);
+
+    // these do not go to on-disk stat data
+    inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid);
+    inode->i_dev = sb->s_dev;
+    inode->i_blksize = sb->s_blocksize;
+    memcpy (INODE_PKEY (inode), &(ih.ih_key), KEY_SIZE);
+    inode_items_version (inode) = ITEM_VERSION_2;
+
+    /* insert the stat data into the tree */
+    retval = reiserfs_insert_item (th, &path_to_key, key, &ih, sdbuf);
+    if (retval) {
+	iput (inode);
+	*err = retval;
+	reiserfs_check_path(&path_to_key) ;
+	return NULL;
+    }
+
+    pgc_age_class_update (th, 0, inode->u.reiserfs_i.lastref);
+
+    /* TODO? inode->i_generation = INODE_PKEY (inode)->k_dir_id; */
+    insert_inode_hash (inode);
+    reiserfs_check_path(&path_to_key) ;
+    return inode;
+}
+
+/* Remap known bad ids to some other ids.  Thus we avoid the "id
+   cannot be created even if you remove old file with this id"
+   situation, at the price of increasing collision probability for the
+   ids that we remap to.  */
+
+static void
+reiserfs_raw_id_correct (struct reiserfs_raw_ioctl_arg *ra)
+{
+    if (ra->id1 == REISERFS_ROOT_PARENT_OBJECTID &&
+	ra->id2 == REISERFS_ROOT_OBJECTID) {
+	ra->id1 += 12345;
+    }
+#define SAFESAFE
+#ifdef SAFESAFE
+    if (ra->id1 <= 1) ra->id1 += 2;
+    if (ra->id2 <= 1) ra->id2 += 2;
+#else
+    /* bravely assuming [0,0], etc. are OK */
+#endif
+}
+
+
+/* The following is a good stuff but should REALLY be moved out of
+   here.  It is unrelated to reiserfs.  --sizif */
+
+/* non-portable extension of sigtimedwait to get many siginfo's per
+   one call.  Probably will improve (K)AIO performance.  
+*/
+int
+reiserfs_sigtimedwait(struct inode * dir, struct reiserfs_sigtimedwait_arg *arg)
+{
+  int i;
+  int ret, sig;
+  sigset_t these;
+  struct timespec ts;
+  siginfo_t info;
+  long timeout = 0;
+  
+  if( arg -> uinfos <= 0 )
+	{
+	  return -EINVAL;
+	}
+
+  /* XXX: Don't preclude handling different sized sigset_t's.  */
+  if( arg -> sigsetsize != sizeof( sigset_t ) )
+	return -EINVAL;
+
+  if( copy_from_user( &these, arg -> uthese, sizeof( these ) ) )
+	return -EFAULT;
+		
+  /*
+   * Invert the set of allowed signals to get those we
+   * want to block.
+   */
+  sigdelsetmask(&these, sigmask(SIGKILL)|sigmask(SIGSTOP));
+  signotset(&these);
+
+  timeout = MAX_SCHEDULE_TIMEOUT;
+  if( arg -> uts ) {
+	if( copy_from_user( &ts, arg -> uts, sizeof( ts ) ) )
+	  return -EFAULT;
+	if( ts.tv_nsec >= 1000000000L || ts.tv_nsec < 0 || ts.tv_sec < 0)
+	  return -EINVAL;
+  }
+
+  ret = 0;
+  for( i = 0 ; i < arg -> uinfos ; ++i )
+	{
+	  spin_lock_irq(&current->sigmask_lock);
+	  sig = dequeue_signal(&these, &info);
+	  /* sleep, but only for the first time */
+	  if (!sig && !i) 
+		{
+		  /* None ready -- temporarily unblock those we're interested
+			 in so that we'll be awakened when they arrive.  */
+		  timeout = (timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec));
+		  if( timeout )
+			{
+			  sigset_t oldblocked = current->blocked;
+			  sigandsets(&current->blocked, &current->blocked, &these);
+			  recalc_sigpending(current);
+			  spin_unlock_irq(&current->sigmask_lock);
+
+			  current->state = TASK_INTERRUPTIBLE;
+			  timeout = schedule_timeout(timeout);
+	
+			  spin_lock_irq(&current->sigmask_lock);
+			  sig = dequeue_signal(&these, &info);
+			  recalc_sigpending(current);
+			  current->blocked = oldblocked;
+			}
+		}
+	  spin_unlock_irq(&current->sigmask_lock);
+
+	  if (sig) {
+		ret = i + 1;
+		if( arg -> uinfo ) {
+		  if (copy_to_user( &arg -> uinfo[ i ], &info, sizeof info))
+			{
+			  ret = -EFAULT;
+			  break;
+			}
+		}
+	  } else {
+		if( i == 0 )
+		  {
+			ret = -EAGAIN;
+			if (timeout)
+			  ret = -EINTR;
+		  }
+		break;
+	  }
+	}
+  return ret;
+}
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/stree.c linux-kgdb/fs/reiserfs/stree.c
--- /usr/src/linux-2.4.9/fs/reiserfs/stree.c	Sat Jul 21 20:20:56 2001
+++ linux-kgdb/fs/reiserfs/stree.c	Sat Aug 25 18:41:48 2001
@@ -734,6 +734,15 @@ int search_by_key (struct super_block * 
 	    return IO_ERROR;
 	}
 
+#ifdef CONFIG_REISERFS_RAW
+        /* PGC: glance through the buffer looking for aged files' stat
+           data.  If any found, we'll remove them at once.  */
+        if (p_s_sb->u.reiserfs_sb.pgc
+            && B_LEVEL (p_s_bh) == DISK_LEAF_NODE_LEVEL) {
+            pgc_scan_buffer (p_s_sb, p_s_bh);
+        }
+#endif /* CONFIG_REISERFS_RAW */
+
 	/* It is possible that schedule occurred. We must check whether the key
 	   to search is still in the tree rooted from the current buffer. If
 	   not then repeat search from the root. */
diff -rupN /usr/src/linux-2.4.9/fs/reiserfs/super.c linux-kgdb/fs/reiserfs/super.c
--- /usr/src/linux-2.4.9/fs/reiserfs/super.c	Sat Jul 21 20:20:00 2001
+++ linux-kgdb/fs/reiserfs/super.c	Sun Aug 26 00:15:29 2001
@@ -112,7 +112,11 @@ void reiserfs_put_super (struct super_bl
     s->u.reiserfs_sb.s_rs->s_state = le16_to_cpu (s->u.reiserfs_sb.s_mount_state);
     journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
   }
-
+#ifdef CONFIG_REISERFS_RAW
+  if (s->u.reiserfs_sb.pgc)
+      pgc_cleanup (s, (s->s_flags & MS_RDONLY)? NULL: &th);
+#endif
+    
   /* note, journal_release checks for readonly mount, and can decide not
   ** to do a journal_end
   */
@@ -154,13 +158,21 @@ struct super_operations reiserfs_sops = 
 
 };
 
+/* return values from parse_options */
+struct mount_options
+{
+   unsigned long blocks;       /* arg of resize= */
+   int pgclo;                  /* 1st arg of pgc=, low threshold */
+   int pgchi;                  /* 2nd arg of pgc=, high threshold */
+};
+
 /* this was (ext2)parse_options */
-static int parse_options (char * options, unsigned long * mount_options, unsigned long * blocks)
+static int parse_options (char * options, unsigned long * mount_options, struct mount_options * mop)
 {
     char * this_char;
     char * value;
   
-    *blocks = 0;
+    memset (mop, 0, sizeof (*mop));
     if (!options)
 	/* use default configuration: create tails, journaling on, no
            conversion to newest format */
@@ -193,7 +205,7 @@ static int parse_options (char * options
 	    set_bit (REPLAYONLY, mount_options);
 	} else if (!strcmp (this_char, "resize")) {
 	    if (value && *value){
-		*blocks = simple_strtoul (value, &value, 0);
+		mop->blocks = simple_strtoul (value, &value, 0);
 	    } else {
 	  	printk("reiserfs: resize option requires a value\n");
 		return 0;
@@ -222,6 +234,29 @@ static int parse_options (char * options
 	  	printk("reiserfs: hash option requires a value\n");
 		return 0 ;
 	    }
+#ifdef CONFIG_REISERFS_RAW
+        } else if (!strcmp (this_char, "raw")) {
+            set_bit (REISERFS_RAW, mount_options);
+        } else if (!strcmp (this_char, "pgc")) {
+            if (! value) {
+            pgc_usage:
+                printk("reiserfs: Usage: pgc=LOW,HIGH\n");
+                return 0;
+            }
+            mop->pgclo = simple_strtoul (value, &value, 10);
+            if (*value != '\0')
+                goto pgc_usage;
+            value = strtok (NULL, ",");
+            if (!value)
+                goto pgc_usage;
+            mop->pgchi = simple_strtoul (value, &value, 10);
+            if (mop->pgclo <= 0 || mop->pgchi < mop->pgclo || mop->pgchi > 100) {
+                printk("reiserfs: pgc: bad parameters\n");
+                return 0;
+            }
+            if (*value != '\0')
+                goto pgc_usage;
+#endif /* CONFIG_REISERFS_RAW */
 	} else {
 	    printk ("reiserfs: Unrecognized mount option %s\n", this_char);
 	    return 0;
@@ -247,20 +282,24 @@ int reiserfs_remount (struct super_block
 {
   struct reiserfs_super_block * rs;
   struct reiserfs_transaction_handle th ;
-  unsigned long blocks;
+  struct mount_options mo;
   unsigned long mount_options;
 
   rs = SB_DISK_SUPER_BLOCK (s);
 
-  if (!parse_options(data, &mount_options, &blocks))
+  if (!parse_options(data, &mount_options, &mo))
   	return 0;
 
-  if(blocks) {
-      int rc = reiserfs_resize(s, blocks);
+  if(mo.blocks) {
+      int rc = reiserfs_resize(s, mo.blocks);
       if (rc != 0)
 	  return rc;
   }
-
+#if defined( CONFIG_REISERFS_RAW )
+  if (mo.pgclo)
+      pgc_set_thresholds (s, mo.pgclo, mo.pgchi);
+#endif
+    
   if ((unsigned long)(*flags & MS_RDONLY) == (s->s_flags & MS_RDONLY)) {
     /* there is nothing to do to remount read-only fs as read-only fs */
     return 0;
@@ -687,18 +726,18 @@ struct super_block * reiserfs_read_super
     extern int *blksize_size[];
     struct reiserfs_transaction_handle th ;
     int old_format = 0;
-    unsigned long blocks;
+    struct mount_options mo;
     int jinit_done = 0 ;
     struct reiserfs_iget4_args args ;
 
 
     memset (&s->u.reiserfs_sb, 0, sizeof (struct reiserfs_sb_info));
 
-    if (parse_options ((char *) data, &(s->u.reiserfs_sb.s_mount_opt), &blocks) == 0) {
+    if (parse_options ((char *) data, &(s->u.reiserfs_sb.s_mount_opt), &mo) == 0) {
 	return NULL;
     }
 
-    if (blocks) {
+    if (mo.blocks) {
   	printk("reserfs: resize option for remount only\n");
 	return NULL;
     }	
@@ -768,7 +807,11 @@ struct super_block * reiserfs_read_super
 	iput(root_inode);
 	goto error;
     }
-
+    if (reiserfs_raw(s) && old_format_only(s)) {
+        printk ("-o raw cannot be used with reiserfs < 3.6\n");
+        goto error;
+    }
+    
     // define and initialize hash function
     s->u.reiserfs_sb.s_hash_function = hash_function (s);
     if (s->u.reiserfs_sb.s_hash_function == NULL) {
@@ -821,6 +864,14 @@ struct super_block * reiserfs_read_super
 
     init_waitqueue_head (&(s->u.reiserfs_sb.s_wait));
 
+#ifdef CONFIG_REISERFS_RAW
+    if (mo.pgclo) {
+        if (pgc_init (s) < 0)
+          goto error;
+       pgc_set_thresholds (s, mo.pgclo, mo.pgchi);
+    }
+#endif
+    
     printk("%s\n", reiserfs_get_version_string()) ;
     return s;
 
diff -rupN /usr/src/linux-2.4.9/fs/super.c linux-kgdb/fs/super.c
--- /usr/src/linux-2.4.9/fs/super.c	Sat Aug 11 15:52:46 2001
+++ linux-kgdb/fs/super.c	Sun Aug 26 19:26:28 2001
@@ -700,6 +700,7 @@ void sync_supers(kdev_t dev)
 		}
 		return;
 	}
+        /* KERNEL_ASSERT("kernel lock not held", KA_HELD_GKL()); */
 restart:
 	spin_lock(&sb_lock);
 	sb = sb_entry(super_blocks.next);
@@ -728,6 +729,7 @@ struct super_block * get_super(kdev_t de
 {
 	struct super_block * s;
 
+	/* KERNEL_ASSERT("kernel lock not held", KA_HELD_GKL()); */
 	if (!dev)
 		return NULL;
 restart:
diff -rupN /usr/src/linux-2.4.9/include/asm/errno.h linux-kgdb/include/asm/errno.h
--- /usr/src/linux-2.4.9/include/asm/errno.h	Fri Feb  9 21:40:02 2001
+++ linux-kgdb/include/asm/errno.h	Sun Aug 26 01:06:23 2001
@@ -129,4 +129,8 @@
 #define	ENOMEDIUM	123	/* No medium found */
 #define	EMEDIUMTYPE	124	/* Wrong medium type */
 
+#if defined(CONFIG_AIO)
+#define ECANCELED	125	/* Async I/O: operation canceled */
+#endif /* CONFIG_AIO */
+
 #endif
diff -rupN /usr/src/linux-2.4.9/include/asm/ioctls.h linux-kgdb/include/asm/ioctls.h
--- /usr/src/linux-2.4.9/include/asm/ioctls.h	Fri Jul 24 21:10:16 1998
+++ linux-kgdb/include/asm/ioctls.h	Sun Aug 26 18:21:42 2001
@@ -67,6 +67,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define TIOCGDB         0x547F  /* enable GDB stub mode on this tty */
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -rupN /usr/src/linux-2.4.9/include/asm/page.h linux-kgdb/include/asm/page.h
--- /usr/src/linux-2.4.9/include/asm/page.h	Fri Aug 24 00:13:23 2001
+++ linux-kgdb/include/asm/page.h	Sun Aug 26 18:40:11 2001
@@ -86,10 +86,14 @@ typedef struct { unsigned long pgprot; }
  * Tell the user there is some problem. Beep too, so we can
  * see^H^H^Hhear bugs in early bootup as well!
  */
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#define BUG() KGDB_ASSERT("BUG", 0)
+#else
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 	__asm__ __volatile__(".byte 0x0f,0x0b"); \
 } while (0)
+#endif
 
 #define PAGE_BUG(page) do { \
 	BUG(); \
diff -rupN /usr/src/linux-2.4.9/include/asm/processor.h linux-kgdb/include/asm/processor.h
--- /usr/src/linux-2.4.9/include/asm/processor.h	Fri Aug 24 00:23:39 2001
+++ linux-kgdb/include/asm/processor.h	Sun Aug 26 18:40:11 2001
@@ -379,6 +379,9 @@ struct thread_struct {
 /* IO permissions */
 	int		ioperm;
 	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	struct pt_regs *kgdbregs;
+#endif
 };
 
 #define INIT_THREAD  {						\
diff -rupN /usr/src/linux-2.4.9/include/asm/unistd.h linux-kgdb/include/asm/unistd.h
--- /usr/src/linux-2.4.9/include/asm/unistd.h	Fri Aug 11 23:39:23 2000
+++ linux-kgdb/include/asm/unistd.h	Sun Aug 26 01:06:23 2001
@@ -228,6 +228,10 @@
 #define __NR_getdents64		220
 #define __NR_fcntl64		221
 
+#if defined(CONFIG_AIO)
+#define __NR_aio		251
+#endif
+
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
 #define __syscall_return(type, res) \
diff -rupN /usr/src/linux-2.4.9/include/asm-i386/errno.h linux-kgdb/include/asm-i386/errno.h
--- /usr/src/linux-2.4.9/include/asm-i386/errno.h	Fri Feb  9 21:40:02 2001
+++ linux-kgdb/include/asm-i386/errno.h	Sun Aug 26 01:06:23 2001
@@ -129,4 +129,8 @@
 #define	ENOMEDIUM	123	/* No medium found */
 #define	EMEDIUMTYPE	124	/* Wrong medium type */
 
+#if defined(CONFIG_AIO)
+#define ECANCELED	125	/* Async I/O: operation canceled */
+#endif /* CONFIG_AIO */
+
 #endif
diff -rupN /usr/src/linux-2.4.9/include/asm-i386/ioctls.h linux-kgdb/include/asm-i386/ioctls.h
--- /usr/src/linux-2.4.9/include/asm-i386/ioctls.h	Fri Jul 24 21:10:16 1998
+++ linux-kgdb/include/asm-i386/ioctls.h	Sun Aug 26 18:21:42 2001
@@ -67,6 +67,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define TIOCGDB         0x547F  /* enable GDB stub mode on this tty */
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -rupN /usr/src/linux-2.4.9/include/asm-i386/page.h linux-kgdb/include/asm-i386/page.h
--- /usr/src/linux-2.4.9/include/asm-i386/page.h	Fri Aug 24 00:13:23 2001
+++ linux-kgdb/include/asm-i386/page.h	Sun Aug 26 18:40:11 2001
@@ -86,10 +86,14 @@ typedef struct { unsigned long pgprot; }
  * Tell the user there is some problem. Beep too, so we can
  * see^H^H^Hhear bugs in early bootup as well!
  */
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#define BUG() KGDB_ASSERT("BUG", 0)
+#else
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 	__asm__ __volatile__(".byte 0x0f,0x0b"); \
 } while (0)
+#endif
 
 #define PAGE_BUG(page) do { \
 	BUG(); \
diff -rupN /usr/src/linux-2.4.9/include/asm-i386/processor.h linux-kgdb/include/asm-i386/processor.h
--- /usr/src/linux-2.4.9/include/asm-i386/processor.h	Fri Aug 24 00:23:39 2001
+++ linux-kgdb/include/asm-i386/processor.h	Sun Aug 26 18:40:11 2001
@@ -379,6 +379,9 @@ struct thread_struct {
 /* IO permissions */
 	int		ioperm;
 	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	struct pt_regs *kgdbregs;
+#endif
 };
 
 #define INIT_THREAD  {						\
diff -rupN /usr/src/linux-2.4.9/include/asm-i386/unistd.h linux-kgdb/include/asm-i386/unistd.h
--- /usr/src/linux-2.4.9/include/asm-i386/unistd.h	Fri Aug 11 23:39:23 2000
+++ linux-kgdb/include/asm-i386/unistd.h	Sun Aug 26 01:06:23 2001
@@ -228,6 +228,10 @@
 #define __NR_getdents64		220
 #define __NR_fcntl64		221
 
+#if defined(CONFIG_AIO)
+#define __NR_aio		251
+#endif
+
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
 #define __syscall_return(type, res) \
diff -rupN /usr/src/linux-2.4.9/include/linux/age_class.h linux-kgdb/include/linux/age_class.h
--- /usr/src/linux-2.4.9/include/linux/age_class.h	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/include/linux/age_class.h	Sun Aug 26 01:06:23 2001
@@ -0,0 +1,69 @@
+/*
+ * include/linux/age_class.h
+ *
+ * Class LRU routines for file aging and replacement.
+ *
+ * Written by Yury Shevchuk <sizif@botik.ru>
+ *
+ * Copyright 2000 Hans Reiser, see reiserfs/README for licensing and copyright details
+ *
+ * $Id: age_class.h,v 1.1.2.5 2000/10/08 11:49:02 lim Exp $
+ */
+
+#ifndef __AGE_CLASS_H__
+#define __AGE_CLASS_H__
+
+/*
+ *
+ * Class LRU routines
+ * 
+ * 
+ * Class LRU control structure is a small array of counters.  Each
+ * counter counts files whose timestamp falls within the time interval
+ * associated with this counter:
+ *
+ *                    time interval    file count
+ * Age class 0:   curtime...t[0]          c[0]
+ * Age class 1:      t[0]...t[1]          c[1]
+ * Age class 2:      t[1]...t[2]          c[2]
+ * Age class 3:      t[2]...t[3]          c[3]
+ * Age class 4:      t[3]...t[4]          c[4]
+ * ...
+ *
+ * In normal operation, c[0] is incremented with every file
+ * create/open.  When the counter grows above 1/AGE_CLASS_COUNT of the
+ * total number of files, age_class_shift shifts age class boundaries
+ * leaving class 0 with c[0] == 0 and t[0] == curtime.  The shift
+ * procedure tends to maintain more or less equal size classes.
+ * 
+ * This compact counter structure provides a replacement for expensive
+ * true LRU list.  By knowing the age distribution, we can compute
+ * reasonable age threshold and then scan the store (either actively or
+ * passively) removing all files older than that.  */
+
+#include <linux/types.h>
+
+#define AGE_CLASS_COUNT		15 /* was 32; lowered to make it fit
+				      in zeroed s_unused in reiserfs
+				      superblock */
+
+typedef
+struct age_class {
+    unsigned total;	/* sum of class[*].c: total number of files in
+			   this fs */
+    struct {
+	unsigned c;	/* count of files in this class */
+	time_t t; 	/* low time boundary: files with timestamp>=t
+			   but less than class[-1].t belong to this class */
+    } class[AGE_CLASS_COUNT];
+} age_class;
+
+void   age_class_init (age_class *a, time_t curtime);
+void   age_class_update (age_class *a, time_t time, int inc);
+int    age_class_find (age_class *a, time_t time);
+int    age_class_shift (age_class *a, time_t curtime);
+char * age_class_dump (age_class *a, time_t curtime, char *buf, int bufsz);
+time_t age_class_threshold (age_class *a, unsigned ratio, time_t curtime);
+
+
+#endif /* __AGE_CLASS_H__ */
diff -rupN /usr/src/linux-2.4.9/include/linux/aio.h linux-kgdb/include/linux/aio.h
--- /usr/src/linux-2.4.9/include/linux/aio.h	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/include/linux/aio.h	Sun Aug 26 18:54:55 2001
@@ -0,0 +1,322 @@
+#ifndef _LINUX_AIO_H
+#define _LINUX_AIO_H
+/*
+ * A kernel implementation of POSIX Asynchronous I/O facility (KAIO).
+ *
+ * Copyright 1999, Silicon Graphics, Inc.
+ *
+ * Written October 1999 by Rajagopal Ananthanarayanan (ananth)
+ *  			at Silicon Graphics, Inc.
+ */
+
+/*
+ * User code gets access to AIO by simply including this header file.
+ * CONFIG_AIO has to be explicitly turned on for the kernel.
+ */
+
+#ifndef __KERNEL__
+#define CONFIG_AIO
+#endif
+
+#if defined(CONFIG_AIO)
+
+#ifdef __KERNEL__
+#include <asm/siginfo.h>
+#else
+#include <sys/types.h> 		/* off_t, etc. 				*/
+#include <signal.h>		/* sigevent_t, etc. 			*/
+#endif
+
+/*
+ * Default & maximum number of threads to be used for processing
+ * parts of aio request. Number of threads can be changed using the
+ * environment variable below.
+ */
+
+#define AIO_THREAD_ENVIRON	"AIO_NTHREADS"
+#define AIO_DEFAULT_THREADS 	 4
+/* #define AIO_MAX_THREADS		64 */
+#define AIO_MAX_THREADS		(1024-100)
+
+#define AIO_TIMES	8
+#define AIO_RESERVED	4
+
+#define KAIO_STATS
+
+/*
+ * User code can turn on 64-bit offsets in aiocb by:
+ * 	#define _FILE_OFFSET_BITS 64
+ *	#include <features.h>
+ *	#include <linux/aio.h>
+ * which will turn all aio_*() interfaces to operate with 64-bit offsets.
+ * 
+ * Further, #define _LARGEFILE64_SOURCE will enable LFS style aio_*64()
+ * interfaces. Important note: <features.h> should be included as
+ * the first file in a code module, for the above to work correctly.
+ * See <features.h> for further details.
+ *
+ * An alternate way to turn on 64-bit offsets in aiocb is to:
+ *	#define AIO_FILE_OFFSET64
+ *	#include <linux/aio.h>
+ * Similarly LFS interfaces can be enabled by:
+ *	#define AIO_LARGEFILE64
+ *	#include <linux/aio.h>
+ * 
+ * The kernel always uses 64-bit offset values. If user code does not
+ * enable 64-bit offsets, the library will suitably zero out the padding.
+ */
+typedef struct aiocb {
+	int		aio_fildes;	/* File descriptor to perform aio  */ 
+	void		*aio_buf;	/* User's data buffer 		   */
+	size_t		aio_nbytes;	/* No. of bytes in transfer 	   */
+#if defined(__USE_FILE_OFFSET64) || defined(AIO_FILE_OFFSET64) || defined(__KERNEL__)
+	loff_t		aio_offset;
+#else
+	off_t		aio_offset;	/* File position to begin transfer */
+	char		__aio_pad[sizeof(loff_t) - sizeof(off_t)];
+#endif
+	int		aio_reqprio;	/* Unused - Reserved 		   */
+	sigevent_t	aio_sigevent;	/* Notification Options 	   */
+	int		aio_lio_opcode; /* lio_listio opcode 		   */
+	unsigned long	aio_reserved[AIO_RESERVED];/* Don't use this 		   */
+#ifdef KAIO_STATS
+	unsigned long	aio_times[AIO_TIMES];
+#endif
+} aiocb_t;
+
+
+#if defined(__USE_LARGEFILE64) || defined(AIO_LARGEFILE64)
+typedef struct aiocb64 {
+	int		aio_fildes;	/* File descriptor to perform aio  */ 
+	void		*aio_buf;	/* User's data buffer 		   */
+	size_t		aio_nbytes;	/* No. of bytes in transfer 	   */
+	loff_t		aio_offset;	/* File offset - 64 bits	   */
+	int		aio_reqprio;	/* Unused - Reserved 		   */
+	sigevent_t	aio_sigevent;	/* Notification Options 	   */
+	int		aio_lio_opcode; /* lio_listio opcode 		   */
+	unsigned long	aio_reserved[AIO_RESERVED];/* Don't use this 		   */
+#ifdef KAIO_STATS
+	unsigned long	aio_times[AIO_TIMES];
+#endif
+} aiocb64_t;
+#endif
+
+/*
+ * Internal to the aio library
+ */
+#define AIOCMD_READ		1
+#define AIOCMD_SUSPEND		2
+#define AIOCMD_CANCEL		3
+#define AIOCMD_RETURN		4
+#define AIOCMD_PCINVALIDATE	5	/* invalidate page cache	   */
+#define AIOCMD_SLAVE		6	/* put a slave in wait for request */
+#define AIOCMD_WRITE		7
+#define AIOCMD_GENERIC_READ	8 	/* Reserved for internal use	   */
+#define AIOCMD_LIST_IO		9
+#define AIOCMD_IOCTL            10
+#define AIOCMD_CLOSE            11
+
+/*
+ * For gathering timing statistics.
+ */
+/*
+#define AIOTIME_REQUEST		0
+#define AIOTIME_IO		1
+#define AIOTIME_COPY		2
+*/
+#define AIOTIME_REQUEST         0 /* (userspace) before aio_* */
+#define AIOTIME_ENQUEUED        1 /* kaiocb created */
+#define AIOTIME_DEQUEUED        2 /* request dequeued by a slave */
+#define AIOTIME_IO              3 /* i/o finished */
+#define AIOTIME_COPY            4 /* copying to userspace finshed */
+#define AIOTIME_COMPLETE        6 /* in kaio_io_complete */
+#define AIOTIME_FINISH          7 /* (userspace) noticed op completion */
+
+#if !defined(__USE_FILE_OFFSET64) && !defined(AIO_FILE_OFFSET64)
+/*
+ * Procedural interfaces.
+ */
+int 	aio_read(struct aiocb *aiocbp);
+int 	aio_write(struct aiocb *aiocbp);
+ssize_t	aio_return(struct aiocb *aiocbp);
+int	aio_cancel(int fildes, struct aiocb *aiocbp);
+int	aio_fsync(int op, struct aiocb *aiocbp);
+int	aio_suspend(const struct aiocb *const list[],
+			 int nent, const struct timespec *timeout);
+int 	lio_listio(int mode, struct aiocb *const list[],
+			int nent, struct sigevent *sig);
+int     aio_ioctl(struct aiocb *aiocbp);
+int     aio_close(struct aiocb *aiocbp);
+#else
+# ifdef __REDIRECT
+extern int __REDIRECT (aio_read, __P ((struct aiocb *__aiocbp)), aio_read64);
+extern int __REDIRECT (aio_write, __P ((struct aiocb *__aiocbp)), aio_write64);
+extern int __REDIRECT (lio_listio, __P ((int __mode,
+		     struct aiocb *__const __restrict __list[],
+		     int __nent, struct sigevent *__restrict __sig)), lio_listio64);
+extern __ssize_t __REDIRECT (aio_return, __P ((struct aiocb *__aiocbp)), aio_return64);
+extern int __REDIRECT (aio_cancel, __P ((int __fildes, struct aiocb *__aiocbp)),
+		       aio_cancel64);
+extern int __REDIRECT (aio_suspend,
+		       __P ((__const struct aiocb *__const __restrict __list[],
+			     int __nent,
+			     __const struct timespec *__restrict __timeout)),
+		       aio_suspend64);
+#else
+#define aio_read aio_read64
+#define aio_write aio_write64
+#define lio_listio lio_listio64
+#define aio_return aio_return64
+#define aio_cancel aio_cancel64
+#define aio_suspend aio_suspend64
+#endif
+#endif
+
+#define aio_error(a)	(volatile int)(a)->aio_reserved[2]
+/*
+ * 64-bit interfaces.
+ */
+#if defined(__USE_LARGEFILE64) || defined(AIO_LARGEFILE64)
+int 	aio_read64(struct aiocb64 *aiocbp);
+int 	aio_write64(struct aiocb64 *aiocbp);
+ssize_t	aio_return64(struct aiocb64 *aiocbp);
+int	aio_cancel64(int fildes, struct aiocb64 *aiocbp);
+int	aio_fsync64(int op, struct aiocb64 *aiocbp);
+#define aio_error64(a)	aio_error(a)
+int	aio_suspend64(const struct aiocb64 *const list[],
+			 int nent, const struct timespec *timeout);
+int 	lio_listio64(int mode, struct aiocb64 *const list[],
+			int nent, struct sigevent *sig);
+int     aio_ioctl64(struct aiocb64 *aiocbp);
+int     aio_close64(struct aiocb64 *aiocbp);
+#endif
+
+/*
+ * Return values for aio_cancel.
+ */
+#define AIO_CANCELED		1
+#define AIO_NOTCANCELED		2
+#define AIO_ALLDONE		3
+
+/*
+ * Listio modes
+ */
+#define LIO_WAIT		1
+#define LIO_NOWAIT		2
+
+
+/*
+ * Listio opcodes
+ */
+#define LIO_READ		1
+#define LIO_WRITE		2
+#define LIO_NOP			3
+
+#ifdef __KERNEL__
+
+#if defined(CONFIG_RAW)
+#include <linux/iobuf.h>
+/*
+ * Interfaces expected from Raw I/O for AIO.
+ */
+extern	int kaio_is_raw(struct file *);
+extern	int kaio_raw_wait(void *, struct kiobuf *);
+extern	void *kaio_raw_rw(int, struct file *, char *, size_t, loff_t *, 
+			  int *, struct semaphore *, struct kiobuf *);
+#endif
+
+typedef struct liocb {
+	spinlock_t 	 lio_lock; 	/* protects nent manipulation	   */
+	int	   	 lio_nent; 	/* number of kaio's being awaited  */
+	int	   	 lio_done; 	/* number of kaio's completed	   */
+	wait_queue_head_t lio_wait;	/* wait here for completion of lio */
+	struct sigevent	   lio_sigevent;/* completeion signal info, if any */
+	struct task_struct *lio_task;	/* requesting task		   */
+	int		 lio_mode;	/* mode used in request 	   */
+} liocb_t;
+
+typedef struct kaiocb {
+
+	struct file	*kaio_filp;	/* held by an fget() 		*/
+	void		*kaio_buf;	/* user's data buffer */
+	size_t		kaio_nbytes;
+	aiocb_t		*kaio_uaiocb; /* user aiocb for this request  */
+
+	/* 0x10 */
+	loff_t		kaio_offset;
+	int 		kaio_cmd;	/* read / write 		*/
+	int		kaio_error;
+
+	/* 0x20 */
+	int		kaio_id;	/* unique id for this kaiocb	*/
+	struct kaiocb	*kaio_h_next;	/* hash table pointer		*/
+	struct kaiocb	**kaio_h_pprev;	/* hash table pointer		*/
+	struct page 	**kaio_pages;	/* list of kernel pages   	*/
+
+	/* 0x30 */
+	int		kaio_npages; 	/* no. of kernel pages 	  	*/
+	liocb_t		*kaio_liocb; 	/* List I/O control block pointer */
+	wait_queue_head_t *kaio_suspend_wait;	/* wait here on kaio_suspend */
+	struct page 	*kaio_page_inline; /* one page optimization	*/
+
+	/* 0x40 */
+	struct list_head   kaio_ioq;	/* pointers for queueing aio 	*/
+	struct task_struct *kaio_task;	/* requesting task		*/
+	void		   *kaio_kq;	/* kaioq  of requesting task	*/
+
+	/* 0x50 */
+	sigevent_t	kaio_sigevent;	/* Notification Options		*/
+
+#if defined(CONFIG_RAW)
+	/* RAW I/O fields */
+	struct semaphore kaio_sem;	/* for use by raw I/O		*/
+	struct kiobuf 	 kaio_iobuf; 	/* for use by raw I/O		*/
+	void 		 *kaio_scp;	/* cookie returned by raw I/O   */
+#endif
+
+        int             kaio_fd;        /* original fd, for AIOCMD_<syscall> */
+
+#ifdef KAIO_STATS
+	unsigned long	kaio_times[AIO_TIMES];
+#define kaio_set_time(k, x) 	(k)->kaio_times[(x)] = kaio_time()
+#else
+#define kaio_set_time(k, x)
+#endif /* KAIO_STATS */
+
+} kaiocb_t;
+
+
+typedef struct kaio_key {
+	int	kaio_kid;
+	void	*kaio_kq;
+} kaio_key_t;
+
+
+#define aio_key		aio_reserved[0]
+/* 	aio_key[1]	aio_reserved[1] */
+
+#undef aio_error	/* don't want user definition which is a function */
+#define aio_error	aio_reserved[2]
+#define aio_return	aio_reserved[3]
+
+extern int kaio_rw(int cmd, struct aiocb *, liocb_t *);
+extern int kaio_syscall(int cmd, struct aiocb *);
+extern int kaio_list_io(int, struct aiocb *[], int, sigevent_t *);
+extern int kaio_suspend(aiocb_t *[], int, struct timespec *, int);
+extern int kaio_cancel(int, kaio_key_t *);
+extern void kaio_init(void);
+extern void kaio_slave(void);
+extern void kaio_q_create(struct task_struct *);
+
+
+/*
+ * Prefix for the names of slave threads
+ */
+#define KAIO_SLAVE_NAME		"kaiod-"
+#define KAIO_SLAVE_NAMELEN	6
+
+#endif /* __KERNEL__ */
+
+#endif /* CONFIG_AIO */
+
+#endif /* _LINUX_AIO_H */
diff -rupN /usr/src/linux-2.4.9/include/linux/dcache.h linux-kgdb/include/linux/dcache.h
--- /usr/src/linux-2.4.9/include/linux/dcache.h	Fri Aug 24 00:23:39 2001
+++ linux-kgdb/include/linux/dcache.h	Sun Aug 26 18:40:11 2001
@@ -4,6 +4,7 @@
 #ifdef __KERNEL__
 
 #include <asm/atomic.h>
+#include <linux/gdb.h>
 #include <linux/mount.h>
 
 /*
diff -rupN /usr/src/linux-2.4.9/include/linux/gdb.h linux-kgdb/include/linux/gdb.h
--- /usr/src/linux-2.4.9/include/linux/gdb.h	Thu Jan  1 03:00:00 1970
+++ linux-kgdb/include/linux/gdb.h	Sun Aug 26 18:40:11 2001
@@ -0,0 +1,67 @@
+#ifndef _GDB_H_
+#define _GDB_H_
+
+/*
+ * Copyright (C) 2001 Amit S. Kale
+ */
+
+/* gdb locks */
+#define KGDB_MAX_NO_CPUS 8
+
+extern int gdb_enter;	/* 1 = enter debugger on boot */
+extern int gdb_ttyS;
+extern int gdb_baud;
+extern int gdb_initialized;
+
+extern int gdb_hook(void);
+extern void breakpoint(void);
+
+typedef int     gdb_debug_hook(int trapno,
+                               int signo,
+                               int err_code,
+                               struct pt_regs *regs);
+extern gdb_debug_hook  *linux_debug_hook;
+
+#ifdef CONFIG_SMP
+extern spinlock_t kgdb_spinlock;
+extern spinlock_t kgdb_nmispinlock;
+#else
+extern unsigned kgdb_spinlock;
+extern unsigned kgdb_nmispinlock;
+#endif
+
+extern volatile int kgdb_memerr_expected;
+
+struct console;
+void gdb_console_write(struct console *co, const char *s,
+				unsigned count);
+void gdb_console_init(void);
+
+extern volatile int procindebug[KGDB_MAX_NO_CPUS];
+
+#define KGDB_ASSERT(message, condition)	do {			\
+	if (!(condition)) {					\
+		printk("kgdb assertion failed: %s\n", message); \
+		asm ("int $0x3");				\
+	}							\
+} while (0)
+
+#ifdef CONFIG_KERNEL_ASSERTS
+#define KERNEL_ASSERT(message, condition) KGDB_ASSERT(message, condition)
+#else
+#define KERNEL_ASSERT(message, condition)
+#endif
+
+#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
+
+#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
+
+#define KA_VALID_KPTR(ptr)  (!(ptr) ||	\
+	       ((void *)(ptr) >= (void *)PAGE_OFFSET &&  \
+	       (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
+
+#define KA_VALID_PTRORERR(errptr) (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
+
+#define KA_HELD_GKL()	(current->lock_depth >= 0)
+
+#endif /* _GDB_H_ */
diff -rupN /usr/src/linux-2.4.9/include/linux/mount.h linux-kgdb/include/linux/mount.h
--- /usr/src/linux-2.4.9/include/linux/mount.h	Sat Aug 11 15:52:51 2001
+++ linux-kgdb/include/linux/mount.h	Sun Aug 26 18:21:42 2001
@@ -30,8 +30,11 @@ struct vfsmount
 
 static inline struct vfsmount *mntget(struct vfsmount *mnt)
 {
-	if (mnt)
+	if (mnt) {
+		KERNEL_ASSERT("mount_count wrong",
+			atomic_read(&mnt->mnt_count) > 0);
 		atomic_inc(&mnt->mnt_count);
+	}
 	return mnt;
 }
 
diff -rupN /usr/src/linux-2.4.9/include/linux/reiserfs_fs.h linux-kgdb/include/linux/reiserfs_fs.h
--- /usr/src/linux-2.4.9/include/linux/reiserfs_fs.h	Fri Aug 24 01:36:23 2001
+++ linux-kgdb/include/linux/reiserfs_fs.h	Sun Aug 26 19:02:37 2001
@@ -118,6 +118,7 @@
 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
 #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
 
+#ifdef __KERNEL__
 static inline int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
 {
     return (!strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING, 
@@ -125,6 +126,7 @@ static inline int is_reiserfs_magic_stri
 	    !strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, 
 		      strlen ( REISER2FS_SUPER_MAGIC_STRING)));
 }
+#endif /* __KERNEL__ */
 
 				/* ReiserFS leaves the first 64k unused,
                                    so that partition labels have enough
@@ -466,7 +468,7 @@ static inline __u32 type2uniqueness (int
     return V1_ANY_UNIQUENESS;
 }
 
-
+#ifdef __KERNEL__
 //
 // key is pointer to on disk key which is stored in le, result is cpu,
 // there is no way to get version of object from key, so, provide
@@ -530,7 +532,7 @@ static inline void set_le_ih_k_type (str
 #define is_indirect_le_ih(ih) is_indirect_le_key (ih_version(ih), &((ih)->ih_key))
 #define is_statdata_le_ih(ih) is_statdata_le_key (ih_version (ih), &((ih)->ih_key))
 
-
+#endif /* __KERNEL__ */
 
 //
 // key is pointer to cpu key, result is cpu
@@ -722,6 +724,8 @@ struct stat_data {
 				       based on sd_size and our tail
 				       suppression policy? */
   } __attribute__ ((__packed__)) u;
+    int more[0];                /* reference point for extensions
+                                   like raw attributes below */
 } __attribute__ ((__packed__));
 //
 // this is 40 bytes long
@@ -730,6 +734,25 @@ struct stat_data {
 
 #define stat_data_v1(ih) (ih_version (ih) == ITEM_VERSION_1)
 
+/*
+ * Reiserfs-raw keeps its extra attributes in stat data.  There is no
+ * place for them in struct stat_data, and I don't want to add
+ * additional fields to the disk structure -- normal files don't need
+ * these extra attributes, so we use the following trick.  For raw
+ * files, we create enlargened SD item, and keep our attribute values
+ * just after stat data structure.  Here are macros to access them.
+ * Remember they are in le32 layout.
+ */
+struct raw_attr {
+    __u32 lastref;
+    __u32 expires;
+    __u32 user1;
+};
+#define ATTR_LASTREF(SD)        (((struct raw_attr *)(SD)->more)->lastref)
+#define ATTR_EXPIRES(SD)        (((struct raw_attr *)(SD)->more)->expires)
+#define ATTR_USER1(SD)          (((struct raw_attr *)(SD)->more)->user1)
+#define RAW_SD_SIZE             (sizeof(struct stat_data) + \
+                                 sizeof(struct raw_attr))
 
 /***************************************************************************/
 /*                      DIRECTORY STRUCTURE                                */
@@ -826,6 +849,7 @@ struct reiserfs_de_head
 #define de_visible(deh)	    	    test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
 #define de_hidden(deh)	    	    !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
 
+#ifdef __KERNEL__
 /* compose directory item containing "." and ".." entries (entries are
    not aligned to 4 byte boundary) */
 static inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
@@ -932,7 +956,7 @@ static inline int entry_length (struct b
 // two entries per block (at least)
 #define REISERFS_MAX_NAME_LEN(block_size) 255
 
-
+#endif /* __KERNEL__ */
 
 
 /* this structure is used for operations on directory entries. It is
@@ -1135,6 +1159,7 @@ struct path var = {ILLEGAL_PATH_ELEMENT_
 
 ///#define TOO_LONG_LENGTH		(~0ULL)
 
+#ifdef __KERNEL__
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
 #define U32_MAX (~(__u32)0)
 static inline loff_t max_reiserfs_offset (struct inode * inode)
@@ -1144,7 +1169,7 @@ static inline loff_t max_reiserfs_offset
 
     return (loff_t)((~(__u64)0) >> 4);
 }
-
+#endif /* __KERNEL__ */
 
 /*#define MAX_KEY_UNIQUENESS	MAX_UL_INT*/
 #define MAX_KEY_OBJECTID	MAX_UL_INT
@@ -1397,6 +1422,7 @@ struct buffer_info {
 +-------------------+------------+--------------+------------+
 */
 
+#ifdef __KERNEL__ 
 struct item_operations {
     int (*bytes_number) (struct item_head * ih, int block_size);
     void (*decrement_key) (struct cpu_key *);
@@ -1430,7 +1456,7 @@ extern struct item_operations * item_ops
 #define op_unit_num(vi)				     item_ops[(vi)->vi_index]->unit_num (vi)
 #define op_print_vi(vi)                              item_ops[(vi)->vi_index]->print_vi (vi)
 
-
+#endif /* __KERNEL__ */
 
 
 
@@ -1544,9 +1570,10 @@ struct reiserfs_journal_header {
   __u32 j_first_unflushed_offset ;      /* offset in the log of where to start replay after a crash */
   __u32 j_mount_id ;
 } ;
-
+#ifdef __KERNEL__
 extern task_queue reiserfs_commit_thread_tq ;
 extern wait_queue_head_t reiserfs_commit_thread_wait ;
+#endif /* __KERNEL__ */
 
 /* biggest tunable defines are right here */
 #define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */
@@ -1580,6 +1607,7 @@ extern wait_queue_head_t reiserfs_commit
 */
 #define JOURNAL_BUFFER(j,n) ((j)->j_ap_blocks[((j)->j_start + (n)) % JOURNAL_BLOCK_COUNT])
 
+#ifdef __KERNEL__
 void reiserfs_wait_on_write_block(struct super_block *s) ;
 void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ;
 void reiserfs_allow_writes(struct super_block *s) ;
@@ -1773,12 +1801,15 @@ int reiserfs_prepare_write(struct file *
 void reiserfs_truncate_file(struct inode *, int update_timestamps) ;
 void make_cpu_key (struct cpu_key * cpu_key, const struct inode * inode, loff_t offset,
 		   int type, int key_length);
+void _make_cpu_key (struct cpu_key * key, int version, __u32 dirid, __u32 objectid, 
+                    loff_t offset, int type, int length);
 void make_le_item_head (struct item_head * ih, struct cpu_key * key, int version,
 			       loff_t offset, int type, int length, int entry_count);
 /*void store_key (struct key * key);
 void forget_key (struct key * key);*/
 int reiserfs_get_block (struct inode * inode, long block,
 			struct buffer_head * bh_result, int create);
+void inode2sd (void * sd, struct inode * inode);
 struct inode * reiserfs_iget (struct super_block * s, struct cpu_key * key);
 void reiserfs_read_inode (struct inode * inode) ;
 void reiserfs_read_inode2(struct inode * inode, void *p) ;
@@ -1944,6 +1975,47 @@ __u32 r5_hash (const char *msg, int len)
 
 /* version.c */
 char *reiserfs_get_version_string(void) ;
+#endif /* __KERNEL__ */
+
+/* raw.c */
+struct reiserfs_raw_ioctl_arg {
+    __u32 id1;          /* object id of the obj to operate on (low part) */
+    __u32 id2;          /* object id of the obj to operate on (high part) */
+    __u32 lastref;      /* last reference date (a la atime) */
+    __u32 expires;      /* expiration date */
+    __u32 user1;        /* user attribute, not used by the kernel */
+    loff_t size;        /* file size returned by RAWOPEN */
+};
+
+struct reiserfs_sigtimedwait_arg {
+  sigset_t        *uthese;
+  size_t           sigsetsize;
+  siginfo_t       *uinfo; 
+  size_t           uinfos;
+  struct timespec *uts;
+};
+
+#ifdef __KERNEL__
+int reiserfs_rawopen (struct inode *, struct vfsmount *, struct reiserfs_raw_ioctl_arg *);
+int reiserfs_rawcreat (struct inode *, struct vfsmount *, struct reiserfs_raw_ioctl_arg *);
+int reiserfs_rawsetattr (struct inode *, struct reiserfs_raw_ioctl_arg *);
+int reiserfs_rawsetattr_f (struct inode *, struct reiserfs_raw_ioctl_arg *);
+int reiserfs_rawsetattr2 (struct inode *, struct reiserfs_raw_ioctl_arg *);
+int reiserfs_rawunlink (struct inode *, struct reiserfs_raw_ioctl_arg *);
+int reiserfs_rawunlink2 (struct inode *);
+int reiserfs_sigtimedwait(struct inode *, struct reiserfs_sigtimedwait_arg *);
+
+/* pgc.c */
+int  pgc_init (struct super_block *sb);
+void pgc_cleanup (struct super_block *, struct reiserfs_transaction_handle *);
+void pgc_set_thresholds (struct super_block *, int, int);
+void pgc_scan_buffer (struct super_block *sb, struct buffer_head *bh);
+void pgc_age_class_update (struct reiserfs_transaction_handle *th,
+                           time_t old_lastref, time_t new_lastref);
+void pgc_process_unlinkq (struct super_block *sb);
+time_t pgc_current_time (struct super_block *sb);
+
+#endif /*__KERNEL__*/
 
 /* the ext2 bit routines adjust for big or little endian as
 ** appropriate for the arch, so in our laziness we use them rather
@@ -2039,6 +2111,7 @@ found_middle:
    absolutely safe */
 #define SPARE_SPACE 500
 
+#ifdef __KERNEL__
 static inline unsigned long reiserfs_get_journal_block(struct super_block *s) {
     return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_journal_block) ;
 }
@@ -2050,10 +2123,18 @@ static inline unsigned long reiserfs_get
 int reiserfs_ioctl (struct inode * inode, struct file * filp, 
  		    unsigned int cmd, unsigned long arg);
 int reiserfs_unpack (struct inode * inode, struct file * filp);
- 
+int reiserfs_dir_ioctl (struct inode * inode, struct file * filp, 
+                        unsigned int cmd, unsigned long arg);
+#endif /* __KERNEL__ */
+
 /* ioctl's command */
 #define REISERFS_IOC_UNPACK		_IOW(0xCD,1,long)
- 			         
+#define REISERFS_IOC_RAWOPEN           _IOWR(0xCD,15,sizeof(struct reiserfs_raw_ioctl_arg))
+#define REISERFS_IOC_RAWCREAT           _IOW(0xCD,16,sizeof(struct reiserfs_raw_ioctl_arg))
+#define REISERFS_IOC_RAWSETATTR         _IOW(0xCD,17,sizeof(struct reiserfs_raw_ioctl_arg))
+#define REISERFS_IOC_RAWUNLINK          _IOW(0xCD,18,sizeof(struct reiserfs_raw_ioctl_arg))
+#define REISERFS_IOC_TIMEDWAIT          _IOW(0xCD,19,sizeof(struct reiserfs_sigtimedwait_arg))
+
 #endif /* _LINUX_REISER_FS_H */
 
 
diff -rupN /usr/src/linux-2.4.9/include/linux/reiserfs_fs_i.h linux-kgdb/include/linux/reiserfs_fs_i.h
--- /usr/src/linux-2.4.9/include/linux/reiserfs_fs_i.h	Sat Jul 21 20:20:58 2001
+++ linux-kgdb/include/linux/reiserfs_fs_i.h	Sat Aug 25 17:39:03 2001
@@ -40,6 +40,35 @@ struct reiserfs_inode_info {
                                    is a comment you should make.... -Hans */
   //nopack-attribute
   int nopack;
+
+  /* reiserfs_raw attributes */
+  __u32 lastref;                /* the time the file was last
+                                   referenced (created or open). This
+                                   is used for garbage collection, so
+                                   we don't need precise timestamping
+                                   -- all timestamps that fit in one
+                                   age class can be considered the
+                                   same. So we use coarse-grained
+                                   timestamp provided by
+                                   pgc_current_time() to avoid
+                                   excessive timestamp updates when
+                                   the file is accessed frequently. In
+                                   other words, we avoid updating
+                                   timestamps unless the update would
+                                   result in moving the file into
+                                   another age class. */
+  __u32 expires;                /* expiration date -- may be set by
+                                   application to request removal of
+                                   the file by PGC even if the lastref
+                                   isn't old enough to indicate it
+                                   should be targeted for removal
+                                   lastref-wise */
+  __u32 user1;                  /* an opaque attribute for application
+                                   use: the kernel only stores and
+                                   retrieves it, but never looks at
+                                   its value.  In the case of squid it
+                                   may someday hold the length of the
+                                   header.  */
 };
 
 
diff -rupN /usr/src/linux-2.4.9/include/linux/reiserfs_fs_sb.h linux-kgdb/include/linux/reiserfs_fs_sb.h
--- /usr/src/linux-2.4.9/include/linux/reiserfs_fs_sb.h	Fri Aug 24 00:23:40 2001
+++ linux-kgdb/include/linux/reiserfs_fs_sb.h	Sun Aug 26 18:40:11 2001
@@ -6,6 +6,7 @@
 
 #ifdef __KERNEL__
 #include <linux/tqueue.h>
+#include <linux/age_class.h>
 #endif
 
 //
@@ -302,6 +303,9 @@ struct reiserfs_sb_info
     int s_bmaps_without_search;
     int s_direct2indirect;
     int s_indirect2direct;
+#ifdef CONFIG_REISERFS_RAW
+    struct pgc *pgc;
+#endif
 };
 
 
@@ -327,6 +331,13 @@ struct reiserfs_sb_info
 #define FORCE_R5_HASH 8       /* try to force rupasov hash on mount */
 #define FORCE_HASH_DETECT 9   /* try to detect hash function on mount */
 
+/* -o raw: enable ioctl (REISERFS_IOC_RAW*) which provides raw access
+   to internal reiserfs tree.  This is designed for squid proxy cache
+   acceleration.  To use this, recompile the kernel with
+   CONFIG_REISERFS_RAW enabled. */
+
+#define REISERFS_RAW 10
+
 
 /* used for testing experimental features, makes benchmarking new
    features with and without more convenient, should never be used by
@@ -355,7 +366,7 @@ struct reiserfs_sb_info
 #define replay_only(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REPLAYONLY))
 #define reiserfs_dont_log(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_NOLOG))
 #define old_format_only(s) ((SB_VERSION(s) != REISERFS_VERSION_2) && !((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_CONVERT)))
-
+#define reiserfs_raw(s) ((s)->u.reiserfs_sb.s_mount_opt & (1 << REISERFS_RAW))
 
 void reiserfs_file_buffer (struct buffer_head * bh, int list);
 int reiserfs_is_super(struct super_block *s)  ;
diff -rupN /usr/src/linux-2.4.9/include/linux/sched.h linux-kgdb/include/linux/sched.h
--- /usr/src/linux-2.4.9/include/linux/sched.h	Fri Aug 24 00:39:19 2001
+++ linux-kgdb/include/linux/sched.h	Sun Aug 26 18:40:11 2001
@@ -151,7 +151,9 @@ extern void update_one_process(struct ta
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
-asmlinkage void schedule(void);
+asmlinkage void do_schedule(void);
+asmlinkage void kern_schedule(void);
+asmlinkage void kern_do_schedule(struct pt_regs);
 
 extern int schedule_task(struct tq_struct *task);
 extern void flush_scheduled_tasks(void);
@@ -401,6 +403,11 @@ struct task_struct {
    	u32 self_exec_id;
 /* Protection of (de-)allocation: mm, files, fs, tty */
 	spinlock_t alloc_lock;
+
+#if defined(CONFIG_AIO)
+	void *kaio_info;
+#endif
+
 };
 
 /*
@@ -891,6 +898,12 @@ static inline char * d_path(struct dentr
 	mntput(rootmnt);
 	return res;
 }
+
+#ifdef CONFIG_KGDB_THREAD
+#define schedule() kern_schedule()
+#else
+#define schedule() do_schedule()
+#endif
 
 #endif /* __KERNEL__ */
 
diff -rupN /usr/src/linux-2.4.9/init/main.c linux-kgdb/init/main.c
--- /usr/src/linux-2.4.9/init/main.c	Sat Jul 21 20:20:59 2001
+++ linux-kgdb/init/main.c	Sun Aug 26 18:33:35 2001
@@ -57,6 +57,10 @@
 #include <linux/nubus.h>
 #endif
 
+#ifdef CONFIG_X86_REMOTE_DEBUG
+#include <linux/gdb.h>
+#endif
+
 #ifdef CONFIG_ISAPNP
 #include <linux/isapnp.h>
 #endif
@@ -590,6 +594,13 @@ asmlinkage void __init start_kernel(void
 #if defined(CONFIG_SYSVIPC)
 	ipc_init();
 #endif
+#if defined(CONFIG_AIO)
+	{
+		extern void kaio_init(void);
+
+		kaio_init();
+	}
+#endif
 	check_bugs();
 	printk("POSIX conformance testing by UNIFIX\n");
 
@@ -599,6 +610,11 @@ asmlinkage void __init start_kernel(void
 	 *	make syscalls (and thus be locked).
 	 */
 	smp_init();
+#ifdef CONFIG_X86_REMOTE_DEBUG
+	if (gdb_enter) {
+		gdb_hook();		/* right at boot time */
+	}
+#endif
 	rest_init();
 }
 
diff -rupN /usr/src/linux-2.4.9/kernel/exit.c linux-kgdb/kernel/exit.c
--- /usr/src/linux-2.4.9/kernel/exit.c	Fri Aug 24 00:13:25 2001
+++ linux-kgdb/kernel/exit.c	Sat Aug 25 01:18:48 2001
@@ -438,6 +438,13 @@ fake_volatile:
 #ifdef CONFIG_BSD_PROCESS_ACCT
 	acct_process(code);
 #endif
+#if defined(CONFIG_AIO)
+	if (tsk->kaio_info) {
+		extern void kaio_exit(void);
+
+		kaio_exit();
+	}
+#endif
 	__exit_mm(tsk);
 
 	lock_kernel();
diff -rupN /usr/src/linux-2.4.9/kernel/fork.c linux-kgdb/kernel/fork.c
--- /usr/src/linux-2.4.9/kernel/fork.c	Sat Jul 21 20:20:59 2001
+++ linux-kgdb/kernel/fork.c	Sat Aug 25 01:18:48 2001
@@ -680,6 +680,13 @@ int do_fork(unsigned long clone_flags, u
 	if (!current->counter)
 		current->need_resched = 1;
 
+#if defined(CONFIG_AIO)
+	if (current->kaio_info) {
+		extern int kaio_fork(struct task_struct *, int);
+
+		kaio_fork(p, clone_flags);
+	}
+#endif
 	/*
 	 * Ok, add it to the run-queues and make it
 	 * visible to the rest of the system.
diff -rupN /usr/src/linux-2.4.9/kernel/ksyms.c linux-kgdb/kernel/ksyms.c
--- /usr/src/linux-2.4.9/kernel/ksyms.c	Fri Aug 24 00:13:25 2001
+++ linux-kgdb/kernel/ksyms.c	Sun Aug 26 18:21:42 2001
@@ -439,7 +439,10 @@ EXPORT_SYMBOL(sleep_on);
 EXPORT_SYMBOL(sleep_on_timeout);
 EXPORT_SYMBOL(interruptible_sleep_on);
 EXPORT_SYMBOL(interruptible_sleep_on_timeout);
-EXPORT_SYMBOL(schedule);
+EXPORT_SYMBOL(do_schedule);
+#ifdef CONFIG_KGDB_THREAD
+EXPORT_SYMBOL(kern_schedule);
+#endif
 EXPORT_SYMBOL(schedule_timeout);
 EXPORT_SYMBOL(jiffies);
 EXPORT_SYMBOL(xtime);
diff -rupN /usr/src/linux-2.4.9/kernel/sched.c linux-kgdb/kernel/sched.c
--- /usr/src/linux-2.4.9/kernel/sched.c	Sat Jul 21 20:20:59 2001
+++ linux-kgdb/kernel/sched.c	Sun Aug 26 18:21:42 2001
@@ -527,7 +527,7 @@ void schedule_tail(struct task_struct *p
  * tasks can run. It can not be killed, and it cannot sleep. The 'state'
  * information in task[0] is never used.
  */
-asmlinkage void schedule(void)
+asmlinkage void do_schedule(void)
 {
 	struct schedule_data * sched_data;
 	struct task_struct *prev, *next, *p;
@@ -706,6 +706,22 @@ scheduling_in_interrupt:
 	BUG();
 	return;
 }
+
+asmlinkage void user_schedule(void)
+{
+#ifdef CONFIG_KGDB_THREAD
+	current->thread.kgdbregs = NULL;
+#endif
+	do_schedule();
+}
+
+#ifdef CONFIG_KGDB_THREAD
+asmlinkage void kern_do_schedule(struct pt_regs regs)
+{
+	current->thread.kgdbregs = &regs;
+	do_schedule();
+}
+#endif
 
 /*
  * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just wake everything
diff -rupN /usr/src/linux-2.4.9/mm/filemap.c linux-kgdb/mm/filemap.c
--- /usr/src/linux-2.4.9/mm/filemap.c	Fri Aug 24 00:13:25 2001
+++ linux-kgdb/mm/filemap.c	Sun Aug 26 20:36:51 2001
@@ -2,6 +2,13 @@
  *	linux/mm/filemap.c
  *
  * Copyright (C) 1994-1999  Linus Torvalds
+ * 
+ * KAIO modifications:
+ * 	Copyright 1999, Silicon Graphics, Inc.
+ *
+ * 	Written October 1999 by Rajagopal Ananthanarayanan (ananth)
+ *                      at Silicon Graphics, Inc.
+ * 	With modifications suggested by Doug Rady at Silicon Graphics, Inc.
  */
 
 /*
@@ -29,6 +36,25 @@
 
 #include <linux/highmem.h>
 
+#if defined(CONFIG_AIO)
+#include <linux/aio.h>
+
+#ifdef AIO_DEBUG
+#define	assert(expression) { \
+	if (!(expression)) { \
+		(void)printk(KERN_ERR \
+			"assertion \"%s\" failed: file \"%s\", line %d\n", \
+			#expression, \
+			__FILE__, __LINE__); \
+	} \
+}
+#else
+#define assert(expresssion)
+#endif
+
+#define pageof(x)	(x >> PAGE_SHIFT)
+#endif /* CONFIG_AIO */
+
 /*
  * Shared mappings implemented 30.11.1994. It's not fully working yet,
  * though.
@@ -1221,6 +1247,1329 @@ int file_read_actor(read_descriptor_t * 
 	desc->buf += size;
 	return size;
 }
+
+#if defined(CONFIG_AIO)
+
+static unsigned long 	kaio_hash_mask = 0;
+static kaiocb_t 	**kaio_hash_table;
+static int		kaio_hash_table_size;
+static int		kaio_number = 1;  	/* id for kaio 		*/
+static int		kaio_nr_hashed = 0;
+static spinlock_t 	kaio_hash_lock = SPIN_LOCK_UNLOCKED;
+
+typedef struct {
+	spinlock_t kaioq_lock;
+	struct semaphore kaiosem;
+
+	/* 0x10 */
+	struct list_head kaioq;
+	int		 kaioqref;
+	volatile int	 kaioq_nslaves;
+
+	/* 0x20 */
+	struct semaphore kaioq_exit_sem;
+} kaio_queue_t;
+
+#define KAIO_INFO(task) ((kaio_queue_t *) (task)->kaio_info)
+
+static inline unsigned long
+kaio_time(void)
+{
+	struct timeval tv;
+
+	do_gettimeofday(&tv);
+	return (tv.tv_sec * 1000000 + tv.tv_usec);
+}
+
+/*
+ * AIO HASH TABLE:
+ * 	A simple system wide table hashed on kq & aio_id. 
+ *	Most of this code adapted from the buffer cache hash table.
+ *	All operations protected by kernel lock.
+ */
+#define _kaio_hashfn(kq, kid)	((unsigned)(((unsigned)kq)^(kid)) & kaio_hash_mask)
+#define kaio_hash(kq, kid)	kaio_hash_table[_kaio_hashfn((kq),(kid))]
+
+static void
+kaio_init_hash_table(void)
+{
+	int order = 1;		/* Currently maximum order.. */
+
+	kaio_hash_table_size = (1UL << order) * PAGE_SIZE / sizeof(kaiocb_t *);
+	kaio_hash_table = (kaiocb_t  **) __get_free_pages(GFP_ATOMIC, order);
+	
+	if (!kaio_hash_table)
+		panic("Failed to allocate kaio hash table\n");
+	memset(kaio_hash_table, 0, kaio_hash_table_size * sizeof(kaiocb_t *));
+	kaio_hash_mask = kaio_hash_table_size-1;
+}
+
+static void
+kaio_add_hash(kaiocb_t *kaiocb)
+{
+	kaiocb_t **khp;
+	kaiocb_t *next;
+
+	spin_lock(&kaio_hash_lock);
+	kaiocb->kaio_id = kaio_number++; /* XXX: how about overflow? */
+	khp = &kaio_hash(current->kaio_info, kaiocb->kaio_id);
+	next = *khp;
+
+	kaiocb->kaio_h_next = NULL;
+	kaiocb->kaio_h_pprev = NULL;
+
+	if (next) {
+		kaiocb->kaio_h_next = next;
+		next->kaio_h_pprev = &kaiocb->kaio_h_next;
+	}
+	*khp = kaiocb;
+	kaiocb->kaio_h_pprev = khp;
+	kaio_nr_hashed++;
+	spin_unlock(&kaio_hash_lock);
+}
+
+static kaiocb_t *
+kaio_find_hash(kaio_key_t *kkey)
+{		
+	kaiocb_t *next;
+
+	next = kaio_hash(KAIO_INFO(current), kkey->kaio_kid);
+	for (;;) {
+		kaiocb_t *tmp = next;
+		if (!next)
+			break;
+		next = tmp->kaio_h_next;
+		if (tmp->kaio_id != kkey->kaio_kid)
+			continue;
+		assert(tmp->kaio_task->kaio_info == kkey->kaio_kq);
+		next = tmp;
+		break;
+	}
+	return next;
+}
+
+static inline void
+kaio_remove_hash(kaiocb_t *kaiocb)
+{
+	kaiocb_t **pprev = kaiocb->kaio_h_pprev;
+	if (pprev) {
+		kaiocb_t *next = kaiocb->kaio_h_next;
+		if (next) {
+			next->kaio_h_pprev = pprev;
+			kaiocb->kaio_h_next = NULL;
+		}
+		*pprev = next;
+		kaiocb->kaio_h_pprev = NULL;
+	}
+	kaio_nr_hashed--;
+}
+
+/*
+ * PER-TASK AIO QUEUE OPERATIONS.
+ * 	Proceted by a spinlock embedded in the queue.
+ */
+
+
+/*
+ * Create: an aio queue for the given task. A q create is attempted as 
+ * part of all aio operations, including the slave start operation.
+ * The queue is freed as part of exit. 
+ */
+void
+kaio_q_create(struct task_struct *task)
+{
+	struct task_struct 	*p;
+	kaio_queue_t		*kq;
+
+	/* protected by lock_kernel */
+	if (KAIO_INFO(task))
+		return;
+
+	kq = kmalloc(sizeof(kaio_queue_t), GFP_KERNEL);
+
+	if (!kq) {
+		printk("kmalloc KAIO_INFO(task) failed!!\n");
+		do_exit(SIGKILL);
+	}
+	/*
+	 * XXX: the following memset is required
+	 * in spite of individual member initializaion of
+	 * kaio_queue_t. why?
+	 */
+	memset(&kq->kaioq_lock, 0, sizeof(kaio_queue_t));
+	sema_init(&kq->kaiosem, 0);
+	sema_init(&kq->kaioq_exit_sem, 0);
+	INIT_LIST_HEAD(&kq->kaioq);
+	spin_lock_init(&kq->kaioq_lock);
+
+	kq->kaioq_nslaves = -1; /* -1 indicates no slaves yet */
+	/*
+	 * If there are any clones, propage kaio_info.
+	 * Following will automatically set current task kaioq & reference.
+	 */
+	kq->kaioqref = 0;
+	for_each_task(p) {
+		if (p->mm == current->mm) {
+			KAIO_INFO(p) = kq;
+			kq->kaioqref++;
+		}
+	}
+	
+}
+
+
+/*
+ * Enqueue: now the aio is officially enqueued for I/O, accessible to the slave
+ * 	threads, and is also entered into the hash table, accessible to
+ * 	user operations such as aio_suspend.
+ */
+static int
+kaio_enqueue(kaio_queue_t *kq, kaiocb_t *kaiocb)
+{
+	kaiocb->kaio_error = EINPROGRESS;
+	if (put_user(kaiocb->kaio_error, &kaiocb->kaio_uaiocb->aio_error))
+		return(-EFAULT);
+	kaiocb->kaio_suspend_wait = 0;
+	INIT_LIST_HEAD(&kaiocb->kaio_ioq);
+
+	spin_lock(&kq->kaioq_lock);
+	if (kq->kaioq_nslaves == 0) {
+		spin_unlock(&kq->kaioq_lock);
+		return -EAGAIN;
+		
+	}
+	kaio_add_hash(kaiocb);
+	list_add(&kaiocb->kaio_ioq, &kq->kaioq);
+	up(&kq->kaiosem);
+	spin_unlock(&kq->kaioq_lock);
+
+        kaio_set_time(kaiocb, AIOTIME_ENQUEUED);
+
+        return 0;
+}
+
+/*
+ * Wait for an aio and dequeue. Normally, kaiosem counts the number
+ * of entries available in the queue; however, kaio_cancel can
+ * dequeue entries as well, and it does not down the semaphore,
+ * because there is no easy way to synchronize this action with kaio_dequeue.
+ * Instead, the dequeue operation simply retries if it finds the queue
+ * empty eventhough the semaphore count was non-zero (i.e. the down succeded).
+ * The down() is interrupted when the parent sends a signal when it exits.
+ */
+static kaiocb_t *
+kaio_dequeue(kaio_queue_t *kq)
+{
+	struct list_head *tmp;
+
+retry:
+	if (down_interruptible(&kq->kaiosem))
+		return 0;
+
+	spin_lock(&kq->kaioq_lock);
+	tmp = kq->kaioq.prev;
+	if (tmp != &kq->kaioq) {
+		list_del(tmp);
+		spin_unlock(&kq->kaioq_lock);
+		INIT_LIST_HEAD(tmp);
+		return(list_entry(tmp, struct kaiocb, kaio_ioq));
+	} else {
+		spin_unlock(&kq->kaioq_lock);
+		goto retry;
+	}
+}
+
+static int
+kaio_dequeue_kaiocb(kaio_queue_t *kq, kaiocb_t *kaiocb)
+{
+	spin_lock(&kq->kaioq_lock);
+	if (kaiocb->kaio_ioq.prev == &kaiocb->kaio_ioq) {
+		assert(kaiocb->kaio_ioq.next == &kaiocb->kaio_ioq);
+		spin_unlock(&kq->kaioq_lock);
+		return 0;
+	}
+	list_del(&kaiocb->kaio_ioq);
+	INIT_LIST_HEAD(&kaiocb->kaio_ioq);
+	spin_unlock(&kq->kaioq_lock);
+	return 1;
+}
+
+static kaiocb_t *
+kaio_dequeue_fd(kaio_queue_t *kq, struct file *filp)
+{
+	struct list_head *tmp;
+	kaiocb_t *kaiocb;
+
+	spin_lock(&kq->kaioq_lock);
+	tmp = kq->kaioq.next; /* start from first of list; why not? */
+	while (tmp != &kq->kaioq) {
+		kaiocb = list_entry(tmp, struct kaiocb, kaio_ioq);
+		if (kaiocb->kaio_filp == filp) {
+			list_del(tmp);
+			spin_unlock(&kq->kaioq_lock);
+			INIT_LIST_HEAD(tmp);
+			return(kaiocb);
+		}
+		tmp = tmp->next;
+	}
+	spin_unlock(&kq->kaioq_lock);
+	return 0;
+}
+
+/*
+ * Boot time initialization.
+ */
+void
+kaio_init(void)
+{
+	kaio_init_hash_table();
+}
+
+static void
+send_signal(sigevent_t *sigev, struct task_struct *task)
+{
+	if (sigev->sigev_notify == SIGEV_SIGNAL) {
+		struct siginfo sinfo;
+                int r;
+		
+		memset(&sinfo, 0, sizeof(sinfo));
+		sinfo.si_signo = sigev->sigev_signo;
+		sinfo.si_code = SI_ASYNCIO;
+		sinfo.si_value = sigev->sigev_value;
+
+                /* signal queue items are allocated at GFP_ATOMIC, so
+                   -EAGAIN is possible.  We don't want to lose
+                   completion signals, really, so don't leave before
+                   we succeed queuing the signal. */
+        retry:
+                r = send_sig_info(sigev->sigev_signo, &sinfo, task);
+                if (r == -EAGAIN) {
+                        schedule ();
+                        goto retry;
+                }
+	}
+}
+
+static int
+lio_complete(liocb_t *liocb, int n, int wakeup)
+{
+	spin_lock(&liocb->lio_lock);
+	liocb->lio_done += n;
+	if (liocb->lio_nent == liocb->lio_done) {
+		spin_unlock(&liocb->lio_lock);
+		if (wakeup) {
+			lock_kernel();
+			wake_up(&liocb->lio_wait);
+			unlock_kernel();
+		}
+		send_signal(&liocb->lio_sigevent, liocb->lio_task);
+		if (liocb->lio_mode == LIO_NOWAIT)
+			kfree(liocb);
+		return 1;
+	}
+	if (!wakeup)
+		lock_kernel();
+	spin_unlock(&liocb->lio_lock);
+	return 0;
+}
+
+static int
+kaio_io_complete(kaiocb_t *kaiocb, int nbytes, int ret, int gc)
+{
+	aiocb_t	*uaiocb = kaiocb->kaio_uaiocb;
+	liocb_t	*liocb = kaiocb->kaio_liocb;
+	int	i;
+
+	if (kaiocb->kaio_pages) {
+
+		for (i = 0; i < kaiocb->kaio_npages; i++)
+			page_cache_release(kaiocb->kaio_pages[i]);
+		if (kaiocb->kaio_pages != &kaiocb->kaio_page_inline)
+			kfree(kaiocb->kaio_pages);
+	}
+
+#ifdef KAIO_STATS
+        kaio_set_time(kaiocb, AIOTIME_COMPLETE);
+	if (copy_to_user(&uaiocb->aio_times[1], &kaiocb->kaio_times[1],
+			sizeof(unsigned long) * (AIO_TIMES-1)))
+	{
+		ret = -EFAULT;
+	} else
+#endif
+	if (put_user(nbytes, &uaiocb->aio_return))
+		ret = -EFAULT;
+	/* aio_error does not go through syscall so -ret */
+	else if (put_user(-ret, &uaiocb->aio_error))
+		ret = -EFAULT;
+	else {
+		send_signal(&kaiocb->kaio_sigevent, kaiocb->kaio_task);
+		spin_lock(&kaio_hash_lock);
+		if (kaiocb->kaio_suspend_wait) {
+			lock_kernel();
+			kaiocb->kaio_error = -ret;
+			wake_up(kaiocb->kaio_suspend_wait);
+			unlock_kernel();
+		} else {
+			kaiocb->kaio_error = -ret;
+			/* gc |= (liocb && liocb->lio_mode == LIO_WAIT); */
+			gc = 1;
+			if (gc)
+				kaio_remove_hash(kaiocb);
+		}
+		spin_unlock(&kaio_hash_lock);
+		if (liocb)
+			lio_complete(liocb, 1, 1);
+	}
+	if (gc) {
+		fput(kaiocb->kaio_filp);
+		kfree(kaiocb);
+	}
+	return ret;
+}
+
+static int
+kaio_slave_suspend(kaiocb_t *kaiocb)
+{
+	off_t pos;
+	int i, ret = 0, nbytes, isize;
+	struct page *page;
+
+	nbytes = kaiocb->kaio_nbytes;
+	isize = kaiocb->kaio_filp->f_dentry->d_inode->i_size;
+	for (i = 0; i < kaiocb->kaio_npages; i++) {
+		page = kaiocb->kaio_pages[i];
+		wait_on_page(page);
+		/*
+		 * Ok, we have the page. 
+		 */
+		if (!Page_Uptodate(page) || PageError(page)) {
+			ret = -EIO; /* Some unspecfied error */
+			goto error;
+		}
+	}
+	kaio_set_time(kaiocb, AIOTIME_IO);
+
+	pos = kaiocb->kaio_offset;
+	i = 0;
+	page = kaiocb->kaio_pages[0];
+	assert(nbytes);
+
+	while  (nbytes && pos < isize) {
+		unsigned long offset, nr, left;
+
+		offset = pos & ~PAGE_MASK;
+		nr = PAGE_SIZE - offset;
+		if (nr > isize - pos)
+			nr = isize - pos;
+		if (nbytes < nr)
+			nr = nbytes;
+
+		left = __copy_to_user(kaiocb->kaio_buf,
+				(char *) page_address(page) + offset, nr);
+		nbytes -= (nr - left);
+		if (left) {
+			ret = -EFAULT;
+			goto error; 
+		}
+		pos += nr;
+		kaiocb->kaio_buf = (char *)kaiocb->kaio_buf + nr;
+		if ((pos & ~PAGE_MASK) == 0) { /* beginning of next page */
+			i++;
+			page = kaiocb->kaio_pages[i];
+		}
+	}
+	assert(!nbytes || pos == isize);
+	kaio_set_time(kaiocb, AIOTIME_COPY);
+
+error:
+
+	/* nbytes contains remainder unread, for eg., due to isize limit */
+	ret = kaio_io_complete(kaiocb, kaiocb->kaio_nbytes - nbytes, ret, 0);
+
+	return ret;
+}
+
+#if defined(CONFIG_RAW)
+static int
+do_raw_wait(kaiocb_t *kaiocb)
+{
+	int diag;
+
+	do {
+		diag = kaio_raw_wait(kaiocb->kaio_scp, &kaiocb->kaio_iobuf);
+	} while (diag == -EAGAIN);
+	diag = kaio_io_complete(kaiocb, diag, (diag > 0 ? 0 : diag), 0);
+	return diag;
+}
+
+static int
+do_kaio_raw_rw(int cmd, struct file *filp, struct kaiocb *kaiocb)
+{
+	int diag;
+	void *scp;
+
+	kaiocb->kaio_sem = MUTEX_LOCKED;
+	scp = kaio_raw_rw((cmd == AIOCMD_READ ? READ : WRITE), filp,
+			kaiocb->kaio_buf, kaiocb->kaio_nbytes,
+			&kaiocb->kaio_offset, &diag,
+			&kaiocb->kaio_sem, &kaiocb->kaio_iobuf);
+	kaiocb->kaio_scp = scp;
+	if (diag == 0) {
+		diag = kaio_enqueue(KAIO_INFO(current), kaiocb);
+		if (diag) {
+			do {
+				diag = kaio_raw_wait(kaiocb->kaio_scp,
+					&kaiocb->kaio_iobuf);
+			} while (diag == -EAGAIN);
+		}
+	}
+	return diag;
+}
+#endif /* CONFIG_RAW */
+
+kaiocb_t *susp_kaiocb;
+
+int
+kaio_suspend(aiocb_t *list[], int nent, struct timespec *utimeout, int nwait)
+{
+	int 			ret = 0, i, valid, pending;
+	struct timespec 	timeout;
+	aiocb_t			*uaiocb = 0;
+	kaio_key_t		kkey;
+	kaiocb_t 		*kaiocb, **kaiocbs, *kaiocb_array[256];
+	wait_queue_head_t	wq;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (utimeout && copy_from_user(&timeout, (struct timespec *)utimeout,
+				    sizeof(struct timespec)))
+	{
+		return -EFAULT;
+	}
+	/*
+	 * For more normal requests, allocate on stack.
+	 */
+	if (nent > 256) {
+		kaiocbs = kmalloc(sizeof(kaiocb_t *) * nent, GFP_KERNEL);
+		if (!kaiocbs)
+			return -EAGAIN;
+	} else
+		kaiocbs = kaiocb_array;
+
+	init_waitqueue_head(&wq);
+	add_wait_queue(&wq, &wait);
+
+	/*
+	 * Go through the list, if nwait done, return; otherwise
+	 * mark kaiocb so it will wake this thread when done.
+	 */
+	for (i = 0, valid = 0; nwait > 0 && i < nent; i++) {
+		if (get_user(uaiocb, &list[i])) {
+			ret = -EFAULT;
+			goto suspend_error;
+		}
+		if (!uaiocb)
+			continue;
+		/*
+		 * Check to see if done, otherwise put this
+		 * thread on the list of things to wake up.
+		 */
+		if (copy_from_user(&kkey, &uaiocb->aio_key,
+			sizeof(kaio_key_t)))
+		{
+			ret = -EFAULT;
+			goto suspend_error;
+		}
+		spin_lock(&kaio_hash_lock);
+		if ((kaiocb = kaio_find_hash(&kkey)) == 0) {
+			/* get_user can fault, better drop lock */
+			spin_unlock(&kaio_hash_lock);
+			if (get_user(ret, &uaiocb->aio_error)) {
+				ret = -EFAULT;
+				goto suspend_error;
+			}
+			/*
+			 * Assume that user gave a valid aiocb,
+			 * and that it is done.
+			 */
+			nwait--;
+		} else {
+			if (kaiocb->kaio_suspend_wait) {
+				/*
+				 * Don't allow two different processes to
+				 * wait on the same I/O request.
+				 */
+				ret = -EAGAIN;
+				spin_unlock(&kaio_hash_lock);
+				goto suspend_error;
+			}
+			kaiocb->kaio_suspend_wait = &wq;
+			kaiocbs[valid++] = kaiocb;
+			spin_unlock(&kaio_hash_lock);
+		}
+	}
+	if (!nwait && !valid)
+		return ret;
+	
+	susp_kaiocb = kaiocbs[0];
+
+	/*
+	 * Pending keeps track of how many I/Os  are being
+	 * wait upon. Valid is the index into kaiocbs where
+	 * the kaiocb of the last pending I/O is stored.
+	 * After sleeping & waking up on any one of the pending
+	 * I/O to complete, we scan the kaiocbs, garbage collect
+	 * all complete kaiocb & put a null entry in kaiocbs[].
+	 */
+	pending = valid;
+	lock_kernel();
+	while (nwait > 0 && pending) {
+		/*
+		 * See how many more done & free kaiocb's as necessary.
+		 */
+		for (i = 0; i < valid; i++) {
+			if (kaiocbs[i]->kaio_error != EINPROGRESS &&
+			     kaiocbs[i]->kaio_suspend_wait)
+			{
+				nwait--;
+				pending--;
+				kaiocbs[i]->kaio_suspend_wait = 0;
+			}
+			/* already done ?! */
+			if (!pending || nwait <= 0)
+				goto done_wait;
+		}
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		current->state = TASK_INTERRUPTIBLE;
+		if (utimeout)
+			(void) schedule_timeout(timespec_to_jiffies(&timeout));
+		else
+			schedule();
+		current->state = TASK_RUNNING;
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+	}
+done_wait:
+	unlock_kernel();
+
+suspend_error:
+	spin_lock(&kaio_hash_lock);
+	/*
+	 * Unmark & free kaiocb's as necessary.
+	 */
+	for (i = 0; i < valid; i++) {
+		kaiocbs[i]->kaio_suspend_wait = 0;
+		if (kaiocbs[i]->kaio_error != EINPROGRESS) {
+			kaio_remove_hash(kaiocbs[i]);
+			fput(kaiocbs[i]->kaio_filp);
+			kfree(kaiocbs[i]);
+		}
+	}
+	spin_unlock(&kaio_hash_lock);
+	if (kaiocbs != kaiocb_array)
+		kfree(kaiocbs);
+	return(ret);
+}
+
+/*
+ * kaio_cancel: if given kkey, cancel a specific aio; otherwise
+ * 		cancel all aios for given fd. All successful canceled
+ *		aios will have -1 return & ECANCELED as aio_error.
+ *		kaio_io_complete handles normal signal delivery and
+ *		any listio that the aio may be part of.
+ *	kernel lock held on call.
+ */
+int
+kaio_cancel(int fd, kaio_key_t *kkey)
+{
+	kaiocb_t 	*kaiocb;
+	struct file 	*filp;
+	int		ret = 0;
+
+	if (!(filp = fget(fd)))
+		return -EBADF;
+
+	if (kkey) {
+		spin_lock(&kaio_hash_lock);
+		kaiocb = kaio_find_hash(kkey);
+		spin_unlock(&kaio_hash_lock);
+		if (kaiocb == 0) {
+			ret = -EINVAL;
+			goto cancel_out;
+		}
+
+		if (filp != kaiocb->kaio_filp) {
+			ret = -EBADF;
+			goto cancel_out;
+		}
+
+		if (!kaio_dequeue_kaiocb(KAIO_INFO(current), kaiocb)) {
+			ret = AIO_NOTCANCELED;
+			goto cancel_out;
+		}
+		ret = kaio_io_complete(kaiocb, -1, -ECANCELED, 1);
+		if (ret == 0)
+			ret = AIO_CANCELED;
+	} else {
+		/* cancel all associated with fd */
+		if ((kaiocb = kaio_dequeue_fd(KAIO_INFO(current), filp)) == 0) {
+			ret = AIO_ALLDONE;
+			goto cancel_out;
+		}
+		do {
+			/* XXX: what if error occurs */
+			kaio_io_complete(kaiocb, -1, -ECANCELED, 1);
+		} while ((kaiocb = kaio_dequeue_fd(KAIO_INFO(current), filp)) != 0);
+	}
+cancel_out:
+	fput(filp);
+	return ret;
+}
+
+void
+kaio_fork(struct task_struct *p, int clone_flags)
+{
+	/* Assumes kernel lock held */
+
+	/*
+	 * If the new thread is not sharing VM with parent,
+	 * then it can't share AIO state.
+	 */
+	if (clone_flags & CLONE_VM) {
+		KAIO_INFO(p) = KAIO_INFO(current);
+		KAIO_INFO(p)->kaioqref++;
+	} else
+		p->kaio_info = 0;
+}
+
+/*
+ * kaio_exit:
+ *	Called by generic exit when a thread has async I/O (kaio_info).
+ *	This routine does the following:
+ * 	(1) kills the slave threads, by signalling and
+ * 	     waiting for them to be reaped.
+ *	(2) Removes any queued aios (these may not have been intiated at all).
+ *	(3) Removes any remaining aios for this thread from the hash (these
+ *		have completed but not reaped through aio_suspend).
+ *	All actions protected by kernel lock.
+ */
+void
+kaio_exit(void)
+{
+	struct task_struct 	*p;
+	kaiocb_t 		**khpp;
+	kaio_queue_t		*kq;
+	struct list_head 	*tmp;
+	kaiocb_t 		*curr, *next;
+
+	lock_kernel();
+
+	/* kill all slaves if last clone */
+
+	kq = KAIO_INFO(current);
+	if (kq->kaioqref != 1) {
+		kq->kaioqref--;
+		unlock_kernel();
+		return;
+	}
+	/*
+	 * Last reference, kill all slaves & cleanup pending I/Os.
+	 */
+
+	for_each_task(p) {
+		/*
+		 * Look for slaves by name.
+		 */
+		if (p->mm == current->mm &&
+		     strncmp(&p->comm[0], KAIO_SLAVE_NAME,
+			     KAIO_SLAVE_NAMELEN) == 0)
+		{ 
+			send_sig(SIGKILL, p, 1);
+		}
+	}
+	/* kernel lock held for the test below */
+	while (kq->kaioq_nslaves != 0)
+		down(&kq->kaioq_exit_sem);
+	/*
+	 * Any queued aios can be simply "completed" & garbage collected. 
+	 */
+	for (tmp = kq->kaioq.prev; tmp != &kq->kaioq; tmp = kq->kaioq.prev) {
+		list_del(tmp);
+		kaio_io_complete(list_entry(tmp, struct kaiocb, kaio_ioq),
+					-1, -1, 1);
+	}
+	/*
+	 * Free up all hashed aios for this pid; these are already complete,
+	 * but pending aio_suspend.
+	 */
+	unlock_kernel();
+	spin_lock(&kaio_hash_lock);
+	for (khpp = &kaio_hash_table[0];
+		khpp < &kaio_hash_table[kaio_hash_table_size]; khpp++)
+	{
+
+		for  (curr = *khpp; curr; curr = next) {
+			next = curr->kaio_h_next;
+			if (curr->kaio_kq == kq) {
+				kaio_remove_hash(curr);
+				kfree(curr);
+			}
+		}
+	}
+	spin_unlock(&kaio_hash_lock);
+	kfree(kq);
+}
+
+#define KAIO_DO_FOP(op, k)  {						      \
+	int ret;							      \
+	(k)->kaio_filp->f_pos = (k)->kaio_offset;                             \
+	ret = (k)->kaio_filp->f_op-> ## op ((k)->kaio_filp,                   \
+		(k)->kaio_buf, (k)->kaio_nbytes, &(k)->kaio_filp->f_pos);     \
+	kaio_io_complete((k), ret < 0 ? 0 : ret, ret > 0 ? 0 : ret, 0);	      \
+}
+/*		(k)->kaio_buf, (k)->kaio_nbytes, &(k)->kaio_offset);     \ */
+
+static void
+kaio_set_slave_name(void)
+{
+	char newcomm[16];
+
+	sprintf(newcomm, "%s%05d", KAIO_SLAVE_NAME, current->p_pptr->pid);
+	strcpy(current->comm, newcomm);
+	current->mm->arg_start = current->mm->arg_end = 0;
+}
+
+/* Called from kaio_slave to do AIOCMD_<syscall> requests */
+asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+static void
+kaio_do_syscall(kaiocb_t *kaiocb)
+{
+        int ret;
+
+        switch (kaiocb->kaio_cmd) {
+        case AIOCMD_IOCTL:
+                ret = sys_ioctl(kaiocb->kaio_fd, kaiocb->kaio_nbytes,
+                                (unsigned long) kaiocb->kaio_buf);
+                break;
+        case AIOCMD_CLOSE:
+                ret = sys_close(kaiocb->kaio_fd);
+                break;
+        default:
+                ret = -EINVAL;
+                break;
+        }
+
+        kaio_io_complete(kaiocb, ret<0? 0:ret,  ret>0? 0:ret, 0);
+        return;
+}
+
+/*
+ * kaio_slave:
+ * 	Entry point for slave threads that service queued I/O requests.
+ * For each task that employs async I/O there may be several slave threads.
+ * 
+ *	The main function of the slave threads is to wait & dequeue an I/O
+ * request and serice it. Requests may be split-phase with a seperate initiate
+ * and wait routine, or with a unified routine that does both.  Not all
+ * file systems support split-phase requests; only raw I/O directly support it.
+ * Additionally, for file systems that employ generic_read we can use
+ * the recoded kaio_generic_read & associated wait (kaio_slave_suspend).
+ *	
+ *	Slave threads are explicitly started by the library, but are killed
+ * when the "parent" task (that initiates I/O) exits (kaio_exit).
+ */
+void
+kaio_slave()
+{
+	kaiocb_t *kaiocb;
+	kaio_queue_t *kq;
+
+	if (current->p_pptr->pid == 1) { /* too late */
+		unlock_kernel();
+		return;
+	}
+
+	kaio_set_slave_name();
+	kq = KAIO_INFO(current->p_pptr); /* service parent's kaio queue */
+        if (! kq) {    
+                unlock_kernel();
+                return;
+        }
+	KAIO_INFO(current) = 0; /* so kaio_exit does not trip */
+	kq->kaioqref--;
+	if (kq->kaioq_nslaves == -1)
+		kq->kaioq_nslaves = 1; /* initialize it */
+	else
+		kq->kaioq_nslaves++;
+	unlock_kernel();
+
+drain_io:
+	while ((kaiocb = kaio_dequeue(kq))) { /* blocks */
+                kaio_set_time(kaiocb, AIOTIME_DEQUEUED);
+#if defined(CONFIG_RAW)
+		if (kaio_is_raw(kaiocb->kaio_filp))
+			do_raw_wait(kaiocb);
+		else
+#endif
+		{
+			switch (kaiocb->kaio_cmd) {
+			case AIOCMD_GENERIC_READ:
+				kaio_slave_suspend(kaiocb);
+				break;
+			case AIOCMD_READ:
+				KAIO_DO_FOP(read, kaiocb);
+				break;
+		        case AIOCMD_WRITE: {
+		        	KAIO_DO_FOP(write, kaiocb);
+				break;
+			}
+                        /*
+                        case AIOCMD_WRITE: {
+                            /* TODO: for O_APPEND files, write
+                               requests must be done in the submission
+                               order.  Howto?  --sizif * /
+                            loff_t pos = kaiocb->kaio_offset;
+                            int ret = kaiocb->kaio_filp->f_op->write
+                                (kaiocb->kaio_filp,
+                                 kaiocb->kaio_buf,
+                                 kaiocb->kaio_nbytes,
+                                 &pos);
+                            kaiocb->kaio_filp->f_pos = pos;
+                            kaio_set_time(kaiocb, AIOTIME_IO);
+                            kaio_io_complete(kaiocb,
+                                             ret<0? 0:ret,
+                                             ret>0? 0:ret, 0);
+                            break;
+                        }
+                        */
+                        case AIOCMD_IOCTL:
+                        case AIOCMD_CLOSE:
+                                kaio_do_syscall(kaiocb);
+                                break;
+			default:
+				kaio_io_complete(kaiocb, 0, -EINVAL, 0);
+			}
+		}
+	}
+
+	spin_lock(&kq->kaioq_lock);
+	if (atomic_read(&kq->kaiosem.count) > 0) {
+		/*
+		 * There are queued I/Os; process them now.
+		 */
+		spin_unlock(&kq->kaioq_lock);
+		goto drain_io;
+	}
+	lock_kernel();
+	kq->kaioq_nslaves--;
+	spin_unlock(&kq->kaioq_lock);
+	up(&kq->kaioq_exit_sem);
+	unlock_kernel();
+}
+
+/*
+ * This is an asynchronous generic file read routine, and uses the
+ * inode->i_op->readpage() function for the actual low-level stuff.
+ */
+static inline int
+do_kaio_generic_read(struct file * filp, kaiocb_t *kaiocb)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	size_t pos;
+	struct address_space *mapping = inode->i_mapping;
+	struct page **hash, *page, *page_cache;
+	int i, ret = 0, npages;
+
+	pos = kaiocb->kaio_offset;
+
+	if (pos >= inode->i_size) {
+		/*
+		 * No I/O possible; specified offset beyond file end
+		 */
+		return -EINVAL;
+	}
+
+	i = pos + kaiocb->kaio_nbytes - 1; /* last byte in I/O */
+	if (i > inode->i_size)
+		i = inode->i_size;
+	npages = pageof(i) - pageof(pos) + 1;
+	/*
+	 * Allocate space to hold page pointers.
+	 */
+	if (npages == 1)
+		kaiocb->kaio_pages = &kaiocb->kaio_page_inline;
+	else {
+		kaiocb->kaio_pages =
+			kmalloc(sizeof(struct page *) * npages, GFP_KERNEL);
+		if (!kaiocb->kaio_pages) 
+			return -EAGAIN;
+	}
+	page_cache = 0;
+	pos = pageof(pos) * PAGE_SIZE;
+	for (i = 0; i < npages; i++, pos += PAGE_SIZE) {
+
+retry:
+		/*
+		 * Try to find the data in the page cache..
+		 */
+		hash = page_hash(mapping, pageof(pos));
+		spin_lock(&pagecache_lock);
+		page = __find_page_nolock(mapping, pageof(pos), *hash);
+		if (page) {
+			get_page(page);
+			kaiocb->kaio_pages[i] = page;
+			spin_unlock(&pagecache_lock);
+			continue;
+		}
+
+		/*
+		 * Ok, it wasn't cached, so we need to create a new
+		 * page.. or reuse a page previously allocated,
+		 * and did not use in retry path below (found page in
+		 * hash after allocation).
+		 */
+		if (!page_cache) {
+			spin_unlock(&pagecache_lock);
+			page_cache = page_cache_alloc(mapping);
+			/*
+			 * That could have slept, so go around to the
+			 * very beginning..
+			 */
+			if (page_cache)
+				goto retry;
+			ret = -ENOMEM;
+			break;
+		}
+
+		/*
+		 * Ok, add the new page to the page cache.
+		 */
+		page = page_cache;
+		__add_to_page_cache(page, mapping, pageof(pos), hash);
+		spin_unlock(&pagecache_lock);
+		page_cache = 0;
+		kaiocb->kaio_pages[i] = page;
+
+		/*
+		 * Fire off the I/O; read page may also add page's
+		 * bufferheads to buffer cache.
+		 */
+		if ((ret = mapping->a_ops->readpage(filp, page)))
+			break;
+		run_task_queue(&tq_disk); /* XXX - improves perf. but why ??*/
+	}
+	if (!ret) {
+		kaiocb->kaio_npages = npages;
+		ret = kaio_enqueue(KAIO_INFO(current), kaiocb);
+	}
+	if (ret) { /* recheck return from kaio_enqueue */
+		for (i--; i >=0; i--) {
+			assert(kaiocb->kaio_pages[i]);
+			page_cache_free(kaiocb->kaio_pages[i]);
+		}
+		if (kaiocb->kaio_pages != &kaiocb->kaio_page_inline)
+			kfree(kaiocb->kaio_pages);
+	}
+	if (page_cache)
+		page_cache_free(page_cache);
+	UPDATE_ATIME(inode);
+	return ret;
+}
+
+/*
+ * Initiate buffered async I/O (e.g. file systems).
+ *
+ * Kaiocb describing the I/O is queued as part of a per-task queue (KAIO_INFO).
+ * I/O is actually initiated only in the case of generic_read. For all
+ * other cases, slave threads initiate and wait for queued requests.
+ *
+ */
+static inline int
+do_kaio_fs_rw(int cmd, struct file *filp, struct kaiocb *kaiocb)
+{
+	/*
+	 * if read request & the fop operation is generic,
+	 * use our own parallel async version; for all other
+	 * reads & for writes, asynchronize by queuing f_op to be
+	 * executed directly by slave.
+	 */
+	if (cmd == AIOCMD_READ && filp->f_op->read == generic_file_read) {
+		kaiocb->kaio_cmd = AIOCMD_GENERIC_READ;
+		return(do_kaio_generic_read(filp, kaiocb));
+	} else {
+		return(kaio_enqueue(KAIO_INFO(current), kaiocb));
+	}
+}
+
+/*
+ * kaio_rw: Initiate async I/O read or write.
+ *
+ *	cmd 	= AIOCMD_{READ,WRITE}; ignored for listio.
+ *	uaiocb 	= user space address of aiocb describing request.
+ *	liocb 	= if not null then part of a list io. 
+ *
+ * Kernel lock held across this function. If I/O successfully queued,
+ * kaiocb holds reference to file (with fget, correspoding fput will be done
+ * at io completion/cancellation/exit). Kaiocb also holds references to the
+ * requesting task, the uaiocb (for transmitting back return/error values),
+ * and liocb, if any. A unique id, representing the  kaiocb in a hash table,
+ * is "returned" back to user on successful queueing.
+ *
+ */
+int
+kaio_rw(int cmd, aiocb_t *uaiocb, liocb_t *liocb)
+{
+	struct file 	*filp = NULL;
+	aiocb_t		aiocb;
+	int 		ret = 0;
+	kaiocb_t 	*kaiocb = NULL;
+
+
+	if (copy_from_user(&aiocb, uaiocb, sizeof(aiocb_t)))
+		return -EFAULT;
+
+	if (kaio_nr_hashed > CONFIG_AIO_MAX) {
+		ret = -EAGAIN;
+		goto rw_error;
+	}
+	if (liocb) {
+		switch (aiocb.aio_lio_opcode) {
+		case LIO_READ:
+			cmd = AIOCMD_READ;
+			break;
+		case LIO_WRITE:
+			cmd = AIOCMD_WRITE;
+			break;
+		case LIO_NOP:
+			/*
+			 * No easy way to return to caller an
+			 * indication to ignore; so, alternately,
+			 * mark as complete.
+			 */
+			if (!lio_complete(liocb, 1, 0))
+				unlock_kernel(); /* not really sleeping */
+			return 0;
+		default:
+			ret =  -EINVAL;
+			goto rw_error;
+		}
+	}
+	if (!(filp = fget(aiocb.aio_fildes))) {
+		ret = -EBADF;
+		goto rw_error;
+	}
+	if (!(filp->f_mode &
+		(cmd == AIOCMD_READ ? FMODE_READ: FMODE_WRITE)))
+	{
+		ret = -EBADF;
+		goto rw_error;
+	}
+	if (aiocb.aio_nbytes) {
+
+		kaiocb = kmalloc(sizeof(kaiocb_t), GFP_KERNEL);
+		if (!kaiocb) {
+			ret = -EAGAIN;
+			goto rw_error;
+		}
+		kaiocb->kaio_filp = filp;
+		kaiocb->kaio_buf = aiocb.aio_buf;
+		kaiocb->kaio_nbytes = aiocb.aio_nbytes;
+		kaiocb->kaio_offset = aiocb.aio_offset;
+		kaiocb->kaio_sigevent = aiocb.aio_sigevent;
+		kaiocb->kaio_task = current;
+		kaiocb->kaio_kq = KAIO_INFO(current);
+		kaiocb->kaio_uaiocb = uaiocb;
+		kaiocb->kaio_cmd = cmd;
+		kaiocb->kaio_liocb = liocb;
+		kaiocb->kaio_pages = 0;
+#ifdef KAIO_STATS
+                memset(kaiocb->kaio_times, 0, sizeof (kaiocb->kaio_times));
+#endif
+                if (cmd == AIOCMD_READ &&
+			!access_ok(VERIFY_WRITE, aiocb.aio_buf, aiocb.aio_nbytes))
+		{
+			ret = -EFAULT;
+			goto rw_error;
+		}
+		ret = locks_verify_area(cmd == AIOCMD_READ ?
+					FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
+					filp->f_dentry->d_inode, filp,
+					aiocb.aio_offset, aiocb.aio_nbytes);
+		if (ret)
+			goto rw_error;
+#if defined(CONFIG_RAW)
+		if (kaio_is_raw(filp))
+			ret = do_kaio_raw_rw(cmd, filp, kaiocb);
+		else
+#endif
+			ret = do_kaio_fs_rw(cmd, filp, kaiocb);
+	}
+	if (!ret) {
+		kaio_key_t kkey;
+
+		kkey.kaio_kid = kaiocb->kaio_id;
+		kkey.kaio_kq = current->kaio_info;
+
+		if (copy_to_user(&uaiocb->aio_key, &kkey, sizeof(kkey)))
+			ret = -EFAULT;
+	}
+rw_error:
+	if (ret) {
+		if (filp)
+			fput(filp);
+		if (kaiocb)
+			kfree(kaiocb);
+	}
+	if (liocb && ret) {
+		/*
+		 * Have to set individual errors for list io
+		 */
+		 (void) put_user(-ret, &uaiocb->aio_error);
+	}
+	return ret;
+}
+
+int
+kaio_syscall(int cmd, aiocb_t *uaiocb)
+{
+        struct file     *filp = NULL;
+        aiocb_t         aiocb;
+        int             ret = 0;
+        kaiocb_t        *kaiocb = NULL;
+
+
+        if (copy_from_user(&aiocb, uaiocb, sizeof(aiocb_t)))
+                return -EFAULT;
+        if (!(filp = fget(aiocb.aio_fildes)))
+                return -EBADF;
+
+        kaiocb = kmalloc(sizeof(kaiocb_t), GFP_KERNEL);
+        if (!kaiocb) {
+                ret = -EAGAIN;
+                goto error;
+        }
+        kaiocb->kaio_fd = aiocb.aio_fildes;
+        kaiocb->kaio_filp = filp;
+        kaiocb->kaio_buf = aiocb.aio_buf;
+        kaiocb->kaio_nbytes = aiocb.aio_nbytes;
+        kaiocb->kaio_offset = aiocb.aio_offset;
+        kaiocb->kaio_sigevent = aiocb.aio_sigevent;
+        kaiocb->kaio_task = current;
+        kaiocb->kaio_kq = KAIO_INFO(current);
+        kaiocb->kaio_uaiocb = uaiocb;
+        kaiocb->kaio_cmd = cmd;
+        kaiocb->kaio_liocb = NULL;
+        kaiocb->kaio_pages = 0;
+#ifdef KAIO_STATS
+        memset(kaiocb->kaio_times, 0, sizeof (kaiocb->kaio_times));
+#endif
+
+        ret = kaio_enqueue(KAIO_INFO(current), kaiocb);
+        if (!ret) {
+                kaio_key_t kkey;
+
+                kkey.kaio_kid = kaiocb->kaio_id;
+                kkey.kaio_kq = current->kaio_info;
+
+                if (copy_to_user(&uaiocb->aio_key, &kkey, sizeof(kkey)))
+                        ret = -EFAULT;
+        }
+ error:
+        if (ret) {
+                if (filp)
+                        fput(filp);
+                if (kaiocb)
+                        kfree(kaiocb);
+        }
+        return ret;
+}
+
+static void
+kaio_set_list_errors(aiocb_t *list[], int nent, int error)
+{
+	int	i;
+	aiocb_t *uaiocbp;
+
+	/*
+	 * Have to set individual errors for each aiocb.
+	 */
+	for (i = 0; i < nent; i++)
+		if (get_user(uaiocbp, &list[i]) == 0 && uaiocbp)
+			 (void) put_user(-error, &uaiocbp->aio_error);
+}
+
+int
+kaio_list_io(int mode, struct aiocb *list[], int nent, sigevent_t *sig)
+{
+	liocb_t *liocb;
+	aiocb_t *aiocbp;
+	int	i = 0, ret = 0, ignore = 0, error = 0;
+
+	liocb = kmalloc(sizeof(liocb_t), GFP_KERNEL);
+	if (!liocb) {
+		ret = -EAGAIN;
+		kaio_set_list_errors(list, nent, ret);
+		return ret;
+	}
+
+	liocb->lio_lock = SPIN_LOCK_UNLOCKED;
+	liocb->lio_nent = nent;
+	liocb->lio_done = 0;
+	liocb->lio_mode = mode;
+	init_waitqueue_head(&liocb->lio_wait);
+	liocb->lio_task = current;
+	if (sig) {
+		if (copy_from_user(&liocb->lio_sigevent,
+			sig, sizeof(sigevent_t)))
+		{
+			ret =  -EFAULT;
+			kaio_set_list_errors(list, nent, ret);
+			error = nent; /* all are in error */
+			goto lio_error;
+		}
+	} else
+		liocb->lio_sigevent.sigev_notify = SIGEV_NONE;
+	for ( ; i < nent; i++) {
+		if (get_user(aiocbp, &list[i])) {
+			ret = -EFAULT;
+			error++;
+			continue;
+		}
+		if (!aiocbp) {
+			ignore++;
+			continue;
+		}
+		/* 0 == cmd for kaio_rw derived from aiocbp */
+		if ((ret = kaio_rw(0, aiocbp, liocb)))
+			error++;
+	}
+	if (!error) {
+		if (!lio_complete(liocb, ignore, 0)) {
+			if (mode == LIO_WAIT)
+				interruptible_sleep_on(&liocb->lio_wait);
+			unlock_kernel();
+		}
+		if (mode == LIO_WAIT)
+			kfree(liocb);
+		return 0;
+	}
+lio_error:
+	if (!lio_complete(liocb, (ignore + error), 0)) {
+		/* pending I/O's; but we are not interested */
+		liocb->lio_mode = LIO_NOWAIT;
+		liocb->lio_sigevent.sigev_notify = SIGEV_NONE;
+		unlock_kernel();
+	} else if (mode != LIO_NOWAIT) {
+		/* if no wait then lio_complete frees liocb */
+		kfree(liocb);
+	}
+	return ret;
+}
+#endif /* CONFIG_AIO */
 
 /*
  * This is the "read()" routine for all filesystems
