diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes	Tue Oct 15 20:29:21 2002
+++ b/Documentation/Changes	Tue Oct 15 20:29:21 2002
@@ -95,7 +95,7 @@
 Make
 ----
 
-You will need Gnu make 3.77 or later to build the kernel.
+You will need Gnu make 3.78 or later to build the kernel.
 
 Binutils
 --------
@@ -287,9 +287,9 @@
 ----------
 o  <ftp://ftp.gnu.org/gnu/gcc/gcc-2.95.3.tar.gz>
 
-Make 3.77
+Make 3.78
 ---------
-o  <ftp://ftp.gnu.org/gnu/make/make-3.77.tar.gz>
+o  <ftp://ftp.gnu.org/gnu/make/make-3.78.1.tar.gz>
 
 Binutils
 --------
diff -Nru a/Documentation/DocBook/scsidrivers.tmpl b/Documentation/DocBook/scsidrivers.tmpl
--- a/Documentation/DocBook/scsidrivers.tmpl	Tue Oct 15 20:29:10 2002
+++ b/Documentation/DocBook/scsidrivers.tmpl	Tue Oct 15 20:29:10 2002
@@ -60,7 +60,7 @@
 </para>
   </chapter>
 
-  <chapter id="driver_struct">
+  <chapter id="driver-struct">
       <title>Driver structure</title>
   <para>
 Traditionally a lower level driver for the scsi subsystem has been
diff -Nru a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
--- a/Documentation/SubmittingPatches	Tue Oct 15 20:29:11 2002
+++ b/Documentation/SubmittingPatches	Tue Oct 15 20:29:11 2002
@@ -243,7 +243,7 @@
 	if (!dev)
 		return -ENODEV;
 	#ifdef CONFIG_NET_FUNKINESS
-		init_funky_net(dev);
+	init_funky_net(dev);
 	#endif
 
 Cleaned-up example:
diff -Nru a/Documentation/arm/XScale/ADIFCC/80200EVB b/Documentation/arm/XScale/ADIFCC/80200EVB
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/arm/XScale/ADIFCC/80200EVB	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,111 @@
+
+Board Overview
+-----------------------------
+
+This is an beta release of the Xscale Linux port to the ADI 80200EVB
+evaluation board.
+
+The 80200EVB is an evaluation platform for ADI Engineering's high-performance
+80200FCC chipset for the Intel 80200 XScale CPU. The 80200FCC is an open
+source FPGA based system that contains a PCI unit and a high performance
+memory controller.
+
+In addition to the 80200FCC, the board also contains a 16C550 UART, and 4MB
+of flash.
+
+The board is still under development and currently only the UART is functional
+as the PCI bits have not been programmed into the FPGA.
+
+For more information on the board, see http://www.adiengineering.com
+
+Port Status
+-----------------------------
+
+Supported:
+
+- Onboard UART (Polled operation only)
+- Cache/TLB locking on 80200 CPU
+
+TODO:
+
+- PCI when hardware supports it
+
+Building the Kernel
+-----------------------------
+change Linux makefile
+make adi_evb_config
+make oldconfig
+make dep
+make zImage
+
+Loading Linux
+-----------------------------
+
+Before you can use Linux on the ADI board, you need to grab the following:
+
+ADI 80200EVB Monitor:
+	ftp://source.mvista.com/pub/xscale/ADI_EVB/monitor.srec
+
+ADI JFFS2 Image:
+	ftp://source.mvista.com/pub/xscale/ADI_EVB/adi.jffs2
+
+Once you've got the Cygnus prompt, type in the following command:
+
+	load
+
+On another terminal window:
+
+	cat monitor.srec > /dev/ttyS0
+
+(replace ttyS0 with the serial port you are using)
+
+Once completed, just type 'go' at the cygmon prompt and you should see:
+
+	MontaVista IQ80310 Monitor Version 0.1
+	monitor>
+
+Type 'b 115200' at the prompt and change your terminal speed to 115200
+
+The first thing to do is to upload and burn the jffs2 filesystem image
+onto the boards 4MB of flash:
+
+	monitor> u c1000000
+	Uploading file at 0xc1000000
+	Now send file with ymodem
+
+Do as the monitor says and transfer the file adi.jffs2.  Once complete,
+the following will copy the jffs2 image to location 0x80000 in the flash.
+
+	monitor> f 8000 c1000000 200000
+	Erasing sector 0x00080000
+	Writing sector 0x00080000 with data at 0xC1000000
+	Erasing sector 0x000A0000
+	Writing sector 0x000A0000 with data at 0xC1020000
+	Erasing sector 0x000C0000
+	...
+
+Now use the same command as above to upload your zImage to location c1000000.
+When you've done that, type 'j c1000000' to run Linux.  Login as
+root and you're all set to go.
+
+Misc Notes
+-----------------------------
+
+The current version of the HW does not have an onboard timer, so the 80200
+PMU is not available for general use as it is being used for a timer source.
+
+By default, the MTD driver reserves the first 512K for bootloaders and
+the remaining 3.5MB for the filesystem. You can edit drivers/mtd/map/adi_evb.c
+to change this as needed for your application.
+
+Contributors
+-----------------------------
+
+Thanks to ADI Engineering for providing the hardware for development
+
+Deepak Saxena <dsaxena@mvista.com> - Initial port
+
+-----------------------------
+Enjoy.  If you have any problem please contact Deepak Saxena
+dsaxena@mvista.com
+
diff -Nru a/Documentation/arm/XScale/IOP310/IQ80310 b/Documentation/arm/XScale/IOP310/IQ80310
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/arm/XScale/IOP310/IQ80310	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,295 @@
+
+Board Overview
+-----------------------------
+
+The Cyclone IQ80310 board is an evaluation platform for Intel's 80200 Xscale
+CPU and 80312 Intelligent I/O chipset (collectively called IOP310 chipset).
+
+The 80312 contains dual PCI hoses (called the ATUs), a PCI-to-PCI bridge,
+three DMA channels (1 on secondary PCI, one on primary PCI ), I2C, I2O
+messaging unit, XOR unit for RAID operations, a bus performance monitoring
+unit, and a memory controller with ECC features.
+
+For more information on the board, see http://developer.intel.com/iio
+
+Port Status
+-----------------------------
+
+Supported:
+
+- MTD/JFFS/JFFS2
+- NFS root
+- RAMDISK root
+- 2ndary PCI slots
+- Onboard ethernet
+- Serial ports (ttyS0/S1)
+- Cache/TLB locking on 80200 CPU
+- Performance monitoring unit on 80200 CPU
+- 80200 Performance Monitoring Unit
+- Acting as a system controller on Cyclone 80303BP PCI backplane
+- DMA engines (EXPERIMENTAL)
+- 80312 Bus Performance Monitor (EXPERIMENTAL)
+- Application Accelerator Unit (XOR engine for RAID) (EXPERIMENTAL)
+- Messaging Unit (EXPERIMENTAL)
+
+TODO:
+- I2C
+
+Building the Kernel
+-----------------------------
+make iq80310_config
+make oldconfig
+make dep
+make zImage
+
+This will build an image setup for BOOTP/NFS root support.  To change this,
+just run make menuconfig and disable nfs root or add a "root=" option.
+
+Preparing the Hardware
+-----------------------------
+
+This document assumes you're using a Rev D or newer board running
+Redboot as the bootloader.
+
+The as-supplied RedBoot image appears to leave the first page of RAM
+in a corrupt state such that certain words in that page are unwritable
+and contain random data.  The value of the data, and the location within
+the first page changes with each boot, but is generally in the range
+0xa0000150 to 0xa0000fff.
+
+You can grab the source from the ECOS CVS or you can get a prebuilt image
+from:
+
+   ftp://source.mvista.com/pub/xscale/iop310/IQ80310/redboot.bin
+
+which is:
+
+    # strings redboot.bin | grep bootstrap
+    RedBoot(tm) bootstrap and debug environment, version UNKNOWN - built 14:58:21, Aug 15 2001
+
+md5sum of this version:
+
+    bcb96edbc6f8e55b16c165930b6e4439  redboot.bin
+
+You have two options to program it:
+
+1. Using the FRU program (see the instructions in the user manual).
+
+2. Using a Linux host, with MTD support built into the host kernel:
+   - ensure that the RedBoot image is not locked (issue the following
+     command under the existing RedBoot image):
+    RedBoot> fis unlock -f 0 -l 0x40000
+   - switch S3-1 and S3-2 on.
+   - reboot the host
+   - login as root
+   - identify the 80310 card:
+    # lspci
+    ...
+    00:0c.1 Memory controller: Intel Corporation 80310 IOP [IO Processor] (rev 01)
+   - in this example, bus 0, slot 0c, function 1.
+   - insert the MTD modules, and the PCI map module:
+    # insmod drivers/mtd/maps/pci.o
+   - locate the MTD device (using the bus, slot, function)
+    # cat /proc/mtd
+    dev:    size   erasesize  name
+    mtd0: 00800000 00020000 "00:0c.1"
+   - in this example, it is mtd device 0.  Yours will be different.
+     Check carefully.
+   - program the flash
+    # cat redboot.bin > /dev/mtdblock0
+   - check the kernel message log for errors (some cat commands don't
+     error on failure)   
+    # dmesg
+   - switch S3-1 and S3-2 off
+   - reboot host
+
+In any case, make sure you do an 'fis init' command once you boot with the new
+RedBoot image.
+
+
+
+Downloading Linux
+-----------------------------
+
+Assuming you have your development system setup to act as a bootp/dhcp
+server and running tftp:
+
+   RedBoot> load -r -b 0xa1008000 /tftpboot/zImage.xs
+   Raw file loaded 0xa1008000-0xa1094bd8
+
+If you're not using dhcp/tftp, you can use y-modem instead:
+
+   RedBoot> load -r -b 0xa1008000 -m y
+
+Note that on Rev D. of the board, tftp does not work due to intermittent
+interrupt issues, so you need to download using ymodem.
+
+Once the download is completed:
+
+   RedBoot> go 0xa1008000
+
+Root Devices
+-----------------------------
+
+A kernel is not useful without a root filesystem, and you have several
+choices with this board:  NFS root, RAMDISK, or JFFS/JFFS2.  For development
+purposes, it is suggested that you use NFS root for easy access to various
+tools.  Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on
+the flash device.
+
+MTD on the IQ80310
+-----------------------------
+
+Linux on the IQ80310 supports RedBoot FIS paritioning if it is enabled.
+Out of the box, once you've done 'fis init' on RedBoot, you will get
+the following partitioning scheme:
+
+   root@192.168.0.14:~# cat /proc/mtd
+   dev:    size   erasesize  name
+   mtd0: 00040000 00020000 "RedBoot"
+   mtd1: 00040000 00020000 "RedBoot[backup]"
+   mtd2: 0075f000 00020000 "unallocated space"
+   mtd3: 00001000 00020000 "RedBoot config"
+   mtd4: 00020000 00020000 "FIS directory"
+
+To create an FIS directory, you need to use the fis command in RedBoot.
+As an example, you can burn the kernel into the flash once it's downloaded:
+
+   RedBoot> fis create -b 0xa1008000 -l 0x8CBAC -r 0xa1008000 -f 0x80000 kernel
+   ... Erase from 0x00080000-0x00120000: .....
+   ... Program from 0xa1008000-0xa1094bac at 0x00080000: .....
+   ... Unlock from 0x007e0000-0x00800000: .
+   ... Erase from 0x007e0000-0x00800000: .
+   ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: .
+   ... Lock from 0x007e0000-0x00800000: .
+
+   RedBoot> fis list
+   Name              FLASH addr  Mem addr    Length      Entry point
+   RedBoot           0x00000000  0x00000000  0x00040000  0x00000000
+   RedBoot[backup]   0x00040000  0x00040000  0x00040000  0x00000000
+   RedBoot config    0x007DF000  0x007DF000  0x00001000  0x00000000
+   FIS directory     0x007E0000  0x007E0000  0x00020000  0x00000000
+   kernel            0x00080000  0xA1008000  0x000A0000  0x00000000
+
+This leads to the following Linux MTD setup:
+
+   mtroot@192.168.0.14:~# cat /proc/mtd
+   dev:    size   erasesize  name
+   mtd0: 00040000 00020000 "RedBoot"
+   mtd1: 00040000 00020000 "RedBoot[backup]"
+   mtd2: 000a0000 00020000 "kernel"
+   mtd3: 006bf000 00020000 "unallocated space"
+   mtd4: 00001000 00020000 "RedBoot config"
+   mtd5: 00020000 00020000 "FIS directory"
+
+Note that there is not a 1:1 mapping to the number of RedBoot paritions to
+MTD partitions as unused space also gets allocated into MTD partitions.
+
+As an aside, the -r option when creating the Kernel entry allows you to
+simply do an 'fis load kernel' to copy the image from flash into memory.
+You can then do an 'fis go 0xa1008000' to start Linux.
+
+If you choose to use static partitioning instead of the RedBoot partioning:
+
+   /dev/mtd0  0x00000000 - 0x0007ffff: Boot Monitor     (512k)
+   /dev/mtd1  0x00080000 - 0x0011ffff: Kernel Image     (640K)
+   /dev/mtd2  0x00120000 - 0x0071ffff: File System      (6M)
+   /dev/mtd3  0x00720000 - 0x00800000: RedBoot Reserved (896K)
+
+To use a JFFS1/2 root FS, you need to donwload the JFFS image using either
+tftp or ymodem, and then copy it to flash:
+
+   RedBoot> load -r -b 0xa1000000 /tftpboot/jffs.img
+   Raw file loaded 0xa1000000-0xa1600000
+   RedBoot> fis create -b 0xa1000000 -l 0x600000 -f 0x120000 jffs
+   ... Erase from 0x00120000-0x00720000: ..................................
+   ... Program from 0xa1000000-0xa1600000 at 0x00120000: ..................
+   ......................
+   ... Unlock from 0x007e0000-0x00800000: .
+   ... Erase from 0x007e0000-0x00800000: .
+   ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: .
+   ... Lock from 0x007e0000-0x00800000: .
+   RedBoot> fis list
+   Name              FLASH addr  Mem addr    Length      Entry point
+   RedBoot           0x00000000  0x00000000  0x00040000  0x00000000
+   RedBoot[backup]   0x00040000  0x00040000  0x00040000  0x00000000
+   RedBoot config    0x007DF000  0x007DF000  0x00001000  0x00000000
+   FIS directory     0x007E0000  0x007E0000  0x00020000  0x00000000
+   kernel            0x00080000  0xA1008000  0x000A0000  0xA1008000
+   jffs              0x00120000  0x00120000  0x00600000  0x00000000
+
+This looks like this in Linux:
+
+   root@192.168.0.14:~# cat /proc/mtd
+   dev:    size   erasesize  name
+   mtd0: 00040000 00020000 "RedBoot"
+   mtd1: 00040000 00020000 "RedBoot[backup]"
+   mtd2: 000a0000 00020000 "kernel"
+   mtd3: 00600000 00020000 "jffs"
+   mtd4: 000bf000 00020000 "unallocated space"
+   mtd5: 00001000 00020000 "RedBoot config"
+   mtd6: 00020000 00020000 "FIS directory"
+
+You need to boot the kernel once and watch the boot messages to see how the
+JFFS RedBoot partition mapped into the MTD partition scheme.
+
+You can grab a pre-built JFFS image to use as a root file system at:
+
+   ftp://source.mvista.com/pub/xscale/iop310/IQ80310/jffs.img
+
+For detailed info on using MTD and creating a JFFS image go to:
+
+   http://www.linux-mtd.infradead.org.
+
+For details on using RedBoot's FIS commands, type 'fis help' or consult
+your RedBoot manual.
+
+Contributors
+-----------------------------
+
+Thanks to Intel Corporation for providing the hardware.
+
+John Clark <jclark@teamasa.com> - Initial discovery of RedBoot issues
+Dave Jiang <dave.jiang@intel.com> - IRQ demux fixes, AAU, DMA, MU
+Nicolas Pitre <nico@cam.org> - Initial port, cleanup, debugging
+Matt Porter <mporter@mvista.com> - PCI subsystem development, debugging
+Tim Sanders <tsanders@sanders.org> - Initial PCI code
+Mark Salter <msalter@redhat.com> - RedBoot fixes
+Deepak Saxena <dsaxena@mvista.com> - Cleanup, debug, cache lock, PMU
+
+-----------------------------
+Enjoy.
+
+If you have any problems please contact Deepak Saxena <dsaxena@mvista.com>
+
+A few notes from rmk
+-----------------------------
+
+These are notes of my initial experience getting the IQ80310 Rev D up and
+running.  In total, it has taken many hours to work out what's going on...
+The version of redboot used is:
+
+ RedBoot(tm) bootstrap and debug environment, version UNKNOWN - built 14:58:21, Aug 15 2001
+
+
+1. I've had a corrupted download of the redboot.bin file from Montavista's
+   FTP site.  It would be a good idea if there were md5sums, sum or gpg
+   signatures available to ensure the integrity of the downloaded files.
+   The result of this was an apparantly 100% dead card.
+
+2. RedBoot Intel EtherExpress Pro 100 driver seems to be very unstable -
+   I've had it take out the whole of a 100mbit network for several minutes.
+   The Hub indiates ZERO activity, despite machines attempting to communicate.
+   Further to this, while tftping the kernel, the transfer will stall regularly,
+   and might even drop the link LED.
+
+3. There appears to be a bug in the Intel Documentation Pack that comes with
+   the IQ80310 board.  Serial port 1, which is the socket next to the LEDs
+   is address 0xfe810000, not 0xfe800000.
+
+   Note that RedBoot uses either serial port 1 OR serial port 2, so if you
+   have your console connected to the wrong port, you'll see redboot messages
+   but not kernel boot messages.
+
+4. Trying to use fconfig to setup a boot script fails - it hangs when trying
+   to erase the flash.
diff -Nru a/Documentation/filesystems/afs.txt b/Documentation/filesystems/afs.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/filesystems/afs.txt	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,155 @@
+			     kAFS: AFS FILESYSTEM
+			     ====================
+
+ABOUT
+=====
+
+This filesystem provides a fairly simple AFS filesystem driver. It is under
+development and only provides very basic facilities. It does not yet support
+the following AFS features:
+
+	(*) Write support.
+	(*) Communications security.
+	(*) Local caching.
+	(*) pioctl() system call.
+	(*) Automatic mounting of embedded mountpoints.
+
+
+USAGE
+=====
+
+When inserting the driver modules the root cell must be specified along with a
+list of volume location server IP addresses:
+
+	insmod rxrpc.o
+	insmod kafs.o rootcell=cambridge.redhat.com:172.16.18.73:172.16.18.91
+
+The first module is a driver for the RxRPC remote operation protocol, and the
+second is the actual filesystem driver for the AFS filesystem.
+
+Once the module has been loaded, more modules can be added by the following
+procedure:
+
+	echo add grand.central.org 18.7.14.88:128.2.191.224 >/proc/fs/afs/cells
+
+Where the parameters to the "add" command are the name of a cell and a list of
+volume location servers within that cell.
+
+Filesystems can be mounted anywhere by commands similar to the following:
+
+	mount -t afs "%cambridge.redhat.com:root.afs." /afs
+	mount -t afs "#cambridge.redhat.com:root.cell." /afs/cambridge
+	mount -t afs "#root.afs." /afs
+	mount -t afs "#root.cell." /afs/cambridge
+
+  NB: When using this on Linux 2.4, the mount command has to be different,
+      since the filesystem doesn't have access to the device name argument:
+
+	mount -t afs none /afs -ovol="#root.afs."
+
+Where the initial character is either a hash or a percent symbol depending on
+whether you definitely want a R/W volume (hash) or whether you'd prefer a R/O
+volume, but are willing to use a R/W volume instead (percent).
+
+The name of the volume can be suffixes with ".backup" or ".readonly" to
+specify connection to only volumes of those types.
+
+The name of the cell is optional, and if not given during a mount, then the
+named volume will be looked up in the cell specified during insmod.
+
+Additional cells can be added through /proc (see later section).
+
+
+MOUNTPOINTS
+===========
+
+AFS has a concept of mountpoints. These are specially formatted symbolic links
+(of the same form as the "device name" passed to mount). kAFS presents these
+to the user as directories that have special properties:
+
+  (*) They cannot be listed. Running a program like "ls" on them will incur an
+      EREMOTE error (Object is remote).
+
+  (*) Other objects can't be looked up inside of them. This also incurs an
+      EREMOTE error.
+
+  (*) They can be queried with the readlink() system call, which will return
+      the name of the mountpoint to which they point. The "readlink" program
+      will also work.
+
+  (*) They can be mounted on (which symbolic links can't).
+
+
+PROC FILESYSTEM
+===============
+
+The rxrpc module creates a number of files in various places in the /proc
+filesystem:
+
+  (*) Firstly, some information files are made available in a directory called
+      "/proc/net/rxrpc/". These list the extant transport endpoint, peer,
+      connection and call records.
+
+  (*) Secondly, some control files are made available in a directory called
+      "/proc/sys/rxrpc/". Currently, all these files can be used for is to
+      turn on various levels of tracing.
+
+The AFS modules creates a "/proc/fs/afs/" directory and populates it:
+
+  (*) A "cells" file that lists cells currently known to the afs module.
+
+  (*) A directory per cell that contains files that list volume location
+      servers, volumes, and active servers known within that cell.
+
+
+THE CELL DATABASE
+=================
+
+The filesystem maintains an internal database of all the cells it knows and
+the IP addresses of the volume location servers for those cells. The cell to
+which the computer belongs is added to the database when insmod is performed
+by the "rootcell=" argument.
+
+Further cells can be added by commands similar to the following:
+
+	echo add CELLNAME VLADDR[:VLADDR][:VLADDR]... >/proc/fs/afs/cells
+	echo add grand.central.org 18.7.14.88:128.2.191.224 >/proc/fs/afs/cells
+
+No other cell database operations are available at this time.
+
+
+EXAMPLES
+========
+
+Here's what I use to test this. Some of the names and IP addresses are local
+to my internal DNS. My "root.afs" partition has a mount point within it for
+some public volumes volumes.
+
+insmod -S /tmp/rxrpc.o 
+insmod -S /tmp/kafs.o rootcell=cambridge.redhat.com:172.16.18.73:172.16.18.91
+
+mount -t afs \%root.afs. /afs
+mount -t afs \%cambridge.redhat.com:root.cell. /afs/cambridge.redhat.com/
+
+echo add grand.central.org 18.7.14.88:128.2.191.224 > /proc/fs/afs/cells 
+mount -t afs "#grand.central.org:root.cell." /afs/grand.central.org/
+mount -t afs "#grand.central.org:root.archive." /afs/grand.central.org/archive
+mount -t afs "#grand.central.org:root.contrib." /afs/grand.central.org/contrib
+mount -t afs "#grand.central.org:root.doc." /afs/grand.central.org/doc
+mount -t afs "#grand.central.org:root.project." /afs/grand.central.org/project
+mount -t afs "#grand.central.org:root.service." /afs/grand.central.org/service
+mount -t afs "#grand.central.org:root.software." /afs/grand.central.org/software
+mount -t afs "#grand.central.org:root.user." /afs/grand.central.org/user
+
+umount /afs/grand.central.org/user
+umount /afs/grand.central.org/software
+umount /afs/grand.central.org/service
+umount /afs/grand.central.org/project
+umount /afs/grand.central.org/doc
+umount /afs/grand.central.org/contrib
+umount /afs/grand.central.org/archive
+umount /afs/grand.central.org
+umount /afs/cambridge.redhat.com
+umount /afs
+rmmod kafs
+rmmod rxrpc
diff -Nru a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
--- a/Documentation/filesystems/proc.txt	Tue Oct 15 20:29:15 2002
+++ b/Documentation/filesystems/proc.txt	Tue Oct 15 20:29:15 2002
@@ -966,7 +966,7 @@
 Contains, as a percentage of total system memory, the number of pages at which
 the pdflush background writeback daemon will start writing out dirty data.
 
-dirty_async_ratio
+dirty_ratio
 -----------------
 
 Contains, as a percentage of total system memory, the number of pages at which
diff -Nru a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
--- a/Documentation/filesystems/vfat.txt	Tue Oct 15 20:29:17 2002
+++ b/Documentation/filesystems/vfat.txt	Tue Oct 15 20:29:17 2002
@@ -8,6 +8,10 @@
 
 VFAT MOUNT OPTIONS
 ----------------------------------------------------------------------
+umask=###     -- The permission mask (see umask(1)) for the regulare file.
+                 The default is the umask of current process.
+dmask=###     -- The permission mask for the directory.
+                 The default is the umask of current process.
 codepage=###  -- Sets the codepage for converting to shortname characters
 		 on FAT and VFAT filesystems.  By default, codepage 437
 		 is used.  This is the default for the U.S. and some
@@ -31,10 +35,6 @@
 		 illegal on the vfat filesystem.  The escape sequence
 		 that gets used is ':' and the four digits of hexadecimal
 		 unicode.
-posix=<bool>  -- Allow names of same letters, different case such as
-                 'LongFileName' and 'longfilename' to coexist.  This has some
-                 problems currently because 8.3 conflicts are not handled
-                 correctly for POSIX filesystem compliance.
 nonumtail=<bool> -- When creating 8.3 aliases, normally the alias will
                  end in '~1' or tilde followed by some number.  If this
                  option is set, then if the filename is 
@@ -65,10 +65,6 @@
 * Need to get rid of the raw scanning stuff.  Instead, always use
   a get next directory entry approach.  The only thing left that uses
   raw scanning is the directory renaming code.
-
-* Fix the POSIX filesystem support to work in 8.3 space.  This involves
-  renaming aliases if a conflict occurs between a new filename and
-  an old alias.  This is quite a mess.
 
 
 POSSIBLE PROBLEMS
diff -Nru a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt
--- a/Documentation/filesystems/xfs.txt	Tue Oct 15 20:29:20 2002
+++ b/Documentation/filesystems/xfs.txt	Tue Oct 15 20:29:20 2002
@@ -29,12 +29,6 @@
 	The preferred buffered I/O size can also be altered on an
 	individual file basis using the ioctl(2) system call.
 
-  irixsgid
-	Do not inherit the ISGID bit on subdirectories of ISGID
-	directories, if the process creating the subdirectory
-	is not a member of the parent directory group ID.
-	This matches IRIX behavior.
-
   logbufs=value
 	Set the number of in-memory log buffers.  Valid numbers range
 	from 2-8 inclusive.
diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt	Tue Oct 15 20:29:23 2002
+++ b/Documentation/kernel-parameters.txt	Tue Oct 15 20:29:23 2002
@@ -23,6 +23,7 @@
 	HW	Appropriate hardware is enabled.
 	IA-32	IA-32 aka i386 architecture is enabled.
 	IA-64	IA-64 architecture is enabled.
+	IP_PNP	IP DCHP, BOOTP, or RARP is enabled.
 	ISAPNP  ISA PnP code is enabled.
 	ISDN	Appropriate ISDN support is enabled.
 	JOY 	Appropriate joystick support is enabled.
@@ -257,7 +258,7 @@
 
 	initrd=		[BOOT] Specify the location of the initial ramdisk. 
 
-	ip=		[PNP]
+	ip=		[IP_PNP]
 
 	isapnp=		[ISAPNP] Specify RDP, reset, pci_scan and verbosity.
 
@@ -279,10 +280,14 @@
  
 	kbd-reset	[VT]
 
-	keep_initrd	[HW, ARM]
+	keepinitrd	[HW, ARM]
 
 	load_ramdisk=	[RAM] List of ramdisks to load from floppy.
 
+	lockd.udpport=	[NFS]
+
+	lockd.tcpport=	[NFS]
+
 	logi_busmouse=	[HW, MOUSE]
 
 	lp=0		[LP]	Specify parallel ports to use, e.g,
@@ -323,6 +328,8 @@
 				to off as the mainboard support is not always present.
 				You must activate it as a boot option
 
+	mca-pentium	[BUGS=IA-32]
+
 	mcd=		[HW,CD]
 
 	mcdx=		[HW,CD]
@@ -335,6 +342,11 @@
 
 	megaraid=	[HW,SCSI]
  
+	mem=exactmap	[KNL,BOOT,IA-32] enable setting of an exact
+			e820 memory map, as specified by the user.
+			Such mem=exactmap lines can be constructed
+			based on BIOS output or other requirements.
+
 	mem=nn[KMG]	[KNL,BOOT] force use of a specific amount of
 			memory; to be used when the kernel is not able
 			to see the whole system memory or for test.
@@ -390,7 +402,9 @@
 
 	nohlt		[BUGS=ARM]
  
-	no-hlt		[BUGS=IA-32]
+	no-hlt		[BUGS=IA-32] Tells the kernel that the hlt
+			instruction doesn't work correctly and not to
+			use it.
 
 	noht		[SMP,IA-32] Disables P4 Xeon(tm) HyperThreading.
 
@@ -536,6 +550,10 @@
 	ro		[KNL] Mount root device read-only on boot.
 
 	root=		[KNL] root filesystem.
+
+	rootflags=	[KNL] set root filesystem mount option string
+
+	rootfstype=	[KNL] set root filesystem type
 
 	rw		[KNL] Mount root device read-write on boot.
 
diff -Nru a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
--- a/Documentation/sysctl/vm.txt	Tue Oct 15 20:29:19 2002
+++ b/Documentation/sysctl/vm.txt	Tue Oct 15 20:29:19 2002
@@ -18,14 +18,14 @@
 Currently, these files are in /proc/sys/vm:
 - overcommit_memory
 - page-cluster
-- dirty_async_ratio
+- dirty_ratio
 - dirty_background_ratio
 - dirty_expire_centisecs
 - dirty_writeback_centisecs
 
 ==============================================================
 
-dirty_async_ratio, dirty_background_ratio, dirty_expire_centisecs,
+dirty_ratio, dirty_background_ratio, dirty_expire_centisecs,
 dirty_writeback_centisecs:
 
 See Documentation/filesystems/proc.txt
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Tue Oct 15 20:29:17 2002
+++ b/MAINTAINERS	Tue Oct 15 20:29:17 2002
@@ -1592,6 +1592,11 @@
 M:	jb@technologeek.org
 S:	Maintained
 
+TI PARALLEL LINK CABLE DRIVER
+P:     Romain Lievin
+M:     roms@lpg.ticalc.org
+S:     Maintained
+
 TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
 P:	Stephane Dalton
 M:	sdalton@videotron.ca
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Tue Oct 15 20:29:12 2002
+++ b/Makefile	Tue Oct 15 20:29:12 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 42
+SUBLEVEL = 43
 EXTRAVERSION =
 
 # *DOCUMENTATION*
diff -Nru a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
--- a/arch/alpha/kernel/irq.c	Tue Oct 15 20:29:20 2002
+++ b/arch/alpha/kernel/irq.c	Tue Oct 15 20:29:20 2002
@@ -62,13 +62,13 @@
 }
 
 struct hw_interrupt_type no_irq_type = {
-	typename:	"none",
-	startup:	no_irq_startup,
-	shutdown:	no_irq_enable_disable,
-	enable:		no_irq_enable_disable,
-	disable:	no_irq_enable_disable,
-	ack:		no_irq_ack,
-	end:		no_irq_enable_disable,
+	.typename	= "none",
+	.startup	= no_irq_startup,
+	.shutdown	= no_irq_enable_disable,
+	.enable		= no_irq_enable_disable,
+	.disable	= no_irq_enable_disable,
+	.ack		= no_irq_ack,
+	.end		= no_irq_enable_disable,
 };
 
 int
diff -Nru a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
--- a/arch/alpha/kernel/irq_alpha.c	Tue Oct 15 20:29:13 2002
+++ b/arch/alpha/kernel/irq_alpha.c	Tue Oct 15 20:29:13 2002
@@ -213,19 +213,19 @@
 static unsigned int rtc_startup(unsigned int irq) { return 0; }
 
 struct irqaction timer_irqaction = {
-	handler:	timer_interrupt,
-	flags:		SA_INTERRUPT,
-	name:		"timer",
+	.handler	= timer_interrupt,
+	.flags		= SA_INTERRUPT,
+	.name		= "timer",
 };
 
 static struct hw_interrupt_type rtc_irq_type = {
-	typename:	"RTC",
-	startup:	rtc_startup,
-	shutdown:	rtc_enable_disable,
-	enable:		rtc_enable_disable,
-	disable:	rtc_enable_disable,
-	ack:		rtc_enable_disable,
-	end:		rtc_enable_disable,
+	.typename	= "RTC",
+	.startup	= rtc_startup,
+	.shutdown	= rtc_enable_disable,
+	.enable		= rtc_enable_disable,
+	.disable	= rtc_enable_disable,
+	.ack		= rtc_enable_disable,
+	.end		= rtc_enable_disable,
 };
 
 void __init
@@ -238,16 +238,16 @@
 
 /* Dummy irqactions.  */
 struct irqaction isa_cascade_irqaction = {
-	handler:	no_action,
-	name:		"isa-cascade"
+	.handler	= no_action,
+	.name		= "isa-cascade"
 };
 
 struct irqaction timer_cascade_irqaction = {
-	handler:	no_action,
-	name:		"timer-cascade"
+	.handler	= no_action,
+	.name		= "timer-cascade"
 };
 
 struct irqaction halt_switch_irqaction = {
-	handler:	no_action,
-	name:		"halt-switch"
+	.handler	= no_action,
+	.name		= "halt-switch"
 };
diff -Nru a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c
--- a/arch/alpha/kernel/irq_i8259.c	Tue Oct 15 20:29:20 2002
+++ b/arch/alpha/kernel/irq_i8259.c	Tue Oct 15 20:29:20 2002
@@ -85,21 +85,21 @@
 }
 
 struct hw_interrupt_type i8259a_irq_type = {
-	typename:	"XT-PIC",
-	startup:	i8259a_startup_irq,
-	shutdown:	i8259a_disable_irq,
-	enable:		i8259a_enable_irq,
-	disable:	i8259a_disable_irq,
-	ack:		i8259a_mask_and_ack_irq,
-	end:		i8259a_end_irq,
+	.typename	= "XT-PIC",
+	.startup	= i8259a_startup_irq,
+	.shutdown	= i8259a_disable_irq,
+	.enable		= i8259a_enable_irq,
+	.disable	= i8259a_disable_irq,
+	.ack		= i8259a_mask_and_ack_irq,
+	.end		= i8259a_end_irq,
 };
 
 void __init
 init_i8259a_irqs(void)
 {
 	static struct irqaction cascade = {
-		handler:	no_action,
-		name:		"cascade",
+		.handler	= no_action,
+		.name		= "cascade",
 	};
 
 	long i;
diff -Nru a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c
--- a/arch/alpha/kernel/irq_pyxis.c	Tue Oct 15 20:29:23 2002
+++ b/arch/alpha/kernel/irq_pyxis.c	Tue Oct 15 20:29:23 2002
@@ -71,13 +71,13 @@
 }
 
 static struct hw_interrupt_type pyxis_irq_type = {
-	typename:	"PYXIS",
-	startup:	pyxis_startup_irq,
-	shutdown:	pyxis_disable_irq,
-	enable:		pyxis_enable_irq,
-	disable:	pyxis_disable_irq,
-	ack:		pyxis_mask_and_ack_irq,
-	end:		pyxis_end_irq,
+	.typename	= "PYXIS",
+	.startup	= pyxis_startup_irq,
+	.shutdown	= pyxis_disable_irq,
+	.enable		= pyxis_enable_irq,
+	.disable	= pyxis_disable_irq,
+	.ack		= pyxis_mask_and_ack_irq,
+	.end		= pyxis_end_irq,
 };
 
 void 
diff -Nru a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c
--- a/arch/alpha/kernel/irq_srm.c	Tue Oct 15 20:29:20 2002
+++ b/arch/alpha/kernel/irq_srm.c	Tue Oct 15 20:29:20 2002
@@ -49,13 +49,13 @@
 
 /* Handle interrupts from the SRM, assuming no additional weirdness.  */
 static struct hw_interrupt_type srm_irq_type = {
-	typename:	"SRM",
-	startup:	srm_startup_irq,
-	shutdown:	srm_disable_irq,
-	enable:		srm_enable_irq,
-	disable:	srm_disable_irq,
-	ack:		srm_disable_irq,
-	end:		srm_end_irq,
+	.typename	= "SRM",
+	.startup	= srm_startup_irq,
+	.shutdown	= srm_disable_irq,
+	.enable		= srm_enable_irq,
+	.disable	= srm_disable_irq,
+	.ack		= srm_disable_irq,
+	.end		= srm_end_irq,
 };
 
 void __init
diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
--- a/arch/alpha/kernel/pci.c	Tue Oct 15 20:29:12 2002
+++ b/arch/alpha/kernel/pci.c	Tue Oct 15 20:29:12 2002
@@ -102,7 +102,7 @@
 #define DMAPSZ (max_low_pfn << PAGE_SHIFT) /* memory size, not window size */
 		if ((__direct_map_base + DMAPSZ - 1) >= 0xfff00000UL) {
 			__direct_map_size = 0xfff00000UL - __direct_map_base;
-			printk("%s: adjusting direct map size to 0x%x\n",
+			printk("%s: adjusting direct map size to 0x%lx\n",
 			       __FUNCTION__, __direct_map_size);
 		} else {
 			struct pci_controller *hose = dev->sysdata;
diff -Nru a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
--- a/arch/alpha/kernel/setup.c	Tue Oct 15 20:29:12 2002
+++ b/arch/alpha/kernel/setup.c	Tue Oct 15 20:29:12 2002
@@ -112,12 +112,12 @@
  */
 
 struct screen_info screen_info = {
-	orig_x: 0,
-	orig_y: 25,
-	orig_video_cols: 80,
-	orig_video_lines: 25,
-	orig_video_isVGA: 1,
-	orig_video_points: 16
+	.orig_x = 0,
+	.orig_y = 25,
+	.orig_video_cols = 80,
+	.orig_video_lines = 25,
+	.orig_video_isVGA = 1,
+	.orig_video_points = 16
 };
 
 /*
@@ -452,12 +452,12 @@
 }
 
 static struct console srmcons = {
-	name:		"srm0",
-	write:		srm_console_write,
-	device:		srm_console_device,
-	setup:		srm_console_setup,
-	flags:		CON_PRINTBUFFER | CON_ENABLED, /* fake it out */
-	index:		-1,
+	.name		= "srm0",
+	.write		= srm_console_write,
+	.device		= srm_console_device,
+	.setup		= srm_console_setup,
+	.flags		= CON_PRINTBUFFER | CON_ENABLED, /* fake it out */
+	.index		= -1,
 };
 
 #else
@@ -1150,10 +1150,10 @@
 }
 
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= show_cpuinfo,
 };
 
 
diff -Nru a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c
--- a/arch/alpha/kernel/sys_alcor.c	Tue Oct 15 20:29:16 2002
+++ b/arch/alpha/kernel/sys_alcor.c	Tue Oct 15 20:29:16 2002
@@ -91,13 +91,13 @@
 }
 
 static struct hw_interrupt_type alcor_irq_type = {
-	typename:	"ALCOR",
-	startup:	alcor_startup_irq,
-	shutdown:	alcor_disable_irq,
-	enable:		alcor_enable_irq,
-	disable:	alcor_disable_irq,
-	ack:		alcor_mask_and_ack_irq,
-	end:		alcor_end_irq,
+	.typename	= "ALCOR",
+	.startup	= alcor_startup_irq,
+	.shutdown	= alcor_disable_irq,
+	.enable		= alcor_enable_irq,
+	.disable	= alcor_disable_irq,
+	.ack		= alcor_mask_and_ack_irq,
+	.end		= alcor_end_irq,
 };
 
 static void
@@ -245,29 +245,29 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_ALCOR)
 struct alpha_machine_vector alcor_mv __initmv = {
-	vector_name:		"Alcor",
+	.vector_name		= "Alcor",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_CIA_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_ALCOR_MAX_DMA_ADDRESS,
-	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	CIA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		48,
-	device_interrupt:	alcor_device_interrupt,
-
-	init_arch:		cia_init_arch,
-	init_irq:		alcor_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		cia_init_pci,
-	kill_arch:		alcor_kill_arch,
-	pci_map_irq:		alcor_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_ALCOR_MAX_DMA_ADDRESS,
+	.min_io_address		= EISA_DEFAULT_IO_BASE,
+	.min_mem_address	= CIA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 48,
+	.device_interrupt	= alcor_device_interrupt,
+
+	.init_arch		= cia_init_arch,
+	.init_irq		= alcor_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= cia_init_pci,
+	.kill_arch		= alcor_kill_arch,
+	.pci_map_irq		= alcor_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { cia: {
-	    gru_int_req_bits:	ALCOR_GRU_INT_REQ_BITS
+	.sys = { .cia = {
+	    .gru_int_req_bits	= ALCOR_GRU_INT_REQ_BITS
 	}}
 };
 ALIAS_MV(alcor)
@@ -275,29 +275,29 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_XLT)
 struct alpha_machine_vector xlt_mv __initmv = {
-	vector_name:		"XLT",
+	.vector_name		= "XLT",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_CIA_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	CIA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		48,
-	device_interrupt:	alcor_device_interrupt,
-
-	init_arch:		cia_init_arch,
-	init_irq:		alcor_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		cia_init_pci,
-	kill_arch:		alcor_kill_arch,
-	pci_map_irq:		alcor_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= EISA_DEFAULT_IO_BASE,
+	.min_mem_address	= CIA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 48,
+	.device_interrupt	= alcor_device_interrupt,
+
+	.init_arch		= cia_init_arch,
+	.init_irq		= alcor_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= cia_init_pci,
+	.kill_arch		= alcor_kill_arch,
+	.pci_map_irq		= alcor_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { cia: {
-	    gru_int_req_bits:	XLT_GRU_INT_REQ_BITS
+	.sys = { .cia = {
+	    .gru_int_req_bits	= XLT_GRU_INT_REQ_BITS
 	}}
 };
 ALIAS_MV(xlt)
diff -Nru a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
--- a/arch/alpha/kernel/sys_cabriolet.c	Tue Oct 15 20:29:15 2002
+++ b/arch/alpha/kernel/sys_cabriolet.c	Tue Oct 15 20:29:15 2002
@@ -73,13 +73,13 @@
 }
 
 static struct hw_interrupt_type cabriolet_irq_type = {
-	typename:	"CABRIOLET",
-	startup:	cabriolet_startup_irq,
-	shutdown:	cabriolet_disable_irq,
-	enable:		cabriolet_enable_irq,
-	disable:	cabriolet_disable_irq,
-	ack:		cabriolet_disable_irq,
-	end:		cabriolet_end_irq,
+	.typename	= "CABRIOLET",
+	.startup	= cabriolet_startup_irq,
+	.shutdown	= cabriolet_disable_irq,
+	.enable		= cabriolet_enable_irq,
+	.disable	= cabriolet_disable_irq,
+	.ack		= cabriolet_disable_irq,
+	.end		= cabriolet_end_irq,
 };
 
 static void 
@@ -321,26 +321,26 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET)
 struct alpha_machine_vector cabriolet_mv __initmv = {
-	vector_name:		"Cabriolet",
+	.vector_name		= "Cabriolet",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_APECS_IO,
 	DO_APECS_BUS,
-	machine_check:		apecs_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		35,
-	device_interrupt:	cabriolet_device_interrupt,
-
-	init_arch:		apecs_init_arch,
-	init_irq:		cabriolet_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		cabriolet_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		cabriolet_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= apecs_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 35,
+	.device_interrupt	= cabriolet_device_interrupt,
+
+	.init_arch		= apecs_init_arch,
+	.init_irq		= cabriolet_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= cabriolet_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= cabriolet_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 #ifndef CONFIG_ALPHA_EB64P
 ALIAS_MV(cabriolet)
@@ -349,101 +349,101 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164)
 struct alpha_machine_vector eb164_mv __initmv = {
-	vector_name:		"EB164",
+	.vector_name		= "EB164",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_CIA_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	CIA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		35,
-	device_interrupt:	cabriolet_device_interrupt,
-
-	init_arch:		cia_init_arch,
-	init_irq:		cabriolet_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		cia_cab_init_pci,
-	pci_map_irq:		cabriolet_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= CIA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 35,
+	.device_interrupt	= cabriolet_device_interrupt,
+
+	.init_arch		= cia_init_arch,
+	.init_irq		= cabriolet_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= cia_cab_init_pci,
+	.pci_map_irq		= cabriolet_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(eb164)
 #endif
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P)
 struct alpha_machine_vector eb66p_mv __initmv = {
-	vector_name:		"EB66+",
+	.vector_name		= "EB66+",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_LCA_IO,
 	DO_LCA_BUS,
-	machine_check:		lca_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		35,
-	device_interrupt:	cabriolet_device_interrupt,
-
-	init_arch:		lca_init_arch,
-	init_irq:		cabriolet_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		cabriolet_init_pci,
-	pci_map_irq:		eb66p_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= lca_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 35,
+	.device_interrupt	= cabriolet_device_interrupt,
+
+	.init_arch		= lca_init_arch,
+	.init_irq		= cabriolet_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= cabriolet_init_pci,
+	.pci_map_irq		= eb66p_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(eb66p)
 #endif
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164)
 struct alpha_machine_vector lx164_mv __initmv = {
-	vector_name:		"LX164",
+	.vector_name		= "LX164",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_PYXIS_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		PYXIS_DAC_OFFSET,
-
-	nr_irqs:		35,
-	device_interrupt:	cabriolet_device_interrupt,
-
-	init_arch:		pyxis_init_arch,
-	init_irq:		cabriolet_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		alphapc164_init_pci,
-	pci_map_irq:		alphapc164_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= PYXIS_DAC_OFFSET,
+
+	.nr_irqs		= 35,
+	.device_interrupt	= cabriolet_device_interrupt,
+
+	.init_arch		= pyxis_init_arch,
+	.init_irq		= cabriolet_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= alphapc164_init_pci,
+	.pci_map_irq		= alphapc164_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(lx164)
 #endif
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
 struct alpha_machine_vector pc164_mv __initmv = {
-	vector_name:		"PC164",
+	.vector_name		= "PC164",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_CIA_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	CIA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		35,
-	device_interrupt:	pc164_device_interrupt,
-
-	init_arch:		cia_init_arch,
-	init_irq:		pc164_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		alphapc164_init_pci,
-	pci_map_irq:		alphapc164_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= CIA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 35,
+	.device_interrupt	= pc164_device_interrupt,
+
+	.init_arch		= cia_init_arch,
+	.init_irq		= pc164_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= alphapc164_init_pci,
+	.pci_map_irq		= alphapc164_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(pc164)
 #endif
diff -Nru a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
--- a/arch/alpha/kernel/sys_dp264.c	Tue Oct 15 20:29:12 2002
+++ b/arch/alpha/kernel/sys_dp264.c	Tue Oct 15 20:29:12 2002
@@ -197,25 +197,25 @@
 }
 
 static struct hw_interrupt_type dp264_irq_type = {
-	typename:	"DP264",
-	startup:	dp264_startup_irq,
-	shutdown:	dp264_disable_irq,
-	enable:		dp264_enable_irq,
-	disable:	dp264_disable_irq,
-	ack:		dp264_disable_irq,
-	end:		dp264_end_irq,
-	set_affinity:	dp264_set_affinity,
+	.typename	= "DP264",
+	.startup	= dp264_startup_irq,
+	.shutdown	= dp264_disable_irq,
+	.enable		= dp264_enable_irq,
+	.disable	= dp264_disable_irq,
+	.ack		= dp264_disable_irq,
+	.end		= dp264_end_irq,
+	.set_affinity	= dp264_set_affinity,
 };
 
 static struct hw_interrupt_type clipper_irq_type = {
-	typename:	"CLIPPER",
-	startup:	clipper_startup_irq,
-	shutdown:	clipper_disable_irq,
-	enable:		clipper_enable_irq,
-	disable:	clipper_disable_irq,
-	ack:		clipper_disable_irq,
-	end:		clipper_end_irq,
-	set_affinity:	clipper_set_affinity,
+	.typename	= "CLIPPER",
+	.startup	= clipper_startup_irq,
+	.shutdown	= clipper_disable_irq,
+	.enable		= clipper_enable_irq,
+	.disable	= clipper_disable_irq,
+	.ack		= clipper_disable_irq,
+	.end		= clipper_end_irq,
+	.set_affinity	= clipper_set_affinity,
 };
 
 static void
@@ -566,100 +566,100 @@
  */
 
 struct alpha_machine_vector dp264_mv __initmv = {
-	vector_name:		"DP264",
+	.vector_name		= "DP264",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_TSUNAMI_IO,
 	DO_TSUNAMI_BUS,
-	machine_check:		tsunami_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
-
-	nr_irqs:		64,
-	device_interrupt:	dp264_device_interrupt,
-
-	init_arch:		tsunami_init_arch,
-	init_irq:		dp264_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		dp264_init_pci,
-	kill_arch:		tsunami_kill_arch,
-	pci_map_irq:		dp264_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= tsunami_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= TSUNAMI_DAC_OFFSET,
+
+	.nr_irqs		= 64,
+	.device_interrupt	= dp264_device_interrupt,
+
+	.init_arch		= tsunami_init_arch,
+	.init_irq		= dp264_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= dp264_init_pci,
+	.kill_arch		= tsunami_kill_arch,
+	.pci_map_irq		= dp264_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(dp264)
 
 struct alpha_machine_vector monet_mv __initmv = {
-	vector_name:		"Monet",
+	.vector_name		= "Monet",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_TSUNAMI_IO,
 	DO_TSUNAMI_BUS,
-	machine_check:		tsunami_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
-
-	nr_irqs:		64,
-	device_interrupt:	dp264_device_interrupt,
-
-	init_arch:		tsunami_init_arch,
-	init_irq:		dp264_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		monet_init_pci,
-	kill_arch:		tsunami_kill_arch,
-	pci_map_irq:		monet_map_irq,
-	pci_swizzle:		monet_swizzle,
+	.machine_check		= tsunami_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= TSUNAMI_DAC_OFFSET,
+
+	.nr_irqs		= 64,
+	.device_interrupt	= dp264_device_interrupt,
+
+	.init_arch		= tsunami_init_arch,
+	.init_irq		= dp264_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= monet_init_pci,
+	.kill_arch		= tsunami_kill_arch,
+	.pci_map_irq		= monet_map_irq,
+	.pci_swizzle		= monet_swizzle,
 };
 
 struct alpha_machine_vector webbrick_mv __initmv = {
-	vector_name:		"Webbrick",
+	.vector_name		= "Webbrick",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_TSUNAMI_IO,
 	DO_TSUNAMI_BUS,
-	machine_check:		tsunami_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
-
-	nr_irqs:		64,
-	device_interrupt:	dp264_device_interrupt,
-
-	init_arch:		webbrick_init_arch,
-	init_irq:		dp264_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		tsunami_kill_arch,
-	pci_map_irq:		webbrick_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= tsunami_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= TSUNAMI_DAC_OFFSET,
+
+	.nr_irqs		= 64,
+	.device_interrupt	= dp264_device_interrupt,
+
+	.init_arch		= webbrick_init_arch,
+	.init_irq		= dp264_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= tsunami_kill_arch,
+	.pci_map_irq		= webbrick_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 
 struct alpha_machine_vector clipper_mv __initmv = {
-	vector_name:		"Clipper",
+	.vector_name		= "Clipper",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_TSUNAMI_IO,
 	DO_TSUNAMI_BUS,
-	machine_check:		tsunami_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
-
-	nr_irqs:		64,
-	device_interrupt:	dp264_device_interrupt,
-
-	init_arch:		tsunami_init_arch,
-	init_irq:		clipper_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		tsunami_kill_arch,
-	pci_map_irq:		clipper_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= tsunami_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= TSUNAMI_DAC_OFFSET,
+
+	.nr_irqs		= 64,
+	.device_interrupt	= dp264_device_interrupt,
+
+	.init_arch		= tsunami_init_arch,
+	.init_irq		= clipper_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= tsunami_kill_arch,
+	.pci_map_irq		= clipper_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 
 /* Sharks strongly resemble Clipper, at least as far
@@ -668,27 +668,27 @@
  */
 
 struct alpha_machine_vector shark_mv __initmv = {
-	vector_name:		"Shark",
+	.vector_name		= "Shark",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_TSUNAMI_IO,
 	DO_TSUNAMI_BUS,
-	machine_check:		tsunami_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
-
-	nr_irqs:		64,
-	device_interrupt:	dp264_device_interrupt,
-
-	init_arch:		tsunami_init_arch,
-	init_irq:		clipper_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		tsunami_kill_arch,
-	pci_map_irq:		clipper_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= tsunami_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= TSUNAMI_DAC_OFFSET,
+
+	.nr_irqs		= 64,
+	.device_interrupt	= dp264_device_interrupt,
+
+	.init_arch		= tsunami_init_arch,
+	.init_irq		= clipper_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= tsunami_kill_arch,
+	.pci_map_irq		= clipper_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 
 /* No alpha_mv alias for webbrick/monet/clipper, since we compile them
diff -Nru a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c
--- a/arch/alpha/kernel/sys_eb64p.c	Tue Oct 15 20:29:19 2002
+++ b/arch/alpha/kernel/sys_eb64p.c	Tue Oct 15 20:29:19 2002
@@ -71,13 +71,13 @@
 }
 
 static struct hw_interrupt_type eb64p_irq_type = {
-	typename:	"EB64P",
-	startup:	eb64p_startup_irq,
-	shutdown:	eb64p_disable_irq,
-	enable:		eb64p_enable_irq,
-	disable:	eb64p_disable_irq,
-	ack:		eb64p_disable_irq,
-	end:		eb64p_end_irq,
+	.typename	= "EB64P",
+	.startup	= eb64p_startup_irq,
+	.shutdown	= eb64p_disable_irq,
+	.enable		= eb64p_enable_irq,
+	.disable	= eb64p_disable_irq,
+	.ack		= eb64p_disable_irq,
+	.end		= eb64p_end_irq,
 };
 
 static void 
@@ -208,51 +208,51 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB64P)
 struct alpha_machine_vector eb64p_mv __initmv = {
-	vector_name:		"EB64+",
+	.vector_name		= "EB64+",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_APECS_IO,
 	DO_APECS_BUS,
-	machine_check:		apecs_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		32,
-	device_interrupt:	eb64p_device_interrupt,
-
-	init_arch:		apecs_init_arch,
-	init_irq:		eb64p_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		eb64p_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= apecs_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 32,
+	.device_interrupt	= eb64p_device_interrupt,
+
+	.init_arch		= apecs_init_arch,
+	.init_irq		= eb64p_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= eb64p_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(eb64p)
 #endif
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66)
 struct alpha_machine_vector eb66_mv __initmv = {
-	vector_name:		"EB66",
+	.vector_name		= "EB66",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_LCA_IO,
 	DO_LCA_BUS,
-	machine_check:		lca_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		32,
-	device_interrupt:	eb64p_device_interrupt,
-
-	init_arch:		lca_init_arch,
-	init_irq:		eb64p_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	pci_map_irq:		eb64p_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= lca_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 32,
+	.device_interrupt	= eb64p_device_interrupt,
+
+	.init_arch		= lca_init_arch,
+	.init_irq		= eb64p_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.pci_map_irq		= eb64p_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(eb66)
 #endif
diff -Nru a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c
--- a/arch/alpha/kernel/sys_eiger.c	Tue Oct 15 20:29:12 2002
+++ b/arch/alpha/kernel/sys_eiger.c	Tue Oct 15 20:29:12 2002
@@ -81,13 +81,13 @@
 }
 
 static struct hw_interrupt_type eiger_irq_type = {
-	typename:	"EIGER",
-	startup:	eiger_startup_irq,
-	shutdown:	eiger_disable_irq,
-	enable:		eiger_enable_irq,
-	disable:	eiger_disable_irq,
-	ack:		eiger_disable_irq,
-	end:		eiger_end_irq,
+	.typename	= "EIGER",
+	.startup	= eiger_startup_irq,
+	.shutdown	= eiger_disable_irq,
+	.enable		= eiger_enable_irq,
+	.disable	= eiger_disable_irq,
+	.ack		= eiger_disable_irq,
+	.end		= eiger_end_irq,
 };
 
 static void
@@ -225,26 +225,26 @@
  */
 
 struct alpha_machine_vector eiger_mv __initmv = {
-	vector_name:		"Eiger",
+	.vector_name		= "Eiger",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_TSUNAMI_IO,
 	DO_TSUNAMI_BUS,
-	machine_check:		tsunami_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		TSUNAMI_DAC_OFFSET,
-
-	nr_irqs:		128,
-	device_interrupt:	eiger_device_interrupt,
-
-	init_arch:		tsunami_init_arch,
-	init_irq:		eiger_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		tsunami_kill_arch,
-	pci_map_irq:		eiger_map_irq,
-	pci_swizzle:		eiger_swizzle,
+	.machine_check		= tsunami_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= TSUNAMI_DAC_OFFSET,
+
+	.nr_irqs		= 128,
+	.device_interrupt	= eiger_device_interrupt,
+
+	.init_arch		= tsunami_init_arch,
+	.init_irq		= eiger_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= tsunami_kill_arch,
+	.pci_map_irq		= eiger_map_irq,
+	.pci_swizzle		= eiger_swizzle,
 };
 ALIAS_MV(eiger)
diff -Nru a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
--- a/arch/alpha/kernel/sys_jensen.c	Tue Oct 15 20:29:17 2002
+++ b/arch/alpha/kernel/sys_jensen.c	Tue Oct 15 20:29:17 2002
@@ -119,13 +119,13 @@
 }
 
 static struct hw_interrupt_type jensen_local_irq_type = {
-	typename:	"LOCAL",
-	startup:	jensen_local_startup,
-	shutdown:	jensen_local_shutdown,
-	enable:		jensen_local_enable,
-	disable:	jensen_local_disable,
-	ack:		jensen_local_ack,
-	end:		jensen_local_end,
+	.typename	= "LOCAL",
+	.startup	= jensen_local_startup,
+	.shutdown	= jensen_local_shutdown,
+	.enable		= jensen_local_enable,
+	.disable	= jensen_local_disable,
+	.ack		= jensen_local_ack,
+	.end		= jensen_local_end,
 };
 
 static void 
@@ -252,21 +252,21 @@
  */
 
 struct alpha_machine_vector jensen_mv __initmv = {
-	vector_name:		"Jensen",
+	.vector_name		= "Jensen",
 	DO_EV4_MMU,
 	IO_LITE(JENSEN,jensen),
 	BUS(jensen),
-	machine_check:		jensen_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	rtc_port:		0x170,
-
-	nr_irqs:		16,
-	device_interrupt:	jensen_device_interrupt,
-
-	init_arch:		jensen_init_arch,
-	init_irq:		jensen_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		NULL,
-	kill_arch:		NULL,
+	.machine_check		= jensen_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.rtc_port		= 0x170,
+
+	.nr_irqs		= 16,
+	.device_interrupt	= jensen_device_interrupt,
+
+	.init_arch		= jensen_init_arch,
+	.init_irq		= jensen_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= NULL,
+	.kill_arch		= NULL,
 };
 ALIAS_MV(jensen)
diff -Nru a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c
--- a/arch/alpha/kernel/sys_miata.c	Tue Oct 15 20:29:17 2002
+++ b/arch/alpha/kernel/sys_miata.c	Tue Oct 15 20:29:17 2002
@@ -261,26 +261,26 @@
  */
 
 struct alpha_machine_vector miata_mv __initmv = {
-	vector_name:		"Miata",
+	.vector_name		= "Miata",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_PYXIS_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		PYXIS_DAC_OFFSET,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= PYXIS_DAC_OFFSET,
 
-	nr_irqs:		48,
-	device_interrupt:	pyxis_device_interrupt,
+	.nr_irqs		= 48,
+	.device_interrupt	= pyxis_device_interrupt,
 
-	init_arch:		pyxis_init_arch,
-	init_irq:		miata_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		miata_init_pci,
-	kill_arch:		miata_kill_arch,
-	pci_map_irq:		miata_map_irq,
-	pci_swizzle:		miata_swizzle,
+	.init_arch		= pyxis_init_arch,
+	.init_irq		= miata_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= miata_init_pci,
+	.kill_arch		= miata_kill_arch,
+	.pci_map_irq		= miata_map_irq,
+	.pci_swizzle		= miata_swizzle,
 };
 ALIAS_MV(miata)
diff -Nru a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c
--- a/arch/alpha/kernel/sys_mikasa.c	Tue Oct 15 20:29:19 2002
+++ b/arch/alpha/kernel/sys_mikasa.c	Tue Oct 15 20:29:20 2002
@@ -70,13 +70,13 @@
 }
 
 static struct hw_interrupt_type mikasa_irq_type = {
-	typename:	"MIKASA",
-	startup:	mikasa_startup_irq,
-	shutdown:	mikasa_disable_irq,
-	enable:		mikasa_enable_irq,
-	disable:	mikasa_disable_irq,
-	ack:		mikasa_disable_irq,
-	end:		mikasa_end_irq,
+	.typename	= "MIKASA",
+	.startup	= mikasa_startup_irq,
+	.shutdown	= mikasa_disable_irq,
+	.enable		= mikasa_enable_irq,
+	.disable	= mikasa_disable_irq,
+	.ack		= mikasa_disable_irq,
+	.end		= mikasa_end_irq,
 };
 
 static void 
@@ -217,51 +217,51 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
 struct alpha_machine_vector mikasa_mv __initmv = {
-	vector_name:		"Mikasa",
+	.vector_name		= "Mikasa",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_APECS_IO,
 	DO_APECS_BUS,
-	machine_check:		mikasa_apecs_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		32,
-	device_interrupt:	mikasa_device_interrupt,
-
-	init_arch:		apecs_init_arch,
-	init_irq:		mikasa_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		mikasa_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= mikasa_apecs_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 32,
+	.device_interrupt	= mikasa_device_interrupt,
+
+	.init_arch		= apecs_init_arch,
+	.init_irq		= mikasa_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= mikasa_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(mikasa)
 #endif
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO)
 struct alpha_machine_vector mikasa_primo_mv __initmv = {
-	vector_name:		"Mikasa-Primo",
+	.vector_name		= "Mikasa-Primo",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_CIA_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	CIA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		32,
-	device_interrupt:	mikasa_device_interrupt,
-
-	init_arch:		cia_init_arch,
-	init_irq:		mikasa_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		cia_init_pci,
-	pci_map_irq:		mikasa_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= CIA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 32,
+	.device_interrupt	= mikasa_device_interrupt,
+
+	.init_arch		= cia_init_arch,
+	.init_irq		= mikasa_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= cia_init_pci,
+	.pci_map_irq		= mikasa_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(mikasa_primo)
 #endif
diff -Nru a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
--- a/arch/alpha/kernel/sys_nautilus.c	Tue Oct 15 20:29:16 2002
+++ b/arch/alpha/kernel/sys_nautilus.c	Tue Oct 15 20:29:16 2002
@@ -510,25 +510,25 @@
  */
 
 struct alpha_machine_vector nautilus_mv __initmv = {
-	vector_name:		"Nautilus",
+	.vector_name		= "Nautilus",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_IRONGATE_IO,
 	DO_IRONGATE_BUS,
-	machine_check:		nautilus_machine_check,
-	max_dma_address:	ALPHA_NAUTILUS_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	IRONGATE_DEFAULT_MEM_BASE,
+	.machine_check		= nautilus_machine_check,
+	.max_dma_address	= ALPHA_NAUTILUS_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= IRONGATE_DEFAULT_MEM_BASE,
 
-	nr_irqs:		16,
-	device_interrupt:	isa_device_interrupt,
+	.nr_irqs		= 16,
+	.device_interrupt	= isa_device_interrupt,
 
-	init_arch:		irongate_init_arch,
-	init_irq:		nautilus_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		nautilus_kill_arch,
-	pci_map_irq:		nautilus_map_irq,
-	pci_swizzle:		common_swizzle,
+	.init_arch		= irongate_init_arch,
+	.init_irq		= nautilus_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= nautilus_kill_arch,
+	.pci_map_irq		= nautilus_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(nautilus)
diff -Nru a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c
--- a/arch/alpha/kernel/sys_noritake.c	Tue Oct 15 20:29:13 2002
+++ b/arch/alpha/kernel/sys_noritake.c	Tue Oct 15 20:29:13 2002
@@ -68,13 +68,13 @@
 }
 
 static struct hw_interrupt_type noritake_irq_type = {
-	typename:	"NORITAKE",
-	startup:	noritake_startup_irq,
-	shutdown:	noritake_disable_irq,
-	enable:		noritake_enable_irq,
-	disable:	noritake_disable_irq,
-	ack:		noritake_disable_irq,
-	end:		noritake_enable_irq,
+	.typename	= "NORITAKE",
+	.startup	= noritake_startup_irq,
+	.shutdown	= noritake_disable_irq,
+	.enable		= noritake_enable_irq,
+	.disable	= noritake_disable_irq,
+	.ack		= noritake_disable_irq,
+	.end		= noritake_enable_irq,
 };
 
 static void 
@@ -299,51 +299,51 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
 struct alpha_machine_vector noritake_mv __initmv = {
-	vector_name:		"Noritake",
+	.vector_name		= "Noritake",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_APECS_IO,
 	DO_APECS_BUS,
-	machine_check:		noritake_apecs_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		48,
-	device_interrupt:	noritake_device_interrupt,
-
-	init_arch:		apecs_init_arch,
-	init_irq:		noritake_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		noritake_map_irq,
-	pci_swizzle:		noritake_swizzle,
+	.machine_check		= noritake_apecs_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= EISA_DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 48,
+	.device_interrupt	= noritake_device_interrupt,
+
+	.init_arch		= apecs_init_arch,
+	.init_irq		= noritake_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= noritake_map_irq,
+	.pci_swizzle		= noritake_swizzle,
 };
 ALIAS_MV(noritake)
 #endif
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO)
 struct alpha_machine_vector noritake_primo_mv __initmv = {
-	vector_name:		"Noritake-Primo",
+	.vector_name		= "Noritake-Primo",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_CIA_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	CIA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		48,
-	device_interrupt:	noritake_device_interrupt,
-
-	init_arch:		cia_init_arch,
-	init_irq:		noritake_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		cia_init_pci,
-	pci_map_irq:		noritake_map_irq,
-	pci_swizzle:		noritake_swizzle,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= EISA_DEFAULT_IO_BASE,
+	.min_mem_address	= CIA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 48,
+	.device_interrupt	= noritake_device_interrupt,
+
+	.init_arch		= cia_init_arch,
+	.init_irq		= noritake_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= cia_init_pci,
+	.pci_map_irq		= noritake_map_irq,
+	.pci_swizzle		= noritake_swizzle,
 };
 ALIAS_MV(noritake_primo)
 #endif
diff -Nru a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c
--- a/arch/alpha/kernel/sys_rawhide.c	Tue Oct 15 20:29:21 2002
+++ b/arch/alpha/kernel/sys_rawhide.c	Tue Oct 15 20:29:21 2002
@@ -124,13 +124,13 @@
 }
 
 static struct hw_interrupt_type rawhide_irq_type = {
-	typename:	"RAWHIDE",
-	startup:	rawhide_startup_irq,
-	shutdown:	rawhide_disable_irq,
-	enable:		rawhide_enable_irq,
-	disable:	rawhide_disable_irq,
-	ack:		rawhide_mask_and_ack_irq,
-	end:		rawhide_end_irq,
+	.typename	= "RAWHIDE",
+	.startup	= rawhide_startup_irq,
+	.shutdown	= rawhide_disable_irq,
+	.enable		= rawhide_enable_irq,
+	.disable	= rawhide_disable_irq,
+	.ack		= rawhide_mask_and_ack_irq,
+	.end		= rawhide_end_irq,
 };
 
 static void 
@@ -246,26 +246,26 @@
  */
 
 struct alpha_machine_vector rawhide_mv __initmv = {
-	vector_name:		"Rawhide",
+	.vector_name		= "Rawhide",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_MCPCIA_IO,
 	DO_MCPCIA_BUS,
-	machine_check:		mcpcia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	MCPCIA_DEFAULT_MEM_BASE,
-	pci_dac_offset:		MCPCIA_DAC_OFFSET,
-
-	nr_irqs:		128,
-	device_interrupt:	rawhide_srm_device_interrupt,
-
-	init_arch:		mcpcia_init_arch,
-	init_irq:		rawhide_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		rawhide_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= mcpcia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= MCPCIA_DEFAULT_MEM_BASE,
+	.pci_dac_offset		= MCPCIA_DAC_OFFSET,
+
+	.nr_irqs		= 128,
+	.device_interrupt	= rawhide_srm_device_interrupt,
+
+	.init_arch		= mcpcia_init_arch,
+	.init_irq		= rawhide_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= rawhide_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(rawhide)
diff -Nru a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c
--- a/arch/alpha/kernel/sys_ruffian.c	Tue Oct 15 20:29:17 2002
+++ b/arch/alpha/kernel/sys_ruffian.c	Tue Oct 15 20:29:17 2002
@@ -212,26 +212,26 @@
  */
 
 struct alpha_machine_vector ruffian_mv __initmv = {
-	vector_name:		"Ruffian",
+	.vector_name		= "Ruffian",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_PYXIS_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_RUFFIAN_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		PYXIS_DAC_OFFSET,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_RUFFIAN_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= PYXIS_DAC_OFFSET,
 
-	nr_irqs:		48,
-	device_interrupt:	pyxis_device_interrupt,
+	.nr_irqs		= 48,
+	.device_interrupt	= pyxis_device_interrupt,
 
-	init_arch:		pyxis_init_arch,
-	init_irq:		ruffian_init_irq,
-	init_rtc:		ruffian_init_rtc,
-	init_pci:		cia_init_pci,
-	kill_arch:		ruffian_kill_arch,
-	pci_map_irq:		ruffian_map_irq,
-	pci_swizzle:		ruffian_swizzle,
+	.init_arch		= pyxis_init_arch,
+	.init_irq		= ruffian_init_irq,
+	.init_rtc		= ruffian_init_rtc,
+	.init_pci		= cia_init_pci,
+	.kill_arch		= ruffian_kill_arch,
+	.pci_map_irq		= ruffian_map_irq,
+	.pci_swizzle		= ruffian_swizzle,
 };
 ALIAS_MV(ruffian)
diff -Nru a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c
--- a/arch/alpha/kernel/sys_rx164.c	Tue Oct 15 20:29:11 2002
+++ b/arch/alpha/kernel/sys_rx164.c	Tue Oct 15 20:29:11 2002
@@ -73,13 +73,13 @@
 }
 
 static struct hw_interrupt_type rx164_irq_type = {
-	typename:	"RX164",
-	startup:	rx164_startup_irq,
-	shutdown:	rx164_disable_irq,
-	enable:		rx164_enable_irq,
-	disable:	rx164_disable_irq,
-	ack:		rx164_disable_irq,
-	end:		rx164_end_irq,
+	.typename	= "RX164",
+	.startup	= rx164_startup_irq,
+	.shutdown	= rx164_disable_irq,
+	.enable		= rx164_enable_irq,
+	.disable	= rx164_disable_irq,
+	.ack		= rx164_disable_irq,
+	.end		= rx164_end_irq,
 };
 
 static void 
@@ -197,25 +197,25 @@
  */
 
 struct alpha_machine_vector rx164_mv __initmv = {
-	vector_name:		"RX164",
+	.vector_name		= "RX164",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_POLARIS_IO,
 	DO_POLARIS_BUS,
-	machine_check:		polaris_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-
-	nr_irqs:		40,
-	device_interrupt:	rx164_device_interrupt,
-
-	init_arch:		polaris_init_arch,
-	init_irq:		rx164_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		rx164_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= polaris_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 40,
+	.device_interrupt	= rx164_device_interrupt,
+
+	.init_arch		= polaris_init_arch,
+	.init_irq		= rx164_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= rx164_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(rx164)
diff -Nru a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c
--- a/arch/alpha/kernel/sys_sable.c	Tue Oct 15 20:29:12 2002
+++ b/arch/alpha/kernel/sys_sable.c	Tue Oct 15 20:29:12 2002
@@ -185,13 +185,13 @@
 }
 
 static struct hw_interrupt_type sable_irq_type = {
-	typename:	"SABLE",
-	startup:	sable_startup_irq,
-	shutdown:	sable_disable_irq,
-	enable:		sable_enable_irq,
-	disable:	sable_disable_irq,
-	ack:		sable_mask_and_ack_irq,
-	end:		sable_end_irq,
+	.typename	= "SABLE",
+	.startup	= sable_startup_irq,
+	.shutdown	= sable_disable_irq,
+	.enable		= sable_enable_irq,
+	.disable	= sable_disable_irq,
+	.ack		= sable_mask_and_ack_irq,
+	.end		= sable_end_irq,
 };
 
 static void 
@@ -284,29 +284,29 @@
 #undef GAMMA_BIAS
 #define GAMMA_BIAS 0
 struct alpha_machine_vector sable_mv __initmv = {
-	vector_name:		"Sable",
+	.vector_name		= "Sable",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_T2_IO,
 	DO_T2_BUS,
-	machine_check:		t2_machine_check,
-	max_dma_address:	ALPHA_SABLE_MAX_DMA_ADDRESS,
-	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	T2_DEFAULT_MEM_BASE,
-
-	nr_irqs:		40,
-	device_interrupt:	sable_srm_device_interrupt,
-
-	init_arch:		t2_init_arch,
-	init_irq:		sable_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		sable_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= t2_machine_check,
+	.max_dma_address	= ALPHA_SABLE_MAX_DMA_ADDRESS,
+	.min_io_address		= EISA_DEFAULT_IO_BASE,
+	.min_mem_address	= T2_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 40,
+	.device_interrupt	= sable_srm_device_interrupt,
+
+	.init_arch		= t2_init_arch,
+	.init_irq		= sable_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= sable_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { t2: {
-	    gamma_bias:		0
+	.sys = { .t2 = {
+	    .gamma_bias		= 0
 	} }
 };
 ALIAS_MV(sable)
@@ -316,28 +316,28 @@
 #undef GAMMA_BIAS
 #define GAMMA_BIAS _GAMMA_BIAS
 struct alpha_machine_vector sable_gamma_mv __initmv = {
-	vector_name:		"Sable-Gamma",
+	.vector_name		= "Sable-Gamma",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_T2_IO,
 	DO_T2_BUS,
-	machine_check:		t2_machine_check,
-	max_dma_address:	ALPHA_SABLE_MAX_DMA_ADDRESS,
-	min_io_address:		EISA_DEFAULT_IO_BASE,
-	min_mem_address:	T2_DEFAULT_MEM_BASE,
-
-	nr_irqs:		40,
-	device_interrupt:	sable_srm_device_interrupt,
-
-	init_arch:		t2_init_arch,
-	init_irq:		sable_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	pci_map_irq:		sable_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= t2_machine_check,
+	.max_dma_address	= ALPHA_SABLE_MAX_DMA_ADDRESS,
+	.min_io_address		= EISA_DEFAULT_IO_BASE,
+	.min_mem_address	= T2_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 40,
+	.device_interrupt	= sable_srm_device_interrupt,
+
+	.init_arch		= t2_init_arch,
+	.init_irq		= sable_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.pci_map_irq		= sable_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { t2: {
-	    gamma_bias:		_GAMMA_BIAS
+	.sys = { .t2 = {
+	    .gamma_bias		= _GAMMA_BIAS
 	} }
 };
 ALIAS_MV(sable_gamma)
diff -Nru a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c
--- a/arch/alpha/kernel/sys_sio.c	Tue Oct 15 20:29:11 2002
+++ b/arch/alpha/kernel/sys_sio.c	Tue Oct 15 20:29:11 2002
@@ -252,30 +252,30 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_BOOK1)
 struct alpha_machine_vector alphabook1_mv __initmv = {
-	vector_name:		"AlphaBook1",
+	.vector_name		= "AlphaBook1",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_LCA_IO,
 	DO_LCA_BUS,
-	machine_check:		lca_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		16,
-	device_interrupt:	isa_device_interrupt,
-
-	init_arch:		alphabook1_init_arch,
-	init_irq:		sio_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		alphabook1_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		noname_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= lca_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 16,
+	.device_interrupt	= isa_device_interrupt,
+
+	.init_arch		= alphabook1_init_arch,
+	.init_irq		= sio_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= alphabook1_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= noname_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { sio: {
+	.sys = { .sio = {
 		/* NCR810 SCSI is 14, PCMCIA controller is 15.  */
-		route_tab:	0x0e0f0a0a,
+		.route_tab	= 0x0e0f0a0a,
 	}}
 };
 ALIAS_MV(alphabook1)
@@ -283,28 +283,28 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_AVANTI)
 struct alpha_machine_vector avanti_mv __initmv = {
-	vector_name:		"Avanti",
+	.vector_name		= "Avanti",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_APECS_IO,
 	DO_APECS_BUS,
-	machine_check:		apecs_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		16,
-	device_interrupt:	isa_device_interrupt,
-
-	init_arch:		apecs_init_arch,
-	init_irq:		sio_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		noname_init_pci,
-	pci_map_irq:		noname_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= apecs_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 16,
+	.device_interrupt	= isa_device_interrupt,
+
+	.init_arch		= apecs_init_arch,
+	.init_irq		= sio_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= noname_init_pci,
+	.pci_map_irq		= noname_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { sio: {
-		route_tab:	0x0b0a0e0f,
+	.sys = { .sio = {
+		.route_tab	= 0x0b0a0e0f,
 	}}
 };
 ALIAS_MV(avanti)
@@ -312,27 +312,27 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_NONAME)
 struct alpha_machine_vector noname_mv __initmv = {
-	vector_name:		"Noname",
+	.vector_name		= "Noname",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_LCA_IO,
 	DO_LCA_BUS,
-	machine_check:		lca_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		16,
-	device_interrupt:	srm_device_interrupt,
-
-	init_arch:		lca_init_arch,
-	init_irq:		sio_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		noname_init_pci,
-	pci_map_irq:		noname_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= lca_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 16,
+	.device_interrupt	= srm_device_interrupt,
+
+	.init_arch		= lca_init_arch,
+	.init_irq		= sio_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= noname_init_pci,
+	.pci_map_irq		= noname_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { sio: {
+	.sys = { .sio = {
 		/* For UDB, the only available PCI slot must not map to IRQ 9,
 		   since that's the builtin MSS sound chip. That PCI slot
 		   will map to PIRQ1 (for INTA at least), so we give it IRQ 15
@@ -342,7 +342,7 @@
 		   they are co-indicated when the platform type "Noname" is
 		   selected... :-(  */
 
-		route_tab:	0x0b0a0f0d,
+		.route_tab	= 0x0b0a0f0d,
 	}}
 };
 ALIAS_MV(noname)
@@ -350,28 +350,28 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_P2K)
 struct alpha_machine_vector p2k_mv __initmv = {
-	vector_name:		"Platform2000",
+	.vector_name		= "Platform2000",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_LCA_IO,
 	DO_LCA_BUS,
-	machine_check:		lca_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	APECS_AND_LCA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		16,
-	device_interrupt:	srm_device_interrupt,
-
-	init_arch:		lca_init_arch,
-	init_irq:		sio_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		noname_init_pci,
-	pci_map_irq:		p2k_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= lca_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= APECS_AND_LCA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 16,
+	.device_interrupt	= srm_device_interrupt,
+
+	.init_arch		= lca_init_arch,
+	.init_irq		= sio_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= noname_init_pci,
+	.pci_map_irq		= p2k_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { sio: {
-		route_tab:	0x0b0a090f,
+	.sys = { .sio = {
+		.route_tab	= 0x0b0a090f,
 	}}
 };
 ALIAS_MV(p2k)
@@ -379,28 +379,28 @@
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_XL)
 struct alpha_machine_vector xl_mv __initmv = {
-	vector_name:		"XL",
+	.vector_name		= "XL",
 	DO_EV4_MMU,
 	DO_DEFAULT_RTC,
 	DO_APECS_IO,
 	BUS(apecs),
-	machine_check:		apecs_machine_check,
-	max_dma_address:	ALPHA_XL_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	XL_DEFAULT_MEM_BASE,
-
-	nr_irqs:		16,
-	device_interrupt:	isa_device_interrupt,
-
-	init_arch:		apecs_init_arch,
-	init_irq:		sio_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		noname_init_pci,
-	pci_map_irq:		noname_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= apecs_machine_check,
+	.max_dma_address	= ALPHA_XL_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= XL_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 16,
+	.device_interrupt	= isa_device_interrupt,
+
+	.init_arch		= apecs_init_arch,
+	.init_irq		= sio_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= noname_init_pci,
+	.pci_map_irq		= noname_map_irq,
+	.pci_swizzle		= common_swizzle,
 
-	sys: { sio: {
-		route_tab:	0x0b0a090f,
+	.sys = { .sio = {
+		.route_tab	= 0x0b0a090f,
 	}}
 };
 ALIAS_MV(xl)
diff -Nru a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c
--- a/arch/alpha/kernel/sys_sx164.c	Tue Oct 15 20:29:17 2002
+++ b/arch/alpha/kernel/sys_sx164.c	Tue Oct 15 20:29:17 2002
@@ -154,26 +154,26 @@
  */
 
 struct alpha_machine_vector sx164_mv __initmv = {
-	vector_name:		"SX164",
+	.vector_name		= "SX164",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_PYXIS_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		PYXIS_DAC_OFFSET,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= PYXIS_DAC_OFFSET,
 
-	nr_irqs:		48,
-	device_interrupt:	pyxis_device_interrupt,
+	.nr_irqs		= 48,
+	.device_interrupt	= pyxis_device_interrupt,
 
-	init_arch:		sx164_init_arch,
-	init_irq:		sx164_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		sx164_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		sx164_map_irq,
-	pci_swizzle:		common_swizzle,
+	.init_arch		= sx164_init_arch,
+	.init_irq		= sx164_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= sx164_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= sx164_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(sx164)
diff -Nru a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c
--- a/arch/alpha/kernel/sys_takara.c	Tue Oct 15 20:29:12 2002
+++ b/arch/alpha/kernel/sys_takara.c	Tue Oct 15 20:29:12 2002
@@ -75,13 +75,13 @@
 }
 
 static struct hw_interrupt_type takara_irq_type = {
-	typename:	"TAKARA",
-	startup:	takara_startup_irq,
-	shutdown:	takara_disable_irq,
-	enable:		takara_enable_irq,
-	disable:	takara_disable_irq,
-	ack:		takara_disable_irq,
-	end:		takara_end_irq,
+	.typename	= "TAKARA",
+	.startup	= takara_startup_irq,
+	.shutdown	= takara_disable_irq,
+	.enable		= takara_enable_irq,
+	.disable	= takara_disable_irq,
+	.ack		= takara_disable_irq,
+	.end		= takara_end_irq,
 };
 
 static void
@@ -269,25 +269,25 @@
  */
 
 struct alpha_machine_vector takara_mv __initmv = {
-	vector_name:		"Takara",
+	.vector_name		= "Takara",
 	DO_EV5_MMU,
 	DO_DEFAULT_RTC,
 	DO_CIA_IO,
 	DO_CIA_BUS,
-	machine_check:		cia_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	CIA_DEFAULT_MEM_BASE,
-
-	nr_irqs:		128,
-	device_interrupt:	takara_device_interrupt,
-
-	init_arch:		cia_init_arch,
-	init_irq:		takara_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		takara_init_pci,
-	kill_arch:		NULL,
-	pci_map_irq:		takara_map_irq,
-	pci_swizzle:		takara_swizzle,
+	.machine_check		= cia_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= CIA_DEFAULT_MEM_BASE,
+
+	.nr_irqs		= 128,
+	.device_interrupt	= takara_device_interrupt,
+
+	.init_arch		= cia_init_arch,
+	.init_irq		= takara_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= takara_init_pci,
+	.kill_arch		= NULL,
+	.pci_map_irq		= takara_map_irq,
+	.pci_swizzle		= takara_swizzle,
 };
 ALIAS_MV(takara)
diff -Nru a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
--- a/arch/alpha/kernel/sys_titan.c	Tue Oct 15 20:29:21 2002
+++ b/arch/alpha/kernel/sys_titan.c	Tue Oct 15 20:29:21 2002
@@ -152,14 +152,14 @@
 }
 
 static struct hw_interrupt_type privateer_irq_type = {
-	typename:	"PRIVATEER",
-	startup:	privateer_startup_irq,
-	shutdown:	privateer_disable_irq,
-	enable:		privateer_enable_irq,
-	disable:	privateer_disable_irq,
-	ack:		privateer_disable_irq,
-	end:		privateer_end_irq,
-	set_affinity:	privateer_set_affinity,
+	.typename	= "PRIVATEER",
+	.startup	= privateer_startup_irq,
+	.shutdown	= privateer_disable_irq,
+	.enable		= privateer_enable_irq,
+	.disable	= privateer_disable_irq,
+	.ack		= privateer_disable_irq,
+	.end		= privateer_end_irq,
+	.set_affinity	= privateer_set_affinity,
 };
 
 static void
@@ -367,26 +367,26 @@
  */
 
 struct alpha_machine_vector privateer_mv __initmv = {
-	vector_name:		"PRIVATEER",
+	.vector_name		= "PRIVATEER",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_TITAN_IO,
 	DO_TITAN_BUS,
-	machine_check:		privateer_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-	pci_dac_offset:		TITAN_DAC_OFFSET,
-
-	nr_irqs:		80,	/* 64 + 16 */
-	device_interrupt:	privateer_device_interrupt,
-
-	init_arch:		titan_init_arch,
-	init_irq:		privateer_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		privateer_init_pci,
-	kill_arch:		titan_kill_arch,
-	pci_map_irq:		privateer_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= privateer_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+	.pci_dac_offset		= TITAN_DAC_OFFSET,
+
+	.nr_irqs		= 80,	/* 64 + 16 */
+	.device_interrupt	= privateer_device_interrupt,
+
+	.init_arch		= titan_init_arch,
+	.init_irq		= privateer_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= privateer_init_pci,
+	.kill_arch		= titan_kill_arch,
+	.pci_map_irq		= privateer_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(privateer)
diff -Nru a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c
--- a/arch/alpha/kernel/sys_wildfire.c	Tue Oct 15 20:29:16 2002
+++ b/arch/alpha/kernel/sys_wildfire.c	Tue Oct 15 20:29:16 2002
@@ -158,13 +158,13 @@
 }
 
 static struct hw_interrupt_type wildfire_irq_type = {
-	typename:	"WILDFIRE",
-	startup:	wildfire_startup_irq,
-	shutdown:	wildfire_disable_irq,
-	enable:		wildfire_enable_irq,
-	disable:	wildfire_disable_irq,
-	ack:		wildfire_mask_and_ack_irq,
-	end:		wildfire_end_irq,
+	.typename	= "WILDFIRE",
+	.startup	= wildfire_startup_irq,
+	.shutdown	= wildfire_disable_irq,
+	.enable		= wildfire_enable_irq,
+	.disable	= wildfire_disable_irq,
+	.ack		= wildfire_mask_and_ack_irq,
+	.end		= wildfire_end_irq,
 };
 
 static void __init
@@ -173,8 +173,8 @@
 	int i, irq_bias;
 	unsigned long io_bias;
 	static struct irqaction isa_enable = {
-		handler:	no_action,
-		name:		"isa_enable",
+		.handler	= no_action,
+		.name		= "isa_enable",
 	};
 
 	irq_bias = qbbno * (WILDFIRE_PCA_PER_QBB * WILDFIRE_IRQ_PER_PCA)
@@ -333,25 +333,25 @@
  */
 
 struct alpha_machine_vector wildfire_mv __initmv = {
-	vector_name:		"WILDFIRE",
+	.vector_name		= "WILDFIRE",
 	DO_EV6_MMU,
 	DO_DEFAULT_RTC,
 	DO_WILDFIRE_IO,
 	DO_WILDFIRE_BUS,
-	machine_check:		wildfire_machine_check,
-	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	min_io_address:		DEFAULT_IO_BASE,
-	min_mem_address:	DEFAULT_MEM_BASE,
-
-	nr_irqs:		WILDFIRE_NR_IRQS,
-	device_interrupt:	wildfire_device_interrupt,
-
-	init_arch:		wildfire_init_arch,
-	init_irq:		wildfire_init_irq,
-	init_rtc:		common_init_rtc,
-	init_pci:		common_init_pci,
-	kill_arch:		wildfire_kill_arch,
-	pci_map_irq:		wildfire_map_irq,
-	pci_swizzle:		common_swizzle,
+	.machine_check		= wildfire_machine_check,
+	.max_dma_address	= ALPHA_MAX_DMA_ADDRESS,
+	.min_io_address		= DEFAULT_IO_BASE,
+	.min_mem_address	= DEFAULT_MEM_BASE,
+
+	.nr_irqs		= WILDFIRE_NR_IRQS,
+	.device_interrupt	= wildfire_device_interrupt,
+
+	.init_arch		= wildfire_init_arch,
+	.init_irq		= wildfire_init_irq,
+	.init_rtc		= common_init_rtc,
+	.init_pci		= common_init_pci,
+	.kill_arch		= wildfire_kill_arch,
+	.pci_map_irq		= wildfire_map_irq,
+	.pci_swizzle		= common_swizzle,
 };
 ALIAS_MV(wildfire)
diff -Nru a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
--- a/arch/alpha/kernel/systbls.S	Tue Oct 15 20:29:17 2002
+++ b/arch/alpha/kernel/systbls.S	Tue Oct 15 20:29:17 2002
@@ -4,6 +4,7 @@
  * The system call table. 
  */
 
+#include <linux/config.h>			/* CONFIG_OSF4_COMPAT */
 #include <asm/unistd.h>
 
 	.data
diff -Nru a/arch/alpha/lib/ev6-stxncpy.S b/arch/alpha/lib/ev6-stxncpy.S
--- a/arch/alpha/lib/ev6-stxncpy.S	Tue Oct 15 20:29:20 2002
+++ b/arch/alpha/lib/ev6-stxncpy.S	Tue Oct 15 20:29:20 2002
@@ -253,7 +253,7 @@
 
 	stq_u	t0, -8(a0)	# U : save the current word
 	beq	a2, $u_eoc	# U :
-	ldq_u	t2, 0(a1)	# U : Latency=3 load high word for next time
+	ldq_u	t2, 8(a1)	# U : Latency=3 load high word for next time
 	addq	a1, 8, a1	# E :
 
 	extqh	t2, a1, t0	# U : extract low bits (2 cycle stall)
diff -Nru a/arch/alpha/lib/stxncpy.S b/arch/alpha/lib/stxncpy.S
--- a/arch/alpha/lib/stxncpy.S	Tue Oct 15 20:29:22 2002
+++ b/arch/alpha/lib/stxncpy.S	Tue Oct 15 20:29:22 2002
@@ -210,7 +210,7 @@
 	addq	a0, 8, a0	# .. e1 :
 	extql	t2, a1, t1	# e0    : extract high bits for next time
 	beq	a2, $u_eoc	# .. e1 :
-	ldq_u	t2, 0(a1)	# e0    : load high word for next time
+	ldq_u	t2, 8(a1)	# e0    : load high word for next time
 	addq	a1, 8, a1	# .. e1 :
 	nop			# e0    :
 	cmpbge	zero, t2, t8	# e1    : test new word for eos (stall)
diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile	Tue Oct 15 20:29:16 2002
+++ b/arch/arm/Makefile	Tue Oct 15 20:29:16 2002
@@ -8,6 +8,7 @@
 # Copyright (C) 1995-2001 by Russell King
 
 LDFLAGS_vmlinux	:=-p -X
+AFLAGS_vmlinux.lds.o = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR)
 OBJCOPYFLAGS	:=-O binary -R .note -R .comment -S
 GZFLAGS		:=-9
 #CFLAGS		+=-pipe
@@ -50,18 +51,29 @@
 tune-$(CONFIG_CPU_SA1100)	:=-mtune=strongarm1100
 tune-$(CONFIG_CPU_XSCALE)	:=-mtune=strongarm #-mtune=xscale
 
-CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
-CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float
-AFLAGS		+=$(apcs-y) $(arch-y) -mno-fpu -msoft-float
+# Force -mno-fpu to be passed to the assembler.  Some versions of gcc don't
+# do this with -msoft-float
+CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu
+CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu
+AFLAGS		+=$(apcs-y) $(arch-y) -mno-fpu -msoft-float -Wa,-mno-fpu
 
 ifeq ($(CONFIG_CPU_26),y)
 PROCESSOR	:= armo
 HEAD		:= arch/arm/mach-arc/head.o arch/arm/kernel/init_task.o
+  ifeq ($(CONFIG_ROM_KERNEL),y)
+    DATAADDR	 = 0x02080000
+    TEXTADDR	 = 0x03800000
+    LDSCRIPT	 = arch/arm/vmlinux-armo-rom.lds.in
+  else
+    TEXTADDR	 = 0x02080000
+    LDSCRIPT	 = arch/arm/vmlinux-armo.lds.in
+  endif
 endif
 
 ifeq ($(CONFIG_CPU_32),y)
 PROCESSOR	 = armv
 HEAD		:= arch/arm/kernel/head.o arch/arm/kernel/init_task.o
+TEXTADDR	 = 0xC0008000
 endif
 
 ifeq ($(CONFIG_ARCH_ARCA5K),y)
@@ -175,7 +187,7 @@
 core-$(CONFIG_FPE_FASTFPE)	+= $(FASTFPE_OBJ)
 
 drivers-$(CONFIG_ARCH_CLPS7500)	+= drivers/acorn/char/
-drivers-$(CONFIG_ARCH_L7200))	+= drivers/acorn/char/
+drivers-$(CONFIG_ARCH_L7200)	+= drivers/acorn/char/
 
 libs-y				+= arch/arm/lib/
 
diff -Nru a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
--- a/arch/arm/boot/compressed/Makefile	Tue Oct 15 20:29:12 2002
+++ b/arch/arm/boot/compressed/Makefile	Tue Oct 15 20:29:12 2002
@@ -18,7 +18,7 @@
 #
 ifeq ($(CONFIG_ARCH_ACORN),y)
 OBJS		+= ll_char_wr.o font.o
-ZLDFLAGS	+= -defsym params=$(PARAMS_PHYS)
+CFLAGS		+= -DPARAMS_PHYS=$(PARAMS_PHYS)
 endif
 
 ifeq ($(CONFIG_ARCH_NETWINDER),y)
diff -Nru a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
--- a/arch/arm/boot/compressed/head.S	Tue Oct 15 20:29:21 2002
+++ b/arch/arm/boot/compressed/head.S	Tue Oct 15 20:29:21 2002
@@ -55,6 +55,18 @@
 		.macro	writeb, rb
 		strb	\rb, [r3, #0]
 		.endm
+#elif defined(CONFIG_ARCH_SA1100)
+		.macro	loadsp, rb
+		mov	\rb, #0x80000000	@ physical base address
+#  if defined(CONFIG_DEBUG_LL_SER3)
+		add	\rb, \rb, #0x00050000	@ Ser3
+#  else
+		add	\rb, \rb, #0x00010000	@ Ser1
+#  endif
+		.endm
+		.macro	writeb, rb
+		str	\rb, [r3, #0x14]	@ UTDR
+		.endm
 #else
 #error no serial architecture defined
 #endif
@@ -151,22 +163,55 @@
 		ldmia	r0, {r1, r2, r3, r4, r5, r6, ip, sp}
 		subs	r0, r0, r1		@ calculate the delta offset
 
-		teq	r0, #0			@ if delta is zero, we're
+						@ if delta is zero, we're
 		beq	not_relocated		@ running at the address we
 						@ were linked at.
 
-		add	r2, r2, r0		@ different address, so we
-		add	r3, r3, r0		@ need to fix up various
-		add	r5, r5, r0		@ pointers.
+		/*
+		 * We're running at a different address.  We need to fix
+		 * up various pointers:
+		 *   r5 - zImage base address
+		 *   r6 - GOT start
+		 *   ip - GOT end
+		 */
+		add	r5, r5, r0
 		add	r6, r6, r0
 		add	ip, ip, r0
+
+#ifndef CONFIG_ZBOOT_ROM
+		/*
+		 * If we're running fully PIC === CONFIG_ZBOOT_ROM = n,
+		 * we need to fix up pointers into the BSS region.
+		 *   r2 - BSS start
+		 *   r3 - BSS end
+		 *   sp - stack pointer
+		 */
+		add	r2, r2, r0
+		add	r3, r3, r0
 		add	sp, sp, r0
 
+		/*
+		 * Relocate all entries in the GOT table.
+		 */
 1:		ldr	r1, [r6, #0]		@ relocate entries in the GOT
 		add	r1, r1, r0		@ table.  This fixes up the
 		str	r1, [r6], #4		@ C references.
 		cmp	r6, ip
 		blo	1b
+#else
+
+		/*
+		 * Relocate entries in the GOT table.  We only relocate
+		 * the entries that are outside the (relocated) BSS region.
+		 */
+1:		ldr	r1, [r6, #0]		@ relocate entries in the GOT
+		cmp	r1, r2			@ entry < bss_start ||
+		cmphs	r3, r1			@ _end < entry
+		addlo	r1, r1, r0		@ table.  This fixes up the
+		str	r1, [r6], #4		@ C references.
+		cmp	r6, ip
+		blo	1b
+#endif
 
 not_relocated:	mov	r0, #0
 1:		str	r0, [r2], #4		@ clear bss
@@ -176,6 +221,11 @@
 		cmp	r2, r3
 		blo	1b
 
+		/*
+		 * The C runtime environment should now be setup
+		 * sufficiently.  Turn the cache on, set up some
+		 * pointers, and start decompressing.
+		 */
 		bl	cache_on
 
 		mov	r1, sp			@ malloc space above stack
diff -Nru a/arch/arm/boot/compressed/ll_char_wr.S b/arch/arm/boot/compressed/ll_char_wr.S
--- a/arch/arm/boot/compressed/ll_char_wr.S	Tue Oct 15 20:29:15 2002
+++ b/arch/arm/boot/compressed/ll_char_wr.S	Tue Oct 15 20:29:15 2002
@@ -19,144 +19,116 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-		.text
+	.text
 
-#define BOLD            0x01
-#define ITALIC          0x02
-#define UNDERLINE       0x04
-#define FLASH           0x08
-#define INVERSE         0x10
-
-LC0:		.word	bytes_per_char_h
-		.word	video_size_row
-		.word	acorndata_8x8
-		.word	con_charconvtable
+LC0:	.word	LC0
+	.word	bytes_per_char_h
+	.word	video_size_row
+	.word	acorndata_8x8
+	.word	con_charconvtable
 
+/*
+ * r0 = ptr
+ * r1 = char
+ * r2 = white
+ */
 ENTRY(ll_write_char)
-		stmfd	sp!, {r4 - r7, lr}
+	stmfd	sp!, {r4 - r7, lr}
 @
 @ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc)
 @
-		eor	ip, r1, #UNDERLINE << 9
-/*
- * calculate colours
- */
-		tst	r1, #INVERSE << 9
-		moveq	r2, r1, lsr #16
-		moveq	r3, r1, lsr #24
-		movne	r2, r1, lsr #24
-		movne	r3, r1, lsr #16
-		and	r3, r3, #255
-		and	r2, r2, #255
-/*
- * calculate offset into character table
- */
-		mov	r1, r1, lsl #23
-		mov	r1, r1, lsr #20
-/*
- * calculate offset required for each row [maybe I should make this an argument to this fn.
- * Have to see what the register usage is like in the calling routines.
- */
-		adr	r4, LC0
-		ldmia	r4, {r4, r5, r6, lr}
-		ldr	r4, [r4]
-		ldr	r5, [r5]
-/*
- * Go to resolution-dependent routine...
- */
-		cmp	r4, #4
-		blt	Lrow1bpp
-		eor	r2, r3, r2			@ Create eor mask to change colour from bg
-		orr	r3, r3, r3, lsl #8		@ to fg.
-		orr	r3, r3, r3, lsl #16
-		add	r0, r0, r5, lsl #3		@ Move to bottom of character
-		add	r1, r1, #7
-		ldrb	r7, [r6, r1]
-		tst	ip, #UNDERLINE << 9
-		eoreq	r7, r7, #255
-		teq	r4, #8
-		beq	Lrow8bpplp
+	/*
+	 * calculate offset into character table
+	 */
+	mov	r1, r1, lsl #3
+	/*
+	 * calculate offset required for each row.
+	 */
+	adr	ip, LC0
+	ldmia	ip, {r3, r4, r5, r6, lr}
+	sub	ip, ip, r3
+	add	r6, r6, ip
+	add	lr, lr, ip
+	ldr	r4, [r4, ip]
+	ldr	r5, [r5, ip]
+	/*
+	 * Go to resolution-dependent routine...
+	 */
+	cmp	r4, #4
+	blt	Lrow1bpp
+	add	r0, r0, r5, lsl #3		@ Move to bottom of character
+	orr	r1, r1, #7
+	ldrb	r7, [r6, r1]
+	teq	r4, #8
+	beq	Lrow8bpplp
 @
 @ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
 @
-		orr	r3, r3, r3, lsl #4
-Lrow4bpplp:	ldr	r7, [lr, r7, lsl #2]
-		mul	r7, r2, r7
-		tst	r1, #7				@ avoid using r7 directly after
-		eor	ip, r3, r7
-		str	ip, [r0, -r5]!
-		LOADREGS(eqfd, sp!, {r4 - r7, pc})
-		sub	r1, r1, #1
-		ldrb	r7, [r6, r1]
-		ldr	r7, [lr, r7, lsl #2]
-		mul	r7, r2, r7
-		tst	r1, #7				@ avoid using r7 directly after
-		eor	ip, r3, r7
-		str	ip, [r0, -r5]!
-		subne	r1, r1, #1
-		ldrneb	r7, [r6, r1]
-		bne	Lrow4bpplp
-		LOADREGS(fd, sp!, {r4 - r7, pc})
+Lrow4bpplp:
+	ldr	r7, [lr, r7, lsl #2]
+	mul	r7, r2, r7
+	sub	r1, r1, #1			@ avoid using r7 directly after
+	str	r7, [r0, -r5]!
+	ldrb	r7, [r6, r1]
+	ldr	r7, [lr, r7, lsl #2]
+	mul	r7, r2, r7
+	tst	r1, #7				@ avoid using r7 directly after
+	str	r7, [r0, -r5]!
+	subne	r1, r1, #1
+	ldrneb	r7, [r6, r1]
+	bne	Lrow4bpplp
+	LOADREGS(fd, sp!, {r4 - r7, pc})
 
 @
 @ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc)
 @
-Lrow8bpplp:	mov	ip, r7, lsr #4
-		ldr	ip, [lr, ip, lsl #2]
-		mul	r4, r2, ip
-		and	ip, r7, #15			@ avoid r4
-		ldr	ip, [lr, ip, lsl #2]		@ avoid r4
-		mul	ip, r2, ip			@ avoid r4
-		eor	r4, r3, r4			@ avoid ip
-		tst	r1, #7				@ avoid ip
-		sub	r0, r0, r5			@ avoid ip
-		eor	ip, r3, ip
-		stmia	r0, {r4, ip}
-		LOADREGS(eqfd, sp!, {r4 - r7, pc})
-		sub	r1, r1, #1
-		ldrb	r7, [r6, r1]
-		mov	ip, r7, lsr #4
-		ldr	ip, [lr, ip, lsl #2]
-		mul	r4, r2, ip
-		and	ip, r7, #15			@ avoid r4
-		ldr	ip, [lr, ip, lsl #2]		@ avoid r4
-		mul	ip, r2, ip			@ avoid r4
-		eor	r4, r3, r4			@ avoid ip
-		tst	r1, #7				@ avoid ip
-		sub	r0, r0, r5			@ avoid ip
-		eor	ip, r3, ip
-		stmia	r0, {r4, ip}
-		subne	r1, r1, #1
-		ldrneb	r7, [r6, r1]
-		bne	Lrow8bpplp
-		LOADREGS(fd, sp!, {r4 - r7, pc})
+Lrow8bpplp:
+	mov	ip, r7, lsr #4
+	ldr	ip, [lr, ip, lsl #2]
+	mul	r4, r2, ip
+	and	ip, r7, #15			@ avoid r4
+	ldr	ip, [lr, ip, lsl #2]		@ avoid r4
+	mul	ip, r2, ip			@ avoid r4
+	sub	r1, r1, #1			@ avoid ip
+	sub	r0, r0, r5			@ avoid ip
+	stmia	r0, {r4, ip}
+	ldrb	r7, [r6, r1]
+	mov	ip, r7, lsr #4
+	ldr	ip, [lr, ip, lsl #2]
+	mul	r4, r2, ip
+	and	ip, r7, #15			@ avoid r4
+	ldr	ip, [lr, ip, lsl #2]		@ avoid r4
+	mul	ip, r2, ip			@ avoid r4
+	tst	r1, #7				@ avoid ip
+	sub	r0, r0, r5			@ avoid ip
+	stmia	r0, {r4, ip}
+	subne	r1, r1, #1
+	ldrneb	r7, [r6, r1]
+	bne	Lrow8bpplp
+	LOADREGS(fd, sp!, {r4 - r7, pc})
 
 @
 @ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc)
 @
-Lrow1bpp:	add	r6, r6, r1
-		ldmia	r6, {r4, r7}
-		tst	ip, #INVERSE << 9
-		mvnne	r4, r4
-		mvnne	r7, r7
-		strb	r4, [r0], r5
-		mov	r4, r4, lsr #8
-		strb	r4, [r0], r5
-		mov	r4, r4, lsr #8
-		strb	r4, [r0], r5
-		mov	r4, r4, lsr #8
-		strb	r4, [r0], r5
-		strb	r7, [r0], r5
-		mov	r7, r7, lsr #8
-		strb	r7, [r0], r5
-		mov	r7, r7, lsr #8
-		strb	r7, [r0], r5
-		mov	r7, r7, lsr #8
-		tst	ip, #UNDERLINE << 9
-		mvneq	r7, r7
-		strb	r7, [r0], r5
-		LOADREGS(fd, sp!, {r4 - r7, pc})
+Lrow1bpp:
+	add	r6, r6, r1
+	ldmia	r6, {r4, r7}
+	strb	r4, [r0], r5
+	mov	r4, r4, lsr #8
+	strb	r4, [r0], r5
+	mov	r4, r4, lsr #8
+	strb	r4, [r0], r5
+	mov	r4, r4, lsr #8
+	strb	r4, [r0], r5
+	strb	r7, [r0], r5
+	mov	r7, r7, lsr #8
+	strb	r7, [r0], r5
+	mov	r7, r7, lsr #8
+	strb	r7, [r0], r5
+	mov	r7, r7, lsr #8
+	strb	r7, [r0], r5
+	LOADREGS(fd, sp!, {r4 - r7, pc})
 
-		.bss
+	.bss
 ENTRY(con_charconvtable)
-		.space	1024
+	.space	1024
diff -Nru a/arch/arm/config.in b/arch/arm/config.in
--- a/arch/arm/config.in	Tue Oct 15 20:29:12 2002
+++ b/arch/arm/config.in	Tue Oct 15 20:29:12 2002
@@ -94,6 +94,8 @@
      "$CONFIG_SA1100_XP860" = "y" ]; then
    define_bool CONFIG_SA1111 y
    define_int CONFIG_FORCE_MAX_ZONEORDER 9
+else
+   define_bool CONFIG_SA1111 n
 fi
 
 comment 'Processor Type'
@@ -231,6 +233,8 @@
      "$CONFIG_CPU_ARM922T" = "y" -o "$CONFIG_CPU_ARM926T" = "y" -o \
      "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_XSCALE" = "y" ]; then
    dep_bool 'Support Thumb instructions (EXPERIMENTAL)' CONFIG_ARM_THUMB $CONFIG_EXPERIMENTAL
+else
+   define_bool CONFIG_ARM_THUMB n
 fi
 if [ "$CONFIG_CPU_ARM920T" = "y" -o "$CONFIG_CPU_ARM922T" = "y" -o \
      "$CONFIG_CPU_ARM926T" = "y" -o "$CONFIG_CPU_ARM1020" = "y" ]; then
diff -Nru a/arch/arm/kernel/arch.c b/arch/arm/kernel/arch.c
--- a/arch/arm/kernel/arch.c	Tue Oct 15 20:29:12 2002
+++ b/arch/arm/kernel/arch.c	Tue Oct 15 20:29:12 2002
@@ -8,6 +8,7 @@
 #include <linux/types.h>
 
 #include <asm/elf.h>
+#include <asm/page.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
diff -Nru a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
--- a/arch/arm/kernel/bios32.c	Tue Oct 15 20:29:16 2002
+++ b/arch/arm/kernel/bios32.c	Tue Oct 15 20:29:16 2002
@@ -599,7 +599,7 @@
  * pcibios_enable_device - Enable I/O and memory.
  * @dev: PCI device to be enabled
  */
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -608,6 +608,10 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for (idx = 0; idx < 6; idx++) {
+		/* Only set up the requested stuff */
+		if (!(mask & (1 << idx)))
+			continue;
+
 		r = dev->resource + idx;
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because"
@@ -624,5 +628,31 @@
 		       dev->slot_name, old_cmd, cmd);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
+	return 0;
+}
+
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+			enum pci_mmap_state mmap_state, int write_combine)
+{
+	struct pci_sys_data *root = dev->sysdata;
+	unsigned long prot, phys;
+
+	if (mmap_state == pci_mmap_io) {
+		return -EINVAL;
+	} else {
+		phys = root->mem_offset + (vma->vm_pgoff << PAGE_SHIFT);
+	}
+
+	/*
+	 * Mark this as IO
+	 */
+	vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	if (remap_page_range(vma, vma->vm_start, phys,
+			     vma->vm_end - vma->vm_start,
+			     vma->vm_page_prot))
+		return -EAGAIN;
+
 	return 0;
 }
diff -Nru a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
--- a/arch/arm/kernel/ecard.c	Tue Oct 15 20:29:20 2002
+++ b/arch/arm/kernel/ecard.c	Tue Oct 15 20:29:20 2002
@@ -38,6 +38,7 @@
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 #include <linux/notifier.h>
+#include <linux/device.h>
 #include <linux/init.h>
 
 #include <asm/dma.h>
@@ -48,6 +49,7 @@
 #include <asm/pgalloc.h>
 #include <asm/mmu_context.h>
 #include <asm/mach/irq.h>
+#include <asm/tlbflush.h>
 
 #ifndef CONFIG_ARCH_RPC
 #define HAVE_EXPMASK
@@ -92,6 +94,8 @@
 asmlinkage extern int
 ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader);
 
+static const struct ecard_id *
+ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec);
 
 static inline unsigned short
 ecard_getu16(unsigned char *v)
@@ -969,6 +973,14 @@
 
 	*ecp = ec;
 	slot_to_expcard[slot] = ec;
+
+	snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot);
+	strcpy(ec->dev.name, "fixme!");
+	ec->dev.parent = NULL;
+	ec->dev.bus    = &ecard_bus_type;
+
+	device_register(&ec->dev);
+
 	return 0;
 
 nodev:
@@ -995,22 +1007,17 @@
 		if (finding_pos->claimed)
 			continue;
 
+		if (finding_pos->dev.driver)
+			continue;
+
 		if (!cids) {
 			if ((finding_pos->cid.id ^ cid) == 0)
 				break;
 		} else {
-			unsigned int manufacturer, product;
-			int i;
-
-			manufacturer = finding_pos->cid.manufacturer;
-			product = finding_pos->cid.product;
-
-			for (i = 0; cids[i].manufacturer != 65535; i++)
-				if (manufacturer == cids[i].manufacturer &&
-				    product == cids[i].product)
-					break;
+			const struct ecard_id *id;
 
-			if (cids[i].manufacturer != 65535)
+			id = ecard_match_device(cids, finding_pos);
+			if (id)
 				break;
 		}
 	}
@@ -1023,7 +1030,7 @@
  * Locate all hardware - interrupt management and
  * actual cards.
  */
-void __init ecard_init(void)
+static int __init ecard_init(void)
 {
 	int slot, irqhw;
 
@@ -1053,11 +1060,96 @@
 				irqhw ? ecard_irqexp_handler : ecard_irq_handler);
 
 	ecard_proc_init();
+
+	return 0;
 }
 
 subsys_initcall(ecard_init);
 
+/*
+ *	ECARD "bus"
+ */
+static const struct ecard_id *
+ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec)
+{
+	int i;
+
+	for (i = 0; ids[i].manufacturer != 65535; i++)
+		if (ec->cid.manufacturer == ids[i].manufacturer &&
+		    ec->cid.product == ids[i].product)
+			return ids + i;
+
+	return NULL;
+}
+
+static int ecard_drv_probe(struct device *dev)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct ecard_driver *drv = ECARD_DRV(dev->driver);
+	const struct ecard_id *id;
+
+	id = ecard_match_device(drv->id_table, ec);
+
+	return drv->probe(ec, id);
+}
+
+static int ecard_drv_remove(struct device *dev)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct ecard_driver *drv = ECARD_DRV(dev->driver);
+
+	drv->remove(ec);
+
+	return 0;
+}
+
+int ecard_register_driver(struct ecard_driver *drv)
+{
+	drv->drv.bus = &ecard_bus_type;
+	drv->drv.probe = ecard_drv_probe;
+	drv->drv.remove = ecard_drv_remove;
+
+	return driver_register(&drv->drv);
+}
+
+void ecard_remove_driver(struct ecard_driver *drv)
+{
+	remove_driver(&drv->drv);
+}
+
+static int ecard_match(struct device *_dev, struct device_driver *_drv)
+{
+	struct expansion_card *ec = ECARD_DEV(_dev);
+	struct ecard_driver *drv = ECARD_DRV(_drv);
+	int ret;
+
+	if (drv->id_table) {
+		ret = ecard_match_device(drv->id_table, ec) != NULL;
+	} else {
+		ret = ec->cid.id == drv->id;
+	}
+
+	return ret;
+}
+
+struct bus_type ecard_bus_type = {
+	.name	= "ecard",
+	.match	= ecard_match,
+};
+
+static int ecard_bus_init(void)
+{
+	return bus_register(&ecard_bus_type);
+}
+
+postcore_initcall(ecard_bus_init);
+
 EXPORT_SYMBOL(ecard_startfind);
 EXPORT_SYMBOL(ecard_find);
 EXPORT_SYMBOL(ecard_readchunk);
 EXPORT_SYMBOL(ecard_address);
+
+EXPORT_SYMBOL(ecard_register_driver);
+EXPORT_SYMBOL(ecard_remove_driver);
+
+EXPORT_SYMBOL(ecard_bus_type);
diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
--- a/arch/arm/kernel/entry-armv.S	Tue Oct 15 20:29:15 2002
+++ b/arch/arm/kernel/entry-armv.S	Tue Oct 15 20:29:15 2002
@@ -189,11 +189,10 @@
 
 		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
 		mov	r4, #0xe0000000
-		orr	r4, r4, #0x20
 
 		mov	\irqstat, #0x0C
-		strb	\irqstat, [r4]			@outb(0x0C, 0x20) /* Poll command */
-		ldrb	\irqnr, [r4]			@irq = inb(0x20) & 7
+		strb	\irqstat, [r4, #0x20]		@outb(0x0C, 0x20) /* Poll command */
+		ldrb	\irqnr, [r4, #0x10]		@irq = inb(0x20) & 7
 		and	\irqstat, \irqnr, #0x80
 		teq	\irqstat, #0
 		beq	43f
@@ -201,8 +200,8 @@
 		teq	\irqnr, #2
 		bne	44f
 43:		mov	\irqstat, #0x0C
-		strb	\irqstat, [r4, #0x80]		@outb(0x0C, 0xA0) /* Poll command */
-		ldrb	\irqnr, [r4, #0x80]		@irq = (inb(0xA0) & 7) + 8
+		strb	\irqstat, [r4, #0xa0]		@outb(0x0C, 0xA0) /* Poll command */
+		ldrb	\irqnr, [r4, #0xa0]		@irq = (inb(0xA0) & 7) + 8
 		and	\irqstat, \irqnr, #0x80
 		teq	\irqstat, #0
 		beq	44f
@@ -655,7 +654,7 @@
 		and	r2, r6, #31			@ int mode
 		b	bad_mode
 
-#if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE
+#if 1 /* defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE */
 		/* The FPE is always present */
 		.equ	fpe_not_present, fpundefinstr
 #else
@@ -766,6 +765,8 @@
 		msr	spsr, r0
 		ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
 
+		.ltorg
+
 #ifdef CONFIG_PREEMPT
 svc_preempt:	teq	r9, #0				@ was preempt count = 0
 		ldreq	r6, .LCirq_stat
@@ -901,6 +902,8 @@
 #endif
 		mov	why, #0
 		b	ret_to_user
+
+		.ltorg
 
 		.align	5
 __und_usr:	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
--- a/arch/arm/kernel/process.c	Tue Oct 15 20:29:21 2002
+++ b/arch/arm/kernel/process.c	Tue Oct 15 20:29:21 2002
@@ -367,8 +367,8 @@
 
 	dump->u_debugreg[0] = tsk->thread.debug.bp[0].address;
 	dump->u_debugreg[1] = tsk->thread.debug.bp[1].address;
-	dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn;
-	dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn;
+	dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn.arm;
+	dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn.arm;
 	dump->u_debugreg[4] = tsk->thread.debug.nsaved;
 
 	if (dump->start_stack < 0x04000000)
diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
--- a/arch/arm/kernel/ptrace.c	Tue Oct 15 20:29:12 2002
+++ b/arch/arm/kernel/ptrace.c	Tue Oct 15 20:29:12 2002
@@ -32,10 +32,24 @@
  * in exit.c or in signal.c.
  */
 
+#if 1
 /*
  * Breakpoint SWI instruction: SWI &9F0001
  */
 #define BREAKINST_ARM	0xef9f0001
+#define BREAKINST_THUMB	0xdf00		/* fill this in later */
+#else
+/*
+ * New breakpoints - use an undefined instruction.  The ARM architecture
+ * reference manual guarantees that the following instruction space
+ * will produce an undefined instruction exception on all CPUs:
+ *
+ *  ARM:   xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
+ *  Thumb: 1101 1110 xxxx xxxx
+ */
+#define BREAKINST_ARM	0xe7f001f0
+#define BREAKINST_THUMB	0xde01
+#endif
 
 /*
  * Get the address of the live pt_regs for the specified task.
@@ -89,23 +103,32 @@
 }
 
 static inline int
-read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res)
+read_u32(struct task_struct *task, unsigned long addr, u32 *res)
 {
-	int copied;
+	int ret;
 
-	copied = access_process_vm(child, addr, res, sizeof(*res), 0);
+	ret = access_process_vm(task, addr, res, sizeof(*res), 0);
 
-	return copied != sizeof(*res) ? -EIO : 0;
+	return ret == sizeof(*res) ? 0 : -EIO;
 }
 
 static inline int
-write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val)
+read_instr(struct task_struct *task, unsigned long addr, u32 *res)
 {
-	int copied;
-
-	copied = access_process_vm(child, addr, &val, sizeof(val), 1);
+	int ret;
 
-	return copied != sizeof(val) ? -EIO : 0;
+	if (addr & 1) {
+		u16 val;
+		ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0);
+		ret = ret == sizeof(val) ? 0 : -EIO;
+		*res = val;
+	} else {
+		u32 val;
+		ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0);
+		ret = ret == sizeof(val) ? 0 : -EIO;
+		*res = val;
+	}
+	return ret;
 }
 
 /*
@@ -206,7 +229,7 @@
 static unsigned long
 get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
 {
-	unsigned long alt = 0;
+	u32 alt = 0;
 
 	switch (insn & 0x0e000000) {
 	case 0x00000000:
@@ -262,7 +285,7 @@
 				else
 					base -= aluop2;
 			}
-			if (read_tsk_long(child, base, &alt) == 0)
+			if (read_u32(child, base, &alt) == 0)
 				alt = pc_pointer(alt);
 		}
 		break;
@@ -289,7 +312,7 @@
 
 			base = ptrace_getrn(child, insn);
 
-			if (read_tsk_long(child, base + nr_regs, &alt) == 0)
+			if (read_u32(child, base + nr_regs, &alt) == 0)
 				alt = pc_pointer(alt);
 			break;
 		}
@@ -319,30 +342,71 @@
 }
 
 static int
-add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr)
+swap_insn(struct task_struct *task, unsigned long addr,
+	  void *old_insn, void *new_insn, int size)
+{
+	int ret;
+
+	ret = access_process_vm(task, addr, old_insn, size, 0);
+	if (ret == size)
+		ret = access_process_vm(task, addr, new_insn, size, 1);
+	return ret;
+}
+
+static void
+add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr)
 {
 	int nr = dbg->nsaved;
-	int res = -EINVAL;
 
 	if (nr < 2) {
-		res = read_tsk_long(child, addr, &dbg->bp[nr].insn);
-		if (res == 0)
-			res = write_tsk_long(child, addr, BREAKINST_ARM);
+		u32 new_insn = BREAKINST_ARM;
+		int res;
+
+		res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4);
 
-		if (res == 0) {
+		if (res == 4) {
 			dbg->bp[nr].address = addr;
 			dbg->nsaved += 1;
 		}
 	} else
 		printk(KERN_ERR "ptrace: too many breakpoints\n");
+}
 
-	return res;
+/*
+ * Clear one breakpoint in the user program.  We copy what the hardware
+ * does and use bit 0 of the address to indicate whether this is a Thumb
+ * breakpoint or an ARM breakpoint.
+ */
+static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp)
+{
+	unsigned long addr = bp->address;
+	union debug_insn old_insn;
+	int ret;
+
+	if (addr & 1) {
+		ret = swap_insn(task, addr & ~1, &old_insn.thumb,
+				&bp->insn.thumb, 2);
+
+		if (ret != 2 || old_insn.thumb != BREAKINST_THUMB)
+			printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at "
+				"0x%08lx (0x%04x)\n", task->comm, task->pid,
+				addr, old_insn.thumb);
+	} else {
+		ret = swap_insn(task, addr & ~3, &old_insn.arm,
+				&bp->insn.arm, 4);
+
+		if (ret != 4 || old_insn.arm != BREAKINST_ARM)
+			printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at "
+				"0x%08lx (0x%08x)\n", task->comm, task->pid,
+				addr, old_insn.arm);
+	}
 }
 
 void ptrace_set_bpt(struct task_struct *child)
 {
 	struct pt_regs *regs;
-	unsigned long pc, insn;
+	unsigned long pc;
+	u32 insn;
 	int res;
 
 	regs = get_user_regs(child);
@@ -353,7 +417,7 @@
 		return;
 	}
 
-	res = read_tsk_long(child, pc, &insn);
+	res = read_instr(child, pc, &insn);
 	if (!res) {
 		struct debug_info *dbg = &child->thread.debug;
 		unsigned long alt;
@@ -362,7 +426,7 @@
 
 		alt = get_branch_address(child, pc, insn);
 		if (alt)
-			res = add_breakpoint(child, dbg, alt);
+			add_breakpoint(child, dbg, alt);
 
 		/*
 		 * Note that we ignore the result of setting the above
@@ -374,7 +438,7 @@
 		 * loose control of the thread during single stepping.
 		 */
 		if (!alt || predicate(insn) != PREDICATE_ALWAYS)
-			res = add_breakpoint(child, dbg, pc + 4);
+			add_breakpoint(child, dbg, pc + 4);
 	}
 }
 
@@ -384,24 +448,17 @@
  */
 void __ptrace_cancel_bpt(struct task_struct *child)
 {
-	struct debug_info *dbg = &child->thread.debug;
-	int i, nsaved = dbg->nsaved;
+	int i, nsaved = child->thread.debug.nsaved;
 
-	dbg->nsaved = 0;
+	child->thread.debug.nsaved = 0;
 
 	if (nsaved > 2) {
 		printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
 		nsaved = 2;
 	}
 
-	for (i = 0; i < nsaved; i++) {
-		unsigned long tmp;
-
-		read_tsk_long(child, dbg->bp[i].address, &tmp);
-		write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn);
-		if (tmp != BREAKINST_ARM)
-			printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n");
-	}
+	for (i = 0; i < nsaved; i++)
+		clear_breakpoint(child, &child->thread.debug.bp[i]);
 }
 
 /*
@@ -537,9 +594,12 @@
 		 */
 		case PTRACE_PEEKTEXT:
 		case PTRACE_PEEKDATA:
-			ret = read_tsk_long(child, addr, &tmp);
-			if (!ret)
+			ret = access_process_vm(child, addr, &tmp,
+						sizeof(unsigned long), 0);
+			if (ret == sizeof(unsigned long))
 				ret = put_user(tmp, (unsigned long *) data);
+			else
+				ret = -EIO;
 			break;
 
 		case PTRACE_PEEKUSR:
@@ -551,7 +611,12 @@
 		 */
 		case PTRACE_POKETEXT:
 		case PTRACE_POKEDATA:
-			ret = write_tsk_long(child, addr, data);
+			ret = access_process_vm(child, addr, &data,
+						sizeof(unsigned long), 1);
+			if (ret == sizeof(unsigned long))
+				ret = 0;
+			else
+				ret = -EIO;
 			break;
 
 		case PTRACE_POKEUSR:
diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
--- a/arch/arm/kernel/setup.c	Tue Oct 15 20:29:17 2002
+++ b/arch/arm/kernel/setup.c	Tue Oct 15 20:29:17 2002
@@ -193,26 +193,25 @@
 			CACHE_LINE(cache)));
 }
 
-static inline void dump_cpu_cache_id(void)
+static void __init dump_cpu_info(void)
 {
-	unsigned int cache_info;
+	unsigned int info;
 
-	asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info));
+	asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (info));
 
-	if (cache_info == processor_id)
-		return;
-
-	printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(cache_info)]);
-	if (CACHE_S(cache_info)) {
-		dump_cache("CPU: I cache", CACHE_ISIZE(cache_info));
-		dump_cache("CPU: D cache", CACHE_DSIZE(cache_info));
-	} else {
-		dump_cache("CPU: cache", CACHE_ISIZE(cache_info));
+	if (info != processor_id) {
+		printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(info)]);
+		if (CACHE_S(info)) {
+			dump_cache("CPU: I cache", CACHE_ISIZE(info));
+			dump_cache("CPU: D cache", CACHE_DSIZE(info));
+		} else {
+			dump_cache("CPU: cache", CACHE_ISIZE(info));
+		}
 	}
 }
 
 #else
-#define dump_cpu_cache_id() do { } while (0)
+#define dump_cpu_info() do { } while (0)
 #endif
 
 static void __init setup_processor(void)
@@ -255,7 +254,7 @@
 	       proc_info.manufacturer, proc_info.cpu_name,
 	       (int)processor_id & 15);
 
-	dump_cpu_cache_id();
+	dump_cpu_info();
 
 	sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
 	sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
diff -Nru a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
--- a/arch/arm/kernel/signal.c	Tue Oct 15 20:29:11 2002
+++ b/arch/arm/kernel/signal.c	Tue Oct 15 20:29:11 2002
@@ -59,11 +59,11 @@
 	sigset_t saveset;
 
 	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	regs->ARM_r0 = -EINTR;
 
 	while (1) {
@@ -87,11 +87,11 @@
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	current->blocked = newset;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	regs->ARM_r0 = -EINTR;
 
 	while (1) {
@@ -207,10 +207,10 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	if (restore_sigcontext(regs, &frame->sc))
 		goto badframe;
@@ -247,10 +247,10 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
 		goto badframe;
@@ -477,12 +477,12 @@
 			ka->sa.sa_handler = SIG_DFL;
 
 		if (!(ka->sa.sa_flags & SA_NODEFER)) {
-			spin_lock_irq(&tsk->sigmask_lock);
+			spin_lock_irq(&tsk->sig->siglock);
 			sigorsets(&tsk->blocked, &tsk->blocked,
 				  &ka->sa.sa_mask);
 			sigaddset(&tsk->blocked, sig);
 			recalc_sigpending();
-			spin_unlock_irq(&tsk->sigmask_lock);
+			spin_unlock_irq(&tsk->sig->siglock);
 		}
 		return;
 	}
@@ -520,20 +520,10 @@
 	for (;;) {
 		unsigned long signr = 0;
 		struct k_sigaction *ka;
-		sigset_t *mask = &current->blocked;
 
-		local_irq_disable();
-		if (current->sig->shared_pending.head) {
-			spin_lock(&current->sig->siglock);
-			signr = dequeue_signal(&current->sig->shared_pending, mask, &info);
-			spin_unlock(&current->sig->siglock);
-		}
-		if (!signr) {
-			spin_lock(&current->sigmask_lock);
-			signr = dequeue_signal(&current->pending, mask, &info);
-			spin_unlock(&current->sigmask_lock);
-		}
-		local_irq_enable();
+		spin_lock_irq(&current->sig->siglock);
+		signr = dequeue_signal(&current->blocked, &info);
+		spin_unlock_irq(&current->sig->siglock);
 
 		if (!signr)
 			break;
diff -Nru a/arch/arm/kernel/time-acorn.c b/arch/arm/kernel/time-acorn.c
--- a/arch/arm/kernel/time-acorn.c	Tue Oct 15 20:29:23 2002
+++ b/arch/arm/kernel/time-acorn.c	Tue Oct 15 20:29:23 2002
@@ -25,44 +25,37 @@
 
 static unsigned long ioctime_gettimeoffset(void)
 {
-	unsigned int count1, count2, status1, status2;
-	unsigned long offset = 0;
+	unsigned int count1, count2, status;
+	long offset;
 
-	status1 = ioc_readb(IOC_IRQREQA);
-	barrier ();
 	ioc_writeb (0, IOC_T0LATCH);
 	barrier ();
 	count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
 	barrier ();
-	status2 = ioc_readb(IOC_IRQREQA);
+	status = ioc_readb(IOC_IRQREQA);
 	barrier ();
 	ioc_writeb (0, IOC_T0LATCH);
 	barrier ();
 	count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8);
 
+	offset = count2;
 	if (count2 < count1) {
 		/*
-		 * This means that we haven't just had an interrupt
-		 * while reading into status2.
+		 * We have not had an interrupt between reading count1
+		 * and count2.
 		 */
-		if (status2 & (1 << 5))
-			offset = tick;
-		count1 = count2;
+		if (status & (1 << 5))
+			offset -= LATCH;
 	} else if (count2 > count1) {
 		/*
-		 * We have just had another interrupt while reading
-		 * status2.
+		 * We have just had another interrupt between reading
+		 * count1 and count2.
 		 */
-		offset += tick;
-		count1 = count2;
+		offset -= LATCH;
 	}
 
-	count1 = LATCH - count1;
-	/*
-	 * count1 = number of clock ticks since last interrupt
-	 */
-	offset += count1 * tick / LATCH;
-	return offset;
+	offset = (LATCH - offset) * (tick_nsec / 1000);
+	return (offset + LATCH/2) / LATCH;
 }
 
 void __init ioctime_init(void)
diff -Nru a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
--- a/arch/arm/kernel/time.c	Tue Oct 15 20:29:19 2002
+++ b/arch/arm/kernel/time.c	Tue Oct 15 20:29:19 2002
@@ -115,8 +115,8 @@
 	    time_before(xtime.tv_sec, next_rtc_update))
 		return;
 
-	if (xtime.tv_usec < 50000 - (tick >> 1) &&
-	    xtime.tv_usec >= 50000 + (tick >> 1))
+	if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) &&
+	    xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1))
 		return;
 
 	if (set_rtc())
@@ -166,7 +166,7 @@
 		usec += lost * USECS_PER_JIFFY;
 
 	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
+	usec += xtime.tv_nsec / 1000;
 	read_unlock_irqrestore(&xtime_lock, flags);
 
 	/* usec may have gone up a lot: be safe */
@@ -196,7 +196,8 @@
 		tv->tv_sec--;
 	}
 
-	xtime = *tv;
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_nsec = tv->tv_usec * 1000;
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
--- a/arch/arm/kernel/traps.c	Tue Oct 15 20:29:16 2002
+++ b/arch/arm/kernel/traps.c	Tue Oct 15 20:29:16 2002
@@ -32,6 +32,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
+#include <asm/semaphore.h>
 
 #include "ptrace.h"
 
@@ -77,8 +78,7 @@
 	fs = get_fs();
 	set_fs(KERNEL_DS);
 
-	printk("%s", str);
-	printk("(0x%08lx to 0x%08lx)\n", bottom, top);
+	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
 
 	for (p = bottom & ~31; p < top;) {
 		printk("%04lx: ", p & 0xffff);
@@ -136,7 +136,7 @@
 	set_fs(fs);
 }
 
-static void dump_stack(struct task_struct *tsk, unsigned long sp)
+static void __dump_stack(struct task_struct *tsk, unsigned long sp)
 {
 	dump_mem("Stack: ", sp, 8192+(unsigned long)tsk->thread_info);
 }
@@ -163,15 +163,20 @@
 }
 
 /*
- * This is called from SysRq-T (show_task) to display the current
- * call trace for each process.  Very useful.
+ * This is called from SysRq-T (show_task) to display the current call
+ * trace for each process.  This version will also display the running
+ * threads call trace (ie, us.)
  */
 void show_trace_task(struct task_struct *tsk)
 {
-	if (tsk != current) {
-		unsigned int fp = thread_saved_fp(tsk);
-		c_backtrace(fp, 0x10);
-	}
+	unsigned int fp;
+
+	if (tsk != current)
+		fp = thread_saved_fp(tsk);
+	else
+		asm("mov%? %0, fp" : "=r" (fp));
+
+	c_backtrace(fp, 0x10);
 }
 
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
@@ -193,7 +198,7 @@
 		current->comm, current->pid, tsk->thread_info + 1);
 
 	if (!user_mode(regs) || in_interrupt()) {
-		dump_stack(tsk, (unsigned long)(regs + 1));
+		__dump_stack(tsk, (unsigned long)(regs + 1));
 		dump_backtrace(regs, tsk);
 		dump_instr(regs);
 	}
diff -Nru a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
--- a/arch/arm/mach-integrator/cpu.c	Tue Oct 15 20:29:17 2002
+++ b/arch/arm/mach-integrator/cpu.c	Tue Oct 15 20:29:17 2002
@@ -73,36 +73,37 @@
  * Validate the speed in khz.  If it is outside our
  * range, then return the lowest.
  */
-static unsigned int
-integrator_validatespeed(unsigned int cpu, unsigned int freq_khz)
+static void integrator_verify_speed(struct cpufreq_policy *policy)
 {
 	struct vco vco;
 
-	if (freq_khz < 12000)
-		freq_khz = 12000;
-	if (freq_khz > 160000)
-		freq_khz = 160000;
+	if (policy->max > policy->max_cpu_freq)
+		policy->max = policy->max_cpu_freq;
 
-	vco = freq_to_vco(freq_khz, 1);
+	if (policy->max < 12000)
+		policy->max = 12000;
+	if (policy->max > 160000)
+		policy->max = 160000;
+
+	vco = freq_to_vco(policy->max, 1);
+
+	if (vco.vdw < 4)
+		vco.vdw = 4;
+	if (vco.vdw > 152)
+		vco.vdw = 152;
 
-	if (vco.vdw < 4 || vco.vdw > 152)
-		return -EINVAL;
-
-	return vco_to_freq(vco, 1);
+	policy->min = policy->max = vco_to_freq(vco, 1);
 }
 
-static void integrator_setspeed(unsigned int cpu, unsigned int freq_khz)
+static void do_set_policy(int cpu, struct cpufreq_policy *policy)
 {
-	struct vco vco = freq_to_vco(freq_khz, 1);
-	unsigned long cpus_allowed;
+	struct vco vco = freq_to_vco(policy->max, 1);
 	u_int cm_osc;
 
 	/*
-	 * Save this threads cpus_allowed mask, and bind to the
-	 * specified CPU.  When this call returns, we should be
-	 * running on the right CPU.
+	 * Bind to the specified CPU.  When this call returns,
+	 * we should be running on the right CPU.
 	 */
-	cpus_allowed = current->cpus_allowed;
 	set_cpus_allowed(current, 1 << cpu);
 	BUG_ON(cpu != smp_processor_id());
 
@@ -113,6 +114,26 @@
 	__raw_writel(0xa05f, CM_LOCK);
 	__raw_writel(cm_osc, CM_OSC);
 	__raw_writel(0, CM_LOCK);
+}
+
+static void integrator_set_policy(struct cpufreq_policy *policy)
+{
+	unsigned long cpus_allowed;
+	int cpu;
+
+	/*
+	 * Save this threads cpus_allowed mask.
+	 */
+	cpus_allowed = current->cpus_allowed;
+
+	if (policy->cpu == CPUFREQ_ALL_CPUS) {
+		for (cpu = 0; cpu < NR_CPUS; cpu++) {
+			if (!cpu_online(cpu))
+				continue;
+			do_set_policy(cpu, policy);
+		}
+	} else
+		do_set_policy(policy->cpu, policy);
 
 	/*
 	 * Restore the CPUs allowed mask.
@@ -120,23 +141,30 @@
 	set_cpus_allowed(current, cpus_allowed);
 }
 
+static struct cpufreq_policy integrator_policy = {
+	.cpu		= 0,
+	.policy		= CPUFREQ_POLICY_POWERSAVE,
+	.max_cpu_freq	= 160000,
+};
+
 static struct cpufreq_driver integrator_driver = {
-	.validate	= integrator_validatespeed,
-	.setspeed	= integrator_setspeed,
-	.sync		= 1,
+	.verify		= integrator_verify_speed,
+	.setpolicy	= integrator_set_policy,
+	.policy		= &integrator_policy,
+	.cpu_min_freq	= 12000,
 };
 #endif
 
 static int __init integrator_cpu_init(void)
 {
-	struct cpufreq_freqs *freqs;
+	struct cpufreq_policy *policies;
 	unsigned long cpus_allowed;
 	int cpu;
 
-	freqs = kmalloc(sizeof(struct cpufreq_freqs) * NR_CPUS,
-			GFP_KERNEL);
-	if (!freqs) {
-		printk(KERN_ERR "CPU: unable to allocate cpufreqs structure\n");
+	policies = kmalloc(sizeof(struct cpufreq_freqs) * NR_CPUS,
+			   GFP_KERNEL);
+	if (!policies) {
+		printk(KERN_ERR "CPU: unable to allocate policies structure\n");
 		return -ENOMEM;
 	}
 
@@ -164,18 +192,20 @@
 		vco.od = (cm_osc >> 8) & 7;
 		vco.vdw = cm_osc & 255;
 
-		freqs[cpu].min = 12000;
-		freqs[cpu].max = 160000;
-		freqs[cpu].cur = vco_to_freq(vco, 1);
+		policies[cpu].cpu = cpu;
+		policies[cpu].policy = CPUFREQ_POLICY_POWERSAVE,
+		policies[cpu].max_cpu_freq = 160000;
+		policies[cpu].min =
+		policies[cpu].max = vco_to_freq(vco, 1);
 	}
 
 	set_cpus_allowed(current, cpus_allowed);
 
 #ifdef CONFIG_CPU_FREQ
-	integrator_driver.freq = freqs;
+	integrator_driver.policy = policies;
 	cpufreq_register(&integrator_driver);
 #else
-	kfree(freqs);
+	kfree(policies);
 #endif
 
 	return 0;
diff -Nru a/arch/arm/mach-iop310/iop310-pci.c b/arch/arm/mach-iop310/iop310-pci.c
--- a/arch/arm/mach-iop310/iop310-pci.c	Tue Oct 15 20:29:16 2002
+++ b/arch/arm/mach-iop310/iop310-pci.c	Tue Oct 15 20:29:16 2002
@@ -145,7 +145,7 @@
 }
 
 static int
-iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where
+iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where,
 			int size, u32 value)
 {
 	unsigned long addr = iop310_cfg_address(bus, devfn, where);
@@ -163,7 +163,7 @@
 		else
 			val &= ~(0xffff << where);
 
-		*IOP310_POCCDR = val | v << where;
+		*IOP310_POCCDR = val | value << where;
 	} else {
 		asm volatile(
 			"str	%1, [%2]\n\t"
@@ -173,7 +173,7 @@
 			"nop\n\t"
 			"nop\n\t"
 			:
-			: "r" (val), "r" (addr),
+			: "r" (value), "r" (addr),
 			  "r" (IOP310_POCCAR), "r" (IOP310_POCCDR));
 	}
 
@@ -246,7 +246,7 @@
 }
 
 static int
-iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where
+iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where,
 			int size, u32 value)
 {
 	unsigned long addr = iop310_cfg_address(bus, devfn, where);
@@ -265,7 +265,7 @@
 		else
 			val &= ~(0xffff << where);
 
-		*IOP310_SOCCDR = val | v << where;
+		*IOP310_SOCCDR = val | value << where;
 	} else {
 		asm volatile(
 			"str	%1, [%2]\n\t"
@@ -275,7 +275,7 @@
 			"nop\n\t"
 			"nop\n\t"
 			:
-			: "r" (val), "r" (addr),
+			: "r" (value), "r" (addr),
 			  "r" (IOP310_SOCCAR), "r" (IOP310_SOCCDR));
 	}
 
diff -Nru a/arch/arm/mach-iop310/iq80310-time.c b/arch/arm/mach-iop310/iq80310-time.c
--- a/arch/arm/mach-iop310/iq80310-time.c	Tue Oct 15 20:29:19 2002
+++ b/arch/arm/mach-iop310/iq80310-time.c	Tue Oct 15 20:29:19 2002
@@ -85,7 +85,7 @@
 	/*
 	 * Now convert them to usec.
 	 */
-	usec = (unsigned long)(elapsed*tick)/LATCH;
+	usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
 
 	return usec;
 }
diff -Nru a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
--- a/arch/arm/mach-sa1100/Makefile	Tue Oct 15 20:29:23 2002
+++ b/arch/arm/mach-sa1100/Makefile	Tue Oct 15 20:29:23 2002
@@ -2,20 +2,17 @@
 # Makefile for the linux kernel.
 #
 
-# Common support (must be linked before board specific support)
+# Common support
 obj-y := generic.o irq.o dma.o
 obj-m :=
 obj-n :=
 obj-  :=
 led-y := leds.o
 
-export-objs :=	dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o \
-		usb_ctl.o usb_recv.o usb_send.o
+export-objs := dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o
 
 # This needs to be cleaned up.  We probably need to have SA1100
 # and SA1110 config symbols.
-#
-# We link the CPU support next, so that RAM timings can be tuned.
 ifeq ($(CONFIG_CPU_FREQ),y)
 obj-$(CONFIG_SA1100_ASSABET)		+= cpu-sa1110.o
 obj-$(CONFIG_SA1100_CERF)		+= cpu-sa1110.o
@@ -107,10 +104,7 @@
 obj-$(CONFIG_LEDS) += $(led-y)
 
 # SA1110 USB client support
-sa1100usb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o
-obj-$(CONFIG_SA1100_USB) += sa1100usb_core.o
-obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o
-obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o
+#obj-$(CONFIG_SA1100_USB)		+= usb/
 
 # Miscelaneous functions
 obj-$(CONFIG_PM) += pm.o sleep.o
diff -Nru a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
--- a/arch/arm/mach-sa1100/assabet.c	Tue Oct 15 20:29:11 2002
+++ b/arch/arm/mach-sa1100/assabet.c	Tue Oct 15 20:29:11 2002
@@ -302,21 +302,24 @@
 		 */
 		neponset_map_io();
 #endif
-		/*
-		 * When Neponset is attached, the first UART should be
-		 * UART3.  That's what Angel is doing and many documents
-		 * are stating this.
-		 * We do the Neponset mapping even if Neponset support
-		 * isn't compiled in so the user will still get something on
-		 * the expected physical serial port.
-		 */
-		sa1100_register_uart(0, 3);
-		sa1100_register_uart(2, 1);
 	} else {
 		sa1100_register_uart_fns(&assabet_port_fns);
-		sa1100_register_uart(0, 1);	/* com port */
-		sa1100_register_uart(2, 3);	/* radio module */
 	}
+
+	/*
+	 * When Neponset is attached, the first UART should be
+	 * UART3.  That's what Angel is doing and many documents
+	 * are stating this.
+	 *
+	 * We do the Neponset mapping even if Neponset support
+	 * isn't compiled in so the user will still get something on
+	 * the expected physical serial port.
+	 *
+	 * We no longer do this; not all boot loaders support it,
+	 * and UART3 appears to be somewhat unreliable with blob.
+	 */
+	sa1100_register_uart(0, 1);
+	sa1100_register_uart(2, 3);
 }
 
 
diff -Nru a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
--- a/arch/arm/mach-sa1100/generic.c	Tue Oct 15 20:29:15 2002
+++ b/arch/arm/mach-sa1100/generic.c	Tue Oct 15 20:29:15 2002
@@ -55,8 +55,8 @@
 
 	khz /= 100;
 
-	for (i = 0; i < ARRAY_SIZE(cclk_frequency_100khz); i--)
-		if (cclk_frequency_100khz[i] >= khz)
+	for (i = NR_FREQS - 1; i > 0; i--)
+		if (cclk_frequency_100khz[i] <= khz)
 			break;
 
 	return i;
diff -Nru a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
--- a/arch/arm/mach-sa1100/neponset.c	Tue Oct 15 20:29:17 2002
+++ b/arch/arm/mach-sa1100/neponset.c	Tue Oct 15 20:29:17 2002
@@ -193,20 +193,30 @@
 }
 
 static struct device_driver neponset_device_driver = {
-	.suspend = neponset_suspend,
-	.resume  = neponset_resume,
+	.name		= "NEPONSET",
+	.bus		= &system_bus_type,
+	.suspend	= neponset_suspend,
+	.resume		= neponset_resume,
 };
 
-static struct device neponset_device = {
-	.name	= "Neponset",
-	.bus_id	= "neponset",
-	.driver = &neponset_device_driver,
+static struct sys_device neponset_device = {
+	.name		= "NEPONSET",
+	.id		= 0,
+	.root		= NULL,
+	.dev = {
+		.name	= "Neponset",
+		.bus_id	= "neponset",
+		.bus	= &system_bus_type,
+		.driver = &neponset_device_driver,
+	},
 };
 
 static int __init neponset_init(void)
 {
 	int ret;
 
+	driver_register(&neponset_device_driver);
+
 	/*
 	 * The Neponset is only present on the Assabet machine type.
 	 */
@@ -231,7 +241,7 @@
 		return -ENODEV;
 	}
 
-	ret = register_sys_device(&neponset_device);
+	ret = sys_device_register(&neponset_device);
 	if (ret)
 		return ret;
 
@@ -256,7 +266,7 @@
 	return sa1111_init(0x40000000, IRQ_NEPONSET_SA1111);
 }
 
-arch_initcall(neponset_init);
+subsys_initcall(neponset_init);
 
 static struct map_desc neponset_io_desc[] __initdata = {
  /* virtual     physical    length type */
diff -Nru a/arch/arm/mach-sa1100/sa1111.c b/arch/arm/mach-sa1100/sa1111.c
--- a/arch/arm/mach-sa1100/sa1111.c	Tue Oct 15 20:29:16 2002
+++ b/arch/arm/mach-sa1100/sa1111.c	Tue Oct 15 20:29:16 2002
@@ -43,7 +43,7 @@
  * anchor point for all the other drivers.
  */
 struct sa1111 {
-	struct device	dev;
+	struct device	*dev;
 	struct resource	res;
 	int		irq;
 	spinlock_t	lock;
@@ -64,7 +64,7 @@
 	.devid		= SA1111_DEVID_USB,
 	.irq = {
 		IRQ_USBPWR,
-		IRQ_NHCIM,
+		IRQ_HCIM,
 		IRQ_HCIBUFFACC,
 		IRQ_HCIRMTWKP,
 		IRQ_NHCIMFCIR,
@@ -148,7 +148,6 @@
 	&ssp_dev,
 	&kbd_dev,
 	&mse_dev,
-	&int_dev,
 	&pcmcia_dev,
 };
 
@@ -158,7 +157,6 @@
 	0x0800,
 	SA1111_KBD,
 	SA1111_MSE,
-	SA1111_INTC,
 	0x1800,
 };
 
@@ -372,7 +370,106 @@
 	set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler);
 }
 
-static struct device_driver sa1111_device_driver;
+/*
+ * Bring the SA1111 out of reset.  This requires a set procedure:
+ *  1. nRESET asserted (by hardware)
+ *  2. CLK turned on from SA1110
+ *  3. nRESET deasserted
+ *  4. VCO turned on, PLL_BYPASS turned off
+ *  5. Wait lock time, then assert RCLKEn
+ *  7. PCR set to allow clocking of individual functions
+ *
+ * Until we've done this, the only registers we can access are:
+ *   SBI_SKCR
+ *   SBI_SMCR
+ *   SBI_SKID
+ */
+static void sa1111_wake(struct sa1111 *sachip)
+{
+	unsigned long flags, r;
+
+	spin_lock_irqsave(&sachip->lock, flags);
+
+	/*
+	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
+	 * (SA-1110 Developer's Manual, section 9.1.2.1)
+	 */
+	GAFR |= GPIO_32_768kHz;
+	GPDR |= GPIO_32_768kHz;
+	TUCR = TUCR_3_6864MHz;
+
+	/*
+	 * Turn VCO on, and disable PLL Bypass.
+	 */
+	r = sa1111_readl(sachip->base + SA1111_SKCR);
+	r &= ~SKCR_VCO_OFF;
+	sa1111_writel(r, sachip->base + SA1111_SKCR);
+	r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
+	sa1111_writel(r, sachip->base + SA1111_SKCR);
+
+	/*
+	 * Wait lock time.  SA1111 manual _doesn't_
+	 * specify a figure for this!  We choose 100us.
+	 */
+	udelay(100);
+
+	/*
+	 * Enable RCLK.  We also ensure that RDYEN is set.
+	 */
+	r |= SKCR_RCLKEN | SKCR_RDYEN;
+	sa1111_writel(r, sachip->base + SA1111_SKCR);
+
+	/*
+	 * Wait 14 RCLK cycles for the chip to finish coming out
+	 * of reset. (RCLK=24MHz).  This is 590ns.
+	 */
+	udelay(1);
+
+	/*
+	 * Ensure all clocks are initially off.
+	 */
+	sa1111_writel(0, sachip->base + SA1111_SKPCR);
+
+	spin_unlock_irqrestore(&sachip->lock, flags);
+}
+
+/*
+ * Configure the SA1111 shared memory controller.
+ */
+void
+sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
+		     unsigned int cas_latency)
+{
+	unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
+
+	if (cas_latency == 3)
+		smcr |= SMCR_CLAT;
+
+	sa1111_writel(smcr, sachip->base + SA1111_SMCR);
+}
+
+static void
+sa1111_init_one_child(struct sa1111 *sachip, struct sa1111_dev *sadev, unsigned int offset)
+{
+	snprintf(sadev->dev.bus_id, sizeof(sadev->dev.bus_id),
+		 "%4.4x", offset);
+
+	sadev->dev.parent = sachip->dev;
+	sadev->dev.bus    = &sa1111_bus_type;
+	sadev->res.start  = sachip->res.start + offset;
+	sadev->res.end    = sadev->res.start + 511;
+	sadev->res.name   = sadev->dev.name;
+	sadev->res.flags  = IORESOURCE_MEM;
+	sadev->mapbase    = sachip->base + offset;
+
+	if (request_resource(&sachip->res, &sadev->res)) {
+		printk("SA1111: failed to allocate resource for %s\n",
+			sadev->res.name);
+		return;
+	}
+
+	device_register(&sadev->dev);
+}
 
 /**
  *	sa1111_probe - probe for a single SA1111 chip.
@@ -387,11 +484,11 @@
  *	%0		successful.
  */
 static int __init
-sa1111_probe(unsigned long phys_addr, int irq)
+__sa1111_probe(struct device *me, unsigned long phys_addr, int irq)
 {
 	struct sa1111 *sachip;
 	unsigned long id;
-	unsigned int has_devs;
+	unsigned int has_devs, val;
 	int i, ret = -ENODEV;
 
 	sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL);
@@ -402,12 +499,10 @@
 
 	spin_lock_init(&sachip->lock);
 
-	strncpy(sachip->dev.name, "Intel Corporation SA1111", sizeof(sachip->dev.name));
-	snprintf(sachip->dev.bus_id, sizeof(sachip->dev.bus_id), "%8.8lx", phys_addr);
-	sachip->dev.driver = &sa1111_device_driver;
-	sachip->dev.driver_data = sachip;
+	sachip->dev = me;
+	dev_set_drvdata(sachip->dev, sachip);
 
-	sachip->res.name  = sachip->dev.name;
+	sachip->res.name  = me->name;
 	sachip->res.start = phys_addr;
 	sachip->res.end   = phys_addr + 0x2000;
 	sachip->irq = irq;
@@ -417,6 +512,10 @@
 		goto out;
 	}
 
+	/*
+	 * Map the whole region.  This also maps the
+	 * registers for our children.
+	 */
 	sachip->base = ioremap(phys_addr, PAGE_SIZE * 2);
 	if (!sachip->base) {
 		ret = -ENOMEM;
@@ -433,17 +532,47 @@
 		goto unmap;
 	}
 
-	/*
-	 * We found the chip.
-	 */
-	ret = register_sys_device(&sachip->dev);
-	if (ret)
-		printk("sa1111 device_register failed: %d\n", ret);
-
 	printk(KERN_INFO "SA1111 Microprocessor Companion Chip: "
 		"silicon revision %lx, metal revision %lx\n",
 		(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
 
+	/*
+	 * We found it.  Wake the chip up, and initialise.
+	 */
+	sa1111_wake(sachip);
+
+	/*
+	 * The SDRAM configuration of the SA1110 and the SA1111 must
+	 * match.  This is very important to ensure that SA1111 accesses
+	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
+	 * MBGNT signal, so we must have called sa1110_mb_disable()
+	 * beforehand.
+	 */
+	sa1111_configure_smc(sachip, 1,
+			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
+			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
+
+	/*
+	 * We only need to turn on DCLK whenever we want to use the
+	 * DMA.  It can otherwise be held firmly in the off position.
+	 * (currently, we always enable it.)
+	 */
+	val = sa1111_readl(sachip->base + SA1111_SKPCR);
+	sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR);
+
+	/*
+	 * Enable the SA1110 memory bus request and grant signals.
+	 */
+	sa1110_mb_enable();
+
+	/*
+	 * The interrupt controller must be initialised before any
+	 * other device to ensure that the interrupts are available.
+	 */
+	int_dev.irq[0] = irq;
+	sa1111_init_one_child(sachip, &int_dev, SA1111_INTC);
+	sa1111_init_irq(&int_dev);
+
 	g_sa1111 = sachip;
 
 	has_devs = ~0;
@@ -453,29 +582,9 @@
 	else
 		has_devs &= ~(1 << 1);
 
-	for (i = 0; i < ARRAY_SIZE(devs); i++) {
-		if (!(has_devs & (1 << i)))
-			continue;
-
-		snprintf(devs[i]->dev.bus_id, sizeof(devs[i]->dev.bus_id),
-			 "%4.4x", dev_offset[i]);
-
-		devs[i]->dev.parent = &sachip->dev;
-		devs[i]->dev.bus    = &sa1111_bus_type;
-		devs[i]->res.start  = sachip->res.start + dev_offset[i];
-		devs[i]->res.end    = devs[i]->res.start + 511;
-		devs[i]->res.name   = devs[i]->dev.name;
-		devs[i]->res.flags  = IORESOURCE_MEM;
-		devs[i]->mapbase    = sachip->base + dev_offset[i];
-
-		if (request_resource(&sachip->res, &devs[i]->res)) {
-			printk("SA1111: failed to allocate resource for %s\n",
-				devs[i]->res.name);
-			continue;
-		}
-
-		device_register(&devs[i]->dev);
-	}
+	for (i = 0; i < ARRAY_SIZE(devs); i++)
+		if (has_devs & (1 << i))
+			sa1111_init_one_child(sachip, devs[i], dev_offset[i]);
 
 	return 0;
 
@@ -503,84 +612,6 @@
 }
 
 /*
- * Bring the SA1111 out of reset.  This requires a set procedure:
- *  1. nRESET asserted (by hardware)
- *  2. CLK turned on from SA1110
- *  3. nRESET deasserted
- *  4. VCO turned on, PLL_BYPASS turned off
- *  5. Wait lock time, then assert RCLKEn
- *  7. PCR set to allow clocking of individual functions
- *
- * Until we've done this, the only registers we can access are:
- *   SBI_SKCR
- *   SBI_SMCR
- *   SBI_SKID
- */
-static void sa1111_wake(struct sa1111 *sachip)
-{
-	unsigned long flags, r;
-
-	spin_lock_irqsave(&sachip->lock, flags);
-
-	/*
-	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
-	 * (SA-1110 Developer's Manual, section 9.1.2.1)
-	 */
-	GAFR |= GPIO_32_768kHz;
-	GPDR |= GPIO_32_768kHz;
-	TUCR = TUCR_3_6864MHz;
-
-	/*
-	 * Turn VCO on, and disable PLL Bypass.
-	 */
-	r = sa1111_readl(sachip->base + SA1111_SKCR);
-	r &= ~SKCR_VCO_OFF;
-	sa1111_writel(r, sachip->base + SA1111_SKCR);
-	r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
-	sa1111_writel(r, sachip->base + SA1111_SKCR);
-
-	/*
-	 * Wait lock time.  SA1111 manual _doesn't_
-	 * specify a figure for this!  We choose 100us.
-	 */
-	udelay(100);
-
-	/*
-	 * Enable RCLK.  We also ensure that RDYEN is set.
-	 */
-	r |= SKCR_RCLKEN | SKCR_RDYEN;
-	sa1111_writel(r, sachip->base + SA1111_SKCR);
-
-	/*
-	 * Wait 14 RCLK cycles for the chip to finish coming out
-	 * of reset. (RCLK=24MHz).  This is 590ns.
-	 */
-	udelay(1);
-
-	/*
-	 * Ensure all clocks are initially off.
-	 */
-	sa1111_writel(0, sachip->base + SA1111_SKPCR);
-
-	spin_unlock_irqrestore(&sachip->lock, flags);
-}
-
-/*
- * Configure the SA1111 shared memory controller.
- */
-void
-sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
-		     unsigned int cas_latency)
-{
-	unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
-
-	if (cas_latency == 3)
-		smcr |= SMCR_CLAT;
-
-	sa1111_writel(smcr, sachip->base + SA1111_SMCR);
-}
-
-/*
  * According to the "Intel StrongARM SA-1111 Microprocessor Companion
  * Chip Specification Update" (June 2000), erratum #7, there is a
  * significant bug in the SA1111 SDRAM shared memory controller.  If
@@ -648,52 +679,6 @@
 	return 0;
 }
 
-int sa1111_init(unsigned long phys, unsigned int irq)
-{
-	unsigned int val;
-	int ret;
-
-	ret = sa1111_probe(phys, irq);
-	if (ret < 0)
-		return ret;
-
-	/*
-	 * We found it.  Wake the chip up.
-	 */
-	sa1111_wake(g_sa1111);
-
-	/*
-	 * The SDRAM configuration of the SA1110 and the SA1111 must
-	 * match.  This is very important to ensure that SA1111 accesses
-	 * don't corrupt the SDRAM.  Note that this ungates the SA1111's
-	 * MBGNT signal, so we must have called sa1110_mb_disable()
-	 * beforehand.
-	 */
-	sa1111_configure_smc(g_sa1111, 1,
-			     FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
-			     FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
-
-	/*
-	 * We only need to turn on DCLK whenever we want to use the
-	 * DMA.  It can otherwise be held firmly in the off position.
-	 */
-	val = sa1111_readl(g_sa1111->base + SA1111_SKPCR);
-	sa1111_writel(val | SKPCR_DCLKEN, g_sa1111->base + SA1111_SKPCR);
-
-	/*
-	 * Enable the SA1110 memory bus request and grant signals.
-	 */
-	sa1110_mb_enable();
-
-	/*
-	 * Initialise SA1111 IRQs
-	 */
-	int_dev.irq[0] = irq;
-	sa1111_init_irq(&int_dev);
-
-	return 0;
-}
-
 struct sa1111_save_data {
 	unsigned int	skcr;
 	unsigned int	skpcr;
@@ -717,7 +702,7 @@
 
 static int sa1111_suspend(struct device *dev, u32 state, u32 level)
 {
-	struct sa1111 *sachip = dev->driver_data;
+	struct sa1111 *sachip = dev_get_drvdata(dev);
 	unsigned long flags;
 	char *base;
 
@@ -789,7 +774,7 @@
  */
 static int sa1111_resume(struct device *dev, u32 level)
 {
-	struct sa1111 *sachip = dev->driver_data;
+	struct sa1111 *sachip = dev_get_drvdata(dev);
 	struct sa1111_save_data *save;
 	unsigned long flags, id;
 	char *base;
@@ -809,6 +794,7 @@
 	id = sa1111_readl(sachip->base + SA1111_SKID);
 	if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
 		__sa1111_remove(sachip);
+		dev_set_drvdata(dev, NULL);
 		kfree(save);
 		return 0;
 	}
@@ -840,18 +826,85 @@
 	return 0;
 }
 
+static int sa1111_probe(struct device *dev)
+{
+	return -ENODEV;
+}
+
+static int sa1111_remove(struct device *dev)
+{
+	struct sa1111 *sachip = dev_get_drvdata(dev);
+
+	if (sachip) {
+		__sa1111_remove(sachip);
+		dev_set_drvdata(dev, NULL);
+
+		kfree(dev->saved_state);
+		dev->saved_state = NULL;
+	}
+
+	return 0;
+}
+
+/*
+ *	Not sure if this should be on the system bus or not yet.
+ *	We really want some way to register a system device at
+ *	the per-machine level, and then have this driver pick
+ *	up the registered devices.
+ *
+ *	We also need to handle the SDRAM configuration for
+ *	PXA250/SA1110 machine classes.
+ */
 static struct device_driver sa1111_device_driver = {
+	.name		= "SA1111",
+	.bus		= &system_bus_type,
+	.probe		= sa1111_probe,
+	.remove		= sa1111_remove,
 	.suspend	= sa1111_suspend,
 	.resume		= sa1111_resume,
 };
 
 /*
+ *	Register the SA1111 driver with LDM.
+ */
+static int sa1111_driver_init(void)
+{
+	driver_register(&sa1111_device_driver);
+	return 0;
+}
+
+arch_initcall(sa1111_driver_init);
+
+static struct sys_device sa1111_device = {
+	.name		= "SA1111",
+	.id		= 0,
+	.root		= NULL,
+	.dev = {
+		.name	= "Intel Corporation SA1111",
+		.driver	= &sa1111_device_driver,
+	},
+};
+
+int sa1111_init(unsigned long phys, unsigned int irq)
+{
+	int ret;
+
+	snprintf(sa1111_device.dev.bus_id, sizeof(sa1111_device.dev.bus_id), "%8.8lx", phys);
+
+	ret = sys_device_register(&sa1111_device);
+	if (ret)
+		printk("sa1111 device_register failed: %d\n", ret);
+
+	return __sa1111_probe(&sa1111_device.dev, phys, irq);
+}
+
+/*
  *	Get the parent device driver (us) structure
  *	from a child function device
  */
 static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev)
 {
-	return (struct sa1111 *)sadev->dev.parent->driver_data;
+	return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent);
 }
 
 /*
diff -Nru a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
--- a/arch/arm/mm/fault-armv.c	Tue Oct 15 20:29:13 2002
+++ b/arch/arm/mm/fault-armv.c	Tue Oct 15 20:29:13 2002
@@ -16,8 +16,10 @@
 #include <linux/bitops.h>
 #include <linux/init.h>
 
+#include <asm/cacheflush.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
+#include <asm/tlbflush.h>
 
 #include "fault.h"
 
diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c
--- a/arch/arm/mm/init.c	Tue Oct 15 20:29:12 2002
+++ b/arch/arm/mm/init.c	Tue Oct 15 20:29:12 2002
@@ -519,6 +519,10 @@
 				bdata->node_boot_start >> PAGE_SHIFT, zhole_size);
 	}
 
+#ifndef CONFIG_DISCONTIGMEM
+	mem_map = contig_page_data.node_mem_map;
+#endif
+
 	/*
 	 * finish off the bad pages once
 	 * the mem_map is initialised
@@ -559,7 +563,9 @@
 	initpages = &__init_end - &__init_begin;
 
 	high_memory = (void *)__va(meminfo.end);
+#ifndef CONFIG_DISCONTIGMEM
 	max_mapnr   = virt_to_page(high_memory) - mem_map;
+#endif
 
 	/*
 	 * We may have non-contiguous memory.
diff -Nru a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c
--- a/arch/arm/mm/minicache.c	Tue Oct 15 20:29:19 2002
+++ b/arch/arm/mm/minicache.c	Tue Oct 15 20:29:19 2002
@@ -15,9 +15,11 @@
  */
 #include <linux/init.h>
 #include <linux/mm.h>
+
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
+#include <asm/tlbflush.h>
 
 /*
  * 0xffff8000 to 0xffffffff is reserved for any ARM architecture
diff -Nru a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
--- a/arch/arm/mm/mm-armv.c	Tue Oct 15 20:29:17 2002
+++ b/arch/arm/mm/mm-armv.c	Tue Oct 15 20:29:17 2002
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/highmem.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -20,6 +21,7 @@
 #include <asm/rmap.h>
 #include <asm/io.h>
 #include <asm/setup.h>
+#include <asm/tlbflush.h>
 
 #include <asm/mach/map.h>
 
@@ -213,6 +215,50 @@
 	pmd_clear(pmd_offset(pgd_offset_k(virt), virt));
 }
 
+struct mem_types {
+	unsigned int	prot_pte;
+	unsigned int	prot_sect;
+	unsigned int	domain;
+};
+
+static struct mem_types mem_types[] __initdata = {
+	[MT_DEVICE] = {
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_WRITE,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
+		.domain    = DOMAIN_IO,
+	},
+	[MT_CACHECLEAN] = {
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_CACHEABLE | L_PTE_BUFFERABLE,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE |
+				PMD_SECT_BUFFERABLE,
+		.domain    = DOMAIN_KERNEL,
+	},
+	[MT_MINICLEAN] = {
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_CACHEABLE,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE,
+		.domain    = DOMAIN_KERNEL,
+	},
+	[MT_VECTORS] = {
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_CACHEABLE | L_PTE_BUFFERABLE |
+				L_PTE_EXEC,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE |
+				PMD_SECT_BUFFERABLE,
+		.domain    = DOMAIN_USER,
+	},
+	[MT_MEMORY] = {
+		.prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+				L_PTE_CACHEABLE | L_PTE_BUFFERABLE |
+				L_PTE_EXEC | L_PTE_WRITE,
+		.prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE |
+				PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE,
+		.domain    = DOMAIN_KERNEL,
+	}
+};
+
 /*
  * Create the page directory entries and any necessary
  * page tables for the mapping specified by `md'.  We
@@ -232,42 +278,9 @@
 		return;
 	}
 
-	prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
-	prot_sect = PMD_TYPE_SECT;
-
-	switch (md->type) {
-	case MT_DEVICE:
-		prot_pte  |= L_PTE_WRITE;
-		prot_sect |= PMD_SECT_AP_WRITE;
-		domain     = DOMAIN_IO;
-		break;
-
-	case MT_CACHECLEAN:
-		prot_pte  |= L_PTE_CACHEABLE | L_PTE_BUFFERABLE;
-		prot_sect |= PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE;
-		domain     = DOMAIN_KERNEL;
-		break;
-
-	case MT_MINICLEAN:
-		prot_pte  |= L_PTE_CACHEABLE;
-		prot_sect |= PMD_SECT_CACHEABLE;
-		domain     = DOMAIN_KERNEL;
-		break;
-
-	case MT_VECTORS:
-		prot_pte  |= L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE;
-		prot_sect |= PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE;
-		domain     = DOMAIN_USER;
-		break;
-
-	case MT_MEMORY:
-		prot_pte  |= L_PTE_WRITE | L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE;
-		prot_sect |= PMD_SECT_AP_WRITE | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE;
-		domain     = DOMAIN_KERNEL;
-		break;
-	}
-
-	prot_sect |= PMD_DOMAIN(domain);
+	domain	  = mem_types[md->type].domain;
+	prot_pte  = mem_types[md->type].prot_pte;
+	prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
 
 	virt   = md->virtual;
 	off    = md->physical - virt;
diff -Nru a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
--- a/arch/arm/mm/proc-syms.c	Tue Oct 15 20:29:16 2002
+++ b/arch/arm/mm/proc-syms.c	Tue Oct 15 20:29:16 2002
@@ -10,8 +10,10 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 
+#include <asm/cacheflush.h>
 #include <asm/pgalloc.h>
 #include <asm/proc-fns.h>
+#include <asm/tlbflush.h>
 
 #ifndef MULTI_CPU
 EXPORT_SYMBOL(cpu_cache_clean_invalidate_all);
@@ -29,11 +31,11 @@
 EXPORT_SYMBOL(processor);
 #endif
 
-#ifndef MULTI_TLB
-EXPORT_SYMBOL_NOVERS(__cpu_flush_kern_tlb_all);
-EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_mm);
-EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_range);
-EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_page);
-#else
+/*
+ * No module should need to touch the TLB (and currently
+ * no modules do.  We export this for "loadkernel" support
+ * (booting a new kernel from within a running kernel.)
+ */
+#ifdef MULTI_TLB
 EXPORT_SYMBOL(cpu_tlb);
 #endif
diff -Nru a/arch/arm/mm/tlb-v3.S b/arch/arm/mm/tlb-v3.S
--- a/arch/arm/mm/tlb-v3.S	Tue Oct 15 20:29:11 2002
+++ b/arch/arm/mm/tlb-v3.S	Tue Oct 15 20:29:11 2002
@@ -13,32 +13,11 @@
  */
 #include <linux/linkage.h>
 #include <asm/constants.h>
+#include <asm/tlbflush.h>
 #include "proc-macros.S"
 
 	.align	5
 /*
- *	v3_flush_user_tlb_mm(mm)
- *
- *	Invalidate all TLB entries in a particular address space
- *
- *	- mm    - mm_struct describing address space
- */
-ENTRY(v3_flush_user_tlb_mm)
-	act_mm	r1				@ get current->active_mm
-	teq	r0, r1				@ == mm ?
-	movne	pc, lr				@ no, we dont do anything
-
-/*
- *	v3_flush_kern_tlb_all()
- *
- *	Invalidate the entire TLB
- */
-ENTRY(v3_flush_kern_tlb_all)
-	mov	r0, #0
-	mcr	p15, 0, r0, c5, c0, 0		@ invalidate TLB
-	mov	pc, lr
-
-/*
  *	v3_flush_user_tlb_range(start, end, mm)
  *
  *	Invalidate a range of TLB entries in the specified address space.
@@ -62,32 +41,11 @@
 	blo	1b
 	mov	pc, lr
 
-/*
- *	v3_flush_user_tlb_page(vaddr,vma)
- *
- *	Invalidate the specified page in the specified address space.
- *
- *	- vaddr - virtual address (may not be aligned)
- *	- vma   - vma_struct describing address range
- */
-	.align	5
-ENTRY(v3_flush_user_tlb_page)
-	vma_vm_mm r2, r1			@ get vma->vm_mm
-	act_mm	r3				@ get current->active_mm
-	teq	r2, r3				@ equal
-	movne	pc, lr				@ no
-ENTRY(v3_flush_kern_tlb_page)
-	mcr	p15, 0, r0, c6, c0, 0		@ invalidate TLB entry
-	mov	pc, lr
-
 	.section ".text.init", #alloc, #execinstr
 
 	.type	v3_tlb_fns, #object
 ENTRY(v3_tlb_fns)
-	.long	v3_flush_kern_tlb_all
-	.long	v3_flush_user_tlb_mm
 	.long	v3_flush_user_tlb_range
-	.long	v3_flush_user_tlb_page
 	.long	v3_flush_kern_tlb_range
-	.long	v3_flush_kern_tlb_page
+	.long	v3_tlb_flags
 	.size	v3_tlb_fns, . - v3_tlb_fns
diff -Nru a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S
--- a/arch/arm/mm/tlb-v4.S	Tue Oct 15 20:29:16 2002
+++ b/arch/arm/mm/tlb-v4.S	Tue Oct 15 20:29:16 2002
@@ -14,32 +14,11 @@
  */
 #include <linux/linkage.h>
 #include <asm/constants.h>
+#include <asm/tlbflush.h>
 #include "proc-macros.S"
 
 	.align	5
 /*
- *	v4_flush_user_tlb_mm(mm)
- *
- *	Invalidate all TLB entries in a particular address space
- *
- *	- mm    - mm_struct describing address space
- */
-ENTRY(v4_flush_user_tlb_mm)
-	act_mm	r1				@ get current->active_mm
-	teq	r0, r1				@ == mm ?
-	movne	pc, lr				@ no, we dont do anything
-
-/*
- *	v4_flush_kern_tlb_all()
- *
- *	Invalidate the entire TLB
- */
-ENTRY(v4_flush_kern_tlb_all)
-	mov	r0, #0
-	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
-	mov	pc, lr
-
-/*
  *	v4_flush_user_tlb_range(start, end, mm)
  *
  *	Invalidate a range of TLB entries in the specified user address space.
@@ -65,25 +44,6 @@
 	mov	pc, lr
 
 /*
- *	v4_flush_user_tlb_page(vaddr,vma)
- *
- *	Invalidate the specified page in the specified address space.
- *
- *	- vaddr - virtual address (may not be aligned)
- *	- vma   - vma_struct describing address range
- */
-	.align	5
-ENTRY(v4_flush_user_tlb_page)
-	vma_vm_mm r2, r1			@ get vma->vm_mm
-	act_mm	r3				@ get current->active_mm
-	teq	r2, r3				@ equal
-	movne	pc, lr				@ no
-	vma_vm_flags r2, r1
-.v4_flush_kern_tlb_page:
-	mcr	p15, 0, r0, c8, c7, 1		@ invalidate TLB entry
-	mov	pc, lr
-
-/*
  *	v4_flush_kerm_tlb_range(start, end)
  *
  *	Invalidate a range of TLB entries in the specified kernel
@@ -95,27 +55,11 @@
 .globl v4_flush_kern_tlb_range
 .equ v4_flush_kern_tlb_range, .v4_flush_kern_tlb_range
 
-
-/*
- *	v4_flush_kern_tlb_page(kaddr)
- *
- *	Invalidate the TLB entry for the specified page.  The address
- *	will be in the kernels virtual memory space.  Current uses
- *	only require the D-TLB to be invalidated.
- *
- *	- kaddr - Kernel virtual memory address
- */
-.globl v4_flush_kern_tlb_page
-.equ v4_flush_kern_tlb_page, .v4_flush_kern_tlb_page
-
 	.section ".text.init", #alloc, #execinstr
 
 	.type	v4_tlb_fns, #object
 ENTRY(v4_tlb_fns)
-	.long	v4_flush_kern_tlb_all
-	.long	v4_flush_user_tlb_mm
 	.long	v4_flush_user_tlb_range
-	.long	v4_flush_user_tlb_page
 	.long	v4_flush_kern_tlb_range
-	.long	v4_flush_kern_tlb_page
+	.long	v4_tlb_flags
 	.size	v4_tlb_fns, . - v4_tlb_fns
diff -Nru a/arch/arm/mm/tlb-v4wb.S b/arch/arm/mm/tlb-v4wb.S
--- a/arch/arm/mm/tlb-v4wb.S	Tue Oct 15 20:29:15 2002
+++ b/arch/arm/mm/tlb-v4wb.S	Tue Oct 15 20:29:15 2002
@@ -14,35 +14,11 @@
  */
 #include <linux/linkage.h>
 #include <asm/constants.h>
+#include <asm/tlbflush.h>
 #include "proc-macros.S"
 
 	.align	5
 /*
- *	v4wb_flush_user_tlb_mm(mm)
- *
- *	Invalidate all TLB entries in a particular address space
- *
- *	- mm    - mm_struct describing address space
- */
-ENTRY(v4wb_flush_user_tlb_mm)
-ENTRY(v4wbi_flush_user_tlb_mm)
-	act_mm	r1				@ get current->active_mm
-	teq	r0, r1				@ == mm ?
-	movne	pc, lr				@ no, we dont do anything
-
-/*
- *	v4wb_flush_tlb_all()
- *
- *	Invalidate the entire TLB
- */
-ENTRY(v4wb_flush_kern_tlb_all)
-ENTRY(v4wbi_flush_kern_tlb_all)
-	mov	r0, #0
-	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
-	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
-	mov	pc, lr
-
-/*
  *	v4wb_flush_user_tlb_range(start, end, mm)
  *
  *	Invalidate a range of TLB entries in the specified address space.
@@ -70,28 +46,6 @@
 	mov	pc, lr
 
 /*
- *	v4wb_flush_user_tlb_page(vaddr,vma)
- *
- *	Invalidate the specified page in the specified address space.
- *
- *	- vaddr - virtual address (may not be aligned)
- *	- vma   - vma_struct describing address range
- */
-	.align	5
-ENTRY(v4wb_flush_user_tlb_page)
-	vma_vm_mm r2, r1			@ get vma->vm_mm
-	act_mm	r3				@ get current->active_mm
-	teq	r2, r3				@ equal
-	movne	pc, lr				@ no
-	vma_vm_flags r2, r1
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-	tst	r2, #VM_EXEC
-	mcrne	p15, 0, r3, c8, c5, 0		@ invalidate I TLB
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mov	pc, lr
-
-/*
  *	v4_flush_kerm_tlb_range(start, end)
  *
  *	Invalidate a range of TLB entries in the specified kernel
@@ -113,20 +67,6 @@
 	mov	pc, lr
 
 /*
- *	v4_flush_kern_tlb_page(kaddr)
- *
- *	Invalidate the TLB entry for the specified page.  The address
- *	will be in the kernels virtual memory space.  Current uses
- *	only require the D-TLB to be invalidated.
- *
- *	- kaddr - Kernel virtual memory address
- */
-ENTRY(v4wb_flush_kern_tlb_page)
-	mcr	p15, 0, r3, c8, c5, 0		@ invalidate I TLB
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mov	pc, lr
-
-/*
  * These two are optimised for ARM920, ARM922, ARM926, Xscale
  */
 
@@ -158,28 +98,6 @@
 	blo	1b
 	mov	pc, lr
 
-/*
- *	v4wb_flush_tlb_page(vaddr,vma)
- *
- *	Invalidate the specified page in the specified address space.
- *
- *	- vaddr - virtual address (may not be aligned)
- *	- vma   - vma_struct describing address range
- */
-	.align	5
-ENTRY(v4wbi_flush_user_tlb_page)
-	vma_vm_mm r2, r1			@ get vma->vm_mm
-	act_mm	r3				@ get current->active_mm
-	teq	r2, r3				@ equal
-	movne	pc, lr				@ no
-	vma_vm_flags r2, r1
-	mov	r3, #0
-	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
-	tst	r2, #VM_EXEC
-	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mov	pc, lr
-
 ENTRY(v4wbi_flush_kern_tlb_range)
 	mov	r3, #0
 	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
@@ -192,29 +110,18 @@
 	blo	1b
 	mov	pc, lr
 
-ENTRY(v4wbi_flush_kern_tlb_page)
-	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
-	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
-	mov	pc, lr
-
 	.section ".text.init", #alloc, #execinstr
 
 	.type	v4wb_tlb_fns, #object
 ENTRY(v4wb_tlb_fns)
-	.long	v4wb_flush_kern_tlb_all
-	.long	v4wb_flush_user_tlb_mm
 	.long	v4wb_flush_user_tlb_range
-	.long	v4wb_flush_user_tlb_page
 	.long	v4wb_flush_kern_tlb_range
-	.long	v4wb_flush_kern_tlb_page
+	.long	v4wb_tlb_flags
 	.size	v4wb_tlb_fns, . - v4wb_tlb_fns
 
 	.type	v4wbi_tlb_fns, #object
 ENTRY(v4wbi_tlb_fns)
-	.long	v4wbi_flush_kern_tlb_all
-	.long	v4wbi_flush_user_tlb_mm
 	.long	v4wbi_flush_user_tlb_range
-	.long	v4wbi_flush_user_tlb_page
 	.long	v4wbi_flush_kern_tlb_range
-	.long	v4wbi_flush_kern_tlb_page
+	.long	v4wbi_tlb_flags
 	.size	v4wbi_tlb_fns, . - v4wbi_tlb_fns
diff -Nru a/arch/arm/vmlinux.lds.S b/arch/arm/vmlinux.lds.S
--- a/arch/arm/vmlinux.lds.S	Tue Oct 15 20:29:11 2002
+++ b/arch/arm/vmlinux.lds.S	Tue Oct 15 20:29:11 2002
@@ -4,13 +4,10 @@
 
 #ifdef CONFIG_ROM_KERNEL
 
-#define DATAADDR 0x02080000
-#define TEXTADDR 0x03800000
 #include "vmlinux-armo-rom.lds.in"
 
 #else
 
-#define TEXTADDR 0x02080000
 #include "vmlinux-armo.lds.in"
 
 #endif
@@ -19,7 +16,6 @@
 
 #ifdef CONFIG_CPU_32
 
-#define TEXTADDR 0xC0008000
 #include "vmlinux-armv.lds.in"
 
 #endif
diff -Nru a/arch/cris/drivers/examples/kiobuftest.c b/arch/cris/drivers/examples/kiobuftest.c
--- a/arch/cris/drivers/examples/kiobuftest.c	Tue Oct 15 20:29:22 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,111 +0,0 @@
-/*
- * Example showing how to pin down a range of virtual pages from user-space
- * to be able to do for example DMA directly into them.
- *
- * It is necessary because the pages the virtual pointers reference, might
- * not exist in memory (could be mapped to the zero-page, filemapped etc)
- * and DMA cannot trigger the MMU to force them in (and would have time 
- * contraints making it impossible to wait for it anyway).
- *
- * Author:  Bjorn Wesen
- *
- * $Log: kiobuftest.c,v $
- * Revision 1.1.1.1  2001/12/17 13:59:27  bjornw
- * Import of Linux 2.5.1
- *
- * Revision 1.2  2001/02/27 13:52:50  bjornw
- * malloc.h -> slab.h
- *
- * Revision 1.1  2001/01/19 15:57:49  bjornw
- * Example of how to do direct HW -> user-mode DMA
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/iobuf.h>
-
-#define KIOBUFTEST_MAJOR 124  /* in the local range, experimental */
-
-
-static ssize_t
-kiobuf_read(struct file *filp, char *buf, size_t len, loff_t *ppos)
-{
-
-     struct kiobuf *iobuf;
-     int res, i;
- 
-     /* Make a kiobuf that maps the entire length the reader has given
-      * us
-      */
-
-     res = alloc_kiovec(1, &iobuf);
-     if (res)
-	     return res;
-     
-     if((res = map_user_kiobuf(READ, iobuf, (unsigned long)buf, len))) {
-	     printk("map_user_kiobuf failed, return %d\n", res);
-	     return res;
-     }
-
-     /* At this point, the virtual area buf[0] -> buf[len-1] will
-      * have corresponding pages mapped in physical memory and locked
-      * until we unmap the kiobuf. They cannot be swapped out or moved
-      * around.
-      */
-
-     printk("nr_pages == %d\noffset == %d\nlength == %d\n",
-	    iobuf->nr_pages, iobuf->offset, iobuf->length);
-
-     for(i = 0; i < iobuf->nr_pages; i++) {
-	     printk("page_add(maplist[%d]) == 0x%x\n", i,
-		    page_address(iobuf->maplist[i]));
-     }
-
-     /* This is the place to create the necessary scatter-gather vector
-      * for the DMA using the iobuf->maplist array and page_address
-      * (don't forget __pa if the DMA needs the actual physical DRAM address)
-      * and run it.
-      */
-
-
-
-
-     /* Release the mapping and exit */
-
-     unmap_kiobuf(iobuf); /* The unlock_kiobuf is implicit here */
-
-     return len;
-}
-
-
-static struct file_operations kiobuf_fops = {
-	owner:    THIS_MODULE,
-	read:     kiobuf_read
-};
-
-static int __init
-kiobuftest_init(void)
-{
-	int res;
-
-	/* register char device */
-
-	res = register_chrdev(KIOBUFTEST_MAJOR, "kiobuftest", &kiobuf_fops);
-	if(res < 0) {
-		printk(KERN_ERR "kiobuftest: couldn't get a major number.\n");
-		return res;
-	}
-
-	printk("Initializing kiobuf-test device\n");
-}
-
-module_init(kiobuftest_init);
diff -Nru a/arch/i386/Config.help b/arch/i386/Config.help
--- a/arch/i386/Config.help	Tue Oct 15 20:29:12 2002
+++ b/arch/i386/Config.help	Tue Oct 15 20:29:12 2002
@@ -73,6 +73,12 @@
   If you are suffering from time skew using a multi-CEC system, say YES.
   Otherwise it is safe to say NO.
 
+CONFIG_X86_SUMMIT
+  This option is needed for IBM systems that use the Summit/EXA chipset.
+  In particular, it is needed for the x440.
+
+  If you don't have one of these computers, you should say N here.
+
 CONFIG_X86_UP_IOAPIC
   An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an
   SMP-capable replacement for PC-style interrupt controllers. Most
@@ -1048,6 +1054,11 @@
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
 
+Profiling support
+CONFIG_PROFILING
+  Say Y here to enable the extended profiling support mechanisms used
+  by profilers such as OProfile.
+ 
 Software Suspend
 CONFIG_SOFTWARE_SUSPEND
   Enable the possibilty of suspendig machine. It doesn't need APM.
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Tue Oct 15 20:29:16 2002
+++ b/arch/i386/Makefile	Tue Oct 15 20:29:16 2002
@@ -57,6 +57,8 @@
 					   arch/i386/$(MACHINE)/
 drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
 drivers-$(CONFIG_PCI)			+= arch/i386/pci/
+# FIXME: is drivers- right ?
+drivers-$(CONFIG_OPROFILE)		+= arch/i386/oprofile/
 
 CFLAGS += -Iarch/i386/$(MACHINE)
 AFLAGS += -Iarch/i386/$(MACHINE)
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Tue Oct 15 20:29:15 2002
+++ b/arch/i386/config.in	Tue Oct 15 20:29:15 2002
@@ -172,7 +172,8 @@
   if [ "$CONFIG_X86_NUMA" = "y" ]; then
      #Platform Choices
      bool 'Multiquad (IBM/Sequent) NUMAQ support' CONFIG_X86_NUMAQ
-     if [ "$CONFIG_X86_NUMAQ" = "y" ]; then
+     bool 'IBM x440 (Summit/EXA) support' CONFIG_X86_SUMMIT
+     if [ "$CONFIG_X86_NUMAQ" = "y" -o "$CONFIG_X86_SUMMIT" = "y" ]; then
         define_bool CONFIG_CLUSTERED_APIC y
      fi
      # Common NUMA Features
@@ -442,6 +443,8 @@
 
 source net/bluetooth/Config.in
 
+source arch/i386/oprofile/Config.in
+ 
 mainmenu_option next_comment
 comment 'Kernel hacking'
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Tue Oct 15 20:29:12 2002
+++ b/arch/i386/kernel/Makefile	Tue Oct 15 20:29:12 2002
@@ -27,6 +27,7 @@
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
+obj-$(CONFIG_PROFILING)		+= profile.o
 
 EXTRA_AFLAGS   := -traditional
 
diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
--- a/arch/i386/kernel/apic.c	Tue Oct 15 20:29:23 2002
+++ b/arch/i386/kernel/apic.c	Tue Oct 15 20:29:23 2002
@@ -31,6 +31,7 @@
 #include <asm/pgalloc.h>
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
+#include "mach_apic.h"
 
 void __init apic_intr_init(void)
 {
@@ -328,15 +329,13 @@
 		 * Put the APIC into flat delivery mode.
 		 * Must be "all ones" explicitly for 82489DX.
 		 */
-		apic_write_around(APIC_DFR, 0xffffffff);
+		apic_write_around(APIC_DFR, APIC_DFR_VALUE);
 
 		/*
 		 * Set up the logical destination ID.
 		 */
 		value = apic_read(APIC_LDR);
-		value &= ~APIC_LDR_MASK;
-		value |= (1<<(smp_processor_id()+24));
-		apic_write_around(APIC_LDR, value);
+		apic_write_around(APIC_LDR, calculate_ldr(value));
 	}
 
 	/*
@@ -1008,17 +1007,9 @@
 
 inline void smp_local_timer_interrupt(struct pt_regs * regs)
 {
-	int user = user_mode(regs);
 	int cpu = smp_processor_id();
 
-	/*
-	 * The profiling function is SMP safe. (nothing can mess
-	 * around with "current", and the profiling counters are
-	 * updated with atomic operations). This is especially
-	 * useful with a profiling multiplier != 1
-	 */
-	if (!user)
-		x86_do_profile(regs->eip);
+	x86_do_profile(regs);
 
 	if (--prof_counter[cpu] <= 0) {
 		/*
@@ -1036,7 +1027,7 @@
 		}
 
 #ifdef CONFIG_SMP
-		update_process_times(user);
+		update_process_times(user_mode(regs));
 #endif
 	}
 
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	Tue Oct 15 20:29:16 2002
+++ b/arch/i386/kernel/dmi_scan.c	Tue Oct 15 20:29:16 2002
@@ -31,7 +31,7 @@
 	if(!s)
 		return "";
 	s--;
-	while(s>0)
+	while(s>0 && *bp)
 	{
 		bp+=strlen(bp);
 		bp++;
@@ -50,7 +50,7 @@
 	u8 *buf;
 	struct dmi_header *dm;
 	u8 *data;
-	int i=1;
+	int i=0;
 		
 	buf = bt_ioremap(base, len);
 	if(buf==NULL)
@@ -59,28 +59,23 @@
 	data = buf;
 
 	/*
- 	 *	Stop when we see al the items the table claimed to have
+ 	 *	Stop when we see all the items the table claimed to have
  	 *	OR we run off the end of the table (also happens)
  	 */
  
-	while(i<num && (data - buf) < len)
+	while(i<num && data-buf+sizeof(struct dmi_header)<=len)
 	{
 		dm=(struct dmi_header *)data;
-	
 		/*
-		 *	Avoid misparsing crud if the length of the last
-	 	 *	record is crap 
+		 *  We want to know the total length (formated area and strings)
+		 *  before decoding to make sure we won't run off the table in
+		 *  dmi_decode or dmi_string
 		 */
-		if((data-buf+dm->length) >= len)
-			break;
-		decode(dm);		
 		data+=dm->length;
-		/*
-		 *	Don't go off the end of the data if there is
-	 	 *	stuff looking like string fill past the end
-	 	 */
-		while((data-buf) < len && (*data || data[1]))
+		while(data-buf<len-1 && (data[0] || data[1]))
 			data++;
+		if(data-buf<len-1)
+			decode(dm);
 		data+=2;
 		i++;
 	}
@@ -89,11 +84,20 @@
 }
 
 
+inline static int __init dmi_checksum(u8 *buf)
+{
+	u8 sum=0;
+	int a;
+	
+	for(a=0; a<15; a++)
+		sum+=buf[a];
+	return (sum==0);
+}
+
 static int __init dmi_iterate(void (*decode)(struct dmi_header *))
 {
-	unsigned char buf[20];
-	long fp=0xE0000L;
-	fp -= 16;
+	u8 buf[15];
+	u32 fp=0xF0000;
 
 #ifdef CONFIG_SIMNOW
 	/*
@@ -105,24 +109,30 @@
  	
 	while( fp < 0xFFFFF)
 	{
-		fp+=16;
-		isa_memcpy_fromio(buf, fp, 20);
-		if(memcmp(buf, "_DMI_", 5)==0)
+		isa_memcpy_fromio(buf, fp, 15);
+		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
 		{
 			u16 num=buf[13]<<8|buf[12];
 			u16 len=buf[7]<<8|buf[6];
 			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
 
-			dmi_printk((KERN_INFO "DMI %d.%d present.\n",
-				buf[14]>>4, buf[14]&0x0F));
+			/*
+			 * DMI version 0.0 means that the real version is taken from
+			 * the SMBIOS version, which we don't know at this point.
+			 */
+			if(buf[14]!=0)
+				dmi_printk((KERN_INFO "DMI %d.%d present.\n",
+					buf[14]>>4, buf[14]&0x0F));
+			else
+				dmi_printk((KERN_INFO "DMI present.\n"));
 			dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
-				buf[13]<<8|buf[12],
-				buf[7]<<8|buf[6]));
+				num, len));
 			dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
-				buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]));
+				base));
 			if(dmi_table(base,len, num, decode)==0)
 				return 0;
 		}
+		fp+=16;
 	}
 	return -1;
 }
@@ -823,59 +833,43 @@
 static void __init dmi_decode(struct dmi_header *dm)
 {
 	u8 *data = (u8 *)dm;
-	char *p;
 	
 	switch(dm->type)
 	{
 		case  0:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("BIOS Vendor: %s\n", p));
-				dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
-				dmi_printk(("BIOS Version: %s\n", 
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
-				dmi_printk(("BIOS Release: %s\n",
-					dmi_string(dm, data[8])));
-				dmi_save_ident(dm, DMI_BIOS_DATE, 8);
-			}
+			dmi_printk(("BIOS Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
+			dmi_printk(("BIOS Version: %s\n", 
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
+			dmi_printk(("BIOS Release: %s\n",
+				dmi_string(dm, data[8])));
+			dmi_save_ident(dm, DMI_BIOS_DATE, 8);
 			break;
-			
 		case 1:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("System Vendor: %s.\n",p));
-				dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
-				dmi_printk(("Product Name: %s.\n",
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
-				dmi_printk(("Version %s.\n",
-					dmi_string(dm, data[6])));
-				dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
-				dmi_printk(("Serial Number %s.\n",
-					dmi_string(dm, data[7])));
-			}
+			dmi_printk(("System Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
+			dmi_printk(("Product Name: %s\n",
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
+			dmi_printk(("Version: %s\n",
+				dmi_string(dm, data[6])));
+			dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
+			dmi_printk(("Serial Number: %s\n",
+				dmi_string(dm, data[7])));
 			break;
 		case 2:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("Board Vendor: %s.\n",p));
-				dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
-				dmi_printk(("Board Name: %s.\n",
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_BOARD_NAME, 5);
-				dmi_printk(("Board Version: %s.\n",
-					dmi_string(dm, data[6])));
-				dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
-			}
-			break;
-		case 3:
-			p=dmi_string(dm,data[8]);
-			if(*p && *p!=' ')
-				dmi_printk(("Asset Tag: %s.\n", p));
+			dmi_printk(("Board Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
+			dmi_printk(("Board Name: %s\n",
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_BOARD_NAME, 5);
+			dmi_printk(("Board Version: %s\n",
+				dmi_string(dm, data[6])));
+			dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
 			break;
 	}
 }
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Tue Oct 15 20:29:15 2002
+++ b/arch/i386/kernel/entry.S	Tue Oct 15 20:29:15 2002
@@ -736,6 +736,7 @@
 	.long sys_alloc_hugepages /* 250 */
 	.long sys_free_hugepages
 	.long sys_exit_group
+	.long sys_lookup_dcookie
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Tue Oct 15 20:29:23 2002
+++ b/arch/i386/kernel/i386_ksyms.c	Tue Oct 15 20:29:23 2002
@@ -29,6 +29,7 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
+#include <asm/nmi.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
@@ -151,6 +152,10 @@
 EXPORT_SYMBOL(flush_tlb_page);
 #endif
 
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM)
+EXPORT_SYMBOL_GPL(set_nmi_pm_callback);
+EXPORT_SYMBOL_GPL(unset_nmi_pm_callback);
+#endif
 #ifdef CONFIG_X86_IO_APIC
 EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
 #endif
@@ -167,6 +172,11 @@
 
 EXPORT_SYMBOL(rtc_lock);
 
+EXPORT_SYMBOL_GPL(register_profile_notifier);
+EXPORT_SYMBOL_GPL(unregister_profile_notifier);
+EXPORT_SYMBOL_GPL(set_nmi_callback);
+EXPORT_SYMBOL_GPL(unset_nmi_callback);
+ 
 #undef memcpy
 #undef memset
 extern void * memset(void *,int,__kernel_size_t);
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Tue Oct 15 20:29:15 2002
+++ b/arch/i386/kernel/io_apic.c	Tue Oct 15 20:29:15 2002
@@ -35,6 +35,7 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/desc.h>
+#include "mach_apic.h"
 
 #undef APIC_LOCKUP_DEBUG
 
@@ -1151,7 +1152,7 @@
 		
 		old_id = mp_ioapics[apic].mpc_apicid;
 
-		if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+		if (mp_ioapics[apic].mpc_apicid >= APIC_BROADCAST_ID) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
@@ -1164,7 +1165,8 @@
 		 * system must have a unique ID or we get lots of nice
 		 * 'stuck on smp_invalidate_needed IPI wait' messages.
 		 */
-		if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) {
+		if (check_apicid_used(phys_id_present_map,
+					mp_ioapics[apic].mpc_apicid)) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			for (i = 0; i < 0xf; i++)
diff -Nru a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
--- a/arch/i386/kernel/ldt.c	Tue Oct 15 20:29:19 2002
+++ b/arch/i386/kernel/ldt.c	Tue Oct 15 20:29:19 2002
@@ -20,10 +20,10 @@
 #include <asm/desc.h>
 
 #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
-static void flush_ldt(void *mm)
+static void flush_ldt(void *null)
 {
-	if (current->mm)
-		load_LDT(&current->mm->context);
+	if (current->active_mm)
+		load_LDT(&current->active_mm->context);
 }
 #endif
 
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Tue Oct 15 20:29:15 2002
+++ b/arch/i386/kernel/mpparse.c	Tue Oct 15 20:29:15 2002
@@ -30,6 +30,7 @@
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
 #include <asm/io_apic.h>
+#include "mach_apic.h"
 
 /* Have we found an MP table */
 int smp_found_config;
@@ -69,6 +70,9 @@
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
 
+int summit_x86 = 0;
+u8 raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+
 /*
  * Intel MP BIOS table parsing routines:
  */
@@ -189,7 +193,7 @@
 	if (clustered_apic_mode) {
 		phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad);
 	} else {
-		phys_cpu_present_map |= 1 << m->mpc_apicid;
+		phys_cpu_present_map |= apicid_to_cpu_present(m->mpc_apicid);
 	}
 	/*
 	 * Validate version
@@ -199,6 +203,7 @@
 		ver = 0x10;
 	}
 	apic_version[m->mpc_apicid] = ver;
+	raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
 }
 
 static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -356,6 +361,7 @@
 static int __init smp_read_mpc(struct mp_config_table *mpc)
 {
 	char str[16];
+	char oem[10];
 	int count=sizeof(*mpc);
 	unsigned char *mpt=((unsigned char *)mpc)+count;
 
@@ -380,14 +386,16 @@
 		printk(KERN_ERR "SMP mptable: null local APIC address!\n");
 		return 0;
 	}
-	memcpy(str,mpc->mpc_oem,8);
-	str[8]=0;
-	printk("OEM ID: %s ",str);
+	memcpy(oem,mpc->mpc_oem,8);
+	oem[8]=0;
+	printk("OEM ID: %s ",oem);
 
 	memcpy(str,mpc->mpc_productid,12);
 	str[12]=0;
 	printk("Product ID: %s ",str);
 
+	summit_check(oem, str);
+
 	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
 
 	/* 
@@ -465,6 +473,7 @@
 		}
 		++mpc_record;
 	}
+	clustered_apic_check();
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
--- a/arch/i386/kernel/nmi.c	Tue Oct 15 20:29:17 2002
+++ b/arch/i386/kernel/nmi.c	Tue Oct 15 20:29:17 2002
@@ -175,6 +175,18 @@
 	return 0;
 }
 
+struct pm_dev * set_nmi_pm_callback(pm_callback callback)
+{
+	apic_pm_unregister(nmi_pmdev);
+	return apic_pm_register(PM_SYS_DEV, 0, callback);
+}
+
+void unset_nmi_pm_callback(struct pm_dev * dev)
+{
+	apic_pm_unregister(dev);
+	nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback);
+}
+ 
 static void nmi_pm_init(void)
 {
 	if (!nmi_pmdev)
diff -Nru a/arch/i386/kernel/profile.c b/arch/i386/kernel/profile.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/profile.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,45 @@
+/*
+ *	linux/arch/i386/kernel/profile.c
+ *
+ *	(C) 2002 John Levon <levon@movementarian.org>
+ *
+ */
+
+#include <linux/profile.h>
+#include <linux/spinlock.h>
+#include <linux/notifier.h>
+#include <linux/irq.h>
+#include <asm/hw_irq.h> 
+ 
+static struct notifier_block * profile_listeners;
+static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
+ 
+int register_profile_notifier(struct notifier_block * nb)
+{
+	int err;
+	write_lock_irq(&profile_lock);
+	err = notifier_chain_register(&profile_listeners, nb);
+	write_unlock_irq(&profile_lock);
+	return err;
+}
+
+
+int unregister_profile_notifier(struct notifier_block * nb)
+{
+	int err;
+	write_lock_irq(&profile_lock);
+	err = notifier_chain_unregister(&profile_listeners, nb);
+	write_unlock_irq(&profile_lock);
+	return err;
+}
+
+
+void x86_profile_hook(struct pt_regs * regs)
+{
+	/* we would not even need this lock if
+	 * we had a global cli() on register/unregister
+	 */ 
+	read_lock(&profile_lock);
+	notifier_call_chain(&profile_listeners, 0, regs);
+	read_unlock(&profile_lock);
+}
diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c	Tue Oct 15 20:29:17 2002
+++ b/arch/i386/kernel/smpboot.c	Tue Oct 15 20:29:17 2002
@@ -51,6 +51,7 @@
 #include <asm/desc.h>
 #include <asm/arch_hooks.h>
 #include "smpboot_hooks.h"
+#include "mach_apic.h"
 
 /* Set if we find a B stepping CPU */
 static int __initdata smp_b_stepping;
diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c	Tue Oct 15 20:29:17 2002
+++ b/arch/i386/kernel/time.c	Tue Oct 15 20:29:17 2002
@@ -43,7 +43,6 @@
 #include <linux/smp.h>
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/cpufreq.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -64,11 +63,6 @@
 extern spinlock_t i8259A_lock;
 
 #include "do_timer.h"
-
-/*
- * for x86_do_profile()
- */
-#include <linux/irq.h>
 
 u64 jiffies_64;
 
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
--- a/arch/i386/kernel/timers/timer_tsc.c	Tue Oct 15 20:29:18 2002
+++ b/arch/i386/kernel/timers/timer_tsc.c	Tue Oct 15 20:29:19 2002
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/timex.h>
 #include <linux/errno.h>
+#include <linux/cpufreq.h>
 
 #include <asm/timer.h>
 #include <asm/io.h>
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Tue Oct 15 20:29:12 2002
+++ b/arch/i386/kernel/traps.c	Tue Oct 15 20:29:12 2002
@@ -40,6 +40,7 @@
 #include <asm/debugreg.h>
 #include <asm/desc.h>
 #include <asm/i387.h>
+#include <asm/nmi.h>
 
 #include <asm/smp.h>
 #include <asm/pgalloc.h>
@@ -478,17 +479,16 @@
 		return;
 	}
 #endif
-	printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
+	printk("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
+		reason, smp_processor_id());
 	printk("Dazed and confused, but trying to continue\n");
 	printk("Do you have a strange power saving mode enabled?\n");
 }
 
-asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+static void default_do_nmi(struct pt_regs * regs)
 {
 	unsigned char reason = inb(0x61);
-
-	++nmi_count(smp_processor_id());
-
+ 
 	if (!(reason & 0xc0)) {
 #if CONFIG_X86_LOCAL_APIC
 		/*
@@ -515,6 +515,33 @@
 	inb(0x71);		/* dummy */
 	outb(0x0f, 0x70);
 	inb(0x71);		/* dummy */
+}
+
+static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
+{
+	return 0;
+}
+ 
+static nmi_callback_t nmi_callback = dummy_nmi_callback;
+ 
+asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+{
+	int cpu = smp_processor_id();
+
+	++nmi_count(cpu);
+
+	if (!nmi_callback(regs, cpu))
+		default_do_nmi(regs);
+}
+
+void set_nmi_callback(nmi_callback_t callback)
+{
+	nmi_callback = callback;
+}
+
+void unset_nmi_callback(void)
+{
+	nmi_callback = dummy_nmi_callback;
 }
 
 /*
diff -Nru a/arch/i386/mach-generic/do_timer.h b/arch/i386/mach-generic/do_timer.h
--- a/arch/i386/mach-generic/do_timer.h	Tue Oct 15 20:29:21 2002
+++ b/arch/i386/mach-generic/do_timer.h	Tue Oct 15 20:29:21 2002
@@ -20,8 +20,7 @@
  * system, in that case we have to call the local interrupt handler.
  */
 #ifndef CONFIG_X86_LOCAL_APIC
-	if (!user_mode(regs))
-		x86_do_profile(regs->eip);
+	x86_do_profile(regs);
 #else
 	if (!using_apic_timer)
 		smp_local_timer_interrupt(regs);
diff -Nru a/arch/i386/mach-generic/mach_apic.h b/arch/i386/mach-generic/mach_apic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/mach_apic.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,46 @@
+#ifndef __ASM_MACH_APIC_H
+#define __ASM_MACH_APIC_H
+
+static inline unsigned long calculate_ldr(unsigned long old)
+{
+	unsigned long id;
+
+	id = 1UL << smp_processor_id();
+	return ((old & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(id));
+}
+
+#define APIC_DFR_VALUE	(APIC_DFR_FLAT)
+
+#ifdef CONFIG_SMP
+ #define TARGET_CPUS (clustered_apic_mode ? 0xf : cpu_online_map)
+#else
+ #define TARGET_CPUS 0x01
+#endif
+
+#define APIC_BROADCAST_ID      0x0F
+#define check_apicid_used(bitmap, apicid) (bitmap & (1 << apicid))
+
+static inline void summit_check(char *oem, char *productid) 
+{
+}
+
+static inline void clustered_apic_check(void)
+{
+	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
+		(clustered_apic_mode ? "NUMA-Q" : "Flat"), nr_ioapics);
+}
+
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+	if (clustered_apic_mode)
+		return ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) );
+	else
+		return mps_cpu;
+}
+
+static inline unsigned long apicid_to_cpu_present(int apicid)
+{
+	return (1ul << apicid);
+}
+
+#endif /* __ASM_MACH_APIC_H */
diff -Nru a/arch/i386/mach-summit/mach_apic.h b/arch/i386/mach-summit/mach_apic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-summit/mach_apic.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,57 @@
+#ifndef __ASM_MACH_APIC_H
+#define __ASM_MACH_APIC_H
+
+extern int x86_summit;
+
+#define XAPIC_DEST_CPUS_MASK    0x0Fu
+#define XAPIC_DEST_CLUSTER_MASK 0xF0u
+
+#define xapic_phys_to_log_apicid(phys_apic) ( (1ul << ((phys_apic) & 0x3)) |\
+		((phys_apic) & XAPIC_DEST_CLUSTER_MASK) )
+
+static inline unsigned long calculate_ldr(unsigned long old)
+{
+	unsigned long id;
+
+	if (x86_summit)
+		id = xapic_phys_to_log_apicid(hard_smp_processor_id());
+	else
+		id = 1UL << smp_processor_id();
+	return ((old & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(id));
+}
+
+#define APIC_DFR_VALUE	(x86_summit ? APIC_DFR_CLUSTER : APIC_DFR_FLAT)
+#define TARGET_CPUS	(x86_summit ? XAPIC_DEST_CPUS_MASK : cpu_online_map)
+
+#define APIC_BROADCAST_ID     (x86_summit ? 0xFF : 0x0F)
+#define check_apicid_used(bitmap, apicid) (0)
+
+static inline void summit_check(char *oem, char *productid)
+{
+	if (!strncmp(oem, "IBM ENSW", 8) && !strncmp(str, "VIGIL SMP", 9))
+		x86_summit = 1;
+}
+
+static inline void clustered_apic_check(void)
+{
+	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
+		(x86_summit ? "Summit" : "Flat"), nr_ioapics);
+}
+
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+	if (x86_summit)
+		return (int) raw_phys_apicid[mps_cpu];
+	else
+		return mps_cpu;
+}
+
+static inline unsigned long apicid_to_phys_cpu_present(int apicid)
+{
+	if (x86_summit)
+		return (1ul << (((apicid >> 4) << 2) | (apicid & 0x3)));
+	else
+		return (1ul << apicid);
+}
+
+#endif /* __ASM_MACH_APIC_H */
diff -Nru a/arch/i386/mach-visws/do_timer.h b/arch/i386/mach-visws/do_timer.h
--- a/arch/i386/mach-visws/do_timer.h	Tue Oct 15 20:29:15 2002
+++ b/arch/i386/mach-visws/do_timer.h	Tue Oct 15 20:29:15 2002
@@ -15,8 +15,7 @@
  * system, in that case we have to call the local interrupt handler.
  */
 #ifndef CONFIG_X86_LOCAL_APIC
-	if (!user_mode(regs))
-		x86_do_profile(regs->eip);
+	x86_do_profile(regs);
 #else
 	if (!using_apic_timer)
 		smp_local_timer_interrupt(regs);
diff -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
--- a/arch/i386/mm/discontig.c	Tue Oct 15 20:29:17 2002
+++ b/arch/i386/mm/discontig.c	Tue Oct 15 20:29:17 2002
@@ -70,6 +70,7 @@
 	node_datasz = PFN_UP(sizeof(struct pglist_data));
 	NODE_DATA(nid) = (pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT));
 	min_low_pfn += node_datasz;
+	memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
 }
 
 /*
diff -Nru a/arch/i386/oprofile/Config.help b/arch/i386/oprofile/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/Config.help	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,6 @@
+CONFIG_OPROFILE
+  OProfile is a profiling system capable of profiling the
+  whole system, include the kernel, kernel modules, libraries,
+  and applications.
+
+  If unsure, say N.
diff -Nru a/arch/i386/oprofile/Config.in b/arch/i386/oprofile/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/Config.in	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,9 @@
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   mainmenu_option next_comment
+   comment 'Profiling support'
+   bool 'Profiling support (EXPERIMENTAL)' CONFIG_PROFILING
+   if [ "$CONFIG_PROFILING" = "y" ]; then
+      tristate '  OProfile system profiling (EXPERIMENTAL)' CONFIG_OPROFILE
+   fi
+   endmenu
+fi
diff -Nru a/arch/i386/oprofile/Makefile b/arch/i386/oprofile/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/Makefile	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,16 @@
+vpath %.c = . $(TOPDIR)/drivers/oprofile
+
+obj-$(CONFIG_OPROFILE) += oprofile.o
+ 
+DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
+	oprof.o cpu_buffer.o buffer_sync.o \
+	event_buffer.o oprofile_files.o \
+	oprofilefs.o oprofile_stats.o )
+ 
+oprofile-objs := $(DRIVER_OBJS) init.o timer_int.o
+
+ifdef CONFIG_X86_LOCAL_APIC
+oprofile-objs += nmi_int.o op_model_athlon.o op_model_ppro.o
+endif
+ 
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/init.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,30 @@
+/**
+ * @file init.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/oprofile.h>
+#include <linux/init.h>
+ 
+/* We support CPUs that have performance counters like the Pentium Pro
+ * with NMI mode samples. Other x86 CPUs use a simple interrupt keyed
+ * off the timer interrupt, which cannot profile interrupts-disabled
+ * code unlike the NMI-based code.
+ */
+ 
+extern int nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
+extern void timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
+
+int __init oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	if (!nmi_init(ops, cpu))
+#endif
+		timer_init(ops, cpu);
+	return 0;
+}
diff -Nru a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/nmi_int.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,258 @@
+/**
+ * @file nmi_int.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/smp.h>
+#include <linux/oprofile.h>
+#include <linux/pm.h>
+#include <asm/thread_info.h>
+#include <asm/nmi.h>
+#include <asm/ptrace.h>
+#include <asm/msr.h>
+#include <asm/apic.h>
+#include <asm/bitops.h>
+#include <asm/processor.h>
+ 
+#include "op_counter.h"
+#include "op_x86_model.h"
+ 
+static struct op_x86_model_spec const * model;
+static struct op_msrs cpu_msrs[NR_CPUS];
+static unsigned long saved_lvtpc[NR_CPUS];
+static unsigned long kernel_only;
+ 
+static int nmi_start(void);
+static void nmi_stop(void);
+
+static struct pm_dev * oprofile_pmdev;
+ 
+/* We're at risk of causing big trouble unless we
+ * make sure to not cause any NMI interrupts when
+ * suspended.
+ */
+static int oprofile_pm_callback(struct pm_dev * dev,
+		pm_request_t rqst, void * data)
+{
+	switch (rqst) {
+		case PM_SUSPEND:
+			nmi_stop();
+			break;
+		case PM_RESUME:
+			nmi_start();
+			break;
+	}
+	return 0;
+}
+ 
+ 
+// FIXME: kernel_only
+static int nmi_callback(struct pt_regs * regs, int cpu)
+{
+	return (model->check_ctrs(cpu, &cpu_msrs[cpu], regs));
+}
+ 
+ 
+static void nmi_save_registers(struct op_msrs * msrs)
+{
+	unsigned int const nr_ctrs = model->num_counters;
+	unsigned int const nr_ctrls = model->num_controls; 
+	struct op_msr_group * counters = &msrs->counters;
+	struct op_msr_group * controls = &msrs->controls;
+	int i;
+
+	for (i = 0; i < nr_ctrs; ++i) {
+		rdmsr(counters->addrs[i],
+			counters->saved[i].low,
+			counters->saved[i].high);
+	}
+ 
+	for (i = 0; i < nr_ctrls; ++i) {
+		rdmsr(controls->addrs[i],
+			controls->saved[i].low,
+			controls->saved[i].high);
+	}
+}
+
+ 
+static void nmi_cpu_setup(void * dummy)
+{
+	int cpu = smp_processor_id();
+	struct op_msrs * msrs = &cpu_msrs[cpu];
+	model->fill_in_addresses(msrs);
+	nmi_save_registers(msrs);
+	spin_lock(&oprofilefs_lock);
+	model->setup_ctrs(msrs);
+	spin_unlock(&oprofilefs_lock);
+	saved_lvtpc[cpu] = apic_read(APIC_LVTPC);
+	apic_write(APIC_LVTPC, APIC_DM_NMI);
+}
+ 
+
+static int nmi_setup(void)
+{
+	/* We walk a thin line between law and rape here.
+	 * We need to be careful to install our NMI handler
+	 * without actually triggering any NMIs as this will
+	 * break the core code horrifically.
+	 */
+	smp_call_function(nmi_cpu_setup, NULL, 0, 1);
+	nmi_cpu_setup(0);
+	set_nmi_callback(nmi_callback);
+	oprofile_pmdev = set_nmi_pm_callback(oprofile_pm_callback);
+	return 0;
+}
+
+
+static void nmi_restore_registers(struct op_msrs * msrs)
+{
+	unsigned int const nr_ctrs = model->num_counters;
+	unsigned int const nr_ctrls = model->num_controls; 
+	struct op_msr_group * counters = &msrs->counters;
+	struct op_msr_group * controls = &msrs->controls;
+	int i;
+
+	for (i = 0; i < nr_ctrls; ++i) {
+		wrmsr(controls->addrs[i],
+			controls->saved[i].low,
+			controls->saved[i].high);
+	}
+ 
+	for (i = 0; i < nr_ctrs; ++i) {
+		wrmsr(counters->addrs[i],
+			counters->saved[i].low,
+			counters->saved[i].high);
+	}
+}
+ 
+
+static void nmi_cpu_shutdown(void * dummy)
+{
+	int cpu = smp_processor_id();
+	struct op_msrs * msrs = &cpu_msrs[cpu];
+	apic_write(APIC_LVTPC, saved_lvtpc[cpu]);
+	nmi_restore_registers(msrs);
+}
+
+ 
+static void nmi_shutdown(void)
+{
+	unset_nmi_pm_callback(oprofile_pmdev);
+	unset_nmi_callback();
+	smp_call_function(nmi_cpu_shutdown, NULL, 0, 1);
+	nmi_cpu_shutdown(0);
+}
+
+ 
+static void nmi_cpu_start(void * dummy)
+{
+	struct op_msrs const * msrs = &cpu_msrs[smp_processor_id()];
+	model->start(msrs);
+}
+ 
+
+static int nmi_start(void)
+{
+	smp_call_function(nmi_cpu_start, NULL, 0, 1);
+	nmi_cpu_start(0);
+	return 0;
+}
+ 
+ 
+static void nmi_cpu_stop(void * dummy)
+{
+	struct op_msrs const * msrs = &cpu_msrs[smp_processor_id()];
+	model->stop(msrs);
+}
+ 
+ 
+static void nmi_stop(void)
+{
+	smp_call_function(nmi_cpu_stop, NULL, 0, 1);
+	nmi_cpu_stop(0);
+}
+
+
+struct op_counter_config counter_config[OP_MAX_COUNTER];
+
+static int nmi_create_files(struct super_block * sb, struct dentry * root)
+{
+	int i;
+
+	for (i = 0; i < model->num_counters; ++i) {
+		struct dentry * dir;
+		char buf[2];
+ 
+		snprintf(buf, 2, "%d", i);
+		dir = oprofilefs_mkdir(sb, root, buf);
+		oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); 
+		oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); 
+		oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); 
+		oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); 
+		oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); 
+		oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); 
+	}
+
+	oprofilefs_create_ulong(sb, root, "kernel_only", &kernel_only);
+	return 0;
+}
+ 
+ 
+struct oprofile_operations nmi_ops = {
+	.create_files 	= nmi_create_files,
+	.setup 		= nmi_setup,
+	.shutdown	= nmi_shutdown,
+	.start		= nmi_start,
+	.stop		= nmi_stop
+};
+ 
+ 
+int __init nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+{
+	__u8 vendor = current_cpu_data.x86_vendor;
+	__u8 family = current_cpu_data.x86;
+	__u8 cpu_model = current_cpu_data.x86_model;
+ 
+	if (!cpu_has_apic)
+		return 0;
+ 
+	switch (vendor) {
+		case X86_VENDOR_AMD:
+			/* Needs to be at least an Athlon (or hammer in 32bit mode) */
+			if (family < 6)
+				return 0;
+			model = &op_athlon_spec;
+			*cpu = OPROFILE_CPU_ATHLON;
+			break;
+ 
+		case X86_VENDOR_INTEL:
+			/* Less than a P6-class processor */
+			if (family != 6)
+				return 0;
+	 
+			if (cpu_model > 5) {
+				*cpu = OPROFILE_CPU_PIII;
+			} else if (cpu_model > 2) {
+				*cpu = OPROFILE_CPU_PII;
+			} else {
+				*cpu = OPROFILE_CPU_PPRO;
+			}
+ 
+			model = &op_ppro_spec;
+			break;
+
+		default:
+			return 0;
+	}
+
+	*ops = &nmi_ops;
+	printk(KERN_INFO "oprofile: using NMI interrupt.\n");
+	return 1;
+}
diff -Nru a/arch/i386/oprofile/op_counter.h b/arch/i386/oprofile/op_counter.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/op_counter.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,29 @@
+/**
+ * @file op_counter.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ */
+ 
+#ifndef OP_COUNTER_H
+#define OP_COUNTER_H
+ 
+#define OP_MAX_COUNTER 4
+ 
+/* Per-perfctr configuration as set via
+ * oprofilefs.
+ */
+struct op_counter_config {
+        unsigned long count;
+        unsigned long enabled;
+        unsigned long event;
+        unsigned long kernel;
+        unsigned long user;
+        unsigned long unit_mask;
+};
+
+extern struct op_counter_config counter_config[];
+
+#endif /* OP_COUNTER_H */
diff -Nru a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/op_model_athlon.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,149 @@
+/**
+ * @file op_model_athlon.h
+ * athlon / K7 model-specific MSR operations
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ * @author Graydon Hoare
+ */
+
+#include <linux/oprofile.h>
+#include <asm/ptrace.h>
+#include <asm/msr.h>
+ 
+#include "op_x86_model.h"
+#include "op_counter.h"
+
+#define NUM_COUNTERS 4
+#define NUM_CONTROLS 4
+
+#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters.addrs[(c)], (l), (h));} while (0)
+#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters.addrs[(c)], -(unsigned int)(l), -1);} while (0)
+#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
+#define CTRL_READ(l,h,msrs,c) do {rdmsr(msrs->controls.addrs[(c)], (l), (h));} while (0)
+#define CTRL_WRITE(l,h,msrs,c) do {wrmsr(msrs->controls.addrs[(c)], (l), (h));} while (0)
+#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
+#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
+#define CTRL_CLEAR(x) (x &= (1<<21))
+#define CTRL_SET_ENABLE(val) (val |= 1<<20)
+#define CTRL_SET_USR(val,u) (val |= ((u & 1) << 16))
+#define CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17))
+#define CTRL_SET_UM(val, m) (val |= (m << 8))
+#define CTRL_SET_EVENT(val, e) (val |= e)
+
+static unsigned long reset_value[NUM_COUNTERS];
+ 
+static void athlon_fill_in_addresses(struct op_msrs * const msrs)
+{
+	msrs->counters.addrs[0] = MSR_K7_PERFCTR0;
+	msrs->counters.addrs[1] = MSR_K7_PERFCTR1;
+	msrs->counters.addrs[2] = MSR_K7_PERFCTR2;
+	msrs->counters.addrs[3] = MSR_K7_PERFCTR3;
+
+	msrs->controls.addrs[0] = MSR_K7_EVNTSEL0;
+	msrs->controls.addrs[1] = MSR_K7_EVNTSEL1;
+	msrs->controls.addrs[2] = MSR_K7_EVNTSEL2;
+	msrs->controls.addrs[3] = MSR_K7_EVNTSEL3;
+}
+
+ 
+static void athlon_setup_ctrs(struct op_msrs const * const msrs)
+{
+	unsigned int low, high;
+	int i;
+ 
+	/* clear all counters */
+	for (i = 0 ; i < NUM_CONTROLS; ++i) {
+		CTRL_READ(low, high, msrs, i);
+		CTRL_CLEAR(low);
+		CTRL_WRITE(low, high, msrs, i);
+	}
+	
+	/* avoid a false detection of ctr overflows in NMI handler */
+	for (i = 0; i < NUM_COUNTERS; ++i) {
+		CTR_WRITE(1, msrs, i);
+	}
+
+	/* enable active counters */
+	for (i = 0; i < NUM_COUNTERS; ++i) {
+		if (counter_config[i].event) {
+			reset_value[i] = counter_config[i].count;
+
+			CTR_WRITE(counter_config[i].count, msrs, i);
+
+			CTRL_READ(low, high, msrs, i);
+			CTRL_CLEAR(low);
+			CTRL_SET_ENABLE(low);
+			CTRL_SET_USR(low, counter_config[i].user);
+			CTRL_SET_KERN(low, counter_config[i].kernel);
+			CTRL_SET_UM(low, counter_config[i].unit_mask);
+			CTRL_SET_EVENT(low, counter_config[i].event);
+			CTRL_WRITE(low, high, msrs, i);
+		} else {
+			reset_value[i] = 0;
+		}
+	}
+}
+
+ 
+static int athlon_check_ctrs(unsigned int const cpu, 
+			      struct op_msrs const * const msrs, 
+			      struct pt_regs * const regs)
+{
+	unsigned int low, high;
+	int handled = 0;
+	int i;
+	for (i = 0 ; i < NUM_COUNTERS; ++i) {
+		CTR_READ(low, high, msrs, i);
+		if (CTR_OVERFLOWED(low)) {
+			oprofile_add_sample(regs->eip, i, cpu);
+			CTR_WRITE(reset_value[i], msrs, i);
+			handled = 1;
+		}
+	}
+	return handled;
+}
+
+ 
+static void athlon_start(struct op_msrs const * const msrs)
+{
+	unsigned int low, high;
+	int i;
+	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+		if (reset_value[i]) {
+			CTRL_READ(low, high, msrs, i);
+			CTRL_SET_ACTIVE(low);
+			CTRL_WRITE(low, high, msrs, i);
+		}
+	}
+}
+
+
+static void athlon_stop(struct op_msrs const * const msrs)
+{
+	unsigned int low,high;
+	int i;
+
+	/* Subtle: stop on all counters to avoid race with
+	 * setting our pm callback */
+	for (i = 0 ; i < NUM_COUNTERS ; ++i) {
+		CTRL_READ(low, high, msrs, i);
+		CTRL_SET_INACTIVE(low);
+		CTRL_WRITE(low, high, msrs, i);
+	}
+}
+
+
+struct op_x86_model_spec const op_athlon_spec = {
+	.num_counters = NUM_COUNTERS,
+	.num_controls = NUM_CONTROLS,
+	.fill_in_addresses = &athlon_fill_in_addresses,
+	.setup_ctrs = &athlon_setup_ctrs,
+	.check_ctrs = &athlon_check_ctrs,
+	.start = &athlon_start,
+	.stop = &athlon_stop
+};
diff -Nru a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/op_model_ppro.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,133 @@
+/**
+ * @file op_model_ppro.h
+ * pentium pro / P6 model-specific MSR operations
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author Philippe Elie
+ * @author Graydon Hoare
+ */
+
+#include <linux/oprofile.h>
+#include <asm/ptrace.h>
+#include <asm/msr.h>
+ 
+#include "op_x86_model.h"
+#include "op_counter.h"
+
+#define NUM_COUNTERS 2
+#define NUM_CONTROLS 2
+
+#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters.addrs[(c)], (l), (h));} while (0)
+#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters.addrs[(c)], -(u32)(l), -1);} while (0)
+#define CTR_OVERFLOWED(n) (!((n) & (1U<<31)))
+
+#define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls.addrs[(c)]), (l), (h));} while (0)
+#define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls.addrs[(c)]), (l), (h));} while (0)
+#define CTRL_SET_ACTIVE(n) (n |= (1<<22))
+#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22))
+#define CTRL_CLEAR(x) (x &= (1<<21))
+#define CTRL_SET_ENABLE(val) (val |= 1<<20)
+#define CTRL_SET_USR(val,u) (val |= ((u & 1) << 16))
+#define CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17))
+#define CTRL_SET_UM(val, m) (val |= (m << 8))
+#define CTRL_SET_EVENT(val, e) (val |= e)
+
+static unsigned long reset_value[NUM_COUNTERS];
+ 
+static void ppro_fill_in_addresses(struct op_msrs * const msrs)
+{
+	msrs->counters.addrs[0] = MSR_P6_PERFCTR0;
+	msrs->counters.addrs[1] = MSR_P6_PERFCTR1;
+	
+	msrs->controls.addrs[0] = MSR_P6_EVNTSEL0;
+	msrs->controls.addrs[1] = MSR_P6_EVNTSEL1;
+}
+
+
+static void ppro_setup_ctrs(struct op_msrs const * const msrs)
+{
+	unsigned int low, high;
+	int i;
+
+	/* clear all counters */
+	for (i = 0 ; i < NUM_CONTROLS; ++i) {
+		CTRL_READ(low, high, msrs, i);
+		CTRL_CLEAR(low);
+		CTRL_WRITE(low, high, msrs, i);
+	}
+	
+	/* avoid a false detection of ctr overflows in NMI handler */
+	for (i = 0; i < NUM_COUNTERS; ++i) {
+		CTR_WRITE(1, msrs, i);
+	}
+
+	/* enable active counters */
+	for (i = 0; i < NUM_COUNTERS; ++i) {
+		if (counter_config[i].event) {
+			reset_value[i] = counter_config[i].count;
+
+			CTR_WRITE(counter_config[i].count, msrs, i);
+
+			CTRL_READ(low, high, msrs, i);
+			CTRL_CLEAR(low);
+			CTRL_SET_ENABLE(low);
+			CTRL_SET_USR(low, counter_config[i].user);
+			CTRL_SET_KERN(low, counter_config[i].kernel);
+			CTRL_SET_UM(low, counter_config[i].unit_mask);
+			CTRL_SET_EVENT(low, counter_config[i].event);
+			CTRL_WRITE(low, high, msrs, i);
+		}
+	}
+}
+
+ 
+static int ppro_check_ctrs(unsigned int const cpu, 
+			    struct op_msrs const * const msrs,
+			    struct pt_regs * const regs)
+{
+	unsigned int low, high;
+	int i;
+	int handled = 0;
+ 
+	for (i = 0 ; i < NUM_COUNTERS; ++i) {
+		CTR_READ(low, high, msrs, i);
+		if (CTR_OVERFLOWED(low)) {
+			oprofile_add_sample(regs->eip, i, cpu);
+			CTR_WRITE(reset_value[i], msrs, i);
+			handled = 1;
+		}
+	}
+	return handled;
+}
+
+ 
+static void ppro_start(struct op_msrs const * const msrs)
+{
+	unsigned int low,high;
+	CTRL_READ(low, high, msrs, 0);
+	CTRL_SET_ACTIVE(low);
+	CTRL_WRITE(low, high, msrs, 0);
+}
+
+
+static void ppro_stop(struct op_msrs const * const msrs)
+{
+	unsigned int low,high;
+	CTRL_READ(low, high, msrs, 0);
+	CTRL_SET_INACTIVE(low);
+	CTRL_WRITE(low, high, msrs, 0);
+}
+
+
+struct op_x86_model_spec const op_ppro_spec = {
+	.num_counters = NUM_COUNTERS,
+	.num_controls = NUM_CONTROLS,
+	.fill_in_addresses = &ppro_fill_in_addresses,
+	.setup_ctrs = &ppro_setup_ctrs,
+	.check_ctrs = &ppro_check_ctrs,
+	.start = &ppro_start,
+	.stop = &ppro_stop
+};
diff -Nru a/arch/i386/oprofile/op_x86_model.h b/arch/i386/oprofile/op_x86_model.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/op_x86_model.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,52 @@
+/**
+ * @file op_x86_model.h
+ * interface to x86 model-specific MSR operations
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ */
+
+#ifndef OP_X86_MODEL_H
+#define OP_X86_MODEL_H
+
+/* will need re-working for Pentium IV */
+#define MAX_MSR 4
+ 
+struct op_saved_msr {
+	unsigned int high;
+	unsigned int low;
+};
+
+struct op_msr_group {
+	unsigned int addrs[MAX_MSR];
+	struct op_saved_msr saved[MAX_MSR];
+};
+
+struct op_msrs {
+	struct op_msr_group counters;
+	struct op_msr_group controls;
+};
+
+struct pt_regs;
+
+/* The model vtable abstracts the differences between
+ * various x86 CPU model's perfctr support.
+ */
+struct op_x86_model_spec {
+	unsigned int const num_counters;
+	unsigned int const num_controls;
+	void (*fill_in_addresses)(struct op_msrs * const msrs);
+	void (*setup_ctrs)(struct op_msrs const * const msrs);
+	int (*check_ctrs)(unsigned int const cpu, 
+		struct op_msrs const * const msrs,
+		struct pt_regs * const regs);
+	void (*start)(struct op_msrs const * const msrs);
+	void (*stop)(struct op_msrs const * const msrs);
+};
+
+extern struct op_x86_model_spec const op_ppro_spec;
+extern struct op_x86_model_spec const op_athlon_spec;
+
+#endif /* OP_X86_MODEL_H */
diff -Nru a/arch/i386/oprofile/timer_int.c b/arch/i386/oprofile/timer_int.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/oprofile/timer_int.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,57 @@
+/**
+ * @file timer_int.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <linux/oprofile.h>
+#include <asm/ptrace.h>
+ 
+#include "op_counter.h"
+ 
+static int timer_notify(struct notifier_block * self, unsigned long val, void * data)
+{
+	struct pt_regs * regs = (struct pt_regs *)data;
+	int cpu = smp_processor_id();
+ 
+	oprofile_add_sample(regs->eip, 0, cpu);
+	return 0;
+}
+ 
+ 
+static struct notifier_block timer_notifier = {
+	.notifier_call	= timer_notify,
+};
+ 
+
+static int timer_start(void)
+{
+	return register_profile_notifier(&timer_notifier);
+}
+
+
+static void timer_stop(void)
+{
+	unregister_profile_notifier(&timer_notifier);
+}
+
+
+static struct oprofile_operations timer_ops = {
+	.start	= timer_start,
+	.stop	= timer_stop
+};
+
+ 
+void __init timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+{
+	*ops = &timer_ops;
+	*cpu = OPROFILE_CPU_TIMER;
+	printk(KERN_INFO "oprofile: using timer interrupt.\n");
+}
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c	Tue Oct 15 20:29:17 2002
+++ b/arch/ia64/ia32/sys_ia32.c	Tue Oct 15 20:29:17 2002
@@ -1763,7 +1763,6 @@
 	struct msghdr msg_sys;
 	unsigned long cmsg_ptr;
 	int err, iov_size, total_len, len;
-	struct scm_cookie scm;
 
 	/* kernel mode address */
 	char addr[MAX_SOCK_ADDR];
@@ -1811,20 +1810,35 @@
 	if (sock->file->f_flags & O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
 
-	memset(&scm, 0, sizeof(scm));
-
+	/* XXX This code needs massive updating... -DaveM */
 	lock_kernel();
 	{
-		err = sock->ops->recvmsg(sock, &msg_sys, total_len, flags, &scm);
+		struct sock_iocb *si;
+		struct kiocb iocb;
+
+		init_sync_kiocb(&iocb, NULL);
+		si = kiocb_to_siocb(&iocb);
+		si->sock = sock;
+		si->scm = &si->async_scm;
+		si->msg = &msg_sys;
+		si->size = total_len;
+		si->flags = flags;
+		memset(si->scm, 0, sizeof(*si->scm));
+
+		err = sock->ops->recvmsg(&iocb, sock, &msg_sys, total_len,
+					 flags, si->scm);
+		if (-EIOCBQUEUED == err)
+			err = wait_on_sync_kiocb(&iocb);
+
 		if (err < 0)
 			goto out_unlock_freeiov;
 
 		len = err;
 		if (!msg_sys.msg_control) {
-			if (sock->passcred || scm.fp)
+			if (sock->passcred || si->scm->fp)
 				msg_sys.msg_flags |= MSG_CTRUNC;
-			if (scm.fp)
-				__scm_destroy(&scm);
+			if (si->scm->fp)
+				__scm_destroy(si->scm);
 		} else {
 			/*
 			 * If recvmsg processing itself placed some control messages into
@@ -1837,9 +1851,10 @@
 			/* Wheee... */
 			if (sock->passcred)
 				put_cmsg32(&msg_sys, SOL_SOCKET, SCM_CREDENTIALS,
-					   sizeof(scm.creds), &scm.creds);
-			if (scm.fp != NULL)
-				scm_detach_fds32(&msg_sys, &scm);
+					   sizeof(si->scm->creds),
+					   &si->scm->creds);
+			if (si->scm->fp != NULL)
+				scm_detach_fds32(&msg_sys, si->scm);
 		}
 	}
 	unlock_kernel();
diff -Nru a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c
--- a/arch/m68k/atari/stram.c	Tue Oct 15 20:29:19 2002
+++ b/arch/m68k/atari/stram.c	Tue Oct 15 20:29:19 2002
@@ -1021,8 +1021,6 @@
 		printk( KERN_NOTICE "Only kernel can open ST-RAM device\n" );
 		return( -EPERM );
 	}
-	if (MINOR(inode->i_rdev) != STRAM_MINOR)
-		return( -ENXIO );
 	if (refcnt)
 		return( -EBUSY );
 	++refcnt;
@@ -1057,7 +1055,7 @@
 	if (!max_swap_size)
 		/* swapping not enabled */
 		return -ENXIO;
-	stram_disk = alloc_disk();
+	stram_disk = alloc_disk(1);
 	if (!stram_disk)
 		return -ENOMEM;
 
@@ -1070,7 +1068,6 @@
 	blk_init_queue(BLK_DEFAULT_QUEUE(STRAM_MAJOR), do_stram_request);
 	stram_disk->major = STRAM_MAJOR;
 	stram_disk->first_minor = STRAM_MINOR;
-	stram_disk->minor_shift = 0;
 	stram_disk->fops = &stram_fops;
 	sprintf(stram_disk->disk_name, "stram");
 	set_capacity(stram_disk, (swap_end - swap_start)/512);
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	Tue Oct 15 20:29:19 2002
+++ b/arch/ppc64/kernel/sys_ppc32.c	Tue Oct 15 20:29:19 2002
@@ -3320,20 +3320,33 @@
 
 	sock = sockfd_lookup(fd, &err);
 	if (sock != NULL) {
-		struct scm_cookie scm;
+		struct sock_iocb *si;
+		struct kiocb iocb;
 
 		if (sock->file->f_flags & O_NONBLOCK)
 			user_flags |= MSG_DONTWAIT;
-		memset(&scm, 0, sizeof(scm));
-		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
-					 user_flags, &scm);
+
+		init_sync_kiocb(&iocb, NULL);
+		si = kiocb_to_siocb(&iocb);
+		si->sock = sock;
+		si->scm = &si->async_scm;
+		si->msg = &kern_msg;
+		si->size = total_len;
+		si->flags = user_flags;
+		memset(si->scm, 0, sizeof(*si->scm));
+
+		err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len,
+					 user_flags, si->scm);
+		if (-EIOCBQUEUED == err)
+			err = wait_on_sync_kiocb(&iocb);
+
 		if(err >= 0) {
 			len = err;
 			if(!kern_msg.msg_control) {
-				if(sock->passcred || scm.fp)
+				if(sock->passcred || si->scm->fp)
 					kern_msg.msg_flags |= MSG_CTRUNC;
-				if(scm.fp)
-					__scm_destroy(&scm);
+				if(si->scm->fp)
+					__scm_destroy(si->scm);
 			} else {
 				/* If recvmsg processing itself placed some
 				 * control messages into user space, it's is
@@ -3347,9 +3360,10 @@
 				if(sock->passcred)
 					put_cmsg32(&kern_msg,
 						   SOL_SOCKET, SCM_CREDENTIALS,
-						   sizeof(scm.creds), &scm.creds);
-				if(scm.fp != NULL)
-					scm_detach_fds32(&kern_msg, &scm);
+						   sizeof(si->scm->creds),
+						   &si->scm->creds);
+				if(si->scm->fp != NULL)
+					scm_detach_fds32(&kern_msg, si->scm);
 			}
 		}
 		sockfd_put(sock);
diff -Nru a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c
--- a/arch/s390x/kernel/linux32.c	Tue Oct 15 20:29:12 2002
+++ b/arch/s390x/kernel/linux32.c	Tue Oct 15 20:29:12 2002
@@ -2596,20 +2596,33 @@
 
 	sock = sockfd_lookup(fd, &err);
 	if (sock != NULL) {
-		struct scm_cookie scm;
+		struct sock_iocb *si;
+		struct kiocb iocb;
 
 		if (sock->file->f_flags & O_NONBLOCK)
 			user_flags |= MSG_DONTWAIT;
-		memset(&scm, 0, sizeof(scm));
-		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
-					 user_flags, &scm);
+
+		init_sync_kiocb(&iocb, NULL);
+		si = kiocb_to_siocb(&iocb);
+		si->sock = sock;
+		si->scm = &si->async_scm;
+		si->msg = &kern_msg;
+		si->size = total_len;
+		si->flags = user_flags;
+		memset(si->scm, 0, sizeof(*si->scm));
+
+		err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len,
+					 user_flags, si->scm);
+		if (-EIOCBQUEUED == err)
+			err = wait_on_sync_kiocb(&iocb);
+
 		if(err >= 0) {
 			len = err;
 			if(!kern_msg.msg_control) {
-				if(sock->passcred || scm.fp)
+				if(sock->passcred || si->scm->fp)
 					kern_msg.msg_flags |= MSG_CTRUNC;
-				if(scm.fp)
-					__scm_destroy(&scm);
+				if(si->scm->fp)
+					__scm_destroy(si->scm);
 			} else {
 				/* If recvmsg processing itself placed some
 				 * control messages into user space, it's is
@@ -2623,9 +2636,10 @@
 				if(sock->passcred)
 					put_cmsg32(&kern_msg,
 						   SOL_SOCKET, SCM_CREDENTIALS,
-						   sizeof(scm.creds), &scm.creds);
-				if(scm.fp != NULL)
-					scm_detach_fds32(&kern_msg, &scm);
+						   sizeof(si->scm->creds),
+						   &si->scm->creds);
+				if(si->scm->fp != NULL)
+					scm_detach_fds32(&kern_msg, si->scm);
 			}
 		}
 		sockfd_put(sock);
@@ -2746,6 +2760,8 @@
 	struct msghdr msg_sys;
 	unsigned long cmsg_ptr;
 	int err, iov_size, total_len, len;
+	struct sock_iocb *si;
+	struct kiocb iocb;
 
 	/* kernel mode address */
 	char addr[MAX_SOCK_ADDR];
@@ -2753,7 +2769,6 @@
 	/* user mode address pointers */
 	struct sockaddr *uaddr;
 	int *uaddr_len;
-	struct scm_cookie scm;
 	
 	err=-EFAULT;
 	if (msghdr_from_user32_to_kern(&msg_sys, msg))
@@ -2793,9 +2808,20 @@
 	
 	if (sock->file->f_flags & O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
-	memset(&scm, 0, sizeof(scm));
-	err = sock->ops->recvmsg(sock, &msg_sys, total_len,
-				 flags, &scm);
+
+	init_sync_kiocb(&iocb, NULL);
+	si = kiocb_to_siocb(&iocb);
+	si->sock = sock;
+	si->scm = &si->async_scm;
+	si->msg = &msg_sys;
+	si->size = total_len;
+	si->flags = flags;
+	memset(si->scm, 0, sizeof(*si->scm));
+
+	err = sock->ops->recvmsg(&iocb, sock, &msg_sys, total_len,
+				 flags, si->scm);
+	if (-EIOCBQUEUED == err)
+		err = wait_on_sync_kiocb(&iocb);
 	if (err < 0)
 		goto out_freeiov;
 	len = err;
@@ -2808,10 +2834,10 @@
 			goto out_freeiov;
 	}
 	if(!msg_sys.msg_control) {
-		if(sock->passcred || scm.fp)
+		if(sock->passcred || si->scm->fp)
 			msg_sys.msg_flags |= MSG_CTRUNC;
-		if(scm.fp)
-			__scm_destroy(&scm);
+		if(si->scm->fp)
+			__scm_destroy(si->scm);
 	} else {
 		/* If recvmsg processing itself placed some
 		 * control messages into user space, it's is
@@ -2824,9 +2850,9 @@
 		if(sock->passcred)
 			put_cmsg32(&msg_sys,
 				SOL_SOCKET, SCM_CREDENTIALS,
-				sizeof(scm.creds), &scm.creds);
-		if(scm.fp != NULL)
-			scm_detach_fds32(&msg_sys, &scm);
+				sizeof(si->scm->creds), &si->scm->creds);
+		if(si->scm->fp != NULL)
+			scm_detach_fds32(&msg_sys, si->scm);
 	}
 
 out_freeiov:
diff -Nru a/arch/sh/kernel/mach_7751se.c b/arch/sh/kernel/mach_7751se.c
--- a/arch/sh/kernel/mach_7751se.c	Tue Oct 15 20:29:17 2002
+++ b/arch/sh/kernel/mach_7751se.c	Tue Oct 15 20:29:17 2002
@@ -27,52 +27,52 @@
  */
 
 struct sh_machine_vector mv_7751se __initmv = {
-	mv_name:		"7751 SolutionEngine",
+	.mv_name		= "7751 SolutionEngine",
 
-	mv_nr_irqs:		72,
+	.mv_nr_irqs		= 72,
 
-	mv_inb:			sh7751se_inb,
-	mv_inw:			sh7751se_inw,
-	mv_inl:			sh7751se_inl,
-	mv_outb:		sh7751se_outb,
-	mv_outw:		sh7751se_outw,
-	mv_outl:		sh7751se_outl,
-
-	mv_inb_p:		sh7751se_inb_p,
-	mv_inw_p:		sh7751se_inw,
-	mv_inl_p:		sh7751se_inl,
-	mv_outb_p:		sh7751se_outb_p,
-	mv_outw_p:		sh7751se_outw,
-	mv_outl_p:		sh7751se_outl,
-
-	mv_insb:		sh7751se_insb,
-	mv_insw:		sh7751se_insw,
-	mv_insl:		sh7751se_insl,
-	mv_outsb:		sh7751se_outsb,
-	mv_outsw:		sh7751se_outsw,
-	mv_outsl:		sh7751se_outsl,
-
-	mv_readb:		sh7751se_readb,
-	mv_readw:		sh7751se_readw,
-	mv_readl:		sh7751se_readl,
-	mv_writeb:		sh7751se_writeb,
-	mv_writew:		sh7751se_writew,
-	mv_writel:		sh7751se_writel,
+	.mv_inb			= sh7751se_inb,
+	.mv_inw			= sh7751se_inw,
+	.mv_inl			= sh7751se_inl,
+	.mv_outb		= sh7751se_outb,
+	.mv_outw		= sh7751se_outw,
+	.mv_outl		= sh7751se_outl,
+
+	.mv_inb_p		= sh7751se_inb_p,
+	.mv_inw_p		= sh7751se_inw,
+	.mv_inl_p		= sh7751se_inl,
+	.mv_outb_p		= sh7751se_outb_p,
+	.mv_outw_p		= sh7751se_outw,
+	.mv_outl_p		= sh7751se_outl,
+
+	.mv_insb		= sh7751se_insb,
+	.mv_insw		= sh7751se_insw,
+	.mv_insl		= sh7751se_insl,
+	.mv_outsb		= sh7751se_outsb,
+	.mv_outsw		= sh7751se_outsw,
+	.mv_outsl		= sh7751se_outsl,
+
+	.mv_readb		= sh7751se_readb,
+	.mv_readw		= sh7751se_readw,
+	.mv_readl		= sh7751se_readl,
+	.mv_writeb		= sh7751se_writeb,
+	.mv_writew		= sh7751se_writew,
+	.mv_writel		= sh7751se_writel,
 
-	mv_ioremap:		generic_ioremap,
-	mv_iounmap:		generic_iounmap,
+	.mv_ioremap		= generic_ioremap,
+	.mv_iounmap		= generic_iounmap,
 
-	mv_isa_port2addr:	sh7751se_isa_port2addr,
+	.mv_isa_port2addr	= sh7751se_isa_port2addr,
 
-	mv_init_arch:		setup_7751se,
-	mv_init_irq:		init_7751se_IRQ,
+	.mv_init_arch		= setup_7751se,
+	.mv_init_irq		= init_7751se_IRQ,
 #ifdef CONFIG_HEARTBEAT
-	mv_heartbeat:		heartbeat_7751se,
+	.mv_heartbeat		= heartbeat_7751se,
 #endif
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 
-	mv_hw_7751se:		1,
+	.mv_hw_7751se		= 1,
 };
 ALIAS_MV(7751se)
diff -Nru a/arch/sh/kernel/mach_adx.c b/arch/sh/kernel/mach_adx.c
--- a/arch/sh/kernel/mach_adx.c	Tue Oct 15 20:29:17 2002
+++ b/arch/sh/kernel/mach_adx.c	Tue Oct 15 20:29:17 2002
@@ -25,49 +25,49 @@
  */
 
 struct sh_machine_vector mv_adx __initmv = {
-	mv_name:		"A&D_ADX",
+	.mv_name		= "A&D_ADX",
 
-	mv_nr_irqs:		48,
+	.mv_nr_irqs		= 48,
 
-	mv_inb:			adx_inb,
-	mv_inw:			adx_inw,
-	mv_inl:			adx_inl,
-	mv_outb:		adx_outb,
-	mv_outw:		adx_outw,
-	mv_outl:		adx_outl,
-
-	mv_inb_p:		adx_inb_p,
-	mv_inw_p:		adx_inw,
-	mv_inl_p:		adx_inl,
-	mv_outb_p:		adx_outb_p,
-	mv_outw_p:		adx_outw,
-	mv_outl_p:		adx_outl,
-
-	mv_insb:		adx_insb,
-	mv_insw:		adx_insw,
-	mv_insl:		adx_insl,
-	mv_outsb:		adx_outsb,
-	mv_outsw:		adx_outsw,
-	mv_outsl:		adx_outsl,
-
-	mv_readb:		adx_readb,
-	mv_readw:		adx_readw,
-	mv_readl:		adx_readl,
-	mv_writeb:		adx_writeb,
-	mv_writew:		adx_writew,
-	mv_writel:		adx_writel,
-
-	mv_ioremap:		adx_ioremap,
-	mv_iounmap:		adx_iounmap,
-
-	mv_isa_port2addr:	adx_isa_port2addr,
+	.mv_inb			= adx_inb,
+	.mv_inw			= adx_inw,
+	.mv_inl			= adx_inl,
+	.mv_outb		= adx_outb,
+	.mv_outw		= adx_outw,
+	.mv_outl		= adx_outl,
+
+	.mv_inb_p		= adx_inb_p,
+	.mv_inw_p		= adx_inw,
+	.mv_inl_p		= adx_inl,
+	.mv_outb_p		= adx_outb_p,
+	.mv_outw_p		= adx_outw,
+	.mv_outl_p		= adx_outl,
+
+	.mv_insb		= adx_insb,
+	.mv_insw		= adx_insw,
+	.mv_insl		= adx_insl,
+	.mv_outsb		= adx_outsb,
+	.mv_outsw		= adx_outsw,
+	.mv_outsl		= adx_outsl,
+
+	.mv_readb		= adx_readb,
+	.mv_readw		= adx_readw,
+	.mv_readl		= adx_readl,
+	.mv_writeb		= adx_writeb,
+	.mv_writew		= adx_writew,
+	.mv_writel		= adx_writel,
+
+	.mv_ioremap		= adx_ioremap,
+	.mv_iounmap		= adx_iounmap,
+
+	.mv_isa_port2addr	= adx_isa_port2addr,
 
-	mv_init_arch:		setup_adx,
-	mv_init_irq:		init_adx_IRQ,
+	.mv_init_arch		= setup_adx,
+	.mv_init_irq		= init_adx_IRQ,
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 
-	mv_hw_adx:		1,
+	.mv_hw_adx		= 1,
 };
 ALIAS_MV(adx)
diff -Nru a/arch/sh/kernel/mach_bigsur.c b/arch/sh/kernel/mach_bigsur.c
--- a/arch/sh/kernel/mach_bigsur.c	Tue Oct 15 20:29:19 2002
+++ b/arch/sh/kernel/mach_bigsur.c	Tue Oct 15 20:29:19 2002
@@ -29,49 +29,49 @@
 extern void init_bigsur_IRQ(void);
 
 struct sh_machine_vector mv_bigsur __initmv = {
-	mv_name:		"Big Sur",
-	mv_nr_irqs:		NR_IRQS,     // Defined in <asm/irq.h>
-	mv_inb:			bigsur_inb,
-	mv_inw:			bigsur_inw,
-	mv_inl:			bigsur_inl,
-	mv_outb:		bigsur_outb,
-	mv_outw:		bigsur_outw,
-	mv_outl:		bigsur_outl,
-
-	mv_inb_p:		bigsur_inb_p,
-	mv_inw_p:		bigsur_inw,
-	mv_inl_p:		bigsur_inl,
-	mv_outb_p:		bigsur_outb_p,
-	mv_outw_p:		bigsur_outw,
-	mv_outl_p:		bigsur_outl,
-
-	mv_insb:		bigsur_insb,
-	mv_insw:		bigsur_insw,
-	mv_insl:		bigsur_insl,
-	mv_outsb:		bigsur_outsb,
-	mv_outsw:		bigsur_outsw,
-	mv_outsl:		bigsur_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
+	.mv_name		= "Big Sur",
+	.mv_nr_irqs		= NR_IRQS,     // Defined in <asm/irq.h>
+	.mv_inb			= bigsur_inb,
+	.mv_inw			= bigsur_inw,
+	.mv_inl			= bigsur_inl,
+	.mv_outb		= bigsur_outb,
+	.mv_outw		= bigsur_outw,
+	.mv_outl		= bigsur_outl,
+
+	.mv_inb_p		= bigsur_inb_p,
+	.mv_inw_p		= bigsur_inw,
+	.mv_inl_p		= bigsur_inl,
+	.mv_outb_p		= bigsur_outb_p,
+	.mv_outw_p		= bigsur_outw,
+	.mv_outl_p		= bigsur_outl,
+
+	.mv_insb		= bigsur_insb,
+	.mv_insw		= bigsur_insw,
+	.mv_insl		= bigsur_insl,
+	.mv_outsb		= bigsur_outsb,
+	.mv_outsw		= bigsur_outsw,
+	.mv_outsl		= bigsur_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
 
-	mv_ioremap:		generic_ioremap,
-	mv_iounmap:		generic_iounmap,
+	.mv_ioremap		= generic_ioremap,
+	.mv_iounmap		= generic_iounmap,
 
-	mv_isa_port2addr:	bigsur_isa_port2addr,
-	mv_irq_demux:       bigsur_irq_demux,
+	.mv_isa_port2addr	= bigsur_isa_port2addr,
+	.mv_irq_demux       = bigsur_irq_demux,
 
-	mv_init_arch:		setup_bigsur,
-	mv_init_irq:		init_bigsur_IRQ,
+	.mv_init_arch		= setup_bigsur,
+	.mv_init_irq		= init_bigsur_IRQ,
 #ifdef CONFIG_HEARTBEAT
-	mv_heartbeat:		heartbeat_bigsur,
+	.mv_heartbeat		= heartbeat_bigsur,
 #endif
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 
 };
 ALIAS_MV(bigsur)
diff -Nru a/arch/sh/kernel/mach_cat68701.c b/arch/sh/kernel/mach_cat68701.c
--- a/arch/sh/kernel/mach_cat68701.c	Tue Oct 15 20:29:22 2002
+++ b/arch/sh/kernel/mach_cat68701.c	Tue Oct 15 20:29:22 2002
@@ -23,50 +23,50 @@
  */
 
 struct sh_machine_vector mv_cat68701 __initmv = {
-	mv_name:		"CAT-68701",
-	mv_nr_irqs:		32,
-	mv_inb:			cat68701_inb,
-	mv_inw:			cat68701_inw,
-	mv_inl:			cat68701_inl,
-	mv_outb:		cat68701_outb,
-	mv_outw:		cat68701_outw,
-	mv_outl:		cat68701_outl,
-
-	mv_inb_p:		cat68701_inb_p,
-	mv_inw_p:		cat68701_inw,
-	mv_inl_p:		cat68701_inl,
-	mv_outb_p:		cat68701_outb_p,
-	mv_outw_p:		cat68701_outw,
-	mv_outl_p:		cat68701_outl,
-
-	mv_insb:		cat68701_insb,
-	mv_insw:		cat68701_insw,
-	mv_insl:		cat68701_insl,
-	mv_outsb:		cat68701_outsb,
-	mv_outsw:		cat68701_outsw,
-	mv_outsl:		cat68701_outsl,
-
-	mv_readb:		cat68701_readb,
-	mv_readw:		cat68701_readw,
-	mv_readl:		cat68701_readl,
-	mv_writeb:		cat68701_writeb,
-	mv_writew:		cat68701_writew,
-	mv_writel:		cat68701_writel,
+	.mv_name		= "CAT-68701",
+	.mv_nr_irqs		= 32,
+	.mv_inb			= cat68701_inb,
+	.mv_inw			= cat68701_inw,
+	.mv_inl			= cat68701_inl,
+	.mv_outb		= cat68701_outb,
+	.mv_outw		= cat68701_outw,
+	.mv_outl		= cat68701_outl,
+
+	.mv_inb_p		= cat68701_inb_p,
+	.mv_inw_p		= cat68701_inw,
+	.mv_inl_p		= cat68701_inl,
+	.mv_outb_p		= cat68701_outb_p,
+	.mv_outw_p		= cat68701_outw,
+	.mv_outl_p		= cat68701_outl,
+
+	.mv_insb		= cat68701_insb,
+	.mv_insw		= cat68701_insw,
+	.mv_insl		= cat68701_insl,
+	.mv_outsb		= cat68701_outsb,
+	.mv_outsw		= cat68701_outsw,
+	.mv_outsl		= cat68701_outsl,
+
+	.mv_readb		= cat68701_readb,
+	.mv_readw		= cat68701_readw,
+	.mv_readl		= cat68701_readl,
+	.mv_writeb		= cat68701_writeb,
+	.mv_writew		= cat68701_writew,
+	.mv_writel		= cat68701_writel,
 
-	mv_ioremap:		cat68701_ioremap,
-	mv_iounmap:		cat68701_iounmap,
+	.mv_ioremap		= cat68701_ioremap,
+	.mv_iounmap		= cat68701_iounmap,
 
-	mv_isa_port2addr:	cat68701_isa_port2addr,
-	mv_irq_demux:           cat68701_irq_demux,
+	.mv_isa_port2addr	= cat68701_isa_port2addr,
+	.mv_irq_demux           = cat68701_irq_demux,
 
-	mv_init_arch:		setup_cat68701,
-	mv_init_irq:		init_cat68701_IRQ,
+	.mv_init_arch		= setup_cat68701,
+	.mv_init_irq		= init_cat68701_IRQ,
 #ifdef CONFIG_HEARTBEAT
-	mv_heartbeat:		heartbeat_cat68701,
+	.mv_heartbeat		= heartbeat_cat68701,
 #endif
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 
 };
 ALIAS_MV(cat68701)
diff -Nru a/arch/sh/kernel/mach_dc.c b/arch/sh/kernel/mach_dc.c
--- a/arch/sh/kernel/mach_dc.c	Tue Oct 15 20:29:12 2002
+++ b/arch/sh/kernel/mach_dc.c	Tue Oct 15 20:29:12 2002
@@ -26,48 +26,48 @@
  */
 
 struct sh_machine_vector mv_dreamcast __initmv = {
-	mv_name:		"dreamcast",
+	.mv_name		= "dreamcast",
 
-	mv_nr_irqs:		NR_IRQS,
+	.mv_nr_irqs		= NR_IRQS,
 
-	mv_inb:			generic_inb,
-	mv_inw:			generic_inw,
-	mv_inl:			generic_inl,
-	mv_outb:		generic_outb,
-	mv_outw:		generic_outw,
-	mv_outl:		generic_outl,
-
-	mv_inb_p:		generic_inb_p,
-	mv_inw_p:		generic_inw,
-	mv_inl_p:		generic_inl,
-	mv_outb_p:		generic_outb_p,
-	mv_outw_p:		generic_outw,
-	mv_outl_p:		generic_outl,
-
-	mv_insb:		generic_insb,
-	mv_insw:		generic_insw,
-	mv_insl:		generic_insl,
-	mv_outsb:		generic_outsb,
-	mv_outsw:		generic_outsw,
-	mv_outsl:		generic_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
-
-	mv_ioremap:		generic_ioremap,
-	mv_iounmap:		generic_iounmap,
-
-	mv_init_arch:		setup_dreamcast,
-	mv_isa_port2addr:	dreamcast_isa_port2addr,
-	mv_irq_demux:		systemasic_irq_demux,
+	.mv_inb			= generic_inb,
+	.mv_inw			= generic_inw,
+	.mv_inl			= generic_inl,
+	.mv_outb		= generic_outb,
+	.mv_outw		= generic_outw,
+	.mv_outl		= generic_outl,
+
+	.mv_inb_p		= generic_inb_p,
+	.mv_inw_p		= generic_inw,
+	.mv_inl_p		= generic_inl,
+	.mv_outb_p		= generic_outb_p,
+	.mv_outw_p		= generic_outw,
+	.mv_outl_p		= generic_outl,
+
+	.mv_insb		= generic_insb,
+	.mv_insw		= generic_insw,
+	.mv_insl		= generic_insl,
+	.mv_outsb		= generic_outsb,
+	.mv_outsw		= generic_outsw,
+	.mv_outsl		= generic_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
+
+	.mv_ioremap		= generic_ioremap,
+	.mv_iounmap		= generic_iounmap,
+
+	.mv_init_arch		= setup_dreamcast,
+	.mv_isa_port2addr	= dreamcast_isa_port2addr,
+	.mv_irq_demux		= systemasic_irq_demux,
 
-	mv_rtc_gettimeofday:	aica_rtc_gettimeofday,
-	mv_rtc_settimeofday:	aica_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= aica_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= aica_rtc_settimeofday,
 
-	mv_hw_dreamcast:	1,
+	.mv_hw_dreamcast	= 1,
 };
 ALIAS_MV(dreamcast)
diff -Nru a/arch/sh/kernel/mach_dmida.c b/arch/sh/kernel/mach_dmida.c
--- a/arch/sh/kernel/mach_dmida.c	Tue Oct 15 20:29:12 2002
+++ b/arch/sh/kernel/mach_dmida.c	Tue Oct 15 20:29:12 2002
@@ -30,44 +30,44 @@
  */
 
 struct sh_machine_vector mv_dmida __initmv = {
-	mv_name:		"DMIDA",
+	.mv_name		= "DMIDA",
 
-	mv_nr_irqs:		HD64465_IRQ_BASE+HD64465_IRQ_NUM,
+	.mv_nr_irqs		= HD64465_IRQ_BASE+HD64465_IRQ_NUM,
 
-	mv_inb:			hd64465_inb,
-	mv_inw:			hd64465_inw,
-	mv_inl:			hd64465_inl,
-	mv_outb:		hd64465_outb,
-	mv_outw:		hd64465_outw,
-	mv_outl:		hd64465_outl,
-
-	mv_inb_p:		hd64465_inb_p,
-	mv_inw_p:		hd64465_inw,
-	mv_inl_p:		hd64465_inl,
-	mv_outb_p:		hd64465_outb_p,
-	mv_outw_p:		hd64465_outw,
-	mv_outl_p:		hd64465_outl,
-
-	mv_insb:		hd64465_insb,
-	mv_insw:		hd64465_insw,
-	mv_insl:		hd64465_insl,
-	mv_outsb:		hd64465_outsb,
-	mv_outsw:		hd64465_outsw,
-	mv_outsl:		hd64465_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
+	.mv_inb			= hd64465_inb,
+	.mv_inw			= hd64465_inw,
+	.mv_inl			= hd64465_inl,
+	.mv_outb		= hd64465_outb,
+	.mv_outw		= hd64465_outw,
+	.mv_outl		= hd64465_outl,
+
+	.mv_inb_p		= hd64465_inb_p,
+	.mv_inw_p		= hd64465_inw,
+	.mv_inl_p		= hd64465_inl,
+	.mv_outb_p		= hd64465_outb_p,
+	.mv_outw_p		= hd64465_outw,
+	.mv_outl_p		= hd64465_outl,
+
+	.mv_insb		= hd64465_insb,
+	.mv_insw		= hd64465_insw,
+	.mv_insl		= hd64465_insl,
+	.mv_outsb		= hd64465_outsb,
+	.mv_outsw		= hd64465_outsw,
+	.mv_outsl		= hd64465_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
 
-	mv_irq_demux:		hd64465_irq_demux,
+	.mv_irq_demux		= hd64465_irq_demux,
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 
-	mv_hw_hd64465:		1,
+	.mv_hw_hd64465		= 1,
 };
 ALIAS_MV(dmida)
 
diff -Nru a/arch/sh/kernel/mach_ec3104.c b/arch/sh/kernel/mach_ec3104.c
--- a/arch/sh/kernel/mach_ec3104.c	Tue Oct 15 20:29:20 2002
+++ b/arch/sh/kernel/mach_ec3104.c	Tue Oct 15 20:29:20 2002
@@ -28,42 +28,42 @@
  */
 
 struct sh_machine_vector mv_ec3104 __initmv = {
-	mv_name:		"EC3104",
+	.mv_name		= "EC3104",
 
-	mv_nr_irqs:		96,
+	.mv_nr_irqs		= 96,
 
-	mv_inb:			ec3104_inb,
-	mv_inw:			ec3104_inw,
-	mv_inl:			ec3104_inl,
-	mv_outb:		ec3104_outb,
-	mv_outw:		ec3104_outw,
-	mv_outl:		ec3104_outl,
-
-	mv_inb_p:		generic_inb_p,
-	mv_inw_p:		generic_inw,
-	mv_inl_p:		generic_inl,
-	mv_outb_p:		generic_outb_p,
-	mv_outw_p:		generic_outw,
-	mv_outl_p:		generic_outl,
-
-	mv_insb:		generic_insb,
-	mv_insw:		generic_insw,
-	mv_insl:		generic_insl,
-	mv_outsb:		generic_outsb,
-	mv_outsw:		generic_outsw,
-	mv_outsl:		generic_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
+	.mv_inb			= ec3104_inb,
+	.mv_inw			= ec3104_inw,
+	.mv_inl			= ec3104_inl,
+	.mv_outb		= ec3104_outb,
+	.mv_outw		= ec3104_outw,
+	.mv_outl		= ec3104_outl,
+
+	.mv_inb_p		= generic_inb_p,
+	.mv_inw_p		= generic_inw,
+	.mv_inl_p		= generic_inl,
+	.mv_outb_p		= generic_outb_p,
+	.mv_outw_p		= generic_outw,
+	.mv_outl_p		= generic_outl,
+
+	.mv_insb		= generic_insb,
+	.mv_insw		= generic_insw,
+	.mv_insl		= generic_insl,
+	.mv_outsb		= generic_outsb,
+	.mv_outsw		= generic_outsw,
+	.mv_outsl		= generic_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
 
-	mv_irq_demux:		ec3104_irq_demux,
+	.mv_irq_demux		= ec3104_irq_demux,
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 };
 
 ALIAS_MV(ec3104)
diff -Nru a/arch/sh/kernel/mach_hp600.c b/arch/sh/kernel/mach_hp600.c
--- a/arch/sh/kernel/mach_hp600.c	Tue Oct 15 20:29:17 2002
+++ b/arch/sh/kernel/mach_hp600.c	Tue Oct 15 20:29:17 2002
@@ -24,135 +24,135 @@
  */
 
 struct sh_machine_vector mv_hp620 __initmv = {
-	mv_name:		"hp620",
+	.mv_name		= "hp620",
 
-	mv_nr_irqs:		HD64461_IRQBASE+HD64461_IRQ_NUM,
+	.mv_nr_irqs		= HD64461_IRQBASE+HD64461_IRQ_NUM,
 
-	mv_inb:			hd64461_inb,
-	mv_inw:			hd64461_inw,
-	mv_inl:			hd64461_inl,
-	mv_outb:		hd64461_outb,
-	mv_outw:		hd64461_outw,
-	mv_outl:		hd64461_outl,
-
-	mv_inb_p:		hd64461_inb_p,
-	mv_inw_p:		hd64461_inw,
-	mv_inl_p:		hd64461_inl,
-	mv_outb_p:		hd64461_outb_p,
-	mv_outw_p:		hd64461_outw,
-	mv_outl_p:		hd64461_outl,
-
-	mv_insb:		hd64461_insb,
-	mv_insw:		hd64461_insw,
-	mv_insl:		hd64461_insl,
-	mv_outsb:		hd64461_outsb,
-	mv_outsw:		hd64461_outsw,
-	mv_outsl:		hd64461_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
-
-	mv_irq_demux:		hd64461_irq_demux,
-
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
-
-	mv_hw_hp600:		1,
-	mv_hw_hp620:		1,
-	mv_hw_hd64461:		1,
+	.mv_inb			= hd64461_inb,
+	.mv_inw			= hd64461_inw,
+	.mv_inl			= hd64461_inl,
+	.mv_outb		= hd64461_outb,
+	.mv_outw		= hd64461_outw,
+	.mv_outl		= hd64461_outl,
+
+	.mv_inb_p		= hd64461_inb_p,
+	.mv_inw_p		= hd64461_inw,
+	.mv_inl_p		= hd64461_inl,
+	.mv_outb_p		= hd64461_outb_p,
+	.mv_outw_p		= hd64461_outw,
+	.mv_outl_p		= hd64461_outl,
+
+	.mv_insb		= hd64461_insb,
+	.mv_insw		= hd64461_insw,
+	.mv_insl		= hd64461_insl,
+	.mv_outsb		= hd64461_outsb,
+	.mv_outsw		= hd64461_outsw,
+	.mv_outsl		= hd64461_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
+
+	.mv_irq_demux		= hd64461_irq_demux,
+
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
+
+	.mv_hw_hp600		= 1,
+	.mv_hw_hp620		= 1,
+	.mv_hw_hd64461		= 1,
 };
 ALIAS_MV(hp620)
 
 
 struct sh_machine_vector mv_hp680 __initmv = {
-	mv_name:		"hp680",
+	.mv_name		= "hp680",
 
-	mv_nr_irqs:		HD64461_IRQBASE+HD64461_IRQ_NUM,
+	.mv_nr_irqs		= HD64461_IRQBASE+HD64461_IRQ_NUM,
 
-	mv_inb:			hd64461_inb,
-	mv_inw:			hd64461_inw,
-	mv_inl:			hd64461_inl,
-	mv_outb:		hd64461_outb,
-	mv_outw:		hd64461_outw,
-	mv_outl:		hd64461_outl,
-
-	mv_inb_p:		hd64461_inb_p,
-	mv_inw_p:		hd64461_inw,
-	mv_inl_p:		hd64461_inl,
-	mv_outb_p:		hd64461_outb_p,
-	mv_outw_p:		hd64461_outw,
-	mv_outl_p:		hd64461_outl,
-
-	mv_insb:		hd64461_insb,
-	mv_insw:		hd64461_insw,
-	mv_insl:		hd64461_insl,
-	mv_outsb:		hd64461_outsb,
-	mv_outsw:		hd64461_outsw,
-	mv_outsl:		hd64461_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
-
-	mv_irq_demux:		hd64461_irq_demux,
-
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
-
-	mv_hw_hp600:		1,
-	mv_hw_hp680:		1,
-	mv_hw_hd64461:		1,
+	.mv_inb			= hd64461_inb,
+	.mv_inw			= hd64461_inw,
+	.mv_inl			= hd64461_inl,
+	.mv_outb		= hd64461_outb,
+	.mv_outw		= hd64461_outw,
+	.mv_outl		= hd64461_outl,
+
+	.mv_inb_p		= hd64461_inb_p,
+	.mv_inw_p		= hd64461_inw,
+	.mv_inl_p		= hd64461_inl,
+	.mv_outb_p		= hd64461_outb_p,
+	.mv_outw_p		= hd64461_outw,
+	.mv_outl_p		= hd64461_outl,
+
+	.mv_insb		= hd64461_insb,
+	.mv_insw		= hd64461_insw,
+	.mv_insl		= hd64461_insl,
+	.mv_outsb		= hd64461_outsb,
+	.mv_outsw		= hd64461_outsw,
+	.mv_outsl		= hd64461_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
+
+	.mv_irq_demux		= hd64461_irq_demux,
+
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
+
+	.mv_hw_hp600		= 1,
+	.mv_hw_hp680		= 1,
+	.mv_hw_hd64461		= 1,
 };
 ALIAS_MV(hp680)
 
 
 struct sh_machine_vector mv_hp690 __initmv = {
-	mv_name:		"hp690",
+	.mv_name		= "hp690",
 
-	mv_nr_irqs:		HD64461_IRQBASE+HD64461_IRQ_NUM,
+	.mv_nr_irqs		= HD64461_IRQBASE+HD64461_IRQ_NUM,
 
-	mv_inb:			hd64461_inb,
-	mv_inw:			hd64461_inw,
-	mv_inl:			hd64461_inl,
-	mv_outb:		hd64461_outb,
-	mv_outw:		hd64461_outw,
-	mv_outl:		hd64461_outl,
-
-	mv_inb_p:		hd64461_inb_p,
-	mv_inw_p:		hd64461_inw,
-	mv_inl_p:		hd64461_inl,
-	mv_outb_p:		hd64461_outb_p,
-	mv_outw_p:		hd64461_outw,
-	mv_outl_p:		hd64461_outl,
-
-	mv_insb:		hd64461_insb,
-	mv_insw:		hd64461_insw,
-	mv_insl:		hd64461_insl,
-	mv_outsb:		hd64461_outsb,
-	mv_outsw:		hd64461_outsw,
-	mv_outsl:		hd64461_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
-
-	mv_irq_demux:		hd64461_irq_demux,
-
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
-
-	mv_hw_hp600:		1,
-	mv_hw_hp690:		1,
-	mv_hw_hd64461:		1,
+	.mv_inb			= hd64461_inb,
+	.mv_inw			= hd64461_inw,
+	.mv_inl			= hd64461_inl,
+	.mv_outb		= hd64461_outb,
+	.mv_outw		= hd64461_outw,
+	.mv_outl		= hd64461_outl,
+
+	.mv_inb_p		= hd64461_inb_p,
+	.mv_inw_p		= hd64461_inw,
+	.mv_inl_p		= hd64461_inl,
+	.mv_outb_p		= hd64461_outb_p,
+	.mv_outw_p		= hd64461_outw,
+	.mv_outl_p		= hd64461_outl,
+
+	.mv_insb		= hd64461_insb,
+	.mv_insw		= hd64461_insw,
+	.mv_insl		= hd64461_insl,
+	.mv_outsb		= hd64461_outsb,
+	.mv_outsw		= hd64461_outsw,
+	.mv_outsl		= hd64461_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
+
+	.mv_irq_demux		= hd64461_irq_demux,
+
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
+
+	.mv_hw_hp600		= 1,
+	.mv_hw_hp690		= 1,
+	.mv_hw_hd64461		= 1,
 };
 ALIAS_MV(hp690)
diff -Nru a/arch/sh/kernel/mach_se.c b/arch/sh/kernel/mach_se.c
--- a/arch/sh/kernel/mach_se.c	Tue Oct 15 20:29:20 2002
+++ b/arch/sh/kernel/mach_se.c	Tue Oct 15 20:29:20 2002
@@ -27,58 +27,58 @@
  */
 
 struct sh_machine_vector mv_se __initmv = {
-	mv_name:		"SolutionEngine",
+	.mv_name		= "SolutionEngine",
 
 #if defined(__SH4__)
-	mv_nr_irqs:		48,
+	.mv_nr_irqs		= 48,
 #elif defined(CONFIG_CPU_SUBTYPE_SH7708)
-	mv_nr_irqs:		32,
+	.mv_nr_irqs		= 32,
 #elif defined(CONFIG_CPU_SUBTYPE_SH7709)
-	mv_nr_irqs:		61,
+	.mv_nr_irqs		= 61,
 #endif
 
-	mv_inb:			se_inb,
-	mv_inw:			se_inw,
-	mv_inl:			se_inl,
-	mv_outb:		se_outb,
-	mv_outw:		se_outw,
-	mv_outl:		se_outl,
-
-	mv_inb_p:		se_inb_p,
-	mv_inw_p:		se_inw,
-	mv_inl_p:		se_inl,
-	mv_outb_p:		se_outb_p,
-	mv_outw_p:		se_outw,
-	mv_outl_p:		se_outl,
-
-	mv_insb:		se_insb,
-	mv_insw:		se_insw,
-	mv_insl:		se_insl,
-	mv_outsb:		se_outsb,
-	mv_outsw:		se_outsw,
-	mv_outsl:		se_outsl,
-
-	mv_readb:		se_readb,
-	mv_readw:		se_readw,
-	mv_readl:		se_readl,
-	mv_writeb:		se_writeb,
-	mv_writew:		se_writew,
-	mv_writel:		se_writel,
+	.mv_inb			= se_inb,
+	.mv_inw			= se_inw,
+	.mv_inl			= se_inl,
+	.mv_outb		= se_outb,
+	.mv_outw		= se_outw,
+	.mv_outl		= se_outl,
+
+	.mv_inb_p		= se_inb_p,
+	.mv_inw_p		= se_inw,
+	.mv_inl_p		= se_inl,
+	.mv_outb_p		= se_outb_p,
+	.mv_outw_p		= se_outw,
+	.mv_outl_p		= se_outl,
+
+	.mv_insb		= se_insb,
+	.mv_insw		= se_insw,
+	.mv_insl		= se_insl,
+	.mv_outsb		= se_outsb,
+	.mv_outsw		= se_outsw,
+	.mv_outsl		= se_outsl,
+
+	.mv_readb		= se_readb,
+	.mv_readw		= se_readw,
+	.mv_readl		= se_readl,
+	.mv_writeb		= se_writeb,
+	.mv_writew		= se_writew,
+	.mv_writel		= se_writel,
 
-	mv_ioremap:		generic_ioremap,
-	mv_iounmap:		generic_iounmap,
+	.mv_ioremap		= generic_ioremap,
+	.mv_iounmap		= generic_iounmap,
 
-	mv_isa_port2addr:	se_isa_port2addr,
+	.mv_isa_port2addr	= se_isa_port2addr,
 
-	mv_init_arch:		setup_se,
-	mv_init_irq:		init_se_IRQ,
+	.mv_init_arch		= setup_se,
+	.mv_init_irq		= init_se_IRQ,
 #ifdef CONFIG_HEARTBEAT
-	mv_heartbeat:		heartbeat_se,
+	.mv_heartbeat		= heartbeat_se,
 #endif
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 
-	mv_hw_se:		1,
+	.mv_hw_se		= 1,
 };
 ALIAS_MV(se)
diff -Nru a/arch/sh/kernel/mach_unknown.c b/arch/sh/kernel/mach_unknown.c
--- a/arch/sh/kernel/mach_unknown.c	Tue Oct 15 20:29:12 2002
+++ b/arch/sh/kernel/mach_unknown.c	Tue Oct 15 20:29:12 2002
@@ -23,50 +23,50 @@
  */
 
 struct sh_machine_vector mv_unknown __initmv = {
-	mv_name:		"Unknown",
+	.mv_name		= "Unknown",
 
 #if defined(__SH4__)
-	mv_nr_irqs:		48,
+	.mv_nr_irqs		= 48,
 #elif defined(CONFIG_CPU_SUBTYPE_SH7708)
-	mv_nr_irqs:		32,
+	.mv_nr_irqs		= 32,
 #elif defined(CONFIG_CPU_SUBTYPE_SH7709)
-	mv_nr_irqs:		61,
+	.mv_nr_irqs		= 61,
 #endif
 
-	mv_inb:			unknown_inb,
-	mv_inw:			unknown_inw,
-	mv_inl:			unknown_inl,
-	mv_outb:		unknown_outb,
-	mv_outw:		unknown_outw,
-	mv_outl:		unknown_outl,
-
-	mv_inb_p:		unknown_inb_p,
-	mv_inw_p:		unknown_inw_p,
-	mv_inl_p:		unknown_inl_p,
-	mv_outb_p:		unknown_outb_p,
-	mv_outw_p:		unknown_outw_p,
-	mv_outl_p:		unknown_outl_p,
-
-	mv_insb:		unknown_insb,
-	mv_insw:		unknown_insw,
-	mv_insl:		unknown_insl,
-	mv_outsb:		unknown_outsb,
-	mv_outsw:		unknown_outsw,
-	mv_outsl:		unknown_outsl,
-
-	mv_readb:		unknown_readb,
-	mv_readw:		unknown_readw,
-	mv_readl:		unknown_readl,
-	mv_writeb:		unknown_writeb,
-	mv_writew:		unknown_writew,
-	mv_writel:		unknown_writel,
+	.mv_inb			= unknown_inb,
+	.mv_inw			= unknown_inw,
+	.mv_inl			= unknown_inl,
+	.mv_outb		= unknown_outb,
+	.mv_outw		= unknown_outw,
+	.mv_outl		= unknown_outl,
+
+	.mv_inb_p		= unknown_inb_p,
+	.mv_inw_p		= unknown_inw_p,
+	.mv_inl_p		= unknown_inl_p,
+	.mv_outb_p		= unknown_outb_p,
+	.mv_outw_p		= unknown_outw_p,
+	.mv_outl_p		= unknown_outl_p,
+
+	.mv_insb		= unknown_insb,
+	.mv_insw		= unknown_insw,
+	.mv_insl		= unknown_insl,
+	.mv_outsb		= unknown_outsb,
+	.mv_outsw		= unknown_outsw,
+	.mv_outsl		= unknown_outsl,
+
+	.mv_readb		= unknown_readb,
+	.mv_readw		= unknown_readw,
+	.mv_readl		= unknown_readl,
+	.mv_writeb		= unknown_writeb,
+	.mv_writew		= unknown_writew,
+	.mv_writel		= unknown_writel,
 
-	mv_ioremap:		unknown_ioremap,
-	mv_iounmap:		unknown_iounmap,
+	.mv_ioremap		= unknown_ioremap,
+	.mv_iounmap		= unknown_iounmap,
 
-	mv_isa_port2addr:	unknown_isa_port2addr,
+	.mv_isa_port2addr	= unknown_isa_port2addr,
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 };
 ALIAS_MV(unknown)
diff -Nru a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
--- a/arch/sh/kernel/setup.c	Tue Oct 15 20:29:17 2002
+++ b/arch/sh/kernel/setup.c	Tue Oct 15 20:29:17 2002
@@ -171,12 +171,12 @@
 }
 
 static struct console sh_console = {
-	name:		"bios",
-	write:		sh_console_write,
-	device:		sh_console_device,
-	setup:		sh_console_setup,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name		= "bios",
+	.write		= sh_console_write,
+	.device		= sh_console_device,
+	.setup		= sh_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
 };
 
 void sh_console_init(void)
@@ -548,9 +548,9 @@
 {
 }
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= show_cpuinfo,
 };
 #endif
diff -Nru a/arch/sh/kernel/setup_cqreek.c b/arch/sh/kernel/setup_cqreek.c
--- a/arch/sh/kernel/setup_cqreek.c	Tue Oct 15 20:29:16 2002
+++ b/arch/sh/kernel/setup_cqreek.c	Tue Oct 15 20:29:16 2002
@@ -200,53 +200,53 @@
  */
 
 struct sh_machine_vector mv_cqreek __initmv = {
-	mv_name:		"CqREEK",
+	.mv_name		= "CqREEK",
 
 #if defined(__SH4__)
-	mv_nr_irqs:		48,
+	.mv_nr_irqs		= 48,
 #elif defined(CONFIG_CPU_SUBTYPE_SH7708)
-	mv_nr_irqs:		32,
+	.mv_nr_irqs		= 32,
 #elif defined(CONFIG_CPU_SUBTYPE_SH7709)
-	mv_nr_irqs:		61,
+	.mv_nr_irqs		= 61,
 #endif
 
-	mv_inb:			generic_inb,
-	mv_inw:			generic_inw,
-	mv_inl:			generic_inl,
-	mv_outb:		generic_outb,
-	mv_outw:		generic_outw,
-	mv_outl:		generic_outl,
-
-	mv_inb_p:		generic_inb_p,
-	mv_inw_p:		generic_inw_p,
-	mv_inl_p:		generic_inl_p,
-	mv_outb_p:		generic_outb_p,
-	mv_outw_p:		generic_outw_p,
-	mv_outl_p:		generic_outl_p,
-
-	mv_insb:		generic_insb,
-	mv_insw:		generic_insw,
-	mv_insl:		generic_insl,
-	mv_outsb:		generic_outsb,
-	mv_outsw:		generic_outsw,
-	mv_outsl:		generic_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
-
-	mv_init_arch:		setup_cqreek,
-	mv_init_irq:		init_cqreek_IRQ,
+	.mv_inb			= generic_inb,
+	.mv_inw			= generic_inw,
+	.mv_inl			= generic_inl,
+	.mv_outb		= generic_outb,
+	.mv_outw		= generic_outw,
+	.mv_outl		= generic_outl,
+
+	.mv_inb_p		= generic_inb_p,
+	.mv_inw_p		= generic_inw_p,
+	.mv_inl_p		= generic_inl_p,
+	.mv_outb_p		= generic_outb_p,
+	.mv_outw_p		= generic_outw_p,
+	.mv_outl_p		= generic_outl_p,
+
+	.mv_insb		= generic_insb,
+	.mv_insw		= generic_insw,
+	.mv_insl		= generic_insl,
+	.mv_outsb		= generic_outsb,
+	.mv_outsw		= generic_outsw,
+	.mv_outsl		= generic_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
+
+	.mv_init_arch		= setup_cqreek,
+	.mv_init_irq		= init_cqreek_IRQ,
 
-	mv_isa_port2addr:	cqreek_port2addr,
+	.mv_isa_port2addr	= cqreek_port2addr,
 
-	mv_ioremap:		generic_ioremap,
-	mv_iounmap:		generic_iounmap,
+	.mv_ioremap		= generic_ioremap,
+	.mv_iounmap		= generic_iounmap,
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 };
 ALIAS_MV(cqreek)
diff -Nru a/arch/sh/kernel/setup_dc.c b/arch/sh/kernel/setup_dc.c
--- a/arch/sh/kernel/setup_dc.c	Tue Oct 15 20:29:12 2002
+++ b/arch/sh/kernel/setup_dc.c	Tue Oct 15 20:29:12 2002
@@ -123,13 +123,13 @@
 }
 
 static struct hw_interrupt_type systemasic_int = {
-	typename:       "System ASIC",
-	startup:        startup_systemasic_irq,
-	shutdown:       shutdown_systemasic_irq,
-	enable:         enable_systemasic_irq,
-	disable:        disable_systemasic_irq,
-	ack:            ack_systemasic_irq,
-	end:            end_systemasic_irq,
+	.typename       = "System ASIC",
+	.startup        = startup_systemasic_irq,
+	.shutdown       = shutdown_systemasic_irq,
+	.enable         = enable_systemasic_irq,
+	.disable        = disable_systemasic_irq,
+	.ack            = ack_systemasic_irq,
+	.end            = end_systemasic_irq,
 };
 
 /*
diff -Nru a/arch/sh/kernel/setup_ec3104.c b/arch/sh/kernel/setup_ec3104.c
--- a/arch/sh/kernel/setup_ec3104.c	Tue Oct 15 20:29:21 2002
+++ b/arch/sh/kernel/setup_ec3104.c	Tue Oct 15 20:29:21 2002
@@ -185,13 +185,13 @@
 }
 
 static struct hw_interrupt_type ec3104_int = {
-	typename:	"EC3104",
-	enable:		enable_ec3104_irq,
-	disable:	disable_ec3104_irq,
-	ack:		mask_and_ack_ec3104_irq,
-	end:		end_ec3104_irq,
-	startup:	startup_ec3104_irq,
-	shutdown:	shutdown_ec3104_irq,
+	.typename	= "EC3104",
+	.enable		= enable_ec3104_irq,
+	.disable	= disable_ec3104_irq,
+	.ack		= mask_and_ack_ec3104_irq,
+	.end		= end_ec3104_irq,
+	.startup	= startup_ec3104_irq,
+	.shutdown	= shutdown_ec3104_irq,
 };
 
 /* Yuck.  the _demux API is ugly */
diff -Nru a/arch/sh/kernel/setup_hd64465.c b/arch/sh/kernel/setup_hd64465.c
--- a/arch/sh/kernel/setup_hd64465.c	Tue Oct 15 20:29:23 2002
+++ b/arch/sh/kernel/setup_hd64465.c	Tue Oct 15 20:29:23 2002
@@ -89,13 +89,13 @@
 
 
 static struct hw_interrupt_type hd64465_irq_type = {
-	typename:	"HD64465-IRQ",
-	startup:	startup_hd64465_irq,
-	shutdown:	shutdown_hd64465_irq,
-	enable:		enable_hd64465_irq,
-	disable:	disable_hd64465_irq,
-	ack:		mask_and_ack_hd64465,
-	end:		end_hd64465_irq
+	.typename	= "HD64465-IRQ",
+	.startup	= startup_hd64465_irq,
+	.shutdown	= shutdown_hd64465_irq,
+	.enable		= enable_hd64465_irq,
+	.disable	= disable_hd64465_irq,
+	.ack		= mask_and_ack_hd64465,
+	.end		= end_hd64465_irq
 };
 
 
diff -Nru a/arch/sh/kernel/setup_sh2000.c b/arch/sh/kernel/setup_sh2000.c
--- a/arch/sh/kernel/setup_sh2000.c	Tue Oct 15 20:29:15 2002
+++ b/arch/sh/kernel/setup_sh2000.c	Tue Oct 15 20:29:15 2002
@@ -48,48 +48,48 @@
  */
 
 struct sh_machine_vector mv_sh2000 __initmv = {
-	mv_name:		"sh2000",
+	.mv_name		= "sh2000",
 
-	mv_nr_irqs:		80,
+	.mv_nr_irqs		= 80,
 
-	mv_inb:			generic_inb,
-	mv_inw:			generic_inw,
-	mv_inl:			generic_inl,
-	mv_outb:		generic_outb,
-	mv_outw:		generic_outw,
-	mv_outl:		generic_outl,
-
-	mv_inb_p:		generic_inb_p,
-	mv_inw_p:		generic_inw_p,
-	mv_inl_p:		generic_inl_p,
-	mv_outb_p:		generic_outb_p,
-	mv_outw_p:		generic_outw_p,
-	mv_outl_p:		generic_outl_p,
-
-	mv_insb:		generic_insb,
-	mv_insw:		generic_insw,
-	mv_insl:		generic_insl,
-	mv_outsb:		generic_outsb,
-	mv_outsw:		generic_outsw,
-	mv_outsl:		generic_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
-
-	mv_init_arch:		setup_sh2000,
-
-	mv_isa_port2addr:	sh2000_isa_port2addr,
+	.mv_inb			= generic_inb,
+	.mv_inw			= generic_inw,
+	.mv_inl			= generic_inl,
+	.mv_outb		= generic_outb,
+	.mv_outw		= generic_outw,
+	.mv_outl		= generic_outl,
+
+	.mv_inb_p		= generic_inb_p,
+	.mv_inw_p		= generic_inw_p,
+	.mv_inl_p		= generic_inl_p,
+	.mv_outb_p		= generic_outb_p,
+	.mv_outw_p		= generic_outw_p,
+	.mv_outl_p		= generic_outl_p,
+
+	.mv_insb		= generic_insb,
+	.mv_insw		= generic_insw,
+	.mv_insl		= generic_insl,
+	.mv_outsb		= generic_outsb,
+	.mv_outsw		= generic_outsw,
+	.mv_outsl		= generic_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
+
+	.mv_init_arch		= setup_sh2000,
+
+	.mv_isa_port2addr	= sh2000_isa_port2addr,
 
-	mv_ioremap:		generic_ioremap,
-	mv_iounmap:		generic_iounmap,
+	.mv_ioremap		= generic_ioremap,
+	.mv_iounmap		= generic_iounmap,
 
-	mv_rtc_gettimeofday:	sh_rtc_gettimeofday,
-	mv_rtc_settimeofday:	sh_rtc_settimeofday,
+	.mv_rtc_gettimeofday	= sh_rtc_gettimeofday,
+	.mv_rtc_settimeofday	= sh_rtc_settimeofday,
 
-	mv_hw_sh2000:		1,
+	.mv_hw_sh2000		= 1,
 };
 ALIAS_MV(sh2000)
diff -Nru a/arch/sh/stboards/mach.c b/arch/sh/stboards/mach.c
--- a/arch/sh/stboards/mach.c	Tue Oct 15 20:29:17 2002
+++ b/arch/sh/stboards/mach.c	Tue Oct 15 20:29:17 2002
@@ -26,52 +26,52 @@
  */
 
 struct sh_machine_vector mv_harp __initmv = {
-	mv_name:		"STB1 Harp",
+	.mv_name		= "STB1 Harp",
 
-	mv_nr_irqs:		89 + HD64465_IRQ_NUM,
+	.mv_nr_irqs		= 89 + HD64465_IRQ_NUM,
 
-	mv_inb:			hd64465_inb,
-	mv_inw:			hd64465_inw,
-	mv_inl:			hd64465_inl,
-	mv_outb:		hd64465_outb,
-	mv_outw:		hd64465_outw,
-	mv_outl:		hd64465_outl,
-
-	mv_inb_p:		hd64465_inb_p,
-	mv_inw_p:		hd64465_inw,
-	mv_inl_p:		hd64465_inl,
-	mv_outb_p:		hd64465_outb_p,
-	mv_outw_p:		hd64465_outw,
-	mv_outl_p:		hd64465_outl,
-
-	mv_insb:		hd64465_insb,
-	mv_insw:		hd64465_insw,
-	mv_insl:		hd64465_insl,
-	mv_outsb:		hd64465_outsb,
-	mv_outsw:		hd64465_outsw,
-	mv_outsl:		hd64465_outsl,
-
-	mv_readb:		generic_readb,
-	mv_readw:		generic_readw,
-	mv_readl:		generic_readl,
-	mv_writeb:		generic_writeb,
-	mv_writew:		generic_writew,
-	mv_writel:		generic_writel,
+	.mv_inb			= hd64465_inb,
+	.mv_inw			= hd64465_inw,
+	.mv_inl			= hd64465_inl,
+	.mv_outb		= hd64465_outb,
+	.mv_outw		= hd64465_outw,
+	.mv_outl		= hd64465_outl,
+
+	.mv_inb_p		= hd64465_inb_p,
+	.mv_inw_p		= hd64465_inw,
+	.mv_inl_p		= hd64465_inl,
+	.mv_outb_p		= hd64465_outb_p,
+	.mv_outw_p		= hd64465_outw,
+	.mv_outl_p		= hd64465_outl,
+
+	.mv_insb		= hd64465_insb,
+	.mv_insw		= hd64465_insw,
+	.mv_insl		= hd64465_insl,
+	.mv_outsb		= hd64465_outsb,
+	.mv_outsw		= hd64465_outsw,
+	.mv_outsl		= hd64465_outsl,
+
+	.mv_readb		= generic_readb,
+	.mv_readw		= generic_readw,
+	.mv_readl		= generic_readl,
+	.mv_writeb		= generic_writeb,
+	.mv_writew		= generic_writew,
+	.mv_writel		= generic_writel,
 
-        mv_ioremap:             generic_ioremap,
-        mv_iounmap:             generic_iounmap,
+        .mv_ioremap             = generic_ioremap,
+        .mv_iounmap             = generic_iounmap,
  
-        mv_isa_port2addr:       hd64465_isa_port2addr,
+        .mv_isa_port2addr       = hd64465_isa_port2addr,
 
-	mv_init_arch:		setup_harp,
+	.mv_init_arch		= setup_harp,
 #ifdef CONFIG_PCI
-	mv_init_irq:		init_harp_irq,
+	.mv_init_irq		= init_harp_irq,
 #endif
 #ifdef CONFIG_HEARTBEAT
-	mv_heartbeat:		heartbeat_harp,
+	.mv_heartbeat		= heartbeat_harp,
 #endif
-        mv_rtc_gettimeofday:    sh_rtc_gettimeofday,
-        mv_rtc_settimeofday:    sh_rtc_settimeofday,
+        .mv_rtc_gettimeofday    = sh_rtc_gettimeofday,
+        .mv_rtc_settimeofday    = sh_rtc_settimeofday,
 };
 
 ALIAS_MV(harp)
diff -Nru a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
--- a/arch/sparc/kernel/pcic.c	Tue Oct 15 20:29:17 2002
+++ b/arch/sparc/kernel/pcic.c	Tue Oct 15 20:29:17 2002
@@ -34,6 +34,8 @@
 #include <asm/timer.h>
 #include <asm/uaccess.h>
 
+extern rwlock_t xtime_lock;
+
 #ifndef CONFIG_PCI
 
 asmlinkage int sys_pciconfig_read(unsigned long bus,
@@ -737,8 +739,10 @@
 
 static void pcic_timer_handler (int irq, void *h, struct pt_regs *regs)
 {
+	write_lock(&xtime_lock);	/* Dummy, to show that we remember */
 	pcic_clear_clock_irq();
 	do_timer(regs);
+	write_unlock(&xtime_lock);
 }
 
 #define USECS_PER_JIFFY  10000  /* We have 100HZ "standard" timer for sparc */
@@ -776,25 +780,17 @@
 
 static __inline__ unsigned long do_gettimeoffset(void)
 {
-	struct tasklet_struct *t;
-	unsigned long offset = 0;
-
-	/* 
+	/*
 	 * We devide all to 100
 	 * to have microsecond resolution and to avoid overflow
 	 */
-	unsigned long count = 
+	unsigned long count =
 	    readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
 	count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
-
-	t = &bh_task_vec[TIMER_BH];
-	if (test_bit(TASKLET_STATE_SCHED, &t->state))
-		offset = 1000000;
-	return offset + count;
+	return count;
 }
 
 extern unsigned long wall_jiffies;
-extern rwlock_t xtime_lock;
 
 static void pci_do_gettimeofday(struct timeval *tv)
 {
diff -Nru a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
--- a/arch/sparc/kernel/time.c	Tue Oct 15 20:29:17 2002
+++ b/arch/sparc/kernel/time.c	Tue Oct 15 20:29:17 2002
@@ -129,6 +129,8 @@
 		sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
 #endif
 
+	/* Protect counter clear so that do_gettimeoffset works */
+	write_lock(&xtime_lock);
 #ifdef CONFIG_SUN4
 	if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
 	   (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
@@ -140,8 +142,6 @@
 #endif
 	clear_clock_irq();
 
-	write_lock(&xtime_lock);
-
 	do_timer(regs);
 
 	/* Determine when to update the Mostek clock. */
@@ -459,17 +459,7 @@
 
 extern __inline__ unsigned long do_gettimeoffset(void)
 {
-	struct tasklet_struct *t;
-	unsigned long offset = 0;
-	unsigned int count;
-
-	count = (*master_l10_counter >> 10) & 0x1fffff;
-
-	t = &bh_task_vec[TIMER_BH];
-	if (test_bit(TASKLET_STATE_SCHED, &t->state))
-		offset = 1000000;
-
-	return offset + count;
+	return (*master_l10_counter >> 10) & 0x1fffff;
 }
 
 /* Ok, my cute asm atomicity trick doesn't work anymore.
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Tue Oct 15 20:29:16 2002
+++ b/arch/sparc64/defconfig	Tue Oct 15 20:29:16 2002
@@ -32,6 +32,7 @@
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_SMP=y
 # CONFIG_PREEMPT is not set
+CONFIG_NR_CPUS=4
 CONFIG_SPARC64=y
 CONFIG_HOTPLUG=y
 CONFIG_HAVE_DEC_LOCK=y
@@ -59,7 +60,6 @@
 CONFIG_BINFMT_MISC=m
 # CONFIG_SUNOS_EMUL is not set
 CONFIG_SOLARIS_EMUL=m
-CONFIG_NR_CPUS=64
 
 #
 # Parallel port support
@@ -220,6 +220,8 @@
 # CONFIG_BLK_DEV_GENERIC is not set
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDE_TCQ is not set
+# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set
 # CONFIG_BLK_DEV_OFFBOARD is not set
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
@@ -1025,15 +1027,20 @@
 CONFIG_BLUEZ=m
 CONFIG_BLUEZ_L2CAP=m
 CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
 
 #
 # Bluetooth device drivers
 #
 CONFIG_BLUEZ_HCIUSB=m
-CONFIG_BLUEZ_USB_FW_LOAD=y
 CONFIG_BLUEZ_USB_ZERO_PACKET=y
 CONFIG_BLUEZ_HCIUART=m
 CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
 # CONFIG_BLUEZ_HCIDTL1 is not set
 # CONFIG_BLUEZ_HCIBT3C is not set
 # CONFIG_BLUEZ_HCIBLUECARD is not set
diff -Nru a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
--- a/arch/sparc64/kernel/ebus.c	Tue Oct 15 20:29:15 2002
+++ b/arch/sparc64/kernel/ebus.c	Tue Oct 15 20:29:15 2002
@@ -247,7 +247,7 @@
 
 	mem = kmalloc(size, GFP_ATOMIC);
 	if (!mem)
-		panic(__FUNCTION__ ": out of memory");
+		panic("ebus_alloc: out of memory");
 	memset((char *)mem, 0, size);
 	return mem;
 }
diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
--- a/arch/sparc64/kernel/pci.c	Tue Oct 15 20:29:10 2002
+++ b/arch/sparc64/kernel/pci.c	Tue Oct 15 20:29:10 2002
@@ -72,10 +72,134 @@
  */
 int pci_device_reorder = 0;
 
-spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED;
 volatile int pci_poke_in_progress;
 volatile int pci_poke_cpu = -1;
 volatile int pci_poke_faulted;
+
+static spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED;
+
+void pci_config_read8(u8 *addr, u8 *ret)
+{
+	unsigned long flags;
+	u8 byte;
+
+	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "lduba [%1] %2, %0\n\t"
+			     "membar #Sync"
+			     : "=r" (byte)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+			     : "memory");
+	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
+	if (!pci_poke_faulted)
+		*ret = byte;
+	spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+void pci_config_read16(u16 *addr, u16 *ret)
+{
+	unsigned long flags;
+	u16 word;
+
+	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "lduha [%1] %2, %0\n\t"
+			     "membar #Sync"
+			     : "=r" (word)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+			     : "memory");
+	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
+	if (!pci_poke_faulted)
+		*ret = word;
+	spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+void pci_config_read32(u32 *addr, u32 *ret)
+{
+	unsigned long flags;
+	u32 dword;
+
+	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "lduwa [%1] %2, %0\n\t"
+			     "membar #Sync"
+			     : "=r" (dword)
+			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+			     : "memory");
+	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
+	if (!pci_poke_faulted)
+		*ret = dword;
+	spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+void pci_config_write8(u8 *addr, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "stba %0, [%1] %2\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+			     : "memory");
+	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
+	spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+void pci_config_write16(u16 *addr, u16 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "stha %0, [%1] %2\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+			     : "memory");
+	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
+	spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
+
+void pci_config_write32(u32 *addr, u32 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pci_poke_lock, flags);
+	pci_poke_cpu = smp_processor_id();
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "stwa %0, [%1] %2\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
+			     : "memory");
+	pci_poke_in_progress = 0;
+	pci_poke_cpu = -1;
+	spin_unlock_irqrestore(&pci_poke_lock, flags);
+}
 
 /* Probe for all PCI controllers in the system. */
 extern void sabre_init(int, char *);
diff -Nru a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
--- a/arch/sparc64/kernel/pci_impl.h	Tue Oct 15 20:29:10 2002
+++ b/arch/sparc64/kernel/pci_impl.h	Tue Oct 15 20:29:10 2002
@@ -42,132 +42,11 @@
 extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
 
 /* Configuration space access. */
-extern spinlock_t pci_poke_lock;
-extern volatile int pci_poke_in_progress;
-extern volatile int pci_poke_cpu;
-extern volatile int pci_poke_faulted;
-
-static __inline__ void pci_config_read8(u8 *addr, u8 *ret)
-{
-	unsigned long flags;
-	u8 byte;
-
-	spin_lock_irqsave(&pci_poke_lock, flags);
-	pci_poke_cpu = smp_processor_id();
-	pci_poke_in_progress = 1;
-	pci_poke_faulted = 0;
-	__asm__ __volatile__("membar #Sync\n\t"
-			     "lduba [%1] %2, %0\n\t"
-			     "membar #Sync"
-			     : "=r" (byte)
-			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
-			     : "memory");
-	pci_poke_in_progress = 0;
-	pci_poke_cpu = -1;
-	if (!pci_poke_faulted)
-		*ret = byte;
-	spin_unlock_irqrestore(&pci_poke_lock, flags);
-}
-
-static __inline__ void pci_config_read16(u16 *addr, u16 *ret)
-{
-	unsigned long flags;
-	u16 word;
-
-	spin_lock_irqsave(&pci_poke_lock, flags);
-	pci_poke_cpu = smp_processor_id();
-	pci_poke_in_progress = 1;
-	pci_poke_faulted = 0;
-	__asm__ __volatile__("membar #Sync\n\t"
-			     "lduha [%1] %2, %0\n\t"
-			     "membar #Sync"
-			     : "=r" (word)
-			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
-			     : "memory");
-	pci_poke_in_progress = 0;
-	pci_poke_cpu = -1;
-	if (!pci_poke_faulted)
-		*ret = word;
-	spin_unlock_irqrestore(&pci_poke_lock, flags);
-}
-
-static __inline__ void pci_config_read32(u32 *addr, u32 *ret)
-{
-	unsigned long flags;
-	u32 dword;
-
-	spin_lock_irqsave(&pci_poke_lock, flags);
-	pci_poke_cpu = smp_processor_id();
-	pci_poke_in_progress = 1;
-	pci_poke_faulted = 0;
-	__asm__ __volatile__("membar #Sync\n\t"
-			     "lduwa [%1] %2, %0\n\t"
-			     "membar #Sync"
-			     : "=r" (dword)
-			     : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
-			     : "memory");
-	pci_poke_in_progress = 0;
-	pci_poke_cpu = -1;
-	if (!pci_poke_faulted)
-		*ret = dword;
-	spin_unlock_irqrestore(&pci_poke_lock, flags);
-}
-
-static __inline__ void pci_config_write8(u8 *addr, u8 val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pci_poke_lock, flags);
-	pci_poke_cpu = smp_processor_id();
-	pci_poke_in_progress = 1;
-	pci_poke_faulted = 0;
-	__asm__ __volatile__("membar #Sync\n\t"
-			     "stba %0, [%1] %2\n\t"
-			     "membar #Sync"
-			     : /* no outputs */
-			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
-			     : "memory");
-	pci_poke_in_progress = 0;
-	pci_poke_cpu = -1;
-	spin_unlock_irqrestore(&pci_poke_lock, flags);
-}
-
-static __inline__ void pci_config_write16(u16 *addr, u16 val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pci_poke_lock, flags);
-	pci_poke_cpu = smp_processor_id();
-	pci_poke_in_progress = 1;
-	pci_poke_faulted = 0;
-	__asm__ __volatile__("membar #Sync\n\t"
-			     "stha %0, [%1] %2\n\t"
-			     "membar #Sync"
-			     : /* no outputs */
-			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
-			     : "memory");
-	pci_poke_in_progress = 0;
-	pci_poke_cpu = -1;
-	spin_unlock_irqrestore(&pci_poke_lock, flags);
-}
-
-static __inline__ void pci_config_write32(u32 *addr, u32 val)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&pci_poke_lock, flags);
-	pci_poke_cpu = smp_processor_id();
-	pci_poke_in_progress = 1;
-	pci_poke_faulted = 0;
-	__asm__ __volatile__("membar #Sync\n\t"
-			     "stwa %0, [%1] %2\n\t"
-			     "membar #Sync"
-			     : /* no outputs */
-			     : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L)
-			     : "memory");
-	pci_poke_in_progress = 0;
-	pci_poke_cpu = -1;
-	spin_unlock_irqrestore(&pci_poke_lock, flags);
-}
+extern void pci_config_read8(u8 *addr, u8 *ret);
+extern void pci_config_read16(u16 *addr, u16 *ret);
+extern void pci_config_read32(u32 *addr, u32 *ret);
+extern void pci_config_write8(u8 *addr, u8 val);
+extern void pci_config_write16(u16 *addr, u16 val);
+extern void pci_config_write32(u32 *addr, u32 val);
 
 #endif /* !(PCI_IMPL_H) */
diff -Nru a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c
--- a/arch/sparc64/kernel/semaphore.c	Tue Oct 15 20:29:14 2002
+++ b/arch/sparc64/kernel/semaphore.c	Tue Oct 15 20:29:14 2002
@@ -40,13 +40,57 @@
 	return old_count;
 }
 
-void __up(struct semaphore *sem)
+static void __up(struct semaphore *sem)
 {
 	__sem_update_count(sem, 1);
 	wake_up(&sem->wait);
 }
 
-void __down(struct semaphore * sem)
+void up(struct semaphore *sem)
+{
+	/* This atomically does:
+	 * 	old_val = sem->count;
+	 *	new_val = sem->count + 1;
+	 *	sem->count = new_val;
+	 *	if (old_val < 0)
+	 *		__up(sem);
+	 *
+	 * The (old_val < 0) test is equivalent to
+	 * the more straightforward (new_val <= 0),
+	 * but it is easier to test the former because
+	 * of how the CAS instruction works.
+	 */
+
+	__asm__ __volatile__("\n"
+"	! up sem(%0)\n"
+"	membar	#StoreLoad | #LoadLoad\n"
+"1:	lduw	[%0], %%g5\n"
+"	add	%%g5, 1, %%g7\n"
+"	cas	[%0], %%g5, %%g7\n"
+"	cmp	%%g5, %%g7\n"
+"	bne,pn	%%icc, 1b\n"
+"	 addcc	%%g7, 1, %%g0\n"
+"	ble,pn	%%icc, 3f\n"
+"	 membar	#StoreLoad | #StoreStore\n"
+"2:\n"
+"	.subsection 2\n"
+"3:	mov	%0, %%g5\n"
+"	save	%%sp, -160, %%sp\n"
+"	mov	%%g1, %%l1\n"
+"	mov	%%g2, %%l2\n"
+"	mov	%%g3, %%l3\n"
+"	call	%1\n"
+"	 mov	%%g5, %%o0\n"
+"	mov	%%l1, %%g1\n"
+"	mov	%%l2, %%g2\n"
+"	ba,pt	%%xcc, 2b\n"
+"	 restore %%l3, %%g0, %%g3\n"
+"	.previous\n"
+	: : "r" (sem), "i" (__up)
+	: "g5", "g7", "memory", "cc");
+}
+
+static void __down(struct semaphore * sem)
 {
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
@@ -64,7 +108,90 @@
 	wake_up(&sem->wait);
 }
 
-int __down_interruptible(struct semaphore * sem)
+void down(struct semaphore *sem)
+{
+	/* This atomically does:
+	 * 	old_val = sem->count;
+	 *	new_val = sem->count - 1;
+	 *	sem->count = new_val;
+	 *	if (old_val < 1)
+	 *		__down(sem);
+	 *
+	 * The (old_val < 1) test is equivalent to
+	 * the more straightforward (new_val < 0),
+	 * but it is easier to test the former because
+	 * of how the CAS instruction works.
+	 */
+
+	__asm__ __volatile__("\n"
+"	! down sem(%0)\n"
+"1:	lduw	[%0], %%g5\n"
+"	sub	%%g5, 1, %%g7\n"
+"	cas	[%0], %%g5, %%g7\n"
+"	cmp	%%g5, %%g7\n"
+"	bne,pn	%%icc, 1b\n"
+"	 cmp	%%g7, 1\n"
+"	bl,pn	%%icc, 3f\n"
+"	 membar	#StoreLoad | #StoreStore\n"
+"2:\n"
+"	.subsection 2\n"
+"3:	mov	%0, %%g5\n"
+"	save	%%sp, -160, %%sp\n"
+"	mov	%%g1, %%l1\n"
+"	mov	%%g2, %%l2\n"
+"	mov	%%g3, %%l3\n"
+"	call	%1\n"
+"	 mov	%%g5, %%o0\n"
+"	mov	%%l1, %%g1\n"
+"	mov	%%l2, %%g2\n"
+"	ba,pt	%%xcc, 2b\n"
+"	 restore %%l3, %%g0, %%g3\n"
+"	.previous\n"
+	: : "r" (sem), "i" (__down)
+	: "g5", "g7", "memory", "cc");
+}
+
+int down_trylock(struct semaphore *sem)
+{
+	int ret;
+
+	/* This atomically does:
+	 * 	old_val = sem->count;
+	 *	new_val = sem->count - 1;
+	 *	if (old_val < 1) {
+	 *		ret = 1;
+	 *	} else {
+	 *		sem->count = new_val;
+	 *		ret = 0;
+	 *	}
+	 *
+	 * The (old_val < 1) test is equivalent to
+	 * the more straightforward (new_val < 0),
+	 * but it is easier to test the former because
+	 * of how the CAS instruction works.
+	 */
+
+	__asm__ __volatile__("\n"
+"	! down_trylock sem(%1) ret(%0)\n"
+"1:	lduw	[%1], %%g5\n"
+"	sub	%%g5, 1, %%g7\n"
+"	cmp	%%g5, 1\n"
+"	bl,pn	%%icc, 2f\n"
+"	 mov	1, %0\n"
+"	cas	[%1], %%g5, %%g7\n"
+"	cmp	%%g5, %%g7\n"
+"	bne,pn	%%icc, 1b\n"
+"	 mov	0, %0\n"
+"	membar	#StoreLoad | #StoreStore\n"
+"2:\n"
+	: "=&r" (ret)
+	: "r" (sem)
+	: "g5", "g7", "memory", "cc");
+
+	return ret;
+}
+
+static int __down_interruptible(struct semaphore * sem)
 {
 	int retval = 0;
 	struct task_struct *tsk = current;
@@ -86,4 +213,52 @@
 	remove_wait_queue(&sem->wait, &wait);
 	wake_up(&sem->wait);
 	return retval;
+}
+
+int down_interruptible(struct semaphore *sem)
+{
+	int ret = 0;
+	
+	/* This atomically does:
+	 * 	old_val = sem->count;
+	 *	new_val = sem->count - 1;
+	 *	sem->count = new_val;
+	 *	if (old_val < 1)
+	 *		ret = __down_interruptible(sem);
+	 *
+	 * The (old_val < 1) test is equivalent to
+	 * the more straightforward (new_val < 0),
+	 * but it is easier to test the former because
+	 * of how the CAS instruction works.
+	 */
+
+	__asm__ __volatile__("\n"
+"	! down_interruptible sem(%2) ret(%0)\n"
+"1:	lduw	[%2], %%g5\n"
+"	sub	%%g5, 1, %%g7\n"
+"	cas	[%2], %%g5, %%g7\n"
+"	cmp	%%g5, %%g7\n"
+"	bne,pn	%%icc, 1b\n"
+"	 cmp	%%g7, 1\n"
+"	bl,pn	%%icc, 3f\n"
+"	 membar	#StoreLoad | #StoreStore\n"
+"2:\n"
+"	.subsection 2\n"
+"3:	mov	%2, %%g5\n"
+"	save	%%sp, -160, %%sp\n"
+"	mov	%%g1, %%l1\n"
+"	mov	%%g2, %%l2\n"
+"	mov	%%g3, %%l3\n"
+"	call	%3\n"
+"	 mov	%%g5, %%o0\n"
+"	mov	%%l1, %%g1\n"
+"	mov	%%l2, %%g2\n"
+"	mov	%%l3, %%g3\n"
+"	ba,pt	%%xcc, 2b\n"
+"	 restore %%o0, %%g0, %0\n"
+"	.previous\n"
+	: "=r" (ret)
+	: "0" (ret), "r" (sem), "i" (__down_interruptible)
+	: "g5", "g7", "memory", "cc");
+	return ret;
 }
diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Tue Oct 15 20:29:11 2002
+++ b/arch/sparc64/kernel/signal32.c	Tue Oct 15 20:29:11 2002
@@ -230,7 +230,7 @@
 	}
 }
 
-static inline int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
 	unsigned long *fpregs = current_thread_info()->fpregs;
 	unsigned long fprs;
@@ -477,7 +477,7 @@
 	return 0;
 }
 
-static inline void *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
+static void *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
 {
 	unsigned long sp;
 	
@@ -645,7 +645,7 @@
 }
 
 
-static inline int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
 	unsigned long *fpregs = current_thread_info()->fpregs;
 	unsigned long fprs;
@@ -665,8 +665,8 @@
 	return err;
 }
 
-static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
-				     int signo, sigset_t *oldset)
+static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
+			      int signo, sigset_t *oldset)
 {
 	struct new_signal_frame32 *sf;
 	int sigframe_size;
@@ -790,7 +790,7 @@
 }
 
 /* Setup a Solaris stack frame */
-static inline void
+static void
 setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
 		   struct pt_regs *regs, int signr, sigset_t *oldset)
 {
@@ -1089,9 +1089,9 @@
 	do_exit(SIGSEGV);
 }
 
-static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
-				        unsigned long signr, sigset_t *oldset,
-				        siginfo_t *info)
+static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
+			     unsigned long signr, sigset_t *oldset,
+			     siginfo_t *info)
 {
 	struct rt_signal_frame32 *sf;
 	int sigframe_size;
diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Tue Oct 15 20:29:20 2002
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Tue Oct 15 20:29:20 2002
@@ -161,9 +161,10 @@
 #endif
 
 /* semaphores */
-EXPORT_SYMBOL(__down);
-EXPORT_SYMBOL(__down_interruptible);
-EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(down);
+EXPORT_SYMBOL(down_trylock);
+EXPORT_SYMBOL(down_interruptible);
+EXPORT_SYMBOL(up);
 
 /* Atomic counter implementation. */
 EXPORT_SYMBOL(__atomic_add);
@@ -332,6 +333,7 @@
 EXPORT_SYMBOL(__memmove);
 
 EXPORT_SYMBOL(csum_partial_copy_sparc64);
+EXPORT_SYMBOL(ip_fast_csum);
 
 /* Moving data to/from userspace. */
 EXPORT_SYMBOL(__copy_to_user);
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Tue Oct 15 20:29:17 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Tue Oct 15 20:29:17 2002
@@ -273,7 +273,7 @@
     struct timeval32 it_value;
 };
 
-static inline long get_tv32(struct timeval *o, struct timeval32 *i)
+static long get_tv32(struct timeval *o, struct timeval32 *i)
 {
 	return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) ||
 		(__get_user(o->tv_sec, &i->tv_sec) |
@@ -296,7 +296,7 @@
 		 __get_user(o->it_value.tv_usec, &i->it_value.tv_usec)));
 }
 
-static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
+static long put_it32(struct itimerval32 *o, struct itimerval *i)
 {
 	return (!access_ok(VERIFY_WRITE, i32, sizeof(*i32)) ||
 		(__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
@@ -890,7 +890,7 @@
 	return sys32_fcntl(fd, cmd, arg);
 }
 
-static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
+static int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
 	int err;
 	
@@ -1272,8 +1272,7 @@
  * 64-bit unsigned longs.
  */
 
-static inline int
-get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
+static int get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
 {
 	if (ufdset) {
 		unsigned long odd;
@@ -1303,8 +1302,7 @@
 	return 0;
 }
 
-static inline void
-set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
+static void set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
 {
 	unsigned long odd;
 
@@ -2217,8 +2215,8 @@
 	return tot_len;
 }
 
-static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
-					     struct msghdr32 *umsg)
+static int msghdr_from_user32_to_kern(struct msghdr *kmsg,
+				      struct msghdr32 *umsg)
 {
 	u32 tmp1, tmp2, tmp3;
 	int err;
@@ -2599,20 +2597,33 @@
 
 	sock = sockfd_lookup(fd, &err);
 	if (sock != NULL) {
-		struct scm_cookie scm;
+		struct sock_iocb *si;
+		struct kiocb iocb;
 
 		if (sock->file->f_flags & O_NONBLOCK)
 			user_flags |= MSG_DONTWAIT;
-		memset(&scm, 0, sizeof(scm));
-		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
-					 user_flags, &scm);
+
+		init_sync_kiocb(&iocb, NULL);
+		si = kiocb_to_siocb(&iocb);
+		si->sock = sock;
+		si->scm = &si->async_scm;
+		si->msg = &kern_msg;
+		si->size = total_len;
+		si->flags = user_flags;
+		memset(si->scm, 0, sizeof(*si->scm));
+
+		err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len,
+					 user_flags, si->scm);
+		if (-EIOCBQUEUED == err)
+			err = wait_on_sync_kiocb(&iocb);
+
 		if(err >= 0) {
 			len = err;
 			if(!kern_msg.msg_control) {
-				if(sock->passcred || scm.fp)
+				if(sock->passcred || si->scm->fp)
 					kern_msg.msg_flags |= MSG_CTRUNC;
-				if(scm.fp)
-					__scm_destroy(&scm);
+				if(si->scm->fp)
+					__scm_destroy(si->scm);
 			} else {
 				/* If recvmsg processing itself placed some
 				 * control messages into user space, it's is
@@ -2626,9 +2637,10 @@
 				if(sock->passcred)
 					put_cmsg32(&kern_msg,
 						   SOL_SOCKET, SCM_CREDENTIALS,
-						   sizeof(scm.creds), &scm.creds);
-				if(scm.fp != NULL)
-					scm_detach_fds32(&kern_msg, &scm);
+						   sizeof(si->scm->creds),
+						   &si->scm->creds);
+				if(si->scm->fp != NULL)
+					scm_detach_fds32(&kern_msg, si->scm);
 			}
 		}
 		sockfd_put(sock);
diff -Nru a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
--- a/arch/sparc64/kernel/unaligned.c	Tue Oct 15 20:29:15 2002
+++ b/arch/sparc64/kernel/unaligned.c	Tue Oct 15 20:29:15 2002
@@ -149,8 +149,8 @@
 	}
 }
 
-static inline unsigned long compute_effective_address(struct pt_regs *regs,
-						      unsigned int insn, unsigned int rd)
+static unsigned long compute_effective_address(struct pt_regs *regs,
+					       unsigned int insn, unsigned int rd)
 {
 	unsigned int rs1 = (insn >> 14) & 0x1f;
 	unsigned int rs2 = insn & 0x1f;
diff -Nru a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
--- a/arch/sparc64/lib/Makefile	Tue Oct 15 20:29:12 2002
+++ b/arch/sparc64/lib/Makefile	Tue Oct 15 20:29:12 2002
@@ -10,6 +10,6 @@
 	 VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \
 	 VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \
 	 dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \
-	 U3copy_in_user.o mcount.o
+	 U3copy_in_user.o mcount.o ipcsum.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/sparc64/lib/ipcsum.S b/arch/sparc64/lib/ipcsum.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sparc64/lib/ipcsum.S	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,32 @@
+	.text
+	.align		32
+	.globl		ip_fast_csum
+ip_fast_csum:	/* %o0 = iph, %o1 = ihl */
+	sub	%o1, 4, %g7
+	lduw	[%o0 + 0x00], %o2
+	lduw	[%o0 + 0x04], %g2
+	lduw	[%o0 + 0x08], %g3
+	addcc	%g2, %o2, %o2
+	lduw	[%o0 + 0x0c], %g2
+	addccc	%g3, %o2, %o2
+	lduw	[%o0 + 0x10], %g3
+
+	addccc	%g2, %o2, %o2
+	addc	%o2, %g0, %o2
+1:	addcc	%g3, %o2, %o2
+	add	%o0, 4, %o0
+	addccc	%o2, %g0, %o2
+	subcc	%g7, 1, %g7
+	be,a,pt	%icc, 2f
+	 sll	%o2, 16, %g2
+
+	lduw	[%o0 + 0x10], %g3
+	ba,pt	%xcc, 1b
+	 nop
+2:	addcc	%o2, %g2, %g2
+	srl	%g2, 16, %o2
+	addc	%o2, %g0, %o2
+	xnor	%g0, %o2, %o2
+	set	0xffff, %o1
+	retl
+	 and	%o2, %o1, %o0
diff -Nru a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
--- a/arch/sparc64/mm/fault.c	Tue Oct 15 20:29:22 2002
+++ b/arch/sparc64/mm/fault.c	Tue Oct 15 20:29:22 2002
@@ -222,7 +222,7 @@
 extern int handle_ldf_stq(u32, struct pt_regs *);
 extern int handle_ld_nf(u32, struct pt_regs *);
 
-static inline unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn)
+static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn)
 {
 	if (!insn) {
 		if (!regs->tpc || (regs->tpc & 0x3))
diff -Nru a/arch/um/Makefile b/arch/um/Makefile
--- a/arch/um/Makefile	Tue Oct 15 20:29:12 2002
+++ b/arch/um/Makefile	Tue Oct 15 20:29:12 2002
@@ -43,22 +43,13 @@
 # in CFLAGS.  Otherwise, it would cause ld to complain about the two different
 # errnos.
 
-CFLAGS += $(DEBUG) $(PROFILE) $(ARCH_CFLAGS) -D__arch_um__ \
-	-DSUBARCH=\"$(SUBARCH)\" -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) \
-	-Derrno=kernel_errno
+CFLAGS += $(DEBUG) $(PROFILE) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+	-D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) -Derrno=kernel_errno
 
 LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
 
 SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
 
-$(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S
-	$(call if_changed_dep,as_s_S)
-
-AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \
-	-DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum
-
-LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o
-
 SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
 	include/asm-um/sigcontext.h include/asm-um/processor.h \
 	include/asm-um/ptrace.h include/asm-um/arch-signal.h
@@ -71,11 +62,25 @@
 $(ARCH_DIR)/vmlinux.lds.S :
 	touch $@
 
-linux: scripts $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \
-	arch/um/uml.lds.s $(ARCH_DIR)/main.o vmlinux
+prepare: $(ARCH_SYMLINKS) $(GEN_HEADERS)
+
+
+LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o
+
+vmlinux: $(ARCH_DIR)/main.o 
+
+
+$(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S
+	$(call if_changed_dep,as_s_S)
+
+AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \
+	-DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum
+
+linux: arch/um/uml.lds.s vmlinux
 	$(CC) -Wl,-T,arch/um/uml.lds.s -o $@ $(LINK_PROFILE) \
 	$(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil
 
+
 USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
 USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
 USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE)
@@ -125,8 +130,9 @@
 $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
 	$< > $@
 
-$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util/mk_task_user.c \
-	$(ARCH_DIR)/util/mk_task_kern.c 
-	$(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util all
+$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util FORCE ;
+
+$(ARCH_DIR)/util: FORCE
+	@$(call descend,$@,)
 
 export SUBARCH USER_CFLAGS OS
diff -Nru a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
--- a/arch/um/Makefile-i386	Tue Oct 15 20:29:14 2002
+++ b/arch/um/Makefile-i386	Tue Oct 15 20:29:14 2002
@@ -4,31 +4,28 @@
 TOP_ADDR = 0xc0000000
 endif
 
-ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH)
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
 ELF_ARCH = $(SUBARCH)
 ELF_FORMAT = elf32-$(SUBARCH)
 
+SYS_DIR		:= $(ARCH_DIR)/include/sysdep-i386
+SYS_UTIL_DIR	:= $(ARCH_DIR)/sys-i386/util
 
-SYS_HEADERS = $(ARCH_DIR)/include/sysdep-i386/sc.h \
-	$(ARCH_DIR)/include/sysdep-i386/thread.h
+SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
 
-$(ARCH_DIR)/include/sysdep-i386/sc.h : $(ARCH_DIR)/sys-i386/util/mk_sc \
-	include/asm
-	$(ARCH_DIR)/sys-i386/util/mk_sc > $@
-
-$(ARCH_DIR)/include/sysdep-i386/thread.h : $(ARCH_DIR)/sys-i386/util/mk_thread\
-	include/asm
-	$(ARCH_DIR)/sys-i386/util/mk_thread > $@
-
-$(ARCH_DIR)/sys-i386/util/mk_sc : $(ARCH_DIR)/sys-i386/util/mk_sc.c \
-	include/asm
-	$(MAKE) -C $(ARCH_DIR)/sys-i386/util mk_sc
-
-$(ARCH_DIR)/sys-i386/util/mk_thread : \
-	$(ARCH_DIR)/sys-i386/util/mk_thread_user.c \
-	$(ARCH_DIR)/sys-i386/util/mk_thread_kern.c
-	$(MAKE) -C $(ARCH_DIR)/sys-i386/util mk_thread
+prepare: $(SYS_HEADERS)
+
+$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
+	$< > $@
+
+$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread
+	$< > $@
+
+$(SYS_UTIL_DIR)/mk_sc $(SYS_UTIL_DIR)/mk_thread: $(SYS_UTIL_DIR) FORCE ; 
+
+$(SYS_UTIL_DIR): include/asm FORCE
+	@$(call descend,$@,)
 
 sysclean :
 	rm -f $(SYS_HEADERS)
-	make -C $(ARCH_DIR)/sys-i386/util clean
+	@$(call descend,$(SYS_DIR),clean)
diff -Nru a/arch/um/config.in b/arch/um/config.in
--- a/arch/um/config.in	Tue Oct 15 20:29:23 2002
+++ b/arch/um/config.in	Tue Oct 15 20:29:23 2002
@@ -28,8 +28,13 @@
 bool 'Management console' CONFIG_MCONSOLE
 dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_MCONSOLE
 bool '2G/2G host address space split' CONFIG_HOST_2G_2G
+
 bool 'Symmetric multi-processing support' CONFIG_UML_SMP
 define_bool CONFIG_SMP $CONFIG_UML_SMP
+if [ "$CONFIG_SMP" = "y" ]; then
+  int  'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32
+fi
+
 int 'Nesting level' CONFIG_NEST_LEVEL 0
 int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1
 bool 'Highmem support' CONFIG_HIGHMEM
diff -Nru a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
--- a/arch/um/drivers/chan_user.c	Tue Oct 15 20:29:11 2002
+++ b/arch/um/drivers/chan_user.c	Tue Oct 15 20:29:11 2002
@@ -155,6 +155,8 @@
 		       errno);
 }
 
+/* Called only by the tracing thread during initialization */
+
 void setup_tracer_winch(void)
 {
 	int err;
diff -Nru a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c
--- a/arch/um/drivers/harddog_kern.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/drivers/harddog_kern.c	Tue Oct 15 20:29:17 2002
@@ -51,8 +51,8 @@
 
 MODULE_LICENSE("GPL");
 
+/* Locked by the BKL in harddog_open and harddog_release */
 static int timer_alive;
-
 static int harddog_in_fd = -1;
 static int harddog_out_fd = -1;
 
@@ -67,6 +67,7 @@
 	int err;
 	char *sock = NULL;
 
+	lock_kernel();
 	if(timer_alive)
 		return -EBUSY;
 #ifdef CONFIG_HARDDOG_NOWAYOUT	 
@@ -80,6 +81,7 @@
 	if(err) return(err);
 
 	timer_alive = 1;
+	unlock_kernel();
 	return 0;
 }
 
diff -Nru a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
--- a/arch/um/drivers/hostaudio_kern.c	Tue Oct 15 20:29:16 2002
+++ b/arch/um/drivers/hostaudio_kern.c	Tue Oct 15 20:29:16 2002
@@ -15,6 +15,7 @@
 #include "init.h"
 #include "hostaudio.h"
 
+/* Only changed from linux_main at boot time */
 char *dsp = HOSTAUDIO_DEV_DSP;
 char *mixer = HOSTAUDIO_DEV_MIXER;
 
diff -Nru a/arch/um/drivers/line.c b/arch/um/drivers/line.c
--- a/arch/um/drivers/line.c	Tue Oct 15 20:29:21 2002
+++ b/arch/um/drivers/line.c	Tue Oct 15 20:29:21 2002
@@ -99,19 +99,27 @@
 	i = minor(tty->device) - tty->driver.minor_start;
 	line = &lines[i];
 
+	down(&line->sem);
 	if(line->head != line->tail){
 		local_irq_save(flags);
 		buffer_data(line, buf, len);
 		err = flush_buffer(line);
 		local_irq_restore(flags);
-		if(err <= 0) return(len);
+		if(err <= 0)
+			goto out;
 	}
 	else {
 		n = write_chan(&line->chan_list, buf, len, 
 			       line->driver->write_irq);
-		if(n < 0) return(n);
-		if(n < len) buffer_data(line, buf + n, len - n);
+		if(n < 0){
+			len = n;
+			goto out;
+		}
+		if(n < len)
+			buffer_data(line, buf + n, len - n);
 	}
+ out:
+	up(&line->sem);
 	return(len);
 }
 
@@ -249,6 +257,7 @@
 	else n = minor(tty->device) - tty->driver.minor_start;
 	line = &lines[n];
 
+	down(&line->sem);
 	line->count--;
 
 	/* I don't like this, but I can't think of anything better.  What's
@@ -261,6 +270,7 @@
 		line->tty = NULL;
 	if(line->count == 0)
 		line_disable(line, -1);
+	up(&line->sem);
 }
 
 void close_lines(struct line *lines, int nlines)
@@ -343,8 +353,6 @@
 	driver->write_room = line_write_room;
 	driver->init_termios = tty_std_termios;
 
-	driver->refcount = &set->refcount;
-
 	if (tty_register_driver(driver))
 		panic("line_register_devfs : Couldn't register driver\n");
 
@@ -408,16 +416,18 @@
 	reactivate_fd(winch->fd, WINCH_IRQ);
 }
 
+DECLARE_MUTEX(winch_handler_sem);
 LIST_HEAD(winch_handlers);
 
 void register_winch_irq(int fd, int tty_fd, int pid, void *line)
 {
 	struct winch *winch;
 
+	down(&winch_handler_sem);
 	winch = kmalloc(sizeof(*winch), GFP_KERNEL);
 	if(winch == NULL){
 		printk("register_winch_irq - kmalloc failed\n");
-		return;
+		goto out;
 	}
 	*winch = ((struct winch) { list : 	LIST_HEAD_INIT(winch->list),
 				   fd : 	fd,
@@ -429,6 +439,8 @@
 			  SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, 
 			  "winch", winch) < 0)
 		printk("register_winch_irq - failed to register IRQ\n");
+ out:
+	up(&winch_handler_sem);
 }
 
 static void winch_cleanup(void)
@@ -439,7 +451,6 @@
 	list_for_each(ele, &winch_handlers){
 		winch = list_entry(ele, struct winch, list);
 		close(winch->fd);
-		free_irq_by_fd(winch->fd);
 		if(winch->pid != -1) os_kill_process(winch->pid);
 	}
 }
diff -Nru a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
--- a/arch/um/drivers/mconsole_kern.c	Tue Oct 15 20:29:11 2002
+++ b/arch/um/drivers/mconsole_kern.c	Tue Oct 15 20:29:11 2002
@@ -40,6 +40,11 @@
 	priority:		0,
 };
 
+/* Safe without explicit locking for now.  Tasklets provide their own 
+ * locking, and the interrupt handler is safe because it can't interrupt
+ * itself and it can only happen on CPU 0.
+ */
+
 LIST_HEAD(mc_requests);
 
 void mc_work_proc(void *unused)
@@ -49,12 +54,12 @@
 	int done;
 
 	do {
-		save_flags(flags);
+		local_save_flags(flags);
 		req = list_entry(mc_requests.next, struct mconsole_entry, 
 				 list);
 		list_del(&req->list);
 		done = list_empty(&mc_requests);
-		restore_flags(flags);
+		local_irq_restore(flags);
 		req->request.cmd->handler(&req->request);
 		kfree(req);
 	} while(!done);
@@ -152,6 +157,8 @@
 	mconsole_reply(req, "", 0, 0);
 }
 
+/* This list is populated by __initcall routines. */
+
 LIST_HEAD(mconsole_devices);
 
 void mconsole_register_dev(struct mc_device *new)
@@ -224,7 +231,10 @@
 }
 #endif
 
-static char *notify_socket = NULL;
+/* Changed by mconsole_setup, which is __setup, and called before SMP is
+ * active.
+ */
+static char *notify_socket = NULL; 
 
 int mconsole_init(void)
 {
@@ -299,6 +309,18 @@
 	ent->read_proc = NULL;
 	ent->write_proc = write_proc_mconsole;
 	return(0);
+}
+
+static spinlock_t notify_spinlock = SPIN_LOCK_UNLOCKED;
+
+void lock_notify(void)
+{
+	spin_lock(&notify_spinlock);
+}
+
+void unlock_notify(void)
+{
+	spin_unlock(&notify_spinlock);
 }
 
 __initcall(create_proc_mconsole);
diff -Nru a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
--- a/arch/um/drivers/mconsole_user.c	Tue Oct 15 20:29:12 2002
+++ b/arch/um/drivers/mconsole_user.c	Tue Oct 15 20:29:12 2002
@@ -30,6 +30,7 @@
 	{ "go", mconsole_go, 1 },
 };
 
+/* Initialized in mconsole_init, which is an initcall */
 char mconsole_socket_name[256];
 
 int mconsole_reply_v0(struct mc_request *req, char *reply)
@@ -162,16 +163,21 @@
 {
 	struct sockaddr_un target;
 	struct mconsole_notify packet;
-	int n, err;
+	int n, err = 0;
 
+	lock_notify();
 	if(notify_sock < 0){
 		notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0);
 		if(notify_sock < 0){
 			printk("mconsole_notify - socket failed, errno = %d\n",
 			       errno);
-			return(-errno);
+			err = -errno;
 		}
 	}
+	unlock_notify();
+	
+	if(err)
+		return(err);
 
 	target.sun_family = AF_UNIX;
 	strcpy(target.sun_path, sock_name);
diff -Nru a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
--- a/arch/um/drivers/mmapper_kern.c	Tue Oct 15 20:29:12 2002
+++ b/arch/um/drivers/mmapper_kern.c	Tue Oct 15 20:29:12 2002
@@ -15,13 +15,14 @@
 #include <linux/mm.h> 
 #include <linux/slab.h>
 #include <linux/init.h> 
+#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include <asm/irq.h>
-#include <asm/smplock.h>
 #include <asm/pgtable.h>
 #include "mem_user.h"
 #include "user_util.h"
  
+/* These are set in mmapper_init, which is called at boot time */
 static unsigned long mmapper_size;
 static unsigned long p_buf = 0;
 static char *v_buf = NULL;
diff -Nru a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
--- a/arch/um/drivers/net_kern.c	Tue Oct 15 20:29:16 2002
+++ b/arch/um/drivers/net_kern.c	Tue Oct 15 20:29:16 2002
@@ -27,6 +27,7 @@
 #include "init.h"
 #include "irq_user.h"
 
+static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED;
 LIST_HEAD(opened);
 
 static int uml_net_rx(struct net_device *dev)
@@ -118,7 +119,9 @@
 	lp->tl.data = (unsigned long) &lp->user;
 	netif_start_queue(dev);
 
+	spin_lock(&opened_lock);
 	list_add(&lp->list, &opened);
+	spin_unlock(&opened_lock);
 	MOD_INC_USE_COUNT;
  out:
 	spin_unlock(&lp->lock);
@@ -135,8 +138,10 @@
 	free_irq(dev->irq, dev);
 	if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
 	lp->fd = -1;
+	spin_lock(&opened_lock);
 	list_del(&lp->list);
-	
+	spin_unlock(&opened_lock);
+
 	MOD_DEC_USE_COUNT;
 	spin_unlock(&lp->lock);
 	return 0;
@@ -245,6 +250,7 @@
 #endif
 }
 
+static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
 static struct list_head devices = LIST_HEAD_INIT(devices);
 
 static int eth_configure(int n, void *init, char *mac,
@@ -261,7 +267,10 @@
 		return(1);
 	}
 
+	spin_lock(&devices_lock);
 	list_add(&device->list, &devices);
+	spin_unlock(&devices_lock);
+
 	device->index = n;
 
 	size = transport->private_size + sizeof(struct uml_net_private) + 
@@ -373,12 +382,16 @@
 	struct uml_net *device;
 	struct list_head *ele;
 
+	spin_lock(&devices_lock);
 	list_for_each(ele, &devices){
 		device = list_entry(ele, struct uml_net, list);
 		if(device->index == n)
-			return(device);
+			goto out;
 	}
-	return(NULL);
+	device = NULL;
+ out:
+	spin_unlock(&devices_lock);
+	return(device);
 }
 
 static int eth_parse(char *str, int *index_out, char **str_out)
@@ -418,8 +431,12 @@
 	int index;
 };
 
+/* Filled in at boot time.  Will need locking if the transports become
+ * modular.
+ */
 struct list_head transports = LIST_HEAD_INIT(transports);
 
+/* Filled in during early boot */
 struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
 
 static int check_transport(struct transport *transport, char *eth, int n,
@@ -518,8 +535,6 @@
 "eth[0-9]+=<transport>,<options>\n"
 "    Configure a network device.\n\n"
 );
-
-int ndev = 0;
 
 static int eth_init(void)
 {
diff -Nru a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
--- a/arch/um/drivers/port_kern.c	Tue Oct 15 20:29:12 2002
+++ b/arch/um/drivers/port_kern.c	Tue Oct 15 20:29:12 2002
@@ -62,8 +62,6 @@
 	up(&conn->port->sem);
 }
 
-struct list_head ports = LIST_HEAD_INIT(ports);
-
 static void port_interrupt(int irq, void *data, struct pt_regs *regs)
 {
 	struct port_list *port = data;
@@ -107,6 +105,9 @@
 	reactivate_fd(port->fd, ACCEPT_IRQ);
 } 
 
+DECLARE_MUTEX(ports_sem);
+struct list_head ports = LIST_HEAD_INIT(ports);
+
 void *port_data(int port_num)
 {
 	struct list_head *ele;
@@ -114,6 +115,7 @@
 	struct port_dev *dev;
 	int fd;
 
+	down(&ports_sem);
 	list_for_each(ele, &ports){
 		port = list_entry(ele, struct port_list, list);
 		if(port->port == port_num) goto found;
@@ -121,7 +123,7 @@
 	port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
 	if(port == NULL){
 		printk(KERN_ERR "Allocation of port list failed\n");
-		return(NULL);
+		goto out;
 	}
 
 	fd = port_listen_fd(port_num);
@@ -151,18 +153,21 @@
 	dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
 	if(dev == NULL){
 		printk(KERN_ERR "Allocation of port device entry failed\n");
-		return(NULL);
+		goto out;
 	}
 
  	*dev = ((struct port_dev) { port : 		port,
  				    fd :		-1,
  				    helper_pid : 	-1 });
+	up(&ports_sem);
 	return(dev);
 
  out_free:
 	kfree(port);
  out_close:
 	os_close_file(fd);
+ out:
+	up(&ports_sem);
 	return(NULL);
 }
 
@@ -184,7 +189,6 @@
 
 	list_for_each(ele, &ports){
 		port = list_entry(ele, struct port_list, list);
- 		free_irq(ACCEPT_IRQ, port);
 		os_close_file(port->fd);
 	}
 }
diff -Nru a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
--- a/arch/um/drivers/ssl.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/drivers/ssl.c	Tue Oct 15 20:29:17 2002
@@ -24,10 +24,13 @@
 
 static int ssl_version = 1;
 
-static struct tty_driver ssl_driver;
-
+/* Referenced only by tty_driver below - presumably it's locked correctly
+ * by the tty driver.
+ */
 static int ssl_refcount = 0;
 
+static struct tty_driver ssl_driver;
+
 #define NR_PORTS 64
 
 void ssl_announce(char *dev_name, int dev)
@@ -58,7 +61,10 @@
 	symlink_to :		"tts",
 };
 
-static struct line serial_lines[NR_PORTS] = 
+/* The array is initialized by line_init, which is an initcall.  The 
+ * individual elements are protected by individual semaphores.
+ */
+static struct line serial_lines[NR_PORTS] =
 	{ [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) };
 
 static struct lines lines = LINES_INIT(NR_PORTS);
@@ -153,6 +159,27 @@
 {
 }
 
+static struct tty_driver ssl_driver = {
+	refcount :		&ssl_refcount,
+	open :	 		ssl_open,
+	close :	 		ssl_close,
+	write :	 		ssl_write,
+	put_char :		ssl_put_char,
+	flush_chars :		ssl_flush_chars,
+	chars_in_buffer :	ssl_chars_in_buffer,
+	flush_buffer :		ssl_flush_buffer,
+	ioctl :	 		ssl_ioctl,
+	throttle :		ssl_throttle,
+	unthrottle :		ssl_unthrottle,
+	set_termios :		ssl_set_termios,
+	stop :	 		ssl_stop,
+	start :	 		ssl_start,
+	hangup :	 	ssl_hangup
+};
+
+/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
+ * by being an initcall and exitcall, respectively.
+ */
 static int ssl_init_done = 0;
 
 int ssl_init(void)
@@ -161,25 +188,6 @@
 
 	printk(KERN_INFO "Initializing software serial port version %d\n", 
 	       ssl_version);
-
-	ssl_driver = ((struct tty_driver)
-		      {
-			      refcount :	&ssl_refcount,
-			      open :	 	ssl_open,
-			      close :	 	ssl_close,
-			      write :	 	ssl_write,
-			      put_char :	ssl_put_char,
-			      flush_chars :	ssl_flush_chars,
-			      chars_in_buffer :	ssl_chars_in_buffer,
-			      flush_buffer :	ssl_flush_buffer,
-			      ioctl :	 	ssl_ioctl,
-			      throttle :	ssl_throttle,
-			      unthrottle :	ssl_unthrottle,
-			      set_termios :	ssl_set_termios,
-			      stop :	 	ssl_stop,
-			      start :	 	ssl_start,
-			      hangup :	 	ssl_hangup
-		      });
 
 	line_register_devfs(&lines, &driver, &ssl_driver, serial_lines, 
 			    sizeof(serial_lines)/sizeof(serial_lines[0]));
diff -Nru a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
--- a/arch/um/drivers/stdio_console.c	Tue Oct 15 20:29:14 2002
+++ b/arch/um/drivers/stdio_console.c	Tue Oct 15 20:29:14 2002
@@ -32,8 +32,14 @@
 
 #define MAX_TTYS (8)
 
+/* Referenced only by tty_driver below - presumably it's locked correctly
+ * by the tty driver.
+ */
+
 static struct tty_driver console_driver;
 
+static int console_refcount = 0;
+
 static struct chan_ops init_console_ops = {
 	init : 		NULL,
 	open : 		NULL,
@@ -88,6 +94,9 @@
 
 static struct lines console_lines = LINES_INIT(MAX_TTYS);
 
+/* The array is initialized by line_init, which is an initcall.  The 
+ * individual elements are protected by individual semaphores.
+ */
 struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver),
 			      [ 1 ... MAX_TTYS - 1 ] = 
 			      LINE_INIT(CONFIG_CON_CHAN, &driver) };
@@ -130,15 +139,6 @@
 
 	printk(KERN_INFO "Initializing stdio console driver\n");
 
-	console_driver = ((struct tty_driver)
-		      {
-			      open :	 	con_open,
-			      close :	 	con_close,
-			      write :	 	con_write,
-			      chars_in_buffer :	chars_in_buffer,
-			      set_termios :	set_termios
-		      });
-
 	line_register_devfs(&console_lines, &driver, &console_driver, vts, 
 			    sizeof(vts)/sizeof(vts[0]));
 
@@ -157,9 +157,20 @@
 static void console_write(struct console *console, const char *string, 
 			  unsigned len)
 {
+	if(con_init_done) down(&vts[console->index].sem);
 	console_write_chan(&vts[console->index].chan_list, string, len);
+	if(con_init_done) up(&vts[console->index].sem);
 }
 
+static struct tty_driver console_driver = {
+	refcount :		&console_refcount,
+	open :	 		con_open,
+	close :	 		con_close,
+	write :	 		con_write,
+	chars_in_buffer :	chars_in_buffer,
+	set_termios :		set_termios
+};
+
 static kdev_t console_device(struct console *c)
 {
 	return mk_kdev(TTY_MAJOR, c->index);
@@ -193,7 +204,6 @@
 static void console_exit(void)
 {
 	if(!con_init_done) return;
-	line_close(vts, NULL);
 	close_lines(vts, sizeof(vts)/sizeof(vts[0]));
 }
 
diff -Nru a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
--- a/arch/um/drivers/ubd_kern.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/drivers/ubd_kern.c	Tue Oct 15 20:29:17 2002
@@ -25,6 +25,7 @@
 #include "linux/vmalloc.h"
 #include "linux/blkpg.h"
 #include "linux/genhd.h"
+#include "linux/spinlock.h"
 #include "asm/segment.h"
 #include "asm/uaccess.h"
 #include "asm/irq.h"
@@ -41,7 +42,9 @@
 #include "2_5compat.h"
 #include "os.h"
 
-static spinlock_t ubd_lock;
+static spinlock_t ubd_io_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED;
+
 static void (*do_ubd)(void);
 
 static int ubd_open(struct inode * inode, struct file * filp);
@@ -62,9 +65,12 @@
         .revalidate =	ubd_revalidate,
 };
 
+/* Protected by the queue_lock */
 static request_queue_t *ubd_queue;
 
+/* Protected by ubd_lock */
 static int fake_major = 0;
+
 static struct gendisk *ubd_gendisk[MAX_DEV];
 static struct gendisk *fake_gendisk[MAX_DEV];
  
@@ -74,6 +80,9 @@
 #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0 })
 #endif
 
+/* Not protected - changed only in ubd_setup_common and then only to
+ * to enable O_SYNC.
+ */
 static struct openflags global_openflags = OPEN_FLAGS;
 
 struct cow {
@@ -130,12 +139,7 @@
 
 __initcall(ubd0_init);
 
-static struct hd_driveid ubd_id = {
-        .cyls =		0,
-	.heads =	128,
-	.sectors =	32,
-};
-
+/* Only changed by fake_ide_setup which is a setup */
 static int fake_ide = 0;
 static struct proc_dir_entry *proc_ide_root = NULL;
 static struct proc_dir_entry *proc_ide = NULL;
@@ -161,7 +165,6 @@
 	else len = count;
 	*start = page + off;
 	return len;
-	
 }
 
 static void make_ide_entries(char *dev_name)
@@ -170,7 +173,9 @@
 	char name[64];
 
 	if(!fake_ide) return;
+
 	if(proc_ide_root == NULL) make_proc_ide();
+
 	dir = proc_mkdir(dev_name, proc_ide);
 	ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir);
 	if(!ent) return;
@@ -199,7 +204,7 @@
 {
 	struct openflags flags = global_openflags;
 	char *backing_file;
-	int n;
+	int n, err;
 
 	if(index_out) *index_out = -1;
 	n = *str++;
@@ -224,12 +229,22 @@
 			return(1);
 		}
 
-		fake_major = major;
+		err = 1;
+ 		spin_lock(&ubd_lock);
+ 		if(!fake_major_allowed){
+ 			printk(KERN_ERR "Can't assign a fake major twice\n");
+ 			goto out1;
+ 		}
+ 
+ 		fake_major = major;
 		fake_major_allowed = 0;
 
 		printk(KERN_INFO "Setting extra ubd major number to %d\n",
 		       major);
-		return(0);
+ 		err = 0;
+ 	out1:
+ 		spin_unlock(&ubd_lock);
+		return(err);
 	}
 
 	if(n < '0'){
@@ -247,9 +262,12 @@
 		return(1);
 	}
 
+	err = 1;
+	spin_lock(&ubd_lock);
+
 	if(ubd_dev[n].file != NULL){
 		printk(KERN_ERR "ubd_setup : device already configured\n");
-		return(1);
+		goto out2;
 	}
 
 	if(index_out) *index_out = n;
@@ -264,8 +282,10 @@
 	}
 	if(*str++ != '='){
 		printk(KERN_ERR "ubd_setup : Expected '='\n");
-		return(1);
+		goto out2;
 	}
+
+	err = 0;
 	backing_file = strchr(str, ',');
 	if(backing_file){
 		*backing_file = '\0';
@@ -276,7 +296,9 @@
 		ubd_dev[n].is_dir = 1;
 	ubd_dev[n].cow.file = backing_file;
 	ubd_dev[n].boot_openflags = flags;
-	return(0);
+ out2:
+	spin_unlock(&ubd_lock);
+	return(err);
 }
 
 static int ubd_setup(char *str)
@@ -317,8 +339,12 @@
 
 static void do_ubd_request(request_queue_t * q);
 
+/* Only changed by ubd_init, which is an initcall. */
 int thread_fd = -1;
 
+/* Changed by ubd_handler, which is serialized because interrupts only
+ * happen on CPU 0.
+ */
 int intr_count = 0;
 
 static void ubd_finish(int error)
@@ -326,7 +352,9 @@
 	int nsect;
 
 	if(error){
+ 		spin_lock(&ubd_io_lock);
 		end_request(CURRENT, 0);
+ 		spin_unlock(&ubd_io_lock);
 		return;
 	}
 	nsect = CURRENT->current_nr_sectors;
@@ -335,7 +363,9 @@
 	CURRENT->errors = 0;
 	CURRENT->nr_sectors -= nsect;
 	CURRENT->current_nr_sectors = 0;
+	spin_lock(&ubd_io_lock);
 	end_request(CURRENT, 1);
+	spin_unlock(&ubd_io_lock);
 }
 
 static void ubd_handler(void)
@@ -349,9 +379,9 @@
 	if(n != sizeof(req)){
 		printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
 		       "errno = %d\n", os_getpid(), -n);
-		spin_lock(&ubd_lock);
+		spin_lock(&ubd_io_lock);
 		end_request(CURRENT, 0);
-		spin_unlock(&ubd_lock);
+		spin_unlock(&ubd_io_lock);
 		return;
 	}
         
@@ -359,11 +389,9 @@
 	   (req.length != (CURRENT->current_nr_sectors) << 9))
 		panic("I/O op mismatch");
 	
-	spin_lock(&ubd_lock);
 	ubd_finish(req.error);
 	reactivate_fd(thread_fd, UBD_IRQ);	
 	do_ubd_request(ubd_queue);
-	spin_unlock(&ubd_lock);
 }
 
 static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
@@ -371,6 +399,7 @@
 	ubd_handler();
 }
 
+/* Only changed by ubd_init, which is an initcall. */
 static int io_pid = -1;
 
 void kill_io_thread(void)
@@ -380,8 +409,6 @@
 
 __uml_exitcall(kill_io_thread);
 
-int sync = 0;
-
 static int ubd_file_size(struct ubd *dev, __u64 *size_out)
 {
 	char *file;
@@ -390,6 +417,7 @@
 	return(os_file_size(file, size_out));
 }
 
+/* Initialized in an initcall, and unchanged thereafter */
 devfs_handle_t ubd_dir_handle;
 devfs_handle_t ubd_fake_dir_handle;
 
@@ -402,14 +430,13 @@
 	u64 size;
 
 	if (!dev->file)
-		return -1;
+		goto out;
 
-	disk = alloc_disk();
+	disk = alloc_disk(1 << UBD_SHIFT);
 	if (!disk)
 		return -1;
 	disk->major = MAJOR_NR;
 	disk->first_minor = n << UBD_SHIFT;
-	disk->minor_shift = UBD_SHIFT;
 	disk->fops = &ubd_blops;
 	if (fakehd_set)
 		sprintf(disk->disk_name, "hd%c", n + 'a');
@@ -417,14 +444,13 @@
 		sprintf(disk->disk_name, "ubd%d", n);
 
 	if (fake_major) {
-		fake_disk = alloc_disk();
+		fake_disk = alloc_disk(1 << UBD_SHIFT);
 		if (!fake_disk) {
 			put_disk(disk);
 			return -1;
 		}
 		fake_disk->major = fake_major;
 		fake_disk->first_minor = n << UBD_SHIFT;
-		fake_disk->minor_shift = UBD_SHIFT;
 		fake_disk->fops = &ubd_blops;
 		sprintf(fake_disk->disk_name, "ubd%d", n);
 		fake_gendisk[n] = fake_disk;
@@ -443,23 +469,32 @@
 			      MAJOR_NR, n << UBD_SHIFT,
 			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP,
 			      &ubd_blops, NULL);
-	add_disk(disk);
+ 	if(real == NULL) 
+ 		goto out;
+ 	ubd_dev[n].real = real;
+
 	if (fake_major) {
 		fake = devfs_register(ubd_fake_dir_handle, name, 
 				      DEVFS_FL_REMOVABLE, fake_major,
 				      n << UBD_SHIFT, 
 				      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |
 				      S_IWGRP, &ubd_blops, NULL);
-		add_disk(fake_disk);
- 		if(fake == NULL) return(-1);
+ 		if(fake == NULL)
+			goto out_unregister;
+
  		ubd_dev[n].fake = fake;
+		add_disk(fake_disk);
 	}
  
- 	if(real == NULL) return(-1);
- 	ubd_dev[n].real = real;
- 
+	add_disk(disk);
 	make_ide_entries(disk->disk_name);
 	return(0);
+
+ out_unregister:
+	devfs_unregister(real);
+	ubd_dev[n].real = NULL;
+ out:
+	return(-1);
 }
 
 static int ubd_config(char *str)
@@ -478,24 +513,29 @@
 	}
 	if(n == -1) return(0);
 
+ 	spin_lock(&ubd_lock);
 	err = ubd_add(n);
-	if(err){
+	if(err)
 		ubd_dev[n].file = NULL;
-		return(err);
-	}
+ 	spin_unlock(&ubd_lock);
 
-	return(0);
+	return(err);
 }
 
 static int ubd_remove(char *str)
 {
 	struct ubd *dev;
-	int n;
+	int n, err;
 
-	if(!isdigit(*str)) return(-1);
+	if(!isdigit(*str)) 
+		return(-1);
 	n = *str - '0';
-	if(n > MAX_DEV) return(-1);
+	if(n > MAX_DEV) 
+		return(-1);
 	dev = &ubd_dev[n];
+
+	err = 0;
+ 	spin_lock(&ubd_lock);
 	del_gendisk(ubd_gendisk[n]);
 	put_disk(ubd_gendisk[n]);
 	ubd_gendisk[n] = NULL;
@@ -504,12 +544,20 @@
 		put_disk(fake_gendisk[n]);
 		fake_gendisk[n] = NULL;
 	}
-	if(dev->file == NULL) return(0);
-	if(dev->count > 0) return(-1);
-	if(dev->real != NULL) devfs_unregister(dev->real);
-	if(dev->fake != NULL) devfs_unregister(dev->fake);
+	if(dev->file == NULL)
+		goto out;
+	err = -1;
+	if(dev->count > 0)
+		goto out;
+	if(dev->real != NULL) 
+		devfs_unregister(dev->real);
+	if(dev->fake != NULL) 
+		devfs_unregister(dev->fake);
 	*dev = ((struct ubd) DEFAULT_UBD);
-	return(0);
+	err = 0;
+ out:
+ 	spin_unlock(&ubd_lock);
+	return(err);
 }
 
 static struct mc_device ubd_mc = {
@@ -541,7 +589,7 @@
 		return -1;
 	}
 	ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
-	INIT_QUEUE(ubd_queue, do_ubd_request, &ubd_lock);
+	blk_init_queue(ubd_queue, do_ubd_request, &ubd_io_lock);
 	elevator_init(ubd_queue, &elevator_noop);
 	if(fake_major != 0){
 		char name[sizeof("ubd_nnn\0")];
@@ -566,7 +614,7 @@
 	unsigned long stack;
 	int err;
 
-	if(sync){
+	if(global_openflags.s){
 		printk(KERN_INFO "ubd : Synchronous mode\n");
 		return(0);
 	}
@@ -590,9 +638,9 @@
 
 static void ubd_close(struct ubd *dev)
 {
-	close_fd(dev->fd);
+	os_close_file(dev->fd);
 	if(dev->cow.file != NULL) {
-		close_fd(dev->cow.fd);
+		os_close_file(dev->cow.fd);
 		vfree(dev->cow.bitmap);
 		dev->cow.bitmap = NULL;
 	}
@@ -644,22 +692,17 @@
 	}
 	return(0);
  error:
-	close_fd(dev->fd);
+	os_close_file(dev->fd);
 	return(err);
 }
 
 static int ubd_open(struct inode *inode, struct file *filp)
 {
-	struct ubd *dev;
-	int n, offset, err;
-
-	n = DEVICE_NR(inode->i_rdev);
-	dev = &ubd_dev[n];
-	if(n > MAX_DEV)
-		return -ENODEV;
-	offset = n << UBD_SHIFT;
+	int n = DEVICE_NR(inode->i_rdev);
+	struct ubd *dev = &ubd_dev[n];
+	int err;
 	if(dev->is_dir == 1)
-		return(0);
+		goto out;
 
 	if(dev->count == 0){
 		dev->openflags = dev->boot_openflags;
@@ -668,36 +711,26 @@
 		if(err){
 			printk(KERN_ERR "ubd%d: Can't open \"%s\": "
 			       "errno = %d\n", n, dev->file, -err);
-			return(err);
+			goto out;
 		}
-		if(err) return(err);
 	}
 	dev->count++;
 	if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){
 	        if(--dev->count == 0) ubd_close(dev);
-	        return -EROFS;
+	        err = -EROFS;
 	}
-	return(0);
+ out:
+	return(err);
 }
 
 static int ubd_release(struct inode * inode, struct file * file)
 {
-        int n, offset;
-
-	n = DEVICE_NR(inode->i_rdev);
-	offset = n << UBD_SHIFT;
-	if(n > MAX_DEV)
-		return -ENODEV;
-
+        int n = DEVICE_NR(inode->i_rdev);
 	if(--ubd_dev[n].count == 0)
 		ubd_close(&ubd_dev[n]);
-
 	return(0);
 }
 
-int cow_read = 0;
-int cow_write = 0;
-
 void cowify_req(struct io_thread_req *req, struct ubd *dev)
 {
         int i, update_bitmap, sector = req->offset >> 9;
@@ -710,14 +743,12 @@
 					dev->cow.bitmap)){
 				ubd_set_bit(i, (unsigned char *) 
 					    &req->sector_mask);
-				cow_read++;
 			}
                 }
         } 
         else {
 		update_bitmap = 0;
 		for(i = 0; i < req->length >> 9; i++){
-			cow_write++;
 			ubd_set_bit(i, (unsigned char *) 
 				    &req->sector_mask);
 			if(!ubd_test_bit(sector + i, (unsigned char *) 
@@ -752,13 +783,17 @@
 	if(dev->is_dir){
 		strcpy(req->buffer, "HOSTFS:");
 		strcat(req->buffer, dev->file);
+ 		spin_lock(&ubd_io_lock);
 		end_request(req, 1);
+ 		spin_unlock(&ubd_io_lock);
 		return(1);
 	}
 
 	if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
 		printk("Write attempted on readonly ubd device %d\n", n);
+ 		spin_lock(&ubd_io_lock);
 		end_request(req, 0);
+ 		spin_unlock(&ubd_io_lock);
 		return(1);
 	}
 
@@ -819,6 +854,12 @@
 	struct hd_geometry *loc = (struct hd_geometry *) arg;
  	struct ubd *dev;
 	int n, min, err;
+	struct hd_driveid ubd_id = {
+		.cyls =		0,
+		.heads =	128,
+		.sectors =	32,
+	};
+
 
         if(!inode) return(-EINVAL);
 	min = minor(inode->i_rdev);
@@ -892,8 +933,11 @@
 
 	n = minor(rdev) >> UBD_SHIFT;
 	dev = &ubd_dev[n];
+
+	err = 0;
+	spin_lock(&ubd_lock);
 	if(dev->is_dir) 
-		return(0);
+		goto out;
 	
 	err = ubd_file_size(dev, &size);
 	if (!err) {
@@ -902,7 +946,8 @@
 			set_capacity(fake_gendisk[n], size / 512);
 		dev->size = size;
 	}
-
+ out:
+	spin_unlock(&ubd_lock);
 	return err;
 }
 
diff -Nru a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
--- a/arch/um/drivers/ubd_user.c	Tue Oct 15 20:29:14 2002
+++ b/arch/um/drivers/ubd_user.c	Tue Oct 15 20:29:14 2002
@@ -533,8 +533,12 @@
 	return;
 }
 
+/* Changed in start_io_thread, which is serialized by being called only
+ * from ubd_init, which is an initcall.
+ */
 int kernel_fd = -1;
 
+/* Only changed by the io thread */
 int io_count = 0;
 
 int io_thread(void *arg)
diff -Nru a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
--- a/arch/um/drivers/xterm.c	Tue Oct 15 20:29:12 2002
+++ b/arch/um/drivers/xterm.c	Tue Oct 15 20:29:12 2002
@@ -44,6 +44,7 @@
 	return(data);
 }
 
+/* Only changed by xterm_setup, which is a setup */
 static char *terminal_emulator = "xterm";
 static char *title_switch = "-T";
 static char *exec_switch = "-e";
diff -Nru a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h
--- a/arch/um/include/2_5compat.h	Tue Oct 15 20:29:16 2002
+++ b/arch/um/include/2_5compat.h	Tue Oct 15 20:29:16 2002
@@ -20,8 +20,6 @@
 	next :		NULL \
 }
 
-#define INIT_QUEUE(queue, request, lock) blk_init_queue(queue, request, lock)
-
 #define INIT_HARDSECT(arr, maj, sizes)
 
 #define SET_PRI(task) do ; while(0)
diff -Nru a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h
--- a/arch/um/include/irq_user.h	Tue Oct 15 20:29:17 2002
+++ b/arch/um/include/irq_user.h	Tue Oct 15 20:29:17 2002
@@ -18,7 +18,9 @@
 extern void init_irq_signals(int on_sigstack);
 extern void forward_ipi(int fd, int pid);
 extern void free_irq_later(int irq, void *dev_id);
-
+extern int activate_ipi(int fd, int pid);
+extern unsigned long irq_lock(void);
+extern void irq_unlock(unsigned long flags);
 #endif
 
 /*
diff -Nru a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
--- a/arch/um/include/kern_util.h	Tue Oct 15 20:29:16 2002
+++ b/arch/um/include/kern_util.h	Tue Oct 15 20:29:16 2002
@@ -50,12 +50,8 @@
 extern void block_signals(void);
 extern void unblock_signals(void);
 extern void deliver_signals(void *t);
-extern void lock_syscall(void);
-extern void unlock_syscall(void);
-extern void lock_trap(void);
-extern void unlock_trap(void);
-extern void lock_pid(void);
-extern void unlock_pid(void);
+extern int next_syscall_index(int max);
+extern int next_trap_index(int max);
 extern void default_idle(void);
 extern void finish_fork(void);
 extern void paging_init(void);
@@ -121,7 +117,7 @@
 extern int is_valid_pid(int pid);
 extern void free_irq(unsigned int, void *);
 extern int um_in_interrupt(void);
-
+extern int cpu(void);
 #endif
 
 /*
diff -Nru a/arch/um/include/line.h b/arch/um/include/line.h
--- a/arch/um/include/line.h	Tue Oct 15 20:29:19 2002
+++ b/arch/um/include/line.h	Tue Oct 15 20:29:19 2002
@@ -61,12 +61,9 @@
 
 struct lines {
 	int num;
-	int refcount;
 };
 
-#define LINES_INIT(n) \
-	{  num :		n, \
-	   refcount :		0 }
+#define LINES_INIT(n) {  num :		n }
 
 extern void line_interrupt(int irq, void *data, struct pt_regs *unused);
 extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
diff -Nru a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h
--- a/arch/um/include/mconsole.h	Tue Oct 15 20:29:16 2002
+++ b/arch/um/include/mconsole.h	Tue Oct 15 20:29:16 2002
@@ -77,6 +77,8 @@
 extern int mconsole_notify(char *sock_name, int type, const void *data, 
 			   int len);
 extern char *mconsole_notify_socket(void);
+extern void lock_notify(void);
+extern void unlock_notify(void);
 
 #endif
 
diff -Nru a/arch/um/include/sigio.h b/arch/um/include/sigio.h
--- a/arch/um/include/sigio.h	Tue Oct 15 20:29:12 2002
+++ b/arch/um/include/sigio.h	Tue Oct 15 20:29:12 2002
@@ -11,6 +11,8 @@
 extern int read_sigio_fd(int fd);
 extern int add_sigio_fd(int fd, int read);
 extern int ignore_sigio_fd(int fd);
+extern void sigio_lock(void);
+extern void sigio_unlock(void);
 
 #endif
 
diff -Nru a/arch/um/include/tempfile.h b/arch/um/include/tempfile.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/include/tempfile.h	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,21 @@
+/* 
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TEMPFILE_H__
+#define __TEMPFILE_H__
+
+extern int make_tempfile(const char *template, char **tempname, int do_unlink);
+
+#endif
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/include/time_user.h b/arch/um/include/time_user.h
--- a/arch/um/include/time_user.h	Tue Oct 15 20:29:12 2002
+++ b/arch/um/include/time_user.h	Tue Oct 15 20:29:12 2002
@@ -7,11 +7,11 @@
 #define __TIME_USER_H__
 
 extern void timer(void);
-extern void get_profile_timer(void);
-extern void disable_profile_timer(void);
 extern void switch_timers(int to_real);
 extern void user_time_init(void);
-extern void set_timers(int set_signal);
 extern void idle_sleep(int secs);
+extern void enable_timer(void);
+extern void time_lock(void);
+extern void time_unlock(void);
 
 #endif
diff -Nru a/arch/um/include/user_util.h b/arch/um/include/user_util.h
--- a/arch/um/include/user_util.h	Tue Oct 15 20:29:12 2002
+++ b/arch/um/include/user_util.h	Tue Oct 15 20:29:12 2002
@@ -48,32 +48,21 @@
 extern int pty_output_sigio;
 extern int pty_close_sigio;
 
-extern void *open_maps(void);
-extern void close_maps(void *fd);
-extern unsigned long get_brk(void);
 extern void stop(void);
-extern int proc_start_thread(unsigned long ip, unsigned long sp);
 extern void stack_protections(unsigned long address);
 extern void task_protections(unsigned long address);
-extern void abandon_proc_space(int (*proc)(void *), unsigned long sp);
 extern int signals(int (*init_proc)(void *), void *sp);
-extern int __personality(int);
 extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
 extern void *add_signal_handler(int sig, void (*handler)(int));
-extern void signal_init(void);
 extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
 			    int clone_flags, int (*tramp)(void *));
 extern void trace_myself(void);
 extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
-extern int input_loop(void);
-extern void continue_execing_proc(int pid);
 extern int linux_main(int argc, char **argv);
 extern void remap_data(void *segment_start, void *segment_end, int w);
 extern void set_cmdline(char *cmd);
 extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
-extern void setup_input(void);
 extern int get_pty(void);
-extern void save_signal_state(int *sig_ptr);
 extern void *um_kmalloc(int size);
 extern int raw(int fd, int complain);
 extern int switcheroo(int fd, int prot, void *from, void *to, int size);
@@ -82,15 +71,11 @@
 extern void add_arg(char *cmd_line, char *arg);
 extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int));
 extern void attach_process(int pid);
-extern void calc_sigframe_size(void);
 extern int fork_tramp(void *sig_stack);
 extern void do_exec(int old_pid, int new_pid);
 extern void tracer_panic(char *msg, ...);
-extern void close_fd(int);
-extern int make_tempfile(const char *template, char **tempname, int do_unlink);
 extern char *get_umid(int only_if_set);
 extern void do_longjmp(void *p);
-extern void term_handler(int sig);
 extern void suspend_new_thread(int fd);
 extern int detach(int pid, int sig);
 extern int attach(int pid);
@@ -99,12 +84,9 @@
 extern void check_ptrace(void);
 extern void check_sigio(void);
 extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
-extern int user_read(int fd, char *buf, int len);
-extern int user_write(int fd, char *buf, int len);
 extern void write_sigio_workaround(void);
 extern void arch_check_bugs(void);
 extern int arch_handle_signal(int sig, struct uml_pt_regs *regs);
-extern unsigned long pid_pc(int pid);
 extern int arch_fixup(unsigned long address, void *sc_ptr);
 extern void forward_pending_sigio(int target);
 
diff -Nru a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
--- a/arch/um/kernel/Makefile	Tue Oct 15 20:29:19 2002
+++ b/arch/um/kernel/Makefile	Tue Oct 15 20:29:19 2002
@@ -3,9 +3,9 @@
 
 obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \
 	helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \
-	process.o process_kern.o ptrace.o reboot.o resource.o setup.o \
-	sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
-	syscall_kern.o syscall_user.o sysrq.o sys_call_table.o time.o \
+	process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \
+	sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \
+	syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \
 	time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \
 	umid.o user_util.o
 
@@ -14,8 +14,8 @@
 # user_syms.o not included here because Rules.make has its own ideas about
 # building anything in export-objs
 
-USER_OBJS := $(filter %_user.o,$(obj-y)) config.o frame.o helper.o process.o \
-	time.o tty_log.o umid.o user_util.o user_syms.o
+USER_OBJS := $(filter %_user.o,$(obj-y)) config.o helper.o process.o \
+	tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o
 USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file))
 
 export-objs := ksyms.o process_kern.o signal_kern.o gprof_syms.o gmon_syms.o
@@ -50,6 +50,9 @@
 
 arch/um/kernel/unmap_fin.o : arch/um/kernel/unmap.o
 	ld -r -o $@ $< -lc -L/usr/lib
+
+arch/um/kernel/frame.o: arch/um/kernel/frame.c
+	$(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $<
 
 QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
 
diff -Nru a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
--- a/arch/um/kernel/exec_kern.c	Tue Oct 15 20:29:15 2002
+++ b/arch/um/kernel/exec_kern.c	Tue Oct 15 20:29:15 2002
@@ -17,6 +17,7 @@
 #include "tlb.h"
 #include "2_5compat.h"
 #include "os.h"
+#include "time_user.h"
 
 /* See comment above fork_tramp for why sigstop is defined and used like
  * this
@@ -28,7 +29,6 @@
 {
 	int sig = sigstop;
 
-	block_signals();
 	init_new_thread(sig_stack, NULL);
 	kill(os_getpid(), sig);
 	return(0);
@@ -62,6 +62,7 @@
 	unprotect_stack((unsigned long) current->thread_info);
 	os_usr1_process(os_getpid());
 
+	enable_timer();
 	free_page(stack);
 	protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
 	task_protections((unsigned long) current->thread_info);
diff -Nru a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
--- a/arch/um/kernel/exitcode.c	Tue Oct 15 20:29:15 2002
+++ b/arch/um/kernel/exitcode.c	Tue Oct 15 20:29:15 2002
@@ -8,6 +8,9 @@
 #include "linux/proc_fs.h"
 #include "asm/uaccess.h"
 
+/* If read and write race, the read will still atomically read a valid
+ * value.
+ */
 int uml_exitcode = 0;
 
 static int read_proc_exitcode(char *page, char **start, off_t off,
diff -Nru a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c
--- a/arch/um/kernel/frame.c	Tue Oct 15 20:29:16 2002
+++ b/arch/um/kernel/frame.c	Tue Oct 15 20:29:16 2002
@@ -130,6 +130,7 @@
 	os_stop_process(os_getpid());
 }
 
+/* Changed only during early boot */
 struct sc_frame signal_frame_sc;
 
 struct sc_frame_raw {
@@ -142,6 +143,7 @@
 	struct arch_frame_data_raw arch;
 };
 
+/* Changed only during early boot */
 static struct sc_frame_raw *raw_sc = NULL;
 
 static void sc_handler(int sig, struct sigcontext sc)
@@ -163,6 +165,7 @@
 	return(-1);
 }
 
+/* Changed only during early boot */
 struct si_frame signal_frame_si;
 
 struct si_frame_raw {
@@ -175,6 +178,7 @@
 	unsigned long sp;
 };
 
+/* Changed only during early boot */
 static struct si_frame_raw *raw_si = NULL;
 
 static void si_handler(int sig, siginfo_t *si)
diff -Nru a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c
--- a/arch/um/kernel/helper.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/kernel/helper.c	Tue Oct 15 20:29:17 2002
@@ -22,6 +22,7 @@
 	int fd;
 };
 
+/* Debugging aid, changed only from gdb */
 int helper_pause = 0;
 
 static void helper_hup(int sig)
diff -Nru a/arch/um/kernel/initrd_kern.c b/arch/um/kernel/initrd_kern.c
--- a/arch/um/kernel/initrd_kern.c	Tue Oct 15 20:29:11 2002
+++ b/arch/um/kernel/initrd_kern.c	Tue Oct 15 20:29:11 2002
@@ -13,6 +13,7 @@
 #include "init.h"
 #include "os.h"
 
+/* Changed by uml_initrd_setup, which is a setup */
 static char *initrd __initdata = NULL;
 
 static int __init read_initrd(void)
diff -Nru a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
--- a/arch/um/kernel/irq.c	Tue Oct 15 20:29:20 2002
+++ b/arch/um/kernel/irq.c	Tue Oct 15 20:29:20 2002
@@ -78,6 +78,7 @@
 	end_none
 };
 
+/* Not changed */
 volatile unsigned long irq_err_count;
 
 /*
@@ -87,6 +88,7 @@
 int get_irq_list(char *buf)
 {
 	int i, j;
+	unsigned long flags;
 	struct irqaction * action;
 	char *p = buf;
 
@@ -96,9 +98,10 @@
 	*p++ = '\n';
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
+		spin_lock_irqsave(&irq_desc[i].lock, flags);
 		action = irq_desc[i].action;
 		if (!action) 
-			continue;
+			goto end;
 		p += sprintf(p, "%3d: ",i);
 #ifndef CONFIG_SMP
 		p += sprintf(p, "%10u ", kstat_irqs(i));
@@ -113,6 +116,8 @@
 		for (action=action->next; action; action = action->next)
 			p += sprintf(p, ", %s", action->name);
 		*p++ = '\n';
+	end:
+		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
 	}
 	p += sprintf(p, "\n");
 #ifdef notdef
@@ -548,11 +553,15 @@
 	}
 }
 
+/* These are initialized by sysctl_init, which is called from init/main.c */
 static struct proc_dir_entry * root_irq_dir;
 static struct proc_dir_entry * irq_dir [NR_IRQS];
 static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
 
-unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+/* These are read and written as longs, so a read won't see a partial write
+ * even during a race.
+ */
+static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
 
 #define HEX_DIGITS 8
 
@@ -679,6 +688,7 @@
 	smp_affinity_entry[irq] = entry;
 }
 
+/* Read and written as a long */
 unsigned long prof_cpu_mask = -1;
 
 void __init init_irq_proc (void)
@@ -702,6 +712,21 @@
 	 */
 	for (i = 0; i < NR_IRQS; i++)
 		register_irq_proc(i);
+}
+
+static spinlock_t irq_spinlock = SPIN_LOCK_UNLOCKED;
+
+unsigned long irq_lock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq_spinlock, flags);
+	return(flags);
+}
+
+void irq_unlock(unsigned long flags)
+{
+	spin_unlock_irqrestore(&irq_spinlock, flags);
 }
 
 unsigned long probe_irq_on(void)
diff -Nru a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
--- a/arch/um/kernel/irq_user.c	Tue Oct 15 20:29:16 2002
+++ b/arch/um/kernel/irq_user.c	Tue Oct 15 20:29:16 2002
@@ -111,40 +111,20 @@
 
 int activate_fd(int irq, int fd, int type, void *dev_id)
 {
-	struct irq_fd *new_fd;
-	int pid, retval, events, err;
+	struct pollfd *tmp_pfd;
+	struct irq_fd *new_fd, *irq_fd;
+	unsigned long flags;
+	int pid, events, err, n, size;
+
+	pid = os_getpid();
+	err = os_set_fd_async(fd, pid);
+	if(err < 0)
+		goto out;
 
-	for(new_fd = active_fds;new_fd;new_fd = new_fd->next){
-		if((new_fd->fd == fd) && (new_fd->type == type)){
-			printk("Registering fd %d twice\n", fd);
-			printk("Irqs : %d, %d\n", new_fd->irq, irq);
-			printk("Ids : 0x%x, 0x%x\n", new_fd->id, dev_id);
-			return(-EIO);
-		}
-	}
-	pid = cpu_tasks[0].pid;
-	if((retval = os_set_fd_async(fd, pid)) != 0)
-		return(retval);
 	new_fd = um_kmalloc(sizeof(*new_fd));
 	err = -ENOMEM;
-	if(new_fd == NULL) return(err);
-	pollfds_num++;
-	if(pollfds_num > pollfds_size){
-		struct pollfd *tmp_pfd;
-
-		tmp_pfd = um_kmalloc(pollfds_num * sizeof(pollfds[0]));
-		if(tmp_pfd == NULL){
-			pollfds_num--;
-			goto out_irq;
-		}
-		if(pollfds != NULL){
-			memcpy(tmp_pfd, pollfds,
-			       sizeof(pollfds[0]) * pollfds_size);
-			kfree(pollfds);
-		}
-		pollfds = tmp_pfd;
-		pollfds_size = pollfds_num;
-	}
+	if(new_fd == NULL)
+		goto out;
 
 	if(type == IRQ_READ) events = POLLIN | POLLPRI;
 	else events = POLLOUT;
@@ -158,29 +138,90 @@
 				     current_events: 	0,
 				     freed :		0  } );
 
-	*last_irq_ptr = new_fd;
-	last_irq_ptr = &new_fd->next;
+	/* Critical section - locked by a spinlock because this stuff can
+	 * be changed from interrupt handlers.  The stuff above is done 
+	 * outside the lock because it allocates memory.
+	 */
+
+	/* Actually, it only looks like it can be called from interrupt
+	 * context.  The culprit is reactivate_fd, which calls 
+	 * maybe_sigio_broken, which calls write_sigio_workaround,
+	 * which calls activate_fd.  However, write_sigio_workaround should
+	 * only be called once, at boot time.  That would make it clear that
+	 * this is called only from process context, and can be locked with
+	 * a semaphore.
+	 */
+	flags = irq_lock();
+	for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
+		if((irq_fd->fd == fd) && (irq_fd->type == type)){
+			printk("Registering fd %d twice\n", fd);
+			printk("Irqs : %d, %d\n", irq_fd->irq, irq);
+			printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id);
+			goto out_unlock;
+		}
+	}
+
+	n = pollfds_num;
+	if(n == pollfds_size){
+		while(1){
+			/* Here we have to drop the lock in order to call 
+			 * kmalloc, which might sleep.  If something else
+			 * came in and changed the pollfds array, we free
+			 * the buffer and try again.
+			 */
+			irq_unlock(flags);
+			size = (pollfds_num + 1) * sizeof(pollfds[0]);
+			tmp_pfd = um_kmalloc(size);
+			flags = irq_lock();
+			if(tmp_pfd == NULL)
+				goto out_unlock;
+			if(n == pollfds_size)
+				break;
+			kfree(tmp_pfd);
+		}
+		if(pollfds != NULL){
+			memcpy(tmp_pfd, pollfds,
+			       sizeof(pollfds[0]) * pollfds_size);
+			kfree(pollfds);
+		}
+		pollfds = tmp_pfd;
+		pollfds_size++;
+	}
 
 	if(type == IRQ_WRITE) events = 0;
 
-	pollfds[pollfds_num - 1] = ((struct pollfd) { fd :	fd,
-						      events :	events,
-						      revents :	0 });
+	pollfds[pollfds_num] = ((struct pollfd) { fd :	fd,
+						  events :	events,
+						  revents :	0 });
+	pollfds_num++;
+
+	*last_irq_ptr = new_fd;
+	last_irq_ptr = &new_fd->next;
+
+	irq_unlock(flags);
 
+	/* This calls activate_fd, so it has to be outside the critical
+	 * section.
+	 */
 	maybe_sigio_broken(fd, type);
 
 	return(0);
 
- out_irq:
+ out_unlock:
+	irq_unlock(flags);
+ out_free:
 	kfree(new_fd);
+ out:
 	return(err);
 }
 
 static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg)
 {
 	struct irq_fd **prev;
+	unsigned long flags;
 	int i = 0;
 
+	flags = irq_lock();
 	prev = &active_fds;
 	while(*prev != NULL){
 		if((*test)(*prev, arg)){
@@ -190,7 +231,7 @@
 				printk("free_irq_by_cb - mismatch between "
 				       "active_fds and pollfds, fd %d vs %d\n",
 				       (*prev)->fd, pollfds[i].fd);
-				return;
+				goto out;
 			}
 			memcpy(&pollfds[i], &pollfds[i + 1],
 			       (pollfds_num - i - 1) * sizeof(pollfds[0]));
@@ -206,6 +247,8 @@
 		prev = &(*prev)->next;
 		i++;
 	}
+ out:
+	irq_unlock(flags);
 }
 
 struct irq_and_dev {
@@ -242,29 +285,33 @@
 {
 	struct irq_fd *irq;
 	int i = 0;
-	
+
 	for(irq=active_fds; irq != NULL; irq = irq->next){
 		if((irq->fd == fd) && (irq->irq == irqnum)) break;
 		i++;
 	}
 	if(irq == NULL){
 		printk("find_irq_by_fd doesn't have descriptor %d\n", fd);
-		return(NULL);
+		goto out;
 	}
 	if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){
 		printk("find_irq_by_fd - mismatch between active_fds and "
 		       "pollfds, fd %d vs %d, need %d\n", irq->fd, 
 		       pollfds[i].fd, fd);
-		return(NULL);
+		irq = NULL;
+		goto out;
 	}
 	*index_out = i;
+ out:
 	return(irq);
 }
 
 void free_irq_later(int irq, void *dev_id)
 {
 	struct irq_fd *irq_fd;
+	unsigned long flags;
 
+	flags = irq_lock();
 	for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){
 		if((irq_fd->irq == irq) && (irq_fd->id == dev_id))
 			break;
@@ -272,30 +319,48 @@
 	if(irq_fd == NULL){
 		printk("free_irq_later found no irq, irq = %d, "
 		       "dev_id = 0x%p\n", irq, dev_id);
-		return;
+		goto out;
 	}
 	irq_fd->freed = 1;
+ out:
+	irq_unlock(flags);
 }
 
 void reactivate_fd(int fd, int irqnum)
 {
 	struct irq_fd *irq;
+	unsigned long flags;
 	int i;
 
+	flags = irq_lock();
 	irq = find_irq_by_fd(fd, irqnum, &i);
-	if(irq == NULL) return;
+	if(irq == NULL){
+		irq_unlock(flags);
+		return;
+	}
 	pollfds[i].fd = irq->fd;
+
+	irq_unlock(flags);
+
+	/* This calls activate_fd, so it has to be outside the critical
+	 * section.
+	 */
 	maybe_sigio_broken(fd, irq->type);
 }
 
 void deactivate_fd(int fd, int irqnum)
 {
 	struct irq_fd *irq;
+	unsigned long flags;
 	int i;
 
+	flags = irq_lock();
 	irq = find_irq_by_fd(fd, irqnum, &i);
-	if(irq == NULL) return;
+	if(irq == NULL)
+		goto out;
 	pollfds[i].fd = -1;
+ out:
+	irq_unlock(flags);
 }
 
 void forward_ipi(int fd, int pid)
@@ -313,7 +378,9 @@
 void forward_interrupts(int pid)
 {
 	struct irq_fd *irq;
+	unsigned long flags;
 
+	flags = irq_lock();
 	for(irq=active_fds;irq != NULL;irq = irq->next){
 		if(fcntl(irq->fd, F_SETOWN, pid) < 0){
 			int save_errno = errno;
@@ -328,6 +395,7 @@
 		}
 		irq->pid = pid;
 	}
+	irq_unlock(flags);
 }
 
 void init_irq_signals(int on_sigstack)
@@ -339,10 +407,10 @@
 	if(timer_irq_inited) h = (__sighandler_t) alarm_handler;
 	else h = boot_timer_handler;
 
-	set_handler(SIGVTALRM, h, flags | SA_NODEFER | SA_RESTART, 
-		    SIGUSR1, SIGIO, SIGWINCH, -1);
+	set_handler(SIGVTALRM, h, flags | SA_RESTART, 
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1);
 	set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART,
-		    SIGUSR1, SIGIO, SIGWINCH, -1);
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	signal(SIGWINCH, SIG_IGN);
 }
 
diff -Nru a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
--- a/arch/um/kernel/ksyms.c	Tue Oct 15 20:29:12 2002
+++ b/arch/um/kernel/ksyms.c	Tue Oct 15 20:29:12 2002
@@ -20,6 +20,7 @@
 EXPORT_SYMBOL(sys_waitpid);
 EXPORT_SYMBOL(task_size);
 EXPORT_SYMBOL(__do_copy_from_user);
+EXPORT_SYMBOL(__do_copy_to_user);
 EXPORT_SYMBOL(__do_strncpy_from_user);
 EXPORT_SYMBOL(__do_strnlen_user); 
 EXPORT_SYMBOL(flush_tlb_range);
diff -Nru a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
--- a/arch/um/kernel/mem.c	Tue Oct 15 20:29:16 2002
+++ b/arch/um/kernel/mem.c	Tue Oct 15 20:29:16 2002
@@ -26,33 +26,32 @@
 #include "kern.h"
 #include "init.h"
 
+/* Changed during early boot */
+pgd_t swapper_pg_dir[1024];
 unsigned long high_physmem;
-unsigned long low_physmem;
-
 unsigned long vm_start;
 unsigned long vm_end;
-
 unsigned long highmem;
-
-pgd_t swapper_pg_dir[1024];
-
 unsigned long *empty_zero_page = NULL;
-
 unsigned long *empty_bad_page = NULL;
 
+/* Not modified */
 const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
 
 extern char __init_begin, __init_end;
 extern long physmem_size;
 
+/* Not changed by UML */
 mmu_gather_t mmu_gathers[NR_CPUS];
 
+/* Changed during early boot */
 int kmalloc_ok = 0;
 
 #define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0) + 1)
 struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL };
 #define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1)
 
+/* Changed during early boot */
 static unsigned long brk_end;
 
 static void map_cb(void *unused)
@@ -108,6 +107,7 @@
 }
 
 #if CONFIG_HIGHMEM
+/* Changed during early boot */
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 
@@ -187,18 +187,22 @@
 	return(0);
 }
 
+DECLARE_MUTEX(regions_sem);
+
 static int setup_one_range(int fd, char *driver, unsigned long start, 
 			   unsigned long pfn, int len, 
 			   struct mem_region *region)
 {
 	int i;
 
+	down(&regions_sem);
 	for(i = 0; i < NREGIONS; i++){
 		if(regions[i] == NULL) break;		
 	}
 	if(i == NREGIONS){
 		printk("setup_range : no free regions\n");
-		return(-1);
+		i = -1;
+		goto out;
 	}
 
 	if(fd == -1)
@@ -216,6 +220,8 @@
 					 len :		len, 
 					 fd :		fd } );
 	regions[i] = region;
+ out:
+	up(&regions_sem);
 	return(i);
 }
 
@@ -373,7 +379,8 @@
         printk("%d pages swap cached\n", cached);
 }
 
-unsigned long kmem_top = 0;
+/* Changed during early boot */
+static unsigned long kmem_top = 0;
 
 unsigned long get_kmem_end(void)
 {
@@ -428,8 +435,10 @@
 	goto again;
 }
 
+DECLARE_MUTEX(vm_reserved_sem);
 static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved);
 
+/* Static structures, linked in to the list in early boot */
 static struct vm_reserved head = {
 	list :		LIST_HEAD_INIT(head.list),
 	start :		0,
@@ -455,7 +464,9 @@
 {
 	struct vm_reserved *entry = e, *reserved, *prev;
 	struct list_head *ele;
+	int err;
 
+	down(&vm_reserved_sem);
 	list_for_each(ele, &vm_reserved){
 		reserved = list_entry(ele, struct vm_reserved, list);
 		if(reserved->start >= end) goto found;
@@ -469,13 +480,17 @@
 		entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 	if(entry == NULL){
 		printk("reserve_vm : Failed to allocate entry\n");
-		return(-ENOMEM);
+		err = -ENOMEM;
+		goto out;
 	}
 	*entry = ((struct vm_reserved) 
 		{ list :	LIST_HEAD_INIT(entry->list),
 		  start :	start,
 		  end :		end });
 	list_add(&entry->list, &prev->list);
+	err = 0;
+ out:
+	up(&vm_reserved_sem);
 	return(0);
 }
 
@@ -486,6 +501,7 @@
 	unsigned long start;
 	int err;
 	
+	down(&vm_reserved_sem);
 	list_for_each(ele, &vm_reserved){
 		this = list_entry(ele, struct vm_reserved, list);
 		next = list_entry(ele->next, struct vm_reserved, list);
@@ -493,8 +509,10 @@
 		   (this->end + len + PAGE_SIZE <= next->start))
 			goto found;
 	}
+	up(&vm_reserved_sem);
 	return(0);
  found:
+	up(&vm_reserved_sem);
 	start = (unsigned long) ROUND_UP(this->end) + PAGE_SIZE;
 	err = reserve_vm(start, start + len, NULL);
 	if(err) return(0);
@@ -533,7 +551,11 @@
 	unsigned long size;
 };
 
-struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = 
+/* iomem regions can only be added on the command line at the moment.  
+ * Locking will be needed when they can be added via mconsole.
+ */
+
+struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] =
 					 { name : 	NULL,
 					   fd : 	-1,
 					   size :	0 } };
@@ -569,6 +591,7 @@
 #define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 #define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
 
+/* Changed during early boot */
 static struct mem_region physmem_region;
 static struct vm_reserved physmem_reserved;
 
diff -Nru a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
--- a/arch/um/kernel/mem_user.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/kernel/mem_user.c	Tue Oct 15 20:29:17 2002
@@ -46,10 +46,9 @@
 #include "mem_user.h"
 #include "init.h"
 #include "os.h"
+#include "tempfile.h"
 
-struct mem_region physmem_region;
-
-struct mem_region *mem_list = &physmem_region;
+extern struct mem_region physmem_region;
 
 #define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
 
diff -Nru a/arch/um/kernel/process.c b/arch/um/kernel/process.c
--- a/arch/um/kernel/process.c	Tue Oct 15 20:29:20 2002
+++ b/arch/um/kernel/process.c	Tue Oct 15 20:29:20 2002
@@ -48,23 +48,23 @@
 		flags = SA_ONSTACK;
 	}
 	set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
-		    SIGUSR1, SIGIO, SIGWINCH, -1);
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, 
-		    SIGUSR1, SIGIO, SIGWINCH, -1);
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, 
-		    SIGUSR1, SIGIO, SIGWINCH, -1);
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	set_handler(SIGILL, (__sighandler_t) sig_handler, flags, 
-		    SIGUSR1, SIGIO, SIGWINCH, -1);
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, 
-		    SIGUSR1, SIGIO, SIGWINCH, -1);
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, 
-		    SIGUSR1, SIGIO, SIGWINCH, -1);
+		    SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
 	set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
 		    SA_NOMASK | flags, -1);
 	if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1);
 	signal(SIGCHLD, SIG_IGN);
 	signal(SIGHUP, SIG_IGN);
-	set_timers(1);  /* XXX A bit of a race here */
+
 	init_irq_signals(sig_stack != NULL);
 }
 
diff -Nru a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
--- a/arch/um/kernel/process_kern.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/kernel/process_kern.c	Tue Oct 15 20:29:17 2002
@@ -41,6 +41,10 @@
 #include "2_5compat.h"
 #include "os.h"
 
+/* This is a per-cpu array.  A processor only modifies its entry and it only
+ * cares about its entry, so it's OK if another processor is modifying its
+ * entry.
+ */
 struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
 
 struct task_struct *get_task(int pid, int require)
@@ -86,7 +90,7 @@
 {
 	int i;
 
-	for(i = 0; i < num_online_cpus(); i++){
+	for(i = 0; i < ncpus; i++){
 		if(cpu_tasks[i].pid == pid) return(i);
 	}
 	return(-1);
@@ -152,12 +156,19 @@
 	current->thread.regs.regs.sc = (void *) (&sig + 1);
 	suspend_new_thread(current->thread.switch_pipe[0]);
 
+	block_signals();
+#ifdef CONFIG_SMP
+	schedule_tail(NULL);
+#endif
+	enable_timer();
 	free_page(current->thread.temp_stack);
 	set_cmdline("(kernel thread)");
 	force_flush_all();
 
 	current->thread.prev_sched = NULL;
 	change_sig(SIGUSR1, 1);
+	change_sig(SIGVTALRM, 1);
+	change_sig(SIGPROF, 1);
 	unblock_signals();
 	if(!run_kernel_thread(fn, arg, &current->thread.jmp))
 		do_exit(0);
@@ -165,7 +176,9 @@
 
 static int new_thread_proc(void *stack)
 {
-	block_signals();
+	change_sig(SIGIO, 0);
+	change_sig(SIGVTALRM, 0);
+	change_sig(SIGPROF, 0);
 	init_new_thread(stack, new_thread_handler);
 	os_usr1_process(os_getpid());
 	return(0);
@@ -204,6 +217,9 @@
 	unsigned long flags;
 	int vtalrm, alrm, prof, err, cpu;
 	char c;
+	/* jailing and SMP are incompatible, so this doesn't need to be 
+	 * made per-cpu 
+	 */
 	static int reading;
 
 	from = prev;
@@ -229,7 +245,7 @@
 	set_current(to);
 
 	reading = 0;
-	err = user_write(to->thread.switch_pipe[1], &c, sizeof(c));
+	err = os_write_file(to->thread.switch_pipe[1], &c, sizeof(c));
 	if(err != sizeof(c))
 		panic("write of switch_pipe failed, errno = %d", -err);
 
@@ -237,7 +253,7 @@
 	if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD))
 		os_kill_process(os_getpid());
 
-	err = user_read(from->thread.switch_pipe[0], &c, sizeof(c));
+	err = os_read_file(from->thread.switch_pipe[0], &c, sizeof(c));
 	if(err != sizeof(c))
 		panic("read of switch_pipe failed, errno = %d", -err);
 
@@ -298,13 +314,16 @@
  * onto the signal frame.
  */
 
-extern int hit_me;
-
 void finish_fork_handler(int sig)
 {
 	current->thread.regs.regs.sc = (void *) (&sig + 1);
 	suspend_new_thread(current->thread.switch_pipe[0]);
-	
+
+#ifdef CONFIG_SMP	
+	schedule_tail(NULL);
+#endif
+	enable_timer();
+	change_sig(SIGVTALRM, 1);
 	force_flush_all();
 	if(current->mm != current->parent->mm)
 		protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
@@ -313,7 +332,6 @@
 	current->thread.prev_sched = NULL;
 
 	free_page(current->thread.temp_stack);
-	block_signals();
 	change_sig(SIGUSR1, 0);
 	set_user_mode(current);
 }
@@ -339,7 +357,9 @@
 {
 	int sig = sigusr1;
 
-	block_signals();
+	change_sig(SIGIO, 0);
+	change_sig(SIGVTALRM, 0);
+	change_sig(SIGPROF, 0);
 	init_new_thread(stack, finish_fork_handler);
 
 	kill(os_getpid(), sig);
@@ -474,7 +494,7 @@
 
 void default_idle(void)
 {
- 	if(current->thread_info->cpu == 0) idle_timer();
+	idle_timer();
 
 	atomic_inc(&init_mm.mm_count);
 	current->mm = &init_mm;
@@ -644,6 +664,7 @@
 	return(new);
 }
 
+/* Changed by jail_setup, which is a setup */
 int jail = 0;
 
 int __init jail_setup(char *line, int *add)
@@ -708,17 +729,14 @@
 	mprotect_kernel_vm(w);
 }
 
-int jail_timer_off = 0;
-
+/* No SMP problems since jailing and SMP are incompatible */
 void unprotect_kernel_mem(void)
 {
 	mprotect_kernel_mem(1);
-	jail_timer_off = 0;
 }
 
 void protect_kernel_mem(void)
 {
-	jail_timer_off = 1;
 	mprotect_kernel_mem(0);
 }
 
@@ -749,9 +767,11 @@
 
 int smp_sigio_handler(void)
 {
+	int cpu = current->thread_info->cpu;
 #ifdef CONFIG_SMP
-	IPI_handler(hard_smp_processor_id());
-	if (hard_smp_processor_id() != 0) return(1);
+	IPI_handler(cpu);
+	if(cpu != 0)
+		return(1);
 #endif
 	return(0);
 }
@@ -759,6 +779,11 @@
 int um_in_interrupt(void)
 {
 	return(in_interrupt());
+}
+
+int cpu(void)
+{
+	return(current->thread_info->cpu);
 }
 
 /*
diff -Nru a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c
--- a/arch/um/kernel/sigio_kern.c	Tue Oct 15 20:29:14 2002
+++ b/arch/um/kernel/sigio_kern.c	Tue Oct 15 20:29:14 2002
@@ -11,6 +11,7 @@
 #include "sigio.h"
 #include "irq_user.h"
 
+/* Protected by sigio_lock() called from write_sigio_workaround */
 static int sigio_irq_fd = -1;
 
 void sigio_interrupt(int irq, void *data, struct pt_regs *unused)
@@ -29,6 +30,18 @@
 	}
 	sigio_irq_fd = fd;
 	return(0);
+}
+
+static spinlock_t sigio_spinlock = SPIN_LOCK_UNLOCKED;
+
+void sigio_lock(void)
+{
+	spin_lock(&sigio_spinlock);
+}
+
+void sigio_unlock(void)
+{
+	spin_unlock(&sigio_spinlock);
 }
 
 /*
diff -Nru a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
--- a/arch/um/kernel/sigio_user.c	Tue Oct 15 20:29:22 2002
+++ b/arch/um/kernel/sigio_user.c	Tue Oct 15 20:29:22 2002
@@ -21,9 +21,11 @@
 #include "helper.h"
 #include "os.h"
 
+/* Changed during early boot */
 int pty_output_sigio = 0;
 int pty_close_sigio = 0;
 
+/* Used as a flag during SIGIO testing early in boot */
 static int got_sigio = 0;
 
 void __init handler(int sig)
@@ -151,7 +153,15 @@
 	check_one_sigio(tty_close);
 }
 
+/* Protected by sigio_lock(), also used by sigio_cleanup, which is an 
+ * exitcall.
+ */
 static int write_sigio_pid = -1;
+
+/* These arrays are initialized before the sigio thread is started, and
+ * the descriptors closed after it is killed.  So, it can't see them change.
+ * On the UML side, they are changed under the sigio_lock.
+ */
 static int write_sigio_fds[2] = { -1, -1 };
 static int sigio_private[2] = { -1, -1 };
 
@@ -161,6 +171,9 @@
 	int used;
 };
 
+/* Protected by sigio_lock().  Used by the sigio thread, but the UML thread
+ * synchronizes with it.
+ */
 struct pollfds current_poll = {
 	poll : 		NULL,
 	size :		0,
@@ -217,8 +230,6 @@
 	}
 }
 
-/* XXX SMP locking needed here too */
-
 static int need_poll(int n)
 {
 	if(n <= next_poll.size){
@@ -260,25 +271,31 @@
 	set_signals(flags);
 	return;
  fail:
+	sigio_lock();
 	if(write_sigio_pid != -1) kill(write_sigio_pid, SIGKILL);
 	write_sigio_pid = -1;
 	close(sigio_private[0]);
 	close(sigio_private[1]);	
 	close(write_sigio_fds[0]);
 	close(write_sigio_fds[1]);
+	sigio_unlock();
 	set_signals(flags);
 }
 
 int add_sigio_fd(int fd, int read)
 {
-	int err, i, n, events;
+	int err = 0, i, n, events;
 
-	for(i = 0; i < current_poll.used; i++)
-		if(current_poll.poll[i].fd == fd) return(0);
+	sigio_lock();
+	for(i = 0; i < current_poll.used; i++){
+		if(current_poll.poll[i].fd == fd) 
+			goto out;
+	}
 
 	n = current_poll.used + 1;
 	err = need_poll(n);
-	if(err) return(err);
+	if(err) 
+		goto out;
 
 	for(i = 0; i < current_poll.used; i++)
 		next_poll.poll[i] = current_poll.poll[i];
@@ -290,21 +307,26 @@
 						   events :	events,
 						   revents :	0 });
 	update_thread();
-	return(0);
+ out:
+	sigio_unlock();
+	return(err);
 }
 
 int ignore_sigio_fd(int fd)
 {
 	struct pollfd *p;
-	int err, i, n = 0;
+	int err = 0, i, n = 0;
 
+	sigio_lock();
 	for(i = 0; i < current_poll.used; i++){
 		if(current_poll.poll[i].fd == fd) break;
 	}
-	if(i == current_poll.used) return(0);
+	if(i == current_poll.used)
+		goto out;
 	
 	err = need_poll(current_poll.used - 1);
-	if(err) return(err);
+	if(err)
+		goto out;
 
 	for(i = 0; i < current_poll.used; i++){
 		p = &current_poll.poll[i];
@@ -312,11 +334,14 @@
 	}
 	if(n == i){
 		printk("ignore_sigio_fd : fd %d not found\n", fd);
-		return(-1);
+		err = -1;
+		goto out;
 	}
 
 	update_thread();
-	return(0);
+ out:
+	sigio_unlock();
+	return(err);
 }
 
 static int setup_initial_poll(int fd)
@@ -342,14 +367,15 @@
 	unsigned long stack;
 	int err;
 
-	if(write_sigio_pid != -1) return;
+	sigio_lock();
+	if(write_sigio_pid != -1)
+		goto out;
 
-	/* XXX This needs SMP locking */
 	err = os_pipe(write_sigio_fds, 1, 1);
 	if(err){
 		printk("write_sigio_workaround - os_pipe 1 failed, "
 		       "errno = %d\n", -err);
-		return;
+		goto out;
 	}
 	err = os_pipe(sigio_private, 1, 1);
 	if(err){
@@ -368,6 +394,8 @@
 	if(write_sigio_irq(write_sigio_fds[0])) 
 		goto out_kill;
 
+ out:
+	sigio_unlock();
 	return;
 
  out_kill:
@@ -379,6 +407,7 @@
  out_close1:
 	close(write_sigio_fds[0]);
 	close(write_sigio_fds[1]);
+	sigio_unlock();
 }
 
 int read_sigio_fd(int fd)
diff -Nru a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c
--- a/arch/um/kernel/signal_user.c	Tue Oct 15 20:29:19 2002
+++ b/arch/um/kernel/signal_user.c	Tue Oct 15 20:29:19 2002
@@ -19,8 +19,6 @@
 #include "sysdep/sigcontext.h"
 #include "sigcontext.h"
 
-extern int kern_timer_on;
-
 void set_sigstack(void *sig_stack, int size)
 {
 	stack_t stack;
@@ -57,7 +55,7 @@
 	sigemptyset(&sigset);
 	sigaddset(&sigset, signal);
 	sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old);
-	return(sigismember(&old, signal));
+	return(!sigismember(&old, signal));
 }
 
 static void change_signals(int type)
@@ -65,12 +63,8 @@
 	sigset_t mask;
 
 	sigemptyset(&mask);
-	if(type == SIG_BLOCK) kern_timer_on = 0;
-	else {
-		kern_timer_on = 1;
-		sigaddset(&mask, SIGVTALRM);
-		sigaddset(&mask, SIGALRM);
-	}
+	sigaddset(&mask, SIGVTALRM);
+	sigaddset(&mask, SIGALRM);
 	sigaddset(&mask, SIGIO);
 	sigaddset(&mask, SIGPROF);
 	if(sigprocmask(type, &mask, NULL) < 0)
@@ -97,7 +91,6 @@
 	sigs = sigismember(mask, SIGIO) ? 1 << SIGIO_BIT : 0;
 	sigs |= sigismember(mask, SIGVTALRM) ? 1 << SIGVTALRM_BIT : 0;
 	sigs |= sigismember(mask, SIGALRM) ? 1 << SIGVTALRM_BIT : 0;
-	if(!kern_timer_on) sigs |= 1 << SIGVTALRM_BIT;
 	return(sigs);
 }
 
@@ -116,21 +109,27 @@
 	int ret;
 
 	sigemptyset(&mask);
-	if(!(disable & (1 << SIGIO_BIT))) sigaddset(&mask, SIGIO);
+	if(!(disable & (1 << SIGIO_BIT)))
+		sigaddset(&mask, SIGIO);
 	if(!(disable & (1 << SIGVTALRM_BIT))){
-		kern_timer_on = 1;
 		sigaddset(&mask, SIGVTALRM);
 		sigaddset(&mask, SIGALRM);
 	}
 	if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0)
 		panic("Failed to enable signals");
+
 	ret = disable_mask(&mask);
+
 	sigemptyset(&mask);
-	if(disable & (1 << SIGIO_BIT)) sigaddset(&mask, SIGIO);
-	if(disable & (1 << SIGVTALRM_BIT))
-		kern_timer_on = 0;
+	if(disable & (1 << SIGIO_BIT))
+		sigaddset(&mask, SIGIO);
+	if(disable & (1 << SIGVTALRM_BIT)){
+		sigaddset(&mask, SIGVTALRM);
+		sigaddset(&mask, SIGALRM);
+	}
 	if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0)
 		panic("Failed to block signals");
+
 	return(ret);
 }
 
diff -Nru a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
--- a/arch/um/kernel/smp.c	Tue Oct 15 20:29:13 2002
+++ b/arch/um/kernel/smp.c	Tue Oct 15 20:29:13 2002
@@ -5,7 +5,7 @@
 
 #include "linux/config.h"
 
-/* CPU online map */
+/* CPU online map, set by smp_boot_cpus */
 unsigned long cpu_online_map = 1;
 
 #ifdef CONFIG_SMP
@@ -21,25 +21,32 @@
 #include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
+#include "irq_user.h"
 #include "os.h"
 
-/* The 'big kernel lock' */
-spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
-
-/* Per CPU bogomips and other parameters */
+/* Per CPU bogomips and other parameters
+ * The only piece used here is the ipi pipe, which is set before SMP is
+ * started and never changed.
+ */
 struct cpuinfo_um cpu_data[NR_CPUS];
 
 spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED;
 
 atomic_t global_bh_count;
 
+/* Not used by UML */
 unsigned char global_irq_holder = NO_PROC_ID;
 unsigned volatile long global_irq_lock;
 
 /* Set when the idlers are all forked */
 int smp_threads_ready = 0;
+
+/* A statistic, can be a little off */
 int num_reschedules_sent = 0;
 
+/* Small, random number, never changed */
+unsigned long cache_decay_ticks = 5;
+
 void smp_send_reschedule(int cpu)
 {
 	write(cpu_data[cpu].ipi_pipe[1], "R", 1);
@@ -83,30 +90,24 @@
 
 void smp_send_stop(void)
 {
-	printk(KERN_INFO "Stopping all CPUs\n");
-}
+	int i;
 
+	printk(KERN_INFO "Stopping all CPUs...");
+	for(i = 0; i < num_online_cpus(); i++){
+		if(i == current->thread_info->cpu)
+			continue;
+		write(cpu_data[i].ipi_pipe[1], "S", 1);
+	}
+	printk("done\n");
+}
 
-static atomic_t smp_commenced = ATOMIC_INIT(0);
+static unsigned long smp_commenced_mask;
 static volatile unsigned long smp_callin_map = 0;
 
-void smp_commence(void)
+static int idle_proc(void *cpup)
 {
-	printk("All CPUs are go!\n");
-
-	wmb();
-	atomic_set(&smp_commenced, 1);
-}
-
-static int idle_proc(void *unused)
-{
-	int cpu, err;
-
-	set_current(current);
-	del_from_runqueue(current);
-	unhash_process(current);
+	int cpu = (int) cpup, err;
 
-	cpu = current->processor;
 	err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
 	if(err)
 		panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, 
@@ -115,46 +116,41 @@
 	activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.extern_pid);
  
 	wmb();
-	if (test_and_set_bit(current->processor, &smp_callin_map)) {
-		printk("huh, CPU#%d already present??\n", current->processor);
+	if (test_and_set_bit(cpu, &smp_callin_map)) {
+		printk("huh, CPU#%d already present??\n", cpu);
 		BUG();
 	}
 
-	while (!atomic_read(&smp_commenced))
+	while (!test_bit(cpu, &smp_commenced_mask))
 		cpu_relax();
 
-	init_idle();
+	set_bit(cpu, &cpu_online_map);
 	default_idle();
 	return(0);
 }
 
-int inited_cpus = 1;
-
-static int idle_thread(int (*fn)(void *), int cpu)
+static struct task_struct *idle_thread(int cpu)
 {
-	struct task_struct *p;
-	int pid;
+	struct task_struct *new_task;
 	unsigned char c;
 
-        current->thread.request.u.thread.proc = fn;
-        current->thread.request.u.thread.arg = NULL;
-	p = do_fork(CLONE_VM | CLONE_PID, 0, NULL, 0);
-	if(IS_ERR(p)) panic("do_fork failed in idle_thread");
-
-	cpu_tasks[cpu].pid = p->thread.extern_pid;
-	cpu_tasks[cpu].task = p;
-	inited_cpus++;
-	init_tasks[cpu] = p;
-	p->processor = cpu;
-	p->cpus_allowed = 1 << cpu;
-	p->cpus_runnable = p->cpus_allowed;
-	write(p->thread.switch_pipe[1], &c, sizeof(c));
-	return(p->thread.extern_pid);
-}
-
-void smp_boot_cpus(void)
-{
-	int err;
+        current->thread.request.u.thread.proc = idle_proc;
+        current->thread.request.u.thread.arg = (void *) cpu;
+	new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL);
+	if(IS_ERR(new_task)) panic("do_fork failed in idle_thread");
+
+	cpu_tasks[cpu] = ((struct cpu_task) 
+		          { .pid = 	new_task->thread.extern_pid,
+			    .task = 	new_task } );
+	write(new_task->thread.switch_pipe[1], &c, sizeof(c));
+	return(new_task);
+}
+
+void smp_prepare_cpus(unsigned int maxcpus)
+{
+	struct task_struct *idle;
+	unsigned long waittime;
+	int err, cpu;
 
 	set_bit(0, &cpu_online_map);
 	set_bit(0, &smp_callin_map);
@@ -164,44 +160,30 @@
 
 	activate_ipi(cpu_data[0].ipi_pipe[0], current->thread.extern_pid);
 
-	if(ncpus < 1){
-		printk(KERN_INFO "ncpus set to 1\n");
-		ncpus = 1;
+	for(cpu = 1; cpu < ncpus; cpu++){
+		printk("Booting processor %d...\n", cpu);
+		
+		idle = idle_thread(cpu);
+
+		init_idle(idle, cpu);
+		unhash_process(idle);
+
+		waittime = 200000000;
+		while (waittime-- && !test_bit(cpu, &smp_callin_map))
+			cpu_relax();
+
+		if (test_bit(cpu, &smp_callin_map))
+			printk("done\n");
+		else printk("failed\n");
 	}
-	else if(ncpus > NR_CPUS){
-		printk(KERN_INFO 
-		       "ncpus can't be greater than NR_CPUS, set to %d\n",
-		       NR_CPUS);
-		ncpus = NR_CPUS;
-	}
-
-	if(ncpus > 1){
-		int i, pid;
+}
 
-		printk(KERN_INFO "Starting up other processors:\n");
-		for(i=1;i<ncpus;i++){
-			int waittime;
-
-			/* Do this early, for hard_smp_processor_id()  */
-			cpu_tasks[i].pid = -1;
-			set_bit(i, &cpu_online_map);
-
-			pid = idle_thread(idle_proc, i);
-			printk(KERN_INFO "\t#%d - idle thread pid = %d.. ",
-			       i, pid);
-
-			waittime = 200000000;
-			while (waittime-- && !test_bit(i, &smp_callin_map))
-				cpu_relax();
-
-			if (test_bit(i, &smp_callin_map))
-				printk("online\n");
-			else {
-				printk("failed\n");
-				clear_bit(i, &cpu_online_map);
-			}
-		}
-	}
+int __cpu_up(unsigned int cpu)
+{
+	set_bit(cpu, &smp_commenced_mask);
+	while (!test_bit(cpu, &cpu_online_map))
+		mb();
+	return(0);
 }
 
 int setup_profiling_timer(unsigned int multiplier)
@@ -225,7 +207,13 @@
 			break;
 
 		case 'R':
-			current->need_resched = 1;
+			set_tsk_need_resched(current);
+			break;
+
+		case 'S':
+			printk("CPU#%d stopping\n", cpu);
+			while(1)
+				pause();
 			break;
 
 		default:
@@ -269,7 +257,8 @@
 	info = _info;
 
 	for (i=0;i<NR_CPUS;i++)
-		if (i != current->processor && test_bit(i, &cpu_online_map))
+		if((i != current->thread_info->cpu) && 
+		   test_bit(i, &cpu_online_map))
 			write(cpu_data[i].ipi_pipe[1], "C", 1);
 
 	while (atomic_read(&scf_started) != cpus)
diff -Nru a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
--- a/arch/um/kernel/syscall_kern.c	Tue Oct 15 20:29:19 2002
+++ b/arch/um/kernel/syscall_kern.c	Tue Oct 15 20:29:19 2002
@@ -384,6 +384,7 @@
 	return(0);
 }
 
+/*  Unlocked, I don't care if this is a bit off */
 int nsyscalls = 0;
 
 extern syscall_handler_t *sys_call_table[];
@@ -417,14 +418,18 @@
 
 spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED;
 
-void lock_syscall(void)
-{
-	spin_lock(&syscall_lock);
-}
+static int syscall_index = 0;
 
-void unlock_syscall(void)
+int next_syscall_index(int limit)
 {
+	int ret;
+
+	spin_lock(&syscall_lock);
+	ret = syscall_index;
+	if(++syscall_index == limit)
+		syscall_index = 0;
 	spin_unlock(&syscall_lock);
+	return(ret);
 }
 
 /*
diff -Nru a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c
--- a/arch/um/kernel/syscall_user.c	Tue Oct 15 20:29:13 2002
+++ b/arch/um/kernel/syscall_user.c	Tue Oct 15 20:29:13 2002
@@ -34,21 +34,14 @@
 	struct timeval end;
 } syscall_record[1024];
 
-int syscall_index = 0;
-
-extern int kern_timer_on;
-
 void syscall_handler(int sig, struct uml_pt_regs *regs)
 {
 	void *sc;
 	long result;
-	int index, syscall;
+	int index, max, syscall;
 
-	lock_syscall();
-	if(syscall_index == 1024) syscall_index = 0;
-	index = syscall_index;
-	syscall_index++;
-	unlock_syscall();
+	max = sizeof(syscall_record)/sizeof(syscall_record[0]);
+	index = next_syscall_index(max);
 
 	syscall = regs->syscall;
 	sc = regs->sc;
diff -Nru a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/um/kernel/tempfile.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/param.h>
+#include "init.h"
+
+char *tempdir = NULL;
+
+static void __init find_tempdir(void)
+{
+	char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
+	int i;
+	char *dir = NULL;
+
+	if(tempdir != NULL) return;	/* We've already been called */
+	for(i = 0; dirs[i]; i++){
+		dir = getenv(dirs[i]);
+		if(dir != NULL) break;
+	}
+	if(dir == NULL) dir = "/tmp";
+	else if(*dir == '\0') dir = NULL;
+	if(dir != NULL) {
+		tempdir = malloc(strlen(dir) + 2);
+		if(tempdir == NULL){
+			fprintf(stderr, "Failed to malloc tempdir, "
+				"errno = %d\n", errno);
+			return;
+		}
+		strcpy(tempdir, dir);
+		strcat(tempdir, "/");
+	}
+}
+
+int make_tempfile(const char *template, char **out_tempname, int do_unlink)
+{
+	char tempname[MAXPATHLEN];
+	int fd;
+
+	find_tempdir();
+	if (*template != '/')
+		strcpy(tempname, tempdir);
+	else
+		*tempname = 0;
+	strcat(tempname, template);
+	if((fd = mkstemp(tempname)) < 0){
+		fprintf(stderr, "open - cannot create %s: %s\n", tempname, 
+			strerror(errno));
+		return -1;
+	}
+	if(do_unlink && (unlink(tempname) < 0)){
+		perror("unlink");
+		return -1;
+	}
+	if(out_tempname){
+		if((*out_tempname = strdup(tempname)) == NULL){
+			perror("strdup");
+			return -1;
+		}
+	}
+	return(fd);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ */
diff -Nru a/arch/um/kernel/time.c b/arch/um/kernel/time.c
--- a/arch/um/kernel/time.c	Tue Oct 15 20:29:12 2002
+++ b/arch/um/kernel/time.c	Tue Oct 15 20:29:12 2002
@@ -14,33 +14,15 @@
 #include "user.h"
 #include "process.h"
 #include "signal_user.h"
+#include "time_user.h"
 
 extern struct timeval xtime;
 
-void timer_handler(int sig, struct uml_pt_regs *regs)
-{
-	timer_irq(regs);
-}
-
 void timer(void)
 {
 	gettimeofday(&xtime, NULL);
 }
 
-static struct itimerval profile_interval;
-
-void get_profile_timer(void)
-{
-	getitimer(ITIMER_PROF, &profile_interval);
-	profile_interval.it_value = profile_interval.it_interval;
-}
-
-void disable_profile_timer(void)
-{
-	struct itimerval interval = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
-	setitimer(ITIMER_PROF, &interval, NULL);
-}
-
 static void set_interval(int timer_type)
 {
 	struct itimerval interval;
@@ -53,6 +35,15 @@
 		panic("setitimer failed - errno = %d\n", errno);
 }
 
+void enable_timer(void)
+{
+	struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() },
+							{ 0, 1000000/hz() }});
+	if(setitimer(ITIMER_VIRTUAL, &enable, NULL))
+		printk("enable_timer - setitimer failed, errno = %d\n",
+		       errno);
+}
+
 void switch_timers(int to_real)
 {
 	struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
@@ -79,8 +70,9 @@
 {
 	if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
 		panic("Couldn't unset SIGVTALRM handler");
+	
 	set_handler(SIGALRM, (__sighandler_t) alarm_handler, 
-		    SA_NODEFER | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1);
+		    SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1);
 	set_interval(ITIMER_REAL);
 }
 
@@ -98,28 +90,24 @@
 	set_interval(ITIMER_VIRTUAL);
 }
 
-void set_timers(int set_signal)
-{
-	if(set_signal)
-		set_interval(ITIMER_VIRTUAL);
-	if(setitimer(ITIMER_PROF, &profile_interval, NULL) == -1)
-		panic("setitimer ITIMER_PROF failed - errno = %d\n", errno);
-}
-
 struct timeval local_offset = { 0, 0 };
 
 void do_gettimeofday(struct timeval *tv)
 {
+	time_lock();
 	gettimeofday(tv, NULL);
 	timeradd(tv, &local_offset, tv);
+	time_unlock();
 }
 
 void do_settimeofday(struct timeval *tv)
 {
 	struct timeval now;
 
+	time_lock();
 	gettimeofday(&now, NULL);
 	timersub(tv, &now, &local_offset);
+	time_unlock();
 }
 
 void idle_sleep(int secs)
diff -Nru a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
--- a/arch/um/kernel/time_kern.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/kernel/time_kern.c	Tue Oct 15 20:29:17 2002
@@ -27,21 +27,21 @@
 	return(HZ);
 }
 
+/* Changed at early boot */
 int timer_irq_inited = 0;
 
-/* kern_timer_on and missed_ticks are modified after kernel memory has been 
+/* missed_ticks will be modified after kernel memory has been 
  * write-protected, so this puts it in a section which will be left 
  * write-enabled.
  */
-int __attribute__ ((__section__ (".unprotected"))) kern_timer_on = 0;
-int __attribute__ ((__section__ (".unprotected"))) missed_ticks = 0;
+int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS];
 
 void timer_irq(struct uml_pt_regs *regs)
 {
-	int ticks = missed_ticks;
+	int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu];
 
         if(!timer_irq_inited) return;
-	missed_ticks = 0;
+	missed_ticks[cpu] = 0;
 	while(ticks--) do_IRQ(TIMER_IRQ, regs);
 }
 
@@ -86,6 +86,7 @@
 	return 0;
 }
 
+/* XXX Needs to be moved under sys-i386 */
 void __delay(um_udelay_t time)
 {
 	/* Stolen from the i386 __loop_delay */
@@ -114,6 +115,27 @@
 
 	n = (loops_per_jiffy * HZ * usecs) / 1000000;
 	for(i=0;i<n;i++) ;
+}
+
+void timer_handler(int sig, struct uml_pt_regs *regs)
+{
+#ifdef CONFIG_SMP
+	update_process_times(user_context(UPT_SP(regs)));
+#endif
+	if(current->thread_info->cpu == 0)
+		timer_irq(regs);
+}
+
+static spinlock_t timer_spinlock = SPIN_LOCK_UNLOCKED;
+
+void time_lock(void)
+{
+	spin_lock(&timer_spinlock);
+}
+
+void time_unlock(void)
+{
+	spin_unlock(&timer_spinlock);
 }
 
 int __init timer_init(void)
diff -Nru a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
--- a/arch/um/kernel/trap_kern.c	Tue Oct 15 20:29:12 2002
+++ b/arch/um/kernel/trap_kern.c	Tue Oct 15 20:29:12 2002
@@ -171,14 +171,18 @@
 
 spinlock_t trap_lock = SPIN_LOCK_UNLOCKED;
 
-void lock_trap(void)
-{
-	spin_lock(&trap_lock);
-}
+static int trap_index = 0;
 
-void unlock_trap(void)
+int next_trap_index(int limit)
 {
+	int ret;
+
+	spin_lock(&trap_lock);
+	ret = trap_index;
+	if(++trap_index == limit)
+		trap_index = 0;
 	spin_unlock(&trap_lock);
+	return(ret);
 }
 
 extern int debugger_pid;
@@ -209,6 +213,7 @@
 	tramp_stack :	0,
 };
 
+/* Accessed by the tracing thread, which automatically serializes access */
 static void *xterm_data;
 static int xterm_fd;
 
diff -Nru a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
--- a/arch/um/kernel/trap_user.c	Tue Oct 15 20:29:16 2002
+++ b/arch/um/kernel/trap_user.c	Tue Oct 15 20:29:16 2002
@@ -70,10 +70,10 @@
 	while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT);
 }
 
+/* Changed early in boot, and then only read */
 int debug = 0;
 int debug_stop = 1;
 int debug_parent = 0;
-
 int honeypot = 0;
 
 static int signal_tramp(void *arg)
@@ -90,7 +90,6 @@
 	signal(SIGUSR1, SIG_IGN);
 	change_sig(SIGCHLD, 0);
 	signal(SIGSEGV, (__sighandler_t) sig_handler);
-	set_timers(0);
 	set_cmdline("(idle thread)");
 	set_init_pid(os_getpid());
 	proc = arg;
@@ -99,6 +98,7 @@
 
 static void last_ditch_exit(int sig)
 {
+	kmalloc_ok = 0;
 	signal(SIGINT, SIG_DFL);
 	signal(SIGTERM, SIG_DFL);
 	signal(SIGHUP, SIG_DFL);
@@ -142,33 +142,20 @@
 	}
 }
 
-#ifdef CONFIG_SMP
-#error need to make these arrays
-#endif
-
+/* Accessed only by the tracing thread */
 int debugger_pid = -1;
 int debugger_parent = -1;
 int debugger_fd = -1;
 int gdb_pid = -1;
 
 struct {
-	unsigned long address;
-	int is_write;
-	int pid;
-	unsigned long sp;
-	int is_user;
-} segfault_record[1024];
-
-int segfault_index = 0;
-
-struct {
 	int pid;
 	int signal;
 	unsigned long addr;
 	struct timeval time;
-} signal_record[1024];
+} signal_record[1024][32];
 
-int signal_index = 0;
+int signal_index[32];
 int nsignals = 0;
 int debug_trace = 0;
 extern int io_nsignals, io_count, intr_count;
@@ -188,7 +175,7 @@
 	signal(SIGPIPE, SIG_IGN);
 	setup_tracer_winch();
 	tracing_pid = os_getpid();
-	printk("tracing thread pid = %d\n", tracing_pid);
+	printf("tracing thread pid = %d\n", tracing_pid);
 
 	pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
 	n = waitpid(pid, &status, WUNTRACED);
@@ -207,7 +194,7 @@
 	set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
 	set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1);
 	if(debug_trace){
-		printk("Tracing thread pausing to be attached\n");
+		printf("Tracing thread pausing to be attached\n");
 		stop();
 	}
 	if(debug){
@@ -219,14 +206,14 @@
 			init_parent_proxy(debugger_parent);
 			err = attach(debugger_parent);
 			if(err){
-				printk("Failed to attach debugger parent %d, "
+				printf("Failed to attach debugger parent %d, "
 				       "errno = %d\n", debugger_parent, err);
 				debugger_parent = -1;
 			}
 			else {
 				if(ptrace(PTRACE_SYSCALL, debugger_parent, 
 					  0, 0) < 0){
-					printk("Failed to continue debugger "
+					printf("Failed to continue debugger "
 					       "parent, errno = %d\n", errno);
 					debugger_parent = -1;
 				}
@@ -237,7 +224,7 @@
 	while(1){
 		if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){
 			if(errno != ECHILD){
-				printk("wait failed - errno = %d\n", errno);
+				printf("wait failed - errno = %d\n", errno);
 			}
 			continue;
 		}
@@ -259,36 +246,36 @@
 		if(WIFEXITED(status)) ;
 #ifdef notdef
 		{
-			printk("Child %d exited with status %d\n", pid, 
+			printf("Child %d exited with status %d\n", pid, 
 			       WEXITSTATUS(status));
 		}
 #endif
 		else if(WIFSIGNALED(status)){
 			sig = WTERMSIG(status);
 			if(sig != 9){
-				printk("Child %d exited with signal %d\n", pid,
+				printf("Child %d exited with signal %d\n", pid,
 				       sig);
 			}
 		}
 		else if(WIFSTOPPED(status)){
+			proc_id = pid_to_processor_id(pid);
 			sig = WSTOPSIG(status);
-			if(signal_index == 1024){
-				signal_index = 0;
+			if(signal_index[proc_id] == 1024){
+				signal_index[proc_id] = 0;
 				last_index = 1023;
 			}
-			else last_index = signal_index - 1;
+			else last_index = signal_index[proc_id] - 1;
 			if(((sig == SIGPROF) || (sig == SIGVTALRM) || 
 			    (sig == SIGALRM)) &&
-			   (signal_record[last_index].signal == sig) &&
-			   (signal_record[last_index].pid == pid))
-				signal_index = last_index;
-			signal_record[signal_index].pid = pid;
-			gettimeofday(&signal_record[signal_index].time, NULL);
+			   (signal_record[proc_id][last_index].signal == sig)&&
+			   (signal_record[proc_id][last_index].pid == pid))
+				signal_index[proc_id] = last_index;
+			signal_record[proc_id][signal_index[proc_id]].pid = pid;
+			gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL);
 			eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
-			signal_record[signal_index].addr = eip;
-			signal_record[signal_index++].signal = sig;
+			signal_record[proc_id][signal_index[proc_id]].addr = eip;
+			signal_record[proc_id][signal_index[proc_id]++].signal = sig;
 			
-			proc_id = pid_to_processor_id(pid);
 			if(proc_id == -1){
 				sleeping_process_signal(pid, sig);
 				continue;
@@ -314,7 +301,7 @@
 					ptrace(PTRACE_KILL, pid, 0, 0);
 					return(op == OP_REBOOT);
 				case OP_NONE:
-					printk("Detaching pid %d\n", pid);
+					printf("Detaching pid %d\n", pid);
 					detach(pid, SIGSTOP);
 					continue;
 				default:
@@ -413,22 +400,30 @@
 "    UML.  This implies 'jail'.\n\n"
 );
 
+/* Unlocked - don't care if this is a bit off */
 int nsegfaults = 0;
 
+struct {
+	unsigned long address;
+	int is_write;
+	int pid;
+	unsigned long sp;
+	int is_user;
+} segfault_record[1024];
+
 void segv_handler(int sig, struct uml_pt_regs *regs)
 {
 	struct sigcontext *context = regs->sc;
-	int index;
+	int index, max;
 
 	if(regs->is_user && !SEGV_IS_FIXABLE(context)){
 		bad_segv(SC_FAULT_ADDR(context), SC_IP(context), 
 			 SC_FAULT_WRITE(context));
 		return;
 	}
-	lock_trap();
-	index = segfault_index++;
-	if(segfault_index == 1024) segfault_index = 0;
-	unlock_trap();
+	max = sizeof(segfault_record)/sizeof(segfault_record[0]);
+	index = next_trap_index(max);
+
 	nsegfaults++;
 	segfault_record[index].address = SC_FAULT_ADDR(context);
 	segfault_record[index].pid = os_getpid();
@@ -439,8 +434,6 @@
 	     regs->is_user, context);
 }
 
-extern int kern_timer_on;
-
 struct signal_info {
 	void (*handler)(int, struct uml_pt_regs *);
 	int is_irq;
@@ -471,7 +464,7 @@
 {
 	struct uml_pt_regs save_regs, *r;
 	struct signal_info *info;
-	int save_errno = errno, save_timer = kern_timer_on, is_user;
+	int save_errno = errno, is_user;
 
 	unprotect_kernel_mem();
 
@@ -488,7 +481,6 @@
 
 	(*info->handler)(sig, r);
 
-	kern_timer_on = save_timer;
 	if(is_user){
 		interrupt_end();
 		block_signals();
@@ -505,19 +497,15 @@
 	sig_handler_common(sig, &sc);
 }
 
-extern int timer_irq_inited, missed_ticks;
-
-extern int jail_timer_off;
+extern int timer_irq_inited, missed_ticks[];
 
 void alarm_handler(int sig, struct sigcontext sc)
 {
 	int user;
 
 	if(!timer_irq_inited) return;
-	missed_ticks++;
+	missed_ticks[cpu()]++;
 	user = user_context(SC_SP(&sc));
-	if(!user && !kern_timer_on) return;
-	if(!user && jail_timer_off) return;
 
 	if(sig == SIGALRM)
 		switch_timers(0);
diff -Nru a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c
--- a/arch/um/kernel/tty_log.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/kernel/tty_log.c	Tue Oct 15 20:29:17 2002
@@ -17,8 +17,8 @@
 
 #define TTY_LOG_DIR "./"
 
-char *tty_log_dir = TTY_LOG_DIR;
-
+/* Set early in boot and then unchanged */
+static char *tty_log_dir = TTY_LOG_DIR;
 static int tty_log_fd = -1;
 
 #define TTY_LOG_OPEN 1
@@ -104,7 +104,7 @@
 
 	tty_log_fd = strtoul(name, &end, 0);
 	if(*end != '\0'){
-		printk("set_tty_log_dir - strtoul failed on '%s'\n", name);
+		printk("set_tty_log_fd - strtoul failed on '%s'\n", name);
 		tty_log_fd = -1;
 	}
 	return 0;
diff -Nru a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
--- a/arch/um/kernel/um_arch.c	Tue Oct 15 20:29:20 2002
+++ b/arch/um/kernel/um_arch.c	Tue Oct 15 20:29:20 2002
@@ -37,6 +37,11 @@
 
 #define DEFAULT_COMMAND_LINE "root=6200"
 
+struct cpuinfo_um boot_cpu_data = { 
+	.loops_per_jiffy = 	0,
+	.ipi_pipe = 		{ -1, -1 }
+};
+
 unsigned long thread_saved_pc(struct task_struct *task)
 {
 	return(os_process_pc(task->thread.extern_pid));
@@ -119,6 +124,7 @@
 #define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000)
 #define START (TOP - SIZE)
 
+/* Set in main */
 unsigned long host_task_size;
 unsigned long task_size;
 
@@ -129,17 +135,21 @@
 	task_size = START;
 }
 
+/* Set in early boot */
 unsigned long uml_physmem;
 unsigned long uml_reserved;
-
 unsigned long start_vm;
 unsigned long end_vm;
-
 int ncpus = 1;
 
+/* Pointer set in linux_main, the array itself is private to each thread,
+ * and changed at address space creation time so this poses no concurrency
+ * problems.
+ */
 static char *argv1_begin = NULL;
 static char *argv1_end = NULL;
 
+/* Set in early boot */
 static int have_root __initdata = 0;
 long physmem_size = 32 * 1024 * 1024;
 
@@ -258,8 +268,9 @@
 }
 
 extern int debug_trace;
-unsigned long brk_start;
 
+/* Set during early boot */
+unsigned long brk_start;
 static struct vm_reserved kernel_vm_reserved;
 
 #define MIN_VMALLOC (32 * 1024 * 1024)
@@ -316,11 +327,12 @@
 	end_vm = start_vm + virtmem_size;
 
 	if(virtmem_size < physmem_size)
-		printk(KERN_INFO "Kernel virtual memory size shrunk to %ld "
-		       "bytes\n", virtmem_size);
+		printf("Kernel virtual memory size shrunk to %ld bytes\n",
+		       virtmem_size);
 
 	err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved);
-	if(err)	panic("Failed to reserve VM area for kernel VM\n");
+	if(err)	
+		tracer_panic("Failed to reserve VM area for kernel VM\n");
 
   	uml_postsetup();
 
@@ -363,18 +375,6 @@
 	arch_check_bugs();
 	check_ptrace();
 	check_sigio();
-}
-
-spinlock_t pid_lock = SPIN_LOCK_UNLOCKED;
-
-void lock_pid(void)
-{
-	spin_lock(&pid_lock);
-}
-
-void unlock_pid(void)
-{
-	spin_unlock(&pid_lock);
 }
 
 /*
diff -Nru a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
--- a/arch/um/kernel/umid.c	Tue Oct 15 20:29:21 2002
+++ b/arch/um/kernel/umid.c	Tue Oct 15 20:29:21 2002
@@ -21,9 +21,13 @@
 #define UMID_LEN 64
 #define UML_DIR "~/.uml/"
 
+/* Changed by set_umid and make_umid, which are run early in boot */
 static char umid[UMID_LEN] = { 0 };
+
+/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */
 static char *uml_dir = UML_DIR;
 
+/* Changed by set_umid */
 static int umid_is_random = 1;
 static int umid_inited = 0;
 
diff -Nru a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
--- a/arch/um/kernel/user_util.c	Tue Oct 15 20:29:12 2002
+++ b/arch/um/kernel/user_util.c	Tue Oct 15 20:29:12 2002
@@ -1,5 +1,5 @@
 /* 
- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
  * Licensed under the GPL
  */
 
@@ -32,6 +32,7 @@
 
 #define COMMAND_LINE_SIZE _POSIX_ARG_MAX
 
+/* Changed in linux_main and setup_arch, which run before SMP is started */
 char saved_command_line[COMMAND_LINE_SIZE] = { 0 };
 char command_line[COMMAND_LINE_SIZE] = { 0 };
 
@@ -182,85 +183,6 @@
 	uname(&host);
 	sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
 		host.release, host.version, host.machine);
-}
-
-void close_fd(int fd)
-{
-	close(fd);
-}
-
-char *tempdir = NULL;
-
-static void __init find_tempdir(void)
-{
-	char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL };
-	int i;
-	char *dir = NULL;
-
-	if(tempdir != NULL) return;	/* We've already been called */
-	for(i = 0; dirs[i]; i++){
-		dir = getenv(dirs[i]);
-		if(dir != NULL) break;
-	}
-	if(dir == NULL) dir = "/tmp";
-	else if(*dir == '\0') dir = NULL;
-	if(dir != NULL) {
-		tempdir = malloc(strlen(dir) + 2);
-		if(tempdir == NULL){
-			fprintf(stderr, "Failed to malloc tempdir, "
-				"errno = %d\n", errno);
-			return;
-		}
-		strcpy(tempdir, dir);
-		strcat(tempdir, "/");
-	}
-}
-
-int make_tempfile(const char *template, char **out_tempname, int do_unlink)
-{
-	char tempname[MAXPATHLEN];
-	int fd;
-
-	find_tempdir();
-	if (*template != '/')
-		strcpy(tempname, tempdir);
-	else
-		*tempname = 0;
-	strcat(tempname, template);
-	if((fd = mkstemp(tempname)) < 0){
-		fprintf(stderr, "open - cannot create %s: %s\n", tempname, 
-			strerror(errno));
-		return -1;
-	}
-	if(do_unlink && (unlink(tempname) < 0)){
-		perror("unlink");
-		return -1;
-	}
-	if(out_tempname){
-		if((*out_tempname = strdup(tempname)) == NULL){
-			perror("strdup");
-			return -1;
-		}
-	}
-	return(fd);
-}
-
-int user_read(int fd, char *buf, int len)
-{
-	int err;
-
-	err = read(fd, buf, len);
-	if(err < 0) return(-errno);
-	else return(err);
-}
-
-int user_write(int fd, char *buf, int len)
-{
-	int err;
-
-	err = write(fd, buf, len);
-	if(err < 0) return(-errno);
-	else return(err);
 }
 
 /*
diff -Nru a/arch/um/main.c b/arch/um/main.c
--- a/arch/um/main.c	Tue Oct 15 20:29:14 2002
+++ b/arch/um/main.c	Tue Oct 15 20:29:14 2002
@@ -18,15 +18,22 @@
 #include "user.h"
 #include "init.h"
 
+/* Set in set_stklim, which is called from main and __wrap_malloc.  
+ * __wrap_malloc only calls it if main hasn't started.
+ */
 unsigned long stacksizelim;
 
+/* Set in main */
 char *linux_prog;
 
 #define PGD_BOUND (4 * 1024 * 1024)
 #define STACKSIZE (8 * 1024 * 1024)
 #define THREAD_NAME_LEN (256)
 
-char padding[THREAD_NAME_LEN] = { [ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0' };
+/* Never changed */
+static char padding[THREAD_NAME_LEN] = { 
+	[ 0 ...  THREAD_NAME_LEN - 2] = ' ', '\0' 
+};
 
 static void set_stklim(void)
 {
@@ -129,7 +136,8 @@
 	return(uml_exitcode);
 }
 
-int allocating_monbuf = 0;
+/* Changed in  __wrap___monstartup and __wrap_malloc very early */
+static int allocating_monbuf = 0;
 
 #ifdef PROFILING
 extern void __real___monstartup (unsigned long, unsigned long);
@@ -146,6 +154,7 @@
 extern void *__real_malloc(int);
 extern unsigned long host_task_size;
 
+/* Set in __wrap_malloc early */
 static void *gmon_buf = NULL;
 
 void *__wrap_malloc(int size)
diff -Nru a/arch/um/ptproxy/proxy.c b/arch/um/ptproxy/proxy.c
--- a/arch/um/ptproxy/proxy.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/ptproxy/proxy.c	Tue Oct 15 20:29:17 2002
@@ -30,6 +30,7 @@
 #include "user_util.h"
 #include "user.h"
 #include "os.h"
+#include "tempfile.h"
 
 static int debugger_wait(debugger_state *debugger, int *status, int options,
 			 int (*syscall)(debugger_state *debugger, pid_t child),
@@ -122,6 +123,7 @@
 	return(0);
 }
 
+/* Used by the tracing thread */
 static debugger_state parent;
 static int parent_syscall(debugger_state *debugger, int pid);
 
@@ -174,10 +176,7 @@
 	syscall_continue(debugger->pid);
 }
 
-#ifdef CONFIG_SMP
-#error need to make these arrays
-#endif
-
+/* Used by the tracing thread */
 static debugger_state debugger;
 static debugee_state debugee;
 
diff -Nru a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
--- a/arch/um/sys-i386/bugs.c	Tue Oct 15 20:29:20 2002
+++ b/arch/um/sys-i386/bugs.c	Tue Oct 15 20:29:20 2002
@@ -15,6 +15,7 @@
 
 #define MAXTOKEN 64
 
+/* Set during early boot */
 int cpu_has_cmov = 1;
 int cpu_has_xmm = 0;
 
diff -Nru a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
--- a/arch/um/sys-i386/ptrace_user.c	Tue Oct 15 20:29:14 2002
+++ b/arch/um/sys-i386/ptrace_user.c	Tue Oct 15 20:29:14 2002
@@ -59,6 +59,7 @@
 	}
 }
 
+/* Accessed only by the tracing thread */
 static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 };
 static int debugregs_seq = 0;
 
diff -Nru a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile
--- a/arch/um/sys-i386/util/Makefile	Tue Oct 15 20:29:16 2002
+++ b/arch/um/sys-i386/util/Makefile	Tue Oct 15 20:29:16 2002
@@ -1,16 +1,18 @@
-host-progs = mk_sc
+EXTRA_TARGETS	:= mk_sc mk_thread mk_thread_kern.o
 
-mk_sc-objs = mk_sc.o
+host-progs	:= mk_sc
+
+mk_sc-objs	:= mk_sc.o
 
 include $(TOPDIR)/Rules.make
 
-mk_thread : mk_thread_kern.o mk_thread_user.o
-	$(CC) $(CFLAGS) -o $@ mk_thread_user.o mk_thread_kern.o
+$(obj)/mk_thread : $(obj)/mk_thread_kern.o $(obj)/mk_thread_user.o
+	$(CC) $(CFLAGS) -o $@ $^
 
-mk_thread_user.o : mk_thread_user.c
+$(obj)/mk_thread_user.o : $(src)/mk_thread_user.c
 	$(CC) $(USER_CFLAGS) -c -o $@ $<
 
 clean :
-	$(RM) $(host-progs) mk_thread
+	$(RM) -f $(EXTRA_TARGETS)
 
 archmrproper : clean
diff -Nru a/arch/um/sys-ppc/miscthings.c b/arch/um/sys-ppc/miscthings.c
--- a/arch/um/sys-ppc/miscthings.c	Tue Oct 15 20:29:17 2002
+++ b/arch/um/sys-ppc/miscthings.c	Tue Oct 15 20:29:17 2002
@@ -2,9 +2,6 @@
 #include "linux/stddef.h"  // for NULL
 #include "linux/elf.h"  // for AT_NULL
 
-/* unsigned int local_bh_count[NR_CPUS]; */
-unsigned long isa_io_base = 0;
-
 /* The following function nicked from arch/ppc/kernel/process.c and
  * adapted slightly */
 /*
diff -Nru a/arch/um/uml.lds.S b/arch/um/uml.lds.S
--- a/arch/um/uml.lds.S	Tue Oct 15 20:29:16 2002
+++ b/arch/um/uml.lds.S	Tue Oct 15 20:29:16 2002
@@ -67,6 +67,9 @@
   __setup_start = .;
   .setup.init : { *(.setup.init) }
   __setup_end = .;
+  __per_cpu_start = . ; 
+  .data.percpu : { *(.data.percpu) }
+  __per_cpu_end = . ; 
   __initcall_start = .;
   .initcall.init : {
 	*(.initcall1.init) 
diff -Nru a/arch/um/util/Makefile b/arch/um/util/Makefile
--- a/arch/um/util/Makefile	Tue Oct 15 20:29:23 2002
+++ b/arch/um/util/Makefile	Tue Oct 15 20:29:23 2002
@@ -1,14 +1,14 @@
-include $(TOPDIR)/Rules.make
+EXTRA_TARGETS := mk_task mk_task_kern.o
 
-all : mk_task
+include $(TOPDIR)/Rules.make
 
-mk_task : mk_task_user.o mk_task_kern.o
-	$(CC) -o mk_task mk_task_user.o mk_task_kern.o
+$(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o
+	$(CC) -o $@ $^
 
-mk_task_user.o : mk_task_user.c
-	$(CC) -c $< 
+$(obj)/mk_task_user.o: $(src)/mk_task_user.c
+	$(CC) -o $@ -c $< 
 
-clean :
-	$(RM) mk_task *.o *~
+clean:
+	$(RM) $(EXTRA_TARGETS)
 
-archmrproper : clean
+archmrproper:
diff -Nru a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
--- a/arch/x86_64/boot/Makefile	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/boot/Makefile	Tue Oct 15 20:29:16 2002
@@ -21,28 +21,52 @@
 
 SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
 
-# ---------------------------------------------------------------------------
+# If you want the RAM disk device, define this to be the size in blocks.
+
+#RAMDISK := -DRAMDISK=512
+
+EXTRA_TARGETS	:= vmlinux.bin bootsect bootsect.o \
+		   setup setup.o zImage bzImage
 
-BOOT_INCL =	$(TOPDIR)/include/linux/config.h \
-		$(TOPDIR)/include/linux/autoconf.h \
-		$(TOPDIR)/include/asm/boot.h
-
-zImage: bootsect setup compressed/vmlinux tools/build
-	$(OBJCOPY) $(OBJCOPYFLAGS) compressed/vmlinux compressed/vmlinux.out
-	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
-
-bzImage: bbootsect bsetup compressed/bvmlinux tools/build
-	$(OBJCOPY) $(OBJCOPYFLAGS) compressed/bvmlinux compressed/bvmlinux.out
-	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
+CFLAGS += -m32
 
-bzImage-padded: bzImage
-	dd if=/dev/zero bs=1k count=70 >> bzImage
+host-progs	:= tools/build
 
-compressed/vmlinux: $(TOPDIR)/vmlinux
-	@$(MAKE) -C compressed vmlinux
+# 	Default
+
+boot: bzImage
+
+include $(TOPDIR)/Rules.make
+
+# ---------------------------------------------------------------------------
+
+$(obj)/zImage:  IMAGE_OFFSET := 0x1000
+$(obj)/zImage:  EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK)
+$(obj)/bzImage: IMAGE_OFFSET := 0x100000
+$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
+$(obj)/bzImage: BUILDFLAGS   := -b
+
+quiet_cmd_image = BUILD   $(echo_target)
+cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
+	    $(obj)/vmlinux.bin $(ROOT_DEV) > $@
+
+$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
+			      $(obj)/vmlinux.bin $(obj)/tools/build FORCE
+	$(call if_changed,image)
+
+$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
+	$(call if_changed,objcopy)
+
+LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
+LDFLAGS_setup	 := -Ttext 0x0 -s --oformat binary -e begtext
+
+$(obj)/setup $(obj)/bootsect: %: %.o FORCE
+	$(call if_changed,ld)
+
+$(obj)/compressed/vmlinux: FORCE
+	+@$(call descend,$(obj)/compressed,IMAGE_OFFSET=$(IMAGE_OFFSET) \
+		$(obj)/compressed/vmlinux)
 
-compressed/bvmlinux: $(TOPDIR)/vmlinux
-	@$(MAKE) -C compressed bvmlinux
 
 zdisk: $(BOOTIMAGE)
 	dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
@@ -51,53 +75,21 @@
 	if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
 	if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
 	cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
-	cp $(TOPDIR)/System.map $(INSTALL_PATH)/
+	cp System.map $(INSTALL_PATH)/
 	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
 install: $(BOOTIMAGE)
-	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
-
-tools/build: tools/build.c
-	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
-
-bootsect: bootsect.o
-	$(IA32_LD) -Ttext 0x0 -s --oformat binary -o $@ $<
-
-bootsect.o: bootsect.s
-	$(IA32_AS) -o $@ $<
-
-bootsect.s: bootsect.S Makefile $(BOOT_INCL)
-	$(IA32_CPP) $(CPPFLAGS) -traditional -D__ASSEMBLY__ $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-bbootsect: bbootsect.o
-	$(IA32_LD) -Ttext 0x0 -s --oformat binary $< -o $@
-
-bbootsect.o: bbootsect.s
-	$(IA32_AS) -o $@ $<
-
-bbootsect.s: bootsect.S Makefile $(BOOT_INCL)
-	$(IA32_CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-setup: setup.o
-	$(IA32_LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
-setup.o: setup.s
-	$(IA32_AS) -o $@ $<
-
-setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
-	$(IA32_CPP) $(CPPFLAGS) -traditional -D__ASSEMBLY__ $(SVGA_MODE) $(RAMDISK) $< -o $@
-
-bsetup: bsetup.o
-	$(IA32_LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
-
-bsetup.o: bsetup.s
-	$(IA32_AS) -o $@ $<
-
-bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
-	$(IA32_CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+	sh $(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
 
 clean:
-	rm -f tools/build
-	rm -f setup bootsect zImage compressed/vmlinux.out
-	rm -f bsetup bbootsect bzImage compressed/bvmlinux.out
-	@$(MAKE) -C compressed clean
+	@echo 'Cleaning up (boot)'
+	@rm -f $(host-progs) $(EXTRA_TARGETS)
+	+@$(call descend,$(obj)/compressed) clean
+
+archhelp:
+	@echo  '* bzImage	- Compressed kernel image (arch/$(ARCH)/boot/bzImage)'
+	@echo  '  install	- Install kernel using'
+	@echo  '                  (your) ~/bin/installkernel or'
+	@echo  '                  (distribution) /sbin/installkernel or'
+	@echo  '        	  install to $$(INSTALL_PATH) and run lilo'
+
diff -Nru a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
--- a/arch/x86_64/boot/compressed/Makefile	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/boot/compressed/Makefile	Tue Oct 15 20:29:16 2002
@@ -1,43 +1,38 @@
 #
-# linux/arch/i386/boot/compressed/Makefile
+# linux/arch/x86_64/boot/compressed/Makefile
 #
 # create a compressed vmlinux image from the original vmlinux
 #
+# Note all the files here are compiled/linked as 32bit executables.
+#
 
-HEAD = head.o
-SYSTEM = $(TOPDIR)/vmlinux
-
-OBJECTS = $(HEAD) misc.o
+EXTRA_TARGETS	:= vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+EXTRA_AFLAGS	:= -traditional -m32
 
-IA32_CFLAGS := -O2 -DSTDC_HEADERS
+# cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
+# -m32
+CFLAGS := -m32 -D__KERNEL__ -I$(TOPDIR)/include -O2  
+LDFLAGS := -m elf_i386
 
-#
-# ZIMAGE_OFFSET is the load offset of the compression loader
-# BZIMAGE_OFFSET is the load offset of the high loaded compression loader
-#
-BZIMAGE_OFFSET = 0x100000
+include $(TOPDIR)/Rules.make
 
-BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS)
+LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386
 
-all: vmlinux
+$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
+	$(call if_changed,ld)
 
-bvmlinux: piggy.o $(OBJECTS)
-	$(IA32_LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.o
+$(obj)/vmlinux.bin: vmlinux FORCE
+	strip vmlinux
+	$(call if_changed,objcopy)
 
-head.o: head.S
-	$(IA32_AS) -c head.S
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+	$(call if_changed,gzip)
 
-misc.o: misc.c
-	$(IA32_CC) $(IA32_CFLAGS) -c misc.c
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
 
-piggy.o:	$(SYSTEM)
-	tmppiggy=_tmp_$$$$piggy; \
-	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \
-	$(OBJCOPY) $(OBJCOPYFLAGS) $< $$tmppiggy; \
-	gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
-	echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \
-	$(IA32_LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \
-	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+	$(call if_changed,ld)
 
 clean:
-	rm -f vmlinux bvmlinux _tmp_*
+	@echo 'Cleaning up (boot/compressed)'
+	@rm -f $(EXTRA_TARGETS)
diff -Nru a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c
--- a/arch/x86_64/boot/compressed/misc.c	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/boot/compressed/misc.c	Tue Oct 15 20:29:16 2002
@@ -89,12 +89,8 @@
 static uch *output_data;
 static unsigned long output_ptr = 0;
 
- 
 static void *malloc(int size);
 static void free(void *where);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
  
 static void puts(const char *);
   
diff -Nru a/arch/x86_64/boot/compressed/miscsetup.h b/arch/x86_64/boot/compressed/miscsetup.h
--- a/arch/x86_64/boot/compressed/miscsetup.h	Tue Oct 15 20:29:21 2002
+++ b/arch/x86_64/boot/compressed/miscsetup.h	Tue Oct 15 20:29:21 2002
@@ -1,5 +1,5 @@
 #define NULL 0
-typedef unsigned int size_t; 
+//typedef unsigned int size_t; 
 
 
 struct screen_info {
diff -Nru a/arch/x86_64/boot/compressed/vmlinux.scr b/arch/x86_64/boot/compressed/vmlinux.scr
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/boot/compressed/vmlinux.scr	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,9 @@
+SECTIONS
+{
+  .data : { 
+	input_len = .;
+	LONG(input_data_end - input_data) input_data = .; 
+	*(.data) 
+	input_data_end = .; 
+	}
+}
diff -Nru a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S
--- a/arch/x86_64/boot/video.S	Tue Oct 15 20:29:17 2002
+++ b/arch/x86_64/boot/video.S	Tue Oct 15 20:29:17 2002
@@ -95,6 +95,7 @@
 #define PARAM_VESAPM_SEG	0x2e
 #define PARAM_VESAPM_OFF	0x30
 #define PARAM_LFB_PAGES		0x32
+#define PARAM_VESA_ATTRIB	0x34
 
 
 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
@@ -220,6 +221,8 @@
 	movl	%eax, %fs:(PARAM_LFB_COLORS)
 	movl	35(%di), %eax
 	movl	%eax, %fs:(PARAM_LFB_COLORS+4)
+	movw	0(%di), %ax
+	movw	%ax, %fs:(PARAM_VESA_ATTRIB)
 
 # get video mem size
 	leaw	modelist+1024, %di
diff -Nru a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile
--- a/arch/x86_64/ia32/Makefile	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/ia32/Makefile	Tue Oct 15 20:29:15 2002
@@ -2,17 +2,10 @@
 # Makefile for the ia32 kernel emulation subsystem.
 #
 
-USE_STANDARD_AS_RULE := true
-
 export-objs := ia32_ioctl.o sys_ia32.o
 
-all: ia32.o
-
-O_TARGET := ia32.o
 obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o \
 	ia32_signal.o \
 	ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o
-
-clean::
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
--- a/arch/x86_64/ia32/ia32_binfmt.c	Tue Oct 15 20:29:11 2002
+++ b/arch/x86_64/ia32/ia32_binfmt.c	Tue Oct 15 20:29:11 2002
@@ -58,6 +58,8 @@
     int tv_sec, tv_usec;
 };
 
+#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0)
+
 struct elf_prstatus
 {
 	struct elf_siginfo pr_info;	/* Info associated with signal */
@@ -162,6 +164,7 @@
 
 #define ELF_PLAT_INIT(r)		elf32_init(r)
 #define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
+int ia32_setup_arg_pages(struct linux_binprm *bprm);
 
 #undef start_thread
 #define start_thread(regs,new_rip,new_rsp) do { \
diff -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c
--- a/arch/x86_64/ia32/ia32_ioctl.c	Tue Oct 15 20:29:17 2002
+++ b/arch/x86_64/ia32/ia32_ioctl.c	Tue Oct 15 20:29:17 2002
@@ -55,6 +55,7 @@
 #include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/reiserfs_fs.h>
+#include <linux/dirent.h>
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 /* Ugh. This header really is not clean */
 #define min min
@@ -2000,6 +2001,7 @@
 
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 /* Ugh, LVM. Pitty it was not cleaned up before accepted :((. */
+/* AK: dev_t/kdev_t use here is somewhat dubious */
 typedef struct {
 	uint8_t vg_name[NAME_LEN];
 	uint32_t vg_number;
@@ -2034,7 +2036,7 @@
 	uint8_t pv_name[NAME_LEN];
 	uint8_t vg_name[NAME_LEN];
 	uint8_t system_id[NAME_LEN];
-	kdev_t pv_dev;
+	__u32 pv_dev;
 	uint32_t pv_number;
 	uint32_t pv_status;
 	uint32_t pv_allocatable;
@@ -3084,38 +3086,108 @@
 	return err;	
 }
 
-static int generic_long_put(unsigned int fd, unsigned int cmd, unsigned long arg)
+
+struct dirent32 {
+	unsigned int		d_ino;
+	__kernel_off_t32	d_off;
+	unsigned short	d_reclen;
+	char		d_name[256]; /* We must not include limits.h! */
+};
+
+#define	VFAT_IOCTL_READDIR_BOTH32	_IOR('r', 1, struct dirent32 [2])
+#define	VFAT_IOCTL_READDIR_SHORT32	_IOR('r', 2, struct dirent32 [2])
+
+static int put_dirent32(struct dirent *src, struct dirent32 *dst)
 {
 	int ret; 
-	unsigned long val = 0; 
-	mm_segment_t oldseg = get_fs();
+	ret = put_user(src->d_ino, &dst->d_ino); 
+	ret |= __put_user(src->d_off, &dst->d_off); 
+	ret |= __put_user(src->d_reclen, &dst->d_reclen); 
+	if (__copy_to_user(&dst->d_name, src->d_name, src->d_reclen))
+		ret |= -EFAULT;
+	return ret;
+} 
+
+static int vfat_ioctl32(unsigned fd, unsigned cmd,  void *ptr) 
+{
+	int ret;
+	mm_segment_t oldfs = get_fs();
+	struct dirent d[2]; 
+
 	set_fs(KERNEL_DS);
-	cmd = (cmd & 0xc000ffff)  | (sizeof(unsigned long) << _IOC_SIZESHIFT); 
-	ret = sys_ioctl(fd, cmd, (unsigned long)&val);  
-	set_fs(oldseg); 
-	if (!ret || val) {
-		if (put_user((int)val, (unsigned int *)arg)) 
-			return -EFAULT; 
+	ret = sys_ioctl(fd,cmd,(unsigned long)&d); 
+	set_fs(oldfs); 
+	if (!ret) { 
+		ret |= put_dirent32(&d[0], (struct dirent32 *)ptr); 
+		ret |= put_dirent32(&d[1], ((struct dirent32 *)ptr) + 1); 
 	}
 	return ret; 
 } 
 
-static int generic_long_get(unsigned int fd, unsigned int cmd, unsigned long arg)
+
+
+#define REISERFS_IOC_UNPACK32               _IOW(0xCD,1,int)
+
+static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) 
+{ 
+	if (cmd == REISERFS_IOC_UNPACK32) 
+		cmd = REISERFS_IOC_UNPACK; 
+	return sys_ioctl(fd,cmd,ptr); 
+} 
+
+#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
+
+static int autofs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) 
 {
 	int ret; 
-	unsigned int ival; 
-	unsigned long val = 0; 
-	mm_segment_t oldseg = get_fs();
-	if (get_user(ival, (unsigned int *)arg))
-		return -EFAULT;
-	val = ival;
+	unsigned long val;
+	mm_segment_t oldfs = get_fs();
 	set_fs(KERNEL_DS);
-	cmd = (cmd & 0xc000ffff)  | (sizeof(unsigned long) << _IOC_SIZESHIFT); 
-	ret = sys_ioctl(fd, cmd, (unsigned long)&val);  
-	set_fs(oldseg); 
+	ret = sys_ioctl(fd, AUTOFS_IOC_SETTIMEOUT32, (unsigned long)&val); 
+	set_fs(oldfs); 
+	if (!ret) 
+		ret = put_user(val, (int *) ptr); 
 	return ret; 
 } 
 
+#define RTC_IRQP_READ32	_IOR('p', 0x0b, unsigned int)	 /* Read IRQ rate   */
+#define RTC_IRQP_SET32	_IOW('p', 0x0c, unsigned int)	 /* Set IRQ rate    */
+#define RTC_EPOCH_READ32	_IOR('p', 0x0d, unsigned)	 /* Read epoch      */
+#define RTC_EPOCH_SET32		_IOW('p', 0x0e, unsigned)	 /* Set epoch       */
+
+static int rtc32_ioctl(unsigned fd, unsigned cmd, unsigned long arg) 
+{ 
+	unsigned long val;
+	mm_segment_t oldfs = get_fs(); 
+	int ret; 
+	
+	switch (cmd) { 
+	case RTC_IRQP_READ32: 
+		set_fs(KERNEL_DS); 
+		ret = sys_ioctl(fd, RTC_IRQP_READ, (unsigned long)&val); 
+		set_fs(oldfs); 
+		if (!ret)
+			ret = put_user(val, (unsigned int*) arg); 
+		return ret; 
+
+	case RTC_IRQP_SET32: 
+		cmd = RTC_EPOCH_SET; 
+		break; 
+
+	case RTC_EPOCH_READ32:
+		set_fs(KERNEL_DS); 
+		ret = sys_ioctl(fd, RTC_EPOCH_READ, (unsigned long) &val); 
+		set_fs(oldfs); 
+		if (!ret)
+			ret = put_user(val, (unsigned int*) arg); 
+		return ret; 
+
+	case RTC_EPOCH_SET32:
+		cmd = RTC_EPOCH_SET; 
+		break; 
+	} 
+	return sys_ioctl(fd,cmd,arg); 
+} 
 
 struct ioctl_trans {
 	unsigned long cmd;
@@ -3344,14 +3416,10 @@
 COMPATIBLE_IOCTL(RTC_SET_TIME)
 COMPATIBLE_IOCTL(RTC_WKALM_SET)
 COMPATIBLE_IOCTL(RTC_WKALM_RD)
-#define RTC_IRQP_READ32	_IOR('p', 0x0b, unsigned int)	 /* Read IRQ rate   */
-HANDLE_IOCTL(RTC_IRQP_READ32,generic_long_put)
-#define RTC_IRQP_SET32	_IOW('p', 0x0c, unsigned int)	 /* Set IRQ rate    */
-HANDLE_IOCTL(RTC_IRQP_SET32,generic_long_get)
-#define RTC_EPOCH_READ32	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
-#define RTC_EPOCH_SET32		_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
-HANDLE_IOCTL(RTC_EPOCH_READ32, generic_long_put)
-HANDLE_IOCTL(RTC_EPOCH_SET32, generic_long_get)
+HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl)
+HANDLE_IOCTL(RTC_IRQP_SET32,rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl)
+HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl)
 /* Little m */
 COMPATIBLE_IOCTL(MTIOCTOP)
 /* Socket level stuff */
@@ -3619,8 +3687,7 @@
 COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
 COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
 COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
-#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
-HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, generic_long_get); 
+HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, autofs_ioctl32); 
 /* DEVFS */
 COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
 COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
@@ -3687,7 +3754,9 @@
 COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
 COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
 #endif /* DRM */
-COMPATIBLE_IOCTL(REISERFS_IOC_UNPACK);
+HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32);
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32);
+HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32);
 /* serial driver */ 
 HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl);
 HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl);
@@ -3854,6 +3923,8 @@
 #define IOCTL_HASHSIZE 256
 struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
 
+extern struct ioctl_trans ioctl_start[], ioctl_end[]; 
+
 static inline unsigned long ioctl32_hash(unsigned long cmd)
 {
 	return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
@@ -3879,7 +3950,6 @@
 static int __init init_sys32_ioctl(void)
 {
 	int i;
-	extern struct ioctl_trans ioctl_start[], ioctl_end[]; 
 
 	for (i = 0; &ioctl_start[i] < &ioctl_end[0]; i++) {
 		if (ioctl_start[i].next != 0) { 
@@ -3894,57 +3964,108 @@
 
 __initcall(init_sys32_ioctl);
 
-static struct ioctl_trans *additional_ioctls;
-
-/* Always call these with kernel lock held! */
+static struct ioctl_trans *ioctl_free_list;
 
+/* Never free them really. This avoids SMP races. With a Read-Copy-Update
+   enabled kernel we could just use the RCU infrastructure for this. */
+static void free_ioctl(struct ioctl_trans *t) 
+{ 
+	t->cmd = 0; 
+	mb();
+	t->next = ioctl_free_list;
+	ioctl_free_list = t;
+} 
 
 int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *))
 {
-	int i;
-	if (!additional_ioctls) {
-		additional_ioctls = (struct ioctl_trans *)get_zeroed_page(GFP_KERNEL);
-		if (!additional_ioctls)
-			return -ENOMEM;
+	struct ioctl_trans *t;
+	unsigned long hash = ioctl32_hash(cmd);
+
+	lock_kernel(); 
+	for (t = (struct ioctl_trans *)ioctl32_hash_table[hash];
+	     t;
+	     t = t->next) { 
+		if (t->cmd == cmd) {
+			printk("Trying to register duplicated ioctl32 handler %x\n", cmd);
+			unlock_kernel();
+			return -EINVAL; 
 	}
-	for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++)
-		if (!additional_ioctls[i].cmd)
-			break;
-	if (i == PAGE_SIZE/sizeof(struct ioctl_trans))
+	} 
+
+	if (ioctl_free_list) { 
+		t = ioctl_free_list; 
+		ioctl_free_list = t->next; 
+	} else { 
+		t = kmalloc(sizeof(struct ioctl_trans), GFP_KERNEL); 
+		if (!t) { 
+			unlock_kernel();
 		return -ENOMEM;
-	additional_ioctls[i].cmd = cmd;
-	if (!handler)
-		additional_ioctls[i].handler = 
-	    (int (*)(unsigned,unsigned,unsigned long, struct file *))sys_ioctl;
-	else
-		additional_ioctls[i].handler = handler;
-	ioctl32_insert_translation(&additional_ioctls[i]);
+		}
+	}
+	
+	t->next = NULL;
+	t->cmd = cmd;
+	t->handler = handler; 
+	ioctl32_insert_translation(t);
+
+	unlock_kernel();
 	return 0;
 }
 
+static inline int builtin_ioctl(struct ioctl_trans *t)
+{ 
+	return t >= (struct ioctl_trans *)ioctl_start &&
+	       t < (struct ioctl_trans *)ioctl_end; 
+} 
+
+/* Problem: 
+   This function cannot unregister duplicate ioctls, because they are not
+   unique.
+   When they happen we need to extend the prototype to pass handler too. */
 
 int unregister_ioctl32_conversion(unsigned int cmd)
 {
 	unsigned long hash = ioctl32_hash(cmd);
 	struct ioctl_trans *t, *t1;
 
-	t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash];
-	if (!t) return -EINVAL;
-	if (t->cmd == cmd && t >= additional_ioctls &&
-	    (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
+	lock_kernel(); 
+
+	t = (struct ioctl_trans *)ioctl32_hash_table[hash];
+	if (!t) { 
+		unlock_kernel();
+		return -EINVAL;
+	} 
+
+	if (t->cmd == cmd) { 
+		if (builtin_ioctl(t)) {
+			printk("%p tried to unregister builtin ioctl %x\n",
+			       __builtin_return_address(0), cmd);
+		} else { 
 		ioctl32_hash_table[hash] = t->next;
-		t->cmd = 0;
+			free_ioctl(t); 
+			unlock_kernel();
 		return 0;
-	} else while (t->next) {
+		}
+	} 
+	while (t->next) {
 		t1 = (struct ioctl_trans *)(long)t->next;
-		if (t1->cmd == cmd && t1 >= additional_ioctls &&
-		    (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) {
-			t1->cmd = 0;
+		if (t1->cmd == cmd) { 
+			if (builtin_ioctl(t1)) {
+				printk("%p tried to unregister builtin ioctl %x\n",
+				       __builtin_return_address(0), cmd);
+				goto out;
+			} else { 
 			t->next = t1->next;
+				free_ioctl(t1); 
+				unlock_kernel();
 			return 0;
 		}
+		}
 		t = t1;
 	}
+	printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n", cmd);
+ out:
+	unlock_kernel();
 	return -EINVAL;
 }
 
@@ -3967,10 +4088,10 @@
 		goto out;
 	}
 
-	t = (struct ioctl_trans *)(long)ioctl32_hash_table [ioctl32_hash (cmd)];
+	t = (struct ioctl_trans *)ioctl32_hash_table [ioctl32_hash (cmd)];
 
 	while (t && t->cmd != cmd)
-		t = (struct ioctl_trans *)(long)t->next;
+		t = (struct ioctl_trans *)t->next;
 	if (t) {
 		handler = t->handler;
 		error = handler(fd, cmd, arg, filp);
diff -Nru a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
--- a/arch/x86_64/ia32/ia32_signal.c	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/ia32/ia32_signal.c	Tue Oct 15 20:29:16 2002
@@ -81,11 +81,11 @@
 	sigset_t saveset;
 
 	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	siginitset(&current->blocked, mask);
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 
 	regs.rax = -EINTR;
 	while (1) {
@@ -170,10 +170,7 @@
     	  asm volatile("movl %%" #seg ",%0" : "=r" (cur));		\
 	  if (pre != cur) loadsegment(seg,pre); }
 
-	/* Reload fs and gs if they have changed in the signal handler.
-	   This does not handle long fs/gs base changes in the handler, but does not clobber 
-	   them at least in the normal case. */ 
-	
+	/* Reload fs and gs if they have changed in the signal handler. */
 	
 	{
 		unsigned short gs; 
@@ -181,11 +178,18 @@
 		load_gs_index(gs); 
 	} 
 	RELOAD_SEG(fs);
+	RELOAD_SEG(ds);
+	RELOAD_SEG(es);
 
 	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
 	COPY(dx); COPY(cx); COPY(ip);
 	/* Don't touch extended registers */ 
 	
+	err |= __get_user(regs->cs, &sc->cs); 
+	regs->cs |= 2;  
+	err |= __get_user(regs->ss, &sc->ss); 
+	regs->ss |= 2; 
+
 	{
 		unsigned int tmpflags;
 		err |= __get_user(tmpflags, &sc->eflags);
@@ -231,10 +235,10 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	
 	if (ia32_restore_sigcontext(&regs, &frame->sc, &eax))
 		goto badframe;
@@ -258,10 +262,10 @@
 		goto badframe;
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	
 	if (ia32_restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax))
 		goto badframe;
@@ -299,6 +303,10 @@
 	err |= __put_user(tmp, (unsigned int *)&sc->gs);
 	__asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp));
 	err |= __put_user(tmp, (unsigned int *)&sc->fs);
+	__asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp));
+	err |= __put_user(tmp, (unsigned int *)&sc->ds);
+	__asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp));
+	err |= __put_user(tmp, (unsigned int *)&sc->es);
 
 	err |= __put_user((u32)regs->rdi, &sc->edi);
 	err |= __put_user((u32)regs->rsi, &sc->esi);
@@ -308,6 +316,8 @@
 	err |= __put_user((u32)regs->rdx, &sc->edx);
 	err |= __put_user((u32)regs->rcx, &sc->ecx);
 	err |= __put_user((u32)regs->rax, &sc->eax);
+	err |= __put_user((u32)regs->cs, &sc->cs);
+	err |= __put_user((u32)regs->ss, &sc->ss);
 	err |= __put_user(current->thread.trap_no, &sc->trapno);
 	err |= __put_user(current->thread.error_code, &sc->err);
 	err |= __put_user((u32)regs->rip, &sc->eip);
@@ -406,8 +416,13 @@
 	regs->rsp = (unsigned long) frame;
 	regs->rip = (unsigned long) ka->sa.sa_handler;
 
+	asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); 
+	asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); 
+
+	regs->cs = __USER32_CS; 
+	regs->ss = __USER32_DS; 
+
 	set_fs(USER_DS);
-	// XXX: cs
 	regs->eflags &= ~TF_MASK;
 
 #if DEBUG_SIG
@@ -479,8 +494,13 @@
 	regs->rsp = (unsigned long) frame;
 	regs->rip = (unsigned long) ka->sa.sa_handler;
 
+	asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); 
+	asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); 
+	
+	regs->cs = __USER32_CS; 
+	regs->ss = __USER32_DS; 
+
 	set_fs(USER_DS);
-	// XXX: cs
 	regs->eflags &= ~TF_MASK;
 
 #if DEBUG_SIG
diff -Nru a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
--- a/arch/x86_64/ia32/ia32entry.S	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/ia32/ia32entry.S	Tue Oct 15 20:29:16 2002
@@ -171,7 +171,7 @@
 	.quad sys_umount			/* new_umount */
 	.quad ni_syscall			/* old lock syscall holder */
 	.quad sys32_ioctl
-	.quad sys32_fcntl		/* 55 */
+	.quad sys32_fcntl64		/* 55 */
 	.quad ni_syscall			/* old mpx syscall holder */
 	.quad sys_setpgid
 	.quad ni_syscall			/* old ulimit syscall holder */
@@ -319,15 +319,15 @@
 	.quad sys_getgid		/* 200 */
 	.quad sys_geteuid
 	.quad sys_getegid
-	.quad sys32_setreuid
-	.quad sys32_setregid
-	.quad sys32_getgroups	/* 205 */
-	.quad sys32_setgroups
+	.quad sys_setreuid
+	.quad sys_setregid
+	.quad sys_getgroups	/* 205 */
+	.quad sys_setgroups
 	.quad sys_fchown
-	.quad sys32_setresuid
-	.quad sys32_getresuid
-	.quad sys32_setresgid	/* 210 */
-	.quad sys32_getresgid
+	.quad sys_setresuid
+	.quad sys_getresuid
+	.quad sys_setresgid	/* 210 */
+	.quad sys_getresgid
 	.quad sys_chown
 	.quad sys_setuid
 	.quad sys_setgid
@@ -356,9 +356,19 @@
 	.quad sys_fremovexattr
 	.quad sys_tkill		/* 238 */ 
 	.quad sys_sendfile64 
-	.quad sys_futex
+	.quad sys_futex		/* 240 */
         .quad sys32_sched_setaffinity
         .quad sys32_sched_getaffinity
+	.quad sys_set_thread_area
+	.quad sys_get_thread_area
+	.quad sys32_io_setup
+	.quad sys_io_destroy
+	.quad sys_io_getevents
+	.quad sys_io_submit
+	.quad sys_io_cancel
+	.quad sys_ni_syscall /* 250 alloc_huge_pages */
+	.quad sys_ni_syscall /* free_huge_pages */
+	.quad sys_ni_syscall /* exit_group */
 ia32_syscall_end:		
 	.rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
 		.quad ni_syscall
diff -Nru a/arch/x86_64/ia32/ipc32.c b/arch/x86_64/ia32/ipc32.c
--- a/arch/x86_64/ia32/ipc32.c	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/ia32/ipc32.c	Tue Oct 15 20:29:16 2002
@@ -152,8 +152,8 @@
 };
 
 struct ipc_kludge {
-	struct msgbuf *msgp;
-	int msgtyp;
+	u32 msgp;
+	s32 msgtyp;
 };
 
 
@@ -268,14 +268,19 @@
 	return err;
 }
 
+#define MAXBUF (64*1024)
+
 static int
 do_sys32_msgsnd (int first, int second, int third, void *uptr)
 {
-	struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
+	struct msgbuf *p;
 	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
 	mm_segment_t old_fs;
 	int err;
 
+	if (second >= MAXBUF-sizeof(struct msgbuf))
+		return -EINVAL;
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
 	if (!p)
 		return -ENOMEM;
 	err = get_user(p->mtype, &up->mtype);
@@ -312,13 +317,15 @@
 		uptr = (void *)A(ipck.msgp);
 		msgtyp = ipck.msgtyp;
 	}
+	if (second >= MAXBUF-sizeof(struct msgbuf))
+		return -EINVAL; 
 	err = -ENOMEM;
-	p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER);
+	p = kmalloc(second + sizeof(struct msgbuf), GFP_USER);
 	if (!p)
 		goto out;
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
-	err = sys_msgrcv(first, p, second + 4, msgtyp, third);
+	err = sys_msgrcv(first, p, second, msgtyp, third);
 	set_fs(old_fs);
 	if (err < 0)
 		goto free_then_out;
diff -Nru a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
--- a/arch/x86_64/ia32/ptrace32.c	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/ia32/ptrace32.c	Tue Oct 15 20:29:15 2002
@@ -24,6 +24,7 @@
 #include <asm/i387.h>
 #include <asm/fpu32.h>
 #include <linux/mm.h>
+#include <linux/ptrace.h>
 
 #define R32(l,q) \
 	case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break
@@ -35,20 +36,32 @@
 
 	switch (regno) {
 	case offsetof(struct user32, regs.fs):
+		if (val && (val & 3) != 3) return -EIO; 
 	        child->thread.fs = val; 
 		break;
 	case offsetof(struct user32, regs.gs):
+		if (val && (val & 3) != 3) return -EIO; 
 		child->thread.gs = val;
 		break;
 	case offsetof(struct user32, regs.ds):
+		if (val && (val & 3) != 3) return -EIO; 
 		child->thread.ds = val;
 		break;
 	case offsetof(struct user32, regs.es):
+		if (val && (val & 3) != 3) return -EIO; 
 		child->thread.es = val;
 		break;
 
-	R32(cs, cs);
-	R32(ss, ss);
+	case offsetof(struct user32, regs.ss): 
+		if ((val & 3) != 3) return -EIO;
+		stack[offsetof(struct pt_regs, ss)/8] = val; 
+		break;
+
+	case offsetof(struct user32, regs.cs): 
+		if ((val & 3) != 3) return -EIO;
+		stack[offsetof(struct pt_regs, cs)/8] = val; 
+		break;
+
 	R32(ebx, rbx); 
 	R32(ecx, rcx);
 	R32(edx, rdx);
diff -Nru a/arch/x86_64/ia32/socket32.c b/arch/x86_64/ia32/socket32.c
--- a/arch/x86_64/ia32/socket32.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/ia32/socket32.c	Tue Oct 15 20:29:12 2002
@@ -436,20 +436,33 @@
 
 	sock = sockfd_lookup(fd, &err);
 	if (sock != NULL) {
-		struct scm_cookie scm;
+		struct sock_iocb *si;
+		struct kiocb iocb;
 
 		if (sock->file->f_flags & O_NONBLOCK)
 			user_flags |= MSG_DONTWAIT;
-		memset(&scm, 0, sizeof(scm));
-		err = sock->ops->recvmsg(sock, &kern_msg, total_len,
-					 user_flags, &scm);
+
+		init_sync_kiocb(&iocb, NULL);
+		si = kiocb_to_siocb(&iocb);
+		si->sock = sock;
+		si->scm = &si->async_scm;
+		si->msg = &kern_msg;
+		si->size = total_len;
+		si->flags = user_flags;
+		memset(si->scm, 0, sizeof(*si->scm));
+
+		err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len,
+					 user_flags, si->scm);
+		if (-EIOCBQUEUED == err)
+			err = wait_on_sync_kiocb(&iocb);
+
 		if(err >= 0) {
 			len = err;
 			if(!kern_msg.msg_control) {
-				if(sock->passcred || scm.fp)
+				if(sock->passcred || si->scm->fp)
 					kern_msg.msg_flags |= MSG_CTRUNC;
-				if(scm.fp)
-					__scm_destroy(&scm);
+				if(si->scm->fp)
+					__scm_destroy(si->scm);
 			} else {
 				/* If recvmsg processing itself placed some
 				 * control messages into user space, it's is
@@ -463,9 +476,10 @@
 				if(sock->passcred)
 					put_cmsg32(&kern_msg,
 						   SOL_SOCKET, SCM_CREDENTIALS,
-						   sizeof(scm.creds), &scm.creds);
-				if(scm.fp != NULL)
-					scm_detach_fds32(&kern_msg, &scm);
+						   sizeof(si->scm->creds),
+						   &si->scm->creds);
+				if(si->scm->fp != NULL)
+					scm_detach_fds32(&kern_msg, si->scm);
 			}
 		}
 		sockfd_put(sock);
diff -Nru a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
--- a/arch/x86_64/ia32/sys_ia32.c	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/ia32/sys_ia32.c	Tue Oct 15 20:29:16 2002
@@ -57,6 +57,7 @@
 #include <linux/ipc.h>
 #include <linux/rwsem.h>
 #include <linux/init.h>
+#include <linux/aio_abi.h>
 #include <asm/mman.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
@@ -1288,37 +1289,71 @@
 
 extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
-asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static inline int get_flock64(struct ia32_flock64 *fl32, struct flock *fl64)
 {
-	switch (cmd) {
-	case F_GETLK:
-	case F_SETLK:
-	case F_SETLKW:
-		{
-	struct flock f;
-	mm_segment_t old_fs;
-	long ret;
-
-			if (get_flock(&f, (struct flock32 *)arg))
-			return -EFAULT;
-			old_fs = get_fs(); set_fs (KERNEL_DS);
-		ret = sys_fcntl(fd, cmd, (unsigned long)&f);
-			set_fs (old_fs);
-			if (ret) return ret;
-			if (put_flock(&f, (struct flock32 *)arg))
-			return -EFAULT;
-			return 0;
+	if (access_ok(fl32, sizeof(struct ia32_flock64), VERIFY_WRITE)) {
+		int ret = __get_user(fl64->l_type, &fl32->l_type); 
+		ret |= __get_user(fl64->l_whence, &fl32->l_whence);
+		ret |= __get_user(fl64->l_start, &fl32->l_start); 
+		ret |= __get_user(fl64->l_len, &fl32->l_len); 
+		ret |= __get_user(fl64->l_pid, &fl32->l_pid); 
+		return ret; 
 		}
-	default:
-		return sys_fcntl(fd, cmd, (unsigned long)arg);
+	return -EFAULT; 
+}
+
+static inline int put_flock64(struct ia32_flock64 *fl32, struct flock *fl64)
+{
+	if (access_ok(fl32, sizeof(struct ia32_flock64), VERIFY_WRITE)) {
+		int ret = __put_user(fl64->l_type, &fl32->l_type); 
+		ret |= __put_user(fl64->l_whence, &fl32->l_whence);
+		ret |= __put_user(fl64->l_start, &fl32->l_start); 
+		ret |= __put_user(fl64->l_len, &fl32->l_len); 
+		ret |= __put_user(fl64->l_pid, &fl32->l_pid); 
+		return ret; 
 	}
+	return -EFAULT; 
 }
 
 asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-	if (cmd >= F_GETLK64 && cmd <= F_SETLKW64)
-		return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg);
-	return sys32_fcntl(fd, cmd, arg);
+	struct flock fl64;  
+	mm_segment_t oldfs = get_fs(); 
+	int ret = 0, origcmd; 
+	unsigned long origarg;
+
+	origcmd = cmd; 
+	origarg = arg;
+	switch (cmd) {
+	case F_GETLK: 
+	case F_SETLK:
+	case F_SETLKW:
+		ret = get_flock(&fl64, (struct flock32 *)arg); 
+		arg = (unsigned long) &fl64; 
+		set_fs(KERNEL_DS); 
+		break;
+	case F_GETLK64: 
+		cmd = F_GETLK; 
+		goto cnv64;
+	case F_SETLK64: 
+		cmd = F_SETLK; 
+		goto cnv64; 
+	case F_SETLKW64:
+		cmd = F_SETLKW; 
+	cnv64:
+		ret = get_flock64((struct ia32_flock64 *)arg, &fl64); 
+		arg = (unsigned long)&fl64; 
+		set_fs(KERNEL_DS); 
+		break; 
+	}
+	if (!ret)
+		ret = sys_fcntl(fd, cmd, arg);
+	set_fs(oldfs); 
+	if (origcmd == F_GETLK && !ret)
+		ret = put_flock(&fl64, (struct flock32 *)origarg); 
+	else if (cmd == F_GETLK && !ret)
+		ret = put_flock64((struct ia32_flock64 *)origarg, &fl64); 
+	return ret; 
 }
 
 int sys32_ni_syscall(int call)
@@ -1362,42 +1397,6 @@
 	return ret;
 }
 
-/*
- * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-
-static inline int
-get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
-{
-	if (ufdset) {
-		unsigned long odd;
-
-		if (verify_area(VERIFY_READ, ufdset, n*sizeof(u32)))
-			return -EFAULT;
-
-		odd = n & 1UL;
-		n &= ~1UL;
-		while (n) {
-			unsigned long h, l;
-			__get_user(l, ufdset);
-			__get_user(h, ufdset+1);
-			ufdset += 2;
-			*fdset++ = h << 32 | l;
-			n -= 2;
-		}
-		if (odd)
-			__get_user(*fdset, ufdset);
-	} else {
-		/* Tricky, must clear full unsigned long in the
-		 * kernel fdset at the end, this makes sure that
-		 * actually happens.
-		 */
-		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
-	}
-	return 0;
-}
-
 extern asmlinkage long sys_sysfs(int option, unsigned long arg1,
 				unsigned long arg2);
 
@@ -1704,136 +1703,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid);
-
-asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid)
-{
-	uid_t sruid, seuid;
-
-	sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
-	seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
-	return sys_setreuid(sruid, seuid);
-}
-
-extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid);
-
-asmlinkage long
-sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid,
-		__kernel_uid_t32 suid)
-{
-	uid_t sruid, seuid, ssuid;
-
-	sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid);
-	seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid);
-	ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid);
-	return sys_setresuid(sruid, seuid, ssuid);
-}
-
-extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
-
-asmlinkage long
-sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid,
-		__kernel_uid_t32 *suid)
-{
-	uid_t a, b, c;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-		
-	set_fs (KERNEL_DS);
-	ret = sys_getresuid(&a, &b, &c);
-	set_fs (old_fs);
-	if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid))
-		return -EFAULT;
-	return ret;
-}
-
-extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid);
-
-asmlinkage long
-sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid)
-{
-	gid_t srgid, segid;
-
-	srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
-	segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
-	return sys_setregid(srgid, segid);
-}
-
-extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid);
-
-asmlinkage long
-sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid,
-		__kernel_gid_t32 sgid)
-{
-	gid_t srgid, segid, ssgid;
-
-	srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid);
-	segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
-	ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid);
-	return sys_setresgid(srgid, segid, ssgid);
-}
-
-extern asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
-
-asmlinkage long
-sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid,
-		__kernel_gid_t32 *sgid) 
-{
-	gid_t a, b, c;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-		
-	set_fs (KERNEL_DS);
-	ret = sys_getresgid(&a, &b, &c);
-	set_fs (old_fs);
-	if (!ret) {
-		ret = put_user (a, rgid);
-		ret |= put_user (b, egid);
-		ret |= put_user (c, sgid);
-	}
-	return ret;
-}
-
-extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist);
-
-asmlinkage long
-sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
-{
-	gid_t gl[NGROUPS];
-	int ret, i;
-	mm_segment_t old_fs = get_fs ();
-	
-	set_fs (KERNEL_DS);
-	ret = sys_getgroups(gidsetsize, gl);
-	set_fs (old_fs);
-	if (gidsetsize && ret > 0 && ret <= NGROUPS)
-		for (i = 0; i < ret; i++, grouplist++)
-			if (put_user (gl[i], grouplist))
-				return -EFAULT;
-	return ret;
-}
-
-extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist);
-
-asmlinkage long
-sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
-{
-	gid_t gl[NGROUPS];
-	int ret, i;
-	mm_segment_t old_fs = get_fs ();
-	
-	if ((unsigned) gidsetsize > NGROUPS)
-		return -EINVAL;
-	for (i = 0; i < gidsetsize; i++, grouplist++)
-		if (get_user (gl[i], grouplist))
-			return -EFAULT;
-        set_fs (KERNEL_DS);
-	ret = sys_setgroups(gidsetsize, gl);
-	set_fs (old_fs);
-	return ret;
-}
-
-
 extern void check_pending(int signum);
 
 asmlinkage long sys_utimes(char *, struct timeval *);
@@ -1943,7 +1812,7 @@
 	int ret = sys_newuname(name);
 	
 	if (current->personality == PER_LINUX32 && !ret) {
-		ret = copy_to_user(name->machine, "i386\0\0", 8);
+		ret = copy_to_user(name->machine, "i686\0\0", 6);
 	}
 	return ret;
 }
@@ -2164,7 +2033,7 @@
 	err=copy_to_user(name, &system_utsname, sizeof (*name));
 	up_read(&uts_sem);
 	if (current->personality == PER_LINUX32) 
-		err |= copy_to_user(&name->machine, "i386", 5);
+		err |= copy_to_user(&name->machine, "i686", 5);
 	return err?-EFAULT:0;
 }
 
@@ -2270,16 +2139,17 @@
 asmlinkage int sys32_fork(struct pt_regs regs)
 {
 	struct task_struct *p;
-	p = do_fork(SIGCHLD, regs.rsp, &regs, 0);
+	p = do_fork(SIGCHLD, regs.rsp, &regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
 asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
 {
 	struct task_struct *p;
+	int *user_tid = (int *)regs.rdx;
 	if (!newsp)
 		newsp = regs.rsp;
-	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
+	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
@@ -2296,7 +2166,7 @@
 asmlinkage int sys32_vfork(struct pt_regs regs)
 {
 	struct task_struct *p;
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
+	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
@@ -2695,10 +2565,26 @@
 	return err;
 }
 
+extern long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
+
+long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p)
+{ 
+	long ret; 
+	aio_context_t ctx64;
+	mm_segment_t oldfs = get_fs(); 	
+	set_fs(KERNEL_DS); 
+	ret = sys_io_setup(nr_reqs, &ctx64); 
+	set_fs(oldfs); 
+	/* truncating is ok because it's a user address */
+	if (!ret) 
+		ret = put_user((u32)ctx64, ctx32p);
+	return ret;
+} 
+
 struct exec_domain ia32_exec_domain = { 
-	name: "linux/x86",
-	pers_low: PER_LINUX32,
-	pers_high: PER_LINUX32,
+	.name = "linux/x86",
+	.pers_low = PER_LINUX32,
+	.pers_high = PER_LINUX32,
 };      
 
 static int __init ia32_init (void)
diff -Nru a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
--- a/arch/x86_64/kernel/Makefile	Tue Oct 15 20:29:19 2002
+++ b/arch/x86_64/kernel/Makefile	Tue Oct 15 20:29:19 2002
@@ -2,15 +2,14 @@
 # Makefile for the linux kernel.
 #
 
-O_TARGET	:= kernel.o
 EXTRA_TARGETS 	:= head.o head64.o init_task.o
 
-export-objs     := mtrr.o x8664_ksyms.o
+export-objs     := mtrr.o x8664_ksyms.o pci-gart.o
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \
 		pci-dma.o x8664_ksyms.o i387.o syscall.o vsyscall.o \
-		setup64.o bluesmoke.o bootflag.o
+		setup64.o bluesmoke.o bootflag.o e820.o reboot.o
 
 obj-$(CONFIG_MTRR)	+= mtrr.o
 obj-$(CONFIG_X86_MSR)	+= msr.o
@@ -18,9 +17,11 @@
 obj-$(CONFIG_SMP)	+= smp.o smpboot.o trampoline.o
 obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o  nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o mpparse.o
-#obj-$(CONFIG_ACPI)             += acpi.o
+obj-$(CONFIG_ACPI)             += acpi.o
 #obj-$(CONFIG_ACPI_SLEEP)       += acpi_wakeup.o
 obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
+obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o
+obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o
 
 EXTRA_AFLAGS := -traditional
 
diff -Nru a/arch/x86_64/kernel/acpi.c b/arch/x86_64/kernel/acpi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/kernel/acpi.c	Tue Oct 15 20:29:24 2002
@@ -0,0 +1,569 @@
+/*
+ *  acpi.c - Architecture-Specific Low-Level ACPI Support
+ *
+ *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
+ *  Copyright (C) 2001 Patrick Mochel <mochel@osdl.org>
+ *  Copyright (C) 2002 Andi Kleen, SuSE Labs (x86-64 port)
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+#include <linux/acpi.h>
+#include <asm/mpspec.h>
+#include <asm/io.h>
+#include <asm/apic.h>
+#include <asm/apicdef.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/io_apic.h>
+
+extern int acpi_disabled;
+
+#define PREFIX			"ACPI: "
+
+
+/* --------------------------------------------------------------------------
+                              Boot-time Configuration
+   -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ACPI_BOOT
+
+enum acpi_irq_model_id		acpi_irq_model;
+
+
+/*
+ * Use reserved fixmap pages for physical-to-virtual mappings of ACPI tables.
+ * Note that the same range is used for each table, so tables that need to
+ * persist should be memcpy'd.
+ */
+
+extern unsigned long end_pfn; 
+
+/* rely on all ACPI tables being in the direct mapping */
+char *
+__acpi_map_table (
+	unsigned long	phys_addr,
+	unsigned long	size)
+{
+	if (!phys_addr || !size)
+		return NULL;
+
+	if (phys_addr < (end_pfn << PAGE_SHIFT)) 
+		return __va(phys_addr); 
+
+	printk("acpi mapping beyond end_pfn: %lx > %lx\n", phys_addr, end_pfn<<PAGE_SHIFT);
+	return NULL; 
+} 	      
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+int acpi_lapic;
+
+static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
+
+
+static int __init
+acpi_parse_madt (
+	unsigned long		phys_addr,
+	unsigned long		size)
+{
+	struct acpi_table_madt	*madt = NULL;
+
+	if (!phys_addr || !size)
+		return -EINVAL;
+
+	madt = (struct acpi_table_madt *) __acpi_map_table(phys_addr, size);
+	if (!madt) {
+		printk(KERN_WARNING PREFIX "Unable to map MADT\n");
+		return -ENODEV;
+	}
+
+	if (madt->lapic_address)
+		acpi_lapic_addr = (u64) madt->lapic_address;
+
+	printk(KERN_INFO PREFIX "Local APIC address 0x%08x\n",
+		madt->lapic_address);
+
+	return 0;
+}
+
+
+static int __init
+acpi_parse_lapic (
+	acpi_table_entry_header *header)
+{
+	struct acpi_table_lapic	*processor = NULL;
+
+	processor = (struct acpi_table_lapic*) header;
+	if (!processor)
+		return -EINVAL;
+
+	acpi_table_print_madt_entry(header);
+
+	mp_register_lapic (
+		processor->id,					   /* APIC ID */
+		processor->flags.enabled);			  /* Enabled? */
+
+	return 0;
+}
+
+
+static int __init
+acpi_parse_lapic_addr_ovr (
+	acpi_table_entry_header *header)
+{
+	struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL;
+
+	lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr*) header;
+	if (!lapic_addr_ovr)
+		return -EINVAL;
+
+	acpi_lapic_addr = lapic_addr_ovr->address;
+
+	return 0;
+}
+
+
+static int __init
+acpi_parse_lapic_nmi (
+	acpi_table_entry_header *header)
+{
+	struct acpi_table_lapic_nmi *lapic_nmi = NULL;
+
+	lapic_nmi = (struct acpi_table_lapic_nmi*) header;
+	if (!lapic_nmi)
+		return -EINVAL;
+
+	acpi_table_print_madt_entry(header);
+
+	if (lapic_nmi->lint != 1)
+		printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");
+
+	return 0;
+}
+
+#endif /*CONFIG_X86_LOCAL_APIC*/
+
+#ifdef CONFIG_X86_IO_APIC
+
+int acpi_ioapic;
+
+static int __init
+acpi_parse_ioapic (
+	acpi_table_entry_header *header)
+{
+	struct acpi_table_ioapic *ioapic = NULL;
+
+	ioapic = (struct acpi_table_ioapic*) header;
+	if (!ioapic)
+		return -EINVAL;
+ 
+	acpi_table_print_madt_entry(header);
+
+	mp_register_ioapic (
+		ioapic->id,
+		ioapic->address,
+		ioapic->global_irq_base);
+ 
+	return 0;
+}
+
+
+static int __init
+acpi_parse_int_src_ovr (
+	acpi_table_entry_header *header)
+{
+	struct acpi_table_int_src_ovr *intsrc = NULL;
+
+	intsrc = (struct acpi_table_int_src_ovr*) header;
+	if (!intsrc)
+		return -EINVAL;
+
+	acpi_table_print_madt_entry(header);
+
+	mp_override_legacy_irq (
+		intsrc->bus_irq,
+		intsrc->flags.polarity,
+		intsrc->flags.trigger,
+		intsrc->global_irq);
+
+	return 0;
+}
+
+
+static int __init
+acpi_parse_nmi_src (
+	acpi_table_entry_header *header)
+{
+	struct acpi_table_nmi_src *nmi_src = NULL;
+
+	nmi_src = (struct acpi_table_nmi_src*) header;
+	if (!nmi_src)
+		return -EINVAL;
+
+	acpi_table_print_madt_entry(header);
+
+	/* TBD: Support nimsrc entries? */
+
+	return 0;
+}
+
+#endif /*CONFIG_X86_IO_APIC*/
+
+#ifdef CONFIG_HPET_TIMER
+static int __init
+acpi_parse_hpet (
+	unsigned long		phys_addr,
+	unsigned long		size)
+{
+	struct acpi_table_hpet *hpet_tbl;
+
+	hpet_tbl = __va(phys_addr);
+
+	if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) {
+		printk(KERN_WARNING "acpi: HPET timers must be located in memory.\n");
+		return -1;
+	}
+
+	hpet.address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32);
+
+	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet.address);
+
+	return 0;
+} 
+#endif
+
+static unsigned long __init
+acpi_scan_rsdp (
+	unsigned long		start,
+	unsigned long		length)
+{
+	unsigned long		offset = 0;
+	unsigned long		sig_len = sizeof("RSD PTR ") - 1;
+
+	/*
+	 * Scan all 16-byte boundaries of the physical memory region for the
+	 * RSDP signature.
+	 */
+	for (offset = 0; offset < length; offset += 16) {
+		if (strncmp((char *) (start + offset), "RSD PTR ", sig_len))
+			continue;
+		return (start + offset);
+	}
+
+	return 0;
+}
+
+
+unsigned long __init
+acpi_find_rsdp (void)
+{
+	unsigned long		rsdp_phys = 0;
+
+	/*
+	 * Scan memory looking for the RSDP signature. First search EBDA (low
+	 * memory) paragraphs and then search upper memory (E0000-FFFFF).
+	 */
+	rsdp_phys = acpi_scan_rsdp (0, 0x400);
+	if (!rsdp_phys)
+		rsdp_phys = acpi_scan_rsdp (0xE0000, 0xFFFFF);
+
+	return rsdp_phys;
+}
+
+
+int __init
+acpi_boot_init (
+	char			*cmdline)
+{
+	int			result = 0;
+
+	/*
+	 * The default interrupt routing model is PIC (8259).  This gets
+	 * overriden if IOAPICs are enumerated (below).
+	 */
+	acpi_irq_model = ACPI_IRQ_MODEL_PIC;
+
+	/* 
+	 * Initialize the ACPI boot-time table parser.
+	 */
+	result = acpi_table_init(cmdline);
+	if (result)
+		return result;
+
+	result = acpi_blacklisted();
+	if (result) {
+		acpi_disabled = 1;
+		return result;
+	} else
+               printk(KERN_NOTICE PREFIX "BIOS passes blacklist\n");
+
+
+#ifdef CONFIG_X86_LOCAL_APIC
+
+	/* 
+	 * MADT
+	 * ----
+	 * Parse the Multiple APIC Description Table (MADT), if exists.
+	 * Note that this table provides platform SMP configuration 
+	 * information -- the successor to MPS tables.
+	 */
+
+	result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+	if (!result) {
+		printk(KERN_WARNING PREFIX "MADT not present\n");
+		return 0;
+	}
+	else if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing MADT\n");
+		return result;
+	}
+	else if (result > 1) 
+		printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n");
+
+	/* 
+	 * Local APIC
+	 * ----------
+	 * Note that the LAPIC address is obtained from the MADT (32-bit value)
+	 * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
+	 */
+
+	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr);
+	if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
+		return result;
+	}
+
+	mp_register_lapic_address(acpi_lapic_addr);
+
+	result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic);
+	if (!result) { 
+		printk(KERN_ERR PREFIX "No LAPIC entries present\n");
+		/* TBD: Cleanup to allow fallback to MPS */
+		return -ENODEV;
+	}
+	else if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
+		/* TBD: Cleanup to allow fallback to MPS */
+		return result;
+	}
+
+	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi);
+	if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
+		/* TBD: Cleanup to allow fallback to MPS */
+		return result;
+	}
+
+	acpi_lapic = 1;
+
+#endif /*CONFIG_X86_LOCAL_APIC*/
+
+#ifdef CONFIG_X86_IO_APIC
+
+	/* 
+	 * I/O APIC 
+	 * --------
+	 */
+
+	result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic);
+	if (!result) { 
+		printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
+		return -ENODEV;
+	}
+	else if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
+		return result;
+	}
+
+	/* Build a default routing table for legacy (ISA) interrupts. */
+	mp_config_acpi_legacy_irqs();
+
+	result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr);
+	if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
+		/* TBD: Cleanup to allow fallback to MPS */
+		return result;
+	}
+
+	result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src);
+	if (result < 0) {
+		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
+		/* TBD: Cleanup to allow fallback to MPS */
+		return result;
+	}
+
+	acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
+
+	acpi_ioapic = 1;
+
+#endif /*CONFIG_X86_IO_APIC*/
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	if (acpi_lapic && acpi_ioapic)
+		smp_found_config = 1;
+#endif
+
+#ifdef CONFIG_HPET_TIMER
+	result = acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+	if (result < 0) 
+		printk("ACPI: no HPET table found (%d).\n", result); 
+#endif
+
+	return 0;
+}
+
+#endif /*CONFIG_ACPI_BOOT*/
+
+
+/* --------------------------------------------------------------------------
+                              Low-Level Sleep Support
+   -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ACPI_SLEEP
+
+#error not ported to x86-64 yet
+
+#define DEBUG
+
+#ifdef DEBUG
+#include <linux/serial.h>
+#endif
+
+/* address in low memory of the wakeup routine. */
+unsigned long acpi_wakeup_address = 0;
+
+/* new page directory that we will be using */
+static pmd_t *pmd;
+
+/* saved page directory */
+static pmd_t saved_pmd;
+
+/* page which we'll use for the new page directory */
+static pte_t *ptep;
+
+extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
+
+/*
+ * acpi_create_identity_pmd
+ *
+ * Create a new, identity mapped pmd.
+ *
+ * Do this by creating new page directory, and marking all the pages as R/W
+ * Then set it as the new Page Middle Directory.
+ * And, of course, flush the TLB so it takes effect.
+ *
+ * We save the address of the old one, for later restoration.
+ */
+static void acpi_create_identity_pmd (void)
+{
+	pgd_t *pgd;
+	int i;
+
+	ptep = (pte_t*)__get_free_page(GFP_KERNEL);
+
+	/* fill page with low mapping */
+	for (i = 0; i < PTRS_PER_PTE; i++)
+		set_pte(ptep + i, mk_pte_phys(i << PAGE_SHIFT, PAGE_SHARED));
+
+	pgd = pgd_offset(current->active_mm, 0);
+	pmd = pmd_alloc(current->mm,pgd, 0);
+
+	/* save the old pmd */
+	saved_pmd = *pmd;
+
+	/* set the new one */
+	set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(ptep)));
+
+	/* flush the TLB */
+	local_flush_tlb();
+}
+
+/*
+ * acpi_restore_pmd
+ *
+ * Restore the old pmd saved by acpi_create_identity_pmd and
+ * free the page that said function alloc'd
+ */
+static void acpi_restore_pmd (void)
+{
+	set_pmd(pmd, saved_pmd);
+	local_flush_tlb();
+	free_page((unsigned long)ptep);
+}
+
+/**
+ * acpi_save_state_mem - save kernel state
+ *
+ * Create an identity mapped page table and copy the wakeup routine to
+ * low memory.
+ */
+int acpi_save_state_mem (void)
+{
+	acpi_create_identity_pmd();
+	acpi_copy_wakeup_routine(acpi_wakeup_address);
+
+	return 0;
+}
+
+/**
+ * acpi_save_state_disk - save kernel state to disk
+ *
+ */
+int acpi_save_state_disk (void)
+{
+	return 1;
+}
+
+/*
+ * acpi_restore_state
+ */
+void acpi_restore_state_mem (void)
+{
+	acpi_restore_pmd();
+}
+
+/**
+ * acpi_reserve_bootmem - do _very_ early ACPI initialisation
+ *
+ * We allocate a page in low memory for the wakeup
+ * routine for when we come back from a sleep state. The
+ * runtime allocator allows specification of <16M pages, but not
+ * <1M pages.
+ */
+void __init acpi_reserve_bootmem(void)
+{
+	acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE);
+	printk(KERN_DEBUG "ACPI: have wakeup address 0x%8.8lx\n", acpi_wakeup_address);
+}
+
+#endif /*CONFIG_ACPI_SLEEP*/
+
+void acpi_pci_link_exit(void) {}
diff -Nru a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/kernel/aperture.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,123 @@
+/* 
+ * Firmware replacement code.
+ * 
+ * Work around broken BIOSes that don't set an aperture. 
+ * The IOMMU code needs an aperture even who no AGP is present in the system.
+ * Map the aperture over some low memory.  This is cheaper than doing bounce 
+ * buffering. The memory is lost. This is done at early boot because only
+ * the bootmem allocator can allocate 32+MB. 
+ * 
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ * $Id: aperture.c,v 1.2 2002/09/19 19:25:32 ak Exp $
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mmzone.h>
+#include <linux/pci_ids.h>
+#include <asm/e820.h>
+#include <asm/io.h>
+#include <asm/proto.h>
+#include <asm/pci-direct.h>
+
+int fallback_aper_order __initdata = 1; /* 64MB */
+int fallback_aper_force __initdata = 0; 
+
+extern int no_iommu, force_mmu;
+
+/* This code runs before the PCI subsystem is initialized, so just 
+   access the northbridge directly. */
+
+#define NB_ID_3 (PCI_VENDOR_ID_AMD | (0x1103<<16))
+
+static u32 __init allocate_aperture(void) 
+{
+#ifdef CONFIG_DISCONTIGMEM
+	pg_data_t *nd0 = NODE_DATA(0);
+#else
+	pg_data_t *nd0 = &contig_page_data;
+#endif	
+	u32 aper_size;
+	void *p; 
+
+	if (fallback_aper_order > 7) 
+		fallback_aper_order = 7; 
+	aper_size = (32 * 1024 * 1024) << fallback_aper_order; 
+
+	/* 
+         * Aperture has to be naturally aligned it seems. This means an
+	 * 2GB aperture won't have much changes to succeed in the lower 4GB of 
+	 * memory. Unfortunately we cannot move it up because that would make
+	 * the IOMMU useless.
+	 */
+	p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0); 
+	if (!p || __pa(p)+aper_size > 0xffffffff) {
+		printk("Cannot allocate aperture memory hole (%p,%uK)\n",
+		       p, aper_size>>10);
+		if (p)
+			free_bootmem((unsigned long)p, aper_size); 
+		return 0;
+	}
+	printk("Mapping aperture over %d KB of RAM @ %lx\n",  
+	       aper_size >> 10, __pa(p)); 
+	return (u32)__pa(p); 
+}
+
+void __init iommu_hole_init(void) 
+{ 
+	int fix, num; 
+	u32 aper_size, aper_alloc, aper_order;
+	u64 aper_base; 
+
+	if (no_iommu)
+		return;
+	if (end_pfn < (0xffffffff>>PAGE_SHIFT) && !force_mmu) 
+		return;
+
+	printk("Checking aperture...\n"); 
+
+	fix = 0;
+	for (num = 24; num < 32; num++) {		
+		if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) 
+			continue;	
+
+		aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7; 
+		aper_size = (32 * 1024 * 1024) << aper_order; 
+		aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
+		aper_base <<= 25; 
+
+		printk("CPU %d: aperture @ %Lx size %u KB\n", num-24, 
+		       aper_base, aper_size>>10);
+		if (!aper_base || aper_base + aper_size >= 0xffffffff) {
+			fix = 1; 
+			break; 
+		} 
+		
+		if (e820_mapped(aper_base, aper_base + aper_size, E820_RAM)) {  
+			printk("Aperture pointing to e820 RAM. Ignoring.\n");
+			fix = 1; 
+			break; 
+		} 
+	} 
+
+	if (!fix && !fallback_aper_force) 
+		return; 
+
+	printk("Your BIOS is broken and doesn't leave a aperture memory hole\n");
+	aper_alloc = allocate_aperture(); 
+	if (!aper_alloc) 
+		return; 
+
+	for (num = 24; num < 32; num++) { 		
+		if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) 
+			continue;	
+
+		/* Don't enable translation yet. That is done later. 
+		   Assume this BIOS didn't initialise the GART so 
+		   just overwrite all previous bits */ 
+		write_pci_config(0, num, 3, 0x90, fallback_aper_order<<1); 
+		write_pci_config(0, num, 3, 0x94, aper_alloc>>25); 
+	} 
+} 
diff -Nru a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
--- a/arch/x86_64/kernel/apic.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/kernel/apic.c	Tue Oct 15 20:29:12 2002
@@ -30,6 +30,8 @@
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
 
+int disable_apic_timer __initdata;
+
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer = 0;
 
@@ -598,7 +600,7 @@
 
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
-		if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1)
+		if (boot_cpu_data.x86 > 6)
 			break;
 		goto no_apic;
 	case X86_VENDOR_INTEL:
@@ -640,6 +642,8 @@
 	if (nmi_watchdog != NMI_NONE)
 		nmi_watchdog = NMI_LOCAL_APIC;
 
+	apic_pm_init1();
+
 	printk("Found and enabled local APIC!\n");
 	return 0;
 
@@ -695,59 +699,6 @@
 }
 
 /*
- * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts
- * per second. We assume that the caller has already set up the local
- * APIC.
- *
- * The APIC timer is not exactly sync with the external timer chip, it
- * closely follows bus clocks.
- */
-
-/*
- * The timer chip is already set up at HZ interrupts per second here,
- * but we do not accept timer interrupts yet. We only allow the BP
- * to calibrate.
- */
-static unsigned int __init get_8254_timer_count(void)
-{
-	extern spinlock_t i8253_lock;
-	unsigned long flags;
-
-	unsigned int count;
-
-	spin_lock_irqsave(&i8253_lock, flags);
-
-	outb_p(0x00, 0x43);
-	count = inb_p(0x40);
-	count |= inb_p(0x40) << 8;
-
-	spin_unlock_irqrestore(&i8253_lock, flags);
-
-	return count;
-}
-
-void __init wait_8254_wraparound(void)
-{
-	unsigned int curr_count, prev_count=~0;
-	int delta;
-
-	curr_count = get_8254_timer_count();
-
-	do {
-		prev_count = curr_count;
-		curr_count = get_8254_timer_count();
-		delta = curr_count-prev_count;
-
-	/*
-	 * This limit for delta seems arbitrary, but it isn't, it's
-	 * slightly above the level of error a buggy Mercury/Neptune
-	 * chipset timer can cause.
-	 */
-
-	} while (delta < 300);
-}
-
-/*
  * This function sets up the local APIC timer, with a timeout of
  * 'clocks' APIC bus clock. During calibration we actually call
  * this function twice on the boot CPU, once with a bogus timeout
@@ -779,52 +730,36 @@
 	apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
 }
 
-void setup_APIC_timer(void * data)
+static void setup_APIC_timer(unsigned int clocks)
 {
-	unsigned int clocks = (unsigned long) data, slice, t0, t1;
 	unsigned long flags;
-	int delta;
 
-	local_save_flags(flags);
-	local_irq_enable();
-	/*
-	 * ok, Intel has some smart code in their APIC that knows
-	 * if a CPU was in 'hlt' lowpower mode, and this increases
-	 * its APIC arbitration priority. To avoid the external timer
-	 * IRQ APIC event being in synchron with the APIC clock we
-	 * introduce an interrupt skew to spread out timer events.
-	 *
-	 * The number of slices within a 'big' timeslice is smp_num_cpus+1
-	 */
-
-	slice = clocks / (smp_num_cpus+1);
-	printk("cpu: %d, clocks: %d, slice: %d\n",
-		smp_processor_id(), clocks, slice);
-
-	/*
-	 * Wait for IRQ0's slice:
-	 */
-	wait_8254_wraparound();
+	local_irq_save(flags);
 
+#if 0
+	/* For some reasons this doesn't work on Simics, so fake it for now */ 
+	if (strstr(boot_cpu_data.x86_model_id, "Screwdriver")) { 
 	__setup_APIC_LVTT(clocks);
+		return;
+	} 
+#endif
 
-	t0 = apic_read(APIC_TMICT)*APIC_DIVISOR;
-	/* Wait till TMCCT gets reloaded from TMICT... */
-	do {
-		t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
-		delta = (int)(t0 - t1 - slice*(smp_processor_id()+1));
-	} while (delta >= 0);
-	/* Now wait for our slice for real. */
+	/* wait for irq slice */
+	{
+		int c1, c2;
+		outb_p(0x00, 0x43);
+		c2 = inb_p(0x40);
+		c2 |= inb_p(0x40) << 8;
 	do {
-		t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR;
-		delta = (int)(t0 - t1 - slice*(smp_processor_id()+1));
-	} while (delta < 0);
+			c1 = c2;
+			outb_p(0x00, 0x43);
+			c2 = inb_p(0x40);
+			c2 |= inb_p(0x40) << 8;
+		} while (c2 - c1 < 300);
+	}
 
 	__setup_APIC_LVTT(clocks);
 
-	printk("CPU%d<T0:%u,T1:%u,D:%d,S:%u,C:%u>\n",
-			smp_processor_id(), t0, t1, delta, slice, clocks);
-
 	local_irq_restore(flags);
 }
 
@@ -841,16 +776,12 @@
  * APIC irq that way.
  */
 
+#define TICK_COUNT 100000000
+
 int __init calibrate_APIC_clock(void)
 {
-	unsigned long t1 = 0, t2 = 0;
-	int tt1, tt2;
+	int apic, apic_start, tsc, tsc_start;
 	int result;
-	int i;
-	const int LOOPS = HZ/10;
-
-	printk("calibrating APIC timer ...\n");
-
 	/*
 	 * Put whatever arbitrary (but long enough) timeout
 	 * value into the APIC clock, we just want to get the
@@ -858,61 +789,31 @@
 	 */
 	__setup_APIC_LVTT(1000000000);
 
-	/*
-	 * The timer chip counts down to zero. Let's wait
-	 * for a wraparound to start exact measurement:
-	 * (the current tick might have been already half done)
-	 */
-
-	wait_8254_wraparound();
-
-	/*
-	 * We wrapped around just now. Let's start:
-	 */
-	if (cpu_has_tsc)
-		rdtscll(t1);
-	tt1 = apic_read(APIC_TMCCT);
-
-	/*
-	 * Let's wait LOOPS wraprounds:
-	 */
-	for (i = 0; i < LOOPS; i++)
-		wait_8254_wraparound();
-
-	tt2 = apic_read(APIC_TMCCT);
-	if (cpu_has_tsc)
-		rdtscll(t2);
-
-	/*
-	 * The APIC bus clock counter is 32 bits only, it
-	 * might have overflown, but note that we use signed
-	 * longs, thus no extra care needed.
-	 *
-	 * underflown to be exact, as the timer counts down ;)
-	 */
-
-	result = (tt1-tt2)*APIC_DIVISOR/LOOPS;
-
-	
-	printk("t1 = %ld t2 = %ld tt1 = %d tt2 = %d\n", t1, t2, tt1, tt2);  
+	apic_start = apic_read(APIC_TMCCT);
+	rdtscl(tsc_start);
 
+	do {
+		apic = apic_read(APIC_TMCCT);
+		rdtscl(tsc);
+	} while ((tsc - tsc_start) < TICK_COUNT && (apic - apic_start) < TICK_COUNT);
 
-	if (cpu_has_tsc)
-		printk("..... CPU clock speed is %d.%04d MHz.\n",
-			((int)(t2-t1)/LOOPS)/(1000000/HZ),
-			((int)(t2-t1)/LOOPS)%(1000000/HZ));
+	result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start);
 
-	printk("..... host bus clock speed is %d.%04d MHz.\n",
-		result/(1000000/HZ),
-		result%(1000000/HZ));
+	printk("Detected %d.%03d MHz APIC timer.\n",
+		result / 1000 / 1000, result / 1000 % 1000);
 
-	return result;
+	return result * APIC_DIVISOR / HZ;
 }
 
 static unsigned int calibration_result;
 
-void __init setup_APIC_clocks (void)
+void __init setup_boot_APIC_clock (void)
 {
+	if (disable_apic_timer) { 
+		printk("Disabling APIC timer\n"); 
+		return; 
+	} 
+
 	printk("Using local APIC timer interrupts.\n");
 	using_apic_timer = 1;
 
@@ -922,12 +823,16 @@
 	/*
 	 * Now set up the timer for real.
 	 */
-	setup_APIC_timer((void *)(u64)calibration_result);
+	setup_APIC_timer(calibration_result);
 
 	local_irq_enable();
+}
 
-	/* and update all other cpus */
-	smp_call_function(setup_APIC_timer, (void *)(u64)calibration_result, 1, 1);
+void __init setup_secondary_APIC_clock(void)
+{
+	local_irq_disable(); /* FIXME: Do we need this? --RR */
+	setup_APIC_timer(calibration_result);
+	local_irq_enable();
 }
 
 void __init disable_APIC_timer(void)
@@ -1044,8 +949,6 @@
  * [ if a single-CPU system runs an SMP kernel then we call the local
  *   interrupt as well. Thus we cannot inline the local irq ... ]
  */
-unsigned int apic_timer_irqs [NR_CPUS];
-
 void smp_apic_timer_interrupt(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
@@ -1053,7 +956,7 @@
 	/*
 	 * the NMI deadlock-detector uses this.
 	 */
-	apic_timer_irqs[cpu]++;
+	add_pda(apic_timer_irqs, 1);
 
 	/*
 	 * NOTE! We'd better ACK the irq immediately,
@@ -1065,12 +968,9 @@
 	 * Besides, if we don't timer interrupts ignore the global
 	 * interrupt lock, which is the WrongThing (tm) to do.
 	 */
-	irq_enter(cpu, 0);
+	irq_enter();
 	smp_local_timer_interrupt(regs);
-	irq_exit(cpu, 0);
-
-	if (softirq_pending(cpu))
-		do_softirq();
+	irq_exit();
 }
 
 /*
@@ -1082,6 +982,7 @@
 	static unsigned long last_warning; 
 	static unsigned long skipped; 
 
+	irq_enter();
 	/*
 	 * Check if this really is a spurious interrupt and ACK it
 	 * if it is a vectored one.  Just in case...
@@ -1099,6 +1000,7 @@
 	} else { 
 		skipped++; 
 	} 
+	irq_exit();
 }
 
 /*
@@ -1109,6 +1011,7 @@
 {
 	unsigned int v, v1;
 
+	irq_enter();
 	/* First tickle the hardware, only then report what went on. -- REW */
 	v = apic_read(APIC_ESR);
 	apic_write(APIC_ESR, 0);
@@ -1126,16 +1029,23 @@
 	   6: Received illegal vector
 	   7: Illegal register address
 	*/
-	printk (KERN_ERR "APIC error on CPU%d: %02x(%02x)\n",
+	printk (KERN_INFO "APIC error on CPU%d: %02x(%02x)\n",
 	        smp_processor_id(), v , v1);
+	irq_exit();
 }
 
+int disable_apic __initdata; 
+
 /*
  * This initializes the IO-APIC and APIC hardware if this is
  * a UP kernel.
  */
 int __init APIC_init_uniprocessor (void)
 {
+	if (disable_apic) { 
+		printk(KERN_INFO "Apic disabled\n");
+		return -1; 
+	}
 	if (!smp_found_config && !cpu_has_apic)
 		return -1;
 
@@ -1166,7 +1076,21 @@
 		if (!skip_ioapic_setup && nr_ioapics)
 			setup_IO_APIC();
 #endif
-	setup_APIC_clocks();
+	setup_boot_APIC_clock();
 
 	return 0;
 }
+
+static __init int setup_disableapic(char *str) 
+{ 
+	disable_apic = 1;
+} 
+
+static __init int setup_noapictimer(char *str) 
+{ 
+	disable_apic_timer = 1;
+} 
+
+__setup("disableapic", setup_disableapic); 
+__setup("noapictimer", setup_noapictimer); 
+
diff -Nru a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c
--- a/arch/x86_64/kernel/asm-offsets.c	Tue Oct 15 20:29:17 2002
+++ b/arch/x86_64/kernel/asm-offsets.c	Tue Oct 15 20:29:17 2002
@@ -24,15 +24,16 @@
 	ENTRY(state);
 	ENTRY(flags); 
 	ENTRY(thread); 
+	ENTRY(pid);
 	BLANK();
 #undef ENTRY
-#define ENTRY(entry) DEFINE(threadinfo__ ## entry, offsetof(struct thread_info, entry))
+#define ENTRY(entry) DEFINE(threadinfo_ ## entry, offsetof(struct thread_info, entry))
 	ENTRY(flags);
 	ENTRY(addr_limit);
 	ENTRY(preempt_count);
 	BLANK();
 #undef ENTRY
-#define ENTRY(entry) DEFINE(pda__ ## entry, offsetof(struct x8664_pda, entry))
+#define ENTRY(entry) DEFINE(pda_ ## entry, offsetof(struct x8664_pda, entry))
 	ENTRY(kernelstack); 
 	ENTRY(oldrsp); 
 	ENTRY(pcurrent); 
diff -Nru a/arch/x86_64/kernel/bluesmoke.c b/arch/x86_64/kernel/bluesmoke.c
--- a/arch/x86_64/kernel/bluesmoke.c	Tue Oct 15 20:29:21 2002
+++ b/arch/x86_64/kernel/bluesmoke.c	Tue Oct 15 20:29:21 2002
@@ -39,7 +39,7 @@
 		recover=0;
 
 	printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl);
-
+	preempt_disable();
 	for (i=0;i<banks;i++) {
 		rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high);
 		if(high&(1<<31)) {
@@ -64,6 +64,7 @@
 			wmb();
 		}
 	}
+	preempt_enable();
 
 	if(recover&2)
 		panic("CPU context corrupt");
@@ -110,6 +111,7 @@
 
 	BUG_ON (*cpu != smp_processor_id());
 
+	preempt_disable();
 	for (i=0; i<banks; i++) {
 		rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
 
@@ -124,6 +126,7 @@
 			wmb();
 		}
 	}
+	preempt_enable();
 }
 
 
diff -Nru a/arch/x86_64/kernel/cpuid.c b/arch/x86_64/kernel/cpuid.c
--- a/arch/x86_64/kernel/cpuid.c	Tue Oct 15 20:29:14 2002
+++ b/arch/x86_64/kernel/cpuid.c	Tue Oct 15 20:29:14 2002
@@ -146,10 +146,10 @@
  * File operations we support
  */
 static struct file_operations cpuid_fops = {
-  owner:	THIS_MODULE,
-  llseek:	cpuid_seek,
-  read:		cpuid_read,
-  open:		cpuid_open,
+  .owner =	THIS_MODULE,
+  .llseek =	cpuid_seek,
+  .read =	cpuid_read,
+  .open =	cpuid_open,
 };
 
 int __init cpuid_init(void)
diff -Nru a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/kernel/e820.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,527 @@
+/* 
+ * Handle the memory map.
+ * The functions here do the job until bootmem takes over.
+ * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
+
+ * AK: some of these functions are not used in 2.5 yet but they will be when
+ * NUMA is completely merged.
+
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+#include <asm/page.h>
+#include <asm/e820.h>
+#include <asm/proto.h>
+#include <asm/bootsetup.h>
+
+extern unsigned long table_start, table_end;
+extern char _end[];
+
+extern struct resource code_resource, data_resource, vram_resource;
+
+/* Check for some hardcoded bad areas that early boot is not allowed to touch */ 
+static inline int bad_addr(unsigned long *addrp, unsigned long size)
+{ 
+	unsigned long addr = *addrp, last = addr + size; 
+
+	/* various gunk below that needed for SMP startup */
+	if (addr < 7*PAGE_SIZE) { 
+		*addrp = 7*PAGE_SIZE; 
+		return 1; 
+	}
+
+#if 0
+	/* direct mapping tables of the kernel */
+	if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) { 
+		*addrp = table_end << PAGE_SHIFT; 
+		return 1;
+	} 
+#endif
+
+	/* initrd */ 
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (LOADER_TYPE && INITRD_START && last >= INITRD_START && 
+	    addr < INITRD_START+INITRD_SIZE) { 
+		*addrp = INITRD_START + INITRD_SIZE; 
+		return 1;
+	} 
+#endif
+	/* kernel code + 640k memory hole (later should not be needed, but 
+	   be paranoid for now) */
+	if (last >= 640*1024 && addr < __pa_symbol(&_end)) { 
+		*addrp = __pa_symbol(&_end);
+		return 1;
+	}
+	/* XXX ramdisk image here? */ 
+	return 0;
+} 
+
+int __init e820_mapped(unsigned long start, unsigned long end, int type) 
+{ 
+	int i;
+	for (i = 0; i < e820.nr_map; i++) { 
+		struct e820entry *ei = &e820.map[i]; 
+		if (type && ei->type != type) 
+			continue;
+		if (ei->addr >= end || ei->addr + ei->size < start) 
+			continue; 
+		return 1; 
+	} 
+	return 0;
+}
+
+/* 
+ * Find a free area in a specific range. 
+ */ 
+unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size) 
+{ 
+	int i; 
+	for (i = 0; i < e820.nr_map; i++) { 
+		struct e820entry *ei = &e820.map[i]; 
+		unsigned long addr = ei->addr, last; 
+		if (ei->type != E820_RAM) 
+			continue; 
+		if (addr < start) 
+			addr = start;
+		if (addr > ei->addr + ei->size) 
+			continue; 
+		while (bad_addr(&addr, size) && addr+size < ei->addr + ei->size)
+			;
+		last = addr + size;
+		if (last > ei->addr + ei->size)
+			continue;
+		if (last > end) 
+			continue;
+		return addr; 
+	} 
+	return -1UL;		
+} 
+
+/* 
+ * Free bootmem based on the e820 table for a node.
+ */
+void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end)
+{
+	int i;
+	for (i = 0; i < e820.nr_map; i++) {
+		struct e820entry *ei = &e820.map[i]; 
+		unsigned long last, addr;
+
+		if (ei->type != E820_RAM || 
+		    ei->addr+ei->size <= start || 
+		    ei->addr > end)
+			continue;
+
+		addr = round_up(ei->addr, PAGE_SIZE);
+		if (addr < start) 
+			addr = start;
+
+		last = round_down(ei->addr + ei->size, PAGE_SIZE); 
+		if (last >= end)
+			last = end; 
+
+		if (last > addr && last-addr >= PAGE_SIZE)
+			free_bootmem_node(pgdat, addr, last-addr);
+	}
+}
+
+/*
+ * Find the highest page frame number we have available
+ */
+void __init e820_end_of_ram(void)
+{
+	int i;
+	end_pfn = 0;
+	for (i = 0; i < e820.nr_map; i++) {
+		struct e820entry *ei = &e820.map[i]; 
+		unsigned long start, end;
+
+		/* count all types of areas for now to map ACPI easily */
+		start = round_up(ei->addr, PAGE_SIZE); 
+		end = round_down(ei->addr + ei->size, PAGE_SIZE); 
+		if (start >= end)
+			continue;
+		if (end > end_pfn<<PAGE_SHIFT)
+			end_pfn = end>>PAGE_SHIFT;
+	}
+
+	if (end_pfn > MAXMEM >> PAGE_SHIFT)
+		end_pfn = MAXMEM >> PAGE_SHIFT;
+}
+
+/* 
+ * Mark e820 reserved areas as busy for the resource manager.
+ */
+void __init e820_reserve_resources(void)
+{
+	int i;
+	for (i = 0; i < e820.nr_map; i++) {
+		struct resource *res;
+		if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
+			continue;
+		res = alloc_bootmem_low(sizeof(struct resource));
+		switch (e820.map[i].type) {
+		case E820_RAM:	res->name = "System RAM"; break;
+		case E820_ACPI:	res->name = "ACPI Tables"; break;
+		case E820_NVS:	res->name = "ACPI Non-volatile Storage"; break;
+		default:	res->name = "reserved";
+		}
+		res->start = e820.map[i].addr;
+		res->end = res->start + e820.map[i].size - 1;
+		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+		request_resource(&iomem_resource, res);
+		if (e820.map[i].type == E820_RAM) {
+			/*
+			 *  We dont't know which RAM region contains kernel data,
+			 *  so we try it repeatedly and let the resource manager
+			 *  test it.
+			 */
+			request_resource(res, &code_resource);
+			request_resource(res, &data_resource);
+		}
+	}
+}
+
+/* 
+ * Add a memory region to the kernel e820 map.
+ */ 
+void __init add_memory_region(unsigned long start, unsigned long size, int type)
+{
+	int x = e820.nr_map;
+
+	if (x == E820MAX) {
+		printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
+		return;
+	}
+
+	e820.map[x].addr = start;
+	e820.map[x].size = size;
+	e820.map[x].type = type;
+	e820.nr_map++;
+}
+
+void __init e820_print_map(char *who)
+{
+	int i;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		printk(" %s: %016Lx - %016Lx ", who,
+			(unsigned long long) e820.map[i].addr,
+			(unsigned long long) (e820.map[i].addr + e820.map[i].size));
+		switch (e820.map[i].type) {
+		case E820_RAM:	printk("(usable)\n");
+				break;
+		case E820_RESERVED:
+				printk("(reserved)\n");
+				break;
+		case E820_ACPI:
+				printk("(ACPI data)\n");
+				break;
+		case E820_NVS:
+				printk("(ACPI NVS)\n");
+				break;
+		default:	printk("type %u\n", e820.map[i].type);
+				break;
+		}
+	}
+}
+
+/*
+ * Sanitize the BIOS e820 map.
+ *
+ * Some e820 responses include overlapping entries.  The following 
+ * replaces the original e820 map with a new one, removing overlaps.
+ *
+ */
+static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
+{
+	struct change_member {
+		struct e820entry *pbios; /* pointer to original bios entry */
+		unsigned long long addr; /* address for this change point */
+	};
+	static struct change_member change_point_list[2*E820MAX] __initdata;
+	static struct change_member *change_point[2*E820MAX] __initdata;
+	static struct e820entry *overlap_list[E820MAX] __initdata;
+	static struct e820entry new_bios[E820MAX] __initdata;
+	struct change_member *change_tmp;
+	unsigned long current_type, last_type;
+	unsigned long long last_addr;
+	int chgidx, still_changing;
+	int overlap_entries;
+	int new_bios_entry;
+	int old_nr, new_nr;
+	int i;
+
+	/*
+		Visually we're performing the following (1,2,3,4 = memory types)...
+
+		Sample memory map (w/overlaps):
+		   ____22__________________
+		   ______________________4_
+		   ____1111________________
+		   _44_____________________
+		   11111111________________
+		   ____________________33__
+		   ___________44___________
+		   __________33333_________
+		   ______________22________
+		   ___________________2222_
+		   _________111111111______
+		   _____________________11_
+		   _________________4______
+
+		Sanitized equivalent (no overlap):
+		   1_______________________
+		   _44_____________________
+		   ___1____________________
+		   ____22__________________
+		   ______11________________
+		   _________1______________
+		   __________3_____________
+		   ___________44___________
+		   _____________33_________
+		   _______________2________
+		   ________________1_______
+		   _________________4______
+		   ___________________2____
+		   ____________________33__
+		   ______________________4_
+	*/
+
+	/* if there's only one memory region, don't bother */
+	if (*pnr_map < 2)
+		return -1;
+
+	old_nr = *pnr_map;
+
+	/* bail out if we find any unreasonable addresses in bios map */
+	for (i=0; i<old_nr; i++)
+		if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
+			return -1;
+
+	/* create pointers for initial change-point information (for sorting) */
+	for (i=0; i < 2*old_nr; i++)
+		change_point[i] = &change_point_list[i];
+
+	/* record all known change-points (starting and ending addresses) */
+	chgidx = 0;
+	for (i=0; i < old_nr; i++)	{
+		change_point[chgidx]->addr = biosmap[i].addr;
+		change_point[chgidx++]->pbios = &biosmap[i];
+		change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
+		change_point[chgidx++]->pbios = &biosmap[i];
+	}
+
+	/* sort change-point list by memory addresses (low -> high) */
+	still_changing = 1;
+	while (still_changing)	{
+		still_changing = 0;
+		for (i=1; i < 2*old_nr; i++)  {
+			/* if <current_addr> > <last_addr>, swap */
+			/* or, if current=<start_addr> & last=<end_addr>, swap */
+			if ((change_point[i]->addr < change_point[i-1]->addr) ||
+				((change_point[i]->addr == change_point[i-1]->addr) &&
+				 (change_point[i]->addr == change_point[i]->pbios->addr) &&
+				 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
+			   )
+			{
+				change_tmp = change_point[i];
+				change_point[i] = change_point[i-1];
+				change_point[i-1] = change_tmp;
+				still_changing=1;
+			}
+		}
+	}
+
+	/* create a new bios memory map, removing overlaps */
+	overlap_entries=0;	 /* number of entries in the overlap table */
+	new_bios_entry=0;	 /* index for creating new bios map entries */
+	last_type = 0;		 /* start with undefined memory type */
+	last_addr = 0;		 /* start with 0 as last starting address */
+	/* loop through change-points, determining affect on the new bios map */
+	for (chgidx=0; chgidx < 2*old_nr; chgidx++)
+	{
+		/* keep track of all overlapping bios entries */
+		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
+		{
+			/* add map entry to overlap list (> 1 entry implies an overlap) */
+			overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
+		}
+		else
+		{
+			/* remove entry from list (order independent, so swap with last) */
+			for (i=0; i<overlap_entries; i++)
+			{
+				if (overlap_list[i] == change_point[chgidx]->pbios)
+					overlap_list[i] = overlap_list[overlap_entries-1];
+			}
+			overlap_entries--;
+		}
+		/* if there are overlapping entries, decide which "type" to use */
+		/* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
+		current_type = 0;
+		for (i=0; i<overlap_entries; i++)
+			if (overlap_list[i]->type > current_type)
+				current_type = overlap_list[i]->type;
+		/* continue building up new bios map based on this information */
+		if (current_type != last_type)	{
+			if (last_type != 0)	 {
+				new_bios[new_bios_entry].size =
+					change_point[chgidx]->addr - last_addr;
+				/* move forward only if the new size was non-zero */
+				if (new_bios[new_bios_entry].size != 0)
+					if (++new_bios_entry >= E820MAX)
+						break; 	/* no more space left for new bios entries */
+			}
+			if (current_type != 0)	{
+				new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
+				new_bios[new_bios_entry].type = current_type;
+				last_addr=change_point[chgidx]->addr;
+			}
+			last_type = current_type;
+		}
+	}
+	new_nr = new_bios_entry;   /* retain count for new bios entries */
+
+	/* copy new bios mapping into original location */
+	memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
+	*pnr_map = new_nr;
+
+	return 0;
+}
+
+/*
+ * Copy the BIOS e820 map into a safe place.
+ *
+ * Sanity-check it while we're at it..
+ *
+ * If we're lucky and live on a modern system, the setup code
+ * will have given us a memory map that we can use to properly
+ * set up memory.  If we aren't, we'll fake a memory map.
+ *
+ * We check to see that the memory map contains at least 2 elements
+ * before we'll use it, because the detection code in setup.S may
+ * not be perfect and most every PC known to man has two memory
+ * regions: one from 0 to 640k, and one from 1mb up.  (The IBM
+ * thinkpad 560x, for example, does not cooperate with the memory
+ * detection code.)
+ */
+static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+{
+	/* Only one memory region (or negative)? Ignore it */
+	if (nr_map < 2)
+		return -1;
+
+	do {
+		unsigned long start = biosmap->addr;
+		unsigned long size = biosmap->size;
+		unsigned long end = start + size;
+		unsigned long type = biosmap->type;
+
+		/* Overflow in 64 bits? Ignore the memory map. */
+		if (start > end)
+			return -1;
+
+		/*
+		 * Some BIOSes claim RAM in the 640k - 1M region.
+		 * Not right. Fix it up.
+		 * 
+		 * This should be removed on Hammer which is supposed to not
+		 * have non e820 covered ISA mappings there, but I had some strange
+		 * problems so it stays for now.  -AK
+		 */
+		if (type == E820_RAM) {
+			if (start < 0x100000ULL && end > 0xA0000ULL) {
+				if (start < 0xA0000ULL)
+					add_memory_region(start, 0xA0000ULL-start, type);
+				if (end <= 0x100000ULL)
+					continue;
+				start = 0x100000ULL;
+				size = end - start;
+			}
+		}
+
+		add_memory_region(start, size, type);
+	} while (biosmap++,--nr_map);
+	return 0;
+}
+
+void __init setup_memory_region(void)
+{
+	char *who = "BIOS-e820";
+
+	/*
+	 * Try to copy the BIOS-supplied E820-map.
+	 *
+	 * Otherwise fake a memory map; one section from 0k->640k,
+	 * the next section from 1mb->appropriate_mem_k
+	 */
+	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+		unsigned long mem_size;
+
+		/* compare results from other methods and take the greater */
+		if (ALT_MEM_K < EXT_MEM_K) {
+			mem_size = EXT_MEM_K;
+			who = "BIOS-88";
+		} else {
+			mem_size = ALT_MEM_K;
+			who = "BIOS-e801";
+		}
+
+		e820.nr_map = 0;
+		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+  	}
+	printk(KERN_INFO "BIOS-provided physical RAM map:\n");
+	e820_print_map(who);
+}
+
+static int usermem __initdata; 
+
+void __init parse_memopt(char *p) 
+{ 
+	if (!strncmp(p,"exactmap",8)) { 
+		e820.nr_map = 0;
+		usermem = 1; 
+	} else { 
+	       	/* If the user specifies memory size, we
+		 * blow away any automatically generated
+		 * size
+		 */
+		unsigned long long start_at, mem_size;
+		
+		if (usermem == 0) {
+			/* first time in: zap the whitelist
+			 * and reinitialize it with the
+			 * standard low-memory region.
+			 */
+			e820.nr_map = 0;
+			usermem = 1;
+			add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+		}
+		mem_size = memparse(p, &p);
+		if (*p == '@')
+			start_at = memparse(p+1, &p);
+		else {
+			start_at = HIGH_MEMORY;
+			mem_size -= HIGH_MEMORY;
+			usermem=0;
+		}
+		add_memory_region(start_at, mem_size, E820_RAM);
+	}
+		
+} 
+
+void __init print_user_map(void)
+{ 
+	if (usermem) {
+		printk(KERN_INFO "user-defined physical RAM map:\n");
+		e820_print_map("user");
+	}
+}
diff -Nru a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
--- a/arch/x86_64/kernel/early_printk.c	Tue Oct 15 20:29:19 2002
+++ b/arch/x86_64/kernel/early_printk.c	Tue Oct 15 20:29:19 2002
@@ -47,10 +47,10 @@
 }
 
 static struct console early_vga_console = {
-	name:		"earlyvga",
-	write:		early_vga_write,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name =		"earlyvga",
+	.write =	early_vga_write,
+	.flags =	CON_PRINTBUFFER,
+	.index =	-1,
 };
 
 /* Serial functions losely based on a similar package from Klaus P. Gerlicher */ 
@@ -138,10 +138,10 @@
 }
 
 static struct console early_serial_console = {
-	name:		"earlyser",
-	write:		early_serial_write,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name =		"earlyser",
+	.write =	early_serial_write,
+	.flags =	CON_PRINTBUFFER,
+	.index =	-1,
 };
 
 /* Direct interface for emergencies */
@@ -181,6 +181,9 @@
 	if (!strncmp(buf, "serial", 6)) { 
 		early_serial_init(buf + 6);
 		early_console = &early_serial_console;
+	} else if (!strncmp(buf, "ttyS", 4)) { 
+		early_serial_init(buf);
+		early_console = &early_serial_console;		
 	} else if (!strncmp(buf, "vga", 3)) {
 		early_console = &early_vga_console; 
 	} else {
diff -Nru a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
--- a/arch/x86_64/kernel/entry.S	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/kernel/entry.S	Tue Oct 15 20:29:16 2002
@@ -84,7 +84,7 @@
 	xorq %rax, %rax
 	pushq %rax /* ss */
 	pushq %rax /* rsp */
-	pushq %rax /* eflags */
+	pushq $(1<<9) /* eflags - interrupts on */
 	pushq $__KERNEL_CS /* cs */
 	pushq \child_rip /* rip */
 	pushq	%rax /* orig rax */
@@ -236,21 +236,17 @@
  * Has correct top of stack, but partial stack frame.
  */ 	
 ENTRY(int_ret_from_sys_call)	
-	testl $3,CS-ARGOFFSET(%rsp)	# kernel syscall?
-	je int_restore_args
+	cli
+	testl $3,CS-ARGOFFSET(%rsp)
+	je retint_restore_args
 	movl $_TIF_ALLWORK_MASK,%edi
 	/* edi:	mask to check */
 int_with_check:
 	GET_THREAD_INFO(%rcx)
-	cli
 	movl threadinfo_flags(%rcx),%edx
 	andl %edi,%edx
 	jnz   int_careful
-int_restore_swapgs:	
-	swapgs
-int_restore_args:		
-	RESTORE_ARGS 0,8,0
-	iretq
+	jmp   retint_swapgs
 
 	/* Either reschedule or signal or syscall exit tracking needed. */
 	/* First do a reschedule test. */
@@ -364,15 +360,11 @@
 	.macro interrupt func
 	cld
 	SAVE_ARGS
-#ifdef CONFIG_PREEMPT
-	GET_THREAD_INFO(%rdx)
-	incl threadinfo_preempt_count(%rdx)
-#endif		
 	leaq -ARGOFFSET(%rsp),%rdi	# arg1 for handler
 	testl $3,CS(%rdi)
 	je 1f
 	swapgs	
-1:	addl $1,PDAREF(pda_irqcount)	# XXX: should be merged with irq.c irqcount
+1:	addl $1,PDAREF(pda_irqcount)	# RED-PEN should check preempt count
 	movq PDAREF(pda_irqstackptr),%rax
 	cmoveq %rax,%rsp							
 	pushq %rdi			# save old stack	
@@ -389,9 +381,6 @@
 	leaq ARGOFFSET(%rdi),%rsp
 exit_intr:	 	
 	GET_THREAD_INFO(%rcx)
-#ifdef CONFIG_PREEMPT	
-	decl threadinfo_preempt_count(%rcx)
-#endif
 	testl $3,CS-ARGOFFSET(%rsp)
 	je retint_kernel
 	
@@ -407,11 +396,24 @@
 	andl %edi,%edx
 	jnz  retint_careful
 retint_swapgs:	 	
+	cli
 	swapgs 
 retint_restore_args:				
+	cli
 	RESTORE_ARGS 0,8,0						
+iret_label:	
 	iretq
 
+	.section __ex_table,"a"
+	.quad iret_label,bad_iret	
+	.previous
+	.section .fixup,"ax"
+	/* force a signal here? this matches i386 behaviour */
+bad_iret:
+	movq $-9999,%rdi	/* better code? */
+	jmp do_exit			
+	.previous	
+	
 	/* edi: workmask, edx: work */	
 retint_careful:
 	bt    $TIF_NEED_RESCHED,%edx
@@ -448,9 +450,8 @@
 	jnz  retint_restore_args
 	bt  $TIF_NEED_RESCHED,threadinfo_flags(%rcx)
 	jnc  retint_restore_args
-	movl PDAREF(pda___local_bh_count),%eax
-	addl PDAREF(pda___local_irq_count),%eax
-	jnz  retint_restore_args
+	bt   $9,EFLAGS-ARGOFFSET(%rsp)	/* interrupts off? */
+	jc   retint_restore_args
 	movl $PREEMPT_ACTIVE,threadinfo_preempt_count(%rcx)
 	sti
 	call schedule
@@ -513,11 +514,6 @@
  */ 		  				
  	ALIGN
 error_entry:
-	testl $3,24(%rsp)	
-	je  error_kernelspace	
-	swapgs
-error_kernelspace:			
-	sti
 	/* rdi slot contains rax, oldrax contains error code */
 	pushq %rsi
 	movq  8(%rsp),%rsi	/* load rax */
@@ -530,17 +526,25 @@
 	pushq %r11
 	cld	
 	SAVE_REST
+	testl $3,CS(%rsp)
+	je  error_kernelspace
+error_swapgs:	
+	xorl %ebx,%ebx	
+	swapgs
+error_sti:	
+	sti
 	movq %rdi,RDI(%rsp) 	
 	movq %rsp,%rdi
 	movq ORIG_RAX(%rsp),%rsi	/* get error code */ 
 	movq $-1,ORIG_RAX(%rsp)
 	call *%rax
 error_exit:		
+	movl %ebx,%eax		
 	RESTORE_REST
 	cli
 	GET_THREAD_INFO(%rcx)	
-	testl $3,CS-ARGOFFSET(%rsp)
-	je retint_kernel
+	testl %eax,%eax
+	jne  retint_kernel
 	movl  threadinfo_flags(%rcx),%edx
 	movl  $_TIF_WORK_MASK,%edi
 	andl  %edi,%edx
@@ -549,6 +553,39 @@
 	RESTORE_ARGS 0,8,0						
 	iretq
 
+error_kernelspace:
+       /* There are two places in the kernel that can potentially fault with
+          usergs. Handle them here. */    
+	cmpq $iret_label,RIP(%rsp) 
+	je   error_swapgs
+	cmpq $gs_change,RIP(%rsp)
+        je   error_swapgs
+	movl $1,%ebx	
+	jmp  error_sti
+	
+       /* Reload gs selector with exception handling */
+       /* edi:  new selector */ 
+ENTRY(load_gs_index)
+	pushf
+	cli
+        swapgs
+gs_change:     
+        movl %edi,%gs   
+2:      swapgs
+        popf
+        ret
+       
+        .section __ex_table,"a"
+        .align 8
+        .quad gs_change,bad_gs
+        .previous
+        .section .fixup,"ax"
+bad_gs: 
+	xorl %eax,%eax
+        movl %eax,%gs
+        jmp  2b
+        .previous       
+	
 /*
  * Create a kernel thread.
  *
@@ -564,7 +601,7 @@
 
 	# rdi: flags, rsi: usp, rdx: will be &pt_regs
 	movq %rdx,%rdi
-	orq  kernel_thread_flags(%rip), %rdi
+	orq  kernel_thread_flags(%rip),%rdi
 	movq $-1, %rsi
 	movq %rsp, %rdx
 
@@ -573,8 +610,9 @@
 
 	xorl %edi,%edi
 	cmpq $-1000,%rax
-	cmovb %rdi,%rax
-	movq %rax,RAX(%rsp)
+	jnb  1f
+	movl tsk_pid(%rax),%eax	
+1:	movq %rax,RAX(%rsp)
 
 	/*
 	 * It isn't worth to check for reschedule here,
@@ -648,18 +686,19 @@
 	zeroentry do_simd_coprocessor_error	
 
 ENTRY(device_not_available)
-	testl $3,8(%rsp)
+	pushq $-1	#error code
+	SAVE_ALL
+	movl  $1,%ebx
+	testl $3,CS(%rsp)
 	je 1f
+	xorl %ebx,%ebx
 	swapgs
-1:	pushq $-1	#error code
-	SAVE_ALL
-	movq  %cr0,%rax
+1:	movq  %cr0,%rax
 	leaq  math_state_restore(%rip),%rcx
-	leaq  math_emulate(%rip),%rbx
+	leaq  math_emulate(%rip),%rdx
 	testl $0x4,%eax
-	cmoveq %rcx,%rbx
-	preempt_stop
-	call  *%rbx
+	cmoveq %rcx,%rdx
+	call  *%rdx
 	jmp  error_exit
 
 ENTRY(debug)
diff -Nru a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
--- a/arch/x86_64/kernel/head.S	Tue Oct 15 20:29:17 2002
+++ b/arch/x86_64/kernel/head.S	Tue Oct 15 20:29:17 2002
@@ -159,7 +159,7 @@
 	 * addresses where we're currently running on. We have to do that here
 	 * because in 32bit we couldn't load a 64bit linear address.
 	 */
-	lgdt	pGDT64
+	lgdt	cpu_gdt_descr
 
 	/* 
 	 * Setup up a dummy PDA. this is just for some early bootup code
@@ -276,7 +276,7 @@
 .org 0x5000
 ENTRY(level2_kernel_pgt)
 	/* 40MB kernel mapping. The kernel code cannot be bigger than that.
-	   When you change this change KERNEL_TEXT_SIZE in pgtable.h too. */
+	   When you change this change KERNEL_TEXT_SIZE in page.h too. */
 	/* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
 	.quad	0x0000000000000183
 	.quad	0x0000000000200183
@@ -320,16 +320,18 @@
 .org 0xb000
 .data
 
-.globl gdt
-
-	.word 0
 	.align 16
-	.word 0
-pGDT64:
-	.word	gdt_end-gdt_table
+	.globl cpu_gdt_descr
+cpu_gdt_descr:
+	.word	gdt_end-cpu_gdt_table
 gdt:
-	.quad	gdt_table
-	
+	.quad	cpu_gdt_table
+#ifdef CONFIG_SMP
+	.rept	NR_CPUS-1
+	.word	0
+	.quad	0
+	.endr
+#endif
 
 .align 64 /* cacheline aligned */
 ENTRY(gdt_table32)
@@ -344,8 +346,12 @@
  */
 		 		
 .align 64 /* cacheline aligned, keep this synchronized with asm/desc.h */
-ENTRY(gdt_table)
-	.quad	0x0000000000000000	/* This one is magic */
+
+/* The TLS descriptors are currently at a different place compared to i386.
+   Hopefully nobody expects them at a fixed place (Wine?) */
+	
+ENTRY(cpu_gdt_table)
+	.quad	0x0000000000000000	/* NULL descriptor */
 	.quad	0x0000000000000000	/* unused */
 	.quad	0x00af9a000000ffff	/* __KERNEL_CS */
 	.quad	0x00cf92000000ffff	/* __KERNEL_DS */
@@ -358,14 +364,19 @@
 	.word	0x00CF				# granularity = 4096, 386
 						#  (+5th nibble of limit)
 					/* __KERNEL32_CS */
-
-	.globl  tss_start
-tss_start:
-	.rept NR_CPUS	 	
-	.quad   0,0,0,0,0,0,0,0		/* TSS/LDT/per cpu entries. filled in later */
-	.endr	
+	.quad	0,0			/* TSS */
+	.quad	0			/* LDT */
+	.quad   0,0,0			/* three TLS descriptors */ 
+	.quad	0,0			/* pad to cache line boundary */
 gdt_end:	
 	.globl gdt_end
+
+	/* GDTs of other CPUs */	
+#ifdef CONFIG_SMP
+	.rept NR_CPUS-1
+	.quad 0,0,0,0,0,0,0,0,0,0,0
+	.endr	
+#endif
 
 	.align  64
 ENTRY(idt_table)	
diff -Nru a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
--- a/arch/x86_64/kernel/head64.c	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/kernel/head64.c	Tue Oct 15 20:29:16 2002
@@ -71,6 +71,7 @@
 }
 
 extern void start_kernel(void), pda_init(int), setup_early_printk(char *); 
+extern int disable_apic;
 
 void __init x86_64_start_kernel(char * real_mode_data)
 {
@@ -82,6 +83,10 @@
 	s = strstr(saved_command_line, "earlyprintk="); 
 	if (s != NULL)
 		setup_early_printk(s+12); 
+#ifdef CONFIG_X86_IO_APIC
+	if (strstr(saved_command_line, "disableapic"))
+		disable_apic = 1;
+#endif
 	setup_boot_cpu_data();
 	start_kernel();
 }
diff -Nru a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
--- a/arch/x86_64/kernel/i8259.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/kernel/i8259.c	Tue Oct 15 20:29:12 2002
@@ -1,6 +1,5 @@
 #include <linux/linkage.h>
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -120,7 +119,8 @@
 		BUG(); 
 	}
 
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
+	    irq_desc[irq].action)
 		enable_8259A_irq(irq);
 }
 
@@ -319,18 +319,6 @@
 		goto handle_real_irq;
 	}
 }
-
-static struct device device_i8259A = {
-       name:           "i8259A",
-       bus_id:         "0020",
-};
-
-static int __init init_8259A_devicefs(void)
-{
-       return register_sys_device(&device_i8259A);
-}
-
-__initcall(init_8259A_devicefs);
 
 void __init init_8259A(int auto_eoi)
 {
diff -Nru a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c
--- a/arch/x86_64/kernel/init_task.c	Tue Oct 15 20:29:17 2002
+++ b/arch/x86_64/kernel/init_task.c	Tue Oct 15 20:29:17 2002
@@ -10,7 +10,7 @@
 
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
diff -Nru a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
--- a/arch/x86_64/kernel/io_apic.c	Tue Oct 15 20:29:17 2002
+++ b/arch/x86_64/kernel/io_apic.c	Tue Oct 15 20:29:17 2002
@@ -17,6 +17,7 @@
  *					thanks to Eric Gilmore
  *					and Rolf G. Tews
  *					for testing these extensively
+ *	Paul Diefenbaugh	:	Added full ACPI support
  */
 
 #include <linux/mm.h>
@@ -28,6 +29,7 @@
 #include <linux/config.h>
 #include <linux/smp_lock.h>
 #include <linux/mc146818rtc.h>
+#include <linux/acpi.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -746,7 +748,8 @@
 		(reg_01.entries != 0x1f) && /* dual Xeon boards */
 		(reg_01.entries != 0x22) && /* bigger Xeon boards */
 		(reg_01.entries != 0x2E) &&
-		(reg_01.entries != 0x3F)
+		(reg_01.entries != 0x3F) &&
+		(reg_01.entries != 0x03) 
 	)
 		UNEXPECTED_IO_APIC();
 
@@ -1014,6 +1017,8 @@
 	unsigned char old_id;
 	unsigned long flags;
 
+	if (acpi_ioapic) return; /* ACPI does that already */
+
 	/*
 	 * Set the IOAPIC ID to the value stored in the MPC table.
 	 */
@@ -1104,7 +1109,7 @@
 {
 	unsigned int t1 = jiffies;
 
-	sti();
+	local_irq_enable();
 	/* Let ten ticks pass... */
 	mdelay((10 * 1000) / HZ);
 
@@ -1117,7 +1122,6 @@
 	 */
 	if (jiffies - t1 > 4)
 		return 1;
-
 	return 0;
 }
 
@@ -1376,7 +1380,7 @@
 	end_lapic_irq
 };
 
-static void enable_NMI_through_LVT0 (void * dummy)
+void enable_NMI_through_LVT0 (void * dummy)
 {
 	unsigned int v, ver;
 
@@ -1401,7 +1405,6 @@
 	 */ 
 	printk(KERN_INFO "activating NMI Watchdog ...");
 
-	smp_call_function(enable_NMI_through_LVT0, NULL, 1, 1);
 	enable_NMI_through_LVT0(NULL);
 
 	printk(" done.\n");
@@ -1477,7 +1480,6 @@
  */
 static inline void check_timer(void)
 {
-	extern int timer_ack;
 	int pin1, pin2;
 	int vector;
 
@@ -1497,7 +1499,6 @@
 	 */
 	apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
 	init_8259A(1);
-	timer_ack = 1;
 	enable_8259A_irq(0);
 
 	pin1 = find_isa_irq_pin(0, mp_INT);
@@ -1605,8 +1606,7 @@
 	printk("ENABLING IO-APIC IRQs\n");
 
 	/*
-	 * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS
-	 * mptable:
+	 * Set up the IO-APIC IRQ routing table.
 	 */
 	setup_ioapic_ids_from_mpc();
 	sync_Arb_IDs();
@@ -1615,3 +1615,175 @@
 	check_timer();
 	print_IO_APIC();
 }
+
+/* Ensure the ACPI SCI interrupt level is active low, edge-triggered */
+
+void __init mp_config_ioapic_for_sci(int irq)
+{
+#if 0 /* fixme */
+       int ioapic;
+       int ioapic_pin;
+
+       ioapic = mp_find_ioapic(irq);
+
+       ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
+
+       io_apic_set_pci_routing(ioapic, ioapic_pin, irq);
+#endif
+}
+
+
+/* --------------------------------------------------------------------------
+                          ACPI-based IOAPIC Configuration
+   -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ACPI_BOOT
+
+#define IO_APIC_MAX_ID		15
+
+int __init io_apic_get_unique_id (int ioapic, int apic_id)
+{
+	struct IO_APIC_reg_00 reg_00;
+	static unsigned long apic_id_map = 0;
+	unsigned long flags;
+	int i = 0;
+
+	/*
+	 * The P4 platform supports up to 256 APIC IDs on two separate APIC 
+	 * buses (one for LAPICs, one for IOAPICs), where predecessors only 
+	 * supports up to 16 on one shared APIC bus.
+	 * 
+	 * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
+	 *      advantage of new APIC bus architecture.
+	 */
+
+	if (!apic_id_map)
+		apic_id_map = phys_cpu_present_map;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	*(int *)&reg_00 = io_apic_read(ioapic, 0);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	if (apic_id >= IO_APIC_MAX_ID) {
+		printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
+			"%d\n", ioapic, apic_id, reg_00.ID);
+		apic_id = reg_00.ID;
+	}
+
+	/*
+	 * Every APIC in a system must have a unique ID or we get lots of nice 
+	 * 'stuck on smp_invalidate_needed IPI wait' messages.
+	 */
+	if (apic_id_map & (1 << apic_id)) {
+
+		for (i = 0; i < IO_APIC_MAX_ID; i++) {
+			if (!(apic_id_map & (1 << i)))
+				break;
+		}
+
+		if (i == IO_APIC_MAX_ID)
+			panic("Max apic_id exceeded!\n");
+
+		printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
+			"trying %d\n", ioapic, apic_id, i);
+
+		apic_id = i;
+	} 
+
+	apic_id_map |= (1 << apic_id);
+
+	if (reg_00.ID != apic_id) {
+		reg_00.ID = apic_id;
+
+		spin_lock_irqsave(&ioapic_lock, flags);
+		io_apic_write(ioapic, 0, *(int *)&reg_00);
+		*(int *)&reg_00 = io_apic_read(ioapic, 0);
+		spin_unlock_irqrestore(&ioapic_lock, flags);
+
+		/* Sanity check */
+		if (reg_00.ID != apic_id)
+			panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic);
+	}
+
+	printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
+
+	return apic_id;
+}
+
+
+int __init io_apic_get_version (int ioapic)
+{
+	struct IO_APIC_reg_01	reg_01;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	*(int *)&reg_01 = io_apic_read(ioapic, 1);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	return reg_01.version;
+}
+
+
+int __init io_apic_get_redir_entries (int ioapic)
+{
+	struct IO_APIC_reg_01	reg_01;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	*(int *)&reg_01 = io_apic_read(ioapic, 1);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	return reg_01.entries;
+}
+
+
+int io_apic_set_pci_routing (int ioapic, int pin, int irq)
+{
+	struct IO_APIC_route_entry entry;
+	unsigned long flags;
+
+	if (!IO_APIC_IRQ(irq)) {
+		printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0/n", 
+			ioapic);
+		return -EINVAL;
+	}
+
+	/*
+	 * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
+	 * Note that we mask (disable) IRQs now -- these get enabled when the
+	 * corresponding device driver registers for this IRQ.
+	 */
+
+	memset(&entry,0,sizeof(entry));
+
+	entry.delivery_mode = dest_LowestPrio;
+	entry.dest_mode = INT_DELIVERY_MODE;
+	entry.dest.logical.logical_dest = TARGET_CPUS;
+	entry.mask = 1;					 /* Disabled (masked) */
+	entry.trigger = 1;				   /* Level sensitive */
+	entry.polarity = 1;					/* Low active */
+
+	add_pin_to_irq(irq, ioapic, pin);
+
+	entry.vector = assign_irq_vector(irq);
+
+	printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
+		"IRQ %d)\n", ioapic, 
+		mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq);
+
+	irq_desc[irq].handler = &ioapic_level_irq_type;
+
+	set_intr_gate(entry.vector, interrupt[irq]);
+
+	if (!ioapic && (irq < 16))
+		disable_8259A_irq(irq);
+
+	spin_lock_irqsave(&ioapic_lock, flags);
+	io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
+	io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+
+	return entry.vector;
+}
+
+#endif /*CONFIG_ACPI_BOOT*/
diff -Nru a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c
--- a/arch/x86_64/kernel/ioport.c	Tue Oct 15 20:29:14 2002
+++ b/arch/x86_64/kernel/ioport.c	Tue Oct 15 20:29:14 2002
@@ -56,17 +56,21 @@
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
 	struct thread_struct * t = &current->thread;
-	struct tss_struct * tss = init_tss + smp_processor_id();
+	struct tss_struct * tss;
+	int ret = 0;
 
 	if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
 		return -EINVAL;
 	if (turn_on && !capable(CAP_SYS_RAWIO))
 		return -EPERM;
 
+	tss  = init_tss + get_cpu();
 	if (!t->io_bitmap_ptr) { 
 		t->io_bitmap_ptr = kmalloc((IO_BITMAP_SIZE+1)*4, GFP_KERNEL);
-		if (!t->io_bitmap_ptr) 
-			return -ENOMEM; 
+		if (!t->io_bitmap_ptr) { 
+			ret = -ENOMEM;
+			goto out;
+		}
 		memset(t->io_bitmap_ptr,0xff,(IO_BITMAP_SIZE+1)*4);
 		tss->io_map_base = IO_BITMAP_OFFSET;
 	}
@@ -77,7 +81,9 @@
 	set_bitmap((unsigned long *) t->io_bitmap_ptr, from, num, !turn_on);
 	set_bitmap((unsigned long *) tss->io_bitmap, from, num, !turn_on);
 
-	return 0;
+ out:
+	put_cpu();
+	return ret;
 }
 
 /*
diff -Nru a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
--- a/arch/x86_64/kernel/irq.c	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/kernel/irq.c	Tue Oct 15 20:29:16 2002
@@ -18,7 +18,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -138,7 +137,7 @@
 	struct irqaction * action;
 
 	seq_printf(p, "           ");
-	for (j=0; j<smp_num_cpus; j++)
+	for_each_cpu(j) 
 		seq_printf(p, "CPU%d       ",j);
 	seq_putc(p, '\n');
 
@@ -150,9 +149,9 @@
 #ifndef CONFIG_SMP
 		seq_printf(p, "%10u ", kstat_irqs(i));
 #else
-		for (j = 0; j < smp_num_cpus; j++)
+		for_each_cpu(j) 
 			seq_printf(p, "%10u ",
-				kstat.irqs[cpu_logical_map(j)][i]);
+				kstat.irqs[j][i]);
 #endif
 		seq_printf(p, " %14s", irq_desc[i].handler->typename);
 		seq_printf(p, "  %s", action->name);
@@ -162,13 +161,13 @@
 		seq_putc(p, '\n');
 	}
 	seq_printf(p, "NMI: ");
-	for (j = 0; j < smp_num_cpus; j++)
-		seq_printf(p, "%10u ", cpu_pda[cpu_logical_map(j)].__nmi_count);
+	for_each_cpu(j)
+		seq_printf(p, "%10u ", cpu_pda[j].__nmi_count);
 	seq_putc(p, '\n');
 #if CONFIG_X86_LOCAL_APIC
 	seq_printf(p, "LOC: ");
-	for (j = 0; j < smp_num_cpus; j++)
-		seq_printf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]);
+	for_each_cpu(j)
+		seq_printf(p, "%10u ", cpu_pda[j].apic_timer_irqs);
 	seq_putc(p, '\n');
 #endif
 	seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
@@ -180,250 +179,12 @@
 	return 0;
 }
 
-/*
- * Global interrupt locks for SMP. Allow interrupts to come in on any
- * CPU, yet make cli/sti act globally to protect critical regions..
- */
-
 #ifdef CONFIG_SMP
-unsigned char global_irq_holder = NO_PROC_ID;
-unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */
-
-extern void show_stack(unsigned long* esp);
-
-
-/* XXX: this unfortunately doesn't support irqstacks currently, should check the other PDAs */
-static void show(char * str)
-{
-	int i;
-	int cpu = smp_processor_id();
-
-	printk("\n%s, CPU %d:\n", str, cpu);
-	printk("irq:  %d [",irqs_running());
-	for(i=0;i < smp_num_cpus;i++)
-		printk(" %d",local_irq_count(i));
-	printk(" ]\nbh:   %d [",spin_is_locked(&global_bh_lock) ? 1 : 0);
-	for(i=0;i < smp_num_cpus;i++)
-		printk(" %d",local_bh_count(i));
-
-	printk(" ]\nStack dumps:");
-	for(i = 0; i < smp_num_cpus; i++) {
-		unsigned long esp;
-		if (i == cpu)
-			continue;
-		printk("\nCPU %d:",i);
-		esp = init_tss[i].rsp0;
-		if (!esp) {
-			/* tss->esp0 is set to NULL in cpu_init(),
-			 * it's initialized when the cpu returns to user
-			 * space. -- manfreds
-			 */
-			printk(" <unknown> ");
-			continue;
-		}
-		esp &= ~(THREAD_SIZE-1);
-		esp += sizeof(struct thread_info);
-		show_stack((void*)esp);
- 	}
-	printk("\nCPU %d:",cpu);
-	show_stack(NULL);
-	printk("\n");
-}
-	
-#define MAXCOUNT 100000000
-
-/*
- * I had a lockup scenario where a tight loop doing
- * spin_unlock()/spin_lock() on CPU#1 was racing with
- * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but
- * apparently the spin_unlock() information did not make it
- * through to CPU#0 ... nasty, is this by design, do we have to limit
- * 'memory update oscillation frequency' artificially like here?
- *
- * Such 'high frequency update' races can be avoided by careful design, but
- * some of our major constructs like spinlocks use similar techniques,
- * it would be nice to clarify this issue. Set this define to 0 if you
- * want to check whether your system freezes.  I suspect the delay done
- * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but
- * i thought that such things are guaranteed by design, since we use
- * the 'LOCK' prefix.
- */
-#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0
-
-#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND
-# define SYNC_OTHER_CORES(x) udelay(x+1)
-#else
-/*
- * We have to allow irqs to arrive between local_irq_enable and local_irq_disable
- */
-# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop")
-#endif
-
-static inline void wait_on_irq(int cpu)
-{
-	int count = MAXCOUNT;
-
-	for (;;) {
-
-		/*
-		 * Wait until all interrupts are gone. Wait
-		 * for bottom half handlers unless we're
-		 * already executing in one..
-		 */
-		if (!irqs_running())
-			if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock))
-				break;
-
-		/* Duh, we have to loop. Release the lock to avoid deadlocks */
-		clear_bit(0,&global_irq_lock);
-
-		for (;;) {
-			if (!--count) {
-				show("wait_on_irq");
-				count = ~0;
-			}
-			local_irq_enable();
-			SYNC_OTHER_CORES(cpu);
-			local_irq_disable();
-			if (irqs_running())
-				continue;
-			if (global_irq_lock)
-				continue;
-			if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock))
-				continue;
-			if (!test_and_set_bit(0,&global_irq_lock))
-				break;
-		}
-	}
-}
-
-/*
- * This is called when we want to synchronize with
- * interrupts. We may for example tell a device to
- * stop sending interrupts: but to make sure there
- * are no interrupts that are executing on another
- * CPU we need to call this function.
- */
-void synchronize_irq(void)
-{
-	if (irqs_running()) {
-		/* Stupid approach */
-		cli();
-		sti();
-	}
-}
-
-static inline void get_irqlock(int cpu)
-{
-	if (test_and_set_bit(0,&global_irq_lock)) {
-		/* do we already hold the lock? */
-		if ((unsigned char) cpu == global_irq_holder)
-			return;
-		/* Uhhuh.. Somebody else got it. Wait.. */
-		do {
-			do {
-				rep_nop();
-			} while (test_bit(0,&global_irq_lock));
-		} while (test_and_set_bit(0,&global_irq_lock));		
-	}
-	/* 
-	 * We also to make sure that nobody else is running
-	 * in an interrupt context. 
-	 */
-	wait_on_irq(cpu);
-
-	/*
-	 * Ok, finally..
-	 */
-	global_irq_holder = cpu;
-}
-
-#define EFLAGS_IF_SHIFT 9
-
-/*
- * A global "cli()" while in an interrupt context
- * turns into just a local cli(). Interrupts
- * should use spinlocks for the (very unlikely)
- * case that they ever want to protect against
- * each other.
- *
- * If we already have local interrupts disabled,
- * this will not turn a local disable into a
- * global one (problems with spinlocks: this makes
- * save_flags+cli+sti usable inside a spinlock).
- */
-void __global_cli(void)
-{
-	unsigned long flags;
-
-	local_save_flags(flags);
-	if (flags & (1 << EFLAGS_IF_SHIFT)) {
-		int cpu = smp_processor_id();
-		local_irq_disable();
-		if (!local_irq_count(cpu))
-			get_irqlock(cpu);
-	}
-}
-
-void __global_sti(void)
+inline void synchronize_irq(unsigned int irq)
 {
-	int cpu = smp_processor_id();
-
-	if (!local_irq_count(cpu))
-		release_irqlock(cpu);
-	local_irq_enable();
+	while (irq_desc[irq].status & IRQ_INPROGRESS)
+		cpu_relax();
 }
-
-/*
- * SMP flags value to restore to:
- * 0 - global cli
- * 1 - global sti
- * 2 - local cli
- * 3 - local sti
- */
-unsigned long __global_save_flags(void)
-{
-	int retval;
-	int local_enabled;
-	unsigned long flags;
-	int cpu = smp_processor_id();
-
-	local_save_flags(flags);
-	local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1;
-	/* default to local */
-	retval = 2 + local_enabled;
-
-	/* check for global flags if we're not in an interrupt */
-	if (!local_irq_count(cpu)) {
-		if (local_enabled)
-			retval = 1;
-		if (global_irq_holder == cpu)
-			retval = 0;
-	}
-	return retval;
-}
-
-void __global_restore_flags(unsigned long flags)
-{
-	switch (flags) {
-	case 0:
-		__global_cli();
-		break;
-	case 1:
-		__global_sti();
-		break;
-	case 2:
-		local_irq_disable();
-		break;
-	case 3:
-		local_irq_enable();
-		break;
-	default:
-		printk("global_restore_flags: %08lx (%08lx)\n",
-			flags, (&flags)[-1]);
-	}
-}
-
 #endif
 
 /*
@@ -435,11 +196,7 @@
  */
 int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
 {
-	int status;
-
-	irq_enter(0, irq);
-
-	status = 1;	/* Force the "do bottom halves" bit */
+	int status = 1; /* Force the "do bottom halves" bit */
 
 	if (!(action->flags & SA_INTERRUPT))
 		local_irq_enable();
@@ -453,8 +210,6 @@
 		add_interrupt_randomness(irq);
 	local_irq_disable();
 
-	irq_exit(0, irq);
-
 	return status;
 }
 
@@ -474,7 +229,7 @@
  *	Unlike disable_irq(), this function does not ensure existing
  *	instances of the IRQ handler have completed before returning.
  *
- *	This function may be called from IRQ context.
+ *	This function must not be called from IRQ context.
  */
  
 inline void disable_irq_nosync(unsigned int irq)
@@ -506,13 +261,7 @@
 void disable_irq(unsigned int irq)
 {
 	disable_irq_nosync(irq);
-
-	if (!local_irq_count(smp_processor_id())) {
-		do {
-			barrier();
-			cpu_relax();
-		} while (irq_desc[irq].status & IRQ_INPROGRESS);
-	}
+	synchronize_irq(irq);
 }
 
 /**
@@ -578,6 +327,7 @@
 
 	if (irq > 256) BUG();
 
+	irq_enter(); 
 	kstat.irqs[cpu][irq]++;
 	spin_lock(&desc->lock);
 	desc->handler->ack(irq);
@@ -593,7 +343,7 @@
 	 * use the action we have.
 	 */
 	action = NULL;
-	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+	if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
 		action = desc->action;
 		status &= ~IRQ_PENDING; /* we commit to handling */
 		status |= IRQ_INPROGRESS; /* we are handling it */
@@ -606,7 +356,7 @@
 	   a different instance of this same irq, the other processor
 	   will take care of it.
 	 */
-	if (!action)
+	if (unlikely(!action))
 		goto out;
 
 	/*
@@ -624,7 +374,7 @@
 		handle_IRQ_event(irq, regs, action);
 		spin_lock(&desc->lock);
 		
-		if (!(desc->status & IRQ_PENDING))
+		if (unlikely(!(desc->status & IRQ_PENDING)))
 			break;
 		desc->status &= ~IRQ_PENDING;
 	}
@@ -638,8 +388,7 @@
 	desc->handler->end(irq);
 	spin_unlock(&desc->lock);
 
-	if (softirq_pending(cpu))
-		do_softirq();
+	irq_exit();
 	return 1;
 }
 
@@ -703,7 +452,7 @@
 		return -EINVAL;
 
 	action = (struct irqaction *)
-			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+			kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
 	if (!action)
 		return -ENOMEM;
 
@@ -766,13 +515,7 @@
 			}
 			spin_unlock_irqrestore(&desc->lock,flags);
 
-#ifdef CONFIG_SMP
-			/* Wait to make sure it's not being used on another CPU */
-			while (desc->status & IRQ_INPROGRESS) {
-				barrier();
-				cpu_relax();
-			}
-#endif
+			synchronize_irq(irq);
 			kfree(action);
 			return;
 		}
@@ -824,7 +567,7 @@
 
 	/* Wait for longstanding interrupts to trigger. */
 	for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
-		/* about 20ms delay */ synchronize_irq();
+		/* about 20ms delay */ barrier();
 
 	/*
 	 * enable any unassigned irqs
@@ -847,7 +590,7 @@
 	 * Wait for spurious interrupts to trigger
 	 */
 	for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
-		/* about 100ms delay */ synchronize_irq();
+		/* about 100ms delay */ barrier();
 
 	/*
 	 * Now filter out any obviously spurious interrupts
diff -Nru a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt.c
--- a/arch/x86_64/kernel/ldt.c	Tue Oct 15 20:29:21 2002
+++ b/arch/x86_64/kernel/ldt.c	Tue Oct 15 20:29:21 2002
@@ -22,32 +22,13 @@
 #include <asm/ldt.h>
 #include <asm/desc.h>
 
-void load_gs_index(unsigned gs)
-{
-	int access;
-	struct task_struct *me = current;
-	if (me->mm) 
-		read_lock(&me->mm->context.ldtlock); 
-	asm volatile("pushf\n\t" 
-		     "cli\n\t"
-		     "swapgs\n\t"
-		     "lar %1,%0\n\t"
-		     "jnz 1f\n\t"
-		     "movl %1,%%eax\n\t"
-		     "movl %%eax,%%gs\n\t"
-		     "jmp 2f\n\t"
-		     "1: movl %2,%%gs\n\t"
-		     "2: swapgs\n\t"
-		     "popf" : "=g" (access) : "g" (gs), "r" (0) : "rax"); 
-	if (me->mm) 
-		read_unlock(&me->mm->context.ldtlock); 
-}
+extern void load_gs_index(unsigned gs);
 
 #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
-static void flush_ldt(void *mm)
+static void flush_ldt(void *null)
 {
-	if (current->mm)
-		load_LDT(&current->mm->context);
+	if (current->active_mm)
+               load_LDT(&current->active_mm->context);
 }
 #endif
 
@@ -75,15 +56,18 @@
 	memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
 	wmb();
 	pc->ldt = newldt;
+	wmb();
 	pc->size = mincount;
+	wmb();
 	if (reload) {
 		load_LDT(pc);
 #ifdef CONFIG_SMP
+		preempt_disable();
 		if (current->mm->cpu_vm_mask != (1<<smp_processor_id()))
 			smp_call_function(flush_ldt, 0, 1, 1);
+		preempt_enable();
 #endif
 	}
-	wmb();
 	if (oldsize) {
 		if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
 			vfree(oldldt);
@@ -96,11 +80,8 @@
 static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
 {
 	int err = alloc_ldt(new, old->size, 0);
-	if (err < 0) {
-		printk(KERN_WARNING "ldt allocation failed\n");
-		new->size = 0;
+	if (err < 0)
 		return err;
-	}
 	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
 	return 0;
 }
@@ -187,7 +168,7 @@
 	struct mm_struct * mm = me->mm;
 	__u32 entry_1, entry_2, *lp;
 	int error;
-	struct modify_ldt_ldt_s ldt_info;
+	struct user_desc ldt_info;
 
 	error = -EINVAL;
 
@@ -223,34 +204,17 @@
 
    	/* Allow LDTs to be cleared by the user. */
    	if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
-		if (oldmode ||
-		    (ldt_info.contents == 0		&&
-		     ldt_info.read_exec_only == 1	&&
-		     ldt_info.seg_32bit == 0		&&
-		     ldt_info.limit_in_pages == 0	&&
-		     ldt_info.seg_not_present == 1	&&
-		     ldt_info.useable == 0 && 
-		     ldt_info.lm == 0)) {
+		if (oldmode || LDT_empty(&ldt_info)) {
 			entry_1 = 0;
 			entry_2 = 0;
 			goto install;
 		}
 	}
 
-	entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
-		  (ldt_info.limit & 0x0ffff);
-	entry_2 = (ldt_info.base_addr & 0xff000000) |
-		  ((ldt_info.base_addr & 0x00ff0000) >> 16) |
-		  (ldt_info.limit & 0xf0000) |
-		  ((ldt_info.read_exec_only ^ 1) << 9) |
-		  (ldt_info.contents << 10) |
-		  ((ldt_info.seg_not_present ^ 1) << 15) |
-		  (ldt_info.seg_32bit << 22) |
-		  (ldt_info.limit_in_pages << 23) |
-		  (ldt_info.lm << 21) |
-		  0x7000;
-	if (!oldmode)
-		entry_2 |= (ldt_info.useable << 20);
+	entry_1 = LDT_entry_a(&ldt_info);
+	entry_2 = LDT_entry_b(&ldt_info);
+	if (oldmode)
+		entry_2 &= ~(1 << 20);
 
 	/* Install the new entry ...  */
 install:
diff -Nru a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
--- a/arch/x86_64/kernel/mpparse.c	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/kernel/mpparse.c	Tue Oct 15 20:29:15 2002
@@ -10,6 +10,7 @@
  *		Alan Cox	:	Added EBDA scanning
  *		Ingo Molnar	:	various cleanups and rewrites
  *	Maciej W. Rozycki	:	Bits for default MP configurations
+ *		Paul Diefenbaugh:	Added full ACPI support
  */
 
 #include <linux/mm.h>
@@ -21,11 +22,13 @@
 #include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
+#include <linux/acpi.h>
 
 #include <asm/smp.h>
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
+#include <asm/io_apic.h>
 
 /* Have we found an MP table */
 int smp_found_config;
@@ -262,7 +265,7 @@
 	printk("APIC at: 0x%X\n",mpc->mpc_lapic);
 
 	/* save the local APIC address, it might be non-default */
-	if (!acpi_found_madt)
+	if (!acpi_lapic)
 	mp_lapic_addr = mpc->mpc_lapic;
 
 	/*
@@ -274,7 +277,7 @@
 			{
 				struct mpc_config_processor *m=
 					(struct mpc_config_processor *)mpt;
-				if (!acpi_found_madt)
+				if (!acpi_lapic)
 				MP_processor_info(m);
 				mpt += sizeof(*m);
 				count += sizeof(*m);
@@ -490,19 +493,18 @@
 {
 	struct intel_mp_floating *mpf = mpf_found;
 
-#ifdef CONFIG_ACPI_BOOT
 	/*
-	 * Check if the MADT exists, and if so, use it to get processor
-	 * information (ACPI_MADT_LAPIC).  The MADT supports the concept
-	 * of both logical (e.g. HT) and physical processor(s); where the
-	 * MPS only supports physical.
-	 */
-	if (acpi_boot.madt) {
-		acpi_found_madt = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
-		if (acpi_found_madt > 0)
-			acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic);
+ 	 * ACPI may be used to obtain the entire SMP configuration or just to 
+ 	 * enumerate/configure processors (CONFIG_ACPI_HT_ONLY).  Note that 
+ 	 * ACPI supports both logical (e.g. Hyper-Threading) and physical 
+ 	 * processors, where MPS only supports physical.
+ 	 */
+ 	if (acpi_lapic && acpi_ioapic) {
+ 		printk(KERN_INFO "Using ACPI (MADT) for SMP configuration information\n");
+ 		return;
 	}
-#endif /*CONFIG_ACPI_BOOT*/
+ 	else if (acpi_lapic)
+ 		printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n");
 
 	printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
 	if (mpf->mpf_feature2 & (1<<7)) {
@@ -664,3 +666,315 @@
 #endif
 }
 
+
+/* --------------------------------------------------------------------------
+                            ACPI-based MP Configuration
+   -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ACPI_BOOT
+
+void __init mp_register_lapic_address (
+	u64			address)
+{
+	mp_lapic_addr = (unsigned long) address;
+
+	set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
+
+	if (boot_cpu_id == -1U)
+		boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID));
+
+	Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid);
+}
+
+
+void __init mp_register_lapic (
+	u8			id, 
+	u8			enabled)
+{
+	struct mpc_config_processor processor;
+	int			boot_cpu = 0;
+	
+	if (id >= MAX_APICS) {
+		printk(KERN_WARNING "Processor #%d invalid (max %d)\n",
+			id, MAX_APICS);
+		return;
+	}
+
+	if (id == boot_cpu_physical_apicid)
+		boot_cpu = 1;
+
+	processor.mpc_type = MP_PROCESSOR;
+	processor.mpc_apicid = id;
+	processor.mpc_apicver = 0x10; /* TBD: lapic version */
+	processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0);
+	processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0);
+	processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | 
+		(boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask;
+	processor.mpc_featureflag = boot_cpu_data.x86_capability[0];
+	processor.mpc_reserved[0] = 0;
+	processor.mpc_reserved[1] = 0;
+
+	MP_processor_info(&processor);
+}
+
+#ifdef CONFIG_X86_IO_APIC
+
+#define MP_ISA_BUS		0
+#define MP_MAX_IOAPIC_PIN	127
+
+struct mp_ioapic_routing {
+	int			apic_id;
+	int			irq_start;
+	int			irq_end;
+	u32			pin_programmed[4];
+} mp_ioapic_routing[MAX_IO_APICS];
+
+
+static int __init mp_find_ioapic (
+	int			irq)
+{
+	int			i = 0;
+
+	/* Find the IOAPIC that manages this IRQ. */
+	for (i = 0; i < nr_ioapics; i++) {
+		if ((irq >= mp_ioapic_routing[i].irq_start)
+			&& (irq <= mp_ioapic_routing[i].irq_end))
+			return i;
+	}
+
+	printk(KERN_ERR "ERROR: Unable to locate IOAPIC for IRQ %d/n", irq);
+
+	return -1;
+}
+	
+
+void __init mp_register_ioapic (
+	u8			id, 
+	u32			address,
+	u32			irq_base)
+{
+	int			idx = 0;
+
+	if (nr_ioapics >= MAX_IO_APICS) {
+		printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
+			"(found %d)\n", MAX_IO_APICS, nr_ioapics);
+		panic("Recompile kernel with bigger MAX_IO_APICS!\n");
+	}
+	if (!address) {
+		printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
+			" found in MADT table, skipping!\n");
+		return;
+	}
+
+	idx = nr_ioapics++;
+
+	mp_ioapics[idx].mpc_type = MP_IOAPIC;
+	mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
+	mp_ioapics[idx].mpc_apicaddr = address;
+
+	set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
+	mp_ioapics[idx].mpc_apicid = io_apic_get_unique_id(idx, id);
+	mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
+	
+	/* 
+	 * Build basic IRQ lookup table to facilitate irq->io_apic lookups
+	 * and to prevent reprogramming of IOAPIC pins (PCI IRQs).
+	 */
+	mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid;
+	mp_ioapic_routing[idx].irq_start = irq_base;
+	mp_ioapic_routing[idx].irq_end = irq_base + 
+		io_apic_get_redir_entries(idx);
+
+	printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, "
+		"IRQ %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, 
+		mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
+		mp_ioapic_routing[idx].irq_start,
+		mp_ioapic_routing[idx].irq_end);
+
+	return;
+}
+
+
+void __init mp_override_legacy_irq (
+	u8			bus_irq,
+	u8			polarity, 
+	u8			trigger, 
+	u32			global_irq)
+{
+	struct mpc_config_intsrc intsrc;
+	int			i = 0;
+	int			found = 0;
+	int			ioapic = -1;
+	int			pin = -1;
+
+	/* 
+	 * Convert 'global_irq' to 'ioapic.pin'.
+	 */
+	ioapic = mp_find_ioapic(global_irq);
+	if (ioapic < 0)
+		return;
+	pin = global_irq - mp_ioapic_routing[ioapic].irq_start;
+
+	/*
+	 * TBD: This check is for faulty timer entries, where the override
+	 *      erroneously sets the trigger to level, resulting in a HUGE 
+	 *      increase of timer interrupts!
+	 */
+	if ((bus_irq == 0) && (global_irq == 2) && (trigger == 3))
+		trigger = 1;
+
+	intsrc.mpc_type = MP_INTSRC;
+	intsrc.mpc_irqtype = mp_INT;
+	intsrc.mpc_irqflag = (trigger << 2) | polarity;
+	intsrc.mpc_srcbus = MP_ISA_BUS;
+	intsrc.mpc_srcbusirq = bus_irq;				       /* IRQ */
+	intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;	   /* APIC ID */
+	intsrc.mpc_dstirq = pin;				    /* INTIN# */
+
+	Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n", 
+		intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3, 
+		(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, 
+		intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
+
+	/* 
+	 * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it.
+	 * Otherwise create a new entry (e.g. global_irq == 2).
+	 */
+	for (i = 0; i < mp_irq_entries; i++) {
+		if ((mp_irqs[i].mpc_dstapic == intsrc.mpc_dstapic) 
+			&& (mp_irqs[i].mpc_dstirq == intsrc.mpc_dstirq)) {
+			mp_irqs[i] = intsrc;
+			found = 1;
+			break;
+		}
+	}
+	if (!found) {
+		mp_irqs[mp_irq_entries] = intsrc;
+		if (++mp_irq_entries == MAX_IRQ_SOURCES)
+			panic("Max # of irq sources exceeded!\n");
+	}
+
+	return;
+}
+
+
+void __init mp_config_acpi_legacy_irqs (void)
+{
+	struct mpc_config_intsrc intsrc;
+	int			i = 0;
+	int			ioapic = -1;
+
+	/* 
+	 * Fabricate the legacy ISA bus (bus #31).
+	 */
+	mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA;
+	Dprintk("Bus #%d is ISA\n", MP_ISA_BUS);
+
+	/* 
+	 * Locate the IOAPIC that manages the ISA IRQs (0-15). 
+	 */
+	ioapic = mp_find_ioapic(0);
+	if (ioapic < 0)
+		return;
+
+	intsrc.mpc_type = MP_INTSRC;
+	intsrc.mpc_irqflag = 0;					/* Conforming */
+	intsrc.mpc_srcbus = MP_ISA_BUS;
+	intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;
+
+	/* 
+	 * Use the default configuration for the IRQs 0-15.  These may be
+	 * overriden by (MADT) interrupt source override entries.
+	 */
+	for (i = 0; i < 16; i++) {
+
+		if (i == 2) continue;			/* Don't connect IRQ2 */
+
+		intsrc.mpc_irqtype = i ? mp_INT : mp_ExtINT;   /* 8259A to #0 */
+		intsrc.mpc_srcbusirq = i;		   /* Identity mapped */
+		intsrc.mpc_dstirq = i;
+
+		Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, "
+			"%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3, 
+			(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, 
+			intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, 
+			intsrc.mpc_dstirq);
+
+		mp_irqs[mp_irq_entries] = intsrc;
+		if (++mp_irq_entries == MAX_IRQ_SOURCES)
+			panic("Max # of irq sources exceeded!\n");
+	}
+
+	return;
+}
+
+#ifdef CONFIG_ACPI_PCI
+
+void __init mp_parse_prt (void)
+{
+	struct list_head	*node = NULL;
+	struct acpi_prt_entry	*entry = NULL;
+	int			vector = 0;
+	int			ioapic = -1;
+	int			ioapic_pin = 0;
+	int			irq = 0;
+	int			idx, bit = 0;
+
+	/*
+	 * Parsing through the PCI Interrupt Routing Table (PRT) and program
+	 * routing for all static (IOAPIC-direct) entries.
+	 */
+	list_for_each(node, &acpi_prt.entries) {
+		entry = list_entry(node, struct acpi_prt_entry, node);
+
+		/* We're only interested in static (non-link) entries. */
+		if (entry->link.handle)
+			continue;
+
+		irq = entry->link.index;
+		ioapic = mp_find_ioapic(irq);
+		if (ioapic < 0)
+			continue;
+		ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
+
+		/* 
+		 * Avoid pin reprogramming.  PRTs typically include entries  
+		 * with redundant pin->irq mappings (but unique PCI devices);
+		 * we only only program the IOAPIC on the first.
+		 */
+		bit = ioapic_pin % 32;
+		idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
+		if (idx > 3) {
+			printk(KERN_ERR "Invalid reference to IOAPIC pin "
+				"%d-%d\n", mp_ioapic_routing[ioapic].apic_id, 
+				ioapic_pin);
+			continue;
+		}
+		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+			printk(KERN_DEBUG "Pin %d-%d already programmed\n",
+				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+			entry->irq = irq;
+			continue;
+		}
+
+		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
+
+		vector = io_apic_set_pci_routing(ioapic, ioapic_pin, irq);
+		if (vector)
+			entry->irq = irq;
+
+		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> vector 0x%02x"
+			" -> IRQ %d\n", entry->id.segment, entry->id.bus, 
+			entry->id.device, ('A' + entry->pin), 
+			mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, 
+			entry->irq);
+	}
+	
+	return;
+}
+
+#endif /*CONFIG_ACPI_PCI*/
+
+#endif /*CONFIG_X86_IO_APIC*/
+
+#endif /*CONFIG_ACPI_BOOT*/
diff -Nru a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c
--- a/arch/x86_64/kernel/msr.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/kernel/msr.c	Tue Oct 15 20:29:12 2002
@@ -247,11 +247,11 @@
  * File operations we support
  */
 static struct file_operations msr_fops = {
-  owner:	THIS_MODULE,
-  llseek:	msr_seek,
-  read:		msr_read,
-  write:	msr_write,
-  open:		msr_open,
+  .owner =	THIS_MODULE,
+  .llseek =	msr_seek,
+  .read =	msr_read,
+  .write =	msr_write,
+  .open =	msr_open,
 };
 
 int __init msr_init(void)
diff -Nru a/arch/x86_64/kernel/mtrr.c b/arch/x86_64/kernel/mtrr.c
--- a/arch/x86_64/kernel/mtrr.c	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/kernel/mtrr.c	Tue Oct 15 20:29:15 2002
@@ -25,6 +25,9 @@
 	v2.01  June 2002  Dave Jones <davej@suse.de>
 	  Removal of redundant abstraction layer.
 	  64-bit fixes.
+	v2.02  July 2002  Dave Jones <davej@suse.de>
+	  Fix gentry inconsistencies between kernel/userspace.
+	  More casts to clean up warnings.
 */
 
 #include <linux/types.h>
@@ -50,6 +53,7 @@
 #include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/agp_backend.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -64,7 +68,7 @@
 #include <asm/hardirq.h>
 #include <linux/irq.h>
 
-#define MTRR_VERSION "2.01 (20020605)"
+#define MTRR_VERSION "2.02 (20020716)"
 
 #define TRUE  1
 #define FALSE 0
@@ -106,7 +110,7 @@
 struct set_mtrr_context {
 	u32 deftype_lo;
 	u32 deftype_hi;
-	u64 flags;
+	unsigned long flags;
 	u64 cr4val;
 };
 
@@ -117,7 +121,7 @@
 	u64 cr0;
 
 	/* Disable interrupts locally */
-	local_save_flags(ctxt->flags);
+	local_irq_save(ctxt->flags);
 	local_irq_disable();
 
     /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
@@ -221,6 +225,8 @@
 		   u32 size, mtrr_type type, int do_safe)
 {
     struct set_mtrr_context ctxt;
+	u64 base64;
+	u64 size64;
 
 	if (do_safe)
 		set_mtrr_prepare (&ctxt);
@@ -230,10 +236,12 @@
 	   relevant mask register to disable a range. */
 		wrmsr (MSR_MTRRphysMask(reg), 0, 0);
 	} else {
-		wrmsr (MSR_MTRRphysBase(reg), base << PAGE_SHIFT | type,
-		(base & size_and_mask) >> (32 - PAGE_SHIFT));
-		wrmsr (MSR_MTRRphysMask(reg), (-size-1) << PAGE_SHIFT | 0x800,
-		       ((-size-1) & size_and_mask) >> (32 - PAGE_SHIFT));
+		base64 = (base << PAGE_SHIFT) & size_and_mask;
+		wrmsr (MSR_MTRRphysBase(reg), base64 | type, base64 >> 32);
+
+		size64 = ~((size << PAGE_SHIFT) - 1);
+		size64 = size64 & size_and_mask;
+		wrmsr (MSR_MTRRphysMask(reg), (u32) (size64 | 0x800), (u32) (size64 >> 32));
     }
 	if (do_safe)
 		set_mtrr_done (&ctxt);
@@ -267,15 +275,15 @@
     int changed = FALSE;
 
 	rdmsr (MSR_MTRRphysBase(index), lo, hi);
-	if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff)
-	    || (vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) {
+	if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) ||
+		(vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) {
 		wrmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi);
 	changed = TRUE;
     }
 
 	rdmsr (MSR_MTRRphysMask(index), lo, hi);
-	if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800)
-	    || (vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) {
+	if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) ||
+		(vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) {
 		wrmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi);
 	changed = TRUE;
     }
@@ -457,7 +465,7 @@
     data.smp_type = type;
     wait_barrier_execute = TRUE;
     wait_barrier_cache_enable = TRUE;
-    atomic_set (&undone_count, smp_num_cpus - 1);
+	atomic_set (&undone_count, num_online_cpus() - 1);
 
     /*  Start the ball rolling on other CPUs  */
     if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
@@ -471,7 +479,7 @@
 		barrier ();
 
 	/* Set up for completion wait and then release other CPUs to change MTRRs */
-    atomic_set (&undone_count, smp_num_cpus - 1);
+	atomic_set (&undone_count, num_online_cpus() - 1);
     wait_barrier_execute = FALSE;
 	set_mtrr_up (reg, base, size, type, FALSE);
 
@@ -596,11 +604,22 @@
 
 	if (base + size < 0x100) {
 		printk (KERN_WARNING
-			"mtrr: cannot set region below 1 MiB (0x%lx000,0x%x000)\n",
+			"mtrr: cannot set region below 1 MiB (0x%Lx000,0x%x000)\n",
 		    base, size);
 	    return -EINVAL;
 	}
 
+#if defined(__x86_64__) && defined(CONFIG_AGP) 
+/*	{
+	agp_kern_info info; 
+	if (type != MTRR_TYPE_UNCACHABLE && agp_copy_info(&info) >= 0 && 
+	    base<<PAGE_SHIFT >= info.aper_base && 
+            (base<<PAGE_SHIFT)+(size<<PAGE_SHIFT) >= 
+			info.aper_base+info.aper_size*1024*1024)
+		printk(KERN_INFO "%s[%d] setting conflicting mtrr into agp aperture\n",current->comm,current->pid); 
+	}*/
+#endif
+
 	/*  Check upper bits of base and last are equal and lower bits are 0
 	    for base and 1 for last  */
 	last = base + size - 1;
@@ -609,7 +628,7 @@
 
 	if (lbase != last) {
 		printk (KERN_WARNING
-			"mtrr: base(0x%lx000) is not aligned on a size(0x%x000) boundary\n",
+			"mtrr: base(0x%Lx000) is not aligned on a size(0x%x000) boundary\n",
 			base, size);
 	return -EINVAL;
     }
@@ -626,8 +645,14 @@
         return -ENOSYS;
     }
 
-	if (base & size_or_mask || size & size_or_mask) {
-	printk ("mtrr: base or size exceeds the MTRR width\n");
+	if (base & (size_or_mask>>PAGE_SHIFT)) {
+		printk (KERN_WARNING "mtrr: base(%lx) exceeds the MTRR width(%lx)\n",
+				base, (size_or_mask>>PAGE_SHIFT));
+		return -EINVAL;
+	}
+
+	if (size & (size_or_mask>>PAGE_SHIFT)) {
+		printk (KERN_WARNING "mtrr: size exceeds the MTRR width\n");
 	return -EINVAL;
     }
 
@@ -646,8 +671,8 @@
 		if ((base < lbase) || (base + size > lbase + lsize)) {
 			up (&mtrr_lock);
 			printk (KERN_WARNING
-				"mtrr: 0x%lx000,0x%x000 overlaps existing"
-				" 0x%lx000,0x%x000\n", base, size, lbase, lsize);
+				"mtrr: 0x%Lx000,0x%x000 overlaps existing"
+				" 0x%Lx000,0x%x000\n", base, size, lbase, lsize);
 	    return -EINVAL;
 	}
 	/*  New region is enclosed by an existing region  */
@@ -656,7 +681,7 @@
 				continue;
 			up (&mtrr_lock);
 			printk
-			    ("mtrr: type mismatch for %lx000,%x000 old: %s new: %s\n",
+			    ("mtrr: type mismatch for %Lx000,%x000 old: %s new: %s\n",
 			     base, size,
 				 attrib_to_str (ltype),
 			     attrib_to_str (type));
@@ -720,7 +745,7 @@
 {
 	if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
 	printk ("mtrr: size and base must be multiples of 4 kiB\n");
-		printk ("mtrr: size: 0x%x  base: 0x%lx\n", size, base);
+		printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
 	return -EINVAL;
     }
 	return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
@@ -763,7 +788,7 @@
 	}
 		if (reg < 0) {
 			up (&mtrr_lock);
-			printk ("mtrr: no MTRR for %lx000,%x000 found\n", base, size);
+			printk ("mtrr: no MTRR for %Lx000,%x000 found\n", base, size);
 	    return -EINVAL;
 	}
     }
@@ -814,7 +839,7 @@
 {
 	if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
 	printk ("mtrr: size and base must be multiples of 4 kiB\n");
-		printk ("mtrr: size: 0x%x  base: 0x%lx\n", size, base);
+		printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
 	return -EINVAL;
     }
 	return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
@@ -844,7 +869,7 @@
 		if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
 			printk
 			    ("mtrr: size and base must be multiples of 4 kiB\n");
-			printk ("mtrr: size: 0x%x  base: 0x%lx\n", size, base);
+			printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
 	    return -EINVAL;
 	}
 	base >>= PAGE_SHIFT;
@@ -869,7 +894,7 @@
 		if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
 			printk
 			    ("mtrr: size and base must be multiples of 4 kiB\n");
-			printk ("mtrr: size: 0x%x  base: 0x%lx\n", size, base);
+			printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
 	    return -EINVAL;
 	}
 	base >>= PAGE_SHIFT;
@@ -961,7 +986,7 @@
 
 	if ((base & 0xfff) || (size & 0xfff)) {
 	printk ("mtrr: size and base must be multiples of 4 kiB\n");
-		printk ("mtrr: size: 0x%x  base: 0x%lx\n", size, base);
+		printk ("mtrr: size: 0x%x  base: 0x%Lx\n", size, base);
 	return -EINVAL;
     }
 
@@ -1007,8 +1032,7 @@
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
-		err =
-		    mtrr_file_add (sentry.base, sentry.size, sentry.type,
+		err = mtrr_file_add (sentry.base, sentry.size, sentry.type,
 				   file, 0);
 		if (err < 0)
 			return err;
@@ -1049,7 +1073,7 @@
 	    return -EFAULT;
 		if (gentry.regnum >= get_num_var_ranges ())
 			return -EINVAL;
-		get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type);
+		get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type);
 
 	/* Hide entries that go above 4GB */
 		if (gentry.base + gentry.size > 0x100000
@@ -1070,9 +1094,7 @@
 			return -EPERM;
 		if (copy_from_user (&sentry, (void *) arg, sizeof sentry))
 	    return -EFAULT;
-		err =
-		    mtrr_file_add (sentry.base, sentry.size, sentry.type,
-				   file, 1);
+		err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 1);
 		if (err < 0)
 			return err;
 	break;
@@ -1112,7 +1134,7 @@
 	    return -EFAULT;
 		if (gentry.regnum >= get_num_var_ranges ())
 			return -EINVAL;
-		get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type);
+		get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type);
 	gentry.type = type;
 
 		if (copy_to_user ((void *) arg, &gentry, sizeof gentry))
@@ -1131,6 +1153,7 @@
 	if (fcount == NULL)
 		return 0;
 
+	lock_kernel ();
     max = get_num_var_ranges ();
 	for (i = 0; i < max; ++i) {
 		while (fcount[i] > 0) {
@@ -1139,6 +1162,7 @@
 	    --fcount[i];
 	}
     }
+	unlock_kernel ();
     kfree (fcount);
     file->private_data = NULL;
     return 0;
@@ -1146,11 +1170,11 @@
 
 
 static struct file_operations mtrr_fops = {
-    owner:	THIS_MODULE,
-    read:	mtrr_read,
-    write:	mtrr_write,
-    ioctl:	mtrr_ioctl,
-	release:mtrr_close,
+	.owner   = THIS_MODULE,
+	.read	 = mtrr_read,
+	.write	 = mtrr_write,
+	.ioctl   = mtrr_ioctl,
+	.release = mtrr_close,
 };
 
 #ifdef CONFIG_PROC_FS
@@ -1182,10 +1206,9 @@
 		factor = 'M';
 		size >>= 20 - PAGE_SHIFT;
 	    }
-	    sprintf
-		(ascii_buffer + ascii_buf_bytes,
-			     "reg%02i: base=0x%05lx000 (%4liMB), size=%4i%cB: %s, count=%d\n",
-		 i, base, base >> (20 - PAGE_SHIFT), size, factor,
+			sprintf (ascii_buffer + ascii_buf_bytes,
+				"reg%02i: base=0x%05Lx000 (%4iMB), size=%4i%cB: %s, count=%d\n",
+				i, base, (u32) base >> (20 - PAGE_SHIFT), size, factor,
 		 attrib_to_str (type), usage_table[i]);
 			ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
 	}
@@ -1213,8 +1236,12 @@
 		if ((cpuid_eax (0x80000000) >= 0x80000008)) {
 			u32	phys_addr;
 			phys_addr = cpuid_eax (0x80000008) & 0xff;
-			size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1);
-			size_and_mask = ~size_or_mask & 0xfffffffffff00000;
+			size_or_mask = ~((1L << phys_addr) - 1);
+			/*
+			 * top bits MBZ as its beyond the addressable range.
+			 * bottom bits MBZ as we don't care about lower 12 bits of addr.
+			 */
+			size_and_mask = (~size_or_mask) & 0x000ffffffffff000L;
 	}
 		printk ("mtrr: detected mtrr type: x86-64\n");
     }
diff -Nru a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
--- a/arch/x86_64/kernel/nmi.c	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/kernel/nmi.c	Tue Oct 15 20:29:16 2002
@@ -24,7 +24,7 @@
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 
-unsigned int nmi_watchdog = NMI_NONE;
+unsigned int nmi_watchdog = NMI_LOCAL_APIC;
 static unsigned int nmi_hz = HZ;
 unsigned int nmi_perfctr_msr;	/* the MSR to reset in NMI handler */
 extern void show_registers(struct pt_regs *regs);
@@ -43,22 +43,38 @@
 #define P6_EVENT_CPU_CLOCKS_NOT_HALTED	0x79
 #define P6_NMI_EVENT		P6_EVENT_CPU_CLOCKS_NOT_HALTED
 
+/* Why is there no CPUID flag for this? */
+static __init int cpu_has_lapic(void)
+{
+	switch (boot_cpu_data.x86_vendor) { 
+	case X86_VENDOR_INTEL:
+	case X86_VENDOR_AMD: 
+		return boot_cpu_data.x86 >= 6; 
+	/* .... add more cpus here or find a different way to figure this out. */	
+	default:
+		return 0;
+	} 	
+}
+
 int __init check_nmi_watchdog (void)
 {
 	int counts[NR_CPUS];
-	int j, cpu;
+	int cpu;
+
+	if (nmi_watchdog == NMI_LOCAL_APIC && !cpu_has_lapic())  {
+		nmi_watchdog = NMI_NONE;
+		return -1; 
+	}	
 
 	printk(KERN_INFO "testing NMI watchdog ... ");
 
-	for (j = 0; j < NR_CPUS; ++j) {
-		cpu = cpu_logical_map(j); 
+	for_each_cpu(cpu) { 
 		counts[cpu] = cpu_pda[cpu].__nmi_count; 
 	}
-	sti();
+	local_irq_enable();
 	mdelay((10*1000)/nmi_hz); // wait 10 ticks
 
-	for (j = 0; j < smp_num_cpus; j++) {
-		cpu = cpu_logical_map(j);
+	for_each_cpu(cpu) { 
 		if (cpu_pda[cpu].__nmi_count - counts[cpu] <= 5) {
 			printk("CPU#%d: NMI appears to be stuck (%d)!\n", 
 			       cpu,
@@ -84,26 +100,6 @@
 
 	if (nmi >= NMI_INVALID)
 		return 0;
-	if (nmi == NMI_NONE)
-		nmi_watchdog = nmi;
-	/*
-	 * If any other x86 CPU has a local APIC, then
-	 * please test the NMI stuff there and send me the
-	 * missing bits. Right now Intel P6 and AMD K7 only.
-	 */
-	if ((nmi == NMI_LOCAL_APIC) &&
-			(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
-			(boot_cpu_data.x86 == 6))
-		nmi_watchdog = nmi;
-	if ((nmi == NMI_LOCAL_APIC) &&
-			(boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
-			(boot_cpu_data.x86 == 6))
-		nmi_watchdog = nmi;
-	/*
-	 * We can enable the IO-APIC watchdog
-	 * unconditionally.
-	 */
-	if (nmi == NMI_IO_APIC)
 		nmi_watchdog = nmi;
 	return 1;
 }
@@ -167,6 +163,8 @@
 	int i;
 	unsigned int evntsel;
 
+	/* XXX should check these in EFER */
+
 	nmi_perfctr_msr = MSR_K7_PERFCTR0;
 
 	for(i = 0; i < 4; ++i) {
@@ -180,7 +178,7 @@
 		| K7_NMI_EVENT;
 
 	wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
-	Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
+	printk(KERN_INFO "watchdog: setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
 	wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
 	apic_write(APIC_LVTPC, APIC_DM_NMI);
 	evntsel |= K7_EVNTSEL_ENABLE;
@@ -191,7 +189,11 @@
 {
 	switch (boot_cpu_data.x86_vendor) {
 	case X86_VENDOR_AMD:
-		if (boot_cpu_data.x86 != 6)
+		if (boot_cpu_data.x86 < 6)
+			return;
+		/* Simics masquerades as AMD, but does not support 
+		   performance counters */
+		if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
 			return;
 		setup_k7_watchdog();
 		break;
@@ -230,7 +232,7 @@
 	 * Just reset the alert counters, (other CPUs might be
 	 * spinning on locks we hold):
 	 */
-	for (i = 0; i < smp_num_cpus; i++)
+	for (i = 0; i < NR_CPUS; i++)
 		alert_counter[i] = 0;
 }
 
@@ -243,8 +245,7 @@
 	 * smp_processor_id().
 	 */
 	int sum, cpu = smp_processor_id();
-
-	sum = apic_timer_irqs[cpu];
+	sum = read_pda(apic_timer_irqs);
 
 	if (last_irq_sums[cpu] == sum) {
 		/*
diff -Nru a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
--- a/arch/x86_64/kernel/pci-dma.c	Tue Oct 15 20:29:21 2002
+++ b/arch/x86_64/kernel/pci-dma.c	Tue Oct 15 20:29:21 2002
@@ -1,5 +1,5 @@
 /*
- * Dynamic DMA mapping support.
+ * Dynamic DMA mapping support. Common code
  */
 
 #include <linux/types.h>
@@ -8,24 +8,63 @@
 #include <linux/pci.h>
 #include <asm/io.h>
 
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-			   dma_addr_t *dma_handle)
+dma_addr_t bad_dma_address = -1UL; 
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for DMA.  This is the scather-gather version of the
+ * above pci_map_single interface.  Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length.  They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ *       DMA address/length pairs than there are SG table elements.
+ *       (for example via virtual mapping capabilities)
+ *       The routine returns the number of addr/length pairs actually
+ *       used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			     int nents, int direction)
 {
-	void *ret;
-	int gfp = GFP_ATOMIC;
+	int i;
 
-	gfp |= GFP_DMA;
-	ret = (void *)__get_free_pages(gfp, get_order(size));
+	BUG_ON(direction == PCI_DMA_NONE);
+ 
+ 	/*
+ 	 *
+ 	 */
+ 	for (i = 0; i < nents; i++ ) {
+		struct scatterlist *s = &sg[i];
+ 		if (s->page) { 
+			s->dma_address = pci_map_page(hwdev, s->page, s->offset, 
+						      s->length, direction); 
+		} else
+			BUG(); 
 
-	if (ret != NULL) {
-		memset(ret, 0, size);
-		*dma_handle = virt_to_phys(ret);
+		if (unlikely(s->dma_address == bad_dma_address))
+			goto error; 
 	}
-	return ret;
+	return nents;
+
+ error: 
+	pci_unmap_sg(hwdev, sg, i, direction); 
+	return 0; 
 }
 
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
+/* Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg, 
+				  int nents, int dir)
 {
-	free_pages((unsigned long)vaddr, get_order(size));
+	int i;
+	for (i = 0; i < nents; i++) { 
+		struct scatterlist *s = &sg[i];
+		BUG_ON(s->page == NULL); 
+		BUG_ON(s->dma_address == 0); 
+		pci_unmap_single(dev, s->dma_address, s->length, dir); 
+	} 
 }
diff -Nru a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/kernel/pci-gart.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,560 @@
+/*
+ * Dynamic DMA mapping support for AMD Hammer.
+ * 
+ * Use the integrated AGP GART in the Hammer northbridge as an IOMMU for PCI.
+ * This allows to use PCI devices that only support 32bit addresses on systems
+ * with more than 4GB. 
+ *
+ * See Documentation/DMA-mapping.txt for the interface specification.
+ * 
+ * Copyright 2002 Andi Kleen, SuSE Labs.
+ * $Id: pci-gart.c,v 1.12 2002/09/19 19:25:32 ak Exp $
+ */
+
+/* 
+ * Notebook:
+
+agpgart_be
+ check if the simple reservation scheme is enough.
+
+possible future tuning: 
+ fast path for sg streaming mappings 
+ more intelligent flush strategy - flush only a single NB?
+ move boundary between IOMMU and AGP in GART dynamically
+ could use exact fit in the gart in alloc_consistent, not order of two.
+*/ 
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/agp_backend.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/mtrr.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/proto.h>
+#include <asm/cacheflush.h>
+
+unsigned long iommu_bus_base;	/* GART remapping area (physical) */
+static unsigned long iommu_size; 	/* size of remapping area bytes */
+static unsigned long iommu_pages;	/* .. and in pages */
+
+u32 *iommu_gatt_base; 		/* Remapping table */
+
+int no_iommu; 
+static int no_agp; 
+int force_mmu = 1;
+
+extern int fallback_aper_order;
+extern int fallback_aper_force;
+
+/* Allocation bitmap for the remapping area */ 
+static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */
+
+#define GPTE_MASK 0xfffffff000
+#define GPTE_VALID    1
+#define GPTE_COHERENT 2
+#define GPTE_ENCODE(x,flag) (((x) & 0xfffffff0) | ((x) >> 28) | GPTE_VALID | (flag))
+#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((x) & 0xff0) << 28))
+
+#define for_all_nb(dev) \
+	pci_for_each_dev(dev) \
+		if (dev->bus->number == 0 && PCI_FUNC(dev->devfn) == 3 && \
+		    (PCI_SLOT(dev->devfn) >= 24) && (PCI_SLOT(dev->devfn) <= 31))
+
+#define EMERGENCY_PAGES 32 /* = 128KB */ 
+
+#ifdef CONFIG_AGP
+extern int agp_init(void);
+#define AGPEXTERN extern
+#else
+#define AGPEXTERN
+#endif
+
+/* backdoor interface to AGP driver */
+AGPEXTERN int agp_memory_reserved;
+AGPEXTERN __u32 *agp_gatt_table;
+
+static unsigned long next_bit;  /* protected by iommu_bitmap_lock */
+
+static unsigned long alloc_iommu(int size) 
+{ 	
+	unsigned long offset, flags;
+
+	spin_lock_irqsave(&iommu_bitmap_lock, flags);	
+
+	offset = find_next_zero_string(iommu_gart_bitmap,next_bit,iommu_pages,size);
+	if (offset == -1) 
+	       	offset = find_next_zero_string(iommu_gart_bitmap,0,next_bit,size);
+	if (offset != -1) { 
+		set_bit_string(iommu_gart_bitmap, offset, size); 
+		next_bit = offset+size; 
+		if (next_bit >= iommu_pages) 
+			next_bit = 0;
+	} 
+	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);      
+	return offset;
+} 
+
+static void free_iommu(unsigned long offset, int size)
+{ 
+	unsigned long flags;
+	spin_lock_irqsave(&iommu_bitmap_lock, flags);
+	clear_bit_string(iommu_gart_bitmap, offset, size);
+	next_bit = offset;
+	spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
+} 
+
+static inline void flush_gart(void) 
+{ 
+	struct pci_dev *nb; 
+	for_all_nb(nb) { 
+		u32 flag; 
+		pci_read_config_dword(nb, 0x9c, &flag); /* could cache this */ 
+		/* could complain for PTE walk errors here (bit 1 of flag) */ 
+		flag |= 1; 
+		pci_write_config_dword(nb, 0x9c, flag); 
+	} 
+} 
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t *dma_handle)
+{
+	void *memory;
+	int gfp = GFP_ATOMIC;
+	int order, i;
+	unsigned long iommu_page;
+
+	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu)
+		gfp |= GFP_DMA;
+
+	/* 
+	 * First try to allocate continuous and use directly if already 
+	 * in lowmem. 
+	 */ 
+	order = get_order(size);
+	memory = (void *)__get_free_pages(gfp, order);
+	if (memory == NULL) {
+		return NULL; 
+	} else {
+		int high = (unsigned long)virt_to_bus(memory) + size
+			>= 0xffffffff;
+		int mmu = high;
+		if (force_mmu) 
+			mmu = 1;
+		if (no_iommu) { 
+			if (high) goto error;
+			mmu = 0; 
+		} 	
+		memset(memory, 0, size); 
+		if (!mmu) { 
+			*dma_handle = virt_to_bus(memory);
+			return memory;
+		}
+	} 
+
+	iommu_page = alloc_iommu(1<<order);
+	if (iommu_page == -1)
+		goto error; 
+
+   	/* Fill in the GATT, allocating pages as needed. */
+	for (i = 0; i < 1<<order; i++) { 
+		unsigned long phys_mem; 
+		void *mem = memory + i*PAGE_SIZE;
+		if (i > 0) 
+			atomic_inc(&virt_to_page(mem)->count); 
+		phys_mem = virt_to_phys(mem); 
+		BUG_ON(phys_mem & ~PTE_MASK); 
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem,GPTE_COHERENT); 
+	} 
+
+	flush_gart();
+	*dma_handle = iommu_bus_base + (iommu_page << PAGE_SHIFT);
+	return memory; 
+	
+ error:
+	free_pages((unsigned long)memory, order); 
+	return NULL; 
+}
+
+/* 
+ * Unmap consistent memory.
+ * The caller must ensure that the device has finished accessing the mapping.
+ */
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t bus)
+{
+	u64 pte;
+	int order = get_order(size);
+	unsigned long iommu_page;
+	int i;
+
+	if (bus < iommu_bus_base || bus > iommu_bus_base + iommu_size) { 
+		free_pages((unsigned long)vaddr, order); 		
+		return;
+	} 
+	iommu_page = (bus - iommu_bus_base) / PAGE_SIZE;
+	for (i = 0; i < 1<<order; i++) {
+		pte = iommu_gatt_base[iommu_page + i];
+		BUG_ON((pte & GPTE_VALID) == 0); 
+		iommu_gatt_base[iommu_page + i] = 0; 		
+		free_page((unsigned long) __va(GPTE_DECODE(pte)));
+	} 
+	flush_gart(); 
+	free_iommu(iommu_page, 1<<order);
+}
+
+#ifdef CONFIG_IOMMU_LEAK
+/* Debugging aid for drivers that don't free their IOMMU tables */
+static void **iommu_leak_tab; 
+static int leak_trace;
+int iommu_leak_dumppages = 20; 
+void dump_leak(void)
+{
+	int i;
+	static int dump; 
+	if (dump || !iommu_leak_tab) return;
+	dump = 1;
+	show_stack(NULL);
+	printk("Dumping %d pages from end of IOMMU:\n", iommu_leak_dumppages); 
+	for (i = 0; i < iommu_leak_dumppages; i++) 
+		printk("[%lu: %lx] ",
+		       iommu_pages-i,(unsigned long) iommu_leak_tab[iommu_pages-i]); 
+	printk("\n");
+}
+#endif
+
+static void iommu_full(struct pci_dev *dev, void *addr, size_t size, int dir)
+{
+	/* 
+	 * Ran out of IOMMU space for this operation. This is very bad.
+	 * Unfortunately the drivers cannot handle this operation properly.
+	 * Return some non mapped prereserved space in the aperture and 
+	 * let the Northbridge deal with it. This will result in garbage
+	 * in the IO operation. When the size exceeds the prereserved space
+	 * memory corruption will occur or random memory will be DMAed 
+	 * out. Hopefully no network devices use single mappings that big.
+	 */ 
+	
+	printk(KERN_ERR 
+  "PCI-DMA: Error: ran out out IOMMU space for %p size %lu at device %s[%s]\n",
+	       addr,size, dev ? dev->name : "?", dev ? dev->slot_name : "?");
+
+	if (size > PAGE_SIZE*EMERGENCY_PAGES) {
+		if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL)
+			panic("PCI-DMA: Memory will be corrupted\n");
+		if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) 
+			panic("PCI-DMA: Random memory will be DMAed\n"); 
+	} 
+
+#ifdef CONFIG_IOMMU_LEAK
+	dump_leak(); 
+#endif
+} 
+
+static inline int need_iommu(struct pci_dev *dev, unsigned long addr, size_t size)
+{ 
+	u64 mask = dev ? dev->dma_mask : 0xffffffff;
+	int high = (~mask & (unsigned long)(addr + size)) != 0;
+	int mmu = high;
+	if (force_mmu) 
+		mmu = 1; 
+	if (no_iommu) { 
+		if (high) 
+			panic("pci_map_single: high address but no IOMMU.\n"); 
+		mmu = 0; 
+	} 	
+	return mmu; 
+}
+
+dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size,int dir)
+{ 
+	unsigned long iommu_page;
+	unsigned long phys_mem, bus;
+	int i, npages;
+
+	BUG_ON(dir == PCI_DMA_NONE);
+
+	phys_mem = virt_to_phys(addr); 
+	if (!need_iommu(dev, phys_mem, size))
+		return phys_mem; 
+
+	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+
+	iommu_page = alloc_iommu(npages); 
+	if (iommu_page == -1) {
+		iommu_full(dev, addr, size, dir); 
+		return iommu_bus_base; 
+	} 
+
+	phys_mem &= PAGE_MASK;
+	for (i = 0; i < npages; i++, phys_mem += PAGE_SIZE) {
+		BUG_ON(phys_mem & ~PTE_MASK); 
+		
+		/* 
+		 * Set coherent mapping here to avoid needing to flush
+		 * the caches on mapping.
+		 */
+		iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem, GPTE_COHERENT);
+
+#ifdef CONFIG_IOMMU_LEAK
+		/* XXX need eventually caller of pci_map_sg */
+		if (iommu_leak_tab) 
+			iommu_leak_tab[iommu_page + i] = __builtin_return_address(0); 
+#endif
+	}
+	flush_gart(); 
+
+	bus = iommu_bus_base + iommu_page*PAGE_SIZE; 
+	return bus + ((unsigned long)addr & ~PAGE_MASK); 	
+} 
+
+/*
+ * Free a temporary PCI mapping.
+ */ 
+void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+		      size_t size, int direction)
+{
+	unsigned long iommu_page; 
+	int i, npages;
+	if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || 
+	    dma_addr > iommu_bus_base + iommu_size)
+		return;
+	iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;	
+	npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT;
+	for (i = 0; i < npages; i++) { 
+		iommu_gatt_base[iommu_page + i] = 0; 
+#ifdef CONFIG_IOMMU_LEAK
+		if (iommu_leak_tab)
+			iommu_leak_tab[iommu_page + i] = 0; 
+#endif
+	}
+	flush_gart(); 
+	free_iommu(iommu_page, npages);
+}
+
+EXPORT_SYMBOL(pci_map_single);
+EXPORT_SYMBOL(pci_unmap_single);
+
+static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
+{ 
+	unsigned long a; 
+	if (!iommu_size) { 
+		iommu_size = aper_size; 
+		if (!no_agp) 
+			iommu_size /= 2; 
+	} 
+
+	a = aper + iommu_size; 
+	iommu_size -= round_up(a, LARGE_PAGE_SIZE) - a;
+
+	if (iommu_size < 64*1024*1024) 
+		printk(KERN_WARNING
+  "PCI-DMA: Warning: Small IOMMU %luMB. Consider increasing the AGP aperture in BIOS\n",iommu_size>>20); 
+	
+	return iommu_size;
+} 
+
+static __init unsigned read_aperture(struct pci_dev *dev, u32 *size) 
+{ 
+	unsigned aper_size = 0, aper_base_32;
+	u64 aper_base;
+	unsigned aper_order;
+
+	pci_read_config_dword(dev, 0x94, &aper_base_32); 
+	pci_read_config_dword(dev, 0x90, &aper_order);
+	aper_order = (aper_order >> 1) & 7;	
+
+	aper_base = aper_base_32 & 0x7fff; 
+	aper_base <<= 25;
+
+	aper_size = (32 * 1024 * 1024) << aper_order; 
+	if (aper_base + aper_size >= 0xffffffff || !aper_size)
+		aper_base = 0;
+
+	*size = aper_size;
+	return aper_base;
+} 
+
+/* 
+ * Private Northbridge GATT initialization in case we cannot use the
+ * AGP driver for some reason.  
+ */
+static __init int init_k8_gatt(agp_kern_info *info)
+{ 
+	struct pci_dev *dev;
+	void *gatt;
+	unsigned aper_base, new_aper_base;
+	unsigned aper_size, gatt_size, new_aper_size;
+	
+	aper_size = aper_base = info->aper_size = 0;
+	for_all_nb(dev) { 
+		new_aper_base = read_aperture(dev, &new_aper_size); 
+		if (!new_aper_base) 
+			goto nommu; 
+		
+		if (!aper_base) { 
+			aper_size = new_aper_size;
+			aper_base = new_aper_base;
+		} 
+		if (aper_size != new_aper_size || aper_base != new_aper_base) 
+			goto nommu;
+	}
+	if (!aper_base)
+		goto nommu; 
+	info->aper_base = aper_base;
+	info->aper_size = aper_size>>20; 
+
+	gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32); 
+	gatt = (void *)__get_free_pages(GFP_KERNEL, get_order(gatt_size)); 
+	if (!gatt) 
+		panic("Cannot allocate GATT table"); 
+	memset(gatt, 0, gatt_size); 
+	change_page_attr(virt_to_page(gatt), gatt_size/PAGE_SIZE, PAGE_KERNEL_NOCACHE);
+	agp_gatt_table = gatt;
+	
+	for_all_nb(dev) { 
+		u32 ctl; 
+		u32 gatt_reg; 
+
+		gatt_reg = ((u64)gatt) >> 12; 
+		gatt_reg <<= 4; 
+		pci_write_config_dword(dev, 0x98, gatt_reg);
+		pci_read_config_dword(dev, 0x90, &ctl); 
+
+		ctl |= 1;
+		ctl &= ~((1<<4) | (1<<5));
+
+		pci_write_config_dword(dev, 0x90, ctl); 
+	}
+	flush_gart(); 
+	
+		
+	printk("PCI-DMA: aperture base @ %x size %u KB\n", aper_base, aper_size>>10); 
+	return 0;
+
+ nommu:
+	/* XXX: reject 0xffffffff mask now in pci mapping functions */
+	printk(KERN_ERR "PCI-DMA: More than 4GB of RAM and no IOMMU\n"
+	       KERN_ERR "PCI-DMA: 32bit PCI IO may malfunction."); 
+	return -1; 
+} 
+
+void __init pci_iommu_init(void)
+{ 
+	agp_kern_info info;
+	unsigned long aper_size;
+	unsigned long iommu_start;
+		
+#ifndef CONFIG_AGP
+	no_agp = 1; 
+#else
+	no_agp = no_agp || (agp_init() < 0) || (agp_copy_info(&info) < 0); 
+#endif	
+
+	if (no_iommu || (!force_mmu && end_pfn < 0xffffffff>>PAGE_SHIFT)) { 
+		printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); 
+		no_iommu = 1;
+		return;
+	}
+
+	if (no_agp) { 
+		int err = -1;
+		printk(KERN_INFO "PCI-DMA: Disabling AGP.\n");
+		no_agp = 1;
+		if (force_mmu || end_pfn >= 0xffffffff>>PAGE_SHIFT)
+			err = init_k8_gatt(&info);
+		if (err < 0) { 
+			printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); 
+			no_iommu = 1;
+			return;
+		}
+	} 
+	
+	aper_size = info.aper_size * 1024 * 1024;	
+	iommu_size = check_iommu_size(info.aper_base, aper_size); 
+	iommu_pages = iommu_size >> PAGE_SHIFT; 
+
+	iommu_gart_bitmap = (void*)__get_free_pages(GFP_KERNEL, 
+						    get_order(iommu_pages/8)); 
+	if (!iommu_gart_bitmap) 
+		panic("Cannot allocate iommu bitmap\n"); 
+	memset(iommu_gart_bitmap, 0, iommu_pages/8);
+
+#ifdef CONFIG_IOMMU_LEAK
+	if (leak_trace) { 
+		iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL, 
+				  get_order(iommu_pages*sizeof(void *)));
+		if (iommu_leak_tab) 
+			memset(iommu_leak_tab, 0, iommu_pages * 8); 
+		else
+			printk("PCI-DMA: Cannot allocate leak trace area\n"); 
+	} 
+#endif
+
+	/* 
+	 * Out of IOMMU space handling.
+	 * Reserve some invalid pages at the beginning of the GART. 
+	 */ 
+	set_bit_string(iommu_gart_bitmap, 0, EMERGENCY_PAGES); 
+
+	agp_memory_reserved = iommu_size;	
+	printk(KERN_INFO"PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n",
+	       iommu_size>>20); 
+
+	iommu_start = aper_size - iommu_size;	
+	iommu_bus_base = info.aper_base + iommu_start; 
+	iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT);
+	bad_dma_address = iommu_bus_base;
+
+	asm volatile("wbinvd" ::: "memory");
+} 
+
+/* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]]
+   size  set size of iommu (in bytes) 
+   noagp don't initialize the AGP driver and use full aperture.
+   off   don't use the IOMMU
+   leak  turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on)
+   memaper[=order] allocate an own aperture over RAM with size 32MB^order.  
+*/
+__init int iommu_setup(char *opt) 
+{ 
+    int arg;
+    char *p = opt;
+    
+    for (;;) { 
+	    if (!memcmp(p,"noagp", 5))
+		    no_agp = 1;
+	    if (!memcmp(p,"off", 3))
+		    no_iommu = 1;
+	    if (!memcmp(p,"force", 5))
+		    force_mmu = 1;
+	    if (!memcmp(p,"noforce", 7))
+		    force_mmu = 0;
+	    if (!memcmp(p, "memaper", 7)) { 
+		    fallback_aper_force = 1; 
+		    p += 7; 
+		    if (*p == '=' && get_option(&p, &arg))
+			    fallback_aper_order = arg;
+	    } 
+#ifdef CONFIG_IOMMU_LEAK
+	    if (!memcmp(p,"leak", 4))
+		    leak_trace = 1;
+#endif
+	    if (isdigit(*p) && get_option(&p, &arg)) 
+		    iommu_size = arg;
+	    do {
+		    if (*p == ' ' || *p == 0) 
+			    return 0; 
+	    } while (*p++ != ','); 
+    }
+    return 1;
+} 
+
diff -Nru a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/kernel/pci-nommu.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,48 @@
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+/* 
+ * Dummy IO MMU functions
+ */
+
+extern unsigned long end_pfn;
+
+void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+			   dma_addr_t *dma_handle)
+{
+	void *ret;
+	int gfp = GFP_ATOMIC;
+	
+	if (hwdev == NULL ||
+	    end_pfn > (hwdev->dma_mask>>PAGE_SHIFT) ||  /* XXX */
+	    (u32)hwdev->dma_mask < 0xffffffff)
+		gfp |= GFP_DMA;
+	ret = (void *)__get_free_pages(gfp, get_order(size));
+
+	if (ret != NULL) {
+		memset(ret, 0, size);
+		*dma_handle = virt_to_bus(ret);
+	}
+	return ret;
+}
+
+void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+			 void *vaddr, dma_addr_t dma_handle)
+{
+	free_pages((unsigned long)vaddr, get_order(size));
+}
+
+
+static void __init check_ram(void) 
+{ 
+	if (end_pfn >= 0xffffffff>>PAGE_SHIFT) { 
+		printk(KERN_ERR "WARNING more than 4GB of memory but no IOMMU.\n"
+		       KERN_ERR "WARNING 32bit PCI may malfunction.\n"); 
+		/* Could play with highmem_start_page here to trick some subsystems
+		   into bounce buffers. Unfortunately that would require setting
+		   CONFIG_HIGHMEM too. 
+		 */ 
+	} 
+} 
diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
--- a/arch/x86_64/kernel/process.c	Tue Oct 15 20:29:11 2002
+++ b/arch/x86_64/kernel/process.c	Tue Oct 15 20:29:11 2002
@@ -36,7 +36,6 @@
 #include <linux/interrupt.h>
 #include <linux/config.h>
 #include <linux/delay.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
@@ -57,6 +56,7 @@
 #include <linux/irq.h>
 
 asmlinkage extern void ret_from_fork(void);
+int sys_arch_prctl(int code, unsigned long addr);
 
 unsigned long kernel_thread_flags = CLONE_VM;
 
@@ -67,11 +67,6 @@
  */
 void (*pm_idle)(void);
 
-/*
- * Power off function, if any
- */
-void (*pm_power_off)(void);
-
 void disable_hlt(void)
 {
 	hlt_counter++;
@@ -160,123 +155,6 @@
 
 __setup("idle=", idle_setup);
 
-static long no_idt[3];
-static int reboot_mode;
-
-#ifdef CONFIG_SMP
-int reboot_smp = 0;
-static int reboot_cpu = -1;
-#endif
-static int __init reboot_setup(char *str)
-{
-	while(1) {
-		switch (*str) {
-		case 'w': /* "warm" reboot (no memory testing etc) */
-			reboot_mode = 0x1234;
-			break;
-		case 'c': /* "cold" reboot (with memory testing etc) */
-			reboot_mode = 0x0;
-			break;
-#ifdef CONFIG_SMP
-		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
-			reboot_smp = 1;
-			if (isdigit(str[1]))
-				sscanf(str+1, "%d", &reboot_cpu);		
-			else if (!strncmp(str,"smp",3))
-				sscanf(str+3, "%d", &reboot_cpu); 
-				/* we will leave sorting out the final value 
-				when we are ready to reboot, since we might not
- 				have set up boot_cpu_id or smp_num_cpu */
-			break;
-#endif
-		}
-		if((str = strchr(str,',')) != NULL)
-			str++;
-		else
-			break;
-	}
-	return 1;
-}
-
-__setup("reboot=", reboot_setup);
-
-static inline void kb_wait(void)
-{
-	int i;
-
-	for (i=0; i<0x10000; i++)
-		if ((inb_p(0x64) & 0x02) == 0)
-			break;
-}
-
-void machine_restart(char * __unused)
-{
-#if CONFIG_SMP
-	int cpuid;
-	
-	cpuid = GET_APIC_ID(apic_read(APIC_ID));
-
-	if (reboot_smp) {
-
-		/* check to see if reboot_cpu is valid 
-		   if its not, default to the BSP */
-		if ((reboot_cpu == -1) ||  
-		      (reboot_cpu > (NR_CPUS -1))  || 
-		      !(phys_cpu_present_map & (1<<cpuid))) 
-			reboot_cpu = boot_cpu_id;
-
-		reboot_smp = 0;  /* use this as a flag to only go through this once*/
-		/* re-run this function on the other CPUs
-		   it will fall though this section since we have 
-		   cleared reboot_smp, and do the reboot if it is the
-		   correct CPU, otherwise it halts. */
-		if (reboot_cpu != cpuid)
-			smp_call_function((void *)machine_restart , NULL, 1, 0);
-	}
-
-	/* if reboot_cpu is still -1, then we want a tradional reboot, 
-	   and if we are not running on the reboot_cpu,, halt */
-	if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
-		for (;;)
-		__asm__ __volatile__ ("hlt");
-	}
-	/*
-	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
-	 * other OSs see a clean IRQ state.
-	 */
-	if (notify_die(DIE_STOP,"cpustop",0,0) != NOTIFY_BAD)
-	smp_send_stop();
-	disable_IO_APIC();
-#endif
-
-		/* rebooting needs to touch the page at absolute addr 0 */
-		*((unsigned short *)__va(0x472)) = reboot_mode;
-		for (;;) {
-			int i;
-		/* First fondle with the keyboard controller. */ 
-			for (i=0; i<100; i++) {
-				kb_wait();
-				udelay(50);
-				outb(0xfe,0x64);         /* pulse reset low */
-				udelay(50);
-			}
-			/* That didn't work - force a triple fault.. */
-			__asm__ __volatile__("lidt %0": :"m" (no_idt));
-			__asm__ __volatile__("int3");
-		}
-
-	/* Could do reset through the northbridge of Hammer here. */
-}
-
-void machine_halt(void)
-{
-}
-
-void machine_power_off(void)
-{
-	if (pm_power_off)
-		pm_power_off();
-}
 
 /* Prints also some state that isn't saved in the pt_regs */ 
 void show_regs(struct pt_regs * regs)
@@ -286,9 +164,11 @@
 	unsigned int ds,cs,es; 
 
 	printk("\n");
+	print_modules();
 	printk("Pid: %d, comm: %.20s %s\n", current->pid, current->comm, print_tainted());
-	printk("RIP: %04lx:[<%016lx>]\n", regs->cs & 0xffff, regs->rip);
-	printk("RSP: %016lx  EFLAGS: %08lx\n", regs->rsp, regs->eflags);
+	printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
+	printk_address(regs->rip); 
+	printk("\nRSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
 	printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
 	       regs->rax, regs->rbx, regs->rcx);
 	printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
@@ -378,6 +258,7 @@
 	if (rsp == ~0) {
 		childregs->rsp = (unsigned long)childregs;
 	}
+	p->user_tid = NULL;
 
 	p->thread.rsp = (unsigned long) childregs;
 	p->thread.rsp0 = (unsigned long) (childregs+1);
@@ -404,6 +285,30 @@
 		       (IO_BITMAP_SIZE+1)*4);
 	} 
 
+	/*
+	 * Set a new TLS for the child thread?
+	 */
+	if (clone_flags & CLONE_SETTLS) {
+		struct n_desc_struct *desc;
+		struct user_desc info;
+		int idx;
+
+		if (copy_from_user(&info, test_thread_flag(TIF_IA32) ? 
+								  (void *)childregs->rsi : 
+								  (void *)childregs->rdx, sizeof(info)))
+			return -EFAULT;
+		if (LDT_empty(&info))
+			return -EINVAL;
+
+		idx = info.entry_number;
+		if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+			return -EINVAL;
+
+		desc = (struct n_desc_struct *)(p->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN;
+		desc->a = LDT_entry_a(&info);
+		desc->b = LDT_entry_b(&info);
+	}
+
 	return 0;
 }
 
@@ -428,8 +333,8 @@
 {
 	struct thread_struct *prev = &prev_p->thread,
 				 *next = &next_p->thread;
-	struct tss_struct *tss = init_tss + smp_processor_id();
-
+	int cpu = smp_processor_id();  
+	struct tss_struct *tss = init_tss + cpu;
 
 	unlazy_fpu(prev_p);
 
@@ -440,6 +345,7 @@
 
 	/* 
 	 * Switch DS and ES.
+	 * This won't pick up thread selector changes, but I guess that is ok.
 	 */
 	asm volatile("movl %%es,%0" : "=m" (prev->es)); 
 	if (unlikely(next->es | prev->es))
@@ -452,25 +358,38 @@
 	/* 
 	 * Switch FS and GS.
 	 * XXX Check if this is safe on SMP (!= -> |)
+	 * Need to simplify this.
 	 */
 	{ 
 		unsigned int fsindex;
+		unsigned int gsindex;
 
 		asm volatile("movl %%fs,%0" : "=g" (fsindex)); 
-		if (unlikely(fsindex != next->fsindex)) /* or likely? */
-			loadsegment(fs, next->fsindex);
+		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
+
+		/*
+		 * Load the per-thread Thread-Local Storage descriptor.
+		 */
+		if (load_TLS(next, cpu)) {
+			loadsegment(fs,next->fsindex);
+			/* should find a way to optimize this away - it is
+			   slow */
+			goto loadgs;    
+		} else { 
+			if (fsindex  != next->fsindex)
+				loadsegment(fs,next->fsindex); 
+			if (gsindex != next->gsindex) {
+			loadgs:
+				load_gs_index(next->gsindex); 
+			} 	
+		}
+				
 		if (unlikely(fsindex != prev->fsindex))
 			prev->fs = 0;				
 		if ((fsindex != prev->fsindex) || (prev->fs != next->fs))
 			wrmsrl(MSR_FS_BASE, next->fs); 
 		prev->fsindex = fsindex;
-	}
-	{
-		unsigned int gsindex;
 
-		asm volatile("movl %%gs,%0" : "=g" (gsindex)); 
-		if (unlikely(gsindex != next->gsindex))
-			load_gs_index(next->gs); 
 		if (unlikely(gsindex != prev->gsindex)) 
 			prev->gs = 0;				
 		if (gsindex != prev->gsindex || prev->gs != next->gs)
@@ -486,6 +405,7 @@
 	write_pda(pcurrent, next_p); 
 	write_pda(kernelstack, (unsigned long)next_p->thread_info + THREAD_SIZE - PDA_STACKOFFSET);
 
+
 	/*
 	 * Now maybe reload the debug registers
 	 */
@@ -556,16 +476,16 @@
 asmlinkage long sys_fork(struct pt_regs regs)
 {
 	struct task_struct *p;
-	p = do_fork(SIGCHLD, regs.rsp, &regs, 0);
+	p = do_fork(SIGCHLD, regs.rsp, &regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
-asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs regs)
+asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void *user_tid, struct pt_regs regs)
 {
 	struct task_struct *p;
 	if (!newsp)
 		newsp = regs.rsp;
-	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
+	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
@@ -582,7 +502,7 @@
 asmlinkage long sys_vfork(struct pt_regs regs)
 {
 	struct task_struct *p;
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0);
+	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, &regs, 0, NULL);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
@@ -617,7 +537,7 @@
 #undef last_sched
 #undef first_sched
 
-asmlinkage int sys_arch_prctl(int code, unsigned long addr)
+int sys_arch_prctl(int code, unsigned long addr)
 { 
 	int ret = 0; 
 	unsigned long tmp; 
@@ -658,3 +578,115 @@
 	return ret;	
 } 
 
+/*
+ * sys_alloc_thread_area: get a yet unused TLS descriptor index.
+ */
+static int get_free_idx(void)
+{
+	struct thread_struct *t = &current->thread;
+	int idx;
+
+	for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
+		if (desc_empty((struct n_desc_struct *)(t->tls_array) + idx))
+			return idx + GDT_ENTRY_TLS_MIN;
+	return -ESRCH;
+}
+
+/*
+ * Set a given TLS descriptor:
+ * When you want addresses > 32bit use arch_prctl() 
+ */
+asmlinkage int sys_set_thread_area(struct user_desc *u_info)
+{
+	struct thread_struct *t = &current->thread;
+	struct user_desc info;
+	struct n_desc_struct *desc;
+	int cpu, idx;
+
+	if (copy_from_user(&info, u_info, sizeof(info)))
+		return -EFAULT;
+	idx = info.entry_number;
+
+	/*
+	 * index -1 means the kernel should try to find and
+	 * allocate an empty descriptor:
+	 */
+	if (idx == -1) {
+		idx = get_free_idx();
+		if (idx < 0)
+			return idx;
+		if (put_user(idx, &u_info->entry_number))
+			return -EFAULT;
+	}
+
+	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+		return -EINVAL;
+
+	desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN;
+
+	/*
+	 * We must not get preempted while modifying the TLS.
+	 */
+	cpu = get_cpu();
+
+	if (LDT_empty(&info)) {
+		desc->a = 0;
+		desc->b = 0;
+	} else {
+		desc->a = LDT_entry_a(&info);
+		desc->b = LDT_entry_b(&info);
+	}
+	load_TLS(t, cpu);
+
+	put_cpu();
+	return 0;
+}
+
+/*
+ * Get the current Thread-Local Storage area:
+ */
+
+#define GET_BASE(desc) ( \
+	(((desc)->a >> 16) & 0x0000ffff) | \
+	(((desc)->b << 16) & 0x00ff0000) | \
+	( (desc)->b        & 0xff000000)   )
+
+#define GET_LIMIT(desc) ( \
+	((desc)->a & 0x0ffff) | \
+	 ((desc)->b & 0xf0000) )
+	
+#define GET_32BIT(desc)		(((desc)->b >> 23) & 1)
+#define GET_CONTENTS(desc)	(((desc)->b >> 10) & 3)
+#define GET_WRITABLE(desc)	(((desc)->b >>  9) & 1)
+#define GET_LIMIT_PAGES(desc)	(((desc)->b >> 23) & 1)
+#define GET_PRESENT(desc)	(((desc)->b >> 15) & 1)
+#define GET_USEABLE(desc)	(((desc)->b >> 20) & 1)
+
+asmlinkage int sys_get_thread_area(struct user_desc *u_info)
+{
+	struct user_desc info;
+	struct n_desc_struct *desc;
+	int idx;
+
+	if (get_user(idx, &u_info->entry_number))
+		return -EFAULT;
+	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+		return -EINVAL;
+
+	desc = ((struct n_desc_struct *)current->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN;
+
+	memset(&info, 0, sizeof(struct user_desc));
+	info.entry_number = idx;
+	info.base_addr = GET_BASE(desc);
+	info.limit = GET_LIMIT(desc);
+	info.seg_32bit = GET_32BIT(desc);
+	info.contents = GET_CONTENTS(desc);
+	info.read_exec_only = !GET_WRITABLE(desc);
+	info.limit_in_pages = GET_LIMIT_PAGES(desc);
+	info.seg_not_present = !GET_PRESENT(desc);
+	info.useable = GET_USEABLE(desc);
+
+	if (copy_to_user(u_info, &info, sizeof(info)))
+		return -EFAULT;
+	return 0;
+}
diff -Nru a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
--- a/arch/x86_64/kernel/ptrace.c	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/kernel/ptrace.c	Tue Oct 15 20:29:15 2002
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/security.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -111,6 +112,11 @@
 				return -EIO;
 			child->thread.es = value & 0xffff;
 			return 0;
+		case offsetof(struct user_regs_struct,ss):
+			if ((value & 3) != 3)
+				return -EIO;
+			value &= 0xffff;
+			return 0;
 		case offsetof(struct user_regs_struct,fs_base):
 			if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
 				return -EIO; 
@@ -128,7 +134,7 @@
 			value |= tmp;
 			break;
 		case offsetof(struct user_regs_struct,cs): 
-			if (value && (value & 3) != 3)
+			if ((value & 3) != 3)
 				return -EIO;
 			value &= 0xffff;
 			break;
@@ -171,6 +177,9 @@
 	if (request == PTRACE_TRACEME) {
 		/* are we already being traced? */
 		if (current->ptrace & PT_PTRACED)
+			goto out;
+		ret = security_ops->ptrace(current->parent, current);
+		if (ret)
 			goto out;
 		/* set the ptrace bit in the process flags. */
 		current->ptrace |= PT_PTRACED;
diff -Nru a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/kernel/reboot.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,136 @@
+/* Various gunk just to reboot the machine. */ 
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <asm/io.h>
+#include <asm/kdebug.h>
+#include <asm/delay.h>
+
+
+/*
+ * Power off function, if any
+ */
+void (*pm_power_off)(void);
+
+static long no_idt[3];
+static int reboot_mode;
+
+#ifdef CONFIG_SMP
+int reboot_smp = 0;
+static int reboot_cpu = -1;
+#endif
+
+static int __init reboot_setup(char *str)
+{
+	while(1) {
+		switch (*str) {
+		case 'w': /* "warm" reboot (no memory testing etc) */
+			reboot_mode = 0x1234;
+			break;
+		case 'c': /* "cold" reboot (with memory testing etc) */
+			reboot_mode = 0x0;
+			break;
+#ifdef CONFIG_SMP
+		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
+			reboot_smp = 1;
+			if (isdigit(str[1]))
+				sscanf(str+1, "%d", &reboot_cpu);		
+			else if (!strncmp(str,"smp",3))
+				sscanf(str+3, "%d", &reboot_cpu); 
+				/* we will leave sorting out the final value 
+				when we are ready to reboot, since we might not
+ 				have set up boot_cpu_id or smp_num_cpu */
+			break;
+#endif
+		}
+		if((str = strchr(str,',')) != NULL)
+			str++;
+		else
+			break;
+	}
+	return 1;
+}
+
+__setup("reboot=", reboot_setup);
+
+static inline void kb_wait(void)
+{
+	int i;
+
+	for (i=0; i<0x10000; i++)
+		if ((inb_p(0x64) & 0x02) == 0)
+			break;
+}
+
+void machine_restart(char * __unused)
+{
+#if CONFIG_SMP
+	int cpuid;
+	
+	cpuid = GET_APIC_ID(apic_read(APIC_ID));
+
+	if (reboot_smp) {
+
+		/* check to see if reboot_cpu is valid 
+		   if its not, default to the BSP */
+		if ((reboot_cpu == -1) ||  
+		      (reboot_cpu > (NR_CPUS -1))  || 
+		      !(phys_cpu_present_map & (1<<cpuid))) 
+			reboot_cpu = boot_cpu_id;
+
+		reboot_smp = 0;  /* use this as a flag to only go through this once*/
+		/* re-run this function on the other CPUs
+		   it will fall though this section since we have 
+		   cleared reboot_smp, and do the reboot if it is the
+		   correct CPU, otherwise it halts. */
+		if (reboot_cpu != cpuid)
+			smp_call_function((void *)machine_restart , NULL, 1, 0);
+	}
+
+	/* if reboot_cpu is still -1, then we want a tradional reboot, 
+	   and if we are not running on the reboot_cpu,, halt */
+	if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
+		for (;;)
+		__asm__ __volatile__ ("hlt");
+	}
+	/*
+	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
+	 * other OSs see a clean IRQ state.
+	 */
+	if (notify_die(DIE_STOP,"cpustop",0,0) != NOTIFY_BAD)
+	smp_send_stop();
+	disable_IO_APIC();
+#endif
+	
+	/* rebooting needs to touch the page at absolute addr 0 */
+	*((unsigned short *)__va(0x472)) = reboot_mode;
+	for (;;) {
+		int i;
+		/* First fondle with the keyboard controller. */ 
+		for (i=0; i<100; i++) {
+			kb_wait();
+			udelay(50);
+			outb(0xfe,0x64);         /* pulse reset low */
+			udelay(50);
+		}
+
+		/* Could do reset through the northbridge of Hammer here. */
+
+		/* That didn't work - force a triple fault.. */
+		__asm__ __volatile__("lidt %0": :"m" (no_idt));
+		__asm__ __volatile__("int3");
+	}      
+}
+
+void machine_halt(void)
+{
+}
+
+void machine_power_off(void)
+{
+	if (pm_power_off)
+		pm_power_off();
+}
diff -Nru a/arch/x86_64/kernel/semaphore.c b/arch/x86_64/kernel/semaphore.c
--- a/arch/x86_64/kernel/semaphore.c	Tue Oct 15 20:29:23 2002
+++ b/arch/x86_64/kernel/semaphore.c	Tue Oct 15 20:29:23 2002
@@ -29,8 +29,8 @@
  * needs to do something only if count was negative before
  * the increment operation.
  *
- * "sleeping" and the contention routine ordering is
- * protected by the semaphore spinlock.
+ * "sleeping" and the contention routine ordering is protected
+ * by the spinlock in the semaphore's waitqueue head.
  *
  * Note that these functions are only called when there is
  * contention on the lock, and as such all this is the
@@ -54,39 +54,41 @@
 	wake_up(&sem->wait);
 }
 
-static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
-
 void __down(struct semaphore * sem)
 {
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
+	unsigned long flags;
+
 	tsk->state = TASK_UNINTERRUPTIBLE;
-	add_wait_queue_exclusive(&sem->wait, &wait);
+	spin_lock_irqsave(&sem->wait.lock, flags);
+	add_wait_queue_exclusive_locked(&sem->wait, &wait);
 
-	spin_lock_irq(&semaphore_lock);
 	sem->sleepers++;
 	for (;;) {
 		int sleepers = sem->sleepers;
 
 		/*
 		 * Add "everybody else" into it. They aren't
-		 * playing, because we own the spinlock.
+		 * playing, because we own the spinlock in
+		 * the wait_queue_head.
 		 */
 		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
 			sem->sleepers = 0;
 			break;
 		}
 		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
+		spin_unlock_irqrestore(&sem->wait.lock, flags);
 
 		schedule();
+
+		spin_lock_irqsave(&sem->wait.lock, flags);
 		tsk->state = TASK_UNINTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
-	remove_wait_queue(&sem->wait, &wait);
+	remove_wait_queue_locked(&sem->wait, &wait);
+	wake_up_locked(&sem->wait);
+	spin_unlock_irqrestore(&sem->wait.lock, flags);
 	tsk->state = TASK_RUNNING;
-	wake_up(&sem->wait);
 }
 
 int __down_interruptible(struct semaphore * sem)
@@ -94,11 +96,13 @@
 	int retval = 0;
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
+	unsigned long flags;
+
 	tsk->state = TASK_INTERRUPTIBLE;
-	add_wait_queue_exclusive(&sem->wait, &wait);
+	spin_lock_irqsave(&sem->wait.lock, flags);
+	add_wait_queue_exclusive_locked(&sem->wait, &wait);
 
-	spin_lock_irq(&semaphore_lock);
-	sem->sleepers ++;
+	sem->sleepers++;
 	for (;;) {
 		int sleepers = sem->sleepers;
 
@@ -118,25 +122,27 @@
 
 		/*
 		 * Add "everybody else" into it. They aren't
-		 * playing, because we own the spinlock. The
-		 * "-1" is because we're still hoping to get
-		 * the lock.
+		 * playing, because we own the spinlock in
+		 * wait_queue_head. The "-1" is because we're
+		 * still hoping to get the semaphore.
 		 */
 		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
 			sem->sleepers = 0;
 			break;
 		}
 		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
+		spin_unlock_irqrestore(&sem->wait.lock, flags);
 
 		schedule();
+
+		spin_lock_irqsave(&sem->wait.lock, flags);
 		tsk->state = TASK_INTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
+	remove_wait_queue_locked(&sem->wait, &wait);
+	wake_up_locked(&sem->wait);
+	spin_unlock_irqrestore(&sem->wait.lock, flags);
+
 	tsk->state = TASK_RUNNING;
-	remove_wait_queue(&sem->wait, &wait);
-	wake_up(&sem->wait);
 	return retval;
 }
 
@@ -153,18 +159,20 @@
 	int sleepers;
 	unsigned long flags;
 
-	spin_lock_irqsave(&semaphore_lock, flags);
+	spin_lock_irqsave(&sem->wait.lock, flags);
 	sleepers = sem->sleepers + 1;
 	sem->sleepers = 0;
 
 	/*
 	 * Add "everybody else" and us into it. They aren't
-	 * playing, because we own the spinlock.
+	 * playing, because we own the spinlock in the
+	 * wait_queue_head.
 	 */
-	if (!atomic_add_negative(sleepers, &sem->count))
-		wake_up(&sem->wait);
+	if (!atomic_add_negative(sleepers, &sem->count)) {
+		wake_up_locked(&sem->wait);
+	}
 
-	spin_unlock_irqrestore(&semaphore_lock, flags);
+	spin_unlock_irqrestore(&sem->wait.lock, flags);
 	return 1;
 }
 
diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
--- a/arch/x86_64/kernel/setup.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/kernel/setup.c	Tue Oct 15 20:29:12 2002
@@ -50,18 +50,18 @@
 #include <asm/mmu_context.h>
 #include <asm/bootsetup.h>
 #include <asm/smp.h>
+#include <asm/proto.h>
 
 /*
  * Machine setup..
  */
 
-extern void mcheck_init(struct cpuinfo_x86 *c);
-extern void init_memory_mapping(void);
-
-struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
+struct cpuinfo_x86 boot_cpu_data;
 
 unsigned long mmu_cr4_features;
 
+int acpi_disabled __initdata = 0;
+
 /* For PCI or other memory-mapped resources */
 unsigned long pci_mem_start = 0x10000000;
 
@@ -86,8 +86,8 @@
 
 static int disable_x86_fxsr __initdata = 0;
 
-static char command_line[COMMAND_LINE_SIZE];
-       char saved_command_line[COMMAND_LINE_SIZE];
+char command_line[COMMAND_LINE_SIZE];
+char saved_command_line[COMMAND_LINE_SIZE];
 
 struct resource standard_io_resources[] = {
 	{ "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
@@ -102,9 +102,9 @@
 
 #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
 
-static struct resource code_resource = { "Kernel code", 0x100000, 0 };
-static struct resource data_resource = { "Kernel data", 0, 0 };
-static struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY };
+struct resource code_resource = { "Kernel code", 0x100000, 0 };
+struct resource data_resource = { "Kernel data", 0, 0 };
+struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY };
 
 /* System ROM resources */
 #define MAXROMS 6
@@ -178,358 +178,33 @@
 	}
 }
 
-void __init add_memory_region(unsigned long long start,
-                                  unsigned long long size, int type)
-{
-	int x = e820.nr_map;
-
-	if (x == E820MAX) {
-	    printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
-	    return;
-	}
-
-	e820.map[x].addr = start;
-	e820.map[x].size = size;
-	e820.map[x].type = type;
-	e820.nr_map++;
-} /* add_memory_region */
-
-#define E820_DEBUG	1
-
-static void __init print_memory_map(char *who)
-{
-	int i;
-
-	for (i = 0; i < e820.nr_map; i++) {
-		printk(" %s: %016Lx - %016Lx ", who,
-			(unsigned long long) e820.map[i].addr,
-			(unsigned long long) (e820.map[i].addr + e820.map[i].size));
-		switch (e820.map[i].type) {
-		case E820_RAM:	printk("(usable)\n");
-				break;
-		case E820_RESERVED:
-				printk("(reserved)\n");
-				break;
-		case E820_ACPI:
-				printk("(ACPI data)\n");
-				break;
-		case E820_NVS:
-				printk("(ACPI NVS)\n");
-				break;
-		default:	printk("type %u\n", e820.map[i].type);
-				break;
-		}
-	}
-}
-
-/*
- * Sanitize the BIOS e820 map.
- *
- * Some e820 responses include overlapping entries.  The following 
- * replaces the original e820 map with a new one, removing overlaps.
- *
- */
-static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
-{
-	struct change_member {
-		struct e820entry *pbios; /* pointer to original bios entry */
-		unsigned long long addr; /* address for this change point */
-	};
-	struct change_member change_point_list[2*E820MAX];
-	struct change_member *change_point[2*E820MAX];
-	struct e820entry *overlap_list[E820MAX];
-	struct e820entry new_bios[E820MAX];
-	struct change_member *change_tmp;
-	unsigned long current_type, last_type;
-	unsigned long long last_addr;
-	int chgidx, still_changing;
-	int overlap_entries;
-	int new_bios_entry;
-	int old_nr, new_nr;
-	int i;
-
-	/*
-		Visually we're performing the following (1,2,3,4 = memory types)...
-
-		Sample memory map (w/overlaps):
-		   ____22__________________
-		   ______________________4_
-		   ____1111________________
-		   _44_____________________
-		   11111111________________
-		   ____________________33__
-		   ___________44___________
-		   __________33333_________
-		   ______________22________
-		   ___________________2222_
-		   _________111111111______
-		   _____________________11_
-		   _________________4______
-
-		Sanitized equivalent (no overlap):
-		   1_______________________
-		   _44_____________________
-		   ___1____________________
-		   ____22__________________
-		   ______11________________
-		   _________1______________
-		   __________3_____________
-		   ___________44___________
-		   _____________33_________
-		   _______________2________
-		   ________________1_______
-		   _________________4______
-		   ___________________2____
-		   ____________________33__
-		   ______________________4_
-	*/
-
-	/* if there's only one memory region, don't bother */
-	if (*pnr_map < 2)
-		return -1;
-
-	old_nr = *pnr_map;
-
-	/* bail out if we find any unreasonable addresses in bios map */
-	for (i=0; i<old_nr; i++)
-		if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
-			return -1;
-
-	/* create pointers for initial change-point information (for sorting) */
-	for (i=0; i < 2*old_nr; i++)
-		change_point[i] = &change_point_list[i];
-
-	/* record all known change-points (starting and ending addresses) */
-	chgidx = 0;
-	for (i=0; i < old_nr; i++)	{
-		change_point[chgidx]->addr = biosmap[i].addr;
-		change_point[chgidx++]->pbios = &biosmap[i];
-		change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
-		change_point[chgidx++]->pbios = &biosmap[i];
-	}
-
-	/* sort change-point list by memory addresses (low -> high) */
-	still_changing = 1;
-	while (still_changing)	{
-		still_changing = 0;
-		for (i=1; i < 2*old_nr; i++)  {
-			/* if <current_addr> > <last_addr>, swap */
-			/* or, if current=<start_addr> & last=<end_addr>, swap */
-			if ((change_point[i]->addr < change_point[i-1]->addr) ||
-				((change_point[i]->addr == change_point[i-1]->addr) &&
-				 (change_point[i]->addr == change_point[i]->pbios->addr) &&
-				 (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
-			   )
-			{
-				change_tmp = change_point[i];
-				change_point[i] = change_point[i-1];
-				change_point[i-1] = change_tmp;
-				still_changing=1;
-			}
-		}
-	}
-
-	/* create a new bios memory map, removing overlaps */
-	overlap_entries=0;	 /* number of entries in the overlap table */
-	new_bios_entry=0;	 /* index for creating new bios map entries */
-	last_type = 0;		 /* start with undefined memory type */
-	last_addr = 0;		 /* start with 0 as last starting address */
-	/* loop through change-points, determining affect on the new bios map */
-	for (chgidx=0; chgidx < 2*old_nr; chgidx++)
-	{
-		/* keep track of all overlapping bios entries */
-		if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
-		{
-			/* add map entry to overlap list (> 1 entry implies an overlap) */
-			overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
-		}
-		else
-		{
-			/* remove entry from list (order independent, so swap with last) */
-			for (i=0; i<overlap_entries; i++)
-			{
-				if (overlap_list[i] == change_point[chgidx]->pbios)
-					overlap_list[i] = overlap_list[overlap_entries-1];
-			}
-			overlap_entries--;
-		}
-		/* if there are overlapping entries, decide which "type" to use */
-		/* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
-		current_type = 0;
-		for (i=0; i<overlap_entries; i++)
-			if (overlap_list[i]->type > current_type)
-				current_type = overlap_list[i]->type;
-		/* continue building up new bios map based on this information */
-		if (current_type != last_type)	{
-			if (last_type != 0)	 {
-				new_bios[new_bios_entry].size =
-					change_point[chgidx]->addr - last_addr;
-				/* move forward only if the new size was non-zero */
-				if (new_bios[new_bios_entry].size != 0)
-					if (++new_bios_entry >= E820MAX)
-						break; 	/* no more space left for new bios entries */
-			}
-			if (current_type != 0)	{
-				new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
-				new_bios[new_bios_entry].type = current_type;
-				last_addr=change_point[chgidx]->addr;
-			}
-			last_type = current_type;
-		}
-	}
-	new_nr = new_bios_entry;   /* retain count for new bios entries */
-
-	/* copy new bios mapping into original location */
-	memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
-	*pnr_map = new_nr;
-
-	return 0;
-}
-
-/*
- * Copy the BIOS e820 map into a safe place.
- *
- * Sanity-check it while we're at it..
- *
- * If we're lucky and live on a modern system, the setup code
- * will have given us a memory map that we can use to properly
- * set up memory.  If we aren't, we'll fake a memory map.
- *
- * We check to see that the memory map contains at least 2 elements
- * before we'll use it, because the detection code in setup.S may
- * not be perfect and most every PC known to man has two memory
- * regions: one from 0 to 640k, and one from 1mb up.  (The IBM
- * thinkpad 560x, for example, does not cooperate with the memory
- * detection code.)
- */
-static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
-{
-	/* Only one memory region (or negative)? Ignore it */
-	if (nr_map < 2)
-		return -1;
-
-	do {
-		unsigned long long start = biosmap->addr;
-		unsigned long long size = biosmap->size;
-		unsigned long long end = start + size;
-		unsigned long type = biosmap->type;
-
-		/* Overflow in 64 bits? Ignore the memory map. */
-		if (start > end)
-			return -1;
-
-		/*
-		 * Some BIOSes claim RAM in the 640k - 1M region.
-		 * Not right. Fix it up.
-		 */
-		if (type == E820_RAM) {
-			if (start < 0x100000ULL && end > 0xA0000ULL) {
-				if (start < 0xA0000ULL)
-					add_memory_region(start, 0xA0000ULL-start, type);
-				if (end <= 0x100000ULL)
-					continue;
-				start = 0x100000ULL;
-				size = end - start;
-			}
-		}
-		add_memory_region(start, size, type);
-	} while (biosmap++,--nr_map);
-	return 0;
-}
-
-/*
- * Do NOT EVER look at the BIOS memory size location.
- * It does not work on many machines.
- */
-#define LOWMEMSIZE()	(0x9f000)
-
-void __init setup_memory_region(void)
-{
-	char *who = "BIOS-e820";
-
-	/*
-	 * Try to copy the BIOS-supplied E820-map.
-	 *
-	 * Otherwise fake a memory map; one section from 0k->640k,
-	 * the next section from 1mb->appropriate_mem_k
-	 */
-	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
-	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
-		unsigned long mem_size;
-
-		/* compare results from other methods and take the greater */
-		if (ALT_MEM_K < EXT_MEM_K) {
-			mem_size = EXT_MEM_K;
-			who = "BIOS-88";
-		} else {
-			mem_size = ALT_MEM_K;
-			who = "BIOS-e801";
-		}
-
-		e820.nr_map = 0;
-		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
-  	}
-	printk(KERN_INFO "BIOS-provided physical RAM map:\n");
-	print_memory_map(who);
-} /* setup_memory_region */
-
-
-static inline void parse_mem_cmdline (char ** cmdline_p)
+static __init void parse_cmdline_early (char ** cmdline_p)
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
-	int usermem = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
 	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
 	for (;;) {
-		/*
-		 * "mem=nopentium" disables the 4MB page tables.
-		 * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
-		 * to <mem>, overriding the bios size.
-		 * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
-		 * <start> to <start>+<mem>, overriding the bios size.
-		 */
-		if (c == ' ' && !memcmp(from, "mem=", 4)) {
-			if (to != command_line)
-				to--;
-			if (!memcmp(from+4, "nopentium", 9)) {
-				from += 9+4;
-				clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability);
-			} else if (!memcmp(from+4, "exactmap", 8)) {
-				from += 8+4;
-				e820.nr_map = 0;
-				usermem = 1;
-			} else {
-				/* If the user specifies memory size, we
-				 * blow away any automatically generated
-				 * size
-				 */
-				unsigned long long start_at, mem_size;
+		if (c != ' ') 
+			goto next_char; 
  
-				if (usermem == 0) {
-					/* first time in: zap the whitelist
-					 * and reinitialize it with the
-					 * standard low-memory region.
-					 */
-					e820.nr_map = 0;
-					usermem = 1;
-					add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-				}
-				mem_size = memparse(from+4, &from);
-				if (*from == '@')
-					start_at = memparse(from+1, &from);
-				else {
-					start_at = HIGH_MEMORY;
-					mem_size -= HIGH_MEMORY;
-					usermem=0;
-				}
-				add_memory_region(start_at, mem_size, E820_RAM);
-			}
+		/* "acpi=off" disables both ACPI table parsing and interpreter init */
+		if (!memcmp(from, "acpi=off", 8))
+			acpi_disabled = 1;
+
+		if (!memcmp(from, "mem=", 4))
+			parse_memopt(from+4); 
+
+#ifdef CONFIG_GART_IOMMU 
+		if (!memcmp(from,"iommu=",6)) { 
+			iommu_setup(from+6); 
 		}
+#endif
+
+	next_char:
 		c = *(from++);
 		if (!c)
 			break;
@@ -539,15 +214,23 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
-	if (usermem) {
-		printk(KERN_INFO "user-defined physical RAM map:\n");
-		print_memory_map("user");
-	}
+	print_user_map(); 
 }
 
-unsigned long start_pfn, end_pfn; 
+#ifndef CONFIG_DISCONTIGMEM
+static void __init contig_initmem_init(void)
+{
+        unsigned long bootmap_size, bootmap; 
+        bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
+        bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
+        if (bootmap == -1L) 
+                panic("Cannot find bootmem map of size %ld\n",bootmap_size);
+        bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
+        e820_bootmem_free(&contig_page_data, 0, end_pfn << PAGE_SHIFT); 
+        reserve_bootmem(bootmap, bootmap_size);
+} 
+#endif
 
-extern void exception_table_check(void);
 
 void __init setup_arch(char **cmdline_p)
 {
@@ -579,7 +262,7 @@
 	data_resource.start = virt_to_phys(&_etext);
 	data_resource.end = virt_to_phys(&_edata)-1;
 
-	parse_mem_cmdline(cmdline_p);
+	parse_cmdline_early(cmdline_p);
 
 #define PFN_UP(x)	(((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
 #define PFN_DOWN(x)	((x) >> PAGE_SHIFT)
@@ -595,68 +278,12 @@
 	 */
 	start_pfn = PFN_UP(__pa_symbol(&_end));
 
-	/*
-	 * Find the highest page frame number we have available
-	 */
-	end_pfn = 0;
-	for (i = 0; i < e820.nr_map; i++) {
-		unsigned long start, end;
-		/* RAM? */
-		if (e820.map[i].type != E820_RAM)
-			continue;
-		start = PFN_UP(e820.map[i].addr);
-		end = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
-		if (start >= end)
-			continue;
-		if (end > end_pfn)
-			end_pfn = end;
-	}
-
-	if (end_pfn > MAXMEM_PFN) {
-		end_pfn = MAXMEM_PFN;
-	}
+	e820_end_of_ram();
 
 	init_memory_mapping(); 
 
-	/*
-	 * Initialize the boot-time allocator (with low memory only):
-	 */
-	bootmap_size = init_bootmem(start_pfn, end_pfn);
-
-	/*
-	 * Register fully available low RAM pages with the bootmem allocator.
-	 */
-	for (i = 0; i < e820.nr_map; i++) {
-		unsigned long curr_pfn, last_pfn, size;
- 		/*
-		 * Reserve usable low memory
-		 */
-		if (e820.map[i].type != E820_RAM)
-			continue;
-		/*
-		 * We are rounding up the start address of usable memory:
-		 */
-		curr_pfn = PFN_UP(e820.map[i].addr);
-		if (curr_pfn >= end_pfn)
-			continue;
-		/*
-		 * ... and at the end of the usable range downwards:
-		 */
-		last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size);
-
-		if (last_pfn > end_pfn)
-			last_pfn = end_pfn;
-
-		/*
-		 * .. finally, did all the rounding and playing
-		 * around just make the area go away?
-		 */
-		if (last_pfn <= curr_pfn)
-			continue;
+	contig_initmem_init(); 
 
-		size = last_pfn - curr_pfn;
-		free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
-	}
 	/*
 	 * Reserve the bootmem bitmap itself as well. We do this in two
 	 * steps (first step was init_bootmem()) because this catches
@@ -694,7 +321,7 @@
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (LOADER_TYPE && INITRD_START) {
-		if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
+		if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) {
 			reserve_bootmem(INITRD_START, INITRD_SIZE);
 			initrd_start =
 				INITRD_START ? INITRD_START + PAGE_OFFSET : 0;
@@ -704,7 +331,7 @@
 			printk(KERN_ERR "initrd extends beyond end of memory "
 			    "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
 			    (unsigned long)(INITRD_START + INITRD_SIZE),
-			    (unsigned long)(max_low_pfn << PAGE_SHIFT));
+			    (unsigned long)(end_pfn << PAGE_SHIFT));
 			initrd_start = 0;
 		}
 	}
@@ -726,6 +353,7 @@
         * the bootmem allocator) but before get_smp_config (to allow parsing
         * of MADT).
         */
+	if (!acpi_disabled)
        acpi_boot_init(*cmdline_p);
 #endif
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -737,48 +365,24 @@
 	init_apic_mappings();
 #endif
 
-
 	/*
 	 * Request address space for all standard RAM and ROM resources
 	 * and also for regions reported as reserved by the e820.
 	 */
 	probe_roms();
-	for (i = 0; i < e820.nr_map; i++) {
-		struct resource *res;
-		if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
-			continue;
-		res = alloc_bootmem_low(sizeof(struct resource));
-		switch (e820.map[i].type) {
-		case E820_RAM:	res->name = "System RAM"; break;
-		case E820_ACPI:	res->name = "ACPI Tables"; break;
-		case E820_NVS:	res->name = "ACPI Non-volatile Storage"; break;
-		default:	res->name = "reserved";
-		}
-		res->start = e820.map[i].addr;
-		res->end = res->start + e820.map[i].size - 1;
-		res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-		request_resource(&iomem_resource, res);
-		if (e820.map[i].type == E820_RAM) {
-			/*
-			 *  We dont't know which RAM region contains kernel data,
-			 *  so we try it repeatedly and let the resource manager
-			 *  test it.
-			 */
-			request_resource(res, &code_resource);
-			request_resource(res, &data_resource);
-		}
-	}
+	e820_reserve_resources(); 
+
 	request_resource(&iomem_resource, &vram_resource);
 
 	/* request I/O space for devices used on all i[345]86 PCs */
 	for (i = 0; i < STANDARD_IO_RESOURCES; i++)
 		request_resource(&ioport_resource, standard_io_resources+i);
 
-	/* Tell the PCI layer not to allocate too close to the RAM area.. */
-	/* ??? move this up on x86-64 */
-	low_mem_size = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff;
-	if (low_mem_size > pci_mem_start)
-		pci_mem_start = low_mem_size;
+	pci_mem_start = IOMAP_START; 
+
+#ifdef CONFIG_GART_IOMMU
+       iommu_hole_init();
+#endif
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
@@ -919,11 +523,14 @@
 
 	/* Intel-defined flags: level 0x00000001 */
 	if ( c->cpuid_level >= 0x00000001 ) {
-		cpuid(0x00000001, &tfms, &junk, &junk,
+		__u32 misc;
+		cpuid(0x00000001, &tfms, &misc, &junk,
 		      &c->x86_capability[0]);
 		c->x86 = (tfms >> 8) & 15;
 		c->x86_model = (tfms >> 4) & 15;
 		c->x86_mask = tfms & 15;
+		if (c->x86_capability[0] & (1<<19)) 
+       		c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
 	} else {
 		/* Have CPUID level 0 only - unheard of */
 		c->x86 = 4;
@@ -946,12 +553,6 @@
 	}
 
 
-	printk(KERN_DEBUG "CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n",
-	       c->x86_capability[0],
-	       c->x86_capability[1],
-	       c->x86_capability[2],
-	       c->x86_vendor);
-
 	/*
 	 * Vendor-specific initialization.  In this section we
 	 * canonicalize the feature flags, meaning if there are
@@ -1017,11 +618,6 @@
 			boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
 	}
 
-	printk(KERN_DEBUG "CPU:             Common caps: %08x %08x %08x %08x\n",
-	       boot_cpu_data.x86_capability[0],
-	       boot_cpu_data.x86_capability[1],
-	       boot_cpu_data.x86_capability[2],
-	       boot_cpu_data.x86_capability[3]);
 }
  
 
@@ -1147,8 +743,8 @@
 }
 
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
+	.start =c_start,
+	.next =	c_next,
+	.stop =	c_stop,
+	.show =	show_cpuinfo,
 };
diff -Nru a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
--- a/arch/x86_64/kernel/setup64.c	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/kernel/setup64.c	Tue Oct 15 20:29:15 2002
@@ -20,10 +20,11 @@
 #include <asm/mmu_context.h>
 #include <asm/smp.h>
 #include <asm/i387.h>
+#include <asm/percpu.h>
 
 char x86_boot_params[2048] __initdata = {0,};
 
-static unsigned long cpu_initialized __initdata = 0;
+unsigned long cpu_initialized __initdata = 0;
 
 struct x8664_pda cpu_pda[NR_CPUS] __cacheline_aligned; 
 
@@ -34,11 +35,15 @@
 
 extern unsigned char __per_cpu_start[], __per_cpu_end[]; 
 
-struct desc_ptr gdt_descr = { 0 /* filled in */, (unsigned long) gdt_table }; 
+extern struct desc_ptr cpu_gdt_descr[];
 struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table }; 
 
 char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned;
 
+#ifndef  __GENERIC_PER_CPU
+
+unsigned long __per_cpu_offset[NR_CPUS];
+
 void __init setup_per_cpu_areas(void)
 { 
 	unsigned long size, i;
@@ -52,10 +57,15 @@
 	ptr = alloc_bootmem(size * NR_CPUS);
 
 	for (i = 0; i < NR_CPUS; i++, ptr += size) {
-		cpu_pda[cpu_logical_map(i)].cpudata_offset = ptr - __per_cpu_start;
+		/* hide this from the compiler to avoid problems */ 
+		unsigned long offset;
+		asm("subq %[b],%0" : "=r" (offset) : "0" (ptr), [b] "r" (&__per_cpu_start));
+		__per_cpu_offset[i] = offset;
+		cpu_pda[i].cpudata_offset = offset;
 		memcpy(ptr, __per_cpu_start, size);
 	}
 } 
+#endif
 
 void pda_init(int cpu)
 { 
@@ -111,38 +121,48 @@
 void __init cpu_init (void)
 {
 #ifdef CONFIG_SMP
-	int nr = stack_smp_processor_id();
+	int cpu = stack_smp_processor_id();
 #else
-	int nr = smp_processor_id();
+	int cpu = smp_processor_id();
 #endif
-	struct tss_struct * t = &init_tss[nr];
+	struct tss_struct * t = &init_tss[cpu];
 	unsigned long v; 
 	char *estacks; 
 	struct task_struct *me;
 
 	/* CPU 0 is initialised in head64.c */
-	if (nr != 0) {
+	if (cpu != 0) {
 		estacks = (char *)__get_free_pages(GFP_ATOMIC, 0); 
 		if (!estacks)
-			panic("Can't allocate exception stacks for CPU %d\n",nr);
-		pda_init(nr);  
+			panic("Can't allocate exception stacks for CPU %d\n",cpu);
+		pda_init(cpu);  
 	} else 
 		estacks = boot_exception_stacks; 
 
 	me = current;
 
-	if (test_and_set_bit(nr, &cpu_initialized))
-		panic("CPU#%d already initialized!\n", nr);
+	if (test_and_set_bit(cpu, &cpu_initialized))
+		panic("CPU#%d already initialized!\n", cpu);
 
-	printk("Initializing CPU#%d\n", nr);
+	printk("Initializing CPU#%d\n", cpu);
 
 		clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
 
-	gdt_descr.size = (__u8*) gdt_end - (__u8*)gdt_table; 
-
-	__asm__ __volatile__("lgdt %0": "=m" (gdt_descr));
+	/*
+	 * Initialize the per-CPU GDT with the boot GDT,
+	 * and set up the GDT descriptor:
+	 */
+	if (cpu) {
+		memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE);
+	}	
+
+	cpu_gdt_descr[cpu].size = GDT_SIZE;
+	cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu];
+	__asm__ __volatile__("lgdt %0": "=m" (cpu_gdt_descr[cpu]));
 	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
 
+	memcpy(me->thread.tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8);
+
 	/*
 	 * Delete NT
 	 */
@@ -177,14 +197,16 @@
 		estacks += EXCEPTION_STKSZ;
 	}
 
+	t->io_map_base = INVALID_IO_BITMAP_OFFSET;
+
 	atomic_inc(&init_mm.mm_count);
 	me->active_mm = &init_mm;
 	if (me->mm)
 		BUG();
-	enter_lazy_tlb(&init_mm, me, nr);
+	enter_lazy_tlb(&init_mm, me, cpu);
 
-	set_tss_desc(nr, t);
-	load_TR(nr);
+	set_tss_desc(cpu, t);
+	load_TR_desc();
 	load_LDT(&init_mm.context);
 
 	/*
diff -Nru a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
--- a/arch/x86_64/kernel/signal.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/kernel/signal.c	Tue Oct 15 20:29:12 2002
@@ -50,11 +50,11 @@
 		return -EFAULT;
 	sigdelsetmask(&newset, ~_BLOCKABLE);
 
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	saveset = current->blocked;
 	current->blocked = newset;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 #if DEBUG_SIG
 	printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
 		saveset, newset, &regs, regs.rip);
@@ -153,10 +153,10 @@
 	} 
 
 	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sigmask_lock);
+	spin_lock_irq(&current->sig->siglock);
 	current->blocked = set;
 	recalc_sigpending();
-	spin_unlock_irq(&current->sigmask_lock);
+	spin_unlock_irq(&current->sig->siglock);
 	
 	if (restore_sigcontext(&regs, &frame->uc.uc_mcontext, &eax)) { 
 		goto badframe;
@@ -390,11 +390,11 @@
 		ka->sa.sa_handler = SIG_DFL;
 
 	if (!(ka->sa.sa_flags & SA_NODEFER)) {
-		spin_lock_irq(&current->sigmask_lock);
+		spin_lock_irq(&current->sig->siglock);
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
 		sigaddset(&current->blocked,sig);
 		recalc_sigpending();
-		spin_unlock_irq(&current->sigmask_lock);
+		spin_unlock_irq(&current->sig->siglock);
 	}
 }
 
diff -Nru a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
--- a/arch/x86_64/kernel/smp.c	Tue Oct 15 20:29:14 2002
+++ b/arch/x86_64/kernel/smp.c	Tue Oct 15 20:29:14 2002
@@ -15,12 +15,14 @@
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
+#include <linux/smp.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
+#include <asm/hardirq.h>
 
 /*
  * the following functions deal with sending IPIs between CPUs.
@@ -75,7 +77,7 @@
 	 * we get an APIC send error if we try to broadcast.
 	 * thus we have to avoid sending IPIs in this case.
 	 */
-	if (smp_num_cpus > 1)
+	if (num_online_cpus() > 1)
 		__send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
 }
 
@@ -224,7 +226,7 @@
 	clear_bit(cpu, &flush_cpumask);
 
 out:
-	put_cpu();
+	put_cpu_no_resched();
 }
 
 static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
@@ -399,7 +401,7 @@
  */
 {
 	struct call_data_struct data;
-	int cpus = smp_num_cpus-1;
+	int cpus = num_online_cpus()-1;
 
 	if (!cpus)
 		return 0;
@@ -448,7 +450,6 @@
 void smp_send_stop(void)
 {
 	smp_call_function(stop_this_cpu, NULL, 1, 0);
-	smp_num_cpus = 1;
 
 	local_irq_disable();
 	disable_local_APIC();
@@ -481,7 +482,9 @@
 	/*
 	 * At this point the info structure may be out of scope unless wait==1
 	 */
+	irq_enter();
 	(*func)(info);
+	irq_exit();
 	if (wait) {
 		mb();
 		atomic_inc(&call_data->finished);
diff -Nru a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
--- a/arch/x86_64/kernel/smpboot.c	Tue Oct 15 20:29:23 2002
+++ b/arch/x86_64/kernel/smpboot.c	Tue Oct 15 20:29:23 2002
@@ -31,6 +31,7 @@
  *		Tigran Aivazian	:	fixed "0.00 in /proc/uptime on SMP" bug.
  *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs
  *	Andi Kleen		:	Changed for SMP boot into long mode.
+ *		Rusty Russell	:	Hacked into shape for new "hotplug" boot process. 
  */
 
 #include <linux/config.h>
@@ -50,12 +51,6 @@
 #include <asm/kdebug.h>
 #include <asm/tlbflush.h>
 
-/* Setup configured maximum number of CPUs to activate */
-static int max_cpus = -1;
-
-/* Total count of live CPUs */
-int smp_num_cpus = 1;
-
 /* Bitmask of currently online CPUs */
 unsigned long cpu_online_map;
 
@@ -65,7 +60,8 @@
 volatile int x86_cpu_to_apicid[NR_CPUS];
 
 static volatile unsigned long cpu_callin_map;
-static volatile unsigned long cpu_callout_map;
+volatile unsigned long cpu_callout_map;
+static unsigned long smp_commenced_mask;
 
 /* Per CPU bogomips and other parameters */
 struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
@@ -74,33 +70,6 @@
 int smp_threads_ready;
 
 /*
- * Setup routine for controlling SMP activation
- *
- * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
- * activation entirely (the MPS table probe still happens, though).
- *
- * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
- * greater than 0, limits the maximum number of CPUs activated in
- * SMP mode to <NUM>.
- */
-
-static int __init nosmp(char *str)
-{
-	max_cpus = 0;
-	return 1;
-}
-
-__setup("nosmp", nosmp);
-
-static int __init maxcpus(char *str)
-{
-	get_option(&str, &max_cpus);
-	return 1;
-}
-
-__setup("maxcpus=", maxcpus);
-
-/*
  * Trampoline 80x86 program as an array.
  */
 
@@ -117,7 +86,7 @@
 static unsigned long __init setup_trampoline(void)
 {
 	extern volatile __u32 tramp_gdt_ptr; 
-	tramp_gdt_ptr = __pa_symbol(&gdt_table); 
+	tramp_gdt_ptr = __pa_symbol(&cpu_gdt_table); 
 	memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
 	return virt_to_phys(trampoline_base);
 }
@@ -142,7 +111,7 @@
  * a given CPU
  */
 
-void __init smp_store_cpu_info(int id)
+static void __init smp_store_cpu_info(int id)
 {
 	struct cpuinfo_x86 *c = cpu_data + id;
 
@@ -151,29 +120,6 @@
 }
 
 /*
- * Architecture specific routine called by the kernel just before init is
- * fired off. This allows the BP to have everything in order [we hope].
- * At the end of this all the APs will hit the system scheduling and off
- * we go. Each AP will load the system gdt's and jump through the kernel
- * init into idle(). At this point the scheduler will one day take over
- * and give them jobs to do. smp_callin is a standard routine
- * we use to track CPUs as they power up.
- */
-
-static atomic_t smp_commenced = ATOMIC_INIT(0);
-
-void __init smp_commence(void)
-{
-	/*
-	 * Lets the callins below out of their loop.
-	 */
-	Dprintk("Setting commenced=1, go go go\n");
-
-	wmb();
-	atomic_set(&smp_commenced,1);
-}
-
-/*
  * TSC synchronization.
  *
  * We first check wether all CPUs have their TSC's synchronized,
@@ -189,11 +135,6 @@
 
 extern unsigned int fast_gettimeoffset_quotient;
 
-static inline unsigned long long div64 (unsigned long long a, unsigned long b)
-{
-	return a/b;
-}
-
 static void __init synchronize_tsc_bp (void)
 {
 	int i;
@@ -202,10 +143,11 @@
 	long long delta;
 	unsigned long one_usec;
 	int buggy = 0;
+	extern unsigned cpu_khz;
 
-	printk("checking TSC synchronization across CPUs: ");
+	printk("checking TSC synchronization across %u CPUs: ",num_booting_cpus());
 
-	one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2);
+	one_usec = cpu_khz; 
 
 	atomic_set(&tsc_start_flag, 1);
 	wmb();
@@ -224,7 +166,7 @@
 		/*
 		 * all APs synchronize but they loop on '== num_cpus'
 		 */
-		while (atomic_read(&tsc_count_start) != smp_num_cpus-1) mb();
+		while (atomic_read(&tsc_count_start) != num_booting_cpus()-1) mb();
 		atomic_set(&tsc_count_stop, 0);
 		wmb();
 		/*
@@ -242,21 +184,26 @@
 		/*
 		 * Wait for all APs to leave the synchronization point:
 		 */
-		while (atomic_read(&tsc_count_stop) != smp_num_cpus-1) mb();
+		while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1) mb();
 		atomic_set(&tsc_count_start, 0);
 		wmb();
 		atomic_inc(&tsc_count_stop);
 	}
 
 	sum = 0;
-	for (i = 0; i < smp_num_cpus; i++) {
+	for (i = 0; i < NR_CPUS; i++) {
+		if (test_bit(i, &cpu_callout_map)) {
 		t0 = tsc_values[i];
 		sum += t0;
 	}
-	avg = div64(sum, smp_num_cpus);
+	}
+	avg = sum / num_booting_cpus();
 
 	sum = 0;
-	for (i = 0; i < smp_num_cpus; i++) {
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!test_bit(i, &cpu_callout_map))
+			continue;
+
 		delta = tsc_values[i] - avg;
 		if (delta < 0)
 			delta = -delta;
@@ -269,7 +216,7 @@
 				buggy = 1;
 				printk("\n");
 			}
-			realdelta = div64(delta, one_usec);
+			realdelta = delta / one_usec;
 			if (tsc_values[i] < avg)
 				realdelta = -realdelta;
 
@@ -288,7 +235,7 @@
 	int i;
 
 	/*
-	 * smp_num_cpus is not necessarily known at the time
+	 * Not every cpu is online at the time
 	 * this gets called, so we first wait for the BP to
 	 * finish SMP initialization:
 	 */
@@ -296,14 +243,14 @@
 
 	for (i = 0; i < NR_LOOPS; i++) {
 		atomic_inc(&tsc_count_start);
-		while (atomic_read(&tsc_count_start) != smp_num_cpus) mb();
+		while (atomic_read(&tsc_count_start) != num_booting_cpus()) mb();
 
 		rdtscll(tsc_values[smp_processor_id()]);
 		if (i == NR_LOOPS-1)
 			write_tsc(0, 0);
 
 		atomic_inc(&tsc_count_stop);
-		while (atomic_read(&tsc_count_stop) != smp_num_cpus) mb();
+		while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb();
 	}
 }
 #undef NR_LOOPS
@@ -330,7 +277,7 @@
 	 */
 	phys_id = GET_APIC_ID(apic_read(APIC_ID));
 	cpuid = smp_processor_id();
-	if (test_and_set_bit(cpuid, &cpu_online_map)) {
+	if (test_and_set_bit(cpuid, &cpu_callin_map)) {
 		printk("huh, phys CPU#%d, CPU#%d already present??\n",
 					phys_id, cpuid);
 		BUG();
@@ -374,7 +321,7 @@
 	Dprintk("CALLIN, before setup_local_APIC().\n");
 	setup_local_APIC();
 
-	sti();
+	local_irq_enable();
 
 #ifdef CONFIG_MTRR
 	/*
@@ -388,6 +335,8 @@
 	calibrate_delay();
 	Dprintk("Stack at about %p\n",&cpuid);
 
+	disable_APIC_timer();
+
 	/*
 	 * Save our processor parameters
 	 */
@@ -416,9 +365,6 @@
  */
 int __init start_secondary(void *unused)
 {
-	int var;
-	printk("rsp %p\n",&var);
-
 	/*
 	 * Dont put anything before smp_callin(), SMP
 	 * booting is too fragile that we want to limit the
@@ -426,14 +372,35 @@
 	 */
 	cpu_init();
 	smp_callin();
-	while (!atomic_read(&smp_commenced))
+
+	Dprintk("cpu %d: waiting for commence\n", smp_processor_id()); 
+	while (!test_bit(smp_processor_id(), &smp_commenced_mask))
 		rep_nop();
+
+	Dprintk("cpu %d: setting up apic clock\n", smp_processor_id()); 	
+	setup_secondary_APIC_clock();
+
+	Dprintk("cpu %d: enabling apic timer\n", smp_processor_id()); 
+
+	if (nmi_watchdog == NMI_IO_APIC) {
+		disable_8259A_irq(0);
+		enable_NMI_through_LVT0(NULL);
+		enable_8259A_irq(0);
+	}
+
+
+	enable_APIC_timer(); 
+
 	/*
 	 * low-memory mappings have been cleared, flush them from
 	 * the local TLBs too.
 	 */
 	local_flush_tlb();
 
+	Dprintk("cpu %d eSetting cpu_online_map\n", smp_processor_id()); 
+	set_bit(smp_processor_id(), &cpu_online_map);
+	wmb();
+	
 	return cpu_idle();
 }
 
@@ -469,7 +436,7 @@
 	 * don't care about the rip and regs settings since
 	 * we'll never reschedule the forked task.
 	 */
-	return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0);
+	return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL);
 }
 
 #if APIC_DEBUG
@@ -510,91 +477,17 @@
 }
 #endif
 
-static void __init do_boot_cpu (int apicid)
+static int __init wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip)
 {
-	struct task_struct *idle;
-	unsigned long send_status, accept_status, boot_status, maxlvt;
-	int timeout, num_starts, j, cpu;
-	unsigned long start_eip;
-
-	printk("do_boot_cpu cpucount = %d\n", cpucount); 
-
-	cpu = ++cpucount;
-	/*
-	 * We can't use kernel_thread since we must avoid to
-	 * reschedule the child.
-	 */
-	idle = fork_by_hand();
-	if (IS_ERR(idle))
-		panic("failed fork for CPU %d", cpu);
-
-	/*
-	 * We remove it from the pidhash and the runqueue
-	 * once we got the process:
-	 */
-	init_idle(idle,cpu);
-
-	x86_cpu_to_apicid[cpu] = apicid;
-	x86_apicid_to_cpu[apicid] = cpu;
-	idle->thread.rip = (unsigned long)start_secondary;
-//	idle->thread.rsp = (unsigned long)idle->thread_info + THREAD_SIZE - 512;
-
-	unhash_process(idle);
-
-	cpu_pda[cpu].pcurrent = idle;
-
-	/* start_eip had better be page-aligned! */
-	start_eip = setup_trampoline();
-
-	init_rsp = (unsigned long)idle->thread_info + PAGE_SIZE + 1024;
-	initial_code = initialize_secondary;
-
-	printk("Booting processor %d/%d rip %lx rsp %lx rsp2 %lx\n", cpu, apicid, 
-	       start_eip, idle->thread.rsp, init_rsp);
-
-	/*
-	 * This grunge runs the startup process for
-	 * the targeted processor.
-	 */
-
-	atomic_set(&init_deasserted, 0);
-
-	Dprintk("Setting warm reset code and vector.\n");
-
-	CMOS_WRITE(0xa, 0xf);
-	local_flush_tlb();
-	Dprintk("1.\n");
-	*((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4;
-	Dprintk("2.\n");
-	*((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf;
-	Dprintk("3.\n");
-
-	/*
-	 * Be paranoid about clearing APIC errors.
-	 */
-	if (APIC_INTEGRATED(apic_version[apicid])) {
-		apic_read_around(APIC_SPIV);
-		apic_write(APIC_ESR, 0);
-		apic_read(APIC_ESR);
-	}
-
-	/*
-	 * Status is now clean
-	 */
-	send_status = 0;
-	accept_status = 0;
-	boot_status = 0;
-
-	/*
-	 * Starting actual IPI sequence...
-	 */
+	unsigned long send_status = 0, accept_status = 0;
+	int maxlvt, timeout, num_starts, j;
 
 	Dprintk("Asserting INIT.\n");
 
 	/*
 	 * Turn INIT on target chip
 	 */
-	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
 
 	/*
 	 * Send IPI
@@ -615,7 +508,7 @@
 	Dprintk("Deasserting INIT.\n");
 
 	/* Target chip */
-	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+	apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
 
 	/* Send IPI */
 	apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
@@ -634,10 +527,9 @@
 	 * Should we send STARTUP IPIs ?
 	 *
 	 * Determine this based on the APIC version.
-	 * If we don't have an integrated APIC, don't
-	 * send the STARTUP IPIs.
+	 * If we don't have an integrated APIC, don't send the STARTUP IPIs.
 	 */
-	if (APIC_INTEGRATED(apic_version[apicid]))
+	if (APIC_INTEGRATED(apic_version[phys_apicid]))
 		num_starts = 2;
 	else
 		num_starts = 0;
@@ -661,12 +553,12 @@
 		 */
 
 		/* Target chip */
-		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+		apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
 
 		/* Boot on the stack */
 		/* Kick the second */
 		apic_write_around(APIC_ICR, APIC_DM_STARTUP
-					| (start_eip >> 12));
+					| (start_rip >> 12));
 
 		/*
 		 * Give the other CPU some time to accept the IPI.
@@ -705,7 +597,89 @@
 	if (accept_status)
 		printk("APIC delivery error (%lx).\n", accept_status);
 
-	if (!send_status && !accept_status) {
+	return (send_status | accept_status);
+}
+
+extern unsigned long cpu_initialized;
+
+static void __init do_boot_cpu (int apicid)
+{
+	struct task_struct *idle;
+	unsigned long boot_error;
+	int timeout, cpu;
+	unsigned long start_rip;
+
+	cpu = ++cpucount;
+	/*
+	 * We can't use kernel_thread since we must avoid to
+	 * reschedule the child.
+	 */
+	idle = fork_by_hand();
+	if (IS_ERR(idle))
+		panic("failed fork for CPU %d", cpu);
+
+	/*
+	 * We remove it from the pidhash and the runqueue
+	 * once we got the process:
+	 */
+	init_idle(idle,cpu);
+
+	x86_cpu_to_apicid[cpu] = apicid;
+	x86_apicid_to_cpu[apicid] = cpu;
+	idle->thread.rip = (unsigned long)start_secondary;
+//	idle->thread.rsp = (unsigned long)idle->thread_info + THREAD_SIZE - 512;
+
+	unhash_process(idle);
+
+	cpu_pda[cpu].pcurrent = idle;
+
+	/* start_eip had better be page-aligned! */
+	start_rip = setup_trampoline();
+
+	init_rsp = (unsigned long)idle->thread_info + PAGE_SIZE + 1024;
+	init_tss[cpu].rsp0 = init_rsp;
+	initial_code = initialize_secondary;
+
+	printk("Booting processor %d/%d rip %lx rsp %lx rsp2 %lx\n", cpu, apicid, 
+	       start_rip, idle->thread.rsp, init_rsp);
+
+	/*
+	 * This grunge runs the startup process for
+	 * the targeted processor.
+	 */
+
+	atomic_set(&init_deasserted, 0);
+
+	Dprintk("Setting warm reset code and vector.\n");
+
+	CMOS_WRITE(0xa, 0xf);
+	local_flush_tlb();
+	Dprintk("1.\n");
+	*((volatile unsigned short *) phys_to_virt(0x469)) = start_rip >> 4;
+	Dprintk("2.\n");
+	*((volatile unsigned short *) phys_to_virt(0x467)) = start_rip & 0xf;
+	Dprintk("3.\n");
+
+	/*
+	 * Be paranoid about clearing APIC errors.
+	 */
+	if (APIC_INTEGRATED(apic_version[apicid])) {
+		apic_read_around(APIC_SPIV);
+		apic_write(APIC_ESR, 0);
+		apic_read(APIC_ESR);
+	}
+
+	/*
+	 * Status is now clean
+	 */
+	boot_error = 0;
+
+	/*
+	 * Starting actual IPI sequence...
+	 */
+	boot_error = wakeup_secondary_via_INIT(apicid, start_rip); 
+
+	if (!boot_error) {
 		/*
 		 * allow APs to start initializing.
 		 */
@@ -729,7 +703,7 @@
 			print_cpu_info(&cpu_data[cpu]);
 			Dprintk("CPU has booted.\n");
 		} else {
-			boot_status = 1;
+			boot_error = 1;
 			if (*((volatile unsigned char *)phys_to_virt(8192))
 					== 0xA5)
 				/* trampoline started but...? */
@@ -742,14 +716,16 @@
 #endif
 		}
 	}
-	if (send_status || accept_status || boot_status) {
+	if (boot_error) {
 		x86_cpu_to_apicid[cpu] = -1;
 		x86_apicid_to_cpu[apicid] = -1;
+		clear_bit(cpu, &cpu_callout_map); /* was set here (do_boot_cpu()) */
+		clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */
 		cpucount--;
 	}
 
 	/* mark "stuck" area as not stuck */
-	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
+	*((volatile unsigned *)phys_to_virt(8192)) = 0;
 }
 
 cycles_t cacheflush_time;
@@ -804,7 +780,7 @@
 extern int prof_old_multiplier[NR_CPUS];
 extern int prof_counter[NR_CPUS];
 
-void __init smp_boot_cpus(void)
+static void __init smp_boot_cpus(unsigned int max_cpus)
 {
 	int apicid, cpu;
 
@@ -835,12 +811,18 @@
 	 * We have the boot CPU online for sure.
 	 */
 	set_bit(0, &cpu_online_map);
+	set_bit(0, &cpu_callout_map);
 	x86_apicid_to_cpu[boot_cpu_id] = 0;
 	x86_cpu_to_apicid[0] = boot_cpu_id;
-	global_irq_holder = NO_PROC_ID;
 	current_thread_info()->cpu = 0;
 	smp_tune_scheduling();
 
+	if (!test_bit(hard_smp_processor_id(), &phys_cpu_present_map)) {
+		printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
+		       hard_smp_processor_id());
+		phys_cpu_present_map |= (1 << hard_smp_processor_id());
+	}
+
 	/*
 	 * If we couldnt find an SMP configuration at boot time,
 	 * get out of here now!
@@ -849,11 +831,11 @@
 		printk(KERN_NOTICE "SMP motherboard not detected.\n");
 		io_apic_irqs = 0;
 		cpu_online_map = phys_cpu_present_map = 1;
-		smp_num_cpus = 1;
+		phys_cpu_present_map = 1;
 		if (APIC_init_uniprocessor())
 			printk(KERN_NOTICE "Local APIC not detected."
 					   " Using dummy APIC emulation.\n");
-		goto smp_done;
+		return;
 	}
 
 	/*
@@ -875,8 +857,8 @@
 		printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
 		io_apic_irqs = 0;
 		cpu_online_map = phys_cpu_present_map = 1;
-		smp_num_cpus = 1;
-		goto smp_done;
+		phys_cpu_present_map = 1;
+		return;
 	}
 
 	verify_local_APIC();
@@ -889,8 +871,8 @@
 		printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
 		io_apic_irqs = 0;
 		cpu_online_map = phys_cpu_present_map = 1;
-		smp_num_cpus = 1;
-		goto smp_done;
+		phys_cpu_present_map = 1;
+		return;
 	}
 
 	connect_bsp_APIC();
@@ -941,7 +923,7 @@
 		 */
 		CMOS_WRITE(0, 0xf);
 
-		*((volatile long *) phys_to_virt(0x467)) = 0;
+		*((volatile int *) phys_to_virt(0x467)) = 0;
 	}
 
 	/*
@@ -954,7 +936,7 @@
 	} else {
 		unsigned long bogosum = 0;
 		for (cpu = 0; cpu < NR_CPUS; cpu++)
-			if (cpu_online_map & (1<<cpu))
+			if (cpu_callout_map & (1<<cpu))
 				bogosum += cpu_data[cpu].loops_per_jiffy;
 		printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
 			cpucount+1,
@@ -962,7 +944,6 @@
 			(bogosum/(5000/HZ))%100);
 		Dprintk("Before bogocount - setting activated=1.\n");
 	}
-	smp_num_cpus = cpucount + 1;
 
 	Dprintk("Boot done.\n");
 
@@ -973,17 +954,43 @@
 	if (!skip_ioapic_setup && nr_ioapics)
 		setup_IO_APIC();
 
-	/*
-	 * Set up all local APIC timers in the system:
-	 */
-	setup_APIC_clocks();
+	setup_boot_APIC_clock();
 
 	/*
 	 * Synchronize the TSC with the AP
 	 */
 	if (cpu_has_tsc && cpucount)
 		synchronize_tsc_bp();
+}
+
+/* These are wrappers to interface to the new boot process.  Someone
+   who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+	smp_boot_cpus(max_cpus);
+}
+
+int __devinit __cpu_up(unsigned int cpu)
+{
+	/* This only works at boot for x86.  See "rewrite" above. */
+	if (test_bit(cpu, &smp_commenced_mask))
+		return -ENOSYS;
 
-smp_done:
+	/* In case one didn't come up */
+	if (!test_bit(cpu, &cpu_callin_map))
+		return -EIO;
+
+	/* Unleash the CPU! */
+	Dprintk("waiting for cpu %d\n", cpu);
+
+	set_bit(cpu, &smp_commenced_mask);
+	while (!test_bit(cpu, &cpu_online_map))
+		mb();
+	return 0;
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
 	zap_low_mappings();
 }
+
diff -Nru a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
--- a/arch/x86_64/kernel/time.c	Tue Oct 15 20:29:19 2002
+++ b/arch/x86_64/kernel/time.c	Tue Oct 15 20:29:19 2002
@@ -1,538 +1,373 @@
 /*
  *  linux/arch/x86-64/kernel/time.c
  *
- *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *  "High Precision Event Timer" based timekeeping.
+ *
+ *  Copyright (c) 1991,1992,1995  Linus Torvalds
+ *  Copyright (c) 1994  Alan Modra
+ *  Copyright (c) 1995  Markus Kuhn
+ *  Copyright (c) 1996  Ingo Molnar
+ *  Copyright (c) 1998  Andrea Arcangeli
+ *  Copyright (c) 2002  Vojtech Pavlik
  *
- * This file contains the PC-specific time handling details:
- * reading the RTC at bootup, etc..
- * 1994-07-02    Alan Modra
- *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- * 1995-03-26    Markus Kuhn
- *      fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
- *      precision CMOS clock update
- * 1996-05-03    Ingo Molnar
- *      fixed time warps in do_[slow|fast]_gettimeoffset()
- * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
- *		"A Kernel Model for Precision Timekeeping" by Dave Mills
- * 1998-09-05    (Various)
- *	More robust do_fast_gettimeoffset() algorithm implemented
- *	(works with APM, Cyrix 6x86MX and Centaur C6),
- *	monotonic gettimeofday() with fast_get_timeoffset(),
- *	drift-proof precision TSC calibration on boot
- *	(C. Scott Ananian <cananian@alumni.princeton.edu>, Andrew D.
- *	Balsa <andrebalsa@altern.org>, Philip Gladstone <philip@raptor.com>;
- *	ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
- * 1998-12-16    Andrea Arcangeli
- *	Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
- *	because was not accounting lost_ticks.
- * 1998-12-24 Copyright (C) 1998  Andrea Arcangeli
- *	Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
- *	serialize accesses to xtime/lost_ticks).
  */
 
-#include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/device.h>
-
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/irq.h>
-#include <asm/msr.h>
-#include <asm/delay.h>
-#include <asm/mpspec.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
 #include <linux/mc146818rtc.h>
-#include <linux/timex.h>
-#include <linux/config.h>
-
-#include <asm/fixmap.h>
-
 #include <linux/irq.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <asm/vsyscall.h>
+#include <asm/timex.h>
 
-unsigned int cpu_khz;	/* Detected as we calibrate the TSC */
-
-/* Number of usecs that the last interrupt was delayed */
-int __delay_at_last_interrupt __section_delay_at_last_interrupt;
-
-unsigned int __last_tsc_low __section_last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
-
-/* Cached *multiplier* to convert TSC counts to microseconds.
- * (see the equation below).
- * Equal to 2^32 * (1 / (clocks per usec) ).
- * Initialized in time_init.
- */
-unsigned int __fast_gettimeoffset_quotient __section_fast_gettimeoffset_quotient;
+u64 jiffies_64; 
 
 extern rwlock_t xtime_lock;
-struct timeval __xtime __section_xtime;
-unsigned long __wall_jiffies __section_wall_jiffies;
-struct timezone __sys_tz __section_sys_tz;
-volatile unsigned long __jiffies __section_jiffies;
- 
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
 
-inline unsigned long do_gettimeoffset(void)
-{
-	register unsigned int eax, edx;
-
-	/* Read the Time Stamp Counter */
+unsigned int cpu_khz;					/* TSC clocks / usec, not used here */
+unsigned long hpet_period;				/* fsecs / HPET clock */
+unsigned long hpet_tick;				/* HPET clocks / interrupt */
+int hpet_report_lost_ticks;				/* command line option */
 
-	rdtsc(eax,edx);
+struct hpet_data __hpet __section_hpet;			/* address, quotient, trigger, hz */
 
-	/* .. relative to previous jiffy (32 bits is enough) */
-	eax -= last_tsc_low;	/* tsc_low delta */
+volatile unsigned long __jiffies __section_jiffies;
+unsigned long __wall_jiffies __section_wall_jiffies;
+struct timespec __xtime __section_xtime;
+struct timezone __sys_tz __section_sys_tz;
 
-	/*
-         * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
-         *             = (tsc_low delta) * (usecs_per_clock)
-         *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
-	 *
-	 * Using a mull instead of a divl saves up to 31 clock cycles
-	 * in the critical path.
+/*
+ * do_gettimeoffset() returns microseconds since last timer interrupt was
+ * triggered by hardware. A memory read of HPET is slower than a register read
+ * of TSC, but much more reliable. It's also synchronized to the timer
+ * interrupt. Note that do_gettimeoffset() may return more than hpet_tick, if a
+ * timer interrupt has happened already, but hpet.trigger wasn't updated yet.
+ * This is not a problem, because jiffies hasn't updated either. They are bound
+ * together by xtime_lock.
          */
 
-	__asm__("mull %2"
-		:"=a" (eax), "=d" (edx)
-		:"rm" (fast_gettimeoffset_quotient),
-		 "0" (eax));
+static spinlock_t time_offset_lock = SPIN_LOCK_UNLOCKED;
+static unsigned long timeoffset = 0;
 
-	/* our adjusted time offset in microseconds */
-	return delay_at_last_interrupt + edx;
+inline unsigned int do_gettimeoffset(void)
+{
+	unsigned long t;
+	rdtscll(t);	
+	return (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset;
 }
 
-#define TICK_SIZE tick
-
-spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
-
-extern spinlock_t i8259A_lock;
-
 /*
- * This version of gettimeofday has microsecond resolution
- * and better than microsecond precision on fast x86 machines with TSC.
+ * This version of gettimeofday() has microsecond resolution and better than
+ * microsecond precision, as we're using at least a 10 MHz (usually 14.31818
+ * MHz) HPET timer.
  */
+
 void do_gettimeofday(struct timeval *tv)
 {
-	unsigned long flags;
-	unsigned long usec, sec;
+	unsigned long flags, t;
+ 	unsigned int sec, usec;
 
 	read_lock_irqsave(&xtime_lock, flags);
-	usec = do_gettimeoffset();
-	{
-		unsigned long lost = jiffies - wall_jiffies;
-		if (lost)
-			usec += lost * (1000000 / HZ);
-	}
+	spin_lock(&time_offset_lock);
+
 	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
-	read_unlock_irqrestore(&xtime_lock, flags);
+	usec = xtime.tv_nsec / 1000;
 
-	while (usec >= 1000000) {
-		usec -= 1000000;
-		sec++;
-	}
+	t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset();
+	if (t > timeoffset) timeoffset = t;
+	usec += timeoffset;
+
+	spin_unlock(&time_offset_lock);
+	read_unlock_irqrestore(&xtime_lock, flags);
 
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
+	tv->tv_sec = sec + usec / 1000000;
+	tv->tv_usec = usec % 1000000;
 }
 
+/*
+ * settimeofday() first undoes the correction that gettimeofday would do
+ * on the time, and then saves it. This is ugly, but has been like this for
+ * ages already.
+ */
+
 void do_settimeofday(struct timeval *tv)
 {
 	write_lock_irq(&xtime_lock);
 	vxtime_lock();
-	/*
-	 * This is revolting. We need to set "xtime" correctly. However, the
-	 * value in this location is the value at the most recent update of
-	 * wall time.  Discover what correction gettimeofday() would have
-	 * made, and then undo it!
-	 */
-	tv->tv_usec -= do_gettimeoffset();
-	tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
+
+	tv->tv_usec -= do_gettimeoffset() +
+		(jiffies - wall_jiffies) * tick_usec;
 
 	while (tv->tv_usec < 0) {
 		tv->tv_usec += 1000000;
 		tv->tv_sec--;
 	}
 
-	xtime = *tv;
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_nsec = (tv->tv_usec * 1000);
 	vxtime_unlock();
 
 	time_adjust = 0;		/* stop active adjtime() */
 	time_status |= STA_UNSYNC;
 	time_maxerror = NTP_PHASE_LIMIT;
 	time_esterror = NTP_PHASE_LIMIT;
+
 	write_unlock_irq(&xtime_lock);
 }
 
 /*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- *
- * BUG: This routine does not handle hour overflow properly; it just
- *      sets the minutes. Usually you'll only notice that after reboot!
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500
+ * ms after the second nowtime has started, because when nowtime is written
+ * into the registers of the CMOS clock, it will jump to the next second
+ * precisely 500 ms later. Check the Motorola MC146818A or Dallas DS12887 data
+ * sheet for details.
  */
-static int set_rtc_mmss(unsigned long nowtime)
+
+static void set_rtc_mmss(unsigned long nowtime)
 {
-	int retval = 0;
 	int real_seconds, real_minutes, cmos_minutes;
-	unsigned char save_control, save_freq_select;
+	unsigned char control, freq_select;
+
+/*
+ * IRQs are disabled when we're called from the timer interrupt,
+ * no need for spin_lock_irqsave()
+ */
 
-	/* gets recalled with irq locally disabled */
 	spin_lock(&rtc_lock);
-	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
 
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+/*
+ * Tell the clock it's being set and stop it.
+ */
+
+	control = CMOS_READ(RTC_CONTROL);
+	CMOS_WRITE(control | RTC_SET, RTC_CONTROL);
+
+	freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	CMOS_WRITE(freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT);
 
 	cmos_minutes = CMOS_READ(RTC_MINUTES);
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 		BCD_TO_BIN(cmos_minutes);
 
-	/*
-	 * since we're only adjusting minutes and seconds,
-	 * don't interfere with hour overflow. This avoids
-	 * messing with unknown time zones but requires your
-	 * RTC not to be off by more than 15 minutes
+/*
+ * since we're only adjusting minutes and seconds, don't interfere with hour
+ * overflow. This avoids messing with unknown time zones but requires your RTC
+ * not to be off by more than 15 minutes. Since we're calling it only when
+ * our clock is externally synchronized using NTP, this shouldn't be a problem.
 	 */
+
 	real_seconds = nowtime % 60;
 	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+	if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
 		real_minutes += 30;		/* correct for half hour time zone */
 	real_minutes %= 60;
 
 	if (abs(real_minutes - cmos_minutes) < 30) {
-		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 			BIN_TO_BCD(real_seconds);
 			BIN_TO_BCD(real_minutes);
-		}
-		CMOS_WRITE(real_seconds,RTC_SECONDS);
-		CMOS_WRITE(real_minutes,RTC_MINUTES);
-	} else {
-		printk(KERN_WARNING
-		       "set_rtc_mmss: can't update from %d to %d\n",
+		CMOS_WRITE(real_seconds, RTC_SECONDS);
+		CMOS_WRITE(real_minutes, RTC_MINUTES);
+	} else
+		printk(KERN_WARNING "time.c: can't update CMOS clock from %d to %d\n",
 		       cmos_minutes, real_minutes);
-		retval = -1;
-	}
-
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	CMOS_WRITE(save_control, RTC_CONTROL);
-	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-	spin_unlock(&rtc_lock);
-
-	return retval;
-}
-
-/* last time the cmos clock got updated */
-static long last_rtc_update;
-
-int timer_ack;
 
 /*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * The following flags have to be released exactly in this order, otherwise the
+ * DS12887 (popular MC146818A clone with integrated battery and quartz) will
+ * not reset the oscillator and will not update precisely 500 ms later. You
+ * won't find this mentioned in the Dallas Semiconductor data sheets, but who
+ * believes data sheets anyway ... -- Markus Kuhn
  */
-static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-#ifdef CONFIG_X86_IO_APIC
-	if (timer_ack) {
-		/*
-		 * Subtle, when I/O APICs are used we have to ack timer IRQ
-		 * manually to reset the IRR bit for do_slow_gettimeoffset().
-		 * This will also deassert NMI lines for the watchdog if run
-		 * on an 82489DX-based system.
-		 */
-		spin_lock(&i8259A_lock);
-		outb(0x0c, 0x20);
-		/* Ack the IRQ; AEOI will end it automatically. */
-		inb(0x20);
-		spin_unlock(&i8259A_lock);
-	}
-#endif
 
-	do_timer(regs);
-/*
- * In the SMP case we use the local APIC timer interrupt to do the
- * profiling, except when we simulate SMP mode on a uniprocessor
- * system, in that case we have to call the local interrupt handler.
- */
-#ifndef CONFIG_X86_LOCAL_APIC
-	if (!user_mode(regs))
-		x86_do_profile(regs->rip);
-#else
-	if (!using_apic_timer)
-		smp_local_timer_interrupt(regs);
-#endif
-
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 */
-	if ((time_status & STA_UNSYNC) == 0 &&
-	    xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&
-	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
-		if (set_rtc_mmss(xtime.tv_sec) == 0)
-			last_rtc_update = xtime.tv_sec;
-		else
-			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-	}
-}
+	CMOS_WRITE(control, RTC_CONTROL);
+	CMOS_WRITE(freq_select, RTC_FREQ_SELECT);
 
-static int use_tsc;
+	spin_unlock(&rtc_lock);
+}
 
-/*
- * This is the same as the above, except we _also_ save the current
- * Time Stamp Counter value at the time of the timer interrupt, so that
- * we later on can estimate the time of day more exactly.
- */
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int count;
+	static unsigned long rtc_update = 0;
 
-	/*
-	 * Here we are in the timer irq handler. We just have irqs locally
-	 * disabled but we don't know if the timer_bh is running on the other
-	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
-	 * the irq version of write_lock because as just said we have irq
-	 * locally disabled. -arca
+/*
+ * Here we are in the timer irq handler. We have irqs locally disabled (so we
+ * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
+ * on the other CPU, so we need a lock. We also need to lock the vsyscall
+ * variables, because both do_timer() and us change them -arca+vojtech
 	 */
+
 	write_lock(&xtime_lock);
 	vxtime_lock();
 
-	if (use_tsc)
 	{
-		/*
-		 * It is important that these two operations happen almost at
-		 * the same time. We do the RDTSC stuff first, since it's
-		 * faster. To avoid any inconsistencies, we need interrupts
-		 * disabled locally.
-		 */
-
-		/*
-		 * Interrupts are just disabled locally since the timer irq
-		 * has the SA_INTERRUPT flag set. -arca
-		 */
-	
-		/* read Pentium cycle counter */
+		unsigned long t;
+
+		rdtscll(t);
+		hpet.offset = (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset - 1000000L / HZ;
+		if (hpet.offset >= 1000000L / HZ)
+			hpet.offset = 0;
+		hpet.ticks = min_t(long, max_t(long, (t  - hpet.last_tsc) * (1000000L / HZ) / (1000000L / HZ - hpet.offset),
+				cpu_khz * 1000/HZ * 15 / 16), cpu_khz * 1000/HZ * 16 / 15); 
+		hpet.last_tsc = t;
+	}
 
-		rdtscl(last_tsc_low);
+/*
+ * Do the timer stuff.
+ */
 
-		spin_lock(&i8253_lock);
-		outb_p(0x00, 0x43);     /* latch the count ASAP */
+	do_timer(regs);
 
-		count = inb_p(0x40);    /* read the latched count */
-		count |= inb(0x40) << 8;
-		spin_unlock(&i8253_lock);
+/*
+ * If we have an externally synchronized Linux clock, then update CMOS clock
+ * accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy
+ * closest to exactly 500 ms before the next second. If the update fails, we
+ * don'tcare, as it'll be updated on the next turn, and the problem (time way
+ * off) isn't likely to go away much sooner anyway.
+ */
 
-		count = ((LATCH-1) - count) * TICK_SIZE;
-		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+	if ((~time_status & STA_UNSYNC) && xtime.tv_sec > rtc_update &&
+		abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) {
+		set_rtc_mmss(xtime.tv_sec);
+		rtc_update = xtime.tv_sec + 660;
 	}
  
-	do_timer_interrupt(irq, NULL, regs);
-
 	vxtime_unlock();
 	write_unlock(&xtime_lock);
-
 }
 
-/* not static: needed by APM */
 unsigned long get_cmos_time(void)
 {
-	unsigned int year, mon, day, hour, min, sec;
-	int i;
+	unsigned int timeout, year, mon, day, hour, min, sec;
+	unsigned char last, this;
+
+/*
+ * The Linux interpretation of the CMOS clock register contents: When the
+ * Update-In-Progress (UIP) flag goes from 1 to 0, the RTC registers show the
+ * second which has precisely just started. Waiting for this can take up to 1
+ * second, we timeout approximately after 2.4 seconds on a machine with
+ * standard 8.3 MHz ISA bus.
+ */
 
 	spin_lock(&rtc_lock); 
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
+
+	timeout = 1000000;
+	last = this = 0;
+
+	while (timeout && last && !this) {
+		last = this;
+		this = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP;
+		timeout--;
+	}
+
+/*
+ * Here we are safe to assume the registers won't change for a whole second, so
+ * we just go ahead and read them.
 	 */
 
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-	do { /* Isn't this overkill ? UIP above should guarantee consistency */
 		sec = CMOS_READ(RTC_SECONDS);
 		min = CMOS_READ(RTC_MINUTES);
 		hour = CMOS_READ(RTC_HOURS);
 		day = CMOS_READ(RTC_DAY_OF_MONTH);
 		mon = CMOS_READ(RTC_MONTH);
 		year = CMOS_READ(RTC_YEAR);
-	} while (sec != CMOS_READ(RTC_SECONDS));
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-	  {
+
+	spin_unlock(&rtc_lock);
+
+/*
+ * We know that x86-64 always uses BCD format, no need to check the config
+ * register.
+ */
+
 	    BCD_TO_BIN(sec);
 	    BCD_TO_BIN(min);
 	    BCD_TO_BIN(hour);
 	    BCD_TO_BIN(day);
 	    BCD_TO_BIN(mon);
 	    BCD_TO_BIN(year);
-	  }
-	spin_unlock(&rtc_lock); 
+
+/*
+ * This will work up to Dec 31, 2069.
+ */
+
 	if ((year += 1900) < 1970)
 		year += 100;
+
 	return mktime(year, mon, day, hour, min, sec);
 }
 
-static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
-
-/* ------ Calibrate the TSC ------- 
- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
- * Too much 64-bit arithmetic here to do this cleanly in C, and for
- * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
- * output busy loop as low as possible. We avoid reading the CTC registers
- * directly because of the awkward 8-bit access mechanism of the 82C54
- * device.
+/*
+ * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing
+ * it to the HPET timer of known frequency.
  */
 
-#define CALIBRATE_LATCH	(5 * LATCH)
-#define CALIBRATE_TIME	(5 * 1000020/HZ)
+#define TICK_COUNT 100000000
+
+/*
+ * pit_calibrate_tsc() uses the speaker output (channel 2) of
+ * the PIT. This is better than using the timer interrupt output,
+ * because we can read the value of the speaker with just one inb(),
+ * where we need three i/o operations for the interrupt channel.
+ * We count how many ticks the TSC does in 50 ms.
+ */
 
-/* Could use 64bit arithmetic on x86-64, but the code is too fragile */
-static unsigned long __init calibrate_tsc(void)
+static unsigned int __init pit_calibrate_tsc(void)
 {
-       /* Set the Gate high, disable speaker */
+	unsigned long start, end;
+	unsigned long flags;
+
 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
 
-	/*
-	 * Now let's take care of CTC channel 2
-	 *
-	 * Set the Gate high, program CTC channel 2 for mode 0,
-	 * (interrupt on terminal count mode), binary count,
-	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
-	 */
-	outb(0xb0, 0x43);			/* binary, mode 0, LSB/MSB, Ch 2 */
-	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
-	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
+	local_irq_save(flags);
+	local_irq_disable();
 
-	{
-		unsigned int startlow, starthigh;
-		unsigned int endlow, endhigh;
-		unsigned int count;
-
-		rdtsc(startlow,starthigh);
-		count = 0;
-		do {
-			count++;
-		} while ((inb(0x61) & 0x20) == 0);
-		rdtsc(endlow,endhigh);
-
-		last_tsc_low = endlow; 
-
-		/* Error: ECTCNEVERSET */
-		if (count <= 1)
-			goto bad_ctc;
-
-		__asm__("subl %2,%0\n\t"
-			"sbbl %3,%1"
-			:"=a" (endlow), "=d" (endhigh)
-			:"g" (startlow), "g" (starthigh),
-			 "0" (endlow), "1" (endhigh));
-
-		/* Error: ECPUTOOFAST */
-		if (endhigh)
-			goto bad_ctc;
-		/* Error: ECPUTOOSLOW */
-		if (endlow  <= CALIBRATE_TIME)
-			goto bad_ctc;
-
-		__asm__("divl %2"
-			:"=a" (endlow), "=d" (endhigh)
-			:"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
+	outb(0xb0, 0x43);
+	outb((1193182 / (1000 / 50)) & 0xff, 0x42);
+	outb((1193182 / (1000 / 50)) >> 8, 0x42);
+	rdtscll(start);
       	
-		return endlow;
-	}
+	while ((inb(0x61) & 0x20) == 0);
+	rdtscll(end);
 
-	/*
-	 * The CTC wasn't reliable: we got a hit on the very first read,
-	 * or the CPU was so fast/slow that the quotient wouldn't fit in
-	 * 32 bits..
-	 */
-bad_ctc:
-	return 0;
-}
 
-void __init time_init(void)
-{
-	extern int x86_udelay_tsc;
+	local_irq_restore(flags);
 	
-	xtime.tv_sec = get_cmos_time();
-	xtime.tv_usec = 0;
+	return (end - start) / 50;
+}
 
-/*
- * If we have APM enabled or the CPU clock speed is variable
- * (CPU stops clock on HLT or slows clock to save power)
- * then the TSC timestamps may diverge by up to 1 jiffy from
- * 'real time' but nothing will break.
- * The most frequent case is that the CPU is "woken" from a halt
- * state by the timer interrupt itself, so we get 0 error. In the
- * rare cases where a driver would "wake" the CPU and request a
- * timestamp, the maximum error is < 1 jiffy. But timestamps are
- * still perfectly ordered.
- */
-
-	if (cpu_has_tsc) {
-		unsigned int tsc_quotient = calibrate_tsc();
-		if (tsc_quotient) {
-			fast_gettimeoffset_quotient = tsc_quotient;
-			use_tsc = 1;
-			/*
-			 *	We could be more selective here I suspect
-			 *	and just enable this for the next intel chips ?
-			 */
-			x86_udelay_tsc = 1;
-
-			/* report CPU clock rate in Hz.
-			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
-			 * clock/second. Our precision is about 100 ppm.
-			 */
-			{	unsigned int eax=0, edx=1000;
-				__asm__("divl %2"
-		       		:"=a" (cpu_khz), "=d" (edx)
-        	       		:"r" (tsc_quotient),
-	                	"0" (eax), "1" (edx));
-				printk("Detected %u.%03u MHz processor.\n", 
-				       cpu_khz / 1000, cpu_khz % 1000);
-			}
-		}
-	}
+void __init pit_init(void)
+{
+	outb_p(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
+	outb_p(LATCH & 0xff, 0x40);	/* LSB */
+	outb_p(LATCH >> 8, 0x40);	/* MSB */
+}
 
-	setup_irq(0, &irq0);
+int __init time_setup(char *str)
+{
+	hpet_report_lost_ticks = 1;
+	return 1;
 }
 
-static struct device device_i8253 = {
-       name:           "i8253",
-       bus_id:         "0040",
-};
+static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
+
+extern void __init config_acpi_tables(void);
 
-static int time_init_driverfs(void)
+void __init time_init(void)
 {
-       return register_sys_device(&device_i8253);
+	xtime.tv_sec = get_cmos_time();
+	xtime.tv_nsec = 0;
+
+	pit_init();
+	printk(KERN_INFO "time.c: Using 1.1931816 MHz PIT timer.\n");
+	setup_irq(0, &irq0);
+	cpu_khz = pit_calibrate_tsc();
+	printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
+		cpu_khz / 1000, cpu_khz % 1000);
+	hpet.ticks = cpu_khz * (1000 / HZ);
+	rdtscll(hpet.last_tsc);
 }
 
-__initcall(time_init_driverfs);
+__setup("report_lost_ticks", time_setup);
diff -Nru a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline.S
--- a/arch/x86_64/kernel/trampoline.S	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/kernel/trampoline.S	Tue Oct 15 20:29:15 2002
@@ -33,7 +33,7 @@
 
 ENTRY(trampoline_data)
 r_base = .
-
+	wbinvd	
 	mov	%cs, %ax	# Code and data in the same place
 	mov	%ax, %ds
 
diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
--- a/arch/x86_64/kernel/traps.c	Tue Oct 15 20:29:11 2002
+++ b/arch/x86_64/kernel/traps.c	Tue Oct 15 20:29:11 2002
@@ -36,6 +36,7 @@
 #include <asm/desc.h>
 #include <asm/i387.h>
 #include <asm/kdebug.h>
+#include <asm/processor.h>
 
 #include <asm/smp.h>
 #include <asm/pgalloc.h>
@@ -47,11 +48,6 @@
 asmlinkage int kernel_syscall(void);
 extern void ia32_syscall(void);
 
-char doublefault_stack[4*1024]; 
-#ifndef CONFIG_SMP
-char stackfault_stack[4*1024];
-#endif
-
 extern struct gate_struct idt_table[256]; 
 
 asmlinkage void divide_error(void);
@@ -101,7 +97,7 @@
 	} 
 	if (!strcmp(modname, "kernel"))
 		modname = delim = ""; 		
-        return printk("[%016lx%s%s%s%s%+ld]",
+        return printk("<%016lx>{%s%s%s%s%+ld}",
 		      address,delim,modname,delim,symname,address-symstart); 
 } 
 #else
@@ -114,7 +110,6 @@
 
 #ifdef CONFIG_MODULES
 
-extern struct module *module_list;
 extern struct module kernel_module;
 
 static inline int kernel_text_address(unsigned long addr)
@@ -149,30 +144,59 @@
 
 #endif
 
+static inline unsigned long *in_exception_stack(int cpu, unsigned long stack) 
+{ 
+	int k;
+	for (k = 0; k < N_EXCEPTION_STACKS; k++) {
+		unsigned long end = init_tss[cpu].ist[k] + EXCEPTION_STKSZ; 
+
+		if (stack >= init_tss[cpu].ist[k]  && stack <= end) 
+			return (unsigned long *)end;
+	}
+	return 0;
+} 
+
 /*
- * These constants are for searching for possible module text
- * segments. MODULE_RANGE is a guess of how much space is likely
- * to be vmalloced.
+ * x86-64 can have upto three kernel stacks: 
+ * process stack
+ * interrupt stack
+ * severe exception (double fault, nmi, stack fault) hardware stack
+ * Check and process them in order.
  */
-#define MODULE_RANGE (8*1024*1024)
 
 void show_trace(unsigned long *stack)
 {
 	unsigned long addr;
-	unsigned long *irqstack, *irqstack_end;
+	unsigned long *irqstack, *irqstack_end, *estack_end;
 	/* FIXME: should read the cpuid from the APIC; to still work with bogus %gs */
 	const int cpu = smp_processor_id();
 	int i;
 
-	printk("\nCall Trace: ");
+	printk("\nCall Trace:");
+	i = 0; 
+	
+	estack_end = in_exception_stack(cpu, (unsigned long)stack); 
+	if (estack_end) { 
+		while (stack < estack_end) { 
+			addr = *stack++; 
+			if (kernel_text_address(addr)) {  
+				i += printk_address(addr);
+				i += printk(" "); 
+				if (i > 50) {
+					printk("\n"); 
+					i = 0;
+				}
+			}
+		}
+		i += printk(" <EOE> "); 
+		i += 7;
+		stack = (unsigned long *) estack_end[-2]; 
+	}  
 
 	irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr);
 	irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE + 64);
 
-	i = 1;
 	if (stack >= irqstack && stack < irqstack_end) {
-		unsigned long *tstack;
-
 		printk("<IRQ> ");  
 		while (stack < irqstack_end) {
 			addr = *stack++;
@@ -195,13 +219,7 @@
 		} 
 		stack = (unsigned long *) (irqstack_end[-1]);
 		printk(" <EOI> ");
-#if 1
-		tstack = (unsigned long *)(current_thread_info()+1);
-		if (stack < tstack || (char*)stack > (char*)tstack+THREAD_SIZE) 
-			printk("\n" KERN_DEBUG 
-		       "no stack at the end of irqstack; stack:%p, curstack %p\n",
-			       stack, tstack); 
-#endif			       
+		i += 7;
 	} 
 
 	while (((long) stack & (THREAD_SIZE-1)) != 0) {
@@ -260,6 +278,15 @@
 	show_trace((unsigned long *)rsp);
 }
 
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+	unsigned long dummy;
+	show_stack(&dummy);
+}
+
 void show_registers(struct pt_regs *regs)
 {
 	int i;
@@ -322,6 +349,7 @@
 		return;
 	if (__get_user(tmp, f.filename))
 		f.filename = "unmapped filename"; 
+	printk("----------- [cut here ] --------- [please bite here ] ---------\n");
 	printk("Kernel BUG at %.50s:%d\n", f.filename, f.line); 	
 } 
 
@@ -377,6 +405,19 @@
 static void do_trap(int trapnr, int signr, char *str, 
 			   struct pt_regs * regs, long error_code, siginfo_t *info)
 {
+#ifdef CONFIG_CHECKING
+       { 
+               unsigned long gs; 
+               struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+               rdmsrl(MSR_GS_BASE, gs); 
+               if (gs != (unsigned long)pda) { 
+                       wrmsrl(MSR_GS_BASE, pda); 
+                       printk("%s: wrong gs %lx expected %p rip %lx\n", str, gs, pda,
+			      regs->rip);
+               }
+       }
+#endif
+
 	if ((regs->cs & 3)  != 0) { 
 		struct task_struct *tsk = current;
 
@@ -452,6 +493,18 @@
 
 asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 {
+#ifdef CONFIG_CHECKING
+       { 
+               unsigned long gs; 
+               struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+               rdmsrl(MSR_GS_BASE, gs); 
+               if (gs != (unsigned long)pda) { 
+                       wrmsrl(MSR_GS_BASE, pda); 
+                       printk("general protection handler: wrong gs %lx expected %p\n", gs, pda);
+               }
+       }
+#endif
+
 	if ((regs->cs & 3)!=0) { 
 		struct task_struct *tsk = current;
 		if (exception_trace)
@@ -501,8 +554,7 @@
 }
 
 static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
-{
-	printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
+{	printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
 	printk("Dazed and confused, but trying to continue\n");
 	printk("Do you have a strange power saving mode enabled?\n");
 }
@@ -532,6 +584,7 @@
 		mem_parity_error(reason, regs);
 	if (reason & 0x40)
 		io_check_error(reason, regs);
+
 	/*
 	 * Reassert NMI in case it became active meanwhile
 	 * as it's edge-triggered.
@@ -547,6 +600,18 @@
 	unsigned long condition;
 	struct task_struct *tsk = current;
 	siginfo_t info;
+
+#ifdef CONFIG_CHECKING
+       { 
+               unsigned long gs; 
+               struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); 
+               rdmsrl(MSR_GS_BASE, gs); 
+               if (gs != (unsigned long)pda) { 
+                       wrmsrl(MSR_GS_BASE, pda); 
+                       printk("debug handler: wrong gs %lx expected %p\n", gs, pda);
+               }
+       }
+#endif
 
 	asm("movq %%db6,%0" : "=r" (condition));
 
diff -Nru a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
--- a/arch/x86_64/kernel/vsyscall.c	Tue Oct 15 20:29:20 2002
+++ b/arch/x86_64/kernel/vsyscall.c	Tue Oct 15 20:29:20 2002
@@ -47,7 +47,7 @@
 
 #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
 
-//#define NO_VSYSCALL 1
+#define NO_VSYSCALL 1
 
 #ifdef NO_VSYSCALL
 #include <asm/unistd.h>
@@ -71,51 +71,27 @@
 
 long __vxtime_sequence[2] __section_vxtime_sequence;
 
+
 static inline void do_vgettimeofday(struct timeval * tv)
 {
-	long sequence;
-	unsigned long usec, sec;
+	long sequence, t;
+	unsigned long sec, usec;
 
 	do {
-		unsigned long eax, edx;
-
 		sequence = __vxtime_sequence[1];
 		rmb();
 		
-		/* Read the Time Stamp Counter */
-		rdtsc(eax,edx);
-
-		/* .. relative to previous jiffy (32 bits is enough) */
-		eax -= __last_tsc_low;	/* tsc_low delta */
-
-		/*
-		 * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient
-		 *             = (tsc_low delta) * (usecs_per_clock)
-		 *             = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy)
-		 *
-		 * Using a mull instead of a divl saves up to 31 clock cycles
-		 * in the critical path.
-		 */
-
-		edx = (eax*__fast_gettimeoffset_quotient) >> 32;
-
-		/* our adjusted time offset in microseconds */
-		usec = __delay_at_last_interrupt + edx;
-
-		{
-			unsigned long lost = __jiffies - __wall_jiffies;
-			if (lost)
-				usec += lost * (1000000 / HZ);
-		}
+		rdtscll(t);
 		sec = __xtime.tv_sec;
-		usec += __xtime.tv_usec;
+		usec = __xtime.tv_usec +
+			(__jiffies - __wall_jiffies) * (1000000 / HZ) +
+			(t  - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset;
 
 		rmb();
 	} while (sequence != __vxtime_sequence[0]);
 
-	tv->tv_sec = sec;
-	tv->tv_usec = usec;
-	timeval_normalize(tv);
+	tv->tv_sec = sec + usec / 1000000;
+	tv->tv_usec = usec % 1000000;
 }
 
 static inline void do_get_tz(struct timezone * tz)
diff -Nru a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
--- a/arch/x86_64/kernel/x8664_ksyms.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/kernel/x8664_ksyms.c	Tue Oct 15 20:29:12 2002
@@ -47,6 +47,7 @@
 EXPORT_SYMBOL(boot_cpu_data);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(ioremap_nocache);
 EXPORT_SYMBOL(iounmap);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
@@ -109,18 +110,11 @@
 
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(smp_num_cpus);
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL_NOVERS(__write_lock_failed);
 EXPORT_SYMBOL_NOVERS(__read_lock_failed);
 
-/* Global SMP irq stuff */
 EXPORT_SYMBOL(synchronize_irq);
-EXPORT_SYMBOL(global_irq_holder);
-EXPORT_SYMBOL(__global_cli);
-EXPORT_SYMBOL(__global_sti);
-EXPORT_SYMBOL(__global_save_flags);
-EXPORT_SYMBOL(__global_restore_flags);
 EXPORT_SYMBOL(smp_call_function);
 
 #endif
diff -Nru a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile
--- a/arch/x86_64/lib/Makefile	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/lib/Makefile	Tue Oct 15 20:29:12 2002
@@ -2,14 +2,12 @@
 # Makefile for x86_64-specific library files.
 #
 
-USE_STANDARD_AS_RULE := true
-
 EXTRA_CFLAGS_csum-partial.o := -funroll-loops
 
 L_TARGET = lib.a
 obj-y  = csum-partial.o csum-copy.o csum-wrappers.o delay.o \
 	usercopy.o getuser.o putuser.o  \
-	thunk.o io.o clear_page.o copy_page.o
+	thunk.o io.o clear_page.o copy_page.o bitstr.o
 obj-y += memcpy.o
 obj-y += memmove.o
 obj-y += memset.o
diff -Nru a/arch/x86_64/lib/bitstr.c b/arch/x86_64/lib/bitstr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/lib/bitstr.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,25 @@
+#include <asm/bitops.h>
+
+/* Find string of zero bits in a bitmap */ 
+unsigned long 
+find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len)
+{ 
+	unsigned long n, end, i; 	
+
+ again:
+	n = find_next_zero_bit(bitmap, nbits, start);
+	if (n == -1) 
+		return -1;
+	
+	/* could test bitsliced, but it's hardly worth it */
+	end = n+len;
+	if (end >= nbits) 
+		return -1; 
+	for (i = n+1; i < end; i++) { 
+		if (test_bit(i, bitmap)) {  
+			start = i+1; 
+			goto again; 
+		} 
+	}
+	return n;
+}
diff -Nru a/arch/x86_64/lib/clear_page.S b/arch/x86_64/lib/clear_page.S
--- a/arch/x86_64/lib/clear_page.S	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/lib/clear_page.S	Tue Oct 15 20:29:16 2002
@@ -1,7 +1,6 @@
 /*
  * Copyright 2002 Andi Kleen, SuSE Labs.
  */		 
-	
 	#include <linux/linkage.h>
 
 /*
@@ -13,7 +12,7 @@
 	movl   $4096/128,%ecx
 	movl   $128,%edx
 loop:
-#define PUT(x) movnti %rax,x*8(%rdi) 
+#define PUT(x) movq %rax,x*8(%rdi) 
 	PUT(0)
 	PUT(1)
 	PUT(2)
diff -Nru a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page.S
--- a/arch/x86_64/lib/copy_page.S	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/lib/copy_page.S	Tue Oct 15 20:29:16 2002
@@ -1,6 +1,7 @@
 /*
  * Copyright 2002 Andi Kleen, SuSE Labs.
  */	 	
+	
 	#include <linux/linkage.h>
 	#include <linux/config.h>
 	#ifdef CONFIG_PREEMPT
@@ -18,7 +19,9 @@
  * Warning: in case of super lazy FP save this needs to be preempt_stop	
  */
 	
-ENTRY(copy_page)
+	.globl copy_page
+	.p2align
+copy_page:
 	prefetchnta (%rsi) 
 	prefetchnta 64(%rsi)
 	    
@@ -37,22 +40,22 @@
 	prefetchnta 64(%rsi) 
 loop_no_prefetch:	
 	movdqa (%rsi),%xmm0 	 			 
-	movdqa 1*16(%rsi),%xmm1
-	movdqa 2*16(%rsi),%xmm2 	 			 
-	movdqa 3*16(%rsi),%xmm3 	 			 
+	movdqa 16(%rsi),%xmm1
+	movdqa 32(%rsi),%xmm2 	 			 
+	movdqa 48(%rsi),%xmm3 	 			 
 	movntdq %xmm0,(%rdi)	 
 	movntdq %xmm1,16(%rdi)	 
-	movntdq %xmm2,2*16(%rdi)	 
-	movntdq %xmm3,3*16(%rdi)
+	movntdq %xmm2,32(%rdi)	 
+	movntdq %xmm3,48(%rdi)
 	
-	movdqa 4*16(%rsi),%xmm0 	 			 
-	movdqa 5*16(%rsi),%xmm1
-	movdqa 6*16(%rsi),%xmm2 	 			 
-	movdqa 7*16(%rsi),%xmm3 	 			 
-	movntdq %xmm0,4*16(%rdi)	 
-	movntdq %xmm1,5*16(%rdi)	 
-	movntdq %xmm2,6*16(%rdi)	 
-	movntdq %xmm3,7*16(%rdi)
+	movdqa 64(%rsi),%xmm0 	 			 
+	movdqa 80(%rsi),%xmm1
+	movdqa 96(%rsi),%xmm2 	 			 
+	movdqa 112(%rsi),%xmm3 	 			 
+	movntdq %xmm0,64(%rdi)	 
+	movntdq %xmm1,80(%rdi)	 
+	movntdq %xmm2,96(%rdi)	 
+	movntdq %xmm3,112(%rdi)
 
 	addq   %rdx,%rdi	
 	addq   %rdx,%rsi
diff -Nru a/arch/x86_64/lib/copy_user.S b/arch/x86_64/lib/copy_user.S
--- a/arch/x86_64/lib/copy_user.S	Tue Oct 15 20:29:17 2002
+++ b/arch/x86_64/lib/copy_user.S	Tue Oct 15 20:29:17 2002
@@ -6,8 +6,12 @@
 
 #define FIX_ALIGNMENT 1
 		
-	#include <asm/thread_info.h>
+#define movnti movq  /* write to cache for now */
+#define prefetch prefetcht2
+		
+	#include <asm/current.h>
 	#include <asm/offset.h>
+	#include <asm/thread_info.h>
 
 /* Standard copy_to_user with segment limit checking */		
 	.globl copy_to_user
@@ -62,7 +66,7 @@
 	   the small movements in ioctls etc., but not penalize the bigger
 	   filesystem data copies too much. */
 	pushq %rbx
-	prefetcht0 (%rsi)
+	prefetch (%rsi)
 	xorl %eax,%eax		/*zero for the exception handler */
 
 #ifdef FIX_ALIGNMENT
@@ -82,7 +86,7 @@
 	jz   loop_no_prefetch
 	
 loop:
-	prefetchnta 64(%rsi)
+	prefetch 64(%rsi)
 	
 loop_no_prefetch:	
 s1:	movq (%rsi),%r11
@@ -118,10 +122,11 @@
 	movl $8,%ebx
 loop_8:
 s9:	movq (%rsi),%r8
-d9:	movnti %r8,(%rdi)
+d9:	movq %r8,(%rdi)
 	addq %rbx,%rdi
 	addq %rbx,%rsi
-	loop loop_8
+	decl %ecx
+	jnz loop_8
 	
 handle_7:		
 	movl %edx,%ecx	
@@ -132,7 +137,8 @@
 d10:	movb %bl,(%rdi)
 	incq %rdi
 	incq %rsi
-	loop loop_1
+	decl %ecx
+	jnz loop_1
 			
 ende:
 	sfence
@@ -153,7 +159,8 @@
 d11:	movb %bl,(%rdi)
 	incq %rsi
 	incq %rdi
-	loop align_1
+	decl %ecx
+	jnz align_1
 	jmp after_bad_alignment
 small_align:
 	addq %r9,%rdx
diff -Nru a/arch/x86_64/lib/csum-copy.S b/arch/x86_64/lib/csum-copy.S
--- a/arch/x86_64/lib/csum-copy.S	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/lib/csum-copy.S	Tue Oct 15 20:29:15 2002
@@ -28,6 +28,10 @@
  * Wrappers need to take care of valid exception sum and zeroing.		 
  */
 
+/* for now - should vary this based on direction */
+ #define prefetch prefetcht2
+ #define movnti   movq
+
 	.macro source
 10:
 	.section __ex_table,"a"
@@ -163,7 +167,8 @@
 	movnti %rbx,(%rsi)
 	leaq (%rsi,%rdx),%rsi /* preserve carry */
 	leaq (%rdi,%rdx),%rdi
-	loop loop_8
+	decl %ecx
+	jnz	loop_8
 	adcq %r9,%rax	/* add in carry */
 
 fold:
@@ -188,7 +193,8 @@
 	movw %bx,(%rsi)
 	addq %rdx,%rdi
 	addq %rdx,%rsi
-	loop loop_1
+	decl %ecx
+	jnz loop_1
 	adcw %r9w,%ax	/* add in carry */
 	
 	/* handle last odd byte */
@@ -235,7 +241,8 @@
 	movw %bx,(%rsi)
 	addq %r10,%rdi
 	addq %r10,%rsi
-	loop align_loop 
+	decl %ecx
+	jnz align_loop
 	jmp after_bad_alignment
 
 	/* weird case. need to swap the sum at the end because the spec requires
diff -Nru a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy.S
--- a/arch/x86_64/lib/memcpy.S	Tue Oct 15 20:29:18 2002
+++ b/arch/x86_64/lib/memcpy.S	Tue Oct 15 20:29:18 2002
@@ -11,19 +11,22 @@
  * Output:
  * rax original destination
  */	
+
+ // #define FIX_ALIGNMENT
  	.globl __memcpy
 	.globl memcpy
 	.p2align
 __memcpy:
 memcpy:		
 	pushq %rbx
-	prefetcht0 (%rsi)	/*for more hopefully the hw prefetch will kick in*/
 	movq %rdi,%rax
 
+#ifdef FIX_ALIGNMENT
 	movl %edi,%ecx
 	andl $7,%ecx
 	jnz  bad_alignment	
 after_bad_alignment:
+#endif
 
 	movq %rdx,%rcx
 	movl $64,%ebx
@@ -31,30 +34,28 @@
 	jz handle_tail
 	
 loop_64:
-	/* no prefetch because we assume the hw prefetcher does it already 
-           and we have no specific temporal hint to give. XXX or give a nta
-	   hint for the source? */
 	movq (%rsi),%r11
 	movq 8(%rsi),%r8
 	movq 2*8(%rsi),%r9
 	movq 3*8(%rsi),%r10
-	movnti %r11,(%rdi)
-	movnti %r8,1*8(%rdi)
-	movnti %r9,2*8(%rdi)
-	movnti %r10,3*8(%rdi)
+	movq %r11,(%rdi)
+	movq %r8,1*8(%rdi)
+	movq %r9,2*8(%rdi)
+	movq %r10,3*8(%rdi)
 		
 	movq 4*8(%rsi),%r11
 	movq 5*8(%rsi),%r8
 	movq 6*8(%rsi),%r9
 	movq 7*8(%rsi),%r10
-	movnti %r11,4*8(%rdi)
-	movnti %r8,5*8(%rdi)
-	movnti %r9,6*8(%rdi)
-	movnti %r10,7*8(%rdi)
+	movq %r11,4*8(%rdi)
+	movq %r8,5*8(%rdi)
+	movq %r9,6*8(%rdi)
+	movq %r10,7*8(%rdi)
 
 	addq %rbx,%rsi	
 	addq %rbx,%rdi
-	loop loop_64
+	decl %ecx
+	jnz  loop_64
 
 handle_tail:
 	movl %edx,%ecx
@@ -64,10 +65,11 @@
 	movl $8,%ebx
 loop_8: 
 	movq (%rsi),%r8
-	movnti %r8,(%rdi) 
+	movq %r8,(%rdi) 
 	addq %rbx,%rdi
 	addq %rbx,%rsi
-	loop loop_8
+	decl %ecx
+	jnz  loop_8
 
 handle_7:
 	movl %edx,%ecx
@@ -78,13 +80,16 @@
 	movb %r8b,(%rdi) 
 	incq %rdi
 	incq %rsi
-	loop loop_1
+	decl %ecx
+	jnz loop_1
 	
 ende: 	
 	sfence
 	popq %rbx
 	ret
 	
+
+#ifdef FIX_ALIGNMENT
 	/* align destination */
 	/* This is simpleminded. For bigger blocks it may make sense to align
 	   src and dst to their aligned subset and handle the rest separately */
@@ -100,8 +105,10 @@
 	movb %r8b,(%rdi) 
 	incq %rdi
 	incq %rsi
-	loop align_1
+	decl %ecx
+	jnz  align_1
 	jmp after_bad_alignment
 small_alignment:
 	addq %r9,%rdx
 	jmp handle_7
+#endif	
diff -Nru a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset.S
--- a/arch/x86_64/lib/memset.S	Tue Oct 15 20:29:15 2002
+++ b/arch/x86_64/lib/memset.S	Tue Oct 15 20:29:15 2002
@@ -1,4 +1,4 @@
-/* Copyright 2002 Andi Kleen */
+/* Copyright 2002 Andi Kleen, SuSE Labs */
 
 /*
  * ISO C memset - set a memory block to a byte value.
@@ -34,16 +34,17 @@
 	jz	 handle_tail
 
 loop_64:	
-	movnti  %rax,(%rdi) 
-	movnti  %rax,8(%rdi) 
-	movnti  %rax,16(%rdi) 
-	movnti  %rax,24(%rdi) 
-	movnti  %rax,32(%rdi) 
-	movnti  %rax,40(%rdi) 
-	movnti  %rax,48(%rdi) 
-	movnti  %rax,56(%rdi) 
+	movq  %rax,(%rdi) 
+	movq  %rax,8(%rdi) 
+	movq  %rax,16(%rdi) 
+	movq  %rax,24(%rdi) 
+	movq  %rax,32(%rdi) 
+	movq  %rax,40(%rdi) 
+	movq  %rax,48(%rdi) 
+	movq  %rax,56(%rdi) 
 	addq    %r8,%rdi
-	loop	loop_64
+	decl   %ecx
+	jnz    loop_64
 
 	/* Handle tail in loops. The loops should be faster than hard
 	   to predict jump tables. */ 
@@ -53,9 +54,10 @@
 	jz 	handle_7
 	shrl	$3,%ecx
 loop_8:
-	movnti  %rax,(%rdi) 
+	movq  %rax,(%rdi) 
 	addq    $8,%rdi
-	loop 	loop_8   
+	decl   %ecx
+	jnz    loop_8
 
 handle_7:
 	movl	%r11d,%ecx
@@ -64,7 +66,8 @@
 loop_1:
 	movb 	%al,(%rdi)
 	addq	$1,%rdi
-	loop	loop_1
+	decl    %ecx
+	jnz     loop_1
 	
 ende:	
 	movq	%r10,%rax
@@ -73,7 +76,7 @@
 bad_alignment:
 	cmpq $7,%r11
 	jbe	handle_7
-	movnti %rax,(%rdi)	/* unaligned store */
+	movq %rax,(%rdi)	/* unaligned store */
 	movq $8,%r8			
 	subq %r9,%r8 
 	addq %r8,%rdi
diff -Nru a/arch/x86_64/lib/thunk.S b/arch/x86_64/lib/thunk.S
--- a/arch/x86_64/lib/thunk.S	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/lib/thunk.S	Tue Oct 15 20:29:16 2002
@@ -34,6 +34,7 @@
 	thunk rwsem_down_read_failed_thunk,rwsem_down_read_failed
 	thunk rwsem_down_write_failed_thunk,rwsem_down_write_failed
 	thunk rwsem_wake_thunk,rwsem_wake
+	thunk rwsem_downgrade_thunk,rwsem_downgrade_wake
 #endif	
 	thunk do_softirq_thunk,do_softirq
 	
diff -Nru a/arch/x86_64/lib/usercopy.c b/arch/x86_64/lib/usercopy.c
--- a/arch/x86_64/lib/usercopy.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/lib/usercopy.c	Tue Oct 15 20:29:12 2002
@@ -11,39 +11,49 @@
  * Copy a null terminated string from userspace.
  */
 
-long __strncpy_from_user(char *dst, const char *src, long count)
+#define __do_strncpy_from_user(dst,src,count,res)			   \
+do {									   \
+	long __d0, __d1, __d2;						   \
+	__asm__ __volatile__(						   \
+		"	testq %1,%1\n"					   \
+		"	jz 2f\n"					   \
+		"0:	lodsb\n"					   \
+		"	stosb\n"					   \
+		"	testb %%al,%%al\n"				   \
+		"	jz 1f\n"					   \
+		"	decq %1\n"					   \
+		"	jnz 0b\n"					   \
+		"1:	subq %1,%0\n"					   \
+		"2:\n"							   \
+		".section .fixup,\"ax\"\n"				   \
+		"3:	movq %5,%0\n"					   \
+		"	jmp 2b\n"					   \
+		".previous\n"						   \
+		".section __ex_table,\"a\"\n"				   \
+		"	.align 4\n"					   \
+		"	.quad 0b,3b\n"					   \
+		".previous"						   \
+		: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),	   \
+		  "=&D" (__d2)						   \
+		: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
+		: "memory");						   \
+} while (0)
+
+long
+__strncpy_from_user(char *dst, const char *src, long count)
 {
 	long res;
-	long __d0, __d1, __d2;
-	asm volatile(		\
-		"	testq %1,%1\n"
-		"	jz 2f\n"
-		"0:	lodsb\n"
-		"	stosb\n"
-		"	testb %%al,%%al\n"
-		"   	loopnz 0b\n"
-		"1:	subq %1,%0\n"
-		"2:\n"
-		".section .fixup,\"ax\"\n"
-		"3:	movq %5,%0\n"
-		"	jmp 2b\n"
-		".previous\n"
-		".section __ex_table,\"a\"\n"
-		"	.align 8\n"
-		"	.quad 0b,3b\n"
-		".previous"
-		: "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),
-		  "=&D" (__d2)
-		: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst)
-		: "memory");
+	__do_strncpy_from_user(dst, src, count, res);
 	return res;
 }
 
-long strncpy_from_user(char *dst, const char *src, long count)
+long
+strncpy_from_user(char *dst, const char *src, long count)
 {
+	long res = -EFAULT;
 	if (access_ok(VERIFY_READ, src, 1))
-		return __strncpy_from_user(dst, src, count);
-	return -EFAULT;
+		__do_strncpy_from_user(dst, src, count, res);
+	return res;
 }
 
 /*
@@ -60,13 +70,13 @@
 		"	jz     4f\n"
 		"0:	movnti %[zero],(%[dst])\n"
 		"	addq   %[eight],%[dst]\n"
-		"	loop   0b\n"
+		"	decl %%ecx ; jnz   0b\n"
 		"4:	movq  %[size1],%%rcx\n"
 		"	testl %%ecx,%%ecx\n"
 		"	jz     2f\n"
 		"1:	movb   %b[zero],(%[dst])\n"
 		"	incq   %[dst]\n"
-		"	loop   1b\n"
+		"	decl %%ecx ; jnz  1b\n"
 		"2:	sfence\n"
 		".section .fixup,\"ax\"\n"
 		"3:	lea 0(%[size1],%[size8],8),%[size8]\n"
diff -Nru a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile
--- a/arch/x86_64/pci/Makefile	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/pci/Makefile	Tue Oct 15 20:29:12 2002
@@ -1,4 +1,3 @@
-O_TARGET        := pci.o
 
 obj-y		:= x86-64.o
 
diff -Nru a/arch/x86_64/pci/common.c b/arch/x86_64/pci/common.c
--- a/arch/x86_64/pci/common.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/pci/common.c	Tue Oct 15 20:29:12 2002
@@ -133,6 +133,10 @@
 
 	pcibios_resource_survey();
 
+#ifdef CONFIG_GART_IOMMU
+	pci_iommu_init();
+#endif
+
 	/* may eventually need to do ACPI sort here. */
 	return 0;
 }
@@ -185,11 +189,11 @@
 	return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	int err;
 
-	if ((err = pcibios_enable_resources(dev)) < 0)
+	if ((err = pcibios_enable_resources(dev, mask)) < 0)
 		return err;
 
 	return pcibios_enable_irq(dev);
diff -Nru a/arch/x86_64/pci/fixup.c b/arch/x86_64/pci/fixup.c
--- a/arch/x86_64/pci/fixup.c	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/pci/fixup.c	Tue Oct 15 20:29:12 2002
@@ -41,19 +41,6 @@
 	}
 }
 
-static void __devinit  pci_fixup_ide_trash(struct pci_dev *d)
-{
-	int i;
-
-	/*
-	 * There exist PCI IDE controllers which have utter garbage
-	 * in first four base registers. Ignore that.
-	 */
-	DBG("PCI: IDE base address trash cleared for %s\n", d->slot_name);
-	for(i=0; i<4; i++)
-		d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0;
-}
-
 struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pci_fixup_ide_bases },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_NCR,	PCI_DEVICE_ID_NCR_53C810,	pci_fixup_ncr53c810 },
diff -Nru a/arch/x86_64/pci/pci.h b/arch/x86_64/pci/pci.h
--- a/arch/x86_64/pci/pci.h	Tue Oct 15 20:29:16 2002
+++ b/arch/x86_64/pci/pci.h	Tue Oct 15 20:29:16 2002
@@ -29,7 +29,7 @@
 extern unsigned int pcibios_max_latency;
 
 void pcibios_resource_survey(void);
-int pcibios_enable_resources(struct pci_dev *);
+int pcibios_enable_resources(struct pci_dev *, int);
 
 /* pci-pc.c */
 
diff -Nru a/arch/x86_64/pci/x86-64.c b/arch/x86_64/pci/x86-64.c
--- a/arch/x86_64/pci/x86-64.c	Tue Oct 15 20:29:22 2002
+++ b/arch/x86_64/pci/x86-64.c	Tue Oct 15 20:29:22 2002
@@ -243,7 +243,7 @@
 	pcibios_assign_resources();
 }
 
-int pcibios_enable_resources(struct pci_dev *dev)
+int pcibios_enable_resources(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
@@ -252,6 +252,9 @@
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
 	for(idx=0; idx<6; idx++) {
+		if (!(mask & (1<<idx)))
+			continue;
+
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
diff -Nru a/arch/x86_64/vmlinux.lds.S b/arch/x86_64/vmlinux.lds.S
--- a/arch/x86_64/vmlinux.lds.S	Tue Oct 15 20:29:12 2002
+++ b/arch/x86_64/vmlinux.lds.S	Tue Oct 15 20:29:12 2002
@@ -55,17 +55,17 @@
   . = ALIGN(64);
   .vxtime_sequence : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.vxtime_sequence) }
   vxtime_sequence = LOADADDR(.vxtime_sequence);
-  .last_tsc_low : AT (LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence)) { *(.last_tsc_low) }
-  last_tsc_low = LOADADDR(.last_tsc_low);
-  .delay_at_last_interrupt : AT (LOADADDR(.last_tsc_low) + SIZEOF(.last_tsc_low)) { *(.delay_at_last_interrupt) }
-  delay_at_last_interrupt = LOADADDR(.delay_at_last_interrupt);
-  .fast_gettimeoffset_quotient : AT (LOADADDR(.delay_at_last_interrupt) + SIZEOF(.delay_at_last_interrupt)) { *(.fast_gettimeoffset_quotient) }
-  fast_gettimeoffset_quotient = LOADADDR(.fast_gettimeoffset_quotient);
-  .wall_jiffies : AT (LOADADDR(.fast_gettimeoffset_quotient) + SIZEOF(.fast_gettimeoffset_quotient)) { *(.wall_jiffies) }
+  . = ALIGN(16);
+  .hpet : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.hpet) }
+  hpet = LOADADDR(.hpet);
+  . = ALIGN(16);
+  .wall_jiffies : AT ((LOADADDR(.hpet) + SIZEOF(.hpet) + 15) & ~(15)) { *(.wall_jiffies) }
   wall_jiffies = LOADADDR(.wall_jiffies);
-  .sys_tz : AT (LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies)) { *(.sys_tz) }
+  . = ALIGN(16);
+  .sys_tz : AT ((LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies) + 15) & ~(15)) { *(.sys_tz) }
   sys_tz = LOADADDR(.sys_tz);
-  .jiffies : AT (LOADADDR(.sys_tz) + SIZEOF(.sys_tz)) { *(.jiffies) }
+  . = ALIGN(16);
+  .jiffies : AT ((LOADADDR(.sys_tz) + SIZEOF(.sys_tz) + 15) & ~(15)) { *(.jiffies) }
   jiffies = LOADADDR(.jiffies);
   . = ALIGN(16);
   .xtime : AT ((LOADADDR(.jiffies) + SIZEOF(.jiffies) + 15) & ~(15)) { *(.xtime) }
@@ -100,7 +100,6 @@
   __initcall_end = .;
   . = ALIGN(32);
   __per_cpu_start = .;
-  . = ALIGN(64); 
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
   . = ALIGN(4096);
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	Tue Oct 15 20:29:20 2002
+++ b/drivers/Makefile	Tue Oct 15 20:29:20 2002
@@ -38,7 +38,7 @@
 obj-$(CONFIG_I2C)		+= i2c/
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
-obj-$(CONFIG_BLUEZ)		+= bluetooth/
+obj-$(CONFIG_BT)		+= bluetooth/
 obj-$(CONFIG_HOTPLUG_PCI)	+= hotplug/
 obj-$(CONFIG_ISDN_BOOL)		+= isdn/
 
diff -Nru a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
--- a/drivers/acorn/block/fd1772.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/acorn/block/fd1772.c	Tue Oct 15 20:29:16 2002
@@ -345,8 +345,6 @@
 static void fd_deselect(void);
 static void fd_motor_off_timer(unsigned long dummy);
 static void check_change(unsigned long dummy);
-static __inline__ void set_head_settle_flag(void);
-static __inline__ int get_head_settle_flag(void);
 static void floppy_irqconsequencehandler(void);
 static void fd_error(void);
 static void do_fd_action(int drive);
@@ -363,7 +361,6 @@
 static void finish_fdc(void);
 static void finish_fdc_done(int dummy);
 static void floppy_off(unsigned int nr);
-static __inline__ void copy_buffer(void *from, void *to);
 static void setup_req_params(int drive);
 static void redo_fd_request(void);
 static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int
@@ -543,12 +540,12 @@
  * seek operation, because we don't use seeks with verify.
  */
 
-static __inline__ void set_head_settle_flag(void)
+static inline void set_head_settle_flag(void)
 {
 	HeadSettleFlag = FDC1772CMDADD_E;
 }
 
-static __inline__ int get_head_settle_flag(void)
+static inline int get_head_settle_flag(void)
 {
 	int tmp = HeadSettleFlag;
 	HeadSettleFlag = 0;
@@ -560,6 +557,15 @@
 
 /* General Interrupt Handling */
 
+static inline void copy_buffer(void *from, void *to)
+{
+	ulong *p1 = (ulong *) from, *p2 = (ulong *) to;
+	int cnt;
+
+	for (cnt = 512 / 4; cnt; cnt--)
+		*p2++ = *p1++;
+}
+
 static void (*FloppyIRQHandler) (int status) = NULL;
 
 static void floppy_irqconsequencehandler(void)
@@ -1175,16 +1181,6 @@
 	return 0;
 }
 
-static __inline__ void copy_buffer(void *from, void *to)
-{
-	ulong *p1 = (ulong *) from, *p2 = (ulong *) to;
-	int cnt;
-
-	for (cnt = 512 / 4; cnt; cnt--)
-		*p2++ = *p1++;
-}
-
-
 /* This sets up the global variables describing the current request. */
 
 static void setup_req_params(int drive)
@@ -1474,9 +1470,6 @@
 	int drive = minor(inode->i_rdev) & 3;
 	int old_dev;
 
-	if ((minor(inode->i_rdev) >> 2) > NUM_DISK_TYPES)
-		return -ENXIO;
-
 	old_dev = fd_device[drive];
 
 	if (fd_ref[drive])
@@ -1551,7 +1544,7 @@
 		return 0;
 
 	for (i = 0; i < FD_MAX_UNITS; i++) {
-		disks[i] = alloc_disk();
+		disks[i] = alloc_disk(1);
 		if (!disks[i])
 			goto out;
 	}
diff -Nru a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
--- a/drivers/acorn/block/mfmhd.c	Tue Oct 15 20:29:13 2002
+++ b/drivers/acorn/block/mfmhd.c	Tue Oct 15 20:29:13 2002
@@ -1186,14 +1186,6 @@
 	return 0;
 }
 
-static int mfm_open(struct inode *inode, struct file *file)
-{
-	int dev = DEVICE_NR(minor(inode->i_rdev));
-	if (dev >= mfm_drives)
-		return -ENODEV;
-	return 0;
-}
-
 /*
  * This is to handle various kernel command line parameters
  * specific to this driver.
@@ -1239,7 +1231,6 @@
 static struct block_device_operations mfm_fops =
 {
 	.owner		= THIS_MODULE,
-	.open		= mfm_open,
 	.ioctl		= mfm_ioctl,
 };
 
@@ -1336,12 +1327,11 @@
 		goto out3;
 	
 	for (i = 0; i < mfm_drives; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(64);
 		if (!disk)
 			goto Enomem;
 		disk->major = MAJOR_NR;
 		disk->first_minor = i << 6;
-		disk->minor_shift = 6;
 		disk->fops = &mfm_fops;
 		sprintf(disk->disk_name, "mfm%c", 'a'+i);
 		mfm_gendisk[i] = disk;
diff -Nru a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
--- a/drivers/acorn/char/Makefile	Tue Oct 15 20:29:12 2002
+++ b/drivers/acorn/char/Makefile	Tue Oct 15 20:29:12 2002
@@ -3,18 +3,11 @@
 #
 
 # All the objects that export symbols.
-obj-arc		:= keyb_arc.o
-obj-rpc		:= keyb_ps2.o
-obj-clps7500	:= keyb_ps2.o defkeymap-acorn.o
+obj-arc		:= keyb_arc.o defkeymap-acorn.o
 
-obj-$(CONFIG_RPCMOUSE)		+= mouse_rpc.o
-obj-$(CONFIG_ATOMWIDE_SERIAL)	+= serial-atomwide.o
-obj-$(CONFIG_DUALSP_SERIAL)	+= serial-dualsp.o
-obj-$(CONFIG_ARCH_ACORN)	+= defkeymap-acorn.o i2c.o pcf8583.o
+obj-$(CONFIG_ARCH_ACORN)	+= i2c.o pcf8583.o
 obj-$(CONFIG_L7200_KEYB)	+= defkeymap-l7200.o keyb_l7200.o
-
-# Do the i2c and rtc last
-obj-y		+= $(obj-$(MACHINE))
+obj-y				+= $(obj-$(MACHINE))
 
 include $(TOPDIR)/Rules.make
 
diff -Nru a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
--- a/drivers/acorn/char/i2c.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/acorn/char/i2c.c	Tue Oct 15 20:29:23 2002
@@ -132,7 +132,7 @@
 	if (rtc_command(RTC_GETDATETIME, &old_rtctm))
 		return 0;
 
-	new_rtctm.cs    = xtime.tv_usec / 10000;
+	new_rtctm.cs    = xtime.tv_nsec / 10000000;
 	new_rtctm.secs  = nowtime % 60;	nowtime /= 60;
 	new_rtctm.mins  = nowtime % 60;	nowtime /= 60;
 	new_rtctm.hours = nowtime % 24;
@@ -283,7 +283,7 @@
 		rtc_client = client;
 		get_rtc_time(&rtctm, &year);
 
-		xtime.tv_usec = rtctm.cs * 10000;
+		xtime.tv_nsec = rtctm.cs * 10000000;
 		xtime.tv_sec  = mktime(year, rtctm.mon, rtctm.mday,
 				       rtctm.hours, rtctm.mins, rtctm.secs);
 		set_rtc = k_set_rtc_time;
diff -Nru a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c
--- a/drivers/acorn/char/keyb_ps2.c	Tue Oct 15 20:29:15 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,416 +0,0 @@
-/*
- *  linux/drivers/acorn/char/keyb_ps2.c
- *
- *  Copyright (C) 2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Keyboard driver for RiscPC ARM Linux.
- *
- *  Note!!! This driver talks directly to the keyboard.
- */
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/ptrace.h>
-#include <linux/signal.h>
-#include <linux/timer.h>
-#include <linux/random.h>
-#include <linux/ctype.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/bitops.h>
-#include <asm/irq.h>
-#include <asm/hardware.h>
-#include <asm/keyboard.h>
-#include <asm/io.h>
-#include <asm/hardware/iomd.h>
-#include <asm/system.h>
-
-extern struct tasklet_struct keyboard_tasklet;
-extern void kbd_reset_kdown(void);
-int kbd_read_mask;
-
-#define TX_DONE 0
-#define TX_SENT 1
-#define TX_SEND 2
-
-static volatile int tx_state;
-
-#define VERSION 100
-
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-
-#define KBD_ESCAPEE0	0xe0		/* in */
-#define KBD_ESCAPEE1	0xe1		/* in */
-
-#define ESCE0(x)	(0xe000|(x))
-#define ESCE1(x)	(0xe100|(x))
-
-#define KBD_BAT		0xaa		/* in */
-#define KBD_SETLEDS	0xed		/* out */
-#define KBD_ECHO	0xee		/* in/out */
-#define KBD_BREAK	0xf0		/* in */
-#define KBD_TYPRATEDLY	0xf3		/* out */
-#define KBD_SCANENABLE	0xf4		/* out */
-#define KBD_DEFDISABLE	0xf5		/* out */
-#define KBD_DEFAULT	0xf6		/* out */
-#define KBD_ACK		0xfa		/* in */
-#define KBD_DIAGFAIL	0xfd		/* in */
-#define KBD_RESEND	0xfe		/* in/out */
-#define KBD_RESET	0xff		/* out */
-
-#define CODE_BREAK	1
-#define CODE_ESCAPEE0	2
-#define CODE_ESCAPEE1	4
-#define CODE_ESCAPE12	8
-
-#define K_NONE		0x7f
-#define K_ESC		0x00
-#define K_F1		0x01
-#define K_F2		0x02
-#define K_F3		0x03
-#define K_F4		0x04
-#define K_F5		0x05
-#define K_F6		0x06
-#define K_F7		0x07
-#define K_F8		0x08
-#define K_F9		0x09
-#define K_F10		0x0a
-#define K_F11		0x0b
-#define K_F12		0x0c
-#define K_PRNT		0x0d
-#define K_SCRL		0x0e
-#define K_BRK		0x0f
-#define K_AGR		0x10
-#define K_1		0x11
-#define K_2		0x12
-#define K_3		0x13
-#define K_4		0x14
-#define K_5		0x15
-#define K_6		0x16
-#define K_7		0x17
-#define K_8		0x18
-#define K_9		0x19
-#define K_0		0x1a
-#define K_MINS		0x1b
-#define K_EQLS		0x1c
-#define K_BKSP		0x1e
-#define K_INS		0x1f
-#define K_HOME		0x20
-#define K_PGUP		0x21
-#define K_NUML		0x22
-#define KP_SLH		0x23
-#define KP_STR		0x24
-#define KP_MNS		0x3a
-#define K_TAB		0x26
-#define K_Q		0x27
-#define K_W		0x28
-#define K_E		0x29
-#define K_R		0x2a
-#define K_T		0x2b
-#define K_Y		0x2c
-#define K_U		0x2d
-#define K_I		0x2e
-#define K_O		0x2f
-#define K_P		0x30
-#define K_LSBK		0x31
-#define K_RSBK		0x32
-#define K_ENTR		0x47
-#define K_DEL		0x34
-#define K_END		0x35
-#define K_PGDN		0x36
-#define KP_7		0x37
-#define KP_8		0x38
-#define KP_9		0x39
-#define KP_PLS		0x4b
-#define K_CAPS		0x5d
-#define K_A		0x3c
-#define K_S		0x3d
-#define K_D		0x3e
-#define K_F		0x3f
-#define K_G		0x40
-#define K_H		0x41
-#define K_J		0x42
-#define K_K		0x43
-#define K_L		0x44
-#define K_SEMI		0x45
-#define K_SQOT		0x46
-#define K_HASH		0x1d
-#define KP_4		0x48
-#define KP_5		0x49
-#define KP_6		0x4a
-#define K_LSFT		0x4c
-#define K_BSLH		0x33
-#define K_Z		0x4e
-#define K_X		0x4f
-#define K_C		0x50
-#define K_V		0x51
-#define K_B		0x52
-#define K_N		0x53
-#define K_M		0x54
-#define K_COMA		0x55
-#define K_DOT		0x56
-#define K_FSLH		0x57
-#define K_RSFT		0x58
-#define K_UP		0x59
-#define KP_1		0x5a
-#define KP_2		0x5b
-#define KP_3		0x5c
-#define KP_ENT		0x67
-#define K_LCTL		0x3b
-#define K_LALT		0x5e
-#define K_SPCE		0x5f
-#define K_RALT		0x60
-#define K_RCTL		0x61
-#define K_LEFT		0x62
-#define K_DOWN		0x63
-#define K_RGHT		0x64
-#define KP_0		0x65
-#define KP_DOT		0x66
-
-static unsigned char keycode_translate[256] =
-{
-/* 00 */  K_NONE, K_F9  , K_NONE, K_F5  , K_F3  , K_F1  , K_F2  , K_F12 ,
-/* 08 */  K_NONE, K_F10 , K_F8  , K_F6  , K_F4  , K_TAB , K_AGR , K_NONE,
-/* 10 */  K_NONE, K_LALT, K_LSFT, K_NONE, K_LCTL, K_Q   , K_1   , K_NONE,
-/* 18 */  K_NONE, K_NONE, K_Z   , K_S   , K_A   , K_W   , K_2   , K_NONE,
-/* 20 */  K_NONE, K_C   , K_X   , K_D   , K_E   , K_4   , K_3   , K_NONE,
-/* 28 */  K_NONE, K_SPCE, K_V   , K_F   , K_T   , K_R   , K_5   , K_NONE,
-/* 30 */  K_NONE, K_N   , K_B   , K_H   , K_G   , K_Y   , K_6   , K_NONE,
-/* 38 */  K_NONE, K_NONE, K_M   , K_J   , K_U   , K_7   , K_8   , K_NONE,
-/* 40 */  K_NONE, K_COMA, K_K   , K_I   , K_O   , K_0   , K_9   , K_NONE,
-/* 48 */  K_NONE, K_DOT , K_FSLH, K_L   , K_SEMI, K_P   , K_MINS, K_NONE,
-/* 50 */  K_NONE, K_NONE, K_SQOT, K_NONE, K_LSBK, K_EQLS, K_NONE, K_NONE,
-/* 58 */  K_CAPS, K_RSFT, K_ENTR, K_RSBK, K_NONE, K_HASH, K_NONE, K_NONE,
-/* 60 */  K_NONE, K_BSLH, K_NONE, K_NONE, K_NONE, K_NONE, K_BKSP, K_NONE,
-/* 68 */  K_NONE, KP_1  , K_NONE, KP_4  , KP_7  , K_NONE, K_NONE, K_NONE,
-/* 70 */  KP_0  , KP_DOT, KP_2  , KP_5  , KP_6  , KP_8  , K_ESC , K_NUML,
-/* 78 */  K_F11 , KP_PLS, KP_3  , KP_MNS, KP_STR, KP_9  , K_SCRL, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_F7  , K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE,
-	  K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE
-};
-
-#ifdef CONFIG_MAGIC_SYSRQ
-static unsigned char ps2kbd_sysrq_xlate[] = 
-{
-    27,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,
-   '`',  '1',  '2',  '3',  '4',  '5',  '6',  '7',
-   '8',  '9',  '0',  '-',  '=',  '£',  127,    0,
-     0,    0,    0,  '/',  '*',  '#',    9,  'q',
-   'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',
-   'p',  '[',  ']', '\\',  22,    23,   25,  '7',
-   '8',  '9',  '-',    0,  'a',  's',  'd',  'f',
-   'g',  'h',  'j',  'k',  'l',  ';', '\'',   13,
-   '4',  '5',  '6',  '+',    0,    0,  'z',  'x',
-   'c',  'v',  'b',  'n',  'm',  ',',  '.',  '/',
-     0,    0,  '1',  '2',  '3',    0,    0,  ' ',
-     0,    0,    0,    0,    0,  '0',  '.',   10,
-     0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,
-     0,    0,    0,    0,    0,    0,    0,    0,
-};
-#endif
-
-static inline void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
-{
-	handle_scancode(keycode, !up_flag);
-}
-
-static inline void ps2kbd_sendbyte(unsigned char val)
-{
-	int tries = 3, timeout = 1000;
-
-	tx_state = TX_SEND;
-
-	do {
-		switch (tx_state) {
-		case TX_SEND:
-			tx_state = TX_SENT;
-			timeout = 1000;
-			tries --;
-
-			while(!(iomd_readb(IOMD_KCTRL) & (1 << 7)));
-			iomd_writeb(val, IOMD_KARTTX);
-			break;
-
-		case TX_SENT:
-			udelay(1000);
-			if (--timeout == 0) {
-				printk(KERN_ERR "Keyboard timeout\n");
-				tx_state = TX_DONE;
-			}
-			break;
-
-		case TX_DONE:
-			break;
-		}
-	} while (tries > 0 && tx_state != TX_DONE);
-}
-
-static unsigned char status;
-static unsigned char ncodes;
-static unsigned char bi;
-static unsigned char buffer[4];
-
-static inline void ps2kbd_reset(void)
-{
-	status = 0;
-	kbd_reset_kdown();
-}
-
-static void handle_rawcode(int keyval)
-{
-	int keysym;
-
-	if (keyval > 0x83) {
-		switch (keyval) {
-		case KBD_ESCAPEE0:
-			ncodes = 2;
-			bi = 0;
-			break;
-
-		case KBD_ESCAPEE1:
-			ncodes = 3;
-			bi = 0;
-			break;
-
-		case KBD_ACK:
-			tx_state = TX_DONE;
-			return;
-
-		case KBD_RESEND:
-			tx_state = TX_SEND;
-			return;
-
-		case KBD_BREAK:
-			status |= CODE_BREAK;
-			return;
-
-		default:
-			return;
-		}
-	}
-
-	if (ncodes) {
-		buffer[bi++] = keyval;
-		ncodes -= 1;
-		if (ncodes)
-			return;
-		keysym = K_NONE;
-		switch (buffer[0] << 8 | buffer[1]) {
-		case ESCE0(0x11): keysym = K_RALT; break;
-		case ESCE0(0x14): keysym = K_RCTL; break;
-		/*
-		 * take care of MS extra keys (actually
-		 * 0x7d - 0x7f, but last one is already K_NONE
-		 */
-		case ESCE0(0x1f): keysym = 124;    break;
-		case ESCE0(0x27): keysym = 125;    break;
-		case ESCE0(0x2f): keysym = 126;    break;
-		case ESCE0(0x4a): keysym = KP_SLH; break;
-		case ESCE0(0x5a): keysym = KP_ENT; break;
-		case ESCE0(0x69): keysym = K_END;  break;
-		case ESCE0(0x6b): keysym = K_LEFT; break;
-		case ESCE0(0x6c): keysym = K_HOME; break;
-		case ESCE0(0x70): keysym = K_INS;  break;
-		case ESCE0(0x71): keysym = K_DEL;  break;
-		case ESCE0(0x72): keysym = K_DOWN; break;
-		case ESCE0(0x74): keysym = K_RGHT; break;
-		case ESCE0(0x75): keysym = K_UP;   break;
-		case ESCE0(0x7a): keysym = K_PGDN; break;
-		case ESCE0(0x7c): keysym = K_PRNT; break;
-		case ESCE0(0x7d): keysym = K_PGUP; break;
-		case ESCE1(0x14):
-			if (buffer[2] == 0x77)
-				keysym = K_BRK;
-			break;
-		case ESCE0(0x12):		/* ignore escaped shift key */
-			status = 0;
-			return;
-		}
-	} else {
-		bi = 0;
-		keysym = keycode_translate[keyval];
-	}
-
-	if (keysym != K_NONE)
-		ps2kbd_key(keysym, status & CODE_BREAK);
-	status = 0;
-}
-
-static void ps2kbd_leds(unsigned char leds)
-{
-	ps2kbd_sendbyte(KBD_SETLEDS);
-	ps2kbd_sendbyte(leds);
-	ps2kbd_sendbyte(KBD_SCANENABLE);
-}
-
-static void ps2kbd_rx(int irq, void *dev_id, struct pt_regs *regs)
-{
-	kbd_pt_regs = regs;
-
-	while (iomd_readb(IOMD_KCTRL) & (1 << 5))
-		handle_rawcode(iomd_readb(IOMD_KARTRX));
-	tasklet_schedule(&keyboard_tasklet);
-}
-
-static void ps2kbd_tx(int irq, void *dev_id, struct pt_regs *regs)
-{
-}
-
-static int ps2kbd_translate(unsigned char scancode, unsigned char *keycode, char rawmode)
-{
-	*keycode = scancode;
-	return 1;
-}
-
-static char ps2kbd_unexpected_up(unsigned char scancode)
-{
-	return 0200;
-}
-
-int __init ps2kbd_init_hw(void)
-{
-	/* Reset the keyboard state machine. */
-	iomd_writeb(0, IOMD_KCTRL);
-	iomd_writeb(8, IOMD_KCTRL);
-	iomd_readb(IOMD_KARTRX);
-
-	if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0)
-		panic("Could not allocate keyboard receive IRQ!");
-	if (request_irq (IRQ_KEYBOARDTX, ps2kbd_tx, 0, "keyboard", NULL) != 0)
-		panic("Could not allocate keyboard transmit IRQ!");
-
-	k_translate	= ps2kbd_translate;
-	k_unexpected_up	= ps2kbd_unexpected_up;
-	k_leds		= ps2kbd_leds;
-#ifdef CONFIG_MAGIC_SYSRQ
-	k_sysrq_xlate	= ps2kbd_sysrq_xlate;
-	k_sysrq_key	= 13;
-#endif
-
-	return 0;
-}
diff -Nru a/drivers/acorn/char/mouse_rpc.c b/drivers/acorn/char/mouse_rpc.c
--- a/drivers/acorn/char/mouse_rpc.c	Tue Oct 15 20:29:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,91 +0,0 @@
-/*
- *  linux/drivers/char/mouse_rpc.c
- *
- *  Copyright (C) 1996-1998 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  This handles the Acorn RiscPCs mouse.  We basically have a couple
- *  of hardware registers that track the sensor count for the X-Y movement
- *  and another register holding the button state.  On every VSYNC interrupt
- *  we read the complete state and then work out if something has changed.
- */
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/hardware/iomd.h>
-
-#include "../../char/busmouse.h"
-
-static short old_x, old_y, old_b;
-static int mousedev;
-
-void
-mouse_rpc_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	short x, y, dx, dy;
-	int buttons;
-
-	x = (short)iomd_readl(IOMD_MOUSEX);
-	y = (short)iomd_readl(IOMD_MOUSEY);
-	buttons = (__raw_readl(0xe0310000) >> 4) & 7;
-
-	dx = x - old_x;
-	old_x = x;
-	dy = y - old_y;
-	old_y = y;
-
-	if (dx || dy || buttons != old_b) {
-		busmouse_add_movementbuttons(mousedev, dx, dy, buttons);
-		old_b = buttons;
-	}
-}
-
-static struct busmouse rpcmouse = {
-	6, "arcmouse", NULL, NULL, NULL, 7
-};
-
-static int __init mouse_rpc_init(void)
-{
-	mousedev = register_busmouse(&rpcmouse);
-
-	if (mousedev < 0)
-		printk("rpcmouse: could not register mouse driver\n");
-	else {
-		old_x = (short)iomd_readl(IOMD_MOUSEX);
-		old_y = (short)iomd_readl(IOMD_MOUSEY);
-		old_b = (__raw_readl(0xe0310000) >> 4) & 7;
-		if (request_irq(IRQ_VSYNCPULSE, mouse_rpc_irq, SA_SHIRQ, "mouse", &mousedev)) {
-			printk("rpcmouse: unable to allocate VSYNC interrupt\n");
-			unregister_busmouse(mousedev);
-			mousedev = -1;
-		}
-	}
-
-	return mousedev >= 0 ? 0 : -ENODEV;
-}
-
-static void __exit mouse_rpc_exit(void)
-{
-	if (mousedev >= 0) {
-		unregister_busmouse(mousedev);
-		free_irq(IRQ_VSYNCPULSE, &mousedev);
-	}
-}
-
-module_init(mouse_rpc_init);
-module_exit(mouse_rpc_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("RiscPC mouse driver");
-MODULE_LICENSE("GPL");
-
diff -Nru a/drivers/acorn/char/serial-atomwide.c b/drivers/acorn/char/serial-atomwide.c
--- a/drivers/acorn/char/serial-atomwide.c	Tue Oct 15 20:29:19 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-/*
- *  linux/arch/arm/drivers/char/serial-atomwide.c
- *
- *  Copyright (C) 1996 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Changelog:
- *   02-05-1996	RMK	Created
- *   07-05-1996	RMK	Altered for greater number of cards.
- *   30-07-1996	RMK	Now uses generic card code.
- */
-#define MY_CARD_LIST { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL }
-#define MY_NUMPORTS 3
-#define MY_BAUD_BASE (7372800 / 16)
-#define MY_BASE_ADDRESS(ec) \
-	ecard_address ((ec), ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2)
-#define MY_PORT_ADDRESS(port,cardaddr) \
-	((cardaddr) + 0x200 - (port) * 0x100)
-
-#include "serial-card.c"
diff -Nru a/drivers/acorn/char/serial-card.c b/drivers/acorn/char/serial-card.c
--- a/drivers/acorn/char/serial-card.c	Tue Oct 15 20:29:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,120 +0,0 @@
-/*
- *  linux/drivers/acorn/char/serial-card.c
- *
- *  Copyright (C) 1996-1999 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * A generic handler of serial expansion cards that use 16550s or
- * the like.
- *
- * Definitions:
- *  MY_PRODS		Product numbers to identify this card by
- *  MY_MANUS		Manufacturer numbers to identify this card by
- *  MY_NUMPORTS		Number of ports per card
- *  MY_BAUD_BASE	Baud base for the card
- *  MY_INIT		Initialisation routine name
- *  MY_BASE_ADDRESS(ec)	Return base address for ports
- *  MY_PORT_ADDRESS
- *	(port,cardaddr)	Return address for port using base address
- *			from above.
- *
- * Changelog:
- *  30-07-1996	RMK	Created
- *  22-04-1998	RMK	Removed old register_pre_init_serial
- */
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/serial.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-#include <asm/string.h>
-
-#ifndef NUM_SERIALS
-#define NUM_SERIALS	MY_NUMPORTS * MAX_ECARDS
-#endif
-
-static int serial_ports[NUM_SERIALS];
-static int serial_pcount;
-static int serial_addr[NUM_SERIALS];
-static struct expansion_card *expcard[MAX_ECARDS];
-
-static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } };
-
-static inline int serial_register_onedev (unsigned long port, int irq)
-{
-	struct serial_struct req;
-
-	memset(&req, 0, sizeof(req));
-	req.baud_base = MY_BAUD_BASE;
-	req.irq = irq;
-	req.port = port;
-	req.flags = 0;
-
-	return register_serial(&req);
-}
-
-static int __init serial_card_init(void)
-{
-	int card = 0;
-
-	ecard_startfind ();
-
-	do {
-		struct expansion_card *ec;
-		unsigned long cardaddr;
-		int port;
-
-		ec = ecard_find (0, serial_cids);
-		if (!ec)
-			break;
-
-		cardaddr = MY_BASE_ADDRESS(ec);
-
-		for (port = 0; port < MY_NUMPORTS; port ++) {
-			unsigned long address;
-			int line;
-
-			address = MY_PORT_ADDRESS(port, cardaddr);
-
-			line = serial_register_onedev (address, ec->irq);
-			if (line < 0)
-				break;
-			serial_ports[serial_pcount] = line;
-			serial_addr[serial_pcount] = address;
-			serial_pcount += 1;
-		}
-
-		if (port) {
-			ecard_claim (ec);
-			expcard[card] = ec;
-		} else
-			break;
-	} while (++card < MAX_ECARDS);
-	return card ? 0 : -ENODEV;
-}
-
-static void __exit serial_card_exit(void)
-{
-	int i;
-
-	for (i = 0; i < serial_pcount; i++) {
-		unregister_serial(serial_ports[i]);
-		release_region(serial_addr[i], 8);
-	}
-
-	for (i = 0; i < MAX_ECARDS; i++)
-		if (expcard[i])
-			ecard_release (expcard[i]);
-}
-
-MODULE_AUTHOR("Russell King");
-MODULE_LICENSE("GPL");
-
-module_init(serial_card_init);
-module_exit(serial_card_exit);
diff -Nru a/drivers/acorn/char/serial-dualsp.c b/drivers/acorn/char/serial-dualsp.c
--- a/drivers/acorn/char/serial-dualsp.c	Tue Oct 15 20:29:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,21 +0,0 @@
-/*
- *  linux/drivers/acorn/char/serial-dualsp.c
- *
- *  Copyright (C) 1996 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- *  Changelog:
- *   30-07-1996	RMK	Created
- */
-#define MY_CARD_LIST { MANU_SERPORT, PROD_SERPORT_DSPORT }
-#define MY_NUMPORTS 2
-#define MY_BAUD_BASE (3686400 / 16)
-#define MY_BASE_ADDRESS(ec) \
-	ecard_address (ec, ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2)
-#define MY_PORT_ADDRESS(port,cardaddress) \
-	((cardaddress) + (port) * 8)
-
-#include "serial-card.c"
diff -Nru a/drivers/acorn/net/ether1.c b/drivers/acorn/net/ether1.c
--- a/drivers/acorn/net/ether1.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/acorn/net/ether1.c	Tue Oct 15 20:29:17 2002
@@ -43,6 +43,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -80,11 +81,6 @@
 #define BUS_16 16
 #define BUS_8  8
 
-static const card_ids __init ether1_cids[] = {
-	{ MANU_ACORN, PROD_ACORN_ETHER1 },
-	{ 0xffff, 0xffff }
-};
-
 /* ------------------------------------------------------------------------- */
 
 #define DISABLEIRQS 1
@@ -647,6 +643,12 @@
 {
 	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
 
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
+			dev->name);
+		return -EINVAL;
+	}
+
 	if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
 		return -EAGAIN;
 
@@ -971,6 +973,23 @@
 	return &priv->stats;
 }
 
+static int
+ether1_set_mac_address(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	/*
+	 * We'll set the MAC address on the chip when we open it.
+	 */
+
+	return 0;
+}
+
 /*
  * Set or clear the multicast filter for this adaptor.
  * num_addrs == -1	Promiscuous mode, receive all packets.
@@ -993,19 +1012,22 @@
 		printk(KERN_INFO "%s", version);
 }
 
-static struct net_device * __init ether1_init_one(struct expansion_card *ec)
+static int __devinit
+ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
 	struct net_device *dev;
 	struct ether1_priv *priv;
-	int i;
+	int i, ret = 0;
 
 	ether1_banner();
 
 	ecard_claim(ec);
 
 	dev = init_etherdev(NULL, sizeof(struct ether1_priv));
-	if (!dev)
+	if (!dev) {
+		ret = -ENOMEM;
 		goto out;
+	}
 
 	SET_MODULE_OWNER(dev);
 
@@ -1019,8 +1041,10 @@
 	request_region(dev->base_addr + 0x800, 4096, dev->name);
 
 	priv = (struct ether1_priv *)dev->priv;
-	if ((priv->bus_type = ether1_reset(dev)) == 0)
+	if ((priv->bus_type = ether1_reset(dev)) == 0) {
+		ret = -ENODEV;
 		goto release;
+	}
 
 	printk(KERN_INFO "%s: ether1 in slot %d, ",
 		dev->name, ec->slot_no);
@@ -1030,16 +1054,21 @@
 		printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
 	}
 
-	if (ether1_init_2(dev))
+	if (ether1_init_2(dev)) {
+		ret = -ENODEV;
 		goto release;
+	}
 
 	dev->open		= ether1_open;
 	dev->stop		= ether1_close;
 	dev->hard_start_xmit    = ether1_sendpacket;
 	dev->get_stats		= ether1_getstats;
 	dev->set_multicast_list = ether1_setmulticastlist;
+	dev->set_mac_address	= ether1_set_mac_address;
 	dev->tx_timeout		= ether1_timeout;
 	dev->watchdog_timeo	= 5 * HZ / 100;
+
+	ecard_set_drvdata(ec, dev);
 	return 0;
 
 release:
@@ -1049,55 +1078,46 @@
 	kfree(dev);
 out:
 	ecard_release(ec);
-	return dev;
+	return ret;
 }
 
-static struct expansion_card	*e_card[MAX_ECARDS];
-static struct net_device	*e_dev[MAX_ECARDS];
-
-static int __init ether1_init(void)
+static void __devexit ether1_remove(struct expansion_card *ec)
 {
-	int i, ret = -ENODEV;
+	struct net_device *dev = ecard_get_drvdata(ec);
 
-	ecard_startfind();
+	ecard_set_drvdata(ec, NULL);	
 
-	for (i = 0; i < MAX_ECARDS; i++) {
-		struct expansion_card *ec;
-		struct net_device *dev;
+	unregister_netdev(dev);
 
-		ec = ecard_find(0, ether1_cids);
-		if (!ec)
-			break;
+	release_region(dev->base_addr, 16);
+	release_region(dev->base_addr + 0x800, 4096);
+	kfree(dev);
 
-		dev = ether1_init_one(ec);
-		if (!dev)
-			break;
+	ecard_release(ec);
+}
 
-		e_card[i] = ec;
-		e_dev[i]  = dev;
-		ret = 0;
-	}
+static const struct ecard_id ether1_ids[] = {
+	{ MANU_ACORN, PROD_ACORN_ETHER1 },
+	{ 0xffff, 0xffff }
+};
 
-	return ret;
+static struct ecard_driver ether1_driver = {
+	.probe		= ether1_probe,
+	.remove		= __devexit_p(ether1_remove),
+	.id_table	= ether1_ids,
+	.drv = {
+		.name	= "ether1",
+	},
+};
+
+static int __init ether1_init(void)
+{
+	return ecard_register_driver(&ether1_driver);
 }
 
 static void __exit ether1_exit(void)
 {
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++) {
-		if (e_dev[i]) {
-			unregister_netdev(e_dev[i]);
-			release_region(e_dev[i]->base_addr, 16);
-			release_region(e_dev[i]->base_addr + 0x800, 4096);
-			kfree(e_dev[i]);
-			e_dev[i] = NULL;
-		}
-		if (e_card[i]) {
-			ecard_release(e_card[i]);
-			e_card[i] = NULL;
-		}
-	}
+	ecard_remove_driver(&ether1_driver);
 }
 
 module_init(ether1_init);
diff -Nru a/drivers/acorn/net/ether3.c b/drivers/acorn/net/ether3.c
--- a/drivers/acorn/net/ether3.c	Tue Oct 15 20:29:22 2002
+++ b/drivers/acorn/net/ether3.c	Tue Oct 15 20:29:22 2002
@@ -61,6 +61,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 
@@ -75,12 +76,6 @@
 #include "ether3.h"
 
 static unsigned int net_debug = NET_DEBUG;
-static const card_ids __init ether3_cids[] = {
-	{ MANU_ANT2, PROD_ANT_ETHER3 },
-	{ MANU_ANT,  PROD_ANT_ETHER3 },
-	{ MANU_ANT,  PROD_ANT_ETHERB },
-	{ 0xffff, 0xffff }
-};
 
 static void	ether3_setmulticastlist(struct net_device *dev);
 static int	ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
@@ -417,6 +412,12 @@
 static int
 ether3_open(struct net_device *dev)
 {
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
+			dev->name);
+		return -EINVAL;
+	}
+
 	if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev))
 		return -EAGAIN;
 
@@ -460,6 +461,23 @@
 	return &priv->stats;
 }
 
+static int
+ether3_set_mac_address(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	/*
+	 * We'll set the MAC address on the chip when we open it.
+	 */
+
+	return 0;
+}
+
 /*
  * Set or clear promiscuous/multicast mode filter for this adaptor.
  *
@@ -784,6 +802,7 @@
 ether3_get_dev(struct net_device *dev, struct expansion_card *ec)
 {
 	const char *name = "ether3";
+
 	dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
 	dev->irq = ec->irq;
 
@@ -796,38 +815,44 @@
 	ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
 	ec->irqmask = 0xf0;
 
-	if (ether3_addr(dev->dev_addr, ec))
-		name = NULL;
+	ether3_addr(dev->dev_addr, ec);
 
 	return name;
 }
 
-static struct net_device * __init ether3_init_one(struct expansion_card *ec)
+static int __devinit
+ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
 	struct net_device *dev;
 	struct dev_priv *priv;
 	const char *name;
-	int i, bus_type;
+	int i, bus_type, ret;
 
 	ether3_banner();
 
 	ecard_claim(ec);
 
 	dev = init_etherdev(NULL, sizeof(struct dev_priv));
-	if (!dev)
+	if (!dev) {
+		ret = -ENOMEM;
 		goto out;
+	}
 
 	SET_MODULE_OWNER(dev);
 
 	name = ether3_get_dev(dev, ec);
-	if (!name)
+	if (!name) {
+		ret = -ENODEV;
 		goto free;
+	}
 
 	/*
 	 * this will not fail - the nature of the bus ensures this
 	 */
-	if (!request_region(dev->base_addr, 128, dev->name))
+	if (!request_region(dev->base_addr, 128, dev->name)) {
+		ret = -EBUSY;
 		goto free;
+	}
 
 	priv = (struct dev_priv *) dev->priv;
 
@@ -852,11 +877,13 @@
 	switch (bus_type) {
 	case BUS_UNKNOWN:
 		printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
+		ret = -ENODEV;
 		goto failed;
 
 	case BUS_8:
 		printk(KERN_ERR "%s: %s found, but is an unsupported "
 			"8-bit card\n", dev->name, name);
+		ret = -ENODEV;
 		goto failed;
 
 	default:
@@ -867,16 +894,21 @@
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
 
-	if (ether3_init_2(dev))
+	if (ether3_init_2(dev)) {
+		ret = -ENODEV;
 		goto failed;
+	}
 
 	dev->open		= ether3_open;
 	dev->stop		= ether3_close;
 	dev->hard_start_xmit	= ether3_sendpacket;
 	dev->get_stats		= ether3_getstats;
 	dev->set_multicast_list	= ether3_setmulticastlist;
+	dev->set_mac_address	= ether3_set_mac_address;
 	dev->tx_timeout		= ether3_timeout;
 	dev->watchdog_timeo	= 5 * HZ / 100;
+
+	ecard_set_drvdata(ec, dev);
 	return 0;
 
 failed:
@@ -886,54 +918,46 @@
 	kfree(dev);
 out:
 	ecard_release(ec);
-	return NULL;
+	return ret;
 }
 
-static struct expansion_card	*e_card[MAX_ECARDS];
-static struct net_device	*e_dev[MAX_ECARDS];
-
-static int ether3_init(void)
+static void __devexit ether3_remove(struct expansion_card *ec)
 {
-	int i, ret = -ENODEV;
+	struct net_device *dev = ecard_get_drvdata(ec);
 
-	ecard_startfind();
+	ecard_set_drvdata(ec, NULL);
 
-	for (i = 0; i < MAX_ECARDS; i++) {
-		struct net_device *dev;
-		struct expansion_card *ec;
+	unregister_netdev(dev);
+	release_region(dev->base_addr, 128);
+	kfree(dev);
 
-		ec = ecard_find(0, ether3_cids);
-		if (!ec)
-			break;
+	ecard_release(ec);
+}
 
-		dev = ether3_init_one(ec);
-		if (!dev)
-			break;
+static const struct ecard_id ether3_ids[] = {
+	{ MANU_ANT2, PROD_ANT_ETHER3 },
+	{ MANU_ANT,  PROD_ANT_ETHER3 },
+	{ MANU_ANT,  PROD_ANT_ETHERB },
+	{ 0xffff, 0xffff }
+};
 
-		e_card[i] = ec;
-		e_dev[i]  = dev;
-		ret = 0;
-	}
+static struct ecard_driver ether3_driver = {
+	.probe		= ether3_probe,
+	.remove		= __devexit_p(ether3_remove),
+	.id_table	= ether3_ids,
+	.drv = {
+		.name	= "ether3",
+	},
+};
 
-	return ret;
+static int __init ether3_init(void)
+{
+	return ecard_register_driver(&ether3_driver);
 }
 
-static void ether3_exit(void)
+static void __exit ether3_exit(void)
 {
-	int i;
-
-	for (i = 0; i < MAX_ECARDS; i++) {
-		if (e_dev[i]) {
-			unregister_netdev(e_dev[i]);
-			release_region(e_dev[i]->base_addr, 128);
-			kfree(e_dev[i]);
-			e_dev[i] = NULL;
-		}
-		if (e_card[i]) {
-			ecard_release(e_card[i]);
-			e_card[i] = NULL;
-		}
-	}
+	ecard_remove_driver(&ether3_driver);
 }
 
 module_init(ether3_init);
diff -Nru a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c
--- a/drivers/acorn/net/etherh.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/acorn/net/etherh.c	Tue Oct 15 20:29:20 2002
@@ -42,6 +42,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/init.h>
 
 #include <asm/system.h>
@@ -57,14 +58,6 @@
 
 static unsigned int net_debug = NET_DEBUG;
 
-static const card_ids __init etherh_cids[] = {
-	{ MANU_ANT, PROD_ANT_ETHERM      },
-	{ MANU_I3,  PROD_I3_ETHERLAN500  },
-	{ MANU_I3,  PROD_I3_ETHERLAN600  },
-	{ MANU_I3,  PROD_I3_ETHERLAN600A },
-	{ 0xffff,   0xffff }
-};
-
 struct etherh_priv {
 	struct ei_device eidev;
 	unsigned int	id;
@@ -441,6 +434,12 @@
 {
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
+			dev->name);
+		return -EINVAL;
+	}
+
 	if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))
 		return -EAGAIN;
 
@@ -483,6 +482,23 @@
 	return 0;
 }
 
+static int
+etherh_set_mac_address(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	/*
+	 * We'll set the MAC address on the chip when we open it.
+	 */
+
+	return 0;
+}
+
 /*
  * Initialisation
  */
@@ -541,21 +557,24 @@
 static u32 etherh_regoffsets[16];
 static u32 etherm_regoffsets[16];
 
-static struct net_device * __init etherh_init_one(struct expansion_card *ec)
+static int __init
+etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
 	struct ei_device *ei_local;
 	struct net_device *dev;
 	struct etherh_priv *eh;
 	const char *dev_type;
-	int i, size;
+	int i, size, ret;
 
 	etherh_banner();
 
 	ecard_claim(ec);
 	
 	dev = init_etherdev(NULL, sizeof(struct etherh_priv));
-	if (!dev)
+	if (!dev) {
+		ret = -ENOMEM;
 		goto out;
+	}
 
 	/*
 	 * init_etherdev allocs and zeros dev->priv
@@ -566,33 +585,33 @@
 
 	SET_MODULE_OWNER(dev);
 
-	dev->open	= etherh_open;
-	dev->stop	= etherh_close;
-	dev->set_config	= etherh_set_config;
-	dev->irq	= ec->irq;
-	dev->base_addr	= ecard_address(ec, ECARD_MEMC, 0);
-	dev->priv	= eh;
+	dev->open		= etherh_open;
+	dev->stop		= etherh_close;
+	dev->set_mac_address	= etherh_set_mac_address;
+	dev->set_config		= etherh_set_config;
+	dev->irq		= ec->irq;
+	dev->base_addr		= ecard_address(ec, ECARD_MEMC, 0);
 
 	/*
 	 * IRQ and control port handling
 	 */
-	ec->ops		= &etherh_ops;
-	ec->irq_data	= eh;
-	eh->ctrl	= 0;
-	eh->id		= ec->cid.product;
+	if (ec->irq != 11) {
+		ec->ops		= &etherh_ops;
+		ec->irq_data	= eh;
+	}
+	eh->ctrl		= 0;
+	eh->id			= ec->cid.product;
 
 	switch (ec->cid.product) {
 	case PROD_ANT_ETHERM:
-		if (etherm_addr(dev->dev_addr))
-			goto free;
+		etherm_addr(dev->dev_addr);
 		dev->base_addr += ETHERM_NS8390;
 		dev->mem_start  = dev->base_addr + ETHERM_DATAPORT;
 		eh->ctrl_port   = dev->base_addr + ETHERM_CTRLPORT;
 		break;
 
 	case PROD_I3_ETHERLAN500:
-		if (etherh_addr(dev->dev_addr, ec))
-			goto free;
+		etherh_addr(dev->dev_addr, ec);
 		dev->base_addr += ETHERH500_NS8390;
 		dev->mem_start  = dev->base_addr + ETHERH500_DATAPORT;
 		eh->ctrl_port   = ecard_address (ec, ECARD_IOC, ECARD_FAST)
@@ -601,8 +620,7 @@
 
 	case PROD_I3_ETHERLAN600:
 	case PROD_I3_ETHERLAN600A:
-		if (etherh_addr(dev->dev_addr, ec))
-			goto free;
+		etherh_addr(dev->dev_addr, ec);
 		dev->base_addr += ETHERH600_NS8390;
 		dev->mem_start  = dev->base_addr + ETHERH600_DATAPORT;
 		eh->ctrl_port   = dev->base_addr + ETHERH600_CTRLPORT;
@@ -611,6 +629,7 @@
 	default:
 		printk(KERN_ERR "%s: unknown card type %x\n",
 		       dev->name, ec->cid.product);
+		ret = -ENODEV;
 		goto free;
 	}
 
@@ -618,11 +637,15 @@
 	if (ec->cid.product == PROD_ANT_ETHERM)
 		size <<= 3;
 
-	if (!request_region(dev->base_addr, size, dev->name))
+	if (!request_region(dev->base_addr, size, dev->name)) {
+		ret = -EBUSY;
 		goto free;
+	}
 
-	if (ethdev_init(dev))
+	if (ethdev_init(dev)) {
+		ret = -ENODEV;
 		goto release;
+	}
 
 	/*
 	 * If we're in the NIC slot, make sure the IRQ is enabled
@@ -690,7 +713,10 @@
 
 	etherh_reset(dev);
 	NS8390_init(dev, 0);
-	return dev;
+
+	ecard_set_drvdata(ec, dev);
+
+	return 0;
 
 release:
 	release_region(dev->base_addr, 16);
@@ -700,67 +726,59 @@
 	kfree(dev);
 out:
 	ecard_release(ec);
-	return NULL;
+	return ret;
+}
+
+static void __devexit etherh_remove(struct expansion_card *ec)
+{
+	struct net_device *dev = ecard_get_drvdata(ec);
+	int size = 16;
+
+	ecard_set_drvdata(ec, NULL);
+
+	unregister_netdev(dev);
+	if (ec->cid.product == PROD_ANT_ETHERM)
+		size <<= 3;
+	release_region(dev->base_addr, size);
+	kfree(dev);
+
+	ec->ops = NULL;
+	kfree(ec->irq_data);
+	ecard_release(ec);
 }
 
-#define MAX_ETHERH_CARDS 2
+static const struct ecard_id etherh_ids[] = {
+	{ MANU_ANT, PROD_ANT_ETHERM      },
+	{ MANU_I3,  PROD_I3_ETHERLAN500  },
+	{ MANU_I3,  PROD_I3_ETHERLAN600  },
+	{ MANU_I3,  PROD_I3_ETHERLAN600A },
+	{ 0xffff,   0xffff }
+};
 
-static struct net_device *e_dev[MAX_ETHERH_CARDS];
-static struct expansion_card *e_card[MAX_ETHERH_CARDS];
+static struct ecard_driver etherh_driver = {
+	.probe		= etherh_probe,
+	.remove		= __devexit_p(etherh_remove),
+	.id_table	= etherh_ids,
+	.drv = {
+		.name	= "etherh",
+	},
+};
 
 static int __init etherh_init(void)
 {
-	int i, ret = -ENODEV;
+	int i;
 
 	for (i = 0; i < 16; i++) {
 		etherh_regoffsets[i] = i;
 		etherm_regoffsets[i] = i << 3;
 	}
 
-	ecard_startfind();
-
-	for (i = 0; i < MAX_ECARDS; i++) {
-		struct expansion_card *ec;
-		struct net_device *dev;
-
-		ec = ecard_find(0, etherh_cids);
-		if (!ec)
-			break;
-
-		dev = etherh_init_one(ec);
-		if (!dev)
-			break;
-
-		e_card[i] = ec;
-		e_dev[i]  = dev;
-		ret = 0;
-	}
-
-	return ret;
+	return ecard_register_driver(&etherh_driver);
 }
 
 static void __exit etherh_exit(void)
 {
-	int i;
-
-	for (i = 0; i < MAX_ETHERH_CARDS; i++) {
-		if (e_dev[i]) {
-			int size;
-			unregister_netdev(e_dev[i]);
-			size = 16;
-			if (e_card[i]->cid.product == PROD_ANT_ETHERM)
-				size <<= 3;
-			release_region(e_dev[i]->base_addr, size);
-			kfree(e_dev[i]);
-			e_dev[i] = NULL;
-		}
-		if (e_card[i]) {
-			e_card[i]->ops = NULL;
-			kfree(e_card[i]->irq_data);
-			ecard_release(e_card[i]);
-			e_card[i] = NULL;
-		}
-	}
+	ecard_remove_driver(&etherh_driver);
 }
 
 module_init(etherh_init);
diff -Nru a/drivers/acorn/scsi/acornscsi.c b/drivers/acorn/scsi/acornscsi.c
--- a/drivers/acorn/scsi/acornscsi.c	Tue Oct 15 20:29:10 2002
+++ b/drivers/acorn/scsi/acornscsi.c	Tue Oct 15 20:29:10 2002
@@ -319,12 +319,12 @@
 
     target_jiffies = jiffies + 1 + cs * HZ / 100;
 
-    save_flags(flags);
-    sti();
+    local_save_flags(flags);
+    local_irq_enable();
 
     while (time_before(jiffies, target_jiffies)) barrier();
 
-    restore_flags(flags);
+    local_irq_restore(flags);
 }
 
 static
@@ -403,8 +403,9 @@
     host->scsi.phase = PHASE_IDLE;
     host->scsi.disconnectable = 0;
 
+    memset(host->busyluns, 0, sizeof(host->busyluns));
+
     for (i = 0; i < 8; i++) {
-	host->busyluns[i] = 0;
 	host->device[i].sync_state = SYNC_NEGOCIATE;
 	host->device[i].disconnect_ok = 1;
     }
@@ -1593,7 +1594,7 @@
 	    printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
 		    host->host->host_no, acornscsi_target(host));
 	    host->SCpnt->device->tagged_queue = 0;
-	    set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns);
+	    set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, host->busyluns);
 	    break;
 #endif
 	case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):
@@ -2637,8 +2638,7 @@
 		printk("executing ");
 //#endif
 
-		save_flags(flags);
-		cli();
+		local_irq_save(flags);
 		switch (host->scsi.phase) {
 		/*
 		 * If the interface is idle, and the command is 'disconnectable',
@@ -2671,7 +2671,7 @@
 			acornscsi_abortcmd(host, host->SCpnt->tag);
 			res = res_snooze;
 		}
-		restore_flags(flags);
+		local_irq_restore(flags);
 	} else if (host->origSCpnt == SCpnt) {
 		/*
 		 * The command will be executed next, but a command
diff -Nru a/drivers/acorn/scsi/acornscsi.h b/drivers/acorn/scsi/acornscsi.h
--- a/drivers/acorn/scsi/acornscsi.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/acorn/scsi/acornscsi.h	Tue Oct 15 20:29:16 2002
@@ -326,7 +326,7 @@
 	syncxfer_t	sync_state;		/* sync xfer negociation state		*/
 	unsigned char	disconnect_ok:1;	/* device can disconnect		*/
     } device[8];
-    unsigned char	busyluns[8];		/* array of bits indicating LUNs busy	*/
+    unsigned long	busyluns[64 / sizeof(unsigned long)];/* array of bits indicating LUNs busy	*/
 
     /* DMA info */
     struct {
diff -Nru a/drivers/acorn/scsi/cumana_1.c b/drivers/acorn/scsi/cumana_1.c
--- a/drivers/acorn/scsi/cumana_1.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/acorn/scsi/cumana_1.c	Tue Oct 15 20:29:12 2002
@@ -83,11 +83,9 @@
 #define NCR5380_read(reg) cumanascsi_read(_instance, reg)
 #define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
 
-#define do_NCR5380_intr do_cumanascsi_intr
-#define NCR5380_queue_command cumanascsi_queue_command
-#define NCR5380_abort cumanascsi_abort
-#define NCR5380_reset cumanascsi_reset
-#define NCR5380_proc_info cumanascsi_proc_info
+#define NCR5380_intr		cumanascsi_intr
+#define NCR5380_queue_command	cumanascsi_queue_command
+#define NCR5380_proc_info	cumanascsi_proc_info
 
 int NCR5380_proc_info(char *buffer, char **start, off_t offset,
 		      int length, int hostno, int inout);
@@ -159,7 +157,7 @@
         outb(0x00, instance->io_port - 577);
 
 	if (instance->irq != IRQ_NONE)
-	    if (request_irq(instance->irq, do_cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) {
+	    if (request_irq(instance->irq, cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) {
 		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
 		    instance->host_no, instance->irq);
 		instance->irq = IRQ_NONE;
@@ -401,8 +399,10 @@
 	.release		= cumanascsi_release,
 	.info			= cumanascsi_info,
 	.queuecommand		= cumanascsi_queue_command,
-	.abort			= cumanascsi_abort,
-	.reset			= cumanascsi_reset,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
 	.bios_param		= scsicam_bios_param,
 	.can_queue		= 16,
 	.this_id		= 7,
diff -Nru a/drivers/acorn/scsi/ecoscsi.c b/drivers/acorn/scsi/ecoscsi.c
--- a/drivers/acorn/scsi/ecoscsi.c	Tue Oct 15 20:29:22 2002
+++ b/drivers/acorn/scsi/ecoscsi.c	Tue Oct 15 20:29:22 2002
@@ -248,11 +248,9 @@
 #define NCR5380_read(reg) ecoscsi_read(_instance, reg)
 #define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value)
 
-#define do_NCR5380_intr do_ecoscsi_intr
-#define NCR5380_queue_command ecoscsi_queue_command
-#define NCR5380_abort ecoscsi_abort
-#define NCR5380_reset ecoscsi_reset
-#define NCR5380_proc_info ecoscsi_proc_info
+#define NCR5380_intr		ecoscsi_intr
+#define NCR5380_queue_command	ecoscsi_queue_command
+#define NCR5380_proc_info	ecoscsi_proc_info
 
 int NCR5380_proc_info(char *buffer, char **start, off_t offset,
 		      int length, int hostno, int inout);
@@ -269,8 +267,10 @@
 	.release	= ecoscsi_release,
 	.info		= ecoscsi_info,
 	.queuecommand	= ecoscsi_queue_command,
-	.abort		= ecoscsi_abort,
-	.reset		= ecoscsi_reset,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
 	.can_queue	= 16,
 	.this_id	= 7,
 	.sg_tablesize	= SG_ALL,
diff -Nru a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c
--- a/drivers/acorn/scsi/fas216.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/acorn/scsi/fas216.c	Tue Oct 15 20:29:16 2002
@@ -603,7 +603,7 @@
 		 * next buffer.
 		 */
 		bytes_transferred -= SCp->this_residual;
-		if (!next_SCp(&info->scsi.SCp)) {
+		if (!next_SCp(&info->scsi.SCp) && bytes_transferred) {
 			printk(KERN_WARNING "scsi%d.%c: out of buffers\n",
 				info->host->host_no, '0' + info->SCpnt->target);
 			return;
@@ -2300,8 +2300,8 @@
 {
 	FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata;
 
-	printk("scsi%d.%c: "__FUNCTION__": called\n",
-		info->host->host_no, '0' + SCpnt->target);
+	printk("scsi%d.%c: %s: called\n",
+		info->host->host_no, '0' + SCpnt->target, __FUNCTION__);
 	return FAILED;
 }
 
@@ -2320,8 +2320,8 @@
 
 	info->stats.bus_resets += 1;
 
-	printk("scsi%d.%c: "__FUNCTION__": resetting bus\n",
-		info->host->host_no, '0' + SCpnt->target);
+	printk("scsi%d.%c: %s: resetting bus\n",
+		info->host->host_no, '0' + SCpnt->target, __FUNCTION__);
 
 	/*
 	 * Attempt to stop all activity on this interface.
@@ -2381,8 +2381,8 @@
 
 	fas216_checkmagic(info);
 
-	printk("scsi%d.%c: "__FUNCTION__": resetting host\n",
-		info->host->host_no, '0' + SCpnt->target);
+	printk("scsi%d.%c: %s: resetting host\n",
+		info->host->host_no, '0' + SCpnt->target, __FUNCTION__);
 
 	/*
 	 * Reset the SCSI chip.
diff -Nru a/drivers/acorn/scsi/fas216.h b/drivers/acorn/scsi/fas216.h
--- a/drivers/acorn/scsi/fas216.h	Tue Oct 15 20:29:23 2002
+++ b/drivers/acorn/scsi/fas216.h	Tue Oct 15 20:29:23 2002
@@ -288,7 +288,7 @@
 		neg_t		sync_state;		/* synchronous transfer mode		*/
 		neg_t		wide_state;		/* wide transfer mode			*/
 	} device[8];
-	unsigned char	busyluns[8];			/* array of bits indicating LUNs busy	*/
+	unsigned long	busyluns[64/sizeof(unsigned long)];/* array of bits indicating LUNs busy	*/
 
 	/* dma */
 	struct {
diff -Nru a/drivers/acorn/scsi/oak.c b/drivers/acorn/scsi/oak.c
--- a/drivers/acorn/scsi/oak.c	Tue Oct 15 20:29:10 2002
+++ b/drivers/acorn/scsi/oak.c	Tue Oct 15 20:29:10 2002
@@ -64,10 +64,8 @@
 
 #define NCR5380_read(reg)		oakscsi_read(_instance, reg)
 #define NCR5380_write(reg, value)	oakscsi_write(_instance, reg, value)
-#define do_NCR5380_intr			do_oakscsi_intr
+#define NCR5380_intr			oakscsi_intr
 #define NCR5380_queue_command		oakscsi_queue_command
-#define NCR5380_abort			oakscsi_abort
-#define NCR5380_reset			oakscsi_reset
 #define NCR5380_proc_info		oakscsi_proc_info
 
 int NCR5380_proc_info(char *buffer, char **start, off_t offset,
@@ -142,7 +140,7 @@
 	}
 
 	if (instance->irq != IRQ_NONE)
-	    if (request_irq(instance->irq, do_oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) {
+	    if (request_irq(instance->irq, oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) {
 		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
 		    instance->host_no, instance->irq);
 		instance->irq = IRQ_NONE;
@@ -264,8 +262,10 @@
 	.release	= oakscsi_release,
 	.info		= oakscsi_info,
 	.queuecommand	= oakscsi_queue_command,
-	.abort		= oakscsi_abort,
-	.reset		= oakscsi_reset,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
 	.can_queue	= 16,
 	.this_id	= 7,
 	.sg_tablesize	= SG_ALL,
diff -Nru a/drivers/acorn/scsi/queue.c b/drivers/acorn/scsi/queue.c
--- a/drivers/acorn/scsi/queue.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/acorn/scsi/queue.c	Tue Oct 15 20:29:12 2002
@@ -161,7 +161,7 @@
  *	     exclude - bit array of target&lun which is busy
  * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
  */
-Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, void *exclude)
+Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
 {
 	unsigned long flags;
 	struct list_head *l;
diff -Nru a/drivers/acorn/scsi/queue.h b/drivers/acorn/scsi/queue.h
--- a/drivers/acorn/scsi/queue.h	Tue Oct 15 20:29:17 2002
+++ b/drivers/acorn/scsi/queue.h	Tue Oct 15 20:29:17 2002
@@ -46,7 +46,7 @@
  *	     exclude - array of busy LUNs
  * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
  */
-extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, void *exclude);
+extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude);
 
 #define queue_add_cmd_ordered(queue,SCpnt) \
 	__queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE)
diff -Nru a/drivers/acorn/scsi/scsi.h b/drivers/acorn/scsi/scsi.h
--- a/drivers/acorn/scsi/scsi.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/acorn/scsi/scsi.h	Tue Oct 15 20:29:12 2002
@@ -51,7 +51,7 @@
 
 static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp)
 {
-	char c = SCp->ptr;
+	char c = *SCp->ptr;
 
 	SCp->ptr += 1;
 	SCp->this_residual -= 1;
@@ -63,7 +63,7 @@
 
 static inline void put_next_SCp_byte(Scsi_Pointer *SCp, unsigned char c)
 {
-	SCp->ptr = c;
+	*SCp->ptr = c;
 	SCp->ptr += 1;
 	SCp->this_residual -= 1;
 	if (SCp->this_residual == 0)
diff -Nru a/drivers/atm/iphase.c b/drivers/atm/iphase.c
--- a/drivers/atm/iphase.c	Tue Oct 15 20:29:22 2002
+++ b/drivers/atm/iphase.c	Tue Oct 15 20:29:22 2002
@@ -1158,18 +1158,6 @@
         }
 		  
         if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) {
-	   /* lets allocate an skb for now */  
-	   skb = alloc_skb(len, GFP_ATOMIC);  
-	   if (!skb)  
-	   {  
-              IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");)  
-              atomic_inc(&vcc->stats->rx_drop);
-              atm_return(vcc, atm_pdu2truesize(len));
-	      goto out_free_desc;
-	   }  
-        }
-        else {
-           IF_EVENT(printk("IA: Rx over the rx_quota %ld\n", vcc->rx_quota);)
            if (vcc->vci < 32)
               printk("Drop control packets\n");
 	      goto out_free_desc;
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/base/core.c	Tue Oct 15 20:29:12 2002
@@ -149,36 +149,16 @@
 	spin_unlock(&device_lock);
 }
 
-/**
- * device_register - register a device
- * @dev:	pointer to the device structure
- *
- * First, make sure that the device has a parent, create
- * a directory for it, then add it to the parent's list of
- * children.
- *
- * Maintains a global list of all devices, in depth-first ordering.
- * The head for that list is device_root.g_list.
- */
-int device_register(struct device *dev)
+int device_add(struct device *dev)
 {
 	int error;
 
 	if (!dev || !strlen(dev->bus_id))
 		return -EINVAL;
 
-	INIT_LIST_HEAD(&dev->node);
-	INIT_LIST_HEAD(&dev->children);
-	INIT_LIST_HEAD(&dev->g_list);
-	INIT_LIST_HEAD(&dev->driver_list);
-	INIT_LIST_HEAD(&dev->bus_list);
-	INIT_LIST_HEAD(&dev->intf_list);
-	spin_lock_init(&dev->lock);
-	atomic_set(&dev->refcount,2);
-	dev->present = 1;
 	spin_lock(&device_lock);
+	dev->present = 1;
 	if (dev->parent) {
-		get_device_locked(dev->parent);
 		list_add_tail(&dev->g_list,&dev->parent->g_list);
 		list_add_tail(&dev->node,&dev->parent->children);
 	} else
@@ -209,10 +189,48 @@
 		list_del_init(&dev->g_list);
 		list_del_init(&dev->node);
 		spin_unlock(&device_lock);
-		if (dev->parent)
-			put_device(dev->parent);
 	}
-	put_device(dev);
+	return error;
+}
+
+void device_initialize(struct device *dev)
+{
+	INIT_LIST_HEAD(&dev->node);
+	INIT_LIST_HEAD(&dev->children);
+	INIT_LIST_HEAD(&dev->g_list);
+	INIT_LIST_HEAD(&dev->driver_list);
+	INIT_LIST_HEAD(&dev->bus_list);
+	INIT_LIST_HEAD(&dev->intf_list);
+	spin_lock_init(&dev->lock);
+	atomic_set(&dev->refcount,1);
+	if (dev->parent)
+		get_device(dev->parent);
+}
+
+/**
+ * device_register - register a device
+ * @dev:	pointer to the device structure
+ *
+ * First, make sure that the device has a parent, create
+ * a directory for it, then add it to the parent's list of
+ * children.
+ *
+ * Maintains a global list of all devices, in depth-first ordering.
+ * The head for that list is device_root.g_list.
+ */
+int device_register(struct device *dev)
+{
+	int error;
+
+	if (!dev || !strlen(dev->bus_id))
+		return -EINVAL;
+
+	device_initialize(dev);
+	if (dev->parent)
+		get_device(dev->parent);
+	error = device_add(dev);
+	if (error && dev->parent)
+		put_device(dev->parent);
 	return error;
 }
 
@@ -257,16 +275,7 @@
 		put_device(parent);
 }
 
-/**
- * device_unregister - unlink device
- * @dev:	device going away
- *
- * The device has been removed from the system, so we disavow knowledge
- * of it. It might not be the final reference to the device, so we mark
- * it as !present, so no more references to it can be acquired.
- * In the end, we decrement the final reference count for it.
- */
-void device_unregister(struct device * dev)
+void device_del(struct device * dev)
 {
 	spin_lock(&device_lock);
 	dev->present = 0;
@@ -293,7 +302,20 @@
 
 	/* remove the driverfs directory */
 	device_remove_dir(dev);
+}
 
+/**
+ * device_unregister - unlink device
+ * @dev:	device going away
+ *
+ * The device has been removed from the system, so we disavow knowledge
+ * of it. It might not be the final reference to the device, so we mark
+ * it as !present, so no more references to it can be acquired.
+ * In the end, we decrement the final reference count for it.
+ */
+void device_unregister(struct device * dev)
+{
+	device_del(dev);
 	put_device(dev);
 }
 
diff -Nru a/drivers/block/Config.in b/drivers/block/Config.in
--- a/drivers/block/Config.in	Tue Oct 15 20:29:14 2002
+++ b/drivers/block/Config.in	Tue Oct 15 20:29:14 2002
@@ -49,7 +49,6 @@
 dep_bool '  Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM
 
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_PPC32" = "y" ]; then
-#   bool 'Support for Large Block Devices' CONFIG_LBD
-   define_bool CONFIG_LBD y
+   bool 'Support for Large Block Devices' CONFIG_LBD
 fi
 endmenu
diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c
--- a/drivers/block/DAC960.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/block/DAC960.c	Tue Oct 15 20:29:20 2002
@@ -1962,7 +1962,6 @@
 	sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n);
 	disk->major = MajorNumber;
 	disk->first_minor = n << DAC960_MaxPartitionsBits;
-	disk->minor_shift = DAC960_MaxPartitionsBits;
 	disk->fops = &DAC960_BlockDeviceOperations;
    }
   /*
@@ -2200,7 +2199,7 @@
 	}
       memset(Controller, 0, sizeof(DAC960_Controller_T));
       for (i = 0; i < DAC960_MaxLogicalDrives; i++) {
-		Controller->disks[i] = alloc_disk();
+		Controller->disks[i] = alloc_disk(1<<DAC960_MaxPartitionsBits);
 		if (!Controller->disks[i])
 			goto Enomem;
       }
diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile
--- a/drivers/block/Makefile	Tue Oct 15 20:29:20 2002
+++ b/drivers/block/Makefile	Tue Oct 15 20:29:20 2002
@@ -9,9 +9,9 @@
 #
 
 export-objs	:= elevator.o ll_rw_blk.o loop.o genhd.o acsi.o \
-		   block_ioctl.o deadline-iosched.o
+		   scsi_ioctl.o deadline-iosched.o
 
-obj-y	:= elevator.o ll_rw_blk.o blkpg.o genhd.o block_ioctl.o deadline-iosched.o
+obj-y	:= elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o deadline-iosched.o
 
 obj-$(CONFIG_MAC_FLOPPY)	+= swim3.o
 obj-$(CONFIG_BLK_DEV_FD)	+= floppy.o
diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c
--- a/drivers/block/acsi.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/block/acsi.c	Tue Oct 15 20:29:23 2002
@@ -1086,8 +1086,6 @@
 					   unsigned int cmd, unsigned long arg )
 {
 	int dev = DEVICE_NR(inode->i_rdev);
-	if (dev >= NDevices)
-		return -EINVAL;
 	switch (cmd) {
 	  case HDIO_GETGEO:
 		/* HDIO_GETGEO is supported more for getting the partition's
@@ -1130,13 +1128,8 @@
 
 static int acsi_open( struct inode * inode, struct file * filp )
 {
-	int  device;
-	struct acsi_info_struct *aip;
-
-	device = DEVICE_NR(inode->i_rdev);
-	if (device >= NDevices)
-		return -ENXIO;
-	aip = &acsi_info[device];
+	int device = DEVICE_NR(inode->i_rdev);
+	struct acsi_info_struct *aip = &acsi_info[device];
 
 	if (access_count[device] == 0 && aip->removable) {
 #if 0
@@ -1729,7 +1722,7 @@
 #endif
 	err = -ENOMEM;
 	for( i = 0; i < NDevices; ++i ) {
-		acsi_gendisk[i] = alloc_disk();
+		acsi_gendisk[i] = alloc_disk(16);
 		if (!acsi_gendisk[i])
 			goto out4;
 	}
@@ -1739,7 +1732,10 @@
 		sprintf(disk->disk_name, "ad%c", 'a'+i);
 		disk->major = MAJOR_NR;
 		disk->first_minor = i << 4;
-		disk->minor_shift = (acsi_info[i].type==HARDDISK)?4:0;
+		if (acsi_info[i].type != HARDDISK) {
+			disk->minor_shift = 0;
+			disk->minors = 1;
+		}
 		disk->fops = &acsi_fops;
 		set_capacity(disk, acsi_info[i].size);
 		add_disk(disk);
diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c
--- a/drivers/block/amiflop.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/block/amiflop.c	Tue Oct 15 20:29:16 2002
@@ -1607,9 +1607,6 @@
 		if (!kdev_same(old_dev, inode->i_rdev))
 			return -EBUSY;
 
-	if (unit[drive].type->code == FD_NODRIVE)
-		return -ENODEV;
-
 	if (filp && filp->f_mode & 3) {
 		check_disk_change(inode->i_bdev);
 		if (filp->f_mode & 2 ) {
@@ -1683,11 +1680,6 @@
 	int changed;
 	static int first_time = 1;
 
-	if (major(dev) != MAJOR_NR) {
-		printk(KERN_CRIT "floppy_change: not a floppy\n");
-		return 0;
-	}
-
 	if (first_time)
 		changed = first_time--;
 	else {
@@ -1735,7 +1727,7 @@
 		fd_probe(drive);
 		if (unit[drive].type->code == FD_NODRIVE)
 			continue;
-		disk = alloc_disk();
+		disk = alloc_disk(1);
 		if (!disk) {
 			unit[drive].type->code = FD_NODRIVE;
 			continue;
@@ -1751,7 +1743,6 @@
 		printk("fd%d ",drive);
 		disk->major = MAJOR_NR;
 		disk->first_minor = drive;
-		disk->minor_shift = 0;
 		disk->fops = &floppy_fops;
 		sprintf(disk->disk_name, "fd%d", drive);
 		set_capacity(disk, 880*2);
diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c
--- a/drivers/block/ataflop.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/block/ataflop.c	Tue Oct 15 20:29:12 2002
@@ -1358,12 +1358,6 @@
 static int check_floppy_change (kdev_t dev)
 {
 	unsigned int drive = minor(dev) & 0x03;
-
-	if (major(dev) != MAJOR_NR) {
-		printk(KERN_ERR "floppy_changed: not a floppy\n");
-		return 0;
-	}
-	
 	if (test_bit (drive, &fake_change)) {
 		/* simulated change (e.g. after formatting) */
 		return 1;
@@ -1855,17 +1849,11 @@
 
 static int floppy_open( struct inode *inode, struct file *filp )
 {
-	int drive, type;
-	int old_dev;
+	int drive = minor(inode->i_rdev) & 3;
+	int type  = minor(inode->i_rdev) >> 2;
+	int old_dev = fd_device[drive];
 
-	drive = minor(inode->i_rdev) & 3;
-	type  = minor(inode->i_rdev) >> 2;
 	DPRINT(("fd_open: type=%d\n",type));
-	if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS)
-		return -ENXIO;
-
-	old_dev = fd_device[drive];
-
 	if (fd_ref[drive] && old_dev != minor(inode->i_rdev))
 		return -EBUSY;
 
@@ -1949,7 +1937,7 @@
 	}
 
 	for (i = 0; i < FD_MAX_UNITS; i++) {
-		unit[i].disk = alloc_disk();
+		unit[i].disk = alloc_disk(1);
 		if (!unit[i].disk)
 			goto Enomem;
 	}
diff -Nru a/drivers/block/blkpg.c b/drivers/block/blkpg.c
--- a/drivers/block/blkpg.c	Tue Oct 15 20:29:12 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,310 +0,0 @@
-/*
- * Partition table and disk geometry handling
- *
- * This obsoletes the partition-handling code in genhd.c:
- * Userspace can look at a disk in arbitrary format and tell
- * the kernel what partitions there are on the disk, and how
- * these should be numbered.
- * It also allows one to repartition a disk that is being used.
- *
- * A single ioctl with lots of subfunctions:
- *
- * Device number stuff:
- *    get_whole_disk()          (given the device number of a partition, find
- *                               the device number of the encompassing disk)
- *    get_all_partitions()      (given the device number of a disk, return the
- *                               device numbers of all its known partitions)
- *
- * Partition stuff:
- *    add_partition()
- *    delete_partition()
- *    test_partition_in_use()   (also for test_disk_in_use)
- *
- * Geometry stuff:
- *    get_geometry()
- *    set_geometry()
- *    get_bios_drivedata()
- *
- * For today, only the partition stuff - aeb, 990515
- */
-
-#include <linux/errno.h>
-#include <linux/fs.h>			/* for BLKROSET, ... */
-#include <linux/sched.h>		/* for capable() */
-#include <linux/blk.h>			/* for set_device_ro() */
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/module.h>               /* for EXPORT_SYMBOL */
-#include <linux/backing-dev.h>
-#include <linux/buffer_head.h>
-
-#include <asm/uaccess.h>
-
-/*
- * What is the data describing a partition?
- *
- * 1. a device number (kdev_t)
- * 2. a starting sector and number of sectors (hd_struct)
- *    given in the part[] array of the gendisk structure for the drive.
- *
- * The number of sectors is replicated in the sizes[] array of
- * the gendisk structure for the major, which again is copied to
- * the blk_size[][] array.
- * (However, hd_struct has the number of 512-byte sectors,
- *  g->sizes[] and blk_size[][] have the number of 1024-byte blocks.)
- * Note that several drives may have the same major.
- */
-
-/*
- * Add a partition.
- *
- * returns: EINVAL: bad parameters
- *          ENXIO: cannot find drive
- *          EBUSY: proposed partition overlaps an existing one
- *                 or has the same number as an existing one
- *          0: all OK.
- */
-int add_partition(struct block_device *bdev, struct blkpg_partition *p)
-{
-	struct gendisk *g;
-	long long ppstart, pplength;
-	int part, i;
-
-	/* convert bytes to sectors */
-	ppstart = (p->start >> 9);
-	pplength = (p->length >> 9);
-
-	/* check for fit in a hd_struct */ 
-	if (sizeof(sector_t) == sizeof(long) && 
-	    sizeof(long long) > sizeof(long)) {
-		long pstart, plength;
-		pstart = ppstart;
-		plength = pplength;
-		if (pstart != ppstart || plength != pplength
-		    || pstart < 0 || plength < 0)
-			return -EINVAL;
-	}
-
-	/* find the drive major */
-	g = get_gendisk(bdev->bd_dev, &part);
-	if (!g)
-		return -ENXIO;
-
-	/* existing drive? */
-
-	/* drive and partition number OK? */
-	if (bdev != bdev->bd_contains)
-		return -EINVAL;
-	if (part)
-		BUG();
-	if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
-		return -EINVAL;
-
-	/* partition number in use? */
-	if (g->part[p->pno - 1].nr_sects != 0)
-		return -EBUSY;
-
-	/* overlap? */
-	for (i = 0; i < (1<<g->minor_shift) - 1; i++)
-		if (!(ppstart+pplength <= g->part[i].start_sect ||
-		      ppstart >= g->part[i].start_sect + g->part[i].nr_sects))
-			return -EBUSY;
-
-	/* all seems OK */
-	g->part[p->pno - 1].start_sect = ppstart;
-	g->part[p->pno - 1].nr_sects = pplength;
-	update_partition(g, p->pno);
-	return 0;
-}
-
-/*
- * Delete a partition given by partition number
- *
- * returns: EINVAL: bad parameters
- *          ENXIO: cannot find partition
- *          EBUSY: partition is busy
- *          0: all OK.
- *
- * Note that the dev argument refers to the entire disk, not the partition.
- */
-int del_partition(struct block_device *bdev, struct blkpg_partition *p)
-{
-	struct gendisk *g;
-	struct block_device *bdevp;
-	int part;
-	int holder;
-
-	/* find the drive major */
-	g = get_gendisk(bdev->bd_dev, &part);
-	if (!g)
-		return -ENXIO;
-	if (bdev != bdev->bd_contains)
-		return -EINVAL;
-	if (part)
-		BUG();
-	if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
-  		return -EINVAL;
-
-	/* existing drive and partition? */
-	if (g->part[p->pno - 1].nr_sects == 0)
-		return -ENXIO;
-
-	/* partition in use? Incomplete check for now. */
-	bdevp = bdget(MKDEV(g->major, g->first_minor + p->pno));
-	if (!bdevp)
-		return -ENOMEM;
-	if (bd_claim(bdevp, &holder) < 0) {
-		bdput(bdevp);
-		return -EBUSY;
-	}
-
-	/* all seems OK */
-	fsync_bdev(bdevp);
-	invalidate_bdev(bdevp, 0);
-
-	g->part[p->pno - 1].start_sect = 0;
-	g->part[p->pno - 1].nr_sects = 0;
-	update_partition(g, p->pno);
-	bd_release(bdevp);
-	bdput(bdevp);
-
-	return 0;
-}
-
-int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
-{
-	struct blkpg_ioctl_arg a;
-	struct blkpg_partition p;
-	int len;
-
-	if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
-		return -EFAULT;
-
-	switch (a.op) {
-		case BLKPG_ADD_PARTITION:
-		case BLKPG_DEL_PARTITION:
-			len = a.datalen;
-			if (len < sizeof(struct blkpg_partition))
-				return -EINVAL;
-			if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
-				return -EFAULT;
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			if (a.op == BLKPG_ADD_PARTITION)
-				return add_partition(bdev, &p);
-			else
-				return del_partition(bdev, &p);
-		default:
-			return -EINVAL;
-	}
-}
-
-/*
- * Common ioctl's for block devices
- */
-int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
-{
-	request_queue_t *q;
-	u64 ullval = 0;
-	int intval;
-	unsigned short usval;
-	kdev_t dev = to_kdev_t(bdev->bd_dev);
-	int holder;
-	struct backing_dev_info *bdi;
-
-	switch (cmd) {
-		case BLKROSET:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			if (get_user(intval, (int *)(arg)))
-				return -EFAULT;
-			set_device_ro(dev, intval);
-			return 0;
-		case BLKROGET:
-			intval = (bdev_read_only(bdev) != 0);
-			return put_user(intval, (int *)(arg));
-
-		case BLKRASET:
-		case BLKFRASET:
-			if(!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			bdi = blk_get_backing_dev_info(bdev);
-			if (bdi == NULL)
-				return -ENOTTY;
-			bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
-			return 0;
-
-		case BLKRAGET:
-		case BLKFRAGET:
-			if (!arg)
-				return -EINVAL;
-			bdi = blk_get_backing_dev_info(bdev);
-			if (bdi == NULL)
-				return -ENOTTY;
-			return put_user((bdi->ra_pages * PAGE_CACHE_SIZE) / 512,
-						(long *)arg);
-
-		case BLKSECTGET:
-			if ((q = bdev_get_queue(bdev)) == NULL)
-				return -EINVAL;
-
-			usval = q->max_sectors;
-			blk_put_queue(q);
-			return put_user(usval, (unsigned short *)arg);
-
-		case BLKFLSBUF:
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			fsync_bdev(bdev);
-			invalidate_bdev(bdev, 0);
-			return 0;
-
-		case BLKSSZGET:
-			/* get block device hardware sector size */
-			intval = bdev_hardsect_size(bdev);
-			return put_user(intval, (int *) arg);
-
-		case BLKGETSIZE: 
-		{
-			unsigned long ret;
-			/* size in sectors, works up to 2 TB */
-			ullval = bdev->bd_inode->i_size;
-			ret = ullval >> 9;
-			if ((u64)ret != (ullval >> 9))
-				return -EFBIG;
-			return put_user(ret, (unsigned long *) arg);
-		}
-		
-		case BLKGETSIZE64:
-			/* size in bytes */
-			ullval = bdev->bd_inode->i_size;
-			return put_user(ullval, (u64 *) arg);
-
-		case BLKPG:
-			return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg);
-		case BLKBSZGET:
-			/* get the logical block size (cf. BLKSSZGET) */
-			intval = block_size(bdev);
-			return put_user(intval, (int *) arg);
-
-		case BLKBSZSET:
-			/* set the logical block size */
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			if (!arg)
-				return -EINVAL;
-			if (get_user(intval, (int *) arg))
-				return -EFAULT;
-			if (intval > PAGE_SIZE || intval < 512 ||
-			    (intval & (intval - 1)))
-				return -EINVAL;
-			if (bd_claim(bdev, &holder) < 0)
-				return -EBUSY;
-			set_blocksize(bdev, intval);
-			bd_release(bdev);
-			return 0;
-
-		default:
-			return -EINVAL;
-	}
-}
diff -Nru a/drivers/block/block_ioctl.c b/drivers/block/block_ioctl.c
--- a/drivers/block/block_ioctl.c	Tue Oct 15 20:29:23 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2001 Jens Axboe <axboe@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public Licens
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
- *
- */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/swap.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/completion.h>
-
-#include <linux/cdrom.h>
-
-int blk_do_rq(request_queue_t *q, struct request *rq)
-{
-	DECLARE_COMPLETION(wait);
-	int err = 0;
-
-	rq->flags |= REQ_NOMERGE;
-	rq->waiting = &wait;
-	elv_add_request(q, rq, 1);
-	generic_unplug_device(q);
-	wait_for_completion(&wait);
-
-	/*
-	 * for now, never retry anything
-	 */
-	if (rq->errors)
-		err = -EIO;
-
-	return err;
-}
-
-int block_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
-{
-	request_queue_t *q;
-	struct request *rq;
-	int close = 0, err;
-
-	q = bdev_get_queue(bdev);
-	if (!q)
-		return -ENXIO;
-
-	switch (cmd) {
-		case CDROMCLOSETRAY:
-			close = 1;
-		case CDROMEJECT:
-			rq = blk_get_request(q, WRITE, __GFP_WAIT);
-			rq->flags = REQ_BLOCK_PC;
-			memset(rq->cmd, 0, sizeof(rq->cmd));
-			rq->cmd[0] = GPCMD_START_STOP_UNIT;
-			rq->cmd[4] = 0x02 + (close != 0);
-			err = blk_do_rq(q, rq);
-			blk_put_request(rq);
-			break;
-		default:
-			err = -ENOTTY;
-	}
-
-	blk_put_queue(q);
-	return err;
-}
-
-EXPORT_SYMBOL(block_ioctl);
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Tue Oct 15 20:29:22 2002
+++ b/drivers/block/cciss.c	Tue Oct 15 20:29:22 2002
@@ -740,7 +740,7 @@
 
 	for(i=0; i< NWD; i++) {
 		struct gendisk *disk = hba[ctlr]->gendisk[i];
-		if (disk->part)
+		if (disk->flags & GENHD_FL_UP)
 			del_gendisk(disk);
 	}
 
@@ -792,7 +792,7 @@
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 
 	/* invalidate the devices and deregister the disk */ 
-	if (disk->part)
+	if (disk->flags & GENHD_FL_UP)
 		del_gendisk(disk);
 	/* check to see if it was the last disk */
 	if (logvol == h->highest_lun) {
@@ -2274,7 +2274,7 @@
 	struct gendisk *disk[NWD];
 	int i, n;
 	for (n = 0; n < NWD; n++) {
-		disk[n] = alloc_disk();
+		disk[n] = alloc_disk(1 << NWD_SHIFT);
 		if (!disk[n])
 			goto out;
 	}
@@ -2447,7 +2447,6 @@
 		sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
 		disk->major = MAJOR_NR + i;
 		disk->first_minor = j << NWD_SHIFT;
-		disk->minor_shift = NWD_SHIFT;
 		if( !(drv->nr_blocks))
 			continue;
 		(BLK_DEFAULT_QUEUE(MAJOR_NR + i))->hardsect_size = drv->block_size;
@@ -2500,7 +2499,7 @@
 	/* remove it from the disk list */
 	for (j = 0; j < NWD; j++) {
 		struct gendisk *disk = hba[i]->gendisk[j];
-		if (disk->part)
+		if (disk->flags & GENHD_FL_UP)
 			del_gendisk(disk);
 	}
 
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/block/cpqarray.c	Tue Oct 15 20:29:12 2002
@@ -304,7 +304,7 @@
 		kfree(hba[i]->cmd_pool_bits);
 
 		for (j = 0; j < NWD; j++) {
-			if (ida_gendisk[i][j]->part)
+			if (ida_gendisk[i][j]->flags & GENHD_FL_UP)
 				del_gendisk(ida_gendisk[i][j]);
 			put_disk(ida_gendisk[i][j]);
 		}
@@ -358,7 +358,7 @@
 		}
 		num_cntlrs_reg++;
 		for (j=0; j<NWD; j++) {
-			ida_gendisk[i][j] = alloc_disk();
+			ida_gendisk[i][j] = alloc_disk(1 << NWD_SHIFT);
 			if (!ida_gendisk[i][j])
 				goto Enomem2;
 		}
@@ -405,7 +405,6 @@
 			sprintf(disk->disk_name, "ida/c%dd%d", i, j);
 			disk->major = MAJOR_NR + i;
 			disk->first_minor = j<<NWD_SHIFT;
-			disk->minor_shift = NWD_SHIFT;
 			disk->flags = GENHD_FL_DEVFS;
 			disk->fops = &ida_fops; 
 			if (!drv->nr_blks)
@@ -1428,7 +1427,7 @@
 	 */
 	for (i = 0; i < NWD; i++) {
 		struct gendisk *disk = ida_gendisk[ctlr][i];
-		if (disk->part)
+		if (disk->flags & GENDH_FL_UP)
 			del_gendisk(disk);
 	}
 	memset(hba[ctlr]->drv,            0, sizeof(drv_info_t)*NWD);
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/block/floppy.c	Tue Oct 15 20:29:12 2002
@@ -3488,16 +3488,6 @@
 			loc.start = 0;
 			return _COPYOUT(loc);
 		}
-
-		case BLKGETSIZE:
-			ECALL(get_floppy_geometry(drive, type, &g));
-			return put_user(g->size, (unsigned long *) param);
-
-		case BLKGETSIZE64:
-			ECALL(get_floppy_geometry(drive, type, &g));
-			return put_user((u64)g->size << 9, (u64 *) param);
-		/* BLKRRPART is not defined as floppies don't have
-		 * partition tables */
 	}
 
 	/* convert the old style command into a new style command */
@@ -4240,7 +4230,7 @@
 	raw_cmd = NULL;
 
 	for (i=0; i<N_DRIVE; i++) {
-		disks[i] = alloc_disk();
+		disks[i] = alloc_disk(1);
 		if (!disks[i])
 			goto Enomem;
 	}
diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/block/genhd.c	Tue Oct 15 20:29:16 2002
@@ -57,34 +57,13 @@
  * This function registers the partitioning information in @gp
  * with the kernel.
  */
-static void add_gendisk(struct gendisk *gp)
+void add_disk(struct gendisk *disk)
 {
-	struct hd_struct *p = NULL;
-
-	if (gp->minor_shift) {
-		size_t size = sizeof(struct hd_struct)*((1<<gp->minor_shift)-1);
-		p = kmalloc(size, GFP_KERNEL);
-		if (!p) {
-			printk(KERN_ERR "out of memory; no partitions for %s\n",
-				gp->disk_name);
-			gp->minor_shift = 0;
-		} else
-			memset(p, 0, size);
-	}
-	gp->part = p;
-
 	write_lock(&gendisk_lock);
-	list_add(&gp->list, &gendisks[gp->major].list);
-	if (gp->minor_shift)
-		list_add_tail(&gp->full_list, &gendisk_list);
-	else
-		INIT_LIST_HEAD(&gp->full_list);
+	list_add(&disk->list, &gendisks[disk->major].list);
+	list_add_tail(&disk->full_list, &gendisk_list);
 	write_unlock(&gendisk_lock);
-}
-
-void add_disk(struct gendisk *disk)
-{
-	add_gendisk(disk);
+	disk->flags |= GENHD_FL_UP;
 	register_disk(disk);
 }
 
@@ -118,6 +97,8 @@
 	read_lock(&gendisk_lock);
 	if (gendisks[major].get) {
 		disk = gendisks[major].get(minor);
+		if (disk)
+			get_disk(disk);
 		read_unlock(&gendisk_lock);
 		return disk;
 	}
@@ -125,8 +106,9 @@
 		disk = list_entry(p, struct gendisk, list);
 		if (disk->first_minor > minor)
 			continue;
-		if (disk->first_minor + (1<<disk->minor_shift) <= minor)
+		if (disk->first_minor + disk->minors <= minor)
 			continue;
+		get_disk(disk);
 		read_unlock(&gendisk_lock);
 		*part = minor - disk->first_minor;
 		return disk;
@@ -135,8 +117,6 @@
 	return NULL;
 }
 
-EXPORT_SYMBOL(get_gendisk);
-
 #ifdef CONFIG_PROC_FS
 /* iterator */
 static void *part_start(struct seq_file *part, loff_t *pos)
@@ -173,7 +153,7 @@
 		seq_puts(part, "major minor  #blocks  name\n\n");
 
 	/* Don't show non-partitionable devices or empty devices */
-	if (!get_capacity(sgp))
+	if (!get_capacity(sgp) || sgp->minors == 1)
 		return 0;
 
 	/* show the full disk and all non-0 size partitions of it */
@@ -181,7 +161,7 @@
 		sgp->major, sgp->first_minor,
 		(unsigned long long)get_capacity(sgp) >> 1,
 		disk_name(sgp, 0, buf));
-	for (n = 0; n < (1<<sgp->minor_shift) - 1; n++) {
+	for (n = 0; n < sgp->minors - 1; n++) {
 		if (sgp->part[n].nr_sects == 0)
 			continue;
 		seq_printf(part, "%4d  %4d %10llu %s\n",
@@ -210,6 +190,10 @@
 	.name		= "disk",
 };
 
+static struct bus_type disk_bus = {
+	name:		"block",
+};
+
 int __init device_init(void)
 {
 	int i;
@@ -218,6 +202,7 @@
 		INIT_LIST_HEAD(&gendisks[i].list);
 	blk_dev_init();
 	devclass_register(&disk_devclass);
+	bus_register(&disk_bus);
 	return 0;
 }
 
@@ -225,17 +210,51 @@
 
 EXPORT_SYMBOL(disk_devclass);
 
-struct gendisk *alloc_disk(void)
+static void disk_release(struct device *dev)
+{
+	struct gendisk *disk = dev->driver_data;
+	kfree(disk->part);
+	kfree(disk);
+}
+
+struct gendisk *alloc_disk(int minors)
 {
 	struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
-	if (disk)
+	if (disk) {
 		memset(disk, 0, sizeof(struct gendisk));
+		if (minors > 1) {
+			int size = (minors - 1) * sizeof(struct hd_struct);
+			disk->part = kmalloc(size, GFP_KERNEL);
+			if (!disk->part) {
+				kfree(disk);
+				return NULL;
+			}
+			memset(disk->part, 0, size);
+		}
+		disk->minors = minors;
+		while (minors >>= 1)
+			disk->minor_shift++;
+		INIT_LIST_HEAD(&disk->full_list);
+		disk->disk_dev.bus = &disk_bus;
+		disk->disk_dev.release = disk_release;
+		disk->disk_dev.driver_data = disk;
+		device_initialize(&disk->disk_dev);
+	}
+	return disk;
+}
+
+struct gendisk *get_disk(struct gendisk *disk)
+{
+	atomic_inc(&disk->disk_dev.refcount);
 	return disk;
 }
 
 void put_disk(struct gendisk *disk)
 {
-	kfree(disk);
+	if (disk)
+		put_device(&disk->disk_dev);
 }
+
 EXPORT_SYMBOL(alloc_disk);
+EXPORT_SYMBOL(get_disk);
 EXPORT_SYMBOL(put_disk);
diff -Nru a/drivers/block/ioctl.c b/drivers/block/ioctl.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/block/ioctl.c	Tue Oct 15 20:29:12 2002
@@ -0,0 +1,215 @@
+#include <linux/sched.h>		/* for capable() */
+#include <linux/blk.h>			/* for set_device_ro() */
+#include <linux/blkpg.h>
+#include <linux/backing-dev.h>
+#include <linux/buffer_head.h>
+#include <asm/uaccess.h>
+
+static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
+{
+	struct block_device *bdevp;
+	int holder;
+	struct gendisk *disk;
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	long long start, length;
+	int part;
+	int i;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
+		return -EFAULT;
+	if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+		return -EFAULT;
+	disk = bdev->bd_disk;
+	if (bdev != bdev->bd_contains)
+		return -EINVAL;
+	part = p.pno;
+	if (part <= 0 || part >= disk->minors)
+		return -EINVAL;
+	switch (a.op) {
+		case BLKPG_ADD_PARTITION:
+			start = p.start >> 9;
+			length = p.length >> 9;
+			/* check for fit in a hd_struct */ 
+			if (sizeof(sector_t) == sizeof(long) && 
+			    sizeof(long long) > sizeof(long)) {
+				long pstart = start, plength = length;
+				if (pstart != start || plength != length
+				    || pstart < 0 || plength < 0)
+					return -EINVAL;
+			}
+			/* partition number in use? */
+			if (disk->part[part - 1].nr_sects != 0)
+				return -EBUSY;
+			/* overlap? */
+			for (i = 0; i < disk->minors - 1; i++) {
+				struct hd_struct *s = &disk->part[i];
+				if (!(start+length <= s->start_sect ||
+				      start >= s->start_sect + s->nr_sects))
+					return -EBUSY;
+			}
+			/* all seems OK */
+			add_partition(disk, part, start, length);
+			return 0;
+		case BLKPG_DEL_PARTITION:
+			if (disk->part[part - 1].nr_sects == 0)
+				return -ENXIO;
+			/* partition in use? Incomplete check for now. */
+			bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part);
+			if (!bdevp)
+				return -ENOMEM;
+			if (bd_claim(bdevp, &holder) < 0) {
+				bdput(bdevp);
+				return -EBUSY;
+			}
+			/* all seems OK */
+			fsync_bdev(bdevp);
+			invalidate_bdev(bdevp, 0);
+
+			delete_partition(disk, part);
+			bd_release(bdevp);
+			bdput(bdevp);
+			return 0;
+		default:
+			return -EINVAL;
+	}
+}
+
+static int blkdev_reread_part(struct block_device *bdev)
+{
+	struct gendisk *disk = bdev->bd_disk;
+	int res;
+
+	if (disk->minors == 1 || bdev != bdev->bd_contains)
+		return -EINVAL;
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (down_trylock(&bdev->bd_sem))
+		return -EBUSY;
+	res = rescan_partitions(disk, bdev);
+	up(&bdev->bd_sem);
+	return res;
+}
+
+static int put_ushort(unsigned long arg, unsigned short val)
+{
+	return put_user(val, (unsigned short *)arg);
+}
+
+static int put_int(unsigned long arg, int val)
+{
+	return put_user(val, (int *)arg);
+}
+
+static int put_long(unsigned long arg, long val)
+{
+	return put_user(val, (long *)arg);
+}
+
+static int put_ulong(unsigned long arg, unsigned long val)
+{
+	return put_user(val, (unsigned long *)arg);
+}
+
+static int put_u64(unsigned long arg, u64 val)
+{
+	return put_user(val, (u64 *)arg);
+}
+
+int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
+			unsigned long arg)
+{
+	struct block_device *bdev = inode->i_bdev;
+	struct backing_dev_info *bdi;
+	int holder;
+	int ret, n;
+
+	switch (cmd) {
+	case BLKELVGET:
+	case BLKELVSET:
+		/* deprecated, use the /proc/iosched interface instead */
+		return -ENOTTY;
+	case BLKRAGET:
+	case BLKFRAGET:
+		if (!arg)
+			return -EINVAL;
+		bdi = blk_get_backing_dev_info(bdev);
+		if (bdi == NULL)
+			return -ENOTTY;
+		return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
+	case BLKROGET:
+		return put_int(arg, bdev_read_only(bdev) != 0);
+	case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */
+		return put_int(arg, block_size(bdev));
+	case BLKSSZGET: /* get block device hardware sector size */
+		return put_int(arg, bdev_hardsect_size(bdev));
+	case BLKSECTGET:
+		return put_ushort(arg, bdev->bd_queue->max_sectors);
+	case BLKRASET:
+	case BLKFRASET:
+		if(!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		bdi = blk_get_backing_dev_info(bdev);
+		if (bdi == NULL)
+			return -ENOTTY;
+		bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
+		return 0;
+	case BLKBSZSET:
+		/* set the logical block size */
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (!arg)
+			return -EINVAL;
+		if (get_user(n, (int *) arg))
+			return -EFAULT;
+		if (n > PAGE_SIZE || n < 512 || (n & (n - 1)))
+			return -EINVAL;
+		if (bd_claim(bdev, &holder) < 0)
+			return -EBUSY;
+		set_blocksize(bdev, n);
+		bd_release(bdev);
+		return 0;
+	case BLKPG:
+		return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg);
+	case BLKRRPART:
+		return blkdev_reread_part(bdev);
+	case BLKGETSIZE:
+		if ((bdev->bd_inode->i_size >> 9) > ~0UL)
+			return -EFBIG;
+		return put_ulong(arg, bdev->bd_inode->i_size >> 9);
+	case BLKGETSIZE64:
+		return put_u64(arg, bdev->bd_inode->i_size);
+	case BLKFLSBUF:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (bdev->bd_op->ioctl) {
+			ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
+			if (ret != -EINVAL)
+				return ret;
+		}
+		fsync_bdev(bdev);
+		invalidate_bdev(bdev, 0);
+		return 0;
+	case BLKROSET:
+		if (bdev->bd_op->ioctl) {
+			ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
+			if (ret != -EINVAL)
+				return ret;
+		}
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (get_user(n, (int *)(arg)))
+			return -EFAULT;
+		set_device_ro(to_kdev_t(bdev->bd_dev), n);
+		return 0;
+	default:
+		if (bdev->bd_op->ioctl) {
+			ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
+			if (ret != -EINVAL)
+				return ret;
+		}
+	}
+	return -ENOTTY;
+}
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/block/ll_rw_blk.c	Tue Oct 15 20:29:12 2002
@@ -1427,7 +1427,19 @@
 	int rw = rq_data_dir(rq);
 	unsigned int index;
 
-	index = disk_index(rq->rq_dev);
+	if (!rq->rq_disk)
+		return;
+
+	if (rw == READ) {
+		rq->rq_disk->rio += new_io;
+		rq->rq_disk->reads += nr_sectors;
+	} else if (rw == WRITE) {
+		rq->rq_disk->wio += new_io;
+		rq->rq_disk->writes += nr_sectors;
+	}
+
+	index = rq->rq_disk->first_minor >> rq->rq_disk->minor_shift;
+
 	if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
 		return;
 
@@ -1747,6 +1759,7 @@
 	req->waiting = NULL;
 	req->bio = req->biotail = bio;
 	req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev);
+	req->rq_disk = bio->bi_bdev->bd_disk;
 	add_request(q, req, insert_here);
 out:
 	if (freereq)
@@ -1878,7 +1891,7 @@
  */
 int submit_bio(int rw, struct bio *bio)
 {
-	int count = bio_sectors(bio) >> 1;
+	int count = bio_sectors(bio);
 
 	BUG_ON(!bio->bi_end_io);
 	BIO_BUG_ON(!bio->bi_size);
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/block/loop.c	Tue Oct 15 20:29:17 2002
@@ -1075,7 +1075,7 @@
 		goto out_mem;
 
 	for (i = 0; i < max_loop; i++) {
-		disks[i] = alloc_disk();
+		disks[i] = alloc_disk(1);
 		if (!disks[i])
 			goto out_mem2;
 	}
diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c
--- a/drivers/block/nbd.c	Tue Oct 15 20:29:13 2002
+++ b/drivers/block/nbd.c	Tue Oct 15 20:29:13 2002
@@ -507,7 +507,7 @@
 	}
 
 	for (i = 0; i < MAX_NBD; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(1);
 		if (!disk)
 			goto out;
 		nbd_dev[i].disk = disk;
@@ -537,7 +537,6 @@
 		nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
 		disk->major = MAJOR_NR;
 		disk->first_minor = i;
-		disk->minor_shift = 0;
 		disk->fops = &nbd_fops;
 		sprintf(disk->disk_name, "nbd%d", i);
 		set_capacity(disk, 0x3ffffe);
diff -Nru a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
--- a/drivers/block/paride/pcd.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/block/paride/pcd.c	Tue Oct 15 20:29:16 2002
@@ -281,7 +281,7 @@
 
 	pcd_drive_count = 0;
 	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(1);
 		if (!disk)
 			continue;
 		cd->disk = disk;
@@ -303,7 +303,6 @@
 		cd->info.mask = 0;
 		disk->major = major;
 		disk->first_minor = unit;
-		disk->minor_shift = 0;
 		strcpy(disk->disk_name, cd->name);	/* umm... */
 		disk->fops = &pcd_bdops;
 	}
diff -Nru a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
--- a/drivers/block/paride/pd.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/block/paride/pd.c	Tue Oct 15 20:29:20 2002
@@ -350,9 +350,6 @@
 	int unit = DEVICE_NR(inode->i_rdev);
 	struct pd_unit *disk = pd + unit;
 
-	if (unit >= PD_UNITS || !disk->present)
-		return -ENODEV;
-
 	disk->access++;
 
 	if (disk->removable) {
@@ -703,14 +700,13 @@
 	}
 	for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
 		if (disk->present) {
-			struct gendisk *p = alloc_disk();
+			struct gendisk *p = alloc_disk(1 << PD_BITS);
 			if (!p) {
 				disk->present = 0;
 				k--;
 				continue;
 			}
 			strcpy(p->disk_name, disk->name);
-			p->minor_shift = PD_BITS;
 			p->fops = &pd_fops;
 			p->major = major;
 			p->first_minor = unit << PD_BITS;
diff -Nru a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
--- a/drivers/block/paride/pf.c	Tue Oct 15 20:29:18 2002
+++ b/drivers/block/paride/pf.c	Tue Oct 15 20:29:18 2002
@@ -308,7 +308,7 @@
 
 	pf_drive_count = 0;
 	for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(1);
 		if (!disk)
 			continue;
 		pf->disk = disk;
@@ -320,7 +320,6 @@
 		disk->major = MAJOR_NR;
 		disk->first_minor = unit;
 		strcpy(disk->disk_name, pf->name);
-		disk->minor_shift = 0;
 		disk->fops = &pf_fops;
 		if (!(*drives[unit])[D_PRT])
 			pf_drive_count++;
@@ -331,9 +330,6 @@
 {
 	int unit = DEVICE_NR(inode->i_rdev);
 	struct pf_unit *pf = units + unit;
-
-	if ((unit >= PF_UNITS) || (!pf->present))
-		return -ENODEV;
 
 	pf_identify(pf);
 
diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
--- a/drivers/block/ps2esdi.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/block/ps2esdi.c	Tue Oct 15 20:29:11 2002
@@ -89,9 +89,6 @@
 static void ps2esdi_normal_interrupt_handler(u_int);
 static void ps2esdi_initial_reset_int_handler(u_int);
 static void ps2esdi_geometry_int_handler(u_int);
-
-static int ps2esdi_open(struct inode *inode, struct file *file);
-
 static int ps2esdi_ioctl(struct inode *inode, struct file *file,
 			 u_int cmd, u_long arg);
 
@@ -141,7 +138,6 @@
 static struct block_device_operations ps2esdi_fops =
 {
 	.owner		= THIS_MODULE,
-	.open		= ps2esdi_open,
 	.ioctl		= ps2esdi_ioctl,
 };
 
@@ -421,13 +417,12 @@
 
 	error = -ENOMEM;
 	for (i = 0; i < ps2esdi_drives; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(64);
 		if (!disk)
 			goto err_out4;
 		disk->major = MAJOR_NR;
 		disk->first_minor = i<<6;
 		sprintf(disk->disk_name, "ed%c", 'a'+i);
-		disk->minor_shift = 6;
 		disk->fops = &ps2esdi_fops;
 		ps2esdi_gendisk[i] = disk;
 	}
@@ -1074,15 +1069,6 @@
 
 #undef WAIT_FOR_STATUS
 
-}
-
-
-static int ps2esdi_open(struct inode *inode, struct file *file)
-{
-	int dev = DEVICE_NR(inode->i_rdev);
-	if (dev >= ps2esdi_drives)
-		return -ENODEV;
-	return 0;
 }
 
 static int ps2esdi_ioctl(struct inode *inode,
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/block/rd.c	Tue Oct 15 20:29:17 2002
@@ -291,8 +291,6 @@
 	if (cmd != BLKFLSBUF)
 		return -EINVAL;
 
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
 	/* special: we want to release the ramdisk memory,
 	   it's not like with the other blockdevices where
 	   this ioctl only flushes away the buffer cache. */
@@ -383,6 +381,7 @@
 		rd_bdev[unit]->bd_inode->i_mapping->a_ops = &ramdisk_aops;
 		rd_bdev[unit]->bd_inode->i_size = rd_length[unit];
 		rd_bdev[unit]->bd_queue = &blk_dev[MAJOR_NR].request_queue;
+		rd_bdev[unit]->bd_disk = get_disk(rd_disks[unit]);
 	}
 
 	return 0;
@@ -431,17 +430,16 @@
 	}
 
 #ifdef CONFIG_BLK_DEV_INITRD
-	initrd_disk = alloc_disk();
+	initrd_disk = alloc_disk(1);
 	if (!initrd_disk)
 		return -ENOMEM;
 	initrd_disk->major = MAJOR_NR;
 	initrd_disk->first_minor = INITRD_MINOR;
-	initrd_disk->minor_shift = 0;
 	initrd_disk->fops = &rd_bd_op;	
 	sprintf(initrd_disk->disk_name, "initrd");
 #endif
 	for (i = 0; i < NUM_RAMDISKS; i++) {
-		rd_disks[i] = alloc_disk();
+		rd_disks[i] = alloc_disk(1);
 		if (!rd_disks[i])
 			goto out;
 	}
@@ -460,7 +458,6 @@
 		rd_length[i] = rd_size << 10;
 		disk->major = MAJOR_NR;
 		disk->first_minor = i;
-		disk->minor_shift = 0;
 		disk->fops = &rd_bd_op;
 		sprintf(disk->disk_name, "rd%d", i);
 		set_capacity(disk, rd_size * 2);
diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/block/scsi_ioctl.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2001 Jens Axboe <axboe@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
+ *
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/swap.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/completion.h>
+#include <linux/cdrom.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+
+#include <asm/uaccess.h>
+
+int blk_do_rq(request_queue_t *q, struct request *rq)
+{
+	DECLARE_COMPLETION(wait);
+	int err = 0;
+
+	rq->flags |= REQ_NOMERGE;
+	rq->waiting = &wait;
+	elv_add_request(q, rq, 1);
+	generic_unplug_device(q);
+	wait_for_completion(&wait);
+
+	/*
+	 * for now, never retry anything
+	 */
+	if (rq->errors)
+		err = -EIO;
+
+	return err;
+}
+
+#include <scsi/sg.h>
+
+static int sg_get_version(int *p)
+{
+	static int sg_version_num = 30527;
+	return put_user(sg_version_num, p);
+}
+
+static int scsi_get_idlun(request_queue_t *q, int *p)
+{
+	return put_user(0, p);
+}
+
+static int scsi_get_bus(request_queue_t *q, int *p)
+{
+	return put_user(0, p);
+}
+
+static int sg_get_timeout(request_queue_t *q)
+{
+	return HZ;
+}
+
+static int sg_set_timeout(request_queue_t *q, int *p)
+{
+	int timeout;
+	int error = get_user(timeout, p);
+	return error;
+}
+
+static int reserved_size = 0;
+
+static int sg_get_reserved_size(request_queue_t *q, int *p)
+{
+	return put_user(reserved_size, p);
+}
+
+static int sg_set_reserved_size(request_queue_t *q, int *p)
+{
+	int size;
+	int error = get_user(size, p);
+	if (!error)
+		reserved_size = size;
+	return error;
+}
+
+static int sg_emulated_host(request_queue_t *q, int *p)
+{
+	return put_user(1, p);
+}
+
+static int sg_io(request_queue_t *q, struct sg_io_hdr *uptr)
+{
+	int err;
+	struct sg_io_hdr hdr;
+	struct request *rq;
+	void *buffer;
+
+	if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr)))
+		return -EFAULT;
+	if (copy_from_user(&hdr, uptr, sizeof(*uptr)))
+		return -EFAULT;
+
+	if ( hdr.cmd_len > sizeof(rq->cmd) )
+		return -EINVAL;
+
+	buffer = NULL;
+	if (hdr.dxfer_len) {
+		unsigned int bytes = (hdr.dxfer_len + 511) & ~511;
+
+		switch (hdr.dxfer_direction) {
+		default:
+			return -EINVAL;
+		case SG_DXFER_TO_DEV:
+		case SG_DXFER_FROM_DEV:
+		case SG_DXFER_TO_FROM_DEV:
+			break;
+		}
+		buffer = kmalloc(bytes, GFP_USER);
+		if (!buffer)
+			return -ENOMEM;
+		if (hdr.dxfer_direction == SG_DXFER_TO_DEV ||
+		    hdr.dxfer_direction == SG_DXFER_TO_FROM_DEV)
+			copy_from_user(buffer, hdr.dxferp, hdr.dxfer_len);
+	}
+
+	rq = blk_get_request(q, WRITE, __GFP_WAIT);
+	rq->timeout = 60*HZ;
+	rq->data = buffer;
+	rq->data_len = hdr.dxfer_len;
+	rq->flags = REQ_BLOCK_PC;
+	memset(rq->cmd, 0, sizeof(rq->cmd));
+	copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len);
+	err = blk_do_rq(q, rq);
+
+	blk_put_request(rq);
+
+	copy_to_user(uptr, &hdr, sizeof(*uptr));
+	if (buffer) {
+		if (hdr.dxfer_direction == SG_DXFER_FROM_DEV ||
+		    hdr.dxfer_direction == SG_DXFER_TO_FROM_DEV)
+			copy_to_user(hdr.dxferp, buffer, hdr.dxfer_len);
+		kfree(buffer);
+	}
+	return err;
+}
+
+int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
+{
+	request_queue_t *q;
+	struct request *rq;
+	int close = 0, err;
+
+	q = bdev_get_queue(bdev);
+	if (!q)
+		return -ENXIO;
+
+	switch (cmd) {
+		case SG_GET_VERSION_NUM:
+			return sg_get_version((int *) arg);
+		case SCSI_IOCTL_GET_IDLUN:
+			return scsi_get_idlun(q, (int *) arg);
+		case SCSI_IOCTL_GET_BUS_NUMBER:
+			return scsi_get_bus(q, (int *) arg);
+		case SG_SET_TIMEOUT:
+			return sg_set_timeout(q, (int *) arg);
+		case SG_GET_TIMEOUT:
+			return sg_get_timeout(q);
+		case SG_GET_RESERVED_SIZE:
+			return sg_get_reserved_size(q, (int *) arg);
+		case SG_SET_RESERVED_SIZE:
+			return sg_set_reserved_size(q, (int *) arg);
+		case SG_EMULATED_HOST:
+			return sg_emulated_host(q, (int *) arg);
+		case SG_IO:
+			return sg_io(q, (struct sg_io_hdr *) arg);
+		case CDROMCLOSETRAY:
+			close = 1;
+		case CDROMEJECT:
+			rq = blk_get_request(q, WRITE, __GFP_WAIT);
+			rq->flags = REQ_BLOCK_PC;
+			rq->data = NULL;
+			rq->data_len = 0;
+			rq->timeout = 60*HZ;
+			memset(rq->cmd, 0, sizeof(rq->cmd));
+			rq->cmd[0] = GPCMD_START_STOP_UNIT;
+			rq->cmd[4] = 0x02 + (close != 0);
+			err = blk_do_rq(q, rq);
+			blk_put_request(rq);
+			break;
+		default:
+			err = -ENOTTY;
+	}
+
+	blk_put_queue(q);
+	return err;
+}
+
+EXPORT_SYMBOL(scsi_cmd_ioctl);
diff -Nru a/drivers/block/swim3.c b/drivers/block/swim3.c
--- a/drivers/block/swim3.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/block/swim3.c	Tue Oct 15 20:29:16 2002
@@ -1037,7 +1037,7 @@
 		return -ENODEV;
 
 	for (i = 0; i < floppy_count; i++) {
-		disks[i] = alloc_disk();
+		disks[i] = alloc_disk(1);
 		if (!disks[i])
 			goto out;
 	}
diff -Nru a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
--- a/drivers/block/swim_iop.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/block/swim_iop.c	Tue Oct 15 20:29:11 2002
@@ -188,7 +188,7 @@
 	printk("SWIM-IOP: detected %d installed drives.\n", floppy_count);
 
 	for (i = 0; i < floppy_count; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(1);
 		if (!disk)
 			continue;
 		disk->major = MAJOR_NR;
diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c
--- a/drivers/block/umem.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/block/umem.c	Tue Oct 15 20:29:23 2002
@@ -864,18 +864,6 @@
 
 	return 0;
 }
-
-/*
------------------------------------------------------------------------------------
---                            mm_open
------------------------------------------------------------------------------------
-*/
-static int mm_open(struct inode *i, struct file *filp)
-{
-	if (DEVICE_NR(i->i_rdev) >= num_cards)
-		return -ENXIO;
-	return 0;
-}
 /*
 -----------------------------------------------------------------------------------
 --                             mm_fops
@@ -883,7 +871,6 @@
 */
 static struct block_device_operations mm_fops = {
 	owner:		THIS_MODULE,
-	open:		mm_open,
 	ioctl:		mm_ioctl,
 	revalidate:	mm_revalidate,
 	check_media_change: mm_check_change,
@@ -1190,7 +1177,7 @@
 	}
 
 	for (i = 0; i < num_cards; i++) {
-		mm_gendisk[i] = alloc_disk();
+		mm_gendisk[i] = alloc_disk(1 << MM_SHIFT);
 		if (!mm_gendisk[i])
 			goto out;
 	}
@@ -1203,7 +1190,6 @@
 		spin_lock_init(&cards[i].lock);
 		disk->major = major_nr;
 		disk->first_minor  = i << MM_SHIFT;
-		disk->minor_shift = MM_SHIFT;
 		disk->fops = &mm_fops;
 		set_capacity(disk, cards[i].mm_size << 1);
 		add_disk(disk);
diff -Nru a/drivers/block/xd.c b/drivers/block/xd.c
--- a/drivers/block/xd.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/block/xd.c	Tue Oct 15 20:29:20 2002
@@ -130,7 +130,6 @@
 
 static struct block_device_operations xd_fops = {
 	owner:		THIS_MODULE,
-	open:		xd_open,
 	ioctl:		xd_ioctl,
 };
 static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
@@ -205,12 +204,11 @@
 		goto out3;
 
 	for (i = 0; i < xd_drives; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(64);
 		if (!disk)
 			goto Enomem;
 		disk->major = MAJOR_NR;
 		disk->first_minor = i<<6;
-		disk->minor_shift = 6;
 		sprintf(disk->disk_name, "xd%c", i+'a');
 		disk->fops = &xd_fops;
 		xd_gendisk[i] = disk;
@@ -284,15 +282,6 @@
 	return (found);
 }
 
-/* xd_open: open a device */
-static int xd_open (struct inode *inode,struct file *file)
-{
-	int dev = DEVICE_NR(inode->i_rdev);
-	if (dev >= xd_drives)
-		return -ENXIO;
-	return 0;
-}
-
 /* do_xd_request: handle an incoming request */
 static void do_xd_request (request_queue_t * q)
 {
@@ -337,8 +326,6 @@
 static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
 {
 	int dev = DEVICE_NR(inode->i_rdev);
-
-	if (dev >= xd_drives) return -EINVAL;
 	switch (cmd) {
 		case HDIO_GETGEO:
 		{
diff -Nru a/drivers/block/z2ram.c b/drivers/block/z2ram.c
--- a/drivers/block/z2ram.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/block/z2ram.c	Tue Oct 15 20:29:17 2002
@@ -365,14 +365,13 @@
 	    MAJOR_NR );
 	return -EBUSY;
     }
-    z2ram_gendisk = alloc_disk();
+    z2ram_gendisk = alloc_disk(1);
     if (!z2ram_gendisk) {
 	unregister_blkdev( MAJOR_NR, DEVICE_NAME );
 	return -ENOMEM;
     }
     z2ram_gendisk->major = MAJOR_NR;
     z2ram_gendisk->first_minor = 0;
-    z2ram_gendisk->minor_shift = 0;
     z2ram_gendisk->fops = &z2_fops;
     sprintf(z2ram_gendisk->disk_name, "z2ram");
 
diff -Nru a/drivers/bluetooth/Config.help b/drivers/bluetooth/Config.help
--- a/drivers/bluetooth/Config.help	Tue Oct 15 20:29:16 2002
+++ b/drivers/bluetooth/Config.help	Tue Oct 15 20:29:16 2002
@@ -1,5 +1,5 @@
 HCI UART driver
-CONFIG_BLUEZ_HCIUART
+CONFIG_BT_HCIUART
   Bluetooth HCI UART driver.
   This driver is required if you want to use Bluetooth devices with
   serial port interface. You will also need this driver if you have 
@@ -10,7 +10,7 @@
   kernel or say M to compile it as module (hci_uart.o).
 
 HCI UART (H4) protocol support 
-CONFIG_BLUEZ_HCIUART_H4
+CONFIG_BT_HCIUART_H4
   UART (H4) is serial protocol for communication between Bluetooth 
   device and host. This protocol is required for most Bluetooth devices 
   with UART interface, including PCMCIA and CF cards. 
@@ -18,7 +18,7 @@
   Say Y here to compile support for HCI UART (H4) protocol.
 
 HCI BCSP protocol support 
-CONFIG_BLUEZ_HCIUART_BCSP
+CONFIG_BT_HCIUART_BCSP
   BCSP (BlueCore Serial Protocol) is serial protocol for communication 
   between Bluetooth device and host. This protocol is required for non
   USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and 
@@ -27,7 +27,7 @@
   Say Y here to compile support for HCI BCSP protocol.
 
 HCI USB driver
-CONFIG_BLUEZ_HCIUSB
+CONFIG_BT_HCIUSB
   Bluetooth HCI USB driver.
   This driver is required if you want to use Bluetooth devices with
   USB interface.
@@ -36,7 +36,7 @@
   kernel or say M to compile it as module (hci_usb.o).
 
 HCI USB zero packet support
-CONFIG_BLUEZ_USB_ZERO_PACKET
+CONFIG_BT_USB_ZERO_PACKET
   Support for USB zero packets. 
   This option is provided only as a work around for buggy Bluetooth USB 
   devices. Do _not_ enable it unless you know for sure that your device 
@@ -44,7 +44,7 @@
   Most people should say N here.
 
 HCI VHCI Virtual HCI device driver
-CONFIG_BLUEZ_HCIVHCI
+CONFIG_BT_HCIVHCI
   Bluetooth Virtual HCI device driver.
   This driver is required if you want to use HCI Emulation software.
 
@@ -52,7 +52,7 @@
   kernel or say M to compile it as module (hci_vhci.o).
 
 HCI DTL1 (PC Card) device driver
-CONFIG_BLUEZ_HCIDTL1
+CONFIG_BT_HCIDTL1
   Bluetooth HCI DTL1 (PC Card) driver.
   This driver provides support for Bluetooth PCMCIA devices with
   Nokia DTL1 interface:
@@ -63,7 +63,7 @@
   kernel or say M to compile it as module (dtl1_cs.o).
 
 HCI BT3C (PC Card) device driver
-CONFIG_BLUEZ_HCIBT3C
+CONFIG_BT_HCIBT3C
   Bluetooth HCI BT3C (PC Card) driver.
   This driver provides support for Bluetooth PCMCIA devices with
   3Com BT3C interface:
@@ -77,7 +77,7 @@
   kernel or say M to compile it as module (bt3c_cs.o).
 
 HCI BlueCard (PC Card) device driver
-CONFIG_BLUEZ_HCIBLUECARD
+CONFIG_BT_HCIBLUECARD
   Bluetooth HCI BlueCard (PC Card) driver.
   This driver provides support for Bluetooth PCMCIA devices with
   Anycom BlueCard interface:
diff -Nru a/drivers/bluetooth/Config.in b/drivers/bluetooth/Config.in
--- a/drivers/bluetooth/Config.in	Tue Oct 15 20:29:17 2002
+++ b/drivers/bluetooth/Config.in	Tue Oct 15 20:29:17 2002
@@ -1,23 +1,23 @@
 mainmenu_option next_comment
 comment 'Bluetooth device drivers'
 
-dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
-if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
-   bool '  USB zero packet support'  CONFIG_BLUEZ_USB_ZERO_PACKET
+dep_tristate 'HCI USB driver' CONFIG_BT_HCIUSB $CONFIG_BT $CONFIG_USB
+if [ "$CONFIG_BT_HCIUSB" != "n" ]; then
+   bool '  USB zero packet support'  CONFIG_BT_USB_ZERO_PACKET
 fi
 
-dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
-if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
-   bool '  UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
-   bool '  BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
+dep_tristate 'HCI UART driver' CONFIG_BT_HCIUART $CONFIG_BT
+if [ "$CONFIG_BT_HCIUART" != "n" ]; then
+   bool '  UART (H4) protocol support' CONFIG_BT_HCIUART_H4
+   bool '  BCSP protocol support' CONFIG_BT_HCIUART_BCSP
 fi
 
-dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
+dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BT_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BT
 
-dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
+dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BT_HCIBT3C $CONFIG_PCMCIA $CONFIG_BT
 
-dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
+dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BT_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BT
 
-dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
+dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BT_HCIVHCI $CONFIG_BT
 
 endmenu
diff -Nru a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
--- a/drivers/bluetooth/Makefile	Tue Oct 15 20:29:22 2002
+++ b/drivers/bluetooth/Makefile	Tue Oct 15 20:29:22 2002
@@ -2,16 +2,16 @@
 # Makefile for the Linux Bluetooth HCI device drivers.
 #
 
-obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
-obj-$(CONFIG_BLUEZ_HCIVHCI)	+= hci_vhci.o
-obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
-obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
-obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
-obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
+obj-$(CONFIG_BT_HCIUSB)	+= hci_usb.o
+obj-$(CONFIG_BT_HCIVHCI)	+= hci_vhci.o
+obj-$(CONFIG_BT_HCIUART)	+= hci_uart.o
+obj-$(CONFIG_BT_HCIDTL1)	+= dtl1_cs.o
+obj-$(CONFIG_BT_HCIBT3C)	+= bt3c_cs.o
+obj-$(CONFIG_BT_HCIBLUECARD)	+= bluecard_cs.o
 
 hci_uart-y				:= hci_ldisc.o
-hci_uart-$(CONFIG_BLUEZ_HCIUART_H4)	+= hci_h4.o
-hci_uart-$(CONFIG_BLUEZ_HCIUART_BCSP)	+= hci_bcsp.o
+hci_uart-$(CONFIG_BT_HCIUART_H4)	+= hci_h4.o
+hci_uart-$(CONFIG_BT_HCIUART_BCSP)	+= hci_bcsp.o
 hci_uart-objs				:= $(hci_uart-y)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
--- a/drivers/bluetooth/bluecard_cs.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/bluetooth/bluecard_cs.c	Tue Oct 15 20:29:17 2002
@@ -60,7 +60,7 @@
 MODULE_PARM(irq_list, "1-4i");
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)");
+MODULE_DESCRIPTION("Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)");
 MODULE_LICENSE("GPL");
 
 
@@ -396,7 +396,7 @@
 		if (info->rx_skb == NULL) {
 			info->rx_state = RECV_WAIT_PACKET_TYPE;
 			info->rx_count = 0;
-			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+			if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
 				printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
 				return;
 			}
@@ -571,7 +571,7 @@
 	/* Ericsson baud rate command */
 	unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
 
-	if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+	if (!(skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
 		printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
 		return -1;
 	}
diff -Nru a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
--- a/drivers/bluetooth/bt3c_cs.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/bluetooth/bt3c_cs.c	Tue Oct 15 20:29:23 2002
@@ -72,7 +72,7 @@
 MODULE_PARM(irq_list, "1-4i");
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
-MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card");
+MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
 MODULE_LICENSE("GPL");
 
 
@@ -264,7 +264,7 @@
 		if (info->rx_skb == NULL) {
 			info->rx_state = RECV_WAIT_PACKET_TYPE;
 			info->rx_count = 0;
-			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+			if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
 				printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
 				return;
 			}
diff -Nru a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
--- a/drivers/bluetooth/dtl1_cs.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/bluetooth/dtl1_cs.c	Tue Oct 15 20:29:16 2002
@@ -66,7 +66,7 @@
 MODULE_PARM(irq_list, "1-4i");
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1");
+MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1");
 MODULE_LICENSE("GPL");
 
 
@@ -238,7 +238,7 @@
 
 		/* Allocate packet */
 		if (info->rx_skb == NULL)
-			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+			if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
 				printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
 				info->rx_state = RECV_WAIT_NSH;
 				info->rx_count = NSHL;
@@ -433,7 +433,7 @@
 	nsh.zero = 0;
 	nsh.len = skb->len;
 
-	s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
+	s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
 	skb_reserve(s, NSHL);
 	memcpy(skb_put(s, skb->len), skb->data, skb->len);
 	if (skb->len & 0x0001)
diff -Nru a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
--- a/drivers/bluetooth/hci_bcsp.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/bluetooth/hci_bcsp.c	Tue Oct 15 20:29:21 2002
@@ -57,7 +57,7 @@
 #include "hci_uart.h"
 #include "hci_bcsp.h"
 
-#ifndef HCI_UART_DEBUG
+#ifndef CONFIG_BT_HCIUART_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #undef  BT_DMP
@@ -176,7 +176,7 @@
 	u8  hdr[4], chan;
 	int rel, i;
 
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
 	u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
 #endif
 
@@ -228,7 +228,7 @@
 		BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
 		bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
 	}
-#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef  CONFIG_BT_HCIUART_BCSP_TXCRC
 	hdr[0] |= 0x40;
 #endif
 
@@ -240,7 +240,7 @@
 	/* Put BCSP header */
 	for (i = 0; i < 4; i++) {
 		bcsp_slip_one_byte(nskb, hdr[i]);
-#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef  CONFIG_BT_HCIUART_BCSP_TXCRC
 		bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
 #endif
 	}
@@ -248,12 +248,12 @@
 	/* Put payload */
 	for (i = 0; i < len; i++) {
 		bcsp_slip_one_byte(nskb, data[i]);
-#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef  CONFIG_BT_HCIUART_BCSP_TXCRC
 		bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
 #endif
 	}
 
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
 	/* Put CRC */
 	bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
 	bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
@@ -611,7 +611,7 @@
 				 * Allocate packet. Max len of a BCSP pkt= 
 				 * 0xFFF (payload) +4 (header) +2 (crc) */
 
-				bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
+				bcsp->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC);
 				if (!bcsp->rx_skb) {
 					BT_ERR("Can't allocate mem for new packet");
 					bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
diff -Nru a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
--- a/drivers/bluetooth/hci_h4.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/bluetooth/hci_h4.c	Tue Oct 15 20:29:16 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ HCI UART(H4) protocol.
+ * Bluetooth HCI UART(H4) protocol.
  *
  * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $    
  */
@@ -56,7 +56,7 @@
 #include "hci_uart.h"
 #include "hci_h4.h"
 
-#ifndef HCI_UART_DEBUG
+#ifndef CONFIG_BT_HCIUART_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #undef  BT_DMP
@@ -160,7 +160,7 @@
 	ptr = data;
 	while (count) {
 		if (h4->rx_count) {
-			len = MIN(h4->rx_count, count);
+			len = min_t(unsigned int, h4->rx_count, count);
 			memcpy(skb_put(h4->rx_skb, len), ptr, len);
 			h4->rx_count -= len; count -= len; ptr += len;
 
@@ -238,7 +238,7 @@
 		ptr++; count--;
 
 		/* Allocate packet */
-		h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+		h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
 		if (!h4->rx_skb) {
 			BT_ERR("Can't allocate mem for new packet");
 			h4->rx_state = H4_W4_PACKET_TYPE;
diff -Nru a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
--- a/drivers/bluetooth/hci_ldisc.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/bluetooth/hci_ldisc.c	Tue Oct 15 20:29:20 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ HCI UART driver.
+ * Bluetooth HCI UART driver.
  *
  * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $    
  */
@@ -55,7 +55,7 @@
 #include <net/bluetooth/hci_core.h>
 #include "hci_uart.h"
 
-#ifndef HCI_UART_DEBUG
+#ifndef CONFIG_BT_HCIUART_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #undef  BT_DMP
@@ -507,11 +507,11 @@
 	return 0;
 }
 
-#ifdef CONFIG_BLUEZ_HCIUART_H4
+#ifdef CONFIG_BT_HCIUART_H4
 int h4_init(void);
 int h4_deinit(void);
 #endif
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+#ifdef CONFIG_BT_HCIUART_BCSP
 int bcsp_init(void);
 int bcsp_deinit(void);
 #endif
@@ -521,7 +521,7 @@
 	static struct tty_ldisc hci_uart_ldisc;
 	int err;
 
-	BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
+	BT_INFO("Bluetooth HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
 		VERSION);
 	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 
@@ -545,10 +545,10 @@
 		return err;
 	}
 
-#ifdef CONFIG_BLUEZ_HCIUART_H4
+#ifdef CONFIG_BT_HCIUART_H4
 	h4_init();
 #endif
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+#ifdef CONFIG_BT_HCIUART_BCSP
 	bcsp_init();
 #endif
 	
@@ -559,10 +559,10 @@
 {
 	int err;
 
-#ifdef CONFIG_BLUEZ_HCIUART_H4
+#ifdef CONFIG_BT_HCIUART_H4
 	h4_deinit();
 #endif
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+#ifdef CONFIG_BT_HCIUART_BCSP
 	bcsp_deinit();
 #endif
 
@@ -575,5 +575,5 @@
 module_exit(hci_uart_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/bluetooth/hci_usb.c	Tue Oct 15 20:29:21 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ HCI USB driver.
+ * Bluetooth HCI USB driver.
  * Based on original USB Bluetooth driver for Linux kernel
  *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
  *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
@@ -59,14 +59,14 @@
 
 #define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1)
 
-#ifndef HCI_USB_DEBUG
+#ifndef CONFIG_BT_HCIUSB_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #undef  BT_DMP
 #define BT_DMP( A... )
 #endif
 
-#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET
+#ifndef CONFIG_BT_USB_ZERO_PACKET
 #undef  USB_ZERO_PACKET
 #define USB_ZERO_PACKET 0
 #endif
@@ -167,7 +167,7 @@
 
         size = HCI_MAX_FRAME_SIZE;
 
-	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
+	if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) {
 		usb_free_urb(urb);
 		return -ENOMEM;
 	}
@@ -465,7 +465,7 @@
 		if (count > len)
 			goto bad_len;
 
-		skb = bluez_skb_alloc(len, GFP_ATOMIC);
+		skb = bt_skb_alloc(len, GFP_ATOMIC);
 		if (!skb) {
 			BT_ERR("%s no memory for event packet", husb->hdev.name);
 			goto done;
@@ -569,7 +569,7 @@
 	if (count != size) {
 		BT_ERR("%s corrupted ACL packet: count %d, dlen %d",
 				husb->hdev.name, count, dlen);
-		bluez_dump("hci_usb", skb->data, count);
+		bt_dump("hci_usb", skb->data, count);
 		husb->hdev.stat.err_rx++;
 		goto resubmit;
 	}
@@ -639,7 +639,7 @@
 	
 	/* Find endpoints that we need */
 
-	ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
+	ifn = min_t(unsigned int, udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
 	for (i = 0; i < ifn; i++) {
 		iface = &udev->actconfig->interface[i];
 		for (a = 0; a < iface->num_altsetting; a++) {
@@ -781,7 +781,7 @@
 {
 	int err;
 
-	BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
+	BT_INFO("Bluetooth HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
 		VERSION);
 	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 
@@ -800,5 +800,5 @@
 module_exit(hci_usb_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
--- a/drivers/bluetooth/hci_vhci.c	Tue Oct 15 20:29:22 2002
+++ b/drivers/bluetooth/hci_vhci.c	Tue Oct 15 20:29:22 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ HCI virtual device driver.
+ * Bluetooth HCI virtual device driver.
  *
  * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $ 
  */
@@ -136,7 +136,7 @@
 	if (count > HCI_MAX_FRAME_SIZE)
 		return -EINVAL;
 
-	if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
+	if (!(skb = bt_skb_alloc(count, GFP_KERNEL)))
 		return -ENOMEM;
 	
 	if (copy_from_user(skb_put(skb, count), buf, count)) {
@@ -172,7 +172,7 @@
 	int len = count, total = 0;
 	char *ptr = buf;
 
-	len = MIN(skb->len, len); 
+	len = min_t(unsigned int, skb->len, len);
 	if (copy_to_user(ptr, skb->data, len))
 		return -EFAULT;
 	total += len;
@@ -331,7 +331,7 @@
 
 int __init hci_vhci_init(void)
 {
-	BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
+	BT_INFO("Bluetooth VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
 		VERSION);
 	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 
@@ -352,5 +352,5 @@
 module_exit(hci_vhci_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth VHCI driver ver " VERSION);
 MODULE_LICENSE("GPL"); 
diff -Nru a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
--- a/drivers/cdrom/aztcd.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/cdrom/aztcd.c	Tue Oct 15 20:29:21 2002
@@ -1908,7 +1908,7 @@
 	}
 	devfs_register(NULL, "aztcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
 		       S_IFBLK | S_IRUGO | S_IWUGO, &azt_fops, NULL);
-	azt_disk = alloc_disk();
+	azt_disk = alloc_disk(1);
 	if (!azt_disk)
 		goto err_out2;
 	if (register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0) {
@@ -1921,7 +1921,6 @@
 	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
 	azt_disk->major = MAJOR_NR;
 	azt_disk->first_minor = 0;
-	azt_disk->minor_shift = 0;
 	azt_disk->fops = &azt_fops;
 	sprintf(azt_disk->disk_name, "aztcd");
 	add_disk(azt_disk);
diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/cdrom/cdrom.c	Tue Oct 15 20:29:12 2002
@@ -443,15 +443,16 @@
 	if ((cdi = cdrom_find_device(dev)) == NULL)
 		return -ENODEV;
 
-	if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM))
-		return -EROFS;
-
 	/* if this was a O_NONBLOCK open and we should honor the flags,
 	 * do a quick open without drive/disc integrity checks. */
 	if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS))
 		ret = cdi->ops->open(cdi, 1);
-	else
+	else {
+		if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM))
+			return -EROFS;
+
 		ret = open_for_data(cdi);
+	}
 
 	if (!ret) cdi->use_count++;
 
diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
--- a/drivers/cdrom/cdu31a.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/cdrom/cdu31a.c	Tue Oct 15 20:29:12 2002
@@ -3366,12 +3366,11 @@
 		goto errout2;
 	}
 
-	disk = alloc_disk();
+	disk = alloc_disk(1);
 	if (!disk)
 		goto errout1;
 	disk->major = MAJOR_NR;
 	disk->first_minor = 0;
-	disk->minor_shift = 0;
 	sprintf(disk->disk_name, "cdu31a");
 	disk->fops = &scd_bdops;
 	disk->flags = GENHD_FL_CD;
diff -Nru a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
--- a/drivers/cdrom/cm206.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/cdrom/cm206.c	Tue Oct 15 20:29:21 2002
@@ -1470,12 +1470,11 @@
 		printk(KERN_INFO "Cannot register for major %d!\n", MAJOR_NR);
 		goto out_blkdev;
 	}
-	disk = alloc_disk();
+	disk = alloc_disk(1);
 	if (!disk)
 		goto out_disk;
 	disk->major = MAJOR_NR;
 	disk->first_minor = 0;
-	disk->minor_shift = 0;
 	sprintf(disk->disk_name, "cm206");
 	disk->fops = &cm206_bdops;
 	disk->flags = GENHD_FL_CD;
diff -Nru a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
--- a/drivers/cdrom/gscd.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/cdrom/gscd.c	Tue Oct 15 20:29:11 2002
@@ -972,12 +972,11 @@
 		i++;
 	}
 
-	gscd_disk = alloc_disk();
+	gscd_disk = alloc_disk(1);
 	if (!gscd_disk)
 		goto err_out1;
 	gscd_disk->major = MAJOR_NR;
 	gscd_disk->first_minor = 0;
-	gscd_disk->minor_shift = 0;
 	gscd_disk->fops = &gscd_fops;
 	sprintf(gscd_disk->disk_name, "gscd");
 
diff -Nru a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
--- a/drivers/cdrom/mcd.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/cdrom/mcd.c	Tue Oct 15 20:29:17 2002
@@ -1031,7 +1031,7 @@
 
 int __init mcd_init(void)
 {
-	struct gendisk *disk = alloc_disk();
+	struct gendisk *disk = alloc_disk(1);
 	int count;
 	unsigned char result[3];
 	char msg[80];
@@ -1124,7 +1124,6 @@
 
 	disk->major = MAJOR_NR;
 	disk->first_minor = 0;
-	disk->minor_shift = 0;
 	sprintf(disk->disk_name, "mcd");
 	disk->fops = &mcd_bdops;
 	disk->flags = GENHD_FL_CD;
diff -Nru a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
--- a/drivers/cdrom/mcdx.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/cdrom/mcdx.c	Tue Oct 15 20:29:16 2002
@@ -1076,7 +1076,7 @@
 		return 1;
 	}
 
-	disk = alloc_disk();
+	disk = alloc_disk(1);
 	if (!disk) {
 		xwarn("init() malloc failed\n");
 		kfree(stuffp);
@@ -1221,7 +1221,6 @@
 	stuffp->info.dev = mk_kdev(MAJOR_NR, drive);
 	disk->major = MAJOR_NR;
 	disk->first_minor = drive;
-	disk->minor_shift = 0;
 	strcpy(disk->disk_name, stuffp->info.name);
 	disk->fops = &mcdx_bdops;
 	disk->flags = GENHD_FL_CD;
diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
--- a/drivers/cdrom/optcd.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/cdrom/optcd.c	Tue Oct 15 20:29:14 2002
@@ -2010,14 +2010,13 @@
 			"optcd: no Optics Storage CDROM Initialization\n");
 		return -EIO;
 	}
-	optcd_disk = alloc_disk();
+	optcd_disk = alloc_disk(1);
 	if (!optcd_disk) {
 		printk(KERN_ERR "optcd: can't allocate disk\n");
 		return -ENOMEM;
 	}
 	optcd_disk->major = MAJOR_NR;
 	optcd_disk->first_minor = 0;
-	optcd_disk->minor_shift = 0;
 	optcd_disk->fops = &opt_fops;
 	sprintf(optcd_disk->disk_name, "optcd");
 	if (!request_region(optcd_port, 4, "optcd")) {
diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
--- a/drivers/cdrom/sbpcd.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/cdrom/sbpcd.c	Tue Oct 15 20:29:12 2002
@@ -5831,10 +5831,9 @@
 		sbpcd_infop->dev = mk_kdev(MAJOR_NR, j);
 		sbpcd_infop->handle = p;
 		p->sbpcd_infop = sbpcd_infop;
-		disk = alloc_disk();
+		disk = alloc_disk(1);
 		disk->major = MAJOR_NR;
 		disk->first_minor = j;
-		disk->minor_shift = 0;
 		disk->fops = &sbpcd_bdops;
 		strcpy(disk->disk_name, sbpcd_infop->name);
 		disk->flags = GENHD_FL_CD;
diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
--- a/drivers/cdrom/sjcd.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/cdrom/sjcd.c	Tue Oct 15 20:29:17 2002
@@ -1689,14 +1689,13 @@
 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sjcd_request, &sjcd_lock);
 	blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
 
-	sjcd_disk = alloc_disk();
+	sjcd_disk = alloc_disk(1);
 	if (!sjcd_disk) {
 		printk(KERN_ERR "SJCD: can't allocate disk");
 		goto out1;
 	}
 	sjcd_disk->major = MAJOR_NR,
 	sjcd_disk->first_minor = 0,
-	sjcd_disk->minor_shift = 0,
 	sjcd_disk->fops = &sjcd_fops,
 	sprintf(sjcd_disk->disk_name, "sjcd");
 
diff -Nru a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
--- a/drivers/cdrom/sonycd535.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/cdrom/sonycd535.c	Tue Oct 15 20:29:16 2002
@@ -1605,12 +1605,11 @@
 	}
 	initialized = 1;
 
-	cdu_disk = alloc_disk();
+	cdu_disk = alloc_disk(1);
 	if (!cdu_disk)
 		goto out6;
 	cdu_disk->major = MAJOR_NR;
 	cdu_disk->first_minor = 0;
-	cdu_disk->minor_shift = 0;
 	cdu_disk->fops = &cdu_fops;
 	sprintf(cdu_disk->disk_name, "cdu");
 
diff -Nru a/drivers/char/Config.help b/drivers/char/Config.help
--- a/drivers/char/Config.help	Tue Oct 15 20:29:16 2002
+++ b/drivers/char/Config.help	Tue Oct 15 20:29:16 2002
@@ -1033,3 +1033,24 @@
 
   If compiled as a module, it will be called scx200_gpio.o.
 
+Texas Instruments parallel link cable support
+CONFIG_TIPAR
+  If you own a Texas Instruments graphing calculator and use a
+  parallel link cable, then you might be interested in this driver.
+
+  If you enable this driver, you will be able to communicate with
+  your calculator through a set of device nodes under /dev. The
+  main advantage of this driver is that you don't have to be root
+  to use this precise link cable (depending on the permissions on
+  the device nodes, though).
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called tipar.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
+  If you don't know what a parallel link cable is or what a Texas
+  Instruments graphing calculator is, then you probably don't need this
+  driver.
+
+  If unsure, say N.
\ No newline at end of file
diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in
--- a/drivers/char/Config.in	Tue Oct 15 20:29:12 2002
+++ b/drivers/char/Config.in	Tue Oct 15 20:29:12 2002
@@ -80,6 +80,7 @@
       bool '  Support for console on line printer' CONFIG_LP_CONSOLE
    fi
    dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
+   dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT
 fi
 if [ "$CONFIG_PPC_PSERIES" = "y" ]; then
    bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Tue Oct 15 20:29:22 2002
+++ b/drivers/char/Makefile	Tue Oct 15 20:29:22 2002
@@ -50,6 +50,7 @@
 obj-$(CONFIG_RAW_DRIVER) += raw.o
 
 obj-$(CONFIG_PRINTER) += lp.o
+obj-$(CONFIG_TIPAR) += tipar.o
 
 obj-$(CONFIG_BUSMOUSE) += busmouse.o
 obj-$(CONFIG_DTLK) += dtlk.o
diff -Nru a/drivers/char/drm/drm_ioctl.h b/drivers/char/drm/drm_ioctl.h
--- a/drivers/char/drm/drm_ioctl.h	Tue Oct 15 20:29:14 2002
+++ b/drivers/char/drm/drm_ioctl.h	Tue Oct 15 20:29:14 2002
@@ -32,6 +32,7 @@
 #define __NO_VERSION__
 #include "drmP.h"
 
+
 int DRM(irq_busid)(struct inode *inode, struct file *filp,
 		   unsigned int cmd, unsigned long arg)
 {
@@ -41,8 +42,20 @@
 	if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
 		return -EFAULT;
 	dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
-	if (dev) p.irq = dev->irq;
-	else	 p.irq = 0;
+	if (!dev) {
+		DRM_ERROR("pci_find_slot failed for %d:%d:%d\n",
+			  p.busnum, p.devnum, p.funcnum);
+		p.irq = 0;
+		goto out;
+	}			
+	if (pci_enable_device(dev) != 0) {
+		DRM_ERROR("pci_enable_device failed for %d:%d:%d\n",
+			  p.busnum, p.devnum, p.funcnum);
+		p.irq = 0;
+		goto out;
+	}		
+	p.irq = dev->irq;
+ out:
 	DRM_DEBUG("%d:%d:%d => IRQ %d\n",
 		  p.busnum, p.devnum, p.funcnum, p.irq);
 	if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
diff -Nru a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
--- a/drivers/char/drm/drm_os_linux.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/char/drm/drm_os_linux.h	Tue Oct 15 20:29:16 2002
@@ -74,7 +74,7 @@
 			ret = -EBUSY;			\
 			break;				\
 		}					\
-		schedule_timeout(max(HZ/100,1));	\
+		schedule_timeout((HZ/100 > 1) ? HZ/100 : 1);	\
 		if (signal_pending(current)) {		\
 			ret = -EINTR;			\
 			break;				\
diff -Nru a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
--- a/drivers/char/drm/mga_dma.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/char/drm/mga_dma.c	Tue Oct 15 20:29:15 2002
@@ -157,8 +157,17 @@
 {
 	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
 	u32 head, tail;
-	DMA_LOCALS;
+	u32 status = 0;
+	int i;
+ 	DMA_LOCALS;
 	DRM_DEBUG( "\n" );
+
+        /* We need to wait so that we can do an safe flush */
+	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
+		status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
+		if ( status == MGA_ENDPRDMASTS ) break;
+		udelay( 1 );
+	}
 
 	if ( primary->tail == primary->last_flush ) {
 		DRM_DEBUG( "   bailing out...\n" );
diff -Nru a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
--- a/drivers/char/n_hdlc.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/char/n_hdlc.c	Tue Oct 15 20:29:15 2002
@@ -9,7 +9,7 @@
  *	Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
  *
  * Original release 01/11/99
- * $Id: n_hdlc.c,v 4.1 2002/04/10 19:30:58 paulkf Exp $
+ * $Id: n_hdlc.c,v 4.2 2002/10/10 14:52:41 paulkf Exp $
  *
  * This code is released under the GNU General Public License (GPL)
  *
@@ -78,7 +78,7 @@
  */
 
 #define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "$Revision: 4.1 $"
+#define HDLC_VERSION "$Revision: 4.2 $"
 
 #include <linux/version.h>
 #include <linux/config.h>
@@ -264,7 +264,8 @@
 		} else
 			break;
 	}
-	
+	if (n_hdlc->tbuf)
+		kfree(n_hdlc->tbuf);
 	kfree(n_hdlc);
 	
 }	/* end of n_hdlc_release() */
@@ -381,16 +382,15 @@
 		printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
  check_again:
 		
-	save_flags(flags);
-	cli ();
+ 	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
 	if (n_hdlc->tbusy) {
 		n_hdlc->woke_up = 1;
-		restore_flags(flags);
+ 		spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
 		return;
 	}
 	n_hdlc->tbusy = 1;
 	n_hdlc->woke_up = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
 
 	/* get current transmit buffer or get new transmit */
 	/* buffer from list of pending transmit buffers */
@@ -445,10 +445,9 @@
 		tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
 	
 	/* Clear the re-entry flag */
-	save_flags(flags);
-	cli ();
+	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
 	n_hdlc->tbusy = 0;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); 
 	
         if (n_hdlc->woke_up)
 	  goto check_again;
diff -Nru a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
--- a/drivers/char/n_r3964.c	Tue Oct 15 20:29:22 2002
+++ b/drivers/char/n_r3964.c	Tue Oct 15 20:29:22 2002
@@ -1126,7 +1126,7 @@
    
    tty->disc_data = pInfo;
 
-   INIT_LIST_HEAD(&pInfo->tmr.list);
+   init_timer(&pInfo->tmr);
    pInfo->tmr.data = (unsigned long)pInfo;
    pInfo->tmr.function = on_timeout;
 
diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
--- a/drivers/char/pcmcia/synclink_cs.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/char/pcmcia/synclink_cs.c	Tue Oct 15 20:29:16 2002
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/pcmcia/synclink_cs.c
  *
- * $Id: synclink_cs.c,v 4.2 2002/04/22 14:36:43 paulkf Exp $
+ * $Id: synclink_cs.c,v 4.4 2002/10/10 14:53:37 paulkf Exp $
  *
  * Device driver for Microgate SyncLink PC Card
  * multiprotocol serial adapter.
@@ -498,7 +498,7 @@
 MODULE_LICENSE("GPL");
 
 static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.2 $";
+static char *driver_version = "$Revision: 4.4 $";
 
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
@@ -2741,7 +2741,7 @@
 			schedule_timeout(char_time);
 			if (signal_pending(current))
 				break;
-			if (timeout && ((orig_jiffies + timeout) < jiffies))
+			if (timeout && time_after(jiffies, orig_jiffies + timeout))
 				break;
 		}
 	} else {
@@ -2751,7 +2751,7 @@
 			schedule_timeout(char_time);
 			if (signal_pending(current))
 				break;
-			if (timeout && ((orig_jiffies + timeout) < jiffies))
+			if (timeout && time_after(jiffies, orig_jiffies + timeout))
 				break;
 		}
 	}
@@ -2849,12 +2849,12 @@
 		printk("%s(%d):block_til_ready before block on %s count=%d\n",
 			 __FILE__,__LINE__, tty->driver.name, info->count );
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&info->lock, flags);
 	if (!tty_hung_up_p(filp)) {
 		extra_count = 1;
 		info->count--;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 	info->blocked_open++;
 	
 	while (1) {
@@ -3319,7 +3319,6 @@
 
 static void __exit synclink_cs_exit(void) 
 {
-	unsigned long flags;
 	int rc;
 
 	printk("Unloading %s: version %s\n", driver_name, driver_version);
@@ -3327,15 +3326,12 @@
 	while(mgslpc_device_list)
 		mgslpc_remove_device(mgslpc_device_list);
 
-	save_flags(flags);
-	cli();
 	if ((rc = tty_unregister_driver(&serial_driver)))
 		printk("%s(%d) failed to unregister tty driver err=%d\n",
 		       __FILE__,__LINE__,rc);
 	if ((rc = tty_unregister_driver(&callout_driver)))
 		printk("%s(%d) failed to unregister callout driver err=%d\n",
 		       __FILE__,__LINE__,rc);
-	restore_flags(flags);
 
 	unregister_pccard_driver(&dev_info);
 	while (dev_list != NULL) {
diff -Nru a/drivers/char/rtc.c b/drivers/char/rtc.c
--- a/drivers/char/rtc.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/char/rtc.c	Tue Oct 15 20:29:16 2002
@@ -86,7 +86,9 @@
 static int rtc_irq = PCI_IRQ_NONE;
 #endif
 
+#if RTC_IRQ
 static int rtc_has_irq = 1;
+#endif
 
 /*
  *	We sponge a minor off of the misc major. No need slurping
@@ -99,7 +101,9 @@
 
 static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
 
+#if RTC_IRQ
 static struct timer_list rtc_irq_timer;
+#endif
 
 static ssize_t rtc_read(struct file *file, char *buf,
 			size_t count, loff_t *ppos);
diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c
--- a/drivers/char/synclink.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/char/synclink.c	Tue Oct 15 20:29:16 2002
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 4.2 2002/04/10 20:45:13 paulkf Exp $
+ * $Id: synclink.c,v 4.4 2002/10/10 14:53:36 paulkf Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -917,7 +917,7 @@
 MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.2 $";
+static char *driver_version = "$Revision: 4.4 $";
 
 static int synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
@@ -3387,7 +3387,7 @@
 			schedule_timeout(char_time);
 			if (signal_pending(current))
 				break;
-			if (timeout && ((orig_jiffies + timeout) < jiffies))
+			if (timeout && time_after(jiffies, orig_jiffies + timeout))
 				break;
 		}
 	} else {
@@ -3397,7 +3397,7 @@
 			schedule_timeout(char_time);
 			if (signal_pending(current))
 				break;
-			if (timeout && ((orig_jiffies + timeout) < jiffies))
+			if (timeout && time_after(jiffies, orig_jiffies + timeout))
 				break;
 		}
 	}
@@ -3512,12 +3512,12 @@
 		printk("%s(%d):block_til_ready before block on %s count=%d\n",
 			 __FILE__,__LINE__, tty->driver.name, info->count );
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&info->irq_spinlock, flags);
 	if (!tty_hung_up_p(filp)) {
 		extra_count = 1;
 		info->count--;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->irq_spinlock, flags);
 	info->blocked_open++;
 	
 	while (1) {
@@ -4728,21 +4728,18 @@
 
 static void __exit synclink_exit(void) 
 {
-	unsigned long flags;
 	int rc;
 	struct mgsl_struct *info;
 	struct mgsl_struct *tmp;
 
 	printk("Unloading %s: %s\n", driver_name, driver_version);
-	save_flags(flags);
-	cli();
+
 	if ((rc = tty_unregister_driver(&serial_driver)))
 		printk("%s(%d) failed to unregister tty driver err=%d\n",
 		       __FILE__,__LINE__,rc);
 	if ((rc = tty_unregister_driver(&callout_driver)))
 		printk("%s(%d) failed to unregister callout driver err=%d\n",
 		       __FILE__,__LINE__,rc);
-	restore_flags(flags);
 
 	info = mgsl_device_list;
 	while(info) {
@@ -7486,7 +7483,7 @@
 	EndTime = jiffies + jiffies_from_ms(100);
 
 	for(;;) {
-		if ( jiffies > EndTime ) {
+		if (time_after(jiffies, EndTime)) {
 			rc = FALSE;
 			break;
 		}
@@ -7542,7 +7539,7 @@
 	EndTime = jiffies + jiffies_from_ms(100);
 
 	for(;;) {
-		if ( jiffies > EndTime ) {
+		if (time_after(jiffies, EndTime)) {
 			rc = FALSE;
 			break;
 		}
@@ -7590,7 +7587,7 @@
 		spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
 		while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) {
-			if ( jiffies > EndTime ) {
+			if (time_after(jiffies, EndTime)) {
 				rc = FALSE;
 				break;
 			}
@@ -7617,8 +7614,7 @@
 		/* Wait for 16C32 to write receive status to buffer entry. */
 		status=info->rx_buffer_list[0].status;
 		while ( status == 0 ) {
-			if ( jiffies > EndTime ) {
-			printk(KERN_ERR"mark 4\n");
+			if (time_after(jiffies, EndTime)) {
 				rc = FALSE;
 				break;
 			}
diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
--- a/drivers/char/synclinkmp.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/char/synclinkmp.c	Tue Oct 15 20:29:12 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: synclinkmp.c,v 4.4 2002/04/22 16:05:41 paulkf Exp $
+ * $Id: synclinkmp.c,v 4.6 2002/10/10 14:50:47 paulkf Exp $
  *
  * Device driver for Microgate SyncLink Multiport
  * high speed multiprotocol serial adapter.
@@ -503,7 +503,7 @@
 MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
 
 static char *driver_name = "SyncLink MultiPort driver";
-static char *driver_version = "$Revision: 4.4 $";
+static char *driver_version = "$Revision: 4.6 $";
 
 static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
 static void synclinkmp_remove_one(struct pci_dev *dev);
@@ -1204,7 +1204,7 @@
 			schedule_timeout(char_time);
 			if (signal_pending(current))
 				break;
-			if (timeout && ((orig_jiffies + timeout) < jiffies))
+			if (timeout && time_after(jiffies, orig_jiffies + timeout))
 				break;
 		}
 	} else {
@@ -1215,7 +1215,7 @@
 			schedule_timeout(char_time);
 			if (signal_pending(current))
 				break;
-			if (timeout && ((orig_jiffies + timeout) < jiffies))
+			if (timeout && time_after(jiffies, orig_jiffies + timeout))
 				break;
 		}
 	}
@@ -2605,18 +2605,11 @@
 
 	info->pending_bh = 0;
 
-	init_timer(&info->tx_timer);
-	info->tx_timer.data = (unsigned long)info;
-	info->tx_timer.function = tx_timeout;
-
 	/* program hardware for current parameters */
 	reset_port(info);
 
 	change_params(info);
 
-	init_timer(&info->status_timer);
-	info->status_timer.data = (unsigned long)info;
-	info->status_timer.function = status_timeout;
 	info->status_timer.expires = jiffies + jiffies_from_ms(10);
 	add_timer(&info->status_timer);
 
@@ -3304,12 +3297,12 @@
 		printk("%s(%d):%s block_til_ready() before block, count=%d\n",
 			 __FILE__,__LINE__, tty->driver.name, info->count );
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&info->lock, flags);
 	if (!tty_hung_up_p(filp)) {
 		extra_count = 1;
 		info->count--;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&info->lock, flags);
 	info->blocked_open++;
 
 	while (1) {
@@ -3772,6 +3765,14 @@
 		info->bus_type = MGSL_BUS_TYPE_PCI;
 		info->irq_flags = SA_SHIRQ;
 
+		init_timer(&info->tx_timer);
+		info->tx_timer.data = (unsigned long)info;
+		info->tx_timer.function = tx_timeout;
+
+		init_timer(&info->status_timer);
+		info->status_timer.data = (unsigned long)info;
+		info->status_timer.function = status_timeout;
+
 		/* Store the PCI9050 misc control register value because a flaw
 		 * in the PCI9050 prevents LCR registers from being read if
 		 * BIOS assigns an LCR base address with bit 7 set.
@@ -3959,15 +3960,13 @@
 	SLMP_INFO *tmp;
 
 	printk("Unloading %s %s\n", driver_name, driver_version);
-	save_flags(flags);
-	cli();
+
 	if ((rc = tty_unregister_driver(&serial_driver)))
 		printk("%s(%d) failed to unregister tty driver err=%d\n",
 		       __FILE__,__LINE__,rc);
 	if ((rc = tty_unregister_driver(&callout_driver)))
 		printk("%s(%d) failed to unregister callout driver err=%d\n",
 		       __FILE__,__LINE__,rc);
-	restore_flags(flags);
 
 	info = synclinkmp_device_list;
 	while(info) {
diff -Nru a/drivers/char/tipar.c b/drivers/char/tipar.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/tipar.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,541 @@
+/* Hey EMACS -*- linux-c -*-
+ *
+ * tipar - low level driver for handling a parallel link cable designed
+ * for Texas Instruments graphing calculators (http://lpg.ticalc.org).
+ * A part of the TiLP project.
+ *
+ * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org>
+ * under the terms of the GNU General Public License.
+ *
+ * Various fixes & clean-up from the Linux Kernel Mailing List
+ * (Alan Cox, Richard B. Johnson, Christoph Hellwig).
+ */
+
+/* This driver should, in theory, work with any parallel port that has an
+ * appropriate low-level driver; all I/O is done through the parport
+ * abstraction layer.
+ *
+ * If this driver is built into the kernel, you can configure it using the
+ * kernel command-line.  For example:
+ *
+ *      tipar=timeout,delay       (set timeout and delay)
+ *
+ * If the driver is loaded as a module, similar functionality is available
+ * using module parameters.  The equivalent of the above commands would be:
+ *
+ *      # insmod tipar timeout=15 delay=10
+ */
+
+/* COMPATIBILITY WITH OLD KERNELS
+ *
+ * Usually, parallel cables were bound to ports at
+ * particular I/O addresses, as follows:
+ *
+ *      tipar0             0x378
+ *      tipar1             0x278
+ *      tipar2             0x3bc
+ *
+ *
+ * This driver, by default, binds tipar devices according to parport and
+ * the minor number.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/fcntl.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <linux/devfs_fs_kernel.h>	/* DevFs support */
+#include <linux/parport.h>	/* Our code depend on parport */
+
+/*
+ * TI definitions
+ */
+#include <linux/ticable.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.17"
+#define DRIVER_AUTHOR  "Romain Lievin <roms@lpg.ticalc.org>"
+#define DRIVER_DESC    "Device driver for TI/PC parallel link cables"
+#define DRIVER_LICENSE "GPL"
+
+#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
+#if LINUX_VERSION_CODE < VERSION(2,5,0)
+# define minor(x) MINOR(x)
+# define need_resched() (current->need_resched)
+#endif
+
+/* ----- global variables --------------------------------------------- */
+
+struct tipar_struct {
+	struct pardevice *dev;	/* Parport device entry */
+};
+
+#define PP_NO 3
+static struct tipar_struct table[PP_NO];
+
+static int delay = IO_DELAY;	/* inter-bit delay in microseconds */
+static int timeout = TIMAXTIME;	/* timeout in tenth of seconds     */
+
+static devfs_handle_t devfs_handle;
+static unsigned int tp_count;	/* tipar count */
+static unsigned long opened;	/* opened devices */
+
+/* --- macros for parport access -------------------------------------- */
+
+#define r_dtr(x)        (parport_read_data(table[(x)].dev->port))
+#define r_str(x)        (parport_read_status(table[(x)].dev->port))
+#define w_ctr(x,y)      (parport_write_control(table[(x)].dev->port, (y)))
+#define w_dtr(x,y)      (parport_write_data(table[(x)].dev->port, (y)))
+
+/* --- setting states on the D-bus with the right timing: ------------- */
+
+static inline void
+outbyte(int value, int minor)
+{
+	w_dtr(minor, value);
+}
+
+static inline int
+inbyte(int minor)
+{
+	return (r_str(minor));
+}
+
+static inline void
+init_ti_parallel(int minor)
+{
+	outbyte(3, minor);
+}
+
+/* ----- global defines ----------------------------------------------- */
+
+#define START(x) { x=jiffies+HZ/(timeout/10); }
+#define WAIT(x)  { \
+  if (time_before((x), jiffies)) return -1; \
+  if (need_resched()) schedule(); }
+
+/* ----- D-bus bit-banging functions ---------------------------------- */
+
+/* D-bus protocol (45kbit/s max):
+                    1                 0                      0
+       _______        ______|______    __________|________    __________
+Red  :        ________      |      ____          |        ____
+       _        ____________|________      ______|__________       _____
+White:  ________            |        ______      |          _______
+*/
+
+/* Try to transmit a byte on the specified port (-1 if error). */
+static int
+put_ti_parallel(int minor, unsigned char data)
+{
+	int bit;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		if (data & 1) {
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x10);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+		} else {
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (inbyte(minor) & 0x20);
+
+			outbyte(3, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+		}
+
+		data >>= 1;
+		udelay(delay);
+
+		if (need_resched())
+			schedule();
+	}
+
+	return 0;
+}
+
+/* Receive a byte on the specified port or -1 if error. */
+static int
+get_ti_parallel(int minor)
+{
+	int bit;
+	unsigned char v, data = 0;
+	unsigned long max;
+
+	for (bit = 0; bit < 8; bit++) {
+		START(max);
+		do {
+			WAIT(max);
+		} while ((v = inbyte(minor) & 0x30) == 0x30);
+
+		if (v == 0x10) {
+			data = (data >> 1) | 0x80;
+			outbyte(1, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x20));
+			outbyte(3, minor);
+		} else {
+			data = data >> 1;
+			outbyte(2, minor);
+			START(max);
+			do {
+				WAIT(max);
+			} while (!(inbyte(minor) & 0x10));
+			outbyte(3, minor);
+		}
+
+		udelay(delay);
+		if (need_resched())
+			schedule();
+	}
+
+	return (int) data;
+}
+
+/* Try to detect a parallel link cable on the specified port */
+static int
+probe_ti_parallel(int minor)
+{
+	int i;
+	int seq[] = { 0x00, 0x20, 0x10, 0x30 };
+
+	for (i = 3; i >= 0; i--) {
+		outbyte(3, minor);
+		outbyte(i, minor);
+		udelay(delay);
+		/*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */
+		if ((inbyte(minor) & 0x30) != seq[i]) {
+			outbyte(3, minor);
+			return -1;
+		}
+	}
+
+	outbyte(3, minor);
+	return 0;
+}
+
+/* ----- kernel module functions--------------------------------------- */
+
+static int
+tipar_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	if (test_and_set_bit(minor, &opened))
+		return -EBUSY;
+
+	parport_claim_or_block(table[minor].dev);
+	init_ti_parallel(minor);
+	parport_release(table[minor].dev);
+
+	return 0;
+}
+
+static int
+tipar_close(struct inode *inode, struct file *file)
+{
+	unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR;
+
+	if (minor > tp_count - 1)
+		return -ENXIO;
+
+	clear_bit(minor, &opened);
+
+	return 0;
+}
+
+static ssize_t
+tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
+{
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t n;
+
+	printk("_write\n");
+	parport_claim_or_block(table[minor].dev);
+
+	for (n = 0; n < count; n++) {
+		unsigned char b;
+
+		if (get_user(b, buf + n)) {
+			n = -EFAULT;
+			goto out;
+		}
+
+		if (put_ti_parallel(minor, b) == -1) {
+			init_ti_parallel(minor);
+			n = -ETIMEDOUT;
+			goto out;
+		}
+	}
+      out:
+	parport_release(table[minor].dev);
+	return n;
+}
+
+static ssize_t
+tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+{
+	int b = 0;
+	unsigned int minor =
+	    minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR;
+	ssize_t retval = 0;
+	ssize_t n = 0;
+
+	if (count == 0)
+		return 0;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	printk("_read\n");
+	parport_claim_or_block(table[minor].dev);
+
+	while (n < count) {
+		b = get_ti_parallel(minor);
+		if (b == -1) {
+			init_ti_parallel(minor);
+			retval = -ETIMEDOUT;
+			goto out;
+		} else {
+			if (put_user(b, ((unsigned char *) buf) + n)) {
+				retval = -EFAULT;
+				break;
+			} else
+				retval = ++n;
+		}
+
+		/* Non-blocking mode : try again ! */
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		}
+
+		/* Signal pending, try again ! */
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+
+		if (need_resched())
+			schedule();
+	}
+
+      out:
+	parport_release(table[minor].dev);
+	return retval;
+}
+
+static int
+tipar_ioctl(struct inode *inode, struct file *file,
+	    unsigned int cmd, unsigned long arg)
+{
+	int retval = 0;
+
+	switch (cmd) {
+	case IOCTL_TIPAR_DELAY:
+	  delay = (int)arg;    //get_user(delay, &arg);
+	  break;
+	case IOCTL_TIPAR_TIMEOUT:
+	  timeout = (int)arg;  //get_user(timeout, &arg);
+	  break;
+	default:
+		retval = -ENOTTY;
+		break;
+	}
+
+	return retval;
+}
+
+/* ----- kernel module registering ------------------------------------ */
+
+static struct file_operations tipar_fops = {
+	owner:THIS_MODULE,
+	llseek:no_llseek,
+	read:tipar_read,
+	write:tipar_write,
+	ioctl:tipar_ioctl,
+	open:tipar_open,
+	release:tipar_close,
+};
+
+/* --- initialisation code ------------------------------------- */
+
+#ifndef MODULE
+/*      You must set these - there is no sane way to probe for this cable.
+ *      You can use 'tipar=timeout,delay' to set these now. */
+static int __init
+tipar_setup(char *str)
+{
+	int ints[2];
+
+	str = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0) {
+		timeout = ints[1];
+		if (ints[0] > 1) {
+			delay = ints[2];
+		}
+	}
+
+	return 1;
+}
+#endif
+
+/*
+ * Register our module into parport.
+ * Pass also 2 callbacks functions to parport: a pre-emptive function and an
+ * interrupt handler function (unused).
+ * Display a message such "tipar0: using parport0 (polling)".
+ */
+static int
+tipar_register(int nr, struct parport *port)
+{
+	char name[8];
+
+	/* Register our module into parport */
+	table[nr].dev = parport_register_device(port, "tipar",
+						NULL, NULL, NULL, 0,
+						(void *) &table[nr]);
+
+	if (table[nr].dev == NULL)
+		return 1;
+
+	/* Use devfs, tree: /dev/ticables/par/[0..2] */
+	sprintf(name, "%d", nr);
+	printk
+	    ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n",
+	     TISER_MAJOR, (TIPAR_MINOR + nr), name);
+	devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR,
+		       TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO,
+		       &tipar_fops, NULL);
+
+	/* Display informations */
+	printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
+	       (port->irq ==
+		PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven");
+
+	if (probe_ti_parallel(nr) != -1)
+		printk("tipar%d: link cable found !\n", nr);
+	else
+		printk("tipar%d: link cable not found.\n", nr);
+
+	return 0;
+}
+
+static void
+tipar_attach(struct parport *port)
+{
+	if (tp_count == PP_NO) {
+		printk("tipar: ignoring parallel port (max. %d)\n", PP_NO);
+		return;
+	}
+
+	if (!tipar_register(tp_count, port))
+		tp_count++;
+}
+
+static void
+tipar_detach(struct parport *port)
+{
+	/* Nothing to do */
+}
+
+static struct parport_driver tipar_driver = {
+	"tipar",
+	tipar_attach,
+	tipar_detach,
+	NULL
+};
+
+int __init
+tipar_init_module(void)
+{
+	printk("tipar: parallel link cable driver, version %s\n",
+	       DRIVER_VERSION);
+
+	if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) {
+		printk("tipar: unable to get major %d\n", TIPAR_MAJOR);
+		return -EIO;
+	}
+
+	/* Use devfs with tree: /dev/ticables/par/[0..2] */
+	devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL);
+
+	if (parport_register_driver(&tipar_driver)) {
+		printk("tipar: unable to register with parport\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+void __exit
+tipar_cleanup_module(void)
+{
+	unsigned int i;
+
+	/* Unregistering module */
+	parport_unregister_driver(&tipar_driver);
+
+	devfs_unregister(devfs_handle);
+	unregister_chrdev(TIPAR_MAJOR, "tipar");
+
+	for (i = 0; i < PP_NO; i++) {
+		if (table[i].dev == NULL)
+			continue;
+		parport_unregister_device(table[i].dev);
+	}
+
+	printk("tipar: module unloaded !\n");
+}
+
+/* --------------------------------------------------------------------- */
+
+__setup("tipar=", tipar_setup);
+module_init(tipar_init_module);
+module_exit(tipar_cleanup_module);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM(timeout, "i");
+MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)");
+MODULE_PARM(delay, "i");
+MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)");
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/char/tty_io.c	Tue Oct 15 20:29:17 2002
@@ -113,7 +113,7 @@
 #define CHECK_TTY_COUNT 1
 
 struct termios tty_std_termios;		/* for the benefit of tty drivers  */
-struct tty_driver *tty_drivers;		/* linked list of tty drivers */
+LIST_HEAD(tty_drivers);			/* linked list of tty drivers */
 struct tty_ldisc ldiscs[NR_LDISCS];	/* line disc dispatch table	*/
 
 #ifdef CONFIG_UNIX98_PTYS
@@ -338,7 +338,7 @@
 	minor = minor(device);
 	major = major(device);
 
-	for (p = tty_drivers; p; p = p->next) {
+	list_for_each_entry(p, &tty_drivers, tty_drivers) {
 		if (p->major != major)
 			continue;
 		if (minor < p->minor_start)
@@ -2083,10 +2083,7 @@
 	if (!driver->put_char)
 		driver->put_char = tty_default_put_char;
 	
-	driver->prev = 0;
-	driver->next = tty_drivers;
-	if (tty_drivers) tty_drivers->prev = driver;
-	tty_drivers = driver;
+	list_add(&driver->tty_drivers, &tty_drivers);
 	
 	if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
 		for(i = 0; i < driver->num; i++)
@@ -2110,7 +2107,7 @@
 	if (*driver->refcount)
 		return -EBUSY;
 
-	for (p = tty_drivers; p; p = p->next) {
+	list_for_each_entry(p, &tty_drivers, tty_drivers) {
 		if (p == driver)
 			found++;
 		else if (p->major == driver->major)
@@ -2127,13 +2124,7 @@
 	} else
 		register_chrdev(driver->major, othername, &tty_fops);
 
-	if (driver->prev)
-		driver->prev->next = driver->next;
-	else
-		tty_drivers = driver->next;
-	
-	if (driver->next)
-		driver->next->prev = driver->prev;
+	list_del(&driver->tty_drivers);
 
 	/*
 	 * Free the termios and termios_locked structures because
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/ide/ide-cd.c	Tue Oct 15 20:29:16 2002
@@ -309,6 +309,8 @@
 #include <linux/ide.h>
 #include <linux/completion.h>
 
+#include <scsi/scsi.h>	/* For SCSI -> ATAPI command conversion */
+
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
@@ -332,12 +334,12 @@
 	info->nsectors_buffered = 0;
 }
 
-static int cdrom_log_sense(ide_drive_t *drive, struct packet_command *pc,
+static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
 			   struct request_sense *sense)
 {
 	int log = 0;
 
-	if (sense == NULL || pc == NULL || pc->quiet)
+	if (!sense || !rq || (rq->flags & REQ_QUIET))
 		return 0;
 
 	switch (sense->sense_key) {
@@ -370,10 +372,9 @@
 
 static
 void cdrom_analyze_sense_data(ide_drive_t *drive,
-			      struct packet_command *failed_command,
+			      struct request *failed_command,
 			      struct request_sense *sense)
 {
-
 	if (!cdrom_log_sense(drive, failed_command, sense))
 		return;
 
@@ -382,7 +383,7 @@
 	 * the first toc has not been recorded yet, it will fail with
 	 * 05/24/00 (which is a confusing error)
 	 */
-	if (failed_command && failed_command->c[0] == GPCMD_READ_TOC_PMA_ATIP)
+	if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
 		if (sense->sense_key == 0x05 && sense->asc == 0x24)
 			return;
 
@@ -453,20 +454,20 @@
 			while (hi > lo) {
 				mid = (lo + hi) / 2;
 				if (packet_command_texts[mid].packet_command ==
-				    failed_command->c[0]) {
+				    failed_command->cmd[0]) {
 					s = packet_command_texts[mid].text;
 					break;
 				}
 				if (packet_command_texts[mid].packet_command >
-				    failed_command->c[0])
+				    failed_command->cmd[0])
 					hi = mid;
 				else
 					lo = mid+1;
 			}
 
 			printk ("  The failed \"%s\" packet command was: \n  \"", s);
-			for (i=0; i<sizeof (failed_command->c); i++)
-				printk ("%02x ", failed_command->c[i]);
+			for (i=0; i<sizeof (failed_command->cmd); i++)
+				printk ("%02x ", failed_command->cmd[i]);
 			printk ("\"\n");
 		}
 
@@ -512,30 +513,39 @@
 #endif /* not VERBOSE_IDE_CD_ERRORS */
 }
 
+/*
+ * Initialize a ide-cd packet command request
+ */
+static void cdrom_prepare_request(struct request *rq)
+{
+	ide_init_drive_cmd(rq);
+	rq->flags = REQ_PC;
+}
+
 static void cdrom_queue_request_sense(ide_drive_t *drive, 
 				      struct completion *wait,
-				      struct request_sense *sense,
-				      struct packet_command *failed_command)
+				      void *sense,
+				      struct request *failed_command)
 {
 	struct cdrom_info *info		= drive->driver_data;
-	struct packet_command *pc	= &info->request_sense_pc;
-	struct request *rq;
+	struct request *rq		= &info->request_sense_request;
 
 	if (sense == NULL)
 		sense = &info->sense_data;
 
-	memset(pc, 0, sizeof(struct packet_command));
-	pc->c[0] = GPCMD_REQUEST_SENSE;
-	pc->c[4] = pc->buflen = 18;
-	pc->buffer = (char *) sense;
-	pc->sense = (struct request_sense *) failed_command;
-
 	/* stuff the sense request in front of our current request */
-	rq = &info->request_sense_request;
-	ide_init_drive_cmd(rq);
+	cdrom_prepare_request(rq);
+
+	rq->data = sense;
+	rq->cmd[0] = GPCMD_REQUEST_SENSE;
+	rq->cmd[4] = rq->data_len = 18;
+
 	rq->flags = REQ_SENSE;
-	rq->buffer = (char *) pc;
 	rq->waiting = wait;
+
+	/* NOTE! Save the failed command in "rq->buffer" */
+	rq->buffer = (void *) failed_command;
+
 	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
@@ -630,17 +640,26 @@
 	struct request *rq = HWGROUP(drive)->rq;
 
 	if ((rq->flags & REQ_SENSE) && uptodate) {
-		struct packet_command *pc = (struct packet_command *) rq->buffer;
-		cdrom_analyze_sense_data(drive,
-			(struct packet_command *) pc->sense,
-			(struct request_sense *) (pc->buffer - pc->c[4]));
+		/* For REQ_SENSE, "rq->buffer" points to the original failed request */
+		struct request *failed = (struct request *) rq->buffer; 
+		struct cdrom_info *info = drive->driver_data;
+		void * sense = &info->sense_data;
+		
+		if (failed && failed->sense)
+			sense = failed->sense;
+
+		cdrom_analyze_sense_data(drive, failed, sense);
 	}
+
 	if (blk_fs_request(rq) && !rq->current_nr_sectors)
 		uptodate = 1;
 
 	ide_end_request(drive, uptodate, rq->hard_cur_sectors);
 }
 
+/* Handle differences between SCSI and ATAPI packet commands */
+static int pre_transform_command(struct request *);
+static void post_transform_command(struct request *);
 
 /* Returns 0 if the request should be continued.
    Returns 1 if the request was ended. */
@@ -649,7 +668,6 @@
 {
 	struct request *rq = HWGROUP(drive)->rq;
 	int stat, err, sense_key;
-	struct packet_command *pc;
 	
 	/* Check for errors. */
 	*stat_ret = stat = HWIF(drive)->INB(IDE_STATUS_REG);
@@ -672,16 +690,18 @@
 		   from the drive (probably while trying
 		   to recover from a former error).  Just give up. */
 
-		pc = (struct packet_command *) rq->buffer;
-		pc->stat = 1;
-		cdrom_end_request(drive, 1);
+		rq->flags |= REQ_FAILED;
+		cdrom_end_request(drive, 0);
 		*startstop = DRIVER(drive)->error(drive, "request sense failure", stat);
 		return 1;
 
-	} else if (rq->flags & REQ_PC) {
+	} else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
 		/* All other functions, except for READ. */
 		struct completion *wait = NULL;
-		pc = (struct packet_command *) rq->buffer;
+
+		/* Fix up any SCSI command differences.. */
+		if (rq->flags & REQ_BLOCK_PC)
+			post_transform_command(rq);
 
 		/* Check for tray open. */
 		if (sense_key == NOT_READY) {
@@ -691,7 +711,7 @@
 			cdrom_saw_media_change (drive);
 			/*printk("%s: media changed\n",drive->name);*/
 			return 0;
-		} else if (!pc->quiet) {
+		} else if (!(rq->flags & REQ_QUIET)) {
 			/* Otherwise, print an error. */
 			ide_dump_status(drive, "packet command error", stat);
 		}
@@ -710,11 +730,11 @@
 			rq->waiting = NULL;
 		}
 
-		pc->stat = 1;
-		cdrom_end_request(drive, 1);
+		rq->flags |= REQ_FAILED;
+		cdrom_end_request(drive, 0);
 
 		if ((stat & ERR_STAT) != 0)
-			cdrom_queue_request_sense(drive, wait, pc->sense, pc);
+			cdrom_queue_request_sense(drive, wait, rq->sense, rq);
 	} else if (blk_fs_request(rq)) {
 		/* Handle errors from READ and WRITE requests. */
 
@@ -770,7 +790,6 @@
 static int cdrom_timer_expiry(ide_drive_t *drive)
 {
 	struct request *rq = HWGROUP(drive)->rq;
-	struct packet_command *pc = (struct packet_command *) rq->buffer;
 	unsigned long wait = 0;
 
 	/*
@@ -779,7 +798,7 @@
 	 * this, but not all commands/drives support that. Let
 	 * ide_timer_expiry keep polling us for these.
 	 */
-	switch (pc->c[0]) {
+	switch (rq->cmd[0]) {
 		case GPCMD_BLANK:
 		case GPCMD_FORMAT_UNIT:
 		case GPCMD_RESERVE_RZONE_TRACK:
@@ -854,12 +873,12 @@
  * struct packet_command *pc; now packet_command_t *pc;
  */
 static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
-					  struct packet_command *pc,
+					  struct request *rq,
 					  ide_handler_t *handler)
 {
-	unsigned char *cmd_buf	= pc->c;
-	int cmd_len		= sizeof(pc->c);
-	unsigned int timeout	= pc->timeout;
+	unsigned char *cmd_buf	= rq->cmd;
+	int cmd_len		= sizeof(rq->cmd);
+	unsigned int timeout	= rq->timeout;
 	struct cdrom_info *info = drive->driver_data;
 	ide_startstop_t startstop;
 
@@ -1029,6 +1048,7 @@
 		if (rq->current_nr_sectors > 0) {
 			printk ("%s: cdrom_read_intr: data underrun (%d blocks)\n",
 				drive->name, rq->current_nr_sectors);
+			rq->flags |= REQ_FAILED;
 			cdrom_end_request(drive, 0);
 		} else
 			cdrom_end_request(drive, 1);
@@ -1179,7 +1199,6 @@
  */
 static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
 {
-	struct packet_command pc;
 	struct request *rq = HWGROUP(drive)->rq;
 	int nsect, sector, nframes, frame, nskip;
 
@@ -1222,11 +1241,10 @@
 		(65534 / CD_FRAMESIZE) : 65535);
 
 	/* Set up the command */
-	memcpy(pc.c, rq->cmd, sizeof(pc.c));
-	pc.timeout = WAIT_CMD;
+	rq->timeout = WAIT_CMD;
 
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command(drive, &pc, &cdrom_read_intr);
+	return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr);
 }
 
 
@@ -1262,7 +1280,6 @@
 
 static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
 {
-	struct packet_command pc;
 	struct request *rq = HWGROUP(drive)->rq;
 	int sector, frame, nskip;
 
@@ -1273,11 +1290,11 @@
 	frame = sector / SECTORS_PER_FRAME;
 
 	memset(rq->cmd, 0, sizeof(rq->cmd));
-	pc.c[0] = GPCMD_SEEK;
-	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
+	rq->cmd[0] = GPCMD_SEEK;
+	put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);
 
-	pc.timeout = WAIT_CMD;
-	return cdrom_transfer_packet_command(drive, &pc, &cdrom_seek_intr);
+	rq->timeout = WAIT_CMD;
+	return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr);
 }
 
 static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
@@ -1296,6 +1313,7 @@
 {
 	if (rq->buffer != bio_data(rq->bio)) {
 		sector_t n = (rq->buffer - (char *) bio_data(rq->bio)) / SECTOR_SIZE;
+
 		rq->buffer = bio_data(rq->bio);
 		rq->nr_sectors += n;
 		rq->sector -= n;
@@ -1352,7 +1370,6 @@
 {
 	int ireason, len, stat, thislen;
 	struct request *rq = HWGROUP(drive)->rq;
-	struct packet_command *pc = (struct packet_command *)rq->buffer;
 	ide_startstop_t startstop;
 	u8 lowcyl = 0, highcyl = 0;
 
@@ -1372,16 +1389,16 @@
 	if ((stat & DRQ_STAT) == 0) {
 		/* Some of the trailing request sense fields are optional, and
 		   some drives don't send them.  Sigh. */
-		if (pc->c[0] == GPCMD_REQUEST_SENSE &&
-		    pc->buflen > 0 &&
-		    pc->buflen <= 5) {
-			while (pc->buflen > 0) {
-				*pc->buffer++ = 0;
-				--pc->buflen;
+		if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
+		    rq->data_len > 0 &&
+		    rq->data_len <= 5) {
+			while (rq->data_len > 0) {
+				*(unsigned char *)rq->data++ = 0;
+				--rq->data_len;
 			}
 		}
 
-		if (pc->buflen == 0)
+		if (rq->data_len == 0)
 			cdrom_end_request(drive, 1);
 		else {
 			/* Comment this out, because this always happens 
@@ -1391,20 +1408,22 @@
 			printk ("%s: cdrom_pc_intr: data underrun %d\n",
 				drive->name, pc->buflen);
 			*/
-			pc->stat = 1;
-			cdrom_end_request(drive, 1);
+			rq->flags |= REQ_FAILED;
+			cdrom_end_request(drive, 0);
 		}
 		return ide_stopped;
 	}
 
 	/* Figure out how much data to transfer. */
-	thislen = pc->buflen;
+	thislen = rq->data_len;
 	if (thislen > len) thislen = len;
 
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
+		if (!rq->data)
+			goto confused;
 		/* Transfer the data. */
-		HWIF(drive)->atapi_output_bytes(drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
@@ -1415,15 +1434,16 @@
 		}
 
 		/* Keep count of how much data we've moved. */
-		pc->buffer += thislen;
-		pc->buflen -= thislen;
+		rq->data += thislen;
+		rq->data_len -= thislen;
 	}
 
 	/* Same drill for reading. */
 	else if ((ireason & 3) == 2) {
-
+		if (!rq->data)
+			goto confused;
 		/* Transfer the data. */
-		HWIF(drive)->atapi_input_bytes(drive, pc->buffer, thislen);
+		HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen);
 
 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
@@ -1434,13 +1454,14 @@
 		}
 
 		/* Keep count of how much data we've moved. */
-		pc->buffer += thislen;
-		pc->buflen -= thislen;
+		rq->data += thislen;
+		rq->data_len -= thislen;
 	} else {
+confused:
 		printk ("%s: cdrom_pc_intr: The drive "
 			"appears confused (ireason = 0x%2x)\n",
 			drive->name, ireason);
-		pc->stat = 1;
+		rq->flags |= REQ_FAILED;
 	}
 
 	if (HWGROUP(drive)->handler != NULL)
@@ -1455,13 +1476,12 @@
 static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
 {
 	struct request *rq = HWGROUP(drive)->rq;
-	struct packet_command *pc = (struct packet_command *)rq->buffer;
 
-	if (!pc->timeout)
-		pc->timeout = WAIT_CMD;
+	if (!rq->timeout)
+		rq->timeout = WAIT_CMD;
 
 	/* Send the command to the drive and return. */
-	return cdrom_transfer_packet_command(drive, pc, &cdrom_pc_intr);
+	return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr);
 }
 
 
@@ -1469,13 +1489,12 @@
 {
 	int len;
 	struct request *rq = HWGROUP(drive)->rq;
-	struct packet_command *pc = (struct packet_command *)rq->buffer;
 	struct cdrom_info *info = drive->driver_data;
 
 	info->dma = 0;
 	info->cmd = 0;
-	pc->stat = 0;
-	len = pc->buflen;
+	rq->flags &= ~REQ_FAILED;
+	len = rq->data_len;
 
 	/* Start sending the command to the drive. */
 	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
@@ -1496,28 +1515,31 @@
 }
 
 static
-int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc)
+int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
 {
 	struct request_sense sense;
-	struct request req;
 	int retries = 10;
+	unsigned int flags = rq->flags;
 
-	if (pc->sense == NULL)
-		pc->sense = &sense;
+	if (rq->sense == NULL)
+		rq->sense = &sense;
 
 	/* Start of retry loop. */
 	do {
-		ide_init_drive_cmd (&req);
-		req.flags = REQ_PC;
-		req.buffer = (char *)pc;
-		ide_do_drive_cmd(drive, &req, ide_wait);
+		int error;
+		unsigned long time = jiffies;
+		rq->flags = flags;
+
+		error = ide_do_drive_cmd(drive, rq, ide_wait);
+		time = jiffies - time;
+
 		/* FIXME: we should probably abort/retry or something 
 		 * in case of failure */
-		if (pc->stat != 0) {
+		if (rq->flags & REQ_FAILED) {
 			/* The request failed.  Retry if it was due to a unit
 			   attention status
 			   (usually means media was changed). */
-			struct request_sense *reqbuf = pc->sense;
+			struct request_sense *reqbuf = rq->sense;
 
 			if (reqbuf->sense_key == UNIT_ATTENTION)
 				cdrom_saw_media_change(drive);
@@ -1535,10 +1557,10 @@
 		}
 
 		/* End of retry loop. */
-	} while (pc->stat != 0 && retries >= 0);
+	} while ((rq->flags & REQ_FAILED) && retries >= 0);
 
 	/* Return an error if the command failed. */
-	return pc->stat ? -EIO : 0;
+	return (rq->flags & REQ_FAILED) ? -EIO : 0;
 }
 
 /*
@@ -1681,20 +1703,18 @@
 
 static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
 {
-	struct packet_command pc;	/* packet_command_t pc; */
 	struct request *rq = HWGROUP(drive)->rq;
 	unsigned nframes, frame;
 
 	nframes = rq->nr_sectors >> 2;
 	frame = rq->sector >> 2;
 
-	memcpy(pc.c, rq->cmd, sizeof(pc.c));
 #if 0	/* the immediate bit */
-	pc.c[1] = 1 << 3;
+	rq->cmd[1] = 1 << 3;
 #endif
-	pc.timeout = 2 * WAIT_CMD;
+	rq->timeout = 2 * WAIT_CMD;
 
-	return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr);
+	return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr);
 }
 
 static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
@@ -1728,20 +1748,54 @@
 	return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
 }
 
+/*
+ * Most of the SCSI commands are supported directly by ATAPI devices.
+ * This transform handles the few exceptions.
+ */
+static int pre_transform_command(struct request *req)
+{
+	u8 *c = req->cmd;
+	/* Transform 6-byte read/write commands to the 10-byte version. */
+	if (c[0] == READ_6 || c[0] == WRITE_6) {
+		c[8] = c[4];
+		c[5] = c[3];
+		c[4] = c[2];
+		c[3] = c[1] & 0x1f;
+		c[2] = 0;
+		c[1] &= 0xe0;
+		c[0] += (READ_10 - READ_6);
+		return 0;
+	}
+
+	/* These also need fixup, not done yet */
+	if (c[0] == MODE_SENSE || c[0] == MODE_SELECT)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void post_transform_command(struct request *req)
+{
+}
+
 static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
 {
-	struct packet_command pc;
 	ide_startstop_t startstop;
+	struct cdrom_info *info;
 
-	memset(&pc, 0, sizeof(pc));
-	memcpy(pc.c, rq->cmd, sizeof(pc.c));
-	pc.quiet = 1;
-	pc.timeout = 60 * HZ;
-	rq->buffer = (char *) &pc;
-
-	startstop = cdrom_do_packet_command(drive);
-	if (pc.stat)
-		rq->errors++;
+	if (pre_transform_command(rq) < 0) {
+		cdrom_end_request(drive, 0);
+		return ide_stopped;
+	}
+
+	rq->flags |= REQ_QUIET;
+
+	info = drive->driver_data;
+	info->dma = 0;
+	info->cmd = 0;
+
+	/* Start sending the command to the drive. */
+	startstop = cdrom_start_packet_command(drive, rq->data_len, cdrom_do_pc_continuation);
 
 	return startstop;
 }
@@ -1757,11 +1811,11 @@
 
 	if (blk_fs_request(rq)) {
 		if (CDROM_CONFIG_FLAGS(drive)->seeking) {
-			unsigned long elpased = jiffies - info->start_seek;
+			unsigned long elapsed = jiffies - info->start_seek;
 			int stat = HWIF(drive)->INB(IDE_STATUS_REG);
 
 			if ((stat & SEEK_STAT) != SEEK_STAT) {
-				if (elpased < IDECD_SEEK_TIMEOUT) {
+				if (elapsed < IDECD_SEEK_TIMEOUT) {
 					ide_stall_queue(drive, IDECD_SEEK_TIMER);
 					return ide_stopped;
 				}
@@ -1781,14 +1835,14 @@
 		return action;
 	} else if (rq->flags & (REQ_PC | REQ_SENSE)) {
 		return cdrom_do_packet_command(drive);
+	} else if (rq->flags & REQ_BLOCK_PC) {
+		return cdrom_do_block_pc(drive, rq);
 	} else if (rq->flags & REQ_SPECIAL) {
 		/*
 		 * right now this can only be a reset...
 		 */
 		cdrom_end_request(drive, 1);
 		return ide_stopped;
-	} else if (rq->flags & REQ_BLOCK_PC) {
-		return cdrom_do_block_pc(drive, rq);
 	}
 
 	blk_dump_rq_flags(rq, "ide-cd bad flags");
@@ -1853,23 +1907,23 @@
 
 static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
 {
-	struct packet_command pc;
+	struct request req;
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
 
-	memset(&pc, 0, sizeof(pc));
-	pc.sense = sense;
+	cdrom_prepare_request(&req);
 
-	pc.c[0] = GPCMD_TEST_UNIT_READY;
+	req.sense = sense;
+	req.cmd[0] = GPCMD_TEST_UNIT_READY;
 
 #if ! STANDARD_ATAPI
         /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to 
            switch CDs instead of supporting the LOAD_UNLOAD opcode   */
 
-        pc.c[7] = cdi->sanyo_slot % 3;
+	req.cmd[7] = cdi->sanyo_slot % 3;
 #endif /* not STANDARD_ATAPI */
 
-	return cdrom_queue_packet_command(drive, &pc);
+	return cdrom_queue_packet_command(drive, &req);
 }
 
 
@@ -1878,7 +1932,7 @@
 cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
 {
 	struct request_sense my_sense;
-	struct packet_command pc;
+	struct request req;
 	int stat;
 
 	if (sense == NULL)
@@ -1888,11 +1942,11 @@
 	if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
 		stat = 0;
 	} else {
-		memset(&pc, 0, sizeof(pc));
-		pc.sense = sense;
-		pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
-		pc.c[4] = lockflag ? 1 : 0;
-		stat = cdrom_queue_packet_command(drive, &pc);
+		cdrom_prepare_request(&req);
+		req.sense = sense;
+		req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
+		req.cmd[4] = lockflag ? 1 : 0;
+		stat = cdrom_queue_packet_command(drive, &req);
 	}
 
 	/* If we got an illegal field error, the drive
@@ -1922,7 +1976,7 @@
 static int cdrom_eject(ide_drive_t *drive, int ejectflag,
 		       struct request_sense *sense)
 {
-	struct packet_command pc;
+	struct request req;
 
 	if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag)
 		return -EDRIVE_CANT_DO_THIS;
@@ -1931,12 +1985,12 @@
 	if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
 		return 0;
 
-	memset(&pc, 0, sizeof (pc));
-	pc.sense = sense;
+	cdrom_prepare_request(&req);
 
-	pc.c[0] = GPCMD_START_STOP_UNIT;
-	pc.c[4] = 0x02 + (ejectflag != 0);
-	return cdrom_queue_packet_command(drive, &pc);
+	req.sense = sense;
+	req.cmd[0] = GPCMD_START_STOP_UNIT;
+	req.cmd[4] = 0x02 + (ejectflag != 0);
+	return cdrom_queue_packet_command(drive, &req);
 }
 
 static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -1948,16 +2002,16 @@
 	} capbuf;
 
 	int stat;
-	struct packet_command pc;
+	struct request req;
 
-	memset(&pc, 0, sizeof(pc));
-	pc.sense = sense;
+	cdrom_prepare_request(&req);
 
-	pc.c[0] = GPCMD_READ_CDVD_CAPACITY;
-	pc.buffer = (char *)&capbuf;
-	pc.buflen = sizeof(capbuf);
+	req.sense = sense;
+	req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
+	req.data = (char *)&capbuf;
+	req.data_len = sizeof(capbuf);
 
-	stat = cdrom_queue_packet_command(drive, &pc);
+	stat = cdrom_queue_packet_command(drive, &req);
 	if (stat == 0)
 		*capacity = 1 + be32_to_cpu(capbuf.lba);
 
@@ -1968,24 +2022,24 @@
 				int format, char *buf, int buflen,
 				struct request_sense *sense)
 {
-	struct packet_command pc;
+	struct request req;
 
-	memset(&pc, 0, sizeof(pc));
-	pc.sense = sense;
+	cdrom_prepare_request(&req);
 
-	pc.buffer =  buf;
-	pc.buflen = buflen;
-	pc.quiet = 1;
-	pc.c[0] = GPCMD_READ_TOC_PMA_ATIP;
-	pc.c[6] = trackno;
-	pc.c[7] = (buflen >> 8);
-	pc.c[8] = (buflen & 0xff);
-	pc.c[9] = (format << 6);
+	req.sense = sense;
+	req.data =  buf;
+	req.data_len = buflen;
+	req.flags |= REQ_QUIET;
+	req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+	req.cmd[6] = trackno;
+	req.cmd[7] = (buflen >> 8);
+	req.cmd[8] = (buflen & 0xff);
+	req.cmd[9] = (format << 6);
 
 	if (msf_flag)
-		pc.c[1] = 2;
+		req.cmd[1] = 2;
 
-	return cdrom_queue_packet_command(drive, &pc);
+	return cdrom_queue_packet_command(drive, &req);
 }
 
 
@@ -2144,20 +2198,20 @@
 static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
 				 int buflen, struct request_sense *sense)
 {
-	struct packet_command pc;
+	struct request req;
 
-	memset(&pc, 0, sizeof(pc));
-	pc.sense = sense;
+	cdrom_prepare_request(&req);
 
-	pc.buffer = buf;
-	pc.buflen = buflen;
-	pc.c[0] = GPCMD_READ_SUBCHANNEL;
-	pc.c[1] = 2;     /* MSF addressing */
-	pc.c[2] = 0x40;  /* request subQ data */
-	pc.c[3] = format;
-	pc.c[7] = (buflen >> 8);
-	pc.c[8] = (buflen & 0xff);
-	return cdrom_queue_packet_command(drive, &pc);
+	req.sense = sense;
+	req.data = buf;
+	req.data_len = buflen;
+	req.cmd[0] = GPCMD_READ_SUBCHANNEL;
+	req.cmd[1] = 2;     /* MSF addressing */
+	req.cmd[2] = 0x40;  /* request subQ data */
+	req.cmd[3] = format;
+	req.cmd[7] = (buflen >> 8);
+	req.cmd[8] = (buflen & 0xff);
+	return cdrom_queue_packet_command(drive, &req);
 }
 
 /* ATAPI cdrom drives are free to select the speed you request or any slower
@@ -2165,45 +2219,45 @@
 static int cdrom_select_speed(ide_drive_t *drive, int speed,
 			      struct request_sense *sense)
 {
-	struct packet_command pc;
-	memset(&pc, 0, sizeof(pc));
-	pc.sense = sense;
+	struct request req;
+	cdrom_prepare_request(&req);
 
+	req.sense = sense;
 	if (speed == 0)
 		speed = 0xffff; /* set to max */
 	else
 		speed *= 177;   /* Nx to kbytes/s */
 
-	pc.c[0] = GPCMD_SET_SPEED;
+	req.cmd[0] = GPCMD_SET_SPEED;
 	/* Read Drive speed in kbytes/second MSB */
-	pc.c[2] = (speed >> 8) & 0xff;	
+	req.cmd[2] = (speed >> 8) & 0xff;	
 	/* Read Drive speed in kbytes/second LSB */
-	pc.c[3] = speed & 0xff;
+	req.cmd[3] = speed & 0xff;
 	if (CDROM_CONFIG_FLAGS(drive)->cd_r ||
 	    CDROM_CONFIG_FLAGS(drive)->cd_rw ||
 	    CDROM_CONFIG_FLAGS(drive)->dvd_r) {
 		/* Write Drive speed in kbytes/second MSB */
-		pc.c[4] = (speed >> 8) & 0xff;
+		req.cmd[4] = (speed >> 8) & 0xff;
 		/* Write Drive speed in kbytes/second LSB */
-		pc.c[5] = speed & 0xff;
+		req.cmd[5] = speed & 0xff;
        }
 
-	return cdrom_queue_packet_command(drive, &pc);
+	return cdrom_queue_packet_command(drive, &req);
 }
 
 static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
 {
 	struct request_sense sense;
-	struct packet_command pc;
+	struct request req;
 
-	memset(&pc, 0, sizeof (pc));
-	pc.sense = &sense;
+	cdrom_prepare_request(&req);
 
-	pc.c[0] = GPCMD_PLAY_AUDIO_MSF;
-	lba_to_msf(lba_start, &pc.c[3], &pc.c[4], &pc.c[5]);
-	lba_to_msf(lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]);
+	req.sense = &sense;
+	req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+	lba_to_msf(lba_start, &req.cmd[3], &req.cmd[4], &req.cmd[5]);
+	lba_to_msf(lba_end-1, &req.cmd[6], &req.cmd[7], &req.cmd[8]);
 
-	return cdrom_queue_packet_command(drive, &pc);
+	return cdrom_queue_packet_command(drive, &req);
 }
 
 static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
@@ -2237,7 +2291,7 @@
 static int ide_cdrom_packet(struct cdrom_device_info *cdi,
 			    struct cdrom_generic_command *cgc)
 {
-	struct packet_command pc;
+	struct request req;
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 
 	if (cgc->timeout <= 0)
@@ -2246,18 +2300,21 @@
 	/* here we queue the commands from the uniform CD-ROM
 	   layer. the packet must be complete, as we do not
 	   touch it at all. */
-	memset(&pc, 0, sizeof(pc));
-	memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
+	cdrom_prepare_request(&req);
+	memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
 	if (cgc->sense)
 		memset(cgc->sense, 0, sizeof(struct request_sense));
-	pc.buffer = cgc->buffer;
-	pc.buflen = cgc->buflen;
-	pc.quiet = cgc->quiet;
-	pc.timeout = cgc->timeout;
-	pc.sense = cgc->sense;
-	cgc->stat = cdrom_queue_packet_command(drive, &pc);
+	req.data = cgc->buffer;
+	req.data_len = cgc->buflen;
+	req.timeout = cgc->timeout;
+
+	if (cgc->quiet)
+		req.flags |= REQ_QUIET;
+
+	req.sense = cgc->sense;
+	cgc->stat = cdrom_queue_packet_command(drive, &req);
 	if (!cgc->stat)
-		cgc->buflen -= pc.buflen;
+		cgc->buflen -= req.data_len;
 	return cgc->stat;
 }
 
@@ -2393,7 +2450,7 @@
 	struct request req;
 	int ret;
 
-	ide_init_drive_cmd (&req);
+	cdrom_prepare_request(&req);
 	req.flags = REQ_SPECIAL;
 	ret = ide_do_drive_cmd(drive, &req, ide_wait);
 
@@ -2969,6 +3026,14 @@
 		     struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
+	int error;
+
+	/* Try the generic SCSI command ioctl's first.. */
+	error = scsi_cmd_ioctl(inode->i_bdev, cmd, arg);
+	if (error != -ENOTTY)
+		return error;
+
+	/* Then the generic cdrom ioctl's.. */
 	return cdrom_ioctl(inode, file, cmd, arg);
 }
 
@@ -3128,8 +3193,10 @@
 	memset(info, 0, sizeof (struct cdrom_info));
 	drive->driver_data = info;
 	DRIVER(drive)->busy++;
+	g->minors = 1;
 	g->minor_shift = 0;
 	g->de = drive->de;
+	g->driverfs_dev = &drive->gendev;
 	g->flags = GENHD_FL_CD;
 	if (ide_cdrom_setup(drive)) {
 		struct cdrom_device_info *devinfo = &info->devinfo;
diff -Nru a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
--- a/drivers/ide/ide-cd.h	Tue Oct 15 20:29:23 2002
+++ b/drivers/ide/ide-cd.h	Tue Oct 15 20:29:23 2002
@@ -105,13 +105,6 @@
 #define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
 
 struct packet_command {
-	char *buffer;
-	int buflen;
-	int stat;
-	int quiet;
-	int timeout;
-	struct request_sense *sense;
-	unsigned char c[12];
 };
 
 /* Structure of a MSF cdrom address. */
@@ -437,7 +430,7 @@
 
 	byte     curlba[3];
 	byte     nslots;
-	__u8 short slot_tablelen;
+	__u16	 slot_tablelen;
 };
 
 
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/ide/ide-disk.c	Tue Oct 15 20:29:16 2002
@@ -1871,8 +1871,10 @@
 		goto failed;
 	}
 	DRIVER(drive)->busy--;
+	g->minors = 1 << PARTN_BITS;
 	g->minor_shift = PARTN_BITS;
 	g->de = drive->de;
+	g->driverfs_dev = &drive->gendev;
 	g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
 	g->flags |= GENHD_FL_DEVFS;
 	set_capacity(g, current_capacity(drive));
@@ -1891,78 +1893,6 @@
 {
 	ide_register_driver(&idedisk_driver);
 	return 0;
-}
-
-ide_startstop_t panic_box(ide_drive_t *drive)
-{
-#if 0
-	panic("%s: Attempted to corrupt something: ide operation "
-#else
-	printk(KERN_ERR "%s: Attempted to corrupt something: ide operation "
-#endif
-		"was pending accross suspend/resume.\n", drive->name);
-	return ide_stopped;
-}
-
-int ide_disks_busy(void)
-{
-	int i;
-	for (i=0; i<MAX_HWIFS; i++) {
-		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
-		if (!hwgroup) continue;
-		if ((hwgroup->handler) && (hwgroup->handler != panic_box))
-			return 1;
-	}
-	return 0;
-}
-
-void ide_disk_suspend(void)
-{
-	int i;
-	while (ide_disks_busy()) {
-		printk("*");
-		schedule();
-	}
-	for (i=0; i<MAX_HWIFS; i++) {
-		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
-
-		if (!hwgroup) continue;
-		hwgroup->handler_save = hwgroup->handler;
-		hwgroup->handler = panic_box;
-	}
-	driver_blocked = 1;
-	if (ide_disks_busy())
-		panic("How did you get that request through?!");
-}
-
-/* unsuspend and resume should be equal in the ideal world */
-
-void ide_disk_unsuspend(void)
-{
-	int i;
-	for (i=0; i<MAX_HWIFS; i++) {
-		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
-
-		if (!hwgroup) continue;
-		hwgroup->handler = NULL; /* hwgroup->handler_save; */
-		hwgroup->handler_save = NULL;
-	}
-	driver_blocked = 0;
-}
-
-void ide_disk_resume(void)
-{
-	int i;
-	for (i=0; i<MAX_HWIFS; i++) {
-		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
-
-		if (!hwgroup) continue;
-		if (hwgroup->handler != panic_box)
-			panic("Handler was not set to panic?");
-		hwgroup->handler_save = NULL;
-		hwgroup->handler = NULL;
-	}
-	driver_blocked = 0;
 }
 
 module_init(idedisk_init);
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/ide/ide-floppy.c	Tue Oct 15 20:29:17 2002
@@ -2108,7 +2108,9 @@
 	DRIVER(drive)->busy++;
 	idefloppy_setup (drive, floppy);
 	DRIVER(drive)->busy--;
+	g->minors = 1 << PARTN_BITS;
 	g->minor_shift = PARTN_BITS;
+	g->driverfs_dev = &drive->gendev;
 	g->de = drive->de;
 	g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
 	g->flags |= GENHD_FL_DEVFS;
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/ide/ide-probe.c	Tue Oct 15 20:29:17 2002
@@ -986,7 +986,7 @@
 	units = MAX_DRIVES;
 
 	for (unit = 0; unit < MAX_DRIVES; unit++) {
-		disks[unit] = alloc_disk();
+		disks[unit] = alloc_disk(1 << PARTN_BITS);
 		if (!disks[unit])
 			goto err_kmalloc_gd;
 	}
@@ -996,7 +996,6 @@
 		disk->major  = hwif->major;
 		disk->first_minor = unit << PARTN_BITS;
 		sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit);
-		disk->minor_shift = PARTN_BITS; 
 		disk->fops = ide_fops;
 		hwif->drives[unit].disk = disk;
 	}
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/ide/ide.c	Tue Oct 15 20:29:15 2002
@@ -2639,7 +2639,7 @@
 
 		case CDROMEJECT:
 		case CDROMCLOSETRAY:
-			return block_ioctl(inode->i_bdev, cmd, arg);
+			return scsi_cmd_ioctl(inode->i_bdev, cmd, arg);
 
 		case HDIO_GET_BUSSTATE:
 			if (!capable(CAP_SYS_ADMIN))
diff -Nru a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
--- a/drivers/ide/legacy/hd.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/ide/legacy/hd.c	Tue Oct 15 20:29:11 2002
@@ -677,21 +677,11 @@
 	}
 }
 
-static int hd_open(struct inode * inode, struct file * filp)
-{
-	int target =  DEVICE_NR(inode->i_rdev);
-	if (target >= NR_HD)
-		return -ENODEV;
-	return 0;
-}
-
 /*
  * Releasing a block device means we sync() it, so that it can safely
  * be forgotten about...
  */
 
-extern struct block_device_operations hd_fops;
-
 static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	void (*handler)(void) = do_hd;
@@ -705,7 +695,6 @@
 }
 
 static struct block_device_operations hd_fops = {
-	.open =		hd_open,
 	.ioctl =	hd_ioctl,
 };
 
@@ -802,12 +791,11 @@
 		goto out;
 
 	for (drive=0 ; drive < NR_HD ; drive++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(64);
 		if (!disk)
 			goto Enomem;
 		disk->major = MAJOR_NR;
 		disk->first_minor = drive << 6;
-		disk->minor_shift = 6;
 		disk->fops = &hd_fops;
 		sprintf(disk->disk_name, "hd%c", 'a'+drive);
 		hd_gendisk[drive] = disk;
diff -Nru a/drivers/ieee1394/cmp.c b/drivers/ieee1394/cmp.c
--- a/drivers/ieee1394/cmp.c	Tue Oct 15 20:29:13 2002
+++ b/drivers/ieee1394/cmp.c	Tue Oct 15 20:29:13 2002
@@ -199,7 +199,7 @@
 }
 
 static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-		    u64 addr, unsigned int length)
+		    u64 addr, unsigned int length, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
@@ -235,7 +235,7 @@
 }
 
 static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-		    u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+		    u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags)
 {
 	int csraddr = addr - CSR_REGISTER_BASE;
 	int plug;
diff -Nru a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
--- a/drivers/ieee1394/csr.c	Tue Oct 15 20:29:13 2002
+++ b/drivers/ieee1394/csr.c	Tue Oct 15 20:29:13 2002
@@ -4,20 +4,33 @@
  * CSR implementation, iso/bus manager implementation.
  *
  * Copyright (C) 1999 Andreas E. Bombe
+ *               2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *
  */
 
 #include <linux/string.h>
+#include <linux/module.h> /* needed for MODULE_PARM */
 
 #include "ieee1394_types.h"
 #include "hosts.h"
 #include "ieee1394.h"
 #include "highlevel.h"
 
+/* Module Parameters */
+/* this module parameter can be used to disable mapping of the FCP registers */
+MODULE_PARM(fcp,"i");
+MODULE_PARM_DESC(fcp, "FCP-registers");
+static int fcp = 1;
 
-/* FIXME: this one won't work on little endian with big endian data */
 static u16 csr_crc16(unsigned *data, int length)
 {
         int check=0, i;
@@ -25,7 +38,7 @@
 
         for (i = length; i; i--) {
                 for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
-                        sum = ((next >> 12) ^ (*data >> shift)) & 0xf;
+                        sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
                         next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
                 }
                 check = next & 0xffff;
@@ -60,6 +73,8 @@
                             | csr_crc16(host->csr.topology_map + 1,
                                         host->selfid_count + 2));
 
+        host->csr.speed_map[1] = 
+                cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1);
         host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 
                                              | csr_crc16(host->csr.speed_map+1,
                                                          0x3f1));
@@ -71,7 +86,7 @@
         host->csr.lock = SPIN_LOCK_UNLOCKED;
 
         host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom);
-
+        host->csr.rom_version           = 0;
         host->csr.state                 = 0;
         host->csr.node_ids              = 0;
         host->csr.split_timeout_hi      = 0;
@@ -84,13 +99,52 @@
         host->csr.channels_available_lo = ~0;
 }
 
+int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, 
+	size_t size, unsigned char rom_version)
+{
+        int ret,flags;
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        if (rom_version != host->csr.rom_version)
+                 ret = -1;
+        else if (size > (CSR_CONFIG_ROM_SIZE << 2))
+                 ret = -2;
+        else {
+                 memcpy(host->csr.rom,new_rom,size);
+                 host->csr.rom_size=size;
+                 host->csr.rom_version++;
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, 
+	size_t buffersize, size_t *rom_size, unsigned char *rom_version)
+{
+        int ret,flags;
+        spin_lock_irqsave(&host->csr.lock, flags); 
+        *rom_version=host->csr.rom_version;
+        *rom_size=host->csr.rom_size;
+        if (buffersize < host->csr.rom_size)
+                 ret = -1;
+        else {
+                 memcpy(buffer,host->csr.rom,host->csr.rom_size);
+                 ret=0;
+        }
+        spin_unlock_irqrestore(&host->csr.lock, flags);
+        return ret;
+}
+
 
 /* Read topology / speed maps and configuration ROM */
 static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         const char *src;
+        int flags;
+
+        spin_lock_irqsave(&host->csr.lock, flags); 
 
         if (csraddr < CSR_TOPOLOGY_MAP) {
                 if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) {
@@ -105,6 +159,7 @@
         }
 
         memcpy(buffer, src, length);
+        spin_unlock_irqrestore(&host->csr.lock, flags);
         return RCODE_COMPLETE;
 }
 
@@ -112,7 +167,7 @@
 #define out if (--length == 0) break
 
 static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
-                     u64 addr, unsigned int length)
+                     u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         int oldcycle;
@@ -222,7 +277,7 @@
 }
 
 static int write_regs(struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length)
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         
@@ -302,7 +357,7 @@
 
 
 static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int extcode)
+                     u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
         unsigned long flags;
@@ -379,7 +434,7 @@
 }
 
 static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
-		     quadlet_t *data, u64 addr, unsigned int length)
+		     quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         int csraddr = addr - CSR_REGISTER_BASE;
 
@@ -436,9 +491,11 @@
         hpsb_register_addrspace(hl, &map_ops, 
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM,
                                 CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
-        hpsb_register_addrspace(hl, &fcp_ops,
+        if (fcp) {
+		hpsb_register_addrspace(hl, &fcp_ops,
                                 CSR_REGISTER_BASE + CSR_FCP_COMMAND,
                                 CSR_REGISTER_BASE + CSR_FCP_END);
+	}
         hpsb_register_addrspace(hl, &map_ops,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
                                 CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
diff -Nru a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
--- a/drivers/ieee1394/csr.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/ieee1394/csr.h	Tue Oct 15 20:29:12 2002
@@ -41,8 +41,10 @@
         quadlet_t bandwidth_available;
         quadlet_t channels_available_hi, channels_available_lo;
 
-        const quadlet_t *rom;
+        quadlet_t *rom;
         size_t rom_size;
+        unsigned char rom_version;
+
 
         quadlet_t topology_map[256];
         quadlet_t speed_map[1024];
diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
--- a/drivers/ieee1394/dv1394.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/ieee1394/dv1394.c	Tue Oct 15 20:29:19 2002
@@ -97,7 +97,6 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -2587,6 +2586,7 @@
 	return p;
 }
 
+#ifdef CONFIG_DEVFS_FS
 static int dv1394_devfs_add_entry(struct video_card *video)
 {
 	char buf[32];
@@ -2694,6 +2694,7 @@
 		kfree(p);
 	}
 }
+#endif /* CONFIG_DEVFS_FS */
 
 /*** IEEE1394 HPSB CALLBACKS ***********************************************/
 
@@ -2852,7 +2853,6 @@
 {
 	struct ti_ohci *ohci;
 	char buf[16];
-	struct dv1394_devfs_entry *devfs_entry;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2874,13 +2874,15 @@
 #endif
 
 #ifdef CONFIG_DEVFS_FS
-	devfs_entry = dv1394_devfs_find("dv");
+{
+	struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv");
 	if (devfs_entry != NULL) {
 		snprintf(buf, sizeof(buf), "host%d", ohci->id);
 		dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry);
 		dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
 		dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
 	}
+}
 #endif
 	
 	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
diff -Nru a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
--- a/drivers/ieee1394/eth1394.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/ieee1394/eth1394.c	Tue Oct 15 20:29:12 2002
@@ -77,7 +77,7 @@
 	printk(KERN_ERR fmt, ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 546 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 601 $ Ben Collins <bcollins@debian.org>";
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
@@ -522,7 +522,7 @@
  * ethernet header, and fill it with some of our other fields. This is
  * an incoming packet from the 1394 bus.  */
 static int ether1394_write (struct hpsb_host *host, int srcid, int destid,
-			    quadlet_t *data, u64 addr, unsigned int len)
+			    quadlet_t *data, u64 addr, unsigned int len, u16 fl)
 {
 	struct sk_buff *skb;
 	char *buf = (char *)data;
@@ -682,8 +682,8 @@
 	ptask->skb = skb;
 	ptask->addr = addr;
 	ptask->dest_node = dest_node;
-	INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask);
-	schedule_task(&ptask->tq);
+	HPSB_INIT_WORK(&ptask->tq, hpsb_write_sched, ptask);
+	hpsb_schedule_work(&ptask->tq);
 
 	return 0;
 fail:
diff -Nru a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
--- a/drivers/ieee1394/eth1394.h	Tue Oct 15 20:29:21 2002
+++ b/drivers/ieee1394/eth1394.h	Tue Oct 15 20:29:21 2002
@@ -56,7 +56,7 @@
 	struct sk_buff *skb;	/* Socket buffer we are sending */
 	nodeid_t dest_node;	/* Destination of the packet */
 	u64 addr;		/* Address */
-	struct tq_struct tq;	/* The task */
+	struct hpsb_queue_struct tq;	/* The task */
 };
 
 /* IP1394 headers */
diff -Nru a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
--- a/drivers/ieee1394/highlevel.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/ieee1394/highlevel.c	Tue Oct 15 20:29:20 2002
@@ -5,6 +5,16 @@
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Christian Toegel <christian.toegel@gmx.at>
+ *        unregister address space
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        unregister address space
+ *
  */
 
 #include <linux/config.h>
@@ -129,6 +139,32 @@
         return retval;
 }
 
+int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
+{
+        int retval = 0;
+        struct hpsb_address_serve *as;
+        struct list_head *entry;
+
+        write_lock_irq(&addr_space_lock);
+
+        entry = hl->addr_list.next;
+
+        while (entry != &hl->addr_list) {
+                as = list_entry(entry, struct hpsb_address_serve, addr_list);
+                entry = entry->next;
+                if (as->start == start) {
+                        list_del(&as->as_list);
+                        list_del(&as->addr_list);
+                        kfree(as);
+                        retval = 1;
+                        break;
+                }
+        }
+
+        write_unlock_irq(&addr_space_lock);
+
+        return retval;
+}
 
 void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
                          unsigned int channel)
@@ -243,7 +279,7 @@
 }
 
 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, unsigned int length)
+                   u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -261,7 +297,7 @@
 
                         if (as->op->read != NULL) {
                                 rcode = as->op->read(host, nodeid, buffer,
-						     addr, partlength);
+						     addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -288,7 +324,7 @@
 }
 
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length)
+		    quadlet_t *data, u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -306,7 +342,7 @@
 
                         if (as->op->write != NULL) {
                                 rcode = as->op->write(host, nodeid, destid,
-						      data, addr, partlength);
+						      data, addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -334,7 +370,7 @@
 
 
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
+                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -349,7 +385,7 @@
                 if (as->end > addr) {
                         if (as->op->lock != NULL) {
                                 rcode = as->op->lock(host, nodeid, store, addr,
-                                                     data, arg, ext_tcode);
+                                                     data, arg, ext_tcode, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
@@ -367,7 +403,7 @@
 }
 
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
+                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -383,7 +419,7 @@
                         if (as->op->lock64 != NULL) {
                                 rcode = as->op->lock64(host, nodeid, store,
                                                        addr, data, arg,
-                                                       ext_tcode);
+                                                       ext_tcode, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
diff -Nru a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
--- a/drivers/ieee1394/highlevel.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/ieee1394/highlevel.h	Tue Oct 15 20:29:16 2002
@@ -74,17 +74,22 @@
          */
 
         /* These functions have to implement block reads for themselves. */
+        /* These functions either return a response code
+           or a negative number. In the first case a response will be generated; in the 
+           later case, no response will be sent and the driver, that handled the request
+           will send the response itself
+        */
         int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                     u64 addr, unsigned int length);
+                     u64 addr, unsigned int length, u16 flags);
         int (*write) (struct hpsb_host *host, int nodeid, int destid,
-		      quadlet_t *data, u64 addr, unsigned int length);
+		      quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 
         /* Lock transactions: write results of ext_tcode operation into
          * *store. */
         int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
-                     u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+                     u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
         int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
-                       u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
+                       u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 };
 
 
@@ -94,14 +99,23 @@
 void highlevel_remove_host(struct hpsb_host *host);
 void highlevel_host_reset(struct hpsb_host *host);
 
+
+/* these functions are called to handle transactions. They are called, when
+   a packet arrives. The flags argument contains the second word of the first header
+   quadlet of the incoming packet (containing transaction label, retry code,
+   transaction code and priority). These functions either return a response code
+   or a negative number. In the first case a response will be generated; in the 
+   later case, no response will be sent and the driver, that handled the request
+   will send the response itself.
+*/
 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
-                   u64 addr, unsigned int length);
+                   u64 addr, unsigned int length, u16 flags);
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-		    quadlet_t *data, u64 addr, unsigned int length);
+		    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
-                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode);
+                   u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
-                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode);
+                     u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 
 void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
                            unsigned int length);
@@ -129,6 +143,8 @@
  */
 int hpsb_register_addrspace(struct hpsb_highlevel *hl,
                             struct hpsb_address_ops *ops, u64 start, u64 end);
+
+int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start);
 
 /*
  * Enable or disable receving a certain isochronous channel through the
diff -Nru a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
--- a/drivers/ieee1394/hosts.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/ieee1394/hosts.c	Tue Oct 15 20:29:16 2002
@@ -138,7 +138,7 @@
 
 	atomic_set(&h->generation, 0);
 
-	INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
+	HPSB_INIT_WORK(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
 
         h->topology_map = h->csr.topology_map + 3;
         h->speed_map = (u8 *)(h->csr.speed_map + 2);
diff -Nru a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
--- a/drivers/ieee1394/hosts.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/ieee1394/hosts.h	Tue Oct 15 20:29:12 2002
@@ -2,13 +2,20 @@
 #define _IEEE1394_HOSTS_H
 
 #include <linux/wait.h>
-#include <linux/tqueue.h>
 #include <linux/list.h>
 #include <asm/semaphore.h>
 
 #include "ieee1394_types.h"
 #include "csr.h"
 
+/* size of the array used to store config rom (in quadlets)
+   maximum is 0x100. About 0x40 is needed for the default
+   entries. So 0x80 should provide enough space for additional
+   directories etc. 
+   Note: All lowlevel drivers are required to allocate at least
+         this amount of memory for the configuration rom!
+*/
+#define CSR_CONFIG_ROM_SIZE       0x100
 
 struct hpsb_packet;
 
@@ -23,7 +30,7 @@
 
         struct list_head pending_packets;
         spinlock_t pending_pkt_lock;
-        struct tq_struct timeout_tq;
+        struct hpsb_queue_struct timeout_tq;
 
         /* A bitmask where a set bit means that this tlabel is in use.
          * FIXME - should be handled per node instead of per bus. */
@@ -119,7 +126,7 @@
          * may not fail.  If any allocation is required, it must be done
          * earlier.
          */
-        size_t (*get_rom) (struct hpsb_host *host, const quadlet_t **pointer);
+        size_t (*get_rom) (struct hpsb_host *host, quadlet_t **pointer);
 
         /* This function shall implement packet transmission based on
          * packet->type.  It shall CRC both parts of the packet (unless
@@ -171,5 +178,25 @@
 struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra);
 void hpsb_add_host(struct hpsb_host *host);
 void hpsb_remove_host(struct hpsb_host *h);
+
+/* updates the configuration rom of a host.
+ * rom_version must be the current version,
+ * otherwise it will fail with return value -1.
+ * Return value -2 indicates that the new
+ * rom version is too big.
+ * Return value 0 indicates success
+ */
+int hpsb_update_config_rom(struct hpsb_host *host,
+      const quadlet_t *new_rom, size_t size, unsigned char rom_version);
+
+/* reads the current version of the configuration rom of a host.
+ * buffersize is the size of the buffer, rom_size
+ * returns the size of the current rom image.
+ * rom_version is the version number of the fetched rom.
+ * return value -1 indicates, that the buffer was
+ * too small, 0 indicates success.
+ */
+int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
+      size_t buffersize, size_t *rom_size, unsigned char *rom_version);
 
 #endif /* _IEEE1394_HOSTS_H */
diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
--- a/drivers/ieee1394/ieee1394_core.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/ieee1394/ieee1394_core.c	Tue Oct 15 20:29:14 2002
@@ -5,9 +5,19 @@
  *               highlevel or lowlevel code
  *
  * Copyright (C) 1999, 2000 Andreas E. Bombe
+ *                     2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        loopback functionality in hpsb_send_packet
+ *        allow highlevel drivers to disable automatic response generation
+ *              and to generate responses themselves (deferred)
+ *
  */
 
 #include <linux/config.h>
@@ -19,7 +29,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 #include <asm/semaphore.h>
@@ -72,9 +81,10 @@
 	struct list_head *lh, *next;
 
 	list_for_each_safe(lh, next, &packet->complete_tq) {
-		struct tq_struct *tq = list_entry(lh, struct tq_struct, list);
-		list_del(&tq->list);
-		schedule_task(tq);
+		struct hpsb_queue_struct *tq =
+			list_entry(lh, struct hpsb_queue_struct, hpsb_queue_list);
+		list_del(&tq->hpsb_queue_list);
+		hpsb_schedule_work(tq);
 	}
 
 	return;
@@ -83,11 +93,11 @@
 /**
  * hpsb_add_packet_complete_task - add a new task for when a packet completes
  * @packet: the packet whose completion we want the task added to
- * @tq: the tq_struct describing the task to add
+ * @tq: the hpsb_queue_struct describing the task to add
  */
-void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq)
+void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq)
 {
-	list_add_tail(&tq->list, &packet->complete_tq);
+	list_add_tail(&tq->hpsb_queue_list, &packet->complete_tq);
 	return;
 }
 
@@ -372,12 +382,19 @@
                 build_speed_map(host, host->node_count);
         }
 
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+        HPSB_INFO("selfid_complete called with successful SelfID stage "
+		"... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id);
+#endif
         /* irm_id is kept up to date by check_selfids() */
         if (host->irm_id == host->node_id) {
                 host->is_irm = 1;
                 host->is_busmgr = 1;
                 host->busmgr_id = host->node_id;
                 host->csr.bus_manager_id = host->node_id;
+        } else {
+                host->is_busmgr = 0;
+                host->is_irm = 0;
         }
 
         host->reset_retries = 0;
@@ -420,7 +437,7 @@
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
         up(&packet->state_change);
-        schedule_task(&host->timeout_tq);
+        hpsb_schedule_work(&host->timeout_tq);
 }
 
 /**
@@ -448,6 +465,45 @@
 
         packet->state = hpsb_queued;
 
+        if (packet->node_id == host->node_id)
+        { /* it is a local request, so handle it locally */
+                quadlet_t *data;
+                size_t size=packet->data_size+packet->header_size;
+
+                int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
+                data = kmalloc(packet->header_size + packet->data_size, kmflags);
+                if (!data) {
+                        HPSB_ERR("unable to allocate memory for concatenating header and data");
+                        return 0;
+                }
+
+                memcpy(data, packet->header, packet->header_size);
+
+                if (packet->data_size)
+                {
+                        if (packet->data_be) {
+                                memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size);
+                        } else {
+                                int i;
+                                quadlet_t *my_data=(quadlet_t*) ((u8*) data + packet->data_size);
+                                for (i=0; i < packet->data_size/4; i++) {
+                                        my_data[i] = cpu_to_be32(packet->data[i]);
+                                }
+                        }
+                }
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                dump_packet("send packet local:", packet->header,
+                            packet->header_size);
+#endif
+                hpsb_packet_sent(host, packet,  packet->expect_response?ACK_PENDING:ACK_COMPLETE);
+                hpsb_packet_received(host, data, size, 0);
+
+                kfree(data);
+
+                return 1;
+        }
+
         if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
                 packet->speed_code =
                         host->speed_map[(host->node_id & NODE_MASK) * 64
@@ -600,8 +656,10 @@
 {
         struct hpsb_packet *packet;
         int length, rcode, extcode;
+        quadlet_t buffer;
         nodeid_t source = data[1] >> 16;
-	nodeid_t dest = data[0] >> 16;
+        nodeid_t dest = data[0] >> 16;
+        u16 flags = (u16) data[0];
         u64 addr;
 
         /* big FIXME - no error checking is done for an out of bounds length */
@@ -610,10 +668,11 @@
         case TCODE_WRITEQ:
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_write(host, source, dest, data+3,
-					addr, 4);
+					addr, 4, flags);
 
                 if (!write_acked
-                    && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+                    && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+                    && (rcode >= 0)) {
                         /* not a broadcast write, reply */
                         PREP_REPLY_PACKET(0);
                         fill_async_write_resp(packet, rcode);
@@ -624,10 +683,11 @@
         case TCODE_WRITEB:
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_write(host, source, dest, data+4,
-					addr, data[3]>>16);
+					addr, data[3]>>16, flags);
 
                 if (!write_acked
-                    && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) {
+                    && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+                    && (rcode >= 0)) {
                         /* not a broadcast write, reply */
                         PREP_REPLY_PACKET(0);
                         fill_async_write_resp(packet, rcode);
@@ -636,12 +696,14 @@
                 break;
 
         case TCODE_READQ:
-                PREP_REPLY_PACKET(0);
-
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
-                rcode = highlevel_read(host, source, data, addr, 4);
-                fill_async_readquad_resp(packet, rcode, *data);
-                send_packet_nocare(packet);
+                rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
+
+                if (rcode >= 0) {
+                        PREP_REPLY_PACKET(0);
+                        fill_async_readquad_resp(packet, rcode, buffer);
+                        send_packet_nocare(packet);
+                }
                 break;
 
         case TCODE_READB:
@@ -650,9 +712,12 @@
 
                 addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
                 rcode = highlevel_read(host, source, packet->data, addr,
-                                       length);
-                fill_async_readblock_resp(packet, rcode, length);
-                send_packet_nocare(packet);
+                                       length, flags);
+
+                if (rcode >= 0) {
+                        fill_async_readblock_resp(packet, rcode, length);
+                        send_packet_nocare(packet);
+                }
                 break;
 
         case TCODE_LOCK_REQUEST:
@@ -670,7 +735,7 @@
                 switch (length) {
                 case 4:
                         rcode = highlevel_lock(host, source, packet->data, addr,
-                                               data[4], 0, extcode);
+                                               data[4], 0, extcode,flags);
                         fill_async_lock_resp(packet, rcode, extcode, 4);
                         break;
                 case 8:
@@ -679,13 +744,13 @@
                                 rcode = highlevel_lock(host, source,
                                                        packet->data, addr,
                                                        data[5], data[4], 
-                                                       extcode);
+                                                       extcode, flags);
                                 fill_async_lock_resp(packet, rcode, extcode, 4);
                         } else {
                                 rcode = highlevel_lock64(host, source,
                                              (octlet_t *)packet->data, addr,
                                              *(octlet_t *)(data + 4), 0ULL,
-                                             extcode);
+                                             extcode, flags);
                                 fill_async_lock_resp(packet, rcode, extcode, 8);
                         }
                         break;
@@ -694,15 +759,20 @@
                                                  (octlet_t *)packet->data, addr,
                                                  *(octlet_t *)(data + 6),
                                                  *(octlet_t *)(data + 4), 
-                                                 extcode);
+                                                 extcode, flags);
                         fill_async_lock_resp(packet, rcode, extcode, 8);
                         break;
                 default:
-                        fill_async_lock_resp(packet, RCODE_TYPE_ERROR,
+                        rcode = RCODE_TYPE_ERROR;
+                        fill_async_lock_resp(packet, rcode,
                                              extcode, 0);
                 }
 
-                send_packet_nocare(packet);
+                if (rcode >= 0) {
+                        send_packet_nocare(packet);
+                } else {
+                        free_hpsb_packet(packet);
+                }
                 break;
         }
 
@@ -811,7 +881,7 @@
         }
 
         if (!list_empty(&host->pending_packets))
-		schedule_task(&host->timeout_tq);
+		hpsb_schedule_work(&host->timeout_tq);
 
         spin_unlock_irqrestore(&host->pending_pkt_lock, flags);
 
@@ -1109,6 +1179,7 @@
 EXPORT_SYMBOL(hpsb_make_writeqpacket);
 EXPORT_SYMBOL(hpsb_make_writebpacket);
 EXPORT_SYMBOL(hpsb_make_lockpacket);
+EXPORT_SYMBOL(hpsb_make_lock64packet);
 EXPORT_SYMBOL(hpsb_make_phypacket);
 EXPORT_SYMBOL(hpsb_packet_success);
 EXPORT_SYMBOL(hpsb_make_packet);
@@ -1119,6 +1190,7 @@
 EXPORT_SYMBOL(hpsb_register_highlevel);
 EXPORT_SYMBOL(hpsb_unregister_highlevel);
 EXPORT_SYMBOL(hpsb_register_addrspace);
+EXPORT_SYMBOL(hpsb_unregister_addrspace);
 EXPORT_SYMBOL(hpsb_listen_channel);
 EXPORT_SYMBOL(hpsb_unlisten_channel);
 EXPORT_SYMBOL(highlevel_read);
@@ -1135,6 +1207,8 @@
 EXPORT_SYMBOL(hpsb_node_read);
 EXPORT_SYMBOL(hpsb_node_write);
 EXPORT_SYMBOL(hpsb_node_lock);
+EXPORT_SYMBOL(hpsb_update_config_rom);
+EXPORT_SYMBOL(hpsb_get_config_rom);
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
 EXPORT_SYMBOL(hpsb_release_unit_directory);
diff -Nru a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
--- a/drivers/ieee1394/ieee1394_core.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/ieee1394/ieee1394_core.h	Tue Oct 15 20:29:12 2002
@@ -2,7 +2,6 @@
 #ifndef _IEEE1394_CORE_H
 #define _IEEE1394_CORE_H
 
-#include <linux/tqueue.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/proc_fs.h>
@@ -78,7 +77,7 @@
 };
 
 /* add a new task for when a packet completes */
-void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq);
+void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq);
 
 static inline struct hpsb_packet *driver_packet(struct list_head *l)
 {
diff -Nru a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
--- a/drivers/ieee1394/ieee1394_transactions.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/ieee1394/ieee1394_transactions.c	Tue Oct 15 20:29:15 2002
@@ -297,14 +297,6 @@
         HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
 }
 
-
-int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr, 
-                       quadlet_t *buffer, size_t length)
-{
-        if (host->node_id != node) return -1;
-        return highlevel_read(host, node, buffer, addr, length);
-}
-
 struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node,
                                           u64 addr)
 {
@@ -400,6 +392,31 @@
         return p;
 }
 
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                           u64 addr, int extcode)
+{
+        struct hpsb_packet *p;
+
+        p = alloc_hpsb_packet(16);
+        if (!p) return NULL;
+
+        p->host = host;
+        p->tlabel = get_tlabel(host, node, 1);
+        p->node_id = node;
+
+        switch (extcode) {
+        case EXTCODE_FETCH_ADD:
+        case EXTCODE_LITTLE_ADD:
+                fill_async_lock(p, addr, extcode, 8);
+                break;
+        default:
+                fill_async_lock(p, addr, extcode, 16);
+                break;
+        }
+
+        return p;
+}
+
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
                                         quadlet_t data) 
 {
@@ -429,18 +446,6 @@
                 return -EINVAL;
         }
 
-        if (host->node_id == node) {
-                switch(highlevel_read(host, node, buffer, addr, length)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
-
         if (length == 4) {
                 packet = hpsb_make_readqpacket(host, node, addr);
         } else {
@@ -509,18 +514,6 @@
 	if (length == 0)
 		return -EINVAL;
 
-	if (host->node_id == node) {
-		switch(highlevel_write(host, node, node, buffer, addr, length)) {
-		case RCODE_COMPLETE:
-			return 0;
-		case RCODE_TYPE_ERROR:
-			return -EACCES;
-		case RCODE_ADDRESS_ERROR:
-		default:
-			return -EINVAL;
-		}
-	}
-
 	packet = hpsb_make_packet (host, node, addr, buffer, length);
 
 	if (!packet)
@@ -551,19 +544,6 @@
         struct hpsb_packet *packet;
         int retval = 0, length;
         
-        if (host->node_id == node) {
-                switch(highlevel_lock(host, node, data, addr, *data, arg,
-                                      extcode)) {
-                case RCODE_COMPLETE:
-                        return 0;
-                case RCODE_TYPE_ERROR:
-                        return -EACCES;
-                case RCODE_ADDRESS_ERROR:
-                default:
-                        return -EINVAL;
-                }
-        }
-
         packet = alloc_hpsb_packet(8);
         if (!packet) {
                 return -ENOMEM;
diff -Nru a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
--- a/drivers/ieee1394/ieee1394_transactions.h	Tue Oct 15 20:29:15 2002
+++ b/drivers/ieee1394/ieee1394_transactions.h	Tue Oct 15 20:29:15 2002
@@ -42,6 +42,8 @@
                                            size_t length);
 struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
                                          u64 addr, int extcode);
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
+                                          u64 addr, int extcode);
 struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
                                         quadlet_t data) ;
 
diff -Nru a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
--- a/drivers/ieee1394/ieee1394_types.h	Tue Oct 15 20:29:19 2002
+++ b/drivers/ieee1394/ieee1394_types.h	Tue Oct 15 20:29:19 2002
@@ -20,23 +20,6 @@
 #define __devexit_p(x) x
 #endif
 
-/* This showed up around this time */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12)
-
-# ifndef MODULE_LICENSE
-# define MODULE_LICENSE(x)
-# endif
-
-# ifndef min
-# define min(x,y) ({ \
-	const typeof(x) _x = (x);       \
-	const typeof(y) _y = (y);       \
-	(void) (&_x == &_y);            \
-	_x < _y ? _x : _y; })
-# endif
-
-#endif /* Linux version < 2.4.12 */
-
 #include <linux/spinlock.h>
 
 #ifndef list_for_each_safe
@@ -58,9 +41,34 @@
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 #endif
 
+
+/* Compatibility for task/work queues */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,42)
+/* Use task queue */
+#include <linux/tqueue.h>
+#define hpsb_queue_struct tq_struct
+#define hpsb_queue_list list
+#define hpsb_schedule_work(x) schedule_task(x)
+#define HPSB_INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z)
+#define HPSB_PREPARE_WORK(x,y,z) PREPARE_TQUEUE(x,y,z)
+#else
+/* Use work queue */
+#include <linux/workqueue.h>
+#define hpsb_queue_struct work_struct
+#define hpsb_queue_list entry
+#define hpsb_schedule_work(x) schedule_work(x)
+#define HPSB_INIT_WORK(x,y,z) INIT_WORK(x,y,z)
+#define HPSB_PREPARE_WORK(x,y,z) PREPARE_WORK(x,y,z)
+#endif
+
+
 typedef u32 quadlet_t;
 typedef u64 octlet_t;
 typedef u16 nodeid_t;
+
+typedef u8  byte_t;
+typedef u64 nodeaddr_t;
+typedef u16 arm_length_t;
 
 #define BUS_MASK  0xffc0
 #define NODE_MASK 0x003f
diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
--- a/drivers/ieee1394/ohci1394.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/ieee1394/ohci1394.c	Tue Oct 15 20:29:20 2002
@@ -91,7 +91,6 @@
 #include <asm/byteorder.h>
 #include <asm/atomic.h>
 #include <asm/uaccess.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 
@@ -154,7 +153,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 578 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 601 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 MODULE_PARM(attempt_root,"i");
@@ -1905,7 +1904,7 @@
 	ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu;
 }
 
-static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
 	struct ti_ohci *ohci=host->hostdata;
 
diff -Nru a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
--- a/drivers/ieee1394/pcilynx.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/ieee1394/pcilynx.c	Tue Oct 15 20:29:16 2002
@@ -1677,7 +1677,7 @@
 
 
 
-static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr)
+static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr)
 {
         struct ti_lynx *lynx = host->hostdata;
         *ptr = lynx->config_rom;
diff -Nru a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
--- a/drivers/ieee1394/raw1394.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/ieee1394/raw1394.c	Tue Oct 15 20:29:11 2002
@@ -4,9 +4,27 @@
  * Raw interface to the bus
  *
  * Copyright (C) 1999, 2000 Andreas E. Bombe
+ *               2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *                     2002 Christian Toegel <christian.toegel@gmx.at>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
+ *
+ *
+ * Contributions:
+ *
+ * Manfred Weihs <weihs@ict.tuwien.ac.at>
+ *        configuration ROM manipulation
+ *        address range mapping
+ *        adaptation for new (transparent) loopback mechanism
+ *        sending of arbitrary async packets
+ * Christian Toegel <christian.toegel@gmx.at>
+ *        address range mapping
+ *        lock64 request
+ *        transmit physical packet
+ *        busreset notification control (switch on/off)
+ *        busreset with selection of type (short/long)
+ *        request_reply
  */
 
 #include <linux/kernel.h>
@@ -40,6 +58,16 @@
 #define ptr2int(x) ((u64)(u32)x)
 #endif
 
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+#define RAW1394_DEBUG
+#endif
+
+#ifdef RAW1394_DEBUG
+#define DBGMSG(fmt, args...) \
+printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
+#else
+#define DBGMSG(fmt, args...)
+#endif
 
 static devfs_handle_t devfs_handle;
 
@@ -53,6 +81,21 @@
 static atomic_t iso_buffer_size;
 static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */
 
+static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+             u64 addr, unsigned int length, u16 flags);
+static int arm_write (struct hpsb_host *host, int nodeid, int destid,
+              quadlet_t *data, u64 addr, unsigned int length, u16 flags);
+static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
+             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
+static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
+               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
+static struct hpsb_address_ops arm_ops = {
+        read:     arm_read,
+        write:    arm_write,
+        lock:     arm_lock,
+        lock64:   arm_lock64,
+};
+
 static void queue_complete_cb(struct pending_request *req);
 
 static struct pending_request *__alloc_pending_request(int flags)
@@ -64,7 +107,7 @@
         if (req != NULL) {
                 memset(req, 0, sizeof(struct pending_request));
                 INIT_LIST_HEAD(&req->list);
-		INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
+                HPSB_INIT_WORK(&req->tq, (void(*)(void*))queue_complete_cb, NULL);
         }
 
         return req;
@@ -128,7 +171,8 @@
                 req->req.length = 0;
         }
 
-        free_tlabel(packet->host, packet->node_id, packet->tlabel);
+        if (req->req.type != RAW1394_REQ_PHYPACKET)
+                free_tlabel(packet->host, packet->node_id, packet->tlabel);
 
         queue_complete_req(req);
 }
@@ -137,6 +181,7 @@
 static void add_host(struct hpsb_host *host)
 {
         struct host_info *hi;
+        unsigned long flags;
 
         hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL);
         if (hi != NULL) {
@@ -144,10 +189,10 @@
                 hi->host = host;
                 INIT_LIST_HEAD(&hi->file_info_list);
 
-                spin_lock_irq(&host_info_lock);
+                spin_lock_irqsave(&host_info_lock, flags);
                 list_add_tail(&hi->list, &host_info_list);
                 host_count++;
-                spin_unlock_irq(&host_info_lock);
+                spin_unlock_irqrestore(&host_info_lock, flags);
         }
 
         atomic_inc(&internal_generation);
@@ -172,15 +217,22 @@
 static void remove_host(struct hpsb_host *host)
 {
         struct host_info *hi;
+        unsigned long flags;
 
-        spin_lock_irq(&host_info_lock);
+        spin_lock_irqsave(&host_info_lock, flags);
         hi = find_host_info(host);
 
         if (hi != NULL) {
                 list_del(&hi->list);
                 host_count--;
+                /* 
+                   FIXME: adressranges should be removed 
+                   and fileinfo states should be initialized
+                   (including setting generation to 
+                   internal-generation ...)
+                */
         }
-        spin_unlock_irq(&host_info_lock);
+        spin_unlock_irqrestore(&host_info_lock, flags);
 
         if (hi == NULL) {
                 printk(KERN_ERR "raw1394: attempt to remove unknown host "
@@ -207,20 +259,22 @@
         if (hi != NULL) {
                 list_for_each(lh, &hi->file_info_list) {
                         fi = list_entry(lh, struct file_info, list);
-                        req = __alloc_pending_request(SLAB_ATOMIC);
+                        if (fi->notification == RAW1394_NOTIFY_ON) {
+                                req = __alloc_pending_request(SLAB_ATOMIC);
 
-                        if (req != NULL) {
-                                req->file_info = fi;
-                                req->req.type = RAW1394_REQ_BUS_RESET;
-                                req->req.generation = get_hpsb_generation(host);
-                                req->req.misc = (host->node_id << 16)
-                                        | host->node_count;
-                                if (fi->protocol_version > 3) {
-                                        req->req.misc |= ((host->irm_id
-                                                           & NODE_MASK) << 8);
-                                }
+                                if (req != NULL) {
+                                        req->file_info = fi;
+                                        req->req.type = RAW1394_REQ_BUS_RESET;
+                                        req->req.generation = get_hpsb_generation(host);
+                                        req->req.misc = (host->node_id << 16)
+                                                | host->node_count;
+                                        if (fi->protocol_version > 3) {
+                                                req->req.misc |= ((host->irm_id
+                                                                   & NODE_MASK) << 8);
+                                        }
 
-                                queue_complete_req(req);
+                                        queue_complete_req(req);
+                                }
                         }
                 }
         }
@@ -529,7 +583,7 @@
 {
         int channel = req->req.misc;
 
-        spin_lock(&host_info_lock);
+        spin_lock_irq(&host_info_lock);
         if ((channel > 63) || (channel < -64)) {
                 req->req.error = RAW1394_ERROR_INVALID_ARG;
         } else if (channel >= 0) {
@@ -556,7 +610,7 @@
 
         req->req.length = 0;
         queue_complete_req(req);
-        spin_unlock(&host_info_lock);
+        spin_unlock_irq(&host_info_lock);
 }
 
 static void handle_fcp_listen(struct file_info *fi, struct pending_request *req)
@@ -579,84 +633,9 @@
         queue_complete_req(req);
 }
 
-static int handle_local_request(struct file_info *fi,
-                                struct pending_request *req, int node)
-{
-        u64 addr = req->req.address & 0xffffffffffffULL;
-
-        req->data = kmalloc(req->req.length, SLAB_KERNEL);
-        if (!req->data) return -ENOMEM;
-        req->free_data = 1;
-
-        switch (req->req.type) {
-        case RAW1394_REQ_ASYNC_READ:
-                req->req.error = highlevel_read(fi->host, node, req->data, addr,
-                                                req->req.length);
-                break;
-
-        case RAW1394_REQ_ASYNC_WRITE:
-                if (copy_from_user(req->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                req->req.error = highlevel_write(fi->host, node, node, req->data,
-                                                 addr, req->req.length);
-                req->req.length = 0;
-                break;
 
-        case RAW1394_REQ_LOCK:
-                if ((req->req.misc == EXTCODE_FETCH_ADD)
-                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
-                        if (req->req.length != 4) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                } else {
-                        if (req->req.length != 8) {
-                                req->req.error = RAW1394_ERROR_INVALID_ARG;
-                                break;
-                        }
-                }
-
-                if (copy_from_user(req->data, int2ptr(req->req.sendb),
-                                   req->req.length)) {
-                        req->req.error = RAW1394_ERROR_MEMFAULT;
-                        break;
-                }
-
-                if (req->req.length == 8) {
-                        req->req.error = highlevel_lock(fi->host, node,
-                                                        req->data, addr,
-                                                        req->data[1],
-                                                        req->data[0],
-                                                        req->req.misc);
-                        req->req.length = 4;
-                } else {
-                        req->req.error = highlevel_lock(fi->host, node,
-                                                        req->data, addr,
-                                                        req->data[0], 0,
-                                                        req->req.misc);
-                }
-                break;
-
-        case RAW1394_REQ_LOCK64:
-        default:
-                req->req.error = RAW1394_ERROR_STATE_ORDER;
-        }
-
-        if (req->req.error)
-                req->req.length = 0;
-        if (req->req.error >= 0)
-                req->req.error |= ACK_PENDING << 16;
-
-        queue_complete_req(req);
-        return sizeof(struct raw1394_request);
-}
-
-static int handle_remote_request(struct file_info *fi,
-                                 struct pending_request *req, int node)
+static int handle_async_request(struct file_info *fi,
+                                struct pending_request *req, int node)
 {
         struct hpsb_packet *packet = NULL;
         u64 addr = req->req.address & 0xffffffffffffULL;
@@ -664,11 +643,13 @@
         switch (req->req.type) {
         case RAW1394_REQ_ASYNC_READ:
                 if (req->req.length == 4) {
+                        DBGMSG("quadlet_read_request called");        
                         packet = hpsb_make_readqpacket(fi->host, node, addr);
                         if (!packet) return -ENOMEM;
 
                         req->data = &packet->header[3];
                 } else {
+                        DBGMSG("block_read_request called");
                         packet = hpsb_make_readbpacket(fi->host, node, addr,
                                                        req->req.length);
                         if (!packet) return -ENOMEM;
@@ -681,6 +662,7 @@
                 if (req->req.length == 4) {
                         quadlet_t x;
 
+                        DBGMSG("quadlet_write_request called");
                         if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) {
                                 req->req.error = RAW1394_ERROR_MEMFAULT;
                         }
@@ -689,6 +671,7 @@
                                                         x);
                         if (!packet) return -ENOMEM;
                 } else {
+                        DBGMSG("block_write_request called");
                         packet = hpsb_make_writebpacket(fi->host, node, addr,
                                                         req->req.length);
                         if (!packet) return -ENOMEM;
@@ -702,6 +685,7 @@
                 break;
 
         case RAW1394_REQ_LOCK:
+                DBGMSG("lock_request called");
                 if ((req->req.misc == EXTCODE_FETCH_ADD)
                     || (req->req.misc == EXTCODE_LITTLE_ADD)) {
                         if (req->req.length != 4) {
@@ -730,6 +714,33 @@
                 break;
 
         case RAW1394_REQ_LOCK64:
+                DBGMSG("lock64_request called");
+                if ((req->req.misc == EXTCODE_FETCH_ADD)
+                    || (req->req.misc == EXTCODE_LITTLE_ADD)) {
+                        if (req->req.length != 8) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                } else {
+                        if (req->req.length != 16) {
+                                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                                break;
+                        }
+                }
+                packet = hpsb_make_lock64packet(fi->host, node, addr,
+                                                req->req.misc);
+                if (!packet) return -ENOMEM;
+
+                if (copy_from_user(packet->data, int2ptr(req->req.sendb),
+                                   req->req.length)) {
+                        req->req.error = RAW1394_ERROR_MEMFAULT;
+                        break;
+                }
+
+                req->data = packet->data;
+                req->req.length = 8;
+                break;
+
         default:
                 req->req.error = RAW1394_ERROR_STATE_ORDER;
         }
@@ -783,8 +794,7 @@
                 return sizeof(struct raw1394_request);
         }
 
-        req->tq.data = req;
-        req->tq.routine = (void (*)(void*))queue_complete_req;
+	HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req);
         req->req.length = 0;
 	hpsb_add_packet_complete_task(packet, &req->tq);
 
@@ -803,25 +813,1092 @@
         return sizeof(struct raw1394_request);
 }
 
-static int state_connected(struct file_info *fi, struct pending_request *req)
+static int handle_async_send(struct file_info *fi, struct pending_request *req)
 {
-        int node = req->req.address >> 48;
+        struct hpsb_packet *packet;
+        int header_length = req->req.misc & 0xffff;
+        int expect_response = req->req.misc >> 16;
 
-        req->req.error = RAW1394_ERROR_NONE;
+        if ((header_length > req->req.length) ||
+            (header_length  < 12))
+        {
+                req->req.error = RAW1394_ERROR_INVALID_ARG;
+                req->req.length = 0;
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
+        } 
 
-        if (req->req.type ==  RAW1394_REQ_ISO_SEND) {
-                return handle_iso_send(fi, req, node);
+        packet = alloc_hpsb_packet(req->req.length-header_length);
+        req->packet = packet;
+        if (!packet) return -ENOMEM;
+
+        if (copy_from_user(packet->header, int2ptr(req->req.sendb),
+                           header_length)) {
+                req->req.error = RAW1394_ERROR_MEMFAULT;
+                req->req.length = 0;
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
         }
 
-        if (req->req.generation != get_hpsb_generation(fi->host)) {
-                req->req.error = RAW1394_ERROR_GENERATION;
-                req->req.generation = get_hpsb_generation(fi->host);
+        if (copy_from_user(packet->data, ((u8*) int2ptr(req->req.sendb)) + header_length,
+                           packet->data_size)) {
+                req->req.error = RAW1394_ERROR_MEMFAULT;
                 req->req.length = 0;
                 queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
+        packet->type = hpsb_async;
+        packet->node_id = packet->header[0] >> 16;
+        packet->tcode = (packet->header[0] >> 4) & 0xf;
+        packet->tlabel = (packet->header[0] >> 10) &0x3f;
+        packet->host = fi->host;
+        packet->expect_response = expect_response;
+        packet->header_size=header_length;
+        packet->data_size=req->req.length-header_length;
+
+	HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req);
+        req->req.length = 0;
+        hpsb_add_packet_complete_task(packet, &req->tq);
+
+        spin_lock_irq(&fi->reqlists_lock);
+        list_add_tail(&req->list, &fi->req_pending);
+        spin_unlock_irq(&fi->reqlists_lock);
+
+        /* Update the generation of the packet just before sending. */
+        packet->generation = get_hpsb_generation(fi->host);
+
+        if (!hpsb_send_packet(packet)) {
+                req->req.error = RAW1394_ERROR_SEND_ERROR;
+                queue_complete_req(req);
+        }
+
+        return sizeof(struct raw1394_request);
+}
+
+static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+             u64 addr, unsigned int length, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;
+        int found=0, size=0, rcode=-1;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        DBGMSG("arm_read  called by node: %X"
+              "addr: %4.4x %8.8x length: %u", nodeid,
+              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+              length);
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+length))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_read addr_entry FOUND");
+        }
+        if (arm_addr->rec_length < length) {
+                DBGMSG("arm_read blocklength too big -> rcode_data_error");
+                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_READ) {
+                        if (!(arm_addr->client_transactions & ARM_READ)) {
+                                memcpy(buffer,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), 
+                                       length);
+                                DBGMSG("arm_read -> (rcode_complete)");
+                                rcode = RCODE_COMPLETE;
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_read -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_READ) {
+                DBGMSG("arm_read -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_read -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                                length * sizeof(byte_t) +
+                                sizeof (struct arm_request_response);
+                } else {
+                        size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                                sizeof (struct arm_request_response);
+                }
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_read -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer  = NULL;
+                arm_resp->buffer = NULL;
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer = ((byte_t *)(arm_resp) + 
+                                (sizeof(struct arm_response)));
+                        memcpy (arm_resp->buffer,
+                                (arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), 
+                                length);
+                        arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                                sizeof (struct arm_request_response) +
+                                sizeof (struct arm_request) +
+                                sizeof (struct arm_response));
+                }
+                arm_resp->buffer_length = (rcode == RCODE_COMPLETE) ? length : 0;
+                arm_resp->response_code = rcode;
+                arm_req->buffer_length = 0;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = 0;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_write (struct hpsb_host *host, int nodeid, int destid,
+              quadlet_t *data, u64 addr, unsigned int length, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;        
+        int found=0, size=0, rcode=-1, length_conflict=0;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        DBGMSG("arm_write called by node: %X"
+              "addr: %4.4x %8.8x length: %u", nodeid,
+              (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+              length);
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+length))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_write addr_entry FOUND");
+        }
+        if (arm_addr->rec_length < length) {
+                DBGMSG("arm_write blocklength too big -> rcode_data_error");
+                length_conflict = 1;
+                rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_WRITE) {
+                        if (!(arm_addr->client_transactions & ARM_WRITE)) {
+                                memcpy((arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        data, length);
+                                DBGMSG("arm_write -> (rcode_complete)");
+                                rcode = RCODE_COMPLETE;
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_write -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_WRITE) {
+                DBGMSG("arm_write -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_write -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request my be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        (length) * sizeof(byte_t) +
+                        sizeof (struct arm_request_response);
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_write -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = NULL;
+                memcpy (arm_req->buffer, data, length);
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_req->buffer_length = length;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = 0;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = destid;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->buffer_length = 0;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store,
+             u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;        
+        int found=0, size=0, rcode=-1;
+        quadlet_t old, new;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+                DBGMSG("arm_lock  called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", 
+                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+                      ext_tcode & 0xFF , be32_to_cpu(data));
+        } else {
+                DBGMSG("arm_lock  called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", 
+                      nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF),
+                      ext_tcode & 0xFF , be32_to_cpu(data), be32_to_cpu(arg));
+        }
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search address-entry */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_lock addr_entry FOUND");
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_LOCK) {
+                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
+                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        sizeof(old));
+                                switch (ext_tcode) {
+                                        case (EXTCODE_MASK_SWAP):
+                                                new = data | (old & ~arg);
+                                                break;
+                                        case (EXTCODE_COMPARE_SWAP):
+                                                if (old == arg) {
+                                                        new = data;
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_FETCH_ADD):
+                                                new = cpu_to_be32(be32_to_cpu(data) + be32_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_LITTLE_ADD):
+                                                new = cpu_to_le32(le32_to_cpu(data) + le32_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_BOUNDED_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be32(be32_to_cpu(data) + 
+                                                                be32_to_cpu(old));
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_WRAP_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be32(be32_to_cpu(data) + 
+                                                                be32_to_cpu(old));
+                                                } else {
+                                                        new = data;
+                                                }
+                                                break;
+                                        default:
+                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                                                printk(KERN_ERR "raw1394: arm_lock FAILED "
+                                                "ext_tcode not allowed -> rcode_type_error\n");
+                                                break;
+                                } /*switch*/
+                                if (rcode == -1) {
+                                        DBGMSG("arm_lock -> (rcode_complete)");
+                                        rcode = RCODE_COMPLETE;
+                                        memcpy (store, &old, sizeof(*store));
+                                        memcpy ((arm_addr->addr_space_buffer)+
+                                                (addr-(arm_addr->start)), 
+                                                &new, sizeof(*store));
+                                }
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_lock -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_LOCK) {
+                DBGMSG("arm_lock -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        DBGMSG("arm_lock -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        3 * sizeof(*store) + 
+                        sizeof (struct arm_request_response);  /* maximum */
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        DBGMSG("arm_lock -> rcode_conflict_error");
+                        spin_unlock(&host_info_lock);
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = ((byte_t *)(arm_req->buffer) + 
+                        (2* sizeof(*store)));
+                if ((ext_tcode == EXTCODE_FETCH_ADD) || 
+                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
+                        arm_req->buffer_length = sizeof(*store);
+                        memcpy (arm_req->buffer, &data, sizeof(*store));
+
+                } else {
+                        arm_req->buffer_length = 2 * sizeof(*store);
+                        memcpy (arm_req->buffer, &arg,  sizeof(*store));
+                        memcpy (((arm_req->buffer) + sizeof(*store)), 
+                                &data, sizeof(*store));
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer_length = sizeof(*store);
+                        memcpy (arm_resp->buffer, &old, sizeof(*store));
+                } else {
+                        arm_resp->buffer = NULL;
+                        arm_resp->buffer_length = 0;
+                }
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | 
+                        (ARM_LOCK & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = ext_tcode;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response) +
+                        2* sizeof (*store));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store,
+               u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
+{
+        struct pending_request *req;
+        struct list_head *lh;
+        struct host_info *hi;
+        struct file_info *fi = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        struct arm_request  *arm_req = NULL;
+        struct arm_response *arm_resp = NULL;
+        int found=0, size=0, rcode=-1;
+        octlet_t old, new;
+        struct arm_request_response *arm_req_resp = NULL;
+
+        if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) ||
+                ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) {
+                DBGMSG("arm_lock64 called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ",
+                      nodeid, (u16) ((addr >>32) & 0xFFFF),
+                      (u32) (addr & 0xFFFFFFFF), 
+                      ext_tcode & 0xFF , 
+                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF));
+        } else {
+                DBGMSG("arm_lock64 called by node: %X "
+                      "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: "
+                      "%8.8X %8.8X ",
+                      nodeid, (u16) ((addr >>32) & 0xFFFF),
+                      (u32) (addr & 0xFFFFFFFF), 
+                      ext_tcode & 0xFF , 
+                      (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(data) & 0xFFFFFFFF),
+                      (u32) ((be64_to_cpu(arg)  >> 32) & 0xFFFFFFFF), 
+                      (u32) (be64_to_cpu(arg)  & 0xFFFFFFFF));
+        }
+        spin_lock(&host_info_lock);
+        hi = find_host_info(host); /* search addressentry in file_info's for host */
+        if (hi != NULL) {
+                list_for_each(lh, &hi->file_info_list) {
+                        fi = list_entry(lh, struct file_info, list);
+                        entry = fi->addr_list.next;
+                        while (entry != &(fi->addr_list)) {
+                                arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                if (((arm_addr->start) <= (addr)) && 
+                                        ((arm_addr->end) >= (addr+sizeof(*store)))) {
+                                        found = 1;
+                                        break;
+                                }
+                                entry = entry->next;
+                        }
+                        if (found) {
+                                break;
+                        }
+                }
+        }
+        rcode = -1;
+        if (!found) {
+                printk(KERN_ERR "raw1394: arm_lock64 FAILED addr_entry not found"
+                " -> rcode_address_error\n");
+                spin_unlock(&host_info_lock);
+                return (RCODE_ADDRESS_ERROR);
+        } else {
+                DBGMSG("arm_lock64 addr_entry FOUND");
+        }
+        if (rcode == -1) {
+                if (arm_addr->access_rights & ARM_LOCK) {
+                        if (!(arm_addr->client_transactions & ARM_LOCK)) {
+                                memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)),
+                                        sizeof(old));
+                                switch (ext_tcode) {
+                                        case (EXTCODE_MASK_SWAP):
+                                                new = data | (old & ~arg);
+                                                break;
+                                        case (EXTCODE_COMPARE_SWAP):
+                                                if (old == arg) {
+                                                        new = data;
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_FETCH_ADD):
+                                                new = cpu_to_be64(be64_to_cpu(data) + be64_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_LITTLE_ADD):
+                                                new = cpu_to_le64(le64_to_cpu(data) + le64_to_cpu(old));
+                                                break;
+                                        case (EXTCODE_BOUNDED_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be64(be64_to_cpu(data) + 
+                                                                be64_to_cpu(old));
+                                                } else {
+                                                        new = old;
+                                                }
+                                                break;
+                                        case (EXTCODE_WRAP_ADD):
+                                                if (old != arg) {
+                                                        new = cpu_to_be64(be64_to_cpu(data) + 
+                                                                be64_to_cpu(old));
+                                                } else {
+                                                        new = data;
+                                                }
+                                                break;
+                                        default:
+                                                printk(KERN_ERR "raw1394: arm_lock64 FAILED "
+                                                "ext_tcode not allowed -> rcode_type_error\n");
+                                                rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                                                break;
+                                } /*switch*/
+                                if (rcode == -1) {
+                                        DBGMSG("arm_lock64 -> (rcode_complete)");
+                                        rcode = RCODE_COMPLETE;
+                                        memcpy (store, &old, sizeof(*store));
+                                        memcpy ((arm_addr->addr_space_buffer)+
+                                                (addr-(arm_addr->start)), 
+                                                &new, sizeof(*store));
+                                } 
+                        }
+                } else {
+                        rcode = RCODE_TYPE_ERROR; /* function not allowed */
+                        DBGMSG("arm_lock64 -> rcode_type_error (access denied)");
+                }
+        }
+        if (arm_addr->notification_options & ARM_LOCK) {
+                DBGMSG("arm_lock64 -> entering notification-section");
+                req = __alloc_pending_request(SLAB_ATOMIC);
+                if (!req) {
+                        spin_unlock(&host_info_lock);
+                        DBGMSG("arm_lock64 -> rcode_conflict_error");
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                size =  sizeof(struct arm_request)+sizeof(struct arm_response) +
+                        3 * sizeof(*store) +
+                        sizeof (struct arm_request_response); /* maximum */
+                req->data = kmalloc(size, SLAB_ATOMIC);
+                if (!(req->data)) {
+                        free_pending_request(req);
+                        spin_unlock(&host_info_lock);
+                        DBGMSG("arm_lock64 -> rcode_conflict_error");
+                        return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 
+                                                        The request may be retried */
+                }
+                req->free_data=1;
+                arm_req_resp = (struct arm_request_response *) (req->data);
+                arm_req  = (struct arm_request *) ((byte_t *)(req->data) + 
+                        (sizeof (struct arm_request_response)));
+                arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + 
+                        (sizeof(struct arm_request)));
+                arm_req->buffer = ((byte_t *)(arm_resp) + 
+                        (sizeof(struct arm_response)));
+                arm_resp->buffer = ((byte_t *)(arm_req->buffer) + 
+                        (2* sizeof(*store)));
+                if ((ext_tcode == EXTCODE_FETCH_ADD) || 
+                        (ext_tcode == EXTCODE_LITTLE_ADD)) {
+                        arm_req->buffer_length = sizeof(*store);
+                        memcpy (arm_req->buffer, &data, sizeof(*store));
+
+                } else {
+                        arm_req->buffer_length = 2 * sizeof(*store);
+                        memcpy (arm_req->buffer, &arg,  sizeof(*store));
+                        memcpy (((arm_req->buffer) + sizeof(*store)), 
+                                &data, sizeof(*store));
+                }
+                if (rcode == RCODE_COMPLETE) {
+                        arm_resp->buffer_length = sizeof(*store);
+                        memcpy (arm_resp->buffer, &old, sizeof(*store));
+                } else {
+                        arm_resp->buffer = NULL;
+                        arm_resp->buffer_length = 0;
+                }
+                req->file_info = fi;
+                req->req.type = RAW1394_REQ_ARM;
+                req->req.generation = get_hpsb_generation(host);
+                req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | 
+                        (ARM_LOCK & 0xFF));
+                req->req.tag  = arm_addr->arm_tag;
+                req->req.recvb = arm_addr->recvb;
+                req->req.length = size;
+                arm_req->generation = req->req.generation;
+                arm_req->extended_transaction_code = ext_tcode;
+                arm_req->destination_offset = addr;
+                arm_req->source_nodeid = nodeid;
+                arm_req->destination_nodeid = host->node_id;
+                arm_req->tlabel = (flags >> 10) & 0x3f;
+                arm_req->tcode = (flags >> 4) & 0x0f;
+                arm_resp->response_code = rcode;
+                arm_req_resp->request  = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response));
+                arm_req_resp->response = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request));
+                arm_req->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response));
+                arm_resp->buffer = int2ptr((arm_addr->recvb) + 
+                        sizeof (struct arm_request_response) +
+                        sizeof (struct arm_request) +
+                        sizeof (struct arm_response) +
+                        2* sizeof (*store));
+                queue_complete_req(req);
+        }
+        spin_unlock(&host_info_lock);
+        return(rcode);
+}
+
+static int arm_register(struct file_info *fi, struct pending_request *req)
+{
+        int retval;
+        struct arm_addr *addr;
+        struct list_head *lh, *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct list_head *entry;
+        struct arm_addr  *arm_addr = NULL;
+        int same_host, another_host;
+        unsigned long flags;
+
+        DBGMSG("arm_register called "
+              "addr(Offset): %8.8x %8.8x length: %u "
+              "rights: %2.2X notify: %2.2X "
+              "max_blk_len: %4.4X",
+              (u32) ((req->req.address >>32) & 0xFFFF),
+              (u32) (req->req.address & 0xFFFFFFFF),
+              req->req.length, ((req->req.misc >> 8) & 0xFF),
+              (req->req.misc & 0xFF),((req->req.misc >> 16) & 0xFFFF));
+        /* check addressrange */
+        if ((((req->req.address) & ~(0xFFFFFFFFFFFF)) != 0) ||
+                (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFF)) != 0)) {
+                req->req.length = 0;
+                return (-EINVAL);
+        }
+        /* addr-list-entry for fileinfo */
+        addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL); 
+        if (!addr) {
+                req->req.length = 0;
+                return (-ENOMEM);
+        } 
+        /* allocation of addr_space_buffer */
+        addr->addr_space_buffer = (u8 *)kmalloc(req->req.length,SLAB_KERNEL);
+        if (!(addr->addr_space_buffer)) {
+                kfree(addr);
+                req->req.length = 0;
+                return (-ENOMEM);
+        }
+        /* initialization of addr_space_buffer */
+        if ((req->req.sendb)== (unsigned long)NULL) {
+                /* init: set 0 */
+                memset(addr->addr_space_buffer, 0,req->req.length);
+        } else {
+                /* init: user -> kernel */
+                if (copy_from_user(addr->addr_space_buffer,int2ptr(req->req.sendb),
+                        req->req.length)) {
+                        kfree(addr->addr_space_buffer);
+                        kfree(addr);
+                        return (-EFAULT);
+                }
+        }
+        INIT_LIST_HEAD(&addr->addr_list);
+        addr->arm_tag   = req->req.tag;
+        addr->start     = req->req.address;
+        addr->end       = req->req.address + req->req.length;
+        addr->access_rights = (u8) (req->req.misc & 0x0F);
+        addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F);
+        addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F);
+        addr->access_rights |= addr->client_transactions;
+        addr->notification_options |= addr->client_transactions;
+        addr->recvb     = req->req.recvb;
+        addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
+        spin_lock_irqsave(&host_info_lock, flags);
+        hi = find_host_info(fi->host);
+        same_host = 0;
+        another_host = 0;
+        /* same host with address-entry containing same addressrange ? */
+        list_for_each(lh, &hi->file_info_list) {
+                fi_hlp = list_entry(lh, struct file_info, list);
+                entry = fi_hlp->addr_list.next;
+                while (entry != &(fi_hlp->addr_list)) {
+                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                        if ( (arm_addr->start == addr->start) && 
+                                (arm_addr->end == addr->end)) {
+                                DBGMSG("same host ownes same "
+                                        "addressrange -> EALREADY");
+                                same_host = 1;
+                                break;
+                        }
+                        entry = entry->next;
+                }
+                if (same_host) {
+                        break;
+                }
+        }
+        if (same_host) {
+                /* addressrange occupied by same host */
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EALREADY);
+        }
+        /* another host with valid address-entry containing same addressrange */
+        list_for_each(lh_1, &host_info_list) {
+                hi = list_entry(lh_1, struct host_info, list);
+                if (hi->host != fi->host) {
+                        list_for_each(lh_2, &hi->file_info_list) {
+                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                                entry = fi_hlp->addr_list.next;
+                                while (entry != &(fi_hlp->addr_list)) {
+                                        arm_addr = list_entry(entry, struct arm_addr, addr_list);
+                                        if ( (arm_addr->start == addr->start) && 
+                                                (arm_addr->end == addr->end)) {
+                                                DBGMSG("another host ownes same "
+                                                "addressrange");
+                                                another_host = 1;
+                                                break;
+                                        }
+                                        entry = entry->next;
+                                }
+                                if (another_host) {
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (another_host) {
+                DBGMSG("another hosts entry is valid -> SUCCESS");
+                if (copy_to_user(int2ptr(req->req.recvb),
+                        int2ptr(&addr->start),sizeof(u64))) {
+                        printk(KERN_ERR "raw1394: arm_register failed "
+                              " address-range-entry is invalid -> EFAULT !!!\n");
+                        kfree(addr->addr_space_buffer);
+                        kfree(addr);
+                        spin_unlock_irqrestore(&host_info_lock, flags);
+                        return (-EFAULT);
+                }
+                free_pending_request(req); /* immediate success or fail */
+                /* INSERT ENTRY */
+                list_add_tail(&addr->addr_list, &fi->addr_list);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return sizeof(struct raw1394_request);
+        }
+        retval = hpsb_register_addrspace(hl_handle, &arm_ops, req->req.address,
+                req->req.address + req->req.length);
+        if (retval) {
+               /* INSERT ENTRY */
+               list_add_tail(&addr->addr_list, &fi->addr_list);
+        } else {
+                DBGMSG("arm_register failed errno: %d \n",retval);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EALREADY); 
+        }
+        spin_unlock_irqrestore(&host_info_lock, flags);
+        free_pending_request(req); /* immediate success or fail */
+        return sizeof(struct raw1394_request);
+}
+
+static int arm_unregister(struct file_info *fi, struct pending_request *req)
+{
+        int found  = 0;
+        int retval = 0;
+        struct list_head *entry;
+        struct arm_addr  *addr = NULL;
+        struct list_head *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct arm_addr  *arm_addr = NULL;
+        int another_host;
+        unsigned long flags;
+
+        DBGMSG("arm_Unregister called addr(Offset): "
+              "%8.8x %8.8x",
+              (u32) ((req->req.address >>32) & 0xFFFF),
+              (u32) (req->req.address & 0xFFFFFFFF));
+        spin_lock_irqsave(&host_info_lock, flags);
+        /* get addr */
+        entry = fi->addr_list.next;
+        while (entry != &(fi->addr_list)) {
+                addr = list_entry(entry, struct arm_addr, addr_list);
+                if (addr->start == req->req.address) {
+                        found = 1;
+                        break;
+                }
+                entry = entry->next;
+        }
+        if (!found) {
+                DBGMSG("arm_Unregister addr not found");
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EINVAL);
+        }
+        DBGMSG("arm_Unregister addr found");
+        another_host = 0;
+        /* another host with valid address-entry containing 
+           same addressrange */
+        list_for_each(lh_1, &host_info_list) {
+                hi = list_entry(lh_1, struct host_info, list);
+                if (hi->host != fi->host) {
+                        list_for_each(lh_2, &hi->file_info_list) {
+                                fi_hlp = list_entry(lh_2, struct file_info, list);
+                                entry = fi_hlp->addr_list.next;
+                                while (entry != &(fi_hlp->addr_list)) {
+                                        arm_addr = list_entry(entry, 
+                                                struct arm_addr, addr_list);
+                                        if (arm_addr->start == 
+                                                addr->start) {
+                                                DBGMSG("another host ownes "
+                                                "same addressrange");
+                                                another_host = 1;
+                                                break;
+                                        }
+                                        entry = entry->next;
+                                }
+                                if (another_host) {
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (another_host) {
+                DBGMSG("delete entry from list -> success");
+                list_del(&addr->addr_list);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+                free_pending_request(req); /* immediate success or fail */
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return sizeof(struct raw1394_request);
+        } 
+        retval = hpsb_unregister_addrspace(hl_handle, addr->start);
+        if (!retval) {
+                printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n");
+                spin_unlock_irqrestore(&host_info_lock, flags);
+                return (-EINVAL);
+        }
+        DBGMSG("delete entry from list -> success");
+        list_del(&addr->addr_list);
+        spin_unlock_irqrestore(&host_info_lock, flags);
+        kfree(addr->addr_space_buffer);
+        kfree(addr);
+        free_pending_request(req); /* immediate success or fail */
+        return sizeof(struct raw1394_request);
+}
+
+static int reset_notification(struct file_info *fi, struct pending_request *req)
+{
+        DBGMSG("reset_notification called - switch %s ",
+                (req->req.misc == RAW1394_NOTIFY_OFF)?"OFF":"ON");
+        if ((req->req.misc == RAW1394_NOTIFY_OFF) ||
+                (req->req.misc == RAW1394_NOTIFY_ON)) {
+                fi->notification=(u8)req->req.misc;
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                return sizeof(struct raw1394_request);
+        } 
+        /* error EINVAL (22) invalid argument */
+        return (-EINVAL);
+}
+
+static int write_phypacket(struct file_info *fi, struct pending_request *req)
+{
+        struct hpsb_packet *packet = NULL;
+        int retval=0;
+        quadlet_t data;
+
+        data = be32_to_cpu((u32)req->req.sendb);
+        DBGMSG("write_phypacket called - quadlet 0x%8.8x ",data);
+        packet = hpsb_make_phypacket (fi->host, data);
+        if (!packet) return -ENOMEM;
+        req->req.length=0;
+        req->packet=packet;
+        req->tq.data=req;
+        hpsb_add_packet_complete_task(packet, &req->tq);
+        spin_lock_irq(&fi->reqlists_lock);
+        list_add_tail(&req->list, &fi->req_pending);
+        spin_unlock_irq(&fi->reqlists_lock);
+        packet->generation = req->req.generation;
+        retval = hpsb_send_packet(packet);
+        DBGMSG("write_phypacket send_packet called => retval: %d ",
+                retval);
+        if (! retval) {
+                req->req.error = RAW1394_ERROR_SEND_ERROR;
+                req->req.length = 0;
+                queue_complete_req(req);
+        }
+        return sizeof(struct raw1394_request);
+}
+
+static int get_config_rom(struct file_info *fi, struct pending_request *req)
+{
+        size_t return_size;
+        unsigned char rom_version;
+        int ret=sizeof(struct raw1394_request);
+        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+        int status;
+        if (!data) return -ENOMEM;
+        status = hpsb_get_config_rom(fi->host, data, 
+                req->req.length, &return_size, &rom_version);
+        if (copy_to_user(int2ptr(req->req.recvb), data, 
+                req->req.length))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.tag), &return_size, 
+                sizeof(return_size)))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.address), &rom_version, 
+                sizeof(rom_version)))
+                ret = -EFAULT;
+        if (copy_to_user(int2ptr(req->req.sendb), &status, 
+                sizeof(status)))
+                ret = -EFAULT;
+        kfree(data);
+        if (ret >= 0) {
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+        }
+        return ret;
+}
+
+static int update_config_rom(struct file_info *fi, struct pending_request *req)
+{
+        int ret=sizeof(struct raw1394_request);
+        quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL);
+        if (!data) return -ENOMEM;
+        if (copy_from_user(data,int2ptr(req->req.sendb), 
+                req->req.length)) {
+                ret= -EFAULT;
+        } else {
+                int status = hpsb_update_config_rom(fi->host, 
+                        data, req->req.length, 
+                        (unsigned char) req->req.misc);
+                if (copy_to_user(int2ptr(req->req.recvb), 
+                        &status, sizeof(status)))
+                        ret = -ENOMEM;
+        }
+        kfree(data);
+        if (ret >= 0) {
+                free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+        }
+        return ret;
+}
+
+static int state_connected(struct file_info *fi, struct pending_request *req)
+{
+        int node = req->req.address >> 48;
+
+        req->req.error = RAW1394_ERROR_NONE;
+
         switch (req->req.type) {
+
+        case RAW1394_REQ_ECHO:
+                queue_complete_req(req);
+                return sizeof(struct raw1394_request);
+
+        case RAW1394_REQ_ISO_SEND:
+                return handle_iso_send(fi, req, node);
+
+        case RAW1394_REQ_ARM_REGISTER:
+                return arm_register(fi, req);
+
+        case RAW1394_REQ_ARM_UNREGISTER:
+                return arm_unregister(fi, req);
+
+        case RAW1394_REQ_RESET_NOTIFY:
+                return reset_notification(fi, req);
+
         case RAW1394_REQ_ISO_LISTEN:
                 handle_iso_listen(fi, req);
                 return sizeof(struct raw1394_request);
@@ -831,21 +1908,49 @@
                 return sizeof(struct raw1394_request);
 
         case RAW1394_REQ_RESET_BUS:
-                hpsb_reset_bus(fi->host, LONG_RESET);
+                if (req->req.misc == RAW1394_LONG_RESET) {
+                        DBGMSG("busreset called (type: LONG)");
+                        hpsb_reset_bus(fi->host, LONG_RESET);
+                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                        return sizeof(struct raw1394_request);
+                }
+                if (req->req.misc == RAW1394_SHORT_RESET) {
+                        DBGMSG("busreset called (type: SHORT)");
+                        hpsb_reset_bus(fi->host, SHORT_RESET);
+                        free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+                        return sizeof(struct raw1394_request);
+                }
+                /* error EINVAL (22) invalid argument */
+                return (-EINVAL);
+        case RAW1394_REQ_GET_ROM:
+                return get_config_rom(fi, req);
+
+        case RAW1394_REQ_UPDATE_ROM:
+                return update_config_rom(fi, req);
+        }
+
+        if (req->req.generation != get_hpsb_generation(fi->host)) {
+                req->req.error = RAW1394_ERROR_GENERATION;
+                req->req.generation = get_hpsb_generation(fi->host);
+                req->req.length = 0;
+                queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
+        switch (req->req.type) {
+        case RAW1394_REQ_PHYPACKET:
+                return write_phypacket(fi, req);
+        case RAW1394_REQ_ASYNC_SEND:
+                return handle_async_send(fi, req);
+        }
+
         if (req->req.length == 0) {
                 req->req.error = RAW1394_ERROR_INVALID_ARG;
                 queue_complete_req(req);
                 return sizeof(struct raw1394_request);
         }
 
-        if (fi->host->node_id == node) {
-                return handle_local_request(fi, req, node);
-        }
-
-        return handle_remote_request(fi, req, node);
+        return handle_async_request(fi, req, node);
 }
 
 
@@ -921,6 +2026,7 @@
                 return -ENOMEM;
         
         memset(fi, 0, sizeof(struct file_info));
+        fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */
 
         INIT_LIST_HEAD(&fi->list);
         fi->state = opened;
@@ -929,6 +2035,7 @@
         sema_init(&fi->complete_sem, 0);
         spin_lock_init(&fi->reqlists_lock);
         init_waitqueue_head(&fi->poll_wait_complete);
+        INIT_LIST_HEAD(&fi->addr_list);
 
         file->private_data = fi;
 
@@ -940,7 +2047,15 @@
         struct file_info *fi = file->private_data;
         struct list_head *lh;
         struct pending_request *req;
-        int done = 0, i;
+        int done = 0, i, fail = 0;
+        int retval = 0;
+        struct list_head *entry;
+        struct arm_addr  *addr = NULL;
+        struct list_head *lh_1, *lh_2;
+        struct host_info *hi;
+        struct file_info *fi_hlp = NULL;
+        struct arm_addr  *arm_addr = NULL;
+        int another_host;
 
         for (i = 0; i < 64; i++) {
                 if (fi->listen_channels & (1ULL << i)) {
@@ -948,9 +2063,63 @@
                 }
         }
 
-        spin_lock(&host_info_lock);
+        spin_lock_irq(&host_info_lock);
         fi->listen_channels = 0;
-        spin_unlock(&host_info_lock);
+        spin_unlock_irq(&host_info_lock);
+
+        fail = 0;
+        /* set address-entries invalid */
+        spin_lock_irq(&host_info_lock);
+
+        while (!list_empty(&fi->addr_list)) {
+                another_host = 0;
+                lh = fi->addr_list.next;
+                addr = list_entry(lh, struct arm_addr, addr_list);
+                /* another host with valid address-entry containing 
+                   same addressrange? */
+                list_for_each(lh_1, &host_info_list) {
+                        hi = list_entry(lh_1, struct host_info, list);
+                        if (hi->host != fi->host) {
+                                list_for_each(lh_2, &hi->file_info_list) {
+                                        fi_hlp = list_entry(lh_2, struct file_info, list);
+                                        entry = fi_hlp->addr_list.next;
+                                        while (entry != &(fi_hlp->addr_list)) {
+                                                arm_addr = list_entry(entry, 
+                                                        struct arm_addr, addr_list);
+                                                if (arm_addr->start == 
+                                                        addr->start) {
+                                                        DBGMSG("raw1394_release: "
+                                                        "another host ownes "
+                                                        "same addressrange");
+                                                        another_host = 1;
+                                                        break;
+                                                }
+                                                entry = entry->next;
+                                        }
+                                        if (another_host) {
+                                                break;
+                                        }
+                                }
+                        }
+                }
+                if (!another_host) {
+                        DBGMSG("raw1394_release: call hpsb_arm_unregister");
+                        retval = hpsb_unregister_addrspace(hl_handle, addr->start);
+                        if (!retval) {
+                                ++fail;
+                                printk(KERN_ERR "raw1394_release arm_Unregister failed\n");
+                        }
+                }
+                DBGMSG("raw1394_release: delete addr_entry from list");
+                list_del(&addr->addr_list);
+                kfree(addr->addr_space_buffer);
+                kfree(addr);
+        } /* while */
+        spin_unlock_irq(&host_info_lock);
+        if (fail > 0) {
+                printk(KERN_ERR "raw1394: during addr_list-release "
+                        "error(s) occured \n");
+        }
 
         while (!done) {
                 spin_lock_irq(&fi->reqlists_lock);
@@ -1009,28 +2178,28 @@
                 return -ENOMEM;
         }
 
-	devfs_handle = devfs_register(NULL,
-				      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
+        devfs_handle = devfs_register(NULL,
+                                      RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
                                       IEEE1394_MAJOR,
-				      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
+                                      IEEE1394_MINOR_BLOCK_RAW1394 * 16,
                                       S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
                                       NULL);
 
         if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
-				      THIS_MODULE, &file_ops)) {
+                                      THIS_MODULE, &file_ops)) {
                 HPSB_ERR("raw1394 failed to register minor device block");
-		devfs_unregister(devfs_handle);
-		hpsb_unregister_highlevel(hl_handle);
+                devfs_unregister(devfs_handle);
+                hpsb_unregister_highlevel(hl_handle);
                 return -EBUSY;
         }
-	printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
+        printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
         return 0;
 }
 
 static void __exit cleanup_raw1394(void)
 {
         ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
-	devfs_unregister(devfs_handle);
+        devfs_unregister(devfs_handle);
         hpsb_unregister_highlevel(hl_handle);
 }
 
diff -Nru a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h
--- a/drivers/ieee1394/raw1394.h	Tue Oct 15 20:29:11 2002
+++ b/drivers/ieee1394/raw1394.h	Tue Oct 15 20:29:11 2002
@@ -14,20 +14,32 @@
 #define RAW1394_REQ_SET_CARD      3
 
 /* state: connected */
-#define RAW1394_REQ_ASYNC_READ    100
-#define RAW1394_REQ_ASYNC_WRITE   101
-#define RAW1394_REQ_LOCK          102
-#define RAW1394_REQ_LOCK64        103
-#define RAW1394_REQ_ISO_SEND      104
-
-#define RAW1394_REQ_ISO_LISTEN    200
-#define RAW1394_REQ_FCP_LISTEN    201
-#define RAW1394_REQ_RESET_BUS     202
+#define RAW1394_REQ_ASYNC_READ      100
+#define RAW1394_REQ_ASYNC_WRITE     101
+#define RAW1394_REQ_LOCK            102
+#define RAW1394_REQ_LOCK64          103
+#define RAW1394_REQ_ISO_SEND        104
+#define RAW1394_REQ_ASYNC_SEND      105
+
+#define RAW1394_REQ_ISO_LISTEN      200
+#define RAW1394_REQ_FCP_LISTEN      201
+#define RAW1394_REQ_RESET_BUS       202
+#define RAW1394_REQ_GET_ROM         203
+#define RAW1394_REQ_UPDATE_ROM      204
+#define RAW1394_REQ_ECHO            205
+
+#define RAW1394_REQ_ARM_REGISTER    300
+#define RAW1394_REQ_ARM_UNREGISTER  301
+
+#define RAW1394_REQ_RESET_NOTIFY    400
+
+#define RAW1394_REQ_PHYPACKET       500
 
 /* kernel to user */
 #define RAW1394_REQ_BUS_RESET     10000
 #define RAW1394_REQ_ISO_RECEIVE   10001
 #define RAW1394_REQ_FCP_REQUEST   10002
+#define RAW1394_REQ_ARM           10003
 
 /* error codes */
 #define RAW1394_ERROR_NONE        0
@@ -45,6 +57,17 @@
 #define RAW1394_ERROR_ABORTED     (-1101)
 #define RAW1394_ERROR_TIMEOUT     (-1102)
 
+/* arm_codes */
+#define ARM_READ   1
+#define ARM_WRITE  2
+#define ARM_LOCK   4
+
+#define RAW1394_LONG_RESET  0
+#define RAW1394_SHORT_RESET 1
+
+/* busresetnotify ... */
+#define RAW1394_NOTIFY_OFF 0
+#define RAW1394_NOTIFY_ON  1
 
 #include <asm/types.h>
 
@@ -69,6 +92,29 @@
         __u8 name[32];
 };
 
+typedef struct arm_request {
+        nodeid_t        destination_nodeid;
+        nodeid_t        source_nodeid;
+        nodeaddr_t      destination_offset;
+        u8              tlabel;
+        u8              tcode;
+        u_int8_t        extended_transaction_code;
+        u_int32_t       generation;
+        arm_length_t    buffer_length;
+        byte_t          *buffer;
+} *arm_request_t;
+
+typedef struct arm_response {
+        int             response_code;
+        arm_length_t    buffer_length;
+        byte_t          *buffer;
+} *arm_response_t;
+
+typedef struct arm_request_response {
+        struct arm_request  *request;
+        struct arm_response *response;
+} *arm_request_response_t;
+
 #ifdef __KERNEL__
 
 struct iso_block_store {
@@ -91,18 +137,34 @@
         spinlock_t reqlists_lock;
         wait_queue_head_t poll_wait_complete;
 
+        struct list_head addr_list;           
+
         u8 *fcp_buffer;
 
         u64 listen_channels;
         quadlet_t *iso_buffer;
         size_t iso_buffer_length;
+
+        u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
+};
+
+struct arm_addr {
+        struct list_head addr_list; /* file_info list */
+        u64    start, end;
+        u64    arm_tag;
+        u8     access_rights;
+        u8     notification_options;
+        u8     client_transactions;
+        u64    recvb;
+        u16    rec_length;
+        u8     *addr_space_buffer; /* accessed by read/write/lock */
 };
 
 struct pending_request {
         struct list_head list;
         struct file_info *file_info;
         struct hpsb_packet *packet;
-        struct tq_struct tq;
+        struct hpsb_queue_struct tq;
         struct iso_block_store *ibs;
         quadlet_t *data;
         int free_data;
diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/ieee1394/sbp2.c	Tue Oct 15 20:29:12 2002
@@ -351,7 +351,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 584 $ James Goodwin <jamesg@filanet.com>";
+	"$Rev: 601 $ James Goodwin <jamesg@filanet.com>";
 
 /*
  * Module load parameter definitions
@@ -421,8 +421,9 @@
  * talking to a single sbp2 device at the same time (filesystem coherency,
  * etc.). If you're running an sbp2 device that supports multiple logins,
  * and you're either running read-only filesystems or some sort of special
- * filesystem supporting multiple hosts, then set sbp2_exclusive_login to
- * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
+ * filesystem supporting multiple hosts (one such filesystem is OpenGFS,
+ * see opengfs.sourceforge.net for more info), then set sbp2_exclusive_login
+ * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
  * concurrent logins.
  */
 MODULE_PARM(sbp2_exclusive_login,"i");
@@ -800,8 +801,9 @@
 		 * Set up a task queue completion routine, which returns
 		 * the packet to the free list and releases the tlabel.
 		 */
-		request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;
-		request_packet->tq.data = request_packet;
+		HPSB_PREPARE_WORK(&request_packet->tq,
+				  (void (*)(void*))sbp2util_free_request_packet,
+				  request_packet);
 		request_packet->hi_context = hi;
 		hpsb_add_packet_complete_task(packet, &request_packet->tq);
 
@@ -1007,13 +1009,8 @@
 					 command->dma_size, command->dma_dir);
 			SBP2_DMA_FREE("single bulk");
 		} else if (command->dma_type == CMD_DMA_PAGE) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
-			pci_unmap_single(hi->host->pdev, command->cmd_dma,
-					 command->dma_size, command->dma_dir);
-#else
 			pci_unmap_page(hi->host->pdev, command->cmd_dma,
 				       command->dma_size, command->dma_dir);
-#endif /* Linux version < 2.4.13 */
 			SBP2_DMA_FREE("single page");
 		} /* XXX: Check for CMD_DMA_NONE bug */
 		command->dma_type = CMD_DMA_NONE;
@@ -2146,17 +2143,11 @@
 			command->dma_dir = dma_dir;
 			command->dma_size = sgpnt[0].length;
 			command->dma_type = CMD_DMA_PAGE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
-			command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
-							   command->dma_size,
-							   command->dma_dir);
-#else
 			command->cmd_dma = pci_map_page(hi->host->pdev,
 							sgpnt[0].page,
 							sgpnt[0].offset,
 							command->dma_size,
 							command->dma_dir);
-#endif /* Linux version < 2.4.13 */
 			SBP2_DMA_ALLOC("single page scatter element");
 
 			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
@@ -2702,7 +2693,7 @@
  * This function deals with status writes from the SBP-2 device
  */
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
-				    quadlet_t *data, u64 addr, unsigned int length)
+				    quadlet_t *data, u64 addr, unsigned int length, u16 fl)
 {
 	struct sbp2scsi_host_info *hi = NULL;
 	struct scsi_id_instance_data *scsi_id = NULL;
@@ -3161,7 +3152,6 @@
 	heads = 64;
 	sectors = 32;
 	cylinders = (int)disk->capacity / (heads * sectors);
-	
 
 	if (cylinders > 1024) {
 		heads = 255;
diff -Nru a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
--- a/drivers/ieee1394/sbp2.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/ieee1394/sbp2.h	Tue Oct 15 20:29:12 2002
@@ -324,7 +324,7 @@
 
 	struct list_head list;
 	struct hpsb_packet *packet;
-	struct tq_struct tq;
+	struct hpsb_queue_struct tq;
 	void *hi_context;
 
 };
@@ -510,9 +510,9 @@
 
 #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
 static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
-                                     u64 addr, unsigned int length);
+                                     u64 addr, unsigned int length, u16 flags);
 static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
-                                    u64 addr, unsigned int length);
+                                    u64 addr, unsigned int length, u16 flags);
 #endif
 
 /*
@@ -522,7 +522,7 @@
 static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
-				    quadlet_t *data, u64 addr, unsigned int length);
+				    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
 static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags);
 static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, 
 				   struct scsi_id_instance_data *scsi_id,
diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
--- a/drivers/ieee1394/video1394.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/ieee1394/video1394.c	Tue Oct 15 20:29:12 2002
@@ -35,7 +35,6 @@
 #include <linux/poll.h>
 #include <linux/smp_lock.h>
 #include <linux/proc_fs.h>
-#include <linux/tqueue.h>
 #include <linux/delay.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -1455,12 +1454,7 @@
  		return -EIO;
  	}
 	
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
-	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME,
-			strlen(VIDEO1394_DRIVER_NAME), NULL);
-#else
 	devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, NULL);
-#endif
 
 	hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops);
 	if (hl_handle == NULL) {
diff -Nru a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
--- a/drivers/isdn/hardware/eicon/divasmain.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/isdn/hardware/eicon/divasmain.c	Tue Oct 15 20:29:12 2002
@@ -21,7 +21,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/ioport.h>
-#include <linux/tqueue.h>
+#include <linux/workqueue.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
@@ -73,7 +73,7 @@
 typedef struct _diva_os_thread_dpc {
 	struct tasklet_struct divas_task;
   diva_os_soft_isr_t*   psoft_isr;
-	struct tq_struct      trap_script_task;
+	struct work_struct      trap_script_task;
   int                   card_failed;
 } diva_os_thread_dpc_t;
 
@@ -297,7 +297,7 @@
 
   if (context && !context->card_failed) {
     context->card_failed = ANum+1;
-    schedule_task(&context->trap_script_task);
+    schedule_work(&context->trap_script_task);
 	}
 }
 
@@ -607,7 +607,7 @@
   psoft_isr->callback         = callback;
   psoft_isr->callback_context = callback_context;
   pdpc->psoft_isr             = psoft_isr;
-  INIT_TQUEUE(&pdpc->trap_script_task, diva_adapter_trapped, pdpc);
+  INIT_WORK(&pdpc->trap_script_task, diva_adapter_trapped, pdpc);
 	tasklet_init(&pdpc->divas_task, diva_os_dpc_proc, (unsigned long)pdpc);
 
   return (0);
@@ -643,7 +643,7 @@
 
     mem = psoft_isr->object;
     psoft_isr->object = 0;
-		flush_scheduled_tasks();
+    flush_scheduled_work();
     diva_os_free (0, mem);
 	}
 }
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/md/md.c	Tue Oct 15 20:29:15 2002
@@ -1394,12 +1394,11 @@
 #endif
 	}
 
-	disk = alloc_disk();
+	disk = alloc_disk(1);
 	if (!disk)
 		return -ENOMEM;
 	disk->major = MD_MAJOR;
 	disk->first_minor = mdidx(mddev);
-	disk->minor_shift = 0;
 	sprintf(disk->disk_name, "md%d", mdidx(mddev));
 	disk->fops = &md_fops;
 
@@ -2732,18 +2731,9 @@
 	return 0;
 }
 
-static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK];
 void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors)
 {
-	kdev_t dev = to_kdev_t(rdev->bdev->bd_dev);
-	unsigned int major = major(dev);
-	unsigned int index;
-
-	index = disk_index(dev);
-	if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
-		return;
-
-	sync_io[major][index] += nr_sectors;
+	rdev->bdev->bd_disk->sync_io += nr_sectors;
 }
 
 static int is_mddev_idle(mddev_t *mddev)
@@ -2755,16 +2745,8 @@
 
 	idle = 1;
 	ITERATE_RDEV(mddev,rdev,tmp) {
-		kdev_t dev = to_kdev_t(rdev->bdev->bd_dev);
-		int major = major(dev);
-		int idx = disk_index(dev);
-
-		if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
-			continue;
-
-		curr_events = kstat.dk_drive_rblk[major][idx] +
-						kstat.dk_drive_wblk[major][idx] ;
-		curr_events -= sync_io[major][idx];
+		struct gendisk *disk = rdev->bdev->bd_disk;
+		curr_events = disk->reads + disk->writes - disk->sync_io;
 		if ((curr_events - rdev->last_events) > 32) {
 			rdev->last_events = curr_events;
 			idle = 0;
diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c
--- a/drivers/md/raid0.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/md/raid0.c	Tue Oct 15 20:29:17 2002
@@ -162,6 +162,29 @@
 	return 1;
 }
 
+/**
+ *	raid0_mergeable_bvec -- tell bio layer if a two requests can be merged
+ *	@q: request queue
+ *	@bio: the buffer head that's been built up so far
+ *	@biovec: the request that could be merged to it.
+ *
+ *	Return 1 if the merge is not permitted (because the
+ *	result would cross a chunk boundary), 0 otherwise.
+ */
+static int raid0_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+{
+	mddev_t *mddev = q->queuedata;
+	sector_t block;
+	unsigned int chunk_size;
+	unsigned int bio_sz;
+
+	chunk_size = mddev->chunk_size >> 10;
+	block = bio->bi_sector >> 1;
+	bio_sz = (bio->bi_size + biovec->bv_len) >> 10;
+
+	return chunk_size < ((block & (chunk_size - 1)) + bio_sz);
+}
+
 static int raid0_run (mddev_t *mddev)
 {
 	unsigned  cur=0, i=0, nb_zone;
@@ -233,6 +256,8 @@
 		conf->hash_table[i++].zone1 = conf->strip_zone + cur;
 		size -= (conf->smallest->size - zone0_size);
 	}
+	blk_queue_max_sectors(&mddev->queue, mddev->chunk_size >> 9);
+	blk_queue_merge_bvec(&mddev->queue, raid0_mergeable_bvec);
 	return 0;
 
 out_free_zone_conf:
@@ -262,13 +287,6 @@
 	return 0;
 }
 
-/*
- * FIXME - We assume some things here :
- * - requested buffers NEVER bigger than chunk size,
- * - requested buffers NEVER cross stripes limits.
- * Of course, those facts may not be valid anymore (and surely won't...)
- * Hey guys, there's some work out there ;-)
- */
 static int raid0_make_request (request_queue_t *q, struct bio *bio)
 {
 	mddev_t *mddev = q->queuedata;
@@ -286,13 +304,16 @@
 	
 
 	{
+#if __GNUC__ < 3
+		volatile
+#endif
 		sector_t x = block;
 		sector_div(x, (unsigned long)conf->smallest->size);
 		hash = conf->hash_table + x;
 	}
 
-	/* Sanity check */
-	if (chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10))
+	/* Sanity check -- queue functions should prevent this happening */
+	if (unlikely(chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10)))
 		goto bad_map;
  
 	if (!hash)
diff -Nru a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
--- a/drivers/media/video/bttv-driver.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/media/video/bttv-driver.c	Tue Oct 15 20:29:20 2002
@@ -31,6 +31,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/init.h>
 #include <linux/kdev_t.h>
 
 #include <asm/io.h>
diff -Nru a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c
--- a/drivers/media/video/bttv-risc.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/media/video/bttv-risc.c	Tue Oct 15 20:29:17 2002
@@ -29,7 +29,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
-#include <linux/iobuf.h>
 #include <linux/vmalloc.h>
 #include <linux/interrupt.h>
 #include <asm/page.h>
diff -Nru a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
--- a/drivers/media/video/bttvp.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/media/video/bttvp.h	Tue Oct 15 20:29:16 2002
@@ -31,7 +31,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
-#include <linux/iobuf.h>
 #include <linux/pci.h>
 #include <asm/scatterlist.h>
 
diff -Nru a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
--- a/drivers/media/video/cpia.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/media/video/cpia.c	Tue Oct 15 20:29:19 2002
@@ -56,7 +56,7 @@
 
 #ifdef MODULE
 MODULE_PARM(video_nr,"i");
-MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
+MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("video");
@@ -163,7 +163,7 @@
 #define COMMAND_SETAPCOR		0x1000
 #define COMMAND_SETFLICKERCTRL		0x2000
 #define COMMAND_SETVLOFFSET		0x4000
-
+#define COMMAND_SETLIGHTS		0x8000
 /* Developer's Guide Table 5 p 3-34
  * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
 static u8 flicker_jumps[2][2][4] =
@@ -244,7 +244,7 @@
 	char *out = page;
 	int len, tmp;
 	struct cam_data *cam = data;
-	char tmpstr[20];
+	char tmpstr[29];
 
 	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
 	 *            or we need to get more sophisticated. */
@@ -281,6 +281,13 @@
 	               cam->params.status.vpStatus);
 	out += sprintf(out, "error_code:               %#04x\n",
 	               cam->params.status.errorCode);
+	/* QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "button:                   %4d\n",
+		               cam->params.qx3.button);
+		out += sprintf(out, "cradled:                  %4d\n",
+		               cam->params.qx3.cradled);
+	}
 	out += sprintf(out, "video_size:               %s\n",
 	               cam->params.format.videoSize == VIDEOSIZE_CIF ?
 		       "CIF " : "QCIF");
@@ -345,16 +352,17 @@
 	if (cam->params.version.firmwareVersion == 1 &&
 	   cam->params.version.firmwareRevision == 2)
 		/* 1-02 firmware limits gain to 2 */
-		sprintf(tmpstr, "%8d  %8d", 1, 2);
+		sprintf(tmpstr, "%8d  %8d  %8d", 1, 2, 2);
 	else
-		sprintf(tmpstr, "1,2,4,8");
+		sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
 
 	if (cam->params.exposure.gainMode == 0)
-		out += sprintf(out, "max_gain:                unknown  %18s"
-		               "  %8d\n", tmpstr, 2); 
+		out += sprintf(out, "max_gain:                unknown  %28s"
+		               "  powers of 2\n", tmpstr); 
 	else
-		out += sprintf(out, "max_gain:               %8d  %18s  %8d\n", 
-		               1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
+		out += sprintf(out, "max_gain:               %8d  %28s"
+			       "  1,2,4 or 8 \n",
+		               1<<(cam->params.exposure.gainMode-1), tmpstr);
 
 	switch(cam->params.exposure.expMode) {
 	case 1:
@@ -481,6 +489,15 @@
 	out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
 	               cam->params.compressionParams.decimationThreshMod,
 		       0, 255, 2);
+	/* QX3 specific entries */
+	if (cam->params.qx3.qx3_detected) {
+		out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.toplight ? "on" : "off",
+			       "off", "on", "off");
+		out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n", 
+		               cam->params.qx3.bottomlight ? "on" : "off",
+			       "off", "on", "off");
+	}
 	
 	len = out - page;
 	len -= off;
@@ -494,18 +511,45 @@
 	return len;
 }
 
-static int cpia_write_proc(struct file *file, const char *buffer,
+static int cpia_write_proc(struct file *file, const char *buf,
                            unsigned long count, void *data)
 {
-	return -EINVAL;
-#if 0
 	struct cam_data *cam = data;
 	struct cam_params new_params;
+	char *page, *buffer;
 	int retval, find_colon;
 	int size = count;
-	unsigned long val;
+	unsigned long val = 0;
 	u32 command_flags = 0;
 	u8 new_mains;
+
+	/*
+	 * This code to copy from buf to page is shamelessly copied
+	 * from the comx driver
+	 */
+	if (count > PAGE_SIZE) {
+		printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
+		return -ENOSPC;
+	}
+
+	if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
+
+	if(copy_from_user(page, buf, count))
+	{
+		retval = -EFAULT;
+		goto out;
+	}
+
+	if (page[count-1] == '\n')
+		page[count-1] = '\0';
+	else if (count < PAGE_SIZE)
+		page[count] = '\0';
+	else if (page[count]) {
+		retval = -EINVAL;
+		goto out;
+	}
+	
+	buffer = page;
 	
 	if (down_interruptible(&cam->param_lock))
 		return -ERESTARTSYS;
@@ -1163,6 +1207,22 @@
 					retval = -EINVAL;
 			}
 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
+		} else if (MATCH("toplight")) {
+		        if (!retval && MATCH("on"))
+				new_params.qx3.toplight = 1;
+			else if (!retval && MATCH("off"))
+				new_params.qx3.toplight = 0;
+			else 
+				retval = -EINVAL;
+			command_flags |= COMMAND_SETLIGHTS;
+		} else if (MATCH("bottomlight")) {
+		        if (!retval && MATCH("on"))
+				new_params.qx3.bottomlight = 1;
+			else if (!retval && MATCH("off"))  
+				new_params.qx3.bottomlight = 0;
+			else 
+				retval = -EINVAL;
+			command_flags |= COMMAND_SETLIGHTS;
 		} else {
 			DBG("No match found\n");
 			retval = -EINVAL;
@@ -1174,7 +1234,10 @@
 				++buffer;
 			}
 			if (count) {
-				if (*buffer != '\n' && *buffer != ';')
+				if (*buffer == '\0' && count != 1)
+					retval = -EINVAL;
+				else if (*buffer != '\n' && *buffer != ';' &&
+					 *buffer != '\0')
 					retval = -EINVAL;
 				else {
 					--count;
@@ -1208,8 +1271,9 @@
 	
 	up(&cam->param_lock);
 	
-	return retval;
-#endif
+out:
+	free_page((unsigned long)page);
+ 	return retval;
 }
 
 static void create_proc_cpia_cam(struct cam_data *cam)
@@ -1229,7 +1293,12 @@
 	ent->data = cam;
 	ent->read_proc = cpia_read_proc;
 	ent->write_proc = cpia_write_proc;
-	ent->size = 3626;
+	/* 
+	   size of the proc entry is 3672 bytes for the standard webcam;
+ 	   the extra features of the QX3 microscope add 188 bytes.
+	   (we have not yet probed the camera to see which type it is).
+	*/
+	ent->size = 3672 + 188;
 	cam->proc_entry = ent;
 }
 
@@ -1523,6 +1592,10 @@
 		down(&cam->param_lock);
 		datasize=8;
 		break;
+	case CPIA_COMMAND_ReadMCPorts: 
+	case CPIA_COMMAND_ReadVCRegs:
+		datasize = 4;
+		break;
 	default:
 		datasize=0;
 		break;
@@ -1620,6 +1693,22 @@
 			  }
 			up(&cam->param_lock);
 			break;
+
+		case CPIA_COMMAND_ReadMCPorts: 
+			if (!cam->params.qx3.qx3_detected) 
+				break;
+			/* test button press */ 
+			cam->params.qx3.button = ((data[1] & 0x02) == 0);
+			if (cam->params.qx3.button) {
+				/* button pressed - unlock the latch */
+				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
+				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
+			}
+
+			/* test whether microscope is cradled */
+			cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
+			break;
+
 		default:
 			break;
 		}
@@ -1779,6 +1868,7 @@
 {
 	switch(fmt) {
 	case VIDEO_PALETTE_GREY:
+		return count;
 	case VIDEO_PALETTE_RGB555:
 	case VIDEO_PALETTE_RGB565:
 	case VIDEO_PALETTE_YUV422:
@@ -2059,6 +2149,13 @@
 	if (cam->cmd_queue & COMMAND_RESUME)
 		init_stream_cap(cam);
 
+	if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) {
+		int p1 = (cam->params.qx3.bottomlight == 0) << 1;
+		int p2 = (cam->params.qx3.toplight == 0) << 3;
+		do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
+		do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
+	}
+
 	up(&cam->param_lock);
 	cam->cmd_queue = COMMAND_NONE;
 	return;
@@ -2133,9 +2230,10 @@
 		/* camera idle now so dispatch queued commands */
 		dispatch_commands(cam);
 
-		/* Update our knowledge of the camera state - FIXME: necessary? */
-		do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
-		do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+		/* Update our knowledge of the camera state */
+ 		do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
+ 		do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
+		do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
 
 		/* decompress and convert image to by copying it from
 		 * raw_image to decompressed_frame
@@ -2346,8 +2444,12 @@
 	get_version_information(cam);
 	if (cam->params.version.firmwareVersion != 1)
 		return -ENODEV;
-	
-	/* The fatal error checking should be done after
+
+	/* set QX3 detected flag */
+	cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
+					cam->params.pnpID.product == 0x0001);
+
+ 	/* The fatal error checking should be done after
 	 * the camera powers up (developer's guide p 3-38) */
 
 	/* Set streamState before transition to high power to avoid bug
@@ -2481,7 +2583,7 @@
 		/* GotoLoPower */
 		goto_low_power(cam);
 
-		/* Update the camera ststus */
+		/* Update the camera status */
 		do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
 
 		/* cleanup internal state stuff */
@@ -2520,7 +2622,7 @@
 	struct video_device *dev = file->private_data;
 	struct cam_data *cam = dev->priv;
 
-	/* make this _really_ smp and multithredi-safe */
+	/* make this _really_ smp and multithread-safe */
 	if (down_interruptible(&cam->busy_lock))
 		return -EINTR;
 
@@ -2728,7 +2830,6 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 		}
 
-		// FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
 		up(&cam->param_lock);
 
 		/* setformat ignored by camera during streaming,
@@ -2762,10 +2863,8 @@
 		struct video_mmap *vm = arg;
 		int video_size;
 
-#if 1
 		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
 		    vm->width, vm->height);
-#endif
 		if (vm->frame<0||vm->frame>=FRAME_NUM) {
 			retval = -EINVAL;
 			break;
@@ -2775,6 +2874,8 @@
 		cam->vp.palette = vm->format;
 		switch(vm->format) {
 		case VIDEO_PALETTE_GREY:
+			cam->vp.depth=8;
+			break;
 		case VIDEO_PALETTE_RGB555:
 		case VIDEO_PALETTE_RGB565:
 		case VIDEO_PALETTE_YUV422:
@@ -2807,10 +2908,6 @@
 			cam->cmd_queue |= COMMAND_SETFORMAT;
 			dispatch_commands(cam);
 		}
-#if 0
-		DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
-		    cam->vw.width, cam->vw.height);
-#endif
 		/* according to v4l-spec we must start streaming here */
 		cam->mmap_kludge = 1;
 		retval = capture_frame(cam, vm);
@@ -2947,7 +3044,7 @@
 	owner:		THIS_MODULE,
 	name:		"CPiA Camera",
 	type:		VID_TYPE_CAPTURE,
-	hardware:	VID_HARDWARE_CPIA,      /* FIXME */
+	hardware:	VID_HARDWARE_CPIA,
 	fops:           &cpia_fops,
 };
 
@@ -3006,8 +3103,8 @@
 	cam->params.sensorFps.divisor = 1;
 	cam->params.sensorFps.baserate = 1;
 	
-	cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
-	cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
+	cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
+	cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
 	
 	cam->params.format.subSample = SUBSAMPLE_422;
 	cam->params.format.yuvOrder = YUVORDER_YUYV;
@@ -3015,8 +3112,14 @@
 	cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
 	cam->params.compressionTarget.frTargeting =
 		CPIA_COMPRESSION_TARGET_QUALITY;
-	cam->params.compressionTarget.targetFR = 7; /* FIXME? */
-	cam->params.compressionTarget.targetQ = 10; /* FIXME? */
+	cam->params.compressionTarget.targetFR = 15; /* From windows driver */
+	cam->params.compressionTarget.targetQ = 5; /* From windows driver */
+
+	cam->params.qx3.qx3_detected = 0;
+	cam->params.qx3.toplight = 0;
+	cam->params.qx3.bottomlight = 0;
+	cam->params.qx3.button = 0;
+	cam->params.qx3.cradled = 0;
 
 	cam->video_size = VIDEOSIZE_CIF;
 	
@@ -3025,8 +3128,8 @@
 	cam->vp.brightness = 32768;  /* 50% */
 	cam->vp.contrast = 32768;    /* 50% */
 	cam->vp.whiteness = 0;       /* not used -> grayscale only */
-	cam->vp.depth = 0;           /* FIXME: to be set by user? */
-	cam->vp.palette = VIDEO_PALETTE_RGB24;         /* FIXME: to be set by user? */
+	cam->vp.depth = 24;          /* to be set by user */
+	cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
 
 	cam->vw.x = 0;
 	cam->vw.y = 0;
@@ -3080,14 +3183,9 @@
 {
         struct cam_data *camera;
 	
-	/* Need a lock when adding/removing cameras.  This doesn't happen
-	 * often and doesn't take very long, so grabbing the kernel lock
-	 * should be OK. */
-	
-	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
-		unlock_kernel();
+	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
 		return NULL;
-	}
+
 	
 	init_camera_struct( camera, ops );
 	camera->lowlevel_data = lowlevel;
@@ -3095,7 +3193,6 @@
 	/* register v4l device */
 	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
 		kfree(camera);
-		unlock_kernel();
 		printk(KERN_DEBUG "video_register_device failed\n");
 		return NULL;
 	}
@@ -3118,12 +3215,6 @@
 	/* close cpia */
 	camera->ops->close(camera->lowlevel_data);
 
-/* Eh? Feeling happy? - jerdfelt */
-/*
-	camera->ops->open(camera->lowlevel_data);
-	camera->ops->close(camera->lowlevel_data);
-*/
-	
 	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
 	       camera->params.version.firmwareVersion,
 	       camera->params.version.firmwareRevision,
diff -Nru a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
--- a/drivers/media/video/cpia.h	Tue Oct 15 20:29:21 2002
+++ b/drivers/media/video/cpia.h	Tue Oct 15 20:29:21 2002
@@ -27,12 +27,12 @@
  */
 
 #define CPIA_MAJ_VER	0
-#define CPIA_MIN_VER    7
-#define CPIA_PATCH_VER	4
+#define CPIA_MIN_VER    8
+#define CPIA_PATCH_VER	1
 
 #define CPIA_PP_MAJ_VER       0
-#define CPIA_PP_MIN_VER       7
-#define CPIA_PP_PATCH_VER     4
+#define CPIA_PP_MIN_VER       8
+#define CPIA_PP_PATCH_VER     1
 
 #define CPIA_MAX_FRAME_SIZE_UNALIGNED	(352 * 288 * 4)   /* CIF at RGB32 */
 #define CPIA_MAX_FRAME_SIZE	((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
@@ -203,7 +203,14 @@
 		u8 videoSize;		/* CIF/QCIF */
 		u8 subSample;
 		u8 yuvOrder;
-	} format;
+ 	} format;
+        struct {                        /* Intel QX3 specific data */
+                u8 qx3_detected;        /* a QX3 is present */
+                u8 toplight;            /* top light lit , R/W */
+                u8 bottomlight;         /* bottom light lit, R/W */
+                u8 button;              /* snapshot button pressed (R/O) */
+                u8 cradled;             /* microscope is in cradle (R/O) */
+        } qx3;
 	struct {
 		u8 colStart;		/* skip first 8*colStart pixels */
 		u8 colEnd;		/* finish at 8*colEnd pixels */
@@ -393,29 +400,6 @@
       (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
         (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
 
-#define ADD_TO_LIST(l, drv) \
-  {\
-    lock_kernel();\
-    (drv)->next = l;\
-    (drv)->previous = &(l);\
-    (l) = drv;\
-    unlock_kernel();\
-  } while(0)
-
-#define REMOVE_FROM_LIST(drv) \
-  {\
-    if ((drv)->previous != NULL) {\
-      lock_kernel();\
-      if ((drv)->next != NULL)\
-        (drv)->next->previous = (drv)->previous;\
-      *((drv)->previous) = (drv)->next;\
-      (drv)->previous = NULL;\
-      (drv)->next = NULL;\
-      unlock_kernel();\
-    }\
-  } while (0)
-
-
 static inline void cpia_add_to_list(struct cam_data* l, struct cam_data* drv)
 {
 	drv->next = l;
@@ -423,7 +407,6 @@
 	l = drv;
 }
 
-
 static inline void cpia_remove_from_list(struct cam_data* drv)
 {
 	if (drv->previous != NULL) {
@@ -434,7 +417,6 @@
 		drv->next = NULL;
 	}
 }
-
 
 #endif /* __KERNEL__ */
 
diff -Nru a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
--- a/drivers/media/video/cpia_pp.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/media/video/cpia_pp.c	Tue Oct 15 20:29:11 2002
@@ -4,7 +4,7 @@
  * Supports CPiA based parallel port Video Camera's.
  *
  * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
- * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@mindspring.com>,
+ * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@securenym.net>,
  * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -341,17 +341,6 @@
 	return 0;
 }
 
-static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
-{
-	int bytes_read, new_bytes;
-	for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
-		new_bytes = parport_read(port, buffer+bytes_read,
-			                 len-bytes_read);
-		if(new_bytes < 0) break;
-	}
-	return bytes_read;
-}
-
 /****************************************************************************
  *
  *  cpia_pp_streamRead
@@ -361,7 +350,7 @@
 {
 	struct pp_cam_entry *cam = privdata;
 	int read_bytes = 0;
-	int i, endseen, block_size, new_bytes;
+	int i, endseen;
 
 	if(cam == NULL) {
 		DBG("Internal driver error: cam is NULL\n");
@@ -390,34 +379,24 @@
 			return -EIO;
 		}
 	}
-	endseen = 0;
-	block_size = PARPORT_CHUNK_SIZE;
-	while( !cam->image_complete ) {
-		cond_resched();
-		
-		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
-		if( new_bytes <= 0 ) {
-			break;
-		}
-		i=-1;
-		while(++i<new_bytes && endseen<4) {
-	        	if(*buffer==EOI) {
-	                	endseen++;
-	                } else {
-	                	endseen=0;
-	                }
-			buffer++;
-		}
-		read_bytes += i;
-		if( endseen==4 ) {
-			cam->image_complete=1;
-			break;
-		}
-		if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
-			block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
-		}
-	}
+	read_bytes = parport_read(cam->port, buffer, CPIA_MAX_IMAGE_SIZE );
+
 	EndTransferMode(cam);
+	DBG("read %d bytes\n", read_bytes);
+	if( read_bytes<0) return -EIO;
+	endseen = 0;
+	for( i=0; i<read_bytes && endseen<4; i++ ) {
+	  if( *buffer==EOI ) {
+	    endseen++;
+	  } else {
+	    endseen=0;
+	  }
+	  buffer++;
+	}
+	if( endseen>3 ) {
+	  cam->image_complete=1;
+	  DBG("endseen at %d bytes\n", i);
+ 	}
 	return cam->image_complete ? read_bytes : -EIO;
 }
 
@@ -716,15 +695,6 @@
 
 static int __init cpia_pp_setup(char *str)
 {
-#if 0
-	/* Is this only a 2.2ism? -jerdfelt */
-	if (!str) {
-		if (ints[0] == 0 || ints[1] == 0) {
-			/* disable driver on "cpia_pp=" or "cpia_pp=0" */
-			parport_nr[0] = PPCPIA_PARPORT_OFF;
-		}
-	} else
-#endif
 	if (!strncmp(str, "parport", 7)) {
 		int n = simple_strtoul(str + 7, NULL, 10);
 		if (parport_ptr < PARPORT_MAX) {
diff -Nru a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
--- a/drivers/media/video/cpia_usb.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/media/video/cpia_usb.c	Tue Oct 15 20:29:11 2002
@@ -273,14 +273,16 @@
 
 error_urb1:		/* free urb 1 */
 	usb_free_urb(ucpia->sbuf[1].urb);
-
+	ucpia->sbuf[1].urb = NULL;
 error_urb0:		/* free urb 0 */
 	usb_free_urb(ucpia->sbuf[0].urb);
-
+	ucpia->sbuf[0].urb = NULL;
 error_1:
 	kfree (ucpia->sbuf[1].data);
+	ucpia->sbuf[1].data = NULL;
 error_0:
 	kfree (ucpia->sbuf[0].data);
+	ucpia->sbuf[0].data = NULL;
 	
 	return retval;
 }
@@ -636,8 +638,10 @@
 		ucpia->buffers[0] = NULL;
 	}
 
-	if (!ucpia->open)
-		kfree(ucpia);
+	if (!ucpia->open) {
+ 		kfree(ucpia);
+		cam->lowlevel_data = NULL;
+	}
 }
 
 static int __init usb_cpia_init(void)
diff -Nru a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
--- a/drivers/media/video/video-buf.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/media/video/video-buf.c	Tue Oct 15 20:29:17 2002
@@ -18,8 +18,8 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/iobuf.h>
 #include <linux/vmalloc.h>
+#include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
@@ -65,32 +65,31 @@
 	return NULL;
 }
 
-struct scatterlist*
-videobuf_iobuf_to_sg(struct kiobuf *iobuf)
+struct scatterlist *
+videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 {
 	struct scatterlist *sglist;
 	int i = 0;
-
-	sglist = kmalloc(sizeof(struct scatterlist) * iobuf->nr_pages,
-			 GFP_KERNEL);
+	
+	if (NULL == pages[0])
+		return NULL;
+	sglist = kmalloc(sizeof(*sglist) * nr_pages, GFP_KERNEL);
 	if (NULL == sglist)
 		return NULL;
-	memset(sglist,0,sizeof(struct scatterlist) * iobuf->nr_pages);
+	memset(sglist, 0, sizeof(*sglist) * nr_pages);
 
-	if (NULL == iobuf->maplist[0])
-		goto err;
-	if (PageHighMem(iobuf->maplist[0]))
+	if (PageHighMem(pages[0]))
 		/* DMA to highmem pages might not work */
 		goto err;
-	sglist[0].page   = iobuf->maplist[0];
-	sglist[0].offset = iobuf->offset;
-	sglist[0].length = PAGE_SIZE - iobuf->offset;
-	for (i = 1; i < iobuf->nr_pages; i++) {
-		if (NULL == iobuf->maplist[i])
+	sglist[0].page   = pages[0];
+	sglist[0].offset = offset;
+	sglist[0].length = PAGE_SIZE - offset;
+	for (i = 1; i < nr_pages; i++) {
+		if (NULL == pages[i])
 			goto err;
-		if (PageHighMem(iobuf->maplist[i]))
+		if (PageHighMem(pages[i]))
 			goto err;
-		sglist[i].page   = iobuf->maplist[i];
+		sglist[i].page   = pages[i];
 		sglist[i].length = PAGE_SIZE;
 	}
 	return sglist;
@@ -100,6 +99,30 @@
 	return NULL;
 }
 
+int videobuf_lock(struct page **pages, int nr_pages)
+{
+	int i;
+
+	for (i = 0; i < nr_pages; i++)
+		if (TestSetPageLocked(pages[i]))
+			goto err;
+	return 0;
+
+ err:
+	while (i > 0)
+		unlock_page(pages[--i]);
+	return -EINVAL;
+}
+
+int videobuf_unlock(struct page **pages, int nr_pages)
+{
+	int i;
+
+	for (i = 0; i < nr_pages; i++)
+		unlock_page(pages[i]);
+	return 0;
+}
+
 /* --------------------------------------------------------------------- */
 
 int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
@@ -113,14 +136,21 @@
 	case PCI_DMA_TODEVICE:   rw = WRITE; break;
 	default:                 BUG();
 	}
-	if (0 != (err = alloc_kiovec(1,&dma->iobuf)))
-		return err;
-	if (0 != (err = map_user_kiobuf(rw, dma->iobuf, data, size))) {
-		dprintk(1,"map_user_kiobuf: %d\n",err);
-		return err;
-	}
-	dma->nr_pages = dma->iobuf->nr_pages;
-	return 0;
+
+	dma->offset   = data & PAGE_MASK;
+	dma->nr_pages = ((((data+size) & ~PAGE_MASK) -
+			  (data & ~PAGE_MASK)) >> PAGE_SHIFT) +1;
+	dma->pages    = kmalloc(dma->nr_pages * sizeof(struct page*),
+				GFP_KERNEL);
+	if (NULL == dma->pages)
+		return -ENOMEM;
+	down_read(&current->mm->mmap_sem);
+        err = get_user_pages(current,current->mm,
+			     data, dma->nr_pages,
+			     rw == READ, 0, /* don't force */
+			     dma->pages, NULL);
+	up_read(&current->mm->mmap_sem);
+	return err;
 }
 
 int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
@@ -144,13 +174,15 @@
 	if (0 == dma->nr_pages)
 		BUG();
 	
-	if (dma->iobuf) {
-		if (0 != (err = lock_kiovec(1,&dma->iobuf,1))) {
-			dprintk(1,"lock_kiovec: %d\n",err);
+	if (dma->pages) {
+		if (0 != (err = videobuf_lock(dma->pages, dma->nr_pages))) {
+			dprintk(1,"videobuf_lock_pages: %d\n",err);
 			return err;
 		}
-		dma->sglist = videobuf_iobuf_to_sg(dma->iobuf);
+		dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
+						   dma->offset);
 	}
+
 	if (dma->vmalloc) {
 		dma->sglist = videobuf_vmalloc_to_sg
 			(dma->vmalloc,dma->nr_pages);
@@ -160,7 +192,7 @@
 		return -ENOMEM;
 	}
 	dma->sglen = pci_map_sg(dev,dma->sglist,dma->nr_pages,
-				 dma->direction);
+				dma->direction);
 	return 0;
 }
 
@@ -182,8 +214,8 @@
 	kfree(dma->sglist);
 	dma->sglist = NULL;
 	dma->sglen = 0;
-	if (dma->iobuf)
-		unlock_kiovec(1,&dma->iobuf);
+	if (dma->pages)
+		videobuf_lock(dma->pages, dma->nr_pages);
 	return 0;
 }
 
@@ -192,11 +224,14 @@
 	if (dma->sglen)
 		BUG();
 
-	if (dma->iobuf) {
-		unmap_kiobuf(dma->iobuf);
-		free_kiovec(1,&dma->iobuf);
-		dma->iobuf = NULL;
+	if (dma->pages) {
+		int i;
+		for (i=0; i < dma->nr_pages; i++)
+			page_cache_release(dma->pages[i]);
+		kfree(dma->pages);
+		dma->pages = NULL;
 	}
+
 	if (dma->vmalloc) {
 		vfree(dma->vmalloc);
 		dma->vmalloc = NULL;
@@ -959,6 +994,7 @@
 	map->q       = q;
 	vma->vm_ops  = &videobuf_vm_ops;
 	vma->vm_flags |= VM_DONTEXPAND;
+	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
 	vma->vm_private_data = map;
 	dprintk(1,"mmap %p: %08lx-%08lx pgoff %08lx bufs %d-%d\n",
 		map,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
@@ -972,7 +1008,6 @@
 /* --------------------------------------------------------------------- */
 
 EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
-EXPORT_SYMBOL_GPL(videobuf_iobuf_to_sg);
 
 EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
 EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
diff -Nru a/drivers/media/video/video-buf.h b/drivers/media/video/video-buf.h
--- a/drivers/media/video/video-buf.h	Tue Oct 15 20:29:17 2002
+++ b/drivers/media/video/video-buf.h	Tue Oct 15 20:29:17 2002
@@ -28,11 +28,12 @@
 struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
 
 /*
- * Return a scatterlist for a locked iobuf (NULL on errors).  Memory
+ * Return a scatterlist for a an array of userpages (NULL on errors).  Memory
  * for the scatterlist is allocated using kmalloc.  The caller must
  * free the memory.
  */
-struct scatterlist* videobuf_iobuf_to_sg(struct kiobuf *iobuf);
+struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
+					 int offset);
 
 /* --------------------------------------------------------------------- */
 
@@ -57,7 +58,8 @@
 
 struct videobuf_dmabuf {
 	/* for userland buffer */
-	struct kiobuf       *iobuf;
+	struct page         **pages;
+	int                 offset;
 
 	/* for kernel buffers */
 	void                *vmalloc;
diff -Nru a/drivers/message/fusion/Config.help b/drivers/message/fusion/Config.help
--- a/drivers/message/fusion/Config.help	Tue Oct 15 20:29:16 2002
+++ b/drivers/message/fusion/Config.help	Tue Oct 15 20:29:16 2002
@@ -42,6 +42,16 @@
   architecture is based on LSI Logic's Message Passing Interface (MPI)
   specification.
 
+Maximum number of scatter gather entries
+CONFIG_FUSION_MAX_SGE
+  This option allows you to specify the maximum number of scatter-
+  gather entries per I/O. The driver defaults to 40, a reasonable number
+  for most systems. However, the user may increase this up to 128.
+  Increasing this parameter will require significantly more memory 
+  on a per controller instance. Increasing the parameter is not
+  necessary (or recommended) unless the user will be running 
+  large I/O's via the raw interface.
+
 CONFIG_FUSION_ISENSE
   The isense module (roughly stands for Interpret SENSE data) is
   completely optional.  It simply provides extra English readable
diff -Nru a/drivers/message/fusion/Config.in b/drivers/message/fusion/Config.in
--- a/drivers/message/fusion/Config.in	Tue Oct 15 20:29:15 2002
+++ b/drivers/message/fusion/Config.in	Tue Oct 15 20:29:15 2002
@@ -10,6 +10,7 @@
   else
     define_bool CONFIG_FUSION_BOOT n
   fi
+  int  "  Maximum number of scatter gather entries" CONFIG_FUSION_MAX_SGE 40 
 
   if [ "$CONFIG_MODULES" = "y" ]; then
     #  How can we force these options to module or nothing?
diff -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
--- a/drivers/message/fusion/linux_compat.h	Tue Oct 15 20:29:15 2002
+++ b/drivers/message/fusion/linux_compat.h	Tue Oct 15 20:29:15 2002
@@ -253,24 +253,35 @@
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
-#define mptscsih_save_flags(flags) \
-({	local_irq_save(flags); \
-})
+#define mptscsih_lock(iocp, flags) \
+                spin_lock_irqsave(&iocp->FreeQlock, flags)
 #else
-#define mptscsih_save_flags(flags) \
+#define mptscsih_lock(iocp, flags) \
 ({	save_flags(flags); \
 	cli(); \
 })
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28)
-#define mptscsih_restore_flags(flags) \
-({	local_irq_enable(); \
-	local_irq_restore(flags); \
-})
+#define mptscsih_unlock(iocp, flags) \
+                spin_unlock_irqrestore(&iocp->FreeQlock, flags)
+#else
+#define mptscsih_unlock(iocp, flags)  restore_flags(flags);
+#endif
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+#define mpt_work_struct work_struct 
+#define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data)
 #else
-#define mptscsih_restore_flags(flags)  restore_flags(flags);
+#define mpt_work_struct tq_struct 
+#define MPT_INIT_WORK(_task, _func, _data) \
+({	(_task)->sync = 0; \
+	(_task)->routine = (_func); \
+	(_task)->data = (void *) (_data); \
+})
 #endif
+
 
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #endif /* _LINUX_COMPAT_H */
diff -Nru a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
--- a/drivers/message/fusion/lsi/mpi.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/message/fusion/lsi/mpi.h	Tue Oct 15 20:29:12 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI Message independent structures and definitions
  *  Creation Date:  July 27, 2000
  *
- *    MPI.H Version:  01.02.06
+ *    MPI.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -47,6 +47,7 @@
  *  03-14-02  01.02.04  Added MPI_HEADER_VERSION_ defines.
  *  05-31-02  01.02.05  Bumped MPI_HEADER_VERSION_UNIT.
  *  07-12-02  01.02.06  Added define for MPI_FUNCTION_MAILBOX.
+ *  09-16-02  01.02.07  Bumped value for MPI_HEADER_VERSION_UNIT.
  *  --------------------------------------------------------------------------
  */
 
@@ -75,7 +76,7 @@
 /* Note: The major versions of 0xe0 through 0xff are reserved */
 
 /* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT             (0x07)
+#define MPI_HEADER_VERSION_UNIT             (0x09)
 #define MPI_HEADER_VERSION_DEV              (0x00)
 #define MPI_HEADER_VERSION_UNIT_MASK        (0xFF00)
 #define MPI_HEADER_VERSION_UNIT_SHIFT       (8)
diff -Nru a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
--- a/drivers/message/fusion/lsi/mpi_cnfg.h	Tue Oct 15 20:29:17 2002
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h	Tue Oct 15 20:29:17 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI Config message, structures, and Pages
  *  Creation Date:  July 27, 2000
  *
- *    MPI_CNFG.H Version:  01.02.08
+ *    MPI_CNFG.H Version:  01.02.09
  *
  *  Version History
  *  ---------------
@@ -127,6 +127,7 @@
  *                      MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE.
  *                      Added new config page: CONFIG_PAGE_SCSI_DEVICE_3.
  *                      Modified MPI_FCPORTPAGE5_FLAGS_ defines.
+ *  09-16-02 01.02.09   Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define.
  *  --------------------------------------------------------------------------
  */
 
@@ -814,6 +815,7 @@
 #define MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED           (0x00000002)
 #define MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED           (0x00000004)
 #define MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE    (0x00000008)
+#define MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG             (0x00000010)
 
 
 typedef struct _CONFIG_PAGE_SCSI_DEVICE_2
diff -Nru a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h
--- a/drivers/message/fusion/lsi/mpi_targ.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/message/fusion/lsi/mpi_targ.h	Tue Oct 15 20:29:12 2002
@@ -6,7 +6,7 @@
  *          Title:  MPI Target mode messages and structures
  *  Creation Date:  June 22, 2000
  *
- *    MPI_TARG.H Version:  01.02.06
+ *    MPI_TARG.H Version:  01.02.07
  *
  *  Version History
  *  ---------------
@@ -39,6 +39,8 @@
  *  05-31-02  01.02.06  Modified TARGET_MODE_REPLY_ALIAS_MASK to only include
  *                      one bit.
  *                      Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER.
+ *  09-16-02  01.02.07  Added flags for confirmed completion.
+ *                      Added PRIORITY_REASON_TARGET_BUSY.
  *  --------------------------------------------------------------------------
  */
 
@@ -138,6 +140,7 @@
 #define PRIORITY_REASON_PROTOCOL_ERR            (0x06)
 #define PRIORITY_REASON_DATA_OUT_PARITY_ERR     (0x07)
 #define PRIORITY_REASON_DATA_OUT_CRC_ERR        (0x08)
+#define PRIORITY_REASON_TARGET_BUSY             (0x09)
 #define PRIORITY_REASON_UNKNOWN                 (0xFF)
 
 
@@ -217,6 +220,7 @@
 #define TARGET_ASSIST_FLAGS_DATA_DIRECTION          (0x01)
 #define TARGET_ASSIST_FLAGS_AUTO_STATUS             (0x02)
 #define TARGET_ASSIST_FLAGS_HIGH_PRIORITY           (0x04)
+#define TARGET_ASSIST_FLAGS_CONFIRMED               (0x08)
 #define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER       (0x80)
 
 
@@ -261,6 +265,7 @@
 
 #define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS   (0x01)
 #define TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY      (0x04)
+#define TARGET_STATUS_SEND_FLAGS_CONFIRMED          (0x08)
 #define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER  (0x80)
 
 /*
diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
--- a/drivers/message/fusion/mptbase.c	Tue Oct 15 20:29:13 2002
+++ b/drivers/message/fusion/mptbase.c	Tue Oct 15 20:29:13 2002
@@ -49,7 +49,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.c,v 1.121 2002/07/23 18:56:59 pdelaney Exp $
+ *  $Id: mptbase.c,v 1.122 2002/10/03 13:10:11 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -1416,10 +1416,30 @@
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
 		ioc->chip_type = FC929X;
 		ioc->prod_name = "LSIFC929X";
+		{
+			/* 929X Chip Fix. Set Split transactions level
+			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+			 */
+			u16 pcixcmd = 0;
+			pci_read_config_word(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0xFF9F;
+			pcixcmd |= 0x0010;
+			pci_write_config_word(pdev, 0x6a, pcixcmd);
+		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
 		ioc->chip_type = FC919X;
 		ioc->prod_name = "LSIFC919X";
+		{
+			/* 919X Chip Fix. Set Split transactions level
+			 * for PCIX. Set bits 5 - 6 to zero, turn on bit 4.
+			 */
+			u16 pcixcmd = 0;
+			pci_read_config_word(pdev, 0x6a, &pcixcmd);
+			pcixcmd &= 0xFF9F;
+			pcixcmd |= 0x0010;
+			pci_write_config_word(pdev, 0x6a, pcixcmd);
+		}
 	}
 	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
 		ioc->chip_type = C1030;
diff -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
--- a/drivers/message/fusion/mptbase.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/message/fusion/mptbase.h	Tue Oct 15 20:29:12 2002
@@ -13,7 +13,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptbase.h,v 1.133 2002/09/05 22:30:09 pdelaney Exp $
+ *  $Id: mptbase.h,v 1.134 2002/10/03 13:10:12 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -80,8 +80,8 @@
 #define COPYRIGHT	"Copyright (c) 1999-2002 " MODULEAUTHOR
 #endif
 
-#define MPT_LINUX_VERSION_COMMON	"2.02.01.01"
-#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.02.01.01"
+#define MPT_LINUX_VERSION_COMMON	"2.02.01.07"
+#define MPT_LINUX_PACKAGE_NAME		"@(#)mptlinux-2.02.01.07"
 #define WHAT_MAGIC_STRING		"@" "(" "#" ")"
 
 #define show_mptmod_ver(s,ver)  \
@@ -91,7 +91,7 @@
 /*
  *  Fusion MPT(linux) driver configurable stuff...
  */
-#define MPT_MAX_ADAPTERS		16
+#define MPT_MAX_ADAPTERS		18
 #define MPT_MAX_PROTOCOL_DRIVERS	16
 #define MPT_MAX_BUS			1
 #define MPT_MAX_FC_DEVICES		255
@@ -397,8 +397,10 @@
 	ScsiCmndTracker		 SentQ;
 	ScsiCmndTracker		 DoneQ;
 //--- LUN split here?
+#ifdef MPT_SAVE_AUTOSENSE
 	u8			 sense[SCSI_STD_SENSE_BYTES];		/* 18 */
 	u8			 rsvd2[2];	/* alignment */
+#endif
 	u32			 luns;		/* Max LUNs is 32 */
 	u8			 inq_data[SCSI_STD_INQUIRY_BYTES];	/* 36 */
 	u8			 pad0[4];
@@ -424,7 +426,9 @@
 #define MPT_TARGET_DEFAULT_DV_STATUS	0
 #define MPT_TARGET_FLAGS_VALID_NEGO	0x01
 #define MPT_TARGET_FLAGS_VALID_INQUIRY	0x02
+#ifdef MPT_SAVE_AUTOSENSE
 #define MPT_TARGET_FLAGS_VALID_SENSE	0x04
+#endif
 #define MPT_TARGET_FLAGS_Q_YES		0x08
 #define MPT_TARGET_FLAGS_VALID_56	0x10
 
@@ -890,6 +894,8 @@
 	MPT_Q_TRACKER		  taskQ;		/* TM request Q */
 	spinlock_t		  freedoneQlock;
 	int			  taskQcnt;
+	int			  num_chain;		/* Number of chain buffers */
+	int			  max_sge;		/* Max No of SGE*/
 	u8			  numTMrequests;
 	u8			  tmPending;
 	u8			  resetPending;
diff -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
--- a/drivers/message/fusion/mptctl.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/message/fusion/mptctl.c	Tue Oct 15 20:29:11 2002
@@ -34,7 +34,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.c,v 1.59 2002/09/05 22:30:10 pdelaney Exp $
+ *  $Id: mptctl.c,v 1.60 2002/10/03 13:10:13 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -627,7 +627,7 @@
 	/* Test for Compaq-specific IOCTL's.
 	 */
 	if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) ||
-		(cmd == CPQFCTS_GETDRIVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) ||
+		(cmd == CPQFCTS_GETDRIVVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) ||
 		(cmd == CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS))
 		return mptctl_compaq_ioctl(file, cmd, arg);
 
@@ -2406,7 +2406,7 @@
 	case CPQFCTS_GETPCIINFO:
 		ret = mptctl_cpq_getpciinfo(arg);
 		break;
-	case CPQFCTS_GETDRIVER:
+	case CPQFCTS_GETDRIVVER:
 		ret = mptctl_cpq_getdriver(arg);
 		break;
 	case CPQFCTS_CTLR_STATUS:
@@ -3180,7 +3180,7 @@
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(CPQFCTS_CTLR_STATUS, NULL);
 	if (++where && err) goto out_fail;
-	err = register_ioctl32_conversion(CPQFCTS_GETDRIVER, NULL);
+	err = register_ioctl32_conversion(CPQFCTS_GETDRIVVER, NULL);
 	if (++where && err) goto out_fail;
 	err = register_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS, NULL);
 	if (++where && err) goto out_fail;
@@ -3234,7 +3234,7 @@
 	unregister_ioctl32_conversion(MPTCOMMAND32);
 	unregister_ioctl32_conversion(MPTFWDOWNLOAD32);
 	unregister_ioctl32_conversion(CPQFCTS_GETPCIINFO);
-	unregister_ioctl32_conversion(CPQFCTS_GETDRIVER);
+	unregister_ioctl32_conversion(CPQFCTS_GETDRIVVER);
 	unregister_ioctl32_conversion(CPQFCTS_CTLR_STATUS);
 	unregister_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS);
 	unregister_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32);
diff -Nru a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
--- a/drivers/message/fusion/mptctl.h	Tue Oct 15 20:29:17 2002
+++ b/drivers/message/fusion/mptctl.h	Tue Oct 15 20:29:17 2002
@@ -20,7 +20,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptctl.h,v 1.10 2002/05/28 15:57:16 pdelaney Exp $
+ *  $Id: mptctl.h,v 1.11 2002/10/03 13:10:13 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -319,12 +319,12 @@
 #define CPQFCTS_IOC_MAGIC 'Z'
 
 #define CPQFCTS_GETPCIINFO		_IOR(CPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct)
-#define CPQFCTS_GETDRIVER		_IOR(CPQFCTS_IOC_MAGIC, 2, int)
+#define CPQFCTS_GETDRIVVER		_IOR(CPQFCTS_IOC_MAGIC, 9, int)
 #define CPQFCTS_CTLR_STATUS		_IOR(CPQFCTS_IOC_MAGIC, 3, struct _cpqfc_ctlr_status)
-#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS	_IOR(CPQFCTS_IOC_MAGIC, 4, struct scsi_fctargaddress)
-#define CPQFCTS_SCSI_PASSTHRU		_IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ)
+#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS	_IOR(CPQFCTS_IOC_MAGIC, 13, struct scsi_fctargaddress)
+#define CPQFCTS_SCSI_PASSTHRU		_IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ)
 #if defined(__sparc__) && defined(__sparc_v9__)
-#define CPQFCTS_SCSI_PASSTHRU32		_IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ32)
+#define CPQFCTS_SCSI_PASSTHRU32		_IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ32)
 #endif
 
 typedef struct {
diff -Nru a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
--- a/drivers/message/fusion/mptlan.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/message/fusion/mptlan.c	Tue Oct 15 20:29:17 2002
@@ -132,7 +132,7 @@
 	u32 total_received;
 	struct net_device_stats stats;	/* Per device statistics */
 
-	struct work_struct post_buckets_task;
+	struct mpt_work_struct post_buckets_task;
 	unsigned long post_buckets_active;
 };
 
@@ -876,9 +876,22 @@
 	
 	if (test_and_set_bit(0, &priv->post_buckets_active) == 0) {
 		if (priority) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
 			schedule_work(&priv->post_buckets_task);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+			schedule_task(&priv->post_buckets_task);
+#else
+			queue_task(&priv->post_buckets_task, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+#endif
 		} else {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
 			schedule_delayed_work(&priv->post_buckets_task, 1);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+			schedule_task(&priv->post_buckets_task);
+#else
+			queue_task(&priv->post_buckets_task, &tq_timer);
+#endif
 			dioprintk((KERN_INFO MYNAM ": post_buckets queued on "
 				   "timer.\n"));
 		}
@@ -1364,8 +1377,8 @@
 	priv->mpt_dev = mpt_dev;
 	priv->pnum = pnum;
 
-	memset(&priv->post_buckets_task, 0, sizeof(struct work_struct));
-	INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
+	memset(&priv->post_buckets_task, 0, sizeof(struct mpt_work_struct));
+	MPT_INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev);
 	priv->post_buckets_active = 0;
 
 	dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n",
diff -Nru a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
--- a/drivers/message/fusion/mptlan.h	Tue Oct 15 20:29:15 2002
+++ b/drivers/message/fusion/mptlan.h	Tue Oct 15 20:29:15 2002
@@ -20,7 +20,11 @@
 #include <linux/slab.h>
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)
+#include <linux/tqueue.h>
+#else
 #include <linux/workqueue.h>
+#endif
 #include <linux/delay.h>
 // #include <linux/trdevice.h>
 
diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
--- a/drivers/message/fusion/mptscsih.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/message/fusion/mptscsih.c	Tue Oct 15 20:29:16 2002
@@ -26,7 +26,7 @@
  *  (mailto:sjralston1@netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.c,v 1.101 2002/09/05 22:30:11 pdelaney Exp $
+ *  $Id: mptscsih.c,v 1.102 2002/10/03 13:10:14 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -76,7 +76,6 @@
 #include <linux/delay.h>	/* for mdelay */
 #include <linux/interrupt.h>	/* needed for in_interrupt() proto */
 #include <linux/reboot.h>	/* notifier code */
-#include <linux/workqueue.h>
 #include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 #include "../../scsi/sd.h"
@@ -165,7 +164,6 @@
 static int	mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex);
 static void	mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx);
 static int	mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init);
-
 static void	copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
 #ifndef MPT_SCSI_USE_NEW_EH
 static void	search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd);
@@ -184,7 +182,9 @@
 
 static VirtDevice	*mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen);
 void		mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56);
+#ifdef MPT_SAVE_AUTOSENSE
 static void	clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
+#endif
 static void	mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq);
 static void	mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags);
 static void	mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id);
@@ -245,7 +245,7 @@
  */
 static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int mytaskQ_bh_active = 0;
-static struct work_struct	mptscsih_ptaskfoo;
+static struct mpt_work_struct	mptscsih_ptaskfoo;
 static atomic_t	mpt_taskQdepth;
 #endif
 
@@ -256,7 +256,7 @@
 static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED;
 static int dvtaskQ_active = 0;
 static int dvtaskQ_release = 0;
-static struct work_struct	mptscsih_dvTask;
+static struct mpt_work_struct	mptscsih_dvTask;
 #endif
 
 /*
@@ -352,7 +352,9 @@
 						dlen);
 			}
 		}
+#ifdef MPT_SAVE_AUTOSENSE
 		clear_sense_flag(hd, pScsiReq);
+#endif
 	} else {
 		u32	 xfer_cnt;
 		u16	 status;
@@ -437,17 +439,21 @@
 			 *  precedence!
 			 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
 			clear_sense_flag(hd, pScsiReq);
-			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#endif
+			if (scsi_state == 0) {
+				;
+			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
 				/* Have already saved the status and sense data
 				 */
 				;
-			} else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
+			} else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) {
 				/* What to do?
 				 */
 				sc->result = DID_SOFT_ERROR << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
 				sc->result = DID_RESET << 16;
 			}
@@ -488,9 +494,12 @@
 		case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR:	/* 0x0040 */
 		case MPI_IOCSTATUS_SUCCESS:			/* 0x0000 */
 			sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus;
+#ifdef MPT_SAVE_AUTOSENSE
 			clear_sense_flag(hd, pScsiReq);
-
-			if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#endif
+			if (scsi_state == 0) {
+				;
+			} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
 				/*
 				 * If running agains circa 200003dd 909 MPT f/w,
 				 * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL
@@ -521,7 +530,7 @@
 #endif
 
 			}
-			else if (pScsiReply->SCSIState &
+			else if (scsi_state &
 			         (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)
 			   ) {
 				/*
@@ -529,11 +538,11 @@
 				 */
 				sc->result = DID_SOFT_ERROR << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) {
+			else if (scsi_state & MPI_SCSI_STATE_TERMINATED) {
 				/*  Not real sure here either...  */
 				sc->result = DID_RESET << 16;
 			}
-			else if (pScsiReply->SCSIState & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
+			else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) {
 				/* Device Inq. data indicates that it supports
 				 * QTags, but rejects QTag messages.
 				 * This command completed OK.
@@ -1024,21 +1033,13 @@
 	MPT_FRAME_HDR	*chain;
 	u8		*mem;
 	unsigned long	flags;
-	int		sz, ii, numChain;
+	int		sz, ii, num_chain;
+	int 		scale, num_sge;
 
-
-        /* Chain buffer allocations
-	 * Allocate and initialize tracker structures
+	/* ReqToChain size must equal the req_depth
+	 * index = req_idx
 	 */
-	if (hd->ioc->req_sz <= 64)
-		numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth;
-	else if (hd->ioc->req_sz <= 96)
-		numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth;
-	else
-		numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth;
-
-	sz = numChain * sizeof(int);
-
+	sz = hd->ioc->req_depth * sizeof(int);
 	if (hd->ReqToChain == NULL) {
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
@@ -1050,6 +1051,38 @@
 	}
 	memset(mem, 0xFF, sz);
 
+
+	/* ChainToChain size must equal the total number
+	 * of chain buffers to be allocated.
+	 * index = chain_idx
+	 *
+	 * Calculate the number of chain buffers needed(plus 1) per I/O 
+	 * then multiply the the maximum number of simultaneous cmds
+	 *
+	 * num_sge = num sge in request frame + last chain buffer
+	 * scale = num sge per chain buffer if no chain element
+	 */
+	scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32));
+	if (sizeof(dma_addr_t) == sizeof(u64))
+		num_sge =  scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32));
+	else
+		num_sge =  1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
+
+	num_chain = 1;
+	while (hd->max_sge - num_sge > 0) {
+		num_chain++;
+		num_sge += (scale - 1);
+	}
+	num_chain++;
+
+	if ((int) hd->ioc->chip_type > (int) FC929)
+		num_chain *= MPT_SCSI_CAN_QUEUE;
+	else
+		num_chain *= MPT_FC_CAN_QUEUE;
+
+	hd->num_chain = num_chain;
+
+	sz = num_chain * sizeof(int);
 	if (hd->ChainToChain == NULL) {
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
@@ -1061,10 +1094,10 @@
 	}
 	memset(mem, 0xFF, sz);
 
+	sz = num_chain * hd->ioc->req_sz;
 	if (hd->ChainBuffer == NULL) {
 		/* Allocate free chain buffer pool
 		 */
-		sz = numChain * hd->ioc->req_sz;
 		mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA);
 		if (mem == NULL)
 			return -1;
@@ -1090,7 +1123,7 @@
 	/* Post the chain buffers to the FreeChainQ.
 	 */
 	mem = (u8 *)hd->ChainBuffer;
-	for (ii=0; ii < numChain; ii++) {
+	for (ii=0; ii < num_chain; ii++) {
 		chain = (MPT_FRAME_HDR *) mem;
 		Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR);
 		mem += hd->ioc->req_sz;
@@ -1227,7 +1260,7 @@
 #endif
 			sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST));
 			if (sh != NULL) {
-				mptscsih_save_flags(flags);
+				mptscsih_lock(this, flags);
 				sh->io_port = 0;
 				sh->n_io_port = 0;
 				sh->irq = 0;
@@ -1254,12 +1287,21 @@
 				}
 				sh->max_lun = MPT_LAST_LUN + 1;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
+				sh->max_sectors = MPT_SCSI_MAX_SECTORS;
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
+				sh->highmem_io = 1;
+#endif
 				sh->this_id = this->pfacts[portnum].PortSCSIID;
 
 				/* OS entry to allow host drivers to force
 				 * a queue depth on a per device basis.
 				 */
 				sh->select_queue_depths = mptscsih_select_queue_depths;
+				/* Required entry.
+				 */
+				sh->unique_id = this->id;
 
 				/* Verify that we won't exceed the maximum
 				 * number of chain buffers
@@ -1291,10 +1333,11 @@
 				 */
 				scsi_set_pci_device(sh, this->pcidev);
 
-				mptscsih_restore_flags(flags);
+				mptscsih_unlock(this, flags);
 
 				hd = (MPT_SCSI_HOST *) sh->hostdata;
 				hd->ioc = this;
+				hd->max_sge = sh->sg_tablesize;
 
 				if ((int)this->chip_type > (int)FC929)
 					hd->is_spi = 1;
@@ -1534,7 +1577,6 @@
 		int szc2chain = 0;
 		int szchain = 0;
 		int szQ = 0;
-		int scale;
 
 		/* Synchronize disk caches
 		 */
@@ -1542,13 +1584,6 @@
 
 		sz1 = sz2 = sz3 = 0;
 
-		if (hd->ioc->req_sz <= 64)
-			scale = MPT_SG_REQ_64_SCALE;
-		else if (hd->ioc->req_sz <= 96)
-			scale = MPT_SG_REQ_96_SCALE;
-		else
-			scale = MPT_SG_REQ_128_SCALE;
-
 		if (hd->ScsiLookup != NULL) {
 			sz1 = hd->ioc->req_depth * sizeof(void *);
 			kfree(hd->ScsiLookup);
@@ -1556,19 +1591,19 @@
 		}
 
 		if (hd->ReqToChain != NULL) {
-			szr2chain = scale * hd->ioc->req_depth * sizeof(int);
+			szr2chain = hd->ioc->req_depth * sizeof(int);
 			kfree(hd->ReqToChain);
 			hd->ReqToChain = NULL;
 		}
 
 		if (hd->ChainToChain != NULL) {
-			szc2chain = scale * hd->ioc->req_depth * sizeof(int);
+			szc2chain = hd->num_chain * sizeof(int);
 			kfree(hd->ChainToChain);
 			hd->ChainToChain = NULL;
 		}
 
 		if (hd->ChainBuffer != NULL) {
-			sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz;
+			sz2 = hd->num_chain * hd->ioc->req_sz;
 			szchain = szr2chain + szc2chain + sz2;
 
 			pci_free_consistent(hd->ioc->pcidev, sz2,
@@ -1591,7 +1626,7 @@
 			if (hd->is_spi) {
 				max = MPT_MAX_SCSI_DEVICES;
 			} else {
-				max = MPT_MAX_FC_DEVICES;
+				max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
 			}
 			for (ii=0; ii < max; ii++) {
 				if (hd->Targets[ii]) {
@@ -1805,6 +1840,7 @@
 	dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
 			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
 
+#ifdef MPT_SAVE_AUTOSENSE
 	/* 20000617 -sralston
 	 *  GRRRRR...  Shouldn't have to do this but...
 	 *  Do explicit check for REQUEST_SENSE and cached SenseData.
@@ -1840,6 +1876,7 @@
 			}
 		}
 	}
+#endif
 
 	if (hd->resetPending) {
 		/* Prevent new commands from being issued
@@ -2020,7 +2057,8 @@
 					if (!dvtaskQ_active) {
 						dvtaskQ_active = 1;
 						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
-						INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd);
+						MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); 
+
 						SCHEDULE_TASK(&mptscsih_dvTask);
 					} else {
 						spin_unlock_irqrestore(&dvtaskQ_lock, lflags);
@@ -3046,7 +3084,7 @@
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct work_struct	*ptaskfoo;
+	struct mpt_work_struct	*ptaskfoo;
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
@@ -3154,10 +3192,8 @@
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
 		 */
-		ptaskfoo = (struct work_struct *) &mptscsih_ptaskfoo;
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
+		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); 
 
 		SCHEDULE_TASK(ptaskfoo);
 	} else  {
@@ -3182,7 +3218,7 @@
 {
 	MPT_SCSI_HOST		*hd;
 	MPT_FRAME_HDR		*mf;
-	struct work_struct	*ptaskfoo;
+	struct mpt_work_struct	*ptaskfoo;
 	unsigned long		 flags;
 	int			 scpnt_idx;
 
@@ -3284,10 +3320,8 @@
 		 *  Oh how cute, no alloc/free/mgmt needed if we use
 		 *  (bottom/unused portion of) MPT request frame.
 		 */
-		ptaskfoo = (struct work_struct *) &mptscsih_ptaskfoo;
-		ptaskfoo->sync = 0;
-		ptaskfoo->routine = mptscsih_taskmgmt_bh;
-		ptaskfoo->data = SCpnt;
+		ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo;
+		MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); 
 
 		SCHEDULE_TASK(ptaskfoo);
 	} else  {
@@ -3655,7 +3689,7 @@
 			if (hd->is_spi)
 				max = MPT_MAX_SCSI_DEVICES;
 			else
-				max = MPT_MAX_FC_DEVICES;
+				max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255;
 
 			for (ii=0; ii < max; ii++) {
 				pTarget = hd->Targets[ii];
@@ -3801,6 +3835,7 @@
 		/* save sense data to the target device
 		 */
 		if (target) {
+#ifdef MPT_SAVE_AUTOSENSE
 			int sz;
 
 			sz = MIN(pReq->SenseBufferLength, sense_count);
@@ -3808,6 +3843,7 @@
 				sz =  SCSI_STD_SENSE_BYTES;
 			memcpy(target->sense, sense_data, sz);
 			target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE;
+#endif
 
 #ifdef ABORT_FIX
 			if (sz >= SCSI_STD_SENSE_BYTES) {
@@ -4491,6 +4527,7 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+#if 0
 static int dump_sd(char *foo, unsigned char *sd)
 {
 	int snsLen = 8 + SD_Additional_Sense_Length(sd);
@@ -4503,6 +4540,7 @@
 
 	return l;
 }
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*  Do ASC/ASCQ lookup/grindage to English readable string(s)  */
@@ -4594,6 +4632,15 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
+ *  SCSI Information Report; desired output format...
+ *---
+SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION)
+  Key=6h (UNIT ATTENTION); FRU=03h
+  ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED"
+  CDB: 00 00 00 00 00 00 - TestUnitReady
+ *---
+ */
+/*
  *  SCSI Error Report; desired output format...
  *---
 SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0)
@@ -4617,6 +4664,22 @@
 	unsigned char	 ascq		= SD_ASCQ(ioop->sensePtr);
 	int		 l;
 
+	/* Change the error logging to only report errors on
+	 * read and write commands. Ignore errors on other commands.
+	 * Should this be configurable via proc?
+	 */
+	switch (ioop->cdbPtr[0]) {
+	case READ_6:
+	case WRITE_6:
+	case READ_10:
+	case WRITE_10:
+	case READ_12:
+	case WRITE_12:
+		break;
+	default:
+		return 0;
+	}
+
 	/*
 	 *  More quiet mode.
 	 *  Filter out common, repetitive, warning-type errors...  like:
@@ -4627,6 +4690,7 @@
 	if (sk == SK_NO_SENSE) {
 		return 0;
 	}
+
 	if (	(sk==SK_UNIT_ATTENTION	&& asc==0x29 && (ascq==0x00 || ascq==0x01))
 	     || (sk==SK_NOT_READY	&& asc==0x04 && (ascq==0x01 || ascq==0x02))
 	     || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00)
@@ -4681,20 +4745,12 @@
 	else if (mpt_ScsiOpcodesPtr)
 		opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]];
 
-	l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n"
-	  "  SCSI_Status=%02Xh (%s)\n"
-	  "  Original_CDB[]:",
-			ioop->DevIDStr,
-			ioop->SCSIStatus,
-			statstr);
-	l += dump_cdb(foo+l, ioop->cdbPtr);
-	if (opstr)
-		l += sprintf(foo+l, " - \"%s\"", opstr);
-	l += sprintf(foo+l, "\n  SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr));
-	l += dump_sd(foo+l, ioop->sensePtr);
-	l += sprintf(foo+l, "\n  SenseKey=%Xh (%s); FRU=%02Xh\n  ASC/ASCQ=%02Xh/%02Xh",
-			sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
-
+	l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n",
+			  ioop->DevIDStr,
+			  ioop->SCSIStatus,
+			  statstr);
+	l += sprintf(foo+l, " Key=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh",
+		  sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq );
 	{
 		const char	*x1, *x2, *x3, *x4;
 		x1 = x2 = x3 = x4 = "";
@@ -4706,11 +4762,11 @@
 				l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4);
 		}
 	}
-
-#if 0
-	if (SPECIAL_ASCQ(asc,ascq))
-		l += sprintf(foo+l, " (%02Xh)", ascq);
-#endif
+	l += sprintf(foo+l, "\n CDB:");
+	l += dump_cdb(foo+l, ioop->cdbPtr);
+	if (opstr)
+		l += sprintf(foo+l, " - \"%s\"", opstr);
+	l += sprintf(foo+l, "\n");
 
 	PrintF(("%s\n", foo));
 
@@ -4953,6 +5009,7 @@
 	return;
 }
 
+#ifdef MPT_SAVE_AUTOSENSE
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Clear sense valid flag.
@@ -4968,6 +5025,7 @@
 
 	return;
 }
+#endif
 
 /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return.
  * Else set the NEED_DV flag after Read Capacity Issued (disks) 
@@ -5366,7 +5424,9 @@
 
 	/* If target struct exists, clear sense valid flag.
 	 */
+#ifdef MPT_SAVE_AUTOSENSE
 	clear_sense_flag(hd, pReq);
+#endif
 
 	if (mr == NULL) {
 		completionCode = MPT_SCANDV_GOOD;
@@ -5418,7 +5478,9 @@
 					completionCode = MPT_SCANDV_SOME_ERROR;
 
 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+#ifdef MPT_SAVE_AUTOSENSE
 				VirtDevice	*target;
+#endif
 				u8		*sense_data;
 				int		 sz;
 
@@ -5433,12 +5495,14 @@
 							SCSI_STD_SENSE_BYTES);
 				memcpy(hd->pLocal->sense, sense_data, sz);
 
+#ifdef MPT_SAVE_AUTOSENSE
 				target = hd->Targets[pReq->TargetID];
 				if (target) {
 					memcpy(target->sense, sense_data, sz);
 					target->tflags
 						|= MPT_TARGET_FLAGS_VALID_SENSE;
 				}
+#endif
 
 				ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
 						sense_data));
diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
--- a/drivers/message/fusion/mptscsih.h	Tue Oct 15 20:29:23 2002
+++ b/drivers/message/fusion/mptscsih.h	Tue Oct 15 20:29:23 2002
@@ -20,7 +20,7 @@
  *  (mailto:netscape.net)
  *  (mailto:Pam.Delaney@lsil.com)
  *
- *  $Id: mptscsih.h,v 1.18 2002/06/06 15:32:52 pdelaney Exp $
+ *  $Id: mptscsih.h,v 1.19 2002/10/03 13:10:15 pdelaney Exp $
  */
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
@@ -77,7 +77,22 @@
 #define MPT_SCSI_CAN_QUEUE	MPT_FC_CAN_QUEUE
 #define MPT_SCSI_CMD_PER_LUN	 7
 
+#define MPT_SCSI_MAX_SECTORS    8192
+
+/*
+ * Set the MAX_SGE value based on user input.
+ */
+#ifdef  CONFIG_FUSION_MAX_SGE
+#if     CONFIG_FUSION_MAX_SGE  < 16
+#define MPT_SCSI_SG_DEPTH	16
+#elif   CONFIG_FUSION_MAX_SGE  > 128
+#define MPT_SCSI_SG_DEPTH	128
+#else
+#define MPT_SCSI_SG_DEPTH	CONFIG_FUSION_MAX_SGE
+#endif
+#else
 #define MPT_SCSI_SG_DEPTH	40
+#endif
 
 /* To disable domain validation, uncomment the
  * following line. No effect for FC devices.
@@ -146,25 +161,39 @@
 /*
  *	tq_scheduler disappeared @ lk-2.4.0-test12
  *	(right when <linux/sched.h> newly defined TQ_ACTIVE)
+ *	tq_struct reworked in 2.5.41. Include workqueue.h.
  */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41)
+#	include <linux/sched.h>
+#	include <linux/workqueue.h>
+#define SCHEDULE_TASK(x)		\
+	if (schedule_work(x) == 0) {	\
+		/*MOD_DEC_USE_COUNT*/;	\
+	}
+#else
 #define HAVE_TQ_SCHED	1
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 #	include <linux/sched.h>
 #	ifdef TQ_ACTIVE
 #		undef HAVE_TQ_SCHED
 #	endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40)
+#		undef HAVE_TQ_SCHED
+#endif
 #endif
 #ifdef HAVE_TQ_SCHED
 #define SCHEDULE_TASK(x)		\
 	/*MOD_INC_USE_COUNT*/;		\
-	schedule_work(x)
+	(x)->next = NULL;		\
+	queue_task(x, &tq_scheduler)
 #else
 #define SCHEDULE_TASK(x)		\
 	/*MOD_INC_USE_COUNT*/;		\
-	if (schedule_work(x) == 0) {	\
+	if (schedule_task(x) == 0) {	\
 		/*MOD_DEC_USE_COUNT*/;	\
 	}
 #endif
+#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
@@ -236,6 +265,7 @@
 	can_queue:			MPT_SCSI_CAN_QUEUE,	\
 	this_id:			-1,			\
 	sg_tablesize:			MPT_SCSI_SG_DEPTH,	\
+	max_sectors:			MPT_SCSI_MAX_SECTORS,   \
 	cmd_per_lun:			MPT_SCSI_CMD_PER_LUN,	\
 	unchecked_isa_dma:		0,			\
 	use_clustering:			ENABLE_CLUSTERING,	\
diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
--- a/drivers/message/i2o/i2o_block.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/message/i2o/i2o_block.c	Tue Oct 15 20:29:19 2002
@@ -1647,7 +1647,7 @@
 	}
 
 	for (i = 0; i < MAX_I2OB; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(16);
 		if (!disk)
 			goto oom;
 		i2o_disk[i] = disk;
@@ -1679,7 +1679,6 @@
 		struct gendisk *disk = i2ob_disk + i;
 		disk->major = MAJOR_NR;
 		disk->first_minor = i<<4;
-		disk->minor_shift = 4;
 		disk->fops = &i2ob_fops;
 		sprintf(disk->disk_name, "i2o/hd%c", 'a' + i);
 	}
diff -Nru a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
--- a/drivers/message/i2o/i2o_scsi.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/message/i2o/i2o_scsi.c	Tue Oct 15 20:29:14 2002
@@ -9,10 +9,11 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
- * For the purpose of avoiding doubt the preferred form of the work
- * for making modifications shall be a standards compliant form such
- * gzipped tar and not one requiring a proprietary or patent encumbered
- * tool to unpack.
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
  *
  *  Complications for I2O scsi
  *
@@ -61,7 +62,7 @@
 #include "../../scsi/sd.h"
 #include "i2o_scsi.h"
 
-#define VERSION_STRING        "Version 0.1.0"
+#define VERSION_STRING        "Version 0.1.1"
 
 #define dprintk(x)
 
@@ -114,7 +115,10 @@
 static int sg_chain_tag = 0;
 static int sg_max_frags = SG_MAX_FRAGS;
 
-/*
+/**
+ *	i2o_retry_run		-	retry on timeout
+ *	@f: unused
+ *
  *	Retry congested frames. This actually needs pushing down into
  *	i2o core. We should only bother the OSM with this when we can't
  *	queue and retry the frame. Or perhaps we should call the OSM
@@ -134,6 +138,13 @@
 	spin_unlock_irqrestore(&retry_lock, flags);
 }
 
+/**
+ *	flush_pending		-	empty the retry queue
+ *
+ *	Turn each of the pending commands into a NOP and post it back
+ *	to the controller to clear it.
+ */
+ 
 static void flush_pending(void)
 {
 	int i;
@@ -150,6 +161,20 @@
 	spin_unlock_irqrestore(&retry_lock, flags);
 }
 
+/**
+ *	i2o_scsi_reply		-	scsi message reply processor
+ *	@h: our i2o handler
+ *	@c: controller issuing the reply
+ *	@msg: the message from the controller (mapped)
+ *
+ *	Process reply messages (interrupts in normal scsi controller think).
+ *	We can get a variety of messages to process. The normal path is
+ *	scsi command completions. We must also deal with IOP failures,
+ *	the reply to a bus reset and the reply to a LUN query.
+ *
+ *	Locks: the queue lock is taken to call the completion handler
+ */
+
 static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
 {
 	Scsi_Cmnd *current_command;
@@ -227,7 +252,7 @@
 	dprintk(("i2o got a scsi reply %08X: ", m[0]));
 	dprintk(("m[2]=%08X: ", m[2]));
 	dprintk(("m[4]=%08X\n", m[4]));
-
+ 
 	if(m[2]&0x80000000)
 	{
 		if(m[2]&0x40000000)
@@ -236,7 +261,7 @@
 			lun_done=1;
 			return;
 		}
-		printk(KERN_ERR "i2o_scsi: bus reset reply.\n");
+		printk(KERN_INFO "i2o_scsi: bus reset completed.\n");
 		return;
 	}
 	/*
@@ -313,6 +338,18 @@
 	I2O_CLASS_SCSI_PERIPHERAL
 };
 
+/**
+ *	i2o_find_lun		-	report the lun of an i2o device
+ *	@c: i2o controller owning the device
+ *	@d: i2o disk device
+ *	@target: filled in with target id
+ *	@lun: filled in with target lun
+ *
+ *	Query an I2O device to find out its SCSI lun and target numbering. We
+ *	don't currently handle some of the fancy SCSI-3 stuff although our
+ *	querying is sufficient to do so.
+ */
+ 
 static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun)
 {
 	u8 reply[8];
@@ -331,6 +368,19 @@
 	return 0;
 }
 
+/**
+ *	i2o_scsi_init		-	initialize an i2o device for scsi
+ *	@c: i2o controller owning the device
+ *	@d: scsi controller
+ *	@shpnt: scsi device we wish it to become
+ *
+ *	Enumerate the scsi peripheral/fibre channel peripheral class
+ *	devices that are children of the controller. From that we build
+ *	a translation map for the command queue code. Since I2O works on
+ *	its own tid's we effectively have to think backwards to get what
+ *	the midlayer wants
+ */
+ 
 static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
 {
 	struct i2o_device *unit;
@@ -391,6 +441,16 @@
 	}		
 }
 
+/**
+ *	i2o_scsi_detect		-	probe for I2O scsi devices
+ *	@tpnt: scsi layer template
+ *
+ *	I2O is a little odd here. The I2O core already knows what the
+ *	devices are. It also knows them by disk and tape as well as
+ *	by controller. We register each I2O scsi class object as a
+ *	scsi controller and then let the enumeration fake up the rest
+ */
+ 
 static int i2o_scsi_detect(Scsi_Host_Template * tpnt)
 {
 	unsigned long flags;
@@ -398,7 +458,7 @@
 	int i;
 	int count;
 
-	printk("i2o_scsi.c: %s\n", VERSION_STRING);
+	printk(KERN_INFO "i2o_scsi.c: %s\n", VERSION_STRING);
 
 	if(i2o_install_handler(&i2o_scsi_handler)<0)
 	{
@@ -409,14 +469,14 @@
 	
 	if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL)
 	{
-		printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ);
-		printk("i2o_scsi: SG chaining DISABLED!\n");
+		printk(KERN_INFO "i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ);
+		printk(KERN_INFO "i2o_scsi: SG chaining DISABLED!\n");
 		sg_max_frags = 11;
 	}
 	else
 	{
-		printk("  chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool);
-		printk("  (%d byte buffers X %d can_queue X %d i2o controllers)\n",
+		printk(KERN_INFO "  chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool);
+		printk(KERN_INFO "  (%d byte buffers X %d can_queue X %d i2o controllers)\n",
 				SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers);
 		sg_max_frags = SG_MAX_FRAGS;    // 64
 	}
@@ -456,14 +516,11 @@
 			shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host));
 			if(shpnt==NULL)
 				continue;
-			save_flags(flags);
-			cli();
 			shpnt->unique_id = (u32)d;
 			shpnt->io_port = 0;
 			shpnt->n_io_port = 0;
 			shpnt->irq = 0;
 			shpnt->this_id = /* Good question */15;
-			restore_flags(flags);
 			i2o_scsi_init(c, d, shpnt);
 			count++;
 		}
@@ -509,6 +566,20 @@
 	return(&hostdata->controller->name[0]);
 }
 
+/**
+ *	i2o_scsi_queuecommand	-	queue a SCSI command
+ *	@SCpnt: scsi command pointer
+ *	@done: callback for completion
+ *
+ *	Issue a scsi comamnd asynchronously. Return 0 on success or 1 if
+ *	we hit an error (normally message queue congestion). The only 
+ *	minor complication here is that I2O deals with the device addressing
+ *	so we have to map the bus/dev/lun back to an I2O handle as well
+ *	as faking absent devices ourself. 
+ *
+ *	Locks: takes the controller lock on error path only
+ */
+ 
 static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	int i;
@@ -525,6 +596,7 @@
 	u32 len;
 	u32 reqlen;
 	u32 tag;
+	unsigned long flags;
 	
 	static int max_qd = 1;
 	
@@ -560,24 +632,22 @@
 	if(tid == -1)
 	{
 		SCpnt->result = DID_NO_CONNECT << 16;
+		spin_lock_irqsave(host->host_lock, flags);
 		done(SCpnt);
+		spin_unlock_irqrestore(host->host_lock, flags);
 		return 0;
 	}
 	
 	dprintk(("Real scsi messages.\n"));
 
-	
 	/*
-	 *	Obtain an I2O message. Right now we _have_ to obtain one
-	 *	until the scsi layer stuff is cleaned up.
+	 *	Obtain an I2O message. If there are none free then 
+	 *	throw it back to the scsi layer
 	 */	
 	 
-	do
-	{
-		mb();
-		m = le32_to_cpu(I2O_POST_READ32(c));
-	}
-	while(m==0xFFFFFFFF);
+	m = le32_to_cpu(I2O_POST_READ32(c));
+	if(m==0xFFFFFFFF)
+		return 1;
 
 	msg = (u32 *)(c->mem_offset + m);
 	
@@ -603,7 +673,11 @@
 	{
 		/* Unknown - kill the command */
 		SCpnt->result = DID_NO_CONNECT << 16;
+		
+		/* We must lock the request queue while completing */
+		spin_lock_irqsave(host->host_lock, flags);
 		done(SCpnt);
+		spin_unlock_irqrestore(host->host_lock, flags);
 		return 0;
 	}
 	
@@ -772,11 +846,25 @@
 	return 0;
 }
 
+/**
+ *	internal_done	-	legacy scsi glue
+ *	@SCPnt: command
+ *
+ *	Completion function for a synchronous command
+ */
+
 static void internal_done(Scsi_Cmnd * SCpnt)
 {
 	SCpnt->SCp.Status++;
 }
 
+/**
+ *	i2o_scsi_command	-	issue a scsi command and wait
+ *	@SCPnt: command
+ *
+ *	Issue a SCSI command and wait for it to complete.
+ */
+ 
 static int i2o_scsi_command(Scsi_Cmnd * SCpnt)
 {
 	i2o_scsi_queuecommand(SCpnt, internal_done);
@@ -786,6 +874,17 @@
 	return SCpnt->result;
 }
 
+/**
+ *	i2o_scsi_abort	-	abort a running command
+ *	@SCpnt: command to abort
+ *
+ *	Ask the I2O controller to abort a command. This is an asynchrnous
+ *	process and oru callback handler will see the command complete
+ *	with an aborted message if it succeeds. 
+ *
+ *	Locks: no locks are held or needed
+ */
+ 
 int i2o_scsi_abort(Scsi_Cmnd * SCpnt)
 {
 	struct i2o_controller *c;
@@ -795,21 +894,24 @@
 	u32 m;
 	int tid;
 	
-	printk("i2o_scsi: Aborting command block.\n");
+	printk(KERN_WARNING "i2o_scsi: Aborting command block.\n");
 	
 	host = SCpnt->host;
 	hostdata = (struct i2o_scsi_host *)host->hostdata;
 	tid = hostdata->task[SCpnt->target][SCpnt->lun];
 	if(tid==-1)
 	{
-		printk(KERN_ERR "impossible command to abort.\n");
-		return SCSI_ABORT_NOT_RUNNING;
+		printk(KERN_ERR "i2o_scsi: Impossible command to abort!\n");
+		return FAILED;
 	}
 	c = hostdata->controller;
 	
 	/*
 	 *	Obtain an I2O message. Right now we _have_ to obtain one
 	 *	until the scsi layer stuff is cleaned up.
+	 *
+	 *	FIXME: we are in error context so we could sleep retry
+	 * 	a bit and then bail in the improved scsi layer.
 	 */	
 	 
 	do
@@ -828,10 +930,21 @@
 	wmb();
 	i2o_post_message(c,m);
 	wmb();
-	return SCSI_ABORT_PENDING;
+	return SUCCESS;
 }
 
-static int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+/**
+ *	i2o_scsi_bus_reset		-	Issue a SCSI reset
+ *	@SCpnt: the command that caused the reset
+ *
+ *	Perform a SCSI bus reset operation. In I2O this is just a message
+ *	we pass. I2O can do clever multi-initiator and shared reset stuff
+ *	but we don't support this.
+ *
+ *	Locks: called with no lock held, requires no locks.
+ */
+ 
+static int i2o_scsi_bus_reset(Scsi_Cmnd * SCpnt)
 {
 	int tid;
 	struct i2o_controller *c;
@@ -844,7 +957,7 @@
 	 *	Find the TID for the bus
 	 */
 
-	printk("i2o_scsi: Attempting to reset the bus.\n");
+	printk(KERN_WARNING "i2o_scsi: Attempting to reset the bus.\n");
 	
 	host = SCpnt->host;
 	hostdata = (struct i2o_scsi_host *)host->hostdata;
@@ -875,11 +988,43 @@
 	__raw_writel(c->unit << 16 | tid, msg+12);
 	wmb();
 	i2o_post_message(c,m);
-	return SCSI_RESET_PENDING;
+	return SUCCESS;
 }
 
-/*
- *	This is anyones guess quite frankly.
+/**
+ *	i2o_scsi_host_reset	-	host reset callback
+ *	@SCpnt: command causing the reset
+ *
+ *	An I2O controller can be many things at once. While we can
+ *	reset a controller the potential mess from doing so is vast, and
+ *	it's better to simply hold on and pray
+ */
+ 
+static int i2o_scsi_host_reset(Scsi_Cmnd * SCpnt)
+{
+	return FAILED;
+}
+
+/**
+ *	i2o_scsi_device_reset	-	device reset callback
+ *	@SCpnt: command causing the reset
+ *
+ *	I2O does not (AFAIK) support doing a device reset
+ */
+ 
+static int i2o_scsi_device_reset(Scsi_Cmnd * SCpnt)
+{
+	return FAILED;
+}
+
+/**
+ *	i2o_scsi_bios_param	-	Invent disk geometry
+ *	@disk: device 
+ *	@dev: block layer device
+ *	@ip: geometry array
+ *
+ *	This is anyones guess quite frankly. We use the same rules everyone 
+ *	else appears to and hope. It seems to work.
  */
  
 static int i2o_scsi_bios_param(Disk * disk, struct block_device *dev, int *ip)
diff -Nru a/drivers/message/i2o/i2o_scsi.h b/drivers/message/i2o/i2o_scsi.h
--- a/drivers/message/i2o/i2o_scsi.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/message/i2o/i2o_scsi.h	Tue Oct 15 20:29:16 2002
@@ -1,12 +1,6 @@
 #ifndef _I2O_SCSI_H
 #define _I2O_SCSI_H
 
-#if !defined(LINUX_VERSION_CODE)
-#include <linux/version.h>
-#endif
-
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 
@@ -19,28 +13,32 @@
 static int i2o_scsi_command(Scsi_Cmnd *);
 static int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int i2o_scsi_abort(Scsi_Cmnd *);
-static int i2o_scsi_reset(Scsi_Cmnd *, unsigned int);
+static int i2o_scsi_bus_reset(Scsi_Cmnd *);
+static int i2o_scsi_host_reset(Scsi_Cmnd *);
+static int i2o_scsi_device_reset(Scsi_Cmnd *);
 static int i2o_scsi_bios_param(Disk *, struct block_device *, int *);
 static int i2o_scsi_release(struct Scsi_Host *host);
 
-#define I2OSCSI {                                          \
-		  next: NULL,				    \
-                  proc_name:         "i2o_scsi",   \
-                  name:              "I2O SCSI Layer", 	    \
-                  detect:            i2o_scsi_detect,       \
-                  release:	     i2o_scsi_release,	    \
-                  info:              i2o_scsi_info,         \
-                  command:           i2o_scsi_command,      \
-                  queuecommand:      i2o_scsi_queuecommand, \
-                  abort:             i2o_scsi_abort,        \
-                  reset:             i2o_scsi_reset,        \
-                  bios_param:        i2o_scsi_bios_param,   \
-                  can_queue:         I2O_SCSI_CAN_QUEUE,    \
-                  this_id:           I2O_SCSI_ID,           \
-                  sg_tablesize:      8,                     \
-                  cmd_per_lun:       I2O_SCSI_CMD_PER_LUN,  \
-                  unchecked_isa_dma: 0,                     \
-                  use_clustering:    ENABLE_CLUSTERING     \
+#define I2OSCSI {                                       		\
+		  next: NULL,						\
+                  proc_name:         		"i2o_scsi",   		\
+                  name:              		"I2O SCSI Layer", 	\
+                  detect:            		i2o_scsi_detect,	\
+                  release:	     		i2o_scsi_release,	\
+                  info:              		i2o_scsi_info,		\
+                  command:           		i2o_scsi_command,	\
+                  queuecommand:      		i2o_scsi_queuecommand,	\
+                  eh_abort_handler:             i2o_scsi_abort,		\
+                  eh_bus_reset_handler:         i2o_scsi_bus_reset,	\
+                  eh_device_reset_handler:      i2o_scsi_device_reset,	\
+                  eh_host_reset_handler:	i2o_scsi_host_reset,	\
+  		  bios_param:        i2o_scsi_bios_param,   		\
+                  can_queue:         I2O_SCSI_CAN_QUEUE,    		\
+                  this_id:           I2O_SCSI_ID,           		\
+                  sg_tablesize:      8,                     		\
+                  cmd_per_lun:       I2O_SCSI_CMD_PER_LUN,  		\
+                  unchecked_isa_dma: 0,                     		\
+                  use_clustering:    ENABLE_CLUSTERING     		\
                   }
 
 #endif
diff -Nru a/drivers/mtd/Config.help b/drivers/mtd/Config.help
--- a/drivers/mtd/Config.help	Tue Oct 15 20:29:23 2002
+++ b/drivers/mtd/Config.help	Tue Oct 15 20:29:23 2002
@@ -21,36 +21,62 @@
   devices. Partitioning on NFTL 'devices' is a different - that's the
   'normal' form of partitioning used on a block device.
 
+CONFIG_MTD_CONCAT
+  Support for concatenating several MTD devices into a single
+  (virtual) one. This allows you to have -for example- a JFFS(2)
+  file system spanning multiple physical flash chips. If unsure,
+  say 'Y'.
+
 CONFIG_MTD_REDBOOT_PARTS
   RedBoot is a ROM monitor and bootloader which deals with multiple
-  'images' in flash devices by putting a table in the last erase block
-  of the device, similar to a partition table, which gives the
-  offsets, lengths and names of all the images stored in the flash.
+  'images' in flash devices by putting a table in the last erase
+  block of the device, similar to a partition table, which gives
+  the offsets, lengths and names of all the images stored in the
+  flash.
 
   If you need code which can detect and parse this table, and register
   MTD 'partitions' corresponding to each image in the table, enable
-  this option.
+  this option. 
 
   You will still need the parsing functions to be called by the driver
-  for your particular device. It won't happen automatically. The
-  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
+  for your particular device. It won't happen automatically. The 
+  SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
   example.
 
-CONFIG_MTD_BOOTLDR_PARTS
-  The Compaq bootldr deals with multiple 'images' in flash devices
-  by putting a table in one of the first erase blocks of the device,
-  similar to a partition table, which gives the offsets, lengths and
-  names of all the images stored in the flash.
-
-  If you need code which can detect and parse this table, and register
-  MTD 'partitions' corresponding to each image in the table, enable
-  this option.
-
+CONFIG_MTD_CMDLINE_PARTS
+  Allow generic configuration of the MTD paritition tables via the kernel
+  command line. Multiple flash resources are supported for hardware where
+  different kinds of flash memory are available. 
+  
   You will still need the parsing functions to be called by the driver
   for your particular device. It won't happen automatically. The 
   SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for 
   example.
 
+  The format for the command line is as follows:
+
+  mtdparts=<mtddef>[;<mtddef]
+  <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
+  <partdef> := <size>[@offset][<name>][ro]
+  <mtd-id>  := unique id used in mapping driver/device
+  <size>    := standard linux memsize OR "-" to denote all 
+               remaining space
+  <name>    := (NAME)
+
+  Due to the way Linux handles the command line, no spaces are 
+  allowed in the partition definition, including mtd id's and partition 
+  names.
+
+  Examples:
+
+  1 flash resource (mtd-id "sa1100"), with 1 single writable partition:
+  mtdparts=sa1100:-
+
+  Same flash, but 2 named partitions, the first one being read-only:
+  mtdparts=sa1100:256k(ARMboot)ro,-(root)
+
+  If unsure, say 'N'.
+
 CONFIG_MTD_AFS_PARTS
   The ARM Firmware Suite allows the user to divide flash devices into
   multiple 'images'. Each such image has a header containing its name
@@ -61,7 +87,7 @@
   enable this option.
 
   You will still need the parsing functions to be called by the driver
-  for your particular device.  It won't happen automatically.  The 
+  for your particular device. It won't happen automatically. The
   'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
 
 CONFIG_MTD_DEBUG_VERBOSE
diff -Nru a/drivers/mtd/Config.in b/drivers/mtd/Config.in
--- a/drivers/mtd/Config.in	Tue Oct 15 20:29:12 2002
+++ b/drivers/mtd/Config.in	Tue Oct 15 20:29:12 2002
@@ -1,5 +1,5 @@
 
-# $Id: Config.in,v 1.71 2001/10/03 11:38:38 dwmw2 Exp $
+# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $
 
 mainmenu_option next_comment
 comment 'Memory Technology Devices (MTD)'
@@ -12,9 +12,10 @@
       int '  Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0
    fi
    dep_tristate '  MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
+   dep_tristate '  MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD
    dep_tristate '  RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
+   dep_tristate '  Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS
    if [ "$CONFIG_ARM" = "y" ]; then
-      dep_tristate '  Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
       dep_tristate '  ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
    fi
 
diff -Nru a/drivers/mtd/Makefile b/drivers/mtd/Makefile
--- a/drivers/mtd/Makefile	Tue Oct 15 20:29:16 2002
+++ b/drivers/mtd/Makefile	Tue Oct 15 20:29:16 2002
@@ -1,12 +1,12 @@
 #
 # Makefile for the memory technology device drivers.
 #
-#
-# $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $
+# Based on:
+# $Id: Makefile,v 1.66 2002/04/23 13:52:14 mag Exp $
 
-export-objs	:= mtdcore.o mtdpart.o redboot.o bootldr.o afs.o
+export-objs	:= mtdcore.o mtdpart.o redboot.o cmdline.o afs.o mtdconcat.o
 
-obj-y           += chips/ maps/	devices/ nand/
+obj-y           += chips/ maps/ devices/ nand/
 
 #                       *** BIG UGLY NOTE ***
 #
@@ -26,9 +26,10 @@
 
 # Core functionality.
 obj-$(CONFIG_MTD)		+= mtdcore.o
+obj-$(CONFIG_MTD_CONCAT)	+= mtdconcat.o
 obj-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
-obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
+obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdline.o
 obj-$(CONFIG_MTD_AFS_PARTS)	+= afs.o
 
 # 'Users' - code which presents functionality to userspace.
diff -Nru a/drivers/mtd/afs.c b/drivers/mtd/afs.c
--- a/drivers/mtd/afs.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/mtd/afs.c	Tue Oct 15 20:29:21 2002
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: afs.c,v 1.6 2001/10/02 10:04:51 rmk Exp $
+   $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $
 
 ======================================================================*/
 
@@ -82,6 +82,12 @@
 	if (fs.signature != 0xa0ffff9f)
 		ret = 1;
 
+	/*
+	 * Don't touch the SIB.
+	 */
+	if (fs.type == 2)
+		ret = 1;
+
 	*iis_start = fs.image_info_base & mask;
 	*img_start = fs.image_start & mask;
 
@@ -163,6 +169,7 @@
 	if (!parts)
 		return -ENOMEM;
 
+	memset(parts, 0, sz);
 	str = (char *)(parts + idx);
 
 	/*
diff -Nru a/drivers/mtd/bootldr.c b/drivers/mtd/bootldr.c
--- a/drivers/mtd/bootldr.c	Tue Oct 15 20:29:21 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,214 +0,0 @@
-/*
- * Read flash partition table from Compaq Bootloader
- *
- * Copyright 2001 Compaq Computer Corporation.
- *
- * $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- */
-
-/*
- * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <asm/setup.h>
-#include <linux/bootmem.h>
-
-#define FLASH_PARTITION_NAMELEN 32
-enum LFR_FLAGS {
-   LFR_SIZE_PREFIX = 1,		/* prefix data with 4-byte size */
-   LFR_PATCH_BOOTLDR = 2,	/* patch bootloader's 0th instruction */
-   LFR_KERNEL = 4,		/* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
-   LFR_EXPAND = 8               /* expand partition size to fit rest of flash */
-};
-
-// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
-// for now
-#define MAX_NUM_PARTITIONS 8
-typedef struct FlashRegion {
-   char name[FLASH_PARTITION_NAMELEN];
-   unsigned long base;
-   unsigned long size;
-   enum LFR_FLAGS flags;
-} FlashRegion;
-
-typedef struct BootldrFlashPartitionTable {
-  int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
-  int npartitions;
-  struct FlashRegion partition[8];
-} BootldrFlashPartitionTable;
-
-#define BOOTLDR_MAGIC      0x646c7462        /* btld: marks a valid bootldr image */
-#define BOOTLDR_PARTITION_MAGIC  0x646c7470  /* btlp: marks a valid bootldr partition table in params sector */
-
-#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
-#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
-
-#define BOOTCAP_WAKEUP	(1<<0)
-#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
-#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
-
-static struct BootldrFlashPartitionTable Table;
-static struct BootldrFlashPartitionTable *partition_table = NULL;
-
-
-int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
-{
-	struct mtd_partition *parts;
-	int ret, retlen, i;
-	int npartitions = 0;
-	long partition_table_offset;
-	long bootmagic = 0;
-	long bootcap = 0;
-	int namelen = 0;
-
-	char *names; 
-
-#if 0
-	/* verify bootldr magic */
-	ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
-	if (ret) 
-		goto out;
-        if (bootmagic != BOOTLDR_MAGIC)
-                goto out;
-	/* see if bootldr supports partition tables and where to find the partition table */
-	ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
-	if (ret) 
-		goto out;
-
-	if (!(bootcap & BOOTCAP_PARTITIONS))
-		goto out;
-	if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
-		partition_table_offset = master->erasesize;
-	else
-		partition_table_offset = master->size - master->erasesize;
-
-	printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
-	printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);
-
-
-	/* Read the partition table */
-	partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!partition_table)
-		return -ENOMEM;
-
-	ret = master->read(master, partition_table_offset,
-			   PAGE_SIZE, &retlen, (void *)partition_table);
-	if (ret)
-	    goto out;
-
-#endif
-	if (!partition_table)
-	    return -ENOMEM;
-
-	
-	printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
-	printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);
-
-
-	/* check for partition table magic number */
-	if (partition_table->magic != BOOTLDR_PARTITION_MAGIC) 
-		goto out;
-	npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
-	    MAX_NUM_PARTITIONS:partition_table->npartitions;	
-
-	printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
-
-	for (i = 0; i < npartitions; i++) {
-		namelen += strlen(partition_table->partition[i].name) + 1;
-	}
-
-	parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
-	if (!parts) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	names = (char *)&parts[npartitions];
-	memset(parts, 0, sizeof(*parts)*npartitions + namelen);
-
-
-
-	// from here we use the partition table
-	for (i = 0; i < npartitions; i++) {
-                struct FlashRegion *partition = &partition_table->partition[i];
-		const char *name = partition->name;
-		parts[i].name = names;
-		names += strlen(name) + 1;
-		strcpy(parts[i].name, name);
-
-                if (partition->flags & LFR_EXPAND)
-                        parts[i].size = MTDPART_SIZ_FULL;
-                else
-                        parts[i].size = partition->size;
-		parts[i].offset = partition->base;
-		parts[i].mask_flags = 0;
-		
-		printk("        partition %s o=%x s=%x\n", 
-		       parts[i].name, parts[i].offset, parts[i].size);
-
-	}
-
-	ret = npartitions;
-	*pparts = parts;
-
- out:
-#if 0
-	if (partition_table)
-		kfree(partition_table);
-#endif
-	
-	return ret;
-}
-
-
-static int __init parse_tag_ptable(const struct tag *tag)
-{
-    char buf[128];
-    int i;
-    int j;
-    
-    partition_table = &Table;
-
-#ifdef CONFIG_DEBUG_LL    
-    sprintf(buf,"ptable: magic = = 0x%lx  npartitions= %d \n",
-	    tag->u.ptable.magic,tag->u.ptable.npartitions);
-    printascii(buf);
-    
-    for (i=0; i<tag->u.ptable.npartitions; i++){
-	sprintf(buf,"ptable: partition name = %s base= 0x%lx  size= 0x%lx flags= 0x%lx\n",
-	    (char *) (&tag->u.ptable.partition[i].name[0]),
-		tag->u.ptable.partition[i].base,
-		tag->u.ptable.partition[i].size,
-		tag->u.ptable.partition[i].flags);
-	printascii(buf);
-    }
-#endif
-
-    memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
-	sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
-
-    
-    return 0;
-}
-
-__tagtable(ATAG_PTABLE, parse_tag_ptable);
-
-EXPORT_SYMBOL(parse_bootldr_partitions);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
diff -Nru a/drivers/mtd/cmdline.c b/drivers/mtd/cmdline.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/cmdline.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,343 @@
+/*
+ * $Id: cmdline.c,v 1.4 2002/09/13 01:18:38 jamey Exp $
+ *
+ * Read flash partition table from command line
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * The format for the command line is as follows:
+ * 
+ * mtdparts=<mtddef>[;<mtddef]
+ * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
+ * <partdef> := <size>[@offset][<name>][ro]
+ * <mtd-id>  := unique id used in mapping driver/device
+ * <size>    := standard linux memsize OR "-" to denote all remaining space
+ * <name>    := '(' NAME ')'
+ * 
+ * Examples:
+ * 
+ * 1 NOR Flash, with 1 single writable partition:
+ * edb7312-nor:-
+ * 
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/setup.h>
+#include <linux/bootmem.h>
+
+/* error message prefix */
+#define ERRP "mtd: "
+
+/* debug macro */
+#if 0
+#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
+#else
+#define dbg(x)
+#endif
+
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xffffffff
+
+struct cmdline_mtd_partition {
+	struct cmdline_mtd_partition *next;
+	char *mtd_id;
+	int num_parts;
+	struct mtd_partition *parts;
+};
+
+/* mtdpart_setup() parses into here */
+static struct cmdline_mtd_partition *partitions;
+
+/* the command line passed to mtdpart_setupd() */
+static char *cmdline;
+static int cmdline_parsed = 0;
+
+/*
+ * Parse one partition definition for an MTD. Since there can be many
+ * comma separated partition definitions, this function calls itself 
+ * recursively until no more partition definitions are found. Nice side
+ * effect: the memory to keep the mtd_partition structs and the names
+ * is allocated upon the last definition being found. At that point the
+ * syntax has been verified ok.
+ */
+static struct mtd_partition * newpart(char *s, 
+                                      char **retptr,
+                                      int *num_parts,
+                                      int this_part, 
+                                      unsigned char **extra_mem_ptr, 
+                                      int extra_mem_size)
+{
+	struct mtd_partition *parts;
+	unsigned long size;
+	unsigned long offset = 0;
+	char *name;
+	int name_len;
+	unsigned char *extra_mem;
+	char delim;
+	unsigned int mask_flags;
+
+	/* fetch the partition size */
+	if (*s == '-')
+	{	/* assign all remaining space to this partition */
+		size = SIZE_REMAINING;
+		s++;
+	}
+	else
+	{
+		size = memparse(s, &s);
+		if (size < PAGE_SIZE)
+		{
+			printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
+			return 0;
+		}
+	}
+
+	/* fetch partition name and flags */
+	mask_flags = 0; /* this is going to be a regular partition */
+	delim = 0;
+        /* check for offset */
+        if (*s == '@') 
+	{
+           s++;
+           offset = memparse(s, &s);
+        }
+        /* now look for name */
+	if (*s == '(')
+	{
+		delim = ')';
+	}
+	if (delim)
+	{
+		char *p;
+
+	    	name = ++s;
+		if ((p = strchr(name, delim)) == 0)
+		{
+			printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
+			return 0;
+		}
+		name_len = p - name;
+		s = p + 1;
+	}
+	else
+	{
+	    	name = NULL;
+		name_len = 13; /* Partition_000 */
+	}
+   
+	/* record name length for memory allocation later */
+	extra_mem_size += name_len + 1;
+
+        /* test for options */
+        if (strncmp(s, "ro", 2) == 0) 
+	{
+		mask_flags |= MTD_WRITEABLE;
+		s += 2;
+        }
+
+	/* test if more partitions are following */
+	if (*s == ',')
+	{
+		if (size == SIZE_REMAINING)
+		{
+			printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
+			return 0;
+		}
+		/* more partitions follow, parse them */
+		if ((parts = newpart(s + 1, &s, num_parts, 
+		                     this_part + 1, &extra_mem, extra_mem_size)) == 0)
+		  return 0;
+	}
+	else
+	{	/* this is the last partition: allocate space for all */
+		int alloc_size;
+
+		*num_parts = this_part + 1;
+		alloc_size = *num_parts * sizeof(struct mtd_partition) +
+			     extra_mem_size;
+		parts = kmalloc(alloc_size, GFP_KERNEL);
+		if (!parts)
+		{
+			printk(KERN_ERR ERRP "out of memory\n");
+			return 0;
+		}
+		memset(parts, 0, alloc_size);
+		extra_mem = (unsigned char *)(parts + *num_parts);
+	}
+	/* enter this partition (offset will be calculated later if it is zero at this point) */
+	parts[this_part].size = size;
+	parts[this_part].offset = offset;
+	parts[this_part].mask_flags = mask_flags;
+	if (name)
+	{
+		strncpy(extra_mem, name, name_len);
+		extra_mem[name_len] = 0;
+	}
+	else
+	{
+		sprintf(extra_mem, "Partition_%03d", this_part);
+	}
+	parts[this_part].name = extra_mem;
+	extra_mem += name_len + 1;
+
+	dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+	     this_part, 
+	     parts[this_part].name,
+	     parts[this_part].offset,
+	     parts[this_part].size,
+	     parts[this_part].mask_flags));
+
+	/* return (updated) pointer to extra_mem memory */
+	if (extra_mem_ptr)
+	  *extra_mem_ptr = extra_mem;
+
+	/* return (updated) pointer command line string */
+	*retptr = s;
+
+	/* return partition table */
+	return parts;
+}
+
+/* 
+ * Parse the command line. 
+ */
+static int mtdpart_setup_real(char *s)
+{
+	cmdline_parsed = 1;
+
+	for( ; s != NULL; )
+	{
+		struct cmdline_mtd_partition *this_mtd;
+		struct mtd_partition *parts;
+	    	int mtd_id_len;
+		int num_parts;
+		char *p, *mtd_id;
+
+	    	mtd_id = s;
+		/* fetch <mtd-id> */
+		if (!(p = strchr(s, ':')))
+		{
+			printk(KERN_ERR ERRP "no mtd-id\n");
+			return 0;
+		}
+		mtd_id_len = p - mtd_id;
+
+		dbg(("parsing <%s>\n", p+1));
+
+		/* 
+		 * parse one mtd. have it reserve memory for the
+		 * struct cmdline_mtd_partition and the mtd-id string.
+		 */
+		parts = newpart(p + 1,		/* cmdline */
+				&s,		/* out: updated cmdline ptr */
+				&num_parts,	/* out: number of parts */
+				0,		/* first partition */
+				(unsigned char**)&this_mtd, /* out: extra mem */
+				mtd_id_len + 1 + sizeof(*this_mtd));
+
+		/* enter results */	    
+		this_mtd->parts = parts;
+		this_mtd->num_parts = num_parts;
+		this_mtd->mtd_id = (char*)(this_mtd + 1);
+		strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len);
+		this_mtd->mtd_id[mtd_id_len] = 0;
+
+		/* link into chain */
+		this_mtd->next = partitions;	    	
+		partitions = this_mtd;
+
+		dbg(("mtdid=<%s> num_parts=<%d>\n", 
+		     this_mtd->mtd_id, this_mtd->num_parts));
+		
+
+		/* EOS - we're done */
+		if (*s == 0)
+			break;
+
+		/* does another spec follow? */
+		if (*s != ';')
+		{
+			printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
+			return 0;
+		}
+		s++;
+	}
+	return 1;
+}
+
+/*
+ * Main function to be called from the MTD mapping driver/device to
+ * obtain the partitioning information. At this point the command line
+ * arguments will actually be parsed and turned to struct mtd_partition
+ * information.
+ */
+int parse_cmdline_partitions(struct mtd_info *master, 
+                             struct mtd_partition **pparts,
+                             const char *mtd_id)
+{
+	unsigned long offset;
+	int i;
+	struct cmdline_mtd_partition *part;
+
+	if (!cmdline)
+		return -EINVAL;
+
+	/* parse command line */
+	if (!cmdline_parsed)
+		mtdpart_setup_real(cmdline);
+
+	for(part = partitions; part; part = part->next)
+	{
+		if (!strcmp(part->mtd_id, mtd_id))
+		{
+			for(i = 0, offset = 0; i < part->num_parts; i++)
+			{
+				if (!part->parts[i].offset)
+				  part->parts[i].offset = offset;
+				else
+				  offset = part->parts[i].offset;
+				if (part->parts[i].size == SIZE_REMAINING)
+				  part->parts[i].size = master->size - offset;
+				if (offset + part->parts[i].size > master->size)
+				{
+					printk(KERN_WARNING ERRP 
+					       "%s: partitioning exceeds flash size, truncating\n",
+					       mtd_id);
+					part->parts[i].size = master->size - offset;
+					part->num_parts = i;
+				}
+				offset += part->parts[i].size;
+			}
+			*pparts = part->parts;
+			return part->num_parts;
+		}
+	}
+	return -EINVAL;
+}
+
+
+/* 
+ * This is the handler for our kernel parameter, called from 
+ * main.c::checksetup(). Note that we can not yet kmalloc() anything,
+ * so we only save the commandline for later processing.
+ */
+static int __init mtdpart_setup(char *s)
+{
+	cmdline = s;
+	return 1;
+}
+
+__setup("mtdparts=", mtdpart_setup);
+
+EXPORT_SYMBOL(parse_cmdline_partitions);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Command line configuration of MTD partitions");
diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
--- a/drivers/mtd/ftl.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/mtd/ftl.c	Tue Oct 15 20:29:15 2002
@@ -1223,7 +1223,7 @@
 	}
 
 	partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
-	disk = alloc_disk();
+	disk = alloc_disk(1 << PART_BITS);
 		
 	if (!partition||!disk) {
 		printk(KERN_WARNING "No memory to scan for FTL on %s\n",
@@ -1237,7 +1237,6 @@
 	sprintf(disk->disk_name, "ftl%c", 'a' + device);
 	disk->major = FTL_MAJOR;
 	disk->first_minor = device << 4;
-	disk->minor_shift = PART_BITS;
 	disk->fops = &ftl_blk_fops;
 	partition->mtd = mtd;
 	partition->disk = disk;
diff -Nru a/drivers/mtd/maps/Config.help b/drivers/mtd/maps/Config.help
--- a/drivers/mtd/maps/Config.help	Tue Oct 15 20:29:15 2002
+++ b/drivers/mtd/maps/Config.help	Tue Oct 15 20:29:15 2002
@@ -1,3 +1,32 @@
+CONFIG_MTD_CDB89712
+  This enables access to the flash or ROM chips on the CDB89712 board.
+  If you have such a board, say 'Y'.
+
+CONFIG_MTD_CEIVA
+  This enables access to the flash chips on the Ceiva/Polaroid
+  PhotoMax Digital Picture Frame.
+  If you have such a device, say 'Y'.
+
+CONFIG_MTD_FORTUNET
+  This enables access to the Flash on the FortuNet board.  If you
+  have such a board, say 'Y'.
+
+CONFIG_MTD_AUTCPU12
+  This enables access to the NV-RAM on autronix autcpu12 board.
+  If you have such a board, say 'Y'.
+
+CONFIG_MTD_EDB7312
+  This enables access to the CFI Flash on the Cogent EDB7312 board.
+  If you have such a board, say 'Y' here.
+
+CONFIG_MTD_NAND_EDB7312
+  This enables access to the NAND Flash on the Cogent EDB7312 board.
+  If you have such a board, say 'Y' here.
+
+CONFIG_MTD_IMPA7
+  This enables access to the NOR Flash on the impA7 board of
+  implementa GmbH. If you have such a board, say 'Y' here.
+
 CONFIG_MTD_SA1100
   This enables access to the flash chips on most platforms based on
   the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
@@ -39,6 +68,12 @@
 CONFIG_MTD_NORA
   If you had to ask, you don't have one. Say 'N'.
 
+CONFIG_MTD_L440GX
+  Support for treating the BIOS flash chip on Intel L440GX motherboards
+  as an MTD device - with this you can reprogram your BIOS.
+
+  BE VERY CAREFUL.
+
 CONFIG_MTD_PNC2000
   PNC-2000 is the name of Network Camera product from PHOTRON
   Ltd. in Japan. It uses CFI-compliant flash.
@@ -50,6 +85,13 @@
   to communicate with the chips on the RPXLite board. More at
   <http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>.
 
+CONFIG_MTD_TQM8XXL
+  The TQM8xxL PowerPC board has up to two banks of CFI-compliant
+  chips, currently uses AMD one. This 'mapping' driver supports
+  that arrangement, allowing the CFI probe and command set driver
+  code to communicate with the chips on the TQM8xxL board. More at
+  <http://www.denx.de/embedded-ppc-en.html>.
+
 CONFIG_MTD_SC520CDP
   The SC520 CDP board has two banks of CFI-compliant chips and one
   Dual-in-line JEDEC chip. This 'mapping' driver supports that
@@ -59,7 +101,7 @@
   This provides a driver for the on-board flash of Arcom Control
   Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX.
   By default the flash is split into 3 partitions which are accessed
-  as separate MTD devices.  This board utilizes Intel StrataFlash.
+  as separate MTD devices. This board utilizes Intel StrataFlash.
   More info at
   <http://www.arcomcontrols.com/products/icp/pc104/processors/>.
 
@@ -78,6 +120,11 @@
   demonstration board. If you have one of these boards and would like 
   to use the flash chips on it, say 'Y'.
 
+CONFIG_MTD_OCELOT
+  This enables access routines for the boot flash device and for the
+  NVRAM on the Momenco Ocelot board. If you have one of these boards
+  and would like access to either of these, say 'Y'.
+
 CONFIG_MTD_ELAN_104NC
   This provides a driver for the on-board flash of the Arcom Control
   System's ELAN-104NC development board. By default the flash
@@ -91,17 +138,17 @@
   <http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm>.
 
 CONFIG_MTD_CSTM_MIPS_IXX
-  This provides a mapping driver for the Integrated Tecnology Express,
-  Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference
-  Board.  It provides the necessary addressing, length, buswidth, vpp
-  code and addition setup of the flash device for these boards.  In
-  addition, this mapping driver can be used for other boards via
-  setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH
-  parameters.  This mapping will provide one mtd device using one
-  partition.  The start address can be offset from the beginning of
-  flash and the len can be less than the total flash device size to
-  allow a window into the flash.  Both CFI and JEDEC probes are
-  called.
+  This provides a mapping driver for the Integrated Tecnology
+  Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR
+  Reference Board. It provides the necessary addressing, length,
+  buswidth, vpp code and addition setup of the flash device for
+  these boards. In addition, this mapping driver can be used for
+  other boards via setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/
+  LEN/BUSWIDTH parameters. This mapping will provide one mtd device
+  using one partition. The start address can be offset from the
+  beginning of flash and the len can be less than the total flash
+  device size to allow a window into the flash. Both CFI and JEDEC
+  probes are called.
 
 CONFIG_MTD_CSTM_MIPS_IXX_START
   This is the physical memory location that the MTD driver will
@@ -141,6 +188,11 @@
   Computer. More information on the board is available at
   <http://www.octagonsystems.com/Products/5066/5066.html>.
 
+CONFIG_MTD_PCMCIA
+  Map driver for accessing PCMCIA linear flash memory cards. These
+  cards are usually around 4-16MiB in size. This does not include
+  Compact Flash cards which are treated as IDE devices.
+
 CONFIG_MTD_VMAX
   This provides a 'mapping' driver which supports the way in which
   the flash chips are connected in the Tempustech VMAX SBC301 Single
@@ -148,32 +200,21 @@
   <http://www.tempustech.com/tt301.htm>.
 
 CONFIG_MTD_CFI_FLAGADM
-  Mapping for the Flaga digital module.  If you don´t have one, ignore
+  Mapping for the Flaga digital module. If you don´t have one, ignore
   this setting.
 
-CONFIG_MTD_OCELOT
-  This enables access routines for the boot flash device and for the
-  NVRAM on the Momenco Ocelot board.  If you have one of these boards
-  and would like access to either of these, say 'Y'.
-
-CONFIG_MTD_CDB89712
-  This enables access to the flash or ROM chips on the CDB89712 board.
-  If you have such a board, say 'Y'.
-
-CONFIG_MTD_L440GX
-  Support for treating the BIOS flash chip on Intel L440GX motherboards
-  as an MTD device - with this you can reprogram your BIOS.
-
-  BE VERY CAREFUL.
-
 CONFIG_MTD_SOLUTIONENGINE
   This enables access to the flash chips on the Hitachi SolutionEngine and
   similar boards. Say 'Y' if you are building a kernel for such a board.
 
-CONFIG_MTD_TQM8XXL
-  The TQM8xxL PowerPC board has up to two banks of CFI-compliant
-  chips, currently uses AMD one. This 'mapping' driver supports
-  that arrangement, allowing the CFI probe and command set driver
-  code to communicate with the chips on the TQM8xxL board. More at
-  <http://www.denx.de/embedded-ppc-en.html>.
+CONFIG_MTD_EPXA10DB
+  This enables support for the flash devices on the Altera
+  Excalibur XA10 Development Board. If you are building a kernel
+  for on of these boards then you should say 'Y' otherwise say 'N'.
+
+CONFIG_MTD_PCI
+  Mapping for accessing flash devices on add-in cards like the Intel XScale
+  IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode
+  (please see the manual for the link settings).
 
+  If you are not sure, say N.
diff -Nru a/drivers/mtd/maps/Config.in b/drivers/mtd/maps/Config.in
--- a/drivers/mtd/maps/Config.in	Tue Oct 15 20:29:17 2002
+++ b/drivers/mtd/maps/Config.in	Tue Oct 15 20:29:17 2002
@@ -56,8 +56,18 @@
    dep_tristate '  CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI
    dep_tristate '  Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712
    dep_tristate '  CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
-   dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
+   dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE
    dep_tristate '  CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
+   dep_tristate '  CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI  $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
+   dep_tristate '  CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET
+   dep_tristate '  NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
+   dep_tristate '  CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI
+   dep_tristate '  JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE
+   dep_tristate '  JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE  $CONFIG_ARCH_CEIVA
 fi
+
+# This needs CFI or JEDEC, depending on the cards found.
+dep_tristate '  PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
+dep_tristate '  PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA
 
 endmenu
diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
--- a/drivers/mtd/maps/Makefile	Tue Oct 15 20:29:10 2002
+++ b/drivers/mtd/maps/Makefile	Tue Oct 15 20:29:10 2002
@@ -4,29 +4,37 @@
 # $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $
 
 # Chip mappings
-obj-$(CONFIG_MTD_CDB89712)      += cdb89712.o
+obj-$(CONFIG_MTD_CDB89712)	+= cdb89712.o
 obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
 obj-$(CONFIG_MTD_CFI_FLAGADM)	+= cfi_flagadm.o
-obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
-obj-$(CONFIG_MTD_DC21285)       += dc21285.o
-obj-$(CONFIG_MTD_ELAN_104NC)    += elan-104nc.o
+obj-$(CONFIG_MTD_CSTM_MIPS_IXX)	+= cstm_mips_ixx.o
+obj-$(CONFIG_MTD_DC21285)	+= dc21285.o
+obj-$(CONFIG_MTD_ELAN_104NC)	+= elan-104nc.o
+obj-$(CONFIG_MTD_EPXA10DB)	+= epxa10db-flash.o
 obj-$(CONFIG_MTD_IQ80310)	+= iq80310.o
 obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
 obj-$(CONFIG_MTD_NORA)		+= nora.o
+obj-$(CONFIG_MTD_CEIVA)		+= ceiva.o
 obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
 obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
 obj-$(CONFIG_MTD_PNC2000)	+= pnc2000.o
+obj-$(CONFIG_MTD_PCMCIA)	+= pcmciamtd.o
 obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
 obj-$(CONFIG_MTD_TQM8XXL)	+= tqm8xxl.o
-obj-$(CONFIG_MTD_SA1100)        += sa1100-flash.o
+obj-$(CONFIG_MTD_SA1100)	+= sa1100-flash.o
 obj-$(CONFIG_MTD_SBC_GXX)	+= sbc_gxx.o
 obj-$(CONFIG_MTD_SC520CDP)	+= sc520cdp.o
 obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
-obj-$(CONFIG_MTD_SUN_UFLASH)    += sun_uflash.o
+obj-$(CONFIG_MTD_SUN_UFLASH)	+= sun_uflash.o
 obj-$(CONFIG_MTD_VMAX)		+= vmax301.o
 obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)	+= ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
+obj-$(CONFIG_MTD_PCI)		+= pci.o
+obj-$(CONFIG_MTD_AUTCPU12)	+= autcpu12-nvram.o
+obj-$(CONFIG_MTD_EDB7312)	+= edb7312.o
+obj-$(CONFIG_MTD_IMPA7)		+= impa7.o
+obj-$(CONFIG_MTD_FORTUNET)	+= fortunet.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/autcpu12-nvram.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,179 @@
+/*
+ * NV-RAM memory access on autcpu12 
+ * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $ 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/hardware.h>
+#include <asm/arch/autcpu12.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+__u8 autcpu12_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 autcpu12_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 autcpu12_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	while(len) {
+		__raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
+		from++;
+		to++;
+		len--;
+	}
+}
+
+static struct mtd_info *sram_mtd;
+
+struct map_info autcpu12_sram_map = {
+	name: "SRAM",
+	size: 32768,
+	buswidth: 8,
+	read8: autcpu12_read8,
+	read16: autcpu12_read16,
+	read32: autcpu12_read32,
+	copy_from: autcpu12_copy_from,
+	write8: autcpu12_write8,
+	write16: autcpu12_write16,
+	write32: autcpu12_write32,
+	copy_to: autcpu12_copy_to
+};
+
+static int __init init_autcpu12_sram (void)
+{
+	int err, save0, save1;
+
+	autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K);
+	if (!autcpu12_sram_map.map_priv_1) {
+		printk("Failed to ioremap autcpu12 NV-RAM space\n");
+		err = -EIO;
+		goto out;
+	}
+	
+	/* 
+	 * Check for 32K/128K 
+	 * read ofs 0 
+	 * read ofs 0x10000 
+	 * Write complement to ofs 0x100000
+	 * Read	and check result on ofs 0x0
+	 * Restore contents
+	 */
+	save0 = autcpu12_read32(&autcpu12_sram_map,0);
+	save1 = autcpu12_read32(&autcpu12_sram_map,0x10000);
+	autcpu12_write32(&autcpu12_sram_map,~save0,0x10000);
+	/* if we find this pattern on 0x0, we have 32K size 
+	 * restore contents and exit
+	 */
+	if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) {
+		autcpu12_write32(&autcpu12_sram_map,save0,0x0);
+		goto map;
+	}
+	/* We have a 128K found, restore 0x10000 and set size
+	 * to 128K
+	 */
+	autcpu12_write32(&autcpu12_sram_map,save1,0x10000);
+	autcpu12_sram_map.size = SZ_128K;
+
+map:
+	sram_mtd = do_map_probe("map_ram", &autcpu12_sram_map);
+	if (!sram_mtd) {
+		printk("NV-RAM probe failed\n");
+		err = -ENXIO;
+		goto out_ioremap;
+	}
+
+	sram_mtd->module = THIS_MODULE;
+	sram_mtd->erasesize = 16;
+	
+	if (add_mtd_device(sram_mtd)) {
+		printk("NV-RAM device addition failed\n");
+		err = -ENOMEM;
+		goto out_probe;
+	}
+
+	printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
+		
+	return 0;
+
+out_probe:
+	map_destroy(sram_mtd);
+	sram_mtd = 0;
+
+out_ioremap:
+	iounmap((void *)autcpu12_sram_map.map_priv_1);
+out:
+	return err;
+}
+
+static void __exit cleanup_autcpu12_maps(void)
+{
+	if (sram_mtd) {
+		del_mtd_device(sram_mtd);
+		map_destroy(sram_mtd);
+		iounmap((void *)autcpu12_sram_map.map_priv_1);
+	}
+}
+
+module_init(init_autcpu12_sram);
+module_exit(cleanup_autcpu12_maps);
+
+MODULE_AUTHOR("Thomas Gleixner");
+MODULE_DESCRIPTION("autcpu12 NV-RAM map driver");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/ceiva.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,408 @@
+/*
+ * Ceiva flash memory driver.
+ * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
+ *
+ * Note: this driver supports jedec compatible devices. Modification
+ * for CFI compatible devices should be straight forward: change
+ * jedec_probe to cfi_probe.
+ *
+ * Based on: sa1100-flash.c, which has the following copyright:
+ * Flash memory access on SA11x0 based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_CEIVA_STATICMAP
+
+static __u8 clps_read8(struct map_info *map, unsigned long ofs)
+{
+	return readb(map->map_priv_1 + ofs);
+}
+
+static __u16 clps_read16(struct map_info *map, unsigned long ofs)
+{
+	return readw(map->map_priv_1 + ofs);
+}
+
+static __u32 clps_read32(struct map_info *map, unsigned long ofs)
+{
+	return readl(map->map_priv_1 + ofs);
+}
+
+static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void clps_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	writeb(d, map->map_priv_1 + adr);
+}
+
+static void clps_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	writew(d, map->map_priv_1 + adr);
+}
+
+static void clps_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	writel(d, map->map_priv_1 + adr);
+}
+
+static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+static struct map_info clps_map __initdata = {
+	name:		"clps flash",
+	read8:		clps_read8,
+	read16:		clps_read16,
+	read32:		clps_read32,
+	copy_from:	clps_copy_from,
+	write8:		clps_write8,
+	write16:	clps_write16,
+	write32:	clps_write32,
+	copy_to:	clps_copy_to,
+};
+
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+/*
+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
+ * structure.
+ *
+ * Please note:
+ *  1. The flash size given should be the largest flash size that can
+ *     be accomodated.
+ *
+ *  2. The bus width must defined in clps_setup_flash.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ */
+
+#ifdef CONFIG_ARCH_CEIVA
+/* Flash / Partition sizing */
+/* For the 28F8003, we use the block mapping to calcuate the sizes */
+#define MAX_SIZE_KiB                  (16 + 8 + 8 + 96 + (7*128))
+#define BOOT_PARTITION_SIZE_KiB       (16)
+#define PARAMS_PARTITION_SIZE_KiB     (8)
+#define KERNEL_PARTITION_SIZE_KiB     (4*128)
+/* Use both remaing portion of first flash, and all of second flash */
+#define ROOT_PARTITION_SIZE_KiB       (3*128) + (8*128)
+
+static struct mtd_partition ceiva_partitions[] = {
+	{
+		name: "Ceiva BOOT partition",
+		size:   BOOT_PARTITION_SIZE_KiB*1024,
+		offset: 0,
+
+	},{
+		name: "Ceiva parameters partition",
+		size:   PARAMS_PARTITION_SIZE_KiB*1024,
+		offset: (16 + 8) * 1024,
+	},{
+		name: "Ceiva kernel partition",
+		size: (KERNEL_PARTITION_SIZE_KiB)*1024,
+		offset: 0x20000,
+
+	},{
+		name: "Ceiva root filesystem partition",
+		offset: MTDPART_OFS_APPEND,
+		size: (ROOT_PARTITION_SIZE_KiB)*1024,
+	}
+};
+#endif
+
+static int __init clps_static_partitions(struct mtd_partition **parts)
+{
+	int nb_parts = 0;
+
+#ifdef CONFIG_ARCH_CEIVA
+	if (machine_is_ceiva()) {
+		*parts       = ceiva_partitions;
+		nb_parts     = ARRAY_SIZE(ceiva_partitions);
+	}
+#endif
+	return nb_parts;
+}
+#endif
+
+struct clps_info {
+	unsigned long base;
+	unsigned long size;
+	int width;
+	void *vbase;
+	struct map_info *map;
+	struct mtd_info *mtd;
+	struct resource *res;
+};
+
+#define NR_SUBMTD 4
+
+static struct clps_info info[NR_SUBMTD];
+
+static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd)
+{
+	struct mtd_info *subdev[nr];
+	struct map_info *maps;
+	int i, found = 0, ret = 0;
+
+	/*
+	 * Allocate the map_info structs in one go.
+	 */
+	maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+	if (!maps)
+		return -ENOMEM;
+
+	/*
+	 * Claim and then map the memory regions.
+	 */
+	for (i = 0; i < nr; i++) {
+		if (clps[i].base == (unsigned long)-1)
+			break;
+
+		clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash");
+		if (!clps[i].res) {
+			ret = -EBUSY;
+			break;
+		}
+
+		clps[i].map = maps + i;
+		memcpy(clps[i].map, &clps_map, sizeof(struct map_info));
+
+		clps[i].vbase = ioremap(clps[i].base, clps[i].size);
+		if (!clps[i].vbase) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase;
+		clps[i].map->buswidth = clps[i].width;
+		clps[i].map->size = clps[i].size;
+
+		clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
+		if (clps[i].mtd == NULL) {
+			ret = -ENXIO;
+			break;
+		}
+		clps[i].mtd->module = THIS_MODULE;
+		subdev[i] = clps[i].mtd;
+
+		printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
+			"%d-bit\n", clps[i].base, clps[i].mtd->size >> 20,
+			clps[i].width * 8);
+		found += 1;
+	}
+
+	/*
+	 * ENXIO is special.  It means we didn't find a chip when
+	 * we probed.  We need to tear down the mapping, free the
+	 * resource and mark it as such.
+	 */
+	if (ret == -ENXIO) {
+		iounmap(clps[i].vbase);
+		clps[i].vbase = NULL;
+		release_resource(clps[i].res);
+		clps[i].res = NULL;
+	}
+
+	/*
+	 * If we found one device, don't bother with concat support.
+	 * If we found multiple devices, use concat if we have it
+	 * available, otherwise fail.
+	 */
+	if (ret == 0 || ret == -ENXIO) {
+		if (found == 1) {
+			*rmtd = subdev[0];
+			ret = 0;
+		} else if (found > 1) {
+			/*
+			 * We detected multiple devices.  Concatenate
+			 * them together.
+			 */
+#ifdef CONFIG_MTD_CONCAT
+			*rmtd = mtd_concat_create(subdev, found,
+						  "clps flash");
+			if (*rmtd == NULL)
+				ret = -ENXIO;
+#else
+			printk(KERN_ERR "clps flash: multiple devices "
+			       "found but MTD concat support disabled.\n");
+			ret = -ENXIO;
+#endif
+		}
+	}
+
+	/*
+	 * If we failed, clean up.
+	 */
+	if (ret) {
+		do {
+			if (clps[i].mtd)
+				map_destroy(clps[i].mtd);
+			if (clps[i].vbase)
+				iounmap(clps[i].vbase);
+			if (clps[i].res)
+				release_resource(clps[i].res);
+		} while (i--);
+
+		kfree(maps);
+	}
+
+	return ret;
+}
+
+static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd)
+{
+	int i;
+
+	del_mtd_partitions(mtd);
+
+	if (mtd != clps[0].mtd)
+		mtd_concat_destroy(mtd);
+
+	for (i = NR_SUBMTD; i >= 0; i--) {
+		if (clps[i].mtd)
+			map_destroy(clps[i].mtd);
+		if (clps[i].vbase)
+			iounmap(clps[i].vbase);
+		if (clps[i].res)
+			release_resource(clps[i].res);
+	}
+	kfree(clps[0].map);
+}
+
+/*
+ * We define the memory space, size, and width for the flash memory
+ * space here.
+ */
+
+static int __init clps_setup_flash(void)
+{
+	int nr;
+
+#ifdef CONFIG_ARCH_CEIVA
+	if (machine_is_ceiva()) {
+		info[0].base = CS0_PHYS_BASE;
+		info[0].size = SZ_32M;
+		info[0].width = CEIVA_FLASH_WIDTH;
+		info[1].base = CS1_PHYS_BASE;
+		info[1].size = SZ_32M;
+		info[1].width = CEIVA_FLASH_WIDTH;
+		nr = 2;
+	}
+#endif
+	return nr;
+}
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+
+static struct mtd_partition *parsed_parts;
+
+static void __init clps_locate_partitions(struct mtd_info *mtd)
+{
+	const char *part_type = NULL;
+	int nr_parts = 0;
+	do {
+		/*
+		 * Partition selection stuff.
+		 */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps");
+		if (nr_parts > 0) {
+			part_type = "command line";
+			break;
+		}
+#endif
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+		nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "RedBoot";
+			break;
+		}
+#endif
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+		nr_parts = clps_static_partitions(&parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "static";
+			break;
+		}
+		printk("found: %d partitions\n", nr_parts);
+#endif
+	} while (0);
+
+	if (nr_parts == 0) {
+		printk(KERN_NOTICE "clps flash: no partition info "
+			"available, registering whole flash\n");
+		add_mtd_device(mtd);
+	} else {
+		printk(KERN_NOTICE "clps flash: using %s partition "
+			"definition\n", part_type);
+		add_mtd_partitions(mtd, parsed_parts, nr_parts);
+	}
+
+	/* Always succeeds. */
+}
+
+static void __exit clps_destroy_partitions(void)
+{
+	if (parsed_parts)
+		kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init clps_mtd_init(void)
+{
+	int ret;
+	int nr;
+
+	nr = clps_setup_flash();
+	if (nr < 0)
+		return nr;
+
+	ret = clps_setup_mtd(info, nr, &mymtd);
+	if (ret)
+		return ret;
+
+	clps_locate_partitions(mymtd);
+
+	return 0;
+}
+
+static void __exit clps_mtd_cleanup(void)
+{
+	clps_destroy_mtd(info, mymtd);
+	clps_destroy_partitions();
+}
+
+module_init(clps_mtd_init);
+module_exit(clps_mtd_cleanup);
+
+MODULE_AUTHOR("Rob Scott");
+MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c
--- a/drivers/mtd/maps/dc21285.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/mtd/maps/dc21285.c	Tue Oct 15 20:29:16 2002
@@ -5,9 +5,9 @@
  *
  * This code is GPL
  * 
- * $Id: dc21285.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $
  */
-
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -44,15 +44,15 @@
 
 void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
 {
-	*CSR_ROMWRITEREG = adr;
+	*CSR_ROMWRITEREG = adr & 3;
 	adr &= ~3;
 	*(__u8*)(map->map_priv_1 + adr) = d;
 }
 
 void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
 {
-	*CSR_ROMWRITEREG = adr;
-	adr &= ~1;
+	*CSR_ROMWRITEREG = adr & 3;
+	adr &= ~3;
 	*(__u16*)(map->map_priv_1 + adr) = d;
 }
 
@@ -131,7 +131,7 @@
 		dc21285_map.buswidth*8);
 
 	/* Let's map the flash area */
-	dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0);
+	dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
 	if (!dc21285_map.map_priv_1) {
 		printk("Failed to ioremap\n");
 		return -EIO;
@@ -139,20 +139,21 @@
 
 	mymtd = do_map_probe("cfi_probe", &dc21285_map);
 	if (mymtd) {
-		int nrparts;
+		int nrparts = 0;
 
 		mymtd->module = THIS_MODULE;
 			
 		/* partition fixup */
 
+#ifdef CONFIG_MTD_REDBOOT_PARTS
 		nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
-		if (nrparts <=0) {
+#endif
+		if (nrparts > 0) {
+			add_mtd_partitions(mymtd, dc21285_parts, nrparts);
+		} else if (nrparts == 0) {
 			printk(KERN_NOTICE "RedBoot partition table failed\n");
-			iounmap((void *)dc21285_map.map_priv_1);
-			return -ENXIO;
+			add_mtd_device(mymtd);
 		}
-
-		add_mtd_partitions(mymtd, dc21285_parts, nrparts);
 
 		/* 
 		 * Flash timing is determined with bits 19-16 of the
diff -Nru a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/edb7312.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,202 @@
+/*
+ * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on Cogent EDB7312 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR 0x00000000      /* physical properties of flash */
+#define WINDOW_SIZE 0x01000000
+#define BUSWIDTH    2
+#define FLASH_BLOCKSIZE_MAIN	0x20000
+#define FLASH_NUMBLOCKS_MAIN	128
+/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "cfi_probe", 0 }
+
+#define MSG_PREFIX "EDB7312-NOR:"   /* prefix for our printk()'s */
+#define MTDID      "edb7312-nor"    /* for mtdparts= partitioning */
+
+static struct mtd_info *mymtd;
+
+__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info edb7312nor_map = {
+	name: "NOR flash on EDB7312",
+	size: WINDOW_SIZE,
+	buswidth: BUSWIDTH,
+	read8: edb7312nor_read8,
+	read16: edb7312nor_read16,
+	read32: edb7312nor_read32,
+	copy_from: edb7312nor_copy_from,
+	write8: edb7312nor_write8,
+	write16: edb7312nor_write16,
+	write32: edb7312nor_write32,
+	copy_to: edb7312nor_copy_to
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff 
+ */
+static struct mtd_partition static_partitions[3] =
+{
+    {
+	name: "ARMboot",
+	  size: 0x40000,
+	  offset: 0
+    },
+    {
+	name: "Kernel",
+	  size: 0x200000,
+	  offset: 0x40000
+    },
+    {
+	name: "RootFS",
+	  size: 0xDC0000,
+	  offset: 0x240000
+    },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master, 
+			     struct mtd_partition **pparts,
+			     const char *mtd_id);
+#endif
+
+#endif
+
+static int                   mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts    = 0;
+
+int __init init_edb7312nor(void)
+{
+	static const char *rom_probe_types[] = PROBETYPES;
+	const char **type;
+	const char *part_type = 0;
+
+       	printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", 
+	       WINDOW_SIZE, WINDOW_ADDR);
+	edb7312nor_map.map_priv_1 = (unsigned long)
+	  ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+	if (!edb7312nor_map.map_priv_1) {
+		printk(MSG_PREFIX "failed to ioremap\n");
+		return -EIO;
+	}
+
+	mymtd = 0;
+	type = rom_probe_types;
+	for(; !mymtd && *type; type++) {
+		mymtd = do_map_probe(*type, &edb7312nor_map);
+	}
+	if (mymtd) {
+		mymtd->module = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID);
+		if (mtd_parts_nb > 0)
+		  part_type = "command line";
+#endif
+		if (mtd_parts_nb == 0)
+		{
+			mtd_parts = static_partitions;
+			mtd_parts_nb = NB_OF(static_partitions);
+			part_type = "static";
+		}
+#endif
+		add_mtd_device(mymtd);
+		if (mtd_parts_nb == 0)
+		  printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
+		else
+		{
+			printk(KERN_NOTICE MSG_PREFIX
+			       "using %s partition definition\n", part_type);
+			add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
+		}
+		return 0;
+	}
+
+	iounmap((void *)edb7312nor_map.map_priv_1);
+	return -ENXIO;
+}
+
+static void __exit cleanup_edb7312nor(void)
+{
+	if (mymtd) {
+		del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (edb7312nor_map.map_priv_1) {
+		iounmap((void *)edb7312nor_map.map_priv_1);
+		edb7312nor_map.map_priv_1 = 0;
+	}
+}
+
+module_init(init_edb7312nor);
+module_exit(cleanup_edb7312nor);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
diff -Nru a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/epxa10db-flash.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,233 @@
+/*
+ * Flash memory access on EPXA based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *  Copyright (C) 2001 Altera Corporation
+ *  Copyright (C) 2001 Red Hat, Inc.
+ *
+ * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $ 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+#ifdef CONFIG_EPXA10DB
+#define BOARD_NAME "EPXA10DB"
+#else
+#define BOARD_NAME "EPXA1DB"
+#endif
+
+static int nr_parts = 0;
+static struct mtd_partition *parts;
+
+static struct mtd_info *mymtd;
+
+extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
+static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+
+static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
+}
+
+
+
+static struct map_info epxa_map = {
+	name:		"EPXA flash",
+	size:		FLASH_SIZE,
+	buswidth:	2,
+	read8:		epxa_read8,
+	read16:		epxa_read16,
+	read32:		epxa_read32,
+	copy_from:	epxa_copy_from,
+	write8:		epxa_write8,
+	write16:	epxa_write16,
+	write32:	epxa_write32,
+	copy_to:	epxa_copy_to
+};
+
+
+static int __init epxa_mtd_init(void)
+{
+	int i;
+	
+	printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
+	epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+	if (!epxa_map.map_priv_1) {
+		printk("Failed to ioremap %s flash\n",BOARD_NAME);
+		return -EIO;
+	}
+
+	mymtd = do_map_probe("cfi_probe", &epxa_map);
+	if (!mymtd) {
+		iounmap((void *)epxa_map.map_priv_1);
+		return -ENXIO;
+	}
+
+	mymtd->module = THIS_MODULE;
+
+	/* Unlock the flash device. */
+	if(mymtd->unlock){
+		for (i=0; i<mymtd->numeraseregions;i++){
+			int j;
+			for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
+				mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize);
+			}
+		}
+	}
+
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+	nr_parts = parse_redboot_partitions(mymtd, &parts);
+
+	if (nr_parts > 0) {
+		add_mtd_partitions(mymtd, parts, nr_parts);
+		return 0;
+	}
+#endif
+#ifdef CONFIG_MTD_AFS_PARTS
+	nr_parts = parse_afs_partitions(mymtd, &parts);
+
+	if (nr_parts > 0) {
+		add_mtd_partitions(mymtd, parts, nr_parts);
+		return 0;
+	}
+#endif
+
+	/* No recognised partitioning schemes found - use defaults */
+	nr_parts = epxa_default_partitions(mymtd, &parts);
+	if (nr_parts > 0) {
+		add_mtd_partitions(mymtd, parts, nr_parts);
+		return 0;
+	}
+
+	/* If all else fails... */
+	add_mtd_device(mymtd);
+	return 0;
+}
+
+static void __exit epxa_mtd_cleanup(void)
+{
+	if (mymtd) {
+		if (nr_parts)
+			del_mtd_partitions(mymtd);
+		else
+			del_mtd_device(mymtd);
+		map_destroy(mymtd);
+	}
+	if (epxa_map.map_priv_1) {
+		iounmap((void *)epxa_map.map_priv_1);
+		epxa_map.map_priv_1 = 0;
+	}
+}
+
+
+/* 
+ * This will do for now, once we decide which bootldr we're finally 
+ * going to use then we'll remove this function and do it properly
+ *
+ * Partions are currently (as offsets from base of flash):
+ * 0x00000000 - 0x003FFFFF - bootloader (!)
+ * 0x00400000 - 0x00FFFFFF - Flashdisk
+ */
+
+static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+{
+	struct mtd_partition *parts;
+	int ret, i;
+	int npartitions = 0;
+	char *names; 
+	const char *name = "jffs";
+
+	printk("Using default partitions for %s\n",BOARD_NAME);
+	npartitions=1;
+	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
+	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
+	if (!parts) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	i=0;
+	names = (char *)&parts[npartitions];	
+	parts[i].name = names;
+	names += strlen(name) + 1;
+	strcpy(parts[i].name, name);
+
+#ifdef CONFIG_EPXA10DB
+	parts[i].size = FLASH_SIZE-0x00400000;
+	parts[i].offset = 0x00400000;
+#else
+	parts[i].size = FLASH_SIZE-0x00180000;
+	parts[i].offset = 0x00180000;
+#endif
+
+ out:
+	*pparts = parts;
+	return npartitions;
+}
+
+
+module_init(epxa_mtd_init);
+module_exit(epxa_mtd_cleanup);
+
+MODULE_AUTHOR("Clive Davies");
+MODULE_DESCRIPTION("Altera epxa mtd flash map");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/fortunet.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,309 @@
+/* fortunet.c memory map
+ *
+ * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define MAX_NUM_REGIONS		4
+#define MAX_NUM_PARTITIONS	8
+
+#define DEF_WINDOW_ADDR_PHY	0x00000000
+#define DEF_WINDOW_SIZE		0x00800000		// 8 Mega Bytes
+
+#define MTD_FORTUNET_PK		"MTD FortuNet: "
+
+#define MAX_NAME_SIZE		128
+
+struct map_region
+{
+	int			window_addr_phyical;
+	int			altbuswidth;
+	struct map_info		map_info;
+	struct mtd_info		*mymtd;
+	struct mtd_partition	parts[MAX_NUM_PARTITIONS];
+	char			map_name[MAX_NAME_SIZE];
+	char			parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
+};
+
+static struct map_region	map_regions[MAX_NUM_REGIONS];
+static int			map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
+static int			map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
+
+
+__u8 fortunet_read8(struct map_info *map, unsigned long ofs)
+{
+	return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 fortunet_read16(struct map_info *map, unsigned long ofs)
+{
+	return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 fortunet_read32(struct map_info *map, unsigned long ofs)
+{
+	return *(__u32 *)(map->map_priv_1 + ofs);
+}
+
+void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	*(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	*(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	*(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+struct map_info default_map = {
+	size: DEF_WINDOW_SIZE,
+	buswidth: 4,
+	read8: fortunet_read8,
+	read16: fortunet_read16,
+	read32: fortunet_read32,
+	copy_from: fortunet_copy_from,
+	write8: fortunet_write8,
+	write16: fortunet_write16,
+	write32: fortunet_write32,
+	copy_to: fortunet_copy_to
+};
+
+static char * __init get_string_option(char *dest,int dest_size,char *sor)
+{
+	if(!dest_size)
+		return sor;
+	dest_size--;
+	while(*sor)
+	{
+		if(*sor==',')
+		{
+			sor++;
+			break;
+		}
+		else if(*sor=='\"')
+		{
+			sor++;
+			while(*sor)
+			{
+				if(*sor=='\"')
+				{
+					sor++;
+					break;
+				}
+				*dest = *sor;
+				dest++;
+				sor++;
+				dest_size--;
+				if(!dest_size)
+				{
+					*dest = 0;
+					return sor;
+				}
+			}
+		}
+		else
+		{
+			*dest = *sor;
+			dest++;
+			sor++;
+			dest_size--;
+			if(!dest_size)
+			{
+				*dest = 0;
+				return sor;
+			}
+		}
+	}
+	*dest = 0;
+	return sor;
+}
+
+static int __init MTD_New_Region(char *line)
+{
+	char	string[MAX_NAME_SIZE];
+	int	params[6];
+	get_options (get_string_option(string,sizeof(string),line),6,params);
+	if(params[0]<1)
+	{
+		printk(MTD_FORTUNET_PK "Bad paramters for MTD Region "
+			" name,region-number[,base,size,buswidth,altbuswidth]\n");
+		return 1;
+	}
+	if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+	{
+		printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+			params[1],MAX_NUM_REGIONS-1);
+		return 1;
+	}
+	memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
+	memcpy(&map_regions[params[1]].map_info,
+		&default_map,sizeof(map_regions[params[1]].map_info));
+        map_regions_set[params[1]] = 1;
+        map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+        map_regions[params[1]].altbuswidth = 2;
+        map_regions[params[1]].mymtd = NULL;
+	map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
+	strcpy(map_regions[params[1]].map_info.name,string);
+	if(params[0]>1)
+	{
+		map_regions[params[1]].window_addr_phyical = params[2];
+	}
+	if(params[0]>2)
+	{
+		map_regions[params[1]].map_info.size = params[3];
+	}
+	if(params[0]>3)
+	{
+		map_regions[params[1]].map_info.buswidth = params[4];
+	}
+	if(params[0]>4)
+	{
+		map_regions[params[1]].altbuswidth = params[5];
+	}
+	return 1;
+}
+
+static int __init MTD_New_Partion(char *line)
+{
+	char	string[MAX_NAME_SIZE];
+	int	params[4];
+	get_options (get_string_option(string,sizeof(string),line),4,params);
+	if(params[0]<3)
+	{
+		printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion "
+			" name,region-number,size,offset\n");
+		return 1;
+	}
+	if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+	{
+		printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+			params[1],MAX_NUM_REGIONS-1);
+		return 1;
+	}
+	if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
+	{
+		printk(MTD_FORTUNET_PK "Out of space for partion in this region\n");
+		return 1;
+	}
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
+		map_regions[params[1]].	parts_name[map_regions_parts[params[1]]];
+	strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
+		params[2];
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
+		params[3];
+	map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
+	map_regions_parts[params[1]]++;
+	return 1;
+}
+
+__setup("MTD_Region=", MTD_New_Region);
+__setup("MTD_Partion=", MTD_New_Partion);
+
+int __init init_fortunet(void)
+{
+	int	ix,iy;
+	for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
+	{
+		if(map_regions_parts[ix]&&(!map_regions_set[ix]))
+		{
+			printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n",
+				ix);
+			memset(&map_regions[ix],0,sizeof(map_regions[ix]));
+			memcpy(&map_regions[ix].map_info,&default_map,
+				sizeof(map_regions[ix].map_info));
+			map_regions_set[ix] = 1;
+			map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+			map_regions[ix].altbuswidth = 2;
+			map_regions[ix].mymtd = NULL;
+			map_regions[ix].map_info.name = map_regions[ix].map_name;
+			strcpy(map_regions[ix].map_info.name,"FORTUNET");
+		}
+		if(map_regions_set[ix])
+		{
+			iy++;
+			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly "
+				" address %x size %x\n",
+				map_regions[ix].map_info.name,
+				map_regions[ix].window_addr_phyical,
+				map_regions[ix].map_info.size);
+			map_regions[ix].map_info.map_priv_1 =
+				(int)ioremap_nocache(
+				map_regions[ix].window_addr_phyical,
+				map_regions[ix].map_info.size);
+			if(!map_regions[ix].map_info.map_priv_1)
+			{
+				printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
+					map_regions[ix].map_info.name);
+				return -ENXIO;
+			}
+			printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n",
+				map_regions[ix].map_info.name,
+				map_regions[ix].map_info.map_priv_1);
+			map_regions[ix].mymtd = do_map_probe("cfi_probe",
+				&map_regions[ix].map_info);
+			if((!map_regions[ix].mymtd)&&(
+				map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
+			{
+				printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth "
+					"for %s flash.\n",
+					map_regions[ix].map_info.name);
+				map_regions[ix].map_info.buswidth =
+					map_regions[ix].altbuswidth;
+				map_regions[ix].mymtd = do_map_probe("cfi_probe",
+					&map_regions[ix].map_info);
+			}
+			map_regions[ix].mymtd->module = THIS_MODULE;
+			add_mtd_partitions(map_regions[ix].mymtd,
+				map_regions[ix].parts,map_regions_parts[ix]);
+		}
+	}
+	if(iy)
+		return 0;
+	return -ENXIO;
+}
+
+static void __exit cleanup_fortunet(void)
+{
+	int	ix;
+	for(ix=0;ix<MAX_NUM_REGIONS;ix++)
+	{
+		if(map_regions_set[ix])
+		{
+			if( map_regions[ix].mymtd )
+			{
+				del_mtd_partitions( map_regions[ix].mymtd );
+				map_destroy( map_regions[ix].mymtd );
+			}
+			iounmap((void *)map_regions[ix].map_info.map_priv_1);
+		}
+	}
+}
+
+module_init(init_fortunet);
+module_exit(cleanup_fortunet);
+
+MODULE_AUTHOR("FortuNet, Inc.");
+MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
diff -Nru a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/impa7.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,234 @@
+/*
+ * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on implementa A7 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR0 0x00000000      /* physical properties of flash */
+#define WINDOW_SIZE0 0x00800000
+#define WINDOW_ADDR1 0x10000000      /* physical properties of flash */
+#define WINDOW_SIZE1 0x00800000
+#define NUM_FLASHBANKS 2
+#define BUSWIDTH     4
+
+/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "jedec_probe", 0 }
+
+#define MSG_PREFIX "impA7:"   /* prefix for our printk()'s */
+#define MTDID      "impa7-%d"  /* for mtdparts= partitioning */
+
+static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
+
+__u8 impa7_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 impa7_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 impa7_read32(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void impa7_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+	__raw_writel(d, map->map_priv_1 + adr);
+	mb();
+}
+
+void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info impa7_map[NUM_FLASHBANKS] = {
+	{
+	name: "impA7 NOR Flash Bank #0",
+	size: WINDOW_SIZE0,
+	buswidth: BUSWIDTH,
+	read8: impa7_read8,
+	read16: impa7_read16,
+	read32: impa7_read32,
+	copy_from: impa7_copy_from,
+	write8: impa7_write8,
+	write16: impa7_write16,
+	write32: impa7_write32,
+	copy_to: impa7_copy_to
+	},
+	{
+	name: "impA7 NOR Flash Bank #1",
+	size: WINDOW_SIZE1,
+	buswidth: BUSWIDTH,
+	read8: impa7_read8,
+	read16: impa7_read16,
+	read32: impa7_read32,
+	copy_from: impa7_copy_from,
+	write8: impa7_write8,
+	write16: impa7_write16,
+	write32: impa7_write32,
+	copy_to: impa7_copy_to
+	},
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff 
+ */
+static struct mtd_partition static_partitions[] =
+{
+    {
+	name: "FileSystem",
+	  size: 0x800000,
+	  offset: 0x00000000
+    },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master, 
+			     struct mtd_partition **pparts,
+			     const char *mtd_id);
+#endif
+
+#endif
+
+static int                   mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts    = 0;
+
+int __init init_impa7(void)
+{
+	static const char *rom_probe_types[] = PROBETYPES;
+	const char **type;
+	const char *part_type = 0;
+	int i;
+	static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
+	  { WINDOW_ADDR0, WINDOW_SIZE0 },
+	  { WINDOW_ADDR1, WINDOW_SIZE1 },
+        };
+	char mtdid[10];
+	int devicesfound = 0;
+
+	for(i=0; i<NUM_FLASHBANKS; i++)
+	{
+		printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
+		       pt[i].size, pt[i].addr);
+		impa7_map[i].map_priv_1 = (unsigned long)
+		  ioremap(pt[i].addr, pt[i].size);
+
+		if (!impa7_map[i].map_priv_1) {
+			printk(MSG_PREFIX "failed to ioremap\n");
+			return -EIO;
+		}
+
+		impa7_mtd[i] = 0;
+		type = rom_probe_types;
+		for(; !impa7_mtd[i] && *type; type++) {
+			impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
+		}
+
+		if (impa7_mtd[i]) 
+		{
+			impa7_mtd[i]->module = THIS_MODULE;
+			add_mtd_device(impa7_mtd[i]);
+			devicesfound++;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+			sprintf(mtdid, MTDID, i);
+			mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i], 
+								&mtd_parts, 
+								mtdid);
+			if (mtd_parts_nb > 0)
+			  part_type = "command line";
+#endif
+			if (mtd_parts_nb <= 0)
+			{
+				mtd_parts = static_partitions;
+				mtd_parts_nb = NB_OF(static_partitions);
+				part_type = "static";
+			}
+			if (mtd_parts_nb <= 0)
+			{
+				printk(KERN_NOTICE MSG_PREFIX 
+				       "no partition info available\n");
+			}
+			else
+			{
+				printk(KERN_NOTICE MSG_PREFIX
+				       "using %s partition definition\n", 
+				       part_type);
+				add_mtd_partitions(impa7_mtd[i], 
+						   mtd_parts, mtd_parts_nb);
+			}
+#endif
+		}
+		else 
+		  iounmap((void *)impa7_map[i].map_priv_1);
+	}
+	return devicesfound == 0 ? -ENXIO : 0;
+}
+
+static void __exit cleanup_impa7(void)
+{
+	int i;
+	for (i=0; i<NUM_FLASHBANKS; i++) 
+	{
+		if (impa7_mtd[i]) 
+		{
+			del_mtd_device(impa7_mtd[i]);
+			map_destroy(impa7_mtd[i]);
+		}
+		if (impa7_map[i].map_priv_1)
+		{
+			iounmap((void *)impa7_map[i].map_priv_1);
+			impa7_map[i].map_priv_1 = 0;
+		}
+	}
+}
+
+module_init(init_impa7);
+module_exit(cleanup_impa7);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pavel Bartusek <pba@sysgo.de>");
+MODULE_DESCRIPTION("MTD map driver for implementa impA7");
diff -Nru a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c
--- a/drivers/mtd/maps/integrator-flash.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/mtd/maps/integrator-flash.c	Tue Oct 15 20:29:20 2002
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: integrator-flash.c,v 1.6 2001/10/02 16:00:01 dwmw2 Exp $
+   $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $
 
 ======================================================================*/
 
@@ -208,10 +208,10 @@
 };
 
 static struct mtd_info *mtd;
+static struct mtd_partition *parts;
 
 static int __init armflash_cfi_init(void *base, u_int size)
 {
-	struct mtd_partition *parts;
 	int ret;
 
 	armflash_flash_init();
@@ -238,8 +238,6 @@
 	ret = parse_afs_partitions(mtd, &parts);
 	if (ret > 0) {
 		ret = add_mtd_partitions(mtd, parts, ret);
-		/* we don't need the partition info any longer */
-		kfree(parts);
 		if (ret)
 			printk(KERN_ERR "mtd partition registration "
 				"failed: %d\n", ret);
@@ -262,6 +260,8 @@
 		del_mtd_partitions(mtd);
 		map_destroy(mtd);
 	}
+	if (parts)
+		kfree(parts);
 }
 
 static int __init armflash_init(void)
diff -Nru a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c
--- a/drivers/mtd/maps/iq80310.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/mtd/maps/iq80310.c	Tue Oct 15 20:29:16 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: iq80310.c,v 1.8 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $
  *
  * Mapping for the Intel XScale IQ80310 evaluation board
  *
@@ -116,7 +116,7 @@
 	int parsed_nr_parts = 0;
 	char *part_type = "static";
 
-	iq80310_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
+	iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
 	if (!iq80310_map.map_priv_1) {
 		printk("Failed to ioremap\n");
 		return -EIO;
@@ -161,7 +161,6 @@
 	}
 	if (iq80310_map.map_priv_1)
 		iounmap((void *)iq80310_map.map_priv_1);
-	return 0;
 }
 
 module_init(init_iq80310);
diff -Nru a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/pci.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,385 @@
+/*
+ *  linux/drivers/mtd/maps/pci.c
+ *
+ *  Copyright (C) 2001 Russell King, All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $
+ * 
+ * Generic PCI memory map driver.  We support the following boards:
+ *  - Intel IQ80310 ATU.
+ *  - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+struct map_pci_info;
+
+struct mtd_pci_info {
+	int  (*init)(struct pci_dev *dev, struct map_pci_info *map);
+	void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
+	unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
+	const char *map_name;
+};
+
+struct map_pci_info {
+	struct map_info map;
+	void *base;
+	void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
+	unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
+	struct pci_dev *dev;
+};	
+
+/*
+ * Intel IOP80310 Flash driver
+ */
+
+static int
+intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map)
+{
+	u32 win_base;
+
+	map->map.buswidth = 1;
+	map->map.size     = 0x00800000;
+	map->base         = ioremap_nocache(pci_resource_start(dev, 0),
+					    pci_resource_len(dev, 0));
+
+	if (!map->base)
+		return -ENOMEM;
+
+	/*
+	 * We want to base the memory window at Xscale
+	 * bus address 0, not 0x1000.
+	 */
+	pci_read_config_dword(dev, 0x44, &win_base);
+	pci_write_config_dword(dev, 0x44, 0);
+
+	map->map.map_priv_2 = win_base;
+
+	return 0;
+}
+
+static void
+intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map)
+{
+	if (map->base)
+		iounmap((void *)map->base);
+	pci_write_config_dword(dev, 0x44, map->map.map_priv_2);
+}
+
+static unsigned long
+intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs)
+{
+	unsigned long page_addr = ofs & 0x00400000;
+
+	/*
+	 * This mundges the flash location so we avoid
+	 * the first 80 bytes (they appear to read nonsense).
+	 */
+	if (page_addr) {
+		writel(0x00000008, map->base + 0x1558);
+		writel(0x00000000, map->base + 0x1550);
+	} else {
+		writel(0x00000007, map->base + 0x1558);
+		writel(0x00800000, map->base + 0x1550);
+		ofs += 0x00800000;
+	}
+
+	return ofs;
+}
+
+static struct mtd_pci_info intel_iq80310_info = {
+	init:		intel_iq80310_init,
+	exit:		intel_iq80310_exit,
+	translate:	intel_iq80310_translate,
+	map_name:	"cfi_probe",
+};
+
+/*
+ * Intel DC21285 driver
+ */
+
+static int
+intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)
+{
+	unsigned long base, len;
+
+	base = pci_resource_start(dev, PCI_ROM_RESOURCE);
+	len  = pci_resource_len(dev, PCI_ROM_RESOURCE);
+
+	if (!len || !base) {
+		/*
+		 * No ROM resource
+		 */
+		base = pci_resource_start(dev, 2);
+		len  = pci_resource_len(dev, 2);
+
+		/*
+		 * We need to re-allocate PCI BAR2 address range to the
+		 * PCI ROM BAR, and disable PCI BAR2.
+		 */
+	} else {
+		/*
+		 * Hmm, if an address was allocated to the ROM resource, but
+		 * not enabled, should we be allocating a new resource for it
+		 * or simply enabling it?
+		 */
+		if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) &
+		     PCI_ROM_ADDRESS_ENABLE)) {
+		     	u32 val;
+			pci_resource_flags(dev, PCI_ROM_RESOURCE) |= PCI_ROM_ADDRESS_ENABLE;
+			pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
+			val |= PCI_ROM_ADDRESS_ENABLE;
+			pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+			printk("%s: enabling expansion ROM\n", dev->slot_name);
+		}
+	}
+
+	if (!len || !base)
+		return -ENXIO;
+
+	map->map.buswidth = 4;
+	map->map.size     = len;
+	map->base         = ioremap_nocache(base, len);
+
+	if (!map->base)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void
+intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map)
+{
+	u32 val;
+
+	if (map->base)
+		iounmap((void *)map->base);
+
+	/*
+	 * We need to undo the PCI BAR2/PCI ROM BAR address alteration.
+	 */
+	pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
+	val &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+}
+
+static unsigned long
+intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs)
+{
+	return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5));
+}
+
+static struct mtd_pci_info intel_dc21285_info = {
+	init:		intel_dc21285_init,
+	exit:		intel_dc21285_exit,
+	translate:	intel_dc21285_translate,
+	map_name:	"jedec_probe",
+};
+
+/*
+ * PCI device ID table
+ */
+
+static struct pci_device_id mtd_pci_ids[] __devinitdata = {
+	{
+		vendor:		PCI_VENDOR_ID_INTEL,
+		device:		0x530d,
+		subvendor:	PCI_ANY_ID,
+		subdevice:	PCI_ANY_ID,
+		class:		PCI_CLASS_MEMORY_OTHER << 8,
+		class_mask:	0xffff00,
+		driver_data:	(unsigned long)&intel_iq80310_info,
+	},
+	{
+		vendor:		PCI_VENDOR_ID_DEC,
+		device:		PCI_DEVICE_ID_DEC_21285,
+		subvendor:	0,	/* DC21285 defaults to 0 on reset */
+		subdevice:	0,	/* DC21285 defaults to 0 on reset */
+		class:		0,
+		class_mask:	0,
+		driver_data:	(unsigned long)&intel_dc21285_info,
+	},
+	{ 0, }
+};
+
+/*
+ * Generic code follows.
+ */
+
+static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	u8 val = readb(map->base + map->translate(map, ofs));
+//	printk("read8 : %08lx => %02x\n", ofs, val);
+	return val;
+}
+
+static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	u16 val = readw(map->base + map->translate(map, ofs));
+//	printk("read16: %08lx => %04x\n", ofs, val);
+	return val;
+}
+
+static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	u32 val = readl(map->base + map->translate(map, ofs));
+//	printk("read32: %08lx => %08x\n", ofs, val);
+	return val;
+}
+
+static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	memcpy_fromio(to, map->base + map->translate(map, from), len);
+}
+
+static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+//	printk("write8 : %08lx <= %02x\n", ofs, val);
+	writeb(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+//	printk("write16: %08lx <= %04x\n", ofs, val);
+	writew(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+//	printk("write32: %08lx <= %08x\n", ofs, val);
+	writel(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
+{
+	struct map_pci_info *map = (struct map_pci_info *)_map;
+	memcpy_toio(map->base + map->translate(map, to), from, len);
+}
+
+static struct map_info mtd_pci_map = {
+	read8:		mtd_pci_read8,
+	read16:		mtd_pci_read16,
+	read32:		mtd_pci_read32,
+	copy_from:	mtd_pci_copyfrom,
+	write8:		mtd_pci_write8,
+	write16:	mtd_pci_write16,
+	write32:	mtd_pci_write32,
+	copy_to:	mtd_pci_copyto,
+};
+
+static int __devinit
+mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
+	struct map_pci_info *map = NULL;
+	struct mtd_info *mtd = NULL;
+	int err;
+
+	err = pci_enable_device(dev);
+	if (err)
+		goto out;
+
+	err = pci_request_regions(dev, "pci mtd");
+	if (err)
+		goto out;
+
+	map = kmalloc(sizeof(*map), GFP_KERNEL);
+	err = -ENOMEM;
+	if (!map)
+		goto release;
+
+	map->map       = mtd_pci_map;
+	map->map.name  = dev->slot_name;
+	map->dev       = dev;
+	map->exit      = info->exit;
+	map->translate = info->translate;
+
+	err = info->init(dev, map);
+	if (err)
+		goto release;
+
+	/* tsk - do_map_probe should take const char * */
+	mtd = do_map_probe((char *)info->map_name, &map->map);
+	err = -ENODEV;
+	if (!mtd)
+		goto release;
+
+	mtd->module = THIS_MODULE;
+	add_mtd_device(mtd);
+
+	pci_set_drvdata(dev, mtd);
+
+	return 0;
+
+release:
+	if (mtd)
+		map_destroy(mtd);
+
+	if (map) {
+		map->exit(dev, map);
+		kfree(map);
+	}
+
+	pci_release_regions(dev);
+out:
+	return err;
+}
+
+static void __devexit
+mtd_pci_remove(struct pci_dev *dev)
+{
+	struct mtd_info *mtd = pci_get_drvdata(dev);
+	struct map_pci_info *map = mtd->priv;
+
+	del_mtd_device(mtd);
+	map_destroy(mtd);
+	map->exit(dev, map);
+	kfree(map);
+
+	pci_set_drvdata(dev, NULL);
+	pci_release_regions(dev);
+}
+
+static struct pci_driver mtd_pci_driver = {
+	name:		"MTD PCI",
+	probe:		mtd_pci_probe,
+	remove:		mtd_pci_remove,
+	id_table:	mtd_pci_ids,
+};
+
+static int __init mtd_pci_maps_init(void)
+{
+	return pci_module_init(&mtd_pci_driver);
+}
+
+static void __exit mtd_pci_maps_exit(void)
+{
+	pci_unregister_driver(&mtd_pci_driver);
+}
+
+module_init(mtd_pci_maps_init);
+module_exit(mtd_pci_maps_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Generic PCI map driver");
+MODULE_DEVICE_TABLE(pci, mtd_pci_ids);
+
diff -Nru a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/maps/pcmciamtd.c	Tue Oct 15 20:29:24 2002
@@ -0,0 +1,893 @@
+/*
+ * $Id: pcmciamtd.c,v 1.36 2002/10/14 18:49:12 rmk Exp $
+ *
+ * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_DEBUG
+static int debug = CONFIG_MTD_DEBUG_VERBOSE;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
+#undef DEBUG
+#define DEBUG(n, format, arg...) \
+	if (n <= debug) {	 \
+		printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+	}
+
+#else
+#undef DEBUG
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
+
+
+#define DRIVER_DESC	"PCMCIA Flash memory card driver"
+#define DRIVER_VERSION	"$Revision: 1.36 $"
+
+/* Size of the PCMCIA address space: 26 bits = 64 MB */
+#define MAX_PCMCIA_ADDR	0x4000000
+
+struct pcmciamtd_dev {
+	struct list_head list;
+	dev_link_t	link;		/* PCMCIA link */
+	caddr_t		win_base;	/* ioremapped address of PCMCIA window */
+	unsigned int	win_size;	/* size of window */
+	unsigned int	cardsize;	/* size of whole card */
+	unsigned int	offset;		/* offset into card the window currently points at */
+	struct map_info	pcmcia_map;
+	struct mtd_info	*mtd_info;
+	u8		vpp;
+	char		mtd_name[sizeof(struct cistpl_vers_1_t)];
+};
+
+
+static dev_info_t dev_info = "pcmciamtd";
+static LIST_HEAD(dev_list);
+
+/* Module parameters */
+
+/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
+static int buswidth = 2;
+
+/* Speed of memory accesses, in ns */
+static int mem_speed;
+
+/* Force the size of an SRAM card */
+static int force_size;
+
+/* Force Vpp */
+static int vpp;
+
+/* Set Vpp */
+static int setvpp;
+
+/* Force card to be treated as FLASH, ROM or RAM */
+static int mem_type;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(buswidth, "i");
+MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
+MODULE_PARM(force_size, "i");
+MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)");
+MODULE_PARM(setvpp, "i");
+MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
+MODULE_PARM(vpp, "i");
+MODULE_PARM_DESC(vpp, "Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous)");
+MODULE_PARM(mem_type, "i");
+MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)");
+
+
+
+static void inline cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */
+
+static caddr_t remap_window(struct map_info *map, unsigned long to)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	window_handle_t win = (window_handle_t)map->map_priv_2;
+	memreq_t mrq;
+	int ret;
+
+	mrq.CardOffset = to & ~(dev->win_size-1);
+	if(mrq.CardOffset != dev->offset) {
+		DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
+		      dev->offset, mrq.CardOffset);
+		mrq.Page = 0;
+		if( (ret = CardServices(MapMemPage, win, &mrq)) != CS_SUCCESS) {
+			cs_error(dev->link.handle, MapMemPage, ret);
+			return NULL;
+		}
+		dev->offset = mrq.CardOffset;
+	}
+	return dev->win_base + (to & (dev->win_size-1));
+}
+
+
+static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
+{
+	caddr_t addr;
+	u8 d;
+
+	addr = remap_window(map, ofs);
+	if(!addr)
+		return 0;
+
+	d = readb(addr);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d);
+	return d;
+}
+
+
+static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
+{
+	caddr_t addr;
+	u16 d;
+
+	addr = remap_window(map, ofs);
+	if(!addr)
+		return 0;
+
+	d = readw(addr);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d);
+	return d;
+}
+
+
+static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	unsigned long win_size = dev->win_size;
+
+	DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+	while(len) {
+		int toread = win_size - (from & (win_size-1));
+		caddr_t addr;
+
+		if(toread > len)
+			toread = len;
+		
+		addr = remap_window(map, from);
+		if(!addr)
+			return;
+
+		DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread);
+		memcpy_fromio(to, addr, toread);
+		len -= toread;
+		to += toread;
+		from += toread;
+	}
+}
+
+
+static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr)
+{
+	caddr_t addr = remap_window(map, adr);
+
+	if(!addr)
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02x", adr, addr, d);
+	writeb(d, addr);
+}
+
+
+static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr)
+{
+	caddr_t addr = remap_window(map, adr);
+	if(!addr)
+		return;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04x", adr, addr, d);
+	writew(d, addr);
+}
+
+
+static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	unsigned long win_size = dev->win_size;
+
+	DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+	while(len) {
+		int towrite = win_size - (to & (win_size-1));
+		caddr_t addr;
+
+		if(towrite > len)
+			towrite = len;
+
+		addr = remap_window(map, to);
+		if(!addr)
+			return;
+
+		DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite);
+		memcpy_toio(addr, from, towrite);
+		len -= towrite;
+		to += towrite;
+		from += towrite;
+	}
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with direct access */
+
+static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+	u8 d;
+
+	d = readb(win_base + ofs);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
+	return d;
+}
+
+
+static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+	u16 d;
+
+	d = readw(win_base + ofs);
+	DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
+	return d;
+}
+
+
+static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+	memcpy_fromio(to, win_base + from, len);
+}
+
+
+static void pcmcia_write8(struct map_info *map, u8 d, unsigned long adr)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%02x", adr, win_base + adr, d);
+	writeb(d, win_base + adr);
+}
+
+
+static void pcmcia_write16(struct map_info *map, u16 d, unsigned long adr)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	DEBUG(3, "adr = 0x%08lx (%p)  data = 0x%04x", adr, win_base + adr, d);
+	writew(d, win_base + adr);
+}
+
+
+static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	caddr_t win_base = (caddr_t)map->map_priv_2;
+
+	DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+	memcpy_toio(win_base + to, from, len);
+}
+
+
+static void pcmciamtd_set_vpp(struct map_info *map, int on)
+{
+	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+	dev_link_t *link = &dev->link;
+	modconf_t mod;
+	int ret;
+
+	mod.Attributes = CONF_VPP1_CHANGE_VALID | CONF_VPP2_CHANGE_VALID;
+	mod.Vcc = 0;
+	mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0;
+
+	DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
+	ret = CardServices(ModifyConfiguration, link->handle, &mod);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, ModifyConfiguration, ret);
+	}
+}
+
+
+/* After a card is removed, pcmciamtd_release() will unregister the
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+
+static void pcmciamtd_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	struct pcmciamtd_dev *dev = NULL;
+	int ret;
+	struct list_head *temp1, *temp2;
+
+	DEBUG(3, "link = 0x%p", link);
+	/* Find device in list */
+	list_for_each_safe(temp1, temp2, &dev_list) {
+		dev = list_entry(temp1, struct pcmciamtd_dev, list);
+		if(link == &dev->link)
+			break;
+	}
+	if(link != &dev->link) {
+		DEBUG(1, "Cant find %p in dev_list", link);
+		return;
+	}
+
+	if(dev) {
+		if(dev->mtd_info) {
+			del_mtd_device(dev->mtd_info);
+			dev->mtd_info = NULL;
+			MOD_DEC_USE_COUNT;
+		}
+		if (link->win) {
+			if(dev->win_base) {
+				iounmap(dev->win_base);
+				dev->win_base = NULL;
+			}
+			CardServices(ReleaseWindow, link->win);
+		}
+		ret = CardServices(ReleaseConfiguration, link->handle);
+		if(ret != CS_SUCCESS)
+			cs_error(link->handle, ReleaseConfiguration, ret);
+			
+	}
+	link->state &= ~DEV_CONFIG;
+}
+
+
+static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_name)
+{
+	int rc;
+	tuple_t tuple;
+	cisparse_t parse;
+	u_char buf[64];
+
+	tuple.Attributes = 0;
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+
+	rc = CardServices(GetFirstTuple, link->handle, &tuple);
+	while(rc == CS_SUCCESS) {
+		rc = CardServices(GetTupleData, link->handle, &tuple);
+		if(rc != CS_SUCCESS) {
+			cs_error(link->handle, GetTupleData, rc);
+			break;
+		}
+		rc = CardServices(ParseTuple, link->handle, &tuple, &parse);
+		if(rc != CS_SUCCESS) {
+			cs_error(link->handle, ParseTuple, rc);
+			break;
+		}
+		
+		switch(tuple.TupleCode) {
+		case  CISTPL_FORMAT: {
+			cistpl_format_t *t = &parse.format;
+			(void)t; /* Shut up, gcc */
+			DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u",
+			      t->type, t->edc, t->offset, t->length);
+			break;
+			
+		}
+			
+		case CISTPL_DEVICE: {
+			cistpl_device_t *t = &parse.device;
+			int i;
+			DEBUG(2, "Common memory:");
+			dev->pcmcia_map.size = t->dev[0].size;
+			for(i = 0; i < t->ndev; i++) {
+				DEBUG(2, "Region %d, type = %u", i, t->dev[i].type);
+				DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp);
+				DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed);
+				DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size);
+			}
+			break;
+		}
+			
+		case CISTPL_VERS_1: {
+			cistpl_vers_1_t *t = &parse.version_1;
+			int i;
+			if(t->ns) {
+				dev->mtd_name[0] = '\0';
+				for(i = 0; i < t->ns; i++) {
+					if(i)
+						strcat(dev->mtd_name, " ");
+					strcat(dev->mtd_name, t->str+t->ofs[i]);
+				}
+			}
+			DEBUG(2, "Found name: %s", dev->mtd_name);
+			break;
+		}
+			
+		case CISTPL_JEDEC_C: {
+			cistpl_jedec_t *t = &parse.jedec;
+			int i;
+			for(i = 0; i < t->nid; i++) {
+				DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info);
+			}
+			break;
+		}
+			
+		case CISTPL_DEVICE_GEO: {
+			cistpl_device_geo_t *t = &parse.device_geo;
+			int i;
+			dev->pcmcia_map.buswidth = t->geo[0].buswidth;
+			for(i = 0; i < t->ngeo; i++) {
+				DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth);
+				DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
+				DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
+				DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
+				DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition);
+				DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave);
+			}
+			break;
+		}
+			
+		default:
+			DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
+		}
+		
+		rc = CardServices(GetNextTuple, link->handle, &tuple, &parse);
+	}
+	if(!dev->pcmcia_map.size)
+		dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
+
+	if(!dev->pcmcia_map.buswidth)
+		dev->pcmcia_map.buswidth = 2;
+
+	if(force_size) {
+		dev->pcmcia_map.size = force_size << 20;
+		DEBUG(2, "size forced to %dM", force_size);
+
+	}
+
+	if(buswidth) {
+		dev->pcmcia_map.buswidth = buswidth;
+		DEBUG(2, "buswidth forced to %d", buswidth);
+	}		
+
+	dev->pcmcia_map.name = dev->mtd_name;
+	if(!dev->mtd_name[0]) {
+		strcpy(dev->mtd_name, "PCMCIA Memory card");
+		*new_name = 1;
+	}
+
+	DEBUG(1, "Device: Size: %lu Width:%d Name: %s",
+	      dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name);
+}
+
+
+/* pcmciamtd_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * MTD device available to the system.
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void pcmciamtd_config(dev_link_t *link)
+{
+	struct pcmciamtd_dev *dev = link->priv;
+	struct mtd_info *mtd = NULL;
+	cs_status_t status;
+	win_req_t req;
+	int last_ret = 0, last_fn = 0;
+	int ret;
+	int i;
+	config_info_t t;
+	static char *probes[] = { "jedec_probe", "cfi_probe" };
+	cisinfo_t cisinfo;
+	int new_name = 0;
+
+	DEBUG(3, "link=0x%p", link);
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	DEBUG(2, "Validating CIS");
+	ret = CardServices(ValidateCIS, link->handle, &cisinfo);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, GetTupleData, ret);
+	} else {
+		DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains);
+	}
+
+	card_settings(dev, link, &new_name);
+
+	dev->pcmcia_map.read8 = pcmcia_read8_remap;
+	dev->pcmcia_map.read16 = pcmcia_read16_remap;
+	dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
+	dev->pcmcia_map.write8 = pcmcia_write8_remap;
+	dev->pcmcia_map.write16 = pcmcia_write16_remap;
+	dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
+	if(setvpp == 1)
+		dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
+
+	/* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum
+	   that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the
+	   whole card - otherwise we try smaller windows until we succeed */
+
+	req.Attributes =  WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+	req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
+	req.Base = 0;
+	req.AccessSpeed = mem_speed;
+	link->win = (window_handle_t)link->handle;
+	req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR;
+	dev->win_size = 0;
+
+	do {
+		int ret;
+		DEBUG(2, "requesting window with size = %dKB memspeed = %d",
+		      req.Size >> 10, req.AccessSpeed);
+		link->win = (window_handle_t)link->handle;
+		ret = CardServices(RequestWindow, &link->win, &req);
+		DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size);
+		if(ret) {
+			req.Size >>= 1;
+		} else {
+			DEBUG(2, "Got window of size %dKB", req.Size >> 10);
+			dev->win_size = req.Size;
+			break;
+		}
+	} while(req.Size >= 0x1000);
+
+	DEBUG(2, "dev->win_size = %d", dev->win_size);
+
+	if(!dev->win_size) {
+		err("Cant allocate memory window");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10);
+		
+	/* Get write protect status */
+	CS_CHECK(GetStatus, link->handle, &status);
+	DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
+	      status.CardState, (unsigned long)link->win);
+	dev->win_base = ioremap(req.Base, req.Size);
+	if(!dev->win_base) {
+		err("ioremap(%lu, %u) failed", req.Base, req.Size);
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
+	      dev, req.Base, dev->win_base, req.Size);
+	dev->cardsize = 0;
+	dev->offset = 0;
+
+	dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
+	dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
+
+	DEBUG(2, "Getting configuration");
+	CS_CHECK(GetConfigurationInfo, link->handle, &t);
+	DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
+	dev->vpp = (vpp) ? vpp : t.Vpp1;
+	link->conf.Attributes = 0;
+	link->conf.Vcc = t.Vcc;
+	if(setvpp == 2) {
+		link->conf.Vpp1 = dev->vpp;
+		link->conf.Vpp2 = dev->vpp;
+	} else {
+		link->conf.Vpp1 = 0;
+		link->conf.Vpp2 = 0;
+	}
+
+	link->conf.IntType = INT_MEMORY;
+	link->conf.ConfigBase = t.ConfigBase;
+	link->conf.Status = t.Status;
+	link->conf.Pin = t.Pin;
+	link->conf.Copy = t.Copy;
+	link->conf.ExtStatus = t.ExtStatus;
+	link->conf.ConfigIndex = 0;
+	link->conf.Present = t.Present;
+	DEBUG(2, "Setting Configuration");
+	ret = CardServices(RequestConfiguration, link->handle, &link->conf);
+	if(ret != CS_SUCCESS) {
+		cs_error(link->handle, RequestConfiguration, ret);
+	}
+
+	link->dev = NULL;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	if(mem_type == 1) {
+		mtd = do_map_probe("map_ram", &dev->pcmcia_map);
+	} else if(mem_type == 2) {
+		mtd = do_map_probe("map_rom", &dev->pcmcia_map);
+	} else {
+		for(i = 0; i < sizeof(probes) / sizeof(char *); i++) {
+			DEBUG(1, "Trying %s", probes[i]);
+			mtd = do_map_probe(probes[i], &dev->pcmcia_map);
+			if(mtd)
+				break;
+			
+			DEBUG(1, "FAILED: %s", probes[i]);
+		}
+	}
+	
+	if(!mtd) {
+		DEBUG(1, "Cant find an MTD");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+
+	dev->mtd_info = mtd;
+	mtd->module = THIS_MODULE;
+	dev->cardsize = mtd->size;
+
+	if(new_name) {
+		int size = 0;
+		char unit = ' ';
+		/* Since we are using a default name, make it better by adding in the
+		   size */
+		if(mtd->size < 1048576) { /* <1MB in size, show size in K */
+			size = mtd->size >> 10;
+			unit = 'K'; 
+		} else {
+			size = mtd->size >> 20;
+			unit = 'M';
+		}
+		sprintf(mtd->name, "%d%cB %s", size, unit, "PCMCIA Memory card");
+	}
+
+	/* If the memory found is fits completely into the mapped PCMCIA window,
+	   use the faster non-remapping read/write functions */
+	if(dev->cardsize <= dev->win_size) {
+		DEBUG(1, "Using non remapping memory functions");
+
+		dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
+		dev->pcmcia_map.read8 = pcmcia_read8;
+		dev->pcmcia_map.read16 = pcmcia_read16;
+		dev->pcmcia_map.copy_from = pcmcia_copy_from;
+		dev->pcmcia_map.write8 = pcmcia_write8;
+		dev->pcmcia_map.write16 = pcmcia_write16;
+		dev->pcmcia_map.copy_to = pcmcia_copy_to;
+	}
+
+	MOD_INC_USE_COUNT;
+	if(add_mtd_device(mtd)) {
+		dev->mtd_info = NULL;
+		MOD_DEC_USE_COUNT;
+		err("Couldnt register MTD device");
+		pcmciamtd_release((u_long)link);
+		return;
+	}
+	DEBUG(1, "mtd added @ %p mtd->priv = %p", mtd, mtd->priv);
+
+	return;
+
+ cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	err("CS Error, exiting");
+	pcmciamtd_release((u_long)link);
+	return;
+}
+
+
+/* The card status event handler.  Mostly, this schedules other
+ * stuff to run after an event is received.  A CARD_REMOVAL event
+ * also sets some flags to discourage the driver from trying
+ * to talk to the card any more.
+ */
+
+static int pcmciamtd_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+
+	DEBUG(1, "event=0x%06x", event);
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		DEBUG(2, "EVENT_CARD_REMOVAL");
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG)
+			mod_timer(&link->release, jiffies + HZ/20);
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		DEBUG(2, "EVENT_CARD_INSERTION");
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		pcmciamtd_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		DEBUG(2, "EVENT_PM_SUSPEND");
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		DEBUG(2, "EVENT_RESET_PHYSICAL");
+		/* get_lock(link); */
+		break;
+	case CS_EVENT_PM_RESUME:
+		DEBUG(2, "EVENT_PM_RESUME");
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		DEBUG(2, "EVENT_CARD_RESET");
+		/* free_lock(link); */
+		break;
+	default:
+		DEBUG(2, "Unknown event %d", event);
+	}
+	return 0;
+}
+
+
+/* This deletes a driver "instance".  The device is de-registered
+ * with Card Services.  If it has been released, all local data
+ * structures are freed.  Otherwise, the structures will be freed
+ * when the device is released.
+ */
+
+static void pcmciamtd_detach(dev_link_t *link)
+{
+	int ret;
+	struct pcmciamtd_dev *dev = NULL;
+	struct list_head *temp1, *temp2;
+
+	DEBUG(3, "link=0x%p", link);
+
+	/* Find device in list */
+	list_for_each_safe(temp1, temp2, &dev_list) {
+		dev = list_entry(temp1, struct pcmciamtd_dev, list);
+		if(link == &dev->link)
+			break;
+	}
+	if(link != &dev->link) {
+		DEBUG(1, "Cant find %p in dev_list", link);
+		return;
+	}
+	
+	del_timer(&link->release);
+
+	if(!dev) {
+		DEBUG(3, "dev is NULL");
+		return;
+	}
+
+	if (link->state & DEV_CONFIG) {
+		//pcmciamtd_release((u_long)link);
+		DEBUG(3, "DEV_CONFIG set");
+		link->state |= DEV_STALE_LINK;
+		return;
+	}
+
+	if (link->handle) {
+		DEBUG(2, "Deregistering with card services");
+		ret = CardServices(DeregisterClient, link->handle);
+		if (ret != CS_SUCCESS)
+			cs_error(link->handle, DeregisterClient, ret);
+	}
+	DEBUG(3, "Freeing dev (%p)", dev);
+	list_del(&dev->list);
+	link->priv = NULL;
+	kfree(dev);
+}
+
+
+/* pcmciamtd_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device.  The device is registered
+ * with Card Services.
+ */
+
+static dev_link_t *pcmciamtd_attach(void)
+{
+	struct pcmciamtd_dev *dev;
+	dev_link_t *link;
+	client_reg_t client_reg;
+	int ret;
+
+	/* Create new memory card device */
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) return NULL;
+	DEBUG(1, "dev=0x%p", dev);
+
+	memset(dev, 0, sizeof(*dev));
+	link = &dev->link; link->priv = dev;
+
+	link->release.function = &pcmciamtd_release;
+	link->release.data = (u_long)link;
+
+	link->conf.Attributes = 0;
+	link->conf.IntType = INT_MEMORY;
+
+	list_add(&dev->list, &dev_list);
+
+	/* Register with Card Services */
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &pcmciamtd_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	DEBUG(2, "Calling RegisterClient");
+	ret = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (ret != 0) {
+		cs_error(link->handle, RegisterClient, ret);
+		pcmciamtd_detach(link);
+		return NULL;
+	}
+
+	return link;
+}
+
+
+static int __init init_pcmciamtd(void)
+{
+	servinfo_t serv;
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		err("Card Services release does not match!");
+		return -1;
+	}
+
+	if(buswidth && buswidth != 1 && buswidth != 2) {
+		info("bad buswidth (%d), using default", buswidth);
+		buswidth = 2;
+	}
+	if(force_size && (force_size < 1 || force_size > 64)) {
+		info("bad force_size (%d), using default", force_size);
+		force_size = 0;
+	}
+	if(mem_type && mem_type != 1 && mem_type != 2) {
+		info("bad mem_type (%d), using default", mem_type);
+		mem_type = 0;
+	}
+	register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
+	return 0;
+}
+
+
+static void __exit exit_pcmciamtd(void)
+{
+	struct list_head *temp1, *temp2;
+
+	DEBUG(1, DRIVER_DESC " unloading");
+	unregister_pccard_driver(&dev_info);
+	list_for_each_safe(temp1, temp2, &dev_list) {
+		dev_link_t *link = &list_entry(temp1, struct pcmciamtd_dev, list)->link;
+		if (link && (link->state & DEV_CONFIG)) {
+			pcmciamtd_release((u_long)link);
+			pcmciamtd_detach(link);
+		}
+	}
+}
+
+module_init(init_pcmciamtd);
+module_exit(exit_pcmciamtd);
diff -Nru a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
--- a/drivers/mtd/maps/sa1100-flash.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/mtd/maps/sa1100-flash.c	Tue Oct 15 20:29:14 2002
@@ -3,28 +3,35 @@
  * 
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  * 
- * $Id: sa1100-flash.c,v 1.22 2001/10/02 10:04:52 rmk Exp $
+ * $Id: sa1100-flash.c,v 1.28 2002/05/07 13:48:38 abz Exp $
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
+#include <linux/ioport.h>
 #include <linux/kernel.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/io.h>
+#include <asm/sizes.h>
 
+#include <asm/arch/h3600.h>
 
 #ifndef CONFIG_ARCH_SA1100
 #error This is for SA1100 architecture only
 #endif
 
-
-#define WINDOW_ADDR 0xe8000000
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_SA1100_STATICMAP 1
 
 static __u8 sa1100_read8(struct map_info *map, unsigned long ofs)
 {
@@ -66,33 +73,7 @@
 	memcpy((void *)(map->map_priv_1 + to), from, len);
 }
 
-
-#ifdef CONFIG_SA1100_H3600
-
-static void h3600_set_vpp(struct map_info *map, int vpp)
-{
-	if (vpp)
-		set_h3600_egpio(EGPIO_H3600_VPP_ON);
-	else
-		clr_h3600_egpio(EGPIO_H3600_VPP_ON);
-}
-
-#endif
-
-#ifdef CONFIG_SA1100_JORNADA720
-
-static void jornada720_set_vpp(int vpp)
-{
-  if (vpp)
-      PPSR |= 0x80;
-  else
-      PPSR &= ~0x80;
-  PPDR |= 0x80;
-}
-
-#endif
-
-static struct map_info sa1100_map = {
+static struct map_info sa1100_map __initdata = {
 	name:		"SA1100 flash",
 	read8:		sa1100_read8,
 	read16:		sa1100_read16,
@@ -102,609 +83,1232 @@
 	write16:	sa1100_write16,
 	write32:	sa1100_write32,
 	copy_to:	sa1100_copy_to,
-
-	map_priv_1:	WINDOW_ADDR,
 };
 
 
+#ifdef CONFIG_MTD_SA1100_STATICMAP
 /*
  * Here are partition information for all known SA1100-based devices.
  * See include/linux/mtd/partitions.h for definition of the mtd_partition
  * structure.
- * 
- * The *_max_flash_size is the maximum possible mapped flash size which
- * is not necessarily the actual flash size.  It must correspond to the 
- * value specified in the mapping definition defined by the
- * "struct map_desc *_io_desc" for the corresponding machine.
+ *
+ * Please note:
+ *  1. We no longer support static flash mappings via the machine io_desc
+ *     structure.
+ *  2. The flash size given should be the largest flash size that can
+ *     be accomodated.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ * Please keep these in alphabetical order, and formatted as per existing
+ * entries.  Thanks.
  */
 
-#ifdef CONFIG_SA1100_ASSABET
+#ifdef CONFIG_SA1100_ADSBITSY
+static struct mtd_partition adsbitsy_partitions[] = {
+	{
+		name:		"bootROM",
+		size:		0x80000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"zImage",
+		size:		0x100000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#endif
 
+#ifdef CONFIG_SA1100_ASSABET
 /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
-static unsigned long assabet4_max_flash_size = 0x00400000;
 static struct mtd_partition assabet4_partitions[] = {
-        {
-                name: "bootloader",
-                size: 0x00020000,
-                offset: 0,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "bootloader params",
-                size: 0x00020000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "jffs",
-                size: MTDPART_SIZ_FULL,
-                offset: MTDPART_OFS_APPEND
-        }
+	{
+		name:		"bootloader",
+		size:		0x00020000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"bootloader params",
+		size:		0x00020000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"jffs",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
 };
 
 /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
-static unsigned long assabet5_max_flash_size = 0x02000000;
 static struct mtd_partition assabet5_partitions[] = {
-        {
-                name: "bootloader",
-                size: 0x00040000,
-                offset: 0,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "bootloader params",
-                size: 0x00040000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "jffs",
-                size: MTDPART_SIZ_FULL,
-                offset: MTDPART_OFS_APPEND
-        }
+	{
+		name:		"bootloader",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"bootloader params",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"jffs",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
 };
 
-#define assabet_max_flash_size assabet5_max_flash_size
-#define assabet_partitions     assabet5_partitions
-
+#define assabet_partitions	assabet5_partitions
 #endif
 
-#ifdef CONFIG_SA1100_FLEXANET
-
-/* Flexanet has two 28F128J3A flash parts in bank 0: */
-static unsigned long flexanet_max_flash_size = 0x02000000;
-static struct mtd_partition flexanet_partitions[] = {
-        {
-                name: "bootloader",
-                size: 0x00040000,
-                offset: 0,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "bootloader params",
-                size: 0x00040000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "kernel",
-                size: 0x000C0000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "altkernel",
-                size: 0x000C0000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "root",
-                size: 0x00400000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "free1",
-                size: 0x00300000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "free2",
-                size: 0x00300000,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        },{
-                name: "free3",
-                size: MTDPART_SIZ_FULL,
-                offset: MTDPART_OFS_APPEND,
-                mask_flags: MTD_WRITEABLE
-        }
+#ifdef CONFIG_SA1100_BADGE4
+/*
+ * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit)
+ *   Eight 4 KiW Parameter Bottom Blocks (64 KiB)
+ *   Sixty-three 32 KiW Main Blocks (4032 Ki b)
+ */
+static struct mtd_partition badge4_partitions[] = {
+	{
+		name:		"BLOB boot loader",
+		offset:		0,
+		size:		0x0000A000
+	}, {
+		name:		"params",
+		offset:		MTDPART_OFS_APPEND,
+		size:		0x00006000
+	}, {
+		name:		"kernel",
+		offset:		MTDPART_OFS_APPEND,
+		size:		0x00100000
+	}, {
+		name:		"root",
+		offset:		MTDPART_OFS_APPEND,
+		size:		MTDPART_SIZ_FULL
+	}
 };
-
 #endif
 
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-static unsigned long huw_webpanel_max_flash_size = 0x01000000;
-static struct mtd_partition huw_webpanel_partitions[] = {
-	{ 
-	  name: "Loader",
-	  size: 0x00040000,
-	  offset: 0,
-	},{
-	  name: "Sector 1",
-	  size: 0x00040000,
-	  offset: MTDPART_OFS_APPEND,
-	},{
-	  size: MTDPART_SIZ_FULL,
-	  offset: MTDPART_OFS_APPEND,
+
+#ifdef CONFIG_SA1100_CERF
+#ifdef CONFIG_SA1100_CERF_FLASH_32MB
+static struct mtd_partition cerf_partitions[] = {
+	{
+		name:		"firmware",
+		size:		0x00040000,
+		offset:		0,
+	}, {
+		name:		"params",
+		size:		0x00040000,
+		offset:		0x00040000,
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		0x00080000,
+	}, {
+		name:		"rootdisk",
+		size:		0x01E80000,
+		offset:		0x00180000,
 	}
 };
-#endif /* CONFIG_SA1100_HUW_WEBPANEL */
-
-
-#ifdef CONFIG_SA1100_H3600
-
-static unsigned long h3600_max_flash_size = 0x02000000;
-static struct mtd_partition h3600_partitions[] = {
+#elif defined CONFIG_SA1100_CERF_FLASH_16MB
+static struct mtd_partition cerf_partitions[] = {
 	{
-		name: "H3600 boot firmware",
-		size: 0x00040000,
-		offset: 0,
-		mask_flags: MTD_WRITEABLE  /* force read-only */
-	},{
-		name: "H3600 kernel",
-		size: 0x00080000,
-		offset: 0x40000
-	},{
-		name: "H3600 params",
-		size: 0x00040000,
-		offset: 0xC0000
-	},{
-#ifdef CONFIG_JFFS2_FS
-		name: "H3600 root jffs2",
-		offset: 0x00100000,
-		size: MTDPART_SIZ_FULL
+		name:		"firmware",
+		size:		0x00020000,
+		offset:		0,
+	}, {
+		name:		"params",
+		size:		0x00020000,
+		offset:		0x00020000,
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		0x00040000,
+	}, {
+		name:		"rootdisk",
+		size:		0x00EC0000,
+		offset:		0x00140000,
+	}
+};
+#elif defined CONFIG_SA1100_CERF_FLASH_8MB
+#   error "Unwritten type definition"
 #else
-		name: "H3600 initrd",
-		size: 0x00100000,
-		offset: 0x00100000
-	},{
-		name: "H3600 root cramfs",
-		size: 0x00300000,
-		offset: 0x00200000
-	},{
-		name: "H3600 usr cramfs",
-		size: 0x00800000,
-		offset: 0x00500000
-	},{
-		name: "H3600 usr local",
-		offset: 0x00d00000,
-		size: MTDPART_SIZ_FULL
+#   error "Undefined memory orientation for CERF in sa1100-flash.c"
 #endif
+#endif
+
+#ifdef CONFIG_SA1100_CONSUS
+static struct mtd_partition consus_partitions[] = {
+	{
+		name:		"Consus boot firmware",
+		offset: 	0,
+		size:		0x00040000,
+		mask_flags:	MTD_WRITABLE, /* force read-only */
+	}, {
+		name:		"Consus kernel",
+		offset: 	0x00040000,
+		size:		0x00100000,
+		mask_flags:	0,
+	}, {
+		name:		"Consus disk",
+		offset: 	0x00140000,
+		/* The rest (up to 16M) for jffs.  We could put 0 and
+		   make it find the size automatically, but right now
+		   i have 32 megs.  jffs will use all 32 megs if given
+		   the chance, and this leads to horrible problems
+		   when you try to re-flash the image because blob
+		   won't erase the whole partition. */
+		size:		0x01000000 - 0x00140000,
+		mask_flags:	0,
+	}, {
+		/* this disk is a secondary disk, which can be used as
+		   needed, for simplicity, make it the size of the other
+		   consus partition, although realistically it could be
+		   the remainder of the disk (depending on the file
+		   system used) */
+		 name:		"Consus disk2",
+		 offset:	0x01000000,
+		 size:		0x01000000 - 0x00140000,
+		 mask_flags:	0,
 	}
 };
+#endif
 
+#ifdef CONFIG_SA1100_FLEXANET
+/* Flexanet has two 28F128J3A flash parts in bank 0: */
+#define FLEXANET_FLASH_SIZE		0x02000000
+static struct mtd_partition flexanet_partitions[] = {
+	{
+		name:		"bootloader",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"bootloader params",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"kernel",
+		size:		0x000C0000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"altkernel",
+		size:		0x000C0000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"root",
+		size:		0x00400000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"free1",
+		size:		0x00300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"free2",
+		size:		0x00300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}, {
+		name:		"free3",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,
+	}
+};
 #endif
+
 #ifdef CONFIG_SA1100_FREEBIRD
-static unsigned long freebird_max_flash_size = 0x02000000;
 static struct mtd_partition freebird_partitions[] = {
 #if CONFIG_SA1100_FREEBIRD_NEW
-    {
-     name: "firmware",
-     size: 0x00040000,
-     offset: 0,
-     mask_flags: MTD_WRITEABLE  /* force read-only */
-    },{
-     name: "kernel",
-     size: 0x00080000,
-     offset: 0x40000
-    },{
-     name: "params",
-     size: 0x00040000,
-     offset: 0xC0000
-    },{
-     name: "initrd",
-     size: 0x00100000,
-     offset: 0x00100000
-    },{
-     name: "root cramfs",
-     size: 0x00300000,
-     offset: 0x00200000
-    },{
-     name: "usr cramfs",
-     size: 0x00C00000,
-     offset: 0x00500000
-    },{
-	 name: "local",
-	 offset: 0x01100000,
-	 size: MTDPART_SIZ_FULL 
+	{
+		name:		"firmware",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"kernel",
+		size:		0x00080000,
+		offset:		0x00040000,
+	}, {
+		name:		"params",
+		size:		0x00040000,
+		offset:		0x000C0000,
+	}, {
+		name:		"initrd",
+		size:		0x00100000,
+		offset:		0x00100000,
+	}, {
+		name:		"root cramfs",
+		size:		0x00300000,
+		offset:		0x00200000,
+	}, {
+		name:		"usr cramfs",
+		size:		0x00C00000,
+		offset:		0x00500000,
+	}, {
+		name:		"local",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x01100000,
 	}
 #else
-	{ offset: 0,            		size: 0x00040000,   },
-	{ offset: MTDPART_OFS_APPEND,   size: 0x000c0000,   },
-	{ offset: MTDPART_OFS_APPEND,	size: 0x00400000,	},
-	{ offset: MTDPART_OFS_APPEND,   size: MTDPART_SIZ_FULL  }
+	{
+		size:		0x00040000,
+		offset:		0,
+	}, {
+		size:		0x000c0000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		0x00400000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
 #endif
-	};
+};
 #endif
-																									
 
-#ifdef CONFIG_SA1100_CERF
-
-static unsigned long cerf_max_flash_size = 0x01000000;
-static struct mtd_partition cerf_partitions[] = {
-	{ offset: 0,			size: 0x00800000 	},
-	{ offset: MTDPART_OFS_APPEND,	size: 0x00800000 	}
+#ifdef CONFIG_SA1100_FRODO
+/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
+static struct mtd_partition frodo_partitions[] =
+{
+	{
+		name:		"bootloader",
+		size:		0x00040000,
+		offset: 	0x00000000,
+		mask_flags:	MTD_WRITEABLE
+	}, {
+		name:		"bootloader params",
+		size:		0x00040000,
+		offset: 	MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset: 	MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE
+	}, {
+		name:		"ramdisk",
+		size:		0x00400000,
+		offset: 	MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE
+	}, {
+		name:		"file system",
+		size:		MTDPART_SIZ_FULL,
+		offset: 	MTDPART_OFS_APPEND
+	}
 };
-
 #endif
 
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
-
-static unsigned long graphicsclient_max_flash_size = 0x01000000;
 static struct mtd_partition graphicsclient_partitions[] = {
-	{ 
-	 name: "zImage",
-	 offset: 0,
-	 size: 0x100000
-	},
-	{ 
-         name: "ramdisk.gz",
-         offset: MTDPART_OFS_APPEND,
-         size: 0x300000 		
-	},
-	{ 
-	  name: "User FS",
-          offset: MTDPART_OFS_APPEND,	
-          size: MTDPART_SIZ_FULL
+	{
+		name:		"zImage",
+		size:		0x100000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
 	}
 };
-
 #endif
 
 #ifdef CONFIG_SA1100_GRAPHICSMASTER
-
-static unsigned long graphicsmaster_max_flash_size = 0x01000000;
 static struct mtd_partition graphicsmaster_partitions[] = {
-	{ 
-	 name: "zImage",
-	 offset: 0,
-	 size: 0x100000
+	{
+		name:		"zImage",
+		size:		0x100000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
 	},
-	{ 
-         name: "ramdisk.gz",
-         offset: MTDPART_OFS_APPEND,
-         size: 0x300000 		
+	{
+		name:		"ramdisk.gz",
+		size:		0x300000,
+		offset:		MTDPART_OFS_APPEND,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
 	},
-	{ 
-	  name: "User FS",
-          offset: MTDPART_OFS_APPEND,	
-          size: MTDPART_SIZ_FULL
+	{
+		name:		"User FS",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
 	}
 };
+#endif
 
+#ifdef CONFIG_SA1100_H3XXX
+static struct mtd_partition h3xxx_partitions[] = {
+	{
+		name:		"H3XXX boot firmware",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+#ifdef CONFIG_MTD_2PARTS_IPAQ
+		name:		"H3XXX root jffs2",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00040000,
+#else
+		name:		"H3XXX kernel",
+		size:		0x00080000,
+		offset:		0x00040000,
+	}, {
+		name:		"H3XXX params",
+		size:		0x00040000,
+		offset:		0x000C0000,
+	}, {
+#ifdef CONFIG_JFFS2_FS
+		name:		"H3XXX root jffs2",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00100000,
+#else
+		name:		"H3XXX initrd",
+		size:		0x00100000,
+		offset:		0x00100000,
+	}, {
+		name:		"H3XXX root cramfs",
+		size:		0x00300000,
+		offset:		0x00200000,
+	}, {
+		name:		"H3XXX usr cramfs",
+		size:		0x00800000,
+		offset:		0x00500000,
+	}, {
+		name:		"H3XXX usr local",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00d00000,
+#endif
 #endif
+	}
+};
 
-#ifdef CONFIG_SA1100_PANGOLIN
+static void h3xxx_set_vpp(struct map_info *map, int vpp)
+{
+	assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
+}
+#else
+#define h3xxx_set_vpp NULL
+#endif
 
-static unsigned long pangolin_max_flash_size = 0x04000000;
-static struct mtd_partition pangolin_partitions[] = {
-	{
-	  name: "boot firmware",
-	  offset: 0x00000000,
-	  size: 0x00080000,
-	  mask_flags: MTD_WRITEABLE,  /* force read-only */
-	},
-	{
-	  name: "kernel",
-	  offset: 0x00080000,
-	  size: 0x00100000,
-	},
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+static struct mtd_partition huw_webpanel_partitions[] = {
 	{
-	  name: "initrd",
-	  offset: 0x00180000,
-	  size: 0x00280000,
-	},
+		name:		"Loader",
+		size:		0x00040000,
+		offset:		0,
+	}, {
+		name:		"Sector 1",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA720
+static struct mtd_partition jornada720_partitions[] = {
 	{
-	  name: "initrd-test",
-	  offset: 0x00400000,
-	  size: 0x03C00000,
+		name:		"JORNADA720 boot firmware",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"JORNADA720 kernel",
+		size:		0x000c0000,
+		offset:		0x00040000,
+	}, {
+		name:		"JORNADA720 params",
+		size:		0x00040000,
+		offset:		0x00100000,
+	}, {
+		name:		"JORNADA720 initrd",
+		size:		0x00100000,
+		offset:		0x00140000,
+	}, {
+		name:		"JORNADA720 root cramfs",
+		size:		0x00300000,
+		offset:		0x00240000,
+	}, {
+		name:		"JORNADA720 usr cramfs",
+		size:		0x00800000,
+		offset:		0x00540000,
+	}, {
+		name:		"JORNADA720 usr local",
+		size:		0  /* will expand to the end of the flash */
+		offset:		0x00d00000,
 	}
 };
 
+static void jornada720_set_vpp(int vpp)
+{
+	if (vpp)
+		PPSR |= 0x80;
+	else
+		PPSR &= ~0x80;
+	PPDR |= 0x80;
+}
+#else
+#define jornada720_set_vpp NULL
+#endif
+
+#ifdef CONFIG_SA1100_PANGOLIN
+static struct mtd_partition pangolin_partitions[] = {
+	{
+		name:		"boot firmware",
+		size:		0x00080000,
+		offset:		0x00000000,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		0x00080000,
+	}, {
+		name:		"initrd",
+		size:		0x00280000,
+		offset:		0x00180000,
+	}, {
+		name:		"initrd-test",
+		size:		0x03C00000,
+		offset:		0x00400000,
+	}
+};
 #endif
 
-#ifdef CONFIG_SA1100_YOPY
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+/* erase size is 0x40000 == 256k partitions have to have this boundary */
+static struct mtd_partition system3_partitions[] = {
+	{
+		name:		"BLOB",
+		size:		0x00040000,
+		offset:		0x00000000,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"config",
+		size:		0x00040000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"kernel",
+		size:		0x00100000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		name:		"root",
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#endif
 
-static unsigned long yopy_max_flash_size = 0x08000000;
-static struct mtd_partition yopy_partitions[] = {
+#ifdef CONFIG_SA1100_SHANNON
+static struct mtd_partition shannon_partitions[] = {
 	{
-		name: "boot firmware",
-		offset: 0x00000000,
-		size: 0x00040000,
-		mask_flags: MTD_WRITEABLE,  /* force read-only */
+		name: "BLOB boot loader",
+		offset: 0,
+		size: 0x20000
 	},
 	{
 		name: "kernel",
-		offset: 0x00080000,
-		size: 0x00080000,
+		offset: MTDPART_OFS_APPEND,
+		size: 0xe0000
 	},
-	{
+	{ 
 		name: "initrd",
-		offset: 0x00100000,
-		size: 0x00300000,
-	},
-	{
-		name: "root",
-		offset: 0x00400000,
-		size: 0x01000000,
-	},
+		offset: MTDPART_OFS_APPEND,	
+		size: MTDPART_SIZ_FULL
+	}
 };
 
 #endif
 
-#ifdef CONFIG_SA1100_JORNADA720
-
-static unsigned long jornada720_max_flash_size = 0x02000000;
-static struct mtd_partition jornada720_partitions[] = {
+#ifdef CONFIG_SA1100_SHERMAN
+static struct mtd_partition sherman_partitions[] = {
 	{
-		name: "JORNADA720 boot firmware",
-		size: 0x00040000,
-		offset: 0,
-		mask_flags: MTD_WRITEABLE  /* force read-only */
-	},{
-		name: "JORNADA720 kernel",
-		size: 0x000c0000,
-		offset: 0x40000
-	},{
-		name: "JORNADA720 params",
-		size: 0x00040000,
-		offset: 0x100000
-	},{
-		name: "JORNADA720 initrd",
-		size: 0x00100000,
-		offset: 0x00140000
-	},{
-		name: "JORNADA720 root cramfs",
-		size: 0x00300000,
-		offset: 0x00240000
-	},{
-		name: "JORNADA720 usr cramfs",
-		size: 0x00800000,
-		offset: 0x00540000
-	},{
-		name: "JORNADA720 usr local",
-		offset: 0x00d00000,
-		size: 0  /* will expand to the end of the flash */
+		size:		0x50000,
+		offset:		0,
+	}, {
+		size:		0x70000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		0x600000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		0xA0000,
+		offset:		MTDPART_OFS_APPEND,
 	}
 };
 #endif
 
-#ifdef CONFIG_SA1100_SHERMAN
-
-static unsigned long sherman_max_flash_size = 0x02000000;
-static struct mtd_partition sherman_partitions[] = {
-	{ offset: 0,			size: 0x50000 	},
-	{ offset: MTDPART_OFS_APPEND,	size: 0x70000 	},
-	{ offset: MTDPART_OFS_APPEND,	size: 0x600000 	},
-	{ offset: MTDPART_OFS_APPEND,	size: 0xA0000 	}
-};
-
+#ifdef CONFIG_SA1100_SIMPAD
+static struct mtd_partition simpad_partitions[] = {
+	{
+		name:		"SIMpad boot firmware",
+		size:		0x00080000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"SIMpad kernel",
+		size:		0x00100000,
+		offset:		0x00080000,
+	}, {
+#ifdef CONFIG_JFFS2_FS
+		name:		"SIMpad root jffs2",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00180000,
+#else
+		name:		"SIMpad initrd",
+		size:		0x00300000,
+		offset:		0x00180000,
+	}, {
+		name:		"SIMpad root cramfs",
+		size:		0x00300000,
+		offset:		0x00480000,
+	}, {
+		name:		"SIMpad usr cramfs",
+		size:		0x005c0000,
+		offset:		0x00780000,
+	}, {
+		name:		"SIMpad usr local",
+		size:		MTDPART_SIZ_FULL,
+		offset:		0x00d40000,
 #endif
+	}
+};
+#endif /* CONFIG_SA1100_SIMPAD */
 
 #ifdef CONFIG_SA1100_STORK
-
-static unsigned long stork_max_flash_size = 0x02000000;
 static struct mtd_partition stork_partitions[] = {
 	{
-		name: "STORK boot firmware",
-		size: 0x00040000,
-		offset: 0,
-		mask_flags: MTD_WRITEABLE  /* force read-only */
-	},{
-		name: "STORK params",
-		size: 0x00040000,
-		offset: 0x40000
-	},{
-		name: "STORK kernel",
-		size: 0x00100000,
-		offset: 0x80000
-	},{
+		name:		"STORK boot firmware",
+		size:		0x00040000,
+		offset:		0,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"STORK params",
+		size:		0x00040000,
+		offset:		0x00040000,
+	}, {
+		name:		"STORK kernel",
+		size:		0x00100000,
+		offset:		0x00080000,
+	}, {
 #ifdef CONFIG_JFFS2_FS
-		name: "STORK root jffs2",
-		offset: 0x00180000,
-		size: MTDPART_SIZ_FULL
+		name:		"STORK root jffs2",
+		offset:		0x00180000,
+		size:		MTDPART_SIZ_FULL,
 #else
-		name: "STORK initrd",
-		size: 0x00100000,
-		offset: 0x00180000
-	},{
-		name: "STORK root cramfs",
-		size: 0x00300000,
-		offset: 0x00280000
-	},{
-		name: "STORK usr cramfs",
-		size: 0x00800000,
-		offset: 0x00580000
-	},{
-		name: "STORK usr local",
-		offset: 0x00d80000,
-		size: MTDPART_SIZ_FULL
+		name:		"STORK initrd",
+		size:		0x00100000,
+		offset:		0x00180000,
+	}, {
+		name:		"STORK root cramfs",
+		size:		0x00300000,
+		offset:		0x00280000,
+	}, {
+		name:		"STORK usr cramfs",
+		size:		0x00800000,
+		offset:		0x00580000,
+	}, {
+		name:		"STORK usr local",
+		offset:		0x00d80000,
+		size:		MTDPART_SIZ_FULL,
 #endif
 	}
 };
-
 #endif
 
-#define NB_OF(x)  (sizeof(x)/sizeof(x[0]))
-
-
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+#ifdef CONFIG_SA1100_TRIZEPS
+static struct mtd_partition trizeps_partitions[] = {
+	{
+		name:		"Bootloader & the kernel",
+		size:		0x00200000,
+		offset:		0,
+	}, {
+		name:		"Data",
+		size:		0x00400000,
+		offset:		MTDPART_OFS_APPEND,
+	}, {
+		size:		MTDPART_SIZ_FULL,
+		offset:		MTDPART_OFS_APPEND,
+	}
+};
+#endif
 
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *mymtd;
+#ifdef CONFIG_SA1100_YOPY
+static struct mtd_partition yopy_partitions[] = {
+	{
+		name:		"boot firmware",
+		size:		0x00040000,
+		offset:		0x00000000,
+		mask_flags:	MTD_WRITEABLE,  /* force read-only */
+	}, {
+		name:		"kernel",
+		size:		0x00080000,
+		offset:		0x00080000,
+	}, {
+		name:		"initrd",
+		size:		0x00300000,
+		offset:		0x00100000,
+	}, {
+		name:		"root",
+		size:		0x01000000,
+		offset:		0x00400000,
+	}
+};
+#endif
 
-int __init sa1100_mtd_init(void)
+static int __init sa1100_static_partitions(struct mtd_partition **parts)
 {
-	struct mtd_partition *parts;
 	int nb_parts = 0;
-	int parsed_nr_parts = 0;
-	char *part_type;
-	
-	/* Default flash buswidth */
-	sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4;
 
-	/*
-	 * Static partition definition selection
-	 */
-	part_type = "static";
+#ifdef CONFIG_SA1100_ADSBITSY
+	if (machine_is_adsbitsy()) {
+		*parts       = adsbitsy_partitions;
+		nb_parts     = ARRAY_SIZE(adsbitsy_partitions);
+	}
+#endif
 #ifdef CONFIG_SA1100_ASSABET
 	if (machine_is_assabet()) {
-		parts = assabet_partitions;
-		nb_parts = NB_OF(assabet_partitions);
-		sa1100_map.size = assabet_max_flash_size;
+		*parts       = assabet_partitions;
+		nb_parts     = ARRAY_SIZE(assabet_partitions);
 	}
 #endif
-
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-	if (machine_is_huw_webpanel()) {
-		parts = huw_webpanel_partitions;
-		nb_parts = NB_OF(huw_webpanel_partitions);
-		sa1100_map.size = huw_webpanel_max_flash_size;
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4()) {
+		*parts       = badge4_partitions;
+		nb_parts     = ARRAY_SIZE(badge4_partitions);
 	}
 #endif
-
-#ifdef CONFIG_SA1100_H3600
-	if (machine_is_h3600()) {
-		parts = h3600_partitions;
-		nb_parts = NB_OF(h3600_partitions);
-		sa1100_map.size = h3600_max_flash_size;
-		sa1100_map.set_vpp = h3600_set_vpp;
+#ifdef CONFIG_SA1100_CERF
+	if (machine_is_cerf()) {
+		*parts       = cerf_partitions;
+		nb_parts     = ARRAY_SIZE(cerf_partitions);
+	}
+#endif
+#ifdef CONFIG_SA1100_CONSUS
+	if (machine_is_consus()) {
+		*parts       = consus_partitions;
+		nb_parts     = ARRAY_SIZE(consus_partitions);
+	}
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+	if (machine_is_flexanet()) {
+		*parts       = flexanet_partitions;
+		nb_parts     = ARRAY_SIZE(flexanet_partitions);
 	}
 #endif
 #ifdef CONFIG_SA1100_FREEBIRD
 	if (machine_is_freebird()) {
-		parts = freebird_partitions;
-		nb_parts = NB_OF(freebird_partitions);
-		sa1100_map.size = freebird_max_flash_size;
+		*parts       = freebird_partitions;
+		nb_parts     = ARRAY_SIZE(freebird_partitions);
 	}
 #endif
-#ifdef CONFIG_SA1100_CERF
-	if (machine_is_cerf()) {
-		parts = cerf_partitions;
-		nb_parts = NB_OF(cerf_partitions);
-		sa1100_map.size = cerf_max_flash_size;
+#ifdef CONFIG_SA1100_FRODO
+	if (machine_is_frodo()) {
+		*parts       = frodo_partitions;
+		nb_parts     = ARRAY_SIZE(frodo_partitions);
 	}
-#endif
+#endif	
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 	if (machine_is_graphicsclient()) {
-		parts = graphicsclient_partitions;
-		nb_parts = NB_OF(graphicsclient_partitions);
-		sa1100_map.size = graphicsclient_max_flash_size;
-		sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
+		*parts       = graphicsclient_partitions;
+		nb_parts     = ARRAY_SIZE(graphicsclient_partitions);
 	}
 #endif
 #ifdef CONFIG_SA1100_GRAPHICSMASTER
 	if (machine_is_graphicsmaster()) {
-		parts = graphicsmaster_partitions;
-		nb_parts = NB_OF(graphicsmaster_partitions);
-		sa1100_map.size = graphicsmaster_max_flash_size;
-		sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
+		*parts       = graphicsmaster_partitions;
+		nb_parts     = ARRAY_SIZE(graphicsmaster_partitions);
 	}
 #endif
-#ifdef CONFIG_SA1100_PANGOLIN
-	if (machine_is_pangolin()) {
-		parts = pangolin_partitions;
-		nb_parts = NB_OF(pangolin_partitions);
-		sa1100_map.size = pangolin_max_flash_size;
+#ifdef CONFIG_SA1100_H3XXX
+	if (machine_is_h3xxx()) {
+		*parts       = h3xxx_partitions;
+		nb_parts     = ARRAY_SIZE(h3xxx_partitions);
+	}
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+	if (machine_is_huw_webpanel()) {
+		*parts       = huw_webpanel_partitions;
+		nb_parts     = ARRAY_SIZE(huw_webpanel_partitions);
 	}
 #endif
 #ifdef CONFIG_SA1100_JORNADA720
 	if (machine_is_jornada720()) {
-		parts = jornada720_partitions;
-		nb_parts = NB_OF(jornada720_partitions);
-		sa1100_map.size = jornada720_max_flash_size;
-		sa1100_map.set_vpp = jornada720_set_vpp;
+		*parts       = jornada720_partitions;
+		nb_parts     = ARRAY_SIZE(jornada720_partitions);
 	}
 #endif
-#ifdef CONFIG_SA1100_YOPY
-	if (machine_is_yopy()) {
-		parts = yopy_partitions;
-		nb_parts = NB_OF(yopy_partitions);
-		sa1100_map.size = yopy_max_flash_size;
+#ifdef CONFIG_SA1100_PANGOLIN
+	if (machine_is_pangolin()) {
+		*parts       = pangolin_partitions;
+		nb_parts     = ARRAY_SIZE(pangolin_partitions);
+	}
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+	if (machine_is_pt_system3()) {
+		*parts       = system3_partitions;
+		nb_parts     = ARRAY_SIZE(system3_partitions);
+	}
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+	if (machine_is_shannon()) {
+		*parts       = shannon_partitions;
+		nb_parts     = ARRAY_SIZE(shannon_partitions);
 	}
 #endif
 #ifdef CONFIG_SA1100_SHERMAN
 	if (machine_is_sherman()) {
-		parts = sherman_partitions;
-		nb_parts = NB_OF(sherman_partitions);
-		sa1100_map.size = sherman_max_flash_size;
+		*parts       = sherman_partitions;
+		nb_parts     = ARRAY_SIZE(sherman_partitions);
 	}
 #endif
-#ifdef CONFIG_SA1100_FLEXANET
-	if (machine_is_flexanet()) {
-		parts = flexanet_partitions;
-		nb_parts = NB_OF(flexanet_partitions);
-		sa1100_map.size = flexanet_max_flash_size;
+#ifdef CONFIG_SA1100_SIMPAD
+	if (machine_is_simpad()) {
+		*parts       = simpad_partitions;
+		nb_parts     = ARRAY_SIZE(simpad_partitions);
 	}
 #endif
 #ifdef CONFIG_SA1100_STORK
 	if (machine_is_stork()) {
-		parts = stork_partitions;
-		nb_parts = NB_OF(stork_partitions);
-		sa1100_map.size = stork_max_flash_size;
+		*parts       = stork_partitions;
+		nb_parts     = ARRAY_SIZE(stork_partitions);
+	}
+#endif
+#ifdef CONFIG_SA1100_TRIZEPS
+	if (machine_is_trizeps()) {
+		*parts       = trizeps_partitions;
+		nb_parts     = ARRAY_SIZE(trizeps_parititons);
+	}
+#endif
+#ifdef CONFIG_SA1100_YOPY
+	if (machine_is_yopy()) {
+		*parts       = yopy_partitions;
+		nb_parts     = ARRAY_SIZE(yopy_partitions);
 	}
 #endif
 
+	return nb_parts;
+}
+#endif
+
+struct sa_info {
+	unsigned long base;
+	unsigned long size;
+	int width;
+	void *vbase;
+	struct map_info *map;
+	struct mtd_info *mtd;
+	struct resource *res;
+};
+
+#define NR_SUBMTD 4
+
+static struct sa_info info[NR_SUBMTD];
+
+static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd)
+{
+	struct mtd_info *subdev[nr];
+	struct map_info *maps;
+	int i, found = 0, ret = 0;
+
 	/*
-	 * Now let's probe for the actual flash.  Do it here since
-	 * specific machine settings might have been set above.
+	 * Allocate the map_info structs in one go.
 	 */
-	printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8);
-	mymtd = do_map_probe("cfi_probe", &sa1100_map);
-	if (!mymtd)
-		return -ENXIO;
-	mymtd->module = THIS_MODULE;
+	maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+	if (!maps)
+		return -ENOMEM;
 
 	/*
-	 * Dynamic partition selection stuff (might override the static ones)
+	 * Claim and then map the memory regions.
 	 */
-#ifdef CONFIG_MTD_REDBOOT_PARTS
-	if (parsed_nr_parts == 0) {
-		int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-		
-		if (ret > 0) {
-			part_type = "RedBoot";
-			parsed_nr_parts = ret;
+	for (i = 0; i < nr; i++) {
+		if (sa[i].base == (unsigned long)-1)
+			break;
+
+		sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash");
+		if (!sa[i].res) {
+			ret = -EBUSY;
+			break;
+		}
+
+		sa[i].map = maps + i;
+		memcpy(sa[i].map, &sa1100_map, sizeof(struct map_info));
+
+		sa[i].vbase = ioremap(sa[i].base, sa[i].size);
+		if (!sa[i].vbase) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		sa[i].map->map_priv_1 = (unsigned long)sa[i].vbase;
+		sa[i].map->buswidth = sa[i].width;
+		sa[i].map->size = sa[i].size;
+
+		/*
+		 * Now let's probe for the actual flash.  Do it here since
+		 * specific machine settings might have been set above.
+		 */
+		sa[i].mtd = do_map_probe("cfi_probe", sa[i].map);
+		if (sa[i].mtd == NULL) {
+			ret = -ENXIO;
+			break;
 		}
+		sa[i].mtd->module = THIS_MODULE;
+		subdev[i] = sa[i].mtd;
+
+		printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
+			"%d-bit\n", sa[i].base, sa[i].mtd->size >> 20,
+			sa[i].width * 8);
+		found += 1;
+	}
+
+	/*
+	 * ENXIO is special.  It means we didn't find a chip when
+	 * we probed.  We need to tear down the mapping, free the
+	 * resource and mark it as such.
+	 */
+	if (ret == -ENXIO) {
+		iounmap(sa[i].vbase);
+		sa[i].vbase = NULL;
+		release_resource(sa[i].res);
+		sa[i].res = NULL;
 	}
+
+	/*
+	 * If we found one device, don't bother with concat support.
+	 * If we found multiple devices, use concat if we have it
+	 * available, otherwise fail.
+	 */
+	if (ret == 0 || ret == -ENXIO) {
+		if (found == 1) {
+			*rmtd = subdev[0];
+			ret = 0;
+		} else if (found > 1) {
+			/*
+			 * We detected multiple devices.  Concatenate
+			 * them together.
+			 */
+#ifdef CONFIG_MTD_CONCAT
+			*rmtd = mtd_concat_create(subdev, found,
+						  "sa1100 flash");
+			if (*rmtd == NULL)
+				ret = -ENXIO;
+#else
+			printk(KERN_ERR "SA1100 flash: multiple devices "
+			       "found but MTD concat support disabled.\n");
+			ret = -ENXIO;
 #endif
-#ifdef CONFIG_MTD_BOOTLDR_PARTS
-	if (parsed_nr_parts == 0) {
-		int ret = parse_bootldr_partitions(mymtd, &parsed_parts);
-		if (ret > 0) {
-			part_type = "Compaq bootldr";
-			parsed_nr_parts = ret;
 		}
 	}
-#endif
 
-	if (parsed_nr_parts > 0) {
-		parts = parsed_parts;
-		nb_parts = parsed_nr_parts;
+	/*
+	 * If we failed, clean up.
+	 */
+	if (ret) {
+		do {
+			if (sa[i].mtd)
+				map_destroy(sa[i].mtd);
+			if (sa[i].vbase)
+				iounmap(sa[i].vbase);
+			if (sa[i].res)
+				release_resource(sa[i].res);
+		} while (i--);
+
+		kfree(maps);
+	}
+
+	return ret;
+}
+
+static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd)
+{
+	int i;
+
+	del_mtd_partitions(mtd);
+
+	if (mtd != sa[0].mtd)
+		mtd_concat_destroy(mtd);
+
+	for (i = NR_SUBMTD; i >= 0; i--) {
+		if (sa[i].mtd)
+			map_destroy(sa[i].mtd);
+		if (sa[i].vbase)
+			iounmap(sa[i].vbase);
+		if (sa[i].res)
+			release_resource(sa[i].res);
+	}
+	kfree(sa[0].map);
+}
+
+static int __init sa1100_locate_flash(void)
+{
+	int i, nr = -ENODEV;
+
+	if (machine_is_adsbitsy()) {
+		info[0].base = SA1100_CS1_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_assabet()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		info[1].base = SA1100_CS1_PHYS; /* neponset */
+		info[1].size = SZ_32M;
+		nr = 2;
+	}
+	if (machine_is_badge4()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_4M;
+		nr = 1;
+	}
+	if (machine_is_cerf()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_consus()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_flexanet()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_freebird()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_frodo()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_graphicsclient()) {
+		info[0].base = SA1100_CS1_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_graphicsmaster()) {
+		info[0].base = SA1100_CS1_PHYS;
+		info[0].size = SZ_16M;
+		nr = 1;
+	}
+	if (machine_is_h3xxx()) {
+		sa1100_map.set_vpp = h3xxx_set_vpp;
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_huw_webpanel()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_16M;
+		nr = 1;
+	}
+	if (machine_is_itsy()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_jornada720()) {
+		sa1100_map.set_vpp = jornada720_set_vpp;
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_nanoengine()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[1].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_pangolin()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_64M;
+		nr = 1;
+	}
+	if (machine_is_pfs168()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_pleb()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_4M;
+		info[1].base = SA1100_CS1_PHYS;
+		info[1].size = SZ_4M;
+		nr = 2;
+	}
+	if (machine_is_pt_system3()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_16M;
+		nr = 1;
+	}
+	if (machine_is_shannon()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_4M;
+		nr = 1;
+	}
+	if (machine_is_sherman()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_simpad()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_stork()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_32M;
+		nr = 1;
+	}
+	if (machine_is_trizeps()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_16M;
+		nr = 1;
+	}
+	if (machine_is_victor()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_2M;
+		nr = 1;
+	}
+	if (machine_is_yopy()) {
+		info[0].base = SA1100_CS0_PHYS;
+		info[0].size = SZ_64M;
+		info[1].base = SA1100_CS1_PHYS;
+		info[1].size = SZ_64M;
+		nr = 2;
+	}
+
+	if (nr < 0)
+		return nr;
+
+	/*
+	 * Retrieve the buswidth from the MSC registers.
+	 * We currently only implement CS0 and CS1 here.
+	 */
+	for (i = 0; i < nr; i++) {
+		switch (info[i].base) {
+		default:
+			printk(KERN_WARNING "SA1100 flash: unknown base address "
+				"0x%08lx, assuming CS0\n", info[i].base);
+		case SA1100_CS0_PHYS:
+			info[i].width = (MSC0 & MSC_RBW) ? 2 : 4;
+			break;
+
+		case SA1100_CS1_PHYS:
+			info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
+			break;
+		}
 	}
 
-	if (nb_parts == 0) {
-		printk(KERN_NOTICE "SA1100 flash: no partition info available, registering whole flash at once\n");
-		add_mtd_device(mymtd);
+	return nr;
+}
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+
+static struct mtd_partition *parsed_parts;
+
+static void __init sa1100_locate_partitions(struct mtd_info *mtd)
+{
+	const char *part_type = NULL;
+	int nr_parts = 0;
+
+	do {
+		/*
+		 * Partition selection stuff.
+		 */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+		nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "sa1100");
+		if (nr_parts > 0) {
+			part_type = "command line";
+			break;
+		}
+#endif
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+		nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "RedBoot";
+			break;
+		}
+#endif
+#ifdef CONFIG_MTD_SA1100_STATICMAP
+		nr_parts = sa1100_static_partitions(&parsed_parts);
+		if (nr_parts > 0) {
+			part_type = "static";
+			break;
+		}
+#endif
+	} while (0);
+
+	if (nr_parts == 0) {
+		printk(KERN_NOTICE "SA1100 flash: no partition info "
+			"available, registering whole flash\n");
+		add_mtd_device(mtd);
 	} else {
-		printk(KERN_NOTICE "Using %s partition definition\n", part_type);
-		add_mtd_partitions(mymtd, parts, nb_parts);
+		printk(KERN_NOTICE "SA1100 flash: using %s partition "
+			"definition\n", part_type);
+		add_mtd_partitions(mtd, parsed_parts, nr_parts);
 	}
-	return 0;
+
+	/* Always succeeds. */
+}
+
+static void __exit sa1100_destroy_partitions(void)
+{
+	if (parsed_parts)
+		kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init sa1100_mtd_init(void)
+{
+	int ret;
+	int nr;
+
+	nr = sa1100_locate_flash();
+	if (nr < 0)
+		return nr;
+
+	ret = sa1100_setup_mtd(info, nr, &mymtd);
+	if (ret == 0)
+		sa1100_locate_partitions(mymtd);
+
+	return ret;
 }
 
 static void __exit sa1100_mtd_cleanup(void)
 {
-	if (mymtd) {
-		del_mtd_partitions(mymtd);
-		map_destroy(mymtd);
-		if (parsed_parts)
-			kfree(parsed_parts);
-	}
+	sa1100_destroy_mtd(info, mymtd);
+	sa1100_destroy_partitions();
 }
 
 module_init(sa1100_mtd_init);
diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
--- a/drivers/mtd/mtdblock.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/mtd/mtdblock.c	Tue Oct 15 20:29:16 2002
@@ -295,7 +295,7 @@
 	spin_unlock(&mtdblks_lock);
 
 	mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
-	disk = alloc_disk();
+	disk = alloc_disk(1);
 	if (!mtdblk || !disk)
 		goto Enomem;
 	memset(mtdblk, 0, sizeof(*mtdblk));
@@ -313,7 +313,6 @@
 	}
 	disk->major = MAJOR_NR;
 	disk->first_minor = dev;
-	disk->minor_shift = 0;
 	disk->fops = &mtd_fops;
 	sprintf(disk->disk_name, "mtd%d", dev);
 	mtdblk->disk = disk;
@@ -518,8 +517,6 @@
 
 	switch (cmd) {
 	case BLKFLSBUF:
-		if(!capable(CAP_SYS_ADMIN))
-			return -EACCES;
 		fsync_bdev(inode->i_bdev);
 		invalidate_bdev(inode->i_bdev, 0);
 		down(&mtdblk->cache_sem);
diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
--- a/drivers/mtd/mtdblock_ro.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/mtd/mtdblock_ro.c	Tue Oct 15 20:29:17 2002
@@ -15,6 +15,8 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/compatmac.h>
+#include <linux/buffer_head.h>
+#include <linux/genhd.h>
 
 #define LOCAL_END_REQUEST
 #define MAJOR_NR MTD_BLOCK_MAJOR
@@ -47,7 +49,7 @@
 		return -EINVAL;
 	}
 
-	set_capacit(disk, mtd->size>>9);
+	set_capacity(disk, mtd->size>>9);
 	add_disk(disk);
 
 	DEBUG(1, "ok\n");
@@ -119,7 +121,7 @@
 
       mtd = __get_mtd_device(NULL, minor(current_request->rq_dev));
       if (!mtd) {
-	      printk("MTD device %d doesn't appear to exist any more\n", DEVICE_NR(CURRENT->rq_dev));
+	      printk("MTD device %s doesn't appear to exist any more\n", kdevname(DEVICE_NR(CURRENT->rq_dev)));
 	      mtdblock_end_request(current_request, 0);
       }
 
@@ -199,8 +201,6 @@
 	if (!mtd || cmd != BLKFLSBUF)
 		return -EINVAL;
 
-	if(!capable(CAP_SYS_ADMIN))
-		return -EACCES;
 	fsync_bdev(inode->i_bdev);
 	invalidate_bdev(inode->i_bdev, 0);
 	if (mtd->sync)
@@ -222,7 +222,7 @@
 	int i;
 
 	for (i = 0; i < MAX_MTD_DEVICES; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(1);
 		if (!disk)
 			goto out;
 		disk->major = MAJOR_NR;
diff -Nru a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/mtd/mtdconcat.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,675 @@
+/*
+ * MTD device concatenation layer
+ *
+ * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
+ *
+ * This code is GPL
+ *
+ * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
+
+/*
+ * Our storage structure:
+ * Subdev points to an array of pointers to struct mtd_info objects
+ * which is allocated along with this structure
+ *
+ */
+struct mtd_concat {
+	struct mtd_info mtd;
+	int             num_subdev;
+	struct mtd_info **subdev;
+};
+
+/*
+ * how to calculate the size required for the above structure,
+ * including the pointer array subdev points to:
+ */
+#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev)	\
+	((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
+
+
+/*
+ * Given a pointer to the MTD object in the mtd_concat structure,
+ * we can retrieve the pointer to that structure with this macro.
+ */
+#define CONCAT(x)  ((struct mtd_concat *)(x))
+
+	
+/* 
+ * MTD methods which look up the relevant subdevice, translate the
+ * effective address and pass through to the subdevice.
+ */
+
+static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, 
+			size_t *retlen, u_char *buf)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int err = -EINVAL;
+	int i;
+
+	*retlen = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, retsize;
+
+		if (from >= subdev->size)
+		{
+			size  = 0;
+			from -= subdev->size;
+		}
+		else
+		{
+			if (from + len > subdev->size)
+				size = subdev->size - from;
+			else
+				size = len;
+
+			err = subdev->read(subdev, from, size, &retsize, buf);
+
+			if(err)
+				break;
+
+			*retlen += retsize;
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			buf += size;
+			from = 0;
+		}
+	}
+	return err;
+}
+
+static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int err = -EINVAL;
+	int i;
+
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+
+	*retlen = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, retsize;
+
+		if (to >= subdev->size)
+		{
+			size  = 0;
+			to -= subdev->size;
+		}
+		else
+		{
+			if (to + len > subdev->size)
+				size = subdev->size - to;
+			else
+				size = len;
+
+			if (!(subdev->flags & MTD_WRITEABLE))
+				err = -EROFS;
+			else
+				err = subdev->write(subdev, to, size, &retsize, buf);
+
+			if(err)
+				break;
+
+			*retlen += retsize;
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			buf += size;
+			to = 0;
+		}
+	}
+	return err;
+}
+
+static void concat_erase_callback (struct erase_info *instr)
+{
+	wake_up((wait_queue_head_t *)instr->priv);
+}
+
+static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+	int err;
+	wait_queue_head_t waitq;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 * This code was stol^H^H^H^Hinspired by mtdchar.c
+	 */
+	init_waitqueue_head(&waitq);
+
+	erase->mtd = mtd;
+	erase->callback = concat_erase_callback;
+	erase->priv = (unsigned long)&waitq;
+			
+	/*
+	 * FIXME: Allow INTERRUPTIBLE. Which means
+	 * not having the wait_queue head on the stack.
+	 */
+	err = mtd->erase(mtd, erase);
+	if (!err)
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&waitq, &wait);
+		if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
+			schedule();
+		remove_wait_queue(&waitq, &wait);
+		set_current_state(TASK_RUNNING);
+
+		err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0;
+	}
+	return err;
+}
+
+static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	struct mtd_info *subdev;
+	int i, err;
+	u_int32_t length;
+	struct erase_info *erase;
+
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+
+	if(instr->addr > concat->mtd.size)
+		return -EINVAL;
+
+	if(instr->len + instr->addr > concat->mtd.size)
+		return -EINVAL;
+
+	/*
+	 * Check for proper erase block alignment of the to-be-erased area.
+	 * It is easier to do this based on the super device's erase
+	 * region info rather than looking at each particular sub-device
+	 * in turn.
+	 */
+	if (!concat->mtd.numeraseregions)
+	{	/* the easy case: device has uniform erase block size */
+		if(instr->addr & (concat->mtd.erasesize - 1))
+			return -EINVAL;
+		if(instr->len & (concat->mtd.erasesize - 1))
+			return -EINVAL;
+	}
+	else
+	{	/* device has variable erase size */
+		struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
+
+		/*
+		 * Find the erase region where the to-be-erased area begins:
+		 */
+		for(i = 0; i < concat->mtd.numeraseregions && 
+		           instr->addr >= erase_regions[i].offset; i++)
+			;
+		--i;
+
+		/*
+		 * Now erase_regions[i] is the region in which the
+		 * to-be-erased area begins. Verify that the starting
+		 * offset is aligned to this region's erase size:
+		 */
+		if (instr->addr & (erase_regions[i].erasesize-1))
+			return -EINVAL;
+
+		/*
+		 * now find the erase region where the to-be-erased area ends:
+		 */
+		for(; i < concat->mtd.numeraseregions && 
+		      (instr->addr + instr->len) >=  erase_regions[i].offset ; ++i)
+			;
+		--i;
+		/*
+		 * check if the ending offset is aligned to this region's erase size
+		 */
+		if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
+			return -EINVAL;
+	}
+
+	/* make a local copy of instr to avoid modifying the caller's struct */
+	erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+
+	if (!erase)
+		return -ENOMEM;
+
+	*erase = *instr;
+	length = instr->len;
+
+	/*
+	 * find the subdevice where the to-be-erased area begins, adjust
+	 * starting offset to be relative to the subdevice start
+	 */
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		subdev = concat->subdev[i];
+		if(subdev->size <= erase->addr)
+			erase->addr -= subdev->size;
+		else
+			break;
+    }
+	if(i >= concat->num_subdev)	/* must never happen since size */
+		BUG();					/* limit has been verified above */
+
+	/* now do the erase: */
+	err = 0;
+	for(;length > 0; i++)	/* loop for all subevices affected by this request */
+	{
+		subdev = concat->subdev[i];		/* get current subdevice */
+
+		/* limit length to subdevice's size: */
+		if(erase->addr + length > subdev->size)
+			erase->len = subdev->size - erase->addr;
+		else
+			erase->len = length;
+
+		if (!(subdev->flags & MTD_WRITEABLE))
+		{
+			err = -EROFS;
+			break;
+		}
+		length -= erase->len;
+		if ((err = concat_dev_erase(subdev, erase)))
+		{
+			if(err == -EINVAL)	/* sanity check: must never happen since */
+				BUG();			/* block alignment has been checked above */
+			break;
+		}
+		/*
+		 * erase->addr specifies the offset of the area to be
+		 * erased *within the current subdevice*. It can be
+		 * non-zero only the first time through this loop, i.e.
+		 * for the first subdevice where blocks need to be erased.
+		 * All the following erases must begin at the start of the
+		 * current subdevice, i.e. at offset zero.
+		 */
+		erase->addr = 0;
+	}
+	kfree(erase);
+	if (err)
+		return err;
+
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+	return 0;
+}
+
+static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i, err = -EINVAL;
+
+	if ((len + ofs) > mtd->size) 
+		return -EINVAL;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size;
+
+		if (ofs >= subdev->size)
+		{
+			size  = 0;
+			ofs -= subdev->size;
+		}
+		else
+		{
+			if (ofs + len > subdev->size)
+				size = subdev->size - ofs;
+			else
+				size = len;
+
+			err = subdev->lock(subdev, ofs, size);
+
+			if(err)
+				break;
+
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			ofs = 0;
+		}
+	}
+	return err;
+}
+
+static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i, err = 0;
+
+	if ((len + ofs) > mtd->size) 
+		return -EINVAL;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size;
+
+		if (ofs >= subdev->size)
+		{
+			size  = 0;
+			ofs -= subdev->size;
+		}
+		else
+		{
+			if (ofs + len > subdev->size)
+				size = subdev->size - ofs;
+			else
+				size = len;
+
+			err = subdev->unlock(subdev, ofs, size);
+
+			if(err)
+				break;
+
+			len -= size;
+			if(len == 0)
+				break;
+
+			err = -EINVAL;
+			ofs = 0;
+		}
+	}
+	return err;
+}
+
+static void concat_sync(struct mtd_info *mtd)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		subdev->sync(subdev);
+	}
+}
+
+static int concat_suspend(struct mtd_info *mtd)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i, rc = 0;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		if((rc = subdev->suspend(subdev)) < 0)
+			return rc;
+	}
+	return rc;
+}
+
+static void concat_resume(struct mtd_info *mtd)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i;
+
+	for(i = 0; i < concat->num_subdev; i++)
+	{
+		struct mtd_info *subdev = concat->subdev[i];
+		subdev->resume(subdev);
+	}
+}
+
+/*
+ * This function constructs a virtual MTD device by concatenating
+ * num_devs MTD devices. A pointer to the new device object is
+ * stored to *new_dev upon success. This function does _not_
+ * register any devices: this is the caller's responsibility.
+ */
+struct mtd_info *mtd_concat_create(
+	struct mtd_info *subdev[],	/* subdevices to concatenate */
+	int num_devs,				/* number of subdevices      */
+	char *name)					/* name for the new device   */
+{
+	int i;
+	size_t size;
+	struct mtd_concat *concat;
+	u_int32_t max_erasesize, curr_erasesize;
+	int num_erase_region;
+
+	printk(KERN_NOTICE "Concatenating MTD devices:\n");
+	for(i = 0; i < num_devs; i++)
+		printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
+	printk(KERN_NOTICE "into device \"%s\"\n", name);
+
+	/* allocate the device structure */
+	size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
+	concat = kmalloc (size, GFP_KERNEL);
+	if(!concat)
+	{
+		printk ("memory allocation error while creating concatenated device \"%s\"\n",
+				name);
+			return NULL;
+	}
+	memset(concat, 0, size);
+	concat->subdev = (struct mtd_info **)(concat + 1);
+
+	/*
+	 * Set up the new "super" device's MTD object structure, check for
+	 * incompatibilites between the subdevices.
+	 */
+	concat->mtd.type      = subdev[0]->type;
+	concat->mtd.flags     = subdev[0]->flags;
+	concat->mtd.size      = subdev[0]->size;
+	concat->mtd.erasesize = subdev[0]->erasesize;
+	concat->mtd.oobblock  = subdev[0]->oobblock;
+	concat->mtd.oobsize   = subdev[0]->oobsize;
+	concat->mtd.ecctype   = subdev[0]->ecctype;
+	concat->mtd.eccsize   = subdev[0]->eccsize;
+
+	concat->subdev[0]   = subdev[0];
+
+	for(i = 1; i < num_devs; i++)
+	{
+		if(concat->mtd.type != subdev[i]->type)
+		{
+			kfree(concat);
+			printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
+			return NULL;
+		}
+		if(concat->mtd.flags != subdev[i]->flags)
+		{	/*
+			 * Expect all flags except MTD_WRITEABLE to be equal on
+			 * all subdevices.
+			 */
+			if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
+			{
+				kfree(concat);
+				printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
+				return NULL;
+			}
+			else	/* if writeable attribute differs, make super device writeable */
+				concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
+		}
+		concat->mtd.size += subdev[i]->size;
+		if(concat->mtd.oobblock != subdev[i]->oobblock ||
+		   concat->mtd.oobsize  != subdev[i]->oobsize  ||
+		   concat->mtd.ecctype  != subdev[i]->ecctype  ||
+		   concat->mtd.eccsize  != subdev[i]->eccsize)
+		{
+			kfree(concat);
+			printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
+			return NULL;
+		}
+		concat->subdev[i] = subdev[i];
+		
+	}
+
+	concat->num_subdev  = num_devs;
+	concat->mtd.name    = name;
+
+	/*
+	 * NOTE: for now, we do not provide any readv()/writev() methods
+	 *       because they are messy to implement and they are not
+	 *       used to a great extent anyway.
+	 */
+	concat->mtd.erase   = concat_erase;
+	concat->mtd.read    = concat_read;
+	concat->mtd.write   = concat_write;
+	concat->mtd.sync    = concat_sync;
+	concat->mtd.lock    = concat_lock;
+	concat->mtd.unlock  = concat_unlock;
+	concat->mtd.suspend = concat_suspend;
+	concat->mtd.resume  = concat_resume;
+
+
+	/*
+	 * Combine the erase block size info of the subdevices:
+	 *
+	 * first, walk the map of the new device and see how
+	 * many changes in erase size we have
+	 */
+	max_erasesize = curr_erasesize = subdev[0]->erasesize;
+	num_erase_region = 1;
+	for(i = 0; i < num_devs; i++)
+	{
+		if(subdev[i]->numeraseregions == 0)
+		{	/* current subdevice has uniform erase size */
+			if(subdev[i]->erasesize != curr_erasesize)
+			{	/* if it differs from the last subdevice's erase size, count it */
+				++num_erase_region;
+				curr_erasesize = subdev[i]->erasesize;
+				if(curr_erasesize > max_erasesize)
+					max_erasesize = curr_erasesize;
+			}
+		}
+		else
+		{	/* current subdevice has variable erase size */
+			int j;
+			for(j = 0; j < subdev[i]->numeraseregions; j++)
+			{	/* walk the list of erase regions, count any changes */
+				if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+				{
+					++num_erase_region;
+					curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+					if(curr_erasesize > max_erasesize)
+						max_erasesize = curr_erasesize;
+				}
+			}
+		}
+	}
+
+	if(num_erase_region == 1)
+	{	/*
+		 * All subdevices have the same uniform erase size.
+		 * This is easy:
+		 */
+		concat->mtd.erasesize = curr_erasesize;
+		concat->mtd.numeraseregions = 0;
+	}
+	else
+	{	/*
+		 * erase block size varies across the subdevices: allocate
+		 * space to store the data describing the variable erase regions
+		 */
+		struct mtd_erase_region_info *erase_region_p;
+		u_int32_t begin, position;
+
+		concat->mtd.erasesize = max_erasesize;
+		concat->mtd.numeraseregions = num_erase_region;
+		concat->mtd.eraseregions = erase_region_p = kmalloc (
+		     num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+		if(!erase_region_p)
+		{
+			kfree(concat);
+			printk ("memory allocation error while creating erase region list"
+			        " for device \"%s\"\n", name);
+			return NULL;
+		}
+
+		/*
+		 * walk the map of the new device once more and fill in
+		 * in erase region info:
+		 */
+		curr_erasesize = subdev[0]->erasesize;
+		begin = position = 0;
+		for(i = 0; i < num_devs; i++)
+		{
+			if(subdev[i]->numeraseregions == 0)
+			{	/* current subdevice has uniform erase size */
+				if(subdev[i]->erasesize != curr_erasesize)
+				{	/*
+					 *  fill in an mtd_erase_region_info structure for the area
+					 *  we have walked so far:
+					 */
+					erase_region_p->offset    = begin;
+					erase_region_p->erasesize = curr_erasesize;
+					erase_region_p->numblocks = (position - begin) / curr_erasesize;
+					begin = position;
+
+					curr_erasesize = subdev[i]->erasesize;
+					++erase_region_p;
+				}
+				position += subdev[i]->size;
+			}
+			else
+			{	/* current subdevice has variable erase size */
+				int j;
+				for(j = 0; j < subdev[i]->numeraseregions; j++)
+				{	/* walk the list of erase regions, count any changes */
+					if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+					{
+						erase_region_p->offset    = begin;
+						erase_region_p->erasesize = curr_erasesize;
+						erase_region_p->numblocks = (position - begin) / curr_erasesize;
+						begin = position;
+
+						curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+						++erase_region_p;
+					}
+					position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
+				}
+			}
+		}
+		/* Now write the final entry */
+		erase_region_p->offset    = begin;
+		erase_region_p->erasesize = curr_erasesize;
+		erase_region_p->numblocks = (position - begin) / curr_erasesize;
+	}
+
+	return &concat->mtd;
+}
+
+/* 
+ * This function destroys an MTD object obtained from concat_mtd_devs()
+ */
+
+void mtd_concat_destroy(struct mtd_info *mtd)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	if(concat->mtd.numeraseregions)
+		kfree(concat->mtd.eraseregions);
+	kfree(concat);
+}
+
+
+EXPORT_SYMBOL(mtd_concat_create);
+EXPORT_SYMBOL(mtd_concat_destroy);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
+MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
--- a/drivers/mtd/nftlcore.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/mtd/nftlcore.c	Tue Oct 15 20:29:11 2002
@@ -74,7 +74,7 @@
         }
 
 	nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
-	gd = alloc_disk();
+	gd = alloc_disk(1 << NFTL_PARTN_BITS);
 	if (!nftl || !gd) {
 		kfree(nftl);
 		put_disk(gd);
@@ -132,7 +132,6 @@
 	sprintf(gd->disk_name, "nftl%c", 'a' + firstfree);
 	gd->major = MAJOR_NR;
 	gd->first_minor = firstfree << NFTL_PARTN_BITS;
-	gd->minor_shift = NFTL_PARTN_BITS;
 	set_capacity(gd, nftl->nr_sects);
 	nftl->disk = gd;
 	add_disk(gd);
@@ -771,7 +770,6 @@
 		return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
 	}
 	case BLKFLSBUF:
-		if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 		fsync_bdev(inode->i_bdev);
 		invalidate_bdev(inode->i_bdev, 0);
 		if (nftl->mtd->sync)
diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c
--- a/drivers/net/pppoe.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/net/pppoe.c	Tue Oct 15 20:29:17 2002
@@ -5,7 +5,7 @@
  * PPPoE --- PPP over Ethernet (RFC 2516)
  *
  *
- * Version:    0.6.10
+ * Version:    0.6.11
  *
  * 220102 :	Fix module use count on failure in pppoe_create, pppox_sk -acme
  * 030700 :     Fixed connect logic to allow for disconnect.
@@ -35,6 +35,7 @@
  * 121301 :     New ppp channels interface; cannot unregister a channel
  *              from interrupts.  Thus, we mark the socket as a ZOMBIE
  *              and do the unregistration later.
+ * 081002 :	seq_file support for proc stuff -acme
  *
  * Author:	Michal Ostrowski <mostrows@speakeasy.net>
  * Contributors:
@@ -75,6 +76,7 @@
 #include <linux/notifier.h>
 #include <linux/file.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 
 
@@ -773,7 +775,7 @@
 }
 
 
-int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
+int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
 		  int total_len, struct scm_cookie *scm)
 {
 	struct sk_buff *skb = NULL;
@@ -934,7 +936,7 @@
 
 struct ppp_channel_ops pppoe_chan_ops = { pppoe_xmit , NULL };
 
-int pppoe_rcvmsg(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm)
+int pppoe_rcvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sk_buff *skb = NULL;
@@ -974,63 +976,102 @@
 	return error;
 }
 
-int pppoe_proc_info(char *buffer, char **start, off_t offset, int length)
+#ifdef CONFIG_PROC_FS
+static int pppoe_seq_show(struct seq_file *seq, void *v)
 {
 	struct pppox_opt *po;
-	int len = 0;
-	off_t pos = 0;
-	off_t begin = 0;
-	int size;
-	int i;
+	char *dev_name;
 
-	len += sprintf(buffer,
-		       "Id       Address              Device\n");
-	pos = len;
+	if (v == (void *)1) {
+		seq_puts(seq, "Id       Address              Device\n");
+		goto out;
+	}
 
-	write_lock_bh(&pppoe_hash_lock);
+	po = v;
+	dev_name = po->pppoe_pa.dev;
+
+	seq_printf(seq, "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n",
+		   po->pppoe_pa.sid,
+		   po->pppoe_pa.remote[0], po->pppoe_pa.remote[1],
+		   po->pppoe_pa.remote[2], po->pppoe_pa.remote[3],
+		   po->pppoe_pa.remote[4], po->pppoe_pa.remote[5], dev_name);
+out:
+  	return 0;
+}
 
-	for (i = 0; i < PPPOE_HASH_SIZE; i++) {
+static __inline__ struct pppox_opt *pppoe_get_idx(loff_t pos)
+{
+	struct pppox_opt *po = NULL;
+	int i = 0;
+
+	for (; i < PPPOE_HASH_SIZE; i++) {
 		po = item_hash_table[i];
 		while (po) {
-			char *dev = po->pppoe_pa.dev;
+			if (!pos--)
+				goto out;
+			po = po->next;
+		}
+	}
+out:
+	return po;
+}
 
-			size = sprintf(buffer + len,
-				       "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n",
-				       po->pppoe_pa.sid,
-				       po->pppoe_pa.remote[0],
-				       po->pppoe_pa.remote[1],
-				       po->pppoe_pa.remote[2],
-				       po->pppoe_pa.remote[3],
-				       po->pppoe_pa.remote[4],
-				       po->pppoe_pa.remote[5],
-				       dev);
-			len += size;
-			pos += size;
-			if (pos < offset) {
-				len = 0;
-				begin = pos;
-			}
+static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	loff_t l = *pos;
 
-			if (pos > offset + length)
-				break;
+	read_lock_bh(&pppoe_hash_lock);
+	return l ? pppoe_get_idx(--l) : (void *)1;
+}
 
-			po = po->next;
+static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct pppox_opt *po;
+
+	++*pos;
+	if (v == (void *)1) {
+		po = pppoe_get_idx(0);
+		goto out;
+	}
+	po = v;
+	po = po->next;
+	if (!po) {
+		int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
+
+		while (++hash < PPPOE_HASH_SIZE) {
+			po = item_hash_table[hash];
+			if (po)
+				break;
 		}
+	}
+out:
+	return po;
+}
 
-		if (po)
-			break;
-  	}
-	write_unlock_bh(&pppoe_hash_lock);
+static void pppoe_seq_stop(struct seq_file *seq, void *v)
+{
+	read_unlock_bh(&pppoe_hash_lock);
+}
+
+struct seq_operations pppoe_seq_ops = {
+	.start		= pppoe_seq_start,
+	.next		= pppoe_seq_next,
+	.stop		= pppoe_seq_stop,
+	.show		= pppoe_seq_show,
+};
 
-  	*start = buffer + (offset - begin);
-  	len -= (offset - begin);
-  	if (len > length)
-  		len = length;
-	if (len < 0)
-		len = 0;
-  	return len;
+static int pppoe_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &pppoe_seq_ops);
 }
 
+static struct file_operations pppoe_seq_fops = {
+	.open           = pppoe_seq_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release        = seq_release,
+};
+#endif /* CONFIG_PROC_FS */
 
 struct proto_ops pppoe_ops = {
     .family		= AF_PPPOX,
@@ -1061,13 +1102,28 @@
 {
  	int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto);
 
-	if (err == 0) {
-		dev_add_pack(&pppoes_ptype);
-		dev_add_pack(&pppoed_ptype);
-		register_netdevice_notifier(&pppoe_notifier);
-		proc_net_create("pppoe", 0, pppoe_proc_info);
-	}
+	if (err)
+		goto out;
+#ifdef CONFIG_PROC_FS
+{
+	struct proc_dir_entry *p = create_proc_entry("pppoe", S_IRUGO,
+						     proc_net);
+	err = -ENOMEM;
+	if (!p)
+		goto out_unregister;
+	
+	p->proc_fops = &pppoe_seq_fops;
+	err = 0;
+}
+#endif /* CONFIG_PROC_FS */
+	dev_add_pack(&pppoes_ptype);
+	dev_add_pack(&pppoed_ptype);
+	register_netdevice_notifier(&pppoe_notifier);
+out:
 	return err;
+out_unregister:
+	unregister_pppox_proto(PX_PROTO_OE);
+	goto out;
 }
 
 void __exit pppoe_exit(void)
@@ -1076,7 +1132,7 @@
 	dev_remove_pack(&pppoes_ptype);
 	dev_remove_pack(&pppoed_ptype);
 	unregister_netdevice_notifier(&pppoe_notifier);
-	proc_net_remove("pppoe");
+	remove_proc_entry("pppoe", proc_net);
 }
 
 module_init(pppoe_init);
diff -Nru a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
--- a/drivers/net/wan/syncppp.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/net/wan/syncppp.c	Tue Oct 15 20:29:15 2002
@@ -1284,12 +1284,12 @@
 {
 	struct sppp *sp = (struct sppp*) arg;
 	unsigned long flags;
-	save_flags(flags);
-	cli();
+
+	spin_lock_irqsave(&spppq_lock, flags);
 
 	sp->pp_flags &= ~PP_TIMO;
 	if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&spppq_lock, flags);
 		return;
 	}
 	switch (sp->lcp.state) {
@@ -1328,7 +1328,7 @@
 		}
 		break;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&spppq_lock, flags);
 }
 
 static char *sppp_lcp_type_name (u8 type)
diff -Nru a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/buffer_sync.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,394 @@
+/**
+ * @file buffer_sync.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ *
+ * This is the core of the buffer management. Each
+ * CPU buffer is processed and entered into the
+ * global event buffer. Such processing is necessary
+ * in several circumstances, mentioned below.
+ *
+ * The processing does the job of converting the
+ * transitory EIP value into a persistent dentry/offset
+ * value that the profiler can record at its leisure.
+ *
+ * See fs/dcookies.c for a description of the dentry/offset
+ * objects.
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/dcookies.h>
+#include <linux/notifier.h>
+#include <linux/profile.h>
+#include <linux/workqueue.h>
+
+#include "event_buffer.h"
+#include "cpu_buffer.h"
+#include "oprofile_stats.h"
+ 
+#define DEFAULT_EXPIRE (HZ / 4)
+ 
+static void wq_sync_buffers(void *);
+static DECLARE_WORK(sync_wq, wq_sync_buffers, 0);
+ 
+static struct timer_list sync_timer;
+static void timer_ping(unsigned long data);
+static void sync_cpu_buffers(void);
+
+ 
+/* We must make sure to process every entry in the CPU buffers
+ * before a task got the PF_EXITING flag, otherwise we will hold
+ * references to a possibly freed task_struct. We are safe with
+ * samples past the PF_EXITING point in do_exit(), because we
+ * explicitly check for that in cpu_buffer.c 
+ */
+static int exit_task_notify(struct notifier_block * self, unsigned long val, void * data)
+{
+	sync_cpu_buffers();
+	return 0;
+}
+ 
+/* There are two cases of tasks modifying task->mm->mmap list we
+ * must concern ourselves with. First, when a task is about to
+ * exit (exit_mmap()), we should process the buffer to deal with
+ * any samples in the CPU buffer, before we lose the ->mmap information
+ * we need. Second, a task may unmap (part of) an executable mmap,
+ * so we want to process samples before that happens too
+ */
+static int mm_notify(struct notifier_block * self, unsigned long val, void * data)
+{
+	sync_cpu_buffers();
+	return 0;
+}
+
+ 
+static struct notifier_block exit_task_nb = {
+	.notifier_call	= exit_task_notify,
+};
+
+static struct notifier_block exec_unmap_nb = {
+	.notifier_call	= mm_notify,
+};
+
+static struct notifier_block exit_mmap_nb = {
+	.notifier_call	= mm_notify,
+};
+ 
+ 
+int sync_start(void)
+{
+	int err = profile_event_register(EXIT_TASK, &exit_task_nb);
+	if (err)
+		goto out;
+	err = profile_event_register(EXIT_MMAP, &exit_mmap_nb);
+	if (err)
+		goto out2;
+	err = profile_event_register(EXEC_UNMAP, &exec_unmap_nb);
+	if (err)
+		goto out3;
+ 
+	sync_timer.function = timer_ping;
+	sync_timer.expires = jiffies + DEFAULT_EXPIRE;
+	add_timer(&sync_timer);
+out:
+	return err;
+out3:
+	profile_event_unregister(EXIT_MMAP, &exit_mmap_nb);
+out2:
+	profile_event_unregister(EXIT_TASK, &exit_task_nb);
+	goto out;
+}
+
+
+void sync_stop(void)
+{
+	profile_event_unregister(EXIT_TASK, &exit_task_nb);
+	profile_event_unregister(EXIT_MMAP, &exit_mmap_nb);
+	profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb);
+	del_timer_sync(&sync_timer);
+}
+
+ 
+/* Optimisation. We can manage without taking the dcookie sem
+ * because we cannot reach this code without at least one
+ * dcookie user still being registered (namely, the reader
+ * of the event buffer). */
+static inline u32 fast_get_dcookie(struct dentry * dentry,
+	struct vfsmount * vfsmnt)
+{
+	u32 cookie;
+ 
+	if (dentry->d_cookie)
+		return (u32)dentry;
+	get_dcookie(dentry, vfsmnt, &cookie);
+	return cookie;
+}
+
+ 
+/* Look up the dcookie for the task's first VM_EXECUTABLE mapping,
+ * which corresponds loosely to "application name". This is
+ * not strictly necessary but allows oprofile to associate
+ * shared-library samples with particular applications
+ */
+static u32 get_exec_dcookie(struct mm_struct * mm)
+{
+	u32 cookie = 0;
+	struct vm_area_struct * vma;
+ 
+	if (!mm)
+		goto out;
+ 
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		if (!vma->vm_file)
+			continue;
+		if (!vma->vm_flags & VM_EXECUTABLE)		
+			continue;
+		cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+			vma->vm_file->f_vfsmnt);
+		break;
+	}
+
+out:
+	return cookie;
+}
+
+
+/* Convert the EIP value of a sample into a persistent dentry/offset
+ * pair that can then be added to the global event buffer. We make
+ * sure to do this lookup before a mm->mmap modification happens so
+ * we don't lose track.
+ */
+static u32 lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
+{
+	u32 cookie = 0;
+	struct vm_area_struct * vma;
+
+	for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
+		if (!vma)
+			goto out;
+ 
+		if (!vma->vm_file)
+			continue;
+
+		if (addr < vma->vm_start || addr >= vma->vm_end)
+			continue;
+
+		cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+			vma->vm_file->f_vfsmnt);
+		*offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start; 
+		break;
+	}
+out:
+	return cookie;
+}
+
+
+static u32 last_cookie = ~0UL;
+ 
+static void add_cpu_switch(int i)
+{
+	add_event_entry(ESCAPE_CODE);
+	add_event_entry(CPU_SWITCH_CODE);
+	add_event_entry(i);
+	last_cookie = ~0UL;
+}
+
+ 
+static void add_ctx_switch(pid_t pid, u32 cookie)
+{
+	add_event_entry(ESCAPE_CODE);
+	add_event_entry(CTX_SWITCH_CODE); 
+	add_event_entry(pid);
+	add_event_entry(cookie);
+}
+
+ 
+static void add_cookie_switch(u32 cookie)
+{
+	add_event_entry(ESCAPE_CODE);
+	add_event_entry(COOKIE_SWITCH_CODE);
+	add_event_entry(cookie);
+}
+
+ 
+static void add_sample_entry(unsigned long offset, unsigned long event)
+{
+	add_event_entry(offset);
+	add_event_entry(event);
+}
+
+
+static void add_us_sample(struct mm_struct * mm, struct op_sample * s)
+{
+	u32 cookie;
+	off_t offset;
+ 
+ 	cookie = lookup_dcookie(mm, s->eip, &offset);
+ 
+	if (!cookie)
+		return;
+
+	if (cookie != last_cookie) {
+		add_cookie_switch(cookie);
+		last_cookie = cookie;
+	}
+
+	add_sample_entry(offset, s->event);
+}
+
+ 
+static inline int is_kernel(unsigned long val)
+{
+	return val > __PAGE_OFFSET;
+}
+
+
+/* Add a sample to the global event buffer. If possible the
+ * sample is converted into a persistent dentry/offset pair
+ * for later lookup from userspace.
+ */
+static void add_sample(struct mm_struct * mm, struct op_sample * s)
+{
+	if (is_kernel(s->eip)) {
+		add_sample_entry(s->eip, s->event);
+	} else if (mm) {
+		add_us_sample(mm, s);
+	}
+}
+ 
+ 
+static void release_mm(struct mm_struct * mm)
+{
+	if (mm)
+		up_read(&mm->mmap_sem);
+}
+
+
+/* Take the task's mmap_sem to protect ourselves from
+ * races when we do lookup_dcookie().
+ */
+static struct mm_struct * take_task_mm(struct task_struct * task)
+{
+	struct mm_struct * mm;
+	task_lock(task);
+	mm = task->mm;
+	task_unlock(task);
+ 
+	/* if task->mm !NULL, mm_count must be at least 1. It cannot
+	 * drop to 0 without the task exiting, which will have to sleep
+	 * on buffer_sem first. So we do not need to mark mm_count
+	 * ourselves.
+	 */
+	if (mm) {
+		/* More ugliness. If a task took its mmap
+		 * sem then came to sleep on buffer_sem we
+		 * will deadlock waiting for it. So we can
+		 * but try. This will lose samples :/
+		 */
+		if (!down_read_trylock(&mm->mmap_sem)) {
+			/* FIXME: this underestimates samples lost */
+			atomic_inc(&oprofile_stats.sample_lost_mmap_sem);
+			mm = NULL;
+		}
+	}
+ 
+	return mm;
+}
+ 
+ 
+static inline int is_ctx_switch(unsigned long val)
+{
+	return val == ~0UL;
+}
+ 
+
+/* Sync one of the CPU's buffers into the global event buffer.
+ * Here we need to go through each batch of samples punctuated
+ * by context switch notes, taking the task's mmap_sem and doing
+ * lookup in task->mm->mmap to convert EIP into dcookie/offset
+ * value.
+ */
+static void sync_buffer(struct oprofile_cpu_buffer * cpu_buf)
+{
+	struct mm_struct * mm = 0;
+	struct task_struct * new;
+	u32 cookie;
+	int i;
+ 
+	for (i=0; i < cpu_buf->pos; ++i) {
+		struct op_sample * s = &cpu_buf->buffer[i];
+ 
+		if (is_ctx_switch(s->eip)) {
+			new = (struct task_struct *)s->event;
+ 
+			release_mm(mm);
+			mm = take_task_mm(new);
+ 
+			cookie = get_exec_dcookie(mm);
+			add_ctx_switch(new->pid, cookie);
+		} else {
+			add_sample(mm, s);
+		}
+	}
+	release_mm(mm);
+
+	cpu_buf->pos = 0;
+}
+ 
+ 
+/* Process each CPU's local buffer into the global
+ * event buffer.
+ */
+static void sync_cpu_buffers(void)
+{
+	int i;
+
+	down(&buffer_sem);
+ 
+	for (i = 0; i < NR_CPUS; ++i) {
+		struct oprofile_cpu_buffer * cpu_buf;
+ 
+		if (!cpu_possible(i))
+			continue;
+ 
+		cpu_buf = &cpu_buffer[i];
+ 
+		/* We take a spin lock even though we might
+		 * sleep. It's OK because other users are try
+		 * lockers only, and this region is already
+		 * protected by buffer_sem. It's raw to prevent
+		 * the preempt bogometer firing. Fruity, huh ? */
+		_raw_spin_lock(&cpu_buf->int_lock);
+		add_cpu_switch(i);
+		sync_buffer(cpu_buf);
+		_raw_spin_unlock(&cpu_buf->int_lock);
+	}
+
+	up(&buffer_sem);
+ 
+	mod_timer(&sync_timer, jiffies + DEFAULT_EXPIRE);
+}
+ 
+
+static void wq_sync_buffers(void * data)
+{
+	sync_cpu_buffers();
+}
+ 
+ 
+/* It is possible that we could have no munmap() or
+ * other events for a period of time. This will lead
+ * the CPU buffers to overflow and lose samples and
+ * context switches. We try to reduce the problem
+ * by timing out when nothing happens for a while.
+ */
+static void timer_ping(unsigned long data)
+{
+	schedule_work(&sync_wq);
+	/* timer is re-added by the scheduled task */
+}
diff -Nru a/drivers/oprofile/buffer_sync.h b/drivers/oprofile/buffer_sync.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/buffer_sync.h	Tue Oct 15 20:29:24 2002
@@ -0,0 +1,19 @@
+/**
+ * @file buffer_sync.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef OPROFILE_BUFFER_SYNC_H
+#define OPROFILE_BUFFER_SYNC_H
+ 
+/* add the necessary profiling hooks */
+int sync_start(void);
+
+/* remove the hooks */
+void sync_stop(void);
+ 
+#endif /* OPROFILE_BUFFER_SYNC_H */
diff -Nru a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/cpu_buffer.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,135 @@
+/**
+ * @file cpu_buffer.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ *
+ * Each CPU has a local buffer that stores PC value/event
+ * pairs. We also log context switches when we notice them.
+ * Eventually each CPU's buffer is processed into the global
+ * event buffer by sync_cpu_buffers().
+ *
+ * We use a local buffer for two reasons: an NMI or similar
+ * interrupt cannot synchronise, and high sampling rates
+ * would lead to catastrophic global synchronisation if
+ * a global buffer was used.
+ */
+
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+ 
+#include "cpu_buffer.h"
+#include "oprof.h"
+#include "oprofile_stats.h"
+
+struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned;
+
+static unsigned long buffer_size;
+ 
+static void __free_cpu_buffers(int num)
+{
+	int i;
+ 
+	for (i=0; i < num; ++i) {
+		struct oprofile_cpu_buffer * b = &cpu_buffer[i];
+ 
+		if (!cpu_possible(i)) 
+			continue;
+ 
+		vfree(b->buffer);
+	}
+}
+ 
+ 
+int alloc_cpu_buffers(void)
+{
+	int i;
+ 
+	buffer_size = fs_cpu_buffer_size;
+ 
+	for (i=0; i < NR_CPUS; ++i) {
+		struct oprofile_cpu_buffer * b = &cpu_buffer[i];
+ 
+		if (!cpu_possible(i)) 
+			continue;
+ 
+		b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size);
+		if (!b->buffer)
+			goto fail;
+ 
+		spin_lock_init(&b->int_lock);
+		b->pos = 0;
+		b->last_task = 0;
+		b->sample_received = 0;
+		b->sample_lost_locked = 0;
+		b->sample_lost_overflow = 0;
+	}
+	return 0;
+fail:
+	__free_cpu_buffers(i);
+	return -ENOMEM;
+}
+ 
+
+void free_cpu_buffers(void)
+{
+	__free_cpu_buffers(NR_CPUS);
+}
+
+ 
+/* Note we can't use a semaphore here as this is supposed to
+ * be safe from any context. Instead we trylock the CPU's int_lock.
+ * int_lock is taken by the processing code in sync_cpu_buffers()
+ * so we avoid disturbing that.
+ */
+void oprofile_add_sample(unsigned long eip, unsigned long event, int cpu)
+{
+	struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu];
+	struct task_struct * task;
+
+	/* temporary ? */
+	BUG_ON(!oprofile_started);
+ 
+	cpu_buf->sample_received++;
+ 
+	if (!spin_trylock(&cpu_buf->int_lock)) {
+		cpu_buf->sample_lost_locked++;
+		return;
+	}
+
+	if (cpu_buf->pos > buffer_size - 2) {
+		cpu_buf->sample_lost_overflow++;
+		goto out;
+	}
+ 
+	task = current;
+
+	/* notice a task switch */
+	if (cpu_buf->last_task != task) {
+		cpu_buf->last_task = task;
+		if (!(task->flags & PF_EXITING)) {
+			cpu_buf->buffer[cpu_buf->pos].eip = ~0UL;
+			cpu_buf->buffer[cpu_buf->pos].event = (unsigned long)task;
+			cpu_buf->pos++;
+		}
+	}
+ 
+	/* If the task is exiting it's not safe to take a sample
+	 * as the task_struct is about to be freed. We can't just
+	 * notify at release_task() time because of CLONE_DETACHED
+	 * tasks that release_task() themselves.
+	 */
+	if (task->flags & PF_EXITING) {
+		cpu_buf->sample_lost_task_exit++;
+		goto out;
+	}
+ 
+	cpu_buf->buffer[cpu_buf->pos].eip = eip;
+	cpu_buf->buffer[cpu_buf->pos].event = event;
+	cpu_buf->pos++;
+out:
+	spin_unlock(&cpu_buf->int_lock);
+}
diff -Nru a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/cpu_buffer.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,45 @@
+/**
+ * @file cpu_buffer.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef OPROFILE_CPU_BUFFER_H
+#define OPROFILE_CPU_BUFFER_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+ 
+struct task_struct;
+ 
+/* allocate a sample buffer for each CPU */
+int alloc_cpu_buffers(void);
+
+void free_cpu_buffers(void);
+ 
+/* CPU buffer is composed of such entries (which are
+ * also used for context switch notes)
+ */
+struct op_sample {
+	unsigned long eip;
+	unsigned long event;
+};
+ 
+struct oprofile_cpu_buffer {
+	spinlock_t int_lock;
+	/* protected by int_lock */
+	unsigned long pos;
+	struct task_struct * last_task;
+	struct op_sample * buffer;
+	unsigned long sample_received;
+	unsigned long sample_lost_locked;
+	unsigned long sample_lost_overflow;
+	unsigned long sample_lost_task_exit;
+} ____cacheline_aligned;
+
+extern struct oprofile_cpu_buffer cpu_buffer[];
+
+#endif /* OPROFILE_CPU_BUFFER_H */
diff -Nru a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/event_buffer.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,186 @@
+/**
+ * @file event_buffer.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ *
+ * This is the global event buffer that the user-space
+ * daemon reads from. The event buffer is an untyped array
+ * of unsigned longs. Entries are prefixed by the
+ * escape value ESCAPE_CODE followed by an identifying code.
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/dcookies.h>
+#include <linux/oprofile.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include "event_buffer.h"
+#include "cpu_buffer.h"
+#include "oprof.h"
+#include "oprofile_stats.h"
+
+DECLARE_MUTEX(buffer_sem);
+ 
+static unsigned long buffer_opened;
+static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
+static unsigned long * event_buffer;
+static unsigned long buffer_size;
+static unsigned long buffer_watershed;
+static size_t buffer_pos;
+/* atomic_t because wait_event checks it outside of buffer_sem */
+static atomic_t buffer_ready = ATOMIC_INIT(0);
+
+/* Add an entry to the event buffer. When we
+ * get near to the end we wake up the process
+ * sleeping on the read() of the file.
+ */
+void add_event_entry(unsigned long value)
+{
+	if (buffer_pos == buffer_size) {
+		atomic_inc(&oprofile_stats.event_lost_overflow);
+		return;
+	}
+
+	event_buffer[buffer_pos] = value;
+	if (++buffer_pos == buffer_size - buffer_watershed) {
+		atomic_set(&buffer_ready, 1);
+		wake_up(&buffer_wait);
+	}
+}
+
+
+/* Wake up the waiting process if any. This happens
+ * on "echo 0 >/dev/oprofile/enable" so the daemon
+ * processes the data remaining in the event buffer.
+ */
+void wake_up_buffer_waiter(void)
+{
+	down(&buffer_sem);
+	atomic_set(&buffer_ready, 1);
+	wake_up(&buffer_wait);
+	up(&buffer_sem);
+}
+
+ 
+int alloc_event_buffer(void)
+{
+	int err = -ENOMEM;
+
+	spin_lock(&oprofilefs_lock);
+	buffer_size = fs_buffer_size;
+	buffer_watershed = fs_buffer_watershed;
+	spin_unlock(&oprofilefs_lock);
+ 
+	if (buffer_watershed >= buffer_size)
+		return -EINVAL;
+ 
+	event_buffer = vmalloc(sizeof(unsigned long) * buffer_size);
+	if (!event_buffer)
+		goto out; 
+
+	err = 0;
+out:
+	return err;
+}
+
+
+void free_event_buffer(void)
+{
+	vfree(event_buffer);
+}
+
+ 
+int event_buffer_open(struct inode * inode, struct file * file)
+{
+	int err = -EPERM;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (test_and_set_bit(0, &buffer_opened))
+		return -EBUSY;
+
+	/* Register as a user of dcookies
+	 * to ensure they persist for the lifetime of
+	 * the open event file
+	 */
+	err = -EINVAL;
+	file->private_data = dcookie_register();
+	if (!file->private_data)
+		goto out;
+		 
+	if ((err = oprofile_setup()))
+		goto fail;
+
+	/* NB: the actual start happens from userspace
+	 * echo 1 >/dev/oprofile/enable
+	 */
+ 
+	return 0;
+
+fail:
+	dcookie_unregister(file->private_data);
+out:
+	clear_bit(0, &buffer_opened);
+	return err;
+}
+
+
+int event_buffer_release(struct inode * inode, struct file * file)
+{
+	oprofile_stop();
+	oprofile_shutdown();
+	dcookie_unregister(file->private_data);
+	buffer_pos = 0;
+	atomic_set(&buffer_ready, 0);
+	clear_bit(0, &buffer_opened);
+	return 0;
+}
+
+
+ssize_t event_buffer_read(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+	int retval = -EINVAL;
+	size_t const max = buffer_size * sizeof(unsigned long);
+
+	/* handling partial reads is more trouble than it's worth */
+	if (count != max || *offset)
+		return -EINVAL;
+
+	/* wait for the event buffer to fill up with some data */
+	wait_event_interruptible(buffer_wait, atomic_read(&buffer_ready));
+	if (signal_pending(current))
+		return -EINTR;
+
+	down(&buffer_sem);
+
+	atomic_set(&buffer_ready, 0);
+
+	retval = -EFAULT;
+
+	count = buffer_pos * sizeof(unsigned long);
+ 
+	if (copy_to_user(buf, event_buffer, count))
+		goto out;
+
+	retval = count;
+	buffer_pos = 0;
+ 
+out:
+	up(&buffer_sem);
+	return retval;
+}
+ 
+struct file_operations event_buffer_fops = {
+	.open		= event_buffer_open,
+	.release	= event_buffer_release,
+	.read		= event_buffer_read,
+};
diff -Nru a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/event_buffer.h	Tue Oct 15 20:29:24 2002
@@ -0,0 +1,42 @@
+/**
+ * @file event_buffer.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef EVENT_BUFFER_H
+#define EVENT_BUFFER_H
+
+#include <linux/types.h> 
+#include <linux/sem.h>
+ 
+int alloc_event_buffer(void);
+
+void free_event_buffer(void);
+ 
+/* wake up the process sleeping on the event file */
+void wake_up_buffer_waiter(void);
+ 
+/* Each escaped entry is prefixed by ESCAPE_CODE
+ * then one of the following codes, then the
+ * relevant data.
+ */
+#define ESCAPE_CODE		~0UL
+#define CTX_SWITCH_CODE 	1
+#define CPU_SWITCH_CODE 	2
+#define COOKIE_SWITCH_CODE 	3
+ 
+/* add data to the event buffer */
+void add_event_entry(unsigned long data);
+ 
+extern struct file_operations event_buffer_fops;
+ 
+/* mutex between sync_cpu_buffers() and the
+ * file reading code.
+ */
+extern struct semaphore buffer_sem;
+ 
+#endif /* EVENT_BUFFER_H */
diff -Nru a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/oprof.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,153 @@
+/**
+ * @file oprof.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/profile.h>
+#include <linux/oprofile.h>
+
+#include "oprof.h"
+#include "event_buffer.h"
+#include "cpu_buffer.h"
+#include "buffer_sync.h"
+#include "oprofile_stats.h"
+ 
+struct oprofile_operations * oprofile_ops;
+enum oprofile_cpu oprofile_cpu_type;
+unsigned long oprofile_started;
+static unsigned long is_setup;
+static DECLARE_MUTEX(start_sem);
+
+int oprofile_setup(void)
+{
+	int err;
+ 
+	if ((err = alloc_cpu_buffers()))
+		goto out;
+
+	if ((err = alloc_event_buffer()))
+		goto out1;
+ 
+	if (oprofile_ops->setup && (err = oprofile_ops->setup()))
+		goto out2;
+ 
+	/* Note even though this starts part of the
+	 * profiling overhead, it's necessary to prevent
+	 * us missing task deaths and eventually oopsing
+	 * when trying to process the event buffer.
+	 */
+	if ((err = sync_start()))
+		goto out3;
+
+	down(&start_sem);
+	is_setup = 1;
+	up(&start_sem);
+	return 0;
+ 
+out3:
+	if (oprofile_ops->shutdown)
+		oprofile_ops->shutdown();
+out2:
+	free_event_buffer();
+out1:
+	free_cpu_buffers();
+out:
+	return err;
+}
+
+
+/* Actually start profiling (echo 1>/dev/oprofile/enable) */
+int oprofile_start(void)
+{
+	int err = -EINVAL;
+ 
+	down(&start_sem);
+ 
+	if (!is_setup)
+		goto out;
+
+	err = 0; 
+ 
+	if (oprofile_started)
+		goto out;
+ 
+	if ((err = oprofile_ops->start()))
+		goto out;
+
+	oprofile_started = 1;
+	oprofile_reset_stats();
+out:
+	up(&start_sem); 
+	return err;
+}
+
+ 
+/* echo 0>/dev/oprofile/enable */
+void oprofile_stop(void)
+{
+	down(&start_sem);
+	if (!oprofile_started)
+		goto out;
+	oprofile_ops->stop();
+	oprofile_started = 0;
+	/* wake up the daemon to read what remains */
+	wake_up_buffer_waiter();
+out:
+	up(&start_sem);
+}
+
+
+void oprofile_shutdown(void)
+{
+	sync_stop();
+	if (oprofile_ops->shutdown)
+		oprofile_ops->shutdown(); 
+	/* down() is also necessary to synchronise all pending events
+	 * before freeing */
+	down(&buffer_sem);
+	is_setup = 0;
+	up(&buffer_sem);
+	free_event_buffer();
+	free_cpu_buffers();
+}
+
+ 
+static int __init oprofile_init(void)
+{
+	int err;
+
+	/* Architecture must fill in the interrupt ops and the
+	 * logical CPU type.
+	 */
+	err = oprofile_arch_init(&oprofile_ops, &oprofile_cpu_type);
+	if (err)
+		goto out;
+
+	err = oprofilefs_register();
+	if (err)
+		goto out;
+ 
+out:
+	return err;
+}
+
+
+static void __exit oprofile_exit(void)
+{
+	oprofilefs_unregister();
+}
+
+MODULE_LICENSE("GPL");
+module_init(oprofile_init);
+module_exit(oprofile_exit);
diff -Nru a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/oprof.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,34 @@
+/**
+ * @file oprof.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef OPROF_H
+#define OPROF_H
+
+#include <linux/spinlock.h>
+#include <linux/oprofile.h>
+ 
+int oprofile_setup(void);
+void oprofile_shutdown(void); 
+
+int oprofilefs_register(void);
+void oprofilefs_unregister(void);
+
+int oprofile_start(void);
+void oprofile_stop(void);
+
+extern unsigned long fs_buffer_size;
+extern unsigned long fs_cpu_buffer_size;
+extern unsigned long fs_buffer_watershed;
+extern enum oprofile_cpu oprofile_cpu_type;
+extern struct oprofile_operations * oprofile_ops;
+extern unsigned long oprofile_started;
+ 
+void oprofile_create_files(struct super_block * sb, struct dentry * root);
+ 
+#endif /* OPROF_H */
diff -Nru a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/oprofile_files.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,91 @@
+/**
+ * @file oprofile_files.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/oprofile.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+ 
+#include "oprof.h"
+#include "event_buffer.h"
+#include "oprofile_stats.h"
+ 
+unsigned long fs_buffer_size = 131072;
+unsigned long fs_cpu_buffer_size = 8192;
+unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
+
+ 
+static int simple_open(struct inode * inode, struct file * filp)
+{
+	return 0;
+}
+
+
+static ssize_t cpu_type_read(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+	unsigned long cpu_type = oprofile_cpu_type;
+
+	return oprofilefs_ulong_to_user(&cpu_type, buf, count, offset);
+}
+ 
+ 
+static struct file_operations cpu_type_fops = {
+	.open		= simple_open,
+	.read		= cpu_type_read,
+};
+ 
+ 
+static ssize_t enable_read(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+	return oprofilefs_ulong_to_user(&oprofile_started, buf, count, offset);
+}
+
+
+static ssize_t enable_write(struct file *file, char const * buf, size_t count, loff_t * offset)
+{
+	unsigned long val;
+	int retval;
+
+	if (*offset)
+		return -EINVAL;
+
+	retval = oprofilefs_ulong_from_user(&val, buf, count);
+	if (retval)
+		return retval;
+ 
+	if (val)
+		retval = oprofile_start();
+	else
+		oprofile_stop();
+
+	if (retval)
+		return retval;
+	return count;
+}
+
+ 
+static struct file_operations enable_fops = {
+	.open		= simple_open,
+	.read		= enable_read,
+	.write		= enable_write,
+};
+
+ 
+void oprofile_create_files(struct super_block * sb, struct dentry * root)
+{
+	oprofilefs_create_file(sb, root, "enable", &enable_fops);
+	oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
+	oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
+	oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
+	oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size);
+	oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); 
+	oprofile_create_stats_files(sb, root);
+	if (oprofile_ops->create_files)
+		oprofile_ops->create_files(sb, root);
+}
diff -Nru a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/oprofile_stats.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,77 @@
+/**
+ * @file oprofile_stats.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ */
+
+#include <linux/oprofile.h>
+#include <linux/smp.h>
+ 
+#include "oprofile_stats.h"
+#include "cpu_buffer.h"
+ 
+struct oprofile_stat_struct oprofile_stats;
+ 
+void oprofile_reset_stats(void)
+{
+	struct oprofile_cpu_buffer * cpu_buf; 
+	int i;
+ 
+	for (i = 0; i < NR_CPUS; ++i) {
+		if (!cpu_possible(i))
+			continue;
+
+		cpu_buf = &cpu_buffer[i]; 
+		cpu_buf->sample_received = 0;
+		cpu_buf->sample_lost_locked = 0;
+		cpu_buf->sample_lost_overflow = 0;
+		cpu_buf->sample_lost_task_exit = 0;
+	}
+ 
+	atomic_set(&oprofile_stats.sample_lost_mmap_sem, 0);
+	atomic_set(&oprofile_stats.event_lost_overflow, 0);
+}
+
+
+void oprofile_create_stats_files(struct super_block * sb, struct dentry * root)
+{
+	struct oprofile_cpu_buffer * cpu_buf;
+	struct dentry * cpudir;
+	struct dentry * dir;
+	char buf[10];
+	int i;
+
+	dir = oprofilefs_mkdir(sb, root, "stats");
+	if (!dir)
+		return;
+
+	for (i = 0; i < NR_CPUS; ++i) {
+		if (!cpu_possible(i))
+			continue;
+
+		cpu_buf = &cpu_buffer[i]; 
+		snprintf(buf, 6, "cpu%d", i);
+		cpudir = oprofilefs_mkdir(sb, dir, buf);
+ 
+		/* Strictly speaking access to these ulongs is racy,
+		 * but we can't simply lock them, and they are
+		 * informational only.
+		 */
+		oprofilefs_create_ro_ulong(sb, cpudir, "sample_received",
+			&cpu_buf->sample_received);
+		oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_locked",
+			&cpu_buf->sample_lost_locked);
+		oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_overflow",
+			&cpu_buf->sample_lost_overflow);
+		oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_task_exit",
+			&cpu_buf->sample_lost_task_exit);
+	}
+ 
+	oprofilefs_create_ro_atomic(sb, dir, "sample_lost_mmap_sem",
+		&oprofile_stats.sample_lost_mmap_sem);
+	oprofilefs_create_ro_atomic(sb, dir, "event_lost_overflow",
+		&oprofile_stats.event_lost_overflow);
+}
diff -Nru a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/oprofile_stats.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,31 @@
+/**
+ * @file oprofile_stats.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ */
+
+#ifndef OPROFILE_STATS_H
+#define OPROFILE_STATS_H
+
+#include <asm/atomic.h>
+ 
+struct oprofile_stat_struct {
+	atomic_t sample_lost_mmap_sem;
+	atomic_t event_lost_overflow;
+};
+
+extern struct oprofile_stat_struct oprofile_stats;
+ 
+/* reset all stats to zero */
+void oprofile_reset_stats(void);
+ 
+struct super_block;
+struct dentry;
+ 
+/* create the stats/ dir */
+void oprofile_create_stats_files(struct super_block * sb, struct dentry * root);
+
+#endif /* OPROFILE_STATS_H */
diff -Nru a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/oprofile/oprofilefs.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,306 @@
+/**
+ * @file oprofilefs.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ *
+ * A simple filesystem for configuration and
+ * access of oprofile.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/fs.h>
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/oprofile.h>
+#include <asm/uaccess.h>
+
+#include "oprof.h"
+
+#define OPROFILEFS_MAGIC 0x6f70726f
+
+spinlock_t oprofilefs_lock = SPIN_LOCK_UNLOCKED;
+
+static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode)
+{
+	struct inode * inode = new_inode(sb);
+
+	if (inode) {
+		inode->i_mode = mode;
+		inode->i_uid = 0;
+		inode->i_gid = 0;
+		inode->i_blksize = PAGE_CACHE_SIZE;
+		inode->i_blocks = 0;
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	}
+	return inode;
+}
+
+
+static struct super_operations s_ops = {
+	.statfs		= simple_statfs,
+	.drop_inode 	= generic_delete_inode,
+};
+
+#define TMPBUFSIZE 50
+
+ssize_t oprofilefs_ulong_to_user(unsigned long * val, char * buf, size_t count, loff_t * offset)
+{
+	char tmpbuf[TMPBUFSIZE];
+	size_t maxlen;
+
+	if (!count)
+		return 0;
+
+	spin_lock(&oprofilefs_lock);
+	maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", *val);
+	spin_unlock(&oprofilefs_lock);
+	if (maxlen > TMPBUFSIZE)
+		maxlen = TMPBUFSIZE;
+
+	if (*offset > maxlen)
+		return 0;
+
+	if (count > maxlen - *offset)
+		count = maxlen - *offset;
+
+	if (copy_to_user(buf, tmpbuf + *offset, count))
+		return -EFAULT;
+
+	*offset += count;
+
+	return count;
+}
+
+
+int oprofilefs_ulong_from_user(unsigned long * val, char const * buf, size_t count)
+{
+	char tmpbuf[TMPBUFSIZE];
+
+	if (!count)
+		return 0;
+
+	if (count > TMPBUFSIZE - 1)
+		return -EINVAL;
+
+	memset(tmpbuf, 0x0, TMPBUFSIZE);
+
+	if (copy_from_user(tmpbuf, buf, count))
+		return -EFAULT;
+
+	spin_lock(&oprofilefs_lock);
+	*val = simple_strtoul(tmpbuf, NULL, 10);
+	spin_unlock(&oprofilefs_lock);
+	return 0;
+}
+
+
+static ssize_t ulong_read_file(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+	return oprofilefs_ulong_to_user(file->private_data, buf, count, offset);
+}
+
+
+static ssize_t ulong_write_file(struct file * file, char const * buf, size_t count, loff_t * offset)
+{
+	unsigned long * value = file->private_data;
+	int retval;
+
+	if (*offset)
+		return -EINVAL;
+
+	retval = oprofilefs_ulong_from_user(value, buf, count);
+
+	if (retval)
+		return retval;
+	return count;
+}
+
+
+static int default_open(struct inode * inode, struct file * filp)
+{
+	if (inode->u.generic_ip)
+		filp->private_data = inode->u.generic_ip;
+	return 0;
+}
+
+
+static struct file_operations ulong_fops = {
+	.read		= ulong_read_file,
+	.write		= ulong_write_file,
+	.open		= default_open,
+};
+
+
+static struct file_operations ulong_ro_fops = {
+	.read		= ulong_read_file,
+	.open		= default_open,
+};
+
+
+static struct dentry * __oprofilefs_create_file(struct super_block * sb,
+	struct dentry * root, char const * name, struct file_operations * fops)
+{
+	struct dentry * dentry;
+	struct inode * inode;
+	struct qstr qname;
+	qname.name = name;
+	qname.len = strlen(name);
+	qname.hash = full_name_hash(qname.name, qname.len);
+	dentry = d_alloc(root, &qname);
+	if (!dentry)
+		return 0;
+	inode = oprofilefs_get_inode(sb, S_IFREG | 0644);
+	if (!inode) {
+		dput(dentry);
+		return 0;
+	}
+	inode->i_fop = fops;
+	d_add(dentry, inode);
+	return dentry;
+}
+
+
+int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
+	char const * name, unsigned long * val)
+{
+	struct dentry * d = __oprofilefs_create_file(sb, root, name, &ulong_fops);
+	if (!d)
+		return -EFAULT;
+
+	d->d_inode->u.generic_ip = val;
+	return 0;
+}
+
+
+int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
+	char const * name, unsigned long * val)
+{
+	struct dentry * d = __oprofilefs_create_file(sb, root, name, &ulong_ro_fops);
+	if (!d)
+		return -EFAULT;
+
+	d->d_inode->u.generic_ip = val;
+	return 0;
+}
+
+
+static ssize_t atomic_read_file(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+	atomic_t * aval = file->private_data;
+	unsigned long val = atomic_read(aval);
+	return oprofilefs_ulong_to_user(&val, buf, count, offset);
+}
+ 
+
+static struct file_operations atomic_ro_fops = {
+	.read		= atomic_read_file,
+	.open		= default_open,
+};
+ 
+
+int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
+	char const * name, atomic_t * val)
+{
+	struct dentry * d = __oprofilefs_create_file(sb, root, name, &atomic_ro_fops);
+	if (!d)
+		return -EFAULT;
+
+	d->d_inode->u.generic_ip = val;
+	return 0;
+}
+
+ 
+int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
+	char const * name, struct file_operations * fops)
+{
+	if (!__oprofilefs_create_file(sb, root, name, fops))
+		return -EFAULT;
+	return 0;
+}
+
+
+struct dentry * oprofilefs_mkdir(struct super_block * sb,
+	struct dentry * root, char const * name)
+{
+	struct dentry * dentry;
+	struct inode * inode;
+	struct qstr qname;
+	qname.name = name;
+	qname.len = strlen(name);
+	qname.hash = full_name_hash(qname.name, qname.len);
+	dentry = d_alloc(root, &qname);
+	if (!dentry)
+		return 0;
+	inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
+	if (!inode) {
+		dput(dentry);
+		return 0;
+	}
+	inode->i_op = &simple_dir_inode_operations;
+	inode->i_fop = &simple_dir_operations;
+	d_add(dentry, inode);
+	return dentry;
+}
+
+
+static int oprofilefs_fill_super(struct super_block * sb, void * data, int silent)
+{
+	struct inode * root_inode;
+	struct dentry * root_dentry;
+
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = OPROFILEFS_MAGIC;
+	sb->s_op = &s_ops;
+
+	root_inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
+	if (!root_inode)
+		return -ENOMEM;
+	root_inode->i_op = &simple_dir_inode_operations;
+	root_inode->i_fop = &simple_dir_operations;
+	root_dentry = d_alloc_root(root_inode);
+	if (!root_dentry) {
+		iput(root_inode);
+		return -ENOMEM;
+	}
+
+	sb->s_root = root_dentry;
+
+	oprofile_create_files(sb, root_dentry);
+
+	// FIXME: verify kill_litter_super removes our dentries
+	return 0;
+}
+
+
+static struct super_block * oprofilefs_get_sb(struct file_system_type * fs_type,
+	int flags, char * dev_name, void * data)
+{
+	return get_sb_single(fs_type, flags, data, oprofilefs_fill_super);
+}
+
+
+static struct file_system_type oprofilefs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "oprofilefs",
+	.get_sb		= oprofilefs_get_sb,
+	.kill_sb	= kill_litter_super,
+};
+
+
+int __init oprofilefs_register(void)
+{
+	return register_filesystem(&oprofilefs_type);
+}
+
+
+void __exit oprofilefs_unregister(void)
+{
+	unregister_filesystem(&oprofilefs_type);
+}
diff -Nru a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c
--- a/drivers/pcmcia/bulkmem.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/pcmcia/bulkmem.c	Tue Oct 15 20:29:23 2002
@@ -211,7 +211,7 @@
     retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
 }
 
-static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
+static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
 {
     erase_busy_t *busy;
     region_info_t *info;
@@ -229,8 +229,10 @@
 	else {
 	    erase->State = 1;
 	    busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
-	    if (!busy)
-		return CS_GENERAL_FAILURE;
+	    if (!busy) {
+		erase->State = ERASE_FAILED;
+		return;
+	    }
 	    busy->erase = erase;
 	    busy->client = handle;
 	    init_timer(&busy->timeout);
@@ -240,7 +242,6 @@
 	    retry_erase(busy, 0);
 	}
     }
-    return CS_SUCCESS;
 } /* setup_erase_request */
 
 /*======================================================================
@@ -325,7 +326,7 @@
     
 ======================================================================*/
 
-static int setup_regions(client_handle_t handle, int attr,
+static void setup_regions(client_handle_t handle, int attr,
 			  memory_handle_t *list)
 {
     int i, code, has_jedec, has_geo;
@@ -340,7 +341,7 @@
 
     code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
     if (read_tuple(handle, code, &device) != CS_SUCCESS)
-	return CS_GENERAL_FAILURE;
+	return;
     code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
     has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
     if (has_jedec && (device.ndev != jedec.nid)) {
@@ -363,8 +364,10 @@
 	if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
 	    (device.dev[i].size != 0)) {
 	    r = kmalloc(sizeof(*r), GFP_KERNEL);
-	    if (!r)
-		return CS_GENERAL_FAILURE;
+	    if (!r) {
+		printk(KERN_NOTICE "cs: setup_regions: kmalloc failed!\n");
+		return;
+	    }
 	    r->region_magic = REGION_MAGIC;
 	    r->state = 0;
 	    r->dev_info[0] = '\0';
@@ -389,7 +392,6 @@
 	}
 	offset += device.dev[i].size;
     }
-    return CS_SUCCESS;
 } /* setup_regions */
 
 /*======================================================================
@@ -423,10 +425,8 @@
     
     if ((handle->Attributes & INFO_MASTER_CLIENT) &&
 	(!(s->state & SOCKET_REGION_INFO))) {
-	if (setup_regions(handle, 0, &s->c_region) != CS_SUCCESS)
-	    return CS_GENERAL_FAILURE;
-	if (setup_regions(handle, 1, &s->a_region) != CS_SUCCESS)
-	    return CS_GENERAL_FAILURE;
+	setup_regions(handle, 0, &s->c_region);
+	setup_regions(handle, 1, &s->a_region);
 	s->state |= SOCKET_REGION_INFO;
     }
 
diff -Nru a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h
--- a/drivers/pcmcia/ricoh.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/pcmcia/ricoh.h	Tue Oct 15 20:29:16 2002
@@ -75,6 +75,12 @@
 #define RL5C46X_BCR_3E0_ENA		0x0800
 #define RL5C46X_BCR_3E2_ENA		0x1000
 
+/* Bridge Configuration Register */
+#define RL5C4XX_CONFIG			0x80	/* 16 bit */
+#define  RL5C4XX_CONFIG_IO_1_MODE	0x0200
+#define  RL5C4XX_CONFIG_IO_0_MODE	0x0100
+#define  RL5C4XX_CONFIG_PREFETCH	0x0001
+
 /* Misc Control Register */
 #define RL5C4XX_MISC			0x0082	/* 16 bit */
 #define  RL5C4XX_MISC_HW_SUSPEND_ENA	0x0002
@@ -117,6 +123,7 @@
 #define rl_ctl(socket)		((socket)->private[1])
 #define rl_io(socket)		((socket)->private[2])
 #define rl_mem(socket)		((socket)->private[3])
+#define rl_config(socket)	((socket)->private[4])
 
 /*
  * Magic Ricoh initialization code.. Save state at
@@ -128,9 +135,17 @@
 	rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL);
 	rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0);
 	rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0);
+	rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG);
 
 	/* Set the default timings, don't trust the original values */
 	rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
+
+	if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) {
+		rl_ctl(socket) |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2;
+	} else {
+		rl_config(socket) |= RL5C4XX_CONFIG_PREFETCH;
+	}
+
 	return 0;
 }
 
@@ -142,6 +157,8 @@
 	config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
 	config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket));
 	config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket));
+	config_writew(socket, RL5C4XX_CONFIG, rl_config(socket));
+	
 	return 0;
 }
 
diff -Nru a/drivers/pcmcia/sa1100_adsbitsy.c b/drivers/pcmcia/sa1100_adsbitsy.c
--- a/drivers/pcmcia/sa1100_adsbitsy.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/pcmcia/sa1100_adsbitsy.c	Tue Oct 15 20:29:23 2002
@@ -84,14 +84,14 @@
 }
 
 static struct pcmcia_low_level adsbitsy_pcmcia_ops = {
-  init:			adsbitsy_pcmcia_init,
-  shutdown:		sa1111_pcmcia_shutdown,
-  socket_state:		sa1111_pcmcia_socket_state,
-  get_irq_info:		sa1111_pcmcia_get_irq_info,
-  configure_socket:	adsbitsy_pcmcia_configure_socket,
+  .init			= adsbitsy_pcmcia_init,
+  .shutdown		= sa1111_pcmcia_shutdown,
+  .socket_state		= sa1111_pcmcia_socket_state,
+  .get_irq_info		= sa1111_pcmcia_get_irq_info,
+  .configure_socket	= adsbitsy_pcmcia_configure_socket,
 
-  socket_init:		sa1111_pcmcia_socket_init,
-  socket_suspend:	sa1111_pcmcia_socket_suspend,
+  .socket_init		= sa1111_pcmcia_socket_init,
+  .socket_suspend	= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_adsbitsy_init(void)
diff -Nru a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c
--- a/drivers/pcmcia/sa1100_assabet.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/pcmcia/sa1100_assabet.c	Tue Oct 15 20:29:20 2002
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include <asm/arch/assabet.h>
 
@@ -192,14 +193,14 @@
 }
 
 static struct pcmcia_low_level assabet_pcmcia_ops = { 
-	init:			assabet_pcmcia_init,
-	shutdown:		assabet_pcmcia_shutdown,
-	socket_state:		assabet_pcmcia_socket_state,
-	get_irq_info:		assabet_pcmcia_get_irq_info,
-	configure_socket:	assabet_pcmcia_configure_socket,
+	.init			= assabet_pcmcia_init,
+	.shutdown		= assabet_pcmcia_shutdown,
+	.socket_state		= assabet_pcmcia_socket_state,
+	.get_irq_info		= assabet_pcmcia_get_irq_info,
+	.configure_socket	= assabet_pcmcia_configure_socket,
 
-	socket_init:		assabet_pcmcia_socket_init,
-	socket_suspend:		assabet_pcmcia_socket_suspend,
+	.socket_init		= assabet_pcmcia_socket_init,
+	.socket_suspend		= assabet_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_assabet_init(void)
diff -Nru a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c
--- a/drivers/pcmcia/sa1100_badge4.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/pcmcia/sa1100_badge4.c	Tue Oct 15 20:29:12 2002
@@ -146,14 +146,14 @@
 }
 
 static struct pcmcia_low_level badge4_pcmcia_ops = {
-	init:			badge4_pcmcia_init,
-	shutdown:		badge4_pcmcia_shutdown,
-	socket_state:		sa1111_pcmcia_socket_state,
-	get_irq_info:		sa1111_pcmcia_get_irq_info,
-	configure_socket:	badge4_pcmcia_configure_socket,
+	.init			= badge4_pcmcia_init,
+	.shutdown		= badge4_pcmcia_shutdown,
+	.socket_state		= sa1111_pcmcia_socket_state,
+	.get_irq_info		= sa1111_pcmcia_get_irq_info,
+	.configure_socket	= badge4_pcmcia_configure_socket,
 
-	socket_init:		sa1111_pcmcia_socket_init,
-	socket_suspend:		sa1111_pcmcia_socket_suspend,
+	.socket_init		= sa1111_pcmcia_socket_init,
+	.socket_suspend		= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_badge4_init(void)
diff -Nru a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
--- a/drivers/pcmcia/sa1100_cerf.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/pcmcia/sa1100_cerf.c	Tue Oct 15 20:29:21 2002
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
@@ -160,14 +161,14 @@
 }
 
 static struct pcmcia_low_level cerf_pcmcia_ops = { 
-  init:			cerf_pcmcia_init,
-  shutdown:		cerf_pcmcia_shutdown,
-  socket_state:		cerf_pcmcia_socket_state,
-  get_irq_info:		cerf_pcmcia_get_irq_info,
-  configure_socket:	cerf_pcmcia_configure_socket,
+  .init			= cerf_pcmcia_init,
+  .shutdown		= cerf_pcmcia_shutdown,
+  .socket_state		= cerf_pcmcia_socket_state,
+  .get_irq_info		= cerf_pcmcia_get_irq_info,
+  .configure_socket	= cerf_pcmcia_configure_socket,
 
-  socket_init:		cerf_pcmcia_socket_init,
-  socket_suspend:	cerf_pcmcia_socket_suspend,
+  .socket_init		= cerf_pcmcia_socket_init,
+  .socket_suspend	= cerf_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_cerf_init(void)
diff -Nru a/drivers/pcmcia/sa1100_flexanet.c b/drivers/pcmcia/sa1100_flexanet.c
--- a/drivers/pcmcia/sa1100_flexanet.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/pcmcia/sa1100_flexanet.c	Tue Oct 15 20:29:17 2002
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
@@ -221,14 +222,14 @@
  *
  */
 static struct pcmcia_low_level flexanet_pcmcia_ops = {
-  init:			flexanet_pcmcia_init,
-  shutdown:		flexanet_pcmcia_shutdown,
-  socket_state:		flexanet_pcmcia_socket_state,
-  get_irq_info:		flexanet_pcmcia_get_irq_info,
-  configure_socket:	flexanet_pcmcia_configure_socket,
+  .init			= flexanet_pcmcia_init,
+  .shutdown		= flexanet_pcmcia_shutdown,
+  .socket_state		= flexanet_pcmcia_socket_state,
+  .get_irq_info		= flexanet_pcmcia_get_irq_info,
+  .configure_socket	= flexanet_pcmcia_configure_socket,
 
-  socket_init:		flexanet_pcmcia_socket_init,
-  socket_suspend:	flexanet_pcmcia_socket_suspend,
+  .socket_init		= flexanet_pcmcia_socket_init,
+  .socket_suspend	= flexanet_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_flexanet_init(void)
diff -Nru a/drivers/pcmcia/sa1100_freebird.c b/drivers/pcmcia/sa1100_freebird.c
--- a/drivers/pcmcia/sa1100_freebird.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/pcmcia/sa1100_freebird.c	Tue Oct 15 20:29:11 2002
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
@@ -178,14 +179,14 @@
 }
 
 static struct pcmcia_low_level freebird_pcmcia_ops = {
-  init:			freebird_pcmcia_init,
-  shutdown:		freebird_pcmcia_shutdown,
-  socket_state:		freebird_pcmcia_socket_state,
-  get_irq_info:		freebird_pcmcia_get_irq_info,
-  configure_socket:	freebird_pcmcia_configure_socket,
+  .init			= freebird_pcmcia_init,
+  .shutdown		= freebird_pcmcia_shutdown,
+  .socket_state		= freebird_pcmcia_socket_state,
+  .get_irq_info		= freebird_pcmcia_get_irq_info,
+  .configure_socket	= freebird_pcmcia_configure_socket,
 
-  socket_init:		freebird_pcmcia_socket_init,
-  socket_suspend:	freebird_pcmcia_socket_suspend,
+  .socket_init		= freebird_pcmcia_socket_init,
+  .socket_suspend	= freebird_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_freebird_init(void)
diff -Nru a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
--- a/drivers/pcmcia/sa1100_generic.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/pcmcia/sa1100_generic.c	Tue Oct 15 20:29:17 2002
@@ -719,7 +719,7 @@
 	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
 	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
 
-  if (map->map >= MAX_WIN){
+  if (map->map >= MAX_WIN) {
     printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
 	   map->map);
     return -1;
@@ -853,19 +853,19 @@
 #endif  /* defined(CONFIG_PROC_FS) */
 
 static struct pccard_operations sa1100_pcmcia_operations = {
-  init:			sa1100_pcmcia_sock_init,
-  suspend:		sa1100_pcmcia_suspend,
-  register_callback:	sa1100_pcmcia_register_callback,
-  inquire_socket:	sa1100_pcmcia_inquire_socket,
-  get_status:		sa1100_pcmcia_get_status,
-  get_socket:		sa1100_pcmcia_get_socket,
-  set_socket:		sa1100_pcmcia_set_socket,
-  get_io_map:		sa1100_pcmcia_get_io_map,
-  set_io_map:		sa1100_pcmcia_set_io_map,
-  get_mem_map:		sa1100_pcmcia_get_mem_map,
-  set_mem_map:		sa1100_pcmcia_set_mem_map,
+  .init			= sa1100_pcmcia_sock_init,
+  .suspend		= sa1100_pcmcia_suspend,
+  .register_callback	= sa1100_pcmcia_register_callback,
+  .inquire_socket	= sa1100_pcmcia_inquire_socket,
+  .get_status		= sa1100_pcmcia_get_status,
+  .get_socket		= sa1100_pcmcia_get_socket,
+  .set_socket		= sa1100_pcmcia_set_socket,
+  .get_io_map		= sa1100_pcmcia_get_io_map,
+  .set_io_map		= sa1100_pcmcia_set_io_map,
+  .get_mem_map		= sa1100_pcmcia_get_mem_map,
+  .set_mem_map		= sa1100_pcmcia_set_mem_map,
 #ifdef CONFIG_PROC_FS
-  proc_setup:		sa1100_pcmcia_proc_setup
+  .proc_setup		= sa1100_pcmcia_proc_setup
 #endif
 };
 
@@ -927,7 +927,7 @@
 }
 
 static struct notifier_block sa1100_pcmcia_notifier_block = {
-	notifier_call:	sa1100_pcmcia_notifier
+	.notifier_call	= sa1100_pcmcia_notifier
 };
 #endif
 
@@ -1148,6 +1148,9 @@
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 	pcmcia_gcplus_init();
 #endif
+#ifdef CONFIG_SA1100_H3600
+	pcmcia_h3600_init();
+#endif
 #ifdef CONFIG_SA1100_PANGOLIN
 	pcmcia_pangolin_init();
 #endif
@@ -1191,6 +1194,9 @@
 #endif
 #ifdef CONFIG_SA1100_GRAPHICSCLIENT
 	pcmcia_gcplus_exit();
+#endif
+#ifdef CONFIG_SA1100_H3600
+	pcmcia_h3600_exit();
 #endif
 #ifdef CONFIG_SA1100_PANGOLIN
 	pcmcia_pangolin_exit();
diff -Nru a/drivers/pcmcia/sa1100_graphicsclient.c b/drivers/pcmcia/sa1100_graphicsclient.c
--- a/drivers/pcmcia/sa1100_graphicsclient.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/pcmcia/sa1100_graphicsclient.c	Tue Oct 15 20:29:11 2002
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
@@ -159,14 +160,14 @@
 }
 
 static struct pcmcia_low_level gcplus_pcmcia_ops = { 
-  init:			gcplus_pcmcia_init,
-  shutdown:		gcplus_pcmcia_shutdown,
-  socket_state:		gcplus_pcmcia_socket_state,
-  get_irq_info:		gcplus_pcmcia_get_irq_info,
-  configure_socket:	gcplus_pcmcia_configure_socket,
+  .init			= gcplus_pcmcia_init,
+  .shutdown		= gcplus_pcmcia_shutdown,
+  .socket_state		= gcplus_pcmcia_socket_state,
+  .get_irq_info		= gcplus_pcmcia_get_irq_info,
+  .configure_socket	= gcplus_pcmcia_configure_socket,
 
-  socket_init:		gcplus_pcmcia_socket_init,
-  socket_suspend:	gcplus_pcmcia_socket_suspend,
+  .socket_init		= gcplus_pcmcia_socket_init,
+  .socket_suspend	= gcplus_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_gcplus_init(void)
diff -Nru a/drivers/pcmcia/sa1100_graphicsmaster.c b/drivers/pcmcia/sa1100_graphicsmaster.c
--- a/drivers/pcmcia/sa1100_graphicsmaster.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/pcmcia/sa1100_graphicsmaster.c	Tue Oct 15 20:29:12 2002
@@ -82,14 +82,14 @@
 }
 
 static struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
-  init:			graphicsmaster_pcmcia_init,
-  shutdown:		sa1111_pcmcia_shutdown,
-  socket_state:		sa1111_pcmcia_socket_state,
-  get_irq_info:		sa1111_pcmcia_get_irq_info,
-  configure_socket:	graphicsmaster_pcmcia_configure_socket,
+  .init			= graphicsmaster_pcmcia_init,
+  .shutdown		= sa1111_pcmcia_shutdown,
+  .socket_state		= sa1111_pcmcia_socket_state,
+  .get_irq_info		= sa1111_pcmcia_get_irq_info,
+  .configure_socket	= graphicsmaster_pcmcia_configure_socket,
 
-  socket_init:		sa1111_pcmcia_socket_init,
-  socket_suspend:	sa1111_pcmcia_socket_suspend,
+  .socket_init		= sa1111_pcmcia_socket_init,
+  .socket_suspend	= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_graphicsmaster_init(void)
diff -Nru a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c
--- a/drivers/pcmcia/sa1100_h3600.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/pcmcia/sa1100_h3600.c	Tue Oct 15 20:29:19 2002
@@ -10,6 +10,9 @@
 
 #include <asm/hardware.h>
 #include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/arch/h3600.h>
+
 #include "sa1100_generic.h"
 
 static struct irqs {
@@ -185,13 +188,27 @@
 }
 
 struct pcmcia_low_level h3600_pcmcia_ops = { 
-	init:			h3600_pcmcia_init,
-	shutdown:		h3600_pcmcia_shutdown,
-	socket_state:		h3600_pcmcia_socket_state,
-	get_irq_info:		h3600_pcmcia_get_irq_info,
-	configure_socket:	h3600_pcmcia_configure_socket,
+	.init			= h3600_pcmcia_init,
+	.shutdown		= h3600_pcmcia_shutdown,
+	.socket_state		= h3600_pcmcia_socket_state,
+	.get_irq_info		= h3600_pcmcia_get_irq_info,
+	.configure_socket	= h3600_pcmcia_configure_socket,
 
-	socket_init:		h3600_pcmcia_socket_init,
-	socket_suspend:		h3600_pcmcia_socket_suspend,
+	.socket_init		= h3600_pcmcia_socket_init,
+	.socket_suspend		= h3600_pcmcia_socket_suspend,
 };
 
+int __init pcmcia_h3600_init(void)
+{
+	int ret = -ENODEV;
+
+	if (machine_is_h3600())
+		ret = sa1100_register_pcmcia(&h3600_pcmcia_ops);
+
+	return ret;
+}
+
+void __exit pcmcia_h3600_exit(void)
+{
+	sa1100_unregister_pcmcia(&h3600_pcmcia_ops);
+}
diff -Nru a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
--- a/drivers/pcmcia/sa1100_jornada720.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/pcmcia/sa1100_jornada720.c	Tue Oct 15 20:29:16 2002
@@ -97,14 +97,14 @@
 }
 
 static struct pcmcia_low_level jornada720_pcmcia_ops = {
-  init:			jornada720_pcmcia_init,
-  shutdown:		sa1111_pcmcia_shutdown,
-  socket_state:		sa1111_pcmcia_socket_state,
-  get_irq_info:		sa1111_pcmcia_get_irq_info,
-  configure_socket:	jornada720_pcmcia_configure_socket,
+  .init			= jornada720_pcmcia_init,
+  .shutdown		= sa1111_pcmcia_shutdown,
+  .socket_state		= sa1111_pcmcia_socket_state,
+  .get_irq_info		= sa1111_pcmcia_get_irq_info,
+  .configure_socket	= jornada720_pcmcia_configure_socket,
 
-  socket_init:		sa1111_pcmcia_socket_init,
-  socket_suspend:	sa1111_pcmcia_socket_suspend,
+  .socket_init		= sa1111_pcmcia_socket_init,
+  .socket_suspend	= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_jornada720_init(void)
diff -Nru a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
--- a/drivers/pcmcia/sa1100_neponset.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/pcmcia/sa1100_neponset.c	Tue Oct 15 20:29:21 2002
@@ -127,14 +127,14 @@
 }
 
 static struct pcmcia_low_level neponset_pcmcia_ops = {
-	init:			neponset_pcmcia_init,
-	shutdown:		sa1111_pcmcia_shutdown,
-	socket_state:		sa1111_pcmcia_socket_state,
-	get_irq_info:		sa1111_pcmcia_get_irq_info,
-	configure_socket:	neponset_pcmcia_configure_socket,
+	.init			= neponset_pcmcia_init,
+	.shutdown		= sa1111_pcmcia_shutdown,
+	.socket_state		= sa1111_pcmcia_socket_state,
+	.get_irq_info		= sa1111_pcmcia_get_irq_info,
+	.configure_socket	= neponset_pcmcia_configure_socket,
 
-	socket_init:		sa1111_pcmcia_socket_init,
-	socket_suspend:		sa1111_pcmcia_socket_suspend,
+	.socket_init		= sa1111_pcmcia_socket_init,
+	.socket_suspend		= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_neponset_init(void)
diff -Nru a/drivers/pcmcia/sa1100_pangolin.c b/drivers/pcmcia/sa1100_pangolin.c
--- a/drivers/pcmcia/sa1100_pangolin.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/pcmcia/sa1100_pangolin.c	Tue Oct 15 20:29:12 2002
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
@@ -159,13 +160,13 @@
 }
 
 static struct pcmcia_low_level pangolin_pcmcia_ops = { 
-  init:			pangolin_pcmcia_init,
-  shutdown:		pangolin_pcmcia_shutdown,
-  socket_state:		pangolin_pcmcia_socket_state,
-  get_irq_info:		pangolin_pcmcia_get_irq_info,
-  configure_socket:	pangolin_pcmcia_configure_socket,
+  .init			= pangolin_pcmcia_init,
+  .shutdown		= pangolin_pcmcia_shutdown,
+  .socket_state		= pangolin_pcmcia_socket_state,
+  .get_irq_info		= pangolin_pcmcia_get_irq_info,
+  .configure_socket	= pangolin_pcmcia_configure_socket,
 
-  socket_init:		pangolin_pcmcia_socket_init,
+  .socket_init		= pangolin_pcmcia_socket_init,
   socket_suspend,	pangolin_pcmcia_socket_suspend,
 };
 
diff -Nru a/drivers/pcmcia/sa1100_pfs168.c b/drivers/pcmcia/sa1100_pfs168.c
--- a/drivers/pcmcia/sa1100_pfs168.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/pcmcia/sa1100_pfs168.c	Tue Oct 15 20:29:16 2002
@@ -119,14 +119,14 @@
 }
 
 static struct pcmcia_low_level pfs168_pcmcia_ops = {
-  init:			pfs168_pcmcia_init,
-  shutdown:		sa1111_pcmcia_shutdown,
-  socket_state:		sa1111_pcmcia_socket_state,
-  get_irq_info:		sa1111_pcmcia_get_irq_info,
-  configure_socket:	pfs168_pcmcia_configure_socket,
+  .init			= pfs168_pcmcia_init,
+  .shutdown		= sa1111_pcmcia_shutdown,
+  .socket_state		= sa1111_pcmcia_socket_state,
+  .get_irq_info		= sa1111_pcmcia_get_irq_info,
+  .configure_socket	= pfs168_pcmcia_configure_socket,
 
-  socket_init:		sa1111_pcmcia_socket_init,
-  socket_suspend:	sa1111_pcmcia_socket_suspend,
+  .socket_init		= sa1111_pcmcia_socket_init,
+  .socket_suspend	= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_pfs168_init(void)
diff -Nru a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c
--- a/drivers/pcmcia/sa1100_shannon.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/pcmcia/sa1100_shannon.c	Tue Oct 15 20:29:21 2002
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/arch/shannon.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
@@ -151,14 +152,14 @@
 }
 
 static struct pcmcia_low_level shannon_pcmcia_ops = {
-	init:			shannon_pcmcia_init,
-	shutdown:		shannon_pcmcia_shutdown,
-	socket_state:		shannon_pcmcia_socket_state,
-	get_irq_info:		shannon_pcmcia_get_irq_info,
-	configure_socket:	shannon_pcmcia_configure_socket,
+	.init			= shannon_pcmcia_init,
+	.shutdown		= shannon_pcmcia_shutdown,
+	.socket_state		= shannon_pcmcia_socket_state,
+	.get_irq_info		= shannon_pcmcia_get_irq_info,
+	.configure_socket	= shannon_pcmcia_configure_socket,
 
-	socket_init:		shannon_pcmcia_socket_init,
-	socket_suspend:		shannon_pcmcia_socket_suspend,
+	.socket_init		= shannon_pcmcia_socket_init,
+	.socket_suspend		= shannon_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_shannon_init(void)
diff -Nru a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c
--- a/drivers/pcmcia/sa1100_simpad.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/pcmcia/sa1100_simpad.c	Tue Oct 15 20:29:23 2002
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
  
@@ -158,14 +159,14 @@
 }
 
 static struct pcmcia_low_level simpad_pcmcia_ops = { 
-  init:			simpad_pcmcia_init,
-  shutdown:		simpad_pcmcia_shutdown,
-  socket_state:		simpad_pcmcia_socket_state,
-  get_irq_info:		simpad_pcmcia_get_irq_info,
-  configure_socket:	simpad_pcmcia_configure_socket,
+  .init			= simpad_pcmcia_init,
+  .shutdown		= simpad_pcmcia_shutdown,
+  .socket_state		= simpad_pcmcia_socket_state,
+  .get_irq_info		= simpad_pcmcia_get_irq_info,
+  .configure_socket	= simpad_pcmcia_configure_socket,
 
-  socket_init:		simpad_pcmcia_socket_init,
-  socket_suspend:	simpad_pcmcia_socket_suspend,
+  .socket_init		= simpad_pcmcia_socket_init,
+  .socket_suspend	= simpad_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_simpad_init(void)
diff -Nru a/drivers/pcmcia/sa1100_stork.c b/drivers/pcmcia/sa1100_stork.c
--- a/drivers/pcmcia/sa1100_stork.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/pcmcia/sa1100_stork.c	Tue Oct 15 20:29:17 2002
@@ -25,6 +25,7 @@
 #include <linux/i2c.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
@@ -227,14 +228,14 @@
 }
 
 static struct pcmcia_low_level stork_pcmcia_ops = { 
-	init:			stork_pcmcia_init,
-	shutdown:		stork_pcmcia_shutdown,
-	socket_state:		stork_pcmcia_socket_state,
-	get_irq_info:		stork_pcmcia_get_irq_info,
-	configure_socket:	stork_pcmcia_configure_socket,
+	.init			= stork_pcmcia_init,
+	.shutdown		= stork_pcmcia_shutdown,
+	.socket_state		= stork_pcmcia_socket_state,
+	.get_irq_info		= stork_pcmcia_get_irq_info,
+	.configure_socket	= stork_pcmcia_configure_socket,
 
-	socket_init:		stork_pcmcia_socket_init,
-	socket_suspend:		stork_pcmcia_socket_suspend,
+	.socket_init		= stork_pcmcia_socket_init,
+	.socket_suspend		= stork_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_stork_init(void)
diff -Nru a/drivers/pcmcia/sa1100_system3.c b/drivers/pcmcia/sa1100_system3.c
--- a/drivers/pcmcia/sa1100_system3.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/pcmcia/sa1100_system3.c	Tue Oct 15 20:29:23 2002
@@ -106,14 +106,14 @@
 }
 
 struct pcmcia_low_level system3_pcmcia_ops = {
-	init:				system3_pcmcia_init,
-	shutdown:			system3_pcmcia_shutdown,
-	socket_state:		system3_pcmcia_socket_state,
-	get_irq_info:		sa1111_pcmcia_get_irq_info,
-	configure_socket:	system3_pcmcia_configure_socket,
+	.init				= system3_pcmcia_init,
+	.shutdown			= system3_pcmcia_shutdown,
+	.socket_state		= system3_pcmcia_socket_state,
+	.get_irq_info		= sa1111_pcmcia_get_irq_info,
+	.configure_socket	= system3_pcmcia_configure_socket,
 
-	socket_init:		sa1111_pcmcia_socket_init,
-	socket_suspend:		sa1111_pcmcia_socket_suspend,
+	.socket_init		= sa1111_pcmcia_socket_init,
+	.socket_suspend		= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_system3_init(void)
diff -Nru a/drivers/pcmcia/sa1100_trizeps.c b/drivers/pcmcia/sa1100_trizeps.c
--- a/drivers/pcmcia/sa1100_trizeps.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/pcmcia/sa1100_trizeps.c	Tue Oct 15 20:29:17 2002
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>   // included trizeps.h
+#include <asm/mach-types.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
@@ -191,13 +192,13 @@
  *
  ******************************************************/
 struct pcmcia_low_level trizeps_pcmcia_ops = {
-	init:			trizeps_pcmcia_init,
-	shutdown:		trizeps_pcmcia_shutdown,
-	socket_state:		trizeps_pcmcia_socket_state,
-	get_irq_info:		trizeps_pcmcia_get_irq_info,
-	configure_socket:	trizeps_pcmcia_configure_socket,
-	socket_init:		trizeps_pcmcia_socket_init,
-	socket_suspend:		trizeps_pcmcia_socket_suspend,
+	.init			= trizeps_pcmcia_init,
+	.shutdown		= trizeps_pcmcia_shutdown,
+	.socket_state		= trizeps_pcmcia_socket_state,
+	.get_irq_info		= trizeps_pcmcia_get_irq_info,
+	.configure_socket	= trizeps_pcmcia_configure_socket,
+	.socket_init		= trizeps_pcmcia_socket_init,
+	.socket_suspend		= trizeps_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_trizeps_init(void)
diff -Nru a/drivers/pcmcia/sa1100_xp860.c b/drivers/pcmcia/sa1100_xp860.c
--- a/drivers/pcmcia/sa1100_xp860.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/pcmcia/sa1100_xp860.c	Tue Oct 15 20:29:16 2002
@@ -132,14 +132,14 @@
 }
 
 static struct pcmcia_low_level xp860_pcmcia_ops = { 
-  init:			xp860_pcmcia_init,
-  shutdown:		sa1111_pcmcia_shutdown,
-  socket_state:		sa1111_pcmcia_socket_state,
-  get_irq_info:		sa1111_pcmcia_get_irq_info,
-  configure_socket:	xp860_pcmcia_configure_socket,
+  .init			= xp860_pcmcia_init,
+  .shutdown		= sa1111_pcmcia_shutdown,
+  .socket_state		= sa1111_pcmcia_socket_state,
+  .get_irq_info		= sa1111_pcmcia_get_irq_info,
+  .configure_socket	= xp860_pcmcia_configure_socket,
 
-  socket_init:		sa1111_pcmcia_socket_init,
-  socket_suspend:	sa1111_pcmcia_socket_suspend,
+  .socket_init		= sa1111_pcmcia_socket_init,
+  .socket_suspend	= sa1111_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_xp860_init(void)
diff -Nru a/drivers/pcmcia/sa1100_yopy.c b/drivers/pcmcia/sa1100_yopy.c
--- a/drivers/pcmcia/sa1100_yopy.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/pcmcia/sa1100_yopy.c	Tue Oct 15 20:29:20 2002
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 
 #include <asm/hardware.h>
+#include <asm/mach-types.h>
 #include <asm/irq.h>
 #include "sa1100_generic.h"
 
@@ -160,14 +161,14 @@
 }
 
 static struct pcmcia_low_level yopy_pcmcia_ops = {
-	init:			yopy_pcmcia_init,
-	shutdown:		yopy_pcmcia_shutdown,
-	socket_state:		yopy_pcmcia_socket_state,
-	get_irq_info:		yopy_pcmcia_get_irq_info,
-	configure_socket:	yopy_pcmcia_configure_socket,
+	.init			= yopy_pcmcia_init,
+	.shutdown		= yopy_pcmcia_shutdown,
+	.socket_state		= yopy_pcmcia_socket_state,
+	.get_irq_info		= yopy_pcmcia_get_irq_info,
+	.configure_socket	= yopy_pcmcia_configure_socket,
 
-	socket_init:		yopy_pcmcia_socket_init,
-	socket_suspend:		yopy_pcmcia_socket_suspend,
+	.socket_init		= yopy_pcmcia_socket_init,
+	.socket_suspend		= yopy_pcmcia_socket_suspend,
 };
 
 int __init pcmcia_yopy_init(void)
diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/s390/block/dasd.c	Tue Oct 15 20:29:16 2002
@@ -2110,8 +2110,6 @@
 	dasd_device_t *device;
 	int rc;
 	
-	if ((!inp) || kdev_none(inp->i_rdev))
-		return -EINVAL;
 	if (dasd_probeonly) {
 		MESSAGE(KERN_INFO,
 			"No access to device (%d:%d) due to probeonly mode",
@@ -2154,8 +2152,6 @@
 	dasd_devmap_t *devmap;
 	dasd_device_t *device;
 
-	if ((!inp) || kdev_none(inp->i_rdev))
-		return -EINVAL;
 	devmap = dasd_devmap_from_kdev(inp->i_rdev);
 	device = (devmap != NULL) ?
 		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
--- a/drivers/s390/block/dasd_genhd.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/s390/block/dasd_genhd.c	Tue Oct 15 20:29:20 2002
@@ -190,14 +190,13 @@
 		}
 	}
 
-	gdp = alloc_disk();
+	gdp = alloc_disk(1 << DASD_PARTN_BITS);
 	if (!gdp)
 		return ERR_PTR(-ENOMEM);
 
 	/* Initialize gendisk structure. */
 	gdp->major = mi->major;
 	gdp->first_minor = index << DASD_PARTN_BITS;
-	gdp->minor_shift = DASD_PARTN_BITS;
 	gdp->fops = &dasd_device_operations;
 
 	/*
diff -Nru a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
--- a/drivers/s390/block/xpram.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/s390/block/xpram.c	Tue Oct 15 20:29:19 2002
@@ -324,24 +324,12 @@
 	return 0;
 }
 
-/*
- * The file operations
- */
-static int xpram_open (struct inode *inode, struct file *filp)
-{
-	if (minor(inode->i_rdev) >= xpram_devs)
-		return -ENODEV;
-	return 0;
-}
-
 static int xpram_ioctl (struct inode *inode, struct file *filp,
 		 unsigned int cmd, unsigned long arg)
 {
 	struct hd_geometry *geo;
 	unsigned long size;
 	int idx = minor(inode->i_rdev);
-	if (idx >= xpram_devs)
-		return -ENODEV;
  	if (cmd != HDIO_GETGEO)
 		return -EINVAL;
 	/*
@@ -350,8 +338,6 @@
 	 * whatever cylinders. Tell also that data starts at sector. 4.
 	 */
 	geo = (struct hd_geometry *) arg;
-	if (geo == NULL)
-		return -EINVAL;
 	size = (xpram_pages * 8) & ~0x3f;
 	put_user(size >> 6, &geo->cylinders);
 	put_user(4, &geo->heads);
@@ -364,7 +350,6 @@
 {
 	owner:   THIS_MODULE,
 	ioctl:   xpram_ioctl,
-	open:    xpram_open,
 };
 
 /*
@@ -441,7 +426,7 @@
 	int i, rc = -ENOMEM;
 
 	for (i = 0; i < xpram_devs; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(1);
 		if (!disk)
 			goto out;
 		xpram_disks[i] = disk;
@@ -481,7 +466,6 @@
 		offset += xpram_devices[i].size;
 		disk->major = XPRAM_MAJOR;
 		disk->first_minor = i;
-		disk->minor_shift = 0;
 		disk->fops = &xpram_devops;
 		sprintf(disk->disk_name, "slram%d", i);
 		set_capacity(disk, xpram_sizes[i] << 1);
diff -Nru a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
--- a/drivers/sbus/char/jsflash.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/sbus/char/jsflash.c	Tue Oct 15 20:29:16 2002
@@ -104,7 +104,6 @@
 struct jsfd_part {
 	unsigned long dbase;
 	unsigned long dsize;
-	int refcnt;
 };
 
 struct jsflash {
@@ -454,54 +453,12 @@
 	return 0;	/* XXX What security? */
 }
 
-static int jsfd_open(struct inode *inode, struct file *file)
-{
-	struct jsfd_part *jdp;
-	int dev;
-
-	if (!inode)
-		return -EINVAL;
-	dev = MINOR(inode->i_rdev);
-	if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) {
-		printk(KERN_ALERT "jsfd_open: illegal minor %d\n", dev);
-		return -ENODEV;
-	}
-
-	jdp = &jsf0.dv[dev];
-	jdp->refcnt++;
-
-	return 0;
-}
-
 static int jsf_release(struct inode *inode, struct file *file)
 {
 	jsf0.busy = 0;
 	return 0;
 }
 
-static int jsfd_release(struct inode *inode, struct file *file)
-{
-	struct jsfd_part *jdp;
-	int dev;
-
-	if (!inode)
-		return -ENODEV;
-	dev = MINOR(inode->i_rdev);
-	if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) {
-		printk(KERN_ALERT "jsfd_release: illegal minor %d\n", dev);
-		return -ENODEV;
-	}
-
-	jdp = &jsf0.dv[dev];
-	if (jdp->refcnt <= 0) {
-		printk(KERN_ALERT "jsfd_release: bad ref on minor %d\n", dev);
-	} else {
-		--jdp->refcnt;
-	}
-	/* N.B. Doesn't lo->file need an fput?? */
-	return 0;
-}
-
 static struct file_operations jsf_fops = {
 	.owner =	THIS_MODULE,
 	.llseek =	jsf_lseek,
@@ -517,8 +474,6 @@
 
 static struct block_device_operations jsfd_fops = {
 	.owner =	THIS_MODULE,
-	.open =		jsfd_open,
-	.release =	jsfd_release,
 };
 
 static int jsflash_init(void)
@@ -622,7 +577,7 @@
 
 	err = -ENOMEM;
 	for (i = 0; i < JSF_MAX; i++) {
-		struct gendisk *disk = alloc_disk();
+		struct gendisk *disk = alloc_disk(1);
 		if (!disk)
 			goto out;
 		jsfd_disk[i] = disk;
@@ -642,13 +597,10 @@
 		jsf = &jsf0;	/* actually, &jsfv[i >> JSF_PART_BITS] */
 		jdp = &jsf->dv[i&JSF_PART_MASK];
 
-		jdp->refcnt = 0;
-
 		disk->major = JSFD_MAJOR;
 		disk->first_minor = i;
 		sprintf(disk->disk_name, "jsfd%d", i);
 		disk->fops = &jsfd_fops;
-		disk->minor_shift = 0;
 		set_capacity(disk, jdp->dsize >> 9);
 		add_disk(disk);
 		set_device_ro(MKDEV(JSFD_MAJOR, i), 1);
diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
--- a/drivers/scsi/BusLogic.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/scsi/BusLogic.c	Tue Oct 15 20:29:21 2002
@@ -2604,21 +2604,21 @@
   through Host Adapter.
 */
 
-static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
+/*static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
 					    *HostAdapter)
 {
   int TargetID;
-  /*
+*/  /*
     Inhibit the Target Device Inquiry and Reporting if requested.
   */
-  if (BusLogic_MultiMasterHostAdapterP(HostAdapter) &&
+/*  if (BusLogic_MultiMasterHostAdapterP(HostAdapter) &&
       HostAdapter->DriverOptions != NULL &&
       HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
     return;
-  /*
+*/  /*
     Report on the Target Devices found.
   */
-  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+/*  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
     {
       BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
       if (TargetFlags->TargetExists && !TargetFlags->TargetInfoReported)
@@ -2674,7 +2674,7 @@
 	}
     }
 }
-
+*/
 
 /*
   BusLogic_InitializeHostStructure initializes the fields in the SCSI Host
@@ -2700,6 +2700,49 @@
   Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth;
 }
 
+/*
+  BusLogic_SlaveAttach will actually set the queue depth on individual
+  scsi devices as they are permanently added to the device chain.  We
+  shamelessly rip off the SelectQueueDepths code to make this work mostly
+  like it used to.  Since we don't get called once at the end of the scan
+  but instead get called for each device, we have to do things a bit
+  differently.
+*/
+int BusLogic_SlaveAttach(SCSI_Device_T *Device)
+{
+  BusLogic_HostAdapter_T *HostAdapter =
+    (BusLogic_HostAdapter_T *) Device->host->hostdata;
+  int TargetID = Device->id;
+  int QueueDepth = HostAdapter->QueueDepth[TargetID];
+
+  if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported &&
+      (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
+    {
+      if (QueueDepth == 0)
+	QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth;
+      HostAdapter->QueueDepth[TargetID] = QueueDepth;
+      scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth);
+    }
+  else
+    {
+      HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
+      QueueDepth = HostAdapter->UntaggedQueueDepth;
+      HostAdapter->QueueDepth[TargetID] = QueueDepth;
+      scsi_adjust_queue_depth(Device, 0, QueueDepth);
+    }
+  QueueDepth = 0;
+  for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+    if (HostAdapter->TargetFlags[TargetID].TargetExists)
+      {
+	QueueDepth += HostAdapter->QueueDepth[TargetID];
+      }
+  if (QueueDepth > HostAdapter->AllocatedCCBs)
+    BusLogic_CreateAdditionalCCBs(HostAdapter,
+				  QueueDepth
+				  - HostAdapter->AllocatedCCBs,
+				  false);
+  return 0;
+}
 
 /*
   BusLogic_SelectQueueDepths selects Queue Depths for each Target Device based
@@ -2709,7 +2752,7 @@
   since all the Target Devices have now been probed.
 */
 
-static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
+/* static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
 				       SCSI_Device_T *DeviceList)
 {
   BusLogic_HostAdapter_T *HostAdapter =
@@ -2764,8 +2807,8 @@
   for (Device = DeviceList; Device != NULL; Device = Device->next)
     if (Device->host == Host)
       Device->queue_depth = HostAdapter->QueueDepth[Device->id];
-  /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */
-  AllocatedQueueDepth += HostAdapter->TargetDeviceCount;
+*/  /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */
+/*  AllocatedQueueDepth += HostAdapter->TargetDeviceCount;
   if (AllocatedQueueDepth > HostAdapter->DriverQueueDepth)
     AllocatedQueueDepth = HostAdapter->DriverQueueDepth;
   BusLogic_CreateAdditionalCCBs(HostAdapter,
@@ -2778,7 +2821,7 @@
 	 HostAdapter = HostAdapter->Next)
       BusLogic_ReportTargetDeviceInfo(HostAdapter);
 }
-
+*/
 
 /*
   BusLogic_DetectHostAdapter probes for BusLogic Host Adapters at the standard
@@ -2881,7 +2924,10 @@
       memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T));
       HostAdapter->SCSI_Host = Host;
       HostAdapter->HostNumber = Host->host_no;
+      /*
+       * This function is deprecated
       Host->select_queue_depths = BusLogic_SelectQueueDepths;
+       */
       /*
 	Add Host Adapter to the end of the list of registered BusLogic
 	Host Adapters.
diff -Nru a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
--- a/drivers/scsi/BusLogic.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/BusLogic.h	Tue Oct 15 20:29:16 2002
@@ -60,6 +60,7 @@
 extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, struct block_device *,
 				       int *);
 extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
+extern int BusLogic_SlaveAttach(SCSI_Device_T *);
 
 
 /*
@@ -76,6 +77,7 @@
     queuecommand:   BusLogic_QueueCommand,	  /* Queue Command Function */ \
     abort:          BusLogic_AbortCommand,	  /* Abort Command Function */ \
     reset:          BusLogic_ResetCommand,	  /* Reset Command Function */ \
+    slave_attach:   BusLogic_SlaveAttach,	  /* Configure a SCSI_Device*/ \
     bios_param:     BusLogic_BIOSDiskParameters,  /* BIOS Disk Parameters   */ \
     unchecked_isa_dma: 1,			  /* Default Initial Value  */ \
     max_sectors:    128,			  /* I/O queue len limit    */ \
diff -Nru a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
--- a/drivers/scsi/NCR5380.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/scsi/NCR5380.c	Tue Oct 15 20:29:14 2002
@@ -1068,7 +1068,7 @@
  *      twiddling done to the host specific fields of cmd.  If the 
  *      main coroutine is not running, it is restarted.
  *
- *	Locks: io_request lock held by caller. Called functions drop and
+ *	Locks: host lock taken by caller. Called functions drop and
  *	retake this lock. Called functions take dma lock.
  */
 
@@ -1080,6 +1080,7 @@
 	struct Scsi_Host *instance = cmd->host;
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	Scsi_Cmnd *tmp;
+	unsigned long flags;
 
 #if (NDEBUG & NDEBUG_NO_WRITE)
 	switch (cmd->cmnd[0]) {
@@ -1092,6 +1093,7 @@
 	}
 #endif				/* (NDEBUG & NDEBUG_NO_WRITE) */
 
+	spin_lock_irqsave(instance->host_lock, flags);
 #ifdef NCR5380_STATS
 	switch (cmd->cmnd[0]) {
 		case WRITE:
@@ -1139,8 +1141,8 @@
 	dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"));
 
 	/* Run the coroutine if it isn't already running. */
+	spin_unlock_irqrestore(instance->host_lock, flags);
 	
-	/* FIMXE: drop any locks here */
 	run_main();
 	return 0;
 }
@@ -1892,7 +1894,6 @@
  *	back into sane shape.
  *
  *	Locks: caller holds queue lock
- *	FIXME: sort this out and get new_eh running
  */
  
 static void do_reset(struct Scsi_Host *host) {
@@ -2841,7 +2842,7 @@
  *	a problem, we could implement longjmp() / setjmp(), setjmp()
  *	called where the loop started in NCR5380_main().
  *
- *	Locks: io_request_lock held by caller
+ * Locks: host lock taken by function
  */
 
 #ifndef NCR5380_abort
@@ -2850,8 +2851,11 @@
 int NCR5380_abort(Scsi_Cmnd * cmd) {
 	NCR5380_local_declare();
 	struct Scsi_Host *instance = cmd->host;
+	unsigned long flags;
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	Scsi_Cmnd *tmp, **prev;
+	
+	spin_lock_irqsave(instance->host_lock, flags);
 
 	printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no);
 	print_Scsi_Cmnd(cmd);
@@ -2895,6 +2899,7 @@
  * aborted flag and get back into our main loop.
  */
 
+		spin_unlock_irqrestore(instance->host_lock, flags);
 		return 0;
 	}
 #endif
@@ -2915,6 +2920,7 @@
 			tmp->result = DID_ABORT << 16;
 			dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no));
 			tmp->done(tmp);
+			spin_unlock_irqrestore(instance->host_lock, flags);
 			return SUCCESS;
 		}
 #if (NDEBUG  & NDEBUG_ABORT)
@@ -2936,6 +2942,7 @@
 
 	if (hostdata->connected) {
 		dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no));
+		spin_unlock_irqrestore(instance->host_lock, flags);
 		return FAILED;
 	}
 /*
@@ -2980,6 +2987,7 @@
 					tmp->host_scribble = NULL;
 					tmp->result = DID_ABORT << 16;
 					tmp->done(tmp);
+					spin_unlock_irqrestore(instance->host_lock, flags);
 					return SUCCESS;
 				}
 		}
@@ -2992,7 +3000,9 @@
  * so we won't panic, but we will notify the user in case something really
  * broke.
  */
-	printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n" "         before abortion\n", instance->host_no);
+	spin_unlock_irqrestore(instance->host_lock, flags);
+	printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n"
+			"         before abortion\n", instance->host_no);
 	return FAILED;
 }
 
@@ -3004,19 +3014,22 @@
  *
  * Returns : SUCCESS
  *
- * Locks: io_request_lock held by caller
+ * Locks: host lock taken by function
  */
 
 #ifndef NCR5380_bus_reset
 static
 #endif
 int NCR5380_bus_reset(Scsi_Cmnd * cmd) {
+	unsigned long flags;
+	struct Scsi_Host *instance = cmd->host;
 	NCR5380_local_declare();
 	NCR5380_setup(cmd->host);
 
+	spin_lock_irqsave(instance->host_lock, flags);
 	NCR5380_print_status(cmd->host);
 	do_reset(cmd->host);
-
+	spin_unlock_irqrestore(instance->host_lock, flags);
 	return SUCCESS;
 }
 
diff -Nru a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile
--- a/drivers/scsi/aacraid/Makefile	Tue Oct 15 20:29:20 2002
+++ b/drivers/scsi/aacraid/Makefile	Tue Oct 15 20:29:20 2002
@@ -1,8 +1,10 @@
 # Adaptec aacraid
- 
+
 obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
 
 aacraid-objs	:= linit.o aachba.o commctrl.o comminit.o commsup.o \
 		   dpcsup.o rx.o sa.o
+
+EXTRA_CFLAGS	:= -Idrivers/scsi
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
--- a/drivers/scsi/aacraid/linit.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/aacraid/linit.c	Tue Oct 15 20:29:16 2002
@@ -128,7 +128,7 @@
 static int aac_eh_bus_reset(Scsi_Cmnd* cmd);
 static int aac_eh_reset(Scsi_Cmnd* cmd);
 
-static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *);
+static int aac_slave_attach(Scsi_Device *);
 
 /**
  *	aac_detect	-	Probe for aacraid cards
@@ -227,12 +227,6 @@
 			 * value returned as aac->id.
 			 */
 			host_ptr->unique_id = aac_count - 1;
-			/*
-			 *	This function is called after the device list has
-			 *	been built to find the tagged queueing depth 
-			 *	supported for each device.
-			 */
-			host_ptr->select_queue_depths = aac_queuedepth;
 			aac = (struct aac_dev *)host_ptr->hostdata;
 			/* attach a pointer back to Scsi_Host */
 			aac->scsi_host_ptr = host_ptr;	
@@ -520,31 +514,25 @@
 }
 
 /**
- *	aac_queuedepth		-	compute queue depths
- *	@host:	SCSI host in question
- *	@dev:	SCSI device we are considering
+ *	aac_slave_attach	-	do device specific setup
+ *	@dev:	SCSI device we are attaching
  *
- *	Selects queue depths for each target device based on the host adapter's
- *	total capacity and the queue depth supported by the target device.
- *	A queue depth of one automatically disables tagged queueing.
+ * 	Currently, all we do is set the queue depth on the device.
  */
 
-static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev )
+static int aac_slave_attach(Scsi_Device * dev )
 {
-	Scsi_Device * dptr;
 
-	dprintk((KERN_DEBUG "aac_queuedepth.\n"));
-	dprintk((KERN_DEBUG "Device #   Q Depth   Online\n"));
-	dprintk((KERN_DEBUG "---------------------------\n"));
-	for(dptr = dev; dptr != NULL; dptr = dptr->next)
-	{
-		if(dptr->host == host)
-		{
-			dptr->queue_depth = 10;		
-			dprintk((KERN_DEBUG "  %2d         %d        %d\n", 
-				dptr->id, dptr->queue_depth, dptr->online));
-		}
-	}
+	if(dev->tagged_supported)
+		scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, 128);
+	else
+		scsi_adjust_queue_depth(dev, 0, 1);
+
+	dprintk((KERN_DEBUG "(scsi%d:%d:%d:%d) Tagged Queue depth %2d, "
+				"%s\n", dev->host->host_no, dev->channel,
+				dev->id, dev->lun, dev->new_queue_depth,
+				dev->online ? "OnLine" : "OffLine"));
+	return 0;
 }
 
 
@@ -693,6 +681,7 @@
 	ioctl:          	aac_ioctl,
 	queuecommand:   	aac_queuecommand,
 	bios_param:     	aac_biosparm,	
+	slave_attach:		aac_slave_attach,
 	can_queue:      	AAC_NUM_IO_FIB,	
 	this_id:        	16,
 	sg_tablesize:   	16,
diff -Nru a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
--- a/drivers/scsi/advansys.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/scsi/advansys.c	Tue Oct 15 20:29:15 2002
@@ -673,6 +673,10 @@
      3.3GJ (4/15/02):
 	 1. hacks for lk 2.5 series (D. Gilbert)
 
+     3.3GJD (10/14/02):
+         1. change select_queue_depths to slave_attach
+	 2. make cmd_per_lun be sane again
+
   I. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -4208,8 +4212,7 @@
  */
 
 STATIC void       advansys_interrupt(int, void *, struct pt_regs *);
-STATIC void       advansys_select_queue_depths(struct Scsi_Host *,
-                                               Scsi_Device *);
+STATIC int	  advansys_slave_attach(Scsi_Device *);
 STATIC void       asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
@@ -5307,17 +5310,15 @@
              * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
              * SCSI function 'allocate_device' will panic. To allow the driver
              * to work as a module in these kernels set 'cmd_per_lun' to 1.
-             */
+	     *
+	     * Note: This is wrong.  cmd_per_lun should be set to the depth
+	     * you want on untagged devices always.
 #ifdef MODULE
+             */
             shp->cmd_per_lun = 1;
-#else /* MODULE */
+/* #else
             shp->cmd_per_lun = 0;
-#endif /* MODULE */
-            /*
-             * Use the host 'select_queue_depths' function to determine
-             * the number of commands to queue per device.
-             */
-            shp->select_queue_depths = advansys_select_queue_depths;
+#endif */
 
             /*
              * Set the maximum number of scatter-gather elements the
@@ -6346,34 +6347,33 @@
  * Set the number of commands to queue per device for the
  * specified host adapter.
  */
-STATIC void
-advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
+STATIC int
+advansys_slave_attach(Scsi_Device *device)
 {
-    Scsi_Device        *device;
     asc_board_t        *boardp;
 
-    boardp = ASC_BOARDP(shp);
+    boardp = ASC_BOARDP(device->host);
     boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
-    for (device = devicelist; device != NULL; device = device->next) {
-        if (device->host != shp) {
-            continue;
-        }
-        /*
-         * Save a pointer to the device and set its initial/maximum
-         * queue depth.
-         */
+    /*
+     * Save a pointer to the device and set its initial/maximum
+     * queue depth.  Only save the pointer for a lun0 dev though.
+     */
+    if(device->lun == 0)
         boardp->device[device->id] = device;
+    if(device->tagged_supported) {
         if (ASC_NARROW_BOARD(boardp)) {
-            device->queue_depth =
-                boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id];
+	    scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+                boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]);
         } else {
-            device->queue_depth =
-                boardp->dvc_var.adv_dvc_var.max_dvc_qng;
+	    scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+                boardp->dvc_var.adv_dvc_var.max_dvc_qng);
         }
-        ASC_DBG3(1,
-            "advansys_select_queue_depths: shp 0x%lx, id %d, depth %d\n",
-            (ulong) shp, device->id, device->queue_depth);
+    } else {
+	scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
     }
+    ASC_DBG3(1, "advansys_slave_attach: shp 0x%lx, id %d, depth %d\n",
+            (ulong) shp, device->id, device->queue_depth);
+    return 0;
 }
 
 /*
@@ -8432,7 +8432,7 @@
                 continue;
             }
             len = asc_prt_line(cp, leftlen, " %X:%d",
-                i, boardp->device[i]->queue_depth);
+                i, boardp->device[i]->current_queue_depth);
             ASC_PRT_NEXT();
         }
         len = asc_prt_line(cp, leftlen, "\n");
diff -Nru a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
--- a/drivers/scsi/advansys.h	Tue Oct 15 20:29:23 2002
+++ b/drivers/scsi/advansys.h	Tue Oct 15 20:29:23 2002
@@ -53,6 +53,7 @@
 int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 int advansys_reset(Scsi_Cmnd *);
 int advansys_biosparam(Disk *, struct block_device *, int[]);
+static int advansys_slave_attach(Scsi_Device *);
 #ifdef CONFIG_PROC_FS
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
 extern struct proc_dir_entry proc_scsi_advansys;
@@ -79,6 +80,7 @@
     queuecommand:               advansys_queuecommand, \
     eh_bus_reset_handler:	advansys_reset, \
     bios_param:                 advansys_biosparam, \
+    slave_attach:		advansys_slave_attach, \
     /* \
      * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
      * must be set. The flag will be cleared in advansys_detect for non-ISA \
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- a/drivers/scsi/aic7xxx/aic7xxx_linux.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c	Tue Oct 15 20:29:16 2002
@@ -430,8 +430,7 @@
 static void ahc_linux_release_sim_queue(u_long arg);
 static int  ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
 static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
-static void ahc_linux_select_queue_depth(struct Scsi_Host *host,
-					 Scsi_Device *scsi_devs);
+static int  ahc_linux_slave_attach(Scsi_Device *device);
 static void ahc_linux_device_queue_depth(struct ahc_softc *ahc,
 					 Scsi_Device *device);
 static struct ahc_linux_target*	ahc_linux_alloc_target(struct ahc_softc*,
@@ -1131,7 +1130,6 @@
 	host->can_queue = AHC_MAX_QUEUE;
 	host->cmd_per_lun = 2;
 	host->sg_tablesize = AHC_NSEG;
-	host->select_queue_depths = ahc_linux_select_queue_depth;
 	/* XXX No way to communicate the ID for multiple channels */
 	host->this_id = ahc->our_id;
 	host->irq = ahc->platform_data->irq;
@@ -1449,25 +1447,17 @@
  * Sets the queue depth for each SCSI device hanging
  * off the input host adapter.
  */
-static void
-ahc_linux_select_queue_depth(struct Scsi_Host * host,
-			     Scsi_Device * scsi_devs)
+static int
+ahc_linux_slave_attach(Scsi_Device * device)
 {
-	Scsi_Device *device;
 	struct	ahc_softc *ahc;
 	u_long	flags;
-	int	scbnum;
 
-	ahc = *((struct ahc_softc **)host->hostdata);
+	ahc = *((struct ahc_softc **)device->host->hostdata);
 	ahc_lock(ahc, &flags);
-	scbnum = 0;
-	for (device = scsi_devs; device != NULL; device = device->next) {
-		if (device->host == host) {
-			ahc_linux_device_queue_depth(ahc, device);
-			scbnum += device->queue_depth;
-		}
-	}
+	ahc_linux_device_queue_depth(ahc, device);
 	ahc_unlock(ahc, &flags);
+	return 0;
 }
 
 /*
@@ -1512,7 +1502,8 @@
 		}
 	}
 	if (tags != 0) {
-		device->queue_depth = tags;
+		scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, tags);
+		/* device->queue_depth = tags; */
 		ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
 		printf("scsi%d:%c:%d:%d: Tagged Queuing enabled.  Depth %d\n",
 	       	       ahc->platform_data->host->host_no, device->channel + 'A',
@@ -1523,8 +1514,9 @@
 		 * us at any time even though we can only execute them
 		 * serially on the controller/device.  This should remove
 		 * some latency.
-		 */
 		device->queue_depth = 2;
+		 */
+		scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
 	}
 }
 
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
--- a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h	Tue Oct 15 20:29:16 2002
@@ -80,7 +80,7 @@
 	eh_host_reset_handler: NULL,				\
 	abort: NULL,						\
 	reset: NULL,						\
-	slave_attach: NULL,					\
+	slave_attach: ahc_linux_slave_attach,			\
 	bios_param: AIC7XXX_BIOSPARAM,				\
 	can_queue: 253,		/* max simultaneous cmds      */\
 	this_id: -1,		/* scsi id of host adapter    */\
diff -Nru a/drivers/scsi/cpqfc.Readme b/drivers/scsi/cpqfc.Readme
--- a/drivers/scsi/cpqfc.Readme	Tue Oct 15 20:29:23 2002
+++ b/drivers/scsi/cpqfc.Readme	Tue Oct 15 20:29:23 2002
@@ -7,6 +7,8 @@
 SEST size 512 Exchanges (simultaneous I/Os) limited by module kmalloc() 
 	max of 128k bytes contiguous.
 
+Ver 2.5.4  Oct 03, 2002
+   * fixed memcpy of sense buffer in ioctl to copy the smaller defined size
 Ver 2.5.3  Aug 01, 2002
    * fix the passthru ioctl to handle the Scsi_Cmnd->request being a pointer
 Ver 2.5.1  Jul 30, 2002
diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
--- a/drivers/scsi/cpqfcTSinit.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/scsi/cpqfcTSinit.c	Tue Oct 15 20:29:12 2002
@@ -68,7 +68,7 @@
 
 /* Embedded module documentation macros - see module.h */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.3");
+MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.4");
 MODULE_LICENSE("GPL");
   
 int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
@@ -668,7 +668,11 @@
 	{
 	  memcpy( vendor_cmd->sense_data, // see struct def - size=40
 		  ScsiPassThruReq->sr_sense_buffer, 
-		  sizeof(ScsiPassThruReq->sr_sense_buffer)); 
+		  sizeof(ScsiPassThruReq->sr_sense_buffer) <
+                  sizeof(vendor_cmd->sense_data)           ?
+                  sizeof(ScsiPassThruReq->sr_sense_buffer) :
+                  sizeof(vendor_cmd->sense_data)
+                ); 
 	}
         SDpnt = ScsiPassThruReq->sr_device;
 	/* upper_private_data is already freed in call_scsi_done() */
diff -Nru a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h
--- a/drivers/scsi/cpqfcTSstructs.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/cpqfcTSstructs.h	Tue Oct 15 20:29:16 2002
@@ -32,7 +32,7 @@
 // don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
 #define VER_MAJOR 2
 #define VER_MINOR 5
-#define VER_SUBMINOR 3
+#define VER_SUBMINOR 4
 
 // Macros for kernel (esp. SMP) tracing using a PCI analyzer
 // (e.g. x86).
diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
--- a/drivers/scsi/dpt_i2o.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/scsi/dpt_i2o.c	Tue Oct 15 20:29:15 2002
@@ -48,7 +48,6 @@
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include <linux/delay.h>	/* for udelay */
-#include <linux/tqueue.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>	/* for printk */
 #include <linux/sched.h>
@@ -356,23 +355,20 @@
 }
 
 
-static void adpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device * devicelist)
+static int adpt_slave_attach(Scsi_Device * device)
 {
-	Scsi_Device *device;	/* scsi layer per device information */
+	struct Scsi_Host *host = device->host;
 	adpt_hba* pHba;
 
 	pHba = (adpt_hba *) host->hostdata[0];
 
-	for (device = devicelist; device != NULL; device = device->next) {
-		if (device->host != host) {
-			continue;
-		}
-		if (host->can_queue) {
-			device->queue_depth =  host->can_queue - 1;
-		} else {
-			device->queue_depth = 1;
-		}
+	if (host->can_queue && device->tagged_supported) {
+		scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+				host->can_queue - 1);
+	} else {
+		scsi_adjust_queue_depth(device, 0, 1);
 	}
+	return 0;
 }
 
 static int adpt_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
@@ -2194,11 +2190,10 @@
 	host->max_id = 16;
 	host->max_lun = 256;
 	host->max_channel = pHba->top_scsi_channel + 1;
-	host->cmd_per_lun = 256;
+	host->cmd_per_lun = 1;
 	host->unique_id = (uint) pHba;
 	host->sg_tablesize = pHba->sg_tablesize;
 	host->can_queue = pHba->post_fifo_size;
-	host->select_queue_depths = adpt_select_queue_depths;
 
 	return 0;
 }
diff -Nru a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
--- a/drivers/scsi/dpti.h	Tue Oct 15 20:29:11 2002
+++ b/drivers/scsi/dpti.h	Tue Oct 15 20:29:11 2002
@@ -43,6 +43,7 @@
 static int adpt_abort(Scsi_Cmnd * cmd);
 static int adpt_reset(Scsi_Cmnd* cmd);
 static int adpt_release(struct Scsi_Host *host);
+static int adpt_slave_attach(Scsi_Device *);
 
 static const char *adpt_info(struct Scsi_Host *pSHost);
 static int adpt_bios_param(Disk * disk, struct block_device *dev, int geom[]);
@@ -90,10 +91,11 @@
 	eh_bus_reset_handler: adpt_bus_reset,				\
 	eh_host_reset_handler: adpt_reset,				\
 	bios_param: adpt_bios_param,					\
+	slave_attach: adpt_slave_attach,				\
 	can_queue: MAX_TO_IOP_MESSAGES,	/* max simultaneous cmds      */\
 	this_id: 7,			/* scsi id of host adapter    */\
 	sg_tablesize: 0,		/* max scatter-gather cmds    */\
-	cmd_per_lun: 256,		/* cmds per lun (linked cmds) */\
+	cmd_per_lun: 1,			/* cmds per lun (linked cmds) */\
 	use_clustering: ENABLE_CLUSTERING,				\
 	proc_name: "dpt_i2o"	/* this is the name of our proc node*/	\
 }
@@ -346,7 +348,6 @@
 static s32 adpt_i2o_reparse_lct(adpt_hba* pHba);
 static s32 adpt_send_nop(adpt_hba*pHba,u32 m);
 static void adpt_i2o_delete_hba(adpt_hba* pHba);
-static void adpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device * devicelist);
 static void adpt_inquiry(adpt_hba* pHba);
 static void adpt_fail_posted_scbs(adpt_hba* pHba);
 static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun);
diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c
--- a/drivers/scsi/eata.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/scsi/eata.c	Tue Oct 15 20:29:20 2002
@@ -750,63 +750,34 @@
 static int max_queue_depth = MAX_CMD_PER_LUN;
 #endif
 
-static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
-   Scsi_Device *dev;
-   int j, ntag = 0, nuntag = 0, tqd, utqd;
+static int eata2x_slave_attach(Scsi_Device *dev) {
+   int j, tqd, utqd;
+   char *link_suffix = "";
+   struct Scsi_Host *host = dev->host;
 
    j = ((struct hostdata *) host->hostdata)->board_number;
 
-   for(dev = devlist; dev; dev = dev->next) {
-
-      if (dev->host != host) continue;
-
-      if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm))
-         ntag++;
-      else
-         nuntag++;
-      }
-
    utqd = MAX_CMD_PER_LUN;
+   tqd = (host->can_queue - utqd);
 
-   tqd = (host->can_queue - utqd * nuntag) / (ntag ? ntag : 1);
-
-   if (tqd > max_queue_depth) tqd = max_queue_depth;
-
-   if (tqd < MAX_CMD_PER_LUN) tqd = MAX_CMD_PER_LUN;
-
-   for(dev = devlist; dev; dev = dev->next) {
-      char *tag_suffix = "", *link_suffix = "";
-
-      if (dev->host != host) continue;
-
-      if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm))
-         dev->queue_depth = tqd;
+   if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) {
+      if(!dev->tagged_supported)
+         scsi_adjust_queue_depth(dev, 0, tqd);
       else
-         dev->queue_depth = utqd;
-
-      if (TLDEV(dev->type)) {
-         if (linked_comm && dev->queue_depth > 2)
-            link_suffix = ", sorted";
-         else
-            link_suffix = ", unsorted";
-         }
-
-      if (tagged_comm && dev->tagged_supported && TLDEV(dev->type)) {
-         dev->tagged_queue = 1;
-         dev->current_tag = 1;
-         }
-
-      if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue)
-         tag_suffix = ", soft-tagged";
-      else if (dev->tagged_supported && TLDEV(dev->type))
-         tag_suffix = ", tagged";
-
-      printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n",
-             BN(j), host->host_no, dev->channel, dev->id, dev->lun,
-             dev->queue_depth, link_suffix, tag_suffix);
-      }
+         scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd);
+   } else {
+      scsi_adjust_queue_depth(dev, 0, utqd);
+   }
 
-   return;
+   if (!dev->simple_tags && dev->new_queue_depth > 2)
+      link_suffix = ", sorted";
+   else if (dev->simple_tags)
+      link_suffix = ", unsorted";
+
+   printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s.\n",
+          BN(j), host->host_no, dev->channel, dev->id, dev->lun,
+          dev->new_queue_depth, link_suffix);
+   return 0;
 }
 
 static inline int wait_on_busy(unsigned long iobase, unsigned int loop) {
@@ -1071,7 +1042,6 @@
    sh[j]->this_id = (ushort) info.host_addr[3];
    sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size);
    sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
-   sh[j]->select_queue_depths = select_queue_depths;
    memset(HD(j), 0, sizeof(struct hostdata));
    HD(j)->subversion = subversion;
    HD(j)->protocol_rev = protocol_rev;
@@ -1542,7 +1512,7 @@
    /* Map DMA buffers and SG list */
    map_dma(i, j);
 
-   if (SCpnt->device->tagged_queue) {
+   if (SCpnt->device->simple_tags) {
 
       if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] ||
             HD(j)->target_to[SCpnt->target][SCpnt->channel])
@@ -1560,8 +1530,7 @@
       cpp->mess[1] = SCpnt->device->current_tag++;
       }
 
-   if (linked_comm && SCpnt->device->queue_depth > 2
-                                     && TLDEV(SCpnt->device->type)) {
+   if (SCpnt->device->new_queue_depth > 2 && !SCpnt->device->simple_tags) {
       HD(j)->cp_stat[i] = READY;
       flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE);
       return 0;
@@ -2071,7 +2040,7 @@
 
    sync_dma(i, j);
 
-   if (linked_comm && SCpnt->device->queue_depth > 2
+   if (linked_comm && SCpnt->device->new_queue_depth > 2
                                      && TLDEV(SCpnt->device->type))
       flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE);
 
diff -Nru a/drivers/scsi/eata.h b/drivers/scsi/eata.h
--- a/drivers/scsi/eata.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/scsi/eata.h	Tue Oct 15 20:29:12 2002
@@ -12,6 +12,7 @@
 int eata2x_abort(Scsi_Cmnd *);
 int eata2x_reset(Scsi_Cmnd *);
 int eata2x_biosparam(Disk *, struct block_device *, int *);
+static int eata2x_slave_attach(Scsi_Device *);
 
 #define EATA_VERSION "7.22.00"
 
@@ -27,6 +28,7 @@
                 eh_bus_reset_handler:    NULL,                               \
                 eh_host_reset_handler:   eata2x_reset,                       \
                 bios_param:              eata2x_biosparam,                   \
+		slave_attach:		 eata2x_slave_attach,		     \
                 this_id:                 7,                                  \
                 unchecked_isa_dma:       1,                                  \
                 use_clustering:          ENABLE_CLUSTERING,                  \
diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/scsi/esp.c	Tue Oct 15 20:29:23 2002
@@ -1576,7 +1576,6 @@
 		memset(esp_dev, 0, sizeof(struct esp_device));
 		SDptr->hostdata = esp_dev;
 	}
-	}
 
 	esp->snip = 0;
 	esp->msgout_len = 0;
@@ -3589,7 +3588,7 @@
 				     Scsi_Cmnd *SCptr,
 				     struct esp_device *esp_dev)
 {
-	if (esp_dev->sync || SCptr->SDptr->borken) {
+	if (esp_dev->sync || SCptr->device->borken) {
 		/* sorry, no can do */
 		ESPSDTR(("forcing to async, "));
 		build_sync_nego_msg(esp, 0, 0);
@@ -3811,7 +3810,7 @@
 
 			/* Regardless, next try for sync transfers. */
 			build_sync_nego_msg(esp, esp->sync_defp, 15);
-			espo_dev->sync = 1;
+			esp_dev->sync = 1;
 			esp->snip = 1;
 			message_out = EXTENDED_MESSAGE;
 		}
diff -Nru a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
--- a/drivers/scsi/fcal.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/scsi/fcal.c	Tue Oct 15 20:29:12 2002
@@ -70,17 +70,21 @@
 
 static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
 
-static void fcal_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist)
+int fcal_slave_attach(Scsi_Device *device)
 {
-	Scsi_Device *device;
+	int depth_to_use;
 	
-	for (device = devlist; device; device = device->next) {
-		if (device->host != host) continue;
-		if (device->tagged_supported)
-			device->queue_depth = /* 254 */ 8;
-		else
-			device->queue_depth = 2;
-	}
+	if (device->tagged_supported)
+		depth_to_use = /* 254 */ 8;
+	else
+		depth_to_use = 2;
+
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+
+	return 0;
 }
 
 /* Detect all FC Arbitrated Loops attached to the machine.
@@ -165,7 +169,6 @@
 #ifdef __sparc_v9__
 		host->unchecked_isa_dma = 1;
 #endif
-		host->select_queue_depths = fcal_select_queue_depths;
 
 		fc->channels = 1;
 		fc->targets = 127;
diff -Nru a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h
--- a/drivers/scsi/fcal.h	Tue Oct 15 20:29:11 2002
+++ b/drivers/scsi/fcal.h	Tue Oct 15 20:29:11 2002
@@ -23,6 +23,7 @@
 int fcal_detect(Scsi_Host_Template *);
 int fcal_release(struct Scsi_Host *);
 int fcal_proc_info (char *, char **, off_t, int, int, int);
+int fcal_slave_attach(Scsi_Device *);
 
 #define FCAL {							\
 	name:			"Fibre Channel Arbitrated Loop",\
@@ -30,6 +31,7 @@
 	release:		fcal_release,			\
 	proc_info:		fcal_proc_info,			\
 	queuecommand:		fcp_scsi_queuecommand,		\
+	slave_attach:		fcal_slave_attach,		\
 	can_queue:		FCAL_CAN_QUEUE,			\
 	this_id:		-1,				\
 	sg_tablesize:		1,				\
diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/scsi/hosts.c	Tue Oct 15 20:29:12 2002
@@ -229,7 +229,6 @@
     if (!blk_nohighio)
 	retval->highmem_io = tpnt->highmem_io;
 
-    retval->select_queue_depths = tpnt->select_queue_depths;
     retval->max_sectors = tpnt->max_sectors;
     retval->use_blk_tcq = tpnt->use_blk_tcq;
 
diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h	Tue Oct 15 20:29:15 2002
+++ b/drivers/scsi/hosts.h	Tue Oct 15 20:29:15 2002
@@ -266,14 +266,6 @@
      */
     int (* bios_param)(Disk *, struct block_device *, int []);
 
-
-    /*
-     * Used to set the queue depth for a specific device.
-     *
-     * Once the slave_attach() function is in full use, this will go away.
-     */
-    void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
-
     /*
      * This determines if we will use a non-interrupt driven
      * or an interrupt driven scheme,  It is set to the maximum number
@@ -384,6 +376,8 @@
      */
     struct Scsi_Host      * next;
     Scsi_Device           * host_queue;
+    struct list_head	  all_scsi_hosts;
+    struct list_head	  my_devices;
 
     spinlock_t		  default_lock;
     spinlock_t		  *host_lock;
@@ -488,8 +482,6 @@
      * Value host_blocked counts down from
      */
     unsigned int max_host_blocked;
-
-    void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
     /*
      * For SCSI hosts which are PCI devices, set pci_dev so that
diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/scsi/ips.c	Tue Oct 15 20:29:11 2002
@@ -1879,10 +1879,12 @@
    int          min;
 
    ha = IPS_HA(SDptr->host);
-   min = ha->max_cmds / 4;
-   if (min < 8)
-      min = ha->max_cmds - 1;
-   scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
+   if (SDptr->tagged_supported) {
+      min = ha->max_cmds / 2;
+      if (min <= 16)
+         min = ha->max_cmds - 1;
+      scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
+   }
    return 0;
 }
 
diff -Nru a/drivers/scsi/ips.h b/drivers/scsi/ips.h
--- a/drivers/scsi/ips.h	Tue Oct 15 20:29:14 2002
+++ b/drivers/scsi/ips.h	Tue Oct 15 20:29:14 2002
@@ -429,7 +429,7 @@
     can_queue : 0,                        \
     this_id: -1,                          \
     sg_tablesize : IPS_MAX_SG,            \
-    cmd_per_lun: 16,                      \
+    cmd_per_lun: 3,                       \
     present : 0,                          \
     unchecked_isa_dma : 0,                \
     use_clustering : ENABLE_CLUSTERING,   \
@@ -458,7 +458,7 @@
     can_queue : 0,                        \
     this_id: -1,                          \
     sg_tablesize : IPS_MAX_SG,            \
-    cmd_per_lun: 16,                      \
+    cmd_per_lun: 3,                       \
     present : 0,                          \
     unchecked_isa_dma : 0,                \
     use_clustering : ENABLE_CLUSTERING,   \
@@ -488,7 +488,7 @@
     can_queue : 0,                        \
     this_id: -1,                          \
     sg_tablesize : IPS_MAX_SG,            \
-    cmd_per_lun: 16,                      \
+    cmd_per_lun: 3,                       \
     present : 0,                          \
     unchecked_isa_dma : 0,                \
     use_clustering : ENABLE_CLUSTERING,   \
diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/scsi/ncr53c8xx.c	Tue Oct 15 20:29:15 2002
@@ -378,8 +378,6 @@
 
 #define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
 
-static void ncr53c8xx_select_queue_depths(
-	struct Scsi_Host *host, struct scsi_device *devlist);
 static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
 static void ncr53c8xx_timeout(unsigned long np);
 
@@ -3710,7 +3708,6 @@
 	instance->dma_channel	= 0;
 	instance->cmd_per_lun	= MAX_TAGS;
 	instance->can_queue	= (MAX_START-4);
-	instance->select_queue_depths = ncr53c8xx_select_queue_depths;
 	scsi_set_pci_device(instance, device->pdev);
 
 #ifdef SCSI_NCR_INTEGRITY_CHECKING
@@ -8500,56 +8497,57 @@
 **   Linux select queue depths function
 */
 
-static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist)
+int ncr53c8xx_slave_attach(Scsi_Device *device)
 {
-	struct scsi_device *device;
+	struct Scsi_Host *host = device->host;
+	ncb_p np;
+	tcb_p tp;
+	lcb_p lp;
+	int numtags, depth_to_use;
 
-	for (device = devlist; device; device = device->next) {
-		ncb_p np;
-		tcb_p tp;
-		lcb_p lp;
-		int numtags;
-
-		if (device->host != host)
-			continue;
-
-		np = ((struct host_data *) host->hostdata)->ncb;
-		tp = &np->target[device->id];
-		lp = tp->lp[device->lun];
-
-		/*
-		**	Select queue depth from driver setup.
-		**	Donnot use more than configured by user.
-		**	Use at least 2.
-		**	Donnot use more than our maximum.
-		*/
-		numtags = device_queue_depth(np->unit, device->id, device->lun);
-		if (numtags > tp->usrtags)
-			numtags = tp->usrtags;
-		if (!device->tagged_supported)
-			numtags = 1;
-		device->queue_depth = numtags;
-		if (device->queue_depth < 2)
-			device->queue_depth = 2;
-		if (device->queue_depth > MAX_TAGS)
-			device->queue_depth = MAX_TAGS;
-
-		/*
-		**	Since the queue depth is not tunable under Linux,
-		**	we need to know this value in order not to 
-		**	announce stupid things to user.
-		*/
-		if (lp) {
-			lp->numtags = lp->maxtags = numtags;
-			lp->scdev_depth = device->queue_depth;
-		}
-		ncr_setup_tags (np, device->id, device->lun);
+	np = ((struct host_data *) host->hostdata)->ncb;
+	tp = &np->target[device->id];
+	lp = tp->lp[device->lun];
+
+	/*
+	**	Select queue depth from driver setup.
+	**	Donnot use more than configured by user.
+	**	Use at least 2.
+	**	Donnot use more than our maximum.
+	*/
+	numtags = device_queue_depth(np->unit, device->id, device->lun);
+	if (numtags > tp->usrtags)
+		numtags = tp->usrtags;
+	if (!device->tagged_supported)
+		numtags = 1;
+	depth_to_use = numtags;
+	if (depth_to_use < 2)
+		depth_to_use = 2;
+	if (depth_to_use > MAX_TAGS)
+		depth_to_use = MAX_TAGS;
+
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+
+	/*
+	**	Since the queue depth is not tunable under Linux,
+	**	we need to know this value in order not to 
+	**	announce stupid things to user.
+	*/
+	if (lp) {
+		lp->numtags = lp->maxtags = numtags;
+		lp->scdev_depth = depth_to_use;
+	}
+	ncr_setup_tags (np, device->id, device->lun);
 
 #ifdef DEBUG_NCR53C8XX
-printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
-	np->unit, device->id, device->lun, device->queue_depth);
+	printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
+	       np->unit, device->id, device->lun, depth_to_use);
 #endif
-	}
+
+	return 0;
 }
 
 /*
diff -Nru a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
--- a/drivers/scsi/ncr53c8xx.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/ncr53c8xx.h	Tue Oct 15 20:29:16 2002
@@ -59,6 +59,7 @@
 const char *ncr53c8xx_info(struct Scsi_Host *host);
 int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int);
+int ncr53c8xx_slave_attach(Scsi_Device *);
 
 #ifdef MODULE
 int ncr53c8xx_release(struct Scsi_Host *);
@@ -74,6 +75,7 @@
 			release:        ncr53c8xx_release,	\
 			info:           ncr53c8xx_info, 	\
 			queuecommand:   ncr53c8xx_queue_command,\
+			slave_attach:   ncr53c8xx_slave_attach, \
 			abort:          ncr53c8xx_abort,	\
 			reset:          ncr53c8xx_reset,	\
 			bios_param:     scsicam_bios_param,	\
diff -Nru a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
--- a/drivers/scsi/pluto.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/pluto.c	Tue Oct 15 20:29:16 2002
@@ -71,17 +71,21 @@
 		up(&fc_sem);
 }
 
-static void pluto_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist)
+int pluto_slave_attach(Scsi_Device *device)
 {
-	Scsi_Device *device;
-	
-	for (device = devlist; device; device = device->next) {
-		if (device->host != host) continue;
-		if (device->tagged_supported)
-			device->queue_depth = /* 254 */ 8;
-		else
-			device->queue_depth = 2;
-	}
+	int depth_to_use;
+
+	if (device->tagged_supported)
+		depth_to_use = /* 254 */ 8;
+	else
+		depth_to_use = 2;
+
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+
+	return 0;
 }
 
 /* Detect all SSAs attached to the machine.
@@ -241,7 +245,6 @@
 				host->unchecked_isa_dma = 1;
 #endif
 
-				host->select_queue_depths = pluto_select_queue_depths;
 
 				fc->channels = inq->channels + 1;
 				fc->targets = inq->targets;
diff -Nru a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
--- a/drivers/scsi/pluto.h	Tue Oct 15 20:29:17 2002
+++ b/drivers/scsi/pluto.h	Tue Oct 15 20:29:17 2002
@@ -41,6 +41,7 @@
 int pluto_detect(Scsi_Host_Template *);
 int pluto_release(struct Scsi_Host *);
 const char * pluto_info(struct Scsi_Host *);
+int pluto_slave_attach(Scsi_Device *);
 
 #define PLUTO {							\
 	name:			"Sparc Storage Array 100/200",	\
@@ -48,6 +49,7 @@
 	release:		pluto_release,			\
 	info:			pluto_info,			\
 	queuecommand:		fcp_scsi_queuecommand,		\
+	slave_attach:		pluto_slave_attach,		\
 	can_queue:		PLUTO_CAN_QUEUE,		\
 	this_id:		-1,				\
 	sg_tablesize:		1,				\
diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/scsi/qla1280.c	Tue Oct 15 20:29:23 2002
@@ -382,8 +382,7 @@
 static void qla1280_next(struct scsi_qla_host *, scsi_lu_t *, int);
 static void qla1280_putq_t(scsi_lu_t *, srb_t *);
 static void qla1280_done_q_put(srb_t *, srb_t **, srb_t **);
-static void qla1280_device_queue_depth(struct scsi_qla_host *, Scsi_Device *);
-static void qla1280_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+static int qla1280_slave_attach(Scsi_Device *);
 #if STOP_ON_ERROR
 static void qla1280_panic(char *, struct Scsi_Host *host);
 #endif
@@ -840,7 +839,6 @@
 
 	host->can_queue = 0xfffff;	/* unlimited  */
 	host->cmd_per_lun = 1;
-	host->select_queue_depths = qla1280_select_queue_depth;
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
 	host->base = (unsigned char *)ha->mmpbase;
 #else
@@ -1796,7 +1794,7 @@
 }
 
 /**************************************************************************
- *   qla1280_device_queue_depth
+ *   qla1280_slave_attach
  *
  * Description:
  *   Determines the queue depth for a given device.  There are two ways
@@ -1806,51 +1804,28 @@
  *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
  *   default queue depth (dependent on the number of hardware SCBs).
  **************************************************************************/
-static void
-qla1280_device_queue_depth(struct scsi_qla_host *p, Scsi_Device * device)
+static int
+qla1280_slave_attach(Scsi_Device * device)
 {
-	int default_depth = 3;
+	struct scsi_qla_host *p = (struct scsi_qla_host *)device->host->hostdata;
 	int bus = device->channel;
 	int target = device->id;
 
-	device->queue_depth = default_depth;
-
+	if (qla1280_check_for_dead_scsi_bus(p, bus))
+		return 1;
 	if (device->tagged_supported &&
 	    (p->bus_settings[bus].qtag_enables & (BIT_0 << target))) {
-		device->tagged_queue = 1;
-		device->current_tag = 0;
-		device->queue_depth = p->bus_settings[bus].hiwat;
+		scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+			       	p->bus_settings[bus].hiwat);
 		/* device->queue_depth = 20; */
 		printk(KERN_INFO "scsi(%li:%d:%d:%d): Enabled tagged queuing, "
 		       "queue depth %d.\n", p->host_no, device->channel,
-		       device->id, device->lun, device->queue_depth);
+		       device->id, device->lun, device->new_queue_depth);
+	} else {
+		scsi_adjust_queue_depth(device, 0 /* TCQ off */, 3);
 	}
 	qla12160_get_target_parameters(p, bus, target, device->lun);
-}
-
-/**************************************************************************
- *   qla1280_select_queue_depth
- *
- *   Sets the queue depth for each SCSI device hanging off the input
- *   host adapter.  We use a queue depth of 2 for devices that do not
- *   support tagged queueing.
- **************************************************************************/
-static void
-qla1280_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
-{
-	Scsi_Device *device;
-	struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
-
-	ENTER("qla1280_select_queue_depth");
-	for (device = scsi_devs; device != NULL; device = device->next) {
-		if (device->host == host)
-			qla1280_device_queue_depth (ha, device);
-	}
-
-	if (scsi_devs)
-		qla1280_check_for_dead_scsi_bus(ha, scsi_devs->channel);
-
-	LEAVE("qla1280_select_queue_depth");
+	return 0;
 }
 
 /*
diff -Nru a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
--- a/drivers/scsi/qla1280.h	Tue Oct 15 20:29:23 2002
+++ b/drivers/scsi/qla1280.h	Tue Oct 15 20:29:23 2002
@@ -1314,6 +1314,7 @@
 int qla1280_abort(Scsi_Cmnd *);
 int qla1280_reset(Scsi_Cmnd *, unsigned int);
 int qla1280_biosparam(Disk *, struct block_device *, int[]);
+static int qla1280_slave_attach(Scsi_Device *);
 void qla1280_intr_handler(int, void *, struct pt_regs *);
 void qla1280_setup(char *s, int *dummy);
 
@@ -1342,7 +1343,7 @@
 /*	use_new_eh_code: 0, */					\
 	abort: qla1280_abort,					\
 	reset: qla1280_reset,					\
-	slave_attach: NULL,					\
+	slave_attach: qla1280_slave_attach,			\
 	bios_param: qla1280_biosparam,				\
 	can_queue: 255,		/* max simultaneous cmds      */\
 	this_id: -1,		/* scsi id of host adapter    */\
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/scsi/scsi.c	Tue Oct 15 20:29:17 2002
@@ -568,7 +568,7 @@
 				   atomic_read(&SCpnt->host->host_active),
 				   SCpnt->host->host_failed));
 
-	if(SDpnt->queue_depth > SDpnt->new_queue_depth) {
+	if(SDpnt->current_queue_depth > SDpnt->new_queue_depth) {
 		Scsi_Cmnd *prev, *next;
 		/*
 		 * Release the command block and decrement the queue
@@ -582,10 +582,10 @@
 		else
 			prev->next = next->next;
 		kfree((char *)SCpnt);
-		SDpnt->queue_depth--;
-	} else if(SDpnt->queue_depth < SDpnt->new_queue_depth) {
+		SDpnt->current_queue_depth--;
+	} else if(SDpnt->current_queue_depth < SDpnt->new_queue_depth) {
 		alloc_cmd = 1;
-		SDpnt->queue_depth++;
+		SDpnt->current_queue_depth++;
 	}
 	spin_unlock_irqrestore(&device_request_lock, flags);
 
@@ -633,7 +633,7 @@
 			spin_unlock_irqrestore(&device_request_lock, flags);
 		} else {
 			spin_lock_irqsave(&device_request_lock, flags);
-			SDpnt->queue_depth--;
+			SDpnt->current_queue_depth--;
 			spin_unlock_irqrestore(&device_request_lock, flags);
 		}
 	}
@@ -1399,14 +1399,10 @@
  */
 int scsi_retry_command(Scsi_Cmnd * SCpnt)
 {
-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
-	       sizeof(SCpnt->data_cmnd));
-	SCpnt->request_buffer = SCpnt->buffer;
-	SCpnt->request_bufflen = SCpnt->bufflen;
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->cmd_len = SCpnt->old_cmd_len;
-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
-	SCpnt->underflow = SCpnt->old_underflow;
+	/*
+	 * Restore the SCSI command state.
+	 */
+	scsi_setup_cmd_retry(SCpnt);
 
         /*
          * Zero the sense information from the last time we tried
@@ -1509,7 +1505,7 @@
 		SDpnt->device_queue = SCnext = SCpnt->next;
 		kfree((char *) SCpnt);
 	}
-	SDpnt->queue_depth = 0;
+	SDpnt->current_queue_depth = 0;
 	SDpnt->new_queue_depth = 0;
 	spin_unlock_irqrestore(&device_request_lock, flags);
 }
@@ -1533,7 +1529,7 @@
 	unsigned long flags;
 	Scsi_Cmnd *SCpnt;
 
-	if (SDpnt->queue_depth != 0)
+	if (SDpnt->current_queue_depth != 0)
 		return;
 		
 	SCpnt = (Scsi_Cmnd *) kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC |
@@ -1571,7 +1567,7 @@
 	spin_lock_irqsave(&device_request_lock, flags);
 	if(SDpnt->new_queue_depth == 0)
 		SDpnt->new_queue_depth = 1;
-	SDpnt->queue_depth++;
+	SDpnt->current_queue_depth++;
 	SCpnt->next = SDpnt->device_queue;
 	SDpnt->device_queue = SCpnt;
 	spin_unlock_irqrestore(&device_request_lock, flags);
@@ -1601,12 +1597,13 @@
  *
  * 		If cmdblocks != 0 then we are a live device.  We just set the
  * 		new_queue_depth variable and when the scsi completion handler
- * 		notices that queue_depth != new_queue_depth it will work to
- *		rectify the situation.  If new_queue_depth is less than current
- *		queue_depth, then it will free the completed command instead of
- *		putting it back on the free list and dec queue_depth.  Otherwise
- *		it will try to allocate a new command block for the device and
- *		put it on the free list along with the command that is being
+ * 		notices that current_queue_depth != new_queue_depth it will
+ * 		work to rectify the situation.  If new_queue_depth is less than
+ * 		current_queue_depth, then it will free the completed command
+ * 		instead of putting it back on the free list and dec
+ * 		current_queue_depth.  Otherwise	it will try to allocate a new
+ * 		command block for the device and put it on the free list along
+ * 		with the command that is being
  *		completed.  Obviously, if the device isn't doing anything then
  *		neither is this code, so it will bring the devices queue depth
  *		back into line when the device is actually being used.  This
@@ -1652,14 +1649,11 @@
 				SDpnt->channel, SDpnt->id, SDpnt->lun); 
 		case 0:
 			SDpnt->ordered_tags = SDpnt->simple_tags = 0;
-			if(SDpnt->host->cmd_per_lun)
-				SDpnt->new_queue_depth = SDpnt->host->cmd_per_lun;
-			else
-				SDpnt->new_queue_depth = 1;
+			SDpnt->new_queue_depth = tags;
 			break;
 	}
 	spin_unlock_irqrestore(&device_request_lock, flags);
-	if(SDpnt->queue_depth == 0)
+	if(SDpnt->current_queue_depth == 0)
 	{
 		scsi_build_commandblocks(SDpnt);
 	}
@@ -2120,7 +2114,7 @@
 							(*sdtpnt->attach) (SDpnt);
 					if (SDpnt->attached) {
 						scsi_build_commandblocks(SDpnt);
-						if (SDpnt->queue_depth == 0)
+						if (SDpnt->current_queue_depth == 0)
 							out_of_space = 1;
 					}
 				}
@@ -2409,10 +2403,10 @@
 			 * If this driver attached to the device, and don't have any
 			 * command blocks for this device, allocate some.
 			 */
-			if (SDpnt->attached && SDpnt->queue_depth == 0) {
+			if (SDpnt->attached && SDpnt->current_queue_depth == 0) {
 				SDpnt->online = TRUE;
 				scsi_build_commandblocks(SDpnt);
-				if (SDpnt->queue_depth == 0)
+				if (SDpnt->current_queue_depth == 0)
 					out_of_space = 1;
 			}
 		}
@@ -2820,7 +2814,7 @@
 	SDpnt->new_queue_depth = 1;
         
 	scsi_build_commandblocks(SDpnt);
-	if(SDpnt->queue_depth == 0) {
+	if(SDpnt->current_queue_depth == 0) {
 		kfree(SDpnt);
 		return NULL;
 	}
diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h	Tue Oct 15 20:29:14 2002
+++ b/drivers/scsi/scsi.h	Tue Oct 15 20:29:14 2002
@@ -467,6 +467,7 @@
 				   int sectors);
 extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *);
 extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt);
+extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt);
 extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
 extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
 			       int block_sectors);
@@ -556,15 +557,19 @@
 	 */
 	struct scsi_device *next;	/* Used for linked list */
 	struct scsi_device *prev;	/* Used for linked list */
+	struct list_head    siblings;   /* list of all devices on this host */
+	struct list_head    same_target_siblings; /* just the devices sharing same target id */
 	wait_queue_head_t   scpnt_wait;	/* Used to wait if
 					   device is busy */
 	struct Scsi_Host *host;
 	request_queue_t request_queue;
         atomic_t                device_active; /* commands checked out for device */
 	volatile unsigned short device_busy;	/* commands actually active on low-level */
+	struct list_head free_cmnds;    /* list of available Scsi_Cmnd structs */
+	struct list_head busy_cmnds;    /* list of Scsi_Cmnd structs in use */
 	Scsi_Cmnd *device_queue;	/* queue of SCSI Command structures */
         Scsi_Cmnd *current_cmnd;	/* currently active command */
-	unsigned short queue_depth;	/* How deep of a queue we have */
+	unsigned short current_queue_depth;/* How deep of a queue we have */
 	unsigned short new_queue_depth; /* How deep of a queue we want */
 
 	unsigned int id, lun, channel;
@@ -597,9 +602,10 @@
 	unsigned changed:1;	/* Data invalid due to media change */
 	unsigned busy:1;	/* Used to prevent races */
 	unsigned lockable:1;	/* Able to prevent media removal */
+	unsigned locked:1;      /* Media removal disabled */
 	unsigned borken:1;	/* Tell the Seagate driver to be 
 				 * painfully slow on this device */
-//	unsigned disconnect:1;	/* can disconnect */
+	unsigned disconnect:1;	/* can disconnect */
 	unsigned soft_reset:1;	/* Uses soft reset option */
 	unsigned sdtr:1;	/* Device supports SDTR messages */
 	unsigned wdtr:1;	/* Device supports WDTR messages */
@@ -711,6 +717,7 @@
 	Scsi_Request *sc_request;
 	struct scsi_cmnd *next;
 	struct scsi_cmnd *reset_chain;
+	struct list_head list_entry; /* Used to place us on the cmd lists */
 
 	int eh_state;		/* Used for state tracking in error handlr */
 	int eh_eflags;		/* Used by error handlr */
@@ -974,5 +981,7 @@
 #define SCSI_EH_REC_TIMEOUT	0x0008	/* Recovery cmd timeout */
 
 #define SCSI_SENSE_VALID(scmd) ((scmd->sense_buffer[0] & 0x70) == 0x70)
+
+int scsi_set_medium_removal(Scsi_Device *dev, char state);
 
 #endif
diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/scsi/scsi_error.c	Tue Oct 15 20:29:11 2002
@@ -8,6 +8,10 @@
  *
  *	Restructured scsi_unjam_host and associated functions.
  *	September 04, 2002 Mike Anderson (andmike@us.ibm.com)
+ *
+ *	Forward port of Russell King's (rmk@arm.linux.org.uk) changes and
+ *	minor  cleanups.
+ *	September 30, 2002 Mike Anderson (andmike@us.ibm.com)
  */
 
 #include <linux/module.h>
@@ -35,6 +39,8 @@
 #include "scsi.h"
 #include "hosts.h"
 
+#include <scsi/scsi_ioctl.h> /* grr */
+
 /*
  * We must always allow SHUTDOWN_SIGS.  Even if we are not a module,
  * the host drivers that we are using may be loaded as modules, and
@@ -59,7 +65,7 @@
  * These should *probably* be handled by the host itself.
  * Since it is allowed to sleep, it probably should.
  */
-#define BUS_RESET_SETTLE_TIME   5*HZ
+#define BUS_RESET_SETTLE_TIME   10*HZ
 #define HOST_RESET_SETTLE_TIME  10*HZ
 
 /**
@@ -91,9 +97,9 @@
 	scmd->eh_timeout.expires = jiffies + timeout;
 	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at"
-					  "%d (%p)\n", scmd, timeout,
-					  complete));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
+					  " %d, (%p)\n", __FUNCTION__,
+					  scmd, timeout, complete));
 
 	add_timer(&scmd->eh_timeout);
 
@@ -116,8 +122,9 @@
 
 	rtn = del_timer(&scmd->eh_timeout);
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p"
-					 " %d\n", scmd, rtn));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
+					 " rtn: %d\n", __FUNCTION__,
+					 scmd, rtn));
 
 	scmd->eh_timeout.data = (unsigned long) NULL;
 	scmd->eh_timeout.function = NULL;
@@ -150,7 +157,7 @@
 	scsi_host_failed_inc_and_test(scmd->host);
 
 	SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d "
-				   "failed=%d\n",
+				   " failed=%d\n",
 				   atomic_read(&scmd->host->host_active),
 				   scmd->host->host_busy,
 				   scmd->host->host_failed));
@@ -173,7 +180,7 @@
 
 	SCSI_SLEEP(&sdev->host->host_wait, sdev->host->in_recovery);
 
-	SCSI_LOG_ERROR_RECOVERY(5, printk("Open returning %d\n",
+	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __FUNCTION__,
 					  sdev->online));
 
 	return sdev->online;
@@ -209,10 +216,10 @@
 
 		if (cmd_timed_out || cmd_failed) {
 			SCSI_LOG_ERROR_RECOVERY(3,
-				printk("scsi_eh: %d:%d:%d:%d cmds failed: %d,"
-				       "timedout: %d\n",
-				       shost->host_no, sdev->channel,
-				       sdev->id, sdev->lun,
+				printk("%s: %d:%d:%d:%d cmds failed: %d,"
+				       " timedout: %d\n",
+				       __FUNCTION__, shost->host_no,
+				       sdev->channel, sdev->id, sdev->lun,
 				       cmd_failed, cmd_timed_out));
 			cmd_timed_out = 0;
 			cmd_failed = 0;
@@ -220,8 +227,8 @@
 		}
 	}
 
-	SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d "
-					  "devices require eh work\n",
+	SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d"
+					  " devices require eh work\n",
 				  total_failures, devices_failed));
 }
 #endif
@@ -265,10 +272,10 @@
 				 * queued and will be finished along the
 				 * way.
 				 */
-				SCSI_LOG_ERROR_RECOVERY(1, printk("Error hdlr "
-							  "prematurely woken "
-							  "cmds still active "
-							  "(%p %x %d)\n",
+				SCSI_LOG_ERROR_RECOVERY(1, printk("Error hdlr"
+							  " prematurely woken"
+							  " cmds still active"
+							  " (%p %x %d)\n",
 					       scmd, scmd->state,
 					       scmd->target));
 				}
@@ -278,12 +285,17 @@
 
 	SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost));
 
-	BUG_ON(shost->host_failed != found);
+	if (shost->host_failed != found)
+		printk(KERN_ERR "%s: host_failed: %d != found: %d\n", 
+		       __FUNCTION__, shost->host_failed, found);
 }
 
 /**
  * scsi_check_sense - Examine scsi cmd sense
  * @scmd:	Cmd to have sense checked.
+ *
+ * Return value:
+ * 	SUCCESS or FAILED or NEEDS_RETRY
  **/
 static int scsi_check_sense(Scsi_Cmnd *scmd)
 {
@@ -353,7 +365,6 @@
  **/
 static int scsi_eh_completed_normally(Scsi_Cmnd *scmd)
 {
-	int rtn;
 
 	/*
 	 * first check the host byte, to see if there is anything in there
@@ -369,7 +380,7 @@
 			 * SUCCESS.
 			 */
 			scmd->flags &= ~IS_RESETTING;
-			goto maybe_retry;
+			return NEEDS_RETRY;
 		}
 		/*
 		 * rats.  we are already in the error handler, so we now
@@ -377,10 +388,7 @@
 		 * is valid, we have a pretty good idea of what to do.
 		 * if not, we mark it as FAILED.
 		 */
-		rtn = scsi_check_sense(scmd);
-		if (rtn == NEEDS_RETRY)
-			goto maybe_retry;
-		return rtn;
+		return scsi_check_sense(scmd);
 	}
 	if (host_byte(scmd->result) != DID_OK) {
 		return FAILED;
@@ -400,10 +408,7 @@
 	case COMMAND_TERMINATED:
 		return SUCCESS;
 	case CHECK_CONDITION:
-		rtn = scsi_check_sense(scmd);
-		if (rtn == NEEDS_RETRY)
-			goto maybe_retry;
-		return rtn;
+		return scsi_check_sense(scmd);
 	case CONDITION_GOOD:
 	case INTERMEDIATE_GOOD:
 	case INTERMEDIATE_C_GOOD:
@@ -418,14 +423,6 @@
 		return FAILED;
 	}
 	return FAILED;
-
- maybe_retry:
-	if ((++scmd->retries) < scmd->allowed) {
-		return NEEDS_RETRY;
-	} else {
-		/* no more retries - report this one back to upper level */
-		return SUCCESS;
-	}
 }
 
 /**
@@ -440,12 +437,13 @@
 static void scsi_eh_times_out(Scsi_Cmnd *scmd)
 {
 	scsi_eh_eflags_set(scmd, SCSI_EH_REC_TIMEOUT);
-	SCSI_LOG_ERROR_RECOVERY(3, printk("in scsi_eh_times_out %p\n", scmd));
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd:%p\n", __FUNCTION__,
+					  scmd));
 
 	if (scmd->host->eh_action != NULL)
 		up(scmd->host->eh_action);
 	else
-		printk("missing scsi error handler thread\n");
+		printk("%s: eh_action NULL\n", __FUNCTION__);
 }
 
 /**
@@ -471,8 +469,8 @@
 
 	scmd->owner = SCSI_OWNER_ERROR_HANDLER;
 
-	SCSI_LOG_ERROR_RECOVERY(3, printk("in eh_done %p result:%x\n", scmd,
-					  scmd->result));
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s scmd: %p result: %x\n",
+					  __FUNCTION__, scmd, scmd->result));
 
 	if (scmd->host->eh_action != NULL)
 		up(scmd->host->eh_action);
@@ -488,7 +486,7 @@
  *    this case, and furthermore, there is a different completion handler
  *    vs scsi_dispatch_cmd.
  * Return value:
- *    SUCCESS/FAILED
+ *    SUCCESS or FAILED or NEEDS_RETRY
  **/
 static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout)
 {
@@ -498,7 +496,6 @@
 
 	ASSERT_LOCK(host->host_lock, 0);
 
-retry:
 	/*
 	 * we will use a queued command if possible, otherwise we will
 	 * emulate the queuing and calling of completion function ourselves.
@@ -552,9 +549,8 @@
 			
 			rtn = FAILED;
 		}
-		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: %p rtn:%x\n",
-						  __FUNCTION__, scmd,
-						  rtn));
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n",
+						  __FUNCTION__, scmd, rtn));
 	} else {
 		int temp;
 
@@ -576,16 +572,15 @@
 	 * actually did complete normally.
 	 */
 	if (rtn == SUCCESS) {
-		int ret = scsi_eh_completed_normally(scmd);
+		int rtn = scsi_eh_completed_normally(scmd);
 		SCSI_LOG_ERROR_RECOVERY(3,
 			printk("%s: scsi_eh_completed_normally %x\n",
-			       __FUNCTION__, ret));
-		switch (ret) {
+			       __FUNCTION__, rtn));
+		switch (rtn) {
 		case SUCCESS:
-			break;
 		case NEEDS_RETRY:
-			goto retry;
 		case FAILED:
+			break;
 		default:
 			rtn = FAILED;
 			break;
@@ -622,7 +617,7 @@
 	    ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
 
 	if (scsi_result == NULL) {
-		printk("cannot allocate scsi_result in scsi_request_sense.\n");
+		printk("%s: cannot allocate scsi_result.\n", __FUNCTION__);
 		return FAILED;
 	}
 	/*
@@ -657,15 +652,8 @@
 	 * when we eventually call scsi_finish, we really wish to complete
 	 * the original request, so let's restore the original data. (db)
 	 */
-	memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd,
-	       sizeof(scmd->data_cmnd));
+	scsi_setup_cmd_retry(scmd);
 	scmd->result = saved_result;
-	scmd->request_buffer = scmd->buffer;
-	scmd->request_bufflen = scmd->bufflen;
-	scmd->use_sg = scmd->old_use_sg;
-	scmd->cmd_len = scmd->old_cmd_len;
-	scmd->sc_data_direction = scmd->sc_old_data_direction;
-	scmd->underflow = scmd->old_underflow;
 
 	/*
 	 * hey, we are done.  let's look to see what happened.
@@ -683,16 +671,16 @@
  **/
 static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd)
 {
-	memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd,
-	       sizeof(scmd->data_cmnd));
-	scmd->request_buffer = scmd->buffer;
-	scmd->request_bufflen = scmd->bufflen;
-	scmd->use_sg = scmd->old_use_sg;
-	scmd->cmd_len = scmd->old_cmd_len;
-	scmd->sc_data_direction = scmd->sc_old_data_direction;
-	scmd->underflow = scmd->old_underflow;
+	int rtn = SUCCESS;
 
-	return scsi_send_eh_cmnd(scmd, scmd->timeout_per_command);
+	for (; scmd->retries < scmd->allowed; scmd->retries++) {
+		scsi_setup_cmd_retry(scmd);
+		rtn = scsi_send_eh_cmnd(scmd, scmd->timeout_per_command);
+		if (rtn != NEEDS_RETRY)
+			break;
+	}
+
+	return rtn;
 }
 
 /**
@@ -717,9 +705,7 @@
 	 * set this back so that the upper level can correctly free up
 	 * things.
 	 */
-	scmd->use_sg = scmd->old_use_sg;
-	scmd->sc_data_direction = scmd->sc_old_data_direction;
-	scmd->underflow = scmd->old_underflow;
+	scsi_setup_cmd_retry(scmd);
 }
 
 /**
@@ -758,14 +744,14 @@
 			continue;
 
 		SCSI_LOG_ERROR_RECOVERY(2, printk("%s: requesting sense"
-						  "for %d\n", __FUNCTION__,
-						  scmd->target));
+						  " for tgt: %d\n",
+						  __FUNCTION__, scmd->target));
 		rtn = scsi_request_sense(scmd);
 		if (rtn != SUCCESS)
 			continue;
 
 		SCSI_LOG_ERROR_RECOVERY(3, printk("sense requested for %p"
-						  "- result %x\n", scmd,
+						  " result %x\n", scmd,
 						  scmd->result));
 		SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", scmd));
 
@@ -847,7 +833,9 @@
 	static unsigned char tur_command[6] =
 	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
 	int rtn;
+	int retry_cnt = 1;
 
+retry_tur:
 	memcpy((void *) scmd->cmnd, (void *) tur_command,
 	       sizeof(tur_command));
 
@@ -873,32 +861,18 @@
 	 * when we eventually call scsi_finish, we really wish to complete
 	 * the original request, so let's restore the original data. (db)
 	 */
-	memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd,
-	       sizeof(scmd->data_cmnd));
-	scmd->request_buffer = scmd->buffer;
-	scmd->request_bufflen = scmd->bufflen;
-	scmd->use_sg = scmd->old_use_sg;
-	scmd->cmd_len = scmd->old_cmd_len;
-	scmd->sc_data_direction = scmd->sc_old_data_direction;
-	scmd->underflow = scmd->old_underflow;
+	scsi_setup_cmd_retry(scmd);
 
 	/*
 	 * hey, we are done.  let's look to see what happened.
 	 */
-	SCSI_LOG_ERROR_RECOVERY(3,
-		printk("%s: scmd %p rtn %x\n",
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
 		__FUNCTION__, scmd, rtn));
-	if ((rtn == SUCCESS) && scmd->result) {
-		if (((driver_byte(scmd->result) & DRIVER_SENSE) ||
-		     (status_byte(scmd->result) & CHECK_CONDITION)) &&
-		    (SCSI_SENSE_VALID(scmd))) {
-			if (((scmd->sense_buffer[2] & 0xf) != NOT_READY) &&
-			    ((scmd->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
-			    ((scmd->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) {
-				return 0;
-			}
-		}
-	}
+	if (rtn == SUCCESS)
+		return 0;
+	else if (rtn == NEEDS_RETRY)
+		if (retry_cnt--)
+			goto retry_tur;
 	return 1;
 }
 
@@ -929,7 +903,7 @@
 
 		rtn = scsi_try_to_abort_cmd(scmd);
 		if (rtn == SUCCESS) {
-			if (scsi_eh_tur(scmd)) {
+			if (!scsi_eh_tur(scmd)) {
 				rtn = scsi_eh_retry_cmd(scmd);
 				if (rtn == SUCCESS)
 					scsi_eh_finish_cmd(scmd, shost);
@@ -963,6 +937,11 @@
 	rtn = scmd->host->hostt->eh_device_reset_handler(scmd);
 	spin_unlock_irqrestore(scmd->host->host_lock, flags);
 
+	if (rtn == SUCCESS) {
+		scmd->device->was_reset = 1;
+		scmd->device->expecting_cc_ua = 1;
+	}
+
 	return rtn;
 }
 
@@ -999,7 +978,7 @@
 		 * a bus device reset to it.
 		 */
 		rtn = scsi_try_bus_device_reset(scmd);
-		if ((rtn == SUCCESS) && (scsi_eh_tur(scmd)))
+		if ((rtn == SUCCESS) && (!scsi_eh_tur(scmd)))
 				for (scmd = sc_todo; scmd; scmd = scmd->bh_next)
 					if ((scmd->device == sdev) &&
 					    scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) {
@@ -1141,7 +1120,7 @@
 				if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)
 				    || channel != scmd->channel)
 					continue;
-				if (scsi_eh_tur(scmd)) {
+				if (!scsi_eh_tur(scmd)) {
 					rtn = scsi_eh_retry_cmd(scmd);
 
 					if (rtn == SUCCESS)
@@ -1168,10 +1147,10 @@
 		if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR))
 			continue;
 
-		printk(KERN_INFO "%s: Device set offline - not"
-				"ready or command retry failed"
-				"after error recovery: host"
-				"%d channel %d id %d lun %d\n",
+		printk(KERN_INFO "%s: Device offlined - not"
+				" ready or command retry failed"
+				" after error recovery: host"
+				" %d channel %d id %d lun %d\n",
 				__FUNCTION__, shost->host_no,
 				scmd->device->channel,
 				scmd->device->id,
@@ -1243,7 +1222,7 @@
 	 */
 	if (scmd->device->online == FALSE) {
 		SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report"
-						  "as SUCCESS\n",
+						  " as SUCCESS\n",
 						  __FUNCTION__));
 		return SUCCESS;
 	}
@@ -1367,7 +1346,7 @@
 		return SUCCESS;
 
 	case RESERVATION_CONFLICT:
-		printk("scsi%d (%d,%d,%d) : reservation conflict\n", 
+		printk("scsi%d (%d,%d,%d) : reservation conflict\n",
 		       scmd->host->host_no, scmd->channel,
 		       scmd->device->id, scmd->device->lun);
 		return SUCCESS; /* causes immediate i/o error */
@@ -1389,6 +1368,75 @@
 }
 
 /**
+ * scsi_eh_lock_done - done function for eh door lock request
+ * @scmd:	SCSI command block for the door lock request
+ *
+ * Notes:
+ * 	We completed the asynchronous door lock request, and it has either
+ * 	locked the door or failed.  We must free the command structures
+ * 	associated with this request.
+ **/
+static void scsi_eh_lock_done(struct scsi_cmnd *scmd)
+{
+	struct scsi_request *sreq = scmd->sc_request;
+
+	scmd->sc_request = NULL;
+	sreq->sr_command = NULL;
+
+	scsi_release_command(scmd);
+	scsi_release_request(sreq);
+}
+
+
+/**
+ * scsi_eh_lock_door - Prevent medium removal for the specified device
+ * @sdev:	SCSI device to prevent medium removal
+ *
+ * Locking:
+ * 	We must be called from process context; scsi_allocate_request()
+ * 	may sleep.
+ *
+ * Notes:
+ * 	We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
+ * 	head of the devices request queue, and continue.
+ *
+ * Bugs:
+ * 	scsi_allocate_request() may sleep waiting for existing requests to
+ * 	be processed.  However, since we haven't kicked off any request
+ * 	processing for this host, this may deadlock.
+ *
+ *	If scsi_allocate_request() fails for what ever reason, we
+ *	completely forget to lock the door.
+ **/
+static void scsi_eh_lock_door(struct scsi_device *sdev)
+{
+	struct scsi_request *sreq = scsi_allocate_request(sdev);
+
+	if (sreq == NULL) {
+		printk(KERN_ERR "%s: request allocate failed,"
+		       "prevent media removal cmd not sent", __FUNCTION__);
+		return;
+	}
+
+	sreq->sr_cmnd[0] = ALLOW_MEDIUM_REMOVAL;
+	sreq->sr_cmnd[1] = (sdev->scsi_level <= SCSI_2) ? (sdev->lun << 5) : 0;
+	sreq->sr_cmnd[2] = 0;
+	sreq->sr_cmnd[3] = 0;
+	sreq->sr_cmnd[4] = SCSI_REMOVAL_PREVENT;
+	sreq->sr_cmnd[5] = 0;
+	sreq->sr_data_direction = SCSI_DATA_NONE;
+	sreq->sr_bufflen = 0;
+	sreq->sr_buffer = NULL;
+	sreq->sr_allowed = 5;
+	sreq->sr_done = scsi_eh_lock_done;
+	sreq->sr_timeout_per_command = 10 * HZ;
+	sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]);
+
+	scsi_insert_special_req(sreq, 1);
+}
+
+
+/**
  * scsi_restart_operations - restart io operations to the specified host.
  * @shost:	Host we are restarting.
  *
@@ -1404,6 +1452,15 @@
 	ASSERT_LOCK(shost->host_lock, 0);
 
 	/*
+	 * If the door was locked, we need to insert a door lock request
+	 * onto the head of the SCSI request queue for the device.  There
+	 * is no point trying to lock the door of an off-line device.
+	 */
+	for (sdev = shost->host_queue; sdev; sdev = sdev->next)
+		if (sdev->online && sdev->locked)
+			scsi_eh_lock_door(sdev);
+
+	/*
 	 * next free up anything directly waiting upon the host.  this
 	 * will be requests for character device operations, and also for
 	 * ioctls to queued block devices.
@@ -1426,8 +1483,7 @@
 		if ((shost->can_queue > 0 &&
 		     (shost->host_busy >= shost->can_queue))
 		    || (shost->host_blocked)
-		    || (shost->host_self_blocked)
-		    || (sdev->device_blocked)) {
+		    || (shost->host_self_blocked)) {
 			break;
 		}
 
@@ -1475,7 +1531,7 @@
 	if (scsi_eh_get_sense(sc_todo, shost))
 		if (scsi_eh_abort_cmd(sc_todo, shost))
 			if (scsi_eh_bus_device_reset(sc_todo, shost))
-				if(scsi_eh_bus_host_reset(sc_todo, shost))
+				if (scsi_eh_bus_host_reset(sc_todo, shost))
 					scsi_eh_offline_sdevs(sc_todo, shost);
 
 	BUG_ON(shost->host_failed);
@@ -1563,8 +1619,7 @@
 	/*
 	 * Wake up the thread that created us.
 	 */
-	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n",
-					  shost->eh_notify->count.counter));
+	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent \n"));
 
 	up(shost->eh_notify);
 
diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
--- a/drivers/scsi/scsi_ioctl.c	Tue Oct 15 20:29:22 2002
+++ b/drivers/scsi/scsi_ioctl.c	Tue Oct 15 20:29:22 2002
@@ -151,6 +151,29 @@
 	return result;
 }
 
+int scsi_set_medium_removal(Scsi_Device *dev, char state)
+{
+	char scsi_cmd[MAX_COMMAND_SIZE];
+	int ret;
+
+	if (!dev->removable || !dev->lockable)
+	       return 0;
+
+	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+	scsi_cmd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
+	scsi_cmd[2] = 0;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = state;
+	scsi_cmd[5] = 0;
+
+	ret = ioctl_internal_command(dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
+
+	if (ret == 0)
+		dev->locked = state == SCSI_REMOVAL_PREVENT;
+
+	return ret;
+}
+
 /*
  * This interface is deprecated - users should use the scsi generic (sg)
  * interface instead, as this is a more flexible approach to performing
@@ -456,24 +479,9 @@
 		return scsi_ioctl_send_command((Scsi_Device *) dev,
 					     (Scsi_Ioctl_Command *) arg);
 	case SCSI_IOCTL_DOORLOCK:
-		if (!dev->removable || !dev->lockable)
-			return 0;
-		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-		scsi_cmd[1] = cmd_byte1;
-		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-		scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
-		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
-		break;
+		return scsi_set_medium_removal(dev, SCSI_REMOVAL_PREVENT);
 	case SCSI_IOCTL_DOORUNLOCK:
-		if (!dev->removable || !dev->lockable)
-			return 0;
-		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-		scsi_cmd[1] = cmd_byte1;
-		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-		scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
-		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
+		return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW);
 	case SCSI_IOCTL_TEST_UNIT_READY:
 		scsi_cmd[0] = TEST_UNIT_READY;
 		scsi_cmd[1] = cmd_byte1;
diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/scsi/scsi_lib.c	Tue Oct 15 20:29:17 2002
@@ -160,6 +160,30 @@
 }
 
 /*
+ * Function:   scsi_setup_cmd_retry()
+ *
+ * Purpose:    Restore the command state for a retry
+ *
+ * Arguments:  SCpnt   - command to be restored
+ *
+ * Returns:    Nothing
+ *
+ * Notes:      Immediately prior to retrying a command, we need
+ *             to restore certain fields that we saved above.
+ */
+void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt)
+{
+	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+		sizeof(SCpnt->data_cmnd));
+	SCpnt->request_buffer = SCpnt->buffer;
+	SCpnt->request_bufflen = SCpnt->bufflen;
+	SCpnt->use_sg = SCpnt->old_use_sg;
+	SCpnt->cmd_len = SCpnt->old_cmd_len;
+	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+	SCpnt->underflow = SCpnt->old_underflow;
+}
+
+/*
  * Function:    scsi_queue_next_request()
  *
  * Purpose:     Handle post-processing of completed commands.
@@ -614,7 +638,7 @@
 			printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ",
 			       SCpnt->host->host_no, (int) SCpnt->channel,
 			       (int) SCpnt->target, (int) SCpnt->lun);
-			print_command(SCpnt->cmnd);
+			print_command(SCpnt->data_cmnd);
 			print_sense("sd", SCpnt);
 			SCpnt = scsi_end_request(SCpnt, 0, block_sectors);
 			return;
@@ -796,33 +820,6 @@
 			break;
 		} else {
 			SDpnt->starved = 0;
-		}
-
- 		/*
-		 * FIXME(eric)
-		 * I am not sure where the best place to do this is.  We need
-		 * to hook in a place where we are likely to come if in user
-		 * space.   Technically the error handling thread should be
-		 * doing this crap, but the error handler isn't used by
-		 * most hosts.
-		 */
-		if (SDpnt->was_reset) {
-			/*
-			 * We need to relock the door, but we might
-			 * be in an interrupt handler.  Only do this
-			 * from user space, since we do not want to
-			 * sleep from an interrupt.
-			 *
-			 * FIXME(eric) - have the error handler thread do
-			 * this work.
-			 */
-			SDpnt->was_reset = 0;
-			if (SDpnt->removable && !in_interrupt()) {
-				spin_unlock_irq(q->queue_lock);
-				scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0);
-				spin_lock_irq(q->queue_lock);
-				continue;
-			}
 		}
 
 		/*
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/scsi/scsi_scan.c	Tue Oct 15 20:29:20 2002
@@ -1532,7 +1532,7 @@
 	 */
 	sdevscan->new_queue_depth = 1;
 	scsi_build_commandblocks(sdevscan);
-	if (sdevscan->queue_depth == 0)
+	if (sdevscan->current_queue_depth == 0)
 		goto alloc_failed;
 
 	sreq = scsi_allocate_request(sdevscan);
@@ -1606,7 +1606,7 @@
 		kfree(scsi_result);
 	if (sreq != NULL)
 		scsi_release_request(sreq);
-	if (sdevscan->queue_depth != 0)
+	if (sdevscan->current_queue_depth != 0)
 		scsi_release_commandblocks(sdevscan);
 	return SCSI_SCAN_NO_RESPONSE;
 }
@@ -1762,7 +1762,7 @@
 
 	sdevscan->new_queue_depth = 1;
 	scsi_build_commandblocks(sdevscan);
-	if (sdevscan->queue_depth == 0) {
+	if (sdevscan->current_queue_depth == 0) {
 		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
 		/*
 		 * We are out of memory, don't try scanning any further.
@@ -2030,7 +2030,7 @@
 				(*sdt->attach) (sdev);
 				if (sdev->attached) {
 					scsi_build_commandblocks(sdev);
-					if (sdev->queue_depth == 0)
+					if (sdev->current_queue_depth == 0)
 						printk(ALLOC_FAILURE_MSG,
 						       __FUNCTION__);
 				}
diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
--- a/drivers/scsi/scsi_syms.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/scsi/scsi_syms.c	Tue Oct 15 20:29:17 2002
@@ -54,6 +54,7 @@
 EXPORT_SYMBOL(print_Scsi_Cmnd);
 EXPORT_SYMBOL(scsi_block_when_processing_errors);
 EXPORT_SYMBOL(scsi_ioctl_send_command);
+EXPORT_SYMBOL(scsi_set_medium_removal);
 #if defined(CONFIG_SCSI_LOGGING)	/* { */
 EXPORT_SYMBOL(scsi_logging_level);
 #endif
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/scsi/sd.c	Tue Oct 15 20:29:19 2002
@@ -529,7 +529,7 @@
 	if (sdp->removable)
 		if (sdp->access_count==1)
 			if (scsi_block_when_processing_errors(sdp))
-				scsi_ioctl(sdp, SCSI_IOCTL_DOORLOCK, NULL);
+				scsi_set_medium_removal(sdp, SCSI_REMOVAL_PREVENT);
 
 	return 0;
 
@@ -573,7 +573,7 @@
 	if (sdp->removable) {
 		if (!sdp->access_count)
 			if (scsi_block_when_processing_errors(sdp))
-				scsi_ioctl(sdp, SCSI_IOCTL_DOORUNLOCK, NULL);
+				scsi_set_medium_removal(sdp, SCSI_REMOVAL_ALLOW);
 	}
 	if (sdp->host->hostt->module)
 		__MOD_DEC_USE_COUNT(sdp->host->hostt->module);
@@ -916,7 +916,7 @@
 
 		SRpnt->sr_data_direction = SCSI_DATA_READ;
 		scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
-			    24, SD_TIMEOUT, MAX_RETRIES);
+			    128, SD_TIMEOUT, MAX_RETRIES);
 
 		the_result = SRpnt->sr_result;
 		retries--;
@@ -1386,7 +1386,7 @@
 	    ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)))
 		return 0;
 
-	gd = alloc_disk();
+	gd = alloc_disk(16);
 	if (!gd)
 		return 1;
 
@@ -1423,7 +1423,6 @@
         gd->de = sdp->de;
 	gd->major = SD_MAJOR(dsk_nr>>4);
 	gd->first_minor = (dsk_nr & 15)<<4;
-	gd->minor_shift = 4;
 	gd->fops = &sd_fops;
 	if (dsk_nr > 26)
 		sprintf(gd->disk_name, "sd%c%c",'a'+dsk_nr/26-1,'a'+dsk_nr%26);
@@ -1623,7 +1622,6 @@
 	}
 
 	the_result = SRpnt->sr_result;
-	scsi_release_request(SRpnt);
 	if(verbose) {
 		if(the_result != 0) {
 			printk("FAILED\n  status = %x, message = %02x, host = %d, driver = %02x\n  ",
@@ -1636,6 +1634,7 @@
 
 		}
 	}
+	scsi_release_request(SRpnt);
 	return (the_result == 0);
 }
 
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/sg.c	Tue Oct 15 20:29:16 2002
@@ -852,7 +852,7 @@
 			__put_user((int) sdp->device->type, &sg_idp->scsi_type);
 			__put_user((short) sdp->device->host->cmd_per_lun,
 				   &sg_idp->h_cmd_per_lun);
-			__put_user((short) sdp->device->queue_depth,
+			__put_user((short) sdp->device->new_queue_depth,
 				   &sg_idp->d_queue_depth);
 			__put_user(0, &sg_idp->unused[0]);
 			__put_user(0, &sg_idp->unused[1]);
@@ -3039,7 +3039,7 @@
 				   scsidp->host->host_no, scsidp->channel,
 				   scsidp->id, scsidp->lun, (int) scsidp->type,
 				   (int) scsidp->access_count,
-				   (int) scsidp->queue_depth,
+				   (int) scsidp->new_queue_depth,
 				   (int) scsidp->device_busy,
 				   (int) scsidp->online);
 		else
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/scsi/sr.c	Tue Oct 15 20:29:14 2002
@@ -575,7 +575,7 @@
 
 void get_capabilities(Scsi_CD *cd)
 {
-	unsigned char cmd[6];
+	struct cdrom_generic_command cgc;
 	unsigned char *buffer;
 	int rc, n;
 
@@ -597,13 +597,18 @@
 		printk(KERN_ERR "sr: out of memory.\n");
 		return;
 	}
-	cmd[0] = MODE_SENSE;
-	cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-		 ((cd->device->lun << 5) & 0xe0) : 0;
-	cmd[2] = 0x2a;
-	cmd[4] = 128;
-	cmd[3] = cmd[5] = 0;
-	rc = sr_do_ioctl(cd, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL);
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = MODE_SENSE;
+	cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+		     ((cd->device->lun << 5) & 0xe0) : 0;
+	cgc.cmd[2] = 0x2a;
+	cgc.cmd[4] = 128;
+	cgc.buffer = buffer;
+	cgc.buflen = 128;
+	cgc.quiet = 1;
+	cgc.data_direction = SCSI_DATA_READ;
+	cgc.timeout = SR_TIMEOUT;
+	rc = sr_do_ioctl(cd, &cgc);
 
 	if (rc) {
 		/* failed, drive doesn't have capabilities mode page */
@@ -680,7 +685,10 @@
 	if (device->scsi_level <= SCSI_2)
 		cgc->cmd[1] |= device->lun << 5;
 
-	cgc->stat = sr_do_ioctl(cdi->handle, cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense);
+	if (cgc->timeout <= 0)
+		cgc->timeout = IOCTL_TIMEOUT;
+
+	sr_do_ioctl(cdi->handle, cgc);
 
 	return cgc->stat;
 }
@@ -718,24 +726,6 @@
 	return 1;
 }
 
-/* Driverfs file support */
-static ssize_t sr_device_kdev_read(struct device *driverfs_dev, 
-				   char *page, size_t count, loff_t off)
-{
-	kdev_t kdev; 
-	kdev.value=(int)(long)driverfs_dev->driver_data;
-	return off ? 0 : sprintf(page, "%x\n",kdev.value);
-}
-static DEVICE_ATTR(kdev,S_IRUGO,sr_device_kdev_read,NULL);
-
-static ssize_t sr_device_type_read(struct device *driverfs_dev, 
-				   char *page, size_t count, loff_t off) 
-{
-	return off ? 0 : sprintf (page, "CHR\n");
-}
-static DEVICE_ATTR(type,S_IRUGO,sr_device_type_read,NULL);
-
-
 void sr_finish()
 {
 	int i;
@@ -749,7 +739,7 @@
 		 * with loadable modules. */
 		if (cd->disk)
 			continue;
-		disk = alloc_disk();
+		disk = alloc_disk(1);
 		if (!disk)
 			continue;
 		if (cd->disk) {
@@ -758,7 +748,6 @@
 		}
 		disk->major = MAJOR_NR;
 		disk->first_minor = i;
-		disk->minor_shift = 0;
 		strcpy(disk->disk_name, cd->cdi.name);
 		disk->fops = &sr_bdops;
 		disk->flags = GENHD_FL_CD;
@@ -790,22 +779,8 @@
 		 */
 		get_capabilities(cd);
 		sr_vendor_init(cd);
-
-		sprintf(cd->cdi.cdrom_driverfs_dev.bus_id, "%s:cd",
-			cd->device->sdev_driverfs_dev.bus_id);
-		sprintf(cd->cdi.cdrom_driverfs_dev.name, "%scdrom",
-			cd->device->sdev_driverfs_dev.name);
-		cd->cdi.cdrom_driverfs_dev.parent = 
-			&cd->device->sdev_driverfs_dev;
-		cd->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type;
-		cd->cdi.cdrom_driverfs_dev.driver_data = 
-			(void *)(long)__mkdev(MAJOR_NR, i);
-		device_register(&cd->cdi.cdrom_driverfs_dev);
-		device_create_file(&cd->cdi.cdrom_driverfs_dev,
-				   &dev_attr_type);
-		device_create_file(&cd->cdi.cdrom_driverfs_dev,
-				   &dev_attr_kdev);
 		disk->de = cd->device->de;
+		disk->driverfs_dev = &cd->device->sdev_driverfs_dev;
 		register_cdrom(&cd->cdi);
 		set_capacity(disk, cd->capacity);
 		add_disk(disk);
diff -Nru a/drivers/scsi/sr.h b/drivers/scsi/sr.h
--- a/drivers/scsi/sr.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/sr.h	Tue Oct 15 20:29:16 2002
@@ -20,6 +20,10 @@
 #include "scsi.h"
 #include <linux/genhd.h>
 
+/* The CDROM is fairly slow, so we need a little extra time */
+/* In fact, it is very slow if it has to spin up first */
+#define IOCTL_TIMEOUT 30*HZ
+
 typedef struct {
 	unsigned capacity;	/* size in blocks                       */
 	Scsi_Device *device;
@@ -34,7 +38,7 @@
 	struct gendisk *disk;
 } Scsi_CD;
 
-int sr_do_ioctl(Scsi_CD *, unsigned char *, void *, unsigned, int, int, struct request_sense *);
+int sr_do_ioctl(Scsi_CD *, struct cdrom_generic_command *);
 
 int sr_lock_door(struct cdrom_device_info *, int);
 int sr_tray_move(struct cdrom_device_info *, int);
diff -Nru a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
--- a/drivers/scsi/sr_ioctl.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/scsi/sr_ioctl.c	Tue Oct 15 20:29:17 2002
@@ -25,9 +25,6 @@
 static int xa_test = 0;
 
 #define IOCTL_RETRIES 3
-/* The CDROM is fairly slow, so we need a little extra time */
-/* In fact, it is very slow if it has to spin up first */
-#define IOCTL_TIMEOUT 30*HZ
 
 /* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command.  When these drives
    are emulating a SCSI device via the idescsi module, they need to have
@@ -37,7 +34,7 @@
 {
 	struct cdrom_tocentry trk0_te, trk1_te;
 	struct cdrom_tochdr tochdr;
-	u_char sr_cmd[10];
+	struct cdrom_generic_command cgc;
 	int ntracks, ret;
 
 	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)))
@@ -59,22 +56,25 @@
 		return ret;
 	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk1_te)))
 		return ret;
-	
-	sr_cmd[0] = GPCMD_PLAY_AUDIO_MSF;
-	sr_cmd[3] = trk0_te.cdte_addr.msf.minute;
-	sr_cmd[4] = trk0_te.cdte_addr.msf.second;
-	sr_cmd[5] = trk0_te.cdte_addr.msf.frame;
-	sr_cmd[6] = trk1_te.cdte_addr.msf.minute;
-	sr_cmd[7] = trk1_te.cdte_addr.msf.second;
-	sr_cmd[8] = trk1_te.cdte_addr.msf.frame;
-	return sr_do_ioctl(cdi->handle, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+	cgc.cmd[3] = trk0_te.cdte_addr.msf.minute;
+	cgc.cmd[4] = trk0_te.cdte_addr.msf.second;
+	cgc.cmd[5] = trk0_te.cdte_addr.msf.frame;
+	cgc.cmd[6] = trk1_te.cdte_addr.msf.minute;
+	cgc.cmd[7] = trk1_te.cdte_addr.msf.second;
+	cgc.cmd[8] = trk1_te.cdte_addr.msf.frame;
+	cgc.data_direction = SCSI_DATA_NONE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	return sr_do_ioctl(cdi->handle, &cgc);
 }
 
 /* We do our own retries because we want to know what the specific
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
 
-int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite, struct request_sense *sense)
+int sr_do_ioctl(Scsi_CD *cd, struct cdrom_generic_command *cgc)
 {
 	Scsi_Request *SRpnt;
 	Scsi_Device *SDev;
@@ -86,29 +86,32 @@
 	SRpnt = scsi_allocate_request(SDev);
         if (!SRpnt) {
                 printk("Unable to allocate SCSI request in sr_do_ioctl");
-                return -ENOMEM;
+		err = -ENOMEM;
+		goto out;
         }
-	SRpnt->sr_data_direction = readwrite;
+	SRpnt->sr_data_direction = cgc->data_direction;
 
 	/* use ISA DMA buffer if necessary */
-	SRpnt->sr_request->buffer = buffer;
-	if (buffer && SRpnt->sr_host->unchecked_isa_dma &&
-	    (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) {
-		bounce_buffer = (char *) kmalloc(buflength, GFP_DMA);
+	SRpnt->sr_request->buffer = cgc->buffer;
+	if (cgc->buffer && SRpnt->sr_host->unchecked_isa_dma &&
+	    (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) {
+		bounce_buffer = (char *) kmalloc(cgc->buflen, GFP_DMA);
 		if (bounce_buffer == NULL) {
 			printk("SCSI DMA pool exhausted.");
-			return -ENOMEM;
+			err = -ENOMEM;
+			goto out;
 		}
-		memcpy(bounce_buffer, (char *) buffer, buflength);
-		buffer = bounce_buffer;
+		memcpy(bounce_buffer, cgc->buffer, cgc->buflen);
+		cgc->buffer = bounce_buffer;
 	}
       retry:
-	if (!scsi_block_when_processing_errors(SDev))
-		return -ENODEV;
-
+	if (!scsi_block_when_processing_errors(SDev)) {
+		err = -ENODEV;
+		goto out;
+	}
 
-	scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength,
-		      IOCTL_TIMEOUT, IOCTL_RETRIES);
+	scsi_wait_req(SRpnt, cgc->cmd, cgc->buffer, cgc->buflen,
+		      cgc->timeout, IOCTL_RETRIES);
 
 	req = SRpnt->sr_request;
 	if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) {
@@ -124,7 +127,7 @@
 		switch (SRpnt->sr_sense_buffer[2] & 0xf) {
 		case UNIT_ATTENTION:
 			SDev->changed = 1;
-			if (!quiet)
+			if (!cgc->quiet)
 				printk(KERN_INFO "%s: disc change detected.\n", cd->cdi.name);
 			if (retries++ < 10)
 				goto retry;
@@ -134,7 +137,7 @@
 			if (SRpnt->sr_sense_buffer[12] == 0x04 &&
 			    SRpnt->sr_sense_buffer[13] == 0x01) {
 				/* sense: Logical unit is in process of becoming ready */
-				if (!quiet)
+				if (!cgc->quiet)
 					printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name);
 				if (retries++ < 10) {
 					/* sleep 2 sec and try again */
@@ -146,7 +149,7 @@
 					break;
 				}
 			}
-			if (!quiet)
+			if (!cgc->quiet)
 				printk(KERN_INFO "%s: CDROM not ready.  Make sure there is a disc in the drive.\n", cd->cdi.name);
 #ifdef DEBUG
 			print_req_sense("sr", SRpnt);
@@ -154,7 +157,7 @@
 			err = -ENOMEDIUM;
 			break;
 		case ILLEGAL_REQUEST:
-			if (!quiet)
+			if (!cgc->quiet)
 				printk(KERN_ERR "%s: CDROM (ioctl) reports ILLEGAL "
 				       "REQUEST.\n", cd->cdi.name);
 			if (SRpnt->sr_sense_buffer[12] == 0x20 &&
@@ -165,24 +168,26 @@
 				err = -EINVAL;
 			}
 #ifdef DEBUG
-			print_command(sr_cmd);
+			print_command(cgc->cmd);
 			print_req_sense("sr", SRpnt);
 #endif
 			break;
 		default:
 			printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name);
-			print_command(sr_cmd);
+			print_command(cgc->cmd);
 			print_req_sense("sr", SRpnt);
 			err = -EIO;
 		}
 	}
 
-	if (sense)
-		memcpy(sense, SRpnt->sr_sense_buffer, sizeof(*sense));
+	if (cgc->sense)
+		memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense));
 
 	/* Wake up a process waiting for device */
 	scsi_release_request(SRpnt);
 	SRpnt = NULL;
+      out:
+	cgc->stat = err;
 	return err;
 }
 
@@ -191,35 +196,39 @@
 
 static int test_unit_ready(Scsi_CD *cd)
 {
-	u_char sr_cmd[10];
+	struct cdrom_generic_command cgc;
 
-	sr_cmd[0] = GPCMD_TEST_UNIT_READY;
-	sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-	            ((cd->device->lun) << 5) : 0;
-	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-	return sr_do_ioctl(cd, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL);
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
+	cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+		     ((cd->device->lun) << 5) : 0;
+	cgc.quiet = 1;
+	cgc.data_direction = SCSI_DATA_NONE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	return sr_do_ioctl(cd, &cgc);
 }
 
 int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
 	Scsi_CD *cd = cdi->handle;
-	u_char sr_cmd[10];
-
-	sr_cmd[0] = GPCMD_START_STOP_UNIT;
-	sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-	            ((cd->device->lun) << 5) : 0;
-	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-	sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
+	struct cdrom_generic_command cgc;
 
-	return sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = GPCMD_START_STOP_UNIT;
+	cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+		     ((cd->device->lun) << 5) : 0;
+	cgc.cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
+	cgc.data_direction = SCSI_DATA_NONE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	return sr_do_ioctl(cd, &cgc);
 }
 
 int sr_lock_door(struct cdrom_device_info *cdi, int lock)
 {
 	Scsi_CD *cd = cdi->handle;
 
-	return scsi_ioctl(cd->device, lock ? SCSI_IOCTL_DOORLOCK :
-			SCSI_IOCTL_DOORUNLOCK, 0);
+	return scsi_set_medium_removal(cd->device, lock ?
+		       SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
 }
 
 int sr_drive_status(struct cdrom_device_info *cdi, int slot)
@@ -278,22 +287,22 @@
 int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
 {
 	Scsi_CD *cd = cdi->handle;
-	u_char sr_cmd[10];
+	struct cdrom_generic_command cgc;
 	char buffer[32];
 	int result;
 
-	sr_cmd[0] = GPCMD_READ_SUBCHANNEL;
-	sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-	            ((cd->device->lun) << 5) : 0;
-	sr_cmd[2] = 0x40;	/* I do want the subchannel info */
-	sr_cmd[3] = 0x02;	/* Give me medium catalog number info */
-	sr_cmd[4] = sr_cmd[5] = 0;
-	sr_cmd[6] = 0;
-	sr_cmd[7] = 0;
-	sr_cmd[8] = 24;
-	sr_cmd[9] = 0;
-
-	result = sr_do_ioctl(cd, sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL);
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
+	cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+		     ((cd->device->lun) << 5) : 0;
+	cgc.cmd[2] = 0x40;	/* I do want the subchannel info */
+	cgc.cmd[3] = 0x02;	/* Give me medium catalog number info */
+	cgc.cmd[8] = 24;
+	cgc.buffer = buffer;
+	cgc.buflen = 24;
+	cgc.data_direction = SCSI_DATA_READ;
+	cgc.timeout = IOCTL_TIMEOUT;
+	result = sr_do_ioctl(cd, &cgc);
 
 	memcpy(mcn->medium_catalog_number, buffer + 9, 13);
 	mcn->medium_catalog_number[13] = 0;
@@ -309,21 +318,23 @@
 int sr_select_speed(struct cdrom_device_info *cdi, int speed)
 {
 	Scsi_CD *cd = cdi->handle;
-	u_char sr_cmd[MAX_COMMAND_SIZE];
+	struct cdrom_generic_command cgc;
 
 	if (speed == 0)
 		speed = 0xffff;	/* set to max */
 	else
 		speed *= 177;	/* Nx to kbyte/s */
 
-	memset(sr_cmd, 0, MAX_COMMAND_SIZE);
-	sr_cmd[0] = GPCMD_SET_SPEED;	/* SET CD SPEED */
-	sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-	            ((cd->device->lun) << 5) : 0;
-	sr_cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
-	sr_cmd[3] = speed & 0xff;	/* LSB */
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = GPCMD_SET_SPEED;	/* SET CD SPEED */
+	cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+		     ((cd->device->lun) << 5) : 0;
+	cgc.cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
+	cgc.cmd[3] = speed & 0xff;	/* LSB */
+	cgc.data_direction = SCSI_DATA_NONE;
+	cgc.timeout = IOCTL_TIMEOUT;
 
-	if (sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL))
+	if (sr_do_ioctl(cd, &cgc))
 		return -EIO;
 	return 0;
 }
@@ -337,24 +348,28 @@
 int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
 {
 	Scsi_CD *cd = cdi->handle;
-	u_char sr_cmd[10];
+	struct cdrom_generic_command cgc;
 	int result;
 	unsigned char buffer[32];
 
-	memset(sr_cmd, 0, sizeof(sr_cmd));
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.timeout = IOCTL_TIMEOUT;
 
 	switch (cmd) {
 	case CDROMREADTOCHDR:
 		{
 			struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
 
-			sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-			sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-			            ((cd->device->lun) << 5) : 0;
-			sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-			sr_cmd[8] = 12;		/* LSB of length */
+			cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+			cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+				     ((cd->device->lun) << 5) : 0;
+			cgc.cmd[8] = 12;		/* LSB of length */
+			cgc.buffer = buffer;
+			cgc.buflen = 12;
+			cgc.quiet = 1;
+			cgc.data_direction = SCSI_DATA_READ;
 
-			result = sr_do_ioctl(cd, sr_cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
+			result = sr_do_ioctl(cd, &cgc);
 
 			tochdr->cdth_trk0 = buffer[2];
 			tochdr->cdth_trk1 = buffer[3];
@@ -366,15 +381,17 @@
 		{
 			struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
 
-			sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
-			sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-			            ((cd->device->lun) << 5) : 0;
-			sr_cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
-			sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-			sr_cmd[6] = tocentry->cdte_track;
-			sr_cmd[8] = 12;		/* LSB of length */
+			cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+			cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+				     ((cd->device->lun) << 5) : 0;
+			cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
+			cgc.cmd[6] = tocentry->cdte_track;
+			cgc.cmd[8] = 12;		/* LSB of length */
+			cgc.buffer = buffer;
+			cgc.buflen = 12;
+			cgc.data_direction = SCSI_DATA_READ;
 
-			result = sr_do_ioctl(cd, sr_cmd, buffer, 12, 0, SCSI_DATA_READ, NULL);
+			result = sr_do_ioctl(cd, &cgc);
 
 			tocentry->cdte_ctrl = buffer[5] & 0xf;
 			tocentry->cdte_adr = buffer[5] >> 4;
@@ -393,15 +410,16 @@
 	case CDROMPLAYTRKIND: {
 		struct cdrom_ti* ti = (struct cdrom_ti*)arg;
 
-		sr_cmd[0] = GPCMD_PLAYAUDIO_TI;
-		sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-		            (cd->device->lun << 5) : 0;
-		sr_cmd[4] = ti->cdti_trk0;
-		sr_cmd[5] = ti->cdti_ind0;
-		sr_cmd[7] = ti->cdti_trk1;
-		sr_cmd[8] = ti->cdti_ind1;
+		cgc.cmd[0] = GPCMD_PLAYAUDIO_TI;
+		cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+			     (cd->device->lun << 5) : 0;
+		cgc.cmd[4] = ti->cdti_trk0;
+		cgc.cmd[5] = ti->cdti_ind0;
+		cgc.cmd[7] = ti->cdti_trk1;
+		cgc.cmd[8] = ti->cdti_ind1;
+		cgc.data_direction = SCSI_DATA_NONE;
 
-		result = sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL);
+		result = sr_do_ioctl(cd, &cgc);
 		if (result == -EDRIVE_CANT_DO_THIS)
 			result = sr_fake_playtrkind(cdi, ti);
 
@@ -436,38 +454,42 @@
 
 static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int blksize)
 {
-	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct cdrom_generic_command cgc;
 
 #ifdef DEBUG
 	printk("%s: sr_read_cd lba=%d format=%d blksize=%d\n",
 	       cd->cdi.name, lba, format, blksize);
 #endif
 
-	memset(cmd, 0, MAX_COMMAND_SIZE);
-	cmd[0] = GPCMD_READ_CD;	/* READ_CD */
-	cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-	         (cd->device->lun << 5) : 0;
-	cmd[1] |= ((format & 7) << 2);
-	cmd[2] = (unsigned char) (lba >> 24) & 0xff;
-	cmd[3] = (unsigned char) (lba >> 16) & 0xff;
-	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
-	cmd[5] = (unsigned char) lba & 0xff;
-	cmd[8] = 1;
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = GPCMD_READ_CD;	/* READ_CD */
+	cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+		     (cd->device->lun << 5) : 0;
+	cgc.cmd[1] |= ((format & 7) << 2);
+	cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff;
+	cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff;
+	cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff;
+	cgc.cmd[5] = (unsigned char) lba & 0xff;
+	cgc.cmd[8] = 1;
 	switch (blksize) {
 	case 2336:
-		cmd[9] = 0x58;
+		cgc.cmd[9] = 0x58;
 		break;
 	case 2340:
-		cmd[9] = 0x78;
+		cgc.cmd[9] = 0x78;
 		break;
 	case 2352:
-		cmd[9] = 0xf8;
+		cgc.cmd[9] = 0xf8;
 		break;
 	default:
-		cmd[9] = 0x10;
+		cgc.cmd[9] = 0x10;
 		break;
 	}
-	return sr_do_ioctl(cd, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL);
+	cgc.buffer = dest;
+	cgc.buflen = blksize;
+	cgc.data_direction = SCSI_DATA_READ;
+	cgc.timeout = IOCTL_TIMEOUT;
+	return sr_do_ioctl(cd, &cgc);
 }
 
 /*
@@ -476,7 +498,7 @@
 
 static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest)
 {
-	unsigned char cmd[MAX_COMMAND_SIZE];	/* the scsi-command */
+	struct cdrom_generic_command cgc;
 	int rc;
 
 	/* we try the READ CD command first... */
@@ -497,16 +519,20 @@
 	printk("%s: sr_read_sector lba=%d blksize=%d\n", cd->cdi.name, lba, blksize);
 #endif
 
-	memset(cmd, 0, MAX_COMMAND_SIZE);
-	cmd[0] = GPCMD_READ_10;
-	cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-	         (cd->device->lun << 5) : 0;
-	cmd[2] = (unsigned char) (lba >> 24) & 0xff;
-	cmd[3] = (unsigned char) (lba >> 16) & 0xff;
-	cmd[4] = (unsigned char) (lba >> 8) & 0xff;
-	cmd[5] = (unsigned char) lba & 0xff;
-	cmd[8] = 1;
-	rc = sr_do_ioctl(cd, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL);
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = GPCMD_READ_10;
+	cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+		     (cd->device->lun << 5) : 0;
+	cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff;
+	cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff;
+	cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff;
+	cgc.cmd[5] = (unsigned char) lba & 0xff;
+	cgc.cmd[8] = 1;
+	cgc.buffer = dest;
+	cgc.buflen = blksize;
+	cgc.data_direction = SCSI_DATA_READ;
+	cgc.timeout = IOCTL_TIMEOUT;
+	rc = sr_do_ioctl(cd, &cgc);
 
 	return rc;
 }
@@ -562,7 +588,6 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
--- a/drivers/scsi/sr_vendor.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/sr_vendor.c	Tue Oct 15 20:29:16 2002
@@ -58,6 +58,8 @@
 #define VENDOR_TOSHIBA         3
 #define VENDOR_WRITER          4	/* pre-scsi3 writers */
 
+#define VENDOR_TIMEOUT	30*HZ
+
 void sr_vendor_init(Scsi_CD *cd)
 {
 #ifndef CONFIG_BLK_DEV_SR_VENDOR
@@ -104,7 +106,7 @@
 int sr_set_blocklength(Scsi_CD *cd, int blocklength)
 {
 	unsigned char *buffer;	/* the buffer for the ioctl */
-	unsigned char cmd[MAX_COMMAND_SIZE];	/* the scsi-command */
+	struct cdrom_generic_command cgc;
 	struct ccs_modesel_head *modesel;
 	int rc, density = 0;
 
@@ -120,19 +122,23 @@
 #ifdef DEBUG
 	printk("%s: MODE SELECT 0x%x/%d\n", cd->cdi.name, density, blocklength);
 #endif
-	memset(cmd, 0, MAX_COMMAND_SIZE);
-	cmd[0] = MODE_SELECT;
-	cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-	         (cd->device->lun << 5) : 0;
-	cmd[1] |= (1 << 4);
-	cmd[4] = 12;
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+	cgc.cmd[0] = MODE_SELECT;
+	cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+		     (cd->device->lun << 5) : 0;
+	cgc.cmd[1] |= (1 << 4);
+	cgc.cmd[4] = 12;
 	modesel = (struct ccs_modesel_head *) buffer;
 	memset(modesel, 0, sizeof(*modesel));
 	modesel->block_desc_length = 0x08;
 	modesel->density = density;
 	modesel->block_length_med = (blocklength >> 8) & 0xff;
 	modesel->block_length_lo = blocklength & 0xff;
-	if (0 == (rc = sr_do_ioctl(cd, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE, NULL))) {
+	cgc.buffer = buffer;
+	cgc.buflen = sizeof(*modesel);
+	cgc.data_direction = SCSI_DATA_WRITE;
+	cgc.timeout = VENDOR_TIMEOUT;
+	if (0 == (rc = sr_do_ioctl(cd, &cgc))) {
 		cd->device->sector_size = blocklength;
 	}
 #ifdef DEBUG
@@ -154,7 +160,7 @@
 	Scsi_CD *cd = cdi->handle;
 	unsigned long sector;
 	unsigned char *buffer;	/* the buffer for the ioctl */
-	unsigned char cmd[MAX_COMMAND_SIZE];	/* the scsi-command */
+	struct cdrom_generic_command cgc;
 	int rc, no_multi;
 
 	if (cd->cdi.mask & CDC_MULTI_SESSION)
@@ -168,16 +174,22 @@
 	no_multi = 0;		/* flag: the drive can't handle multisession */
 	rc = 0;
 
+	memset(&cgc, 0, sizeof(struct cdrom_generic_command));
+
 	switch (cd->vendor) {
 
 	case VENDOR_SCSI3:
-		memset(cmd, 0, MAX_COMMAND_SIZE);
-		cmd[0] = READ_TOC;
-		cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-		         (cd->device->lun << 5) : 0;
-		cmd[8] = 12;
-		cmd[9] = 0x40;
-		rc = sr_do_ioctl(cd, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
+		cgc.cmd[0] = READ_TOC;
+		cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+			     (cd->device->lun << 5) : 0;
+		cgc.cmd[8] = 12;
+		cgc.cmd[9] = 0x40;
+		cgc.buffer = buffer;
+		cgc.buflen = 12;
+		cgc.quiet = 1;
+		cgc.data_direction = SCSI_DATA_READ;
+		cgc.timeout = VENDOR_TIMEOUT;
+		rc = sr_do_ioctl(cd, &cgc);
 		if (rc != 0)
 			break;
 		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
@@ -197,13 +209,17 @@
 #ifdef CONFIG_BLK_DEV_SR_VENDOR
 	case VENDOR_NEC:{
 			unsigned long min, sec, frame;
-			memset(cmd, 0, MAX_COMMAND_SIZE);
-			cmd[0] = 0xde;
-			cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-			         (cd->device->lun << 5) : 0;
-			cmd[1] |= 0x03;
-			cmd[2] = 0xb0;
-			rc = sr_do_ioctl(cd, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL);
+			cgc.cmd[0] = 0xde;
+			cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+				     (cd->device->lun << 5) : 0;
+			cgc.cmd[1] |= 0x03;
+			cgc.cmd[2] = 0xb0;
+			cgc.buffer = buffer;
+			cgc.buflen = 0x16;
+			cgc.quiet = 1;
+			cgc.data_direction = SCSI_DATA_READ;
+			cgc.timeout = VENDOR_TIMEOUT;
+			rc = sr_do_ioctl(cd, &cgc);
 			if (rc != 0)
 				break;
 			if (buffer[14] != 0 && buffer[14] != 0xb0) {
@@ -225,12 +241,16 @@
 
 			/* we request some disc information (is it a XA-CD ?,
 			 * where starts the last session ?) */
-			memset(cmd, 0, MAX_COMMAND_SIZE);
-			cmd[0] = 0xc7;
-			cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-			         (cd->device->lun << 5) : 0;
-			cmd[1] |= 0x03;
-			rc = sr_do_ioctl(cd, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL);
+			cgc.cmd[0] = 0xc7;
+			cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+				     (cd->device->lun << 5) : 0;
+			cgc.cmd[1] |= 0x03;
+			cgc.buffer = buffer;
+			cgc.buflen = 4;
+			cgc.quiet = 1;
+			cgc.data_direction = SCSI_DATA_READ;
+			cgc.timeout = VENDOR_TIMEOUT;
+			rc = sr_do_ioctl(cd, &cgc);
 			if (rc == -EINVAL) {
 				printk(KERN_INFO "%s: Hmm, seems the drive "
 				       "doesn't support multisession CD's\n",
@@ -251,13 +271,17 @@
 		}
 
 	case VENDOR_WRITER:
-		memset(cmd, 0, MAX_COMMAND_SIZE);
-		cmd[0] = READ_TOC;
-		cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-		         (cd->device->lun << 5) : 0;
-		cmd[8] = 0x04;
-		cmd[9] = 0x40;
-		rc = sr_do_ioctl(cd, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL);
+		cgc.cmd[0] = READ_TOC;
+		cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+			     (cd->device->lun << 5) : 0;
+		cgc.cmd[8] = 0x04;
+		cgc.cmd[9] = 0x40;
+		cgc.buffer = buffer;
+		cgc.buflen = 0x04;
+		cgc.quiet = 1;
+		cgc.data_direction = SCSI_DATA_READ;
+		cgc.timeout = VENDOR_TIMEOUT;
+		rc = sr_do_ioctl(cd, &cgc);
 		if (rc != 0) {
 			break;
 		}
@@ -266,13 +290,18 @@
 			       "%s: No finished session\n", cd->cdi.name);
 			break;
 		}
-		cmd[0] = READ_TOC;	/* Read TOC */
-		cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
-		         (cd->device->lun << 5) : 0;
-		cmd[6] = rc & 0x7f;	/* number of last session */
-		cmd[8] = 0x0c;
-		cmd[9] = 0x40;
-		rc = sr_do_ioctl(cd, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL);
+		cgc.cmd[0] = READ_TOC;	/* Read TOC */
+		cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ?
+			     (cd->device->lun << 5) : 0;
+		cgc.cmd[6] = rc & 0x7f;	/* number of last session */
+		cgc.cmd[8] = 0x0c;
+		cgc.cmd[9] = 0x40;
+		cgc.buffer = buffer;
+		cgc.buflen = 12;
+		cgc.quiet = 1;
+		cgc.data_direction = SCSI_DATA_READ;
+		cgc.timeout = VENDOR_TIMEOUT;
+		rc = sr_do_ioctl(cd, &cgc);
 		if (rc != 0) {
 			break;
 		}
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/scsi/st.c	Tue Oct 15 20:29:17 2002
@@ -12,13 +12,13 @@
    Copyright 1992 - 2002 Kai Makisara
    email Kai.Makisara@metla.fi
 
-   Last modified: Sun Sep 29 22:29:16 2002 by makisara
+   Last modified: Tue Oct 15 22:01:04 2002 by makisara
    Some small formal changes - aeb, 950809
 
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static char *verstr = "20020929";
+static char *verstr = "20021015";
 
 #include <linux/module.h>
 
@@ -291,6 +291,8 @@
 	if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */
 		STp->cleaning_req = 1;
 
+	STp->pos_unknown |= STp->device->was_reset;
+
 	if ((sense[0] & 0x70) == 0x70 &&
 	    scode == RECOVERED_ERROR
 #if ST_RECOVERED_WRITE_FATAL
@@ -566,7 +568,7 @@
 	 * If there was a bus reset, block further access
 	 * to this device.
 	 */
-	if (STp->device->was_reset)
+	if (STp->pos_unknown)
 		return (-EIO);
 
 	if (STp->ready != ST_READY)
@@ -640,6 +642,52 @@
 	}
 	return 0;
 }
+
+
+/* Lock or unlock the drive door. Don't use when Scsi_Request allocated. */
+static int do_door_lock(Scsi_Tape * STp, int do_lock)
+{
+	int retval, cmd;
+	DEB(int dev = TAPE_NR(STp->devt);)
+
+
+	cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
+	DEBC(printk(ST_DEB_MSG "st%d: %socking drive door.\n", dev,
+		    do_lock ? "L" : "Unl"));
+	retval = scsi_ioctl(STp->device, cmd, NULL);
+	if (!retval) {
+		STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
+	}
+	else {
+		STp->door_locked = ST_LOCK_FAILS;
+	}
+	return retval;
+}
+
+
+/* Set the internal state after reset */
+static void reset_state(Scsi_Tape *STp)
+{
+	int i;
+	ST_partstat *STps;
+
+	STp->pos_unknown = 0;
+	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(STp->ps[i]);
+		STps->rw = ST_IDLE;
+		STps->eof = ST_NOEOF;
+		STps->at_sm = 0;
+		STps->last_block_valid = FALSE;
+		STps->drv_block = -1;
+		STps->drv_file = -1;
+	}
+	if (STp->can_partitions) {
+		STp->partition = find_partition(STp);
+		if (STp->partition < 0)
+			STp->partition = 0;
+		STp->new_partition = STp->partition;
+	}
+}
 
 /* Test if the drive is ready. Returns either one of the codes below or a negative system
    error code. */
@@ -757,7 +805,7 @@
 	    goto err_out;
 
 	if (retval == CHKRES_NEW_SESSION) {
-		(STp->device)->was_reset = 0;
+		STp->pos_unknown = 0;
 		STp->partition = STp->new_partition = 0;
 		if (STp->can_partitions)
 			STp->nbr_partitions = 1; /* This guess will be updated later
@@ -1021,7 +1069,7 @@
 	STm = &(STp->modes[STp->current_mode]);
 	STps = &(STp->ps[STp->partition]);
 
-	if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+	if (STps->rw == ST_WRITING && !STp->pos_unknown) {
 		result = flush_write_buffer(STp);
 		if (result != 0 && result != (-ENOSPC))
 			goto out;
@@ -1040,7 +1088,7 @@
 		printk(KERN_WARNING "st%d: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
 		       dev, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
 
-	if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+	if (STps->rw == ST_WRITING && !STp->pos_unknown) {
 
                 DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
                             dev, (long) (filp->f_pos));
@@ -1136,7 +1184,7 @@
 	read_unlock(&st_dev_arr_lock);
 
 	if (STp->door_locked == ST_LOCKED_AUTO)
-		st_int_ioctl(STp, MTUNLOCK, 0);
+		do_door_lock(STp, 0);
 
 	normalize_buffer(STp->buffer);
 	write_lock(&st_dev_arr_lock);
@@ -1189,7 +1237,7 @@
 	 * If there was a bus reset, block further access
 	 * to this device.
 	 */
-	if (STp->device->was_reset) {
+	if (STp->pos_unknown) {
 		retval = (-EIO);
 		goto out;
 	}
@@ -1216,7 +1264,7 @@
 	}
 
 	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
-	    !st_int_ioctl(STp, MTLOCK, 0))
+	    !do_door_lock(STp, 1))
 		STp->door_locked = ST_LOCKED_AUTO;
 
  out:
@@ -2502,18 +2550,6 @@
                 DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev));
 		fileno = blkno = at_sm = 0;
 		break;
-	case MTLOCK:
-		chg_eof = FALSE;
-		cmd[0] = ALLOW_MEDIUM_REMOVAL;
-		cmd[4] = SCSI_REMOVAL_PREVENT;
-                DEBC(printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev));
-		break;
-	case MTUNLOCK:
-		chg_eof = FALSE;
-		cmd[0] = ALLOW_MEDIUM_REMOVAL;
-		cmd[4] = SCSI_REMOVAL_ALLOW;
-                DEBC(printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev));
-		break;
 	case MTSETBLK:		/* Set block length */
 	case MTSETDENSITY:	/* Set tape density */
 	case MTSETDRVBUFFER:	/* Set drive buffering */
@@ -2594,11 +2630,6 @@
 		STps->drv_file = fileno;
 		STps->at_sm = at_sm;
 
-		if (cmd_in == MTLOCK)
-			STp->door_locked = ST_LOCKED_EXPLICIT;
-		else if (cmd_in == MTUNLOCK)
-			STp->door_locked = ST_UNLOCKED;
-
 		if (cmd_in == MTBSFM)
 			ioctl_result = st_int_ioctl(STp, MTFSF, 1);
 		else if (cmd_in == MTFSFM)
@@ -2713,9 +2744,6 @@
 		if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
 			STps->eof = ST_EOD;
 
-		if (cmd_in == MTLOCK)
-			STp->door_locked = ST_LOCK_FAILS;
-
 		scsi_release_request(SRpnt);
 		SRpnt = NULL;
 	}
@@ -3104,7 +3132,7 @@
 			goto out;
 		}
 
-		if (!(STp->device)->was_reset) {
+		if (!STp->pos_unknown) {
 
 			if (STps->eof == ST_FM_HIT) {
 				if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
@@ -3152,16 +3180,9 @@
 				retval = (-EIO);
 				goto out;
 			}
+			reset_state(STp);
+			/* remove this when the midlevel properly clears was_reset */
 			STp->device->was_reset = 0;
-			if (STp->door_locked != ST_UNLOCKED &&
-			    STp->door_locked != ST_LOCK_FAILS) {
-				if (st_int_ioctl(STp, MTLOCK, 0)) {
-					printk(KERN_NOTICE
-                                               "st%d: Could not relock door after bus reset.\n",
-					       dev);
-					STp->door_locked = ST_UNLOCKED;
-				}
-			}
 		}
 
 		if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
@@ -3170,7 +3191,7 @@
 			STps->rw = ST_IDLE;	/* Prevent automatic WEOF and fsf */
 
 		if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
-			st_int_ioctl(STp, MTUNLOCK, 0);	/* Ignore result! */
+			do_door_lock(STp, 0);	/* Ignore result! */
 
 		if (mtc.mt_op == MTSETDRVBUFFER &&
 		    (mtc.mt_count & MT_ST_OPTIONS) != 0) {
@@ -3238,6 +3259,11 @@
 			goto out;
 		}
 
+		if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
+			retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
+			goto out;
+		}
+
 		if (STp->can_partitions && STp->ready == ST_READY &&
 		    (i = switch_partition(STp)) < 0) {
 			retval = i;
@@ -3642,13 +3668,13 @@
 
 static struct file_operations st_fops =
 {
-	owner:		THIS_MODULE,
-	read:		st_read,
-	write:		st_write,
-	ioctl:		st_ioctl,
-	open:		st_open,
-	flush:		st_flush,
-	release:	st_release,
+	.owner =	THIS_MODULE,
+	.read =		st_read,
+	.write =	st_write,
+	.ioctl =	st_ioctl,
+	.open =		st_open,
+	.flush =	st_flush,
+	.release =	st_release,
 };
 
 static int st_attach(Scsi_Device * SDp)
@@ -3909,12 +3935,12 @@
 						   &dev_attr_type);
 				device_remove_file(&tpnt->driverfs_dev_r[mode],
 						   &dev_attr_kdev);
-				put_device(&tpnt->driverfs_dev_r[mode]);
+				device_unregister(&tpnt->driverfs_dev_r[mode]);
 				device_remove_file(&tpnt->driverfs_dev_n[mode],
 						   &dev_attr_type);
 				device_remove_file(&tpnt->driverfs_dev_n[mode],
 						   &dev_attr_kdev);
-				put_device(&tpnt->driverfs_dev_n[mode]);
+				device_unregister(&tpnt->driverfs_dev_n[mode]);
 			}
 			if (tpnt->buffer) {
 				tpnt->buffer->orig_frp_segs = 0;
diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h
--- a/drivers/scsi/st.h	Tue Oct 15 20:29:20 2002
+++ b/drivers/scsi/st.h	Tue Oct 15 20:29:20 2002
@@ -94,6 +94,7 @@
 	unsigned char use_pf;			/* Set Page Format bit in all mode selects? */
 	unsigned char try_dio;			/* try direct i/o? */
 	unsigned char c_algo;			/* compression algorithm */
+	unsigned char pos_unknown;			/* after reset position unknown */
 	int tape_type;
 	int write_threshold;
 	int timeout;		/* timeout for normal commands */
diff -Nru a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
--- a/drivers/scsi/sym53c416.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/scsi/sym53c416.c	Tue Oct 15 20:29:12 2002
@@ -9,6 +9,8 @@
  *  Alan Cox <alan@redhat.com> : Cleaned up code formatting
  *				 Fixed an irq locking bug
  *				 Added ISAPnP support
+ *  Bjoern A. Zeeb <bzeeb@zabbadoz.net> : Initial irq locking updates
+ *					  Added another card with ISAPnP support
  * 
  *  LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>]
  *
@@ -27,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/init.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
@@ -194,18 +197,10 @@
 
 #endif
 
-/* #define DEBUG */
-
-/* Macro for debugging purposes */
-
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
-
 #define MAXHOSTS 4
 
+#define SG_ADDRESS(buffer)     ((char *) (page_address((buffer)->page)+(buffer)->offset))
+
 enum phases
 {
 	idle,
@@ -246,6 +241,8 @@
 	outb((len & 0xFF0000) >> 16, base + TC_HIGH);
 }
 
+static spinlock_t sym53c416_lock = SPIN_LOCK_UNLOCKED;
+
 /* Returns the number of bytes read */
 static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len)
 {
@@ -256,8 +253,7 @@
 	int timeout = READ_TIMEOUT;
 
 	/* Do transfer */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&sym53c416_lock, flags);
 	while(len && timeout)
 	{
 		bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
@@ -276,17 +272,16 @@
 		else
 		{
 			i = jiffies + timeout;
-			restore_flags(flags);
+			spin_unlock_irqrestore(&sym53c416_lock, flags);
 			while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
 				if(inb(base + PIO_INT_REG) & SCI)
 					timeout = 0;
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&sym53c416_lock, flags);
 			if(inb(base + PIO_INT_REG) & EMPTY)
 				timeout = 0;
 		}
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&sym53c416_lock, flags);
 	return orig_len - len;
 }
 
@@ -300,8 +295,7 @@
 	unsigned int timeout = WRITE_TIMEOUT;
 
 	/* Do transfer */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&sym53c416_lock, flags);
 	while(len && timeout)
 	{
 		bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
@@ -322,16 +316,15 @@
 		else
 		{
 			i = jiffies + timeout;
-			restore_flags(flags);
+			spin_unlock_irqrestore(&sym53c416_lock, flags);
 			while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout)
 				;
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&sym53c416_lock, flags);
 			if(inb(base + PIO_INT_REG) & FULL)
 				timeout = 0;
 		}
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&sym53c416_lock, flags);
 	return orig_len - len;
 }
 
@@ -449,7 +442,7 @@
 					sglist = current_command->request_buffer;
 					while(sgcount--)
 					{
-						tot_trans += sym53c416_write(base, sglist->address, sglist->length);
+						tot_trans += sym53c416_write(base, SG_ADDRESS(sglist), sglist->length);
 						sglist++;
 					}
 				}
@@ -475,7 +468,7 @@
 					sglist = current_command->request_buffer;
 					while(sgcount--)
 					{
-						tot_trans += sym53c416_read(base, sglist->address, sglist->length);
+						tot_trans += sym53c416_read(base, SG_ADDRESS(sglist), sglist->length);
 						sglist++;
 					}
 				}
@@ -562,7 +555,7 @@
 	i = jiffies + 20;
 	while(i > jiffies && !(inb(base + STATUS_REG) & SCI))
 		barrier();
-	if(i <= jiffies) /* timed out */
+	if(time_before_eq(i, jiffies))	/* timed out */
 		return 0;
 	/* Get occurred irq */
 	irq = probe_irq_off(irqs);
@@ -611,10 +604,12 @@
 }
 
 
-static struct isapnp_device_id id_table[] = {
+static struct isapnp_device_id id_table[] __devinitdata = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4161), 0 },
 	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
 		ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4163), 0 },
-	{0}
+	{	ISAPNP_DEVICE_SINGLE_END }
 };
 
 MODULE_DEVICE_TABLE(isapnp, id_table);
@@ -635,7 +630,7 @@
 	}
 }
 
-int sym53c416_detect(Scsi_Host_Template *tpnt)
+int __init sym53c416_detect(Scsi_Host_Template *tpnt)
 {
 	unsigned long flags;
 	struct Scsi_Host * shpnt = NULL;
@@ -674,29 +669,32 @@
 #endif
 	printk(KERN_INFO "sym53c416.c: %s\n", VERSION_STRING);
 
-	while((idev=isapnp_find_dev(NULL, ISAPNP_VENDOR('S','L','I'), 
-				ISAPNP_FUNCTION(0x4163), idev))!=NULL)
-	{
-		int i[3];
-		
-		if(idev->prepare(idev)<0)
-		{
-			printk(KERN_WARNING "sym53c416: unable to prepare PnP card.\n");
-			continue;
-		}
-		if(idev->activate(idev)<0)
+	for (i=0; id_table[i].vendor != 0; i++) {
+		while((idev=isapnp_find_dev(NULL, id_table[i].vendor,
+					id_table[i].function, idev))!=NULL)
 		{
-			printk(KERN_WARNING "sym53c416: unable to activate PnP card.\n");
-			continue;
-		}
-		
-		i[0] = 2;
-		i[1] = idev->resource[0].start;
-		i[2] = idev->irq_resource[0].start;
-		
-		printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n",
-			i[1], i[2]);
-		sym53c416_setup(NULL, i);
+			int i[3];
+
+			if(idev->prepare(idev)<0)
+			{
+				printk(KERN_WARNING "sym53c416: unable to prepare PnP card.\n");
+				continue;
+			}
+			if(idev->activate(idev)<0)
+			{
+				printk(KERN_WARNING "sym53c416: unable to activate PnP card.\n");
+				continue;
+			
+			}
+
+			i[0] = 2;
+			i[1] = idev->resource[0].start;
+ 			i[2] = idev->irq_resource[0].start;
+
+			printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n",
+				i[1], i[2]);
+ 			sym53c416_setup(NULL, i);
+ 		}
 	}
 	sym53c416_probe();
 
@@ -716,13 +714,12 @@
 				shpnt = scsi_register(tpnt, 0);
 				if(shpnt==NULL)
 					continue;
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&sym53c416_lock, flags);
 				/* FIXME: Request_irq with CLI is not safe */
 				/* Request for specified IRQ */
 				if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, shpnt))
 				{
-					restore_flags(flags);
+					spin_unlock_irqrestore(&sym53c416_lock, flags);
 					printk(KERN_ERR "sym53c416: Unable to assign IRQ %d\n", hosts[i].irq);
 					scsi_unregister(shpnt);
 				}
@@ -737,7 +734,7 @@
 					shpnt->this_id = hosts[i].scsi_id;
 					sym53c416_init(hosts[i].base, hosts[i].scsi_id);
 					count++;
-					restore_flags(flags);
+					spin_unlock_irqrestore(&sym53c416_lock, flags);
 				}
 			}
 		}
@@ -774,8 +771,7 @@
 	current_command->SCp.Status = 0;
 	current_command->SCp.Message = 0;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&sym53c416_lock, flags);
 	outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target        */
 	outb(FLUSH_FIFO, base + COMMAND_REG);    /* Flush SCSI and PIO FIFO's */
 	/* Write SCSI command into the SCSI fifo */
@@ -784,7 +780,7 @@
 	/* Start selection sequence */
 	outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
 	/* Now an interrupt will be generated which we will catch in out interrupt routine */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&sym53c416_lock, flags);
 	return 0;
 }
 
@@ -804,7 +800,7 @@
 
 static int sym53c416_abort(Scsi_Cmnd *SCpnt)
 {
-	//printk("sym53c416_abort\n");
+	/* printk("sym53c416_abort\n"); */
 	/* We don't know how to abort for the moment */
 	return SCSI_ABORT_SNOOZE;
 }
@@ -815,7 +811,7 @@
 	int scsi_id = -1;	
 	int i;
 
-	//printk("sym53c416_reset\n");
+	/* printk("sym53c416_reset\n"); */
 	base = SCpnt->host->io_port;
 	/* search scsi_id */
 	for(i = 0; i < host_index && scsi_id != -1; i++)
diff -Nru a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
--- a/drivers/scsi/sym53c8xx.c	Tue Oct 15 20:29:18 2002
+++ b/drivers/scsi/sym53c8xx.c	Tue Oct 15 20:29:18 2002
@@ -1341,8 +1341,6 @@
 #define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff)
 #endif
 
-static void sym53c8xx_select_queue_depths(
-	struct Scsi_Host *host, struct scsi_device *devlist);
 static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
 static void sym53c8xx_timeout(unsigned long np);
 
@@ -5923,8 +5921,6 @@
 #endif
 #endif
 	
-	instance->select_queue_depths = sym53c8xx_select_queue_depths;
-
 	NCR_UNLOCK_NCB(np, flags);
 
 	/*
@@ -13545,56 +13541,57 @@
 	return DEF_DEPTH;
 }
 
-static void sym53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist)
+int sym53c8xx_slave_attach(Scsi_Device *device)
 {
-	struct scsi_device *device;
-
-	for (device = devlist; device; device = device->next) {
-		ncb_p np;
-		tcb_p tp;
-		lcb_p lp;
-		int numtags;
-
-		if (device->host != host)
-			continue;
+	struct Scsi_Host *host = device->host;
+	ncb_p np;
+	tcb_p tp;
+	lcb_p lp;
+	int numtags, depth_to_use;
 
-		np = ((struct host_data *) host->hostdata)->ncb;
-		tp = &np->target[device->id];
-		lp = ncr_lp(np, tp, device->lun);
-
-		/*
-		**	Select queue depth from driver setup.
-		**	Donnot use more than configured by user.
-		**	Use at least 2.
-		**	Donnot use more than our maximum.
-		*/
-		numtags = device_queue_depth(np, device->id, device->lun);
-		if (numtags > tp->usrtags)
-			numtags = tp->usrtags;
-		if (!device->tagged_supported)
-			numtags = 1;
-		device->queue_depth = numtags;
-		if (device->queue_depth < 2)
-			device->queue_depth = 2;
-		if (device->queue_depth > MAX_TAGS)
-			device->queue_depth = MAX_TAGS;
-
-		/*
-		**	Since the queue depth is not tunable under Linux,
-		**	we need to know this value in order not to 
-		**	announce stupid things to user.
-		*/
-		if (lp) {
-			lp->numtags = lp->maxtags = numtags;
-			lp->scdev_depth = device->queue_depth;
-		}
-		ncr_setup_tags (np, device->id, device->lun);
+	np = ((struct host_data *) host->hostdata)->ncb;
+	tp = &np->target[device->id];
+	lp = ncr_lp(np, tp, device->lun);
+
+	/*
+	**	Select queue depth from driver setup.
+	**	Donnot use more than configured by user.
+	**	Use at least 2.
+	**	Donnot use more than our maximum.
+	*/
+	numtags = device_queue_depth(np, device->id, device->lun);
+	if (numtags > tp->usrtags)
+		numtags = tp->usrtags;
+	if (!device->tagged_supported)
+		numtags = 1;
+	depth_to_use = numtags;
+	if (depth_to_use < 2)
+		depth_to_use = 2;
+	if (depth_to_use > MAX_TAGS)
+		depth_to_use = MAX_TAGS;
+
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+
+	/*
+	**	Since the queue depth is not tunable under Linux,
+	**	we need to know this value in order not to 
+	**	announce stupid things to user.
+	*/
+	if (lp) {
+		lp->numtags = lp->maxtags = numtags;
+		lp->scdev_depth = depth_to_use;
+	}
+	ncr_setup_tags (np, device->id, device->lun);
 
 #ifdef DEBUG_SYM53C8XX
-printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
-	np->unit, device->id, device->lun, device->queue_depth);
+	printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
+	       np->unit, device->id, device->lun, depth_to_use);
 #endif
-	}
+
+	return 0;
 }
 
 /*
diff -Nru a/drivers/scsi/sym53c8xx.h b/drivers/scsi/sym53c8xx.h
--- a/drivers/scsi/sym53c8xx.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/scsi/sym53c8xx.h	Tue Oct 15 20:29:16 2002
@@ -74,6 +74,7 @@
 const char *sym53c8xx_info(struct Scsi_Host *host);
 int sym53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int sym53c8xx_reset(Scsi_Cmnd *, unsigned int);
+int sym53c8xx_slave_attach(Scsi_Device *);
 
 #ifdef MODULE
 int sym53c8xx_release(struct Scsi_Host *);
@@ -89,6 +90,7 @@
 			release:        sym53c8xx_release,	\
 			info:           sym53c8xx_info, 	\
 			queuecommand:   sym53c8xx_queue_command,\
+			slave_attach:   sym53c8xx_slave_attach, \
 			abort:          sym53c8xx_abort,	\
 			reset:          sym53c8xx_reset,	\
 			bios_param:     scsicam_bios_param,	\
diff -Nru a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Tue Oct 15 20:29:23 2002
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Tue Oct 15 20:29:23 2002
@@ -89,6 +89,8 @@
 int sym53c8xx_eh_bus_reset_handler(Scsi_Cmnd *);
 int sym53c8xx_eh_host_reset_handler(Scsi_Cmnd *);
 
+int sym53c8xx_slave_attach(Scsi_Device *);
+
 #ifdef MODULE
 int sym53c8xx_release(struct Scsi_Host *);
 #else
@@ -109,6 +111,7 @@
 	release:		sym53c8xx_release,			\
 	info:			sym53c8xx_info, 			\
 	queuecommand:		sym53c8xx_queue_command,		\
+	slave_attach:		sym53c8xx_slave_attach,			\
 	eh_abort_handler:	sym53c8xx_eh_abort_handler,		\
 	eh_device_reset_handler:sym53c8xx_eh_device_reset_handler,	\
 	eh_bus_reset_handler:	sym53c8xx_eh_bus_reset_handler,		\
diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	Tue Oct 15 20:29:23 2002
@@ -1327,66 +1327,63 @@
 /*
  * Linux entry point for device queue sizing.
  */
-static void 
-sym53c8xx_select_queue_depths(struct Scsi_Host *host, 
-                              struct scsi_device *devlist)
-{
-	struct scsi_device *device;
-
-	for (device = devlist; device; device = device->next) {
-		hcb_p np;
-		tcb_p tp;
-		lcb_p lp;
-		int reqtags;
-
-		if (device->host != host)
-			continue;
+int
+sym53c8xx_slave_attach(Scsi_Device *device)
+{
+	struct Scsi_Host *host = device->host;
+	hcb_p np;
+	tcb_p tp;
+	lcb_p lp;
+	int reqtags, depth_to_use;
 
-		np = ((struct host_data *) host->hostdata)->ncb;
-		tp = &np->target[device->id];
+	np = ((struct host_data *) host->hostdata)->ncb;
+	tp = &np->target[device->id];
 
-		/*
-		 *  Get user settings for transfer parameters.
-		 */
-		tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16);
-		sym_update_trans_settings(np, tp);
+	/*
+	 *  Get user settings for transfer parameters.
+	 */
+	tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16);
+	sym_update_trans_settings(np, tp);
 
-		/*
-		 *  Allocate the LCB if not yet.
-		 *  If it fail, we may well be in the sh*t. :)
-		 */
-		lp = sym_alloc_lcb(np, device->id, device->lun);
-		if (!lp) {
-			device->queue_depth = 1;
-			continue;
-		}
+	/*
+	 *  Allocate the LCB if not yet.
+	 *  If it fail, we may well be in the sh*t. :)
+	 */
+	lp = sym_alloc_lcb(np, device->id, device->lun);
+	if (!lp)
+		return -ENOMEM;
 
-		/*
-		 *  Get user flags.
-		 */
-		lp->curr_flags = lp->user_flags;
+	/*
+	 *  Get user flags.
+	 */
+	lp->curr_flags = lp->user_flags;
 
-		/*
-		 *  Select queue depth from driver setup.
-		 *  Donnot use more than configured by user.
-		 *  Use at least 2.
-		 *  Donnot use more than our maximum.
-		 */
-		reqtags = device_queue_depth(np, device->id, device->lun);
-		if (reqtags > tp->usrtags)
-			reqtags = tp->usrtags;
-		if (!device->tagged_supported)
-			reqtags = 0;
+	/*
+	 *  Select queue depth from driver setup.
+	 *  Donnot use more than configured by user.
+	 *  Use at least 2.
+	 *  Donnot use more than our maximum.
+	 */
+	reqtags = device_queue_depth(np, device->id, device->lun);
+	if (reqtags > tp->usrtags)
+		reqtags = tp->usrtags;
+	if (!device->tagged_supported)
+		reqtags = 0;
 #if 1 /* Avoid to locally queue commands for no good reasons */
-		if (reqtags > SYM_CONF_MAX_TAG)
-			reqtags = SYM_CONF_MAX_TAG;
-		device->queue_depth = reqtags ? reqtags : 2;
-#else
-		device->queue_depth = reqtags ? SYM_CONF_MAX_TAG : 2;
-#endif
-		lp->s.scdev_depth = device->queue_depth;
-		sym_tune_dev_queuing(np, device->id, device->lun, reqtags);
-	}
+	if (reqtags > SYM_CONF_MAX_TAG)
+		reqtags = SYM_CONF_MAX_TAG;
+	depth_to_use = (reqtags ? reqtags : 2);
+#else
+	depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2);
+#endif
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+	lp->s.scdev_depth = depth_to_use;
+	sym_tune_dev_queuing(np, device->id, device->lun, reqtags);
+
+	return 0;
 }
 
 /*
@@ -2132,7 +2129,6 @@
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
 	instance->max_cmd_len	= 16;
 #endif
-	instance->select_queue_depths = sym53c8xx_select_queue_depths;
 	instance->highmem_io	= 1;
 
 	SYM_UNLOCK_HCB(np, flags);
diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c
--- a/drivers/serial/8250.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/serial/8250.c	Tue Oct 15 20:29:12 2002
@@ -1885,7 +1885,7 @@
 	port.line     = line;
 
 	if (HIGH_BITS_OFFSET)
-		port.iobase |= req->port_high << HIGH_BITS_OFFSET;
+		port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
 
 	/*
 	 * If a clock rate wasn't specified by the low level
diff -Nru a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/8250_acorn.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,150 @@
+/*
+ *  linux/drivers/serial/acorn.c
+ *
+ *  Copyright (C) 1996-2002 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+#include <asm/string.h>
+
+#define MAX_PORTS	3
+
+struct serial_card_type {
+	unsigned int	num_ports;
+	unsigned int	baud_base;
+	int		type;
+	int		speed;
+	int		offset[MAX_PORTS];
+};
+
+struct serial_card_info {
+	unsigned int	num_ports;
+	int		ports[MAX_PORTS];
+	unsigned long	base[MAX_PORTS];
+};
+
+static inline int serial_register_onedev(unsigned long port, int irq, unsigned int baud_base)
+{
+	struct serial_struct req;
+
+	memset(&req, 0, sizeof(req));
+	req.baud_base = baud_base;
+	req.irq = irq;
+	req.port = port;
+	req.flags = 0;
+
+	return register_serial(&req);
+}
+
+static int __devinit serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct serial_card_info *info;
+	struct serial_card_type *type = id->data;
+	unsigned long cardaddr, address;
+	int port;
+
+	ecard_claim (ec);
+
+	info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	memset(info, 0, sizeof(struct serial_card_info));
+	info->num_ports = type->num_ports;
+
+	cardaddr = ecard_address(ec, type->type, type->speed);
+
+	for (port = 0; port < info->num_ports; port ++) {
+		address = cardaddr + type->offset[port];
+
+		info->ports[port] = -1;
+		info->base[port] = address;
+
+		if (!request_region(address, 8, "acornserial"))
+			continue;
+
+		info->ports[port] = serial_register_onedev(address, ec->irq, type->baud_base);
+		if (info->ports[port] < 0)
+			break;
+	}
+
+	return 0;
+}
+
+static void __devexit serial_card_remove(struct expansion_card *ec)
+{
+	struct serial_card_info *info = ecard_get_drvdata(ec);
+	int i;
+
+	ecard_set_drvdata(ec, NULL);
+
+	for (i = 0; i < info->num_ports; i++) {
+		if (info->ports[i] > 0) {
+			unregister_serial(info->ports[i]);
+			release_region(info->base[i], 8);
+		}
+	}
+
+	kfree(info);
+
+	ecard_release(ec);
+}
+
+static struct serial_card_type atomwide_type = {
+	.num_ports	= 3,
+	.baud_base	= 7372800 / 16,
+	.type		= ECARD_IOC,
+	.speed		= ECARD_SLOW,
+	.offset		= { 0xa00, 0x900, 0x800 },
+};
+
+static struct serial_card_type serport_type = {
+	.num_ports	= 2,
+	.baud_base	= 3686400 / 16,
+	.type		= ECARD_IOC,
+	.speed		= ECARD_SLOW,
+	.offset		= { 0x800, 0x808 },
+};
+
+static const struct ecard_id serial_cids[] = {
+	{ MANU_ATOMWIDE,	PROD_ATOMWIDE_3PSERIAL,	&atomwide_type	},
+	{ MANU_SERPORT,		PROD_SERPORT_DSPORT,	&serport_type	},
+	{ 0xffff, 0xffff }
+};
+
+static struct ecard_driver serial_card_driver = {
+	.probe		= serial_card_probe,
+	.remove 	= __devexit_p(serial_card_remove),
+	.id_table	= serial_cids,
+	.drv = {
+		.name	= "acornserial",
+	},
+};
+
+static int __init serial_card_init(void)
+{
+	return ecard_register_driver(&serial_card_driver);
+}
+
+static void __exit serial_card_exit(void)
+{
+	ecard_remove_driver(&serial_card_driver);
+}
+
+MODULE_AUTHOR("Russell King");
+MODULE_LICENSE("GPL");
+
+module_init(serial_card_init);
+module_exit(serial_card_exit);
diff -Nru a/drivers/serial/Config.help b/drivers/serial/Config.help
--- a/drivers/serial/Config.help	Tue Oct 15 20:29:13 2002
+++ b/drivers/serial/Config.help	Tue Oct 15 20:29:13 2002
@@ -103,20 +103,15 @@
 CONFIG_SERIAL_8250_RSA
   ::: To be written :::
 
-CONFIG_ATOMWIDE_SERIAL
-  If you have an Atomwide Serial card for an Acorn system, say Y to
-  this option.  The driver can handle 1, 2, or 3 port cards.
-  If unsure, say N.
-
-CONFIG_DUALSP_SERIAL
-  If you have the Serial Port's dual serial card for an Acorn system,
-  say Y to this option.  If unsure, say N.
+CONFIG_SERIAL_8250_ACORN
+  If you have an Atomwide Serial card or Serial Port card for an Acorn
+  system, say Y to this option.  The driver can handle 1, 2, or 3 port
+  cards.  If unsure, say N.
 
 CONFIG_SERIAL_ANAKIN
   ::: To be written :::
-CONFIG_SERIAL_ANAKIN_CONSOLE
-  ::: To be written :::
 
+CONFIG_SERIAL_ANAKIN_CONSOLE
   Even if you say Y here, the currently visible virtual console
   (/dev/tty0) will still be used as the system console by default, but
   you can alter that using a kernel command line option such as
@@ -149,8 +144,6 @@
   ::: To be written :::
 
 CONFIG_SERIAL_CLPS711X_CONSOLE
-  ::: To be written :::
-
   Even if you say Y here, the currently visible virtual console
   (/dev/tty0) will still be used as the system console by default, but
   you can alter that using a kernel command line option such as
diff -Nru a/drivers/serial/Config.in b/drivers/serial/Config.in
--- a/drivers/serial/Config.in	Tue Oct 15 20:29:12 2002
+++ b/drivers/serial/Config.in	Tue Oct 15 20:29:12 2002
@@ -22,8 +22,7 @@
 comment 'Non-8250 serial port support'
 
 if [ "$CONFIG_ARM" = "y" ]; then
-   dep_tristate 'Acorn Atomwide 16550 serial port support' CONFIG_ATOMWIDE_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250
-   dep_tristate 'Acorn Dual 16550 serial port support' CONFIG_DUALSP_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250
+   dep_tristate 'Acorn expansion card serial port support' CONFIG_SERIAL_8250_ACORN $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250
    dep_bool 'Anakin serial port support' CONFIG_SERIAL_ANAKIN $CONFIG_ARCH_ANAKIN
    dep_bool '  Console on Anakin serial port' CONFIG_SERIAL_ANAKIN_CONSOLE $CONFIG_SERIAL_ANAKIN
    if [ "$CONFIG_SERIAL_ANAKIN" = "y" ]; then
@@ -53,7 +52,6 @@
 
 if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then
    define_bool CONFIG_SERIAL_SUNCORE y
-   define_bool CONFIG_SERIAL_CORE_CONSOLE y
    tristate 'Sun Zilog8530 serial support' CONFIG_SERIAL_SUNZILOG
    dep_tristate 'Sun SU serial support' CONFIG_SERIAL_SUNSU $CONFIG_PCI
    dep_tristate 'Sun Siemens SAB82532 serial support' CONFIG_SERIAL_SUNSAB $CONFIG_PCI
@@ -63,16 +61,14 @@
      "$CONFIG_SERIAL_21285" = "y"  -o "$CONFIG_SERIAL_SA1100" = "y" -o \
      "$CONFIG_SERIAL_ANAKIN" = "y" -o "$CONFIG_SERIAL_UART00" = "y" -o \
      "$CONFIG_SERIAL_8250" = "y"   -o "$CONFIG_SERIAL_ROCKETPORT" = "y" -o \
-     "$CONFIG_SERIAL_SUNZILOG" = "y" -o "$CONFIG_SERIAL_SUNSU" = "y" -o \
-     "$CONFIG_SERIAL_SUNSAB" = "y" ]; then
+     "$CONFIG_SERIAL_SUNCORE" = "y" ]; then
    define_bool CONFIG_SERIAL_CORE y
 else
    if [ "$CONFIG_SERIAL_AMBA" = "m"   -o "$CONFIG_SERIAL_CLPS711X" = "m" -o \
         "$CONFIG_SERIAL_21285" = "m"  -o "$CONFIG_SERIAL_SA1100" = "m" -o \
         "$CONFIG_SERIAL_ANAKIN" = "m" -o "$CONFIG_SERIAL_UART00" = "m" -o \
         "$CONFIG_SERIAL_8250" = "m"   -o "$CONFIG_SERIAL_ROCKETPORT" = "m" -o \
-        "$CONFIG_SERIAL_SUNZILOG" = "m" -o "$CONFIG_SERIAL_SUNSU" = "m" -o \
-        "$CONFIG_SERIAL_SUNSAB" = "m" ]; then
+        "$CONFIG_SERIAL_SUNCORE" = "m" ]; then
       define_bool CONFIG_SERIAL_CORE m
    fi
 fi
diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile
--- a/drivers/serial/Makefile	Tue Oct 15 20:29:17 2002
+++ b/drivers/serial/Makefile	Tue Oct 15 20:29:17 2002
@@ -13,6 +13,7 @@
 obj-$(CONFIG_SERIAL_21285) += 21285.o
 obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
 obj-$(CONFIG_SERIAL_8250_CS) += 8250_cs.o
+obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
 obj-$(CONFIG_SERIAL_ANAKIN) += anakin.o
 obj-$(CONFIG_SERIAL_AMBA) += amba.o
 obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c
--- a/drivers/serial/core.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/serial/core.c	Tue Oct 15 20:29:14 2002
@@ -593,7 +593,7 @@
 	tmp.line	    = port->line;
 	tmp.port	    = port->iobase;
 	if (HIGH_BITS_OFFSET)
-		tmp.port_high = port->iobase >> HIGH_BITS_OFFSET;
+		tmp.port_high = (long) port->iobase >> HIGH_BITS_OFFSET;
 	tmp.irq		    = port->irq;
 	tmp.flags	    = port->flags | info->flags;
 	tmp.xmit_fifo_size  = port->fifosize;
diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c
--- a/drivers/tc/zs.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/tc/zs.c	Tue Oct 15 20:29:20 2002
@@ -443,7 +443,7 @@
 		if (break_pressed && info->line == sercons.index) {
 			if (ch != 0 &&
 			    time_before(jiffies, break_pressed + HZ*5)) {
-				handle_sysrq(ch, regs, NULL, NULL);
+				handle_sysrq(ch, regs, NULL);
 				break_pressed = 0;
 				goto ignore_char;
 			}
diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/usb/core/hcd-pci.c	Tue Oct 15 20:29:17 2002
@@ -62,6 +62,9 @@
 	int			retval, region;
 	char			buf [8], *bufp = buf;
 
+	if (usb_disabled())
+		return -ENODEV;
+
 	if (!id || !(driver = (struct hc_driver *) id->driver_data))
 		return -EINVAL;
 
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/core/hub.c	Tue Oct 15 20:29:16 2002
@@ -943,7 +943,9 @@
 
 		list_del_init(tmp);
 
-		down(&hub->khubd_sem); /* never blocks, we were on list */
+		if (unlikely(down_trylock(&hub->khubd_sem)))
+			BUG();	/* never blocks, we were on list */
+
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
@@ -1067,10 +1069,10 @@
 }
 
 static struct usb_device_id hub_id_table [] = {
-    { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS,
-      bDeviceClass: USB_CLASS_HUB},
-    { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
-      bInterfaceClass: USB_CLASS_HUB},
+    { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
+      .bDeviceClass = USB_CLASS_HUB},
+    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
+      .bInterfaceClass = USB_CLASS_HUB},
     { }						/* Terminating entry */
 };
 
diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/usb/core/inode.c	Tue Oct 15 20:29:12 2002
@@ -45,7 +45,8 @@
 static struct vfsmount *usbdevfs_mount;
 static struct vfsmount *usbfs_mount;
 static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;
-static int mount_count;	/* = 0 */
+static int usbdevfs_mount_count;	/* = 0 */
+static int usbfs_mount_count;	/* = 0 */
 
 static struct dentry *devices_usbdevfs_dentry;
 static struct dentry *devices_usbfs_dentry;
@@ -507,14 +508,14 @@
 };
 
 /* --------------------------------------------------------------------- */
-static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount)
+static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount, int *mount_count)
 {
 	struct vfsmount *mnt;
 
 	spin_lock (&mount_lock);
 	if (*mount) {
 		mntget(*mount);
-		++mount_count;
+		++(*mount_count);
 		spin_unlock (&mount_lock);
 		goto go_ahead;
 	}
@@ -528,33 +529,33 @@
 	spin_lock (&mount_lock);
 	if (!*mount) {
 		*mount = mnt;
-		++mount_count;
+		++(*mount_count);
 		spin_unlock (&mount_lock);
 		goto go_ahead;
 	}
 	mntget(*mount);
-	++mount_count;
+	++(*mount_count);
 	spin_unlock (&mount_lock);
 	mntput(mnt);
 
 go_ahead:
-	dbg("mount_count = %d", mount_count);
+	dbg("mount_count = %d", *mount_count);
 	return 0;
 }
 
-static void put_mount (struct vfsmount **mount)
+static void put_mount (struct vfsmount **mount, int *mount_count)
 {
 	struct vfsmount *mnt;
 
 	spin_lock (&mount_lock);
 	mnt = *mount;
-	--mount_count;
-	if (!mount_count)
+	--(*mount_count);
+	if (!(*mount_count))
 		*mount = NULL;
 
 	spin_unlock (&mount_lock);
 	mntput(mnt);
-	dbg("mount_count = %d", mount_count);
+	dbg("mount_count = %d", *mount_count);
 }
 
 static int create_special_files (void)
@@ -563,13 +564,13 @@
 	int retval = 0;
 
 	/* create the devices special file */
-	retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount);
+	retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount, &usbdevfs_mount_count);
 	if (retval) {
 		err ("Unable to get usbdevfs mount");
 		goto exit;
 	}
 
-	retval = get_mount (&usb_fs_type, &usbfs_mount);
+	retval = get_mount (&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
 	if (retval) {
 		err ("Unable to get usbfs mount");
 		goto error_clean_usbdevfs_mount;
@@ -604,10 +605,10 @@
 	devices_usbfs_dentry = NULL;
 
 error_clean_mounts:
-	put_mount (&usbfs_mount);
+	put_mount (&usbfs_mount, &usbfs_mount_count);
 
 error_clean_usbdevfs_mount:
-	put_mount (&usbdevfs_mount);	
+	put_mount (&usbdevfs_mount, &usbdevfs_mount_count);
 
 exit:
 	return retval;
@@ -621,8 +622,8 @@
 		fs_remove_file (devices_usbfs_dentry);
 	devices_usbdevfs_dentry = NULL;
 	devices_usbfs_dentry = NULL;
-	put_mount (&usbdevfs_mount);
-	put_mount (&usbfs_mount);
+	put_mount (&usbdevfs_mount, &usbdevfs_mount_count);
+	put_mount (&usbfs_mount, &usbfs_mount_count);
 }
 
 void usbfs_update_special (void)
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/usb/core/message.c	Tue Oct 15 20:29:14 2002
@@ -756,6 +756,7 @@
  *
  * This is used to enable data transfers on interfaces that may not
  * be enabled by default.  Not all devices support such configurability.
+ * Only the driver bound to an interface may change its setting.
  *
  * Within any given configuration, each interface may have several
  * alternative settings.  These are often used to control levels of
@@ -808,6 +809,22 @@
 				   interface, NULL, 0, HZ * 5)) < 0)
 		return ret;
 
+	/* FIXME drivers shouldn't need to replicate/bugfix the logic here
+	 * when they implement async or easily-killable versions of this or
+	 * other "should-be-internal" functions (like clear_halt).
+	 * should hcd+usbcore postprocess control requests?
+	 */
+
+	/* prevent submissions using previous endpoint settings */
+	iface_as = iface->altsetting + iface->act_altsetting;
+	for (i = 0; i < iface_as->bNumEndpoints; i++) {
+		u8	ep = iface_as->endpoint [i].bEndpointAddress;
+		int	out = !(ep & USB_DIR_IN);
+
+		ep &= USB_ENDPOINT_NUMBER_MASK;
+		(out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0;
+		// FIXME want hcd hook here, "no such endpoint"
+	}
 	iface->act_altsetting = alternate;
 
 	/* 9.1.1.5: reset toggles for all endpoints affected by this iface-as
@@ -819,21 +836,20 @@
 	 * any SetInterface request and hence assume toggles need to be reset.
 	 * However, EP0 toggles are re-synced for every individual transfer
 	 * during the SETUP stage - hence EP0 toggles are "don't care" here.
+	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 */
 
 	iface_as = &iface->altsetting[alternate];
 	for (i = 0; i < iface_as->bNumEndpoints; i++) {
 		u8	ep = iface_as->endpoint[i].bEndpointAddress;
+		int	out = !(ep & USB_DIR_IN);
 
-		usb_settoggle(dev, ep&USB_ENDPOINT_NUMBER_MASK, usb_endpoint_out(ep), 0);
+		ep &= USB_ENDPOINT_NUMBER_MASK;
+		usb_settoggle (dev, ep, out, 0);
+		(out ? dev->epmaxpacketout : dev->epmaxpacketin) [ep]
+			= iface_as->endpoint [ep].wMaxPacketSize;
 	}
 
-	/* usb_set_maxpacket() sets the maxpacket size for all EP in all
-	 * interfaces but it shouldn't do any harm here: we have changed
-	 * the AS for the requested interface only, hence for unaffected
-	 * interfaces it's just re-application of still-valid values.
-	 */
-	usb_set_maxpacket(dev);
 	return 0;
 }
 
diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/usb/core/urb.c	Tue Oct 15 20:29:17 2002
@@ -272,9 +272,9 @@
 	/* enforce simple/standard policy */
 	allowed = USB_ASYNC_UNLINK;	// affects later unlinks
 	allowed |= URB_NO_DMA_MAP;
+	allowed |= URB_NO_INTERRUPT;
 	switch (temp) {
 	case PIPE_BULK:
-		allowed |= URB_NO_INTERRUPT;
 		if (is_out)
 			allowed |= USB_ZERO_PACKET;
 		/* FALLTHROUGH */
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/usb/core/usb.c	Tue Oct 15 20:29:17 2002
@@ -50,6 +50,9 @@
 extern void usb_major_cleanup(void);
 
 
+int nousb;		/* Disable USB when built into kernel image */
+			/* Not honored on modular build */
+
 
 static int generic_probe (struct device *dev)
 {
@@ -167,6 +170,9 @@
 {
 	int retval = 0;
 
+	if (nousb)
+		return -ENODEV;
+
 	new_driver->driver.name = (char *)new_driver->name;
 	new_driver->driver.bus = &usb_bus_type;
 	new_driver->driver.probe = usb_device_probe;
@@ -1338,11 +1344,37 @@
 	.hotplug =	usb_hotplug,
 };
 
+#ifndef MODULE
+
+static int __init usb_setup_disable(char *str)
+{
+	nousb = 1;
+	return 1;
+}
+
+/* format to disable USB on kernel command line is: nousb */
+__setup("nousb", usb_setup_disable);
+
+#endif
+
+/*
+ * for external read access to <nousb>
+ */
+int usb_disabled(void)
+{
+	return nousb;
+}
+
 /*
  * Init
  */
 static int __init usb_init(void)
 {
+	if (nousb) {
+		info("USB support disabled\n");
+		return 0;
+	}
+
 	bus_register(&usb_bus_type);
 	usb_major_init();
 	usbfs_init();
@@ -1358,6 +1390,10 @@
  */
 static void __exit usb_exit(void)
 {
+	/* This will matter if shutdown/reboot does exitcalls. */
+	if (nousb)
+		return;
+
 	remove_driver(&usb_generic_driver);
 	usb_major_cleanup();
 	usbfs_cleanup();
@@ -1377,6 +1413,7 @@
 
 EXPORT_SYMBOL(usb_register);
 EXPORT_SYMBOL(usb_deregister);
+EXPORT_SYMBOL(usb_disabled);
 
 EXPORT_SYMBOL(usb_device_probe);
 EXPORT_SYMBOL(usb_device_remove);
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/usb/host/ehci-hcd.c	Tue Oct 15 20:29:17 2002
@@ -985,6 +985,9 @@
 static int __init init (void) 
 {
 	dbg (DRIVER_INFO);
+	if (usb_disabled())
+		return -ENODEV;
+
 	dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd",
 		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
 		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
diff -Nru a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c
--- a/drivers/usb/host/hc_sl811.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/usb/host/hc_sl811.c	Tue Oct 15 20:29:19 2002
@@ -1321,6 +1321,9 @@
 	int ret;
 
 	DBGFUNC ("Enter hci_hcd_init\n");
+	if (usb_disabled())
+		return -ENODEV;
+
 	ret = hc_found_hci (base_addr, data_reg_addr, irq);
 
 	return ret;
diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
--- a/drivers/usb/host/ohci-pci.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/usb/host/ohci-pci.c	Tue Oct 15 20:29:19 2002
@@ -365,6 +365,9 @@
 static int __init ohci_hcd_pci_init (void) 
 {
 	dbg (DRIVER_INFO " (PCI)");
+	if (usb_disabled())
+		return -ENODEV;
+
 	dbg ("block sizes: ed %d td %d",
 		sizeof (struct ed), sizeof (struct td));
 	return pci_module_init (&ohci_pci_driver);
diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
--- a/drivers/usb/host/ohci-sa1111.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/usb/host/ohci-sa1111.c	Tue Oct 15 20:29:17 2002
@@ -23,6 +23,8 @@
 #error "This file is SA-1111 bus glue.  CONFIG_SA1111 must be defined."
 #endif
 
+extern int usb_disabled(void);
+
 /*-------------------------------------------------------------------------*/
 
 static void sa1111_start_hc(struct sa1111_dev *dev)
@@ -354,6 +356,9 @@
 	struct sa1111_dev *dev = SA1111_DEV(_dev);
 	struct usb_hcd *hcd = NULL;
 	int ret;
+
+	if (usb_disabled())
+		return -ENODEV;
 
 	ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev);
 
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Tue Oct 15 20:29:21 2002
+++ b/drivers/usb/host/uhci-hcd.c	Tue Oct 15 20:29:21 2002
@@ -2484,6 +2484,9 @@
 
 	info(DRIVER_DESC " " DRIVER_VERSION);
 
+	if (usb_disabled())
+		return -ENODEV;
+
 	if (debug) {
 		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
 		if (!errbuf)
diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
--- a/drivers/usb/input/wacom.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/usb/input/wacom.c	Tue Oct 15 20:29:12 2002
@@ -402,7 +402,6 @@
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct usb_endpoint_descriptor *endpoint;
 	struct wacom *wacom;
-	char rep_data[2] = {0x02, 0x02};
 	char path[64];
 
 	if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL)))
diff -Nru a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile
--- a/drivers/usb/media/Makefile	Tue Oct 15 20:29:11 2002
+++ b/drivers/usb/media/Makefile	Tue Oct 15 20:29:11 2002
@@ -14,6 +14,6 @@
 obj-$(CONFIG_USB_PWC)		+= pwc.o
 obj-$(CONFIG_USB_SE401)		+= se401.o
 obj-$(CONFIG_USB_STV680)	+= stv680.o
-obj-$(CONFIG_USB_VICAM)		+= vicam.o
+obj-$(CONFIG_USB_VICAM)		+= vicam.o usbvideo.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
--- a/drivers/usb/media/vicam.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/media/vicam.c	Tue Oct 15 20:29:16 2002
@@ -1,102 +1,356 @@
-/* -*- linux-c -*-
- * USB ViCAM driver
- *
- * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx)
- * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License as
- *      published by the Free Software Foundation; either version 2 of
- *      the License, or (at your option) any later version.
- *
- * This driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB
- *
- * Thanks to Greg Kroah-Hartman for the USB Skeleton driver
- *
- * TODO:
- *	- find out the ids for the Vista Imaging ViCAM
+/*
+ * USB ViCam WebCam driver
+ * Copyright (c) 2002 Joe Burks (jburks@wavicle.org)
  *
- * History:
+ * Supports 3COM HomeConnect PC Digital WebCam
  *
- * 2001_07_07 - 0.1 - christopher: first version
- * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try 
- 			while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done
-		      yep, moving pictures.
- * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun,
- 			get gqcam-0.9, compile it and run. Better than dd ;-).
- * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional)
- 			kill update_params if it does not seem to work for you.
- * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This source code is based heavily on the CPiA webcam driver which was
+ * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
+ *
+ * Portions of this code were also copied from usbvideo.c
+ *
+ * Special thanks to the the whole team at Sourceforge for help making
+ * this driver become a reality.  Notably:
+ * Andy Armstrong who reverse engineered the color encoding and
+ * Pavel Machek and Chris Cheney who worked on reverse engineering the
+ *    camera controls and wrote the first generation driver.
+ * */
 
- *
- * FIXME: It crashes on rmmod with camera plugged.
- */
-#define DEBUG 1
-
-#include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
+#include <linux/wrapper.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
+#include <linux/init.h>
+#include <linux/videodev.h>
 #include <linux/usb.h>
-
-#include <asm/io.h>
-#include <linux/wrapper.h>
 #include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include "usbvideo.h"
 
-#include <linux/videodev.h>
+// #define VICAM_DEBUG
 
-#include "vicam.h"
-#include "vicamurbs.h"
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(a)
+#endif
+
+#ifndef bool
+#define bool int
+#endif
+
+#ifdef VICAM_DEBUG
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
+#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
+#else
+#define DBG(fmn,args...) do {} while(0)
+#endif
 
 /* Version Information */
-#define DRIVER_VERSION "v0"
-#define DRIVER_AUTHOR "Christopher L Cheney <ccheney@cheney.cx>, Pavel Machek <pavel@suse.cz>"
-#define DRIVER_DESC "USB ViCAM Driver"
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
+#define DRIVER_DESC "ViCam WebCam Driver"
 
 /* Define these values to match your device */
-#define USB_VICAM_VENDOR_ID	0x04C1
-#define USB_VICAM_PRODUCT_ID	0x009D
+#define USB_VICAM_VENDOR_ID	0x04c1
+#define USB_VICAM_PRODUCT_ID	0x009d
 
-/* table of devices that work with this driver */
-static struct usb_device_id vicam_table [] = {
-	{ USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) },
-	{ }					/* Terminating entry */
-};
+#define VICAM_BYTES_PER_PIXEL 3
+#define VICAM_MAX_READ_SIZE (512*242+128)
+#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
+#define VICAM_FRAMES 2
+
+/* Not sure what all the bytes in these char
+ * arrays do, but they're necessary to make
+ * the camera work.
+ */
 
-MODULE_DEVICE_TABLE (usb, vicam_table);
+static unsigned char setup1[] = {
+	0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67,
+	0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00,
+	0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17,
+	0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00,
+	0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
+};
 
-static int video_nr = -1; 		/* next avail video device */
-static struct usb_driver vicam_driver;
+static unsigned char setup2[] = {
+	0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00,
+	0x00, 0x00
+};
 
-static char *buf, *buf2;
-static volatile int change_pending = 0; 
+static unsigned char setup3[] = {
+	0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00
+};
 
-static int vicam_parameters(struct usb_vicam *vicam);
+static unsigned char setup4[] = {
+	0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07,
+	0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00,
+	0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00,
+	0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07,
+	0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00,
+	0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00,
+	0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07,
+	0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF,
+	0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0,
+	0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07,
+	0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00,
+	0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0,
+	0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1,
+	0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09,
+	0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00,
+	0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF,
+	0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02,
+	0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00,
+	0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF,
+	0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00,
+	0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00,
+	0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05,
+	0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA,
+	0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06,
+	0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF,
+	0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05,
+	0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01,
+	0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09,
+	0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06,
+	0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05,
+	0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA,
+	0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05,
+	0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+	0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00,
+	0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF,
+	0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00,
+	0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0,
+	0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06,
+	0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00,
+	0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07,
+	0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF,
+	0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00,
+	0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+	0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57,
+	0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57,
+	0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00,
+	0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0,
+	0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B,
+	0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06,
+	0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06,
+	0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E,
+	0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00,
+	0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05,
+	0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00,
+	0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06,
+	0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF,
+	0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0,
+	0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
+	0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05,
+	0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF,
+	0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0,
+	0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07,
+	0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07,
+	0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF,
+	0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF,
+	0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+	0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1,
+	0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+	0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00,
+	0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07,
+	0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+	0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07,
+	0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00,
+	0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06,
+	0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67,
+	0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8,
+	0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0,
+	0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF,
+	0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02,
+	0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+	0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06,
+	0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05,
+	0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+	0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00,
+	0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06,
+	0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07,
+	0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05,
+	0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05,
+	0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80,
+	0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04,
+	0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF,
+	0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06,
+	0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00,
+	0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05,
+	0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07,
+	0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07,
+	0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07,
+	0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF,
+	0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07,
+	0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06,
+	0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05,
+	0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07,
+	0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00,
+	0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00,
+	0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77,
+	0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04,
+	0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0,
+	0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1,
+	0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07,
+	0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+	0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
+	0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
+	0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77,
+	0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1,
+	0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07,
+	0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06,
+	0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07,
+	0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07,
+	0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07,
+	0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00,
+	0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00,
+	0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
+	0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F,
+	0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00,
+	0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00,
+	0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA,
+	0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
+	0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06,
+	0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B,
+	0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09,
+	0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05,
+	0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07,
+	0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00,
+	0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF,
+	0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05,
+	0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00,
+	0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00,
+	0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00,
+	0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF,
+	0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09,
+	0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
+	0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00,
+	0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00,
+	0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00,
+	0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05,
+	0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0,
+	0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67,
+	0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87,
+	0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9,
+	0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1,
+	0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF,
+	0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00,
+	0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0,
+	0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87,
+	0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF,
+	0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67,
+	0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
+	0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+	0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67,
+	0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
+	0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01,
+	0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00,
+	0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF,
+	0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0,
+	0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67,
+	0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09,
+	0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
+	0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA,
+	0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87,
+	0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+	0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+	0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07,
+	0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80,
+	0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02,
+	0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09,
+	0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
 
-/******************************************************************************
- *
- *  Memory management functions
- *
- *  Taken from bttv-drivers.c 2.4.7-pre3
- *
- ******************************************************************************/
+static unsigned char setup5[] = {
+	0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00,
+	0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00,
+	0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00,
+	0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00,
+	0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00,
+	0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00,
+	0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00,
+	0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01,
+	0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01,
+	0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01,
+	0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01,
+	0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01,
+	0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01,
+	0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01,
+	0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01,
+	0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02,
+	0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02,
+	0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02,
+	0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02,
+	0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02,
+	0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02,
+	0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02,
+	0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02,
+	0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03,
+	0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03,
+	0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03,
+	0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03,
+	0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03,
+	0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03,
+	0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03,
+	0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04,
+	0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04,
+	0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04,
+	0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04,
+	0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04,
+	0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04,
+	0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04,
+	0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05,
+	0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
+};
 
-/* Here we want the physical address of the memory.
- * This is used when initializing the contents of the area.
- */
-static inline unsigned long kvirt_to_pa(unsigned long adr)
+static unsigned long kvirt_to_pa(unsigned long adr)
 {
 	unsigned long kva, ret;
 
@@ -106,526 +360,734 @@
 	return ret;
 }
 
-static void * rvmalloc(unsigned long size)
+/* rvmalloc / rvfree copied from usbvideo.c
+ *
+ * Not sure why these are not yet non-statics which I can reference through
+ * usbvideo.h the same as it is in 2.4.20.  I bet this will get fixed sometime
+ * in the future.
+ * 
+*/
+static void *rvmalloc(unsigned long size)
 {
-	void * mem;
+	void *mem;
 	unsigned long adr;
 
-	size=PAGE_ALIGN(size);
-	mem=vmalloc_32(size);
-	if (mem)
-	{
-		memset(mem, 0, size); /* Clear the ram out, no junk to the user */
-		adr=(unsigned long) mem;
-		while (size > 0)
-		{
-			mem_map_reserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
+	size = PAGE_ALIGN(size);
+	mem = vmalloc_32(size);
+	if (!mem)
+		return NULL;
+
+	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+	adr = (unsigned long) mem;
+	while (size > 0) {
+		mem_map_reserve(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
 	}
+
 	return mem;
 }
 
-static void rvfree(void * mem, unsigned long size)
+static void rvfree(void *mem, unsigned long size)
 {
 	unsigned long adr;
 
-	if (mem)
-	{
-		adr=(unsigned long) mem;
-		while ((long) size > 0)
-		{
-			mem_map_unreserve(vmalloc_to_page((void *)adr));
-			adr+=PAGE_SIZE;
-			size-=PAGE_SIZE;
-		}
-		vfree(mem);
+	if (!mem)
+		return;
+
+	adr = (unsigned long) mem;
+	while ((long) size > 0) {
+		mem_map_unreserve(vmalloc_to_page((void *)adr));
+		adr += PAGE_SIZE;
+		size -= PAGE_SIZE;
 	}
+	vfree(mem);
 }
+	
+struct vicam_camera {
+	u16 shutter_speed;	// capture shutter speed
+	u16 gain;		// capture gain
 
-/******************************************************************************
- *
- *  Foo Bar
- *
- ******************************************************************************/
+	u8 *raw_image;		// raw data captured from the camera
+	u8 *framebuf;		// processed data in RGB24 format
 
-/**
- *	usb_vicam_debug_data
- */
-static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data)
-{
-	int i;
+	struct video_device vdev;	// v4l video device
+	struct usb_device *udev;	// usb device
 
-	if (!debug)
-		return;
+	struct semaphore busy_lock;	// guard against SMP multithreading
 
-	printk (KERN_DEBUG __FILE__": %s - length = %d, data = ",
-		function, size);
-	for (i = 0; i < size; ++i) {
-		printk ("%.2x ", data[i]);
-	}
-	printk ("\n");
-}
+	bool is_initialized;
+	u8 open_count;
+	u8 bulkEndpoint;
+	bool needsDummyRead;
 
-/*****************************************************************************
- *
- *  Send command to vicam
- *
- *****************************************************************************/
+	u32 framebuf_size;	// # of valid bytes in framebuf
+	u32 framebuf_read_start;	// position in frame buf that a read is happening at.
 
-static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req,
-	unsigned short value, unsigned char *cp, int size)
-{
-	int ret;
-	unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL);
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc_entry;
+#endif
+
+};
+
+static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
+static void vicam_disconnect(struct usb_interface *intf);
+static void read_frame(struct vicam_camera *cam, int framenum);
+
+static int
+send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index,
+		 unsigned char *cp, u16 size)
+{
+	int status;
+
+	// for reasons not yet known to me, you can't send USB control messages
+	// with data in the module (if you are compiled as a module).  Whatever
+	// the reason, copying it to memory allocated as kernel memory then
+	// doing the usb control message fixes the problem.
 
-	/* Needs to return data I think, works for sending though */
+	unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL);
 	memcpy(transfer_buffer, cp, size);
-	
-	ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ);
+
+	status = usb_control_msg(udev,
+				 usb_sndctrlpipe(udev, 0),
+				 request,
+				 USB_DIR_OUT | USB_TYPE_VENDOR |
+				 USB_RECIP_DEVICE, value, index,
+				 transfer_buffer, size, HZ);
 
 	kfree(transfer_buffer);
-	if (ret)
-		printk("vicam: error: %d\n", ret);
-	mdelay(100);
-	return ret;
-}
 
+	if (status < 0) {
+		printk(KERN_INFO "Failed sending control message, error %d.\n",
+		       status);
+	}
+
+	return status;
+}
+
+static int
+initialize_camera(struct vicam_camera *cam)
+{
+	struct usb_device *udev = cam->udev;
+	int status;
+
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0)
+		return status;
+	if ((status =
+	     send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0)
+		return status;
 
-/*****************************************************************************
- *
- *  Video4Linux Helpers
- * 
- *****************************************************************************/
+	return 0;
+}
 
-static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b)
+static int
+set_camera_power(struct vicam_camera *cam, int state)
 {
-	dbg("vicam_get_capability");
+	int status;
 
-	strcpy(b->name, vicam->camera_name);
-	b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME;
-	b->channels = 1;
-	b->audios = 0;
+	if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0)
+		return status;
 
-	b->maxwidth = vicam->width[vicam->sizes-1];
-	b->maxheight = vicam->height[vicam->sizes-1];
-	b->minwidth = vicam->width[0];
-	b->minheight = vicam->height[0];
+	if (state) {
+		send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0);
+	}
 
 	return 0;
 }
-		
-static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v)
+
+static int
+vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long ul_arg)
 {
-	dbg("vicam_get_channel");
+	void *arg = (void *)ul_arg;
+	struct vicam_camera *cam = file->private_data;
+	int retval = 0;
 
-	if (v->channel != 0)
-		return -EINVAL;
- 
-	v->flags = 0;
-	v->tuners = 0;
-	v->type = VIDEO_TYPE_CAMERA;
-	strcpy(v->name, "Camera");
+	if (!cam)
+		return -ENODEV;
 
-	return 0;
-} 
-		
-static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v)
-{
-	dbg("vicam_set_channel");
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
 
-	if (v->channel != 0)
-		return -EINVAL;
-	
-	return 0;
-}
-		
-static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm)
-{
-	int i;
+	switch (ioctlnr) {
+		/* query capabilites */
+	case VIDIOCGCAP:
+		{
+			struct video_capability b;
 
-	dbg("vicam_get_mmapbuffer");
+			DBG("VIDIOCGCAP\n");
+			strcpy(b.name, "ViCam-based Camera");
+			b.type = VID_TYPE_CAPTURE;
+			b.channels = 1;
+			b.audios = 0;
+			b.maxwidth = 320;	/* VIDEOSIZE_CIF */
+			b.maxheight = 240;
+			b.minwidth = 320;	/* VIDEOSIZE_48_48 */
+			b.minheight = 240;
 
-	memset(vm, 0, sizeof(vm));
-	vm->size = VICAM_NUMFRAMES * vicam->maxframesize;
-	vm->frames = VICAM_NUMFRAMES;
+			if (copy_to_user(arg, &b, sizeof (b)))
+				retval = -EFAULT;
 
-	for (i=0; i<VICAM_NUMFRAMES; i++)
-		vm->offsets[i] = vicam->maxframesize * i;
+			break;
+		}
+		/* get/set video source - we are a camera and nothing else */
+	case VIDIOCGCHAN:
+		{
+			struct video_channel v;
 
-	return 0;
-}
+			DBG("VIDIOCGCHAN\n");
+			if (copy_from_user(&v, arg, sizeof (v))) {
+				retval = -EFAULT;
+				break;
+			}
+			if (v.channel != 0) {
+				retval = -EINVAL;
+				break;
+			}
+
+			v.channel = 0;
+			strcpy(v.name, "Camera");
+			v.tuners = 0;
+			v.flags = 0;
+			v.type = VIDEO_TYPE_CAMERA;
+			v.norm = 0;
+
+			if (copy_to_user(arg, &v, sizeof (v)))
+				retval = -EFAULT;
+			break;
+		}
 
-static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p)
-{
-	dbg("vicam_get_picture");
+	case VIDIOCSCHAN:
+		{
+			int v;
 
-	/* This is probably where that weird 0x56 call goes */
-	p->brightness = vicam->win.brightness;
-	p->hue = vicam->win.hue;
-	p->colour = vicam->win.colour;
-	p->contrast = vicam->win.contrast;
-	p->whiteness = vicam->win.whiteness;
-	p->depth = vicam->win.depth;
-	p->palette = vicam->win.palette;
+			if (copy_from_user(&v, arg, sizeof (v)))
+				retval = -EFAULT;
+			DBG("VIDIOCSCHAN %d\n", v);
 
-	return 0;
-}
+			if (retval == 0 && v != 0)
+				retval = -EINVAL;
 
-static void synchronize(struct usb_vicam *vicam)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	change_pending = 1;
-	set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue(&vicam->wait, &wait);
-	if (change_pending)
-		schedule();
-	remove_wait_queue(&vicam->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
-	mdelay(10);
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-	mdelay(10);
-}
-
-static void params_changed(struct usb_vicam *vicam)
-{
-#if 1
-	synchronize(vicam);
-	mdelay(10);
-	vicam_parameters(vicam);
-	printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL));
-#endif
-}
+			break;
+		}
 
-static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p)
-{
-	int changed = 0;
-	info("vicam_set_picture (%d)", p->brightness);
+		/* image properties */
+	case VIDIOCGPICT:
+		{
+			struct video_picture vp;
+			DBG("VIDIOCGPICT\n");
+			memset(&vp, 0, sizeof (struct video_picture));
+			vp.brightness = cam->gain << 8;
+			vp.depth = 24;
+			vp.palette = VIDEO_PALETTE_RGB24;
+			if (copy_to_user
+			    (arg, &vp, sizeof (struct video_picture)))
+				retval = -EFAULT;
+			break;
+		}
 
+	case VIDIOCSPICT:
+		{
+			struct video_picture *vp = (struct video_picture *) arg;
 
-#define SET(x) \
-	if (vicam->win.x != p->x) \
-		vicam->win.x = p->x, changed = 1;
-	SET(brightness);
-	SET(hue);
-	SET(colour);
-	SET(contrast);
-	SET(whiteness);
-	SET(depth);
-	SET(palette);
-	if (changed)
-		params_changed(vicam);
+			DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth,
+			    vp->palette);
 
-	return 0;
-	/* Investigate what should be done maybe 0x56 type call */
-	if (p->depth != 8) return 1;
-	if (p->palette != VIDEO_PALETTE_GREY) return 1;
+			cam->gain = vp->brightness >> 8;
 
-	return 0;
-}
+			if (vp->depth != 24
+			    || vp->palette != VIDEO_PALETTE_RGB24)
+				retval = -EINVAL;
 
-/* FIXME - vicam_sync_frame - important */
-static int vicam_sync_frame(struct usb_vicam *vicam, int frame)
-{
-	dbg("vicam_sync_frame");
+			break;
+		}
 
-	if(frame <0 || frame >= VICAM_NUMFRAMES)
-		return -EINVAL;
+		/* get/set capture window */
+	case VIDIOCGWIN:
+		{
+			struct video_window vw;
+			vw.x = 0;
+			vw.y = 0;
+			vw.width = 320;
+			vw.height = 240;
+			vw.chromakey = 0;
+			vw.flags = 0;
+			vw.clips = NULL;
+			vw.clipcount = 0;
+
+			DBG("VIDIOCGWIN\n");
+
+			if (copy_to_user
+			    ((void *) arg, (void *) &vw, sizeof (vw)))
+				retval = -EFAULT;
+
+			// I'm not sure what the deal with a capture window is, it is very poorly described
+			// in the doc.  So I won't support it now.
+			break;
+		}
 
-	/* Probably need to handle various cases */
-/*	ret=vicam_newframe(vicam, frame);
-	vicam->frame[frame].grabstate=FRAME_UNUSED;
-*/
-	return 0;
-}
-	
-static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw)
-{
-	dbg("vicam_get_window");
+	case VIDIOCSWIN:
+		{
 
-	vw->x = 0;
-	vw->y = 0;
-	vw->chromakey = 0;
-	vw->flags = 0;
-	vw->clipcount = 0;
-	vw->width = vicam->win.width;
-	vw->height = vicam->win.height;
+			struct video_window *vw = (struct video_window *) arg;
+			DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height);
 
-	return 0;
-}
+			if ( vw->width != 320 || vw->height != 240 )
+				retval = -EFAULT;
+			
+			break;
+		}
 
-static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw)
-{
-	info("vicam_set_window");
-		
-	if (vw->flags)
-		return -EINVAL;
-	if (vw->clipcount)
-		return -EINVAL;
+		/* mmap interface */
+	case VIDIOCGMBUF:
+		{
+			struct video_mbuf vm;
+			int i;
 
-	if (vicam->win.width == vw->width && vicam->win.height == vw->height)
-		return 0;
+			DBG("VIDIOCGMBUF\n");
+			memset(&vm, 0, sizeof (vm));
+			vm.size =
+			    VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
+			vm.frames = VICAM_FRAMES;
+			for (i = 0; i < VICAM_FRAMES; i++)
+				vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
+
+			if (copy_to_user
+			    ((void *) arg, (void *) &vm, sizeof (vm)))
+				retval = -EFAULT;
 
-	/* Pick largest mode that is smaller than specified res */
-	/* If specified res is too small reject                 */
+			break;
+		}
+
+	case VIDIOCMCAPTURE:
+		{
+			struct video_mmap vm;
+			// int video_size;
 
-	/* Add urb send to device... */
+			if (copy_from_user
+			    ((void *) &vm, (void *) arg, sizeof (vm))) {
+				retval = -EFAULT;
+				break;
+			}
+
+			DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
+
+			if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
+				retval = -EINVAL;
+
+			// in theory right here we'd start the image capturing
+			// (fill in a bulk urb and submit it asynchronously)
+			//
+			// Instead we're going to do a total hack job for now and
+			// retrieve the frame in VIDIOCSYNC
 
-	vicam->win.width = vw->width;
-	vicam->win.height = vw->height;
-	params_changed(vicam);
+			break;
+		}
 
-	return 0;
+	case VIDIOCSYNC:
+		{
+			int frame;
+
+			if (copy_from_user((void *) &frame, arg, sizeof (int))) {
+				retval = -EFAULT;
+				break;
+			}
+			DBG("VIDIOCSYNC: %d\n", frame);
+
+			read_frame(cam, frame);
+
+			break;
+		}
+
+		/* pointless to implement overlay with this camera */
+	case VIDIOCCAPTURE:
+	case VIDIOCGFBUF:
+	case VIDIOCSFBUF:
+	case VIDIOCKEY:
+		retval = -EINVAL;
+		break;
+
+		/* tuner interface - we have none */
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	case VIDIOCGFREQ:
+	case VIDIOCSFREQ:
+		retval = -EINVAL;
+		break;
+
+		/* audio interface - we have none */
+	case VIDIOCGAUDIO:
+	case VIDIOCSAUDIO:
+		retval = -EINVAL;
+		break;
+	default:
+		retval = -ENOIOCTLCMD;
+		break;
+	}
+
+	up(&cam->busy_lock);
+	return retval;
 }
 
-/* FIXME - vicam_mmap_capture - important */
-static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm)
+static int
+vicam_open(struct inode *inode, struct file *file)
 {
-	dbg("vicam_mmap_capture");
+	struct video_device *dev = video_devdata(file);
+	struct vicam_camera *cam =
+	    (struct vicam_camera *) dev->priv;
+	DBG("open\n");
 
-	/* usbvideo.c looks good for using here */
+	if (!cam) {
+		printk(KERN_ERR
+		       "vicam video_device improperly initialized");
+	}
 
-	/* 
-	if (vm->frame >= VICAM_NUMFRAMES)
-		return -EINVAL;
-	if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED)
+	down_interruptible(&cam->busy_lock);
+
+	if (cam->open_count > 0) {
+		printk(KERN_INFO
+		       "vicam_open called on already opened camera");
+		up(&cam->busy_lock);
 		return -EBUSY;
-	vicam->frame[vm->frame].grabstate=FRAME_READY;
-	*/
+	}
 
-	/* No need to vicam_set_window here according to Alan */
+	if (!cam->raw_image) {
+		cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
+		if (!cam->raw_image) {
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
+	}
 
-	/*
-	if (!vicam->streaming)
-		vicam_start_stream(vicam);
-	*/
+	if (!cam->framebuf) {
+		cam->framebuf =
+		    rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+		if (!cam->framebuf) {
+			kfree(cam->raw_image);
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
+	}
+	// First upload firmware, then turn the camera on
 
-	/* set frame as ready */
+	if (!cam->is_initialized) {
+		initialize_camera(cam);
 
-	return 0;
-}
+		cam->is_initialized = 1;
+	}
 
-/*****************************************************************************
- *
- *  Video4Linux
- * 
- *****************************************************************************/
+	set_camera_power(cam, 1);
 
-static int vicam_v4l_open(struct inode *inode, struct file *file)
-{
-	struct video_device *vdev = video_devdata(file);
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
-	int err = 0;
-	
-	dbg("vicam_v4l_open");
-	down(&vicam->sem);
+	cam->needsDummyRead = 1;
+	cam->open_count++;
 
-	vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES);
-	if (vicam->open_count) {
-		err = -EBUSY;
-	} else if (!vicam->fbuf) {
-		err =- ENOMEM;
-	} else {
-#ifdef BLINKING
-		vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-		info ("led on");
-		vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-#endif
-		vicam->open_count++;
-		file->private_data = vdev;
-	}
+	up(&cam->busy_lock);
 
-	up(&vicam->sem);
-	return err;
+	file->private_data = cam;	
+	
+	return 0;
 }
 
-static int vicam_v4l_close(struct inode *inode, struct file *file)
+static int 
+vicam_close(struct inode *inode, struct file *file)
 {
-	struct video_device *vdev = file->private_data;
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
-
-	dbg("vicam_v4l_close");
-	
-	down(&vicam->sem);
+	struct vicam_camera *cam = file->private_data;
+	DBG("close\n");
+	set_camera_power(cam, 0);
 
-#ifdef BLINKING
-	info ("led off");
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-//	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on
-#endif
+	cam->open_count--;
 
-	rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES);
-	vicam->fbuf = 0;
-	vicam->open_count=0;
-	file->private_data = NULL;
-
-	up(&vicam->sem);
-	/* Why does se401.c have a usbdevice check here? */
-	/* If device is unplugged while open, I guess we only may unregister now */
 	return 0;
 }
 
-static int vicam_v4l_read(struct file *file, char *user_buf,
-			  size_t buflen, loff_t *ppos)
+inline int pin(int x)
 {
-	struct video_device *vdev = file->private_data;
-	//struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+	return((x > 255) ? 255 : ((x < 0) ? 0 : x));
+}
 
-	dbg("vicam_v4l_read(%d)", buflen);
+inline void writepixel(char *rgb, int Y, int Cr, int Cb)
+{
+	Y = 1160 * (Y - 16);
+	
+	rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 );
+	rgb[1] = pin( ( ( Y - (  392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 );
+	rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 );
+}
 
-	if (!vdev || !buf)
-		return -EFAULT;
+#define DATA_HEADER_SIZE 64
 
-	if (copy_to_user(user_buf, buf2, buflen))
-		return -EFAULT;
-	return buflen;
-}
+// --------------------------------------------------------------------------------
+//	vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
+//
+//   Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
+// --------------------------------------------------------------------------------
 
-static int vicam_v4l_do_ioctl(struct inode *inode, struct file *file,
-			      unsigned int cmd, void *arg)
+void vicam_decode_color( char *data, char *rgb)
 {
-	struct video_device *vdev = file->private_data;
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
-	int ret = -EL3RST;
+	int x,y;
+	int Cr, Cb;
+	int sign;
+	int prevX, nextX, prevY, nextY;
+	int skip;
+	unsigned char *src;
+	unsigned char *dst;
 
-	if (!vicam->udev)
-		return -EIO;
+	prevY = 512;
+	nextY = 512;
 
-	down(&vicam->sem);
+	src = data + DATA_HEADER_SIZE;
+	dst = rgb;
 
-	switch (cmd) {
-	case VIDIOCGCAP:
-	{
-		struct video_capability *b = arg;
-		ret = vicam_get_capability(vicam,b);
-		dbg("name %s",b->name);
-		break;
-	}
-	case VIDIOCGFBUF:
-	{
-		struct video_buffer *vb = arg;
-		info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param");
-		/* frame buffer not supported, not used */
-		memset(vb, 0, sizeof(*vb));
-		ret = 0;
-		break;
-	}
-	case VIDIOCGWIN:
+	for(y = 1; y < 241; y += 2)
 	{
-		struct video_window *vw = arg;
-		ret = vicam_get_window(vicam, vw);
-		break;
-	}
-	case VIDIOCSWIN:
-	{
-		struct video_window *vw = arg;
-		ret = vicam_set_window(vicam, vw);
-		break;
-	}
-	case VIDIOCGCHAN:
-	{
-		struct video_channel *v = arg;
+		// even line
+		sign = 1;
+		prevX = 1;
+		nextX = 1;
 
-		ret = vicam_get_channel(vicam,v);
-		break;
-	}
-	case VIDIOCSCHAN:
-	{
-		struct video_channel *v = arg;
-		ret = vicam_set_channel(vicam,v);
-		break;
- 	}
-	case VIDIOCGPICT:
-	{
-		struct video_picture *p = arg;
-		ret = vicam_get_picture(vicam,p);
-		break;
-	}
-	case VIDIOCSPICT:
-	{
-		struct video_picture *p = arg;
-		ret = vicam_set_picture(vicam,p);
-		break;
-	}
-	case VIDIOCGMBUF:
-	{
-		struct video_mbuf *vm = arg;
-		ret = vicam_get_mmapbuffer(vicam,vm);
-		break;
-	}
-	case VIDIOCMCAPTURE:
-	{
-		struct video_mmap *vm = arg;
-		ret = vicam_mmap_capture(vicam,vm);
-		break;
+		skip = 0;
+
+		dst = rgb + (y-1)*320*3;
+		
+		for(x = 0; x < 512; x++)
+		{
+			if(x == 512-1)
+				nextX = -1;
+
+			Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1;
+			Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2;
+
+			writepixel(
+					dst + ((x*5)>>3)*3,
+					src[0] + (sign * (Cr >> 1)),
+					Cr,
+					Cb);
+
+			src++;
+			sign *= -1;
+			prevX = -1;
+		}
+
+		prevY = -512;
+
+		if(y == (242 - 2))
+			nextY = -512;
+
+		// odd line
+		sign = 1;
+		prevX = 1;
+		nextX = 1;
+
+		skip = 0;
+
+		dst = rgb + (y)*320*3;
+		
+		for(x = 0; x < 512; x++)
+		{
+			if(x == 512-1)
+				nextX = -1;
+			
+			Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2;
+			Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1;
+
+			writepixel(
+					dst + ((x * 5)>>3)*3,
+					src[0] - (sign * (Cb >> 1)),
+					Cr,
+					Cb);
+
+			src++;
+			sign *= -1;
+			prevX = -1;
+		}
 	}
-	case VIDIOCSYNC:
-	{
-		int *frame = arg;
-		ret = vicam_sync_frame(vicam,*frame);
-		break;
+}
+
+static void
+read_frame(struct vicam_camera *cam, int framenum)
+{
+	unsigned char request[16];
+	int realShutter;
+	int n;
+	int actual_length;
+
+	memset(request, 0, 16);
+	request[0] = cam->gain;	// 0 = 0% gain, FF = 100% gain
+
+	request[1] = 0;	// 512x242 capture
+
+	request[2] = 0x90;	// the function of these two bytes
+	request[3] = 0x07;	// is not yet understood
+
+	if (cam->shutter_speed > 60) {
+		// Short exposure
+		realShutter =
+		    ((-15631900 / cam->shutter_speed) + 260533) / 1000;
+		request[4] = realShutter & 0xFF;
+		request[5] = (realShutter >> 8) & 0xFF;
+		request[6] = 0x03;
+		request[7] = 0x01;
+	} else {
+		// Long exposure
+		realShutter = 15600 / cam->shutter_speed - 1;
+		request[4] = 0;
+		request[5] = 0;
+		request[6] = realShutter & 0xFF;
+		request[7] = realShutter >> 8;
+	}
+
+	// Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
+	request[8] = 0;
+	// bytes 9-15 do not seem to affect exposure or image quality
+
+	n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16);
+
+	if (n < 0) {
+		printk(KERN_ERR
+		       " Problem sending frame capture control message");
+		return;
 	}
 
-	case VIDIOCKEY:
-		ret = 0;
- 
-	case VIDIOCCAPTURE:
-	case VIDIOCSFBUF:
-	case VIDIOCGTUNER:
-	case VIDIOCSTUNER:
-	case VIDIOCGFREQ:
-	case VIDIOCSFREQ:
-	case VIDIOCGAUDIO:
-	case VIDIOCSAUDIO:
-	case VIDIOCGUNIT:
-		ret = -EINVAL;
+	n = usb_bulk_msg(cam->udev,
+			 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
+			 cam->raw_image,
+			 512 * 242 + 128, &actual_length, HZ*10);
 
-	default:
-	{
-		info("vicam_v4l_ioctl - %ui",cmd);
-		ret = -ENOIOCTLCMD;
+	if (n < 0) {
+		printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
+		       n);
 	}
-	} /* end switch */
 
-	up(&vicam->sem);
-        return ret;
+	vicam_decode_color(cam->raw_image,
+			 cam->framebuf +
+			 framenum * VICAM_MAX_FRAME_SIZE );
+
+	cam->framebuf_size =
+	    320 * 240 * VICAM_BYTES_PER_PIXEL;
+	cam->framebuf_read_start = 0;
+
+	return;
+
 }
 
-static int vicam_v4l_ioctl(struct inode *inode, struct file *file,
-			   unsigned int cmd, unsigned long arg)
+static int
+vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos )
 {
-	return video_usercopy(inode, file, cmd, arg, vicam_v4l_do_ioctl);
+	struct vicam_camera *cam = file->private_data;
+	DBG("read %d bytes.\n", (int) count);
+
+	if (!buf)
+		return -EINVAL;
+
+	if (!count)
+		return -EINVAL;
+
+	// This is some code that will hopefully allow us to do shell copies from
+	// the /dev/videoX to a file and have it actually work.
+	if (cam->framebuf_size != 0) {
+		if (cam->framebuf_read_start == cam->framebuf_size) {
+			cam->framebuf_size = cam->framebuf_read_start = 0;
+			return 0;
+		} else {
+			if (cam->framebuf_read_start + count <=
+			    cam->framebuf_size) {
+				// count does not exceed available bytes
+				copy_to_user(buf,
+					     (cam->framebuf) +
+					     cam->framebuf_read_start, count);
+				cam->framebuf_read_start += count;
+				return count;
+			} else {
+				count =
+				    cam->framebuf_size -
+				    cam->framebuf_read_start;
+				copy_to_user(buf,
+					     (cam->framebuf) +
+					     cam->framebuf_read_start, count);
+				cam->framebuf_read_start = cam->framebuf_size;
+				return count;
+			}
+		}
+	}
+
+	down_interruptible(&cam->busy_lock);
+
+	if (cam->needsDummyRead) {
+		read_frame(cam, 0);
+		cam->needsDummyRead = 0;
+	}
+	// read_frame twice because the camera doesn't seem to take the shutter speed for the first one.
+
+	read_frame(cam, 0);
+
+	if (count > cam->framebuf_size)
+		count = cam->framebuf_size;
+
+	copy_to_user(buf, cam->framebuf, count);
+
+	if (count != cam->framebuf_size)
+		cam->framebuf_read_start = count;
+	else
+		cam->framebuf_size = 0;
+
+	up(&cam->busy_lock);
+
+	return count;
 }
 
-static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma)
+
+static int
+vicam_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct video_device *vdev = file->private_data;
-	struct usb_vicam *vicam = (struct usb_vicam *)vdev;
+	// TODO: allocate the raw frame buffer if necessary
+	unsigned long page, pos;
 	unsigned long start = vma->vm_start;
 	unsigned long size  = vma->vm_end-vma->vm_start;
-	unsigned long page, pos;
+	struct vicam_camera *cam = file->private_data;
 
-	down(&vicam->sem);
-	
-	if (vicam->udev == NULL) {
-		up(&vicam->sem);
-		return -EIO;
-	}
-#if 0
-	if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
-		up(&vicam->sem);
-		return -EINVAL;
+	if (!cam)
+		return -ENODEV;
+
+	DBG("vicam_mmap: %ld\n", size);
+
+	/* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
+	 * to the size the application requested for mmap and it was screwing apps up.
+	 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
+	 return -EINVAL;
+	 */
+
+	/* make this _really_ smp-safe */
+	if (down_interruptible(&cam->busy_lock))
+		return -EINTR;
+
+	if (!cam->framebuf) {	/* we do lazy allocation */
+		cam->framebuf =
+		    rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+		if (!cam->framebuf) {
+			up(&cam->busy_lock);
+			return -ENOMEM;
+		}
 	}
-#endif
-	pos = (unsigned long)vicam->fbuf;
+
+	pos = (unsigned long)cam->framebuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
-		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
-			up(&vicam->sem);
+		if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
 			return -EAGAIN;
-		}
+
 		start += PAGE_SIZE;
 		pos += PAGE_SIZE;
 		if (size > PAGE_SIZE)
@@ -633,299 +1095,315 @@
 		else
 			size = 0;
 	}
-	up(&vicam->sem);
 
-        return 0;
+	up(&cam->busy_lock);
+
+	return 0;
 }
 
-/* FIXME - vicam_template - important */
-static struct file_operations vicam_fops = {
-	.owner =	THIS_MODULE,
-	.open =		vicam_v4l_open,
-	.release =     	vicam_v4l_close,
-	.read =		vicam_v4l_read,
-	.mmap =		vicam_v4l_mmap,
-	.ioctl =	vicam_v4l_ioctl,
-	.llseek =       no_llseek,
-};
-static struct video_device vicam_template = {
-	.owner =	THIS_MODULE,
-	.name =		"vicam USB camera",
-	.type =		VID_TYPE_CAPTURE,
-	.hardware =	VID_HARDWARE_SE401, /* need to ask for own id */
-	.fops =         &vicam_fops,
-};
+#ifdef CONFIG_PROC_FS
 
-/******************************************************************************
- *
- *  Some Routines
- *
- ******************************************************************************/
+static struct proc_dir_entry *vicam_proc_root = NULL;
 
-/*
-Flash the led
-vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-info ("led on");
-vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-info ("led off");
-vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0);
-vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0);
-*/
+static int
+vicam_read_proc(char *page, char **start, off_t off,
+		      int count, int *eof, void *data)
+{
+	char *out = page;
+	int len;
+	struct vicam_camera *cam = (struct vicam_camera *) data;
+
+	out +=
+	    sprintf(out, "Vicam-based WebCam Linux Driver.\n");
+	out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n");
+	out += sprintf(out, "vicam stats:\n");
+	out += sprintf(out, "    Shutter Speed: 1/%d\n", cam->shutter_speed);
+	out += sprintf(out, "             Gain: %d\n", cam->gain);
+
+	len = out - page;
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0)
+			return 0;
+	} else
+		len = count;
+
+	*start = page + off;
+	return len;
+}
+
+static int
+vicam_write_proc(struct file *file, const char *buffer,
+		       unsigned long count, void *data)
+{
+	char *in;
+	char *start;
+	struct vicam_camera *cam = (struct vicam_camera *) data;
+
+	in = kmalloc(count + 1, GFP_KERNEL);
+	if (!in)
+		return -ENOMEM;
+
+	in[count] = 0;		// I'm not sure buffer is gauranteed to be null terminated
+	// so I do this to make sure I have a null in there.
+
+	strncpy(in, buffer, count);
+
+	start = strstr(in, "gain=");
+	if (start
+	    && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
+		cam->gain = simple_strtoul(start + 5, NULL, 10);
+
+	start = strstr(in, "shutter=");
+	if (start
+	    && (start == in || *(start - 1) == ' ' || *(start - 1) == ','))
+		cam->shutter_speed = simple_strtoul(start + 8, NULL, 10);
+
+	kfree(in);
+	return count;
+}
 
-static void vicam_bulk(struct urb *urb)
+void
+vicam_create_proc_root(void)
 {
-	struct usb_vicam *vicam = urb->context;
+	vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0);
 
-	/*	if (!vicam || !vicam->dev || !vicam->used)
-		return;
-	*/
+	if (vicam_proc_root)
+		vicam_proc_root->owner = THIS_MODULE;
+	else
+		printk(KERN_ERR
+		       "could not create /proc entry for vicam!");
+}
 
-	if (urb->status)
-		printk("vicam%d: nonzero read/write bulk status received: %d",
-			0, urb->status);
-
-	urb->actual_length = 0;
-	urb->dev = vicam->udev;
-
-	memcpy(buf2, buf+64, 0x1e480);
-	if (vicam->fbuf)
-		memcpy(vicam->fbuf, buf+64, 0x1e480);
-
-	if (!change_pending) {
-		if (usb_submit_urb(urb, GFP_ATOMIC))
-			dbg("failed resubmitting read urb");
-	} else {
-		change_pending = 0;
-		wake_up_interruptible(&vicam->wait);
-	}
+void
+vicam_destroy_proc_root(void)
+{
+	if (vicam_proc_root)
+		remove_proc_entry("video/vicam", 0);
 }
 
-static int vicam_parameters(struct usb_vicam *vicam)
+void
+vicam_create_proc_entry(void *ptr)
 {
-	unsigned char req[0x10];
-	unsigned int shutter;
-	shutter = 10;
+	struct vicam_camera *cam = (struct vicam_camera *) ptr;
 
-	switch (vicam->win.width) {
-	case 512:
-	default:
-		memcpy(req, s512x242bw, 0x10);
-		break;
-	case 256:
-		memcpy(req, s256x242bw, 0x10);
-		break;
-	case 128:
-		memcpy(req, s128x122bw, 0x10);
-		break;
+	char name[7];
+	struct proc_dir_entry *ent;
+
+	DBG(KERN_INFO "vicam: creating proc entry\n");
+
+	if (!vicam_proc_root || !cam) {
+		printk(KERN_INFO
+		       "vicam: could not create proc entry, %s pointer is null.\n",
+		       (!cam ? "camera" : "root"));
+		return;
 	}
 
+	sprintf(name, "video%d", cam->vdev.minor);
 
-	mdelay(10);
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0);
-	info ("led on");
-	vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0);
-
-	mdelay(10);
-
-	shutter = vicam->win.contrast / 256;
-	if (shutter == 0)
-		shutter = 1;
-	printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter );
-	req[0] = vicam->win.brightness /256;
-	shutter = 15600/shutter - 1;
-	req[6] = shutter & 0xff;
-	req[7] = (shutter >> 8) & 0xff;
-	vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10);
-	mdelay(10);
-	vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10);
-	mdelay(10);
+	ent =
+	    create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+			      vicam_proc_root);
+	if (!ent)
+		return;
 
-	return 0;
+	ent->data = cam;
+	ent->read_proc = vicam_read_proc;
+	ent->write_proc = vicam_write_proc;
+	ent->size = 512;
+	cam->proc_entry = ent;
 }
 
-static int vicam_init(struct usb_vicam *vicam)
+void
+vicam_destroy_proc_entry(void *ptr)
 {
-	int width[] = {128, 256, 512};
-	int height[] = {122, 242, 242};
+	struct vicam_camera *cam = (struct vicam_camera *) ptr;
+	char name[7];
+
+	if (!cam || !cam->proc_entry)
+		return;
 
-	dbg("vicam_init");
-	buf = kmalloc(0x1e480, GFP_KERNEL);
-	buf2 = kmalloc(0x1e480, GFP_KERNEL);
-	if ((!buf) || (!buf2)) {
-		printk("Not enough memory for vicam!\n");
-		goto error;
-	}
-
-	/* do we do aspect correction in kernel or not? */
-	vicam->sizes = 3;
-	vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
-	vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL);
-	memcpy(vicam->width, &width, sizeof(width));
-	memcpy(vicam->height, &height, sizeof(height));
-	vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1];
-
-	/* Download firmware to camera */
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2));
-	vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup));
-
-	vicam_parameters(vicam);
-
-	FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81),
-		      buf, 0x1e480, vicam_bulk, vicam);
-	printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL));
+	sprintf(name, "video%d", cam->vdev.minor);
+	remove_proc_entry(name, vicam_proc_root);
+	cam->proc_entry = NULL;
 
+}
+
+#endif
+
+int
+vicam_video_init(struct video_device *vdev)
+{
+	// This would normally create the proc entry for this camera
+#ifdef CONFIG_PROC_FS
+	vicam_create_proc_entry(vdev->priv);
+#endif
 	return 0;
-error:
-	if (buf)
-		kfree(buf);
-	if (buf2)
-		kfree(buf2);
-	return 1;
-}
-
-static int vicam_probe(struct usb_interface *intf, 
-	const struct usb_device_id *id)
-{
-	struct usb_device *udev = interface_to_usbdev(intf);
-	struct usb_vicam *vicam;
-	char *camera_name=NULL;
+}
 
-	dbg("vicam_probe");
+static struct file_operations vicam_fops = {
+	.owner =  THIS_MODULE,
+	.open =   vicam_open,
+	.release =vicam_close,
+	.read =   vicam_read,
+	.mmap =   vicam_mmap,
+	.ioctl =  vicam_ioctl,
+	.llseek = no_llseek,
+};
 
+static struct video_device vicam_template = {
+	.owner = THIS_MODULE,
+	.name = "ViCam-based USB Camera",
+	.type = VID_TYPE_CAPTURE,
+	.hardware = VID_HARDWARE_VICAM,
+	.fops = &vicam_fops,
+//	.initialize = vicam_video_init,
+	.minor = -1,
+};
+
+/* table of devices that work with this driver */
+static struct usb_device_id vicam_table[] = {
+	{USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
+	{}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, vicam_table);
+
+static struct usb_driver vicam_driver = {
+	name:"vicam",
+	probe:vicam_probe,
+	disconnect:vicam_disconnect,
+	id_table:vicam_table
+};
+
+/**
+ *	vicam_probe
+ *
+ *	Called by the usb core when a new device is connected that it thinks
+ *	this driver might be interested in.
+ */
+static int
+vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	int bulkEndpoint = 0;
+	const struct usb_interface_descriptor *interface;
+	const struct usb_endpoint_descriptor *endpoint;
+	struct vicam_camera *cam;
+	
 	/* See if the device offered us matches what we can accept */
-	if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
-	    (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
+	if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) ||
+	    (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) {
 		return -ENODEV;
 	}
-	
-	camera_name="3Com HomeConnect USB";
-	info("ViCAM camera found: %s", camera_name);
-	
-	vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL);
-	if (vicam == NULL) {
-		err ("couldn't kmalloc vicam struct");
-		return -ENOMEM;
-	}
-	memset(vicam, 0, sizeof(*vicam));
 
-	vicam->readurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!vicam->readurb) {
-		kfree(vicam);
-		return -ENOMEM;
+	printk(KERN_INFO "ViCam based webcam connected\n");
+
+	interface = &intf->altsetting[0];
+
+	DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
+	       ifnum, (unsigned) (interface->bNumEndpoints));
+	endpoint = &interface->endpoint[0];
+
+	if ((endpoint->bEndpointAddress & 0x80) &&
+	    ((endpoint->bmAttributes & 3) == 0x02)) {
+		/* we found a bulk in endpoint */
+		bulkEndpoint = endpoint->bEndpointAddress;
+	} else {
+		printk(KERN_ERR
+		       "No bulk in endpoint was found ?! (this is bad)\n");
 	}
 
-	vicam->udev = udev;
-	vicam->camera_name = camera_name;
-	vicam->win.brightness = 128;
-	vicam->win.contrast = 10;
-
-	/* FIXME */
-	if (vicam_init(vicam)) {
-		usb_free_urb(vicam->readurb);
-		kfree(vicam);
+	if ((cam =
+	     kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+		printk(KERN_WARNING
+		       "could not allocate kernel memory for vicam_camera struct\n");
 		return -ENOMEM;
 	}
-	memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template));
-	memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name));
-	
-	if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
-		err("video_register_device");
-		usb_free_urb(vicam->readurb);
-		kfree(vicam);
-		return -EIO;
-	}
 
-	info("registered new video device: video%d", vicam->vdev.minor);
-	
-	init_MUTEX (&vicam->sem);
-	init_waitqueue_head(&vicam->wait);
-	
-	dev_set_drvdata (&intf->dev, vicam);
-	return 0;
-}
+	memset(cam, 0, sizeof (struct vicam_camera));
 
+	cam->shutter_speed = 15;
 
-/* FIXME - vicam_disconnect - important */
-static void vicam_disconnect(struct usb_interface *intf)
-{
-	struct usb_vicam *vicam;
+	init_MUTEX(&cam->busy_lock);
 
-	vicam = dev_get_drvdata (&intf->dev);
+	memcpy(&cam->vdev, &vicam_template,
+	       sizeof (vicam_template));
+	cam->vdev.priv = cam;	// sort of a reverse mapping for those functions that get vdev only
 
-	dev_set_drvdata (&intf->dev, NULL);
+	cam->udev = dev;
+	cam->bulkEndpoint = bulkEndpoint;
 
-	if (vicam) {
-		video_unregister_device(&vicam->vdev);
-		vicam->udev = NULL;
-/*
-		vicam->frame[0].grabstate = FRAME_ERROR;
-		vicam->frame[1].grabstate = FRAME_ERROR;
-*/
+	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+		kfree(cam);
+		printk(KERN_WARNING "video_register_device failed\n");
+		return -EIO;
+	}
 
-		/* Free buffers and shit */
-		info("%s disconnected", vicam->camera_name);
-		synchronize(vicam);
+	printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
 
-		if (!vicam->open_count) {
-			/* Other random junk */
-			usb_free_urb(vicam->readurb);
-			kfree(vicam);
-			vicam = NULL;
-		}
-	}
+	dev_set_drvdata(&intf->dev, cam);
+	
+	return 0;
 }
 
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver vicam_driver = {
-	.owner =	THIS_MODULE,
-	.name =		"vicam",
-	.probe =	vicam_probe,
-	.disconnect =	vicam_disconnect,
-	.id_table =	vicam_table,
-};
+static void
+vicam_disconnect(struct usb_interface *intf)
+{
+	struct vicam_camera *cam = dev_get_drvdata(&intf->dev);
 
-/******************************************************************************
- *
- *  Module Routines
- *
- ******************************************************************************/
+	dev_set_drvdata ( &intf->dev, NULL );
+	usb_put_dev(cam->udev);
+	
+	cam->udev = NULL;
+	
+	video_unregister_device(&cam->vdev);
 
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
+#ifdef CONFIG_PROC_FS
+	vicam_destroy_proc_entry(cam);
+#endif
 
-/* Module paramaters */
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug enabled or not");
+	if (cam->raw_image)
+		kfree(cam->raw_image);
+	if (cam->framebuf)
+		rvfree(cam->framebuf,
+		       VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
 
-static int __init usb_vicam_init(void)
-{
-	int result;
+	kfree(cam);
 
-	printk("VICAM: initializing\n");
-	/* register this driver with the USB subsystem */
-	result = usb_register(&vicam_driver);
-	if (result < 0) {
-		err("usb_register failed for the "__FILE__" driver. Error number %d",
-		    result);
-		return -1;
-	}
+	printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
+}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+/*
+ */
+static int __init
+usb_vicam_init(void)
+{
+	DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
+#ifdef CONFIG_PROC_FS
+	vicam_create_proc_root();
+#endif
+	if (usb_register(&vicam_driver) != 0)
+		printk(KERN_WARNING "usb_register failed!\n");
 	return 0;
 }
 
-static void __exit usb_vicam_exit(void)
+static void __exit
+usb_vicam_exit(void)
 {
-	/* deregister this driver with the USB subsystem */
+	DBG(KERN_INFO
+	       "ViCam-based WebCam driver shutdown\n");
+
 	usb_deregister(&vicam_driver);
+#ifdef CONFIG_PROC_FS
+	vicam_destroy_proc_root();
+#endif
 }
 
 module_init(usb_vicam_init);
 module_exit(usb_vicam_exit);
 
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/media/vicam.h b/drivers/usb/media/vicam.h
--- a/drivers/usb/media/vicam.h	Tue Oct 15 20:29:12 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,81 +0,0 @@
-/*
- *
- * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
- * Christopher L Cheney (C) 2001
- * 
- */
-
-#ifndef __LINUX_VICAM_H
-#define __LINUX_VICAM_H
-
-
-#ifdef CONFIG_USB_DEBUG
-	static int debug = 1;
-#else
-	static int debug;
-#endif
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0)
-
-#define VICAM_NUMFRAMES 30
-#define VICAM_NUMSBUF 1
-
-/* USB REQUEST NUMBERS */
-#define VICAM_REQ_VENDOR	0xff
-#define VICAM_REQ_CAMERA_POWER	0x50
-#define VICAM_REQ_CAPTURE	0x51
-#define VICAM_REQ_LED_CONTROL	0x55
-#define VICAM_REQ_GET_SOMETHIN	0x56
- 
-/* not required but lets you know camera is on */
-/* camera must be on to turn on led */
-/* 0x01 always on  0x03 on when picture taken (flashes) */
-
-struct picture_parm
-{
-	int width;
-	int height;
-	int brightness;
-	int hue;
-	int colour;
-	int contrast;
-	int whiteness;
-	int depth;
-	int palette;
-};
-
-struct vicam_scratch {
-        unsigned char *data;
-        volatile int state;
-        int offset;
-        int length;
-};
-
-/* Structure to hold all of our device specific stuff */
-struct usb_vicam
-{
-	struct video_device vdev;
-	struct usb_device *udev;
-
-	int open_count;	/* number of times this port has been opened */
-	struct semaphore sem;			/* locks this structure */
-	wait_queue_head_t wait;			/* Processes waiting */ 
-
-	int streaming;
-
-	/* v4l stuff */
-	char *camera_name;
-	char *fbuf;
-	struct urb *urb[VICAM_NUMSBUF];
-	int sizes;
-	int *width;
-	int *height;
-	int maxframesize;
-	struct picture_parm win;
-	struct proc_dir_entry *proc_entry;      /* /proc/se401/videoX */
-	struct urb *readurb;
-};
-
-#endif
diff -Nru a/drivers/usb/media/vicamurbs.h b/drivers/usb/media/vicamurbs.h
--- a/drivers/usb/media/vicamurbs.h	Tue Oct 15 20:29:15 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,332 +0,0 @@
-/*
- *
- * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver
- * Christopher L Cheney (C) 2001
- * 
- */
-
-
-#ifndef __LINUX_VICAMURBS_H
-#define __LINUX_VICAMURBS_H
-
-/* -------------------------------------------------------------------------- */
-
-/* FIXME - Figure out transfers so that this doesn't need to be here
- *
- * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */
-
-/* Request 0x51 Image Setup */
-
-#if 0
-/* 128x98 ? 0x3180 size */
-static unsigned char s128x98bw[] = {
-  0,    0x34, 0xC4, 0x00, 0x00, 0x00, 0,    0,
-  0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-#endif
-
-/* 128x122 3D80 size */
-static unsigned char s128x122bw[] = {
-  0,    0x34, 0xF4, 0x00, 0x00, 0x00, 0,    0,
-  0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* 256x242 ? 0xF280 size */
-static unsigned char s256x242bw[] = {
-  0,    0x03, 0xC8, 0x03, 0x00, 0x00, 0,    0,
-  0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* 512x242 0x1E480 size */
-static unsigned char s512x242bw[] = {
-  0,    0x05, 0x90, 0x07, 0x00, 0x00, 0,    0,
-  0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00
-};
-
-/* In s512x242:
-   byte 0: gain -- higher number means brighter image
-   byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000).
-*/
-
-/* -------------------------------------------------------------------------- */
-
-static unsigned char fsetup[] = {
-  0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64,
-
-  0x00, 0x00
-};
-
-static unsigned char firmware1[] = {
-  0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64,
-
-  0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09,
-  0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03,
-  0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07,
-  0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00
-};
-
-static unsigned char findex1[] = {
-  0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64,
-
-  0x18, 0x00, 0x00, 0x00
-};
-
-static unsigned char firmware2[] = {
-  0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64,
-
-  0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07,
-  0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01,
-  0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00,
-  0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07,
-  0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00,
-  0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0,
-  0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07,
-  0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00,
-  0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0,
-  0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87,
-  0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09,
-  0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0,
-  0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01,
-  0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07,
-  0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0,
-  0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00,
-  0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77,
-  0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57,
-  0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57,
-  0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF,
-  0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05,
-  0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF,
-  0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00,
-  0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01,
-  0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09,
-  0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06,
-  0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0,
-  0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09,
-  0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06,
-  0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06,
-  0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00,
-  0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF,
-  0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07,
-  0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05,
-  0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17,
-  0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06,
-  0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00,
-  0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57,
-  0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03,
-  0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF,
-  0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07,
-  0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00,
-  0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00,
-  0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02,
-  0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57,
-  0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00,
-  0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02,
-  0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90,
-  0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B,
-  0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF,
-  0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07,
-  0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF,
-  0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E,
-  0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00,
-  0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67,
-  0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD,
-  0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0,
-  0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF,
-  0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0,
-  0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00,
-  0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0,
-  0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00,
-  0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00,
-  0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87,
-  0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02,
-  0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0,
-  0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
-  0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1,
-  0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF,
-  0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF,
-  0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07,
-  0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF,
-  0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06,
-  0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67,
-  0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00,
-  0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0,
-  0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF,
-  0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
-  0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
-  0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02,
-  0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
-  0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C,
-  0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00,
-  0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05,
-  0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07,
-  0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02,
-  0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07,
-  0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF,
-  0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF,
-  0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B,
-  0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05,
-  0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF,
-  0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00,
-  0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06,
-  0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02,
-  0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF,
-  0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05,
-  0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07,
-  0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06,
-  0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01,
-  0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07,
-  0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07,
-  0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01,
-  0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0,
-  0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06,
-  0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06,
-  0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06,
-  0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00,
-  0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05,
-  0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05,
-  0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA,
-  0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1,
-  0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00,
-  0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00,
-  0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05,
-  0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF,
-  0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57,
-  0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07,
-  0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07,
-  0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07,
-  0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07,
-  0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67,
-  0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0,
-  0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00,
-  0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00,
-  0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00,
-  0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05,
-  0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8,
-  0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05,
-  0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07,
-  0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05,
-  0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B,
-  0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17,
-  0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07,
-  0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09,
-  0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1,
-  0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00,
-  0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05,
-  0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05,
-  0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07,
-  0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07,
-  0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF,
-  0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9,
-  0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00,
-  0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0,
-  0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67,
-  0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA,
-  0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0,
-  0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87,
-  0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF,
-  0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0,
-  0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF,
-  0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0,
-  0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87,
-  0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00,
-  0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05,
-  0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67,
-  0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87,
-  0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07,
-  0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67,
-  0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE,
-  0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0,
-  0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA,
-  0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00,
-  0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0,
-  0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1,
-  0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF,
-  0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77,
-  0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
-  0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77,
-  0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF,
-  0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80,
-  0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00,
-  0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char findex2[] = {
-  0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64,
-
-  0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00,
-  0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00,
-  0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00,
-  0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00,
-  0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00,
-  0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00,
-  0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01,
-  0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01,
-  0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01,
-  0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01,
-  0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01,
-  0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01,
-  0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01,
-  0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01,
-  0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02,
-  0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02,
-  0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02,
-  0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02,
-  0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02,
-  0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02,
-  0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02,
-  0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02,
-  0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03,
-  0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03,
-  0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03,
-  0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03,
-  0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03,
-  0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03,
-  0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03,
-  0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04,
-  0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04,
-  0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04,
-  0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04,
-  0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04,
-  0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04,
-  0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04,
-  0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04,
-  0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00
-};
-
-#endif
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/usb/net/usbnet.c	Tue Oct 15 20:29:17 2002
@@ -2092,7 +2092,7 @@
 #ifdef	CONFIG_USB_EPSON2888
 {
 	USB_DEVICE (0x0525, 0x2888),	// EPSON USB client
-	driver_info:	(unsigned long) &epson2888_info,
+	.driver_info	= (unsigned long) &epson2888_info,
 },
 #endif
 
diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
--- a/drivers/usb/serial/io_ti.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/serial/io_ti.c	Tue Oct 15 20:29:16 2002
@@ -2617,47 +2617,47 @@
 
 
 static struct usb_serial_device_type edgeport_1port_device = {
-	owner:			THIS_MODULE,
-	name:			"Edgeport TI 1 port adapter",
-	id_table:		edgeport_1port_id_table,
-	num_interrupt_in:	1,
-	num_bulk_in:		1,
-	num_bulk_out:		1,
-	num_ports:		1,
-	open:			edge_open,
-	close:			edge_close,
-	throttle:		edge_throttle,
-	unthrottle:		edge_unthrottle,
-	attach:			edge_startup,
-	shutdown:		edge_shutdown,
-	ioctl:			edge_ioctl,
-	set_termios:		edge_set_termios,
-	write:			edge_write,
-	write_room:		edge_write_room,
-	chars_in_buffer:	edge_chars_in_buffer,
-	break_ctl:		edge_break,
+	.owner			= THIS_MODULE,
+	.name			= "Edgeport TI 1 port adapter",
+	.id_table		= edgeport_1port_id_table,
+	.num_interrupt_in	= 1,
+	.num_bulk_in		= 1,
+	.num_bulk_out		= 1,
+	.num_ports		= 1,
+	.open			= edge_open,
+	.close			= edge_close,
+	.throttle		= edge_throttle,
+	.unthrottle		= edge_unthrottle,
+	.attach			= edge_startup,
+	.shutdown		= edge_shutdown,
+	.ioctl			= edge_ioctl,
+	.set_termios		= edge_set_termios,
+	.write			= edge_write,
+	.write_room		= edge_write_room,
+	.chars_in_buffer	= edge_chars_in_buffer,
+	.break_ctl		= edge_break,
 };
 
 static struct usb_serial_device_type edgeport_2port_device = {
-	owner:			THIS_MODULE,
-	name:			"Edgeport TI 2 port adapter",
-	id_table:		edgeport_2port_id_table,
-	num_interrupt_in:	1,
-	num_bulk_in:		2,
-	num_bulk_out:		2,
-	num_ports:		2,
-	open:			edge_open,
-	close:			edge_close,
-	throttle:		edge_throttle,
-	unthrottle:		edge_unthrottle,
-	attach:			edge_startup,
-	shutdown:		edge_shutdown,
-	ioctl:			edge_ioctl,
-	set_termios:		edge_set_termios,
-	write:			edge_write,
-	write_room:		edge_write_room,
-	chars_in_buffer:	edge_chars_in_buffer,
-	break_ctl:		edge_break,
+	.owner			= THIS_MODULE,
+	.name			= "Edgeport TI 2 port adapter",
+	.id_table		= edgeport_2port_id_table,
+	.num_interrupt_in	= 1,
+	.num_bulk_in		= 2,
+	.num_bulk_out		= 2,
+	.num_ports		= 2,
+	.open			= edge_open,
+	.close			= edge_close,
+	.throttle		= edge_throttle,
+	.unthrottle		= edge_unthrottle,
+	.attach			= edge_startup,
+	.shutdown		= edge_shutdown,
+	.ioctl			= edge_ioctl,
+	.set_termios		= edge_set_termios,
+	.write			= edge_write,
+	.write_room		= edge_write_room,
+	.chars_in_buffer	= edge_chars_in_buffer,
+	.break_ctl		= edge_break,
 };
 
 
diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
--- a/drivers/usb/serial/usb-serial.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/serial/usb-serial.c	Tue Oct 15 20:29:16 2002
@@ -1237,16 +1237,17 @@
 	}
 
 #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE)
-#if 0
 	/* BEGIN HORRIBLE HACK FOR PL2303 */ 
 	/* this is needed due to the looney way its endpoints are set up */
-	if (ifnum == 1) {
-		if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) &&
-		     (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) ||
-		    ((dev->descriptor.idVendor == ATEN_VENDOR_ID) &&
-		     (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
+	if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) &&
+	     (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) ||
+	    ((dev->descriptor.idVendor == ATEN_VENDOR_ID) &&
+	     (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) {
+		//if (ifnum == 1) {
+		if (interface != &dev->actconfig->interface[0]) {
 			/* check out the endpoints of the other interface*/
-			interface = &dev->actconfig->interface[ifnum ^ 1];
+			//interface = &dev->actconfig->interface[ifnum ^ 1];
+			interface = &dev->actconfig->interface[0];
 			iface_desc = &interface->altsetting[0];
 			for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
 				endpoint = &iface_desc->endpoint[i];
@@ -1259,9 +1260,18 @@
 				}
 			}
 		}
+
+		/* Now make sure the PL-2303 is configured correctly.
+		 * If not, give up now and hope this hack will work
+		 * properly during a later invocation of usb_serial_probe
+		 */
+		if (num_bulk_in == 0 || num_bulk_out == 0) {
+			info("PL-2303 hack: descriptors matched but endpoints did not");
+			kfree (serial);
+			return -ENODEV;
+		}
 	}
 	/* END HORRIBLE HACK FOR PL2303 */
-#endif
 #endif
 
 	/* found all that we need */
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Tue Oct 15 20:29:15 2002
+++ b/drivers/usb/serial/visor.c	Tue Oct 15 20:29:15 2002
@@ -669,7 +669,7 @@
 	/* get the interface number */
 	result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0),
 				  USB_REQ_GET_INTERFACE, 
-				  USB_DIR_IN | USB_DT_DEVICE,
+				  USB_DIR_IN | USB_RECIP_INTERFACE,
 				  0, 0, &data, 1, HZ * 3);
 	if (result < 0) {
 		err("%s: get interface number failed: %d", __FUNCTION__, result);
diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
--- a/drivers/usb/serial/whiteheat.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/serial/whiteheat.c	Tue Oct 15 20:29:16 2002
@@ -334,6 +334,12 @@
 	command_port = &serial->port[COMMAND_PORT];
 
 	pipe = usb_sndbulkpipe (serial->dev, command_port->bulk_out_endpointAddress);
+	/*
+	 * When the module is reloaded the firmware is still there and
+	 * the endpoints are still in the usb core unchanged. This is the
+         * unlinking bug in disguise. Same for the call below.
+         */
+	usb_clear_halt(serial->dev, pipe);
 	ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, COMMAND_TIMEOUT);
 	if (ret) {
 		err("%s: Couldn't send command [%d]", serial->type->name, ret);
@@ -344,6 +350,8 @@
 	}
 
 	pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress);
+	/* See the comment on the usb_clear_halt() above */
+	usb_clear_halt(serial->dev, pipe);
 	ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, COMMAND_TIMEOUT);
 	if (ret) {
 		err("%s: Couldn't get results [%d]", serial->type->name, ret);
@@ -438,6 +446,10 @@
 	if (retval)
 		goto exit;
 
+	/* Work around HCD bugs */
+	usb_clear_halt(port->serial->dev, port->read_urb->pipe);
+	usb_clear_halt(port->serial->dev, port->write_urb->pipe);
+
 	/* Start reading from the device */
 	port->read_urb->dev = port->serial->dev;
 	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
@@ -489,7 +501,8 @@
 {
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	
-	if (tty_hung_up_p(filp)) {
+	/* filp is NULL when called from usb_serial_disconnect */
+	if (filp && (tty_hung_up_p(filp))) {
 		return;
 	}
 
@@ -1145,6 +1158,9 @@
 	command_info = (struct whiteheat_command_private *)command_port->private;
 	spin_lock_irqsave(&command_info->lock, flags);
 	if (!command_info->port_running) {
+		/* Work around HCD bugs */
+		usb_clear_halt(serial->dev, command_port->read_urb->pipe);
+
 		command_port->read_urb->dev = serial->dev;
 		retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL);
 		if (retval) {
diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
--- a/drivers/usb/storage/datafab.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/usb/storage/datafab.c	Tue Oct 15 20:29:23 2002
@@ -67,25 +67,23 @@
 
 static inline int
 datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) {
-	unsigned int act_len;	/* ignored */
-
 	if (len == 0)
 		return USB_STOR_XFER_GOOD;
 
 	US_DEBUGP("datafab_bulk_read:  len = %d\n", len);
-	return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len);
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			data, len, NULL);
 }
 
 
 static inline int
 datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) {
-	unsigned int act_len;	/* ignored */
-
 	if (len == 0)
 		return USB_STOR_XFER_GOOD;
 
 	US_DEBUGP("datafab_bulk_write:  len = %d\n", len);
-	return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len);
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+			data, len, NULL);
 }
 
 
@@ -522,6 +520,7 @@
 		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
 	};
 
+	srb->resid = 0;
 	if (!us->extra) {
 		us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO);
 		if (!us->extra) {
diff -Nru a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
--- a/drivers/usb/storage/freecom.c	Tue Oct 15 20:29:23 2002
+++ b/drivers/usb/storage/freecom.c	Tue Oct 15 20:29:23 2002
@@ -108,72 +108,9 @@
 /* All packets (except for status) are 64 bytes long. */
 #define FCM_PACKET_LENGTH	64
 
-/*
- * Transfer an entire SCSI command's worth of data payload over the bulk
- * pipe.
- *
- * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this
- * function simply determines if we're going to use scatter-gather or not,
- * and acts appropriately.  For now, it also re-interprets the error codes.
- */
-static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer_amount)
-{
-	int i;
-	int result = -1;
-	struct scatterlist *sg;
-	unsigned int total_transferred = 0;
-
-	/* was someone foolish enough to request more data than available
-	 * buffer space? */
-	if (transfer_amount > srb->request_bufflen)
-		transfer_amount = srb->request_bufflen;
-
-	/* are we scatter-gathering? */
-	if (srb->use_sg) {
-
-		/* loop over all the scatter gather structures and 
-		 * make the appropriate requests for each, until done
-		 */
-		sg = (struct scatterlist *) srb->request_buffer;
-		for (i = 0; i < srb->use_sg; i++) {
-
-			US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred);
-
-			/* End this if we're done */
-			if (transfer_amount == total_transferred)
-				break;
-
-			/* transfer the lesser of the next buffer or the
-			 * remaining data */
-			if (transfer_amount - total_transferred >= 
-					sg[i].length) {
-				result = usb_stor_transfer_partial(us,
-						sg_address(sg[i]), sg[i].length);
-				total_transferred += sg[i].length;
-			} else {
-				result = usb_stor_transfer_partial(us,
-						sg_address(sg[i]),
-						transfer_amount - total_transferred);
-				total_transferred += transfer_amount - total_transferred;
-			}
-
-			/* if we get an error, end the loop here */
-			if (result)
-				break;
-		}
-	}
-	else
-		/* no scatter-gather, just make the request */
-		result = usb_stor_transfer_partial(us, srb->request_buffer, 
-					     transfer_amount);
-
-	/* return the result in the data structure itself */
-	srb->result = result;
-}
-
 static int
 freecom_readdata (Scsi_Cmnd *srb, struct us_data *us,
-                int ipipe, int opipe, int count)
+                unsigned int ipipe, unsigned int opipe, int count)
 {
         freecom_udata_t extra = (freecom_udata_t) us->extra;
         struct freecom_xfer_wrap *fxfr =
@@ -206,15 +143,15 @@
 
         /* Now transfer all of our blocks. */
 	US_DEBUGP("Start of read\n");
-	us_transfer_freecom(srb, us, count);
+	result = usb_stor_bulk_transfer_srb(us, ipipe, srb, count);
         US_DEBUGP("freecom_readdata done!\n");
 
-        return USB_STOR_TRANSPORT_GOOD;
+        return result;
 }
 
 static int
 freecom_writedata (Scsi_Cmnd *srb, struct us_data *us,
-                int ipipe, int opipe, int count)
+                int unsigned ipipe, unsigned int opipe, int count)
 {
         freecom_udata_t extra = (freecom_udata_t) us->extra;
         struct freecom_xfer_wrap *fxfr =
@@ -248,10 +185,10 @@
 
         /* Now transfer all of our blocks. */
 	US_DEBUGP("Start of write\n");
-	us_transfer_freecom(srb, us, count);
+	result = usb_stor_bulk_transfer_srb(us, opipe, srb, count);
 
         US_DEBUGP("freecom_writedata done!\n");
-        return USB_STOR_TRANSPORT_GOOD;
+        return result;
 }
 
 /*
@@ -262,7 +199,7 @@
 {
         struct freecom_cb_wrap *fcb;
         struct freecom_status  *fst;
-        int ipipe, opipe;             /* We need both pipes. */
+        unsigned int ipipe, opipe;             /* We need both pipes. */
         int result;
         int partial;
         int length;
@@ -276,8 +213,8 @@
         US_DEBUGP("Freecom TRANSPORT STARTED\n");
 
         /* Get handles for both transports. */
-        opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out);
-        ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in);
+        opipe = us->send_bulk_pipe;
+        ipipe = us->recv_bulk_pipe;
 
         /* The ATAPI Command always goes out first. */
         fcb->Type = FCM_PACKET_ATAPI | 0x00;
@@ -515,8 +452,7 @@
                 }
         }
 
-	result = usb_control_msg(us->pusb_dev,
-			usb_rcvctrlpipe(us->pusb_dev, 0),
+	result = usb_control_msg(us->pusb_dev, us->recv_ctrl_pipe,
 			0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ);
 	buffer[32] = '\0';
 	US_DEBUGP("String returned from FC init is: %s\n", buffer);
@@ -528,8 +464,7 @@
 	 */
 
 	/* send reset */
-	result = usb_control_msg(us->pusb_dev,
-			usb_sndctrlpipe(us->pusb_dev, 0),
+	result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe,
 			0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ);
 	US_DEBUGP("result from activate reset is %d\n", result);
 
@@ -537,8 +472,7 @@
 	mdelay(250);
 
 	/* clear reset */
-	result = usb_control_msg(us->pusb_dev,
-			usb_sndctrlpipe(us->pusb_dev, 0),
+	result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe,
 			0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ);
 	US_DEBUGP("result from clear reset is %d\n", result);
 
diff -Nru a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
--- a/drivers/usb/storage/initializers.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/storage/initializers.c	Tue Oct 15 20:29:16 2002
@@ -50,7 +50,7 @@
 	int result;
 
 	US_DEBUGP("Attempting to init eUSCSI bridge...\n");
-	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0),
+	result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe,
 			0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
 			0x01, 0x0, &data, 0x1, 5*HZ);
 	US_DEBUGP("-- result is %d\n", result);
diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
--- a/drivers/usb/storage/isd200.c	Tue Oct 15 20:29:17 2002
+++ b/drivers/usb/storage/isd200.c	Tue Oct 15 20:29:17 2002
@@ -408,13 +408,13 @@
 {
         int result;
         int partial;
-        int pipe;
+        unsigned int pipe;
 
         /* calculate the appropriate pipe information */
 	if (dataDirection == SCSI_DATA_READ)
-                pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+                pipe = us->recv_bulk_pipe;
         else
-                pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+                pipe = us->send_bulk_pipe;
 
         /* transfer the data */
         US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length);
@@ -546,7 +546,6 @@
         struct bulk_cb_wrap bcb;
         struct bulk_cs_wrap bcs;
         int result;
-        int pipe;
         int partial;
         unsigned int transfer_amount;
 
@@ -566,9 +565,6 @@
 
         bcb.Length = AtaCdbLength;
     
-        /* construct the pipe handle */
-        pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-    
         /* copy the command payload */
         memset(bcb.CDB, 0, sizeof(bcb.CDB));
         memcpy(bcb.CDB, AtaCdb, bcb.Length);
@@ -578,8 +574,8 @@
                   le32_to_cpu(bcb.Signature), bcb.Tag,
                   (bcb.Lun >> 4), (bcb.Lun & 0xFF), 
                   le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
-        result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, 
-				   &partial);
+        result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe,
+				US_BULK_CB_WRAP_LEN, &partial);
         US_DEBUGP("Bulk command transfer result=%d\n", result);
     
 	/* did we abort this command? */
@@ -589,8 +585,9 @@
 
 	else if (result == -EPIPE) {
 		/* if we stall, we need to clear it before we go on */
-                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-                if (usb_stor_clear_halt(us, pipe) < 0)
+                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
+				us->send_bulk_pipe);
+                if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0)
 			return ISD200_TRANSPORT_ERROR;
 	} else if (result)  
                 return ISD200_TRANSPORT_ERROR;
@@ -608,13 +605,10 @@
          * an explanation of how this code works.
          */
     
-        /* construct the pipe handle */
-        pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-    
         /* get CSW for device status */
         US_DEBUGP("Attempting to get CSW...\n");
-        result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, 
-				   &partial);
+        result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe,
+				US_BULK_CS_WRAP_LEN, &partial);
 	/* did we abort this command? */
 	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 		return ISD200_TRANSPORT_ABORTED;
@@ -622,13 +616,14 @@
 
         /* did the attempt to read the CSW fail? */
         if (result == -EPIPE) {
-                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-                if (usb_stor_clear_halt(us, pipe) < 0)
+                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
+				us->recv_bulk_pipe);
+                if (usb_stor_clear_halt(us, us->recv_bulk_pipe) < 0)
 			return ISD200_TRANSPORT_ERROR;
            
                 /* get the status again */
                 US_DEBUGP("Attempting to get CSW (2nd try)...\n");
-                result = usb_stor_bulk_msg(us, &bcs, pipe,
+                result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe,
                                            US_BULK_CS_WRAP_LEN, &partial);
 
                 /* if the command was aborted, indicate that */
@@ -638,8 +633,9 @@
         
                 /* if it fails again, we need a reset and return an error*/
                 if (result == -EPIPE) {
-                        US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
-                        usb_stor_clear_halt(us, pipe);
+                        US_DEBUGP("clearing halt for pipe 0x%x\n",
+					us->recv_bulk_pipe);
+                        usb_stor_clear_halt(us, us->recv_bulk_pipe);
                         return ISD200_TRANSPORT_ERROR;
                 }
         }
@@ -937,7 +933,7 @@
 	/* let's send the command via the control pipe */
 	result = usb_stor_control_msg(
                 us, 
-                usb_sndctrlpipe(us->pusb_dev,0),
+                us->send_ctrl_pipe,
                 0x01, 
                 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
                 0x0000, 
@@ -978,7 +974,7 @@
 
 	result = usb_stor_control_msg(
                 us, 
-                usb_rcvctrlpipe(us->pusb_dev,0),
+                us->recv_ctrl_pipe,
                 0x02, 
                 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
                 0x0000, 
diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
--- a/drivers/usb/storage/jumpshot.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/usb/storage/jumpshot.c	Tue Oct 15 20:29:11 2002
@@ -62,13 +62,12 @@
 				     unsigned char *data, 
 				     unsigned int len)
 {
-	unsigned int act_len;	/* ignored */
-
 	if (len == 0)
 		return USB_STOR_XFER_GOOD;
 
 	US_DEBUGP("jumpshot_bulk_read:  len = %d\n", len);
-	return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len);
+	return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			data, len, NULL);
 }
 
 
@@ -76,13 +75,12 @@
 				      unsigned char *data, 
 				      unsigned int len)
 {
-	unsigned int act_len;	/* ignored */
-
 	if (len == 0)
 		return USB_STOR_XFER_GOOD;
 
 	US_DEBUGP("jumpshot_bulk_write:  len = %d\n", len);
-	return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len);
+	return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+			data, len, NULL);
 }
 
 
@@ -95,12 +93,11 @@
 		return USB_STOR_TRANSPORT_ERROR;
 
 	// send the setup
-	rc = usb_storage_send_control(us,
-				   usb_rcvctrlpipe(us->pusb_dev, 0),
+	rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
 				   0, 0xA0, 0, 7, &reply, 1);
 
-	if (rc != USB_STOR_TRANSPORT_GOOD)
-		return rc;
+	if (rc != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	if (reply != 0x50) {
 		US_DEBUGP("jumpshot_get_status:  0x%2x\n",
@@ -160,10 +157,9 @@
 		command[5] |= (sector >> 24) & 0x0F;
 
 		// send the setup + command
-		result = usb_storage_send_control(us,
-					       usb_sndctrlpipe(us->pusb_dev, 0),
+		result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
 					       0, 0x20, 0, 1, command, 7);
-		if (result != USB_STOR_TRANSPORT_GOOD)
+		if (result != USB_STOR_XFER_GOOD)
 			goto leave;
 
 		// read the result
@@ -247,9 +243,10 @@
 		command[5] |= (sector >> 24) & 0x0F;
 
 		// send the setup + command
-		result = usb_storage_send_control(
-			us, usb_sndctrlpipe(us->pusb_dev, 0),
+		result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
 			0, 0x20, 0, 1, command, 7);
+		if (result != USB_STOR_XFER_GOOD)
+			goto leave;
 
 		// send the data
 		result = jumpshot_bulk_write(us, ptr, len);
@@ -302,11 +299,10 @@
 		return USB_STOR_TRANSPORT_ERROR;
 
 	// send the setup
-	rc = usb_storage_send_control(us,
-				   usb_sndctrlpipe(us->pusb_dev, 0),
+	rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
 				   0, 0x20, 0, 6, command, 2);
 
-	if (rc != USB_STOR_TRANSPORT_GOOD) {
+	if (rc != USB_STOR_XFER_GOOD) {
 		US_DEBUGP("jumpshot_id_device:  Gah! "
 			  "send_control for read_capacity failed\n");
 		return rc;
@@ -468,7 +464,7 @@
 		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
 	};
 
-
+	srb->resid = 0;
 	if (!us->extra) {
 		us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO);
 		if (!us->extra) {
diff -Nru a/drivers/usb/storage/raw_bulk.c b/drivers/usb/storage/raw_bulk.c
--- a/drivers/usb/storage/raw_bulk.c	Tue Oct 15 20:29:19 2002
+++ b/drivers/usb/storage/raw_bulk.c	Tue Oct 15 20:29:19 2002
@@ -13,219 +13,6 @@
 #include "transport.h"
 #include "raw_bulk.h"
 
-#ifdef CONFIG_USB_STORAGE_DEBUG
-#define DEBUG_PRCT 12
-#else
-#define DEBUG_PRCT 0
-#endif
-
-/*
- * Send a control message and wait for the response.
- *
- * us - the pointer to the us_data structure for the device to use
- *
- * request - the URB Setup Packet's first 6 bytes. The first byte always
- *  corresponds to the request type, and the second byte always corresponds
- *  to the request.  The other 4 bytes do not correspond to value and index,
- *  since they are used in a custom way by the SCM protocol.
- *
- * xfer_data - a buffer from which to get, or to which to store, any data
- *  that gets send or received, respectively, with the URB. Even though
- *  it looks like we allocate a buffer in this code for the data, xfer_data
- *  must contain enough allocated space.
- *
- * xfer_len - the number of bytes to send or receive with the URB.
- *
- */
-
-int
-usb_storage_send_control(struct us_data *us,
-			 int pipe,
-			 unsigned char request,
-			 unsigned char requesttype,
-			 unsigned int value,
-			 unsigned int index,
-			 unsigned char *xfer_data,
-			 unsigned int xfer_len) {
-
-	int result;
-
-	// Send the URB to the device and wait for a response.
-
-	/* Why are request and request type reversed in this call? */
-
-	result = usb_stor_control_msg(us, pipe,
-			request, requesttype, value, index,
-			xfer_data, xfer_len);
-
-	/* did we abort this command? */
-	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-		US_DEBUGP("usb_stor_send_control(): transfer aborted\n");
-		return USB_STOR_TRANSPORT_ABORTED;
-	}
-
-	// Check the return code for the command.
-	if (result < 0) {
-
-		/* a stall indicates a protocol error */
-		if (result == -EPIPE) {
-			US_DEBUGP("-- Stall on control pipe\n");
-			return USB_STOR_TRANSPORT_ERROR;
-		}
-
-		/* Uh oh... serious problem here */
-		return USB_STOR_TRANSPORT_ERROR;
-	}
-
-	return USB_STOR_TRANSPORT_GOOD;
-}
-
-int
-usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data,
-		     unsigned int len, unsigned int *act_len) {
-
-	int result;
-	int pipe;
-
-	if (direction == SCSI_DATA_READ)
-		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-	else
-		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-
-	result = usb_stor_bulk_msg(us, data, pipe, len, act_len);
-
-	/* if we stall, we need to clear it before we go on */
-	if (result == -EPIPE) {
-		US_DEBUGP("EPIPE: clearing endpoint halt for"
-			  " pipe 0x%x, stalled at %d bytes\n",
-			  pipe, *act_len);
-		if (usb_stor_clear_halt(us, pipe) < 0)
-			return USB_STOR_XFER_ERROR;
-		return USB_STOR_XFER_STALLED;
-	}
-
-	/* did we abort this command? */
-	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-		US_DEBUGP("usb_storage_raw_bulk(): transfer aborted\n");
-		return USB_STOR_XFER_ABORTED;
-	}
-
-	if (result) {
-		/* NAK - that means we've retried a few times already */
-       		if (result == -ETIMEDOUT)
-			US_DEBUGP("raw_bulk(): device NAKed\n");
-		else if (result == -EOVERFLOW)
-			US_DEBUGP("raw_bulk(): babble/overflow\n");
-		else if (result == -ECONNRESET)
-			US_DEBUGP("raw_bulk(): asynchronous reset\n");
-		else if (result != -EPIPE)
-			US_DEBUGP("raw_bulk(): unknown error %d\n",
-				  result);
-
-		return USB_STOR_XFER_ERROR;
-	}
-
-	if (*act_len != len) {
-		US_DEBUGP("Warning: Transferred only %d of %d bytes\n",
-			  *act_len, len);
-		return USB_STOR_XFER_SHORT;
-	}
-
-#if 0
-	US_DEBUGP("raw_bulk(): Transferred %s %d of %d bytes\n",
-		  (direction == SCSI_DATA_READ) ? "in" : "out",
-		  *act_len, len);
-#endif
-
-	return USB_STOR_XFER_GOOD;
-}
-
-int
-usb_storage_bulk_transport(struct us_data *us, int direction,
-			   unsigned char *data, unsigned int len,
-			   int use_sg) {
-
-	int result = USB_STOR_XFER_ERROR;
-	int transferred = 0;
-	int i;
-	struct scatterlist *sg;
-	unsigned int act_len;
-
-	if (len == 0)
-		return USB_STOR_XFER_GOOD;
-
-#if DEBUG_PRCT
-
-	if (direction == SCSI_DATA_WRITE && !use_sg) {
-		char string[64];
-
-		/* Debug-print the first N bytes of the write transfer */
-
-		strcpy(string, "wr: ");
-		for (i=0; i<len && i<DEBUG_PRCT; i++) {
-			sprintf(string+strlen(string), "%02X ", data[i]);
-			if ((i%16) == 15) {
-				US_DEBUGP("%s\n", string);
-				strcpy(string, "wr: ");
-			}
-		}
-		if ((i%16)!=0)
-			US_DEBUGP("%s\n", string);
-	}
-
-	US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",
-		  (direction == SCSI_DATA_READ) ? "in" : "out",
-		  len, use_sg);
-
-#endif /* DEBUG_PRCT */
-
-	if (!use_sg)
-		result = usb_storage_raw_bulk(us, direction,
-					      data, len, &act_len);
-	else {
-		sg = (struct scatterlist *)data;
-
-		for (i=0; i<use_sg && transferred<len; i++) {
-			unsigned char *buf;
-			unsigned int length;
-
-			buf = sg_address(sg[i]);
-			length = len-transferred;
-			if (length > sg[i].length)
-				length = sg[i].length;
-
-			result = usb_storage_raw_bulk(us, direction,
-						      buf, length, &act_len);
-			if (result != USB_STOR_XFER_GOOD)
-				break;
-			transferred += length;
-		}
-	}
-
-#if DEBUG_PRCT
-
-	if (direction == SCSI_DATA_READ && !use_sg) {
-		char string[64];
-
-		/* Debug-print the first N bytes of the read transfer */
-
-		strcpy(string, "rd: ");
-		for (i=0; i<len && i<act_len && i<DEBUG_PRCT; i++) {
-			sprintf(string+strlen(string), "%02X ", data[i]);
-			if ((i%16) == 15) {
-				US_DEBUGP("%s\n", string);
-				strcpy(string, "rd: ");
-			}
-		}
-		if ((i%16)!=0)
-			US_DEBUGP("%s\n", string);
-	}
-
-#endif /* DEBUG_PRCT */
-
-	return result;
-}
-
 /*
  * The routines below convert scatter-gather to single buffer.
  * Some drivers claim this is necessary.
diff -Nru a/drivers/usb/storage/raw_bulk.h b/drivers/usb/storage/raw_bulk.h
--- a/drivers/usb/storage/raw_bulk.h	Tue Oct 15 20:29:12 2002
+++ b/drivers/usb/storage/raw_bulk.h	Tue Oct 15 20:29:12 2002
@@ -1,21 +1,6 @@
 #ifndef _USB_STORAGE_RAW_BULK_H_
 #define _USB_STORAGE_RAW_BULK_H_
 
-/* usb bulk */
-extern int usb_storage_send_control(
-	struct us_data *us, int pipe,
-	unsigned char request, unsigned char requesttype,
-	unsigned int value, unsigned int index,
-	unsigned char *xfer_data, unsigned int xfer_len);
-
-extern int usb_storage_raw_bulk(
-	struct us_data *us, int direction,
-	unsigned char *data, unsigned int len, unsigned int *act_len);
-
-extern int usb_storage_bulk_transport(
-	struct us_data *us, int direction,
-	unsigned char *data, unsigned int len, int use_sg);
-
 /* scatter-gather */
 extern unsigned char *us_copy_from_sgbuf(
 	unsigned char *content, int buflen,
diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
--- a/drivers/usb/storage/sddr09.c	Tue Oct 15 20:29:20 2002
+++ b/drivers/usb/storage/sddr09.c	Tue Oct 15 20:29:20 2002
@@ -224,18 +224,21 @@
 		    unsigned char direction,
 		    unsigned char *xfer_data,
 		    unsigned int xfer_len) {
-	int pipe;
+	unsigned int pipe;
 	unsigned char requesttype = (0x41 | direction);
+	int rc;
 
 	// Get the receive or send control pipe number
 
 	if (direction == USB_DIR_IN)
-		pipe = usb_rcvctrlpipe(us->pusb_dev,0);
+		pipe = us->recv_ctrl_pipe;
 	else
-		pipe = usb_sndctrlpipe(us->pusb_dev,0);
+		pipe = us->send_ctrl_pipe;
 
-	return usb_storage_send_control(us, pipe, request, requesttype,
+	rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype,
 				   0, 0, xfer_data, xfer_len);
+	return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD :
+			USB_STOR_TRANSPORT_ERROR);
 }
 
 static int
@@ -276,7 +279,6 @@
 		0x03, LUNBITS, 0, 0, buflen, 0, 0, 0, 0, 0, 0, 0
 	};
 	int result;
-	unsigned int act_len;
 
 	result = sddr09_send_scsi_command(us, command, sizeof(command));
 	if (result != USB_STOR_TRANSPORT_GOOD) {
@@ -284,7 +286,8 @@
 		return result;
 	}
 
-	result = usb_storage_raw_bulk(us, SCSI_DATA_READ, sensebuf, buflen, &act_len);
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			sensebuf, buflen, NULL);
 	if (result != USB_STOR_XFER_GOOD) {
 		US_DEBUGP("request sense bulk in failed\n");
 		return USB_STOR_TRANSPORT_ERROR;
@@ -343,11 +346,11 @@
 		return result;
 	}
 
-	result = usb_storage_bulk_transport(us, SCSI_DATA_READ,
-				       buf, bulklen, use_sg);
+	result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe,
+				       buf, bulklen, use_sg, NULL);
 
 	if (result != USB_STOR_XFER_GOOD) {
-		US_DEBUGP("Result for bulk_transport in sddr09_read2%d %d\n",
+		US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n",
 			  x, result);
 		return USB_STOR_TRANSPORT_ERROR;
 	}
@@ -510,11 +513,11 @@
 		return result;
 	}
 
-	result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE,
-				       buf, bulklen, use_sg);
+	result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe,
+				       buf, bulklen, use_sg, NULL);
 
 	if (result != USB_STOR_XFER_GOOD) {
-		US_DEBUGP("Result for bulk_transport in sddr09_writeX %d\n",
+		US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n",
 			  result);
 		return USB_STOR_TRANSPORT_ERROR;
 	}
@@ -592,11 +595,11 @@
 	if (!buf)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	result = usb_storage_bulk_transport(us, SCSI_DATA_READ,
-				       buf, bulklen, 0);
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				       buf, bulklen, NULL);
 	kfree(buf);
 	if (result != USB_STOR_XFER_GOOD) {
-		US_DEBUGP("Result for bulk_transport in sddr09_read_sg %d\n",
+		US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n",
 			  result);
 		return USB_STOR_TRANSPORT_ERROR;
 	}
@@ -631,8 +634,8 @@
 	if (result != USB_STOR_TRANSPORT_GOOD)
 		return result;
 
-	result = usb_storage_bulk_transport(us, SCSI_DATA_READ,
-				       data, sizeof(data), 0);
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				       data, sizeof(data), NULL);
 	*status = data[0];
 	return (result == USB_STOR_XFER_GOOD ?
 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
@@ -954,7 +957,8 @@
 	if (result != USB_STOR_TRANSPORT_GOOD)
 		return result;
 
-	result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, 64, 0);
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+			content, 64, NULL);
 
 	for (i = 0; i < 4; i++)
 		deviceID[i] = content[i];
@@ -1368,6 +1372,7 @@
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
 
+	srb->resid = 0;
 	info = (struct sddr09_card_info *)us->extra;
 	if (!info) {
 		nand_init_ecc();
@@ -1544,17 +1549,16 @@
 
 	if (srb->sc_data_direction == SCSI_DATA_WRITE ||
 	    srb->sc_data_direction == SCSI_DATA_READ) {
+		unsigned int pipe = (srb->sc_data_direction == SCSI_DATA_WRITE)
+				? us->send_bulk_pipe : us->recv_bulk_pipe;
 
 		US_DEBUGP("SDDR09: %s %d bytes\n",
 			  (srb->sc_data_direction == SCSI_DATA_WRITE) ?
 			  "sending" : "receiving",
 			  srb->request_bufflen);
 
-		result = usb_storage_bulk_transport(us,
-					       srb->sc_data_direction,
-					       srb->request_buffer, 
-					       srb->request_bufflen,
-					       srb->use_sg);
+		result = usb_stor_bulk_transfer_srb(us, pipe, srb,
+							srb->request_bufflen);
 
 		return (result == USB_STOR_XFER_GOOD ?
 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
diff -Nru a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
--- a/drivers/usb/storage/sddr55.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/storage/sddr55.c	Tue Oct 15 20:29:16 2002
@@ -75,10 +75,13 @@
 sddr55_bulk_transport(struct us_data *us, int direction,
 		      unsigned char *data, unsigned int len) {
 	struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra;
+	unsigned int pipe = (direction == SCSI_DATA_READ) ?
+			us->recv_bulk_pipe : us->send_bulk_pipe;
 
-	if (len)
-		info->last_access = jiffies;
-	return usb_storage_bulk_transport(us, direction, data, len, 0);
+	if (!len)
+		return USB_STOR_XFER_GOOD;
+	info->last_access = jiffies;
+	return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL);
 }
 
 /* check if card inserted, if there is, update read_only status
@@ -743,6 +746,7 @@
 	unsigned short pages;
 	struct sddr55_card_info *info;
 
+	srb->resid = 0;
 	if (!us->extra) {
 		us->extra = kmalloc(
 			sizeof(struct sddr55_card_info), GFP_NOIO);
diff -Nru a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
--- a/drivers/usb/storage/shuttle_usbat.c	Tue Oct 15 20:29:11 2002
+++ b/drivers/usb/storage/shuttle_usbat.c	Tue Oct 15 20:29:11 2002
@@ -50,12 +50,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 
-extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
-	u8 request, u8 requesttype, u16 value, u16 index,
-	void *data, u16 size);
-extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
-	unsigned int len, unsigned int *act_len);
-
 #define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) )
 #define LSB_of(s) ((s)&0xFF)
 #define MSB_of(s) ((s)>>8)
@@ -69,8 +63,8 @@
 
 	int result;
 
-	result = usb_storage_send_control(us,
-		usb_rcvctrlpipe(us->pusb_dev,0),
+	result = usb_stor_ctrl_transfer(us,
+		us->recv_ctrl_pipe,
 		access,
 		0xC0,
 		(u16)reg,
@@ -88,8 +82,8 @@
 
 	int result;
 
-	result = usb_storage_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
+	result = usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
 		access|0x01,
 		0x40,
 		short_pack(reg, content),
@@ -114,8 +108,8 @@
 		test_pattern, mask_byte, subcountL, subcountH
 	};
 
-	result = usb_storage_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
+	result = usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
 		0x80,
 		0x40,
 		0,
@@ -139,8 +133,11 @@
 		LSB_of(len), MSB_of(len)
 	};
 
-	result = usb_storage_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
+	if (!len)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	result = usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
 		0x80,
 		0x40,
 		0,
@@ -148,10 +145,11 @@
 		command,
 		8);
 
-	if (result != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
-	result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, len, use_sg);
+	result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe,
+			content, len, use_sg, NULL);
 
 	return (result == USB_STOR_XFER_GOOD ?
 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
@@ -178,8 +176,8 @@
 
  		result = usbat_read(us, USBAT_ATA, 0x17, &status);
 
-		if (result!=USB_STOR_TRANSPORT_GOOD)
-			return result;
+		if (result!=USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
 		if (status&0x01) { // check condition
 			result = usbat_read(us, USBAT_ATA, 0x10, &status);
 			return USB_STOR_TRANSPORT_FAILED;
@@ -221,8 +219,11 @@
 		LSB_of(len), MSB_of(len)
 	};
 
-	result = usb_storage_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
+	if (!len)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	result = usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
 		0x80,
 		0x40,
 		0,
@@ -230,10 +231,11 @@
 		command,
 		8);
 
-	if (result != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
-	result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE, content, len, use_sg);
+	result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe,
+			content, len, use_sg, NULL);
 
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
@@ -257,6 +259,8 @@
 	     int minutes) {
 
 	int result;
+	unsigned int pipe = (direction == SCSI_DATA_READ) ?
+			us->recv_bulk_pipe : us->send_bulk_pipe;
 
 	// Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
 	// but that's what came out of the trace every single time.
@@ -292,8 +296,8 @@
 		 * that, we just return a failure.
 		 */
 
-		result = usb_storage_send_control(us,
-			  usb_sndctrlpipe(us->pusb_dev,0),
+		result = usb_stor_ctrl_transfer(us,
+			us->send_ctrl_pipe,
 			0x80,
 			0x40,
 			0,
@@ -301,16 +305,16 @@
 			(i==0 ? command : command+8),
 			(i==0 ? 16 : 8));
 
-		if (result != USB_STOR_TRANSPORT_GOOD)
-			return result;
+		if (result != USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
 
 		if (i==0) {
 
-			result = usb_storage_bulk_transport(us,
-				SCSI_DATA_WRITE, 
-				data, num_registers*2, 0);
+			result = usb_stor_bulk_transfer_buf(us,
+					us->send_bulk_pipe,
+					data, num_registers*2, NULL);
 
-			if (result!=USB_STOR_XFER_GOOD)
+			if (result != USB_STOR_XFER_GOOD)
 				return USB_STOR_TRANSPORT_ERROR;
 
 		}
@@ -320,8 +324,8 @@
 		//	direction == SCSI_DATA_WRITE ? "out" : "in",
 		//	len, use_sg);
 
-		result = usb_storage_bulk_transport(us,
-			direction, content, len, use_sg);
+		result = usb_stor_bulk_transfer_sg(us,
+			pipe, content, len, use_sg, NULL);
 
 		/*
 		 * If we get a stall on the bulk download, we'll retry
@@ -352,8 +356,7 @@
 
 			if (direction==SCSI_DATA_READ && i==0) {
 				if (usb_stor_clear_halt(us,
-					usb_sndbulkpipe(us->pusb_dev,
-					  us->ep_out)) < 0)
+						us->send_bulk_pipe) < 0)
 					return USB_STOR_TRANSPORT_ERROR;
 			}
 
@@ -365,8 +368,8 @@
 				direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, 
 				&status);
 
-			if (result!=USB_STOR_TRANSPORT_GOOD)
-				return result;
+			if (result!=USB_STOR_XFER_GOOD)
+				return USB_STOR_TRANSPORT_ERROR;
 			if (status&0x01) // check condition
 				return USB_STOR_TRANSPORT_FAILED;
 			if (status&0x20) // device fault
@@ -412,8 +415,8 @@
 		data[1+(i<<1)] = data_out[i];
 	}
 
-	result = usb_storage_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
+	result = usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
 		0x80,
 		0x40,
 		0,
@@ -421,11 +424,11 @@
 		command,
 		8);
 
-	if (result != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
-	result = usb_storage_bulk_transport(us,
-		SCSI_DATA_WRITE, data, num_registers*2, 0);
+	result = usb_stor_bulk_transfer_buf(us,
+		us->send_bulk_pipe, data, num_registers*2, NULL);
 
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
@@ -438,8 +441,8 @@
 
 	int result;
 
-	result = usb_storage_send_control(us,
-		usb_rcvctrlpipe(us->pusb_dev,0),
+	result = usb_stor_ctrl_transfer(us,
+		us->recv_ctrl_pipe,
 		0x82,
 		0xC0,
 		0,
@@ -456,8 +459,8 @@
 
 	int result;
 
-	result = usb_storage_send_control(us,
-		usb_sndctrlpipe(us->pusb_dev,0),
+	result = usb_stor_ctrl_transfer(us,
+		us->send_ctrl_pipe,
 		0x82,
 		0x40,
 		short_pack(enable_flags, data_flags),
@@ -589,7 +592,6 @@
 
 static int hp_8200e_select_and_test_registers(struct us_data *us) {
 
-	int result;
 	int selector;
 	unsigned char status;
 
@@ -597,44 +599,44 @@
 
 	for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
 
-		if ( (result = usbat_write(us, USBAT_ATA, 0x16, selector)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
-
-		if ( (result = usbat_read(us, USBAT_ATA, 0x17, &status)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
-
-		if ( (result = usbat_read(us, USBAT_ATA, 0x16, &status)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
-
-		if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
-
-		if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
-
-		if ( (result = usbat_write(us, USBAT_ATA, 0x14, 0x55)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
-
-		if ( (result = usbat_write(us, USBAT_ATA, 0x15, 0xAA)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
-
-		if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
-
-		if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != 
-				USB_STOR_TRANSPORT_GOOD)
-			return result;
+		if (usbat_write(us, USBAT_ATA, 0x16, selector) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, 0x17, &status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, 0x16, &status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, 0x14, &status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, 0x15, &status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_write(us, USBAT_ATA, 0x14, 0x55) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_write(us, USBAT_ATA, 0x15, 0xAA) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, 0x14, &status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
+
+		if (usbat_read(us, USBAT_ATA, 0x15, &status) != 
+				USB_STOR_XFER_GOOD)
+			return USB_STOR_TRANSPORT_ERROR;
 	}
 
-	return result;
+	return USB_STOR_TRANSPORT_GOOD;
 }
 
 int init_8200e(struct us_data *us) {
@@ -644,44 +646,44 @@
 
 	// Enable peripheral control signals
 
-	if ( (result = usbat_write_user_io(us,
+	if (usbat_write_user_io(us,
 	  USBAT_UIO_OE1 | USBAT_UIO_OE0,
-	  USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	  USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 1\n");
 
 	wait_ms(2000);
 
-	if ( (result = usbat_read_user_io(us, &status)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_read_user_io(us, &status) !=
+			USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 2\n");
 
-	if ( (result = usbat_read_user_io(us, &status)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_read_user_io(us, &status) !=
+			USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 3\n");
 
 	// Reset peripheral, enable periph control signals
 	// (bring reset signal up)
 
-	if ( (result = usbat_write_user_io(us,
+	if (usbat_write_user_io(us,
 	  USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
-	  USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	  USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 4\n");
 
 	// Enable periph control signals
 	// (bring reset signal down)
 
-	if ( (result = usbat_write_user_io(us,
+	if (usbat_write_user_io(us,
 	  USBAT_UIO_OE1 | USBAT_UIO_OE0,
-	  USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	  USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 5\n");
 
@@ -689,23 +691,23 @@
 
 	// Write 0x80 to ISA port 0x3F
 
-	if ( (result = usbat_write(us, USBAT_ISA, 0x3F, 0x80)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_write(us, USBAT_ISA, 0x3F, 0x80) !=
+			USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 6\n");
 
 	// Read ISA port 0x27
 
-	if ( (result = usbat_read(us, USBAT_ISA, 0x27, &status)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_read(us, USBAT_ISA, 0x27, &status) !=
+			USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 7\n");
 
-	if ( (result = usbat_read_user_io(us, &status)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_read_user_io(us, &status) !=
+			USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 8\n");
 
@@ -715,32 +717,32 @@
 
 	US_DEBUGP("INIT 9\n");
 
-	if ( (result = usbat_read_user_io(us, &status)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_read_user_io(us, &status) !=
+			USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 10\n");
 
 	// Enable periph control signals and card detect
 
-	if ( (result = usbat_write_user_io(us,
+	if (usbat_write_user_io(us,
 	  USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0,
-	  USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
-		return result;
+	  USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 11\n");
 
-	if ( (result = usbat_read_user_io(us, &status)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_read_user_io(us, &status) !=
+			USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 12\n");
 
 	wait_ms(1400);
 
-	if ( (result = usbat_read_user_io(us, &status)) !=
-			USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_read_user_io(us, &status) !=
+			USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 13\n");
 
@@ -750,14 +752,14 @@
 
 	US_DEBUGP("INIT 14\n");
 
-	if ( (result = usbat_set_shuttle_features(us, 
-			0x83, 0x00, 0x88, 0x08, 0x15, 0x14)) !=
-			 USB_STOR_TRANSPORT_GOOD)
-		return result;
+	if (usbat_set_shuttle_features(us, 
+			0x83, 0x00, 0x88, 0x08, 0x15, 0x14) !=
+			 USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
 	US_DEBUGP("INIT 15\n");
 
-	return result;
+	return USB_STOR_TRANSPORT_ERROR;
 }
 
 /*
@@ -773,6 +775,7 @@
 	int i;
 	char string[64];
 
+	srb->resid = 0;
 	len = srb->request_bufflen;
 
 	/* Send A0 (ATA PACKET COMMAND).
@@ -863,17 +866,16 @@
 
 		// How many bytes to read in? Check cylL register
 
-		if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != 
-		    USB_STOR_TRANSPORT_GOOD) {
-			return result;
+		if (usbat_read(us, USBAT_ATA, 0x14, &status) != 
+		    	USB_STOR_XFER_GOOD) {
+			return USB_STOR_TRANSPORT_ERROR;
 		}
 
-		if (len>0xFF) { // need to read cylH also
+		if (len > 0xFF) { // need to read cylH also
 			len = status;
-			if ( (result = usbat_read(us, USBAT_ATA, 0x15,
-				&status)) !=
-				    USB_STOR_TRANSPORT_GOOD) {
-				return result;
+			if (usbat_read(us, USBAT_ATA, 0x15, &status) !=
+				    USB_STOR_XFER_GOOD) {
+				return USB_STOR_TRANSPORT_ERROR;
 			}
 			len += ((unsigned int)status)<<8;
 		}
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/storage/transport.c	Tue Oct 15 20:29:16 2002
@@ -488,7 +488,7 @@
 /* This is our function to emulate usb_bulk_msg() with enough control
  * to make aborts/resets/timeouts work
  */
-int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
+int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe,
 		      unsigned int len, unsigned int *act_len)
 {
 	int status;
@@ -515,13 +515,12 @@
  * Since many vendors in this space limit their testing to interoperability
  * with these two OSes, specification violations like this one are common.
  */
-int usb_stor_clear_halt(struct us_data *us, int pipe)
+int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
 {
 	int result;
 	int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);
 
-	result = usb_stor_control_msg(us,
-		usb_sndctrlpipe(us->pusb_dev, 0),
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
 		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
 		endp, NULL, 0);		/* note: no 3*HZ timeout */
 	US_DEBUGP("usb_stor_clear_halt: result=%d\n", result);
@@ -542,37 +541,81 @@
 }
 
 /*
- * Transfer one SCSI scatter-gather buffer via bulk transfer
+ * Transfer one control message
  *
- * Note that this function is necessary because we want the ability to
- * use scatter-gather memory.  Good performance is achieved by a combination
- * of scatter-gather and clustering (which makes each chunk bigger).
+ * This function does basically the same thing as usb_stor_control_msg()
+ * above, except that return codes are USB_STOR_XFER_xxx rather than the
+ * urb status or transfer length.
+ */
+int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
+		u8 request, u8 requesttype, u16 value, u16 index,
+		void *data, u16 size) {
+	int result;
+
+	US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x "
+			"value=%04x index=%02x len=%d\n",
+			request, requesttype, value, index, size);
+	result = usb_stor_control_msg(us, pipe, request, requesttype,
+			value, index, data, size);
+	US_DEBUGP("usb_stor_control_msg returned %d\n", result);
+
+	/* did we abort this command? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+		US_DEBUGP("-- transfer aborted\n");
+		return USB_STOR_XFER_ABORTED;
+	}
+
+	/* a stall indicates a protocol error */
+	if (result == -EPIPE) {
+		US_DEBUGP("-- stall on control pipe\n");
+		return USB_STOR_XFER_ERROR;
+	}
+
+	/* some other serious problem here */
+	if (result < 0) {
+		US_DEBUGP("-- unknown error\n");
+		return USB_STOR_XFER_ERROR;
+	}
+
+	/* was the entire command transferred? */
+	if (result < size) {
+		US_DEBUGP("-- transferred only %d bytes\n", result);
+		return USB_STOR_XFER_SHORT;
+	}
+
+	US_DEBUGP("-- transfer completed successfully\n");
+	return USB_STOR_XFER_GOOD;
+}
+
+/*
+ * Transfer one buffer via bulk transfer
+ *
+ * This function does basically the same thing as usb_stor_bulk_msg()
+ * above, except that:
  *
- * Note that the lower layer will always retry when a NAK occurs, up to the
- * timeout limit.  Thus we don't have to worry about it for individual
- * packets.
+ *	1.  If the bulk pipe stalls during the transfer, the halt is
+ *	    automatically cleared;
+ *	2.  Return codes are USB_STOR_XFER_xxx rather than the
+ *	    urb status or transfer length.
  */
-int usb_stor_transfer_partial(struct us_data *us, char *buf, int length)
+int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+	char *buf, unsigned int length, unsigned int *act_len)
 {
 	int result;
 	int partial;
-	int pipe;
-
-	/* calculate the appropriate pipe information */
-	if (us->srb->sc_data_direction == SCSI_DATA_READ)
-		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-	else
-		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
 
 	/* transfer the data */
-	US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length);
+	US_DEBUGP("usb_stor_bulk_transfer_buf(): xfer %d bytes\n", length);
 	result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
 	US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
 		  result, partial, length);
+	if (act_len)
+		*act_len = partial;
 
 	/* if we stall, we need to clear it before we go on */
 	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x,"
+				" stalled at %d bytes\n", pipe, partial);
 		if (usb_stor_clear_halt(us, pipe) < 0)
 			return USB_STOR_XFER_ERROR;
 		return USB_STOR_XFER_STALLED;
@@ -580,25 +623,25 @@
 
 	/* did we abort this command? */
 	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-		US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n");
+		US_DEBUGP("-- transfer aborted\n");
 		return USB_STOR_XFER_ABORTED;
 	}
 
 	/* NAK - that means we've retried a few times already */
 	if (result == -ETIMEDOUT) {
-		US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n");
+		US_DEBUGP("-- device NAKed\n");
 		return USB_STOR_XFER_ERROR;
 	}
 
 	/* the catch-all error case */
 	if (result) {
-		US_DEBUGP("usb_stor_transfer_partial(): unknown error\n");
+		US_DEBUGP("-- unknown error\n");
 		return USB_STOR_XFER_ERROR;
 	}
 
 	/* did we send all the data? */
 	if (partial == length) {
-		US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n");
+		US_DEBUGP("-- transfer complete\n");
 		return USB_STOR_XFER_GOOD;
 	}
 
@@ -611,59 +654,51 @@
  * Transfer an entire SCSI command's worth of data payload over the bulk
  * pipe.
  *
- * Note that this uses usb_stor_transfer_partial to achieve its goals -- this
+ * Note that this uses usb_stor_transfer_buf to achieve its goals -- this
  * function simply determines if we're going to use scatter-gather or not,
  * and acts appropriately.  For now, it also re-interprets the error codes.
  */
-void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us)
+int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,
+		char *buf, unsigned int length_left, int use_sg, int *residual)
 {
 	int i;
 	int result = -1;
 	struct scatterlist *sg;
-	unsigned int total_transferred = 0;
-	unsigned int transfer_amount;
-
-	/* calculate how much we want to transfer */
-	transfer_amount = usb_stor_transfer_length(srb);
-
-	/* was someone foolish enough to request more data than available
-	 * buffer space? */
-	if (transfer_amount > srb->request_bufflen)
-		transfer_amount = srb->request_bufflen;
+	unsigned int amount;
+	unsigned int partial;
 
 	/* are we scatter-gathering? */
-	if (srb->use_sg) {
+	if (use_sg) {
 
 		/* loop over all the scatter gather structures and 
 		 * make the appropriate requests for each, until done
 		 */
-		sg = (struct scatterlist *) srb->request_buffer;
-		for (i = 0; i < srb->use_sg; i++) {
+		sg = (struct scatterlist *) buf;
+		for (i = 0; (i < use_sg) && (length_left > 0); (i++, ++sg)) {
 
 			/* transfer the lesser of the next buffer or the
 			 * remaining data */
-			if (transfer_amount - total_transferred >= 
-					sg[i].length) {
-				result = usb_stor_transfer_partial(us,
-						sg_address(sg[i]), sg[i].length);
-				total_transferred += sg[i].length;
-			} else
-				result = usb_stor_transfer_partial(us,
-						sg_address(sg[i]),
-						transfer_amount - total_transferred);
+			amount = sg->length < length_left ?
+					sg->length : length_left;
+			result = usb_stor_bulk_transfer_buf(us, pipe,
+					sg_address(*sg), amount, &partial);
+			length_left -= partial;
 
 			/* if we get an error, end the loop here */
-			if (result)
+			if (result != USB_STOR_XFER_GOOD)
 				break;
 		}
-	}
-	else
+	} else {
 		/* no scatter-gather, just make the request */
-		result = usb_stor_transfer_partial(us, srb->request_buffer, 
-					     transfer_amount);
+		result = usb_stor_bulk_transfer_buf(us, pipe, buf, 
+				length_left, &partial);
+		length_left -= partial;
+	}
 
-	/* return the result in the data structure itself */
-	srb->result = result;
+	/* store the residual and return the error code */
+	if (residual)
+		*residual = length_left;
+	return result;
 }
 
 /***********************************************************************
@@ -742,7 +777,7 @@
 	 * Also, if we have a short transfer on a command that can't have
 	 * a short transfer, we're going to do this.
 	 */
-	if ((srb->result == USB_STOR_XFER_SHORT) &&
+	if ((srb->resid > 0) &&
 	    !((srb->cmnd[0] == REQUEST_SENSE) ||
 	      (srb->cmnd[0] == INQUIRY) ||
 	      (srb->cmnd[0] == MODE_SENSE) ||
@@ -974,6 +1009,7 @@
 
 int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
+	unsigned int transfer_length = usb_stor_transfer_length(srb);
 	int result;
 
 	/* re-initialize the mutex so that we avoid any races with
@@ -985,14 +1021,14 @@
 
 	/* COMMAND STAGE */
 	/* let's send the command via the control pipe */
-	result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+	result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
 				      US_CBI_ADSC, 
 				      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
 				      us->ifnum, srb->cmnd, srb->cmd_len);
 
 	/* check the return code for the command */
-	US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
-	if (result < 0) {
+	US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
+	if (result != USB_STOR_XFER_GOOD) {
 		/* Reset flag for status notification */
 		clear_bit(US_FLIDX_IP_WANTED, &us->flags);
 	}
@@ -1003,22 +1039,16 @@
 		return USB_STOR_TRANSPORT_ABORTED;
 	}
 
-	/* a stall indicates a protocol error */
-	if (result == -EPIPE) {
-		US_DEBUGP("-- Stall on control pipe\n");
-		return USB_STOR_TRANSPORT_ERROR;
-	}
-
-	if (result < 0) {
+	if (result != USB_STOR_XFER_GOOD) {
 		/* Uh oh... serious problem here */
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
 	/* DATA STAGE */
 	/* transfer the data payload for this command, if one exists*/
-	if (usb_stor_transfer_length(srb)) {
-		usb_stor_transfer(srb, us);
-		result = srb->result;
+	if (transfer_length > 0) {
+		result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe,
+				srb, transfer_length);
 		US_DEBUGP("CBI data stage result is 0x%x\n", result);
 
 		/* report any errors */
@@ -1093,39 +1123,34 @@
  */
 int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
+	unsigned int transfer_length = usb_stor_transfer_length(srb);
 	int result;
 
 	/* COMMAND STAGE */
 	/* let's send the command via the control pipe */
-	result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0),
+	result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe,
 				      US_CBI_ADSC, 
 				      USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, 
 				      us->ifnum, srb->cmnd, srb->cmd_len);
 
 	/* check the return code for the command */
-	US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result);
-	if (result < 0) {
-		/* did we abort this command? */
-		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-			US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n");
-			return USB_STOR_TRANSPORT_ABORTED;
-		}
+	US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result);
 
-		/* a stall indicates a protocol error */
-		if (result == -EPIPE) {
-			US_DEBUGP("-- Stall on control pipe\n");
-			return USB_STOR_TRANSPORT_ERROR;
-		}
+	/* did we abort this command? */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+		US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n");
+		return USB_STOR_TRANSPORT_ABORTED;
 
+	if (result != USB_STOR_XFER_GOOD) {
 		/* Uh oh... serious problem here */
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
 	/* DATA STAGE */
 	/* transfer the data payload for this command, if one exists*/
-	if (usb_stor_transfer_length(srb)) {
-		usb_stor_transfer(srb, us);
-		result = srb->result;
+	if (transfer_length)
+		result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe,
+				srb, transfer_length);
 		US_DEBUGP("CB data stage result is 0x%x\n", result);
 
 		/* report any errors */
@@ -1153,12 +1178,12 @@
 {
 	unsigned char data;
 	int result;
-	int pipe;
 
-	/* issue the command -- use usb_control_msg() because
-	 * this is not a scsi queued-command */
-	pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
-	result = usb_control_msg(us->pusb_dev, pipe,
+	/* Issue the command -- use usb_control_msg() because this is
+	 * not a scsi queued-command.  Also note that at this point the
+	 * cached pipe values have not yet been stored. */
+	result = usb_control_msg(us->pusb_dev,
+				 usb_rcvctrlpipe(us->pusb_dev, 0),
 				 US_BULK_GET_MAX_LUN, 
 				 USB_DIR_IN | USB_TYPE_CLASS | 
 				 USB_RECIP_INTERFACE,
@@ -1179,13 +1204,13 @@
 {
 	struct bulk_cb_wrap bcb;
 	struct bulk_cs_wrap bcs;
+	unsigned int transfer_length = usb_stor_transfer_length(srb);
 	int result;
-	int pipe;
 	int partial;
 
 	/* set up the command wrapper */
 	bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
-	bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb));
+	bcb.DataTransferLength = cpu_to_le32(transfer_length);
 	bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
 	bcb.Tag = srb->serial_number;
 	bcb.Lun = srb->cmnd[1] >> 5;
@@ -1193,9 +1218,6 @@
 		bcb.Lun |= srb->target << 4;
 	bcb.Length = srb->cmd_len;
 
-	/* construct the pipe handle */
-	pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-
 	/* copy the command payload */
 	memset(bcb.CDB, 0, sizeof(bcb.CDB));
 	memcpy(bcb.CDB, srb->cmnd, bcb.Length);
@@ -1205,8 +1227,8 @@
 		  le32_to_cpu(bcb.Signature), bcb.Tag,
 		  (bcb.Lun >> 4), (bcb.Lun & 0x0F), 
 		  bcb.DataTransferLength, bcb.Flags, bcb.Length);
-	result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, 
-				   &partial);
+	result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe,
+				US_BULK_CB_WRAP_LEN, &partial);
 	US_DEBUGP("Bulk command transfer result=%d\n", result);
 
 	/* did we abort this command? */
@@ -1217,47 +1239,45 @@
 
 	/* if we stall, we need to clear it before we go on */
 	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		result = usb_stor_clear_halt(us, pipe);
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
+				us->send_bulk_pipe);
+		result = usb_stor_clear_halt(us, us->send_bulk_pipe);
 
 		/* did we abort this command? */
 		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 			US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
 			return USB_STOR_TRANSPORT_ABORTED;
 		}
-		if (result < 0)
-			return USB_STOR_TRANSPORT_ERROR;
-		result = -EPIPE;
+		return USB_STOR_TRANSPORT_ERROR;
 	} else if (result) {
 		/* unknown error -- we've got a problem */
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
-	/* if the command transfered well, then we go to the data stage */
-	if (result == 0) {
-		/* send/receive data payload, if there is any */
-		if (bcb.DataTransferLength) {
-			usb_stor_transfer(srb, us);
-			result = srb->result;
-			US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+	/* DATA STAGE */
+	/* send/receive data payload, if there is any */
+	if (transfer_length) {
+		unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? 
+				us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_transfer_srb(us, pipe, srb,
+					transfer_length);
+		US_DEBUGP("Bulk data transfer result 0x%x\n", result);
 
-			/* if it was aborted, we need to indicate that */
-			if (result == USB_STOR_XFER_ABORTED)
-				return USB_STOR_TRANSPORT_ABORTED;
-		}
+		/* if it was aborted, we need to indicate that */
+		if (result == USB_STOR_XFER_ABORTED)
+			return USB_STOR_TRANSPORT_ABORTED;
+		if (result == USB_STOR_XFER_ERROR)
+			return USB_STOR_TRANSPORT_ERROR;
 	}
 
 	/* See flow chart on pg 15 of the Bulk Only Transport spec for
 	 * an explanation of how this code works.
 	 */
 
-	/* construct the pipe handle */
-	pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
-
 	/* get CSW for device status */
 	US_DEBUGP("Attempting to get CSW...\n");
-	result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, 
-				   &partial);
+	result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe,
+				US_BULK_CS_WRAP_LEN, &partial);
 
 	/* did we abort this command? */
 	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
@@ -1267,8 +1287,9 @@
 
 	/* did the attempt to read the CSW fail? */
 	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		result = usb_stor_clear_halt(us, pipe);
+		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
+				us->recv_bulk_pipe);
+		result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
 
 		/* did we abort this command? */
 		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
@@ -1280,7 +1301,7 @@
 
 		/* get the status again */
 		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
-		result = usb_stor_bulk_msg(us, &bcs, pipe,
+		result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe,
 					   US_BULK_CS_WRAP_LEN, &partial);
 
 		/* did we abort this command? */
@@ -1291,8 +1312,9 @@
 
 		/* if it fails again, we need a reset and return an error*/
 		if (result == -EPIPE) {
-			US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
-			result = usb_stor_clear_halt(us, pipe);
+			US_DEBUGP("clearing halt for pipe 0x%x\n",
+					us->recv_bulk_pipe);
+			result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
 
 			/* did we abort this command? */
 			if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
@@ -1364,7 +1386,7 @@
 	 *  following a powerup or USB attach event. */
 
 	/* Use usb_control_msg() because this is not a queued-command */
-	result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0),
+	result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe,
 			request, requesttype, value, index, data, size,
 			20*HZ);
 	if (result < 0)
@@ -1377,14 +1399,12 @@
 
 	/* Use usb_clear_halt() because this is not a queued-command */
 	US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
-	result = usb_clear_halt(us->pusb_dev,
-		usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	result = usb_clear_halt(us->pusb_dev, us->recv_bulk_pipe);
 	if (result < 0)
 		goto Done;
 
 	US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
-	result = usb_clear_halt(us->pusb_dev,
-		usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+	result = usb_clear_halt(us->pusb_dev, us->send_bulk_pipe);
 
 	Done:
 
diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
--- a/drivers/usb/storage/transport.h	Tue Oct 15 20:29:16 2002
+++ b/drivers/usb/storage/transport.h	Tue Oct 15 20:29:16 2002
@@ -115,7 +115,7 @@
 #define US_BULK_GET_MAX_LUN	0xfe
 
 /*
- * usb_stor_transfer() return codes, in order of severity
+ * usb_stor_bulk_transfer_xxx() return codes, in order of severity
  */
 #define USB_STOR_XFER_GOOD		0  /* good transfer                 */
 #define USB_STOR_XFER_SHORT		1  /* transfered less than expected */
@@ -151,14 +151,26 @@
 extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*);
 extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*);
 extern void usb_stor_abort_transport(struct us_data*);
-extern int usb_stor_transfer_partial(struct us_data*, char*, int);
 
-extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
-		unsigned int len, unsigned int *act_len);
+extern int usb_stor_bulk_msg(struct us_data *us, void *data,
+		unsigned int pipe, unsigned int len, unsigned int *act_len);
 extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
 		u8 request, u8 requesttype, u16 value, u16 index,
 		void *data, u16 size);
 
-extern int usb_stor_clear_halt(struct us_data*, int );
-extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*);
+extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe);
+extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
+		u8 request, u8 requesttype, u16 value, u16 index,
+		void *data, u16 size);
+extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
+		char *buf, unsigned int length, unsigned int *act_len);
+extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
+		char *buf, unsigned int length, int use_sg, int *residual);
+
+static __inline__ int usb_stor_bulk_transfer_srb(struct us_data *us,
+		unsigned int pipe, Scsi_Cmnd *srb, unsigned int length) {
+	return usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer,
+			length, srb->use_sg, &srb->resid);
+}
+
 #endif
diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Tue Oct 15 20:29:14 2002
+++ b/drivers/usb/storage/usb.c	Tue Oct 15 20:29:14 2002
@@ -525,6 +525,12 @@
 	int maxp;
 	int result;
 
+	/* calculate and store the pipe values */
+	ss->send_bulk_pipe = usb_sndbulkpipe(ss->pusb_dev, ss->ep_out);
+	ss->recv_bulk_pipe = usb_rcvbulkpipe(ss->pusb_dev, ss->ep_in);
+	ss->send_ctrl_pipe = usb_sndctrlpipe(ss->pusb_dev, 0);
+	ss->recv_ctrl_pipe = usb_rcvctrlpipe(ss->pusb_dev, 0);
+
 	/* allocate the usb_ctrlrequest for control packets */
 	US_DEBUGP("Allocating usb_ctrlrequest\n");
 	ss->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Tue Oct 15 20:29:17 2002
+++ b/drivers/usb/storage/usb.h	Tue Oct 15 20:29:17 2002
@@ -134,6 +134,10 @@
 	struct semaphore	dev_semaphore;	 /* protect pusb_dev */
 	struct usb_device	*pusb_dev;	 /* this usb_device */
 	unsigned long		flags;		 /* from filter initially */
+	unsigned int		send_bulk_pipe;	 /* cached pipe values */
+	unsigned int		recv_bulk_pipe;
+	unsigned int		send_ctrl_pipe;
+	unsigned int		recv_ctrl_pipe;
 
 	/* information about the device -- always good */
 	char			vendor[USB_STOR_STRING_LEN];
diff -Nru a/drivers/video/acornfb.c b/drivers/video/acornfb.c
--- a/drivers/video/acornfb.c	Tue Oct 15 20:29:16 2002
+++ b/drivers/video/acornfb.c	Tue Oct 15 20:29:16 2002
@@ -380,7 +380,7 @@
  *  vder : >= vdsr
  */
 static void
-acornfb_set_timing(struct fb_var_screeninfo *var)
+acornfb_set_timing(struct fb_info *info, struct fb_var_screeninfo *var)
 {
 	struct vidc_timing vidc;
 	u_int vcr, fsize;
@@ -470,7 +470,7 @@
 
 	words_per_line = var->xres * var->bits_per_pixel / 32;
 
-	if (current_par.using_vram && current_par.screen_size == 2048*1024)
+	if (current_par.using_vram && info->fix.smem_len == 2048*1024)
 		words_per_line /= 2;
 
 	/* RiscPC doesn't use the VIDC's VRAM control. */
@@ -549,7 +549,7 @@
  * the resolution to fit the rules.
  */
 static int
-acornfb_adjust_timing(struct fb_var_screeninfo *var, int con)
+acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, int con)
 {
 	u_int font_line_len;
 	u_int fontht;
@@ -595,13 +595,13 @@
 	 * If minimum screen size is greater than that we have
 	 * available, reject it.
 	 */
-	if (min_size > current_par.screen_size)
+	if (min_size > info->fix.smem_len)
 		return -EINVAL;
 
 	/* Find int 'y', such that y * fll == s * sam < maxsize
 	 * y = s * sam / fll; s = maxsize / sam
 	 */
-	for (size = current_par.screen_size;
+	for (size = info->fix.smem_len;
 	     nr_y = size / font_line_len, min_size <= size;
 	     size -= sam_size) {
 		if (nr_y * font_line_len == size)
@@ -614,14 +614,14 @@
 			/*
 			 * failed, use ypan
 			 */
-			size = current_par.screen_size;
+			size = info->fix.smem_len;
 			var->yres_virtual = size / (font_line_len / fontht);
 		} else
 			var->yres_virtual = nr_y;
 	} else if (var->yres_virtual > nr_y)
 		var->yres_virtual = nr_y;
 
-	current_par.screen_end = current_par.screen_base_p + size;
+	current_par.screen_end = info->fix.smem_start + size;
 
 	/*
 	 * Fix yres & yoffset if needed.
@@ -691,7 +691,7 @@
 }
 
 static inline void
-acornfb_update_dma(struct fb_var_screeninfo *var)
+acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var)
 {
 	int off = (var->yoffset * var->xres_virtual *
 		   var->bits_per_pixel) >> 3;
@@ -699,7 +699,7 @@
 #if defined(HAS_MEMC)
 	memc_write(VDMA_INIT, off >> 2);
 #elif defined(HAS_IOMD)
-	iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT);
+	iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT);
 #endif
 }
 
@@ -792,7 +792,7 @@
 }
 
 static int
-acornfb_decode_var(struct fb_var_screeninfo *var, int con)
+acornfb_decode_var(struct fb_info *info, struct fb_var_screeninfo *var, int con)
 {
 	int err;
 
@@ -865,7 +865,7 @@
 	 * Validate and adjust the resolution to
 	 * match the video generator hardware.
 	 */
-	err = acornfb_adjust_timing(var, con);
+	err = acornfb_adjust_timing(info, var, con);
 	if (err)
 		return err;
 
@@ -877,55 +877,18 @@
 }
 
 static int
-acornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
-{
-	struct display *display;
-
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, "Acorn");
-
-	if (con >= 0)
-		display = fb_display + con;
-	else
-		display = &global_disp;
-
-	fix->smem_start	 = current_par.screen_base_p;
-	fix->smem_len	 = current_par.screen_size;
-	fix->type	 = display->type;
-	fix->type_aux	 = display->type_aux;
-	fix->xpanstep	 = 0;
-	fix->ypanstep	 = display->ypanstep;
-	fix->ywrapstep	 = display->ywrapstep;
-	fix->visual	 = display->visual;
-	fix->line_length = display->line_length;
-	fix->accel	 = FB_ACCEL_NONE;
-
-	return 0;
-}
-
-static int
-acornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
-{
-	if (con == -1) {
-		*var = global_disp.var;
-	} else
-		*var = fb_display[con].var;
-
-	return 0;
-}
-
-static int
 acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
 	struct display *display;
-	int err, chgvar = 0;
+	unsigned int visual, chgvar = 0;
+	int err;
 
 	if (con >= 0)
 		display = fb_display + con;
 	else
 		display = &global_disp;
 
-	err = acornfb_decode_var(var, con);
+	err = acornfb_decode_var(info, var, con);
 	if (err)
 		return err;
 
@@ -969,21 +932,21 @@
 	case 1:
 		current_par.palette_size = 2;
 		display->dispsw = &fbcon_mfb;
-		display->visual = FB_VISUAL_MONO10;
+		visual = FB_VISUAL_MONO10;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB2
 	case 2:
 		current_par.palette_size = 4;
 		display->dispsw = &fbcon_cfb2;
-		display->visual = FB_VISUAL_PSEUDOCOLOR;
+		visual = FB_VISUAL_PSEUDOCOLOR;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB4
 	case 4:
 		current_par.palette_size = 16;
 		display->dispsw = &fbcon_cfb4;
-		display->visual = FB_VISUAL_PSEUDOCOLOR;
+		visual = FB_VISUAL_PSEUDOCOLOR;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB8
@@ -991,9 +954,9 @@
 		current_par.palette_size = VIDC_PALETTE_SIZE;
 		display->dispsw = &fbcon_cfb8;
 #ifdef HAS_VIDC
-		display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+		visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
 #else
-		display->visual = FB_VISUAL_PSEUDOCOLOR;
+		visual = FB_VISUAL_PSEUDOCOLOR;
 #endif
 		break;
 #endif
@@ -1002,7 +965,7 @@
 		current_par.palette_size = 32;
 		display->dispsw = &fbcon_cfb16;
 		display->dispsw_data = current_par.cmap.cfb16;
-		display->visual = FB_VISUAL_DIRECTCOLOR;
+		visual = FB_VISUAL_DIRECTCOLOR;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -1010,22 +973,17 @@
 		current_par.palette_size = VIDC_PALETTE_SIZE;
 		display->dispsw = &fbcon_cfb32;
 		display->dispsw_data = current_par.cmap.cfb32;
-		display->visual = FB_VISUAL_TRUECOLOR;
+		visual = FB_VISUAL_TRUECOLOR;
 		break;
 #endif
 	default:
 		display->dispsw = &fbcon_dummy;
+		visual = FB_VISUAL_MONO10;
 		break;
 	}
 
-	info->screen_base	= (char *)current_par.screen_base;
-	display->type		= FB_TYPE_PACKED_PIXELS;
-	display->type_aux	= 0;
-	display->ypanstep	= 1;
-	display->ywrapstep	= 1;
-	display->line_length	=
 	display->next_line      = (var->xres * var->bits_per_pixel) / 8;
-	display->can_soft_blank	= display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
+	display->can_soft_blank	= visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
 	display->inverse	= 0;
 
 	if (chgvar && info && info->changevar)
@@ -1036,16 +994,18 @@
 		unsigned long start, size;
 		int control;
 
+		info->fix.visual = visual;
+
 #if defined(HAS_MEMC)
 		start   = 0;
-		size    = current_par.screen_size - VDMA_XFERSIZE;
+		size    = info->fix.smem_len - VDMA_XFERSIZE;
 		control = 0;
 
 		memc_write(VDMA_START, start);
 		memc_write(VDMA_END, size >> 2);
 #elif defined(HAS_IOMD)
 
-		start = current_par.screen_base_p;
+		start = info->fix.smem_start;
 		size  = current_par.screen_end;
 
 		if (current_par.using_vram) {
@@ -1060,8 +1020,8 @@
 		iomd_writel(size,    IOMD_VIDEND);
 		iomd_writel(control, IOMD_VIDCR);
 #endif
-		acornfb_update_dma(var);
-		acornfb_set_timing(var);
+		acornfb_update_dma(info, var);
+		acornfb_set_timing(info, var);
 
 		if (display->cmap.len)
 			cmap = &display->cmap;
@@ -1090,7 +1050,7 @@
 	if (y_bottom > fb_display[con].var.yres_virtual)
 		return -EINVAL;
 
-	acornfb_update_dma(var);
+	acornfb_update_dma(info, var);
 
 	fb_display[con].var.yoffset = var->yoffset;
 	if (var->vmode & FB_VMODE_YWRAP)
@@ -1147,8 +1107,8 @@
 
 	off = vma->vm_pgoff << PAGE_SHIFT;
 
-	start = current_par.screen_base_p;
-	len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size;
+	start = info->fix.smem_start;
+	len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len;
 	start &= PAGE_MASK;
 	if ((vma->vm_end - vma->vm_start + off) > len)
 		return -EINVAL;
@@ -1176,23 +1136,21 @@
 }
 
 static struct fb_ops acornfb_ops = {
-	.owner =	THIS_MODULE,
-	.fb_get_fix =	acornfb_get_fix,
-	.fb_get_var =	acornfb_get_var,
-	.fb_set_var =	acornfb_set_var,
-	.fb_get_cmap =	acornfb_get_cmap,
-	.fb_set_cmap =	gen_set_cmap,
-	.fb_setcolreg =	acornfb_setcolreg,
-	.fb_pan_display =acornfb_pan_display,
-	.fb_blank =	acornfb_blank,
-	.fb_mmap =	acornfb_mmap,
+	.owner		= THIS_MODULE,
+	.fb_set_var	= acornfb_set_var,
+	.fb_get_cmap	= acornfb_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
+	.fb_setcolreg	= acornfb_setcolreg,
+	.fb_pan_display	= acornfb_pan_display,
+	.fb_blank	= acornfb_blank,
+	.fb_mmap	= acornfb_mmap,
 };
 
 static int
 acornfb_updatevar(int con, struct fb_info *info)
 {
 	if (con == info->currcon)
-		acornfb_update_dma(&fb_display[con].var);
+		acornfb_update_dma(info, &fb_display[con].var);
 
 	return 0;
 }
@@ -1302,15 +1260,24 @@
 	strcpy(fb_info.modename, "Acorn");
 	strcpy(fb_info.fontname, "Acorn8x8");
 
-	fb_info.node		   = NODEV;
-	fb_info.fbops		   = &acornfb_ops;
-	fb_info.disp		   = &global_disp;
-	fb_info.changevar	   = NULL;
-	fb_info.switch_con	   = acornfb_switch;
-	fb_info.updatevar	   = acornfb_updatevar;
-	fb_info.flags		   = FBINFO_FLAG_DEFAULT;
+	fb_info.node		= NODEV;
+	fb_info.fbops		= &acornfb_ops;
+	fb_info.disp		= &global_disp;
+	fb_info.changevar	= NULL;
+	fb_info.switch_con	= acornfb_switch;
+	fb_info.updatevar	= acornfb_updatevar;
+	fb_info.flags		= FBINFO_FLAG_DEFAULT;
+
+	strcpy(fb_info.fix.id, "Acorn");
+	fb_info.fix.type	= FB_TYPE_PACKED_PIXELS;
+	fb_info.fix.type_aux	= 0;
+	fb_info.fix.xpanstep	= 0;
+	fb_info.fix.ypanstep	= 1;
+	fb_info.fix.ywrapstep	= 1;
+	fb_info.fix.line_length	= 0;
+	fb_info.fix.accel	= FB_ACCEL_NONE;
 
-	global_disp.dispsw	   = &fbcon_dummy;
+	global_disp.dispsw	= &fbcon_dummy;
 
 	/*
 	 * setup initial parameters
@@ -1618,10 +1585,10 @@
 		}
 	}
 
-	fb_info.currcon	   = -1;
-	current_par.screen_base	   = SCREEN_BASE;
-	current_par.screen_base_p  = SCREEN_START;
-	current_par.using_vram     = 0;
+	fb_info.currcon	       = -1;
+	fb_info.screen_base    = (char *)SCREEN_BASE;
+	fb_info.fix.smem_start = SCREEN_START;
+	current_par.using_vram = 0;
 
 	/*
 	 * If vram_size is set, we are using VRAM in
@@ -1653,27 +1620,26 @@
 		 * VRAM.  Archimedes/A5000 machines use a
 		 * fixed address for their framebuffers.
 		 */
-		int order = 0;
-		unsigned long page, top;
-		while (size > (PAGE_SIZE * (1 << order)))
-			order++;
-		current_par.screen_base = __get_free_pages(GFP_KERNEL, order);
-		if (current_par.screen_base == 0) {
+		unsigned long page, top, base;
+		int order = get_order(size);
+
+		base = __get_free_pages(GFP_KERNEL, order);
+		if (base == 0) {
 			printk(KERN_ERR "acornfb: unable to allocate screen "
 			       "memory\n");
 			return -ENOMEM;
 		}
-		top = current_par.screen_base + (PAGE_SIZE * (1 << order));
+		top = base + (PAGE_SIZE << order);
+
 		/* Mark the framebuffer pages as reserved so mmap will work. */
-		for (page = current_par.screen_base; 
-		     page < PAGE_ALIGN(current_par.screen_base + size);
-		     page += PAGE_SIZE)
+		for (page = base; page < PAGE_ALIGN(base + size); page += PAGE_SIZE)
 			SetPageReserved(virt_to_page(page));
 		/* Hand back any excess pages that we allocated. */
-		for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE)
+		for (page = base + size; page < top; page += PAGE_SIZE)
 			free_page(page);
-		current_par.screen_base_p =
-			virt_to_phys((void *)current_par.screen_base);
+
+		fb_info.screen_base = (char *)base;
+		fb_info.fix.smem_start = virt_to_phys(fb_info.screen_base);
 	}
 #endif
 #if defined(HAS_VIDC)
@@ -1683,7 +1649,7 @@
 	free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
 #endif
 	
-	current_par.screen_size	   = size;
+	fb_info.fix.smem_len = size;
 	current_par.palette_size   = VIDC_PALETTE_SIZE;
 
 	/*
@@ -1734,9 +1700,9 @@
 	v_sync = h_sync / (init_var.yres + init_var.upper_margin +
 		 init_var.lower_margin + init_var.vsync_len);
 
-	printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, "
+	printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, "
 		"%d.%03dkHz, %dHz\n",
-		current_par.screen_size / 1024,
+		fb_info.fix.smem_len / 1024,
 		current_par.using_vram ? 'V' : 'D',
 		VIDC_NAME, init_var.xres, init_var.yres,
 		h_sync / 1000, h_sync % 1000, v_sync);
diff -Nru a/drivers/video/acornfb.h b/drivers/video/acornfb.h
--- a/drivers/video/acornfb.h	Tue Oct 15 20:29:17 2002
+++ b/drivers/video/acornfb.h	Tue Oct 15 20:29:17 2002
@@ -47,10 +47,7 @@
 };
 
 struct acornfb_par {
-	unsigned long	screen_base;
-	unsigned long	screen_base_p;
 	unsigned long	screen_end;
-	unsigned long	screen_size;
 	unsigned int	dram_size;
 	unsigned int	vram_half_sam;
 	unsigned int	palette_size;
diff -Nru a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
--- a/drivers/video/clps711xfb.c	Tue Oct 15 20:29:12 2002
+++ b/drivers/video/clps711xfb.c	Tue Oct 15 20:29:12 2002
@@ -25,6 +25,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/delay.h>
 
 #include <video/fbcon.h>
 
@@ -37,7 +38,7 @@
 
 struct fb_info	*cfb;
 
-#define CMAP_SIZE	16
+#define CMAP_MAX_SIZE	16
 
 /* The /proc entry for the backlight. */
 static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL;
@@ -48,6 +49,13 @@
 		const char *buffer, unsigned long count, void *data);
 
 /*
+ * LCD AC Prescale.  This comes from the LCD panel manufacturers specifications.
+ * This determines how many clocks + 1 of CL1 before the M signal toggles.
+ * The number of lines on the display must not be divisible by this number.
+ */
+static unsigned int lcd_ac_prescale = 13;
+
+/*
  *    Set a single color register. Return != 0 for invalid regno.
  */
 static int
@@ -56,7 +64,7 @@
 {
 	unsigned int level, mask, shift, pal;
 
-	if (regno >= CMAP_SIZE)
+	if (regno >= (1 << info->var.bits_per_pixel))
 		return 1;
 
 	/* gray = 0.30*R + 0.58*G + 0.11*B */
@@ -104,6 +112,8 @@
 
 	if (var->bits_per_pixel > 4) 
 		return -EINVAL;
+
+	return 0;
 }
 
 /*
@@ -112,32 +122,46 @@
 static int 
 clps7111fb_set_par(struct fb_info *info)
 {
-	unsigned int lcdcon, syscon;
+	unsigned int lcdcon, syscon, pixclock;
 
-	switch (var->bits_per_pixel) {
+	switch (info->var.bits_per_pixel) {
 	case 1:
-		info->fix.visual	= FB_VISUAL_MONO01;
+		info->fix.visual = FB_VISUAL_MONO01;
 		break;
 	case 2:
-		info->fix.visual	= FB_VISUAL_PSEUDOCOLOR;
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 		break;
 	case 4:
-		info->fix.visual	= FB_VISUAL_PSEUDOCOLOR;
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 		break;
 	}
 
 	info->fix.line_length = info->var.xres_virtual * info->var.bits_per_pixel / 8;
 
-	/*
-	 * LCDCON must only be changed while the LCD is disabled
-	 */
 	lcdcon = (info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel) / 128 - 1;
 	lcdcon |= ((info->var.xres_virtual / 16) - 1) << 13;
-	lcdcon |= 2 << 19;
-	lcdcon |= 13 << 25;
-	lcdcon |= LCDCON_GSEN;
-	lcdcon |= LCDCON_GSMD;
+	lcdcon |= lcd_ac_prescale << 25;
+
+	/*
+	 * Calculate pixel prescale value from the pixclock.  This is:
+	 *  36.864MHz / pixclock_mhz - 1.
+	 * However, pixclock is in picoseconds, so this ends up being:
+	 *  36864000 * pixclock_ps / 10^12 - 1
+	 * and this will overflow the 32-bit math.  We perform this as
+	 * (9 * 4096000 == 36864000):
+	 *  pixclock_ps * 9 * (4096000 / 10^12) - 1
+	 */
+	pixclock = 9 * info->var.pixclock / 244140 - 1;
+	lcdcon |= pixclock << 19;
+
+	if (info->var.bits_per_pixel == 4)
+		lcdcon |= LCDCON_GSMD;
+	if (info->var.bits_per_pixel >= 2)
+		lcdcon |= LCDCON_GSEN;
 
+	/*
+	 * LCDCON must only be changed while the LCD is disabled
+	 */
 	syscon = clps_readl(SYSCON1);
 	clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1);
 	clps_writel(lcdcon, LCDCON);
@@ -149,8 +173,6 @@
 {
     	if (blank) {
 		if (machine_is_edb7211()) {
-			int i;
-
 			/* Turn off the LCD backlight. */
 			clps_writeb(clps_readb(PDDR) & ~EDB_PD3_LCDBL, PDDR);
 
@@ -169,8 +191,6 @@
 		}
 	} else {
 		if (machine_is_edb7211()) {
-			int i;
-
 			/* Power up the LCD controller. */
 			clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN,
 					SYSCON1);
@@ -256,6 +276,93 @@
 	return count;
 }
 
+static void __init clps711x_guess_lcd_params(struct fb_info *info)
+{
+	unsigned int lcdcon, syscon, size;
+	unsigned long phys_base = PAGE_OFFSET;
+	void *virt_base = (void *)PAGE_OFFSET;
+
+	info->var.xres_virtual	 = 640;
+	info->var.yres_virtual	 = 240;
+	info->var.bits_per_pixel = 4;
+	info->var.activate	 = FB_ACTIVATE_NOW;
+	info->var.height	 = -1;
+	info->var.width		 = -1;
+	info->var.pixclock	 = 93006; /* 10.752MHz pixel clock */
+
+	/*
+	 * If the LCD controller is already running, decode the values
+	 * in LCDCON to xres/yres/bpp/pixclock/acprescale
+	 */
+	syscon = clps_readl(SYSCON1);
+	if (syscon & SYSCON1_LCDEN) {
+		lcdcon = clps_readl(LCDCON);
+
+		/*
+		 * Decode GSMD and GSEN bits to bits per pixel
+		 */
+		switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) {
+		case LCDCON_GSMD | LCDCON_GSEN:
+			info->var.bits_per_pixel = 4;
+			break;
+
+		case LCDCON_GSEN:
+			info->var.bits_per_pixel = 2;
+			break;
+
+		default:
+			info->var.bits_per_pixel = 1;
+			break;
+		}
+
+		/*
+		 * Decode xres/yres
+		 */
+		info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16;
+		info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) /
+					  (info->var.xres_virtual *
+					   info->var.bits_per_pixel);
+
+		/*
+		 * Calculate pixclock
+		 */
+		info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9;
+
+		/*
+		 * Grab AC prescale
+		 */
+		lcd_ac_prescale = (lcdcon >> 25) & 0x1f;
+	}
+
+	info->var.xres = info->var.xres_virtual;
+	info->var.yres = info->var.yres_virtual;
+	info->var.grayscale = info->var.bits_per_pixel > 1;
+
+	size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8;
+
+	/*
+	 * Might be worth checking to see if we can use the on-board
+	 * RAM if size here...
+	 * CLPS7110 - no on-board SRAM
+	 * EP7212   - 38400 bytes
+	 */
+	if (size < 38400) {
+		printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n");
+	}
+
+	if ((syscon & SYSCON1_LCDEN) == 0) {
+		/*
+		 * The display isn't running.  Ensure that
+		 * the display memory is empty.
+		 */
+		memset(virt_base, 0, size);
+	}
+
+	info->screen_base    = virt_base;
+	info->fix.smem_start = phys_base;
+	info->fix.smem_len   = PAGE_ALIGN(size);
+	info->fix.type       = FB_TYPE_PACKED_PIXELS;
+}
 
 int __init clps711xfb_init(void)
 {
@@ -266,34 +373,19 @@
 		goto out;
 
 	memset(cfb, 0, sizeof(*cfb) + sizeof(struct display));
-	memset((void *)PAGE_OFFSET, 0, 0x14000);
+	strcpy(cfb->fix.id, "clps711x");
 
 	cfb->currcon		= -1;
-
-	strcpy(cfb->fix.id, "clps7111");
-	cfb->screen_base	= (void *)PAGE_OFFSET;
-	cfb->fix.smem_start	= PAGE_OFFSET;
-	cfb->fix.smem_len	= 0x14000;
-	cfb->fix.type	= FB_TYPE_PACKED_PIXELS;
-
-	cfb->var.xres	 = 640;
-	cfb->var.xres_virtual = 640;
-	cfb->var.yres	 = 240;
-	cfb->var.yres_virtual = 240;
-	cfb->var.bits_per_pixel = 4;
-	cfb->var.grayscale   = 1;
-	cfb->var.activate	= FB_ACTIVATE_NOW;
-	cfb->var.height	= -1;
-	cfb->var.width	= -1;
-
 	cfb->fbops		= &clps7111fb_ops;
-	cfb->changevar	= NULL;
-	cfb->switch_con	= gen_switch;
-	cfb->updatevar	= gen_update_var;
+	cfb->changevar		= NULL;
+	cfb->switch_con		= gen_switch;
+	cfb->updatevar		= gen_update_var;
 	cfb->flags		= FBINFO_FLAG_DEFAULT;
 	cfb->disp		= (struct display *)(cfb + 1);
 
-	fb_alloc_cmap(&cfb->cmap, CMAP_SIZE, 0);
+	clps711x_guess_lcd_params(cfb);
+
+	fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0);
 
 	/* Register the /proc entries. */
 	clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444,
@@ -317,8 +409,6 @@
 	}
 
 	if (machine_is_edb7211()) {
-		int i;
-
 		/* Power up the LCD panel. */
 		clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR);
 
diff -Nru a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
--- a/drivers/video/cyber2000fb.c	Tue Oct 15 20:29:13 2002
+++ b/drivers/video/cyber2000fb.c	Tue Oct 15 20:29:13 2002
@@ -1,11 +1,14 @@
 /*
  *  linux/drivers/video/cyber2000fb.c
  *
- *  Copyright (C) 1998-2000 Russell King
+ *  Copyright (C) 1998-2002 Russell King
  *
  *  MIPS and 50xx clock support
  *  Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
  *
+ *  32 bit support, text color and panning fixes for modes != 8 bit
+ *  Copyright (C) 2002 Denis Oliver Kropp <dok@directfb.org>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
@@ -14,17 +17,24 @@
  *
  * Based on cyberfb.c.
  *
- * Note that we now use the new fbcon fix, var and cmap scheme.  We do still
- * have to check which console is the currently displayed one however, since
- * especially for the colourmap stuff.
+ * Note that we now use the new fbcon fix, var and cmap scheme.  We do
+ * still have to check which console is the currently displayed one
+ * however, especially for the colourmap stuff.
+ *
+ * We also use the new hotplug PCI subsystem.  I'm not sure if there
+ * are any such cards, but I'm erring on the side of caution.  We don't
+ * want to go pop just because someone does have one.
  *
- * We also use the new hotplug PCI subsystem.  I'm not sure if there are any
- * such cards, but I'm erring on the side of caution.  We don't want to go
- * pop just because someone does have one.
+ * Note that this doesn't work fully in the case of multiple CyberPro
+ * cards with grabbers.  We currently can only attach to the first
+ * CyberPro card found.
  *
- * Note that this doesn't work fully in the case of multiple CyberPro cards
- * with grabbers.  We currently can only attach to the first CyberPro card
- * found.
+ * When we're in truecolour mode, we power down the LUT RAM as a power
+ * saving feature.  Also, when we enter any of the powersaving modes
+ * (except soft blanking) we power down the RAMDACs.  This saves about
+ * 1W, which is roughly 8% of the power consumption of a NetWinder
+ * (which, incidentally, is about the same saving as a 2.5in hard disk
+ * entering standby mode.)
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -49,11 +59,7 @@
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
 #include <video/fbcon-cfb24.h>
-
-/*
- * Define this if you don't want RGB565, but RGB555 for 16bpp displays.
- */
-/*#define CFB16_IS_CFB15*/
+#include <video/fbcon-cfb32.h>
 
 #include "cyber2000fb.h"
 
@@ -64,6 +70,7 @@
 	struct pci_dev		*dev;
 	unsigned char 		*region;
 	unsigned char		*regs;
+	u_int			id;
 	int			func_use_count;
 	u_long			ref_ps;
 
@@ -80,6 +87,11 @@
 	u_char			mem_ctl2;
 	u_char			mclk_mult;
 	u_char			mclk_div;
+	/*
+	 * RAMDAC control register is both of these or'ed together
+	 */
+	u_char			ramdac_ctrl;
+	u_char			ramdac_powerdown;
 };
 
 static char default_font_storage[40];
@@ -139,7 +151,7 @@
 {
 	int count = 100000;
 
-	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) {
+	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) {
 		if (!count--) {
 			debug_printf("accel_wait timed out\n");
 			cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
@@ -163,8 +175,7 @@
 	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
 	struct fb_var_screeninfo *var = &display->var;
 	u_long src, dst;
-	u_int fh, fw;
-	int cmd = CO_CMD_L_PATTERN_FGCOL;
+	u_int fh, fw, cmd = CO_CMD_L_PATTERN_FGCOL;
 
 	fw    = fontwidth(display);
 	sx    *= fw;
@@ -194,22 +205,21 @@
 	dst    = dx + dy * var->xres_virtual;
 
 	cyber2000_accel_wait(cfb);
-	cyber2000fb_writeb(0x00,  CO_REG_CONTROL, cfb);
-	cyber2000fb_writeb(0x03,  CO_REG_FORE_MIX, cfb);
-	cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
-
-	if (var->bits_per_pixel != 24) {
-		cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
-		cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb);
-	} else {
-		cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
-		cyber2000fb_writeb(dst,     CO_REG_X_PHASE, cfb);
-		cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb);
+	cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
+	cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb);
+	cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb);
+
+	if (var->bits_per_pixel == 24) {
+		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
+		dst *= 3;
+		src *= 3;
 	}
 
-	cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
-	cyber2000fb_writew(cmd,    CO_REG_CMD_L, cfb);
-	cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb);
+	cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb);
+	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+	cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
+	cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
+	cyber2000fb_writew(CO_CMD_H_FGSRCMAP|CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
 }
 
 static void
@@ -230,28 +240,25 @@
 	height = height * fh - 1;
 
 	cyber2000_accel_wait(cfb);
-	cyber2000fb_writeb(0x00,   CO_REG_CONTROL,  cfb);
-	cyber2000fb_writeb(0x03,   CO_REG_FORE_MIX, cfb);
-	cyber2000fb_writew(width,  CO_REG_WIDTH,    cfb);
-	cyber2000fb_writew(height, CO_REG_HEIGHT,   cfb);
-
-	switch (var->bits_per_pixel) {
-	case 16:
-		bgx = ((u16 *)display->dispsw_data)[bgx];
-	case 8:
-		cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
-		break;
+	cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
+	cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb);
+	cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb);
 
-	case 24:
-		cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
+	if (var->bits_per_pixel == 24) {
 		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
-		bgx = ((u32 *)display->dispsw_data)[bgx];
-		break;
+		dst *= 3;
 	}
 
-	cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb);
+	if (var->bits_per_pixel == 16)
+		bgx = ((u16 *)display->dispsw_data)[bgx];
+	else if (var->bits_per_pixel >= 24)
+		bgx = ((u32 *)display->dispsw_data)[bgx];
+
+	cyber2000fb_writel(bgx, CO_REG_FGCOLOUR, cfb);
+	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+	cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
 	cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
-	cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb);
+	cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
 }
 
 static void
@@ -292,16 +299,23 @@
 }
 
 static struct display_switch fbcon_cyber_accel = {
-	.setup =	cyber2000_accel_setup,
-	.bmove =	cyber2000_accel_bmove,
-	.clear =	cyber2000_accel_clear,
-	.putc =		cyber2000_accel_putc,
-	.putcs =	cyber2000_accel_putcs,
-	.revc =		cyber2000_accel_revc,
-	.clear_margins =cyber2000_accel_clear_margins,
-	.fontwidthmask =FONTWIDTH(8)|FONTWIDTH(16)
+	.setup		= cyber2000_accel_setup,
+	.bmove		= cyber2000_accel_bmove,
+	.clear		= cyber2000_accel_clear,
+	.putc		= cyber2000_accel_putc,
+	.putcs		= cyber2000_accel_putcs,
+	.revc		= cyber2000_accel_revc,
+	.clear_margins	= cyber2000_accel_clear_margins,
+	.fontwidthmask	= FONTWIDTH(8)|FONTWIDTH(16)
 };
 
+static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf)
+{
+	u_int mask = (1 << bf->length) - 1;
+
+	return (val >> (16 - bf->length) & mask) << bf->offset;
+}
+
 /*
  *    Set a single color register. Return != 0 for invalid regno.
  */
@@ -311,85 +325,145 @@
 {
 	struct cfb_info *cfb = (struct cfb_info *)info;
 	struct fb_var_screeninfo *var = &cfb->display->var;
+	u32 pseudo_val;
+	int ret = 1;
 
-	if (regno >= NR_PALETTE)
+	switch (cfb->fb.fix.visual) {
+	default:
 		return 1;
 
-	red   >>= 8;
-	green >>= 8;
-	blue  >>= 8;
-
-	cfb->palette[regno].red   = red;
-	cfb->palette[regno].green = green;
-	cfb->palette[regno].blue  = blue;
-
-	switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
-	case 8:
+	/*
+	 * Pseudocolour:
+	 *         8     8
+	 * pixel --/--+--/-->  red lut  --> red dac
+	 *            |  8
+	 *            +--/--> green lut --> green dac
+	 *            |  8
+	 *            +--/-->  blue lut --> blue dac
+	 */
+	case FB_VISUAL_PSEUDOCOLOR:
+		if (regno >= NR_PALETTE)
+			return 1;
+
+		red >>= 8;
+		green >>= 8;
+		blue >>= 8;
+
+		cfb->palette[regno].red   = red;
+		cfb->palette[regno].green = green;
+		cfb->palette[regno].blue  = blue;
+
 		cyber2000fb_writeb(regno, 0x3c8, cfb);
-		cyber2000fb_writeb(red,   0x3c9, cfb);
+		cyber2000fb_writeb(red, 0x3c9, cfb);
 		cyber2000fb_writeb(green, 0x3c9, cfb);
-		cyber2000fb_writeb(blue,  0x3c9, cfb);
-		break;
+		cyber2000fb_writeb(blue, 0x3c9, cfb);
+		return 0;
 #endif
 
-#ifdef FBCON_HAS_CFB16
-	case 16:
-#ifndef CFB16_IS_CFB15
-		if (var->green.length == 6) {
-			if (regno < 64) {
-				/* write green */
-				cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
-				cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
-				cyber2000fb_writeb(green, 0x3c9, cfb);
-				cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
-			}
-
-			if (regno < 32) {
-				/* write red,blue */
-				cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
-				cyber2000fb_writeb(red, 0x3c9, cfb);
-				cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb);
-				cyber2000fb_writeb(blue, 0x3c9, cfb);
-			}
-
-			if (regno < 16)
-				((u16 *)cfb->fb.pseudo_palette)[regno] =
-					regno | regno << 5 | regno << 11;
-			break;
+	/*
+	 * Direct colour:
+	 *          n     rl
+	 *  pixel --/--+--/-->  red lut  --> red dac
+	 *             |  gl
+	 *             +--/--> green lut --> green dac
+	 *             |  bl
+	 *             +--/-->  blue lut --> blue dac
+	 * n = bpp, rl = red length, gl = green length, bl = blue length
+	 */
+	case FB_VISUAL_DIRECTCOLOR:
+		red >>= 8;
+		green >>= 8;
+		blue >>= 8;
+
+		if (var->green.length == 6 && regno < 64) {
+			cfb->palette[regno << 2].green = green;
+
+			/*
+			 * The 6 bits of the green component are applied
+			 * to the high 6 bits of the LUT.
+			 */
+			cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
+			cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
+			cyber2000fb_writeb(green, 0x3c9, cfb);
+			cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
+
+			green = cfb->palette[regno << 3].green;
+
+			ret = 0;
 		}
-#endif
-		if (regno < 32) {
+
+		if (var->green.length >= 5 && regno < 32) {
+			cfb->palette[regno << 3].red   = red;
+			cfb->palette[regno << 3].green = green;
+			cfb->palette[regno << 3].blue  = blue;
+
+			/*
+			 * The 5 bits of each colour component are
+			 * applied to the high 5 bits of the LUT.
+			 */
 			cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
 			cyber2000fb_writeb(red, 0x3c9, cfb);
 			cyber2000fb_writeb(green, 0x3c9, cfb);
 			cyber2000fb_writeb(blue, 0x3c9, cfb);
+			ret = 0;
 		}
-		if (regno < 16)
-			((u16 *)cfb->fb.pseudo_palette)[regno] =
-				regno | regno << 5 | regno << 10;
-		break;
 
-#endif
+		if (var->green.length == 4 && regno < 16) {
+			cfb->palette[regno << 4].red   = red;
+			cfb->palette[regno << 4].green = green;
+			cfb->palette[regno << 4].blue  = blue;
+
+			/*
+			 * The 5 bits of each colour component are
+			 * applied to the high 5 bits of the LUT.
+			 */
+			cyber2000fb_writeb(regno << 4, 0x3c8, cfb);
+			cyber2000fb_writeb(red, 0x3c9, cfb);
+			cyber2000fb_writeb(green, 0x3c9, cfb);
+			cyber2000fb_writeb(blue, 0x3c9, cfb);
+			ret = 0;
+		}
 
-#ifdef FBCON_HAS_CFB24
-	case 24:
-		cyber2000fb_writeb(regno, 0x3c8, cfb);
-		cyber2000fb_writeb(red,   0x3c9, cfb);
-		cyber2000fb_writeb(green, 0x3c9, cfb);
-		cyber2000fb_writeb(blue,  0x3c9, cfb);
+		/*
+		 * Since this is only used for the first 16 colours, we
+		 * don't have to care about overflowing for regno >= 32
+		 */
+		pseudo_val = regno << var->red.offset |
+			     regno << var->green.offset |
+			     regno << var->blue.offset;
+		break;
 
-		if (regno < 16)
-			((u32 *)cfb->fb.pseudo_palette)[regno] =
-				regno | regno << 8 | regno << 16;
+	/*
+	 * True colour:
+	 *          n     rl
+	 *  pixel --/--+--/--> red dac
+	 *             |  gl
+	 *             +--/--> green dac
+	 *             |  bl
+	 *             +--/--> blue dac
+	 * n = bpp, rl = red length, gl = green length, bl = blue length
+	 */
+	case FB_VISUAL_TRUECOLOR:
+		pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp);
+		pseudo_val |= convert_bitfield(red, &var->red);
+		pseudo_val |= convert_bitfield(green, &var->green);
+		pseudo_val |= convert_bitfield(blue, &var->blue);
 		break;
-#endif
+	}
 
-	default:
-		return 1;
+	/*
+	 * Now set our pseudo palette for the CFB16/24/32 drivers.
+	 */
+	if (regno < 16) {
+		if (var->bits_per_pixel == 16)
+			((u16 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
+		else
+			((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
+		ret = 0;
 	}
 
-	return 0;
+	return ret;
 }
 
 struct par_info {
@@ -399,7 +473,7 @@
 	u_char	clock_mult;
 	u_char	clock_div;
 	u_char	extseqmisc;
-	u_char	pixformat;
+	u_char	co_pixfmt;
 	u_char	crtc_ofl;
 	u_char	crtc[19];
 	u_int	width;
@@ -409,8 +483,7 @@
 	/*
 	 * Other
 	 */
-	u_char	palette_ctrl;
-	u_int	vmode;
+	u_char	ramdac;
 };
 
 static const u_char crtc_idx[] = {
@@ -419,6 +492,18 @@
 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
 };
 
+static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
+{
+	unsigned int i;
+	unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown;
+
+	cyber2000fb_writeb(0x56, 0x3ce, cfb);
+	i = cyber2000fb_readb(0x3cf, cfb);
+	cyber2000fb_writeb(i | 4, 0x3cf, cfb);
+	cyber2000fb_writeb(val, 0x3c6, cfb);
+	cyber2000fb_writeb(i, 0x3cf, cfb);
+}
+
 static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
 {
 	u_int i;
@@ -450,7 +535,7 @@
 	for (i = 0x0a; i < 0x10; i++)
 		cyber2000_crtcw(i, 0, cfb);
 
-	cyber2000_grphw(0x11, hw->crtc_ofl, cfb);
+	cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb);
 	cyber2000_grphw(0x00, 0x00, cfb);
 	cyber2000_grphw(0x01, 0x00, cfb);
 	cyber2000_grphw(0x02, 0x00, cfb);
@@ -471,16 +556,6 @@
 	cyber2000_attrw(0x13, 0x00, cfb);
 	cyber2000_attrw(0x14, 0x00, cfb);
 
-	/* woody: set the interlaced bit... */
-	/* FIXME: what about doublescan? */
-	cyber2000fb_writeb(0x11, 0x3ce, cfb);
-	i = cyber2000fb_readb(0x3cf, cfb);
-	if (hw->vmode == FB_VMODE_INTERLACED)
-		i |= 0x20;
-	else
-		i &= ~0x20;
-	cyber2000fb_writeb(i, 0x3cf, cfb);
-
 	/* PLL registers */
 	cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
 	cyber2000_grphw(EXT_DCLK_DIV,  hw->clock_div, cfb);
@@ -490,11 +565,8 @@
 	cyber2000_grphw(0xb9, 0x80, cfb);
 	cyber2000_grphw(0xb9, 0x00, cfb);
 
-	cyber2000fb_writeb(0x56, 0x3ce, cfb);
-	i = cyber2000fb_readb(0x3cf, cfb);
-	cyber2000fb_writeb(i | 4, 0x3cf, cfb);
-	cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb);
-	cyber2000fb_writeb(i,    0x3cf, cfb);
+	cfb->ramdac_ctrl = hw->ramdac;
+	cyber2000fb_write_ramdac_ctrl(cfb);
 
 	cyber2000fb_writeb(0x20, 0x3c0, cfb);
 	cyber2000fb_writeb(0xff, 0x3c6, cfb);
@@ -504,25 +576,20 @@
 			      ((hw->pitch >> 4) & 0x30), cfb);
 	cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb);
 
-	cyber2000_grphw(EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE |
-				      EXT_BIU_MISC_COP_ENABLE |
-				      EXT_BIU_MISC_COP_BFC, cfb);
-
 	/*
 	 * Set up accelerator registers
 	 */
 	cyber2000fb_writew(hw->width,     CO_REG_SRC_WIDTH,  cfb);
 	cyber2000fb_writew(hw->width,     CO_REG_DEST_WIDTH, cfb);
-	cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb);
+	cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb);
 }
 
 static inline int
 cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
 {
-	u_int base;
+	u_int base = var->yoffset * var->xres_virtual + var->xoffset;
 
-	base = var->yoffset * var->xres_virtual * var->bits_per_pixel +
-		var->xoffset * var->bits_per_pixel;
+	base *= var->bits_per_pixel;
 
 	/*
 	 * Convert to bytes and shift two extra bits because DAC
@@ -606,8 +673,9 @@
 	hw->crtc[16] = Vblankend;
 	hw->crtc[18] = 0xff;
 
-	/* overflow - graphics reg 0x11 */
-	/* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
+	/*
+	 * overflow - graphics reg 0x11
+	 * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
 	 * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
 	 */
 	hw->crtc_ofl =
@@ -615,7 +683,12 @@
 		BIT(Vdispend,   10, 0x01,  1) |
 		BIT(Vsyncstart, 10, 0x01,  2) |
 		BIT(Vblankstart,10, 0x01,  3) |
-		1 << 4;
+		EXT_CRT_VRTOFL_LINECOMP10;
+
+	/* woody: set the interlaced bit... */
+	/* FIXME: what about doublescan? */
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+		hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE;
 
 	return 0;
 }
@@ -735,51 +808,131 @@
 cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb,
 		       struct par_info *hw)
 {
+	unsigned int mem;
 	int err;
 
 	hw->width = var->xres_virtual;
-	hw->palette_ctrl = 0x06;
-	hw->vmode = var->vmode;
+	hw->ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT;
+
+	var->transp.msb_right	= 0;
+	var->red.msb_right	= 0;
+	var->green.msb_right	= 0;
+	var->blue.msb_right	= 0;
 
 	switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
 	case 8:	/* PSEUDOCOLOUR, 256 */
-		hw->pixformat		= PIXFORMAT_8BPP;
-		hw->extseqmisc		= EXT_SEQ_MISC_8;
+		hw->co_pixfmt		= CO_PIXFMT_8BPP;
 		hw->pitch		= hw->width >> 3;
+		hw->extseqmisc		= EXT_SEQ_MISC_8;
+
+		var->transp.offset	= 0;
+		var->transp.length	= 0;
+		var->red.offset		= 0;
+		var->red.length		= 8;
+		var->green.offset	= 0;
+		var->green.length	= 8;
+		var->blue.offset	= 0;
+		var->blue.length	= 8;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
-	case 16:
-		hw->pixformat		= PIXFORMAT_16BPP;
+	case 16:/* DIRECTCOLOUR, 64k or 32k */
+		hw->co_pixfmt		= CO_PIXFMT_16BPP;
 		hw->pitch		= hw->width >> 2;
-		hw->palette_ctrl	|= 0x10;
 
-#ifndef CFB16_IS_CFB15
-		/* DIRECTCOLOUR, 64k */
-		if (var->green.length == 6) {
+		switch (var->green.length) {
+		case 6: /* RGB565, 64k */
 			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB565;
+
+			var->transp.offset	= 0;
+			var->transp.length	= 0;
+			var->red.offset		= 11;
+			var->red.length		= 5;
+			var->green.offset	= 5;
+			var->green.length	= 6;
+			var->blue.offset	= 0;
+			var->blue.length	= 5;
+			break;
+
+		default:
+		case 5: /* RGB555, 32k */
+			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB555;
+
+			var->transp.offset	= 0;
+			var->transp.length	= 0;
+			var->red.offset		= 10;
+			var->red.length		= 5;
+			var->green.offset	= 5;
+			var->green.length	= 5;
+			var->blue.offset	= 0;
+			var->blue.length	= 5;
+			break;
+
+		case 4: /* RGB444, 4k + transparency? */
+			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB444;
+
+			var->transp.offset	= 12;
+			var->transp.length	= 4;
+			var->red.offset		= 8;
+			var->red.length		= 4;
+			var->green.offset	= 4;
+			var->green.length	= 4;
+			var->blue.offset	= 0;
+			var->blue.length	= 4;
 			break;
 		}
-#endif
-		/* DIRECTCOLOUR, 32k */
-		hw->extseqmisc		= EXT_SEQ_MISC_16_RGB555;
 		break;
-
 #endif
 #ifdef FBCON_HAS_CFB24
 	case 24:/* TRUECOLOUR, 16m */
-		hw->pixformat		= PIXFORMAT_24BPP;
-		hw->extseqmisc		= EXT_SEQ_MISC_24_RGB888;
+		hw->co_pixfmt		= CO_PIXFMT_24BPP;
 		hw->width		*= 3;
 		hw->pitch		= hw->width >> 3;
-		hw->palette_ctrl	|= 0x10;
+		hw->ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+		hw->extseqmisc		= EXT_SEQ_MISC_24_RGB888;
+
+		var->transp.offset	= 0;
+		var->transp.length	= 0;
+		var->red.offset		= 16;
+		var->red.length		= 8;
+		var->green.offset	= 8;
+		var->green.length	= 8;
+		var->blue.offset	= 0;
+		var->blue.length	= 8;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:/* TRUECOLOUR, 16m */
+		hw->co_pixfmt		= CO_PIXFMT_32BPP;
+		hw->pitch		= hw->width >> 1;
+		hw->ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+		hw->extseqmisc		= EXT_SEQ_MISC_32;
+
+		var->transp.offset	= 24;
+		var->transp.length	= 8;
+		var->red.offset		= 16;
+		var->red.length		= 8;
+		var->green.offset	= 8;
+		var->green.length	= 8;
+		var->blue.offset	= 0;
+		var->blue.length	= 8;
 		break;
 #endif
 	default:
 		return -EINVAL;
 	}
 
+	mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
+	if (mem > cfb->fb.fix.smem_len)
+		var->yres_virtual = cfb->fb.fix.smem_len * 8 /
+			(var->bits_per_pixel * var->xres_virtual);
+
+	if (var->yres > var->yres_virtual)
+		var->yres = var->yres_virtual;
+	if (var->xres > var->xres_virtual)
+		var->xres = var->xres_virtual;
+
 	err = cyber2000fb_decode_clock(hw, cfb, var);
 	if (err)
 		return err;
@@ -807,7 +960,7 @@
 	struct cfb_info *cfb = (struct cfb_info *)info;
 	struct display *display;
 	struct par_info hw;
-	int err, chgvar = 0;
+	int err, chgvar;
 
 	/*
 	 * CONUPDATE and SMOOTH_XPAN are equal.  However,
@@ -819,7 +972,7 @@
 		var->yoffset = cfb->display->var.yoffset;
 	}
 
-	err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw);
+	err = cyber2000fb_decode_var(var, cfb, &hw);
 	if (err)
 		return err;
 
@@ -831,84 +984,62 @@
 
 	if (con < 0) {
 		display = cfb->fb.disp;
-		chgvar = 0;
 	} else {
 		display = fb_display + con;
 	}
 
-	if (display->var.xres != var->xres)
-		chgvar = 1;
-	if (display->var.yres != var->yres)
-		chgvar = 1;
-	if (display->var.xres_virtual != var->xres_virtual)
-		chgvar = 1;
-	if (display->var.yres_virtual != var->yres_virtual)
-		chgvar = 1;
-	if (display->var.bits_per_pixel != var->bits_per_pixel)
+	chgvar = cfb->fb.var.xres != var->xres ||
+		 cfb->fb.var.yres != var->yres ||
+		 cfb->fb.var.xres_virtual != var->xres_virtual ||
+		 cfb->fb.var.yres_virtual != var->yres_virtual ||
+		 cfb->fb.var.bits_per_pixel != var->bits_per_pixel;
+
+	if (memcmp(&cfb->fb.var.red, &var->red, sizeof(var->red)) ||
+	    memcmp(&cfb->fb.var.green, &var->green, sizeof(var->green)) ||
+	    memcmp(&cfb->fb.var.blue, &var->blue, sizeof(var->blue)))
 		chgvar = 1;
 
+	if (con >= 0 && chgvar == 0)
+		return 0;
+
 	if (con < 0)
 		chgvar = 0;
 
-	var->red.msb_right	= 0;
-	var->green.msb_right	= 0;
-	var->blue.msb_right	= 0;
+	/*
+	 * If we are setting all the virtual consoles, also set the
+	 * defaults used to create new consoles.
+	 */
+	err = var->activate;
+	var->activate = FB_ACTIVATE_NOW;
+	if (err & FB_ACTIVATE_ALL)
+		cfb->fb.disp->var = *var;
+
+	cfb->fb.var = *var;
+	cfb->fb.fix.line_length	= var->xres_virtual * var->bits_per_pixel / 8;
 
 	switch (var->bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
 	case 8:	/* PSEUDOCOLOUR, 256 */
-		var->red.offset		= 0;
-		var->red.length		= 8;
-		var->green.offset	= 0;
-		var->green.length	= 8;
-		var->blue.offset	= 0;
-		var->blue.length	= 8;
-
-		cfb->fb.fix.visual	= FB_VISUAL_PSEUDOCOLOR;
 		cfb->dispsw		= &fbcon_cfb8;
 		display->dispsw_data	= NULL;
-		display->next_line	= var->xres_virtual;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
-	case 16:
-		var->bits_per_pixel	= 16;
-		var->red.length		= 5;
-		var->green.offset	= 5;
-		var->blue.offset	= 0;
-		var->blue.length	= 5;
-
-		cfb->fb.fix.visual	= FB_VISUAL_DIRECTCOLOR;
+	case 16:/* DIRECTCOLOUR */
 		cfb->dispsw		= &fbcon_cfb16;
 		display->dispsw_data	= cfb->fb.pseudo_palette;
-		display->next_line	= var->xres_virtual * 2;
-
-#ifndef CFB16_IS_CFB15
-		/* DIRECTCOLOUR, 64k */
-		if (var->green.length == 6) {
-			var->red.offset		= 11;
-			var->green.length	= 6;
-			break;
-		}
-#endif
-		/* DIRECTCOLOUR, 32k */
-		var->red.offset		= 10;
-		var->green.length	= 5;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB24
 	case 24:/* TRUECOLOUR, 16m */
-		var->red.offset		= 16;
-		var->red.length		= 8;
-		var->green.offset	= 8;
-		var->green.length	= 8;
-		var->blue.offset	= 0;
-		var->blue.length	= 8;
-
-		cfb->fb.fix.visual	= FB_VISUAL_TRUECOLOR;
 		cfb->dispsw		= &fbcon_cfb24;
 		display->dispsw_data	= cfb->fb.pseudo_palette;
-		display->next_line	= var->xres_virtual * 3;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	case 32:/* TRUECOLOUR, 16m */
+		cfb->dispsw		= &fbcon_cfb32;
+		display->dispsw_data	= cfb->fb.pseudo_palette;
 		break;
 #endif
 	default:/* in theory this should never happen */
@@ -918,40 +1049,34 @@
 		break;
 	}
 
+	/*
+	 * 8bpp displays are always pseudo colour.
+	 * 16bpp and above are direct colour or true colour, depending
+	 * on whether the RAMDAC palettes are bypassed.  (Direct colour
+	 * has palettes, true colour does not.)
+	 */
+	if (var->bits_per_pixel == 8)
+		cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else if (hw.ramdac & RAMDAC_BYPASS)
+		cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+	else
+		cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
+
 	if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)
 		display->dispsw = &fbcon_cyber_accel;
 	else
 		display->dispsw = cfb->dispsw;
 
-	cfb->fb.fix.line_length	= display->next_line;
-
-	display->line_length	= cfb->fb.fix.line_length;
-	display->visual		= cfb->fb.fix.visual;
-	display->type		= cfb->fb.fix.type;
-	display->type_aux	= cfb->fb.fix.type_aux;
-	display->ypanstep	= cfb->fb.fix.ypanstep;
-	display->ywrapstep	= cfb->fb.fix.ywrapstep;
 	display->can_soft_blank = 1;
 	display->inverse	= 0;
-	display->var		= *var;
-	display->var.activate	&= ~FB_ACTIVATE_ALL;
-
-	cfb->fb.var = display->var;
-
-	/*
-	 * If we are setting all the virtual consoles, also set the
-	 * defaults used to create new consoles.
-	 */
-	if (var->activate & FB_ACTIVATE_ALL)
-		cfb->fb.disp->var = display->var;
 
-	if (chgvar && info && cfb->fb.changevar)
-		cfb->fb.changevar(con);
-
-	cyber2000fb_update_start(cfb, var);
 	cyber2000fb_set_timing(cfb, &hw);
+	cyber2000fb_update_start(cfb, var);
 	fb_set_cmap(&cfb->fb.cmap, 1, &cfb->fb);
 
+	if (chgvar && cfb->fb.changevar)
+		cfb->fb.changevar(con);
+
 	return 0;
 }
 
@@ -1044,6 +1169,20 @@
 
 /*
  *    (Un)Blank the display.
+ *
+ *  Blank the screen if blank_mode != 0, else unblank. If
+ *  blank == NULL then the caller blanks by setting the CLUT
+ *  (Color Look Up Table) to all black. Return 0 if blanking
+ *  succeeded, != 0 if un-/blanking failed due to e.g. a
+ *  video mode which doesn't support it. Implements VESA
+ *  suspend and powerdown modes on hardware that supports
+ *  disabling hsync/vsync:
+ *    blank_mode == 2: suspend vsync
+ *    blank_mode == 3: suspend hsync
+ *    blank_mode == 4: powerdown
+ *
+ *  wms...Enable VESA DMPS compatible powerdown mode
+ *  run "setterm -powersave powerdown" to take advantage
  */
 static int cyber2000fb_blank(int blank, struct fb_info *info)
 {
@@ -1051,22 +1190,6 @@
 	unsigned int sync = 0;
 	int i;
 
-	/*
-	 *  Blank the screen if blank_mode != 0, else unblank. If
-	 *  blank == NULL then the caller blanks by setting the CLUT
-	 *  (Color Look Up Table) to all black. Return 0 if blanking
-	 *  succeeded, != 0 if un-/blanking failed due to e.g. a
-	 *  video mode which doesn't support it. Implements VESA
-	 *  suspend and powerdown modes on hardware that supports
-	 *  disabling hsync/vsync:
-	 *    blank_mode == 2: suspend vsync
-	 *    blank_mode == 3: suspend hsync
-	 *    blank_mode == 4: powerdown
-	 *
-	 *  wms...Enable VESA DMPS compatible powerdown mode
-	 *  run "setterm -powersave powerdown" to take advantage
-	 */
-     
 	switch (blank) {
 	case 4:	/* powerdown - both sync lines down */
 		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0;
@@ -1078,44 +1201,54 @@
 		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL;
 		break;
 	case 1:	/* soft blank */
-		break;
 	default: /* unblank */
 		break;
 	}
+
 	cyber2000_grphw(EXT_SYNC_CTL, sync, cfb);
 
-	switch (blank) {
-	case 4:
-	case 3:
-	case 2:
-	case 1:	/* soft blank */
+	if (blank <= 1) {
+		/* turn on ramdacs */
+		cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
+		cyber2000fb_write_ramdac_ctrl(cfb);
+	}
+
+	/*
+	 * Soft blank/unblank the display.
+	 */
+	if (blank) {	/* soft blank */
 		for (i = 0; i < NR_PALETTE; i++) {
 			cyber2000fb_writeb(i, 0x3c8, cfb);
 			cyber2000fb_writeb(0, 0x3c9, cfb);
 			cyber2000fb_writeb(0, 0x3c9, cfb);
 			cyber2000fb_writeb(0, 0x3c9, cfb);
 		}
-		break;
-	default: /* unblank */
+	} else {	/* unblank */
 		for (i = 0; i < NR_PALETTE; i++) {
 			cyber2000fb_writeb(i, 0x3c8, cfb);
 			cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
 			cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
 			cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
 		}
-		break;
 	}
+
+	if (blank >= 2) {
+		/* turn off ramdacs */
+		cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN;
+		cyber2000fb_write_ramdac_ctrl(cfb);
+	}
+
 	return 0;
 }
 
 static struct fb_ops cyber2000fb_ops = {
 	.owner		= THIS_MODULE,
 	.fb_set_var	= cyber2000fb_set_var,
+	.fb_get_cmap	= gen_get_cmap,
+	.fb_set_cmap	= gen_set_cmap,
 	.fb_setcolreg	= cyber2000fb_setcolreg,
 	.fb_pan_display	= cyber2000fb_pan_display,
 	.fb_blank	= cyber2000fb_blank,
-	.fb_get_cmap	= gen_get_cmap,
-	.fb_set_cmap	= gen_set_cmap,
 };
 
 /*
@@ -1206,18 +1339,18 @@
  * 640x480, hsync 31.5kHz, vsync 60Hz
  */
 static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
-	.refresh =	60,
-	.xres =		640,
-	.yres =		480,
-	.pixclock =	39722,
-	.left_margin =	56,
-	.right_margin =	16,
-	.upper_margin =	34,
-	.lower_margin =	9,
-	.hsync_len =	88,
-	.vsync_len =	2,
-	.sync =		FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-	.vmode =	FB_VMODE_NONINTERLACED
+	.refresh	= 60,
+	.xres		= 640,
+	.yres		= 480,
+	.pixclock	= 39722,
+	.left_margin	= 56,
+	.right_margin	= 16,
+	.upper_margin	= 34,
+	.lower_margin	= 9,
+	.hsync_len	= 88,
+	.vsync_len	= 2,
+	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	.vmode		= FB_VMODE_NONINTERLACED
 };
 
 static char igs_regs[] __devinitdata = {
@@ -1265,7 +1398,7 @@
 	for (i = 0; i < sizeof(igs_regs); i += 2)
 		cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
 
-	if (cfb->fb.fix.accel == FB_ACCEL_IGS_CYBER5000) {
+	if (cfb->id == ID_CYBERPRO_5000) {
 		unsigned char val;
 		cyber2000fb_writeb(0xba, 0x3ce, cfb);
 		val = cyber2000fb_readb(0x3cf, cfb) & 0x80;
@@ -1286,6 +1419,8 @@
 
 	memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display));
 
+	cfb->id			= id;
+
 	if (id == ID_CYBERPRO_5000)
 		cfb->ref_ps	= 40690; // 24.576 MHz
 	else
@@ -1403,6 +1538,8 @@
 	u_int h_sync, v_sync;
 	int err;
 
+	cyberpro_init_hw(cfb);
+
 	/*
 	 * Get the video RAM size and width from the VGA register.
 	 * This should have been already initialised by the BIOS,
@@ -1521,8 +1658,6 @@
 	cfb->mclk_mult = 0xdb;
 	cfb->mclk_div  = 0x54;
 
-	cyberpro_init_hw(cfb);
-
 	err = cyberpro_common_probe(cfb);
 	if (err)
 		goto failed;
@@ -1559,6 +1694,8 @@
  */
 static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
 {
+	unsigned char val;
+
 #if defined(__sparc_v9__)
 #error "You loose, consult DaveM."
 #elif defined(__sparc__)
@@ -1593,6 +1730,22 @@
 	outb(EXT_BIU_MISC, 0x3ce);
 	outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf);
 #endif
+
+	/*
+	 * Allow the CyberPro to accept PCI burst accesses
+	 */
+	val = cyber2000_grphr(EXT_BUS_CTL, cfb);
+	if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
+		printk(KERN_INFO "%s: enabling PCI bursts\n", cfb->fb.fix.id);
+
+		val |= EXT_BUS_CTL_PCIBURST_WRITE;
+
+		if (cfb->id == ID_CYBERPRO_5000)
+			val |= EXT_BUS_CTL_PCIBURST_READ;
+
+		cyber2000_grphw(EXT_BUS_CTL, val, cfb);
+	}
+
 	return 0;
 }
 
@@ -1652,8 +1805,6 @@
 	cfb->mclk_div  = 0x54;
 #endif
 
-	cyberpro_init_hw(cfb);
-
 	err = cyberpro_common_probe(cfb);
 	if (err)
 		goto failed;
@@ -1742,12 +1893,12 @@
 MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
 
 static struct pci_driver cyberpro_driver = {
-	.name =		"CyberPro",
-	.probe =	cyberpro_pci_probe,
-	.remove =	__devexit_p(cyberpro_pci_remove),
-	.suspend =	cyberpro_pci_suspend,
-	.resume =	cyberpro_pci_resume,
-	.id_table =	cyberpro_pci_table
+	.name		= "CyberPro",
+	.probe		= cyberpro_pci_probe,
+	.remove		= __devexit_p(cyberpro_pci_remove),
+	.suspend	= cyberpro_pci_suspend,
+	.resume		= cyberpro_pci_resume,
+	.id_table	= cyberpro_pci_table
 };
 #endif
 
@@ -1758,17 +1909,20 @@
  */
 int __init cyber2000fb_init(void)
 {
-	int ret = -1, err = -ENODEV;
+	int ret = -1, err;
+
 #ifdef CONFIG_ARCH_SHARK
 	err = cyberpro_vl_probe();
 	if (!err) {
-		ret = err;
+		ret = 0;
 		MOD_INC_USE_COUNT;
 	}
 #endif
+#ifdef CONFIG_PCI
 	err = pci_module_init(&cyberpro_driver);
 	if (!err)
-		ret = err;
+		ret = 0;
+#endif
 
 	return ret ? err : 0;
 }
diff -Nru a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h
--- a/drivers/video/cyber2000fb.h	Tue Oct 15 20:29:15 2002
+++ b/drivers/video/cyber2000fb.h	Tue Oct 15 20:29:15 2002
@@ -36,9 +36,15 @@
 #define debug_printf(x...) do { } while (0)
 #endif
 
-#define PIXFORMAT_8BPP		0
-#define PIXFORMAT_16BPP		1
-#define PIXFORMAT_24BPP		2
+#define RAMDAC_RAMPWRDN		0x01
+#define RAMDAC_DAC8BIT		0x02
+#define RAMDAC_VREFEN		0x04
+#define RAMDAC_BYPASS		0x10
+#define RAMDAC_DACPWRDN		0x40
+
+#define EXT_CRT_VRTOFL		0x11
+#define EXT_CRT_VRTOFL_LINECOMP10	0x10
+#define EXT_CRT_VRTOFL_INTERLACE	0x20
 
 #define EXT_CRT_IRQ		0x12
 #define EXT_CRT_IRQ_ENABLE		0x01
@@ -61,7 +67,8 @@
 #define EXT_BUS_CTL_LIN_2MB		0x01
 #define EXT_BUS_CTL_LIN_4MB		0x02
 #define EXT_BUS_CTL_ZEROWAIT		0x04
-#define EXT_BUS_CTL_PCIBURST		0x20
+#define EXT_BUS_CTL_PCIBURST_WRITE	0x20
+#define EXT_BUS_CTL_PCIBURST_READ	0x80	/* CyberPro 5000 only */
 
 #define EXT_SEG_WRITE_PTR	0x31
 #define EXT_SEG_READ_PTR	0x32
@@ -401,24 +408,54 @@
 /*
  * Graphics Co-processor
  */
-#define CO_CMD_L_PATTERN_FGCOL	0x8000
-#define CO_CMD_L_INC_LEFT	0x0004
-#define CO_CMD_L_INC_UP		0x0002
-
-#define CO_CMD_H_SRC_PIXMAP	0x2000
-#define CO_CMD_H_BLITTER	0x0800
-
 #define CO_REG_CONTROL		0xbf011
+#define CO_CTRL_BUSY			0x80
+#define CO_CTRL_CMDFULL			0x04
+#define CO_CTRL_FIFOEMPTY		0x02
+#define CO_CTRL_READY			0x01
+
 #define CO_REG_SRC_WIDTH	0xbf018
-#define CO_REG_PIX_FORMAT	0xbf01c
-#define CO_REG_FORE_MIX		0xbf048
-#define CO_REG_FOREGROUND	0xbf058
-#define CO_REG_WIDTH		0xbf060
-#define CO_REG_HEIGHT		0xbf062
+#define CO_REG_PIXFMT		0xbf01c
+#define CO_PIXFMT_32BPP			0x03
+#define CO_PIXFMT_24BPP			0x02
+#define CO_PIXFMT_16BPP			0x01
+#define CO_PIXFMT_8BPP			0x00
+
+#define CO_REG_FGMIX		0xbf048
+#define CO_FG_MIX_ZERO			0x00
+#define CO_FG_MIX_SRC_AND_DST		0x01
+#define CO_FG_MIX_SRC_AND_NDST		0x02
+#define CO_FG_MIX_SRC			0x03
+#define CO_FG_MIX_NSRC_AND_DST		0x04
+#define CO_FG_MIX_DST			0x05
+#define CO_FG_MIX_SRC_XOR_DST		0x06
+#define CO_FG_MIX_SRC_OR_DST		0x07
+#define CO_FG_MIX_NSRC_AND_NDST		0x08
+#define CO_FG_MIX_SRC_XOR_NDST		0x09
+#define CO_FG_MIX_NDST			0x0a
+#define CO_FG_MIX_SRC_OR_NDST		0x0b
+#define CO_FG_MIX_NSRC			0x0c
+#define CO_FG_MIX_NSRC_OR_DST		0x0d
+#define CO_FG_MIX_NSRC_OR_NDST		0x0e
+#define CO_FG_MIX_ONES			0x0f
+
+#define CO_REG_FGCOLOUR		0xbf058
+#define CO_REG_BGCOLOUR		0xbf05c
+#define CO_REG_PIXWIDTH		0xbf060
+#define CO_REG_PIXHEIGHT	0xbf062
 #define CO_REG_X_PHASE		0xbf078
 #define CO_REG_CMD_L		0xbf07c
+#define CO_CMD_L_PATTERN_FGCOL		0x8000
+#define CO_CMD_L_INC_LEFT		0x0004
+#define CO_CMD_L_INC_UP			0x0002
+
 #define CO_REG_CMD_H		0xbf07e
-#define CO_REG_SRC_PTR		0xbf170
+#define CO_CMD_H_BGSRCMAP		0x8000	/* otherwise bg colour */
+#define CO_CMD_H_FGSRCMAP		0x2000	/* otherwise fg colour */
+#define CO_CMD_H_BLITTER		0x0800
+
+#define CO_REG_SRC1_PTR		0xbf170
+#define CO_REG_SRC2_PTR		0xbf174
 #define CO_REG_DEST_PTR		0xbf178
 #define CO_REG_DEST_WIDTH	0xbf218
 
diff -Nru a/fs/Config.help b/fs/Config.help
--- a/fs/Config.help	Tue Oct 15 20:29:20 2002
+++ b/fs/Config.help	Tue Oct 15 20:29:20 2002
@@ -535,6 +535,13 @@
   causes open() to return EINVAL if a file residing in NFS is
   opened with the O_DIRECT flag.
 
+CONFIG_NFS_V4
+  Say Y here if you want your NFS client to be able to speak the newer
+  version 4 of the NFS protocol.  This feature is experimental, and
+  should only be used if you are interested in helping to test NFSv4.
+
+  If unsure, say N.
+
 CONFIG_ROOT_NFS
   If you want your Linux box to mount its whole root file system (the
   one containing the directory /) from some other computer over the
@@ -1134,6 +1141,14 @@
 
   This feature is unsupported at this time, is not yet fully
   functional, and may cause serious problems.
+
+  If unsure, say N.
+
+CONFIG_AFS_FS
+  If you say Y here, you will get an experimental Andrew File System
+  driver. It currently only supports unsecured read-only AFS access.
+
+  See Documentation/filesystems/afs.txt for more intormation.
 
   If unsure, say N.
 
diff -Nru a/fs/Config.in b/fs/Config.in
--- a/fs/Config.in	Tue Oct 15 20:29:17 2002
+++ b/fs/Config.in	Tue Oct 15 20:29:17 2002
@@ -117,6 +117,7 @@
    dep_tristate 'InterMezzo file system support (replicating fs) (EXPERIMENTAL)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
    dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
    dep_mbool '  Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS
+   dep_mbool '  Provide NFSv4 client support (EXPERIMENTAL)' CONFIG_NFS_V4 $CONFIG_NFS_FS $CONFIG_EXPERIMENTAL
    dep_bool '  Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
 
    dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
@@ -157,6 +158,16 @@
       # for fs/nls/Config.in
       define_bool CONFIG_NCPFS_NLS n
    fi
+
+   dep_tristate 'Andrew File System support (AFS) (Experimental)' CONFIG_AFS_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
+   if [ "$CONFIG_AFS_FS" = "y" ]; then
+      define_tristate CONFIG_RXRPC y
+   else
+      if [ "$CONFIG_AFS_FS" = "m" ]; then
+	 define_tristate CONFIG_RXRPC m
+      fi
+   fi
+
    endmenu
 
 else
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Tue Oct 15 20:29:17 2002
+++ b/fs/Makefile	Tue Oct 15 20:29:17 2002
@@ -6,12 +6,12 @@
 # 
 
 export-objs :=	open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o \
-                fcntl.o read_write.o
+                fcntl.o read_write.o dcookies.o
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
 		bio.o super.o block_dev.o char_dev.o stat.o exec.o pipe.o \
 		namei.o fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
-		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
+		dcache.o inode.o attr.o bad_inode.o file.o dnotify.o \
 		filesystems.o namespace.o seq_file.o xattr.o libfs.o \
 		fs-writeback.o mpage.o direct-io.o aio.o
 
@@ -40,6 +40,8 @@
 obj-y				+= driverfs/
 obj-y				+= devpts/
 
+obj-$(CONFIG_PROFILING)		+= dcookies.o
+ 
 # Do not add any filesystems before this line
 obj-$(CONFIG_EXT3_FS)		+= ext3/ # Before ext2 so root fs can be ext3
 obj-$(CONFIG_JBD)		+= jbd/
@@ -84,5 +86,6 @@
 obj-$(CONFIG_SUN_OPENPROMFS)	+= openpromfs/
 obj-$(CONFIG_JFS_FS)		+= jfs/
 obj-$(CONFIG_XFS_FS)		+= xfs/
+obj-$(CONFIG_AFS_FS)		+= afs/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
--- a/fs/adfs/dir_f.c	Tue Oct 15 20:29:17 2002
+++ b/fs/adfs/dir_f.c	Tue Oct 15 20:29:17 2002
@@ -469,9 +469,9 @@
 }
 
 struct adfs_dir_ops adfs_f_dir_ops = {
-	read:		adfs_f_read,
-	setpos:		adfs_f_setpos,
-	getnext:	adfs_f_getnext,
-	update:		adfs_f_update,
-	free:		adfs_f_free
+	.read		= adfs_f_read,
+	.setpos		= adfs_f_setpos,
+	.getnext	= adfs_f_getnext,
+	.update		= adfs_f_update,
+	.free		= adfs_f_free
 };
diff -Nru a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
--- a/fs/adfs/dir_fplus.c	Tue Oct 15 20:29:12 2002
+++ b/fs/adfs/dir_fplus.c	Tue Oct 15 20:29:12 2002
@@ -172,8 +172,8 @@
 }
 
 struct adfs_dir_ops adfs_fplus_dir_ops = {
-	read:		adfs_fplus_read,
-	setpos:		adfs_fplus_setpos,
-	getnext:	adfs_fplus_getnext,
-	free:		adfs_fplus_free
+	.read		= adfs_fplus_read,
+	.setpos		= adfs_fplus_setpos,
+	.getnext	= adfs_fplus_getnext,
+	.free		= adfs_fplus_free
 };
diff -Nru a/fs/afs/Makefile b/fs/afs/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/Makefile	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,36 @@
+#
+# Makefile for Red Hat Linux AFS client.
+#
+
+kafs-objs := \
+	callback.o \
+	cell.o \
+	cmservice.o \
+	dir.o \
+	file.o \
+	fsclient.o \
+	inode.o \
+	kafsasyncd.o \
+	kafstimod.o \
+	main.o \
+	misc.o \
+	mntpt.o \
+	proc.o \
+	server.o \
+	super.o \
+	vlclient.o \
+	vlocation.o \
+	vnode.o \
+	volume.o
+
+#	cache.o
+
+obj-m  := kafs.o
+
+# superfluous for 2.5, but needed for 2.4..
+ifeq "$(VERSION).$(PATCHLEVEL)" "2.4"
+kafs.o: $(kafs-objs)
+	$(LD) -r -o kafs.o $(kafs-objs)
+endif
+
+include $(TOPDIR)/Rules.make
diff -Nru a/fs/afs/cache-layout.h b/fs/afs/cache-layout.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/cache-layout.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,224 @@
+/* cache-layout.h: AFS cache layout
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * The cache is stored on a block device and is laid out as:
+ *
+ *  0	+------------------------------------------------
+ *	|
+ *	|  SuperBlock
+ *	|
+ *  1	+------------------------------------------------
+ *	|
+ *	|  file-meta-data File: Data block #0
+ *	|  - file-meta-data file (volix #0 file #0) : Meta-data block
+ *	|    - contains direct pointers to first 64 file data blocks
+ *	|  - Cached cell catalogue file (volix #0 file #1) file: Meta-data block
+ *	|  - Cached volume location catalogue file (volix #0 file #2): Meta-data block
+ *	|  - Vnode catalogue hash bucket #n file: Meta-data block
+ *	|
+ *  2	+------------------------------------------------
+ *	|
+ *	|  Bitmap Block Allocation Bitmap
+ *	|  - 1 bit per block in the bitmap block
+ *      |  - bit 0 of dword 0 refers to the bitmap block 0
+ *	|    - set if the bitmap block is full
+ *      |  - 32768 bits per block, requiring 4 blocks for a 16Tb cache
+ *	|  - bitmap bitmap blocks are cleared initially
+ *	|  - not present if <4 bitmap blocks
+ *	|
+ *	+------------------------------------------------
+ *	|
+ *	|  File Block Allocation Bitmap
+ *	|  - 1 bit per block in the cache
+ *      |  - bit 0 of dword 0 refers to the first block of the data cache
+ *	|    - set if block is allocated
+ *      |  - 32768 bits per block, requiring 131072 blocks for a 16Tb cache
+ *	|  - bitmap blocks are cleared lazily (sb->bix_bitmap_unready)
+ *	|
+ *	+------------------------------------------------
+ *	|
+ *	|  Data Cache
+ *	|
+ *  End	+------------------------------------------------
+ *
+ * Blocks are indexed by an unsigned 32-bit word, meaning that the cache can hold up to 2^32 pages,
+ * or 16Tb in total.
+ *
+ * Credentials will be cached in memory, since they are subject to change without notice, and are
+ * difficult to derive manually, being constructed from the following information:
+ * - per vnode user ID and mode mask
+ * - parent directory ACL
+ * - directory ACL (dirs only)
+ * - group lists from ptserver
+ */
+
+#ifndef _LINUX_AFS_CACHE_LAYOUT_H
+#define _LINUX_AFS_CACHE_LAYOUT_H
+
+#include "types.h"
+
+typedef u32 afsc_blockix_t;
+typedef u32 afsc_cellix_t;
+
+/* Cached volume index
+ * - afsc_volix_t/4 is the index into the volume cache
+ * - afsc_volix_t%4 is 0 for R/W, 1 for R/O and 2 for Bak (3 is not used)
+ * - afsc_volix_t==0-3 refers to a "virtual" volume that stores meta-data about the cache
+ */
+typedef struct {
+	u32 index;
+} afsc_volix_t;
+
+#define AFSC_VNCAT_HASH_NBUCKETS	128
+
+/* special meta file IDs (all cell 0 vol 0) */
+enum afsc_meta_fids {
+	AFSC_META_FID_METADATA		= 0,
+	AFSC_META_FID_CELL_CATALOGUE	= 1,
+	AFSC_META_FID_VLDB_CATALOGUE	= 2,
+	AFSC_META_FID_VNODE_CATALOGUE0	= 3,
+	AFSC_META_FID__COUNT		= AFSC_VNCAT_HASH_NBUCKETS + 3
+};
+
+/*****************************************************************************/
+/*
+ * cache superblock block layout
+ * - the blockdev is prepared for initialisation by 'echo "kafsuninit" >/dev/hdaXX' before mounting
+ * - when initialised, the magic number is changed to "kafs-cache"
+ */
+struct afsc_super_block
+{
+	char			magic[10];	/* magic number */
+#define AFSC_SUPER_MAGIC "kafs-cache"
+#define AFSC_SUPER_MAGIC_NEEDS_INIT "kafsuninit"
+#define AFSC_SUPER_MAGIC_SIZE 10
+
+	unsigned short		endian;		/* 0x1234 stored CPU-normal order */
+#define AFSC_SUPER_ENDIAN 0x1234
+
+	unsigned		version;	/* format version */
+#define AFSC_SUPER_VERSION 1
+
+	/* layout */
+	unsigned		bsize;			/* cache block size */
+	afsc_blockix_t		bix_bitmap_fullmap;	/* block ix of bitmap full bitmap */
+	afsc_blockix_t		bix_bitmap;		/* block ix of alloc bitmap */
+	afsc_blockix_t		bix_bitmap_unready;	/* block ix of unready area of bitmap */
+	afsc_blockix_t		bix_cache;		/* block ix of data cache */
+	afsc_blockix_t		bix_end;		/* block ix of end of cache */
+};
+
+/*****************************************************************************/
+/*
+ * vnode (inode) metadata cache record
+ * - padded out to 512 bytes and stored eight to a page
+ * - only the data version is necessary
+ *   - disconnected operation is not supported
+ *   - afs_iget() contacts the server to get the meta-data _anyway_ when an inode is first brought
+ *     into memory
+ * - at least 64 direct block pointers will be available (a directory is max 256Kb)
+ * - any block pointer which is 0 indicates an uncached page
+ */
+struct afsc_vnode_meta
+{
+	/* file ID */
+	afsc_volix_t		volume_ix;	/* volume catalogue index */
+	unsigned		vnode;		/* vnode number */
+	unsigned		unique;		/* FID unique */
+	unsigned		size;		/* size of file */
+	time_t			mtime;		/* last modification time */
+
+	/* file status */
+	afs_dataversion_t	version;	/* current data version */
+
+	/* file contents */
+	afsc_blockix_t		dbl_indirect;	/* double indirect block index */
+	afsc_blockix_t		indirect;	/* single indirect block 0 index */
+	afsc_blockix_t		direct[0];	/* direct block index (#AFSC_VNODE_META_DIRECT) */
+};
+
+#define AFSC_VNODE_META_RECSIZE	512	/* record size */
+
+#define AFSC_VNODE_META_DIRECT	\
+	((AFSC_VNODE_META_RECSIZE-sizeof(struct afsc_vnode_meta))/sizeof(afsc_blockix_t))
+
+#define AFSC_VNODE_META_PER_PAGE	(PAGE_SIZE / AFSC_VNODE_META_RECSIZE)
+
+/*****************************************************************************/
+/*
+ * entry in the cached cell catalogue
+ */
+struct afsc_cell_record
+{
+	char			name[64];	/* cell name (padded with NULs) */
+	struct in_addr		servers[16];	/* cached cell servers */
+};
+
+/*****************************************************************************/
+/*
+ * entry in the cached volume location catalogue
+ * - indexed by afsc_volix_t/4
+ */
+struct afsc_vldb_record
+{
+	char			name[64];	/* volume name (padded with NULs) */
+	afs_volid_t		vid[3];		/* volume IDs for R/W, R/O and Bak volumes */
+	unsigned char		vidmask;	/* voltype mask for vid[] */
+	unsigned char		_pad[1];
+	unsigned short		nservers;	/* number of entries used in servers[] */
+	struct in_addr		servers[8];	/* fileserver addresses */
+	unsigned char		srvtmask[8];	/* voltype masks for servers[] */
+#define AFSC_VOL_STM_RW	0x01 /* server holds a R/W version of the volume */
+#define AFSC_VOL_STM_RO	0x02 /* server holds a R/O version of the volume */
+#define AFSC_VOL_STM_BAK	0x04 /* server holds a backup version of the volume */
+
+	afsc_cellix_t		cell_ix;	/* cell catalogue index (MAX_UINT if unused) */
+	time_t			ctime;		/* time at which cached */
+};
+
+/*****************************************************************************/
+/*
+ * vnode catalogue entry
+ * - must be 2^x size so that do_generic_file_read doesn't present them split across pages
+ */
+struct afsc_vnode_catalogue
+{
+	afsc_volix_t		volume_ix;	/* volume catalogue index */
+	afs_vnodeid_t		vnode;		/* vnode ID */
+	u32			meta_ix;	/* metadata file index */
+	u32			atime;		/* last time entry accessed */
+} __attribute__((packed));
+
+#define AFSC_VNODE_CATALOGUE_PER_BLOCK ((size_t)(PAGE_SIZE/sizeof(struct afsc_vnode_catalogue)))
+
+/*****************************************************************************/
+/*
+ * vnode data "page directory" block
+ * - first 1024 pages don't map through here
+ * - PAGE_SIZE in size
+ */
+struct afsc_indirect_block
+{
+	afsc_blockix_t		pt_bix[1024];	/* "page table" block indices */
+};
+
+/*****************************************************************************/
+/*
+ * vnode data "page table" block
+ * - PAGE_SIZE in size
+ */
+struct afsc_dbl_indirect_block
+{
+	afsc_blockix_t		page_bix[1024];	/* "page" block indices */
+};
+
+
+#endif /* _LINUX_AFS_CACHE_LAYOUT_H */
diff -Nru a/fs/afs/callback.c b/fs/afs/callback.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/callback.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the
+ * GNU General Public License.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
+ *          David Howells <dhowells@redhat.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include "server.h"
+#include "vnode.h"
+#include "internal.h"
+
+/*****************************************************************************/
+/*
+ * allow the fileserver to request callback state (re-)initialisation
+ */
+int SRXAFSCM_InitCallBackState(afs_server_t *server)
+{
+	struct list_head callbacks;
+
+	_enter("%p",server);
+
+	INIT_LIST_HEAD(&callbacks);
+
+	/* transfer the callback list from the server to a temp holding area */
+	spin_lock(&server->cb_lock);
+
+	list_add(&callbacks,&server->cb_promises);
+	list_del_init(&server->cb_promises);
+
+	/* munch our way through the list, grabbing the inode, dropping all the locks and regetting
+	 * them in the right order
+	 */
+	while (!list_empty(&callbacks)) {
+		struct inode *inode;
+		afs_vnode_t *vnode;
+
+		vnode = list_entry(callbacks.next,afs_vnode_t,cb_link);
+		list_del_init(&vnode->cb_link);
+
+		/* try and grab the inode - may fail */
+		inode = igrab(AFS_VNODE_TO_I(vnode));
+		if (inode) {
+			int release = 0;
+
+			spin_unlock(&server->cb_lock);
+			spin_lock(&vnode->lock);
+
+			if (vnode->cb_server==server) {
+				vnode->cb_server = NULL;
+				afs_kafstimod_del_timer(&vnode->cb_timeout);
+				spin_lock(&afs_cb_hash_lock);
+				list_del_init(&vnode->cb_hash_link);
+				spin_unlock(&afs_cb_hash_lock);
+				release = 1;
+			}
+
+			spin_unlock(&vnode->lock);
+
+			iput(inode);
+			if (release) afs_put_server(server);
+
+			spin_lock(&server->cb_lock);
+		}
+	}
+
+	spin_unlock(&server->cb_lock);
+
+	_leave(" = 0");
+	return 0;
+} /* end SRXAFSCM_InitCallBackState() */
+
+/*****************************************************************************/
+/*
+ * allow the fileserver to break callback promises
+ */
+int SRXAFSCM_CallBack(afs_server_t *server, size_t count, afs_callback_t callbacks[])
+{
+	struct list_head *_p;
+
+	_enter("%p,%u,",server,count);
+
+	for (; count>0; callbacks++, count--) {
+		struct inode *inode = NULL;
+		afs_vnode_t *vnode = NULL;
+		int valid = 0;
+
+		_debug("- Fid { vl=%08x n=%u u=%u }  CB { v=%u x=%u t=%u }",
+		       callbacks->fid.vid,
+		       callbacks->fid.vnode,
+		       callbacks->fid.unique,
+		       callbacks->version,
+		       callbacks->expiry,
+		       callbacks->type
+		       );
+
+		/* find the inode for this fid */
+		spin_lock(&afs_cb_hash_lock);
+
+		list_for_each(_p,&afs_cb_hash(server,&callbacks->fid)) {
+			vnode = list_entry(_p,afs_vnode_t,cb_hash_link);
+
+			if (memcmp(&vnode->fid,&callbacks->fid,sizeof(afs_fid_t))!=0)
+				continue;
+
+			/* right vnode, but is it same server? */
+			if (vnode->cb_server!=server)
+				break; /* no */
+
+			/* try and nail the inode down */
+			inode = igrab(AFS_VNODE_TO_I(vnode));
+			break;
+		}
+
+		spin_unlock(&afs_cb_hash_lock);
+
+		if (inode) {
+			/* we've found the record for this vnode */
+			spin_lock(&vnode->lock);
+			if (vnode->cb_server==server) {
+				/* the callback _is_ on the calling server */
+				vnode->cb_server = NULL;
+				valid = 1;
+
+				afs_kafstimod_del_timer(&vnode->cb_timeout);
+				vnode->flags |= AFS_VNODE_CHANGED;
+
+				spin_lock(&server->cb_lock);
+				list_del_init(&vnode->cb_link);
+				spin_unlock(&server->cb_lock);
+
+				spin_lock(&afs_cb_hash_lock);
+				list_del_init(&vnode->cb_hash_link);
+				spin_unlock(&afs_cb_hash_lock);
+			}
+			spin_unlock(&vnode->lock);
+
+			if (valid) {
+				invalidate_inode_pages(inode->i_mapping);
+				afs_put_server(server);
+			}
+			iput(inode);
+		}
+	}
+
+	_leave(" = 0");
+	return 0;
+} /* end SRXAFSCM_CallBack() */
+
+/*****************************************************************************/
+/*
+ * allow the fileserver to see if the cache manager is still alive
+ */
+int SRXAFSCM_Probe(afs_server_t *server)
+{
+	_debug("SRXAFSCM_Probe(%p)\n",server);
+	return 0;
+} /* end SRXAFSCM_Probe() */
diff -Nru a/fs/afs/cell.c b/fs/afs/cell.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/cell.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,452 @@
+/* cell.c: AFS cell and server record management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include "volume.h"
+#include "cell.h"
+#include "server.h"
+#include "transport.h"
+#include "vlclient.h"
+#include "kafstimod.h"
+#include "super.h"
+#include "internal.h"
+
+DECLARE_RWSEM(afs_proc_cells_sem);
+LIST_HEAD(afs_proc_cells);
+
+static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
+static rwlock_t afs_cells_lock = RW_LOCK_UNLOCKED;
+static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
+static afs_cell_t *afs_cell_root;
+
+static char *rootcell;
+
+MODULE_PARM(rootcell,"s");
+MODULE_PARM_DESC(rootcell,"root AFS cell name and VL server IP addr list");
+
+/*****************************************************************************/
+/*
+ * create a cell record
+ * - "name" is the name of the cell
+ * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
+ */
+int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell)
+{
+	afs_cell_t *cell;
+	char *next;
+	int ret;
+
+	_enter("%s",name);
+
+	if (!name) BUG(); /* TODO: want to look up "this cell" in the cache */
+
+	down_write(&afs_cells_sem);
+
+	/* allocate and initialise a cell record */
+	cell = kmalloc(sizeof(afs_cell_t) + strlen(name) + 1,GFP_KERNEL);
+	if (!cell) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	memset(cell,0,sizeof(afs_cell_t));
+	atomic_set(&cell->usage,0);
+
+	INIT_LIST_HEAD(&cell->link);
+	INIT_LIST_HEAD(&cell->caches);
+
+	rwlock_init(&cell->sv_lock);
+	INIT_LIST_HEAD(&cell->sv_list);
+	INIT_LIST_HEAD(&cell->sv_graveyard);
+	spin_lock_init(&cell->sv_gylock);
+
+	init_rwsem(&cell->vl_sem);
+	INIT_LIST_HEAD(&cell->vl_list);
+	INIT_LIST_HEAD(&cell->vl_graveyard);
+	spin_lock_init(&cell->vl_gylock);
+
+	strcpy(cell->name,name);
+
+	/* fill in the VL server list from the rest of the string */
+	ret = -EINVAL;
+	do {
+		unsigned a, b, c, d;
+
+		next = strchr(vllist,':');
+		if (next) *next++ = 0;
+
+		if (sscanf(vllist,"%u.%u.%u.%u",&a,&b,&c,&d)!=4)
+			goto badaddr;
+
+		if (a>255 || b>255 || c>255 || d>255)
+			goto badaddr;
+
+		cell->vl_addrs[cell->vl_naddrs++].s_addr =
+			htonl((a<<24)|(b<<16)|(c<<8)|d);
+
+		if (cell->vl_naddrs>=16)
+			break;
+
+	} while(vllist=next, vllist);
+
+	/* add a proc dir for this cell */
+	ret = afs_proc_cell_setup(cell);
+	if (ret<0)
+		goto error;
+
+	/* add to the cell lists */
+	write_lock(&afs_cells_lock);
+	list_add_tail(&cell->link,&afs_cells);
+	write_unlock(&afs_cells_lock);
+
+	down_write(&afs_proc_cells_sem);
+	list_add_tail(&cell->proc_link,&afs_proc_cells);
+	up_write(&afs_proc_cells_sem);
+
+	*_cell = cell;
+	up_write(&afs_cells_sem);
+
+	_leave(" = 0 (%p)",cell);
+	return 0;
+
+ badaddr:
+	printk("kAFS: bad VL server IP address: '%s'\n",vllist);
+ error:
+	up_write(&afs_cells_sem);
+	kfree(afs_cell_root);
+	return ret;
+} /* end afs_cell_create() */
+
+/*****************************************************************************/
+/*
+ * initialise the cell database from module parameters
+ */
+int afs_cell_init(void)
+{
+	char *cp;
+	int ret;
+
+	_enter("");
+
+	if (!rootcell) {
+		printk("kAFS: no root cell specified\n");
+		return -EINVAL;
+	}
+
+	cp = strchr(rootcell,':');
+	if (!cp) {
+		printk("kAFS: no VL server IP addresses specified\n");
+		return -EINVAL;
+	}
+
+	/* allocate a cell record for the root cell */
+	*cp++ = 0;
+	ret = afs_cell_create(rootcell,cp,&afs_cell_root);
+	if (ret==0)
+		afs_get_cell(afs_cell_root);
+
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end afs_cell_init() */
+
+/*****************************************************************************/
+/*
+ * lookup a cell record
+ */
+int afs_cell_lookup(const char *name, afs_cell_t **_cell)
+{
+	struct list_head *_p;
+	afs_cell_t *cell;
+
+	_enter("\"%s\",",name?name:"*thiscell*");
+
+	cell = afs_cell_root;
+
+	if (name) {
+		/* if the cell was named, look for it in the cell record list */
+		cell = NULL;
+		read_lock(&afs_cells_lock);
+
+		list_for_each(_p,&afs_cells) {
+			cell = list_entry(_p,afs_cell_t,link);
+			if (strcmp(cell->name,name)==0)
+				break;
+			cell = NULL;
+		}
+
+		read_unlock(&afs_cells_lock);
+	}
+
+	if (cell)
+		afs_get_cell(cell);
+
+	*_cell = cell;
+	_leave(" = %d (%p)",cell?0:-ENOENT,cell);
+	return cell ? 0 : -ENOENT;
+
+} /* end afs_cell_lookup() */
+
+/*****************************************************************************/
+/*
+ * try and get a cell record
+ */
+afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell)
+{
+	afs_cell_t *cell;
+
+	write_lock(&afs_cells_lock);
+
+	cell = *_cell;
+	if (cell && !list_empty(&cell->link))
+		atomic_inc(&cell->usage);
+	else 
+		cell = NULL;
+
+	write_unlock(&afs_cells_lock);
+
+	return cell;
+} /* end afs_get_cell_maybe() */
+
+/*****************************************************************************/
+/*
+ * destroy a cell record
+ */
+void afs_put_cell(afs_cell_t *cell)
+{
+	_enter("%p{%d,%s}",cell,atomic_read(&cell->usage),cell->name);
+
+	/* sanity check */
+	if (atomic_read(&cell->usage)<=0)
+		BUG();
+
+	/* to prevent a race, the decrement and the dequeue must be effectively atomic */
+	write_lock(&afs_cells_lock);
+
+	if (likely(!atomic_dec_and_test(&cell->usage))) {
+		write_unlock(&afs_cells_lock);
+		_leave("");
+		return;
+	}
+
+	write_unlock(&afs_cells_lock);
+
+	if (!list_empty(&cell->sv_list))	BUG();
+	if (!list_empty(&cell->sv_graveyard))	BUG();
+	if (!list_empty(&cell->vl_list))	BUG();
+	if (!list_empty(&cell->vl_graveyard))	BUG();
+
+	_leave(" [unused]");
+} /* end afs_put_cell() */
+
+/*****************************************************************************/
+/*
+ * destroy a cell record
+ */
+static void afs_cell_destroy(afs_cell_t *cell)
+{
+	_enter("%p{%d,%s}",cell,atomic_read(&cell->usage),cell->name);
+
+	/* to prevent a race, the decrement and the dequeue must be effectively atomic */
+	write_lock(&afs_cells_lock);
+
+	/* sanity check */
+	if (atomic_read(&cell->usage)!=0)
+		BUG();
+
+	list_del_init(&cell->link);
+
+	write_unlock(&afs_cells_lock);
+
+	down_write(&afs_cells_sem);
+
+	afs_proc_cell_remove(cell);
+
+	down_write(&afs_proc_cells_sem);
+	list_del_init(&cell->proc_link);
+	up_write(&afs_proc_cells_sem);
+
+	up_write(&afs_cells_sem);
+
+	if (!list_empty(&cell->sv_list))	BUG();
+	if (!list_empty(&cell->sv_graveyard))	BUG();
+	if (!list_empty(&cell->vl_list))	BUG();
+	if (!list_empty(&cell->vl_graveyard))	BUG();
+
+	/* finish cleaning up the cell */
+	kfree(cell);
+
+	_leave(" [destroyed]");
+} /* end afs_cell_destroy() */
+
+/*****************************************************************************/
+/*
+ * lookup the server record corresponding to an Rx RPC peer
+ */
+int afs_server_find_by_peer(const struct rxrpc_peer *peer, afs_server_t **_server)
+{
+	struct list_head *_pc, *_ps;
+	afs_server_t *server;
+	afs_cell_t *cell;
+
+	_enter("%p{a=%08x},",peer,ntohl(peer->addr.s_addr));
+
+	/* search the cell list */
+	read_lock(&afs_cells_lock);
+
+	list_for_each(_pc,&afs_cells) {
+		cell = list_entry(_pc,afs_cell_t,link);
+
+		_debug("? cell %s",cell->name);
+
+		write_lock(&cell->sv_lock);
+
+		/* check the active list */
+		list_for_each(_ps,&cell->sv_list) {
+			server = list_entry(_ps,afs_server_t,link);
+
+			_debug("?? server %08x",ntohl(server->addr.s_addr));
+
+			if (memcmp(&server->addr,&peer->addr,sizeof(struct in_addr))==0)
+				goto found_server;
+		}
+
+		/* check the inactive list */
+		spin_lock(&cell->sv_gylock);
+		list_for_each(_ps,&cell->sv_graveyard) {
+			server = list_entry(_ps,afs_server_t,link);
+
+			_debug("?? dead server %08x",ntohl(server->addr.s_addr));
+
+			if (memcmp(&server->addr,&peer->addr,sizeof(struct in_addr))==0)
+				goto found_dead_server;
+		}
+		spin_unlock(&cell->sv_gylock);
+
+		write_unlock(&cell->sv_lock);
+	}
+	read_unlock(&afs_cells_lock);
+
+	_leave(" = -ENOENT");
+	return -ENOENT;
+
+	/* we found it in the graveyard - resurrect it */
+ found_dead_server:
+	list_del(&server->link);
+	list_add_tail(&server->link,&cell->sv_list);
+	afs_get_server(server);
+	afs_kafstimod_del_timer(&server->timeout);
+	spin_unlock(&cell->sv_gylock);
+	goto success;
+
+	/* we found it - increment its ref count and return it */
+ found_server:
+	afs_get_server(server);
+
+ success:
+	write_unlock(&cell->sv_lock);
+	read_unlock(&afs_cells_lock);
+
+	*_server = server;
+	_leave(" = 0 (s=%p c=%p)",server,cell);
+	return 0;
+
+} /* end afs_server_find_by_peer() */
+
+/*****************************************************************************/
+/*
+ * purge in-memory cell database on module unload
+ * - the timeout daemon is stopped before calling this
+ */
+void afs_cell_purge(void)
+{
+	afs_vlocation_t *vlocation;
+	afs_cell_t *cell;
+
+	_enter("");
+
+	if (afs_cell_root)
+		afs_put_cell(afs_cell_root);
+
+	while (!list_empty(&afs_cells)) {
+		cell = NULL;
+
+		/* remove the next cell from the front of the list */
+		write_lock(&afs_cells_lock);
+
+		if (!list_empty(&afs_cells)) {
+			cell = list_entry(afs_cells.next,afs_cell_t,link);
+			list_del_init(&cell->link);
+		}
+
+		write_unlock(&afs_cells_lock);
+
+		if (cell) {
+			_debug("PURGING CELL %s (%d)",cell->name,atomic_read(&cell->usage));
+
+			if (!list_empty(&cell->sv_list)) BUG();
+			if (!list_empty(&cell->vl_list)) BUG();
+
+			/* purge the cell's VL graveyard list */
+			_debug(" - clearing VL graveyard");
+
+			spin_lock(&cell->vl_gylock);
+
+			while (!list_empty(&cell->vl_graveyard)) {
+				vlocation = list_entry(cell->vl_graveyard.next,
+						       afs_vlocation_t,link);
+				list_del_init(&vlocation->link);
+
+				afs_kafstimod_del_timer(&vlocation->timeout);
+
+				spin_unlock(&cell->vl_gylock);
+
+				afs_vlocation_do_timeout(vlocation);
+				/* TODO: race if move to use krxtimod instead of kafstimod */
+
+				spin_lock(&cell->vl_gylock);
+			}
+
+			spin_unlock(&cell->vl_gylock);
+
+			/* purge the cell's server graveyard list */
+			_debug(" - clearing server graveyard");
+
+			spin_lock(&cell->sv_gylock);
+
+			while (!list_empty(&cell->sv_graveyard)) {
+				afs_server_t *server;
+
+				server = list_entry(cell->sv_graveyard.next,afs_server_t,link);
+				list_del_init(&server->link);
+
+				afs_kafstimod_del_timer(&server->timeout);
+
+				spin_unlock(&cell->sv_gylock);
+
+				afs_server_do_timeout(server);
+
+				spin_lock(&cell->sv_gylock);
+			}
+
+			spin_unlock(&cell->sv_gylock);
+
+			/* now the cell should be left with no references */
+			afs_cell_destroy(cell);
+		}
+	}
+
+	_leave("");
+} /* end afs_cell_purge() */
diff -Nru a/fs/afs/cell.h b/fs/afs/cell.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/cell.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,63 @@
+/* cell.h: AFS cell record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_CELL_H
+#define _LINUX_AFS_CELL_H
+
+#include "types.h"
+
+extern volatile int afs_cells_being_purged; /* T when cells are being purged by rmmod */
+
+/*****************************************************************************/
+/*
+ * AFS cell record
+ */
+struct afs_cell
+{
+	atomic_t		usage;
+	struct list_head	link;		/* main cell list link */
+	struct list_head	proc_link;	/* /proc cell list link */
+	struct proc_dir_entry	*proc_dir;	/* /proc dir for this cell */
+	struct list_head	caches;		/* list of caches currently backing this cell */
+
+	/* server record management */
+	rwlock_t		sv_lock;	/* active server list lock */
+	struct list_head	sv_list;	/* active server list */
+	struct list_head	sv_graveyard;	/* inactive server list */
+	spinlock_t		sv_gylock;	/* inactive server list lock */
+
+	/* volume location record management */
+	struct rw_semaphore	vl_sem;		/* volume management serialisation semaphore */
+	struct list_head	vl_list;	/* cell's active VL record list */
+	struct list_head	vl_graveyard;	/* cell's inactive VL record list */
+	spinlock_t		vl_gylock;	/* graveyard lock */
+	unsigned short		vl_naddrs;	/* number of VL servers in addr list */
+	unsigned short		vl_curr_svix;	/* current server index */
+	struct in_addr		vl_addrs[16];	/* cell VL server addresses */
+
+	char			name[0];	/* cell name - must go last */
+};
+
+extern int afs_cell_init(void);
+
+extern int afs_cell_create(const char *name, char *vllist, afs_cell_t **_cell);
+
+extern int afs_cell_lookup(const char *name, afs_cell_t **_cell);
+
+#define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
+
+extern afs_cell_t *afs_get_cell_maybe(afs_cell_t **_cell);
+
+extern void afs_put_cell(afs_cell_t *cell);
+
+extern void afs_cell_purge(void);
+
+#endif /* _LINUX_AFS_CELL_H */
diff -Nru a/fs/afs/cmservice.c b/fs/afs/cmservice.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/cmservice.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,639 @@
+/* cmservice.c: AFS Cache Manager Service
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include "server.h"
+#include "cell.h"
+#include "transport.h"
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include "cmservice.h"
+#include "internal.h"
+
+static unsigned afscm_usage;		/* AFS cache manager usage count */
+static struct rw_semaphore afscm_sem;	/* AFS cache manager start/stop semaphore */
+
+static int afscm_new_call(struct rxrpc_call *call);
+static void afscm_attention(struct rxrpc_call *call);
+static void afscm_error(struct rxrpc_call *call);
+static void afscm_aemap(struct rxrpc_call *call);
+
+static void _SRXAFSCM_CallBack(struct rxrpc_call *call);
+static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call);
+static void _SRXAFSCM_Probe(struct rxrpc_call *call);
+
+typedef void (*_SRXAFSCM_xxxx_t)(struct rxrpc_call *call);
+
+static const struct rxrpc_operation AFSCM_ops[] = {
+	{
+		.id	= 204,
+		.asize	= RXRPC_APP_MARK_EOF,
+		.name	= "CallBack",
+		.user	= _SRXAFSCM_CallBack,
+	},
+	{
+		.id	= 205,
+		.asize	= RXRPC_APP_MARK_EOF,
+		.name	= "InitCallBackState",
+		.user	= _SRXAFSCM_InitCallBackState,
+	},
+	{
+		.id	= 206,
+		.asize	= RXRPC_APP_MARK_EOF,
+		.name	= "Probe",
+		.user	= _SRXAFSCM_Probe,
+	},
+#if 0
+	{
+		.id	= 207,
+		.asize	= RXRPC_APP_MARK_EOF,
+		.name	= "GetLock",
+		.user	= _SRXAFSCM_GetLock,
+	},
+	{
+		.id	= 208,
+		.asize	= RXRPC_APP_MARK_EOF,
+		.name	= "GetCE",
+		.user	= _SRXAFSCM_GetCE,
+	},
+	{
+		.id	= 209,
+		.asize	= RXRPC_APP_MARK_EOF,
+		.name	= "GetXStatsVersion",
+		.user	= _SRXAFSCM_GetXStatsVersion,
+	},
+	{
+		.id	= 210,
+		.asize	= RXRPC_APP_MARK_EOF,
+		.name	= "GetXStats",
+		.user	= _SRXAFSCM_GetXStats,
+	}
+#endif
+};
+
+static struct rxrpc_service AFSCM_service = {
+	.name		= "AFS/CM",
+	.owner		= THIS_MODULE,
+	.link		= LIST_HEAD_INIT(AFSCM_service.link),
+	.new_call	= afscm_new_call,
+	.service_id	= 1,
+	.attn_func	= afscm_attention,
+	.error_func	= afscm_error,
+	.aemap_func	= afscm_aemap,
+	.ops_begin	= &AFSCM_ops[0],
+	.ops_end	= &AFSCM_ops[sizeof(AFSCM_ops)/sizeof(AFSCM_ops[0])],
+};
+
+static DECLARE_COMPLETION(kafscmd_alive);
+static DECLARE_COMPLETION(kafscmd_dead);
+static DECLARE_WAIT_QUEUE_HEAD(kafscmd_sleepq);
+static LIST_HEAD(kafscmd_attention_list);
+static LIST_HEAD(afscm_calls);
+static spinlock_t afscm_calls_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t kafscmd_attention_lock = SPIN_LOCK_UNLOCKED;
+static int kafscmd_die;
+
+/*****************************************************************************/
+/*
+ * AFS Cache Manager kernel thread
+ */
+static int kafscmd(void *arg)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_call *call;
+	_SRXAFSCM_xxxx_t func;
+	int die;
+
+	printk("kAFS: Started kafscmd %d\n",current->pid);
+	strcpy(current->comm,"kafscmd");
+
+	daemonize();
+
+	complete(&kafscmd_alive);
+
+	/* only certain signals are of interest */
+	spin_lock_irq(&current->sig->siglock);
+	siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+	recalc_sigpending();
+#else
+	recalc_sigpending(current);
+#endif
+	spin_unlock_irq(&current->sig->siglock);
+
+	/* loop around looking for things to attend to */
+	do {
+		if (list_empty(&kafscmd_attention_list)) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			add_wait_queue(&kafscmd_sleepq,&myself);
+
+			for (;;) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (!list_empty(&kafscmd_attention_list) ||
+				    signal_pending(current) ||
+				    kafscmd_die)
+					break;
+
+				schedule();
+			}
+
+			remove_wait_queue(&kafscmd_sleepq,&myself);
+			set_current_state(TASK_RUNNING);
+		}
+
+		die = kafscmd_die;
+
+		/* dequeue the next call requiring attention */
+		call = NULL;
+		spin_lock(&kafscmd_attention_lock);
+
+		if (!list_empty(&kafscmd_attention_list)) {
+			call = list_entry(kafscmd_attention_list.next,
+					  struct rxrpc_call,
+					  app_attn_link);
+			list_del_init(&call->app_attn_link);
+			die = 0;
+		}
+
+		spin_unlock(&kafscmd_attention_lock);
+
+		if (call) {
+			/* act upon it */
+			_debug("@@@ Begin Attend Call %p",call);
+
+			func = call->app_user;
+			if (func)
+				func(call);
+
+			rxrpc_put_call(call);
+
+			_debug("@@@ End Attend Call %p",call);
+		}
+
+	} while(!die);
+
+	/* and that's all */
+	complete_and_exit(&kafscmd_dead,0);
+
+} /* end kafscmd() */
+
+/*****************************************************************************/
+/*
+ * handle a call coming in to the cache manager
+ * - if I want to keep the call, I must increment its usage count
+ * - the return value will be negated and passed back in an abort packet if non-zero
+ * - serialised by virtue of there only being one krxiod
+ */
+static int afscm_new_call(struct rxrpc_call *call)
+{
+	_enter("%p{cid=%u u=%d}",call,ntohl(call->call_id),atomic_read(&call->usage));
+
+	rxrpc_get_call(call);
+
+	/* add to my current call list */
+	spin_lock(&afscm_calls_lock);
+	list_add(&call->app_link,&afscm_calls);
+	spin_unlock(&afscm_calls_lock);
+
+	_leave(" = 0");
+	return 0;
+
+} /* end afscm_new_call() */
+
+/*****************************************************************************/
+/*
+ * queue on the kafscmd queue for attention
+ */
+static void afscm_attention(struct rxrpc_call *call)
+{
+	_enter("%p{cid=%u u=%d}",call,ntohl(call->call_id),atomic_read(&call->usage));
+
+	spin_lock(&kafscmd_attention_lock);
+
+	if (list_empty(&call->app_attn_link)) {
+		list_add_tail(&call->app_attn_link,&kafscmd_attention_list);
+		rxrpc_get_call(call);
+	}
+
+	spin_unlock(&kafscmd_attention_lock);
+
+	wake_up(&kafscmd_sleepq);
+
+	_leave(" {u=%d}",atomic_read(&call->usage));
+} /* end afscm_attention() */
+
+/*****************************************************************************/
+/*
+ * handle my call being aborted
+ * - clean up, dequeue and put my ref to the call
+ */
+static void afscm_error(struct rxrpc_call *call)
+{
+	int removed;
+
+	_enter("%p{est=%s ac=%u er=%d}",
+	       call,
+	       rxrpc_call_error_states[call->app_err_state],
+	       call->app_abort_code,
+	       call->app_errno);
+
+	spin_lock(&kafscmd_attention_lock);
+
+	if (list_empty(&call->app_attn_link)) {
+		list_add_tail(&call->app_attn_link,&kafscmd_attention_list);
+		rxrpc_get_call(call);
+	}
+
+	spin_unlock(&kafscmd_attention_lock);
+
+	removed = 0;
+	spin_lock(&afscm_calls_lock);
+	if (!list_empty(&call->app_link)) {
+		list_del_init(&call->app_link);
+		removed = 1;
+	}
+	spin_unlock(&afscm_calls_lock);
+
+	if (removed)
+		rxrpc_put_call(call);
+
+	wake_up(&kafscmd_sleepq);
+
+	_leave("");
+} /* end afscm_error() */
+
+/*****************************************************************************/
+/*
+ * map afs abort codes to/from Linux error codes
+ * - called with call->lock held
+ */
+static void afscm_aemap(struct rxrpc_call *call)
+{
+	switch (call->app_err_state) {
+	case RXRPC_ESTATE_LOCAL_ABORT:
+		call->app_abort_code = -call->app_errno;
+		break;
+	case RXRPC_ESTATE_PEER_ABORT:
+		call->app_errno = -ECONNABORTED;
+		break;
+	default:
+		break;
+	}
+} /* end afscm_aemap() */
+
+/*****************************************************************************/
+/*
+ * start the cache manager service if not already started
+ */
+int afscm_start(void)
+{
+	int ret;
+
+	down_write(&afscm_sem);
+	if (!afscm_usage) {
+		ret = kernel_thread(kafscmd,NULL,0);
+		if (ret<0)
+			goto out;
+
+		wait_for_completion(&kafscmd_alive);
+
+		ret = rxrpc_add_service(afs_transport,&AFSCM_service);
+		if (ret<0)
+			goto kill;
+	}
+
+	afscm_usage++;
+	up_write(&afscm_sem);
+
+	return 0;
+
+ kill:
+	kafscmd_die = 1;
+	wake_up(&kafscmd_sleepq);
+	wait_for_completion(&kafscmd_dead);
+
+ out:
+	up_write(&afscm_sem);
+	return ret;
+
+} /* end afscm_start() */
+
+/*****************************************************************************/
+/*
+ * stop the cache manager service
+ */
+void afscm_stop(void)
+{
+	struct rxrpc_call *call;
+
+	down_write(&afscm_sem);
+
+	if (afscm_usage==0) BUG();
+	afscm_usage--;
+
+	if (afscm_usage==0) {
+		/* don't want more incoming calls */
+		rxrpc_del_service(afs_transport,&AFSCM_service);
+
+		/* abort any calls I've still got open (the afscm_error() will dequeue them) */
+		spin_lock(&afscm_calls_lock);
+		while (!list_empty(&afscm_calls)) {
+			call = list_entry(afscm_calls.next,struct rxrpc_call,app_link);
+			list_del_init(&call->app_link);
+			rxrpc_get_call(call);
+			spin_unlock(&afscm_calls_lock);
+
+			rxrpc_call_abort(call,-ESRCH); /* abort, dequeue and put */
+
+			rxrpc_put_call(call);
+
+			spin_lock(&afscm_calls_lock);
+		}
+		spin_unlock(&afscm_calls_lock);
+
+		/* get rid of my daemon */
+		kafscmd_die = 1;
+		wake_up(&kafscmd_sleepq);
+		wait_for_completion(&kafscmd_dead);
+
+		/* dispose of any calls waiting for attention */
+		spin_lock(&kafscmd_attention_lock);
+		while (!list_empty(&kafscmd_attention_list)) {
+			call = list_entry(kafscmd_attention_list.next,
+					  struct rxrpc_call,
+					  app_attn_link);
+
+			list_del_init(&call->app_attn_link);
+			spin_unlock(&kafscmd_attention_lock);
+
+			rxrpc_put_call(call);
+
+			spin_lock(&kafscmd_attention_lock);
+		}
+		spin_unlock(&kafscmd_attention_lock);
+	}
+
+	up_write(&afscm_sem);
+
+} /* end afscm_stop() */
+
+/*****************************************************************************/
+/*
+ * handle the fileserver breaking a set of callbacks
+ */
+static void _SRXAFSCM_CallBack(struct rxrpc_call *call)
+{
+	afs_server_t *server;
+	size_t count, qty, tmp;
+	int ret = 0, removed;
+
+	_enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
+
+	server = afs_server_get_from_peer(call->conn->peer);
+
+	switch (call->app_call_state) {
+		/* we've received the last packet
+		 * - drain all the data from the call and send the reply
+		 */
+	case RXRPC_CSTATE_SRVR_GOT_ARGS:
+		ret = -EBADMSG;
+		qty = call->app_ready_qty;
+		if (qty<8 || qty>50*(6*4)+8)
+			break;
+
+		{
+			afs_callback_t *cb, *pcb;
+			int loop;
+			u32 *fp, *bp;
+
+			fp = rxrpc_call_alloc_scratch(call,qty);
+
+			/* drag the entire argument block out to the scratch space */
+			ret = rxrpc_call_read_data(call,fp,qty,0);
+			if (ret<0)
+				break;
+
+			/* and unmarshall the parameter block */
+			ret = -EBADMSG;
+			count = ntohl(*fp++);
+			if (count>AFSCBMAX ||
+			    (count*(3*4)+8 != qty && count*(6*4)+8 != qty))
+				break;
+
+			bp = fp + count*3;
+			tmp = ntohl(*bp++);
+			if (tmp>0 && tmp!=count)
+				break;
+			if (tmp==0)
+				bp = NULL;
+
+			pcb = cb = rxrpc_call_alloc_scratch_s(call,afs_callback_t);
+
+			for (loop=count-1; loop>=0; loop--) {
+				pcb->fid.vid	= ntohl(*fp++);
+				pcb->fid.vnode	= ntohl(*fp++);
+				pcb->fid.unique	= ntohl(*fp++);
+				if (bp) {
+					pcb->version	= ntohl(*bp++);
+					pcb->expiry	= ntohl(*bp++);
+					pcb->type	= ntohl(*bp++);
+				}
+				else {
+					pcb->version	= 0;
+					pcb->expiry	= 0;
+					pcb->type	= AFSCM_CB_UNTYPED;
+				}
+				pcb++;
+			}
+
+			/* invoke the actual service routine */
+			ret = SRXAFSCM_CallBack(server,count,cb);
+			if (ret<0)
+				break;
+		}
+
+		/* send the reply */
+		ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
+		if (ret<0)
+			break;
+		break;
+
+		/* operation complete */
+	case RXRPC_CSTATE_COMPLETE:
+		call->app_user = NULL;
+		removed = 0;
+		spin_lock(&afscm_calls_lock);
+		if (!list_empty(&call->app_link)) {
+			list_del_init(&call->app_link);
+			removed = 1;
+		}
+		spin_unlock(&afscm_calls_lock);
+
+		if (removed)
+			rxrpc_put_call(call);
+		break;
+
+		/* operation terminated on error */
+	case RXRPC_CSTATE_ERROR:
+		call->app_user = NULL;
+		break;
+
+	default:
+		break;
+	}
+
+	if (ret<0)
+		rxrpc_call_abort(call,ret);
+
+	if (server) afs_put_server(server);
+
+	_leave(" = %d",ret);
+
+} /* end _SRXAFSCM_CallBack() */
+
+/*****************************************************************************/
+/*
+ * handle the fileserver asking us to initialise our callback state
+ */
+static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call)
+{
+	afs_server_t *server;
+	size_t count;
+	int ret = 0, removed;
+
+	_enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
+
+	server = afs_server_get_from_peer(call->conn->peer);
+
+	switch (call->app_call_state) {
+		/* we've received the last packet - drain all the data from the call */
+	case RXRPC_CSTATE_SRVR_GOT_ARGS:
+		/* shouldn't be any args */
+		ret = -EBADMSG;
+		break;
+
+		/* send the reply when asked for it */
+	case RXRPC_CSTATE_SRVR_SND_REPLY:
+		/* invoke the actual service routine */
+		ret = SRXAFSCM_InitCallBackState(server);
+		if (ret<0)
+			break;
+
+		ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
+		if (ret<0)
+			break;
+		break;
+
+		/* operation complete */
+	case RXRPC_CSTATE_COMPLETE:
+		call->app_user = NULL;
+		removed = 0;
+		spin_lock(&afscm_calls_lock);
+		if (!list_empty(&call->app_link)) {
+			list_del_init(&call->app_link);
+			removed = 1;
+		}
+		spin_unlock(&afscm_calls_lock);
+
+		if (removed)
+			rxrpc_put_call(call);
+		break;
+
+		/* operation terminated on error */
+	case RXRPC_CSTATE_ERROR:
+		call->app_user = NULL;
+		break;
+
+	default:
+		break;
+	}
+
+	if (ret<0)
+		rxrpc_call_abort(call,ret);
+
+	if (server) afs_put_server(server);
+
+	_leave(" = %d",ret);
+
+} /* end _SRXAFSCM_InitCallBackState() */
+
+/*****************************************************************************/
+/*
+ * handle a probe from a fileserver
+ */
+static void _SRXAFSCM_Probe(struct rxrpc_call *call)
+{
+	afs_server_t *server;
+	size_t count;
+	int ret = 0, removed;
+
+	_enter("%p{acs=%s}",call,rxrpc_call_states[call->app_call_state]);
+
+	server = afs_server_get_from_peer(call->conn->peer);
+
+	switch (call->app_call_state) {
+		/* we've received the last packet - drain all the data from the call */
+	case RXRPC_CSTATE_SRVR_GOT_ARGS:
+		/* shouldn't be any args */
+		ret = -EBADMSG;
+		break;
+
+		/* send the reply when asked for it */
+	case RXRPC_CSTATE_SRVR_SND_REPLY:
+		/* invoke the actual service routine */
+		ret = SRXAFSCM_Probe(server);
+		if (ret<0)
+			break;
+
+		ret = rxrpc_call_write_data(call,0,NULL,RXRPC_LAST_PACKET,GFP_KERNEL,0,&count);
+		if (ret<0)
+			break;
+		break;
+
+		/* operation complete */
+	case RXRPC_CSTATE_COMPLETE:
+		call->app_user = NULL;
+		removed = 0;
+		spin_lock(&afscm_calls_lock);
+		if (!list_empty(&call->app_link)) {
+			list_del_init(&call->app_link);
+			removed = 1;
+		}
+		spin_unlock(&afscm_calls_lock);
+
+		if (removed)
+			rxrpc_put_call(call);
+		break;
+
+		/* operation terminated on error */
+	case RXRPC_CSTATE_ERROR:
+		call->app_user = NULL;
+		break;
+
+	default:
+		break;
+	}
+
+	if (ret<0)
+		rxrpc_call_abort(call,ret);
+
+	if (server) afs_put_server(server);
+
+	_leave(" = %d",ret);
+
+} /* end _SRXAFSCM_Probe() */
diff -Nru a/fs/afs/cmservice.h b/fs/afs/cmservice.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/cmservice.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,27 @@
+/* cmservice.h: AFS Cache Manager Service declarations
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_CMSERVICE_H
+#define _LINUX_AFS_CMSERVICE_H
+
+#include <rxrpc/transport.h>
+#include "types.h"
+
+/* cache manager start/stop */
+extern int afscm_start(void);
+extern void afscm_stop(void);
+
+/* cache manager server functions */
+extern int SRXAFSCM_InitCallBackState(afs_server_t *server);
+extern int SRXAFSCM_CallBack(afs_server_t *server, size_t count, afs_callback_t callbacks[]);
+extern int SRXAFSCM_Probe(afs_server_t *server);
+
+#endif /* _LINUX_AFS_CMSERVICE_H */
diff -Nru a/fs/afs/dir.c b/fs/afs/dir.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/dir.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,642 @@
+/* dir.c: AFS filesystem directory handling
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include "vnode.h"
+#include "volume.h"
+#include <rxrpc/call.h>
+#include "super.h"
+#include "internal.h"
+
+static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry);
+static int afs_dir_open(struct inode *inode, struct file *file);
+static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir);
+static int afs_d_revalidate(struct dentry *dentry, int flags);
+static int afs_d_delete(struct dentry *dentry);
+static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos,
+				     ino_t ino, unsigned dtype);
+
+struct file_operations afs_dir_file_operations = {
+	.open		= afs_dir_open,
+	.readdir	= afs_dir_readdir,
+};
+
+struct inode_operations afs_dir_inode_operations = {
+	.lookup		= afs_dir_lookup,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	.getattr	= afs_inode_getattr,
+#else
+	.revalidate	= afs_inode_revalidate,
+#endif
+//	.create		= afs_dir_create,
+//	.link		= afs_dir_link,
+//	.unlink		= afs_dir_unlink,
+//	.symlink	= afs_dir_symlink,
+//	.mkdir		= afs_dir_mkdir,
+//	.rmdir		= afs_dir_rmdir,
+//	.mknod		= afs_dir_mknod,
+//	.rename		= afs_dir_rename,
+};
+
+static struct dentry_operations afs_fs_dentry_operations = {
+	.d_revalidate	= afs_d_revalidate,
+	.d_delete	= afs_d_delete,
+};
+
+#define AFS_DIR_HASHTBL_SIZE	128
+#define AFS_DIR_DIRENT_SIZE	32
+#define AFS_DIRENT_PER_BLOCK	64
+
+typedef union afs_dirent {
+	struct {
+		u8	valid;
+		u8	unused[1];
+		u16	hash_next;
+		u32	vnode;
+		u32	unique;
+		u8	name[16];
+		u8	overflow[4];	/* if any char of the name (inc NUL) reaches here, consume
+					 * the next dirent too */
+	};
+	u8	extended_name[32];
+} afs_dirent_t;
+
+/* AFS directory page header (one at the beginning of every 2048-byte chunk) */
+typedef struct afs_dir_pagehdr {
+	u16	npages;
+	u16	magic;
+#define AFS_DIR_MAGIC htons(1234)
+	u8	nentries;
+	u8	bitmap[8];
+	u8	pad[19];
+} afs_dir_pagehdr_t;
+
+/* directory block layout */
+typedef union afs_dir_block {
+
+	afs_dir_pagehdr_t pagehdr;
+
+	struct {
+		afs_dir_pagehdr_t pagehdr;
+		u8		alloc_ctrs[128];
+		u16		hashtable[AFS_DIR_HASHTBL_SIZE]; /* dir hash table */
+	} hdr;
+
+	afs_dirent_t dirents[AFS_DIRENT_PER_BLOCK];
+} afs_dir_block_t;
+
+/* layout on a linux VM page */
+typedef struct afs_dir_page {
+	afs_dir_block_t	blocks[PAGE_SIZE/sizeof(afs_dir_block_t)];
+} afs_dir_page_t;
+
+struct afs_dir_lookup_cookie {
+	afs_fid_t	fid;
+	const char	*name;
+	size_t		nlen;
+	int		found;
+};
+
+/*****************************************************************************/
+/*
+ * check that a directory page is valid
+ */
+static inline void afs_dir_check_page(struct inode *dir, struct page *page)
+{
+	afs_dir_page_t *dbuf;
+	loff_t latter;
+	int tmp, qty;
+
+#if 0
+	/* check the page count */
+	qty = desc.size/sizeof(dbuf->blocks[0]);
+	if (qty==0)
+		goto error;
+
+	if (page->index==0 && qty!=ntohs(dbuf->blocks[0].pagehdr.npages)) {
+		printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n",
+		       __FUNCTION__,dir->i_ino,qty,ntohs(dbuf->blocks[0].pagehdr.npages));
+		goto error;
+	}
+#endif
+
+	/* determine how many magic numbers there should be in this page */
+	latter = dir->i_size - (page->index << PAGE_CACHE_SHIFT);
+	if (latter >= PAGE_SIZE)
+		qty = PAGE_SIZE;
+	else
+		qty = latter;
+	qty /= sizeof(afs_dir_block_t);
+
+	/* check them */
+	dbuf = page_address(page);
+	for (tmp=0; tmp<qty; tmp++) {
+		if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
+			printk("kAFS: %s(%lu): bad magic %d/%d is %04hx\n",
+			       __FUNCTION__,dir->i_ino,tmp,
+			       qty,ntohs(dbuf->blocks[tmp].pagehdr.magic));
+			goto error;
+		}
+	}
+
+	SetPageChecked(page);
+	return;
+
+ error:
+	SetPageChecked(page);
+	SetPageError(page);
+
+} /* end afs_dir_check_page() */
+
+/*****************************************************************************/
+/*
+ * discard a page cached in the pagecache
+ */
+static inline void afs_dir_put_page(struct page *page)
+{
+	kunmap(page);
+	page_cache_release(page);
+
+} /* end afs_dir_put_page() */
+
+/*****************************************************************************/
+/*
+ * get a page into the pagecache
+ */
+static struct page *afs_dir_get_page(struct inode *dir, unsigned long index)
+{
+	struct page *page;
+
+	_enter("{%lu},%lu",dir->i_ino,index);
+
+	page = read_cache_page(dir->i_mapping,index,
+			       (filler_t*)dir->i_mapping->a_ops->readpage,NULL);
+	if (!IS_ERR(page)) {
+		wait_on_page_locked(page);
+		kmap(page);
+		if (!PageUptodate(page))
+			goto fail;
+		if (!PageChecked(page))
+			afs_dir_check_page(dir,page);
+		if (PageError(page))
+			goto fail;
+	}
+	return page;
+
+ fail:
+	afs_dir_put_page(page);
+	return ERR_PTR(-EIO);
+} /* end afs_dir_get_page() */
+
+/*****************************************************************************/
+/*
+ * open an AFS directory file
+ */
+static int afs_dir_open(struct inode *inode, struct file *file)
+{
+	_enter("{%lu}",inode->i_ino);
+
+	if (sizeof(afs_dir_block_t) != 2048) BUG();
+	if (sizeof(afs_dirent_t) != 32) BUG();
+
+	if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED)
+		return -ENOENT;
+
+	_leave(" = 0");
+	return 0;
+
+} /* end afs_dir_open() */
+
+/*****************************************************************************/
+/*
+ * deal with one block in an AFS directory
+ */
+static int afs_dir_iterate_block(unsigned *fpos,
+				    afs_dir_block_t *block,
+				    unsigned blkoff,
+				    void *cookie,
+				    filldir_t filldir)
+{
+	afs_dirent_t *dire;
+	unsigned offset, next, curr;
+	size_t nlen;
+	int tmp, ret;
+
+	_enter("%u,%x,%p,,",*fpos,blkoff,block);
+
+	curr = (*fpos - blkoff) / sizeof(afs_dirent_t);
+
+	/* walk through the block, an entry at a time */
+	for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries;
+	     offset < AFS_DIRENT_PER_BLOCK;
+	     offset = next
+	     ) {
+		next = offset + 1;
+
+		/* skip entries marked unused in the bitmap */
+		if (!(block->pagehdr.bitmap[offset/8] & (1 << (offset % 8)))) {
+			_debug("ENT[%u.%u]: unused\n",blkoff/sizeof(afs_dir_block_t),offset);
+			if (offset>=curr)
+				*fpos = blkoff + next * sizeof(afs_dirent_t);
+			continue;
+		}
+
+		/* got a valid entry */
+		dire = &block->dirents[offset];
+		nlen = strnlen(dire->name,sizeof(*block) - offset*sizeof(afs_dirent_t));
+
+		_debug("ENT[%u.%u]: %s %u \"%.*s\"\n",
+		       blkoff/sizeof(afs_dir_block_t),offset,
+		       offset<curr ? "skip" : "fill",
+		       nlen,nlen,dire->name);
+
+		/* work out where the next possible entry is */
+		for (tmp=nlen; tmp>15; tmp-=sizeof(afs_dirent_t)) {
+			if (next>=AFS_DIRENT_PER_BLOCK) {
+				_debug("ENT[%u.%u]:"
+				       " %u travelled beyond end dir block (len %u/%u)\n",
+				       blkoff/sizeof(afs_dir_block_t),offset,next,tmp,nlen);
+				return -EIO;
+			}
+			if (!(block->pagehdr.bitmap[next/8] & (1 << (next % 8)))) {
+				_debug("ENT[%u.%u]: %u unmarked extension (len %u/%u)\n",
+				       blkoff/sizeof(afs_dir_block_t),offset,next,tmp,nlen);
+				return -EIO;
+			}
+
+			_debug("ENT[%u.%u]: ext %u/%u\n",
+			       blkoff/sizeof(afs_dir_block_t),next,tmp,nlen);
+			next++;
+		}
+
+		/* skip if starts before the current position */
+		if (offset<curr)
+			continue;
+
+		/* found the next entry */
+		ret = filldir(cookie,
+			      dire->name,
+			      nlen,
+			      blkoff + offset * sizeof(afs_dirent_t),
+			      ntohl(dire->vnode),
+			      filldir==afs_dir_lookup_filldir ? dire->unique : DT_UNKNOWN);
+		if (ret<0) {
+			_leave(" = 0 [full]");
+			return 0;
+		}
+
+		*fpos = blkoff + next * sizeof(afs_dirent_t);
+	}
+
+	_leave(" = 1 [more]");
+	return 1;
+} /* end afs_dir_iterate_block() */
+
+/*****************************************************************************/
+/*
+ * read an AFS directory
+ */
+static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, filldir_t filldir)
+{
+	afs_dir_block_t	*dblock;
+	afs_dir_page_t *dbuf;
+	struct page *page;
+	unsigned blkoff, limit;
+	int ret;
+
+	_enter("{%lu},%u,,",dir->i_ino,*fpos);
+
+	if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) {
+		_leave(" = -ESTALE");
+		return -ESTALE;
+	}
+
+	/* round the file position up to the next entry boundary */
+	*fpos += sizeof(afs_dirent_t) - 1;
+	*fpos &= ~(sizeof(afs_dirent_t) - 1);
+
+	/* walk through the blocks in sequence */
+	ret = 0;
+	while (*fpos < dir->i_size) {
+		blkoff = *fpos & ~(sizeof(afs_dir_block_t) - 1);
+
+		/* fetch the appropriate page from the directory */
+		page = afs_dir_get_page(dir,blkoff/PAGE_SIZE);
+		if (IS_ERR(page)) {
+			ret = PTR_ERR(page);
+			break;
+		}
+
+		limit = blkoff & ~(PAGE_SIZE-1);
+
+		dbuf = page_address(page);
+
+		/* deal with the individual blocks stashed on this page */
+		do {
+			dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) / sizeof(afs_dir_block_t)];
+			ret = afs_dir_iterate_block(fpos,dblock,blkoff,cookie,filldir);
+			if (ret!=1) {
+				afs_dir_put_page(page);
+				goto out;
+			}
+
+			blkoff += sizeof(afs_dir_block_t);
+
+		} while (*fpos < dir->i_size && blkoff < limit);
+
+		afs_dir_put_page(page);
+		ret = 0;
+	}
+
+ out:
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_dir_iterate() */
+
+/*****************************************************************************/
+/*
+ * read an AFS directory
+ */
+static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir)
+{
+	unsigned fpos;
+	int ret;
+
+	_enter("{%Ld,{%lu}}",file->f_pos,file->f_dentry->d_inode->i_ino);
+
+	fpos = file->f_pos;
+	ret = afs_dir_iterate(file->f_dentry->d_inode,&fpos,cookie,filldir);
+	file->f_pos = fpos;
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_dir_readdir() */
+
+/*****************************************************************************/
+/*
+ * search the directory for a name
+ * - if afs_dir_iterate_block() spots this function, it'll pass the FID uniquifier through dtype
+ */
+static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen, loff_t fpos,
+				  ino_t ino, unsigned dtype)
+{
+	struct afs_dir_lookup_cookie *cookie = _cookie;
+
+	_enter("{%s,%u},%s,%u,,%lu,%u",cookie->name,cookie->nlen,name,nlen,ino,ntohl(dtype));
+
+	if (cookie->nlen != nlen || memcmp(cookie->name,name,nlen)!=0) {
+		_leave(" = 0 [no]");
+		return 0;
+	}
+
+	cookie->fid.vnode = ino;
+	cookie->fid.unique = ntohl(dtype);
+	cookie->found = 1;
+
+	_leave(" = -1 [found]");
+	return -1;
+} /* end afs_dir_lookup_filldir() */
+
+/*****************************************************************************/
+/*
+ * look up an entry in a directory
+ */
+static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry)
+{
+	struct afs_dir_lookup_cookie cookie;
+	struct afs_super_info *as;
+	struct inode *inode;
+	afs_vnode_t *vnode;
+	unsigned fpos;
+	int ret;
+
+	_enter("{%lu},{%s}",dir->i_ino,dentry->d_name.name);
+
+	/* insanity checks first */
+	if (sizeof(afs_dir_block_t) != 2048) BUG();
+	if (sizeof(afs_dirent_t) != 32) BUG();
+
+	if (dentry->d_name.len > 255) {
+		_leave(" = -ENAMETOOLONG");
+		return ERR_PTR(-ENAMETOOLONG);
+	}
+
+	vnode = AFS_FS_I(dir);
+	if (vnode->flags & AFS_VNODE_DELETED) {
+		_leave(" = -ESTALE");
+		return ERR_PTR(-ESTALE);
+	}
+
+	as = dir->i_sb->s_fs_info;
+
+	/* search the directory */
+	cookie.name	= dentry->d_name.name;
+	cookie.nlen	= dentry->d_name.len;
+	cookie.fid.vid	= as->volume->vid;
+	cookie.found	= 0;
+
+	fpos = 0;
+	ret = afs_dir_iterate(dir,&fpos,&cookie,afs_dir_lookup_filldir);
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ERR_PTR(ret);
+	}
+
+	ret = -ENOENT;
+	if (!cookie.found) {
+		_leave(" = %d",ret);
+		return ERR_PTR(ret);
+	}
+
+	/* instantiate the dentry */
+	ret = afs_iget(dir->i_sb,&cookie.fid,&inode);
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ERR_PTR(ret);
+	}
+
+	dentry->d_op = &afs_fs_dentry_operations;
+	dentry->d_fsdata = (void*) (unsigned) vnode->status.version;
+
+	d_add(dentry,inode);
+	_leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%lu }",
+	       cookie.fid.vnode,
+	       cookie.fid.unique,
+	       dentry->d_inode->i_ino,
+	       dentry->d_inode->i_version);
+
+	return NULL;
+} /* end afs_dir_lookup() */
+
+/*****************************************************************************/
+/*
+ * check that a dentry lookup hit has found a valid entry
+ * - NOTE! the hit can be a negative hit too, so we can't assume we have an inode
+ * (derived from nfs_lookup_revalidate)
+ */
+static int afs_d_revalidate(struct dentry *dentry, int flags)
+{
+	struct afs_dir_lookup_cookie cookie;
+	struct dentry *parent;
+	struct inode *inode, *dir;
+	unsigned fpos;
+	int ret;
+
+	_enter("%s,%x",dentry->d_name.name,flags);
+
+	/* lock down the parent dentry so we can peer at it */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	read_lock(&dparent_lock);
+	parent = dget(dentry->d_parent);
+	read_unlock(&dparent_lock);
+#else
+	lock_kernel();
+	parent = dget(dentry->d_parent);
+	unlock_kernel();
+#endif
+
+	dir = parent->d_inode;
+	inode = dentry->d_inode;
+
+	/* handle a negative inode */
+	if (!inode)
+		goto out_bad;
+
+	/* handle a bad inode */
+	if (is_bad_inode(inode)) {
+		printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
+		       dentry->d_parent->d_name.name,dentry->d_name.name);
+		goto out_bad;
+	}
+
+	/* force a full look up if the parent directory changed since last the server was consulted
+	 * - otherwise this inode must still exist, even if the inode details themselves have
+	 *   changed
+	 */
+	if (AFS_FS_I(dir)->flags & AFS_VNODE_CHANGED)
+		afs_vnode_fetch_status(AFS_FS_I(dir));
+
+	if (AFS_FS_I(dir)->flags & AFS_VNODE_DELETED) {
+		_debug("%s: parent dir deleted",dentry->d_name.name);
+		goto out_bad;
+	}
+
+	if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED) {
+		_debug("%s: file already deleted",dentry->d_name.name);
+		goto out_bad;
+	}
+
+	if ((unsigned)dentry->d_fsdata != (unsigned)AFS_FS_I(dir)->status.version) {
+		_debug("%s: parent changed %u -> %u",
+		       dentry->d_name.name,
+		       (unsigned)dentry->d_fsdata,
+		       (unsigned)AFS_FS_I(dir)->status.version);
+
+		/* search the directory for this vnode */
+		cookie.name	= dentry->d_name.name;
+		cookie.nlen	= dentry->d_name.len;
+		cookie.fid.vid	= AFS_FS_I(inode)->volume->vid;
+		cookie.found	= 0;
+
+		fpos = 0;
+		ret = afs_dir_iterate(dir,&fpos,&cookie,afs_dir_lookup_filldir);
+		if (ret<0) {
+			_debug("failed to iterate dir %s: %d",parent->d_name.name,ret);
+			goto out_bad;
+		}
+
+		if (!cookie.found) {
+			_debug("%s: dirent not found",dentry->d_name.name);
+			goto not_found;
+		}
+
+		/* if the vnode ID has changed, then the dirent points to a different file */
+		if (cookie.fid.vnode!=AFS_FS_I(inode)->fid.vnode) {
+			_debug("%s: dirent changed",dentry->d_name.name);
+			goto not_found;
+		}
+
+		/* if the vnode ID uniqifier has changed, then the file has been deleted */
+		if (cookie.fid.unique!=AFS_FS_I(inode)->fid.unique) {
+			_debug("%s: file deleted (uq %u -> %u I:%lu)",
+			       dentry->d_name.name,
+			       cookie.fid.unique,
+			       AFS_FS_I(inode)->fid.unique,
+			       inode->i_version);
+			spin_lock(&AFS_FS_I(inode)->lock);
+			AFS_FS_I(inode)->flags |= AFS_VNODE_DELETED;
+			spin_unlock(&AFS_FS_I(inode)->lock);
+			invalidate_inode_pages(inode->i_mapping);
+			goto out_bad;
+		}
+
+		dentry->d_fsdata = (void*) (unsigned) AFS_FS_I(dir)->status.version;
+	}
+
+ out_valid:
+	dput(parent);
+	_leave(" = 1 [valid]");
+	return 1;
+
+	/* the dirent, if it exists, now points to a different vnode */
+ not_found:
+	dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+
+ out_bad:
+	if (inode) {
+		/* don't unhash if we have submounts */
+		if (have_submounts(dentry))
+			goto out_valid;
+	}
+
+	shrink_dcache_parent(dentry);
+
+	_debug("dropping dentry %s/%s",dentry->d_parent->d_name.name,dentry->d_name.name);
+	d_drop(dentry);
+
+	dput(parent);
+
+	_leave(" = 0 [bad]");
+	return 0;
+} /* end afs_d_revalidate() */
+
+/*****************************************************************************/
+/*
+ * allow the VFS to enquire as to whether a dentry should be unhashed (mustn't sleep)
+ * - called from dput() when d_count is going to 0.
+ * - return 1 to request dentry be unhashed, 0 otherwise
+ */
+static int afs_d_delete(struct dentry *dentry)
+{
+	_enter("%s",dentry->d_name.name);
+
+	if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+		goto zap;
+
+	if (dentry->d_inode) {
+		if (AFS_FS_I(dentry->d_inode)->flags & AFS_VNODE_DELETED)
+			goto zap;
+	}
+
+	_leave(" = 0 [keep]");
+	return 0;
+
+ zap:
+	_leave(" = 1 [zap]");
+	return 1;
+} /* end afs_d_delete() */
diff -Nru a/fs/afs/errors.h b/fs/afs/errors.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/errors.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,34 @@
+/* errors.h: AFS abort/error codes
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _H_DB712916_5113_11D6_9A6D_0002B3163499
+#define _H_DB712916_5113_11D6_9A6D_0002B3163499
+
+#include "types.h"
+
+/* file server abort codes */
+typedef enum {
+	VSALVAGE	= 101,	/* volume needs salvaging */
+	VNOVNODE	= 102,	/* no such file/dir (vnode) */
+	VNOVOL		= 103,	/* no such volume or volume unavailable */
+	VVOLEXISTS	= 104,	/* volume name already exists */
+	VNOSERVICE	= 105,	/* volume not currently in service */
+	VOFFLINE	= 106,	/* volume is currently offline (more info available [VVL-spec]) */
+	VONLINE		= 107,	/* volume is already online */
+	VDISKFULL	= 108,	/* disk partition is full */
+	VOVERQUOTA	= 109,	/* volume's maximum quota exceeded */
+	VBUSY		= 110,	/* volume is temporarily unavailable */
+	VMOVED		= 111,	/* volume moved to new server - ask this FS where */
+} afs_rxfs_abort_t;
+
+extern int afs_abort_to_error(int abortcode);
+
+#endif /* _H_DB712916_5113_11D6_9A6D_0002B3163499 */
diff -Nru a/fs/afs/file.c b/fs/afs/file.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/file.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,143 @@
+/* file.c: AFS filesystem file handling
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "vnode.h"
+#include <rxrpc/call.h>
+#include "internal.h"
+
+//static int afs_file_open(struct inode *inode, struct file *file);
+//static int afs_file_release(struct inode *inode, struct file *file);
+
+static int afs_file_readpage(struct file *file, struct page *page);
+
+//static ssize_t afs_file_read(struct file *file, char *buf, size_t size, loff_t *off);
+
+static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, loff_t *off);
+
+struct inode_operations afs_file_inode_operations = {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	.getattr	= afs_inode_getattr,
+#else
+	.revalidate	= afs_inode_revalidate,
+#endif
+};
+
+struct file_operations afs_file_file_operations = {
+//	.open		= afs_file_open,
+//	.release	= afs_file_release,
+	.read		= generic_file_read, //afs_file_read,
+	.write		= afs_file_write,
+	.mmap		= generic_file_mmap,
+//	.fsync		= afs_file_fsync,
+};
+
+struct address_space_operations afs_fs_aops = {
+	.readpage	= afs_file_readpage,
+};
+
+/*****************************************************************************/
+/*
+ * AFS file read
+ */
+#if 0
+static ssize_t afs_file_read(struct file *file, char *buf, size_t size, loff_t *off)
+{
+	struct afs_inode_info *ai;
+
+	ai = AFS_FS_I(file->f_dentry->d_inode);
+	if (ai->flags & AFS_INODE_DELETED)
+		return -ESTALE;
+
+	return -EIO;
+} /* end afs_file_read() */
+#endif
+
+/*****************************************************************************/
+/*
+ * AFS file write
+ */
+static ssize_t afs_file_write(struct file *file, const char *buf, size_t size, loff_t *off)
+{
+	afs_vnode_t *vnode;
+
+	vnode = AFS_FS_I(file->f_dentry->d_inode);
+	if (vnode->flags & AFS_VNODE_DELETED)
+		return -ESTALE;
+
+	return -EIO;
+} /* end afs_file_write() */
+
+/*****************************************************************************/
+/*
+ * AFS read page from file (or symlink)
+ */
+static int afs_file_readpage(struct file *file, struct page *page)
+{
+	struct afs_rxfs_fetch_descriptor desc;
+	struct inode *inode;
+	afs_vnode_t *vnode;
+	int ret;
+
+	inode = page->mapping->host;
+
+	_enter("{%lu},{%lu}",inode->i_ino,page->index);
+
+	vnode = AFS_FS_I(inode);
+
+	if (!PageLocked(page))
+		PAGE_BUG(page);
+
+	ret = -ESTALE;
+	if (vnode->flags & AFS_VNODE_DELETED)
+		goto error;
+
+	/* work out how much to get and from where */
+	desc.fid	= vnode->fid;
+	desc.offset	= page->index << PAGE_CACHE_SHIFT;
+	desc.size	= min((size_t)(inode->i_size - desc.offset),(size_t)PAGE_SIZE);
+	desc.buffer	= kmap(page);
+
+	clear_page(desc.buffer);
+
+	/* read the contents of the file from the server into the page */
+	ret = afs_vnode_fetch_data(vnode,&desc);
+	kunmap(page);
+	if (ret<0) {
+		if (ret==-ENOENT) {
+			_debug("got NOENT from server - marking file deleted and stale");
+			vnode->flags |= AFS_VNODE_DELETED;
+			ret = -ESTALE;
+		}
+		goto error;
+	}
+
+	SetPageUptodate(page);
+	unlock_page(page);
+
+	_leave(" = 0");
+	return 0;
+
+ error:
+	SetPageError(page);
+	unlock_page(page);
+
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end afs_file_readpage() */
diff -Nru a/fs/afs/fsclient.c b/fs/afs/fsclient.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/fsclient.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,816 @@
+/* fsclient.c: AFS File Server client stubs
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include "fsclient.h"
+#include "cmservice.h"
+#include "vnode.h"
+#include "server.h"
+#include "errors.h"
+#include "internal.h"
+
+#define FSFETCHSTATUS		132	/* AFS Fetch file status */
+#define FSFETCHDATA		130	/* AFS Fetch file data */
+#define FSGIVEUPCALLBACKS	147	/* AFS Discard server callback promises */
+#define FSGETVOLUMEINFO		148	/* AFS Get root volume information */
+#define FSGETROOTVOLUME		151	/* AFS Get root volume name */
+#define FSLOOKUP		161	/* AFS lookup file in directory */
+
+/*****************************************************************************/
+/*
+ * map afs abort codes to/from Linux error codes
+ * - called with call->lock held
+ */
+static void afs_rxfs_aemap(struct rxrpc_call *call)
+{
+	switch (call->app_err_state) {
+	case RXRPC_ESTATE_LOCAL_ABORT:
+		call->app_abort_code = -call->app_errno;
+		break;
+	case RXRPC_ESTATE_PEER_ABORT:
+		call->app_errno = afs_abort_to_error(call->app_abort_code);
+		break;
+	default:
+		break;
+	}
+} /* end afs_rxfs_aemap() */
+
+/*****************************************************************************/
+/*
+ * get the root volume name from a fileserver
+ * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2
+ */
+#if 0
+int afs_rxfs_get_root_volume(afs_server_t *server, char *buf, size_t *buflen)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_connection *conn;
+	struct rxrpc_call *call;
+	struct iovec piov[2];
+	size_t sent;
+	int ret;
+	u32 param[1];
+
+	kenter("%p,%p,%u",server,buf,*buflen);
+
+	/* get hold of the fileserver connection */
+	ret = afs_server_get_fsconn(server,&conn);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(conn,NULL,NULL,afs_rxfs_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = FSGETROOTVOLUME;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	param[0] = htonl(FSGETROOTVOLUME);
+
+	piov[0].iov_len = sizeof(param);
+	piov[0].iov_base = param;
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the reply to completely arrive */
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (call->app_call_state!=RXRPC_CSTATE_CLNT_RCV_REPLY ||
+		    signal_pending(current))
+			break;
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+
+	ret = -EINTR;
+	if (signal_pending(current))
+		goto abort;
+
+	switch (call->app_call_state) {
+	case RXRPC_CSTATE_ERROR:
+		ret = call->app_errno;
+		kdebug("Got Error: %d",ret);
+		goto out_unwait;
+
+	case RXRPC_CSTATE_CLNT_GOT_REPLY:
+		/* read the reply */
+		kdebug("Got Reply: qty=%d",call->app_ready_qty);
+
+		ret = -EBADMSG;
+		if (call->app_ready_qty <= 4)
+			goto abort;
+
+		ret = rxrpc_call_read_data(call,NULL,call->app_ready_qty,0);
+		if (ret<0)
+			goto abort;
+
+#if 0
+		/* unmarshall the reply */
+		bp = buffer;
+		for (loop=0; loop<65; loop++)
+			entry->name[loop] = ntohl(*bp++);
+		entry->name[64] = 0;
+
+		entry->type = ntohl(*bp++);
+		entry->num_servers = ntohl(*bp++);
+
+		for (loop=0; loop<8; loop++)
+			entry->servers[loop].addr.s_addr = *bp++;
+
+		for (loop=0; loop<8; loop++)
+			entry->servers[loop].partition = ntohl(*bp++);
+
+		for (loop=0; loop<8; loop++)
+			entry->servers[loop].flags = ntohl(*bp++);
+
+		for (loop=0; loop<3; loop++)
+			entry->volume_ids[loop] = ntohl(*bp++);
+
+		entry->clone_id = ntohl(*bp++);
+		entry->flags = ntohl(*bp);
+#endif
+
+		/* success */
+		ret = 0;
+		goto out_unwait;
+
+	default:
+		BUG();
+	}
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	afs_server_release_fsconn(server,conn);
+ out:
+	kleave("");
+	return ret;
+} /* end afs_rxfs_get_root_volume() */
+#endif
+
+/*****************************************************************************/
+/*
+ * get information about a volume
+ */
+#if 0
+int afs_rxfs_get_volume_info(afs_server_t *server,
+			     const char *name,
+			     afs_volume_info_t *vinfo)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_connection *conn;
+	struct rxrpc_call *call;
+	struct iovec piov[3];
+	size_t sent;
+	int ret;
+	u32 param[2], *bp, zero;
+
+	_enter("%p,%s,%p",server,name,vinfo);
+
+	/* get hold of the fileserver connection */
+	ret = afs_server_get_fsconn(server,&conn);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(conn,NULL,NULL,afs_rxfs_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = FSGETVOLUMEINFO;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	piov[1].iov_len = strlen(name);
+	piov[1].iov_base = (char*)name;
+
+	zero = 0;
+	piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
+	piov[2].iov_base = &zero;
+
+	param[0] = htonl(FSGETVOLUMEINFO);
+	param[1] = htonl(piov[1].iov_len);
+
+	piov[0].iov_len = sizeof(param);
+	piov[0].iov_base = param;
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,3,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the reply to completely arrive */
+	bp = rxrpc_call_alloc_scratch(call,64);
+
+	ret = rxrpc_call_read_data(call,bp,64,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+	if (ret<0) {
+		if (ret==-ECONNABORTED) {
+			ret = call->app_errno;
+			goto out_unwait;
+		}
+		goto abort;
+	}
+
+	/* unmarshall the reply */
+	vinfo->vid = ntohl(*bp++);
+	vinfo->type = ntohl(*bp++);
+
+	vinfo->type_vids[0] = ntohl(*bp++);
+	vinfo->type_vids[1] = ntohl(*bp++);
+	vinfo->type_vids[2] = ntohl(*bp++);
+	vinfo->type_vids[3] = ntohl(*bp++);
+	vinfo->type_vids[4] = ntohl(*bp++);
+
+	vinfo->nservers = ntohl(*bp++);
+	vinfo->servers[0].addr.s_addr = *bp++;
+	vinfo->servers[1].addr.s_addr = *bp++;
+	vinfo->servers[2].addr.s_addr = *bp++;
+	vinfo->servers[3].addr.s_addr = *bp++;
+	vinfo->servers[4].addr.s_addr = *bp++;
+	vinfo->servers[5].addr.s_addr = *bp++;
+	vinfo->servers[6].addr.s_addr = *bp++;
+	vinfo->servers[7].addr.s_addr = *bp++;
+
+	ret = -EBADMSG;
+	if (vinfo->nservers>8)
+		goto abort;
+
+	/* success */
+	ret = 0;
+
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	afs_server_release_fsconn(server,conn);
+ out:
+	_leave("");
+	return ret;
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+	goto out_unwait;
+
+} /* end afs_rxfs_get_volume_info() */
+#endif
+
+/*****************************************************************************/
+/*
+ * fetch the status information for a file
+ */
+int afs_rxfs_fetch_file_status(afs_server_t *server,
+			       afs_vnode_t *vnode,
+			       afs_volsync_t *volsync)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct afs_server_callslot callslot;
+	struct rxrpc_call *call;
+	struct iovec piov[1];
+	size_t sent;
+	int ret;
+	u32 *bp;
+
+	_enter("%p,{%u,%u,%u}",server,vnode->fid.vid,vnode->fid.vnode,vnode->fid.unique);
+
+	/* get hold of the fileserver connection */
+	ret = afs_server_request_callslot(server,&callslot);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(callslot.conn,NULL,NULL,afs_rxfs_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = FSFETCHSTATUS;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	bp = rxrpc_call_alloc_scratch(call,16);
+	bp[0] = htonl(FSFETCHSTATUS);
+	bp[1] = htonl(vnode->fid.vid);
+	bp[2] = htonl(vnode->fid.vnode);
+	bp[3] = htonl(vnode->fid.unique);
+
+	piov[0].iov_len = 16;
+	piov[0].iov_base = bp;
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the reply to completely arrive */
+	bp = rxrpc_call_alloc_scratch(call,120);
+
+	ret = rxrpc_call_read_data(call,bp,120,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+	if (ret<0) {
+		if (ret==-ECONNABORTED) {
+			ret = call->app_errno;
+			goto out_unwait;
+		}
+		goto abort;
+	}
+
+	/* unmarshall the reply */
+	vnode->status.if_version	= ntohl(*bp++);
+	vnode->status.type		= ntohl(*bp++);
+	vnode->status.nlink		= ntohl(*bp++);
+	vnode->status.size		= ntohl(*bp++);
+	vnode->status.version		= ntohl(*bp++);
+	vnode->status.author		= ntohl(*bp++);
+	vnode->status.owner		= ntohl(*bp++);
+	vnode->status.caller_access	= ntohl(*bp++);
+	vnode->status.anon_access	= ntohl(*bp++);
+	vnode->status.mode		= ntohl(*bp++);
+	vnode->status.parent.vid	= vnode->fid.vid;
+	vnode->status.parent.vnode	= ntohl(*bp++);
+	vnode->status.parent.unique	= ntohl(*bp++);
+	bp++; /* seg size */
+	vnode->status.mtime_client	= ntohl(*bp++);
+	vnode->status.mtime_server	= ntohl(*bp++);
+	bp++; /* group */
+	bp++; /* sync counter */
+	vnode->status.version		|= ((unsigned long long) ntohl(*bp++)) << 32;
+	bp++; /* spare2 */
+	bp++; /* spare3 */
+	bp++; /* spare4 */
+
+	vnode->cb_version		= ntohl(*bp++);
+	vnode->cb_expiry		= ntohl(*bp++);
+	vnode->cb_type			= ntohl(*bp++);
+
+	if (volsync) {
+		volsync->creation	= ntohl(*bp++);
+		bp++; /* spare2 */
+		bp++; /* spare3 */
+		bp++; /* spare4 */
+		bp++; /* spare5 */
+		bp++; /* spare6 */
+	}
+
+	/* success */
+	ret = 0;
+
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	afs_server_release_callslot(server,&callslot);
+ out:
+	_leave("");
+	return ret;
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+	goto out_unwait;
+} /* end afs_rxfs_fetch_file_status() */
+
+/*****************************************************************************/
+/*
+ * fetch the contents of a file or directory
+ */
+int afs_rxfs_fetch_file_data(afs_server_t *server,
+			     afs_vnode_t *vnode,
+			     struct afs_rxfs_fetch_descriptor *desc,
+			     afs_volsync_t *volsync)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct afs_server_callslot callslot;
+	struct rxrpc_call *call;
+	struct iovec piov[1];
+	size_t sent;
+	int ret;
+	u32 *bp;
+
+	_enter("%p,{fid={%u,%u,%u},sz=%u,of=%lu}",
+	       server,
+	       desc->fid.vid,
+	       desc->fid.vnode,
+	       desc->fid.unique,
+	       desc->size,
+	       desc->offset);
+
+	/* get hold of the fileserver connection */
+	ret = afs_server_request_callslot(server,&callslot);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(callslot.conn,NULL,NULL,afs_rxfs_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = FSFETCHDATA;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	bp = rxrpc_call_alloc_scratch(call,24);
+	bp[0] = htonl(FSFETCHDATA);
+	bp[1] = htonl(desc->fid.vid);
+	bp[2] = htonl(desc->fid.vnode);
+	bp[3] = htonl(desc->fid.unique);
+	bp[4] = htonl(desc->offset);
+	bp[5] = htonl(desc->size);
+
+	piov[0].iov_len = 24;
+	piov[0].iov_base = bp;
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the data count to arrive */
+	ret = rxrpc_call_read_data(call,bp,4,RXRPC_CALL_READ_BLOCK);
+	if (ret<0)
+		goto read_failed;
+
+	desc->actual = ntohl(bp[0]);
+	if (desc->actual!=desc->size) {
+		ret = -EBADMSG;
+		goto abort;
+	}
+
+	/* call the app to read the actual data */
+	rxrpc_call_reset_scratch(call);
+
+	ret = rxrpc_call_read_data(call,desc->buffer,desc->actual,RXRPC_CALL_READ_BLOCK);
+	if (ret<0)
+		goto read_failed;
+
+	/* wait for the rest of the reply to completely arrive */
+	rxrpc_call_reset_scratch(call);
+	bp = rxrpc_call_alloc_scratch(call,120);
+
+	ret = rxrpc_call_read_data(call,bp,120,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+	if (ret<0)
+		goto read_failed;
+
+	/* unmarshall the reply */
+	vnode->status.if_version	= ntohl(*bp++);
+	vnode->status.type		= ntohl(*bp++);
+	vnode->status.nlink		= ntohl(*bp++);
+	vnode->status.size		= ntohl(*bp++);
+	vnode->status.version		= ntohl(*bp++);
+	vnode->status.author		= ntohl(*bp++);
+	vnode->status.owner		= ntohl(*bp++);
+	vnode->status.caller_access	= ntohl(*bp++);
+	vnode->status.anon_access	= ntohl(*bp++);
+	vnode->status.mode		= ntohl(*bp++);
+	vnode->status.parent.vid	= desc->fid.vid;
+	vnode->status.parent.vnode	= ntohl(*bp++);
+	vnode->status.parent.unique	= ntohl(*bp++);
+	bp++; /* seg size */
+	vnode->status.mtime_client	= ntohl(*bp++);
+	vnode->status.mtime_server	= ntohl(*bp++);
+	bp++; /* group */
+	bp++; /* sync counter */
+	vnode->status.version		|= ((unsigned long long) ntohl(*bp++)) << 32;
+	bp++; /* spare2 */
+	bp++; /* spare3 */
+	bp++; /* spare4 */
+
+	vnode->cb_version		= ntohl(*bp++);
+	vnode->cb_expiry		= ntohl(*bp++);
+	vnode->cb_type			= ntohl(*bp++);
+
+	if (volsync) {
+		volsync->creation	= ntohl(*bp++);
+		bp++; /* spare2 */
+		bp++; /* spare3 */
+		bp++; /* spare4 */
+		bp++; /* spare5 */
+		bp++; /* spare6 */
+	}
+
+	/* success */
+	ret = 0;
+
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	afs_server_release_callslot(server,&callslot);
+ out:
+	_leave(" = %d",ret);
+	return ret;
+
+ read_failed:
+	if (ret==-ECONNABORTED) {
+		ret = call->app_errno;
+		goto out_unwait;
+	}
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+	goto out_unwait;
+
+} /* end afs_rxfs_fetch_file_data() */
+
+/*****************************************************************************/
+/*
+ * ask the AFS fileserver to discard a callback request on a file
+ */
+int afs_rxfs_give_up_callback(afs_server_t *server, afs_vnode_t *vnode)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct afs_server_callslot callslot;
+	struct rxrpc_call *call;
+	struct iovec piov[1];
+	size_t sent;
+	int ret;
+	u32 *bp;
+
+	_enter("%p,{%u,%u,%u}",server,vnode->fid.vid,vnode->fid.vnode,vnode->fid.unique);
+
+	/* get hold of the fileserver connection */
+	ret = afs_server_request_callslot(server,&callslot);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(callslot.conn,NULL,NULL,afs_rxfs_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = FSGIVEUPCALLBACKS;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	bp = rxrpc_call_alloc_scratch(call,(1+4+4)*4);
+
+	piov[0].iov_len = (1+4+4)*4;
+	piov[0].iov_base = bp;
+
+	*bp++ = htonl(FSGIVEUPCALLBACKS);
+	*bp++ = htonl(1);
+	*bp++ = htonl(vnode->fid.vid);
+	*bp++ = htonl(vnode->fid.vnode);
+	*bp++ = htonl(vnode->fid.unique);
+	*bp++ = htonl(1);
+	*bp++ = htonl(vnode->cb_version);
+	*bp++ = htonl(vnode->cb_expiry);
+	*bp++ = htonl(vnode->cb_type);
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the reply to completely arrive */
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (call->app_call_state!=RXRPC_CSTATE_CLNT_RCV_REPLY ||
+		    signal_pending(current))
+			break;
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+
+	ret = -EINTR;
+	if (signal_pending(current))
+		goto abort;
+
+	switch (call->app_call_state) {
+	case RXRPC_CSTATE_ERROR:
+		ret = call->app_errno;
+		goto out_unwait;
+
+	case RXRPC_CSTATE_CLNT_GOT_REPLY:
+		ret = 0;
+		goto out_unwait;
+
+	default:
+		BUG();
+	}
+
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	afs_server_release_callslot(server,&callslot);
+ out:
+	_leave("");
+	return ret;
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+	goto out_unwait;
+} /* end afs_rxfs_give_up_callback() */
+
+/*****************************************************************************/
+/*
+ * look a filename up in a directory
+ * - this operation doesn't seem to work correctly in OpenAFS server 1.2.2
+ */
+#if 0
+int afs_rxfs_lookup(afs_server_t *server,
+		    afs_vnode_t *dir,
+		    const char *filename,
+		    afs_vnode_t *vnode,
+		    afs_volsync_t *volsync)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_connection *conn;
+	struct rxrpc_call *call;
+	struct iovec piov[3];
+	size_t sent;
+	int ret;
+	u32 *bp, zero;
+
+	kenter("%p,{%u,%u,%u},%s",server,fid->vid,fid->vnode,fid->unique,filename);
+
+	/* get hold of the fileserver connection */
+	ret = afs_server_get_fsconn(server,&conn);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(conn,NULL,NULL,afs_rxfs_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = FSLOOKUP;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	bp = rxrpc_call_alloc_scratch(call,20);
+
+	zero = 0;
+
+	piov[0].iov_len = 20;
+	piov[0].iov_base = bp;
+	piov[1].iov_len = strlen(filename);
+	piov[1].iov_base = (char*) filename;
+	piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
+	piov[2].iov_base = &zero;
+
+	*bp++ = htonl(FSLOOKUP);
+	*bp++ = htonl(dirfid->vid);
+	*bp++ = htonl(dirfid->vnode);
+	*bp++ = htonl(dirfid->unique);
+	*bp++ = htonl(piov[1].iov_len);
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,3,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the reply to completely arrive */
+	bp = rxrpc_call_alloc_scratch(call,220);
+
+	ret = rxrpc_call_read_data(call,bp,220,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+	if (ret<0) {
+		if (ret==-ECONNABORTED) {
+			ret = call->app_errno;
+			goto out_unwait;
+		}
+		goto abort;
+	}
+
+	/* unmarshall the reply */
+	fid->vid		= ntohl(*bp++);
+	fid->vnode		= ntohl(*bp++);
+	fid->unique		= ntohl(*bp++);
+
+	vnode->status.if_version	= ntohl(*bp++);
+	vnode->status.type		= ntohl(*bp++);
+	vnode->status.nlink		= ntohl(*bp++);
+	vnode->status.size		= ntohl(*bp++);
+	vnode->status.version		= ntohl(*bp++);
+	vnode->status.author		= ntohl(*bp++);
+	vnode->status.owner		= ntohl(*bp++);
+	vnode->status.caller_access	= ntohl(*bp++);
+	vnode->status.anon_access	= ntohl(*bp++);
+	vnode->status.mode		= ntohl(*bp++);
+	vnode->status.parent.vid	= dirfid->vid;
+	vnode->status.parent.vnode	= ntohl(*bp++);
+	vnode->status.parent.unique	= ntohl(*bp++);
+	bp++; /* seg size */
+	vnode->status.mtime_client	= ntohl(*bp++);
+	vnode->status.mtime_server	= ntohl(*bp++);
+	bp++; /* group */
+	bp++; /* sync counter */
+	vnode->status.version		|= ((unsigned long long) ntohl(*bp++)) << 32;
+	bp++; /* spare2 */
+	bp++; /* spare3 */
+	bp++; /* spare4 */
+
+	dir->status.if_version		= ntohl(*bp++);
+	dir->status.type			= ntohl(*bp++);
+	dir->status.nlink		= ntohl(*bp++);
+	dir->status.size			= ntohl(*bp++);
+	dir->status.version		= ntohl(*bp++);
+	dir->status.author		= ntohl(*bp++);
+	dir->status.owner		= ntohl(*bp++);
+	dir->status.caller_access	= ntohl(*bp++);
+	dir->status.anon_access		= ntohl(*bp++);
+	dir->status.mode			= ntohl(*bp++);
+	dir->status.parent.vid		= dirfid->vid;
+	dir->status.parent.vnode		= ntohl(*bp++);
+	dir->status.parent.unique	= ntohl(*bp++);
+	bp++; /* seg size */
+	dir->status.mtime_client		= ntohl(*bp++);
+	dir->status.mtime_server		= ntohl(*bp++);
+	bp++; /* group */
+	bp++; /* sync counter */
+	dir->status.version		|= ((unsigned long long) ntohl(*bp++)) << 32;
+	bp++; /* spare2 */
+	bp++; /* spare3 */
+	bp++; /* spare4 */
+
+	callback->fid		= *fid;
+	callback->version	= ntohl(*bp++);
+	callback->expiry	= ntohl(*bp++);
+	callback->type		= ntohl(*bp++);
+
+	if (volsync) {
+		volsync->creation	= ntohl(*bp++);
+		bp++; /* spare2 */
+		bp++; /* spare3 */
+		bp++; /* spare4 */
+		bp++; /* spare5 */
+		bp++; /* spare6 */
+	}
+
+	/* success */
+	ret = 0;
+
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	afs_server_release_fsconn(server,conn);
+ out:
+	kleave("");
+	return ret;
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+	goto out_unwait;
+} /* end afs_rxfs_lookup() */
+#endif
diff -Nru a/fs/afs/fsclient.h b/fs/afs/fsclient.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/fsclient.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,53 @@
+/* fsclient.h: AFS File Server client stub declarations
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_FSCLIENT_H
+#define _LINUX_AFS_FSCLIENT_H
+
+#include "server.h"
+
+extern int afs_rxfs_get_volume_info(afs_server_t *server,
+				    const char *name,
+				    afs_volume_info_t *vinfo);
+
+extern int afs_rxfs_fetch_file_status(afs_server_t *server,
+				      afs_vnode_t *vnode,
+				      afs_volsync_t *volsync);
+
+struct afs_rxfs_fetch_descriptor {
+	afs_fid_t	fid;		/* file ID to fetch */
+	size_t		size;		/* total number of bytes to fetch */
+	off_t		offset;		/* offset in file to start from */
+	void		*buffer;	/* read buffer */
+	size_t		actual;		/* actual size sent back by server */
+};
+
+extern int afs_rxfs_fetch_file_data(afs_server_t *server,
+				    afs_vnode_t *vnode,
+				    struct afs_rxfs_fetch_descriptor *desc,
+				    afs_volsync_t *volsync);
+
+extern int afs_rxfs_give_up_callback(afs_server_t *server, afs_vnode_t *vnode);
+
+/* this doesn't appear to work in OpenAFS server */
+extern int afs_rxfs_lookup(afs_server_t *server,
+			   afs_vnode_t *dir,
+			   const char *filename,
+			   afs_vnode_t *vnode,
+			   afs_volsync_t *volsync);
+
+/* this is apparently mis-implemented in OpenAFS server */
+extern int afs_rxfs_get_root_volume(afs_server_t *server,
+				    char *buf,
+				    size_t *buflen);
+
+
+#endif /* _LINUX_AFS_FSCLIENT_H */
diff -Nru a/fs/afs/inode.c b/fs/afs/inode.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/inode.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the
+ * GNU General Public License.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
+ *          David Howells <dhowells@redhat.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "vnode.h"
+#include "super.h"
+#include "internal.h"
+
+struct afs_iget_data {
+	afs_fid_t		fid;
+	afs_volume_t		*volume;	/* volume on which resides */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	afs_vnode_t		*new_vnode;	/* new vnode record */
+#endif
+};
+
+/*****************************************************************************/
+/*
+ * map the AFS file status to the inode member variables
+ */
+static int afs_inode_map_status(afs_vnode_t *vnode)
+{
+	struct inode *inode = AFS_VNODE_TO_I(vnode);
+
+	_debug("FS: ft=%d lk=%d sz=%u ver=%Lu mod=%hu",
+	       vnode->status.type,
+	       vnode->status.nlink,
+	       vnode->status.size,
+	       vnode->status.version,
+	       vnode->status.mode);
+
+	switch (vnode->status.type) {
+	case AFS_FTYPE_FILE:
+		inode->i_mode	= S_IFREG | vnode->status.mode;
+		inode->i_op	= &afs_file_inode_operations;
+		inode->i_fop	= &afs_file_file_operations;
+		break;
+	case AFS_FTYPE_DIR:
+		inode->i_mode	= S_IFDIR | vnode->status.mode;
+		inode->i_op	= &afs_dir_inode_operations;
+		inode->i_fop	= &afs_dir_file_operations;
+		break;
+	case AFS_FTYPE_SYMLINK:
+		inode->i_mode	= S_IFLNK | vnode->status.mode;
+		inode->i_op	= &page_symlink_inode_operations;
+		break;
+	default:
+		printk("kAFS: AFS vnode with undefined type\n");
+		return -EBADMSG;
+	}
+
+	inode->i_nlink		= vnode->status.nlink;
+	inode->i_uid		= vnode->status.owner;
+	inode->i_gid		= 0;
+	inode->i_rdev		= NODEV;
+	inode->i_size		= vnode->status.size;
+	inode->i_atime		= inode->i_mtime = inode->i_ctime = vnode->status.mtime_server;
+	inode->i_blksize	= PAGE_CACHE_SIZE;
+	inode->i_blocks		= 0;
+	inode->i_version	= vnode->fid.unique;
+	inode->i_mapping->a_ops	= &afs_fs_aops;
+
+	/* check to see whether a symbolic link is really a mountpoint */
+	if (vnode->status.type==AFS_FTYPE_SYMLINK) {
+		afs_mntpt_check_symlink(vnode);
+
+		if (vnode->flags & AFS_VNODE_MOUNTPOINT) {
+			inode->i_mode	= S_IFDIR | vnode->status.mode;
+			inode->i_op	= &afs_mntpt_inode_operations;
+			inode->i_fop	= &afs_mntpt_file_operations;
+		}
+	}
+
+	return 0;
+} /* end afs_inode_map_status() */
+
+/*****************************************************************************/
+/*
+ * attempt to fetch the status of an inode, coelescing multiple simultaneous fetches
+ */
+int afs_inode_fetch_status(struct inode *inode)
+{
+	afs_vnode_t *vnode;
+	int ret;
+
+	vnode = AFS_FS_I(inode);
+
+	ret = afs_vnode_fetch_status(vnode);
+
+	if (ret==0)
+		ret = afs_inode_map_status(vnode);
+
+	return ret;
+
+} /* end afs_inode_fetch_status() */
+
+/*****************************************************************************/
+/*
+ * iget5() comparator
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static int afs_iget5_test(struct inode *inode, void *opaque)
+{
+	struct afs_iget_data *data = opaque;
+
+	/* only match inodes with the same version number */
+	return inode->i_ino==data->fid.vnode && inode->i_version==data->fid.unique;
+} /* end afs_iget5_test() */
+#endif
+
+/*****************************************************************************/
+/*
+ * iget5() inode initialiser
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static int afs_iget5_set(struct inode *inode, void *opaque)
+{
+	struct afs_iget_data *data = opaque;
+	afs_vnode_t *vnode = AFS_FS_I(inode);
+
+	inode->i_ino = data->fid.vnode;
+	inode->i_version = data->fid.unique;
+	vnode->fid = data->fid;
+	vnode->volume = data->volume;
+
+	return 0;
+} /* end afs_iget5_set() */
+#endif
+
+/*****************************************************************************/
+/*
+ * iget4() comparator
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int afs_iget4_test(struct inode *inode, ino_t ino, void *opaque)
+{
+	struct afs_iget_data *data = opaque;
+
+	/* only match inodes with the same version number */
+	return inode->i_ino==data->fid.vnode && inode->i_version==data->fid.unique;
+} /* end afs_iget4_test() */
+#endif
+
+/*****************************************************************************/
+/*
+ * read an inode (2.4 only)
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+void afs_read_inode2(struct inode *inode, void *opaque)
+{
+	struct afs_iget_data *data = opaque;
+	afs_vnode_t *vnode;
+	int ret;
+
+	_enter(",{{%u,%u,%u},%p}",data->fid.vid,data->fid.vnode,data->fid.unique,data->volume);
+
+	if (inode->u.generic_ip) BUG();
+
+	/* attach a pre-allocated vnode record */
+	inode->u.generic_ip = vnode = data->new_vnode;
+	data->new_vnode = NULL;
+
+	memset(vnode,0,sizeof(*vnode));
+	vnode->inode = inode;
+	init_waitqueue_head(&vnode->update_waitq);
+	spin_lock_init(&vnode->lock);
+	INIT_LIST_HEAD(&vnode->cb_link);
+	INIT_LIST_HEAD(&vnode->cb_hash_link);
+	afs_timer_init(&vnode->cb_timeout,&afs_vnode_cb_timed_out_ops);
+	vnode->flags |= AFS_VNODE_CHANGED;
+	vnode->volume = data->volume;
+	vnode->fid = data->fid;
+
+	/* ask the server for a status check */
+	ret = afs_vnode_fetch_status(vnode);
+	if (ret<0) {
+		make_bad_inode(inode);
+		_leave(" [bad inode]");
+		return;
+	}
+
+	ret = afs_inode_map_status(vnode);
+	if (ret<0) {
+		make_bad_inode(inode);
+		_leave(" [bad inode]");
+		return;
+	}
+
+	_leave("");
+	return;
+} /* end afs_read_inode2() */
+#endif
+
+/*****************************************************************************/
+/*
+ * inode retrieval
+ */
+inline int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inode)
+{
+	struct afs_iget_data data = { fid: *fid };
+	struct afs_super_info *as;
+	struct inode *inode;
+	afs_vnode_t *vnode;
+	int ret;
+
+	_enter(",{%u,%u,%u},,",fid->vid,fid->vnode,fid->unique);
+
+	as = sb->s_fs_info;
+	data.volume = as->volume;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	inode = iget5_locked(sb,fid->vnode,afs_iget5_test,afs_iget5_set,&data);
+	if (!inode) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	vnode = AFS_FS_I(inode);
+
+	/* deal with an existing inode */
+	if (!(inode->i_state & I_NEW)) {
+		ret = afs_vnode_fetch_status(vnode);
+		if (ret==0)
+			*_inode = inode;
+		else
+			iput(inode);
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	/* okay... it's a new inode */
+	vnode->flags |= AFS_VNODE_CHANGED;
+	ret = afs_inode_fetch_status(inode);
+	if (ret<0)
+		goto bad_inode;
+
+#if 0
+	/* find a cache entry for it */
+	ret = afs_cache_lookup_vnode(as->volume,vnode);
+	if (ret<0)
+		goto bad_inode;
+#endif
+
+	/* success */
+	unlock_new_inode(inode);
+
+	*_inode = inode;
+	_leave(" = 0 [CB { v=%u x=%lu t=%u nix=%u }]",
+	       vnode->cb_version,
+	       vnode->cb_timeout.timo_jif,
+	       vnode->cb_type,
+	       vnode->nix
+	       );
+	return 0;
+
+	/* failure */
+ bad_inode:
+	make_bad_inode(inode);
+	unlock_new_inode(inode);
+	iput(inode);
+
+	_leave(" = %d [bad]",ret);
+	return ret;
+
+#else
+
+	/* pre-allocate a vnode record so that afs_read_inode2() doesn't have to return an inode
+	 * without one attached
+	 */
+	data.new_vnode = kmalloc(sizeof(afs_vnode_t),GFP_KERNEL);
+	if (!data.new_vnode) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	inode = iget4(sb,fid->vnode,afs_iget4_test,&data);
+	if (data.new_vnode) kfree(data.new_vnode); 
+	if (!inode) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	vnode = AFS_FS_I(inode);
+	*_inode = inode;
+	_leave(" = 0 [CB { v=%u x=%lu t=%u nix=%u }]",
+	       vnode->cb_version,
+	       vnode->cb_timeout.timo_jif,
+	       vnode->cb_type,
+	       vnode->nix
+	       );
+	return 0;
+#endif
+} /* end afs_iget() */
+
+/*****************************************************************************/
+/*
+ * read the attributes of an inode
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+	struct inode *inode;
+	afs_vnode_t *vnode;
+	int ret;
+
+	inode = dentry->d_inode;
+
+	_enter("{ ino=%lu v=%lu }",inode->i_ino,inode->i_version);
+
+	vnode = AFS_FS_I(inode);
+
+	ret = afs_inode_fetch_status(inode);
+	if (ret==-ENOENT) {
+		_leave(" = %d [%d %p]",ret,atomic_read(&dentry->d_count),dentry->d_inode);
+		return ret;
+	}
+	else if (ret<0) {
+		make_bad_inode(inode);
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	/* transfer attributes from the inode structure to the stat structure */
+	generic_fillattr(inode,stat);
+
+	_leave(" = 0 CB { v=%u x=%u t=%u }",
+	       vnode->cb_version,
+	       vnode->cb_expiry,
+	       vnode->cb_type);
+
+	return 0;
+} /* end afs_inode_getattr() */
+#endif
+
+/*****************************************************************************/
+/*
+ * revalidate the inode
+ */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+int afs_inode_revalidate(struct dentry *dentry)
+{
+	struct inode *inode;
+	afs_vnode_t *vnode;
+	int ret;
+
+	inode = dentry->d_inode;
+
+	_enter("{ ino=%lu v=%lu }",inode->i_ino,inode->i_version);
+
+	vnode = AFS_FS_I(inode);
+
+	ret = afs_inode_fetch_status(inode);
+	if (ret==-ENOENT) {
+		_leave(" = %d [%d %p]",ret,atomic_read(&dentry->d_count),dentry->d_inode);
+		return ret;
+	}
+	else if (ret<0) {
+		make_bad_inode(inode);
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	_leave(" = 0 CB { v=%u x=%u t=%u }",
+	       vnode->cb_version,
+	       vnode->cb_expiry,
+	       vnode->cb_type);
+
+	return 0;
+} /* end afs_inode_revalidate() */
+#endif
+
+/*****************************************************************************/
+/*
+ * clear an AFS inode
+ */
+void afs_clear_inode(struct inode *inode)
+{
+	afs_vnode_t *vnode;
+
+	vnode = AFS_FS_I(inode);
+
+	_enter("ino=%lu { vn=%08x v=%u x=%u t=%u }",
+	       inode->i_ino,
+	       vnode->fid.vnode,
+	       vnode->cb_version,
+	       vnode->cb_expiry,
+	       vnode->cb_type
+	       );
+
+	if (inode->i_ino!=vnode->fid.vnode) BUG();
+
+	afs_vnode_give_up_callback(vnode);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+	if (inode->u.generic_ip) kfree(inode->u.generic_ip);
+#endif
+
+	_leave("");
+} /* end afs_clear_inode() */
diff -Nru a/fs/afs/internal.h b/fs/afs/internal.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/internal.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,127 @@
+/* internal.h: internal AFS stuff
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef AFS_INTERNAL_H
+#define AFS_INTERNAL_H
+
+#include <linux/version.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+
+/*
+ * debug tracing
+ */
+#define kenter(FMT,...)	printk("==> %s("FMT")\n",__FUNCTION__,##__VA_ARGS__)
+#define kleave(FMT,...)	printk("<== %s()"FMT"\n",__FUNCTION__,##__VA_ARGS__)
+#define kdebug(FMT,...)	printk(FMT"\n",##__VA_ARGS__)
+#define kproto(FMT,...)	printk("### "FMT"\n",##__VA_ARGS__)
+#define knet(FMT,...)	printk(FMT"\n",##__VA_ARGS__)
+
+#if 0
+#define _enter(FMT,...)	kenter(FMT,##__VA_ARGS__)
+#define _leave(FMT,...)	kleave(FMT,##__VA_ARGS__)
+#define _debug(FMT,...)	kdebug(FMT,##__VA_ARGS__)
+#define _proto(FMT,...)	kproto(FMT,##__VA_ARGS__)
+#define _net(FMT,...)	knet(FMT,##__VA_ARGS__)
+#else
+#define _enter(FMT,...)	do { } while(0)
+#define _leave(FMT,...)	do { } while(0)
+#define _debug(FMT,...)	do { } while(0)
+#define _proto(FMT,...)	do { } while(0)
+#define _net(FMT,...)	do { } while(0)
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+#define wait_on_page_locked wait_on_page
+#define PageUptodate Page_Uptodate
+
+static inline struct proc_dir_entry *PDE(const struct inode *inode)
+{
+	return (struct proc_dir_entry *)inode->u.generic_ip;
+}
+#endif
+
+static inline void afs_discard_my_signals(void)
+{
+	while (signal_pending(current)) {
+		siginfo_t sinfo;
+
+		spin_lock_irq(&current->sig->siglock);
+		dequeue_signal(&current->blocked,&sinfo);
+		spin_unlock_irq(&current->sig->siglock);
+	}
+}
+
+/*
+ * cell.c
+ */
+extern struct rw_semaphore afs_proc_cells_sem;
+extern struct list_head afs_proc_cells;
+
+/*
+ * dir.c
+ */
+extern struct inode_operations afs_dir_inode_operations;
+extern struct file_operations afs_dir_file_operations;
+
+/*
+ * file.c
+ */
+extern struct address_space_operations afs_fs_aops;
+extern struct inode_operations afs_file_inode_operations;
+extern struct file_operations afs_file_file_operations;
+
+/*
+ * inode.c
+ */
+extern int afs_iget(struct super_block *sb, afs_fid_t *fid, struct inode **_inode);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+extern int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+#else
+extern void afs_read_inode2(struct inode *inode, void *opaque);
+extern int afs_inode_revalidate(struct dentry *dentry);
+#endif
+extern void afs_clear_inode(struct inode *inode);
+
+/*
+ * mntpt.c
+ */
+extern struct inode_operations afs_mntpt_inode_operations;
+extern struct file_operations afs_mntpt_file_operations;
+
+extern int afs_mntpt_check_symlink(afs_vnode_t *vnode);
+
+/*
+ * super.c
+ */
+extern int afs_fs_init(void);
+extern void afs_fs_exit(void);
+
+#define AFS_CB_HASH_COUNT (PAGE_SIZE/sizeof(struct list_head))
+
+extern struct list_head afs_cb_hash_tbl[];
+extern spinlock_t afs_cb_hash_lock;
+
+#define afs_cb_hash(SRV,FID) \
+	afs_cb_hash_tbl[((unsigned)(SRV) + (FID)->vid + (FID)->vnode + (FID)->unique) % \
+			AFS_CB_HASH_COUNT]
+
+/*
+ * proc.c
+ */
+extern int afs_proc_init(void);
+extern void afs_proc_cleanup(void);
+extern int afs_proc_cell_setup(afs_cell_t *cell);
+extern void afs_proc_cell_remove(afs_cell_t *cell);
+
+#endif /* AFS_INTERNAL_H */
diff -Nru a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/kafsasyncd.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,260 @@
+/* kafsasyncd.c: AFS asynchronous operation daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *
+ * The AFS async daemon is used to the following:
+ * - probe "dead" servers to see whether they've come back to life yet.
+ * - probe "live" servers that we haven't talked to for a while to see if they are better
+ *   candidates for serving than what we're currently using
+ * - poll volume location servers to keep up to date volume location lists
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include "cell.h"
+#include "server.h"
+#include "volume.h"
+#include "kafsasyncd.h"
+#include "kafstimod.h"
+#include <rxrpc/call.h>
+#include <asm/errno.h>
+#include "internal.h"
+
+static DECLARE_COMPLETION(kafsasyncd_alive);
+static DECLARE_COMPLETION(kafsasyncd_dead);
+static DECLARE_WAIT_QUEUE_HEAD(kafsasyncd_sleepq);
+static struct task_struct *kafsasyncd_task;
+static int kafsasyncd_die;
+
+static int kafsasyncd(void *arg);
+
+static LIST_HEAD(kafsasyncd_async_attnq);
+static LIST_HEAD(kafsasyncd_async_busyq);
+static spinlock_t kafsasyncd_async_lock = SPIN_LOCK_UNLOCKED;
+
+static void kafsasyncd_null_call_attn_func(struct rxrpc_call *call)
+{
+}
+
+static void kafsasyncd_null_call_error_func(struct rxrpc_call *call)
+{
+}
+
+/*****************************************************************************/
+/*
+ * start the async daemon
+ */
+int afs_kafsasyncd_start(void)
+{
+	int ret;
+
+	ret = kernel_thread(kafsasyncd,NULL,0);
+	if (ret<0)
+		return ret;
+
+	wait_for_completion(&kafsasyncd_alive);
+
+	return ret;
+} /* end afs_kafsasyncd_start() */
+
+/*****************************************************************************/
+/*
+ * stop the async daemon
+ */
+void afs_kafsasyncd_stop(void)
+{
+	/* get rid of my daemon */
+	kafsasyncd_die = 1;
+	wake_up(&kafsasyncd_sleepq);
+	wait_for_completion(&kafsasyncd_dead);
+
+} /* end afs_kafsasyncd_stop() */
+
+/*****************************************************************************/
+/*
+ * probing daemon
+ */
+static int kafsasyncd(void *arg)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct list_head *_p;
+	int die;
+
+	kafsasyncd_task = current;
+
+	printk("kAFS: Started kafsasyncd %d\n",current->pid);
+	strcpy(current->comm,"kafsasyncd");
+
+	daemonize();
+
+	complete(&kafsasyncd_alive);
+
+	/* only certain signals are of interest */
+	spin_lock_irq(&current->sig->siglock);
+	siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+	recalc_sigpending();
+#else
+	recalc_sigpending(current);
+#endif
+	spin_unlock_irq(&current->sig->siglock);
+
+	/* loop around looking for things to attend to */
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&kafsasyncd_sleepq,&myself);
+
+		for (;;) {
+			if (!list_empty(&kafsasyncd_async_attnq) ||
+			    signal_pending(current) ||
+			    kafsasyncd_die)
+				break;
+
+			schedule();
+			set_current_state(TASK_INTERRUPTIBLE);
+		}
+
+		remove_wait_queue(&kafsasyncd_sleepq,&myself);
+		set_current_state(TASK_RUNNING);
+
+		/* discard pending signals */
+		afs_discard_my_signals();
+
+		die = kafsasyncd_die;
+
+		/* deal with the next asynchronous operation requiring attention */
+		if (!list_empty(&kafsasyncd_async_attnq)) {
+			struct afs_async_op *op;
+
+			_debug("@@@ Begin Asynchronous Operation");
+
+			op = NULL;
+			spin_lock(&kafsasyncd_async_lock);
+
+			if (!list_empty(&kafsasyncd_async_attnq)) {
+				op = list_entry(kafsasyncd_async_attnq.next,afs_async_op_t,link);
+				list_del(&op->link);
+				list_add_tail(&op->link,&kafsasyncd_async_busyq);
+			}
+
+			spin_unlock(&kafsasyncd_async_lock);
+
+			_debug("@@@ Operation %p {%p}\n",op,op?op->ops:NULL);
+
+			if (op)
+				op->ops->attend(op);
+
+			_debug("@@@ End Asynchronous Operation");
+		}
+
+	} while(!die);
+
+	/* need to kill all outstanding asynchronous operations before exiting */
+	kafsasyncd_task = NULL;
+	spin_lock(&kafsasyncd_async_lock);
+
+	/* fold the busy and attention queues together */
+	list_splice(&kafsasyncd_async_busyq,&kafsasyncd_async_attnq);
+	list_del_init(&kafsasyncd_async_busyq);
+
+	/* dequeue kafsasyncd from all their wait queues */
+	list_for_each(_p,&kafsasyncd_async_attnq) {
+		afs_async_op_t *op = list_entry(_p,afs_async_op_t,link);
+
+		op->call->app_attn_func = kafsasyncd_null_call_attn_func;
+		op->call->app_error_func = kafsasyncd_null_call_error_func;
+		remove_wait_queue(&op->call->waitq,&op->waiter);
+	}
+
+	spin_unlock(&kafsasyncd_async_lock);
+
+	/* abort all the operations */
+	while (!list_empty(&kafsasyncd_async_attnq)) {
+		afs_async_op_t *op = list_entry(_p,afs_async_op_t,link);
+		list_del_init(&op->link);
+
+		rxrpc_call_abort(op->call,-EIO);
+		rxrpc_put_call(op->call);
+		op->call = NULL;
+
+		op->ops->discard(op);
+	}
+
+	/* and that's all */
+	_leave("");
+	complete_and_exit(&kafsasyncd_dead,0);
+
+} /* end kafsasyncd() */
+
+/*****************************************************************************/
+/*
+ * begin an operation
+ * - place operation on busy queue
+ */
+void afs_kafsasyncd_begin_op(afs_async_op_t *op)
+{
+	_enter("");
+
+	spin_lock(&kafsasyncd_async_lock);
+
+	init_waitqueue_entry(&op->waiter,kafsasyncd_task);
+
+	list_del(&op->link);
+	list_add_tail(&op->link,&kafsasyncd_async_busyq);
+
+	spin_unlock(&kafsasyncd_async_lock);
+
+	_leave("");
+} /* end afs_kafsasyncd_begin_op() */
+
+/*****************************************************************************/
+/*
+ * request attention for an operation
+ * - move to attention queue
+ */
+void afs_kafsasyncd_attend_op(afs_async_op_t *op)
+{
+	_enter("");
+
+	spin_lock(&kafsasyncd_async_lock);
+
+	list_del(&op->link);
+	list_add_tail(&op->link,&kafsasyncd_async_attnq);
+
+	spin_unlock(&kafsasyncd_async_lock);
+
+	wake_up(&kafsasyncd_sleepq);
+
+	_leave("");
+} /* end afs_kafsasyncd_attend_op() */
+
+/*****************************************************************************/
+/*
+ * terminate an operation
+ * - remove from either queue
+ */
+void afs_kafsasyncd_terminate_op(afs_async_op_t *op)
+{
+	_enter("");
+
+	spin_lock(&kafsasyncd_async_lock);
+
+	list_del_init(&op->link);
+
+	spin_unlock(&kafsasyncd_async_lock);
+
+	wake_up(&kafsasyncd_sleepq);
+
+	_leave("");
+} /* end afs_kafsasyncd_terminate_op() */
diff -Nru a/fs/afs/kafsasyncd.h b/fs/afs/kafsasyncd.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/kafsasyncd.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,49 @@
+/* kafsasyncd.h: AFS asynchronous operation daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_KAFSASYNCD_H
+#define _LINUX_AFS_KAFSASYNCD_H
+
+#include "types.h"
+
+struct afs_async_op_ops {
+	void (*attend)(afs_async_op_t *op);
+	void (*discard)(afs_async_op_t *op);
+};
+
+/*****************************************************************************/
+/*
+ * asynchronous operation record
+ */
+struct afs_async_op
+{
+	struct list_head		link;
+	afs_server_t			*server;	/* server being contacted */
+	struct rxrpc_call		*call;		/* RxRPC call performing op */
+	wait_queue_t			waiter;		/* wait queue for kafsasyncd */
+	const struct afs_async_op_ops	*ops;		/* operations */
+};
+
+static inline void afs_async_op_init(afs_async_op_t *op, const struct afs_async_op_ops *ops)
+{
+	INIT_LIST_HEAD(&op->link);
+	op->call = NULL;
+	op->ops = ops;
+}
+
+extern int afs_kafsasyncd_start(void);
+extern void afs_kafsasyncd_stop(void);
+
+extern void afs_kafsasyncd_begin_op(afs_async_op_t *op);
+extern void afs_kafsasyncd_attend_op(afs_async_op_t *op);
+extern void afs_kafsasyncd_terminate_op(afs_async_op_t *op);
+
+#endif /* _LINUX_AFS_KAFSASYNCD_H */
diff -Nru a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/kafstimod.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,211 @@
+/* kafstimod.c: AFS timeout daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include "cell.h"
+#include "volume.h"
+#include "kafstimod.h"
+#include <asm/errno.h>
+#include "internal.h"
+
+static DECLARE_COMPLETION(kafstimod_alive);
+static DECLARE_COMPLETION(kafstimod_dead);
+static DECLARE_WAIT_QUEUE_HEAD(kafstimod_sleepq);
+static int kafstimod_die;
+
+static LIST_HEAD(kafstimod_list);
+static spinlock_t kafstimod_lock = SPIN_LOCK_UNLOCKED;
+
+static int kafstimod(void *arg);
+
+/*****************************************************************************/
+/*
+ * start the timeout daemon
+ */
+int afs_kafstimod_start(void)
+{
+	int ret;
+
+	ret = kernel_thread(kafstimod,NULL,0);
+	if (ret<0)
+		return ret;
+
+	wait_for_completion(&kafstimod_alive);
+
+	return ret;
+} /* end afs_kafstimod_start() */
+
+/*****************************************************************************/
+/*
+ * stop the timeout daemon
+ */
+void afs_kafstimod_stop(void)
+{
+	/* get rid of my daemon */
+	kafstimod_die = 1;
+	wake_up(&kafstimod_sleepq);
+	wait_for_completion(&kafstimod_dead);
+
+} /* end afs_kafstimod_stop() */
+
+/*****************************************************************************/
+/*
+ * timeout processing daemon
+ */
+static int kafstimod(void *arg)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	afs_timer_t *timer;
+
+	printk("kAFS: Started kafstimod %d\n",current->pid);
+	strcpy(current->comm,"kafstimod");
+
+	daemonize();
+
+	complete(&kafstimod_alive);
+
+	/* only certain signals are of interest */
+	spin_lock_irq(&current->sig->siglock);
+	siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+	recalc_sigpending();
+#else
+	recalc_sigpending(current);
+#endif
+	spin_unlock_irq(&current->sig->siglock);
+
+	/* loop around looking for things to attend to */
+ loop:
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&kafstimod_sleepq,&myself);
+
+	for (;;) {
+		unsigned long jif;
+		signed long timeout;
+
+		/* deal with the server being asked to die */
+		if (kafstimod_die) {
+			remove_wait_queue(&kafstimod_sleepq,&myself);
+			_leave("");
+			complete_and_exit(&kafstimod_dead,0);
+		}
+
+		/* discard pending signals */
+		afs_discard_my_signals();
+
+		/* work out the time to elapse before the next event */
+		spin_lock(&kafstimod_lock);
+		if (list_empty(&kafstimod_list)) {
+			timeout = MAX_SCHEDULE_TIMEOUT;
+		}
+		else {
+			timer = list_entry(kafstimod_list.next,afs_timer_t,link);
+			timeout = timer->timo_jif;
+			jif = jiffies;
+
+			if (time_before_eq(timeout,jif))
+				goto immediate;
+
+			else {
+				timeout = (long)timeout - (long)jiffies;
+			}
+		}
+		spin_unlock(&kafstimod_lock);
+
+		schedule_timeout(timeout);
+
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+
+	/* the thing on the front of the queue needs processing
+	 * - we come here with the lock held and timer pointing to the expired entry
+	 */
+ immediate:
+	remove_wait_queue(&kafstimod_sleepq,&myself);
+	set_current_state(TASK_RUNNING);
+
+	_debug("@@@ Begin Timeout of %p",timer);
+
+	/* dequeue the timer */
+	list_del_init(&timer->link);
+	spin_unlock(&kafstimod_lock);
+
+	/* call the timeout function */
+	timer->ops->timed_out(timer);
+
+	_debug("@@@ End Timeout");
+	goto loop;
+
+} /* end kafstimod() */
+
+/*****************************************************************************/
+/*
+ * (re-)queue a timer
+ */
+void afs_kafstimod_add_timer(afs_timer_t *timer, unsigned long timeout)
+{
+	struct list_head *_p;
+	afs_timer_t *ptimer;
+
+	_enter("%p,%lu",timer,timeout);
+
+	spin_lock(&kafstimod_lock);
+
+	list_del(&timer->link);
+
+	/* the timer was deferred or reset - put it back in the queue at the right place */
+	timer->timo_jif = jiffies + timeout;
+
+	list_for_each(_p,&kafstimod_list) {
+		ptimer = list_entry(_p,afs_timer_t,link);
+		if (time_before(timer->timo_jif,ptimer->timo_jif))
+			break;
+	}
+
+	list_add_tail(&timer->link,_p); /* insert before stopping point */
+
+	spin_unlock(&kafstimod_lock);
+
+	wake_up(&kafstimod_sleepq);
+
+	_leave("");
+} /* end afs_kafstimod_queue_vlocation() */
+
+/*****************************************************************************/
+/*
+ * dequeue a timer
+ * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
+ */
+int afs_kafstimod_del_timer(afs_timer_t *timer)
+{
+	int ret = 0;
+
+	_enter("%p",timer);
+
+	spin_lock(&kafstimod_lock);
+
+	if (list_empty(&timer->link))
+		ret = -ENOENT;
+	else
+		list_del_init(&timer->link);
+
+	spin_unlock(&kafstimod_lock);
+
+	wake_up(&kafstimod_sleepq);
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_kafstimod_del_timer() */
diff -Nru a/fs/afs/kafstimod.h b/fs/afs/kafstimod.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/kafstimod.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,45 @@
+/* kafstimod.h: AFS timeout daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_KAFSTIMOD_H
+#define _LINUX_AFS_KAFSTIMOD_H
+
+#include "types.h"
+
+struct afs_timer_ops {
+	/* called when the front of the timer queue has timed out */
+	void (*timed_out)(struct afs_timer *timer);
+};
+
+/*****************************************************************************/
+/*
+ * AFS timer/timeout record
+ */
+struct afs_timer
+{
+	struct list_head		link;		/* link in timer queue */
+	unsigned long			timo_jif;	/* timeout time */
+	const struct afs_timer_ops	*ops;		/* timeout expiry function */
+};
+
+static inline void afs_timer_init(afs_timer_t *timer, const struct afs_timer_ops *ops)
+{
+	INIT_LIST_HEAD(&timer->link);
+	timer->ops = ops;
+}
+
+extern int afs_kafstimod_start(void);
+extern void afs_kafstimod_stop(void);
+
+extern void afs_kafstimod_add_timer(afs_timer_t *timer, unsigned long timeout);
+extern int afs_kafstimod_del_timer(afs_timer_t *timer);
+
+#endif /* _LINUX_AFS_KAFSTIMOD_H */
diff -Nru a/fs/afs/main.c b/fs/afs/main.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/main.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,193 @@
+/* main.c: AFS client file system
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/call.h>
+#include <rxrpc/peer.h>
+#include "cell.h"
+#include "server.h"
+#include "fsclient.h"
+#include "cmservice.h"
+#include "kafstimod.h"
+#include "kafsasyncd.h"
+#include "internal.h"
+
+struct rxrpc_transport *afs_transport;
+
+static int afs_init(void);
+static void afs_exit(void);
+static int afs_adding_peer(struct rxrpc_peer *peer);
+static void afs_discarding_peer(struct rxrpc_peer *peer);
+
+module_init(afs_init);
+module_exit(afs_exit);
+
+MODULE_DESCRIPTION("AFS Client File System");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+static struct rxrpc_peer_ops afs_peer_ops = {
+	.adding		= afs_adding_peer,
+	.discarding	= afs_discarding_peer,
+};
+
+struct list_head afs_cb_hash_tbl[AFS_CB_HASH_COUNT];
+spinlock_t afs_cb_hash_lock = SPIN_LOCK_UNLOCKED;
+
+/*****************************************************************************/
+/*
+ * initialise the AFS client FS module
+ */
+static int afs_init(void)
+{
+	int loop, ret;
+
+	printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 registering.\n");
+
+	/* initialise the callback hash table */
+	spin_lock_init(&afs_cb_hash_lock);
+	for (loop=AFS_CB_HASH_COUNT-1; loop>=0; loop--)
+		INIT_LIST_HEAD(&afs_cb_hash_tbl[loop]);
+
+	/* register the /proc stuff */
+	ret = afs_proc_init();
+	if (ret<0)
+		return ret;
+
+	/* initialise the cell DB */
+	ret = afs_cell_init();
+	if (ret<0)
+		goto error;
+
+	/* start the timeout daemon */
+	ret = afs_kafstimod_start();
+	if (ret<0)
+		goto error;
+
+	/* start the async operation daemon */
+	ret = afs_kafsasyncd_start();
+	if (ret<0)
+		goto error_kafstimod;
+
+	/* create the RxRPC transport */
+	ret = rxrpc_create_transport(7001,&afs_transport);
+	if (ret<0)
+		goto error_kafsasyncd;
+
+	afs_transport->peer_ops = &afs_peer_ops;
+
+	/* register the filesystems */
+	ret = afs_fs_init();
+	if (ret<0)
+		goto error_transport;
+
+	return ret;
+
+ error_transport:
+	rxrpc_put_transport(afs_transport);
+ error_kafsasyncd:
+	afs_kafsasyncd_stop();
+ error_kafstimod:
+	afs_kafstimod_stop();
+ error:
+	afs_cell_purge();
+	afs_proc_cleanup();
+	printk(KERN_ERR "kAFS: failed to register: %d\n",ret);
+	return ret;
+} /* end afs_init() */
+
+/*****************************************************************************/
+/*
+ * clean up on module removal
+ */
+static void afs_exit(void)
+{
+	printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
+
+	afs_fs_exit();
+	rxrpc_put_transport(afs_transport);
+	afs_kafstimod_stop();
+	afs_kafsasyncd_stop();
+	afs_cell_purge();
+	afs_proc_cleanup();
+
+} /* end afs_exit() */
+
+/*****************************************************************************/
+/*
+ * notification that new peer record is being added
+ * - called from krxsecd
+ * - return an error to induce an abort
+ * - mustn't sleep (caller holds an rwlock)
+ */
+static int afs_adding_peer(struct rxrpc_peer *peer)
+{
+	afs_server_t *server;
+	int ret;
+
+	_debug("kAFS: Adding new peer %08x\n",ntohl(peer->addr.s_addr));
+
+	/* determine which server the peer resides in (if any) */
+	ret = afs_server_find_by_peer(peer,&server);
+	if (ret<0)
+		return ret; /* none that we recognise, so abort */
+
+	_debug("Server %p{u=%d}\n",server,atomic_read(&server->usage));
+
+	_debug("Cell %p{u=%d}\n",server->cell,atomic_read(&server->cell->usage));
+
+	/* cross-point the structs under a global lock */
+	spin_lock(&afs_server_peer_lock);
+	peer->user = server;
+	server->peer = peer;
+	spin_unlock(&afs_server_peer_lock);
+
+	afs_put_server(server);
+
+	return 0;
+} /* end afs_adding_peer() */
+
+/*****************************************************************************/
+/*
+ * notification that a peer record is being discarded
+ * - called from krxiod or krxsecd
+ */
+static void afs_discarding_peer(struct rxrpc_peer *peer)
+{
+	afs_server_t *server;
+
+	_enter("%p",peer);
+
+	_debug("Discarding peer %08x (rtt=%lu.%lumS)\n",
+	       ntohl(peer->addr.s_addr),
+	       peer->rtt/1000,
+	       peer->rtt%1000);
+
+	/* uncross-point the structs under a global lock */
+	spin_lock(&afs_server_peer_lock);
+	server = peer->user;
+	if (server) {
+		peer->user = NULL;
+		server->peer = NULL;
+
+		//_debug("Server %p{u=%d}\n",server,atomic_read(&server->usage));
+		//_debug("Cell %p{u=%d}\n",server->cell,atomic_read(&server->cell->usage));
+	}
+	spin_unlock(&afs_server_peer_lock);
+
+	_leave("");
+
+} /* end afs_discarding_peer() */
diff -Nru a/fs/afs/misc.c b/fs/afs/misc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/misc.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,39 @@
+/* misc.c: miscellaneous bits
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include "errors.h"
+#include "internal.h"
+
+/*****************************************************************************/
+/*
+ * convert an AFS abort code to a Linux error number
+ */
+int afs_abort_to_error(int abortcode)
+{
+	switch (abortcode) {
+	case VSALVAGE:		return -EIO;
+	case VNOVNODE:		return -ENOENT;
+	case VNOVOL:		return -ENXIO;
+	case VVOLEXISTS:	return -EEXIST;
+	case VNOSERVICE:	return -EIO;
+	case VOFFLINE:		return -ENOENT;
+	case VONLINE:		return -EEXIST;
+	case VDISKFULL:		return -ENOSPC;
+	case VOVERQUOTA:	return -EDQUOT;
+	case VBUSY:		return -EBUSY;
+	case VMOVED:		return -ENXIO;
+	default:		return -EIO;
+	}
+
+} /* end afs_abort_to_error() */
diff -Nru a/fs/afs/mntpt.c b/fs/afs/mntpt.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/mntpt.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,112 @@
+/* mntpt.c: mountpoint management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "vnode.h"
+#include "internal.h"
+
+
+static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry);
+static int afs_mntpt_open(struct inode *inode, struct file *file);
+
+struct file_operations afs_mntpt_file_operations = {
+	.open		= afs_mntpt_open,
+};
+
+struct inode_operations afs_mntpt_inode_operations = {
+	.lookup		= afs_mntpt_lookup,
+	.readlink	= page_readlink,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	.getattr	= afs_inode_getattr,
+#else
+	.revalidate	= afs_inode_revalidate,
+#endif
+};
+
+/*****************************************************************************/
+/*
+ * check a symbolic link to see whether it actually encodes a mountpoint
+ * - sets the AFS_VNODE_MOUNTPOINT flag on the vnode appropriately
+ */
+int afs_mntpt_check_symlink(afs_vnode_t *vnode)
+{
+	struct page *page;
+	size_t size;
+	char *buf;
+	int ret;
+
+	_enter("{%u,%u}",vnode->fid.vnode,vnode->fid.unique);
+
+	/* read the contents of the symlink into the pagecache */
+	page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping,0,
+			       (filler_t*)AFS_VNODE_TO_I(vnode)->i_mapping->a_ops->readpage,NULL);
+	if (IS_ERR(page)) {
+		ret = PTR_ERR(page);
+		goto out;
+	}
+
+	ret = -EIO;
+	wait_on_page_locked(page);
+	buf = kmap(page);
+	if (!PageUptodate(page))
+		goto out_free;
+	if (PageError(page))
+		goto out_free;
+
+	/* examine the symlink's contents */
+	size = vnode->status.size;
+	_debug("symlink to %*.*s",size,size,buf);
+
+	if (size>2 &&
+	    (buf[0]=='%' || buf[0]=='#') &&
+	    buf[size-1]=='.'
+	    ) {
+		_debug("symlink is a mountpoint");
+		spin_lock(&vnode->lock);
+		vnode->flags |= AFS_VNODE_MOUNTPOINT;
+		spin_unlock(&vnode->lock);
+	}
+
+	ret = 0;
+
+ out_free:
+	kunmap(page);
+	page_cache_release(page);
+ out:
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end afs_mntpt_check_symlink() */
+
+/*****************************************************************************/
+/*
+ * no valid lookup procedure on this sort of dir
+ */
+static struct dentry *afs_mntpt_lookup(struct inode *dir, struct dentry *dentry)
+{
+	return ERR_PTR(-EREMOTE);
+} /* end afs_mntpt_lookup() */
+
+/*****************************************************************************/
+/*
+ * no valid open procedure on this sort of dir
+ */
+static int afs_mntpt_open(struct inode *inode, struct file *file)
+{
+	return -EREMOTE;
+} /* end afs_mntpt_open() */
diff -Nru a/fs/afs/mount.h b/fs/afs/mount.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/mount.h	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,23 @@
+/* mount.h: mount parameters
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_MOUNT_H
+#define _LINUX_AFS_MOUNT_H
+
+struct afs_mountdata {
+	const char		*volume;	/* name of volume */
+	const char		*cell;		/* name of cell containing volume */
+	const char		*cache;		/* name of cache block device */
+	size_t			nservers;	/* number of server addresses listed */
+	u_int32_t		servers[10];	/* IP addresses of servers in this cell */
+};
+
+#endif /* _LINUX_AFS_MOUNT_H */
diff -Nru a/fs/afs/proc.c b/fs/afs/proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/proc.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,739 @@
+/* proc.c: /proc interface for AFS
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include "cell.h"
+#include "volume.h"
+#include <asm/uaccess.h>
+#include "internal.h"
+
+static struct proc_dir_entry *proc_afs;
+
+
+static int afs_proc_cells_open(struct inode *inode, struct file *file);
+static void *afs_proc_cells_start(struct seq_file *p, loff_t *pos);
+static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos);
+static void afs_proc_cells_stop(struct seq_file *p, void *v);
+static int afs_proc_cells_show(struct seq_file *m, void *v);
+static ssize_t afs_proc_cells_write(struct file *file, const char *buf, size_t size, loff_t *_pos);
+
+static struct seq_operations afs_proc_cells_ops = {
+	.start	= afs_proc_cells_start,
+	.next	= afs_proc_cells_next,
+	.stop	= afs_proc_cells_stop,
+	.show	= afs_proc_cells_show,
+};
+
+static struct file_operations afs_proc_cells_fops = {
+	.open		= afs_proc_cells_open,
+	.read		= seq_read,
+	.write		= afs_proc_cells_write,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
+static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file);
+static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
+static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, loff_t *pos);
+static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v);
+static int afs_proc_cell_volumes_show(struct seq_file *m, void *v);
+
+static struct seq_operations afs_proc_cell_volumes_ops = {
+	.start	= afs_proc_cell_volumes_start,
+	.next	= afs_proc_cell_volumes_next,
+	.stop	= afs_proc_cell_volumes_stop,
+	.show	= afs_proc_cell_volumes_show,
+};
+
+static struct file_operations afs_proc_cell_volumes_fops = {
+	.open		= afs_proc_cell_volumes_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= afs_proc_cell_volumes_release,
+};
+
+static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file);
+static int afs_proc_cell_vlservers_release(struct inode *inode, struct file *file);
+static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
+static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, loff_t *pos);
+static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v);
+static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v);
+
+static struct seq_operations afs_proc_cell_vlservers_ops = {
+	.start	= afs_proc_cell_vlservers_start,
+	.next	= afs_proc_cell_vlservers_next,
+	.stop	= afs_proc_cell_vlservers_stop,
+	.show	= afs_proc_cell_vlservers_show,
+};
+
+static struct file_operations afs_proc_cell_vlservers_fops = {
+	.open		= afs_proc_cell_vlservers_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= afs_proc_cell_vlservers_release,
+};
+
+static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
+static int afs_proc_cell_servers_release(struct inode *inode, struct file *file);
+static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos);
+static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, loff_t *pos);
+static void afs_proc_cell_servers_stop(struct seq_file *p, void *v);
+static int afs_proc_cell_servers_show(struct seq_file *m, void *v);
+
+static struct seq_operations afs_proc_cell_servers_ops = {
+	.start	= afs_proc_cell_servers_start,
+	.next	= afs_proc_cell_servers_next,
+	.stop	= afs_proc_cell_servers_stop,
+	.show	= afs_proc_cell_servers_show,
+};
+
+static struct file_operations afs_proc_cell_servers_fops = {
+	.open		= afs_proc_cell_servers_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= afs_proc_cell_servers_release,
+};
+
+/*****************************************************************************/
+/*
+ * initialise the /proc/fs/afs/ directory
+ */
+int afs_proc_init(void)
+{
+	struct proc_dir_entry *p;
+
+	_enter("");
+
+	proc_afs = proc_mkdir("fs/afs",NULL);
+	if (!proc_afs)
+		goto error;
+	proc_afs->owner = THIS_MODULE;
+
+	p = create_proc_entry("cells",0,proc_afs);
+	if (!p)
+		goto error_proc;
+	p->proc_fops = &afs_proc_cells_fops;
+	p->owner = THIS_MODULE;
+
+	_leave(" = 0");
+	return 0;
+
+#if 0
+ error_cells:
+	remove_proc_entry("cells",proc_afs);
+#endif
+ error_proc:
+	remove_proc_entry("fs/afs",NULL);
+ error:
+	_leave(" = -ENOMEM");
+	return -ENOMEM;
+
+} /* end afs_proc_init() */
+
+/*****************************************************************************/
+/*
+ * clean up the /proc/fs/afs/ directory
+ */
+void afs_proc_cleanup(void)
+{
+	remove_proc_entry("cells",proc_afs);
+
+	remove_proc_entry("fs/afs",NULL);
+
+} /* end afs_proc_cleanup() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/fs/afs/cells" which provides a summary of extant cells
+ */
+static int afs_proc_cells_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *m;
+	int ret;
+
+	ret = seq_open(file,&afs_proc_cells_ops);
+	if (ret<0)
+		return ret;
+
+	m = file->private_data;
+	m->private = PDE(inode)->data;
+
+	return 0;
+} /* end afs_proc_cells_open() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the cells list and return the first item
+ */
+static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
+{
+	struct list_head *_p;
+	loff_t pos = *_pos;
+
+	/* lock the list against modification */
+	down_read(&afs_proc_cells_sem);
+
+	/* allow for the header line */
+	if (!pos)
+		return (void *)1;
+	pos--;
+
+	/* find the n'th element in the list */
+	list_for_each(_p,&afs_proc_cells)
+		if (!pos--)
+			break;
+
+	return _p!=&afs_proc_cells ? _p : NULL;
+} /* end afs_proc_cells_start() */
+
+/*****************************************************************************/
+/*
+ * move to next cell in cells list
+ */
+static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos)
+{
+	struct list_head *_p;
+
+	(*pos)++;
+
+	_p = v;
+	_p = v==(void*)1 ? afs_proc_cells.next : _p->next;
+
+	return _p!=&afs_proc_cells ? _p : NULL;
+} /* end afs_proc_cells_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the cells list
+ */
+static void afs_proc_cells_stop(struct seq_file *p, void *v)
+{
+	up_read(&afs_proc_cells_sem);
+
+} /* end afs_proc_cells_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of cell lines
+ */
+static int afs_proc_cells_show(struct seq_file *m, void *v)
+{
+	afs_cell_t *cell = list_entry(v,afs_cell_t,proc_link);
+
+	/* display header on line 1 */
+	if (v == (void *)1) {
+		seq_puts(m, "USE NAME\n");
+		return 0;
+	}
+
+	/* display one cell per line on subsequent lines */
+	seq_printf(m,"%3d %s\n",atomic_read(&cell->usage),cell->name);
+
+	return 0;
+} /* end afs_proc_cells_show() */
+
+/*****************************************************************************/
+/*
+ * handle writes to /proc/fs/afs/cells
+ * - to add cells: echo "add <cellname> <IP>[:<IP>][:<IP>]*
+ */
+static ssize_t afs_proc_cells_write(struct file *file, const char *buf, size_t size, loff_t *_pos)
+{
+	char *kbuf, *name, *args;
+	int ret;
+
+	/* start by dragging the command into memory */
+	if (size<=1 || size>=PAGE_SIZE)
+		return -EINVAL;
+
+	kbuf = kmalloc(size+1,GFP_KERNEL);
+	if (!kbuf)
+		return -ENOMEM;
+
+	ret = -EFAULT;
+	if (copy_from_user(kbuf,buf,size)!=0)
+		goto done;
+	kbuf[size] = 0;
+
+	/* trim to first NL */
+	name = memchr(kbuf,'\n',size);
+	if (name) *name = 0;
+
+	/* split into command, name and argslist */
+	name = strchr(kbuf,' ');
+	if (!name) goto inval;
+	do { *name++ = 0; } while(*name==' ');
+	if (!*name) goto inval;
+
+	args = strchr(name,' ');
+	if (!args) goto inval;
+	do { *args++ = 0; } while(*args==' ');
+	if (!*args) goto inval;
+
+	/* determine command to perform */
+	_debug("cmd=%s name=%s args=%s",kbuf,name,args);
+
+	if (strcmp(kbuf,"add")==0) {
+		afs_cell_t *cell;
+		ret = afs_cell_create(name,args,&cell);
+		if (ret<0)
+			goto done;
+
+		printk("kAFS: Added new cell '%s'\n",name);
+	}
+	else {
+		goto inval;
+	}
+
+	ret = size;
+
+ done:
+	kfree(kbuf);
+	_leave(" = %d",ret);
+	return ret;
+
+ inval:
+	ret = -EINVAL;
+	printk("kAFS: Invalid Command on /proc/fs/afs/cells file\n");
+	goto done;
+} /* end afs_proc_cells_write() */
+
+/*****************************************************************************/
+/*
+ * initialise /proc/fs/afs/<cell>/
+ */
+int afs_proc_cell_setup(afs_cell_t *cell)
+{
+	struct proc_dir_entry *p;
+
+	_enter("%p{%s}",cell,cell->name);
+
+	cell->proc_dir = proc_mkdir(cell->name,proc_afs);
+	if (!cell->proc_dir)
+		return -ENOMEM;
+
+	p = create_proc_entry("servers",0,cell->proc_dir);
+	if (!p)
+		goto error_proc;
+	p->proc_fops = &afs_proc_cell_servers_fops;
+	p->owner = THIS_MODULE;
+	p->data = cell;
+
+	p = create_proc_entry("vlservers",0,cell->proc_dir);
+	if (!p)
+		goto error_servers;
+	p->proc_fops = &afs_proc_cell_vlservers_fops;
+	p->owner = THIS_MODULE;
+	p->data = cell;
+
+	p = create_proc_entry("volumes",0,cell->proc_dir);
+	if (!p)
+		goto error_vlservers;
+	p->proc_fops = &afs_proc_cell_volumes_fops;
+	p->owner = THIS_MODULE;
+	p->data = cell;
+
+	_leave(" = 0");
+	return 0;
+
+ error_vlservers:
+	remove_proc_entry("vlservers",cell->proc_dir);
+ error_servers:
+	remove_proc_entry("servers",cell->proc_dir);
+ error_proc:
+	remove_proc_entry(cell->name,proc_afs);
+	_leave(" = -ENOMEM");
+	return -ENOMEM;
+} /* end afs_proc_cell_setup() */
+
+/*****************************************************************************/
+/*
+ * remove /proc/fs/afs/<cell>/
+ */
+void afs_proc_cell_remove(afs_cell_t *cell)
+{
+	_enter("");
+
+	remove_proc_entry("volumes",cell->proc_dir);
+	remove_proc_entry("vlservers",cell->proc_dir);
+	remove_proc_entry("servers",cell->proc_dir);
+	remove_proc_entry(cell->name,proc_afs);
+
+	_leave("");
+} /* end afs_proc_cell_remove() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/fs/afs/<cell>/volumes" which provides a summary of extant cells
+ */
+static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *m;
+	afs_cell_t *cell;
+	int ret;
+
+	cell = afs_get_cell_maybe((afs_cell_t**)&PDE(inode)->data);
+	if (!cell)
+		return -ENOENT;
+
+	ret = seq_open(file,&afs_proc_cell_volumes_ops);
+	if (ret<0)
+		return ret;
+
+	m = file->private_data;
+	m->private = cell;
+
+	return 0;
+} /* end afs_proc_cell_volumes_open() */
+
+/*****************************************************************************/
+/*
+ * close the file and release the ref to the cell
+ */
+static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
+{
+	afs_cell_t *cell = PDE(inode)->data;
+	int ret;
+
+	ret = seq_release(inode,file);
+
+	afs_put_cell(cell);
+
+} /* end afs_proc_cell_volumes_release() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the cells list and return the first item
+ */
+static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
+{
+	struct list_head *_p;
+	afs_cell_t *cell = m->private;
+	loff_t pos = *_pos;
+
+	_enter("cell=%p pos=%Ld",cell,*_pos);
+
+	/* lock the list against modification */
+	down_read(&cell->vl_sem);
+
+	/* allow for the header line */
+	if (!pos)
+		return (void *)1;
+	pos--;
+
+	/* find the n'th element in the list */
+	list_for_each(_p,&cell->vl_list)
+		if (!pos--)
+			break;
+
+	return _p!=&cell->vl_list ? _p : NULL;
+} /* end afs_proc_cell_volumes_start() */
+
+/*****************************************************************************/
+/*
+ * move to next cell in cells list
+ */
+static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v, loff_t *_pos)
+{
+	struct list_head *_p;
+	afs_cell_t *cell = p->private;
+
+	_enter("cell=%p pos=%Ld",cell,*_pos);
+
+	(*_pos)++;
+
+	_p = v;
+	_p = v==(void*)1 ? cell->vl_list.next : _p->next;
+
+	return _p!=&cell->vl_list ? _p : NULL;
+} /* end afs_proc_cell_volumes_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the cells list
+ */
+static void afs_proc_cell_volumes_stop(struct seq_file *p, void *v)
+{
+	afs_cell_t *cell = p->private;
+
+	up_read(&cell->vl_sem);
+
+} /* end afs_proc_cell_volumes_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of volume lines
+ */
+static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
+{
+	afs_vlocation_t *vlocation = list_entry(v,afs_vlocation_t,link);
+
+	/* display header on line 1 */
+	if (v == (void *)1) {
+		seq_puts(m, "USE VLID[0]  VLID[1]  VLID[2]  NAME\n");
+		return 0;
+	}
+
+	/* display one cell per line on subsequent lines */
+	seq_printf(m,"%3d %08x %08x %08x %s\n",
+		   atomic_read(&vlocation->usage),
+		   vlocation->vldb.vid[0],
+		   vlocation->vldb.vid[1],
+		   vlocation->vldb.vid[2],
+		   vlocation->vldb.name
+		   );
+
+	return 0;
+} /* end afs_proc_cell_volumes_show() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/fs/afs/<cell>/vlservers" which provides a list of volume location server
+ */
+static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *m;
+	afs_cell_t *cell;
+	int ret;
+
+	cell = afs_get_cell_maybe((afs_cell_t**)&PDE(inode)->data);
+	if (!cell)
+		return -ENOENT;
+
+	ret = seq_open(file,&afs_proc_cell_vlservers_ops);
+	if (ret<0)
+		return ret;
+
+	m = file->private_data;
+	m->private = cell;
+
+	return 0;
+} /* end afs_proc_cell_vlservers_open() */
+
+/*****************************************************************************/
+/*
+ * close the file and release the ref to the cell
+ */
+static int afs_proc_cell_vlservers_release(struct inode *inode, struct file *file)
+{
+	afs_cell_t *cell = PDE(inode)->data;
+	int ret;
+
+	ret = seq_release(inode,file);
+
+	afs_put_cell(cell);
+
+} /* end afs_proc_cell_vlservers_release() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the cells list and return the first item
+ */
+static void *afs_proc_cell_vlservers_start(struct seq_file *m, loff_t *_pos)
+{
+	afs_cell_t *cell = m->private;
+	loff_t pos = *_pos;
+
+	_enter("cell=%p pos=%Ld",cell,*_pos);
+
+	/* lock the list against modification */
+	down_read(&cell->vl_sem);
+
+	/* allow for the header line */
+	if (!pos)
+		return (void *)1;
+	pos--;
+
+	if (pos>=cell->vl_naddrs)
+		return NULL;
+
+	return &cell->vl_addrs[pos];
+} /* end afs_proc_cell_vlservers_start() */
+
+/*****************************************************************************/
+/*
+ * move to next cell in cells list
+ */
+static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v, loff_t *_pos)
+{
+	afs_cell_t *cell = p->private;
+	loff_t pos;
+
+	_enter("cell=%p{nad=%u} pos=%Ld",cell,cell->vl_naddrs,*_pos);
+
+	pos = *_pos;
+	(*_pos)++;
+	if (pos>=cell->vl_naddrs)
+		return NULL;
+
+	return &cell->vl_addrs[pos];
+} /* end afs_proc_cell_vlservers_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the cells list
+ */
+static void afs_proc_cell_vlservers_stop(struct seq_file *p, void *v)
+{
+	afs_cell_t *cell = p->private;
+
+	up_read(&cell->vl_sem);
+
+} /* end afs_proc_cell_vlservers_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of volume lines
+ */
+static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
+{
+	struct in_addr *addr = v;
+
+	/* display header on line 1 */
+	if (v == (struct in_addr *)1) {
+		seq_puts(m,"ADDRESS\n");
+		return 0;
+	}
+
+	/* display one cell per line on subsequent lines */
+	seq_printf(m,"%u.%u.%u.%u\n",NIPQUAD(addr->s_addr));
+
+	return 0;
+} /* end afs_proc_cell_vlservers_show() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/fs/afs/<cell>/servers" which provides a summary of active servers
+ */
+static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *m;
+	afs_cell_t *cell;
+	int ret;
+
+	cell = afs_get_cell_maybe((afs_cell_t**)&PDE(inode)->data);
+	if (!cell)
+		return -ENOENT;
+
+	ret = seq_open(file,&afs_proc_cell_servers_ops);
+	if (ret<0)
+		return ret;
+
+	m = file->private_data;
+	m->private = cell;
+
+	return 0;
+} /* end afs_proc_cell_servers_open() */
+
+/*****************************************************************************/
+/*
+ * close the file and release the ref to the cell
+ */
+static int afs_proc_cell_servers_release(struct inode *inode, struct file *file)
+{
+	afs_cell_t *cell = PDE(inode)->data;
+	int ret;
+
+	ret = seq_release(inode,file);
+
+	afs_put_cell(cell);
+
+} /* end afs_proc_cell_servers_release() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the cells list and return the first item
+ */
+static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
+{
+	struct list_head *_p;
+	afs_cell_t *cell = m->private;
+	loff_t pos = *_pos;
+
+	_enter("cell=%p pos=%Ld",cell,*_pos);
+
+	/* lock the list against modification */
+	read_lock(&cell->sv_lock);
+
+	/* allow for the header line */
+	if (!pos)
+		return (void *)1;
+	pos--;
+
+	/* find the n'th element in the list */
+	list_for_each(_p,&cell->sv_list)
+		if (!pos--)
+			break;
+
+	return _p!=&cell->sv_list ? _p : NULL;
+} /* end afs_proc_cell_servers_start() */
+
+/*****************************************************************************/
+/*
+ * move to next cell in cells list
+ */
+static void *afs_proc_cell_servers_next(struct seq_file *p, void *v, loff_t *_pos)
+{
+	struct list_head *_p;
+	afs_cell_t *cell = p->private;
+
+	_enter("cell=%p pos=%Ld",cell,*_pos);
+
+	(*_pos)++;
+
+	_p = v;
+	_p = v==(void*)1 ? cell->sv_list.next : _p->next;
+
+	return _p!=&cell->sv_list ? _p : NULL;
+} /* end afs_proc_cell_servers_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the cells list
+ */
+static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
+{
+	afs_cell_t *cell = p->private;
+
+	read_unlock(&cell->sv_lock);
+
+} /* end afs_proc_cell_servers_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of volume lines
+ */
+static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
+{
+	afs_server_t *server = list_entry(v,afs_server_t,link);
+	char ipaddr[20];
+
+	/* display header on line 1 */
+	if (v == (void *)1) {
+		seq_puts(m, "USE ADDR            STATE\n");
+		return 0;
+	}
+
+	/* display one cell per line on subsequent lines */
+	sprintf(ipaddr,"%u.%u.%u.%u",NIPQUAD(server->addr));
+	seq_printf(m,"%3d %-15.15s %5d\n",
+		   atomic_read(&server->usage),
+		   ipaddr,
+		   server->fs_state
+		   );
+
+	return 0;
+} /* end afs_proc_cell_servers_show() */
diff -Nru a/fs/afs/server.c b/fs/afs/server.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/server.c	Tue Oct 15 20:29:24 2002
@@ -0,0 +1,489 @@
+/* server.c: AFS server record management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include "volume.h"
+#include "cell.h"
+#include "server.h"
+#include "transport.h"
+#include "vlclient.h"
+#include "kafstimod.h"
+#include "internal.h"
+
+spinlock_t afs_server_peer_lock = SPIN_LOCK_UNLOCKED;
+
+#define FS_SERVICE_ID		1	/* AFS Volume Location Service ID */
+#define VL_SERVICE_ID		52	/* AFS Volume Location Service ID */
+
+static void __afs_server_timeout(afs_timer_t *timer)
+{
+	afs_server_t *server = list_entry(timer,afs_server_t,timeout);
+
+	_debug("SERVER TIMEOUT [%p{u=%d}]",server,atomic_read(&server->usage));
+
+	afs_server_do_timeout(server);
+}
+
+static const struct afs_timer_ops afs_server_timer_ops = {
+	.timed_out	= __afs_server_timeout,
+};
+
+/*****************************************************************************/
+/*
+ * lookup a server record in a cell
+ * - TODO: search the cell's server list
+ */
+int afs_server_lookup(afs_cell_t *cell, const struct in_addr *addr, afs_server_t **_server)
+{
+	struct list_head *_p;
+	afs_server_t *server, *active, *zombie;
+	int loop;
+
+	_enter("%p,%08x,",cell,ntohl(addr->s_addr));
+
+	/* allocate and initialise a server record */
+	server = kmalloc(sizeof(afs_server_t),GFP_KERNEL);
+	if (!server) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	memset(server,0,sizeof(afs_server_t));
+	atomic_set(&server->usage,1);
+
+	INIT_LIST_HEAD(&server->link);
+	init_rwsem(&server->sem);
+	INIT_LIST_HEAD(&server->fs_callq);
+	spin_lock_init(&server->fs_lock);
+	INIT_LIST_HEAD(&server->cb_promises);
+	spin_lock_init(&server->cb_lock);
+
+	for (loop=0; loop<AFS_SERVER_CONN_LIST_SIZE; loop++)
+		server->fs_conn_cnt[loop] = 4;
+
+	memcpy(&server->addr,addr,sizeof(struct in_addr));
+	server->addr.s_addr = addr->s_addr;
+
+	afs_timer_init(&server->timeout,&afs_server_timer_ops);
+
+	/* add to the cell */
+	write_lock(&cell->sv_lock);
+
+	/* check the active list */
+	list_for_each(_p,&cell->sv_list) {
+		active = list_entry(_p,afs_server_t,link);
+
+		if (active->addr.s_addr==addr->s_addr)
+			goto use_active_server;
+	}
+
+	/* check the inactive list */
+	spin_lock(&cell->sv_gylock);
+	list_for_each(_p,&cell->sv_graveyard) {
+		zombie = list_entry(_p,afs_server_t,link);
+
+		if (zombie->addr.s_addr==addr->s_addr)
+			goto resurrect_server;
+	}
+	spin_unlock(&cell->sv_gylock);
+
+	afs_get_cell(cell);
+	server->cell = cell;
+	list_add_tail(&server->link,&cell->sv_list);
+
+	write_unlock(&cell->sv_lock);
+
+	*_server = server;
+	_leave(" = 0 (%p)",server);
+	return 0;
+
+	/* found a matching active server */
+ use_active_server:
+	_debug("active server");
+	afs_get_server(active);
+	write_unlock(&cell->sv_lock);
+
+	kfree(server);
+
+	*_server = active;
+	_leave(" = 0 (%p)",active);
+	return 0;
+
+	/* found a matching server in the graveyard, so resurrect it and dispose of the new rec */
+ resurrect_server:
+	_debug("resurrecting server");
+
+	list_del(&zombie->link);
+	list_add_tail(&zombie->link,&cell->sv_list);
+	afs_get_server(zombie);
+	afs_kafstimod_del_timer(&zombie->timeout);
+	spin_unlock(&cell->sv_gylock);
+	write_unlock(&cell->sv_lock);
+
+	kfree(server);
+
+	*_server = zombie;
+	_leave(" = 0 (%p)",zombie);
+	return 0;
+
+} /* end afs_server_lookup() */
+
+/*****************************************************************************/
+/*
+ * destroy a server record
+ * - removes from the cell list
+ */
+void afs_put_server(afs_server_t *server)
+{
+	afs_cell_t *cell;
+
+	_enter("%p",server);
+
+	cell = server->cell;
+
+	/* sanity check */
+	if (atomic_read(&server->usage)<=0)
+		BUG();
+
+	/* to prevent a race, the decrement and the dequeue must be effectively atomic */
+	write_lock(&cell->sv_lock);
+
+	if (likely(!atomic_dec_and_test(&server->usage))) {
+		write_unlock(&cell->sv_lock);
+		_leave("");
+		return;
+	}
+
+	spin_lock(&cell->sv_gylock);
+	list_del(&server->link);
+	list_add_tail(&server->link,&cell->sv_graveyard);
+
+	/* time out in 10 secs */
+	afs_kafstimod_add_timer(&server->timeout,10*HZ);
+
+	spin_unlock(&cell->sv_gylock);
+	write_unlock(&cell->sv_lock);
+
+	_leave(" [killed]");
+} /* end afs_put_server() */
+
+/*****************************************************************************/
+/*
+ * timeout server record
+ * - removes from the cell's graveyard if the usage count is zero
+ */
+void afs_server_do_timeout(afs_server_t *server)
+{
+	struct rxrpc_peer *peer;
+	afs_cell_t *cell;
+	int loop;
+
+	_enter("%p",server);
+
+	cell = server->cell;
+
+	if (atomic_read(&server->usage)<0) BUG();
+
+	/* remove from graveyard if still dead */
+	spin_lock(&cell->vl_gylock);
+	if (atomic_read(&server->usage)==0)
+		list_del_init(&server->link);
+	else
+		server = NULL;
+	spin_unlock(&cell->vl_gylock);
+
+	if (!server) {
+		_leave("");
+		return; /* resurrected */
+	}
+
+	/* we can now destroy it properly */
+	afs_put_cell(cell);
+
+	/* uncross-point the structs under a global lock */
+	spin_lock(&afs_server_peer_lock);
+	peer = server->peer;
+	if (peer) {
+		server->peer = NULL;
+		peer->user = NULL;
+	}
+	spin_unlock(&afs_server_peer_lock);
+
+	/* finish cleaning up the server */
+	for (loop=AFS_SERVER_CONN_LIST_SIZE-1; loop>=0; loop--)
+		if (server->fs_conn[loop])
+			rxrpc_put_connection(server->fs_conn[loop]);
+
+	if (server->vlserver)
+		rxrpc_put_connection(server->vlserver);
+
+	kfree(server);
+
+	_leave(" [destroyed]");
+} /* end afs_server_do_timeout() */
+
+/*****************************************************************************/
+/*
+ * get a callslot on a connection to the fileserver on the specified server
+ */
+int afs_server_request_callslot(afs_server_t *server, struct afs_server_callslot *callslot)
+{
+	struct afs_server_callslot *pcallslot;
+	struct rxrpc_connection *conn;
+	int nconn, ret;
+
+	_enter("%p,",server);
+
+	INIT_LIST_HEAD(&callslot->link);
+	callslot->task = current;
+	callslot->conn = NULL;
+	callslot->nconn = -1;
+	callslot->ready = 0;
+
+	ret = 0;
+	conn = NULL;
+
+	/* get hold of a callslot first */
+	spin_lock(&server->fs_lock);
+
+	/* resurrect the server if it's death timeout has expired */
+	if (server->fs_state) {
+		if (time_before(jiffies,server->fs_dead_jif)) {
+			ret = server->fs_state;
+			spin_unlock(&server->fs_lock);
+			_leave(" = %d [still dead]",ret);
+			return ret;
+		}
+
+		server->fs_state = 0;
+	}
+
+	/* try and find a connection that has spare callslots */
+	for (nconn=0; nconn<AFS_SERVER_CONN_LIST_SIZE; nconn++) {
+		if (server->fs_conn_cnt[nconn]>0) {
+			server->fs_conn_cnt[nconn]--;
+			spin_unlock(&server->fs_lock);
+			callslot->nconn = nconn;
+			goto obtained_slot;
+		}
+	}
+
+	/* none were available - wait interruptibly for one to become available */
+	set_current_state(TASK_INTERRUPTIBLE);
+	list_add_tail(&callslot->link,&server->fs_callq);
+	spin_unlock(&server->fs_lock);
+
+	while (!callslot->ready && !signal_pending(current)) {
+		schedule();
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+
+	set_current_state(TASK_RUNNING);
+
+	/* even if we were interrupted we may still be queued */
+	if (!callslot->ready) {
+		spin_lock(&server->fs_lock);
+		list_del_init(&callslot->link);
+		spin_unlock(&server->fs_lock);
+	}
+
+	nconn = callslot->nconn;
+
+	/* if interrupted, we must release any slot we also got before returning an error */
+	if (signal_pending(current)) {
+		ret = -EINTR;
+		goto error_release;
+	}
+
+	/* if we were woken up with an error, then pass that error back to the called */
+	if (nconn<0) {
+		_leave(" = %d",callslot->errno);
+		return callslot->errno;
+	}
+
+	/* were we given a connection directly? */
+	if (callslot->conn) {
+		/* yes - use it */
+		_leave(" = 0 (nc=%d)",nconn);
+		return 0;
+	}
+
+	/* got a callslot, but no connection */
+ obtained_slot:
+
+	/* need to get hold of the RxRPC connection */
+	down_write(&server->sem);
+
+	/* quick check to see if there's an outstanding error */
+	ret = server->fs_state;
+	if (ret)
+		goto error_release_upw;
+
+	if (server->fs_conn[nconn]) {
+		/* reuse an existing connection */
+		rxrpc_get_connection(server->fs_conn[nconn]);
+		callslot->conn = server->fs_conn[nconn];
+	}
+	else {
+		/* create a new connection */
+		ret = rxrpc_create_connection(afs_transport,
+					      htons(7000),
+					      server->addr.s_addr,
+					      FS_SERVICE_ID,
+					      NULL,
+					      &server->fs_conn[nconn]);
+
+		if (ret<0)
+			goto error_release_upw;
+
+		callslot->conn = server->fs_conn[0];
+		rxrpc_get_connection(callslot->conn);
+	}
+
+	up_write(&server->sem);
+
+ 	_leave(" = 0");
+	return 0;
+
+	/* handle an error occurring */
+ error_release_upw:
+	up_write(&server->sem);
+
+ error_release:
+	/* either release the callslot or pass it along to another deserving task */
+	spin_lock(&server->fs_lock);
+
+	if (nconn<0) {
+		/* no callslot allocated */
+	}
+	else if (list_empty(&server->fs_callq)) {
+		/* no one waiting */
+		server->fs_conn_cnt[nconn]++;
+		spin_unlock(&server->fs_lock);
+	}
+	else {
+		/* someone's waiting - dequeue them and wake them up */
+		pcallslot = list_entry(server->fs_callq.next,struct afs_server_callslot,link);
+		list_del_init(&pcallslot->link);
+
+		pcallslot->errno = server->fs_state;
+		if (!pcallslot->errno) {
+			/* pass them out callslot details */
+			callslot->conn = xchg(&pcallslot->conn,callslot->conn);
+			pcallslot->nconn = nconn;
+			callslot->nconn = nconn = -1;
+		}
+		pcallslot->ready = 1;
+		wake_up_process(pcallslot->task);
+		spin_unlock(&server->fs_lock);
+	}
+
+	if (callslot->conn) rxrpc_put_connection(callslot->conn);
+	callslot->conn = NULL;
+
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end afs_server_request_callslot() */
+
+/*****************************************************************************/
+/*
+ * release a callslot back to the server
+ * - transfers the RxRPC connection to the next pending callslot if possible
+ */
+void afs_server_release_callslot(afs_server_t *server, struct afs_server_callslot *callslot)
+{
+	struct afs_server_callslot *pcallslot;
+
+	_enter("{ad=%08x,cnt=%u},{%d}",
+	       ntohl(server->addr.s_addr),
+	       server->fs_conn_cnt[callslot->nconn],
+	       callslot->nconn);
+
+	if (callslot->nconn<0) BUG();
+
+	spin_lock(&server->fs_lock);
+
+	if (list_empty(&server->fs_callq)) {
+		/* no one waiting */
+		server->fs_conn_cnt[callslot->nconn]++;
+		spin_unlock(&server->fs_lock);
+	}
+	else {
+		/* someone's waiting - dequeue them and wake them up */
+		pcallslot = list_entry(server->fs_callq.next,struct afs_server_callslot,link);
+		list_del_init(&pcallslot->link);
+
+		pcallslot->errno = server->fs_state;
+		if (!pcallslot->errno) {
+			/* pass them out callslot details */
+			callslot->conn = xchg(&pcallslot->conn,callslot->conn);
+			pcallslot->nconn = callslot->nconn;
+			callslot->nconn = -1;
+		}
+
+		pcallslot->ready = 1;
+		wake_up_process(pcallslot->task);
+		spin_unlock(&server->fs_lock);
+	}
+
+	if (callslot->conn) rxrpc_put_connection(callslot->conn);
+
+	_leave("");
+} /* end afs_server_release_callslot() */
+
+/*****************************************************************************/
+/*
+ * get a handle to a connection to the vlserver (volume location) on the specified server
+ */
+int afs_server_get_vlconn(afs_server_t *server, struct rxrpc_connection **_conn)
+{
+	struct rxrpc_connection *conn;
+	int ret;
+
+	_enter("%p,",server);
+
+	ret = 0;
+	conn = NULL;
+	down_read(&server->sem);
+
+	if (server->vlserver) {
+		/* reuse an existing connection */
+		rxrpc_get_connection(server->vlserver);
+		conn = server->vlserver;
+		up_read(&server->sem);
+	}
+	else {
+		/* create a new connection */
+		up_read(&server->sem);
+		down_write(&server->sem);
+		if (!server->vlserver) {
+			ret = rxrpc_create_connection(afs_transport,
+						      htons(7003),
+						      server->addr.s_addr,
+						      VL_SERVICE_ID,
+						      NULL,
+						      &server->vlserver);
+		}
+		if (ret==0) {
+			rxrpc_get_connection(server->vlserver);
+			conn = server->vlserver;
+		}
+		up_write(&server->sem);
+	}
+
+	*_conn = conn;
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_server_get_vlconn() */
diff -Nru a/fs/afs/server.h b/fs/afs/server.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/server.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,97 @@
+/* server.h: AFS server record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_SERVER_H
+#define _LINUX_AFS_SERVER_H
+
+#include "types.h"
+#include "kafstimod.h"
+#include <rxrpc/peer.h>
+#include <linux/rwsem.h>
+
+extern spinlock_t afs_server_peer_lock;
+
+/*****************************************************************************/
+/*
+ * AFS server record
+ */
+struct afs_server
+{
+	atomic_t		usage;
+	afs_cell_t		*cell;		/* cell in which server resides */
+	struct list_head	link;		/* link in cell's server list */
+	struct rw_semaphore	sem;		/* access lock */
+	afs_timer_t		timeout;	/* graveyard timeout */
+	struct in_addr		addr;		/* server address */
+	struct rxrpc_peer	*peer;		/* peer record for this server */
+	struct rxrpc_connection	*vlserver;	/* connection to the volume location service */
+
+	/* file service access */
+#define AFS_SERVER_CONN_LIST_SIZE 2
+	struct rxrpc_connection	*fs_conn[AFS_SERVER_CONN_LIST_SIZE]; /* FS connections */
+	unsigned		fs_conn_cnt[AFS_SERVER_CONN_LIST_SIZE];	/* per conn call count */
+	struct list_head	fs_callq;	/* queue of processes waiting to make a call */
+	spinlock_t		fs_lock;	/* access lock */
+	int			fs_state;      	/* 0 or reason FS currently marked dead (-errno) */
+	unsigned		fs_rtt;		/* FS round trip time */
+	unsigned long		fs_act_jif;	/* time at which last activity occurred */
+	unsigned long		fs_dead_jif;	/* time at which no longer to be considered dead */
+
+	/* callback promise management */
+	struct list_head	cb_promises;	/* as yet unbroken promises from this server */
+	spinlock_t		cb_lock;	/* access lock */
+};
+
+extern int afs_server_lookup(afs_cell_t *cell, const struct in_addr *addr, afs_server_t **_server);
+
+#define afs_get_server(S) do { atomic_inc(&(S)->usage); } while(0)
+
+extern void afs_put_server(afs_server_t *server);
+extern void afs_server_do_timeout(afs_server_t *server);
+
+extern int afs_server_find_by_peer(const struct rxrpc_peer *peer, afs_server_t **_server);
+
+extern int afs_server_get_vlconn(afs_server_t *server, struct rxrpc_connection **_conn);
+
+static inline afs_server_t *afs_server_get_from_peer(struct rxrpc_peer *peer)
+{
+	afs_server_t *server;
+
+	spin_lock(&afs_server_peer_lock);
+	server = peer->user;
+	if (server)
+		afs_get_server(server);
+	spin_unlock(&afs_server_peer_lock);
+
+	return server;
+}
+
+/*****************************************************************************/
+/*
+ * AFS server callslot grant record
+ */
+struct afs_server_callslot
+{
+	struct list_head	link;		/* link in server's list */
+	struct task_struct	*task;		/* process waiting to make call */
+	struct rxrpc_connection	*conn;		/* connection to use (or NULL on error) */
+	short			nconn;		/* connection slot number (-1 on error) */
+	char			ready;		/* T when ready */
+	int			errno;		/* error number if nconn==-1 */
+};
+
+extern int afs_server_request_callslot(afs_server_t *server,
+				       struct afs_server_callslot *callslot);
+
+extern void afs_server_release_callslot(afs_server_t *server,
+					struct afs_server_callslot *callslot);
+
+#endif /* _LINUX_AFS_SERVER_H */
diff -Nru a/fs/afs/super.c b/fs/afs/super.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/super.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the
+ * GNU General Public License.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors: David Howells <dhowells@redhat.com>
+ *          David Woodhouse <dwmw2@cambridge.redhat.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "vnode.h"
+#include "volume.h"
+#include "cell.h"
+#include "cmservice.h"
+#include "fsclient.h"
+#include "super.h"
+#include "internal.h"
+
+#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
+
+static inline char *strdup(const char *s)
+{
+	char *ns = kmalloc(strlen(s)+1,GFP_KERNEL);
+	if (ns)
+		strcpy(ns,s);
+	return ns;
+}
+
+static void afs_i_init_once(void *foo, kmem_cache_t *cachep, unsigned long flags);
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static struct super_block *afs_get_sb(struct file_system_type *fs_type,
+				      int flags, char *dev_name, void *data);
+#else
+static struct super_block *afs_read_super(struct super_block *sb, void *data, int);
+#endif
+
+static struct inode *afs_alloc_inode(struct super_block *sb);
+
+static void afs_put_super(struct super_block *sb);
+
+static void afs_destroy_inode(struct inode *inode);
+
+static struct file_system_type afs_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "afs",
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	.get_sb		= afs_get_sb,
+	.kill_sb	= kill_anon_super,
+#else
+	.read_super	= afs_read_super,
+#endif
+};
+
+static struct super_operations afs_super_ops = {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	.statfs		= simple_statfs,
+	.alloc_inode	= afs_alloc_inode,
+	.drop_inode	= generic_delete_inode,
+	.destroy_inode	= afs_destroy_inode,
+#else
+	.read_inode2	= afs_read_inode2,
+#endif
+	.clear_inode	= afs_clear_inode,
+	.put_super	= afs_put_super,
+};
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static kmem_cache_t *afs_inode_cachep;
+#endif
+
+/*****************************************************************************/
+/*
+ * initialise the filesystem
+ */
+int __init afs_fs_init(void)
+{
+	int ret;
+
+	kenter("");
+
+	/* open the cache */
+#if 0
+	ret = -EINVAL;
+	if (!cachedev) {
+		printk(KERN_NOTICE "kAFS: No cache device specified as module parm\n");
+		printk(KERN_NOTICE "kAFS: Set with \"cachedev=<devname>\" on insmod's cmdline\n");
+		return ret;
+	}
+
+	ret = afs_cache_open(cachedev,&afs_cache);
+	if (ret<0) {
+		printk(KERN_NOTICE "kAFS: Failed to open cache device\n");
+		return ret;
+	}
+#endif
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	/* create ourselves an inode cache */
+	ret = -ENOMEM;
+	afs_inode_cachep = kmem_cache_create("afs_inode_cache",
+						sizeof(afs_vnode_t),
+						0,
+						SLAB_HWCACHE_ALIGN,
+						afs_i_init_once,
+						NULL);
+	if (!afs_inode_cachep) {
+		printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n");
+#if 0
+		afs_put_cache(afs_cache);
+#endif
+		return ret;
+	}
+#endif
+
+	/* now export our filesystem to lesser mortals */
+	ret = register_filesystem(&afs_fs_type);
+	if (ret<0) {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+		kmem_cache_destroy(afs_inode_cachep);
+#endif
+#if 0
+		afs_put_cache(afs_cache);
+#endif
+		kleave(" = %d",ret);
+		return ret;
+	}
+
+	kleave(" = 0");
+	return 0;
+} /* end afs_fs_init() */
+
+/*****************************************************************************/
+/*
+ * clean up the filesystem
+ */
+void __exit afs_fs_exit(void)
+{
+	/* destroy our private inode cache */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	kmem_cache_destroy(afs_inode_cachep);
+#endif
+
+	unregister_filesystem(&afs_fs_type);
+
+#if 0
+	if (afs_cache)
+		afs_put_cache(afs_cache);
+#endif
+} /* end afs_fs_exit() */
+
+/*****************************************************************************/
+/*
+ * check that an argument has a value
+ */
+static int want_arg(char **_value, const char *option)
+{
+	if (!_value || !*_value || !**_value) {
+		printk(KERN_NOTICE "kAFS: %s: argument missing\n",option);
+		return 0;
+	}
+	return 1;
+} /* end want_arg() */
+
+/*****************************************************************************/
+/*
+ * check that there is a value
+ */
+#if 0
+static int want_value(char **_value, const char *option)
+{
+	if (!_value || !*_value || !**_value) {
+		printk(KERN_NOTICE "kAFS: %s: argument incomplete\n",option);
+		return 0;
+	}
+	return 1;
+} /* end want_value() */
+#endif
+
+/*****************************************************************************/
+/*
+ * check that there's no subsequent value
+ */
+static int want_no_value(char *const *_value, const char *option)
+{
+	if (*_value && **_value) {
+		printk(KERN_NOTICE "kAFS: %s: Invalid argument: %s\n",option,*_value);
+		return 0;
+	}
+	return 1;
+} /* end want_no_value() */
+
+/*****************************************************************************/
+/*
+ * extract a number from an option string value
+ */
+#if 0
+static int want_number(char **_value, const char *option, unsigned long *number,
+		       unsigned long limit)
+{
+	char *value = *_value;
+
+	if (!want_value(_value,option))
+		return 0;
+
+	*number = simple_strtoul(value,_value,0);
+
+	if (value==*_value) {
+		printk(KERN_NOTICE "kAFS: %s: Invalid number: %s\n",option,value);
+		return 0;
+	}
+
+	if (*number>limit) {
+		printk(KERN_NOTICE "kAFS: %s: numeric value %lu > %lu\n",option,*number,limit);
+		return 0;
+	}
+
+	return 1;
+} /* end want_number() */
+#endif
+
+/*****************************************************************************/
+/*
+ * extract a separator from an option string value
+ */
+#if 0
+static int want_sep(char **_value, const char *option, char sep)
+{
+	if (!want_value(_value,option))
+		return 0;
+
+	if (*(*_value)++ != sep) {
+		printk(KERN_NOTICE "kAFS: %s: '%c' expected: %s\n",option,sep,*_value-1);
+		return 0;
+	}
+
+	return 1;
+} /* end want_number() */
+#endif
+
+/*****************************************************************************/
+/*
+ * extract an IP address from an option string value
+ */
+#if 0
+static int want_ipaddr(char **_value, const char *option, struct in_addr *addr)
+{
+	unsigned long number[4];
+
+	if (!want_value(_value,option))
+		return 0;
+
+	if (!want_number(_value,option,&number[0],255) ||
+	    !want_sep(_value,option,'.') ||
+	    !want_number(_value,option,&number[1],255) ||
+	    !want_sep(_value,option,'.') ||
+	    !want_number(_value,option,&number[2],255) ||
+	    !want_sep(_value,option,'.') ||
+	    !want_number(_value,option,&number[3],255))
+		return 0;
+
+	((u8*)addr)[0] = number[0];
+	((u8*)addr)[1] = number[1];
+	((u8*)addr)[2] = number[2];
+	((u8*)addr)[3] = number[3];
+
+	return 1;
+} /* end want_numeric() */
+#endif
+
+/*****************************************************************************/
+/*
+ * parse the mount options
+ * - this function has been shamelessly adapted from the ext3 fs which shamelessly adapted it from
+ *   the msdos fs
+ */
+static int afs_super_parse_options(struct afs_super_info *as, char *options, char **devname)
+{
+	char *key, *value;
+	int ret;
+
+	_enter("%s",options);
+
+	ret = 0;
+	while ((key = strsep(&options,",")))
+	{
+		value = strchr(key,'=');
+		if (value)
+			*value++ = 0;
+
+		printk("kAFS: KEY: %s, VAL:%s\n",key,value?:"-");
+
+		if (strcmp(key,"rwpath")==0) {
+			if (!want_no_value(&value,"rwpath")) return -EINVAL;
+			as->rwparent = 1;
+			continue;
+		}
+		else if (strcmp(key,"vol")==0) {
+			if (!want_arg(&value,"vol")) return -EINVAL;
+			*devname = value;
+			continue;
+		}
+
+#if 0
+		if (strcmp(key,"servers")==0) {
+			if (!want_arg(&value,"servers")) return -EINVAL;
+
+			_debug("servers=%s",value);
+
+			for (;;) {
+				struct in_addr addr;
+
+				if (!want_ipaddr(&value,"servers",&addr))
+					return -EINVAL;
+
+				ret = afs_create_server(as->cell,&addr,&as->server);
+				if (ret<0) {
+					printk("kAFS: unable to create server: %d\n",ret);
+					return ret;
+				}
+
+				if (!*value)
+					break;
+
+				if (as->server) {
+					printk(KERN_NOTICE
+					       "kAFS: only one server can be specified\n");
+					return -EINVAL;
+				}
+
+				if (!want_sep(&value,"servers",':'))
+					return -EINVAL;
+			}
+			continue;
+		}
+#endif
+
+		printk("kAFS: Unknown mount option: '%s'\n",key);
+		ret = -EINVAL;
+		goto error;
+	}
+
+	ret = 0;
+
+ error:
+	_leave(" = %d",ret);
+
+	return ret;
+} /* end afs_super_parse_options() */
+
+/*****************************************************************************/
+/*
+ * fill in the superblock
+ */
+static int afs_fill_super(struct super_block *sb, void *_data, int silent)
+{
+	struct afs_super_info *as = NULL;
+	struct dentry *root = NULL;
+	struct inode *inode = NULL;
+	afs_fid_t fid;
+	void **data = _data;
+	char *options, *devname;
+	int ret;
+
+	_enter("");
+
+	if (!data) {
+		_leave(" = -EINVAL");
+		return -EINVAL;
+	}
+	devname = data[0];
+	options = data[1];
+	if (options)
+		options[PAGE_SIZE-1] = 0;
+
+	/* allocate a superblock info record */
+	as = kmalloc(sizeof(struct afs_super_info),GFP_KERNEL);
+	if (!as) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	memset(as,0,sizeof(struct afs_super_info));
+
+	/* parse the options */
+	if (options) {
+		ret = afs_super_parse_options(as,options,&devname);
+		if (ret<0)
+			goto error;
+		if (!devname) {
+			printk("kAFS: no volume name specified\n");
+			ret = -EINVAL;
+			goto error;
+		}
+	}
+
+	/* parse the device name */
+	ret = afs_volume_lookup(devname,as->rwparent,&as->volume);
+	if (ret<0)
+		goto error;
+
+	/* fill in the superblock */
+	sb->s_blocksize		= PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits	= PAGE_CACHE_SHIFT;
+	sb->s_magic		= AFS_FS_MAGIC;
+	sb->s_op		= &afs_super_ops;
+	sb->s_fs_info		= as;
+
+	/* allocate the root inode and dentry */
+	fid.vid		= as->volume->vid;
+	fid.vnode	= 1;
+	fid.unique	= 1;
+	ret = afs_iget(sb,&fid,&inode);
+	if (ret<0)
+		goto error;
+
+	ret = -ENOMEM;
+	root = d_alloc_root(inode);
+	if (!root)
+		goto error;
+
+	sb->s_root = root;
+
+	_leave(" = 0");
+	return 0;
+
+ error:
+	if (root) dput(root);
+	if (inode) iput(inode);
+	if (as) {
+		if (as->volume)		afs_put_volume(as->volume);
+		kfree(as);
+	}
+	sb->s_fs_info = NULL;
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_fill_super() */
+
+/*****************************************************************************/
+/*
+ * get an AFS superblock
+ * - TODO: don't use get_sb_nodev(), but rather call sget() directly
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static struct super_block *afs_get_sb(struct file_system_type *fs_type,
+				      int flags,
+				      char *dev_name,
+				      void *options)
+{
+	struct super_block *sb;
+	void *data[2] = { dev_name, options };
+	int ret;
+
+	_enter(",,%s,%p",dev_name,options);
+
+	/* start the cache manager */
+	ret = afscm_start();
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ERR_PTR(ret);
+	}
+
+	/* allocate a deviceless superblock */
+	sb = get_sb_nodev(fs_type,flags,data,afs_fill_super);
+	if (IS_ERR(sb)) {
+		afscm_stop();
+		return sb;
+	}
+
+	_leave("");
+	return sb;
+} /* end afs_get_sb() */
+#endif
+
+/*****************************************************************************/
+/*
+ * read an AFS superblock
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static struct super_block *afs_read_super(struct super_block *sb, void *options, int silent)
+{
+	void *data[2] = { NULL, options };
+	int ret;
+
+	_enter(",,%s",(char*)options);
+
+	/* start the cache manager */
+	ret = afscm_start();
+	if (ret<0) {
+		_leave(" = NULL (%d)",ret);
+		return NULL;
+	}
+
+	/* allocate a deviceless superblock */
+	ret = afs_fill_super(sb,data,silent);
+	if (ret<0) {
+		afscm_stop();
+		_leave(" = NULL (%d)",ret);
+		return NULL;
+	}
+
+	_leave(" = %p",sb);
+	return sb;
+} /* end afs_read_super() */
+#endif
+
+/*****************************************************************************/
+/*
+ * finish the unmounting process on the superblock
+ */
+static void afs_put_super(struct super_block *sb)
+{
+	struct afs_super_info *as = sb->s_fs_info;
+
+	_enter("");
+
+	if (as) {
+		if (as->volume)		afs_put_volume(as->volume);
+	}
+
+	/* stop the cache manager */
+	afscm_stop();
+
+	_leave("");
+} /* end afs_put_super() */
+
+/*****************************************************************************/
+/*
+ * initialise an inode cache slab element prior to any use
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static void afs_i_init_once(void *_vnode, kmem_cache_t *cachep, unsigned long flags)
+{
+	afs_vnode_t *vnode = (afs_vnode_t *) _vnode;
+
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) {
+		memset(vnode,0,sizeof(*vnode));
+		inode_init_once(&vnode->vfs_inode);
+		init_waitqueue_head(&vnode->update_waitq);
+		spin_lock_init(&vnode->lock);
+		INIT_LIST_HEAD(&vnode->cb_link);
+		INIT_LIST_HEAD(&vnode->cb_hash_link);
+		afs_timer_init(&vnode->cb_timeout,&afs_vnode_cb_timed_out_ops);
+	}
+
+} /* end afs_i_init_once() */
+#endif
+
+/*****************************************************************************/
+/*
+ * allocate an AFS inode struct from our slab cache
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static struct inode *afs_alloc_inode(struct super_block *sb)
+{
+	afs_vnode_t *vnode;
+
+	vnode = (afs_vnode_t *) kmem_cache_alloc(afs_inode_cachep,SLAB_KERNEL);
+	if (!vnode)
+		return NULL;
+
+	memset(&vnode->fid,0,sizeof(vnode->fid));
+	memset(&vnode->status,0,sizeof(vnode->status));
+
+	vnode->volume = NULL;
+	vnode->update_cnt = 0;
+	vnode->flags = 0;
+
+	return &vnode->vfs_inode;
+} /* end afs_alloc_inode() */
+#endif
+
+/*****************************************************************************/
+/*
+ * destroy an AFS inode struct
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+static void afs_destroy_inode(struct inode *inode)
+{
+	_enter("{%lu}",inode->i_ino);
+	kmem_cache_free(afs_inode_cachep, AFS_FS_I(inode));
+} /* end afs_destroy_inode() */
+#endif
diff -Nru a/fs/afs/super.h b/fs/afs/super.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/super.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,43 @@
+/* super.h: AFS filesystem internal private data
+ *
+ * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
+ *
+ * This software may be freely redistributed under the terms of the
+ * GNU General Public License.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Authors: David Woodhouse <dwmw2@cambridge.redhat.com>
+ *          David Howells <dhowells@redhat.com>
+ *
+ */
+
+#ifndef _LINUX_AFS_SUPER_H
+#define _LINUX_AFS_SUPER_H
+
+#include <linux/fs.h>
+#include "server.h"
+
+#ifdef __KERNEL__
+
+/*****************************************************************************/
+/*
+ * AFS superblock private data
+ * - there's one superblock per volume
+ */
+struct afs_super_info
+{
+	afs_volume_t		*volume;	/* volume record */
+	char			rwparent;	/* T if parent is R/W AFS volume */
+};
+
+static inline struct afs_super_info *AFS_FS_S(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_AFS_SUPER_H */
diff -Nru a/fs/afs/transport.h b/fs/afs/transport.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/transport.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,21 @@
+/* transport.h: AFS transport management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_TRANSPORT_H
+#define _LINUX_AFS_TRANSPORT_H
+
+#include "types.h"
+#include <rxrpc/transport.h>
+
+/* the cache manager transport endpoint */
+extern struct rxrpc_transport *afs_transport;
+
+#endif /* _LINUX_AFS_TRANSPORT_H */
diff -Nru a/fs/afs/types.h b/fs/afs/types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/types.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,152 @@
+/* types.h: AFS types
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_TYPES_H
+#define _LINUX_AFS_TYPES_H
+
+#ifdef __KERNEL__
+#include <rxrpc/types.h>
+#endif /* __KERNEL__ */
+
+typedef unsigned			afs_volid_t;
+typedef unsigned			afs_vnodeid_t;
+typedef unsigned long long		afs_dataversion_t;
+
+typedef struct afs_async_op		afs_async_op_t;
+typedef struct afs_callback		afs_callback_t;
+typedef struct afs_cell			afs_cell_t;
+typedef struct afs_fid			afs_fid_t;
+typedef struct afs_file_status		afs_file_status_t;
+typedef struct afs_server		afs_server_t;
+typedef struct afs_timer		afs_timer_t;
+typedef struct afs_vlocation		afs_vlocation_t;
+typedef struct afs_vnode		afs_vnode_t;
+typedef struct afs_volsync		afs_volsync_t;
+typedef struct afs_volume		afs_volume_t;
+typedef struct afs_volume_info		afs_volume_info_t;
+
+typedef struct afsc_cache		afsc_cache_t;
+typedef struct afsc_cache_cell		afsc_cache_cell_t;
+typedef struct afsc_cache_vldb		afsc_cache_vldb_t;
+typedef struct afsc_cell_record		afsc_cell_record_t;
+typedef struct afsc_inode		afsc_inode_t;
+typedef struct afsc_io			afsc_io_t;
+typedef struct afsc_io_subop		afsc_io_subop_t;
+typedef struct afsc_io_queue		afsc_io_queue_t;
+typedef struct afsc_super_block		afsc_super_block_t;
+typedef struct afsc_vldb_record		afsc_vldb_record_t;
+typedef struct afsc_vnode_catalogue	afsc_vnode_catalogue_t;
+typedef struct afsc_vnode_meta		afsc_vnode_meta_t;
+
+typedef struct afsvl_dbentry		afsvl_dbentry_t;
+
+typedef enum {
+	AFSVL_RWVOL,			/* read/write volume */
+	AFSVL_ROVOL,			/* read-only volume */
+	AFSVL_BACKVOL,			/* backup volume */
+} afs_voltype_t;
+
+extern const char *afs_voltypes[];
+
+typedef enum {
+	AFS_FTYPE_INVALID	= 0,
+	AFS_FTYPE_FILE		= 1,
+	AFS_FTYPE_DIR		= 2,
+	AFS_FTYPE_SYMLINK	= 3,
+} afs_file_type_t;
+
+#ifdef __KERNEL__
+
+/*****************************************************************************/
+/*
+ * AFS file identifier
+ */
+struct afs_fid
+{
+	afs_volid_t	vid;		/* volume ID */
+	afs_vnodeid_t	vnode;		/* file index within volume */
+	unsigned	unique;		/* unique ID number (file index version) */
+};
+
+/*****************************************************************************/
+/*
+ * AFS callback notification
+ */
+typedef enum {
+	AFSCM_CB_UNTYPED	= 0,	/* no type set on CB break */
+	AFSCM_CB_EXCLUSIVE	= 1,	/* CB exclusive to CM [not implemented] */
+	AFSCM_CB_SHARED		= 2,	/* CB shared by other CM's */
+	AFSCM_CB_DROPPED	= 3,	/* CB promise cancelled by file server */
+} afs_callback_type_t;
+
+struct afs_callback
+{
+	afs_server_t		*server;	/* server that made the promise */
+	afs_fid_t		fid;		/* file identifier */
+	unsigned		version;	/* callback version */
+	unsigned		expiry;		/* time at which expires */
+	afs_callback_type_t	type;		/* type of callback */
+};
+
+#define AFSCBMAX 50
+
+/*****************************************************************************/
+/*
+ * AFS volume information
+ */
+struct afs_volume_info
+{
+	afs_volid_t		vid;		/* volume ID */
+	afs_voltype_t		type;		/* type of this volume */
+	afs_volid_t		type_vids[5];	/* volume ID's for possible types for this vol */
+	
+	/* list of fileservers serving this volume */
+	size_t			nservers;	/* number of entries used in servers[] */
+	struct {
+		struct in_addr	addr;		/* fileserver address */
+	} servers[8];
+};
+
+/*****************************************************************************/
+/*
+ * AFS file status information
+ */
+struct afs_file_status
+{
+	unsigned		if_version;	/* interface version */
+#define AFS_FSTATUS_VERSION	1
+
+	afs_file_type_t		type;		/* file type */
+	unsigned		nlink;		/* link count */
+	size_t			size;		/* file size */
+	afs_dataversion_t	version;	/* current data version */
+	unsigned		author;		/* author ID */
+	unsigned		owner;		/* owner ID */
+	unsigned		caller_access;	/* access rights for authenticated caller */
+	unsigned		anon_access;	/* access rights for unauthenticated caller */
+	umode_t			mode;		/* UNIX mode */
+	afs_fid_t		parent;		/* parent file ID */
+	time_t			mtime_client;	/* last time client changed data */
+	time_t			mtime_server;	/* last time server changed data */
+};
+
+/*****************************************************************************/
+/*
+ * AFS volume synchronisation information
+ */
+struct afs_volsync
+{
+	time_t			creation;	/* volume creation time */
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_AFS_TYPES_H */
diff -Nru a/fs/afs/vlclient.c b/fs/afs/vlclient.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/vlclient.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,662 @@
+/* vlclient.c: AFS Volume Location Service client
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include "server.h"
+#include "volume.h"
+#include "vlclient.h"
+#include "kafsasyncd.h"
+#include "kafstimod.h"
+#include "errors.h"
+#include "internal.h"
+
+#define VLGETENTRYBYID		503	/* AFS Get Cache Entry By ID operation ID */
+#define VLGETENTRYBYNAME	504	/* AFS Get Cache Entry By Name operation ID */
+#define VLPROBE			514	/* AFS Probe Volume Location Service operation ID */
+
+static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call);
+static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call);
+
+/*****************************************************************************/
+/*
+ * map afs VL abort codes to/from Linux error codes
+ * - called with call->lock held
+ */
+static void afs_rxvl_aemap(struct rxrpc_call *call)
+{
+	int err;
+
+	_enter("{%u,%u,%d}",call->app_err_state,call->app_abort_code,call->app_errno);
+
+	switch (call->app_err_state) {
+	case RXRPC_ESTATE_LOCAL_ABORT:
+		call->app_abort_code = -call->app_errno;
+		return;
+
+	case RXRPC_ESTATE_PEER_ABORT:
+		switch (call->app_abort_code) {
+		case AFSVL_IDEXIST:		err = -EEXIST;		break;
+		case AFSVL_IO:			err = -EREMOTEIO;	break;
+		case AFSVL_NAMEEXIST:		err = -EEXIST;		break;
+		case AFSVL_CREATEFAIL:		err = -EREMOTEIO;	break;
+		case AFSVL_NOENT:		err = -ENOMEDIUM;	break;
+		case AFSVL_EMPTY:		err = -ENOMEDIUM;	break;
+		case AFSVL_ENTDELETED:		err = -ENOMEDIUM;	break;
+		case AFSVL_BADNAME:		err = -EINVAL;		break;
+		case AFSVL_BADINDEX:		err = -EINVAL;		break;
+		case AFSVL_BADVOLTYPE:		err = -EINVAL;		break;
+		case AFSVL_BADSERVER:		err = -EINVAL;		break;
+		case AFSVL_BADPARTITION:	err = -EINVAL;		break;
+		case AFSVL_REPSFULL:		err = -EFBIG;		break;
+		case AFSVL_NOREPSERVER:		err = -ENOENT;		break;
+		case AFSVL_DUPREPSERVER:	err = -EEXIST;		break;
+		case AFSVL_RWNOTFOUND:		err = -ENOENT;		break;
+		case AFSVL_BADREFCOUNT:		err = -EINVAL;		break;
+		case AFSVL_SIZEEXCEEDED:	err = -EINVAL;		break;
+		case AFSVL_BADENTRY:		err = -EINVAL;		break;
+		case AFSVL_BADVOLIDBUMP:	err = -EINVAL;		break;
+		case AFSVL_IDALREADYHASHED:	err = -EINVAL;		break;
+		case AFSVL_ENTRYLOCKED:		err = -EBUSY;		break;
+		case AFSVL_BADVOLOPER:		err = -EBADRQC;		break;
+		case AFSVL_BADRELLOCKTYPE:	err = -EINVAL;		break;
+		case AFSVL_RERELEASE:		err = -EREMOTEIO;	break;
+		case AFSVL_BADSERVERFLAG:	err = -EINVAL;		break;
+		case AFSVL_PERM:		err = -EACCES;		break;
+		case AFSVL_NOMEM:		err = -EREMOTEIO;	break;
+		default:
+			err = afs_abort_to_error(call->app_abort_code);
+			break;
+		}
+		call->app_errno = err;
+		return;
+
+	default:
+		return;
+	}
+} /* end afs_rxvl_aemap() */
+
+/*****************************************************************************/
+/*
+ * probe a volume location server to see if it is still alive
+ */
+int afs_rxvl_probe(afs_server_t *server, int alloc_flags)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_connection *conn;
+	struct rxrpc_call *call;
+	struct iovec piov[1];
+	size_t sent;
+	int ret;
+	u32 param[1];
+
+	/* get hold of the vlserver connection */
+	ret = afs_server_get_vlconn(server,&conn);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(conn,NULL,NULL,afs_rxvl_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = VLPROBE;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	param[0] = htonl(VLPROBE);
+	piov[0].iov_len = sizeof(param);
+	piov[0].iov_base = param;
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,alloc_flags,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the reply to completely arrive */
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (call->app_call_state!=RXRPC_CSTATE_CLNT_RCV_REPLY ||
+		    signal_pending(current))
+			break;
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+
+	ret = -EINTR;
+	if (signal_pending(current))
+		goto abort;
+
+	switch (call->app_call_state) {
+	case RXRPC_CSTATE_ERROR:
+		ret = call->app_errno;
+		goto out_unwait;
+
+	case RXRPC_CSTATE_CLNT_GOT_REPLY:
+		ret = 0;
+		goto out_unwait;
+
+	default:
+		BUG();
+	}
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	rxrpc_put_connection(conn);
+ out:
+	return ret;
+
+} /* end afs_rxvl_probe() */
+
+/*****************************************************************************/
+/*
+ * look up a volume location database entry by name
+ */
+int afs_rxvl_get_entry_by_name(afs_server_t *server, const char *volname,
+			       afsc_vldb_record_t *entry)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_connection *conn;
+	struct rxrpc_call *call;
+	struct iovec piov[3];
+	unsigned tmp;
+	size_t sent;
+	int ret, loop;
+	u32 *bp, param[2], zero;
+
+	_enter(",%s,",volname);
+
+	memset(entry,0,sizeof(*entry));
+
+	/* get hold of the vlserver connection */
+	ret = afs_server_get_vlconn(server,&conn);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(conn,NULL,NULL,afs_rxvl_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = VLGETENTRYBYNAME;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	piov[1].iov_len = strlen(volname);
+	piov[1].iov_base = (char*)volname;
+
+	zero = 0;
+	piov[2].iov_len = (4 - (piov[1].iov_len & 3)) & 3;
+	piov[2].iov_base = &zero;
+
+	param[0] = htonl(VLGETENTRYBYNAME);
+	param[1] = htonl(piov[1].iov_len);
+
+	piov[0].iov_len = sizeof(param);
+	piov[0].iov_base = param;
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,3,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the reply to completely arrive */
+	bp = rxrpc_call_alloc_scratch(call,384);
+
+	ret = rxrpc_call_read_data(call,bp,384,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+	if (ret<0) {
+		if (ret==-ECONNABORTED) {
+			ret = call->app_errno;
+			goto out_unwait;
+		}
+		goto abort;
+	}
+
+	/* unmarshall the reply */
+	for (loop=0; loop<64; loop++)
+		entry->name[loop] = ntohl(*bp++);
+	bp++; /* final NUL */
+
+	bp++; /* type */
+	entry->nservers = ntohl(*bp++);
+
+	for (loop=0; loop<8; loop++)
+		entry->servers[loop].s_addr = *bp++;
+
+	bp += 8; /* partition IDs */
+
+	for (loop=0; loop<8; loop++) {
+		tmp = ntohl(*bp++);
+		if (tmp & AFS_VLSF_RWVOL  ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
+		if (tmp & AFS_VLSF_ROVOL  ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
+		if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
+	}
+
+	entry->vid[0] = ntohl(*bp++);
+	entry->vid[1] = ntohl(*bp++);
+	entry->vid[2] = ntohl(*bp++);
+
+	bp++; /* clone ID */
+
+	tmp = ntohl(*bp++); /* flags */
+	if (tmp & AFS_VLF_RWEXISTS  ) entry->vidmask |= AFSC_VOL_STM_RW;
+	if (tmp & AFS_VLF_ROEXISTS  ) entry->vidmask |= AFSC_VOL_STM_RO;
+	if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
+
+	ret = -ENOMEDIUM;
+	if (!entry->vidmask)
+		goto abort;
+
+	/* success */
+	entry->ctime = xtime.tv_sec;
+	ret = 0;
+
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	rxrpc_put_connection(conn);
+ out:
+	_leave(" = %d",ret);
+	return ret;
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+	goto out_unwait;
+} /* end afs_rxvl_get_entry_by_name() */
+
+/*****************************************************************************/
+/*
+ * look up a volume location database entry by ID
+ */
+int afs_rxvl_get_entry_by_id(afs_server_t *server,
+			     afs_volid_t volid,
+			     afs_voltype_t voltype,
+			     afsc_vldb_record_t *entry)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_connection *conn;
+	struct rxrpc_call *call;
+	struct iovec piov[1];
+	unsigned tmp;
+	size_t sent;
+	int ret, loop;
+	u32 *bp, param[3];
+
+	_enter(",%x,%d,",volid,voltype);
+
+	memset(entry,0,sizeof(*entry));
+
+	/* get hold of the vlserver connection */
+	ret = afs_server_get_vlconn(server,&conn);
+	if (ret<0)
+		goto out;
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(conn,NULL,NULL,afs_rxvl_aemap,&call);
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		goto out_put_conn;
+	}
+	call->app_opcode = VLGETENTRYBYID;
+
+	/* we want to get event notifications from the call */
+	add_wait_queue(&call->waitq,&myself);
+
+	/* marshall the parameters */
+	param[0] = htonl(VLGETENTRYBYID);
+	param[1] = htonl(volid);
+	param[2] = htonl(voltype);
+
+	piov[0].iov_len = sizeof(param);
+	piov[0].iov_base = param;
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0)
+		goto abort;
+
+	/* wait for the reply to completely arrive */
+	bp = rxrpc_call_alloc_scratch(call,384);
+
+	ret = rxrpc_call_read_data(call,bp,384,RXRPC_CALL_READ_BLOCK|RXRPC_CALL_READ_ALL);
+	if (ret<0) {
+		if (ret==-ECONNABORTED) {
+			ret = call->app_errno;
+			goto out_unwait;
+		}
+		goto abort;
+	}
+
+	/* unmarshall the reply */
+	for (loop=0; loop<64; loop++)
+		entry->name[loop] = ntohl(*bp++);
+	bp++; /* final NUL */
+
+	bp++; /* type */
+	entry->nservers = ntohl(*bp++);
+
+	for (loop=0; loop<8; loop++)
+		entry->servers[loop].s_addr = *bp++;
+
+	bp += 8; /* partition IDs */
+
+	for (loop=0; loop<8; loop++) {
+		tmp = ntohl(*bp++);
+		if (tmp & AFS_VLSF_RWVOL  ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
+		if (tmp & AFS_VLSF_ROVOL  ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
+		if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
+	}
+
+	entry->vid[0] = ntohl(*bp++);
+	entry->vid[1] = ntohl(*bp++);
+	entry->vid[2] = ntohl(*bp++);
+
+	bp++; /* clone ID */
+
+	tmp = ntohl(*bp++); /* flags */
+	if (tmp & AFS_VLF_RWEXISTS  ) entry->vidmask |= AFSC_VOL_STM_RW;
+	if (tmp & AFS_VLF_ROEXISTS  ) entry->vidmask |= AFSC_VOL_STM_RO;
+	if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
+
+	ret = -ENOMEDIUM;
+	if (!entry->vidmask)
+		goto abort;
+
+#if 0 /* TODO: remove */
+	entry->nservers = 3;
+	entry->servers[0].s_addr = htonl(0xac101249);
+	entry->servers[1].s_addr = htonl(0xac101243);
+	entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
+
+	entry->srvtmask[0] = AFSC_VOL_STM_RO;
+	entry->srvtmask[1] = AFSC_VOL_STM_RO;
+	entry->srvtmask[2] = AFSC_VOL_STM_RO | AFSC_VOL_STM_RW;
+#endif
+
+	/* success */
+	entry->ctime = xtime.tv_sec;
+	ret = 0;
+
+ out_unwait:
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&call->waitq,&myself);
+	rxrpc_put_call(call);
+ out_put_conn:
+	rxrpc_put_connection(conn);
+ out:
+	_leave(" = %d",ret);
+	return ret;
+
+ abort:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	rxrpc_call_abort(call,ret);
+	schedule();
+	goto out_unwait;
+} /* end afs_rxvl_get_entry_by_id() */
+
+/*****************************************************************************/
+/*
+ * look up a volume location database entry by ID asynchronously
+ */
+int afs_rxvl_get_entry_by_id_async(afs_async_op_t *op,
+				   afs_volid_t volid,
+				   afs_voltype_t voltype)
+{
+	struct rxrpc_connection *conn;
+	struct rxrpc_call *call;
+	struct iovec piov[1];
+	size_t sent;
+	int ret;
+	u32 param[3];
+
+	_enter(",%x,%d,",volid,voltype);
+
+	/* get hold of the vlserver connection */
+	ret = afs_server_get_vlconn(op->server,&conn);
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	/* create a call through that connection */
+	ret = rxrpc_create_call(conn,
+				afs_rxvl_get_entry_by_id_attn,
+				afs_rxvl_get_entry_by_id_error,
+				afs_rxvl_aemap,
+				&op->call);
+	rxrpc_put_connection(conn);
+
+	if (ret<0) {
+		printk("kAFS: Unable to create call: %d\n",ret);
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	op->call->app_opcode = VLGETENTRYBYID;
+	op->call->app_user = op;
+
+	call = op->call;
+	rxrpc_get_call(call);
+
+	/* send event notifications from the call to kafsasyncd */
+	afs_kafsasyncd_begin_op(op);
+
+	/* marshall the parameters */
+	param[0] = htonl(VLGETENTRYBYID);
+	param[1] = htonl(volid);
+	param[2] = htonl(voltype);
+
+	piov[0].iov_len = sizeof(param);
+	piov[0].iov_base = param;
+
+	/* allocate result read buffer in scratch space */
+	call->app_scr_ptr = rxrpc_call_alloc_scratch(op->call,384);
+
+	/* send the parameters to the server */
+	ret = rxrpc_call_write_data(call,1,piov,RXRPC_LAST_PACKET,GFP_NOFS,0,&sent);
+	if (ret<0) {
+		rxrpc_call_abort(call,ret); /* handle from kafsasyncd */
+		ret = 0;
+		goto out;
+	}
+
+	/* wait for the reply to completely arrive */
+	ret = rxrpc_call_read_data(call,call->app_scr_ptr,384,0);
+	switch (ret) {
+	case 0:
+	case -EAGAIN:
+	case -ECONNABORTED:
+		ret = 0;
+		break;	/* all handled by kafsasyncd */
+
+	default:
+		rxrpc_call_abort(call,ret); /* force kafsasyncd to handle it */
+		ret = 0;
+		break;
+	}
+
+ out:
+	rxrpc_put_call(call);
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end afs_rxvl_get_entry_by_id_async() */
+
+/*****************************************************************************/
+/*
+ * attend to the asynchronous get VLDB entry by ID
+ */
+int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
+				    afsc_vldb_record_t *entry)
+{
+	unsigned *bp, tmp;
+	int loop, ret;
+
+	_enter("{op=%p cst=%u}",op,op->call->app_call_state);
+
+	memset(entry,0,sizeof(*entry));
+
+	if (op->call->app_call_state==RXRPC_CSTATE_COMPLETE) {
+		/* operation finished */
+		afs_kafsasyncd_terminate_op(op);
+
+		bp = op->call->app_scr_ptr;
+
+		/* unmarshall the reply */
+		for (loop=0; loop<64; loop++)
+			entry->name[loop] = ntohl(*bp++);
+		bp++; /* final NUL */
+
+		bp++; /* type */
+		entry->nservers = ntohl(*bp++);
+
+		for (loop=0; loop<8; loop++)
+			entry->servers[loop].s_addr = *bp++;
+
+		bp += 8; /* partition IDs */
+
+		for (loop=0; loop<8; loop++) {
+			tmp = ntohl(*bp++);
+			if (tmp & AFS_VLSF_RWVOL  ) entry->srvtmask[loop] |= AFSC_VOL_STM_RW;
+			if (tmp & AFS_VLSF_ROVOL  ) entry->srvtmask[loop] |= AFSC_VOL_STM_RO;
+			if (tmp & AFS_VLSF_BACKVOL) entry->srvtmask[loop] |= AFSC_VOL_STM_BAK;
+		}
+
+		entry->vid[0] = ntohl(*bp++);
+		entry->vid[1] = ntohl(*bp++);
+		entry->vid[2] = ntohl(*bp++);
+
+		bp++; /* clone ID */
+
+		tmp = ntohl(*bp++); /* flags */
+		if (tmp & AFS_VLF_RWEXISTS  ) entry->vidmask |= AFSC_VOL_STM_RW;
+		if (tmp & AFS_VLF_ROEXISTS  ) entry->vidmask |= AFSC_VOL_STM_RO;
+		if (tmp & AFS_VLF_BACKEXISTS) entry->vidmask |= AFSC_VOL_STM_BAK;
+
+		ret = -ENOMEDIUM;
+		if (!entry->vidmask) {
+			rxrpc_call_abort(op->call,ret);
+			goto done;
+		}
+
+#if 0 /* TODO: remove */
+		entry->nservers = 3;
+		entry->servers[0].s_addr = htonl(0xac101249);
+		entry->servers[1].s_addr = htonl(0xac101243);
+		entry->servers[2].s_addr = htonl(0xac10125b /*0xac10125b*/);
+
+		entry->srvtmask[0] = AFSC_VOL_STM_RO;
+		entry->srvtmask[1] = AFSC_VOL_STM_RO;
+		entry->srvtmask[2] = AFSC_VOL_STM_RO | AFSC_VOL_STM_RW;
+#endif
+
+		/* success */
+		entry->ctime = xtime.tv_sec;
+		ret = 0;
+		goto done;
+	}
+
+	if (op->call->app_call_state==RXRPC_CSTATE_ERROR) {
+		/* operation error */
+		ret = op->call->app_errno;
+		goto done;
+	}
+
+	_leave(" = -EAGAIN");
+	return -EAGAIN;
+
+ done:
+	rxrpc_put_call(op->call);
+	op->call = NULL;
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_rxvl_get_entry_by_id_async2() */
+
+/*****************************************************************************/
+/*
+ * handle attention events on an async get-entry-by-ID op
+ * - called from krxiod
+ */
+static void afs_rxvl_get_entry_by_id_attn(struct rxrpc_call *call)
+{
+	afs_async_op_t *op = call->app_user;
+
+	_enter("{op=%p cst=%u}",op,call->app_call_state);
+
+	switch (call->app_call_state) {
+	case RXRPC_CSTATE_COMPLETE:
+		afs_kafsasyncd_attend_op(op);
+		break;
+	case RXRPC_CSTATE_CLNT_RCV_REPLY:
+		if (call->app_async_read)
+			break;
+	case RXRPC_CSTATE_CLNT_GOT_REPLY:
+		if (call->app_read_count==0)
+			break;
+		printk("kAFS: Reply bigger than expected {cst=%u asyn=%d mark=%d rdy=%u pr=%u%s}",
+		       call->app_call_state,
+		       call->app_async_read,
+		       call->app_mark,
+		       call->app_ready_qty,
+		       call->pkt_rcv_count,
+		       call->app_last_rcv ? " last" : "");
+
+		rxrpc_call_abort(call,-EBADMSG);
+		break;
+	default:
+		BUG();
+	}
+
+	_leave("");
+
+} /* end afs_rxvl_get_entry_by_id_attn() */
+
+/*****************************************************************************/
+/*
+ * handle error events on an async get-entry-by-ID op
+ * - called from krxiod
+ */
+static void afs_rxvl_get_entry_by_id_error(struct rxrpc_call *call)
+{
+	afs_async_op_t *op = call->app_user;
+
+	_enter("{op=%p cst=%u}",op,call->app_call_state);
+
+	afs_kafsasyncd_attend_op(op);
+
+	_leave("");
+
+} /* end afs_rxvl_get_entry_by_id_error() */
diff -Nru a/fs/afs/vlclient.h b/fs/afs/vlclient.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/vlclient.h	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,95 @@
+/* vlclient.h: Volume Location Service client interface
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_VLCLIENT_H
+#define _LINUX_AFS_VLCLIENT_H
+
+#include "types.h"
+
+enum AFSVL_Errors {
+	AFSVL_IDEXIST 		= 363520,	/* Volume Id entry exists in vl database */
+	AFSVL_IO 		= 363521,	/* I/O related error */
+	AFSVL_NAMEEXIST 	= 363522,	/* Volume name entry exists in vl database */
+	AFSVL_CREATEFAIL 	= 363523,	/* Internal creation failure */
+	AFSVL_NOENT 		= 363524,	/* No such entry */
+	AFSVL_EMPTY 		= 363525,	/* Vl database is empty */
+	AFSVL_ENTDELETED 	= 363526,	/* Entry is deleted (soft delete) */
+	AFSVL_BADNAME 		= 363527,	/* Volume name is illegal */
+	AFSVL_BADINDEX 		= 363528,	/* Index is out of range */
+	AFSVL_BADVOLTYPE 	= 363529,	/* Bad volume type */
+	AFSVL_BADSERVER 	= 363530,	/* Illegal server number (out of range) */
+	AFSVL_BADPARTITION 	= 363531,	/* Bad partition number */
+	AFSVL_REPSFULL 		= 363532,	/* Run out of space for Replication sites */
+	AFSVL_NOREPSERVER 	= 363533,	/* No such Replication server site exists */
+	AFSVL_DUPREPSERVER 	= 363534,	/* Replication site already exists */
+	AFSVL_RWNOTFOUND 	= 363535,	/* Parent R/W entry not found */
+	AFSVL_BADREFCOUNT 	= 363536,	/* Illegal Reference Count number */
+	AFSVL_SIZEEXCEEDED 	= 363537,	/* Vl size for attributes exceeded */
+	AFSVL_BADENTRY 		= 363538,	/* Bad incoming vl entry */
+	AFSVL_BADVOLIDBUMP 	= 363539,	/* Illegal max volid increment */
+	AFSVL_IDALREADYHASHED 	= 363540,	/* RO/BACK id already hashed */
+	AFSVL_ENTRYLOCKED 	= 363541,	/* Vl entry is already locked */
+	AFSVL_BADVOLOPER 	= 363542,	/* Bad volume operation code */
+	AFSVL_BADRELLOCKTYPE 	= 363543,	/* Bad release lock type */
+	AFSVL_RERELEASE 	= 363544,	/* Status report: last release was aborted */
+	AFSVL_BADSERVERFLAG 	= 363545,	/* Invalid replication site server °ag */
+	AFSVL_PERM 		= 363546,	/* No permission access */
+	AFSVL_NOMEM 		= 363547,	/* malloc/realloc failed to alloc enough memory */
+};
+
+/* maps to "struct vldbentry" in vvl-spec.pdf */
+struct  afsvl_dbentry {
+	char		name[65];		/* name of volume (including NUL char) */
+	afs_voltype_t	type;			/* volume type */
+	unsigned	num_servers;		/* num servers that hold instances of this vol */
+	unsigned	clone_id;		/* cloning ID */
+
+	unsigned	flags;
+#define AFS_VLF_RWEXISTS	0x1000		/* R/W volume exists */
+#define AFS_VLF_ROEXISTS	0x2000		/* R/O volume exists */
+#define AFS_VLF_BACKEXISTS	0x4000		/* backup volume exists */
+
+	afs_volid_t	volume_ids[3];		/* volume IDs */
+
+	struct {
+		struct in_addr	addr;		/* server address */
+		unsigned	partition;	/* partition ID on this server */
+		unsigned	flags;		/* server specific flags */
+#define AFS_VLSF_NEWREPSITE	0x0001	/* unused */
+#define AFS_VLSF_ROVOL		0x0002	/* this server holds a R/O instance of the volume */
+#define AFS_VLSF_RWVOL		0x0004	/* this server holds a R/W instance of the volume */
+#define AFS_VLSF_BACKVOL	0x0008	/* this server holds a backup instance of the volume */
+	} servers[8];
+
+};
+
+/* probe a volume location server to see if it is still alive */
+extern int afs_rxvl_probe(afs_server_t *server, int alloc_flags);
+
+/* look up a volume location database entry by name */
+extern int afs_rxvl_get_entry_by_name(afs_server_t *server,
+				      const char *volname,
+				      afsc_vldb_record_t *entry);
+
+/* look up a volume location database entry by ID */
+extern int afs_rxvl_get_entry_by_id(afs_server_t *server,
+				    afs_volid_t	volid,
+				    afs_voltype_t voltype,
+				    afsc_vldb_record_t *entry);
+
+extern int afs_rxvl_get_entry_by_id_async(afs_async_op_t *op,
+					  afs_volid_t volid,
+					  afs_voltype_t voltype);
+
+extern int afs_rxvl_get_entry_by_id_async2(afs_async_op_t *op,
+					   afsc_vldb_record_t *entry);
+
+#endif /* _LINUX_AFS_VLCLIENT_H */
diff -Nru a/fs/afs/vlocation.c b/fs/afs/vlocation.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/vlocation.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,824 @@
+/* vlocation.c: volume location management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "cell.h"
+#include "cmservice.h"
+#include "fsclient.h"
+#include "vlclient.h"
+#include "kafstimod.h"
+#include <rxrpc/connection.h>
+#include "internal.h"
+
+#define AFS_VLDB_TIMEOUT HZ*1000
+
+static void afs_vlocation_update_timer(afs_timer_t *timer);
+static void afs_vlocation_update_attend(afs_async_op_t *op);
+static void afs_vlocation_update_discard(afs_async_op_t *op);
+
+static void __afs_vlocation_timeout(afs_timer_t *timer)
+{
+	afs_vlocation_t *vlocation = list_entry(timer,afs_vlocation_t,timeout);
+
+	_debug("VL TIMEOUT [%s{u=%d}]",vlocation->vldb.name,atomic_read(&vlocation->usage));
+
+	afs_vlocation_do_timeout(vlocation);
+}
+
+static const struct afs_timer_ops afs_vlocation_timer_ops = {
+	.timed_out	= __afs_vlocation_timeout,
+};
+
+static const struct afs_timer_ops afs_vlocation_update_timer_ops = {
+	.timed_out	= afs_vlocation_update_timer,
+};
+
+static const struct afs_async_op_ops afs_vlocation_update_op_ops = {
+	.attend		= afs_vlocation_update_attend,
+	.discard	= afs_vlocation_update_discard,
+};
+
+static LIST_HEAD(afs_vlocation_update_pendq);	/* queue of VLs awaiting update */
+static afs_vlocation_t *afs_vlocation_update;	/* VL currently being updated */
+static spinlock_t afs_vlocation_update_lock = SPIN_LOCK_UNLOCKED; /* lock guarding update queue */
+
+/*****************************************************************************/
+/*
+ * iterate through the VL servers in a cell until one of them admits knowing about the volume in
+ * question
+ * - caller must have cell->vl_sem write-locked
+ */
+static int afs_vlocation_access_vl_by_name(afs_vlocation_t *vlocation,
+					   const char *name,
+					   afsc_vldb_record_t *vldb)
+{
+	afs_server_t *server = NULL;
+	afs_cell_t *cell = vlocation->cell;
+	int count, ret;
+
+	_enter("%s,%s,",cell->name,name);
+
+	ret = -ENOMEDIUM;
+	for (count=cell->vl_naddrs; count>0; count--) {
+		_debug("CellServ[%hu]: %08x",
+		       cell->vl_curr_svix,cell->vl_addrs[cell->vl_curr_svix].s_addr);
+
+		/* try and create a server */
+		ret = afs_server_lookup(cell,&cell->vl_addrs[cell->vl_curr_svix],&server);
+		switch (ret) {
+		case 0:
+			break;
+		case -ENOMEM:
+		case -ENONET:
+			goto out;
+		default:
+			goto rotate;
+		}
+
+		/* attempt to access the VL server */
+		ret = afs_rxvl_get_entry_by_name(server,name,vldb);
+		switch (ret) {
+		case 0:
+			afs_put_server(server);
+			goto out;
+		case -ENOMEM:
+		case -ENONET:
+		case -ENETUNREACH:
+		case -EHOSTUNREACH:
+		case -ECONNREFUSED:
+			down_write(&server->sem);
+			if (server->vlserver) {
+				rxrpc_put_connection(server->vlserver);
+				server->vlserver = NULL;
+			}
+			up_write(&server->sem);
+			afs_put_server(server);
+			if (ret==-ENOMEM || ret==-ENONET)
+				goto out;
+			goto rotate;
+		case -ENOMEDIUM:
+			afs_put_server(server);
+			goto out;
+		default:
+			afs_put_server(server);
+			ret = -ENOMEDIUM;
+			goto rotate;
+		}
+
+		/* rotate the server records upon lookup failure */
+	rotate:
+		cell->vl_curr_svix++;
+		cell->vl_curr_svix %= cell->vl_naddrs;
+	}
+
+ out:
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end afs_vlocation_access_vl_by_name() */
+
+/*****************************************************************************/
+/*
+ * iterate through the VL servers in a cell until one of them admits knowing about the volume in
+ * question
+ * - caller must have cell->vl_sem write-locked
+ */
+static int afs_vlocation_access_vl_by_id(afs_vlocation_t *vlocation,
+					 afs_volid_t volid,
+					 afs_voltype_t voltype,
+					 afsc_vldb_record_t *vldb)
+{
+	afs_server_t *server = NULL;
+	afs_cell_t *cell = vlocation->cell;
+	int count, ret;
+
+	_enter("%s,%x,%d,",cell->name,volid,voltype);
+
+	ret = -ENOMEDIUM;
+	for (count=cell->vl_naddrs; count>0; count--) {
+		_debug("CellServ[%hu]: %08x",
+		       cell->vl_curr_svix,cell->vl_addrs[cell->vl_curr_svix].s_addr);
+
+		/* try and create a server */
+		ret = afs_server_lookup(cell,&cell->vl_addrs[cell->vl_curr_svix],&server);
+		switch (ret) {
+		case 0:
+			break;
+		case -ENOMEM:
+		case -ENONET:
+			goto out;
+		default:
+			goto rotate;
+		}
+
+		/* attempt to access the VL server */
+		ret = afs_rxvl_get_entry_by_id(server,volid,voltype,vldb);
+		switch (ret) {
+		case 0:
+			afs_put_server(server);
+			goto out;
+		case -ENOMEM:
+		case -ENONET:
+		case -ENETUNREACH:
+		case -EHOSTUNREACH:
+		case -ECONNREFUSED:
+			down_write(&server->sem);
+			if (server->vlserver) {
+				rxrpc_put_connection(server->vlserver);
+				server->vlserver = NULL;
+			}
+			up_write(&server->sem);
+			afs_put_server(server);
+			if (ret==-ENOMEM || ret==-ENONET)
+				goto out;
+			goto rotate;
+		case -ENOMEDIUM:
+			afs_put_server(server);
+			goto out;
+		default:
+			afs_put_server(server);
+			ret = -ENOMEDIUM;
+			goto rotate;
+		}
+
+		/* rotate the server records upon lookup failure */
+	rotate:
+		cell->vl_curr_svix++;
+		cell->vl_curr_svix %= cell->vl_naddrs;
+	}
+
+ out:
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end afs_vlocation_access_vl_by_id() */
+
+/*****************************************************************************/
+/*
+ * lookup volume location
+ * - caller must have cell->vol_sem write-locked
+ * - iterate through the VL servers in a cell until one of them admits knowing about the volume in
+ *   question
+ * - lookup in the local cache if not able to find on the VL server
+ * - insert/update in the local cache if did get a VL response
+ */
+int afs_vlocation_lookup(afs_cell_t *cell, const char *name, afs_vlocation_t **_vlocation)
+{
+	afsc_vldb_record_t vldb;
+	struct list_head *_p;
+	afs_vlocation_t *vlocation;
+	afs_voltype_t voltype;
+	afs_volid_t vid;
+	int active = 0, ret;
+
+	_enter(",%s,%s,",cell->name,name);
+
+	if (strlen(name)>sizeof(vlocation->vldb.name)) {
+		_leave(" = -ENAMETOOLONG");
+		return -ENAMETOOLONG;
+	}
+
+	/* search the cell's active list first */
+	list_for_each(_p,&cell->vl_list) {
+		vlocation = list_entry(_p,afs_vlocation_t,link);
+		if (strncmp(vlocation->vldb.name,name,sizeof(vlocation->vldb.name))==0)
+			goto found_in_memory;
+	}
+
+	/* search the cell's graveyard list second */
+	spin_lock(&cell->vl_gylock);
+	list_for_each(_p,&cell->vl_graveyard) {
+		vlocation = list_entry(_p,afs_vlocation_t,link);
+		if (strncmp(vlocation->vldb.name,name,sizeof(vlocation->vldb.name))==0)
+			goto found_in_graveyard;
+	}
+	spin_unlock(&cell->vl_gylock);
+
+	/* not in the cell's in-memory lists - create a new record */
+	vlocation = kmalloc(sizeof(afs_vlocation_t),GFP_KERNEL);
+	if (!vlocation)
+		return -ENOMEM;
+
+	memset(vlocation,0,sizeof(afs_vlocation_t));
+	atomic_set(&vlocation->usage,1);
+	INIT_LIST_HEAD(&vlocation->link);
+	rwlock_init(&vlocation->lock);
+	strncpy(vlocation->vldb.name,name,sizeof(vlocation->vldb.name));
+
+	afs_timer_init(&vlocation->timeout,&afs_vlocation_timer_ops);
+	afs_timer_init(&vlocation->upd_timer,&afs_vlocation_update_timer_ops);
+	afs_async_op_init(&vlocation->upd_op,&afs_vlocation_update_op_ops);
+
+	INIT_LIST_HEAD(&vlocation->caches);
+
+	afs_get_cell(cell);
+	vlocation->cell = cell;
+
+	list_add_tail(&vlocation->link,&cell->vl_list);
+
+#if 0
+	/* search local cache if wasn't in memory */
+	ret = afsc_lookup_vlocation(vlocation);
+	switch (ret) {
+	default:	goto error;		/* disk error */
+	case 0:		goto found_in_cache;	/* pulled from local cache into memory */
+	case -ENOENT:	break;			/* not in local cache */
+	}
+#endif
+
+	/* try to look up an unknown volume in the cell VL databases by name */
+	ret = afs_vlocation_access_vl_by_name(vlocation,name,&vldb);
+	if (ret<0) {
+		printk("kAFS: failed to locate '%s' in cell '%s'\n",name,cell->name);
+		goto error;
+	}
+
+	goto found_on_vlserver;
+
+ found_in_graveyard:
+	/* found in the graveyard - resurrect */
+	_debug("found in graveyard");
+	atomic_inc(&vlocation->usage);
+	list_del(&vlocation->link);
+	list_add_tail(&vlocation->link,&cell->vl_list);
+	spin_unlock(&cell->vl_gylock);
+
+	afs_kafstimod_del_timer(&vlocation->timeout);
+	goto active;
+
+ found_in_memory:
+	/* found in memory - check to see if it's active */
+	_debug("found in memory");
+	atomic_inc(&vlocation->usage);
+
+ active:
+	active = 1;
+
+/* found_in_cache: */
+	/* try to look up a cached volume in the cell VL databases by ID */
+	_debug("found in cache");
+
+	_debug("Locally Cached: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",
+	       vlocation->vldb.name,
+	       vlocation->vldb.vidmask,
+	       ntohl(vlocation->vldb.servers[0].s_addr),vlocation->vldb.srvtmask[0],
+	       ntohl(vlocation->vldb.servers[1].s_addr),vlocation->vldb.srvtmask[1],
+	       ntohl(vlocation->vldb.servers[2].s_addr),vlocation->vldb.srvtmask[2]
+	       );
+
+	_debug("Vids: %08x %08x %08x",
+	       vlocation->vldb.vid[0],vlocation->vldb.vid[1],vlocation->vldb.vid[2]);
+
+	if (vlocation->vldb.vidmask & AFSC_VOL_STM_RW) {
+		vid = vlocation->vldb.vid[0];
+		voltype = AFSVL_RWVOL;
+	}
+	else if (vlocation->vldb.vidmask & AFSC_VOL_STM_RO) {
+		vid = vlocation->vldb.vid[1];
+		voltype = AFSVL_ROVOL;
+	}
+	else if (vlocation->vldb.vidmask & AFSC_VOL_STM_BAK) {
+		vid = vlocation->vldb.vid[2];
+		voltype = AFSVL_BACKVOL;
+	}
+	else {
+		BUG();
+		vid = 0;
+		voltype = 0;
+	}
+
+	ret = afs_vlocation_access_vl_by_id(vlocation,vid,voltype,&vldb);
+	switch (ret) {
+		/* net error */
+	default:
+		printk("kAFS: failed to volume '%s' (%x) up in '%s': %d\n",
+		       name,vid,cell->name,ret);
+		goto error;
+
+		/* pulled from local cache into memory */
+	case 0:	
+		goto found_on_vlserver;
+
+		/* uh oh... looks like the volume got deleted */
+	case -ENOMEDIUM:
+		printk("kAFS: volume '%s' (%x) does not exist '%s'\n",name,vid,cell->name);
+
+		/* TODO: make existing record unavailable */
+		goto error;
+	}
+
+ found_on_vlserver:
+	_debug("Done VL Lookup: %s %02x { %08x(%x) %08x(%x) %08x(%x) }",
+	       name,
+	       vldb.vidmask,
+	       ntohl(vldb.servers[0].s_addr),vldb.srvtmask[0],
+	       ntohl(vldb.servers[1].s_addr),vldb.srvtmask[1],
+	       ntohl(vldb.servers[2].s_addr),vldb.srvtmask[2]
+	       );
+
+	_debug("Vids: %08x %08x %08x",vldb.vid[0],vldb.vid[1],vldb.vid[2]);
+
+	if (strncmp(vldb.name,name,sizeof(vlocation->vldb.name))!=0)
+		printk("kAFS: name of volume '%s' changed to '%s' on server\n",name,vldb.name);
+
+	memcpy(&vlocation->vldb,&vldb,sizeof(vlocation->vldb));
+
+#if 0
+	/* add volume entry to local cache */
+	ret = afsc_update_vlocation(vlocation);
+	if (ret<0)
+		goto error;
+#endif
+
+	afs_kafstimod_add_timer(&vlocation->upd_timer,10*HZ);
+
+	*_vlocation = vlocation;
+	_leave(" = 0 (%p)",vlocation);
+	return 0;
+
+ error:
+	if (vlocation) {
+		if (active) {
+			__afs_put_vlocation(vlocation);
+		}
+		else {
+			list_del(&vlocation->link);
+			afs_put_cell(vlocation->cell);
+#if 0
+			afs_put_cache(vlocation->cache);
+#endif
+			kfree(vlocation);
+		}
+	}
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_vlocation_lookup() */
+
+/*****************************************************************************/
+/*
+ * finish using a volume location record
+ * - caller must have cell->vol_sem write-locked
+ */
+void __afs_put_vlocation(afs_vlocation_t *vlocation)
+{
+	afs_cell_t *cell = vlocation->cell;
+
+	_enter("%s",vlocation->vldb.name);
+
+	/* sanity check */
+	if (atomic_read(&vlocation->usage)<=0)
+		BUG();
+
+	spin_lock(&cell->vl_gylock);
+	if (likely(!atomic_dec_and_test(&vlocation->usage))) {
+		spin_unlock(&cell->vl_gylock);
+		_leave("");
+		return;
+	}
+
+	/* move to graveyard queue */
+	list_del(&vlocation->link);
+	list_add_tail(&vlocation->link,&cell->vl_graveyard);
+
+	/* remove from pending timeout queue (refcounted if actually being updated) */
+	list_del_init(&vlocation->upd_op.link);
+
+	/* time out in 10 secs */
+	afs_kafstimod_del_timer(&vlocation->upd_timer);
+	afs_kafstimod_add_timer(&vlocation->timeout,10*HZ);
+
+	spin_unlock(&cell->vl_gylock);
+
+	_leave(" [killed]");
+} /* end __afs_put_vlocation() */
+
+/*****************************************************************************/
+/*
+ * finish using a volume location record
+ */
+void afs_put_vlocation(afs_vlocation_t *vlocation)
+{
+	afs_cell_t *cell = vlocation->cell;
+
+	down_write(&cell->vl_sem);
+	__afs_put_vlocation(vlocation);
+	up_write(&cell->vl_sem);
+} /* end afs_put_vlocation() */
+
+/*****************************************************************************/
+/*
+ * timeout vlocation record
+ * - removes from the cell's graveyard if the usage count is zero
+ */
+void afs_vlocation_do_timeout(afs_vlocation_t *vlocation)
+{
+	afs_cell_t *cell;
+
+	_enter("%s",vlocation->vldb.name);
+
+	cell = vlocation->cell;
+
+	if (atomic_read(&vlocation->usage)<0) BUG();
+
+	/* remove from graveyard if still dead */
+	spin_lock(&cell->vl_gylock);
+	if (atomic_read(&vlocation->usage)==0)
+		list_del_init(&vlocation->link);
+	else
+		vlocation = NULL;
+	spin_unlock(&cell->vl_gylock);
+
+	if (!vlocation) {
+		_leave("");
+		return; /* resurrected */
+	}
+
+	/* we can now destroy it properly */
+	afs_put_cell(cell);
+#if 0
+	afs_put_cache(vlocation->cache);
+#endif
+
+	kfree(vlocation);
+
+	_leave(" [destroyed]");
+} /* end afs_vlocation_do_timeout() */
+
+/*****************************************************************************/
+/*
+ * send an update operation to the currently selected server
+ */
+static int afs_vlocation_update_begin(afs_vlocation_t *vlocation)
+{
+	afs_voltype_t voltype;
+	afs_volid_t vid;
+	int ret;
+
+	_enter("%s{ufs=%u ucs=%u}",
+	       vlocation->vldb.name,vlocation->upd_first_svix,vlocation->upd_curr_svix);
+
+	/* try to look up a cached volume in the cell VL databases by ID */
+	if (vlocation->vldb.vidmask & AFSC_VOL_STM_RW) {
+		vid = vlocation->vldb.vid[0];
+		voltype = AFSVL_RWVOL;
+	}
+	else if (vlocation->vldb.vidmask & AFSC_VOL_STM_RO) {
+		vid = vlocation->vldb.vid[1];
+		voltype = AFSVL_ROVOL;
+	}
+	else if (vlocation->vldb.vidmask & AFSC_VOL_STM_BAK) {
+		vid = vlocation->vldb.vid[2];
+		voltype = AFSVL_BACKVOL;
+	}
+	else {
+		BUG();
+		vid = 0;
+		voltype = 0;
+	}
+
+	/* contact the chosen server */
+	ret = afs_server_lookup(vlocation->cell,
+				&vlocation->cell->vl_addrs[vlocation->upd_curr_svix],
+				&vlocation->upd_op.server);
+	switch (ret) {
+	case 0:
+		break;
+	case -ENOMEM:
+	case -ENONET:
+	default:
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	/* initiate the update operation */
+	ret = afs_rxvl_get_entry_by_id_async(&vlocation->upd_op,vid,voltype);
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_vlocation_update_begin() */
+
+/*****************************************************************************/
+/*
+ * abandon updating a VL record
+ * - does not restart the update timer
+ */
+static void afs_vlocation_update_abandon(afs_vlocation_t *vlocation,
+					 afs_vlocation_upd_t state,
+					 int ret)
+{
+	_enter("%s,%u",vlocation->vldb.name,state);
+
+	if (ret<0)
+		printk("kAFS: Abandoning VL update '%s': %d\n",vlocation->vldb.name,ret);
+
+	/* discard the server record */
+	if (vlocation->upd_op.server) {
+		afs_put_server(vlocation->upd_op.server);
+		vlocation->upd_op.server = NULL;
+	}
+
+	spin_lock(&afs_vlocation_update_lock);
+	afs_vlocation_update = NULL;
+	vlocation->upd_state = state;
+
+	/* TODO: start updating next VL record on pending list */
+
+	spin_unlock(&afs_vlocation_update_lock);
+
+	_leave("");
+} /* end afs_vlocation_update_abandon() */
+
+/*****************************************************************************/
+/*
+ * handle periodic update timeouts and busy retry timeouts
+ * - called from kafstimod
+ */
+static void afs_vlocation_update_timer(afs_timer_t *timer)
+{
+	afs_vlocation_t *vlocation = list_entry(timer,afs_vlocation_t,upd_timer);
+	int ret;
+
+	_enter("%s",vlocation->vldb.name);
+
+	/* only update if not in the graveyard (defend against putting too) */
+	spin_lock(&vlocation->cell->vl_gylock);
+
+	if (!atomic_read(&vlocation->usage))
+		goto out_unlock1;
+
+	spin_lock(&afs_vlocation_update_lock);
+
+	/* if we were woken up due to EBUSY sleep then restart immediately if possible or else jump
+	 * to front of pending queue */
+	if (vlocation->upd_state==AFS_VLUPD_BUSYSLEEP) {
+		if (afs_vlocation_update) {
+			list_add(&vlocation->upd_op.link,&afs_vlocation_update_pendq);
+		}
+		else {
+			afs_get_vlocation(vlocation);
+			afs_vlocation_update = vlocation;
+			vlocation->upd_state = AFS_VLUPD_INPROGRESS;
+		}
+		goto out_unlock2;
+	}
+
+	/* put on pending queue if there's already another update in progress */
+	if (afs_vlocation_update) {
+		vlocation->upd_state = AFS_VLUPD_PENDING;
+		list_add_tail(&vlocation->upd_op.link,&afs_vlocation_update_pendq);
+		goto out_unlock2;
+	}
+
+	/* hold a ref on it while actually updating */
+	afs_get_vlocation(vlocation);
+	afs_vlocation_update = vlocation;
+	vlocation->upd_state = AFS_VLUPD_INPROGRESS;
+
+	spin_unlock(&afs_vlocation_update_lock);
+	spin_unlock(&vlocation->cell->vl_gylock);
+
+	/* okay... we can start the update */
+	_debug("BEGIN VL UPDATE [%s]",vlocation->vldb.name);
+	vlocation->upd_first_svix = vlocation->cell->vl_curr_svix;
+	vlocation->upd_curr_svix = vlocation->upd_first_svix;
+	vlocation->upd_rej_cnt = 0;
+	vlocation->upd_busy_cnt = 0;
+
+	ret = afs_vlocation_update_begin(vlocation);
+	if (ret<0) {
+		afs_vlocation_update_abandon(vlocation,AFS_VLUPD_SLEEP,ret);
+		afs_kafstimod_add_timer(&vlocation->upd_timer,AFS_VLDB_TIMEOUT);
+		afs_put_vlocation(vlocation);
+	}
+
+	_leave("");
+	return;
+
+ out_unlock2:
+	spin_unlock(&afs_vlocation_update_lock);
+ out_unlock1:
+	spin_unlock(&vlocation->cell->vl_gylock);
+	_leave("");
+	return;
+
+} /* end afs_vlocation_update_timer() */
+
+/*****************************************************************************/
+/*
+ * attend to an update operation upon which an event happened
+ * - called in kafsasyncd context
+ */
+static void afs_vlocation_update_attend(afs_async_op_t *op)
+{
+	afsc_vldb_record_t vldb;
+	afs_vlocation_t *vlocation = list_entry(op,afs_vlocation_t,upd_op);
+	unsigned tmp;
+	int ret;
+
+	_enter("%s",vlocation->vldb.name);
+
+	ret = afs_rxvl_get_entry_by_id_async2(op,&vldb);
+	switch (ret) {
+	case -EAGAIN:
+		_leave(" [unfinished]");
+		return;
+
+	case 0:
+		_debug("END VL UPDATE: %d\n",ret);
+		vlocation->valid = 1;
+
+		_debug("Done VL Lookup: %02x { %08x(%x) %08x(%x) %08x(%x) }",
+		       vldb.vidmask,
+		       ntohl(vldb.servers[0].s_addr),vldb.srvtmask[0],
+		       ntohl(vldb.servers[1].s_addr),vldb.srvtmask[1],
+		       ntohl(vldb.servers[2].s_addr),vldb.srvtmask[2]
+		       );
+
+		_debug("Vids: %08x %08x %08x",vldb.vid[0],vldb.vid[1],vldb.vid[2]);
+
+		afs_vlocation_update_abandon(vlocation,AFS_VLUPD_SLEEP,0);
+
+		down_write(&vlocation->cell->vl_sem);
+
+		/* actually update the cache */
+		if (strncmp(vldb.name,vlocation->vldb.name,sizeof(vlocation->vldb.name))!=0)
+			printk("kAFS: name of volume '%s' changed to '%s' on server\n",
+			       vlocation->vldb.name,vldb.name);
+
+		memcpy(&vlocation->vldb,&vldb,sizeof(vlocation->vldb));
+
+#if 0
+		/* add volume entry to local cache */
+		ret = afsc_update_vlocation(vlocation);
+#endif
+
+		up_write(&vlocation->cell->vl_sem);
+
+		if (ret<0)
+			printk("kAFS: failed to update local cache: %d\n",ret);
+
+		afs_kafstimod_add_timer(&vlocation->upd_timer,AFS_VLDB_TIMEOUT);
+		afs_put_vlocation(vlocation);
+		_leave(" [found]");
+		return;
+
+	case -ENOMEDIUM:
+		vlocation->upd_rej_cnt++;
+		goto try_next;
+
+		/* the server is locked - retry in a very short while */
+	case -EBUSY:
+		vlocation->upd_busy_cnt++;
+		if (vlocation->upd_busy_cnt>3)
+			goto try_next; /* too many retries */
+
+		afs_vlocation_update_abandon(vlocation,AFS_VLUPD_BUSYSLEEP,0);
+		afs_kafstimod_add_timer(&vlocation->upd_timer,HZ/2);
+		afs_put_vlocation(vlocation);
+		_leave(" [busy]");
+		return;
+
+	case -ENETUNREACH:
+	case -EHOSTUNREACH:
+	case -ECONNREFUSED:
+	case -EREMOTEIO:
+		/* record bad vlserver info in the cell too
+		 * - TODO: use down_write_trylock() if available
+		 */
+		if (vlocation->upd_curr_svix == vlocation->cell->vl_curr_svix)
+			vlocation->cell->vl_curr_svix =
+				vlocation->cell->vl_curr_svix % vlocation->cell->vl_naddrs;
+
+	case -EBADRQC:
+	case -EINVAL:
+	case -EACCES:
+	case -EBADMSG:
+		goto try_next;
+
+	default:
+		goto abandon;
+	}
+
+	/* try contacting the next server */
+ try_next:
+	vlocation->upd_busy_cnt = 0;
+
+	if (vlocation->upd_op.server) {
+		/* discard the server record */
+		afs_put_server(vlocation->upd_op.server);
+		vlocation->upd_op.server = NULL;
+	}
+
+	tmp = vlocation->cell->vl_naddrs;
+	if (tmp==0)
+		goto abandon;
+
+	vlocation->upd_curr_svix++;
+	if (vlocation->upd_curr_svix >= tmp) vlocation->upd_curr_svix = 0;
+	if (vlocation->upd_first_svix >= tmp) vlocation->upd_first_svix = tmp - 1;
+
+	/* move to the next server */
+	if (vlocation->upd_curr_svix!=vlocation->upd_first_svix) {
+		afs_vlocation_update_begin(vlocation);
+		_leave(" [next]");
+		return;
+	}
+
+	/* run out of servers to try - was the volume rejected? */
+	if (vlocation->upd_rej_cnt>0) {
+		printk("kAFS: Active volume no longer valid '%s'\n",vlocation->vldb.name);
+		vlocation->valid = 0;
+		afs_vlocation_update_abandon(vlocation,AFS_VLUPD_SLEEP,0);
+		afs_kafstimod_add_timer(&vlocation->upd_timer,AFS_VLDB_TIMEOUT);
+		afs_put_vlocation(vlocation);
+		_leave(" [invalidated]");
+		return;
+	}
+
+	/* abandon the update */
+ abandon:
+	afs_vlocation_update_abandon(vlocation,AFS_VLUPD_SLEEP,ret);
+	afs_kafstimod_add_timer(&vlocation->upd_timer,HZ*10);
+	afs_put_vlocation(vlocation);
+	_leave(" [abandoned]");
+
+} /* end afs_vlocation_update_attend() */
+
+/*****************************************************************************/
+/*
+ * deal with an update operation being discarded
+ * - called in kafsasyncd context when it's dying due to rmmod
+ * - the call has already been aborted and put()'d
+ */
+static void afs_vlocation_update_discard(afs_async_op_t *op)
+{
+	afs_vlocation_t *vlocation = list_entry(op,afs_vlocation_t,upd_op);
+
+	_enter("%s",vlocation->vldb.name);
+
+	afs_put_server(op->server);
+	op->server = NULL;
+
+	afs_put_vlocation(vlocation);
+
+	_leave("");
+} /* end afs_vlocation_update_discard() */
diff -Nru a/fs/afs/vnode.c b/fs/afs/vnode.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/vnode.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,316 @@
+/* vnode.c: AFS vnode management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "cell.h"
+#include "cmservice.h"
+#include "fsclient.h"
+#include "vlclient.h"
+#include "vnode.h"
+#include "internal.h"
+
+static void afs_vnode_cb_timed_out(struct afs_timer *timer);
+
+struct afs_timer_ops afs_vnode_cb_timed_out_ops = {
+	.timed_out	= afs_vnode_cb_timed_out,
+};
+
+/*****************************************************************************/
+/*
+ * handle a callback timing out
+ * TODO: retain a ref to vnode struct for an outstanding callback timeout
+ */
+static void afs_vnode_cb_timed_out(struct afs_timer *timer)
+{
+	afs_server_t *oldserver;
+	afs_vnode_t *vnode;
+
+	vnode = list_entry(timer,afs_vnode_t,cb_timeout);
+
+	_enter("%p",vnode);
+
+	/* set the changed flag in the vnode and release the server */
+	spin_lock(&vnode->lock);
+
+	oldserver = xchg(&vnode->cb_server,NULL);
+	if (oldserver) {
+		vnode->flags |= AFS_VNODE_CHANGED;
+
+		spin_lock(&afs_cb_hash_lock);
+		list_del_init(&vnode->cb_hash_link);
+		spin_unlock(&afs_cb_hash_lock);
+
+		spin_lock(&oldserver->cb_lock);
+		list_del_init(&vnode->cb_link);
+		spin_unlock(&oldserver->cb_lock);
+	}
+
+	spin_unlock(&vnode->lock);
+
+	if (oldserver)
+		afs_put_server(oldserver);
+
+	_leave("");
+} /* end afs_vnode_cb_timed_out() */
+
+/*****************************************************************************/
+/*
+ * finish off updating the recorded status of a file
+ * - starts callback expiry timer
+ * - adds to server's callback list
+ */
+void afs_vnode_finalise_status_update(afs_vnode_t *vnode, afs_server_t *server, int ret)
+{
+	afs_server_t *oldserver = NULL;
+
+	_enter("%p,%p,%d",vnode,server,ret);
+
+	spin_lock(&vnode->lock);
+
+	vnode->flags &= ~AFS_VNODE_CHANGED;
+
+	if (ret==0) {
+		/* adjust the callback timeout appropriately */
+		afs_kafstimod_add_timer(&vnode->cb_timeout,vnode->cb_expiry*HZ);
+
+		spin_lock(&afs_cb_hash_lock);
+		list_del(&vnode->cb_hash_link);
+		list_add_tail(&vnode->cb_hash_link,&afs_cb_hash(server,&vnode->fid));
+		spin_unlock(&afs_cb_hash_lock);
+
+		/* swap ref to old callback server with that for new callback server */
+		oldserver = xchg(&vnode->cb_server,server);
+		if (oldserver!=server) {
+			if (oldserver) {
+				spin_lock(&oldserver->cb_lock);
+				list_del_init(&vnode->cb_link);
+				spin_unlock(&oldserver->cb_lock);
+			}
+
+			afs_get_server(server);
+			spin_lock(&server->cb_lock);
+			list_add_tail(&vnode->cb_link,&server->cb_promises);
+			spin_unlock(&server->cb_lock);
+		}
+		else {
+			/* same server */
+			oldserver = NULL;
+		}
+	}
+	else if (ret==-ENOENT) {
+		/* the file was deleted - clear the callback timeout */
+		oldserver = xchg(&vnode->cb_server,NULL);
+		afs_kafstimod_del_timer(&vnode->cb_timeout);
+
+		_debug("got NOENT from server - marking file deleted");
+		vnode->flags |= AFS_VNODE_DELETED;
+	}
+
+	vnode->update_cnt--;
+
+	spin_unlock(&vnode->lock);
+
+	wake_up_all(&vnode->update_waitq);
+
+	if (oldserver)
+		afs_put_server(oldserver);
+
+	_leave("");
+
+} /* end afs_vnode_finalise_status_update() */
+
+/*****************************************************************************/
+/*
+ * fetch file status from the volume
+ * - don't issue a fetch if:
+ *   - the changed bit is not set and there's a valid callback
+ *   - there are any outstanding ops that will fetch the status
+ * - TODO implement local caching
+ */
+int afs_vnode_fetch_status(afs_vnode_t *vnode)
+{
+	afs_server_t *server;
+	int ret;
+
+	DECLARE_WAITQUEUE(myself,current);
+
+	_enter("%s,{%u,%u,%u}",vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,vnode->fid.vnode,vnode->fid.unique);
+
+	if (!(vnode->flags & AFS_VNODE_CHANGED) && vnode->cb_server) {
+		_leave(" [unchanged]");
+		return 0;
+	}
+
+	if (vnode->flags & AFS_VNODE_DELETED) {
+		_leave(" [deleted]");
+		return -ENOENT;
+	}
+
+	spin_lock(&vnode->lock);
+
+	if (!(vnode->flags & AFS_VNODE_CHANGED)) {
+		spin_unlock(&vnode->lock);
+		_leave(" [unchanged]");
+		return 0;
+	}
+
+	if (vnode->update_cnt>0) {
+		/* someone else started a fetch */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&vnode->update_waitq,&myself);
+
+		/* wait for the status to be updated */
+		for (;;) {
+			if (!(vnode->flags & AFS_VNODE_CHANGED))	break;
+			if (vnode->flags & AFS_VNODE_DELETED)		break;
+
+			/* it got updated and invalidated all before we saw it */
+			if (vnode->update_cnt==0) {
+				remove_wait_queue(&vnode->update_waitq,&myself);
+				set_current_state(TASK_RUNNING);
+				goto get_anyway;
+			}
+
+			spin_unlock(&vnode->lock);
+
+			schedule();
+			set_current_state(TASK_UNINTERRUPTIBLE);
+
+			spin_lock(&vnode->lock);
+		}
+
+		remove_wait_queue(&vnode->update_waitq,&myself);
+		spin_unlock(&vnode->lock);
+		set_current_state(TASK_RUNNING);
+
+		return vnode->flags & AFS_VNODE_DELETED ? -ENOENT : 0;
+	}
+
+ get_anyway:
+	/* okay... we're going to have to initiate the op */
+	vnode->update_cnt++;
+
+	spin_unlock(&vnode->lock);
+
+	/* merge AFS status fetches and clear outstanding callback on this vnode */
+	do {
+		/* pick a server to query */
+		ret = afs_volume_pick_fileserver(vnode->volume,&server);
+		if (ret<0)
+			return ret;
+
+		_debug("USING SERVER: %08x\n",ntohl(server->addr.s_addr));
+
+		ret = afs_rxfs_fetch_file_status(server,vnode,NULL);
+
+	} while (!afs_volume_release_fileserver(vnode->volume,server,ret));
+
+	/* adjust the flags */
+	afs_vnode_finalise_status_update(vnode,server,ret);
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_vnode_fetch_status() */
+
+/*****************************************************************************/
+/*
+ * fetch file data from the volume
+ * - TODO implement caching and server failover
+ */
+int afs_vnode_fetch_data(afs_vnode_t *vnode, struct afs_rxfs_fetch_descriptor *desc)
+{
+	afs_server_t *server;
+	int ret;
+
+	_enter("%s,{%u,%u,%u}",
+	       vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,
+	       vnode->fid.vnode,
+	       vnode->fid.unique);
+
+	/* this op will fetch the status */
+	spin_lock(&vnode->lock);
+	vnode->update_cnt++;
+	spin_unlock(&vnode->lock);
+
+	/* merge in AFS status fetches and clear outstanding callback on this vnode */
+	do {
+		/* pick a server to query */
+		ret = afs_volume_pick_fileserver(vnode->volume,&server);
+		if (ret<0)
+			return ret;
+
+		_debug("USING SERVER: %08x\n",ntohl(server->addr.s_addr));
+
+		ret = afs_rxfs_fetch_file_data(server,vnode,desc,NULL);
+
+	} while (!afs_volume_release_fileserver(vnode->volume,server,ret));
+
+	/* adjust the flags */
+	afs_vnode_finalise_status_update(vnode,server,ret);
+
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end afs_vnode_fetch_data() */
+
+/*****************************************************************************/
+/*
+ * break any outstanding callback on a vnode
+ * - only relevent to server that issued it
+ */
+int afs_vnode_give_up_callback(afs_vnode_t *vnode)
+{
+	afs_server_t *server;
+	int ret;
+
+	_enter("%s,{%u,%u,%u}",
+	       vnode->volume->vlocation->vldb.name,
+	       vnode->fid.vid,
+	       vnode->fid.vnode,
+	       vnode->fid.unique);
+
+	spin_lock(&afs_cb_hash_lock);
+	list_del_init(&vnode->cb_hash_link);
+	spin_unlock(&afs_cb_hash_lock);
+
+	/* set the changed flag in the vnode and release the server */
+	spin_lock(&vnode->lock);
+
+	afs_kafstimod_del_timer(&vnode->cb_timeout);
+
+	server = xchg(&vnode->cb_server,NULL);
+	if (server) {
+		vnode->flags |= AFS_VNODE_CHANGED;
+
+		spin_lock(&server->cb_lock);
+		list_del_init(&vnode->cb_link);
+		spin_unlock(&server->cb_lock);
+	}
+
+	spin_unlock(&vnode->lock);
+
+	ret = 0;
+	if (server) {
+		ret = afs_rxfs_give_up_callback(server,vnode);
+		afs_put_server(server);
+	}
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_vnode_give_up_callback() */
diff -Nru a/fs/afs/vnode.h b/fs/afs/vnode.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/vnode.h	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,88 @@
+/* vnode.h: AFS vnode record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_VNODE_H
+#define _LINUX_AFS_VNODE_H
+
+#include <linux/fs.h>
+#include <linux/version.h>
+#include "server.h"
+#include "kafstimod.h"
+
+#ifdef __KERNEL__
+
+struct afs_rxfs_fetch_descriptor;
+
+/*****************************************************************************/
+/*
+ * AFS inode private data
+ */
+struct afs_vnode
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	struct inode		vfs_inode;	/* the VFS's inode record */
+#else
+	struct inode		*inode;		/* the VFS's inode */
+#endif
+
+	afs_volume_t		*volume;	/* volume on which vnode resides */
+	afs_fid_t		fid;		/* the file identifier for this inode */
+	afs_file_status_t	status;		/* AFS status info for this file */
+	unsigned		nix;		/* vnode index in cache */
+
+	wait_queue_head_t	update_waitq;	/* status fetch waitqueue */
+	unsigned		update_cnt;	/* number of outstanding ops that will update the
+						 * status */
+	spinlock_t		lock;		/* waitqueue/flags lock */
+	unsigned		flags;
+#define AFS_VNODE_CHANGED	0x00000001	/* set if vnode reported changed by callback */
+#define AFS_VNODE_DELETED	0x00000002	/* set if vnode deleted on server */
+#define AFS_VNODE_MOUNTPOINT	0x00000004	/* set if vnode is a mountpoint symlink */
+
+	/* outstanding callback notification on this file */
+	afs_server_t		*cb_server;	/* server that made the current promise */
+	struct list_head	cb_link;	/* link in server's promises list */
+	struct list_head	cb_hash_link;	/* link in master callback hash */
+	afs_timer_t		cb_timeout;	/* timeout on promise */
+	unsigned		cb_version;	/* callback version */
+	unsigned		cb_expiry;	/* callback expiry time */
+	afs_callback_type_t	cb_type;	/* type of callback */
+};
+
+static inline afs_vnode_t *AFS_FS_I(struct inode *inode)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	return list_entry(inode,afs_vnode_t,vfs_inode);
+#else
+	return inode->u.generic_ip;
+#endif
+}
+
+static inline struct inode *AFS_VNODE_TO_I(afs_vnode_t *vnode)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	return &vnode->vfs_inode;
+#else
+	return vnode->inode;
+#endif
+}
+
+extern int afs_vnode_fetch_status(afs_vnode_t *vnode);
+
+extern int afs_vnode_fetch_data(afs_vnode_t *vnode, struct afs_rxfs_fetch_descriptor *desc);
+
+extern int afs_vnode_give_up_callback(afs_vnode_t *vnode);
+
+extern struct afs_timer_ops afs_vnode_cb_timed_out_ops;
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_AFS_VNODE_H */
diff -Nru a/fs/afs/volume.c b/fs/afs/volume.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/volume.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,430 @@
+/* volume.c: AFS volume management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include "volume.h"
+#include "cell.h"
+#include "cmservice.h"
+#include "fsclient.h"
+#include "vlclient.h"
+#include "internal.h"
+
+const char *afs_voltypes[] = { "R/W", "R/O", "BAK" };
+
+/*****************************************************************************/
+/*
+ * lookup a volume by name
+ * - this can be one of the following:
+ *	"%[cell:]volume[.]"		R/W volume
+ *	"#[cell:]volume[.]"		R/O or R/W volume (rwparent=0), or R/W (rwparent=1) volume
+ *	"%[cell:]volume.readonly"	R/O volume
+ *	"#[cell:]volume.readonly"	R/O volume
+ *	"%[cell:]volume.backup"		Backup volume
+ *	"#[cell:]volume.backup"		Backup volume
+ *
+ * The cell name is optional, and defaults to the current cell.
+ *
+ * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin Guide
+ * - Rule 1: Explicit type suffix forces access of that type or nothing
+ *           (no suffix, then use Rule 2 & 3)
+ * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W if not available
+ * - Rule 3: If parent volume is R/W, then only mount R/W volume unless explicitly told otherwise
+ */
+int afs_volume_lookup(char *name, int rwparent, afs_volume_t **_volume)
+{
+	afs_vlocation_t *vlocation = NULL;
+	afs_voltype_t type;
+	afs_volume_t *volume = NULL;
+	afs_cell_t *cell = NULL;
+	char *cellname, *volname, *suffix;
+	char srvtmask;
+	int force, ret, loop;
+
+	_enter(",%s,",name);
+
+	if (!name || (name[0]!='%' && name[0]!='#') || !name[1]) {
+		printk("kAFS: unparsable volume name\n");
+		return -EINVAL;
+	}
+
+	/* determine the type of volume we're looking for */
+	force = 0;
+	type = AFSVL_ROVOL;
+
+	if (rwparent || name[0]=='%') {
+		type = AFSVL_RWVOL;
+		force = 1;
+	}
+
+	suffix = strrchr(name,'.');
+	if (suffix) {
+		if (strcmp(suffix,".readonly")==0) {
+			type = AFSVL_ROVOL;
+			force = 1;
+		}
+		else if (strcmp(suffix,".backup")==0) {
+			type = AFSVL_BACKVOL;
+			force = 1;
+		}
+		else if (suffix[1]==0) {
+			*suffix = 0;
+			suffix = NULL;
+		}
+		else {
+			suffix = NULL;
+		}
+	}
+
+	/* split the cell and volume names */
+	name++;
+	volname = strchr(name,':');
+	if (volname) {
+		*volname++ = 0;
+		cellname = name;
+	}
+	else {
+		volname = name;
+		cellname = NULL;
+	}
+
+	_debug("CELL:%s VOLUME:%s SUFFIX:%s TYPE:%d%s",
+	       cellname,volname,suffix?:"-",type,force?" FORCE":"");
+
+	/* lookup the cell record */
+	ret = afs_cell_lookup(cellname,&cell);
+	if (ret<0)
+		printk("kAFS: unable to lookup cell '%s'\n",cellname?:"");
+
+	if (cellname) volname[-1] = ':';
+	if (ret<0)
+		goto error;
+
+	/* lookup the volume location record */
+	if (suffix) *suffix = 0;
+	ret = afs_vlocation_lookup(cell,volname,&vlocation);
+	if (suffix) *suffix = '.';
+	if (ret<0)
+		goto error;
+
+	/* make the final decision on the type we want */
+	ret = -ENOMEDIUM;
+	if (force && !(vlocation->vldb.vidmask & (1<<type)))
+		goto error;
+
+	srvtmask = 0;
+	for (loop=0; loop<vlocation->vldb.nservers; loop++)
+		srvtmask |= vlocation->vldb.srvtmask[loop];
+
+	if (force) {
+		if (!(srvtmask & (1 <<type)))
+			goto error;
+	}
+	else if (srvtmask & AFSC_VOL_STM_RO) {
+		type = AFSVL_ROVOL;
+	}
+	else if (srvtmask & AFSC_VOL_STM_RW) {
+		type = AFSVL_RWVOL;
+	}
+	else {
+		goto error;
+	}
+
+	down_write(&cell->vl_sem);
+
+	/* is the volume already active? */
+	if (vlocation->vols[type]) {
+		/* yes - re-use it */
+		volume = vlocation->vols[type];
+		afs_get_volume(volume);
+		goto success;
+	}
+
+	/* create a new volume record */
+	_debug("creating new volume record");
+
+	ret = -ENOMEM;
+	volume = kmalloc(sizeof(afs_volume_t),GFP_KERNEL);
+	if (!volume)
+		goto error_up;
+
+	memset(volume,0,sizeof(afs_volume_t));
+	atomic_set(&volume->usage,1);
+	volume->type = type;
+	volume->type_force = force;
+	volume->cell = cell;
+	volume->vid = vlocation->vldb.vid[type];
+
+	init_rwsem(&volume->server_sem);
+
+	/* look up all the applicable server records */
+	for (loop=0; loop<8; loop++) {
+		if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) {
+			ret = afs_server_lookup(volume->cell,
+						&vlocation->vldb.servers[loop],
+						&volume->servers[volume->nservers]);
+			if (ret<0)
+				goto error_discard;
+
+			volume->nservers++;
+		}
+	}
+
+	/* attach the cache and volume location */
+#if 0
+	afs_get_cache(cache);		volume->cache = cache;
+#endif
+	afs_get_vlocation(vlocation);	volume->vlocation = vlocation;
+
+	vlocation->vols[type] = volume;
+
+ success:
+	_debug("kAFS selected %s volume %08x",afs_voltypes[volume->type],volume->vid);
+	*_volume = volume;
+	ret = 0;
+
+	/* clean up */
+ error_up:
+	up_write(&cell->vl_sem);
+ error:
+	if (vlocation)	afs_put_vlocation(vlocation);
+	if (cell)	afs_put_cell(cell);
+
+	_leave(" = %d (%p)",ret,volume);
+	return ret;
+
+ error_discard:
+	up_write(&cell->vl_sem);
+
+	for (loop=volume->nservers-1; loop>=0; loop--)
+		if (volume->servers[loop])
+			afs_put_server(volume->servers[loop]);
+
+	kfree(volume);
+	goto error;
+} /* end afs_volume_lookup() */
+
+/*****************************************************************************/
+/*
+ * destroy a volume record
+ */
+void afs_put_volume(afs_volume_t *volume)
+{
+	afs_vlocation_t *vlocation;
+	int loop;
+
+	_enter("%p",volume);
+
+	vlocation = volume->vlocation;
+
+	/* sanity check */
+	if (atomic_read(&volume->usage)<=0)
+		BUG();
+
+	/* to prevent a race, the decrement and the dequeue must be effectively atomic */
+	down_write(&vlocation->cell->vl_sem);
+
+	if (likely(!atomic_dec_and_test(&volume->usage))) {
+		up_write(&vlocation->cell->vl_sem);
+		_leave("");
+		return;
+	}
+
+	vlocation->vols[volume->type] = NULL;
+
+	up_write(&vlocation->cell->vl_sem);
+
+	afs_put_vlocation(vlocation);
+
+	/* finish cleaning up the volume */
+#if 0
+	if (volume->cache)	afs_put_cache(volume->cache);
+#endif
+
+	for (loop=volume->nservers-1; loop>=0; loop--)
+		if (volume->servers[loop])
+			afs_put_server(volume->servers[loop]);
+
+	kfree(volume);
+
+	_leave(" [destroyed]");
+} /* end afs_put_volume() */
+
+/*****************************************************************************/
+/*
+ * pick a server to use to try accessing this volume
+ * - returns with an elevated usage count on the server chosen
+ */
+int afs_volume_pick_fileserver(afs_volume_t *volume, afs_server_t **_server)
+{
+	afs_server_t *server;
+	int ret, state, loop;
+
+	_enter("%s",volume->vlocation->vldb.name);
+
+	down_read(&volume->server_sem);
+
+	/* handle the no-server case */
+	if (volume->nservers==0) {
+		ret = volume->rjservers ? -ENOMEDIUM : -ESTALE;
+		up_read(&volume->server_sem);
+		_leave(" = %d [no servers]",ret);
+		return ret;
+	}
+
+	/* basically, just search the list for the first live server and use that */
+	ret = 0;
+	for (loop=0; loop<volume->nservers; loop++) {
+		server = volume->servers[loop];
+		state = server->fs_state;
+
+		switch (state) {
+			/* found an apparently healthy server */
+		case 0:
+			afs_get_server(server);
+			up_read(&volume->server_sem);
+			*_server = server;
+			_leave(" = 0 (picked %08x)",ntohl(server->addr.s_addr));
+			return 0;
+
+		case -ENETUNREACH:
+			if (ret==0)
+				ret = state;
+			break;
+
+		case -EHOSTUNREACH:
+			if (ret==0 || ret==-ENETUNREACH)
+				ret = state;
+			break;
+
+		case -ECONNREFUSED:
+			if (ret==0 || ret==-ENETUNREACH || ret==-EHOSTUNREACH)
+				ret = state;
+			break;
+
+		default:
+		case -EREMOTEIO:
+			if (ret==0 ||
+			    ret==-ENETUNREACH ||
+			    ret==-EHOSTUNREACH ||
+			    ret==-ECONNREFUSED)
+				ret = state;
+			break;
+		}
+	}
+
+	/* no available servers
+	 * - TODO: handle the no active servers case better
+	 */
+	up_read(&volume->server_sem);
+	_leave(" = %d",ret);
+	return ret;
+} /* end afs_volume_pick_fileserver() */
+
+/*****************************************************************************/
+/*
+ * release a server after use
+ * - releases the ref on the server struct that was acquired by picking
+ * - records result of using a particular server to access a volume
+ * - return 0 to try again, 1 if okay or to issue error
+ */
+int afs_volume_release_fileserver(afs_volume_t *volume, afs_server_t *server, int result)
+{
+	unsigned loop;
+
+	_enter("%s,%08x,%d",volume->vlocation->vldb.name,ntohl(server->addr.s_addr),result);
+
+	switch (result) {
+		/* success */
+	case 0:
+		server->fs_act_jif = jiffies;
+		break;
+
+		/* the fileserver denied all knowledge of the volume */
+	case -ENOMEDIUM:
+		server->fs_act_jif = jiffies;
+		down_write(&volume->server_sem);
+
+		/* first, find where the server is in the active list (if it is) */
+		for (loop=0; loop<volume->nservers; loop++)
+			if (volume->servers[loop]==server)
+				goto present;
+
+		/* no longer there - may have been discarded by another op */
+		goto try_next_server_upw;
+
+	present:
+		volume->nservers--;
+		memmove(&volume->servers[loop],
+			&volume->servers[loop+1],
+			sizeof(volume->servers[loop]) * (volume->nservers - loop)
+			);
+		volume->servers[volume->nservers] = NULL;
+		afs_put_server(server);
+		volume->rjservers++;
+
+		if (volume->nservers>0)
+			/* another server might acknowledge its existence */
+			goto try_next_server_upw;
+
+		/* handle the case where all the fileservers have rejected the volume
+		 * - TODO: try asking the fileservers for volume information
+		 * - TODO: contact the VL server again to see if the volume is no longer registered
+		 */
+		up_write(&volume->server_sem);
+		afs_put_server(server);
+		_leave(" [completely rejected]");
+		return 1;
+
+		/* problem reaching the server */
+	case -ENETUNREACH:
+	case -EHOSTUNREACH:
+	case -ECONNREFUSED:
+	case -ETIMEDOUT:
+	case -EREMOTEIO:
+		/* mark the server as dead
+		 * TODO: vary dead timeout depending on error
+		 */
+		spin_lock(&server->fs_lock);
+		if (!server->fs_state) {
+			server->fs_dead_jif = jiffies + HZ * 10;
+			server->fs_state = result;
+			printk("kAFS: SERVER DEAD state=%d\n",result);
+		}
+		spin_unlock(&server->fs_lock);
+		goto try_next_server;
+
+		/* miscellaneous error */
+	default:
+		server->fs_act_jif = jiffies;
+	case -ENOMEM:
+	case -ENONET:
+		break;
+	}
+
+	/* tell the caller to accept the result */
+	afs_put_server(server);
+	_leave("");
+	return 1;
+
+	/* tell the caller to loop around and try the next server */
+ try_next_server_upw:
+	up_write(&volume->server_sem);
+ try_next_server:
+	afs_put_server(server);
+	_leave(" [try next server]");
+	return 0;
+
+} /* end afs_volume_release_fileserver() */
diff -Nru a/fs/afs/volume.h b/fs/afs/volume.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/afs/volume.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,92 @@
+/* volume.h: AFS volume management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_AFS_VOLUME_H
+#define _LINUX_AFS_VOLUME_H
+
+#include "types.h"
+#include "fsclient.h"
+#include "kafstimod.h"
+#include "kafsasyncd.h"
+#include "cache-layout.h"
+
+#define __packed __attribute__((packed))
+
+typedef enum {
+	AFS_VLUPD_SLEEP,		/* sleeping waiting for update timer to fire */
+	AFS_VLUPD_PENDING,		/* on pending queue */
+	AFS_VLUPD_INPROGRESS,		/* op in progress */
+	AFS_VLUPD_BUSYSLEEP,		/* sleeping because server returned EBUSY */
+	
+} __attribute__((packed)) afs_vlocation_upd_t;
+
+/*****************************************************************************/
+/*
+ * AFS volume location record
+ */
+struct afs_vlocation
+{
+	atomic_t		usage;
+	struct list_head	link;		/* link in cell volume location list */
+	afs_timer_t		timeout;	/* decaching timer */
+	afs_cell_t		*cell;		/* cell to which volume belongs */
+	struct list_head	caches;		/* backing caches */
+	afsc_vldb_record_t	vldb;		/* volume information DB record */
+	struct afs_volume	*vols[3];	/* volume access record pointer (index by type) */
+	rwlock_t		lock;		/* access lock */
+	unsigned long		read_jif;	/* time at which last read from vlserver */
+	afs_timer_t		upd_timer;	/* update timer */
+	afs_async_op_t		upd_op;		/* update operation */
+	afs_vlocation_upd_t	upd_state;	/* update state */
+	unsigned short		upd_first_svix;	/* first server index during update */
+	unsigned short		upd_curr_svix;	/* current server index during update */
+	unsigned short		upd_rej_cnt;	/* ENOMEDIUM count during update */
+	unsigned short		upd_busy_cnt;	/* EBUSY count during update */
+	unsigned short		valid;		/* T if valid */
+};
+
+extern int afs_vlocation_lookup(afs_cell_t *cell, const char *name, afs_vlocation_t **_vlocation);
+
+#define afs_get_vlocation(V) do { atomic_inc(&(V)->usage); } while(0)
+
+extern void __afs_put_vlocation(afs_vlocation_t *vlocation);
+extern void afs_put_vlocation(afs_vlocation_t *vlocation);
+extern void afs_vlocation_do_timeout(afs_vlocation_t *vlocation);
+
+/*****************************************************************************/
+/*
+ * AFS volume access record
+ */
+struct afs_volume
+{
+	atomic_t		usage;
+	afs_cell_t		*cell;		/* cell to which belongs (unrefd ptr) */
+	afs_vlocation_t		*vlocation;	/* volume location */
+	afs_volid_t		vid;		/* volume ID */
+	afs_voltype_t __packed	type;		/* type of volume */
+	char			type_force;	/* force volume type (suppress R/O -> R/W) */
+	unsigned short		nservers;	/* number of server slots filled */
+	unsigned short		rjservers;	/* number of servers discarded due to -ENOMEDIUM */
+	afs_server_t		*servers[8];	/* servers on which volume resides (ordered) */
+	struct rw_semaphore	server_sem;	/* lock for accessing current server */
+};
+
+extern int afs_volume_lookup(char *name, int ro, afs_volume_t **_volume);
+
+#define afs_get_volume(V) do { atomic_inc(&(V)->usage); } while(0)
+
+extern void afs_put_volume(afs_volume_t *volume);
+
+extern int afs_volume_pick_fileserver(afs_volume_t *volume, afs_server_t **_server);
+
+extern int afs_volume_release_fileserver(afs_volume_t *volume, afs_server_t *server, int result);
+
+#endif /* _LINUX_AFS_VOLUME_H */
diff -Nru a/fs/aio.c b/fs/aio.c
--- a/fs/aio.c	Tue Oct 15 20:29:16 2002
+++ b/fs/aio.c	Tue Oct 15 20:29:16 2002
@@ -9,6 +9,7 @@
  *	See ../COPYING for licensing terms.
  */
 #include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/aio_abi.h>
@@ -21,15 +22,9 @@
 #include <linux/file.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
-#include <linux/vmalloc.h>
-#include <linux/iobuf.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
-#include <linux/brlock.h>
 #include <linux/aio.h>
-#include <linux/smp_lock.h>
-#include <linux/compiler.h>
-#include <linux/brlock.h>
 #include <linux/module.h>
 #include <linux/highmem.h>
 #include <linux/workqueue.h>
@@ -1254,3 +1249,4 @@
 
 EXPORT_SYMBOL(aio_complete);
 EXPORT_SYMBOL(aio_put_req);
+EXPORT_SYMBOL(wait_on_sync_kiocb);
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Tue Oct 15 20:29:17 2002
+++ b/fs/bio.c	Tue Oct 15 20:29:17 2002
@@ -20,7 +20,7 @@
 #include <linux/bio.h>
 #include <linux/blk.h>
 #include <linux/slab.h>
-#include <linux/iobuf.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mempool.h>
@@ -438,128 +438,6 @@
 	return 0;
 }
 
-static int bio_end_io_kio(struct bio *bio, unsigned int bytes_done, int error)
-{
-	struct kiobuf *kio = (struct kiobuf *) bio->bi_private;
-
-	if (bio->bi_size)
-		return 1;
-
-	end_kio_request(kio, error);
-	bio_put(bio);
-	return 0;
-}
-
-/**
- * ll_rw_kio - submit a &struct kiobuf for I/O
- * @rw:   %READ or %WRITE
- * @kio:   the kiobuf to do I/O on
- * @bdev:   target device
- * @sector:   start location on disk
- *
- * Description:
- *   ll_rw_kio will map the page list inside the &struct kiobuf to
- *   &struct bio and queue them for I/O. The kiobuf given must describe
- *   a continous range of data, and must be fully prepared for I/O.
- **/
-void ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t sector)
-{
-	int i, offset, size, err, map_i, total_nr_pages, nr_pages;
-	struct bio *bio;
-
-	err = 0;
-	if ((rw & WRITE) && bdev_read_only(bdev)) {
-		printk("ll_rw_bio: WRITE to ro device %s\n", bdevname(bdev));
-		err = -EPERM;
-		goto out;
-	}
-
-	if (!kio->nr_pages) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	/*
-	 * maybe kio is bigger than the max we can easily map into a bio.
-	 * if so, split it up in appropriately sized chunks.
-	 */
-	total_nr_pages = kio->nr_pages;
-	offset = kio->offset & ~PAGE_MASK;
-	size = kio->length;
-
-	atomic_set(&kio->io_count, 1);
-
-	map_i = 0;
-
-next_chunk:
-	nr_pages = BIO_MAX_PAGES;
-	if (nr_pages > total_nr_pages)
-		nr_pages = total_nr_pages;
-
-	atomic_inc(&kio->io_count);
-
-	/*
-	 * allocate bio and do initial setup
-	 */
-	if ((bio = bio_alloc(GFP_NOIO, nr_pages)) == NULL) {
-		err = -ENOMEM;
-		goto out;
-	}
-
-	bio->bi_sector = sector;
-	bio->bi_bdev = bdev;
-	bio->bi_idx = 0;
-	bio->bi_end_io = bio_end_io_kio;
-	bio->bi_private = kio;
-
-	for (i = 0; i < nr_pages; i++, map_i++) {
-		int nbytes = PAGE_SIZE - offset;
-
-		if (nbytes > size)
-			nbytes = size;
-
-		BUG_ON(kio->maplist[map_i] == NULL);
-
-		/*
-		 * if we can't add this page to the bio, submit for i/o
-		 * and alloc a new one if needed
-		 */
-		if (bio_add_page(bio, kio->maplist[map_i], nbytes, offset))
-			break;
-
-		/*
-		 * kiobuf only has an offset into the first page
-		 */
-		offset = 0;
-
-		sector += nbytes >> 9;
-		size -= nbytes;
-		total_nr_pages--;
-		kio->offset += nbytes;
-	}
-
-	submit_bio(rw, bio);
-
-	if (total_nr_pages)
-		goto next_chunk;
-
-	if (size) {
-		printk("ll_rw_kio: size %d left (kio %d)\n", size, kio->length);
-		BUG();
-	}
-
-out:
-	if (err)
-		kio->errno = err;
-
-	/*
-	 * final atomic_dec of io_count to match our initial setting of 1.
-	 * I/O may or may not have completed at this point, final completion
-	 * handler is only run on last decrement.
-	 */
-	end_kio_request(kio, !err);
-}
-
 /**
  * bio_endio - end I/O on a bio
  * @bio:	bio
@@ -662,7 +540,6 @@
 
 EXPORT_SYMBOL(bio_alloc);
 EXPORT_SYMBOL(bio_put);
-EXPORT_SYMBOL(ll_rw_kio);
 EXPORT_SYMBOL(bio_endio);
 EXPORT_SYMBOL(bio_init);
 EXPORT_SYMBOL(bio_copy);
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Tue Oct 15 20:29:23 2002
+++ b/fs/block_dev.c	Tue Oct 15 20:29:23 2002
@@ -14,7 +14,6 @@
 #include <linux/major.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/smp_lock.h>
-#include <linux/iobuf.h>
 #include <linux/highmem.h>
 #include <linux/blkdev.h>
 #include <linux/module.h>
@@ -527,8 +526,6 @@
 {
 	struct block_device_operations * bdops = bdev->bd_op;
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
-	struct gendisk *disk;
-	int part;
 
 	if (bdops->check_media_change == NULL)
 		return 0;
@@ -538,10 +535,9 @@
 	if (invalidate_device(dev, 0))
 		printk("VFS: busy inodes on changed media.\n");
 
-	disk = get_gendisk(bdev->bd_dev, &part);
 	if (bdops->revalidate)
 		bdops->revalidate(dev);
-	if (disk && disk->minor_shift)
+	if (bdev->bd_disk->minors > 1)
 		bdev->bd_invalidated = 1;
 	return 1;
 }
@@ -549,12 +545,11 @@
 int full_check_disk_change(struct block_device *bdev)
 {
 	int res = 0;
-	int n;
 	if (bdev->bd_contains != bdev)
 		BUG();
 	down(&bdev->bd_sem);
 	if (check_disk_change(bdev)) {
-		rescan_partitions(get_gendisk(bdev->bd_dev, &n), bdev);
+		rescan_partitions(bdev->bd_disk, bdev);
 		res = 1;
 	}
 	up(&bdev->bd_sem);
@@ -596,6 +591,8 @@
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	struct module *owner = NULL;
 	struct block_device_operations *ops, *old;
+	struct gendisk *disk;
+	int part;
 
 	lock_kernel();
 	ops = get_blkfops(major(dev));
@@ -615,33 +612,32 @@
 		if (owner)
 			__MOD_DEC_USE_COUNT(owner);
 	}
+	disk = get_gendisk(bdev->bd_dev, &part);
+	if (!disk)
+		goto out1;
 	if (!bdev->bd_contains) {
-		int part;
-		struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
 		bdev->bd_contains = bdev;
-		if (g && part) {
-			struct block_device *disk;
-			disk = bdget(MKDEV(g->major, g->first_minor));
+		if (part) {
+			struct block_device *whole;
+			whole = bdget(MKDEV(disk->major, disk->first_minor));
 			ret = -ENOMEM;
-			if (!disk)
+			if (!whole)
 				goto out1;
-			ret = blkdev_get(disk, file->f_mode, file->f_flags, BDEV_RAW);
+			ret = blkdev_get(whole, file->f_mode, file->f_flags, BDEV_RAW);
 			if (ret)
 				goto out1;
-			bdev->bd_contains = disk;
+			bdev->bd_contains = whole;
 		}
 	}
 	if (bdev->bd_contains == bdev) {
-		int part;
-		struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
-
+		if (!bdev->bd_openers)
+			bdev->bd_disk = disk;
 		if (!bdev->bd_queue) {
 			struct blk_dev_struct *p = blk_dev + major(dev);
 			bdev->bd_queue = &p->request_queue;
 			if (p->queue)
 				bdev->bd_queue =  p->queue(dev);
 		}
-
 		if (bdev->bd_op->open) {
 			ret = bdev->bd_op->open(inode, file);
 			if (ret)
@@ -649,12 +645,8 @@
 		}
 		if (!bdev->bd_openers) {
 			struct backing_dev_info *bdi;
-			sector_t sect = 0;
-
 			bdev->bd_offset = 0;
-			if (g)
-				sect = get_capacity(g);
-			bd_set_size(bdev, (loff_t)sect << 9);
+			bd_set_size(bdev, (loff_t)get_capacity(disk) << 9);
 			bdi = blk_get_backing_dev_info(bdev);
 			if (bdi == NULL)
 				bdi = &default_backing_dev_info;
@@ -662,19 +654,17 @@
 			bdev->bd_inode->i_data.backing_dev_info = bdi;
 		}
 		if (bdev->bd_invalidated)
-			rescan_partitions(g, bdev);
+			rescan_partitions(disk, bdev);
 	} else {
 		down(&bdev->bd_contains->bd_sem);
 		bdev->bd_contains->bd_part_count++;
 		if (!bdev->bd_openers) {
-			int part;
-			struct gendisk *g = get_gendisk(bdev->bd_dev, &part);
 			struct hd_struct *p;
-			p = g->part + part - 1;
+			p = disk->part + part - 1;
 			inode->i_data.backing_dev_info =
 			   bdev->bd_inode->i_data.backing_dev_info =
 			   bdev->bd_contains->bd_inode->i_data.backing_dev_info;
-			if (!p->nr_sects) {
+			if (!(disk->flags & GENHD_FL_UP) || !p->nr_sects) {
 				bdev->bd_contains->bd_part_count--;
 				up(&bdev->bd_contains->bd_sem);
 				ret = -ENXIO;
@@ -683,10 +673,12 @@
 			bdev->bd_queue = bdev->bd_contains->bd_queue;
 			bdev->bd_offset = p->start_sect;
 			bd_set_size(bdev, (loff_t) p->nr_sects << 9);
+			bdev->bd_disk = disk;
 		}
 		up(&bdev->bd_contains->bd_sem);
 	}
-	bdev->bd_openers++;
+	if (bdev->bd_openers++)
+		put_disk(disk);
 	up(&bdev->bd_sem);
 	unlock_kernel();
 	return 0;
@@ -700,6 +692,7 @@
 		}
 	}
 out1:
+	put_disk(disk);
 	if (!old) {
 		bdev->bd_op = NULL;
 		if (owner)
@@ -773,15 +766,18 @@
 		up(&bdev->bd_contains->bd_sem);
 	}
 	if (!bdev->bd_openers) {
+		struct gendisk *disk = bdev->bd_disk;
 		if (bdev->bd_op->owner)
 			__MOD_DEC_USE_COUNT(bdev->bd_op->owner);
 		bdev->bd_op = NULL;
 		bdev->bd_queue = NULL;
+		bdev->bd_disk = NULL;
 		bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info;
 		if (bdev != bdev->bd_contains) {
 			blkdev_put(bdev->bd_contains, BDEV_RAW);
 			bdev->bd_contains = NULL;
 		}
+		put_disk(disk);
 	}
 	unlock_kernel();
 	up(&bdev->bd_sem);
@@ -794,76 +790,12 @@
 	return blkdev_put(inode->i_bdev, BDEV_FILE);
 }
 
-static int blkdev_reread_part(struct block_device *bdev)
-{
-	int part;
-	struct gendisk *disk = get_gendisk(bdev->bd_dev, &part);
-	int res = 0;
-
-	if (!disk || !disk->minor_shift || bdev != bdev->bd_contains)
-		return -EINVAL;
-	if (part)
-		BUG();
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-	if (down_trylock(&bdev->bd_sem))
-		return -EBUSY;
-	res = rescan_partitions(disk, bdev);
-	up(&bdev->bd_sem);
-	return res;
-}
-
 static ssize_t blkdev_file_write(struct file *file, const char *buf,
 				   size_t count, loff_t *ppos)
 {
 	struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count };
 
 	return generic_file_write_nolock(file, &local_iov, 1, ppos);
-}
-
-static int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
-			unsigned long arg)
-{
-	struct block_device *bdev = inode->i_bdev;
-	int ret = -EINVAL;
-	switch (cmd) {
-	/*
-	 * deprecated, use the /proc/iosched interface instead
-	 */
-	case BLKELVGET:
-	case BLKELVSET:
-		ret = -ENOTTY;
-		break;
-	case BLKRAGET:
-	case BLKROGET:
-	case BLKBSZGET:
-	case BLKSSZGET:
-	case BLKFRAGET:
-	case BLKSECTGET:
-	case BLKRASET:
-	case BLKFRASET:
-	case BLKBSZSET:
-	case BLKPG:
-		ret = blk_ioctl(bdev, cmd, arg);
-		break;
-	case BLKRRPART:
-		ret = blkdev_reread_part(bdev);
-		break;
-	default:
-		if (bdev->bd_op->ioctl)
-			ret =bdev->bd_op->ioctl(inode, file, cmd, arg);
-		if (ret == -EINVAL) {
-			switch (cmd) {
-				case BLKGETSIZE:
-				case BLKGETSIZE64:
-				case BLKFLSBUF:
-				case BLKROSET:
-					ret = blk_ioctl(bdev,cmd,arg);
-					break;
-			}
-		}
-	}
-	return ret;
 }
 
 struct address_space_operations def_blk_aops = {
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Tue Oct 15 20:29:17 2002
+++ b/fs/buffer.c	Tue Oct 15 20:29:17 2002
@@ -28,7 +28,6 @@
 #include <linux/blkdev.h>
 #include <linux/file.h>
 #include <linux/quotaops.h>
-#include <linux/iobuf.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/writeback.h>
@@ -812,6 +811,13 @@
 			if (buffer_dirty(bh)) {
 				get_bh(bh);
 				spin_unlock(lock);
+				/*
+				 * Ensure any pending I/O completes so that
+				 * ll_rw_block() actually writes the current
+				 * contents - it is a noop if I/O is still in
+				 * flight on potentially older contents.
+				 */
+				wait_on_buffer(bh);
 				ll_rw_block(WRITE, 1, &bh);
 				brelse(bh);
 				spin_lock(lock);
@@ -2298,65 +2304,6 @@
 	tmp.b_blocknr = 0;
 	get_block(inode, block, &tmp, 0);
 	return tmp.b_blocknr;
-}
-
-/*
- * Start I/O on a physical range of kernel memory, defined by a vector
- * of kiobuf structs (much like a user-space iovec list).
- *
- * The kiobuf must already be locked for IO.  IO is submitted
- * asynchronously: you need to check page->locked and page->uptodate.
- *
- * It is up to the caller to make sure that there are enough blocks
- * passed in to completely map the iobufs to disk.
- */
-int brw_kiovec(int rw, int nr, struct kiobuf *iovec[],
-	       struct block_device *bdev, sector_t b[], int size)
-{
-	int		transferred;
-	int		i;
-	int		err;
-	struct kiobuf *	iobuf;
-
-	if (!nr)
-		return 0;
-	
-	/* 
-	 * First, do some alignment and validity checks 
-	 */
-	for (i = 0; i < nr; i++) {
-		iobuf = iovec[i];
-		if ((iobuf->offset & (size-1)) || (iobuf->length & (size-1)))
-			return -EINVAL;
-		if (!iobuf->nr_pages)
-			panic("brw_kiovec: iobuf not initialised");
-	}
-
-	/* 
-	 * OK to walk down the iovec doing page IO on each page we find. 
-	 */
-	for (i = 0; i < nr; i++) {
-		iobuf = iovec[i];
-		iobuf->errno = 0;
-
-		ll_rw_kio(rw, iobuf, bdev, b[i] * (size >> 9));
-	}
-
-	/*
-	 * now they are all submitted, wait for completion
-	 */
-	transferred = 0;
-	err = 0;
-	for (i = 0; i < nr; i++) {
-		iobuf = iovec[i];
-		kiobuf_wait_for_io(iobuf);
-		if (iobuf->errno && !err)
-			err = iobuf->errno;
-		if (!err)
-			transferred += iobuf->length;
-	}
-
-	return err ? err : transferred;
 }
 
 static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err)
diff -Nru a/fs/cifs/asn1.c b/fs/cifs/asn1.c
--- a/fs/cifs/asn1.c	Tue Oct 15 20:29:11 2002
+++ b/fs/cifs/asn1.c	Tue Oct 15 20:29:11 2002
@@ -458,7 +458,7 @@
 	unsigned int cls, con, tag, oidlen, rc;
 	int use_ntlmssp = FALSE;
 
-	dump_mem(" Received SecBlob ", security_blob, length);
+	/* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
 
 	asn1_open(&ctx, security_blob, length);
 
diff -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
--- a/fs/cifs/cifs_debug.c	Tue Oct 15 20:29:17 2002
+++ b/fs/cifs/cifs_debug.c	Tue Oct 15 20:29:17 2002
@@ -32,7 +32,7 @@
 #include "cifs_debug.h"
 
 void
-dump_mem(char *label, void *data, int length)
+cifs_dump_mem(char *label, void *data, int length)
 {
 	int i, j;
 	int *intptr = data;
diff -Nru a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
--- a/fs/cifs/cifs_debug.h	Tue Oct 15 20:29:17 2002
+++ b/fs/cifs/cifs_debug.h	Tue Oct 15 20:29:17 2002
@@ -23,7 +23,7 @@
 #ifndef _H_CIFS_DEBUG
 #define _H_CIFS_DEBUG
 
-void dump_mem(char *label, void *data, int length);
+void cifs_dump_mem(char *label, void *data, int length);
 extern int traceSMB;		/* flag which enables the function below */
 void dump_smb(struct smb_hdr *, int);
 
diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
--- a/fs/cifs/cifssmb.c	Tue Oct 15 20:29:13 2002
+++ b/fs/cifs/cifssmb.c	Tue Oct 15 20:29:13 2002
@@ -21,7 +21,7 @@
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
- /* All SMB/CIFS PDU handling routines go here - except for a few leftovers in connect.c */
+ /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -85,7 +85,8 @@
     }
 
 	pSMB->ByteCount = strlen(protocols[0].name) + 1;
-	strncpy(pSMB->DialectsArray, protocols[0].name, 30);	/* null guaranteed to be at end of source and target buffers anyway */
+	strncpy(pSMB->DialectsArray, protocols[0].name, 30);	
+    /* null guaranteed to be at end of source and target buffers anyway */
 
 	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
 	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
@@ -94,17 +95,19 @@
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	if (rc == 0) {
 		ses->dialectIndex = le16_to_cpu(pSMBr->DialectIndex);
-		ses->secMode = pSMBr->SecurityMode;	/* one byte - no need to convert this or EncryptionKeyLen field from le,  */
+		ses->secMode = pSMBr->SecurityMode;	
+        /* one byte - no need to convert this or EncryptionKeyLen from le,*/
 		ses->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
 		/* probably no need to store and check maxvcs */
 		ses->maxBuf =
 		    min(le32_to_cpu(pSMBr->MaxBufferSize),
 			(__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE);
-		ses->maxRw = le32_to_cpu(pSMBr->MaxRawSize);	/* BB le_to_host needed around here and ff */
+		ses->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
 		cFYI(1, ("\nMax buf = %d ", ses->maxBuf));
 		GETU32(ses->sessid) = le32_to_cpu(pSMBr->SessionKey);
 		ses->capabilities = le32_to_cpu(pSMBr->Capabilities);
-		ses->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);	/* BB with UTC do we ever need to be using srvr timezone? */
+		ses->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);	
+        /* BB with UTC do we ever need to be using srvr timezone? */
 		if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
 			memcpy(cryptokey, pSMBr->u.EncryptionKey,
 			       CIFS_CRYPTO_KEY_SIZE);
@@ -495,7 +498,6 @@
 		pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength);
 		*nbytes = pSMBr->DataLength;
 		/* BB check that DataLength would not go beyond end of SMB BB */
-/* if(pSMBr->DataOffset < pSMBr->ByteCount + sizeof(READ_RSP) - 1 *//* BB fix this length check */
 		if (pSMBr->DataLength > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
 			rc = -EIO;
 			*nbytes = 0;
@@ -541,7 +543,7 @@
 		pSMB->DataLengthLow = count;
 	pSMB->DataLengthHigh = 0;
 	pSMB->DataOffset =
-	    cpu_to_le16((int) &(pSMB->Data) - (int) pSMB->hdr.Protocol);
+	    cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 	copy_from_user(pSMB->Data, buf, pSMB->DataLengthLow);
 
 	pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ;
@@ -685,7 +687,8 @@
 		name_len2++;	/* signature byte */
 	}
 
-	pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;	/* we could also set search attributes but not needed */
+	pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;	
+    /* we could also set search attributes but not needed */
 	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
 	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
 
@@ -739,8 +742,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
 	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
 
 	data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
@@ -759,7 +762,7 @@
 
 	pSMB->DataCount = name_len_target;
 	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/*BB find exact max SMB from sess */
 	pSMB->SetupCount = 1;
 	pSMB->Reserved3 = 0;
 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
@@ -825,8 +828,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
 	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
 
 	data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
@@ -845,7 +848,7 @@
 
 	pSMB->DataCount = name_len_target;
 	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB from sess*/
 	pSMB->SetupCount = 1;
 	pSMB->Reserved3 = 0;
 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
@@ -983,9 +986,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    cpu_to_le16((int) &(pSMB->InformationLevel) -
-			(int) pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;
@@ -1084,8 +1086,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset = cpu_to_le16((int) &(pSMB->InformationLevel)
-					    - (int) pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;
@@ -1161,9 +1163,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    cpu_to_le16((int) &(pSMB->InformationLevel) -
-			(int) pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;
@@ -1238,9 +1239,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    cpu_to_le16((int) &pSMB->InformationLevel -
-			(int) &pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(
+        offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;	/* one byte, no need to le convert */
@@ -1321,9 +1321,8 @@
 	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
 	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
 	pSMB->ParameterCount = pSMB->TotalParameterCount;
-	pSMB->ParameterOffset =
-	    cpu_to_le16((int) &pSMB->SearchAttributes -
-			(int) &pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
+        smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;	/* one byte no need to make endian neutral */
@@ -1407,8 +1406,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    cpu_to_le16((int) &pSMB->SearchHandle - (int) &pSMB->hdr.Protocol);
+	pSMB->ParameterOffset =  cpu_to_le16(offsetof(
+        struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;
@@ -1532,9 +1531,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    cpu_to_le16((int) &(pSMB->MaxReferralLevel) -
-			(int) pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
 	pSMB->SetupCount = 1;
 	pSMB->Reserved3 = 0;
 	pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
@@ -1587,8 +1585,8 @@
 	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
 	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
 	pSMB->ParameterCount = pSMB->TotalParameterCount;
-	pSMB->ParameterOffset = cpu_to_le16((int) &(pSMB->InformationLevel)
-					    - (int) pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;
@@ -1662,8 +1660,8 @@
 	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
 	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
 	pSMB->ParameterCount = pSMB->TotalParameterCount;
-	pSMB->ParameterOffset = cpu_to_le16((int) &(pSMB->InformationLevel)
-					    - (int) pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;
@@ -1725,9 +1723,9 @@
 	pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
 	pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
 	pSMB->ParameterCount = pSMB->TotalParameterCount;
-	pSMB->ParameterOffset =
-	    cpu_to_le16((int) &(pSMB->InformationLevel) -
-			(int) pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+
 	pSMB->DataCount = 0;
 	pSMB->DataOffset = 0;
 	pSMB->SetupCount = 1;
@@ -1743,7 +1741,8 @@
 		cERROR(1, ("\nSend error in QFSDeviceInfo = %d\n", rc));
 	} else {		/* decode response */
 		pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
-		if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)) || (pSMBr->DataOffset > 512))	/* BB also check enough bytes returned */
+		if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO))
+                 || (pSMBr->DataOffset > 512))
 			rc = -EIO;	/* bad smb */
 		else {
 			response_data =
@@ -1790,9 +1789,8 @@
 	pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ;
 	pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
 	pSMB->TotalParameterCount = pSMB->ParameterCount;
-	pSMB->ParameterOffset =
-	    cpu_to_le16((int) &(pSMB->InformationLevel) -
-			(int) pSMB->hdr.Protocol);
+	pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
+        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
 	pSMB->SetupCount = 1;
 	pSMB->Reserved3 = 0;
 	pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
@@ -1806,7 +1804,7 @@
 		cERROR(1, ("\nSend error in QFSUnixInfo = %d\n", rc));
 	} else {		/* decode response */
 		pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset);
-		if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {	/* BB also check enough bytes returned */
+		if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {
 			rc = -EIO;	/* bad smb */
 		} else {
 			response_data =
@@ -1862,14 +1860,14 @@
 	pSMB->ParameterCount = 6 + name_len;
 	pSMB->DataCount = sizeof (struct file_end_of_file_info);
 	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB size from sess */
 	pSMB->MaxSetupCount = 0;
 	pSMB->Reserved = 0;
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
 	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
     if(SetAllocation) {
         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
@@ -1946,15 +1944,15 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    (int) &(pSMB->Fid) - (int) pSMB->hdr.Protocol;
+	pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
+                                     Fid) - 4;
 	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
 
 	data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;	
 
 	pSMB->DataCount = sizeof(struct file_end_of_file_info);
 	pSMB->MaxParameterCount = cpu_to_le16(2);
-	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find exact max SMB PDU from sess structure BB */
+	pSMB->MaxDataCount = cpu_to_le16(1000);	/* BB find max SMB PDU from sess */
 	pSMB->SetupCount = 1;
 	pSMB->Reserved3 = 0;
 	pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -2042,8 +2040,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
 	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
 	data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
 	pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
@@ -2118,8 +2116,8 @@
 	pSMB->Flags = 0;
 	pSMB->Timeout = 0;
 	pSMB->Reserved2 = 0;
-	pSMB->ParameterOffset =
-	    (int) &(pSMB->InformationLevel) - (int) pSMB->hdr.Protocol;
+	pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
 	pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
 	data_offset =
 	    (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
@@ -2138,9 +2136,7 @@
 	pSMB->Reserved4 = 0;
 	pSMB->hdr.smb_buf_length += pSMB->ByteCount;
 	data_offset->Uid = cpu_to_le64(uid);
-	cFYI(1, ("\nUid = %lld from %lld ", data_offset->Uid, uid));
 	data_offset->Gid = cpu_to_le64(gid);
-	cFYI(1, ("\nGid = %lld from %lld ", data_offset->Gid, gid));
 	data_offset->Permissions = cpu_to_le64(mode);
 	pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
 	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c
--- a/fs/cifs/connect.c	Tue Oct 15 20:29:21 2002
+++ b/fs/cifs/connect.c	Tue Oct 15 20:29:21 2002
@@ -168,7 +168,7 @@
 			} else if (temp[0] != (char) 0) {
 				cERROR(1,
 				       ("\nUnknown RFC 1001 frame received not 0x00 nor 0x85"));
-				dump_mem(" Received Data is: ", temp, length);
+				cifs_dump_mem(" Received Data is: ", temp, length);
 				break;
 			} else {
 				if ((length != sizeof (struct smb_hdr) - 1)
@@ -757,8 +757,7 @@
                /* Removed following few lines to not send old style password 
                   hash ever - for better security */
 			   /* toUpper(cifs_sb->local_nls, password_with_pad);
-				   SMBencrypt(password_with_pad, cryptKey,session_key); 
-				   dump_mem("\nCIFS (Samba encrypt): ", session_key,CIFS_SESSION_KEY_SIZE); */
+				   SMBencrypt(password_with_pad, cryptKey,session_key); */
 
 				rc = CIFSSessSetup(xid, pSesInfo,
 						   volume_info.username,
@@ -925,7 +924,7 @@
 	bcc_ptr += CIFS_SESSION_KEY_SIZE;
 
 	if (ses->capabilities & CAP_UNICODE) {
-		if ((int) bcc_ptr % 2) {	/* must be word aligned for Unicode */
+		if ((long) bcc_ptr % 2) {	/* must be word aligned for Unicode */
 			*bcc_ptr = 0;
 			bcc_ptr++;
 		}
@@ -983,13 +982,12 @@
 		strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
 		bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
 	}
-	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
 	smb_buffer->smb_buf_length += BCC(smb_buffer);
 	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
 
 	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
 			 &bytes_returned, 1);
-	/* dump_mem("\nSessSetup response is: ", smb_buffer_response, 92);*/
 	if (rc) {
 /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
 	} else if ((smb_buffer_response->WordCount == 3)
@@ -1011,7 +1009,7 @@
 					    pSMBr->resp.SecurityBlobLength;
 
 				if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
-					if ((int) (bcc_ptr) % 2) {
+					if ((long) (bcc_ptr) % 2) {
 						remaining_words =
 						    (BCC(smb_buffer_response)
 						     - 1) / 2;
@@ -1069,7 +1067,7 @@
 				} else {	/* ASCII */
 
 					len = strnlen(bcc_ptr, 1024);
-					if (((int) bcc_ptr + len) - (int)
+					if (((long) bcc_ptr + len) - (long)
 					    pByteArea(smb_buffer_response)
 					    <= BCC(smb_buffer_response)) {
 						ses->serverOS = kcalloc(len + 1,GFP_KERNEL);
@@ -1176,7 +1174,7 @@
 	bcc_ptr += SecurityBlobLength;
 
 	if (ses->capabilities & CAP_UNICODE) {
-		if ((int) bcc_ptr % 2) {	/* must be word aligned for Unicode strings */
+		if ((long) bcc_ptr % 2) {	/* must be word aligned for Unicode strings */
 			*bcc_ptr = 0;
 			bcc_ptr++;
 		}
@@ -1229,13 +1227,12 @@
 		strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
 		bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
 	}
-	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
 	smb_buffer->smb_buf_length += BCC(smb_buffer);
 	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
 
 	rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
 			 &bytes_returned, 1);
-	/* dump_mem("\nSessSetup response is: ", smb_buffer_response, 92);  */
 	if (rc) {
 /*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
 	} else if ((smb_buffer_response->WordCount == 3)
@@ -1265,7 +1262,7 @@
 				}
 
 				if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
-					if ((int) (bcc_ptr) % 2) {
+					if ((long) (bcc_ptr) % 2) {
 						remaining_words =
 						    (BCC(smb_buffer_response)
 						     - 1) / 2;
@@ -1328,7 +1325,7 @@
 				} else {	/* ASCII */
 
 					len = strnlen(bcc_ptr, 1024);
-					if (((int) bcc_ptr + len) - (int)
+					if (((long) bcc_ptr + len) - (long)
 					    pByteArea(smb_buffer_response)
 					    <= BCC(smb_buffer_response)) {
 						ses->serverOS = kcalloc(len + 1, GFP_KERNEL);
@@ -1465,16 +1462,16 @@
 		SecurityBlob->DomainName.MaximumLength =
 		    cpu_to_le16(SecurityBlob->DomainName.Length);
 		SecurityBlob->DomainName.Buffer =
-		    cpu_to_le32((unsigned int) &SecurityBlob->
+		    cpu_to_le32((long) &SecurityBlob->
 				DomainString -
-				(unsigned int) &SecurityBlob->Signature);
+				(long) &SecurityBlob->Signature);
 		bcc_ptr += SecurityBlob->DomainName.Length;
 		SecurityBlobLength += SecurityBlob->DomainName.Length;
 		SecurityBlob->DomainName.Length =
 		    cpu_to_le16(SecurityBlob->DomainName.Length);
 	}
 	if (ses->capabilities & CAP_UNICODE) {
-		if ((int) bcc_ptr % 2) {
+		if ((long) bcc_ptr % 2) {
 			*bcc_ptr = 0;
 			bcc_ptr++;
 		}
@@ -1511,7 +1508,7 @@
 	SecurityBlob->NegotiateFlags =
 	    cpu_to_le32(SecurityBlob->NegotiateFlags);
 	pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
-	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
 	smb_buffer->smb_buf_length += BCC(smb_buffer);
 	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
 
@@ -1564,7 +1561,7 @@
                 if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
                     *pNTLMv2_flag = TRUE;
 				if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
-					if ((int) (bcc_ptr) % 2) {
+					if ((long) (bcc_ptr) % 2) {
 						remaining_words =
 						    (BCC(smb_buffer_response)
 						     - 1) / 2;
@@ -1650,7 +1647,7 @@
 				} else {	/* ASCII */
 
 					len = strnlen(bcc_ptr, 1024);
-					if (((int) bcc_ptr + len) - (int)
+					if (((long) bcc_ptr + len) - (long)
 					    pByteArea(smb_buffer_response)
 					    <= BCC(smb_buffer_response)) {
 						ses->serverOS =
@@ -1846,7 +1843,7 @@
 		   SecurityBlobLength += SecurityBlob->WorkstationName.Length;
 		   SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length);  */
 
-		if ((int) bcc_ptr % 2) {
+		if ((long) bcc_ptr % 2) {
 			*bcc_ptr = 0;
 			bcc_ptr++;
 		}
@@ -1918,7 +1915,7 @@
 	SecurityBlob->NegotiateFlags =
 	    cpu_to_le32(SecurityBlob->NegotiateFlags);
 	pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
-	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
 	smb_buffer->smb_buf_length += BCC(smb_buffer);
 	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
 
@@ -1959,7 +1956,7 @@
 				     ("\nNTLMSSP response to Authenticate "));
 
 				if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
-					if ((int) (bcc_ptr) % 2) {
+					if ((long) (bcc_ptr) % 2) {
 						remaining_words =
 						    (BCC(smb_buffer_response)
 						     - 1) / 2;
@@ -2037,8 +2034,8 @@
 				} else {	/* ASCII */
 
 					len = strnlen(bcc_ptr, 1024);
-					if (((int) bcc_ptr + len) - 
-                        (int) pByteArea(smb_buffer_response) 
+					if (((long) bcc_ptr + len) - 
+                        (long) pByteArea(smb_buffer_response) 
                             <= BCC(smb_buffer_response)) {
 						ses->serverOS = kcalloc(len + 1,GFP_KERNEL);
 						strncpy(ses->serverOS,bcc_ptr, len);
@@ -2142,7 +2139,7 @@
 	strcpy(bcc_ptr, "?????");
 	bcc_ptr += strlen("?????");
 	bcc_ptr += 1;
-	BCC(smb_buffer) = (int) bcc_ptr - (int) pByteArea(smb_buffer);
+	BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
 	smb_buffer->smb_buf_length += BCC(smb_buffer);
 	BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
 
@@ -2159,8 +2156,8 @@
         strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
 		if (smb_buffer->Flags2 &= SMBFLG2_UNICODE) {
 			length = UniStrnlen((wchar_t *) bcc_ptr, 512);
-			if (((int) bcc_ptr + (2 * length)) -
-			    (int) pByteArea(smb_buffer_response) <=
+			if (((long) bcc_ptr + (2 * length)) -
+			    (long) pByteArea(smb_buffer_response) <=
 			    BCC(smb_buffer_response)) {
 				tcon->nativeFileSystem =
 				    kcalloc(length + 2, GFP_KERNEL);
@@ -2175,8 +2172,8 @@
 			/* else do not bother copying these informational fields */
 		} else {
 			length = strnlen(bcc_ptr, 1024);
-			if (((int) bcc_ptr + length) -
-			    (int) pByteArea(smb_buffer_response) <=
+			if (((long) bcc_ptr + length) -
+			    (long) pByteArea(smb_buffer_response) <=
 			    BCC(smb_buffer_response)) {
 				tcon->nativeFileSystem =
 				    kcalloc(length + 1, GFP_KERNEL);
diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c
--- a/fs/cifs/file.c	Tue Oct 15 20:29:11 2002
+++ b/fs/cifs/file.c	Tue Oct 15 20:29:11 2002
@@ -572,9 +572,6 @@
 	tmp_inode->i_size = pfindData->EndOfFile;
 	tmp_inode->i_blocks =
 	    do_div(pfindData->AllocationSize, tmp_inode->i_blksize);
-	cFYI(1,
-	     ("\nFinddata alloc size (from smb) %lld",
-	      pfindData->AllocationSize));
 	if (pfindData->AllocationSize < pfindData->EndOfFile)
 		cFYI(1, ("\nServer inconsistency Error: it says allocation size less than end of file "));
 	cFYI(1,
@@ -652,10 +649,6 @@
 	tmp_inode->i_size = pfindData->EndOfFile;
 	tmp_inode->i_blocks =
 	    do_div(pfindData->NumOfBytes, tmp_inode->i_blksize);
-	cFYI(0, ("\nFinddata alloc size (from smb) %lld", pfindData->NumOfBytes));	/* BB remove */
-	if (pfindData->NumOfBytes < pfindData->EndOfFile)
-		cFYI(0, ("\nServer inconsistency Error: it says allocation size less than end of file "));	/* BB remove */
-	cFYI(1, ("\nCIFS FFIRST: Size %ld and blocks %ld ", (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks));	/* BB remove */
 	if (S_ISREG(tmp_inode->i_mode)) {
 		cFYI(1, (" File inode "));
 		tmp_inode->i_op = &cifs_file_inode_ops;
diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c
--- a/fs/cifs/inode.c	Tue Oct 15 20:29:11 2002
+++ b/fs/cifs/inode.c	Tue Oct 15 20:29:11 2002
@@ -131,9 +131,6 @@
 		inode->i_blksize =
 		    (pTcon->ses->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;
 		inode->i_blocks = do_div(findData.NumOfBytes, inode->i_blksize);
-		cFYI(1,
-		     ("\nFinddata alloc size (from smb) %lld",
-		      findData.NumOfBytes));
 		if (findData.NumOfBytes < findData.EndOfFile)
 			cFYI(1, ("\nServer inconsistency Error: it says allocation size less than end of file "));
 		cFYI(1,
diff -Nru a/fs/cifs/nterr.c b/fs/cifs/nterr.c
--- a/fs/cifs/nterr.c	Tue Oct 15 20:29:10 2002
+++ b/fs/cifs/nterr.c	Tue Oct 15 20:29:10 2002
@@ -694,8 +694,8 @@
 /*****************************************************************************
  Print an error message from the status code
  *****************************************************************************/
-void
-print_status(__u32 status_code)
+/* void
+cifs_print_status(__u32 status_code)
 {
 	int idx = 0;
 
@@ -709,4 +709,4 @@
 		idx++;
 	}
 	return;
-}
+} */
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Tue Oct 15 20:29:12 2002
+++ b/fs/dcache.c	Tue Oct 15 20:29:12 2002
@@ -328,7 +328,7 @@
  * all the dentries are in use.
  */
  
-void prune_dcache(int count)
+static void prune_dcache(int count)
 {
 	spin_lock(&dcache_lock);
 	for (; count ; count--) {
@@ -572,25 +572,24 @@
  * This is called from kswapd when we think we need some
  * more memory. 
  */
-int shrink_dcache_memory(int ratio, unsigned int gfp_mask)
+static int shrink_dcache_memory(int nr, unsigned int gfp_mask)
 {
-	int entries = dentry_stat.nr_dentry / ratio + 1;
-	/*
-	 * Nasty deadlock avoidance.
-	 *
-	 * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache->
-	 * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op->
-	 * put_inode->ext2_discard_prealloc->ext2_free_blocks->lock_super->
-	 * DEADLOCK.
-	 *
-	 * We should make sure we don't hold the superblock lock over
-	 * block allocations, but for now:
-	 */
-	if (!(gfp_mask & __GFP_FS))
-		return 0;
-
-	prune_dcache(entries);
-	return entries;
+	if (nr) {
+		/*
+		 * Nasty deadlock avoidance.
+		 *
+	 	 * ext2_new_block->getblk->GFP->shrink_dcache_memory->
+		 * prune_dcache->prune_one_dentry->dput->dentry_iput->iput->
+		 * inode->i_sb->s_op->put_inode->ext2_discard_prealloc->
+		 * ext2_free_blocks->lock_super->DEADLOCK.
+	 	 *
+	 	 * We should make sure we don't hold the superblock lock over
+	 	 * block allocations, but for now:
+		 */
+		if (gfp_mask & __GFP_FS)
+			prune_dcache(nr);
+	}
+	return dentry_stat.nr_dentry;
 }
 
 #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
@@ -638,6 +637,7 @@
 	dentry->d_op = NULL;
 	dentry->d_fsdata = NULL;
 	dentry->d_mounted = 0;
+	dentry->d_cookie = NULL;
 	INIT_LIST_HEAD(&dentry->d_hash);
 	INIT_LIST_HEAD(&dentry->d_lru);
 	INIT_LIST_HEAD(&dentry->d_subdirs);
@@ -1330,6 +1330,8 @@
 					 NULL, NULL);
 	if (!dentry_cache)
 		panic("Cannot create dentry cache");
+	
+	set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory);
 
 #if PAGE_SHIFT < 13
 	mempages >>= (13 - PAGE_SHIFT);
@@ -1375,9 +1377,6 @@
 /* SLAB cache for file structures */
 kmem_cache_t *filp_cachep;
 
-/* SLAB cache for dquot structures */
-kmem_cache_t *dquot_cachep;
-
 EXPORT_SYMBOL(d_genocide);
 
 extern void bdev_cache_init(void);
@@ -1396,14 +1395,6 @@
 			SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if(!filp_cachep)
 		panic("Cannot create filp SLAB cache");
-
-#if defined (CONFIG_QUOTA)
-	dquot_cachep = kmem_cache_create("dquot", 
-			sizeof(struct dquot), sizeof(unsigned long) * 4,
-			SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if (!dquot_cachep)
-		panic("Cannot create dquot SLAB cache");
-#endif
 
 	dcache_init(mempages);
 	inode_init(mempages);
diff -Nru a/fs/dcookies.c b/fs/dcookies.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/dcookies.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,323 @@
+/*
+ * dcookies.c
+ *
+ * Copyright 2002 John Levon <levon@movementarian.org>
+ *
+ * Persistent cookie-path mappings. These are used by
+ * profilers to convert a per-task EIP value into something
+ * non-transitory that can be processed at a later date.
+ * This is done by locking the dentry/vfsmnt pair in the
+ * kernel until released by the tasks needing the persistent
+ * objects. The tag is simply an u32 that refers
+ * to the pair and can be looked up from userspace.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/mount.h>
+#include <linux/dcache.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/dcookies.h>
+#include <asm/uaccess.h>
+
+/* The dcookies are allocated from a kmem_cache and
+ * hashed onto a small number of lists. None of the
+ * code here is particularly performance critical
+ */
+struct dcookie_struct {
+	struct dentry * dentry;
+	struct vfsmount * vfsmnt;
+	struct list_head hash_list;
+};
+
+static LIST_HEAD(dcookie_users);
+static DECLARE_MUTEX(dcookie_sem);
+static kmem_cache_t * dcookie_cache;
+static struct list_head * dcookie_hashtable;
+static size_t hash_size;
+
+static inline int is_live(void)
+{
+	return !(list_empty(&dcookie_users));
+}
+
+
+/* The dentry is locked, its address will do for the cookie */
+static inline u32 dcookie_value(struct dcookie_struct * dcs)
+{
+	return (u32)dcs->dentry;
+}
+
+
+static size_t dcookie_hash(u32 dcookie)
+{
+	return (dcookie >> 2) & (hash_size - 1);
+}
+
+
+static struct dcookie_struct * find_dcookie(u32 dcookie)
+{
+	struct dcookie_struct * found = 0;
+	struct dcookie_struct * dcs;
+	struct list_head * pos;
+	struct list_head * list;
+
+	list = dcookie_hashtable + dcookie_hash(dcookie);
+
+	list_for_each(pos, list) {
+		dcs = list_entry(pos, struct dcookie_struct, hash_list);
+		if (dcookie_value(dcs) == dcookie) {
+			found = dcs;
+			break;
+		}
+	}
+
+	return found;
+}
+
+
+static void hash_dcookie(struct dcookie_struct * dcs)
+{
+	struct list_head * list = dcookie_hashtable + dcookie_hash(dcookie_value(dcs));
+	list_add(&dcs->hash_list, list);
+}
+
+
+static struct dcookie_struct * alloc_dcookie(struct dentry * dentry,
+	struct vfsmount * vfsmnt)
+{
+	struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_KERNEL);
+	if (!dcs)
+		return NULL;
+
+	atomic_inc(&dentry->d_count);
+	atomic_inc(&vfsmnt->mnt_count);
+	dentry->d_cookie = dcs;
+
+	dcs->dentry = dentry;
+	dcs->vfsmnt = vfsmnt;
+	hash_dcookie(dcs);
+
+	return dcs;
+}
+
+
+/* This is the main kernel-side routine that retrieves the cookie
+ * value for a dentry/vfsmnt pair.
+ */
+int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt,
+	u32 * cookie)
+{
+	int err = 0;
+	struct dcookie_struct * dcs;
+
+	down(&dcookie_sem);
+
+	if (!is_live()) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	dcs = dentry->d_cookie;
+
+	if (!dcs)
+		dcs = alloc_dcookie(dentry, vfsmnt);
+
+	if (!dcs) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	*cookie = dcookie_value(dcs);
+
+out:
+	up(&dcookie_sem);
+	return err;
+}
+
+
+/* And here is where the userspace process can look up the cookie value
+ * to retrieve the path.
+ */
+asmlinkage int sys_lookup_dcookie(u32 cookie, char * buf, size_t len)
+{
+	char * kbuf;
+	char * path;
+	int err = -EINVAL;
+	size_t pathlen;
+	struct dcookie_struct * dcs;
+
+	/* we could leak path information to users
+	 * without dir read permission without this
+	 */
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	down(&dcookie_sem);
+
+	if (!is_live()) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (!(dcs = find_dcookie(cookie)))
+		goto out;
+
+	err = -ENOMEM;
+	kbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!kbuf)
+		goto out;
+	memset(kbuf, 0, PAGE_SIZE);
+
+	/* FIXME: (deleted) ? */
+	path = d_path(dcs->dentry, dcs->vfsmnt, kbuf, PAGE_SIZE);
+
+	err = 0;
+
+	pathlen = kbuf + PAGE_SIZE - path;
+	if (len > pathlen)
+		len = pathlen;
+
+	if (copy_to_user(buf, path, len))
+		err = -EFAULT;
+
+	kfree(kbuf);
+out:
+	up(&dcookie_sem);
+	return err;
+}
+
+
+static int dcookie_init(void)
+{
+	struct list_head * d;
+	unsigned int i, hash_bits;
+	int err = -ENOMEM;
+
+	dcookie_cache = kmem_cache_create("dcookie_cache",
+		sizeof(struct dcookie_struct),
+		0, 0, NULL, NULL);
+
+	if (!dcookie_cache)
+		goto out;
+
+	dcookie_hashtable = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!dcookie_hashtable)
+		goto out_kmem;
+
+	err = 0;
+
+	/*
+	 * Find the power-of-two list-heads that can fit into the allocation..
+	 * We don't guarantee that "sizeof(struct list_head)" is necessarily
+	 * a power-of-two.
+	 */
+	hash_size = PAGE_SIZE / sizeof(struct list_head);
+	hash_bits = 0;
+	do {
+		hash_bits++;
+	} while ((hash_size >> hash_bits) != 0);
+	hash_bits--;
+
+	/*
+	 * Re-calculate the actual number of entries and the mask
+	 * from the number of bits we can fit.
+	 */
+	hash_size = 1UL << hash_bits;
+
+	/* And initialize the newly allocated array */
+	d = dcookie_hashtable;
+	i = hash_size;
+	do {
+		INIT_LIST_HEAD(d);
+		d++;
+		i--;
+	} while (i);
+
+out:
+	return err;
+out_kmem:
+	kmem_cache_destroy(dcookie_cache);
+	goto out;
+}
+
+
+static void free_dcookie(struct dcookie_struct * dcs)
+{
+	dcs->dentry->d_cookie = NULL;
+	dput(dcs->dentry);
+	mntput(dcs->vfsmnt);
+	kmem_cache_free(dcookie_cache, dcs);
+}
+
+
+static void dcookie_exit(void)
+{
+	struct list_head * list;
+	struct list_head * pos;
+	struct list_head * pos2;
+	struct dcookie_struct * dcs;
+	size_t i;
+
+	for (i = 0; i < hash_size; ++i) {
+		list = dcookie_hashtable + i;
+		list_for_each_safe(pos, pos2, list) {
+			dcs = list_entry(pos, struct dcookie_struct, hash_list);
+			list_del(&dcs->hash_list);
+			free_dcookie(dcs);
+		}
+	}
+
+	kfree(dcookie_hashtable);
+	kmem_cache_destroy(dcookie_cache);
+}
+
+
+struct dcookie_user {
+	struct list_head next;
+};
+ 
+struct dcookie_user * dcookie_register(void)
+{
+	struct dcookie_user * user;
+
+	down(&dcookie_sem);
+
+	user = kmalloc(sizeof(struct dcookie_user), GFP_KERNEL);
+	if (!user)
+		goto out;
+
+	if (!is_live() && dcookie_init())
+		goto out_free;
+
+	list_add(&user->next, &dcookie_users);
+
+out:
+	up(&dcookie_sem);
+	return user;
+out_free:
+	kfree(user);
+	user = NULL;
+	goto out;
+}
+
+
+void dcookie_unregister(struct dcookie_user * user)
+{
+	down(&dcookie_sem);
+
+	list_del(&user->next);
+	kfree(user);
+
+	if (!is_live())
+		dcookie_exit();
+
+	up(&dcookie_sem);
+}
+
+EXPORT_SYMBOL_GPL(dcookie_register);
+EXPORT_SYMBOL_GPL(dcookie_unregister);
+EXPORT_SYMBOL_GPL(get_dcookie);
diff -Nru a/fs/direct-io.c b/fs/direct-io.c
--- a/fs/direct-io.c	Tue Oct 15 20:29:17 2002
+++ b/fs/direct-io.c	Tue Oct 15 20:29:17 2002
@@ -388,7 +388,7 @@
 /*
  * There is no bio.  Make one now.
  */
-static int dio_new_bio(struct dio *dio)
+static int dio_new_bio(struct dio *dio, sector_t blkno)
 {
 	sector_t sector;
 	int ret, nr_pages;
@@ -396,7 +396,7 @@
 	ret = dio_bio_reap(dio);
 	if (ret)
 		goto out;
-	sector = dio->next_block_in_bio << (dio->blkbits - 9);
+	sector = blkno << (dio->blkbits - 9);
 	nr_pages = min(dio->pages_left, bio_get_nr_vecs(dio->map_bh.b_bdev));
 	BUG_ON(nr_pages <= 0);
 	ret = dio_bio_alloc(dio, dio->map_bh.b_bdev, sector, nr_pages);
@@ -408,23 +408,26 @@
 
 static int
 dio_bio_add_page(struct dio *dio, struct page *page,
-		unsigned int bv_len, unsigned int bv_offset)
+		unsigned int bv_len, unsigned int bv_offset, sector_t blkno)
 {
 	int ret = 0;
 
 	if (bv_len == 0) 
 		goto out;
 
+	/* Take a ref against the page each time it is placed into a BIO */
 	page_cache_get(page);
 	if (bio_add_page(dio->bio, page, bv_len, bv_offset)) {
 		dio_bio_submit(dio);
-		ret = dio_new_bio(dio);
+		ret = dio_new_bio(dio, blkno);
 		if (ret == 0) {
 			ret = bio_add_page(dio->bio, page, bv_len, bv_offset);
 			BUG_ON(ret != 0);
+		} else {
+			/* The page didn't make it into a BIO */
+			page_cache_release(page);
 		}
 	}
-	page_cache_release(page);
 	dio->pages_left--;
 out:
 	return ret;
@@ -460,6 +463,7 @@
 		int new_page;	/* Need to insert this page into the BIO? */
 		unsigned int bv_offset;
 		unsigned int bv_len;
+		sector_t curr_blkno;
 
 		page = dio_get_page(dio);
 		if (IS_ERR(page)) {
@@ -470,6 +474,7 @@
 		new_page = 1;
 		bv_offset = 0;
 		bv_len = 0;
+		curr_blkno = 0;
 		while (block_in_page < blocks_per_page) {
 			unsigned this_chunk_bytes;	/* # of bytes mapped */
 			unsigned this_chunk_blocks;	/* # of blocks */
@@ -477,7 +482,7 @@
 
 			ret = get_more_blocks(dio);
 			if (ret)
-				goto out;
+				goto fail_release;
 
 			/* Handle holes */
 			if (!buffer_mapped(&dio->map_bh)) {
@@ -494,15 +499,16 @@
 
 			dio_prep_bio(dio);
 			if (dio->bio == NULL) {
-				ret = dio_new_bio(dio);
+				ret = dio_new_bio(dio, dio->next_block_in_bio);
 				if (ret)
-					goto out;
+					goto fail_release;
 				new_page = 1;
 			}
 
 			if (new_page) {
 				bv_len = 0;
 				bv_offset = block_in_page << blkbits;
+				curr_blkno = dio->next_block_in_bio;
 				new_page = 0;
 			}
 
@@ -530,11 +536,18 @@
 			if (dio->block_in_file == dio->final_block_in_request)
 				break;
 		}
-		ret = dio_bio_add_page(dio, page, bv_len, bv_offset);
+		ret = dio_bio_add_page(dio, page, bv_len,
+					bv_offset, curr_blkno);
 		if (ret)
-			goto out;
+			goto fail_release;
+
+		/* Drop the ref which was taken in get_user_pages() */
+		page_cache_release(page);
 		block_in_page = 0;
 	}
+	goto out;
+fail_release:
+	page_cache_release(page);
 out:
 	return ret;
 }
diff -Nru a/fs/dquot.c b/fs/dquot.c
--- a/fs/dquot.c	Tue Oct 15 20:29:19 2002
+++ b/fs/dquot.c	Tue Oct 15 20:29:19 2002
@@ -55,6 +55,7 @@
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
 #include <linux/time.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -481,14 +482,14 @@
  * more memory
  */
 
-int shrink_dqcache_memory(int ratio, unsigned int gfp_mask)
+static int shrink_dqcache_memory(int nr, unsigned int gfp_mask)
 {
-	int entries = dqstats.allocated_dquots / ratio + 1;
-
-	lock_kernel();
-	prune_dqcache(entries);
-	unlock_kernel();
-	return entries;
+	if (nr) {
+		lock_kernel();
+		prune_dqcache(nr);
+		unlock_kernel();
+	}
+	return dqstats.allocated_dquots;
 }
 
 /*
@@ -1490,6 +1491,9 @@
 	{},
 };
 
+/* SLAB cache for dquot structures */
+kmem_cache_t *dquot_cachep;
+
 static int __init dquot_init(void)
 {
 	int i;
@@ -1499,9 +1503,17 @@
 		INIT_LIST_HEAD(dquot_hash + i);
 	printk(KERN_NOTICE "VFS: Disk quotas v%s\n", __DQUOT_VERSION__);
 
+	dquot_cachep = kmem_cache_create("dquot", 
+			sizeof(struct dquot), sizeof(unsigned long) * 4,
+			SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (!dquot_cachep)
+		panic("Cannot create dquot SLAB cache");
+
+	set_shrinker(DEFAULT_SEEKS, shrink_dqcache_memory);
+
 	return 0;
 }
-__initcall(dquot_init);
+module_init(dquot_init);
 
 EXPORT_SYMBOL(register_quota_format);
 EXPORT_SYMBOL(unregister_quota_format);
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Tue Oct 15 20:29:16 2002
+++ b/fs/exec.c	Tue Oct 15 20:29:16 2002
@@ -37,6 +37,7 @@
 #include <linux/personality.h>
 #include <linux/binfmts.h>
 #include <linux/swap.h>
+#include <linux/utsname.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/namei.h>
@@ -52,6 +53,8 @@
 #endif
 
 int core_uses_pid;
+char core_pattern[65] = "core";
+/* The maximal length of core_pattern is also specified in sysctl.c */ 
 
 static struct linux_binfmt *formats;
 static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED;
@@ -1090,10 +1093,126 @@
 		__MOD_DEC_USE_COUNT(old->module);
 }
 
+#define CORENAME_MAX_SIZE 64
+
+/* format_corename will inspect the pattern parameter, and output a
+ * name into corename, which must have space for at least
+ * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
+ */
+void format_corename(char *corename, const char *pattern, long signr)
+{
+	const char *pat_ptr = pattern;
+	char *out_ptr = corename;
+	char *const out_end = corename + CORENAME_MAX_SIZE;
+	int rc;
+	int pid_in_pattern = 0;
+
+	/* Repeat as long as we have more pattern to process and more output
+	   space */
+	while (*pat_ptr) {
+		if (*pat_ptr != '%') {
+			if (out_ptr == out_end)
+				goto out;
+			*out_ptr++ = *pat_ptr++;
+		} else {
+			switch (*++pat_ptr) {
+			case 0:
+				goto out;
+			/* Double percent, output one percent */
+			case '%':
+				if (out_ptr == out_end)
+					goto out;
+				*out_ptr++ = '%';
+				break;
+			/* pid */
+			case 'p':
+				pid_in_pattern = 1;
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->pid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* uid */
+			case 'u':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->uid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* gid */
+			case 'g':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->gid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* signal that caused the coredump */
+			case 's':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%ld", signr);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* UNIX time of coredump */
+			case 't': {
+				struct timeval tv;
+				do_gettimeofday(&tv);
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%lu", tv.tv_sec);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			}
+			/* hostname */
+			case 'h':
+				down_read(&uts_sem);
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%s", system_utsname.nodename);
+				up_read(&uts_sem);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* executable */
+			case 'e':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%s", current->comm);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			default:
+				break;
+			}
+			++pat_ptr;
+		}
+	}
+	/* Backward compatibility with core_uses_pid:
+	 *
+	 * If core_pattern does not include a %p (as is the default)
+	 * and core_uses_pid is set, then .%pid will be appended to
+	 * the filename */
+	if (!pid_in_pattern
+            && (core_uses_pid || atomic_read(&current->mm->mm_users) != 1)) {
+		rc = snprintf(out_ptr, out_end - out_ptr,
+			      ".%d", current->pid);
+		if (rc > out_end - out_ptr)
+			goto out;
+		out_ptr += rc;
+	}
+      out:
+	*out_ptr = 0;
+}
+
 int do_coredump(long signr, struct pt_regs * regs)
 {
 	struct linux_binfmt * binfmt;
-	char corename[6+sizeof(current->comm)+10];
+	char corename[CORENAME_MAX_SIZE + 1];
 	struct file * file;
 	struct inode * inode;
 	int retval = 0;
@@ -1108,9 +1227,7 @@
 	if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
 		goto fail;
 
-	memcpy(corename,"core", 5); /* include trailing \0 */
- 	if (core_uses_pid || atomic_read(&current->mm->mm_users) != 1)
- 		sprintf(&corename[4], ".%d", current->pid);
+ 	format_corename(corename, core_pattern, signr);
 	file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600);
 	if (IS_ERR(file))
 		goto fail;
diff -Nru a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
--- a/fs/ext2/ialloc.c	Tue Oct 15 20:29:17 2002
+++ b/fs/ext2/ialloc.c	Tue Oct 15 20:29:17 2002
@@ -342,7 +342,8 @@
 	if (ino < EXT2_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
 		ext2_error (sb, "ext2_new_inode",
 			    "reserved inode or inode > inodes count - "
-			    "block_group = %d,inode=%ld", group, ino);
+			    "block_group = %d,inode=%lu", group,
+			    (unsigned long) ino);
 		err = -EIO;
 		goto fail2;
 	}
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Tue Oct 15 20:29:12 2002
+++ b/fs/ext2/inode.c	Tue Oct 15 20:29:12 2002
@@ -952,12 +952,13 @@
 	return (struct ext2_inode *) (bh->b_data + offset);
 
 Einval:
-	ext2_error(sb, "ext2_get_inode", "bad inode number: %lu", ino);
+	ext2_error(sb, "ext2_get_inode", "bad inode number: %lu",
+		   (unsigned long) ino);
 	return ERR_PTR(-EINVAL);
 Eio:
 	ext2_error(sb, "ext2_get_inode",
 		   "unable to read inode block - inode=%lu, block=%lu",
-		   ino, block);
+		   (unsigned long) ino, block);
 Egdp:
 	return ERR_PTR(-EIO);
 }
@@ -1076,7 +1077,8 @@
  		return -EIO;
 
 	if (ino == EXT2_ACL_IDX_INO || ino == EXT2_ACL_DATA_INO) {
-		ext2_error (sb, "ext2_write_inode", "bad inode number: %lu", ino);
+		ext2_error (sb, "ext2_write_inode", "bad inode number: %lu",
+			    (unsigned long) ino);
 		brelse(bh);
 		return -EIO;
 	}
@@ -1146,7 +1148,7 @@
 		wait_on_buffer (bh);
 		if (buffer_req(bh) && !buffer_uptodate(bh)) {
 			printk ("IO error syncing ext2 inode [%s:%08lx]\n",
-				sb->s_id, ino);
+				sb->s_id, (unsigned long) ino);
 			err = -EIO;
 		}
 	}
diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
--- a/fs/ext3/ialloc.c	Tue Oct 15 20:29:17 2002
+++ b/fs/ext3/ialloc.c	Tue Oct 15 20:29:17 2002
@@ -458,7 +458,8 @@
 	/* Error cases - e2fsck has already cleaned up for us */
 	if (ino > max_ino) {
 		ext3_warning(sb, __FUNCTION__,
-			     "bad orphan ino %ld!  e2fsck was run?\n", ino);
+			     "bad orphan ino %lu!  e2fsck was run?\n",
+			     (unsigned long) ino);
 		goto out;
 	}
 
@@ -467,7 +468,8 @@
 	bitmap_bh = read_inode_bitmap(sb, block_group);
 	if (!bitmap_bh) {
 		ext3_warning(sb, __FUNCTION__,
-			     "inode bitmap error for orphan %ld\n", ino);
+			     "inode bitmap error for orphan %lu\n",
+			     (unsigned long) ino);
 		goto out;
 	}
 
@@ -490,7 +492,8 @@
 			       is_bad_inode(inode));
 			printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%d\n",
 			       NEXT_ORPHAN(inode));
-			printk(KERN_NOTICE "max_ino=%ld\n", max_ino);
+			printk(KERN_NOTICE "max_ino=%lu\n",
+			       (unsigned long) max_ino);
 		}
 		/* Avoid freeing blocks if we got a bad deleted inode */
 		if (inode && inode->i_nlink == 0)
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Tue Oct 15 20:29:16 2002
+++ b/fs/fat/inode.c	Tue Oct 15 20:29:16 2002
@@ -14,6 +14,7 @@
 #include <linux/time.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
+#include <linux/seq_file.h>
 #include <linux/msdos_fs.h>
 #include <linux/fat_cvf.h>
 #include <linux/pagemap.h>
@@ -201,38 +202,118 @@
 	kfree(sbi);
 }
 
+static int simple_getbool(char *s, int *setval)
+{
+	if (s) {
+		if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true"))
+			*setval = 1;
+		else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false"))
+			*setval = 0;
+		else
+			return 0;
+	} else
+		*setval = 1;
+	return 1;
+}
+
+static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	struct msdos_sb_info *sbi = MSDOS_SB(mnt->mnt_sb);
+	struct fat_mount_options *opts = &sbi->options;
+	int isvfat = opts->isvfat;
+
+	if (opts->fs_uid != 0)
+		seq_printf(m, ",uid=%d", opts->fs_uid);
+	if (opts->fs_gid != 0)
+		seq_printf(m, ",gid=%d", opts->fs_gid);
+	seq_printf(m, ",umask=%04o", opts->fs_umask);
+	seq_printf(m, ",dmask=%04o", opts->fs_dmask);
+	if (sbi->nls_disk)
+		seq_printf(m, ",codepage=%s", sbi->nls_disk->charset);
+	if (isvfat) {
+		if (sbi->nls_io
+		    && strcmp(sbi->nls_io->charset, CONFIG_NLS_DEFAULT))
+			seq_printf(m, ",iocharset=%s", sbi->nls_io->charset);
+
+		switch (opts->shortname) {
+		case VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95:
+			seq_puts(m, ",shortname=win95");
+			break;
+		case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT:
+			seq_puts(m, ",shortname=winnt");
+			break;
+		case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95:
+			seq_puts(m, ",shortname=mixed");
+			break;
+		case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95:
+			/* seq_puts(m, ",shortname=lower"); */
+			break;
+		default:
+			seq_puts(m, ",shortname=unknown");
+			break;
+		}
+	}
+	if (opts->name_check != 'n')
+		seq_printf(m, ",check=%c", opts->name_check);
+	if (opts->conversion != 'b')
+		seq_printf(m, ",conv=%c", opts->conversion);
+	if (opts->quiet)
+		seq_puts(m, ",quiet");
+	if (opts->showexec)
+		seq_puts(m, ",showexec");
+	if (opts->sys_immutable)
+		seq_puts(m, ",sys_immutable");
+	if (!isvfat) {
+		if (opts->dotsOK)
+			seq_puts(m, ",dotsOK=yes");
+		if (opts->nocase)
+			seq_puts(m, ",nocase");
+	} else {
+		if (opts->utf8)
+			seq_puts(m, ",utf8");
+		if (opts->unicode_xlate)
+			seq_puts(m, ",uni_xlate");
+		if (!opts->numtail)
+			seq_puts(m, ",nonumtail");
+	}
 
-static int parse_options(char *options, int *debug,
+	return 0;
+}
+
+static int parse_options(char *options, int is_vfat, int *debug,
 			 struct fat_mount_options *opts,
 			 char *cvf_format, char *cvf_options)
 {
-	char *this_char,*value,save,*savep;
-	char *p;
-	int ret = 1, len;
+	char *this_char, *value, *p;
+	int ret = 1, val, len;
+
+	opts->isvfat = is_vfat;
 
-	opts->name_check = 'n';
-	opts->conversion = 'b';
 	opts->fs_uid = current->uid;
 	opts->fs_gid = current->gid;
-	opts->fs_umask = current->fs->umask;
-	opts->quiet = opts->sys_immutable = opts->dotsOK = opts->showexec = 0;
+	opts->fs_umask = opts->fs_dmask = current->fs->umask;
 	opts->codepage = 0;
-	opts->nocase = 0;
-	opts->shortname = 0;
-	opts->utf8 = 0;
 	opts->iocharset = NULL;
+	if (is_vfat)
+		opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95;
+	else
+		opts->shortname = 0;
+	opts->name_check = 'n';
+	opts->conversion = 'b';
+	opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK =  0;
+	opts->utf8 = opts->unicode_xlate = 0;
+	opts->numtail = 1;
+	opts->nocase = 0;
 	*debug = 0;
 
 	if (!options)
 		goto out;
-	save = 0;
-	savep = NULL;
 	while ((this_char = strsep(&options,",")) != NULL) {
-		if ((value = strchr(this_char,'=')) != NULL) {
-			save = *value;
-			savep = value;
+		if (!*this_char)
+			continue;
+		if ((value = strchr(this_char,'=')) != NULL)
 			*value++ = 0;
-		}
+
 		if (!strcmp(this_char,"check") && value) {
 			if (value[0] && !value[1] && strchr("rns",*value))
 				opts->name_check = *value;
@@ -255,23 +336,18 @@
 				opts->conversion = 'a';
 			else ret = 0;
 		}
-		else if (!strcmp(this_char,"dots")) {
-			opts->dotsOK = 1;
-		}
 		else if (!strcmp(this_char,"nocase")) {
-			opts->nocase = 1;
-		}
-		else if (!strcmp(this_char,"nodots")) {
-			opts->dotsOK = 0;
+			if (!is_vfat)
+				opts->nocase = 1;
+			else {
+				/* for backward compatible */
+				opts->shortname = VFAT_SFN_DISPLAY_WIN95
+					| VFAT_SFN_CREATE_WIN95;
+			}
 		}
 		else if (!strcmp(this_char,"showexec")) {
 			opts->showexec = 1;
 		}
-		else if (!strcmp(this_char,"dotsOK") && value) {
-			if (!strcmp(value,"yes")) opts->dotsOK = 1;
-			else if (!strcmp(value,"no")) opts->dotsOK = 0;
-			else ret = 0;
-		}
 		else if (!strcmp(this_char,"uid")) {
 			if (!value || !*value) ret = 0;
 			else {
@@ -293,6 +369,13 @@
 				if (*value) ret = 0;
 			}
 		}
+		else if (!strcmp(this_char,"dmask")) {
+			if (!value || !*value) ret = 0;
+			else {
+				opts->fs_dmask = simple_strtoul(value,&value,8);
+				if (*value) ret = 0;
+			}
+		}
 		else if (!strcmp(this_char,"debug")) {
 			if (value) ret = 0;
 			else *debug = 1;
@@ -317,7 +400,32 @@
 			opts->codepage = simple_strtoul(value,&value,0);
 			if (*value) ret = 0;
 		}
-		else if (!strcmp(this_char,"iocharset") && value) {
+		else if (!strcmp(this_char,"cvf_format")) {
+			if (!value)
+				return 0;
+			strncpy(cvf_format,value,20);
+		}
+		else if (!strcmp(this_char,"cvf_options")) {
+			if (!value)
+				return 0;
+			strncpy(cvf_options,value,100);
+		}
+
+		/* msdos specific */
+		else if (!is_vfat && !strcmp(this_char,"dots")) {
+			opts->dotsOK = 1;
+		}
+		else if (!is_vfat && !strcmp(this_char,"nodots")) {
+			opts->dotsOK = 0;
+		}
+		else if (!is_vfat && !strcmp(this_char,"dotsOK") && value) {
+			if (!strcmp(value,"yes")) opts->dotsOK = 1;
+			else if (!strcmp(value,"no")) opts->dotsOK = 0;
+			else ret = 0;
+		}
+
+		/* vfat specific */
+		else if (is_vfat && !strcmp(this_char,"iocharset") && value) {
 			p = value;
 			while (*value && *value != ',')
 				value++;
@@ -338,23 +446,52 @@
 					ret = 0;
 			}
 		}
-		else if (!strcmp(this_char,"cvf_format")) {
-			if (!value)
-				return 0;
-			strncpy(cvf_format,value,20);
+		else if (is_vfat && !strcmp(this_char,"utf8")) {
+			ret = simple_getbool(value, &val);
+			if (ret) opts->utf8 = val;
+		}
+		else if (is_vfat && !strcmp(this_char,"uni_xlate")) {
+			ret = simple_getbool(value, &val);
+			if (ret) opts->unicode_xlate = val;
 		}
-		else if (!strcmp(this_char,"cvf_options")) {
-			if (!value)
-				return 0;
-			strncpy(cvf_options,value,100);
+		else if (is_vfat && !strcmp(this_char,"posix")) {
+			printk("FAT: posix option is obsolete, "
+			       "not supported now\n");
+		}
+		else if (is_vfat && !strcmp(this_char,"nonumtail")) {
+			ret = simple_getbool(value, &val);
+			if (ret) {
+				opts->numtail = !val;
+			}
+		}
+		else if (is_vfat && !strcmp(this_char, "shortname")) {
+			if (!strcmp(value, "lower"))
+				opts->shortname = VFAT_SFN_DISPLAY_LOWER
+						| VFAT_SFN_CREATE_WIN95;
+			else if (!strcmp(value, "win95"))
+				opts->shortname = VFAT_SFN_DISPLAY_WIN95
+						| VFAT_SFN_CREATE_WIN95;
+			else if (!strcmp(value, "winnt"))
+				opts->shortname = VFAT_SFN_DISPLAY_WINNT
+						| VFAT_SFN_CREATE_WINNT;
+			else if (!strcmp(value, "mixed"))
+				opts->shortname = VFAT_SFN_DISPLAY_WINNT
+						| VFAT_SFN_CREATE_WIN95;
+			else
+				ret = 0;
+		} else {
+			printk("FAT: Unrecognized mount option %s\n",
+			       this_char);
+			ret = 0;
 		}
 
-		if (options) *(options-1) = ',';
-		if (value) *savep = save;
 		if (ret == 0)
 			break;
 	}
 out:
+	if (opts->unicode_xlate)
+		opts->utf8 = 0;
+	
 	return ret;
 }
 
@@ -401,7 +538,7 @@
 	inode->i_gid = sbi->options.fs_gid;
 	inode->i_version++;
 	inode->i_generation = 0;
-	inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_umask) | S_IFDIR;
+	inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
 	inode->i_op = sbi->dir_ops;
 	inode->i_fop = &fat_dir_operations;
 	if (sbi->fat_bits == 32) {
@@ -617,6 +754,8 @@
 	clear_inode:	fat_clear_inode,
 
 	read_inode:	make_bad_inode,
+
+	show_options:	fat_show_options,
 };
 
 static struct export_operations fat_export_ops = {
@@ -639,7 +778,7 @@
 	int logical_sector_size, fat_clusters, debug, cp, first;
 	unsigned int total_sectors, rootdir_sectors;
 	unsigned char media;
-	long error = -EIO;
+	long error;
 	char buf[50];
 	int i;
 	char cvf_format[21];
@@ -658,11 +797,11 @@
 	sb->s_magic = MSDOS_SUPER_MAGIC;
 	sb->s_op = &fat_sops;
 	sb->s_export_op = &fat_export_ops;
-	sbi->options.isvfat = isvfat;
 	sbi->dir_ops = fs_dir_inode_ops;
 	sbi->cvf_format = &default_cvf;
 
-	if (!parse_options((char *)data, &debug, &sbi->options,
+	error = -EINVAL;
+	if (!parse_options((char *)data, isvfat, &debug, &sbi->options,
 			   cvf_format, cvf_options))
 		goto out_fail;
 
@@ -670,6 +809,7 @@
 	/* set up enough so that it can read an inode */
 	init_MUTEX(&sbi->fat_lock);
 
+	error = -EIO;
 	sb_min_blocksize(sb, 512);
 	bh = sb_bread(sb, 0);
 	if (bh == NULL) {
@@ -848,13 +988,14 @@
 		goto out_invalid;
 	}
 
+	error = -EINVAL;
 	if (!strcmp(cvf_format, "none"))
 		i = -1;
 	else
 		i = detect_cvf(sb, cvf_format);
 	if (i >= 0) {
 		if (cvf_formats[i]->mount_cvf(sb, cvf_options))
-			goto out_invalid;
+			goto out_fail;
 	}
 
 	cp = sbi->options.codepage ? sbi->options.codepage : 437;
@@ -869,8 +1010,6 @@
 		sbi->options.codepage = 0; /* already 0?? */
 		sbi->nls_disk = load_nls_default();
 	}
-	if (!silent)
-		printk("FAT: Using codepage %s\n", sbi->nls_disk->charset);
 
 	/* FIXME: utf8 is using iocharset for upper/lower conversion */
 	if (sbi->options.isvfat) {
@@ -883,9 +1022,6 @@
 			}
 		} else
 			sbi->nls_io = load_nls_default();
-		if (!silent)
-			printk("FAT: Using IO charset %s\n",
-			       sbi->nls_io->charset);
 	}
 
 	error = -ENOMEM;
@@ -912,6 +1048,9 @@
 
 out_invalid:
 	error = -EINVAL;
+	if (!silent)
+		printk(KERN_INFO "VFS: Can't find a valid FAT filesystem"
+		       " on dev %s.\n", sb->s_id);
 
 out_fail:
 	if (root_inode)
@@ -1026,8 +1165,8 @@
 	
 	if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
 		inode->i_generation &= ~1;
-		inode->i_mode = MSDOS_MKMODE(de->attr,S_IRWXUGO &
-		    ~sbi->options.fs_umask) | S_IFDIR;
+		inode->i_mode = MSDOS_MKMODE(de->attr,
+			S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR;
 		inode->i_op = sbi->dir_ops;
 		inode->i_fop = &fat_dir_operations;
 
@@ -1147,9 +1286,9 @@
 
 int fat_notify_change(struct dentry * dentry, struct iattr * attr)
 {
-	struct super_block *sb = dentry->d_sb;
+	struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
 	struct inode *inode = dentry->d_inode;
-	int error = 0;
+	int mask, error = 0;
 
 	lock_kernel();
 
@@ -1163,21 +1302,21 @@
 
 	error = inode_change_ok(inode, attr);
 	if (error) {
-		if( MSDOS_SB(sb)->options.quiet )
-		    error = 0; 
+		if (sbi->options.quiet)
+			error = 0;
  		goto out;
 	}
 
 	if (((attr->ia_valid & ATTR_UID) && 
-	     (attr->ia_uid != MSDOS_SB(sb)->options.fs_uid)) ||
+	     (attr->ia_uid != sbi->options.fs_uid)) ||
 	    ((attr->ia_valid & ATTR_GID) && 
-	     (attr->ia_gid != MSDOS_SB(sb)->options.fs_gid)) ||
+	     (attr->ia_gid != sbi->options.fs_gid)) ||
 	    ((attr->ia_valid & ATTR_MODE) &&
 	     (attr->ia_mode & ~MSDOS_VALID_MODE)))
 		error = -EPERM;
 
 	if (error) {
-		if( MSDOS_SB(sb)->options.quiet )  
+		if (sbi->options.quiet)  
 			error = 0;
 		goto out;
 	}
@@ -1186,11 +1325,10 @@
 		goto out;
 
 	if (S_ISDIR(inode->i_mode))
-		inode->i_mode |= S_IXUGO;
-
-	inode->i_mode = ((inode->i_mode & S_IFMT) | ((((inode->i_mode & S_IRWXU
-	    & ~MSDOS_SB(sb)->options.fs_umask) | S_IRUSR) >> 6)*S_IXUGO)) &
-	    ~MSDOS_SB(sb)->options.fs_umask;
+		mask = sbi->options.fs_dmask;
+	else
+		mask = sbi->options.fs_umask;
+	inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
 out:
 	unlock_kernel();
 	return error;
diff -Nru a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c	Tue Oct 15 20:29:12 2002
+++ b/fs/fcntl.c	Tue Oct 15 20:29:12 2002
@@ -10,7 +10,6 @@
 #include <linux/dnotify.h>
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
-#include <linux/iobuf.h>
 #include <linux/module.h>
 #include <linux/security.h>
 
diff -Nru a/fs/file_table.c b/fs/file_table.c
--- a/fs/file_table.c	Tue Oct 15 20:29:11 2002
+++ b/fs/file_table.c	Tue Oct 15 20:29:11 2002
@@ -11,7 +11,6 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
-#include <linux/iobuf.h>
 #include <linux/fs.h>
 #include <linux/security.h>
 
diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c	Tue Oct 15 20:29:17 2002
+++ b/fs/fs-writeback.c	Tue Oct 15 20:29:17 2002
@@ -327,6 +327,7 @@
 	}
 	spin_unlock(&sb_lock);
 	spin_unlock(&inode_lock);
+	blk_run_queues();
 }
 
 /*
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Tue Oct 15 20:29:23 2002
+++ b/fs/inode.c	Tue Oct 15 20:29:23 2002
@@ -243,22 +243,25 @@
  * Dispose-list gets a local list with local inodes in it, so it doesn't
  * need to worry about list corruption and SMP locks.
  */
-static void dispose_list(struct list_head * head)
+static void dispose_list(struct list_head *head)
 {
-	struct list_head * inode_entry;
-	struct inode * inode;
+	int nr_disposed = 0;
+
+	while (!list_empty(head)) {
+		struct inode *inode;
 
-	while ((inode_entry = head->next) != head)
-	{
-		list_del(inode_entry);
+		inode = list_entry(head->next, struct inode, i_list);
+		list_del(&inode->i_list);
 
-		inode = list_entry(inode_entry, struct inode, i_list);
 		if (inode->i_data.nrpages)
 			truncate_inode_pages(&inode->i_data, 0);
 		clear_inode(inode);
 		destroy_inode(inode);
-		inodes_stat.nr_inodes--;
+		nr_disposed++;
 	}
+	spin_lock(&inode_lock);
+	inodes_stat.nr_inodes -= nr_disposed;
+	spin_unlock(&inode_lock);
 }
 
 /*
@@ -377,7 +380,7 @@
 	 !inode_has_buffers(inode))
 #define INODE(entry)	(list_entry(entry, struct inode, i_list))
 
-void prune_icache(int goal)
+static inline void prune_icache(int goal)
 {
 	LIST_HEAD(list);
 	struct list_head *entry, *freeable = &list;
@@ -417,23 +420,19 @@
  * This is called from kswapd when we think we need some
  * more memory. 
  */
-int shrink_icache_memory(int ratio, unsigned int gfp_mask)
+static int shrink_icache_memory(int nr, unsigned int gfp_mask)
 {
-	int entries = inodes_stat.nr_inodes / ratio + 1;
-	/*
-	 * Nasty deadlock avoidance..
-	 *
-	 * We may hold various FS locks, and we don't
-	 * want to recurse into the FS that called us
-	 * in clear_inode() and friends..
-	 */
-	if (!(gfp_mask & __GFP_FS))
-		return 0;
-
-	prune_icache(entries);
-	return entries;
+	if (nr) {
+		/*
+		 * Nasty deadlock avoidance.  We may hold various FS locks,
+		 * and we don't want to recurse into the FS that called us
+		 * in clear_inode() and friends..
+	 	 */
+		if (gfp_mask & __GFP_FS)
+			prune_icache(nr);
+	}
+	return inodes_stat.nr_inodes;
 }
-EXPORT_SYMBOL(shrink_icache_memory);
 
 /*
  * Called with the inode lock held.
@@ -1226,4 +1225,6 @@
 					 NULL);
 	if (!inode_cachep)
 		panic("cannot create inode slab cache");
+
+	set_shrinker(DEFAULT_SEEKS, shrink_icache_memory);
 }
diff -Nru a/fs/intermezzo/Makefile b/fs/intermezzo/Makefile
--- a/fs/intermezzo/Makefile	Tue Oct 15 20:29:19 2002
+++ b/fs/intermezzo/Makefile	Tue Oct 15 20:29:19 2002
@@ -4,9 +4,11 @@
 
 obj-$(CONFIG_INTERMEZZO_FS) += intermezzo.o
 
-intermezzo-objs := journal_reiserfs.o cache.o journal.o presto.o vfs.o \
-		   psdev.o upcall.o methods.o sysctl.o dcache.o dir.o \
-		   super.o journal_ext2.o journal_ext3.o journal_xfs.o \
-		   inode.o  file.o journal_obdfs.o
+intermezzo-objs := cache.o dcache.o dir.o ext_attr.o file.o fileset.o \
+	           inode.o io_daemon.o journal.o journal_ext2.o journal_ext3.o \
+	           journal_obdfs.o journal_reiserfs.o journal_tmpfs.o journal_xfs.o \
+	           kml_reint.o kml_unpack.o methods.o presto.o psdev.o replicator.o \
+	           super.o sysctl.o upcall.o vfs.o
+
 
 include $(TOPDIR)/Rules.make
diff -Nru a/fs/intermezzo/cache.c b/fs/intermezzo/cache.c
--- a/fs/intermezzo/cache.c	Tue Oct 15 20:29:16 2002
+++ b/fs/intermezzo/cache.c	Tue Oct 15 20:29:16 2002
@@ -1,10 +1,23 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
  *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #define __NO_VERSION__
@@ -19,14 +32,14 @@
 #include <linux/ext2_fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 /*
@@ -37,24 +50,27 @@
    The methods for the cache are set up in methods.
 */
 
+extern kmem_cache_t * presto_dentry_slab;
+
 /* the intent of this hash is to have collision chains of length 1 */
 #define CACHES_BITS 8
 #define CACHES_SIZE (1 << CACHES_BITS)
 #define CACHES_MASK CACHES_SIZE - 1
 static struct list_head presto_caches[CACHES_SIZE];
 
-static inline int presto_cache_hash(struct super_block *sb)
+static inline int presto_cache_hash(kdev_t dev)
 {
-        return (CACHES_MASK) & ((unsigned long)sb / L1_CACHE_BYTES);
+        return (CACHES_MASK) & ((0x000F & (major(dev)) << 8) + (0x000F & minor(dev)));
 }
 
-inline void presto_cache_add(struct presto_cache *cache, struct super_block *sb)
+inline void presto_cache_add(struct presto_cache *cache, kdev_t dev)
 {
         list_add(&cache->cache_chain,
-                 &presto_caches[presto_cache_hash(sb)]);
+                 &presto_caches[presto_cache_hash(dev)]);
+        cache->cache_dev = dev;
 }
 
-inline void presto_init_cache_hash(void)
+inline void presto_cache_init_hash(void)
 {
         int i;
         for ( i = 0; i < CACHES_SIZE; i++ ) {
@@ -63,16 +79,17 @@
 }
 
 /* map a device to a cache */
-struct presto_cache *presto_find_cache(struct super_block *sb)
+struct presto_cache *presto_cache_find(kdev_t dev)
 {
         struct presto_cache *cache;
         struct list_head *lh, *tmp;
 
-        lh = tmp = &(presto_caches[presto_cache_hash(sb)]);
+        lh = tmp = &(presto_caches[presto_cache_hash(dev)]);
         while ( (tmp = lh->next) != lh ) {
                 cache = list_entry(tmp, struct presto_cache, cache_chain);
-                if (cache->cache_sb == sb)
+                if ( kdev_same(cache->cache_dev, dev) ) {
                         return cache;
+                }
         }
         return NULL;
 }
@@ -82,85 +99,19 @@
 struct presto_cache *presto_get_cache(struct inode *inode)
 {
         struct presto_cache *cache;
-
+        ENTRY;
         /* find the correct presto_cache here, based on the device */
-        cache = presto_find_cache(inode->i_sb);
+        cache = presto_cache_find(to_kdev_t(inode->i_dev));
         if ( !cache ) {
-                printk("WARNING: no presto cache for dev %s, ino %ld\n",
-                       inode->i_sb->s_id, inode->i_ino);
+                CERROR("WARNING: no presto cache for dev %x, ino %ld\n",
+                       inode->i_dev, inode->i_ino);
                 EXIT;
                 return NULL;
         }
+        EXIT;
         return cache;
 }
 
-
-/* list cache mount points for ioctl's or /proc/fs/intermezzo/mounts */
-int presto_sprint_mounts(char *buf, int buflen, int minor)
-{
-        int len = 0;
-        int i;
-        struct list_head *head, *tmp;
-        struct presto_cache *cache;
-
-        buf[0] = '\0';
-        for (i=0 ; i<CACHES_SIZE ; i++) {
-                head = tmp = &presto_caches[i];
-                while ( (tmp = tmp->next) != head ) {
-                        cache = list_entry(tmp, struct presto_cache,
-                                            cache_chain);
-                        if ( !cache->cache_root_fileset || !cache->cache_mtpt)
-                                continue;
-                        if ((minor != -1) &&
-                            (cache->cache_psdev->uc_minor != minor))
-                                continue;
-                        if ( strlen(cache->cache_root_fileset) +
-                             strlen(cache->cache_mtpt) + 
-                             strlen(cache->cache_psdev->uc_devname) +
-                             4 > buflen - len)
-                                break;
-                        len += sprintf(buf + len, "%s %s %s\n",
-                                       cache->cache_root_fileset,
-                                       cache->cache_mtpt,
-                                       cache->cache_psdev->uc_devname);
-                }
-        }
-
-        buf[buflen-1] = '\0';
-        CDEBUG(D_SUPER, "%s\n", buf);
-        return len;
-}
-
-#ifdef CONFIG_KREINT
-/* get mount point by volname
-       Arthur Ma, 2000.12.25
- */
-int presto_get_mount (char *buf, int buflen, char *volname)
-{
-        int i;
-        struct list_head *head, *tmp;
-        struct presto_cache *cache = NULL;
-        char *path = "";
-
-        buf[0] = '\0';
-        for (i=0 ; i<CACHES_SIZE ; i++) {
-                head = tmp = &presto_caches[i];
-                while ( (tmp = tmp->next) != head ) {
-                        cache = list_entry(tmp, struct presto_cache,
-                                            cache_chain);
-                        if ( !cache->cache_root_fileset || !cache->cache_mtpt)
-                                continue;
-                        if ( strcmp(cache->cache_root_fileset, volname) == 0)
-                                break;
-                }
-        }
-        if (cache != NULL)
-                path = cache->cache_mtpt;
-        strncpy (buf, path, buflen);
-        return strlen (buf);
-}
-#endif
-
 /* another debugging routine: check fs is InterMezzo fs */
 int presto_ispresto(struct inode *inode)
 {
@@ -171,27 +122,25 @@
         cache = presto_get_cache(inode);
         if ( !cache )
                 return 0;
-        return (inode->i_sb == cache->cache_sb);
+        return kdev_same(to_kdev_t(inode->i_dev), cache->cache_dev);
 }
 
 /* setup a cache structure when we need one */
-struct presto_cache *presto_init_cache(void)
+struct presto_cache *presto_cache_init(void)
 {
         struct presto_cache *cache;
 
-        /* make a presto_cache structure for the hash */
-        PRESTO_ALLOC(cache, struct presto_cache *, sizeof(struct presto_cache));
+        PRESTO_ALLOC(cache, sizeof(struct presto_cache));
         if ( cache ) {
                 memset(cache, 0, sizeof(struct presto_cache));
                 INIT_LIST_HEAD(&cache->cache_chain);
                 INIT_LIST_HEAD(&cache->cache_fset_list);
+                cache->cache_lock = SPIN_LOCK_UNLOCKED;
+                cache->cache_reserved = 0; 
         }
-	cache->cache_lock = SPIN_LOCK_UNLOCKED;
-	cache->cache_reserved = 0; 
         return cache;
 }
 
-
 /* free a cache structure and all of the memory it is pointing to */
 inline void presto_free_cache(struct presto_cache *cache)
 {
@@ -199,12 +148,12 @@
                 return;
 
         list_del(&cache->cache_chain);
-        if (cache->cache_mtpt)
-                PRESTO_FREE(cache->cache_mtpt, strlen(cache->cache_mtpt) + 1);
-        if (cache->cache_type)
-                PRESTO_FREE(cache->cache_type, strlen(cache->cache_type) + 1);
-        if (cache->cache_root_fileset)
-                PRESTO_FREE(cache->cache_root_fileset, strlen(cache->cache_root_fileset) + 1);
+        if (cache->cache_sb && cache->cache_sb->s_root &&
+                        presto_d2d(cache->cache_sb->s_root)) {
+                kmem_cache_free(presto_dentry_slab, 
+                                presto_d2d(cache->cache_sb->s_root));
+                cache->cache_sb->s_root->d_fsdata = NULL;
+        }
 
         PRESTO_FREE(cache, sizeof(struct presto_cache));
 }
@@ -213,41 +162,43 @@
 {
         struct filter_fs *filter; 
         loff_t avail; 
-	struct super_block *sb = cache->cache_sb;
+        struct super_block *sb = cache->cache_sb;
         filter = cache->cache_filter;
-	if (!filter ) {
-		EXIT;
-		return 0; 
-	}
-	if (!filter->o_trops ) {
-		EXIT;
-		return 0; 
-	}
-	if (!filter->o_trops->tr_avail ) {
-		EXIT;
-		return 0; 
-	}
+        if (!filter ) {
+                EXIT;
+                return 0; 
+        }
+        if (!filter->o_trops ) {
+                EXIT;
+                return 0; 
+        }
+        if (!filter->o_trops->tr_avail ) {
+                EXIT;
+                return 0; 
+        }
+
+        spin_lock(&cache->cache_lock);
         avail = filter->o_trops->tr_avail(cache, sb); 
         CDEBUG(D_SUPER, "ESC::%ld +++> %ld \n", (long) cache->cache_reserved,
-	         (long) (cache->cache_reserved + req)); 
+                 (long) (cache->cache_reserved + req)); 
         CDEBUG(D_SUPER, "ESC::Avail::%ld \n", (long) avail);
-	spin_lock(&cache->cache_lock);
         if (req + cache->cache_reserved > avail) {
-		spin_unlock(&cache->cache_lock);
+                spin_unlock(&cache->cache_lock);
                 EXIT;
                 return -ENOSPC;
         }
-	cache->cache_reserved += req; 
-	spin_unlock(&cache->cache_lock);
+        cache->cache_reserved += req; 
+        spin_unlock(&cache->cache_lock);
 
+        EXIT;
         return 0;
 }
 
 void presto_release_space(struct presto_cache *cache, loff_t req)
 {
         CDEBUG(D_SUPER, "ESC::%ld ---> %ld \n", (long) cache->cache_reserved,
-	         (long) (cache->cache_reserved - req)); 
-	spin_lock(&cache->cache_lock);
-	cache->cache_reserved -= req; 
-	spin_unlock(&cache->cache_lock);
+                 (long) (cache->cache_reserved - req)); 
+        spin_lock(&cache->cache_lock);
+        cache->cache_reserved -= req; 
+        spin_unlock(&cache->cache_lock);
 }
diff -Nru a/fs/intermezzo/dcache.c b/fs/intermezzo/dcache.c
--- a/fs/intermezzo/dcache.c	Tue Oct 15 20:29:20 2002
+++ b/fs/intermezzo/dcache.c	Tue Oct 15 20:29:20 2002
@@ -1,126 +1,333 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Original version: Copyright (C) 1996 P. Braam and M. Callahan
+ *  Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University
+ *  d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  * Directory operations for InterMezzo filesystem
- * Original version: (C) 1996 P. Braam and M. Callahan
- * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
+ */
+
+/* inode dentry alias list walking code adapted from linux/fs/dcache.c
+ *
+ * fs/dcache.c
  *
- * Stelias encourages users to contribute improvements to
- * the InterMezzo project. Contact Peter Braam (coda@stelias.com).
+ * (C) 1997 Thomas Schoebel-Theuer,
+ * with heavy changes by Linus Torvalds
  */
 
 #define __NO_VERSION__
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
 #include <linux/slab.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
 
 #include <linux/intermezzo_fs.h>
 
-static int presto_dentry_revalidate(struct dentry *de, int );
 static kmem_cache_t * presto_dentry_slab;
 
 /* called when a cache lookup succeeds */
-static int presto_dentry_revalidate(struct dentry *de, int flag)
+static int presto_d_revalidate(struct dentry *de, int flag)
 {
-	struct inode *inode = de->d_inode;
-	ENTRY;
-	if (!inode) {
-		EXIT;
-		return 1;
-	}
-	if (is_bad_inode(inode)) {
-		EXIT;
-		return 0;
-	}
-
-	if ( S_ISDIR(inode->i_mode) ) {
-		EXIT;
-		return (presto_chk(de, PRESTO_DATA) &&
-			(presto_chk(de, PRESTO_ATTR)));
-	} else {
-		EXIT;
-		return presto_chk(de, PRESTO_ATTR);
-	}
+        struct inode *inode = de->d_inode;
+        struct presto_file_set * root_fset;
+
+        ENTRY;
+        if (!inode) {
+                EXIT;
+                return 0;
+        }
+
+        if (is_bad_inode(inode)) {
+                EXIT;
+                return 0;
+        }
+
+        if (!presto_d2d(de)) {
+                presto_set_dd(de);
+        }
+
+        if (!presto_d2d(de)) {
+                EXIT;
+                return 0;
+        }
+
+        root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset;
+        if (root_fset->fset_flags & FSET_FLAT_BRANCH && 
+            (presto_d2d(de)->dd_fset != root_fset )) {
+                presto_d2d(de)->dd_fset = root_fset;
+        }
+
+        EXIT;
+        return 1;
+
+#if 0
+        /* The following is needed for metadata on demand. */
+        if ( S_ISDIR(inode->i_mode) ) {
+                EXIT;
+                return (presto_chk(de, PRESTO_DATA) &&
+                        (presto_chk(de, PRESTO_ATTR)));
+        } else {
+                EXIT;
+                return presto_chk(de, PRESTO_ATTR);
+        }
+#endif
 }
 
 static void presto_d_release(struct dentry *dentry)
 {
         if (!presto_d2d(dentry)) {
-                /* This should really only happen in the case of a dentry
-                 * with no inode. */
+                /* This can happen for dentries from NFSd */
                 return;
         }
-
         presto_d2d(dentry)->dd_count--;
 
-        if (! presto_d2d(dentry)->dd_count) {
+        if (!presto_d2d(dentry)->dd_count) {
                 kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
-		dentry->d_fsdata = NULL;
+                dentry->d_fsdata = NULL;
         }
 }
 
 struct dentry_operations presto_dentry_ops = 
 {
-	d_revalidate: presto_dentry_revalidate,
-        d_release: presto_d_release
+        .d_revalidate =  presto_d_revalidate,
+        .d_release = presto_d_release
 };
 
+static inline int presto_is_dentry_ROOT (struct dentry *dentry)
+{
+        return(dentry_name_cmp(dentry,"ROOT") &&
+               !dentry_name_cmp(dentry->d_parent,".intermezzo"));
+}
 
-// XXX THIS DEPENDS ON THE KERNEL LOCK!
+static struct presto_file_set* presto_try_find_fset(struct dentry* dentry,
+                int *is_under_d_intermezzo)
+{
+        struct dentry* temp_dentry;
+        struct presto_dentry_data *d_data;
+        int found_root=0;
 
-void presto_set_dd(struct dentry * dentry)
+        ENTRY;
+        CDEBUG(D_FSDATA, "finding fileset for %p:%s\n", dentry, 
+                        dentry->d_name.name);
+
+        *is_under_d_intermezzo = 0;
+
+        /* walk up through the branch to get the fileset */
+        /* The dentry we are passed presumably does not have the correct
+         * fset information. However, we still want to start walking up
+         * the branch from this dentry to get our found_root and 
+         * is_under_d_intermezzo decisions correct
+         */
+        for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) {
+                CDEBUG(D_FSDATA, "--->dentry %p:%*s\n", temp_dentry, 
+                        temp_dentry->d_name.len,temp_dentry->d_name.name);
+                if (presto_is_dentry_ROOT(temp_dentry))
+                        found_root = 1;
+                if (!found_root &&
+                    dentry_name_cmp(temp_dentry, ".intermezzo")) {
+                        *is_under_d_intermezzo = 1;
+                }
+                d_data = presto_d2d(temp_dentry);
+                if (d_data) {
+                        /* If we found a "ROOT" dentry while walking up the
+                         * branch, we will journal regardless of whether
+                         * we are under .intermezzo or not.
+                         * If we are already under d_intermezzo don't reverse
+                         * the decision here...even if we found a "ROOT"
+                         * dentry above .intermezzo (if we were ever to
+                         * modify the directory structure).
+                         */
+                        if (!*is_under_d_intermezzo)  
+                                *is_under_d_intermezzo = !found_root &&
+                                  (d_data->dd_flags & PRESTO_DONT_JOURNAL);
+                        EXIT;
+                        return d_data->dd_fset;
+                }
+                if (temp_dentry->d_parent == temp_dentry) {
+                        break;
+                }
+        }
+        EXIT;
+        return NULL;
+}
+
+/* Only call this function on positive dentries */
+static struct presto_dentry_data* presto_try_find_alias_with_dd (
+                  struct dentry* dentry)
+{
+        struct inode *inode=dentry->d_inode;
+        struct list_head *head, *next, *tmp;
+        struct dentry *tmp_dentry;
+
+        /* Search through the alias list for dentries with d_fsdata */
+        spin_lock(&dcache_lock);
+        head = &inode->i_dentry;
+        next = inode->i_dentry.next;
+        while (next != head) {
+                tmp = next;
+                next = tmp->next;
+                tmp_dentry = list_entry(tmp, struct dentry, d_alias);
+                if (!presto_d2d(tmp_dentry)) {
+                        spin_unlock(&dcache_lock);
+                        return presto_d2d(tmp_dentry);
+                }
+        }
+        spin_unlock(&dcache_lock);
+        return NULL;
+}
+
+/* Only call this function on positive dentries */
+static void presto_set_alias_dd (struct dentry *dentry, 
+                struct presto_dentry_data* dd)
+{
+        struct inode *inode=dentry->d_inode;
+        struct list_head *head, *next, *tmp;
+        struct dentry *tmp_dentry;
+
+        /* Set d_fsdata for this dentry */
+        dd->dd_count++;
+        dentry->d_fsdata = dd;
+
+        /* Now set d_fsdata for all dentries in the alias list. */
+        spin_lock(&dcache_lock);
+        head = &inode->i_dentry;
+        next = inode->i_dentry.next;
+        while (next != head) {
+                tmp = next;
+                next = tmp->next;
+                tmp_dentry = list_entry(tmp, struct dentry, d_alias);
+                if (!presto_d2d(tmp_dentry)) {
+                        dd->dd_count++;
+                        tmp_dentry->d_fsdata = dd;
+                }
+        }
+        spin_unlock(&dcache_lock);
+        return;
+}
+
+inline struct presto_dentry_data *izo_alloc_ddata(void)
+{
+        struct presto_dentry_data *dd;
+
+        dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
+        if (dd == NULL) {
+                CERROR("IZO: out of memory trying to allocate presto_dentry_data\n");
+                return NULL;
+        }
+        memset(dd, 0, sizeof(*dd));
+        dd->dd_count = 1;
+
+        return dd;
+}
+
+/* This uses the BKL! */
+int presto_set_dd(struct dentry * dentry)
 {
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd;
+        int is_under_d_izo;
+        int error=0;
+
         ENTRY;
-        if (dentry == NULL)
+
+        if (!dentry)
                 BUG();
 
+        lock_kernel();
+
+        /* Did we lose a race? */
         if (dentry->d_fsdata) {
-                printk("VERY BAD: dentry: %p\n", dentry);
+                CERROR("dentry %p already has d_fsdata set\n", dentry);
                 if (dentry->d_inode)
-                        printk("    inode: %ld\n", dentry->d_inode->i_ino);
+                        CERROR("    inode: %ld\n", dentry->d_inode->i_ino);
                 EXIT;
-                return;
+                goto out_unlock;
         }
 
-        if (dentry->d_inode == NULL) {
-                dentry->d_fsdata = kmem_cache_alloc(presto_dentry_slab,
-                                                    SLAB_KERNEL);
-                memset(dentry->d_fsdata, 0, sizeof(struct presto_dentry_data));
-                presto_d2d(dentry)->dd_count = 1;
-                EXIT;
-                return;
+        if (dentry->d_inode != NULL) {
+                /* NFSd runs find_fh_dentry which instantiates disconnected
+                 * dentries which are then connected without a lookup(). 
+                 * So it is possible to have connected dentries that do not 
+                 * have d_fsdata set. So we walk the list trying to find 
+                 * an alias which has its d_fsdata set and then use that 
+                 * for all the other dentries  as well. 
+                 * - SHP,Vinny. 
+                 */
+
+                /* If there is an alias with d_fsdata use it. */
+                if ((dd = presto_try_find_alias_with_dd (dentry))) {
+                        presto_set_alias_dd (dentry, dd);
+                        EXIT;
+                        goto out_unlock;
+                }
+        } else {
+                /* Negative dentry */
+                CDEBUG(D_FSDATA,"negative dentry %p: %*s\n", dentry, 
+                                dentry->d_name.len, dentry->d_name.name);
         }
 
-        /* If there's already a dentry for this inode, share the data */
-        if (dentry->d_alias.next != &dentry->d_inode->i_dentry ||
-            dentry->d_alias.prev != &dentry->d_inode->i_dentry) {
-                struct dentry *de;
-
-                if (dentry->d_alias.next != &dentry->d_inode->i_dentry)
-                        de = list_entry(dentry->d_alias.next, struct dentry,
-                                        d_alias);
-                else
-                        de = list_entry(dentry->d_alias.prev, struct dentry,
-                                        d_alias);
-
-                dentry->d_fsdata = de->d_fsdata;
-                presto_d2d(dentry)->dd_count++;
+        /* No pre-existing d_fsdata, we need to construct one.
+         * First, we must walk up the tree to find the fileset 
+         * If a fileset can't be found, we leave a null fsdata
+         * and return EROFS to indicate that we can't journal
+         * updates. 
+         */
+        fset = presto_try_find_fset (dentry, &is_under_d_izo);
+        if (!fset) { 
+#ifdef PRESTO_NO_NFS
+                CERROR("No fileset for dentry %p: %*s\n", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
+#endif
+                error = -EROFS;
                 EXIT;
-                return;
+                goto out_unlock;
         }
 
-        dentry->d_fsdata = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
-        memset(dentry->d_fsdata, 0, sizeof(struct presto_dentry_data));
-        presto_d2d(dentry)->dd_count = 1;
+        dentry->d_fsdata = izo_alloc_ddata();
+        if (!presto_d2d(dentry)) {
+                CERROR ("InterMezzo: out of memory allocating d_fsdata\n");
+                error = -ENOMEM;
+                goto out_unlock;
+        }
+        presto_d2d(dentry)->dd_fset = fset;
+        if (is_under_d_izo)
+                presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL;
         EXIT;
-        return; 
+
+out_unlock:    
+        CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %p\n", 
+                        dentry, dentry->d_name.len, dentry->d_name.name, 
+                        dentry->d_fsdata);
+        unlock_kernel();
+        return error; 
 }
 
-void presto_init_ddata_cache(void)
+int presto_init_ddata_cache(void)
 {
         ENTRY;
         presto_dentry_slab =
@@ -129,6 +336,7 @@
                                   SLAB_HWCACHE_ALIGN, NULL,
                                   NULL);
         EXIT;
+        return (presto_dentry_slab != NULL);
 }
 
 void presto_cleanup_ddata_cache(void)
diff -Nru a/fs/intermezzo/dir.c b/fs/intermezzo/dir.c
--- a/fs/intermezzo/dir.c	Tue Oct 15 20:29:14 2002
+++ b/fs/intermezzo/dir.c	Tue Oct 15 20:29:14 2002
@@ -1,68 +1,83 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 Tacitus Systems
  *  Copyright (C) 2000 Peter J. Braam
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include <stdarg.h>
 
 #include <asm/bitops.h>
+#include <asm/ioctls.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/smp_lock.h>
 
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/namei.h>
 #include <linux/ext2_fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 static inline void presto_relock_sem(struct inode *dir) 
 {
-	/* the lock from sys_mkdir / lookup_create */
-	down(&dir->i_sem);
-	/* the rest is done by the do_{create,mkdir, ...} */
+        /* the lock from sys_mkdir / lookup_create */
+        down(&dir->i_sem);
+        /* the rest is done by the do_{create,mkdir, ...} */
 }
 
 static inline void presto_relock_other(struct inode *dir) 
 {
-	/* vfs_mkdir locks */
-        down(&dir->i_zombie);
-	lock_kernel(); 
+        /* vfs_mkdir locks */
+        //        down(&dir->i_zombie);
+        lock_kernel(); 
 }
 
 static inline void presto_fulllock(struct inode *dir) 
 {
-	/* the lock from sys_mkdir / lookup_create */
-	down(&dir->i_sem);
-	/* vfs_mkdir locks */
-        down(&dir->i_zombie);
-	lock_kernel(); 
+        /* the lock from sys_mkdir / lookup_create */
+        down(&dir->i_sem);
+        /* vfs_mkdir locks */
+        //        down(&dir->i_zombie);
+        lock_kernel(); 
 }
 
 static inline void presto_unlock(struct inode *dir) 
 {
-	/* vfs_mkdir locks */
-	unlock_kernel(); 
-        up(&dir->i_zombie);
-	/* the lock from sys_mkdir / lookup_create */
-	up(&dir->i_sem);
+        /* vfs_mkdir locks */
+        unlock_kernel(); 
+        //        up(&dir->i_zombie);
+        /* the lock from sys_mkdir / lookup_create */
+        up(&dir->i_sem);
 }
 
 
@@ -70,123 +85,83 @@
  * these are initialized in super.c
  */
 extern int presto_permission(struct inode *inode, int mask);
-int presto_ilookup_uid = 0;
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
+static int izo_authorized_uid = 0;
 
-static int dentry2id(struct dentry *dentry, ino_t *id, unsigned int *generation)
+int izo_dentry_is_ilookup(struct dentry *dentry, ino_t *id,
+                          unsigned int *generation)
 {
-        char *tmpname;
+        char tmpname[64];
         char *next;
-        int error = 0;
 
         ENTRY;
-        if (dentry->d_name.len > EXT2_NAME_LEN) {
-                EXIT;
-                return -ENAMETOOLONG;
-        }
-
         /* prefix is 7 characters: '...ino:' */
-        if ( dentry->d_name.len < 7 ||
+        if ( dentry->d_name.len < 7 || dentry->d_name.len > 64 ||
              memcmp(dentry->d_name.name, PRESTO_ILOOKUP_MAGIC, 7) != 0 ) {
                 EXIT;
-                return 1;
-        }
-
-        PRESTO_ALLOC(tmpname, char *, dentry->d_name.len - 7 + 1);
-        if ( !tmpname ) {
-                EXIT;
-                return -ENOMEM;
+                return 0;
         }
 
         memcpy(tmpname, dentry->d_name.name + 7, dentry->d_name.len - 7);
-        *(tmpname + dentry->d_name.len) = '\0';
+        *(tmpname + dentry->d_name.len - 7) = '\0';
 
-        /* name is of the form <inode number>:<generation> */
-        *id = simple_strtoul(tmpname, &next, 0);
+        /* name is of the form ...ino:<inode number>:<generation> */
+        *id = simple_strtoul(tmpname, &next, 16);
         if ( *next == PRESTO_ILOOKUP_SEP ) {
-                *generation = simple_strtoul(next + 1, 0, 0);
-                CDEBUG(D_INODE, "INO to find = %s\n", tmpname);
-                CDEBUG(D_INODE, "Id = %lx (%lu), generation %x (%d)\n",
-                       *id, *id, *generation, *generation);
-        } else
-                error = 1;
-
-        PRESTO_FREE(tmpname, dentry->d_name.len - 7 + 1);
-        EXIT;
-        return error;
+                *generation = simple_strtoul(next + 1, 0, 16);
+                CDEBUG(D_INODE, "ino string: %s, Id = %lx (%lu), "
+                       "generation %x (%d)\n",
+                       tmpname, *id, *id, *generation, *generation);
+                EXIT;
+                return 1;
+        } else {
+                EXIT;
+                return 0;
+        }
 }
 
-static int presto_opendir_upcall(int minor, struct dentry *de, 
-                          struct dentry *root, int async)
+struct dentry *presto_tmpfs_ilookup(struct inode *dir, 
+                                    struct dentry *dentry,
+                                    ino_t ino, 
+                                    unsigned int generation)
 {
-        int rc;
-        char *path, *buffer;
-        int pathlen;
-
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
-        if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
-                return ENOMEM;
-        }
-        path = presto_path(de, root, buffer, PAGE_SIZE);
-        pathlen = MYPATHLEN(buffer, path);
-        CDEBUG(D_INODE, "path: %*s, len %d\n", pathlen, path, pathlen);
-        rc = lento_opendir(minor, pathlen, path, async);
-        PRESTO_FREE(buffer, PAGE_SIZE);
-        return rc;
+        return dentry; 
 }
 
+
 inline int presto_can_ilookup(void)
 {
-        return (current->euid == presto_ilookup_uid ||
+        return (current->euid == izo_authorized_uid ||
                 capable(CAP_DAC_READ_SEARCH));
 }
 
-struct dentry *presto_ilookup(struct inode *dir, struct dentry *dentry,
-                            ino_t ino, unsigned int generation)
+struct dentry *presto_iget_ilookup(struct inode *dir, 
+                                          struct dentry *dentry,
+                                          ino_t ino, 
+                                          unsigned int generation)
 {
         struct inode *inode;
         int error;
 
         ENTRY;
 
-        /* if we can't ilookup, forbid anything with this name to
-         * avoid any security issues/name clashes.
-         */
         if ( !presto_can_ilookup() ) {
-                CDEBUG(D_CACHE, "ilookup denied: euid %u, ilookup_uid %u\n",
-                       current->euid, presto_ilookup_uid);
-                EXIT;
+                CERROR("ilookup denied: euid %u, authorized_uid %u\n",
+                       current->euid, izo_authorized_uid);
                 return ERR_PTR(-EPERM);
         }
+        error = -ENOENT;
         inode = iget(dir->i_sb, ino);
-        if (!inode || is_bad_inode(inode)) {
-                CDEBUG(D_PIOCTL, "fatal: invalid inode %ld (%s).\n",
-                       ino, inode ? inode->i_nlink ? "bad inode" :
-                       "no links" : "NULL");
-                error = -ENOENT;
-                EXIT;
+        if (!inode) { 
+                CERROR("fatal: NULL inode ino %lu\n", ino); 
+                goto cleanup_iput;
+        }
+        if (is_bad_inode(inode) || inode->i_nlink == 0) {
+                CERROR("fatal: bad inode ino %lu, links %d\n", ino, inode->i_nlink); 
                 goto cleanup_iput;
-        } else if (inode->i_nlink == 0) {
-                /* This is quite evil, but we have little choice.  If we were
-                 * to iput() again with i_nlink == 0, delete_inode would get
-                 * called again, which ext3 really Does Not Like. */
-                atomic_dec(&inode->i_count);
-                EXIT;
-                return ERR_PTR(-ENOENT);
         }
-
-        /* We need to make sure we have the right inode (by checking the
-         * generation) so we don't write into the wrong file (old inode was
-         * deleted and then a new one was created with the same number).
-         */
         if (inode->i_generation != generation) {
-                CDEBUG(D_PIOCTL, "fatal: bad generation %u (want %u)\n",
+                CERROR("fatal: bad generation %u (want %u)\n",
                        inode->i_generation, generation);
-                error = -ENOENT;
-                EXIT;
                 goto cleanup_iput;
         }
 
@@ -202,76 +177,164 @@
         return ERR_PTR(error);
 }
 
+struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
+                                         struct dentry *real)
+{
+        struct inode *inode = real->d_inode;
+        struct dentry *de;
+        char buf[32];
+        char *ptr = buf;
+        struct dentry *inodir;
+        struct presto_dentry_data *dd;
+
+        inodir = lookup_one_len("..iopen..", parent,  strlen("..iopen..")); 
+        if (!inodir || IS_ERR(inodir) || !inodir->d_inode ) { 
+                CERROR("%s: bad ..iopen.. lookup\n", __FUNCTION__); 
+                return NULL; 
+        }
+        inodir->d_inode->i_op = &presto_dir_iops;
+
+        snprintf(ptr, 32, "...ino:%lx:%x", inode->i_ino, inode->i_generation);
+
+        de = lookup_one_len(ptr, inodir,  strlen(ptr)); 
+        if (!de || IS_ERR(de)) {
+                CERROR("%s: bad ...ino lookup %ld\n", 
+                       __FUNCTION__, PTR_ERR(de)); 
+                dput(inodir);
+                return NULL; 
+        }
+
+        dd = presto_d2d(real);
+        if (!dd) 
+                BUG();
+
+        /* already exists */
+        if (de->d_inode)
+                BUG();
+#if 0 
+                if (de->d_inode != inode ) { 
+                        CERROR("XX de->d_inode %ld, inode %ld\n", 
+                               de->d_inode->i_ino, inode->i_ino); 
+                        BUG();
+                }
+                if (dd->dd_inodentry) { 
+                        CERROR("inodentry exists %ld \n", inode->i_ino);
+                        BUG();
+                }
+                dput(inodir);
+                return de;
+        }
+#endif 
+
+        if (presto_d2d(de)) 
+                BUG();
+
+        atomic_inc(&inode->i_count);
+        de->d_op = &presto_dentry_ops;
+        d_add(de, inode);
+        if (!de->d_op)
+                CERROR("DD: no ops dentry %p, dd %p\n", de, dd);
+        dd->dd_inodentry = de;
+        dd->dd_count++;
+        de->d_fsdata = dd;
+
+        dput(inodir);
+        return de;
+}
 
 struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry)
 {
         int rc = 0;
         struct dentry *de;
         struct presto_cache *cache;
-        struct presto_file_set *fset;
-        int error; 
         int minor;
         ino_t ino;
         unsigned int generation;
+        struct inode_operations *iops;
+        int is_ilookup = 0;
 
         ENTRY;
-        CDEBUG(D_CACHE, "calling presto_prep on dentry %p\n", dentry);
-        error = presto_prep(dentry->d_parent, &cache, &fset);
-        if ( error  ) {
+        cache = presto_get_cache(dir);
+        if (cache == NULL) {
+                CERROR("InterMezzo BUG: no cache in presto_lookup "
+                       "(dir ino: %ld)!\n", dir->i_ino);
                 EXIT;
-                return ERR_PTR(error);
+                return NULL;
         }
         minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "dir ino: %ld, name: %*s\n",
-               dir->i_ino, dentry->d_name.len, dentry->d_name.name);
-        if ( ISLENTO(minor) )
-                CDEBUG(D_CACHE, "We are lento\n");
-
-        rc = dentry2id(dentry, &ino, &generation);
-        CDEBUG(D_CACHE, "dentry2id returned %d\n", rc);
-        if ( rc < 0 ) {
-                EXIT;
-                goto exit;
+        iops = filter_c2cdiops(cache->cache_filter);
+        if (!iops || !iops->lookup) {
+                CERROR("InterMezzo BUG: filesystem has no lookup\n");
+                EXIT;
+                return NULL;
         }
 
-        if ( rc == 0 ) {
-                de = presto_ilookup(dir, dentry, ino, generation);
-        } else {
-                struct inode_operations *iops = filter_c2cdiops(cache->cache_filter);
-                rc = 0;
-                /* recursively do a cache lookup in dir */
-                if (iops && iops->lookup) 
+
+        CDEBUG(D_CACHE, "dentry %p, dir ino: %ld, name: %*s, islento: %d\n",
+               dentry, dir->i_ino, dentry->d_name.len, dentry->d_name.name,
+               ISLENTO(minor));
+
+        if (dentry->d_fsdata)
+                CERROR("DD -- BAD dentry %p has data\n", dentry);
+                       
+        dentry->d_fsdata = NULL;
+#if 0
+        if (ext2_check_for_iopen(dir, dentry))
+                de = NULL;
+        else {
+#endif
+                if ( izo_dentry_is_ilookup(dentry, &ino, &generation) ) { 
+                        de = cache->cache_filter->o_trops->tr_ilookup
+                                (dir, dentry, ino, generation);
+                        is_ilookup = 1;
+                } else
                         de = iops->lookup(dir, dentry);
-                else {
-		        printk("filesystem has no lookup\n");
-                        EXIT;
-                        goto exit;
-                }
+#if 0
         }
-        /* XXX this needs some work to handle returning de if we get it */
-        filter_setup_dentry_ops(cache->cache_filter, 
-                                dentry->d_op, &presto_dentry_ops);
-        dentry->d_op = filter_c2udops(cache->cache_filter);
+#endif
+
         if ( IS_ERR(de) ) {
-                rc = PTR_ERR(de);
-                CDEBUG(D_CACHE, "dentry lookup error %d\n", rc);
-                EXIT;
-                goto exit;
+                CERROR("dentry lookup error %ld\n", PTR_ERR(de));
+                return de;
         }
 
-        presto_set_dd(dentry);
+        /* some file systems have no read_inode: set methods here */
+        if (dentry->d_inode)
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
+        filter_setup_dentry_ops(cache->cache_filter,
+                                dentry->d_op, &presto_dentry_ops);
+        dentry->d_op = filter_c2udops(cache->cache_filter);
+
+        /* In lookup we will tolerate EROFS return codes from presto_set_dd
+         * to placate NFS. EROFS indicates that a fileset was not found but
+         * we should still be able to continue through a lookup.
+         * Anything else is a hard error and must be returned to VFS. */
+        if (!is_ilookup)
+                rc = presto_set_dd(dentry);
+        if (rc && rc != -EROFS) {
+                CERROR("presto_set_dd failed (dir %ld, name %*s): %d\n",
+                       dir->i_ino, dentry->d_name.len, dentry->d_name.name, rc);
+                return ERR_PTR(rc);
+        }
 
-        /* some file systems set the methods in lookup, not in
-           read_inode, as a result we should set the methods here 
-           as well as in read_inode 
-        */
-	if (dentry->d_inode) {
-		presto_set_ops(dentry->d_inode, cache->cache_filter); 
-	}
         EXIT;
-exit:
-        return ERR_PTR(rc);
+        return NULL;
+}
+
+static inline int presto_check_set_fsdata (struct dentry *de)
+{
+        if (presto_d2d(de) == NULL) {
+#ifdef PRESTO_NO_NFS
+                CERROR("dentry without fsdata: %p: %*s\n", de, 
+                                de->d_name.len, de->d_name.name);
+                BUG();
+#endif
+                return presto_set_dd (de);
+        }
+
+        return 0;
 }
 
 int presto_setattr(struct dentry *de, struct iattr *iattr)
@@ -281,13 +344,12 @@
         struct presto_file_set *fset;
         struct lento_vfs_context info = { 0, 0, 0 };
 
-	lock_kernel();	
-
         ENTRY;
+
         error = presto_prep(de, &cache, &fset);
         if ( error ) {
                 EXIT;
-                goto out;        
+                return error;
         }
 
         if (!iattr->ia_valid)
@@ -301,17 +363,14 @@
         
         if ( presto_get_permit(de->d_inode) < 0 ) {
                 EXIT;
-                error = -EROFS;
-                goto out;
+                return -EROFS;
         }
 
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_setattr(fset, de, iattr, &info);
         presto_put_permit(de->d_inode);
-out:
-        unlock_kernel();
         return error;
 }
 
@@ -324,23 +383,32 @@
 
 int presto_prep(struct dentry *dentry, struct presto_cache **cache,
                 struct presto_file_set **fset)
-{
+{       
+        int rc;
+
+        /* NFS might pass us dentries which have not gone through lookup.
+         * Test and set d_fsdata for such dentries
+         */
+        rc = presto_check_set_fsdata (dentry);
+        if (rc) return rc;
+
         *fset = presto_fset(dentry);
-        if ( !*fset ) {
-                CDEBUG(D_INODE, "No file set for dentry at %p\n", dentry);
+        if ( *fset == NULL ) {
+                CERROR("No file set for dentry at %p: %*s\n", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
                 return -EROFS;
         }
 
         *cache = (*fset)->fset_cache;
-        if ( !*cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+        if ( *cache == NULL ) {
+                CERROR("PRESTO: BAD, BAD: cannot find cache\n");
                 return -EBADF;
         }
 
         CDEBUG(D_PIOCTL, "---> cache flags %x, fset flags %x\n",
               (*cache)->cache_flags, (*fset)->fset_flags);
         if( presto_is_read_only(*fset) ) {
-                printk("PRESTO: cannot modify read-only fileset, minor %d.\n",
+                CERROR("PRESTO: cannot modify read-only fileset, minor %d.\n",
                        presto_c2m(*cache));
                 return -EROFS;
         }
@@ -356,12 +424,18 @@
         struct presto_file_set *fset;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
                 return error;
         }
-	presto_unlock(dir);
+        presto_unlock(dir);
 
         /* Does blocking and non-blocking behavious need to be 
            checked for.  Without blocking (return 1), the permit
@@ -374,12 +448,13 @@
         }
 
         presto_relock_sem(dir);
-	parent = dentry->d_parent; 
+        parent = dentry->d_parent; 
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_create(fset, parent, dentry, mode, &info);
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         EXIT;
@@ -402,6 +477,12 @@
                 return error;
         }
 
+        error = presto_check_set_fsdata(new_dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(new_dentry->d_parent, &new_cache, &new_fset);
         if ( error ) {
                 EXIT;
@@ -426,15 +507,25 @@
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = new_dentry->d_parent;
 
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_link(fset, old_dentry, parent,
                                new_dentry, &info);
+
+#if 0
+        /* XXX for links this is not right */
+        if (cache->cache_filter->o_trops->tr_add_ilookup ) { 
+                struct dentry *d;
+                d = cache->cache_filter->o_trops->tr_add_ilookup
+                        (dir->i_sb->s_root, new_dentry, 1); 
+        }
+#endif 
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         presto_put_permit(old_dentry->d_inode);
@@ -451,13 +542,19 @@
 
         ENTRY;
 
+        error = presto_check_set_fsdata(dentry);
+        if ( error  ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
                 return error;
         }
 
-	presto_unlock(dir); 
+        presto_unlock(dir); 
 
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
@@ -468,17 +565,18 @@
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
 
-	presto_relock_sem(dir); 
-	parent = dentry->d_parent;
+        presto_relock_sem(dir); 
+        parent = dentry->d_parent;
         error = presto_do_mkdir(fset, parent, dentry, mode, &info);
-	presto_relock_other(dir); 
+        presto_relock_other(dir); 
         presto_put_permit(dir);
         return error;
 }
 
 
+
 static int presto_symlink(struct inode *dir, struct dentry *dentry,
                    const char *name)
 {
@@ -489,6 +587,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
@@ -498,16 +602,16 @@
         presto_unlock(dir);
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
-		presto_fulllock(dir);
+                presto_fulllock(dir);
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_symlink(fset, parent, dentry, name, &info);
         presto_relock_other(dir);
         presto_put_permit(dir);
@@ -523,6 +627,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
@@ -532,17 +642,19 @@
         presto_unlock(dir);
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
-		presto_fulllock(dir);
+                presto_fulllock(dir);
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
+
         error = presto_do_unlink(fset, parent, dentry, &info);
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         return error;
@@ -558,6 +670,13 @@
 
         ENTRY;
         CDEBUG(D_FILE, "prepping presto\n");
+        error = presto_check_set_fsdata(dentry);
+
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
@@ -568,32 +687,35 @@
         /* We need to dget() before the dput in double_unlock, to ensure we
          * still have dentry references.  double_lock doesn't do dget for us.
          */
-	unlock_kernel();
-	if (d_unhashed(dentry))
-		d_rehash(dentry);
-        double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
-        double_up(&dir->i_sem, &dentry->d_inode->i_sem);
+        if (d_unhashed(dentry))
+                d_rehash(dentry);
+        //        double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
+        up(&dentry->d_inode->i_sem);
+        up(&dir->i_sem);
 
         CDEBUG(D_FILE, "getting permit\n");
         if ( presto_get_permit(parent->d_inode) < 0 ) {
                 EXIT;
-		double_down(&dir->i_sem, &dentry->d_inode->i_sem);
-		double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
-		
-		lock_kernel();
+                down(&dir->i_sem);
+                down(&dentry->d_inode->i_sem);
+                //                double_down(&dir->i_sem, &dentry->d_inode->i_sem);
+                //                double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
+                
+                lock_kernel();
                 return -EROFS;
         }
         CDEBUG(D_FILE, "locking\n");
 
-	double_down(&dir->i_sem, &dentry->d_inode->i_sem);
-	parent = dentry->d_parent;
+        down(&dir->i_sem);
+        down(&dentry->d_inode->i_sem);
+        parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_rmdir(fset, parent, dentry, &info);
         presto_put_permit(parent->d_inode);
-	lock_kernel();
+        lock_kernel();
         EXIT;
         return error;
 }
@@ -607,6 +729,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
@@ -619,13 +747,13 @@
                 presto_fulllock(dir);
                 return -EROFS;
         }
-	
-	presto_relock_sem(dir);
+        
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_mknod(fset, parent, dentry, mode, rdev, &info);
         presto_relock_other(dir);
         presto_put_permit(dir);
@@ -633,80 +761,6 @@
         return error;
 }
 
-inline void presto_triple_unlock(struct inode *old_dir, struct inode *new_dir, 
-				 struct dentry *old_dentry, 
-				 struct dentry *new_dentry, int triple)
-{
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		if (triple) {			
-			triple_up(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_up(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-		up(&old_dir->i_sb->s_vfs_rename_sem);
-	} else /* this case is rename_other */
-		double_up(&old_dir->i_zombie, &new_dir->i_zombie);
-	/* done by do_rename */
-	unlock_kernel();
-	double_up(&old_dir->i_sem, &new_dir->i_sem);
-}
-
-inline void presto_triple_fulllock(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* done by do_rename */
-	double_down(&old_dir->i_sem, &new_dir->i_sem);
-	lock_kernel();
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		down(&old_dir->i_sb->s_vfs_rename_sem);
-		if (triple) {			
-			triple_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-	} else /* this case is rename_other */
-		double_down(&old_dir->i_zombie, &new_dir->i_zombie);
-}
-
-inline void presto_triple_relock_sem(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* done by do_rename */
-	double_down(&old_dir->i_sem, &new_dir->i_sem);
-	lock_kernel();
-}
-
-inline void presto_triple_relock_other(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		down(&old_dir->i_sb->s_vfs_rename_sem);
-		if (triple) {			
-			triple_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-	} else /* this case is rename_other */
-		double_down(&old_dir->i_zombie, &new_dir->i_zombie);
-}
 
 
 // XXX this can be optimized: renamtes across filesets only require 
@@ -746,27 +800,24 @@
         triple = (S_ISDIR(old_dentry->d_inode->i_mode) && new_dentry->d_inode)?
                 1:0;
 
-	presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        unlock_rename(new_dentry->d_parent, old_dentry->d_parent);
 
         if ( presto_get_permit(old_dir) < 0 ) {
                 EXIT;
-		presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
                 return -EROFS;
         }
         if ( presto_get_permit(new_dir) < 0 ) {
                 EXIT;
-		presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
                 return -EROFS;
         }
 
-	presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        lock_rename(new_dentry->d_parent, old_dentry->d_parent);
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
-        error = presto_do_rename(fset, old_parent, old_dentry, new_parent,
-                                 new_dentry, &info);
-	presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        info.flags |= LENTO_FL_IGNORE_TIME;
+        error = do_rename(fset, old_parent, old_dentry, new_parent,
+                          new_dentry, &info);
 
         presto_put_permit(new_dir);
         presto_put_permit(old_dir);
@@ -785,15 +836,13 @@
 {
         unsigned short mode = inode->i_mode;
         struct presto_cache *cache;
-        int rc = 0;
+        int rc;
 
-	lock_kernel();
         ENTRY;
-
         if ( presto_can_ilookup() && !(mask & S_IWOTH)) {
                 CDEBUG(D_CACHE, "ilookup on %ld OK\n", inode->i_ino);
-		EXIT;
-		goto out;
+                EXIT;
+                return 0;
         }
 
         cache = presto_get_cache(inode);
@@ -805,92 +854,490 @@
 
                 if ( S_ISREG(mode) && fiops && fiops->permission ) {
                         EXIT;
-                        rc = fiops->permission(inode, mask);
-			goto out;
+                        return fiops->permission(inode, mask);
                 }
                 if ( S_ISDIR(mode) && diops && diops->permission ) {
                         EXIT;
-                        rc = diops->permission(inode, mask);
-			goto out;
+                        return diops->permission(inode, mask);
                 }
         }
 
-        rc = vfs_permission(inode, mask);
+        /* The cache filesystem doesn't have its own permission function,
+         * but we don't want to duplicate the VFS code here.  In order
+         * to avoid looping from permission calling this function again,
+         * we temporarily override the permission operation while we call
+         * the VFS permission function.
+         */
+        inode->i_op->permission = NULL;
+        rc = permission(inode, mask);
+        inode->i_op->permission = &presto_permission;
 
         EXIT;
-
- out:
-	unlock_kernel();
         return rc;
 }
 
 
-static int presto_dir_open(struct inode *inode, struct file *file)
+int presto_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
 {
-        int rc = 0;
-        struct dentry *de = file->f_dentry;
-        struct file_operations *fops;
-        struct presto_cache *cache;
-        struct presto_file_set *fset;
-        int minor;
-        int error; 
+        char buf[1024];
+        struct izo_ioctl_data *data = NULL;
+        struct presto_dentry_data *dd;
+        int rc;
 
         ENTRY;
 
-        error = presto_prep(file->f_dentry, &cache, &fset);
-        if ( error  ) {
+        /* Try the filesystem's ioctl first, and return if it succeeded. */
+        dd = presto_d2d(file->f_dentry); 
+        if (dd && dd->dd_fset) { 
+                int (*cache_ioctl)(struct inode *, struct file *, unsigned int, unsigned long ) = filter_c2cdfops(dd->dd_fset->fset_cache->cache_filter)->ioctl;
+                rc = -ENOTTY;
+                if (cache_ioctl)
+                        rc = cache_ioctl(inode, file, cmd, arg);
+                if (rc != -ENOTTY) {
+                        EXIT;
+                        return rc;
+                }
+        }
+
+        if (current->euid != 0 && current->euid != izo_authorized_uid) {
                 EXIT;
-                make_bad_inode(inode);
-                return error;
+                return -EPERM;
         }
-        minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "minor %d, DATA_OK: %d, ino: %ld\n",
-               minor, presto_chk(de, PRESTO_DATA), inode->i_ino);
+        memset(buf, 0, sizeof(buf));
+        
+        if (izo_ioctl_getdata(buf, buf + 1024, (void *)arg)) { 
+                CERROR("intermezzo ioctl: data error\n");
+                return -EINVAL;
+        }
+        data = (struct izo_ioctl_data *)buf;
+        
+        switch(cmd) {
+        case IZO_IOC_REINTKML: { 
+                int rc;
+                int cperr;
+                rc = kml_reint_rec(file, data);
+
+                EXIT;
+                cperr = copy_to_user((char *)arg, data, sizeof(*data));
+                if (cperr) { 
+                        CERROR("WARNING: cperr %d\n", cperr); 
+                        rc = -EFAULT;
+                }
+                return rc;
+        }
+
+        case IZO_IOC_GET_RCVD: {
+                struct izo_rcvd_rec rec;
+                struct presto_file_set *fset;
+                int rc;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                EXIT;
+                return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_REPSTATUS: {
+                __u64 client_kmlsize;
+                struct izo_rcvd_rec *lr_client;
+                struct izo_rcvd_rec rec;
+                struct presto_file_set *fset;
+                int minor;
+                int rc;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                client_kmlsize = data->ioc_kmlsize;
+                lr_client =  (struct izo_rcvd_rec *) data->ioc_pbuf1;
+
+                rc = izo_repstatus(fset, client_kmlsize, 
+                                       lr_client, &rec);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                EXIT;
+                return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_GET_CHANNEL: {
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                
+                data->ioc_dev = fset->fset_cache->cache_psdev->uc_minor;
+                CDEBUG(D_PSDEV, "CHANNEL %d\n", data->ioc_dev); 
+                EXIT;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_SET_IOCTL_UID:
+                izo_authorized_uid = data->ioc_uid;
+                EXIT;
+                return 0;
+
+        case IZO_IOC_SET_PID:
+                rc = izo_psdev_setpid(data->ioc_dev);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_SET_CHANNEL:
+                rc = izo_psdev_setchannel(file, data->ioc_dev);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_GET_KML_SIZE: {
+                struct presto_file_set *fset;
+                __u64 kmlsize;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                kmlsize = presto_kml_offset(fset) + fset->fset_kml_logical_off;
+
+                EXIT;
+                return copy_to_user((char *)arg, &kmlsize, sizeof(kmlsize))?-EFAULT : 0;
+        }
+
+        case IZO_IOC_PURGE_FILE_DATA: {
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                rc = izo_purge_file(fset, data->ioc_inlbuf1);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_GET_FILEID: {
+                rc = izo_get_fileid(file, data);
+                EXIT;
+                if (rc)
+                        return rc;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_SET_FILEID: {
+                rc = izo_set_fileid(file, data);
+                EXIT;
+                if (rc)
+                        return rc;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT  : 0;
+        }
+
+        case IZO_IOC_ADJUST_LML: { 
+                struct lento_vfs_context *info; 
+                info = (struct lento_vfs_context *)data->ioc_inlbuf1;
+                rc = presto_adjust_lml(file, info); 
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_CONNECT: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_connect(minor, data->ioc_ino,
+                                     data->ioc_generation, data->ioc_uuid,
+                                     data->ioc_flags);
+                EXIT;
+                return rc;
+        }
 
-        if ( ISLENTO(minor) )
-                goto cache;
+        case IZO_IOC_GO_FETCH_KML: {
+                struct presto_file_set *fset;
+                int minor;
 
-        if ( !presto_chk(de, PRESTO_DATA) ) {
-                CDEBUG(D_CACHE, "doing lento_opendir\n");
-                rc = presto_opendir_upcall(minor, file->f_dentry, fset->fset_mtpt, SYNCHRONOUS);
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_go_fetch_kml(minor, fset->fset_name,
+                                          data->ioc_uuid, data->ioc_kmlsize);
+                EXIT;
+                return rc;
         }
 
-        if ( rc ) {
-                printk("presto_dir_open: DATA_OK: %d, ino: %ld, error %d\n",
-                       presto_chk(de, PRESTO_DATA), inode->i_ino, rc);
-                return rc ;
+        case IZO_IOC_REVOKE_PERMIT:
+                if (data->ioc_flags)
+                        rc = izo_revoke_permit(file->f_dentry, data->ioc_uuid);
+                else
+                        rc = izo_revoke_permit(file->f_dentry, NULL);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_CLEAR_FSET:
+                rc = izo_clear_fsetroot(file->f_dentry);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_CLEAR_ALL_FSETS: { 
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                rc = izo_clear_all_fsetroots(fset->fset_cache);
+                EXIT;
+                return rc;
         }
 
- cache:
-        fops = filter_c2cdfops(cache->cache_filter);
-        if ( fops->open ) {
-                rc = fops->open(inode, file);
+        case IZO_IOC_SET_FSET:
+                /*
+                 * Mark this dentry as being a fileset root.
+                 */
+                rc = presto_set_fsetroot_from_ioc(file->f_dentry, 
+                                                  data->ioc_inlbuf1,
+                                                  data->ioc_flags);
+                EXIT;
+                return rc;
+
+
+        case IZO_IOC_MARK: {
+                int res = 0;  /* resulting flags - returned to user */
+                int error;
+
+                CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %d\n",
+                       file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
+                       data->ioc_or_flag, data->ioc_mark_what);
+
+                switch (data->ioc_mark_what) {
+                case MARK_DENTRY:               
+                        error = izo_mark_dentry(file->f_dentry,
+                                                   data->ioc_and_flag,
+                                                   data->ioc_or_flag, &res);
+                        break;
+                case MARK_FSET:
+                        error = izo_mark_fset(file->f_dentry,
+                                                 data->ioc_and_flag,
+                                                 data->ioc_or_flag, &res);
+                        break;
+                case MARK_CACHE:
+                        error = izo_mark_cache(file->f_dentry,
+                                                  data->ioc_and_flag,
+                                                  data->ioc_or_flag, &res);
+                        break;
+                case MARK_GETFL: {
+                        int fflags, cflags;
+                        data->ioc_and_flag = 0xffffffff;
+                        data->ioc_or_flag = 0; 
+                        error = izo_mark_dentry(file->f_dentry,
+                                                   data->ioc_and_flag,
+                                                   data->ioc_or_flag, &res);
+                        if (error) 
+                                break;
+                        error = izo_mark_fset(file->f_dentry,
+                                                 data->ioc_and_flag,
+                                                 data->ioc_or_flag, &fflags);
+                        if (error) 
+                                break;
+                        error = izo_mark_cache(file->f_dentry,
+                                                  data->ioc_and_flag,
+                                                  data->ioc_or_flag,
+                                                  &cflags);
+
+                        if (error) 
+                                break;
+                        data->ioc_and_flag = fflags;
+                        data->ioc_or_flag = cflags;
+                        break;
+                }
+                default:
+                        error = -EINVAL;
+                }
+
+                if (error) { 
+                        EXIT;
+                        return error;
+                }
+                data->ioc_mark_what = res;
+                CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %x\n",
+                       file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
+                       data->ioc_or_flag, data->ioc_mark_what);
+
+                EXIT;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+#if 0
+        case IZO_IOC_CLIENT_MAKE_BRANCH: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_client_make_branch(minor, fset->fset_name,
+                                                data->ioc_inlbuf1,
+                                                data->ioc_inlbuf2);
+                EXIT;
+                return rc;
         }
-        presto_set(de, PRESTO_DATA | PRESTO_ATTR);
-        CDEBUG(D_CACHE, "returns %d, data %d, attr %d\n", rc,
-               presto_chk(de, PRESTO_DATA), presto_chk(de, PRESTO_ATTR));
+#endif
+        case IZO_IOC_SERVER_MAKE_BRANCH: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                izo_upc_server_make_branch(minor, data->ioc_inlbuf1);
+                EXIT;
+                return 0;
+        }
+        case IZO_IOC_SET_KMLSIZE: {
+                struct presto_file_set *fset;
+                int minor;
+                struct izo_rcvd_rec rec;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_set_kmlsize(minor, fset->fset_name, data->ioc_uuid,
+                                         data->ioc_kmlsize);
+
+                if (rc != 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
+                if (rc == -EINVAL) {
+                        /* We don't know anything about this uuid yet; no
+                         * worries. */
+                        memset(&rec, 0, sizeof(rec));
+                } else if (rc <= 0) {
+                        CERROR("InterMezzo: error reading last_rcvd: %d\n", rc);
+                        EXIT;
+                        return rc;
+                }
+                rec.lr_remote_offset = data->ioc_kmlsize;
+                rc = izo_rcvd_write(fset, &rec);
+                if (rc <= 0) {
+                        CERROR("InterMezzo: error writing last_rcvd: %d\n", rc);
+                        EXIT;
+                        return rc;
+                }
+                EXIT;
+                return rc;
+        }
+        case IZO_IOC_BRANCH_UNDO: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_branch_undo(minor, fset->fset_name,
+                                         data->ioc_inlbuf1);
+                EXIT;
+                return rc;
+        }
+        case IZO_IOC_BRANCH_REDO: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_branch_redo(minor, fset->fset_name,
+                                         data->ioc_inlbuf1);
+                EXIT;
+                return rc;
+        }
+
+        case TCGETS:
+                EXIT;
+                return -EINVAL;
+
+        default:
+                EXIT;
+                return -EINVAL;
+                
+        }
+        EXIT;
         return 0;
 }
 
 struct file_operations presto_dir_fops = {
-        open: presto_dir_open
+        .ioctl =  presto_ioctl
 };
 
 struct inode_operations presto_dir_iops = {
-        create: presto_create,
-        lookup: presto_lookup,
-        link:   presto_link,
-        unlink: presto_unlink,
-        symlink:        presto_symlink,
-        mkdir:  presto_mkdir,
-        rmdir:  presto_rmdir,
-        mknod:  presto_mknod,
-        rename: presto_rename,
-        permission:     presto_permission,
-        setattr:        presto_setattr,
+        .create       = presto_create,
+        .lookup       = presto_lookup,
+        .link         = presto_link,
+        .unlink       = presto_unlink,
+        .symlink      = presto_symlink,
+        .mkdir        = presto_mkdir,
+        .rmdir        = presto_rmdir,
+        .mknod        = presto_mknod,
+        .rename       = presto_rename,
+        .permission   = presto_permission,
+        .setattr      = presto_setattr,
 #ifdef CONFIG_FS_EXT_ATTR
-	set_ext_attr:	presto_set_ext_attr,
+        .set_ext_attr = presto_set_ext_attr,
 #endif
-
 };
+
+
diff -Nru a/fs/intermezzo/ext_attr.c b/fs/intermezzo/ext_attr.c
--- a/fs/intermezzo/ext_attr.c	Tue Oct 15 20:29:17 2002
+++ b/fs/intermezzo/ext_attr.c	Tue Oct 15 20:29:17 2002
@@ -1,10 +1,25 @@
-/* 
- * Extended attribute handling for presto.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ * 
+ *  Copyright (C) 2001 Tacit Networks, Inc.
+ *    Author: Shirish H. Phatak <shirish@tacitnetworks.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
  *
- * Copyright (C) 2001. All rights reserved.
- * Shirish H. Phatak
- * Tacit Networks, Inc.
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
  *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Extended attribute handling for presto.
  */
 
 #define __NO_VERSION__
@@ -14,6 +29,7 @@
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
 #include <linux/unistd.h>
 
 #include <asm/system.h>
@@ -22,18 +38,16 @@
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
-#include <linux/locks.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <asm/uaccess.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <asm/segment.h>
 #include <linux/smp_lock.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
 
 #ifdef CONFIG_FS_EXT_ATTR
 #include <linux/ext_attr.h>
@@ -41,9 +55,6 @@
 extern inline void presto_debug_fail_blkdev(struct presto_file_set *fset,
                                             unsigned long value);
 
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
-
 
 /* VFS interface */
 /* XXX! Fixme test for user defined attributes */
@@ -75,7 +86,7 @@
          * we do a reverse mapping from inode to the first dentry 
          */
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -EINVAL;
         }
@@ -99,12 +110,13 @@
             * (works for ext3)
             */
             if (flags & EXT_ATTR_FLAG_USER) {
-                PRESTO_ALLOC(buf, char *, buffer_len);
+                PRESTO_ALLOC(buf, buffer_len);
                 if (!buf) {
-                        printk("InterMezzo: out of memory!!!\n");
+                        CERROR("InterMezzo: out of memory!!!\n");
                         return -ENOMEM;
                 }
-                if (copy_from_user(buf, buffer, buffer_len))
+                error = copy_from_user(buf, buffer, buffer_len);
+                if (error) 
                         return -EFAULT;
             } else 
                 buf = buffer;
@@ -172,7 +184,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_dentry;
         }
diff -Nru a/fs/intermezzo/file.c b/fs/intermezzo/file.c
--- a/fs/intermezzo/file.c	Tue Oct 15 20:29:17 2002
+++ b/fs/intermezzo/file.c	Tue Oct 15 20:29:17 2002
@@ -1,22 +1,34 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 TurboLinux, Inc.
  *  Copyright (C) 2000 Los Alamos National Laboratory.
- *  Copyright (C) 2000 Tacitus Systems
+ *  Copyright (C) 2000, 2001 Tacit Networks, Inc.
  *  Copyright (C) 2000 Peter J. Braam
  *  Copyright (C) 2001 Mountain View Data, Inc. 
  *  Copyright (C) 2001 Cluster File Systems, Inc. 
  *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License as
- *  published by the Free Software Foundation; either version 2 of the
- *  License, or (at your option) any later version.
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ *  This file manages file I/O
+ * 
  */
 
-
 #include <stdarg.h>
 
 #include <asm/bitops.h>
@@ -28,9 +40,10 @@
 #include <linux/ext2_fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
@@ -38,71 +51,126 @@
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 #include <linux/fsfilter.h>
 /*
  * these are initialized in super.c
  */
 extern int presto_permission(struct inode *inode, int mask);
-extern int presto_opendir_upcall(int minor, struct dentry *de, int async);
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
 
 
-#if 0
 static int presto_open_upcall(int minor, struct dentry *de)
 {
         int rc;
         char *path, *buffer;
+        struct presto_file_set *fset;
         int pathlen;
+        struct lento_vfs_context info;
+        struct presto_dentry_data *dd = presto_d2d(de);
 
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
+        PRESTO_ALLOC(buffer, PAGE_SIZE);
         if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
-                return ENOMEM;
+                CERROR("PRESTO: out of memory!\n");
+                return -ENOMEM;
         }
-        path = presto_path(de, buffer, PAGE_SIZE);
+        fset = presto_fset(de);
+        path = presto_path(de, fset->fset_dentry, buffer, PAGE_SIZE);
         pathlen = MYPATHLEN(buffer, path);
-        rc = lento_open(minor, pathlen, path);
+        
+        CDEBUG(D_FILE, "de %p, dd %p\n", de, dd);
+        if (dd->remote_ino == 0) {
+                rc = presto_get_fileid(minor, fset, de);
+        }
+        memset (&info, 0, sizeof(info));
+        if (dd->remote_ino > 0) {
+                info.remote_ino = dd->remote_ino;
+                info.remote_generation = dd->remote_generation;
+        } else
+                CERROR("get_fileid failed %d, ino: %Lx, fetching by name\n", rc,
+                       dd->remote_ino);
+
+        rc = izo_upc_open(minor, pathlen, path, fset->fset_name, &info);
         PRESTO_FREE(buffer, PAGE_SIZE);
         return rc;
 }
-#endif
 
+static inline int open_check_dod(struct file *file,
+                                 struct presto_file_set *fset)
+{
+        int gen, is_iopen = 0, minor;
+        struct presto_cache *cache = fset->fset_cache;
+        ino_t inum;
+
+        minor = presto_c2m(cache);
+
+        if ( ISLENTO(minor) ) {
+                CDEBUG(D_CACHE, "is lento, not doing DOD.\n");
+                return 0;
+        }
+
+        /* Files are only ever opened by inode during backfetches, when by
+         * definition we have the authoritative copy of the data.  No DOD. */
+        is_iopen = izo_dentry_is_ilookup(file->f_dentry, &inum, &gen);
+
+        if (is_iopen) {
+                CDEBUG(D_CACHE, "doing iopen, not doing DOD.\n");
+                return 0;
+        }
+
+        if (!(fset->fset_flags & FSET_DATA_ON_DEMAND)) {
+                CDEBUG(D_CACHE, "fileset not on demand.\n");
+                return 0;
+        }
+                
+        if (file->f_flags & O_TRUNC) {
+                CDEBUG(D_CACHE, "fileset dod: O_TRUNC.\n");
+                return 0;
+        }
+                
+        if (presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL)) {
+                CDEBUG(D_CACHE, "file under .intermezzo, not doing DOD\n");
+                return 0;
+        }
+
+        if (presto_chk(file->f_dentry, PRESTO_DATA)) {
+                CDEBUG(D_CACHE, "PRESTO_DATA is set, not doing DOD.\n");
+                return 0;
+        }
+
+        if (cache->cache_filter->o_trops->tr_all_data(file->f_dentry->d_inode)) {
+                CDEBUG(D_CACHE, "file not sparse, not doing DOD.\n");
+                return 0;
+        }
+
+        return 1;
+}
 
 static int presto_file_open(struct inode *inode, struct file *file)
 {
         int rc = 0;
         struct file_operations *fops;
         struct presto_cache *cache;
+        struct presto_file_set *fset;
         struct presto_file_data *fdata;
         int writable = (file->f_flags & (O_RDWR | O_WRONLY));
-        int minor;
-        int i;
+        int minor, i;
 
         ENTRY;
 
-        cache = presto_get_cache(inode);
-        if ( !cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+        if (presto_prep(file->f_dentry, &cache, &fset) < 0) {
                 EXIT;
                 return -EBADF;
         }
 
         minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "presto_file_open: DATA_OK: %d, ino: %ld\n",
-               presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino);
-
-        if ( ISLENTO(minor) )
-                goto cache;
-
-        if ( file->f_flags & O_RDWR || file->f_flags & O_WRONLY) {
-                CDEBUG(D_CACHE, "presto_file_open: calling presto_get_permit\n");
-                /* lock needed to protect permit_count manipulations -SHP */
+        CDEBUG(D_CACHE, "DATA_OK: %d, ino: %ld, islento: %d\n",
+               presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino,
+               ISLENTO(minor));
+
+        if ( !ISLENTO(minor) && (file->f_flags & O_RDWR ||
+                                 file->f_flags & O_WRONLY)) {
+                CDEBUG(D_CACHE, "calling presto_get_permit\n");
                 if ( presto_get_permit(inode) < 0 ) {
                         EXIT;
                         return -EROFS;
@@ -110,71 +178,97 @@
                 presto_put_permit(inode);
         }
 
-        /* XXX name space synchronization here for data/streaming on demand?*/
-        /* XXX Lento can make us wait here for backfetches to complete */
-#if 0
-        if ( !presto_chk(file->f_dentry, PRESTO_DATA) ||
-             !presto_has_all_data(file->f_dentry->d_inode) ) {
-                CDEBUG(D_CACHE, "presto_file_open: presto_open_upcall\n");
+        if (open_check_dod(file, fset)) {
+                CDEBUG(D_CACHE, "presto_open_upcall\n");
+                CDEBUG(D_CACHE, "dentry: %p setting DATA, ATTR\n", file->f_dentry);
+                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
                 rc = presto_open_upcall(minor, file->f_dentry);
+                if (rc) {
+                        EXIT;
+                        CERROR("%s: returning error %d\n", __FUNCTION__, rc);
+                        return rc;
+                }
+
+        }
+
+        /* file was truncated upon open: do not refetch */
+        if (file->f_flags & O_TRUNC) { 
+                CDEBUG(D_CACHE, "setting DATA, ATTR\n");
+                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
         }
 
-#endif
-        rc = 0;
- cache:
         fops = filter_c2cffops(cache->cache_filter);
         if ( fops->open ) {
-                CDEBUG(D_CACHE, "presto_file_open: calling fs open\n");
+                CDEBUG(D_CACHE, "calling fs open\n");
                 rc = fops->open(inode, file);
-        }
-        if (rc) {
-            EXIT;
-            return rc;
-        }
 
-        CDEBUG(D_CACHE, "presto_file_open: setting DATA, ATTR\n");
-        if( ISLENTO(minor) )
-            presto_set(file->f_dentry, PRESTO_ATTR );
-        else
-                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
+                if (rc) {
+                        EXIT;
+                        return rc;
+                }
+        }
 
-        if (writable) { 
-                PRESTO_ALLOC(fdata, struct presto_file_data *, sizeof(*fdata));
+        if (writable) {
+                PRESTO_ALLOC(fdata, sizeof(*fdata));
                 if (!fdata) {
                         EXIT;
                         return -ENOMEM;
                 }
-                /* we believe that on open the kernel lock
-                   assures that only one process will do this allocation */ 
+                /* LOCK: XXX check that the kernel lock protects this alloc */
                 fdata->fd_do_lml = 0;
+                fdata->fd_bytes_written = 0;
                 fdata->fd_fsuid = current->fsuid;
                 fdata->fd_fsgid = current->fsgid;
                 fdata->fd_mode = file->f_dentry->d_inode->i_mode;
+                fdata->fd_uid = file->f_dentry->d_inode->i_uid;
+                fdata->fd_gid = file->f_dentry->d_inode->i_gid;
                 fdata->fd_ngroups = current->ngroups;
-                for (i=0 ; i<current->ngroups ; i++)
-                        fdata->fd_groups[i] = current->groups[i]; 
-                fdata->fd_bytes_written = 0; /*when open,written data is zero*/ 
-                file->private_data = fdata; 
+                for (i=0 ; i < current->ngroups ; i++)
+                        fdata->fd_groups[i] = current->groups[i];
+                if (!ISLENTO(minor)) 
+                        fdata->fd_info.flags = LENTO_FL_KML; 
+                else { 
+                        /* this is for the case of DOD, 
+                           reint_close will adjust flags if needed */
+                        fdata->fd_info.flags = 0;
+                }
+
+                presto_getversion(&fdata->fd_version, inode);
+                file->private_data = fdata;
         } else {
                 file->private_data = NULL;
         }
 
+        EXIT;
         return 0;
 }
 
+int presto_adjust_lml(struct file *file, struct lento_vfs_context *info)
+{
+        struct presto_file_data *fdata = 
+                (struct presto_file_data *) file->private_data;
+
+        if (!fdata) { 
+                EXIT;
+                return -EINVAL;
+        }
+                
+        memcpy(&fdata->fd_info, info, sizeof(*info));
+        EXIT;
+        return 0; 
+}
+
+
 static int presto_file_release(struct inode *inode, struct file *file)
 {
-        struct rec_info rec;
         int rc;
-        int writable = (file->f_flags & (O_RDWR | O_WRONLY));
         struct file_operations *fops;
         struct presto_cache *cache;
         struct presto_file_set *fset;
-        void *handle; 
         struct presto_file_data *fdata = 
                 (struct presto_file_data *)file->private_data;
-
         ENTRY;
+
         rc = presto_prep(file->f_dentry, &cache, &fset);
         if ( rc ) {
                 EXIT;
@@ -182,96 +276,40 @@
         }
 
         fops = filter_c2cffops(cache->cache_filter);
-        rc = fops->release(inode, file);
+        if (fops && fops->release)
+                rc = fops->release(inode, file);
 
-        CDEBUG(D_CACHE, "islento = %d (minor %d), writable = %d, rc %d, data %p\n",
+        CDEBUG(D_CACHE, "islento = %d (minor %d), rc %d, data %p\n",
                ISLENTO(cache->cache_psdev->uc_minor), 
-               cache->cache_psdev->uc_minor, 
-               writable, rc, fdata);
-
-        if (fdata && fdata->fd_do_lml) { 
-                CDEBUG(D_CACHE, "LML at %lld\n", fdata->fd_lml_offset); 
-        }
-
-        /* don't journal close if file couldn't have been written to */
-        /*    if (!ISLENTO(cache->cache_prestominor) && !rc && writable) {*/
-        if (fdata && fdata->fd_do_lml && 
-            !rc && writable && (! ISLENTO(cache->cache_psdev->uc_minor))) {
-                struct presto_version new_ver;
-
-                presto_getversion(&new_ver, inode);
+               cache->cache_psdev->uc_minor, rc, fdata);
 
+        /* this file was modified: ignore close errors, write KML */
+        if (fdata && fdata->fd_do_lml) {
                 /* XXX: remove when lento gets file granularity cd */
-                /* Lock needed to protect permit_count manipulations -SHP */
                 if ( presto_get_permit(inode) < 0 ) {
                         EXIT;
                         return -EROFS;
                 }
-                CDEBUG(D_CACHE, "presto_file_release: writing journal\n");
         
-                rc = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-                if (rc) { 
-                        presto_put_permit(inode); 
-                        EXIT; 
-                        return rc;
-                }
-                handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                            PRESTO_OP_RELEASE);
-                if ( IS_ERR(handle) ) {
-                        printk("presto_release: no space for transaction\n");
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                rc = presto_journal_close(&rec, fset, file, file->f_dentry, 
-                                          &new_ver);
-                if (rc) { 
-                        printk("presto_close: cannot journal close\n");
-                        /* XXX oops here to get this bug */ 
-                        *(int *)0 = 1;
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                presto_trans_commit(fset, handle); 
-
-                /* cancel the LML record */ 
-                handle = presto_trans_start
-                        (fset, inode, PRESTO_OP_WRITE);
-                if ( IS_ERR(handle) ) {
-                        printk("presto_release: no space for clear\n");
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                rc = presto_clear_lml_close(fset,
-                                            fdata->fd_lml_offset); 
-                if (rc < 0 ) { 
-                        /* XXX oops here to get this bug */ 
-                        *(int *)0 = 1;
-                        presto_put_permit(inode);
-                        printk("presto_close: cannot journal close\n");
-                        return -ENOSPC;
-                }
-                presto_trans_commit(fset, handle); 
-                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-
-                presto_truncate_lml(fset);
-
+                fdata->fd_info.updated_time = file->f_dentry->d_inode->i_mtime;
+                rc = presto_do_close(fset, file); 
                 presto_put_permit(inode);
         }
 
         if (!rc && fdata) {
                 PRESTO_FREE(fdata, sizeof(*fdata));
+                file->private_data = NULL; 
         }
-        file->private_data = NULL; 
         
         EXIT;
         return rc;
 }
 
-
-
-static void presto_apply_write_policy(struct file *file, struct presto_file_set *fset, loff_t res)
+static void presto_apply_write_policy(struct file *file,
+                                      struct presto_file_set *fset, loff_t res)
 {
-        struct presto_file_data *fdata = (struct presto_file_data *)file->private_data;
+        struct presto_file_data *fdata =
+                (struct presto_file_data *)file->private_data;
         struct presto_cache *cache = fset->fset_cache;
         struct presto_version new_file_ver;
         int error;
@@ -284,40 +322,44 @@
          journaling in a thread, add more options etc.)
         */ 
  
-         if (  (fset->fset_flags & FSET_JCLOSE_ON_WRITE)
-                 && (!ISLENTO(cache->cache_psdev->uc_minor)))  {
-                 fdata->fd_bytes_written += res;
+        if ((fset->fset_flags & FSET_JCLOSE_ON_WRITE) &&
+            (!ISLENTO(cache->cache_psdev->uc_minor))) {
+                fdata->fd_bytes_written += res;
  
-                 if (fdata->fd_bytes_written >= fset->fset_file_maxio) {
-                         presto_getversion(&new_file_ver, file->f_dentry->d_inode);
+                if (fdata->fd_bytes_written >= fset->fset_file_maxio) {
+                        presto_getversion(&new_file_ver,
+                                          file->f_dentry->d_inode);
                         /* This is really heavy weight and should be fixed
                            ASAP. At most we should be recording the number
                            of bytes written and not locking the kernel, 
                            wait for permits, etc, on the write path. SHP
                         */
                         lock_kernel();
-                         if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) {
-                                 EXIT;
-                                 /* we must be disconnected, not to worry */
+                        if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) {
+                                EXIT;
+                                /* we must be disconnected, not to worry */
+                                unlock_kernel();
                                 return; 
-                         }
-                         error = presto_journal_close
-                                (&rec, fset, file, file->f_dentry, &new_file_ver);
-                         presto_put_permit(file->f_dentry->d_inode);
+                        }
+                        error = presto_journal_close(&rec, fset, file,
+                                                     file->f_dentry,
+                                                     &fdata->fd_version,
+                                                     &new_file_ver);
+                        presto_put_permit(file->f_dentry->d_inode);
                         unlock_kernel();
-                         if ( error ) {
-                                 printk("presto_close: cannot journal close\n");
-                                 /* XXX these errors are really bad */
+                        if ( error ) {
+                                CERROR("presto_close: cannot journal close\n");
+                                /* XXX these errors are really bad */
                                 /* panic(); */
-                                 return;
-                         }
-                             fdata->fd_bytes_written = 0;
-                     } 
+                                return;
+                        }
+                        fdata->fd_bytes_written = 0;
+                }
         }
 }
 
-static ssize_t presto_file_write(struct file *file, const char *buf, size_t size, 
-                          loff_t *off)
+static ssize_t presto_file_write(struct file *file, const char *buf,
+                                 size_t size, loff_t *off)
 {
         struct rec_info rec;
         int error;
@@ -343,83 +385,155 @@
                 << file->f_dentry->d_inode->i_sb->s_blocksize_bits);
 
         error = presto_reserve_space(fset->fset_cache, res_size); 
-        CDEBUG(D_INODE, "Reserved %Ld for %Zd\n", res_size, size); 
+        CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size); 
         if ( error ) { 
                 EXIT;
                 return -ENOSPC;
         }
 
-        /* XXX lock something here */
-        CDEBUG(D_INODE, "islento %d, minor: %d\n", ISLENTO(cache->cache_psdev->uc_minor),
+        CDEBUG(D_INODE, "islento %d, minor: %d\n", 
+               ISLENTO(cache->cache_psdev->uc_minor),
                cache->cache_psdev->uc_minor); 
+
+        /* 
+         *  XXX this lock should become a per inode lock when 
+         *  Vinny's changes are in; we could just use i_sem.
+         */
         read_lock(&fset->fset_lml.fd_lock); 
         fdata = (struct presto_file_data *)file->private_data;
-        do_lml_here = (!ISLENTO(cache->cache_psdev->uc_minor)) &&
-                size && (fdata->fd_do_lml == 0);
+        do_lml_here = size && (fdata->fd_do_lml == 0) &&
+                !presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL);
 
         if (do_lml_here)
                 fdata->fd_do_lml = 1;
         read_unlock(&fset->fset_lml.fd_lock); 
 
-        /* XXX we have two choices:
-           - we do the transaction for the LML record BEFORE any write
-           transaction starts - that has the benefit that no other
-           short write can complete without the record being there. 
-           The disadvantage is that even if no write happens we get 
-           the LML record. 
-           - we bundle the transaction with this write.  In that case
-           we may not have an LML record is a short write goes through
-           before this one (can that actually happen?).
+        /* XXX 
+           There might be a bug here.  We need to make 
+           absolutely sure that the ext3_file_write commits 
+           after our transaction that writes the LML record.
+           Nesting the file write helps if new blocks are allocated. 
         */
         res = 0;
         if (do_lml_here) {
+                struct presto_version file_version;
                 /* handle different space reqs from file system below! */
                 handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                            PRESTO_OP_WRITE);
+                                            KML_OPCODE_WRITE);
                 if ( IS_ERR(handle) ) {
                         presto_release_space(fset->fset_cache, res_size); 
-                        printk("presto_write: no space for transaction\n");
+                        CERROR("presto_write: no space for transaction\n");
                         return -ENOSPC;
                 }
-                res = presto_journal_write(&rec, fset, file);
+
+                presto_getversion(&file_version, file->f_dentry->d_inode); 
+                res = presto_write_lml_close(&rec, fset, file, 
+                                             fdata->fd_info.remote_ino, 
+                                             fdata->fd_info.remote_generation, 
+                                             &fdata->fd_info.remote_version, 
+                                             &file_version);
                 fdata->fd_lml_offset = rec.offset;
                 if ( res ) {
-                        /* XXX oops here to get this bug */ 
-                        /* *(int *)0 = 1; */
+                        CERROR("intermezzo: PANIC failed to write LML\n");
+                        *(int *)0 = 1;
                         EXIT;
                         goto exit_write;
                 }
-                
                 presto_trans_commit(fset, handle);
         }
 
         fops = filter_c2cffops(cache->cache_filter);
         res = fops->write(file, buf, size, off);
         if ( res != size ) {
-                CDEBUG(D_FILE, "file write returns short write: size %Zd, res %Zd\n", size, res); 
+                CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res); 
         }
 
         if ( (res > 0) && fdata ) 
                  presto_apply_write_policy(file, fset, res);
-  
+
  exit_write:
         presto_release_space(fset->fset_cache, res_size); 
         return res;
 }
 
 struct file_operations presto_file_fops = {
-        write:   presto_file_write,
-        open:    presto_file_open,
-        release: presto_file_release
+        .write   = presto_file_write,
+        .open    = presto_file_open,
+        .release = presto_file_release,
+        .ioctl   = presto_ioctl
 };
 
 struct inode_operations presto_file_iops = {
-        permission: presto_permission,
-	setattr: presto_setattr,
+        .permission   = presto_permission,
+        .setattr      = presto_setattr,
 #ifdef CONFIG_FS_EXT_ATTR
-	set_ext_attr: presto_set_ext_attr,
+        .set_ext_attr = presto_set_ext_attr,
 #endif
 };
 
+/* FIXME: I bet we want to add a lock here and in presto_file_open. */
+int izo_purge_file(struct presto_file_set *fset, char *file)
+{
+#if 0
+        void *handle = NULL;
+        char *path = NULL;
+        struct nameidata nd;
+        struct dentry *dentry;
+        int rc = 0, len;
+        loff_t oldsize;
+
+        /* FIXME: not mtpt it's gone */
+        len = strlen(fset->fset_cache->cache_mtpt) + strlen(file) + 1;
+        PRESTO_ALLOC(path, len + 1);
+        if (path == NULL)
+                return -1;
+
+        sprintf(path, "%s/%s", fset->fset_cache->cache_mtpt, file);
+        rc = izo_lookup_file(fset, path, &nd);
+        if (rc)
+                goto error;
+        dentry = nd.dentry;
+
+        /* FIXME: take a lock here */
+
+        if (dentry->d_inode->i_atime > CURRENT_TIME - 5) {
+                /* We lost the race; this file was accessed while we were doing
+                 * ioctls and lookups and whatnot. */
+                rc = -EBUSY;
+                goto error_unlock;
+        }
+
+        /* FIXME: Check if this file is open. */
+
+        handle = presto_trans_start(fset, dentry->d_inode, KML_OPCODE_TRUNC);
+        if (IS_ERR(handle)) {
+                rc = -ENOMEM;
+                goto error_unlock;
+        }
+
+        /* FIXME: Write LML record */
+
+        oldsize = dentry->d_inode->i_size;
+        rc = izo_do_truncate(fset, dentry, 0, oldsize);
+        if (rc != 0)
+                goto error_clear;
+        rc = izo_do_truncate(fset, dentry, oldsize, 0);
+        if (rc != 0)
+                goto error_clear;
 
+ error_clear:
+        /* FIXME: clear LML record */
 
+ error_unlock:
+        /* FIXME: release the lock here */
+
+ error:
+        if (handle != NULL && !IS_ERR(handle))
+                presto_trans_commit(fset, handle);
+        if (path != NULL)
+                PRESTO_FREE(path, len + 1);
+        return rc;
+#else
+        return 0;
+#endif
+}
diff -Nru a/fs/intermezzo/fileset.c b/fs/intermezzo/fileset.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/intermezzo/fileset.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,676 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Managing filesets
+ *
+ */
+
+#define __NO_VERSION__
+#include <stdarg.h>
+
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/ext2_fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/intermezzo_fs.h>
+#include <linux/intermezzo_psdev.h>
+
+static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
+{
+        if (presto_d2d(dentry) == NULL) {
+                EXIT;
+                return NULL;
+        }
+        return presto_d2d(dentry)->dd_fset;
+}
+
+/* find the fileset dentry for this dentry */
+struct presto_file_set *presto_fset(struct dentry *de)
+{
+        struct dentry *fsde;
+        ENTRY;
+        if ( !de->d_inode ) {
+                /* FIXME: is this ok to be NULL? */
+                CDEBUG(D_INODE,"presto_fset: warning %*s has NULL inode.\n",
+                de->d_name.len, de->d_name.name);
+        }
+        for (fsde = de;; fsde = fsde->d_parent) {
+                if ( presto_dentry2fset(fsde) ) {
+                        EXIT;
+                        return presto_dentry2fset(fsde);
+                }
+                if (fsde->d_parent == fsde)
+                        break;
+        }
+        EXIT;
+        return NULL;
+}
+
+int presto_get_lastrecno(char *path, off_t *recno)
+{
+        struct nameidata nd; 
+        struct presto_file_set *fset;
+        struct dentry *dentry;
+        int error;
+        ENTRY;
+
+        error = presto_walk(path, &nd);
+        if (error) {
+                EXIT;
+                return error;
+        }
+
+        dentry = nd.dentry;
+
+        error = -ENXIO;
+        if ( !presto_ispresto(dentry->d_inode) ) {
+                EXIT;
+                goto kml_out;
+        }
+
+        error = -EINVAL;
+        if ( ! presto_dentry2fset(dentry)) {
+                EXIT;
+                goto kml_out;
+        }
+
+        fset = presto_dentry2fset(dentry);
+        if (!fset) {
+                EXIT;
+                goto kml_out;
+        }
+        error = 0;
+        *recno = fset->fset_kml.fd_recno;
+
+ kml_out:
+        path_release(&nd);
+        return error;
+}
+
+static char * _izo_make_path(char *fsetname, char *name)
+{
+        char *path = NULL;
+        int len;
+
+        len = strlen("/.intermezzo/") + strlen(fsetname) 
+                + 1 + strlen(name) + 1;
+
+        PRESTO_ALLOC(path, len);
+        if (path == NULL)
+                return NULL;
+
+        sprintf(path, "/.intermezzo/%s/%s", fsetname, name);
+
+        return path;
+}
+
+char * izo_make_path(struct presto_file_set *fset, char *name)
+{
+        return _izo_make_path(fset->fset_name, name);
+}
+
+static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode) 
+{
+        char *path;
+        struct file *f;
+        int error;
+        ENTRY;
+
+        path = _izo_make_path(fsetname, name);
+        if (path == NULL) {
+                EXIT;
+                return ERR_PTR(-ENOMEM);
+        }
+
+        CDEBUG(D_INODE, "opening file %s\n", path);
+        f = filp_open(path, flags, mode);
+        error = PTR_ERR(f);
+        if (IS_ERR(f)) {
+                CDEBUG(D_INODE, "Error %d\n", error);
+        }
+
+        PRESTO_FREE(path, strlen(path));
+
+        EXIT;
+        return f;
+
+}
+
+struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode) 
+{
+        return _izo_fset_open(fset->fset_name, name, flags, mode);
+}
+
+
+
+/*
+ *  note: this routine "pins" a dentry for a fileset root
+ */
+int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname,
+                        unsigned int flags)
+{
+        struct presto_file_set *fset = NULL;
+        struct presto_cache *cache;
+        int error;
+        struct file  *fset_root;
+        struct dentry *dentry;
+
+        ENTRY;
+
+        fset_root = _izo_fset_open(fsetname, "ROOT",  O_RDONLY, 000);
+        if (IS_ERR(fset_root)) {
+                CERROR("Can't open %s/ROOT\n", fsetname);
+                EXIT;
+                error = PTR_ERR(fset_root);
+                goto out;
+        }
+        dentry = dget(fset_root->f_dentry);
+        filp_close(fset_root, NULL);
+
+        dentry->d_inode->i_op = ioctl_dentry->d_inode->i_op;
+        dentry->d_inode->i_fop = ioctl_dentry->d_inode->i_fop;
+        dentry->d_op = ioctl_dentry->d_op;
+        fset = presto_dentry2fset(dentry);
+        if (fset && (fset->fset_dentry == dentry) ) { 
+                CERROR("Fsetroot already set (inode %ld)\n",
+                       dentry->d_inode->i_ino);
+                /* XXX: ignore because clear_fsetroot is broken  */
+#if 0
+                dput(dentry);
+                EXIT;
+                error = -EEXIST;
+                goto out;
+#endif
+        }
+
+        cache = presto_get_cache(dentry->d_inode);
+        if (!cache) { 
+                CERROR("No cache found for inode %ld\n",
+                       dentry->d_inode->i_ino);
+                EXIT;
+                error = -ENODEV;
+                goto out_free;
+        }
+
+        PRESTO_ALLOC(fset, sizeof(*fset));
+        if ( !fset ) {
+                CERROR("No memory allocating fset for %s\n", fsetname);
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        CDEBUG(D_INODE, "fset at %p\n", fset);
+
+        CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n",
+               dentry->d_inode->i_ino, fsetname);
+
+        fset->fset_mnt = mntget(current->fs->pwdmnt); 
+        fset->fset_cache = cache;
+        fset->fset_dentry = dentry; 
+        fset->fset_name = strdup(fsetname);
+        fset->fset_chunkbits = CHUNK_BITS;
+        fset->fset_flags = flags;
+        fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; 
+        fset->fset_permit_lock = SPIN_LOCK_UNLOCKED;
+        PRESTO_ALLOC(fset->fset_reint_buf, 64 * 1024);
+        if (fset->fset_reint_buf == NULL) {
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        init_waitqueue_head(&fset->fset_permit_queue);
+
+        if (presto_d2d(dentry) == NULL) { 
+                dentry->d_fsdata = izo_alloc_ddata();
+        }
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: %s: no memory\n", __FUNCTION__);
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        presto_d2d(dentry)->dd_fset = fset;
+        list_add(&fset->fset_list, &cache->cache_fset_list);
+
+        error = izo_init_kml_file(fset, &fset->fset_kml);
+        if ( error ) {
+                EXIT;
+                CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
+                goto out_list_del;
+        }
+
+        error = izo_init_lml_file(fset, &fset->fset_lml);
+        if ( error ) {
+                int rc;
+                EXIT;
+                rc = izo_log_close(&fset->fset_kml);
+                CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
+                goto out_list_del;
+        }
+
+        /* init_last_rcvd_file could trigger a presto_file_write(), which
+         * requires that the lml structure be initialized. -phil */
+        error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd);
+        if ( error ) {
+                int rc;
+                EXIT;
+                rc = izo_log_close(&fset->fset_kml);
+                rc = izo_log_close(&fset->fset_lml);
+                CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
+                goto out_list_del;
+        }
+
+        CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p,"
+               "fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n",
+               fset, dentry, fset->fset_dentry, fset->fset_name, cache,
+               presto_d2d(dentry)->dd_fset);
+
+        EXIT;
+        return 0;
+
+ out_list_del:
+        list_del(&fset->fset_list);
+        presto_d2d(dentry)->dd_fset = NULL;
+ out_free:
+        if (fset) {
+                mntput(fset->fset_mnt); 
+                if (fset->fset_reint_buf != NULL)
+                        PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
+                PRESTO_FREE(fset, sizeof(*fset));
+        }
+        dput(dentry); 
+ out:
+        return error;
+}
+
+static int izo_cleanup_fset(struct presto_file_set *fset)
+{
+        int error;
+        struct presto_cache *cache;
+
+        ENTRY;
+
+        CERROR("Cleaning up fset %s\n", fset->fset_name);
+
+        error = izo_log_close(&fset->fset_kml);
+        if (error)
+                CERROR("InterMezzo: Closing kml for fset %s: %d\n",
+                       fset->fset_name, error);
+        error = izo_log_close(&fset->fset_lml);
+        if (error)
+                CERROR("InterMezzo: Closing lml for fset %s: %d\n",
+                       fset->fset_name, error);
+        error = izo_log_close(&fset->fset_rcvd);
+        if (error)
+                CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n",
+                       fset->fset_name, error);
+
+        cache = fset->fset_cache;
+
+        list_del(&fset->fset_list);
+
+        presto_d2d(fset->fset_dentry)->dd_fset = NULL;
+        dput(fset->fset_dentry);
+        mntput(fset->fset_mnt);
+
+        PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
+        PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
+        PRESTO_FREE(fset, sizeof(*fset));
+        EXIT;
+        return error;
+}
+
+int izo_clear_fsetroot(struct dentry *dentry)
+{
+        struct presto_file_set *fset;
+
+        ENTRY;
+
+        fset = presto_dentry2fset(dentry);
+        if (!fset) {
+                EXIT;
+                return -EINVAL;
+        }
+
+        izo_cleanup_fset(fset);
+        EXIT;
+        return 0;
+}
+
+int izo_clear_all_fsetroots(struct presto_cache *cache)
+{
+        struct presto_file_set *fset;
+        struct list_head *tmp,*tmpnext;
+        int error;
+ 
+        error = 0;
+        tmp = &cache->cache_fset_list;
+        tmpnext = tmp->next;
+        while ( tmpnext != &cache->cache_fset_list) {
+                tmp = tmpnext;
+                tmpnext = tmp->next;
+                fset = list_entry(tmp, struct presto_file_set, fset_list);
+
+                error = izo_cleanup_fset(fset);
+                if (error)
+                        break;
+        }
+        return error;
+}
+
+static struct vfsmount *izo_alloc_vfsmnt(void)
+{
+        struct vfsmount *mnt;
+        PRESTO_ALLOC(mnt, sizeof(*mnt));
+        if (mnt) {
+                memset(mnt, 0, sizeof(struct vfsmount));
+                atomic_set(&mnt->mnt_count,1);
+                INIT_LIST_HEAD(&mnt->mnt_hash);
+                INIT_LIST_HEAD(&mnt->mnt_child);
+                INIT_LIST_HEAD(&mnt->mnt_mounts);
+                INIT_LIST_HEAD(&mnt->mnt_list);
+        }
+        return mnt;
+}
+
+
+static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt,
+                           struct run_ctxt *save) 
+{
+        struct run_ctxt new;
+
+        mnt->mnt_root = root;
+        mnt->mnt_sb = root->d_inode->i_sb;
+        unlock_super(mnt->mnt_sb);
+
+        new.rootmnt = mnt;
+        new.root = root;
+        new.pwdmnt = mnt;
+        new.pwd = root;
+        new.fsuid = 0;
+        new.fsgid = 0;
+        new.fs = get_fs(); 
+        /* XXX where can we get the groups from? */
+        new.ngroups = 0;
+
+        push_ctxt(save, &new); 
+}
+
+static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save) 
+{
+        lock_super(mnt->mnt_sb);
+        pop_ctxt(save); 
+}
+
+static int izo_simple_mkdir(struct dentry *dir, char *name, int mode)
+{
+        struct dentry *dchild; 
+        int err;
+        ENTRY;
+        
+        dchild = lookup_one_len(name, dir, strlen(name));
+        if (IS_ERR(dchild)) { 
+                EXIT;
+                return PTR_ERR(dchild); 
+        }
+
+        if (dchild->d_inode) { 
+                dput(dchild);
+                EXIT;
+                return -EEXIST;
+        }
+
+        err = vfs_mkdir(dir->d_inode, dchild, mode);
+        dput(dchild);
+        
+        EXIT;
+        return err;
+}
+
+static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt)
+{
+        struct dentry *dchild; 
+        int err;
+        ENTRY;
+        
+        dchild = lookup_one_len(name, dir, strlen(name));
+        if (IS_ERR(dchild)) { 
+                EXIT;
+                return PTR_ERR(dchild); 
+        }
+
+        if (dchild->d_inode) { 
+                dput(dchild);
+                EXIT;
+                return -EEXIST;
+        }
+
+        err = vfs_symlink(dir->d_inode, dchild, tgt);
+        dput(dchild);
+        
+        EXIT;
+        return err;
+}
+
+/*
+ * run set_fsetroot in chroot environment
+ */
+int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname,
+                                 unsigned int flags)
+{
+        int rc;
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+
+        if (root != root->d_inode->i_sb->s_root) {
+                CERROR ("IOC_SET_FSET must be called on mount point\n");
+                return -ENODEV;
+        }
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount;
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        izo_setup_ctxt(root, mnt, &save); 
+        rc = presto_set_fsetroot(root, fsetname, flags);
+        izo_cleanup_ctxt(mnt, &save);
+        return rc;
+}
+
+/* XXX: this function should detect if fsetname is already in use for
+   the cache under root
+*/ 
+int izo_prepare_fileset(struct dentry *root, char *fsetname) 
+{
+        int err;
+        struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL; 
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount = izo_alloc_vfsmnt();
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        if (!fsetname) 
+                fsetname = "rootfset"; 
+
+        izo_setup_ctxt(root, mnt, &save); 
+
+        err = izo_simple_mkdir(root, ".intermezzo", 0755);
+        CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err); 
+
+        err = izo_simple_mkdir(root, "..iopen..", 0755);
+        CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err); 
+
+        dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen.."));
+        if (IS_ERR(dotiopen)) { 
+                EXIT;
+                goto out;
+        }
+        dotiopen->d_inode->i_op = &presto_dir_iops;
+        dput(dotiopen);
+
+
+        dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo"));
+        if (IS_ERR(dotizo)) { 
+                EXIT;
+                goto out;
+        }
+
+
+        err = izo_simple_mkdir(dotizo, fsetname, 0755);
+        CDEBUG(D_CACHE, "mkdir err %d\n", err); 
+
+        /* XXX find the dentry of the root of the fileset (root for now) */ 
+        fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname));
+        if (IS_ERR(fsetdir)) { 
+                EXIT;
+                goto out;
+        }
+
+        err = izo_simple_symlink(fsetdir, "ROOT", "../.."); 
+
+        /* XXX read flags from flags file */ 
+        err =  presto_set_fsetroot(root, fsetname, 0); 
+        CDEBUG(D_CACHE, "set_fsetroot err %d\n", err); 
+
+ out:
+        if (dotizo && !IS_ERR(dotizo)) 
+                dput(dotizo); 
+        if (fsetdir && !IS_ERR(fsetdir)) 
+                dput(fsetdir); 
+        izo_cleanup_ctxt(mnt, &save);
+        return err; 
+}
+
+int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data)
+{
+        int rc = 0;
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+        struct nameidata nd;
+        struct dentry *dentry;
+        struct presto_dentry_data *dd;
+        struct dentry *root;
+        char *buf = NULL; 
+
+        ENTRY;
+
+
+        root = dir->f_dentry;
+
+        /* actually, needs to be called on ROOT of fset, not mount point  
+        if (root != root->d_inode->i_sb->s_root) {
+                CERROR ("IOC_SET_FSET must be called on mount point\n");
+                return -ENODEV;
+        }
+        */
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount;
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        izo_setup_ctxt(root, mnt, &save); 
+        
+        PRESTO_ALLOC(buf, data->ioc_plen1);
+        if (!buf) { 
+                rc = -ENOMEM;
+                EXIT;
+                goto out;
+        }
+        if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
+                rc =  -EFAULT;
+                EXIT;
+                goto out;
+        }
+
+        rc = presto_walk(buf, &nd);
+        if (rc) {
+                CERROR("Unable to open: %s\n", buf);
+                EXIT;
+                goto out;
+        }
+        dentry = nd.dentry;
+        if (!dentry) {
+                CERROR("no dentry!\n");
+                rc =  -EINVAL;
+                EXIT;
+                goto out_close;
+        }
+        dd = presto_d2d(dentry);
+        if (!dd) {
+                CERROR("no dentry_data!\n");
+                rc = -EINVAL;
+                EXIT;
+                goto out_close;
+        }
+
+        CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
+
+        if (dd->remote_ino != 0) {
+                CERROR("remote_ino already set? %Lx:%Lx\n", dd->remote_ino,
+                       dd->remote_generation);
+                rc = 0;
+                EXIT;
+                goto out_close;
+        }
+
+
+        CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd, 
+               buf, data->ioc_ino,
+               data->ioc_generation);
+        dd->remote_ino = data->ioc_ino;
+        dd->remote_generation = data->ioc_generation;
+
+        EXIT;
+ out_close:
+        path_release(&nd);
+ out:
+        if (buf)
+                PRESTO_FREE(buf, data->ioc_plen1);
+        izo_cleanup_ctxt(mnt, &save);
+        return rc;
+}
diff -Nru a/fs/intermezzo/inode.c b/fs/intermezzo/inode.c
--- a/fs/intermezzo/inode.c	Tue Oct 15 20:29:11 2002
+++ b/fs/intermezzo/inode.c	Tue Oct 15 20:29:11 2002
@@ -1,11 +1,27 @@
-/*
- * Super block/filesystem wide operations
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
+ *    Michael Callahan <callahan@maths.ox.ac.uk>
+ *  Copyright (C) 1999 Carnegie Mellon University
+ *    Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
  *
- * Copryright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
- * Michael Callahan <callahan@maths.ox.ac.uk>
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
  *
- * Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>
- * Copyright (C) Carnegie Mellon University
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Super block/filesystem wide operations
  */
 
 #define __NO_VERSION__
@@ -15,6 +31,7 @@
 #include <linux/string.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
 #include <linux/unistd.h>
 
 #include <asm/system.h>
@@ -23,61 +40,53 @@
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <asm/uaccess.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
+#include <asm/segment.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
-extern int presto_remount(struct super_block *, int *, char *);
-
-int presto_excluded_gid = PRESTO_EXCL_GID;
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                              struct presto_file_set **);
 extern void presto_free_cache(struct presto_cache *);
 
-
 void presto_set_ops(struct inode *inode, struct  filter_fs *filter)
 {
-	ENTRY; 
-	if (inode->i_gid == presto_excluded_gid ) { 
-		EXIT;
-                CDEBUG(D_INODE, "excluded methods for %ld at %p, %p\n",
-                       inode->i_ino, inode->i_op, inode->i_fop);
-		return; 
-	}
+        ENTRY; 
+
+        if (!inode || is_bad_inode(inode))
+                return;
+
         if (S_ISREG(inode->i_mode)) {
                 if ( !filter_c2cfiops(filter) ) {
                        filter_setup_file_ops(filter, 
-					     inode, &presto_file_iops,
-					     &presto_file_fops);
+                                             inode, &presto_file_iops,
+                                             &presto_file_fops);
                 }
-		inode->i_op = filter_c2ufiops(filter);
-		inode->i_fop = filter_c2uffops(filter);
+                inode->i_op = filter_c2ufiops(filter);
+                inode->i_fop = filter_c2uffops(filter);
                 CDEBUG(D_INODE, "set file methods for %ld to %p\n",
                        inode->i_ino, inode->i_op);
         } else if (S_ISDIR(inode->i_mode)) {
-		inode->i_op = filter_c2udiops(filter);
-		inode->i_fop = filter_c2udfops(filter);
-                CDEBUG(D_INODE, "set dir methods for %ld to %p lookup %p\n",
-                       inode->i_ino, inode->i_op, inode->i_op->lookup);
+                inode->i_op = filter_c2udiops(filter);
+                inode->i_fop = filter_c2udfops(filter);
+                CDEBUG(D_INODE, "set dir methods for %ld to %p ioctl %p\n",
+                       inode->i_ino, inode->i_op, inode->i_fop->ioctl);
         } else if (S_ISLNK(inode->i_mode)) {
                 if ( !filter_c2csiops(filter)) {
                         filter_setup_symlink_ops(filter, 
                                                  inode,
                                                  &presto_sym_iops, 
-						 &presto_sym_fops);
+                                                 &presto_sym_fops);
                 }
-		inode->i_op = filter_c2usiops(filter);
-		inode->i_fop = filter_c2usfops(filter);
+                inode->i_op = filter_c2usiops(filter);
+                inode->i_fop = filter_c2usfops(filter);
                 CDEBUG(D_INODE, "set link methods for %ld to %p\n",
                        inode->i_ino, inode->i_op);
         }
-	EXIT;
+        EXIT;
 }
 
 void presto_read_inode(struct inode *inode)
@@ -86,7 +95,7 @@
 
         cache = presto_get_cache(inode);
         if ( !cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+                CERROR("PRESTO: BAD, BAD: cannot find cache\n");
                 make_bad_inode(inode);
                 return ;
         }
@@ -94,37 +103,52 @@
         filter_c2csops(cache->cache_filter)->read_inode(inode);
 
         CDEBUG(D_INODE, "presto_read_inode: ino %ld, gid %d\n", 
-	       inode->i_ino, inode->i_gid);
-
-	//        if (inode->i_gid == presto_excluded_gid)
-        //       return;
+               inode->i_ino, inode->i_gid);
 
-	presto_set_ops(inode, cache->cache_filter); 
+        presto_set_ops(inode, cache->cache_filter); 
         /* XXX handle special inodes here or not - probably not? */
 }
 
-void presto_put_super(struct super_block *sb)
+static void presto_put_super(struct super_block *sb)
 {
         struct presto_cache *cache;
-        struct upc_comm *psdev;
+        struct upc_channel *channel;
         struct super_operations *sops;
         struct list_head *lh;
+        int err;
 
-	ENTRY;
-        cache = presto_find_cache(sb);
+        ENTRY;
+        cache = presto_cache_find(to_kdev_t(sb->s_dev));
         if (!cache) {
-		EXIT;
+                EXIT;
                 goto exit;
-	}
-        psdev = &upc_comms[presto_c2m(cache)];
-
+        }
+        channel = &izo_channels[presto_c2m(cache)];
         sops = filter_c2csops(cache->cache_filter);
+        err = izo_clear_all_fsetroots(cache); 
+        if (err) { 
+                CERROR("%s: err %d\n", __FUNCTION__, err);
+        }
+        PRESTO_FREE(cache->cache_vfsmount, sizeof(struct vfsmount));
+
+        /* look at kill_super - fsync_super is not exported GRRR but 
+           probably not needed */ 
+        unlock_super(sb);
+        shrink_dcache_parent(cache->cache_root); 
+        dput(cache->cache_root); 
+        //fsync_super(sb); 
+        lock_super(sb);
+
+        if (sops->write_super)
+                sops->write_super(sb); 
+
         if (sops->put_super)
                 sops->put_super(sb);
 
         /* free any remaining async upcalls when the filesystem is unmounted */
-        lh = psdev->uc_pending.next;
-        while ( lh != &psdev->uc_pending) {
+        spin_lock(&channel->uc_lock);
+        lh = channel->uc_pending.next;
+        while ( lh != &channel->uc_pending) {
                 struct upc_req *req;
                 req = list_entry(lh, struct upc_req, rq_chain);
 
@@ -136,6 +160,8 @@
                 PRESTO_FREE(req->rq_data, req->rq_bufsize);
                 PRESTO_FREE(req, sizeof(struct upc_req));
         }
+        list_del(&cache->cache_channel_list); 
+        spin_unlock(&channel->uc_lock);
 
         presto_free_cache(cache);
 
@@ -146,18 +172,16 @@
         return ;
 }
 
+struct super_operations presto_super_ops = {
+        .read_inode    = presto_read_inode,
+        .put_super     = presto_put_super,
+};
+
 
 /* symlinks can be chowned */
 struct inode_operations presto_sym_iops = {
-	setattr:	presto_setattr
+        .setattr       = presto_setattr
 };
 
 /* NULL for now */
 struct file_operations presto_sym_fops; 
-
-struct super_operations presto_super_ops = {
-        read_inode:     presto_read_inode,
-        put_super:      presto_put_super,
-        remount_fs:     presto_remount
-};
-MODULE_LICENSE("GPL");
diff -Nru a/fs/intermezzo/journal.c b/fs/intermezzo/journal.c
--- a/fs/intermezzo/journal.c	Tue Oct 15 20:29:11 2002
+++ b/fs/intermezzo/journal.c	Tue Oct 15 20:29:11 2002
@@ -1,31 +1,63 @@
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam
+ *  Copyright (C) 2001 Cluster File Systems, Inc. 
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *  Support for journalling extended attributes
+ *  Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ * 
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
  *
- * Support for journalling extended attributes
- * (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/namei.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/time.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
-static int presto_log(struct presto_file_set *fset, struct rec_info *rec,
-                      const char *buf, size_t size,
-                      const char *string1, int len1, 
-                      const char *string2, int len2,
-                      const char *string3, int len3);
+struct presto_reservation_data {
+        unsigned int ri_recno;
+        loff_t ri_offset;
+        loff_t ri_size;
+        struct list_head ri_list;
+};
+
+/* 
+ *  Locking Semantics
+ * 
+ * write lock in struct presto_log_fd: 
+ *  - name: fd_lock
+ *  - required for: accessing any field in a presto_log_fd 
+ *  - may not be held across I/O
+ *  - 
+ *  
+ */
 
 /*
  *  reserve record space and/or atomically request state of the log
@@ -55,22 +87,25 @@
 
         fd->fd_recno++;
         
-        /* this move the fd_offset back after truncation */ 
+        /* this moves the fd_offset back after truncation */ 
         if ( list_empty(&fd->fd_reservations) && 
              !chunked_record) { 
                 fd->fd_offset = fd->fd_file->f_dentry->d_inode->i_size;
         }
 
         rec->offset = fd->fd_offset;
-        rec->recno = fd->fd_recno;
+        if (rec->is_kml)
+                rec->offset += fset->fset_kml_logical_off;
 
-        fd->fd_offset += rec->size;
+        rec->recno = fd->fd_recno;
 
         /* add the reservation data to the end of the list */
-        list_add(&rd->ri_list, fd->fd_reservations.prev);
-        rd->ri_offset = rec->offset;
+        rd->ri_offset = fd->fd_offset;
         rd->ri_size = rec->size;
         rd->ri_recno = rec->recno; 
+        list_add(&rd->ri_list, fd->fd_reservations.prev);
+
+        fd->fd_offset += rec->size;
 
         write_unlock(&fd->fd_lock); 
 
@@ -85,61 +120,92 @@
         write_unlock(&fd->fd_lock);
 }
 
-static int presto_do_truncate(struct presto_file_set *fset, 
-                              struct dentry *dentry, loff_t length, 
-                              loff_t size_check)
+/* XXX should we ask for do_truncate to be exported? */
+int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry,
+                    loff_t length,  loff_t size_check)
 {
         struct inode *inode = dentry->d_inode;
-        struct inode_operations *op; 
         int error;
         struct iattr newattrs;
 
         ENTRY;
 
-        /* Not pretty: "inode->i_size" shouldn't really be "loff_t". */
-        if ((off_t) length < 0)
+        if (length < 0) {
+                EXIT;
                 return -EINVAL;
+        }
 
-        fs_down(&inode->i_sem);
+        down(&inode->i_sem);
         lock_kernel();
         
         if (size_check != inode->i_size) { 
                 unlock_kernel();
-                fs_up(&inode->i_sem);
+                up(&inode->i_sem);
                 EXIT;
                 return -EALREADY; 
         }
 
         newattrs.ia_size = length;
         newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-        op = filter_c2cfiops(fset->fset_cache->cache_filter);
 
-        if (op != NULL && op->setattr != NULL)
-                error = op->setattr(dentry, &newattrs);
+        if (inode->i_op && inode->i_op->setattr)
+                error = inode->i_op->setattr(dentry, &newattrs);
         else {
                 inode_setattr(dentry->d_inode, &newattrs);
-                /* Some filesystems, e.g. ext2 and older versions of ext3
-                   legitimately do not have a <fs>_setattr method. -SHP
-                */
-                /*
-                printk ("Warning:: int presto_do_truncate(xxx), op->setattr == NULL");
-		error = -EOPNOTSUPP; 
-		*/
-		error = 0;
+                error = 0;
         }
+
         unlock_kernel();
-        fs_up(&inode->i_sem);
+        up(&inode->i_sem);
         EXIT;
         return error;
 }
 
+static void presto_kml_truncate(struct presto_file_set *fset)
+{
+        int rc;
+        ENTRY;
+
+        write_lock(&fset->fset_kml.fd_lock);
+        if (fset->fset_kml.fd_truncating == 1 ) {
+                write_unlock(&fset->fset_kml.fd_lock);
+                EXIT;
+                return;
+        }
+
+        fset->fset_kml.fd_truncating = 1;
+        write_unlock(&fset->fset_kml.fd_lock);
+
+        CERROR("islento: %d, count: %d\n",
+               ISLENTO(presto_i2m(fset->fset_dentry->d_inode)),
+               fset->fset_permit_count);
+
+        rc = izo_upc_kml_truncate(fset->fset_cache->cache_psdev->uc_minor,
+                                fset->fset_lento_off, fset->fset_lento_recno,
+                                fset->fset_name);
+
+        /* Userspace is the only permitholder now, and will retain an exclusive
+         * hold on the permit until KML truncation completes. */
+        /* FIXME: double check this code path now that the precise semantics of
+         * fset->fset_permit_count have changed. */
+
+        if (rc != 0) {
+                write_lock(&fset->fset_kml.fd_lock);
+                fset->fset_kml.fd_truncating = 0;
+                write_unlock(&fset->fset_kml.fd_lock);
+        }
+
+        EXIT;
+}
 
 void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
                          int op)
 {
         ENTRY;
-        if ( !fset->fset_cache->cache_filter->o_trops )
+        if ( !fset->fset_cache->cache_filter->o_trops ) {
+                EXIT;
                 return NULL;
+        }
         EXIT;
         return fset->fset_cache->cache_filter->o_trops->tr_start
                 (fset, inode, op);
@@ -148,28 +214,39 @@
 void presto_trans_commit(struct presto_file_set *fset, void *handle)
 {
         ENTRY;
-        if (!fset->fset_cache->cache_filter->o_trops )
+        if (!fset->fset_cache->cache_filter->o_trops ) {
+                EXIT;
                 return;
-        EXIT;
-        return fset->fset_cache->cache_filter->o_trops->tr_commit(fset, handle);
+        }
 
+        fset->fset_cache->cache_filter->o_trops->tr_commit(fset, handle);
+
+        /* Check to see if the KML needs truncated. */
+        if (fset->kml_truncate_size > 0 &&
+            !fset->fset_kml.fd_truncating &&
+            fset->fset_kml.fd_offset > fset->kml_truncate_size) {
+                CDEBUG(D_JOURNAL, "kml size: %lu; truncating\n",
+                       (unsigned long)fset->fset_kml.fd_offset);
+                presto_kml_truncate(fset);
+        }
+        EXIT;
 }
 
 inline int presto_no_journal(struct presto_file_set *fset)
 {
         int minor = fset->fset_cache->cache_psdev->uc_minor;
-        return upc_comms[minor].uc_no_journal;
+        return izo_channels[minor].uc_no_journal;
 }
 
 #define size_round(x)  (((x)+3) & ~0x3)
 
 #define BUFF_FREE(buf) PRESTO_FREE(buf, PAGE_SIZE)
-#define BUFF_ALLOC(newbuf, oldbuf)                      \
-        PRESTO_ALLOC(newbuf, char *, PAGE_SIZE);        \
-        if ( !newbuf ) {                                \
-                if (oldbuf)                             \
-                        BUFF_FREE(oldbuf);              \
-                return -ENOMEM;                         \
+#define BUFF_ALLOC(newbuf, oldbuf)              \
+        PRESTO_ALLOC(newbuf, PAGE_SIZE);        \
+        if ( !newbuf ) {                        \
+                if (oldbuf)                     \
+                        BUFF_FREE(oldbuf);      \
+                return -ENOMEM;                 \
         }
 
 /*
@@ -232,38 +309,40 @@
                                        __u32 ngroups, gid_t *groups,
                                        __u32 fsuid, __u32 fsgid)
 {
-        struct big_journal_prefix p;
+        struct kml_prefix_hdr p;
+        u32 loggroups[NGROUPS_MAX];
+
         int i; 
 
         p.len = cpu_to_le32(rec->size);
-        p.version = PRESTO_KML_MAJOR_VERSION | PRESTO_KML_MINOR_VERSION;
+        p.version = KML_MAJOR_VERSION | KML_MINOR_VERSION;
         p.pid = cpu_to_le32(current->pid);
-        p.uid = cpu_to_le32(current->uid);
+        p.auid = cpu_to_le32(current->uid);
         p.fsuid = cpu_to_le32(fsuid);
         p.fsgid = cpu_to_le32(fsgid);
         p.ngroups = cpu_to_le32(ngroups);
         p.opcode = cpu_to_le32(opcode);
         for (i=0 ; i < ngroups ; i++)
-                p.groups[i] = cpu_to_le32((__u32) groups[i]);
+                loggroups[i] = cpu_to_le32((__u32) groups[i]);
 
-        buf = logit(buf, &p, sizeof(struct journal_prefix) + 
-                    sizeof(__u32) * ngroups);
+        buf = logit(buf, &p, sizeof(struct kml_prefix_hdr));
+        buf = logit(buf, &loggroups, sizeof(__u32) * ngroups);
         return buf;
 }
 
 static inline char *
 journal_log_prefix(char *buf, int opcode, struct rec_info *rec)
 {
-	__u32 groups[NGROUPS_MAX]; 
-	int i; 
+        __u32 groups[NGROUPS_MAX]; 
+        int i; 
 
-	/* convert 16 bit gid's to 32 bit gid's */
-	for (i=0; i<current->ngroups; i++) 
-		groups[i] = (__u32) current->groups[i];
-	
+        /* convert 16 bit gid's to 32 bit gid's */
+        for (i=0; i<current->ngroups; i++) 
+                groups[i] = (__u32) current->groups[i];
+        
         return journal_log_prefix_with_groups_and_ids(buf, opcode, rec,
                                                       (__u32)current->ngroups,
-						      groups,
+                                                      groups,
                                                       (__u32)current->fsuid,
                                                       (__u32)current->fsgid);
 }
@@ -278,26 +357,57 @@
                                                       (__u32)current->fsgid);
 }
 
-static inline char *log_version(char *buf, struct dentry *dentry)
+static inline char *log_dentry_version(char *buf, struct dentry *dentry)
 {
         struct presto_version version;
 
         presto_getversion(&version, dentry->d_inode);
+        
+        version.pv_mtime = HTON__u64(version.pv_mtime);
+        version.pv_ctime = HTON__u64(version.pv_ctime);
+        version.pv_size = HTON__u64(version.pv_size);
 
         return logit(buf, &version, sizeof(version));
 }
 
+static inline char *log_version(char *buf, struct presto_version *pv)
+{
+        struct presto_version version;
+
+        memcpy(&version, pv, sizeof(version));
+        
+        version.pv_mtime = HTON__u64(version.pv_mtime);
+        version.pv_ctime = HTON__u64(version.pv_ctime);
+        version.pv_size = HTON__u64(version.pv_size);
+
+        return logit(buf, &version, sizeof(version));
+}
+
+static inline char *log_rollback(char *buf, struct izo_rollback_data *rb)
+{
+        struct izo_rollback_data rollback;
+
+        memcpy(&rollback, rb, sizeof(rollback));
+        
+        rollback.rb_mode = HTON__u32(rollback.rb_mode);
+        rollback.rb_rdev = HTON__u32(rollback.rb_rdev);
+        rollback.rb_uid = HTON__u64(rollback.rb_uid);
+        rollback.rb_gid = HTON__u64(rollback.rb_gid);
+
+        return logit(buf, &rollback, sizeof(rollback));
+}
+
 static inline char *journal_log_suffix(char *buf, char *log,
                                        struct presto_file_set *fset,
                                        struct dentry *dentry,
                                        struct rec_info *rec)
 {
-        struct journal_suffix s;
-        struct journal_prefix *p = (struct journal_prefix *)log;
+        struct kml_suffix s;
+        struct kml_prefix_hdr *p = (struct kml_prefix_hdr *)log;
 
 #if 0
-	/* XXX needs to be done after reservation, 
-	   disable ths until version 1.2 */
+        /* XXX needs to be done after reservation, 
+           disable ths until version 1.2 */
         if ( dentry ) { 
                 s.prevrec = cpu_to_le32(rec->offset - 
                                         presto_d2d(dentry)->dd_kml_offset);
@@ -306,56 +416,27 @@
                 s.prevrec = -1;
         }
 #endif
-	s.prevrec = 0; 
+        s.prevrec = 0; 
 
         /* record number needs to be filled in after reservation 
            s.recno = cpu_to_le32(rec->recno); */ 
         s.time = cpu_to_le32(CURRENT_TIME);
-        s.len = cpu_to_le32(p->len);
+        s.len = p->len;
         return logit(buf, &s, sizeof(s));
 }
 
-int presto_close_journal_file(struct presto_file_set *fset)
+int izo_log_close(struct presto_log_fd *logfd)
 {
         int rc = 0;
-        int rc2 = 0;
-        int rc3 = 0;
 
-        ENTRY;
-        if ( fset->fset_kml.fd_file) {
-                rc =filp_close(fset->fset_kml.fd_file, 0);
-                fset->fset_kml.fd_file = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-        if ( rc ) {
-                printk("presto: close files: kml filp won't close %d\n", rc);
-        }
-
-        if ( fset->fset_last_rcvd) {
-                rc2 = filp_close(fset->fset_last_rcvd, 0);
-                fset->fset_last_rcvd = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-
-        if ( rc2 ) {
-                if ( !rc )
-                        rc = rc2;
-                printk("presto: close files: last_rcvd filp won't close %d\n", rc2);
-        }
+        if (logfd->fd_file) {
+                rc = filp_close(logfd->fd_file, 0);
+                logfd->fd_file = NULL;
+        } else
+                CERROR("InterMezzo: %s: no filp\n", __FUNCTION__);
+        if (rc != 0)
+                CERROR("InterMezzo: close files: filp won't close: %d\n", rc);
 
-        if ( fset->fset_lml.fd_file) {
-                rc3 = filp_close(fset->fset_lml.fd_file, 0);
-                fset->fset_lml.fd_file = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-        if ( rc3 ) {
-                if ( (!rc) && (!rc2) )
-                        rc = rc3;
-                printk("presto: close files: lml filp won't close %d\n", rc3);
-        }
         return rc;
 }
 
@@ -390,7 +471,7 @@
         set_fs(get_ds());
         rc = file->f_op->write(file, str, len, off);
         if (rc != len) {
-                printk("presto_fwrite: wrote %d bytes instead of "
+                CERROR("presto_fwrite: wrote %d bytes instead of "
                        "%d at %ld\n", rc, len, (long)*off);
                 rc = -EIO; 
         }
@@ -405,10 +486,9 @@
         mm_segment_t old_fs;
         ENTRY;
 
-        if ( len > 512 ) {
-                printk("presto_fread: read at %Ld for %d bytes, ino %ld\n",
+        if (len > 512)
+                CERROR("presto_fread: read at %Ld for %d bytes, ino %ld\n",
                        *off, len, file->f_dentry->d_inode->i_ino); 
-        }
 
         rc = -EINVAL;
         if ( !off ) {
@@ -435,21 +515,47 @@
         set_fs(get_ds());
         rc = file->f_op->read(file, str, len, off);
         if (rc != len) {
-                printk("presto_fread: read %d bytes instead of "
-                       "%d at %ld\n", rc, len, (long)*off);
+                CDEBUG(D_FILE, "presto_fread: read %d bytes instead of "
+                       "%d at %Ld\n", rc, len, *off);
                 rc = -EIO; 
         }
         set_fs(old_fs);
+        EXIT;
         return rc;
 }
 
+loff_t presto_kml_offset(struct presto_file_set *fset)
+{
+        unsigned int kml_recno;
+        struct presto_log_fd *fd = &fset->fset_kml;
+        loff_t  offset;
+        ENTRY;
+
+        write_lock(&fd->fd_lock); 
+
+        /* Determine the largest valid offset, i.e. up until the first
+         * reservation held on the file. */
+        if ( !list_empty(&fd->fd_reservations) ) {
+                struct presto_reservation_data *rd;
+                rd = list_entry(fd->fd_reservations.next, 
+                                struct presto_reservation_data, 
+                                ri_list);
+                offset = rd->ri_offset;
+                kml_recno = rd->ri_recno;
+        } else {
+                offset = fd->fd_file->f_dentry->d_inode->i_size;
+                kml_recno = fset->fset_kml.fd_recno; 
+        }
+        write_unlock(&fd->fd_lock); 
+        return offset; 
+}
 
 static int presto_kml_dispatch(struct presto_file_set *fset)
 {
         int rc = 0;
         unsigned int kml_recno;
         struct presto_log_fd *fd = &fset->fset_kml;
-        loff_t  offset;
+        loff_t offset;
         ENTRY;
 
         write_lock(&fd->fd_lock); 
@@ -469,18 +575,27 @@
         }
 
         if ( kml_recno < fset->fset_lento_recno ) {
-                printk("presto_kml_dispatch: smoke is coming\n"); 
+                CERROR("presto_kml_dispatch: smoke is coming\n"); 
                 write_unlock(&fd->fd_lock);
+                EXIT;
                 return 0; 
         } else if ( kml_recno == fset->fset_lento_recno ) {
                 write_unlock(&fd->fd_lock);
                 EXIT;
                 return 0; 
+                /* XXX add a further "if" here to delay the KML upcall */ 
+#if 0
+        } else if ( kml_recno < fset->fset_lento_recno + 100) {
+                write_unlock(&fd->fd_lock);
+                EXIT;
+                return 0;
+#endif
         }
         CDEBUG(D_PIOCTL, "fset: %s\n", fset->fset_name);
-        rc = lento_kml(fset->fset_cache->cache_psdev->uc_minor,
+
+        rc = izo_upc_kml(fset->fset_cache->cache_psdev->uc_minor,
                        fset->fset_lento_off, fset->fset_lento_recno,
-                       offset, kml_recno, strlen(fset->fset_name),
+                       offset + fset->fset_kml_logical_off, kml_recno,
                        fset->fset_name);
 
         if ( rc ) {
@@ -496,6 +611,255 @@
         return 0;
 }
 
+int izo_lookup_file(struct presto_file_set *fset, char *path,
+                    struct nameidata *nd)
+{
+        int error = 0;
+
+        CDEBUG(D_CACHE, "looking up: %s\n", path);
+
+        error = path_lookup(path, LOOKUP_PARENT, nd);
+        if (error) {
+                EXIT;
+                return error;
+        }
+
+        return 0;
+}
+
+/* FIXME: this function is a mess of locking and error handling.  There's got to
+ * be a better way. */
+static int do_truncate_rename(struct presto_file_set *fset, char *oldname,
+                              char *newname)
+{
+        struct dentry *old_dentry, *new_dentry;
+        struct nameidata oldnd, newnd;
+        char *oldpath, *newpath;
+        int error;
+
+        ENTRY;
+
+        oldpath = izo_make_path(fset, oldname);
+        if (oldpath == NULL) {
+                EXIT;
+                return -ENOENT;
+        }
+
+        newpath = izo_make_path(fset, newname);
+        if (newpath == NULL) {
+                error = -ENOENT;
+                EXIT;
+                goto exit;
+        }
+
+        if ((error = izo_lookup_file(fset, oldpath, &oldnd)) != 0) {
+                EXIT;
+                goto exit1;
+        }
+
+        if ((error = izo_lookup_file(fset, newpath, &newnd)) != 0) {
+                EXIT;
+                goto exit2;
+        }
+
+        lock_rename(newnd.dentry, oldnd.dentry);
+        old_dentry = lookup_hash(&oldnd.last, oldnd.dentry);
+        error = PTR_ERR(old_dentry);
+        if (IS_ERR(old_dentry)) {
+                EXIT;
+                goto exit3;
+        }
+        error = -ENOENT;
+        if (!old_dentry->d_inode) {
+                EXIT;
+                goto exit4;
+        }
+        new_dentry = lookup_hash(&newnd.last, newnd.dentry);
+        error = PTR_ERR(new_dentry);
+        if (IS_ERR(new_dentry)) {
+                EXIT;
+                goto exit4;
+        }
+
+        {
+        extern int presto_rename(struct inode *old_dir,struct dentry *old_dentry,
+                                struct inode *new_dir,struct dentry *new_dentry);
+        error = presto_rename(old_dentry->d_parent->d_inode, old_dentry,
+                              new_dentry->d_parent->d_inode, new_dentry);
+        }
+
+        dput(new_dentry);
+        EXIT;
+ exit4:
+        dput(old_dentry);
+ exit3:
+        unlock_rename(newnd.dentry, oldnd.dentry);
+        path_release(&newnd);
+ exit2:
+        path_release(&oldnd);
+ exit1:
+        PRESTO_FREE(newpath, strlen(newpath) + 1);
+ exit:
+        PRESTO_FREE(oldpath, strlen(oldpath) + 1);
+        return error;
+}
+
+/* This function is called with the fset->fset_kml.fd_lock held */
+int presto_finish_kml_truncate(struct presto_file_set *fset,
+                               unsigned long int offset)
+{
+        struct lento_vfs_context info;
+        void *handle;
+        struct file *f;
+        struct dentry *dentry;
+        int error = 0, len;
+        struct nameidata nd;
+        char *kmlpath = NULL, *smlpath = NULL;
+        ENTRY;
+
+        if (offset == 0) {
+                /* Lento couldn't do what it needed to; abort the truncation. */
+                fset->fset_kml.fd_truncating = 0;
+                EXIT;
+                return 0;
+        }
+
+        /* someone is about to write to the end of the KML; try again later. */
+        if ( !list_empty(&fset->fset_kml.fd_reservations) ) {
+                EXIT;
+                return -EAGAIN;
+        }
+
+        f = presto_copy_kml_tail(fset, offset);
+        if (IS_ERR(f)) {
+                EXIT;
+                return PTR_ERR(f);
+        }                        
+
+        /* In a single transaction:
+         *
+         *   - unlink 'kml'
+         *   - rename 'kml_tmp' to 'kml'
+         *   - unlink 'sml'
+         *   - rename 'sml_tmp' to 'sml'
+         *   - rewrite the first record of last_rcvd with the new kml
+         *     offset.
+         */
+        handle = presto_trans_start(fset, fset->fset_dentry->d_inode,
+                                    KML_OPCODE_KML_TRUNC);
+        if (IS_ERR(handle)) {
+                presto_release_space(fset->fset_cache, PRESTO_REQLOW);
+                CERROR("ERROR: presto_finish_kml_truncate: no space for transaction\n");
+                EXIT;
+                return -ENOMEM;
+        }
+
+        memset(&info, 0, sizeof(info));
+        info.flags = LENTO_FL_IGNORE_TIME;
+
+        kmlpath = izo_make_path(fset, "kml");
+        if (kmlpath == NULL) {
+                error = -ENOMEM;
+                CERROR("make_path failed: ENOMEM\n");
+                EXIT;
+                goto exit_commit;
+        }
+
+        if ((error = izo_lookup_file(fset, kmlpath, &nd)) != 0) {
+                CERROR("izo_lookup_file(kml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+        down(&nd.dentry->d_inode->i_sem);
+        dentry = lookup_hash(&nd.last, nd.dentry);
+        error = PTR_ERR(dentry);
+        if (IS_ERR(dentry)) {
+                up(&nd.dentry->d_inode->i_sem);
+                path_release(&nd);
+                CERROR("lookup_hash failed\n");
+                EXIT;
+                goto exit_commit;
+        }
+        error = presto_do_unlink(fset, dentry->d_parent, dentry, &info);
+        dput(dentry);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
+
+        if (error != 0) {
+                CERROR("presto_do_unlink(kml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+
+        smlpath = izo_make_path(fset, "sml");
+        if (smlpath == NULL) {
+                error = -ENOMEM;
+                CERROR("make_path() failed: ENOMEM\n");
+                EXIT;
+                goto exit_commit;
+        }
+
+        if ((error = izo_lookup_file(fset, smlpath, &nd)) != 0) {
+                CERROR("izo_lookup_file(sml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+        down(&nd.dentry->d_inode->i_sem);
+        dentry = lookup_hash(&nd.last, nd.dentry);
+        error = PTR_ERR(dentry);
+        if (IS_ERR(dentry)) {
+                up(&nd.dentry->d_inode->i_sem);
+                path_release(&nd);
+                CERROR("lookup_hash failed\n");
+                EXIT;
+                goto exit_commit;
+        }
+        error = presto_do_unlink(fset, dentry->d_parent, dentry, &info);
+        dput(dentry);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
+
+        if (error != 0) {
+                CERROR("presto_do_unlink(sml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+
+        error = do_truncate_rename(fset, "kml_tmp", "kml");
+        if (error != 0)
+                CERROR("do_truncate_rename(kml_tmp, kml) failed: %d\n", error);
+        error = do_truncate_rename(fset, "sml_tmp", "sml");
+        if (error != 0)
+                CERROR("do_truncate_rename(sml_tmp, sml) failed: %d\n", error);
+
+        /* Write a new 'last_rcvd' record with the new KML offset */
+        fset->fset_kml_logical_off += offset;
+        CDEBUG(D_CACHE, "new kml_logical_offset: %Lu\n",
+               fset->fset_kml_logical_off);
+        if (presto_write_kml_logical_offset(fset) != 0) {
+                CERROR("presto_write_kml_logical_offset failed\n");
+        }
+
+        presto_trans_commit(fset, handle);
+
+        /* Everything was successful, so swap the KML file descriptors */
+        filp_close(fset->fset_kml.fd_file, NULL);
+        fset->fset_kml.fd_file = f;
+        fset->fset_kml.fd_offset -= offset;
+        fset->fset_kml.fd_truncating = 0;
+
+        EXIT;
+        return 0;
+
+ exit_commit:
+        presto_trans_commit(fset, handle);
+        len = strlen("/.intermezzo/") + strlen(fset->fset_name) +strlen("sml");
+        if (kmlpath != NULL)
+                PRESTO_FREE(kmlpath, len);
+        if (smlpath != NULL)
+                PRESTO_FREE(smlpath, len);
+        return error;
+}
 
 /* structure of an extended log record:
 
@@ -512,10 +876,10 @@
         size_t prefix_size; 
         int rc;
 
-        prefix_size = size - sizeof(struct journal_suffix);
+        prefix_size = size - sizeof(struct kml_suffix);
         rc = presto_fwrite(f, buf, prefix_size, off);
         if ( rc != prefix_size ) {
-                printk("Write error!\n");
+                CERROR("Write error!\n");
                 EXIT;
                 return -EIO;
         }
@@ -523,7 +887,7 @@
         if  ( string1  && len1 ) {
                 rc = presto_fwrite(f, string1, len1, off);
                 if ( rc != len1 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
@@ -532,7 +896,7 @@
         if  ( string2 && len2 ) {
                 rc = presto_fwrite(f, string2, len2, off);
                 if ( rc != len2 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
@@ -541,16 +905,16 @@
         if  ( string3 && len3 ) {
                 rc = presto_fwrite(f, string3, len3, off);
                 if ( rc != len3 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
         }
 
         rc = presto_fwrite(f, buf + prefix_size,
-                           sizeof(struct journal_suffix), off);
-        if ( rc != sizeof(struct journal_suffix) ) {
-                printk("Write error!\n");
+                           sizeof(struct kml_suffix), off);
+        if ( rc != sizeof(struct kml_suffix) ) {
+                CERROR("Write error!\n");
                 EXIT;
                 return -EIO;
         }
@@ -560,18 +924,20 @@
 
 /*
  * rec->size must be valid prior to calling this function.
+ *
+ * had to export this for branch_reinter in kml_reint.c 
  */
-static int presto_log(struct presto_file_set *fset, struct rec_info *rec,
-                      const char *buf, size_t size,
-                      const char *string1, int len1, 
-                      const char *string2, int len2,
-                      const char *string3, int len3)
+int presto_log(struct presto_file_set *fset, struct rec_info *rec,
+               const char *buf, size_t size,
+               const char *string1, int len1, 
+               const char *string2, int len2,
+               const char *string3, int len3)
 {
         int rc;
         struct presto_reservation_data rd;
         loff_t offset;
         struct presto_log_fd *fd;
-        struct journal_suffix *s;
+        struct kml_suffix *s;
         int prefix_size; 
 
         ENTRY;
@@ -589,17 +955,26 @@
         }
 
         presto_reserve_record(fset, fd, rec, &rd);
-        offset = rec->offset;
+
+        if (rec->is_kml) {
+                if (rec->offset < fset->fset_kml_logical_off) {
+                        CERROR("record with pre-trunc offset.  tell phil.\n");
+                        BUG();
+                }
+                offset = rec->offset - fset->fset_kml_logical_off;
+        } else {
+                offset = rec->offset;
+        }
 
         /* now we know the record number */ 
-        prefix_size = size - sizeof(struct journal_suffix);
-        s = (struct journal_suffix *) (buf + prefix_size); 
-        s->recno =  cpu_to_le32(rec->recno); 
+        prefix_size = size - sizeof(struct kml_suffix);
+        s = (struct kml_suffix *) (buf + prefix_size); 
+        s->recno = cpu_to_le32(rec->recno); 
 
         rc = presto_write_record(fd->fd_file, &offset, buf, size, 
                                  string1, len1, string2, len2, string3, len3); 
         if (rc) {
-                printk("presto: error writing record to %s\n",
+                CERROR("presto: error writing record to %s\n",
                         rec->is_kml ? "KML" : "LML"); 
                 return rc;
         }
@@ -615,7 +990,7 @@
 static int presto_last_record(struct presto_log_fd *fd, loff_t *size, 
                              loff_t *tail_offset, __u32 *recno, loff_t tail)
 {
-        struct journal_suffix suffix;
+        struct kml_suffix suffix;
         int rc;
         loff_t zeroes;
 
@@ -623,7 +998,7 @@
         *tail_offset = 0;
         *size = 0;
         
-        if (tail < sizeof(struct journal_prefix) + sizeof(suffix)) {
+        if (tail < sizeof(struct kml_prefix_hdr) + sizeof(suffix)) {
                 EXIT;
                 return 0;
         }
@@ -643,18 +1018,18 @@
         }
 
         /* zeroes at the begining of file. this is needed to prevent
-	   presto_fread errors  -SHP
-	*/
+           presto_fread errors  -SHP
+        */
         if (zeroes <= 0) return 0;
                        
-        zeroes -= sizeof(suffix);
+        zeroes -= sizeof(suffix) + sizeof(int);
         rc = presto_fread(fd->fd_file, (char *)&suffix, sizeof(suffix), &zeroes);
         if ( rc != sizeof(suffix) ) {
                 EXIT;
                 return rc;
         }
         if ( suffix.len > 500 ) {
-                printk("PRESTO: Warning long record tail at %ld, rec tail_offset at %ld (size %d)\n", 
+                CERROR("InterMezzo: Warning long record tail at %ld, rec tail_offset at %ld (size %d)\n", 
                         (long) zeroes, (long)*tail_offset, suffix.len); 
         }
 
@@ -664,213 +1039,259 @@
         return 0;
 }
 
-static int presto_kml_last_recno(struct presto_file_set *fset)
+static int izo_kml_last_recno(struct presto_log_fd *logfd)
 {
         int rc; 
         loff_t size;
         loff_t tail_offset;
         int recno;
-        loff_t tail = fset->fset_kml.fd_file->f_dentry->d_inode->i_size;
+        loff_t tail = logfd->fd_file->f_dentry->d_inode->i_size;
 
-        if ((rc = presto_last_record(&fset->fset_kml, &size, 
-                                        &tail_offset, &recno, tail)) ) {
+        rc = presto_last_record(logfd, &size, &tail_offset, &recno, tail);
+        if (rc != 0) {
                 EXIT;
                 return rc;
         }
 
-        fset->fset_kml.fd_offset = tail_offset;
-        fset->fset_kml.fd_recno = recno;
+        logfd->fd_offset = tail_offset;
+        logfd->fd_recno = recno;
         CDEBUG(D_JOURNAL, "setting fset_kml->fd_recno to %d, offset  %Ld\n",
                recno, tail_offset); 
         EXIT;
         return 0;
 }
 
-static struct file *presto_log_open(struct presto_file_set *fset, char *name, int flags)
+struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags)
 {
         struct presto_cache *cache = fset->fset_cache;
         struct file *f;
         int error;
-        int mtpt_len, path_len;
-        char *path;
         ENTRY;
 
-        mtpt_len = strlen(cache->cache_mtpt);
-        path_len = mtpt_len + strlen("/.intermezzo/") +
-                strlen(fset->fset_name) + strlen(name);
-
-        error = -ENOMEM;
-        PRESTO_ALLOC(path, char *, path_len + 1);
-        if ( !path ) {
-                EXIT;
-                return ERR_PTR(-ENOMEM);
-        }
-
-        sprintf(path, "%s/.intermezzo/%s/%s", cache->cache_mtpt,
-                fset->fset_name, name);
-        CDEBUG(D_INODE, "opening file %s\n", path);
-
-        f = filp_open(path, flags, 0);
+        f = izo_fset_open(fset, name, flags, 0644);
         error = PTR_ERR(f);
         if (IS_ERR(f)) {
-                CDEBUG(D_INODE, "Error %d\n", error);
                 EXIT;
-                goto out_free;
+                return f;
         }
 
         error = -EINVAL;
         if ( cache != presto_get_cache(f->f_dentry->d_inode) ) {
-                printk("PRESTO: %s cache does not match fset cache!\n", name);
+                CERROR("InterMezzo: %s cache does not match fset cache!\n",name);
                 fset->fset_kml.fd_file = NULL;
                 filp_close(f, NULL);
-                goto out_free;
+                f = NULL;
+                EXIT;
+                return f;
         }
 
         if (cache->cache_filter &&  cache->cache_filter->o_trops &&
-	    cache->cache_filter->o_trops->tr_journal_data) {
-		CDEBUG(D_INODE, "\n");
+            cache->cache_filter->o_trops->tr_journal_data) {
                 cache->cache_filter->o_trops->tr_journal_data
                         (f->f_dentry->d_inode);
         } else {
-                printk("WARNING: InterMezzo no file data logging!\n"); 
+                CERROR("InterMezzo WARNING: no file data logging!\n"); 
         }
 
- out_free:
-        PRESTO_FREE(path, path_len + 1);
-
         EXIT;
+
         return f;
 }
 
-int presto_init_kml_file(struct presto_file_set *fset)
+int izo_init_kml_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
 
         ENTRY;
-        if (fset->fset_kml.fd_file) {
+        if (logfd->fd_file) {
                 CDEBUG(D_INODE, "fset already has KML open\n");
                 EXIT;
                 return 0;
         }
 
-        fset->fset_kml.fd_lock = RW_LOCK_UNLOCKED;
-        INIT_LIST_HEAD(&fset->fset_kml.fd_reservations); 
-        f = presto_log_open(fset, "kml",  O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "kml",  O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_kml.fd_file = f;
-        error = presto_kml_last_recno(fset);
+        logfd->fd_file = f;
+        error = izo_kml_last_recno(logfd);
 
-        if ( error ) {
-                EXIT;
-                fset->fset_kml.fd_file = NULL;
+        if (error) {
+                logfd->fd_file = NULL;
                 filp_close(f, NULL);
-                printk("presto: IO error in KML of fset %s\n", 
+                CERROR("InterMezzo: IO error in KML of fset %s\n",
                        fset->fset_name);
+                EXIT;
+                return error;
         }
-        fset->fset_lento_off = fset->fset_kml.fd_offset;
-        fset->fset_lento_recno = fset->fset_kml.fd_recno;
+        fset->fset_lento_off = logfd->fd_offset;
+        fset->fset_lento_recno = logfd->fd_recno;
 
         EXIT;
         return error;
 }
 
-
-int presto_init_last_rcvd_file(struct presto_file_set *fset)
+int izo_init_last_rcvd_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
+        struct rec_info recinfo;
 
         ENTRY;
-        if (fset->fset_last_rcvd) {
+        if (logfd->fd_file != NULL) {
                 CDEBUG(D_INODE, "fset already has last_rcvd open\n");
                 EXIT;
                 return 0;
         }
 
-        f = presto_log_open(fset, "last_rcvd", O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "last_rcvd", O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_last_rcvd = f;
+        logfd->fd_file = f;
+        logfd->fd_offset = f->f_dentry->d_inode->i_size;
+
+        error = izo_rep_cache_init(fset);
+
+        if (presto_read_kml_logical_offset(&recinfo, fset) == 0) {
+                fset->fset_kml_logical_off = recinfo.offset;
+        } else {
+                /* The 'last_rcvd' file doesn't contain a kml offset record,
+                 * probably because we just created 'last_rcvd'.  Write one. */
+                fset->fset_kml_logical_off = 0;
+                presto_write_kml_logical_offset(fset);
+        }
 
         EXIT;
         return error;
 }
 
-int presto_init_lml_file(struct presto_file_set *fset)
+int izo_init_lml_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
 
         ENTRY;
-        if (fset->fset_lml.fd_file) {
+        if (logfd->fd_file) {
                 CDEBUG(D_INODE, "fset already has lml open\n");
                 EXIT;
                 return 0;
         }
 
-        fset->fset_lml.fd_lock = RW_LOCK_UNLOCKED;
-        INIT_LIST_HEAD(&fset->fset_lml.fd_reservations); 
-        f = presto_log_open(fset, "lml", O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "lml", O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_lml.fd_file = f;
-        fset->fset_lml.fd_offset = 
-                fset->fset_lml.fd_file->f_dentry->d_inode->i_size;
+        logfd->fd_file = f;
+        logfd->fd_offset = f->f_dentry->d_inode->i_size;
 
         EXIT;
         return error;
 }
 
-/* Write the last_rcvd values to the last)_rcvd file */
-int presto_write_last_rcvd(struct rec_info *recinfo,
-                           struct presto_file_set *fset,
-                           struct lento_vfs_context *info)
-{
-        int ret;
-        loff_t off = info->slot_offset;
-        struct {
-                __u32 remote_recno;
-                __u64 remote_offset;
-                __u32 local_recno;
-                __u64 local_offset;
-        } rcvd_rec;
-
-        rcvd_rec.remote_recno = cpu_to_le32(info->recno);
-        rcvd_rec.remote_offset = cpu_to_le64(info->kml_offset);
-        rcvd_rec.local_recno = cpu_to_le32(recinfo->recno);
-        rcvd_rec.local_offset = cpu_to_le64(recinfo->offset + recinfo->size);
+/* Get the KML-offset record from the last_rcvd file */
+int presto_read_kml_logical_offset(struct rec_info *recinfo,
+                                   struct presto_file_set *fset)
+{
+        loff_t off;
+        struct izo_rcvd_rec rec;
+        char uuid[16] = {0};
+
+        off = izo_rcvd_get(&rec, fset, uuid);
+        if (off < 0)
+                return -1;
 
-        ret = presto_fwrite(fset->fset_last_rcvd, (char *)(&rcvd_rec),
-                            sizeof(rcvd_rec), &off);
+        recinfo->offset = rec.lr_local_offset;
+        return 0;
+}
+
+int presto_write_kml_logical_offset(struct presto_file_set *fset)
+{
+        loff_t rc;
+        struct izo_rcvd_rec rec;
+        char uuid[16] = {0};
 
-        if (ret == sizeof(rcvd_rec))
-                ret = 0;
+        rc = izo_rcvd_get(&rec, fset, uuid);
+        if (rc < 0)
+                memset(&rec, 0, sizeof(rec));
 
-        return ret;
+        rec.lr_local_offset =
+                cpu_to_le64(fset->fset_kml_logical_off);
+
+        return izo_rcvd_write(fset, &rec);
 }
 
+struct file * presto_copy_kml_tail(struct presto_file_set *fset,
+                                   unsigned long int start)
+{
+        struct file *f;
+        int len;
+        loff_t read_off, write_off, bytes;
+
+        ENTRY;
+
+        /* Copy the tail of 'kml' to 'kml_tmp' */
+        f = izo_log_open(fset, "kml_tmp", O_RDWR);
+        if (IS_ERR(f)) {
+                EXIT;
+                return f;
+        }
+
+        write_off = 0;
+        read_off = start;
+        bytes = fset->fset_kml.fd_offset - start;
+        while (bytes > 0) {
+                char buf[4096];
+                int toread;
+
+                if (bytes > sizeof(buf))
+                        toread = sizeof(buf);
+                else
+                        toread = bytes;
+
+                len = presto_fread(fset->fset_kml.fd_file, buf, toread,
+                                   &read_off);
+                if (len <= 0)
+                        break;
+
+                if (presto_fwrite(f, buf, len, &write_off) != len) {
+                        filp_close(f, NULL);
+                        EXIT;
+                        return ERR_PTR(-EIO);
+                }
+
+                bytes -= len;
+        }
+
+        EXIT;
+        return f;
+}
+
+
 /* LML records here */
-/* this writes the LML records for close, in conjunction with the KML  */
+/* this writes an LML record to the LML file (rec->is_kml =0)  */
 int presto_write_lml_close(struct rec_info *rec,
                            struct presto_file_set *fset, 
                            struct file *file,
                            __u64 remote_ino,
-                           __u32 remote_generation,
-                           __u32 remote_version,
+                           __u64 remote_generation,
+                           struct presto_version *remote_version,
                            struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
+        int opcode = KML_OPCODE_CLOSE;
         char *buffer;
         struct dentry *dentry = file->f_dentry; 
         __u64 ino;
@@ -889,7 +1310,7 @@
           EXIT;
           return 0;
         }
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
@@ -898,28 +1319,27 @@
         ino = cpu_to_le64(dentry->d_inode->i_ino);
         generation = cpu_to_le32(dentry->d_inode->i_generation);
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) +
                 sizeof(ino) + sizeof(generation) + sizeof(pathlen) +
                 sizeof(remote_ino) + sizeof(remote_generation) + 
                 sizeof(remote_version) + sizeof(rec->offset) +
-                sizeof(struct journal_suffix);
-
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+                sizeof(struct kml_suffix);
 
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
+        
         rec->is_kml = 0;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &remote_ino, sizeof(remote_ino));
         logrecord = logit(logrecord, &remote_generation,
                           sizeof(remote_generation));
-        logrecord = logit(logrecord, &remote_version, sizeof(remote_version));
+        logrecord = log_version(logrecord, remote_version);
         logrecord = logit(logrecord, &rec->offset, sizeof(rec->offset));
         logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
 
@@ -933,28 +1353,6 @@
         return error;
 }
 
-int presto_journal_write(struct rec_info *rec,
-                         struct presto_file_set *fset, 
-                         struct file *file)
-{
-        struct presto_version file_version;
-        int rc;
-        ENTRY;
-
-        presto_getversion(&file_version, file->f_dentry->d_inode); 
-        /* append this record */
-        rc = presto_write_lml_close
-                (rec, 
-                 fset, 
-                 file,
-                 0, /* remote_ino */
-                 0, /* remote_generation */
-                 0, /* remote_version */
-                 &file_version);
-        EXIT;
-        return rc;
-}
-
 /* 
  * Check if the given record is at the end of the file. If it is, truncate
  * the lml to the record's offset, removing it. Repeat on prior record,
@@ -968,7 +1366,7 @@
         loff_t lml_last_recsize;
         loff_t local_offset;
         int recno;
-        struct journal_prefix prefix;
+        struct kml_prefix_hdr prefix;
         struct inode *inode = fset->fset_lml.fd_file->f_dentry->d_inode;
         void *handle;
         int rc;
@@ -1003,33 +1401,33 @@
           beginning of the file. -SHP
        */
        if (lml_last_recsize != 0) {
-       		local_offset = lml_last_rec - lml_last_recsize;
-       		rc = presto_fread(fset->fset_lml.fd_file, (char *)&prefix,  
-                          		sizeof(prefix), &local_offset); 
-        	if (rc != sizeof(prefix)) {
-                	EXIT;
-                	goto tr_out;
-        	}
+                local_offset = lml_last_rec - lml_last_recsize;
+                rc = presto_fread(fset->fset_lml.fd_file, (char *)&prefix,  
+                                        sizeof(prefix), &local_offset); 
+                if (rc != sizeof(prefix)) {
+                        EXIT;
+                        goto tr_out;
+                }
        
-        	if ( prefix.opcode != PRESTO_OP_NOOP ) {
-                	EXIT;
-                	rc = 0;
+                if ( prefix.opcode != KML_OPCODE_NOOP ) {
+                        EXIT;
+                        rc = 0;
                         /* We may have zeroes at the end of the file, should
-			   we clear them out? -SHP
+                           we clear them out? -SHP
                         */
-                	goto tr_out;
-        	}
-	} else 
-	 	lml_last_rec=0;
+                        goto tr_out;
+                }
+        } else 
+                lml_last_rec=0;
 
-        handle = presto_trans_start(fset, inode, PRESTO_OP_TRUNC);
-        if ( !handle ) {
+        handle = presto_trans_start(fset, inode, KML_OPCODE_TRUNC);
+        if ( IS_ERR(handle) ) {
                 EXIT;
                 rc = -ENOMEM;
                 goto tr_out;
         }
 
-        rc = presto_do_truncate(fset, fset->fset_lml.fd_file->f_dentry, 
+        rc = izo_do_truncate(fset, fset->fset_lml.fd_file->f_dentry, 
                                 lml_last_rec - lml_last_recsize, lml_tail);
         presto_trans_commit(fset, handle); 
         if ( rc == 0 ) {
@@ -1047,25 +1445,21 @@
 
 int presto_truncate_lml(struct presto_file_set *fset)
 {
-
         int rc; 
         ENTRY;
         
         while ( (rc = presto_truncate_lml_tail(fset)) > 0);
         if ( rc < 0 && rc != -EALREADY) {
-                printk("truncate_lml error %d\n", rc); 
+                CERROR("truncate_lml error %d\n", rc); 
         }
         EXIT;
         return rc;
 }
 
-
-
-int presto_clear_lml_close(struct presto_file_set *fset, 
-                           loff_t  lml_offset)
+int presto_clear_lml_close(struct presto_file_set *fset, loff_t lml_offset)
 {
         int rc;
-        struct journal_prefix record;
+        struct kml_prefix_hdr record;
         loff_t offset = lml_offset;
 
         ENTRY;
@@ -1075,20 +1469,20 @@
                 return 0;
         }
 
-        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", 
+        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %d\n", 
                (long)lml_offset, sizeof(record));
         rc = presto_fread(fset->fset_lml.fd_file, (char *)&record,
                           sizeof(record), &offset);
 
         if ( rc != sizeof(record) ) {
-                printk("presto: clear_lml io error %d\n", rc); 
+                CERROR("presto: clear_lml io error %d\n", rc); 
                 EXIT;
                 return -EIO;
         }
 
         /* overwrite the prefix */ 
         CDEBUG(D_JOURNAL, "overwriting prefix: off %ld\n", (long)lml_offset);
-        record.opcode = PRESTO_OP_NOOP;
+        record.opcode = KML_OPCODE_NOOP;
         offset = lml_offset;
         /* note: this does just a single transaction in the cache */
         rc = presto_fwrite(fset->fset_lml.fd_file, (char *)(&record), 
@@ -1106,22 +1500,16 @@
 
 /* now a journal function for every operation */
 
-int presto_journal_setattr(struct rec_info *rec, 
-                           struct presto_file_set *fset, 
-                           struct dentry *dentry,
-                           struct presto_version *old_ver, struct iattr *iattr)
+int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset,
+                           struct dentry *dentry, struct presto_version *old_ver,
+                           struct izo_rollback_data *rb, struct iattr *iattr)
 {
-        int opcode = PRESTO_OP_SETATTR;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_SETATTR;
+        char *buffer, *path, *logrecord, record[316];
         struct dentry *root;
-        __u32 uid, gid, mode, valid, flags;
+        __u32 uid, gid, mode, valid, flags, pathlen;
         __u64 fsize, mtime, ctime;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1129,25 +1517,26 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*old_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*old_ver) +
                 sizeof(valid) + sizeof(mode) + sizeof(uid) + sizeof(gid) +
                 sizeof(fsize) + sizeof(mtime) + sizeof(ctime) + sizeof(flags) +
-                sizeof(pathlen) + sizeof(struct journal_suffix);
+                sizeof(pathlen) + sizeof(*rb) + sizeof(struct kml_suffix);
+
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
         /* Only journal one kind of mtime, and not atime at all.  Also don't
          * journal bogus data in iattr, to make the journal more compressible.
          */
@@ -1168,7 +1557,7 @@
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, old_ver, sizeof(*old_ver));
+        logrecord = log_version(logrecord, old_ver);
         logrecord = logit(logrecord, &valid, sizeof(valid));
         logrecord = logit(logrecord, &mode, sizeof(mode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
@@ -1177,6 +1566,7 @@
         logrecord = logit(logrecord, &mtime, sizeof(mtime));
         logrecord = logit(logrecord, &ctime, sizeof(ctime));
         logrecord = logit(logrecord, &flags, sizeof(flags));
+        logrecord = log_rollback(logrecord, rb);
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
 
@@ -1189,21 +1579,69 @@
         return error;
 }
 
+int presto_get_fileid(int minor, struct presto_file_set *fset,
+                      struct dentry *dentry)
+{
+        int opcode = KML_OPCODE_GET_FILEID;
+        struct rec_info rec;
+        char *buffer, *path, *logrecord, record[4096]; /*include path*/
+        struct dentry *root;
+        __u32 uid, gid, pathlen;
+        int error, size;
+        struct kml_suffix *suffix;
+
+        ENTRY;
+
+        root = fset->fset_dentry;
+
+        uid = cpu_to_le32(dentry->d_inode->i_uid);
+        gid = cpu_to_le32(dentry->d_inode->i_gid);
+        BUFF_ALLOC(buffer, NULL);
+        path = presto_path(dentry, root, buffer, PAGE_SIZE);
+        pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
+        size =  sizeof(__u32) * current->ngroups + 
+                sizeof(struct kml_prefix_hdr) + sizeof(pathlen) +
+                size_round(le32_to_cpu(pathlen)) +
+                sizeof(struct kml_suffix);
+
+        CDEBUG(D_FILE, "kml size: %d\n", size);
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
+
+        memset(&rec, 0, sizeof(rec));
+        rec.is_kml = 1;
+        rec.size = size;
+
+        logrecord = journal_log_prefix(record, opcode, &rec);
+        logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
+        logrecord = logit(logrecord, path, size_round(le32_to_cpu(pathlen)));
+        suffix = (struct kml_suffix *)logrecord;
+        logrecord = journal_log_suffix(logrecord, record, fset, dentry, &rec);
+        /* journal_log_suffix expects journal_log to set this */
+        suffix->recno = 0;
+
+        CDEBUG(D_FILE, "actual kml size: %d\n", logrecord - record);
+        CDEBUG(D_FILE, "get fileid: uid %d, gid %d, path: %s\n", uid, gid,path);
+
+        error = izo_upc_get_fileid(minor, size, record, 
+                                   size_round(le32_to_cpu(pathlen)), path,
+                                   fset->fset_name);
+
+        BUFF_FREE(buffer);
+        EXIT;
+        return error;
+}
+
 int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset,
                           struct dentry *dentry,
                           struct presto_version *tgt_dir_ver,
                           struct presto_version *new_file_ver, int mode)
 {
-        int opcode = PRESTO_OP_CREATE;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_CREATE;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode;
-        int error;
+        __u32 uid, gid, lmode, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1211,7 +1649,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1221,21 +1659,20 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1251,22 +1688,17 @@
         return error;
 }
 
-int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry,
-                           const char *target,
+int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset,
+                           struct dentry *dentry, const char *target,
                            struct presto_version *tgt_dir_ver,
                            struct presto_version *new_link_ver)
 {
-        int opcode = PRESTO_OP_SYMLINK;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
-        __u32 targetlen = cpu_to_le32(strlen(target));
+        int opcode = KML_OPCODE_SYMLINK;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid;
-        int error;
+        __u32 uid, gid, pathlen;
+        __u32 targetlen = cpu_to_le32(strlen(target));
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1274,7 +1706,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1283,22 +1715,21 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(targetlen) + sizeof(struct journal_suffix);
+                sizeof(targetlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) +
                 size_round(le32_to_cpu(targetlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_link_ver, sizeof(*new_link_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_link_ver);
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1315,20 +1746,16 @@
         return error;
 }
 
-int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry,
+int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset,
+                         struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
                          struct presto_version *new_dir_ver, int mode)
 {
-        int opcode = PRESTO_OP_MKDIR;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_MKDIR;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode;
-        int error;
+        __u32 uid, gid, lmode, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1336,7 +1763,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1346,21 +1773,20 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size = sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
         logrecord = journal_log_prefix(record, opcode, rec);
 
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_dir_ver, sizeof(*new_dir_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_dir_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1380,18 +1806,14 @@
 int
 presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset,
                      struct dentry *dir, struct presto_version *tgt_dir_ver,
-                     struct presto_version *old_dir_ver, int len,
-                     const char *name)
+                     struct presto_version *old_dir_ver,
+                     struct izo_rollback_data *rb, int len, const char *name)
 {
-        int opcode = PRESTO_OP_RMDIR;
-        char *buffer;
-        char *path;
+        int opcode = KML_OPCODE_RMDIR;
+        char *buffer, *path, *logrecord, record[316];
         __u32 pathlen, llen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1399,19 +1821,19 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         llen = cpu_to_le32(len);
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dir, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
-                sizeof(pathlen) + sizeof(llen) + sizeof(struct journal_suffix);
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(pathlen) + sizeof(llen) + sizeof(*rb) +
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         CDEBUG(D_JOURNAL, "path: %s (%d), name: %s (%d), size %d\n",
                path, pathlen, name, len, size);
@@ -1421,9 +1843,10 @@
                 size_round(len);
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dir);
-        logrecord = logit(logrecord, old_dir_ver, sizeof(*old_dir_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dir);
+        logrecord = log_version(logrecord, old_dir_ver);
+        logrecord = logit(logrecord, rb, sizeof(*rb));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &llen, sizeof(llen));
         logrecord = journal_log_suffix(logrecord, record, fset, dir, rec);
@@ -1444,16 +1867,11 @@
                      struct presto_version *new_node_ver, int mode,
                      int dmajor, int dminor )
 {
-        int opcode = PRESTO_OP_MKNOD;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_MKNOD;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode, lmajor, lminor;
-        int error;
+        __u32 uid, gid, lmode, lmajor, lminor, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1461,7 +1879,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1473,22 +1891,21 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size = sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(lmajor) +
                 sizeof(lminor) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_node_ver, sizeof(*new_node_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_node_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1512,15 +1929,11 @@
                     struct presto_version *tgt_dir_ver,
                     struct presto_version *new_link_ver)
 {
-        int opcode = PRESTO_OP_LINK;
-        char *buffer, *srcbuffer;
-        char *path, *srcpath;
+        int opcode = KML_OPCODE_LINK;
+        char *buffer, *srcbuffer, *path, *srcpath, *logrecord, record[292];
         __u32 pathlen, srcpathlen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1528,7 +1941,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(srcbuffer, NULL);
         srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE);
@@ -1538,22 +1951,21 @@
         path = presto_path(tgt, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(srcpathlen) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) + 
                 size_round(le32_to_cpu(srcpathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, tgt->d_parent);
-        logrecord = logit(logrecord, new_link_ver, sizeof(*new_link_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, tgt->d_parent);
+        logrecord = log_version(logrecord, new_link_ver);
         logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec);
@@ -1570,20 +1982,16 @@
 }
 
 
-int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset, struct dentry *src,
-                          struct dentry *tgt,
+int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset,
+                          struct dentry *src, struct dentry *tgt,
                           struct presto_version *src_dir_ver,
                           struct presto_version *tgt_dir_ver)
 {
-        int opcode = PRESTO_OP_RENAME;
-        char *buffer, *srcbuffer;
-        char *path, *srcpath;
+        int opcode = KML_OPCODE_RENAME;
+        char *buffer, *srcbuffer, *path, *srcpath, *logrecord, record[292];
         __u32 pathlen, srcpathlen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1591,7 +1999,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(srcbuffer, NULL);
         srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE);
@@ -1601,23 +2009,22 @@
         path = presto_path(tgt, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 4 * sizeof(*src_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 4 * sizeof(*src_dir_ver) +
                 sizeof(srcpathlen) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) + 
                 size_round(le32_to_cpu(srcpathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, src_dir_ver, sizeof(*src_dir_ver));
-        logrecord = log_version(logrecord, src->d_parent);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, tgt->d_parent);
+        logrecord = log_version(logrecord, src_dir_ver);
+        logrecord = log_dentry_version(logrecord, src->d_parent);
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, tgt->d_parent);
         logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec);
@@ -1633,21 +2040,18 @@
         return error;
 }
 
-
-int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dir,
-                          struct presto_version *tgt_dir_ver,
-                          struct presto_version *old_file_ver, int len,
-                          const char *name)
-{
-        int opcode = PRESTO_OP_UNLINK;
-        char *buffer;
-        char *path;
+int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset,
+                          struct dentry *dir, struct presto_version *tgt_dir_ver,
+                          struct presto_version *old_file_ver,
+                          struct izo_rollback_data *rb, struct dentry *dentry,
+                          char *old_target, int old_targetlen)
+{
+        int opcode = KML_OPCODE_UNLINK;
+        char *buffer, *path, *logrecord, record[316];
+        const char *name;
         __u32 pathlen, llen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size, len;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1655,35 +2059,41 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
+
+        name = dentry->d_name.name;
+        len = dentry->d_name.len;
 
         llen = cpu_to_le32(len);
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dir, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
-                sizeof(pathlen) + sizeof(llen) + sizeof(struct journal_suffix);
+        size = sizeof(__u32) * current->ngroups + 
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(pathlen) + sizeof(llen) + sizeof(*rb) +
+                sizeof(old_targetlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
-        rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len);
+        rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len) +
+                size_round(old_targetlen);
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dir);
-        logrecord = logit(logrecord, old_file_ver, sizeof(*old_file_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dir);
+        logrecord = log_version(logrecord, old_file_ver);
+        logrecord = log_rollback(logrecord, rb);
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &llen, sizeof(llen));
+        logrecord = logit(logrecord, &old_targetlen, sizeof(old_targetlen));
         logrecord = journal_log_suffix(logrecord, record, fset, dir, rec);
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           name, size_round(len), 
-                           NULL, 0);
+                           name, size_round(len),
+                           old_target, size_round(old_targetlen));
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1693,20 +2103,16 @@
 int
 presto_journal_close(struct rec_info *rec, struct presto_file_set *fset,
                      struct file *file, struct dentry *dentry,
-		     struct presto_version *new_file_ver)
+                     struct presto_version *old_file_ver,
+                     struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
+        int opcode = KML_OPCODE_CLOSE;
         struct presto_file_data *fd;
-        char *buffer;
-        char *path;
-        __u64 ino;
-        __u32 pathlen;
-        __u32 generation;
-        int size;
-        char *logrecord;
-        char record[292];
+        char *buffer, *path, *logrecord, record[316];
         struct dentry *root;
-        int error;
+        int error, size, i;
+        __u32 pathlen, generation;
+        __u64 ino;
         __u32 open_fsuid;
         __u32 open_fsgid;
         __u32 open_ngroups;
@@ -1714,7 +2120,6 @@
         __u32 open_mode;
         __u32 open_uid;
         __u32 open_gid;
-        int i;
 
         ENTRY;
 
@@ -1723,18 +2128,19 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         fd = (struct presto_file_data *)file->private_data;
         if (fd) {
                 open_ngroups = fd->fd_ngroups;
                 for (i = 0; i < fd->fd_ngroups; i++)
-			open_groups[i] = (__u32) fd->fd_groups[i];
+                        open_groups[i] = (__u32) fd->fd_groups[i];
                 open_mode = fd->fd_mode;
                 open_uid = fd->fd_uid;
                 open_gid = fd->fd_gid;
@@ -1743,7 +2149,7 @@
         } else {
                 open_ngroups = current->ngroups;
                 for (i=0; i<current->ngroups; i++)
-			open_groups[i] =  (__u32) current->groups[i]; 
+                        open_groups[i] =  (__u32) current->groups[i]; 
                 open_mode = dentry->d_inode->i_mode;
                 open_uid = dentry->d_inode->i_uid;
                 open_gid = dentry->d_inode->i_gid;
@@ -1757,13 +2163,12 @@
         generation = cpu_to_le32(dentry->d_inode->i_generation);
         size =  sizeof(__u32) * open_ngroups +
                 sizeof(open_mode) + sizeof(open_uid) + sizeof(open_gid) +
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
-                sizeof(ino) + sizeof(generation) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_prefix_hdr) + sizeof(*old_file_ver) +
+                sizeof(*new_file_ver) + sizeof(ino) + sizeof(generation) +
+                sizeof(pathlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
@@ -1774,7 +2179,8 @@
         logrecord = logit(logrecord, &open_mode, sizeof(open_mode));
         logrecord = logit(logrecord, &open_uid, sizeof(open_uid));
         logrecord = logit(logrecord, &open_gid, sizeof(open_gid));
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, old_file_ver);
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1795,12 +2201,10 @@
                          __u64 ino,     __u32 generation, 
                          struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_CLOSE;
+        char *logrecord, record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
 
@@ -1809,24 +2213,23 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         size =  sizeof(__u32) * ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) +
                 sizeof(ino) + sizeof(generation) + 
                 sizeof(le32_to_cpu(pathlen)) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix_with_groups(record, opcode, rec,
                                                    ngroups, groups);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1861,7 +2264,7 @@
                 __u64 lml_offset;
         } close_rec; 
         struct file *file = fset->fset_lml.fd_file;
-        struct journal_prefix prefix;
+        struct kml_prefix_hdr prefix;
         int rc = 0;
         ENTRY;
 
@@ -1877,11 +2280,11 @@
                           sizeof(prefix), &read_offset);
         if ( rc != sizeof(prefix) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 1, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 1, tell Peter\n");
                 return -EIO;
         }
 
-        if ( prefix.opcode == PRESTO_OP_NOOP ) {
+        if ( prefix.opcode == KML_OPCODE_NOOP ) {
                 lml_offset += prefix.len; 
                 goto again; 
         }
@@ -1890,7 +2293,7 @@
                           prefix.ngroups * sizeof(__u32), &read_offset); 
         if ( rc != prefix.ngroups * sizeof(__u32) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 2, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 2, tell Peter\n");
                 return -EIO;
         }
 
@@ -1898,7 +2301,7 @@
                           sizeof(close_rec), &read_offset); 
         if ( rc != sizeof(close_rec) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 3, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 3, tell Peter\n");
                 return -EIO;
         }
 
@@ -1913,20 +2316,20 @@
                           le32_to_cpu(close_rec.pathlen), &read_offset); 
         if ( rc != le32_to_cpu(close_rec.pathlen) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 4, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 4, tell Peter\n");
                 return -EIO;
         }
         
         handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                    PRESTO_OP_RELEASE);
-        if ( !handle ) {
+                                    KML_OPCODE_RELEASE);
+        if ( IS_ERR(handle) ) {
                 EXIT;
                 return -ENOMEM; 
         }
 
         rc = presto_clear_lml_close(fset, lml_offset); 
         if ( rc ) {
-                printk("error during clearing: %d\n", rc);
+                CERROR("error during clearing: %d\n", rc);
                 presto_trans_commit(fset, handle);
                 EXIT; 
                 return rc; 
@@ -1937,7 +2340,7 @@
                                   close_rec.ino, close_rec.generation,
                                   &close_rec.new_file_ver); 
         if ( rc ) {
-                printk("error during rewrite close: %d\n", rc);
+                CERROR("error during rewrite close: %d\n", rc);
                 presto_trans_commit(fset, handle);
                 EXIT; 
                 return rc; 
@@ -1945,7 +2348,7 @@
 
         presto_trans_commit(fset, handle); 
         if ( rc ) { 
-                printk("error during truncation: %d\n", rc);
+                CERROR("error during truncation: %d\n", rc);
                 EXIT; 
                 return rc;
         }
@@ -1972,20 +2375,14 @@
                                  int flags) 
 { 
         int opcode = (buffer == NULL) ? 
-                     PRESTO_OP_DELEXTATTR : 
-                     PRESTO_OP_SETEXTATTR ;
-        char *temp;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+                     KML_OPCODE_DELEXTATTR : 
+                     KML_OPCODE_SETEXTATTR ;
+        char *temp, *path, *logrecord, record[292];
         struct dentry *root;
-        int error;
+        int error, size;
         __u32 namelen=cpu_to_le32(strnlen(name,PRESTO_EXT_ATTR_NAME_MAX));
         __u32 buflen=(buffer != NULL)? cpu_to_le32(buffer_len): cpu_to_le32(0);
-        __u32 mode;
-
+        __u32 mode, pathlen;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1993,12 +2390,13 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(temp, NULL);
         path = presto_path(dentry, root, temp, PAGE_SIZE);
@@ -2012,15 +2410,14 @@
         mode=cpu_to_le32(dentry->d_inode->i_mode);
 
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 
+                sizeof(struct kml_prefix_hdr) + 
                 2 * sizeof(struct presto_version) +
                 sizeof(flags) + sizeof(mode) + sizeof(namelen) + 
                 sizeof(buflen) + sizeof(pathlen) + 
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         /* Make space for a path, a attr name and value*/
@@ -2035,8 +2432,8 @@
                     size_round(le32_to_cpu(buflen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, ver, sizeof(*ver));
-        logrecord = log_version(logrecord, dentry);
+        logrecord = log_version(logrecord, ver);
+        logrecord = log_dentry_version(logrecord, dentry);
         logrecord = logit(logrecord, &flags, sizeof(flags));
         logrecord = logit(logrecord, &mode, sizeof(flags));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -2054,4 +2451,3 @@
         return error;
 }
 #endif
-
diff -Nru a/fs/intermezzo/journal_ext2.c b/fs/intermezzo/journal_ext2.c
--- a/fs/intermezzo/journal_ext2.c	Tue Oct 15 20:29:15 2002
+++ b/fs/intermezzo/journal_ext2.c	Tue Oct 15 20:29:15 2002
@@ -1,24 +1,40 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/ext2_fs.h> 
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #if defined(CONFIG_EXT2_FS)
 
@@ -46,7 +62,7 @@
                 return ERR_PTR(-ENOSPC);
         }
         
-        if (  (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR)
+        if (  (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR)
               && avail_kmlblocks < 6 ) {
                 return ERR_PTR(-ENOSPC);
         }            
@@ -55,10 +71,17 @@
 
 static void presto_e2_trans_commit(struct presto_file_set *fset, void *handle)
 {
-  do {} while (0);
+        do {} while (0);
+}
+
+static int presto_e2_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
 }
 
 struct journal_ops presto_ext2_journal_ops = {
+        tr_all_data: presto_e2_has_all_data,
         tr_avail: presto_e2_freespace,
         tr_start: presto_e2_trans_start,
         tr_commit: presto_e2_trans_commit,
diff -Nru a/fs/intermezzo/journal_ext3.c b/fs/intermezzo/journal_ext3.c
--- a/fs/intermezzo/journal_ext3.c	Tue Oct 15 20:29:17 2002
+++ b/fs/intermezzo/journal_ext3.c	Tue Oct 15 20:29:17 2002
@@ -1,21 +1,40 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
 #include <linux/param.h>
 #include <linux/kernel.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/smp_lock.h>
@@ -26,9 +45,7 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE)
 
@@ -52,9 +69,9 @@
 static loff_t presto_e3_freespace(struct presto_cache *cache,
                                          struct super_block *sb)
 {
-        loff_t freebl = le32_to_cpu(sb->u.ext3_sb.s_es->s_free_blocks_count);
+        loff_t freebl = le32_to_cpu(EXT3_SB(sb)->s_es->s_free_blocks_count);
         loff_t avail =   freebl - 
-                le32_to_cpu(sb->u.ext3_sb.s_es->s_r_blocks_count);
+                le32_to_cpu(EXT3_SB(sb)->s_es->s_r_blocks_count);
         return (avail <<  EXT3_BLOCK_SIZE_BITS(sb));
 }
 
@@ -77,13 +94,13 @@
             return NULL;
           }
 
-        avail_kmlblocks = inode->i_sb->u.ext3_sb.s_es->s_free_blocks_count;
+        avail_kmlblocks = EXT3_SB(inode->i_sb)->s_es->s_free_blocks_count;
         
         if ( avail_kmlblocks < 3 ) {
                 return ERR_PTR(-ENOSPC);
         }
         
-        if (  (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR)
+        if (  (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR)
               && avail_kmlblocks < 6 ) {
                 return ERR_PTR(-ENOSPC);
         }            
@@ -105,52 +122,71 @@
            and operations involving the LML records 
         */
         switch (op) {
-        case PRESTO_OP_TRUNC:
+        case KML_OPCODE_TRUNC:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS; 
                 break;
-        case PRESTO_OP_RELEASE:
+        case KML_OPCODE_KML_TRUNC:
+                /* Hopefully this is a little better, but I'm still mostly
+                 * guessing here. */
+                /* unlink 1 */
+                jblocks = extra_name_blks + trunc_blks +
+                        EXT3_DELETE_TRANS_BLOCKS + 2; 
+
+                /* unlink 2 */
+                jblocks += extra_name_blks + trunc_blks +
+                        EXT3_DELETE_TRANS_BLOCKS + 2; 
+
+                /* rename 1 */
+                jblocks += 2 * extra_path_blks + trunc_blks + 
+                        2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
+
+                /* rename 2 */
+                jblocks += 2 * extra_path_blks + trunc_blks + 
+                        2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
+                break;
+        case KML_OPCODE_RELEASE:
                 /* 
                 jblocks = one_path_blks + lml_blks + 2*trunc_blks; 
                 */
                 jblocks = one_path_blks; 
                 break;
-        case PRESTO_OP_SETATTR:
+        case KML_OPCODE_SETATTR:
                 jblocks = one_path_blks + trunc_blks + 1 ; 
                 break;
-        case PRESTO_OP_CREATE:
+        case KML_OPCODE_CREATE:
                 jblocks = one_path_blks + trunc_blks 
                         + EXT3_DATA_TRANS_BLOCKS + 3 + 2; 
                 break;
-        case PRESTO_OP_LINK:
+        case KML_OPCODE_LINK:
                 jblocks = one_path_blks + trunc_blks 
                         + EXT3_DATA_TRANS_BLOCKS + 2; 
                 break;
-        case PRESTO_OP_UNLINK:
+        case KML_OPCODE_UNLINK:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS + 2; 
                 break;
-        case PRESTO_OP_SYMLINK:
+        case KML_OPCODE_SYMLINK:
                 jblocks = one_path_blks + extra_path_blks + trunc_blks
                         + EXT3_DATA_TRANS_BLOCKS + 5; 
                 break;
-        case PRESTO_OP_MKDIR:
+        case KML_OPCODE_MKDIR:
                 jblocks = one_path_blks + trunc_blks
                         + EXT3_DATA_TRANS_BLOCKS + 4 + 2;
                 break;
-        case PRESTO_OP_RMDIR:
+        case KML_OPCODE_RMDIR:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS + 1; 
                 break;
-        case PRESTO_OP_MKNOD:
+        case KML_OPCODE_MKNOD:
                 jblocks = one_path_blks + trunc_blks + 
                         EXT3_DATA_TRANS_BLOCKS + 3 + 2;
                 break;
-        case PRESTO_OP_RENAME:
+        case KML_OPCODE_RENAME:
                 jblocks = one_path_blks + extra_path_blks + trunc_blks + 
                         2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
                 break;
-        case PRESTO_OP_WRITE:
+        case KML_OPCODE_WRITE:
                 jblocks = one_path_blks; 
                 /*  add this when we can wrap our transaction with 
                     that of ext3_file_write (ordered writes)
@@ -162,7 +198,8 @@
                 return NULL;
         }
 
-        CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
+        CDEBUG(D_JOURNAL, "creating journal handle (%d blocks) for op %d\n",
+               jblocks, op);
         /* journal_start/stop does not do its own locking while updating
          * the handle/transaction information. Hence we create our own
          * critical section to protect these calls. -SHP
@@ -173,7 +210,7 @@
         return handle;
 }
 
-void presto_e3_trans_commit(struct presto_file_set *fset, void *handle)
+static void presto_e3_trans_commit(struct presto_file_set *fset, void *handle)
 {
         if ( presto_no_journal(fset) || !handle)
                 return;
@@ -184,7 +221,7 @@
         unlock_kernel();
 }
 
-void presto_e3_journal_file_data(struct inode *inode)
+static void presto_e3_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
         EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
@@ -193,11 +230,56 @@
 #endif
 }
 
+/* The logic here is a slightly modified version of ext3/inode.c:block_to_path
+ */
+static int presto_e3_has_all_data(struct inode *inode)
+{
+        int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+        int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb);
+        const long direct_blocks = EXT3_NDIR_BLOCKS,
+                indirect_blocks = ptrs,
+                double_blocks = (1 << (ptrs_bits * 2));
+        long block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+                inode->i_sb->s_blocksize_bits;
+
+        ENTRY;
+
+        if (inode->i_size == 0) {
+                EXIT;
+                return 1;
+        }
+
+        if (block < direct_blocks) {
+                /* No indirect blocks, no problem. */
+        } else if (block < indirect_blocks + direct_blocks) {
+                block++;
+        } else if (block < double_blocks + indirect_blocks + direct_blocks) {
+                block += 2;
+        } else if (((block - double_blocks - indirect_blocks - direct_blocks)
+                    >> (ptrs_bits * 2)) < ptrs) {
+                block += 3;
+        }
+
+        block *= (inode->i_sb->s_blocksize / 512);
+
+        CDEBUG(D_CACHE, "Need %ld blocks, have %ld.\n", block, inode->i_blocks);
+
+        if (block > inode->i_blocks) {
+                EXIT;
+                return 0;
+        }
+
+        EXIT;
+        return 1;
+}
+
 struct journal_ops presto_ext3_journal_ops = {
-        tr_avail: presto_e3_freespace,
-        tr_start:  presto_e3_trans_start,
-        tr_commit: presto_e3_trans_commit,
-        tr_journal_data: presto_e3_journal_file_data
+        .tr_all_data     = presto_e3_has_all_data,
+        .tr_avail        = presto_e3_freespace,
+        .tr_start        =  presto_e3_trans_start,
+        .tr_commit       = presto_e3_trans_commit,
+        .tr_journal_data = presto_e3_journal_file_data,
+        .tr_ilookup      = presto_iget_ilookup
 };
 
 #endif /* CONFIG_EXT3_FS */
diff -Nru a/fs/intermezzo/journal_obdfs.c b/fs/intermezzo/journal_obdfs.c
--- a/fs/intermezzo/journal_obdfs.c	Tue Oct 15 20:29:11 2002
+++ b/fs/intermezzo/journal_obdfs.c	Tue Oct 15 20:29:11 2002
@@ -1,21 +1,39 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
 #include <linux/param.h>
 #include <linux/kernel.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #ifdef CONFIG_OBDFS_FS
@@ -23,9 +41,7 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #ifdef CONFIG_OBDFS_FS
 
@@ -162,17 +178,17 @@
 void presto_obdfs_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
-        EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
+        inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
 #else
 #warning You must have a facility to enable journaled writes for recovery!
 #endif
 }
 
 struct journal_ops presto_obdfs_journal_ops = {
-        tr_avail: presto_obdfs_freespace,
-        tr_start:  presto_obdfs_trans_start,
-        tr_commit: presto_obdfs_trans_commit,
-        tr_journal_data: presto_obdfs_journal_file_data
+        .tr_avail        = presto_obdfs_freespace,
+        .tr_start        =  presto_obdfs_trans_start,
+        .tr_commit       = presto_obdfs_trans_commit,
+        .tr_journal_data = presto_obdfs_journal_file_data
 };
 
 #endif
diff -Nru a/fs/intermezzo/journal_reiserfs.c b/fs/intermezzo/journal_reiserfs.c
--- a/fs/intermezzo/journal_reiserfs.c	Tue Oct 15 20:29:15 2002
+++ b/fs/intermezzo/journal_reiserfs.c	Tue Oct 15 20:29:15 2002
@@ -1,21 +1,39 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
 #include <linux/param.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/smp_lock.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #if 0
@@ -26,9 +44,8 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
+
 #if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE)
 
 
@@ -52,9 +69,9 @@
         __u32 avail_kmlblocks;
 	struct reiserfs_transaction_handle *th ;
 
-	PRESTO_ALLOC(th, struct reiserfs_transaction_handle *, sizeof(*th));
+	PRESTO_ALLOC(th, sizeof(*th));
 	if (!th) { 
-		printk("presto: No memory for trans handle\n");
+		CERROR("presto: No memory for trans handle\n");
 		return NULL;
 	}
 
@@ -81,36 +98,44 @@
         CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
 
 	lock_kernel();
-	//journal_begin(th, inode->i_sb, jblocks);
+	journal_begin(th, inode->i_sb, jblocks);
 	unlock_kernel();
 	return th; 
 }
 
-void presto_reiserfs_trans_commit(struct presto_file_set *fset, void *handle)
+static void presto_reiserfs_trans_commit(struct presto_file_set *fset,
+                                         void *handle)
 {
 	int jblocks;
 	jblocks = 3 + JOURNAL_PER_BALANCE_CNT * 4;
 	
 	lock_kernel();
-	//journal_end(handle, fset->fset_cache->cache_sb, jblocks);
+	journal_end(handle, fset->fset_cache->cache_sb, jblocks);
 	unlock_kernel();
 	PRESTO_FREE(handle, sizeof(struct reiserfs_transaction_handle));
 }
 
-void presto_reiserfs_journal_file_data(struct inode *inode)
+static void presto_reiserfs_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
-        EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL;
+        inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
 #else
 #warning You must have a facility to enable journaled writes for recovery!
 #endif
 }
 
+static int presto_reiserfs_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
+}
+
 struct journal_ops presto_reiserfs_journal_ops = {
-        tr_avail: presto_reiserfs_freespace,
-        tr_start:  presto_reiserfs_trans_start,
-        tr_commit: presto_reiserfs_trans_commit,
-        tr_journal_data: presto_reiserfs_journal_file_data
+        .tr_all_data     = presto_reiserfs_has_all_data,
+        .tr_avail        = presto_reiserfs_freespace,
+        .tr_start        = presto_reiserfs_trans_start,
+        .tr_commit       = presto_reiserfs_trans_commit,
+        .tr_journal_data = presto_reiserfs_journal_file_data
 };
 
 #endif
diff -Nru a/fs/intermezzo/journal_tmpfs.c b/fs/intermezzo/journal_tmpfs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/intermezzo/journal_tmpfs.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,109 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#if defined(CONFIG_TMPFS)
+#include <linux/jbd.h>
+#if defined(CONFIG_EXT3)
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jbd.h>
+#endif
+#endif
+
+#include <linux/intermezzo_fs.h>
+#include <linux/intermezzo_psdev.h>
+
+#if defined(CONFIG_TMPFS)
+
+/* space requirements: 
+   presto_do_truncate: 
+        used to truncate the KML forward to next fset->chunksize boundary
+          - zero partial block
+          - update inode
+   presto_write_record: 
+        write header (< one block) 
+        write one path (< MAX_PATHLEN) 
+        possibly write another path (< MAX_PATHLEN)
+        write suffix (< one block) 
+   presto_update_last_rcvd
+        write one block
+*/
+
+static loff_t presto_tmpfs_freespace(struct presto_cache *cache,
+                                         struct super_block *sb)
+{
+        return (1<<30);
+}
+
+/* start the filesystem journal operations */
+static void *presto_tmpfs_trans_start(struct presto_file_set *fset, 
+                                   struct inode *inode, 
+                                   int op)
+{
+        return (void *)1; 
+}
+
+static void presto_tmpfs_trans_commit(struct presto_file_set *fset, void *handle)
+{
+        return;
+}
+
+static void presto_tmpfs_journal_file_data(struct inode *inode)
+{
+        return; 
+}
+
+/* The logic here is a slightly modified version of ext3/inode.c:block_to_path
+ */
+static int presto_tmpfs_has_all_data(struct inode *inode)
+{
+        return 0;
+}
+
+struct journal_ops presto_tmpfs_journal_ops = {
+        tr_all_data: presto_tmpfs_has_all_data,
+        tr_avail: presto_tmpfs_freespace,
+        tr_start:  presto_tmpfs_trans_start,
+        tr_commit: presto_tmpfs_trans_commit,
+        tr_journal_data: presto_tmpfs_journal_file_data,
+        tr_ilookup: presto_tmpfs_ilookup,
+        tr_add_ilookup: presto_add_ilookup_dentry
+};
+
+#endif /* CONFIG_EXT3_FS */
diff -Nru a/fs/intermezzo/journal_xfs.c b/fs/intermezzo/journal_xfs.c
--- a/fs/intermezzo/journal_xfs.c	Tue Oct 15 20:29:20 2002
+++ b/fs/intermezzo/journal_xfs.c	Tue Oct 15 20:29:20 2002
@@ -1,25 +1,43 @@
-
-/*
- *  * Intermezzo. (C) 1998 Peter J. Braam
- *   */
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
+#if 0
+/* XFS Support not there yet */
 #ifdef CONFIG_FS_XFS
 #include <linux/xfs_fs.h>
 #endif
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_journal.h>
 
 #if 0
@@ -118,18 +136,27 @@
 	xfs_trans_stop(handle);
 }
 
-void presto_xfs_journal_file_data(struct inode *inode)
+static void presto_xfs_journal_file_data(struct inode *inode)
 {
         return; 
 }
 
+static int presto_xfs_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
+}
+
 struct journal_ops presto_xfs_journal_ops = {
-        tr_avail: presto_xfs_freespace,
-        tr_start:  presto_xfs_trans_start,
-        tr_commit: presto_xfs_trans_commit,
-        tr_journal_data: presto_xfs_journal_file_data
+        .tr_all_data     = presto_xfs_has_all_data,
+        .tr_avail        = presto_xfs_freespace,
+        .tr_start        = presto_xfs_trans_start,
+        .tr_commit       = presto_xfs_trans_commit,
+        .tr_journal_data = presto_xfs_journal_file_data
 };
 
-#endif /* CONFIG_XFS_FS */
+#endif
 
+
+#endif /* CONFIG_XFS_FS */
 
diff -Nru a/fs/intermezzo/kml_reint.c b/fs/intermezzo/kml_reint.c
--- a/fs/intermezzo/kml_reint.c	Tue Oct 15 20:29:21 2002
+++ b/fs/intermezzo/kml_reint.c	Tue Oct 15 20:29:21 2002
@@ -1,9 +1,25 @@
-/*
- * KML REINT
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- * Copryright (C) 1996 Arthur Ma <arthur.ma@mountainviewdata.com>
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Reintegration of KML records
  *
- * Copyright (C) 2000 Mountainview Data, Inc.
  */
 
 #define __NO_VERSION__
@@ -17,393 +33,598 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
+#include <asm/mmu_context.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_upcall.h>
-
-static void kmlreint_pre_secure (struct kml_rec *rec);
-static void kmlreint_post_secure (struct kml_rec *rec);
 
-static void kmlreint_pre_secure (struct kml_rec *rec)
+static void kmlreint_pre_secure(struct kml_rec *rec, struct file *dir,
+                                struct run_ctxt *saved)
 {
-        if (current->fsuid != current->uid)
-                CDEBUG (D_KML, "reint_kmlreint_pre_secure: cannot setfsuid\n");
-        if (current->fsgid != current->gid)
-                CDEBUG (D_KML, "reint_kmlreint_pre_secure: cannot setfsgid\n");
-        current->fsuid = rec->rec_head.uid;
-        current->fsgid = rec->rec_head.fsgid;
+        struct run_ctxt ctxt; 
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        int i;
+
+        ctxt.fsuid = rec->prefix.hdr->fsuid;
+        ctxt.fsgid = rec->prefix.hdr->fsgid;
+        ctxt.fs = KERNEL_DS; 
+        ctxt.pwd = dd->dd_fset->fset_dentry;
+        ctxt.pwdmnt = dd->dd_fset->fset_mnt;
+
+        ctxt.root = ctxt.pwd;
+        ctxt.rootmnt = ctxt.pwdmnt;
+        if (rec->prefix.hdr->ngroups > 0) {
+                ctxt.ngroups = rec->prefix.hdr->ngroups;
+                for (i = 0; i< ctxt.ngroups; i++) 
+                        ctxt.groups[i] = rec->prefix.groups[i];
+        } else
+                ctxt.ngroups = 0;
+
+        push_ctxt(saved, &ctxt);
+}
+
+
+/* Append two strings in a less-retarded fashion. */
+static char * path_join(char *p1, int p1len, char *p2, int p2len)
+{
+        int size = p1len + p2len + 2; /* possibly one extra /, one NULL */
+        char *path;
+
+        path = kmalloc(size, GFP_KERNEL);
+        if (path == NULL)
+                return NULL;
+
+        memcpy(path, p1, p1len);
+        if (path[p1len - 1] != '/') {
+                path[p1len] = '/';
+                p1len++;
+        }
+        memcpy(path + p1len, p2, p2len);
+        path[p1len + p2len] = '\0';
+
+        return path;
 }
 
-static void kmlreint_post_secure (struct kml_rec *rec)
+static inline int kml_recno_equal(struct kml_rec *rec,
+                                  struct presto_file_set *fset)
 {
-        current->fsuid = current->uid; 
-        current->fsgid = current->gid;
-        /* current->egid = current->gid; */ 
-        /* ????????????? */
+        return (rec->suffix->recno == fset->fset_lento_recno + 1);
 }
 
-static int reint_create (int slot_offset, struct kml_rec *rec)
+static inline int version_equal(struct presto_version *a, struct inode *inode)
 {
-        struct  lento_vfs_context info;
-        struct  kml_create *create = &rec->rec_kml.create;
-        mm_segment_t old_fs;
-        int     error;
+        if (a == NULL)
+                return 1;
+
+        if (inode == NULL) {
+                CERROR("InterMezzo: NULL inode in version_equal()\n");
+                return 0;
+        }
+
+        if (inode->i_mtime == a->pv_mtime &&
+            (S_ISDIR(inode->i_mode) || inode->i_size == a->pv_size))
+                return 1;
 
+        return 0;
+}
+
+static int reint_close(struct kml_rec *rec, struct file *file,
+                       struct lento_vfs_context *given_info)
+{
+        struct run_ctxt saved_ctxt;
+        int error;
+        struct presto_file_set *fset;
+        struct lento_vfs_context info; 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        memcpy(&info, given_info, sizeof(*given_info));
 
-        CDEBUG (D_KML, "=====REINT_CREATE::%s\n", create->path);
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_create(create->path, create->mode, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+
+        CDEBUG (D_KML, "=====REINT_CLOSE::%s\n", rec->path);
+
+        fset = presto_fset(file->f_dentry);
+        if (fset->fset_flags & FSET_DATA_ON_DEMAND) {
+                struct iattr iattr;
+
+                iattr.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_SIZE;
+                iattr.ia_mtime = (time_t)rec->new_objectv->pv_mtime;
+                iattr.ia_ctime = (time_t)rec->new_objectv->pv_ctime;
+                iattr.ia_size = (time_t)rec->new_objectv->pv_size;
+
+                /* no kml record, but update last rcvd */
+                /* save fileid in dentry for later backfetch */
+                info.flags |= LENTO_FL_EXPECT | LENTO_FL_SET_DDFILEID;
+                info.remote_ino = rec->ino;
+                info.remote_generation = rec->generation;
+                info.flags &= ~LENTO_FL_KML;
+                kmlreint_pre_secure(rec, file, &saved_ctxt);
+                error = lento_setattr(rec->path, &iattr, &info);
+                pop_ctxt(&saved_ctxt);
+
+                presto_d2d(file->f_dentry)->dd_flags &= ~PRESTO_DATA;
+        } else {
+                int minor = presto_f2m(fset);
+
+                info.updated_time = rec->new_objectv->pv_mtime;
+                memcpy(&info.remote_version, rec->old_objectv, 
+                       sizeof(*rec->old_objectv));
+                info.remote_ino = rec->ino;
+                info.remote_generation = rec->generation;
+                error = izo_upc_backfetch(minor, rec->path, fset->fset_name,
+                                          &info);
+                if (error) {
+                        CERROR("backfetch error %d\n", error);
+                        /* if file doesn't exist anymore,  then ignore the CLOSE
+                         * and just update the last_rcvd.
+                         */
+                        if (error == ENOENT) {
+                                CDEBUG(D_KML, "manually updating remote offset uuid %s"
+                                       "recno %d offset %Lu\n", info.uuid, info.recno, info.kml_offset);
+                                error = izo_rcvd_upd_remote(fset, info.uuid, info.recno, info.kml_offset);
+                                if(error)
+                                        CERROR("izo_rcvd_upd_remote error %d\n", error);
+
+                        } 
+                }
+                        
+                /* propagate error to avoid further reint */
+        }
 
         EXIT;
         return error;
 }
 
-static int reint_open (int slot_offset, struct kml_rec *rec)
+static int reint_create(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        return 0;
+        struct run_ctxt saved_ctxt;
+        int     error;        ENTRY;
+
+        CDEBUG (D_KML, "=====REINT_CREATE::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_create(rec->path, rec->mode, info);
+        pop_ctxt(&saved_ctxt); 
+
+        EXIT;
+        return error;
 }
 
-static int reint_mkdir (int slot_offset, struct kml_rec *rec)
+static int reint_link(struct kml_rec *rec, struct file *dir,
+                      struct lento_vfs_context *info)
 {
-        struct  lento_vfs_context info;
-        struct  kml_mkdir *mkdir = &rec->rec_kml.mkdir;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_mkdir (mkdir->path, mkdir->mode, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_LINK::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_link(rec->path, rec->target, info);
+        pop_ctxt(&saved_ctxt); 
 
         EXIT;
         return error;
 }
 
-static int reint_rmdir (int slot_offset, struct kml_rec *rec)
+static int reint_mkdir(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
 {
-        struct  kml_rmdir  *rmdir = &rec->rec_kml.rmdir;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
-        char *name;
-        int error;
+        struct run_ctxt saved_ctxt;
+        int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
-        name = bdup_printf ("%s/%s", rmdir->path, rmdir->name);
-        if (name == NULL)
-        {
-                kmlreint_post_secure (rec);
-                EXIT;
-                return -ENOMEM;
-        }
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_rmdir (name, &info);
-        set_fs (old_fs);
+        CDEBUG (D_KML, "=====REINT_MKDIR::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_mkdir(rec->path, rec->mode, info);
+        pop_ctxt(&saved_ctxt); 
+
+        EXIT;
+        return error;
+}
+
+static int reint_mknod(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
+{
+        struct run_ctxt saved_ctxt;
+        int     error, dev;
+
+        ENTRY;
+
+        CDEBUG (D_KML, "=====REINT_MKNOD::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+
+        dev = rec->rdev ?: MKDEV(rec->major, rec->minor);
+
+        error = lento_mknod(rec->path, rec->mode, dev, info);
+        pop_ctxt(&saved_ctxt); 
 
-        PRESTO_FREE (name, strlen (name) + 1);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_link (int slot_offset, struct kml_rec *rec)
+
+static int reint_noop(struct kml_rec *rec, struct file *dir,
+                      struct lento_vfs_context *info)
+{
+        return 0;
+}
+
+static int reint_rename(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        struct  kml_link *link = &rec->rec_kml.link;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        CDEBUG (D_KML, "=====REINT_RENAME::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_rename(rec->path, rec->target, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_link (link->sourcepath, link->targetpath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_unlink (int slot_offset, struct kml_rec *rec)
+static int reint_rmdir(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
 {
-        struct  kml_unlink *unlink = &rec->rec_kml.unlink;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
-        char   *name;
+        char *path;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
-        name = bdup_printf ("%s/%s", unlink->path, unlink->name);
-        if (name == NULL)
-        {
-                kmlreint_post_secure (rec);
+
+        path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
+        if (path == NULL) {
                 EXIT;
                 return -ENOMEM;
         }
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_unlink (name, &info);
-        set_fs (old_fs);
-        PRESTO_FREE (name, strlen (name));
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_RMDIR::%s\n", path);
+        info->updated_time = rec->new_parentv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_rmdir(path, info);
+        pop_ctxt(&saved_ctxt); 
 
+        kfree(path);
         EXIT;
         return error;
 }
 
-static int reint_symlink (int slot_offset, struct kml_rec *rec)
+static int reint_setattr(struct kml_rec *rec, struct file *dir,
+                         struct lento_vfs_context *info)
 {
-        struct  kml_symlink *symlink = &rec->rec_kml.symlink;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
+        struct iattr iattr;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        iattr.ia_valid = rec->valid;
+        iattr.ia_mode  = (umode_t)rec->mode;
+        iattr.ia_uid   = (uid_t)rec->uid;
+        iattr.ia_gid   = (gid_t)rec->gid;
+        iattr.ia_size  = (off_t)rec->size;
+        iattr.ia_ctime = (time_t)rec->ctime;
+        iattr.ia_mtime = (time_t)rec->mtime;
+        iattr.ia_atime = iattr.ia_mtime; /* We don't track atimes. */
+        iattr.ia_attr_flags = rec->flags;
+
+        CDEBUG (D_KML, "=====REINT_SETATTR::%s (%d)\n", rec->path, rec->valid);
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_setattr(rec->path, &iattr, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_symlink (symlink->targetpath, 
-                        symlink->sourcepath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_rename (int slot_offset, struct kml_rec *rec)
+static int reint_symlink(struct kml_rec *rec, struct file *dir,
+                         struct lento_vfs_context *info)
 {
-        struct  kml_rename *rename = &rec->rec_kml.rename;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
-
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_rename (rename->sourcepath, rename->targetpath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_SYMLINK::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_symlink(rec->target, rec->path, info);
+        pop_ctxt(&saved_ctxt); 
 
         EXIT;
         return error;
 }
 
-static int reint_setattr (int slot_offset, struct kml_rec *rec)
+static int reint_unlink(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        struct  kml_setattr *setattr = &rec->rec_kml.setattr;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
+        char *path;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = setattr->iattr.ia_attr_flags;
+        path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
+        if (path == NULL) {
+                EXIT;
+                return -ENOMEM;
+        }
+
+        CDEBUG (D_KML, "=====REINT_UNLINK::%s\n", path);
+        info->updated_time = rec->new_parentv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_unlink(path, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_setattr (setattr->path, &setattr->iattr, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        kfree(path);
         EXIT;
         return error;
 }
 
-static int reint_mknod (int slot_offset, struct kml_rec *rec)
+static int branch_reint_rename(struct presto_file_set *fset, struct kml_rec *rec, 
+                   struct file *dir, struct lento_vfs_context *info,
+                   char * kml_data, __u64 kml_size)
 {
-        struct  kml_mknod *mknod = &rec->rec_kml.mknod;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
+        error = reint_rename(rec, dir, info);
+        if (error == -ENOENT) {
+                /* normal reint failed because path was not found */
+                struct rec_info rec;
+                
+                CDEBUG(D_KML, "saving branch rename kml\n");
+                rec.is_kml = 1;
+                rec.size = kml_size;
+                error = presto_log(fset, &rec, kml_data, kml_size,
+                           NULL, 0, NULL, 0,  NULL, 0);
+                if (error == 0)
+                        error = presto_write_last_rcvd(&rec, fset, info);
+        }
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_mknod (mknod->path, mknod->mode, 
-                mk_kdev(mknod->major, mknod->minor), &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-int kml_reint (char *mtpt, int slot_offset, struct kml_rec *rec)
+int branch_reinter(struct presto_file_set *fset, struct kml_rec *rec, 
+                   struct file *dir, struct lento_vfs_context *info,
+                   char * kml_data, __u64 kml_size)
 {
         int error = 0;
-        switch (rec->rec_head.opcode)
-        {
-                case KML_CREATE:
-                        error = reint_create (slot_offset, rec);
-                        break;
-                case KML_OPEN:
-                        error = reint_open (slot_offset, rec);
-                        break;
-                case KML_CLOSE:
-                        /* error = reint_close (slot_offset, rec);
-                           force the system to return to lento */
-                        error = KML_CLOSE_BACKFETCH;
-                        break;
-                case KML_MKDIR:
-                        error = reint_mkdir (slot_offset, rec);
-                        break;
-                case KML_RMDIR:
-                        error = reint_rmdir (slot_offset, rec);
-                        break;
-                case KML_UNLINK:
-                        error = reint_unlink (slot_offset, rec);
-                        break;
-                case KML_LINK:
-                        error =  reint_link (slot_offset, rec);
-                        break;
-                case KML_SYMLINK:
-                        error = reint_symlink (slot_offset, rec);
-                        break;
-                case KML_RENAME:
-                        error = reint_rename (slot_offset, rec);
-                        break;
-                case KML_SETATTR:
-                        error =  reint_setattr (slot_offset, rec);
-                        break;
-                case KML_MKNOD:
-                        error = reint_mknod (slot_offset, rec);
-                        break;
-                default:
-                        CDEBUG (D_KML, "wrong opcode::%d\n", rec->rec_head.opcode);
-                        return -EBADF;
-        }
-        if (error != 0 && error != KML_CLOSE_BACKFETCH)
-                CDEBUG (D_KML, "KML_ERROR::error = %d\n", error);
+        int op = rec->prefix.hdr->opcode;
+
+        if (op == KML_OPCODE_CLOSE) {
+                /* regular close and backfetch */
+                error = reint_close(rec, dir, info);
+        } else if  (op == KML_OPCODE_RENAME) {
+                /* rename only if name already exists  */
+                error = branch_reint_rename(fset, rec, dir, info,
+                                            kml_data, kml_size);
+        } else {
+                /* just rewrite kml into branch/kml and update last_rcvd */
+                struct rec_info rec;
+                
+                CDEBUG(D_KML, "Saving branch kml\n");
+                rec.is_kml = 1;
+                rec.size = kml_size;
+                error = presto_log(fset, &rec, kml_data, kml_size,
+                           NULL, 0, NULL, 0,  NULL, 0);
+                if (error == 0)
+                        error = presto_write_last_rcvd(&rec, fset, info);
+        }
+                
         return error;
 }
 
-/* return the old mtpt */
-/*
-struct fs_struct {
-        atomic_t count;
-        int umask;
-        struct dentry * root, * pwd;
+typedef int (*reinter_t)(struct kml_rec *rec, struct file *basedir,
+                         struct lento_vfs_context *info);
+
+static reinter_t presto_reinters[KML_OPCODE_NUM] =
+{
+        [KML_OPCODE_CLOSE] = reint_close,
+        [KML_OPCODE_CREATE] = reint_create,
+        [KML_OPCODE_LINK] = reint_link,
+        [KML_OPCODE_MKDIR] = reint_mkdir,
+        [KML_OPCODE_MKNOD] = reint_mknod,
+        [KML_OPCODE_NOOP] = reint_noop,
+        [KML_OPCODE_RENAME] = reint_rename,
+        [KML_OPCODE_RMDIR] = reint_rmdir,
+        [KML_OPCODE_SETATTR] = reint_setattr,
+        [KML_OPCODE_SYMLINK] = reint_symlink,
+        [KML_OPCODE_UNLINK] = reint_unlink,
 };
-*/
-static int do_set_fs_root (struct dentry *newroot, 
-                                        struct dentry **old_root)
-{
-        struct dentry *de = current->fs->root;
-        current->fs->root = newroot;
-	if (old_root != (struct dentry **) NULL)
-        	*old_root = de;
-        return 0;
+
+static inline reinter_t get_reinter(int op)
+{
+        if (op < 0 || op >= sizeof(presto_reinters) / sizeof(reinter_t)) 
+                return NULL; 
+        else 
+                return  presto_reinters[op];
 }
 
-static int set_system_mtpt (char *mtpt, struct dentry **old_root)
+int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data)
 {
-	struct nameidata nd;
-        struct dentry *dentry;
-	int error;
-
-	error = path_lookup(pathname, LOOKUP_PARENT, &nd);
-        if (error) {
-                CDEBUG (D_KML, "Yean!!!!::Can't find mtpt::%s\n", mtpt);
+        char *ptr;
+        char *end;
+        struct kml_rec rec;
+        int error = 0;
+        struct lento_vfs_context info;
+        struct presto_cache *cache;
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        int op;
+        reinter_t reinter;
+
+        struct izo_rcvd_rec lr_rec;
+        int off;
+
+        ENTRY;
+
+        error = presto_prep(dir->f_dentry, &cache, &fset);
+        if ( error  ) {
+                CERROR("intermezzo: Reintegration on invalid file\n");
                 return error;
-	}
+        }
+
+        if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { 
+                CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
+                       dir->f_dentry->d_inode->i_ino);
+                    
+                return -EINVAL;
+        }
+
+        if (data->ioc_plen1 > 64 * 1024) {
+                EXIT;
+                return -ENOSPC;
+        }
+
+        ptr = fset->fset_reint_buf;
+        end = ptr + data->ioc_plen1;
+
+        if (copy_from_user(ptr, data->ioc_pbuf1, data->ioc_plen1)) { 
+                EXIT;
+                error = -EFAULT;
+                goto out;
+        }
+
+        error = kml_unpack(&rec, &ptr, end);
+        if (error) { 
+                EXIT;
+                error = -EFAULT;
+                goto out;
+        }
+
+        off = izo_rcvd_get(&lr_rec, fset, data->ioc_uuid);
+        if (off < 0) {
+                CERROR("No last_rcvd record, setting to 0\n");
+                memset(&lr_rec, 0, sizeof(lr_rec));
+        }
+ 
+        data->ioc_kmlsize = ptr - fset->fset_reint_buf;
 
-        dentry = nd.dentry;
-        error = do_set_fs_root (dentry, old_root);
-        path_release (&nd);
+        if (rec.suffix->recno != lr_rec.lr_remote_recno + 1) {
+                CERROR("KML record number %Lu expected, not %d\n",
+                       lr_rec.lr_remote_recno + 1,
+                       rec.suffix->recno);
+
+#if 0
+                if (!version_check(&rec, dd->dd_fset, &info)) {
+                        /* FIXME: do an upcall to resolve conflicts */
+                        CERROR("intermezzo: would be a conflict!\n");
+                        error = -EINVAL;
+                        EXIT;
+                        goto out;
+                }
+#endif
+        }
+
+        op = rec.prefix.hdr->opcode;
+
+        reinter = get_reinter(op);
+        if (!reinter) { 
+                CERROR("%s: Unrecognized KML opcode %d\n", __FUNCTION__, op);
+                error = -EINVAL;
+                EXIT;
+                goto out;
+        }
+
+        info.kml_offset = data->ioc_offset + data->ioc_kmlsize;
+        info.recno = rec.suffix->recno;
+        info.flags = LENTO_FL_EXPECT;
+        if (data->ioc_flags)
+                info.flags |= LENTO_FL_KML;
+
+        memcpy(info.uuid, data->ioc_uuid, sizeof(info.uuid));
+
+        if (fset->fset_flags & FSET_IS_BRANCH && data->ioc_flags)
+                error = branch_reinter(fset, &rec, dir, &info, fset->fset_reint_buf,
+                                       data->ioc_kmlsize);
+        else 
+                error = reinter(&rec, dir, &info);
+ out: 
+        EXIT;
         return error;
 }
 
-int kml_reintbuf (struct  kml_fsdata *kml_fsdata,
-                  char *mtpt, struct kml_rec **close_rec)
+int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data)
 {
-        struct kml_rec *rec = NULL;
-        struct list_head *head, *tmp;
-        struct dentry *old_root;
-        int    error = 0;
-
-        head = &kml_fsdata->kml_reint_cache;
-        if (list_empty(head))
-                return 0;
+        char *buf = NULL; 
+        char *ptr;
+        char *end;
+        struct kml_rec rec;
+        struct file *file;
+        struct presto_cache *cache;
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        struct run_ctxt saved_ctxt;
+        int     error;
 
-        if (kml_fsdata->kml_reint_current == NULL ||
-            kml_fsdata->kml_reint_current == head->next)
-                return 0;
+        ENTRY;
 
-        error = set_system_mtpt (mtpt, &old_root);
-        if (error)
+        error = presto_prep(dir->f_dentry, &cache, &fset);
+        if ( error  ) {
+                CERROR("intermezzo: Reintegration on invalid file\n");
                 return error;
+        }
+
+        if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { 
+                CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
+                       dir->f_dentry->d_inode->i_ino);
+                    
+                return -EINVAL;
+        }
+
+
+        PRESTO_ALLOC(buf, data->ioc_plen1);
+        if (!buf) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        ptr = buf;
+        end = buf + data->ioc_plen1;
+
+        if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
+                EXIT;
+                PRESTO_FREE(buf, data->ioc_plen1);
+                return -EFAULT;
+        }
 
-        tmp = head->next;
-        while (error == 0 &&  tmp != head ) {
-                rec = list_entry(tmp, struct kml_rec, kml_optimize.kml_chains);
-                error = kml_reint (mtpt, rec->rec_kml_offset, rec);
-                tmp = tmp->next;
+        error = kml_unpack(&rec, &ptr, end);
+        if (error) { 
+                EXIT;
+                PRESTO_FREE(buf, data->ioc_plen1);
+                return -EFAULT;
         }
 
-        do_set_fs_root (old_root, NULL);
-
-        if (error == KML_CLOSE_BACKFETCH)
-                *close_rec = rec;
-        kml_fsdata->kml_reint_current = tmp;
+        kmlreint_pre_secure(&rec, dir, &saved_ctxt);
+
+        file = filp_open(rec.path, O_RDONLY, 0);
+        if (!file || IS_ERR(file)) { 
+                error = PTR_ERR(file);
+                goto out;
+        }
+        data->ioc_ino = file->f_dentry->d_inode->i_ino;
+        data->ioc_generation = file->f_dentry->d_inode->i_generation; 
+        filp_close(file, 0); 
+
+        CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path, 
+               data->ioc_ino, data->ioc_generation);
+
+ out:
+        if (buf) 
+                PRESTO_FREE(buf, data->ioc_plen1);
+        pop_ctxt(&saved_ctxt); 
+        EXIT;
         return error;
 }
+
 
diff -Nru a/fs/intermezzo/kml_unpack.c b/fs/intermezzo/kml_unpack.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/intermezzo/kml_unpack.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,708 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Unpacking of KML records
+ *
+ */
+
+#ifdef __KERNEL__
+#  include <linux/module.h>
+#  include <linux/errno.h>
+#  include <linux/kernel.h>
+#  include <linux/major.h>
+#  include <linux/sched.h>
+#  include <linux/lp.h>
+#  include <linux/slab.h>
+#  include <linux/ioport.h>
+#  include <linux/fcntl.h>
+#  include <linux/delay.h>
+#  include <linux/skbuff.h>
+#  include <linux/proc_fs.h>
+#  include <linux/vmalloc.h>
+#  include <linux/fs.h>
+#  include <linux/poll.h>
+#  include <linux/init.h>
+#  include <linux/list.h>
+#  include <linux/stat.h>
+#  include <asm/io.h>
+#  include <asm/segment.h>
+#  include <asm/system.h>
+#  include <asm/poll.h>
+#  include <asm/uaccess.h>
+#else
+#  include <time.h>
+#  include <stdio.h>
+#  include <string.h>
+#  include <stdlib.h>
+#  include <errno.h>
+#  include <sys/stat.h>
+#  include <glib.h>
+#endif
+
+#include <linux/intermezzo_lib.h>
+#include <linux/intermezzo_idl.h>
+#include <linux/intermezzo_fs.h>
+
+int kml_unpack_version(struct presto_version **ver, char **buf, char *end) 
+{
+	char *ptr = *buf;
+        struct presto_version *pv;
+
+	UNLOGP(*ver, struct presto_version, ptr, end);
+        pv = *ver;
+        pv->pv_mtime   = NTOH__u64(pv->pv_mtime);
+        pv->pv_ctime   = NTOH__u64(pv->pv_ctime);
+        pv->pv_size    = NTOH__u64(pv->pv_size);
+
+	*buf = ptr;
+
+        return 0;
+}
+
+
+static int kml_unpack_noop(struct kml_rec *rec, char **buf, char *end)
+{
+	return 0;
+}
+
+ 
+static int kml_unpack_get_fileid(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+	return 0;
+}
+
+static int kml_unpack_create(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+ 
+static int kml_unpack_mkdir(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_unlink(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+        LUNLOGV(rec->old_targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+        UNLOGL(rec->old_target, char, rec->old_targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_rmdir(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_close(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	LUNLOGV(rec->mode, __u32, ptr, end);  // used for open_mode
+	LUNLOGV(rec->uid, __u32, ptr, end);   // used for open_uid
+	LUNLOGV(rec->gid, __u32, ptr, end);   // used for open_gid
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->ino, __u64, ptr, end);
+	LUNLOGV(rec->generation, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_symlink(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_rename(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_setattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	LUNLOGV(rec->valid, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->size, __u64, ptr, end);
+	LUNLOGV(rec->mtime, __u64, ptr, end);
+	LUNLOGV(rec->ctime, __u64, ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_link(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+static int kml_unpack_mknod(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->major, __u32, ptr, end);
+	LUNLOGV(rec->minor, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_write(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_release(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_trunc(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_setextattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->namelen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+        UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->name, char, rec->namelen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_delextattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->namelen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->name, char, rec->namelen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+static int kml_unpack_open(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+static int kml_unpack_kml_trunc(struct kml_rec *rec, char **buf, char *end)
+{
+
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+typedef int (*unpacker)(struct kml_rec *rec, char **buf, char *end);
+
+static unpacker unpackers[KML_OPCODE_NUM] = 
+{
+	[KML_OPCODE_NOOP] = kml_unpack_noop,
+	[KML_OPCODE_CREATE] = kml_unpack_create, 
+	[KML_OPCODE_MKDIR] = kml_unpack_mkdir,
+	[KML_OPCODE_UNLINK] = kml_unpack_unlink,
+	[KML_OPCODE_RMDIR] = kml_unpack_rmdir,
+	[KML_OPCODE_CLOSE] = kml_unpack_close,
+	[KML_OPCODE_SYMLINK] = kml_unpack_symlink,
+	[KML_OPCODE_RENAME] = kml_unpack_rename,
+	[KML_OPCODE_SETATTR] = kml_unpack_setattr,
+	[KML_OPCODE_LINK] = kml_unpack_link,
+	[KML_OPCODE_OPEN] = kml_unpack_open,
+	[KML_OPCODE_MKNOD] = kml_unpack_mknod,
+	[KML_OPCODE_WRITE] = kml_unpack_write,
+	[KML_OPCODE_RELEASE] = kml_unpack_release,
+	[KML_OPCODE_TRUNC] = kml_unpack_trunc,
+	[KML_OPCODE_SETEXTATTR] = kml_unpack_setextattr,
+	[KML_OPCODE_DELEXTATTR] = kml_unpack_delextattr,
+	[KML_OPCODE_KML_TRUNC] = kml_unpack_kml_trunc,
+	[KML_OPCODE_GET_FILEID] = kml_unpack_get_fileid
+};
+
+int kml_unpack_prefix(struct kml_rec *rec, char **buf, char *end) 
+{
+	char *ptr = *buf;
+        int n;
+
+        UNLOGP(rec->prefix.hdr, struct kml_prefix_hdr, ptr, end);
+        rec->prefix.hdr->len     = NTOH__u32(rec->prefix.hdr->len);
+        rec->prefix.hdr->version = NTOH__u32(rec->prefix.hdr->version);
+        rec->prefix.hdr->pid     = NTOH__u32(rec->prefix.hdr->pid);
+        rec->prefix.hdr->auid    = NTOH__u32(rec->prefix.hdr->auid);
+        rec->prefix.hdr->fsuid   = NTOH__u32(rec->prefix.hdr->fsuid);
+        rec->prefix.hdr->fsgid   = NTOH__u32(rec->prefix.hdr->fsgid);
+        rec->prefix.hdr->opcode  = NTOH__u32(rec->prefix.hdr->opcode);
+        rec->prefix.hdr->ngroups = NTOH__u32(rec->prefix.hdr->ngroups);
+
+	UNLOGL(rec->prefix.groups, __u32, rec->prefix.hdr->ngroups, ptr, end);
+        for (n = 0; n < rec->prefix.hdr->ngroups; n++) {
+                rec->prefix.groups[n] = NTOH__u32(rec->prefix.groups[n]);
+        }
+
+	*buf = ptr;
+
+        return 0;
+}
+
+int kml_unpack_suffix(struct kml_rec *rec, char **buf, char *end) 
+{
+	char *ptr = *buf;
+
+	UNLOGP(rec->suffix, struct kml_suffix, ptr, end);
+        rec->suffix->prevrec   = NTOH__u32(rec->suffix->prevrec);
+        rec->suffix->recno    = NTOH__u32(rec->suffix->recno);
+        rec->suffix->time     = NTOH__u32(rec->suffix->time);
+        rec->suffix->len      = NTOH__u32(rec->suffix->len);
+
+	*buf = ptr;
+
+        return 0;
+}
+
+int kml_unpack(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+	int err; 
+
+        if (((unsigned long)ptr % 4) != 0) {
+                printf("InterMezzo: %s: record misaligned.\n", __FUNCTION__);
+                return -EINVAL;
+        }
+
+        while (ptr < end) { 
+                __u32 *i = (__u32 *)ptr;
+                if (*i)
+                        break;
+                ptr += sizeof(*i);
+        }
+	*buf = ptr;
+
+	memset(rec, 0, sizeof(*rec));
+
+        err = kml_unpack_prefix(rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpack_prefix failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+        if (rec->prefix.hdr->opcode < 0  ||
+            rec->prefix.hdr->opcode >= KML_OPCODE_NUM) {
+                printf("InterMezzo: %s: invalid opcode (%d)\n",
+                       __FUNCTION__, rec->prefix.hdr->opcode);
+		return -EINVAL;
+        }
+	err = unpackers[rec->prefix.hdr->opcode](rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpacker failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+        err = kml_unpack_suffix(rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpack_suffix failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+
+	if (rec->prefix.hdr->len != rec->suffix->len) {
+                printf("InterMezzo: %s: lengths don't match\n",
+                       __FUNCTION__);
+		return -EINVAL;
+        }
+        if ((rec->prefix.hdr->len % 4) != 0) {
+                printf("InterMezzo: %s: record length not a "
+                       "multiple of 4.\n", __FUNCTION__);
+                return -EINVAL;
+        }
+        if (ptr - *buf != rec->prefix.hdr->len) {
+                printf("InterMezzo: %s: unpacking error\n",
+                       __FUNCTION__);
+                return -EINVAL;
+        }
+        while (ptr < end) { 
+                __u32 *i = (__u32 *)ptr;
+                if (*i)
+                        break;
+                ptr += sizeof(*i);
+        }
+	*buf = ptr;
+	return 0;
+}
+
+
+#ifndef __KERNEL__
+#define STR(ptr) ((ptr))? (ptr) : ""
+
+#define OPNAME(n) [KML_OPCODE_##n] = #n
+static char *opnames[KML_OPCODE_NUM] = {
+	OPNAME(NOOP),
+	OPNAME(CREATE),
+	OPNAME(MKDIR), 
+	OPNAME(UNLINK),
+	OPNAME(RMDIR),
+	OPNAME(CLOSE),
+	OPNAME(SYMLINK),
+	OPNAME(RENAME),
+	OPNAME(SETATTR),
+	OPNAME(LINK),
+	OPNAME(OPEN),
+	OPNAME(MKNOD),
+	OPNAME(WRITE),
+	OPNAME(RELEASE),
+	OPNAME(TRUNC),
+	OPNAME(SETEXTATTR),
+	OPNAME(DELEXTATTR),
+	OPNAME(KML_TRUNC),
+	OPNAME(GET_FILEID)
+};
+#undef OPNAME
+
+static char *print_opname(int op)
+{
+	if (op < 0 || op >= sizeof (opnames) / sizeof (*opnames))
+		return NULL;
+	return opnames[op];
+}
+
+
+static char *print_time(__u64 i)
+{
+	char buf[128];
+	
+	memset(buf, 0, 128);
+
+#ifndef __KERNEL__
+	strftime(buf, 128, "%Y/%m/%d %H:%M:%S", gmtime((time_t *)&i));
+#else
+	sprintf(buf, "%Ld\n", i);
+#endif
+
+	return strdup(buf);
+}
+
+static char *print_version(struct presto_version *ver)
+{
+	char ver_buf[128];
+	char *mtime;
+	char *ctime;
+
+	if (!ver || ver->pv_ctime == 0) {
+		return strdup("");
+	} 
+	mtime = print_time(ver->pv_mtime);
+	ctime = print_time(ver->pv_ctime);
+	sprintf(ver_buf, "mtime %s, ctime %s, len %lld", 
+		mtime, ctime, ver->pv_size);
+	free(mtime);
+	free(ctime);
+	return strdup(ver_buf);
+}
+
+
+char *kml_print_rec(struct kml_rec *rec, int brief)
+{
+	char *str;
+	char *nov, *oov, *ntv, *otv, *npv, *opv;
+	char *rectime, *mtime, *ctime;
+
+        if (brief) {
+		str = g_strdup_printf(" %08d %7s %*s %*s", 
+                                      rec->suffix->recno,
+                                      print_opname (rec->prefix.hdr->opcode),
+                                      rec->pathlen, STR(rec->path),
+                                      rec->targetlen, STR(rec->target));
+                
+		return str;
+	}
+
+	rectime = print_time(rec->suffix->time);
+	mtime = print_time(rec->mtime);
+	ctime = print_time(rec->ctime);
+
+	nov = print_version(rec->new_objectv);
+	oov = print_version(rec->old_objectv);
+	ntv = print_version(rec->new_targetv);
+	otv = print_version(rec->old_targetv);
+	npv = print_version(rec->new_parentv);
+	opv = print_version(rec->old_parentv);
+
+	str = g_strdup_printf("\n -- Record:\n"
+		"    Recno     %d\n"
+		"    KML off   %lld\n" 
+		"    Version   %d\n" 
+		"    Len       %d\n"
+		"    Suf len   %d\n"
+		"    Time      %s\n"
+		"    Opcode    %d\n"
+		"    Op        %s\n"
+		"    Pid       %d\n"
+		"    AUid      %d\n"
+		"    Fsuid     %d\n" 
+		"    Fsgid     %d\n"
+		"    Prevrec   %d\n" 
+		"    Ngroups   %d\n"
+		//"    Groups    @{$self->{groups}}\n" 
+		" -- Path:\n"
+		"    Inode     %d\n"
+		"    Gen num   %u\n"
+                "    Old mode  %o\n"
+                "    Old rdev  %x\n"
+                "    Old uid   %llu\n"
+                "    Old gid   %llu\n"
+		"    Path      %*s\n"
+		//"    Open_mode %o\n",
+		"    Pathlen   %d\n"
+		"    Tgt       %*s\n"
+		"    Tgtlen    %d\n" 
+		"    Old Tgt   %*s\n"
+		"    Old Tgtln %d\n" 
+		" -- Attr:\n"
+		"    Valid     %x\n"
+		"    mode %o, uid %d, gid %d, size %lld, mtime %s, ctime %s rdev %x (%d:%d)\n"
+		" -- Versions:\n"
+		"    New object %s\n"
+		"    Old object %s\n"
+		"    New target %s\n"
+		"    Old target %s\n"
+		"    New parent %s\n"
+		"    Old parent %s\n", 
+		
+		rec->suffix->recno, 
+		rec->offset, 
+		rec->prefix.hdr->version, 
+		rec->prefix.hdr->len, 
+		rec->suffix->len, 
+		rectime,
+		rec->prefix.hdr->opcode, 
+		print_opname (rec->prefix.hdr->opcode),
+		rec->prefix.hdr->pid,
+		rec->prefix.hdr->auid,
+		rec->prefix.hdr->fsuid,
+		rec->prefix.hdr->fsgid,
+		rec->suffix->prevrec,
+		rec->prefix.hdr->ngroups,
+		rec->ino,
+		rec->generation,
+                rec->old_mode,
+                rec->old_rdev,
+                rec->old_uid,
+                rec->old_gid,
+		rec->pathlen,
+		STR(rec->path),
+		rec->pathlen,
+		rec->targetlen,
+		STR(rec->target),
+		rec->targetlen,
+		rec->old_targetlen,
+		STR(rec->old_target),
+		rec->old_targetlen,
+		
+		rec->valid, 
+		rec->mode,
+		rec->uid,
+		rec->gid,
+		rec->size,
+		mtime,
+		ctime,
+		rec->rdev, rec->major, rec->minor,
+		nov, oov, ntv, otv, npv, opv);
+		
+	free(nov);
+	free(oov);
+	free(ntv);
+	free(otv);
+	free(npv);
+	free(opv);
+
+	free(rectime); 
+	free(ctime);
+	free(mtime);
+
+	return str;
+}
+#endif
diff -Nru a/fs/intermezzo/methods.c b/fs/intermezzo/methods.c
--- a/fs/intermezzo/methods.c	Tue Oct 15 20:29:21 2002
+++ b/fs/intermezzo/methods.c	Tue Oct 15 20:29:21 2002
@@ -1,5 +1,5 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
@@ -7,6 +7,22 @@
  *
  *  Extended Attribute Support
  *  Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  */
 
 #include <stdarg.h>
@@ -20,9 +36,10 @@
 #include <linux/ext2_fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 #define __NO_VERSION__
@@ -149,6 +166,16 @@
                 FDEBUG(D_SUPER, "ops at %p\n", ops);
         }
 
+        if ( strlen(cache_type) == strlen("tmpfs") &&
+             memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
+#if defined(CONFIG_TMPFS)
+                ops->o_trops = &presto_tmpfs_journal_ops;
+#else
+                ops->o_trops = NULL;
+#endif
+                FDEBUG(D_SUPER, "ops at %p\n", ops);
+        }
+
         if ( strlen(cache_type) == strlen("reiserfs") &&
              memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
 #if 0
@@ -163,7 +190,7 @@
         if ( strlen(cache_type) == strlen("xfs") &&
              memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) {
 #if 0
-                //#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE)
+/*#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE) */
                 ops->o_trops = &presto_xfs_journal_ops;
 #else
                 ops->o_trops = NULL;
@@ -206,6 +233,13 @@
                 ops = &filter_oppar[FILTER_FS_EXT3];
                 FDEBUG(D_SUPER, "ops at %p\n", ops);
         }
+
+        if ( strlen(cache_type) == strlen("tmpfs") &&
+             memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
+                ops = &filter_oppar[FILTER_FS_TMPFS];
+                FDEBUG(D_SUPER, "ops at %p\n", ops);
+        }
+
         if ( strlen(cache_type) == strlen("reiserfs") &&
              memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
                 ops = &filter_oppar[FILTER_FS_REISERFS];
@@ -218,7 +252,7 @@
         }
 
         if (ops == NULL) {
-                printk("prepare to die: unrecognized cache type for Filter\n");
+                CERROR("prepare to die: unrecognized cache type for Filter\n");
         }
         return ops;
         FEXIT;
@@ -342,7 +376,7 @@
         memcpy(filter_c2udfops(cache), cache_fops, sizeof(*cache_fops));
 
         /* unconditional filtering operations */
-        filter_c2udfops(cache)->open = filter_fops->open;
+        filter_c2udfops(cache)->ioctl = filter_fops->ioctl;
 
         FEXIT;
 }
@@ -373,7 +407,7 @@
         memcpy(pr_iops, cache_iops, sizeof(*cache_iops));
 
         /* copy dir fops */
-        printk("*** cache file ops at %p\n", cache_fops);
+        CERROR("*** cache file ops at %p\n", cache_fops);
         memcpy(filter_c2uffops(cache), cache_fops, sizeof(*cache_fops));
 
         /* assign */
@@ -382,6 +416,8 @@
                 pr_iops->setattr = filter_iops->setattr;
         if (cache_iops->getattr)
                 pr_iops->getattr = filter_iops->getattr;
+        /* XXX Should this be conditional rmr ? */
+        pr_iops->permission = filter_iops->permission;
 #ifdef CONFIG_FS_EXT_ATTR
     	/* For now we assume that posix acls are handled through extended
 	* attributes. If this is not the case, we must explicitly trap and 
@@ -396,6 +432,7 @@
         filter_c2uffops(cache)->open = filter_fops->open;
         filter_c2uffops(cache)->release = filter_fops->release;
         filter_c2uffops(cache)->write = filter_fops->write;
+        filter_c2uffops(cache)->ioctl = filter_fops->ioctl;
 
         FEXIT;
 }
@@ -454,7 +491,7 @@
                filter_dop, sizeof(*filter_dop));
         
         if (cache_dop &&  cache_dop != filter_dop && cache_dop->d_revalidate){
-                printk("WARNING: filter overriding revalidation!\n");
+                CERROR("WARNING: filter overriding revalidation!\n");
         }
         return;
 }
diff -Nru a/fs/intermezzo/presto.c b/fs/intermezzo/presto.c
--- a/fs/intermezzo/presto.c	Tue Oct 15 20:29:17 2002
+++ b/fs/intermezzo/presto.c	Tue Oct 15 20:29:17 2002
@@ -1,60 +1,62 @@
-/*
- * intermezzo.c
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- * This file implements basic routines supporting the semantics
+ *  Author: Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 1998 Stelias Computing Inc
+ *  Copyright (C) 1999 Red Hat Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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.
  *
- * Author: Peter J. Braam  <braam@cs.cmu.edu>
- * Copyright (C) 1998 Stelias Computing Inc
- * Copyright (C) 1999 Red Hat Inc.
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * This file implements basic routines supporting the semantics
  */
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
+#include <linux/namei.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
-extern int presto_init_last_rcvd_file(struct presto_file_set *);
-extern int presto_init_lml_file(struct presto_file_set *);
-extern int presto_init_kml_file(struct presto_file_set *);
 
 int presto_walk(const char *name, struct nameidata *nd)
 {
+        int err;
         /* we do not follow symlinks to support symlink operations 
            correctly. The vfs should always hand us resolved dentries
            so we should not be required to use LOOKUP_FOLLOW. At the
-	   reintegrating end, lento again should be working with the 
+           reintegrating end, lento again should be working with the 
            resolved pathname and not the symlink. SHP
            XXX: This code implies that direct symlinks do not work. SHP
         */
-        unsigned int flags = 0;
-        return path_lookup(name, flags, nd);
-}
+        unsigned int flags = 0; //LOOKUP_POSITIVE;
 
-inline struct presto_dentry_data *presto_d2d(struct dentry *dentry)
-{
-        return (struct presto_dentry_data *)dentry->d_fsdata;
+        ENTRY;
+        err = path_lookup(name, flags, nd);
+        return err;
 }
 
-static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
-{
-        if (dentry->d_fsdata == NULL) {
-                printk("fucked dentry: %p\n", dentry);
-                BUG();
-        }
-        return presto_d2d(dentry)->dd_fset;
-}
 
 /* find the presto minor device for this inode */
 int presto_i2m(struct inode *inode)
@@ -64,8 +66,8 @@
         cache = presto_get_cache(inode);
         CDEBUG(D_PSDEV, "\n");
         if ( !cache ) {
-                printk("PRESTO: BAD: cannot find cache for dev %s, ino %ld\n",
-                       inode->i_sb->s_id, inode->i_ino);
+                CERROR("PRESTO: BAD: cannot find cache for dev %d, ino %ld\n",
+                       inode->i_dev, inode->i_ino);
                 EXIT;
                 return -1;
         }
@@ -85,48 +87,6 @@
 
 }
 
-int presto_has_all_data(struct inode *inode)
-{
-        ENTRY;
-
-        if ( (inode->i_size >> inode->i_sb->s_blocksize_bits) >
-             inode->i_blocks) {
-                EXIT;
-                return 0;
-        }
-        EXIT;
-        return 1;
-
-}
-
-/* find the fileset dentry for this dentry */
-struct presto_file_set *presto_fset(struct dentry *de)
-{
-        struct dentry *fsde;
-        ENTRY;
-        fsde = de;
-        for ( ; ; ) {
-                if ( presto_dentry2fset(fsde) ) {
-                        EXIT;
-                        return presto_dentry2fset(fsde);
-                }
-                /* are we at the cache "/" ?? */
-                if ( fsde->d_parent == fsde ) {
-                        if ( !de->d_inode ) {
-                                printk("Warning %*s has no fileset inode.\n",
-                                       de->d_name.len, de->d_name.name);
-                        }
-                        /* better to return a BAD thing */
-                        EXIT;
-                        return NULL;
-                }
-                fsde = fsde->d_parent;
-        }
-        /* not reached */
-        EXIT;
-        return NULL;
-}
-
 /* XXX check this out */
 struct presto_file_set *presto_path2fileset(const char *name)
 {
@@ -162,7 +122,7 @@
 
         ENTRY;
         minor = presto_i2m(dentry->d_inode);
-        if ( upc_comms[minor].uc_no_filter ) {
+        if ( izo_channels[minor].uc_no_filter ) {
                 EXIT;
                 return ~0;
         }
@@ -172,7 +132,7 @@
              (flag == PRESTO_ATTR || flag == PRESTO_DATA) &&
              (fset->fset_flags & FSET_INSYNC) ) {
                 CDEBUG(D_INODE, "fset in sync (ino %ld)!\n",
-                       fset->fset_mtpt->d_inode->i_ino);
+                       fset->fset_dentry->d_inode->i_ino);
                 EXIT;
                 return 1;
         }
@@ -184,12 +144,16 @@
 /* set a bit in the dentry flags */
 void presto_set(struct dentry *dentry, int flag)
 {
-
         ENTRY;
         if ( dentry->d_inode ) {
                 CDEBUG(D_INODE, "SET ino %ld, flag %x\n",
                        dentry->d_inode->i_ino, flag);
         }
+        if ( presto_d2d(dentry) == NULL) {
+                CERROR("dentry without d_fsdata in presto_set: %p: %*s", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
+                BUG();
+        }
         presto_d2d(dentry)->dd_flags |= flag;
         EXIT;
 }
@@ -203,7 +167,6 @@
         struct presto_file_set *fset;
         ENTRY;
 
-
         error = presto_walk(path, &nd);
         if (error) {
                 EXIT;
@@ -221,7 +184,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto out_complete;
         }
@@ -235,108 +198,7 @@
         return error;
 }       
 
-/* set the fset recno and offset to a given value */ 
-int lento_reset_fset(char *path, __u64 offset, __u32 recno)
-{
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-        struct presto_file_set *fset;
-        ENTRY;
-
-
-        error = presto_walk(path, &nd);
-        if (error)
-                return error;
-
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_complete;
-        }
-        
-        fset = presto_fset(dentry);
-        error = -EINVAL;
-        if ( !fset ) {
-                printk("No fileset!\n");
-                EXIT;
-                goto out_complete;
-        }
-
-        write_lock(&fset->fset_kml.fd_lock);
-        fset->fset_kml.fd_recno = recno;
-        fset->fset_kml.fd_offset = offset;
-        read_lock(&fset->fset_kml.fd_lock);
-        
-        EXIT;
- out_complete:
-        path_release(&nd);
-        return error;
-}       
-
-
-
-/* given a path, write an LML record for it - thus must have root's 
-   group array settings, since lento is doing this 
-*/ 
-int lento_write_lml(char *path,
-                     __u64 remote_ino, 
-                     __u32 remote_generation,
-                     __u32 remote_version,
-                     struct presto_version *remote_file_version)
-{
-        struct nameidata nd; 
-        struct rec_info rec;
-        struct dentry *dentry;
-        struct file file;
-        int error;
-        struct presto_file_set *fset;
-        ENTRY;
-
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        file.f_dentry = dentry;
-        file.private_data = NULL;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_lml;
-        }
-        
-        fset = presto_fset(dentry);
-        error = -EINVAL;
-        if ( !fset ) {
-                printk("No fileset!\n");
-                EXIT;
-                goto out_lml;
-        }
-
-        
-        /* setting offset to -1 appends */
-        rec.offset = -1;
-        /* this only requires a transaction below which is automatic */
-        error = presto_write_lml_close(&rec, 
-                                       fset,
-                                       &file, 
-                                       remote_ino,
-                                       remote_generation,
-                                       remote_version,
-                                       remote_file_version);
-        
-        EXIT;
- out_lml:
-        path_release(&nd);
-        return error;
-}       
-
+#if 0
 /* given a path: write a close record and cancel an LML record, finally
    call truncate LML.  Lento is doing this so it goes in with uid/gid's 
    root. 
@@ -375,14 +237,14 @@
 
         error=-EINVAL;
         if (fset==NULL) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto out_cancel_lml;
         }
         
         /* this only requires a transaction below which is automatic */
         handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_RELEASE); 
-        if ( !handle ) {
+        if ( IS_ERR(handle) ) {
                 error = -ENOMEM; 
                 EXIT; 
                 goto out_cancel_lml; 
@@ -414,7 +276,7 @@
 
         if (info->flags & LENTO_FL_WRITE_EXPECT) {
                 error = presto_write_last_rcvd(&rec, fset, info); 
-                if ( error ) {
+                if ( error < 0 ) {
                         EXIT; 
                         presto_trans_commit(fset, handle);
                         goto out_cancel_lml;
@@ -433,136 +295,101 @@
         path_release(&nd); 
         return error;
 }       
+#endif 
 
-
-/* given a path, operate on the flags in its dentry.  Used by downcalls */
-int presto_mark_dentry(const char *name, int and_flag, int or_flag, 
+/* given a dentry, operate on the flags in its dentry.  Used by downcalls */
+int izo_mark_dentry(struct dentry *dentry, int and_flag, int or_flag, 
                        int *res)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
-        dentry = nd.dentry;
-
-        CDEBUG(D_INODE, "name: %s, and flag %x, or flag %x, dd_flags %x\n",
-               name, and_flag, or_flag, presto_d2d(dentry)->dd_flags);
-
+        int error = 0;
 
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                goto out;
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: no ddata for inode %ld in %s\n",
+                       dentry->d_inode->i_ino, __FUNCTION__);
+                return -EINVAL;
+        }
 
-        error = 0;
+        CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n",
+               dentry->d_inode->i_ino, and_flag, or_flag,
+               presto_d2d(dentry)->dd_flags);
 
-        presto_d2d(dentry)->dd_flags  &= and_flag;
-        presto_d2d(dentry)->dd_flags  |= or_flag;
+        presto_d2d(dentry)->dd_flags &= and_flag;
+        presto_d2d(dentry)->dd_flags |= or_flag;
         if (res) 
                 *res = presto_d2d(dentry)->dd_flags;
 
-        // XXX this check makes no sense as d_count can change anytime.
-        /* indicate if we were the only users while changing the flag */
-        if ( atomic_read(&dentry->d_count) > 1 )
-                error = -EBUSY;
-
-out:
-        path_release(&nd);
         return error;
 }
 
 /* given a path, operate on the flags in its cache.  Used by mark_ioctl */
-int presto_mark_cache(const char *name, int and_flag, int or_flag, 
-                      int *res)
+int izo_mark_cache(struct dentry *dentry, int and_flag, int or_flag, 
+                   int *res)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
         struct presto_cache *cache;
-        int error;
-
-        CDEBUG(D_INODE,
-               "presto_mark_cache :: name: %s, and flag %x, or flag %x\n",
-               name, and_flag, or_flag);
 
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: no ddata for inode %ld in %s\n",
+                       dentry->d_inode->i_ino, __FUNCTION__);
+                return -EINVAL;
+        }
 
-        dentry = nd.dentry;
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                goto out;
+        CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n",
+               dentry->d_inode->i_ino, and_flag, or_flag,
+               presto_d2d(dentry)->dd_flags);
 
-        error = -EBADF;
         cache = presto_get_cache(dentry->d_inode);
         if ( !cache ) {
-                printk("PRESTO: BAD: cannot find cache in presto_mark_cache\n");
-                make_bad_inode(dentry->d_inode);
-                goto out;
+                CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n");
+                return -EBADF;
         }
-        error = 0;
+
         ((int)cache->cache_flags) &= and_flag;
         ((int)cache->cache_flags) |= or_flag;
-        if (res) {
+        if (res)
                 *res = (int)cache->cache_flags;
-        }
 
-out:
-        path_release(&nd);
-        return error;
+        return 0;
 }
 
-int presto_mark_fset_dentry(struct dentry *dentry, int and_flag, int or_flag, 
-                     int * res)
+int presto_set_max_kml_size(const char *path, unsigned long max_size)
 {
-        int error;
         struct presto_file_set *fset;
 
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                return error;
+        ENTRY;
+
+        fset = presto_path2fileset(path);
+        if (IS_ERR(fset)) {
+                EXIT;
+                return PTR_ERR(fset);
+        }
+
+        fset->kml_truncate_size = max_size;
+        CDEBUG(D_CACHE, "KML truncate size set to %lu bytes for fset %s.\n",
+               max_size, path);
 
-        error = -EBADF;
+        EXIT;
+        return 0;
+}
+
+int izo_mark_fset(struct dentry *dentry, int and_flag, int or_flag, 
+                  int * res)
+{
+        struct presto_file_set *fset;
+        
         fset = presto_fset(dentry);
         if ( !fset ) {
-                printk("PRESTO: BAD: cannot find cache in presto_mark_cache\n");
+                CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n");
                 make_bad_inode(dentry->d_inode);
-                return error;
+                return -EBADF;
         }
-        error = 0;
         ((int)fset->fset_flags) &= and_flag;
         ((int)fset->fset_flags) |= or_flag;
-        if (res) { 
+        if (res)
                 *res = (int)fset->fset_flags;
-        }
-
-        return error;
-}
-
-/* given a path, operate on the flags in its cache.  Used by mark_ioctl */
-inline int presto_mark_fset(const char *name, int and_flag, int or_flag, 
-                     int * res)
-{
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-        ENTRY;
 
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
-
-
-        dentry = nd.dentry;
-        error = presto_mark_fset_dentry(dentry, and_flag, or_flag, res);
-
-        path_release(&nd);
-        return error;
+        return 0;
 }
 
-
 /* talk to Lento about the permit */
 static int presto_permit_upcall(struct dentry *dentry)
 {
@@ -573,8 +400,12 @@
         int fsetnamelen;
         struct presto_file_set *fset = NULL;
 
-        if ( (minor = presto_i2m(dentry->d_inode)) < 0)
+        ENTRY;
+
+        if ( (minor = presto_i2m(dentry->d_inode)) < 0) {
+                EXIT;
                 return -EINVAL;
+        }
 
         fset = presto_fset(dentry);
         if (!fset) {
@@ -584,22 +415,26 @@
         
         if ( !presto_lento_up(minor) ) {
                 if ( fset->fset_flags & FSET_STEAL_PERMIT ) {
+                        EXIT;
                         return 0;
                 } else {
+                        EXIT;
                         return -ENOTCONN;
                 }
         }
 
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
+        PRESTO_ALLOC(buffer, PAGE_SIZE);
         if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
+                CERROR("PRESTO: out of memory!\n");
+                EXIT;
                 return -ENOMEM;
         }
-        path = presto_path(dentry, fset->fset_mtpt, buffer, PAGE_SIZE);
+        path = presto_path(dentry, fset->fset_dentry, buffer, PAGE_SIZE);
         pathlen = MYPATHLEN(buffer, path);
         fsetnamelen = strlen(fset->fset_name); 
-        rc = lento_permit(minor, pathlen, fsetnamelen, path, fset->fset_name);
+        rc = izo_upc_permit(minor, dentry, pathlen, path, fset->fset_name);
         PRESTO_FREE(buffer, PAGE_SIZE);
+        EXIT;
         return rc;
 }
 
@@ -608,13 +443,16 @@
  *  - if 0 is returned the permit was already in the kernel -- or --
  *    Lento gave us the permit without reintegration
  *  - lento returns the number of records it reintegrated 
+ *
+ * Note that if this fileset has branches, a permit will -never- to a normal
+ * process for writing in the data area (ie, outside of .intermezzo)
  */
 int presto_get_permit(struct inode * inode)
 {
         struct dentry *de;
         struct presto_file_set *fset;
         int minor = presto_i2m(inode);
-        int rc;
+        int rc = 0;
 
         ENTRY;
         if (minor < 0) {
@@ -624,47 +462,101 @@
 
         if ( ISLENTO(minor) ) {
                 EXIT;
-                return -EINVAL;
+                return 0;
         }
 
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -EINVAL;
         }
 
         de = list_entry(inode->i_dentry.next, struct dentry, d_alias);
 
+        if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
+                EXIT;
+                return 0;
+        }
+
         fset = presto_fset(de);
         if ( !fset ) {
-                printk("Presto: no fileset in presto_get_permit!\n");
+                CERROR("Presto: no fileset in presto_get_permit!\n");
                 EXIT;
                 return -EINVAL;
         }
 
+        if (fset->fset_flags & FSET_HAS_BRANCHES) {
+                EXIT;
+                return -EROFS;
+        }
+
+        spin_lock(&fset->fset_permit_lock);
         if (fset->fset_flags & FSET_HASPERMIT) {
-                lock_kernel();
                 fset->fset_permit_count++;
                 CDEBUG(D_INODE, "permit count now %d, inode %lx\n", 
                        fset->fset_permit_count, inode->i_ino);
-                unlock_kernel();
+                spin_unlock(&fset->fset_permit_lock);
                 EXIT;
                 return 0;
+        }
+
+        /* Allow reintegration to proceed without locks -SHP */
+        fset->fset_permit_upcall_count++;
+        if (fset->fset_permit_upcall_count == 1) {
+                spin_unlock(&fset->fset_permit_lock);
+                rc = presto_permit_upcall(fset->fset_dentry);
+                spin_lock(&fset->fset_permit_lock);
+                fset->fset_permit_upcall_count--;
+                if (rc == 0) {
+                        izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
+                                      NULL);
+                        fset->fset_permit_count++;
+                } else if (rc == ENOTCONN) {
+                        CERROR("InterMezzo: disconnected operation. stealing permit.\n");
+                        izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
+                                      NULL);
+                        fset->fset_permit_count++;
+                        /* set a disconnected flag here to stop upcalls */
+                        rc = 0;
+                } else {
+                        CERROR("InterMezzo: presto_permit_upcall failed: %d\n", rc);
+                        rc = -EROFS;
+                        /* go to sleep here and try again? */
+                }
+                wake_up_interruptible(&fset->fset_permit_queue);
         } else {
-		/* Allow reintegration to proceed without locks -SHP */
-                rc = presto_permit_upcall(fset->fset_mtpt);
-                lock_kernel();
-                if ( !rc ) { 
-                	presto_mark_fset_dentry
-				(fset->fset_mtpt, ~0, FSET_HASPERMIT, NULL);
-                	fset->fset_permit_count++;
+                /* Someone is already doing an upcall; go to sleep. */
+                DECLARE_WAITQUEUE(wait, current);
+
+                spin_unlock(&fset->fset_permit_lock);
+                add_wait_queue(&fset->fset_permit_queue, &wait);
+                while (1) {
+                        set_current_state(TASK_INTERRUPTIBLE);
+
+                        spin_lock(&fset->fset_permit_lock);
+                        if (fset->fset_permit_upcall_count == 0)
+                                break;
+                        spin_unlock(&fset->fset_permit_lock);
+
+                        if (signal_pending(current)) {
+                                remove_wait_queue(&fset->fset_permit_queue,
+                                                  &wait);
+                                return -ERESTARTSYS;
+                        }
+                        schedule();
                 }
-                CDEBUG(D_INODE, "permit count now %d, ino %lx (likely 1), rc %d\n", 
-        		fset->fset_permit_count, inode->i_ino, rc);
-                unlock_kernel();
-                EXIT;
-                return rc;
+                remove_wait_queue(&fset->fset_permit_queue, &wait);
+                /* We've been woken up: do we have the permit? */
+                if (fset->fset_flags & FSET_HASPERMIT)
+                        /* FIXME: Is this the right thing? */
+                        rc = -EAGAIN;
         }
+
+        CDEBUG(D_INODE, "permit count now %d, ino %ld (likely 1), "
+               "rc %d\n", fset->fset_permit_count, inode->i_ino, rc);
+        spin_unlock(&fset->fset_permit_lock);
+        EXIT;
+        return rc;
 }
 
 int presto_put_permit(struct inode * inode)
@@ -681,11 +573,11 @@
 
         if ( ISLENTO(minor) ) {
                 EXIT;
-                return -1;
+                return 0;
         }
 
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -1;
         }
@@ -694,437 +586,143 @@
 
         fset = presto_fset(de);
         if ( !fset ) {
-                printk("Presto: no fileset in presto_get_permit!\n");
+                CERROR("InterMezzo: no fileset in %s!\n", __FUNCTION__);
                 EXIT;
                 return -1;
         }
 
-        lock_kernel();
+        if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
+                EXIT;
+                return 0;
+        }
+
+        spin_lock(&fset->fset_permit_lock);
         if (fset->fset_flags & FSET_HASPERMIT) {
-                if (fset->fset_permit_count > 0) fset->fset_permit_count--;
-                else printk("Put permit while permit count is 0, inode %lx!\n",
-                                inode->i_ino); 
+                if (fset->fset_permit_count > 0)
+                        fset->fset_permit_count--;
+                else
+                        CERROR("Put permit while permit count is 0, "
+                               "inode %ld!\n", inode->i_ino); 
         } else {
-        	fset->fset_permit_count=0;
-        	printk("Put permit while no permit, inode %lx, flags %x!\n", 
-               		inode->i_ino, fset->fset_flags);
+                fset->fset_permit_count = 0;
+                CERROR("InterMezzo: put permit while no permit, inode %ld, "
+                       "flags %x!\n", inode->i_ino, fset->fset_flags);
         }
 
-        CDEBUG(D_INODE, "permit count now %d, inode %lx\n", 
-        		fset->fset_permit_count, inode->i_ino);
+        CDEBUG(D_INODE, "permit count now %d, inode %ld\n",
+               fset->fset_permit_count, inode->i_ino);
 
         if (fset->fset_flags & FSET_PERMIT_WAITING &&
-                    fset->fset_permit_count == 0) {
-                CDEBUG(D_INODE, "permit count now 0, ino %lx, notify Lento\n", 
+            fset->fset_permit_count == 0) {
+                CDEBUG(D_INODE, "permit count now 0, ino %ld, wake sleepers\n",
                        inode->i_ino);
-                presto_mark_fset_dentry(fset->fset_mtpt, ~FSET_PERMIT_WAITING, 0, NULL);
-                presto_mark_fset_dentry(fset->fset_mtpt, ~FSET_HASPERMIT, 0, NULL);
-                lento_release_permit(fset->fset_cache->cache_psdev->uc_minor,
-                                     fset->fset_permit_cookie);
-                fset->fset_permit_cookie = 0; 
+                wake_up_interruptible(&fset->fset_permit_queue);
         }
-        unlock_kernel();
+        spin_unlock(&fset->fset_permit_lock);
 
         EXIT;
         return 0;
 }
 
-
 void presto_getversion(struct presto_version * presto_version,
                        struct inode * inode)
 {
-        presto_version->pv_mtime = cpu_to_le64((__u64)inode->i_mtime);
-        presto_version->pv_ctime = cpu_to_le64((__u64)inode->i_ctime);
-        presto_version->pv_size = cpu_to_le64((__u64)inode->i_size);
+        presto_version->pv_mtime = (__u64)inode->i_mtime;
+        presto_version->pv_ctime = (__u64)inode->i_ctime;
+        presto_version->pv_size  = (__u64)inode->i_size;
 }
 
-/*
- *  note: this routine "pins" a dentry for a fileset root
+
+/* If uuid is non-null, it is the uuid of the peer that's making the revocation
+ * request.  If it is null, this request was made locally, without external
+ * pressure to give up the permit.  This most often occurs when a client
+ * starts up.
+ *
+ * FIXME: this function needs to be refactored slightly once we start handling
+ * multiple clients.
  */
-int presto_set_fsetroot(char *path, char *fsetname, unsigned int fsetid,
-                        unsigned int flags)
+int izo_revoke_permit(struct dentry *dentry, __u8 uuid[16])
 {
-        struct presto_file_set *fset;
-        struct presto_file_set *fset2;
-        struct dentry *dentry;
-        struct presto_cache *cache;
-        int error;
+        struct presto_file_set *fset; 
+        DECLARE_WAITQUEUE(wait, current);
+        int minor, rc;
 
         ENTRY;
 
-        PRESTO_ALLOC(fset, struct presto_file_set *, sizeof(*fset));
-        error = -ENOMEM;
-        if ( !fset ) {
-                printk(KERN_ERR "No memory allocating fset for %s\n", fsetname);
-                EXIT;
-                return -ENOMEM;
-        }
-        CDEBUG(D_INODE, "fset at %p\n", fset);
-
-        printk("presto: fsetroot: path %s, fileset name %s\n", path, fsetname);
-        error = presto_walk(path, &fset->fset_nd);
-        CDEBUG(D_INODE, "\n");
-        if (error) {
-                EXIT;
-                goto out_free;
-        }
-        dentry = fset->fset_nd.dentry;
-        CDEBUG(D_INODE, "\n");
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_dput;
-        }
-
-        CDEBUG(D_INODE, "\n");
-        cache = presto_get_cache(dentry->d_inode);
-        if (!cache) {
-                printk(KERN_ERR "No cache found for %s\n", path);
+        minor = presto_i2m(dentry->d_inode);
+        if (minor < 0) {
                 EXIT;
-                goto out_dput;
+                return -ENODEV;
         }
 
-        CDEBUG(D_INODE, "\n");
-        error = -EINVAL;
-        if ( !cache->cache_mtpt) {
-                printk(KERN_ERR "Presto - no mountpoint: fsetroot fails!\n");
+        fset = presto_fset(dentry);
+        if (fset == NULL) {
                 EXIT;
-                goto out_dput;
+                return -ENODEV;
         }
-        CDEBUG(D_INODE, "\n");
 
-        if (!cache->cache_root_fileset)  {
-                printk(KERN_ERR "Presto - no file set: fsetroot fails!\n");
+        spin_lock(&fset->fset_permit_lock);
+        if (fset->fset_flags & FSET_PERMIT_WAITING) {
+                CERROR("InterMezzo: Two processes are waiting on the same permit--this not yet supported!  Aborting this particular permit request...\n");
                 EXIT;
-                goto out_dput;
+                spin_unlock(&fset->fset_permit_lock);
+                return -EINVAL;
         }
 
-        error = -EEXIST;
-        CDEBUG(D_INODE, "\n");
+        if (fset->fset_permit_count == 0)
+                goto got_permit;
 
-        fset2 = presto_fset(dentry);
-        if (fset2 && (fset2->fset_mtpt == dentry) ) { 
-                printk(KERN_ERR "Fsetroot already set (path %s)\n", path);
+        /* Something is still using this permit.  Mark that we're waiting for it
+         * and go to sleep. */
+        rc = izo_mark_fset(dentry, ~0, FSET_PERMIT_WAITING, NULL);
+        spin_unlock(&fset->fset_permit_lock);
+        if (rc < 0) {
                 EXIT;
-                goto out_dput;
+                return rc;
         }
 
-        fset->fset_cache = cache;
-        fset->fset_mtpt = dentry;
-        fset->fset_name = fsetname;
-        fset->fset_chunkbits = CHUNK_BITS;
-        fset->fset_flags = flags;
-	fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; 
-
-        presto_d2d(dentry)->dd_fset = fset;
-        list_add(&fset->fset_list, &cache->cache_fset_list);
-
-        error = presto_init_kml_file(fset);
-        if ( error ) {
-                EXIT;
-                CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
-                goto out_list_del;
-        }
+        add_wait_queue(&fset->fset_permit_queue, &wait);
+        while (1) {
+                set_current_state(TASK_INTERRUPTIBLE);
+
+                spin_lock(&fset->fset_permit_lock);
+                if (fset->fset_permit_count == 0)
+                        break;
+                spin_unlock(&fset->fset_permit_lock);
+
+                if (signal_pending(current)) {
+                        /* FIXME: there must be a better thing to return... */
+                        remove_wait_queue(&fset->fset_permit_queue, &wait);
+                        EXIT;
+                        return -ERESTARTSYS;
+                }
 
-        error = presto_init_last_rcvd_file(fset);
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
-                goto out_list_del;
-        }
+                /* FIXME: maybe there should be a timeout here. */
 
-        error = presto_init_lml_file(fset);
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
-                goto out_list_del;
+                schedule();
         }
 
-#ifdef  CONFIG_KREINT
-        /* initialize kml reint buffer */
-        error = kml_init (fset); 
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init kml reint %d, cleanup %d\n", 
-                                error, rc);
-                goto out_list_del;
-        }
-#endif
-        if ( dentry->d_inode == dentry->d_inode->i_sb->s_root->d_inode) {
-                cache->cache_flags |= CACHE_FSETROOT_SET;
+        remove_wait_queue(&fset->fset_permit_queue, &wait);
+ got_permit:
+        /* By this point fset->fset_permit_count is zero and we're holding the
+         * lock. */
+        CDEBUG(D_CACHE, "InterMezzo: releasing permit inode %ld\n",
+               dentry->d_inode->i_ino);
+
+        if (uuid != NULL) {
+                rc = izo_upc_revoke_permit(minor, fset->fset_name, uuid);
+                if (rc < 0) {
+                        spin_unlock(&fset->fset_permit_lock);
+                        EXIT;
+                        return rc;
+                }
         }
 
-        CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p, fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n",
-               fset, dentry, fset->fset_mtpt, fset->fset_name, cache, presto_d2d(dentry)->dd_fset);
-
+        izo_mark_fset(fset->fset_dentry, ~FSET_PERMIT_WAITING, 0, NULL);
+        izo_mark_fset(fset->fset_dentry, ~FSET_HASPERMIT, 0, NULL);
+        spin_unlock(&fset->fset_permit_lock);
         EXIT;
         return 0;
-
- out_list_del:
-        list_del(&fset->fset_list);
-        presto_d2d(dentry)->dd_fset = NULL;
- out_dput:
-        path_release(&fset->fset_nd); 
- out_free:
-        PRESTO_FREE(fset, sizeof(*fset));
-        return error;
-}
-
-int presto_get_kmlsize(char *path, size_t *size)
-{
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        int error;
-
-        ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto kml_out;
-        }
-
-        error = -EINVAL;
-        if ( ! presto_dentry2fset(dentry)) {
-                EXIT;
-                goto kml_out;
-        }
-
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
-                EXIT;
-                goto kml_out;
-        }
-        error = 0;
-        *size = fset->fset_kml.fd_offset;
-
- kml_out:
-        path_release(&nd);
-        return error;
-}
-
-static void presto_cleanup_fset(struct presto_file_set *fset)
-{
-	int error;
-	struct presto_cache *cache;
-
-	ENTRY;
-#ifdef  CONFIG_KREINT
-        error = kml_cleanup (fset);
-        if ( error ) {
-                printk("InterMezzo: Closing kml for fset %s: %d\n",
-                       fset->fset_name, error);
-        }
-#endif
-
-        error = presto_close_journal_file(fset);
-        if ( error ) {
-                printk("InterMezzo: Closing journal for fset %s: %d\n",
-                       fset->fset_name, error);
-        }
-        cache = fset->fset_cache;
-        cache->cache_flags &= ~CACHE_FSETROOT_SET;
-
-        list_del(&fset->fset_list);
-
-	presto_d2d(fset->fset_mtpt)->dd_fset = NULL;
-        path_release(&fset->fset_nd);
-
-        fset->fset_mtpt = NULL;
-        PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
-        PRESTO_FREE(fset, sizeof(*fset));
-        EXIT;
-}
-
-int presto_clear_fsetroot(char *path)
-{
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        int error;
-
-        ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto put_out;
-        }
-
-        error = -EINVAL;
-        if ( ! presto_dentry2fset(dentry)) {
-                EXIT;
-                goto put_out;
-        }
-
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
-                EXIT;
-                goto put_out;
-        }
-
-	presto_cleanup_fset(fset);
-        EXIT;
-
-put_out:
-        path_release(&nd); /* for our lookup */
-        return error;
-}
-
-int presto_clear_all_fsetroots(char *path)
-{
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        struct presto_cache *cache;
-        int error;
-        struct list_head *tmp,*tmpnext;
-
-
-        ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto put_out;
-        }
-
-        error = -EINVAL;
-        if ( ! presto_dentry2fset(dentry)) {
-                EXIT;
-                goto put_out;
-        }
-
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
-                EXIT;
-                goto put_out;
-        }
-
-	error = 0;
-        cache = fset->fset_cache;
-        cache->cache_flags &= ~CACHE_FSETROOT_SET;
-
-        tmp = &cache->cache_fset_list;
-        tmpnext = tmp->next;
-        while ( tmpnext != &cache->cache_fset_list) {
-		tmp = tmpnext;
-                tmpnext = tmp->next;
-                fset = list_entry(tmp, struct presto_file_set, fset_list);
-
-		presto_cleanup_fset(fset);
-        }
-
-        EXIT;
- put_out:
-        path_release(&nd); /* for our lookup */
-        return error;
-}
-
-
-int presto_get_lastrecno(char *path, off_t *recno)
-{
-        struct nameidata nd; 
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        int error;
-        ENTRY;
-
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto kml_out;
-        }
-
-        error = -EINVAL;
-        if ( ! presto_dentry2fset(dentry)) {
-                EXIT;
-                goto kml_out;
-        }
-
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
-                EXIT;
-                goto kml_out;
-        }
-        error = 0;
-        *recno = fset->fset_kml.fd_recno;
-
- kml_out:
-        path_release(&nd);
-        return error;
-}
-
-/* 
-   if *cookie != 0, lento must wait for this cookie
-   before releasing the permit, operations are in progress. 
-*/ 
-int presto_permit_downcall( const char * path, int *cookie )
-{
-        int result;
-        struct presto_file_set *fset; 
-
-        fset = presto_path2fileset(path);
-        if (IS_ERR(fset)) { 
-                EXIT;
-                return PTR_ERR(fset);
-        }
-
-	lock_kernel();
-        if (fset->fset_permit_count != 0) {
-                /* is there are previous cookie? */
-                if (fset->fset_permit_cookie == 0) {
-                        CDEBUG(D_CACHE, "presto installing cookie 0x%x, %s\n",
-                               *cookie, path);
-                        fset->fset_permit_cookie = *cookie;
-                } else {
-                        *cookie = fset->fset_permit_cookie;
-                        CDEBUG(D_CACHE, "presto has cookie 0x%x, %s\n",
-                               *cookie, path);
-                }
-                result = presto_mark_fset(path, 0, FSET_PERMIT_WAITING, NULL);
-        } else {
-                *cookie = 0;
-                CDEBUG(D_CACHE, "presto releasing permit %s\n", path);
-                result = presto_mark_fset(path, ~FSET_HASPERMIT, 0, NULL);
-        }
-	unlock_kernel();
-
-        return result;
 }
 
 inline int presto_is_read_only(struct presto_file_set * fset)
@@ -1139,4 +737,3 @@
         mask= (ISLENTO(minor)? CACHE_LENTO_RO : CACHE_CLIENT_RO);
         return  ((cache->cache_flags & mask)? 1 : 0);
 }
-
diff -Nru a/fs/intermezzo/psdev.c b/fs/intermezzo/psdev.c
--- a/fs/intermezzo/psdev.c	Tue Oct 15 20:29:16 2002
+++ b/fs/intermezzo/psdev.c	Tue Oct 15 20:29:16 2002
@@ -1,4 +1,6 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
  *              An implementation of a loadable kernel mode driver providing
  *              multiple kernel/user space bidirectional communications links.
  *
@@ -6,8 +8,7 @@
  *
  *              This program is free software; you can redistribute it and/or
  *              modify it under the terms of the GNU General Public License
- *              as published by the Free Software Foundation; either version
- *              2 of the License, or (at your option) any later version.
+ *              version 2 as published by the Free Software Foundation.
  *
  *              Adapted to become the Linux 2.0 Coda pseudo device
  *              Peter  Braam  <braam@maths.ox.ac.uk>
@@ -22,20 +23,15 @@
  *              Copyright (c) 2000 Tacitus Systems, Inc.
  *              Copyright (c) 2001 Cluster File Systems, Inc.
  *
- *		Extended attribute support
- *		Copyright (c) 2001 Shirish. H. Phatak
- *		Copyright (c) 2001 Tacit Networks, Inc.
  */
 
-
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/lp.h>
 #include <linux/slab.h>
-#include <asm/ioctls.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
 #include <linux/delay.h>
@@ -43,20 +39,20 @@
 #include <linux/proc_fs.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
-#include <linux/tty.h>
+#include <linux/file.h>
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/devfs_fs_kernel.h>
 #include <asm/io.h>
+#include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/poll.h>
 #include <asm/uaccess.h>
-#include <asm/ioctls.h>
+#include <linux/miscdevice.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 
 #ifdef PRESTO_DEVEL
@@ -68,121 +64,178 @@
 #endif
 
 /* Like inode.c (presto_sym_iops), the initializer is just to prevent
-   upc_comms from appearing as a COMMON symbol (and therefore
-   interfering with other modules that use the same variable name. */
-struct upc_comm upc_comms[MAX_PRESTODEV] = {{0}};
+   izo_channels from appearing as a COMMON symbol (and therefore
+   interfering with other modules that use the same variable name). */
+struct upc_channel izo_channels[MAX_CHANNEL] = {{0}};
 
-/*
- * Device operations: map file to upcall structure
- */
-static inline struct upc_comm *presto_psdev_f2u(struct file *file)
+int izo_psdev_get_free_channel(void)
 {
-        int minor;
+        int i, result = -1;
+        
+        for (i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                if (list_empty(&(izo_channels[i].uc_cache_list))) { 
+                    result = i;
+                    break;
+                }
+        }
+        return result;
+}
 
-        if ( major(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {
-                EXIT;
-                return NULL;
+
+int izo_psdev_setpid(int minor)
+{
+        struct upc_channel *channel; 
+        if (minor < 0 || minor >= MAX_CHANNEL) { 
+                return -EINVAL;
         }
 
-        minor = minor(file->f_dentry->d_inode->i_rdev);
-        if ( minor < 0 || minor >= MAX_PRESTODEV ) {
-                EXIT;
-                return NULL;
+        channel = &(izo_channels[minor]); 
+        /*
+         * This ioctl is performed by each Lento that starts up
+         * and wants to do further communication with presto.
+         */
+        CDEBUG(D_PSDEV, "Setting current pid to %d channel %d\n", 
+               current->pid, minor);
+        channel->uc_pid = current->pid;
+        spin_lock(&channel->uc_lock); 
+        if ( !list_empty(&channel->uc_processing) ) {
+                struct list_head *lh;
+                struct upc_req *req;
+                CERROR("WARNING: setpid & processing not empty!\n");
+                lh = &channel->uc_processing;
+                while ( (lh = lh->next) != &channel->uc_processing) {
+                        req = list_entry(lh, struct upc_req, rq_chain);
+                        /* freeing of req and data is done by the sleeper */
+                        wake_up(&req->rq_sleep);
+                }
+        }
+        if ( !list_empty(&channel->uc_processing) ) {
+                CERROR("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");
+        }
+        spin_unlock(&channel->uc_lock); 
+        EXIT;
+        return 0;
+}
+
+int izo_psdev_setchannel(struct file *file, int fd)
+{
+
+        struct file *psdev_file = fget(fd); 
+        struct presto_cache *cache = presto_get_cache(file->f_dentry->d_inode);
+
+        if (!psdev_file) { 
+                CERROR("%s: no psdev_file!\n", __FUNCTION__);
+                return -EINVAL;
         }
 
-        return &(upc_comms[minor]);
+        if (!cache) { 
+                CERROR("%s: no cache!\n", __FUNCTION__);
+                fput(psdev_file); 
+                return -EINVAL;
+        } 
+
+        if (psdev_file->private_data) { 
+                CERROR("%s: channel already set!\n", __FUNCTION__);
+                fput(psdev_file); 
+                return -EINVAL;
+        }
+
+        psdev_file->private_data = cache->cache_psdev;
+        fput(psdev_file); 
+        EXIT; 
+        return 0; 
 }
 
 inline int presto_lento_up(int minor) 
 {
-        return upc_comms[minor].uc_pid;
+        return izo_channels[minor].uc_pid;
 }
 
-
 static unsigned int presto_psdev_poll(struct file *file, poll_table * wait)
-{
-        struct upc_comm *upccom;
+ {
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         unsigned int mask = POLLOUT | POLLWRNORM;
-        /* ENTRY; this will flood you */
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        /* ENTRY; this will flood you */
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
-        poll_wait(file, &(upccom->uc_waitq), wait);
+        poll_wait(file, &(channel->uc_waitq), wait);
 
-        if (!list_empty(&upccom->uc_pending)) {
+        spin_lock(&channel->uc_lock);
+        if (!list_empty(&channel->uc_pending)) {
                 CDEBUG(D_PSDEV, "Non-empty pending list.\n");
                 mask |= POLLIN | POLLRDNORM;
         }
+        spin_unlock(&channel->uc_lock);
 
         /* EXIT; will flood you */
         return mask;
 }
 
-
-
 /*
  *      Receive a message written by Lento to the psdev
  */
 static ssize_t presto_psdev_write(struct file *file, const char *buf,
                                   size_t count, loff_t *off)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req = NULL;
         struct upc_req *tmp;
         struct list_head *lh;
-        struct lento_down_hdr hdr;
+        struct izo_upcall_resp hdr;
         int error;
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
         /* Peek at the opcode, uniquefier */
         if ( count < sizeof(hdr) ) {
-              printk("presto_psdev_write: Lento didn't write full hdr.\n");
+              CERROR("presto_psdev_write: Lento didn't write full hdr.\n");
                 return -EINVAL;
         }
 
-        if (copy_from_user(&hdr, buf, sizeof(hdr)))
+        error = copy_from_user(&hdr, buf, sizeof(hdr));
+        if ( error )
                 return -EFAULT;
 
         CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%d,%d)\n",
                current->pid, hdr.opcode, hdr.unique);
 
+        spin_lock(&channel->uc_lock); 
         /* Look for the message on the processing queue. */
-        lh  = &upccom->uc_processing;
-        while ( (lh = lh->next) != &upccom->uc_processing ) {
+        lh  = &channel->uc_processing;
+        while ( (lh = lh->next) != &channel->uc_processing ) {
                 tmp = list_entry(lh, struct upc_req , rq_chain);
                 if (tmp->rq_unique == hdr.unique) {
                         req = tmp;
-                      /* unlink here: keeps search length minimal */
-                        list_del(&req->rq_chain);
-                      INIT_LIST_HEAD(&req->rq_chain);
+                        /* unlink here: keeps search length minimal */
+                        list_del_init(&req->rq_chain);
                         CDEBUG(D_PSDEV,"Eureka opc %d uniq %d!\n",
                                hdr.opcode, hdr.unique);
                         break;
                 }
         }
+        spin_unlock(&channel->uc_lock); 
         if (!req) {
-                printk("psdev_write: msg (%d, %d) not found\n",
+                CERROR("psdev_write: msg (%d, %d) not found\n",
                        hdr.opcode, hdr.unique);
                 return(-ESRCH);
         }
 
         /* move data into response buffer. */
         if (req->rq_bufsize < count) {
-                printk("psdev_write: too much cnt: %d, cnt: %Zd, "
+                CERROR("psdev_write: too much cnt: %d, cnt: %d, "
                        "opc: %d, uniq: %d.\n",
                        req->rq_bufsize, count, hdr.opcode, hdr.unique);
                 count = req->rq_bufsize; /* don't have more space! */
         }
-        if (copy_from_user(req->rq_data, buf, count))
+        error = copy_from_user(req->rq_data, buf, count);
+        if ( error )
                 return -EFAULT;
 
         /* adjust outsize: good upcalls can be aware of this */
@@ -199,40 +252,43 @@
 static ssize_t presto_psdev_read(struct file * file, char * buf,
                                  size_t count, loff_t *off)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req;
         int result = count;
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
-        CDEBUG(D_PSDEV, "count %Zd\n", count);
-        if (list_empty(&(upccom->uc_pending))) {
+        spin_lock(&channel->uc_lock); 
+        if (list_empty(&(channel->uc_pending))) {
                 CDEBUG(D_UPCALL, "Empty pending list in read, not good\n");
+                spin_unlock(&channel->uc_lock); 
                 return -EINVAL;
         }
-
-        req = list_entry((upccom->uc_pending.next), struct upc_req, rq_chain);
+        req = list_entry((channel->uc_pending.next), struct upc_req, rq_chain);
         list_del(&(req->rq_chain));
-      if (! (req->rq_flags & REQ_ASYNC) ) {
-              list_add(&(req->rq_chain), upccom->uc_processing.prev);
-      }
-      req->rq_flags |= REQ_READ;
+        if (! (req->rq_flags & REQ_ASYNC) ) {
+                list_add(&(req->rq_chain), channel->uc_processing.prev);
+        }
+        spin_unlock(&channel->uc_lock); 
+
+        req->rq_flags |= REQ_READ;
 
         /* Move the input args into userspace */
+        CDEBUG(D_PSDEV, "\n");
         if (req->rq_bufsize <= count) {
                 result = req->rq_bufsize;
         }
 
         if (count < req->rq_bufsize) {
-                printk ("psdev_read: buffer too small, read %Zd of %d bytes\n",
+                CERROR ("psdev_read: buffer too small, read %d of %d bytes\n",
                         count, req->rq_bufsize);
         }
 
         if ( copy_to_user(buf, req->rq_data, result) ) {
+                BUG();
                 return -EFAULT;
         }
 
@@ -248,999 +304,16 @@
         return result;
 }
 
-static int presto_psdev_ioctl(struct inode *inode, struct file *file,
-                              unsigned int cmd, unsigned long arg)
-{
-        struct upc_comm *upccom;
-        /* XXX is this rdev or dev? */
-        kdev_t dev = inode->i_rdev;
-
-        ENTRY;
-        upccom = presto_psdev_f2u(file);
-        if ( !upccom) {
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
-                EXIT;
-                return -ENODEV;
-        }
-
-        switch(cmd) {
-
-        case TCGETS:
-                return -EINVAL;
-
-        case PRESTO_GETMOUNT: {
-                /* return all the mounts for this device.  */
-                int minor = 0;
-                int len, outlen;
-                struct readmount readmount;
-                struct readmount *user_readmount = (struct readmount *) arg;
-                char * tmp;
-                int error;
-
-                if (copy_from_user(&readmount, (void *)arg, sizeof(readmount)))
-                        printk("psdev: can't copy %Zd bytes from %p to %p\n",
-                                sizeof(readmount), (struct readmount *) arg,
-                                &readmount);
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                len = readmount.io_len;
-                minor = minor(dev);
-                PRESTO_ALLOC(tmp, char *, len);
-                if (!tmp) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-
-                outlen = presto_sprint_mounts(tmp, len, minor);
-                CDEBUG(D_PSDEV, "presto_sprint_mounts returns %d bytes\n",
-                                outlen);
-
-                /* as this came out on 1/3/2000, it could NEVER work.
-                 * So fix it ... RGM
-                 * I mean, let's let the compiler do a little work ...
-                 * gcc suggested the extra ()
-                 */
-                if (copy_to_user(readmount.io_string, tmp, outlen)) {
-                        CDEBUG(D_PSDEV, "Copy_to_user string 0x%p failed\n",
-                               readmount.io_string);
-			error = -EFAULT;
-                }
-                if (!error && copy_to_user(&(user_readmount->io_len),
-                                           &outlen, sizeof(int))) {
-                        CDEBUG(D_PSDEV, "Copy_to_user len @0x%p failed\n",
-                               &(user_readmount->io_len));
-			error = -EFAULT;
-                }
-
-                PRESTO_FREE(tmp, len);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_SETPID: {
-                /*
-                 * This ioctl is performed by each Lento that starts up
-                 * and wants to do further communication with presto.
-                 */
-                CDEBUG(D_PSDEV, "Setting current pid to %d\n", current->pid);
-                upccom->uc_pid = current->pid;
-                if ( !list_empty(&upccom->uc_processing) ) {
-                        struct list_head *lh;
-                        struct upc_req *req;
-                        printk("WARNING: setpid & processing not empty!\n");
-                        lh = &upccom->uc_processing;
-                        while ( (lh = lh->next) != &upccom->uc_processing) {
-                                req = list_entry(lh, struct upc_req, rq_chain);
-                                /* freeing of req and data is done by the sleeper */
-                                wake_up(&req->rq_sleep);
-                        }
-                }
-                if ( !list_empty(&upccom->uc_processing) ) {
-                        printk("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");
-                }
-                EXIT;
-                return 0;
-        }
-
-        case PRESTO_CLEAR_FSETROOT: {
-                /*
-                 * Close KML files.
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                struct {
-                        char *path;
-                        int   path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "clear_fsetroot: path %s\n", path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_clear_fsetroot(path);
-                upccom->uc_pid = saved_pid;
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return error;
-        }
-
-
-        case PRESTO_CLEAR_ALL_FSETROOTS: {
-                /*
-                 * Close KML files.
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                struct {
-                        char *path;
-                        int   path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "clear_all_fsetroot: path %s\n", path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_clear_all_fsetroots(path);
-                upccom->uc_pid = saved_pid;
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_GET_KMLSIZE: {
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                size_t size = 0;
-                struct {
-                        __u64 size;
-                        char *path;
-                        int   path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "get_kmlsize: len %d path %s\n", 
-                       input.path_len, path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_get_kmlsize(path, &size);
-                PRESTO_FREE(path, input.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                input.size = size;
-                upccom->uc_pid = saved_pid;
-
-                CDEBUG(D_PSDEV, "get_kmlsize: size = %Zd\n", size);
-
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_GET_RECNO: {
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                off_t recno = 0;
-                struct {
-                        __u64 recno;
-                        char *path;
-                        int   path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "get_recno: len %d path %s\n", 
-                       input.path_len, path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_get_lastrecno(path, &recno);
-                PRESTO_FREE(path, input.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                input.recno = recno;
-                upccom->uc_pid = saved_pid;
-
-                CDEBUG(D_PSDEV, "get_recno: recno = %d\n", (int) recno);
-
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_SET_FSETROOT: {
-                /*
-                 * Save information about the cache, and initialize "special"
-                 * cache files (KML, etc).
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *fsetname;
-                char *path;
-                struct {
-                        char *path;
-                        int   path_len;
-                        char *name;
-                        int   name_len;
-                        int   id;
-                        int   flags;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        EXIT;
-			error -EFAULT;
-                        goto exit_free_path;
-                }
-                path[input.path_len] = '\0';
-
-                PRESTO_ALLOC(fsetname, char *, input.name_len + 1);
-                if ( !fsetname ) {
-                        error = -ENOMEM;
-                        EXIT;
-                        goto exit_free_path;
-                }
-                if (copy_from_user(fsetname, input.name, input.name_len)) {
-                        EXIT;
-			error = -EFAULT;
-                        goto exit_free_fsetname;
-                }
-                fsetname[input.name_len] = '\0';
-
-                CDEBUG(D_PSDEV,
-                       "set_fsetroot: path %s name %s, id %d, flags %x\n",
-                       path, fsetname, input.id, input.flags);
-                upccom->uc_pid = current->pid;
-                error = presto_set_fsetroot(path, fsetname, input.id,input.flags);
-                upccom->uc_pid = saved_pid;
-                if ( error ) {
-                        EXIT;
-                        goto exit_free_fsetname;
-                }
-                /* fsetname is kept in the fset, so don't free it now */
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return 0;
-
-        exit_free_fsetname:
-                PRESTO_FREE(fsetname, input.name_len + 1);
-        exit_free_path:
-                PRESTO_FREE(path, input.path_len + 1);
-                return error;
-        }
-
-        case PRESTO_CLOSE_JOURNALF: {
-                int saved_pid = upccom->uc_pid;
-                int error;
-
-                CDEBUG(D_SUPER, "HELLO\n");
-
-                /* pretend we are lento: we should lock something */
-                upccom->uc_pid = current->pid;
-                error = presto_close_journal_file(NULL);
-                CDEBUG(D_PSDEV, "error is %d\n", error);
-                upccom->uc_pid = saved_pid;
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_GETOPT:
-        case PRESTO_SETOPT: {
-                /* return all the mounts for this device.  */
-                int dosetopt(int, struct psdev_opt *);
-                int dogetopt(int, struct psdev_opt *);
-                int minor = 0;
-                struct psdev_opt kopt;
-                struct psdev_opt *user_opt = (struct psdev_opt *) arg;
-                int error;
-
-                if (copy_from_user(&kopt, (void *)arg, sizeof(kopt))) {
-                        printk("psdev: can't copyin %Zd bytes from %p to %p\n",
-                               sizeof(kopt), (struct kopt *) arg, &kopt);
-                        EXIT;
-                        return -EFAULT;
-                }
-                minor = minor(dev);
-                if (cmd == PRESTO_SETOPT)
-                        error = dosetopt(minor, &kopt);
-
-                if ( error ) {
-                        CDEBUG(D_PSDEV,
-                               "dosetopt failed minor %d, opt %d, val %d\n",
-                               minor, kopt.optname, kopt.optval);
-                        EXIT;
-                        return error;
-                }
-
-                error = dogetopt(minor, &kopt);
-
-                if ( error ) {
-                        CDEBUG(D_PSDEV,
-                               "dogetopt failed minor %d, opt %d, val %d\n",
-                               minor, kopt.optname, kopt.optval);
-                        EXIT;
-                        return error;
-                }
-
-                if (copy_to_user(user_opt, &kopt, sizeof(kopt))) {
-                        CDEBUG(D_PSDEV, "Copy_to_user opt 0x%p failed\n",
-                               user_opt);
-                        EXIT;
-                        return -EFAULT;
-                }
-                CDEBUG(D_PSDEV, "dosetopt minor %d, opt %d, val %d return %d\n",
-                         minor, kopt.optname, kopt.optval, error);
-                EXIT;
-                return 0;
-        }
-
-        case PRESTO_VFS_SETATTR: {
-                int error;
-                struct lento_input_attr input;
-                struct iattr iattr;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                iattr.ia_valid = input.valid;
-                iattr.ia_mode  = (umode_t)input.mode;
-                iattr.ia_uid   = (uid_t)input.uid;
-                iattr.ia_gid   = (gid_t)input.gid;
-                iattr.ia_size  = (off_t)input.size;
-                iattr.ia_atime = (time_t)input.atime;
-                iattr.ia_mtime = (time_t)input.mtime;
-                iattr.ia_ctime = (time_t)input.ctime;
-                iattr.ia_attr_flags = input.attr_flags;
-
-                error = lento_setattr(input.name, &iattr, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_CREATE: {
-                int error;
-                struct lento_input_mode input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_create(input.name, input.mode, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_LINK: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_link(input.oldname, input.newname, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_UNLINK: {
-                int error;
-                struct lento_input input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_unlink(input.name, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_SYMLINK: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_symlink(input.oldname, input.newname,&input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_MKDIR: {
-                int error;
-                struct lento_input_mode input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_mkdir(input.name, input.mode, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_RMDIR: {
-                int error;
-                struct lento_input input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_rmdir(input.name, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_MKNOD: {
-                int error;
-                struct lento_input_dev input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_mknod(input.name, input.mode,
-                                    mk_kdev(input.major,input.minor),&input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_RENAME: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_rename(input.oldname, input.newname, &input.info);
-                EXIT;
-                return error;
-        }
-
-#ifdef CONFIG_FS_EXT_ATTR
-        /* IOCTL to create/modify an extended attribute */
-        case PRESTO_VFS_SETEXTATTR: {
-                int error;
-                struct lento_input_ext_attr input;
-                char *name;
-                char *buffer;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                    EXIT;
-                    return -EFAULT;
-                }
-
-                /* Now setup the input parameters */
-                PRESTO_ALLOC(name, char *, input.name_len+1);
-                /* We need null terminated strings for attr names */
-                name[input.name_len] = '\0';
-                if (copy_from_user(name, input.name, input.name_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    return -EFAULT;
-                }
-
-                PRESTO_ALLOC(buffer, char *, input.buffer_len+1);
-                if (copy_from_user(buffer, input.buffer, input.buffer_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    PRESTO_FREE(buffer,input.buffer_len+1);
-                    return -EFAULT;
-                }
-                /* Make null terminated for easy printing */
-                buffer[input.buffer_len]='\0';
- 
-                CDEBUG(D_PSDEV," setextattr params: name %s, valuelen %d,"
-                       " value %s, attr flags %x, mode %o, slot offset %d,"
-                       " recno %d, kml offset %lu, flags %x, time %d\n", 
-                       name, input.buffer_len, buffer, input.flags, input.mode,
-                       input.info.slot_offset, input.info.recno,
-                       (unsigned long) input.info.kml_offset, input.info.flags,
-                       input.info.updated_time);
-
-                error=lento_set_ext_attr
-                      (input.path,name,buffer,input.buffer_len,
-                       input.flags, input.mode, &input.info);
-
-                PRESTO_FREE(name,input.name_len+1);
-                PRESTO_FREE(buffer,input.buffer_len+1);
-                EXIT;
-                return error;
-        }
-
-        /* IOCTL to delete an extended attribute */
-        case PRESTO_VFS_DELEXTATTR: {
-                int error;
-                struct lento_input_ext_attr input;
-                char *name;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                    EXIT;
-                    return -EFAULT;
-                }
-
-                /* Now setup the input parameters */
-                PRESTO_ALLOC(name, char *, input.name_len+1);
-                /* We need null terminated strings for attr names */
-                name[input.name_len] = '\0';
-                if (copy_from_user(name, input.name, input.name_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    return -EFAULT;
-                }
-
-                CDEBUG(D_PSDEV," delextattr params: name %s,"
-                       " attr flags %x, mode %o, slot offset %d, recno %d,"
-                       " kml offset %lu, flags %x, time %d\n", 
-                       name, input.flags, input.mode,
-                       input.info.slot_offset, input.info.recno,
-                       (unsigned long) input.info.kml_offset, input.info.flags,
-                       input.info.updated_time);
-
-                error=lento_set_ext_attr
-                      (input.path,name,NULL,0,input.flags,
-                       input.mode,&input.info);
-                PRESTO_FREE(name,input.name_len+1);
-                EXIT;
-                return error;
-        }
-#endif
-
-        case PRESTO_VFS_IOPEN: {
-                struct lento_input_iopen input;
-                int error;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                input.fd = lento_iopen(input.name, (ino_t)input.ino,
-                                       input.generation, input.flags);
-                CDEBUG(D_PIOCTL, "lento_iopen file descriptor: %d\n", input.fd);
-                if (input.fd < 0) {
-                        EXIT;
-                        return input.fd;
-                }
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_VFS_CLOSE: {
-                int error;
-                struct lento_input_close input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                CDEBUG(D_PIOCTL, "lento_close file descriptor: %d\n", input.fd);
-                error = lento_close(input.fd, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_BACKFETCH_LML: {
-                char *user_path;
-                int error;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                        __u64 remote_ino;
-                        __u32 remote_generation;
-                        __u32 remote_version;
-                        struct presto_version remote_file_version;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_write_lml(input.path, 
-                                       input.remote_ino, 
-                                       input.remote_generation,
-                                       input.remote_version,
-                                       &input.remote_file_version); 
-
-        }
-                
-
-        case PRESTO_CANCEL_LML: {
-                char *user_path;
-                int error;
-                struct lml_arg {
-                        char *path;
-                        __u64 lml_offset; 
-                        __u32 path_len;
-                        __u64 remote_ino;
-                        __u32 remote_generation;
-                        __u32 remote_version;
-                        struct lento_vfs_context info;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_cancel_lml(input.path, 
-                                        input.lml_offset, 
-                                        input.remote_ino, 
-                                        input.remote_generation,
-                                        input.remote_version,
-                                        &input.info); 
-
-        }
-
-        case PRESTO_COMPLETE_CLOSES: {
-                char *user_path;
-                int error;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                error = lento_complete_closes(input.path);
-                PRESTO_FREE(input.path, input.path_len + 1);
-                return error;
-        }
-
-        case PRESTO_RESET_FSET: {
-                char *user_path;
-                int error;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                        __u64 offset;
-                        __u32 recno;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_reset_fset(input.path, input.offset, input.recno); 
-
-        }
-                
-
-        case PRESTO_MARK: {
-                char *user_path;
-                int res = 0;  /* resulting flags - returned to user */
-                int error;
-                struct {
-                        int  mark_what;
-                        int  and_flag;
-                        int  or_flag;
-                        int path_len;
-                        char *path;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "mark name: %s, and: %x, or: %x, what %d\n",
-                       input.path, input.and_flag, input.or_flag, 
-                       input.mark_what);
-
-                switch (input.mark_what) {
-                case MARK_DENTRY:               
-                        error = presto_mark_dentry(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_FSET:
-                        error = presto_mark_fset(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_CACHE:
-                        error = presto_mark_cache(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_GETFL: {
-                        int fflags, cflags;
-                        input.and_flag = 0xffffffff;
-                        input.or_flag = 0; 
-                        error = presto_mark_dentry(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        if (error) 
-                                break;
-                        error = presto_mark_fset(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &fflags);
-                        if (error) 
-                                break;
-                        error = presto_mark_cache(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &cflags);
-
-                        if (error) 
-                                break;
-                        input.and_flag = fflags;
-                        input.or_flag = cflags;
-                	break;
-                }
-                default:
-                        error = -EINVAL;
-                }
-
-                PRESTO_FREE(input.path, input.path_len + 1);
-                if (error == -EBUSY) {
-                        input.and_flag = error;
-                        error = 0;
-                }
-                if (error) { 
-                        EXIT;
-                        return error;
-                }
-                /* return the correct cookie to wait for */
-                input.mark_what = res;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-#ifdef  CONFIG_KREINT
-        case PRESTO_REINT_BEGIN:
-                return begin_kml_reint (file, arg);
-        case PRESTO_DO_REINT:
-                return do_kml_reint (file, arg);
-        case PRESTO_REINT_END:
-                return end_kml_reint (file, arg);
-#endif
-
-        case PRESTO_RELEASE_PERMIT: {
-                int error;
-                char *user_path;
-                struct {
-                        int  cookie;
-                        int path_len;
-                        char *path;
-                } permit;
-                
-                if (copy_from_user(&permit, (char *)arg, sizeof(permit))) {
-                        EXIT;
-                        return -EFAULT;
-		}
-                user_path = permit.path;
-                
-                PRESTO_ALLOC(permit.path, char *, permit.path_len + 1);
-                if ( !permit.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(permit.path, user_path, permit.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(permit.path, permit.path_len + 1);
-                        return -EFAULT;
-                }
-                permit.path[permit.path_len] = '\0';
-                
-                CDEBUG(D_DOWNCALL, "release permit: %s, in cookie=%d\n",
-                       permit.path, permit.cookie);
-                error = presto_permit_downcall(permit.path, &permit.cookie);
-                
-                PRESTO_FREE(permit.path, permit.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                /* return the correct cookie to wait for */
-                if (copy_to_user((char *)arg, &permit, sizeof(permit)))
-			return -EFAULT;
-		return 0;
-        }
-        
-        default:
-                CDEBUG(D_PSDEV, "bad ioctl 0x%x, \n", cmd);
-                CDEBUG(D_PSDEV, "valid are 0x%Zx - 0x%Zx, 0x%Zx - 0x%Zx \n",
-                        PRESTO_GETMOUNT, PRESTO_GET_KMLSIZE,
-                        PRESTO_VFS_SETATTR, PRESTO_VFS_IOPEN);
-                EXIT;
-        }
-
-        return -EINVAL;
-}
-
 
 static int presto_psdev_open(struct inode * inode, struct file * file)
 {
-         struct upc_comm *upccom;
-         ENTRY;
+        ENTRY;
 
-         if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                 kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                 printk("InterMezzo: %s, bad device %s\n",
-                        __FUNCTION__, kdevname(dev));
-                 EXIT;
-                 return -EINVAL;
-         }
+        file->private_data = NULL;  
 
         MOD_INC_USE_COUNT;
 
-        CDEBUG(D_PSDEV, "Psdev_open: uc_pid: %d, caller: %d, flags: %d\n",
-               upccom->uc_pid, current->pid, file->f_flags);
+        CDEBUG(D_PSDEV, "Psdev_open: caller: %d, flags: %d\n", current->pid, file->f_flags);
 
         EXIT;
         return 0;
@@ -1250,32 +323,25 @@
 
 static int presto_psdev_release(struct inode * inode, struct file * file)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req;
         struct list_head *lh;
         ENTRY;
 
-
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
-        }
-
-        if ( upccom->uc_pid != current->pid ) {
-                printk("psdev_release: Not lento.\n");
-                MOD_DEC_USE_COUNT;
-                return 0;
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
         MOD_DEC_USE_COUNT;
         CDEBUG(D_PSDEV, "Lento: pid %d\n", current->pid);
-        upccom->uc_pid = 0;
+        channel->uc_pid = 0;
 
         /* Wake up clients so they can return. */
         CDEBUG(D_PSDEV, "Wake up clients sleeping for pending.\n");
-        lh = &upccom->uc_pending;
-        while ( (lh = lh->next) != &upccom->uc_pending) {
+        spin_lock(&channel->uc_lock); 
+        lh = &channel->uc_pending;
+        while ( (lh = lh->next) != &channel->uc_pending) {
                 req = list_entry(lh, struct upc_req, rq_chain);
 
                 /* Async requests stay around for a new lento */
@@ -1288,13 +354,14 @@
         }
 
         CDEBUG(D_PSDEV, "Wake up clients sleeping for processing\n");
-        lh = &upccom->uc_processing;
-        while ( (lh = lh->next) != &upccom->uc_processing) {
+        lh = &channel->uc_processing;
+        while ( (lh = lh->next) != &channel->uc_processing) {
                 req = list_entry(lh, struct upc_req, rq_chain);
                 /* freeing of req and data is done by the sleeper */
                 req->rq_flags |= REQ_DEAD; 
                 wake_up(&req->rq_sleep);
         }
+        spin_unlock(&channel->uc_lock); 
         CDEBUG(D_PSDEV, "Done.\n");
 
         EXIT;
@@ -1302,57 +369,46 @@
 }
 
 static struct file_operations presto_psdev_fops = {
-        read:    presto_psdev_read,
-        write:   presto_psdev_write,
-        poll:    presto_psdev_poll,
-        ioctl:   presto_psdev_ioctl,
-        open:    presto_psdev_open,
-        release: presto_psdev_release
+        .read    = presto_psdev_read,
+        .write   = presto_psdev_write,
+        .poll    = presto_psdev_poll,
+        .open    = presto_psdev_open,
+        .release = presto_psdev_release
 };
 
+/* modules setup */
+static struct miscdevice intermezzo_psdev = {
+        INTERMEZZO_MINOR,
+        "intermezzo",
+        &presto_psdev_fops
+};
 
 int  presto_psdev_init(void)
 {
         int i;
+        int err; 
 
-#ifdef PRESTO_DEVEL
-        if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel",
-                           &presto_psdev_fops)) {
-                printk(KERN_ERR "presto_psdev: unable to get major %d\n",
-                       PRESTO_PSDEV_MAJOR);
+        if ( (err = misc_register(&intermezzo_psdev)) ) { 
+                CERROR("%s: cannot register %d err %d\n", 
+                       __FUNCTION__, INTERMEZZO_MINOR, err);
                 return -EIO;
         }
-#else
-        if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev",
-                           &presto_psdev_fops)) {
-                printk("presto_psdev: unable to get major %d\n",
-                       PRESTO_PSDEV_MAJOR);
-                return -EIO;
-        }
-#endif
 
-        memset(&upc_comms, 0, sizeof(upc_comms));
-        for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) {
-                char *name;
-                struct upc_comm *psdev = &upc_comms[i];
-                INIT_LIST_HEAD(&psdev->uc_pending);
-                INIT_LIST_HEAD(&psdev->uc_processing);
-                INIT_LIST_HEAD(&psdev->uc_cache_list);
-                init_waitqueue_head(&psdev->uc_waitq);
-                psdev->uc_hard = 0;
-                psdev->uc_no_filter = 0;
-                psdev->uc_no_journal = 0;
-                psdev->uc_no_upcall = 0;
-                psdev->uc_timeout = 30;
-                psdev->uc_errorval = 0;
-                psdev->uc_minor = i;
-                PRESTO_ALLOC(name, char *, strlen(PRESTO_PSDEV_NAME "256")+1);
-                if (!name) { 
-                        printk("Unable to allocate memory for device name\n");
-                        continue;
-                }
-                sprintf(name, PRESTO_PSDEV_NAME "%d", i); 
-                psdev->uc_devname = name;
+        memset(&izo_channels, 0, sizeof(izo_channels));
+        for ( i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                struct upc_channel *channel = &(izo_channels[i]);
+                INIT_LIST_HEAD(&channel->uc_pending);
+                INIT_LIST_HEAD(&channel->uc_processing);
+                INIT_LIST_HEAD(&channel->uc_cache_list);
+                init_waitqueue_head(&channel->uc_waitq);
+                channel->uc_lock = SPIN_LOCK_UNLOCKED;
+                channel->uc_hard = 0;
+                channel->uc_no_filter = 0;
+                channel->uc_no_journal = 0;
+                channel->uc_no_upcall = 0;
+                channel->uc_timeout = 30;
+                channel->uc_errorval = 0;
+                channel->uc_minor = i;
         }
         return 0;
 }
@@ -1361,25 +417,24 @@
 {
         int i;
 
-        for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) {
-                struct upc_comm *psdev = &upc_comms[i];
+        misc_deregister(&intermezzo_psdev);
+
+        for ( i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                struct upc_channel *channel = &(izo_channels[i]);
                 struct list_head *lh;
 
-                if ( ! list_empty(&psdev->uc_pending)) { 
-                        printk("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i);
-                }
-                if ( ! list_empty(&psdev->uc_processing)) { 
-                        printk("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i);
+                spin_lock(&channel->uc_lock); 
+                if ( ! list_empty(&channel->uc_pending)) { 
+                        CERROR("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i);
                 }
-                if ( ! list_empty(&psdev->uc_cache_list)) { 
-                        printk("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i);
+                if ( ! list_empty(&channel->uc_processing)) { 
+                        CERROR("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i);
                 }
-                if (psdev->uc_devname) {
-                        PRESTO_FREE(psdev->uc_devname,
-                                    strlen(PRESTO_PSDEV_NAME "256")+1);
+                if ( ! list_empty(&channel->uc_cache_list)) { 
+                        CERROR("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i);
                 }
-                lh = psdev->uc_pending.next;
-                while ( lh != &psdev->uc_pending) {
+                lh = channel->uc_pending.next;
+                while ( lh != &channel->uc_pending) {
                         struct upc_req *req;
 
                         req = list_entry(lh, struct upc_req, rq_chain);
@@ -1395,22 +450,23 @@
                                 wake_up(&req->rq_sleep);
                         }
                 }
-                lh = &psdev->uc_processing;
-                while ( (lh = lh->next) != &psdev->uc_processing ) {
+                lh = &channel->uc_processing;
+                while ( (lh = lh->next) != &channel->uc_processing ) {
                         struct upc_req *req;
                         req = list_entry(lh, struct upc_req, rq_chain);
                         list_del(&(req->rq_chain));
                         req->rq_flags |= REQ_DEAD; 
                         wake_up(&req->rq_sleep);
                 }
+                spin_unlock(&channel->uc_lock); 
         }
 }
 
 /*
  * lento_upcall and lento_downcall routines
  */
-static inline unsigned long lento_waitfor_upcall(struct upc_req *req,
-                                                 int minor)
+static inline unsigned long lento_waitfor_upcall
+            (struct upc_channel *channel, struct upc_req *req, int minor)
 {
         DECLARE_WAITQUEUE(wait, current);
         unsigned long posttime;
@@ -1419,38 +475,39 @@
 
         add_wait_queue(&req->rq_sleep, &wait);
         for (;;) {
-                if ( upc_comms[minor].uc_hard == 0 )
-                        current->state = TASK_INTERRUPTIBLE;
+                if ( izo_channels[minor].uc_hard == 0 )
+                        set_current_state(TASK_INTERRUPTIBLE);
                 else
-                        current->state = TASK_UNINTERRUPTIBLE;
+                        set_current_state(TASK_UNINTERRUPTIBLE);
 
                 /* got a reply */
                 if ( req->rq_flags & (REQ_WRITE | REQ_DEAD) )
                         break;
 
-                if ( !upc_comms[minor].uc_hard && signal_pending(current) ) {
+                /* these cases only apply when TASK_INTERRUPTIBLE */ 
+                if ( !izo_channels[minor].uc_hard && signal_pending(current) ) {
                         /* if this process really wants to die, let it go */
                         if (sigismember(&(current->pending.signal), SIGKILL)||
                             sigismember(&(current->pending.signal), SIGINT) )
                                 break;
                         /* signal is present: after timeout always return
                            really smart idea, probably useless ... */
-                        if ( jiffies > req->rq_posttime +
-                             upc_comms[minor].uc_timeout * HZ )
+                        if ( time_after(jiffies, req->rq_posttime +
+                             izo_channels[minor].uc_timeout * HZ) )
                                 break;
                 }
                 schedule();
-
         }
-      list_del(&req->rq_chain); 
-      INIT_LIST_HEAD(&req->rq_chain); 
+
+        spin_lock(&channel->uc_lock);
+        list_del_init(&req->rq_chain); 
+        spin_unlock(&channel->uc_lock);
         remove_wait_queue(&req->rq_sleep, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
 
         CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n",
                posttime, jiffies-posttime);
         return  (jiffies - posttime);
-
 }
 
 /*
@@ -1466,31 +523,30 @@
  * is read (in presto_psdev_read), when the filesystem is unmounted, or
  * when the module is unloaded.
  */
-int lento_upcall(int minor, int bufsize, int *rep_size, union up_args *buffer,
-                 int async, struct upc_req *rq)
+int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *buffer, 
+                   int async)
 {
         unsigned long runtime;
-        struct upc_comm *upc_commp;
-        union down_args *out;
+        struct upc_channel *channel;
+        struct izo_upcall_resp *out;
         struct upc_req *req;
         int error = 0;
 
         ENTRY;
-        upc_commp = &(upc_comms[minor]);
+        channel = &(izo_channels[minor]);
 
-        if (upc_commp->uc_no_upcall) {
+        if (channel->uc_no_upcall) {
                 EXIT;
                 goto exit_buf;
         }
-        if (!upc_commp->uc_pid && !async) {
+        if (!channel->uc_pid && !async) {
                 EXIT;
                 error = -ENXIO;
                 goto exit_buf;
         }
 
         /* Format the request message. */
-        CDEBUG(D_UPCALL, "buffer at %p, size %d\n", buffer, bufsize);
-        PRESTO_ALLOC(req, struct upc_req *, sizeof(struct upc_req));
+        PRESTO_ALLOC(req, sizeof(struct upc_req));
         if ( !req ) {
                 EXIT;
                 error = -ENOMEM;
@@ -1498,29 +554,29 @@
         }
         req->rq_data = (void *)buffer;
         req->rq_flags = 0;
-        req->rq_bufsize = bufsize;
+        req->rq_bufsize = *size;
         req->rq_rep_size = 0;
-        req->rq_opcode = ((union up_args *)buffer)->uh.opcode;
-        req->rq_unique = ++upc_commp->uc_seq;
+        req->rq_opcode = buffer->u_opc;
+        req->rq_unique = ++channel->uc_seq;
         init_waitqueue_head(&req->rq_sleep);
 
         /* Fill in the common input args. */
-        ((union up_args *)buffer)->uh.unique = req->rq_unique;
+        buffer->u_uniq = req->rq_unique;
+        buffer->u_async = async;
+
+        spin_lock(&channel->uc_lock); 
         /* Append msg to pending queue and poke Lento. */
-        list_add(&req->rq_chain, upc_commp->uc_pending.prev);
+        list_add(&req->rq_chain, channel->uc_pending.prev);
+        spin_unlock(&channel->uc_lock); 
         CDEBUG(D_UPCALL,
                "Proc %d waking Lento %d for(opc,uniq) =(%d,%d) msg at %p.\n",
-               current->pid, upc_commp->uc_pid, req->rq_opcode,
+               current->pid, channel->uc_pid, req->rq_opcode,
                req->rq_unique, req);
-
-        wake_up_interruptible(&upc_commp->uc_waitq);
+        wake_up_interruptible(&channel->uc_waitq);
 
         if ( async ) {
-                req->rq_flags = REQ_ASYNC;
-                if( rq != NULL ) {
-                        *rq = *req; /* struct copying */
-                }
                 /* req, rq_data are freed in presto_psdev_read for async */
+                req->rq_flags = REQ_ASYNC;
                 EXIT;
                 return 0;
         }
@@ -1535,29 +591,29 @@
          * ENODEV.  */
 
         /* Go to sleep.  Wake up on signals only after the timeout. */
-        runtime = lento_waitfor_upcall(req, minor);
+        runtime = lento_waitfor_upcall(channel, req, minor);
 
         CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
                req->rq_opcode, jiffies - req->rq_posttime,
                req->rq_unique, req->rq_rep_size);
         CDEBUG(D_UPCALL,
-               "..process %d woken up by Lento for req at 0x%p, data at %p\n",
-               current->pid, req, req->rq_data);
+               "..process %d woken up by Lento for req at 0x%x, data at %x\n",
+               current->pid, (int)req, (int)req->rq_data);
 
-        if (upc_commp->uc_pid) {      /* i.e. Lento is still alive */
+        if (channel->uc_pid) {      /* i.e. Lento is still alive */
           /* Op went through, interrupt or not we go on */
             if (req->rq_flags & REQ_WRITE) {
-                    out = (union down_args *)req->rq_data;
+                    out = (struct izo_upcall_resp *)req->rq_data;
                     /* here we map positive Lento errors to kernel errors */
-                    if ( out->dh.result < 0 ) {
-                            printk("Tell Peter: Lento returns negative error %d, for oc %d!\n",
-                                   out->dh.result, out->dh.opcode);
-                          out->dh.result = EINVAL;
+                    if ( out->result < 0 ) {
+                            CERROR("Tell Peter: Lento returns negative error %d, for oc %d!\n",
+                                   out->result, out->opcode);
+                          out->result = EINVAL;
                     }
-                    error = -out->dh.result;
+                    error = -out->result;
                     CDEBUG(D_UPCALL, "upcall: (u,o,r) (%d, %d, %d) out at %p\n",
-                           out->dh.unique, out->dh.opcode, out->dh.result, out);
-                    *rep_size = req->rq_rep_size;
+                           out->unique, out->opcode, out->result, out);
+                    *size = req->rq_rep_size;
                     EXIT;
                     goto exit_req;
             }
@@ -1574,53 +630,16 @@
 
             /* interrupted after Lento did its read, send signal */
             if ( (req->rq_flags & REQ_READ) && signal_pending(current) ) {
-                    union up_args *sigargs;
-                    struct upc_req *sigreq;
-
-                    CDEBUG(D_UPCALL,"Sending for: op = %d.%d, flags = %x\n",
+                    CDEBUG(D_UPCALL,"Interrupt after read: op = %d.%d, flags = %x\n",
                            req->rq_opcode, req->rq_unique, req->rq_flags);
 
                     error = -EINTR;
-
-                    /* req, rq_data are freed in presto_psdev_read for async */
-                    PRESTO_ALLOC(sigreq, struct upc_req *,
-                                 sizeof (struct upc_req));
-                    if (!sigreq) {
-                            error = -ENOMEM;
-                            EXIT;
-                            goto exit_req;
-                    }
-                    PRESTO_ALLOC((sigreq->rq_data), char *,
-                                 sizeof(struct lento_up_hdr));
-                    if (!(sigreq->rq_data)) {
-                            PRESTO_FREE(sigreq, sizeof (struct upc_req));
-                            error = -ENOMEM;
-                            EXIT;
-                            goto exit_req;
-                    }
-
-                    sigargs = (union up_args *)sigreq->rq_data;
-                    sigargs->uh.opcode = LENTO_SIGNAL;
-                    sigargs->uh.unique = req->rq_unique;
-
-                    sigreq->rq_flags = REQ_ASYNC;
-                    sigreq->rq_opcode = sigargs->uh.opcode;
-                    sigreq->rq_unique = sigargs->uh.unique;
-                    sigreq->rq_bufsize = sizeof(struct lento_up_hdr);
-                    sigreq->rq_rep_size = 0;
-                    CDEBUG(D_UPCALL,
-                           "presto_upcall: enqueing signal msg (%d, %d)\n",
-                           sigreq->rq_opcode, sigreq->rq_unique);
-
-                    /* insert at head of queue! */
-                    list_add(&sigreq->rq_chain, &upc_commp->uc_pending);
-                    wake_up_interruptible(&upc_commp->uc_waitq);
             } else {
-                  printk("Lento: Strange interruption - tell Peter.\n");
+                  CERROR("Lento: Strange interruption - tell Peter.\n");
                     error = -EINTR;
             }
-        } else {        /* If lento died i.e. !UC_OPEN(upc_commp) */
-                printk("presto_upcall: Lento dead on (op,un) (%d.%d) flags %d\n",
+        } else {        /* If lento died i.e. !UC_OPEN(channel) */
+                CERROR("lento_upcall: Lento dead on (op,un) (%d.%d) flags %d\n",
                        req->rq_opcode, req->rq_unique, req->rq_flags);
                 error = -ENODEV;
         }
@@ -1628,8 +647,5 @@
 exit_req:
         PRESTO_FREE(req, sizeof(struct upc_req));
 exit_buf:
-        PRESTO_FREE(buffer, bufsize);
         return error;
 }
-
-
diff -Nru a/fs/intermezzo/replicator.c b/fs/intermezzo/replicator.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/intermezzo/replicator.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,291 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Manage RCVD records for clients in the kernel
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <stdarg.h>
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+
+#include <linux/intermezzo_fs.h>
+
+/*
+ * this file contains a hash table of replicators/clients for a
+ * fileset. It allows fast lookup and update of reintegration status
+ */
+
+struct izo_offset_rec {
+	struct list_head or_list;
+	char             or_uuid[16];
+	loff_t           or_offset;
+};
+
+#define RCACHE_BITS 8
+#define RCACHE_SIZE (1 << RCACHE_BITS)
+#define RCACHE_MASK (RCACHE_SIZE - 1)
+
+static struct list_head *
+izo_rep_cache(void)
+{
+	int i;
+	struct list_head *cache;
+	PRESTO_ALLOC(cache, sizeof(struct list_head) * RCACHE_SIZE);
+	if (cache == NULL) {
+		CERROR("intermezzo-fatal: no memory for replicator cache\n");
+                return NULL;
+	}
+	memset(cache, 0, sizeof(struct list_head) * RCACHE_SIZE);
+	for (i = 0; i < RCACHE_SIZE; i++)
+		INIT_LIST_HEAD(&cache[i]);
+
+	return cache;
+}
+
+static struct list_head *
+izo_rep_hash(struct list_head *cache, char *uuid)
+{
+        return &cache[(RCACHE_MASK & uuid[1])];
+}
+
+static void
+izo_rep_cache_clean(struct presto_file_set *fset)
+{
+	int i;
+	struct list_head *bucket;
+	struct list_head *tmp;
+
+        if (fset->fset_clients == NULL)
+		return;
+        for (i = 0; i < RCACHE_SIZE; i++) {
+		tmp = bucket = &fset->fset_clients[i];
+
+		tmp = tmp->next;
+                while (tmp != bucket) {
+			struct izo_offset_rec *offrec;
+			tmp = tmp->next;
+			list_del(tmp);
+			offrec = list_entry(tmp, struct izo_offset_rec,
+					    or_list);
+			PRESTO_FREE(offrec, sizeof(struct izo_offset_rec));
+		}
+	}
+}
+
+struct izo_offset_rec *
+izo_rep_cache_find(struct presto_file_set *fset, char *uuid)
+{
+	struct list_head *buck = izo_rep_hash(fset->fset_clients, uuid);
+	struct list_head *tmp = buck;
+        struct izo_offset_rec *rec = NULL;
+
+        while ( (tmp = tmp->next) != buck ) {
+		rec = list_entry(tmp, struct izo_offset_rec, or_list);
+                if ( memcmp(rec->or_uuid, uuid, sizeof(rec->or_uuid)) == 0 )
+			return rec;
+	}
+
+	return NULL;
+}
+
+static int
+izo_rep_cache_add(struct presto_file_set *fset, struct izo_rcvd_rec *rec,
+                  loff_t offset)
+{
+        struct izo_offset_rec *offrec;
+
+        if (izo_rep_cache_find(fset, rec->lr_uuid)) {
+                CERROR("izo: duplicate client entry %s off %Ld\n",
+                       fset->fset_name, offset);
+                return -EINVAL;
+        }
+
+        PRESTO_ALLOC(offrec, sizeof(*offrec));
+        if (offrec == NULL) {
+                CERROR("izo: cannot allocate offrec\n");
+                return -ENOMEM;
+        }
+
+        memcpy(offrec->or_uuid, rec->lr_uuid, sizeof(rec->lr_uuid));
+        offrec->or_offset = offset;
+
+        list_add(&offrec->or_list,
+                 izo_rep_hash(fset->fset_clients, rec->lr_uuid));
+        return 0;
+}
+
+int
+izo_rep_cache_init(struct presto_file_set *fset)
+{
+	struct izo_rcvd_rec rec;
+        loff_t offset = 0, last_offset = 0;
+
+	fset->fset_clients = izo_rep_cache();
+        if (fset->fset_clients == NULL) {
+		CERROR("Error initializing client cache\n");
+		return -ENOMEM;
+	}
+
+        while ( presto_fread(fset->fset_rcvd.fd_file, (char *)&rec,
+                             sizeof(rec), &offset) == sizeof(rec) ) {
+                int rc;
+
+                if ((rc = izo_rep_cache_add(fset, &rec, last_offset)) < 0) {
+			izo_rep_cache_clean(fset);
+			return rc;
+		}
+
+                last_offset = offset;
+	}
+
+	return 0;
+}
+
+/*
+ * Return local last_rcvd record for the client. Update or create 
+ * if necessary.
+ *
+ * XXX: After this call, any -EINVAL from izo_rcvd_get is a real error.
+ */
+int
+izo_repstatus(struct presto_file_set *fset,  __u64 client_kmlsize, 
+              struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server)
+{
+        int rc;
+        rc = izo_rcvd_get(lr_server, fset, lr_client->lr_uuid);
+        if (rc < 0 && rc != -EINVAL) {
+                return rc;
+        }
+
+        /* client is new or has been reset. */
+        if (rc < 0 || (client_kmlsize == 0 && lr_client->lr_remote_offset == 0)) {
+                memset(lr_server, 0, sizeof(*lr_server));
+                memcpy(lr_server->lr_uuid, lr_client->lr_uuid, sizeof(lr_server->lr_uuid));
+                rc = izo_rcvd_write(fset, lr_server);
+                if (rc < 0)
+                        return rc;
+        }
+
+        /* update intersync */
+        rc = izo_upc_repstatus(presto_f2m(fset), fset->fset_name, lr_server);
+        return rc;
+}
+
+loff_t
+izo_rcvd_get(struct izo_rcvd_rec *rec, struct presto_file_set *fset, char *uuid)
+{
+        struct izo_offset_rec *offrec;
+        struct izo_rcvd_rec tmprec;
+        loff_t offset;
+
+        offrec = izo_rep_cache_find(fset, uuid);
+        if (offrec == NULL) {
+                CDEBUG(D_SPECIAL, "izo_get_rcvd: uuid not in hash.\n");
+                return -EINVAL;
+        }
+        offset = offrec->or_offset;
+
+        if (rec == NULL)
+                return offset;
+
+        if (presto_fread(fset->fset_rcvd.fd_file, (char *)&tmprec,
+                         sizeof(tmprec), &offset) != sizeof(tmprec)) {
+                CERROR("izo_get_rcvd: Unable to read from last_rcvd file offset "
+                       "%Lu\n", offset);
+                return -EIO;
+        }
+
+        memcpy(rec->lr_uuid, tmprec.lr_uuid, sizeof(tmprec.lr_uuid));
+        rec->lr_remote_recno = le64_to_cpu(tmprec.lr_remote_recno);
+        rec->lr_remote_offset = le64_to_cpu(tmprec.lr_remote_offset);
+        rec->lr_local_recno = le64_to_cpu(tmprec.lr_local_recno);
+        rec->lr_local_offset = le64_to_cpu(tmprec.lr_local_offset);
+        rec->lr_last_ctime = le64_to_cpu(tmprec.lr_last_ctime);
+
+        return offrec->or_offset;
+}
+
+/* Try to lookup the UUID in the hash.  Insert it if it isn't found.  Write the
+ * data to the file.
+ *
+ * Returns the offset of the beginning of the record in the last_rcvd file. */
+loff_t
+izo_rcvd_write(struct presto_file_set *fset, struct izo_rcvd_rec *rec)
+{
+        struct izo_offset_rec *offrec;
+        loff_t offset, rc;
+
+        ENTRY;
+
+        offrec = izo_rep_cache_find(fset, rec->lr_uuid);
+        if (offrec == NULL) {
+                /* I don't think it should be possible for an entry to be not in
+                 * the hash table without also having an invalid offset, but we
+                 * handle it gracefully regardless. */
+                write_lock(&fset->fset_rcvd.fd_lock);
+                offset = fset->fset_rcvd.fd_offset;
+                fset->fset_rcvd.fd_offset += sizeof(*rec);
+                write_unlock(&fset->fset_rcvd.fd_lock);
+
+                rc = izo_rep_cache_add(fset, rec, offset);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+        } else
+                offset = offrec->or_offset;
+        
+
+        rc = presto_fwrite(fset->fset_rcvd.fd_file, (char *)rec, sizeof(*rec),
+                           &offset);
+        if (rc == sizeof(*rec))
+                /* presto_fwrite() advances 'offset' */
+                rc = offset - sizeof(*rec);
+
+        EXIT;
+        return rc;
+}
+
+loff_t
+izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid,  __u64 remote_recno, 
+                    __u64 remote_offset)
+{
+        struct izo_rcvd_rec rec;
+        
+        loff_t rc;
+
+        ENTRY;
+        rc = izo_rcvd_get(&rec, fset, uuid);
+        if (rc < 0)
+                return rc;
+        rec.lr_remote_recno = remote_recno;
+        rec.lr_remote_offset = remote_offset;
+
+        rc = izo_rcvd_write(fset, &rec);
+        EXIT;
+        if (rc < 0)
+                return rc;
+        return 0;
+}
diff -Nru a/fs/intermezzo/super.c b/fs/intermezzo/super.c
--- a/fs/intermezzo/super.c	Tue Oct 15 20:29:23 2002
+++ b/fs/intermezzo/super.c	Tue Oct 15 20:29:23 2002
@@ -1,13 +1,30 @@
-/*
- *  presto's super.c
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- *  Copyright (C) 1998 Peter J. Braam
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ *  presto's super.c
  */
 
+static char rcsid[] __attribute ((unused)) = "$Id: super.c,v 1.4 2002/10/12 02:16:19 rread Exp $";
+#define INTERMEZZO_VERSION "$Revision: 1.4 $"
 
 #include <stdarg.h>
 
@@ -20,16 +37,17 @@
 #include <linux/ext2_fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/stat.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 #ifdef PRESTO_DEBUG
@@ -37,23 +55,8 @@
 long presto_kmemory = 0;
 #endif
 
-extern struct presto_cache *presto_init_cache(void);
-extern inline void presto_cache_add(struct presto_cache *cache, struct super_block *sb);
-extern inline void presto_init_cache_hash(void);
-
-int presto_remount(struct super_block *, int *, char *);
-extern ssize_t presto_file_write(struct file *file, const char *buf, 
-                                 size_t size, loff_t *off);
-
-/*
- *  Reading the super block.
- *
- *
- *
- */
-
 /* returns an allocated string, copied out from data if opt is found */
-static char *read_opt(const char *opt, char *data)
+static char *opt_read(const char *opt, char *data)
 {
         char *value;
         char *retval;
@@ -66,9 +69,9 @@
                 return NULL;
 
         value++;
-        PRESTO_ALLOC(retval, char *, strlen(value) + 1);
+        PRESTO_ALLOC(retval, strlen(value) + 1);
         if ( !retval ) {
-                printk("InterMezzo: Out of memory!\n");
+                CERROR("InterMezzo: Out of memory!\n");
                 return NULL;
         }
 
@@ -77,21 +80,30 @@
         return retval;
 }
 
-static void store_opt(char **dst, char *opt, char *defval)
+static void opt_store(char **dst, char *opt)
 {
-        if (dst) {
-                if (*dst) { 
-                        PRESTO_FREE(*dst, strlen(*dst) + 1);
-                }
-                *dst = opt;
-        } else {
-                printk("presto: store_opt, error dst == NULL\n"); 
-        }
+        if (!dst) 
+                CERROR("intermezzo: store_opt, error dst == NULL\n"); 
 
+        if (*dst)
+                PRESTO_FREE(*dst, strlen(*dst) + 1);
+        *dst = opt;
+}
+
+static void opt_set_default(char **dst, char *defval)
+{
+        if (!dst) 
+                CERROR("intermezzo: store_opt, error dst == NULL\n"); 
 
-        if (!opt && defval) {
+        if (*dst)
+                PRESTO_FREE(*dst, strlen(*dst) + 1);
+        if (defval) {
                 char *def_alloced; 
-                PRESTO_ALLOC(def_alloced, char *, strlen(defval)+1);
+                PRESTO_ALLOC(def_alloced, strlen(defval)+1);
+                if (!def_alloced) {
+                        CERROR("InterMezzo: Out of memory!\n");
+                        return ;
+                }
                 strcpy(def_alloced, defval);
                 *dst = def_alloced; 
         }
@@ -104,256 +116,197 @@
  * to the read_super operation of the cache).  The return value will
  * be a pointer to the end of the cache_data.
  */
-static char *presto_options(char *options, char *cache_data,
+static char *presto_options(struct file_system_type *fstype, 
+                            char *options, char *cache_data,
                             char **cache_type, char **fileset,
-                            char **prestodev,  char **mtpt)
+                            char **channel)
 {
         char *this_char;
+        char *opt_ptr = options;
         char *cache_data_end = cache_data;
 
+        /* set the defaults */ 
+        if (strcmp(fstype->name, "intermezzo") == 0)
+            opt_set_default(cache_type, "ext3"); 
+        else 
+            opt_set_default(cache_type, "tmpfs"); 
+            
         if (!options || !cache_data)
                 return cache_data_end;
 
-        /* set the defaults */ 
-        store_opt(cache_type, NULL, "ext3"); 
-        store_opt(prestodev, NULL, PRESTO_PSDEV_NAME "0"); 
 
         CDEBUG(D_SUPER, "parsing options\n");
-        while ((this_char = strsep (&options, ",")) != NULL) {
+        while ((this_char = strsep (&opt_ptr, ",")) != NULL) {
                 char *opt;
+                if (!*this_char)
+                        continue;
                 CDEBUG(D_SUPER, "this_char %s\n", this_char);
 
-        	if (!*this_char)
-        		continue;
-                if ( (opt = read_opt("fileset", this_char)) ) {
-                        store_opt(fileset, opt, NULL);
+                if ( (opt = opt_read("fileset", this_char)) ) {
+                        opt_store(fileset, opt);
                         continue;
                 }
-                if ( (opt = read_opt("cache_type", this_char)) ) {
-                        store_opt(cache_type, opt, "ext3");
+                if ( (opt = opt_read("cache_type", this_char)) ) {
+                        opt_store(cache_type, opt);
                         continue;
                 }
-                if ( (opt = read_opt("mtpt", this_char)) ) {
-                        store_opt(mtpt, opt, NULL);
-                        continue;
-                }
-                if ( (opt = read_opt("prestodev", this_char)) ) {
-                        store_opt(prestodev, opt, PRESTO_PSDEV_NAME);
+                if ( (opt = opt_read("channel", this_char)) ) {
+                        opt_store(channel, opt);
                         continue;
                 }
 
-                cache_data_end += sprintf(cache_data_end, "%s%s",
-                                          cache_data_end != cache_data ? ",":"",
-                                          this_char);
+                cache_data_end += 
+                        sprintf(cache_data_end, "%s%s",
+                                cache_data_end != cache_data ? ",":"", 
+                                this_char);
         }
 
         return cache_data_end;
 }
 
-/*
-    map a /dev/intermezzoX path to a minor:
-    used to validate mount options passed to InterMezzo
- */
-static int presto_get_minor(char *dev_path, int *minor)
+static int presto_set_channel(struct presto_cache *cache, char *channel)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
-        kdev_t devno = NODEV;
-        int error; 
+        int minor; 
+
         ENTRY;
+        if (!channel) {
+                minor = izo_psdev_get_free_channel();
+        } else {
+                minor = simple_strtoul(channel, NULL, 0); 
+        }
+        if (minor < 0 || minor >= MAX_CHANNEL) { 
+                CERROR("all channels in use or channel too large %d\n", 
+                       minor);
+                return -EINVAL;
+        }
+        
+        cache->cache_psdev = &(izo_channels[minor]);
+        list_add(&cache->cache_channel_list, 
+                 &cache->cache_psdev->uc_cache_list); 
 
-        /* Special case for root filesystem - use minor 0 always. */
-        if ( current->pid == 1 ) {
-                *minor = 0;
-                return 0;
-        }
-
-        error = presto_walk(dev_path, &nd);
-        if (error) {
-		EXIT;
-                return error;
-	}
-        dentry = nd.dentry;
-
-	error = -ENODEV;
-        if (!dentry->d_inode) { 
-		EXIT;
-		goto out;
-	}
-
-        if (!S_ISCHR(dentry->d_inode->i_mode)) {
-		EXIT;
-		goto out;
-	}
-
-        devno = dentry->d_inode->i_rdev;
-        if ( major(devno) != PRESTO_PSDEV_MAJOR ) { 
-		EXIT;
-		goto out;
-	}
-
-        if ( minor(devno) >= MAX_PRESTODEV ) {
-		EXIT;
-		goto out;
-	}
-
-	EXIT;
- out:
-        *minor = minor(devno);
-        path_release(&nd);
-        return 0;
+        EXIT;
+        return minor;
 }
 
-/* We always need to remove the presto options before passing to bottom FS */
-struct super_block * presto_read_super(struct super_block * presto_sb,
-                                       void * data, int silent)
+/* We always need to remove the presto options before passing 
+   mount options to cache FS */
+struct super_block * presto_get_sb(struct file_system_type *izo_type, 
+                                   int flags, char *devname, void * data)
 {
-        struct super_block *mysb = NULL;
         struct file_system_type *fstype;
         struct presto_cache *cache = NULL;
         char *cache_data = NULL;
         char *cache_data_end;
         char *cache_type = NULL;
         char *fileset = NULL;
-        char *presto_mtpt = NULL;
-        char *prestodev = NULL;
-        struct filter_fs *ops;
-        int minor;
-        struct upc_comm *psdev;
+        char *channel = NULL;
+        struct super_block *sb;
+        int err; 
+        unsigned int minor;
 
         ENTRY;
-        CDEBUG(D_MALLOC, "before parsing: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
 
         /* reserve space for the cache's data */
-        PRESTO_ALLOC(cache_data, void *, PAGE_SIZE);
+        PRESTO_ALLOC(cache_data, PAGE_SIZE);
         if ( !cache_data ) {
-                printk("presto_read_super: Cannot allocate data page.\n");
+                CERROR("presto_read_super: Cannot allocate data page.\n");
                 EXIT;
                 goto out_err;
         }
 
-        CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
-
         /* read and validate options */
-        cache_data_end = presto_options(data, cache_data, &cache_type, &fileset,
-                                        &prestodev, &presto_mtpt);
+        cache_data_end = presto_options(izo_type, data, cache_data, &cache_type, 
+                                        &fileset, &channel);
 
         /* was there anything for the cache filesystem in the data? */
         if (cache_data_end == cache_data) {
                 PRESTO_FREE(cache_data, PAGE_SIZE);
-                cache_data = NULL;
+                cache_data_end = cache_data = NULL;
         } else {
                 CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data,
                        cache_data);
         }
 
-        /* prepare the communication channel */
-        if ( presto_get_minor(prestodev, &minor) ) {
-                /* if (!silent) */
-                printk("InterMezzo: %s not a valid presto dev\n", prestodev);
-                EXIT;
-                goto out_err;
-        }
-        psdev = &upc_comms[minor];
-        CDEBUG(D_SUPER, "\n");
-        psdev->uc_no_filter = 1;
-
-        CDEBUG(D_SUPER, "presto minor is %d\n", minor);
-
         /* set up the cache */
-        cache = presto_init_cache();
+        cache = presto_cache_init();
         if ( !cache ) {
-                printk("presto_read_super: failure allocating cache.\n");
+                CERROR("presto_read_super: failure allocating cache.\n");
                 EXIT;
                 goto out_err;
         }
-
-        /* no options were passed: likely we are "/" readonly */
-        if ( !presto_mtpt || !fileset ) {
-                cache->cache_flags |= CACHE_LENTO_RO | CACHE_CLIENT_RO;
-        }
-        cache->cache_psdev = psdev;
-        /* no options were passed: likely we are "/" readonly */
-        /* before the journaling infrastructure can work, these
-           need to be set; that happens in presto_remount */
-        if ( !presto_mtpt || !fileset ) {
-                if (!presto_mtpt) 
-                        printk("No mountpoint marking cache RO\n");
-                if (!fileset) 
-                        printk("No fileset marking cache RO\n");
-                cache->cache_flags |= CACHE_LENTO_RO | CACHE_CLIENT_RO;
-        }
-
-        cache->cache_mtpt = presto_mtpt;
-        cache->cache_root_fileset = fileset;
         cache->cache_type = cache_type;
 
-        printk("Presto: type=%s, vol=%s, dev=%s (minor %d), mtpt %s, flags %x\n",
-               cache_type, fileset ? fileset : "NULL", prestodev, minor,
-               presto_mtpt ? presto_mtpt : "NULL", cache->cache_flags);
+        /* link cache to channel */ 
+        minor = presto_set_channel(cache, channel);
+        if (minor < 0) { 
+                EXIT;
+                goto out_err;
+        }
 
+        CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %x\n",
+               cache_type, fileset?fileset:"NULL", minor, cache->cache_flags);
 
         MOD_INC_USE_COUNT;
-        fstype = get_fs_type(cache_type);
 
+        /* get the filter for the cache */
+        fstype = get_fs_type(cache_type);
         cache->cache_filter = filter_get_filter_fs((const char *)cache_type); 
         if ( !fstype || !cache->cache_filter) {
-                printk("Presto: unrecognized fs type or cache type\n");
+                CERROR("Presto: unrecognized fs type or cache type\n");
                 MOD_DEC_USE_COUNT;
                 EXIT;
                 goto out_err;
         }
-        mysb = fstype->read_super(presto_sb, cache_data, silent);
-        /* this might have been freed above */
-        if (cache_data) {
-                PRESTO_FREE(cache_data, PAGE_SIZE);
-                cache_data = NULL;
+
+        sb = fstype->get_sb(fstype, flags, devname, cache_data);
+
+        if ( !sb || IS_ERR(sb)) {
+                CERROR("InterMezzo: cache mount failure.\n");
+                MOD_DEC_USE_COUNT;
+                EXIT;
+                goto out_err;
         }
-        if ( !mysb ) {
-                /* if (!silent) */
-                printk("InterMezzo: cache mount failure.\n");
+
+        /* can we in fact mount the cache */ 
+        if (sb->s_bdev && (strcmp(fstype->name, "vintermezzo") == 0)) {
+                CERROR("vintermezzo must not be used with a  block device\n");
                 MOD_DEC_USE_COUNT;
                 EXIT;
                 goto out_err;
         }
 
-	cache->cache_sb = mysb;
-        ops = filter_get_filter_fs(cache_type);
+        /* this might have been freed above */
+        if (cache_data) {
+                PRESTO_FREE(cache_data, PAGE_SIZE);
+                cache_data = NULL;
+        }
 
-        filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
+        cache->cache_sb = sb;
+        cache->cache_root = dget(sb->s_root);
 
         /* we now know the dev of the cache: hash the cache */
-        presto_cache_add(cache, mysb);
+        presto_cache_add(cache, to_kdev_t(sb->s_dev));
+        err = izo_prepare_fileset(sb->s_root, fileset); 
 
-        /* make sure we have our own super operations: mysb
+        filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
+
+        /* make sure we have our own super operations: sb
            still contains the cache operations */
-        filter_setup_super_ops(cache->cache_filter, mysb->s_op, 
+        filter_setup_super_ops(cache->cache_filter, sb->s_op, 
                                &presto_super_ops);
-        mysb->s_op = filter_c2usops(cache->cache_filter);
-
-        /* now get our own directory operations */
-        if ( mysb->s_root && mysb->s_root->d_inode ) {
-                CDEBUG(D_SUPER, "\n");
-                filter_setup_dir_ops(cache->cache_filter, 
-                                     mysb->s_root->d_inode,
-                                     &presto_dir_iops, &presto_dir_fops);
-                mysb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
-                CDEBUG(D_SUPER, "lookup at %p\n", 
-                       mysb->s_root->d_inode->i_op->lookup);
-                filter_setup_dentry_ops(cache->cache_filter, 
-                                        mysb->s_root->d_op, 
-                                        &presto_dentry_ops);
-                presto_sb->s_root->d_op = filter_c2udops(cache->cache_filter);
-                cache->cache_mtde = mysb->s_root;
-                presto_set_dd(mysb->s_root);
-        }
+        sb->s_op = filter_c2usops(cache->cache_filter);
 
-        CDEBUG(D_MALLOC, "after mounting: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
+        /* get izo directory operations: sb->s_root->d_inode exists now */
+        filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode,
+                             &presto_dir_iops, &presto_dir_fops);
+        filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op, 
+                                &presto_dentry_ops);
+        sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
+        sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter);
+        sb->s_root->d_op = filter_c2udops(cache->cache_filter);
 
         EXIT;
-        return mysb;
+        return sb;
 
  out_err:
         CDEBUG(D_SUPER, "out_err called\n");
@@ -363,10 +316,8 @@
                 PRESTO_FREE(cache_data, PAGE_SIZE);
         if (fileset)
                 PRESTO_FREE(fileset, strlen(fileset) + 1);
-        if (presto_mtpt)
-                PRESTO_FREE(presto_mtpt, strlen(presto_mtpt) + 1);
-        if (prestodev)
-                PRESTO_FREE(prestodev, strlen(prestodev) + 1);
+        if (channel)
+                PRESTO_FREE(channel, strlen(channel) + 1);
         if (cache_type)
                 PRESTO_FREE(cache_type, strlen(cache_type) + 1);
 
@@ -375,153 +326,90 @@
         return NULL;
 }
 
-int presto_remount(struct super_block * sb, int *flags, char *data)
-{
-        char *cache_data = NULL;
-        char *cache_data_end;
-        char **type;
-        char **fileset;
-        char **mtpt;
-        char **prestodev;
-        struct super_operations *sops;
-        struct presto_cache *cache = NULL;
-        int err = 0;
-
-        ENTRY;
-        CDEBUG(D_MALLOC, "before remount: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
-        CDEBUG(D_SUPER, "remount opts: %s\n", data ? (char *)data : "(none)");
-        if (data) {
-                /* reserve space for the cache's data */
-                PRESTO_ALLOC(cache_data, void *, PAGE_SIZE);
-                if ( !cache_data ) {
-                        err = -ENOMEM;
-                        EXIT;
-                        goto out_err;
-                }
-        }
-
-        cache = presto_find_cache(sb);
-        if (!cache) {
-                printk(__FUNCTION__ ": cannot find cache on remount\n");
-                err = -ENODEV;
-                EXIT;
-                goto out_err;
-        }
-
-        /* If an option has not yet been set, we allow it to be set on
-         * remount.  If an option already has a value, we pass NULL for
-         * the option pointer, which means that the InterMezzo option
-         * will be parsed but discarded.
-         */
-        type = cache->cache_type ? NULL : &cache->cache_type;
-        fileset = cache->cache_root_fileset ? NULL : &cache->cache_root_fileset;
-        prestodev = cache->cache_psdev ? NULL : &cache->cache_psdev->uc_devname;
-        mtpt = cache->cache_mtpt ? NULL : &cache->cache_mtpt;
-        cache_data_end = presto_options(data, cache_data, type, fileset,
-                                        prestodev, mtpt);
-
-        if (cache_data) {
-                if (cache_data_end == cache_data) {
-                        PRESTO_FREE(cache_data, PAGE_SIZE);
-                        cache_data = NULL;
-                } else {
-                        CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data,
-                               cache_data);
-                }
-        }
-
-        if (cache->cache_root_fileset && cache->cache_mtpt) {
-                cache->cache_flags &= ~(CACHE_LENTO_RO|CACHE_CLIENT_RO);
-        }
 
-        sops = filter_c2csops(cache->cache_filter);
-        if (sops->remount_fs) {
-                err = sops->remount_fs(sb, flags, cache_data);
-        }
 
-        CDEBUG(D_MALLOC, "after remount: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
-        EXIT;
-out_err:
-        if (cache_data)
-                PRESTO_FREE(cache_data, PAGE_SIZE);
-        return err;
-}
 
-struct file_system_type presto_fs_type = {
 #ifdef PRESTO_DEVEL
-        "izofs",
+static DECLARE_FSTYPE(presto_fs_type, "izo", presto_read_super, FS_REQUIRES_DEV);
+static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
 #else 
-        "intermezzo",
-#endif
-        FS_REQUIRES_DEV, /* can use Ibaskets when ext2 does */
-        presto_read_super,
-        NULL
+static struct file_system_type vpresto_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "vintermezzo",
+	.get_sb		= presto_get_sb,
+	.kill_sb	= kill_litter_super,
+};
+static struct file_system_type presto_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "intermezzo",
+	.get_sb		= presto_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
+#endif
+
 
 
-int /* __init */ init_intermezzo_fs(void)
+int __init init_intermezzo_fs(void)
 {
         int status;
 
-        printk(KERN_INFO "InterMezzo Kernel/Lento communications, "
-               "v1.04, braam@inter-mezzo.org\n");
+        printk(KERN_INFO "InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
+               " info@clusterfs.com\n");
 
         status = presto_psdev_init();
         if ( status ) {
-                printk("Problem (%d) in init_intermezzo_psdev\n", status);
+                CERROR("Problem (%d) in init_intermezzo_psdev\n", status);
                 return status;
         }
 
         status = init_intermezzo_sysctl();
         if (status) {
-                printk("presto: failed in init_intermezzo_sysctl!\n");
+                CERROR("presto: failed in init_intermezzo_sysctl!\n");
         }
 
-        presto_init_cache_hash();
-        presto_init_ddata_cache();
+        presto_cache_init_hash();
+
+        if (!presto_init_ddata_cache()) {
+                CERROR("presto out of memory!\n");
+                return -ENOMEM;
+        }
 
         status = register_filesystem(&presto_fs_type);
         if (status) {
-                printk("presto: failed in register_filesystem!\n");
+                CERROR("presto: failed in register_filesystem!\n");
+        }
+        status = register_filesystem(&vpresto_fs_type);
+        if (status) {
+                CERROR("vpresto: failed in register_filesystem!\n");
         }
         return status;
 }
 
-
-#ifdef MODULE
-MODULE_AUTHOR("Peter J. Braam <braam@inter-mezzo.org>");
-MODULE_DESCRIPTION("InterMezzo Kernel/Lento communications, v1.0.5.1");
-
-int init_module(void)
-{
-        return init_intermezzo_fs();
-}
-
-
-void cleanup_module(void)
+void __exit exit_intermezzo_fs(void)
 {
         int err;
 
         ENTRY;
 
         if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) {
-                printk("presto: failed to unregister filesystem\n");
+                CERROR("presto: failed to unregister filesystem\n");
+        }
+        if ( (err = unregister_filesystem(&vpresto_fs_type)) != 0 ) {
+                CERROR("vpresto: failed to unregister filesystem\n");
         }
 
         presto_psdev_cleanup();
         cleanup_intermezzo_sysctl();
         presto_cleanup_ddata_cache();
-
-#ifdef PRESTO_DEVEL
-        unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel");
-#else 
-        unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev");
-#endif
-        CDEBUG(D_MALLOC, "after cleanup: kmem %ld, vmem %ld\n",
+        CERROR("after cleanup: kmem %ld, vmem %ld\n",
                presto_kmemory, presto_vmemory);
 }
 
-#endif
 
+MODULE_AUTHOR("Cluster Filesystems Inc. <info@clusterfs.com>");
+MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION);
+MODULE_LICENSE("GPL");
+
+module_init(init_intermezzo_fs)
+module_exit(exit_intermezzo_fs)
diff -Nru a/fs/intermezzo/sysctl.c b/fs/intermezzo/sysctl.c
--- a/fs/intermezzo/sysctl.c	Tue Oct 15 20:29:12 2002
+++ b/fs/intermezzo/sysctl.c	Tue Oct 15 20:29:12 2002
@@ -1,11 +1,30 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1999 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  *  Sysctrl entries for Intermezzo!
  */
 
 #define __NO_VERSION__
 #include <linux/config.h> /* for CONFIG_PROC_FS */
 #include <linux/module.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
@@ -15,6 +34,7 @@
 #include <linux/ctype.h>
 #include <linux/init.h>
 #include <asm/bitops.h>
+#include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/utsname.h>
 #include <linux/blk.h>
@@ -22,7 +42,6 @@
 
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_upcall.h>
 
 /* /proc entries */
 
@@ -34,8 +53,6 @@
 	int len=0;
 
 	/* this works as long as we are below 1024 characters! */
-	len += presto_sprint_mounts(buffer, length, -1);
-
 	*start = buffer + offset;
 	len -= offset;
 
@@ -65,30 +82,27 @@
 #define PSDEV_NO_UPCALL    7      /* controls lento_upcall */
 #define PSDEV_ERRORVAL     8      /* controls presto_debug_fail_blkdev */
 #define PSDEV_EXCL_GID     9      /* which GID is ignored by presto */
-#define PSDEV_ILOOKUP_UID 10      /* which UID bypasses file access perms */
 #define PSDEV_BYTES_TO_CLOSE 11   /* bytes to write before close */
 
 /* These are global presto control options */
-#define PRESTO_PRIMARY_CTLCNT 4
-static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_PRESTODEV + 1] =
+#define PRESTO_PRIMARY_CTLCNT 2
+static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_CHANNEL + 1] =
 {
 	{PSDEV_DEBUG, "debug", &presto_debug, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_TRACE, "trace", &presto_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_EXCL_GID, "presto_excluded_gid", &presto_excluded_gid, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_ILOOKUP_UID, "presto_ilookup_uid", &presto_ilookup_uid, sizeof(int), 0644, NULL, &proc_dointvec},
 };
 
 /*
  * Intalling the sysctl entries: strategy
  * - have templates for each /proc/sys/intermezzo/ entry
  *   such an entry exists for each /dev/presto
- *    (proto_prestodev_entry)
+ *    (proto_channel_entry)
  * - have a template for the contents of such directories
  *    (proto_psdev_table)
  * - have the master table (presto_table)
  *
  * When installing, malloc, memcpy and fix up the pointers to point to
- * the appropriate constants in upc_comms[your_minor]
+ * the appropriate constants in izo_channels[your_minor]
  */
 
 static ctl_table proto_psdev_table[] = {
@@ -97,15 +111,13 @@
 	{PSDEV_NO_JOURNAL, "no_journal", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_NO_UPCALL, "no_upcall", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_TIMEOUT, "timeout", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_TRACE, "trace", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_DEBUG, "debug", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 #ifdef PRESTO_DEBUG
 	{PSDEV_ERRORVAL, "errorval", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 #endif
 	{ 0 }
 };
 
-static ctl_table proto_prestodev_entry = {
+static ctl_table proto_channel_entry = {
 	PSDEV_INTERMEZZO, 0,  NULL, 0, 0555, 0,
 };
 
@@ -122,6 +134,7 @@
 /* we made these separate as setting may in future be more restricted
  * than getting
  */
+#ifdef RON_MINNICH
 int dosetopt(int minor, struct psdev_opt *opt)
 {
 	int retval = 0;
@@ -132,23 +145,23 @@
 	switch(opt->optname) {
 
 	case PSDEV_TIMEOUT:
-		upc_comms[minor].uc_timeout = newval;
+		izo_channels[minor].uc_timeout = newval;
 		break;
 
 	case PSDEV_HARD:
-		upc_comms[minor].uc_hard = newval;
+		izo_channels[minor].uc_hard = newval;
 		break;
 
 	case PSDEV_NO_FILTER:
-		upc_comms[minor].uc_no_filter = newval;
+		izo_channels[minor].uc_no_filter = newval;
 		break;
 
 	case PSDEV_NO_JOURNAL:
-		upc_comms[minor].uc_no_journal = newval;
+		izo_channels[minor].uc_no_journal = newval;
 		break;
 
 	case PSDEV_NO_UPCALL:
-		upc_comms[minor].uc_no_upcall = newval;
+		izo_channels[minor].uc_no_upcall = newval;
 		break;
 
 #ifdef PRESTO_DEBUG
@@ -159,19 +172,17 @@
 		 * allow setting the underlying device read-only for the
 		 * current presto cache.
 		 */
-		int errorval = upc_comms[minor].uc_errorval;
-		kdev_t kdev = mk_kdev(MAJOR(-errorval), MINOR(-errorval));
+		int errorval = izo_channels[minor].uc_errorval;
 		if (errorval < 0) {
 			if (newval == 0)
-				set_device_ro(kdev, 0);
+				set_device_ro(-errorval, 0);
 			else
-				printk("device %s already read only\n",
-				       kdevname(kdev));
+				CERROR("device %s already read only\n",
+				       kdevname(-errorval));
 		} else {
-			kdev = mk_kdev(MAJOR(-newval), MINOR(-newval));
 			if (newval < 0)
-				set_device_ro(kdev, 1);
-			upc_comms[minor].uc_errorval = newval;
+				set_device_ro(-newval, 1);
+			izo_channels[minor].uc_errorval = newval;
 			CDEBUG(D_PSDEV, "setting errorval to %d\n", newval);
 		}
 
@@ -203,33 +214,32 @@
 	switch(opt->optname) {
 
 	case PSDEV_TIMEOUT:
-		opt->optval = upc_comms[minor].uc_timeout;
+		opt->optval = izo_channels[minor].uc_timeout;
 		break;
 
 	case PSDEV_HARD:
-		opt->optval = upc_comms[minor].uc_hard;
+		opt->optval = izo_channels[minor].uc_hard;
 		break;
 
 	case PSDEV_NO_FILTER:
-		opt->optval = upc_comms[minor].uc_no_filter;
+		opt->optval = izo_channels[minor].uc_no_filter;
 		break;
 
 	case PSDEV_NO_JOURNAL:
-		opt->optval = upc_comms[minor].uc_no_journal;
+		opt->optval = izo_channels[minor].uc_no_journal;
 		break;
 
 	case PSDEV_NO_UPCALL:
-		opt->optval = upc_comms[minor].uc_no_upcall;
+		opt->optval = izo_channels[minor].uc_no_upcall;
 		break;
 
 #ifdef PSDEV_DEBUG
 	case PSDEV_ERRORVAL: {
-		int errorval = upc_comms[minor].uc_errorval;
-		kdev_t kdev = mk_kdev(MAJOR(-errorval), MINOR(-errorval));
-		if (errorval < 0 && is_read_only(kdev))
-			printk(KERN_INFO "device %s has been set read-only\n",
-			       kdevname(kdev));
-		opt->optval = upc_comms[minor].uc_errorval;
+		int errorval = izo_channels[minor].uc_errorval;
+		if (errorval < 0 && is_read_only(-errorval))
+			CERROR("device %s has been set read-only\n",
+			       kdevname(-errorval));
+		opt->optval = izo_channels[minor].uc_errorval;
 		break;
 	}
 #endif
@@ -248,29 +258,26 @@
 	EXIT;
 	return retval;
 }
+#endif
 
 
-
+/* allocate the tables for the presto devices. We need
+ * sizeof(proto_channel_table)/sizeof(proto_channel_table[0])
+ * entries for each dev
+ */
 int /* __init */ init_intermezzo_sysctl(void)
 {
 	int i;
-	extern struct upc_comm upc_comms[MAX_PRESTODEV];
-
-	/* allocate the tables for the presto devices. We need
-	 * sizeof(proto_prestodev_table)/sizeof(proto_prestodev_table[0])
-	 * entries for each dev
-	 */
-	int total_dev = MAX_PRESTODEV;
+	int total_dev = MAX_CHANNEL;
 	int entries_per_dev = sizeof(proto_psdev_table) /
 		sizeof(proto_psdev_table[0]);
 	int total_entries = entries_per_dev * total_dev;
 	ctl_table *dev_ctl_table;
 
-	PRESTO_ALLOC(dev_ctl_table, ctl_table *,
-		     sizeof(ctl_table) * total_entries);
+	PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries);
 
 	if (! dev_ctl_table) {
-		printk("WARNING: presto couldn't allocate dev_ctl_table\n");
+		CERROR("WARNING: presto couldn't allocate dev_ctl_table\n");
 		EXIT;
 		return -ENOMEM;
 	}
@@ -287,14 +294,14 @@
 		/* entries for the individual "files" in this "directory" */
 		ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev];
 		/* init the psdev and psdev_entries with the prototypes */
-		*psdev = proto_prestodev_entry;
+		*psdev = proto_channel_entry;
 		memcpy(psdev_entries, proto_psdev_table,
 		       sizeof(proto_psdev_table));
 		/* now specialize them ... */
 		/* the psdev has to point to psdev_entries, and fix the number */
 		psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */
 
-		psdev->procname = kmalloc(32, GFP_KERNEL);
+		PRESTO_ALLOC((void*)psdev->procname, PROCNAME_SIZE);
 		if (!psdev->procname) {
 			PRESTO_FREE(dev_ctl_table,
 				    sizeof(ctl_table) * total_entries);
@@ -305,15 +312,13 @@
 		psdev->child = psdev_entries;
 
 		/* now for each psdev entry ... */
-		psdev_entries[0].data = &(upc_comms[i].uc_hard);
-		psdev_entries[1].data = &(upc_comms[i].uc_no_filter);
-		psdev_entries[2].data = &(upc_comms[i].uc_no_journal);
-		psdev_entries[3].data = &(upc_comms[i].uc_no_upcall);
-		psdev_entries[4].data = &(upc_comms[i].uc_timeout);
-		psdev_entries[5].data = &presto_print_entry;
-		psdev_entries[6].data = &presto_debug;
+		psdev_entries[0].data = &(izo_channels[i].uc_hard);
+		psdev_entries[1].data = &(izo_channels[i].uc_no_filter);
+		psdev_entries[2].data = &(izo_channels[i].uc_no_journal);
+		psdev_entries[3].data = &(izo_channels[i].uc_no_upcall);
+		psdev_entries[4].data = &(izo_channels[i].uc_timeout);
 #ifdef PRESTO_DEBUG
-		psdev_entries[7].data = &(upc_comms[i].uc_errorval);
+		psdev_entries[5].data = &(izo_channels[i].uc_errorval);
 #endif
 	}
 
@@ -332,8 +337,9 @@
 	return 0;
 }
 
-void cleanup_intermezzo_sysctl() {
-	int total_dev = MAX_PRESTODEV;
+void cleanup_intermezzo_sysctl(void)
+{
+	int total_dev = MAX_CHANNEL;
 	int entries_per_dev = sizeof(proto_psdev_table) /
 		sizeof(proto_psdev_table[0]);
 	int total_entries = entries_per_dev * total_dev;
@@ -347,7 +353,7 @@
 	for(i = 0; i < total_dev; i++) {
 		/* entry for this /proc/sys/intermezzo/intermezzo"i" */
 		ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT];
-		kfree(psdev->procname);
+		PRESTO_FREE(psdev->procname, PROCNAME_SIZE);
 	}
 	/* presto_table[PRESTO_PRIMARY_CTLCNT].child points to the
 	 * dev_ctl_table previously allocated in init_intermezzo_psdev()
diff -Nru a/fs/intermezzo/upcall.c b/fs/intermezzo/upcall.c
--- a/fs/intermezzo/upcall.c	Tue Oct 15 20:29:23 2002
+++ b/fs/intermezzo/upcall.c	Tue Oct 15 20:29:23 2002
@@ -1,25 +1,32 @@
-/*
- * Mostly platform independent upcall operations to Venus:
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001, 2002 Cluster File Systems, Inc. <braam@clusterfs.com>
+ * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Mostly platform independent upcall operations to a cache manager:
  *  -- upcalls
  *  -- upcall routines
  *
- * Linux 2.0 version
- * Copyright (C) 1996 Peter J. Braam <braam@cs.cmu.edu>,
- * Michael Callahan <callahan@maths.ox.ac.uk>
- *
- * Redone for Linux 2.1
- * Copyright (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon University encourages users of this code to contribute
- * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
- *
- * Much cleaned up for InterMezzo
- * Copyright (C) 1998 Peter J. Braam <braam@cs.cmu.edu>,
- * Copyright (C) 1999 Carnegie Mellon University
- *
  */
 
 #include <asm/system.h>
+#include <asm/segment.h>
 #include <asm/signal.h>
 #include <linux/signal.h>
 
@@ -28,218 +35,523 @@
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
-#include <linux/time.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
+#include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <asm/uaccess.h>
 #include <linux/vmalloc.h>
+#include <asm/segment.h>
 
+#include <linux/intermezzo_lib.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
+#include <linux/intermezzo_idl.h>
+
 /*
-  At present: four upcalls
-  - opendir: fetch a directory (synchronous & asynchronous)
-  - open: fetch file (synchronous)
-  - journal: send a journal page (asynchronous)
-  - permit: get a permit (synchronous)
+  At present:
+  -- Asynchronous calls:
+   - kml:            give a "more" kml indication to userland
+   - kml_truncate:   initiate KML truncation
+   - release_permit: kernel is done with permit
+  -- Synchronous
+   - open:           fetch file
+   - permit:         get a permit
 
-  Errors returned here are positive.
+  Errors returned by user level code are positive
 
  */
 
+static struct izo_upcall_hdr *upc_pack(__u32 opcode, int pathlen, char *path,
+                                       char *fsetname, int reclen, char *rec,
+                                       int *size)
+{
+        struct izo_upcall_hdr *hdr;
+        char *ptr;
+        ENTRY;
 
-#define INSIZE(tag) sizeof(struct lento_ ## tag ## _in)
-#define OUTSIZE(tag) sizeof(struct lento_ ## tag ## _out)
-#define SIZE(tag)  ( (INSIZE(tag)>OUTSIZE(tag)) ? INSIZE(tag) : OUTSIZE(tag) )
-
-#define UPARG(op)\
-do {\
-        PRESTO_ALLOC(inp, union up_args *, insize);\
-        if ( !inp ) { return -ENOMEM; }\
-        outp = (union down_args *) (inp);\
-        inp->uh.opcode = (op);\
-        inp->uh.pid = current->pid;\
-        inp->uh.uid = current->fsuid;\
-        outsize = insize;\
-} while (0)
-
-#define BUFF_ALLOC(buffer)                              \
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);        \
-        if ( !buffer ) {                                \
-                printk("PRESTO: out of memory!\n");     \
-                return -ENOMEM;                         \
+        *size = sizeof(struct izo_upcall_hdr);
+        if ( fsetname ) {
+                *size += round_strlen(fsetname);
+        }
+        if ( path ) { 
+                *size += round_strlen(path);
         }
+        if ( rec ) { 
+                *size += size_round(reclen);
+        }
+        PRESTO_ALLOC(hdr, *size);
+        if (!hdr) { 
+                CERROR("intermezzo upcall: out of memory (opc %d)\n", opcode);
+                EXIT;
+                return NULL;
+        }
+        memset(hdr, 0, *size);
+
+        ptr = (char *)hdr + sizeof(*hdr);
+
+        /* XXX do we need fsuid ? */
+        hdr->u_len = *size;
+        hdr->u_version = IZO_UPC_VERSION;
+        hdr->u_opc = opcode;
+        hdr->u_pid = current->pid;
+        hdr->u_uid = current->fsuid;
+
+        if (path) { 
+                /*XXX Robert: please review what len to pass in for 
+                  NUL terminated strings */
+                hdr->u_pathlen = strlen(path);
+                LOGL0(path, hdr->u_pathlen, ptr);
+        }
+        if (fsetname) { 
+                hdr->u_fsetlen = strlen(fsetname);
+                LOGL0(fsetname, strlen(fsetname), ptr);
+        }
+        if (rec) { 
+                hdr->u_reclen = reclen;
+                LOGL(rec, reclen, ptr);
+        }
+        
+        EXIT;
+        return hdr;
+}
 
 /* the upcalls */
-int lento_kml(int minor, unsigned int offset, unsigned int first_recno,
-              unsigned int length, unsigned int last_recno, int namelen,
-              char *fsetname)
-{
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length, __u32 last_recno, char *fsetname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
         ENTRY;
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return 0;
+        }
+
+        hdr = upc_pack(IZO_UPC_KML, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = offset;
+        hdr->u_first_recno = first_recno;
+        hdr->u_length = length;
+        hdr->u_last_recno = last_recno;
+
+        CDEBUG(D_UPCALL, "KML: fileset %s, offset %Lu, length %Lu, "
+               "first %u, last %d; minor %d\n",
+               fsetname, hdr->u_offset, hdr->u_length, hdr->u_first_recno,
+               hdr->u_last_recno, minor);
+
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno, char *fsetname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
 
+        ENTRY;
         if (!presto_lento_up(minor)) {
                 EXIT;
                 return 0;
         }
 
-        insize = SIZE(kml) + namelen + 1;
-        UPARG(LENTO_KML);
-        inp->lento_kml.namelen = namelen;
-        memcpy(inp->lento_kml.fsetname, fsetname, namelen);
-        inp->lento_kml.fsetname[namelen] = '\0';
-        inp->lento_kml.offset = offset;
-        inp->lento_kml.first_recno = first_recno;
-        inp->lento_kml.length = length;
-        inp->lento_kml.last_recno = last_recno;
-
-        CDEBUG(D_UPCALL, "KML: fileset %s, offset %d, length %d, "
-               "first %d, last %d; minor %d\n",
-               inp->lento_kml.fsetname,
-               inp->lento_kml.offset,
-               inp->lento_kml.length,
-               inp->lento_kml.first_recno,
-               inp->lento_kml.last_recno, minor);
+        hdr = upc_pack(IZO_UPC_KML_TRUNC, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_length = length;
+        hdr->u_last_recno = last_recno;
+
+        CDEBUG(D_UPCALL, "KML TRUNCATE: fileset %s, length %Lu, "
+               "last recno %d, minor %d\n",
+               fsetname, hdr->u_length, hdr->u_last_recno, minor);
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             ASYNCHRONOUS, NULL);
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
 
         EXIT;
         return error;
 }
 
-int lento_release_permit( int minor, int mycookie )
+int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, struct lento_vfs_context *info)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
         if (!presto_lento_up(minor)) {
                 EXIT;
-                return 0;
+                return -EIO;
         }
 
-        insize= SIZE(response_cookie);
-        UPARG(LENTO_COOKIE);
-        inp->lento_response_cookie.cookie= mycookie;
+        hdr = upc_pack(IZO_UPC_OPEN, pathlen, path, fsetname, 
+                       sizeof(*info), (char*)info, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
 
-        CDEBUG(D_UPCALL, "cookie %d\n", mycookie);
+        CDEBUG(D_UPCALL, "path %s\n", path);
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             ASYNCHRONOUS, NULL);
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
 
         EXIT;
-        return error;
+        return -error;
 }
 
-int lento_opendir(int minor, int pathlen, char *path, int async)
+int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, 
+                       __u32 pathlen, char *path, char *fsetname)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
-        insize = SIZE(opendir) + pathlen + 1;
-        UPARG(LENTO_OPENDIR);
-        inp->lento_opendir.async = async;
-        inp->lento_opendir.pathlen = pathlen;
-        memcpy(inp->lento_opendir.path, path, pathlen);
-        inp->lento_opendir.path[pathlen] = '\0';
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_GET_FILEID, pathlen, path, fsetname, reclen, rec, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
 
-        CDEBUG(D_UPCALL, "path %s\n", inp->lento_opendir.path);
+        CDEBUG(D_UPCALL, "path %s\n", path);
 
-        if (async) {
-                error = lento_upcall(minor, insize, &outsize, inp,
-                                     ASYNCHRONOUS, NULL);
-                return 0;
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_backfetch(int minor, char *path, char *fsetname, struct lento_vfs_context *info)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
         }
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             SYNCHRONOUS, NULL);
-        if (error && error != EISFSETROOT) {
-                printk("lento_opendir: error %d\n", error);
+        hdr = upc_pack(IZO_UPC_BACKFETCH, strlen(path), path, fsetname, 
+                       sizeof(*info), (char *)info, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
         }
 
+        /* This is currently synchronous, kml_reint_record blocks */
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
         EXIT;
-        return error;
+        return -error;
 }
 
-int lento_open(int minor, int pathlen, char *path)
+int izo_upc_permit(int minor, struct dentry *dentry, __u32 pathlen, char *path,
+                   char *fsetname)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
-
-	ENTRY;
-	insize = SIZE(open) + pathlen + 1;
-	UPARG(LENTO_OPEN);
-	inp->lento_open.pathlen = pathlen;
-	memcpy(inp->lento_open.path, path, pathlen);
-	inp->lento_open.path[pathlen] = '\0';
-
-	CDEBUG(D_UPCALL, "path %s\n", inp->lento_open.path);
-
-	error = lento_upcall(minor, insize, &outsize, inp,
-			     SYNCHRONOUS, NULL);
-	if (error) {
-	        printk("lento_open: error %d\n", error);
-	}
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_PERMIT, pathlen, path, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor, path);
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+
+        if (error == -EROFS) {
+                int err;
+                CERROR("InterMezzo: ERROR - requested permit for read-only "
+                       "fileset.\n   Setting \"%s\" read-only!\n", path);
+                err = izo_mark_cache(dentry, 0xFFFFFFFF, CACHE_CLIENT_RO, NULL);
+                if (err)
+                        CERROR("InterMezzo ERROR: mark_cache %d\n", err);
+        } else if (error) {
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+        }
 
         EXIT;
         return error;
 }
 
+/* This is a ping-pong upcall handled on the server when a client (uuid)
+ * requests the permit for itself. */
+int izo_upc_revoke_permit(int minor, char *fsetname, __u8 uuid[16])
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_REVOKE_PERMIT, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
 
-int lento_permit(int minor, int pathlen, int fsetnamelen, char *path, char *fsetname)
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_go_fetch_kml(int minor, char *fsetname, __u8 uuid[16],
+                         __u64 kmlsize)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
-        insize = SIZE(permit) + pathlen + 1 + fsetnamelen + 1;
-        UPARG(LENTO_PERMIT);
-        inp->lento_permit.pathlen = pathlen;
-        inp->lento_permit.fsetnamelen = fsetnamelen;
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_GO_FETCH_KML, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = kmlsize;
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
 
-        memcpy(inp->lento_permit.path, path, pathlen);
-        inp->lento_permit.path[pathlen] = '\0';
+        EXIT;
+        return -error;
+}
 
-	memcpy(&(inp->lento_permit.path[pathlen+1]), fsetname, fsetnamelen); 
-        inp->lento_permit.path[fsetnamelen + 1 + pathlen] = '\0';
+int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
+                    int client_flag)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
 
-        CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor,
-               inp->lento_permit.path);
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             SYNCHRONOUS, NULL);
+        hdr = upc_pack(IZO_UPC_CONNECT, 0, NULL, NULL, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = ip_address;
+        hdr->u_length = port;
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+        hdr->u_first_recno = client_flag;
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
         if (error) {
-                if( error == -EROFS ) {
-                        int err;
-                        printk("lento_permit: ERROR - requested permit for "
-                               "read-only fileset.\n"
-                               "   Setting \"%s\" read-only!\n",
-                               path);
-                        err= presto_mark_cache(path, 0xFFFFFFFF, 
-                                               CACHE_CLIENT_RO, NULL);
-                        if( err ) {
-                                printk("ERROR : mark_cache %d\n", err);
-                        }
-                }
-                else {
-                        printk("lento_permit: error %d\n", error);
-                }
+                CERROR("%s: error %d\n", __FUNCTION__, error);
         }
 
         EXIT;
+        return -error;
+}
+
+int izo_upc_set_kmlsize(int minor, char *fsetname, __u8 uuid[16], __u64 kmlsize)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_SET_KMLSIZE, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+        hdr->u_length = kmlsize;
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_repstatus(int minor,  char * fsetname, struct izo_rcvd_rec *lr_server)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_REPSTATUS, 0, NULL, fsetname, 
+                       sizeof(*lr_server), (char*)lr_server, 
+                       &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+
+#if 0
+int izo_upc_client_make_branch(int minor, char *fsetname, char *tagname,
+                               char *branchname)
+{
+        int size, error;
+        struct izo_upcall_hdr *hdr;
+        int pathlen;
+        char *path;
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_CLIENT_MAKE_BRANCH, strlen(tagname), tagname,
+                       fsetname, strlen(branchname) + 1, branchname, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                error = -PTR_ERR(hdr);
+                goto error;
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: error %d\n", error);
 
+ error:
+        PRESTO_FREE(path, pathlen);
+        EXIT;
         return error;
 }
+#endif
+
+int izo_upc_server_make_branch(int minor, char *fsetname)
+{
+        int size, error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
 
+        hdr = upc_pack(IZO_UPC_SERVER_MAKE_BRANCH, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                error = -PTR_ERR(hdr);
+                goto error;
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: error %d\n", error);
+
+ error:
+        EXIT;
+        return -error;
+}
+
+int izo_upc_branch_undo(int minor, char *fsetname, char *branchname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_BRANCH_UNDO, strlen(branchname), branchname,
+                       fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_branch_redo(int minor, char *fsetname, char *branchname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_BRANCH_REDO, strlen(branchname) + 1, branchname,
+                       fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
diff -Nru a/fs/intermezzo/vfs.c b/fs/intermezzo/vfs.c
--- a/fs/intermezzo/vfs.c	Tue Oct 15 20:29:15 2002
+++ b/fs/intermezzo/vfs.c	Tue Oct 15 20:29:15 2002
@@ -1,4 +1,25 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ *  Copyright (C) 2000 Stelias Computing, Inc.
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  * vfs.c
  *
  * This file implements kernel downcalls from lento.
@@ -22,7 +43,6 @@
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
-
 /*
  * Some corrections by tytso.
  */
@@ -45,23 +65,54 @@
 
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/namei.h>
 #include <linux/blk.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #ifdef CONFIG_FS_EXT_ATTR
-#include <linux/ext_attr.h>
+# include <linux/ext_attr.h>
 
-#ifdef CONFIG_FS_POSIX_ACL
-#include <linux/posix_acl.h>
-#endif
+# ifdef CONFIG_FS_POSIX_ACL
+#  include <linux/posix_acl.h>
+# endif
 #endif
 
 extern struct inode_operations presto_sym_iops;
 
+/* Write the last_rcvd values to the last_rcvd file.  We don't know what the
+ * UUID or last_ctime values are, so we have to read from the file first
+ * (sigh). 
+ * exported for branch_reinter in kml_reint.c*/
+int presto_write_last_rcvd(struct rec_info *recinfo,
+                           struct presto_file_set *fset,
+                           struct lento_vfs_context *info)
+{
+        int rc;
+        struct izo_rcvd_rec rcvd_rec;
+
+        ENTRY;
+
+        memset(&rcvd_rec, 0, sizeof(rcvd_rec));
+        memcpy(rcvd_rec.lr_uuid, info->uuid, sizeof(rcvd_rec.lr_uuid));
+        rcvd_rec.lr_remote_recno = HTON__u64(info->recno);
+        rcvd_rec.lr_remote_offset = HTON__u64(info->kml_offset);
+        rcvd_rec.lr_local_recno = HTON__u64(recinfo->recno);
+        rcvd_rec.lr_local_offset = HTON__u64(recinfo->offset + recinfo->size);
+
+        rc = izo_rcvd_write(fset, &rcvd_rec);
+        if (rc < 0) {
+                /* izo_rcvd_write returns negative errors and non-negative
+                 * offsets */
+                CERROR("InterMezzo: izo_rcvd_write failed: %d\n", rc);
+                EXIT;
+                return rc;
+        }
+        EXIT;
+        return 0;
+}
+
 /*
  * It's inline, so penalty for filesystems that don't use sticky bit is
  * minimal.
@@ -130,13 +181,13 @@
                                      unsigned long value)
 {
         int minor = presto_f2m(fset);
-        int errorval = upc_comms[minor].uc_errorval;
-        kdev_t dev = fset->fset_mtpt->d_inode->i_dev;
+        int errorval = izo_channels[minor].uc_errorval;
+        kdev_t dev = to_kdev_t(fset->fset_dentry->d_inode->i_dev);
 
         if (errorval && errorval == (long)value && !is_read_only(dev)) {
                 CDEBUG(D_SUPER, "setting device %s read only\n", kdevname(dev));
                 BLKDEV_FAIL(dev, 1);
-                upc_comms[minor].uc_errorval = -kdev_val(dev);
+                izo_channels[minor].uc_errorval = -kdev_val(dev);
         }
 }
 #else
@@ -144,20 +195,22 @@
 #endif
 
 
-static inline int presto_do_kml(struct lento_vfs_context *info, struct inode* inode)
+static inline int presto_do_kml(struct lento_vfs_context *info,
+                                struct dentry *dentry)
 {
-        if ( ! (info->flags & LENTO_FL_KML) ) 
+        if ( ! (info->flags & LENTO_FL_KML) )
                 return 0;
-        if ( inode->i_gid == presto_excluded_gid ) 
+        if ( presto_chk(dentry, PRESTO_DONT_JOURNAL) )
                 return 0;
         return 1;
 }
 
-static inline int presto_do_expect(struct lento_vfs_context *info, struct inode *inode)
+static inline int presto_do_rcvd(struct lento_vfs_context *info,
+                                 struct dentry *dentry)
 {
         if ( ! (info->flags & LENTO_FL_EXPECT) ) 
                 return 0;
-        if ( inode->i_gid == presto_excluded_gid ) 
+        if ( presto_chk(dentry, PRESTO_DONT_JOURNAL) )
                 return 0;
         return 1;
 }
@@ -166,12 +219,15 @@
 /* XXX fixme: this should not fail, all these dentries are in memory
    when _we_ call this */
 int presto_settime(struct presto_file_set *fset, 
-                   struct dentry *dentry, 
+                   struct dentry *newobj,
+                   struct dentry *parent,
+                   struct dentry *target,
                    struct lento_vfs_context *ctx, 
                    int valid)
 {
-        int error; 
-        struct inode *inode = dentry->d_inode;
+        int error = 0;
+        struct dentry *dentry;
+        struct inode *inode;
         struct inode_operations *iops;
         struct iattr iattr;
 
@@ -180,39 +236,128 @@
                 EXIT;
                 return 0;
         }
+
         iattr.ia_ctime = ctx->updated_time;
         iattr.ia_mtime = ctx->updated_time;
         iattr.ia_valid = valid;
 
-        error = -EROFS;
-        if (IS_RDONLY(inode)) {
-                EXIT;
-                return -EROFS;
+        while (1) {
+                if (parent && ctx->flags & LENTO_FL_TOUCH_PARENT) {
+                        dentry = parent;
+                        parent = NULL;
+                } else if (newobj && ctx->flags & LENTO_FL_TOUCH_NEWOBJ) {
+                        dentry = newobj;
+                        newobj = NULL;
+                } else if (target) {
+                        dentry = target;
+                        target = NULL;
+                } else
+                        break;
+
+                inode = dentry->d_inode;
+
+                error = -EROFS;
+                if (IS_RDONLY(inode)) {
+                        EXIT;
+                        return -EROFS;
+                }
+
+                if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+                        EXIT;
+                        return -EPERM;
+                }
+
+                error = -EPERM;
+                iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
+                if (!iops) { 
+                        EXIT;
+                        return error;
+                }
+
+                if (iops->setattr != NULL)
+                        error = iops->setattr(dentry, &iattr);
+                else {
+                        error = 0;
+                        inode_setattr(dentry->d_inode, &iattr);
+                }
         }
+        EXIT;
+        return error;
+}
 
-        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb)
+{
+        rb->rb_mode = (__u32)inode->i_mode;
+        rb->rb_rdev = (__u32)kdev_t_to_nr(inode->i_rdev);
+        rb->rb_uid  = (__u64)inode->i_uid;
+        rb->rb_gid  = (__u64)inode->i_gid;
+}
+
+
+int presto_do_close(struct presto_file_set *fset, struct file *file)
+{
+        struct rec_info rec;
+        int rc = -ENOSPC; 
+        void *handle;
+        struct inode *inode = file->f_dentry->d_inode;
+        struct presto_file_data *fdata = 
+                (struct presto_file_data *)file->private_data;
+
+        ENTRY;
+        presto_getversion(&fdata->fd_info.remote_version, inode);
+
+        rc = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (rc) { 
                 EXIT;
-                return -EPERM;
+                return rc;
         }
 
-        error = -EPERM;
-        iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
-        if (!iops) { 
-                EXIT;
-                return error;
+        handle = presto_trans_start(fset, file->f_dentry->d_inode, 
+                                            KML_OPCODE_RELEASE);
+        if ( IS_ERR(handle) ) {
+                CERROR("presto_release: no space for transaction\n");
+                return rc;
         }
 
-        if (iops->setattr != NULL)
-                error = iops->setattr(dentry, &iattr);
-        else {
-		error = 0;
-                inode_setattr(dentry->d_inode, &iattr);
-	}
+        if (fdata->fd_info.flags & LENTO_FL_KML) 
+                rc = presto_journal_close(&rec, fset, file, file->f_dentry,
+                                          &fdata->fd_version, 
+                                          &fdata->fd_info.remote_version);
+        if (rc) { 
+                CERROR("presto_close: cannot journal close\n");
+                goto out;
+        }
+
+        if (fdata->fd_info.flags & LENTO_FL_EXPECT) 
+                rc = presto_write_last_rcvd(&rec, fset, &fdata->fd_info);
+
+        if (rc) { 
+                CERROR("presto_close: cannot journal last_rcvd\n");
+                goto out;
+        }
+        presto_trans_commit(fset, handle); 
+        
+        /* cancel the LML record */ 
+        handle = presto_trans_start(fset, inode, KML_OPCODE_WRITE);
+        if ( IS_ERR(handle) ) {
+                CERROR("presto_release: no space for clear\n");
+                return -ENOSPC;
+        }
+
+        rc = presto_clear_lml_close(fset, fdata->fd_lml_offset); 
+        if (rc < 0 ) { 
+                CERROR("presto_close: cannot journal close\n");
+                goto out;
+        }
+        presto_truncate_lml(fset);
+
+ out:
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_trans_commit(fset, handle); 
         EXIT;
-        return error;
+        return rc;
 }
 
-
 int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry,
                       struct iattr *iattr, struct lento_vfs_context *info)
 {
@@ -221,8 +366,9 @@
         struct inode_operations *iops;
         int error;
         struct presto_version old_ver, new_ver;
+        struct izo_rollback_data rb;
         void *handle;
-	off_t old_size=inode->i_size;
+        loff_t old_size=inode->i_size;
 
         ENTRY;
         error = -EROFS;
@@ -237,33 +383,34 @@
         }
 
         presto_getversion(&old_ver, dentry->d_inode);
+        izo_get_rollback_data(dentry->d_inode, &rb);
         error = -EPERM;
         iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
-        if (!iops &&
-            !iops->setattr) {
+
+        error = presto_reserve_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+        if (error) {
                 EXIT;
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-		return error;
-	}
-
-	if  (iattr->ia_valid & ATTR_SIZE) { 
-		handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_TRUNC);
-	} else {
-		handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_SETATTR);
-	}
+        if  (iattr->ia_valid & ATTR_SIZE) {
+                if (izo_mark_dentry(dentry, ~PRESTO_DATA, 0, NULL) != 0)
+                        CERROR("izo_mark_dentry(inode %ld, ~PRESTO_DATA) "
+                               "failed\n", dentry->d_inode->i_ino);
+                handle = presto_trans_start(fset, dentry->d_inode,
+                                            KML_OPCODE_TRUNC);
+        } else {
+                handle = presto_trans_start(fset, dentry->d_inode,
+                                            KML_OPCODE_SETATTR);
+        }
 
         if ( IS_ERR(handle) ) {
-                printk("presto_do_setattr: no space for transaction\n");
-		presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+                CERROR("presto_do_setattr: no space for transaction\n");
+                presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
                 return -ENOSPC;
         }
 
-        if (dentry->d_inode && iops->setattr) {
+        if (dentry->d_inode && iops && iops->setattr) {
                 error = iops->setattr(dentry, iattr);
         } else {
                 error = inode_change_ok(dentry->d_inode, iattr);
@@ -271,41 +418,43 @@
                         inode_setattr(inode, iattr);
         }
 
-	if (!error && (iattr->ia_valid & ATTR_SIZE))
-		vmtruncate(inode, iattr->ia_size);
+        if (!error && (iattr->ia_valid & ATTR_SIZE))
+                vmtruncate(inode, iattr->ia_size);
 
         if (error) {
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x10);
 
-        if ( presto_do_kml(info, dentry->d_inode) ) {
+        if ( presto_do_kml(info, dentry) ) {
                 if ((iattr->ia_valid & ATTR_SIZE) && (old_size != inode->i_size)) {
-                	struct file file;
-                	/* Journal a close whenever we see a potential truncate
-                 	* At the receiving end, lento should explicitly remove
-                 	* ATTR_SIZE from the list of valid attributes */
-                	presto_getversion(&new_ver, inode);
-                	file.private_data = NULL;
-                	file.f_dentry = dentry;
-                	error=presto_journal_close(&rec, fset, &file, dentry, &new_ver);
-            	}
+                        struct file file;
+                        /* Journal a close whenever we see a potential truncate
+                        * At the receiving end, lento should explicitly remove
+                        * ATTR_SIZE from the list of valid attributes */
+                        presto_getversion(&new_ver, inode);
+                        file.private_data = NULL;
+                        file.f_dentry = dentry;
+                        error = presto_journal_close(&rec, fset, &file, dentry,
+                                                     &old_ver, &new_ver);
+                }
 
-		if (!error)
-                	error = presto_journal_setattr(&rec, fset, dentry, &old_ver, iattr);
+                if (!error)
+                        error = presto_journal_setattr(&rec, fset, dentry,
+                                                       &old_ver, &rb, iattr);
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x30);
 
         EXIT;
 exit:
-	presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
         presto_trans_commit(fset, handle);
         return error;
 }
@@ -342,7 +491,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_lock;
         }
@@ -378,6 +527,14 @@
 
         error = presto_do_setattr(fset, dentry, iattr, info);
 
+        if (info->flags & LENTO_FL_SET_DDFILEID) {
+                struct presto_dentry_data *dd = presto_d2d(dentry);
+                if (dd) {
+                        dd->remote_ino = info->remote_ino;
+                        dd->remote_generation = info->remote_generation;
+                }
+        }
+
 #ifdef CONFIG_FS_POSIX_ACL
         /* restore the inode_operations if we changed them*/
         if (iattr->ia_valid & ATTR_MODE) 
@@ -407,13 +564,13 @@
         mode &= S_IALLUGO;
         mode |= S_IFREG;
 
-        down(&dir->d_inode->i_sem);
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_sem);
-		return error;
-	}
+        //        down(&dir->d_inode->i_zombie);
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                //                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         error = may_create(dir->d_inode, dentry);
         if (error) {
@@ -429,13 +586,13 @@
         }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_CREATE);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_CREATE);
         if ( IS_ERR(handle) ) {
                 EXIT;
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_create: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_create: no space for transaction\n");
                 error=-ENOSPC;
-		goto exit_pre_lock;
+                goto exit_pre_lock;
         }
         DQUOT_INIT(dir->d_inode);
         lock_kernel();
@@ -445,8 +602,7 @@
                 goto exit_lock;
         }
 
-        if (dentry->d_inode && 
-            dentry->d_inode->i_gid != presto_excluded_gid) {
+        if (dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
                 /* was this already done? */
                 presto_set_ops(dentry->d_inode, cache->cache_filter);
@@ -464,38 +620,45 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit_lock;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit_lock;
         }
 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x10);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x10);
-        presto_getversion(&new_file_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) ) { 
+                presto_getversion(&new_file_ver, dentry->d_inode);
                 error = presto_journal_create(&rec, fset, dentry, &tgt_dir_ver,
                                               &new_file_ver, 
-					      dentry->d_inode->i_mode);
+                                              dentry->d_inode->i_mode);
+        }
+
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x20);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x30);
+
+        /* add inode dentry */
+        if (fset->fset_cache->cache_filter->o_trops->tr_add_ilookup ) { 
+                struct dentry *d;
+                d = fset->fset_cache->cache_filter->o_trops->tr_add_ilookup
+                        (dir->d_inode->i_sb->s_root, dentry);
+        }
+
         EXIT;
 
  exit_lock:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_pre_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-        up(&dir->d_inode->i_sem);
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        //        up(&dir->d_inode->i_zombie);
         return error;
 }
 
@@ -540,9 +703,9 @@
         /* this looks up the parent */
         error = path_lookup(pathname,  LOOKUP_PARENT, &nd);
         if (error) {
-		EXIT;
+                EXIT;
                 goto exit;
-	}
+        }
         dentry = lookup_create(&nd, 0);
         error = PTR_ERR(dentry);
         if (IS_ERR(dentry)) {
@@ -553,7 +716,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_lock;
         }
@@ -564,7 +727,7 @@
 
  exit_lock:
         path_release (&nd);
-	dput(dentry); 
+        dput(dentry); 
         up(&dentry->d_parent->d_inode->i_sem);
         putname(pathname);
 exit:
@@ -583,13 +746,13 @@
         struct presto_version new_link_ver;
         void *handle;
 
-        down(&dir->d_inode->i_sem);
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_sem);
-		return error;
-	}
+        //        down(&dir->d_inode->i_zombie);
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                //                up(&dir->d_inode->i_zombie);
+                return error;
+        }
         error = -ENOENT;
         inode = old_dentry->d_inode;
         if (!inode)
@@ -600,7 +763,7 @@
                 goto exit_lock;
 
         error = -EXDEV;
-        if (dir->d_inode->i_sb != inode->i_sb)
+        if (dir->d_inode->i_dev != inode->i_dev)
                 goto exit_lock;
 
         /*
@@ -620,10 +783,10 @@
 
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_LINK);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_LINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_link: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_link: no space for transaction\n");
                 return -ENOSPC;
         }
 
@@ -636,33 +799,38 @@
                 goto exit_lock;
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit_lock;
-        }
-        error = presto_settime(fset, new_dentry, info, ATTR_CTIME);
+        /* link dd data to that of existing dentry */
+        old_dentry->d_op->d_release(new_dentry); 
+        if (!presto_d2d(old_dentry)) 
+                BUG();
+        presto_d2d(old_dentry)->dd_count++;
+
+        new_dentry->d_fsdata = presto_d2d(old_dentry);
+
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, new_dentry,
+                               info, ATTR_CTIME);
         if (error) { 
                 EXIT;
                 goto exit_lock;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x10);
         presto_getversion(&new_link_ver, new_dentry->d_inode);
-        if ( presto_do_kml(info, old_dentry->d_inode) )
+        if ( presto_do_kml(info, old_dentry) )
                 error = presto_journal_link(&rec, fset, old_dentry, new_dentry,
                                             &tgt_dir_ver, &new_link_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x20);
-        if ( presto_do_expect(info, old_dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x20);
+        if ( presto_do_rcvd(info, old_dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x30);
         EXIT;
         presto_trans_commit(fset, handle);
 exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-        up(&dir->d_inode->i_sem);
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        //        up(&dir->d_inode->i_zombie);
         return error;
 }
 
@@ -671,68 +839,68 @@
                          struct lento_vfs_context *info)
 {
         int error;
-	struct dentry *new_dentry;
-	struct nameidata nd, old_nd;
         char * to;
         struct presto_file_set *fset;
 
         to = getname(newname);
-        if(IS_ERR(to))
-                return PTR_ERR(to);
+        error = PTR_ERR(to);
+        if (!IS_ERR(to)) {
+                struct dentry *new_dentry;
+                struct nameidata nd, old_nd;
 
-	error = __user_walk(oldname, 0, &old_nd);
-	if (error)
-		goto exit;
-	error = path_lookup(to, LOOKUP_PARENT, &nd);
-	if (error)
-		goto out;
-	error = -EXDEV;
-	if (old_nd.mnt != nd.mnt)
-		goto out;
-	new_dentry = lookup_create(&nd, 0);
-	error = PTR_ERR(new_dentry);
-
-	if (!IS_ERR(new_dentry)) {
-		fset = presto_fset(new_dentry);
-		error = -EINVAL;
-		if ( !fset ) {
-			printk("No fileset!\n");
-			EXIT;
-			goto out2;
-		}
-		error = presto_do_link(fset, old_nd.dentry, 
-				       nd.dentry,
-				       new_dentry, info);
-		dput(new_dentry);
-	}
-out2:
-	up(&nd.dentry->d_inode->i_sem);
-	path_release(&nd);
-out:
-	path_release(&old_nd);
-exit:
-	putname(to);
+                error = __user_walk(oldname, 0, &old_nd);
+                if (error)
+                        goto exit;
+                error = path_lookup(to, LOOKUP_PARENT, &nd);
+                if (error)
+                        goto out;
+                error = -EXDEV;
+                if (old_nd.mnt != nd.mnt)
+                        goto out;
+                new_dentry = lookup_create(&nd, 0);
+                error = PTR_ERR(new_dentry);
 
+                if (!IS_ERR(new_dentry)) {
+                        fset = presto_fset(new_dentry);
+                        error = -EINVAL;
+                        if ( !fset ) {
+                                CERROR("No fileset!\n");
+                                EXIT;
+                                goto out2;
+                        }
+                        error = presto_do_link(fset, old_nd.dentry, 
+                                               nd.dentry,
+                                               new_dentry, info);
+                        dput(new_dentry);
+                }
+        out2:
+                up(&nd.dentry->d_inode->i_sem);
+                path_release(&nd);
+        out:
+                path_release(&old_nd);
+        exit:
+                putname(to);
+        }
         return error;
 }
 
-
 int presto_do_unlink(struct presto_file_set *fset, struct dentry *dir,
                      struct dentry *dentry, struct lento_vfs_context *info)
 {
         struct rec_info rec;
-        int error;
         struct inode_operations *iops;
         struct presto_version tgt_dir_ver, old_file_ver;
+        struct izo_rollback_data rb;
         void *handle;
-        int do_kml = 0, do_expect =0;
-	int linkno = 0;
+        int do_kml = 0, do_rcvd = 0, linkno = 0, error, old_targetlen = 0;
+        char *old_target = NULL;
+
         ENTRY;
-        down(&dir->d_inode->i_sem);
+        //        down(&dir->d_inode->i_zombie);
         error = may_delete(dir->d_inode, dentry, 0);
         if (error) {
                 EXIT;
-                up(&dir->d_inode->i_sem);
+                //                up(&dir->d_inode->i_zombie);
                 return error;
         }
 
@@ -740,24 +908,39 @@
         iops = filter_c2cdiops(fset->fset_cache->cache_filter);
         if (!iops->unlink) {
                 EXIT;
-                up(&dir->d_inode->i_sem);
+                //                up(&dir->d_inode->i_zombie);
+                return error;
+        }
+
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQLOW); 
+        if (error) {
+                EXIT;
+                //                up(&dir->d_inode->i_zombie);
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQLOW); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_sem);
-		return error;
-	}
+
+        if (presto_d2d(dentry)) { 
+                struct presto_dentry_data *dd = presto_d2d(dentry); 
+                struct dentry *de = dd->dd_inodentry;
+                if (de && dentry->d_inode->i_nlink == 1) { 
+                        dd->dd_count--;
+                        dd->dd_inodentry = NULL; 
+                        de->d_fsdata = NULL; 
+                        atomic_dec(&de->d_inode->i_count); 
+                        de->d_inode = NULL;
+                        dput(de); 
+                }
+        }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
         presto_getversion(&old_file_ver, dentry->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_UNLINK);
+        izo_get_rollback_data(dentry->d_inode, &rb);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_UNLINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
-                printk("ERROR: presto_do_unlink: no space for transaction. Tell Peter.\n");
-                up(&dir->d_inode->i_sem);
+                presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
+                CERROR("ERROR: presto_do_unlink: no space for transaction. Tell Peter.\n");
+                //                up(&dir->d_inode->i_zombie);
                 return -ENOSPC;
         }
         DQUOT_INIT(dir->d_inode);
@@ -765,12 +948,45 @@
                 error = -EBUSY;
         else {
                 lock_kernel();
-		linkno = dentry->d_inode->i_nlink;
-		if (linkno > 1) {
-			dget(dentry);
-		}
-                do_kml = presto_do_kml(info, dir->d_inode);
-                do_expect = presto_do_expect(info, dir->d_inode);
+                linkno = dentry->d_inode->i_nlink;
+                if (linkno > 1) {
+                        dget(dentry);
+                }
+
+                if (S_ISLNK(dentry->d_inode->i_mode)) {
+                        mm_segment_t old_fs;
+                        struct inode_operations *riops;
+                        riops = filter_c2csiops(fset->fset_cache->cache_filter);
+
+                        PRESTO_ALLOC(old_target, PATH_MAX);
+                        if (old_target == NULL) {
+                                error = -ENOMEM;
+                                EXIT;
+                                goto exit;
+                        }
+
+                        old_fs = get_fs();
+                        set_fs(get_ds());
+
+                        if (riops->readlink == NULL)
+                                CERROR("InterMezzo %s: no readlink iops.\n",
+                                       __FUNCTION__);
+                        else
+                                old_targetlen =
+                                        riops->readlink(dentry, old_target,
+                                                        PATH_MAX);
+                        if (old_targetlen < 0) {
+                                CERROR("InterMezzo: readlink failed: %ld\n",
+                                       PTR_ERR(old_target));
+                                PRESTO_FREE(old_target, PATH_MAX);
+                                old_target = NULL;
+                                old_targetlen = 0;
+                        }
+                        set_fs(old_fs);
+                }
+
+                do_kml = presto_do_kml(info, dir);
+                do_rcvd = presto_do_rcvd(info, dir);
                 error = iops->unlink(dir->d_inode, dentry);
                 unlock_kernel();
                 if (!error)
@@ -778,7 +994,9 @@
         }
 
         if (linkno > 1) { 
-                error = presto_settime(fset, dentry, info, ATTR_CTIME);
+                /* FIXME: Combine this with the next call? */
+                error = presto_settime(fset, NULL, NULL, dentry,
+                                       info, ATTR_CTIME);
                 dput(dentry); 
                 if (error) { 
                         EXIT;
@@ -786,34 +1004,35 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dir,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
-        up(&dir->d_inode->i_sem);
+        //        up(&dir->d_inode->i_zombie);
         if (error) {
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x10);
-        if ( do_kml ) { 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x10);
+        if ( do_kml )
                 error = presto_journal_unlink(&rec, fset, dir, &tgt_dir_ver,
-                                              &old_file_ver,
-                                              dentry->d_name.len,
-                                              dentry->d_name.name);
-	}
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x20);
-        if ( do_expect ) { 
+                                              &old_file_ver, &rb, dentry,
+                                              old_target, old_targetlen);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x20);
+        if ( do_rcvd ) { 
                 error = presto_write_last_rcvd(&rec, fset, info);
-	}
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x30);
+        }
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x30);
         EXIT;
 exit:
-	presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
+        presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
         presto_trans_commit(fset, handle);
+        if (old_target != NULL)
+                PRESTO_FREE(old_target, PATH_MAX);
         return error;
 }
 
@@ -845,7 +1064,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit2;
                 }
@@ -882,14 +1101,14 @@
         void *handle;
 
         ENTRY;
-        down(&dir->d_inode->i_sem);
-	/* record + max path len + space to free */ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_sem);
-		return error;
-	}
+        //        down(&dir->d_inode->i_zombie);
+        /* record + max path len + space to free */ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        if (error) {
+                EXIT;
+                //                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         error = may_create(dir->d_inode, dentry);
         if (error) {
@@ -905,11 +1124,12 @@
         }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_SYMLINK);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_SYMLINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-                printk("ERROR: presto_do_symlink: no space for transaction. Tell Peter.\n"); 
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+                CERROR("ERROR: presto_do_symlink: no space for transaction. Tell Peter.\n"); 
                 EXIT;
+                //                up(&dir->d_inode->i_zombie);
                 return -ENOSPC;
         }
         DQUOT_INIT(dir->d_inode);
@@ -920,8 +1140,7 @@
                 goto exit;
         }
 
-        if (dentry->d_inode &&
-            dentry->d_inode->i_gid != presto_excluded_gid) {
+        if (dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
                 
                 presto_set_ops(dentry->d_inode, cache->cache_filter);
@@ -937,35 +1156,32 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x10);
         presto_getversion(&new_link_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_symlink(&rec, fset, dentry, oldname,
                                                &tgt_dir_ver, &new_link_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x30);
         EXIT;
 exit:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-        up(&dir->d_inode->i_sem);
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        //        up(&dir->d_inode->i_zombie);
         return error;
 }
 
@@ -1004,7 +1220,7 @@
         dentry = lookup_create(&nd, 0);
         error = PTR_ERR(dentry);
         if (IS_ERR(dentry)) {
-        	path_release(&nd);
+                path_release(&nd);
                 EXIT;
                 goto exit_to;
         }
@@ -1012,8 +1228,8 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
-        	path_release(&nd);
+                CERROR("No fileset!\n");
+                path_release(&nd);
                 EXIT;
                 goto exit_lock;
         }
@@ -1043,12 +1259,13 @@
         void *handle;
 
         ENTRY;
-        down(&dir->d_inode->i_sem);
-	/* one journal record + directory block + room for removals*/ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-	if (error) { 
+        //        down(&dir->d_inode->i_zombie);
+
+        /* one journal record + directory block + room for removals*/ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        if (error) { 
                 EXIT;
-        	up(&dir->d_inode->i_sem);
+                //                up(&dir->d_inode->i_zombie);
                 return error;
         }
 
@@ -1066,10 +1283,10 @@
 
         error = -ENOSPC;
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_MKDIR);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_MKDIR);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-                printk("presto_do_mkdir: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+                CERROR("presto_do_mkdir: no space for transaction\n");
                 goto exit_lock;
         }
 
@@ -1082,8 +1299,7 @@
                 goto exit;
         }
 
-        if ( dentry->d_inode && !error && 
-             dentry->d_inode->i_gid != presto_excluded_gid) {
+        if ( dentry->d_inode && !error) {
                 struct presto_cache *cache = fset->fset_cache;
 
                 presto_set_ops(dentry->d_inode, cache->cache_filter);
@@ -1100,36 +1316,33 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                             info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x10);
         presto_getversion(&new_dir_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dir) )
                 error = presto_journal_mkdir(&rec, fset, dentry, &tgt_dir_ver,
                                              &new_dir_ver, 
-					     dentry->d_inode->i_mode);
+                                             dentry->d_inode->i_mode);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x30);
         EXIT;
 exit:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-        up(&dir->d_inode->i_sem);
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        //        up(&dir->d_inode->i_zombie);
         return error;
 }
 
@@ -1164,8 +1377,8 @@
         if (!IS_ERR(dentry)) {
                 fset = presto_fset(dentry);
                 error = -EINVAL;
-                if ( !fset ) {
-                        printk("No fileset!\n");
+                if (!fset) {
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto out_dput;
                 }
@@ -1173,14 +1386,14 @@
                 error = presto_do_mkdir(fset, nd.dentry, dentry, 
                                         mode & S_IALLUGO, info);
 out_dput:
-		dput(dentry);
+                dput(dentry);
         }
-	up(&nd.dentry->d_inode->i_sem);
-	path_release(&nd);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
 out_name:
         EXIT;
         putname(pathname);
-	CDEBUG(D_PIOCTL, "error: %d\n", error);
+        CDEBUG(D_PIOCTL, "error: %d\n", error);
         return error;
 }
 
@@ -1203,10 +1416,11 @@
         struct rec_info rec;
         int error;
         struct presto_version tgt_dir_ver, old_dir_ver;
+        struct izo_rollback_data rb;
         struct inode_operations *iops;
         void *handle;
-        int do_kml, do_expect;
-	int size;
+        int do_kml, do_rcvd;
+        int size;
 
         ENTRY;
         error = may_delete(dir->d_inode, dentry, 1);
@@ -1220,64 +1434,67 @@
                 return error;
         }
 
-	size = PRESTO_REQHIGH - dentry->d_inode->i_size; 
-	error = presto_reserve_space(fset->fset_cache, size); 
-	if (error) { 
-		EXIT;
-		return error;
-	}
+        size = PRESTO_REQHIGH - dentry->d_inode->i_size; 
+        error = presto_reserve_space(fset->fset_cache, size); 
+        if (error) { 
+                EXIT;
+                return error;
+        }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
         presto_getversion(&old_dir_ver, dentry->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_RMDIR);
+        izo_get_rollback_data(dentry->d_inode, &rb);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_RMDIR);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, size); 
-                printk("ERROR: presto_do_rmdir: no space for transaction. Tell Peter.\n");
+                presto_release_space(fset->fset_cache, size); 
+                CERROR("ERROR: presto_do_rmdir: no space for transaction. Tell Peter.\n");
                 return -ENOSPC;
         }
 
         DQUOT_INIT(dir->d_inode);
 
-        do_kml = presto_do_kml(info, dir->d_inode);
-        do_expect = presto_do_expect(info, dir->d_inode);
+        do_kml = presto_do_kml(info, dir);
+        do_rcvd = presto_do_rcvd(info, dir);
 
-        double_down(&dir->d_inode->i_sem, &dentry->d_inode->i_sem);
+        //        double_down(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie);
         d_unhash(dentry);
         if (IS_DEADDIR(dir->d_inode))
                 error = -ENOENT;
-        else if (d_mountpoint(dentry))
+        else if (d_mountpoint(dentry)) {
+                CERROR("foo: d_mountpoint(dentry): ino %ld\n",
+                       dentry->d_inode->i_ino);
                 error = -EBUSY;
-        else {
+        } else {
                 lock_kernel();
                 error = iops->rmdir(dir->d_inode, dentry);
                 unlock_kernel();
                 if (!error) {
                         dentry->d_inode->i_flags |= S_DEAD;
-			error = presto_settime(fset, dir, info, 
-					       ATTR_CTIME | ATTR_MTIME);
-		}
+                        error = presto_settime(fset, NULL, NULL, dir, info,
+                                               ATTR_CTIME | ATTR_MTIME);
+                }
         }
-        double_up(&dir->d_inode->i_sem, &dentry->d_inode->i_sem);
+        //        double_up(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie);
         if (!error)
                 d_delete(dentry);
         dput(dentry);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x10);
         if ( !error && do_kml )
                 error = presto_journal_rmdir(&rec, fset, dir, &tgt_dir_ver,
-                                             &old_dir_ver,
+                                             &old_dir_ver, &rb,
                                              dentry->d_name.len,
                                              dentry->d_name.name);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x20);
-        if ( !error && do_expect ) 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x20);
+        if ( !error && do_rcvd ) 
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x30);
         EXIT;
 
         presto_trans_commit(fset, handle);
-	presto_release_space(fset->fset_cache, size); 
+        presto_release_space(fset->fset_cache, size); 
         return error;
 }
 
@@ -1291,20 +1508,26 @@
 
         ENTRY;
         name = getname(pathname);
-        if(IS_ERR(name))
+        if(IS_ERR(name)) {
+                EXIT;
                 return PTR_ERR(name);
+        }
 
         error = path_lookup(name, LOOKUP_PARENT, &nd);
-        if (error)
+        if (error) {
+                EXIT;
                 goto exit;
-
+        }
         switch(nd.last_type) {
-                case LAST_DOTDOT:
-                        error = -ENOTEMPTY;
-                        goto exit1;
-                case LAST_ROOT: case LAST_DOT:
-                        error = -EBUSY;
-                        goto exit1;
+        case LAST_DOTDOT:
+                error = -ENOTEMPTY;
+                EXIT;
+                goto exit1;
+        case LAST_ROOT:
+        case LAST_DOT:
+                error = -EBUSY;
+                EXIT;
+                goto exit1;
         }
         down(&nd.dentry->d_inode->i_sem);
         dentry = lookup_hash(&nd.last, nd.dentry);
@@ -1313,7 +1536,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit_put;
                 }
@@ -1323,11 +1546,10 @@
         }
         up(&nd.dentry->d_inode->i_sem);
 exit1:
-        EXIT;
         path_release(&nd);
 exit:
-        EXIT;
         putname(name);
+        EXIT;
         return error;
 }
 
@@ -1343,14 +1565,14 @@
 
         ENTRY;
 
-        down(&dir->d_inode->i_sem);
-	/* one KML entry */ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_sem);
-		return error;
-	}
+        //        down(&dir->d_inode->i_zombie);
+        /* one KML entry */ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                //                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) {
                 EXIT;
@@ -1375,16 +1597,19 @@
         
         error = -ENOSPC;
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_MKNOD);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_MKNOD);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_mknod: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_mknod: no space for transaction\n");
                 goto exit_lock2;
         }
 
         error = iops->mknod(dir->d_inode, dentry, mode, dev);
-        if ( dentry->d_inode &&
-             dentry->d_inode->i_gid != presto_excluded_gid) {
+        if (error) {
+                EXIT;
+                goto exit_commit;
+        }
+        if ( dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
 
                 presto_set_ops(dentry->d_inode, cache->cache_filter);
@@ -1401,35 +1626,38 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dir,
+                               info, ATTR_MTIME);
         if (error) { 
                 EXIT;
         }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x10);
         presto_getversion(&new_node_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_mknod(&rec, fset, dentry, &tgt_dir_ver,
                                              &new_node_ver, 
-					     dentry->d_inode->i_mode,
+                                             dentry->d_inode->i_mode,
                                              MAJOR(dev), MINOR(dev) );
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) ) 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x30);
         EXIT;
+ exit_commit:
         presto_trans_commit(fset, handle);
  exit_lock2:
         unlock_kernel();
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-        up(&dir->d_inode->i_sem);
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        //        up(&dir->d_inode->i_zombie);
         return error;
 }
 
@@ -1459,7 +1687,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit_put;
                 }
@@ -1488,7 +1716,7 @@
         return error;
 }
 
-static int do_rename(struct presto_file_set *fset,
+int do_rename(struct presto_file_set *fset,
                      struct dentry *old_parent, struct dentry *old_dentry,
                      struct dentry *new_parent, struct dentry *new_dentry,
                      struct lento_vfs_context *info)
@@ -1498,7 +1726,7 @@
         struct inode_operations *iops;
         struct presto_version src_dir_ver, tgt_dir_ver;
         void *handle;
-	int new_inode_unlink = 0;
+        int new_inode_unlink = 0;
         struct inode *old_dir = old_parent->d_inode;
         struct inode *new_dir = new_parent->d_inode;
 
@@ -1513,15 +1741,15 @@
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-		return error;
-	}
-        handle = presto_trans_start(fset, old_dir, PRESTO_OP_RENAME);
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                return error;
+        }
+        handle = presto_trans_start(fset, old_dir, KML_OPCODE_RENAME);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_rename: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_rename: no space for transaction\n");
                 return -ENOSPC;
         }
         if (new_dentry->d_inode && new_dentry->d_inode->i_nlink > 1) { 
@@ -1537,19 +1765,17 @@
         }
 
         if (new_inode_unlink) { 
-                error = presto_settime(fset, old_dentry, info, ATTR_CTIME);
+                error = presto_settime(fset, NULL, NULL, old_dentry,
+                                       info, ATTR_CTIME);
                 dput(old_dentry); 
                 if (error) { 
                         EXIT;
                         goto exit;
                 }
         }
-        error = presto_settime(fset, old_parent, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, new_parent, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, new_parent, old_parent,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
@@ -1558,21 +1784,22 @@
         /* XXX make a distinction between cross file set
          * and intra file set renames here
          */
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x10);
-        if ( presto_do_kml(info, old_dir) )
-                error = presto_journal_rename(&rec, fset, old_dentry, new_dentry,
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x10);
+        if ( presto_do_kml(info, old_dentry) )
+                error = presto_journal_rename(&rec, fset, old_dentry,
+                                              new_dentry,
                                               &src_dir_ver, &tgt_dir_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x20);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x20);
 
-        if ( presto_do_expect(info, new_dir) ) 
+        if ( presto_do_rcvd(info, old_dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x30);
         EXIT;
 exit:
         presto_trans_commit(fset, handle);
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         return error;
 }
 
@@ -1593,7 +1820,7 @@
         if (error)
                 return error;
 
-        if (new_dir->i_sb != old_dir->i_sb)
+        if (new_dir->i_dev != old_dir->i_dev)
                 return -EXDEV;
 
         if (!new_dentry->d_inode)
@@ -1624,13 +1851,13 @@
                 goto out_unlock;
         target = new_dentry->d_inode;
         if (target) { /* Hastur! Hastur! Hastur! */
-                triple_down(&old_dir->i_sem,
-                            &new_dir->i_sem,
-                            &target->i_sem);
+                //                triple_down(&old_dir->i_zombie,
+                //                            &new_dir->i_zombie,
+                //                            &target->i_zombie);
                 d_unhash(new_dentry);
         } else
-                double_down(&old_dir->i_sem,
-                            &new_dir->i_sem);
+                //                double_down(&old_dir->i_zombie,
+                //                            &new_dir->i_zombie);
         if (IS_DEADDIR(old_dir)||IS_DEADDIR(new_dir))
                 error = -ENOENT;
         else if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
@@ -1641,15 +1868,15 @@
         if (target) {
                 if (!error)
                         target->i_flags |= S_DEAD;
-                triple_up(&old_dir->i_sem,
-                          &new_dir->i_sem,
-                          &target->i_sem);
+                //                triple_up(&old_dir->i_zombie,
+                //                          &new_dir->i_zombie,
+                //                          &target->i_zombie);
                 if (d_unhashed(new_dentry))
                         d_rehash(new_dentry);
                 dput(new_dentry);
         } else
-                double_up(&old_dir->i_sem,
-                          &new_dir->i_sem);
+                //                double_up(&old_dir->i_zombie,
+                //                          &new_dir->i_zombie);
                 
         if (!error)
                 d_move(old_dentry,new_dentry);
@@ -1674,7 +1901,7 @@
         if (error)
                 return error;
 
-        if (new_dir->i_sb != old_dir->i_sb)
+        if (new_dir->i_dev != old_dir->i_dev)
                 return -EXDEV;
 
         if (!new_dentry->d_inode)
@@ -1689,13 +1916,13 @@
 
         DQUOT_INIT(old_dir);
         DQUOT_INIT(new_dir);
-        double_down(&old_dir->i_sem, &new_dir->i_sem);
+        //        double_down(&old_dir->i_zombie, &new_dir->i_zombie);
         if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
                 error = -EBUSY;
         else
                 error = do_rename(fset, old_parent, old_dentry,
-                                         new_parent, new_dentry, info);
-        double_up(&old_dir->i_sem, &new_dir->i_sem);
+                                  new_parent, new_dentry, info);
+        //        double_up(&old_dir->i_zombie, &new_dir->i_zombie);
         if (error)
                 return error;
         /* The following d_move() should become unconditional */
@@ -1731,7 +1958,6 @@
         ENTRY;
 
         error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
-
         if (error)
                 goto exit;
 
@@ -1752,7 +1978,7 @@
         if (newnd.last_type != LAST_NORM)
                 goto exit2;
 
-        double_lock(new_dir, old_dir);
+        lock_rename(new_dir, old_dir);
 
         old_dentry = lookup_hash(&oldnd.last, old_dir);
         error = PTR_ERR(old_dentry);
@@ -1765,7 +1991,7 @@
         fset = presto_fset(old_dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit4;
         }
@@ -1791,7 +2017,7 @@
 exit4:
         dput(old_dentry);
 exit3:
-        double_up(&new_dir->d_inode->i_sem, &old_dir->d_inode->i_sem);
+        unlock_rename(new_dir, old_dir);
 exit2:
         path_release(&newnd);
 exit1:
@@ -1815,7 +2041,7 @@
         if (!IS_ERR(to)) {
                 error = lento_do_rename(from,to, info);
                 putname(to);
-        }
+        } 
         putname(from);
         return error;
 }
@@ -1842,7 +2068,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if (!fset) {
-                printk("No fileset for %*s!\n",
+                CERROR("No fileset for %*s!\n",
                        dentry->d_name.len, dentry->d_name.name);
                 EXIT;
                 dput(dentry);
@@ -1853,7 +2079,7 @@
         sprintf(name, "%s%#lx%c%#x",
                 PRESTO_ILOOKUP_MAGIC, ino, PRESTO_ILOOKUP_SEP, generation);
         CDEBUG(D_PIOCTL, "opening %ld by number (as %s)\n", ino, name);
-        return lookup_one_len(name, fset->fset_mtpt, strlen(name));
+        return lookup_one_len(name, fset->fset_dentry, strlen(name));
 }
 
 static struct file *presto_filp_dopen(struct dentry *dentry, int flags)
@@ -1877,13 +2103,13 @@
                 error = get_write_access(inode);
                 if (error) {
                         CDEBUG(D_PIOCTL, "error getting write access\n");
-                        EXIT;
-                        goto cleanup_file;
+                        EXIT;                        goto cleanup_file;
                 }
         }
 
         f->f_dentry = dentry;
         f->f_pos = 0;
+        //f->f_reada = 0;
         f->f_op = NULL;
         if (inode->i_op)
                 /* XXX should we set to presto ops, or leave at cache ops? */
@@ -1931,8 +2157,8 @@
          * just turn off the flag and ignore it.
          */
         if (flags & O_CREAT) {
-                printk(KERN_WARNING __FUNCTION__
-                       ": create file by inode number (%ld) not allowed\n",ino);
+                CERROR("%s: create file by inode number (%ld) not allowed\n",
+                       __FUNCTION__, ino);
                 EXIT;
                 return -EACCES;
         }
@@ -1948,6 +2174,7 @@
         error = presto_walk(tmp, &nd);
         if ( error && error != -ENOENT ) {
                 EXIT;
+                unlock_kernel();
                 return error;
         } 
         if (error == -ENOENT)
@@ -1962,7 +2189,7 @@
                 slash = strrchr(tmp, '/');
                 if (slash && slash != tmp) {
                         *slash = '\0';
-			path_release(&nd);
+                        path_release(&nd);
                         goto again;
                 }
                 /* we should never get here... */
@@ -2014,7 +2241,7 @@
         EXIT;
 exit:
         unlock_kernel();
-	path_release(&nd);
+        path_release(&nd);
         putname(tmp);
         return fd;
 
@@ -2023,72 +2250,6 @@
         goto exit;
 }
 
-int lento_close(unsigned int fd, struct lento_vfs_context *info)
-{
-        struct rec_info rec;
-        int error;
-        struct file * filp;
-        struct dentry *dentry;
-        int do_kml, do_expect;
-
-        ENTRY;
-        lock_kernel();
-
-        error = -EBADF;
-        filp = fcheck(fd);
-        if (filp) {
-
-                struct files_struct * files = current->files;
-                dentry = filp->f_dentry;
-                dget(dentry);
-                do_kml = presto_do_kml(info, dentry->d_inode);
-                do_expect = presto_do_expect(info, dentry->d_inode);
-                files->fd[fd] = NULL;
-                put_unused_fd(fd);
-                FD_CLR(fd, files->close_on_exec);
-                error = filp_close(filp, files);
-        } else {
-                EXIT;
-                return error;
-        }
-
-        if (error) {
-                EXIT;
-                goto exit;
-        }
-
-        if ( do_kml ) { 
-                struct presto_file_set *fset;
-                struct presto_version new_file_ver;
-
-                fset = presto_fset(dentry);
-                error = -EINVAL;
-                if (!fset) {
-                        printk("No fileset for %*s!\n",
-                               dentry->d_name.len, dentry->d_name.name);
-                        EXIT;
-                        goto exit;
-                }
-                presto_getversion(&new_file_ver, dentry->d_inode);
-                error = presto_journal_close(&rec, fset, filp, dentry, 
-					     &new_file_ver);
-                if ( error ) {
-                        printk("presto: close error %d!\n", error);
-                        EXIT;
-                        goto exit;
-                }
-                if ( do_expect ) 
-
-                        error = presto_write_last_rcvd(&rec, fset, info);
-        }
-
-        EXIT;
-exit:
-        dput(dentry);
-        unlock_kernel();
-        return error;
-}
-
 #ifdef CONFIG_FS_EXT_ATTR
 
 #ifdef CONFIG_FS_POSIX_ACL
@@ -2216,9 +2377,9 @@
         }
 
         
-        handle = presto_trans_start(fset,dentry->d_inode,PRESTO_OP_SETEXTATTR);
+        handle = presto_trans_start(fset,dentry->d_inode,KML_OPCODE_SETEXTATTR);
         if ( IS_ERR(handle) ) {
-                printk("presto_do_set_ext_attr: no space for transaction\n");
+                CERROR("presto_do_set_ext_attr: no space for transaction\n");
                 presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
                 return -ENOSPC;
         }
@@ -2247,15 +2408,15 @@
 #endif
 
         /* Reset ctime. Only inode change time (ctime) is affected */
-        error = presto_settime(fset, dentry, info, ATTR_CTIME);
+        error = presto_settime(fset, NULL, NULL, dentry, info, ATTR_CTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
         if (flags & EXT_ATTR_FLAG_USER) {
-                printk(" USER flag passed to presto_do_set_ext_attr!\n");
-                *(int *)0 = 1;
+                CERROR(" USER flag passed to presto_do_set_ext_attr!\n");
+                BUG();
         }
 
         /* We are here, so set_ext_attr succeeded. We no longer need to keep
@@ -2264,17 +2425,17 @@
          */
         flags &= ~(EXT_ATTR_FLAG_EXISTS | EXT_ATTR_FLAG_CREATE);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x10);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x10);
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_set_ext_attr
                         (&rec, fset, dentry, &ver, name, buffer, 
                          buffer_len, flags);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x30);
         EXIT;
 exit:
         presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
diff -Nru a/fs/iobuf.c b/fs/iobuf.c
--- a/fs/iobuf.c	Tue Oct 15 20:29:20 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,125 +0,0 @@
-/*
- * iobuf.c
- *
- * Keep track of the general-purpose IO-buffer structures used to track
- * abstract kernel-space io buffers.
- * 
- */
-
-#include <linux/iobuf.h>
-#include <linux/slab.h>
-
-int end_kio_request(struct kiobuf *kiobuf, int uptodate)
-{
-	int ret = 1;
-
-	if ((!uptodate) && !kiobuf->errno)
-		kiobuf->errno = -EIO;
-
-	if (atomic_dec_and_test(&kiobuf->io_count)) {
-		ret = 0;
-		if (kiobuf->end_io)
-			kiobuf->end_io(kiobuf);
-		wake_up(&kiobuf->wait_queue);
-	}
-
-	return ret;
-}
-
-static void kiobuf_init(struct kiobuf *iobuf)
-{
-	init_waitqueue_head(&iobuf->wait_queue);
-	atomic_set(&iobuf->io_count, 0);
-	iobuf->array_len = KIO_STATIC_PAGES;
-	iobuf->maplist   = iobuf->map_array;
-	iobuf->nr_pages   = 0;
-	iobuf->locked   = 0;
-	iobuf->io_count.counter   = 0;
-	iobuf->end_io = NULL;
-}
-
-int alloc_kiovec(int nr, struct kiobuf **bufp)
-{
-	int i;
-	struct kiobuf *iobuf;
-	
-	for (i = 0; i < nr; i++) {
-		iobuf = kmalloc(sizeof(struct kiobuf), GFP_KERNEL);
-		if (!iobuf) {
-			free_kiovec(i, bufp);
-			return -ENOMEM;
-		}
-		kiobuf_init(iobuf);
-		bufp[i] = iobuf;
-	}
-	
-	return 0;
-}
-
-void free_kiovec(int nr, struct kiobuf **bufp) 
-{
-	int i;
-	struct kiobuf *iobuf;
-	
-	for (i = 0; i < nr; i++) {
-		iobuf = bufp[i];
-		if (iobuf->locked)
-			unlock_kiovec(1, &iobuf);
-		if (iobuf->array_len > KIO_STATIC_PAGES)
-			kfree (iobuf->maplist);
-		kfree(bufp[i]);
-	}
-}
-
-int expand_kiobuf(struct kiobuf *iobuf, int wanted)
-{
-	struct page ** maplist;
-	
-	if (iobuf->array_len >= wanted)
-		return 0;
-	
-	maplist = (struct page **) 
-		kmalloc(wanted * sizeof(struct page **), GFP_KERNEL);
-	if (!maplist)
-		return -ENOMEM;
-
-	/* Did it grow while we waited? */
-	if (iobuf->array_len >= wanted) {
-		kfree(maplist);
-		return 0;
-	}
-	
-	memcpy (maplist, iobuf->maplist, iobuf->array_len * sizeof(struct page **));
-
-	if (iobuf->array_len > KIO_STATIC_PAGES)
-		kfree (iobuf->maplist);
-	
-	iobuf->maplist   = maplist;
-	iobuf->array_len = wanted;
-	return 0;
-}
-
-
-void kiobuf_wait_for_io(struct kiobuf *kiobuf)
-{
-	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
-
-	if (atomic_read(&kiobuf->io_count) == 0)
-		return;
-
-	add_wait_queue(&kiobuf->wait_queue, &wait);
-repeat:
-	set_task_state(tsk, TASK_UNINTERRUPTIBLE);
-	if (atomic_read(&kiobuf->io_count) != 0) {
-		blk_run_queues();
-		schedule();
-		if (atomic_read(&kiobuf->io_count) != 0)
-			goto repeat;
-	}
-	tsk->state = TASK_RUNNING;
-	remove_wait_queue(&kiobuf->wait_queue, &wait);
-}
-
-
-
diff -Nru a/fs/jffs/intrep.c b/fs/jffs/intrep.c
--- a/fs/jffs/intrep.c	Tue Oct 15 20:29:17 2002
+++ b/fs/jffs/intrep.c	Tue Oct 15 20:29:17 2002
@@ -3379,10 +3379,7 @@
 			unsigned long signr = 0;
 
 			spin_lock_irq(&current->sig->siglock);
-			if (current->sig->shared_pending.head)
-				signr = dequeue_signal(&current->sig->shared_pending, &info);
-			if (!signr)
-				signr = dequeue_signal(&current->pending, &info);
+			signr = dequeue_signal(&current->blocked, &info);
 			spin_unlock_irq(&current->sig->siglock);
 
 			switch(signr) {
diff -Nru a/fs/jffs2/background.c b/fs/jffs2/background.c
--- a/fs/jffs2/background.c	Tue Oct 15 20:29:11 2002
+++ b/fs/jffs2/background.c	Tue Oct 15 20:29:11 2002
@@ -66,7 +66,7 @@
 		/* stop a eventually scheduled wbuf flush timer */
 		del_timer_sync(&c->wbuf_timer);
 		/* make sure, that a scheduled wbuf flush task is completed */
-		flush_scheduled_tasks();
+		flush_scheduled_work();
 	}
 
 	spin_lock_bh(&c->erase_completion_lock);
@@ -115,10 +115,7 @@
                         unsigned long signr = 0 ;
 
                         spin_lock_irq(&current->sig->siglock);
-			if (current->sig->shared_pending.head)
-				signr = dequeue_signal(&current->sig->shared_pending, &info);
-			if (!signr)
-				signr = dequeue_signal(&current->pending, &info);
+			signr = dequeue_signal(&current->blocked, &info);
                         spin_unlock_irq(&current->sig->siglock);
 
                         switch(signr) {
diff -Nru a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
--- a/fs/jfs/jfs_dtree.c	Tue Oct 15 20:29:19 2002
+++ b/fs/jfs/jfs_dtree.c	Tue Oct 15 20:29:19 2002
@@ -490,11 +490,11 @@
 }
 
 /*
- *	get_index()
+ *	read_index()
  *
  *	reads a directory table slot
  */
-static int get_index(struct inode *ip, u32 index,
+static int read_index(struct inode *ip, u32 index,
 		     struct dir_table_slot * dirtab_slot)
 {
 	struct metapage *mp = 0;
@@ -2978,7 +2978,7 @@
 				return 0;
 			}
 		      repeat:
-			rc = get_index(ip, dir_index, &dirtab_slot);
+			rc = read_index(ip, dir_index, &dirtab_slot);
 			if (rc) {
 				filp->f_pos = DIREND;
 				return rc;
diff -Nru a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
--- a/fs/jfs/jfs_mount.c	Tue Oct 15 20:29:14 2002
+++ b/fs/jfs/jfs_mount.c	Tue Oct 15 20:29:14 2002
@@ -478,12 +478,12 @@
 {
 	/* read in primary superblock */
 	*bpp = sb_bread(sb, SUPER1_OFF >> sb->s_blocksize_bits);
-	if (bpp)
+	if (*bpp)
 		return 0;
 
 	/* read in secondary/replicated superblock */
 	*bpp = sb_bread(sb, SUPER2_OFF >> sb->s_blocksize_bits);
-	if (bpp)
+	if (*bpp)
 		return 0;
 
 	return -EIO;
diff -Nru a/fs/msdos/namei.c b/fs/msdos/namei.c
--- a/fs/msdos/namei.c	Tue Oct 15 20:29:17 2002
+++ b/fs/msdos/namei.c	Tue Oct 15 20:29:17 2002
@@ -604,12 +604,8 @@
 	int res;
 
 	res = fat_fill_super(sb, data, silent, &msdos_dir_inode_operations, 0);
-	if (res) {
-		if (res == -EINVAL && !silent)
-			printk(KERN_INFO "VFS: Can't find a valid"
-			       " MSDOS filesystem on dev %s.\n", sb->s_id);
+	if (res)
 		return res;
-	}
 
 	sb->s_root->d_op = &msdos_dentry_operations;
 	return 0;
diff -Nru a/fs/nfs/Makefile b/fs/nfs/Makefile
--- a/fs/nfs/Makefile	Tue Oct 15 20:29:12 2002
+++ b/fs/nfs/Makefile	Tue Oct 15 20:29:12 2002
@@ -8,6 +8,7 @@
 			   proc.o read.o symlink.o unlink.o write.o
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o mount_clnt.o      
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
+nfs-$(CONFIG_NFS_V4)	+= nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o
 nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
 nfs-objs		:= $(nfs-y)
 
diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c	Tue Oct 15 20:29:17 2002
+++ b/fs/nfs/file.c	Tue Oct 15 20:29:17 2002
@@ -259,6 +259,12 @@
 	if (!inode)
 		return -EINVAL;
 
+	/* This will be in a forthcoming patch. */
+	if (NFS_PROTO(inode)->version == 4) {
+		printk(KERN_INFO "NFS: file locking over NFSv4 is not yet supported\n");
+		return -EIO;
+	}
+
 	/* No mandatory locks over NFS */
 	if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
 		return -ENOLCK;
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Tue Oct 15 20:29:20 2002
+++ b/fs/nfs/inode.c	Tue Oct 15 20:29:20 2002
@@ -28,6 +28,7 @@
 #include <linux/sunrpc/stats.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
 #include <linux/nfs_flushd.h>
 #include <linux/lockd/bind.h>
 #include <linux/smp_lock.h>
@@ -76,8 +77,13 @@
 	NULL,
 	NULL,
 	&nfs_version2,
-#ifdef CONFIG_NFS_V3
+#if defined(CONFIG_NFS_V3)
 	&nfs_version3,
+#elif defined(CONFIG_NFS_V4)
+	NULL,
+#endif
+#if defined(CONFIG_NFS_V4)
+	&nfs_version4,
 #endif
 };
 
@@ -157,6 +163,7 @@
 		lockd_down();	/* release rpc.lockd */
 	rpciod_down();		/* release rpciod */
 
+	destroy_nfsv4_state(server);
 	kfree(server->hostname);
 }
 
@@ -234,6 +241,120 @@
 }
 
 /*
+ * Do NFS version-independent mount processing, and sanity checking
+ */
+int nfs_sb_init(struct super_block *sb)
+{
+	struct nfs_server	*server;
+	struct inode		*root_inode = NULL;
+	struct nfs_fattr	fattr;
+	struct nfs_fsinfo	fsinfo = {
+					.fattr = &fattr,
+				};
+	struct nfs_pathconf pathinfo = {
+			.fattr = &fattr,
+	};
+
+	/* We probably want something more informative here */
+	snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
+
+	server = NFS_SB(sb);
+
+	sb->s_magic      = NFS_SUPER_MAGIC;
+	sb->s_op         = &nfs_sops;
+	INIT_LIST_HEAD(&server->lru_read);
+	INIT_LIST_HEAD(&server->lru_dirty);
+	INIT_LIST_HEAD(&server->lru_commit);
+	INIT_LIST_HEAD(&server->lru_busy);
+
+	/* Did getting the root inode fail? */
+	root_inode = nfs_get_root(sb, &server->fh);
+	if (!root_inode)
+		goto out_no_root;
+	sb->s_root = d_alloc_root(root_inode);
+	if (!sb->s_root)
+		goto out_no_root;
+
+	sb->s_root->d_op = &nfs_dentry_operations;
+
+	/* Get some general file system info */
+        if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
+		printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
+		goto out_no_root;
+        }
+	if (server->namelen == 0 &&
+	    server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
+		server->namelen = pathinfo.max_namelen;
+	/* Work out a lot of parameters */
+	if (server->rsize == 0)
+		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+	if (server->wsize == 0)
+		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+	if (sb->s_blocksize == 0) {
+		if (fsinfo.wtmult == 0) {
+			sb->s_blocksize = 512;
+			sb->s_blocksize_bits = 9;
+		} else
+			sb->s_blocksize = nfs_block_bits(fsinfo.wtmult,
+							 &sb->s_blocksize_bits);
+	}
+
+	if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
+		server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
+	if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
+		server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
+
+	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	if (server->rpages > NFS_READ_MAXIOV) {
+		server->rpages = NFS_READ_MAXIOV;
+		server->rsize = server->rpages << PAGE_CACHE_SHIFT;
+	}
+
+	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+        if (server->wpages > NFS_WRITE_MAXIOV) {
+		server->wpages = NFS_WRITE_MAXIOV;
+                server->wsize = server->wpages << PAGE_CACHE_SHIFT;
+	}
+
+	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+	if (server->dtsize > PAGE_CACHE_SIZE)
+		server->dtsize = PAGE_CACHE_SIZE;
+	if (server->dtsize > server->rsize)
+		server->dtsize = server->rsize;
+
+	if (server->flags & NFS_MOUNT_NOAC) {
+		server->acregmin = server->acregmax = 0;
+		server->acdirmin = server->acdirmax = 0;
+		sb->s_flags |= MS_SYNCHRONOUS;
+	}
+
+	sb->s_maxbytes = fsinfo.maxfilesize;
+	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
+		sb->s_maxbytes = MAX_LFS_FILESIZE; 
+
+	/* Fire up the writeback cache */
+	if (nfs_reqlist_alloc(server) < 0) {
+		printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
+		goto failure_kill_reqlist;
+	}
+
+	/* We're airborne Set socket buffersize */
+	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
+	return 0;
+	/* Yargs. It didn't work out. */
+failure_kill_reqlist:
+	nfs_reqlist_exit(server);
+out_free_all:
+	if (root_inode)
+		iput(root_inode);
+	nfs_reqlist_free(server);
+	return -EINVAL;
+out_no_root:
+	printk("nfs_read_super: get root inode failed\n");
+	goto out_free_all;
+}
+
+/*
  * The way this works is that the mount process passes a structure
  * in the data argument which contains the server's IP address
  * and the root file handle obtained from the server's mount
@@ -244,29 +365,20 @@
 	struct nfs_server	*server;
 	struct rpc_xprt		*xprt = NULL;
 	struct rpc_clnt		*clnt = NULL;
-	struct inode		*root_inode = NULL;
-	rpc_authflavor_t	authflavor;
 	struct rpc_timeout	timeparms;
-	struct nfs_fsinfo	fsinfo;
-	int			tcp, version, maxlen;
+	int			tcp, err = -EIO;
 
-	/* We probably want something more informative here */
-	snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
-
-	sb->s_magic      = NFS_SUPER_MAGIC;
-	sb->s_op         = &nfs_sops;
-	sb->s_blocksize_bits = 0;
-	sb->s_blocksize  = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
 	server           = NFS_SB(sb);
-	server->rsize    = nfs_block_size(data->rsize, NULL);
-	server->wsize    = nfs_block_size(data->wsize, NULL);
+	sb->s_blocksize_bits = 0;
+	sb->s_blocksize = 0;
+	if (data->bsize)
+		sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+	if (data->rsize)
+		server->rsize = nfs_block_size(data->rsize, NULL);
+	if (data->wsize)
+		server->wsize = nfs_block_size(data->wsize, NULL);
 	server->flags    = data->flags & NFS_MOUNT_FLAGMASK;
 
-	if (data->flags & NFS_MOUNT_NOAC) {
-		data->acregmin = data->acregmax = 0;
-		data->acdirmin = data->acdirmax = 0;
-		sb->s_flags |= MS_SYNCHRONOUS;
-	}
 	server->acregmin = data->acregmin*HZ;
 	server->acregmax = data->acregmax*HZ;
 	server->acdirmin = data->acdirmin*HZ;
@@ -275,34 +387,26 @@
 	server->namelen  = data->namlen;
 	server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
 	if (!server->hostname)
-		goto out_unlock;
+		goto out_fail;
 	strcpy(server->hostname, data->hostname);
-	INIT_LIST_HEAD(&server->lru_read);
-	INIT_LIST_HEAD(&server->lru_dirty);
-	INIT_LIST_HEAD(&server->lru_commit);
-	INIT_LIST_HEAD(&server->lru_busy);
 
- nfsv3_try_again:
-	server->caps = 0;
 	/* Check NFS protocol revision and initialize RPC op vector
 	 * and file handle pool. */
-	if (data->flags & NFS_MOUNT_VER3) {
+	if (server->flags & NFS_MOUNT_VER3) {
 #ifdef CONFIG_NFS_V3
 		server->rpc_ops = &nfs_v3_clientops;
-		version = 3;
 		server->caps |= NFS_CAP_READDIRPLUS;
 		if (data->version < 4) {
 			printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
-			goto out_unlock;
+			goto out_fail;
 		}
 #else
 		printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
-		goto out_unlock;
+		goto out_fail;
 #endif
 	} else {
 		server->rpc_ops = &nfs_v2_clientops;
-		version = 2;
-        }
+	}
 
 	/* Which protocol do we use? */
 	tcp   = (data->flags & NFS_MOUNT_TCP);
@@ -321,155 +425,54 @@
 	/* Now create transport and client */
 	xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
 						&server->addr, &timeparms);
-	if (xprt == NULL)
-		goto out_no_xprt;
-
-	/* Choose authentication flavor */
-	authflavor = RPC_AUTH_UNIX;
-	if (data->flags & NFS_MOUNT_SECURE)
-		authflavor = RPC_AUTH_DES;
-	else if (data->flags & NFS_MOUNT_KERBEROS)
-		authflavor = RPC_AUTH_KRB;
-
+	if (xprt == NULL) {
+		printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
+		goto out_fail;
+	}
 	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
-				 version, authflavor);
-	if (clnt == NULL)
-		goto out_no_client;
-
-	clnt->cl_intr     = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
-	clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
-	clnt->cl_droppriv = (data->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
+				 server->rpc_ops->version, RPC_AUTH_UNIX);
+	if (clnt == NULL) {
+		printk(KERN_WARNING "NFS: cannot create RPC client.\n");
+		xprt_destroy(xprt);
+		goto out_fail;
+	}
+
+	clnt->cl_intr     = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
+	clnt->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
+	clnt->cl_droppriv = (server->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0;
 	clnt->cl_chatty   = 1;
 	server->client    = clnt;
 
 	/* Fire up rpciod if not yet running */
-	if (rpciod_up() != 0)
-		goto out_no_iod;
-
-	/*
-	 * Keep the super block locked while we try to get 
-	 * the root fh attributes.
-	 */
-	/* Did getting the root inode fail? */
-	if (!(root_inode = nfs_get_root(sb, &server->fh))
-	    && (data->flags & NFS_MOUNT_VER3)) {
-		data->flags &= ~NFS_MOUNT_VER3;
-		rpciod_down();
-		rpc_shutdown_client(server->client);
-		goto nfsv3_try_again;
+	if (rpciod_up() != 0) {
+		printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
+		goto out_shutdown;
 	}
 
-	if (!root_inode)
-		goto out_no_root;
-	sb->s_root = d_alloc_root(root_inode);
-	if (!sb->s_root)
-		goto out_no_root;
-
-	sb->s_root->d_op = &nfs_dentry_operations;
-
-	/* Get some general file system info */
-        if (server->rpc_ops->statfs(server, &server->fh, &fsinfo) >= 0) {
-		if (server->namelen == 0)
-			server->namelen = fsinfo.namelen;
+	err = nfs_sb_init(sb);
+	if (err != 0)
+		goto out_noinit;
+
+	if (server->flags & NFS_MOUNT_VER3) {
+		if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
+			server->namelen = NFS3_MAXNAMLEN;
 	} else {
-		printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
-		goto out_no_root;
-        }
-
-	/* Work out a lot of parameters */
-	if (data->rsize == 0)
-		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
-	if (data->wsize == 0)
-		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
-	/* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
-	if (!fsinfo.bsize)
-		fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
-	/* Also make sure we don't go below rsize/wsize since
-	 * RPC calls are expensive */
-	if (fsinfo.bsize < server->rsize)
-		fsinfo.bsize = server->rsize;
-	if (fsinfo.bsize < server->wsize)
-		fsinfo.bsize = server->wsize;
-
-	if (data->bsize == 0)
-		sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
-	if (server->rsize > fsinfo.rtmax)
-		server->rsize = fsinfo.rtmax;
-	if (server->wsize > fsinfo.wtmax)
-		server->wsize = fsinfo.wtmax;
-
-	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	if (server->rpages > NFS_READ_MAXIOV) {
-		server->rpages = NFS_READ_MAXIOV;
-		server->rsize = server->rpages << PAGE_CACHE_SHIFT;
-	}
-
-	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-        if (server->wpages > NFS_WRITE_MAXIOV) {
-		server->wpages = NFS_WRITE_MAXIOV;
-                server->wsize = server->wpages << PAGE_CACHE_SHIFT;
-	}
-
-	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
-	if (server->dtsize > PAGE_CACHE_SIZE)
-		server->dtsize = PAGE_CACHE_SIZE;
-	if (server->dtsize > server->rsize)
-		server->dtsize = server->rsize;
-
-        maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
-
-        if (server->namelen == 0 || server->namelen > maxlen)
-                server->namelen = maxlen;
-
-	sb->s_maxbytes = fsinfo.maxfilesize;
-	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
-		sb->s_maxbytes = MAX_LFS_FILESIZE; 
-
-	/* Fire up the writeback cache */
-	if (nfs_reqlist_alloc(server) < 0) {
-		printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
-		goto failure_kill_reqlist;
+		if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
+			server->namelen = NFS2_MAXNAMLEN;
 	}
 
-	/* We're airborne Set socket buffersize */
-	rpc_setbufsize(clnt, server->wsize + 100, server->rsize + 100);
-
 	/* Check whether to start the lockd process */
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_up();
 	return 0;
-
-	/* Yargs. It didn't work out. */
- failure_kill_reqlist:
-	nfs_reqlist_exit(server);
-out_no_root:
-	printk("nfs_read_super: get root inode failed\n");
-	iput(root_inode);
+out_noinit:
 	rpciod_down();
-	goto out_shutdown;
-
-out_no_iod:
-	printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
 out_shutdown:
 	rpc_shutdown_client(server->client);
-	goto out_free_host;
-
-out_no_client:
-	printk(KERN_WARNING "NFS: cannot create RPC client.\n");
-	xprt_destroy(xprt);
-	goto out_free_host;
-
-out_no_xprt:
-	printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
-
-out_free_host:
-	nfs_reqlist_free(server);
-	kfree(server->hostname);
-out_unlock:
-	goto out_fail;
-
 out_fail:
-	return -EINVAL;
+	if (server->hostname)
+		kfree(server->hostname);
+	return err;
 }
 
 static int
@@ -478,29 +481,30 @@
 	struct nfs_server *server = NFS_SB(sb);
 	unsigned char blockbits;
 	unsigned long blockres;
-	struct nfs_fsinfo res;
+	struct nfs_fh *rootfh = NFS_FH(sb->s_root->d_inode);
+	struct nfs_fattr fattr;
+	struct nfs_fsstat res = {
+			.fattr = &fattr,
+	};
 	int error;
 
 	lock_kernel();
 
-	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
+	error = server->rpc_ops->statfs(server, rootfh, &res);
 	buf->f_type = NFS_SUPER_MAGIC;
 	if (error < 0)
 		goto out_err;
 
-	if (res.bsize == 0)
-		res.bsize = sb->s_blocksize;
-	buf->f_bsize = nfs_block_bits(res.bsize, &blockbits);
+	buf->f_bsize = sb->s_blocksize;
+	blockbits = sb->s_blocksize_bits;
 	blockres = (1 << blockbits) - 1;
 	buf->f_blocks = (res.tbytes + blockres) >> blockbits;
 	buf->f_bfree = (res.fbytes + blockres) >> blockbits;
 	buf->f_bavail = (res.abytes + blockres) >> blockbits;
 	buf->f_files = res.tfiles;
 	buf->f_ffree = res.afiles;
-	if (res.namelen == 0 || res.namelen > server->namelen)
-		res.namelen = server->namelen;
-	buf->f_namelen = res.namelen;
 
+	buf->f_namelen = server->namelen;
  out:
 	unlock_kernel();
 
@@ -1286,6 +1290,239 @@
 	.fs_flags	= FS_ODD_RENAME,
 };
 
+#ifdef CONFIG_NFS_V4
+
+static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
+{
+	struct nfs_server *server;
+	struct rpc_xprt *xprt = NULL;
+	struct rpc_clnt *clnt = NULL;
+	struct rpc_timeout timeparms;
+	rpc_authflavor_t authflavour;
+	int proto, err = -EIO;
+
+	sb->s_blocksize_bits = 0;
+	sb->s_blocksize = 0;
+	server = NFS_SB(sb);
+	if (data->rsize != 0)
+		server->rsize = nfs_block_size(data->rsize, NULL);
+	if (data->wsize != 0)
+		server->wsize = nfs_block_size(data->wsize, NULL);
+	server->flags = data->flags & NFS_MOUNT_FLAGMASK;
+
+	/* NFSv4 doesn't use NLM locking */
+	server->flags |= NFS_MOUNT_NONLM;
+
+	server->acregmin = data->acregmin*HZ;
+	server->acregmax = data->acregmax*HZ;
+	server->acdirmin = data->acdirmin*HZ;
+	server->acdirmax = data->acdirmax*HZ;
+
+	server->rpc_ops = &nfs_v4_clientops;
+	/* Initialize timeout values */
+
+	timeparms.to_initval = data->timeo * HZ / 10;
+	timeparms.to_retries = data->retrans;
+	timeparms.to_exponential = 1;
+	if (!timeparms.to_retries)
+		timeparms.to_retries = 5;
+
+	proto = data->proto;
+	/* Which IP protocol do we use? */
+	switch (proto) {
+	case IPPROTO_TCP:
+		timeparms.to_maxval  = RPC_MAX_TCP_TIMEOUT;
+		if (!timeparms.to_initval)
+			timeparms.to_initval = 600 * HZ / 10;
+		break;
+	case IPPROTO_UDP:
+		timeparms.to_maxval  = RPC_MAX_UDP_TIMEOUT;
+		if (!timeparms.to_initval)
+			timeparms.to_initval = 11 * HZ / 10;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Now create transport and client */
+	xprt = xprt_create_proto(proto, &server->addr, &timeparms);
+	if (xprt == NULL) {
+		printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
+		goto out_fail;
+	}
+
+	authflavour = RPC_AUTH_UNIX;
+	if (data->auth_flavourlen != 0) {
+		if (data->auth_flavourlen > 1)
+			printk(KERN_INFO "NFS: cannot yet deal with multiple auth flavours.\n");
+		if (copy_from_user(authflavour, data->auth_flavours, sizeof(authflavour))) {
+			err = -EFAULT;
+			goto out_fail;
+		}
+	}
+	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
+				 server->rpc_ops->version, authflavour);
+	if (clnt == NULL) {
+		printk(KERN_WARNING "NFS: cannot create RPC client.\n");
+		xprt_destroy(xprt);
+		goto out_fail;
+	}
+
+	clnt->cl_intr     = (server->flags & NFS4_MOUNT_INTR) ? 1 : 0;
+	clnt->cl_softrtry = (server->flags & NFS4_MOUNT_SOFT) ? 1 : 0;
+	clnt->cl_chatty   = 1;
+	server->client    = clnt;
+
+	/* Fire up rpciod if not yet running */
+	if (rpciod_up() != 0) {
+		printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
+		goto out_shutdown;
+	}
+
+	if (create_nfsv4_state(server, data))
+		goto out_shutdown;
+
+	err = nfs_sb_init(sb);
+	if (err == 0)
+		return 0;
+	rpciod_down();
+	destroy_nfsv4_state(server);
+out_shutdown:
+	rpc_shutdown_client(server->client);
+out_fail:
+	return err;
+}
+
+static int nfs4_compare_super(struct super_block *sb, void *data)
+{
+	struct nfs_server *server = data;
+	struct nfs_server *old = NFS_SB(sb);
+
+	if (strcmp(server->hostname, old->hostname) != 0)
+		return 0;
+	if (strcmp(server->mnt_path, old->mnt_path) != 0)
+		return 0;
+	return 1;
+}
+
+static void *
+nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
+{
+	void *p = NULL;
+
+	if (!src->len)
+		return ERR_PTR(-EINVAL);
+	if (src->len < maxlen)
+		maxlen = src->len;
+	if (dst == NULL) {
+		p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
+		if (p == NULL)
+			return ERR_PTR(-ENOMEM);
+	}
+	if (copy_from_user(dst, src->data, maxlen)) {
+		if (p != NULL)
+			kfree(p);
+		return ERR_PTR(-EFAULT);
+	}
+	dst[maxlen] = '\0';
+	return dst;
+}
+
+static struct super_block *nfs4_get_sb(struct file_system_type *fs_type,
+	int flags, char *dev_name, void *raw_data)
+{
+	int error;
+	struct nfs_server *server;
+	struct super_block *s;
+	struct nfs4_mount_data *data = raw_data;
+	void *p;
+
+	if (!data) {
+		printk("nfs_read_super: missing data argument\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL);
+	if (!server)
+		return ERR_PTR(-ENOMEM);
+	memset(server, 0, sizeof(struct nfs_server));
+
+	if (data->version != NFS4_MOUNT_VERSION) {
+		printk("nfs warning: mount version %s than kernel\n",
+			data->version < NFS_MOUNT_VERSION ? "older" : "newer");
+	}
+
+	p = nfs_copy_user_string(NULL, &data->hostname, 256);
+	if (IS_ERR(p))
+		goto out_err;
+	server->hostname = p;
+
+	p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
+	if (IS_ERR(p))
+		goto out_err;
+	server->mnt_path = p;
+
+	p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
+			sizeof(server->ip_addr));
+	if (IS_ERR(p))
+		goto out_err;
+
+	/* We now require that the mount process passes the remote address */
+	if (data->host_addrlen != sizeof(server->addr)) {
+		s = ERR_PTR(-EINVAL);
+		goto out_free;
+	}
+	if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
+		s = ERR_PTR(-EFAULT);
+		goto out_free;
+	}
+	if (server->addr.sin_family != AF_INET ||
+	    server->addr.sin_addr.s_addr == INADDR_ANY) {
+		printk("NFS: mount program didn't pass remote IP address!\n");
+		s = ERR_PTR(-EINVAL);
+		goto out_free;
+	}
+
+	s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
+
+	if (IS_ERR(s) || s->s_root)
+		goto out_free;
+
+	s->s_flags = flags;
+
+	error = nfs4_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
+	if (error) {
+		up_write(&s->s_umount);
+		deactivate_super(s);
+		return ERR_PTR(error);
+	}
+	s->s_flags |= MS_ACTIVE;
+	return s;
+out_err:
+	s = (struct super_block *)p;
+out_free:
+	if (server->mnt_path)
+		kfree(server->mnt_path);
+	if (server->hostname)
+		kfree(server->hostname);
+	kfree(server);
+	return s;
+}
+
+static struct file_system_type nfs4_fs_type = {
+	.owner		= THIS_MODULE,
+	.name		= "nfs4",
+	.get_sb		= nfs4_get_sb,
+	.kill_sb	= nfs_kill_super,
+	.fs_flags	= FS_ODD_RENAME,
+};
+#define register_nfs4fs() register_filesystem(&nfs4_fs_type)
+#define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type)
+#else
+#define register_nfs4fs() (0)
+#define unregister_nfs4fs()
+#endif
+
 extern int nfs_init_nfspagecache(void);
 extern void nfs_destroy_nfspagecache(void);
 extern int nfs_init_readpagecache(void);
@@ -1377,6 +1614,8 @@
         err = register_filesystem(&nfs_fs_type);
 	if (err)
 		goto out;
+	if ((err = register_nfs4fs()) != 0)
+		goto out;
 	return 0;
 out:
 	rpc_proc_unregister("nfs");
@@ -1401,6 +1640,7 @@
 	rpc_proc_unregister("nfs");
 #endif
 	unregister_filesystem(&nfs_fs_type);
+	unregister_nfs4fs();
 }
 
 /* Not quite true; I just maintain it */
diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Tue Oct 15 20:29:16 2002
+++ b/fs/nfs/nfs2xdr.c	Tue Oct 15 20:29:16 2002
@@ -596,37 +596,18 @@
  * Decode STATFS reply
  */
 static int
-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
 {
 	int	status;
-	u32	xfer_size;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 
-	/* For NFSv2, we more or less have to guess the preferred
-	 * read/write/readdir sizes from the single 'transfer size'
-	 * value.
-	 */
-	xfer_size = ntohl(*p++);	/* tsize */
-	res->rtmax  = 8 * 1024;
-	res->rtpref = xfer_size;
-	res->rtmult = xfer_size;
-	res->wtmax  = 8 * 1024;
-	res->wtpref = xfer_size;
-	res->wtmult = xfer_size;
-	res->dtpref = PAGE_CACHE_SIZE;
-	res->maxfilesize = 0x7FFFFFFF;	/* just a guess */
+	res->tsize  = ntohl(*p++);
 	res->bsize  = ntohl(*p++);
-
-	res->tbytes = ntohl(*p++) * res->bsize;
-	res->fbytes = ntohl(*p++) * res->bsize;
-	res->abytes = ntohl(*p++) * res->bsize;
-	res->tfiles = 0;
-	res->ffiles = 0;
-	res->afiles = 0;
-	res->namelen = 0;
-
+	res->blocks = ntohl(*p++);
+	res->bfree  = ntohl(*p++);
+	res->bavail = ntohl(*p++);
 	return 0;
 }
 
diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Tue Oct 15 20:29:17 2002
+++ b/fs/nfs/nfs3proc.c	Tue Oct 15 20:29:17 2002
@@ -639,24 +639,42 @@
 	return status;
 }
 
-/*
- * This is a combo call of fsstat and fsinfo
- */
 static int
 nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
-		 struct nfs_fsinfo *info)
+		 struct nfs_fsstat *stat)
 {
 	int	status;
 
 	dprintk("NFS call  fsstat\n");
-	memset((char *)info, 0, sizeof(*info));
-	status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, info, 0);
-	if (status < 0)
-		goto error;
+	stat->fattr->valid = 0;
+	status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, stat, 0);
+	dprintk("NFS reply statfs: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+		 struct nfs_fsinfo *info)
+{
+	int	status;
+
+	dprintk("NFS call  fsinfo\n");
+	info->fattr->valid = 0;
 	status = rpc_call(server->client, NFS3PROC_FSINFO, fhandle, info, 0);
+	dprintk("NFS reply fsinfo: %d\n", status);
+	return status;
+}
 
-error:
-	dprintk("NFS reply statfs: %d\n", status);
+static int
+nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+		   struct nfs_pathconf *info)
+{
+	int	status;
+
+	dprintk("NFS call  pathconf\n");
+	info->fattr->valid = 0;
+	status = rpc_call(server->client, NFS3PROC_PATHCONF, fhandle, info, 0);
+	dprintk("NFS reply pathconf: %d\n", status);
 	return status;
 }
 
@@ -824,6 +842,8 @@
 	.readdir	= nfs3_proc_readdir,
 	.mknod		= nfs3_proc_mknod,
 	.statfs		= nfs3_proc_statfs,
+	.fsinfo		= nfs3_proc_fsinfo,
+	.pathconf	= nfs3_proc_pathconf,
 	.decode_dirent	= nfs3_decode_dirent,
 	.read_setup	= nfs3_proc_read_setup,
 	.write_setup	= nfs3_proc_write_setup,
diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
--- a/fs/nfs/nfs3xdr.c	Tue Oct 15 20:29:23 2002
+++ b/fs/nfs/nfs3xdr.c	Tue Oct 15 20:29:23 2002
@@ -912,14 +912,13 @@
  * Decode FSSTAT reply
  */
 static int
-nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
 {
-	struct nfs_fattr dummy;
 	int		status;
 
 	status = ntohl(*p++);
 
-	p = xdr_decode_post_op_attr(p, &dummy);
+	p = xdr_decode_post_op_attr(p, res->fattr);
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
 
@@ -940,12 +939,11 @@
 static int
 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
 {
-	struct nfs_fattr dummy;
 	int		status;
 
 	status = ntohl(*p++);
 
-	p = xdr_decode_post_op_attr(p, &dummy);
+	p = xdr_decode_post_op_attr(p, res->fattr);
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
 
@@ -959,6 +957,7 @@
 	p = xdr_decode_hyper(p, &res->maxfilesize);
 
 	/* ignore time_delta and properties */
+	res->lease_time = 0;
 	return 0;
 }
 
@@ -966,18 +965,17 @@
  * Decode PATHCONF reply
  */
 static int
-nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
 {
-	struct nfs_fattr dummy;
 	int		status;
 
 	status = ntohl(*p++);
 
-	p = xdr_decode_post_op_attr(p, &dummy);
+	p = xdr_decode_post_op_attr(p, res->fattr);
 	if (status != 0)
 		return -nfs_stat_to_errno(status);
-	res->linkmax = ntohl(*p++);
-	res->namelen = ntohl(*p++);
+	res->max_link = ntohl(*p++);
+	res->max_namelen = ntohl(*p++);
 
 	/* ignore remaining fields */
 	return 0;
diff -Nru a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/nfs/nfs4proc.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,1577 @@
+/*
+ *  fs/nfs/nfs4proc.c
+ *
+ *  Client-side procedure declarations for NFSv4.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/mm.h>
+#include <linux/utsname.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_page.h>
+#include <linux/smp_lock.h>
+
+#define NFSDBG_FACILITY		NFSDBG_PROC
+
+#define GET_OP(cp,name)		&cp->ops[cp->req_nops].u.name
+#define OPNUM(cp)		cp->ops[cp->req_nops].opnum
+
+extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
+
+static nfs4_stateid zero_stateid =
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static spinlock_t renew_lock = SPIN_LOCK_UNLOCKED;
+
+static void
+nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
+		    struct nfs_server *server, char *tag)
+{
+	memset(cp, 0, sizeof(*cp));
+	cp->ops = ops;
+	cp->server = server;
+
+#if NFS4_DEBUG
+	cp->taglen = strlen(tag);
+	cp->tag = tag;
+#endif
+}
+
+static void
+nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, u32 *resp_access)
+{
+	struct nfs4_access *access = GET_OP(cp, access);
+	
+	access->ac_req_access = req_access;
+	access->ac_resp_supported = resp_supported;
+	access->ac_resp_access = resp_access;
+	
+	OPNUM(cp) = OP_ACCESS;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_close(struct nfs4_compound *cp, nfs4_stateid stateid, u32 seqid)
+{
+	struct nfs4_close *close = GET_OP(cp, close);
+
+	close->cl_stateid = stateid;
+	close->cl_seqid = seqid;
+
+	OPNUM(cp) = OP_CLOSE;
+	cp->req_nops++;
+	cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_commit(struct nfs4_compound *cp, u64 start, u32 len, struct nfs_writeverf *verf)
+{
+	struct nfs4_commit *commit = GET_OP(cp, commit);
+
+	commit->co_start = start;
+	commit->co_len = len;
+	commit->co_verifier = verf;
+
+	OPNUM(cp) = OP_COMMIT;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name,
+		      struct iattr *sattr, struct nfs4_change_info *info)
+{
+	struct nfs4_create *create = GET_OP(cp, create);
+	
+	create->cr_ftype = NF4DIR;
+	create->cr_namelen = name->len;
+	create->cr_name = name->name;
+	create->cr_attrs = sattr;
+	create->cr_cinfo = info;
+	
+	OPNUM(cp) = OP_CREATE;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_create_symlink(struct nfs4_compound *cp, struct qstr *name,
+			  struct qstr *linktext, struct iattr *sattr,
+			  struct nfs4_change_info *info)
+{
+	struct nfs4_create *create = GET_OP(cp, create);
+
+	create->cr_ftype = NF4LNK;
+	create->cr_textlen = linktext->len;
+	create->cr_text = linktext->name;
+	create->cr_namelen = name->len;
+	create->cr_name = name->name;
+	create->cr_attrs = sattr;
+	create->cr_cinfo = info;
+
+	OPNUM(cp) = OP_CREATE;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_create_special(struct nfs4_compound *cp, struct qstr *name,
+			    dev_t dev, struct iattr *sattr,
+			    struct nfs4_change_info *info)
+{
+	int mode = sattr->ia_mode;
+	struct nfs4_create *create = GET_OP(cp, create);
+
+	BUG_ON(!(sattr->ia_valid & ATTR_MODE));
+	BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
+	
+	if (S_ISFIFO(mode))
+		create->cr_ftype = NF4FIFO;
+	else if (S_ISBLK(mode)) {
+		create->cr_ftype = NF4BLK;
+		create->cr_specdata1 = MAJOR(dev);
+		create->cr_specdata2 = MINOR(dev);
+	}
+	else if (S_ISCHR(mode)) {
+		create->cr_ftype = NF4CHR;
+		create->cr_specdata1 = MAJOR(dev);
+		create->cr_specdata2 = MINOR(dev);
+	}
+	else
+		create->cr_ftype = NF4SOCK;
+	
+	create->cr_namelen = name->len;
+	create->cr_name = name->name;
+	create->cr_attrs = sattr;
+	create->cr_cinfo = info;
+
+	OPNUM(cp) = OP_CREATE;
+	cp->req_nops++;
+}
+
+/*
+ * This is our standard bitmap for GETATTR requests.
+ */
+u32 nfs4_fattr_bitmap[2] = {
+	FATTR4_WORD0_TYPE
+	| FATTR4_WORD0_CHANGE
+	| FATTR4_WORD0_SIZE
+	| FATTR4_WORD0_FSID
+	| FATTR4_WORD0_FILEID,
+	FATTR4_WORD1_MODE
+	| FATTR4_WORD1_NUMLINKS
+	| FATTR4_WORD1_OWNER
+	| FATTR4_WORD1_OWNER_GROUP
+	| FATTR4_WORD1_RAWDEV
+	| FATTR4_WORD1_SPACE_USED
+	| FATTR4_WORD1_TIME_ACCESS
+	| FATTR4_WORD1_TIME_METADATA
+	| FATTR4_WORD1_TIME_MODIFY
+};
+
+u32 nfs4_statfs_bitmap[2] = {
+	FATTR4_WORD0_FILES_AVAIL
+	| FATTR4_WORD0_FILES_FREE
+	| FATTR4_WORD0_FILES_TOTAL,
+	FATTR4_WORD1_SPACE_AVAIL
+	| FATTR4_WORD1_SPACE_FREE
+	| FATTR4_WORD1_SPACE_TOTAL
+};
+
+u32 nfs4_fsinfo_bitmap[2] = {
+	FATTR4_WORD0_MAXFILESIZE
+	| FATTR4_WORD0_MAXREAD
+        | FATTR4_WORD0_MAXWRITE
+	| FATTR4_WORD0_LEASE_TIME,
+	0
+};
+
+u32 nfs4_pathconf_bitmap[2] = {
+	FATTR4_WORD0_MAXLINK
+	| FATTR4_WORD0_MAXNAME,
+	0
+};
+
+/* mount bitmap: fattr bitmap + lease time */
+u32 nfs4_mount_bitmap[2] = {
+	FATTR4_WORD0_TYPE
+	| FATTR4_WORD0_CHANGE
+	| FATTR4_WORD0_SIZE
+	| FATTR4_WORD0_FSID
+	| FATTR4_WORD0_FILEID
+	| FATTR4_WORD0_LEASE_TIME,
+	FATTR4_WORD1_MODE
+	| FATTR4_WORD1_NUMLINKS
+	| FATTR4_WORD1_OWNER
+	| FATTR4_WORD1_OWNER_GROUP
+	| FATTR4_WORD1_RAWDEV
+	| FATTR4_WORD1_SPACE_USED
+	| FATTR4_WORD1_TIME_ACCESS
+	| FATTR4_WORD1_TIME_METADATA
+	| FATTR4_WORD1_TIME_MODIFY
+};
+
+static inline void
+__nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap,
+		     struct nfs_fattr *fattr,
+		     struct nfs_fsstat *fsstat,
+		     struct nfs_fsinfo *fsinfo,
+		     struct nfs_pathconf *pathconf,
+		     u32 *bmres)
+{
+        struct nfs4_getattr *getattr = GET_OP(cp, getattr);
+
+        getattr->gt_bmval = bitmap;
+        getattr->gt_attrs = fattr;
+	getattr->gt_fsstat = fsstat;
+	getattr->gt_fsinfo = fsinfo;
+	getattr->gt_pathconf = pathconf;
+	getattr->gt_bmres = bmres;
+
+        OPNUM(cp) = OP_GETATTR;
+        cp->req_nops++;
+}
+
+static void
+nfs4_setup_getattr(struct nfs4_compound *cp,
+		struct nfs_fattr *fattr,
+		u32 *bmres)
+{
+	__nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr,
+			NULL, NULL, NULL, bmres);
+}
+
+static void
+nfs4_setup_getrootattr(struct nfs4_compound *cp,
+		struct nfs_fattr *fattr,
+		struct nfs_fsinfo *fsinfo,
+		u32 *bmres)
+{
+	__nfs4_setup_getattr(cp, nfs4_mount_bitmap,
+			fattr, NULL, fsinfo, NULL, bmres);
+}
+
+static void
+nfs4_setup_statfs(struct nfs4_compound *cp,
+		struct nfs_fsstat *fsstat,
+		u32 *bmres)
+{
+	__nfs4_setup_getattr(cp, nfs4_statfs_bitmap,
+			NULL, fsstat, NULL, NULL, bmres);
+}
+
+static void
+nfs4_setup_fsinfo(struct nfs4_compound *cp,
+		struct nfs_fsinfo *fsinfo,
+		u32 *bmres)
+{
+	__nfs4_setup_getattr(cp, nfs4_fsinfo_bitmap,
+			NULL, NULL, fsinfo, NULL, bmres);
+}
+
+static void
+nfs4_setup_pathconf(struct nfs4_compound *cp,
+		struct nfs_pathconf *pathconf,
+		u32 *bmres)
+{
+	__nfs4_setup_getattr(cp, nfs4_pathconf_bitmap,
+			NULL, NULL, NULL, pathconf, bmres);
+}
+
+static void
+nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
+{
+	struct nfs4_getfh *getfh = GET_OP(cp, getfh);
+
+	getfh->gf_fhandle = fhandle;
+
+	OPNUM(cp) = OP_GETFH;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name,
+		struct nfs4_change_info *info)
+{
+	struct nfs4_link *link = GET_OP(cp, link);
+
+	link->ln_namelen = name->len;
+	link->ln_name = name->name;
+	link->ln_cinfo = info;
+
+	OPNUM(cp) = OP_LINK;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_lookup(struct nfs4_compound *cp, struct qstr *q)
+{
+	struct nfs4_lookup *lookup = GET_OP(cp, lookup);
+
+	lookup->lo_name = q;
+
+	OPNUM(cp) = OP_LOOKUP;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
+{
+	struct nfs4_putfh *putfh = GET_OP(cp, putfh);
+
+	putfh->pf_fhandle = fhandle;
+
+	OPNUM(cp) = OP_PUTFH;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_putrootfh(struct nfs4_compound *cp)
+{
+        OPNUM(cp) = OP_PUTROOTFH;
+        cp->req_nops++;
+}
+
+static void
+nfs4_setup_open(struct nfs4_compound *cp, int flags, struct qstr *name,
+		struct iattr *sattr, char *stateid, struct nfs4_change_info *cinfo,
+		u32 *rflags)
+{
+	struct nfs4_open *open = GET_OP(cp, open);
+
+	BUG_ON(cp->flags);
+	
+	open->op_share_access = flags & 3;
+	open->op_opentype = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE;
+	open->op_createmode = NFS4_CREATE_UNCHECKED;
+	open->op_attrs = sattr;
+	if (flags & O_EXCL) {
+		u32 *p = (u32 *) open->op_verifier;
+		p[0] = jiffies;
+		p[1] = current->pid;
+		open->op_createmode = NFS4_CREATE_EXCLUSIVE;
+	}
+	open->op_name = name;
+	open->op_stateid = stateid;
+	open->op_cinfo = cinfo;
+	open->op_rflags = rflags;
+
+	OPNUM(cp) = OP_OPEN;
+	cp->req_nops++;
+	cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_open_confirm(struct nfs4_compound *cp, char *stateid)
+{
+	struct nfs4_open_confirm *open_confirm = GET_OP(cp, open_confirm);
+	
+	open_confirm->oc_stateid = stateid;
+
+	OPNUM(cp) = OP_OPEN_CONFIRM;
+	cp->req_nops++;
+	cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_read(struct nfs4_compound *cp, u64 offset, u32 length,
+		struct page **pages, unsigned int pgbase, u32 *eofp, u32 *bytes_read)
+{
+	struct nfs4_read *read = GET_OP(cp, read);
+
+	read->rd_offset = offset;
+	read->rd_length = length;
+	read->rd_pages = pages;
+	read->rd_pgbase = pgbase;
+	read->rd_eof = eofp;
+	read->rd_bytes_read = bytes_read;
+
+	OPNUM(cp) = OP_READ;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
+		     struct page **pages, unsigned int bufsize, struct dentry *dentry)
+{
+	u32 *start, *p;
+	struct nfs4_readdir *readdir = GET_OP(cp, readdir);
+
+	BUG_ON(bufsize < 80);
+	readdir->rd_cookie = (cookie > 2) ? cookie : 0;
+	memcpy(readdir->rd_req_verifier, verifier, sizeof(nfs4_verifier));
+	readdir->rd_count = bufsize;
+	readdir->rd_bmval[0] = FATTR4_WORD0_FILEID;
+	readdir->rd_bmval[1] = 0;
+	readdir->rd_pages = pages;
+	readdir->rd_pgbase = 0;
+	
+	OPNUM(cp) = OP_READDIR;
+	cp->req_nops++;
+
+	if (cookie >= 2)
+		return;
+	
+	/*
+	 * NFSv4 servers do not return entries for '.' and '..'
+	 * Therefore, we fake these entries here.  We let '.'
+	 * have cookie 0 and '..' have cookie 1.  Note that
+	 * when talking to the server, we always send cookie 0
+	 * instead of 1 or 2.
+	 */
+	start = p = (u32 *)kmap(*pages);
+	
+	if (cookie == 0) {
+		*p++ = xdr_one;                                  /* next */
+		*p++ = xdr_zero;                   /* cookie, first word */
+		*p++ = xdr_one;                   /* cookie, second word */
+		*p++ = xdr_one;                             /* entry len */
+		memcpy(p, ".\0\0\0", 4);                        /* entry */
+		p++;
+		*p++ = xdr_one;                         /* bitmap length */
+		*p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
+		*p++ = htonl(8);              /* attribute buffer length */
+		p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
+	}
+	
+	*p++ = xdr_one;                                  /* next */
+	*p++ = xdr_zero;                   /* cookie, first word */
+	*p++ = xdr_two;                   /* cookie, second word */
+	*p++ = xdr_two;                             /* entry len */
+	memcpy(p, "..\0\0", 4);                         /* entry */
+	p++;
+	*p++ = xdr_one;                         /* bitmap length */
+	*p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
+	*p++ = htonl(8);              /* attribute buffer length */
+	p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
+
+	readdir->rd_pgbase = (char *)p - (char *)start;
+	readdir->rd_count -= readdir->rd_pgbase;
+	kunmap(*pages);
+}
+
+static void
+nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages)
+{
+	struct nfs4_readlink *readlink = GET_OP(cp, readlink);
+
+	readlink->rl_count = count;
+	readlink->rl_pages = pages;
+
+	OPNUM(cp) = OP_READLINK;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_change_info *cinfo)
+{
+	struct nfs4_remove *remove = GET_OP(cp, remove);
+
+	remove->rm_namelen = name->len;
+	remove->rm_name = name->name;
+	remove->rm_cinfo = cinfo;
+
+	OPNUM(cp) = OP_REMOVE;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new,
+		  struct nfs4_change_info *old_cinfo, struct nfs4_change_info *new_cinfo)
+{
+	struct nfs4_rename *rename = GET_OP(cp, rename);
+
+	rename->rn_oldnamelen = old->len;
+	rename->rn_oldname = old->name;
+	rename->rn_newnamelen = new->len;
+	rename->rn_newname = new->name;
+	rename->rn_src_cinfo = old_cinfo;
+	rename->rn_dst_cinfo = new_cinfo;
+
+	OPNUM(cp) = OP_RENAME;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_renew(struct nfs4_compound *cp)
+{
+	OPNUM(cp) = OP_RENEW;
+	cp->req_nops++;
+	cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_restorefh(struct nfs4_compound *cp)
+{
+        OPNUM(cp) = OP_RESTOREFH;
+        cp->req_nops++;
+}
+
+static void
+nfs4_setup_savefh(struct nfs4_compound *cp)
+{
+        OPNUM(cp) = OP_SAVEFH;
+        cp->req_nops++;
+}
+
+static void
+nfs4_setup_setattr(struct nfs4_compound *cp, char *stateid, struct iattr *iap)
+{
+	struct nfs4_setattr *setattr = GET_OP(cp, setattr);
+
+	setattr->st_stateid = stateid;
+	setattr->st_iap = iap;
+	
+	OPNUM(cp) = OP_SETATTR;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_setclientid(struct nfs4_compound *cp, u32 program, unsigned short port)
+{
+	struct nfs4_setclientid *setclientid = GET_OP(cp, setclientid);
+	struct nfs_server *server = cp->server;
+	struct timeval tv;
+	u32 *p;
+
+	do_gettimeofday(&tv);
+	p = (u32 *)setclientid->sc_verifier;
+	*p++ = tv.tv_sec;
+	*p++ = tv.tv_usec;
+	setclientid->sc_name = server->ip_addr;
+	sprintf(setclientid->sc_netid, "udp");
+	sprintf(setclientid->sc_uaddr, "%s.%d.%d", server->ip_addr, port >> 8, port & 255);
+	setclientid->sc_prog = program;
+	setclientid->sc_cb_ident = 0;
+	
+	OPNUM(cp) = OP_SETCLIENTID;
+	cp->req_nops++;
+}
+
+static void
+nfs4_setup_setclientid_confirm(struct nfs4_compound *cp)
+{
+	OPNUM(cp) = OP_SETCLIENTID_CONFIRM;
+	cp->req_nops++;
+	cp->renew_index = cp->req_nops;
+}
+
+static void
+nfs4_setup_write(struct nfs4_compound *cp, u64 offset, u32 length, int stable,
+		 struct page **pages, unsigned int pgbase, u32 *bytes_written,
+		 struct nfs_writeverf *verf)
+{
+	struct nfs4_write *write = GET_OP(cp, write);
+
+	write->wr_offset = offset;
+	write->wr_stable_how = stable;
+	write->wr_len = length;
+	write->wr_bytes_written = bytes_written;
+	write->wr_verf = verf;
+
+	write->wr_pages = pages;
+	write->wr_pgbase = pgbase;
+
+	OPNUM(cp) = OP_WRITE;
+	cp->req_nops++;
+}
+
+static inline void
+process_lease(struct nfs4_compound *cp)
+{
+	struct nfs_server *server;
+	
+        /*
+         * Generic lease processing: If this operation contains a
+	 * lease-renewing operation, and it succeeded, update the RENEW time
+	 * in the superblock.  Instead of the current time, we use the time
+	 * when the request was sent out.  (All we know is that the lease was
+	 * renewed sometime between then and now, and we have to assume the
+	 * worst case.)
+	 *
+	 * Notes:
+	 *   (1) renewd doesn't acquire the spinlock when messing with
+	 *     server->last_renewal; this is OK since rpciod always runs
+	 *     under the BKL.
+	 *   (2) cp->timestamp was set at the end of XDR encode.
+         */
+	if (!cp->renew_index)
+		return;
+	if (!cp->toplevel_status || cp->resp_nops > cp->renew_index) {
+		server = cp->server;
+		spin_lock(&renew_lock);
+		if (server->last_renewal < cp->timestamp)
+			server->last_renewal = cp->timestamp;
+		spin_unlock(&renew_lock);
+	}
+}
+
+static int
+nfs4_call_compound(struct nfs4_compound *cp, struct rpc_cred *cred, int flags)
+{
+	int status;
+	struct rpc_message msg = {
+		.rpc_proc = NFSPROC4_COMPOUND,
+		.rpc_argp = cp,
+		.rpc_resp = cp,
+		.rpc_cred = cred,
+	};
+
+	status = rpc_call_sync(cp->server->client, &msg, flags);
+	if (!status)
+		process_lease(cp);
+	
+	return status;
+}
+
+static inline void
+process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr)
+{
+	BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0);
+	BUG_ON((fattr->valid & NFS_ATTR_FATTR_V4) == 0);
+	
+	if (fattr->change_attr == info->after) {
+		fattr->pre_change_attr = info->before;
+		fattr->valid |= NFS_ATTR_PRE_CHANGE;
+		fattr->timestamp = jiffies;
+	}
+}
+
+static int
+do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr,
+	struct nfs_fattr *fattr, struct nfs_fh *fhandle, u32 *seqid, char *stateid)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[7];
+	struct nfs4_change_info	dir_cinfo;
+	struct nfs_fattr	dir_attr;
+	u32			dir_bmres[2];
+	u32			bmres[2];
+	u32			rflags;
+	int			status;
+
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "open");
+	nfs4_setup_putfh(&compound, NFS_FH(dir));
+	nfs4_setup_savefh(&compound);
+	nfs4_setup_open(&compound, flags, name, sattr, stateid, &dir_cinfo, &rflags);
+	nfs4_setup_getattr(&compound, fattr, bmres);
+	nfs4_setup_getfh(&compound, fhandle);
+	nfs4_setup_restorefh(&compound);
+	nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+	if ((status = nfs4_call_compound(&compound, NULL, 0)))
+		return status;
+
+	process_cinfo(&dir_cinfo, &dir_attr);
+	nfs_refresh_inode(dir, &dir_attr);
+	if (!(rflags & NFS4_OPEN_RESULT_CONFIRM)) {
+		*seqid = 1;
+		return 0;
+	}
+	*seqid = 2;
+
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "open_confirm");
+	nfs4_setup_putfh(&compound, fhandle);
+	nfs4_setup_open_confirm(&compound, stateid);
+	return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
+	   struct nfs_fh *fhandle, struct iattr *sattr, char *stateid)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[3];
+	u32			bmres[2];
+
+	fattr->valid = 0;
+	nfs4_setup_compound(&compound, ops, server, "setattr");
+	nfs4_setup_putfh(&compound, fhandle);
+	nfs4_setup_setattr(&compound, stateid, sattr);
+	nfs4_setup_getattr(&compound, fattr, bmres);
+	return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+do_close(struct nfs_server *server, struct nfs_fh *fhandle, u32 seqid, char *stateid)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[2];
+	
+	nfs4_setup_compound(&compound, ops, server, "close");
+	nfs4_setup_putfh(&compound, fhandle);
+	nfs4_setup_close(&compound, stateid, seqid);
+	return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+		   struct nfs_fattr *fattr)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[4];
+	struct nfs_fsinfo	fsinfo;
+	u32			bmres[2];
+	unsigned char *		p;
+	struct qstr		q;
+	int			status;
+
+	fattr->valid = 0;
+
+	if (!(server->nfs4_state = nfs4_get_client()))
+		return -ENOMEM;
+
+	/* 
+	 * SETCLIENTID.
+	 * Until delegations are imported, we don't bother setting the program
+	 * number and port to anything meaningful.
+	 */
+	nfs4_setup_compound(&compound, ops, server, "setclientid");
+	nfs4_setup_setclientid(&compound, 0, 0);
+	if ((status = nfs4_call_compound(&compound, NULL, 0)))
+		goto out;
+
+	/*
+	 * SETCLIENTID_CONFIRM, plus root filehandle.
+	 * We also get the lease time here.
+	 */
+	nfs4_setup_compound(&compound, ops, server, "setclientid_confirm");
+	nfs4_setup_setclientid_confirm(&compound);
+	nfs4_setup_putrootfh(&compound);
+	nfs4_setup_getrootattr(&compound, fattr, &fsinfo, bmres);
+	nfs4_setup_getfh(&compound, fhandle);
+	if ((status = nfs4_call_compound(&compound, NULL, 0)))
+		goto out;
+	
+	/*
+	 * Now that we have instantiated the clientid and determined
+	 * the lease time, we can initialize the renew daemon for this
+	 * server.
+	 */
+	server->lease_time = fsinfo.lease_time * HZ;
+	if ((status = nfs4_init_renewd(server)))
+		goto out;
+	
+	/*
+	 * Now we do a seperate LOOKUP for each component of the mount path.
+	 * The LOOKUPs are done seperately so that we can conveniently
+	 * catch an ERR_WRONGSEC if it occurs along the way...
+	 */
+	p = server->mnt_path;
+	for (;;) {
+		while (*p == '/')
+			p++;
+		if (!*p)
+			break;
+		q.name = p;
+		while (*p && (*p != '/'))
+			p++;
+		q.len = p - q.name;
+
+		nfs4_setup_compound(&compound, ops, server, "mount");
+		nfs4_setup_putfh(&compound, fhandle);
+		nfs4_setup_lookup(&compound, &q);
+		nfs4_setup_getattr(&compound, fattr, bmres);
+		nfs4_setup_getfh(&compound, fhandle);
+		status = nfs4_call_compound(&compound, NULL, 0);
+		if (!status)
+			continue;
+		if (status == -ENOENT) {
+			printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
+			printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n");
+		}
+		break;
+	}
+
+out:
+	return status;
+}
+
+static int
+nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
+{
+	struct nfs4_compound compound;
+	struct nfs4_op ops[2];
+	u32 bmres[2];
+
+	fattr->valid = 0;
+
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr");
+	nfs4_setup_putfh(&compound, NFS_FH(inode));
+	nfs4_setup_getattr(&compound, fattr, bmres);
+	return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+		  struct iattr *sattr)
+{
+	struct inode *		inode = dentry->d_inode;
+	int			size_change = sattr->ia_valid & ATTR_SIZE;
+	struct nfs_fh		throwaway_fh;
+	u32			seqid;
+	nfs4_stateid		stateid;
+	int			status;
+
+	fattr->valid = 0;
+	
+	if (size_change) {
+		status = do_open(dentry->d_parent->d_inode, &dentry->d_name,
+				 NFS4_SHARE_ACCESS_WRITE, NULL, fattr,
+				 &throwaway_fh, &seqid, stateid);
+		if (status)
+			return status;
+
+		/*
+		 * Because OPEN is always done by name in nfsv4, it is
+		 * possible that we opened a different file by the same
+		 * name.  We can recognize this race condition, but we
+		 * can't do anything about it besides returning an error.
+		 *
+		 * XXX: Should we compare filehandles too, as in
+		 * nfs_find_actor()?
+		 */
+		if (fattr->fileid != NFS_FILEID(inode)) {
+			printk(KERN_WARNING "nfs: raced in setattr, returning -EIO\n");
+			do_close(NFS_SERVER(inode), NFS_FH(inode), seqid, stateid);
+			return -EIO;
+		}
+	}
+	else
+		memcpy(stateid, zero_stateid, sizeof(nfs4_stateid));
+	
+	status = do_setattr(NFS_SERVER(inode), fattr, NFS_FH(inode), sattr, stateid);
+	if (size_change)
+		do_close(NFS_SERVER(inode), NFS_FH(inode), seqid, stateid);
+	return status;
+}
+
+static int
+nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+		 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[5];
+	struct nfs_fattr	dir_attr;
+	u32			dir_bmres[2];
+	u32			bmres[2];
+	int			status;
+
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	
+	dprintk("NFS call  lookup %s\n", name->name);
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "lookup");
+	nfs4_setup_putfh(&compound, NFS_FH(dir));
+	nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+	nfs4_setup_lookup(&compound, name);
+	nfs4_setup_getattr(&compound, fattr, bmres);
+	nfs4_setup_getfh(&compound, fhandle);
+	status = nfs4_call_compound(&compound, NULL, 0);
+	dprintk("NFS reply lookup: %d\n", status);
+
+	if (status >= 0)
+		status = nfs_refresh_inode(dir, &dir_attr);
+	return status;
+}
+
+static int
+nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[3];
+	struct nfs_fattr	fattr;
+	u32			bmres[2];
+	u32			req_access = 0, resp_supported, resp_access;
+	int			status;
+
+	fattr.valid = 0;
+
+	/*
+	 * Determine which access bits we want to ask for...
+	 */
+	if (mode & MAY_READ)
+		req_access |= NFS4_ACCESS_READ;
+	if (S_ISDIR(inode->i_mode)) {
+		if (mode & MAY_WRITE)
+			req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
+		if (mode & MAY_EXEC)
+			req_access |= NFS4_ACCESS_LOOKUP;
+	}
+	else {
+		if (mode & MAY_WRITE)
+			req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
+		if (mode & MAY_EXEC)
+			req_access |= NFS4_ACCESS_EXECUTE;
+	}
+
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "access");
+	nfs4_setup_putfh(&compound, NFS_FH(inode));
+	nfs4_setup_getattr(&compound, &fattr, bmres);
+	nfs4_setup_access(&compound, req_access, &resp_supported, &resp_access);
+	status = nfs4_call_compound(&compound, cred, 0);
+	nfs_refresh_inode(inode, &fattr);
+
+	if (!status) {
+		if (req_access != resp_supported) {
+			printk(KERN_NOTICE "NFS: server didn't support all access bits!\n");
+			status = -ENOTSUPP;
+		}
+		else if (req_access != resp_access)
+			status = -EACCES;
+	}
+	return status;
+}
+
+/*
+ * TODO: For the time being, we don't try to get any attributes
+ * along with any of the zero-copy operations READ, READDIR,
+ * READLINK, WRITE.
+ *
+ * In the case of the first three, we want to put the GETATTR
+ * after the read-type operation -- this is because it is hard
+ * to predict the length of a GETATTR response in v4, and thus
+ * align the READ data correctly.  This means that the GETATTR
+ * may end up partially falling into the page cache, and we should
+ * shift it into the 'tail' of the xdr_buf before processing.
+ * To do this efficiently, we need to know the total length
+ * of data received, which doesn't seem to be available outside
+ * of the RPC layer.
+ *
+ * In the case of WRITE, we also want to put the GETATTR after
+ * the operation -- in this case because we want to make sure
+ * we get the post-operation mtime and size.  This means that
+ * we can't use xdr_encode_pages() as written: we need a variant
+ * of it which would leave room in the 'tail' iovec.
+ *
+ * Both of these changes to the XDR layer would in fact be quite
+ * minor, but I decided to leave them for a subsequent patch.
+ */
+static int
+nfs4_proc_readlink(struct inode *inode, struct page *page)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[2];
+
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink");
+	nfs4_setup_putfh(&compound, NFS_FH(inode));
+	nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page);
+	return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_read(struct inode *inode, struct rpc_cred *cred,
+	       struct nfs_fattr *fattr, int flags,
+	       unsigned int base, unsigned int count,
+	       struct page *page, int *eofp)
+{
+	u64			offset = page_offset(page) + base;
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[2];
+	u32			bytes_read;
+	int			status;
+
+	fattr->valid = 0;
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "read [sync]");
+	nfs4_setup_putfh(&compound, NFS_FH(inode));
+	nfs4_setup_read(&compound, offset, count, &page, base, eofp, &bytes_read);
+	status = nfs4_call_compound(&compound, cred, 0);
+
+	if (status >= 0)
+		status = bytes_read;
+	return status;
+}
+
+static int
+nfs4_proc_write(struct inode *inode, struct rpc_cred *cred,
+		struct nfs_fattr *fattr, int flags,
+		unsigned int base, unsigned int count,
+		struct page *page, struct nfs_writeverf *verf)
+{
+	u64			offset = page_offset(page) + base;
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[2];
+	u32			bytes_written;
+	int			stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
+	int			rpcflags = (flags & NFS_RW_SWAP) ? NFS_RPC_SWAPFLAGS : 0;
+	int			status;
+
+	fattr->valid = 0;
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "write [sync]");
+	nfs4_setup_putfh(&compound, NFS_FH(inode));
+	nfs4_setup_write(&compound, offset, count, stable, &page, base, &bytes_written, verf);
+	status = nfs4_call_compound(&compound, cred, rpcflags);
+	
+	if (status >= 0)
+		status = bytes_written;
+	return status;
+}
+
+static int
+nfs4_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
+		 int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	int			oflags;
+	u32			seqid;
+	nfs4_stateid		stateid;
+	int 			status;
+
+	oflags = NFS4_SHARE_ACCESS_READ | O_CREAT | (flags & O_EXCL);
+	status = do_open(dir, name, oflags, sattr, fattr, fhandle, &seqid, stateid);
+	if (!status) {
+		if (flags & O_EXCL)
+			status = do_setattr(NFS_SERVER(dir), fattr, fhandle, sattr, stateid);
+		do_close(NFS_SERVER(dir), fhandle, seqid, stateid);
+	}
+	return status;
+}
+
+static int
+nfs4_proc_remove(struct inode *dir, struct qstr *name)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[3];
+	struct nfs4_change_info	dir_cinfo;
+	struct nfs_fattr	dir_attr;
+	u32			dir_bmres[2];
+	int			status;
+
+	dir_attr.valid = 0;
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "remove");
+	nfs4_setup_putfh(&compound, NFS_FH(dir));
+	nfs4_setup_remove(&compound, name, &dir_cinfo);
+	nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+	status = nfs4_call_compound(&compound, NULL, 0);
+
+	if (!status) {
+		process_cinfo(&dir_cinfo, &dir_attr);
+		nfs_refresh_inode(dir, &dir_attr);
+	}
+	return status;
+}
+
+struct unlink_desc {
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[3];
+	struct nfs4_change_info	cinfo;
+	struct nfs_fattr	attrs;
+};
+
+static int
+nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+{
+	struct unlink_desc *	up;
+	struct nfs4_compound *	cp;
+	u32			bmres[2];
+
+	up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL);
+	if (!up)
+		return -ENOMEM;
+	cp = &up->compound;
+	
+	nfs4_setup_compound(cp, up->ops, NFS_SERVER(dir->d_inode), "unlink_setup");
+	nfs4_setup_putfh(cp, NFS_FH(dir->d_inode));
+	nfs4_setup_remove(cp, name, &up->cinfo);
+	nfs4_setup_getattr(cp, &up->attrs, bmres);
+	
+	msg->rpc_proc = NFSPROC4_COMPOUND;
+	msg->rpc_argp = cp;
+	msg->rpc_resp = cp;
+	return 0;
+}
+
+static int
+nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+{
+	struct rpc_message *msg = &task->tk_msg;
+	struct unlink_desc *up;
+	
+	if (msg->rpc_argp) {
+		up = (struct unlink_desc *) msg->rpc_argp;
+		process_lease(&up->compound);
+		process_cinfo(&up->cinfo, &up->attrs);
+		nfs_refresh_inode(dir->d_inode, &up->attrs);
+		kfree(up);
+		msg->rpc_argp = NULL;
+	}
+	return 0;
+}
+
+static int
+nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
+		 struct inode *new_dir, struct qstr *new_name)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[7];
+	struct nfs4_change_info	old_cinfo, new_cinfo;
+	struct nfs_fattr	old_dir_attr, new_dir_attr;
+	u32			old_dir_bmres[2], new_dir_bmres[2];
+	int			status;
+
+	old_dir_attr.valid = 0;
+	new_dir_attr.valid = 0;
+	
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(old_dir), "rename");
+	nfs4_setup_putfh(&compound, NFS_FH(old_dir));
+	nfs4_setup_savefh(&compound);
+	nfs4_setup_putfh(&compound, NFS_FH(new_dir));
+	nfs4_setup_rename(&compound, old_name, new_name, &old_cinfo, &new_cinfo);
+	nfs4_setup_getattr(&compound, &new_dir_attr, new_dir_bmres);
+	nfs4_setup_restorefh(&compound);
+	nfs4_setup_getattr(&compound, &old_dir_attr, old_dir_bmres);
+	status = nfs4_call_compound(&compound, NULL, 0);
+
+	if (!status) {
+		process_cinfo(&old_cinfo, &old_dir_attr);
+		process_cinfo(&new_cinfo, &new_dir_attr);
+		nfs_refresh_inode(old_dir, &old_dir_attr);
+		nfs_refresh_inode(new_dir, &new_dir_attr);
+	}
+	return status;
+}
+
+static int
+nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[7];
+	struct nfs4_change_info	dir_cinfo;
+	struct nfs_fattr	dir_attr, fattr;
+	u32			dir_bmres[2], bmres[2];
+	int			status;
+	
+	dir_attr.valid = 0;
+	fattr.valid = 0;
+	
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "link");
+	nfs4_setup_putfh(&compound, NFS_FH(inode));
+	nfs4_setup_savefh(&compound);
+	nfs4_setup_putfh(&compound, NFS_FH(dir));
+	nfs4_setup_link(&compound, name, &dir_cinfo);
+	nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+	nfs4_setup_restorefh(&compound);
+	nfs4_setup_getattr(&compound, &fattr, bmres);
+	status = nfs4_call_compound(&compound, NULL, 0);
+
+	if (!status) {
+		process_cinfo(&dir_cinfo, &dir_attr);
+		nfs_refresh_inode(dir, &dir_attr);
+		nfs_refresh_inode(inode, &fattr);
+	}
+	return status;
+}
+
+static int
+nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
+		  struct iattr *sattr, struct nfs_fh *fhandle,
+		  struct nfs_fattr *fattr)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[7];
+	struct nfs_fattr	dir_attr;
+	u32			dir_bmres[2], bmres[2];
+	struct nfs4_change_info	dir_cinfo;
+	int			status;
+
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "symlink");
+	nfs4_setup_putfh(&compound, NFS_FH(dir));
+	nfs4_setup_savefh(&compound);
+	nfs4_setup_create_symlink(&compound, name, path, sattr, &dir_cinfo);
+	nfs4_setup_getattr(&compound, fattr, bmres);
+	nfs4_setup_getfh(&compound, fhandle);
+	nfs4_setup_restorefh(&compound);
+	nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+	status = nfs4_call_compound(&compound, NULL, 0);
+
+	if (!status) {
+		process_cinfo(&dir_cinfo, &dir_attr);
+		nfs_refresh_inode(dir, &dir_attr);
+	}
+	return status;
+}
+
+static int
+nfs4_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
+		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[7];
+	struct nfs_fattr	dir_attr;
+	u32			dir_bmres[2], bmres[2];
+	struct nfs4_change_info	dir_cinfo;
+	int			status;
+
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mkdir");
+	nfs4_setup_putfh(&compound, NFS_FH(dir));
+	nfs4_setup_savefh(&compound);
+	nfs4_setup_create_dir(&compound, name, sattr, &dir_cinfo);
+	nfs4_setup_getattr(&compound, fattr, bmres);
+	nfs4_setup_getfh(&compound, fhandle);
+	nfs4_setup_restorefh(&compound);
+	nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+	status = nfs4_call_compound(&compound, NULL, 0);
+
+	if (!status) {
+		process_cinfo(&dir_cinfo, &dir_attr);
+		nfs_refresh_inode(dir, &dir_attr);
+	}
+	return status;
+}
+
+static int
+nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
+                  u64 cookie, struct page *page, unsigned int count, int plus)
+{
+	struct inode		*dir = dentry->d_inode;
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[2];
+	int			status;
+
+	lock_kernel();
+
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "readdir");
+	nfs4_setup_putfh(&compound, NFS_FH(dir));
+	nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry);
+	status = nfs4_call_compound(&compound, cred, 0);
+
+	unlock_kernel();
+	return status;
+}
+
+static int
+nfs4_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
+		dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[7];
+	struct nfs_fattr	dir_attr;
+	u32			dir_bmres[2], bmres[2];
+	struct nfs4_change_info	dir_cinfo;
+	int			status;
+
+	dir_attr.valid = 0;
+	fattr->valid = 0;
+	
+	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mknod");
+	nfs4_setup_putfh(&compound, NFS_FH(dir));
+	nfs4_setup_savefh(&compound);
+	nfs4_setup_create_special(&compound, name, rdev,sattr, &dir_cinfo);
+	nfs4_setup_getattr(&compound, fattr, bmres);
+	nfs4_setup_getfh(&compound, fh);
+	nfs4_setup_restorefh(&compound);
+	nfs4_setup_getattr(&compound, &dir_attr, dir_bmres);
+	status = nfs4_call_compound(&compound, NULL, 0);
+
+	if (!status) {
+		process_cinfo(&dir_cinfo, &dir_attr);
+		nfs_refresh_inode(dir, &dir_attr);
+	}
+	return status;
+}
+
+static int
+nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+		 struct nfs_fsstat *fsstat)
+{
+	struct nfs4_compound compound;
+	struct nfs4_op ops[2];
+	u32 bmres[2];
+
+	memset(fsstat, 0, sizeof(*fsstat));
+	nfs4_setup_compound(&compound, ops, server, "statfs");
+	nfs4_setup_putfh(&compound, fhandle);
+	nfs4_setup_statfs(&compound, fsstat, bmres);
+	return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+		 struct nfs_fsinfo *fsinfo)
+{
+	struct nfs4_compound compound;
+	struct nfs4_op ops[2];
+	u32 bmres[2];
+
+	memset(fsinfo, 0, sizeof(*fsinfo));
+	nfs4_setup_compound(&compound, ops, server, "statfs");
+	nfs4_setup_putfh(&compound, fhandle);
+	nfs4_setup_fsinfo(&compound, fsinfo, bmres);
+	return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static int
+nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+		   struct nfs_pathconf *pathconf)
+{
+	struct nfs4_compound compound;
+	struct nfs4_op ops[2];
+	u32 bmres[2];
+
+	memset(pathconf, 0, sizeof(*pathconf));
+	nfs4_setup_compound(&compound, ops, server, "statfs");
+	nfs4_setup_putfh(&compound, fhandle);
+	nfs4_setup_pathconf(&compound, pathconf, bmres);
+	return nfs4_call_compound(&compound, NULL, 0);
+}
+
+static void
+nfs4_read_done(struct rpc_task *task)
+{
+	struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
+
+	process_lease(&data->u.v4.compound);
+	nfs_readpage_result(task, data->u.v4.res_count, data->u.v4.res_eof);
+}
+
+static void
+nfs4_proc_read_setup(struct nfs_read_data *data, unsigned int count)
+{
+	struct rpc_task	*task = &data->task;
+	struct nfs4_compound *cp = &data->u.v4.compound;
+	struct rpc_message msg = {
+		.rpc_proc = NFSPROC4_COMPOUND,
+		.rpc_argp = cp,
+		.rpc_resp = cp,
+		.rpc_cred = data->cred,
+	};
+	struct inode *inode = data->inode;
+	struct nfs_page *req = nfs_list_entry(data->pages.next);
+	int flags;
+
+	nfs4_setup_compound(cp, data->u.v4.ops, NFS_SERVER(inode), "read [async]");
+	nfs4_setup_putfh(cp, NFS_FH(inode));
+	nfs4_setup_read(cp, req_offset(req) + req->wb_offset,
+			count, data->pagevec, req->wb_offset,
+			&data->u.v4.res_eof,
+			&data->u.v4.res_count);
+
+	/* N.B. Do we need to test? Never called for swapfile inode */
+	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
+
+	/* Finalize the task. */
+	rpc_init_task(task, NFS_CLIENT(inode), nfs4_read_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_readdata_release;
+
+	rpc_call_setup(task, &msg, 0);
+}
+
+static void
+nfs4_write_done(struct rpc_task *task)
+{
+	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	
+	process_lease(&data->u.v4.compound);
+	nfs_writeback_done(task, data->u.v4.arg_stable,
+			   data->u.v4.arg_count, data->u.v4.res_count);
+}
+
+static void
+nfs4_proc_write_setup(struct nfs_write_data *data, unsigned int count, int how)
+{
+	struct rpc_task	*task = &data->task;
+	struct nfs4_compound *cp = &data->u.v4.compound;
+	struct rpc_message msg = {
+		.rpc_proc = NFSPROC4_COMPOUND,
+		.rpc_argp = cp,
+		.rpc_resp = cp,
+		.rpc_cred = data->cred,
+	};
+	struct inode *inode = data->inode;
+	struct nfs_page *req = nfs_list_entry(data->pages.next);
+	int stable;
+	int flags;
+	
+	if (how & FLUSH_STABLE) {
+		if (!NFS_I(inode)->ncommit)
+			stable = NFS_FILE_SYNC;
+		else
+			stable = NFS_DATA_SYNC;
+	} else
+		stable = NFS_UNSTABLE;
+
+	nfs4_setup_compound(cp, data->u.v4.ops, NFS_SERVER(inode), "write [async]");
+	nfs4_setup_putfh(cp, NFS_FH(inode));
+	nfs4_setup_write(cp, req_offset(req) + req->wb_offset,
+			 count, stable, data->pagevec, req->wb_offset,
+			 &data->u.v4.res_count, &data->verf);
+
+	/* Set the initial flags for the task.  */
+	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
+	/* Finalize the task. */
+	rpc_init_task(task, NFS_CLIENT(inode), nfs4_write_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_writedata_release;
+
+	rpc_call_setup(task, &msg, 0);
+}
+
+static void
+nfs4_commit_done(struct rpc_task *task)
+{
+	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	
+	process_lease(&data->u.v4.compound);
+	nfs_commit_done(task);
+}
+
+static void
+nfs4_proc_commit_setup(struct nfs_write_data *data, u64 start, u32 len, int how)
+{
+	struct rpc_task	*task = &data->task;
+	struct nfs4_compound *cp = &data->u.v4.compound;
+	struct rpc_message msg = {
+		.rpc_proc = NFSPROC4_COMPOUND,
+		.rpc_argp = cp,
+		.rpc_resp = cp,
+		.rpc_cred = data->cred,
+	};	
+	struct inode *inode = data->inode;
+	int flags;
+	
+	nfs4_setup_compound(cp, data->u.v4.ops, NFS_SERVER(inode), "commit [async]");
+	nfs4_setup_putfh(cp, NFS_FH(inode));
+	nfs4_setup_commit(cp, start, len, &data->verf);
+	
+	/* Set the initial flags for the task.  */
+	flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC;
+
+	/* Finalize the task. */
+	rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	task->tk_release = nfs_writedata_release;
+	
+	rpc_call_setup(task, &msg, 0);	
+}
+
+/*
+ * nfs4_proc_renew(): This is not one of the nfs_rpc_ops; it is a special
+ * standalone procedure for queueing an asynchronous RENEW.
+ */
+struct renew_desc {
+	struct rpc_task		task;
+	struct nfs4_compound	compound;
+	struct nfs4_op		ops[1];
+};
+
+static void
+renew_done(struct rpc_task *task)
+{
+	struct nfs4_compound *cp = (struct nfs4_compound *) task->tk_msg.rpc_argp;
+	process_lease(cp);
+}
+
+static void
+renew_release(struct rpc_task *task)
+{
+	kfree(task->tk_calldata);
+	task->tk_calldata = NULL;
+}
+
+int
+nfs4_proc_renew(struct nfs_server *server)
+{
+	struct renew_desc *rp;
+	struct rpc_task *task;
+	struct nfs4_compound *cp;
+	struct rpc_message msg;
+
+	rp = (struct renew_desc *) kmalloc(sizeof(*rp), GFP_KERNEL);
+	if (!rp)
+		return -ENOMEM;
+	cp = &rp->compound;
+	task = &rp->task;
+	
+	nfs4_setup_compound(cp, rp->ops, server, "renew");
+	nfs4_setup_renew(cp);
+	
+	msg.rpc_proc = NFSPROC4_COMPOUND;
+	msg.rpc_argp = cp;
+	msg.rpc_resp = cp;
+	msg.rpc_cred = NULL;
+	rpc_init_task(task, server->client, renew_done, RPC_TASK_ASYNC);
+	rpc_call_setup(task, &msg, 0);
+	task->tk_calldata = rp;
+	task->tk_release = renew_release;
+	
+	return rpc_execute(task);
+}
+
+struct nfs_rpc_ops	nfs_v4_clientops = {
+	.version	= 4,			/* protocol version */
+	.getroot	= nfs4_proc_get_root,
+	.getattr	= nfs4_proc_getattr,
+	.setattr	= nfs4_proc_setattr,
+	.lookup		= nfs4_proc_lookup,
+	.access		= nfs4_proc_access,
+	.readlink	= nfs4_proc_readlink,
+	.read		= nfs4_proc_read,
+	.write		= nfs4_proc_write,
+	.commit		= NULL,
+	.create		= nfs4_proc_create,
+	.remove		= nfs4_proc_remove,
+	.unlink_setup	= nfs4_proc_unlink_setup,
+	.unlink_done	= nfs4_proc_unlink_done,
+	.rename		= nfs4_proc_rename,
+	.link		= nfs4_proc_link,
+	.symlink	= nfs4_proc_symlink,
+	.mkdir		= nfs4_proc_mkdir,
+	.rmdir		= nfs4_proc_remove,
+	.readdir	= nfs4_proc_readdir,
+	.mknod		= nfs4_proc_mknod,
+	.statfs		= nfs4_proc_statfs,
+	.fsinfo		= nfs4_proc_fsinfo,
+	.pathconf	= nfs4_proc_pathconf,
+	.decode_dirent	= nfs4_decode_dirent,
+	.read_setup	= nfs4_proc_read_setup,
+	.write_setup	= nfs4_proc_write_setup,
+	.commit_setup	= nfs4_proc_commit_setup,
+};
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff -Nru a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/nfs/nfs4renewd.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,110 @@
+/*
+ *  fs/nfs/nfs4renewd.c
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Implementation of the NFSv4 "renew daemon", which wakes up periodically to
+ * send a RENEW, to keep state alive on the server.  The daemon is implemented
+ * as an rpc_task, not a real kernel thread, so it always runs in rpciod's
+ * context.  There is one renewd per nfs_server.
+ *
+ * TODO: If the send queue gets backlogged (e.g., if the server goes down),
+ * we will keep filling the queue with periodic RENEW requests.  We need a
+ * mechanism for ensuring that if renewd successfully sends off a request,
+ * then it only wakes up when the request is finished.  Maybe use the
+ * child task framework of the RPC layer?
+ */
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/clnt.h>
+
+#include <linux/nfs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+
+static RPC_WAITQ(nfs4_renewd_queue, "nfs4_renewd_queue");
+
+static void
+renewd(struct rpc_task *task)
+{
+	struct nfs_server *server = (struct nfs_server *)task->tk_calldata;
+	unsigned long lease = server->lease_time;
+	unsigned long last = server->last_renewal;
+	unsigned long timeout;
+
+	if (!server->nfs4_state)
+		timeout = (2 * lease) / 3;
+	else if (jiffies < last + lease/3)
+		timeout = (2 * lease) / 3 + last - jiffies;
+	else {
+		/* Queue an asynchronous RENEW. */
+		nfs4_proc_renew(server);
+		timeout = (2 * lease) / 3;
+	}
+
+	if (timeout < 5 * HZ)    /* safeguard */
+		timeout = 5 * HZ;
+	task->tk_timeout = timeout;
+	task->tk_action = renewd;
+	task->tk_exit = NULL;
+	rpc_sleep_on(&nfs4_renewd_queue, task, NULL, NULL);
+	return;
+}
+
+int
+nfs4_init_renewd(struct nfs_server *server)
+{
+	struct rpc_task *task;
+	int status;
+
+	lock_kernel();
+	status = -ENOMEM;
+	task = rpc_new_task(server->client, NULL, RPC_TASK_ASYNC);
+	if (!task)
+		goto out;
+	task->tk_calldata = server;
+	task->tk_action = renewd;
+	status = rpc_execute(task);
+
+out:
+	unlock_kernel();
+	return status;
+}
+
+/*
+ * Local variables:
+ *   c-basic-offset: 8
+ * End:
+ */
diff -Nru a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/nfs/nfs4state.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,81 @@
+/*
+ *  fs/nfs/nfs4state.c
+ *
+ *  Client-side XDR for NFSv4.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Implementation of the NFSv4 state model.  For the time being,
+ * this is minimal, but will be made much more complex in a
+ * subsequent patch.
+ */
+
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/nfs_fs.h>
+
+/*
+ * nfs4_get_client(): returns an empty client structure
+ * nfs4_put_client(): drops reference to client structure
+ *
+ * Since these are allocated/deallocated very rarely, we don't
+ * bother putting them in a slab cache...
+ */
+struct nfs4_client *
+nfs4_get_client(void)
+{
+        struct nfs4_client *clp;
+
+        if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL))) {
+                atomic_set(&clp->cl_count, 1);
+                clp->cl_clientid = 0;
+                INIT_LIST_HEAD(&clp->cl_lockowners);
+        }
+        return clp;
+}
+
+void
+nfs4_put_client(struct nfs4_client *clp)
+{
+        BUG_ON(!clp);
+        BUG_ON(!atomic_read(&clp->cl_count));
+        
+        if (atomic_dec_and_test(&clp->cl_count)) {
+                BUG_ON(!list_empty(&clp->cl_lockowners));
+                kfree(clp);
+        }
+}
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff -Nru a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/nfs/nfs4xdr.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,1777 @@
+/*
+ *  fs/nfs/nfs4xdr.c
+ *
+ *  Client-side XDR for NFSv4.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kendrick Smith <kmsmith@umich.edu>
+ *  Andy Adamson   <andros@umich.edu>
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the University nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/param.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/pagemap.h>
+#include <linux/proc_fs.h>
+#include <linux/kdev_t.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs4.h>
+#include <linux/nfs_fs.h>
+
+/* Emperically, it seems that the NFS client gets confused if
+ * cookies larger than this are returned -- presumably a
+ * signedness issue?
+ */
+#define COOKIE_MAX		0x7fffffff
+
+#define NFS4_CLIENTID(server)	((server)->nfs4_state->cl_clientid)
+
+#define NFSDBG_FACILITY		NFSDBG_XDR
+
+/* Mapping from NFS error code to "errno" error code. */
+#define errno_NFSERR_IO		EIO
+
+extern int			nfs_stat_to_errno(int);
+
+#define NFS4_enc_void_sz	0
+#define NFS4_dec_void_sz	0
+#define NFS4_enc_compound_sz	1024  /* XXX: large enough? */
+#define NFS4_dec_compound_sz	1024  /* XXX: large enough? */
+
+static struct {
+	unsigned int	mode;
+	unsigned int	nfs2type;
+} nfs_type2fmt[] = {
+	{ 0,		NFNON	     },
+	{ S_IFREG,	NFREG	     },
+	{ S_IFDIR,	NFDIR	     },
+	{ S_IFBLK,	NFBLK	     },
+	{ S_IFCHR,	NFCHR	     },
+	{ S_IFLNK,	NFLNK	     },
+	{ S_IFSOCK,	NFSOCK	     },
+	{ S_IFIFO,	NFFIFO	     },
+	{ 0,		NFNON	     },
+	{ 0,		NFNON	     },
+};
+
+/*
+ * START OF "GENERIC" ENCODE ROUTINES.
+ *   These may look a little ugly since they are imported from a "generic"
+ * set of XDR encode/decode routines which are intended to be shared by
+ * all of our NFSv4 implementations (OpenBSD, MacOS X...).
+ *
+ * If the pain of reading these is too great, it should be a straightforward
+ * task to translate them into Linux-specific versions which are more
+ * consistent with the style used in NFSv2/v3...
+ */
+#define ENCODE_HEAD						\
+	u32 *p;
+#define ENCODE_TAIL						\
+	return 0
+
+#define WRITE32(n)               *p++ = htonl(n)
+#define WRITE64(n)               do {				\
+	*p++ = htonl((u32)((n) >> 32));				\
+	*p++ = htonl((u32)(n));					\
+} while (0)
+#define WRITEMEM(ptr,nbytes)     do {				\
+	p = xdr_writemem(p, ptr, nbytes);			\
+} while (0)
+
+#define RESERVE_SPACE(nbytes)	do { BUG_ON(cp->p + XDR_QUADLEN(nbytes) > cp->end); p = cp->p; } while (0)
+#define ADJUST_ARGS()           cp->p = p
+
+static inline
+u32 *xdr_writemem(u32 *p, const void *ptr, int nbytes)
+{
+	int tmp = XDR_QUADLEN(nbytes);
+	if (!tmp)
+		return p;
+	p[tmp-1] = 0;
+	memcpy(p, ptr, nbytes);
+	return p + tmp;
+}
+
+/*
+ * FIXME: The following dummy entries will be replaced once the userland
+ * upcall gets in...
+ */
+static int
+encode_uid(char *p, uid_t uid)
+{
+	strcpy(p, "nobody");
+	return 6;
+}
+
+/*
+ * FIXME: The following dummy entries will be replaced once the userland
+ * upcall gets in...
+ */
+static int
+encode_gid(char *p, gid_t gid)
+{
+	strcpy(p, "nobody");
+	return 6;
+}
+
+static int
+encode_attrs(struct nfs4_compound *cp, struct iattr *iap)
+{
+	char owner_name[256];
+	char owner_group[256];
+	int owner_namelen = 0;
+	int owner_grouplen = 0;
+	u32 *q;
+	int len;
+	u32 bmval0 = 0;
+	u32 bmval1 = 0;
+	int status;
+	ENCODE_HEAD;
+
+	/*
+	 * We reserve enough space to write the entire attribute buffer at once.
+	 * In the worst-case, this would be
+	 *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
+	 *          = 36 bytes, plus any contribution from variable-length fields
+	 *            such as owner/group/acl's.
+	 */
+	len = 36;
+
+	/* Sigh */
+	if (iap->ia_valid & ATTR_UID) {
+		status = owner_namelen = encode_uid(owner_name, iap->ia_uid);
+		if (status < 0) {
+			printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
+			       iap->ia_uid);
+			goto out;
+		}
+		len += XDR_QUADLEN(owner_namelen);
+	}
+	if (iap->ia_valid & ATTR_GID) {
+		status = owner_grouplen = encode_gid(owner_group, iap->ia_gid);
+		if (status < 0) {
+			printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
+			       iap->ia_gid);
+			goto out;
+		}
+		len += XDR_QUADLEN(owner_grouplen);
+	}
+	RESERVE_SPACE(len);
+
+	/*
+	 * We write the bitmap length now, but leave the bitmap and the attribute
+	 * buffer length to be backfilled at the end of this routine.
+	 */
+	WRITE32(2);
+	q = p;
+	p += 3;
+
+	if (iap->ia_valid & ATTR_SIZE) {
+		bmval0 |= FATTR4_WORD0_SIZE;
+		WRITE64(iap->ia_size);
+	}
+	if (iap->ia_valid & ATTR_MODE) {
+		bmval1 |= FATTR4_WORD1_MODE;
+		WRITE32(iap->ia_mode);
+	}
+	if (iap->ia_valid & ATTR_UID) {
+		bmval1 |= FATTR4_WORD1_OWNER;
+		WRITE32(owner_namelen);
+		WRITEMEM(owner_name, owner_namelen);
+		p += owner_namelen;
+	}
+	if (iap->ia_valid & ATTR_GID) {
+		bmval1 |= FATTR4_WORD1_OWNER_GROUP;
+		WRITE32(owner_grouplen);
+		WRITEMEM(owner_group, owner_grouplen);
+		p += owner_namelen;
+	}
+	if (iap->ia_valid & ATTR_ATIME_SET) {
+		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
+		WRITE32(NFS4_SET_TO_CLIENT_TIME);
+		WRITE32(0);
+		WRITE32(iap->ia_mtime);
+		WRITE32(0);
+	}
+	else if (iap->ia_valid & ATTR_ATIME) {
+		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
+		WRITE32(NFS4_SET_TO_SERVER_TIME);
+	}
+	if (iap->ia_valid & ATTR_MTIME_SET) {
+		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
+		WRITE32(NFS4_SET_TO_CLIENT_TIME);
+		WRITE32(0);
+		WRITE32(iap->ia_mtime);
+		WRITE32(0);
+	}
+	else if (iap->ia_valid & ATTR_MTIME) {
+		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
+		WRITE32(NFS4_SET_TO_SERVER_TIME);
+	}
+	
+	ADJUST_ARGS();
+	
+	/*
+	 * Now we backfill the bitmap and the attribute buffer length.
+	 */
+	len = (char *)p - (char *)q - 12;
+	*q++ = htonl(bmval0);
+	*q++ = htonl(bmval1);
+	*q++ = htonl(len);
+
+	status = 0;
+out:
+	return status;
+}
+
+static int
+encode_access(struct nfs4_compound *cp, struct nfs4_access *access)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(8);
+	WRITE32(OP_ACCESS);
+	WRITE32(access->ac_req_access);
+	ADJUST_ARGS();
+	
+	ENCODE_TAIL;
+}
+
+static int
+encode_close(struct nfs4_compound *cp, struct nfs4_close *close)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(20);
+	WRITE32(OP_CLOSE);
+	WRITE32(close->cl_seqid);
+	WRITEMEM(close->cl_stateid, sizeof(nfs4_stateid));
+	ADJUST_ARGS();
+	
+	ENCODE_TAIL;
+}
+
+static int
+encode_commit(struct nfs4_compound *cp, struct nfs4_commit *commit)
+{
+        ENCODE_HEAD;
+        
+        RESERVE_SPACE(16);
+        WRITE32(OP_COMMIT);
+        WRITE64(commit->co_start);
+        WRITE32(commit->co_len);
+        ADJUST_ARGS();
+
+        ENCODE_TAIL;
+}
+
+static int
+encode_create(struct nfs4_compound *cp, struct nfs4_create *create)
+{
+	ENCODE_HEAD;
+	
+	RESERVE_SPACE(8);
+	WRITE32(OP_CREATE);
+	WRITE32(create->cr_ftype);
+	ADJUST_ARGS();
+
+	switch (create->cr_ftype) {
+	case NF4LNK:
+		RESERVE_SPACE(4 + create->cr_textlen);
+		WRITE32(create->cr_textlen);
+		WRITEMEM(create->cr_text, create->cr_textlen);
+		ADJUST_ARGS();
+		break;
+
+	case NF4BLK: case NF4CHR:
+		RESERVE_SPACE(8);
+		WRITE32(create->cr_specdata1);
+		WRITE32(create->cr_specdata2);
+		ADJUST_ARGS();
+		break;
+
+	default:
+		break;
+	}
+
+	RESERVE_SPACE(4 + create->cr_namelen);
+	WRITE32(create->cr_namelen);
+	WRITEMEM(create->cr_name, create->cr_namelen);
+	ADJUST_ARGS();
+
+	return encode_attrs(cp, create->cr_attrs);
+}
+
+static int
+encode_getattr(struct nfs4_compound *cp, struct nfs4_getattr *getattr)
+{
+        ENCODE_HEAD;
+
+        RESERVE_SPACE(16);
+        WRITE32(OP_GETATTR);
+        WRITE32(2);
+        WRITE32(getattr->gt_bmval[0]);
+        WRITE32(getattr->gt_bmval[1]);
+        ADJUST_ARGS();
+
+        ENCODE_TAIL;
+}
+
+static int
+encode_getfh(struct nfs4_compound *cp)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(4);
+	WRITE32(OP_GETFH);
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_link(struct nfs4_compound *cp, struct nfs4_link *link)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(8 + link->ln_namelen);
+	WRITE32(OP_LINK);
+	WRITE32(link->ln_namelen);
+	WRITEMEM(link->ln_name, link->ln_namelen);
+	ADJUST_ARGS();
+	
+	ENCODE_TAIL;
+}
+
+static int
+encode_lookup(struct nfs4_compound *cp, struct nfs4_lookup *lookup)
+{
+	int len = lookup->lo_name->len;
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(8 + len);
+	WRITE32(OP_LOOKUP);
+	WRITE32(len);
+	WRITEMEM(lookup->lo_name->name, len);
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_open(struct nfs4_compound *cp, struct nfs4_open *open)
+{
+	static int global_id = 0;
+	int id = global_id++;
+	int status;
+	ENCODE_HEAD;
+	
+	/* seqid, share_access, share_deny, clientid, ownerlen, owner, opentype */
+	RESERVE_SPACE(52);
+	WRITE32(OP_OPEN);
+	WRITE32(0);                       /* seqid */
+	WRITE32(open->op_share_access);
+	WRITE32(0);                       /* for us, share_deny== 0 always */
+	WRITE64(NFS4_CLIENTID(cp->server));
+	WRITE32(4);
+	WRITE32(id);
+	WRITE32(open->op_opentype);
+	ADJUST_ARGS();
+	
+	if (open->op_opentype == NFS4_OPEN_CREATE) {
+		if (open->op_createmode == NFS4_CREATE_EXCLUSIVE) {
+			RESERVE_SPACE(12);
+			WRITE32(open->op_createmode);
+			WRITEMEM(open->op_verifier, sizeof(nfs4_verifier));
+			ADJUST_ARGS();
+		}
+		else if (open->op_attrs) {
+			RESERVE_SPACE(4);
+			WRITE32(open->op_createmode);
+			ADJUST_ARGS();
+			if ((status = encode_attrs(cp, open->op_attrs)))
+				return status;
+		}
+		else {
+			RESERVE_SPACE(12);
+			WRITE32(open->op_createmode);
+			WRITE32(0);
+			WRITE32(0);
+			ADJUST_ARGS();
+		}
+	}
+
+	RESERVE_SPACE(8 + open->op_name->len);
+	WRITE32(NFS4_OPEN_CLAIM_NULL);
+	WRITE32(open->op_name->len);
+	WRITEMEM(open->op_name->name, open->op_name->len);
+	ADJUST_ARGS();
+	
+	ENCODE_TAIL;
+}
+
+static int
+encode_open_confirm(struct nfs4_compound *cp, struct nfs4_open_confirm *open_confirm)
+{
+	ENCODE_HEAD;
+
+	/*
+	 * Note: In this "stateless" implementation, the OPEN_CONFIRM
+	 * seqid is always equal to 1.
+	 */
+	RESERVE_SPACE(24);
+	WRITE32(OP_OPEN_CONFIRM);
+	WRITEMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid));
+	WRITE32(1);
+	ADJUST_ARGS();
+	
+	ENCODE_TAIL;
+}
+
+static int
+encode_putfh(struct nfs4_compound *cp, struct nfs4_putfh *putfh)
+{
+	int len = putfh->pf_fhandle->size;
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(8 + len);
+	WRITE32(OP_PUTFH);
+	WRITE32(len);
+	WRITEMEM(putfh->pf_fhandle->data, len);
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_putrootfh(struct nfs4_compound *cp)
+{
+        ENCODE_HEAD;
+        
+        RESERVE_SPACE(4);
+        WRITE32(OP_PUTROOTFH);
+        ADJUST_ARGS();
+
+        ENCODE_TAIL;
+}
+
+static int
+encode_read(struct nfs4_compound *cp, struct nfs4_read *read, struct rpc_rqst *req)
+{
+	struct rpc_auth	*auth = req->rq_task->tk_auth;
+	int		replen;
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(32);
+	WRITE32(OP_READ);
+	WRITE32(0);   /* all-zero stateid! */
+	WRITE32(0);
+	WRITE32(0);
+	WRITE32(0);
+	WRITE64(read->rd_offset);
+	WRITE32(read->rd_length);
+	ADJUST_ARGS();
+
+	/* set up reply iovec
+	 *    toplevel status + taglen + rescount + OP_PUTFH + status
+	 *       + OP_READ + status + eof + datalen = 9
+	 */
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + XDR_QUADLEN(cp->taglen)) << 2;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	xdr_inline_pages(&req->rq_rcv_buf, replen,
+			 read->rd_pages, read->rd_pgbase, read->rd_length);
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_readdir(struct nfs4_compound *cp, struct nfs4_readdir *readdir, struct rpc_rqst *req)
+{
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	int replen;
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(40);
+	WRITE32(OP_READDIR);
+	WRITE64(readdir->rd_cookie);
+	WRITEMEM(readdir->rd_req_verifier, sizeof(nfs4_verifier));
+	WRITE32(readdir->rd_count >> 5);  /* meaningless "dircount" field */
+	WRITE32(readdir->rd_count);
+	WRITE32(2);
+	WRITE32(readdir->rd_bmval[0]);
+	WRITE32(readdir->rd_bmval[1]);
+	ADJUST_ARGS();
+
+	/* set up reply iovec
+	 *    toplevel_status + taglen + rescount + OP_PUTFH + status
+	 *      + OP_READDIR + status + verifer(2)  = 9
+	 */
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + 9 + XDR_QUADLEN(cp->taglen)) << 2;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages,
+			 readdir->rd_pgbase, readdir->rd_count);
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_readlink(struct nfs4_compound *cp, struct nfs4_readlink *readlink, struct rpc_rqst *req)
+{
+	struct rpc_auth *auth = req->rq_task->tk_auth;
+	int replen;
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(4);
+	WRITE32(OP_READLINK);
+	ADJUST_ARGS();
+
+	/* set up reply iovec
+	 *    toplevel_status + taglen + rescount + OP_PUTFH + status
+	 *      + OP_READLINK + status  = 7
+	 */
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + 7 + XDR_QUADLEN(cp->taglen)) << 2;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count);
+	
+	ENCODE_TAIL;
+}
+
+static int
+encode_remove(struct nfs4_compound *cp, struct nfs4_remove *remove)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(8 + remove->rm_namelen);
+	WRITE32(OP_REMOVE);
+	WRITE32(remove->rm_namelen);
+	WRITEMEM(remove->rm_name, remove->rm_namelen);
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_rename(struct nfs4_compound *cp, struct nfs4_rename *rename)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(8 + rename->rn_oldnamelen);
+	WRITE32(OP_RENAME);
+	WRITE32(rename->rn_oldnamelen);
+	WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen);
+	ADJUST_ARGS();
+	
+	RESERVE_SPACE(8 + rename->rn_newnamelen);
+	WRITE32(rename->rn_newnamelen);
+	WRITEMEM(rename->rn_newname, rename->rn_newnamelen);
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_renew(struct nfs4_compound *cp)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(12);
+	WRITE32(OP_RENEW);
+	WRITE64(NFS4_CLIENTID(cp->server));
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_restorefh(struct nfs4_compound *cp)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(4);
+	WRITE32(OP_RESTOREFH);
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_savefh(struct nfs4_compound *cp)
+{
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(4);
+	WRITE32(OP_SAVEFH);
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_setattr(struct nfs4_compound *cp, struct nfs4_setattr *setattr)
+{
+	int status;
+	ENCODE_HEAD;
+	
+        RESERVE_SPACE(20);
+        WRITE32(OP_SETATTR);
+	WRITEMEM(setattr->st_stateid, sizeof(nfs4_stateid));
+        ADJUST_ARGS();
+
+        if ((status = encode_attrs(cp, setattr->st_iap)))
+		return status;
+
+        ENCODE_TAIL;
+}
+
+static int
+encode_setclientid(struct nfs4_compound *cp, struct nfs4_setclientid *setclientid)
+{
+	u32 total_len;
+	u32 len1, len2, len3;
+	ENCODE_HEAD;
+
+	len1 = strlen(setclientid->sc_name);
+	len2 = strlen(setclientid->sc_netid);
+	len3 = strlen(setclientid->sc_uaddr);
+	total_len = XDR_QUADLEN(len1) + XDR_QUADLEN(len2) + XDR_QUADLEN(len3);
+	total_len = (total_len << 2) + 32;
+
+	RESERVE_SPACE(total_len);
+	WRITE32(OP_SETCLIENTID);
+	WRITEMEM(setclientid->sc_verifier, sizeof(nfs4_verifier));
+	WRITE32(len1);
+	WRITEMEM(setclientid->sc_name, len1);
+	WRITE32(setclientid->sc_prog);
+	WRITE32(len2);
+	WRITEMEM(setclientid->sc_netid, len2);
+	WRITE32(len3);
+	WRITEMEM(setclientid->sc_uaddr, len3);
+	WRITE32(setclientid->sc_cb_ident);
+	ADJUST_ARGS();
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_setclientid_confirm(struct nfs4_compound *cp)
+{
+        ENCODE_HEAD;
+
+        RESERVE_SPACE(12 + sizeof(nfs4_verifier));
+        WRITE32(OP_SETCLIENTID_CONFIRM);
+        WRITE64(cp->server->nfs4_state->cl_clientid);
+        WRITEMEM(cp->server->nfs4_state->cl_confirm,sizeof(nfs4_verifier));
+        ADJUST_ARGS();
+
+        ENCODE_TAIL;
+}
+
+static int
+encode_write(struct nfs4_compound *cp, struct nfs4_write *write, struct rpc_rqst *req)
+{
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
+	ENCODE_HEAD;
+
+	RESERVE_SPACE(36);
+	WRITE32(OP_WRITE);
+	WRITE32(0xffffffff);     /* magic stateid -1 */
+	WRITE32(0xffffffff);
+	WRITE32(0xffffffff);
+	WRITE32(0xffffffff);
+	WRITE64(write->wr_offset);
+	WRITE32(write->wr_stable_how);
+	WRITE32(write->wr_len);
+	ADJUST_ARGS();
+
+	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
+	xdr_encode_pages(sndbuf, write->wr_pages, write->wr_pgbase, write->wr_len);
+
+	ENCODE_TAIL;
+}
+
+static int
+encode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
+{
+	int i, status = 0;
+	ENCODE_HEAD;
+
+	dprintk("encode_compound: tag=%.*s\n", (int)cp->taglen, cp->tag);
+	
+	RESERVE_SPACE(12 + cp->taglen);
+	WRITE32(cp->taglen);
+	WRITEMEM(cp->tag, cp->taglen);
+	WRITE32(NFS4_MINOR_VERSION);
+	WRITE32(cp->req_nops);
+	ADJUST_ARGS();
+
+	for (i = 0; i < cp->req_nops; i++) {
+		switch (cp->ops[i].opnum) {
+		case OP_ACCESS:
+			status = encode_access(cp, &cp->ops[i].u.access);
+			break;
+		case OP_CLOSE:
+			status = encode_close(cp, &cp->ops[i].u.close);
+			break;
+		case OP_COMMIT:
+			status = encode_commit(cp, &cp->ops[i].u.commit);
+			break;
+		case OP_CREATE:
+			status = encode_create(cp, &cp->ops[i].u.create);
+			break;
+		case OP_GETATTR:
+			status = encode_getattr(cp, &cp->ops[i].u.getattr);
+			break;
+		case OP_GETFH:
+			status = encode_getfh(cp);
+			break;
+		case OP_LINK:
+			status = encode_link(cp, &cp->ops[i].u.link);
+			break;
+		case OP_LOOKUP:
+			status = encode_lookup(cp, &cp->ops[i].u.lookup);
+			break;
+		case OP_OPEN:
+			status = encode_open(cp, &cp->ops[i].u.open);
+			break;
+		case OP_OPEN_CONFIRM:
+			status = encode_open_confirm(cp, &cp->ops[i].u.open_confirm);
+			break;
+		case OP_PUTFH:
+			status = encode_putfh(cp, &cp->ops[i].u.putfh);
+			break;
+		case OP_PUTROOTFH:
+			status = encode_putrootfh(cp);
+			break;
+		case OP_READ:
+			status = encode_read(cp, &cp->ops[i].u.read, req);
+			break;
+		case OP_READDIR:
+			status = encode_readdir(cp, &cp->ops[i].u.readdir, req);
+			break;
+		case OP_READLINK:
+			status = encode_readlink(cp, &cp->ops[i].u.readlink, req);
+			break;
+		case OP_REMOVE:
+			status = encode_remove(cp, &cp->ops[i].u.remove);
+			break;
+		case OP_RENAME:
+			status = encode_rename(cp, &cp->ops[i].u.rename);
+			break;
+		case OP_RENEW:
+			status = encode_renew(cp);
+			break;
+		case OP_RESTOREFH:
+			status = encode_restorefh(cp);
+			break;
+		case OP_SAVEFH:
+			status = encode_savefh(cp);
+			break;
+		case OP_SETATTR:
+			status = encode_setattr(cp, &cp->ops[i].u.setattr);
+			break;
+		case OP_SETCLIENTID:
+			status = encode_setclientid(cp, &cp->ops[i].u.setclientid);
+			break;
+		case OP_SETCLIENTID_CONFIRM:
+			status = encode_setclientid_confirm(cp);
+			break;
+		case OP_WRITE:
+			status = encode_write(cp, &cp->ops[i].u.write, req);
+			break;
+		default:
+			BUG();
+		}
+		if (status)
+			return status;
+	}
+	
+	ENCODE_TAIL;
+}
+/*
+ * END OF "GENERIC" ENCODE ROUTINES.
+ */
+
+
+/*
+ * Encode void argument
+ */
+static int
+nfs4_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
+{
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
+ * Encode COMPOUND argument
+ */
+static int
+nfs4_xdr_enc_compound(struct rpc_rqst *req, u32 *p, struct nfs4_compound *cp)
+{
+	int status;
+	struct xdr_buf *sndbuf = &req->rq_snd_buf;
+	
+	cp->p = p;
+	cp->end = (u32 *) ((char *)req->rq_svec[0].iov_base + req->rq_svec[0].iov_len);
+	status = encode_compound(cp, req);
+	cp->timestamp = jiffies;
+
+	if (!status && !sndbuf->page_len)
+		req->rq_slen = xdr_adjust_iovec(sndbuf->head, cp->p);
+	return status;
+}
+
+
+/*
+ * START OF "GENERIC" DECODE ROUTINES.
+ *   These may look a little ugly since they are imported from a "generic"
+ * set of XDR encode/decode routines which are intended to be shared by
+ * all of our NFSv4 implementations (OpenBSD, MacOS X...).
+ *
+ * If the pain of reading these is too great, it should be a straightforward
+ * task to translate them into Linux-specific versions which are more
+ * consistent with the style used in NFSv2/v3...
+ */
+#define DECODE_HEAD				\
+	u32 *p;					\
+	int status
+#define DECODE_TAIL				\
+	status = 0;				\
+out:						\
+	return status;				\
+xdr_error:					\
+	printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
+	status = -EIO;				\
+	goto out
+
+#define READ32(x)         (x) = ntohl(*p++)
+#define READ64(x)         do {			\
+	(x) = (u64)ntohl(*p++) << 32;		\
+	(x) |= ntohl(*p++);			\
+} while (0)
+#define READTIME(x)       do {			\
+	p++;					\
+	(x) = (u64)ntohl(*p++) << 32;		\
+	(x) |= ntohl(*p++);			\
+} while (0)
+#define COPYMEM(x,nbytes) do {			\
+	memcpy((x), p, nbytes);			\
+	p += XDR_QUADLEN(nbytes);		\
+} while (0)
+
+#define READ_BUF(nbytes)  do {			\
+	if (nbytes > (u32)((char *)cp->end - (char *)cp->p))  \
+		goto xdr_error;			\
+	p = cp->p;				\
+	cp->p += XDR_QUADLEN(nbytes);		\
+} while (0)
+
+/*
+ * FIXME: The following dummy entry will be replaced once the userland
+ * upcall gets in...
+ */
+static int
+decode_uid(char *p, u32 len, uid_t *uid)
+{
+	*uid = -2;
+	return 0;
+}
+
+/*
+ * FIXME: The following dummy entry will be replaced once the userland
+ * upcall gets in...
+ */
+static int
+decode_gid(char *p, u32 len, gid_t *gid)
+{
+	*gid = -2;
+	return 0;
+}
+
+static int
+decode_change_info(struct nfs4_compound *cp, struct nfs4_change_info *cinfo)
+{
+	DECODE_HEAD;
+
+	READ_BUF(20);
+	READ32(cinfo->atomic);
+	READ64(cinfo->before);
+	READ64(cinfo->after);
+	
+	DECODE_TAIL;
+}
+
+static int
+decode_access(struct nfs4_compound *cp, int nfserr, struct nfs4_access *access)
+{
+	u32 supp, acc;
+	DECODE_HEAD;
+
+	if (!nfserr) {
+		READ_BUF(8);
+		READ32(supp);
+		READ32(acc);
+
+		status = -EIO;
+		if ((supp & ~access->ac_req_access) || (acc & ~supp)) {
+			printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n");
+			goto out;
+		}
+		*access->ac_resp_supported = supp;
+		*access->ac_resp_access = acc;
+	}
+	
+	DECODE_TAIL;
+}
+
+static int
+decode_close(struct nfs4_compound *cp, int nfserr, struct nfs4_close *close)
+{
+	DECODE_HEAD;
+
+	if (!nfserr) {
+		READ_BUF(sizeof(nfs4_stateid));
+		COPYMEM(close->cl_stateid, sizeof(nfs4_stateid));
+	}
+	
+	DECODE_TAIL;
+}
+
+static int
+decode_commit(struct nfs4_compound *cp, int nfserr, struct nfs4_commit *commit)
+{
+        DECODE_HEAD;
+
+        if (!nfserr) {
+                READ_BUF(8);
+                COPYMEM(commit->co_verifier->verifier, 8);
+        }
+
+        DECODE_TAIL;
+}
+
+static int
+decode_create(struct nfs4_compound *cp, int nfserr, struct nfs4_create *create)
+{
+	u32 bmlen;
+	DECODE_HEAD;
+
+	if (!nfserr) {
+		if ((status = decode_change_info(cp, create->cr_cinfo)))
+			goto out;
+		READ_BUF(4);
+		READ32(bmlen);
+		if (bmlen > 2)
+			goto xdr_error;
+		READ_BUF(bmlen << 2);
+	}
+
+	DECODE_TAIL;
+}
+
+extern u32 nfs4_fattr_bitmap[2];
+extern u32 nfs4_fsinfo_bitmap[2];
+extern u32 nfs4_fsstat_bitmap[2];
+extern u32 nfs4_pathconf_bitmap[2];
+
+static int
+decode_getattr(struct nfs4_compound *cp, int nfserr, struct nfs4_getattr *getattr)
+{
+        struct nfs_fattr *nfp = getattr->gt_attrs;
+	struct nfs_fsstat *fsstat = getattr->gt_fsstat;
+	struct nfs_fsinfo *fsinfo = getattr->gt_fsinfo;
+	struct nfs_pathconf *pathconf = getattr->gt_pathconf;
+        u32 bmlen;
+        u32 bmval0 = 0;
+        u32 bmval1 = 0;
+        u32 attrlen;
+        u32 dummy32;
+        u32 len = 0;
+	unsigned int type;
+	int fmode = 0;
+        DECODE_HEAD;
+	
+        if (nfserr)
+                goto success;
+        
+        READ_BUF(4);
+        READ32(bmlen);
+        if (bmlen > 2)
+                goto xdr_error;
+	
+        READ_BUF((bmlen << 2) + 4);
+        if (bmlen > 0)
+                READ32(bmval0);
+        if (bmlen > 1)
+                READ32(bmval1);
+        READ32(attrlen);
+
+	if ((bmval0 & ~getattr->gt_bmval[0]) ||
+	    (bmval1 & ~getattr->gt_bmval[1])) {
+		dprintk("read_attrs: server returned bad attributes!\n");
+		goto xdr_error;
+	}
+	getattr->gt_bmres[0] = bmval0;
+	getattr->gt_bmres[1] = bmval1;
+
+	/*
+	 * In case the server doesn't return some attributes,
+	 * we initialize them here to some nominal values..
+	 */
+	if (nfp) {
+		nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
+		nfp->nlink = 1;
+		nfp->timestamp = jiffies;
+	}
+	if (fsinfo) {
+		fsinfo->rtmult = fsinfo->wtmult = 512;  /* ??? */
+		fsinfo->lease_time = 60;
+	}
+
+        if (bmval0 & FATTR4_WORD0_TYPE) {
+                READ_BUF(4);
+                len += 4;
+                READ32(type);
+                if (type < NF4REG || type > NF4NAMEDATTR) {
+                        dprintk("read_attrs: bad type %d\n", type);
+                        goto xdr_error;
+                }
+		nfp->type = nfs_type2fmt[type].nfs2type;
+		fmode = nfs_type2fmt[type].mode;
+                dprintk("read_attrs: type=%d\n", (u32)nfp->type);
+        }
+        if (bmval0 & FATTR4_WORD0_CHANGE) {
+                READ_BUF(8);
+                len += 8;
+                READ64(nfp->change_attr);
+                dprintk("read_attrs: changeid=%Ld\n", (u64)nfp->change_attr);
+        }
+        if (bmval0 & FATTR4_WORD0_SIZE) {
+                READ_BUF(8);
+                len += 8;
+                READ64(nfp->size);
+                dprintk("read_attrs: size=%Ld\n", (u64)nfp->size);
+        }
+        if (bmval0 & FATTR4_WORD0_FSID) {
+                READ_BUF(16);
+                len += 16;
+                READ64(nfp->fsid_u.nfs4.major);
+                READ64(nfp->fsid_u.nfs4.minor);
+                dprintk("read_attrs: fsid=0x%Lx/0x%Lx\n",
+			nfp->fsid_u.nfs4.major, nfp->fsid_u.nfs4.minor);
+        }
+        if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
+                READ_BUF(4);
+                len += 4;
+                READ32(fsinfo->lease_time);
+                dprintk("read_attrs: lease_time=%d\n", fsinfo->lease_time);
+        }
+        if (bmval0 & FATTR4_WORD0_FILEID) {
+                READ_BUF(8);
+                len += 8;
+                READ64(nfp->fileid);
+                dprintk("read_attrs: fileid=%Ld\n", nfp->fileid);
+        }
+	if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
+		READ_BUF(8);
+		len += 8;
+		READ64(fsstat->afiles);
+		dprintk("read_attrs: files_avail=0x%Lx\n", fsstat->afiles);
+	}
+        if (bmval0 & FATTR4_WORD0_FILES_FREE) {
+                READ_BUF(8);
+                len += 8;
+                READ64(fsstat->ffiles);
+                dprintk("read_attrs: files_free=0x%Lx\n", fsstat->ffiles);
+        }
+        if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
+                READ_BUF(8);
+                len += 8;
+                READ64(fsstat->tfiles);
+                dprintk("read_attrs: files_tot=0x%Lx\n", fsstat->tfiles);
+        }
+        if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
+                READ_BUF(8);
+                len += 8;
+                READ64(fsinfo->maxfilesize);
+                dprintk("read_attrs: maxfilesize=0x%Lx\n", fsinfo->maxfilesize);
+        }
+	if (bmval0 & FATTR4_WORD0_MAXLINK) {
+		READ_BUF(4);
+		len += 4;
+		READ32(pathconf->max_link);
+		dprintk("read_attrs: maxlink=%d\n", pathconf->max_link);
+	}
+        if (bmval0 & FATTR4_WORD0_MAXNAME) {
+                READ_BUF(4);
+                len += 4;
+                READ32(pathconf->max_namelen);
+                dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
+        }
+        if (bmval0 & FATTR4_WORD0_MAXREAD) {
+                READ_BUF(8);
+                len += 8;
+                READ64(fsinfo->rtmax);
+		fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
+                dprintk("read_attrs: maxread=%d\n", fsinfo->rtmax);
+        }
+        if (bmval0 & FATTR4_WORD0_MAXWRITE) {
+                READ_BUF(8);
+                len += 8;
+                READ64(fsinfo->wtmax);
+		fsinfo->wtpref = fsinfo->wtmax;
+                dprintk("read_attrs: maxwrite=%d\n", fsinfo->wtmax);
+        }
+	
+        if (bmval1 & FATTR4_WORD1_MODE) {
+                READ_BUF(4);
+                len += 4;
+                READ32(dummy32);
+		nfp->mode = (dummy32 & ~S_IFMT) | fmode;
+                dprintk("read_attrs: mode=0%o\n", nfp->mode);
+        }
+        if (bmval1 & FATTR4_WORD1_NUMLINKS) {
+                READ_BUF(4);
+                len += 4;
+                READ32(nfp->nlink);
+                dprintk("read_attrs: nlinks=0%o\n", nfp->nlink);
+        }
+        if (bmval1 & FATTR4_WORD1_OWNER) {
+                READ_BUF(4);
+                len += 4;
+                READ32(dummy32);    /* name length */
+                if (dummy32 > XDR_MAX_NETOBJ) {
+			dprintk("read_attrs: name too long!\n");
+                        goto xdr_error;
+                }
+                READ_BUF(dummy32);
+                len += (XDR_QUADLEN(dummy32) << 2);
+                if ((status = decode_uid((char *)p, dummy32, &nfp->uid))) {
+                        dprintk("read_attrs: gss_get_num failed!\n");
+                        goto out;
+                }
+                dprintk("read_attrs: uid=%d\n", (int)nfp->uid);
+        }
+        if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
+                READ_BUF(4);
+                len += 4;
+                READ32(dummy32);
+                if (dummy32 > XDR_MAX_NETOBJ) {
+                        dprintk("read_attrs: name too long!\n");
+                        goto xdr_error;
+                }
+                READ_BUF(dummy32);
+                len += (XDR_QUADLEN(dummy32) << 2);
+                if ((status = decode_gid((char *)p, dummy32, &nfp->gid))) {
+                        dprintk("read_attrs: gss_get_num failed!\n");
+                        goto out;
+                }
+                dprintk("read_attrs: gid=%d\n", (int)nfp->gid);
+        }
+        if (bmval1 & FATTR4_WORD1_RAWDEV) {
+                READ_BUF(8);
+                len += 8;
+                READ32(dummy32);
+		nfp->rdev = (dummy32 << MINORBITS);
+                READ32(dummy32);
+		nfp->rdev |= (dummy32 & MINORMASK);
+                dprintk("read_attrs: rdev=%d\n", nfp->rdev);
+        }
+        if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
+                READ_BUF(8);
+                len += 8;
+                READ64(fsstat->abytes);
+                dprintk("read_attrs: savail=0x%Lx\n", fsstat->abytes);
+        }
+	if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
+                READ_BUF(8);
+                len += 8;
+                READ64(fsstat->fbytes);
+                dprintk("read_attrs: sfree=0x%Lx\n", fsstat->fbytes);
+        }
+        if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
+                READ_BUF(8);
+                len += 8;
+                READ64(fsstat->tbytes);
+                dprintk("read_attrs: stotal=0x%Lx\n", fsstat->tbytes);
+        }
+        if (bmval1 & FATTR4_WORD1_SPACE_USED) {
+                READ_BUF(8);
+                len += 8;
+                READ64(nfp->du.nfs3.used);
+                dprintk("read_attrs: sused=0x%Lx\n", nfp->du.nfs3.used);
+        }
+        if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
+                READ_BUF(12);
+                len += 12;
+                READTIME(nfp->atime);
+                dprintk("read_attrs: atime=%d\n", (int)nfp->atime);
+        }
+        if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
+                READ_BUF(12);
+                len += 12;
+                READTIME(nfp->ctime);
+                dprintk("read_attrs: ctime=%d\n", (int)nfp->ctime);
+        }
+        if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
+                READ_BUF(12);
+                len += 12;
+                READTIME(nfp->mtime);
+                dprintk("read_attrs: mtime=%d\n", (int)nfp->mtime);
+        }
+        if (len != attrlen)
+                goto xdr_error;
+	
+success:
+        DECODE_TAIL;
+}
+
+static int
+decode_getfh(struct nfs4_compound *cp, int nfserr, struct nfs4_getfh *getfh)
+{
+	struct nfs_fh *fh = getfh->gf_fhandle;
+	int len;
+        DECODE_HEAD;
+
+	/* Zero handle first to allow comparisons */
+	memset(fh, 0, sizeof(*fh));
+		
+        if (!nfserr) {
+                READ_BUF(4);
+		READ32(len);
+		if (len > NFS_MAXFHSIZE)
+			goto xdr_error;
+		fh->size = len;
+                READ_BUF(len);
+                COPYMEM(fh->data, len);
+        }
+
+        DECODE_TAIL;
+}
+
+static int
+decode_link(struct nfs4_compound *cp, int nfserr, struct nfs4_link *link)
+{
+	int status = 0;
+	
+	if (!nfserr)
+		status = decode_change_info(cp, link->ln_cinfo);
+	return status;
+}
+
+static int
+decode_open(struct nfs4_compound *cp, int nfserr, struct nfs4_open *open)
+{
+	u32 bmlen, delegation_type;
+	DECODE_HEAD;
+	
+	if (!nfserr) {
+		READ_BUF(sizeof(nfs4_stateid));
+		COPYMEM(open->op_stateid, sizeof(nfs4_stateid));
+
+		decode_change_info(cp, open->op_cinfo);
+
+		READ_BUF(8);
+		READ32(*open->op_rflags);
+		READ32(bmlen);
+		if (bmlen > 10)
+			goto xdr_error;
+		
+		READ_BUF((bmlen << 2) + 4);
+		p += bmlen;
+		READ32(delegation_type);
+		if (delegation_type != NFS4_OPEN_DELEGATE_NONE)
+			goto xdr_error;
+	}
+	
+	DECODE_TAIL;
+}
+
+static int
+decode_open_confirm(struct nfs4_compound *cp, int nfserr, struct nfs4_open_confirm *open_confirm)
+{
+	DECODE_HEAD;
+
+	if (!nfserr) {
+		READ_BUF(sizeof(nfs4_stateid));
+		COPYMEM(open_confirm->oc_stateid, sizeof(nfs4_stateid));
+	}
+
+	DECODE_TAIL;
+}
+
+static int
+decode_read(struct nfs4_compound *cp, int nfserr, struct nfs4_read *read)
+{
+	u32 throwaway;
+	DECODE_HEAD;
+
+	if (!nfserr) {
+		READ_BUF(8);
+		if (read->rd_eof)
+			READ32(*read->rd_eof);
+		else
+			READ32(throwaway);
+		READ32(*read->rd_bytes_read);
+		if (*read->rd_bytes_read > read->rd_length)
+			goto xdr_error;
+	}
+
+	DECODE_TAIL;
+}
+
+static int
+decode_readdir(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struct nfs4_readdir *readdir)
+{
+	struct xdr_buf	*rcvbuf = &req->rq_rcv_buf;
+	struct page	*page = *rcvbuf->pages;
+	unsigned int	pglen = rcvbuf->page_len;
+	u32		*end, *entry;
+	u32		len, attrlen, word;
+	int 		i;
+	DECODE_HEAD;
+
+	if (!nfserr) {
+		READ_BUF(8);
+		COPYMEM(readdir->rd_resp_verifier, 8);
+
+		BUG_ON(pglen > PAGE_CACHE_SIZE);
+		p   = (u32 *) kmap(page);
+		end = (u32 *) ((char *)p + pglen + readdir->rd_pgbase);
+
+		while (*p++) {
+			entry = p - 1;
+			if (p + 3 > end)
+				goto short_pkt;
+			p += 2;     /* cookie */
+			len = ntohl(*p++);  /* filename length */
+			if (len > NFS4_MAXNAMLEN) {
+				printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
+				goto err_unmap;
+			}
+			
+			p += XDR_QUADLEN(len);
+			if (p + 1 > end)
+				goto short_pkt;
+			len = ntohl(*p++);  /* bitmap length */
+			if (len > 10) {
+				printk(KERN_WARNING "NFS: giant bitmap in readdir (len 0x%x)\n", len);
+				goto err_unmap;
+			}
+			if (p + len + 1 > end)
+				goto short_pkt;
+			attrlen = 0;
+			for (i = 0; i < len; i++) {
+				word = ntohl(*p++);
+				if (!word)
+					continue;
+				else if (i == 0 && word == FATTR4_WORD0_FILEID) {
+					attrlen = 8;
+					continue;
+				}
+				printk(KERN_WARNING "NFS: unexpected bitmap word in readdir (0x%x)\n", word);
+				goto err_unmap;
+			}
+			if (ntohl(*p++) != attrlen) {
+				printk(KERN_WARNING "NFS: unexpected attrlen in readdir\n");
+				goto err_unmap;
+			}
+			p += XDR_QUADLEN(attrlen);
+			if (p + 1 > end)
+				goto short_pkt;
+		}
+		kunmap(page);
+	}
+	
+	DECODE_TAIL;
+short_pkt:
+	printk(KERN_NOTICE "NFS: short packet in readdir reply!\n");
+	/* truncate listing */
+	kunmap(page);
+	entry[0] = entry[1] = 0;
+	return 0;
+err_unmap:
+	kunmap(page);
+	return -errno_NFSERR_IO;
+}
+
+static int
+decode_readlink(struct nfs4_compound *cp, int nfserr, struct rpc_rqst *req, struct nfs4_readlink *readlink)
+{
+	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
+	u32 *strlen;
+	u32 len;
+	char *string;
+
+	if (!nfserr) {
+		/*
+		 * The XDR encode routine has set things up so that
+		 * the link text will be copied directly into the
+		 * buffer.  We just have to do overflow-checking,
+		 * and and null-terminate the text (the VFS expects
+		 * null-termination).
+		 */
+		strlen = (u32 *) kmap(rcvbuf->pages[0]);
+		len = ntohl(*strlen);
+		if (len > PAGE_CACHE_SIZE - 5) {
+			printk(KERN_WARNING "nfs: server returned giant symlink!\n");
+			kunmap(rcvbuf->pages[0]);
+			return -EIO;
+		}
+		*strlen = len;
+		
+		string = (char *)(strlen + 1);
+		string[len] = '\0';
+		kunmap(rcvbuf->pages[0]);
+	}
+	return 0;
+}
+
+static int
+decode_remove(struct nfs4_compound *cp, int nfserr, struct nfs4_remove *remove)
+{
+	int status;
+
+	status = 0;
+	if (!nfserr) 
+		status = decode_change_info(cp, remove->rm_cinfo);
+	return status;
+}
+
+static int
+decode_rename(struct nfs4_compound *cp, int nfserr, struct nfs4_rename *rename)
+{
+	int status = 0;
+
+	if (!nfserr) {
+		if ((status = decode_change_info(cp, rename->rn_src_cinfo)))
+			goto out;
+		if ((status = decode_change_info(cp, rename->rn_dst_cinfo)))
+			goto out;
+	}
+out:
+	return status;
+}
+
+static int
+decode_setattr(struct nfs4_compound *cp)
+{
+        u32 bmlen;
+        DECODE_HEAD;
+        
+        READ_BUF(4);
+        READ32(bmlen);
+        if (bmlen > 10)
+                goto xdr_error;
+        READ_BUF(bmlen << 2);
+
+        DECODE_TAIL;
+}
+
+static int
+decode_setclientid(struct nfs4_compound *cp, int nfserr)
+{
+	DECODE_HEAD;
+
+	if (!nfserr) {
+		READ_BUF(8 + sizeof(nfs4_verifier));
+		READ64(cp->server->nfs4_state->cl_clientid);
+		COPYMEM(cp->server->nfs4_state->cl_confirm, sizeof(nfs4_verifier));
+	}
+	else if (nfserr == NFSERR_CLID_INUSE) {
+		u32 len;
+
+		/* skip netid string */
+		READ_BUF(4);
+		READ32(len);
+		READ_BUF(len);
+
+		/* skip uaddr string */
+		READ_BUF(4);
+		READ32(len);
+		READ_BUF(len);
+	}
+
+	DECODE_TAIL;
+}
+
+static int
+decode_write(struct nfs4_compound *cp, int nfserr, struct nfs4_write *write)
+{
+	DECODE_HEAD;
+
+	if (!nfserr) {
+		READ_BUF(16);
+		READ32(*write->wr_bytes_written);
+		if (*write->wr_bytes_written > write->wr_len)
+			goto xdr_error;
+		READ32(write->wr_verf->committed);
+		COPYMEM(write->wr_verf->verifier, 8);
+	}
+
+	DECODE_TAIL;
+}
+
+static int
+decode_compound(struct nfs4_compound *cp, struct rpc_rqst *req)
+{
+	u32 taglen;
+	u32 opnum, nfserr;
+	DECODE_HEAD;
+
+	READ_BUF(8);
+	READ32(cp->toplevel_status);
+	READ32(taglen);
+
+	/*
+	 * We need this if our zero-copy I/O is going to work.  Rumor has
+	 * it that the spec will soon mandate it...
+	 */
+	if (taglen != cp->taglen)
+		dprintk("nfs4: non-conforming server returns tag length mismatch!\n");
+
+	READ_BUF(taglen + 4);
+	p += XDR_QUADLEN(taglen);
+	READ32(cp->resp_nops);
+	if (cp->resp_nops > cp->req_nops) {
+		dprintk("nfs4: resp_nops > req_nops!\n");
+		goto xdr_error;
+	}
+
+	for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++) {
+		READ_BUF(8);
+		READ32(opnum);
+		if (opnum != cp->ops[cp->nops].opnum) {
+			dprintk("nfs4: operation mismatch!\n");
+			goto xdr_error;
+		}
+		READ32(nfserr);
+		if (cp->nops == cp->resp_nops - 1) {
+			if (nfserr != cp->toplevel_status) {
+				dprintk("nfs4: status mismatch!\n");
+				goto xdr_error;
+			}
+		}
+		else if (nfserr) {
+			dprintk("nfs4: intermediate status nonzero!\n");
+			goto xdr_error;
+		}
+		cp->ops[cp->nops].nfserr = nfserr;
+
+		switch (opnum) {
+		case OP_ACCESS:
+			status = decode_access(cp, nfserr, &cp->ops[cp->nops].u.access);
+			break;
+		case OP_CLOSE:
+			status = decode_close(cp, nfserr, &cp->ops[cp->nops].u.close);
+			break;
+		case OP_COMMIT:
+			status = decode_commit(cp, nfserr, &cp->ops[cp->nops].u.commit);
+			break;
+		case OP_CREATE:
+			status = decode_create(cp, nfserr, &cp->ops[cp->nops].u.create);
+			break;
+		case OP_GETATTR:
+			status = decode_getattr(cp, nfserr, &cp->ops[cp->nops].u.getattr);
+			break;
+		case OP_GETFH:
+			status = decode_getfh(cp, nfserr, &cp->ops[cp->nops].u.getfh);
+			break;
+		case OP_LINK:
+			status = decode_link(cp, nfserr, &cp->ops[cp->nops].u.link);
+			break;
+		case OP_LOOKUP:
+			status = 0;
+			break;
+		case OP_OPEN:
+			status = decode_open(cp, nfserr, &cp->ops[cp->nops].u.open);
+			break;
+		case OP_OPEN_CONFIRM:
+			status = decode_open_confirm(cp, nfserr, &cp->ops[cp->nops].u.open_confirm);
+			break;
+		case OP_PUTFH:
+			status = 0;
+			break;
+		case OP_PUTROOTFH:
+			status = 0;
+			break;
+		case OP_READ:
+			status = decode_read(cp, nfserr, &cp->ops[cp->nops].u.read);
+			break;
+		case OP_READDIR:
+			status = decode_readdir(cp, nfserr, req, &cp->ops[cp->nops].u.readdir);
+			break;
+		case OP_READLINK:
+			status = decode_readlink(cp, nfserr, req, &cp->ops[cp->nops].u.readlink);
+			break;
+		case OP_RESTOREFH:
+			status = 0;
+			break;
+		case OP_REMOVE:
+			status = decode_remove(cp, nfserr, &cp->ops[cp->nops].u.remove);
+			break;
+		case OP_RENAME:
+			status = decode_rename(cp, nfserr, &cp->ops[cp->nops].u.rename);
+			break;
+		case OP_RENEW:
+			status = 0;
+			break;
+		case OP_SAVEFH:
+			status = 0;
+			break;
+		case OP_SETATTR:
+			status = decode_setattr(cp);
+			break;
+		case OP_SETCLIENTID:
+			status = decode_setclientid(cp, nfserr);
+			break;
+		case OP_SETCLIENTID_CONFIRM:
+			status = 0;
+			break;
+		case OP_WRITE:
+			status = decode_write(cp, nfserr, &cp->ops[cp->nops].u.write);
+			break;
+		default:
+			BUG();
+			return -EIO;
+		}
+		if (status)
+			goto xdr_error;
+	}
+
+	DECODE_TAIL;
+}
+/*
+ * END OF "GENERIC" DECODE ROUTINES.
+ */
+
+/*
+ * Decode void reply
+ */
+static int
+nfs4_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
+{
+	return 0;
+}
+
+/*
+ * Decode COMPOUND response
+ */
+static int
+nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, u32 *p, struct nfs4_compound *cp)
+{
+	int status;
+	
+	cp->p = p;
+	cp->end = (u32 *) ((u8 *) rqstp->rq_rvec->iov_base + rqstp->rq_rvec->iov_len);
+
+	if ((status = decode_compound(cp, rqstp)))
+		goto out;
+	
+	status = 0;
+	if (cp->toplevel_status)
+		status = -nfs_stat_to_errno(cp->toplevel_status);
+
+out:
+	return status;
+}
+
+u32 *
+nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+{
+	u32 len;
+
+	if (!*p++) {
+		if (!*p)
+			return ERR_PTR(-EAGAIN);
+		entry->eof = 1;
+		return ERR_PTR(-EBADCOOKIE);
+	}
+
+	entry->prev_cookie = entry->cookie;
+	p = xdr_decode_hyper(p, &entry->cookie);
+	entry->len = ntohl(*p++);
+	entry->name = (const char *) p;
+	p += XDR_QUADLEN(entry->len);
+
+	if (entry->cookie > COOKIE_MAX)
+		entry->cookie = COOKIE_MAX;
+	
+	/*
+	 * In case the server doesn't return an inode number,
+	 * we fake one here.  (We don't use inode number 0,
+	 * since glibc seems to choke on it...)
+	 */
+	entry->ino = 1;
+
+	len = ntohl(*p++);             /* bitmap length */
+	p += len;
+	len = ntohl(*p++);             /* attribute buffer length */
+	if (len)
+		p = xdr_decode_hyper(p, &entry->ino);
+
+	entry->eof = !p[0] && p[1];
+	return p;
+}
+
+#ifndef MAX
+# define MAX(a, b)	(((a) > (b))? (a) : (b))
+#endif
+
+#define PROC(proc, argtype, restype)				\
+    { "nfs4_" #proc,						\
+      (kxdrproc_t) nfs4_xdr_##argtype,				\
+      (kxdrproc_t) nfs4_xdr_##restype,				\
+      MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2,	\
+      0							\
+    }
+
+static struct rpc_procinfo	nfs4_procedures[] = {
+  PROC(null,		enc_void,	dec_void),
+  PROC(compound,	enc_compound,	dec_compound)
+};
+
+struct rpc_version		nfs_version4 = {
+	.number			= 4,
+	.nrprocs		= sizeof(nfs4_procedures)/sizeof(nfs4_procedures[0]),
+	.procs			= nfs4_procedures
+};
+
+/*
+ * Local variables:
+ *  c-basic-offset: 8
+ * End:
+ */
diff -Nru a/fs/nfs/proc.c b/fs/nfs/proc.c
--- a/fs/nfs/proc.c	Tue Oct 15 20:29:21 2002
+++ b/fs/nfs/proc.c	Tue Oct 15 20:29:21 2002
@@ -460,17 +460,62 @@
 
 static int
 nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fsinfo *info)
+			struct nfs_fsstat *stat)
 {
+	struct nfs2_fsstat fsinfo;
 	int	status;
 
 	dprintk("NFS call  statfs\n");
-	memset((char *)info, 0, sizeof(*info));
-	status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0);
+	stat->fattr->valid = 0;
+	status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &fsinfo, 0);
 	dprintk("NFS reply statfs: %d\n", status);
+	if (status)
+		goto out;
+	stat->tbytes = (u64)fsinfo.blocks * fsinfo.bsize;
+	stat->fbytes = (u64)fsinfo.bfree  * fsinfo.bsize;
+	stat->abytes = (u64)fsinfo.bavail * fsinfo.bsize;
+	stat->tfiles = 0;
+	stat->ffiles = 0;
+	stat->afiles = 0;
+out:
+	return status;
+}
+
+static int
+nfs_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+			struct nfs_fsinfo *info)
+{
+	struct nfs2_fsstat fsinfo;
+	int	status;
+
+	dprintk("NFS call  fsinfo\n");
+	info->fattr->valid = 0;
+	status = rpc_call(server->client, NFSPROC_STATFS, fhandle, &info, 0);
+	dprintk("NFS reply fsinfo: %d\n", status);
+	if (status)
+		goto out;
+	info->rtmax  = NFS_MAXDATA;
+	info->rtpref = fsinfo.tsize;
+	info->rtmult = fsinfo.bsize;
+	info->wtmax  = NFS_MAXDATA;
+	info->wtpref = fsinfo.tsize;
+	info->wtmult = fsinfo.bsize;
+	info->dtpref = fsinfo.tsize;
+	info->maxfilesize = 0x7FFFFFFF;
+	info->lease_time = 0;
+out:
 	return status;
 }
 
+static int
+nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+		  struct nfs_pathconf *info)
+{
+	info->max_link = 0;
+	info->max_namelen = NFS2_MAXNAMLEN;
+	return 0;
+}
+
 extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
 
 static void
@@ -590,6 +635,8 @@
 	.readdir	= nfs_proc_readdir,
 	.mknod		= nfs_proc_mknod,
 	.statfs		= nfs_proc_statfs,
+	.fsinfo		= nfs_proc_fsinfo,
+	.pathconf	= nfs_proc_pathconf,
 	.decode_dirent	= nfs_decode_dirent,
 	.read_setup	= nfs_proc_read_setup,
 	.write_setup	= nfs_proc_write_setup,
diff -Nru a/fs/nfsd/export.c b/fs/nfsd/export.c
--- a/fs/nfsd/export.c	Tue Oct 15 20:29:17 2002
+++ b/fs/nfsd/export.c	Tue Oct 15 20:29:17 2002
@@ -781,7 +781,8 @@
 			expkey_put(&key->h, &svc_expkey_cache);
 		} else
 			dprintk("nfsd: no export %x/%lx for %s\n",
-				nxp->ex_dev, nxp->ex_ino, nxp->ex_client);
+				nxp->ex_dev, (unsigned long) nxp->ex_ino,
+				nxp->ex_client);
 		auth_domain_put(dom);
 		cache_flush();
 	} else
diff -Nru a/fs/open.c b/fs/open.c
--- a/fs/open.c	Tue Oct 15 20:29:12 2002
+++ b/fs/open.c	Tue Oct 15 20:29:12 2002
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/tty.h>
-#include <linux/iobuf.h>
 #include <linux/namei.h>
 #include <linux/backing-dev.h>
 #include <linux/security.h>
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Tue Oct 15 20:29:16 2002
+++ b/fs/partitions/check.c	Tue Oct 15 20:29:16 2002
@@ -18,6 +18,7 @@
 #include <linux/blk.h>
 #include <linux/kmod.h>
 #include <linux/ctype.h>
+#include <../drivers/base/fs/fs.h>	/* Eeeeewwwww */
 
 #include "check.h"
 
@@ -111,115 +112,17 @@
 	return buf;
 }
 
-/* Driverfs file support */
-static ssize_t partition_device_kdev_read(struct device *driverfs_dev, 
-			char *page, size_t count, loff_t off)
-{
-	kdev_t kdev; 
-	kdev.value=(int)(long)driverfs_dev->driver_data;
-	return off ? 0 : sprintf (page, "%x\n",kdev.value);
-}
-static DEVICE_ATTR(kdev,S_IRUGO,partition_device_kdev_read,NULL);
-
-static ssize_t partition_device_type_read(struct device *driverfs_dev, 
-			char *page, size_t count, loff_t off) 
-{
-	return off ? 0 : sprintf (page, "BLK\n");
-}
-static DEVICE_ATTR(type,S_IRUGO,partition_device_type_read,NULL);
-
-static void driverfs_create_partitions(struct gendisk *hd)
-{
-	int max_p = 1<<hd->minor_shift;
-	struct hd_struct *p = hd->part;
-	char name[DEVICE_NAME_SIZE];
-	char bus_id[BUS_ID_SIZE];
-	struct device *dev, *parent;
-	int part;
-
-	/* if driverfs not supported by subsystem, skip partitions */
-	if (!(hd->flags & GENHD_FL_DRIVERFS))
-		return;
-
-	parent = hd->driverfs_dev;
-
-	if (parent)  {
-		sprintf(name, "%s", parent->name);
-		sprintf(bus_id, "%s:", parent->bus_id);
-	} else {
-		*name = *bus_id = '\0';
-	}
-
-	dev = &hd->disk_dev;
-	dev->driver_data = (void *)(long)__mkdev(hd->major, hd->first_minor);
-	sprintf(dev->name, "%sdisc", name);
-	sprintf(dev->bus_id, "%sdisc", bus_id);
-	for (part=1; part < max_p; part++) {
-		dev = &p[part-1].hd_driverfs_dev;
-		sprintf(dev->name, "%spart%d", name, part);
-		sprintf(dev->bus_id, "%s:p%d", bus_id, part);
-		if (!p[part-1].nr_sects)
-			continue;
-		dev->driver_data =
-				(void *)(long)__mkdev(hd->major, hd->first_minor+part);
-	}
-
-	dev = &hd->disk_dev;
-	dev->parent = parent;
-	if (parent)
-		dev->bus = parent->bus;
-	device_register(dev);
-	device_create_file(dev, &dev_attr_type);
-	device_create_file(dev, &dev_attr_kdev);
-
-	for (part=0; part < max_p-1; part++) {
-		dev = &p[part].hd_driverfs_dev;
-		dev->parent = parent;
-		if (parent)
-			dev->bus = parent->bus;
-		if (!dev->driver_data)
-			continue;
-		device_register(dev);
-		device_create_file(dev, &dev_attr_type);
-		device_create_file(dev, &dev_attr_kdev);
-	}
-}
-
-static void driverfs_remove_partitions(struct gendisk *hd)
-{
-	int max_p = 1<<hd->minor_shift;
-	struct device *dev;
-	struct hd_struct *p;
-	int part;
-
-	for (part=1, p = hd->part; part < max_p; part++, p++) {
-		dev = &p->hd_driverfs_dev;
-		if (dev->driver_data) {
-			device_remove_file(dev, &dev_attr_type);
-			device_remove_file(dev, &dev_attr_kdev);
-			put_device(dev);	
-			dev->driver_data = NULL;
-		}
-	}
-	dev = &hd->disk_dev;
-	if (dev->driver_data) {
-		device_remove_file(dev, &dev_attr_type);
-		device_remove_file(dev, &dev_attr_kdev);
-		put_device(dev);	
-		dev->driver_data = NULL;
-	}
-}
-
-static void check_partition(struct gendisk *hd, struct block_device *bdev)
+static struct parsed_partitions *
+check_partition(struct gendisk *hd, struct block_device *bdev)
 {
+	struct parsed_partitions *state;
 	devfs_handle_t de = NULL;
 	char buf[64];
-	struct parsed_partitions *state;
-	int i;
+	int i, res;
 
 	state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL);
 	if (!state)
-		return;
+		return NULL;
 
 	if (hd->flags & GENHD_FL_DEVFS)
 		de = hd->de;
@@ -233,32 +136,20 @@
 		if (isdigit(state->name[strlen(state->name)-1]))
 			sprintf(state->name, "p");
 	}
-	state->limit = 1<<hd->minor_shift;
-	for (i = 0; check_part[i]; i++) {
-		int res, j;
-		struct hd_struct *p;
+	state->limit = hd->minors;
+	i = res = 0;
+	while (!res && check_part[i]) {
 		memset(&state->parts, 0, sizeof(state->parts));
-		res = check_part[i](state, bdev);
-		if (!res)
-			continue;
-		if (res < 0) {
-			if (warn_no_part)
-				printk(" unable to read partition table\n");
-			return;
-		} 
-		p = hd->part;
-		for (j = 1; j < state->limit; j++) {
-			p[j-1].start_sect = state->parts[j].from;
-			p[j-1].nr_sects = state->parts[j].size;
-#if CONFIG_BLK_DEV_MD
-			if (!state->parts[j].flags)
-				continue;
-			md_autodetect_dev(bdev->bd_dev+j);
-#endif
-		}
-		return;
+		res = check_part[i++](state, bdev);
 	}
-	printk(" unknown partition table\n");
+	if (res > 0)
+		return state;
+	if (!res)
+		printk(" unknown partition table\n");
+	else if (warn_no_part)
+		printk(" unable to read partition table\n");
+	kfree(state);
+	return NULL;
 }
 
 static void devfs_register_partition(struct gendisk *dev, int part)
@@ -298,7 +189,7 @@
 	unsigned int devfs_flags = DEVFS_FL_DEFAULT;
 	char dirname[64], symlink[16];
 	static devfs_handle_t devfs_handle;
-	int part, max_p = 1<<dev->minor_shift;
+	int part, max_p = dev->minors;
 	struct hd_struct *p = dev->part;
 
 	if (dev->flags & GENHD_FL_REMOVABLE)
@@ -329,9 +220,6 @@
 	devfs_auto_unregister(dev->disk_de, slave);
 	if (!(dev->flags & GENHD_FL_DEVFS))
 		devfs_auto_unregister (slave, dir);
-	for (part = 1; part < max_p; part++, p++)
-		if (p->nr_sects)
-			devfs_register_partition(dev, part);
 #endif
 }
 
@@ -348,7 +236,7 @@
 		cdroms = devfs_mk_dir (NULL, "cdroms", NULL);
 
 	dev->number = devfs_alloc_unique_number(&cdrom_numspace);
-	sprintf(vname, "cdroms/cdrom%d", dev->number);
+	sprintf(vname, "cdrom%d", dev->number);
 	if (dev->de) {
 		int pos;
 		devfs_handle_t slave;
@@ -379,11 +267,6 @@
 static void devfs_remove_partitions(struct gendisk *dev)
 {
 #ifdef CONFIG_DEVFS_FS
-	int part;
-	for (part = (1<<dev->minor_shift)-1; part--; ) {
-		devfs_unregister(dev->part[part].de);
-		dev->part[part].de = NULL;
-	}
 	devfs_unregister(dev->disk_de);
 	dev->disk_de = NULL;
 	if (dev->flags & GENHD_FL_CD)
@@ -393,15 +276,196 @@
 #endif
 }
 
+static ssize_t part_dev_read(struct device *dev,
+			char *page, size_t count, loff_t off)
+{
+	struct gendisk *disk = dev->parent->driver_data;
+	struct hd_struct *p = dev->driver_data;
+	int part = p - disk->part + 1;
+	dev_t base = MKDEV(disk->major, disk->first_minor); 
+	return off ? 0 : sprintf(page, "%04x\n",base + part);
+}
+static ssize_t part_start_read(struct device *dev,
+			char *page, size_t count, loff_t off)
+{
+	struct hd_struct *p = dev->driver_data;
+	return off ? 0 : sprintf(page, "%llu\n",(u64)p->start_sect);
+}
+static ssize_t part_size_read(struct device *dev,
+			char *page, size_t count, loff_t off)
+{
+	struct hd_struct *p = dev->driver_data;
+	return off ? 0 : sprintf(page, "%llu\n",(u64)p->nr_sects);
+}
+static struct device_attribute part_attr_dev = {
+	.attr = {.name = "dev", .mode = S_IRUGO },
+	.show	= part_dev_read
+};
+static struct device_attribute part_attr_start = {
+	.attr = {.name = "start", .mode = S_IRUGO },
+	.show	= part_start_read
+};
+static struct device_attribute part_attr_size = {
+	.attr = {.name = "size", .mode = S_IRUGO },
+	.show	= part_size_read
+};
+
+void delete_partition(struct gendisk *disk, int part)
+{
+	struct hd_struct *p = disk->part + part - 1;
+	struct device *dev;
+	if (!p->nr_sects)
+		return;
+	p->start_sect = 0;
+	p->nr_sects = 0;
+	devfs_unregister(p->de);
+	dev = p->hd_driverfs_dev;
+	p->hd_driverfs_dev = NULL;
+	if (dev) {
+		device_remove_file(dev, &part_attr_size);
+		device_remove_file(dev, &part_attr_start);
+		device_remove_file(dev, &part_attr_dev);
+		device_unregister(dev);	
+	}
+}
+
+static void part_release(struct device *dev)
+{
+	kfree(dev);
+}
+
+void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len)
+{
+	struct hd_struct *p = disk->part + part - 1;
+	struct device *parent = &disk->disk_dev;
+	struct device *dev;
+
+	p->start_sect = start;
+	p->nr_sects = len;
+	devfs_register_partition(disk, part);
+	dev = kmalloc(sizeof(struct device), GFP_KERNEL);
+	if (!dev)
+		return;
+	memset(dev, 0, sizeof(struct device));
+	dev->parent = parent;
+	sprintf(dev->bus_id, "p%d", part);
+	dev->release = part_release;
+	dev->driver_data = p;
+	device_register(dev);
+	device_create_file(dev, &part_attr_dev);
+	device_create_file(dev, &part_attr_start);
+	device_create_file(dev, &part_attr_size);
+	p->hd_driverfs_dev = dev;
+}
+
+static ssize_t disk_dev_read(struct device *dev,
+			char *page, size_t count, loff_t off)
+{
+	struct gendisk *disk = dev->driver_data;
+	dev_t base = MKDEV(disk->major, disk->first_minor); 
+	return off ? 0 : sprintf(page, "%04x\n",base);
+}
+static ssize_t disk_range_read(struct device *dev,
+			char *page, size_t count, loff_t off)
+{
+	struct gendisk *disk = dev->driver_data;
+	return off ? 0 : sprintf(page, "%d\n",disk->minors);
+}
+static ssize_t disk_size_read(struct device *dev,
+			char *page, size_t count, loff_t off)
+{
+	struct gendisk *disk = dev->driver_data;
+	return off ? 0 : sprintf(page, "%llu\n",(u64)get_capacity(disk));
+}
+static struct device_attribute disk_attr_dev = {
+	.attr = {.name = "dev", .mode = S_IRUGO },
+	.show	= disk_dev_read
+};
+static struct device_attribute disk_attr_range = {
+	.attr = {.name = "range", .mode = S_IRUGO },
+	.show	= disk_range_read
+};
+static struct device_attribute disk_attr_size = {
+	.attr = {.name = "size", .mode = S_IRUGO },
+	.show	= disk_size_read
+};
+
+static void disk_driverfs_symlinks(struct gendisk *disk)
+{
+	struct device *target = disk->driverfs_dev;
+	struct device *dev = &disk->disk_dev;
+	struct device *p;
+	char *path;
+	char *s;
+	int length;
+	int depth;
+
+	if (!target)
+		return;
+
+	get_device(target);
+
+	length = get_devpath_length(target);
+	length += strlen("..");
+
+	if (length > PATH_MAX)
+		return;
+
+	if (!(path = kmalloc(length,GFP_KERNEL)))
+		return;
+	memset(path,0,length);
+
+	/* our relative position */
+	strcpy(path,"..");
+
+	fill_devpath(target, path, length);
+	driverfs_create_symlink(&dev->dir, "device", path);
+	kfree(path);
+
+	for (p = target, depth = 0; p; p = p->parent, depth++)
+		;
+	length = get_devpath_length(dev);
+	length += 3 * depth - 1;
+
+	if (length > PATH_MAX)
+		return;
+
+	if (!(path = kmalloc(length,GFP_KERNEL)))
+		return;
+	memset(path,0,length);
+	for (s = path; depth--; s += 3)
+		strcpy(s, "../");
+
+	fill_devpath(dev, path, length);
+	driverfs_create_symlink(&target->dir, "block", path);
+	kfree(path);
+}
+
 /* Not exported, helper to add_disk(). */
 void register_disk(struct gendisk *disk)
 {
+	struct device *dev = &disk->disk_dev;
+	struct parsed_partitions *state;
 	struct block_device *bdev;
+	char *s;
+	int j;
+
+	strcpy(dev->bus_id, disk->disk_name);
+	/* ewww... some of these buggers have / in name... */
+	s = strchr(dev->bus_id, '/');
+	if (s)
+		*s = '!';
+	device_add(dev);
+	device_create_file(dev, &disk_attr_dev);
+	device_create_file(dev, &disk_attr_range);
+	device_create_file(dev, &disk_attr_size);
+	disk_driverfs_symlinks(disk);
+
 	if (disk->flags & GENHD_FL_CD)
 		devfs_create_cdrom(disk);
 
 	/* No minors to use for partitions */
-	if (!disk->minor_shift)
+	if (disk->minors == 1)
 		return;
 
 	/* No such device (e.g., media were just removed) */
@@ -411,45 +475,32 @@
 	bdev = bdget(MKDEV(disk->major, disk->first_minor));
 	if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
 		return;
-	check_partition(disk, bdev);
-	driverfs_create_partitions(disk);
+	state = check_partition(disk, bdev);
 	devfs_create_partitions(disk);
-	blkdev_put(bdev, BDEV_RAW);
-}
-
-void update_partition(struct gendisk *disk, int part)
-{
-	struct hd_struct *p = disk->part + part - 1;
-	struct device *dev = &p->hd_driverfs_dev;
-
-	if (!p->nr_sects) {
-		if (p->de) {
-			devfs_unregister(p->de);
-			p->de = NULL;
-		}
-		if (dev->driver_data) {
-			device_remove_file(dev, &dev_attr_type);
-			device_remove_file(dev, &dev_attr_kdev);
-			put_device(dev);	
-			dev->driver_data = NULL;
+	if (state) {
+		for (j = 1; j < state->limit; j++) {
+			sector_t size = state->parts[j].size;
+			sector_t from = state->parts[j].from;
+			if (!size)
+				continue;
+			add_partition(disk, j, from, size);
+#if CONFIG_BLK_DEV_MD
+			if (!state->parts[j].flags)
+				continue;
+			md_autodetect_dev(bdev->bd_dev+j);
+#endif
 		}
-		return;
+		kfree(state);
 	}
-	if (!p->de)
-		devfs_register_partition(disk, part);
-	if (dev->driver_data || !(disk->flags & GENHD_FL_DRIVERFS))
-		return;
-	dev->driver_data =
-		(void *)(long)__mkdev(disk->major, disk->first_minor+part);
-	device_register(dev);
-	device_create_file(dev, &dev_attr_type);
-	device_create_file(dev, &dev_attr_kdev);
+	blkdev_put(bdev, BDEV_RAW);
 }
 
 int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
 {
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
+	struct parsed_partitions *state;
 	int p, res;
+
 	if (!bdev->bd_invalidated)
 		return 0;
 	if (bdev->bd_part_count)
@@ -458,16 +509,25 @@
 	if (res)
 		return res;
 	bdev->bd_invalidated = 0;
-	for (p = 0; p < (1<<disk->minor_shift) - 1; p++) {
-		disk->part[p].start_sect = 0;
-		disk->part[p].nr_sects = 0;
-	}
+	for (p = 1; p < disk->minors; p++)
+		delete_partition(disk, p);
 	if (bdev->bd_op->revalidate)
 		bdev->bd_op->revalidate(dev);
-	if (get_capacity(disk))
-		check_partition(disk, bdev);
-	for (p = 1; p < (1<<disk->minor_shift); p++)
-		update_partition(disk, p);
+	if (!get_capacity(disk) || !(state = check_partition(disk, bdev)))
+		return res;
+	for (p = 1; p < state->limit; p++) {
+		sector_t size = state->parts[p].size;
+		sector_t from = state->parts[p].from;
+		if (!size)
+			continue;
+		add_partition(disk, p, from, size);
+#if CONFIG_BLK_DEV_MD
+		if (!state->parts[j].flags)
+			continue;
+		md_autodetect_dev(bdev->bd_dev+p);
+#endif
+	}
+	kfree(state);
 	return res;
 }
 
@@ -493,48 +553,33 @@
 	return NULL;
 }
 
-static int wipe_partitions(struct gendisk *disk)
+void del_gendisk(struct gendisk *disk)
 {
-	int max_p = 1 << disk->minor_shift;
+	int max_p = disk->minors;
 	kdev_t devp;
-	int res;
 	int p;
 
 	/* invalidate stuff */
 	for (p = max_p - 1; p > 0; p--) {
 		devp = mk_kdev(disk->major,disk->first_minor + p);
-#if 0					/* %%% superfluous? */
-		if (disk->part[p-1].nr_sects == 0)
-			continue;
-#endif
-		res = invalidate_device(devp, 1);
-		if (res)
-			return res;
-		disk->part[p-1].start_sect = 0;
-		disk->part[p-1].nr_sects = 0;
+		invalidate_device(devp, 1);
+		delete_partition(disk, p);
 	}
 	devp = mk_kdev(disk->major,disk->first_minor);
-#if 0					/* %%% superfluous? */
-	if (disk->part[p].nr_sects == 0)
-		continue;
-#endif
-	res = invalidate_device(devp, 1);
-	if (res)
-		return res;
+	invalidate_device(devp, 1);
 	disk->capacity = 0;
-	return 0;
-}
-
-void del_gendisk(struct gendisk *disk)
-{
-	driverfs_remove_partitions(disk);
-	wipe_partitions(disk);
+	disk->flags &= ~GENHD_FL_UP;
 	unlink_gendisk(disk);
 	devfs_remove_partitions(disk);
-	if (disk->part) {
-		kfree(disk->part);
-		disk->part = NULL;
+	device_remove_file(&disk->disk_dev, &disk_attr_dev);
+	device_remove_file(&disk->disk_dev, &disk_attr_range);
+	device_remove_file(&disk->disk_dev, &disk_attr_size);
+	driverfs_remove_file(&disk->disk_dev.dir, "device");
+	if (disk->driverfs_dev) {
+		driverfs_remove_file(&disk->driverfs_dev->dir, "block");
+		put_device(disk->driverfs_dev);
 	}
+	device_del(&disk->disk_dev);
 }
 
 struct dev_name {
@@ -571,6 +616,7 @@
 	dname->name = NULL;
 	if (hd)
 		dname->name = disk_name(hd, part, dname->namebuf);
+	put_disk(hd);
 	if (!dname->name) {
 		sprintf(dname->namebuf, "[dev %s]", kdevname(to_kdev_t(dev)));
 		dname->name = dname->namebuf;
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Tue Oct 15 20:29:12 2002
+++ b/fs/proc/proc_misc.c	Tue Oct 15 20:29:12 2002
@@ -38,6 +38,7 @@
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
 #include <linux/times.h>
+#include <linux/profile.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -202,9 +203,9 @@
 	{
 		extern unsigned long htlbpagemem, htlbzone_pages;
 		len += sprintf(page + len,
-				"HugePages:    %8lu\n"
-				"Available:    %8lu\n"
-				"Size:         %8lu kB\n",
+				"HugePages_Total: %5lu\n"
+				"HugePages_Free:  %5lu\n"
+				"Hugepagesize:    %5lu kB\n",
 				htlbzone_pages,
 				htlbpagemem,
 				HPAGE_SIZE/1024);
diff -Nru a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
--- a/fs/proc/proc_tty.c	Tue Oct 15 20:29:16 2002
+++ b/fs/proc/proc_tty.c	Tue Oct 15 20:29:16 2002
@@ -14,7 +14,6 @@
 #include <linux/tty.h>
 #include <asm/bitops.h>
 
-extern struct tty_driver *tty_drivers;	/* linked list of tty drivers */
 extern struct tty_ldisc ldiscs[];
 
 
@@ -40,7 +39,7 @@
 	char	range[20], deftype[20];
 	char	*type;
 
-	for (p = tty_drivers; p; p = p->next) {
+	list_for_each_entry(p, &tty_drivers, tty_drivers) {
 		if (p->num > 1)
 			sprintf(range, "%d-%d", p->minor_start,
 				p->minor_start + p->num - 1);
diff -Nru a/fs/qnx4/dir.c b/fs/qnx4/dir.c
--- a/fs/qnx4/dir.c	Tue Oct 15 20:29:17 2002
+++ b/fs/qnx4/dir.c	Tue Oct 15 20:29:17 2002
@@ -85,17 +85,17 @@
 
 struct file_operations qnx4_dir_operations =
 {
-	read:		generic_read_dir,
-	readdir:	qnx4_readdir,
-	fsync:		file_fsync,
+	.read		= generic_read_dir,
+	.readdir	= qnx4_readdir,
+	.fsync		= file_fsync,
 };
 
 struct inode_operations qnx4_dir_inode_operations =
 {
-	lookup:		qnx4_lookup,
+	.lookup		= qnx4_lookup,
 #ifdef CONFIG_QNX4FS_RW
-	create:		qnx4_create,
-	unlink:		qnx4_unlink,
-	rmdir:		qnx4_rmdir,
+	.create		= qnx4_create,
+	.unlink		= qnx4_unlink,
+	.rmdir		= qnx4_rmdir,
 #endif
 };
diff -Nru a/fs/qnx4/file.c b/fs/qnx4/file.c
--- a/fs/qnx4/file.c	Tue Oct 15 20:29:16 2002
+++ b/fs/qnx4/file.c	Tue Oct 15 20:29:16 2002
@@ -24,21 +24,19 @@
  */
 struct file_operations qnx4_file_operations =
 {
-	llseek:			generic_file_llseek,
-	read:			generic_file_read,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.mmap		= generic_file_mmap,
+	.sendfile	= generic_file_sendfile,
 #ifdef CONFIG_QNX4FS_RW
-	write:			generic_file_write,
+	.write		= generic_file_write,
+	.fsync		= qnx4_sync_file,
 #endif
-	mmap:			generic_file_mmap,
-#ifdef CONFIG_QNX4FS_RW
-	fsync:			qnx4_sync_file,
-#endif
-	sendfile:		generic_file_sendfile,
 };
 
 struct inode_operations qnx4_file_inode_operations =
 {
 #ifdef CONFIG_QNX4FS_RW
-	truncate:		qnx4_truncate,
+	.truncate	= qnx4_truncate,
 #endif
 };
diff -Nru a/fs/qnx4/inode.c b/fs/qnx4/inode.c
--- a/fs/qnx4/inode.c	Tue Oct 15 20:29:15 2002
+++ b/fs/qnx4/inode.c	Tue Oct 15 20:29:15 2002
@@ -131,19 +131,17 @@
 
 static struct super_operations qnx4_sops =
 {
-	alloc_inode:	qnx4_alloc_inode,
-	destroy_inode:	qnx4_destroy_inode,
-	read_inode:	qnx4_read_inode,
+	.alloc_inode	= qnx4_alloc_inode,
+	.destroy_inode	= qnx4_destroy_inode,
+	.read_inode	= qnx4_read_inode,
+	.put_super	= qnx4_put_super,
+	.statfs		= qnx4_statfs,
+	.remount_fs	= qnx4_remount,
 #ifdef CONFIG_QNX4FS_RW
-	write_inode:	qnx4_write_inode,
-	delete_inode:	qnx4_delete_inode,
+	.write_inode	= qnx4_write_inode,
+	.delete_inode	= qnx4_delete_inode,
+	.write_super	= qnx4_write_super,
 #endif
-	put_super:	qnx4_put_super,
-#ifdef CONFIG_QNX4FS_RW
-	write_super:	qnx4_write_super,
-#endif
-	statfs:		qnx4_statfs,
-	remount_fs:	qnx4_remount,
 };
 
 static int qnx4_remount(struct super_block *sb, int *flags, char *data)
@@ -358,26 +356,19 @@
 
 	sb_set_blocksize(s, QNX4_BLOCK_SIZE);
 
-	/* Check the boot signature. Since the qnx4 code is
+	/* Check the superblock signature. Since the qnx4 code is
 	   dangerous, we should leave as quickly as possible
 	   if we don't belong here... */
-	bh = sb_bread(s, 0);
+	bh = sb_bread(s, 1);
 	if (!bh) {
-		printk("qnx4: unable to read the boot sector\n");
+		printk("qnx4: unable to read the superblock\n");
 		goto outnobh;
 	}
-	if ( memcmp( (char*)bh->b_data + 4, "QNX4FS", 6 ) ) {
+	if ( le32_to_cpu( *(__u32*)bh->b_data ) != QNX4_SUPER_MAGIC ) {
 		if (!silent)
-			printk("qnx4: wrong fsid in boot sector.\n");
+			printk("qnx4: wrong fsid in superblock.\n");
 		goto out;
 	}
-	brelse(bh);
-
-	bh = sb_bread(s, 1);
-	if (!bh) {
-		printk("qnx4: unable to read the superblock\n");
-		goto outnobh;
-	}
 	s->s_op = &qnx4_sops;
 	s->s_magic = QNX4_SUPER_MAGIC;
 #ifndef CONFIG_QNX4FS_RW
@@ -449,12 +440,12 @@
 	return generic_block_bmap(mapping,block,qnx4_get_block);
 }
 struct address_space_operations qnx4_aops = {
-	readpage: qnx4_readpage,
-	writepage: qnx4_writepage,
-	sync_page: block_sync_page,
-	prepare_write: qnx4_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: qnx4_bmap
+	.readpage	= qnx4_readpage,
+	.writepage	= qnx4_writepage,
+	.sync_page	= block_sync_page,
+	.prepare_write	= qnx4_prepare_write,
+	.commit_write	= generic_commit_write,
+	.bmap		= qnx4_bmap
 };
 
 static void qnx4_read_inode(struct inode *inode)
@@ -564,11 +555,11 @@
 }
 
 static struct file_system_type qnx4_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"qnx4",
-	get_sb:		qnx4_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "qnx4",
+	.get_sb		= qnx4_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init init_qnx4_fs(void)
@@ -585,7 +576,7 @@
 		return err;
 	}
 
-	printk("QNX4 filesystem 0.2.2 registered.\n");
+	printk("QNX4 filesystem 0.2.3 registered.\n");
 	return 0;
 }
 
diff -Nru a/fs/smbfs/sock.c b/fs/smbfs/sock.c
--- a/fs/smbfs/sock.c	Tue Oct 15 20:29:16 2002
+++ b/fs/smbfs/sock.c	Tue Oct 15 20:29:16 2002
@@ -40,7 +40,8 @@
 {
 	struct iovec iov;
 	struct msghdr msg;
-	struct scm_cookie scm;
+	struct kiocb iocb;
+	struct sock_iocb *si;
 	mm_segment_t fs;
 
 	fs = get_fs();
@@ -56,10 +57,21 @@
 	iov.iov_base = ubuf;
 	iov.iov_len = size;
 
-	memset(&scm, 0, sizeof(scm));
-	size = socket->ops->recvmsg(socket, &msg, size, flags, &scm);
+	init_sync_kiocb(&iocb, NULL);
+	si = kiocb_to_siocb(&iocb);
+	si->sock = socket;
+	si->scm = &si->async_scm;
+	si->msg = &msg;
+	si->size = size;
+	si->flags = flags;
+
+	memset(si->scm, 0, sizeof(*si->scm));
+
+	size = socket->ops->recvmsg(&iocb, socket, &msg, size, flags, si->scm);
 	if (size >= 0)
-		scm_recv(socket, &msg, &scm, flags);
+		scm_recv(socket, &msg, si->scm, flags);
+	if (-EIOCBQUEUED == size)
+		size = wait_on_sync_kiocb(&iocb);
 
 	set_fs(fs);
 	return size;
@@ -286,7 +298,8 @@
 	unsigned int flags;
 	struct iovec iov;
 	struct msghdr msg;
-	struct scm_cookie scm;
+	struct kiocb iocb;
+	struct sock_iocb *si;
 	mm_segment_t fs;
 	int rlen = smb_len(server->header) - server->smb_read + 4;
 	int result = -EIO;
@@ -313,10 +326,21 @@
 	if (rlen > PAGE_SIZE)
 		rlen = PAGE_SIZE;
 
-	memset(&scm, 0, sizeof(scm));
-	result = sock->ops->recvmsg(sock, &msg, rlen, flags, &scm);
+	init_sync_kiocb(&iocb, NULL);
+	si = kiocb_to_siocb(&iocb);
+	si->sock = sock;
+	si->scm = &si->async_scm;
+	si->msg = &msg;
+	si->size = rlen;
+	si->flags = flags;
+
+	memset(si->scm, 0, sizeof(*si->scm));
+
+	result = sock->ops->recvmsg(&iocb, sock, &msg, rlen, flags, si->scm);
 	if (result >= 0)
-		scm_recv(sock, &msg, &scm, flags);
+		scm_recv(sock, &msg, si->scm, flags);
+	if (-EIOCBQUEUED == result)
+		result = wait_on_sync_kiocb(&iocb);
 
 	set_fs(fs);
 
@@ -345,7 +369,8 @@
 	unsigned int flags;
 	struct iovec iov[4];
 	struct msghdr msg;
-	struct scm_cookie scm;
+	struct kiocb iocb;
+	struct sock_iocb *si;
 	mm_segment_t fs;
 	int rlen;
 	int result = -EIO;
@@ -372,10 +397,21 @@
 	if (req->rq_rlen < rlen)
 		rlen = req->rq_rlen;
 
-	memset(&scm, 0, sizeof(scm));
-	result = sock->ops->recvmsg(sock, &msg, rlen, flags, &scm);
+	init_sync_kiocb(&iocb, NULL);
+	si = kiocb_to_siocb(&iocb);
+	si->sock = sock;
+	si->scm = &si->async_scm;
+	si->msg = &msg;
+	si->size = rlen;
+	si->flags = flags;
+
+	memset(si->scm, 0, sizeof(*si->scm));
+
+	result = sock->ops->recvmsg(&iocb, sock, &msg, rlen, flags, si->scm);
 	if (result >= 0)
-		scm_recv(sock, &msg, &scm, flags);
+		scm_recv(sock, &msg, si->scm, flags);
+	if (-EIOCBQUEUED == result)
+		result = wait_on_sync_kiocb(&iocb);
 
 	set_fs(fs);
 
@@ -403,7 +439,8 @@
 	mm_segment_t fs;
 	struct smb_sb_info *server = req->rq_server;
 	struct socket *sock;
-	struct scm_cookie scm;
+	struct kiocb iocb;
+	struct sock_iocb *si;
 	struct msghdr msg;
         int slen = req->rq_slen - req->rq_bytes_sent;
 	int result = -EIO;
@@ -427,13 +464,23 @@
 	if (req->rq_bytes_sent)
 		smb_move_iov(&msg, iov, req->rq_bytes_sent);
 
+	init_sync_kiocb(&iocb, NULL);
+	si = kiocb_to_siocb(&iocb);
+	si->scm = &si->async_scm;
+	si->sock = sock;
+	si->msg = &msg;
+	si->size = slen;
+
 	fs = get_fs();
 	set_fs(get_ds());
-	result = scm_send(sock, &msg, &scm);
+	result = scm_send(sock, &msg, si->scm);
 	if (result >= 0) {
-		result = sock->ops->sendmsg(sock, &msg, slen, &scm);
-		scm_destroy(&scm);
+		result = sock->ops->sendmsg(&iocb, sock, &msg, slen, si->scm);
+		if (-EIOCBQUEUED != result)
+			scm_destroy(si->scm);
 	}
+	if (-EIOCBQUEUED == result)
+		result = wait_on_sync_kiocb(&iocb);
 	set_fs(fs);
 
 	if (result >= 0) {
diff -Nru a/fs/vfat/namei.c b/fs/vfat/namei.c
--- a/fs/vfat/namei.c	Tue Oct 15 20:29:17 2002
+++ b/fs/vfat/namei.c	Tue Oct 15 20:29:17 2002
@@ -80,93 +80,6 @@
 	return 0;
 }
 
-static int simple_getbool(char *s, int *setval)
-{
-	if (s) {
-		if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true")) {
-			*setval = 1;
-		} else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false")) {
-			*setval = 0;
-		} else {
-			return 0;
-		}
-	} else {
-		*setval = 1;
-	}
-	return 1;
-}
-
-static int parse_options(char *options,	struct fat_mount_options *opts)
-{
-	char *this_char,*value,save,*savep;
-	int ret, val;
-
-	opts->unicode_xlate = opts->posixfs = 0;
-	opts->numtail = 1;
-	opts->utf8 = 0;
-	opts->shortname = VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95;
-	/* for backward compatible */
-	if (opts->nocase) {
-		opts->nocase = 0;
-		opts->shortname = VFAT_SFN_DISPLAY_WIN95
-		  		| VFAT_SFN_CREATE_WIN95;
-	}
-
-	if (!options) return 1;
-	save = 0;
-	savep = NULL;
-	ret = 1;
-	while ((this_char = strsep(&options,",")) != NULL) {
-		if ((value = strchr(this_char,'=')) != NULL) {
-			save = *value;
-			savep = value;
-			*value++ = 0;
-		}
-		if (!strcmp(this_char,"utf8")) {
-			ret = simple_getbool(value, &val);
-			if (ret) opts->utf8 = val;
-		} else if (!strcmp(this_char,"uni_xlate")) {
-			ret = simple_getbool(value, &val);
-			if (ret) opts->unicode_xlate = val;
-		} else if (!strcmp(this_char,"posix")) {
-			ret = simple_getbool(value, &val);
-			if (ret) opts->posixfs = val;
-		} else if (!strcmp(this_char,"nonumtail")) {
-			ret = simple_getbool(value, &val);
-			if (ret) {
-				opts->numtail = !val;
-			}
-		} else if (!strcmp(this_char, "shortname")) {
-			if (!strcmp(value, "lower"))
-				opts->shortname = VFAT_SFN_DISPLAY_LOWER
-						| VFAT_SFN_CREATE_WIN95;
-			else if (!strcmp(value, "win95"))
-				opts->shortname = VFAT_SFN_DISPLAY_WIN95
-						| VFAT_SFN_CREATE_WIN95;
-			else if (!strcmp(value, "winnt"))
-				opts->shortname = VFAT_SFN_DISPLAY_WINNT
-						| VFAT_SFN_CREATE_WINNT;
-			else if (!strcmp(value, "mixed"))
-				opts->shortname = VFAT_SFN_DISPLAY_WINNT
-						| VFAT_SFN_CREATE_WIN95;
-			else
-				ret = 0;
-		}
-		if (options)
-			*(options-1) = ',';
-		if (value) {
-			*savep = save;
-		}
-		if (ret == 0) {
-			return 0;
-		}
-	}
-	if (opts->unicode_xlate) {
-		opts->utf8 = 0;
-	}
-	return 1;
-}
-
 static inline unsigned char
 vfat_tolower(struct nls_table *t, unsigned char c)
 {
@@ -1281,28 +1194,15 @@
 int vfat_fill_super(struct super_block *sb, void *data, int silent)
 {
 	int res;
-	struct msdos_sb_info *sbi;
-  
+
 	res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1);
-	if (res) {
-		if (res == -EINVAL && !silent)
-			printk(KERN_INFO "VFS: Can't find a valid"
-			       " VFAT filesystem on dev %s.\n", sb->s_id);
+	if (res)
 		return res;
-	}
 
-	sbi = MSDOS_SB(sb);
-
-	if (parse_options((char *) data, &(sbi->options))) {
-		sbi->options.dotsOK = 0;
-		if (sbi->options.posixfs) {
-			sbi->options.name_check = 's';
-		}
-	}
-	if (sbi->options.name_check != 's') {
+	if (MSDOS_SB(sb)->options.name_check != 's')
 		sb->s_root->d_op = &vfat_dentry_ops[0];
-	} else {
+	else
 		sb->s_root->d_op = &vfat_dentry_ops[2];
-	}
+
 	return 0;
 }
diff -Nru a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c
--- a/fs/xfs/linux/xfs_aops.c	Tue Oct 15 20:29:21 2002
+++ b/fs/xfs/linux/xfs_aops.c	Tue Oct 15 20:29:21 2002
@@ -34,10 +34,8 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/mpage.h>
-#include <linux/iobuf.h>
 
 
-STATIC int delalloc_convert(struct inode *, struct page *, int, int);
 
 STATIC int
 map_blocks(
@@ -51,17 +49,11 @@
 	int			error, nmaps = 1;
 
 retry:
-	if (flags & PBF_FILE_ALLOCATE) {
-		VOP_STRATEGY(vp, offset, count, flags, NULL,
-				pbmapp, &nmaps, error);
-	} else {
-		VOP_BMAP(vp, offset, count, flags, NULL,
-				pbmapp, &nmaps, error);
-	}
+	VOP_BMAP(vp, offset, count, flags, pbmapp, &nmaps, error);
 	if (flags & PBF_WRITE) {
 		if (unlikely((flags & PBF_DIRECT) && nmaps &&
 		    (pbmapp->pbm_flags & PBMF_DELAY))) {
-			flags = PBF_WRITE | PBF_FILE_ALLOCATE;
+			flags = PBF_FILE_ALLOCATE;
 			goto retry;
 		}
 		VMODIFY(vp);
@@ -131,83 +123,6 @@
 }
 
 /*
- * Convert delalloc space to real space, do not flush the
- * data out to disk, that will be done by the caller.
- */
-STATIC int
-release_page(
-	struct page		*page)
-{
-	struct inode		*inode = (struct inode*)page->mapping->host;
-	unsigned long		end_index = inode->i_size >> PAGE_CACHE_SHIFT;
-	int			ret;
-
-	/* Are we off the end of the file ? */
-	if (page->index >= end_index) {
-		unsigned offset = inode->i_size & (PAGE_CACHE_SIZE-1);
-		if ((page->index >= end_index+1) || !offset) {
-			ret =  -EIO;
-			goto out;
-		}
-	}
-
-	ret = delalloc_convert(inode, page, 0, 0);
-
-out:
-	if (ret < 0) {
-		block_invalidatepage(page, 0);
-		ClearPageUptodate(page);
-
-		return 0;
-	}
-
-	return 1;
-}
-
-/*
- * Convert delalloc or unmapped space to real space and flush out
- * to disk.
- */
-STATIC int
-write_full_page(
-	struct page		*page,
-	int			delalloc)
-{
-	struct inode		*inode = (struct inode*)page->mapping->host;
-	unsigned long		end_index = inode->i_size >> PAGE_CACHE_SHIFT;
-	int			ret;
-
-	/* Are we off the end of the file ? */
-	if (page->index >= end_index) {
-		unsigned offset = inode->i_size & (PAGE_CACHE_SIZE-1);
-		if ((page->index >= end_index+1) || !offset) {
-			ret =  -EIO;
-			goto out;
-		}
-	}
-
-	if (!page_has_buffers(page)) {
-		create_empty_buffers(page, 1 << inode->i_blkbits, 0);
-	}
-
-	ret = delalloc_convert(inode, page, 1, delalloc == 0);
-
-out:
-	if (ret < 0) {
-		/*
-		 * If it's delalloc and we have nowhere to put it,
-		 * throw it away.
-		 */
-		if (delalloc)
-			block_invalidatepage(page, 0);
-		ClearPageUptodate(page);
-		unlock_page(page);
-	}
-
-	return ret;
-}
-
-/*
  * Look for a page at index which is unlocked and not mapped
  * yet - clustering for mmap write case.
  */
@@ -348,16 +263,21 @@
 		end_page_writeback(page);
 }
 
-STATIC int
-map_page(
+/*
+ * Allocate & map buffers for page given the extent map. Write it out.
+ * except for the original page of a writepage, this is called on
+ * delalloc pages only, for the original page it is possible that
+ * the page has no mapping at all.
+ */
+STATIC void
+convert_page(
 	struct inode		*inode,
 	struct page		*page,
 	page_buf_bmap_t		*maps,
-	struct buffer_head	*bh_arr[],
 	int			startio,
 	int			all_bh)
 {
-	struct buffer_head	*bh, *head;
+	struct buffer_head	*bh_arr[MAX_BUF_PER_PAGE], *bh, *head;
 	page_buf_bmap_t		*mp = maps, *tmp;
 	unsigned long		end, offset, end_index;
 	int			i = 0, index = 0;
@@ -394,32 +314,12 @@
 		}
 	} while (i++, (bh = bh->b_this_page) != head);
 
-	return index;
-}
-
-/*
- * Allocate & map buffers for page given the extent map. Write it out.
- * except for the original page of a writepage, this is called on
- * delalloc pages only, for the original page it is possible that
- * the page has no mapping at all.
- */
-STATIC void
-convert_page(
-	struct inode		*inode,
-	struct page		*page,
-	page_buf_bmap_t		*maps,
-	int			startio,
-	int			all_bh)
-{
-	struct buffer_head	*bh_arr[MAX_BUF_PER_PAGE];
-	int			cnt;
-
-	cnt = map_page(inode, page, maps, bh_arr, startio, all_bh);
 	if (startio) {
-		submit_page(page, bh_arr, cnt);
+		submit_page(page, bh_arr, index);
 	} else {
 		unlock_page(page);
 	}
+
 	page_cache_release(page);
 }
 
@@ -440,40 +340,47 @@
 
 	tlast = (mp->pbm_offset + mp->pbm_bsize) >> PAGE_CACHE_SHIFT;
 	for (; tindex < tlast; tindex++) {
-		if (!(page = probe_page(inode, tindex)))
+		page = probe_page(inode, tindex);
+		if (!page)
 			break;
 		convert_page(inode, page, mp, startio, all_bh);
 	}
 }
 
 /*
- * Calling this without allocate_space set means we are being asked to
- * flush a dirty buffer head. When called with async_write set then we
- * are coming from writepage. A writepage call with allocate_space set
- * means we are being asked to write out all of the page which is before
- * EOF and therefore need to allocate space for unmapped portions of the
- * page.
+ * Calling this without startio set means we are being asked to make a dirty
+ * page ready for freeing it's buffers.  When called with startio set then
+ * we are coming from writepage.
  */
 STATIC int
 delalloc_convert(
-	struct inode		*inode,		/* inode containing page */
-	struct page		*page,		/* page to convert - locked */
-	int			startio,	/* start io on the page */
+	struct page		*page,
+	int			startio,
 	int			allocate_space)
 {
-	struct buffer_head	*bh, *head;
-	struct buffer_head	*bh_arr[MAX_BUF_PER_PAGE];
+	struct inode		*inode = page->mapping->host;
+	struct buffer_head	*bh_arr[MAX_BUF_PER_PAGE], *bh, *head;
 	page_buf_bmap_t		*mp, map;
-	int			i, cnt = 0;
-	int			len, err;
-	unsigned long		p_offset = 0;
-	loff_t			offset;
-	loff_t			end_offset;
+	unsigned long		p_offset = 0, end_index;
+	loff_t			offset, end_offset;
+	int			len, err, i, cnt = 0;
+
+	/* Are we off the end of the file ? */
+	end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+	if (page->index >= end_index) {
+		unsigned remaining = inode->i_size & (PAGE_CACHE_SIZE-1);
+		if ((page->index >= end_index+1) || !remaining) {
+			return -EIO;
+		}
+	}
 
 	offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
 	end_offset = offset + PAGE_CACHE_SIZE;
 	if (end_offset > inode->i_size)
 		end_offset = inode->i_size;
+	
+	if (startio && !page_has_buffers(page))
+		create_empty_buffers(page, 1 << inode->i_blkbits, 0);
 
 	bh = head = page_buffers(page);
 	mp = NULL;
@@ -491,9 +398,10 @@
 		if (buffer_delay(bh)) {
 			if (!mp) {
 				err = map_blocks(inode, offset, len, &map,
-						PBF_WRITE|PBF_FILE_ALLOCATE);
-				if (err)
+						PBF_FILE_ALLOCATE);
+				if (err) {
 					goto error;
+				}
 				mp = match_offset_to_mapping(page, &map,
 								p_offset);
 			}
@@ -518,8 +426,9 @@
 								bh, head);
 				err = map_blocks(inode, offset, size, &map,
 						PBF_WRITE|PBF_DIRECT);
-				if (err)
+				if (err) {
 					goto error;
+				}
 				mp = match_offset_to_mapping(page, &map,
 								p_offset);
 			}
@@ -545,12 +454,14 @@
 		bh = bh->b_this_page;
 	} while (offset < end_offset);
 
-	if (startio)
+	if (startio) {
 		submit_page(page, bh_arr, cnt);
+	}
 
-	if (mp)
+	if (mp) {
 		cluster_write(inode, page->index + 1, mp,
 				startio, allocate_space);
+	}
 
 	return 0;
 
@@ -558,7 +469,15 @@
 	for (i = 0; i < cnt; i++) {
 		unlock_buffer(bh_arr[i]);
 	}
-
+	
+	/*
+	 * If it's delalloc and we have nowhere to put it,
+	 * throw it away.
+	 */
+	if (!allocate_space) {
+		block_invalidatepage(page, 0);
+	}
+	ClearPageUptodate(page);
 	return err;
 }
 
@@ -592,7 +511,7 @@
 	}
 
 	VOP_BMAP(vp, offset, size,
-		create ? flags : PBF_READ, NULL,
+		create ? flags : PBF_READ,
 		(struct page_buf_bmap_s *)&pbmap, &retpbbm, error);
 	if (error)
 		return -error;
@@ -746,14 +665,12 @@
 
 		bh = head = page_buffers(page);
 		do {
-			if (buffer_uptodate(bh) && !buffer_mapped(bh)) {
+			if (buffer_uptodate(bh) && !buffer_mapped(bh))
 				(*nr_unmapped)++;
-				continue;
-			}
-			if (!buffer_delay(bh))
-				continue;
-			(*nr_delalloc)++;
+			else if (buffer_delay(bh))
+				(*nr_delalloc)++;
 		} while ((bh = bh->b_this_page) != head);
+
 		return 1;
 	}
 
@@ -765,20 +682,22 @@
 	struct page		*page)
 {
 	int			error;
-	int			need_trans;
+	int			need_trans = 1;
 	int			nr_delalloc, nr_unmapped;
 
-	if (count_page_state(page, &nr_delalloc, &nr_unmapped)) {
+	if (count_page_state(page, &nr_delalloc, &nr_unmapped))
 		need_trans = nr_delalloc + nr_unmapped;
-	} else {
-		need_trans = 1;
-	}
 
 	if ((current->flags & (PF_FSTRANS)) && need_trans)
 		goto out_fail;
 
-	error = write_full_page(page, nr_delalloc);
-
+	/*
+	 * Convert delalloc or unmapped space to real space and flush out
+	 * to disk.
+	 */
+	error = delalloc_convert(page, 1, nr_delalloc == 0);
+	if (unlikely(error))
+		unlock_page(page);
 	return error;
 
 out_fail:
@@ -813,24 +732,26 @@
 	struct page		*page,
 	int			gfp_mask)
 {
-	int			need_trans;
 	int			nr_delalloc, nr_unmapped;
 
 	if (count_page_state(page, &nr_delalloc, &nr_unmapped)) {
-		need_trans = nr_delalloc;
-	} else {
-		need_trans = 0;
-	}
-
-	if (need_trans == 0) {
-		return try_to_free_buffers(page);
-	}
+		if (!nr_delalloc)
+			goto free_buffers;
+	} 
 
 	if (gfp_mask & __GFP_FS) {
-		if (release_page(page) == 0)
-			return try_to_free_buffers(page);
+		/*
+		 * Convert delalloc space to real space, do not flush the
+		 * data out to disk, that will be done by the caller.
+		 */
+		if (delalloc_convert(page, 0, 0) == 0)
+			goto free_buffers;
 	}
+
 	return 0;
+
+free_buffers:
+	return try_to_free_buffers(page);
 }
 
 
diff -Nru a/fs/xfs/linux/xfs_fs_subr.c b/fs/xfs/linux/xfs_fs_subr.c
--- a/fs/xfs/linux/xfs_fs_subr.c	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/linux/xfs_fs_subr.c	Tue Oct 15 20:29:11 2002
@@ -135,7 +135,6 @@
 	struct inode	*ip = LINVFS_GET_IP(vp);
 
 	if (VN_CACHED(vp)) {
-		filemap_fdatawait(ip->i_mapping);
 		filemap_fdatawrite(ip->i_mapping);
 		filemap_fdatawait(ip->i_mapping);
 
@@ -159,7 +158,6 @@
 	struct inode	*ip = LINVFS_GET_IP(vp);
 
 	if (VN_CACHED(vp)) {
-		filemap_fdatawait(ip->i_mapping);
 		filemap_fdatawrite(ip->i_mapping);
 		filemap_fdatawait(ip->i_mapping);
 	}
diff -Nru a/fs/xfs/linux/xfs_globals.c b/fs/xfs/linux/xfs_globals.c
--- a/fs/xfs/linux/xfs_globals.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/linux/xfs_globals.c	Tue Oct 15 20:29:17 2002
@@ -41,12 +41,6 @@
 unsigned long	xfs_physmem;
 
 /*
- * restricted_chown = 1	 bsd style chown(2), only super-user can give away files
- * restricted_chown = 0	 sysV style chown(2), non super-user can give away files
- */
-int		restricted_chown = 1;
-
-/*
  * Used to serialize atomicIncWithWrap.
  */
 spinlock_t Atomic_spin = SPIN_LOCK_UNLOCKED;
@@ -69,3 +63,6 @@
 EXPORT_SYMBOL(xfs_Gqm);
 EXPORT_SYMBOL(xfs_next_bit);
 EXPORT_SYMBOL(xfs_contig_bits);
+EXPORT_SYMBOL(xfs_bmbt_get_all);
+EXPORT_SYMBOL(xfs_bmbt_disk_get_all);
+
diff -Nru a/fs/xfs/linux/xfs_globals.h b/fs/xfs/linux/xfs_globals.h
--- a/fs/xfs/linux/xfs_globals.h	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/linux/xfs_globals.h	Tue Oct 15 20:29:16 2002
@@ -39,7 +39,6 @@
 
 extern uint64_t xfs_panic_mask;		/* set to cause more panics */
 
-extern int	restricted_chown;
 extern unsigned long	xfs_physmem;
 
 extern struct cred *sys_cred;
diff -Nru a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c
--- a/fs/xfs/linux/xfs_ioctl.c	Tue Oct 15 20:29:20 2002
+++ b/fs/xfs/linux/xfs_ioctl.c	Tue Oct 15 20:29:20 2002
@@ -35,7 +35,6 @@
 #include <xfs_dfrag.h>
 #include <linux/dcache.h>
 #include <linux/namei.h>
-#include <linux/iobuf.h>
 
 
 extern int xfs_change_file_space(bhv_desc_t *, int,
@@ -68,7 +67,7 @@
 	if (copy_from_user(&hreq, (xfs_fsop_handlereq_t *)arg, sizeof(hreq)))
 		return -XFS_ERROR(EFAULT);
 
-	bzero((char *)&handle, sizeof(handle));
+	memset((char *)&handle, 0, sizeof(handle));
 
 	switch (cmd) {
 	case XFS_IOC_PATH_TO_FSHANDLE:
@@ -229,7 +228,7 @@
 	if (copy_from_user(handlep, hanp, hlen))
 		return XFS_ERROR(EFAULT);
 	if (hlen < sizeof(*handlep))
-		bzero(((char *)handlep) + hlen, sizeof(*handlep) - hlen);
+		memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);
 	if (hlen > sizeof(handlep->ha_fsid)) {
 		if (handlep->ha_fid.xfs_fid_len !=
 				(hlen - sizeof(handlep->ha_fsid)
@@ -265,12 +264,6 @@
 	vpp = XFS_ITOV(ip);
 	inodep = LINVFS_GET_IP(vpp);
 	xfs_iunlock(ip, XFS_ILOCK_SHARED);
-	error = linvfs_revalidate_core(inodep, ATTR_COMM);
-	if (error) {
-		iput(inodep);
-		/* this error is (-) but our callers expect + */
-		return XFS_ERROR(-error);
-	}
 
 	*vp = vpp;
 	*inode = inodep;
@@ -605,6 +598,7 @@
 		 * it is set to the file system block size to
 		 * avoid having to do block zeroing on short writes.
 		 */
+#define KIO_MAX_ATOMIC_IO 512	/* FIXME: what do we really want here? */
 		da.d_maxiosz = XFS_FSB_TO_B(mp,
 				XFS_B_TO_FSBT(mp, KIO_MAX_ATOMIC_IO << 10));
 
diff -Nru a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c
--- a/fs/xfs/linux/xfs_iops.c	Tue Oct 15 20:29:15 2002
+++ b/fs/xfs/linux/xfs_iops.c	Tue Oct 15 20:29:15 2002
@@ -91,14 +91,14 @@
 		mode &= ~current->fs->umask;
 #endif
 
-	bzero(&va, sizeof(va));
+	memset(&va, 0, sizeof(va));
 	va.va_mask = AT_TYPE|AT_MODE;
 	va.va_type = IFTOVT(mode);
 	va.va_mode = mode;
 
 	switch (mode & S_IFMT) {
 	case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
-		va.va_rdev = rdev;
+		va.va_rdev = XFS_MKDEV(MAJOR(rdev), MINOR(rdev));
 		va.va_mask |= AT_RDEV;
 		/*FALLTHROUGH*/
 	case S_IFREG:
@@ -122,8 +122,6 @@
 
 		if (S_ISCHR(mode) || S_ISBLK(mode))
 			ip->i_rdev = to_kdev_t(rdev);
-		/* linvfs_revalidate_core returns (-) errors */
-		error = -linvfs_revalidate_core(ip, ATTR_COMM);
 		validate_fields(dir);
 		d_instantiate(dentry, ip);
 		mark_inode_dirty_sync(ip);
@@ -186,7 +184,6 @@
 			VN_RELE(cvp);
 			return ERR_PTR(-EACCES);
 		}
-		error = -linvfs_revalidate_core(ip, ATTR_COMM);
 	}
 	if (error && (error != ENOENT))
 		return ERR_PTR(-error);
@@ -262,14 +259,13 @@
 
 	dvp = LINVFS_GET_VP(dir);
 
-	bzero(&va, sizeof(va));
+	memset(&va, 0, sizeof(va));
 	va.va_type = VLNK;
-	va.va_mode = 0777 & ~current->fs->umask;
-	va.va_mask = AT_TYPE|AT_MODE; /* AT_PROJID? */
+	va.va_mode = irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO;
+	va.va_mask = AT_TYPE|AT_MODE;
 
 	error = 0;
-	VOP_SYMLINK(dvp, dentry, &va, (char *)symname,
-							&cvp, NULL, error);
+	VOP_SYMLINK(dvp, dentry, &va, (char *)symname, &cvp, NULL, error);
 	if (!error) {
 		ASSERT(cvp);
 		ASSERT(cvp->v_type == VLNK);
@@ -278,10 +274,9 @@
 			error = ENOMEM;
 			VN_RELE(cvp);
 		} else {
-			/* linvfs_revalidate_core returns (-) errors */
-			error = -linvfs_revalidate_core(ip, ATTR_COMM);
 			d_instantiate(dentry, ip);
 			validate_fields(dir);
+			validate_fields(ip); /* size needs update */
 			mark_inode_dirty_sync(ip);
 			mark_inode_dirty_sync(dir);
 		}
@@ -369,7 +364,7 @@
 }
 
 /*
- * careful here - this function can get called recusively, so
+ * careful here - this function can get called recursively, so
  * we need to be very careful about how much stack we use.
  * uio is kmalloced for this reason...
  */
@@ -441,16 +436,6 @@
  * from the results of a getattr. This gets called out of things
  * like stat.
  */
-int
-linvfs_revalidate_core(
-	struct inode	*inode,
-	int		flags)
-{
-	vnode_t		*vp = LINVFS_GET_VP(inode);
-
-	/* vn_revalidate returns (-) error so this is ok */
-	return vn_revalidate(vp, flags);
-}
 
 STATIC int
 linvfs_getattr(
@@ -463,7 +448,7 @@
 	int		error = 0;
 
 	if (unlikely(vp->v_flag & VMODIFIED)) {
-		error = linvfs_revalidate_core(inode, 0);
+		error = vn_revalidate(vp);
 	}
 	if (!error)
 		generic_fillattr(inode, stat);
@@ -528,7 +513,7 @@
 	}
 
 	if (!error) {
-		vn_revalidate(vp, 0);
+		vn_revalidate(vp);
 		mark_inode_dirty_sync(inode);
 	}
 	return error;
@@ -618,30 +603,17 @@
 		error = -ENOATTR;
 		p += xfs_namespaces[SYSTEM_NAMES].namelen;
 		if (strcmp(p, POSIXACL_ACCESS) == 0) {
-			if (vp->v_flag & VMODIFIED) {
-				error = linvfs_revalidate_core(inode, 0);
-				if (error)
-					return error;
-			}
 			error = xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
-			if (!error) {
-				VMODIFY(vp);
-				error = linvfs_revalidate_core(inode, 0);
-			}
 		}
 		else if (strcmp(p, POSIXACL_DEFAULT) == 0) {
-			error = linvfs_revalidate_core(inode, 0);
-			if (error)
-				return error;
 			error = xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
-			if (!error) {
-				VMODIFY(vp);
-				error = linvfs_revalidate_core(inode, 0);
-			}
 		}
 		else if (strcmp(p, POSIXCAP) == 0) {
 			error = xfs_cap_vset(vp, data, size);
 		}
+		if (!error) {
+			error = vn_revalidate(vp);
+		}
 		return error;
 	}
 
@@ -689,19 +661,9 @@
 		error = -ENOATTR;
 		p += xfs_namespaces[SYSTEM_NAMES].namelen;
 		if (strcmp(p, POSIXACL_ACCESS) == 0) {
-			if (vp->v_flag & VMODIFIED) {
-				error = linvfs_revalidate_core(inode, 0);
-				if (error)
-					return error;
-			}
 			error = xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
 		}
 		else if (strcmp(p, POSIXACL_DEFAULT) == 0) {
-			if (vp->v_flag & VMODIFIED) {
-				error = linvfs_revalidate_core(inode, 0);
-				if (error)
-					return error;
-			}
 			error = xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
 		}
 		else if (strcmp(p, POSIXCAP) == 0) {
diff -Nru a/fs/xfs/linux/xfs_iops.h b/fs/xfs/linux/xfs_iops.h
--- a/fs/xfs/linux/xfs_iops.h	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/linux/xfs_iops.h	Tue Oct 15 20:29:11 2002
@@ -65,7 +65,6 @@
 
 extern struct address_space_operations linvfs_aops;
 
-extern int linvfs_revalidate_core(struct inode *, int);
 extern int linvfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
 
 #endif /* __XFS_IOPS_H__ */
diff -Nru a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h
--- a/fs/xfs/linux/xfs_linux.h	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/linux/xfs_linux.h	Tue Oct 15 20:29:11 2002
@@ -67,6 +67,10 @@
 #define STATIC static
 #endif
 
+#define restricted_chown	xfs_params.restrict_chown
+#define irix_sgid_inherit	xfs_params.sgid_inherit
+#define irix_symlink_mode	xfs_params.symlink_mode
+
 typedef struct xfs_dirent {		/* data from readdir() */
 	xfs_ino_t	d_ino;		/* inode number of entry */
 	xfs_off_t	d_off;		/* offset of disk directory entry */
diff -Nru a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c
--- a/fs/xfs/linux/xfs_lrw.c	Tue Oct 15 20:29:10 2002
+++ b/fs/xfs/linux/xfs_lrw.c	Tue Oct 15 20:29:10 2002
@@ -43,16 +43,16 @@
 						<< mp->m_writeio_log)
 #define XFS_STRAT_WRITE_IMAPS	2
 
-STATIC int xfs_iomap_read(xfs_iocore_t *, loff_t, size_t, int, pb_bmap_t *,
-			int *, struct pm *);
-STATIC int xfs_iomap_write(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *,
-			int *, int, struct pm *);
-STATIC int xfs_iomap_write_delay(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *,
+STATIC int xfs_iomap_read(xfs_iocore_t *, loff_t, size_t, int, page_buf_bmap_t *,
+			int *);
+STATIC int xfs_iomap_write(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
+			int *, int);
+STATIC int xfs_iomap_write_delay(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
 			int *, int, int);
-STATIC int xfs_iomap_write_direct(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *,
+STATIC int xfs_iomap_write_direct(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
 			int *, int, int);
 STATIC int _xfs_imap_to_bmap(xfs_iocore_t *, xfs_off_t, xfs_bmbt_irec_t *,
-			pb_bmap_t *, int, int);
+			page_buf_bmap_t *, int, int);
 
 
 /*
@@ -136,11 +136,14 @@
 	xfs_fsize_t		n;
 	xfs_inode_t		*ip;
 	xfs_mount_t		*mp;
+	vnode_t			*vp;
 	unsigned long		seg;
 	int			direct = filp->f_flags & O_DIRECT;
 
 	ip = XFS_BHVTOI(bdp);
+	vp = BHV_TO_VNODE(bdp);
 	mp = ip->i_mount;
+	vn_trace_entry(vp, "xfs_read", (inst_t *)__return_address);
 
 	XFS_STATS_INC(xfsstats.xs_read_calls);
 
@@ -194,7 +197,7 @@
 
 	xfs_ilock(ip, XFS_IOLOCK_SHARED);
 
-	if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) &&
+	if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) &&
 	    !(filp->f_mode & FINVIS)) {
 		int error;
 		vrwlock_t locktype = VRWLOCK_READ;
@@ -230,8 +233,7 @@
 	xfs_iocore_t	*io,
 	xfs_off_t	offset,
 	xfs_fsize_t	isize,
-	xfs_fsize_t	end_size,
-	struct pm	*pmp)
+	xfs_fsize_t	end_size)
 {
 	xfs_fileoff_t	last_fsb;
 	xfs_mount_t	*mp;
@@ -310,8 +312,7 @@
 	xfs_iocore_t	*io,
 	xfs_off_t	offset,		/* starting I/O offset */
 	xfs_fsize_t	isize,		/* current inode size */
-	xfs_fsize_t	end_size,	/* terminal inode size */
-	struct pm	*pmp)
+	xfs_fsize_t	end_size)	/* terminal inode size */
 {
 	struct inode	*ip = LINVFS_GET_IP(vp);
 	xfs_fileoff_t	start_zero_fsb;
@@ -337,7 +338,7 @@
 	 * First handle zeroing the block on which isize resides.
 	 * We only zero a part of that block so it is handled specially.
 	 */
-	error = xfs_zero_last_block(ip, io, offset, isize, end_size, pmp);
+	error = xfs_zero_last_block(ip, io, offset, isize, end_size);
 	if (error) {
 		ASSERT(ismrlocked(io->io_lock, MR_UPDATE));
 		ASSERT(ismrlocked(io->io_iolock, MR_UPDATE));
@@ -469,6 +470,7 @@
 	XFS_STATS_INC(xfsstats.xs_write_calls);
 
 	vp = BHV_TO_VNODE(bdp);
+	vn_trace_entry(vp, "xfs_write", (inst_t *)__return_address);
 	xip = XFS_BHVTOI(bdp);
 
 	/* START copy & waste from filemap.c */
@@ -592,7 +594,7 @@
 
 	if (!direct && (*offset > isize && isize)) {
 		error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, *offset,
-			isize, *offset + size, NULL);
+			isize, *offset + size);
 		if (error) {
 			xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
 			return(-error);
@@ -755,112 +757,15 @@
 	return(ret);
 }
 
-/*
- * xfs_bmap() is the same as the irix xfs_bmap from xfs_rw.c
- * execpt for slight changes to the params
- */
-int
-xfs_bmap(bhv_desc_t	*bdp,
-	xfs_off_t	offset,
-	ssize_t		count,
-	int		flags,
-	struct cred	*cred,
-	pb_bmap_t	*pbmapp,
-	int		*npbmaps)
-{
-	xfs_inode_t	*ip;
-	int		error;
-	int		lockmode;
-	int		fsynced = 0;
-	vnode_t		*vp;
-
-	ip = XFS_BHVTOI(bdp);
-	ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
-	ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
-	       ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
-	ASSERT((flags & PBF_READ) || (flags & PBF_WRITE));
-
-	if (XFS_FORCED_SHUTDOWN(ip->i_iocore.io_mount))
-		return XFS_ERROR(EIO);
-
-	if (flags & PBF_READ) {
-		lockmode = xfs_ilock_map_shared(ip);
-		error = xfs_iomap_read(&ip->i_iocore, offset, count,
-				 XFS_BMAPI_ENTIRE, pbmapp, npbmaps, NULL);
-		xfs_iunlock_map_shared(ip, lockmode);
-	} else { /* PBF_WRITE */
-		ASSERT(flags & PBF_WRITE);
-		vp = BHV_TO_VNODE(bdp);
-		xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-		/*
-		 * Make sure that the dquots are there. This doesn't hold
-		 * the ilock across a disk read.
-		 */
-
-		if (XFS_IS_QUOTA_ON(ip->i_mount)) {
-			if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
-				if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
-					xfs_iunlock(ip, XFS_ILOCK_EXCL);
-					return XFS_ERROR(error);
-				}
-			}
-		}
-retry:
-		error = xfs_iomap_write(&ip->i_iocore, offset, count,
-					pbmapp, npbmaps, flags, NULL);
-		/* xfs_iomap_write unlocks/locks/unlocks */
-
-		if (error == ENOSPC) {
-			switch (fsynced) {
-			case 0:
-				if (ip->i_delayed_blks) {
-					filemap_fdatawrite(LINVFS_GET_IP(vp)->i_mapping);
-					fsynced = 1;
-				} else {
-					fsynced = 2;
-					flags |= PBF_SYNC;
-				}
-				error = 0;
-				xfs_ilock(ip, XFS_ILOCK_EXCL);
-				goto retry;
-			case 1:
-				fsynced = 2;
-				if (!(flags & PBF_SYNC)) {
-					flags |= PBF_SYNC;
-					error = 0;
-					xfs_ilock(ip, XFS_ILOCK_EXCL);
-					goto retry;
-				}
-			case 2:
-				sync_blockdev(vp->v_vfsp->vfs_super->s_bdev);
-				xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
-						XFS_LOG_FORCE|XFS_LOG_SYNC);
-
-				error = 0;
-/**
-				delay(HZ);
-**/
-				fsynced++;
-				xfs_ilock(ip, XFS_ILOCK_EXCL);
-				goto retry;
-			}
-		}
-	}
-
-	return XFS_ERROR(error);
-}
 
 int
-xfs_strategy(bhv_desc_t *bdp,
+xfs_strategy(xfs_inode_t *ip,
 	xfs_off_t	offset,
 	ssize_t		count,
 	int		flags,
-	struct cred	*cred,
-	pb_bmap_t	*pbmapp,
+	page_buf_bmap_t	*pbmapp,
 	int		*npbmaps)
 {
-	xfs_inode_t	*ip;
 	xfs_iocore_t	*io;
 	xfs_mount_t	*mp;
 	int		error;
@@ -876,20 +781,16 @@
 	xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS];
 	xfs_trans_t	*tp;
 
-	ip = XFS_BHVTOI(bdp);
 	io = &ip->i_iocore;
 	mp = ip->i_mount;
 	/* is_xfs = IO_IS_XFS(io); */
 	ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
 	ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
 	       ((io->io_flags & XFS_IOCORE_RT) != 0));
-	ASSERT((flags & PBF_READ) || (flags & PBF_WRITE));
 
 	if (XFS_FORCED_SHUTDOWN(mp))
 		return XFS_ERROR(EIO);
 
-	ASSERT(flags & PBF_WRITE);
-
 	offset_fsb = XFS_B_TO_FSBT(mp, offset);
 	nimaps = min(XFS_MAX_RW_NBMAPS, *npbmaps);
 	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
@@ -1082,12 +983,110 @@
 }
 
 
+/*
+ * xfs_bmap() is the same as the irix xfs_bmap from xfs_rw.c
+ * execpt for slight changes to the params
+ */
+int
+xfs_bmap(bhv_desc_t	*bdp,
+	xfs_off_t	offset,
+	ssize_t		count,
+	int		flags,
+	page_buf_bmap_t	*pbmapp,
+	int		*npbmaps)
+{
+	xfs_inode_t	*ip;
+	int		error;
+	int		lockmode;
+	int		fsynced = 0;
+	vnode_t		*vp;
+
+	ip = XFS_BHVTOI(bdp);
+	ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
+	ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
+	       ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
+
+	if (XFS_FORCED_SHUTDOWN(ip->i_iocore.io_mount))
+		return XFS_ERROR(EIO);
+
+	if (flags & PBF_READ) {
+		lockmode = xfs_ilock_map_shared(ip);
+		error = xfs_iomap_read(&ip->i_iocore, offset, count,
+				 XFS_BMAPI_ENTIRE, pbmapp, npbmaps);
+		xfs_iunlock_map_shared(ip, lockmode);
+	} else if (flags & PBF_FILE_ALLOCATE) {
+		error = xfs_strategy(ip, offset, count, flags,
+				pbmapp, npbmaps);
+	} else { /* PBF_WRITE */
+		ASSERT(flags & PBF_WRITE);
+		vp = BHV_TO_VNODE(bdp);
+		xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+		/*
+		 * Make sure that the dquots are there. This doesn't hold
+		 * the ilock across a disk read.
+		 */
+
+		if (XFS_IS_QUOTA_ON(ip->i_mount)) {
+			if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+				if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
+					xfs_iunlock(ip, XFS_ILOCK_EXCL);
+					return XFS_ERROR(error);
+				}
+			}
+		}
+retry:
+		error = xfs_iomap_write(&ip->i_iocore, offset, count,
+					pbmapp, npbmaps, flags);
+		/* xfs_iomap_write unlocks/locks/unlocks */
+
+		if (error == ENOSPC) {
+			switch (fsynced) {
+			case 0:
+				if (ip->i_delayed_blks) {
+					filemap_fdatawrite(LINVFS_GET_IP(vp)->i_mapping);
+					fsynced = 1;
+				} else {
+					fsynced = 2;
+					flags |= PBF_SYNC;
+				}
+				error = 0;
+				xfs_ilock(ip, XFS_ILOCK_EXCL);
+				goto retry;
+			case 1:
+				fsynced = 2;
+				if (!(flags & PBF_SYNC)) {
+					flags |= PBF_SYNC;
+					error = 0;
+					xfs_ilock(ip, XFS_ILOCK_EXCL);
+					goto retry;
+				}
+			case 2:
+				sync_blockdev(vp->v_vfsp->vfs_super->s_bdev);
+				xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
+						XFS_LOG_FORCE|XFS_LOG_SYNC);
+
+				error = 0;
+/**
+				delay(HZ);
+**/
+				fsynced++;
+				xfs_ilock(ip, XFS_ILOCK_EXCL);
+				goto retry;
+			}
+		}
+	}
+
+	return XFS_ERROR(error);
+}
+
+
 STATIC int
 _xfs_imap_to_bmap(
 	xfs_iocore_t	*io,
 	xfs_off_t	offset,
 	xfs_bmbt_irec_t *imap,
-	pb_bmap_t	*pbmapp,
+	page_buf_bmap_t	*pbmapp,
 	int		imaps,			/* Number of imap entries */
 	int		pbmaps)			/* Number of pbmap entries */
 {
@@ -1138,9 +1137,8 @@
 	loff_t		offset,
 	size_t		count,
 	int		flags,
-	pb_bmap_t	*pbmapp,
-	int		*npbmaps,
-	struct pm	*pmp)
+	page_buf_bmap_t	*pbmapp,
+	int		*npbmaps)
 {
 	xfs_fileoff_t	offset_fsb;
 	xfs_fileoff_t	end_fsb;
@@ -1191,10 +1189,9 @@
 	xfs_iocore_t	*io,
 	loff_t		offset,
 	size_t		count,
-	pb_bmap_t	*pbmapp,
+	page_buf_bmap_t	*pbmapp,
 	int		*npbmaps,
-	int		ioflag,
-	struct pm	*pmp)
+	int		ioflag)
 {
 	int		maps;
 	int		error = 0;
@@ -1211,7 +1208,7 @@
 	 */
 
 	found = 0;
-	error = xfs_iomap_read(io, offset, count, flags, pbmapp, npbmaps, NULL);
+	error = xfs_iomap_read(io, offset, count, flags, pbmapp, npbmaps);
 	if (error)
 		goto out;
 
@@ -1260,7 +1257,7 @@
 	xfs_mount_t	*mp,
 	xfs_iocore_t	*io,
 	xfs_bmbt_irec_t *imapp,
-	pb_bmap_t	*pbmapp,
+	page_buf_bmap_t	*pbmapp,
 	int		iosize,
 	xfs_fileoff_t	ioalign,
 	xfs_fsize_t	isize)
@@ -1330,7 +1327,7 @@
 	xfs_iocore_t	*io,
 	loff_t		offset,
 	size_t		count,
-	pb_bmap_t	*pbmapp,
+	page_buf_bmap_t	*pbmapp,
 	int		*npbmaps,
 	int		ioflag,
 	int		found)
@@ -1528,7 +1525,7 @@
 	xfs_iocore_t	*io,
 	loff_t		offset,
 	size_t		count,
-	pb_bmap_t	*pbmapp,
+	page_buf_bmap_t	*pbmapp,
 	int		*npbmaps,
 	int		ioflag,
 	int		found)
@@ -1830,36 +1827,22 @@
 }
 
 /*
- * In these two situations we disregard the readonly mount flag and
- * temporarily enable writes (we must, to ensure metadata integrity).
+ * If the underlying (log or data) device is readonly, there are some
+ * operations that cannot proceed.
  */
-STATIC int
-xfs_is_read_only(xfs_mount_t *mp)
+int
+xfs_dev_is_read_only(xfs_mount_t *mp, char *message)
 {
 	if (bdev_read_only(mp->m_ddev_targp->pbr_bdev) ||
-	    bdev_read_only(mp->m_logdev_targp->pbr_bdev)) {
+	    bdev_read_only(mp->m_logdev_targp->pbr_bdev) ||
+	   (mp->m_rtdev_targp && bdev_read_only(mp->m_rtdev_targp->pbr_bdev))) {
+		cmn_err(CE_NOTE,
+			"XFS: %s required on read-only device.", message);
 		cmn_err(CE_NOTE,
 			"XFS: write access unavailable, cannot proceed.");
 		return EROFS;
 	}
-	cmn_err(CE_NOTE,
-		"XFS: write access will be enabled during mount.");
-	XFS_MTOVFS(mp)->vfs_flag &= ~VFS_RDONLY;
-	return 0;
-}
 
-int
-xfs_recover_read_only(xlog_t *log)
-{
-	cmn_err(CE_NOTE, "XFS: WARNING: "
-		"recovery required on readonly filesystem.");
-	return xfs_is_read_only(log->l_mp);
+	return 0;
 }
 
-int
-xfs_quotacheck_read_only(xfs_mount_t *mp)
-{
-	cmn_err(CE_NOTE, "XFS: WARNING: "
-		"quotacheck required on readonly filesystem.");
-	return xfs_is_read_only(mp);
-}
diff -Nru a/fs/xfs/linux/xfs_lrw.h b/fs/xfs/linux/xfs_lrw.h
--- a/fs/xfs/linux/xfs_lrw.h	Tue Oct 15 20:29:12 2002
+++ b/fs/xfs/linux/xfs_lrw.h	Tue Oct 15 20:29:12 2002
@@ -39,13 +39,12 @@
  */
 #define XFS_MAX_RW_NBMAPS	4
 
-extern int xfs_bmap (bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, pb_bmap_t *, int *);
-extern int xfs_strategy (bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, pb_bmap_t *, int *);
+extern int xfs_bmap (bhv_desc_t *, xfs_off_t, ssize_t, int, page_buf_bmap_t *, int *);
 extern int xfsbdstrat (struct xfs_mount *, struct xfs_buf *);
 extern int xfs_bdstrat_cb (struct xfs_buf *);
 
 extern int xfs_zero_eof (vnode_t *, struct xfs_iocore *, xfs_off_t,
-				xfs_fsize_t, xfs_fsize_t, struct pm *);
+				xfs_fsize_t, xfs_fsize_t);
 extern ssize_t xfs_read (
 	struct bhv_desc		*bdp,
 	struct file		*filp,
@@ -62,8 +61,7 @@
 	loff_t			*offp,
 	struct cred		*credp);
 
-extern int xfs_recover_read_only (xlog_t *);
-extern int xfs_quotacheck_read_only (xfs_mount_t *);
+extern int xfs_dev_is_read_only(xfs_mount_t *, char *);
 
 extern void XFS_log_write_unmount_ro (bhv_desc_t *);
 
diff -Nru a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c
--- a/fs/xfs/linux/xfs_super.c	Tue Oct 15 20:29:21 2002
+++ b/fs/xfs/linux/xfs_super.c	Tue Oct 15 20:29:21 2002
@@ -92,8 +92,6 @@
 #define MNTOPT_SUNIT	"sunit"		/* data volume stripe unit */
 #define MNTOPT_SWIDTH	"swidth"	/* data volume stripe width */
 #define MNTOPT_NORECOVERY "norecovery"	/* don't run XFS recovery */
-#define MNTOPT_OSYNCISDSYNC "osyncisdsync" /* o_sync == o_dsync on this fs */
-					   /* (this is now the default!) */
 #define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */
 #define MNTOPT_QUOTA	"quota"		/* disk quotas */
 #define MNTOPT_MRQUOTA	"mrquota"	/* don't turnoff if SB has quotas on */
@@ -104,7 +102,6 @@
 #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */
 #define MNTOPT_QUOTANOENF  "qnoenforce" /* same as uqnoenforce */
 #define MNTOPT_NOUUID	"nouuid"	/* Ignore FS uuid */
-#define MNTOPT_IRIXSGID "irixsgid"	/* Irix-style sgid inheritance */
 #define MNTOPT_NOLOGFLUSH  "nologflush"	/* Don't use hard flushes in
 					   log writing */
 #define MNTOPT_MTPT	"mtpt"		/* filesystem mount point */
@@ -124,6 +121,9 @@
 
 	iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0;
 
+	/* Default to 32 bit inodes on linux all the time */
+	args->flags |= XFSMNT_32BITINODES;
+
 	/* Copy the already-parsed mount(2) flags we're interested in */
 	if (flags & MS_NOATIME)
 		args->flags |= XFSMNT_NOATIME;
@@ -175,9 +175,6 @@
 			args->iosizelog = (uint8_t) iosize;
 		} else if (!strcmp(this_char, MNTOPT_WSYNC)) {
 			args->flags |= XFSMNT_WSYNC;
-		} else if (!strcmp(this_char, MNTOPT_OSYNCISDSYNC)) {
-			/* no-op, this is now the default */
-printk("XFS: osyncisdsync is now the default, and will soon be deprecated.\n");
 		} else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) {
 			args->flags |= XFSMNT_OSYNCISOSYNC;
 		} else if (!strcmp(this_char, MNTOPT_NORECOVERY)) {
@@ -212,10 +209,13 @@
 			dswidth = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_NOUUID)) {
 			args->flags |= XFSMNT_NOUUID;
-		} else if (!strcmp(this_char, MNTOPT_IRIXSGID)) {
-			args->flags |= XFSMNT_IRIXSGID;
 		} else if (!strcmp(this_char, MNTOPT_NOLOGFLUSH)) {
 			args->flags |= XFSMNT_NOLOGFLUSH;
+		} else if (!strcmp(this_char, "osyncisdsync")) {
+			/* no-op, this is now the default */
+printk("XFS: osyncisdsync is now the default, option is deprecated.\n");
+		} else if (!strcmp(this_char, "irixsgid")) {
+printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n");
 		} else {
 			printk("XFS: unknown mount option [%s].\n", this_char);
 			return rval;
@@ -264,53 +264,72 @@
 	return 0;
 }
 
-/*
- * Convert one device special file to a dev_t.
- * Helper routine, used only by spectodevs below.
- */
 STATIC int
-spectodev(
-	const char		*name,
-	const char		*id,
-	dev_t			*dev)
+xfs_showargs(
+	struct vfs		*vfsp,
+	struct seq_file		*m)
 {
-	struct nameidata	nd;
-	int			error;
+	static struct proc_xfs_info {
+		int	flag;
+		char	*str;
+	} xfs_info[] = {
+		/* the few simple ones we can get from the mount struct */
+		{ XFS_MOUNT_NOALIGN,		"," MNTOPT_NOALIGN },
+		{ XFS_MOUNT_NORECOVERY,		"," MNTOPT_NORECOVERY },
+		{ XFS_MOUNT_OSYNCISOSYNC,	"," MNTOPT_OSYNCISOSYNC },
+		{ XFS_MOUNT_NOUUID,		"," MNTOPT_NOUUID },
+		{ 0, NULL }
+	};
+	struct proc_xfs_info	*xfs_infop;
+	struct xfs_mount	*mp = XFS_BHVTOM(vfsp->vfs_fbhv);
 
-	error = path_lookup(name, LOOKUP_FOLLOW, &nd);
-	if (error)
-		return error;
+	for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
+		if (mp->m_flags & xfs_infop->flag)
+			seq_puts(m, xfs_infop->str);
+	}
 
-	*dev = kdev_t_to_nr(nd.dentry->d_inode->i_rdev);
-	path_release(&nd);
-	return 0;
-}
+	if (mp->m_qflags & XFS_UQUOTA_ACCT) {
+		(mp->m_qflags & XFS_UQUOTA_ENFD) ?
+			seq_puts(m, "," MNTOPT_UQUOTA) :
+			seq_puts(m, "," MNTOPT_UQUOTANOENF);
+	}
 
-/*
- * Convert device special files to dev_t for data, log, realtime.
- */
-int
-spectodevs(
-	struct super_block	*sb,
-	struct xfs_mount_args	*args,
-	dev_t			*ddevp,
-	dev_t			*logdevp,
-	dev_t			*rtdevp)
-{
-	int			rval = 0;
+	if (mp->m_qflags & XFS_GQUOTA_ACCT) {
+		(mp->m_qflags & XFS_GQUOTA_ENFD) ?
+			seq_puts(m, "," MNTOPT_GQUOTA) :
+			seq_puts(m, "," MNTOPT_GQUOTANOENF);
+	}
 
-	*ddevp = sb->s_dev;
+	if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
+		seq_printf(m, "," MNTOPT_BIOSIZE "=%d", mp->m_writeio_log);
 
-	if (args->logname[0])
-		rval = spectodev(args->logname, "log", logdevp);
-	else
-		*logdevp = sb->s_dev;
+	if (mp->m_logbufs > 0)
+		seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs);
 
-	if (args->rtname[0] && !rval)
-		rval = spectodev(args->rtname, "realtime", rtdevp);
-	else
-		*rtdevp = 0;
-	return rval;
+	if (mp->m_logbsize > 0)
+		seq_printf(m, "," MNTOPT_LOGBSIZE "=%d", mp->m_logbsize);
+
+	if (mp->m_ddev_targp->pbr_dev != mp->m_logdev_targp->pbr_dev)
+		seq_printf(m, "," MNTOPT_LOGDEV "=%s",
+				bdevname(mp->m_logdev_targp->pbr_bdev));
+
+	if (mp->m_rtdev_targp &&
+	    mp->m_ddev_targp->pbr_dev != mp->m_rtdev_targp->pbr_dev)
+		seq_printf(m, "," MNTOPT_RTDEV "=%s",
+				bdevname(mp->m_rtdev_targp->pbr_bdev));
+
+	if (mp->m_dalign > 0)
+		seq_printf(m, "," MNTOPT_SUNIT "=%d",
+				(int)XFS_FSB_TO_BB(mp, mp->m_dalign));
+
+	if (mp->m_swidth > 0)
+		seq_printf(m, "," MNTOPT_SWIDTH "=%d",
+				(int)XFS_FSB_TO_BB(mp, mp->m_swidth));
+
+	if (vfsp->vfs_flag & VFS_DMI)
+		seq_puts(m, "," MNTOPT_DMAPI);
+
+	return 0;
 }
 
 
@@ -439,7 +458,6 @@
 		goto fail_unmount;
 
 	ip = LINVFS_GET_IP(rootvp);
-	linvfs_revalidate_core(ip, ATTR_COMM);
 
 	sb->s_root = d_alloc_root(ip);
 	if (!sb->s_root)
@@ -493,12 +511,6 @@
 {
 	vnode_t			*vp = LINVFS_GET_VP(inode);
 
-	inode->i_mode = VTTOIF(vp->v_type);
-
-	/* If this isn't a new inode, nothing to do */
-	if (!(inode->i_state & I_NEW))
-		return;
-
 	if (vp->v_type == VNON) {
 		make_bad_inode(inode);
 	} else if (S_ISREG(inode->i_mode)) {
@@ -517,8 +529,6 @@
 		init_special_inode(inode, inode->i_mode,
 					kdev_t_to_nr(inode->i_rdev));
 	}
-
-	unlock_new_inode(inode);
 }
 
 /*
@@ -580,7 +590,6 @@
 	struct super_block	*sb)
 {
 	int			error;
-	int			sector_size;
 	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
 
 	VFS_DOUNMOUNT(vfsp, 0, NULL, NULL, error);
@@ -591,10 +600,6 @@
 	}
 
 	vfs_deallocate(vfsp);
-
-	/* Reset device block size */
-	sector_size = bdev_hardsect_size(sb->s_bdev);
-	set_blocksize(sb->s_bdev, sector_size);
 }
 
 void
@@ -728,7 +733,6 @@
 			VN_RELE(cvp);
 			return ERR_PTR(-EACCES);
 		}
-		error = -linvfs_revalidate_core(ip, ATTR_COMM);
 	}
 	if (error)
 		return ERR_PTR(-error);
@@ -759,72 +763,9 @@
 	struct seq_file		*m,
 	struct vfsmount		*mnt)
 {
-	vfs_t			*vfsp;
-	xfs_mount_t		*mp;
-	static struct proc_xfs_info {
-		int	flag;
-		char	*str;
-	} xfs_info[] = {
-		/* the few simple ones we can get from the mount struct */
-		{ XFS_MOUNT_NOALIGN,		",noalign" },
-		{ XFS_MOUNT_NORECOVERY,		",norecovery" },
-		{ XFS_MOUNT_OSYNCISOSYNC,	",osyncisosync" },
-		{ XFS_MOUNT_NOUUID,		",nouuid" },
-		{ XFS_MOUNT_IRIXSGID,		",irixsgid" },
-		{ 0, NULL }
-	};
-	struct proc_xfs_info	*xfs_infop;
-
-	vfsp = LINVFS_GET_VFS(mnt->mnt_sb);
-	mp = XFS_BHVTOM(vfsp->vfs_fbhv);
-
-	for (xfs_infop = xfs_info; xfs_infop->flag; xfs_infop++) {
-		if (mp->m_flags & xfs_infop->flag)
-			seq_puts(m, xfs_infop->str);
-	}
-
-	if (mp->m_qflags & XFS_UQUOTA_ACCT) {
-		seq_puts(m, ",uquota");
-		if (!(mp->m_qflags & XFS_UQUOTA_ENFD))
-			seq_puts(m, ",uqnoenforce");
-	}
+	vfs_t			*vfsp = LINVFS_GET_VFS(mnt->mnt_sb);
 
-	if (mp->m_qflags & XFS_GQUOTA_ACCT) {
-		seq_puts(m, ",gquota");
-		if (!(mp->m_qflags & XFS_GQUOTA_ENFD))
-			seq_puts(m, ",gqnoenforce");
-	}
-
-	if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
-		seq_printf(m, ",biosize=%d", mp->m_writeio_log);
-
-	if (mp->m_logbufs > 0)
-		seq_printf(m, ",logbufs=%d", mp->m_logbufs);
-
-	if (mp->m_logbsize > 0)
-		seq_printf(m, ",logbsize=%d", mp->m_logbsize);
-
-	if (mp->m_ddev_targp->pbr_dev != mp->m_logdev_targp->pbr_dev)
-		seq_printf(m, ",logdev=%s",
-				bdevname(mp->m_logdev_targp->pbr_bdev));
-
-	if (mp->m_rtdev_targp &&
-	    mp->m_ddev_targp->pbr_dev != mp->m_rtdev_targp->pbr_dev)
-		seq_printf(m, ",rtdev=%s",
-				bdevname(mp->m_rtdev_targp->pbr_bdev));
-
-	if (mp->m_dalign > 0)
-		seq_printf(m, ",sunit=%d",
-				(int)XFS_FSB_TO_BB(mp, mp->m_dalign));
-
-	if (mp->m_swidth > 0)
-		seq_printf(m, ",swidth=%d",
-				(int)XFS_FSB_TO_BB(mp, mp->m_swidth));
-
-	if (vfsp->vfs_flag & VFS_DMI)
-		seq_puts(m, ",dmapi");
-
-	return 0;
+	return xfs_showargs(vfsp, m);
 }
 
 STATIC struct super_operations linvfs_sops = {
diff -Nru a/fs/xfs/linux/xfs_super.h b/fs/xfs/linux/xfs_super.h
--- a/fs/xfs/linux/xfs_super.h	Tue Oct 15 20:29:15 2002
+++ b/fs/xfs/linux/xfs_super.h	Tue Oct 15 20:29:15 2002
@@ -80,18 +80,8 @@
 	((s)->s_fs_info = vfsp)
 
 
-struct xfs_mount_args;
-
 extern void
 linvfs_set_inode_ops(
 	struct inode	*inode);
-
-extern int
-spectodevs(
-	struct super_block *sb,
-	struct xfs_mount_args *args,
-	dev_t		*ddevp,
-	dev_t		*logdevp,
-	dev_t		*rtdevp);
 
 #endif	/* __XFS_SUPER_H__ */
diff -Nru a/fs/xfs/linux/xfs_sysctl.c b/fs/xfs/linux/xfs_sysctl.c
--- a/fs/xfs/linux/xfs_sysctl.c	Tue Oct 15 20:29:23 2002
+++ b/fs/xfs/linux/xfs_sysctl.c	Tue Oct 15 20:29:23 2002
@@ -35,30 +35,34 @@
 #include <linux/proc_fs.h>
 
 /*
- * Tunable xfs parameters
+ * Tunable XFS parameters
  */
 
 extern struct xfsstats xfsstats;
 
-unsigned long xfs_min[XFS_PARAM] = {			 0,			 0, 0 };
-unsigned long xfs_max[XFS_PARAM] = { XFS_REFCACHE_SIZE_MAX,  XFS_REFCACHE_SIZE_MAX, 1 };
+STATIC ulong xfs_min[XFS_PARAM] = { \
+			    0,			    0, 0, 0, 0, 0 };
+STATIC ulong xfs_max[XFS_PARAM] = { \
+	XFS_REFCACHE_SIZE_MAX,  XFS_REFCACHE_SIZE_MAX, 1, 1, 1, 1 };
 
-xfs_param_t xfs_params = { 128, 32, 0 };
+xfs_param_t xfs_params = { 128, 32, 0, 1, 0, 0 };
 
 static struct ctl_table_header *xfs_table_header;
 
-/* proc handlers */
 
-extern void xfs_refcache_resize(int xfs_refcache_new_size);
+/* Custom proc handlers */
 
-static int
-xfs_refcache_resize_proc_handler(ctl_table *ctl, int write, struct file * filp,
-		       void *buffer, size_t *lenp)
+STATIC int
+xfs_refcache_resize_proc_handler(
+	ctl_table	*ctl,
+	int		write,
+	struct file	*filp,
+	void		*buffer,
+	size_t		*lenp)
 {
-	int	ret;
-	int	*valp = ctl->data;
-	int	xfs_refcache_new_size;
-	int	xfs_refcache_old_size = *valp;
+	int		ret, *valp = ctl->data;
+	int		xfs_refcache_new_size;
+	int		xfs_refcache_old_size = *valp;
 
 	ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp);
 	xfs_refcache_new_size = *valp;
@@ -73,12 +77,15 @@
 	return ret;
 }
 
-static int
-xfs_stats_clear_proc_handler(ctl_table *ctl, int write, struct file * filp,
-		       void *buffer, size_t *lenp)
+STATIC int
+xfs_stats_clear_proc_handler(
+	ctl_table	*ctl,
+	int		write,
+	struct file	*filp,
+	void		*buffer,
+	size_t		*lenp)
 {
-	int		ret;
-	int		*valp = ctl->data;
+	int		ret, *valp = ctl->data;
 	__uint32_t	vn_active;
 
 	ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp);
@@ -95,7 +102,7 @@
 	return ret;
 }
 
-static ctl_table xfs_table[] = {
+STATIC ctl_table xfs_table[] = {
 	{XFS_REFCACHE_SIZE, "refcache_size", &xfs_params.refcache_size,
 	sizeof(ulong), 0644, NULL, &xfs_refcache_resize_proc_handler,
 	&sysctl_intvec, NULL, &xfs_min[0], &xfs_max[0]},
@@ -108,15 +115,27 @@
 	sizeof(ulong), 0644, NULL, &xfs_stats_clear_proc_handler,
 	&sysctl_intvec, NULL, &xfs_min[2], &xfs_max[2]},
 
+	{XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown,
+	sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
+	&sysctl_intvec, NULL, &xfs_min[3], &xfs_max[3]},
+
+	{XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit,
+	sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
+	&sysctl_intvec, NULL, &xfs_min[4], &xfs_max[4]},
+
+	{XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode,
+	sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
+	&sysctl_intvec, NULL, &xfs_min[5], &xfs_max[5]},
+
 	{0}
 };
 
-static ctl_table xfs_dir_table[] = {
+STATIC ctl_table xfs_dir_table[] = {
 	{FS_XFS, "xfs", NULL, 0, 0555, xfs_table},
 	{0}
 };
 
-static ctl_table xfs_root_table[] = {
+STATIC ctl_table xfs_root_table[] = {
 	{CTL_FS, "fs",	NULL, 0, 0555, xfs_dir_table},
 	{0}
 };
diff -Nru a/fs/xfs/linux/xfs_sysctl.h b/fs/xfs/linux/xfs_sysctl.h
--- a/fs/xfs/linux/xfs_sysctl.h	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/linux/xfs_sysctl.h	Tue Oct 15 20:29:11 2002
@@ -39,18 +39,25 @@
  * Tunable xfs parameters
  */
 
-#define XFS_PARAM	3
+#define XFS_PARAM	(sizeof(struct xfs_param) / sizeof(ulong))
 
 typedef struct xfs_param {
-	ulong	refcache_size;	/* Size of nfs refcache */
-	ulong	refcache_purge; /* # of entries to purge each time */
-	ulong	stats_clear;	/* reset all xfs stats to 0 */
+	ulong	refcache_size;	/* Size of NFS reference cache.          */
+	ulong	refcache_purge;	/* # of entries to purge each time.      */
+	ulong	stats_clear;	/* Reset all XFS statistics to zero.     */
+	ulong	restrict_chown;	/* Root/non-root can give away files.    */
+	ulong	sgid_inherit;	/* Inherit ISGID bit if process' GID is  */
+				/*  not a member of the parent dir GID.  */
+	ulong	symlink_mode;	/* Symlink creat mode affected by umask. */
 } xfs_param_t;
 
 enum {
 	XFS_REFCACHE_SIZE = 1,
 	XFS_REFCACHE_PURGE = 2,
 	XFS_STATS_CLEAR = 3,
+	XFS_RESTRICT_CHOWN = 4,
+	XFS_SGID_INHERIT = 5,
+	XFS_SYMLINK_MODE = 6,
 };
 
 extern xfs_param_t	xfs_params;
diff -Nru a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h
--- a/fs/xfs/linux/xfs_vfs.h	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/linux/xfs_vfs.h	Tue Oct 15 20:29:11 2002
@@ -92,6 +92,8 @@
 					/* send dmapi mount event */
 	int	(*vfs_dmapi_fsys_vector)(bhv_desc_t *,
 					 struct dm_fcntl_vector *);
+	void	(*vfs_init_vnode)(bhv_desc_t *, struct vnode *,
+					bhv_desc_t *, int);
 	void	(*vfs_force_shutdown)(bhv_desc_t *,
 					int, char *, int);
 } vfsops_t;
@@ -132,6 +134,14 @@
 	rv = (*(VFS_FOPS(vfsp)->vfs_vget))((vfsp)->vfs_fbhv, vpp, fidp);  \
 	BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \
 }
+
+#define VFS_INIT_VNODE(vfsp, vp, bhv, unlock) \
+{	\
+	BHV_READ_LOCK(&(vfsp)->vfs_bh); \
+	(*(VFS_FOPS(vfsp)->vfs_init_vnode))((vfsp)->vfs_fbhv, vp, bhv, unlock);\
+	BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \
+}
+
 /* No behavior lock here */
 #define VFS_FORCE_SHUTDOWN(vfsp, flags) \
 	(*(VFS_FOPS(vfsp)->vfs_force_shutdown))((vfsp)->vfs_fbhv, flags, __FILE__, __LINE__);
diff -Nru a/fs/xfs/linux/xfs_vnode.c b/fs/xfs/linux/xfs_vnode.c
--- a/fs/xfs/linux/xfs_vnode.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/linux/xfs_vnode.c	Tue Oct 15 20:29:16 2002
@@ -179,20 +179,10 @@
 	if (inode->i_state & I_FREEING)
 		return NULL;
 
-	inode = iget_locked(vmap->v_vfsp->vfs_super, vmap->v_ino);
+	inode = ilookup(vmap->v_vfsp->vfs_super, vmap->v_ino);
 	if (inode == NULL)		/* Inode not present */
 		return NULL;
 
-	/* We do not want to create new inodes via vn_get,
-	 * returning NULL here is OK.
-	 */
-	if (inode->i_state & I_NEW) {
-		make_bad_inode(inode);
-		unlock_new_inode(inode);
-		iput(inode);
-		return NULL;
-	}
-
 	vn_trace_exit(vp, "vn_get", (inst_t *)__return_address);
 	ASSERT((vp->v_flag & VPURGE) == 0);
 
@@ -203,7 +193,7 @@
  * "revalidate" the linux inode.
  */
 int
-vn_revalidate(struct vnode *vp, int flags)
+vn_revalidate(struct vnode *vp)
 {
 	int		error;
 	struct inode	*inode;
@@ -215,7 +205,7 @@
 
 	ASSERT(vp->v_bh.bh_first != NULL);
 
-	VOP_GETATTR(vp, &va, flags & ATTR_LAZY, NULL, error);
+	VOP_GETATTR(vp, &va, 0, NULL, error);
 
 	if (! error) {
 		inode = LINVFS_GET_IP(vp);
@@ -225,27 +215,12 @@
 		inode->i_nlink	    = va.va_nlink;
 		inode->i_uid	    = va.va_uid;
 		inode->i_gid	    = va.va_gid;
-		inode->i_rdev	    = mk_kdev(MAJOR(va.va_rdev),
-						MINOR(va.va_rdev));
-		inode->i_blksize    = PAGE_CACHE_SIZE;
-		inode->i_generation = va.va_gencount;
-		if ((flags & ATTR_COMM) ||
-		    S_ISREG(inode->i_mode) ||
-		    S_ISDIR(inode->i_mode) ||
-		    S_ISLNK(inode->i_mode)) {
-			inode->i_size	    = va.va_size;
-			inode->i_blocks	    = va.va_nblocks;
-			inode->i_atime	    = va.va_atime.tv_sec;
-			inode->i_mtime	    = va.va_mtime.tv_sec;
-			inode->i_ctime	    = va.va_ctime.tv_sec;
-		}
-		if (flags & ATTR_LAZY)
-			vp->v_flag &= ~VMODIFIED;
-		else
-			VUNMODIFY(vp);
-	} else {
-		vn_trace_exit(vp, "vn_revalidate.error",
-					(inst_t *)__return_address);
+		inode->i_size	    = va.va_size;
+		inode->i_blocks	    = va.va_nblocks;
+		inode->i_mtime	    = va.va_mtime.tv_sec;
+		inode->i_ctime	    = va.va_ctime.tv_sec;
+		inode->i_atime	    = va.va_atime.tv_sec;
+		VUNMODIFY(vp);
 	}
 
 	return -error;
@@ -412,8 +387,7 @@
 	 * After the following purge the vnode
 	 * will no longer exist.
 	 */
-	VMAP(vp, XFS_BHVTOI(vp->v_fbhv), vmap);
-
+	VMAP(vp, vmap);
 	vn_purge(vp, &vmap);
 }
 
diff -Nru a/fs/xfs/linux/xfs_vnode.h b/fs/xfs/linux/xfs_vnode.h
--- a/fs/xfs/linux/xfs_vnode.h	Tue Oct 15 20:29:23 2002
+++ b/fs/xfs/linux/xfs_vnode.h	Tue Oct 15 20:29:23 2002
@@ -211,8 +211,7 @@
 typedef int	(*vop_release_t)(bhv_desc_t *);
 typedef int	(*vop_rwlock_t)(bhv_desc_t *, vrwlock_t);
 typedef void	(*vop_rwunlock_t)(bhv_desc_t *, vrwlock_t);
-typedef int	(*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, struct page_buf_bmap_s *, int *);
-typedef int	(*vop_strategy_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, struct page_buf_bmap_s *, int *);
+typedef int	(*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct page_buf_bmap_s *, int *);
 typedef int	(*vop_reclaim_t)(bhv_desc_t *);
 typedef int	(*vop_attr_get_t)(bhv_desc_t *, char *, char *, int *, int,
 				struct cred *);
@@ -254,7 +253,6 @@
 	vop_rwlock_t		vop_rwlock;
 	vop_rwunlock_t		vop_rwunlock;
 	vop_bmap_t		vop_bmap;
-	vop_strategy_t		vop_strategy;
 	vop_reclaim_t		vop_reclaim;
 	vop_attr_get_t		vop_attr_get;
 	vop_attr_set_t		vop_attr_set;
@@ -286,16 +284,10 @@
 	rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,cr);\
 	VN_BHV_READ_UNLOCK(&(vp)->v_bh);				\
 }
-#define VOP_BMAP(vp,of,sz,rw,cr,b,n,rv)					\
+#define VOP_BMAP(vp,of,sz,rw,b,n,rv)					\
 {									\
 	VN_BHV_READ_LOCK(&(vp)->v_bh);					\
-	rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,cr,b,n);		\
-	VN_BHV_READ_UNLOCK(&(vp)->v_bh);				\
-}
-#define VOP_STRATEGY(vp,of,sz,rw,cr,b,n,rv)				\
-{									\
-	VN_BHV_READ_LOCK(&(vp)->v_bh);					\
-	rv = _VOP_(vop_strategy, vp)((vp)->v_fbhv,of,sz,rw,cr,b,n);	\
+	rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n);		\
 	VN_BHV_READ_UNLOCK(&(vp)->v_bh);				\
 }
 #define VOP_OPEN(vp, cr, rv)						\
@@ -528,14 +520,14 @@
 	mode_t		va_mode;	/* file access mode */
 	uid_t		va_uid;		/* owner user id */
 	gid_t		va_gid;		/* owner group id */
-	dev_t		va_fsid;	/* file system id (dev for now) */
+	xfs_dev_t	va_fsid;	/* file system id (dev for now) */
 	xfs_ino_t	va_nodeid;	/* node id */
 	nlink_t		va_nlink;	/* number of references to file */
 	xfs_off_t	va_size;	/* file size in bytes */
 	timespec_t	va_atime;	/* time of last access */
 	timespec_t	va_mtime;	/* time of last modification */
 	timespec_t	va_ctime;	/* time file ``created'' */
-	dev_t		va_rdev;	/* device the file represents */
+	xfs_dev_t	va_rdev;	/* device the file represents */
 	u_long		va_blksize;	/* fundamental block size */
 	__int64_t	va_nblocks;	/* # of blocks allocated */
 	u_long		va_vcode;	/* version code */
@@ -637,12 +629,13 @@
 	xfs_ino_t	v_ino;			/* inode #	*/
 } vmap_t;
 
-#define VMAP(vp, ip, vmap)	{(vmap).v_vfsp	 = (vp)->v_vfsp,	\
-				 (vmap).v_number = (vp)->v_number,	\
-				 (vmap).v_ino	 = (ip)->i_ino; }
+#define VMAP(vp, vmap)	{(vmap).v_vfsp	 = (vp)->v_vfsp,	\
+			 (vmap).v_number = (vp)->v_number,	\
+			 (vmap).v_ino	 = (vp)->v_inode.i_ino; }
+
 extern void	vn_purge(struct vnode *, vmap_t *);
 extern vnode_t	*vn_get(struct vnode *, vmap_t *);
-extern int	vn_revalidate(struct vnode *, int);
+extern int	vn_revalidate(struct vnode *);
 extern void	vn_remove(struct vnode *);
 
 static inline int vn_count(struct vnode *vp)
diff -Nru a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c
--- a/fs/xfs/pagebuf/page_buf.c	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/pagebuf/page_buf.c	Tue Oct 15 20:29:11 2002
@@ -305,8 +305,7 @@
 	/*
 	 * We don't want certain flags to appear in pb->pb_flags.
 	 */
-	flags &= ~(PBF_LOCK|PBF_ENTER_PAGES|PBF_MAPPED);
-	flags &= ~(PBF_DONT_BLOCK|PBF_READ_AHEAD);
+	flags &= ~(PBF_LOCK|PBF_MAPPED|PBF_DONT_BLOCK|PBF_READ_AHEAD);
 
 	pb_tracking_get(pb);
 
@@ -545,9 +544,9 @@
 		size -= nbytes;
 
 		if (!PageUptodate(page)) {
-			if ((blocksize == PAGE_CACHE_SIZE) &&
-			    (flags & PBF_READ)) {
-				pb->pb_locked = 1;
+			if (blocksize == PAGE_CACHE_SIZE) {
+				if (flags & PBF_READ)
+					pb->pb_locked = 1;
 				good_pages--;
 			} else if (!PagePrivate(page)) {
 				unsigned long i, range = (offset + nbytes) >> SECTOR_SHIFT;
@@ -717,7 +716,6 @@
 				PBF_MAPPED | \
 				_PBF_LOCKABLE | \
 				_PBF_ALL_PAGES_MAPPED | \
-				_PBF_SOME_INVALID_PAGES | \
 				_PBF_ADDR_ALLOCATED | \
 				_PBF_MEM_ALLOCATED;
 	PB_TRACE(pb, PB_TRACE_REC(got_lk), 0);
@@ -832,19 +830,11 @@
 	int			flags)
 {
 	page_buf_t		*pb = NULL;
-	int			status;
 
 	flags |= _PBF_PRIVATE_BH;
 	pb = pagebuf_allocate(flags);
 	if (pb) {
 		_pagebuf_initialize(pb, target, ioff, isize, flags);
-		if (flags & PBF_ENTER_PAGES) {
-			status = _pagebuf_lookup_pages(pb, &inode->i_data, 0);
-			if (status != 0) {
-				pagebuf_free(pb);
-				return (NULL);
-			}
-		}
 	}
 	return pb;
 }
@@ -985,6 +975,7 @@
 	}
 	/* otherwise pagebuf_free just ignores it */
 	pb->pb_flags |= _PBF_MEM_ALLOCATED;
+	PB_CLEAR_OWNER(pb);
 	up(&PBP(pb)->pb_sema);	/* Return unlocked pagebuf */
 
 	PB_TRACE(pb, PB_TRACE_REC(no_daddr), rmem);
@@ -1926,14 +1917,14 @@
 	sizeof(ulong), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax,
 	&sysctl_intvec, NULL, &pagebuf_min[1], &pagebuf_max[1]},
 
-	{PB_STATS_CLEAR, "stats_clear", &pb_params.data[3],
+	{PB_STATS_CLEAR, "stats_clear", &pb_params.data[2],
 	sizeof(ulong), 0644, NULL, &pb_stats_clear_handler,
-	&sysctl_intvec, NULL, &pagebuf_min[3], &pagebuf_max[3]},
+	&sysctl_intvec, NULL, &pagebuf_min[2], &pagebuf_max[2]},
 
 #ifdef PAGEBUF_TRACE
-	{PB_DEBUG, "debug", &pb_params.data[4],
+	{PB_DEBUG, "debug", &pb_params.data[3],
 	sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
-	&sysctl_intvec, NULL, &pagebuf_min[4], &pagebuf_max[4]},
+	&sysctl_intvec, NULL, &pagebuf_min[3], &pagebuf_max[3]},
 #endif
 	{0}
 };
diff -Nru a/fs/xfs/pagebuf/page_buf.h b/fs/xfs/pagebuf/page_buf.h
--- a/fs/xfs/pagebuf/page_buf.h	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/pagebuf/page_buf.h	Tue Oct 15 20:29:17 2002
@@ -100,35 +100,27 @@
 	PBF_MAPPABLE = (1 << 9),/* use directly-addressable pages	   */
 	PBF_STALE = (1 << 10),	/* buffer has been staled, do not find it  */
 	PBF_FS_MANAGED = (1 << 11), /* filesystem controls freeing memory  */
-	PBF_RELEASE = (1 << 12),/* buffer to be released after I/O is done */
 
 	/* flags used only as arguments to access routines */
 	PBF_LOCK = (1 << 13),	/* lock requested			   */
 	PBF_TRYLOCK = (1 << 14), /* lock requested, but do not wait	   */
-	PBF_ALLOCATE = (1 << 15), /* allocate all pages		  (UNUSED) */
-	PBF_FILE_ALLOCATE = (1 << 16), /* allocate all file space	   */
-	PBF_DONT_BLOCK = (1 << 17), /* do not block in current thread	   */
-	PBF_DIRECT = (1 << 18),	  /* direct I/O desired			   */
-	PBF_ENTER_PAGES = (1 << 21), /* create invalid pages for all	   */
-				/* pages in the range of the buffer	   */
-				/* not already associated with buffer	   */
+	PBF_FILE_ALLOCATE = (1 << 15), /* allocate all file space	   */
+	PBF_DONT_BLOCK = (1 << 16), /* do not block in current thread	   */
+	PBF_DIRECT = (1 << 17),	  /* direct I/O desired			   */
 
 	/* flags used only internally */
 	_PBF_LOCKABLE = (1 << 19), /* page_buf_t may be locked		   */
 	_PBF_PRIVATE_BH = (1 << 20), /* do not use public buffer heads	   */
-	_PBF_ALL_PAGES_MAPPED = (1 << 22),
+	_PBF_ALL_PAGES_MAPPED = (1 << 21),
 				/* all pages in rage are mapped		   */
-	_PBF_SOME_INVALID_PAGES = (1 << 23),
-				/* some mapped pages are not valid	   */
-	_PBF_ADDR_ALLOCATED = (1 << 24),
+	_PBF_ADDR_ALLOCATED = (1 << 22),
 				/* pb_addr space was allocated		   */
-	_PBF_MEM_ALLOCATED = (1 << 25),
+	_PBF_MEM_ALLOCATED = (1 << 23),
 				/* pb_mem and underlying pages allocated   */
 
-	PBF_FORCEIO = (1 << 27),
-	PBF_FLUSH = (1 << 28),	/* flush disk write cache */
-	PBF_READ_AHEAD = (1 << 29),
-	PBF_FS_RESERVED_3 = (1 << 31)	/* reserved (XFS use: XFS_B_STALE) */
+	PBF_FORCEIO = (1 << 24),
+	PBF_FLUSH = (1 << 25),	/* flush disk write cache */
+	PBF_READ_AHEAD = (1 << 26),
 
 } page_buf_flags_t;
 
@@ -145,7 +137,6 @@
 	struct block_device	*pbr_bdev;
 	struct address_space	*pbr_mapping;
 	unsigned int		pbr_blocksize;
-	unsigned int		pbr_blocksize_bits;
 } pb_target_t;
 
 /*
@@ -303,26 +294,16 @@
 extern int pagebuf_lock(		/* lock buffer			*/
 		page_buf_t *);		/* buffer to lock		*/
 
-extern void pagebuf_lock_disable(	/* disable buffer locking	*/
-		struct pb_target *,	/* inode for buffers		*/
-		int);			/* do blkdev_put?		*/
-
-extern struct pb_target *pagebuf_lock_enable(
-		dev_t,
-		int);			/* do blkdev_get?		*/
-
-extern void pagebuf_target_blocksize(
-		pb_target_t *,
-		unsigned int);		/* block size			*/
-
 extern void pagebuf_target_clear(struct pb_target *);
 
 extern void pagebuf_unlock(		/* unlock buffer		*/
 		page_buf_t *);		/* buffer to unlock		*/
 
 /* Buffer Utility Routines */
-
-#define pagebuf_geterror(pb)	((pb)->pb_error)
+static inline int pagebuf_geterror(page_buf_t *pb)
+{
+	return (pb ? pb->pb_error : ENOMEM);
+}
 
 extern void pagebuf_iodone(		/* mark buffer I/O complete	*/
 		page_buf_t *);		/* buffer to mark		*/
diff -Nru a/fs/xfs/pagebuf/page_buf_locking.c b/fs/xfs/pagebuf/page_buf_locking.c
--- a/fs/xfs/pagebuf/page_buf_locking.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/pagebuf/page_buf_locking.c	Tue Oct 15 20:29:17 2002
@@ -1,6 +1,5 @@
 /*
  * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
- * Portions Copyright (c) 2002 Christoph Hellwig.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -58,10 +57,6 @@
 
 #include "page_buf_internal.h"
 
-#ifndef EVMS_MAJOR
-#define EVMS_MAJOR      117
-#endif
-
 /*
  *	pagebuf_cond_lock
  *
@@ -124,82 +119,6 @@
 	PB_SET_OWNER(pb);
 	PB_TRACE(pb, PB_TRACE_REC(locked), 0);
 	return 0;
-}
-
-/*
- *	pagebuf_lock_disable
- *
- *	pagebuf_lock_disable disables buffer object locking for an inode.
- *	remove_super() does a blkdev_put for us on the data device, hence
- * 	the do_blkdev_put argument.
- */
-void
-pagebuf_lock_disable(
-	pb_target_t		*target,
-	int			do_blkdev_put)
-{
-	pagebuf_delwri_flush(target, PBDF_WAIT, NULL);
-	if (do_blkdev_put)
-		blkdev_put(target->pbr_bdev, BDEV_FS);
-	kfree(target);
-}
-
-/*
- *	pagebuf_lock_enable
- *
- *	get_sb_bdev() does a blkdev_get for us on the data device, hence
- *	the do_blkdev_get argument.
- */
-pb_target_t *
-pagebuf_lock_enable(
-	dev_t			dev,
-	int			do_blkdev_get)
-{
-	struct block_device	*bdev;
-	pb_target_t		*target;
-	int			error = -ENOMEM;
-
-	target = kmalloc(sizeof(pb_target_t), GFP_KERNEL);
-	if (unlikely(!target))
-		return ERR_PTR(error);
-
-	bdev = bdget(dev);
-	if (unlikely(!bdev))
-		goto fail;
-
-	if (do_blkdev_get) {
-		error = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS);
-		if (unlikely(error))
-			goto fail;
-	}
-
-	target->pbr_dev = dev;
-	target->pbr_bdev = bdev;
-	target->pbr_mapping = bdev->bd_inode->i_mapping;
-
-	pagebuf_target_blocksize(target, PAGE_CACHE_SIZE);
-	
-	if ((MAJOR(dev) == MD_MAJOR) || (MAJOR(dev) == EVMS_MAJOR))
-		target->pbr_flags = PBR_ALIGNED_ONLY;
-	else if (MAJOR(dev) == LVM_BLK_MAJOR)
-		target->pbr_flags = PBR_SECTOR_ONLY;
-	else
-		target->pbr_flags = 0;
-
-	return target;
-
-fail:
-	kfree(target);
-	return ERR_PTR(error);
-}
-
-void
-pagebuf_target_blocksize(
-	pb_target_t		*target,
-	unsigned int		blocksize)
-{
-	target->pbr_blocksize = blocksize;
-	target->pbr_blocksize_bits = ffs(blocksize) - 1;
 }
 
 void
diff -Nru a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
--- a/fs/xfs/support/debug.c	Tue Oct 15 20:29:12 2002
+++ b/fs/xfs/support/debug.c	Tue Oct 15 20:29:12 2002
@@ -40,6 +40,11 @@
 static char		message[256];	/* keep it off the stack */
 static spinlock_t 	xfs_err_lock = SPIN_LOCK_UNLOCKED;
 
+/* Translate from CE_FOO to KERN_FOO, err_level(CE_FOO) == KERN_FOO */
+static char		*err_level[8] = {KERN_EMERG, KERN_ALERT, KERN_CRIT,
+					 KERN_ERR, KERN_WARNING, KERN_NOTICE,
+					 KERN_INFO, KERN_DEBUG};
+
 void
 assfail(char *a, char *f, int l)
 {
@@ -71,10 +76,7 @@
 	return current->pid;
 }
 
-# define xdprintk(format...)	printk(format)
-#else
-# define xdprintk(format...)	do { } while (0)
-#endif
+#endif /* DEBUG */
 
 void
 cmn_err(register int level, char *fmt, ...)
@@ -86,18 +88,7 @@
 	va_start(ap, fmt);
 	if (*fmt == '!') fp++;
 	vsprintf(message, fp, ap);
-	switch (level) {
-	case CE_CONT:
-	case CE_WARN:
-		printk("%s", message);
-		break;
-	case CE_DEBUG:
-		xdprintk("%s", message);
-		break;
-	default:
-		printk("%s\n", message);
-		break;
-	}
+	printk("%s%s\n", err_level[level], message);
 	va_end(ap);
 	spin_unlock(&xfs_err_lock);
 
@@ -111,18 +102,8 @@
 {
 	spin_lock(&xfs_err_lock);
 	vsprintf(message, fmt, ap);
-	switch (level) {
-	case CE_CONT:
-	case CE_WARN:
-		printk("%s", message);
-		break;
-	case CE_DEBUG:
-		xdprintk("%s", message);
-		break;
-	default:
-		printk("cmn_err level %d ", level);
-		printk("%s\n", message);
-		break;
-	}
 	spin_unlock(&xfs_err_lock);
+	printk("%s%s\n", err_level[level], message);
+	if (level == CE_PANIC)
+		BUG();
 }
diff -Nru a/fs/xfs/support/move.c b/fs/xfs/support/move.c
--- a/fs/xfs/support/move.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/support/move.c	Tue Oct 15 20:29:17 2002
@@ -72,9 +72,9 @@
 
 		case UIO_SYSSPACE:
 			if (rw == UIO_READ)
-				bcopy(cp, iov->iov_base, cnt);
+				memcpy(iov->iov_base, cp, cnt);
 			else
-				bcopy(iov->iov_base, cp, cnt);
+				memcpy(cp, iov->iov_base, cnt);
 			break;
 
 		default:
diff -Nru a/fs/xfs/support/move.h b/fs/xfs/support/move.h
--- a/fs/xfs/support/move.h	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/support/move.h	Tue Oct 15 20:29:17 2002
@@ -36,11 +36,6 @@
 #include <linux/uio.h>
 #include <asm/uaccess.h>
 
-#define bzero(p,s)	memset((p), 0, (s))
-#define bcopy(s,d,n)	memcpy((d),(s),(n))
-#define bcmp(s1,s2,l)	memcmp(s1,s2,l)
-#define ovbcopy(from,to,count)	memmove(to,from,count)
-
 typedef struct iovec iovec_t;
 
 typedef struct uio {
diff -Nru a/fs/xfs/support/uuid.c b/fs/xfs/support/uuid.c
--- a/fs/xfs/support/uuid.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/support/uuid.c	Tue Oct 15 20:29:16 2002
@@ -109,7 +109,7 @@
 void
 uuid_create_nil(uuid_t *uuid)
 {
-	bzero(uuid, sizeof *uuid);
+	memset(uuid, 0, sizeof(*uuid));
 }
 
 int
@@ -129,7 +129,7 @@
 int
 uuid_equal(uuid_t *uuid1, uuid_t *uuid2)
 {
-	return bcmp(uuid1, uuid2, sizeof(uuid_t)) ? B_FALSE : B_TRUE;
+	return memcmp(uuid1, uuid2, sizeof(uuid_t)) ? B_FALSE : B_TRUE;
 }
 
 /*
diff -Nru a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
--- a/fs/xfs/xfs_alloc.c	Tue Oct 15 20:29:14 2002
+++ b/fs/xfs/xfs_alloc.c	Tue Oct 15 20:29:14 2002
@@ -494,13 +494,13 @@
 		(void *)(__psunsigned_t)INT_GET(agf->agf_seqno, ARCH_CONVERT),
 		(void *)(__psunsigned_t)INT_GET(agf->agf_length, ARCH_CONVERT),
 		(void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_BNO],
-						ARCH_CONVERT);
+						ARCH_CONVERT),
 		(void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_CNT],
-						ARCH_CONVERT);
+						ARCH_CONVERT),
 		(void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_BNO],
-						ARCH_CONVERT);
+						ARCH_CONVERT),
 		(void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_CNT],
-						ARCH_CONVERT);
+						ARCH_CONVERT),
 		(void *)(__psunsigned_t)INT_GET(agf->agf_flfirst, ARCH_CONVERT),
 		(void *)(__psunsigned_t)INT_GET(agf->agf_fllast, ARCH_CONVERT),
 		(void *)(__psunsigned_t)INT_GET(agf->agf_flcount, ARCH_CONVERT),
@@ -2597,7 +2597,7 @@
 	s = mutex_spinlock(&mp->m_perag[agno].pagb_lock);
 	cnt = mp->m_perag[agno].pagb_count;
 
-	uend = bno + len;
+	uend = bno + len - 1;
 
 	/* search pagb_list for this slot, skipping open slots */
 	for (bsy = mp->m_perag[agno].pagb_list, n = 0;
@@ -2607,16 +2607,16 @@
 		 * (start1,length1) within (start2, length2)
 		 */
 		if (bsy->busy_tp != NULL) {
-			bend = bsy->busy_start + bsy->busy_length;
-			if ( (bno >= bsy->busy_start && bno <= bend) ||
-			     (uend >= bsy->busy_start && uend <= bend) ||
-			     (bno <= bsy->busy_start && uend >= bsy->busy_start) ) {
+			bend = bsy->busy_start + bsy->busy_length - 1;
+			if ((bno > bend) ||
+			    (uend < bsy->busy_start)) {
+				cnt--;
+			} else {
 				TRACE_BUSYSEARCH("xfs_alloc_search_busy",
 						 "found1", agno, bno, len, n,
 						 tp);
 				break;
 			}
-			cnt--;
 		}
 	}
 
@@ -2626,7 +2626,7 @@
 	 */
 	if (cnt) {
 		TRACE_BUSYSEARCH("xfs_alloc_search_busy", "found", agno, bno, len, n, tp);
-		lsn = bsy->busy_tp->t_lsn;
+		lsn = bsy->busy_tp->t_commit_lsn;
 		mutex_spinunlock(&mp->m_perag[agno].pagb_lock, s);
 		xfs_log_force(mp, lsn, XFS_LOG_FORCE|XFS_LOG_SYNC);
 	} else {
diff -Nru a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
--- a/fs/xfs/xfs_alloc_btree.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_alloc_btree.c	Tue Oct 15 20:29:17 2002
@@ -132,9 +132,9 @@
 		}
 #endif
 		if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
-			ovbcopy(&lkp[ptr], &lkp[ptr - 1],
+			memmove(&lkp[ptr - 1], &lkp[ptr],
 				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lkp)); /* INT_: mem copy */
-			ovbcopy(&lpp[ptr], &lpp[ptr - 1],
+			memmove(&lpp[ptr - 1], &lpp[ptr],
 				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lpp)); /* INT_: mem copy */
 			xfs_alloc_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
 			xfs_alloc_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
@@ -147,7 +147,7 @@
 	else {
 		lrp = XFS_ALLOC_REC_ADDR(block, 1, cur);
 		if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
-			ovbcopy(&lrp[ptr], &lrp[ptr - 1],
+			memmove(&lrp[ptr - 1], &lrp[ptr],
 				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lrp));
 			xfs_alloc_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
 		}
@@ -464,8 +464,8 @@
 				return error;
 		}
 #endif
-		bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); /* INT_: structure copy */
-		bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); /* INT_: structure copy */
+		memcpy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); /* INT_: structure copy */
+		memcpy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); /* INT_: structure copy */
 		xfs_alloc_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
 				   INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		xfs_alloc_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
@@ -476,7 +476,7 @@
 		 */
 		lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur);
 		rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);
-		bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
+		memcpy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
 		xfs_alloc_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
 				   INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
 	}
@@ -697,9 +697,9 @@
 				return error;
 		}
 #endif
-		ovbcopy(&kp[ptr - 1], &kp[ptr],
+		memmove(&kp[ptr], &kp[ptr - 1],
 			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); /* INT_: copy */
-		ovbcopy(&pp[ptr - 1], &pp[ptr],
+		memmove(&pp[ptr], &pp[ptr - 1],
 			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); /* INT_: copy */
 #ifdef DEBUG
 		if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
@@ -723,7 +723,7 @@
 		 * It's a leaf entry.  Make a hole for the new record.
 		 */
 		rp = XFS_ALLOC_REC_ADDR(block, 1, cur);
-		ovbcopy(&rp[ptr - 1], &rp[ptr],
+		memmove(&rp[ptr], &rp[ptr - 1],
 			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp));
 		/*
 		 * Now stuff the new record in, bump numrecs
@@ -1217,12 +1217,12 @@
 				return error;
 		}
 #endif
-		ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
-		ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+		memmove(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+		memmove(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
 		xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 	} else {
-		ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+		memmove(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
 		xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */
 		key.ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */
@@ -1475,8 +1475,8 @@
 				return error;
 		}
 #endif
-		ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
-		ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+		memmove(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+		memmove(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
 #ifdef DEBUG
 		if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level)))
 			return error;
@@ -1492,7 +1492,7 @@
 
 		lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);
 		rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);
-		ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+		memmove(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
 		*rrp = *lrp;
 		xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);
 		key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */
@@ -1608,8 +1608,8 @@
 				return error;
 		}
 #endif
-		bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); /* INT_: copy */
-		bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));/* INT_: copy */
+		memcpy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); /* INT_: copy */
+		memcpy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); /* INT_: copy */
 		xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		*keyp = *rkp;
@@ -1623,7 +1623,7 @@
 
 		lrp = XFS_ALLOC_REC_ADDR(left, i, cur);
 		rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);
-		bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+		memcpy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
 		xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		keyp->ar_startblock = rrp->ar_startblock; /* INT_: direct copy */
 		keyp->ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */
diff -Nru a/fs/xfs/xfs_arch.h b/fs/xfs/xfs_arch.h
--- a/fs/xfs/xfs_arch.h	Tue Oct 15 20:29:20 2002
+++ b/fs/xfs/xfs_arch.h	Tue Oct 15 20:29:20 2002
@@ -260,13 +260,13 @@
 
 #define DIRINO_COPY_ARCH(from,to,arch) \
     if ((arch) == ARCH_NOCONVERT) { \
-	bcopy(from,to,sizeof(xfs_ino_t)); \
+	memcpy(to,from,sizeof(xfs_ino_t)); \
     } else { \
 	INT_SWAP_UNALIGNED_64(from,to); \
     }
 #define DIRINO4_COPY_ARCH(from,to,arch) \
     if ((arch) == ARCH_NOCONVERT) { \
-	bcopy((((__u8*)from+4)),to,sizeof(xfs_dir2_ino4_t)); \
+	memcpy(to,(((__u8*)from+4)),sizeof(xfs_dir2_ino4_t)); \
     } else { \
 	INT_SWAP_UNALIGNED_32(from,to); \
     }
diff -Nru a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
--- a/fs/xfs/xfs_attr.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_attr.c	Tue Oct 15 20:29:17 2002
@@ -120,7 +120,7 @@
 	/*
 	 * Fill in the arg structure for this request.
 	 */
-	bzero((char *)&args, sizeof(args));
+	memset((char *)&args, 0, sizeof(args));
 	args.name = name;
 	args.namelen = namelen;
 	args.value = value;
@@ -215,7 +215,7 @@
 	/*
 	 * Fill in the arg structure for this request.
 	 */
-	bzero((char *)&args, sizeof(args));
+	memset((char *)&args, 0, sizeof(args));
 	args.name = name;
 	args.namelen = namelen;
 	args.value = value;
@@ -469,7 +469,7 @@
 	/*
 	 * Fill in the arg structure for this request.
 	 */
-	bzero((char *)&args, sizeof(args));
+	memset((char *)&args, 0, sizeof(args));
 	args.name = name;
 	args.namelen = namelen;
 	args.flags = flags;
diff -Nru a/fs/xfs/xfs_attr_fetch.c b/fs/xfs/xfs_attr_fetch.c
--- a/fs/xfs/xfs_attr_fetch.c	Tue Oct 15 20:29:18 2002
+++ b/fs/xfs/xfs_attr_fetch.c	Tue Oct 15 20:29:18 2002
@@ -43,7 +43,7 @@
 	/*
 	 * Do the argument setup for the xfs_attr routines.
 	 */
-	bzero((char *)&args, sizeof(args));
+	memset((char *)&args, 0, sizeof(args));
 	args.dp = ip;
 	args.flags = ATTR_ROOT;
 	args.whichfork = XFS_ATTR_FORK;
diff -Nru a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
--- a/fs/xfs/xfs_attr_leaf.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_attr_leaf.c	Tue Oct 15 20:29:17 2002
@@ -128,7 +128,7 @@
 				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
 		if (sfe->namelen != args->namelen)
 			continue;
-		if (bcmp(args->name, sfe->nameval, args->namelen) != 0)
+		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
 			continue;
 		if (((args->flags & ATTR_ROOT) != 0) !=
 		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
@@ -145,8 +145,8 @@
 	sfe->namelen = args->namelen;
 	INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen);
 	sfe->flags = (args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0;
-	bcopy(args->name, sfe->nameval, args->namelen);
-	bcopy(args->value, &sfe->nameval[args->namelen], args->valuelen);
+	memcpy(sfe->nameval, args->name, args->namelen);
+	memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
 	INT_MOD(sf->hdr.count, ARCH_CONVERT, 1);
 	INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size);
 	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
@@ -178,7 +178,7 @@
 		size = XFS_ATTR_SF_ENTSIZE(sfe);
 		if (sfe->namelen != args->namelen)
 			continue;
-		if (bcmp(sfe->nameval, args->name, args->namelen) != 0)
+		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
 			continue;
 		if (((args->flags & ATTR_ROOT) != 0) !=
 		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
@@ -191,7 +191,7 @@
 	end = base + size;
 	totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
 	if (end != totsize) {
-		ovbcopy(&((char *)sf)[end], &((char *)sf)[base],
+		memmove(&((char *)sf)[base], &((char *)sf)[end],
 							totsize - end);
 	}
 	INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
@@ -222,7 +222,7 @@
 				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
 		if (sfe->namelen != args->namelen)
 			continue;
-		if (bcmp(args->name, sfe->nameval, args->namelen) != 0)
+		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
 			continue;
 		if (((args->flags & ATTR_ROOT) != 0) !=
 		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
@@ -250,7 +250,7 @@
 				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
 		if (sfe->namelen != args->namelen)
 			continue;
-		if (bcmp(args->name, sfe->nameval, args->namelen) != 0)
+		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
 			continue;
 		if (((args->flags & ATTR_ROOT) != 0) !=
 		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
@@ -264,7 +264,7 @@
 			return(XFS_ERROR(ERANGE));
 		}
 		args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
-		bcopy(&sfe->nameval[args->namelen], args->value,
+		memcpy(args->value, &sfe->nameval[args->namelen],
 						    args->valuelen);
 		return(XFS_ERROR(EEXIST));
 	}
@@ -293,7 +293,7 @@
 	size = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
 	tmpbuffer = kmem_alloc(size, KM_SLEEP);
 	ASSERT(tmpbuffer != NULL);
-	bcopy(ifp->if_u1.if_data, tmpbuffer, size);
+	memcpy(tmpbuffer, ifp->if_u1.if_data, size);
 	sf = (xfs_attr_shortform_t *)tmpbuffer;
 
 	xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
@@ -307,7 +307,7 @@
 		if (error == EIO)
 			goto out;
 		xfs_idata_realloc(dp, size, XFS_ATTR_FORK);	/* try to put */
-		bcopy(tmpbuffer, ifp->if_u1.if_data, size);	/* it back */
+		memcpy(ifp->if_u1.if_data, tmpbuffer, size);	/* it back */
 		goto out;
 	}
 
@@ -319,11 +319,11 @@
 		if (error)
 			goto out;
 		xfs_idata_realloc(dp, size, XFS_ATTR_FORK);	/* try to put */
-		bcopy(tmpbuffer, ifp->if_u1.if_data, size);	/* it back */
+		memcpy(ifp->if_u1.if_data, tmpbuffer, size);	/* it back */
 		goto out;
 	}
 
-	bzero((char *)&nargs, sizeof(nargs));
+	memset((char *)&nargs, 0, sizeof(nargs));
 	nargs.dp = dp;
 	nargs.firstblock = args->firstblock;
 	nargs.flist = args->flist;
@@ -590,11 +590,11 @@
 	ASSERT(tmpbuffer != NULL);
 
 	ASSERT(bp != NULL);
-	bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount));
+	memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
 	leaf = (xfs_attr_leafblock_t *)tmpbuffer;
 	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
 						== XFS_ATTR_LEAF_MAGIC);
-	bzero(bp->data, XFS_LBSIZE(dp->i_mount));
+	memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
 
 	/*
 	 * Clean out the prior contents of the attribute list.
@@ -609,7 +609,7 @@
 	/*
 	 * Copy the attributes
 	 */
-	bzero((char *)&nargs, sizeof(nargs));
+	memset((char *)&nargs, 0, sizeof(nargs));
 	nargs.dp = dp;
 	nargs.firstblock = args->firstblock;
 	nargs.flist = args->flist;
@@ -669,7 +669,7 @@
 	if (error)
 		goto out;
 	ASSERT(bp2 != NULL);
-	bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount));
+	memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));
 	xfs_da_buf_done(bp1);
 	bp1 = NULL;
 	xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
@@ -725,7 +725,7 @@
 		return(error);
 	ASSERT(bp != NULL);
 	leaf = bp->data;
-	bzero((char *)leaf, XFS_LBSIZE(dp->i_mount));
+	memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
 	hdr = &leaf->hdr;
 	INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC);
 	INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
@@ -900,7 +900,7 @@
 	if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) {
 		tmp  = INT_GET(hdr->count, ARCH_CONVERT) - args->index;
 		tmp *= sizeof(xfs_attr_leaf_entry_t);
-		ovbcopy((char *)entry, (char *)(entry+1), tmp);
+		memmove((char *)(entry+1), (char *)entry, tmp);
 		xfs_da_log_buf(args->trans, bp,
 		    XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
 	}
@@ -955,13 +955,13 @@
 		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
 		name_loc->namelen = args->namelen;
 		INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen);
-		bcopy(args->name, (char *)name_loc->nameval, args->namelen);
-		bcopy(args->value, (char *)&name_loc->nameval[args->namelen],
+		memcpy((char *)name_loc->nameval, args->name, args->namelen);
+		memcpy((char *)&name_loc->nameval[args->namelen], args->value,
 				   INT_GET(name_loc->valuelen, ARCH_CONVERT));
 	} else {
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
 		name_rmt->namelen = args->namelen;
-		bcopy(args->name, (char *)name_rmt->name, args->namelen);
+		memcpy((char *)name_rmt->name, args->name, args->namelen);
 		entry->flags |= XFS_ATTR_INCOMPLETE;
 		/* just in case */
 		INT_ZERO(name_rmt->valuelen, ARCH_CONVERT);
@@ -1017,8 +1017,8 @@
 	mp = trans->t_mountp;
 	tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP);
 	ASSERT(tmpbuffer != NULL);
-	bcopy(bp->data, tmpbuffer, XFS_LBSIZE(mp));
-	bzero(bp->data, XFS_LBSIZE(mp));
+	memcpy(tmpbuffer, bp->data, XFS_LBSIZE(mp));
+	memset(bp->data, 0, XFS_LBSIZE(mp));
 
 	/*
 	 * Copy basic information
@@ -1390,7 +1390,7 @@
 		 * path point to the block we want to drop (this one).
 		 */
 		forward = (!INT_ISZERO(info->forw, ARCH_CONVERT));
-		bcopy(&state->path, &state->altpath, sizeof(state->path));
+		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
 		if (error)
@@ -1450,7 +1450,7 @@
 	 * Make altpath point to the block we want to keep (the lower
 	 * numbered block) and path point to the block we want to drop.
 	 */
-	bcopy(&state->path, &state->altpath, sizeof(state->path));
+	memcpy(&state->altpath, &state->path, sizeof(state->path));
 	if (blkno < blk->blkno) {
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -1585,7 +1585,7 @@
 	/*
 	 * Compress the remaining entries and zero out the removed stuff.
 	 */
-	bzero(XFS_ATTR_LEAF_NAME(leaf, args->index), entsize);
+	memset(XFS_ATTR_LEAF_NAME(leaf, args->index), 0, entsize);
 	INT_MOD(hdr->usedbytes, ARCH_CONVERT, -entsize);
 	xfs_da_log_buf(args->trans, bp,
 	     XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index),
@@ -1593,12 +1593,12 @@
 
 	tmp = (INT_GET(hdr->count, ARCH_CONVERT) - args->index)
 					* sizeof(xfs_attr_leaf_entry_t);
-	ovbcopy((char *)(entry+1), (char *)entry, tmp);
+	memmove((char *)entry, (char *)(entry+1), tmp);
 	INT_MOD(hdr->count, ARCH_CONVERT, -1);
 	xfs_da_log_buf(args->trans, bp,
 	    XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
 	entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)];
-	bzero((char *)entry, sizeof(xfs_attr_leaf_entry_t));
+	memset((char *)entry, 0, sizeof(xfs_attr_leaf_entry_t));
 
 	/*
 	 * If we removed the first entry, re-find the first used byte
@@ -1701,7 +1701,7 @@
 		 */
 		tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP);
 		ASSERT(tmpbuffer != NULL);
-		bzero(tmpbuffer, state->blocksize);
+		memset(tmpbuffer, 0, state->blocksize);
 		tmp_leaf = (xfs_attr_leafblock_t *)tmpbuffer;
 		tmp_hdr = &tmp_leaf->hdr;
 		tmp_hdr->info = save_hdr->info; /* struct copy */
@@ -1729,7 +1729,7 @@
 				(int)INT_GET(drop_hdr->count, ARCH_CONVERT),
 				mp);
 		}
-		bcopy((char *)tmp_leaf, (char *)save_leaf, state->blocksize);
+		memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize);
 		kmem_free(tmpbuffer, state->blocksize);
 	}
 
@@ -1840,7 +1840,7 @@
 			name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe);
 			if (name_loc->namelen != args->namelen)
 				continue;
-			if (bcmp(args->name, (char *)name_loc->nameval,
+			if (memcmp(args->name, (char *)name_loc->nameval,
 					     args->namelen) != 0)
 				continue;
 			if (((args->flags & ATTR_ROOT) != 0) !=
@@ -1852,7 +1852,7 @@
 			name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, probe);
 			if (name_rmt->namelen != args->namelen)
 				continue;
-			if (bcmp(args->name, (char *)name_rmt->name,
+			if (memcmp(args->name, (char *)name_rmt->name,
 					     args->namelen) != 0)
 				continue;
 			if (((args->flags & ATTR_ROOT) != 0) !=
@@ -1895,7 +1895,7 @@
 	if (entry->flags & XFS_ATTR_LOCAL) {
 		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
 		ASSERT(name_loc->namelen == args->namelen);
-		ASSERT(bcmp(args->name, name_loc->nameval, args->namelen) == 0);
+		ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0);
 		valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT);
 		if (args->flags & ATTR_KERNOVAL) {
 			args->valuelen = valuelen;
@@ -1906,11 +1906,11 @@
 			return(XFS_ERROR(ERANGE));
 		}
 		args->valuelen = valuelen;
-		bcopy(&name_loc->nameval[args->namelen], args->value, valuelen);
+		memcpy(args->value, &name_loc->nameval[args->namelen], valuelen);
 	} else {
 		name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
 		ASSERT(name_rmt->namelen == args->namelen);
-		ASSERT(bcmp(args->name, name_rmt->name, args->namelen) == 0);
+		ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0);
 		valuelen = INT_GET(name_rmt->valuelen, ARCH_CONVERT);
 		args->rmtblkno = INT_GET(name_rmt->valueblk, ARCH_CONVERT);
 		args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, valuelen);
@@ -1983,7 +1983,7 @@
 		tmp *= sizeof(xfs_attr_leaf_entry_t);
 		entry_s = &leaf_d->entries[start_d];
 		entry_d = &leaf_d->entries[start_d + count];
-		ovbcopy((char *)entry_s, (char *)entry_d, tmp);
+		memmove((char *)entry_d, (char *)entry_s, tmp);
 	}
 
 	/*
@@ -2004,7 +2004,7 @@
 		 * off for 6.2, should be revisited later.
 		 */
 		if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */
-			bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp);
+			memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp);
 			INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp);
 			INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
 			entry_d--;	/* to compensate for ++ in loop hdr */
@@ -2021,11 +2021,11 @@
 			entry_d->flags = entry_s->flags;
 			ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp
 							<= XFS_LBSIZE(mp));
-			ovbcopy(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i),
-			      XFS_ATTR_LEAF_NAME(leaf_d, desti), tmp);
+			memmove(XFS_ATTR_LEAF_NAME(leaf_d, desti),
+				XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp);
 			ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp
 							<= XFS_LBSIZE(mp));
-			bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp);
+			memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp);
 			INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp);
 			INT_MOD(hdr_d->usedbytes, ARCH_CONVERT, tmp);
 			INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
@@ -2047,7 +2047,7 @@
 		entry_s = &leaf_s->entries[start_s];
 		ASSERT(((char *)entry_s + tmp) <=
 		       ((char *)leaf_s + XFS_LBSIZE(mp)));
-		bzero((char *)entry_s, tmp);
+		memset((char *)entry_s, 0, tmp);
 	} else {
 		/*
 		 * Move the remaining entries down to fill the hole,
@@ -2057,14 +2057,14 @@
 		tmp *= sizeof(xfs_attr_leaf_entry_t);
 		entry_s = &leaf_s->entries[start_s + count];
 		entry_d = &leaf_s->entries[start_s];
-		ovbcopy((char *)entry_s, (char *)entry_d, tmp);
+		memmove((char *)entry_d, (char *)entry_s, tmp);
 
 		tmp = count * sizeof(xfs_attr_leaf_entry_t);
 		entry_s = &leaf_s->entries[INT_GET(hdr_s->count,
 							ARCH_CONVERT)];
 		ASSERT(((char *)entry_s + tmp) <=
 		       ((char *)leaf_s + XFS_LBSIZE(mp)));
-		bzero((char *)entry_s, tmp);
+		memset((char *)entry_s, 0, tmp);
 	}
 
 	/*
@@ -2345,7 +2345,7 @@
 
 	aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
 	aep->a_valuelen = valuelen;
-	bcopy(name, aep->a_name, namelen);
+	memcpy(aep->a_name, name, namelen);
 	aep->a_name[ namelen ] = 0;
 	context->alist->al_offset[ context->count++ ] = context->firstu;
 	context->alist->al_count = context->count;
@@ -2404,7 +2404,7 @@
 	}
 	ASSERT(INT_GET(entry->hashval, ARCH_CONVERT) == args->hashval);
 	ASSERT(namelen == args->namelen);
-	ASSERT(bcmp(name, args->name, namelen) == 0);
+	ASSERT(memcmp(name, args->name, namelen) == 0);
 #endif /* DEBUG */
 
 	entry->flags &= ~XFS_ATTR_INCOMPLETE;
@@ -2559,7 +2559,7 @@
 	}
 	ASSERT(INT_GET(entry1->hashval, ARCH_CONVERT) == INT_GET(entry2->hashval, ARCH_CONVERT));
 	ASSERT(namelen1 == namelen2);
-	ASSERT(bcmp(name1, name2, namelen1) == 0);
+	ASSERT(memcmp(name1, name2, namelen1) == 0);
 #endif /* DEBUG */
 
 	ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE);
diff -Nru a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
--- a/fs/xfs/xfs_bmap.c	Tue Oct 15 20:29:21 2002
+++ b/fs/xfs/xfs_bmap.c	Tue Oct 15 20:29:21 2002
@@ -489,7 +489,7 @@
 		return 0;
 	if ((ip->i_d.di_mode & IFMT) == IFDIR) {
 		mp = ip->i_mount;
-		bzero(&dargs, sizeof(dargs));
+		memset(&dargs, 0, sizeof(dargs));
 		dargs.dp = ip;
 		dargs.firstblock = firstblock;
 		dargs.flist = flist;
@@ -3146,7 +3146,7 @@
 	ASSERT(ifp->if_flags & XFS_IFEXTENTS);
 	base = ifp->if_u1.if_extents;
 	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - count;
-	ovbcopy(&base[idx + count], &base[idx],
+	memmove(&base[idx], &base[idx + count],
 		(nextents - idx) * sizeof(*base));
 	xfs_iext_realloc(ip, -count, whichfork);
 }
@@ -3174,7 +3174,7 @@
 	xfs_btree_cur_t		*cur;		/* bmap btree cursor */
 	xfs_bmbt_rec_t		*ep;		/* extent list pointer */
 	int			error;		/* error return value */
-	xfs_extnum_t		i;		/* extent list index */
+	xfs_extnum_t		i, cnt;		/* extent list index */
 	xfs_ifork_t		*ifp;		/* inode fork pointer */
 	xfs_bmbt_key_t		*kp;		/* root block key pointer */
 	xfs_mount_t		*mp;		/* mount structure */
@@ -3256,24 +3256,25 @@
 	ablock = XFS_BUF_TO_BMBT_BLOCK(abp);
 	INT_SET(ablock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC);
 	INT_ZERO(ablock->bb_level, ARCH_CONVERT);
-	INT_ZERO(ablock->bb_numrecs, ARCH_CONVERT);
 	INT_SET(ablock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO);
 	INT_SET(ablock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO);
 	arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
 	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-	for (ep = ifp->if_u1.if_extents, i = 0; i < nextents; i++, ep++) {
+	for (ep = ifp->if_u1.if_extents, cnt = i = 0; i < nextents; i++, ep++) {
 		if (!ISNULLSTARTBLOCK(xfs_bmbt_get_startblock(ep))) {
-			*arp++ = *ep;
-			INT_MOD(ablock->bb_numrecs, ARCH_CONVERT, +1);
+			arp->l0 = INT_GET(ep->l0, ARCH_CONVERT);
+			arp->l1 = INT_GET(ep->l1, ARCH_CONVERT);
+			arp++; cnt++;
 		}
 	}
+	INT_SET(ablock->bb_numrecs, ARCH_CONVERT, cnt);
 	ASSERT(INT_GET(ablock->bb_numrecs, ARCH_CONVERT) == XFS_IFORK_NEXTENTS(ip, whichfork));
 	/*
 	 * Fill in the root key and pointer.
 	 */
 	kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
 	arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
-	INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(arp));
+	INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(arp));
 	pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
 	INT_SET(*pp, ARCH_CONVERT, args.fsbno);
 	/*
@@ -3310,7 +3311,7 @@
 	xfs_iext_realloc(ip, count, whichfork);
 	base = ifp->if_u1.if_extents;
 	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-	ovbcopy(&base[idx], &base[idx + count],
+	memmove(&base[idx + count], &base[idx],
 		(nextents - (idx + count)) * sizeof(*base));
 	for (to = idx; to < idx + count; to++, new++)
 		xfs_bmbt_set_all(&base[to], new);
@@ -3380,7 +3381,7 @@
 		ASSERT(args.len == 1);
 		*firstblock = args.fsbno;
 		bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
-		bcopy(ifp->if_u1.if_data, (char *)XFS_BUF_PTR(bp),
+		memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data,
 			ifp->if_bytes);
 		xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
 		xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
@@ -3556,7 +3557,7 @@
 	if (cnt == 1) {
 		ASSERT(r2 == NULL);
 		r2 = &tr2;
-		bzero(&tr2, sizeof(tr2));
+		memset(&tr2, 0, sizeof(tr2));
 	} else
 		ASSERT(r2 != NULL);
 	ktrace_enter(xfs_bmap_trace_buf,
@@ -4332,7 +4333,7 @@
 #ifdef XFS_BMAP_TRACE
 	static char		fname[] = "xfs_bmap_read_extents";
 #endif
-	xfs_extnum_t		i;	/* index into the extents list */
+	xfs_extnum_t		i, j;	/* index into the extents list */
 	xfs_ifork_t		*ifp;	/* fork structure */
 	int			level;	/* btree level, for checking */
 	xfs_mount_t		*mp;	/* file system mount structure */
@@ -4373,28 +4374,9 @@
 			break;
 		pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block,
 			1, mp->m_bmap_dmxr[1]);
-#ifndef __KERNEL__
 		XFS_WANT_CORRUPTED_GOTO(
 			XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)),
 			error0);
-#else	/* additional, temporary, debugging code */
-		if (!(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)))) {
-			cmn_err(CE_NOTE,
-			"xfs_bmap_read_extents: FSB Sanity Check:");
-			if (!(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount))
-				cmn_err(CE_NOTE,
-					"bad AG count %d < agcount %d",
-					XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)),
-					mp->m_sb.sb_agcount);
-			if (!(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks))
-				cmn_err(CE_NOTE,
-					"bad AG BNO %d < %d",
-					XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)),
-					mp->m_sb.sb_agblocks);
-			error = XFS_ERROR(EFSCORRUPTED);
-			goto error0;
-		}
-#endif
 		bno = INT_GET(*pp, ARCH_CONVERT);
 		xfs_trans_brelse(tp, bp);
 	}
@@ -4408,7 +4390,7 @@
 	 * Loop over all leaf nodes.  Copy information to the extent list.
 	 */
 	for (;;) {
-		xfs_bmbt_rec_t	*frp;
+		xfs_bmbt_rec_t	*frp, *temp;
 		xfs_fsblock_t	nextbno;
 		xfs_extnum_t	num_recs;
 
@@ -4422,35 +4404,9 @@
 				(unsigned long long) ip->i_ino);
 			goto error0;
 		}
-#ifndef __KERNEL__
 		XFS_WANT_CORRUPTED_GOTO(
 			XFS_BMAP_SANITY_CHECK(mp, block, 0),
 			error0);
-#else	/* additional, temporary, debugging code */
-		if (!(XFS_BMAP_SANITY_CHECK(mp, block, 0))) {
-			cmn_err(CE_NOTE,
-			"xfs_bmap_read_extents: BMAP Sanity Check:");
-			if (!(INT_GET(block->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC))
-				cmn_err(CE_NOTE,
-					"bb_magic 0x%x",
-					INT_GET(block->bb_magic, ARCH_CONVERT));
-			if (!(INT_GET(block->bb_level, ARCH_CONVERT) == level))
-				cmn_err(CE_NOTE,
-					"bb_level %d",
-					INT_GET(block->bb_level, ARCH_CONVERT));
-			if (!(INT_GET(block->bb_numrecs, ARCH_CONVERT) > 0))
-				cmn_err(CE_NOTE,
-					"bb_numrecs %d",
-					INT_GET(block->bb_numrecs, ARCH_CONVERT));
-			if (!(INT_GET(block->bb_numrecs, ARCH_CONVERT) <= (mp)->m_bmap_dmxr[(level) != 0]))
-				cmn_err(CE_NOTE,
-					"bb_numrecs %d < m_bmap_dmxr[] %d",
-					INT_GET(block->bb_numrecs, ARCH_CONVERT),
-					(mp)->m_bmap_dmxr[(level) != 0]);
-			error = XFS_ERROR(EFSCORRUPTED);
-			goto error0;
-		}
-#endif
 		/*
 		 * Read-ahead the next leaf block, if any.
 		 */
@@ -4462,18 +4418,21 @@
 		 */
 		frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt,
 			block, 1, mp->m_bmap_dmxr[0]);
-		bcopy(frp, trp, num_recs * sizeof(*frp));
+		temp = trp;
+		for (j = 0; j < num_recs; j++, frp++, trp++) {
+			trp->l0 = INT_GET(frp->l0, ARCH_CONVERT);
+			trp->l1 = INT_GET(frp->l1, ARCH_CONVERT);
+		}
 		if (exntf == XFS_EXTFMT_NOSTATE) {
 			/*
 			 * Check all attribute bmap btree records and
 			 * any "older" data bmap btree records for a
 			 * set bit in the "extent flag" position.
 			 */
-			if (xfs_check_nostate_extents(trp, num_recs)) {
+			if (xfs_check_nostate_extents(temp, num_recs)) {
 				goto error0;
 			}
 		}
-		trp += num_recs;
 		i += num_recs;
 		xfs_trans_brelse(tp, bp);
 		bno = nextbno;
@@ -4650,11 +4609,6 @@
 	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) {
-#ifdef __KERNEL__	/* additional, temporary, debugging code */
-		cmn_err(CE_NOTE,
-			"EFSCORRUPTED returned from file %s line %d",
-			__FILE__, __LINE__);
-#endif
 		return XFS_ERROR(EFSCORRUPTED);
 	}
 	mp = ip->i_mount;
@@ -5150,11 +5104,6 @@
 	ifp = XFS_IFORK_PTR(ip, whichfork);
 	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE &&
 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) {
-#ifdef __KERNEL__	/* additional, temporary, debugging code */
-		cmn_err(CE_NOTE,
-			"EFSCORRUPTED returned from file %s line %d",
-			__FILE__, __LINE__);
-#endif
 	       return XFS_ERROR(EFSCORRUPTED);
 	}
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
@@ -5228,11 +5177,6 @@
 	ifp = XFS_IFORK_PTR(ip, whichfork);
 	if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
 	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) {
-#ifdef __KERNEL__	/* additional, temporary, debugging code */
-		cmn_err(CE_NOTE,
-			"EFSCORRUPTED returned from file %s line %d",
-			__FILE__, __LINE__);
-#endif
 		return XFS_ERROR(EFSCORRUPTED);
 	}
 	mp = ip->i_mount;
@@ -6317,7 +6261,7 @@
 	int		b;
 
 	for ( b = 1; b <= numrecs; b++, frp++)
-		*count += xfs_bmbt_get_blockcount(frp);
+		*count += xfs_bmbt_disk_get_blockcount(frp);
 	return 0;
 }
 
diff -Nru a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
--- a/fs/xfs/xfs_bmap_btree.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_bmap_btree.c	Tue Oct 15 20:29:17 2002
@@ -207,7 +207,7 @@
 	xfs_bmbt_irec_t		s;
 
 	d = (xfs_dfsbno_t)f;
-	xfs_bmbt_get_all(r, &s);
+	xfs_bmbt_disk_get_all(r, &s);
 	o = (xfs_dfiloff_t)s.br_startoff;
 	b = (xfs_dfsbno_t)s.br_startblock;
 	c = s.br_blockcount;
@@ -381,9 +381,9 @@
 		}
 #endif
 		if (ptr < numrecs) {
-			ovbcopy(&kp[ptr], &kp[ptr - 1],
+			memmove(&kp[ptr - 1], &kp[ptr],
 				(numrecs - ptr) * sizeof(*kp));
-			ovbcopy(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */
+			memmove(&pp[ptr - 1], &pp[ptr], /* INT_: direct copy */
 				(numrecs - ptr) * sizeof(*pp));
 			xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs - 1);
 			xfs_bmbt_log_keys(cur, bp, ptr, numrecs - 1);
@@ -391,12 +391,12 @@
 	} else {
 		rp = XFS_BMAP_REC_IADDR(block, 1, cur);
 		if (ptr < numrecs) {
-			ovbcopy(&rp[ptr], &rp[ptr - 1],
+			memmove(&rp[ptr - 1], &rp[ptr],
 				(numrecs - ptr) * sizeof(*rp));
 			xfs_bmbt_log_recs(cur, bp, ptr, numrecs - 1);
 		}
 		if (ptr == 1) {
-			INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rp));
+			INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(rp));
 			kp = &key;
 		}
 	}
@@ -619,14 +619,14 @@
 			}
 		}
 #endif
-		bcopy(rkp, lkp, numrrecs * sizeof(*lkp));
-		bcopy(rpp, lpp, numrrecs * sizeof(*lpp));
+		memcpy(lkp, rkp, numrrecs * sizeof(*lkp));
+		memcpy(lpp, rpp, numrrecs * sizeof(*lpp));
 		xfs_bmbt_log_keys(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
 		xfs_bmbt_log_ptrs(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
 	} else {
 		lrp = XFS_BMAP_REC_IADDR(left, numlrecs + 1, cur);
 		rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
-		bcopy(rrp, lrp, numrrecs * sizeof(*lrp));
+		memcpy(lrp, rrp, numrrecs * sizeof(*lrp));
 		xfs_bmbt_log_recs(cur, lbp, numlrecs + 1, numlrecs + numrrecs);
 	}
 	INT_MOD(left->bb_numrecs, ARCH_CONVERT, numrrecs);
@@ -711,10 +711,10 @@
 		return 0;
 	}
 	rp = XFS_BMAP_REC_IADDR(block, ptr, cur);
-	*off = xfs_bmbt_get_startoff(rp);
-	*bno = xfs_bmbt_get_startblock(rp);
-	*len = xfs_bmbt_get_blockcount(rp);
-	*state = xfs_bmbt_get_state(rp);
+	*off = xfs_bmbt_disk_get_startoff(rp);
+	*bno = xfs_bmbt_disk_get_startblock(rp);
+	*len = xfs_bmbt_disk_get_blockcount(rp);
+	*state = xfs_bmbt_disk_get_state(rp);
 	*stat = 1;
 	return 0;
 }
@@ -757,7 +757,8 @@
 	XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
 	XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp);
 	ncur = (xfs_btree_cur_t *)0;
-	INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(recp));
+	INT_SET(key.br_startoff, ARCH_CONVERT,
+		xfs_bmbt_disk_get_startoff(recp));
 	optr = ptr = cur->bc_ptrs[level];
 	if (ptr == 0) {
 		XFS_BMBT_TRACE_CURSOR(cur, EXIT);
@@ -835,7 +836,7 @@
 						}
 #endif
 						ptr = cur->bc_ptrs[level];
-						xfs_bmbt_set_allf(&nrec,
+						xfs_bmbt_disk_set_allf(&nrec,
 							nkey.br_startoff, 0, 0,
 							XFS_EXT_NORM);
 					} else {
@@ -861,9 +862,9 @@
 			}
 		}
 #endif
-		ovbcopy(&kp[ptr - 1], &kp[ptr],
+		memmove(&kp[ptr], &kp[ptr - 1],
 			(numrecs - ptr + 1) * sizeof(*kp));
-		ovbcopy(&pp[ptr - 1], &pp[ptr], /* INT_: direct copy */
+		memmove(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */
 			(numrecs - ptr + 1) * sizeof(*pp));
 #ifdef DEBUG
 		if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)*bnop,
@@ -880,7 +881,7 @@
 		xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs);
 	} else {
 		rp = XFS_BMAP_REC_IADDR(block, 1, cur);
-		ovbcopy(&rp[ptr - 1], &rp[ptr],
+		memmove(&rp[ptr], &rp[ptr - 1],
 			(numrecs - ptr + 1) * sizeof(*rp));
 		rp[ptr - 1] = *recp;
 		numrecs++;
@@ -980,7 +981,7 @@
 	ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) == INT_GET(cblock->bb_numrecs, ARCH_CONVERT));
 	kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
 	ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur);
-	bcopy(ckp, kp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*kp));
+	memcpy(kp, ckp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*kp));
 	pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
 	cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
 #ifdef DEBUG
@@ -991,7 +992,7 @@
 		}
 	}
 #endif
-	bcopy(cpp, pp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
+	memcpy(pp, cpp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
 	xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1,
 		cur->bc_private.b.flist, cur->bc_mp);
 	if (!async)
@@ -1175,7 +1176,7 @@
 					startoff = INT_GET(kkp->br_startoff, ARCH_CONVERT);
 				} else {
 					krp = krbase + keyno - 1;
-					startoff = xfs_bmbt_get_startoff(krp);
+					startoff = xfs_bmbt_disk_get_startoff(krp);
 				}
 				diff = (xfs_sfiloff_t)
 						(startoff - rp->br_startoff);
@@ -1349,14 +1350,15 @@
 			}
 		}
 #endif
-		ovbcopy(rkp + 1, rkp, rrecs * sizeof(*rkp));
-		ovbcopy(rpp + 1, rpp, rrecs * sizeof(*rpp));
+		memmove(rkp, rkp + 1, rrecs * sizeof(*rkp));
+		memmove(rpp, rpp + 1, rrecs * sizeof(*rpp));
 		xfs_bmbt_log_keys(cur, rbp, 1, rrecs);
 		xfs_bmbt_log_ptrs(cur, rbp, 1, rrecs);
 	} else {
-		ovbcopy(rrp + 1, rrp, rrecs * sizeof(*rrp));
+		memmove(rrp, rrp + 1, rrecs * sizeof(*rrp));
 		xfs_bmbt_log_recs(cur, rbp, 1, rrecs);
-		INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp));
+		INT_SET(key.br_startoff, ARCH_CONVERT,
+			xfs_bmbt_disk_get_startoff(rrp));
 		rkp = &key;
 	}
 	if ((error = xfs_bmbt_updkey(cur, rkp, level + 1))) {
@@ -1452,8 +1454,8 @@
 			}
 		}
 #endif
-		ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
-		ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+		memmove(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+		memmove(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
 #ifdef DEBUG
 		if ((error = xfs_btree_check_lptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) {
 			XFS_BMBT_TRACE_CURSOR(cur, ERROR);
@@ -1467,10 +1469,11 @@
 	} else {
 		lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);
 		rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
-		ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+		memmove(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
 		*rrp = *lrp;
 		xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);
-		INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp));
+		INT_SET(key.br_startoff, ARCH_CONVERT,
+			xfs_bmbt_disk_get_startoff(rrp));
 		rkp = &key;
 	}
 	INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1);
@@ -1629,17 +1632,17 @@
 			}
 		}
 #endif
-		bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
-		bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+		memcpy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+		memcpy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
 		xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		keyp->br_startoff = INT_GET(rkp->br_startoff, ARCH_CONVERT);
 	} else {
 		lrp = XFS_BMAP_REC_IADDR(left, i, cur);
 		rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
-		bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+		memcpy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
 		xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
-		keyp->br_startoff = xfs_bmbt_get_startoff(rrp);
+		keyp->br_startoff = xfs_bmbt_disk_get_startoff(rrp);
 	}
 	INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT)));
 	right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */
@@ -1748,8 +1751,8 @@
 	fpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr);
 	tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);
 	dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT);
-	bcopy(fkp, tkp, sizeof(*fkp) * dmxr);
-	bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
+	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
+	memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
 }
 
 /*
@@ -1874,17 +1877,16 @@
  * This code must be in sync with the routines xfs_bmbt_get_startoff,
  * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state.
  */
-void
-xfs_bmbt_get_all(
-	xfs_bmbt_rec_t	*r,
-	xfs_bmbt_irec_t *s)
+
+static __inline__ void
+__xfs_bmbt_get_all(
+		__uint64_t l0,
+		__uint64_t l1,
+		xfs_bmbt_irec_t *s)
 {
 	int	ext_flag;
 	xfs_exntst_t st;
-	__uint64_t	l0, l1;
 
-	l0 = INT_GET(r->l0, ARCH_CONVERT);
-	l1 = INT_GET(r->l1, ARCH_CONVERT);
 	ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN));
 	s->br_startoff = ((xfs_fileoff_t)l0 &
 			   XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
@@ -1915,6 +1917,14 @@
 	s->br_state = st;
 }
 
+void
+xfs_bmbt_get_all(
+	xfs_bmbt_rec_t	*r,
+	xfs_bmbt_irec_t *s)
+{
+	__xfs_bmbt_get_all(r->l0, r->l1, s);
+}
+
 /*
  * Get the block pointer for the given level of the cursor.
  * Fill in the buffer pointer, if applicable.
@@ -1941,23 +1951,94 @@
 }
 
 /*
- * Extract the blockcount field from a bmap extent record.
+ * Extract the blockcount field from an in memory bmap extent record.
  */
 xfs_filblks_t
 xfs_bmbt_get_blockcount(
 	xfs_bmbt_rec_t	*r)
 {
-	return (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21));
+	return (xfs_filblks_t)(r->l1 & XFS_MASK64LO(21));
 }
 
 /*
- * Extract the startblock field from a bmap extent record.
+ * Extract the startblock field from an in memory bmap extent record.
  */
 xfs_fsblock_t
 xfs_bmbt_get_startblock(
 	xfs_bmbt_rec_t	*r)
 {
 #if XFS_BIG_FILESYSTEMS
+	return (((xfs_fsblock_t)r->l0 & XFS_MASK64LO(9)) << 43) |
+	       (((xfs_fsblock_t)r->l1) >> 21);
+#else
+#ifdef DEBUG
+	xfs_dfsbno_t	b;
+
+	b = (((xfs_dfsbno_t)r->l0 & XFS_MASK64LO(9)) << 43) |
+	    (((xfs_dfsbno_t)r->l1) >> 21);
+	ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b));
+	return (xfs_fsblock_t)b;
+#else	/* !DEBUG */
+	return (xfs_fsblock_t)(((xfs_dfsbno_t)r->l1) >> 21);
+#endif	/* DEBUG */
+#endif	/* XFS_BIG_FILESYSTEMS */
+}
+
+/*
+ * Extract the startoff field from an in memory bmap extent record.
+ */
+xfs_fileoff_t
+xfs_bmbt_get_startoff(
+	xfs_bmbt_rec_t	*r)
+{
+	return ((xfs_fileoff_t)r->l0 &
+		 XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
+}
+
+xfs_exntst_t
+xfs_bmbt_get_state(
+	xfs_bmbt_rec_t	*r)
+{
+	int	ext_flag;
+
+	ext_flag = (int)((r->l0) >> (64 - BMBT_EXNTFLAG_BITLEN));
+	return xfs_extent_state(xfs_bmbt_get_blockcount(r),
+				ext_flag);
+}
+
+#if ARCH_CONVERT != ARCH_NOCONVERT
+/* Endian flipping versions of the bmbt extraction functions */
+void
+xfs_bmbt_disk_get_all(
+	xfs_bmbt_rec_t	*r,
+	xfs_bmbt_irec_t *s)
+{
+	__uint64_t	l0, l1;
+
+	l0 = INT_GET(r->l0, ARCH_CONVERT);
+	l1 = INT_GET(r->l1, ARCH_CONVERT);
+
+	__xfs_bmbt_get_all(l0, l1, s);
+}
+
+/*
+ * Extract the blockcount field from an on disk bmap extent record.
+ */
+xfs_filblks_t
+xfs_bmbt_disk_get_blockcount(
+	xfs_bmbt_rec_t	*r)
+{
+	return (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21));
+}
+
+/*
+ * Extract the startblock field from an on disk bmap extent record.
+ */
+xfs_fsblock_t
+xfs_bmbt_disk_get_startblock(
+	xfs_bmbt_rec_t	*r)
+{
+#if XFS_BIG_FILESYSTEMS
 	return (((xfs_fsblock_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) |
 	       (((xfs_fsblock_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21);
 #else
@@ -1975,10 +2056,10 @@
 }
 
 /*
- * Extract the startoff field from a bmap extent record.
+ * Extract the startoff field from a disk format bmap extent record.
  */
 xfs_fileoff_t
-xfs_bmbt_get_startoff(
+xfs_bmbt_disk_get_startoff(
 	xfs_bmbt_rec_t	*r)
 {
 	return ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) &
@@ -1986,15 +2067,16 @@
 }
 
 xfs_exntst_t
-xfs_bmbt_get_state(
+xfs_bmbt_disk_get_state(
 	xfs_bmbt_rec_t	*r)
 {
 	int	ext_flag;
 
 	ext_flag = (int)((INT_GET(r->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN));
-	return xfs_extent_state(xfs_bmbt_get_blockcount(r),
+	return xfs_extent_state(xfs_bmbt_disk_get_blockcount(r),
 				ext_flag);
 }
+#endif
 
 
 /*
@@ -2103,7 +2185,7 @@
 	XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
 	level = 0;
 	nbno = NULLFSBLOCK;
-	xfs_bmbt_set_all(&nrec, &cur->bc_rec.b);
+	xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b);
 	ncur = (xfs_btree_cur_t *)0;
 	pcur = cur;
 	do {
@@ -2333,7 +2415,7 @@
 	cur->bc_ptrs[level + 1] = 1;
 	kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
 	ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur);
-	bcopy(kp, ckp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*kp));
+	memcpy(ckp, kp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*kp));
 	cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
 #ifdef DEBUG
 	for (i = 0; i < INT_GET(cblock->bb_numrecs, ARCH_CONVERT); i++) {
@@ -2343,7 +2425,7 @@
 		}
 	}
 #endif
-	bcopy(pp, cpp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
+	memcpy(cpp, pp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*pp));
 #ifdef DEBUG
 	if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)args.fsbno,
 			level))) {
@@ -2388,6 +2470,97 @@
 	ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0);
 #endif	/* XFS_BIG_FILESYSTEMS */
 #if XFS_BIG_FILESYSTEMS
+	r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+		 ((xfs_bmbt_rec_base_t)s->br_startoff << 9) |
+		 ((xfs_bmbt_rec_base_t)s->br_startblock >> 43);
+	r->l1 = ((xfs_bmbt_rec_base_t)s->br_startblock << 21) |
+		 ((xfs_bmbt_rec_base_t)s->br_blockcount &
+		 (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+#else	/* !XFS_BIG_FILESYSTEMS */
+	if (ISNULLSTARTBLOCK(s->br_startblock)) {
+		r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+			((xfs_bmbt_rec_base_t)s->br_startoff << 9) |
+			  (xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
+		r->l1 = XFS_MASK64HI(11) |
+			  ((xfs_bmbt_rec_base_t)s->br_startblock << 21) |
+			  ((xfs_bmbt_rec_base_t)s->br_blockcount &
+			   (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+	} else {
+		r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+			((xfs_bmbt_rec_base_t)s->br_startoff << 9);
+		r->l1 = ((xfs_bmbt_rec_base_t)s->br_startblock << 21) |
+			  ((xfs_bmbt_rec_base_t)s->br_blockcount &
+			   (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+	}
+#endif	/* XFS_BIG_FILESYSTEMS */
+}
+
+/*
+ * Set all the fields in a bmap extent record from the arguments.
+ */
+void
+xfs_bmbt_set_allf(
+	xfs_bmbt_rec_t	*r,
+	xfs_fileoff_t	o,
+	xfs_fsblock_t	b,
+	xfs_filblks_t	c,
+	xfs_exntst_t	v)
+{
+	int	extent_flag;
+
+	ASSERT((v == XFS_EXT_NORM) || (v == XFS_EXT_UNWRITTEN));
+	extent_flag = (v == XFS_EXT_NORM) ? 0 : 1;
+	ASSERT((o & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0);
+	ASSERT((c & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0);
+#if XFS_BIG_FILESYSTEMS
+	ASSERT((b & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0);
+#endif	/* XFS_BIG_FILESYSTEMS */
+#if XFS_BIG_FILESYSTEMS
+	r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+		((xfs_bmbt_rec_base_t)o << 9) |
+		((xfs_bmbt_rec_base_t)b >> 43));
+	r->l1 = ((xfs_bmbt_rec_base_t)b << 21) |
+		((xfs_bmbt_rec_base_t)c &
+		(xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
+#else	/* !XFS_BIG_FILESYSTEMS */
+	if (ISNULLSTARTBLOCK(b)) {
+		r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+			((xfs_bmbt_rec_base_t)o << 9) |
+			 (xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
+		r->l1 = XFS_MASK64HI(11) |
+			  ((xfs_bmbt_rec_base_t)b << 21) |
+			  ((xfs_bmbt_rec_base_t)c &
+			   (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+	} else {
+		r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
+			((xfs_bmbt_rec_base_t)o << 9);
+		r->l1 = ((xfs_bmbt_rec_base_t)b << 21) |
+			 ((xfs_bmbt_rec_base_t)c &
+			 (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
+	}
+#endif	/* XFS_BIG_FILESYSTEMS */
+}
+
+#if ARCH_CONVERT != ARCH_NOCONVERT
+/*
+ * Set all the fields in a bmap extent record from the uncompressed form.
+ */
+void
+xfs_bmbt_disk_set_all(
+	xfs_bmbt_rec_t	*r,
+	xfs_bmbt_irec_t *s)
+{
+	int	extent_flag;
+
+	ASSERT((s->br_state == XFS_EXT_NORM) ||
+		(s->br_state == XFS_EXT_UNWRITTEN));
+	extent_flag = (s->br_state == XFS_EXT_NORM) ? 0 : 1;
+	ASSERT((s->br_startoff & XFS_MASK64HI(9)) == 0);
+	ASSERT((s->br_blockcount & XFS_MASK64HI(43)) == 0);
+#if XFS_BIG_FILESYSTEMS
+	ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0);
+#endif	/* XFS_BIG_FILESYSTEMS */
+#if XFS_BIG_FILESYSTEMS
 	INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) |
 		  ((xfs_bmbt_rec_base_t)s->br_startoff << 9) |
 		  ((xfs_bmbt_rec_base_t)s->br_startblock >> 43));
@@ -2414,10 +2587,10 @@
 }
 
 /*
- * Set all the fields in a bmap extent record from the arguments.
+ * Set all the fields in a disk format bmap extent record from the arguments.
  */
 void
-xfs_bmbt_set_allf(
+xfs_bmbt_disk_set_allf(
 	xfs_bmbt_rec_t	*r,
 	xfs_fileoff_t	o,
 	xfs_fsblock_t	b,
@@ -2458,6 +2631,7 @@
 	}
 #endif	/* XFS_BIG_FILESYSTEMS */
 }
+#endif
 
 /*
  * Set the blockcount field in a bmap extent record.
@@ -2468,8 +2642,8 @@
 	xfs_filblks_t	v)
 {
 	ASSERT((v & XFS_MASK64HI(43)) == 0);
-	INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(43)) |
-		  (xfs_bmbt_rec_base_t)(v & XFS_MASK64LO(21)));
+	r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64HI(43)) |
+		  (xfs_bmbt_rec_base_t)(v & XFS_MASK64LO(21));
 }
 
 /*
@@ -2484,20 +2658,20 @@
 	ASSERT((v & XFS_MASK64HI(12)) == 0);
 #endif	/* XFS_BIG_FILESYSTEMS */
 #if XFS_BIG_FILESYSTEMS
-	INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(55)) |
-		  (xfs_bmbt_rec_base_t)(v >> 43));
-	INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)) |
-		  (xfs_bmbt_rec_base_t)(v << 21));
+	r->l0 = (r->l0 & (xfs_bmbt_rec_base_t)XFS_MASK64HI(55)) |
+		  (xfs_bmbt_rec_base_t)(v >> 43);
+	r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)) |
+		  (xfs_bmbt_rec_base_t)(v << 21);
 #else	/* !XFS_BIG_FILESYSTEMS */
 	if (ISNULLSTARTBLOCK(v)) {
-		INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) | (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)));
-		INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK64HI(11) |
+		r->l0 |= (xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
+		r->l1 = (xfs_bmbt_rec_base_t)XFS_MASK64HI(11) |
 			  ((xfs_bmbt_rec_base_t)v << 21) |
-			  (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
+			  (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
 	} else {
-		INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & ~(xfs_bmbt_rec_base_t)XFS_MASK64LO(9)));
-		INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)v << 21) |
-			  (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
+		r->l0 &= ~(xfs_bmbt_rec_base_t)XFS_MASK64LO(9);
+		r->l1 = ((xfs_bmbt_rec_base_t)v << 21) |
+			  (r->l1 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
 	}
 #endif	/* XFS_BIG_FILESYSTEMS */
 }
@@ -2511,9 +2685,9 @@
 	xfs_fileoff_t	v)
 {
 	ASSERT((v & XFS_MASK64HI(9)) == 0);
-	INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t) XFS_MASK64HI(1)) |
+	r->l0 = (r->l0 & (xfs_bmbt_rec_base_t) XFS_MASK64HI(1)) |
 		((xfs_bmbt_rec_base_t)v << 9) |
-		  (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)));
+		  (r->l0 & (xfs_bmbt_rec_base_t)XFS_MASK64LO(9));
 }
 
 /*
@@ -2526,9 +2700,9 @@
 {
 	ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN);
 	if (v == XFS_EXT_NORM)
-		INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN));
+		r->l0 &= XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN);
 	else
-		INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) | XFS_MASK64HI(BMBT_EXNTFLAG_BITLEN));
+		r->l0 |= XFS_MASK64HI(BMBT_EXNTFLAG_BITLEN);
 }
 
 /*
@@ -2559,8 +2733,8 @@
 	fpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);
 	tpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr);
 	dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT);
-	bcopy(fkp, tkp, sizeof(*fkp) * dmxr);
-	bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
+	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
+	memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
 }
 
 /*
@@ -2596,7 +2770,7 @@
 #endif
 	ptr = cur->bc_ptrs[0];
 	rp = XFS_BMAP_REC_IADDR(block, ptr, cur);
-	xfs_bmbt_set_allf(rp, off, bno, len, state);
+	xfs_bmbt_disk_set_allf(rp, off, bno, len, state);
 	xfs_bmbt_log_recs(cur, bp, ptr, ptr);
 	if (ptr > 1) {
 		XFS_BMBT_TRACE_CURSOR(cur, EXIT);
@@ -2618,13 +2792,14 @@
  * Return an error condition (1) if any flags found,
  * otherwise return 0.
  */
+
 int
 xfs_check_nostate_extents(
 	xfs_bmbt_rec_t		*ep,
 	xfs_extnum_t		num)
 {
 	for (; num > 0; num--, ep++) {
-		if (((INT_GET(ep->l0, ARCH_CONVERT)) >>
+		if ((ep->l0 >>
 		     (64 - BMBT_EXNTFLAG_BITLEN)) != 0) {
 			ASSERT(0);
 			return 1;
diff -Nru a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h
--- a/fs/xfs/xfs_bmap_btree.h	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_bmap_btree.h	Tue Oct 15 20:29:17 2002
@@ -509,6 +509,41 @@
 xfs_bmbt_get_state(
 	xfs_bmbt_rec_t	*r);
 
+#if ARCH_CONVERT != ARCH_NOCONVERT
+void
+xfs_bmbt_disk_get_all(
+	xfs_bmbt_rec_t	*r,
+	xfs_bmbt_irec_t *s);
+
+xfs_exntst_t
+xfs_bmbt_disk_get_state(
+	xfs_bmbt_rec_t	*r);
+
+xfs_filblks_t
+xfs_bmbt_disk_get_blockcount(
+	xfs_bmbt_rec_t	*r);
+
+xfs_fsblock_t
+xfs_bmbt_disk_get_startblock(
+	xfs_bmbt_rec_t	*r);
+
+xfs_fileoff_t
+xfs_bmbt_disk_get_startoff(
+	xfs_bmbt_rec_t	*r);
+
+#else
+#define xfs_bmbt_disk_get_all(r, s) \
+	xfs_bmbt_get_all(r, s)
+#define xfs_bmbt_disk_get_state(r) \
+	xfs_bmbt_get_state(r)
+#define xfs_bmbt_disk_get_blockcount(r) \
+	xfs_bmbt_get_blockcount(r)
+#define xfs_bmbt_disk_get_startblock(r) \
+	xfs_bmbt_get_blockcount(r)
+#define xfs_bmbt_disk_get_startoff(r) \
+	xfs_bmbt_get_startoff(r)
+#endif
+
 int
 xfs_bmbt_increment(
 	struct xfs_btree_cur *,
@@ -606,6 +641,26 @@
 xfs_bmbt_set_state(
 	xfs_bmbt_rec_t	*r,
 	xfs_exntst_t	v);
+
+#if ARCH_CONVERT != ARCH_NOCONVERT
+void
+xfs_bmbt_disk_set_all(
+	xfs_bmbt_rec_t	*r,
+	xfs_bmbt_irec_t *s);
+
+void
+xfs_bmbt_disk_set_allf(
+	xfs_bmbt_rec_t	*r,
+	xfs_fileoff_t	o,
+	xfs_fsblock_t	b,
+	xfs_filblks_t	c,
+	xfs_exntst_t	v);
+#else
+#define xfs_bmbt_disk_set_all(r, s) \
+	xfs_bmbt_set_all(r, s)
+#define xfs_bmbt_disk_set_allf(r, 0, b, c, v) \
+	xfs_bmbt_set_allf(r, 0, b, c, v)
+#endif
 
 void
 xfs_bmbt_to_bmdr(
diff -Nru a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
--- a/fs/xfs/xfs_btree.c	Tue Oct 15 20:29:19 2002
+++ b/fs/xfs/xfs_btree.c	Tue Oct 15 20:29:19 2002
@@ -261,9 +261,9 @@
 
 		r1 = ar1;
 		r2 = ar2;
-		ASSERT(xfs_bmbt_get_startoff(r1) +
-		       xfs_bmbt_get_blockcount(r1) <=
-		       xfs_bmbt_get_startoff(r2));
+		ASSERT(xfs_bmbt_disk_get_startoff(r1) +
+		       xfs_bmbt_disk_get_blockcount(r1) <=
+		       xfs_bmbt_disk_get_startoff(r2));
 		break;
 	    }
 	case XFS_BTNUM_INO: {
diff -Nru a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
--- a/fs/xfs/xfs_buf_item.c	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/xfs_buf_item.c	Tue Oct 15 20:29:11 2002
@@ -766,7 +766,7 @@
 	 * to have logged.
 	 */
 	bip->bli_orig = (char *)kmem_alloc(XFS_BUF_COUNT(bp), KM_SLEEP);
-	bcopy(XFS_BUF_PTR(bp), bip->bli_orig, XFS_BUF_COUNT(bp));
+	memcpy(bip->bli_orig, XFS_BUF_PTR(bp), XFS_BUF_COUNT(bp));
 	bip->bli_logged = (char *)kmem_zalloc(XFS_BUF_COUNT(bp) / NBBY, KM_SLEEP);
 #endif
 
diff -Nru a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h
--- a/fs/xfs/xfs_clnt.h	Tue Oct 15 20:29:18 2002
+++ b/fs/xfs/xfs_clnt.h	Tue Oct 15 20:29:18 2002
@@ -112,15 +112,14 @@
 						/* only) */
 #define XFSMNT_NOTSERVER	0x00100000	/* give up being the server */
 						/* (remount only) */
-#define XFSMNT_DMAPI		0x00200000	/* enable dmapi/xdsm */
+#define XFSMNT_32BITINODES	0x00200000	/* restrict inodes to 32
+						 * bits of address space */
 #define XFSMNT_GQUOTA		0x00400000	/* group quota accounting */
 #define XFSMNT_GQUOTAENF	0x00800000	/* group quota limit
 						 * enforcement */
 #define XFSMNT_NOUUID		0x01000000	/* Ignore fs uuid */
-#define XFSMNT_32BITINODES	0x02000000	/* restrict inodes to 32
-						 * bits of address space */
-#define XFSMNT_IRIXSGID		0x04000000	/* Irix-style sgid inheritance */
-#define XFSMNT_NOLOGFLUSH	0x08000000	/* Don't flush for log blocks */
+#define XFSMNT_DMAPI		0x02000000	/* enable dmapi/xdsm */
+#define XFSMNT_NOLOGFLUSH	0x04000000	/* Don't flush for log blocks */
 
 /* Did we get any args for CXFS to consume? */
 #define XFSARGS_FOR_CXFSARR(ap)		\
diff -Nru a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
--- a/fs/xfs/xfs_da_btree.c	Tue Oct 15 20:29:20 2002
+++ b/fs/xfs/xfs_da_btree.c	Tue Oct 15 20:29:20 2002
@@ -360,7 +360,7 @@
 		size = (int)((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] -
 			     (char *)leaf);
 	}
-	bcopy(oldroot, node, size);
+	memcpy(node, oldroot, size);
 	xfs_da_log_buf(tp, bp, 0, size - 1);
 	xfs_da_buf_done(blk1->bp);
 	blk1->bp = bp;
@@ -527,7 +527,7 @@
 			tmp *= (uint)sizeof(xfs_da_node_entry_t);
 			btree_s = &node2->btree[0];
 			btree_d = &node2->btree[count];
-			ovbcopy(btree_s, btree_d, tmp);
+			memmove(btree_d, btree_s, tmp);
 		}
 
 		/*
@@ -538,7 +538,7 @@
 		tmp = count * (uint)sizeof(xfs_da_node_entry_t);
 		btree_s = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT) - count];
 		btree_d = &node2->btree[0];
-		bcopy(btree_s, btree_d, tmp);
+		memcpy(btree_d, btree_s, tmp);
 		INT_MOD(node1->hdr.count, ARCH_CONVERT, -(count));
 
 	} else {
@@ -550,7 +550,7 @@
 		tmp = count * (uint)sizeof(xfs_da_node_entry_t);
 		btree_s = &node2->btree[0];
 		btree_d = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT)];
-		bcopy(btree_s, btree_d, tmp);
+		memcpy(btree_d, btree_s, tmp);
 		INT_MOD(node1->hdr.count, ARCH_CONVERT, count);
 		xfs_da_log_buf(tp, blk1->bp,
 			XFS_DA_LOGRANGE(node1, btree_d, tmp));
@@ -562,7 +562,7 @@
 		tmp *= (uint)sizeof(xfs_da_node_entry_t);
 		btree_s = &node2->btree[count];
 		btree_d = &node2->btree[0];
-		ovbcopy(btree_s, btree_d, tmp);
+		memmove(btree_d, btree_s, tmp);
 		INT_MOD(node2->hdr.count, ARCH_CONVERT, -(count));
 	}
 
@@ -622,7 +622,7 @@
 	btree = &node->btree[ oldblk->index ];
 	if (oldblk->index < INT_GET(node->hdr.count, ARCH_CONVERT)) {
 		tmp = (INT_GET(node->hdr.count, ARCH_CONVERT) - oldblk->index) * (uint)sizeof(*btree);
-		ovbcopy(btree, btree + 1, tmp);
+		memmove(btree + 1, btree, tmp);
 	}
 	INT_SET(btree->hashval, ARCH_CONVERT, newblk->hashval);
 	INT_SET(btree->before, ARCH_CONVERT, newblk->blkno);
@@ -790,7 +790,7 @@
 	}
 	ASSERT(INT_ISZERO(blkinfo->forw, ARCH_CONVERT));
 	ASSERT(INT_ISZERO(blkinfo->back, ARCH_CONVERT));
-	bcopy(bp->data, root_blk->bp->data, state->blocksize);
+	memcpy(root_blk->bp->data, bp->data, state->blocksize);
 	xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1);
 	error = xfs_da_shrink_inode(args, child, bp);
 	return(error);
@@ -842,7 +842,7 @@
 		 * path point to the block we want to drop (this one).
 		 */
 		forward = (!INT_ISZERO(info->forw, ARCH_CONVERT));
-		bcopy(&state->path, &state->altpath, sizeof(state->path));
+		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
 		if (error)
@@ -898,7 +898,7 @@
 	 * Make altpath point to the block we want to keep (the lower
 	 * numbered block) and path point to the block we want to drop.
 	 */
-	bcopy(&state->path, &state->altpath, sizeof(state->path));
+	memcpy(&state->altpath, &state->path, sizeof(state->path));
 	if (blkno < blk->blkno) {
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -1001,12 +1001,12 @@
 	if (drop_blk->index < (INT_GET(node->hdr.count, ARCH_CONVERT)-1)) {
 		tmp  = INT_GET(node->hdr.count, ARCH_CONVERT) - drop_blk->index - 1;
 		tmp *= (uint)sizeof(xfs_da_node_entry_t);
-		ovbcopy(btree + 1, btree, tmp);
+		memmove(btree, btree + 1, tmp);
 		xfs_da_log_buf(state->args->trans, drop_blk->bp,
 		    XFS_DA_LOGRANGE(node, btree, tmp));
 		btree = &node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ];
 	}
-	bzero((char *)btree, sizeof(xfs_da_node_entry_t));
+	memset((char *)btree, 0, sizeof(xfs_da_node_entry_t));
 	xfs_da_log_buf(state->args->trans, drop_blk->bp,
 	    XFS_DA_LOGRANGE(node, btree, sizeof(*btree)));
 	INT_MOD(node->hdr.count, ARCH_CONVERT, -1);
@@ -1049,7 +1049,7 @@
 	{
 		btree = &save_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT) ];
 		tmp = INT_GET(save_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t);
-		ovbcopy(&save_node->btree[0], btree, tmp);
+		memmove(btree, &save_node->btree[0], tmp);
 		btree = &save_node->btree[0];
 		xfs_da_log_buf(tp, save_blk->bp,
 			XFS_DA_LOGRANGE(save_node, btree,
@@ -1067,7 +1067,7 @@
 	 * Move all the B-tree elements from drop_blk to save_blk.
 	 */
 	tmp = INT_GET(drop_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t);
-	bcopy(&drop_node->btree[0], btree, tmp);
+	memcpy(btree, &drop_node->btree[0], tmp);
 	INT_MOD(save_node->hdr.count, ARCH_CONVERT, INT_GET(drop_node->hdr.count, ARCH_CONVERT));
 
 	xfs_da_log_buf(tp, save_blk->bp,
@@ -1798,7 +1798,7 @@
 	/*
 	 * Copy the last block into the dead buffer and log it.
 	 */
-	bcopy(last_buf->data, dead_buf->data, mp->m_dirblksize);
+	memcpy(dead_buf->data, last_buf->data, mp->m_dirblksize);
 	xfs_da_log_buf(tp, dead_buf, 0, mp->m_dirblksize - 1);
 	dead_info = dead_buf->data;
 	/*
@@ -2343,7 +2343,7 @@
 	if (state->extravalid && state->extrablk.bp)
 		xfs_da_buf_done(state->extrablk.bp);
 #ifdef DEBUG
-	bzero((char *)state, sizeof(*state));
+	memset((char *)state, 0, sizeof(*state));
 #endif /* DEBUG */
 	kmem_zone_free(xfs_da_state_zone, state);
 }
@@ -2390,7 +2390,7 @@
 		dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP);
 		for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) {
 			bp = bps[i];
-			bcopy(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
+			memcpy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
 				XFS_BUF_COUNT(bp));
 		}
 	}
@@ -2431,7 +2431,7 @@
 		for (i = off = 0; i < dabuf->nbuf;
 				i++, off += XFS_BUF_COUNT(bp)) {
 			bp = dabuf->bps[i];
-			bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
+			memcpy(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
 				XFS_BUF_COUNT(bp));
 		}
 	}
@@ -2462,7 +2462,7 @@
 			dabuf->next->prev = dabuf->prev;
 		mutex_spinunlock(&xfs_dabuf_global_lock, s);
 	}
-	bzero(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf));
+	memset(dabuf, 0, XFS_DA_BUF_SIZE(dabuf->nbuf));
 #endif
 	if (dabuf->nbuf == 1)
 		kmem_zone_free(xfs_dabuf_zone, dabuf);
@@ -2532,7 +2532,7 @@
 		bp = dabuf->bps[0];
 	} else {
 		bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP);
-		bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist));
+		memcpy(bplist, dabuf->bps, nbuf * sizeof(*bplist));
 	}
 	xfs_da_buf_done(dabuf);
 	for (i = 0; i < nbuf; i++)
@@ -2558,7 +2558,7 @@
 		bp = dabuf->bps[0];
 	} else {
 		bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP);
-		bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist));
+		memcpy(bplist, dabuf->bps, nbuf * sizeof(*bplist));
 	}
 	xfs_da_buf_done(dabuf);
 	for (i = 0; i < nbuf; i++)
diff -Nru a/fs/xfs/xfs_dir.c b/fs/xfs/xfs_dir.c
--- a/fs/xfs/xfs_dir.c	Tue Oct 15 20:29:13 2002
+++ b/fs/xfs/xfs_dir.c	Tue Oct 15 20:29:13 2002
@@ -210,7 +210,7 @@
 	xfs_da_args_t args;
 	int error;
 
-	bzero((char *)&args, sizeof(args));
+	memset((char *)&args, 0, sizeof(args));
 	args.dp = dir;
 	args.trans = trans;
 
@@ -534,7 +534,7 @@
 		return 0;
 	}
 	if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) {
-		xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p\n",
+		xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p",
 			dp);
 		return 1;
 	}
@@ -546,7 +546,7 @@
 	count = sf->hdr.count;
 	if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) {
 		xfs_fs_cmn_err(CE_WARN, mp,
-			"Invalid shortform count: dp 0x%p\n", dp);
+			"Invalid shortform count: dp 0x%p", dp);
 		return(1);
 	}
 
@@ -561,7 +561,7 @@
 		xfs_dir_ino_validate(mp, ino);
 		if (sfe->namelen >= XFS_LITINO(mp)) {
 			xfs_fs_cmn_err(CE_WARN, mp,
-				"Invalid shortform namelen: dp 0x%p\n", dp);
+				"Invalid shortform namelen: dp 0x%p", dp);
 			return 1;
 		}
 		namelen_sum += sfe->namelen;
@@ -569,7 +569,7 @@
 	}
 	if (namelen_sum >= XFS_LITINO(mp)) {
 		xfs_fs_cmn_err(CE_WARN, mp,
-			"Invalid shortform namelen: dp 0x%p\n", dp);
+			"Invalid shortform namelen: dp 0x%p", dp);
 		return 1;
 	}
 
diff -Nru a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
--- a/fs/xfs/xfs_dir2.c	Tue Oct 15 20:29:23 2002
+++ b/fs/xfs/xfs_dir2.c	Tue Oct 15 20:29:23 2002
@@ -147,7 +147,7 @@
 	xfs_da_args_t	args;		/* operation arguments */
 	int		error;		/* error return value */
 
-	bzero((char *)&args, sizeof(args));
+	memset((char *)&args, 0, sizeof(args));
 	args.dp = dp;
 	args.trans = tp;
 	ASSERT((dp->i_d.di_mode & IFMT) == IFDIR);
@@ -711,7 +711,7 @@
 	idbp->d_off = pa->cook;
 	idbp->d_name[namelen] = '\0';
 	pa->done = 1;
-	bcopy(pa->name, idbp->d_name, namelen);
+	memcpy(idbp->d_name, pa->name, namelen);
 	return 0;
 }
 
@@ -743,7 +743,7 @@
 	idbp->d_ino = pa->ino;
 	idbp->d_off = pa->cook;
 	idbp->d_name[namelen] = '\0';
-	bcopy(pa->name, idbp->d_name, namelen);
+	memcpy(idbp->d_name, pa->name, namelen);
 	rval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio);
 	pa->done = (rval == 0);
 	return rval;
diff -Nru a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
--- a/fs/xfs/xfs_dir2_block.c	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/xfs_dir2_block.c	Tue Oct 15 20:29:12 2002
@@ -331,7 +331,7 @@
 		blp--;
 		mid++;
 		if (mid)
-			ovbcopy(&blp[1], blp, mid * sizeof(*blp));
+			memmove(blp, &blp[1], mid * sizeof(*blp));
 		lfloglow = 0;
 		lfloghigh = mid;
 	}
@@ -357,7 +357,7 @@
 		    (highstale == INT_GET(btp->count, ARCH_CONVERT) ||
 		     mid - lowstale <= highstale - mid)) {
 			if (mid - lowstale)
-				ovbcopy(&blp[lowstale + 1], &blp[lowstale],
+				memmove(&blp[lowstale], &blp[lowstale + 1],
 					(mid - lowstale) * sizeof(*blp));
 			lfloglow = MIN(lowstale, lfloglow);
 			lfloghigh = MAX(mid, lfloghigh);
@@ -369,7 +369,7 @@
 			ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT));
 			mid++;
 			if (highstale - mid)
-				ovbcopy(&blp[mid], &blp[mid + 1],
+				memmove(&blp[mid + 1], &blp[mid],
 					(highstale - mid) * sizeof(*blp));
 			lfloglow = MIN(mid, lfloglow);
 			lfloghigh = MAX(highstale, lfloghigh);
@@ -397,7 +397,7 @@
 	 */
 	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
 	dep->namelen = args->namelen;
-	bcopy(args->name, dep->name, args->namelen);
+	memcpy(dep->name, args->name, args->namelen);
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
 	INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
 	/*
@@ -717,7 +717,7 @@
 		 */
 		if (dep->namelen == args->namelen &&
 		    dep->name[0] == args->name[0] &&
-		    bcmp(dep->name, args->name, args->namelen) == 0) {
+		    memcmp(dep->name, args->name, args->namelen) == 0) {
 			*bpp = bp;
 			*entno = mid;
 			return 0;
@@ -1075,7 +1075,7 @@
 	buf_len = dp->i_df.if_bytes;
 	buf = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP);
 
-	bcopy(sfp, buf, dp->i_df.if_bytes);
+	memcpy(buf, sfp, dp->i_df.if_bytes);
 	xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK);
 	dp->i_d.di_size = 0;
 	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
@@ -1199,7 +1199,7 @@
 		INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
 				XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT));
 		dep->namelen = sfep->namelen;
-		bcopy(sfep->name, dep->name, dep->namelen);
+		memcpy(dep->name, sfep->name, dep->namelen);
 		tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
 		INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
 		xfs_dir2_data_log_entry(tp, bp, dep);
diff -Nru a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
--- a/fs/xfs/xfs_dir2_data.c	Tue Oct 15 20:29:21 2002
+++ b/fs/xfs/xfs_dir2_data.c	Tue Oct 15 20:29:21 2002
@@ -340,7 +340,7 @@
 	/*
 	 * Start by clearing the table.
 	 */
-	bzero(d->hdr.bestfree, sizeof(d->hdr.bestfree));
+	memset(d->hdr.bestfree, 0, sizeof(d->hdr.bestfree));
 	*loghead = 1;
 	/*
 	 * Set up pointers.
diff -Nru a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
--- a/fs/xfs/xfs_dir2_leaf.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/xfs_dir2_leaf.c	Tue Oct 15 20:29:16 2002
@@ -110,7 +110,7 @@
 	 * Could compact these but I think we always do the conversion
 	 * after squeezing out stale entries.
 	 */
-	bcopy(blp, leaf->ents, INT_GET(btp->count, ARCH_CONVERT) * sizeof(xfs_dir2_leaf_entry_t));
+	memcpy(leaf->ents, blp, INT_GET(btp->count, ARCH_CONVERT) * sizeof(xfs_dir2_leaf_entry_t));
 	xfs_dir2_leaf_log_ents(tp, lbp, 0, INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1);
 	needscan = 0;
 	needlog = 1;
@@ -353,7 +353,7 @@
 		 */
 		if (use_block >= INT_GET(ltp->bestcount, ARCH_CONVERT)) {
 			bestsp--;
-			ovbcopy(&bestsp[1], &bestsp[0],
+			memmove(&bestsp[0], &bestsp[1],
 				INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(bestsp[0]));
 			INT_MOD(ltp->bestcount, ARCH_CONVERT, +1);
 			xfs_dir2_leaf_log_tail(tp, lbp);
@@ -402,7 +402,7 @@
 	dep = (xfs_dir2_data_entry_t *)dup;
 	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
 	dep->namelen = args->namelen;
-	bcopy(args->name, dep->name, dep->namelen);
+	memcpy(dep->name, args->name, dep->namelen);
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
 	INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data));
 	/*
@@ -434,7 +434,7 @@
 		 * lep is still good as the index leaf entry.
 		 */
 		if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT))
-			ovbcopy(lep, lep + 1,
+			memmove(lep + 1, lep,
 				(INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep));
 		/*
 		 * Record low and high logging indices for the leaf.
@@ -493,8 +493,8 @@
 			 * and make room for the new entry.
 			 */
 			if (index - lowstale - 1 > 0)
-				ovbcopy(&leaf->ents[lowstale + 1],
-					&leaf->ents[lowstale],
+				memmove(&leaf->ents[lowstale],
+					&leaf->ents[lowstale + 1],
 					(index - lowstale - 1) * sizeof(*lep));
 			lep = &leaf->ents[index - 1];
 			lfloglow = MIN(lowstale, lfloglow);
@@ -512,8 +512,8 @@
 			 * and make room for the new entry.
 			 */
 			if (highstale - index > 0)
-				ovbcopy(&leaf->ents[index],
-					&leaf->ents[index + 1],
+				memmove(&leaf->ents[index + 1],
+					&leaf->ents[index],
 					(highstale - index) * sizeof(*lep));
 			lep = &leaf->ents[index];
 			lfloglow = MIN(index, lfloglow);
@@ -847,7 +847,7 @@
 					 * the table.
 					 */
 					if (!map->br_blockcount && --map_valid)
-						ovbcopy(&map[1], &map[0],
+						memmove(&map[0], &map[1],
 							sizeof(map[0]) *
 							map_valid);
 					i -= j;
@@ -909,8 +909,8 @@
 						nmap--;
 						length = map_valid + nmap - i;
 						if (length)
-							ovbcopy(&map[i + 1],
-								&map[i],
+							memmove(&map[i],
+								&map[i + 1],
 								sizeof(map[i]) *
 								length);
 					} else {
@@ -1409,7 +1409,7 @@
 		 */
 		if (dep->namelen == args->namelen &&
 		    dep->name[0] == args->name[0] &&
-		    bcmp(dep->name, args->name, args->namelen) == 0) {
+		    memcmp(dep->name, args->name, args->namelen) == 0) {
 			*dbpp = dbp;
 			*indexp = index;
 			return 0;
@@ -1544,7 +1544,7 @@
 			 * Copy the table down so inactive entries at the
 			 * end are removed.
 			 */
-			ovbcopy(bestsp, &bestsp[db - i],
+			memmove(&bestsp[db - i], bestsp,
 				(INT_GET(ltp->bestcount, ARCH_CONVERT) - (db - i)) * sizeof(*bestsp));
 			INT_MOD(ltp->bestcount, ARCH_CONVERT, -(db - i));
 			xfs_dir2_leaf_log_tail(tp, lbp);
@@ -1728,7 +1728,7 @@
 	 */
 	bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
 	INT_MOD(ltp->bestcount, ARCH_CONVERT, -1);
-	ovbcopy(&bestsp[0], &bestsp[1], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp));
+	memmove(&bestsp[1], &bestsp[0], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp));
 	xfs_dir2_leaf_log_tail(tp, lbp);
 	xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
 	return 0;
@@ -1842,7 +1842,7 @@
 	/*
 	 * Set up the leaf bests table.
 	 */
-	bcopy(free->bests, XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT),
+	memcpy(XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), free->bests,
 		INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(leaf->bests[0]));
 	xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1);
 	xfs_dir2_leaf_log_tail(tp, lbp);
diff -Nru a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
--- a/fs/xfs/xfs_dir2_node.c	Tue Oct 15 20:29:10 2002
+++ b/fs/xfs/xfs_dir2_node.c	Tue Oct 15 20:29:10 2002
@@ -239,7 +239,7 @@
 	if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) {
 		lep = &leaf->ents[index];
 		if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT))
-			ovbcopy(lep, lep + 1,
+			memmove(lep + 1, lep,
 				(INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep));
 		lfloglow = index;
 		lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT);
@@ -288,8 +288,8 @@
 			       XFS_DIR2_NULL_DATAPTR);
 			ASSERT(index - lowstale - 1 >= 0);
 			if (index - lowstale - 1 > 0)
-				ovbcopy(&leaf->ents[lowstale + 1],
-					&leaf->ents[lowstale],
+				memmove(&leaf->ents[lowstale],
+					&leaf->ents[lowstale + 1],
 					(index - lowstale - 1) * sizeof(*lep));
 			lep = &leaf->ents[index - 1];
 			lfloglow = MIN(lowstale, lfloglow);
@@ -304,8 +304,8 @@
 			       XFS_DIR2_NULL_DATAPTR);
 			ASSERT(highstale - index >= 0);
 			if (highstale - index > 0)
-				ovbcopy(&leaf->ents[index],
-					&leaf->ents[index + 1],
+				memmove(&leaf->ents[index + 1],
+					&leaf->ents[index],
 					(highstale - index) * sizeof(*lep));
 			lep = &leaf->ents[index];
 			lfloglow = MIN(index, lfloglow);
@@ -564,7 +564,7 @@
 			 */
 			if (dep->namelen == args->namelen &&
 			    dep->name[0] == args->name[0] &&
-			    bcmp(dep->name, args->name, args->namelen) == 0) {
+			    memcmp(dep->name, args->name, args->namelen) == 0) {
 				args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
 				*indexp = index;
 				state->extravalid = 1;
@@ -644,7 +644,7 @@
 	 * to hold the new entries.
 	 */
 	if (start_d < INT_GET(leaf_d->hdr.count, ARCH_CONVERT)) {
-		ovbcopy(&leaf_d->ents[start_d], &leaf_d->ents[start_d + count],
+		memmove(&leaf_d->ents[start_d + count], &leaf_d->ents[start_d],
 			(INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - start_d) *
 			sizeof(xfs_dir2_leaf_entry_t));
 		xfs_dir2_leaf_log_ents(tp, bp_d, start_d + count,
@@ -666,7 +666,7 @@
 	/*
 	 * Copy the leaf entries from source to destination.
 	 */
-	bcopy(&leaf_s->ents[start_s], &leaf_d->ents[start_d],
+	memcpy(&leaf_d->ents[start_d], &leaf_s->ents[start_s],
 		count * sizeof(xfs_dir2_leaf_entry_t));
 	xfs_dir2_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1);
 	/*
@@ -674,7 +674,7 @@
 	 * delete the ones we copied by sliding the next ones down.
 	 */
 	if (start_s + count < INT_GET(leaf_s->hdr.count, ARCH_CONVERT)) {
-		ovbcopy(&leaf_s->ents[start_s + count], &leaf_s->ents[start_s],
+		memmove(&leaf_s->ents[start_s], &leaf_s->ents[start_s + count],
 			count * sizeof(xfs_dir2_leaf_entry_t));
 		xfs_dir2_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1);
 	}
@@ -1135,7 +1135,7 @@
 		 * path point to the block we want to drop (this one).
 		 */
 		forward = !INT_ISZERO(info->forw, ARCH_CONVERT);
-		bcopy(&state->path, &state->altpath, sizeof(state->path));
+		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward, 0,
 			&rval);
 		if (error)
@@ -1197,7 +1197,7 @@
 	 * Make altpath point to the block we want to keep (the lower
 	 * numbered block) and path point to the block we want to drop.
 	 */
-	bcopy(&state->path, &state->altpath, sizeof(state->path));
+	memcpy(&state->altpath, &state->path, sizeof(state->path));
 	if (blkno < blk->blkno)
 		error = xfs_da_path_shift(state, &state->altpath, forward, 0,
 			&rval);
@@ -1685,7 +1685,7 @@
 	dep = (xfs_dir2_data_entry_t *)dup;
 	INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
 	dep->namelen = args->namelen;
-	bcopy(args->name, dep->name, dep->namelen);
+	memcpy(dep->name, args->name, dep->namelen);
 	tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
 	INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data));
 	xfs_dir2_data_log_entry(tp, dbp, dep);
diff -Nru a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
--- a/fs/xfs/xfs_dir2_sf.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_dir2_sf.c	Tue Oct 15 20:29:17 2002
@@ -176,7 +176,7 @@
 	 * and add local data.
 	 */
 	block = kmem_alloc(mp->m_dirblksize, KM_SLEEP);
-	bcopy(bp->data, block, mp->m_dirblksize);
+	memcpy(block, bp->data, mp->m_dirblksize);
 	logflags = XFS_ILOG_CORE;
 	if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) {
 		ASSERT(error != ENOSPC);
@@ -198,7 +198,7 @@
 	 * Copy the header into the newly allocate local space.
 	 */
 	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
-	bcopy(sfhp, sfp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count));
+	memcpy(sfp, sfhp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count));
 	dp->i_d.di_size = size;
 	/*
 	 * Set up to loop over the block's entries.
@@ -241,7 +241,7 @@
 			XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,
 				(xfs_dir2_data_aoff_t)
 				((char *)dep - (char *)block), ARCH_CONVERT);
-			bcopy(dep->name, sfep->name, dep->namelen);
+			memcpy(sfep->name, dep->name, dep->namelen);
 			temp=INT_GET(dep->inumber, ARCH_CONVERT);
 			XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &temp,
 				XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
@@ -405,7 +405,7 @@
 	 */
 	sfep->namelen = args->namelen;
 	XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT);
-	bcopy(args->name, sfep->name, sfep->namelen);
+	memcpy(sfep->name, args->name, sfep->namelen);
 	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber,
 		XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
 	/*
@@ -457,7 +457,7 @@
 	old_isize = (int)dp->i_d.di_size;
 	buf = kmem_alloc(old_isize, KM_SLEEP);
 	oldsfp = (xfs_dir2_sf_t *)buf;
-	bcopy(sfp, oldsfp, old_isize);
+	memcpy(oldsfp, sfp, old_isize);
 	/*
 	 * Loop over the old directory finding the place we're going
 	 * to insert the new entry.
@@ -490,14 +490,14 @@
 	 * Copy the first part of the directory, including the header.
 	 */
 	nbytes = (int)((char *)oldsfep - (char *)oldsfp);
-	bcopy(oldsfp, sfp, nbytes);
+	memcpy(sfp, oldsfp, nbytes);
 	sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes);
 	/*
 	 * Fill in the new entry, and update the header counts.
 	 */
 	sfep->namelen = args->namelen;
 	XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT);
-	bcopy(args->name, sfep->name, sfep->namelen);
+	memcpy(sfep->name, args->name, sfep->namelen);
 	XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber,
 		XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
 	sfp->hdr.count++;
@@ -510,7 +510,7 @@
 	 */
 	if (!eof) {
 		sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
-		bcopy(oldsfep, sfep, old_isize - nbytes);
+		memcpy(sfep, oldsfep, old_isize - nbytes);
 	}
 	kmem_free(buf, old_isize);
 	dp->i_d.di_size = new_isize;
@@ -916,7 +916,7 @@
 	     i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
 		if (sfep->namelen == args->namelen &&
 		    sfep->name[0] == args->name[0] &&
-		    bcmp(args->name, sfep->name, args->namelen) == 0) {
+		    memcmp(args->name, sfep->name, args->namelen) == 0) {
 			args->inumber =
 				XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
 					XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
@@ -971,7 +971,7 @@
 	     i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
 		if (sfep->namelen == args->namelen &&
 		    sfep->name[0] == args->name[0] &&
-		    bcmp(sfep->name, args->name, args->namelen) == 0) {
+		    memcmp(sfep->name, args->name, args->namelen) == 0) {
 			ASSERT(XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
 					XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT) ==
 				args->inumber);
@@ -994,7 +994,7 @@
 	 * Copy the part if any after the removed entry, sliding it down.
 	 */
 	if (byteoff + entsize < oldsize)
-		ovbcopy((char *)sfp + byteoff + entsize, (char *)sfp + byteoff,
+		memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize,
 			oldsize - (byteoff + entsize));
 	/*
 	 * Fix up the header and file size.
@@ -1108,7 +1108,7 @@
 		     i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
 			if (sfep->namelen == args->namelen &&
 			    sfep->name[0] == args->name[0] &&
-			    bcmp(args->name, sfep->name, args->namelen) == 0) {
+			    memcmp(args->name, sfep->name, args->namelen) == 0) {
 #if XFS_BIG_FILESYSTEMS || defined(DEBUG)
 				ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp,
 					XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
@@ -1196,7 +1196,7 @@
 	buf = kmem_alloc(oldsize, KM_SLEEP);
 	oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
 	ASSERT(oldsfp->hdr.i8count == 1);
-	bcopy(oldsfp, buf, oldsize);
+	memcpy(buf, oldsfp, oldsize);
 	/*
 	 * Compute the new inode size.
 	 */
@@ -1228,7 +1228,7 @@
 		  oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) {
 		sfep->namelen = oldsfep->namelen;
 		sfep->offset = oldsfep->offset;
-		bcopy(oldsfep->name, sfep->name, sfep->namelen);
+		memcpy(sfep->name, oldsfep->name, sfep->namelen);
 		ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp,
 			XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT);
 		XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
@@ -1273,7 +1273,7 @@
 	buf = kmem_alloc(oldsize, KM_SLEEP);
 	oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
 	ASSERT(oldsfp->hdr.i8count == 0);
-	bcopy(oldsfp, buf, oldsize);
+	memcpy(buf, oldsfp, oldsize);
 	/*
 	 * Compute the new inode size.
 	 */
@@ -1305,7 +1305,7 @@
 		  oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) {
 		sfep->namelen = oldsfep->namelen;
 		sfep->offset = oldsfep->offset;
-		bcopy(oldsfep->name, sfep->name, sfep->namelen);
+		memcpy(sfep->name, oldsfep->name, sfep->namelen);
 		ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp,
 			XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT);
 		XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
diff -Nru a/fs/xfs/xfs_dir2_sf.h b/fs/xfs/xfs_dir2_sf.h
--- a/fs/xfs/xfs_dir2_sf.h	Tue Oct 15 20:29:12 2002
+++ b/fs/xfs/xfs_dir2_sf.h	Tue Oct 15 20:29:12 2002
@@ -93,7 +93,7 @@
  * be calculated on the fly.
  *
  * Entries are packed toward the top as tightly as possible.  The header
- * and the elements must be bcopy()'d out into a work area to get correct
+ * and the elements must be memcpy'd out into a work area to get correct
  * alignment for the inode number fields.
  */
 typedef struct xfs_dir2_sf_hdr {
diff -Nru a/fs/xfs/xfs_dir2_trace.c b/fs/xfs/xfs_dir2_trace.c
--- a/fs/xfs/xfs_dir2_trace.c	Tue Oct 15 20:29:14 2002
+++ b/fs/xfs/xfs_dir2_trace.c	Tue Oct 15 20:29:14 2002
@@ -65,9 +65,9 @@
 	ASSERT(xfs_dir2_trace_buf);
 	ASSERT(dp->i_dir_trace);
 	if (name)
-		bcopy(name, n, min(sizeof(n), namelen));
+		memcpy(n, name, min(sizeof(n), namelen));
 	else
-		bzero((char *)n, sizeof(n));
+		memset((char *)n, 0, sizeof(n));
 	ktrace_enter(xfs_dir2_trace_buf,
 		(void *)(__psunsigned_t)type, (void *)where,
 		(void *)a0, (void *)a1, (void *)a2, (void *)a3,
diff -Nru a/fs/xfs/xfs_dir_leaf.c b/fs/xfs/xfs_dir_leaf.c
--- a/fs/xfs/xfs_dir_leaf.c	Tue Oct 15 20:29:21 2002
+++ b/fs/xfs/xfs_dir_leaf.c	Tue Oct 15 20:29:21 2002
@@ -105,7 +105,7 @@
 		XFS_AGINO_TO_INO(mp, agno, agino) == ino;
 	if (XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
 			XFS_RANDOM_DIR_INO_VALIDATE)) {
-		xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx\n",
+		xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx",
 				(unsigned long long) ino);
 		return XFS_ERROR(EFSCORRUPTED);
 	}
@@ -171,7 +171,7 @@
 	for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
 		if (sfe->namelen == args->namelen &&
 		    args->name[0] == sfe->name[0] &&
-		    bcmp(args->name, sfe->name, args->namelen) == 0)
+		    memcmp(args->name, sfe->name, args->namelen) == 0)
 			return(XFS_ERROR(EEXIST));
 		sfe = XFS_DIR_SF_NEXTENTRY(sfe);
 	}
@@ -184,7 +184,7 @@
 
 	XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT);
 	sfe->namelen = args->namelen;
-	bcopy(args->name, sfe->name, sfe->namelen);
+	memcpy(sfe->name, args->name, sfe->namelen);
 	INT_MOD(sf->hdr.count, ARCH_CONVERT, +1);
 
 	dp->i_d.di_size += size;
@@ -223,7 +223,7 @@
 		size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe);
 		if (sfe->namelen == args->namelen &&
 		    sfe->name[0] == args->name[0] &&
-		    bcmp(sfe->name, args->name, args->namelen) == 0)
+		    memcmp(sfe->name, args->name, args->namelen) == 0)
 			break;
 		base += size;
 		sfe = XFS_DIR_SF_NEXTENTRY(sfe);
@@ -234,7 +234,7 @@
 	}
 
 	if ((base + size) != dp->i_d.di_size) {
-		ovbcopy(&((char *)sf)[base+size], &((char *)sf)[base],
+		memmove(&((char *)sf)[base], &((char *)sf)[base+size],
 					      dp->i_d.di_size - (base+size));
 	}
 	INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
@@ -283,7 +283,7 @@
 	for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
 		if (sfe->namelen == args->namelen &&
 		    sfe->name[0] == args->name[0] &&
-		    bcmp(args->name, sfe->name, args->namelen) == 0) {
+		    memcmp(args->name, sfe->name, args->namelen) == 0) {
 			XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args->inumber, ARCH_CONVERT);
 			return(XFS_ERROR(EEXIST));
 		}
@@ -324,7 +324,7 @@
 	tmpbuffer = kmem_alloc(size, KM_SLEEP);
 	ASSERT(tmpbuffer != NULL);
 
-	bcopy(dp->i_df.if_u1.if_data, tmpbuffer, size);
+	memcpy(tmpbuffer, dp->i_df.if_u1.if_data, size);
 
 	sf = (xfs_dir_shortform_t *)tmpbuffer;
 	XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &inumber, ARCH_CONVERT);
@@ -611,8 +611,8 @@
 	for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) {
 		if (sfe->namelen == args->namelen &&
 		    sfe->name[0] == args->name[0] &&
-		    bcmp(args->name, sfe->name, args->namelen) == 0) {
-			ASSERT(bcmp((char *)&args->inumber,
+		    memcmp(args->name, sfe->name, args->namelen) == 0) {
+			ASSERT(memcmp((char *)&args->inumber,
 				(char *)&sfe->inumber, sizeof(xfs_ino_t)));
 			XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT);
 			xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA);
@@ -650,10 +650,10 @@
 	if (retval)
 		return(retval);
 	ASSERT(bp != NULL);
-	bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount));
+	memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
 	leaf = (xfs_dir_leafblock_t *)tmpbuffer;
 	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
-	bzero(bp->data, XFS_LBSIZE(dp->i_mount));
+	memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
 
 	/*
 	 * Find and special case the parent inode number
@@ -736,7 +736,7 @@
 		return(retval);
 	}
 	ASSERT(bp2 != NULL);
-	bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount));
+	memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));
 	xfs_da_buf_done(bp1);
 	xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
 
@@ -787,7 +787,7 @@
 		return(retval);
 	ASSERT(bp != NULL);
 	leaf = bp->data;
-	bzero((char *)leaf, XFS_LBSIZE(dp->i_mount));
+	memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
 	hdr = &leaf->hdr;
 	INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_DIR_LEAF_MAGIC);
 	INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
@@ -960,7 +960,7 @@
 	if (index < INT_GET(hdr->count, ARCH_CONVERT)) {
 		tmp  = INT_GET(hdr->count, ARCH_CONVERT) - index;
 		tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
-		ovbcopy(entry, entry + 1, tmp);
+		memmove(entry + 1, entry, tmp);
 		xfs_da_log_buf(args->trans, bp,
 		    XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
 	}
@@ -986,7 +986,7 @@
 	 */
 	namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
 	XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &namest->inumber, ARCH_CONVERT);
-	bcopy(args->name, namest->name, args->namelen);
+	memcpy(namest->name, args->name, args->namelen);
 	xfs_da_log_buf(args->trans, bp,
 	    XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry)));
 
@@ -1029,7 +1029,7 @@
 	lbsize = XFS_LBSIZE(mp);
 	tmpbuffer = kmem_alloc(lbsize, KM_SLEEP);
 	ASSERT(tmpbuffer != NULL);
-	bcopy(bp->data, tmpbuffer, lbsize);
+	memcpy(tmpbuffer, bp->data, lbsize);
 
 	/*
 	 * Make a second copy in case xfs_dir_leaf_moveents()
@@ -1037,9 +1037,9 @@
 	 */
 	if (musthave || justcheck) {
 		tmpbuffer2 = kmem_alloc(lbsize, KM_SLEEP);
-		bcopy(bp->data, tmpbuffer2, lbsize);
+		memcpy(tmpbuffer2, bp->data, lbsize);
 	}
-	bzero(bp->data, lbsize);
+	memset(bp->data, 0, lbsize);
 
 	/*
 	 * Copy basic information
@@ -1072,7 +1072,7 @@
 
 	if (justcheck || rval == ENOSPC) {
 		ASSERT(tmpbuffer2);
-		bcopy(tmpbuffer2, bp->data, lbsize);
+		memcpy(bp->data, tmpbuffer2, lbsize);
 	} else {
 		xfs_da_log_buf(trans, bp, 0, lbsize - 1);
 	}
@@ -1357,7 +1357,7 @@
 		 * path point to the block we want to drop (this one).
 		 */
 		forward = !INT_ISZERO(info->forw, ARCH_CONVERT);
-		bcopy(&state->path, &state->altpath, sizeof(state->path));
+		memcpy(&state->altpath, &state->path, sizeof(state->path));
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
 		if (error)
@@ -1418,7 +1418,7 @@
 	 * Make altpath point to the block we want to keep (the lower
 	 * numbered block) and path point to the block we want to drop.
 	 */
-	bcopy(&state->path, &state->altpath, sizeof(state->path));
+	memcpy(&state->altpath, &state->path, sizeof(state->path));
 	if (blkno < blk->blkno) {
 		error = xfs_da_path_shift(state, &state->altpath, forward,
 						 0, &retval);
@@ -1538,17 +1538,17 @@
 	 * Compress the remaining entries and zero out the removed stuff.
 	 */
 	namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
-	bzero((char *)namest, entsize);
+	memset((char *)namest, 0, entsize);
 	xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize));
 
 	INT_MOD(hdr->namebytes, ARCH_CONVERT, -(entry->namelen));
 	tmp = (INT_GET(hdr->count, ARCH_CONVERT) - index) * (uint)sizeof(xfs_dir_leaf_entry_t);
-	ovbcopy(entry + 1, entry, tmp);
+	memmove(entry, entry + 1, tmp);
 	INT_MOD(hdr->count, ARCH_CONVERT, -1);
 	xfs_da_log_buf(trans, bp,
 	    XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry)));
 	entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)];
-	bzero((char *)entry, sizeof(xfs_dir_leaf_entry_t));
+	memset((char *)entry, 0, sizeof(xfs_dir_leaf_entry_t));
 
 	/*
 	 * If we removed the first entry, re-find the first used byte
@@ -1642,7 +1642,7 @@
 		 */
 		tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP);
 		ASSERT(tmpbuffer != NULL);
-		bzero(tmpbuffer, state->blocksize);
+		memset(tmpbuffer, 0, state->blocksize);
 		tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer;
 		tmp_hdr = &tmp_leaf->hdr;
 		tmp_hdr->info = save_hdr->info; /* struct copy */
@@ -1664,7 +1664,7 @@
 					      tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
 					      (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
 		}
-		bcopy(tmp_leaf, save_leaf, state->blocksize);
+		memcpy(save_leaf, tmp_leaf, state->blocksize);
 		kmem_free(tmpbuffer, state->blocksize);
 	}
 
@@ -1750,7 +1750,7 @@
 		namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
 		if (entry->namelen == args->namelen &&
 		    namest->name[0] == args->name[0] &&
-		    bcmp(args->name, namest->name, args->namelen) == 0) {
+		    memcmp(args->name, namest->name, args->namelen) == 0) {
 			XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args->inumber, ARCH_CONVERT);
 			*index = probe;
 			return(XFS_ERROR(EEXIST));
@@ -1813,7 +1813,7 @@
 		tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
 		entry_s = &leaf_d->entries[start_d];
 		entry_d = &leaf_d->entries[start_d + count];
-		bcopy(entry_s, entry_d, tmp);
+		memcpy(entry_d, entry_s, tmp);
 	}
 
 	/*
@@ -1831,11 +1831,11 @@
 		INT_COPY(entry_d->nameidx, hdr_d->firstused, ARCH_CONVERT);
 		entry_d->namelen = entry_s->namelen;
 		ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
-		bcopy(XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
-		      XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)), tmp);
+		memcpy(XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)),
+		       XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), tmp);
 		ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp));
-		bzero((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
-		      tmp);
+		memset((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)),
+		      0, tmp);
 		INT_MOD(hdr_s->namebytes, ARCH_CONVERT, -(entry_d->namelen));
 		INT_MOD(hdr_d->namebytes, ARCH_CONVERT, entry_d->namelen);
 		INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
@@ -1853,7 +1853,7 @@
 		tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
 		entry_s = &leaf_s->entries[start_s];
 		ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
-		bzero((char *)entry_s, tmp);
+		memset((char *)entry_s, 0, tmp);
 	} else {
 		/*
 		 * Move the remaining entries down to fill the hole,
@@ -1863,12 +1863,12 @@
 		tmp *= (uint)sizeof(xfs_dir_leaf_entry_t);
 		entry_s = &leaf_s->entries[start_s + count];
 		entry_d = &leaf_s->entries[start_s];
-		bcopy(entry_s, entry_d, tmp);
+		memcpy(entry_d, entry_s, tmp);
 
 		tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t);
 		entry_s = &leaf_s->entries[INT_GET(hdr_s->count, ARCH_CONVERT)];
 		ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp));
-		bzero((char *)entry_s, tmp);
+		memset((char *)entry_s, 0, tmp);
 	}
 
 	/*
@@ -2191,7 +2191,7 @@
 	idbp->d_off = pa->cook.o;
 	idbp->d_name[namelen] = '\0';
 	pa->done = 1;
-	bcopy(pa->name, idbp->d_name, namelen);
+	memcpy(idbp->d_name, pa->name, namelen);
 	return 0;
 }
 
@@ -2217,7 +2217,7 @@
 	idbp->d_ino = pa->ino;
 	idbp->d_off = pa->cook.o;
 	idbp->d_name[namelen] = '\0';
-	bcopy(pa->name, idbp->d_name, namelen);
+	memcpy(idbp->d_name, pa->name, namelen);
 	retval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio);
 	pa->done = (retval == 0);
 	return retval;
diff -Nru a/fs/xfs/xfs_dir_sf.h b/fs/xfs/xfs_dir_sf.h
--- a/fs/xfs/xfs_dir_sf.h	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_dir_sf.h	Tue Oct 15 20:29:18 2002
@@ -46,7 +46,7 @@
  * be calculated on the fly.
  *
  * Entries are packed toward the top as tight as possible.  The header
- * and the elements much be bcopy()'d out into a work area to get correct
+ * and the elements much be memcpy'd out into a work area to get correct
  * alignment for the inode number fields.
  */
 typedef struct xfs_dir_shortform {
diff -Nru a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
--- a/fs/xfs/xfs_dquot.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/xfs_dquot.c	Tue Oct 15 20:29:16 2002
@@ -94,7 +94,7 @@
 #endif
 	} else {
 		/*
-		 * Only the q_core portion was bzeroed in dqreclaim_one().
+		 * Only the q_core portion was zeroed in dqreclaim_one().
 		 * So, we need to reset others.
 		 */
 		 dqp->q_nrefs = 0;
@@ -156,7 +156,7 @@
 	xfs_dqblk_t	 *d)
 {
 	/*
-	 * Caller has bzero'd the entire dquot 'chunk' already.
+	 * Caller has zero'd the entire dquot 'chunk' already.
 	 */
 	INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC);
 	INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION);
@@ -351,7 +351,7 @@
 	 */
 	curid = id - (id % XFS_QM_DQPERBLK(mp));
 	ASSERT(curid >= 0);
-	bzero(d, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
+	memset(d, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)));
 	for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++)
 		xfs_qm_dqinit_core(curid, type, d);
 	xfs_trans_dquot_buf(tp, bp,
@@ -614,7 +614,7 @@
 	}
 
 	/* copy everything from disk dquot to the incore dquot */
-	bcopy(ddqp, &dqp->q_core, sizeof(xfs_disk_dquot_t));
+	memcpy(&dqp->q_core, ddqp, sizeof(xfs_disk_dquot_t));
 	ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id);
 	xfs_qm_dquot_logitem_init(dqp);
 
@@ -1209,7 +1209,7 @@
 	}
 
 	/* This is the only portion of data that needs to persist */
-	bcopy(&(dqp->q_core), ddqp, sizeof(xfs_disk_dquot_t));
+	memcpy(ddqp, &(dqp->q_core), sizeof(xfs_disk_dquot_t));
 
 	/*
 	 * Clear the dirty field and remember the flush lsn for later use.
@@ -1475,7 +1475,7 @@
 	dqp->q_mount = NULL;;
 	dqp->q_hash = NULL;
 	dqp->dq_flags = XFS_DQ_INACTIVE;
-	bzero(&dqp->q_core, sizeof(dqp->q_core));
+	memset(&dqp->q_core, 0, sizeof(dqp->q_core));
 	xfs_dqfunlock(dqp);
 	xfs_dqunlock(dqp);
 	XFS_DQ_HASH_UNLOCK(thishash);
@@ -1585,7 +1585,7 @@
 	 */
 	ASSERT(id != -1);
 	ASSERT(flags & XFS_QMOPT_DQREPAIR);
-	bzero(ddq, sizeof(xfs_dqblk_t));
+	memset(ddq, 0, sizeof(xfs_dqblk_t));
 	xfs_qm_dqinit_core(id, type, (xfs_dqblk_t *)ddq);
 	return (errs);
 }
diff -Nru a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
--- a/fs/xfs/xfs_error.c	Tue Oct 15 20:29:21 2002
+++ b/fs/xfs/xfs_error.c	Tue Oct 15 20:29:21 2002
@@ -69,9 +69,9 @@
 void
 xfs_error_test_init(void)
 {
-	bzero(xfs_etest, sizeof(xfs_etest));
-	bzero(xfs_etest_fsid, sizeof(xfs_etest_fsid));
-	bzero(xfs_etest_fsname, sizeof(xfs_etest_fsname));
+	memset(xfs_etest, 0, sizeof(xfs_etest));
+	memset(xfs_etest_fsid, 0, sizeof(xfs_etest_fsid));
+	memset(xfs_etest_fsname, 0, sizeof(xfs_etest_fsname));
 }
 
 int
@@ -84,12 +84,12 @@
 	if (random() % randfactor)
 		return 0;
 
-	bcopy(fsidp, &fsid, sizeof(fsid_t));
+	memcpy(&fsid, fsidp, sizeof(fsid_t));
 
 	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
 		if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) {
 			cmn_err(CE_WARN,
-	"Injecting error (%s) at file %s, line %d, on filesystem \"%s\"\n",
+	"Injecting error (%s) at file %s, line %d, on filesystem \"%s\"",
 				expression, file, line, xfs_etest_fsname[i]);
 			return 1;
 		}
@@ -105,7 +105,7 @@
 	int len;
 	int64_t fsid;
 
-	bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t));
+	memcpy(&fsid, mp->m_fixedfsid, sizeof(fsid_t));
 
 	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++)  {
 		if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
@@ -138,7 +138,7 @@
 	int i;
 	int64_t fsid;
 
-	bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t));
+	memcpy(&fsid, mp->m_fixedfsid, sizeof(fsid_t));
 
 	for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) {
 		if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) {
@@ -191,7 +191,7 @@
 {
 	int64_t fsid;
 
-	bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t));
+	memcpy(&fsid, mp->m_fixedfsid, sizeof(fsid_t));
 
 	return xfs_errortag_clearall_umount(fsid, mp->m_fsname, 1);
 }
diff -Nru a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
--- a/fs/xfs/xfs_fs.h	Tue Oct 15 20:29:14 2002
+++ b/fs/xfs/xfs_fs.h	Tue Oct 15 20:29:14 2002
@@ -427,9 +427,9 @@
 				 - (char *) &(handle))			  \
 				 + (handle).ha_fid.xfs_fid_len)
 
-#define XFS_HANDLE_CMP(h1, h2)	bcmp(h1, h2, sizeof (xfs_handle_t))
+#define XFS_HANDLE_CMP(h1, h2)	memcmp(h1, h2, sizeof(xfs_handle_t))
 
-#define FSHSIZE		sizeof (fsid_t)
+#define FSHSIZE		sizeof(fsid_t)
 
 
 /*
@@ -498,13 +498,5 @@
 #define BTOBB(bytes)	(((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT)
 #define BTOBBT(bytes)	((__u64)(bytes) >> BBSHIFT)
 #define BBTOB(bbs)	((bbs) << BBSHIFT)
-#define OFFTOBB(bytes)	(((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT)
-#define OFFTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT)
-#define BBTOOFF(bbs)	((__u64)(bbs) << BBSHIFT)
-
-#define SEEKLIMIT32	0x7fffffff
-#define BBSEEKLIMIT32	BTOBBT(SEEKLIMIT32)
-#define SEEKLIMIT	0x7fffffffffffffffLL
-#define BBSEEKLIMIT	OFFTOBBT(SEEKLIMIT)
 
 #endif	/* _LINUX_XFS_FS_H */
diff -Nru a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
--- a/fs/xfs/xfs_fsops.c	Tue Oct 15 20:29:21 2002
+++ b/fs/xfs/xfs_fsops.c	Tue Oct 15 20:29:21 2002
@@ -149,7 +149,7 @@
 			sizeof(xfs_perag_t) * nagcount,
 			sizeof(xfs_perag_t) * oagcount,
 			KM_SLEEP);
-		bzero(&mp->m_perag[oagcount],
+		memset(&mp->m_perag[oagcount], 0,
 			(nagcount - oagcount) * sizeof(xfs_perag_t));
 		mp->m_flags |= XFS_MOUNT_32BITINODES;
 		xfs_initialize_perag(mp, nagcount);
@@ -175,7 +175,7 @@
 				  disk_addr,
 				  sectbb, 0);
 		agf = XFS_BUF_TO_AGF(bp);
-		bzero(agf, mp->m_sb.sb_sectsize);
+		memset(agf, 0, mp->m_sb.sb_sectsize);
 		INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC);
 		INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION);
 		INT_SET(agf->agf_seqno, ARCH_CONVERT, agno);
@@ -208,7 +208,7 @@
 				  disk_addr,
 				  sectbb, 0);
 		agi = XFS_BUF_TO_AGI(bp);
-		bzero(agi, mp->m_sb.sb_sectsize);
+		memset(agi, 0, mp->m_sb.sb_sectsize);
 		INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC);
 		INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION);
 		INT_SET(agi->agi_seqno, ARCH_CONVERT, agno);
@@ -233,7 +233,7 @@
 			disk_addr,
 			BTOBB(bsize), 0);
 		block = XFS_BUF_TO_SBLOCK(bp);
-		bzero(block, bsize);
+		memset(block, 0, bsize);
 		INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTB_MAGIC);
 		INT_ZERO(block->bb_level, ARCH_CONVERT);
 		INT_SET(block->bb_numrecs, ARCH_CONVERT, 1);
@@ -255,7 +255,7 @@
 			disk_addr,
 			BTOBB(bsize), 0);
 		block = XFS_BUF_TO_SBLOCK(bp);
-		bzero(block, bsize);
+		memset(block, 0, bsize);
 		INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTC_MAGIC);
 		INT_ZERO(block->bb_level, ARCH_CONVERT);
 		INT_SET(block->bb_numrecs, ARCH_CONVERT, 1);
@@ -278,7 +278,7 @@
 			disk_addr,
 			BTOBB(bsize), 0);
 		block = XFS_BUF_TO_SBLOCK(bp);
-		bzero(block, bsize);
+		memset(block, 0, bsize);
 		INT_SET(block->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC);
 		INT_ZERO(block->bb_level, ARCH_CONVERT);
 		INT_ZERO(block->bb_numrecs, ARCH_CONVERT);
@@ -353,7 +353,7 @@
 				  sectbb, 0, &bp);
 		if (error) {
 			xfs_fs_cmn_err(CE_WARN, mp,
-			"error %d reading secondary superblock for ag %d\n",
+			"error %d reading secondary superblock for ag %d",
 				error, agno);
 			break;
 		}
@@ -368,7 +368,7 @@
 			continue;
 		} else {
 			xfs_fs_cmn_err(CE_WARN, mp,
-		"write error %d updating secondary superblock for ag %d\n",
+		"write error %d updating secondary superblock for ag %d",
 				error, agno);
 			break; /* no point in continuing */
 		}
diff -Nru a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
--- a/fs/xfs/xfs_ialloc.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_ialloc.c	Tue Oct 15 20:29:17 2002
@@ -263,7 +263,7 @@
 		INT_ZERO(dic.di_gid, ARCH_CONVERT);
 		INT_ZERO(dic.di_nlink, ARCH_CONVERT);
 		INT_ZERO(dic.di_projid, ARCH_CONVERT);
-		bzero(&(dic.di_pad[0]),sizeof(dic.di_pad));
+		memset(&(dic.di_pad[0]), 0, sizeof(dic.di_pad));
 		INT_SET(dic.di_atime.t_sec, ARCH_CONVERT, ztime.t_sec);
 		INT_SET(dic.di_atime.t_nsec, ARCH_CONVERT, ztime.t_nsec);
 
@@ -287,7 +287,7 @@
 
 		for (i = 0; i < ninodes; i++) {
 			free = XFS_MAKE_IPTR(args.mp, fbuf, i);
-			bcopy (&dic, &(free->di_core), sizeof(xfs_dinode_core_t));
+			memcpy(&(free->di_core), &dic, sizeof(xfs_dinode_core_t));
 			INT_SET(free->di_next_unlinked, ARCH_CONVERT, NULLAGINO);
 			xfs_ialloc_log_di(tp, fbuf, i,
 				XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED);
diff -Nru a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
--- a/fs/xfs/xfs_ialloc_btree.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/xfs_ialloc_btree.c	Tue Oct 15 20:29:16 2002
@@ -139,9 +139,9 @@
 		}
 #endif
 		if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
-			ovbcopy(&kp[ptr], &kp[ptr - 1],
+			memmove(&kp[ptr - 1], &kp[ptr],
 				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*kp));
-			ovbcopy(&pp[ptr], &pp[ptr - 1],
+			memmove(&pp[ptr - 1], &pp[ptr],
 				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*pp));
 			xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
 			xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
@@ -154,7 +154,7 @@
 	else {
 		rp = XFS_INOBT_REC_ADDR(block, 1, cur);
 		if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) {
-			ovbcopy(&rp[ptr], &rp[ptr - 1],
+			memmove(&rp[ptr - 1], &rp[ptr],
 				(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*rp));
 			xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1);
 		}
@@ -450,8 +450,8 @@
 				return error;
 		}
 #endif
-		bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp));
-		bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp));
+		memcpy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp));
+		memcpy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp));
 		xfs_inobt_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
 				   INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		xfs_inobt_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
@@ -462,7 +462,7 @@
 		 */
 		lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur);
 		rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
-		bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
+		memcpy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp));
 		xfs_inobt_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1,
 				   INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT));
 	}
@@ -690,9 +690,9 @@
 				return error;
 		}
 #endif
-		ovbcopy(&kp[ptr - 1], &kp[ptr],
+		memmove(&kp[ptr], &kp[ptr - 1],
 			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp));
-		ovbcopy(&pp[ptr - 1], &pp[ptr],
+		memmove(&pp[ptr], &pp[ptr - 1],
 			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp));
 		/*
 		 * Now stuff the new data in, bump numrecs and log the new data.
@@ -711,7 +711,7 @@
 		 * It's a leaf entry.  Make a hole for the new record.
 		 */
 		rp = XFS_INOBT_REC_ADDR(block, 1, cur);
-		ovbcopy(&rp[ptr - 1], &rp[ptr],
+		memmove(&rp[ptr], &rp[ptr - 1],
 			(INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp));
 		/*
 		 * Now stuff the new record in, bump numrecs
@@ -1170,12 +1170,12 @@
 				return error;
 		}
 #endif
-		ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
-		ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+		memmove(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+		memmove(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
 		xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 	} else {
-		ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+		memmove(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
 		xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		key.ir_startino = rrp->ir_startino; /* INT_: direct copy */
 		rkp = &key;
@@ -1421,8 +1421,8 @@
 				return error;
 		}
 #endif
-		ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
-		ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+		memmove(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+		memmove(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
 #ifdef DEBUG
 		if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level)))
 			return error;
@@ -1434,7 +1434,7 @@
 	} else {
 		lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur);
 		rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
-		ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+		memmove(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
 		*rrp = *lrp;
 		xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1);
 		key.ir_startino = rrp->ir_startino; /* INT_: direct copy */
@@ -1562,8 +1562,8 @@
 				return error;
 		}
 #endif
-		bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
-		bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
+		memcpy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp));
+		memcpy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));
 		xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		*keyp = *rkp;
@@ -1574,7 +1574,7 @@
 	else {
 		lrp = XFS_INOBT_REC_ADDR(left, i, cur);
 		rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
-		bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
+		memcpy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp));
 		xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT));
 		keyp->ir_startino = rrp->ir_startino; /* INT_: direct copy */
 	}
diff -Nru a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
--- a/fs/xfs/xfs_iget.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/xfs_iget.c	Tue Oct 15 20:29:16 2002
@@ -31,6 +31,7 @@
  */
 
 #include <xfs.h>
+#include <linux/pagemap.h>
 
 
 /*
@@ -109,24 +110,35 @@
 	mp->m_chash = NULL;
 }
 
-
-static inline void
-xfs_iget_vnode_init(
+void
+xfs_revalidate_inode(
 	xfs_mount_t	*mp,
 	vnode_t		*vp,
 	xfs_inode_t	*ip)
 {
-	vp->v_vfsp  = XFS_MTOVFS(mp);
-	vp->v_type  = IFTOVT(ip->i_d.di_mode);
+	struct inode	*inode = LINVFS_GET_IP(vp);
 
-	/* If we have a real type for an on-disk inode, we can set ops(&unlock)
-	 * now.	 If it's a new inode being created, xfs_ialloc will handle it.
-	 */
-	if (vp->v_type != VNON) {
-		linvfs_set_inode_ops(LINVFS_GET_IP(vp));
+	inode->i_mode	= (ip->i_d.di_mode & MODEMASK) | VTTOIF(vp->v_type);
+	inode->i_nlink	= ip->i_d.di_nlink;
+	inode->i_uid	= ip->i_d.di_uid;
+	inode->i_gid 	= ip->i_d.di_gid;
+	if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
+		inode->i_rdev	= NODEV;
+	} else {
+		xfs_dev_t dev = ip->i_df.if_u2.if_rdev;
+		inode->i_rdev	= XFS_DEV_TO_KDEVT(dev);
 	}
-}
+	inode->i_blksize = PAGE_CACHE_SIZE;
+	inode->i_generation = ip->i_d.di_gen;
+	inode->i_size	= ip->i_d.di_size;
+	inode->i_blocks =
+		XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
+	inode->i_atime	= ip->i_d.di_atime.t_sec;
+	inode->i_mtime	= ip->i_d.di_mtime.t_sec;
+	inode->i_ctime	= ip->i_d.di_ctime.t_sec;
 
+	vp->v_flag &= ~VMODIFIED;
+}
 
 /*
  * Look up an inode by number in the given file system.
@@ -159,7 +171,7 @@
  * bno -- the block number starting the buffer containing the inode,
  *	  if known (as by bulkstat), else 0.
  */
-int
+STATIC int
 xfs_iget_core(
 	vnode_t		*vp,
 	xfs_mount_t	*mp,
@@ -205,16 +217,9 @@
 					goto again;
 				}
 
-				xfs_iget_vnode_init(mp, vp, ip);
-
 				vn_trace_exit(vp, "xfs_iget.alloc",
 					(inst_t *)__return_address);
 
-				bhv_desc_init(&(ip->i_bhv_desc), ip, vp,
-							&xfs_vnodeops);
-				vn_bhv_insert_initial(VN_BHV_HEAD(vp),
-							&(ip->i_bhv_desc));
-
 				XFS_STATS_INC(xfsstats.xs_ig_found);
 
 				read_unlock(&ih->ih_lock);
@@ -240,18 +245,12 @@
 				cmn_err(CE_PANIC,
 			"xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p",
 						inode_vp, vp);
-				BUG();
 			}
 
 			read_unlock(&ih->ih_lock);
 
 			XFS_STATS_INC(xfsstats.xs_ig_found);
 
-			/*
-			 * Make sure the vnode and the inode are hooked up
-			 */
-			xfs_iget_vnode_init(mp, vp, ip);
-
 finish_inode:
 			if (lock_flags != 0) {
 				xfs_ilock(ip, lock_flags);
@@ -288,19 +287,8 @@
 		return error;
 	}
 
-	/*
-	 * Vnode provided by vn_initialize.
-	 */
-
-	xfs_iget_vnode_init(mp, vp, ip);
-
 	vn_trace_exit(vp, "xfs_iget.alloc", (inst_t *)__return_address);
 
-	if (vp->v_fbhv == NULL) {
-		bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops);
-		vn_bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc));
-	}
-
 	xfs_inode_lock_init(ip, vp);
 	xfs_iocore_inode_init(ip);
 
@@ -429,8 +417,11 @@
 
 	*ipp = ip;
 
-	/* Update the linux inode */
-	error = vn_revalidate(vp, ATTR_COMM|ATTR_LAZY);
+	/*
+	 * If we have a real type for an on-disk inode, we can set ops(&unlock)
+	 * now.	 If it's a new inode being created, xfs_ialloc will handle it.
+	 */
+	VFS_INIT_VNODE(XFS_MTOVFS(mp), vp, XFS_ITOBHV(ip), 1);
 
 	return 0;
 }
@@ -495,7 +486,6 @@
 			newnode = (ip->i_d.di_mode == 0);
 			if (newnode)
 				xfs_iocore_inode_reinit(ip);
-			vn_revalidate(vp, ATTR_COMM|ATTR_LAZY);
 			XFS_STATS_INC(xfsstats.xs_ig_found);
 			*ipp = ip;
 			error = 0;
@@ -505,7 +495,6 @@
 
 	return error;
 }
-
 
 /*
  * Do the setup for the various locks within the incore inode.
diff -Nru a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
--- a/fs/xfs/xfs_inode.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/xfs_inode.c	Tue Oct 15 20:29:16 2002
@@ -56,8 +56,9 @@
  */
 STATIC void
 xfs_validate_extents(
-	xfs_bmbt_rec_32_t	*ep,
+	xfs_bmbt_rec_t		*ep,
 	int			nrecs,
+	int			disk,
 	xfs_exntfmt_t		fmt)
 {
 	xfs_bmbt_irec_t		irec;
@@ -65,15 +66,18 @@
 	xfs_bmbt_rec_t		rec;
 
 	for (i = 0; i < nrecs; i++) {
-		bcopy(ep, &rec, sizeof(rec));
-		xfs_bmbt_get_all(&rec, &irec);
+		memcpy(&rec, ep, sizeof(rec));
+		if (disk)
+			xfs_bmbt_disk_get_all(&rec, &irec);
+		else
+			xfs_bmbt_get_all(&rec, &irec);
 		if (fmt == XFS_EXTFMT_NOSTATE)
 			ASSERT(irec.br_state == XFS_EXT_NORM);
 		ep++;
 	}
 }
 #else /* DEBUG */
-#define xfs_validate_extents(ep, nrecs, fmt)
+#define xfs_validate_extents(ep, nrecs, disk, fmt)
 #endif /* DEBUG */
 
 /*
@@ -551,7 +555,7 @@
 	/*
 	 * If the size is unreasonable, then something
 	 * is wrong and we just bail out rather than crash in
-	 * kmem_alloc() or bcopy() below.
+	 * kmem_alloc() or memcpy() below.
 	 */
 	if (size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) {
 		xfs_fs_cmn_err(CE_WARN, ip->i_mount,
@@ -575,7 +579,8 @@
 	ifp->if_bytes = size;
 	ifp->if_real_bytes = real_size;
 	if (size)
-		bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_data, size);
+		memcpy(ifp->if_u1.if_data,
+			XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), size);
 	ifp->if_flags &= ~XFS_IFEXTENTS;
 	ifp->if_flags |= XFS_IFINLINE;
 	return 0;
@@ -597,9 +602,10 @@
 	int		whichfork)
 {
 	xfs_ifork_t	*ifp;
-	int		nex;
+	int		nex, i;
 	int		real_size;
 	int		size;
+	xfs_bmbt_rec_t	*ep, *dp;
 
 	ifp = XFS_IFORK_PTR(ip, whichfork);
 	nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT);
@@ -608,7 +614,7 @@
 	/*
 	 * If the number of extents is unreasonable, then something
 	 * is wrong and we just bail out rather than crash in
-	 * kmem_alloc() or bcopy() below.
+	 * kmem_alloc() or memcpy() below.
 	 */
 	if (size < 0 || size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) {
 		xfs_fs_cmn_err(CE_WARN, ip->i_mount,
@@ -632,10 +638,18 @@
 	ifp->if_real_bytes = real_size;
 	if (size) {
 		xfs_validate_extents(
-			(xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT),
-			nex, XFS_EXTFMT_INODE(ip));
-		bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_extents,
-		      size);
+			(xfs_bmbt_rec_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT),
+			nex, 1, XFS_EXTFMT_INODE(ip));
+		dp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT);
+		ep = ifp->if_u1.if_extents;
+#if ARCH_CONVERT != ARCH_NOCONVERT
+		for (i = 0; i < nex; i++, ep++, dp++) {
+			ep->l0 = INT_GET(dp->l0, ARCH_CONVERT);
+			ep->l1 = INT_GET(dp->l1, ARCH_CONVERT);
+		}
+#else
+		memcpy(ep, dp, size);
+#endif
 		xfs_bmap_trace_exlist("xfs_iformat_extents", ip, nex,
 			whichfork);
 		if (whichfork != XFS_DATA_FORK ||
@@ -731,9 +745,9 @@
 
     if (arch == ARCH_NOCONVERT) {
 	if (dir>0) {
-	    bcopy((xfs_caddr_t)buf_core, (xfs_caddr_t)mem_core, sizeof(xfs_dinode_core_t));
+	    memcpy((xfs_caddr_t)mem_core, (xfs_caddr_t)buf_core, sizeof(xfs_dinode_core_t));
 	} else {
-	    bcopy((xfs_caddr_t)mem_core, (xfs_caddr_t)buf_core, sizeof(xfs_dinode_core_t));
+	    memcpy((xfs_caddr_t)buf_core, (xfs_caddr_t)mem_core, sizeof(xfs_dinode_core_t));
 	}
 	return;
     }
@@ -749,9 +763,9 @@
     INT_XLATE(buf_core->di_projid,	mem_core->di_projid,	   dir, arch);
 
     if (dir>0) {
-	bcopy(buf_core->di_pad, mem_core->di_pad, sizeof(buf_core->di_pad));
+	memcpy(mem_core->di_pad, buf_core->di_pad, sizeof(buf_core->di_pad));
     } else {
-	bcopy(mem_core->di_pad, buf_core->di_pad, sizeof(buf_core->di_pad));
+	memcpy(buf_core->di_pad, mem_core->di_pad, sizeof(buf_core->di_pad));
     }
 
     INT_XLATE(buf_core->di_atime.t_sec, mem_core->di_atime.t_sec,  dir, arch);
@@ -978,8 +992,8 @@
 		ifp->if_flags &= ~XFS_IFEXTENTS;
 		return error;
 	}
-	xfs_validate_extents((xfs_bmbt_rec_32_t *)ifp->if_u1.if_extents,
-		XFS_IFORK_NEXTENTS(ip, whichfork), XFS_EXTFMT_INODE(ip));
+	xfs_validate_extents((xfs_bmbt_rec_t *)ifp->if_u1.if_extents,
+		XFS_IFORK_NEXTENTS(ip, whichfork), 0, XFS_EXTFMT_INODE(ip));
 	return 0;
 }
 
@@ -1015,7 +1029,7 @@
 	xfs_inode_t	*pip,
 	mode_t		mode,
 	nlink_t		nlink,
-	dev_t		rdev,
+	xfs_dev_t	rdev,
 	cred_t		*cr,
 	xfs_prid_t	prid,
 	int		okalloc,
@@ -1065,10 +1079,7 @@
 	ip->i_d.di_uid = current->fsuid;
 	ip->i_d.di_gid = current->fsgid;
 	ip->i_d.di_projid = prid;
-	bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
-
-	/* now that we have a v_type we can set Linux inode ops (& unlock) */
-	linvfs_set_inode_ops(LINVFS_GET_IP(XFS_ITOV(ip)));
+	memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
 
 	/*
 	 * If the superblock version is up to where we support new format
@@ -1100,14 +1111,13 @@
 
 	/*
 	 * If the group ID of the new file does not match the effective group
-	 * ID or one of the supplementary group IDs, the ISGID bit is
-	 * cleared if the "irixsgid" mount option is set.
+	 * ID or one of the supplementary group IDs, the ISGID bit is cleared
+	 * (and only if the irix_sgid_inherit compatibility variable is set).
 	 */
-	if (ip->i_d.di_mode & ISGID) {
-		if (!in_group_p((gid_t)ip->i_d.di_gid)
-		    && (ip->i_mount->m_flags & XFS_MOUNT_IRIXSGID)) {
-			ip->i_d.di_mode &= ~ISGID;
-		}
+	if ((irix_sgid_inherit) &&
+	    (ip->i_d.di_mode & ISGID) &&
+	    (!in_group_p((gid_t)ip->i_d.di_gid))) {
+		ip->i_d.di_mode &= ~ISGID;
 	}
 
 	ip->i_d.di_size = 0;
@@ -1128,7 +1138,7 @@
 	case IFBLK:
 	case IFSOCK:
 		ip->i_d.di_format = XFS_DINODE_FMT_DEV;
-		ip->i_df.if_u2.if_rdev = IRIX_MKDEV(MAJOR(rdev), MINOR(rdev));
+		ip->i_df.if_u2.if_rdev = rdev;
 		ip->i_df.if_flags = 0;
 		flags |= XFS_ILOG_DEV;
 		break;
@@ -1172,6 +1182,10 @@
 	 * Log the new values stuffed into the inode.
 	 */
 	xfs_trans_log_inode(tp, ip, flags);
+
+	/* now that we have a v_type we can set Linux inode ops (& unlock) */
+	VFS_INIT_VNODE(XFS_MTOVFS(tp->t_mountp), vp, XFS_ITOBHV(ip), 1);
+
 	*ipp = ip;
 	return 0;
 }
@@ -1714,7 +1728,7 @@
 	 * and any blocks between the old and new file sizes.
 	 */
 	error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, isize,
-				new_size, NULL);
+				new_size);
 	return error;
 }
 
@@ -2156,7 +2170,7 @@
 		ifp->if_broot_bytes = (int)new_size;
 		ASSERT(ifp->if_broot_bytes <=
 			XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ);
-		ovbcopy(op, np, cur_max * (uint)sizeof(xfs_dfsbno_t));
+		memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
 		return;
 	}
 
@@ -2178,7 +2192,7 @@
 		/*
 		 * First copy over the btree block header.
 		 */
-		bcopy(ifp->if_broot, new_broot, sizeof(xfs_bmbt_block_t));
+		memcpy(new_broot, ifp->if_broot, sizeof(xfs_bmbt_block_t));
 	} else {
 		new_broot = NULL;
 		ifp->if_flags &= ~XFS_IFBROOT;
@@ -2195,7 +2209,7 @@
 						     ifp->if_broot_bytes);
 		np = (char *)XFS_BMAP_BROOT_REC_ADDR(new_broot, 1,
 						     (int)new_size);
-		bcopy(op, np, new_max * (uint)sizeof(xfs_bmbt_rec_t));
+		memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
 
 		/*
 		 * Then copy the pointers.
@@ -2204,7 +2218,7 @@
 						     ifp->if_broot_bytes);
 		np = (char *)XFS_BMAP_BROOT_PTR_ADDR(new_broot, 1,
 						     (int)new_size);
-		bcopy(op, np, new_max * (uint)sizeof(xfs_dfsbno_t));
+		memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t));
 	}
 	kmem_free(ifp->if_broot, ifp->if_broot_bytes);
 	ifp->if_broot = new_broot;
@@ -2268,8 +2282,8 @@
 			 * so the if_extents pointer is null.
 			 */
 			if (ifp->if_u1.if_extents) {
-				bcopy(ifp->if_u1.if_extents,
-				      ifp->if_u2.if_inline_ext, new_size);
+				memcpy(ifp->if_u2.if_inline_ext,
+					ifp->if_u1.if_extents, new_size);
 				kmem_free(ifp->if_u1.if_extents,
 					  ifp->if_real_bytes);
 			}
@@ -2286,7 +2300,7 @@
 		if (ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext) {
 			ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
 				kmem_alloc(rnew_size, KM_SLEEP);
-			bcopy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
+			memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
 			      sizeof(ifp->if_u2.if_inline_ext));
 		} else if (rnew_size != ifp->if_real_bytes) {
 			ifp->if_u1.if_extents = (xfs_bmbt_rec_t *)
@@ -2349,7 +2363,7 @@
 			ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
 		} else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
 			ASSERT(ifp->if_real_bytes != 0);
-			bcopy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
+			memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
 			      new_size);
 			kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes);
 			ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
@@ -2382,8 +2396,8 @@
 		} else {
 			ASSERT(ifp->if_real_bytes == 0);
 			ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP);
-			bcopy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
-			      ifp->if_bytes);
+			memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
+				ifp->if_bytes);
 		}
 	}
 	ifp->if_real_bytes = real_size;
@@ -2610,17 +2624,17 @@
  * returns the number of bytes copied into the buffer.
  *
  * If there are no delayed allocation extents, then we can just
- * bcopy() the extents into the buffer.	 Otherwise, we need to
+ * memcpy() the extents into the buffer.  Otherwise, we need to
  * examine each extent in turn and skip those which are delayed.
  */
 int
 xfs_iextents_copy(
 	xfs_inode_t		*ip,
-	xfs_bmbt_rec_32_t	*buffer,
+	xfs_bmbt_rec_t		*buffer,
 	int			whichfork)
 {
 	int			copied;
-	xfs_bmbt_rec_32_t	*dest_ep;
+	xfs_bmbt_rec_t		*dest_ep;
 	xfs_bmbt_rec_t		*ep;
 #ifdef XFS_BMAP_TRACE
 	static char		fname[] = "xfs_iextents_copy";
@@ -2637,28 +2651,13 @@
 	nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
 	xfs_bmap_trace_exlist(fname, ip, nrecs, whichfork);
 	ASSERT(nrecs > 0);
-	if (nrecs == XFS_IFORK_NEXTENTS(ip, whichfork)) {
-		/*
-		 * There are no delayed allocation extents,
-		 * so just copy everything.
-		 */
-		ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
-		ASSERT(ifp->if_bytes ==
-		       (XFS_IFORK_NEXTENTS(ip, whichfork) *
-			(uint)sizeof(xfs_bmbt_rec_t)));
-		bcopy(ifp->if_u1.if_extents, buffer, ifp->if_bytes);
-		xfs_validate_extents(buffer, nrecs, XFS_EXTFMT_INODE(ip));
-		return ifp->if_bytes;
-	}
 
-	ASSERT(whichfork == XFS_DATA_FORK);
 	/*
 	 * There are some delayed allocation extents in the
 	 * inode, so copy the extents one at a time and skip
 	 * the delayed ones.  There must be at least one
 	 * non-delayed extent.
 	 */
-	ASSERT(nrecs > ip->i_d.di_nextents);
 	ep = ifp->if_u1.if_extents;
 	dest_ep = buffer;
 	copied = 0;
@@ -2672,15 +2671,19 @@
 			continue;
 		}
 
-		*dest_ep = *(xfs_bmbt_rec_32_t *)ep;
+#if ARCH_CONVERT != ARCH_NOCONVERT
+		/* Translate to on disk format */
+		dest_ep->l0 = INT_GET(ep->l0, ARCH_CONVERT);
+		dest_ep->l1 = INT_GET(ep->l1, ARCH_CONVERT);
+#else
+		*dest_ep = *ep;
+#endif
 		dest_ep++;
 		ep++;
 		copied++;
 	}
 	ASSERT(copied != 0);
-	ASSERT(copied == ip->i_d.di_nextents);
-	ASSERT((copied * (uint)sizeof(xfs_bmbt_rec_t)) <= XFS_IFORK_DSIZE(ip));
-	xfs_validate_extents(buffer, copied, XFS_EXTFMT_INODE(ip));
+	xfs_validate_extents(buffer, copied, 1, XFS_EXTFMT_INODE(ip));
 
 	return (copied * (uint)sizeof(xfs_bmbt_rec_t));
 }
@@ -2736,7 +2739,7 @@
 		    (ifp->if_bytes > 0)) {
 			ASSERT(ifp->if_u1.if_data != NULL);
 			ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
-			bcopy(ifp->if_u1.if_data, cp, ifp->if_bytes);
+			memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes);
 		}
 		if (whichfork == XFS_DATA_FORK) {
 			if (XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip)) {
@@ -2753,7 +2756,7 @@
 		if ((iip->ili_format.ilf_fields & extflag[whichfork]) &&
 		    (ifp->if_bytes > 0)) {
 			ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
-			(void)xfs_iextents_copy(ip, (xfs_bmbt_rec_32_t *)cp,
+			(void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
 				whichfork);
 		}
 		break;
@@ -2781,7 +2784,7 @@
 	case XFS_DINODE_FMT_UUID:
 		if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) {
 			ASSERT(whichfork == XFS_DATA_FORK);
-			bcopy(&ip->i_df.if_u2.if_uuid, &dip->di_u.di_muuid,
+			memcpy(&dip->di_u.di_muuid, &ip->i_df.if_u2.if_uuid,
 				sizeof(uuid_t));
 		}
 		break;
@@ -3208,8 +3211,8 @@
 			INT_SET(dip->di_core.di_version, ARCH_CONVERT, XFS_DINODE_VERSION_2);
 			ip->i_d.di_onlink = 0;
 			INT_ZERO(dip->di_core.di_onlink, ARCH_CONVERT);
-			bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
-			bzero(&(dip->di_core.di_pad[0]),
+			memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
+			memset(&(dip->di_core.di_pad[0]), 0,
 			      sizeof(dip->di_core.di_pad));
 			ASSERT(ip->i_d.di_projid == 0);
 		}
@@ -3377,7 +3380,7 @@
 			 * entry in the list anyway so we'll know below
 			 * whether we reached the end or not.
 			 */
-			VMAP(vp, ip, vmap);
+			VMAP(vp, vmap);
 			vp->v_flag |= VPURGE;		/* OK for vn_purge */
 			XFS_MOUNT_IUNLOCK(mp);
 
diff -Nru a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
--- a/fs/xfs/xfs_inode.h	Tue Oct 15 20:29:19 2002
+++ b/fs/xfs/xfs_inode.h	Tue Oct 15 20:29:19 2002
@@ -98,7 +98,6 @@
 struct xfs_mount;
 struct xfs_trans;
 struct xfs_dquot;
-struct pm;
 
 
 /*
@@ -119,23 +118,6 @@
 	xfs_extlen_t	xg_count_fsb;
 } xfs_gap_t;
 
-/*
- * This structure is used to hold common pieces of the buffer
- * and file for xfs_dio_write and xfs_dio_read.
- */
-typedef struct xfs_dio {
-	struct xfs_buf	*xd_bp;
-	bhv_desc_t	*xd_bdp;
-	struct xfs_inode *xd_ip;
-	struct xfs_iocore *xd_io;
-	struct cred	*xd_cr;
-	struct pm	*xd_pmp;
-	int		xd_blkalgn;
-	int		xd_ioflag;
-	xfs_off_t	xd_start;
-	size_t		xd_length;
-} xfs_dio_t;
-
 typedef struct dm_attrs_s {
 	__uint32_t	da_dmevmask;	/* DMIG event mask */
 	__uint16_t	da_dmstate;	/* DMIG state info */
@@ -516,7 +498,7 @@
 			  xfs_inode_t **, xfs_daddr_t);
 int		xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int);
 int		xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, nlink_t,
-			   dev_t, struct cred *, xfs_prid_t, int,
+			   xfs_dev_t, struct cred *, xfs_prid_t, int,
 			   struct xfs_buf **, boolean_t *, xfs_inode_t **);
 void		xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *, int,
 			   xfs_arch_t);
@@ -538,7 +520,7 @@
 void		xfs_iroot_realloc(xfs_inode_t *, int, int);
 void		xfs_ipin(xfs_inode_t *);
 void		xfs_iunpin(xfs_inode_t *);
-int		xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_32_t *, int);
+int		xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_t *, int);
 int		xfs_iflush(xfs_inode_t *, uint);
 int		xfs_iflush_all(struct xfs_mount *, int);
 int		xfs_ibusy_check(xfs_inode_t *, int);
@@ -550,7 +532,7 @@
 
 #define xfs_ipincount(ip)	((unsigned int) atomic_read(&ip->i_pincount))
 
-
+void xfs_revalidate_inode(struct xfs_mount *, vnode_t *vp, xfs_inode_t *);
 
 #ifdef DEBUG
 void		xfs_isize_check(struct xfs_mount *, xfs_inode_t *, xfs_fsize_t);
diff -Nru a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
--- a/fs/xfs/xfs_inode_item.c	Tue Oct 15 20:29:19 2002
+++ b/fs/xfs/xfs_inode_item.c	Tue Oct 15 20:29:19 2002
@@ -96,7 +96,7 @@
 			if (iip->ili_root_size > 0) {
 				ASSERT(iip->ili_root_size ==
 				       ip->i_df.if_broot_bytes);
-				ASSERT(bcmp(iip->ili_orig_root,
+				ASSERT(memcmp(iip->ili_orig_root,
 					    ip->i_df.if_broot,
 					    iip->ili_root_size) == 0);
 			} else {
@@ -214,7 +214,7 @@
 	xfs_log_iovec_t		*vecp;
 	xfs_inode_t		*ip;
 	size_t			data_bytes;
-	xfs_bmbt_rec_32_t	*ext_buffer;
+	xfs_bmbt_rec_t		*ext_buffer;
 	int			nrecs;
 	xfs_mount_t		*mp;
 
@@ -297,7 +297,7 @@
 			 */
 			ip->i_d.di_version = XFS_DINODE_VERSION_2;
 			ip->i_d.di_onlink = 0;
-			bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
+			memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
 		}
 	}
 
@@ -314,6 +314,7 @@
 			nrecs = ip->i_df.if_bytes /
 				(uint)sizeof(xfs_bmbt_rec_t);
 			ASSERT(nrecs > 0);
+#if ARCH_CONVERT == ARCH_NOCONVERT
 			if (nrecs == ip->i_d.di_nextents) {
 				/*
 				 * There are no delayed allocation
@@ -323,10 +324,14 @@
 				vecp->i_addr =
 					(char *)(ip->i_df.if_u1.if_extents);
 				vecp->i_len = ip->i_df.if_bytes;
-			} else {
+			} else 
+#endif
+			{
 				/*
 				 * There are delayed allocation extents
-				 * in the inode.  Use xfs_iextents_copy()
+				 * in the inode, or we need to convert
+				 * the extents to on disk format.
+				 * Use xfs_iextents_copy()
 				 * to copy only the real extents into
 				 * a separate buffer.  We'll free the
 				 * buffer in the unlock routine.
@@ -336,7 +341,7 @@
 				iip->ili_extents_buf = ext_buffer;
 				vecp->i_addr = (xfs_caddr_t)ext_buffer;
 				vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
-					XFS_DATA_FORK);
+						XFS_DATA_FORK);
 			}
 			ASSERT(vecp->i_len <= ip->i_df.if_bytes);
 			iip->ili_format.ilf_dsize = vecp->i_len;
@@ -428,6 +433,7 @@
 		ASSERT(!(iip->ili_format.ilf_fields &
 			 (XFS_ILOG_ADATA | XFS_ILOG_ABROOT)));
 		if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) {
+			ASSERT(!(iip->ili_format.ilf_fields & XFS_ILOG_DEXT));
 			ASSERT(ip->i_afp->if_bytes > 0);
 			ASSERT(ip->i_afp->if_u1.if_extents != NULL);
 			ASSERT(ip->i_d.di_anextents > 0);
@@ -437,12 +443,25 @@
 #endif
 			ASSERT(nrecs > 0);
 			ASSERT(nrecs == ip->i_d.di_anextents);
+#if ARCH_CONVERT == ARCH_NOCONVERT
 			/*
 			 * There are not delayed allocation extents
 			 * for attributes, so just point at the array.
 			 */
 			vecp->i_addr = (char *)(ip->i_afp->if_u1.if_extents);
 			vecp->i_len = ip->i_afp->if_bytes;
+#else		
+			ASSERT(iip->ili_aextents_buf == NULL);
+			/*
+			 * Need to endian flip before logging
+			 */
+			ext_buffer = kmem_alloc(ip->i_df.if_bytes,
+				KM_SLEEP);
+			iip->ili_aextents_buf = ext_buffer;
+			vecp->i_addr = (xfs_caddr_t)ext_buffer;
+			vecp->i_len = xfs_iextents_copy(ip, ext_buffer,
+					XFS_ATTR_FORK);
+#endif
 			iip->ili_format.ilf_asize = vecp->i_len;
 			vecp++;
 			nvecs++;
@@ -630,7 +649,6 @@
 	 * If the inode needed a separate buffer with which to log
 	 * its extents, then free it now.
 	 */
-	/* FIXME */
 	if (iip->ili_extents_buf != NULL) {
 		ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS);
 		ASSERT(ip->i_d.di_nextents > 0);
@@ -639,6 +657,14 @@
 		kmem_free(iip->ili_extents_buf, ip->i_df.if_bytes);
 		iip->ili_extents_buf = NULL;
 	}
+	if (iip->ili_aextents_buf != NULL) {
+		ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS);
+		ASSERT(ip->i_d.di_anextents > 0);
+		ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_AEXT);
+		ASSERT(ip->i_afp->if_bytes > 0);
+		kmem_free(iip->ili_aextents_buf, ip->i_afp->if_bytes);
+		iip->ili_aextents_buf = NULL;
+	}
 
 	/*
 	 * Figure out if we should unlock the inode or not.
@@ -889,7 +915,7 @@
 	iip->ili_inode = ip;
 
 	/*
-	   We have bzeroed memory. No need ...
+	   We have zeroed memory. No need ...
 	   iip->ili_extents_buf = NULL;
 	   iip->ili_pushbuf_flag = 0;
 	 */
diff -Nru a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
--- a/fs/xfs/xfs_inode_item.h	Tue Oct 15 20:29:21 2002
+++ b/fs/xfs/xfs_inode_item.h	Tue Oct 15 20:29:21 2002
@@ -141,7 +141,10 @@
 	unsigned short		ili_flags;	   /* misc flags */
 	unsigned short		ili_logged;	   /* flushed logged data */
 	unsigned int		ili_last_fields;   /* fields when flushed */
-	struct xfs_bmbt_rec_32	*ili_extents_buf;  /* array of logged exts */
+	struct xfs_bmbt_rec_32	*ili_extents_buf;  /* array of logged
+						      data exts */
+	struct xfs_bmbt_rec_32	*ili_aextents_buf; /* array of logged
+						      attr exts */
 	unsigned int		ili_pushbuf_flag;  /* one bit used in push_ail */
 
 #ifdef DEBUG
diff -Nru a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
--- a/fs/xfs/xfs_itable.c	Tue Oct 15 20:29:12 2002
+++ b/fs/xfs/xfs_itable.c	Tue Oct 15 20:29:12 2002
@@ -146,7 +146,7 @@
 	buf->bs_extsize = INT_GET(dic->di_extsize, arch) << mp->m_sb.sb_blocklog;
 	buf->bs_extents = INT_GET(dic->di_nextents, arch);
 	buf->bs_gen = INT_GET(dic->di_gen, arch);
-	bzero(buf->bs_pad, sizeof(buf->bs_pad));
+	memset(buf->bs_pad, 0, sizeof(buf->bs_pad));
 	buf->bs_dmevmask = INT_GET(dic->di_dmevmask, arch);
 	buf->bs_dmstate = INT_GET(dic->di_dmstate, arch);
 	buf->bs_aextents = INT_GET(dic->di_anextents, arch);
diff -Nru a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
--- a/fs/xfs/xfs_log.c	Tue Oct 15 20:29:23 2002
+++ b/fs/xfs/xfs_log.c	Tue Oct 15 20:29:23 2002
@@ -1586,8 +1586,8 @@
  *		1. If first write of transaction, write start record
  *		2. Write log operation header (header per region)
  *		3. Find out if we can fit entire region into this iclog
- *		4. Potentially, verify destination bcopy ptr
- *		5. Bcopy (partial) region
+ *		4. Potentially, verify destination memcpy ptr
+ *		5. Memcpy (partial) region
  *		6. If partial copy, release iclog; otherwise, continue
  *			copying more regions into current iclog
  *	4. Mark want sync bit (in simulation mode)
@@ -1628,8 +1628,8 @@
     int		     start_rec_copy; /* # bytes to copy for start record */
     int		     partial_copy;   /* did we split a region? */
     int		     partial_copy_len;/* # bytes copied if split region */
-    int		     need_copy;	     /* # bytes need to bcopy this region */
-    int		     copy_len;	     /* # bytes actually bcopy'ing */
+    int		     need_copy;	     /* # bytes need to memcpy this region */
+    int		     copy_len;	     /* # bytes actually memcpy'ing */
     int		     copy_off;	     /* # bytes from entry start */
     int		     contwr;	     /* continued write of in-core log? */
     int		     firstwr = 0;    /* first write of transaction */
@@ -1733,7 +1733,7 @@
 
 	    /* Partial write last time? => (partial_copy != 0)
 	     * need_copy is the amount we'd like to copy if everything could
-	     * fit in the current bcopy.
+	     * fit in the current memcpy.
 	     */
 	    need_copy = reg[index].i_len - partial_copy_len;
 
@@ -1759,7 +1759,7 @@
 
 	    /* copy region */
 	    ASSERT(copy_len >= 0);
-	    bcopy(reg[index].i_addr + copy_off, (xfs_caddr_t)ptr, copy_len);
+	    memcpy((xfs_caddr_t)ptr, reg[index].i_addr + copy_off, copy_len);
 	    xlog_write_adv_cnt(ptr, len, log_offset, copy_len);
 
 	    /* make copy_len total bytes copied, including headers */
@@ -1836,7 +1836,7 @@
 				changed = 2;
 			}
 			INT_ZERO(iclog->ic_header.h_num_logops, ARCH_CONVERT);
-			bzero(iclog->ic_header.h_cycle_data,
+			memset(iclog->ic_header.h_cycle_data, 0,
 			      sizeof(iclog->ic_header.h_cycle_data));
 			INT_ZERO(iclog->ic_header.h_lsn, ARCH_CONVERT);
 		} else if (iclog->ic_state == XLOG_STATE_ACTIVE)
@@ -2064,7 +2064,7 @@
 		} while (first_iclog != iclog);
 		if (repeats && (repeats % 10) == 0) {
 			xfs_fs_cmn_err(CE_WARN, log->l_mp,
-				"xlog_state_do_callback: looping %d\n", repeats);
+				"xlog_state_do_callback: looping %d", repeats);
 		}
 	} while (!ioerrors && loopdidcallbacks);
 
@@ -2155,20 +2155,13 @@
 		iclog->ic_state = XLOG_STATE_DONE_SYNC;
 	}
 
-	/*
-	 * Someone could be sleeping on the next iclog even though it is
-	 * in the ACTIVE state.	 We kick off one thread to force the
-	 * iclog buffer out.
-	 */
-	if (iclog->ic_next->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR))
-		sv_signal(&iclog->ic_next->ic_forcesema);
 	LOG_UNLOCK(log, s);
 	xlog_state_do_callback(log, aborted, iclog);	/* also cleans log */
 }	/* xlog_state_done_syncing */
 
 
 /*
- * Update counters atomically now that bcopy is done.
+ * Update counters atomically now that memcpy is done.
  */
 /* ARGSUSED */
 static inline void
@@ -2984,11 +2977,9 @@
 		uint	  flags)
 {
     xlog_in_core_t	*iclog;
-    int			already_slept = 0;
     SPLDECL(s);
 
 
-try_again:
     s = LOG_LOCK(log);
     iclog = log->l_iclog;
 
@@ -3009,39 +3000,12 @@
 	}
 
 	if (iclog->ic_state == XLOG_STATE_ACTIVE) {
-		/*
-		 * We sleep here if we haven't already slept (e.g.
-		 * this is the first time we've looked at the correct
-		 * iclog buf) and the buffer before us is going to
-		 * be sync'ed.	We have to do that to ensure that the
-		 * log records go out in the proper order.  When it's
-		 * done, someone waiting on this buffer will be woken up
-		 * (maybe us) to flush this buffer out.
-		 *
-		 * Otherwise, we mark the buffer WANT_SYNC, and bump
-		 * up the refcnt so we can release the log (which drops
-		 * the ref count).  The state switch keeps new transaction
-		 * commits from using this buffer.  When the current commits
-		 * finish writing into the buffer, the refcount will drop to
-		 * zero and the buffer will go out then.
-		 */
-		if (!already_slept &&
-		    (iclog->ic_prev->ic_state & (XLOG_STATE_WANT_SYNC |
-						 XLOG_STATE_SYNCING))) {
-			ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR));
-			XFS_STATS_INC(xfsstats.xs_log_force_sleep);
-			sv_wait(&iclog->ic_prev->ic_forcesema, PSWP,
-				&log->l_icloglock, s);
-			already_slept = 1;
-			goto try_again;
-		} else {
-			iclog->ic_refcnt++;
-			xlog_state_switch_iclogs(log, iclog, 0);
-			LOG_UNLOCK(log, s);
-			if (xlog_state_release_iclog(log, iclog))
-				return XFS_ERROR(EIO);
-			s = LOG_LOCK(log);
-		}
+		iclog->ic_refcnt++;
+		xlog_state_switch_iclogs(log, iclog, 0);
+		LOG_UNLOCK(log, s);
+		if (xlog_state_release_iclog(log, iclog))
+			return XFS_ERROR(EIO);
+		s = LOG_LOCK(log);
 	}
 
 	if ((flags & XFS_LOG_SYNC) && /* sleep */
diff -Nru a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
--- a/fs/xfs/xfs_log_recover.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_log_recover.c	Tue Oct 15 20:29:17 2002
@@ -476,7 +476,7 @@
 	     * mkfs etc write a dummy unmount record to a fresh
 	     * log so we can store the uuid in there
 	     */
-	    xlog_warn("XFS: totally zeroed log\n");
+	    xlog_warn("XFS: totally zeroed log");
 	}
 
 	return 0;
@@ -873,9 +873,19 @@
 	 * overwrite the unmount record after a clean unmount.
 	 *
 	 * Do this only if we are going to recover the filesystem
+	 *
+	 * NOTE: This used to say "if (!readonly)"
+	 * However on Linux, we can & do recover a read-only filesystem.
+	 * We only skip recovery if NORECOVERY is specified on mount,
+	 * in which case we would not be here.
+	 *
+	 * But... if the -device- itself is readonly, just skip this.
+	 * We can't recover this device anyway, so it won't matter.
 	 */
-	if (!readonly)
+
+	if (!bdev_read_only(log->l_mp->m_logdev_targp->pbr_bdev)) {
 		error = xlog_clear_stale_blocks(log, tail_lsn);
+	}
 #endif
 
 bread_err:
@@ -1242,7 +1252,7 @@
 		/* finish copying rest of trans header */
 		xlog_recover_add_item(&trans->r_itemq);
 		ptr = (xfs_caddr_t)&trans->r_theader+sizeof(xfs_trans_header_t)-len;
-		bcopy(dp, ptr, len); /* s, d, l */
+		memcpy(ptr, dp, len); /* d, s, l */
 		return 0;
 	}
 	item = item->ri_prev;
@@ -1251,7 +1261,7 @@
 	old_len = item->ri_buf[item->ri_cnt-1].i_len;
 
 	ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0);
-	bcopy(dp , &ptr[old_len], len); /* s, d, l */
+	memcpy(&ptr[old_len], dp, len); /* d, s, l */
 	item->ri_buf[item->ri_cnt-1].i_len += len;
 	item->ri_buf[item->ri_cnt-1].i_addr = ptr;
 	return 0;
@@ -1282,7 +1292,7 @@
 	if (!len)
 		return 0;
 	ptr = kmem_zalloc(len, 0);
-	bcopy(dp, ptr, len);
+	memcpy(ptr, dp, len);
 
 	in_f = (xfs_inode_log_format_t *)ptr;
 	item = trans->r_itemq;
@@ -1290,7 +1300,7 @@
 		ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC);
 		if (len == sizeof(xfs_trans_header_t))
 			xlog_recover_add_item(&trans->r_itemq);
-		bcopy(dp, &trans->r_theader, len); /* s, d, l */
+		memcpy(&trans->r_theader, dp, len); /* d, s, l */
 		return 0;
 	}
 	if (item->ri_prev->ri_total != 0 &&
@@ -1799,9 +1809,10 @@
 					       "dquot_buf_recover");
 		}
 		if (!error)
-		    bcopy(item->ri_buf[i].i_addr,		   /* source */
-		      xfs_buf_offset(bp, (uint)bit << XFS_BLI_SHIFT), /* dest */
-		      nbits<<XFS_BLI_SHIFT);			   /* length */
+			memcpy(xfs_buf_offset(bp,
+					(uint)bit << XFS_BLI_SHIFT),	/* dest */
+				item->ri_buf[i].i_addr,			/* source */
+				nbits<<XFS_BLI_SHIFT);			/* length */
 		i++;
 		bit += nbits;
 	}
@@ -2115,9 +2126,9 @@
 			      -1, ARCH_CONVERT);
 	/* the rest is in on-disk format */
 	if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) {
-		bcopy(item->ri_buf[1].i_addr + sizeof(xfs_dinode_core_t),
-		      (xfs_caddr_t) dip		 + sizeof(xfs_dinode_core_t),
-		      item->ri_buf[1].i_len  - sizeof(xfs_dinode_core_t));
+		memcpy((xfs_caddr_t) dip + sizeof(xfs_dinode_core_t),
+			item->ri_buf[1].i_addr + sizeof(xfs_dinode_core_t),
+			item->ri_buf[1].i_len  - sizeof(xfs_dinode_core_t));
 	}
 
 	fields = in_f->ilf_fields;
@@ -2143,7 +2154,7 @@
 	switch (fields & XFS_ILOG_DFORK) {
 	case XFS_ILOG_DDATA:
 	case XFS_ILOG_DEXT:
-		bcopy(src, &dip->di_u, len);
+		memcpy(&dip->di_u, src, len);
 		break;
 
 	case XFS_ILOG_DBROOT:
@@ -2182,7 +2193,7 @@
 		case XFS_ILOG_AEXT:
 			dest = XFS_DFORK_APTR(dip);
 			ASSERT(len <= XFS_DFORK_ASIZE(dip, mp));
-			bcopy(src, dest, len);
+			memcpy(dest, src, len);
 			break;
 
 		case XFS_ILOG_ABROOT:
@@ -2341,7 +2352,7 @@
 		return XFS_ERROR(EIO);
 	}
 
-	bcopy(recddq, ddq, item->ri_buf[1].i_len);
+	memcpy(ddq, recddq, item->ri_buf[1].i_len);
 
 	ASSERT(dq_f->qlf_size == 2);
 	ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL ||
@@ -2382,7 +2393,7 @@
 
 	mp = log->l_mp;
 	efip = xfs_efi_init(mp, efi_formatp->efi_nextents);
-	bcopy((char *)efi_formatp, (char *)&(efip->efi_format),
+	memcpy((char *)&(efip->efi_format), (char *)efi_formatp,
 	      sizeof(xfs_efi_log_format_t) +
 	      ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t)));
 	efip->efi_next_extent = efi_formatp->efi_nextents;
@@ -3131,7 +3142,7 @@
 "XFS: Disregard message if filesystem was created with non-DEBUG kernel");
 		    if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
 			    cmn_err(CE_DEBUG,
-				"XFS: LogR this is a LogV2 filesystem\n");
+				"XFS: LogR this is a LogV2 filesystem");
 		    }
 		    log->l_flags |= XLOG_CHKSUM_MISMATCH;
 	    }
@@ -3215,7 +3226,7 @@
 	return ENOMEM;
     }
 
-    bzero(rhash, sizeof(rhash));
+    memset(rhash, 0, sizeof(rhash));
     if (tail_blk <= head_blk) {
 	for (blk_no = tail_blk; blk_no < head_blk; ) {
 	    if ((error = xlog_bread(log, blk_no, hblks, hbp)))
@@ -3521,17 +3532,20 @@
 		 * error message.
 		 * ...but this is no longer true.  Now, unless you specify
 		 * NORECOVERY (in which case this function would never be
-		 * called), it enables read-write access long enough to do
-		 * recovery.
+		 * called), we just go ahead and recover.  We do this all
+		 * under the vfs layer, so we can get away with it unless
+		 * the device itself is read-only, in which case we fail.
 		 */
-		if (readonly) {
 #ifdef __KERNEL__
-			if ((error = xfs_recover_read_only(log)))
-				return error;
+		if ((error = xfs_dev_is_read_only(log->l_mp,
+						"recovery required"))) {
+			return error;
+		}
 #else
+		if (readonly) {
 			return ENOSPC;
-#endif
 		}
+#endif
 
 #ifdef __KERNEL__
 #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
@@ -3548,8 +3562,6 @@
 #endif
 		error = xlog_do_recover(log, head_blk, tail_blk);
 		log->l_flags |= XLOG_RECOVERY_NEEDED;
-		if (readonly)
-			XFS_MTOVFS(log->l_mp)->vfs_flag |= VFS_RDONLY;
 	}
 	return error;
 }	/* xlog_recover */
@@ -3607,7 +3619,7 @@
 		log->l_flags &= ~XLOG_RECOVERY_NEEDED;
 	} else {
 		cmn_err(CE_DEBUG,
-			"!Ending clean XFS mount for filesystem: %s\n",
+			"!Ending clean XFS mount for filesystem: %s",
 			log->l_mp->m_fsname);
 	}
 	return 0;
diff -Nru a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
--- a/fs/xfs/xfs_mount.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/xfs_mount.c	Tue Oct 15 20:29:16 2002
@@ -31,6 +31,13 @@
  */
 
 #include <xfs.h>
+#include <linux/major.h>
+#include <linux/namei.h>
+#include <linux/pagemap.h>
+
+#ifndef EVMS_MAJOR
+#define EVMS_MAJOR	117
+#endif
 
 STATIC void	xfs_mount_reset_sbqflags(xfs_mount_t *);
 STATIC void	xfs_mount_log_sbunit(xfs_mount_t *, __int64_t);
@@ -375,9 +382,9 @@
 		    size == 1 ||
 		    xfs_sb_info[f].type == 1) {
 			if (dir > 0) {
-				bcopy(buf_ptr + first, mem_ptr + first, size);
+				memcpy(mem_ptr + first, buf_ptr + first, size);
 			} else {
-				bcopy(mem_ptr + first, buf_ptr + first, size);
+				memcpy(buf_ptr + first, mem_ptr + first, size);
 			}
 		} else {
 			switch (size) {
@@ -673,7 +680,7 @@
 		}
 		uuid_mounted=1;
 		ret64 = uuid_hash64(&sbp->sb_uuid);
-		bcopy(&ret64, &vfsp->vfs_fsid, sizeof(ret64));
+		memcpy(&vfsp->vfs_fsid, &ret64, sizeof(ret64));
 	}
 
 	/*
@@ -904,7 +911,7 @@
 	rvp = XFS_ITOV(rip);
 	if ((rip->i_d.di_mode & IFMT) != IFDIR) {
 		cmn_err(CE_WARN, "XFS: corrupted root inode");
-		VMAP(rvp, rip, vmap);
+		VMAP(rvp, vmap);
 		prdev("Root inode %llu is not a directory",
 		      mp->m_dev, (unsigned long long)rip->i_ino);
 		rvp->v_flag |= VPURGE;
@@ -930,8 +937,7 @@
 
 	if (((quotaondisk && !XFS_IS_QUOTA_ON(mp)) ||
 	      (!quotaondisk && XFS_IS_QUOTA_ON(mp))) &&
-	    (bdev_read_only(mp->m_ddev_targp->pbr_bdev) ||
-	     bdev_read_only(mp->m_logdev_targp->pbr_bdev))) {
+	      xfs_dev_is_read_only(mp, "changing quota state")) {
 		cmn_err(CE_WARN,
 			"XFS: device %s is read-only, cannot change "
 			"quota state.  Please mount with%s quota option.",
@@ -952,7 +958,7 @@
 		 */
 		cmn_err(CE_WARN, "XFS: failed to read RT inodes");
 		rvp->v_flag |= VPURGE;
-		VMAP(rvp, rip, vmap);
+		VMAP(rvp, vmap);
 		VN_RELE(rvp);
 		vn_purge(rvp, &vmap);
 		goto error3;
@@ -1023,14 +1029,12 @@
 	if (needquotamount) {
 		ASSERT(mp->m_qflags == 0);
 		mp->m_qflags = quotaflags;
-		rootqcheck = ((XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) &&
-				mp->m_dev == rootdev && needquotacheck);
-		if (rootqcheck && (error = xfs_quotacheck_read_only(mp)))
+		rootqcheck = (mp->m_dev == rootdev && needquotacheck);
+		if (rootqcheck && (error = xfs_dev_is_read_only(mp,
+					"quotacheck")))
 			goto error2;
 		if (xfs_qm_mount_quotas(mp))
 			xfs_mount_reset_sbqflags(mp);
-		if (rootqcheck)
-			XFS_MTOVFS(mp)->vfs_flag |= VFS_RDONLY;
 	}
 
 #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
@@ -1135,7 +1139,7 @@
 	/*
 	 * clear all error tags on this filesystem
 	 */
-	bcopy(&(XFS_MTOVFS(mp)->vfs_fsid), &fsid, sizeof(int64_t));
+	memcpy(&fsid, &(XFS_MTOVFS(mp)->vfs_fsid), sizeof(int64_t));
 	(void) xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0);
 #endif
 
@@ -1149,15 +1153,17 @@
 	int		have_logdev = (mp->m_logdev_targp != mp->m_ddev_targp);
 
 	if (mp->m_ddev_targp) {
-		pagebuf_lock_disable(mp->m_ddev_targp, 0);
+		xfs_free_buftarg(mp->m_ddev_targp);
 		mp->m_ddev_targp = NULL;
 	}
 	if (mp->m_rtdev_targp) {
-		pagebuf_lock_disable(mp->m_rtdev_targp, 1);
+		xfs_blkdev_put(mp->m_rtdev_targp->pbr_bdev);
+		xfs_free_buftarg(mp->m_rtdev_targp);
 		mp->m_rtdev_targp = NULL;
 	}
 	if (mp->m_logdev_targp && have_logdev) {
-		pagebuf_lock_disable(mp->m_logdev_targp, 1);
+		xfs_blkdev_put(mp->m_logdev_targp->pbr_bdev);
+		xfs_free_buftarg(mp->m_logdev_targp);
 		mp->m_logdev_targp = NULL;
 	}
 }
@@ -1724,4 +1730,72 @@
 
 	if (level == XFS_FREEZE_TRANS)
 		atomic_inc(&mp->m_active_trans);
+}
+
+int
+xfs_blkdev_get(
+	const char		*name,
+	struct block_device	**bdevp)
+{
+	struct nameidata	nd;
+	int			error = 0;
+
+	error = path_lookup(name, LOOKUP_FOLLOW, &nd);
+	if (error) {
+		printk("XFS: Invalid device [%s], error=%d\n",
+				name, error);
+		return error;
+	}
+
+	/* I think we actually want bd_acquire here..  --hch */
+	*bdevp = bdget(kdev_t_to_nr(nd.dentry->d_inode->i_rdev));
+	if (*bdevp) {
+		error = blkdev_get(*bdevp, FMODE_READ|FMODE_WRITE, 0, BDEV_FS);
+	} else {
+		error = -ENOMEM;
+	}
+
+	path_release(&nd);
+	return -error;
+}
+
+void
+xfs_blkdev_put(
+	struct block_device	*bdev)
+{
+	blkdev_put(bdev, BDEV_FS);
+}
+
+void
+xfs_free_buftarg(
+	xfs_buftarg_t		*btp)
+{
+	pagebuf_delwri_flush(btp, PBDF_WAIT, NULL);
+	kfree(btp);
+}
+
+xfs_buftarg_t *
+xfs_alloc_buftarg(
+	struct block_device	*bdev)
+{
+	xfs_buftarg_t		*btp;
+
+	btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
+
+	btp->pbr_dev =  bdev->bd_dev;
+	btp->pbr_bdev = bdev;
+	btp->pbr_mapping = bdev->bd_inode->i_mapping;
+	btp->pbr_blocksize = PAGE_CACHE_SIZE;
+
+	switch (MAJOR(btp->pbr_dev)) {
+	case MD_MAJOR:
+	case EVMS_MAJOR:
+		btp->pbr_flags = PBR_ALIGNED_ONLY;
+		break;
+	case LVM_BLK_MAJOR:
+		btp->pbr_flags = PBR_SECTOR_ONLY;
+		break;
+	}
+
+	return btp;
 }
diff -Nru a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
--- a/fs/xfs/xfs_mount.h	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/xfs_mount.h	Tue Oct 15 20:29:11 2002
@@ -77,7 +77,6 @@
 struct xfs_perag;
 struct xfs_quotainfo;
 struct xfs_iocore;
-struct xfs_dio;
 struct xfs_bmbt_irec;
 struct xfs_bmap_free;
 
@@ -96,24 +95,18 @@
  * minimize the number of memory indirections involved.
  */
 
-typedef int		(*xfs_dio_write_t)(struct xfs_dio *);
-typedef int		(*xfs_dio_read_t)(struct xfs_dio *);
-typedef int		(*xfs_strat_write_t)(struct xfs_iocore *, struct xfs_buf *);
 typedef int		(*xfs_bmapi_t)(struct xfs_trans *, void *,
 				xfs_fileoff_t, xfs_filblks_t, int,
 				xfs_fsblock_t *, xfs_extlen_t,
 				struct xfs_bmbt_irec *, int *,
 				struct xfs_bmap_free *);
 typedef int		(*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *);
-typedef int		(*xfs_rsync_t)(void *, int, xfs_off_t, xfs_off_t);
-typedef uint		(*xfs_lck_map_shared_t)(void *);
 typedef void		(*xfs_lock_t)(void *, uint);
 typedef void		(*xfs_lock_demote_t)(void *, uint);
 typedef int		(*xfs_lock_nowait_t)(void *, uint);
 typedef void		(*xfs_unlk_t)(void *, unsigned int);
 typedef void		(*xfs_chgtime_t)(void *, int);
 typedef xfs_fsize_t	(*xfs_size_t)(void *);
-typedef xfs_fsize_t	(*xfs_setsize_t)(void *, xfs_off_t);
 typedef xfs_fsize_t	(*xfs_lastbyte_t)(void *);
 
 typedef struct xfs_ioops {
@@ -295,8 +288,7 @@
 #define XFS_MOUNT_NOUUID	0x00004000	/* ignore uuid during mount */
 #define XFS_MOUNT_32BITINODES	0x00008000	/* do not create inodes above
 						 * 32 bits in size */
-#define XFS_MOUNT_IRIXSGID	0x00010000	/* Irix-style sgid inheritance */
-#define XFS_MOUNT_NOLOGFLUSH	0x00020000
+#define XFS_MOUNT_NOLOGFLUSH	0x00010000
 
 /*
  * Flags for m_cxfstype
@@ -435,6 +427,11 @@
 int		xfs_syncsub(xfs_mount_t *, int, int, int *);
 void		xfs_initialize_perag(xfs_mount_t *, int);
 void		xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t);
+
+int		xfs_blkdev_get(const char *, struct block_device **);
+void		xfs_blkdev_put(struct block_device *);
+struct xfs_buftarg *xfs_alloc_buftarg(struct block_device *);
+void		xfs_free_buftarg(struct xfs_buftarg *);
 
 /*
  * Flags for freeze operations.
diff -Nru a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
--- a/fs/xfs/xfs_qm.c	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/xfs_qm.c	Tue Oct 15 20:29:11 2002
@@ -1039,14 +1039,14 @@
 		vp = XFS_ITOV(XFS_QI_UQIP(mp));
 		VN_RELE(vp);
 		if (vn_count(vp) > 1)
-			cmn_err(CE_WARN, "UQUOTA busy vp=0x%x count=%d\n",
+			cmn_err(CE_WARN, "UQUOTA busy vp=0x%x count=%d",
 				vp, vn_count(vp));
 	}
 	if (XFS_IS_GQUOTA_ON(mp)) {
 		vp = XFS_ITOV(XFS_QI_GQIP(mp));
 		VN_RELE(vp);
 		if (vn_count(vp) > 1)
-			cmn_err(CE_WARN, "GQUOTA busy vp=0x%x count=%d\n",
+			cmn_err(CE_WARN, "GQUOTA busy vp=0x%x count=%d",
 				vp, vn_count(vp));
 	}
 
@@ -1427,9 +1427,9 @@
 		xfs_trans_cancel(tp, 0);
 		return (error);
 	}
-	bzero(&zerocr, sizeof(zerocr));
+	memset(&zerocr, 0, sizeof(zerocr));
 
-	if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, mp->m_dev,
+	if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, 0,
 				   &zerocr, 0, 1, ip, &committed))) {
 		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
 				 XFS_TRANS_ABORT);
@@ -1998,11 +1998,16 @@
 	int		error;
 	__int64_t	sbflags;
 	uint		flags;
+	int		readonly;
+	vfs_t		*vfsp;
 
 	ASSERT(mp->m_quotainfo);
 	uip = gip = NULL;
+	error = 0;
 	sbflags = 0;
 	flags = 0;
+	vfsp = XFS_MTOVFS(mp);
+	readonly = vfsp->vfs_flag & VFS_RDONLY;
 
 	/*
 	 * Get the uquota and gquota inodes
@@ -2036,36 +2041,34 @@
 	 * made above will get added to a transaction and logged in one of
 	 * the qino_alloc calls below.
 	 */
+
 	if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
-		if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY)
-			return XFS_ERROR(EROFS);
 		if ((error = xfs_qm_qino_alloc(mp, &uip,
 					      sbflags | XFS_SB_UQUOTINO,
 					      flags | XFS_QMOPT_UQUOTA)))
-			return XFS_ERROR(error);
+			goto error;
 
 		flags &= ~XFS_QMOPT_SBVERSION;
 	}
 	if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) {
-		if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) {
-			if (uip)
-				VN_RELE(XFS_ITOV(uip));
-			return XFS_ERROR(EROFS);
-		}
 		if ((error = xfs_qm_qino_alloc(mp, &gip,
 					      sbflags | XFS_SB_GQUOTINO,
 					      flags | XFS_QMOPT_GQUOTA))) {
 			if (uip)
 				VN_RELE(XFS_ITOV(uip));
 
-			return XFS_ERROR(error);
+			goto error;
 		}
 	}
 
 	XFS_QI_UQIP(mp) = uip;
 	XFS_QI_GQIP(mp) = gip;
 
-	return (0);
+error:
+	if (readonly)
+		vfsp->vfs_flag |= VFS_RDONLY;
+
+	return XFS_ERROR(error);
 }
 
 
@@ -2414,11 +2417,11 @@
 		if ((dqp = xfs_qm_dqreclaim_one())) {
 			XFS_STATS_INC(xfsstats.xs_qm_dqreclaims);
 			/*
-			 * Just bzero the core here. The rest will get
+			 * Just zero the core here. The rest will get
 			 * reinitialized by caller. XXX we shouldn't even
-			 * do this bzero ...
+			 * do this zero ...
 			 */
-			bzero(&dqp->q_core, sizeof(dqp->q_core));
+			memset(&dqp->q_core, 0, sizeof(dqp->q_core));
 			*O_dqpp = dqp;
 			return (B_FALSE);
 		}
diff -Nru a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
--- a/fs/xfs/xfs_qm_syscalls.c	Tue Oct 15 20:29:17 2002
+++ b/fs/xfs/xfs_qm_syscalls.c	Tue Oct 15 20:29:17 2002
@@ -550,7 +550,7 @@
 
 	uip = gip = NULL;
 	tempuqip = tempgqip = B_FALSE;
-	bzero(out, sizeof(fs_quota_stat_t));
+	memset(out, 0, sizeof(fs_quota_stat_t));
 
 	out->qs_version = FS_QSTAT_VERSION;
 	if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
@@ -885,7 +885,7 @@
 	xfs_disk_dquot_t	*src,
 	struct fs_disk_quota	*dst)
 {
-	bzero(dst, sizeof(*dst));
+	memset(dst, 0, sizeof(*dst));
 	dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
 	dst->d_flags =
 		xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT));
@@ -1060,7 +1060,7 @@
 			 * Sample vp mapping while holding the mplock, lest
 			 * we come across a non-existent vnode.
 			 */
-			VMAP(vp, ip, vmap);
+			VMAP(vp, vmap);
 			ireclaims = mp->m_ireclaims;
 			topino = mp->m_inodes;
 			XFS_MOUNT_IUNLOCK(mp);
diff -Nru a/fs/xfs/xfs_quota_priv.h b/fs/xfs/xfs_quota_priv.h
--- a/fs/xfs/xfs_quota_priv.h	Tue Oct 15 20:29:23 2002
+++ b/fs/xfs/xfs_quota_priv.h	Tue Oct 15 20:29:23 2002
@@ -181,7 +181,7 @@
 	  vmap_t dqvmap;		\
 	  vnode_t *dqvp;		\
 	  dqvp = XFS_ITOV(ip);		\
-	  VMAP(dqvp, ip, dqvmap);	\
+	  VMAP(dqvp, dqvmap);		\
 	  VN_RELE(dqvp);		\
 	}
 
diff -Nru a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
--- a/fs/xfs/xfs_rtalloc.c	Tue Oct 15 20:29:12 2002
+++ b/fs/xfs/xfs_rtalloc.c	Tue Oct 15 20:29:12 2002
@@ -170,7 +170,7 @@
 				error = XFS_ERROR(EIO);
 				goto error_exit;
 			}
-			bzero(XFS_BUF_PTR(bp), mp->m_sb.sb_blocksize);
+			memset(XFS_BUF_PTR(bp), 0, mp->m_sb.sb_blocksize);
 			xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
 			/*
 			 * Commit the transaction.
@@ -2322,7 +2322,7 @@
 		vmap_t		vmap;		/* vmap to delete vnode */
 
 		rbmvp = XFS_ITOV(mp->m_rbmip);
-		VMAP(rbmvp, mp->m_rbmip, vmap);
+		VMAP(rbmvp, vmap);
 		VN_RELE(rbmvp);
 		vn_purge(rbmvp, &vmap);
 		return error;
diff -Nru a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
--- a/fs/xfs/xfs_rw.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/xfs_rw.c	Tue Oct 15 20:29:16 2002
@@ -230,7 +230,7 @@
 	xfs_daddr_t		blkno)
 {
 	cmn_err(CE_ALERT,
- "I/O error in filesystem (\"%s\") meta-data dev 0x%x block 0x%llx\n"
+ "I/O error in filesystem (\"%s\") meta-data dev 0x%x block 0x%llx"
  "	 (\"%s\") error %d buf count %u",
 		(!mp || !mp->m_fsname) ? "(fs name not set)" : mp->m_fsname,
 		XFS_BUF_TARGET_DEV(bp),
@@ -362,7 +362,7 @@
 		XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
 		isize = XFS_SIZE(mp, io);
 		if (offset > isize) {
-			xfs_zero_eof(vp, io, offset, isize, offset, NULL);
+			xfs_zero_eof(vp, io, offset, isize, offset);
 		}
 		XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
 	}
diff -Nru a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h
--- a/fs/xfs/xfs_rw.h	Tue Oct 15 20:29:12 2002
+++ b/fs/xfs/xfs_rw.h	Tue Oct 15 20:29:12 2002
@@ -42,8 +42,6 @@
 struct xfs_iocore;
 struct xfs_mount;
 struct xfs_trans;
-struct xfs_dio;
-struct pm;
 
 /*
  * Maximum count of bmaps used by read and write paths.
diff -Nru a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
--- a/fs/xfs/xfs_trans.c	Tue Oct 15 20:29:16 2002
+++ b/fs/xfs/xfs_trans.c	Tue Oct 15 20:29:16 2002
@@ -788,6 +788,7 @@
 	commit_lsn = xfs_log_done(mp, tp->t_ticket, log_flags);
 #endif
 
+	tp->t_commit_lsn = commit_lsn;
 	if (nvec > XFS_TRANS_LOGVEC_COUNT) {
 		kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));
 	}
diff -Nru a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
--- a/fs/xfs/xfs_trans.h	Tue Oct 15 20:29:19 2002
+++ b/fs/xfs/xfs_trans.h	Tue Oct 15 20:29:19 2002
@@ -378,7 +378,10 @@
 	unsigned int		t_rtx_res_used; /* # of resvd rt extents used */
 	xfs_log_ticket_t	t_ticket;	/* log mgr ticket */
 	sema_t			t_sema;		/* sema for commit completion */
-	xfs_lsn_t		t_lsn;		/* log seq num of trans commit*/
+	xfs_lsn_t		t_lsn;		/* log seq num of start of
+						 * transaction. */
+	xfs_lsn_t		t_commit_lsn;	/* log seq num of end of 
+						 * transaction. */
 	struct xfs_mount	*t_mountp;	/* ptr to fs mount struct */
 	struct xfs_dquot_acct	*t_dqinfo;	/* accting info for dquots */
 	xfs_trans_callback_t	t_callback;	/* transaction callback */
diff -Nru a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
--- a/fs/xfs/xfs_trans_buf.c	Tue Oct 15 20:29:12 2002
+++ b/fs/xfs/xfs_trans_buf.c	Tue Oct 15 20:29:12 2002
@@ -472,7 +472,7 @@
 	 */
 #if defined(DEBUG)
 	if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp))
-		cmn_err(CE_NOTE, "about to pop assert, bp == 0x%x\n", bp);
+		cmn_err(CE_NOTE, "about to pop assert, bp == 0x%x", bp);
 #endif
 	ASSERT((XFS_BUF_BFLAGS(bp) & (XFS_B_STALE|XFS_B_DELWRI)) !=
 						(XFS_B_STALE|XFS_B_DELWRI));
@@ -880,7 +880,7 @@
 	bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_DIRTY);
 	bip->bli_format.blf_flags &= ~XFS_BLI_INODE_BUF;
 	bip->bli_format.blf_flags |= XFS_BLI_CANCEL;
-	bzero((char *)(bip->bli_format.blf_data_map),
+	memset((char *)(bip->bli_format.blf_data_map), 0,
 	      (bip->bli_format.blf_map_size * sizeof(uint)));
 	lidp->lid_flags |= XFS_LID_DIRTY;
 	tp->t_flags |= XFS_TRANS_DIRTY;
diff -Nru a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
--- a/fs/xfs/xfs_trans_inode.c	Tue Oct 15 20:29:11 2002
+++ b/fs/xfs/xfs_trans_inode.c	Tue Oct 15 20:29:11 2002
@@ -414,20 +414,8 @@
 		iip->ili_root_size = ip->i_df.if_broot_bytes;
 		iip->ili_orig_root =
 			(char*)kmem_alloc(iip->ili_root_size, KM_SLEEP);
-		bcopy((char*)(ip->i_df.if_broot), iip->ili_orig_root,
+		memcpy(iip->ili_orig_root, (char*)(ip->i_df.if_broot),
 		      iip->ili_root_size);
 	}
 }
 #endif
-
-
-
-
-
-
-
-
-
-
-
-
diff -Nru a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h
--- a/fs/xfs/xfs_types.h	Tue Oct 15 20:29:14 2002
+++ b/fs/xfs/xfs_types.h	Tue Oct 15 20:29:14 2002
@@ -308,23 +308,19 @@
 #endif	/* !CONFIG_PROC_FS */
 
 
+/*
+ * Juggle IRIX device numbers - still used in ondisk structures
+ */
+#define XFS_DEV_BITSMAJOR	14
+#define XFS_DEV_BITSMINOR	18
+#define XFS_DEV_MAXMAJ		0x1ff
+#define XFS_DEV_MAXMIN		0x3ffff
+#define XFS_DEV_MAJOR(dev)	((int)(((unsigned)(dev)>>XFS_DEV_BITSMINOR) \
+				    & XFS_DEV_MAXMAJ))
+#define XFS_DEV_MINOR(dev)	((int)((dev)&XFS_DEV_MAXMIN))
+#define XFS_MKDEV(major,minor) ((xfs_dev_t)(((major)<<XFS_DEV_BITSMINOR) \
+				    | (minor&XFS_DEV_MAXMIN)))
 
-/* juggle IRIX device numbers - still used in ondisk structures */
-
-#ifndef __KERNEL__
-#define MKDEV(major, minor)	makedev(major, minor)
-#endif
-
-#define IRIX_DEV_BITSMAJOR	14
-#define IRIX_DEV_BITSMINOR	18
-#define IRIX_DEV_MAXMAJ		0x1ff
-#define IRIX_DEV_MAXMIN		0x3ffff
-#define IRIX_DEV_MAJOR(dev)	((int)(((unsigned)(dev)>>IRIX_DEV_BITSMINOR) \
-				    & IRIX_DEV_MAXMAJ))
-#define IRIX_DEV_MINOR(dev)	((int)((dev)&IRIX_DEV_MAXMIN))
-#define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major)<<IRIX_DEV_BITSMINOR) \
-				    | (minor&IRIX_DEV_MAXMIN)))
-
-#define IRIX_DEV_TO_KDEVT(dev)	MKDEV(IRIX_DEV_MAJOR(dev),IRIX_DEV_MINOR(dev))
+#define XFS_DEV_TO_KDEVT(dev)	mk_kdev(XFS_DEV_MAJOR(dev),XFS_DEV_MINOR(dev))
 
 #endif	/* !__XFS_TYPES_H */
diff -Nru a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
--- a/fs/xfs/xfs_utils.c	Tue Oct 15 20:29:23 2002
+++ b/fs/xfs/xfs_utils.c	Tue Oct 15 20:29:23 2002
@@ -132,7 +132,7 @@
 					   the inode. */
 	mode_t		mode,
 	nlink_t		nlink,
-	dev_t		rdev,
+	xfs_dev_t	rdev,
 	cred_t		*credp,
 	prid_t		prid,		/* project id */
 	int		okalloc,	/* ok to allocate new space */
@@ -345,7 +345,7 @@
 
 	ip->i_d.di_version = XFS_DINODE_VERSION_2;
 	ip->i_d.di_onlink = 0;
-	bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad));
+	memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
 	mp = tp->t_mountp;
 	if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) {
 		s = XFS_SB_LOCK(mp);
diff -Nru a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h
--- a/fs/xfs/xfs_utils.h	Tue Oct 15 20:29:23 2002
+++ b/fs/xfs/xfs_utils.h	Tue Oct 15 20:29:23 2002
@@ -76,7 +76,7 @@
 	struct xfs_inode	*dp,
 	mode_t			mode,
 	nlink_t			nlink,
-	dev_t			rdev,
+	xfs_dev_t		rdev,
 	struct cred		*credp,
 	prid_t			prid,
 	int			okalloc,
diff -Nru a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
--- a/fs/xfs/xfs_vfsops.c	Tue Oct 15 20:29:12 2002
+++ b/fs/xfs/xfs_vfsops.c	Tue Oct 15 20:29:12 2002
@@ -225,7 +225,7 @@
 	    (ap->logbufs < XLOG_NUM_ICLOGS ||
 	     ap->logbufs > XLOG_MAX_ICLOGS)) {
 		cmn_err(CE_WARN, 
-			"XFS: invalid logbufs value: %d [not %d-%d]\n",
+			"XFS: invalid logbufs value: %d [not %d-%d]",
 			ap->logbufs, XLOG_NUM_ICLOGS, XLOG_MAX_ICLOGS);
 		return XFS_ERROR(EINVAL);
 	}
@@ -237,7 +237,7 @@
 	    ap->logbufsize != 128 * 1024 &&
 	    ap->logbufsize != 256 * 1024) {
 		cmn_err(CE_WARN,
-	"XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]\n",
+	"XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
 			ap->logbufsize);
 		return XFS_ERROR(EINVAL);
 	}
@@ -274,13 +274,9 @@
 	if (ap->flags & XFSMNT_OSYNCISOSYNC)
 		mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC;
 
-	/* Default on Linux */
-	if (1 || ap->flags & XFSMNT_32BITINODES)
+	if (ap->flags & XFSMNT_32BITINODES)
 		mp->m_flags |= XFS_MOUNT_32BITINODES;
 
-	if (ap->flags & XFSMNT_IRIXSGID)
-		mp->m_flags |= XFS_MOUNT_IRIXSGID;
-
 	if (ap->flags & XFSMNT_IOSIZE) {
 		if (ap->iosizelog > XFS_MAX_IO_LOG ||
 		    ap->iosizelog < XFS_MIN_IO_LOG) {
@@ -392,145 +388,115 @@
 }
 
 /*
- * xfs_cmountfs
+ * xfs_mount
  *
- * This function is the common mount file system function for XFS.
+ * The file system configurations are:
+ *	(1) device (partition) with data and internal log
+ *	(2) logical volume with data and log subvolumes.
+ *	(3) logical volume with data, log, and realtime subvolumes.
+ *
+ * The Linux VFS took care of finding and opening the data volume for
+ * us.  We have to handle the other two (if present) here.
  */
 STATIC int
-xfs_cmountfs(
+xfs_mount(
 	vfs_t			*vfsp,
-	dev_t			ddev,
-	dev_t			logdev,
-	dev_t			rtdev,
-	struct xfs_mount_args	*ap,
-	struct cred		*cr)
+	struct xfs_mount_args	*args,
+	cred_t			*credp)
 {
 	xfs_mount_t		*mp;
+	struct block_device	*ddev, *logdev, *rtdev;
 	int			ronly = (vfsp->vfs_flag & VFS_RDONLY);
 	int			error = 0;
 
-	/*
-	 * Allocate VFS private data (xfs mount structure).
-	 */
-	mp = xfs_mount_init();
-
-	vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp);
+	ddev = vfsp->vfs_super->s_bdev;
+	logdev = rtdev = NULL;
 
 	/*
-	 * Open data, real time, and log devices now - order is important.
+	 * Open real time and log devices - order is important.
 	 */
-	mp->m_ddev_targp = pagebuf_lock_enable(ddev, 0);
-	if (IS_ERR(mp->m_ddev_targp)) {
-		error = PTR_ERR(mp->m_ddev_targp);
-		goto error2;
+	if (args->logname[0]) {
+		error = xfs_blkdev_get(args->logname, &logdev);
+		if (error)
+			return error;
 	}
-
-	if (rtdev != 0) {
-		mp->m_rtdev_targp = pagebuf_lock_enable(rtdev, 1);
-		if (IS_ERR(mp->m_rtdev_targp)) {
-			error = PTR_ERR(mp->m_rtdev_targp);
-			pagebuf_lock_disable(mp->m_ddev_targp, 0);
-			goto error2;
+	if (args->rtname[0]) {
+		error = xfs_blkdev_get(args->rtname, &rtdev);
+		if (error) {
+			xfs_blkdev_put(logdev);
+			return error;
 		}
 
 		if (rtdev == ddev || rtdev == logdev) {
 			cmn_err(CE_WARN,
 	"XFS: Cannot mount filesystem with identical rtdev and ddev/logdev.");
-			error = EINVAL;
-			pagebuf_lock_disable(mp->m_ddev_targp, 0);
-			goto error2;
-		}
-		
-		/* Set the realtime device's block size */
-		set_blocksize(mp->m_rtdev_targp->pbr_bdev, 512);
-	}
-
-	if (logdev != ddev) {
-		mp->m_logdev_targp = pagebuf_lock_enable(logdev, 1);
-		if (IS_ERR(mp->m_logdev_targp)) {
-			error = PTR_ERR(mp->m_logdev_targp);
-			pagebuf_lock_disable(mp->m_ddev_targp, 1);
-			if (mp->m_rtdev_targp)
-				pagebuf_lock_disable(mp->m_rtdev_targp, 1);
-			goto error2;
+			xfs_blkdev_put(logdev);
+			xfs_blkdev_put(rtdev);
+			return EINVAL;
 		}
+	}
+
+	/*
+	 * Allocate VFS private data (xfs mount structure).
+	 */
+	mp = xfs_mount_init();
+
+	vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp);
 
-		/* Set the log device's block size */
-		set_blocksize(mp->m_logdev_targp->pbr_bdev, 512);
+	mp->m_ddev_targp = xfs_alloc_buftarg(ddev);
+	if (rtdev != NULL) {
+		mp->m_rtdev_targp = xfs_alloc_buftarg(rtdev);
+		set_blocksize(rtdev, 512);
+	}
+	if (logdev != NULL && logdev != ddev) {
+		mp->m_logdev_targp = xfs_alloc_buftarg(logdev);
+		set_blocksize(logdev, 512);
 	} else {
 		mp->m_logdev_targp = mp->m_ddev_targp;
 	}
 	
-	if ((error = xfs_start_flags(ap, mp, ronly)))
-		goto error3;
+	error = xfs_start_flags(args, mp, ronly);
+	if (error)
+		goto error;
 
-	if ((error = xfs_readsb(mp)))
-		goto error3;
+	error = xfs_readsb(mp);
+	if (error)
+		goto error;
 
-	if ((error = xfs_finish_flags(ap, mp, ronly))) {
+	error = xfs_finish_flags(args, mp, ronly);
+	if (error) {
 		xfs_freesb(mp);
-		goto error3;
+		goto error;
 	}
 
-	pagebuf_target_blocksize(mp->m_ddev_targp, mp->m_sb.sb_blocksize);
-	if (logdev != 0 && logdev != ddev)
-		pagebuf_target_blocksize(mp->m_logdev_targp,
-					mp->m_sb.sb_blocksize);
-	if (rtdev != 0)
-		pagebuf_target_blocksize(mp->m_rtdev_targp,
-					mp->m_sb.sb_blocksize);
+	mp->m_ddev_targp->pbr_blocksize = mp->m_sb.sb_blocksize;
+	if (logdev != 0 && logdev != ddev) {
+		mp->m_logdev_targp->pbr_blocksize = mp->m_sb.sb_blocksize;
+	}
+	if (rtdev != 0) {
+		mp->m_rtdev_targp->pbr_blocksize = mp->m_sb.sb_blocksize;
+	}
 
 	mp->m_cxfstype = XFS_CXFS_NOT;
-	error = xfs_mountfs(vfsp, mp, ddev, 0);
+	error = xfs_mountfs(vfsp, mp, ddev->bd_dev, 0);
 	if (error)
-		goto error3;
+		goto error;
 	return 0;
 
- error3:
-	/* It's impossible to get here before buftargs are filled */
+ error:
 	xfs_binval(mp->m_ddev_targp);
-	pagebuf_lock_disable(mp->m_ddev_targp, 0);
-	if (logdev && logdev != ddev) {
+	if (logdev != NULL && logdev != ddev) {
 		xfs_binval(mp->m_logdev_targp);
-		pagebuf_lock_disable(mp->m_logdev_targp, 1);
 	}
-	if (rtdev != 0) {
+	if (rtdev != NULL) {
 		xfs_binval(mp->m_rtdev_targp);
-		pagebuf_lock_disable(mp->m_rtdev_targp, 1);
-	}
- error2:
-	if (error) {
-		xfs_mount_free(mp, 1);
 	}
+	xfs_unmountfs_close(mp, NULL);
+	xfs_mount_free(mp, 1);
 	return error;
 }
 
 /*
- * xfs_mount
- *
- * The file system configurations are:
- *	(1) device (partition) with data and internal log
- *	(2) logical volume with data and log subvolumes.
- *	(3) logical volume with data, log, and realtime subvolumes.
- */
-STATIC int
-xfs_mount(
-	vfs_t			*vfsp,
-	struct xfs_mount_args	*args,
-	cred_t			*credp)
-{
-	dev_t		ddev;
-	dev_t		logdev;
-	dev_t		rtdev;
-	int		error;
-
-	error = spectodevs(vfsp->vfs_super, args, &ddev, &logdev, &rtdev);
-	if (!error)
-		error = xfs_cmountfs(vfsp, ddev, logdev, rtdev, args, credp);
-	return (error);
-}
-
-/*
  * xfs_ibusy searches for a busy inode in the mounted file system.
  *
  * Return 0 if there are no active inodes otherwise return 1.
@@ -1149,7 +1115,7 @@
 			 * in taking a snapshot of the vnode version number
 			 * for use in calling vn_get().
 			 */
-			VMAP(vp, ip, vmap);
+			VMAP(vp, vmap);
 			IPOINTER_INSERT(ip, mp);
 
 			vp = vn_get(vp, &vmap);
@@ -1601,6 +1567,39 @@
 	return XFS_ERROR(last_error);
 }
 
+STATIC void
+xfs_initialize_vnode(
+	bhv_desc_t	*bdp,
+	vnode_t		*vp,
+	bhv_desc_t	*inode_bhv,
+	int		unlock)
+{
+	xfs_inode_t	*ip = XFS_BHVTOI(inode_bhv);
+	struct inode	*inode = LINVFS_GET_IP(vp);
+
+	if (vp->v_fbhv == NULL) {
+		vp->v_vfsp = bhvtovfs(bdp);
+		bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops);
+		bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc));
+	}
+
+	vp->v_type = IFTOVT(ip->i_d.di_mode);
+	/* Have we been called during the new inode create process,
+	 * in which case we are too early to fill in the linux inode.
+	 */
+	if (vp->v_type == VNON)
+		return;
+
+	xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
+
+	/* For new inodes we need to set the ops vectors,
+	 * and unlock the inode.
+	 */
+	if (unlock && (inode->i_state & I_NEW)) {
+		linvfs_set_inode_ops(inode);
+		unlock_new_inode(inode);
+	}
+}
 
 /*
  * xfs_vget - called by DMAPI to get vnode from file handle
@@ -1653,11 +1652,6 @@
 	inode = LINVFS_GET_IP((*vpp));
 	xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
-	error = linvfs_revalidate_core(inode, ATTR_COMM);
-	if (error) {
-		iput(inode);
-		return XFS_ERROR(error);
-	}
 	return 0;
 }
 
@@ -1670,6 +1664,7 @@
 	.vfs_statvfs		= xfs_statvfs,
 	.vfs_sync		= xfs_sync,
 	.vfs_vget		= xfs_vget,
+	.vfs_init_vnode		= xfs_initialize_vnode,
 	.vfs_force_shutdown	= xfs_do_force_shutdown,
 #ifdef CONFIG_XFS_DMAPI
 	.vfs_dmapi_mount	= xfs_dm_mount,
diff -Nru a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
--- a/fs/xfs/xfs_vnodeops.c	Tue Oct 15 20:29:23 2002
+++ b/fs/xfs/xfs_vnodeops.c	Tue Oct 15 20:29:23 2002
@@ -208,7 +208,7 @@
 				(mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog);
 		}
 	} else {
-		vap->va_rdev = IRIX_DEV_TO_KDEVT(ip->i_df.if_u2.if_rdev);
+		vap->va_rdev = ip->i_df.if_u2.if_rdev;
 		vap->va_blksize = BLKDEV_IOSIZE;
 	}
 
@@ -1970,7 +1970,7 @@
 	vnode_t			*vp=NULL;
 	xfs_trans_t		*tp;
 	xfs_mount_t		*mp;
-	dev_t			rdev;
+	xfs_dev_t		rdev;
 	int			error;
 	xfs_bmap_free_t		free_list;
 	xfs_fsblock_t		first_block;
@@ -2955,8 +2955,7 @@
 	xfs_inode_t		*cdp;	/* inode of created dir */
 	vnode_t			*cvp;	/* vnode of created dir */
 	xfs_trans_t		*tp;
-	dev_t			rdev;
-	mode_t			mode;
+	xfs_dev_t		rdev;
 	xfs_mount_t		*mp;
 	int			cancel_flags;
 	int			error;
@@ -3062,8 +3061,9 @@
 	 * create the directory inode.
 	 */
 	rdev = (vap->va_mask & AT_RDEV) ? vap->va_rdev : 0;
-	mode = IFDIR | (vap->va_mode & ~IFMT);
-	error = xfs_dir_ialloc(&tp, dp, mode, 2, rdev, credp, prid, resblks > 0,
+	error = xfs_dir_ialloc(&tp, dp, 
+			MAKEIMODE(vap->va_type,vap->va_mode), 2,
+			rdev, credp, prid, resblks > 0,
 		&cdp, NULL);
 	if (error) {
 		if (error == ENOSPC)
@@ -3521,7 +3521,7 @@
 	xfs_inode_t		*ip;
 	int			error;
 	int			pathlen;
-	dev_t			rdev;
+	xfs_dev_t		rdev;
 	xfs_bmap_free_t		free_list;
 	xfs_fsblock_t		first_block;
 	boolean_t		dp_joined_to_trans;
@@ -3702,7 +3702,7 @@
 	 */
 	if (pathlen <= XFS_IFORK_DSIZE(ip)) {
 		xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK);
-		bcopy(target_path, ip->i_df.if_u1.if_data, pathlen);
+		memcpy(ip->i_df.if_u1.if_data, target_path, pathlen);
 		ip->i_d.di_size = pathlen;
 
 		/*
@@ -3743,7 +3743,7 @@
 			}
 			pathlen -= byte_cnt;
 
-			bcopy(cur_chunk, XFS_BUF_PTR(bp), byte_cnt);
+			memcpy(XFS_BUF_PTR(bp), cur_chunk, byte_cnt);
 			cur_chunk += byte_cnt;
 
 			xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1);
@@ -3859,10 +3859,10 @@
 	xfid->fid_len = sizeof(xfs_fid2_t) - sizeof(xfid->fid_len);
 	xfid->fid_pad = 0;
 	/*
-	 * use bcopy because the inode is a long long and there's no
+	 * use memcpy because the inode is a long long and there's no
 	 * assurance that xfid->fid_ino is properly aligned.
 	 */
-	bcopy(&ip->i_ino, &xfid->fid_ino, sizeof xfid->fid_ino);
+	memcpy(&xfid->fid_ino, &ip->i_ino, sizeof(xfid->fid_ino));
 	xfid->fid_gen = ip->i_d.di_gen;
 
 	return 0;
@@ -4504,9 +4504,9 @@
 					  mp, bp, XFS_BUF_ADDR(bp));
 			break;
 		}
-		bzero(XFS_BUF_PTR(bp) +
+		memset(XFS_BUF_PTR(bp) +
 			(offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
-		      lastoffset - offset + 1);
+		      0, lastoffset - offset + 1);
 		XFS_BUF_UNDONE(bp);
 		XFS_BUF_UNREAD(bp);
 		XFS_BUF_WRITE(bp);
@@ -4937,7 +4937,6 @@
 	.vop_rwlock		= xfs_rwlock,
 	.vop_rwunlock		= xfs_rwunlock,
 	.vop_bmap		= xfs_bmap,
-	.vop_strategy		= xfs_strategy,
 	.vop_reclaim		= xfs_reclaim,
 	.vop_attr_get		= xfs_attr_get,
 	.vop_attr_set		= xfs_attr_set,
diff -Nru a/fs/xfs/xfsidbg.c b/fs/xfs/xfsidbg.c
--- a/fs/xfs/xfsidbg.c	Tue Oct 15 20:29:14 2002
+++ b/fs/xfs/xfsidbg.c	Tue Oct 15 20:29:14 2002
@@ -53,6 +53,9 @@
 static void	xfsidbg_xagi(xfs_agi_t *);
 static void	xfsidbg_xaildump(xfs_mount_t *);
 static void	xfsidbg_xalloc(xfs_alloc_arg_t *);
+#ifdef DEBUG
+static void	xfsidbg_xalmtrace(xfs_mount_t *);
+#endif
 static void	xfsidbg_xattrcontext(xfs_attr_list_context_t *);
 static void	xfsidbg_xattrleaf(xfs_attr_leafblock_t *);
 static void	xfsidbg_xattrsf(xfs_attr_shortform_t *);
@@ -196,6 +199,29 @@
 	return 0;
 }
 
+#ifdef DEBUG
+static int	kdbm_xfs_xalmtrace(
+	int	argc,
+	const char **argv,
+	const char **envp,
+	struct pt_regs *regs)
+{
+	unsigned long addr;
+	int nextarg = 1;
+	long offset = 0;
+	int diag;
+
+	if (argc != 1)
+		return KDB_ARGCOUNT;
+	diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs);
+	if (diag)
+		return diag;
+
+	xfsidbg_xalmtrace((xfs_mount_t *) addr);
+	return 0;
+}
+#endif /* DEBUG */
+
 static int	kdbm_xfs_xattrcontext(
 	int	argc,
 	const char **argv,
@@ -1700,18 +1726,19 @@
 /* pagebuf stuff */
 
 static char	*pb_flag_vals[] = {
-	"READ", "WRITE", "MAPPED", "PARTIAL",
-	"ASYNC", "NONE", "DELWRI", "FREED", "SYNC",
-	"MAPPABLE", "STALE", "FS_MANAGED", "RELEASE",
-	"LOCK", "TRYLOCK", "ALLOCATE", "FILE_ALLOCATE", "DONT_BLOCK",
-	"DIRECT", "LOCKABLE", "NEXT_KEY", "ENTER_PAGES",
-	"ALL_PAGES_MAPPED", "SOME_INVALID_PAGES", "ADDR_ALLOCATED",
-	"MEM_ALLOCATED", "GRIO", "FORCEIO", "SHUTDOWN",
-	NULL };
+/*  0 */ "READ", "WRITE", "MAPPED", "PARTIAL", "ASYNC",
+/*  5 */ "NONE", "DELWRI", "FREED", "SYNC", "MAPPABLE",
+/* 10 */ "STALE", "FS_MANAGED", "INVALID12", "LOCK", "TRYLOCK",
+/* 15 */ "FILE_ALLOCATE", "DONT_BLOCK", "DIRECT", "INVALID18", "LOCKABLE",
+/* 20 */ "PRIVATE_BH", "ALL_PAGES_MAPPED", "ADDR_ALLOCATED", "MEM_ALLOCATED",
+	 "FORCEIO",
+/* 25 */ "FLUSH", "READ_AHEAD", "INVALID27", "INVALID28", "INVALID29",
+/* 30 */ "INVALID30", "INVALID31",
+	 NULL };
 
 static char	*pbm_flag_vals[] = {
-	"EOF", "HOLE", "DELAY", "FLUSH_OVERLAPS",
-	"READAHEAD", "UNWRITTEN", "DONTALLOC", "NEW",
+	"EOF", "HOLE", "DELAY", "INVALID0x08",
+	"INVALID0x10", "UNWRITTEN", "INVALID0x40", "INVALID0x80",
 	NULL };
 
 
@@ -1964,7 +1991,7 @@
 
 		if ((trace->event < EV_SIZE-1) && event_names[trace->event]) {
 			event = event_names[trace->event];
-		} else if (trace->event == EV_SIZE) {
+		} else if (trace->event == EV_SIZE-1) {
 			event = (char *)trace->misc;
 		} else {
 			event = value;
@@ -2081,6 +2108,10 @@
 				"Dump XFS AIL for a mountpoint" },
   {  "xalloc",	kdbm_xfs_xalloc,	"<xfs_alloc_arg_t>",
 				"Dump XFS allocation args structure" },
+#ifdef DEBUG
+  {  "xalmtrc",	kdbm_xfs_xalmtrace,	"<xfs_mount_t>",
+				"Dump XFS alloc mount-point trace" },
+#endif
   {  "xattrcx", kdbm_xfs_xattrcontext,	"<xfs_attr_list_context_t>",
 				"Dump XFS attr_list context struct"},
   {  "xattrlf", kdbm_xfs_xattrleaf,	"<xfs_attr_leafblock_t>",
@@ -2245,13 +2276,14 @@
 /*
  * Prototypes for static functions.
  */
+#ifdef DEBUG
+static int xfs_alloc_trace_entry(ktrace_entry_t *ktep);
+#endif
 static void xfs_broot(xfs_inode_t *ip, xfs_ifork_t *f);
 static void xfs_btalloc(xfs_alloc_block_t *bt, int bsz);
 static void xfs_btbmap(xfs_bmbt_block_t *bt, int bsz);
 static void xfs_btino(xfs_inobt_block_t *bt, int bsz);
 static void xfs_buf_item_print(xfs_buf_log_item_t *blip, int summary);
-static void xfs_convert_extent(xfs_bmbt_rec_64_t *rp, xfs_dfiloff_t *op,
-			xfs_dfsbno_t *sp, xfs_dfilblks_t *cp, int *fp);
 static void xfs_dastate_path(xfs_da_state_path_t *p);
 static void xfs_dir2data(void *addr, int size);
 static void xfs_dir2leaf(xfs_dir2_leaf_t *leaf, int size);
@@ -2277,6 +2309,137 @@
  * Static functions.
  */
 
+#ifdef DEBUG
+/*
+ * Print xfs alloc trace buffer entry.
+ */
+static int
+xfs_alloc_trace_entry(ktrace_entry_t *ktep)
+{		  
+	static char *modagf_flags[] = {
+		"magicnum",
+		"versionnum",
+		"seqno",
+		"length",
+		"roots",
+		"levels",
+		"flfirst",
+		"fllast",
+		"flcount",
+		"freeblks",
+		"longest",
+		NULL
+	};
+
+	if (((__psint_t)ktep->val[0] & 0xffff) == 0)
+		return 0;
+	switch ((long)ktep->val[0] & 0xffffL) {
+	case XFS_ALLOC_KTRACE_ALLOC:
+		kdb_printf("alloc %s[%s %d] mp 0x%p\n",
+			(char *)ktep->val[1],
+			ktep->val[2] ? (char *)ktep->val[2] : "",
+			(__psint_t)ktep->val[0] >> 16,
+			(xfs_mount_t *)ktep->val[3]);
+		kdb_printf(
+	"agno %d agbno %d minlen %d maxlen %d mod %d prod %d minleft %d\n",
+			(__psunsigned_t)ktep->val[4],
+			(__psunsigned_t)ktep->val[5],
+			(__psunsigned_t)ktep->val[6], 
+			(__psunsigned_t)ktep->val[7], 
+			(__psunsigned_t)ktep->val[8],
+			(__psunsigned_t)ktep->val[9], 
+			(__psunsigned_t)ktep->val[10]);
+		kdb_printf("total %d alignment %d len %d type %s otype %s\n",
+			(__psunsigned_t)ktep->val[11],
+			(__psunsigned_t)ktep->val[12],
+			(__psunsigned_t)ktep->val[13],
+			xfs_alloctype[((__psint_t)ktep->val[14]) >> 16],
+			xfs_alloctype[((__psint_t)ktep->val[14]) & 0xffff]);
+		kdb_printf("wasdel %d wasfromfl %d isfl %d userdata %d\n",
+			((__psint_t)ktep->val[15] & (1 << 3)) != 0,
+			((__psint_t)ktep->val[15] & (1 << 2)) != 0,
+			((__psint_t)ktep->val[15] & (1 << 1)) != 0,
+			((__psint_t)ktep->val[15] & (1 << 0)) != 0);
+		break;
+	case XFS_ALLOC_KTRACE_FREE:
+		kdb_printf("free %s[%s %d] mp 0x%p\n",
+			(char *)ktep->val[1],
+			ktep->val[2] ? (char *)ktep->val[2] : "",
+			(__psint_t)ktep->val[0] >> 16,
+			(xfs_mount_t *)ktep->val[3]);
+		kdb_printf("agno %d agbno %d len %d isfl %d\n",
+			(__psunsigned_t)ktep->val[4],
+			(__psunsigned_t)ktep->val[5],
+			(__psunsigned_t)ktep->val[6],
+			(__psint_t)ktep->val[7]);
+		break;
+	case XFS_ALLOC_KTRACE_MODAGF:
+		kdb_printf("modagf %s[%s %d] mp 0x%p\n",
+			(char *)ktep->val[1],
+			ktep->val[2] ? (char *)ktep->val[2] : "",
+			(__psint_t)ktep->val[0] >> 16,
+			(xfs_mount_t *)ktep->val[3]);
+		printflags((__psint_t)ktep->val[4], modagf_flags, "modified");
+		kdb_printf("seqno %d length %d roots b %d c %d\n",
+			(__psunsigned_t)ktep->val[5],
+			(__psunsigned_t)ktep->val[6],
+			(__psunsigned_t)ktep->val[7],
+			(__psunsigned_t)ktep->val[8]);
+		kdb_printf("levels b %d c %d flfirst %d fllast %d flcount %d\n",
+			(__psunsigned_t)ktep->val[9],
+			(__psunsigned_t)ktep->val[10],
+			(__psunsigned_t)ktep->val[11],
+			(__psunsigned_t)ktep->val[12],
+			(__psunsigned_t)ktep->val[13]);
+		kdb_printf("freeblks %d longest %d\n",
+			(__psunsigned_t)ktep->val[14],
+			(__psunsigned_t)ktep->val[15]);
+		break;
+
+	case XFS_ALLOC_KTRACE_UNBUSY:
+		kdb_printf("unbusy %s [%s %d] mp 0x%p\n",
+			(char *)ktep->val[1],
+			ktep->val[2] ? (char *)ktep->val[2] : "",
+			(__psint_t)ktep->val[0] >> 16,
+			(xfs_mount_t *)ktep->val[3]);
+		kdb_printf("      agno %d slot %d tp 0x%x\n",
+			(__psunsigned_t)ktep->val[4],
+			(__psunsigned_t)ktep->val[7],
+			(__psunsigned_t)ktep->val[8]);
+		break;
+	case XFS_ALLOC_KTRACE_BUSY:
+		kdb_printf("busy %s [%s %d] mp 0x%p\n",
+			(char *)ktep->val[1],
+			ktep->val[2] ? (char *)ktep->val[2] : "",
+			(__psint_t)ktep->val[0] >> 16,
+			(xfs_mount_t *)ktep->val[3]);
+		kdb_printf("      agno %d agbno %d len %d slot %d tp 0x%x\n",
+			(__psunsigned_t)ktep->val[4],
+			(__psunsigned_t)ktep->val[5],
+			(__psunsigned_t)ktep->val[6],
+			(__psunsigned_t)ktep->val[7],
+			(__psunsigned_t)ktep->val[8]);
+		break;
+	case XFS_ALLOC_KTRACE_BUSYSEARCH:
+		kdb_printf("busy-search %s [%s %d] mp 0x%p\n",
+			(char *)ktep->val[1],
+			ktep->val[2] ? (char *)ktep->val[2] : "",
+			(__psint_t)ktep->val[0] >> 16,
+			(xfs_mount_t *)ktep->val[3]);
+		kdb_printf("      agno %d agbno %d len %d slot %d tp 0x%x\n",
+			(__psunsigned_t)ktep->val[4],
+			(__psunsigned_t)ktep->val[5],
+			(__psunsigned_t)ktep->val[6],
+			(__psunsigned_t)ktep->val[7],
+			(__psunsigned_t)ktep->val[8]);
+		break;
+	default:
+		kdb_printf("unknown alloc trace record\n");
+		break;
+	}
+	return 1;
+}
+#endif /* DEBUG */
 
 /*
  * Print an xfs in-inode bmap btree root.
@@ -2359,18 +2522,17 @@
 	kdb_printf("rightsib %Lx\n", INT_GET(bt->bb_rightsib, ARCH_CONVERT));
 	if (INT_ISZERO(bt->bb_level, ARCH_CONVERT)) {
 		for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) {
-			xfs_bmbt_rec_64_t *r;
-			xfs_dfiloff_t o;
-			xfs_dfsbno_t s;
-			xfs_dfilblks_t c;
-			int fl;
+			xfs_bmbt_rec_t *r;
+			xfs_bmbt_irec_t	irec;
 
-			r = (xfs_bmbt_rec_64_t *)XFS_BTREE_REC_ADDR(bsz,
+			r = (xfs_bmbt_rec_t *)XFS_BTREE_REC_ADDR(bsz,
 				xfs_bmbt, bt, i, 0);
-			xfs_convert_extent(r, &o, &s, &c, &fl);
-			kdb_printf("rec %d startoff %Ld ", i, o);
-			kdb_printf("startblock %Lx ", s);
-			kdb_printf("blockcount %Ld flag %d\n", c, fl);
+
+			xfs_bmbt_disk_get_all((xfs_bmbt_rec_t *)r, &irec);
+			kdb_printf("rec %d startoff %Ld startblock %Lx blockcount %Ld flag %d\n",
+				i, irec.br_startoff,
+				(__uint64_t)irec.br_startblock, 
+				irec.br_blockcount, irec.br_state);
 		}
 	} else {
 		int mxr;
@@ -2473,31 +2635,6 @@
 }
 
 /*
- * Convert an external extent descriptor to internal form.
- */
-static void
-xfs_convert_extent(xfs_bmbt_rec_64_t *rp, xfs_dfiloff_t *op, xfs_dfsbno_t *sp,
-		   xfs_dfilblks_t *cp, int *fp)
-{
-	xfs_dfiloff_t o;
-	xfs_dfsbno_t s;
-	xfs_dfilblks_t c;
-	int flag;
-
-	flag = (int)((INT_GET(rp->l0, ARCH_CONVERT)) >> (64 - 1 ));
-	o = ((xfs_fileoff_t)INT_GET(rp->l0, ARCH_CONVERT) &
-			   (((__uint64_t)1 << ( 64 - 1	)) - 1) ) >> 9;
-	s = (((xfs_fsblock_t)INT_GET(rp->l0, ARCH_CONVERT) & (((__uint64_t)1 << ( 9 )) - 1) ) << 43) |
-			   (((xfs_fsblock_t)INT_GET(rp->l1, ARCH_CONVERT)) >> 21);
-	c = (xfs_filblks_t)(INT_GET(rp->l1, ARCH_CONVERT) & (((__uint64_t)1 << ( 21 )) - 1) );
-	*op = o;
-	*sp = s;
-	*cp = c;
-	*fp = flag;
-}
-
-
-/*
  * Print an xfs_da_state_path structure.
  */
 static void
@@ -2890,11 +3027,8 @@
 xfs_xexlist_fork(xfs_inode_t *ip, int whichfork)
 {
 	int nextents, i;
-	xfs_dfiloff_t o;
-	xfs_dfsbno_t s;
-	xfs_dfilblks_t c;
-	int flag;
 	xfs_ifork_t *ifp;
+	xfs_bmbt_irec_t irec;
 
 	ifp = XFS_IFORK_PTR(ip, whichfork);
 	if (ifp->if_flags & XFS_IFEXTENTS) {
@@ -2902,12 +3036,12 @@
 		kdb_printf("inode 0x%p %cf extents 0x%p nextents 0x%x\n",
 			ip, "da"[whichfork], ifp->if_u1.if_extents, nextents);
 		for (i = 0; i < nextents; i++) {
-			xfs_convert_extent(
-				(xfs_bmbt_rec_64_t *)&ifp->if_u1.if_extents[i],
-				&o, &s, &c, &flag);
+			xfs_bmbt_get_all(&ifp->if_u1.if_extents[i], &irec);
 			kdb_printf(
 		"%d: startoff %Ld startblock %s blockcount %Ld flag %d\n",
-				i, o, xfs_fmtfsblock(s, ip->i_mount), c, flag);
+			i, irec.br_startoff,
+			xfs_fmtfsblock(irec.br_startblock, ip->i_mount),
+			irec.br_blockcount, irec.br_state);
 		}
 	}
 }
@@ -3030,7 +3164,33 @@
 		args->wasfromfl, args->isfl, args->userdata);
 }
 
+#ifdef DEBUG
+/*
+ * Print out all the entries in the alloc trace buf corresponding
+ * to the given mount point.
+ */
+static void
+xfsidbg_xalmtrace(xfs_mount_t *mp)
+{
+	ktrace_entry_t	*ktep;
+	ktrace_snap_t	kts;
+	extern ktrace_t	*xfs_alloc_trace_buf;
+
+	if (xfs_alloc_trace_buf == NULL) {
+		kdb_printf("The xfs alloc trace buffer is not initialized\n");
+		return;
+	}
 
+	ktep = ktrace_first(xfs_alloc_trace_buf, &kts);
+	while (ktep != NULL) {
+		if ((__psint_t)ktep->val[0] && (xfs_mount_t *)ktep->val[3] == mp) {
+			(void)xfs_alloc_trace_entry(ktep);
+			kdb_printf("\n");
+		}
+		ktep = ktrace_next(xfs_alloc_trace_buf, &kts);
+	}
+}
+#endif /* DEBUG */
 
 /*
  * Print an attr_list() context structure.
@@ -3199,14 +3359,12 @@
 static void
 xfsidbg_xbrec(xfs_bmbt_rec_64_t *r)
 {
-	xfs_dfiloff_t o;
-	xfs_dfsbno_t s;
-	xfs_dfilblks_t c;
-	int flag;
+	xfs_bmbt_irec_t	irec;
 
-	xfs_convert_extent(r, &o, &s, &c, &flag);
+	xfs_bmbt_get_all((xfs_bmbt_rec_t *)r, &irec);
 	kdb_printf("startoff %Ld startblock %Lx blockcount %Ld flag %d\n",
-		o, s, c, flag);
+		irec.br_startoff, (__uint64_t)irec.br_startblock, 
+		irec.br_blockcount, irec.br_state);
 }
 
 /*
@@ -4412,8 +4570,7 @@
 		"OSYNC",	/* 0x2000 */
 		"NOUUID",	/* 0x4000 */
 		"32BIT",	/* 0x8000 */
-		"IRIXSGID",	/* 0x10000 */
-		"NOLOGFLUSH",	/* 0x20000 */
+		"NOLOGFLUSH",	/* 0x10000 */
 		0
 	};
 
@@ -4438,9 +4595,9 @@
 		mp->m_ail_gen, &mp->m_sb);
 	kdb_printf("sb_lock 0x%p sb_bp 0x%p dev 0x%x logdev 0x%x rtdev 0x%x\n",
 		&mp->m_sb_lock, mp->m_sb_bp,
-		mp->m_ddev_targp->pbr_dev,
-		mp->m_logdev_targp->pbr_dev,
-		mp->m_rtdev_targp->pbr_dev);
+		mp->m_ddev_targp ? mp->m_ddev_targp->pbr_dev : 0,
+		mp->m_logdev_targp ? mp->m_logdev_targp->pbr_dev : 0,
+		mp->m_rtdev_targp ? mp->m_rtdev_targp->pbr_dev : 0);
 	kdb_printf("bsize %d agfrotor %d agirotor %d ihash 0x%p ihsize %d\n",
 		mp->m_bsize, mp->m_agfrotor, mp->m_agirotor,
 		mp->m_ihash, mp->m_ihsize);
@@ -4734,13 +4891,17 @@
 		if (pag->pagi_init)
 			kdb_printf("	i_freecount %d i_inodeok %d\n",
 				pag->pagi_freecount, pag->pagi_inodeok);
-
-		for (busy = 0; busy < XFS_PAGB_NUM_SLOTS; busy++) {
-			kdb_printf("	 %04d: start %d length %d tp 0x%p\n",
-				busy,
-				pag->pagb_list[busy].busy_start,
-				pag->pagb_list[busy].busy_length,
-				pag->pagb_list[busy].busy_tp);
+		if (pag->pagf_init) {
+			for (busy = 0; busy < XFS_PAGB_NUM_SLOTS; busy++) {
+				if (pag->pagb_list[busy].busy_length != 0) {
+					kdb_printf(
+		"	 %04d: start %d length %d tp 0x%p\n",
+					    busy,
+					    pag->pagb_list[busy].busy_start,
+					    pag->pagb_list[busy].busy_length,
+					    pag->pagb_list[busy].busy_tp);
+				}
+			}
 		}
 	}
 }
@@ -5138,8 +5299,10 @@
 		tp->t_log_res, tp->t_blk_res, tp->t_blk_res_used);
 	kdb_printf("rt res %d rt res used %d\n", tp->t_rtx_res,
 		tp->t_rtx_res_used);
-	kdb_printf("ticket 0x%lx lsn %s\n",
-		(unsigned long) tp->t_ticket, xfs_fmtlsn(&tp->t_lsn));
+	kdb_printf("ticket 0x%lx lsn %s commit_lsn %s\n",
+		(unsigned long) tp->t_ticket,
+		xfs_fmtlsn(&tp->t_lsn),
+		xfs_fmtlsn(&tp->t_commit_lsn));
 	kdb_printf("callback 0x%p callarg 0x%p\n",
 		tp->t_callback, tp->t_callarg);
 	kdb_printf("icount delta %ld ifree delta %ld\n",
diff -Nru a/include/asm-alpha/elf.h b/include/asm-alpha/elf.h
--- a/include/asm-alpha/elf.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-alpha/elf.h	Tue Oct 15 20:29:17 2002
@@ -58,44 +58,46 @@
    Eventually, it would be nice if the ECOFF core-dump had to do the
    translation, then ELF_CORE_COPY_REGS() would become trivial and
    faster.  */
-#define ELF_CORE_COPY_REGS(_dest,_regs)				\
-{								\
-	struct user _dump;					\
-								\
-	dump_thread(_regs, &_dump);				\
-	_dest[ 0] = _dump.regs[EF_V0];				\
-	_dest[ 1] = _dump.regs[EF_T0];				\
-	_dest[ 2] = _dump.regs[EF_T1];				\
-	_dest[ 3] = _dump.regs[EF_T2];				\
-	_dest[ 4] = _dump.regs[EF_T3];				\
-	_dest[ 5] = _dump.regs[EF_T4];				\
-	_dest[ 6] = _dump.regs[EF_T5];				\
-	_dest[ 7] = _dump.regs[EF_T6];				\
-	_dest[ 8] = _dump.regs[EF_T7];				\
-	_dest[ 9] = _dump.regs[EF_S0];				\
-	_dest[10] = _dump.regs[EF_S1];				\
-	_dest[11] = _dump.regs[EF_S2];				\
-	_dest[12] = _dump.regs[EF_S3];				\
-	_dest[13] = _dump.regs[EF_S4];				\
-	_dest[14] = _dump.regs[EF_S5];				\
-	_dest[15] = _dump.regs[EF_S6];				\
-	_dest[16] = _dump.regs[EF_A0];				\
-	_dest[17] = _dump.regs[EF_A1];				\
-	_dest[18] = _dump.regs[EF_A2];				\
-	_dest[19] = _dump.regs[EF_A3];				\
-	_dest[20] = _dump.regs[EF_A4];				\
-	_dest[21] = _dump.regs[EF_A5];				\
-	_dest[22] = _dump.regs[EF_T8];				\
-	_dest[23] = _dump.regs[EF_T9];				\
-	_dest[24] = _dump.regs[EF_T10];				\
-	_dest[25] = _dump.regs[EF_T11];				\
-	_dest[26] = _dump.regs[EF_RA];				\
-	_dest[27] = _dump.regs[EF_T12];				\
-	_dest[28] = _dump.regs[EF_AT];				\
-	_dest[29] = _dump.regs[EF_GP];				\
-	_dest[30] = _dump.regs[EF_SP];				\
-	_dest[31] = _dump.regs[EF_PC];	/* store PC here */	\
-	_dest[32] = _dump.regs[EF_PS];				\
+
+#define ELF_CORE_COPY_REGS(_dest,_regs)					\
+{									\
+	extern void dump_thread(struct pt_regs *, struct user *);	\
+	struct user _dump;						\
+									\
+	dump_thread(_regs, &_dump);					\
+	_dest[ 0] = _dump.regs[EF_V0];					\
+	_dest[ 1] = _dump.regs[EF_T0];					\
+	_dest[ 2] = _dump.regs[EF_T1];					\
+	_dest[ 3] = _dump.regs[EF_T2];					\
+	_dest[ 4] = _dump.regs[EF_T3];					\
+	_dest[ 5] = _dump.regs[EF_T4];					\
+	_dest[ 6] = _dump.regs[EF_T5];					\
+	_dest[ 7] = _dump.regs[EF_T6];					\
+	_dest[ 8] = _dump.regs[EF_T7];					\
+	_dest[ 9] = _dump.regs[EF_S0];					\
+	_dest[10] = _dump.regs[EF_S1];					\
+	_dest[11] = _dump.regs[EF_S2];					\
+	_dest[12] = _dump.regs[EF_S3];					\
+	_dest[13] = _dump.regs[EF_S4];					\
+	_dest[14] = _dump.regs[EF_S5];					\
+	_dest[15] = _dump.regs[EF_S6];					\
+	_dest[16] = _dump.regs[EF_A0];					\
+	_dest[17] = _dump.regs[EF_A1];					\
+	_dest[18] = _dump.regs[EF_A2];					\
+	_dest[19] = _dump.regs[EF_A3];					\
+	_dest[20] = _dump.regs[EF_A4];					\
+	_dest[21] = _dump.regs[EF_A5];					\
+	_dest[22] = _dump.regs[EF_T8];					\
+	_dest[23] = _dump.regs[EF_T9];					\
+	_dest[24] = _dump.regs[EF_T10];					\
+	_dest[25] = _dump.regs[EF_T11];					\
+	_dest[26] = _dump.regs[EF_RA];					\
+	_dest[27] = _dump.regs[EF_T12];					\
+	_dest[28] = _dump.regs[EF_AT];					\
+	_dest[29] = _dump.regs[EF_GP];					\
+	_dest[30] = _dump.regs[EF_SP];					\
+	_dest[31] = _dump.regs[EF_PC];	/* store PC here */		\
+	_dest[32] = _dump.regs[EF_PS];					\
 }
 
 /* This yields a mask that user programs can use to figure out what
diff -Nru a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h
--- a/include/asm-alpha/mmu_context.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-alpha/mmu_context.h	Tue Oct 15 20:29:17 2002
@@ -33,7 +33,7 @@
 		"call_pal %2 #__reload_thread"
 		: "=r"(v0), "=r"(a0)
 		: "i"(PAL_swpctx), "r"(a0)
-		: "$1", "$16", "$22", "$23", "$24", "$25");
+		: "$1", "$22", "$23", "$24", "$25");
 
 	return v0;
 }
diff -Nru a/include/asm-alpha/posix_types.h b/include/asm-alpha/posix_types.h
--- a/include/asm-alpha/posix_types.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-alpha/posix_types.h	Tue Oct 15 20:29:12 2002
@@ -12,7 +12,7 @@
 typedef unsigned int	__kernel_mode_t;
 typedef unsigned int	__kernel_nlink_t;
 typedef long		__kernel_off_t;
-typedef long		__kernel_loff_t;
+typedef long long	__kernel_loff_t;
 typedef int		__kernel_pid_t;
 typedef int		__kernel_ipc_pid_t;
 typedef unsigned int	__kernel_uid_t;
diff -Nru a/include/asm-arm/arch-ebsa285/time.h b/include/asm-arm/arch-ebsa285/time.h
--- a/include/asm-arm/arch-ebsa285/time.h	Tue Oct 15 20:29:23 2002
+++ b/include/asm-arm/arch-ebsa285/time.h	Tue Oct 15 20:29:23 2002
@@ -62,7 +62,7 @@
 
 	count_p = count;
 
-	count = (((mSEC_10_from_14/6)-1) - count) * tick;
+	count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000);
 	count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
 
 	return count;
@@ -182,7 +182,7 @@
 {
 	unsigned long value = LATCH - *CSR_TIMER1_VALUE;
 
-	return (tick * value) / LATCH;
+	return ((tick_nsec / 1000) * value) / LATCH;
 }
 
 static void timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
diff -Nru a/include/asm-arm/arch-rpc/ide.h b/include/asm-arm/arch-rpc/ide.h
--- a/include/asm-arm/arch-rpc/ide.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-arm/arch-rpc/ide.h	Tue Oct 15 20:29:16 2002
@@ -44,5 +44,5 @@
 
 	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
 	hw.irq = IRQ_HARDDISK;
-	ide_register_hw(&hw);
+	ide_register_hw(&hw, NULL);
 }
diff -Nru a/include/asm-arm/arch-rpc/serial.h b/include/asm-arm/arch-rpc/serial.h
--- a/include/asm-arm/arch-rpc/serial.h	Tue Oct 15 20:29:13 2002
+++ b/include/asm-arm/arch-rpc/serial.h	Tue Oct 15 20:29:14 2002
@@ -29,7 +29,7 @@
      /* UART CLK        PORT  IRQ     FLAGS        */
 #define STD_SERIAL_PORT_DEFNS \
 	{ 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS },	/* ttyS1 */	\
+	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS1 */	\
 	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS2 */	\
 	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS },	/* ttyS3 */	\
 	{ 0, BASE_BAUD, 0    ,  0, STD_COM_FLAGS }, 	/* ttyS4 */	\
diff -Nru a/include/asm-arm/arch-rpc/uncompress.h b/include/asm-arm/arch-rpc/uncompress.h
--- a/include/asm-arm/arch-rpc/uncompress.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-arm/arch-rpc/uncompress.h	Tue Oct 15 20:29:17 2002
@@ -56,7 +56,7 @@
 #define palette_setpixel(p)	*(unsigned long *)(IO_START+0x00400000) = 0x10000000|((p) & 255)
 #define palette_write(v)	*(unsigned long *)(IO_START+0x00400000) = 0x00000000|((v) & 0x00ffffff)
 
-extern struct param_struct params;
+static struct param_struct *params = (struct param_struct *)PARAMS_PHYS;
 
 #ifndef STANDALONE_DEBUG 
 /*
@@ -64,13 +64,13 @@
  */
 static void puts(const char *s)
 {
-	extern void ll_write_char(char *, unsigned long);
+	extern void ll_write_char(char *, char c, char white);
 	int x,y;
 	unsigned char c;
 	char *ptr;
 
-	x = params.video_x;
-	y = params.video_y;
+	x = params->video_x;
+	y = params->video_y;
 
 	while ( ( c = *(unsigned char *)s++ ) != '\0' ) {
 		if ( c == '\n' ) {
@@ -79,8 +79,8 @@
 				y--;
 			}
 		} else {
-			ptr = VIDMEM + ((y*video_num_columns*params.bytes_per_char_v+x)*bytes_per_char_h);
-			ll_write_char(ptr, c|(white<<16));
+			ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h);
+			ll_write_char(ptr, c, white);
 			if ( ++x >= video_num_columns ) {
 				x = 0;
 				if ( ++y >= video_num_lines ) {
@@ -90,8 +90,8 @@
 		}
 	}
 
-	params.video_x = x;
-	params.video_y = y;
+	params->video_x = x;
+	params->video_y = y;
 }
 
 static void error(char *x);
@@ -103,9 +103,9 @@
 {
 	int i;
 	
-	video_num_lines = params.video_num_rows;
-	video_num_columns = params.video_num_cols;
-	bytes_per_char_h = params.bytes_per_char_h;
+	video_num_lines = params->video_num_rows;
+	video_num_columns = params->video_num_cols;
+	bytes_per_char_h = params->bytes_per_char_h;
 	video_size_row = video_num_columns * bytes_per_char_h;
 	if (bytes_per_char_h == 4)
 		for (i = 0; i < 256; i++)
@@ -140,7 +140,7 @@
 		white = 7;
 	}
 
-	if (params.nr_pages * params.page_size < 4096*1024) error("<4M of mem\n");
+	if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n");
 }
 #endif
 
diff -Nru a/include/asm-arm/arch-sa1100/irqs.h b/include/asm-arm/arch-sa1100/irqs.h
--- a/include/asm-arm/arch-sa1100/irqs.h	Tue Oct 15 20:29:11 2002
+++ b/include/asm-arm/arch-sa1100/irqs.h	Tue Oct 15 20:29:11 2002
@@ -109,7 +109,7 @@
 #define AUDRDD			(IRQ_BOARD_END + 41)
 #define AUDSTO			(IRQ_BOARD_END + 42)
 #define IRQ_USBPWR		(IRQ_BOARD_END + 43)
-#define IRQ_NHCIM		(IRQ_BOARD_END + 44)
+#define IRQ_HCIM		(IRQ_BOARD_END + 44)
 #define IRQ_HCIBUFFACC		(IRQ_BOARD_END + 45)
 #define IRQ_HCIRMTWKP		(IRQ_BOARD_END + 46)
 #define IRQ_NHCIMFCIR		(IRQ_BOARD_END + 47)
diff -Nru a/include/asm-arm/arch-sa1100/time.h b/include/asm-arm/arch-sa1100/time.h
--- a/include/asm-arm/arch-sa1100/time.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-arm/arch-sa1100/time.h	Tue Oct 15 20:29:17 2002
@@ -58,7 +58,7 @@
 	elapsed = LATCH - ticks_to_match;
 
 	/* Now convert them to usec */
-	usec = (unsigned long)(elapsed*tick)/LATCH;
+	usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH;
 
 	return usec;
 }
diff -Nru a/include/asm-arm/ecard.h b/include/asm-arm/ecard.h
--- a/include/asm-arm/ecard.h	Tue Oct 15 20:29:20 2002
+++ b/include/asm-arm/ecard.h	Tue Oct 15 20:29:20 2002
@@ -95,9 +95,10 @@
 	ECARD_SYNC	 = 3
 } card_speed_t;
 
-typedef struct  {			/* Card ID structure		*/
-	unsigned short manufacturer;
-	unsigned short product;
+typedef struct ecard_id {		/* Card ID structure		*/
+	unsigned short	manufacturer;
+	unsigned short	product;
+	void		*data;
 } card_ids;
 
 struct in_ecid {			/* Packed card ID information	*/
@@ -132,6 +133,8 @@
 struct expansion_card {
 	struct expansion_card  *next;
 
+	struct device		dev;
+
 	/* Public data */
 	volatile unsigned char *irqaddr;	/* address of IRQ register	*/
 	volatile unsigned char *fiqaddr;	/* address of FIQ register	*/
@@ -247,5 +250,25 @@
 };
 
 #endif
+
+extern struct bus_type ecard_bus_type;
+
+#define ECARD_DEV(_d)	container_of((_d), struct expansion_card, dev)
+
+struct ecard_driver {
+	int			(*probe)(struct expansion_card *, const struct ecard_id *id);
+	void			(*remove)(struct expansion_card *);
+	const struct ecard_id	*id_table;
+	unsigned int		id;
+	struct device_driver	drv;
+};
+
+#define ECARD_DRV(_d)	container_of((_d), struct ecard_driver, drv)
+
+#define ecard_set_drvdata(ec,data)	dev_set_drvdata(&(ec)->dev, (data))
+#define ecard_get_drvdata(ec)		dev_get_drvdata(&(ec)->dev)
+
+int ecard_register_driver(struct ecard_driver *);
+void ecard_remove_driver(struct ecard_driver *);
 
 #endif
diff -Nru a/include/asm-arm/glue.h b/include/asm-arm/glue.h
--- a/include/asm-arm/glue.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-arm/glue.h	Tue Oct 15 20:29:12 2002
@@ -27,59 +27,6 @@
 
 
 /*
- *	MMU TLB Model
- *	=============
- *
- *	We have the following to choose from:
- *	  v3    - ARMv3
- *	  v4    - ARMv4 without write buffer
- *	  v4wb  - ARMv4 with write buffer without I TLB flush entry instruction
- *	  v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
- */
-#undef _TLB
-#undef MULTI_TLB
-
-#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
-# ifdef _TLB
-#  define MULTI_TLB 1
-# else
-#  define _TLB v3
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM720T)
-# ifdef _TLB
-#  define MULTI_TLB 1
-# else
-#  define _TLB v4
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
-    defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_ARM1020) || \
-    defined(CONFIG_CPU_XSCALE)
-# ifdef _TLB
-#  define MULTI_TLB 1
-# else
-#  define _TLB v4wbi
-# endif
-#endif
-
-#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
-# ifdef _TLB
-#  define MULTI_TLB 1
-# else
-#  define _TLB v4wb
-# endif
-#endif
-
-#ifndef _TLB
-#error Unknown TLB model
-#endif
-
-
-
-/*
  *	Data Abort Model
  *	================
  *
@@ -154,71 +101,6 @@
 
 #ifndef CPU_ABORT_HANDLER
 #error Unknown data abort handler type
-#endif
-
-
-/*
- *	User Space Model
- *	================
- *
- *	This section selects the correct set of functions for dealing with
- *	page-based copying and clearing for user space for the particular
- *	processor(s) we're building for.
- *
- *	We have the following to choose from:
- *	  v3		- ARMv3
- *	  v4wt		- ARMv4 with writethrough cache, without minicache
- *	  v4wb		- ARMv4 with writeback cache, without minicache
- *	  v4_mc		- ARMv4 with minicache
- *	  xscale	- Xscale
- */
-#undef _USER
-#undef MULTI_USER
-
-#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
-# ifdef _USER
-#  define MULTI_USER 1
-# else
-#  define _USER v3
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM720T)
-# ifdef _USER
-#  define MULTI_USER 1
-# else
-#  define _USER v4wt
-# endif
-#endif
-
-#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
-    defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_SA110)   || \
-    defined(CONFIG_CPU_ARM1020)
-# ifdef _USER
-#  define MULTI_USER 1
-# else
-#  define _USER v4wb
-# endif
-#endif
-
-#if defined(CONFIG_CPU_SA1100)
-# ifdef _USER
-#  define MULTI_USER 1
-# else
-#  define _USER v4_mc
-# endif
-#endif
-
-#if defined(CONFIG_CPU_XSCALE)
-# ifdef _USER
-#  define MULTI_USER 1
-# else
-#  define _USER xscale_mc
-# endif
-#endif
-
-#ifndef _USER
-#error Unknown user operations model
 #endif
 
 #endif
diff -Nru a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h
--- a/include/asm-arm/hardirq.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-arm/hardirq.h	Tue Oct 15 20:29:17 2002
@@ -69,10 +69,18 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
+#ifdef CONFIG_PREEMPT
+# define in_atomic()	((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
+# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
+#else
+# define in_atomic()	(preempt_count() != 0)
+# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
+#endif
+
 #ifndef CONFIG_SMP
 #define irq_exit()							\
 	do {								\
-		preempt_count() -= HARDIRQ_OFFSET;			\
+		preempt_count() -= IRQ_EXIT_OFFSET;			\
 		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
 			__asm__("bl%? __do_softirq": : : "lr");/* out of line */\
 		preempt_enable_no_resched();				\
@@ -80,7 +88,7 @@
 
 #define synchronize_irq(irq)	barrier()
 #else
-#error SMP not supported
+extern void synchronize_irq(unsigned int irq);
 #endif
 
 #endif /* __ASM_HARDIRQ_H */
diff -Nru a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h
--- a/include/asm-arm/hardware/sa1111.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-arm/hardware/sa1111.h	Tue Oct 15 20:29:16 2002
@@ -64,10 +64,6 @@
 #define SA1111_SMCR	0x0004
 #define SA1111_SKID	0x0008
 
-#define SBI_SKCR	__CCREG(SA1111_SKCR)
-#define SBI_SMCR	__CCREG(SA1111_SMCR)
-#define SBI_SKID	__CCREG(SA1111_SKID)
-
 #define SKCR_PLL_BYPASS	(1<<0)
 #define SKCR_RCLKEN	(1<<1)
 #define SKCR_SLEEP	(1<<2)
@@ -130,16 +126,6 @@
 #define SA1111_SKPWM0	0x0218
 #define SA1111_SKPEN1	0x021c
 #define SA1111_SKPWM1	0x0220
-
-#define SKPCR		__CCREG(SA1111_SKPCR)
-#define SKCDR		__CCREG(SA1111_SKCDR)
-#define SKAUD		__CCREG(SA1111_SKAUD)
-#define SKPMC		__CCREG(SA1111_SKPMC)
-#define SKPTC		__CCREG(SA1111_SKPTC)
-#define SKPEN0		__CCREG(SA1111_SKPEN0)
-#define SKPWM0		__CCREG(SA1111_SKPWM0)
-#define SKPEN1		__CCREG(SA1111_SKPEN1)
-#define SKPWM1		__CCREG(SA1111_SKPWM1)
 
 #define SKPCR_UCLKEN	(1<<0)
 #define SKPCR_ACCLKEN	(1<<1)
diff -Nru a/include/asm-arm/ide.h b/include/asm-arm/ide.h
--- a/include/asm-arm/ide.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-arm/ide.h	Tue Oct 15 20:29:16 2002
@@ -36,7 +36,6 @@
  * The following are not needed for the non-m68k ports
  */
 #define ide_ack_intr(hwif)		(1)
-#define ide_fix_driveid(id)		do {} while (0)
 #define ide_release_lock(lock)		do {} while (0)
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
diff -Nru a/include/asm-arm/numnodes.h b/include/asm-arm/numnodes.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-arm/numnodes.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,17 @@
+/*
+ *  linux/include/asm-arm/numnodes.h
+ *
+ *  Copyright (C) 2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __ASM_ARM_NUMNODES_H
+#define __ASM_ARM_NUMNODES_H
+
+#include <asm/memory.h>
+
+#define MAX_NUMNODES	NR_NODES
+
+#endif
diff -Nru a/include/asm-arm/page.h b/include/asm-arm/page.h
--- a/include/asm-arm/page.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-arm/page.h	Tue Oct 15 20:29:12 2002
@@ -8,6 +8,70 @@
 
 #include <asm/glue.h>
 
+/*
+ *	User Space Model
+ *	================
+ *
+ *	This section selects the correct set of functions for dealing with
+ *	page-based copying and clearing for user space for the particular
+ *	processor(s) we're building for.
+ *
+ *	We have the following to choose from:
+ *	  v3		- ARMv3
+ *	  v4wt		- ARMv4 with writethrough cache, without minicache
+ *	  v4wb		- ARMv4 with writeback cache, without minicache
+ *	  v4_mc		- ARMv4 with minicache
+ *	  xscale	- Xscale
+ */
+#undef _USER
+#undef MULTI_USER
+
+#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
+# ifdef _USER
+#  define MULTI_USER 1
+# else
+#  define _USER v3
+# endif
+#endif
+
+#if defined(CONFIG_CPU_ARM720T)
+# ifdef _USER
+#  define MULTI_USER 1
+# else
+#  define _USER v4wt
+# endif
+#endif
+
+#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
+    defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_SA110)   || \
+    defined(CONFIG_CPU_ARM1020)
+# ifdef _USER
+#  define MULTI_USER 1
+# else
+#  define _USER v4wb
+# endif
+#endif
+
+#if defined(CONFIG_CPU_SA1100)
+# ifdef _USER
+#  define MULTI_USER 1
+# else
+#  define _USER v4_mc
+# endif
+#endif
+
+#if defined(CONFIG_CPU_XSCALE)
+# ifdef _USER
+#  define MULTI_USER 1
+# else
+#  define _USER xscale_mc
+# endif
+#endif
+
+#ifndef _USER
+#error Unknown user operations model
+#endif
+
 struct cpu_user_fns {
 	void (*cpu_clear_user_page)(void *p, unsigned long user);
 	void (*cpu_copy_user_page)(void *to, const void *from,
diff -Nru a/include/asm-arm/pci.h b/include/asm-arm/pci.h
--- a/include/asm-arm/pci.h	Tue Oct 15 20:29:15 2002
+++ b/include/asm-arm/pci.h	Tue Oct 15 20:29:15 2002
@@ -248,6 +248,10 @@
 void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr);
 #endif
 
+#define HAVE_PCI_MMAP
+extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+                               enum pci_mmap_state mmap_state, int write_combine);
+
 #endif /* __KERNEL__ */
  
 #endif
diff -Nru a/include/asm-arm/pgalloc.h b/include/asm-arm/pgalloc.h
--- a/include/asm-arm/pgalloc.h	Tue Oct 15 20:29:21 2002
+++ b/include/asm-arm/pgalloc.h	Tue Oct 15 20:29:21 2002
@@ -11,9 +11,6 @@
 #define _ASMARM_PGALLOC_H
 
 #include <asm/processor.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-
 #include <asm/proc/pgalloc.h>
 
 /*
diff -Nru a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
--- a/include/asm-arm/pgtable.h	Tue Oct 15 20:29:14 2002
+++ b/include/asm-arm/pgtable.h	Tue Oct 15 20:29:14 2002
@@ -12,6 +12,7 @@
 
 #include <linux/config.h>
 #include <asm/memory.h>
+#include <asm/proc-fns.h>
 #include <asm/arch/vmalloc.h>
 
 /*
diff -Nru a/include/asm-arm/proc-armo/system.h b/include/asm-arm/proc-armo/system.h
--- a/include/asm-arm/proc-armo/system.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-arm/proc-armo/system.h	Tue Oct 15 20:29:16 2002
@@ -10,8 +10,6 @@
 #ifndef __ASM_PROC_SYSTEM_H
 #define __ASM_PROC_SYSTEM_H
 
-#include <asm/proc-fns.h>
-
 #define vectors_base()	(0)
 
 static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
diff -Nru a/include/asm-arm/proc-armv/pgalloc.h b/include/asm-arm/proc-armv/pgalloc.h
--- a/include/asm-arm/proc-armv/pgalloc.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-arm/proc-armv/pgalloc.h	Tue Oct 15 20:29:17 2002
@@ -5,6 +5,7 @@
  *
  * Page table allocation/freeing primitives for 32-bit ARM processors.
  */
+#include <asm/cacheflush.h>
 #include "pgtable.h"
 
 /*
diff -Nru a/include/asm-arm/proc-armv/tlbflush.h b/include/asm-arm/proc-armv/tlbflush.h
--- a/include/asm-arm/proc-armv/tlbflush.h	Tue Oct 15 20:29:13 2002
+++ b/include/asm-arm/proc-armv/tlbflush.h	Tue Oct 15 20:29:13 2002
@@ -7,6 +7,113 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#include <linux/config.h>
+#include <asm/glue.h>
+
+#define TLB_V3_PAGE	(1 << 0)
+#define TLB_V4_U_PAGE	(1 << 1)
+#define TLB_V4_D_PAGE	(1 << 2)
+#define TLB_V4_I_PAGE	(1 << 3)
+
+#define TLB_V3_FULL	(1 << 8)
+#define TLB_V4_U_FULL	(1 << 9)
+#define TLB_V4_D_FULL	(1 << 10)
+#define TLB_V4_I_FULL	(1 << 11)
+
+#define TLB_WB		(1 << 31)
+
+/*
+ *	MMU TLB Model
+ *	=============
+ *
+ *	We have the following to choose from:
+ *	  v3    - ARMv3
+ *	  v4    - ARMv4 without write buffer
+ *	  v4wb  - ARMv4 with write buffer without I TLB flush entry instruction
+ *	  v4wbi - ARMv4 with write buffer with I TLB flush entry instruction
+ */
+#undef _TLB
+#undef MULTI_TLB
+
+#define v3_tlb_flags	(TLB_V3_FULL | TLB_V3_PAGE)
+
+#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB v3
+# endif
+#endif
+
+#define v4_tlb_flags	(TLB_V4_U_FULL | TLB_V4_U_PAGE)
+
+#if defined(CONFIG_CPU_ARM720T)
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB v4
+# endif
+#endif
+
+#define v4wbi_tlb_flags	(TLB_WB | \
+			 TLB_V4_I_FULL | TLB_V4_D_FULL | \
+			 TLB_V4_I_PAGE | TLB_V4_D_PAGE)
+
+#if defined(CONFIG_CPU_ARM920T) || defined(CONFIG_CPU_ARM922T) || \
+    defined(CONFIG_CPU_ARM926T) || defined(CONFIG_CPU_ARM1020) || \
+    defined(CONFIG_CPU_XSCALE)
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB v4wbi
+# endif
+#endif
+
+#define v4wb_tlb_flags	(TLB_WB | \
+			 TLB_V4_I_FULL | TLB_V4_D_FULL | \
+			 TLB_V4_D_PAGE)
+
+#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
+# ifdef _TLB
+#  define MULTI_TLB 1
+# else
+#  define _TLB v4wb
+# endif
+#endif
+
+#ifndef _TLB
+#error Unknown TLB model
+#endif
+
+#ifndef __ASSEMBLY__
+
+struct cpu_tlb_fns {
+	void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
+	void (*flush_kern_range)(unsigned long, unsigned long);
+	unsigned long tlb_flags;
+};
+
+/*
+ * Select the calling method
+ */
+#ifdef MULTI_TLB
+
+extern struct cpu_tlb_fns cpu_tlb;
+
+#define __cpu_flush_user_tlb_range	cpu_tlb.flush_user_range
+#define __cpu_flush_kern_tlb_range	cpu_tlb.flush_kern_range
+#define __cpu_tlb_flags			cpu_tlb.tlb_flags
+
+#else
+
+#define __cpu_flush_user_tlb_range	__glue(_TLB,_flush_user_tlb_range)
+#define __cpu_flush_kern_tlb_range	__glue(_TLB,_flush_kern_tlb_range)
+#define __cpu_tlb_flags			__glue(_TLB,_tlb_flags)
+
+extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
+extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
+
+#endif
 
 /*
  *	TLB Management
@@ -51,56 +158,94 @@
  *		- kaddr - Kernel virtual memory address
  */
 
-struct cpu_tlb_fns {
-	void (*flush_kern_all)(void);
-	void (*flush_user_mm)(struct mm_struct *);
-	void (*flush_user_range)(unsigned long, unsigned long, struct vm_area_struct *);
-	void (*flush_user_page)(unsigned long, struct vm_area_struct *);
-	void (*flush_kern_range)(unsigned long, unsigned long);
-	void (*flush_kern_page)(unsigned long);
-};
+#define tlb_flag(f)	(__cpu_tlb_flags & (f))
+
+static inline void flush_tlb_all(void)
+{
+	const int zero = 0;
+
+	if (tlb_flag(TLB_WB))
+		asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+
+	if (tlb_flag(TLB_V3_FULL))
+		asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
+	if (tlb_flag(TLB_V4_U_FULL))
+		asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero));
+	if (tlb_flag(TLB_V4_D_FULL))
+		asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero));
+	if (tlb_flag(TLB_V4_I_FULL))
+		asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+	const int zero = 0;
+
+	if (tlb_flag(TLB_WB))
+		asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+
+	if (mm == current->active_mm) {
+		if (tlb_flag(TLB_V3_FULL))
+			asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
+		if (tlb_flag(TLB_V4_U_FULL))
+			asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero));
+		if (tlb_flag(TLB_V4_D_FULL))
+			asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero));
+		if (tlb_flag(TLB_V4_I_FULL))
+			asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
+	}
+}
+
+static inline void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+	const int zero = 0;
+
+	uaddr &= PAGE_MASK;
+
+	if (tlb_flag(TLB_WB))
+		asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+
+	if (vma->vm_mm == current->active_mm) {
+		if (tlb_flag(TLB_V3_PAGE))
+			asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (uaddr));
+		if (tlb_flag(TLB_V4_U_PAGE))
+			asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (uaddr));
+		if (tlb_flag(TLB_V4_D_PAGE))
+			asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (uaddr));
+		if (tlb_flag(TLB_V4_I_PAGE))
+			asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
+		if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
+			asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
+	}
+}
+
+static inline void flush_tlb_kernel_page(unsigned long kaddr)
+{
+	const int zero = 0;
+
+	kaddr &= PAGE_MASK;
+
+	if (tlb_flag(TLB_WB))
+		asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+
+	if (tlb_flag(TLB_V3_PAGE))
+		asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (kaddr));
+	if (tlb_flag(TLB_V4_U_PAGE))
+		asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (kaddr));
+	if (tlb_flag(TLB_V4_D_PAGE))
+		asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (kaddr));
+	if (tlb_flag(TLB_V4_I_PAGE))
+		asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (kaddr));
+	if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
+		asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
+}
 
 /*
  * Convert calls to our calling convention.
  */
-#define flush_tlb_all()			__cpu_flush_kern_tlb_all()
-#define flush_tlb_mm(mm)		__cpu_flush_user_tlb_mm(mm)
 #define flush_tlb_range(vma,start,end)	__cpu_flush_user_tlb_range(start,end,vma)
-#define flush_tlb_page(vma,vaddr)	__cpu_flush_user_tlb_page(vaddr,vma)
 #define flush_tlb_kernel_range(s,e)	__cpu_flush_kern_tlb_range(s,e)
-#define flush_tlb_kernel_page(kaddr)	__cpu_flush_kern_tlb_page(kaddr)
-
-/*
- * Now select the calling method
- */
-#ifdef MULTI_TLB
-
-extern struct cpu_tlb_fns cpu_tlb;
-
-#define __cpu_flush_kern_tlb_all	cpu_tlb.flush_kern_all
-#define __cpu_flush_user_tlb_mm		cpu_tlb.flush_user_mm
-#define __cpu_flush_user_tlb_range	cpu_tlb.flush_user_range
-#define __cpu_flush_user_tlb_page	cpu_tlb.flush_user_page
-#define __cpu_flush_kern_tlb_range	cpu_tlb.flush_kern_range
-#define __cpu_flush_kern_tlb_page	cpu_tlb.flush_kern_page
-
-#else
-
-#define __cpu_flush_kern_tlb_all	__glue(_TLB,_flush_kern_tlb_all)
-#define __cpu_flush_user_tlb_mm		__glue(_TLB,_flush_user_tlb_mm)
-#define __cpu_flush_user_tlb_range	__glue(_TLB,_flush_user_tlb_range)
-#define __cpu_flush_user_tlb_page	__glue(_TLB,_flush_user_tlb_page)
-#define __cpu_flush_kern_tlb_range	__glue(_TLB,_flush_kern_tlb_range)
-#define __cpu_flush_kern_tlb_page	__glue(_TLB,_flush_kern_tlb_page)
-
-extern void __cpu_flush_kern_tlb_all(void);
-extern void __cpu_flush_user_tlb_mm(struct mm_struct *);
-extern void __cpu_flush_user_tlb_range(unsigned long, unsigned long, struct vm_area_struct *);
-extern void __cpu_flush_user_tlb_page(unsigned long, struct vm_area_struct *);
-extern void __cpu_flush_kern_tlb_range(unsigned long, unsigned long);
-extern void __cpu_flush_kern_tlb_page(unsigned long);
-
-#endif
 
 /*
  * if PG_dcache_dirty is set for the page, we need to ensure that any
@@ -123,3 +268,4 @@
 #define memc_update_addr(mm,pte,log)	do { } while (0)
 #define memc_clear(mm,physaddr)		do { } while (0)
 
+#endif
diff -Nru a/include/asm-arm/processor.h b/include/asm-arm/processor.h
--- a/include/asm-arm/processor.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-arm/processor.h	Tue Oct 15 20:29:17 2002
@@ -28,22 +28,30 @@
 #include <asm/procinfo.h>
 #include <asm/arch/memory.h>
 #include <asm/proc/processor.h>
+#include <asm/types.h>
+
+union debug_insn {
+	u32	arm;
+	u16	thumb;
+};
+
+struct debug_entry {
+	u32			address;
+	union debug_insn	insn;
+};
 
 struct debug_info {
-	int				nsaved;
-	struct {
-		unsigned long		address;
-		unsigned long		insn;
-	} bp[2];
+	int			nsaved;
+	struct debug_entry	bp[2];
 };
 
 struct thread_struct {
 							/* fault info	  */
-	unsigned long			address;
-	unsigned long			trap_no;
-	unsigned long			error_code;
+	unsigned long		address;
+	unsigned long		trap_no;
+	unsigned long		error_code;
 							/* debugging	  */
-	struct debug_info		debug;
+	struct debug_info	debug;
 };
 
 #define INIT_THREAD  {	}
diff -Nru a/include/asm-arm/procinfo.h b/include/asm-arm/procinfo.h
--- a/include/asm-arm/procinfo.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-arm/procinfo.h	Tue Oct 15 20:29:12 2002
@@ -12,8 +12,6 @@
 
 #ifndef __ASSEMBLY__
 
-#include <asm/proc-fns.h>
-
 struct cpu_tlb_fns;
 struct cpu_user_fns;
 struct processor;
diff -Nru a/include/asm-arm/tlb.h b/include/asm-arm/tlb.h
--- a/include/asm-arm/tlb.h	Tue Oct 15 20:29:11 2002
+++ b/include/asm-arm/tlb.h	Tue Oct 15 20:29:11 2002
@@ -1,21 +1,76 @@
+/*
+ *  linux/include/asm-arm/tlb.h
+ *
+ *  Copyright (C) 2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Experimentation shows that on a StrongARM, it appears to be faster
+ *  to use the "invalidate whole tlb" rather than "invalidate single
+ *  tlb" for this.
+ *
+ *  This appears true for both the process fork+exit case, as well as
+ *  the munmap-large-area case.
+ */
 #ifndef __ASMARM_TLB_H
 #define __ASMARM_TLB_H
 
-#include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-#define tlb_flush(tlb)		\
-	flush_tlb_mm((tlb)->mm)
-#define tlb_start_vma(tlb,vma)	\
-	flush_cache_range(vma, vma->vm_start, vma->vm_end)
-#define tlb_end_vma(tlb,vma)	\
-	flush_tlb_range(vma, vma->vm_start, vma->vm_end)
+/*
+ * TLB handling.  This allows us to remove pages from the page
+ * tables, and efficiently handle the TLB issues.
+ */
+typedef struct free_pte_ctx {
+	struct mm_struct	*mm;
+	unsigned int		freed;
 
-#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+	unsigned int		flushes;
+	unsigned int		avoided_flushes;
+} mmu_gather_t;
 
-#include <asm-generic/tlb.h>
+extern mmu_gather_t mmu_gathers[NR_CPUS];
 
-#define __pmd_free_tlb(tlb, pmd)	pmd_free(pmd)
-#define __pte_free_tlb(tlb, pte)	pte_free(pte)
+static inline mmu_gather_t *tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+{
+	int cpu = smp_processor_id();
+	mmu_gather_t *tlb = &mmu_gathers[cpu];
+
+	tlb->mm = mm;
+	tlb->freed = 0;
+
+	return tlb;
+}
+
+static inline void tlb_finish_mmu(mmu_gather_t *tlb, unsigned long start, unsigned long end)
+{
+	struct mm_struct *mm = tlb->mm;
+	unsigned long freed = tlb->freed;
+	int rss = mm->rss;
+
+	if (rss < freed)
+		freed = rss;
+	mm->rss = rss - freed;
+
+	if (freed) {
+		flush_tlb_mm(mm);
+		tlb->flushes++;
+	} else {
+		tlb->avoided_flushes++;
+	}
+
+	/* keep the page table cache within bounds */
+	check_pgt_cache();
+}
+
+#define tlb_remove_tlb_entry(tlb,ptep,address)	do { } while (0)
+#define tlb_start_vma(tlb,vma)			do { } while (0)
+#define tlb_end_vma(tlb,vma)			do { } while (0)
+
+#define tlb_remove_page(tlb,page)	free_page_and_swap_cache(page)
+#define pte_free_tlb(tlb,ptep)		pte_free(ptep)
+#define pmd_free_tlb(tlb,pmdp)		pmd_free(pmdp)
 
 #endif
diff -Nru a/include/asm-cris/uaccess.h b/include/asm-cris/uaccess.h
--- a/include/asm-cris/uaccess.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-cris/uaccess.h	Tue Oct 15 20:29:12 2002
@@ -147,25 +147,6 @@
 #define __put_user(x,ptr) \
   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
-/*
- * The "xxx_ret" versions return constant specified in third argument, if
- * something bad happens. These macros can be optimized for the
- * case of just returning from the function xxx_ret is used.
- */
-
-#define put_user_ret(x,ptr,ret) \
-	do { if (put_user(x,ptr)) return ret; } while (0)
-
-#define get_user_ret(x,ptr,ret) \
-	do { if (get_user(x,ptr)) return ret; } while (0)
-
-#define __put_user_ret(x,ptr,ret) \
-	do { if (__put_user(x,ptr)) return ret; } while (0)
-
-#define __get_user_ret(x,ptr,ret) \
-	do { if (__get_user(x,ptr)) return ret; } while (0)
-
-
 extern long __put_user_bad(void);
 
 #define __put_user_nocheck(x,ptr,size)			\
@@ -1016,11 +997,6 @@
 (__builtin_constant_p(n) ?			\
  __constant_copy_to_user(to, from, n) :		\
  __generic_copy_to_user(to, from, n))
-
-#define copy_to_user_ret(to,from,n,retval) \
-	do { if (copy_to_user(to,from,n)) return retval; } while (0)
-#define copy_from_user_ret(to,from,n,retval) \
-	do { if (copy_from_user(to,from,n)) return retval; } while (0)
 
 /* We let the __ versions of copy_from/to_user inline, because they're often
  * used in fast paths and have only a small space overhead.
diff -Nru a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h
--- a/include/asm-i386/apicdef.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-i386/apicdef.h	Tue Oct 15 20:29:17 2002
@@ -32,6 +32,8 @@
 #define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
 #define			APIC_ALL_CPUS		0xFF
 #define		APIC_DFR	0xE0
+#define			APIC_DFR_CLUSTER		0x0FFFFFFFul
+#define			APIC_DFR_FLAT			0xFFFFFFFFul
 #define		APIC_SPIV	0xF0
 #define			APIC_SPIV_FOCUS_DISABLED	(1<<9)
 #define			APIC_SPIV_APIC_ENABLED		(1<<8)
@@ -108,7 +110,11 @@
 
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
 
-#define MAX_IO_APICS 8
+#ifdef CONFIG_X86_NUMA
+ #define MAX_IO_APICS 32
+#else
+ #define MAX_IO_APICS 8
+#endif
 
 /*
  * the local APIC register structure, memory mapped. Not terribly well
diff -Nru a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
--- a/include/asm-i386/hw_irq.h	Tue Oct 15 20:29:23 2002
+++ b/include/asm-i386/hw_irq.h	Tue Oct 15 20:29:23 2002
@@ -13,6 +13,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/profile.h>
 #include <asm/atomic.h>
 #include <asm/irq.h>
 
@@ -65,20 +66,31 @@
 
 #define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
 
-extern unsigned long prof_cpu_mask;
-extern unsigned int * prof_buffer;
-extern unsigned long prof_len;
-extern unsigned long prof_shift;
-
 /*
- * x86 profiling function, SMP safe. We might want to do this in
- * assembly totally?
+ * The profiling function is SMP safe. (nothing can mess
+ * around with "current", and the profiling counters are
+ * updated with atomic operations). This is especially
+ * useful with a profiling multiplier != 1
  */
-static inline void x86_do_profile (unsigned long eip)
+static inline void x86_do_profile(struct pt_regs * regs)
 {
+	unsigned long eip;
+	extern unsigned long prof_cpu_mask;
+	extern char _stext;
+#ifdef CONFIG_PROFILING
+	extern void x86_profile_hook(struct pt_regs *);
+ 
+	x86_profile_hook(regs);
+#endif
+ 
+	if (user_mode(regs))
+		return;
+ 
 	if (!prof_buffer)
 		return;
 
+	eip = regs->eip;
+ 
 	/*
 	 * Only measure the CPUs specified by /proc/irq/prof_cpu_mask.
 	 * (default is all CPUs.)
@@ -97,7 +109,28 @@
 		eip = prof_len-1;
 	atomic_inc((atomic_t *)&prof_buffer[eip]);
 }
+ 
+struct notifier_block;
+ 
+#ifdef CONFIG_PROFILING
+ 
+int register_profile_notifier(struct notifier_block * nb);
+int unregister_profile_notifier(struct notifier_block * nb);
+
+#else
+
+static inline int register_profile_notifier(struct notifier_block * nb)
+{
+	return -ENOSYS;
+}
+
+static inline int unregister_profile_notifier(struct notifier_block * nb)
+{
+	return -ENOSYS;
+}
 
+#endif /* CONFIG_PROFILING */
+ 
 #ifdef CONFIG_SMP /*more of this file should probably be ifdefed SMP */
 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {
 	if (IO_APIC_IRQ(i))
diff -Nru a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
--- a/include/asm-i386/mpspec.h	Tue Oct 15 20:29:10 2002
+++ b/include/asm-i386/mpspec.h	Tue Oct 15 20:29:10 2002
@@ -16,11 +16,11 @@
 /*
  * a maximum of 16 APICs with the current APIC ID architecture.
  */
-#ifdef CONFIG_X86_NUMAQ
+#ifdef CONFIG_X86_NUMA
 #define MAX_APICS 256
-#else /* !CONFIG_X86_NUMAQ */
+#else /* !CONFIG_X86_NUMA */
 #define MAX_APICS 16
-#endif /* CONFIG_X86_NUMAQ */
+#endif /* CONFIG_X86_NUMA */
 
 #define MAX_MPC_ENTRY 1024
 
diff -Nru a/include/asm-i386/msr.h b/include/asm-i386/msr.h
--- a/include/asm-i386/msr.h	Tue Oct 15 20:29:11 2002
+++ b/include/asm-i386/msr.h	Tue Oct 15 20:29:11 2002
@@ -99,7 +99,13 @@
 #define MSR_K6_PFIR			0xC0000088
 
 #define MSR_K7_EVNTSEL0			0xC0010000
+#define MSR_K7_EVNTSEL1			0xC0010001
+#define MSR_K7_EVNTSEL2			0xC0010002
+#define MSR_K7_EVNTSEL3			0xC0010003
 #define MSR_K7_PERFCTR0			0xC0010004
+#define MSR_K7_PERFCTR1			0xC0010005
+#define MSR_K7_PERFCTR2			0xC0010006
+#define MSR_K7_PERFCTR3			0xC0010007
 #define MSR_K7_HWCR			0xC0010015
 #define MSR_K7_FID_VID_CTL		0xC0010041
 #define MSR_K7_VID_STATUS		0xC0010042
diff -Nru a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/nmi.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,49 @@
+/*
+ *  linux/include/asm-i386/nmi.h
+ */
+#ifndef ASM_NMI_H
+#define ASM_NMI_H
+
+#include <linux/pm.h>
+ 
+struct pt_regs;
+ 
+typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
+ 
+/** 
+ * set_nmi_callback
+ *
+ * Set a handler for an NMI. Only one handler may be
+ * set. Return 1 if the NMI was handled.
+ */
+void set_nmi_callback(nmi_callback_t callback);
+ 
+/** 
+ * unset_nmi_callback
+ *
+ * Remove the handler previously set.
+ */
+void unset_nmi_callback(void);
+ 
+#ifdef CONFIG_PM
+ 
+/** Replace the PM callback routine for NMI. */
+struct pm_dev * set_nmi_pm_callback(pm_callback callback);
+
+/** Unset the PM callback routine back to the default. */
+void unset_nmi_pm_callback(struct pm_dev * dev);
+
+#else
+
+static inline struct pm_dev * set_nmi_pm_callback(pm_callback callback)
+{
+	return 0;
+} 
+ 
+static inline void unset_nmi_pm_callback(struct pm_dev * dev)
+{
+}
+
+#endif /* CONFIG_PM */
+ 
+#endif /* ASM_NMI_H */
diff -Nru a/include/asm-i386/smp.h b/include/asm-i386/smp.h
--- a/include/asm-i386/smp.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-i386/smp.h	Tue Oct 15 20:29:17 2002
@@ -21,17 +21,10 @@
 #endif
 #endif
 
-#ifdef CONFIG_SMP
-# ifdef CONFIG_CLUSTERED_APIC
-#  define TARGET_CPUS 0xf     /* all CPUs in *THIS* quad */
-#  define INT_DELIVERY_MODE 0     /* physical delivery on LOCAL quad */
-# else
-#  define TARGET_CPUS cpu_online_map
-#  define INT_DELIVERY_MODE 1     /* logical delivery broadcast to all procs */
-# endif
+#ifdef CONFIG_CLUSTERED_APIC
+ #define INT_DELIVERY_MODE 0     /* physical delivery on LOCAL quad */
 #else
-# define INT_DELIVERY_MODE 1     /* logical delivery */
-# define TARGET_CPUS 0x01
+ #define INT_DELIVERY_MODE 1     /* logical delivery broadcast to all procs */
 #endif
 
 #ifndef clustered_apic_mode
@@ -72,6 +65,7 @@
  * the real APIC ID <-> CPU # mapping.
  */
 #define MAX_APICID 256
+#define BAD_APICID 0xFFu
 extern volatile int cpu_to_physical_apicid[NR_CPUS];
 extern volatile int physical_apicid_to_cpu[MAX_APICID];
 extern volatile int cpu_to_logical_apicid[NR_CPUS];
diff -Nru a/include/asm-i386/smpboot.h b/include/asm-i386/smpboot.h
--- a/include/asm-i386/smpboot.h	Tue Oct 15 20:29:21 2002
+++ b/include/asm-i386/smpboot.h	Tue Oct 15 20:29:21 2002
@@ -24,15 +24,6 @@
 #endif /* CONFIG_CLUSTERED_APIC */
 
 /*
- * How to map from the cpu_present_map
- */
-#ifdef CONFIG_CLUSTERED_APIC
- #define cpu_present_to_apicid(mps_cpu) ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) )
-#else /* !CONFIG_CLUSTERED_APIC */
- #define cpu_present_to_apicid(apicid) (apicid)
-#endif /* CONFIG_CLUSTERED_APIC */
-
-/*
  * Mappings between logical cpu number and logical / physical apicid
  * The first four macros are trivial, but it keeps the abstraction consistent
  */
diff -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
--- a/include/asm-i386/unistd.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-i386/unistd.h	Tue Oct 15 20:29:17 2002
@@ -257,6 +257,8 @@
 #define __NR_alloc_hugepages	250
 #define __NR_free_hugepages	251
 #define __NR_exit_group		252
+#define __NR_lookup_dcookie	253
+  
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 
diff -Nru a/include/asm-sparc64/checksum.h b/include/asm-sparc64/checksum.h
--- a/include/asm-sparc64/checksum.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-sparc64/checksum.h	Tue Oct 15 20:29:16 2002
@@ -78,45 +78,8 @@
 /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
  * the majority of the time.
  */
-static __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
-					      unsigned int ihl)
-{
-	unsigned short sum;
-
-	/* Note: We must read %2 before we touch %0 for the first time,
-	 *       because GCC can legitimately use the same register for
-	 *       both operands.
-	 */
-	__asm__ __volatile__(
-"	sub		%2, 4, %%g7		! IEU0\n"
-"	lduw		[%1 + 0x00], %0		! Load	Group\n"
-"	lduw		[%1 + 0x04], %%g2	! Load	Group\n"
-"	lduw		[%1 + 0x08], %%g3	! Load	Group\n"
-"	addcc		%%g2, %0, %0		! IEU1	1 Load Bubble + Group\n"
-"	lduw		[%1 + 0x0c], %%g2	! Load\n"
-"	addccc		%%g3, %0, %0		! Sngle	Group no Bubble\n"
-"	lduw		[%1 + 0x10], %%g3	! Load	Group\n"
-"	addccc		%%g2, %0, %0		! Sngle	Group no Bubble\n"
-"	addc		%0, %%g0, %0		! Sngle Group\n"
-"1:	addcc		%%g3, %0, %0		! IEU1	Group no Bubble\n"
-"	add		%1, 4, %1		! IEU0\n"
-"	addccc		%0, %%g0, %0		! Sngle Group no Bubble\n"
-"	subcc		%%g7, 1, %%g7		! IEU1	Group\n"
-"	be,a,pt		%%icc, 2f		! CTI\n"
-"	 sll		%0, 16, %%g2		! IEU0\n"
-"	lduw		[%1 + 0x10], %%g3	! Load	Group\n"
-"	ba,pt		%%xcc, 1b		! CTI\n"
-"	 nop					! IEU0\n"
-"2:	addcc		%0, %%g2, %%g2		! IEU1	Group\n"
-"	srl		%%g2, 16, %0		! IEU0	Group regdep	XXX Scheisse!\n"
-"	addc		%0, %%g0, %0		! Sngle	Group\n"
-"	xnor		%%g0, %0, %0		! IEU0	Group\n"
-"	srl		%0, 0, %0		! IEU0	Group		XXX Scheisse!\n"
-	: "=r" (sum), "=&r" (iph)
-	: "r" (ihl), "1" (iph)
-	: "g2", "g3", "g7", "cc");
-	return sum;
-}
+extern unsigned short ip_fast_csum(__const__ unsigned char *iph,
+				   unsigned int ihl);
 
 /* Fold a partial checksum without adding pseudo headers. */
 static __inline__ unsigned short csum_fold(unsigned int sum)
diff -Nru a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h
--- a/include/asm-sparc64/irq.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-sparc64/irq.h	Tue Oct 15 20:29:17 2002
@@ -93,7 +93,7 @@
 #define IBF_MULTI	0x08	/* On PCI, indicates shared bucket.		 */
 #define IBF_INPROGRESS	0x10	/* IRQ is being serviced.			 */
 
-#define NUM_IVECS	8192
+#define NUM_IVECS	(IMAP_INR + 1)
 extern struct ino_bucket ivector_table[NUM_IVECS];
 
 #define __irq_ino(irq) \
diff -Nru a/include/asm-sparc64/semaphore.h b/include/asm-sparc64/semaphore.h
--- a/include/asm-sparc64/semaphore.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-sparc64/semaphore.h	Tue Oct 15 20:29:16 2002
@@ -47,184 +47,10 @@
 	sema_init(sem, 0);
 }
 
-extern void __down(struct semaphore * sem);
-extern int  __down_interruptible(struct semaphore * sem);
-extern void __up(struct semaphore * sem);
-
-static __inline__ void down(struct semaphore * sem)
-{
-	/* This atomically does:
-	 * 	old_val = sem->count;
-	 *	new_val = sem->count - 1;
-	 *	sem->count = new_val;
-	 *	if (old_val < 1)
-	 *		__down(sem);
-	 *
-	 * The (old_val < 1) test is equivalent to
-	 * the more straightforward (new_val < 0),
-	 * but it is easier to test the former because
-	 * of how the CAS instruction works.
-	 */
-
-	__asm__ __volatile__("\n"
-"	! down sem(%0)\n"
-"1:	lduw	[%0], %%g5\n"
-"	sub	%%g5, 1, %%g7\n"
-"	cas	[%0], %%g5, %%g7\n"
-"	cmp	%%g5, %%g7\n"
-"	bne,pn	%%icc, 1b\n"
-"	 cmp	%%g7, 1\n"
-"	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreLoad | #StoreStore\n"
-"2:\n"
-"	.subsection 2\n"
-"3:	mov	%0, %%g5\n"
-"	save	%%sp, -160, %%sp\n"
-"	mov	%%g1, %%l1\n"
-"	mov	%%g2, %%l2\n"
-"	mov	%%g3, %%l3\n"
-"	call	%1\n"
-"	 mov	%%g5, %%o0\n"
-"	mov	%%l1, %%g1\n"
-"	mov	%%l2, %%g2\n"
-"	ba,pt	%%xcc, 2b\n"
-"	 restore %%l3, %%g0, %%g3\n"
-"	.previous\n"
-	: : "r" (sem), "i" (__down)
-	: "g5", "g7", "memory", "cc");
-}
-
-static __inline__ int down_interruptible(struct semaphore *sem)
-{
-	int ret = 0;
-	
-	/* This atomically does:
-	 * 	old_val = sem->count;
-	 *	new_val = sem->count - 1;
-	 *	sem->count = new_val;
-	 *	if (old_val < 1)
-	 *		ret = __down_interruptible(sem);
-	 *
-	 * The (old_val < 1) test is equivalent to
-	 * the more straightforward (new_val < 0),
-	 * but it is easier to test the former because
-	 * of how the CAS instruction works.
-	 */
-
-	__asm__ __volatile__("\n"
-"	! down_interruptible sem(%2) ret(%0)\n"
-"1:	lduw	[%2], %%g5\n"
-"	sub	%%g5, 1, %%g7\n"
-"	cas	[%2], %%g5, %%g7\n"
-"	cmp	%%g5, %%g7\n"
-"	bne,pn	%%icc, 1b\n"
-"	 cmp	%%g7, 1\n"
-"	bl,pn	%%icc, 3f\n"
-"	 membar	#StoreLoad | #StoreStore\n"
-"2:\n"
-"	.subsection 2\n"
-"3:	mov	%2, %%g5\n"
-"	save	%%sp, -160, %%sp\n"
-"	mov	%%g1, %%l1\n"
-"	mov	%%g2, %%l2\n"
-"	mov	%%g3, %%l3\n"
-"	call	%3\n"
-"	 mov	%%g5, %%o0\n"
-"	mov	%%l1, %%g1\n"
-"	mov	%%l2, %%g2\n"
-"	mov	%%l3, %%g3\n"
-"	ba,pt	%%xcc, 2b\n"
-"	 restore %%o0, %%g0, %0\n"
-"	.previous\n"
-	: "=r" (ret)
-	: "0" (ret), "r" (sem), "i" (__down_interruptible)
-	: "g5", "g7", "memory", "cc");
-	return ret;
-}
-
-static __inline__ int down_trylock(struct semaphore *sem)
-{
-	int ret;
-
-	/* This atomically does:
-	 * 	old_val = sem->count;
-	 *	new_val = sem->count - 1;
-	 *	if (old_val < 1) {
-	 *		ret = 1;
-	 *	} else {
-	 *		sem->count = new_val;
-	 *		ret = 0;
-	 *	}
-	 *
-	 * The (old_val < 1) test is equivalent to
-	 * the more straightforward (new_val < 0),
-	 * but it is easier to test the former because
-	 * of how the CAS instruction works.
-	 */
-
-	__asm__ __volatile__("\n"
-"	! down_trylock sem(%1) ret(%0)\n"
-"1:	lduw	[%1], %%g5\n"
-"	sub	%%g5, 1, %%g7\n"
-"	cmp	%%g5, 1\n"
-"	bl,pn	%%icc, 2f\n"
-"	 mov	1, %0\n"
-"	cas	[%1], %%g5, %%g7\n"
-"	cmp	%%g5, %%g7\n"
-"	bne,pn	%%icc, 1b\n"
-"	 mov	0, %0\n"
-"	membar	#StoreLoad | #StoreStore\n"
-"2:\n"
-	: "=&r" (ret)
-	: "r" (sem)
-	: "g5", "g7", "memory", "cc");
-
-	return ret;
-}
-
-static __inline__ void up(struct semaphore * sem)
-{
-	/* This atomically does:
-	 * 	old_val = sem->count;
-	 *	new_val = sem->count + 1;
-	 *	sem->count = new_val;
-	 *	if (old_val < 0)
-	 *		__up(sem);
-	 *
-	 * The (old_val < 0) test is equivalent to
-	 * the more straightforward (new_val <= 0),
-	 * but it is easier to test the former because
-	 * of how the CAS instruction works.
-	 */
-
-	__asm__ __volatile__("\n"
-"	! up sem(%0)\n"
-"	membar	#StoreLoad | #LoadLoad\n"
-"1:	lduw	[%0], %%g5\n"
-"	add	%%g5, 1, %%g7\n"
-"	cas	[%0], %%g5, %%g7\n"
-"	cmp	%%g5, %%g7\n"
-"	bne,pn	%%icc, 1b\n"
-"	 addcc	%%g7, 1, %%g0\n"
-"	ble,pn	%%icc, 3f\n"
-"	 membar	#StoreLoad | #StoreStore\n"
-"2:\n"
-"	.subsection 2\n"
-"3:	mov	%0, %%g5\n"
-"	save	%%sp, -160, %%sp\n"
-"	mov	%%g1, %%l1\n"
-"	mov	%%g2, %%l2\n"
-"	mov	%%g3, %%l3\n"
-"	call	%1\n"
-"	 mov	%%g5, %%o0\n"
-"	mov	%%l1, %%g1\n"
-"	mov	%%l2, %%g2\n"
-"	ba,pt	%%xcc, 2b\n"
-"	 restore %%l3, %%g0, %%g3\n"
-"	.previous\n"
-	: : "r" (sem), "i" (__up)
-	: "g5", "g7", "memory", "cc");
-}
+extern void up(struct semaphore *sem);
+extern void down(struct semaphore *sem);
+extern int down_trylock(struct semaphore *sem);
+extern int down_interruptible(struct semaphore *sem);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-um/cache.h b/include/asm-um/cache.h
--- a/include/asm-um/cache.h	Tue Oct 15 20:29:15 2002
+++ b/include/asm-um/cache.h	Tue Oct 15 20:29:15 2002
@@ -1,7 +1,10 @@
 #ifndef __UM_CACHE_H
 #define __UM_CACHE_H
 
+/* These are x86 numbers */
 #define L1_CACHE_SHIFT 5
 #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
+
+#define L1_CACHE_SHIFT_MAX 7	/* largest L1 which this arch supports */
 
 #endif
diff -Nru a/include/asm-um/smp.h b/include/asm-um/smp.h
--- a/include/asm-um/smp.h	Tue Oct 15 20:29:11 2002
+++ b/include/asm-um/smp.h	Tue Oct 15 20:29:11 2002
@@ -6,14 +6,29 @@
 #ifdef CONFIG_SMP
 
 #include "linux/config.h"
+#include "linux/bitops.h"
 #include "asm/current.h"
 
-#define smp_processor_id() (current->processor)
+#define smp_processor_id() (current->thread_info->cpu)
 #define cpu_logical_map(n) (n)
 #define cpu_number_map(n) (n)
 #define PROC_CHANGE_PENALTY	15 /* Pick a number, any number */
 extern int hard_smp_processor_id(void);
 #define NO_PROC_ID -1
+
+#define cpu_online(cpu) (cpu_online_map & (1<<(cpu)))
+
+extern int ncpus;
+#define cpu_possible(cpu) (cpu < ncpus)
+
+extern inline unsigned int num_online_cpus(void)
+{
+	return(hweight32(cpu_online_map));
+}
+
+extern inline void smp_cpus_done(unsigned int maxcpus)
+{
+}
 
 #endif
 
diff -Nru a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
--- a/include/asm-um/thread_info.h	Tue Oct 15 20:29:15 2002
+++ b/include/asm-um/thread_info.h	Tue Oct 15 20:29:15 2002
@@ -64,10 +64,14 @@
 #define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 #define TIF_SIGPENDING		1	/* signal pending */
 #define TIF_NEED_RESCHED	2	/* rescheduling necessary */
+#define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling 
+					 * TIF_NEED_RESCHED 
+					 */
 
 #define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 #define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
+#define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
 
 #endif
 
diff -Nru a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-x86_64/acpi.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,147 @@
+/*
+ *  asm-x86_64/acpi.h
+ *
+ *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *  Copyright (C) 2001 Patrick Mochel <mochel@osdl.org>
+  *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef _ASM_ACPI_H
+#define _ASM_ACPI_H
+
+#ifdef __KERNEL__
+
+#define COMPILER_DEPENDENT_INT64   long long
+#define COMPILER_DEPENDENT_UINT64  unsigned long long
+
+/*
+ * Calling conventions:
+ *
+ * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces 
+ * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
+ * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
+ */
+#define ACPI_SYSTEM_XFACE
+#define ACPI_EXTERNAL_XFACE
+#define ACPI_INTERNAL_XFACE
+#define ACPI_INTERNAL_VAR_XFACE
+
+/* Asm macros */
+
+#define ACPI_ASM_MACROS
+#define BREAKPOINT3
+#define ACPI_DISABLE_IRQS() __cli()
+#define ACPI_ENABLE_IRQS()  __sti()
+#define ACPI_FLUSH_CPU_CACHE()	wbinvd()
+
+/*
+ * A brief explanation as GNU inline assembly is a bit hairy
+ *  %0 is the output parameter in RAX ("=a")
+ *  %1 and %2 are the input parameters in RCX ("c")
+ *  and an immediate value ("i") respectively
+ *  All actual register references are preceded with "%%" as in "%%edx"
+ *  Immediate values in the assembly are preceded by "$" as in "$0x1"
+ *  The final asm parameter are the operation altered non-output registers.
+ */
+#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
+	do { \
+		unsigned long dummy; \
+		asm("1:     movl (%2),%%eax;" \
+			"movl   %%eax,%%edx;" \
+			"andq   %2,%%rdx;" \
+			"btsl   $0x1,%%edx;" \
+			"adcl   $0x0,%%edx;" \
+			"lock;  cmpxchgl %%edx,(%1);" \
+			"jnz    1b;" \
+			"cmpb   $0x3,%%dl;" \
+			"sbbl   %%eax,%%eax" \
+			:"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \
+	} while(0)
+#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
+	do { \
+		unsigned long dummy; \
+		asm("1:     movl (%2),%%eax;" \
+			"movl   %%eax,%%edx;" \
+			"andq   %2,%%rdx;" \
+			"lock;  cmpxchgl %%edx,(%1);" \
+			"jnz    1b;" \
+			"andl   $0x1,%%eax" \
+			:"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \
+	} while(0)
+
+/*
+ * Math helper asm macros
+ */
+#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \
+        asm("divl %2;"        \
+        :"=a"(q32), "=d"(r32) \
+        :"r"(d32),            \
+        "0"(n_lo), "1"(n_hi))
+
+
+#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \
+    asm("shrl   $1,%2;"             \
+        "rcrl   $1,%3;"             \
+        :"=r"(n_hi), "=r"(n_lo)     \
+        :"0"(n_hi), "1"(n_lo))
+
+
+#ifndef CONFIG_ACPI_BOOT
+#define acpi_lapic 0
+#define acpi_ioapic 0
+#else
+#ifdef CONFIG_X86_LOCAL_APIC
+extern int acpi_lapic;
+#else
+#define acpi_lapic 0
+#endif
+#ifdef CONFIG_X86_IO_APIC
+extern int acpi_ioapic;
+#else
+#define acpi_ioapic 0
+#endif
+
+/* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
+#define FIX_ACPI_PAGES 4
+
+#endif /*CONFIG_ACPI_BOOT*/
+
+#ifdef CONFIG_ACPI_SLEEP
+
+/* routines for saving/restoring kernel state */
+extern int acpi_save_state_mem(void);
+extern int acpi_save_state_disk(void);
+extern void acpi_restore_state_mem(void);
+
+extern unsigned long acpi_wakeup_address;
+
+/* early initialization routine */
+extern void acpi_reserve_bootmem(void);
+
+#endif /*CONFIG_ACPI_SLEEP*/
+
+#define boot_cpu_physical_apicid boot_cpu_id
+
+extern int acpi_disabled;
+
+#endif /*__KERNEL__*/
+
+#endif /*_ASM_ACPI_H*/
diff -Nru a/include/asm-x86_64/agp.h b/include/asm-x86_64/agp.h
--- a/include/asm-x86_64/agp.h	Tue Oct 15 20:29:10 2002
+++ b/include/asm-x86_64/agp.h	Tue Oct 15 20:29:10 2002
@@ -11,8 +11,8 @@
  */
 
 #define map_page_into_agp(page) \
-      change_page_attr(page, __pgprot(__PAGE_KERNEL | _PAGE_PCD))
-#define unmap_page_from_agp(page) change_page_attr(page, PAGE_KERNEL)
+      change_page_attr(page, 1, PAGE_KERNEL_NOCACHE)
+#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL)
 #define flush_agp_mappings() global_flush_tlb()
 
 /* Could use CLFLUSH here if the cpu supports it. But then it would
diff -Nru a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
--- a/include/asm-x86_64/apic.h	Tue Oct 15 20:29:21 2002
+++ b/include/asm-x86_64/apic.h	Tue Oct 15 20:29:21 2002
@@ -9,7 +9,7 @@
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
-#define APIC_DEBUG 0
+#define APIC_DEBUG 1
 
 #if APIC_DEBUG
 #define Dprintk(x...) printk(x)
@@ -17,6 +17,8 @@
 #define Dprintk(x...)
 #endif
 
+struct pt_regs;
+
 /*
  * Basic functions accessing APICs.
  */
@@ -70,7 +72,8 @@
 extern void setup_local_APIC (void);
 extern void init_apic_mappings (void);
 extern void smp_local_timer_interrupt (struct pt_regs * regs);
-extern void setup_APIC_clocks (void);
+extern void setup_boot_APIC_clock (void);
+extern void setup_secondary_APIC_clock (void);
 extern void setup_apic_nmi_watchdog (void);
 extern inline void nmi_watchdog_tick (struct pt_regs * regs);
 extern int APIC_init_uniprocessor (void);
@@ -80,7 +83,6 @@
 extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback);
 extern void apic_pm_unregister(struct pm_dev*);
 
-extern unsigned int apic_timer_irqs [NR_CPUS];
 extern int check_nmi_watchdog (void);
 
 extern unsigned int nmi_watchdog;
diff -Nru a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
--- a/include/asm-x86_64/bitops.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-x86_64/bitops.h	Tue Oct 15 20:29:16 2002
@@ -384,6 +384,32 @@
 	return (offset + set + res);
 }
 
+/* 
+ * Find string of zero bits in a bitmap. -1 when not found.
+ */ 
+extern unsigned long 
+find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len);
+
+static inline void set_bit_string(unsigned long *bitmap, unsigned long i, 
+				  int len) 
+{ 
+	unsigned long end = i + len; 
+	while (i < end) {
+		__set_bit(i, bitmap); 
+		i++;
+	}
+} 
+
+static inline void clear_bit_string(unsigned long *bitmap, unsigned long i, 
+				    int len) 
+{ 
+	unsigned long end = i + len; 
+	while (i < end) {
+		clear_bit(i, bitmap); 
+		i++;
+	}
+} 
+
 /**
  * ffz - find first zero in word.
  * @word: The word to search
diff -Nru a/include/asm-x86_64/cacheflush.h b/include/asm-x86_64/cacheflush.h
--- a/include/asm-x86_64/cacheflush.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/cacheflush.h	Tue Oct 15 20:29:12 2002
@@ -1,5 +1,5 @@
-#ifndef _I386_CACHEFLUSH_H
-#define _I386_CACHEFLUSH_H
+#ifndef _X8664_CACHEFLUSH_H
+#define _X8664_CACHEFLUSH_H
 
 /* Keep includes the same across arches.  */
 #include <linux/mm.h>
@@ -18,4 +18,4 @@
 void global_flush_tlb(void); 
 int change_page_attr(struct page *page, int numpages, pgprot_t prot);
 
-#endif /* _I386_CACHEFLUSH_H */
+#endif /* _X8664_CACHEFLUSH_H */
diff -Nru a/include/asm-x86_64/calling.h b/include/asm-x86_64/calling.h
--- a/include/asm-x86_64/calling.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-x86_64/calling.h	Tue Oct 15 20:29:17 2002
@@ -117,7 +117,7 @@
 	subq $6*8,%rsp
 	movq %rax,5*8(%rsp)  /* ss */
 	movq %rax,4*8(%rsp)  /* rsp */
-	movq %rax,3*8(%rsp)  /* eflags */
+	movq $(1<<9),3*8(%rsp)  /* eflags */
 	movq $__KERNEL_CS,2*8(%rsp) /* cs */
 	movq \child_rip,1*8(%rsp)  /* rip */ 
 	movq %rax,(%rsp)   /* orig_rax */ 
diff -Nru a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h
--- a/include/asm-x86_64/cpufeature.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-x86_64/cpufeature.h	Tue Oct 15 20:29:17 2002
@@ -80,6 +80,6 @@
 #define cpu_has_k6_mtrr        0
 #define cpu_has_cyrix_arr      0
 #define cpu_has_centaur_mcr    0
-
+#define cpu_has_clflush	       boot_cpu_has(X86_FEATURE_CLFLSH)
 
 #endif /* __ASM_X8664_CPUFEATURE_H */
diff -Nru a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h
--- a/include/asm-x86_64/desc.h	Tue Oct 15 20:29:23 2002
+++ b/include/asm-x86_64/desc.h	Tue Oct 15 20:29:23 2002
@@ -7,16 +7,21 @@
 
 #ifndef __ASSEMBLY__
 
-/* Keep this syncronized with kernel/head.S */
-#define TSS_START (8 * 8)
-#define LDT_START (TSS_START + 16) 
-
-#define __TSS(n)  (TSS_START + (n)*64)
-#define __LDT(n)  (LDT_START + (n)*64)
-
-extern __u8 tss_start[]; 
-extern __u8 gdt_table[];
-extern __u8 gdt_end[];
+#include <asm/segment.h>
+
+// 8 byte segment descriptor
+struct desc_struct { 
+	u16 limit0;
+	u16 base0;
+	unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1;
+	unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8;
+} __attribute__((packed)); 
+
+struct n_desc_struct { 
+	unsigned int a,b;
+}; 	
+
+extern struct desc_struct cpu_gdt_table[NR_CPUS][GDT_ENTRIES];
 
 enum { 
 	GATE_INTERRUPT = 0xE, 
@@ -38,14 +43,6 @@
 #define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF)
 #define PTR_HIGH(x) ((unsigned long)(x) >> 32)
 
-// 8 byte segment descriptor
-struct desc_struct { 
-	u16 limit0;
-	u16 base0;
-	unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1;
-	unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8;
-} __attribute__((packed)); 
-
 enum { 
 	DESC_TSS = 0x9,
 	DESC_LDT = 0x2,
@@ -66,9 +63,9 @@
 	unsigned long address;
 } __attribute__((packed)) ;
 
-#define load_TR(n) asm volatile("ltr %w0"::"r" (__TSS(n)))
-#define __load_LDT(n) asm volatile("lldt %w0"::"r" (__LDT(n)))
-#define clear_LDT(n)  asm volatile("lldt %w0"::"r" (0))
+#define load_TR_desc() asm volatile("ltr %w0"::"r" (GDT_ENTRY_TSS*8))
+#define load_LDT_desc() asm volatile("lldt %w0"::"r" (GDT_ENTRY_LDT*8))
+#define clear_LDT()  asm volatile("lldt %w0"::"r" (0))
 
 /*
  * This is the ldt that every process will get unless we need
@@ -125,34 +122,95 @@
 	memcpy(ptr, &d, 16); 
 }
 
-static inline void set_tss_desc(unsigned n, void *addr)
+static inline void set_tss_desc(unsigned cpu, void *addr)
 { 
-	set_tssldt_descriptor((__u8*)gdt_table + __TSS(n), (unsigned long)addr, 
+	set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS], (unsigned long)addr, 
 			      DESC_TSS,
 			      sizeof(struct tss_struct)); 
 } 
 
-static inline void set_ldt_desc(unsigned n, void *addr, int size)
+static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
 { 
-	set_tssldt_descriptor((__u8*)gdt_table + __LDT(n), (unsigned long)addr, 
+	set_tssldt_descriptor(&cpu_gdt_table[cpu][GDT_ENTRY_TSS], (unsigned long)addr, 
 			      DESC_LDT, size); 
 }
 
+#define LDT_entry_a(info) \
+	((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
+#define LDT_entry_b(info) \
+	(((info)->base_addr & 0xff000000) | \
+	(((info)->base_addr & 0x00ff0000) >> 16) | \
+	((info)->limit & 0xf0000) | \
+	(((info)->read_exec_only ^ 1) << 9) | \
+	((info)->contents << 10) | \
+	(((info)->seg_not_present ^ 1) << 15) | \
+	((info)->seg_32bit << 22) | \
+	((info)->limit_in_pages << 23) | \
+	((info)->useable << 20) | \
+	((info)->lm << 21) | \
+	0x7000)
+
+#define LDT_empty(info) (\
+	(info)->base_addr	== 0	&& \
+	(info)->limit		== 0	&& \
+	(info)->contents	== 0	&& \
+	(info)->read_exec_only	== 1	&& \
+	(info)->seg_32bit	== 0	&& \
+	(info)->limit_in_pages	== 0	&& \
+	(info)->seg_not_present	== 1	&& \
+	(info)->useable		== 0	&& \
+	(info)->lm		== 0)
+
+#if TLS_SIZE != 24
+# error update this code.
+#endif
+
+
+static inline u64 load_TLS(struct thread_struct *t, int cpu) 
+{
+	u64 *p, old, new, change; 
+	union u { 
+		struct desc_struct d;
+		u64 i; 
+	}; 
+	change = 0; 
+
+	/* check assembly! */
+#define C(i) \
+	p = ((u64 *)cpu_gdt_table[cpu]) + GDT_ENTRY_TLS_MIN + i; \
+	old = *p; \
+	new = t->tls_array[i]; \
+	change |= old - new;  \
+	*p = new;
+
+	C(0); C(1); C(2); 
+	return change; 
+} 
+
+#undef C
+
+
 /*
  * load one particular LDT into the current CPU
  */
-extern inline void load_LDT (mm_context_t *pc)
+extern inline void load_LDT_nolock (mm_context_t *pc, int cpu)
 {
-	int cpu = smp_processor_id();
 	int count = pc->size;
 
-	if (!count) {
-		clear_LDT(cpu);
+	if (likely(!count)) {
+		clear_LDT();
 		return;
 	}
 		
 	set_ldt_desc(cpu, pc->ldt, count);
-	__load_LDT(cpu);
+	load_LDT_desc();
+}
+
+static inline void load_LDT(mm_context_t *pc)
+{
+	int cpu = get_cpu();
+	load_LDT_nolock(pc, cpu);
+	put_cpu();
 }
 
 #endif /* !__ASSEMBLY__ */
diff -Nru a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h
--- a/include/asm-x86_64/e820.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/e820.h	Tue Oct 15 20:29:12 2002
@@ -2,16 +2,17 @@
  * structures and definitions for the int 15, ax=e820 memory map
  * scheme.
  *
- * In a nutshell, arch/x86_64/boot/setup.S populates a scratch table
- * in the empty_zero_block that contains a list of usable address/size
- * duples.   In arch/x86_64/kernel/setup.c, this information is
- * transferred into the e820map, and in arch/i386/x86_64/init.c, that
- * new information is used to mark pages reserved or not.
- *
+ * In a nutshell, setup.S populates a scratch table in the
+ * empty_zero_block that contains a list of usable address/size
+ * duples.  setup.c, this information is transferred into the e820map,
+ * and in init.c/numa.c, that new information is used to mark pages
+ * reserved or not.
  */
 #ifndef __E820_HEADER
 #define __E820_HEADER
 
+#include <linux/mmzone.h>
+
 #define E820MAP	0x2d0		/* our map */
 #define E820MAX	32		/* number of entries in E820MAP */
 #define E820NR	0x1e8		/* # entries in E820MAP */
@@ -23,16 +24,38 @@
 
 #define HIGH_MEMORY	(1024*1024)
 
+#define LOWMEMSIZE()	(0x9f000)
+
+#define MAXMEM		(120UL * 1024 * 1024 * 1024 * 1024)  /* 120TB */ 
+
+
 #ifndef __ASSEMBLY__
+struct e820entry {
+	u64 addr;	/* start of memory segment */
+	u64 size;	/* size of memory segment */
+	u32 type;	/* type of memory segment */
+} __attribute__((packed));
 
 struct e820map {
     int nr_map;
-    struct e820entry {
-	u64 addr __attribute__((packed));	/* start of memory segment */
-	u64 size __attribute__((packed));	/* size of memory segment */
-	u32 type __attribute__((packed));	/* type of memory segment */
-    } map[E820MAX];
+	struct e820entry map[E820MAX];
 };
+
+extern unsigned long find_e820_area(unsigned long start, unsigned long end, 
+				    unsigned size);
+extern void add_memory_region(unsigned long start, unsigned long size, 
+			      int type);
+extern void setup_memory_region(void);
+extern void contig_e820_setup(void); 
+extern void e820_end_of_ram(void);
+extern void e820_reserve_resources(void);
+extern void e820_print_map(char *who);
+extern int e820_mapped(unsigned long start, unsigned long end, int type);
+
+extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end);
+
+extern void __init parse_memopt(char *p);
+extern void __init print_user_map(void);
 
 extern struct e820map e820;
 #endif/*!__ASSEMBLY__*/
diff -Nru a/include/asm-x86_64/elf.h b/include/asm-x86_64/elf.h
--- a/include/asm-x86_64/elf.h	Tue Oct 15 20:29:20 2002
+++ b/include/asm-x86_64/elf.h	Tue Oct 15 20:29:20 2002
@@ -20,14 +20,14 @@
  * This is used to ensure we don't load something for the wrong architecture.
  */
 #define elf_check_arch(x) \
-	((x)->e_machine == EM_X8664)
+	((x)->e_machine == EM_X86_64)
 
 /*
  * These are used to set parameters in the core dumps.
  */
 #define ELF_CLASS	ELFCLASS64
 #define ELF_DATA	ELFDATA2LSB
-#define ELF_ARCH	EM_X8664
+#define ELF_ARCH	EM_X86_64
 
 /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program starts %edx
    contains a pointer to a function which might be registered using `atexit'.
diff -Nru a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h
--- a/include/asm-x86_64/hardirq.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/hardirq.h	Tue Oct 15 20:29:12 2002
@@ -19,75 +19,84 @@
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
 
 /*
- * Are we in an interrupt context? Either doing bottom half
- * or hardware interrupt processing?
+ * We put the hardirq and softirq counter into the preemption
+ * counter. The bitmask has the following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ * - bits 16-23 are the hardirq count (max # of hardirqs: 256)
+ *
+ * - ( bit 26 is the PREEMPT_ACTIVE flag. )
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * HARDIRQ_MASK: 0x0000ff00
+ * SOFTIRQ_MASK: 0x00ff0000
  */
-#define in_interrupt() \
-	((read_pda(__local_irq_count) +  read_pda(__local_bh_count)) != 0)
-#define in_irq() (read_pda(__local_irq_count) != 0)
 
-#ifndef CONFIG_SMP
-
-#define hardirq_trylock(cpu)	(local_irq_count() == 0)
-#define hardirq_endlock(cpu)	do { } while (0)
+#define PREEMPT_BITS	8
+#define SOFTIRQ_BITS	8
+#define HARDIRQ_BITS	8
+
+#define PREEMPT_SHIFT	0
+#define SOFTIRQ_SHIFT	(PREEMPT_SHIFT + PREEMPT_BITS)
+#define HARDIRQ_SHIFT	(SOFTIRQ_SHIFT + SOFTIRQ_BITS)
+
+#define __MASK(x)	((1UL << (x))-1)
+
+#define PREEMPT_MASK	(__MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
+#define HARDIRQ_MASK	(__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
+#define SOFTIRQ_MASK	(__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+
+#define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
+#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
+#define irq_count()	(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK))
+
+#define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
+#define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
+#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
+
+/*
+ * The hardirq mask has to be large enough to have
+ * space for potentially all IRQ sources in the system
+ * nesting on a single CPU:
+ */
+#if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+#endif
+
+/*
+ * Are we doing bottom half or hardware interrupt processing?
+ * Are we in a softirq context? Interrupt context?
+ */
+#define in_irq()		(hardirq_count())
+#define in_softirq()		(softirq_count())
+#define in_interrupt()		(irq_count())
 
-#define irq_enter(cpu, irq)	(local_irq_count()++)
-#define irq_exit(cpu, irq)	(local_irq_count()--)
 
-#define synchronize_irq()	barrier()
+#define hardirq_trylock()	(!in_interrupt())
+#define hardirq_endlock()	do { } while (0)
 
-#define release_irqlock(cpu)	do { } while (0)
+#define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
+#if CONFIG_PREEMPT
+# define in_atomic()   ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
+# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
+# define in_atomic()   (preempt_count() != 0)
+# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
+#endif
+#define irq_exit()							\
+do {									\
+		preempt_count() -= IRQ_EXIT_OFFSET;			\
+		if (!in_interrupt() && softirq_pending(smp_processor_id())) \
+			do_softirq();					\
+		preempt_enable_no_resched();				\
+} while (0)
 
-#include <asm/atomic.h>
-#include <asm/smp.h>
-
-extern unsigned char global_irq_holder;
-extern unsigned volatile long global_irq_lock; /* long for set_bit -RR */
-
-static inline int irqs_running (void)
-{
-	int i;
-
-	for (i = 0; i < smp_num_cpus; i++)
-		if (read_pda(__local_irq_count))
-			return 1;
-	return 0;
-}
-
-static inline void release_irqlock(int cpu)
-{
-	/* if we didn't own the irq lock, just ignore.. */
-	if (global_irq_holder == (unsigned char) cpu) {
-		global_irq_holder = NO_PROC_ID;
-		clear_bit(0,&global_irq_lock);
-	}
-}
-
-static inline void irq_enter(int cpu, int irq)
-{
-	add_pda(__local_irq_count, 1);
-
-	while (test_bit(0,&global_irq_lock)) {
-		cpu_relax();
-	}
-}
-
-static inline void irq_exit(int cpu, int irq)
-{
-	sub_pda(__local_irq_count, 1);
-}
-
-static inline int hardirq_trylock(int cpu)
-{
-	return !read_pda(__local_irq_count) && !test_bit(0,&global_irq_lock);
-}
-
-#define hardirq_endlock(cpu)	do { } while (0)
-
-extern void synchronize_irq(void);
-
+#ifndef CONFIG_SMP
+# define synchronize_irq(irq)	barrier()
+#else
+  extern void synchronize_irq(unsigned int irq);
 #endif /* CONFIG_SMP */
 
 #endif /* __ASM_HARDIRQ_H */
diff -Nru a/include/asm-x86_64/ia32_unistd.h b/include/asm-x86_64/ia32_unistd.h
--- a/include/asm-x86_64/ia32_unistd.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-x86_64/ia32_unistd.h	Tue Oct 15 20:29:17 2002
@@ -249,7 +249,17 @@
 #define __NR_ia32_futex		240
 #define __NR_ia32_sched_setaffinity	241
 #define __NR_ia32_sched_getaffinity	242
+#define __NR_ia32_set_thread_area   243
+#define __NR_ia32_get_thread_area	244
+#define __NR_ia32_io_setup		245
+#define __NR_ia32_io_destroy		246
+#define __NR_ia32_io_getevents	247
+#define __NR_ia32_io_submit		248
+#define __NR_ia32_io_cancel		249
+#define __NR_ia32_alloc_hugepages		250
+#define __NR_ia32_free_hugepages		251
+#define __NR_ia32_exit_group		252
 
-#define IA32_NR_syscalls 243	/* must be > than biggest syscall! */	
+#define IA32_NR_syscalls 260	/* must be > than biggest syscall! */	
 
 #endif /* _ASM_X86_64_IA32_UNISTD_H_ */
diff -Nru a/include/asm-x86_64/ide.h b/include/asm-x86_64/ide.h
--- a/include/asm-x86_64/ide.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-x86_64/ide.h	Tue Oct 15 20:29:17 2002
@@ -72,7 +72,7 @@
 	for(index = 0; index < MAX_HWIFS; index++) {
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw);
+		ide_register_hw(&hw, NULL);
 	}
 #endif
 }
diff -Nru a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
--- a/include/asm-x86_64/io.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-x86_64/io.h	Tue Oct 15 20:29:16 2002
@@ -149,11 +149,7 @@
  * it's useful if some control registers are in such an area and write combining
  * or read caching is not desirable:
  */
-extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
-{
-        return __ioremap(offset, size, _PAGE_PCD);
-}
-
+extern void * ioremap_nocache (unsigned long offset, unsigned long size);
 extern void iounmap(void *addr);
 
 /*
diff -Nru a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
--- a/include/asm-x86_64/io_apic.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/io_apic.h	Tue Oct 15 20:29:12 2002
@@ -141,6 +141,14 @@
  */
 #define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup)
 
+#ifdef CONFIG_ACPI_BOOT
+extern int io_apic_get_unique_id (int ioapic, int apic_id);
+extern int io_apic_get_version (int ioapic);
+extern int io_apic_get_redir_entries (int ioapic);
+extern int io_apic_set_pci_routing (int ioapic, int pin, int irq);
+#endif
+
+
 #else  /* !CONFIG_X86_IO_APIC */
 #define io_apic_assign_pci_irqs 0
 #endif
diff -Nru a/include/asm-x86_64/ipc.h b/include/asm-x86_64/ipc.h
--- a/include/asm-x86_64/ipc.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-x86_64/ipc.h	Tue Oct 15 20:29:17 2002
@@ -1,5 +1,5 @@
-#ifndef __i386_IPC_H__
-#define __i386_IPC_H__
+#ifndef __x86_64_IPC_H__
+#define __x86_64_IPC_H__
 
 /* dummy */
 
diff -Nru a/include/asm-x86_64/kmap_types.h b/include/asm-x86_64/kmap_types.h
--- a/include/asm-x86_64/kmap_types.h	Tue Oct 15 20:29:19 2002
+++ b/include/asm-x86_64/kmap_types.h	Tue Oct 15 20:29:19 2002
@@ -9,6 +9,8 @@
 	KM_USER1,
 	KM_BIO_SRC_IRQ,
 	KM_BIO_DST_IRQ,
+	KM_IRQ0,
+	KM_IRQ1,
 	KM_TYPE_NR
 };
 
diff -Nru a/include/asm-x86_64/ldt.h b/include/asm-x86_64/ldt.h
--- a/include/asm-x86_64/ldt.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/ldt.h	Tue Oct 15 20:29:12 2002
@@ -15,7 +15,7 @@
 /* Note on 64bit base and limit is ignored and you cannot set
    DS/ES/CS not to the default values if you still want to do syscalls. This
    call is more for 32bit mode therefore. */
-struct modify_ldt_ldt_s {
+struct user_desc {
 	unsigned int  entry_number;
 	unsigned int  base_addr;
 	unsigned int  limit;
diff -Nru a/include/asm-x86_64/mman.h b/include/asm-x86_64/mman.h
--- a/include/asm-x86_64/mman.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/mman.h	Tue Oct 15 20:29:12 2002
@@ -5,7 +5,7 @@
 #define PROT_WRITE	0x2		/* page can be written */
 #define PROT_EXEC	0x4		/* page can be executed */
 #define PROT_NONE	0x0		/* page can not be accessed */
-#define PROT_SEM	0x0
+#define PROT_SEM	0x8
 
 #define MAP_SHARED	0x01		/* Share changes */
 #define MAP_PRIVATE	0x02		/* Changes are private */
diff -Nru a/include/asm-x86_64/mmu_context.h b/include/asm-x86_64/mmu_context.h
--- a/include/asm-x86_64/mmu_context.h	Tue Oct 15 20:29:15 2002
+++ b/include/asm-x86_64/mmu_context.h	Tue Oct 15 20:29:15 2002
@@ -43,8 +43,8 @@
 		*read_pda(level4_pgt) = __pa(next->pgd) | _PAGE_TABLE;
 		__flush_tlb();
 
-		if (next->context.size + prev->context.size) 
-			load_LDT(&next->context);
+		if (unlikely(next->context.ldt != prev->context.ldt)) 
+			load_LDT_nolock(&next->context, cpu);
 	}
 #ifdef CONFIG_SMP
 	else {
@@ -56,7 +56,7 @@
 			 * tlb flush IPI delivery. We must flush our tlb.
 			 */
 			local_flush_tlb();
-			load_LDT(&next->context);
+			load_LDT_nolock(&next->context, cpu);
 		}
 	}
 #endif
diff -Nru a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
--- a/include/asm-x86_64/mpspec.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-x86_64/mpspec.h	Tue Oct 15 20:29:16 2002
@@ -187,5 +187,17 @@
 extern int pic_mode;
 extern int using_apic_timer;
 
+#ifdef CONFIG_ACPI_BOOT
+extern void mp_register_lapic (u8 id, u8 enabled);
+extern void mp_register_lapic_address (u64 address);
+
+#ifdef CONFIG_X86_IO_APIC
+extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base);
+extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq);
+extern void mp_config_acpi_legacy_irqs (void);
+extern void mp_parse_prt (void);
+#endif /*CONFIG_X86_IO_APIC*/
+#endif
+
 #endif
 
diff -Nru a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
--- a/include/asm-x86_64/page.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/page.h	Tue Oct 15 20:29:12 2002
@@ -13,6 +13,9 @@
 #define THREAD_SIZE (2*PAGE_SIZE)
 #define CURRENT_MASK (~(THREAD_SIZE-1))
 
+#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
+#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
+
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
@@ -56,6 +59,9 @@
 #define __PAGE_OFFSET           0x0000010000000000
 #define __PHYSICAL_MASK		0x000000ffffffffff
 
+#define KERNEL_TEXT_SIZE  (40UL*1024*1024)
+#define KERNEL_TEXT_START 0xffffffff80000000UL 
+
 #ifndef __ASSEMBLY__
 
 #include <linux/stringify.h>
@@ -108,7 +114,7 @@
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define pfn_valid(pfn)		((pfn) < max_mapnr)
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-
+#define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 
 #define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
                                 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
diff -Nru a/include/asm-x86_64/param.h b/include/asm-x86_64/param.h
--- a/include/asm-x86_64/param.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-x86_64/param.h	Tue Oct 15 20:29:17 2002
@@ -1,6 +1,12 @@
 #ifndef _ASMx86_64_PARAM_H
 #define _ASMx86_64_PARAM_H
 
+#ifdef __KERNEL__
+# define HZ            100            /* Internal kernel timer frequency */
+# define USER_HZ       100          /* .. some user interfaces are in "ticks */
+#define CLOCKS_PER_SEC        (USER_HZ)       /* like times() */
+#endif
+
 #ifndef HZ
 #define HZ 100
 #endif
@@ -16,9 +22,5 @@
 #endif
 
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
-
-#ifdef __KERNEL__
-# define CLOCKS_PER_SEC	100	/* frequency at which times() counts */
-#endif
 
 #endif
diff -Nru a/include/asm-x86_64/pci-direct.h b/include/asm-x86_64/pci-direct.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-x86_64/pci-direct.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,29 @@
+#ifndef ASM_PCI_DIRECT_H
+#define ASM_PCI_DIRECT_H 1
+
+#include <linux/types.h>
+#include <asm/io.h>
+
+/* Direct PCI access. This is used for PCI accesses in early boot before
+   the PCI subsystem works. */ 
+
+#define PDprintk(x...)
+
+static inline u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
+{
+	u32 v; 
+	outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+	v = inl(0xcfc); 
+	PDprintk("%x reading from %x: %x\n", slot, offset, v);
+	return v;
+}
+
+static inline void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset,
+				    u32 val)
+{
+	PDprintk("%x writing to %x: %x\n", slot, offset, val); 
+	outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
+	outl(val, 0xcfc); 
+}
+
+#endif
diff -Nru a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
--- a/include/asm-x86_64/pci.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-x86_64/pci.h	Tue Oct 15 20:29:16 2002
@@ -2,9 +2,15 @@
 #define __x8664_PCI_H
 
 #include <linux/config.h>
+#include <asm/io.h>
 
 #ifdef __KERNEL__
 
+#include <linux/mm.h> /* for struct page */
+
+
+extern dma_addr_t bad_dma_address;
+
 /* Can be used to override the logic in pci_scan_bus for skipping
    already-configured bus numbers - to be used for buggy BIOSes
    or architectures with incomplete PCI setup by the loader */
@@ -23,6 +29,7 @@
 struct pci_bus * pcibios_scan_root(int bus);
 extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
 extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
+
 void pcibios_set_master(struct pci_dev *dev);
 void pcibios_penalize_isa_irq(int irq);
 struct irq_routing_table *pcibios_get_irq_routing_table(void);
@@ -30,19 +37,16 @@
 
 #include <linux/types.h>
 #include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/init.h>
 #include <asm/scatterlist.h>
 #include <linux/string.h>
 #include <asm/io.h>
+#include <asm/page.h>
 
 struct pci_dev;
 
-/* The PCI address space does equal the physical memory
- * address space.  The networking and block device layers use
- * this boolean for bounce buffer decisions.
- */
-#define PCI_DMA_BUS_IS_PHYS	(1)
+extern int iommu_setup(char *opt);
+
+extern void pci_iommu_init(void);
 
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices,
@@ -65,55 +69,95 @@
 extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
 				void *vaddr, dma_addr_t dma_handle);
 
+#ifdef CONFIG_GART_IOMMU
+
 /* Map a single buffer of the indicated size for DMA in streaming mode.
  * The 32-bit bus address to use is returned.
  *
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
+extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+			  size_t size, int direction);
+
+extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t addr,
+				   size_t size, int direction);
+
+/*
+ * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
+ * to pci_map_single, but takes a struct page instead of a virtual address
+ */
+
+#define pci_map_page(dev,page,offset,size,dir) \
+	pci_map_single((dev), page_address(page)+(offset), (size), (dir)) 
+
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
+	dma_addr_t ADDR_NAME;
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)		\
+	__u32 LEN_NAME;
+#define pci_unmap_addr(PTR, ADDR_NAME)			\
+	((PTR)->ADDR_NAME)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)		\
+	(((PTR)->ADDR_NAME) = (VAL))
+#define pci_unmap_len(PTR, LEN_NAME)			\
+	((PTR)->LEN_NAME)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
+	(((PTR)->LEN_NAME) = (VAL))
+
+static inline void pci_dma_sync_single(struct pci_dev *hwdev, 
+				       dma_addr_t dma_handle,
+				       size_t size, int direction)
+{
+	BUG_ON(direction == PCI_DMA_NONE); 
+} 
+
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev, 
+				   struct scatterlist *sg,
+				   int nelems, int direction)
+{ 
+	BUG_ON(direction == PCI_DMA_NONE); 
+} 
+
+#define PCI_DMA_BUS_IS_PHYS	0
+
+
+#else
 static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
 {
+	dma_addr_t addr; 
+
 	if (direction == PCI_DMA_NONE)
-		BUG();
-	flush_write_buffers();
-	return virt_to_phys(ptr);
-}
+		out_of_line_bug();	
+	addr = virt_to_bus(ptr); 
 
-/* Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guarenteed to see
- * whatever the device wrote there.
+	/* 
+	 * This is gross, but what should I do.
+	 * Unfortunately drivers do not test the return value of this.
  */
+	if ((addr+size) & ~hwdev->dma_mask) 
+		out_of_line_bug(); 
+	return addr;
+}
+
 static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
 				    size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	/* Nothing to do */
 }
 
-/*
- * pci_{map,unmap}_single_page maps a kernel page to a dma_addr_t. identical
- * to pci_map_single, but takes a struct page instead of a virtual address
- */
 static inline dma_addr_t pci_map_page(struct pci_dev *hwdev, struct page *page,
 				      unsigned long offset, size_t size, int direction)
 {
+	dma_addr_t addr;
 	if (direction == PCI_DMA_NONE)
-		BUG();
-
-	return (page - mem_map) * PAGE_SIZE + offset;
-}
-
-static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
-				  size_t size, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-		BUG();
-	/* Nothing to do */
+		out_of_line_bug();	
+ 	addr = page_to_pfn(page) * PAGE_SIZE + offset;
+	if ((addr+size) & ~hwdev->dma_mask) 
+		out_of_line_bug();
+	return addr;
 }
 
 /* pci_unmap_{page,single} is a nop so... */
@@ -124,52 +168,6 @@
 #define pci_unmap_len(PTR, LEN_NAME)		(0)
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 
-/* Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above pci_map_single interface.  Here the scatter gather list
- * elements are each tagged with the appropriate dma address
- * and length.  They are obtained via sg_dma_{address,length}(SG).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       The routine returns the number of addr/length pairs actually
- *       used, at most nents.
- *
- * Device ownership issues as mentioned above for pci_map_single are
- * the same here.
- */
-static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-			     int nents, int direction)
-{
-	int i;
-
-	if (direction == PCI_DMA_NONE)
-		BUG();
-
-	for (i = 0; i < nents; i++ ) {
-		if (!sg[i].page)
-			BUG();
-
-		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
-	}
-
-	flush_write_buffers();
-	return nents;
-}
-
-/* Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-				int nents, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-		BUG();
-	/* Nothing to do */
-}
-
 /* Make physical memory consistent for a single
  * streaming mode DMA translation after a transfer.
  *
@@ -184,7 +182,7 @@
 				       size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	flush_write_buffers();
 }
 
@@ -199,10 +197,22 @@
 				   int nelems, int direction)
 {
 	if (direction == PCI_DMA_NONE)
-		BUG();
+		out_of_line_bug();
 	flush_write_buffers();
 }
 
+#define PCI_DMA_BUS_IS_PHYS	1
+
+#endif
+
+extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+		      int nents, int direction);
+extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			 int nents, int direction);
+
+
+#define pci_unmap_page pci_unmap_single
+
 /* Return whether the given PCI device DMA address mask can
  * be supported properly.  For example, if your device can
  * only drive the low 24-bits during PCI bus mastering, then
@@ -234,9 +244,7 @@
 static __inline__ struct page *
 pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
 {
-	unsigned long poff = (dma_addr >> PAGE_SHIFT);
-
-	return mem_map + poff;
+	return virt_to_page(__va(dma_addr)); 	
 }
 
 static __inline__ unsigned long
diff -Nru a/include/asm-x86_64/pda.h b/include/asm-x86_64/pda.h
--- a/include/asm-x86_64/pda.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-x86_64/pda.h	Tue Oct 15 20:29:16 2002
@@ -18,12 +18,11 @@
 	char *irqstackptr;	/* top of irqstack */
 	unsigned long volatile *level4_pgt; 
 	unsigned int __softirq_pending;
-	unsigned int __local_irq_count;
-	unsigned int __local_bh_count;
 	unsigned int __nmi_count;	/* arch dependent */
 	struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
 	struct mm_struct *active_mm;
 	int mmu_state;     
+	unsigned apic_timer_irqs;
 } ____cacheline_aligned;
 
 #define PDA_STACKOFFSET (5*8)
diff -Nru a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
--- a/include/asm-x86_64/percpu.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/percpu.h	Tue Oct 15 20:29:12 2002
@@ -1,12 +1,45 @@
-#ifndef __ARCH_X8664_PERCPU__
-#define __ARCH_X8664_PERCPU__
+#ifndef _ASM_X8664_PERCPU_H_
+#define _ASM_X8664_PERCPU_H_
+#include <linux/compiler.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_SMP
 
 #include <asm/pda.h>
 
+extern unsigned long __per_cpu_offset[NR_CPUS];
+
+/* Separate out the type, so (int[3], foo) works. */
+#ifndef MODULE
+#define DEFINE_PER_CPU(type, name) \
+    __attribute__((__section__(".percpu"))) __typeof__(type) name##__per_cpu
+#endif
+
+/* Completely hide the relocation from the compiler to avoid problems with 
+   the optimizer */ 
+#define __per_cpu(offset,base) \
+	({ typeof(base) ptr = (void *)base; \
+	   asm("addq %1,%0" : "=r" (ptr) : "r" (offset), "0" (ptr)); ptr; })
+
 /* var is in discarded region: offset to particular copy we want */
-#define __get_cpu_var(var)     (*RELOC_HIDE(&var, read_pda(cpudata_offset)))
-#define per_cpu(var, cpu) (*RELOC_HIDE(&var, per_cpu_pda[cpu]))
 
-void setup_per_cpu_areas(void);
+#define per_cpu(var,cpu) (*__per_cpu(__per_cpu_offset[cpu], &var##__per_cpu)) 
+#define __get_cpu_var(var) (*__per_cpu(read_pda(cpudata_offset), &var##__per_cpu))
+
+#else /* ! SMP */
+
+/* Can't define per-cpu variables in modules.  Sorry --RR */
+#ifndef MODULE
+#define DEFINE_PER_CPU(type, name) \
+    __typeof__(type) name##__per_cpu
+#endif
+
+#define per_cpu(var, cpu)			var##__per_cpu
+#define __get_cpu_var(var)			var##__per_cpu
+#endif
+
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) name##__per_cpu
+
+extern void setup_per_cpu_areas(void);
 
-#endif /* __ARCH_X8664_PERCPU__ */
+#endif /* _ASM_X8664_PERCPU_H_ */
diff -Nru a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
--- a/include/asm-x86_64/pgtable.h	Tue Oct 15 20:29:12 2002
+++ b/include/asm-x86_64/pgtable.h	Tue Oct 15 20:29:12 2002
@@ -127,6 +127,8 @@
 #define MODULES_END      0xffffffffafffffff
 #define MODULES_LEN   (MODULES_END - MODULES_VADDR)
 
+#define IOMAP_START      0xfffffe8000000000
+
 #define _PAGE_BIT_PRESENT	0
 #define _PAGE_BIT_RW		1
 #define _PAGE_BIT_USER		2
@@ -169,6 +171,8 @@
 	(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED)
 #define __PAGE_KERNEL_VSYSCALL \
 	(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define __PAGE_KERNEL_LARGE \
+	(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_PSE)
 
 #define MAKE_GLOBAL(x) __pgprot((x) | _PAGE_GLOBAL)
 
@@ -176,6 +180,7 @@
 #define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
 #define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
 #define PAGE_KERNEL_VSYSCALL MAKE_GLOBAL(__PAGE_KERNEL_VSYSCALL)
+#define PAGE_KERNEL_LARGE MAKE_GLOBAL(__PAGE_KERNEL_LARGE)
 
 #define __P000	PAGE_NONE
 #define __P001	PAGE_READONLY
@@ -244,6 +249,12 @@
 static inline  int ptep_test_and_clear_young(pte_t *ptep)	{ return test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep); }
 static inline void ptep_set_wrprotect(pte_t *ptep)		{ clear_bit(_PAGE_BIT_RW, ptep); }
 static inline void ptep_mkdirty(pte_t *ptep)			{ set_bit(_PAGE_BIT_DIRTY, ptep); }
+
+#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT) 
+static inline int pmd_large(pmd_t pte) { 
+	return (pmd_val(pte) & __LARGE_PTE) == __LARGE_PTE; 
+} 	
+
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
diff -Nru a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
--- a/include/asm-x86_64/processor.h	Tue Oct 15 20:29:22 2002
+++ b/include/asm-x86_64/processor.h	Tue Oct 15 20:29:22 2002
@@ -28,6 +28,12 @@
 #define VIP_MASK	0x00100000	/* virtual interrupt pending */
 #define ID_MASK		0x00200000
 
+#define desc_empty(desc) \
+               (!((desc)->a + (desc)->b))
+
+#define desc_equal(desc1, desc2) \
+               (((desc1)->a == (desc2)->a) && ((desc1)->b == (desc2)->b))
+
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -49,8 +55,8 @@
 	__u32	x86_capability[NCAPINTS];
 	char	x86_vendor_id[16];
 	char	x86_model_id[64];
-	int 	x86_cache_size;  /* in KB - valid for CPUS which support this
-				    call  */
+	int 	x86_cache_size;  /* in KB */
+	int	x86_clflush_size;
 	unsigned long loops_per_jiffy;
 } ____cacheline_aligned;
 
@@ -315,10 +321,11 @@
    switch faster for a limited number of ioperm using tasks. -AK */
 	int		ioperm;
 	u32	*io_bitmap_ptr;
+/* cached TLS descriptors. */
+	u64 tls_array[GDT_ENTRY_TLS_ENTRIES];
 };
 
-#define INIT_THREAD  {				\
-}
+#define INIT_THREAD  {}
 
 #define INIT_MMAP \
 { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
diff -Nru a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-x86_64/proto.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,49 @@
+#ifndef _ASM_X8664_PROTO_H
+#define _ASM_X8664_PROTO_H 1
+
+/* misc architecture specific prototypes */
+
+struct cpuinfo_x86; 
+
+extern void get_cpu_vendor(struct cpuinfo_x86*);
+extern void start_kernel(void);
+extern void pda_init(int); 
+
+extern void mcheck_init(struct cpuinfo_x86 *c);
+extern void init_memory_mapping(void);
+
+extern void system_call(void); 
+extern void ia32_cstar_target(void); 
+extern void calibrate_delay(void);
+extern void cpu_idle(void);
+extern void sys_ni_syscall(void);
+extern void config_acpi_tables(void);
+extern void ia32_syscall(void);
+extern void iommu_hole_init(void);
+
+extern void do_softirq_thunk(void);
+
+extern int setup_early_printk(char *); 
+extern void early_printk(const char *fmt, ...) __attribute__((format(printf,1,2)));
+
+extern int k8_scan_nodes(unsigned long start, unsigned long end);
+
+extern int numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
+extern unsigned long numa_free_all_bootmem(void);
+
+extern void reserve_bootmem_generic(unsigned long phys, unsigned len);
+extern void free_bootmem_generic(unsigned long phys, unsigned len);
+
+extern unsigned long start_pfn, end_pfn; 
+
+extern void show_stack(unsigned long * rsp);
+
+extern void exception_table_check(void);
+
+extern void acpi_boot_init(char *);
+
+
+#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
+#define round_down(x,y) ((x) & ~((y)-1))
+
+#endif
diff -Nru a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h
--- a/include/asm-x86_64/ptrace.h	Tue Oct 15 20:29:15 2002
+++ b/include/asm-x86_64/ptrace.h	Tue Oct 15 20:29:15 2002
@@ -84,7 +84,6 @@
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__) 
 #define user_mode(regs) (!!((regs)->cs & 3))
 #define instruction_pointer(regs) ((regs)->rip)
-extern void show_regs(struct pt_regs *);
 void signal_fault(struct pt_regs *regs, void *frame, char *where);
 
 enum {
diff -Nru a/include/asm-x86_64/rmap.h b/include/asm-x86_64/rmap.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-x86_64/rmap.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,7 @@
+#ifndef _X8664_RMAP_H
+#define _X8664_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -Nru a/include/asm-x86_64/rtc.h b/include/asm-x86_64/rtc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-x86_64/rtc.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,10 @@
+#ifndef _X86_64_RTC_H
+#define _X86_64_RTC_H
+
+/*
+ * x86 uses the default access methods for the RTC.
+ */
+
+#include <asm-generic/rtc.h>
+
+#endif
diff -Nru a/include/asm-x86_64/rwsem.h b/include/asm-x86_64/rwsem.h
--- a/include/asm-x86_64/rwsem.h	Tue Oct 15 20:29:20 2002
+++ b/include/asm-x86_64/rwsem.h	Tue Oct 15 20:29:20 2002
@@ -47,6 +47,7 @@
 extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
 extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
 extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
 
 /*
  * the semaphore definition
@@ -113,6 +114,31 @@
 		: "memory", "cc");
 }
 
+
+/*
+ * trylock for reading -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	__s32 result, tmp;
+	__asm__ __volatile__(
+		"# beginning __down_read_trylock\n\t"
+		"  movl      %0,%1\n\t"
+		"1:\n\t"
+		"  movl	     %1,%2\n\t"
+		"  addl      %3,%2\n\t"
+		"  jle	     2f\n\t"
+LOCK_PREFIX	"  cmpxchgl  %2,%0\n\t"
+		"  jnz	     1b\n\t"
+		"2:\n\t"
+		"# ending __down_read_trylock\n\t"
+		: "+m"(sem->count), "=&a"(result), "=&r"(tmp)
+		: "i"(RWSEM_ACTIVE_READ_BIAS)
+		: "memory", "cc");
+	return result>=0 ? 1 : 0;
+}
+
+
 /*
  * lock for writing
  */
@@ -139,6 +165,19 @@
 }
 
 /*
+ * trylock for writing -- returns 1 if successful, 0 if contention
+ */
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	signed long ret = cmpxchg(&sem->count,
+				  RWSEM_UNLOCKED_VALUE, 
+				  RWSEM_ACTIVE_WRITE_BIAS);
+	if (ret == RWSEM_UNLOCKED_VALUE)
+		return 1;
+	return 0;
+}
+
+/*
  * unlock after reading
  */
 static inline void __up_read(struct rw_semaphore *sem)
@@ -157,7 +196,7 @@
 		"  jmp       1b\n"
 		LOCK_SECTION_END
 		"# ending __up_read\n"
-		: "+m"(sem->count), "+r" (tmp)
+		: "+m"(sem->count), [tmp] "+r" (tmp)
 		: "D"(sem)
 		: "memory", "cc");
 }
@@ -170,7 +209,7 @@
 	unsigned tmp; 
 	__asm__ __volatile__(
 		"# beginning __up_write\n\t"
-		"  movl      %2,%[tmp]\n\t"
+		"  movl     %[bias],%[tmp]\n\t"
 LOCK_PREFIX	"  xaddl     %[tmp],(%%rdi)\n\t" /* tries to transition 0xffff0001 -> 0x00000000 */
 		"  jnz       2f\n\t" /* jump if the lock is being waited upon */
 		"1:\n\t"
@@ -182,8 +221,29 @@
 		"  jmp       1b\n"
 		LOCK_SECTION_END
 		"# ending __up_write\n"
-		: "+m"(sem->count), [tmp] "r" (tmp)
-		: "D"(sem), "i"(-RWSEM_ACTIVE_WRITE_BIAS)
+		: "+m"(sem->count), [tmp] "=r" (tmp)
+		: "D"(sem), [bias] "i"(-RWSEM_ACTIVE_WRITE_BIAS)
+		: "memory", "cc");
+}
+
+/*
+ * downgrade write lock to read lock
+ */
+static inline void __downgrade_write(struct rw_semaphore *sem)
+{
+	__asm__ __volatile__(
+		"# beginning __downgrade_write\n\t"
+LOCK_PREFIX	"  addl      %[bias],(%%rdi)\n\t" /* transitions 0xZZZZ0001 -> 0xYYYY0001 */
+		"  js        2f\n\t" /* jump if the lock is being waited upon */
+		"1:\n\t"
+		LOCK_SECTION_START("")
+		"2:\n\t"
+		"  call	     rwsem_downgrade_thunk\n"
+		"  jmp       1b\n"
+		LOCK_SECTION_END
+		"# ending __downgrade_write\n"
+		: "=m"(sem->count)
+		: "D"(sem), [bias] "i"(-RWSEM_WAITING_BIAS), "m"(sem->count)
 		: "memory", "cc");
 }
 
diff -Nru a/include/asm-x86_64/sections.h b/include/asm-x86_64/sections.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-x86_64/sections.h	Tue Oct 15 20:29:24 2002
@@ -0,0 +1,7 @@
+#ifndef _X8664_SECTIONS_H
+#define _X8664_SECTIONS_H
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+#endif
diff -Nru a/include/asm-x86_64/segment.h b/include/asm-x86_64/segment.h
--- a/include/asm-x86_64/segment.h	Tue Oct 15 20:29:21 2002
+++ b/include/asm-x86_64/segment.h	Tue Oct 15 20:29:21 2002
@@ -18,4 +18,17 @@
 #define __USER_CS     0x33   /* 6*8+3 */ 
 #define __USER32_DS	__USER_DS 
 
+#define GDT_ENTRY_TLS 1
+#define GDT_ENTRY_TSS 8	/* needs two entries */
+#define GDT_ENTRY_LDT 10
+#define GDT_ENTRY_TLS_MIN 11
+#define GDT_ENTRY_TLS_MAX 13
+
+#define GDT_ENTRY_TLS_ENTRIES 3
+
+#define IDT_ENTRIES 256
+#define GDT_ENTRIES 16
+#define GDT_SIZE (GDT_ENTRIES * 8)
+#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8) 
+
 #endif
diff -Nru a/include/asm-x86_64/semaphore.h b/include/asm-x86_64/semaphore.h
--- a/include/asm-x86_64/semaphore.h	Tue Oct 15 20:29:11 2002
+++ b/include/asm-x86_64/semaphore.h	Tue Oct 15 20:29:11 2002
@@ -111,7 +111,7 @@
 /*
  * This is ugly, but we want the default case to fall through.
  * "__down_failed" is a special asm handler that calls the C
- * routine that actually waits. See arch/i386/kernel/semaphore.c
+ * routine that actually waits. See arch/x86_64/kernel/semaphore.c
  */
 static inline void down(struct semaphore * sem)
 {
diff -Nru a/include/asm-x86_64/signal.h b/include/asm-x86_64/signal.h
--- a/include/asm-x86_64/signal.h	Tue Oct 15 20:29:11 2002
+++ b/include/asm-x86_64/signal.h	Tue Oct 15 20:29:11 2002
@@ -141,7 +141,6 @@
 #define SIG_IGN	((__sighandler_t)1)	/* ignore signal */
 #define SIG_ERR	((__sighandler_t)-1)	/* error return from signal */
 
-#ifdef __KERNEL__
 struct sigaction {
 	__sighandler_t sa_handler;
 	unsigned long sa_flags;
@@ -152,7 +151,6 @@
 struct k_sigaction {
 	struct sigaction sa;
 };
-#endif /* __KERNEL__ */
 
 typedef struct sigaltstack {
 	void *ss_sp;
diff -Nru a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
--- a/include/asm-x86_64/smp.h	Tue Oct 15 20:29:11 2002
+++ b/include/asm-x86_64/smp.h	Tue Oct 15 20:29:11 2002
@@ -7,13 +7,12 @@
 #ifndef __ASSEMBLY__
 #include <linux/config.h>
 #include <linux/threads.h>
-#include <linux/ptrace.h>
+#include <linux/bitops.h>
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
 #ifndef __ASSEMBLY__
 #include <asm/fixmap.h>
-#include <asm/bitops.h>
 #include <asm/mpspec.h>
 #ifdef CONFIG_X86_IO_APIC
 #include <asm/io_apic.h>
@@ -28,6 +27,8 @@
 
 #include <asm/pda.h>
 
+struct pt_regs;
+
 /*
  * Private routines/data
  */
@@ -50,6 +51,11 @@
  * This simplifies scheduling and IPI sending and
  * compresses data structures.
  */
+
+extern volatile unsigned long cpu_callout_map;
+
+#define cpu_possible(cpu) (cpu_callout_map & (1<<(cpu)))
+
 extern inline int cpu_logical_map(int cpu)
 {
 	return cpu;
@@ -59,6 +65,34 @@
 	return cpu;
 }
 
+extern inline unsigned int num_online_cpus(void)
+{
+	return hweight32(cpu_online_map);
+}
+
+extern inline int find_next_cpu(unsigned cpu) 
+{ 
+	unsigned long left = cpu_online_map >> (cpu+1); 
+	if (!left) 
+		return -1; 
+	return ffz(~left) + cpu; 		
+} 
+
+extern inline int find_first_cpu(void)
+{ 
+	return ffz(~cpu_online_map); 	
+} 
+
+#define for_each_cpu(i) \
+	for((i) = find_first_cpu(); (i)>=0; (i)=find_next_cpu(i))
+
+extern volatile unsigned long cpu_callout_map;
+/* We don't mark CPUs online until __cpu_up(), so we need another measure */
+static inline int num_booting_cpus(void)
+{
+	return hweight32(cpu_callout_map);
+}
+
 /*
  * Some lowlevel functions might want to know about
  * the real APIC ID <-> CPU # mapping.
@@ -67,13 +101,6 @@
 extern volatile int x86_cpu_to_apicid[NR_CPUS];
 
 /*
- * General functions that each host system must provide.
- */
- 
-extern void smp_boot_cpus(void);
-extern void smp_store_cpu_info(int id);		/* Store per CPU info (like the initial udelay numbers */
-
-/*
  * This function is needed by all SMP systems. It must _always_ be valid
  * from the initial startup. We map APIC_BASE very early in page_setup(),
  * so this is correct in the x86 case.
@@ -81,12 +108,14 @@
 
 #define smp_processor_id() read_pda(cpunumber)
 
+
 extern __inline int hard_smp_processor_id(void)
 {
 	/* we don't want to mark this access volatile - bad code generation */
-	return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
+	return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
 }
 
+#define cpu_online(cpu) (cpu_online_map & (1<<(cpu)))
 #endif /* !ASSEMBLY */
 
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
@@ -98,6 +127,8 @@
 
 #ifndef CONFIG_SMP
 #define stack_smp_processor_id() 0
+#define for_each_cpu(x) (x)=0;
+#define cpu_logical_map(x) (x)
 #else
 #include <asm/thread_info.h>
 #define stack_smp_processor_id() \
diff -Nru a/include/asm-x86_64/socket.h b/include/asm-x86_64/socket.h
--- a/include/asm-x86_64/socket.h	Tue Oct 15 20:29:11 2002
+++ b/include/asm-x86_64/socket.h	Tue Oct 15 20:29:11 2002
@@ -3,7 +3,7 @@
 
 #include <asm/sockios.h>
 
-/* For setsockoptions(2) */
+/* For setsockopt(2) */
 #define SOL_SOCKET	1
 
 #define SO_DEBUG	1
diff -Nru a/include/asm-x86_64/softirq.h b/include/asm-x86_64/softirq.h
--- a/include/asm-x86_64/softirq.h	Tue Oct 15 20:29:20 2002
+++ b/include/asm-x86_64/softirq.h	Tue Oct 15 20:29:20 2002
@@ -1,35 +1,20 @@
 #ifndef __ASM_SOFTIRQ_H
 #define __ASM_SOFTIRQ_H
 
-#include <asm/atomic.h>
+#include <linux/preempt.h>
 #include <asm/hardirq.h>
-#include <asm/pda.h>
 
-#define __cpu_bh_enable() do { \
-	barrier(); sub_pda(__local_bh_count,1); preempt_enable(); } while (0)
-#define cpu_bh_disable() do { \
-	preempt_disable(); add_pda(__local_bh_count,1); barrier(); } while (0)
+#define local_bh_disable() \
+		do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0)
+#define __local_bh_enable() \
+		do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0)
 
-#define local_bh_disable()	cpu_bh_disable()
-#define __local_bh_enable()	__cpu_bh_enable()
-
-#define in_softirq() (read_pda(__local_bh_count) != 0)
-
-#define _local_bh_enable() do {							\
-	asm volatile(								\
-		"decl %%gs:%c1;"						\
-		"jnz 1f;"							\
-		"cmpl $0,%%gs:%c0;"						\
-		"jnz 2f;"							\
-		"1:;"								\
-		".section .text.lock,\"ax\";"					\
-		"2: call do_softirq_thunk;"					\
-		"jmp 1b;"							\
-		".previous" 							\
-		:: "i" (pda_offset(__softirq_pending)), \
-		   "i" (pda_offset(__local_bh_count)) : \
-		"memory");	\
+#define local_bh_enable()						\
+do {									\
+	__local_bh_enable();						\
+	if (unlikely(!in_interrupt() && softirq_pending(smp_processor_id()))) \
+		do_softirq();						\
+	preempt_check_resched();					\
 } while (0)
-#define local_bh_enable() do { _local_bh_enable(); preempt_enable(); } while(0)
 		
 #endif	/* __ASM_SOFTIRQ_H */
diff -Nru a/include/asm-x86_64/spinlock.h b/include/asm-x86_64/spinlock.h
--- a/include/asm-x86_64/spinlock.h	Tue Oct 15 20:29:22 2002
+++ b/include/asm-x86_64/spinlock.h	Tue Oct 15 20:29:22 2002
@@ -46,13 +46,13 @@
 	"\n1:\t" \
 	"lock ; decb %0\n\t" \
 	"js 2f\n" \
-	".section .text.lock,\"ax\"\n" \
+	LOCK_SECTION_START("") \
 	"2:\t" \
 	"cmpb $0,%0\n\t" \
 	"rep;nop\n\t" \
 	"jle 2b\n\t" \
 	"jmp 1b\n" \
-	".previous"
+	LOCK_SECTION_END
 
 /*
  * This works. Despite all the confusion.
@@ -167,5 +167,7 @@
 	atomic_add(RW_LOCK_BIAS, count);
 	return 0;
 }
+
+#define rwlock_is_locked(x) ((x)->lock != RW_LOCK_BIAS)
 
 #endif /* __ASM_SPINLOCK_H */
diff -Nru a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
--- a/include/asm-x86_64/system.h	Tue Oct 15 20:29:20 2002
+++ b/include/asm-x86_64/system.h	Tue Oct 15 20:29:20 2002
@@ -39,6 +39,7 @@
 	__POP(rax) __POP(r15) __POP(r14) __POP(r13) __POP(r12) __POP(r11) __POP(r10) \
 	__POP(r9) __POP(r8)
 
+/* RED-PEN: pipeline stall on ret because it is not predicted */
 #define switch_to(prev,next,last) \
 	asm volatile(SAVE_CONTEXT						    \
 		     "movq %%rsp,%[prevrsp]\n\t"				    \
@@ -72,7 +73,7 @@
 		"jmp 2b\n"			\
 		".previous\n"			\
 		".section __ex_table,\"a\"\n\t"	\
-		".align 4\n\t"			\
+		".align 8\n\t"			\
 		".quad 1b,3b\n"			\
 		".previous"			\
 		: :"r" ((int)(value)))
@@ -241,33 +242,15 @@
 #define local_irq_enable()	__asm__ __volatile__("sti": : :"memory")
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
+#define irqs_disabled()			\
+({					\
+	unsigned long flags;		\
+	local_save_flags(flags);	\
+	!(flags & (1<<9));		\
+})
 
 /* For spinlocks etc */
 #define local_irq_save(x) 	do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0)
-#define local_irq_restore(x)	__asm__ __volatile__("# local_irq_restore \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory")
-
-#ifdef CONFIG_SMP
-
-extern void __global_cli(void);
-extern void __global_sti(void);
-extern unsigned long __global_save_flags(void);
-extern void __global_restore_flags(unsigned long);
-#define cli() __global_cli()
-#define sti() __global_sti()
-#define save_flags(x) ((x)=__global_save_flags())
-#define restore_flags(x) __global_restore_flags(x)
-
-#else
-
-#define cli() local_irq_disable()
-#define sti() local_irq_enable()
-#define save_flags(x) local_save_flags(x)
-#define restore_flags(x) local_irq_restore(x)
-
-#endif
-
-/* Default simics "magic" breakpoint */
-#define icebp() asm volatile("xchg %%bx,%%bx" ::: "ebx")
 
 /*
  * disable hlt during certain critical i/o operations
diff -Nru a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
--- a/include/asm-x86_64/thread_info.h	Tue Oct 15 20:29:19 2002
+++ b/include/asm-x86_64/thread_info.h	Tue Oct 15 20:29:19 2002
@@ -35,15 +35,17 @@
 
 /*
  * macros/functions for gaining access to the thread information structure
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
  */
 #ifndef __ASSEMBLY__
 #define INIT_THREAD_INFO(tsk)			\
 {						\
-	task:		&tsk,			\
-	exec_domain:	&default_exec_domain,	\
-	flags:		0,			\
-	cpu:		0,			\
-	addr_limit:	KERNEL_DS,		\
+	.task	       = &tsk,			\
+	.exec_domain   = &default_exec_domain,	\
+	.flags	       = 0,			\
+	.cpu	       = 0,			\
+	.preempt_count = 1,			\
+	.addr_limit     = KERNEL_DS,		\
 }
 
 #define init_thread_info	(init_thread_union.thread_info)
diff -Nru a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h
--- a/include/asm-x86_64/timex.h	Tue Oct 15 20:29:17 2002
+++ b/include/asm-x86_64/timex.h	Tue Oct 15 20:29:17 2002
@@ -36,16 +36,14 @@
 
 static inline cycles_t get_cycles (void)
 {
-#ifndef CONFIG_X86_TSC
-	return 0;
-#else
 	unsigned long long ret;
 
 	rdtscll(ret);
 	return ret;
-#endif
 }
 
 extern unsigned int cpu_khz;
+
+extern struct hpet_data hpet;
 
 #endif
diff -Nru a/include/asm-x86_64/types.h b/include/asm-x86_64/types.h
--- a/include/asm-x86_64/types.h	Tue Oct 15 20:29:20 2002
+++ b/include/asm-x86_64/types.h	Tue Oct 15 20:29:20 2002
@@ -42,6 +42,11 @@
 typedef u64 dma64_addr_t;
 typedef u64 dma_addr_t;
 
+#ifdef CONFIG_LBD
+typedef u64 sector_t;
+#define HAVE_SECTOR_T
+#endif
+
 #endif /* __KERNEL__ */
 
 #endif
diff -Nru a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
--- a/include/asm-x86_64/unistd.h	Tue Oct 15 20:29:19 2002
+++ b/include/asm-x86_64/unistd.h	Tue Oct 15 20:29:19 2002
@@ -468,10 +468,22 @@
 __SYSCALL(__NR_sched_setaffinity, sys_sched_setaffinity)
 #define __NR_sched_getaffinity     204
 __SYSCALL(__NR_sched_getaffinity, sys_sched_getaffinity)
+#define __NR_set_thread_area	205
+__SYSCALL(__NR_set_thread_area, sys_set_thread_area)
+#define __NR_io_setup	206
+__SYSCALL(__NR_io_setup, sys_io_setup)
+#define __NR_io_destroy	207
+__SYSCALL(__NR_io_destroy, sys_io_destroy)
+#define __NR_io_getevents	208
+__SYSCALL(__NR_io_getevents, sys_io_getevents)
+#define __NR_io_submit	209
+__SYSCALL(__NR_io_submit, sys_io_submit)
+#define __NR_io_cancel	210
+__SYSCALL(__NR_io_cancel, sys_io_cancel)
+#define __NR_get_thread_area	211
+__SYSCALL(__NR_get_thread_area, sys_get_thread_area)
 
-
-#define __NR_syscall_max __NR_sched_getaffinity
-
+#define __NR_syscall_max __NR_get_thread_area
 #ifndef __NO_STUBS
 
 /* user-visible error numbers are in the range -1 - -4095 */
@@ -529,7 +541,7 @@
 __asm__ volatile (__syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
-		  "d" ((long)(arg3)) : __syscall_clobber, "r9" ); \
+		  "d" ((long)(arg3)) : __syscall_clobber); \
 __syscall_return(type,__res); \
 }
 
@@ -549,11 +561,25 @@
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
 { \
 long __res; \
-__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r9 ; " __syscall \
+__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; " __syscall \
 	: "=a" (__res) \
 	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
 	  "d" ((long)(arg3)),"g" ((long)(arg4)),"g" ((long)(arg5)) : \
-	__syscall_clobber,"r8","r9","r10" ); \
+	__syscall_clobber,"r8","r10" ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
+	  type5,arg5,type6,arg6) \
+type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
+{ \
+long __res; \
+__asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; movq %7,%%r9" __syscall \
+	: "=a" (__res) \
+	: "0" (__NR_##name),"D" ((long)(arg1)),"S" ((long)(arg2)), \
+	  "d" ((long)(arg3)),"g" ((long)(arg4)),"g" ((long)(arg5), \
+	  "g" ((long)(arg6),) : \
+	__syscall_clobber,"r8","r10","r9" ); \
 __syscall_return(type,__res); \
 }
 
diff -Nru a/include/asm-x86_64/user.h b/include/asm-x86_64/user.h
--- a/include/asm-x86_64/user.h	Tue Oct 15 20:29:21 2002
+++ b/include/asm-x86_64/user.h	Tue Oct 15 20:29:21 2002
@@ -3,7 +3,6 @@
 
 #include <asm/types.h>
 #include <asm/page.h>
-#include <linux/ptrace.h>
 /* Core file format: The core file is written in such a way that gdb
    can understand it and provide useful information to the user.
    There are quite a number of obstacles to being able to view the
diff -Nru a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h
--- a/include/asm-x86_64/vsyscall.h	Tue Oct 15 20:29:16 2002
+++ b/include/asm-x86_64/vsyscall.h	Tue Oct 15 20:29:16 2002
@@ -1,6 +1,8 @@
 #ifndef _ASM_X86_64_VSYSCALL_H_
 #define _ASM_X86_64_VSYSCALL_H_
 
+#include <linux/time.h>
+
 enum vsyscall_num {
 	__NR_vgettimeofday,
 	__NR_vtime,
@@ -13,32 +15,39 @@
 
 #ifdef __KERNEL__
 
-#define __section_last_tsc_low	__attribute__ ((unused, __section__ (".last_tsc_low")))
-#define __section_delay_at_last_interrupt	__attribute__ ((unused, __section__ (".delay_at_last_interrupt")))
-#define __section_fast_gettimeoffset_quotient	__attribute__ ((unused, __section__ (".fast_gettimeoffset_quotient")))
-#define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies")))
-#define __section_jiffies __attribute__ ((unused, __section__ (".jiffies")))
-#define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz")))
-#define __section_xtime __attribute__ ((unused, __section__ (".xtime")))
-#define __section_vxtime_sequence __attribute__ ((unused, __section__ (".vxtime_sequence")))
+#define __section_hpet __attribute__ ((unused, __section__ (".hpet"), aligned(16)))
+#define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"), aligned(16)))
+#define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
+#define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16)))
+#define __section_xtime __attribute__ ((unused, __section__ (".xtime"), aligned(16)))
+#define __section_vxtime_sequence __attribute__ ((unused, __section__ (".vxtime_sequence"), aligned(16)))
+
+struct hpet_data {
+	long address;		/* base address */
+	unsigned long hz;	/* HPET clocks / sec */
+	int trigger;		/* value at last interrupt */
+	int last;
+	int offset;
+	unsigned long last_tsc;
+	long ticks;
+};
+
+#define hpet_readl(a)           readl(fix_to_virt(FIX_HPET_BASE) + a)
+#define hpet_writel(d,a)        writel(d, fix_to_virt(FIX_HPET_BASE) + a)
 
 /* vsyscall space (readonly) */
 extern long __vxtime_sequence[2];
-extern int __delay_at_last_interrupt;
-extern unsigned int __last_tsc_low;
-extern unsigned int __fast_gettimeoffset_quotient;
-extern struct timeval __xtime;
+extern struct hpet_data __hpet;
+extern struct timespec __xtime;
 extern volatile unsigned long __jiffies;
 extern unsigned long __wall_jiffies;
 extern struct timezone __sys_tz;
 
 /* kernel space (writeable) */
-extern unsigned long last_tsc_low;
-extern int delay_at_last_interrupt;
-extern unsigned int fast_gettimeoffset_quotient;
+extern long vxtime_sequence[2];
+extern struct hpet_data hpet;
 extern unsigned long wall_jiffies;
 extern struct timezone sys_tz;
-extern long vxtime_sequence[2];
 
 #define vxtime_lock() do { vxtime_sequence[0]++; wmb(); } while(0)
 #define vxtime_unlock() do { wmb(); vxtime_sequence[1]++; } while (0)
diff -Nru a/include/asm-x86_64/xor.h b/include/asm-x86_64/xor.h
--- a/include/asm-x86_64/xor.h	Tue Oct 15 20:29:13 2002
+++ b/include/asm-x86_64/xor.h	Tue Oct 15 20:29:13 2002
@@ -46,7 +46,7 @@
 		"movups %%xmm1,0x10(%1)	;\n\t"	\
 		"movups %%xmm2,0x20(%1)	;\n\t"	\
 		"movups %%xmm3,0x30(%1)	;\n\t"	\
-		: "=r" (cr0)			\
+		: "=&r" (cr0)			\
 		: "r" (xmm_save) 		\
 		: "memory");			\
 } while(0)
@@ -335,11 +335,11 @@
 }
 
 static struct xor_block_template xor_block_sse = {
-        name: "generic_sse",
-        do_2: xor_sse_2,
-        do_3: xor_sse_3,
-        do_4: xor_sse_4,
-        do_5: xor_sse_5,
+        .name = "generic_sse",
+        .do_2 = xor_sse_2,
+        .do_3 = xor_sse_3,
+        .do_4 = xor_sse_4,
+        .do_5 = xor_sse_5,
 };
 
 #undef XOR_TRY_TEMPLATES
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Tue Oct 15 20:29:13 2002
+++ b/include/linux/blkdev.h	Tue Oct 15 20:29:13 2002
@@ -34,6 +34,7 @@
 
 	int rq_status;	/* should split this into a few status bits */
 	kdev_t rq_dev;
+	struct gendisk *rq_disk;
 	int errors;
 	sector_t sector;
 	unsigned long nr_sectors;
@@ -60,6 +61,12 @@
 	int tag;
 	void *special;
 	char *buffer;
+
+	/* For packet commands */
+	unsigned int data_len;
+	void *data, *sense;
+
+	unsigned int timeout;
 	struct completion *waiting;
 	struct bio *bio, *biotail;
 	request_queue_t *q;
@@ -85,6 +92,8 @@
 	__REQ_BLOCK_PC,	/* queued down pc from block layer */
 	__REQ_SENSE,	/* sense retrival */
 
+	__REQ_FAILED,	/* set if the request failed */
+	__REQ_QUIET,	/* don't worry about errors */
 	__REQ_SPECIAL,	/* driver suplied command */
 	__REQ_DRIVE_CMD,
 	__REQ_DRIVE_TASK,
@@ -103,6 +112,8 @@
 #define REQ_PC		(1 << __REQ_PC)
 #define REQ_BLOCK_PC	(1 << __REQ_BLOCK_PC)
 #define REQ_SENSE	(1 << __REQ_SENSE)
+#define REQ_FAILED	(1 << __REQ_FAILED)
+#define REQ_QUIET	(1 << __REQ_QUIET)
 #define REQ_SPECIAL	(1 << __REQ_SPECIAL)
 #define REQ_DRIVE_CMD	(1 << __REQ_DRIVE_CMD)
 #define REQ_DRIVE_TASK	(1 << __REQ_DRIVE_TASK)
@@ -301,7 +312,7 @@
 extern void blk_recount_segments(request_queue_t *, struct bio *);
 extern inline int blk_phys_contig_segment(request_queue_t *q, struct bio *, struct bio *);
 extern inline int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *);
-extern int block_ioctl(struct block_device *, unsigned int, unsigned long);
+extern int scsi_cmd_ioctl(struct block_device *, unsigned int, unsigned long);
 extern void blk_start_queue(request_queue_t *q);
 extern void blk_stop_queue(request_queue_t *q);
 extern void __blk_stop_queue(request_queue_t *q);
diff -Nru a/include/linux/blkpg.h b/include/linux/blkpg.h
--- a/include/linux/blkpg.h	Tue Oct 15 20:29:16 2002
+++ b/include/linux/blkpg.h	Tue Oct 15 20:29:16 2002
@@ -57,7 +57,6 @@
 #ifdef __KERNEL__
 
 extern char * partition_name(dev_t dev);
-extern int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- a/include/linux/buffer_head.h	Tue Oct 15 20:29:11 2002
+++ b/include/linux/buffer_head.h	Tue Oct 15 20:29:11 2002
@@ -32,7 +32,6 @@
 #define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
 
 struct page;
-struct kiobuf;
 struct buffer_head;
 struct address_space;
 typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
diff -Nru a/include/linux/cdrom.h b/include/linux/cdrom.h
--- a/include/linux/cdrom.h	Tue Oct 15 20:29:11 2002
+++ b/include/linux/cdrom.h	Tue Oct 15 20:29:11 2002
@@ -730,7 +730,6 @@
 	struct cdrom_device_ops  *ops;  /* link to device_ops */
 	struct cdrom_device_info *next; /* next device_info for this major */
 	void *handle;		        /* driver-dependent data */
-	struct device cdrom_driverfs_dev; /* driverfs implementation */
 /* specifications */
         kdev_t dev;	                /* device number */
 	int mask;                       /* mask of capability: disables them */
diff -Nru a/include/linux/dcache.h b/include/linux/dcache.h
--- a/include/linux/dcache.h	Tue Oct 15 20:29:23 2002
+++ b/include/linux/dcache.h	Tue Oct 15 20:29:23 2002
@@ -66,6 +66,8 @@
 
 #define DNAME_INLINE_LEN 16
 
+struct dcookie_struct;
+ 
 struct dentry {
 	atomic_t d_count;
 	unsigned int d_flags;
@@ -84,6 +86,7 @@
 	unsigned long d_vfs_flags;
 	void * d_fsdata;		/* fs-specific data */
 	unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
+	struct dcookie_struct * d_cookie; /* cookie, if any */
 };
 
 struct dentry_operations {
@@ -179,17 +182,6 @@
 extern void shrink_dcache_parent(struct dentry *);
 extern void shrink_dcache_anon(struct list_head *);
 extern int d_invalidate(struct dentry *);
-
-/* dcache memory management */
-extern int shrink_dcache_memory(int, unsigned int);
-extern void prune_dcache(int);
-
-/* icache memory management (defined in linux/fs/inode.c) */
-extern int shrink_icache_memory(int, unsigned int);
-extern void prune_icache(int);
-
-/* quota cache memory management (defined in linux/fs/dquot.c) */
-extern int shrink_dqcache_memory(int, unsigned int);
 
 /* only used at mount-time */
 extern struct dentry * d_alloc_root(struct inode *);
diff -Nru a/include/linux/dcookies.h b/include/linux/dcookies.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/dcookies.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,69 @@
+/*
+ * dcookies.h
+ *
+ * Persistent cookie-path mappings
+ *
+ * Copyright 2002 John Levon <levon@movementarian.org>
+ */
+
+#ifndef DCOOKIES_H
+#define DCOOKIES_H
+ 
+#include <linux/config.h>
+
+#ifdef CONFIG_PROFILING
+ 
+#include <linux/types.h>
+ 
+struct dcookie_user;
+ 
+/**
+ * dcookie_register - register a user of dcookies
+ *
+ * Register as a dcookie user. Returns %NULL on failure.
+ */
+struct dcookie_user * dcookie_register(void);
+
+/**
+ * dcookie_unregister - unregister a user of dcookies
+ *
+ * Unregister as a dcookie user. This may invalidate
+ * any dcookie values returned from get_dcookie().
+ */
+void dcookie_unregister(struct dcookie_user * user);
+  
+/**
+ * get_dcookie - acquire a dcookie
+ *
+ * Convert the given dentry/vfsmount pair into
+ * a cookie value.
+ *
+ * Returns -EINVAL if no living task has registered as a
+ * dcookie user.
+ *
+ * Returns 0 on success, with *cookie filled in
+ */
+int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt,
+	u32 * cookie);
+
+#else
+
+struct dcookie_user * dcookie_register(void)
+{
+	return 0;
+}
+
+void dcookie_unregister(struct dcookie_user * user)
+{
+	return;
+}
+ 
+static inline int get_dcookie(struct dentry * dentry,
+	struct vfsmount * vfsmnt, u32 * cookie)
+{
+	return -ENOSYS;
+} 
+ 
+#endif /* CONFIG_PROFILING */
+ 
+#endif /* DCOOKIES_H */
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Tue Oct 15 20:29:21 2002
+++ b/include/linux/device.h	Tue Oct 15 20:29:21 2002
@@ -329,6 +329,9 @@
  */
 extern int device_register(struct device * dev);
 extern void device_unregister(struct device * dev);
+extern void device_initialize(struct device * dev);
+extern int device_add(struct device * dev);
+extern void device_del(struct device * dev);
 
 /* driverfs interface for exporting device attributes */
 
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Tue Oct 15 20:29:14 2002
+++ b/include/linux/fs.h	Tue Oct 15 20:29:14 2002
@@ -359,6 +359,7 @@
 	sector_t		bd_offset;
 	unsigned		bd_part_count;
 	int			bd_invalidated;
+	struct gendisk *	bd_disk;
 };
 
 struct inode {
@@ -1087,6 +1088,7 @@
 extern struct address_space_operations def_blk_aops;
 extern struct file_operations def_fifo_fops;
 extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
+extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long);
 extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
 extern int blkdev_put(struct block_device *, int);
 extern int bd_claim(struct block_device *, void *);
diff -Nru a/include/linux/fsfilter.h b/include/linux/fsfilter.h
--- a/include/linux/fsfilter.h	Tue Oct 15 20:29:11 2002
+++ b/include/linux/fsfilter.h	Tue Oct 15 20:29:11 2002
@@ -1,3 +1,7 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+
 #ifndef __FILTER_H_
 #define __FILTER_H_ 1
 
@@ -59,12 +63,13 @@
         struct snapshot_ops *o_snops;
 };
 
-#define FILTER_FS_TYPES 5
+#define FILTER_FS_TYPES 6
 #define FILTER_FS_EXT2 0
 #define FILTER_FS_EXT3 1
 #define FILTER_FS_REISERFS 2
 #define FILTER_FS_XFS 3
 #define FILTER_FS_OBDFS 4
+#define FILTER_FS_TMPFS 5
 extern struct filter_fs filter_oppar[FILTER_FS_TYPES];
 
 struct filter_fs *filter_get_filter_fs(const char *cache_type);
@@ -96,7 +101,7 @@
 #define PRESTO_DEBUG
 #ifdef PRESTO_DEBUG
 /* debugging masks */
-#define D_SUPER     1   /* print results returned by Venus */
+#define D_SUPER     1  
 #define D_INODE     2   /* print entry and exit into procedure */
 #define D_FILE      4
 #define D_CACHE     8   /* cache debugging */
diff -Nru a/include/linux/genhd.h b/include/linux/genhd.h
--- a/include/linux/genhd.h	Tue Oct 15 20:29:12 2002
+++ b/include/linux/genhd.h	Tue Oct 15 20:29:12 2002
@@ -62,17 +62,19 @@
 	sector_t start_sect;
 	sector_t nr_sects;
 	devfs_handle_t de;              /* primary (master) devfs entry  */
-	struct device hd_driverfs_dev;  /* support driverfs hiearchy     */
+	struct device *hd_driverfs_dev;  /* support driverfs hiearchy     */
 };
 
 #define GENHD_FL_REMOVABLE  1
 #define GENHD_FL_DRIVERFS  2
 #define GENHD_FL_DEVFS	4
 #define GENHD_FL_CD	8
+#define GENHD_FL_UP	16
 
 struct gendisk {
 	int major;			/* major number of driver */
 	int first_minor;
+	int minors;
 	int minor_shift;		/* number of times minor is shifted to
 					   get real minor */
 	char disk_name[16];		/* name of major driver */
@@ -88,6 +90,10 @@
 	devfs_handle_t disk_de;		/* piled higher and deeper */
 	struct device *driverfs_dev;
 	struct device disk_dev;
+
+	unsigned sync_io;		/* RAID */
+	unsigned reads, writes;
+	unsigned rio, wio;
 };
 
 /* drivers/block/genhd.c */
@@ -260,20 +266,15 @@
 char *disk_name (struct gendisk *hd, int part, char *buf);
 
 extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
-extern void update_partition(struct gendisk *disk, int part);
+extern void add_partition(struct gendisk *, int, sector_t, sector_t);
+extern void delete_partition(struct gendisk *, int);
 
-extern struct gendisk *alloc_disk(void);
+extern struct gendisk *alloc_disk(int minors);
+extern struct gendisk *get_disk(struct gendisk *disk);
 extern void put_disk(struct gendisk *disk);
 
 /* will go away */
 extern void blk_set_probe(int major, struct gendisk *(p)(int));
-
-static inline unsigned int disk_index (kdev_t dev)
-{
-	int part;
-	struct gendisk *g = get_gendisk(kdev_t_to_nr(dev), &part);
-	return g ? (minor(dev) >> g->minor_shift) : 0;
-}
 
 #endif
 
diff -Nru a/include/linux/intermezzo_fs.h b/include/linux/intermezzo_fs.h
--- a/include/linux/intermezzo_fs.h	Tue Oct 15 20:29:16 2002
+++ b/include/linux/intermezzo_fs.h	Tue Oct 15 20:29:16 2002
@@ -1,213 +1,358 @@
-/*
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License as
- *  published by the Free Software Foundation; either version 2 of the
- *  License, or (at your option) any later version.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
+ *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ *  Copyright (C) 2001 Tacitus Systems, Inc.
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 TurboLinux, Inc.
  *  Copyright (C) 2000 Los Alamos National Laboratory.
- *  Copyright (C) 2001 Tacitus Systems, Inc.
- *  Copyright (C) 2001 Cluster File Systems, Inc. 
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef __INTERMEZZO_FS_H_
 #define __INTERMEZZO_FS_H_ 1
 
+#include <linux/intermezzo_lib.h>
+#include <linux/intermezzo_idl.h>
+
+
+#ifdef __KERNEL__
+typedef __u8 uuid_t[16];
+#else
+# include <uuid/uuid.h>
+#endif
+
+struct lento_vfs_context {
+        __u64 kml_offset;
+        __u64 updated_time;
+        __u64 remote_ino;
+        __u64 remote_generation;
+        __u32 slot_offset;
+        __u32 recno;
+        __u32 flags;
+        uuid_t uuid;
+        struct presto_version remote_version;
+};
+
+static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data);
+
 #ifdef __KERNEL__
-#include <linux/smp.h>
-#include <linux/fsfilter.h>
-#include <linux/namei.h>
+# include <linux/smp.h>
+# include <linux/fsfilter.h>
+# include <linux/slab.h>
+# include <linux/vmalloc.h>
+# include <linux/smp_lock.h>
 
 /* fixups for fs.h */
-#ifndef fs_down
-#define fs_down(sem) down(sem)
-#endif
+# ifndef fs_down
+#  define fs_down(sem) down(sem)
+# endif
+
+# ifndef fs_up
+#  define fs_up(sem) up(sem)
+# endif
+
+# define KML_IDLE                        0
+# define KML_DECODE                      1
+# define KML_OPTIMIZE                    2
+# define KML_REINT                       3
+
+# define KML_OPEN_REINT                  0x0100
+# define KML_REINT_BEGIN                 0x0200
+# define KML_BACKFETCH                   0x0400
+# define KML_REINT_END                   0x0800
+# define KML_CLOSE_REINT                 0x1000
+# define KML_REINT_MAXBUF                (64 * 1024)
 
-#ifndef fs_up
-#define fs_up(sem) up(sem)
-#endif
+# define CACHE_CLIENT_RO       0x4
+# define CACHE_LENTO_RO        0x8
 
-/* We will be more tolerant than the default ea patch with attr name sizes and
- * the size of value. If these come via VFS from the default ea patches, the
- * corresponding character strings will be truncated anyway. During journalling- * we journal length for both name and value. See journal_set_ext_attr.
- */
-#define PRESTO_EXT_ATTR_NAME_MAX 128
-#define PRESTO_EXT_ATTR_VALUE_MAX 8192
+/* global variables */
+extern int presto_debug;
+extern int presto_print_entry;
+extern long presto_kmemory;
+extern long presto_vmemory;
 
-#define KML_IDLE                        0
-#define KML_DECODE                      1
-#define KML_OPTIMIZE                    2
-#define KML_REINT                       3
-
-#define KML_OPEN_REINT                  0x0100
-#define KML_REINT_BEGIN                 0x0200
-#define KML_BACKFETCH                   0x0400
-#define KML_REINT_END                   0x0800
-#define KML_CLOSE_REINT                 0x1000
-#define FSET_GET_KMLDATA(fset)          fset->fset_kmldata
-#define KML_REINT_MAXBUF              	(64 * 1024)
-
-struct  kml_fsdata
-{
-        int                kml_state;
-
-        /* kml optimize support */
-        struct list_head   kml_kop_cache;
-
-        /* kml reint support */
-        int                kml_reint_state;
-        struct list_head   kml_reint_cache;
-        struct list_head  *kml_reint_current;
-        int                kml_maxsize;  /* max buffer */
-        int                kml_len;
-        char *             kml_buf;
-        loff_t             kml_reintpos;
-        int                kml_count;
-};
+# define PRESTO_DEBUG
+# ifdef PRESTO_DEBUG
+/* debugging masks */
+#  define D_SUPER       1
+#  define D_INODE       2
+#  define D_FILE        4
+#  define D_CACHE       8  /* cache debugging */
+#  define D_MALLOC     16  /* print malloc, de-alloc information */
+#  define D_JOURNAL    32
+#  define D_UPCALL     64  /* up and downcall debugging */
+#  define D_PSDEV     128
+#  define D_PIOCTL    256
+#  define D_SPECIAL   512
+#  define D_TIMING   1024
+#  define D_DOWNCALL 2048
+#  define D_KML      4096
+#  define D_FSDATA   8192
 
-/* super.c */
-struct presto_cache *presto_find_cache(struct super_block *sb) ;
-extern struct file_system_type presto_fs_type;
-extern int init_intermezzo_fs(void);
+#  define CDEBUG(mask, format, a...)                                    \
+        do {                                                            \
+                if (presto_debug & mask) {                              \
+                        printk("(%s:%s,l. %d %d): " format, __FILE__,   \
+                               __FUNCTION__, __LINE__, current->pid     \
+                               , ## a);                                 \
+                }                                                       \
+        } while (0)
 
-#define CACHE_TYPE_LENGTH       16
+#define CERROR(format, a...)                                            \
+do {                                                                    \
+        printk("(%s:%s,l. %d %d): " format, __FILE__, __FUNCTION__,     \
+               __LINE__, current->pid , ## a);                          \
+} while (0)
 
-int presto_ispresto(struct inode *);
+#  define ENTRY                                                         \
+        if (presto_print_entry)                                         \
+                printk("Process %d entered %s\n", current->pid, __FUNCTION__)
 
-#define CACHE_CLIENT_RO       0x4
-#define CACHE_LENTO_RO        0x8
-#define CACHE_FSETROOT_SET     0x10
+#  define EXIT                                                          \
+        if (presto_print_entry)                                         \
+                printk("Process %d leaving %s at %d\n", current->pid,   \
+                       __FUNCTION__, __LINE__)
 
+#  define presto_kmem_inc(ptr, size) presto_kmemory += (size)
+#  define presto_kmem_dec(ptr, size) presto_kmemory -= (size)
+#  define presto_vmem_inc(ptr, size) presto_vmemory += (size)
+#  define presto_vmem_dec(ptr, size) presto_vmemory -= (size)
+# else /* !PRESTO_DEBUG */
+#  define CDEBUG(mask, format, a...) do {} while (0)
+#  define ENTRY do {} while (0)
+#  define EXIT do {} while (0)
+#  define presto_kmem_inc(ptr, size) do {} while (0)
+#  define presto_kmem_dec(ptr, size) do {} while (0)
+#  define presto_vmem_inc(ptr, size) do {} while (0)
+#  define presto_vmem_dec(ptr, size) do {} while (0)
+# endif /* PRESTO_DEBUG */
+
+
+struct run_ctxt {
+        struct vfsmount *pwdmnt;
+        struct dentry   *pwd;
+        struct vfsmount *rootmnt;
+        struct dentry   *root;
+        uid_t            fsuid;
+        gid_t            fsgid;
+        mm_segment_t     fs;
+	int              ngroups;
+	gid_t	         groups[NGROUPS];
+
+};
+
+static inline void push_ctxt(struct run_ctxt *save, struct run_ctxt *new)
+{
+        int i;
+        save->fs = get_fs();
+        save->pwd = dget(current->fs->pwd);
+        save->pwdmnt = mntget(current->fs->pwdmnt);
+        save->fsgid = current->fsgid;
+        save->fsuid = current->fsuid;
+        save->root = current->fs->root;
+        save->rootmnt = current->fs->rootmnt;
+        save->ngroups = current->ngroups;
+        for (i = 0; i< current->ngroups; i++) 
+                save->groups[i] = current->groups[i];
+
+        set_fs(new->fs);
+        lock_kernel();
+        set_fs_pwd(current->fs, new->pwdmnt, new->pwd);
+        if (new->root)
+                set_fs_root(current->fs, new->rootmnt, new->root);
+        unlock_kernel();
+        current->fsuid = new->fsuid;
+        current->fsgid = new->fsgid;
+        if (new->ngroups > 0) {
+                current->ngroups = new->ngroups;
+                for (i = 0; i< new->ngroups; i++) 
+                        current->groups[i] = new->groups[i];
+        }
+        
+}
+
+static inline void pop_ctxt(struct run_ctxt *saved)
+{
+        int i;
+
+        set_fs(saved->fs);
+        lock_kernel();
+        set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
+        if (saved->root)
+                set_fs_root(current->fs, saved->rootmnt, saved->root);
+        unlock_kernel();
+        current->fsuid = saved->fsuid;
+        current->fsgid = saved->fsgid;
+        current->ngroups = saved->ngroups;
+        for (i = 0; i< saved->ngroups; i++) 
+                current->groups[i] = saved->groups[i];
+
+        mntput(saved->pwdmnt);
+        dput(saved->pwd);
+}
+
+static inline struct presto_dentry_data *presto_d2d(struct dentry *dentry)
+{
+        return (struct presto_dentry_data *)(dentry->d_fsdata);
+}
 
 struct presto_cache {
-        spinlock_t         cache_lock; 
-	loff_t             cache_reserved;
-        struct list_head cache_chain; /* for the dev/cache hash */
+        spinlock_t          cache_lock;
+        loff_t              cache_reserved;
+        struct  vfsmount   *cache_vfsmount;
+        struct super_block *cache_sb;
+        struct  dentry     *cache_root;
+        struct list_head    cache_chain; /* for the dev/cache hash */
 
         int   cache_flags;
-        char *cache_root_fileset;  /* fileset mounted on cache "/"  */
 
-	struct super_block *cache_sb;
-        struct dentry *cache_mtde;  /* unix mtpt of cache XXX NOT VALID XXX */
-        char *cache_mtpt;           /*  again */
+        kdev_t cache_dev;            /* underlying block device */
 
         char *cache_type;            /* filesystem type of cache */
         struct filter_fs *cache_filter;
 
-        struct upc_comm *cache_psdev;  /* points to /dev/intermezzo? we use */
-        struct list_head cache_psdev_chain; 
-
+        struct upc_channel *cache_psdev;  /* points to channel used */
+        struct list_head cache_channel_list; 
         struct list_head cache_fset_list; /* filesets mounted in cache */
 };
 
-
-
-
-/* file sets */
-#define CHUNK_BITS  16
-
 struct presto_log_fd {
-        rwlock_t         fd_lock; 
-        loff_t           fd_offset;  /* offset where next record should go */ 
+        rwlock_t         fd_lock;
+        loff_t           fd_offset;  /* offset where next record should go */
         struct file    *fd_file;
         int             fd_truncating;
-        unsigned int   fd_recno;   /* last recno written */ 
+        unsigned int   fd_recno;   /* last recno written */
         struct list_head  fd_reservations;
 };
 
+/* file sets */
+# define CHUNK_BITS  16
+
 struct presto_file_set {
         struct list_head fset_list;
         struct presto_log_fd fset_kml;
         struct presto_log_fd fset_lml;
-        struct file *fset_last_rcvd;
-        struct dentry *fset_mtpt;
-        struct nameidata fset_nd; 
+        struct presto_log_fd fset_rcvd;
+        struct list_head *fset_clients;  /* cache of clients */
+        struct dentry *fset_dentry;
+        struct vfsmount *fset_mnt;
         struct presto_cache *fset_cache;
 
         unsigned int fset_lento_recno;  /* last recno mentioned to lento */
         loff_t fset_lento_off;    /* last offset mentioned to lento */
+        loff_t fset_kml_logical_off; /* logical offset of kml file byte 0 */
         char * fset_name;
 
         int fset_flags;
+        int fset_chunkbits;
+        char *fset_reint_buf; /* temporary buffer holds kml during reint */
+
+        spinlock_t fset_permit_lock;
         int fset_permit_count;
-        int fset_permit_cookie;
-        int fset_chunkbits; 
-	struct  kml_fsdata *fset_kmldata;
-	loff_t  fset_file_maxio;  /* writing more than this causes a close */ 
+        int fset_permit_upcall_count;
+        /* This queue is used both for processes waiting for the kernel to give
+         * up the permit as well as processes waiting for the kernel to be given
+         * the permit, depending on the state of FSET_HASPERMIT. */
+        wait_queue_head_t fset_permit_queue;
+
+        loff_t  fset_file_maxio;  /* writing more than this causes a close */
+        unsigned long int kml_truncate_size;
 };
 
 /* This is the default number of bytes written before a close is recorded*/
 #define FSET_DEFAULT_MAX_FILEIO (1024<<10)
 
+struct dentry *presto_tmpfs_ilookup(struct inode *dir, struct dentry *dentry, 
+                                    ino_t ino, unsigned int generation);
+struct dentry *presto_iget_ilookup(struct inode *dir, struct dentry *dentry, 
+                                    ino_t ino, unsigned int generation);
+struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
+                                         struct dentry *real);
+
 struct journal_ops {
+        int (*tr_all_data)(struct inode *);
         loff_t (*tr_avail)(struct presto_cache *fset, struct super_block *);
         void *(*tr_start)(struct presto_file_set *, struct inode *, int op);
         void (*tr_commit)(struct presto_file_set *, void *handle);
         void (*tr_journal_data)(struct inode *);
+        struct dentry *(*tr_ilookup)(struct inode *dir, struct dentry *dentry, ino_t ino, unsigned int generation);
+        struct dentry *(*tr_add_ilookup)(struct dentry *parent, struct dentry *real);
 };
 
-
 extern struct journal_ops presto_ext2_journal_ops;
 extern struct journal_ops presto_ext3_journal_ops;
+extern struct journal_ops presto_tmpfs_journal_ops;
 extern struct journal_ops presto_xfs_journal_ops;
 extern struct journal_ops presto_reiserfs_journal_ops;
 extern struct journal_ops presto_obdfs_journal_ops;
-struct lento_vfs_context {
-        __u32 slot_offset;
-        __u32 recno;
-        __u64 kml_offset;
-        __u32 flags;
-        __u32 updated_time;
-};
-
 
-#define LENTO_FL_KML            0x0001
-#define LENTO_FL_EXPECT         0x0002
-#define LENTO_FL_VFSCHECK       0x0004
-#define LENTO_FL_JUSTLOG        0x0008
-#define LENTO_FL_WRITE_KML      0x0010
-#define LENTO_FL_CANCEL_LML     0x0020
-#define LENTO_FL_WRITE_EXPECT   0x0040
-#define LENTO_FL_IGNORE_TIME    0x0080
+# define LENTO_FL_KML            0x0001
+# define LENTO_FL_EXPECT         0x0002
+# define LENTO_FL_VFSCHECK       0x0004
+# define LENTO_FL_JUSTLOG        0x0008
+# define LENTO_FL_WRITE_KML      0x0010
+# define LENTO_FL_CANCEL_LML     0x0020
+# define LENTO_FL_WRITE_EXPECT   0x0040
+# define LENTO_FL_IGNORE_TIME    0x0080
+# define LENTO_FL_TOUCH_PARENT   0x0100
+# define LENTO_FL_TOUCH_NEWOBJ   0x0200
+# define LENTO_FL_SET_DDFILEID   0x0400
 
-struct presto_cache *presto_get_cache(struct inode *inode) ;
+struct presto_cache *presto_get_cache(struct inode *inode);
 int presto_sprint_mounts(char *buf, int buflen, int minor);
 struct presto_file_set *presto_fset(struct dentry *de);
 int presto_journal(struct dentry *dentry, char *buf, size_t size);
 int presto_fwrite(struct file *file, const char *str, int len, loff_t *off);
+int presto_ispresto(struct inode *);
+
+/* super.c */
+extern struct file_system_type presto_fs_type;
+extern int init_intermezzo_fs(void);
+
+/* fileset.c */
+extern int izo_prepare_fileset(struct dentry *root, char *fsetname);
+char * izo_make_path(struct presto_file_set *fset, char *name);
+struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode);
 
 /* psdev.c */
+int izo_psdev_get_free_channel(void);
 int presto_psdev_init(void);
+int izo_psdev_setpid(int minor);
 extern void presto_psdev_cleanup(void);
 inline int presto_lento_up(int minor);
+int izo_psdev_setchannel(struct file *file, int fd);
 
 /* inode.c */
 extern struct super_operations presto_super_ops;
-extern int presto_excluded_gid; 
-#define PRESTO_EXCL_GID 4711
 void presto_set_ops(struct inode *inode, struct  filter_fs *filter);
-void presto_read_inode(struct inode *inode);
-void presto_put_super(struct super_block *);
-
-/* journal.c */
-void presto_trans_commit(struct presto_file_set *fset, void *handle);
-void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
-                           int op);
 
 /* dcache.c */
-void presto_frob_dop(struct dentry *de) ;
-char * presto_path(struct dentry *dentry, struct dentry *root,
-                   char *buffer, int buflen);
-void presto_set_dd(struct dentry *);
-void presto_init_ddata_cache(void);
+void presto_frob_dop(struct dentry *de);
+char *presto_path(struct dentry *dentry, struct dentry *root,
+                  char *buffer, int buflen);
+inline struct presto_dentry_data *izo_alloc_ddata(void);
+int presto_set_dd(struct dentry *);
+int presto_init_ddata_cache(void);
 void presto_cleanup_ddata_cache(void);
 extern struct dentry_operations presto_dentry_ops;
 
-
-
 /* dir.c */
 extern struct inode_operations presto_dir_iops;
 extern struct inode_operations presto_file_iops;
@@ -216,106 +361,103 @@
 extern struct file_operations presto_file_fops;
 extern struct file_operations presto_sym_fops;
 int presto_setattr(struct dentry *de, struct iattr *iattr);
-extern int presto_ilookup_uid; 
-#define PRESTO_ILOOKUP_MAGIC "...ino:"
-#define PRESTO_ILOOKUP_SEP ':'
-
+int presto_settime(struct presto_file_set *fset, struct dentry *newobj,
+                   struct dentry *parent, struct dentry *target,
+                   struct lento_vfs_context *ctx, int valid);
+int presto_ioctl(struct inode *inode, struct file *file,
+                 unsigned int cmd, unsigned long arg);
+
+extern int presto_ilookup_uid;
+# define PRESTO_ILOOKUP_MAGIC "...ino:"
+# define PRESTO_ILOOKUP_SEP ':'
+int izo_dentry_is_ilookup(struct dentry *, ino_t *id, unsigned int *generation);
 struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry);
 
-/* file.c */
-struct presto_reservation_data {
-        unsigned int ri_recno; 
-        loff_t ri_offset;
-        loff_t ri_size;
-        struct list_head ri_list;
-};
-
-
-struct presto_dentry_data { 
+struct presto_dentry_data {
         int dd_count; /* how mnay dentries are using this dentry */
         struct presto_file_set *dd_fset;
+        struct dentry *dd_inodentry; 
         loff_t dd_kml_offset;
         int dd_flags;
+        __u64 remote_ino;
+        __u64 remote_generation;
+};
 
-}; 
-
-struct presto_file_data { 
+struct presto_file_data {
         int fd_do_lml;
         loff_t fd_lml_offset;
-        uid_t fd_fsuid;
-        gid_t fd_fsgid;
+        size_t fd_bytes_written;
+        /* authorization related data of file at open time */
         uid_t fd_uid;
         gid_t fd_gid;
         mode_t fd_mode;
+        /* identification data of calling process */
+        uid_t fd_fsuid;
+        gid_t fd_fsgid;
         int fd_ngroups;
-        size_t fd_bytes_written; /* Number of bytes written so far on this fd*/
         gid_t fd_groups[NGROUPS_MAX];
+        /* information how to complete the close operation */
+        struct lento_vfs_context fd_info;
+        struct presto_version fd_version;
 };
 
-
 /* presto.c and Lento::Downcall */
-struct presto_version {
-        __u64 pv_mtime;
-        __u64 pv_ctime;
-        __u64 pv_size;
-};
-inline struct presto_dentry_data *presto_d2d(struct dentry *);
+
 int presto_walk(const char *name, struct nameidata *nd);
-int presto_clear_fsetroot(char *path);
-int presto_clear_all_fsetroots(char *path);
-int  presto_get_kmlsize(char *path, size_t *size);
-int  presto_get_lastrecno(char *path, off_t *size);
-int presto_set_fsetroot(char *path, char *fsetname, unsigned int fsetid,
+int izo_clear_fsetroot(struct dentry *dentry);
+int izo_clear_all_fsetroots(struct presto_cache *cache);
+int presto_get_kmlsize(char *path, __u64 *size);
+int presto_get_lastrecno(char *path, off_t *size);
+int presto_set_fsetroot(struct dentry *dentry, char *fsetname,
                        unsigned int flags);
-int presto_has_all_data(struct inode *inode);
+int presto_set_fsetroot_from_ioc(struct dentry *dentry, char *fsetname,
+                                 unsigned int flags);
 inline int presto_is_read_only(struct presto_file_set *);
 int presto_truncate_lml(struct presto_file_set *fset);
 int lento_write_lml(char *path,
-                     __u64 remote_ino, 
+                     __u64 remote_ino,
                      __u32 remote_generation,
                      __u32 remote_version,
                     struct presto_version *remote_file_version);
-int lento_reset_fset(char *path, __u64 offset, __u32 recno);
 int lento_complete_closes(char *path);
-int lento_cancel_lml(char *path,
-                     __u64 lml_offset, 
-                     __u64 remote_ino, 
-                     __u32 remote_generation,
-                     __u32 remote_version, 
-                     struct lento_vfs_context *info);
 inline int presto_f2m(struct presto_file_set *fset);
-
+int presto_prep(struct dentry *, struct presto_cache **,
+                       struct presto_file_set **);
 /* cache.c */
+extern struct presto_cache *presto_cache_init(void);
+extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev);
+extern inline void presto_cache_init_hash(void);
+
+struct presto_cache *presto_cache_find(kdev_t dev);
+
 #define PRESTO_REQLOW  (3 * 4096)
 #define PRESTO_REQHIGH (6 * 4096)
 void presto_release_space(struct presto_cache *cache, loff_t req);
 int presto_reserve_space(struct presto_cache *cache, loff_t req);
 
-/* NOTE: PRESTO_FSETROOT MUST be 0x1:
-   - if this bit is set dentry->d_fsdata points to a file_set
-   - the address of the file_set if d_fsdata - 1
-*/
-
-#define PRESTO_FSETROOT         0x00000001 /* dentry is fileset root */
 #define PRESTO_DATA             0x00000002 /* cached data is valid */
 #define PRESTO_ATTR             0x00000004 /* attributes cached */
-
-#define EISFSETROOT             0x2001
-
+#define PRESTO_DONT_JOURNAL     0x00000008 /* things like .intermezzo/ */
 
 struct presto_file_set *presto_path2fileset(const char *name);
-int presto_permit_downcall(const char *path, int *cookie);
+int izo_revoke_permit(struct dentry *, uuid_t uuid);
 int presto_chk(struct dentry *dentry, int flag);
 void presto_set(struct dentry *dentry, int flag);
 int presto_get_permit(struct inode *inode);
 int presto_put_permit(struct inode *inode);
-int presto_mark_dentry(const char *path, int and, int or, int *res);
-int presto_mark_cache(const char *path, int and_bits, int or_bits, int *);
-int presto_mark_fset(const char *path, int and_bits, int or_bits, int *);
+int presto_set_max_kml_size(const char *path, unsigned long max_size);
+int izo_mark_dentry(struct dentry *dentry, int and, int or, int *res);
+int izo_mark_cache(struct dentry *dentry, int and_bits, int or_bits, int *);
+int izo_mark_fset(struct dentry *dentry, int and_bits, int or_bits, int *);
 void presto_getversion(struct presto_version *pv, struct inode *inode);
 int presto_i2m(struct inode *inode);
 int presto_c2m(struct presto_cache *cache);
 
+
+/* file.c */
+int izo_purge_file(struct presto_file_set *fset, char *file);
+int presto_adjust_lml(struct file *file, struct lento_vfs_context *info);
+
 /* journal.c */
 struct rec_info {
         loff_t offset;
@@ -323,21 +465,47 @@
         int recno;
         int is_kml;
 };
+
 void presto_trans_commit(struct presto_file_set *fset, void *handle);
 void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
-                           int op);
-int presto_clear_lml_close(struct presto_file_set *fset, 
+                         int op);
+int presto_fread(struct file *file, char *str, int len, loff_t *off);
+int presto_clear_lml_close(struct presto_file_set *fset,
                            loff_t  lml_offset);
-int presto_write_lml_close(struct rec_info *rec,
-                           struct presto_file_set *fset, 
-                           struct file *file,
-                           __u64 remote_ino,
-                           __u32 remote_generation,
-                           __u32 remote_version,
-                           struct presto_version *new_file_ver);
-int presto_complete_lml(struct presto_file_set *fset); 
+int presto_complete_lml(struct presto_file_set *fset);
+int presto_read_kml_logical_offset(struct rec_info *recinfo,
+                                   struct presto_file_set *fset);
+int presto_write_kml_logical_offset(struct presto_file_set *fset);
+struct file *presto_copy_kml_tail(struct presto_file_set *fset,
+                                  unsigned long int start);
+int presto_finish_kml_truncate(struct presto_file_set *fset,
+                               unsigned long int offset);
+int izo_lookup_file(struct presto_file_set *fset, char *path,
+                    struct nameidata *nd);
+int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry,
+                    loff_t length,  loff_t size_check);
+int izo_log_close(struct presto_log_fd *logfd);
+struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags);
+int izo_init_kml_file(struct presto_file_set *, struct presto_log_fd *);
+int izo_init_lml_file(struct presto_file_set *, struct presto_log_fd *);
+int izo_init_last_rcvd_file(struct presto_file_set *, struct presto_log_fd *);
 
 /* vfs.c */
+
+/* Extra data needed in the KML for rollback operations; this structure is
+ * passed around during the KML-writing process. */
+struct izo_rollback_data {
+        __u32 rb_mode;
+        __u32 rb_rdev;
+        __u64 rb_uid;
+        __u64 rb_gid;
+};
+
+int presto_write_last_rcvd(struct rec_info *recinfo,
+                           struct presto_file_set *fset,
+                           struct lento_vfs_context *info);
+void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb);
+int presto_do_close(struct presto_file_set *fset, struct file *file);
 int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry,
                       struct iattr *iattr, struct lento_vfs_context *info);
 int presto_do_create(struct presto_file_set *fset, struct dentry *dir,
@@ -359,9 +527,11 @@
 int presto_do_mknod(struct presto_file_set *fset, struct dentry *dir,
                     struct dentry *dentry, int mode, dev_t dev,
                     struct lento_vfs_context *info);
-int presto_do_rename(struct presto_file_set *fset, struct dentry *old_dir,
-                     struct dentry *old_dentry, struct dentry *new_dir,
-                     struct dentry *new_dentry, struct lento_vfs_context *info);
+int do_rename(struct presto_file_set *fset, struct dentry *old_dir,
+              struct dentry *old_dentry, struct dentry *new_dir,
+              struct dentry *new_dentry, struct lento_vfs_context *info);
+int presto_do_statfs (struct presto_file_set *fset,
+                      struct statfs * buf);
 
 int lento_setattr(const char *name, struct iattr *iattr,
                   struct lento_vfs_context *info);
@@ -378,8 +548,6 @@
 int lento_rename(const char *oldname, const char *newname,
                  struct lento_vfs_context *info);
 int lento_iopen(const char *name, ino_t ino, unsigned int generation,int flags);
-int lento_close(unsigned int fd, struct lento_vfs_context *info);
-
 
 /* journal.c */
 
@@ -387,12 +555,16 @@
 
 __inline__ int presto_no_journal(struct presto_file_set *fset);
 int journal_fetch(int minor);
-int presto_journal_write(struct rec_info *rec, struct presto_file_set *fset,
-                         struct file *file);
+int presto_log(struct presto_file_set *fset, struct rec_info *rec,
+               const char *buf, size_t size,
+               const char *string1, int len1, 
+               const char *string2, int len2,
+               const char *string3, int len3);
+int presto_get_fileid(int minor, struct presto_file_set *fset,
+                      struct dentry *dentry);
 int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset,
-                           struct dentry *dentry,
-                           struct presto_version *old_ver,
-                           struct iattr *iattr);
+                           struct dentry *dentry, struct presto_version *old_ver,
+                           struct izo_rollback_data *, struct iattr *iattr);
 int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset,
                           struct dentry *dentry,
                           struct presto_version *tgt_dir_ver,
@@ -402,10 +574,11 @@
                         struct presto_version *tgt_dir_ver,
                         struct presto_version *new_link_ver);
 int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset,
-                          struct dentry *dentry,
+                          struct dentry *dir,
                           struct presto_version *tgt_dir_ver,
-                          struct presto_version *old_file_ver, int len,
-                          const char *name);
+                          struct presto_version *old_file_ver,
+                          struct izo_rollback_data *, struct dentry *dentry,
+                          char *old_target, int old_targetlen);
 int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset,
                            struct dentry *dentry, const char *target,
                            struct presto_version *tgt_dir_ver,
@@ -417,8 +590,8 @@
 int presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
-                         struct presto_version *old_dir_ver, int len,
-                         const char *name);
+                         struct presto_version *old_dir_ver,
+                         struct izo_rollback_data *, int len, const char *name);
 int presto_journal_mknod(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
@@ -428,302 +601,332 @@
                           struct dentry *src, struct dentry *tgt,
                           struct presto_version *src_dir_ver,
                           struct presto_version *tgt_dir_ver);
-int presto_journal_open(struct rec_info *rec, struct presto_file_set *fset,
-                        struct dentry *dentry, struct presto_version *old_ver);
-int presto_journal_close(struct rec_info *rec, struct presto_file_set *fset,
-                         struct file *file, 
-			 struct dentry *dentry, 
-			 struct presto_version *new_ver);
-int presto_close_journal_file(struct presto_file_set *fset);
+int presto_journal_open(struct rec_info *, struct presto_file_set *,
+                        struct dentry *, struct presto_version *old_ver);
+int presto_journal_close(struct rec_info *rec, struct presto_file_set *,
+                         struct file *, struct dentry *,
+                         struct presto_version *old_file_ver,
+                         struct presto_version *new_file_ver);
+int presto_write_lml_close(struct rec_info *rec,
+                           struct presto_file_set *fset, 
+                           struct file *file,
+                           __u64 remote_ino,
+                           __u64 remote_generation,
+                           struct presto_version *remote_version,
+                           struct presto_version *new_file_ver);
 void presto_log_op(void *data, int len);
-int presto_write_last_rcvd(struct rec_info *recinfo,
-                           struct presto_file_set *fset,
-                           struct lento_vfs_context *info);
-
-/* journal_ext3.c */
-struct ext3_journal_data {
-        struct file *jd_file;
-};
-extern struct ext3_journal_data e3jd;
-
-
+loff_t presto_kml_offset(struct presto_file_set *fset);
 
+/* upcall.c */
+#define SYNCHRONOUS 0
+#define ASYNCHRONOUS 1
+/* asynchronous calls */
+int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length,
+                __u32 last_recno, char *fsetname);
+int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno,
+                         char *fsetname);
+int izo_upc_go_fetch_kml(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize);
+int izo_upc_backfetch(int minor, char *path, char *fileset, 
+                      struct lento_vfs_context *);
+
+/* synchronous calls */
+int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, 
+                       __u32 pathlen, char *path, char *fsetname);
+int izo_upc_permit(int minor, struct dentry *, __u32 pathlen, char *path,
+                   char *fset);
+int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, 
+                 struct lento_vfs_context *info);
+int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
+                    int client_flag);
+int izo_upc_revoke_permit(int minor, char *fsetname, uuid_t uuid);
+int izo_upc_set_kmlsize(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize);
+int izo_upc_client_make_branch(int minor, char *fsetname);
+int izo_upc_server_make_branch(int minor, char *fsetname);
+int izo_upc_branch_undo(int minor, char *fsetname, char *branchname);
+int izo_upc_branch_redo(int minor, char *fsetname, char *branchname);
+int izo_upc_repstatus(int minor,  char * fsetname, struct izo_rcvd_rec *lr_server);
+
+/* general mechanism */
+int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *, int async);
+
+/* replicator.c */
+int izo_repstatus(struct presto_file_set *fset, __u64 client_kmlsize, 
+                  struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server);
+int izo_rep_cache_init(struct presto_file_set *);
+loff_t izo_rcvd_get(struct izo_rcvd_rec *, struct presto_file_set *, char *uuid);
+loff_t izo_rcvd_write(struct presto_file_set *, struct izo_rcvd_rec *);
+loff_t izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid,  __u64 remote_recno,
+                           __u64 remote_offset);
 
 /* sysctl.c */
 int init_intermezzo_sysctl(void);
 void cleanup_intermezzo_sysctl(void);
 
 /* ext_attr.c */
-#ifdef CONFIG_FS_EXT_ATTR
-/* XXX: Borrowed from vfs.c. Once the ea patch is into CVS 
- * move this prototype -SHP
- */
-int presto_do_set_ext_attr(struct presto_file_set *fset,
-                           struct dentry *dentry,
-                           const char *name, void *buffer,
-                           size_t buffer_len, int flags, mode_t *mode,
-                           struct lento_vfs_context *info);
-int presto_set_ext_attr(struct inode *inode,
-                        const char *name, void *buffer,
-                        size_t buffer_len, int flags);
-int lento_set_ext_attr(const char *path, const char *name,
-                       void *buffer, size_t buffer_len, int flags,
-                       mode_t mode, struct lento_vfs_context *info);
-/* XXX: Borrowed from journal.c. Once the ea patch is into CVS 
- * move this prototype -SHP
+/* We will be more tolerant than the default ea patch with attr name sizes and
+ * the size of value. If these come via VFS from the default ea patches, the
+ * corresponding character strings will be truncated anyway. During journalling- * we journal length for both name and value. See journal_set_ext_attr.
  */
-int presto_journal_set_ext_attr (struct rec_info *rec,
-                                 struct presto_file_set *fset,
-                                 struct dentry *dentry,
-                                 struct presto_version *ver, const char *name,
-                                 const char *buffer, int buffer_len,
-                                 int flags);
-#endif
-
-
-/* global variables */
-extern int presto_debug;
-extern int presto_print_entry;
-
-#define PRESTO_DEBUG
-#ifdef PRESTO_DEBUG
-/* debugging masks */
-#define D_SUPER     1   /* print results returned by Venus */
-#define D_INODE     2   /* print entry and exit into procedure */
-#define D_FILE      4
-#define D_CACHE     8   /* cache debugging */
-#define D_MALLOC    16  /* print malloc, de-alloc information */
-#define D_JOURNAL   32
-#define D_UPCALL    64  /* up and downcall debugging */
-#define D_PSDEV    128
-#define D_PIOCTL   256
-#define D_SPECIAL  512
-#define D_TIMING  1024
-#define D_DOWNCALL 2048
-#define D_KML      4096
-
-#define CDEBUG(mask, format, a...)                                      \
-        do {                                                            \
-                if (presto_debug & mask) {                              \
-                        printk("(%s:%s,l. %d %d): ", __FILE__, __FUNCTION__, __LINE__, current->pid);   \
-                        printk(format, ##a); }                          \
-        } while (0)
-
-#define ENTRY                                                           \
-        if(presto_print_entry)                                          \
-                printk("Process %d entered %s\n", current->pid, __FUNCTION__)
-
-#define EXIT                                                            \
-        if(presto_print_entry)                                          \
-                printk("Process %d leaving %s at %d\n", current->pid,   \
-                       __FUNCTION__,__LINE__)
-
-extern long presto_kmemory;
-extern long presto_vmemory;
-
-#define presto_kmem_inc(ptr, size) presto_kmemory += (size)
-#define presto_kmem_dec(ptr, size) presto_kmemory -= (size)
-#define presto_vmem_inc(ptr, size) presto_vmemory += (size)
-#define presto_vmem_dec(ptr, size) presto_vmemory -= (size)
-#else /* !PRESTO_DEBUG */
-#define CDEBUG(mask, format, a...) do {} while (0)
-#define ENTRY do {} while (0)
-#define EXIT do {} while (0)
-#define presto_kmem_inc(ptr, size) do {} while (0)
-#define presto_kmem_dec(ptr, size) do {} while (0)
-#define presto_vmem_inc(ptr, size) do {} while (0)
-#define presto_vmem_dec(ptr, size) do {} while (0)
-#endif /* PRESTO_DEBUG */
-
+#define PRESTO_EXT_ATTR_NAME_MAX 128
+#define PRESTO_EXT_ATTR_VALUE_MAX 8192
 
-#define PRESTO_ALLOC(ptr, cast, size)                                   \
+#define PRESTO_ALLOC(ptr, size)                                         \
 do {                                                                    \
-    if (size <= 4096) {                                                 \
-        ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL);          \
-        CDEBUG(D_MALLOC, "kmalloced: %ld at %p.\n", (long)size, ptr);   \
-        presto_kmem_inc(ptr, size);                                     \
-    } else {                                                            \
-        ptr = (cast)vmalloc((unsigned long) size);                      \
-        CDEBUG(D_MALLOC, "vmalloced: %ld at %p.\n", (long)size, ptr);   \
-        presto_vmem_inc(ptr, size);                                     \
-    }                                                                   \
-    if ((ptr) == 0)                                                     \
-        printk("PRESTO: out of memory at %s:%d\n", __FILE__, __LINE__); \
-    else                                                                \
-        memset( ptr, 0, size );                                         \
+        long s = (size);                                                \
+        (ptr) = kmalloc(s, GFP_KERNEL);                                 \
+        if ((ptr) == NULL)                                              \
+                CERROR("IZO: out of memory at %s:%d (trying to "        \
+                       "allocate %ld)\n", __FILE__, __LINE__, s);       \
+        else {                                                          \
+                presto_kmem_inc((ptr), s);                              \
+                memset((ptr), 0, s);                                    \
+        }                                                               \
+        CDEBUG(D_MALLOC, "kmalloced: %ld at %p (tot %ld).\n",           \
+               s, (ptr), presto_kmemory);                               \
 } while (0)
 
-
-
-#define PRESTO_FREE(ptr,size)                                           \
+#define PRESTO_FREE(ptr, size)                                          \
 do {                                                                    \
-    if (!ptr) {                                                         \
-        printk("PRESTO: free NULL pointer (%ld bytes) at %s:%d\n",      \
-               (long)size, __FILE__, __LINE__);                         \
-        break;                                                          \
-    }                                                                   \
-    if (size <= 4096) {                                                 \
-        CDEBUG(D_MALLOC, "kfreed: %ld at %p.\n", (long)size, ptr);      \
-        presto_kmem_dec(ptr, size);                                     \
-        kfree((ptr));                                         \
-    } else {                                                            \
-        CDEBUG(D_MALLOC, "vfreed: %ld at %p.\n", (long)size, ptr);      \
-        presto_vmem_dec(ptr, size);                                     \
-        vfree((ptr));                                                   \
-    }                                                                   \
+        long s = (size);                                                \
+        if ((ptr) == NULL) {                                            \
+                CERROR("IZO: free NULL pointer (%ld bytes) at "         \
+                       "%s:%d\n", s, __FILE__, __LINE__);               \
+                break;                                                  \
+        }                                                               \
+        kfree(ptr);                                                     \
+        CDEBUG(D_MALLOC, "kfreed: %ld at %p (tot %ld).\n",              \
+               s, (ptr), presto_kmemory);                               \
+        presto_kmem_dec((ptr), s);                                      \
 } while (0)
 
-#define MYPATHLEN(buffer,path) (buffer + PAGE_SIZE - path - 1)
-
-#else /* __KERNEL__ */
-#include <asm/types.h>
-#include <sys/ioctl.h>
-struct lento_vfs_context {
-        __u32 slot_offset;
-        __u32 recno;
-        __u64 kml_offset;
-        __u32 flags;
-        __u32 updated_time;
-};
-#endif /* __KERNEL__*/
-
-
-/* marking flags for fsets */
-#define FSET_CLIENT_RO 0x00000001
-#define FSET_LENTO_RO  0x00000002
-#define FSET_HASPERMIT  0x00000004 /* we have a permit to WB */
-#define FSET_INSYNC     0x00000008 /* this fileset is in sync */
-#define FSET_PERMIT_WAITING 0x00000010 /* Lento is waiting for permit */
-#define FSET_STEAL_PERMIT 0x00000020 /* take permit if Lento is dead */
-#define FSET_JCLOSE_ON_WRITE 0x00000040 /* Journal closes on writes */
-
-
-/* what to mark indicator (ioctl parameter) */ 
-#define MARK_DENTRY   101
-#define MARK_FSET     102
-#define MARK_CACHE    103
-#define MARK_GETFL    104
+static inline int dentry_name_cmp(struct dentry *dentry, char *name)
+{
+        return (strlen(name) == dentry->d_name.len &&
+                memcmp(name, dentry->d_name.name, dentry->d_name.len) == 0);
+}
 
+static inline char *strdup(char *str)
+{
+        char *tmp;
+        tmp = kmalloc(strlen(str) + 1, GFP_KERNEL);
+        if (tmp)
+                memcpy(tmp, str, strlen(str) + 1);
+               
+        return tmp;
+}
 
+/* buffer MUST be at least the size of izo_ioctl_hdr */
+static inline int izo_ioctl_getdata(char *buf, char *end, void *arg)
+{
+        struct izo_ioctl_hdr *hdr;
+        struct izo_ioctl_data *data;
+        int err;
+        ENTRY;
+
+        hdr = (struct izo_ioctl_hdr *)buf;
+        data = (struct izo_ioctl_data *)buf;
+
+        err = copy_from_user(buf, (void *)arg, sizeof(*hdr));
+        if ( err ) {
+                EXIT;
+                return err;
+        }
+
+        if (hdr->ioc_version != IZO_IOCTL_VERSION) {
+                CERROR("IZO: version mismatch kernel vs application\n");
+                return -EINVAL;
+        }
+
+        if (hdr->ioc_len + buf >= end) {
+                CERROR("IZO: user buffer exceeds kernel buffer\n");
+                return -EINVAL;
+        }
+
+        if (hdr->ioc_len < sizeof(struct izo_ioctl_data)) {
+                CERROR("IZO: user buffer too small for ioctl\n");
+                return -EINVAL;
+        }
+
+        err = copy_from_user(buf, (void *)arg, hdr->ioc_len);
+        if ( err ) {
+                EXIT;
+                return err;
+        }
+
+        if (izo_ioctl_is_invalid(data)) {
+                CERROR("IZO: ioctl not correctly formatted\n");
+                return -EINVAL;
+        }
+
+        if (data->ioc_inllen1) {
+                data->ioc_inlbuf1 = &data->ioc_bulk[0];
+        }
+
+        if (data->ioc_inllen2) {
+                data->ioc_inlbuf2 = &data->ioc_bulk[0] +
+                        size_round(data->ioc_inllen1);
+        }
+
+        EXIT;
+        return 0;
+}
+
+# define MYPATHLEN(buffer, path) ((buffer) + PAGE_SIZE - (path))
+
+# define free kfree
+# define malloc(a) kmalloc(a, GFP_KERNEL)
+# define printf printk
+int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data);
+int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data);
+int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data);
 
-struct readmount {
-        int io_len;  /* this is IN & OUT: true length of str is returned */
-        char *io_string;
-};
+#else /* __KERNEL__ */
+# include <stdlib.h>
+# include <stdio.h>
+# include <sys/types.h>
+# include <sys/ioctl.h>
+# include <string.h>
+
+# define printk printf
+# ifndef CERROR
+#   define CERROR printf
+# endif
+# define kmalloc(a,b) malloc(a)
+
+void init_fsreintdata (void);
+int kml_fsreint(struct kml_rec *rec, char *basedir);
+int kml_iocreint(__u32 size, char *ptr, __u32 offset, int dird,
+                 uuid_t uuid, __u32 generate_kml);
 
-/* modeled after setsockopt */
-/* so if you have no /proc, oh well. */
-/* for now it's all ints. We may grow this later for non-ints. */
-struct psdev_opt {
-        int optname;
-        int optval;
-};
+static inline int izo_ioctl_packlen(struct izo_ioctl_data *data);
 
-struct lento_input {
-        char *name;
-        struct lento_vfs_context info;
-};
+static inline void izo_ioctl_init(struct izo_ioctl_data *data)
+{
+        memset(data, 0, sizeof(*data));
+        data->ioc_len = sizeof(*data);
+        data->ioc_version = IZO_IOCTL_VERSION;
+}
 
-struct lento_input_attr {
-        char *name;
-#if BITS_PER_LONG < 64
-        __u32 dummy;    /* XXX on 64-bit platforms, this is not needed */
-#endif
-        __u32 valid;
-        __u32 mode;
-        __u32 uid;
-        __u32 gid;
-        __u64 size;
-        __s64 atime;
-        __s64 mtime;
-        __s64 ctime;
-        __u32 attr_flags;
-        struct lento_vfs_context info;
-};
+static inline int
+izo_ioctl_pack(struct izo_ioctl_data *data, char **pbuf, int max)
+{
+        char *ptr;
+        struct izo_ioctl_data *overlay;
+        data->ioc_len = izo_ioctl_packlen(data);
+        data->ioc_version = IZO_IOCTL_VERSION;
+
+        if (*pbuf && izo_ioctl_packlen(data) > max)
+                return 1;
+        if (*pbuf == NULL)
+                *pbuf = malloc(data->ioc_len);
+        if (*pbuf == NULL)
+                return 1;
+        overlay = (struct izo_ioctl_data *)*pbuf;
+        memcpy(*pbuf, data, sizeof(*data));
+
+        ptr = overlay->ioc_bulk;
+        if (data->ioc_inlbuf1)
+                LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
+        if (data->ioc_inlbuf2)
+                LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
+        if (izo_ioctl_is_invalid(overlay))
+                return 1;
 
-struct lento_input_mode {
-        char *name;
-        __u32 mode;
-        struct lento_vfs_context info;
-};
+        return 0;
+}
 
-struct lento_input_old_new {
-        char *oldname;
-        char *newname;
-        struct lento_vfs_context info;
-};
+#endif /* __KERNEL__*/
 
-struct lento_input_dev {
-        char *name;
-        __u32 mode;
-        __u32 major;
-        __u32 minor;
-        struct lento_vfs_context info;
-};
+#define IZO_ERROR_NAME 1
+#define IZO_ERROR_UPDATE 2
+#define IZO_ERROR_DELETE 3
+#define IZO_ERROR_RENAME 4
 
-struct lento_input_iopen {
-        char *name;
-#if BITS_PER_LONG < 64
-        __u32 dummy;    /* XXX on 64-bit platforms, this is not needed */
+static inline char *izo_error(int err)
+{
+#ifndef __KERNEL__
+        if (err <= 0)
+                return strerror(-err);
 #endif
-        __u64 ino;
-        __u32 generation;
-        __u32 flags;
-        __s32 fd;
-};
-
-struct lento_input_close {
-        __u32 fd;
-        struct lento_vfs_context info;
-};
+        switch (err) {
+        case IZO_ERROR_NAME:
+                return "InterMezzo name/name conflict";
+        case IZO_ERROR_UPDATE:
+                return "InterMezzo update/update conflict";
+        case IZO_ERROR_DELETE:
+                return "InterMezzo update/delete conflict";
+        case IZO_ERROR_RENAME:
+                return "InterMezzo rename/rename conflict";
+        }
+        return "Unknown InterMezzo error";
+}
 
-/* XXX: check for alignment */
-struct lento_input_ext_attr {
-        char  *path;
-        char  *name;
-        __u32 name_len;
-        char  *buffer;
-        __u32 buffer_len;
-        __u32 flags;
-        __u32 mode;
-        struct lento_vfs_context info;
-};
+static inline int izo_ioctl_packlen(struct izo_ioctl_data *data)
+{
+        int len = sizeof(struct izo_ioctl_data);
+        len += size_round(data->ioc_inllen1);
+        len += size_round(data->ioc_inllen2);
+        return len;
+}
 
-/* XXX should PRESTO_GET_* actually be of type _IOR, since we are reading? */
-#define PRESTO_GETMOUNT         _IOW ('p',0x03, struct readmount *)
-#define PRESTO_SETPID           _IOW ('p',0x04, struct readmount *)
-#define PRESTO_CLOSE_JOURNALF   _IOW ('p',0x06, struct readmount *)
-#define PRESTO_SET_FSETROOT     _IOW ('p',0x07, struct readmount *)
-#define PRESTO_CLEAR_FSETROOT   _IOW ('p',0x08, struct readmount *)
-#define PRESTO_SETOPT           _IOW ('p',0x09, struct psdev_opt *)
-#define PRESTO_GETOPT           _IOW ('p',0x0a, struct psdev_opt *)
-#define PRESTO_GET_KMLSIZE      _IOW ('p',0x0b, struct psdev_opt *)
-#define PRESTO_GET_RECNO        _IOW ('p',0x0c, struct psdev_opt *)
-#define PRESTO_VFS_SETATTR      _IOW ('p',0x10, struct lento_input_attr *)
-#define PRESTO_VFS_CREATE       _IOW ('p',0x11, struct lento_input_mode *)
-#define PRESTO_VFS_LINK         _IOW ('p',0x12, struct lento_input_old_new *)
-#define PRESTO_VFS_UNLINK       _IOW ('p',0x13, struct lento_input *)
-#define PRESTO_VFS_SYMLINK      _IOW ('p',0x14, struct lento_input_old_new *)
-#define PRESTO_VFS_MKDIR        _IOW ('p',0x15, struct lento_input_mode *)
-#define PRESTO_VFS_RMDIR        _IOW ('p',0x16, struct lento_input *)
-#define PRESTO_VFS_MKNOD        _IOW ('p',0x17, struct lento_input_dev *)
-#define PRESTO_VFS_RENAME       _IOW ('p',0x18, struct lento_input_old_new *)
-#define PRESTO_VFS_CLOSE        _IOW ('p',0x1a, struct lento_input_close *)
-#define PRESTO_VFS_IOPEN        _IOW ('p',0x1b, struct lento_input_iopen *)
-#define PRESTO_VFS_SETEXTATTR   _IOW ('p',0x1c, struct lento_input_ext_attr *)
-#define PRESTO_VFS_DELEXTATTR   _IOW ('p',0x1d, struct lento_input_ext_attr *)
-
-#define PRESTO_MARK             _IOW ('p',0x20, struct lento_input_open *)
-#define PRESTO_RELEASE_PERMIT   _IOW ('p',0x21, struct lento_input_open *)
-#define PRESTO_CLEAR_ALL_FSETROOTS  _IOW ('p',0x22, struct readmount *)
-#define PRESTO_BACKFETCH_LML    _IOW ('p',0x23, struct readmount *)
-#define PRESTO_REINT            _IOW ('p',0x24, struct readmount *)
-#define PRESTO_CANCEL_LML       _IOW ('p',0x25, struct readmount *)
-#define PRESTO_RESET_FSET       _IOW ('p',0x26, struct readmount *)
-#define PRESTO_COMPLETE_CLOSES  _IOW ('p',0x27, struct readmount *)
-
-#define PRESTO_REINT_BEGIN      _IOW ('p',0x30, struct readmount *)
-#define PRESTO_DO_REINT         _IOW ('p',0x31, struct readmount *)
-#define PRESTO_REINT_END        _IOW ('p',0x32, struct readmount *)
+static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data)
+{
+        if (data->ioc_len > (1<<30)) {
+                CERROR("IZO ioctl: ioc_len larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inllen1 > (1<<30)) {
+                CERROR("IZO ioctl: ioc_inllen1 larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inllen2 > (1<<30)) {
+                CERROR("IZO ioctl: ioc_inllen2 larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inlbuf1 && !data->ioc_inllen1) {
+                CERROR("IZO ioctl: inlbuf1 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_inlbuf2 && !data->ioc_inllen2) {
+                CERROR("IZO ioctl: inlbuf2 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_pbuf1 && !data->ioc_plen1) {
+                CERROR("IZO ioctl: pbuf1 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_pbuf2 && !data->ioc_plen2) {
+                CERROR("IZO ioctl: pbuf2 pointer but 0 length\n");
+                return 1;
+        }
+        if (izo_ioctl_packlen(data) != data->ioc_len ) {
+                CERROR("IZO ioctl: packlen exceeds ioc_len\n");
+                return 1;
+        }
+        if (data->ioc_inllen1 &&
+            data->ioc_bulk[data->ioc_inllen1 - 1] != '\0') {
+                CERROR("IZO ioctl: inlbuf1 not 0 terminated\n");
+                return 1;
+        }
+        if (data->ioc_inllen2 &&
+            data->ioc_bulk[size_round(data->ioc_inllen1) + data->ioc_inllen2
+                           - 1] != '\0') {
+                CERROR("IZO ioctl: inlbuf2 not 0 terminated\n");
+                return 1;
+        }
+        return 0;
+}
+
+/* kml_unpack.c */
+char *kml_print_rec(struct kml_rec *rec, int brief);
+int kml_unpack(struct kml_rec *rec, char **buf, char *end);
+
+/* fs 2.5 compat */
+
+/* is_read_only() is replaced by bdev_read_only which takes struct
+   block_device *.  Since this is only needed for debugging, it can be
+   safely ignored now.
+*/
+#define is_read_only(dev) 0
 
 #endif
diff -Nru a/include/linux/intermezzo_psdev.h b/include/linux/intermezzo_psdev.h
--- a/include/linux/intermezzo_psdev.h	Tue Oct 15 20:29:16 2002
+++ b/include/linux/intermezzo_psdev.h	Tue Oct 15 20:29:16 2002
@@ -1,57 +1,42 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+
 #ifndef __PRESTO_PSDEV_H
 #define __PRESTO_PSDEV_H
 
-#ifdef PRESTO_DEVEL
-# define PRESTO_FS_NAME "izofs"
-# define PRESTO_PSDEV_NAME "/dev/izo"
-# define PRESTO_PSDEV_MAJOR 186
-#else
-# define PRESTO_FS_NAME "InterMezzo"
-# define PRESTO_PSDEV_NAME "/dev/intermezzo"
-# define PRESTO_PSDEV_MAJOR 185
-#endif
-
-#define MAX_PRESTODEV 16
-
+#define MAX_CHANNEL 16
+#define PROCNAME_SIZE 32
+#include <linux/smp_lock.h>
+#include <linux/smp_lock.h>
 #include <linux/version.h>
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-#define wait_queue_head_t  struct wait_queue *
-#define DECLARE_WAITQUEUE(name,task) \
-        struct wait_queue name = { task, NULL }
-#define init_waitqueue_head(arg) 
-#else
-#ifndef __initfunc
-#define __initfunc(arg) arg
-#endif
-#endif
-
-
-/* represents state of a /dev/presto */
+/* represents state of an instance reached with /dev/intermezzo */
 /* communication pending & processing queues */
-struct upc_comm {
+struct upc_channel {
         unsigned int         uc_seq;
-        wait_queue_head_t    uc_waitq;     /* Lento wait queue */
-        struct list_head    uc_pending;
-        struct list_head    uc_processing;
-        int                  uc_pid;       /* Lento's pid */
-        int                  uc_hard; /* allows signals during upcalls */
+        wait_queue_head_t    uc_waitq;    /* Lento wait queue */
+        struct list_head     uc_pending;
+        struct list_head     uc_processing;
+        spinlock_t            uc_lock;
+        int                  uc_pid;      /* Lento's pid */
+        int                  uc_hard;     /* allows signals during upcalls */
         int                  uc_no_filter;
         int                  uc_no_journal;
         int                  uc_no_upcall;
-        int                  uc_timeout; /* . sec: signals will dequeue upc */
+        int                  uc_timeout;  /* . sec: signals will dequeue upc */
         long                 uc_errorval; /* for testing I/O failures */
         struct list_head     uc_cache_list;
-        int                   uc_minor;
-        char *                uc_devname;
+        int                  uc_minor;
 };
 
-#define ISLENTO(minor) (current->pid == upc_comms[minor].uc_pid \
-                || current->parent->pid == upc_comms[minor].uc_pid)
+#define ISLENTO(minor) (current->pid == izo_channels[minor].uc_pid \
+                || current->real_parent->pid == izo_channels[minor].uc_pid \
+                || current->real_parent->real_parent->pid == izo_channels[minor].uc_pid)
 
-extern struct upc_comm upc_comms[MAX_PRESTODEV];
+extern struct upc_channel izo_channels[MAX_CHANNEL];
 
-/* messages between presto filesystem in kernel and Venus */
+/* message types between presto filesystem in kernel */
 #define REQ_READ   1
 #define REQ_WRITE  2
 #define REQ_ASYNC  4
@@ -60,10 +45,10 @@
 struct upc_req {
         struct list_head   rq_chain;
         caddr_t            rq_data;
-        u_short            rq_flags;
-        u_short            rq_bufsize;
-        u_short            rq_rep_size;
-        u_short            rq_opcode;  /* copied from data to save lookup */
+        int                rq_flags;
+        int                rq_bufsize;
+        int                rq_rep_size;
+        int                rq_opcode;  /* copied from data to save lookup */
         int                rq_unique;
         wait_queue_head_t  rq_sleep;   /* process' wait queue */
         unsigned long      rq_posttime;
diff -Nru a/include/linux/iobuf.h b/include/linux/iobuf.h
--- a/include/linux/iobuf.h	Tue Oct 15 20:29:15 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,88 +0,0 @@
-/*
- * iobuf.h
- *
- * Defines the structures used to track abstract kernel-space io buffers.
- *
- */
-
-#ifndef __LINUX_IOBUF_H
-#define __LINUX_IOBUF_H
-
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <asm/atomic.h>
-
-/*
- * The kiobuf structure describes a physical set of pages reserved
- * locked for IO.  The reference counts on each page will have been
- * incremented, and the flags field will indicate whether or not we have
- * pre-locked all of the pages for IO.
- *
- * kiobufs may be passed in arrays to form a kiovec, but we must
- * preserve the property that no page is present more than once over the
- * entire iovec.
- */
-
-#define KIO_MAX_ATOMIC_IO	512 /* in kb */
-#define KIO_STATIC_PAGES	(KIO_MAX_ATOMIC_IO / (PAGE_SIZE >> 10) + 1)
-#define KIO_MAX_SECTORS		(KIO_MAX_ATOMIC_IO * 2)
-
-/* The main kiobuf struct */
-
-struct kiobuf 
-{
-	int		nr_pages;	/* Pages actually referenced */
-	int		array_len;	/* Space in the allocated lists */
-	int		offset;		/* Offset to start of valid data */
-	int		length;		/* Number of valid bytes of data */
-
-	/* Keep separate track of the physical addresses and page
-	 * structs involved.  If we do IO to a memory-mapped device
-	 * region, there won't necessarily be page structs defined for
-	 * every address. */
-
-	struct page **	maplist;
-
-	unsigned int	locked : 1;	/* If set, pages has been locked */
-	
-	/* Always embed enough struct pages for atomic IO */
-	struct page *	map_array[KIO_STATIC_PAGES];
-	sector_t	blocks[KIO_MAX_SECTORS];
-
-	/* Dynamic state for IO completion: */
-	atomic_t	io_count;	/* IOs still in progress */
-	int		errno;		/* Status of completed IO */
-	void		(*end_io) (struct kiobuf *); /* Completion callback */
-	wait_queue_head_t wait_queue;
-};
-
-
-/* mm/memory.c */
-
-int	map_user_kiobuf(int rw, struct kiobuf *, unsigned long va, size_t len);
-void	unmap_kiobuf(struct kiobuf *iobuf);
-int	lock_kiovec(int nr, struct kiobuf *iovec[], int wait);
-int	unlock_kiovec(int nr, struct kiobuf *iovec[]);
-void	mark_dirty_kiobuf(struct kiobuf *iobuf, int bytes);
-
-/* fs/iobuf.c */
-
-int	end_kio_request(struct kiobuf *, int);
-void	simple_wakeup_kiobuf(struct kiobuf *);
-int	alloc_kiovec(int nr, struct kiobuf **);
-void	free_kiovec(int nr, struct kiobuf **);
-int	expand_kiobuf(struct kiobuf *, int);
-void	kiobuf_wait_for_io(struct kiobuf *);
-extern int alloc_kiobuf_bhs(struct kiobuf *);
-extern void free_kiobuf_bhs(struct kiobuf *);
-
-/* fs/buffer.c */
-
-int	brw_kiovec(int rw, int nr, struct kiobuf *iovec[], 
-		   struct block_device *bdev, sector_t [], int size);
-
-/* fs/bio.c */
-void	ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t block);
-
-#endif /* __LINUX_IOBUF_H */
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Tue Oct 15 20:29:11 2002
+++ b/include/linux/mm.h	Tue Oct 15 20:29:11 2002
@@ -392,6 +392,29 @@
 
 
 /*
+ * Prototype to add a shrinker callback for ageable caches.
+ * 
+ * These functions are passed a count `nr_to_scan' and a gfpmask.  They should
+ * scan `nr_to_scan' objects, attempting to free them.
+ *
+ * The callback must the number of objects which remain in the cache.
+ *
+ * The callback will be passes nr_to_scan == 0 when the VM is querying the
+ * cache size, so a fastpath for that case is appropriate.
+ */
+typedef int (*shrinker_t)(int nr_to_scan, unsigned int gfp_mask);
+
+/*
+ * Add an aging callback.  The int is the number of 'seeks' it takes
+ * to recreate one of the objects that these functions age.
+ */
+
+#define DEFAULT_SEEKS 2
+struct shrinker;
+extern struct shrinker *set_shrinker(int, shrinker_t);
+extern void remove_shrinker(struct shrinker *shrinker);
+
+/*
  * If the mapping doesn't provide a set_page_dirty a_op, then
  * just fall through and assume that it wants buffer_heads.
  * FIXME: make the method unconditional.
diff -Nru a/include/linux/module.h b/include/linux/module.h
--- a/include/linux/module.h	Tue Oct 15 20:29:20 2002
+++ b/include/linux/module.h	Tue Oct 15 20:29:20 2002
@@ -274,8 +274,8 @@
  */
  
 #define MODULE_LICENSE(license) 	\
-static const char __module_license[] __attribute__((section(".modinfo"))) =   \
-"license=" license
+static const char __module_license[]	\
+  __attribute__((section(".modinfo"), unused)) = "license=" license
 
 /* Define the module variable, and usage macros.  */
 extern struct module __this_module;
@@ -286,11 +286,13 @@
 #define MOD_IN_USE		__MOD_IN_USE(THIS_MODULE)
 
 #include <linux/version.h>
-static const char __module_kernel_version[] __attribute__((section(".modinfo"))) =
-"kernel_version=" UTS_RELEASE;
+static const char __module_kernel_version[]
+  __attribute__((section(".modinfo"), unused)) =
+  "kernel_version=" UTS_RELEASE;
 #ifdef CONFIG_MODVERSIONS
-static const char __module_using_checksums[] __attribute__((section(".modinfo"))) =
-"using_checksums=1";
+static const char __module_using_checksums[]
+  __attribute__((section(".modinfo"), unused)) =
+  "using_checksums=1";
 #endif
 
 #else /* MODULE */
diff -Nru a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h
--- a/include/linux/msdos_fs_sb.h	Tue Oct 15 20:29:17 2002
+++ b/include/linux/msdos_fs_sb.h	Tue Oct 15 20:29:17 2002
@@ -10,6 +10,7 @@
 	uid_t fs_uid;
 	gid_t fs_gid;
 	unsigned short fs_umask;
+	unsigned short fs_dmask;
 	unsigned short codepage;  /* Codepage for shortname conversions */
 	char *iocharset;          /* Charset used for filename input/display */
 	unsigned short shortname; /* flags for shortname display/create rule */
@@ -22,7 +23,6 @@
 		 isvfat:1,        /* 0=no vfat long filename support, 1=vfat support */
 		 utf8:1,	  /* Use of UTF8 character set (Default) */
 		 unicode_xlate:1, /* create escape sequences for unhandled Unicode */
-		 posixfs:1,       /* Allow names like makefile and Makefile to coexist */
 		 numtail:1,       /* Does first alias have a numeric '~1' type tail? */
 		 atari:1,         /* Use Atari GEMDOS variation of MS-DOS fs */
 		 nocase:1;	  /* Does this need case conversion? 0=need case conversion*/
diff -Nru a/include/linux/mtd/concat.h b/include/linux/mtd/concat.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/mtd/concat.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,23 @@
+/*
+ * MTD device concatenation layer definitions
+ *
+ * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
+ *
+ * This code is GPL
+ *
+ * $Id: concat.h,v 1.1 2002/03/08 16:34:36 rkaiser Exp $
+ */
+
+#ifndef MTD_CONCAT_H
+#define MTD_CONCAT_H
+
+
+struct mtd_info *mtd_concat_create(
+    struct mtd_info *subdev[],  /* subdevices to concatenate */
+    int num_devs,               /* number of subdevices      */
+    char *name);                /* name for the new device   */
+
+void mtd_concat_destroy(struct mtd_info *mtd);
+
+#endif
+
diff -Nru a/include/linux/net.h b/include/linux/net.h
--- a/include/linux/net.h	Tue Oct 15 20:29:16 2002
+++ b/include/linux/net.h	Tue Oct 15 20:29:16 2002
@@ -81,6 +81,7 @@
 struct scm_cookie;
 struct vm_area_struct;
 struct page;
+struct kiocb;
 
 struct proto_ops {
   int	family;
@@ -104,8 +105,12 @@
 			 char *optval, int optlen);
   int	(*getsockopt)	(struct socket *sock, int level, int optname,
 			 char *optval, int *optlen);
-  int   (*sendmsg)	(struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm);
-  int   (*recvmsg)	(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm);
+  int   (*sendmsg)	(struct kiocb *iocb, struct socket *sock,
+			 struct msghdr *m, int total_len,
+			 struct scm_cookie *scm);
+  int   (*recvmsg)	(struct kiocb *iocb, struct socket *sock,
+			 struct msghdr *m, int total_len, int flags,
+			 struct scm_cookie *scm);
   int	(*mmap)		(struct file *file, struct socket *sock, struct vm_area_struct * vma);
   ssize_t (*sendpage)	(struct socket *sock, struct page *page, int offset, size_t size, int flags);
 };
@@ -194,10 +199,10 @@
 			 char *optval, int optlen), (sock, level, optname, optval, optlen)) \
 SOCKCALL_WRAP(name, getsockopt, (struct socket *sock, int level, int optname, \
 			 char *optval, int *optlen), (sock, level, optname, optval, optlen)) \
-SOCKCALL_WRAP(name, sendmsg, (struct socket *sock, struct msghdr *m, int len, struct scm_cookie *scm), \
-	      (sock, m, len, scm)) \
-SOCKCALL_WRAP(name, recvmsg, (struct socket *sock, struct msghdr *m, int len, int flags, struct scm_cookie *scm), \
-	      (sock, m, len, flags, scm)) \
+SOCKCALL_WRAP(name, sendmsg, (struct kiocb *iocb, struct socket *sock, struct msghdr *m, int len, struct scm_cookie *scm), \
+	      (iocb, sock, m, len, scm)) \
+SOCKCALL_WRAP(name, recvmsg, (struct kiocb *iocb, struct socket *sock, struct msghdr *m, int len, int flags, struct scm_cookie *scm), \
+	      (iocb, sock, m, len, flags, scm)) \
 SOCKCALL_WRAP(name, mmap, (struct file *file, struct socket *sock, struct vm_area_struct *vma), \
 	      (file, sock, vma)) \
 	      \
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h	Tue Oct 15 20:29:23 2002
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h	Tue Oct 15 20:29:23 2002
@@ -17,7 +17,7 @@
 struct ip_conntrack_protocol;
 extern struct ip_conntrack_protocol *ip_ct_find_proto(u_int8_t protocol);
 /* Like above, but you already have conntrack read lock. */
-extern struct ip_conntrack_protocol *__find_proto(u_int8_t protocol);
+extern struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol);
 extern struct list_head protocol_list;
 
 /* Returns conntrack if it dealt with ICMP, and filled in skb->nfct */
diff -Nru a/include/linux/nfs.h b/include/linux/nfs.h
--- a/include/linux/nfs.h	Tue Oct 15 20:29:13 2002
+++ b/include/linux/nfs.h	Tue Oct 15 20:29:13 2002
@@ -120,7 +120,7 @@
 /*
  * This is the kernel NFS client file handle representation
  */
-#define NFS_MAXFHSIZE		64
+#define NFS_MAXFHSIZE		128
 struct nfs_fh {
 	unsigned short		size;
 	unsigned char		data[NFS_MAXFHSIZE];
diff -Nru a/include/linux/nfs3.h b/include/linux/nfs3.h
--- a/include/linux/nfs3.h	Tue Oct 15 20:29:17 2002
+++ b/include/linux/nfs3.h	Tue Oct 15 20:29:17 2002
@@ -59,6 +59,11 @@
 	NF3BAD  = 8
 };
 
+struct nfs3_fh {
+	unsigned short size;
+	unsigned char  data[NFS3_FHSIZE];
+};
+
 #define NFS3_VERSION		3
 #define NFS3PROC_NULL		0
 #define NFS3PROC_GETATTR	1
diff -Nru a/include/linux/nfs4_mount.h b/include/linux/nfs4_mount.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/nfs4_mount.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,70 @@
+#ifndef _LINUX_NFS4_MOUNT_H
+#define _LINUX_NFS4_MOUNT_H
+
+/*
+ *  linux/include/linux/nfs4_mount.h
+ *
+ *  Copyright (C) 2002  Trond Myklebust
+ *
+ *  structure passed from user-space to kernel-space during an nfsv4 mount
+ */
+
+/*
+ * WARNING!  Do not delete or change the order of these fields.  If
+ * a new field is required then add it to the end.  The version field
+ * tracks which fields are present.  This will ensure some measure of
+ * mount-to-kernel version compatibility.  Some of these aren't used yet
+ * but here they are anyway.
+ */
+#define NFS4_MOUNT_VERSION	1
+
+struct nfs_string {
+	unsigned int len;
+	const char* data;
+};
+
+struct nfs4_mount_data {
+	int version;				/* 1 */
+	int flags;				/* 1 */
+	int rsize;				/* 1 */
+	int wsize;				/* 1 */
+	int timeo;				/* 1 */
+	int retrans;				/* 1 */
+	int acregmin;				/* 1 */
+	int acregmax;				/* 1 */
+	int acdirmin;				/* 1 */
+	int acdirmax;				/* 1 */
+
+	/* see the definition of 'struct clientaddr4' in RFC3010 */
+	struct nfs_string client_addr;		/* 1 */
+
+	/* Mount path */
+	struct nfs_string mnt_path;		/* 1 */
+
+	/* Server details */
+	struct nfs_string hostname;		/* 1 */
+	/* Server IP address */
+	unsigned int host_addrlen;		/* 1 */
+	struct sockaddr* host_addr;		/* 1 */
+
+	/* Transport protocol to use */
+	int proto;				/* 1 */
+
+	/* Pseudo-flavours to use for authentication. See RFC2623 */
+	int auth_flavourlen;			/* 1 */
+	int *auth_flavours;			/* 1 */
+};
+
+/* bits in the flags field */
+/* Note: the fields that correspond to existing NFSv2/v3 mount options
+ * 	 should mirror the values from include/linux/nfs_mount.h
+ */
+
+#define NFS4_MOUNT_SOFT		0x0001	/* 1 */
+#define NFS4_MOUNT_INTR		0x0002	/* 1 */
+#define NFS4_MOUNT_NOCTO	0x0010	/* 1 */
+#define NFS4_MOUNT_NOAC		0x0020	/* 1 */
+#define NFS4_MOUNT_STRICTLOCK	0x1000	/* 1 */
+#define NFS4_MOUNT_FLAGMASK	0xFFFF
+
+#endif
diff -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h	Tue Oct 15 20:29:16 2002
+++ b/include/linux/nfs_fs.h	Tue Oct 15 20:29:16 2002
@@ -472,6 +472,55 @@
 
 #define NFS_JUKEBOX_RETRY_TIME (5 * HZ)
 
+#ifdef CONFIG_NFS_V4
+struct nfs4_client {
+        atomic_t                cl_count;       /* refcount */
+        u64                     cl_clientid;    /* constant */
+	 nfs4_verifier           cl_confirm;     
+
+        /*
+         * Starts a list of lockowners, linked through lo_list.
+	 */
+        struct list_head        cl_lockowners;  /* protected by state_spinlock */
+};
+
+/* nfs4proc.c */
+extern int nfs4_proc_renew(struct nfs_server *server);
+
+/* nfs4renewd.c */
+extern int nfs4_init_renewd(struct nfs_server *server);
+#endif /* CONFIG_NFS_V4 */
+
+#ifdef CONFIG_NFS_V4
+
+extern struct nfs4_client *nfs4_get_client(void);
+extern void nfs4_put_client(struct nfs4_client *clp);
+
+struct nfs4_mount_data;
+static inline int
+create_nfsv4_state(struct nfs_server *server, struct nfs4_mount_data *data)
+{
+	server->nfs4_state = NULL;
+	return 0;
+}
+
+static inline void
+destroy_nfsv4_state(struct nfs_server *server)
+{
+	if (server->mnt_path) {
+		kfree(server->mnt_path);
+		server->mnt_path = NULL;
+	}
+	if (server->nfs4_state) {
+		nfs4_put_client(server->nfs4_state);
+		server->nfs4_state = NULL;
+	}
+}
+#else
+#define create_nfsv4_state(server, data)  0
+#define destroy_nfsv4_state(server)       do { } while (0)
+#endif
+
 #endif /* __KERNEL__ */
 
 /*
diff -Nru a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
--- a/include/linux/nfs_fs_sb.h	Tue Oct 15 20:29:23 2002
+++ b/include/linux/nfs_fs_sb.h	Tue Oct 15 20:29:23 2002
@@ -30,6 +30,16 @@
 				lru_busy;
 	struct nfs_fh		fh;
 	struct sockaddr_in	addr;
+#if CONFIG_NFS_V4
+	/* Our own IP address, as a null-terminated string.
+	 * This is used to generate the clientid, and the callback address.
+	 */
+	char			ip_addr[16];
+	char *			mnt_path;
+	struct nfs4_client *	nfs4_state;	/* all NFSv4 state starts here */
+	unsigned long		lease_time;	/* in jiffies */
+	unsigned long		last_renewal;	/* in jiffies */
+#endif
 };
 
 /* Server capabilities */
diff -Nru a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
--- a/include/linux/nfs_mount.h	Tue Oct 15 20:29:11 2002
+++ b/include/linux/nfs_mount.h	Tue Oct 15 20:29:11 2002
@@ -10,6 +10,8 @@
  */
 #include <linux/in.h>
 #include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
 
 /*
  * WARNING!  Do not delete or change the order of these fields.  If
@@ -37,7 +39,7 @@
 	char		hostname[256];		/* 1 */
 	int		namlen;			/* 2 */
 	unsigned int	bsize;			/* 3 */
-	struct nfs_fh	root;			/* 4 */
+	struct nfs3_fh	root;			/* 4 */
 };
 
 /* bits in the flags field */
@@ -53,6 +55,10 @@
 #define NFS_MOUNT_KERBEROS	0x0100	/* 3 */
 #define NFS_MOUNT_NONLM		0x0200	/* 3 */
 #define NFS_MOUNT_BROKEN_SUID	0x0400	/* 4 */
+#if 0
+#define NFS_MOUNT_STRICTLOCK	0x1000	/* reserved for NFSv4 */
+#define NFS_MOUNT_SECFLAVOUR	0x2000	/* reserved */
+#endif
 #define NFS_MOUNT_FLAGMASK	0xFFFF
 
 #endif
diff -Nru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
--- a/include/linux/nfs_xdr.h	Tue Oct 15 20:29:20 2002
+++ b/include/linux/nfs_xdr.h	Tue Oct 15 20:29:20 2002
@@ -50,6 +50,7 @@
  * Info on the file system
  */
 struct nfs_fsinfo {
+	struct nfs_fattr	*fattr; /* Post-op attributes */
 	__u32			rtmax;	/* max.  read transfer size */
 	__u32			rtpref;	/* pref. read transfer size */
 	__u32			rtmult;	/* reads should be multiple of this */
@@ -58,16 +59,31 @@
 	__u32			wtmult;	/* writes should be multiple of this */
 	__u32			dtpref;	/* pref. readdir transfer size */
 	__u64			maxfilesize;
-	__u64			bsize;	/* block size */
+	__u32			lease_time; /* in seconds */
+};
+
+struct nfs_fsstat {
+	struct nfs_fattr	*fattr; /* Post-op attributes */
 	__u64			tbytes;	/* total size in bytes */
 	__u64			fbytes;	/* # of free bytes */
 	__u64			abytes;	/* # of bytes available to user */
 	__u64			tfiles;	/* # of files */
 	__u64			ffiles;	/* # of free files */
 	__u64			afiles;	/* # of files available to user */
-	__u32			linkmax;/* max # of hard links */
-	__u32			namelen;/* max name length */
-	__u32			lease_time; /* in seconds */
+};
+
+struct nfs2_fsstat {
+	__u32			tsize;  /* Server transfer size */
+	__u32			bsize;  /* Filesystem block size */
+	__u32			blocks; /* No. of "bsize" blocks on filesystem */
+	__u32			bfree;  /* No. of free "bsize" blocks */
+	__u32			bavail; /* No. of available "bsize" blocks */
+};
+
+struct nfs_pathconf {
+	struct nfs_fattr	*fattr; /* Post-op attributes */
+	__u32			max_link; /* max # of hard links */
+	__u32			max_namelen; /* max name length */
 };
 
 /*
@@ -309,6 +325,219 @@
 	int			plus;
 };
 
+#ifdef CONFIG_NFS_V4
+
+typedef u64 clientid4;
+
+struct nfs4_change_info {
+	u32				atomic;
+	u64				before;
+	u64				after;
+};
+
+struct nfs4_access {
+	u32				ac_req_access;     /* request */
+	u32 *				ac_resp_supported; /* response */
+	u32 *				ac_resp_access;    /* response */
+};
+
+struct nfs4_close {
+	char *				cl_stateid;        /* request */
+	u32				cl_seqid;          /* request */
+};
+
+struct nfs4_commit {
+	u64				co_start;          /* request */
+	u32				co_len;            /* request */
+	struct nfs_writeverf *		co_verifier;       /* response */
+};
+
+struct nfs4_create {
+	u32				cr_ftype;          /* request */
+	union {                                            /* request */
+		struct {
+			u32		textlen;
+			const char *	text;
+		} symlink;   /* NF4LNK */
+		struct {
+			u32		specdata1;
+			u32		specdata2;
+		} device;    /* NF4BLK, NF4CHR */
+	} u;
+	u32				cr_namelen;        /* request */
+	const char *			cr_name;           /* request */
+	struct iattr *			cr_attrs;          /* request */
+	struct nfs4_change_info	*	cr_cinfo;          /* response */
+};
+#define cr_textlen			u.symlink.textlen
+#define cr_text				u.symlink.text
+#define cr_specdata1			u.device.specdata1
+#define cr_specdata2			u.device.specdata2
+
+struct nfs4_getattr {
+        u32 *				gt_bmval;          /* request */
+        struct nfs_fattr *		gt_attrs;          /* response */
+	struct nfs_fsstat *		gt_fsstat;         /* response */
+	struct nfs_fsinfo *		gt_fsinfo;         /* response */
+	struct nfs_pathconf *		gt_pathconf;       /* response */
+	u32 *				gt_bmres;	   /* response */
+};
+
+struct nfs4_getfh {
+	struct nfs_fh *			gf_fhandle;       /* response */
+};
+
+struct nfs4_link {
+	u32				ln_namelen;       /* request */
+	const char *			ln_name;          /* request */
+	struct nfs4_change_info *	ln_cinfo;         /* response */
+};
+
+struct nfs4_lookup {
+	struct qstr *			lo_name;          /* request */
+};
+
+struct nfs4_open {
+	u32				op_share_access;  /* request */
+	u32				op_opentype;      /* request */
+	u32				op_createmode;    /* request */
+	union {                                           /* request */
+		struct iattr *		attrs;    /* UNCHECKED, GUARDED */
+		nfs4_verifier		verifier; /* EXCLUSIVE */
+	} u;
+	struct qstr *			op_name;          /* request */
+	char *				op_stateid;       /* response */
+	struct nfs4_change_info	*	op_cinfo;         /* response */
+	u32 *				op_rflags;        /* response */
+};
+#define op_attrs     u.attrs
+#define op_verifier  u.verifier
+
+struct nfs4_open_confirm {
+	char *				oc_stateid;       /* request */
+};
+
+struct nfs4_putfh {
+	struct nfs_fh *			pf_fhandle;       /* request */
+};
+
+struct nfs4_read {
+	u64				rd_offset;        /* request */
+	u32				rd_length;        /* request */
+	u32				*rd_eof;          /* response */
+	u32				*rd_bytes_read;   /* response */
+	struct page **			rd_pages;   /* zero-copy data */
+	unsigned int			rd_pgbase;  /* zero-copy data */
+};
+
+struct nfs4_readdir {
+	u64				rd_cookie;        /* request */
+	nfs4_verifier			rd_req_verifier;  /* request */
+	u32				rd_count;         /* request */
+	u32				rd_bmval[2];      /* request */	
+	nfs4_verifier			rd_resp_verifier; /* response */
+	struct page **			rd_pages;   /* zero-copy data */
+	unsigned int			rd_pgbase;  /* zero-copy data */
+};
+
+struct nfs4_readlink {
+	u32				rl_count;   /* zero-copy data */
+	struct page **			rl_pages;   /* zero-copy data */
+};
+
+struct nfs4_remove {
+	u32				rm_namelen;       /* request */
+	const char *			rm_name;          /* request */
+	struct nfs4_change_info *	rm_cinfo;         /* response */
+};
+
+struct nfs4_rename {
+	u32				rn_oldnamelen;    /* request */
+	const char *			rn_oldname;       /* request */
+	u32				rn_newnamelen;    /* request */
+	const char *			rn_newname;       /* request */
+	struct nfs4_change_info	*	rn_src_cinfo;     /* response */
+	struct nfs4_change_info *	rn_dst_cinfo;     /* response */
+};
+
+struct nfs4_setattr {
+	char *				st_stateid;       /* request */
+	struct iattr *			st_iap;           /* request */
+};
+
+struct nfs4_setclientid {
+	nfs4_verifier			sc_verifier;      /* request */
+	char *				sc_name;	  /* request */
+	u32				sc_prog;          /* request */
+	char				sc_netid[4];	  /* request */
+	char				sc_uaddr[24];     /* request */
+	u32				sc_cb_ident;      /* request */
+};
+
+struct nfs4_write {
+	u64				wr_offset;        /* request */
+	u32				wr_stable_how;    /* request */
+	u32				wr_len;           /* request */
+	u32 *				wr_bytes_written; /* response */
+	struct nfs_writeverf *		wr_verf;          /* response */
+	struct page **			wr_pages;   /* zero-copy data */
+	unsigned int			wr_pgbase;  /* zero-copy data */
+};
+
+struct nfs4_op {
+	u32				opnum;
+	u32				nfserr;
+	union {
+		struct nfs4_access	access;
+		struct nfs4_close	close;
+		struct nfs4_commit	commit;
+		struct nfs4_create	create;
+		struct nfs4_getattr	getattr;
+		struct nfs4_getfh	getfh;
+		struct nfs4_link	link;
+		struct nfs4_lookup	lookup;
+		struct nfs4_open	open;
+		struct nfs4_open_confirm open_confirm;
+		struct nfs4_putfh	putfh;
+		struct nfs4_read	read;
+		struct nfs4_readdir	readdir;
+		struct nfs4_readlink	readlink;
+		struct nfs4_remove	remove;
+		struct nfs4_rename	rename;
+		struct nfs4_setattr	setattr;
+		struct nfs4_setclientid	setclientid;
+		struct nfs4_write	write;
+	} u;
+};
+
+struct nfs4_compound {
+	unsigned int		flags;   /* defined below */
+	struct nfs_server *	server;
+
+	/* RENEW information */
+	int			renew_index;
+	unsigned long		timestamp;
+
+	/* scratch variables for XDR encode/decode */
+	int			nops;
+	u32 *			p;
+	u32 *			end;
+
+	/* the individual COMPOUND operations */
+	struct nfs4_op		*ops;
+
+	/* request */
+	int			req_nops;
+	u32			taglen;
+	char *			tag;
+	
+	/* response */
+	int			resp_nops;
+	int			toplevel_status;
+};
+
+#endif /* CONFIG_NFS_V4 */
+
 struct nfs_read_data {
 	struct rpc_task		task;
 	struct inode		*inode;
@@ -322,7 +551,12 @@
 			struct nfs_readres  res;
 		} v3;   /* also v2 */
 #ifdef CONFIG_NFS_V4
-		/* NFSv4 data will come here... */
+		struct {
+			struct nfs4_compound  compound;
+			struct nfs4_op        ops[3];
+			u32                   res_count;
+			u32                   res_eof;
+		} v4;
 #endif
 	} u;
 };
@@ -337,11 +571,17 @@
 	struct page		*pagevec[NFS_WRITE_MAXIOV];
 	union {
 		struct {
-			struct nfs_writeargs args;
-			struct nfs_writeres  res;
+			struct nfs_writeargs	args;		/* argument struct */
+			struct nfs_writeres	res;		/* result struct */
 		} v3;
 #ifdef CONFIG_NFS_V4
-		/* NFSv4 data to come here... */
+		struct {
+			struct nfs4_compound  compound;
+			struct nfs4_op        ops[3];
+			u32                   arg_count;
+			u32                   arg_stable;
+			u32                   res_count;
+		} v4;
 #endif
 	} u;
 };
@@ -391,7 +631,11 @@
 	int	(*mknod)   (struct inode *, struct qstr *, struct iattr *,
 			    dev_t, struct nfs_fh *, struct nfs_fattr *);
 	int	(*statfs)  (struct nfs_server *, struct nfs_fh *,
+			    struct nfs_fsstat *);
+	int	(*fsinfo)  (struct nfs_server *, struct nfs_fh *,
 			    struct nfs_fsinfo *);
+	int	(*pathconf) (struct nfs_server *, struct nfs_fh *,
+			     struct nfs_pathconf *);
 	u32 *	(*decode_dirent)(u32 *, struct nfs_entry *, int plus);
 	void	(*read_setup)   (struct nfs_read_data *, unsigned int count);
 	void	(*write_setup)  (struct nfs_write_data *, unsigned int count, int how);
@@ -410,8 +654,10 @@
  */
 extern struct nfs_rpc_ops	nfs_v2_clientops;
 extern struct nfs_rpc_ops	nfs_v3_clientops;
+extern struct nfs_rpc_ops	nfs_v4_clientops;
 extern struct rpc_version	nfs_version2;
 extern struct rpc_version	nfs_version3;
+extern struct rpc_version	nfs_version4;
 extern struct rpc_program	nfs_program;
 extern struct rpc_stat		nfs_rpcstat;
 
diff -Nru a/include/linux/oprofile.h b/include/linux/oprofile.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/oprofile.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,98 @@
+/**
+ * @file oprofile.h
+ *
+ * API for machine-specific interrupts to interface
+ * to oprofile.
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef OPROFILE_H
+#define OPROFILE_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+ 
+struct super_block;
+struct dentry;
+struct file_operations;
+ 
+enum oprofile_cpu {
+	OPROFILE_CPU_PPRO,
+	OPROFILE_CPU_PII,
+	OPROFILE_CPU_PIII,
+	OPROFILE_CPU_ATHLON,
+	OPROFILE_CPU_TIMER
+};
+
+/* Operations structure to be filled in */
+struct oprofile_operations {
+	/* create any necessary configuration files in the oprofile fs.
+	 * Optional. */
+	int (*create_files)(struct super_block * sb, struct dentry * root);
+	/* Do any necessary interrupt setup. Optional. */
+	int (*setup)(void);
+	/* Do any necessary interrupt shutdown. Optional. */
+	void (*shutdown)(void);
+	/* Start delivering interrupts. */
+	int (*start)(void);
+	/* Stop delivering interrupts. */
+	void (*stop)(void);
+};
+
+/**
+ * One-time initialisation. *ops must be set to a filled-in
+ * operations structure. oprofile_cpu_type must be set.
+ * Return 0 on success.
+ */
+int oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
+ 
+/**
+ * Add a sample. This may be called from any context. Pass
+ * smp_processor_id() as cpu.
+ */
+extern void FASTCALL(oprofile_add_sample(unsigned long eip, unsigned long event, int cpu));
+
+/**
+ * Create a file of the given name as a child of the given root, with
+ * the specified file operations.
+ */
+int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
+	char const * name, struct file_operations * fops);
+ 
+/** Create a file for read/write access to an unsigned long. */
+int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
+	char const * name, ulong * val);
+ 
+/** Create a file for read-only access to an unsigned long. */
+int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
+	char const * name, ulong * val);
+ 
+/** Create a file for read-only access to an atomic_t. */
+int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
+	char const * name, atomic_t * val);
+ 
+/** create a directory */
+struct dentry * oprofilefs_mkdir(struct super_block * sb, struct dentry * root,
+	char const * name);
+
+/**
+ * Convert an unsigned long value into ASCII and copy it to the user buffer @buf,
+ * updating *offset appropriately. Returns bytes written or -EFAULT.
+ */
+ssize_t oprofilefs_ulong_to_user(unsigned long * val, char * buf, size_t count, loff_t * offset);
+
+/**
+ * Read an ASCII string for a number from a userspace buffer and fill *val on success.
+ * Returns 0 on success, < 0 on error.
+ */
+int oprofilefs_ulong_from_user(unsigned long * val, char const * buf, size_t count);
+
+/** lock for read/write safety */
+extern spinlock_t oprofilefs_lock;
+ 
+#endif /* OPROFILE_H */
diff -Nru a/include/linux/profile.h b/include/linux/profile.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/profile.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,67 @@
+#ifndef _LINUX_PROFILE_H
+#define _LINUX_PROFILE_H
+
+#ifdef __KERNEL__
+ 
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/errno.h>
+ 
+/* parse command line */
+int __init profile_setup(char * str);
+ 
+/* init basic kernel profiler */
+void __init profile_init(void);
+
+extern unsigned int * prof_buffer;
+extern unsigned long prof_len;
+extern unsigned long prof_shift;
+
+
+enum profile_type {
+	EXIT_TASK,
+	EXIT_MMAP,
+	EXEC_UNMAP
+};
+
+#ifdef CONFIG_PROFILING
+ 
+struct notifier_block;
+struct task_struct;
+struct mm_struct;
+ 
+/* task is in do_exit() */
+void profile_exit_task(struct task_struct * task);
+ 
+/* change of vma mappings */
+void profile_exec_unmap(struct mm_struct * mm);
+
+/* exit of all vmas for a task */
+void profile_exit_mmap(struct mm_struct * mm);
+
+int profile_event_register(enum profile_type, struct notifier_block * n);
+
+int profile_event_unregister(enum profile_type, struct notifier_block * n);
+ 
+#else
+
+static inline int profile_event_register(enum profile_type t, struct notifier_block * n)
+{
+	return -ENOSYS;
+}
+ 
+static inline int profile_event_unregister(enum profile_type t, struct notifier_block * n)
+{
+	return -ENOSYS;
+}
+ 
+#define profile_exit_task(a) do { } while (0)
+#define profile_exec_unmap(a) do { } while (0)
+#define profile_exit_mmap(a) do { } while (0)
+ 
+#endif /* CONFIG_PROFILING */
+ 
+#endif /* __KERNEL__ */
+ 
+#endif /* _LINUX_PROFILE_H */
diff -Nru a/include/linux/rcupdate.h b/include/linux/rcupdate.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/rcupdate.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,134 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (c) IBM Corporation, 2001
+ *
+ * Author: Dipankar Sarma <dipankar@in.ibm.com>
+ * 
+ * Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ * Papers:
+ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
+ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * 		http://lse.sourceforge.net/locking/rcupdate.html
+ *
+ */
+
+#ifndef __LINUX_RCUPDATE_H
+#define __LINUX_RCUPDATE_H
+
+#ifdef __KERNEL__
+
+#include <linux/cache.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+
+/**
+ * struct rcu_head - callback structure for use with RCU
+ * @list: list_head to queue the update requests
+ * @func: actual update function to call after the grace period.
+ * @arg: argument to be passed to the actual update function.
+ */
+struct rcu_head {
+	struct list_head list;
+	void (*func)(void *obj);
+	void *arg;
+};
+
+#define RCU_HEAD_INIT(head) \
+		{ list: LIST_HEAD_INIT(head.list), func: NULL, arg: NULL }
+#define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT(head)
+#define INIT_RCU_HEAD(ptr) do { \
+       INIT_LIST_HEAD(&(ptr)->list); (ptr)->func = NULL; (ptr)->arg = NULL; \
+} while (0)
+
+
+
+/* Control variables for rcupdate callback mechanism. */
+struct rcu_ctrlblk {
+	spinlock_t	mutex;		/* Guard this struct                  */
+	long		curbatch;	/* Current batch number.	      */
+	long		maxbatch;	/* Max requested batch number.        */
+	unsigned long	rcu_cpu_mask; 	/* CPUs that need to switch in order  */
+					/* for current batch to proceed.      */
+};
+
+/* Is batch a before batch b ? */
+static inline int rcu_batch_before(long a, long b)
+{
+        return (a - b) < 0;
+}
+
+/* Is batch a after batch b ? */
+static inline int rcu_batch_after(long a, long b)
+{
+        return (a - b) > 0;
+}
+
+/*
+ * Per-CPU data for Read-Copy UPdate.
+ * nxtlist - new callbacks are added here
+ * curlist - current batch for which quiescent cycle started if any
+ */
+struct rcu_data {
+	long		qsctr;		 /* User-mode/idle loop etc. */
+        long            last_qsctr;	 /* value of qsctr at beginning */
+                                         /* of rcu grace period */
+        long  	       	batch;           /* Batch # for current RCU batch */
+        struct list_head  nxtlist;
+        struct list_head  curlist;
+} ____cacheline_aligned_in_smp;
+
+extern struct rcu_data rcu_data[NR_CPUS];
+extern struct rcu_ctrlblk rcu_ctrlblk;
+
+#define RCU_qsctr(cpu) 		(rcu_data[(cpu)].qsctr)
+#define RCU_last_qsctr(cpu) 	(rcu_data[(cpu)].last_qsctr)
+#define RCU_batch(cpu) 		(rcu_data[(cpu)].batch)
+#define RCU_nxtlist(cpu) 	(rcu_data[(cpu)].nxtlist)
+#define RCU_curlist(cpu) 	(rcu_data[(cpu)].curlist)
+
+#define RCU_QSCTR_INVALID	0
+
+static inline int rcu_pending(int cpu) 
+{
+	if ((!list_empty(&RCU_curlist(cpu)) &&
+	     rcu_batch_before(RCU_batch(cpu), rcu_ctrlblk.curbatch)) ||
+	    (list_empty(&RCU_curlist(cpu)) &&
+			 !list_empty(&RCU_nxtlist(cpu))) ||
+	    test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask))
+		return 1;
+	else
+		return 0;
+}
+
+#define rcu_read_lock()		preempt_disable()
+#define rcu_read_unlock()	preempt_enable()
+
+extern void rcu_init(void);
+extern void rcu_check_callbacks(int cpu, int user);
+
+/* Exported interfaces */
+extern void FASTCALL(call_rcu(struct rcu_head *head, 
+                          void (*func)(void *arg), void *arg));
+extern void synchronize_kernel(void);
+
+#endif /* __KERNEL__ */
+#endif /* __LINUX_RCUPDATE_H */
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Tue Oct 15 20:29:12 2002
+++ b/include/linux/sched.h	Tue Oct 15 20:29:12 2002
@@ -492,10 +492,6 @@
 extern unsigned long itimer_next;
 extern void do_timer(struct pt_regs *);
 
-extern unsigned int * prof_buffer;
-extern unsigned long prof_len;
-extern unsigned long prof_shift;
-
 extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr));
 extern void FASTCALL(__wake_up_locked(wait_queue_head_t *q, unsigned int mode));
 extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr));
diff -Nru a/include/linux/suspend.h b/include/linux/suspend.h
--- a/include/linux/suspend.h	Tue Oct 15 20:29:14 2002
+++ b/include/linux/suspend.h	Tue Oct 15 20:29:14 2002
@@ -43,8 +43,6 @@
 
 #define SUSPEND_PD_PAGES(x)     (((x)*sizeof(struct pbe))/PAGE_SIZE+1)
    
-extern struct work_struct suspend_tq;
-
 /* mm/vmscan.c */
 extern int shrink_mem(void);
 
diff -Nru a/include/linux/swap.h b/include/linux/swap.h
--- a/include/linux/swap.h	Tue Oct 15 20:29:11 2002
+++ b/include/linux/swap.h	Tue Oct 15 20:29:11 2002
@@ -163,6 +163,8 @@
 
 /* linux/mm/vmscan.c */
 extern int try_to_free_pages(struct zone *, unsigned int, unsigned int);
+int shrink_all_memory(int nr_pages);
+extern int vm_swappiness;
 
 /* linux/mm/page_io.c */
 int swap_readpage(struct file *file, struct page *page);
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Tue Oct 15 20:29:11 2002
+++ b/include/linux/sysctl.h	Tue Oct 15 20:29:11 2002
@@ -128,6 +128,7 @@
 	KERN_TAINTED=53,	/* int: various kernel tainted flags */
 	KERN_CADPID=54,		/* int: PID of the process to notify on CAD */
 	KERN_PIDMAX=55,		/* int: PID # limit */
+  	KERN_CORE_PATTERN=56,	/* string: pattern for core-file names */
 };
 
 
@@ -145,13 +146,14 @@
 	VM_UNUSED9=9,		/* was: struct: Set page table cache parameters */
 	VM_PAGE_CLUSTER=10,	/* int: set number of pages to swap together */
 	VM_DIRTY_BACKGROUND=11,	/* dirty_background_ratio */
-	VM_DIRTY_ASYNC=12,	/* dirty_async_ratio */
+	VM_DIRTY_RATIO=12,	/* dirty_ratio */
 	VM_DIRTY_WB_CS=13,	/* dirty_writeback_centisecs */
 	VM_DIRTY_EXPIRE_CS=14,	/* dirty_expire_centisecs */
 	VM_NR_PDFLUSH_THREADS=15, /* nr_pdflush_threads */
 	VM_OVERCOMMIT_RATIO=16, /* percent of RAM to allow overcommit in */
 	VM_PAGEBUF=17,		/* struct: Control pagebuf parameters */
 	VM_HUGETLB_PAGES=18,	/* int: Number of available Huge Pages */
+	VM_SWAPPINESS=19,	/* Tendency to steal mapped memory */
 };
 
 
@@ -301,7 +303,8 @@
 	NET_IPV4_NONLOCAL_BIND=88,
 	NET_IPV4_ICMP_RATELIMIT=89,
 	NET_IPV4_ICMP_RATEMASK=90,
-	NET_TCP_TW_REUSE=91
+	NET_TCP_TW_REUSE=91,
+	NET_TCP_FRTO=92
 };
 
 enum {
diff -Nru a/include/linux/tcp.h b/include/linux/tcp.h
--- a/include/linux/tcp.h	Tue Oct 15 20:29:17 2002
+++ b/include/linux/tcp.h	Tue Oct 15 20:29:17 2002
@@ -366,6 +366,9 @@
 	unsigned int		keepalive_intvl;  /* time interval between keep alive probes */
 	int			linger2;
 
+	int                     frto_counter; /* Number of new acks after RTO */
+	__u32                   frto_highmark; /* snd_nxt when RTO occurred */
+
 	unsigned long last_synq_overflow; 
 };
 
diff -Nru a/include/linux/tty_driver.h b/include/linux/tty_driver.h
--- a/include/linux/tty_driver.h	Tue Oct 15 20:29:17 2002
+++ b/include/linux/tty_driver.h	Tue Oct 15 20:29:17 2002
@@ -116,6 +116,7 @@
  */
 
 #include <linux/fs.h>
+#include <linux/list.h>
 
 struct tty_driver {
 	int	magic;		/* magic number for this structure */
@@ -170,13 +171,10 @@
 			  int count, int *eof, void *data);
 	int (*write_proc)(struct file *file, const char *buffer,
 			  unsigned long count, void *data);
-
-	/*
-	 * linked list pointers
-	 */
-	struct tty_driver *next;
-	struct tty_driver *prev;
+	struct list_head tty_drivers;
 };
+
+extern struct list_head tty_drivers;
 
 /* tty driver magic number */
 #define TTY_DRIVER_MAGIC		0x5402
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Tue Oct 15 20:29:16 2002
+++ b/include/linux/usb.h	Tue Oct 15 20:29:16 2002
@@ -222,12 +222,42 @@
 	int extralen;
 };
 
+/**
+ * struct usb_interface - what usb device drivers talk to
+ * @altsetting: array of interface descriptors, one for each alternate
+ * 	setting that may be selected.  each one includes a set of
+ * 	endpoint configurations.
+ * @num_altsetting: number of altsettings defined.
+ * @act_altsetting: index of current altsetting.  this number is always
+ *	less than num_altsetting.  after the device is configured, each
+ *	interface uses its default setting of zero.
+ * @dev: driver model's view of this device
+ *
+ * USB device drivers attach to interfaces on a physical device.  Each
+ * interface encapsulates a single high level function, such as feeding
+ * an audio stream to a speaker or reporting a change in a volume control.
+ * Many USB devices only have one interface.  The protocol used to talk to
+ * an interface's endpoints can be defined in a usb "class" specification,
+ * or by a product's vendor.  The (default) control endpoint is part of
+ * every interface, but is never listed among the interface's descriptors.
+ *
+ * The driver that is bound to the interface can use standard driver model
+ * calls such as dev_get_drvdata() on the dev member of this structure.
+ *
+ * Each interface may have alternate settings.  The initial configuration
+ * of a device sets the first of these, but the device driver can change
+ * that setting using usb_set_interface().  Alternate settings are often
+ * used to control the the use of periodic endpoints, such as by having
+ * different endpoints use different amounts of reserved USB bandwidth.
+ * All standards-conformant USB devices that use isochronous endpoints
+ * will use them in non-default settings.
+ */
 struct usb_interface {
 	struct usb_interface_descriptor *altsetting;
 
-	int act_altsetting;		/* active alternate setting */
-	int num_altsetting;		/* number of alternate settings */
-	int max_altsetting;		/* total memory allocated */
+	unsigned act_altsetting;	/* active alternate setting */
+	unsigned num_altsetting;	/* number of alternate settings */
+	unsigned max_altsetting;	/* total memory allocated */
 
 	struct usb_driver *driver;	/* driver */
 	struct device dev;		/* interface specific device info */
@@ -670,6 +700,7 @@
 
 extern int usb_device_probe(struct device *dev);
 extern int usb_device_remove(struct device *dev);
+extern int usb_disabled(void);
 
 /* -------------------------------------------------------------------------- */
 
diff -Nru a/include/linux/vcache.h b/include/linux/vcache.h
--- a/include/linux/vcache.h	Tue Oct 15 20:29:21 2002
+++ b/include/linux/vcache.h	Tue Oct 15 20:29:21 2002
@@ -18,7 +18,7 @@
 		struct mm_struct *mm,
 		void (*callback)(struct vcache_s *data, struct page *new_page));
 
-extern void detach_vcache(vcache_t *vcache);
+extern void __detach_vcache(vcache_t *vcache);
 
 extern void invalidate_vcache(unsigned long address, struct mm_struct *mm,
 				struct page *new_page);
diff -Nru a/include/linux/videodev.h b/include/linux/videodev.h
--- a/include/linux/videodev.h	Tue Oct 15 20:29:23 2002
+++ b/include/linux/videodev.h	Tue Oct 15 20:29:23 2002
@@ -397,6 +397,7 @@
 #define VID_HARDWARE_PWC	31	/* Philips webcams */
 #define VID_HARDWARE_MEYE	32	/* Sony Vaio MotionEye cameras */
 #define VID_HARDWARE_CPIA2	33
+#define VID_HARDWARE_VICAM	34
 
 #endif /* __LINUX_VIDEODEV_H */
 
diff -Nru a/include/linux/writeback.h b/include/linux/writeback.h
--- a/include/linux/writeback.h	Tue Oct 15 20:29:12 2002
+++ b/include/linux/writeback.h	Tue Oct 15 20:29:12 2002
@@ -67,7 +67,7 @@
 
 /* These 5 are exported to sysctl. */
 extern int dirty_background_ratio;
-extern int dirty_async_ratio;
+extern int vm_dirty_ratio;
 extern int dirty_writeback_centisecs;
 extern int dirty_expire_centisecs;
 
diff -Nru a/include/net/arp.h b/include/net/arp.h
--- a/include/net/arp.h	Tue Oct 15 20:29:13 2002
+++ b/include/net/arp.h	Tue Oct 15 20:29:13 2002
@@ -18,6 +18,7 @@
 extern int	arp_bind_neighbour(struct dst_entry *dst);
 extern int	arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir);
 extern void	arp_ifdown(struct net_device *dev);
+extern unsigned arp_state_to_flags(struct neighbour *neigh);
 
 extern struct neigh_ops arp_broken_ops;
 
diff -Nru a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
--- a/include/net/bluetooth/bluetooth.h	Tue Oct 15 20:29:16 2002
+++ b/include/net/bluetooth/bluetooth.h	Tue Oct 15 20:29:16 2002
@@ -40,11 +40,7 @@
 #endif
 
 /* Reserv for core and drivers use */
-#define BLUEZ_SKB_RESERVE       8
-
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
+#define BT_SKB_RESERVE       8
 
 #define BTPROTO_L2CAP   0
 #define BTPROTO_HCI     1
@@ -57,29 +53,12 @@
 #define SOL_SCO     17
 #define SOL_RFCOMM  18
 
-/* Debugging */
-#ifdef CONFIG_BLUEZ_DEBUG
-
-#define HCI_CORE_DEBUG		1
-#define HCI_SOCK_DEBUG		1
-#define HCI_UART_DEBUG		1
-#define HCI_USB_DEBUG		1
-//#define HCI_DATA_DUMP		1
-
-#define L2CAP_DEBUG		1
-#define SCO_DEBUG		1
-#define AF_BLUETOOTH_DEBUG	1
-
-#endif /* CONFIG_BLUEZ_DEBUG */
-
-extern void bluez_dump(char *pref, __u8 *buf, int count);
-
 #define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
 #define BT_DBG(fmt, arg...)  printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg)
 #define BT_ERR(fmt, arg...)  printk(KERN_ERR  "%s: " fmt "\n" , __FUNCTION__ , ## arg)
 
 #ifdef HCI_DATA_DUMP
-#define BT_DMP(buf, len)    bluez_dump(__FUNCTION__, buf, len)
+#define BT_DMP(buf, len)    bt_dump(__FUNCTION__, buf, len)
 #else
 #define BT_DMP(D...)
 #endif
@@ -127,9 +106,9 @@
 
 /* Common socket structures and functions */
 
-#define bluez_sk(__sk) ((struct bluez_sock *) __sk)
+#define bt_sk(__sk) ((struct bt_sock *) __sk)
 
-struct bluez_sock {
+struct bt_sock {
 	struct sock sk;
 	bdaddr_t    src;
 	bdaddr_t    dst;
@@ -137,48 +116,48 @@
 	struct sock *parent;
 };
 
-struct bluez_sock_list {
+struct bt_sock_list {
 	struct sock *head;
 	rwlock_t     lock;
 };
 
-int  bluez_sock_register(int proto, struct net_proto_family *ops);
-int  bluez_sock_unregister(int proto);
-struct sock *bluez_sock_alloc(struct socket *sock, int proto, int pi_size, int prio);
-void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
-void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
-int  bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
-uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
-int  bluez_sock_w4_connect(struct sock *sk, int flags);
+int  bt_sock_register(int proto, struct net_proto_family *ops);
+int  bt_sock_unregister(int proto);
+struct sock *bt_sock_alloc(struct socket *sock, int proto, int pi_size, int prio);
+void bt_sock_link(struct bt_sock_list *l, struct sock *s);
+void bt_sock_unlink(struct bt_sock_list *l, struct sock *s);
+int  bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
+uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
+int  bt_sock_w4_connect(struct sock *sk, int flags);
 
-void bluez_accept_enqueue(struct sock *parent, struct sock *sk);
-struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock);
+void bt_accept_enqueue(struct sock *parent, struct sock *sk);
+struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
 
 /* Skb helpers */
-struct bluez_skb_cb {
-	int    incomming;
+struct bt_skb_cb {
+	int    incoming;
 };
-#define bluez_cb(skb)	((struct bluez_skb_cb *)(skb->cb)) 
+#define bt_cb(skb) ((struct bt_skb_cb *)(skb->cb)) 
 
-static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
+static inline struct sk_buff *bt_skb_alloc(unsigned int len, int how)
 {
 	struct sk_buff *skb;
 
-	if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
-		skb_reserve(skb, BLUEZ_SKB_RESERVE);
-		bluez_cb(skb)->incomming  = 0;
+	if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) {
+		skb_reserve(skb, BT_SKB_RESERVE);
+		bt_cb(skb)->incoming  = 0;
 	}
 	return skb;
 }
 
-static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, 
+static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, unsigned long len, 
 						       int nb, int *err)
 {
 	struct sk_buff *skb;
 
-	if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
-		skb_reserve(skb, BLUEZ_SKB_RESERVE);
-		bluez_cb(skb)->incomming  = 0;
+	if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
+		skb_reserve(skb, BT_SKB_RESERVE);
+		bt_cb(skb)->incoming  = 0;
 	}
 
 	return skb;
@@ -193,11 +172,8 @@
 	return n;
 }
 
-int hci_core_init(void);
-int hci_core_cleanup(void);
-int hci_sock_init(void);
-int hci_sock_cleanup(void);
+void bt_dump(char *pref, __u8 *buf, int count);
 
-int bterr(__u16 code);
+int  bt_err(__u16 code);
 
 #endif /* __BLUETOOTH_H */
diff -Nru a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
--- a/include/net/bluetooth/hci.h	Tue Oct 15 20:29:21 2002
+++ b/include/net/bluetooth/hci.h	Tue Oct 15 20:29:21 2002
@@ -39,6 +39,8 @@
 #define HCI_DEV_UNREG   2
 #define HCI_DEV_UP	3
 #define HCI_DEV_DOWN	4
+#define HCI_DEV_SUSPEND 5
+#define HCI_DEV_RESUME  6
 
 /* HCI device types */
 #define HCI_VHCI	0
@@ -582,7 +584,7 @@
 } __attribute__ ((packed)) evt_read_remote_version_complete;
 #define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
 
-/* Internal events generated by BlueZ stack */
+/* Internal events generated by Bluetooth stack */
 #define EVT_STACK_INTERNAL	0xfd
 typedef struct {
 	__u16   type;
diff -Nru a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
--- a/include/net/bluetooth/hci_core.h	Tue Oct 15 20:29:17 2002
+++ b/include/net/bluetooth/hci_core.h	Tue Oct 15 20:29:17 2002
@@ -302,6 +302,8 @@
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 int hci_register_dev(struct hci_dev *hdev);
 int hci_unregister_dev(struct hci_dev *hdev);
+int hci_suspend_dev(struct hci_dev *hdev);
+int hci_resume_dev(struct hci_dev *hdev);
 int hci_dev_open(__u16 dev);
 int hci_dev_close(__u16 dev);
 int hci_dev_reset(__u16 dev);
diff -Nru a/include/net/flow.h b/include/net/flow.h
--- a/include/net/flow.h	Tue Oct 15 20:29:21 2002
+++ b/include/net/flow.h	Tue Oct 15 20:29:21 2002
@@ -1,6 +1,6 @@
 /*
  *
- *	Flow based forwarding rules (usage: firewalling, etc)
+ *	Generic internet FLOW.
  *
  */
 
@@ -8,12 +8,16 @@
 #define _NET_FLOW_H
 
 struct flowi {
-	int	proto;		/*	{TCP, UDP, ICMP}	*/
+	int	oif;
+	int	iif;
 
 	union {
 		struct {
 			__u32			daddr;
 			__u32			saddr;
+			__u32			fwmark;
+			__u8			tos;
+			__u8			scope;
 		} ip4_u;
 		
 		struct {
@@ -27,9 +31,12 @@
 #define fl6_flowlabel	nl_u.ip6_u.flowlabel
 #define fl4_dst		nl_u.ip4_u.daddr
 #define fl4_src		nl_u.ip4_u.saddr
+#define fl4_fwmark	nl_u.ip4_u.fwmark
+#define fl4_tos		nl_u.ip4_u.tos
+#define fl4_scope	nl_u.ip4_u.scope
 
-	int	oif;
-
+	__u8	proto;
+	__u8	flags;
 	union {
 		struct {
 			__u16	sport;
@@ -41,61 +48,8 @@
 			__u8	code;
 		} icmpt;
 
-		unsigned long	data;
+		__u32		spi;
 	} uli_u;
-};
-
-#define FLOWR_NODECISION	0	/* rule not appliable to flow	*/
-#define FLOWR_SELECT		1	/* flow must follow this rule	*/
-#define FLOWR_CLEAR		2	/* priority level clears flow	*/
-#define FLOWR_ERROR		3
-
-struct fl_acc_args {
-	int	type;
-
-
-#define FL_ARG_FORWARD	1
-#define FL_ARG_ORIGIN	2
-
-	union {
-		struct sk_buff		*skb;
-		struct {
-			struct sock	*sk;
-			struct flowi	*flow;
-		} fl_o;
-	} fl_u;
-};
-
-
-struct pkt_filter {
-	atomic_t		refcnt;
-	unsigned int		offset;
-	__u32			value;
-	__u32			mask;
-	struct pkt_filter	*next;
-};
-
-#define FLR_INPUT		1
-#define FLR_OUTPUT		2
-
-struct flow_filter {
-	int				type;
-	union {
-		struct pkt_filter	*filter;
-		struct sock		*sk;
-	} u;
-};
-
-struct flow_rule {
-	struct flow_rule_ops		*ops;
-	unsigned char			private[0];
-};
-
-struct flow_rule_ops {
-	int			(*accept)(struct rt6_info *rt,
-					  struct rt6_info *rule,
-					  struct fl_acc_args *args,
-					  struct rt6_info **nrt);
 };
 
 #endif
diff -Nru a/include/net/inet_common.h b/include/net/inet_common.h
--- a/include/net/inet_common.h	Tue Oct 15 20:29:19 2002
+++ b/include/net/inet_common.h	Tue Oct 15 20:29:19 2002
@@ -20,10 +20,12 @@
 						   int addr_len, int flags);
 extern int			inet_accept(struct socket *sock, 
 					    struct socket *newsock, int flags);
-extern int			inet_recvmsg(struct socket *sock, 
+extern int			inet_recvmsg(struct kiocb *iocb,
+					     struct socket *sock, 
 					     struct msghdr *ubuf, 
 					     int size, int flags, struct scm_cookie *scm);
-extern int			inet_sendmsg(struct socket *sock, 
+extern int			inet_sendmsg(struct kiocb *iocb,
+					     struct socket *sock, 
 					     struct msghdr *msg, 
 					     int size, struct scm_cookie *scm);
 extern int			inet_shutdown(struct socket *sock, int how);
diff -Nru a/include/net/ip.h b/include/net/ip.h
--- a/include/net/ip.h	Tue Oct 15 20:29:19 2002
+++ b/include/net/ip.h	Tue Oct 15 20:29:19 2002
@@ -174,7 +174,7 @@
 int ip_decrease_ttl(struct iphdr *iph)
 {
 	u32 check = iph->check;
-	check += __constant_htons(0x0100);
+	check += htons(0x0100);
 	iph->check = check + (check>=0xFFFF);
 	return --iph->ttl;
 }
@@ -191,7 +191,7 @@
 
 static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk)
 {
-	if (iph->frag_off&__constant_htons(IP_DF)) {
+	if (iph->frag_off & htons(IP_DF)) {
 		/* This is only to work around buggy Windows95/2000
 		 * VJ compression implementations.  If the ID field
 		 * does not change, they drop every other packet in
@@ -205,7 +205,7 @@
 
 static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst, struct sock *sk, int more)
 {
-	if (iph->frag_off&__constant_htons(IP_DF)) {
+	if (iph->frag_off & htons(IP_DF)) {
 		if (sk && inet_sk(sk)->daddr) {
 			iph->id = htons(inet_sk(sk)->id);
 			inet_sk(sk)->id += 1 + more;
@@ -279,5 +279,7 @@
 			      u16 port, u32 info, u8 *payload);
 extern void	ip_local_error(struct sock *sk, int err, u32 daddr, u16 dport,
 			       u32 info);
+
+extern int ipv4_proc_init(void);
 
 #endif	/* _IP_H */
diff -Nru a/include/net/ip6_fib.h b/include/net/ip6_fib.h
--- a/include/net/ip6_fib.h	Tue Oct 15 20:29:19 2002
+++ b/include/net/ip6_fib.h	Tue Oct 15 20:29:19 2002
@@ -70,14 +70,6 @@
 	u8				rt6i_hoplimit;
 	atomic_t			rt6i_ref;
 
-	union {
-		struct flow_rule	*rt6iu_flowr;
-		struct flow_filter	*rt6iu_filter;
-	} flow_u;
-
-#define rt6i_flowr			flow_u.rt6iu_flowr
-#define rt6i_filter			flow_u.rt6iu_filter
-
 	struct rt6key			rt6i_dst;
 	struct rt6key			rt6i_src;
 };
diff -Nru a/include/net/ip6_fw.h b/include/net/ip6_fw.h
--- a/include/net/ip6_fw.h	Tue Oct 15 20:29:16 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,54 +0,0 @@
-#ifndef __NET_IP6_FW_H
-#define __NET_IP6_FW_H
-
-#define IP6_FW_LISTHEAD		0x1000
-#define IP6_FW_ACCEPT		0x0001
-#define IP6_FW_REJECT		0x0002
-
-#define IP6_FW_DEBUG	2
-
-#define IP6_FW_MSG_ADD		1
-#define IP6_FW_MSG_DEL		2
-#define IP6_FW_MSG_REPORT	3
-
-
-/*
- *	Fast "hack" user interface
- */
-struct ip6_fw_msg {
-	struct in6_addr		dst;
-	struct in6_addr		src;
-	int			dst_len;
-	int			src_len;
-	int			action;
-	int			policy;
-	int			proto;
-	union {
-		struct {
-			__u16	sport;
-			__u16	dport;
-		} transp;
-
-		unsigned long	data;
-
-		int		icmp_type;
-	} u;
-
-	int			msg_len;
-};
-
-#ifdef __KERNEL__
-
-#include <net/flow.h>
-
-struct ip6_fw_rule {
-	struct flow_rule	flowr;
-	struct ip6_fw_rule	*next;
-	struct ip6_fw_rule	*prev;
-	struct flowi		info;
-	unsigned long		policy;
-};
-
-#endif
-
-#endif
diff -Nru a/include/net/ip_fib.h b/include/net/ip_fib.h
--- a/include/net/ip_fib.h	Tue Oct 15 20:29:21 2002
+++ b/include/net/ip_fib.h	Tue Oct 15 20:29:21 2002
@@ -17,6 +17,8 @@
 #define _NET_IP_FIB_H
 
 #include <linux/config.h>
+#include <net/flow.h>
+#include <linux/seq_file.h>
 
 struct kern_rta
 {
@@ -117,7 +119,7 @@
 {
 	unsigned char	tb_id;
 	unsigned	tb_stamp;
-	int		(*tb_lookup)(struct fib_table *tb, const struct rt_key *key, struct fib_result *res);
+	int		(*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
 	int		(*tb_insert)(struct fib_table *table, struct rtmsg *r,
 				     struct kern_rta *rta, struct nlmsghdr *n,
 				     struct netlink_skb_parms *req);
@@ -127,24 +129,23 @@
 	int		(*tb_dump)(struct fib_table *table, struct sk_buff *skb,
 				     struct netlink_callback *cb);
 	int		(*tb_flush)(struct fib_table *table);
-	int		(*tb_get_info)(struct fib_table *table, char *buf,
-				       int first, int count);
+	int		(*tb_seq_show)(struct fib_table *table, struct seq_file *seq);
 	void		(*tb_select_default)(struct fib_table *table,
-					     const struct rt_key *key, struct fib_result *res);
+					     const struct flowi *flp, struct fib_result *res);
 
 	unsigned char	tb_data[0];
 };
 
 #ifndef CONFIG_IP_MULTIPLE_TABLES
 
-extern struct fib_table *local_table;
-extern struct fib_table *main_table;
+extern struct fib_table *ip_fib_local_table;
+extern struct fib_table *ip_fib_main_table;
 
 static inline struct fib_table *fib_get_table(int id)
 {
 	if (id != RT_TABLE_LOCAL)
-		return main_table;
-	return local_table;
+		return ip_fib_main_table;
+	return ip_fib_local_table;
 }
 
 static inline struct fib_table *fib_new_table(int id)
@@ -152,26 +153,26 @@
 	return fib_get_table(id);
 }
 
-static inline int fib_lookup(const struct rt_key *key, struct fib_result *res)
+static inline int fib_lookup(const struct flowi *flp, struct fib_result *res)
 {
-	if (local_table->tb_lookup(local_table, key, res) &&
-	    main_table->tb_lookup(main_table, key, res))
+	if (ip_fib_local_table->tb_lookup(ip_fib_local_table, flp, res) &&
+	    ip_fib_main_table->tb_lookup(ip_fib_main_table, flp, res))
 		return -ENETUNREACH;
 	return 0;
 }
 
-static inline void fib_select_default(const struct rt_key *key, struct fib_result *res)
+static inline void fib_select_default(const struct flowi *flp, struct fib_result *res)
 {
 	if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
-		main_table->tb_select_default(main_table, key, res);
+		ip_fib_main_table->tb_select_default(ip_fib_main_table, flp, res);
 }
 
 #else /* CONFIG_IP_MULTIPLE_TABLES */
-#define local_table (fib_tables[RT_TABLE_LOCAL])
-#define main_table (fib_tables[RT_TABLE_MAIN])
+#define ip_fib_local_table (fib_tables[RT_TABLE_LOCAL])
+#define ip_fib_main_table (fib_tables[RT_TABLE_MAIN])
 
 extern struct fib_table * fib_tables[RT_TABLE_MAX+1];
-extern int fib_lookup(const struct rt_key *key, struct fib_result *res);
+extern int fib_lookup(const struct flowi *flp, struct fib_result *res);
 extern struct fib_table *__fib_new_table(int id);
 extern void fib_rule_put(struct fib_rule *r);
 
@@ -191,7 +192,7 @@
 	return fib_tables[id] ? : __fib_new_table(id);
 }
 
-extern void fib_select_default(const struct rt_key *key, struct fib_result *res);
+extern void fib_select_default(const struct flowi *flp, struct fib_result *res);
 
 #endif /* CONFIG_IP_MULTIPLE_TABLES */
 
@@ -204,13 +205,13 @@
 extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
 extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
 			       struct net_device *dev, u32 *spec_dst, u32 *itag);
-extern void fib_select_multipath(const struct rt_key *key, struct fib_result *res);
+extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
 
 /* Exported by fib_semantics.c */
 extern int 		ip_fib_check_default(u32 gw, struct net_device *dev);
 extern void		fib_release_info(struct fib_info *);
 extern int		fib_semantic_match(int type, struct fib_info *,
-					   const struct rt_key *, struct fib_result*);
+					   const struct flowi *, struct fib_result*);
 extern struct fib_info	*fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
 					 const struct nlmsghdr *, int *err);
 extern int fib_nh_match(struct rtmsg *r, struct nlmsghdr *, struct kern_rta *rta, struct fib_info *fi);
@@ -221,7 +222,8 @@
 extern int fib_sync_up(struct net_device *dev);
 extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
 			       struct kern_rta *rta, struct rtentry *r);
-extern void fib_node_get_info(int type, int dead, struct fib_info *fi, u32 prefix, u32 mask, char *buffer);
+extern void fib_node_seq_show(struct seq_file *seq, int type, int dead,
+			      struct fib_info *fi, u32 prefix, u32 mask);
 extern u32  __fib_res_prefsrc(struct fib_result *res);
 
 /* Exported by fib_hash.c */
diff -Nru a/include/net/route.h b/include/net/route.h
--- a/include/net/route.h	Tue Oct 15 20:29:11 2002
+++ b/include/net/route.h	Tue Oct 15 20:29:11 2002
@@ -27,6 +27,7 @@
 #include <linux/config.h>
 #include <net/dst.h>
 #include <net/inetpeer.h>
+#include <net/flow.h>
 #include <linux/in_route.h>
 #include <linux/rtnetlink.h>
 #include <linux/route.h>
@@ -45,19 +46,6 @@
 
 #define RT_CONN_FLAGS(sk)   (RT_TOS(inet_sk(sk)->tos) | sk->localroute)
 
-struct rt_key
-{
-	__u32			dst;
-	__u32			src;
-	int			iif;
-	int			oif;
-#ifdef CONFIG_IP_ROUTE_FWMARK
-	__u32			fwmark;
-#endif
-	__u8			tos;
-	__u8			scope;
-};
-
 struct inet_peer;
 struct rtable
 {
@@ -78,7 +66,7 @@
 	__u32			rt_gateway;
 
 	/* Cache lookup keys */
-	struct rt_key		key;
+	struct flowi		fl;
 
 	/* Miscellaneous cached information */
 	__u32			rt_spec_dst; /* RFC1122 specific destination */
@@ -124,7 +112,7 @@
 				       u32 src, u8 tos, struct net_device *dev);
 extern void		ip_rt_advice(struct rtable **rp, int advice);
 extern void		rt_cache_flush(int how);
-extern int		ip_route_output_key(struct rtable **, const struct rt_key *key);
+extern int		ip_route_output_key(struct rtable **, const struct flowi *flp);
 extern int		ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
 extern unsigned short	ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
 extern void		ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
@@ -136,16 +124,6 @@
 extern void		ip_rt_get_source(u8 *src, struct rtable *rt);
 extern int		ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb);
 
-/* Deprecated: use ip_route_output_key directly */
-static inline int ip_route_output(struct rtable **rp,
-				      u32 daddr, u32 saddr, u32 tos, int oif)
-{
-	struct rt_key key = { dst:daddr, src:saddr, oif:oif, tos:tos };
-
-	return ip_route_output_key(rp, &key);
-}
-
-
 static inline void ip_rt_put(struct rtable * rt)
 {
 	if (rt)
@@ -163,15 +141,20 @@
 
 static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif)
 {
+	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
+						 .saddr = src,
+						 .tos   = tos } },
+			    .oif = oif };
+
 	int err;
-	err = ip_route_output(rp, dst, src, tos, oif);
+	err = ip_route_output_key(rp, &fl);
 	if (err || (dst && src))
 		return err;
-	dst = (*rp)->rt_dst;
-	src = (*rp)->rt_src;
+	fl.fl4_dst = (*rp)->rt_dst;
+	fl.fl4_src = (*rp)->rt_src;
 	ip_rt_put(*rp);
 	*rp = NULL;
-	return ip_route_output(rp, dst, src, tos, oif);
+	return ip_route_output_key(rp, &fl);
 }
 
 extern void rt_bind_peer(struct rtable *rt, int create);
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Tue Oct 15 20:29:19 2002
+++ b/include/net/sock.h	Tue Oct 15 20:29:19 2002
@@ -51,6 +51,7 @@
 
 #include <asm/atomic.h>
 #include <net/dst.h>
+#include <net/scm.h>
 
 /*
  * This structure really needs to be cleaned up.
@@ -242,9 +243,10 @@
 	int			(*getsockopt)(struct sock *sk, int level, 
 					int optname, char *optval, 
 					int *option);  	 
-	int			(*sendmsg)(struct sock *sk, struct msghdr *msg,
-					   int len);
-	int			(*recvmsg)(struct sock *sk, struct msghdr *msg,
+	int			(*sendmsg)(struct kiocb *iocb, struct sock *sk,
+					   struct msghdr *msg, int len);
+	int			(*recvmsg)(struct kiocb *iocb, struct sock *sk,
+					   struct msghdr *msg,
 					int len, int noblock, int flags, 
 					int *addr_len);
 	int			(*bind)(struct sock *sk, 
@@ -292,7 +294,29 @@
 #define SOCK_BINDADDR_LOCK	4
 #define SOCK_BINDPORT_LOCK	8
 
+/* sock_iocb: used to kick off async processing of socket ios */
+struct sock_iocb {
+	struct list_head	list;
+
+	int			flags;
+	int			size;
+	struct socket		*sock;
+	struct sock		*sk;
+	struct msghdr		*msg, async_msg;
+	struct iovec		async_iov;
+	struct scm_cookie	*scm, async_scm;
+};
+
+static inline struct sock_iocb *kiocb_to_siocb(struct kiocb *iocb)
+{
+	BUG_ON(sizeof(struct sock_iocb) > KIOCB_PRIVATE_SIZE);
+	return (struct sock_iocb *)iocb->private;
+}
 
+static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si)
+{
+	return container_of((void *)si, struct kiocb, private);
+}
 
 /* Used by processes to "lock" a socket state, so that
  * interrupts and bottom half handlers won't change it
@@ -390,10 +414,10 @@
 						   char *, int *);
 extern int			sock_no_setsockopt(struct socket *, int, int,
 						   char *, int);
-extern int                      sock_no_sendmsg(struct socket *,
+extern int                      sock_no_sendmsg(struct kiocb *, struct socket *,
 						struct msghdr *, int,
 						struct scm_cookie *);
-extern int                      sock_no_recvmsg(struct socket *,
+extern int                      sock_no_recvmsg(struct kiocb *, struct socket *,
 						struct msghdr *, int, int,
 						struct scm_cookie *);
 extern int			sock_no_mmap(struct file *file,
diff -Nru a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h	Tue Oct 15 20:29:12 2002
+++ b/include/net/tcp.h	Tue Oct 15 20:29:12 2002
@@ -472,6 +472,7 @@
 extern int sysctl_tcp_app_win;
 extern int sysctl_tcp_adv_win_scale;
 extern int sysctl_tcp_tw_reuse;
+extern int sysctl_tcp_frto;
 
 extern atomic_t tcp_memory_allocated;
 extern atomic_t tcp_sockets_allocated;
@@ -648,7 +649,8 @@
 
 extern int		    	tcp_v4_tw_remember_stamp(struct tcp_tw_bucket *tw);
 
-extern int			tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size);
+extern int			tcp_sendmsg(struct kiocb *iocb, struct sock *sk,
+					    struct msghdr *msg, int size);
 extern ssize_t			tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags);
 
 extern int			tcp_ioctl(struct sock *sk, 
@@ -722,6 +724,7 @@
 extern int			tcp_child_process(struct sock *parent,
 						  struct sock *child,
 						  struct sk_buff *skb);
+extern void			tcp_enter_frto(struct sock *sk);
 extern void			tcp_enter_loss(struct sock *sk, int how);
 extern void			tcp_clear_retrans(struct tcp_opt *tp);
 extern void			tcp_update_metrics(struct sock *sk);
@@ -739,7 +742,7 @@
 					       int optname, char *optval, 
 					       int optlen);
 extern void			tcp_set_keepalive(struct sock *sk, int val);
-extern int			tcp_recvmsg(struct sock *sk, 
+extern int			tcp_recvmsg(struct kiocb *iocb, struct sock *sk,
 					    struct msghdr *msg,
 					    int len, int nonblock, 
 					    int flags, int *addr_len);
@@ -1854,5 +1857,18 @@
 }
 
 #define TCP_CHECK_TIMER(sk) do { } while (0)
+
+static inline int tcp_use_frto(const struct sock *sk)
+{
+	const struct tcp_opt *tp = tcp_sk(sk);
+	
+	/* F-RTO must be activated in sysctl and there must be some
+	 * unsent new data, and the advertised window should allow
+	 * sending it.
+	 */
+	return (sysctl_tcp_frto && tp->send_head &&
+		!after(TCP_SKB_CB(tp->send_head)->end_seq,
+		       tp->snd_una + tp->snd_wnd));
+}
 
 #endif	/* _TCP_H */
diff -Nru a/include/net/udp.h b/include/net/udp.h
--- a/include/net/udp.h	Tue Oct 15 20:29:20 2002
+++ b/include/net/udp.h	Tue Oct 15 20:29:20 2002
@@ -64,7 +64,8 @@
 extern int	udp_connect(struct sock *sk,
 			    struct sockaddr *usin, int addr_len);
 
-extern int	udp_sendmsg(struct sock *sk, struct msghdr *msg, int len);
+extern int	udp_sendmsg(struct kiocb *iocb, struct sock *sk,
+			    struct msghdr *msg, int len);
 
 extern int	udp_rcv(struct sk_buff *skb);
 extern int	udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
diff -Nru a/include/rxrpc/call.h b/include/rxrpc/call.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/call.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,218 @@
+/* call.h: Rx call record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_CALL_H
+#define _LINUX_RXRPC_CALL_H
+
+#include <rxrpc/types.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/packet.h>
+#include <linux/timer.h>
+
+#define RXRPC_CALL_ACK_WINDOW_SIZE	16
+
+extern unsigned rxrpc_call_rcv_timeout;		/* receive activity timeout (secs) */
+extern unsigned rxrpc_call_acks_timeout;	/* pending ACK (retransmit) timeout (secs) */
+extern unsigned rxrpc_call_dfr_ack_timeout;	/* deferred ACK timeout (secs) */
+extern unsigned short rxrpc_call_max_resend;		/* maximum consecutive resend count */
+
+/* application call state
+ * - only state 0 and ffff are reserved, the state is set to 1 after an opid is received
+ */
+enum rxrpc_app_cstate {
+	RXRPC_CSTATE_COMPLETE		= 0,	/* operation complete */
+	RXRPC_CSTATE_ERROR,			/* operation ICMP error or aborted */
+	RXRPC_CSTATE_SRVR_RCV_OPID,		/* [SERVER] receiving operation ID */
+	RXRPC_CSTATE_SRVR_RCV_ARGS,		/* [SERVER] receiving operation data */
+	RXRPC_CSTATE_SRVR_GOT_ARGS,		/* [SERVER] completely received operation data */
+	RXRPC_CSTATE_SRVR_SND_REPLY,		/* [SERVER] sending operation reply */
+	RXRPC_CSTATE_SRVR_RCV_FINAL_ACK,	/* [SERVER] receiving final ACK */
+	RXRPC_CSTATE_CLNT_SND_ARGS,		/* [CLIENT] sending operation args */
+	RXRPC_CSTATE_CLNT_RCV_REPLY,		/* [CLIENT] receiving operation reply */
+	RXRPC_CSTATE_CLNT_GOT_REPLY,		/* [CLIENT] completely received operation reply */
+} __attribute__((packed));
+
+extern const char *rxrpc_call_states[];
+
+enum rxrpc_app_estate {
+	RXRPC_ESTATE_NO_ERROR		= 0,	/* no error */
+	RXRPC_ESTATE_LOCAL_ABORT,		/* aborted locally by application layer */
+	RXRPC_ESTATE_PEER_ABORT,		/* aborted remotely by peer */
+	RXRPC_ESTATE_LOCAL_ERROR,		/* local ICMP network error */
+	RXRPC_ESTATE_REMOTE_ERROR,		/* remote ICMP network error */
+} __attribute__((packed));
+
+extern const char *rxrpc_call_error_states[];
+
+/*****************************************************************************/
+/*
+ * Rx call record and application scratch buffer
+ * - the call record occupies the bottom of a complete page
+ * - the application scratch buffer occupies the rest
+ */
+struct rxrpc_call
+{
+	atomic_t		usage;
+	struct rxrpc_connection	*conn;		/* connection upon which active */
+	spinlock_t		lock;		/* access lock */
+	struct module		*owner;		/* owner module */
+	wait_queue_head_t	waitq;		/* wait queue for events to happen */
+	struct list_head	link;		/* general internal list link */
+	struct list_head	call_link;	/* master call list link */
+	u32			chan_ix;	/* connection channel index (net order) */
+	u32			call_id;	/* call ID on connection (net order) */
+	unsigned long		cjif;		/* jiffies at call creation */
+	unsigned long		flags;		/* control flags */
+#define RXRPC_CALL_ACKS_TIMO	0x00000001	/* ACKS timeout reached */
+#define RXRPC_CALL_ACKR_TIMO	0x00000002	/* ACKR timeout reached */
+#define RXRPC_CALL_RCV_TIMO	0x00000004	/* RCV timeout reached */
+#define RXRPC_CALL_RCV_PKT	0x00000008	/* received packet */
+
+	/* transmission */
+	rxrpc_seq_t		snd_seq_count;	/* outgoing packet sequence number counter */
+	struct rxrpc_message	*snd_nextmsg;	/* next message being constructed for sending */
+	struct rxrpc_message	*snd_ping;	/* last ping message sent */
+	unsigned short		snd_resend_cnt;	/* count of resends since last ACK */
+
+	/* transmission ACK tracking */
+	struct list_head	acks_pendq;	/* messages pending ACK (ordered by seq) */
+	unsigned		acks_pend_cnt;	/* number of un-ACK'd packets */
+	rxrpc_seq_t		acks_dftv_seq;	/* highest definitively ACK'd msg seq */
+	struct timer_list	acks_timeout;	/* timeout on expected ACK */
+
+	/* reception */
+	struct list_head	rcv_receiveq;	/* messages pending reception (ordered by seq) */
+	struct list_head	rcv_krxiodq_lk;	/* krxiod queue for new inbound packets */
+	struct timer_list	rcv_timeout;	/* call receive activity timeout */
+
+	/* reception ACK'ing */
+	rxrpc_seq_t		ackr_win_bot;	/* bottom of ACK window */
+	rxrpc_seq_t		ackr_win_top;	/* top of ACK window */
+	rxrpc_seq_t		ackr_high_seq;	/* highest seqno yet received */
+	rxrpc_seq_t		ackr_prev_seq;	/* previous seqno received */
+	unsigned		ackr_pend_cnt;	/* number of pending ACKs */
+	struct timer_list	ackr_dfr_timo;	/* timeout on deferred ACK */
+	char			ackr_dfr_perm;	/* request for deferred ACKs permitted */
+	rxrpc_seq_t		ackr_dfr_seq;	/* seqno for deferred ACK */
+	struct rxrpc_ackpacket	ackr;		/* pending normal ACK packet */
+	u8			ackr_array[RXRPC_CALL_ACK_WINDOW_SIZE];	/* ACK records */
+
+	/* presentation layer */
+	char			app_last_rcv;	/* T if received last packet from remote end */
+	enum rxrpc_app_cstate	app_call_state;	/* call state */
+	enum rxrpc_app_estate	app_err_state;	/* abort/error state */
+	struct list_head	app_readyq;	/* ordered ready received packet queue */
+	struct list_head	app_unreadyq;	/* ordered post-hole recv'd packet queue */
+	rxrpc_seq_t		app_ready_seq;	/* last seq number dropped into readyq */
+	size_t			app_ready_qty;	/* amount of data ready in readyq */
+	unsigned		app_opcode;	/* operation ID */
+	unsigned		app_abort_code;	/* abort code (when aborted) */
+	int			app_errno;	/* error number (when ICMP error received) */
+
+	/* statisics */
+	unsigned		pkt_rcv_count;	/* count of received packets on this call */
+	unsigned		pkt_snd_count;	/* count of sent packets on this call */
+	unsigned		app_read_count;	/* number of reads issued */
+
+	/* bits for the application to use */
+	rxrpc_call_attn_func_t	app_attn_func;	/* callback when attention required */
+	rxrpc_call_error_func_t	app_error_func;	/* callback when abort sent (cleanup and put) */
+	rxrpc_call_aemap_func_t	app_aemap_func;	/* callback to map abort code to/from errno */
+	void			*app_user;	/* application data */
+	struct list_head	app_link;	/* application list linkage */
+	struct list_head	app_attn_link;	/* application attention list linkage */
+	size_t			app_mark;	/* trigger callback when app_ready_qty>=app_mark */
+	char			app_async_read;	/* T if in async-read mode */
+	u8			*app_read_buf;	/* application async read buffer (app_mark size) */
+	u8			*app_scr_alloc;	/* application scratch allocation pointer */
+	void			*app_scr_ptr;	/* application pointer into scratch buffer */
+
+#define RXRPC_APP_MARK_EOF 0xFFFFFFFFU	/* mark at end of input */
+
+	/* application scratch buffer */
+	u8		app_scratch[0] __attribute__((aligned(sizeof(long))));
+};
+
+#define RXRPC_CALL_SCRATCH_SIZE (PAGE_SIZE - sizeof(struct rxrpc_call))
+
+#define rxrpc_call_reset_scratch(CALL) \
+do { (CALL)->app_scr_alloc = (CALL)->app_scratch; } while(0)
+
+#define rxrpc_call_alloc_scratch(CALL,SIZE)						\
+({											\
+	void *ptr;									\
+	ptr = (CALL)->app_scr_alloc;							\
+	(CALL)->app_scr_alloc += (SIZE);						\
+	if ((SIZE)>RXRPC_CALL_SCRATCH_SIZE ||						\
+	    (size_t)((CALL)->app_scr_alloc - (u8*)(CALL)) > RXRPC_CALL_SCRATCH_SIZE) {	\
+		printk("rxrpc_call_alloc_scratch(%p,%u)\n",(CALL),(SIZE));		\
+		BUG();									\
+	}										\
+	ptr;										\
+})
+
+#define rxrpc_call_alloc_scratch_s(CALL,TYPE)						\
+({											\
+	size_t size = sizeof(TYPE);							\
+	TYPE *ptr;									\
+	ptr = (TYPE*)(CALL)->app_scr_alloc;						\
+	(CALL)->app_scr_alloc += size;							\
+	if (size>RXRPC_CALL_SCRATCH_SIZE ||						\
+	    (size_t)((CALL)->app_scr_alloc - (u8*)(CALL)) > RXRPC_CALL_SCRATCH_SIZE) {	\
+		printk("rxrpc_call_alloc_scratch(%p,%u)\n",(CALL),size);		\
+		BUG();									\
+	}										\
+	ptr;										\
+})
+
+#define rxrpc_call_is_ack_pending(CALL) ((CALL)->ackr.reason != 0)
+
+extern int rxrpc_create_call(struct rxrpc_connection *conn,
+			     rxrpc_call_attn_func_t attn,
+			     rxrpc_call_error_func_t error,
+			     rxrpc_call_aemap_func_t aemap,
+			     struct rxrpc_call **_call);
+
+extern int rxrpc_incoming_call(struct rxrpc_connection *conn,
+			       struct rxrpc_message *msg,
+			       struct rxrpc_call **_call);
+
+static inline void rxrpc_get_call(struct rxrpc_call *call)
+{
+	if (atomic_read(&call->usage)<=0)
+		BUG();
+	atomic_inc(&call->usage);
+	/*printk("rxrpc_get_call(%p{u=%d})\n",(C),atomic_read(&(C)->usage));*/
+}
+
+extern void rxrpc_put_call(struct rxrpc_call *call);
+
+extern void rxrpc_call_do_stuff(struct rxrpc_call *call);
+
+extern int rxrpc_call_abort(struct rxrpc_call *call, int error);
+
+#define RXRPC_CALL_READ_BLOCK	0x0001	/* block if not enough data and not yet EOF */
+#define RXRPC_CALL_READ_ALL	0x0002	/* error if insufficient data received */
+extern int rxrpc_call_read_data(struct rxrpc_call *call, void *buffer, size_t size, int flags);
+
+extern int rxrpc_call_write_data(struct rxrpc_call *call,
+				 size_t sioc,
+				 struct iovec siov[],
+				 u8 rxhdr_flags,
+				 int alloc_flags,
+				 int dup_data,
+				 size_t *size_sent);
+
+extern int rxrpc_call_flush(struct rxrpc_call *call);
+
+extern void rxrpc_call_handle_error(struct rxrpc_call *conn, int local, int errno);
+
+#endif /* _LINUX_RXRPC_CALL_H */
diff -Nru a/include/rxrpc/connection.h b/include/rxrpc/connection.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/connection.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,83 @@
+/* connection.h: Rx connection record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_CONNECTION_H
+#define _LINUX_RXRPC_CONNECTION_H
+
+#include <rxrpc/types.h>
+#include <rxrpc/krxtimod.h>
+
+struct sk_buff;
+
+/*****************************************************************************/
+/*
+ * Rx connection
+ * - connections are matched by (rmt_port,rmt_addr,service_id,conn_id,clientflag)
+ * - connections only retain a refcount on the peer when they are active
+ * - connections with refcount==0 are inactive and reside in the peer's graveyard
+ */
+struct rxrpc_connection
+{
+	atomic_t		usage;
+	struct rxrpc_transport	*trans;		/* transport endpoint */
+	struct rxrpc_peer	*peer;		/* peer from/to which connected */
+	struct rxrpc_service	*service;	/* responsible service (inbound conns) */
+	struct rxrpc_timer	timeout;	/* decaching timer */
+	struct list_head	link;		/* link in peer's list */
+	struct list_head	proc_link;	/* link in proc list */
+	struct list_head	err_link;	/* link in ICMP error processing list */
+	struct sockaddr_in	addr;		/* remote address */
+	struct rxrpc_call	*channels[4];	/* channels (active calls) */
+	wait_queue_head_t	chanwait;	/* wait for channel to become available */
+	spinlock_t		lock;		/* access lock */
+	struct timeval		atime;		/* last access time */
+	size_t			mtu_size;	/* MTU size for outbound messages */
+	unsigned		call_counter;	/* call ID counter */
+	rxrpc_serial_t		serial_counter;	/* packet serial number counter */
+
+	/* the following should all be in net order */
+	u32			in_epoch;	/* peer's epoch */
+	u32			out_epoch;	/* my epoch */
+	u32			conn_id;	/* connection ID, appropriately shifted */
+	u16			service_id;	/* service ID */
+	u8			security_ix;	/* security ID */
+	u8			in_clientflag;	/* RXRPC_CLIENT_INITIATED if we are server */
+	u8			out_clientflag;	/* RXRPC_CLIENT_INITIATED if we are client */
+};
+
+extern int rxrpc_create_connection(struct rxrpc_transport *trans,
+				   u16 port,
+				   u32 addr,
+				   unsigned short service_id,
+				   void *security,
+				   struct rxrpc_connection **_conn);
+
+extern int rxrpc_connection_lookup(struct rxrpc_peer *peer,
+				   struct rxrpc_message *msg,
+				   struct rxrpc_connection **_conn);
+
+static inline void rxrpc_get_connection(struct rxrpc_connection *conn)
+{
+	if (atomic_read(&conn->usage)<0)
+		BUG();
+	atomic_inc(&conn->usage);
+	//printk("rxrpc_get_conn(%p{u=%d})\n",conn,atomic_read(&conn->usage));
+}
+
+extern void rxrpc_put_connection(struct rxrpc_connection *conn);
+
+extern int rxrpc_conn_receive_call_packet(struct rxrpc_connection *conn,
+					  struct rxrpc_call *call,
+					  struct rxrpc_message *msg);
+
+extern void rxrpc_conn_handle_error(struct rxrpc_connection *conn, int local, int errno);
+
+#endif /* _LINUX_RXRPC_CONNECTION_H */
diff -Nru a/include/rxrpc/krxiod.h b/include/rxrpc/krxiod.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/krxiod.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,27 @@
+/* krxiod.h: Rx RPC I/O kernel thread interface
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_KRXIOD_H
+#define _LINUX_RXRPC_KRXIOD_H
+
+#include <rxrpc/types.h>
+
+extern int rxrpc_krxiod_init(void);
+extern void rxrpc_krxiod_kill(void);
+extern void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans);
+extern void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans);
+extern void rxrpc_krxiod_queue_peer(struct rxrpc_peer *peer);
+extern void rxrpc_krxiod_dequeue_peer(struct rxrpc_peer *peer);
+extern void rxrpc_krxiod_clear_peers(struct rxrpc_transport *trans);
+extern void rxrpc_krxiod_queue_call(struct rxrpc_call *call);
+extern void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call);
+
+#endif /* _LINUX_RXRPC_KRXIOD_H */
diff -Nru a/include/rxrpc/krxsecd.h b/include/rxrpc/krxsecd.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/krxsecd.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,22 @@
+/* krxsecd.h: Rx RPC security kernel thread interface
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_KRXSECD_H
+#define _LINUX_RXRPC_KRXSECD_H
+
+#include <rxrpc/types.h>
+
+extern int rxrpc_krxsecd_init(void);
+extern void rxrpc_krxsecd_kill(void);
+extern void rxrpc_krxsecd_clear_transport(struct rxrpc_transport *trans);
+extern void rxrpc_krxsecd_queue_incoming_call(struct rxrpc_message *msg);
+
+#endif /* _LINUX_RXRPC_KRXSECD_H */
diff -Nru a/include/rxrpc/krxtimod.h b/include/rxrpc/krxtimod.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/krxtimod.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,45 @@
+/* krxtimod.h: RxRPC timeout daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_KRXTIMOD_H
+#define _LINUX_RXRPC_KRXTIMOD_H
+
+#include <rxrpc/types.h>
+
+struct rxrpc_timer_ops {
+	/* called when the front of the timer queue has timed out */
+	void (*timed_out)(struct rxrpc_timer *timer);
+};
+
+/*****************************************************************************/
+/*
+ * RXRPC timer/timeout record
+ */
+struct rxrpc_timer
+{
+	struct list_head		link;		/* link in timer queue */
+	unsigned long			timo_jif;	/* timeout time */
+	const struct rxrpc_timer_ops	*ops;		/* timeout expiry function */
+};
+
+static inline void rxrpc_timer_init(rxrpc_timer_t *timer, const struct rxrpc_timer_ops *ops)
+{
+	INIT_LIST_HEAD(&timer->link);
+	timer->ops = ops;
+}
+
+extern int rxrpc_krxtimod_start(void);
+extern void rxrpc_krxtimod_kill(void);
+
+extern void rxrpc_krxtimod_add_timer(rxrpc_timer_t *timer, unsigned long timeout);
+extern int rxrpc_krxtimod_del_timer(rxrpc_timer_t *timer);
+
+#endif /* _LINUX_RXRPC_KRXTIMOD_H */
diff -Nru a/include/rxrpc/message.h b/include/rxrpc/message.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/message.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,72 @@
+/* message.h: Rx message caching
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _H_3AD3363A_3A9C_11D6_83D8_0002B3163499
+#define _H_3AD3363A_3A9C_11D6_83D8_0002B3163499
+
+#include <rxrpc/packet.h>
+
+/*****************************************************************************/
+/*
+ * Rx message record
+ */
+struct rxrpc_message
+{
+	atomic_t		usage;
+	struct list_head	link;		/* list link */
+	struct timeval		stamp;		/* time received or last sent */
+	rxrpc_seq_t		seq;		/* message sequence number */
+
+	int			state;		/* the state the message is currently in */
+#define RXRPC_MSG_PREPARED	0
+#define RXRPC_MSG_SENT		1
+#define RXRPC_MSG_ACKED		2		/* provisionally ACK'd */
+#define RXRPC_MSG_DONE		3		/* definitively ACK'd (msg->seq<ack.firstPacket) */
+#define RXRPC_MSG_RECEIVED	4
+#define RXRPC_MSG_ERROR		-1
+	char			rttdone;	/* used for RTT */
+
+	struct rxrpc_transport	*trans;		/* transport received through */
+	struct rxrpc_connection	*conn;		/* connection received over */
+	struct sk_buff		*pkt;		/* received packet */
+	off_t			offset;		/* offset into pkt of next byte of data */
+
+	struct rxrpc_header	hdr;		/* message header */
+
+	int			dcount;		/* data part count */
+	size_t			dsize;		/* data size */
+#define RXRPC_MSG_MAX_IOCS 8
+	struct iovec		data[RXRPC_MSG_MAX_IOCS]; /* message data */
+	unsigned long		dfree;		/* bit mask indicating kfree(data[x]) if T */
+};
+
+#define rxrpc_get_message(M) do { atomic_inc(&(M)->usage); } while(0)
+
+extern void __rxrpc_put_message(struct rxrpc_message *msg);
+static inline void rxrpc_put_message(struct rxrpc_message *msg)
+{
+	if (atomic_read(&msg->usage)<=0)
+		BUG();
+	if (atomic_dec_and_test(&msg->usage))
+		__rxrpc_put_message(msg);
+}
+
+extern int rxrpc_conn_newmsg(struct rxrpc_connection *conn,
+			     struct rxrpc_call *call,
+			     u8 type,
+			     int count,
+			     struct iovec diov[],
+			     int alloc_flags,
+			     struct rxrpc_message **_msg);
+
+extern int rxrpc_conn_sendmsg(struct rxrpc_connection *conn, struct rxrpc_message *msg);
+
+#endif /* _H_3AD3363A_3A9C_11D6_83D8_0002B3163499 */
diff -Nru a/include/rxrpc/packet.h b/include/rxrpc/packet.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/packet.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,128 @@
+/* packet.h: Rx packet layout and definitions
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_PACKET_H
+#define _LINUX_RXRPC_PACKET_H
+
+#include <rxrpc/types.h>
+
+#define RXRPC_IPUDP_SIZE		28
+extern size_t RXRPC_MAX_PACKET_SIZE;
+#define RXRPC_MAX_PACKET_DATA_SIZE	(RXRPC_MAX_PACKET_SIZE - sizeof(struct rxrpc_header))
+#define RXRPC_LOCAL_PACKET_SIZE		RXRPC_MAX_PACKET_SIZE
+#define RXRPC_REMOTE_PACKET_SIZE	(576 - RXRPC_IPUDP_SIZE)
+
+/*****************************************************************************/
+/*
+ * on-the-wire Rx packet header
+ * - all multibyte fields should be in network byte order
+ */
+struct rxrpc_header
+{
+	u32	epoch;		/* client boot timestamp */
+
+	u32	cid;		/* connection and channel ID */
+#define RXRPC_MAXCALLS		4			/* max active calls per conn */
+#define RXRPC_CHANNELMASK	(RXRPC_MAXCALLS-1)	/* mask for channel ID */
+#define RXRPC_CIDMASK		(~RXRPC_CHANNELMASK)	/* mask for connection ID */
+#define RXRPC_CIDSHIFT		2			/* shift for connection ID */
+
+	u32	callNumber;	/* call ID (0 for connection-level packets) */
+#define RXRPC_PROCESS_MAXCALLS	(1<<2)	/* maximum number of active calls per conn (power of 2) */
+
+	u32	seq;		/* sequence number of pkt in call stream */
+	u32	serial;		/* serial number of pkt sent to network */
+
+	u8	type;		/* packet type */
+#define RXRPC_PACKET_TYPE_DATA		1	/* data */
+#define RXRPC_PACKET_TYPE_ACK		2	/* ACK */
+#define RXRPC_PACKET_TYPE_BUSY		3	/* call reject */
+#define RXRPC_PACKET_TYPE_ABORT		4	/* call/connection abort */
+#define RXRPC_PACKET_TYPE_ACKALL	5	/* ACK all outstanding packets on call */
+#define RXRPC_PACKET_TYPE_CHALLENGE	6	/* connection security challenge (SRVR->CLNT) */
+#define RXRPC_PACKET_TYPE_RESPONSE	7	/* connection secutity response (CLNT->SRVR) */
+#define RXRPC_PACKET_TYPE_DEBUG		8	/* debug info request */
+#define RXRPC_N_PACKET_TYPES		9	/* number of packet types (incl type 0) */
+
+	u8	flags;		/* packet flags */
+#define RXRPC_CLIENT_INITIATED	0x01		/* signifies a packet generated by a client */
+#define RXRPC_REQUEST_ACK	0x02		/* request an unconditional ACK of this packet */
+#define RXRPC_LAST_PACKET	0x04		/* the last packet from this side for this call */
+#define RXRPC_MORE_PACKETS	0x08		/* more packets to come */
+#define RXRPC_JUMBO_PACKET	0x20		/* [DATA] this is a jumbo packet */
+#define RXRPC_SLOW_START_OK	0x20		/* [ACK] slow start supported */
+
+	u8	userStatus;	/* app-layer defined status */
+	u8	securityIndex;	/* security protocol ID */
+	u16	_rsvd;		/* reserved (used by kerberos security as cksum) */
+	u16	serviceId;	/* service ID */
+
+} __attribute__((packed));
+
+#define __rxrpc_header_off(X) offsetof(struct rxrpc_header,X)
+
+extern const char *rxrpc_pkts[];
+
+/*****************************************************************************/
+/*
+ * jumbo packet secondary header
+ * - can be mapped to read header by:
+ *   - new_serial = serial + 1
+ *   - new_seq = seq + 1
+ *   - new_flags = j_flags
+ *   - new__rsvd = j__rsvd
+ *   - duplicating all other fields
+ */
+struct rxrpc_jumbo_header
+{
+	u8	flags;		/* packet flags (as per rxrpc_header) */
+	u8	pad;
+	u16	_rsvd;		/* reserved (used by kerberos security as cksum) */
+};
+
+#define RXRPC_JUMBO_DATALEN	1412	/* non-terminal jumbo packet data length */
+
+/*****************************************************************************/
+/*
+ * on-the-wire Rx ACK packet data payload
+ * - all multibyte fields should be in network byte order
+ */
+struct rxrpc_ackpacket
+{
+	u16	bufferSpace;	/* number of packet buffers available */
+	u16	maxSkew;	/* diff between serno being ACK'd and highest serial no received */
+	u32	firstPacket;	/* sequence no of first ACK'd packet in attached list */
+	u32	previousPacket;	/* sequence no of previous packet received */
+	u32	serial;		/* serial no of packet that prompted this ACK */
+
+	u8	reason;		/* reason for ACK */
+#define RXRPC_ACK_REQUESTED		1	/* ACK was requested on packet */
+#define RXRPC_ACK_DUPLICATE		2	/* duplicate packet received */
+#define RXRPC_ACK_OUT_OF_SEQUENCE	3	/* out of sequence packet received */
+#define RXRPC_ACK_EXCEEDS_WINDOW	4	/* packet received beyond end of ACK window */
+#define RXRPC_ACK_NOSPACE		5	/* packet discarded due to lack of buffer space */
+#define RXRPC_ACK_PING			6	/* keep alive ACK */
+#define RXRPC_ACK_PING_RESPONSE		7	/* response to RXRPC_ACK_PING */
+#define RXRPC_ACK_DELAY			8	/* nothing happened since received packet */
+#define RXRPC_ACK_IDLE			9	/* ACK due to fully received ACK window */
+
+	u8	nAcks;		/* number of ACKs */
+#define RXRPC_MAXACKS	255
+
+	u8	acks[0];	/* list of ACK/NAKs */
+#define RXRPC_ACK_TYPE_NACK		0
+#define RXRPC_ACK_TYPE_ACK		1
+
+} __attribute__((packed));
+
+extern const char *rxrpc_acks[];
+
+#endif /* _LINUX_RXRPC_PACKET_H */
diff -Nru a/include/rxrpc/peer.h b/include/rxrpc/peer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/peer.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,80 @@
+/* peer.h: Rx RPC per-transport peer record
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_PEER_H
+#define _LINUX_RXRPC_PEER_H
+
+#include <linux/wait.h>
+#include <rxrpc/types.h>
+#include <rxrpc/krxtimod.h>
+
+struct rxrpc_peer_ops
+{
+	/* peer record being added */
+	int (*adding)(struct rxrpc_peer *peer);
+
+	/* peer record being discarded from graveyard */
+	void (*discarding)(struct rxrpc_peer *peer);
+
+	/* change of epoch detected on connection */
+	void (*change_of_epoch)(struct rxrpc_connection *conn);
+};
+
+/*****************************************************************************/
+/*
+ * Rx RPC per-transport peer record
+ * - peers only retain a refcount on the transport when they are active
+ * - peers with refcount==0 are inactive and reside in the transport's graveyard
+ */
+struct rxrpc_peer
+{
+	atomic_t		usage;
+	struct rxrpc_peer_ops	*ops;		/* operations on this peer */
+	struct rxrpc_transport	*trans;		/* owner transport */
+	struct rxrpc_timer	timeout;	/* timeout for grave destruction */
+	struct list_head	link;		/* link in transport's peer list */
+	struct list_head	proc_link;	/* link in /proc list */
+	rwlock_t		conn_lock;	/* lock for connections */
+	struct list_head	conn_active;	/* active connections to/from this peer */
+	struct list_head	conn_graveyard;	/* graveyard for inactive connections */
+	spinlock_t		conn_gylock;	/* lock for conn_graveyard */
+	wait_queue_head_t	conn_gy_waitq;	/* wait queue hit when graveyard is empty */
+	atomic_t		conn_count;	/* number of attached connections */
+	struct in_addr		addr;		/* remote address */
+	size_t			if_mtu;		/* interface MTU for this peer */
+	spinlock_t		lock;		/* access lock */
+
+	void			*user;		/* application layer data */
+
+	/* calculated RTT cache */
+#define RXRPC_RTT_CACHE_SIZE 32
+	suseconds_t		rtt;		/* current RTT estimate (in uS) */
+	unsigned short		rtt_point;	/* next entry at which to insert */
+	unsigned short		rtt_usage;	/* amount of cache actually used */
+	suseconds_t		rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* calculated RTT cache */
+};
+
+
+extern int rxrpc_peer_lookup(struct rxrpc_transport *trans,
+			     u32 addr,
+			     struct rxrpc_peer **_peer);
+
+static inline void rxrpc_get_peer(struct rxrpc_peer *peer)
+{
+	if (atomic_read(&peer->usage)<0)
+		BUG();
+	atomic_inc(&peer->usage);
+	//printk("rxrpc_get_peer(%p{u=%d})\n",peer,atomic_read(&peer->usage));
+}
+
+extern void rxrpc_put_peer(struct rxrpc_peer *peer);
+
+#endif /* _LINUX_RXRPC_PEER_H */
diff -Nru a/include/rxrpc/rxrpc.h b/include/rxrpc/rxrpc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/rxrpc.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,29 @@
+/* rx.h: Rx RPC interface
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_RXRPC_H
+#define _LINUX_RXRPC_RXRPC_H
+
+#ifdef __KERNEL__
+
+extern u32 rxrpc_epoch;
+
+extern int rxrpc_ktrace;
+extern int rxrpc_kdebug;
+extern int rxrpc_kproto;
+extern int rxrpc_knet;
+
+extern int rxrpc_sysctl_init(void);
+extern void rxrpc_sysctl_cleanup(void);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_RXRPC_RXRPC_H */
diff -Nru a/include/rxrpc/transport.h b/include/rxrpc/transport.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/transport.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,115 @@
+/* transport.h: Rx transport management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_TRANSPORT_H
+#define _LINUX_RXRPC_TRANSPORT_H
+
+#include <rxrpc/types.h>
+#include <rxrpc/krxiod.h>
+#include <rxrpc/rxrpc.h>
+#include <linux/skbuff.h>
+#include <linux/rwsem.h>
+
+typedef int (*rxrpc_newcall_fnx_t)(struct rxrpc_call *call);
+
+extern wait_queue_head_t rxrpc_krxiod_wq;
+
+/*****************************************************************************/
+/*
+ * Rx operation specification
+ * - tables of these must be sorted by op ID so that they can be binary-chop searched
+ */
+struct rxrpc_operation
+{
+	unsigned		id;		/* operation ID */
+	size_t			asize;		/* minimum size of argument block */
+	const char		*name;		/* name of operation */
+	void			*user;		/* initial user data */
+};
+
+/*****************************************************************************/
+/*
+ * Rx transport service record
+ */
+struct rxrpc_service
+{
+	struct list_head	link;		/* link in services list on transport */
+	struct module		*owner;		/* owner module */
+	rxrpc_newcall_fnx_t	new_call;	/* new call handler function */
+	const char		*name;		/* name of service */
+	unsigned short		service_id;	/* Rx service ID */
+	rxrpc_call_attn_func_t	attn_func;	/* call requires attention callback */
+	rxrpc_call_error_func_t	error_func;	/* call error callback */
+	rxrpc_call_aemap_func_t	aemap_func;	/* abort -> errno mapping callback */
+
+	const struct rxrpc_operation	*ops_begin;	/* beginning of operations table */
+	const struct rxrpc_operation	*ops_end;	/* end of operations table */
+};
+
+/*****************************************************************************/
+/*
+ * Rx transport endpoint record
+ */
+struct rxrpc_transport
+{
+	atomic_t		usage;
+	struct socket		*socket;	/* my UDP socket */
+	struct list_head	services;	/* services listening on this socket */
+	struct list_head	link;		/* link in transport list */
+	struct list_head	proc_link;	/* link in transport proc list */
+	struct list_head	krxiodq_link;	/* krxiod attention queue link */
+	spinlock_t		lock;		/* access lock */
+	struct list_head	peer_active;	/* active peers connected to over this socket */
+	struct list_head	peer_graveyard;	/* inactive peer list */
+	spinlock_t		peer_gylock;	/* peer graveyard lock */
+	wait_queue_head_t	peer_gy_waitq;	/* wait queue hit when peer graveyard is empty */
+	rwlock_t		peer_lock;	/* peer list access lock */
+	atomic_t		peer_count;	/* number of peers */
+	struct rxrpc_peer_ops	*peer_ops;	/* default peer operations */
+	unsigned short		port;		/* port upon which listening */
+	volatile char		error_rcvd;	/* T if received ICMP error outstanding */
+};
+
+extern struct list_head rxrpc_transports;
+
+extern int rxrpc_create_transport(unsigned short port,
+				  struct rxrpc_transport **_trans);
+
+static inline void rxrpc_get_transport(struct rxrpc_transport *trans)
+{
+	if (atomic_read(&trans->usage)<=0)
+		BUG();
+	atomic_inc(&trans->usage);
+	//printk("rxrpc_get_transport(%p{u=%d})\n",trans,atomic_read(&trans->usage));
+}
+
+extern void rxrpc_put_transport(struct rxrpc_transport *trans);
+
+extern int rxrpc_add_service(struct rxrpc_transport *trans,
+			     struct rxrpc_service *srv);
+
+extern void rxrpc_del_service(struct rxrpc_transport *trans,
+			      struct rxrpc_service *srv);
+
+#if 0
+extern int rxrpc_trans_add_connection(struct rxrpc_transport *trans,
+				      struct rxrpc_connection *conn);
+#endif
+
+extern void rxrpc_trans_receive_packet(struct rxrpc_transport *trans);
+
+extern int rxrpc_trans_immediate_abort(struct rxrpc_transport *trans,
+				       struct rxrpc_message *msg,
+				       int error);
+
+extern void rxrpc_clear_transport(struct rxrpc_transport *trans);
+
+#endif /* _LINUX_RXRPC_TRANSPORT_H */
diff -Nru a/include/rxrpc/types.h b/include/rxrpc/types.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/rxrpc/types.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,39 @@
+/* types.h: Rx types
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_RXRPC_TYPES_H
+#define _LINUX_RXRPC_TYPES_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+typedef unsigned	rxrpc_seq_t;	/* Rx message sequence number */
+typedef unsigned	rxrpc_serial_t;	/* Rx message serial number */
+
+struct rxrpc_call;
+struct rxrpc_connection;
+struct rxrpc_header;
+struct rxrpc_message;
+struct rxrpc_operation;
+struct rxrpc_peer;
+struct rxrpc_service;
+typedef struct rxrpc_timer rxrpc_timer_t;
+struct rxrpc_transport;
+
+typedef void (*rxrpc_call_attn_func_t)(struct rxrpc_call *call);
+typedef void (*rxrpc_call_error_func_t)(struct rxrpc_call *call);
+typedef void (*rxrpc_call_aemap_func_t)(struct rxrpc_call *call);
+
+#endif /* _LINUX_RXRPC_TYPES_H */
diff -Nru a/include/sound/asound.h b/include/sound/asound.h
--- a/include/sound/asound.h	Tue Oct 15 20:29:17 2002
+++ b/include/sound/asound.h	Tue Oct 15 20:29:17 2002
@@ -129,7 +129,7 @@
  *                                                                           *
  *****************************************************************************/
 
-#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 2)
+#define SNDRV_PCM_VERSION		SNDRV_PROTOCOL_VERSION(2, 0, 3)
 
 typedef unsigned long sndrv_pcm_uframes_t;
 typedef long sndrv_pcm_sframes_t;
@@ -423,6 +423,7 @@
 	SNDRV_PCM_IOCTL_SW_PARAMS = _IOWR('A', 0x13, struct sndrv_pcm_sw_params),
 	SNDRV_PCM_IOCTL_STATUS = _IOR('A', 0x20, struct sndrv_pcm_status),
 	SNDRV_PCM_IOCTL_DELAY = _IOR('A', 0x21, sndrv_pcm_sframes_t),
+	SNDRV_PCM_IOCTL_HWSYNC = _IO('A', 0x22),
 	SNDRV_PCM_IOCTL_CHANNEL_INFO = _IOR('A', 0x32, struct sndrv_pcm_channel_info),
 	SNDRV_PCM_IOCTL_PREPARE = _IO('A', 0x40),
 	SNDRV_PCM_IOCTL_RESET = _IO('A', 0x41),
diff -Nru a/include/sound/core.h b/include/sound/core.h
--- a/include/sound/core.h	Tue Oct 15 20:29:23 2002
+++ b/include/sound/core.h	Tue Oct 15 20:29:23 2002
@@ -225,7 +225,6 @@
 int snd_minor_info_oss_done(void);
 
 int snd_oss_init_module(void);
-void snd_oss_cleanup_module(void);
 
 #endif
 
diff -Nru a/include/sound/info.h b/include/sound/info.h
--- a/include/sound/info.h	Tue Oct 15 20:29:12 2002
+++ b/include/sound/info.h	Tue Oct 15 20:29:13 2002
@@ -164,7 +164,7 @@
 static inline int snd_info_register(snd_info_entry_t * entry) { return 0; }
 static inline int snd_info_unregister(snd_info_entry_t * entry) { return 0; }
 
-static inline struct proc_dir_entry *snd_create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) { return 0; }
+static inline struct proc_dir_entry *snd_create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) { return NULL; }
 static inline void snd_remove_proc_entry(struct proc_dir_entry *parent,
 					 struct proc_dir_entry *de) { ; }
 
@@ -174,7 +174,7 @@
  * OSS info part
  */
 
-#ifdef CONFIG_SND_OSSEMUL
+#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
 
 #define SNDRV_OSS_INFO_DEV_AUDIO	0
 #define SNDRV_OSS_INFO_DEV_SYNTH	1
@@ -187,6 +187,6 @@
 extern int snd_oss_info_register(int dev, int num, char *string);
 #define snd_oss_info_unregister(dev, num) snd_oss_info_register(dev, num, NULL)
 
-#endif /* CONFIG_SND_OSSEMUL */
+#endif /* CONFIG_SND_OSSEMUL && CONFIG_PROC_FS */
 
 #endif /* __SOUND_INFO_H */
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Tue Oct 15 20:29:16 2002
+++ b/include/sound/version.h	Tue Oct 15 20:29:16 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0rc3"
-#define CONFIG_SND_DATE " (Fri Oct 04 13:09:13 2002 UTC)"
+#define CONFIG_SND_DATE " (Mon Oct 14 16:41:26 2002 UTC)"
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Tue Oct 15 20:29:12 2002
+++ b/init/main.c	Tue Oct 15 20:29:12 2002
@@ -24,13 +24,14 @@
 #include <linux/smp_lock.h>
 #include <linux/blk.h>
 #include <linux/hdreg.h>
-#include <linux/iobuf.h>
 #include <linux/bootmem.h>
 #include <linux/tty.h>
 #include <linux/percpu.h>
 #include <linux/kernel_stat.h>
 #include <linux/security.h>
 #include <linux/workqueue.h>
+#include <linux/profile.h>
+#include <linux/rcupdate.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -53,7 +54,6 @@
 #error Sorry, your GCC is too old. It builds incorrect kernels.
 #endif
 
-extern char _stext, _etext;
 extern char *linux_banner;
 
 static int init(void *);
@@ -131,13 +131,6 @@
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
 char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
 
-static int __init profile_setup(char *str)
-{
-    int par;
-    if (get_option(&str,&par)) prof_shift = par;
-	return 1;
-}
-
 __setup("profile=", profile_setup);
 
 static int __init checksetup(char *line)
@@ -398,6 +391,7 @@
 	printk("Kernel command line: %s\n", saved_command_line);
 	parse_options(command_line);
 	trap_init();
+	rcu_init();
 	init_IRQ();
 	sched_init();
 	softirq_init();
@@ -412,16 +406,7 @@
 #ifdef CONFIG_MODULES
 	init_modules();
 #endif
-	if (prof_shift) {
-		unsigned int size;
-		/* only text is profiled */
-		prof_len = (unsigned long) &_etext - (unsigned long) &_stext;
-		prof_len >>= prof_shift;
-		
-		size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1;
-		prof_buffer = (unsigned int *) alloc_bootmem(size);
-	}
-
+	profile_init();
 	kmem_cache_init();
 	local_irq_enable();
 	calibrate_delay();
diff -Nru a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile	Tue Oct 15 20:29:12 2002
+++ b/kernel/Makefile	Tue Oct 15 20:29:12 2002
@@ -3,12 +3,14 @@
 #
 
 export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \
-	      printk.o platform.o suspend.o dma.o module.o cpufreq.o
+		printk.o platform.o suspend.o dma.o module.o cpufreq.o \
+		profile.o rcupdate.o
 
-obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
+obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
 	    module.o exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
-	    signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o
+	    signal.o sys.o kmod.o workqueue.o futex.o platform.o pid.o \
+	    rcupdate.o
 
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Tue Oct 15 20:29:21 2002
+++ b/kernel/exit.c	Tue Oct 15 20:29:21 2002
@@ -19,6 +19,7 @@
 #include <linux/file.h>
 #include <linux/binfmts.h>
 #include <linux/ptrace.h>
+#include <linux/profile.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -59,11 +60,12 @@
 {
 	struct dentry *proc_dentry;
 	task_t *leader;
-
-	if (p->state < TASK_ZOMBIE)
-		BUG();
+ 
+	BUG_ON(p->state < TASK_ZOMBIE);
+ 
 	if (p != current)
 		wait_task_inactive(p);
+
 	atomic_dec(&p->user->processes);
 	security_ops->task_free_security(p);
 	free_uid(p->user);
@@ -635,6 +637,8 @@
 				current->comm, current->pid,
 				preempt_count());
 
+	profile_exit_task(tsk);
+ 
 fake_volatile:
 	acct_process(code);
 	__exit_mm(tsk);
diff -Nru a/kernel/futex.c b/kernel/futex.c
--- a/kernel/futex.c	Tue Oct 15 20:29:14 2002
+++ b/kernel/futex.c	Tue Oct 15 20:29:14 2002
@@ -115,8 +115,9 @@
 	 * Do a quick atomic lookup first - this is the fastpath.
 	 */
 	page = follow_page(mm, addr, 0);
-	if (likely(page != NULL)) {
-		get_page(page);
+	if (likely(page != NULL)) {	
+		if (!PageReserved(page))
+			get_page(page);
 		return page;
 	}
 
@@ -140,8 +141,10 @@
 	 * check for races:
 	 */
 	tmp = follow_page(mm, addr, 0);
-	if (tmp != page)
+	if (tmp != page) {
+		put_page(page);
 		goto repeat_lookup;
+	}
 
 	return page;
 }
@@ -176,6 +179,7 @@
 
 		if (this->page == page && this->offset == offset) {
 			list_del_init(i);
+			__detach_vcache(&this->vcache);
 			tell_waiter(this);
 			ret++;
 			if (ret >= num)
@@ -235,15 +239,15 @@
 {
 	int ret = 0;
 
-	detach_vcache(&q->vcache);
-
+	spin_lock(&vcache_lock);
 	spin_lock(&futex_lock);
 	if (!list_empty(&q->list)) {
 		list_del(&q->list);
+		__detach_vcache(&q->vcache);
 		ret = 1;
 	}
 	spin_unlock(&futex_lock);
-
+	spin_unlock(&vcache_lock);
 	return ret;
 }
 
@@ -314,13 +318,7 @@
 {
 	struct futex_q *q = filp->private_data;
 
-	spin_lock(&futex_lock);
-	if (!list_empty(&q->list)) {
-		list_del(&q->list);
-		/* Noone can be polling on us now. */
-		BUG_ON(waitqueue_active(&q->waiters));
-	}
-	spin_unlock(&futex_lock);
+	unqueue_me(q);
 	unpin_page(q->page);
 	kfree(filp->private_data);
 	return 0;
@@ -436,9 +434,8 @@
 
 	pos_in_page = uaddr % PAGE_SIZE;
 
-	/* Must be "naturally" aligned, and not on page boundary. */
-	if ((pos_in_page % __alignof__(int)) != 0
-	    || pos_in_page + sizeof(int) > PAGE_SIZE)
+	/* Must be "naturally" aligned */
+	if (pos_in_page % sizeof(int))
 		return -EINVAL;
 
 	switch (op) {
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Tue Oct 15 20:29:11 2002
+++ b/kernel/ksyms.c	Tue Oct 15 20:29:11 2002
@@ -33,7 +33,6 @@
 #include <linux/swap.h>
 #include <linux/ctype.h>
 #include <linux/file.h>
-#include <linux/iobuf.h>
 #include <linux/console.h>
 #include <linux/poll.h>
 #include <linux/mmzone.h>
@@ -103,6 +102,8 @@
 EXPORT_SYMBOL(kmem_cache_alloc);
 EXPORT_SYMBOL(kmem_cache_free);
 EXPORT_SYMBOL(kmem_cache_size);
+EXPORT_SYMBOL(set_shrinker);
+EXPORT_SYMBOL(remove_shrinker);
 EXPORT_SYMBOL(kmalloc);
 EXPORT_SYMBOL(kfree);
 EXPORT_SYMBOL(vfree);
@@ -246,7 +247,6 @@
 EXPORT_SYMBOL(have_submounts);
 EXPORT_SYMBOL(d_find_alias);
 EXPORT_SYMBOL(d_prune_aliases);
-EXPORT_SYMBOL(prune_dcache);
 EXPORT_SYMBOL(shrink_dcache_sb);
 EXPORT_SYMBOL(shrink_dcache_parent);
 EXPORT_SYMBOL(shrink_dcache_anon);
@@ -437,18 +437,6 @@
 EXPORT_SYMBOL(__br_write_lock);
 EXPORT_SYMBOL(__br_write_unlock);
 #endif
-
-/* Kiobufs */
-EXPORT_SYMBOL(alloc_kiovec);
-EXPORT_SYMBOL(free_kiovec);
-EXPORT_SYMBOL(expand_kiobuf);
-
-EXPORT_SYMBOL(map_user_kiobuf);
-EXPORT_SYMBOL(unmap_kiobuf);
-EXPORT_SYMBOL(lock_kiovec);
-EXPORT_SYMBOL(unlock_kiovec);
-EXPORT_SYMBOL(brw_kiovec);
-EXPORT_SYMBOL(kiobuf_wait_for_io);
 
 #ifdef HAVE_DISABLE_HLT
 EXPORT_SYMBOL(disable_hlt);
diff -Nru a/kernel/profile.c b/kernel/profile.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/kernel/profile.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,121 @@
+/*
+ *  linux/kernel/profile.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/profile.h>
+#include <linux/bootmem.h>
+#include <linux/notifier.h>
+#include <linux/mm.h>
+
+extern char _stext, _etext;
+
+unsigned int * prof_buffer;
+unsigned long prof_len;
+unsigned long prof_shift;
+
+int __init profile_setup(char * str)
+{
+	int par;
+	if (get_option(&str,&par))
+		prof_shift = par;
+	return 1;
+}
+
+
+void __init profile_init(void)
+{
+	unsigned int size;
+ 
+	if (!prof_shift) 
+		return;
+ 
+	/* only text is profiled */
+	prof_len = (unsigned long) &_etext - (unsigned long) &_stext;
+	prof_len >>= prof_shift;
+		
+	size = prof_len * sizeof(unsigned int) + PAGE_SIZE - 1;
+	prof_buffer = (unsigned int *) alloc_bootmem(size);
+}
+
+/* Profile event notifications */
+ 
+#ifdef CONFIG_PROFILING
+ 
+static DECLARE_RWSEM(profile_rwsem);
+static struct notifier_block * exit_task_notifier;
+static struct notifier_block * exit_mmap_notifier;
+static struct notifier_block * exec_unmap_notifier;
+ 
+void profile_exit_task(struct task_struct * task)
+{
+	down_read(&profile_rwsem);
+	notifier_call_chain(&exit_task_notifier, 0, task);
+	up_read(&profile_rwsem);
+}
+ 
+void profile_exit_mmap(struct mm_struct * mm)
+{
+	down_read(&profile_rwsem);
+	notifier_call_chain(&exit_mmap_notifier, 0, mm);
+	up_read(&profile_rwsem);
+}
+
+void profile_exec_unmap(struct mm_struct * mm)
+{
+	down_read(&profile_rwsem);
+	notifier_call_chain(&exec_unmap_notifier, 0, mm);
+	up_read(&profile_rwsem);
+}
+
+int profile_event_register(enum profile_type type, struct notifier_block * n)
+{
+	int err = -EINVAL;
+ 
+	down_write(&profile_rwsem);
+ 
+	switch (type) {
+		case EXIT_TASK:
+			err = notifier_chain_register(&exit_task_notifier, n);
+			break;
+		case EXIT_MMAP:
+			err = notifier_chain_register(&exit_mmap_notifier, n);
+			break;
+		case EXEC_UNMAP:
+			err = notifier_chain_register(&exec_unmap_notifier, n);
+			break;
+	}
+ 
+	up_write(&profile_rwsem);
+ 
+	return err;
+}
+
+ 
+int profile_event_unregister(enum profile_type type, struct notifier_block * n)
+{
+	int err = -EINVAL;
+ 
+	down_write(&profile_rwsem);
+ 
+	switch (type) {
+		case EXIT_TASK:
+			err = notifier_chain_unregister(&exit_task_notifier, n);
+			break;
+		case EXIT_MMAP:
+			err = notifier_chain_unregister(&exit_mmap_notifier, n);
+			break;
+		case EXEC_UNMAP:
+			err = notifier_chain_unregister(&exec_unmap_notifier, n);
+			break;
+	}
+
+	up_write(&profile_rwsem);
+	return err;
+}
+
+#endif /* CONFIG_PROFILING */
+
+EXPORT_SYMBOL_GPL(profile_event_register);
+EXPORT_SYMBOL_GPL(profile_event_unregister);
diff -Nru a/kernel/rcupdate.c b/kernel/rcupdate.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/kernel/rcupdate.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,242 @@
+/*
+ * Read-Copy Update mechanism for mutual exclusion
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (c) IBM Corporation, 2001
+ *
+ * Author: Dipankar Sarma <dipankar@in.ibm.com>
+ * 
+ * Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
+ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
+ * Papers:
+ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
+ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * 		http://lse.sourceforge.net/locking/rcupdate.html
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/percpu.h>
+#include <linux/rcupdate.h>
+
+/* Definition for rcupdate control block. */
+struct rcu_ctrlblk rcu_ctrlblk = 
+	{ .mutex = SPIN_LOCK_UNLOCKED, .curbatch = 1, 
+	  .maxbatch = 1, .rcu_cpu_mask = 0 };
+struct rcu_data rcu_data[NR_CPUS] __cacheline_aligned;
+
+/* Fake initialization required by compiler */
+static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL};
+#define RCU_tasklet(cpu) (per_cpu(rcu_tasklet, cpu))
+
+/**
+ * call_rcu - Queue an RCU update request.
+ * @head: structure to be used for queueing the RCU updates.
+ * @func: actual update function to be invoked after the grace period
+ * @arg: argument to be passed to the update function
+ *
+ * The update function will be invoked as soon as all CPUs have performed 
+ * a context switch or been seen in the idle loop or in a user process. 
+ * The read-side of critical section that use call_rcu() for updation must 
+ * be protected by rcu_read_lock()/rcu_read_unlock().
+ */
+void call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg)
+{
+	int cpu;
+	unsigned long flags;
+
+	head->func = func;
+	head->arg = arg;
+	local_irq_save(flags);
+	cpu = smp_processor_id();
+	list_add_tail(&head->list, &RCU_nxtlist(cpu));
+	local_irq_restore(flags);
+}
+
+/*
+ * Invoke the completed RCU callbacks. They are expected to be in
+ * a per-cpu list.
+ */
+static void rcu_do_batch(struct list_head *list)
+{
+	struct list_head *entry;
+	struct rcu_head *head;
+
+	while (!list_empty(list)) {
+		entry = list->next;
+		list_del(entry);
+		head = list_entry(entry, struct rcu_head, list);
+		head->func(head->arg);
+	}
+}
+
+/*
+ * Register a new batch of callbacks, and start it up if there is currently no
+ * active batch and the batch to be registered has not already occurred.
+ * Caller must hold the rcu_ctrlblk lock.
+ */
+static void rcu_start_batch(long newbatch)
+{
+	if (rcu_batch_before(rcu_ctrlblk.maxbatch, newbatch)) {
+		rcu_ctrlblk.maxbatch = newbatch;
+	}
+	if (rcu_batch_before(rcu_ctrlblk.maxbatch, rcu_ctrlblk.curbatch) ||
+	    (rcu_ctrlblk.rcu_cpu_mask != 0)) {
+		return;
+	}
+	rcu_ctrlblk.rcu_cpu_mask = cpu_online_map;
+}
+
+/*
+ * Check if the cpu has gone through a quiescent state (say context
+ * switch). If so and if it already hasn't done so in this RCU
+ * quiescent cycle, then indicate that it has done so.
+ */
+static void rcu_check_quiescent_state(void)
+{
+	int cpu = smp_processor_id();
+
+	if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) {
+		return;
+	}
+
+	/* 
+	 * Races with local timer interrupt - in the worst case
+	 * we may miss one quiescent state of that CPU. That is
+	 * tolerable. So no need to disable interrupts.
+	 */
+	if (RCU_last_qsctr(cpu) == RCU_QSCTR_INVALID) {
+		RCU_last_qsctr(cpu) = RCU_qsctr(cpu);
+		return;
+	}
+	if (RCU_qsctr(cpu) == RCU_last_qsctr(cpu)) {
+		return;
+	}
+
+	spin_lock(&rcu_ctrlblk.mutex);
+	if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) {
+		spin_unlock(&rcu_ctrlblk.mutex);
+		return;
+	}
+	clear_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask);
+	RCU_last_qsctr(cpu) = RCU_QSCTR_INVALID;
+	if (rcu_ctrlblk.rcu_cpu_mask != 0) {
+		spin_unlock(&rcu_ctrlblk.mutex);
+		return;
+	}
+	rcu_ctrlblk.curbatch++;
+	rcu_start_batch(rcu_ctrlblk.maxbatch);
+	spin_unlock(&rcu_ctrlblk.mutex);
+}
+
+
+/*
+ * This does the RCU processing work from tasklet context. 
+ */
+static void rcu_process_callbacks(unsigned long unused)
+{
+	int cpu = smp_processor_id();
+	LIST_HEAD(list);
+
+	if (!list_empty(&RCU_curlist(cpu)) &&
+	    rcu_batch_after(rcu_ctrlblk.curbatch, RCU_batch(cpu))) {
+		list_splice(&RCU_curlist(cpu), &list);
+		INIT_LIST_HEAD(&RCU_curlist(cpu));
+	}
+
+	local_irq_disable();
+	if (!list_empty(&RCU_nxtlist(cpu)) && list_empty(&RCU_curlist(cpu))) {
+		list_splice(&RCU_nxtlist(cpu), &RCU_curlist(cpu));
+		INIT_LIST_HEAD(&RCU_nxtlist(cpu));
+		local_irq_enable();
+
+		/*
+		 * start the next batch of callbacks
+		 */
+		spin_lock(&rcu_ctrlblk.mutex);
+		RCU_batch(cpu) = rcu_ctrlblk.curbatch + 1;
+		rcu_start_batch(RCU_batch(cpu));
+		spin_unlock(&rcu_ctrlblk.mutex);
+	} else {
+		local_irq_enable();
+	}
+	rcu_check_quiescent_state();
+	if (!list_empty(&list))
+		rcu_do_batch(&list);
+}
+
+void rcu_check_callbacks(int cpu, int user)
+{
+	if (user || 
+	    (idle_cpu(cpu) && !in_softirq() && hardirq_count() <= 1))
+		RCU_qsctr(cpu)++;
+	tasklet_schedule(&RCU_tasklet(cpu));
+}
+
+/*
+ * Initializes rcu mechanism.  Assumed to be called early.
+ * That is before local timer(SMP) or jiffie timer (uniproc) is setup.
+ * Note that rcu_qsctr and friends are implicitly
+ * initialized due to the choice of ``0'' for RCU_CTR_INVALID.
+ */
+void __init rcu_init(void)
+{
+	int i;
+
+	memset(&rcu_data[0], 0, sizeof(rcu_data));
+	for (i = 0; i < NR_CPUS; i++) {
+		tasklet_init(&RCU_tasklet(i), rcu_process_callbacks, 0UL);
+		INIT_LIST_HEAD(&RCU_nxtlist(i));
+		INIT_LIST_HEAD(&RCU_curlist(i));
+	}
+}
+
+/* Because of FASTCALL declaration of complete, we use this wrapper */
+static void wakeme_after_rcu(void *completion)
+{
+	complete(completion);
+}
+
+/**
+ * synchronize-kernel - wait until all the CPUs have gone
+ * through a "quiescent" state. It may sleep.
+ */
+void synchronize_kernel(void)
+{
+	struct rcu_head rcu;
+	DECLARE_COMPLETION(completion);
+
+	/* Will wake me after RCU finished */
+	call_rcu(&rcu, wakeme_after_rcu, &completion);
+
+	/* Wait for it */
+	wait_for_completion(&completion);
+}
+
+
+EXPORT_SYMBOL(call_rcu);
+EXPORT_SYMBOL(synchronize_kernel);
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Tue Oct 15 20:29:20 2002
+++ b/kernel/sched.c	Tue Oct 15 20:29:20 2002
@@ -31,6 +31,7 @@
 #include <linux/blkdev.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
+#include <linux/rcupdate.h>
 
 /*
  * Convert user-nice values [ -20 ... 0 ... 19 ]
@@ -865,6 +866,9 @@
 	runqueue_t *rq = this_rq();
 	task_t *p = current;
 
+ 	if (rcu_pending(cpu))
+ 		rcu_check_callbacks(cpu, user_ticks);
+
 	if (p == rq->idle) {
 		/* note: this timer irq context must be accounted for as well */
 		if (irq_count() - HARDIRQ_OFFSET >= SOFTIRQ_OFFSET)
@@ -1023,6 +1027,7 @@
 switch_tasks:
 	prefetch(next);
 	clear_tsk_need_resched(prev);
+	RCU_qsctr(prev->thread_info->cpu)++;
 
 	if (likely(prev != next)) {
 		rq->nr_switches++;
diff -Nru a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c	Tue Oct 15 20:29:12 2002
+++ b/kernel/sys.c	Tue Oct 15 20:29:12 2002
@@ -20,6 +20,7 @@
 #include <linux/device.h>
 #include <linux/times.h>
 #include <linux/security.h>
+#include <linux/dcookies.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -202,6 +203,7 @@
 cond_syscall(sys_nfsservctl)
 cond_syscall(sys_quotactl)
 cond_syscall(sys_acct)
+cond_syscall(sys_lookup_dcookie)
 
 static int set_one_prio(struct task_struct *p, int niceval, int error)
 {
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Tue Oct 15 20:29:12 2002
+++ b/kernel/sysctl.c	Tue Oct 15 20:29:12 2002
@@ -50,6 +50,7 @@
 extern int max_queued_signals;
 extern int sysrq_enabled;
 extern int core_uses_pid;
+extern char core_pattern[];
 extern int cad_pid;
 extern int pid_max;
 
@@ -176,6 +177,8 @@
 	 0644, NULL, &proc_dointvec},
 	{KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+	{KERN_CORE_PATTERN, "core_pattern", core_pattern, 64,
+	 0644, NULL, &proc_dostring, &sysctl_string},
 	{KERN_TAINTED, "tainted", &tainted, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
@@ -283,8 +286,8 @@
 	 &dirty_background_ratio, sizeof(dirty_background_ratio),
 	 0644, NULL, &proc_dointvec_minmax,  &sysctl_intvec, NULL,
 	 &zero, &one_hundred },
-	{VM_DIRTY_ASYNC, "dirty_async_ratio", &dirty_async_ratio,
-	 sizeof(dirty_async_ratio), 0644, NULL, &proc_dointvec_minmax,
+	{VM_DIRTY_RATIO, "dirty_ratio", &vm_dirty_ratio,
+	 sizeof(vm_dirty_ratio), 0644, NULL, &proc_dointvec_minmax,
 	 &sysctl_intvec, NULL, &zero, &one_hundred },
 	{VM_DIRTY_WB_CS, "dirty_writeback_centisecs",
 	 &dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644,
@@ -308,6 +311,9 @@
 	{ VM_NR_PDFLUSH_THREADS, "nr_pdflush_threads",
 	  &nr_pdflush_threads, sizeof nr_pdflush_threads,
 	  0444 /* read-only*/, NULL, &proc_dointvec},
+	{VM_SWAPPINESS, "swappiness", &vm_swappiness, sizeof(vm_swappiness),
+	 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero,
+	 &one_hundred },
 #ifdef CONFIG_HUGETLB_PAGE
 	 {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, 
 	  &proc_dointvec},
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Tue Oct 15 20:29:15 2002
+++ b/kernel/timer.c	Tue Oct 15 20:29:15 2002
@@ -406,10 +406,6 @@
 long time_reftime;			/* time at last adjustment (s)	*/
 long time_adjust;
 
-unsigned int * prof_buffer;
-unsigned long prof_len;
-unsigned long prof_shift;
-
 /*
  * this routine handles the overflow of the microsecond field
  *
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Tue Oct 15 20:29:16 2002
+++ b/mm/filemap.c	Tue Oct 15 20:29:16 2002
@@ -20,7 +20,6 @@
 #include <linux/pagemap.h>
 #include <linux/file.h>
 #include <linux/uio.h>
-#include <linux/iobuf.h>
 #include <linux/hash.h>
 #include <linux/writeback.h>
 #include <linux/pagevec.h>
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Tue Oct 15 20:29:16 2002
+++ b/mm/memory.c	Tue Oct 15 20:29:16 2002
@@ -40,7 +40,6 @@
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
-#include <linux/iobuf.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
 #include <linux/vcache.h>
@@ -355,6 +354,9 @@
 				if (!PageReserved(page)) {
 					if (pte_dirty(pte))
 						set_page_dirty(page);
+					if (page->mapping && pte_young(pte) &&
+							!PageSwapCache(page))
+						mark_page_accessed(page);
 					tlb->freed++;
 					page_remove_rmap(page, ptep);
 					tlb_remove_page(tlb, page);
@@ -501,7 +503,7 @@
 /* 
  * Given a physical address, is there a useful struct page pointing to
  * it?  This may become more complex in the future if we start dealing
- * with IO-aperture pages in kiobufs.
+ * with IO-aperture pages for direct-IO.
  */
 
 static inline struct page *get_page_map(struct page *page)
@@ -584,224 +586,6 @@
 	} while(len);
 out:
 	return i;
-}
-
-/*
- * Force in an entire range of pages from the current process's user VA,
- * and pin them in physical memory.  
- */
-#define dprintk(x...)
-
-int map_user_kiobuf(int rw, struct kiobuf *iobuf, unsigned long va, size_t len)
-{
-	int pgcount, err;
-	struct mm_struct *	mm;
-	
-	/* Make sure the iobuf is not already mapped somewhere. */
-	if (iobuf->nr_pages)
-		return -EINVAL;
-
-	mm = current->mm;
-	dprintk ("map_user_kiobuf: begin\n");
-	
-	pgcount = (va + len + PAGE_SIZE - 1)/PAGE_SIZE - va/PAGE_SIZE;
-	/* mapping 0 bytes is not permitted */
-	if (!pgcount) BUG();
-	err = expand_kiobuf(iobuf, pgcount);
-	if (err)
-		return err;
-
-	iobuf->locked = 0;
-	iobuf->offset = va & (PAGE_SIZE-1);
-	iobuf->length = len;
-	
-	/* Try to fault in all of the necessary pages */
-	down_read(&mm->mmap_sem);
-	/* rw==READ means read from disk, write into memory area */
-	err = get_user_pages(current, mm, va, pgcount,
-			(rw==READ), 0, iobuf->maplist, NULL);
-	up_read(&mm->mmap_sem);
-	if (err < 0) {
-		unmap_kiobuf(iobuf);
-		dprintk ("map_user_kiobuf: end %d\n", err);
-		return err;
-	}
-	iobuf->nr_pages = err;
-	while (pgcount--) {
-		/* FIXME: flush superflous for rw==READ,
-		 * probably wrong function for rw==WRITE
-		 */
-		flush_dcache_page(iobuf->maplist[pgcount]);
-	}
-	dprintk ("map_user_kiobuf: end OK\n");
-	return 0;
-}
-
-/*
- * Mark all of the pages in a kiobuf as dirty 
- *
- * We need to be able to deal with short reads from disk: if an IO error
- * occurs, the number of bytes read into memory may be less than the
- * size of the kiobuf, so we have to stop marking pages dirty once the
- * requested byte count has been reached.
- */
-
-void mark_dirty_kiobuf(struct kiobuf *iobuf, int bytes)
-{
-	int index, offset, remaining;
-	struct page *page;
-	
-	index = iobuf->offset >> PAGE_SHIFT;
-	offset = iobuf->offset & ~PAGE_MASK;
-	remaining = bytes;
-	if (remaining > iobuf->length)
-		remaining = iobuf->length;
-	
-	while (remaining > 0 && index < iobuf->nr_pages) {
-		page = iobuf->maplist[index];
-		
-		if (!PageReserved(page))
-			set_page_dirty(page);
-
-		remaining -= (PAGE_SIZE - offset);
-		offset = 0;
-		index++;
-	}
-}
-
-/*
- * Unmap all of the pages referenced by a kiobuf.  We release the pages,
- * and unlock them if they were locked. 
- */
-
-void unmap_kiobuf (struct kiobuf *iobuf) 
-{
-	int i;
-	struct page *map;
-	
-	for (i = 0; i < iobuf->nr_pages; i++) {
-		map = iobuf->maplist[i];
-		if (map) {
-			if (iobuf->locked)
-				unlock_page(map);
-			/* FIXME: cache flush missing for rw==READ
-			 * FIXME: call the correct reference counting function
-			 */
-			page_cache_release(map);
-		}
-	}
-	
-	iobuf->nr_pages = 0;
-	iobuf->locked = 0;
-}
-
-
-/*
- * Lock down all of the pages of a kiovec for IO.
- *
- * If any page is mapped twice in the kiovec, we return the error -EINVAL.
- *
- * The optional wait parameter causes the lock call to block until all
- * pages can be locked if set.  If wait==0, the lock operation is
- * aborted if any locked pages are found and -EAGAIN is returned.
- */
-
-int lock_kiovec(int nr, struct kiobuf *iovec[], int wait)
-{
-	struct kiobuf *iobuf;
-	int i, j;
-	struct page *page, **ppage;
-	int doublepage = 0;
-	int repeat = 0;
-	
- repeat:
-	
-	for (i = 0; i < nr; i++) {
-		iobuf = iovec[i];
-
-		if (iobuf->locked)
-			continue;
-
-		ppage = iobuf->maplist;
-		for (j = 0; j < iobuf->nr_pages; ppage++, j++) {
-			page = *ppage;
-			if (!page)
-				continue;
-			
-			if (TestSetPageLocked(page)) {
-				while (j--) {
-					struct page *tmp = *--ppage;
-					if (tmp)
-						unlock_page(tmp);
-				}
-				goto retry;
-			}
-		}
-		iobuf->locked = 1;
-	}
-
-	return 0;
-	
- retry:
-	
-	/* 
-	 * We couldn't lock one of the pages.  Undo the locking so far,
-	 * wait on the page we got to, and try again.  
-	 */
-	
-	unlock_kiovec(nr, iovec);
-	if (!wait)
-		return -EAGAIN;
-	
-	/* 
-	 * Did the release also unlock the page we got stuck on?
-	 */
-	if (!PageLocked(page)) {
-		/* 
-		 * If so, we may well have the page mapped twice
-		 * in the IO address range.  Bad news.  Of
-		 * course, it _might_ just be a coincidence,
-		 * but if it happens more than once, chances
-		 * are we have a double-mapped page. 
-		 */
-		if (++doublepage >= 3) 
-			return -EINVAL;
-		
-		/* Try again...  */
-		wait_on_page_locked(page);
-	}
-	
-	if (++repeat < 16)
-		goto repeat;
-	return -EAGAIN;
-}
-
-/*
- * Unlock all of the pages of a kiovec after IO.
- */
-
-int unlock_kiovec(int nr, struct kiobuf *iovec[])
-{
-	struct kiobuf *iobuf;
-	int i, j;
-	struct page *page, **ppage;
-	
-	for (i = 0; i < nr; i++) {
-		iobuf = iovec[i];
-
-		if (!iobuf->locked)
-			continue;
-		iobuf->locked = 0;
-		
-		ppage = iobuf->maplist;
-		for (j = 0; j < iobuf->nr_pages; ppage++, j++) {
-			page = *ppage;
-			if (!page)
-				continue;
-			unlock_page(page);
-		}
-	}
-	return 0;
 }
 
 static inline void zeromap_pte_range(pte_t * pte, unsigned long address,
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Tue Oct 15 20:29:12 2002
+++ b/mm/mmap.c	Tue Oct 15 20:29:12 2002
@@ -16,6 +16,7 @@
 #include <linux/fs.h>
 #include <linux/personality.h>
 #include <linux/security.h>
+#include <linux/profile.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
@@ -1104,6 +1105,10 @@
 	if (mpnt->vm_start >= end)
 		return 0;
 
+	/* Something will probably happen, so notify. */
+	if (mpnt->vm_file && (mpnt->vm_flags & VM_EXEC))
+		profile_exec_unmap(mm);
+ 
 	/*
 	 * If we need to split any vma, do it now to save pain later.
 	 */
@@ -1253,7 +1258,10 @@
 	mmu_gather_t *tlb;
 	struct vm_area_struct * mpnt;
 
+	profile_exit_mmap(mm);
+ 
 	release_segments(mm);
+ 
 	spin_lock(&mm->page_table_lock);
 
 	tlb = tlb_gather_mmu(mm, 1);
diff -Nru a/mm/msync.c b/mm/msync.c
--- a/mm/msync.c	Tue Oct 15 20:29:16 2002
+++ b/mm/msync.c	Tue Oct 15 20:29:16 2002
@@ -137,6 +137,9 @@
 	int ret = 0;
 	struct file * file = vma->vm_file;
 
+	if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED))
+		return -EBUSY;
+
 	if (file && (vma->vm_flags & VM_SHARED)) {
 		ret = filemap_sync(vma, start, end-start, flags);
 
@@ -172,6 +175,8 @@
 	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
 		goto out;
 	if (start & ~PAGE_MASK)
+		goto out;
+	if ((flags & MS_ASYNC) && (flags & MS_SYNC))
 		goto out;
 	error = -ENOMEM;
 	len = (len + ~PAGE_MASK) & PAGE_MASK;
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Tue Oct 15 20:29:19 2002
+++ b/mm/page-writeback.c	Tue Oct 15 20:29:19 2002
@@ -63,9 +63,9 @@
 int dirty_background_ratio = 10;
 
 /*
- * The generator of dirty data starts async writeback at this percentage
+ * The generator of dirty data starts writeback at this percentage
  */
-int dirty_async_ratio = 40;
+int vm_dirty_ratio = 40;
 
 /*
  * The interval between `kupdate'-style writebacks, in centiseconds
@@ -84,9 +84,52 @@
 static void background_writeout(unsigned long _min_pages);
 
 /*
+ * Work out the current dirty-memory clamping and background writeout
+ * thresholds.
+ *
+ * The main aim here is to lower them aggressively if there is a lot of mapped
+ * memory around.  To avoid stressing page reclaim with lots of unreclaimable
+ * pages.  It is better to clamp down on writers than to start swapping, and
+ * performing lots of scanning.
+ *
+ * We only allow 1/2 of the currently-unmapped memory to be dirtied.
+ *
+ * We don't permit the clamping level to fall below 5% - that is getting rather
+ * excessive.
+ *
+ * We make sure that the background writeout level is below the adjusted
+ * clamping level.
+ */
+static void
+get_dirty_limits(struct page_state *ps, long *background, long *dirty)
+{
+	int background_ratio;		/* Percentages */
+	int dirty_ratio;
+	int unmapped_ratio;
+
+	get_page_state(ps);
+
+	unmapped_ratio = 100 - (ps->nr_mapped * 100) / total_pages;
+
+	dirty_ratio = vm_dirty_ratio;
+	if (dirty_ratio > unmapped_ratio / 2)
+		dirty_ratio = unmapped_ratio / 2;
+
+	if (dirty_ratio < 5)
+		dirty_ratio = 5;
+
+	background_ratio = dirty_background_ratio;
+	if (background_ratio >= dirty_ratio)
+		background_ratio = dirty_ratio / 2;
+
+	*background = (background_ratio * total_pages) / 100;
+	*dirty = (dirty_ratio * total_pages) / 100;
+}
+
+/*
  * balance_dirty_pages() must be called by processes which are generating dirty
  * data.  It looks at the number of dirty pages in the machine and will force
- * the caller to perform writeback if the system is over `async_thresh'.
+ * the caller to perform writeback if the system is over `vm_dirty_ratio'.
  * If we're over `background_thresh' then pdflush is woken to perform some
  * writeout.
  */
@@ -94,33 +137,31 @@
 {
 	struct page_state ps;
 	long background_thresh;
-	long async_thresh;
-	unsigned long dirty_and_writeback;
-	struct backing_dev_info *bdi;
-
-	get_page_state(&ps);
-	dirty_and_writeback = ps.nr_dirty + ps.nr_writeback;
-
-	background_thresh = (dirty_background_ratio * total_pages) / 100;
-	async_thresh = (dirty_async_ratio * total_pages) / 100;
-	bdi = mapping->backing_dev_info;
+	long dirty_thresh;
+	struct backing_dev_info *bdi = mapping->backing_dev_info;
 
-	if (dirty_and_writeback > async_thresh) {
+	get_dirty_limits(&ps, &background_thresh, &dirty_thresh);
+	while (ps.nr_dirty + ps.nr_writeback > dirty_thresh) {
 		struct writeback_control wbc = {
 			.bdi		= bdi,
 			.sync_mode	= WB_SYNC_NONE,
 			.older_than_this = NULL,
 			.nr_to_write	= sync_writeback_pages(),
 		};
-		if (!dirty_exceeded)
-			dirty_exceeded = 1;
-		writeback_inodes(&wbc);
-		get_page_state(&ps);
-	} else {
-		if (dirty_exceeded)
-			dirty_exceeded = 0;
+
+		dirty_exceeded = 1;
+
+		if (ps.nr_dirty)
+			writeback_inodes(&wbc);
+
+		get_dirty_limits(&ps, &background_thresh, &dirty_thresh);
+		if (ps.nr_dirty + ps.nr_writeback <= dirty_thresh)
+			break;
+		blk_congestion_wait(WRITE, HZ/10);
 	}
 
+	dirty_exceeded = 0;
+
 	if (!writeback_in_progress(bdi) && ps.nr_dirty > background_thresh)
 		pdflush_operation(background_writeout, 0);
 }
@@ -168,7 +209,6 @@
 static void background_writeout(unsigned long _min_pages)
 {
 	long min_pages = _min_pages;
-	long background_thresh;
 	struct writeback_control wbc = {
 		.bdi		= NULL,
 		.sync_mode	= WB_SYNC_NONE,
@@ -178,12 +218,12 @@
 	};
 
 	CHECK_EMERGENCY_SYNC
-
-	background_thresh = (dirty_background_ratio * total_pages) / 100;
 	for ( ; ; ) {
 		struct page_state ps;
+		long background_thresh;
+		long dirty_thresh;
 
-		get_page_state(&ps);
+		get_dirty_limits(&ps, &background_thresh, &dirty_thresh);
 		if (ps.nr_dirty < background_thresh && min_pages <= 0)
 			break;
 		wbc.encountered_congestion = 0;
@@ -336,8 +376,8 @@
 	if (correction < 100) {
 		dirty_background_ratio *= correction;
 		dirty_background_ratio /= 100;
-		dirty_async_ratio *= correction;
-		dirty_async_ratio /= 100;
+		vm_dirty_ratio *= correction;
+		vm_dirty_ratio /= 100;
 	}
 
 	init_timer(&wb_timer);
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Tue Oct 15 20:29:12 2002
+++ b/mm/page_alloc.c	Tue Oct 15 20:29:12 2002
@@ -1147,6 +1147,8 @@
 	if (!ps)
 		return ERR_PTR(-ENOMEM);
 	get_full_page_state(ps);
+	ps->pgpgin /= 2;		/* sectors -> kbytes */
+	ps->pgpgout /= 2;
 	return (unsigned long *)ps + *pos;
 }
 
diff -Nru a/mm/swap.c b/mm/swap.c
--- a/mm/swap.c	Tue Oct 15 20:29:16 2002
+++ b/mm/swap.c	Tue Oct 15 20:29:16 2002
@@ -194,8 +194,10 @@
 }
 
 /*
- * Add the passed pages to the inactive_list, then drop the caller's refcount
+ * Add the passed pages to the LRU, then drop the caller's refcount
  * on them.  Reinitialises the caller's pagevec.
+ *
+ * Mapped pages go onto the active list.
  */
 void __pagevec_lru_add(struct pagevec *pvec)
 {
@@ -214,7 +216,13 @@
 		}
 		if (TestSetPageLRU(page))
 			BUG();
-		add_page_to_inactive_list(zone, page);
+		if (page_mapped(page)) {
+			if (TestSetPageActive(page))
+				BUG();
+			add_page_to_active_list(zone, page);
+		} else {
+			add_page_to_inactive_list(zone, page);
+		}
 	}
 	if (zone)
 		spin_unlock_irq(&zone->lru_lock);
diff -Nru a/mm/vcache.c b/mm/vcache.c
--- a/mm/vcache.c	Tue Oct 15 20:29:14 2002
+++ b/mm/vcache.c	Tue Oct 15 20:29:14 2002
@@ -41,14 +41,12 @@
 
 	hash_head = hash_vcache(address, mm);
 
-	list_add(&vcache->hash_entry, hash_head);
+	list_add_tail(&vcache->hash_entry, hash_head);
 }
 
-void detach_vcache(vcache_t *vcache)
+void __detach_vcache(vcache_t *vcache)
 {
-	spin_lock(&vcache_lock);
-	list_del(&vcache->hash_entry);
-	spin_unlock(&vcache_lock);
+	list_del_init(&vcache->hash_entry);
 }
 
 void invalidate_vcache(unsigned long address, struct mm_struct *mm,
@@ -61,12 +59,11 @@
 
 	hash_head = hash_vcache(address, mm);
 	/*
-	 * This is safe, because this path is called with the mm
-	 * semaphore read-held, and the add/remove path calls with the
-	 * mm semaphore write-held. So while other mm's might add new
-	 * entries in parallel, and *this* mm is locked out, so if the
-	 * list is empty now then we do not have to take the vcache
-	 * lock to see it's really empty.
+	 * This is safe, because this path is called with the pagetable
+	 * lock held. So while other mm's might add new entries in
+	 * parallel, *this* mm is locked out, so if the list is empty
+	 * now then we do not have to take the vcache lock to see it's
+	 * really empty.
 	 */
 	if (likely(list_empty(hash_head)))
 		return;
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Tue Oct 15 20:29:12 2002
+++ b/mm/vmscan.c	Tue Oct 15 20:29:12 2002
@@ -35,13 +35,18 @@
 #include <linux/swapops.h>
 
 /*
- * The "priority" of VM scanning is how much of the queues we
- * will scan in one go. A value of 12 for DEF_PRIORITY implies
- * that we'll scan 1/4096th of the queues ("queue_length >> 12")
- * during a normal aging round.
+ * The "priority" of VM scanning is how much of the queues we will scan in one
+ * go. A value of 12 for DEF_PRIORITY implies that we will scan 1/4096th of the
+ * queues ("queue_length >> 12") during an aging round.
  */
 #define DEF_PRIORITY 12
 
+/*
+ * From 0 .. 100.  Higher means more swappy.
+ */
+int vm_swappiness = 60;
+static long total_memory;
+
 #ifdef ARCH_HAS_PREFETCH
 #define prefetch_prev_lru_page(_page, _base, _field)			\
 	do {								\
@@ -72,9 +77,94 @@
 #define prefetchw_prev_lru_page(_page, _base, _field) do { } while (0)
 #endif
 
-#ifndef CONFIG_QUOTA
-#define shrink_dqcache_memory(ratio, gfp_mask) do { } while (0)
-#endif
+/*
+ * The list of shrinker callbacks used by to apply pressure to
+ * ageable caches.
+ */
+struct shrinker {
+	shrinker_t		shrinker;
+	struct list_head	list;
+	int			seeks;	/* seeks to recreate an obj */
+	int			nr;	/* objs pending delete */
+};
+
+static LIST_HEAD(shrinker_list);
+static DECLARE_MUTEX(shrinker_sem);
+
+/*
+ * Add a shrinker callback to be called from the vm
+ */
+struct shrinker *set_shrinker(int seeks, shrinker_t theshrinker)
+{
+        struct shrinker *shrinker;
+
+        shrinker = kmalloc(sizeof(*shrinker), GFP_KERNEL);
+        if (shrinker) {
+	        shrinker->shrinker = theshrinker;
+	        shrinker->seeks = seeks;
+	        shrinker->nr = 0;
+	        down(&shrinker_sem);
+	        list_add(&shrinker->list, &shrinker_list);
+	        up(&shrinker_sem);
+	}
+	return shrinker;
+}
+
+/*
+ * Remove one
+ */
+void remove_shrinker(struct shrinker *shrinker)
+{
+	down(&shrinker_sem);
+	list_del(&shrinker->list);
+	up(&shrinker_sem);
+	kfree(shrinker);
+}
+ 
+#define SHRINK_BATCH 32
+/*
+ * Call the shrink functions to age shrinkable caches
+ *
+ * Here we assume it costs one seek to replace a lru page and that it also
+ * takes a seek to recreate a cache object.  With this in mind we age equal
+ * percentages of the lru and ageable caches.  This should balance the seeks
+ * generated by these structures.
+ *
+ * If the vm encounted mapped pages on the LRU it increase the pressure on
+ * slab to avoid swapping.
+ *
+ * FIXME: do not do for zone highmem
+ */
+static int shrink_slab(int scanned,  unsigned int gfp_mask)
+{
+	struct list_head *lh;
+	int pages;
+
+	if (down_trylock(&shrinker_sem))
+		return 0;
+
+	pages = nr_used_zone_pages();
+	list_for_each(lh, &shrinker_list) {
+		struct shrinker *shrinker;
+		int entries;
+		unsigned long delta;
+
+		shrinker = list_entry(lh, struct shrinker, list);
+		entries = (*shrinker->shrinker)(0, gfp_mask);
+		if (!entries)
+			continue;
+		delta = scanned * shrinker->seeks * entries;
+		shrinker->nr += delta / (pages + 1);
+		if (shrinker->nr > SHRINK_BATCH) {
+			int nr = shrinker->nr;
+
+			shrinker->nr = 0;
+			(*shrinker->shrinker)(nr, gfp_mask);
+		}
+	}
+	up(&shrinker_sem);
+	return 0;
+}
 
 /* Must be called with page's pte_chain_lock held. */
 static inline int page_mapping_inuse(struct page * page)
@@ -101,7 +191,6 @@
 	return page_count(page) - !!PagePrivate(page) == 2;
 }
 
-
 /*
  * shrink_list returns the number of reclaimed pages
  */
@@ -439,7 +528,8 @@
  * But we had to alter page->flags anyway.
  */
 static /* inline */ void
-refill_inactive_zone(struct zone *zone, const int nr_pages_in)
+refill_inactive_zone(struct zone *zone, const int nr_pages_in,
+			struct page_state *ps, int priority)
 {
 	int pgdeactivate = 0;
 	int nr_pages = nr_pages_in;
@@ -448,6 +538,10 @@
 	LIST_HEAD(l_active);	/* Pages to go onto the active_list */
 	struct page *page;
 	struct pagevec pvec;
+	int reclaim_mapped = 0;
+	long mapped_ratio;
+	long distress;
+	long swap_tendency;
 
 	lru_add_drain();
 	spin_lock_irq(&zone->lru_lock);
@@ -469,6 +563,37 @@
 	}
 	spin_unlock_irq(&zone->lru_lock);
 
+	/*
+	 * `distress' is a measure of how much trouble we're having reclaiming
+	 * pages.  0 -> no problems.  100 -> great trouble.
+	 */
+	distress = 100 >> priority;
+
+	/*
+	 * The point of this algorithm is to decide when to start reclaiming
+	 * mapped memory instead of just pagecache.  Work out how much memory
+	 * is mapped.
+	 */
+	mapped_ratio = (ps->nr_mapped * 100) / total_memory;
+
+	/*
+	 * Now decide how much we really want to unmap some pages.  The mapped
+	 * ratio is downgraded - just because there's a lot of mapped memory
+	 * doesn't necessarily mean that page reclaim isn't succeeding.
+	 *
+	 * The distress ratio is important - we don't want to start going oom.
+	 *
+	 * A 100% value of vm_swappiness overrides this algorithm altogether.
+	 */
+	swap_tendency = mapped_ratio / 2 + distress + vm_swappiness;
+
+	/*
+	 * Now use this metric to decide whether to start moving mapped memory
+	 * onto the inactive list.
+	 */
+	if (swap_tendency >= 100)
+		reclaim_mapped = 1;
+
 	while (!list_empty(&l_hold)) {
 		page = list_entry(l_hold.prev, struct page, lru);
 		list_del(&page->lru);
@@ -480,6 +605,10 @@
 				continue;
 			}
 			pte_chain_unlock(page);
+			if (!reclaim_mapped) {
+				list_add(&page->lru, &l_active);
+				continue;
+			}
 		}
 		/*
 		 * FIXME: need to consider page_count(page) here if/when we
@@ -546,7 +675,7 @@
  */
 static /* inline */ int
 shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask,
-		const int nr_pages, int *nr_mapped)
+	const int nr_pages, int *nr_mapped, struct page_state *ps, int priority)
 {
 	unsigned long ratio;
 
@@ -563,37 +692,23 @@
 	ratio = (unsigned long)nr_pages * zone->nr_active /
 				((zone->nr_inactive | 1) * 2);
 	atomic_add(ratio+1, &zone->refill_counter);
-	while (atomic_read(&zone->refill_counter) > SWAP_CLUSTER_MAX) {
-		atomic_sub(SWAP_CLUSTER_MAX, &zone->refill_counter);
-		refill_inactive_zone(zone, SWAP_CLUSTER_MAX);
-	}
-	return shrink_cache(nr_pages, zone, gfp_mask, max_scan, nr_mapped);
-}
-
-/*
- * FIXME: don't do this for ZONE_HIGHMEM
- */
-/*
- * Here we assume it costs one seek to replace a lru page and that it also
- * takes a seek to recreate a cache object.  With this in mind we age equal
- * percentages of the lru and ageable caches.  This should balance the seeks
- * generated by these structures.
- *
- * NOTE: for now I do this for all zones.  If we find this is too aggressive
- * on large boxes we may want to exclude ZONE_HIGHMEM.
- *
- * If we're encountering mapped pages on the LRU then increase the pressure on
- * slab to avoid swapping.
- */
-static void shrink_slab(int total_scanned, int gfp_mask)
-{
-	int shrink_ratio;
-	int pages = nr_used_zone_pages();
+	if (atomic_read(&zone->refill_counter) > SWAP_CLUSTER_MAX) {
+		int count;
 
-	shrink_ratio = (pages / (total_scanned + 1)) + 1;
-	shrink_dcache_memory(shrink_ratio, gfp_mask);
-	shrink_icache_memory(shrink_ratio, gfp_mask);
-	shrink_dqcache_memory(shrink_ratio, gfp_mask);
+		/*
+		 * Don't try to bring down too many pages in one attempt.
+		 * If this fails, the caller will increase `priority' and
+		 * we'll try again, with an increased chance of reclaiming
+		 * mapped memory.
+		 */
+		count = atomic_read(&zone->refill_counter);
+		if (count > SWAP_CLUSTER_MAX * 4)
+			count = SWAP_CLUSTER_MAX * 4;
+		atomic_sub(count, &zone->refill_counter);
+		refill_inactive_zone(zone, count, ps, priority);
+	}
+	return shrink_cache(nr_pages, zone, gfp_mask,
+				max_scan, nr_mapped);
 }
 
 /*
@@ -603,7 +718,8 @@
  */
 static int
 shrink_caches(struct zone *classzone, int priority, int *total_scanned,
-		int gfp_mask, const int nr_pages, int order)
+		int gfp_mask, const int nr_pages, int order,
+		struct page_state *ps)
 {
 	struct zone *first_classzone;
 	struct zone *zone;
@@ -630,7 +746,7 @@
 		if (max_scan < to_reclaim * 2)
 			max_scan = to_reclaim * 2;
 		ret += shrink_zone(zone, max_scan, gfp_mask,
-				to_reclaim, &nr_mapped);
+				to_reclaim, &nr_mapped, ps, priority);
 		*total_scanned += max_scan;
 		*total_scanned += nr_mapped;
 		if (ret >= nr_pages)
@@ -638,7 +754,7 @@
 	}
 	return ret;
 }
-
+ 
 /*
  * This is the main entry point to direct page reclaim.
  *
@@ -666,12 +782,14 @@
 
 	inc_page_state(pageoutrun);
 
-	for (priority = DEF_PRIORITY; priority; priority--) {
+	for (priority = DEF_PRIORITY; priority >= 0; priority--) {
 		int total_scanned = 0;
+		struct page_state ps;
 
+		get_page_state(&ps);
 		nr_reclaimed += shrink_caches(classzone, priority,
 					&total_scanned, gfp_mask,
-					nr_pages, order);
+					nr_pages, order, &ps);
 		if (nr_reclaimed >= nr_pages)
 			return 1;
 		if (total_scanned == 0)
@@ -695,12 +813,19 @@
 }
 
 /*
- * kswapd will work across all this node's zones until they are all at
- * pages_high.
+ * For kswapd, balance_pgdat() will work across all this node's zones until
+ * they are all at pages_high.
+ *
+ * If `nr_pages' is non-zero then it is the number of pages which are to be
+ * reclaimed, regardless of the zone occupancies.  This is a software suspend
+ * special.
+ *
+ * Returns the number of pages which were actually freed.
  */
-static void kswapd_balance_pgdat(pg_data_t *pgdat)
+static int balance_pgdat(pg_data_t *pgdat, int nr_pages, struct page_state *ps)
 {
-	int priority = DEF_PRIORITY;
+	int to_free = nr_pages;
+	int priority;
 	int i;
 
 	for (priority = DEF_PRIORITY; priority; priority--) {
@@ -713,20 +838,23 @@
 			int to_reclaim;
 
 			to_reclaim = zone->pages_high - zone->free_pages;
+			if (nr_pages && to_free > 0)
+				to_reclaim = min(to_free, SWAP_CLUSTER_MAX*8);
 			if (to_reclaim <= 0)
 				continue;
 			success = 0;
 			max_scan = zone->nr_inactive >> priority;
 			if (max_scan < to_reclaim * 2)
 				max_scan = to_reclaim * 2;
-			shrink_zone(zone, max_scan, GFP_KSWAPD,
-					to_reclaim, &nr_mapped);
+			to_free -= shrink_zone(zone, max_scan, GFP_KSWAPD,
+					to_reclaim, &nr_mapped, ps, priority);
 			shrink_slab(max_scan + nr_mapped, GFP_KSWAPD);
 		}
 		if (success)
-			break;	/* All zones are at pages_high */
+			break;
 		blk_congestion_wait(WRITE, HZ/4);
 	}
+	return nr_pages - to_free;
 }
 
 /*
@@ -768,16 +896,45 @@
 	tsk->flags |= PF_MEMALLOC|PF_KSWAPD;
 
 	for ( ; ; ) {
+		struct page_state ps;
+
 		if (current->flags & PF_FREEZE)
 			refrigerator(PF_IOTHREAD);
 		prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
 		schedule();
 		finish_wait(&pgdat->kswapd_wait, &wait);
-		kswapd_balance_pgdat(pgdat);
+		get_page_state(&ps);
+		balance_pgdat(pgdat, 0, &ps);
 		blk_run_queues();
 	}
 }
 
+#ifdef CONFIG_SOFTWARE_SUSPEND
+/*
+ * Try to free `nr_pages' of memory, system-wide.  Returns the number of freed
+ * pages.
+ */
+int shrink_all_memory(int nr_pages)
+{
+	pg_data_t *pgdat;
+	int nr_to_free = nr_pages;
+	int ret = 0;
+
+	for_each_pgdat(pgdat) {
+		int freed;
+		struct page_state ps;
+
+		get_page_state(&ps);
+		freed = balance_pgdat(pgdat, nr_to_free, &ps);
+		ret += freed;
+		nr_to_free -= freed;
+		if (nr_to_free <= 0)
+			break;
+	}
+	return ret;
+}
+#endif
+
 static int __init kswapd_init(void)
 {
 	pg_data_t *pgdat;
@@ -785,6 +942,7 @@
 	swap_setup();
 	for_each_pgdat(pgdat)
 		kernel_thread(kswapd, pgdat, CLONE_KERNEL);
+	total_memory = nr_free_pagecache_pages();
 	return 0;
 }
 
diff -Nru a/net/Makefile b/net/Makefile
--- a/net/Makefile	Tue Oct 15 20:29:16 2002
+++ b/net/Makefile	Tue Oct 15 20:29:16 2002
@@ -27,8 +27,9 @@
 obj-$(CONFIG_ROSE)		+= rose/
 obj-$(CONFIG_AX25)		+= ax25/
 obj-$(CONFIG_IRDA)		+= irda/
-obj-$(CONFIG_BLUEZ)		+= bluetooth/
+obj-$(CONFIG_BT)		+= bluetooth/
 obj-$(CONFIG_SUNRPC)		+= sunrpc/
+obj-$(CONFIG_RXRPC)		+= rxrpc/
 obj-$(CONFIG_ATM)		+= atm/
 obj-$(CONFIG_DECNET)		+= decnet/
 obj-$(CONFIG_ECONET)		+= econet/
diff -Nru a/net/appletalk/ddp.c b/net/appletalk/ddp.c
--- a/net/appletalk/ddp.c	Tue Oct 15 20:29:23 2002
+++ b/net/appletalk/ddp.c	Tue Oct 15 20:29:23 2002
@@ -1491,8 +1491,8 @@
 	return 0;
 }
 
-static int atalk_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-			 struct scm_cookie *scm)
+static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+			 int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct atalk_sock *at = at_sk(sk);
@@ -1650,8 +1650,8 @@
 	return len;
 }
 
-static int atalk_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-			 int flags, struct scm_cookie *scm)
+static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+			 int size, int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c	Tue Oct 15 20:29:16 2002
+++ b/net/atm/clip.c	Tue Oct 15 20:29:16 2002
@@ -509,6 +509,7 @@
 	struct atmarp_entry *entry;
 	int error;
 	struct clip_vcc *clip_vcc;
+	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = 1 } } };
 	struct rtable *rt;
 
 	if (vcc->push != clip_push) {
@@ -525,7 +526,7 @@
 		unlink_clip_vcc(clip_vcc);
 		return 0;
 	}
-	error = ip_route_output(&rt,ip,0,1,0);
+	error = ip_route_output_key(&rt,&fl);
 	if (error) return error;
 	neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1);
 	ip_rt_put(rt);
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Tue Oct 15 20:29:23 2002
+++ b/net/atm/common.c	Tue Oct 15 20:29:23 2002
@@ -336,8 +336,8 @@
 }
 
 
-int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len,
-    int flags,struct scm_cookie *scm)
+int atm_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
+		int total_len, int flags, struct scm_cookie *scm)
 {
 	DECLARE_WAITQUEUE(wait,current);
 	struct atm_vcc *vcc;
@@ -417,8 +417,8 @@
 }
 
 
-int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len,
-    struct scm_cookie *scm)
+int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
+		int total_len, struct scm_cookie *scm)
 {
 	DECLARE_WAITQUEUE(wait,current);
 	struct atm_vcc *vcc;
diff -Nru a/net/atm/common.h b/net/atm/common.h
--- a/net/atm/common.h	Tue Oct 15 20:29:19 2002
+++ b/net/atm/common.h	Tue Oct 15 20:29:19 2002
@@ -13,10 +13,10 @@
 int atm_create(struct socket *sock,int protocol,int family);
 int atm_release(struct socket *sock);
 int atm_connect(struct socket *sock,int itf,short vpi,int vci);
-int atm_recvmsg(struct socket *sock,struct msghdr *m,int total_len,
-    int flags,struct scm_cookie *scm);
-int atm_sendmsg(struct socket *sock,struct msghdr *m,int total_len,
-  struct scm_cookie *scm);
+int atm_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
+		int total_len, int flags, struct scm_cookie *scm);
+int atm_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
+		int total_len, struct scm_cookie *scm);
 unsigned int atm_poll(struct file *file,struct socket *sock,poll_table *wait);
 int atm_ioctl(struct socket *sock,unsigned int cmd,unsigned long arg);
 int atm_setsockopt(struct socket *sock,int level,int optname,char *optval,
diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
--- a/net/ax25/af_ax25.c	Tue Oct 15 20:29:21 2002
+++ b/net/ax25/af_ax25.c	Tue Oct 15 20:29:21 2002
@@ -1410,7 +1410,8 @@
 	return err;
 }
 
-static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, int len,
 	struct scm_cookie *scm)
 {
 	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
@@ -1588,8 +1589,8 @@
 	return err;
 }
 
-static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-	int flags, struct scm_cookie *scm)
+static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,
+	struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sk_buff *skb;
diff -Nru a/net/bluetooth/Config.help b/net/bluetooth/Config.help
--- a/net/bluetooth/Config.help	Tue Oct 15 20:29:17 2002
+++ b/net/bluetooth/Config.help	Tue Oct 15 20:29:17 2002
@@ -1,5 +1,5 @@
 Bluetooth subsystem support
-CONFIG_BLUEZ
+CONFIG_BT
   Bluetooth is low-cost, low-power, short-range wireless technology.
   It was designed as a replacement for cables and other short-range
   technologies like IrDA.  Bluetooth operates in personal area range
@@ -7,25 +7,25 @@
   Bluetooth can be found at <http://www.bluetooth.com/>.
 
   Linux Bluetooth subsystem consist of several layers:
-               BlueZ Core (HCI device and connection manager, scheduler)
+               Bluetooth Core (HCI device and connection manager, scheduler)
                HCI Device drivers (interface to the hardware)
                L2CAP Module (L2CAP protocol)
                SCO Module (SCO links)
                RFCOMM Module (RFCOMM protocol)  
                BNEP Module (BNEP protocol)
 
-  Say Y here to enable Linux Bluetooth support and to build BlueZ Core
+  Say Y here to enable Linux Bluetooth support and to build Bluetooth Core
   layer.
 
   To use Linux Bluetooth subsystem, you will need several user-space
   utilities like hciconfig and hcid.  These utilities and updates to
-  Bluetooth kernel modules are provided in the BlueZ package.
+  Bluetooth kernel modules are provided in the BlueZ packages.
   For more information, see <http://bluez.sourceforge.net/>.
 
-  If you want to compile BlueZ Core as module (bluez.o) say M here.
+  If you want to compile Bluetooth Core as module (bluetooth.o) say M here.
 
 L2CAP protocol support
-CONFIG_BLUEZ_L2CAP
+CONFIG_BT_L2CAP
   L2CAP (Logical Link Control and Adaptation Protocol) provides
   connection oriented and connection-less data transport.  L2CAP
   support is required for most Bluetooth applications.
@@ -34,7 +34,7 @@
   compile it as module (l2cap.o).
 
 SCO links support
-CONFIG_BLUEZ_SCO
+CONFIG_BT_SCO
   SCO link provides voice transport over Bluetooth. SCO support is
   required for voice applications like Headset and Audio.
 
diff -Nru a/net/bluetooth/Makefile b/net/bluetooth/Makefile
--- a/net/bluetooth/Makefile	Tue Oct 15 20:29:12 2002
+++ b/net/bluetooth/Makefile	Tue Oct 15 20:29:12 2002
@@ -4,12 +4,12 @@
 
 export-objs := syms.o
 
-obj-$(CONFIG_BLUEZ)		+= bluez.o
-obj-$(CONFIG_BLUEZ_L2CAP)	+= l2cap.o
-obj-$(CONFIG_BLUEZ_SCO)		+= sco.o
-obj-$(CONFIG_BLUEZ_RFCOMM)	+= rfcomm/
-obj-$(CONFIG_BLUEZ_BNEP)	+= bnep/
+obj-$(CONFIG_BT)		+= bluetooth.o
+obj-$(CONFIG_BT_L2CAP)	+= l2cap.o
+obj-$(CONFIG_BT_SCO)		+= sco.o
+obj-$(CONFIG_BT_RFCOMM)	+= rfcomm/
+obj-$(CONFIG_BT_BNEP)	+= bnep/
 
-bluez-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
+bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
--- a/net/bluetooth/af_bluetooth.c	Tue Oct 15 20:29:12 2002
+++ b/net/bluetooth/af_bluetooth.c	Tue Oct 15 20:29:12 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ Bluetooth address family and sockets.
+ *  Bluetooth address family and sockets.
  *
  * $Id: af_bluetooth.c,v 1.3 2002/04/17 17:37:15 maxk Exp $
  */
@@ -51,66 +51,66 @@
 
 #include <net/bluetooth/bluetooth.h>
 
-#ifndef AF_BLUETOOTH_DEBUG
+#ifndef CONFIG_BT_SOCK_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
 
 /* Bluetooth sockets */
-#define BLUEZ_MAX_PROTO	5
-static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
+#define BT_MAX_PROTO	5
+static struct net_proto_family *bt_proto[BT_MAX_PROTO];
 
-static kmem_cache_t *bluez_sock_cache;
+static kmem_cache_t *bt_sock_cache;
 
-int bluez_sock_register(int proto, struct net_proto_family *ops)
+int bt_sock_register(int proto, struct net_proto_family *ops)
 {
-	if (proto >= BLUEZ_MAX_PROTO)
+	if (proto >= BT_MAX_PROTO)
 		return -EINVAL;
 
-	if (bluez_proto[proto])
+	if (bt_proto[proto])
 		return -EEXIST;
 
-	bluez_proto[proto] = ops;
+	bt_proto[proto] = ops;
 	return 0;
 }
 
-int bluez_sock_unregister(int proto)
+int bt_sock_unregister(int proto)
 {
-	if (proto >= BLUEZ_MAX_PROTO)
+	if (proto >= BT_MAX_PROTO)
 		return -EINVAL;
 
-	if (!bluez_proto[proto])
+	if (!bt_proto[proto])
 		return -ENOENT;
 
-	bluez_proto[proto] = NULL;
+	bt_proto[proto] = NULL;
 	return 0;
 }
 
-static int bluez_sock_create(struct socket *sock, int proto)
+static int bt_sock_create(struct socket *sock, int proto)
 {
-	if (proto > BLUEZ_MAX_PROTO)
+	if (proto > BT_MAX_PROTO)
 		return -EINVAL;
 
 #if defined(CONFIG_KMOD)
-	if (!bluez_proto[proto]) {
+	if (!bt_proto[proto]) {
 		char module_name[30];
 		sprintf(module_name, "bt-proto-%d", proto);
 		request_module(module_name);
 	}
 #endif
 
-	if (!bluez_proto[proto])
+	if (!bt_proto[proto])
 		return -ENOENT;
 
-	return bluez_proto[proto]->create(sock, proto);
+	return bt_proto[proto]->create(sock, proto);
 }
 
-struct sock *bluez_sock_alloc(struct socket *sock, int proto, int pi_size, int prio)
+struct sock *bt_sock_alloc(struct socket *sock, int proto, int pi_size, int prio)
 {
 	struct sock *sk;
 	void *pi;
 
-	sk = sk_alloc(PF_BLUETOOTH, prio, sizeof(struct bluez_sock), bluez_sock_cache);
+	sk = sk_alloc(PF_BLUETOOTH, prio, sizeof(struct bt_sock), bt_sock_cache);
 	if (!sk)
 		return NULL;
 	
@@ -125,7 +125,7 @@
 	}
 
 	sock_init_data(sock, sk);
-	INIT_LIST_HEAD(&bluez_sk(sk)->accept_q);
+	INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
 	
 	sk->zapped   = 0;
 	sk->protocol = proto;
@@ -134,7 +134,7 @@
 	return sk;
 }
 
-void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
+void bt_sock_link(struct bt_sock_list *l, struct sock *sk)
 {
 	write_lock_bh(&l->lock);
 	sk->next = l->head;
@@ -143,7 +143,7 @@
 	write_unlock_bh(&l->lock);
 }
 
-void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
+void bt_sock_unlink(struct bt_sock_list *l, struct sock *sk)
 {
 	struct sock **skp;
 
@@ -158,45 +158,45 @@
 	write_unlock_bh(&l->lock);
 }
 
-void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
+void bt_accept_enqueue(struct sock *parent, struct sock *sk)
 {
 	BT_DBG("parent %p, sk %p", parent, sk);
 
 	sock_hold(sk);
-	list_add_tail(&bluez_sk(sk)->accept_q, &bluez_sk(parent)->accept_q);
-	bluez_sk(sk)->parent = parent;
+	list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q);
+	bt_sk(sk)->parent = parent;
 	parent->ack_backlog++;
 }
 
-static void bluez_accept_unlink(struct sock *sk)
+static void bt_accept_unlink(struct sock *sk)
 {
 	BT_DBG("sk %p state %d", sk, sk->state);
 
-	list_del_init(&bluez_sk(sk)->accept_q);
-	bluez_sk(sk)->parent->ack_backlog--;
-	bluez_sk(sk)->parent = NULL;
+	list_del_init(&bt_sk(sk)->accept_q);
+	bt_sk(sk)->parent->ack_backlog--;
+	bt_sk(sk)->parent = NULL;
 	sock_put(sk);
 }
 
-struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
+struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
 {
 	struct list_head *p, *n;
 	struct sock *sk;
 	
 	BT_DBG("parent %p", parent);
 
-	list_for_each_safe(p, n, &bluez_sk(parent)->accept_q) {
-		sk = (struct sock *) list_entry(p, struct bluez_sock, accept_q);
+	list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
+		sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
 		
 		lock_sock(sk);
 		if (sk->state == BT_CLOSED) {
 			release_sock(sk);
-			bluez_accept_unlink(sk);
+			bt_accept_unlink(sk);
 			continue;
 		}
 		
 		if (sk->state == BT_CONNECTED || !newsock) {
-			bluez_accept_unlink(sk);
+			bt_accept_unlink(sk);
 			if (newsock)
 				sock_graft(sk, newsock);
 			release_sock(sk);
@@ -207,7 +207,8 @@
 	return NULL;
 }
 
-int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+	struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
 {
 	int noblock = flags & MSG_DONTWAIT;
 	struct sock *sk = sock->sk;
@@ -241,7 +242,7 @@
 	return err ? : copied;
 }
 
-unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
+unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
 {
 	struct sock *sk = sock->sk;
 	unsigned int mask;
@@ -258,7 +259,7 @@
 		mask |= POLLHUP;
 
 	if (!skb_queue_empty(&sk->receive_queue) || 
-			!list_empty(&bluez_sk(sk)->accept_q) ||
+			!list_empty(&bt_sk(sk)->accept_q) ||
 			(sk->shutdown & RCV_SHUTDOWN))
 		mask |= POLLIN | POLLRDNORM;
 
@@ -276,7 +277,7 @@
 	return mask;
 }
 
-int bluez_sock_w4_connect(struct sock *sk, int flags)
+int bt_sock_w4_connect(struct sock *sk, int flags)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
@@ -315,50 +316,51 @@
 	return err;
 }
 
-struct net_proto_family bluez_sock_family_ops =
+struct net_proto_family bt_sock_family_ops =
 {
-	PF_BLUETOOTH, bluez_sock_create
+	PF_BLUETOOTH, bt_sock_create
 };
 
-static int __init bluez_init(void)
+extern int hci_sock_init(void);
+extern int hci_sock_cleanup(void);
+
+static int __init bt_init(void)
 {
-	BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+	BT_INFO("Bluetooth Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
 		 VERSION);
 	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 
 	proc_mkdir("bluetooth", NULL);
 
 	/* Init socket cache */
-	bluez_sock_cache = kmem_cache_create("bluez_sock",
-			sizeof(struct bluez_sock), 0,
+	bt_sock_cache = kmem_cache_create("bt_sock",
+			sizeof(struct bt_sock), 0,
 			SLAB_HWCACHE_ALIGN, 0, 0);
 
-	if (!bluez_sock_cache) {
-		BT_ERR("BlueZ socket cache creation failed");
+	if (!bt_sock_cache) {
+		BT_ERR("Bluetooth socket cache creation failed");
 		return -ENOMEM;
 	}
 	
-	sock_register(&bluez_sock_family_ops);
+	sock_register(&bt_sock_family_ops);
 
-	hci_core_init();
 	hci_sock_init();
 	return 0;
 }
 
-static void __exit bluez_cleanup(void)
+static void __exit bt_cleanup(void)
 {
 	hci_sock_cleanup();
-	hci_core_cleanup();
 
 	sock_unregister(PF_BLUETOOTH);
-	kmem_cache_destroy(bluez_sock_cache);
+	kmem_cache_destroy(bt_sock_cache);
 
 	remove_proc_entry("bluetooth", NULL);
 }
 
-subsys_initcall(bluez_init);
-module_exit(bluez_cleanup);
+subsys_initcall(bt_init);
+module_exit(bt_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/net/bluetooth/bnep/Config.help b/net/bluetooth/bnep/Config.help
--- a/net/bluetooth/bnep/Config.help	Tue Oct 15 20:29:17 2002
+++ b/net/bluetooth/bnep/Config.help	Tue Oct 15 20:29:17 2002
@@ -1,5 +1,5 @@
 BNEP protocol support
-CONFIG_BLUEZ_BNEP
+CONFIG_BT_BNEP
   BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
   emulation layer on top of Bluetooth. BNEP is required for Bluetooth
   PAN (Personal Area Network).
@@ -12,10 +12,10 @@
   compile it as module (bnep.o).
 
 BNEP multicast filter support
-CONFIG_BLUEZ_BNEP_MC_FILTER
+CONFIG_BT_BNEP_MC_FILTER
   This option enables the multicast filter support for BNEP.
 
 BNEP protocol filter support
-CONFIG_BLUEZ_BNEP_PROTO_FILTER
+CONFIG_BT_BNEP_PROTO_FILTER
   This option enables the protocol filter support for BNEP.
 
diff -Nru a/net/bluetooth/bnep/Config.in b/net/bluetooth/bnep/Config.in
--- a/net/bluetooth/bnep/Config.in	Tue Oct 15 20:29:16 2002
+++ b/net/bluetooth/bnep/Config.in	Tue Oct 15 20:29:16 2002
@@ -1,8 +1,8 @@
 
-dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
+dep_tristate 'BNEP protocol support' CONFIG_BT_BNEP $CONFIG_BT_L2CAP
 
-if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
-   bool '  Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER
-   bool '  Protocol filter support'  CONFIG_BLUEZ_BNEP_PROTO_FILTER
+if [ "$CONFIG_BT_BNEP" != "n" ]; then
+   bool '  Multicast filter support' CONFIG_BT_BNEP_MC_FILTER
+   bool '  Protocol filter support'  CONFIG_BT_BNEP_PROTO_FILTER
 fi
 
diff -Nru a/net/bluetooth/bnep/Makefile b/net/bluetooth/bnep/Makefile
--- a/net/bluetooth/bnep/Makefile	Tue Oct 15 20:29:21 2002
+++ b/net/bluetooth/bnep/Makefile	Tue Oct 15 20:29:21 2002
@@ -2,7 +2,7 @@
 # Makefile for the Linux Bluetooth BNEP layer.
 #
 
-obj-$(CONFIG_BLUEZ_BNEP) += bnep.o
+obj-$(CONFIG_BT_BNEP) += bnep.o
 
 bnep-objs := core.o sock.o netdev.o crc32.o
 
diff -Nru a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
--- a/net/bluetooth/bnep/core.c	Tue Oct 15 20:29:19 2002
+++ b/net/bluetooth/bnep/core.c	Tue Oct 15 20:29:19 2002
@@ -58,7 +58,7 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BLUEZ_BNEP_DEBUG
+#ifndef CONFIG_BT_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
@@ -97,11 +97,26 @@
 
 static int bnep_send(struct bnep_session *s, void *data, size_t len)
 {
+	struct kiocb iocb;
+	struct sock_iocb *si;
 	struct socket *sock = s->sock;
 	struct iovec iv = { data, len };
+	int err;
+
 	s->msg.msg_iov    = &iv;
 	s->msg.msg_iovlen = 1;
-	return sock->ops->sendmsg(sock, &s->msg, len, NULL);
+	init_sync_kiocb(&iocb, NULL);
+	si = kiocb_to_siocb(&iocb);
+	si->scm = NULL;
+	si->sock = sock;
+	si->msg = &s->msg;
+	si->size = len;
+
+	err = sock->ops->sendmsg(&iocb, sock, &s->msg, len, NULL);
+	if (-EIOCBQUEUED == err)
+		err = wait_on_sync_kiocb(&iocb);
+
+	return err;
 }
 
 static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
@@ -129,7 +144,7 @@
 
 	BT_DBG("filter len %d", n);
 
-#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
+#ifdef CONFIG_BT_BNEP_PROTO_FILTER
 	n /= 4;
 	if (n <= BNEP_MAX_PROTO_FILTERS) {
 		struct bnep_proto_filter *f = s->proto_filter;
@@ -171,7 +186,7 @@
 
 	BT_DBG("filter len %d", n);
 
-#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
+#ifdef CONFIG_BT_BNEP_MC_FILTER
 	n /= (ETH_ALEN * 2);
 
 	if (n > 0) {
@@ -426,10 +441,22 @@
 	len += skb->len;
 	
 	/* FIXME: linearize skb */
-	
-	s->msg.msg_iov    = iv;
-	s->msg.msg_iovlen = il;
-	len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
+	{
+		struct kiocb iocb;
+		struct sock_iocb *si;
+	
+		s->msg.msg_iov    = iv;
+		s->msg.msg_iovlen = il;
+		init_sync_kiocb(&iocb, NULL);
+		si = kiocb_to_siocb(&iocb);
+		si->scm = NULL;
+		si->sock = sock;
+		si->msg = &s->msg;
+		si->size = len;
+		len = sock->ops->sendmsg(&iocb, sock, &s->msg, len, NULL);
+		if (-EIOCBQUEUED == len)
+			len = wait_on_sync_kiocb(&iocb);
+	}
 	kfree_skb(skb);
 
 	if (len > 0) {
@@ -452,7 +479,7 @@
 	BT_DBG("");
 
         daemonize();
-	set_user_nice(current, 19);
+	set_user_nice(current, -15);
 	current->flags |= PF_IOTHREAD;
         sigfillset(&current->blocked);
 	flush_signals(current);
@@ -511,8 +538,8 @@
 
 	BT_DBG("");
 
-	baswap((void *) dst, &bluez_sk(sock->sk)->dst);
-	baswap((void *) src, &bluez_sk(sock->sk)->src);
+	baswap((void *) dst, &bt_sk(sock->sk)->dst);
+	baswap((void *) src, &bt_sk(sock->sk)->src);
 
 	s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL);
 	if (!s) 
@@ -545,12 +572,12 @@
 	
 	s->msg.msg_flags = MSG_NOSIGNAL;
 
-#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
+#ifdef CONFIG_BT_BNEP_MC_FILTER
 	/* Set default mc filter */
 	set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
 #endif
 	
-#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
+#ifdef CONFIG_BT_BNEP_PROTO_FILTER
 	/* Set default protocol filter */
 
 	/* (IPv4, ARP)  */
diff -Nru a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
--- a/net/bluetooth/bnep/netdev.c	Tue Oct 15 20:29:19 2002
+++ b/net/bluetooth/bnep/netdev.c	Tue Oct 15 20:29:19 2002
@@ -46,7 +46,7 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BLUEZ_BNEP_DEBUG
+#ifndef CONFIG_BT_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
@@ -73,7 +73,7 @@
 
 static void bnep_net_set_mc_list(struct net_device *dev)
 {
-#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
+#ifdef CONFIG_BT_BNEP_MC_FILTER
 	struct bnep_session *s = dev->priv;
 	struct sock *sk = s->sock->sk;
 	struct bnep_set_filter_req *r;
@@ -143,7 +143,7 @@
 	return -EINVAL;
 }
 
-#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
+#ifdef CONFIG_BT_BNEP_MC_FILTER
 static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
 {
 	struct ethhdr *eh = (void *) skb->data;
@@ -154,7 +154,7 @@
 }
 #endif
 
-#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
+#ifdef CONFIG_BT_BNEP_PROTO_FILTER
 /* Determine ether protocol. Based on eth_type_trans. */
 static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
 {
@@ -192,14 +192,14 @@
 
 	BT_DBG("skb %p, dev %p", skb, dev);
 
-#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
+#ifdef CONFIG_BT_BNEP_MC_FILTER
 	if (bnep_net_mc_filter(skb, s)) {
 		kfree_skb(skb);
 		return 0;
 	}
 #endif
 	
-#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
+#ifdef CONFIG_BT_BNEP_PROTO_FILTER
 	if (bnep_net_proto_filter(skb, s)) {
 		kfree_skb(skb);
 		return 0;
diff -Nru a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
--- a/net/bluetooth/bnep/sock.c	Tue Oct 15 20:29:23 2002
+++ b/net/bluetooth/bnep/sock.c	Tue Oct 15 20:29:23 2002
@@ -50,7 +50,7 @@
 
 #include "bnep.h"
 
-#ifndef CONFIG_BLUEZ_BNEP_DEBUG
+#ifndef CONFIG_BT_BNEP_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
@@ -198,7 +198,7 @@
 	if (sock->type != SOCK_RAW)
 		return -ESOCKTNOSUPPORT;
 
-	if (!(sk = bluez_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
+	if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
 		return -ENOMEM;
 	sock->ops = &bnep_sock_ops;
 
@@ -219,13 +219,13 @@
 
 int bnep_sock_init(void)
 {
-	bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
+	bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
 	return 0;
 }
 
 int bnep_sock_cleanup(void)
 {
-	if (bluez_sock_unregister(BTPROTO_BNEP))
+	if (bt_sock_unregister(BTPROTO_BNEP))
 		BT_ERR("Can't unregister BNEP socket");
 	return 0;
 }
diff -Nru a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
--- a/net/bluetooth/hci_conn.c	Tue Oct 15 20:29:23 2002
+++ b/net/bluetooth/hci_conn.c	Tue Oct 15 20:29:23 2002
@@ -52,7 +52,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef HCI_CORE_DEBUG
+#ifndef CONFIG_BT_HCI_CORE_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
diff -Nru a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
--- a/net/bluetooth/hci_core.c	Tue Oct 15 20:29:14 2002
+++ b/net/bluetooth/hci_core.c	Tue Oct 15 20:29:14 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ HCI Core.
+ * Bluetooth HCI Core.
  *
  * $Id: hci_core.c,v 1.6 2002/04/17 17:37:16 maxk Exp $
  */
@@ -53,7 +53,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef HCI_CORE_DEBUG
+#ifndef CONFIG_BT_HCI_CORE_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
@@ -168,7 +168,7 @@
 
 	switch (hdev->req_status) {
 	case HCI_REQ_DONE:
-		err = -bterr(hdev->req_result);
+		err = -bt_err(hdev->req_result);
 		break;
 
 	case HCI_REQ_CANCELED:
@@ -863,6 +863,22 @@
 	return 0;
 }
 
+/* Suspend HCI device */
+int hci_suspend_dev(struct hci_dev *hdev)
+{
+	hci_notify(hdev, HCI_DEV_SUSPEND);
+	hci_run_hotplug(hdev->name, "suspend");
+	return 0;
+}
+
+/* Resume HCI device */
+int hci_resume_dev(struct hci_dev *hdev)
+{
+	hci_notify(hdev, HCI_DEV_RESUME);
+	hci_run_hotplug(hdev->name, "resume");
+	return 0;
+}       
+
 /* Receive frame from HCI drivers */
 int hci_recv_frame(struct sk_buff *skb)
 {
@@ -877,7 +893,7 @@
 	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
 
 	/* Incomming skb */
-	bluez_cb(skb)->incomming = 1;
+	bt_cb(skb)->incoming = 1;
 
 	/* Time stamp */
 	do_gettimeofday(&skb->stamp);
@@ -1001,7 +1017,7 @@
 
 	BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
 
-	if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
+	if (!(skb = bt_skb_alloc(len, GFP_ATOMIC))) {
 		BT_ERR("%s Can't allocate memory for HCI command", hdev->name);
 		return -ENOMEM;
 	}
@@ -1250,7 +1266,7 @@
 	read_unlock(&hci_task_lock);
 }
 
-/* ----- HCI RX task (incomming data proccessing) ----- */
+/* ----- HCI RX task (incoming data proccessing) ----- */
 
 /* ACL data packet */
 static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1405,16 +1421,4 @@
 			hci_sched_cmd(hdev);
 		}
 	}
-}
-
-/* ---- Initialization ---- */
-
-int hci_core_init(void)
-{
-	return 0;
-}
-
-int hci_core_cleanup(void)
-{
-	return 0;
 }
diff -Nru a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
--- a/net/bluetooth/hci_event.c	Tue Oct 15 20:29:11 2002
+++ b/net/bluetooth/hci_event.c	Tue Oct 15 20:29:11 2002
@@ -52,7 +52,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef HCI_CORE_DEBUG
+#ifndef CONFIG_BT_HCI_CORE_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
@@ -68,7 +68,7 @@
 	default:
 		BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
 		break;
-	};
+	}
 }
 
 /* Command Complete OGF LINK_POLICY  */
@@ -103,7 +103,7 @@
 		BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", 
 				hdev->name, ocf);
 		break;
-	};
+	}
 }
 
 /* Command Complete OGF HOST_CTL  */
@@ -213,7 +213,7 @@
 	default:
 		BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
 		break;
-	};
+	}
 }
 
 /* Command Complete OGF INFO_PARAM  */
@@ -287,7 +287,7 @@
 	default:
 		BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
 		break;
-	};
+	}
 }
 
 /* Command Status OGF LINK_CTL  */
@@ -376,7 +376,7 @@
 		BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", 
 			hdev->name, ocf, status);
 		break;
-	};
+	}
 }
 
 /* Command Status OGF LINK_POLICY */
@@ -388,7 +388,7 @@
 	default:
 		BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
 		break;
-	};
+	}
 }
 
 /* Command Status OGF HOST_CTL */
@@ -400,7 +400,7 @@
 	default:
 		BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
 		break;
-	};
+	}
 }
 
 /* Command Status OGF INFO_PARAM  */
@@ -412,7 +412,7 @@
 	default:
 		BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
 		break;
-	};
+	}
 }
 
 /* Inquiry Complete */
@@ -849,7 +849,7 @@
 	void *ptr;
 
 	size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen;
-	skb  = bluez_skb_alloc(size, GFP_ATOMIC);
+	skb  = bt_skb_alloc(size, GFP_ATOMIC);
 	if (!skb)
 		return;
 
diff -Nru a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
--- a/net/bluetooth/hci_sock.c	Tue Oct 15 20:29:17 2002
+++ b/net/bluetooth/hci_sock.c	Tue Oct 15 20:29:17 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ HCI socket layer.
+ * Bluetooth HCI socket layer.
  *
  * $Id: hci_sock.c,v 1.4 2002/04/18 22:26:14 maxk Exp $
  */
@@ -53,7 +53,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifndef HCI_SOCK_DEBUG
+#ifndef CONFIG_BT_HCI_SOCK_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
@@ -79,7 +79,7 @@
 	}
 };
 
-static struct bluez_sock_list hci_sk_list = {
+static struct bt_sock_list hci_sk_list = {
 	.lock = RW_LOCK_UNLOCKED
 };
 
@@ -144,7 +144,7 @@
 	if (!sk)
 		return 0;
 
-	bluez_sock_unlink(&hci_sk_list, sk);
+	bt_sock_unlink(&hci_sk_list, sk);
 
 	if (hdev) {
 		atomic_dec(&hdev->promisc);
@@ -310,13 +310,13 @@
 	__u32 mask = hci_pi(sk)->cmsg_mask;
 
 	if (mask & HCI_CMSG_DIR)
-        	put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);
+        	put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bt_cb(skb)->incoming);
 
 	if (mask & HCI_CMSG_TSTAMP)
         	put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
 }
  
-static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
 {
 	int noblock = flags & MSG_DONTWAIT;
 	struct sock *sk = sock->sk;
@@ -352,7 +352,7 @@
 	return err ? : copied;
 }
 
-static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int len,
                             struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -378,7 +378,7 @@
 		goto done;
 	}
 
-	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
+	if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
 		goto done;
 
 	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
@@ -454,7 +454,7 @@
 		break;
 
 	case HCI_FILTER:
-		len = MIN(len, sizeof(uf));
+		len = min_t(unsigned int, len, sizeof(uf));
 		if (copy_from_user(&uf, optval, len)) {
 			err = -EFAULT;
 			break;
@@ -472,7 +472,7 @@
 			f->type_mask = uf.type_mask;
 			f->opcode    = uf.opcode;
 			*((u32 *) f->event_mask + 0) = uf.event_mask[0];
-			*((u32 *) f->event_mask + 1) = uf.event_mask[0];
+			*((u32 *) f->event_mask + 1) = uf.event_mask[1];
 		}
 		break; 
 
@@ -522,10 +522,10 @@
 			uf.type_mask = f->type_mask;
 			uf.opcode    = f->opcode;
 			uf.event_mask[0] = *((u32 *) f->event_mask + 0);
-			uf.event_mask[0] = *((u32 *) f->event_mask + 1);
+			uf.event_mask[1] = *((u32 *) f->event_mask + 1);
 		}
 
-		len = MIN(len, sizeof(uf));
+		len = min_t(unsigned int, len, sizeof(uf));
 		if (copy_to_user(optval, &uf, len))
 			return -EFAULT;
 		break;
@@ -568,14 +568,14 @@
 
 	sock->ops = &hci_sock_ops;
 
-	sk = bluez_sock_alloc(sock, protocol, sizeof(struct hci_pinfo), GFP_KERNEL);
+	sk = bt_sock_alloc(sock, protocol, sizeof(struct hci_pinfo), GFP_KERNEL);
 	if (!sk)
 		return -ENOMEM;
 
 	sock->state = SS_UNCONNECTED;
 	sk->state   = BT_OPEN;
 
-	bluez_sock_link(&hci_sk_list, sk);
+	bt_sock_link(&hci_sk_list, sk);
 
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -627,7 +627,7 @@
 
 int hci_sock_init(void)
 {
-	if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
+	if (bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
 		BT_ERR("Can't register HCI socket");
 		return -EPROTO;
 	}
@@ -638,7 +638,7 @@
 
 int hci_sock_cleanup(void)
 {
-	if (bluez_sock_unregister(BTPROTO_HCI))
+	if (bt_sock_unregister(BTPROTO_HCI))
 		BT_ERR("Can't unregister HCI socket");
 
 	hci_unregister_notifier(&hci_sock_nblock);
diff -Nru a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
--- a/net/bluetooth/l2cap.c	Tue Oct 15 20:29:19 2002
+++ b/net/bluetooth/l2cap.c	Tue Oct 15 20:29:19 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ L2CAP core and sockets.
+ * Bluetooth L2CAP core and sockets.
  *
  * $Id: l2cap.c,v 1.15 2002/09/09 01:14:52 maxk Exp $
  */
@@ -57,14 +57,14 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
-#ifndef L2CAP_DEBUG
+#ifndef CONFIG_BT_L2CAP_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
 
 static struct proto_ops l2cap_sock_ops;
 
-struct bluez_sock_list l2cap_sk_list = {
+struct bt_sock_list l2cap_sk_list = {
 	.lock = RW_LOCK_UNLOCKED
 };
 
@@ -188,8 +188,8 @@
 
 int l2cap_connect(struct sock *sk)
 {
-	bdaddr_t *src = &bluez_sk(sk)->src;
-	bdaddr_t *dst = &bluez_sk(sk)->dst;
+	bdaddr_t *src = &bt_sk(sk)->src;
+	bdaddr_t *dst = &bt_sk(sk)->dst;
 	struct l2cap_conn *conn;
 	struct hci_conn   *hcon;
 	struct hci_dev    *hdev;
@@ -248,7 +248,7 @@
 	struct sock *sk;
 	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
 		if (l2cap_pi(sk)->psm == psm &&
-				!bacmp(&bluez_sk(sk)->src, src))
+				!bacmp(&bt_sk(sk)->src, src))
 			break;
 	}
 	return sk;
@@ -267,11 +267,11 @@
 
 		if (l2cap_pi(sk)->psm == psm) {
 			/* Exact match. */
-			if (!bacmp(&bluez_sk(sk)->src, src))
+			if (!bacmp(&bt_sk(sk)->src, src))
 				break;
 
 			/* Closest match */
-			if (!bacmp(&bluez_sk(sk)->src, BDADDR_ANY))
+			if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
 				sk1 = sk;
 		}
 	}
@@ -310,7 +310,7 @@
 	BT_DBG("parent %p", parent);
 
 	/* Close not yet accepted channels */
-	while ((sk = bluez_accept_dequeue(parent, NULL)))
+	while ((sk = bt_accept_dequeue(parent, NULL)))
 		l2cap_sock_close(sk);
 
 	parent->state  = BT_CLOSED;
@@ -328,7 +328,7 @@
 	BT_DBG("sk %p state %d", sk, sk->state);
 
 	/* Kill poor orphan */
-	bluez_sock_unlink(&l2cap_sk_list, sk);
+	bt_sock_unlink(&l2cap_sk_list, sk);
 	sk->dead = 1;
 	sock_put(sk);
 }
@@ -409,7 +409,7 @@
 {
 	struct sock *sk;
 
-	sk = bluez_sock_alloc(sock, proto, sizeof(struct l2cap_pinfo), prio);
+	sk = bt_sock_alloc(sock, proto, sizeof(struct l2cap_pinfo), prio);
 	if (!sk)
 		return NULL;
 
@@ -421,7 +421,7 @@
 
 	l2cap_sock_init_timer(sk);
 
-	bluez_sock_link(&l2cap_sk_list, sk);
+	bt_sock_link(&l2cap_sk_list, sk);
 
 	MOD_INC_USE_COUNT;
 	return sk;
@@ -471,7 +471,7 @@
 		err = -EADDRINUSE;
 	} else {
 		/* Save source address */
-		bacpy(&bluez_sk(sk)->src, &la->l2_bdaddr);
+		bacpy(&bt_sk(sk)->src, &la->l2_bdaddr);
 		l2cap_pi(sk)->psm = la->l2_psm;
 		sk->state = BT_BOUND;
 	}
@@ -524,14 +524,14 @@
 	}
 
 	/* Set destination address and psm */
-	bacpy(&bluez_sk(sk)->dst, &la->l2_bdaddr);
+	bacpy(&bt_sk(sk)->dst, &la->l2_bdaddr);
 	l2cap_pi(sk)->psm = la->l2_psm;
 
 	if ((err = l2cap_connect(sk)))
 		goto done;
 
 wait:
-	err = bluez_sock_w4_connect(sk, flags);
+	err = bt_sock_w4_connect(sk, flags);
 
 done:
 	release_sock(sk);
@@ -586,7 +586,7 @@
 
 	/* Wait for an incoming connection. (wake-one). */
 	add_wait_queue_exclusive(sk->sleep, &wait);
-	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
+	while (!(nsk = bt_accept_dequeue(sk, newsock))) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (!timeo) {
 			err = -EAGAIN;
@@ -633,15 +633,15 @@
 	*len = sizeof(struct sockaddr_l2);
 
 	if (peer)
-		bacpy(&la->l2_bdaddr, &bluez_sk(sk)->dst);
+		bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
 	else
-		bacpy(&la->l2_bdaddr, &bluez_sk(sk)->src);
+		bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
 
 	la->l2_psm = l2cap_pi(sk)->psm;
 	return 0;
 }
 
-static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	int err = 0;
@@ -682,7 +682,7 @@
 
 	switch (optname) {
 	case L2CAP_OPTIONS:
-		len = MIN(sizeof(opts), optlen);
+		len = min_t(unsigned int, sizeof(opts), optlen);
 		if (copy_from_user((char *)&opts, optval, len)) {
 			err = -EFAULT;
 			break;
@@ -727,7 +727,7 @@
 		opts.omtu     = l2cap_pi(sk)->omtu;
 		opts.flush_to = l2cap_pi(sk)->flush_to;
 
-		len = MIN(len, sizeof(opts));
+		len = min_t(unsigned int, len, sizeof(opts));
 		if (copy_to_user(optval, (char *)&opts, len))
 			err = -EFAULT;
 
@@ -746,7 +746,7 @@
 
 		cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
 
-		len = MIN(len, sizeof(cinfo));
+		len = min_t(unsigned int, len, sizeof(cinfo));
 		if (copy_to_user(optval, (char *)&cinfo, len))
 			err = -EFAULT;
 
@@ -892,7 +892,7 @@
 	__l2cap_chan_link(l, sk);
 
 	if (parent)
-		bluez_accept_enqueue(parent, sk);
+		bt_accept_enqueue(parent, sk);
 }
 
 /* Delete channel. 
@@ -900,7 +900,7 @@
 static void l2cap_chan_del(struct sock *sk, int err)
 {
 	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-	struct sock *parent = bluez_sk(sk)->parent;
+	struct sock *parent = bt_sk(sk)->parent;
 
 	l2cap_sock_clear_timer(sk);
 
@@ -954,7 +954,7 @@
 
 static void l2cap_chan_ready(struct sock *sk)
 {
-	struct sock *parent = bluez_sk(sk)->parent;
+	struct sock *parent = bt_sk(sk)->parent;
 
 	BT_DBG("sk %p, parent %p", sk, parent);
 
@@ -1017,9 +1017,9 @@
 	else
 		hlen = L2CAP_HDR_SIZE;
 
-	count = MIN(conn->mtu - hlen, len);
+	count = min_t(unsigned int, (conn->mtu - hlen), len);
 
-	skb = bluez_skb_send_alloc(sk, hlen + count,
+	skb = bt_skb_send_alloc(sk, hlen + count,
 			msg->msg_flags & MSG_DONTWAIT, &err);
 	if (!skb)
 		return err;
@@ -1043,9 +1043,9 @@
 	/* Continuation fragments (no L2CAP header) */
 	frag = &skb_shinfo(skb)->frag_list;
 	while (len) {
-		count = MIN(conn->mtu, len);
+		count = min_t(unsigned int, conn->mtu, len);
 
-		*frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+		*frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
 		if (!*frag)
 			goto fail;
 		
@@ -1103,9 +1103,9 @@
 	BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
 
 	len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
-	count = MIN(conn->mtu, len);
+	count = min_t(unsigned int, conn->mtu, len);
 	
-	skb = bluez_skb_alloc(count, GFP_ATOMIC);
+	skb = bt_skb_alloc(count, GFP_ATOMIC);
 	if (!skb)
 		return NULL;
 
@@ -1129,9 +1129,9 @@
 	/* Continuation fragments (no L2CAP header) */
 	frag = &skb_shinfo(skb)->frag_list;
 	while (len) {
-		count = MIN(conn->mtu, len);
+		count = min_t(unsigned int, conn->mtu, len);
 
-		*frag = bluez_skb_alloc(count, GFP_ATOMIC);
+		*frag = bt_skb_alloc(count, GFP_ATOMIC);
 		if (!*frag)
 			goto fail;
 		
@@ -1374,8 +1374,8 @@
 	hci_conn_hold(conn->hcon);
 
 	l2cap_sock_init(sk, parent);
-	bacpy(&bluez_sk(sk)->src, conn->src);
-	bacpy(&bluez_sk(sk)->dst, conn->dst);
+	bacpy(&bt_sk(sk)->src, conn->src);
+	bacpy(&bt_sk(sk)->dst, conn->dst);
 	l2cap_pi(sk)->psm  = psm;
 	l2cap_pi(sk)->dcid = scid;
 
@@ -1785,10 +1785,10 @@
 		if (sk->state != BT_LISTEN)
 			continue;
 
-		if (!bacmp(&bluez_sk(sk)->src, bdaddr)) {
+		if (!bacmp(&bt_sk(sk)->src, bdaddr)) {
 			lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
 			exact++;
-		} else if (!bacmp(&bluez_sk(sk)->src, BDADDR_ANY))
+		} else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
 			lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
 	}
 	read_unlock(&l2cap_sk_list.lock);
@@ -1810,7 +1810,7 @@
 		if (conn)
 			l2cap_conn_ready(conn);
 	} else 
-		l2cap_conn_del(hcon, bterr(status));
+		l2cap_conn_del(hcon, bt_err(status));
 	
 	return 0;
 }
@@ -1822,7 +1822,7 @@
 	if (hcon->type != ACL_LINK)
 		return 0;
 
-	l2cap_conn_del(hcon, bterr(reason));
+	l2cap_conn_del(hcon, bt_err(reason));
 	return 0;
 }
 
@@ -1958,7 +1958,7 @@
 		}
 
 		/* Allocate skb for the complete frame (with header) */
-		if (!(conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC)))
+		if (!(conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC)))
 			goto drop;
 
 		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
@@ -1996,7 +1996,7 @@
 }
 
 /* ----- Proc fs support ------ */
-static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
+static int l2cap_sock_dump(char *buf, struct bt_sock_list *list)
 {
 	struct l2cap_pinfo *pi;
 	struct sock *sk;
@@ -2007,7 +2007,7 @@
 	for (sk = list->head; sk; sk = sk->next) {
 		pi = l2cap_pi(sk);
 		ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
-				batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst), 
+				batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), 
 				sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
 				pi->link_mode);
 	}
@@ -2051,8 +2051,8 @@
 	.accept  =      l2cap_sock_accept,
 	.getname =      l2cap_sock_getname,
 	.sendmsg =      l2cap_sock_sendmsg,
-	.recvmsg =      bluez_sock_recvmsg,
-	.poll    =      bluez_sock_poll,
+	.recvmsg =      bt_sock_recvmsg,
+	.poll    =      bt_sock_poll,
 	.mmap    =      sock_no_mmap,
 	.socketpair =   sock_no_socketpair,
 	.ioctl      =   sock_no_ioctl,
@@ -2081,7 +2081,7 @@
 {
 	int err;
 
-	if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
+	if ((err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
 		BT_ERR("Can't register L2CAP socket");
 		return err;
 	}
@@ -2093,7 +2093,7 @@
 
 	create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
 
-	BT_INFO("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
+	BT_INFO("Bluetooth L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
 	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 	return 0;
 }
@@ -2103,7 +2103,7 @@
 	remove_proc_entry("bluetooth/l2cap", NULL);
 
 	/* Unregister socket and protocol */
-	if (bluez_sock_unregister(BTPROTO_L2CAP))
+	if (bt_sock_unregister(BTPROTO_L2CAP))
 		BT_ERR("Can't unregister L2CAP socket");
 
 	if (hci_unregister_proto(&l2cap_hci_proto))
@@ -2114,5 +2114,5 @@
 module_exit(l2cap_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/net/bluetooth/lib.c b/net/bluetooth/lib.c
--- a/net/bluetooth/lib.c	Tue Oct 15 20:29:12 2002
+++ b/net/bluetooth/lib.c	Tue Oct 15 20:29:12 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ kernel library.
+ * Bluetooth kernel library.
  *
  * $Id: lib.c,v 1.1 2002/03/08 21:06:59 maxk Exp $
  */
@@ -35,7 +35,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 
-void bluez_dump(char *pref, __u8 *buf, int count)
+void bt_dump(char *pref, __u8 *buf, int count)
 {
 	char *ptr;
 	char line[100];
@@ -83,7 +83,7 @@
 }
 
 /* Bluetooth error codes to Unix errno mapping */
-int bterr(__u16 code)
+int bt_err(__u16 code)
 {
 	switch (code) {
 	case 0:
@@ -171,5 +171,5 @@
 
 	default:
 		return ENOSYS;
-	};
+	}
 }
diff -Nru a/net/bluetooth/rfcomm/Config.help b/net/bluetooth/rfcomm/Config.help
--- a/net/bluetooth/rfcomm/Config.help	Tue Oct 15 20:29:17 2002
+++ b/net/bluetooth/rfcomm/Config.help	Tue Oct 15 20:29:17 2002
@@ -1,5 +1,5 @@
 RFCOMM protocol support
-CONFIG_BLUEZ_RFCOMM
+CONFIG_BT_RFCOMM
   RFCOMM provides connection oriented stream transport. RFCOMM
   support is required for Dialup Networking, OBEX and other Bluetooth
   applications.
@@ -8,5 +8,5 @@
   compile it as module (rfcomm.o).
 
 RFCOMM TTY emulation support
-CONFIG_BLUEZ_RFCOMM_TTY
+CONFIG_BT_RFCOMM_TTY
   This option enables TTY emulation support for RFCOMM channels.
diff -Nru a/net/bluetooth/rfcomm/Config.in b/net/bluetooth/rfcomm/Config.in
--- a/net/bluetooth/rfcomm/Config.in	Tue Oct 15 20:29:17 2002
+++ b/net/bluetooth/rfcomm/Config.in	Tue Oct 15 20:29:17 2002
@@ -1,7 +1,7 @@
 
-dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
+dep_tristate 'RFCOMM protocol support' CONFIG_BT_RFCOMM $CONFIG_BT_L2CAP
 
-if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
-   bool '  RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY
+if [ "$CONFIG_BT_RFCOMM" != "n" ]; then
+   bool '  RFCOMM TTY support' CONFIG_BT_RFCOMM_TTY
 fi
 
diff -Nru a/net/bluetooth/rfcomm/Makefile b/net/bluetooth/rfcomm/Makefile
--- a/net/bluetooth/rfcomm/Makefile	Tue Oct 15 20:29:19 2002
+++ b/net/bluetooth/rfcomm/Makefile	Tue Oct 15 20:29:19 2002
@@ -2,10 +2,10 @@
 # Makefile for the Linux Bluetooth RFCOMM layer.
 #
 
-obj-$(CONFIG_BLUEZ_RFCOMM) += rfcomm.o
+obj-$(CONFIG_BT_RFCOMM) += rfcomm.o
 
 rfcomm-y				:= core.o sock.o crc.o
-rfcomm-$(CONFIG_BLUEZ_RFCOMM_TTY)	+= tty.o
+rfcomm-$(CONFIG_BT_RFCOMM_TTY)	+= tty.o
 rfcomm-objs				:= $(rfcomm-y)
 
 include $(TOPDIR)/Rules.make
diff -Nru a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
--- a/net/bluetooth/rfcomm/core.c	Tue Oct 15 20:29:11 2002
+++ b/net/bluetooth/rfcomm/core.c	Tue Oct 15 20:29:11 2002
@@ -26,7 +26,7 @@
 */
 
 /*
- * RFCOMM core.
+ * Bluetooth RFCOMM core.
  *
  * $Id: core.c,v 1.42 2002/10/01 23:26:25 maxk Exp $
  */
@@ -53,7 +53,7 @@
 
 #define VERSION "0.3"
 
-#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#ifndef CONFIG_BT_RFCOMM_DEBUG
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
@@ -489,10 +489,10 @@
 {
 	struct rfcomm_session *s;
 	struct list_head *p, *n;
-	struct bluez_sock *sk;
+	struct bt_sock *sk;
 	list_for_each_safe(p, n, &session_list) {
 		s = list_entry(p, struct rfcomm_session, list);
-		sk = bluez_sk(s->sock->sk); 
+		sk = bt_sk(s->sock->sk); 
 
 		if ((!bacmp(src, BDADDR_ANY) || !bacmp(&sk->src, src)) &&
 				!bacmp(&sk->dst, dst))
@@ -577,14 +577,16 @@
 {
 	struct sock *sk = s->sock->sk;
 	if (src)
-		bacpy(src, &bluez_sk(sk)->src);
+		bacpy(src, &bt_sk(sk)->src);
 	if (dst)
-		bacpy(dst, &bluez_sk(sk)->dst);
+		bacpy(dst, &bt_sk(sk)->dst);
 }
 
 /* ---- RFCOMM frame sending ---- */
 static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
 {
+	struct kiocb iocb;
+	struct sock_iocb *si;
 	struct socket *sock = s->sock;
 	struct iovec iv = { data, len };
 	struct msghdr msg;
@@ -595,8 +597,16 @@
 	memset(&msg, 0, sizeof(msg));
 	msg.msg_iovlen = 1;
 	msg.msg_iov = &iv;
-
-	err = sock->ops->sendmsg(sock, &msg, len, 0);
+	init_sync_kiocb(&iocb, NULL);
+	si = kiocb_to_siocb(&iocb);
+	si->scm = NULL;
+	si->sock = sock;
+	si->msg = &msg;
+	si->size = len;
+
+	err = sock->ops->sendmsg(&iocb, sock, &msg, len, NULL);
+	if (-EIOCBQUEUED == err)
+		err = wait_on_sync_kiocb(&iocb);
 	return err;
 }
 
@@ -809,10 +819,13 @@
 
 static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
 {
+	struct kiocb iocb;
+	struct sock_iocb *si;
 	struct socket *sock = s->sock;
 	struct iovec iv[3];
 	struct msghdr msg;
 	unsigned char hdr[5], crc[1];
+	int err;
 
 	if (len > 125)
 		return -EINVAL;
@@ -837,7 +850,18 @@
 	memset(&msg, 0, sizeof(msg));
 	msg.msg_iovlen = 3;
 	msg.msg_iov = iv;
-	return sock->ops->sendmsg(sock, &msg, 6 + len, 0);
+	init_sync_kiocb(&iocb, NULL);
+	si = kiocb_to_siocb(&iocb);
+	si->scm = NULL;
+	si->sock = sock;
+	si->msg = &msg;
+	si->size = 6 + len;
+
+	err = sock->ops->sendmsg(&iocb, sock, &msg, 6 + len, NULL);
+	if (-EIOCBQUEUED == err)
+		err = wait_on_sync_kiocb(&iocb);
+
+	return err;
 }
 
 static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
@@ -1485,7 +1509,7 @@
 
 	/* Fast check for a new connection.
 	 * Avoids unnesesary socket allocations. */
-	if (list_empty(&bluez_sk(sock->sk)->accept_q))
+	if (list_empty(&bt_sk(sock->sk)->accept_q))
 		return;
 
 	BT_DBG("session %p", s);
@@ -1703,7 +1727,7 @@
 			d = list_entry(pp, struct rfcomm_dlc, list);
 
 			ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
-				batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst),
+				batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
 				d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
 		}
 	}
@@ -1747,13 +1771,13 @@
 
 	rfcomm_init_sockets();
 
-#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+#ifdef CONFIG_BT_RFCOMM_TTY
 	rfcomm_init_ttys();
 #endif
 
 	create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
 
-	BT_INFO("BlueZ RFCOMM ver %s", VERSION);
+	BT_INFO("Bluetooth RFCOMM ver %s", VERSION);
 	BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
 	BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
 	return 0;
@@ -1772,7 +1796,7 @@
 
 	remove_proc_entry("bluetooth/rfcomm", NULL);
 
-#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+#ifdef CONFIG_BT_RFCOMM_TTY
 	rfcomm_cleanup_ttys();
 #endif
 
@@ -1784,5 +1808,5 @@
 module_exit(rfcomm_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
--- a/net/bluetooth/rfcomm/sock.c	Tue Oct 15 20:29:17 2002
+++ b/net/bluetooth/rfcomm/sock.c	Tue Oct 15 20:29:17 2002
@@ -52,14 +52,14 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/rfcomm.h>
 
-#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#ifndef CONFIG_BT_RFCOMM_DEBUG
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
 
 static struct proto_ops rfcomm_sock_ops;
 
-static struct bluez_sock_list rfcomm_sk_list = {
+static struct bt_sock_list rfcomm_sk_list = {
 	.lock = RW_LOCK_UNLOCKED
 };
 
@@ -98,10 +98,10 @@
 		sk->err = err;
 	sk->state = d->state;
 
-	parent = bluez_sk(sk)->parent;
+	parent = bt_sk(sk)->parent;
 	if (!parent) {
 		if (d->state == BT_CONNECTED)
-			rfcomm_session_getaddr(d->session, &bluez_sk(sk)->src, NULL);
+			rfcomm_session_getaddr(d->session, &bt_sk(sk)->src, NULL);
 		sk->state_change(sk);
 	} else
 		parent->data_ready(parent, 0);
@@ -122,7 +122,7 @@
 
 	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
 		if (rfcomm_pi(sk)->channel == channel && 
-				!bacmp(&bluez_sk(sk)->src, src))
+				!bacmp(&bt_sk(sk)->src, src))
 			break;
 	}
 
@@ -142,11 +142,11 @@
 
 		if (rfcomm_pi(sk)->channel == channel) {
 			/* Exact match. */
-			if (!bacmp(&bluez_sk(sk)->src, src))
+			if (!bacmp(&bt_sk(sk)->src, src))
 				break;
 
 			/* Closest match */
-			if (!bacmp(&bluez_sk(sk)->src, BDADDR_ANY))
+			if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
 				sk1 = sk;
 		}
 	}
@@ -197,7 +197,7 @@
 	BT_DBG("parent %p", parent);
 
 	/* Close not yet accepted dlcs */
-	while ((sk = bluez_accept_dequeue(parent, NULL)))
+	while ((sk = bt_accept_dequeue(parent, NULL)))
 		rfcomm_sock_close(sk);
 
 	parent->state  = BT_CLOSED;
@@ -215,7 +215,7 @@
 	BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt));
 
 	/* Kill poor orphan */
-	bluez_sock_unlink(&rfcomm_sk_list, sk);
+	bt_sock_unlink(&rfcomm_sk_list, sk);
 	sk->dead = 1;
 	sock_put(sk);
 }
@@ -265,7 +265,7 @@
 	struct rfcomm_dlc *d;
 	struct sock *sk;
 
-	sk = bluez_sock_alloc(sock, BTPROTO_RFCOMM, sizeof(struct rfcomm_pinfo), prio);
+	sk = bt_sock_alloc(sock, BTPROTO_RFCOMM, sizeof(struct rfcomm_pinfo), prio);
 	if (!sk)
 		return NULL;
 
@@ -290,7 +290,7 @@
 	sk->protocol = proto;
 	sk->state    = BT_OPEN;
 
-	bluez_sock_link(&rfcomm_sk_list, sk);
+	bt_sock_link(&rfcomm_sk_list, sk);
 
 	BT_DBG("sk %p", sk);
 
@@ -342,7 +342,7 @@
 		err = -EADDRINUSE;
 	} else {
 		/* Save source address */
-		bacpy(&bluez_sk(sk)->src, &sa->rc_bdaddr);
+		bacpy(&bt_sk(sk)->src, &sa->rc_bdaddr);
 		rfcomm_pi(sk)->channel = sa->rc_channel;
 		sk->state = BT_BOUND;
 	}
@@ -375,12 +375,12 @@
 	lock_sock(sk);
 
 	sk->state = BT_CONNECT;
-	bacpy(&bluez_sk(sk)->dst, &sa->rc_bdaddr);
+	bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
 	rfcomm_pi(sk)->channel = sa->rc_channel;
 
-	err = rfcomm_dlc_open(d, &bluez_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
+	err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
 	if (!err)
-		err = bluez_sock_w4_connect(sk, flags);
+		err = bt_sock_w4_connect(sk, flags);
 
 	release_sock(sk);
 	return err;
@@ -429,7 +429,7 @@
 
 	/* Wait for an incoming connection. (wake-one). */
 	add_wait_queue_exclusive(sk->sleep, &wait);
-	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
+	while (!(nsk = bt_accept_dequeue(sk, newsock))) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (!timeo) {
 			err = -EAGAIN;
@@ -475,16 +475,16 @@
 	sa->rc_family  = AF_BLUETOOTH;
 	sa->rc_channel = rfcomm_pi(sk)->channel;
 	if (peer)
-		bacpy(&sa->rc_bdaddr, &bluez_sk(sk)->dst);
+		bacpy(&sa->rc_bdaddr, &bt_sk(sk)->dst);
 	else
-		bacpy(&sa->rc_bdaddr, &bluez_sk(sk)->src);
+		bacpy(&sa->rc_bdaddr, &bt_sk(sk)->src);
 
 	*len = sizeof(struct sockaddr_rc);
 	return 0;
 }
 
-static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-			       struct scm_cookie *scm)
+static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+			       struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
@@ -557,8 +557,9 @@
 	return timeo;
 }
 
-static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-			       int flags, struct scm_cookie *scm)
+static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+			       struct msghdr *msg, int size, int flags,
+			       struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	int target, err = 0, copied = 0;
@@ -706,7 +707,7 @@
 
 	lock_sock(sk);
 
-#ifdef CONFIG_BLUEZ_RFCOMM_TTY
+#ifdef CONFIG_BT_RFCOMM_TTY
 	err = rfcomm_dev_ioctl(sk, cmd, arg);
 #else
 	err = -EOPNOTSUPP;
@@ -761,12 +762,12 @@
 		goto done;
 
 	rfcomm_sock_init(sk, parent);
-	bacpy(&bluez_sk(sk)->src, &src);
-	bacpy(&bluez_sk(sk)->dst, &dst);
+	bacpy(&bt_sk(sk)->src, &src);
+	bacpy(&bt_sk(sk)->dst, &dst);
 	rfcomm_pi(sk)->channel = channel;
 
 	sk->state = BT_CONFIG;
-	bluez_accept_enqueue(parent, sk);
+	bt_accept_enqueue(parent, sk);
 
 	/* Accept connection and return socket DLC */
 	*d = rfcomm_pi(sk)->dlc;
@@ -780,7 +781,7 @@
 /* ---- Proc fs support ---- */
 int rfcomm_sock_dump(char *buf)
 {
-	struct bluez_sock_list *list = &rfcomm_sk_list;
+	struct bt_sock_list *list = &rfcomm_sk_list;
 	struct rfcomm_pinfo *pi;
 	struct sock *sk;
 	char *ptr = buf;
@@ -790,7 +791,7 @@
 	for (sk = list->head; sk; sk = sk->next) {
 		pi = rfcomm_pi(sk);
 		ptr += sprintf(ptr, "sk  %s %s %d %d\n",
-				batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst),
+				batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
 				sk->state, rfcomm_pi(sk)->channel);
 	}
 
@@ -813,7 +814,7 @@
 	.setsockopt	= rfcomm_sock_setsockopt,
 	.getsockopt	= rfcomm_sock_getsockopt,
 	.ioctl		= rfcomm_sock_ioctl,
-	.poll		= bluez_sock_poll,
+	.poll		= bt_sock_poll,
 	.socketpair	= sock_no_socketpair,
 	.mmap		= sock_no_mmap
 };
@@ -827,7 +828,7 @@
 {
 	int err;
 
-	if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
+	if ((err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
 		BT_ERR("Can't register RFCOMM socket layer");
 		return err;
 	}
@@ -840,6 +841,6 @@
 	int err;
 
 	/* Unregister socket, protocol and notifier */
-	if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
+	if ((err = bt_sock_unregister(BTPROTO_RFCOMM)))
 		BT_ERR("Can't unregister RFCOMM socket layer %d", err);
 }
diff -Nru a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
--- a/net/bluetooth/rfcomm/tty.c	Tue Oct 15 20:29:17 2002
+++ b/net/bluetooth/rfcomm/tty.c	Tue Oct 15 20:29:17 2002
@@ -40,7 +40,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/rfcomm.h>
 
-#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
+#ifndef CONFIG_BT_RFCOMM_DEBUG
 #undef  BT_DBG
 #define BT_DBG(D...)
 #endif
diff -Nru a/net/bluetooth/sco.c b/net/bluetooth/sco.c
--- a/net/bluetooth/sco.c	Tue Oct 15 20:29:14 2002
+++ b/net/bluetooth/sco.c	Tue Oct 15 20:29:14 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ SCO sockets.
+ * Bluetooth SCO sockets.
  *
  * $Id: sco.c,v 1.3 2002/04/17 17:37:16 maxk Exp $
  */
@@ -56,14 +56,14 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/sco.h>
 
-#ifndef SCO_DEBUG
+#ifndef CONFIG_BT_SCO_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #endif
 
 static struct proto_ops sco_sock_ops;
 
-static struct bluez_sock_list sco_sk_list = {
+static struct bt_sock_list sco_sk_list = {
 	.lock = RW_LOCK_UNLOCKED
 };
 
@@ -200,8 +200,8 @@
 
 int sco_connect(struct sock *sk)
 {
-	bdaddr_t *src = &bluez_sk(sk)->src;
-	bdaddr_t *dst = &bluez_sk(sk)->dst;
+	bdaddr_t *src = &bt_sk(sk)->src;
+	bdaddr_t *dst = &bt_sk(sk)->dst;
 	struct sco_conn *conn;
 	struct hci_conn *hcon;
 	struct hci_dev  *hdev;
@@ -258,8 +258,8 @@
 
 	BT_DBG("sk %p len %d", sk, len);
 
-	count = MIN(conn->mtu, len);
-	if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
+	count = min_t(unsigned int, conn->mtu, len);
+	if (!(skb = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
 		return err;
 
 	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
@@ -303,7 +303,7 @@
 	struct sock *sk;
 
 	for (sk = sco_sk_list.head; sk; sk = sk->next) {
-		if (!bacmp(&bluez_sk(sk)->src, ba))
+		if (!bacmp(&bt_sk(sk)->src, ba))
 			break;
 	}
 
@@ -324,11 +324,11 @@
 			continue;
 
 		/* Exact match. */
-		if (!bacmp(&bluez_sk(sk)->src, src))
+		if (!bacmp(&bt_sk(sk)->src, src))
 			break;
 
 		/* Closest match */
-		if (!bacmp(&bluez_sk(sk)->src, BDADDR_ANY))
+		if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
 			sk1 = sk;
 	}
 
@@ -357,7 +357,7 @@
 	BT_DBG("parent %p", parent);
 
 	/* Close not yet accepted channels */
-	while ((sk = bluez_accept_dequeue(parent, NULL)))
+	while ((sk = bt_accept_dequeue(parent, NULL)))
 		sco_sock_close(sk);
 
 	parent->state  = BT_CLOSED;
@@ -375,7 +375,7 @@
 	BT_DBG("sk %p state %d", sk, sk->state);
 
 	/* Kill poor orphan */
-	bluez_sock_unlink(&sco_sk_list, sk);
+	bt_sock_unlink(&sco_sk_list, sk);
 	sk->dead = 1;
 	sock_put(sk);
 }
@@ -429,7 +429,7 @@
 {
 	struct sock *sk;
 
-	sk = bluez_sock_alloc(sock, proto, sizeof(struct sco_pinfo), prio);
+	sk = bt_sock_alloc(sock, proto, sizeof(struct sco_pinfo), prio);
 	if (!sk)
 		return NULL;
 
@@ -439,7 +439,7 @@
 
 	sco_sock_init_timer(sk);
 
-	bluez_sock_link(&sco_sk_list, sk);
+	bt_sock_link(&sco_sk_list, sk);
 
 	MOD_INC_USE_COUNT;
 	return sk;
@@ -490,7 +490,7 @@
 		err = -EADDRINUSE;
 	} else {
 		/* Save source address */
-		bacpy(&bluez_sk(sk)->src, &sa->sco_bdaddr);
+		bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
 		sk->state = BT_BOUND;
 	}
 	
@@ -522,12 +522,12 @@
 	lock_sock(sk);
 
 	/* Set destination address and psm */
-	bacpy(&bluez_sk(sk)->dst, &sa->sco_bdaddr);
+	bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
 
 	if ((err = sco_connect(sk)))
 		goto done;
 
-	err = bluez_sock_w4_connect(sk, flags);
+	err = bt_sock_w4_connect(sk, flags);
 
 done:
 	release_sock(sk);
@@ -577,7 +577,7 @@
 
 	/* Wait for an incoming connection. (wake-one). */
 	add_wait_queue_exclusive(sk->sleep, &wait);
-	while (!(ch = bluez_accept_dequeue(sk, newsock))) {
+	while (!(ch = bt_accept_dequeue(sk, newsock))) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (!timeo) {
 			err = -EAGAIN;
@@ -624,14 +624,14 @@
 	*len = sizeof(struct sockaddr_sco);
 
 	if (peer)
-		bacpy(&sa->sco_bdaddr, &bluez_sk(sk)->dst);
+		bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
 	else
-		bacpy(&sa->sco_bdaddr, &bluez_sk(sk)->src);
+		bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
 
 	return 0;
 }
 
-static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	int err = 0;
@@ -699,7 +699,7 @@
 
 		BT_INFO("mtu %d", opts.mtu);
 
-		len = MIN(len, sizeof(opts));
+		len = min_t(unsigned int, len, sizeof(opts));
 		if (copy_to_user(optval, (char *)&opts, len))
 			err = -EFAULT;
 
@@ -713,7 +713,7 @@
 
 		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
 
-		len = MIN(len, sizeof(cinfo));
+		len = min_t(unsigned int, len, sizeof(cinfo));
 		if (copy_to_user(optval, (char *)&cinfo, len))
 			err = -EFAULT;
 
@@ -751,7 +751,7 @@
 	conn->sk = sk;
 
 	if (parent)
-		bluez_accept_enqueue(parent, sk);
+		bt_accept_enqueue(parent, sk);
 }
 
 /* Delete channel. 
@@ -808,8 +808,8 @@
 
 		sco_sock_init(sk, parent);
 
-		bacpy(&bluez_sk(sk)->src, conn->src);
-		bacpy(&bluez_sk(sk)->dst, conn->dst);
+		bacpy(&bt_sk(sk)->src, conn->src);
+		bacpy(&bt_sk(sk)->dst, conn->dst);
 
 		hci_conn_hold(conn->hcon);
         	__sco_chan_add(conn, sk, parent);
@@ -849,7 +849,7 @@
 		if (conn)
 			sco_conn_ready(conn);
 	} else 
-		sco_conn_del(hcon, bterr(status));
+		sco_conn_del(hcon, bt_err(status));
 	
 	return 0;
 }
@@ -861,7 +861,7 @@
 	if (hcon->type != SCO_LINK)
 		return 0;
 
-	sco_conn_del(hcon, bterr(reason));
+	sco_conn_del(hcon, bt_err(reason));
 	return 0;
 }
 
@@ -885,7 +885,7 @@
 }
 
 /* ----- Proc fs support ------ */
-static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
+static int sco_sock_dump(char *buf, struct bt_sock_list *list)
 {
 	struct sco_pinfo *pi;
 	struct sock *sk;
@@ -896,7 +896,7 @@
 	for (sk = list->head; sk; sk = sk->next) {
 		pi = sco_pi(sk);
 		ptr += sprintf(ptr, "%s %s %d\n",
-				batostr(&bluez_sk(sk)->src), batostr(&bluez_sk(sk)->dst),
+				batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
 				sk->state); 
 	}
 
@@ -940,8 +940,8 @@
 	.accept  =      sco_sock_accept,
 	.getname =      sco_sock_getname,
 	.sendmsg =      sco_sock_sendmsg,
-	.recvmsg =      bluez_sock_recvmsg,
-	.poll    =      bluez_sock_poll,
+	.recvmsg =      bt_sock_recvmsg,
+	.poll    =      bt_sock_poll,
 	.ioctl   =      sock_no_ioctl,
 	.mmap    =      sock_no_mmap,
 	.socketpair =   sock_no_socketpair,
@@ -968,7 +968,7 @@
 {
 	int err;
 
-	if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
+	if ((err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
 		BT_ERR("Can't register SCO socket layer");
 		return err;
 	}
@@ -980,7 +980,7 @@
 
 	create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL);
 
-	BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
+	BT_INFO("Bluetooth SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
 	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
 	return 0;
 }
@@ -992,7 +992,7 @@
 	remove_proc_entry("bluetooth/sco", NULL);
 
 	/* Unregister socket, protocol and notifier */
-	if ((err = bluez_sock_unregister(BTPROTO_SCO)))
+	if ((err = bt_sock_unregister(BTPROTO_SCO)))
 		BT_ERR("Can't unregister SCO socket layer %d", err);
 
 	if ((err = hci_unregister_proto(&sco_hci_proto)))
@@ -1003,5 +1003,5 @@
 module_exit(sco_cleanup);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/net/bluetooth/syms.c b/net/bluetooth/syms.c
--- a/net/bluetooth/syms.c	Tue Oct 15 20:29:17 2002
+++ b/net/bluetooth/syms.c	Tue Oct 15 20:29:17 2002
@@ -23,7 +23,7 @@
 */
 
 /*
- * BlueZ symbols.
+ * Bluetooth symbols.
  *
  * $Id: syms.c,v 1.1 2002/03/08 21:06:59 maxk Exp $
  */
@@ -44,6 +44,9 @@
 /* HCI Core */
 EXPORT_SYMBOL(hci_register_dev);
 EXPORT_SYMBOL(hci_unregister_dev);
+EXPORT_SYMBOL(hci_suspend_dev);
+EXPORT_SYMBOL(hci_resume_dev);
+
 EXPORT_SYMBOL(hci_register_proto);
 EXPORT_SYMBOL(hci_unregister_proto);
 
@@ -59,20 +62,20 @@
 EXPORT_SYMBOL(hci_send_raw);
 EXPORT_SYMBOL(hci_si_event);
 
-/* BlueZ lib */
-EXPORT_SYMBOL(bluez_dump);
+/* Bluetooth lib */
+EXPORT_SYMBOL(bt_dump);
 EXPORT_SYMBOL(baswap);
 EXPORT_SYMBOL(batostr);
-EXPORT_SYMBOL(bterr);
+EXPORT_SYMBOL(bt_err);
 
-/* BlueZ sockets */
-EXPORT_SYMBOL(bluez_sock_register);
-EXPORT_SYMBOL(bluez_sock_unregister);
-EXPORT_SYMBOL(bluez_sock_alloc);
-EXPORT_SYMBOL(bluez_sock_link);
-EXPORT_SYMBOL(bluez_sock_unlink);
-EXPORT_SYMBOL(bluez_sock_recvmsg);
-EXPORT_SYMBOL(bluez_sock_poll);
-EXPORT_SYMBOL(bluez_accept_enqueue);
-EXPORT_SYMBOL(bluez_accept_dequeue);
-EXPORT_SYMBOL(bluez_sock_w4_connect);
+/* Bluetooth sockets */
+EXPORT_SYMBOL(bt_sock_register);
+EXPORT_SYMBOL(bt_sock_unregister);
+EXPORT_SYMBOL(bt_sock_alloc);
+EXPORT_SYMBOL(bt_sock_link);
+EXPORT_SYMBOL(bt_sock_unlink);
+EXPORT_SYMBOL(bt_sock_recvmsg);
+EXPORT_SYMBOL(bt_sock_poll);
+EXPORT_SYMBOL(bt_accept_enqueue);
+EXPORT_SYMBOL(bt_accept_dequeue);
+EXPORT_SYMBOL(bt_sock_w4_connect);
diff -Nru a/net/core/netfilter.c b/net/core/netfilter.c
--- a/net/core/netfilter.c	Tue Oct 15 20:29:16 2002
+++ b/net/core/netfilter.c	Tue Oct 15 20:29:16 2002
@@ -563,13 +563,15 @@
 {
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct rtable *rt;
-	struct rt_key key = { dst:iph->daddr,
-			      src:iph->saddr,
-			      oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
-			      tos:RT_TOS(iph->tos)|RTO_CONN,
+	struct flowi fl = { .nl_u = { .ip4_u =
+				      { .daddr = iph->daddr,
+					.saddr = iph->saddr,
+					.tos = RT_TOS(iph->tos)|RTO_CONN,
 #ifdef CONFIG_IP_ROUTE_FWMARK
-			      fwmark:(*pskb)->nfmark
+					.fwmark = (*pskb)->nfmark
 #endif
+				      } },
+			    .oif = (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
 			    };
 	struct net_device *dev_src = NULL;
 	int err;
@@ -578,10 +580,10 @@
 	   0 or a local address; however some non-standard hacks like
 	   ipt_REJECT.c:send_reset() can cause packets with foreign
            saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */
-	if(key.src && !(dev_src = ip_dev_find(key.src)))
-		key.src = 0;
+	if(fl.fl4_src && !(dev_src = ip_dev_find(fl.fl4_src)))
+		fl.fl4_src = 0;
 
-	if ((err=ip_route_output_key(&rt, &key)) != 0) {
+	if ((err=ip_route_output_key(&rt, &fl)) != 0) {
 		printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n",
 			NIPQUAD(iph->daddr), NIPQUAD(iph->saddr),
 			(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0,
diff -Nru a/net/core/sock.c b/net/core/sock.c
--- a/net/core/sock.c	Tue Oct 15 20:29:19 2002
+++ b/net/core/sock.c	Tue Oct 15 20:29:19 2002
@@ -1047,14 +1047,14 @@
 	return -EOPNOTSUPP;
 }
 
-int sock_no_sendmsg(struct socket *sock, struct msghdr *m, int flags,
-		    struct scm_cookie *scm)
+int sock_no_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
+		    int flags, struct scm_cookie *scm)
 {
 	return -EOPNOTSUPP;
 }
 
-int sock_no_recvmsg(struct socket *sock, struct msghdr *m, int len, int flags,
-		    struct scm_cookie *scm)
+int sock_no_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
+		    int len, int flags, struct scm_cookie *scm)
 {
 	return -EOPNOTSUPP;
 }
diff -Nru a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
--- a/net/decnet/af_decnet.c	Tue Oct 15 20:29:17 2002
+++ b/net/decnet/af_decnet.c	Tue Oct 15 20:29:17 2002
@@ -1733,8 +1733,8 @@
 }
 
 
-static int dn_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-	int flags, struct scm_cookie *scm)
+static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
+	struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct dn_scp *scp = DN_SK(sk);
@@ -1901,8 +1901,8 @@
 	return 0;
 }
 
-static int dn_sendmsg(struct socket *sock, struct msghdr *msg, int size, 
-	   struct scm_cookie *scm)
+static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
+	   struct msghdr *msg, int size, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct dn_scp *scp = DN_SK(sk);
diff -Nru a/net/econet/af_econet.c b/net/econet/af_econet.c
--- a/net/econet/af_econet.c	Tue Oct 15 20:29:17 2002
+++ b/net/econet/af_econet.c	Tue Oct 15 20:29:17 2002
@@ -97,8 +97,9 @@
  *	If necessary we block.
  */
 
-static int econet_recvmsg(struct socket *sock, struct msghdr *msg, int len,
-			  int flags, struct scm_cookie *scm)
+static int econet_recvmsg(struct kiocb *iocb, struct socket *sock,
+			  struct msghdr *msg, int len, int flags,
+			  struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sk_buff *skb;
@@ -230,8 +231,8 @@
  *	and hence whether to use real Econet or the UDP emulation.
  */
 
-static int econet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-			  struct scm_cookie *scm)
+static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
+			  struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sockaddr_ec *saddr=(struct sockaddr_ec *)msg->msg_name;
diff -Nru a/net/ipv4/Makefile b/net/ipv4/Makefile
--- a/net/ipv4/Makefile	Tue Oct 15 20:29:14 2002
+++ b/net/ipv4/Makefile	Tue Oct 15 20:29:14 2002
@@ -4,7 +4,7 @@
 
 obj-y     := utils.o route.o inetpeer.o proc.o protocol.o \
 	     ip_input.o ip_fragment.o ip_forward.o ip_options.o \
-	     ip_output.o ip_sockglue.o \
+	     ip_output.o ip_sockglue.o ip_proc.o \
 	     tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \
 	     tcp_diag.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
 	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o
diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c	Tue Oct 15 20:29:12 2002
+++ b/net/ipv4/af_inet.c	Tue Oct 15 20:29:12 2002
@@ -82,7 +82,6 @@
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
-#include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/init.h>
 #include <linux/poll.h>
@@ -93,6 +92,7 @@
 
 #include <linux/smp_lock.h>
 #include <linux/inet.h>
+#include <linux/igmp.h>
 #include <linux/netdevice.h>
 #include <linux/brlock.h>
 #include <net/ip.h>
@@ -124,12 +124,6 @@
 atomic_t inet_sock_nr;
 #endif
 
-extern int raw_get_info(char *, char **, off_t, int);
-extern int snmp_get_info(char *, char **, off_t, int);
-extern int netstat_get_info(char *, char **, off_t, int);
-extern int afinet_get_info(char *, char **, off_t, int);
-extern int tcp_get_info(char *, char **, off_t, int);
-extern int udp_get_info(char *, char **, off_t, int);
 extern void ip_mc_drop_socket(struct sock *sk);
 
 #ifdef CONFIG_DLCI
@@ -753,22 +747,23 @@
 }
 
 
-
-int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-		 int flags, struct scm_cookie *scm)
+int inet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+		 int size, int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	int addr_len = 0;
-	int err = sk->prot->recvmsg(sk, msg, size, flags & MSG_DONTWAIT,
-				    flags & ~MSG_DONTWAIT, &addr_len);
+	int err;
+
+	err = sk->prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,
+				flags & ~MSG_DONTWAIT, &addr_len);
 	if (err >= 0)
 		msg->msg_namelen = addr_len;
 	return err;
 }
 
 
-int inet_sendmsg(struct socket *sock, struct msghdr *msg, int size,
-		 struct scm_cookie *scm)
+int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+		 int size, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 
@@ -776,7 +771,7 @@
 	if (!inet_sk(sk)->num && inet_autobind(sk))
 		return -EAGAIN;
 
-	return sk->prot->sendmsg(sk, msg, size);
+	return sk->prot->sendmsg(iocb, sk, msg, size);
 }
 
 int inet_shutdown(struct socket *sock, int how)
@@ -1113,10 +1108,6 @@
 	.handler =	icmp_rcv,
 };
 
-/*
- *	Called by socket.c on kernel startup.  
- */
-
 static int __init inet_init(void)
 {
 	struct sk_buff *dummy_skb;
@@ -1211,17 +1202,8 @@
 	ip_mr_init();
 #endif
 
-	/*
-	 *	Create all the /proc entries.
-	 */
-#ifdef CONFIG_PROC_FS
-	proc_net_create ("raw", 0, raw_get_info);
-	proc_net_create ("netstat", 0, netstat_get_info);
-	proc_net_create ("snmp", 0, snmp_get_info);
-	proc_net_create ("sockstat", 0, afinet_get_info);
-	proc_net_create ("tcp", 0, tcp_get_info);
-	proc_net_create ("udp", 0, udp_get_info);
-#endif		/* CONFIG_PROC_FS */
+	ipv4_proc_init();
 	return 0;
 }
+
 module_init(inet_init);
diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c
--- a/net/ipv4/arp.c	Tue Oct 15 20:29:20 2002
+++ b/net/ipv4/arp.c	Tue Oct 15 20:29:20 2002
@@ -66,6 +66,8 @@
  *		Alexey Kuznetsov:	new arp state machine;
  *					now it is in net/core/neighbour.c.
  *		Krzysztof Halasa:	Added Frame Relay ARP support.
+ *		Arnaldo C. Melo :	move proc stuff to seq_file and
+ *					net/ipv4/ip_proc.c
  */
 
 #include <linux/types.h>
@@ -85,7 +87,6 @@
 #include <linux/if_arp.h>
 #include <linux/trdevice.h>
 #include <linux/skbuff.h>
-#include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/init.h>
 #ifdef CONFIG_SYSCTL
@@ -347,11 +348,13 @@
 
 static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
 {
+	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip,
+						 .saddr = tip } } };
 	struct rtable *rt;
 	int flag = 0; 
 	/*unsigned long now; */
 
-	if (ip_route_output(&rt, sip, tip, 0, 0) < 0) 
+	if (ip_route_output_key(&rt, &fl) < 0) 
 		return 1;
 	if (rt->u.dst.dev != dev) { 
 		NET_INC_STATS_BH(ArpFilter);
@@ -849,7 +852,7 @@
 }
 
 /*
- *	User level interface (ioctl, /proc)
+ *	User level interface (ioctl)
  */
 
 /*
@@ -890,8 +893,10 @@
 	if (r->arp_flags & ATF_PERM)
 		r->arp_flags |= ATF_COM;
 	if (dev == NULL) {
+		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
+							 .tos = RTO_ONLINK } } };
 		struct rtable * rt;
-		if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0)
+		if ((err = ip_route_output_key(&rt, &fl)) != 0)
 			return err;
 		dev = rt->u.dst.dev;
 		ip_rt_put(rt);
@@ -914,7 +919,7 @@
 	return err;
 }
 
-static unsigned arp_state_to_flags(struct neighbour *neigh)
+unsigned arp_state_to_flags(struct neighbour *neigh)
 {
 	unsigned flags = 0;
 	if (neigh->nud_state&NUD_PERMANENT)
@@ -974,8 +979,10 @@
 	}
 
 	if (dev == NULL) {
+		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
+							 .tos = RTO_ONLINK } } };
 		struct rtable * rt;
-		if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0)
+		if ((err = ip_route_output_key(&rt, &fl)) != 0)
 			return err;
 		dev = rt->u.dst.dev;
 		ip_rt_put(rt);
@@ -1060,111 +1067,6 @@
 	return err;
 }
 
-/*
- *	Write the contents of the ARP cache to a PROCfs file.
- */
-#ifndef CONFIG_PROC_FS
-static int arp_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	return 0;
-}
-#else
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-static char *ax2asc2(ax25_address *a, char *buf);
-#endif
-#define HBUFFERLEN 30
-
-static int arp_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	char hbuffer[HBUFFERLEN];
-	int i,j,k;
-	const char hexbuf[] = "0123456789ABCDEF";
-	int size = sprintf(buffer, "IP address       HW type     Flags       "
-				   "HW address            Mask     Device\n");
-	int len = size;
-	off_t pos = size;
-
-	for (i = 0; i <= NEIGH_HASHMASK; i++) {
-		struct neighbour *n;
-		read_lock_bh(&arp_tbl.lock);
-		for (n = arp_tbl.hash_buckets[i]; n; n = n->next) {
-			char tbuf[16];
-			struct net_device *dev = n->dev;
-			int hatype = dev->type;
-
-			/* Do not confuse users "arp -a" with magic entries */
-			if (!(n->nud_state & ~NUD_NOARP))
-				continue;
-
-			read_lock(&n->lock);
-			/* Convert hardware address to XX:XX:XX:XX ... form. */
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-			if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM)
-				ax2asc2((ax25_address *)n->ha, hbuffer);
-			else {
-#endif
-			for (k = 0, j = 0; k < HBUFFERLEN - 3 &&
-					   j < dev->addr_len; j++) {
-				hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15];
-				hbuffer[k++] = hexbuf[n->ha[j] & 15];
-				hbuffer[k++] = ':';
-			}
-			hbuffer[--k] = 0;
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-			}
-#endif
-			sprintf(tbuf, "%u.%u.%u.%u",
-				NIPQUAD(*(u32*)n->primary_key));
-			size = sprintf(buffer + len, "%-16s 0x%-10x0x%-10x%s"
-						     "     *        %s\n",
-				       tbuf, hatype, arp_state_to_flags(n), 
-				       hbuffer, dev->name);
-			read_unlock(&n->lock);
-
-			len += size;
-			pos += size;
-		  
-			if (pos <= offset)
-				len = 0;
-			if (pos >= offset + length) {
-				read_unlock_bh(&arp_tbl.lock);
- 				goto done;
-			}
-		}
-		read_unlock_bh(&arp_tbl.lock);
-	}
-
-	for (i = 0; i <= PNEIGH_HASHMASK; i++) {
-		struct pneigh_entry *n;
-		for (n = arp_tbl.phash_buckets[i]; n; n = n->next) {
-			struct net_device *dev = n->dev;
-			int hatype = dev ? dev->type : 0;
-			char tbuf[16];
-			sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key));
-			size = sprintf(buffer + len, "%-16s 0x%-10x0x%-10x%s"
-						     "     *        %s\n",
-					tbuf, hatype, ATF_PUBL | ATF_PERM,
-					"00:00:00:00:00:00",
-					dev ? dev->name : "*");
-			len += size;
-			pos += size;
-		  
-			if (pos <= offset)
-				len = 0;
-			if (pos >= offset+length)
-				goto done;
-		}
-	}
-done:	*start = buffer + len - (pos - offset);	/* Start of wanted data */
-	len = pos - offset;			/* Start slop */
-	if (len > length)
-		len = length;			/* Ending slop */
-	if (len < 0)
-		len = 0;
-	return len;
-}
-#endif
-
 /* Note, that it is not on notifier chain.
    It is necessary, that this routine was called after route cache will be
    flushed.
@@ -1185,54 +1087,13 @@
 	.data =	(void*) 1, /* understand shared skbs */
 };
 
-void __init arp_init (void)
+void __init arp_init(void)
 {
 	neigh_table_init(&arp_tbl);
 
 	dev_add_pack(&arp_packet_type);
-
-	proc_net_create ("arp", 0, arp_get_info);
-
 #ifdef CONFIG_SYSCTL
 	neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
 			      NET_IPV4_NEIGH, "ipv4");
 #endif
 }
-
-
-#ifdef CONFIG_PROC_FS
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-
-/*
- *	ax25 -> ASCII conversion
- */
-char *ax2asc2(ax25_address *a, char *buf)
-{
-	char c, *s;
-	int n;
-
-	for (n = 0, s = buf; n < 6; n++) {
-		c = (a->ax25_call[n] >> 1) & 0x7F;
-
-		if (c != ' ') *s++ = c;
-	}
-	
-	*s++ = '-';
-
-	if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
-		*s++ = '1';
-		n -= 10;
-	}
-	
-	*s++ = n + '0';
-	*s++ = '\0';
-
-	if (*buf == '\0' || *buf == '-')
-	   return "*";
-
-	return buf;
-
-}
-
-#endif
-#endif
diff -Nru a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
--- a/net/ipv4/fib_frontend.c	Tue Oct 15 20:29:23 2002
+++ b/net/ipv4/fib_frontend.c	Tue Oct 15 20:29:23 2002
@@ -31,7 +31,6 @@
 #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
-#include <linux/proc_fs.h>
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/init.h>
@@ -51,8 +50,8 @@
 
 #define RT_TABLE_MIN RT_TABLE_MAIN
 
-struct fib_table *local_table;
-struct fib_table *main_table;
+struct fib_table *ip_fib_local_table;
+struct fib_table *ip_fib_main_table;
 
 #else
 
@@ -88,75 +87,31 @@
 		flushed += tb->tb_flush(tb);
 	}
 #else /* CONFIG_IP_MULTIPLE_TABLES */
-	flushed += main_table->tb_flush(main_table);
-	flushed += local_table->tb_flush(local_table);
+	flushed += ip_fib_main_table->tb_flush(ip_fib_main_table);
+	flushed += ip_fib_local_table->tb_flush(ip_fib_local_table);
 #endif /* CONFIG_IP_MULTIPLE_TABLES */
 
 	if (flushed)
 		rt_cache_flush(-1);
 }
 
-
-#ifdef CONFIG_PROC_FS
-
-/* 
- *	Called from the PROCfs module. This outputs /proc/net/route.
- *
- *	It always works in backward compatibility mode.
- *	The format of the file is not supposed to be changed.
- */
- 
-static int
-fib_get_procinfo(char *buffer, char **start, off_t offset, int length)
-{
-	int first = offset/128;
-	char *ptr = buffer;
-	int count = (length+127)/128;
-	int len;
-
-	*start = buffer + offset%128;
-	
-	if (--first < 0) {
-		sprintf(buffer, "%-127s\n", "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
-		--count;
-		ptr += 128;
-		first = 0;
-  	}
-
-	if (main_table && count > 0) {
-		int n = main_table->tb_get_info(main_table, ptr, first, count);
-		count -= n;
-		ptr += n*128;
-	}
-	len = ptr - *start;
-	if (len >= length)
-		return length;
-	if (len >= 0)
-		return len;
-	return 0;
-}
-
-#endif /* CONFIG_PROC_FS */
-
 /*
  *	Find the first device with a given source address.
  */
 
 struct net_device * ip_dev_find(u32 addr)
 {
-	struct rt_key key;
+	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
 	struct fib_result res;
 	struct net_device *dev = NULL;
 
-	memset(&key, 0, sizeof(key));
-	key.dst = addr;
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 	res.r = NULL;
 #endif
 
-	if (!local_table || local_table->tb_lookup(local_table, &key, &res)) {
+	if (!ip_fib_local_table ||
+	    ip_fib_local_table->tb_lookup(ip_fib_local_table, &fl, &res))
 		return NULL;
-	}
 	if (res.type != RTN_LOCAL)
 		goto out;
 	dev = FIB_RES_DEV(res);
@@ -170,7 +125,7 @@
 
 unsigned inet_addr_type(u32 addr)
 {
-	struct rt_key		key;
+	struct flowi		fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
 	struct fib_result	res;
 	unsigned ret = RTN_BROADCAST;
 
@@ -179,15 +134,14 @@
 	if (MULTICAST(addr))
 		return RTN_MULTICAST;
 
-	memset(&key, 0, sizeof(key));
-	key.dst = addr;
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 	res.r = NULL;
 #endif
 	
-	if (local_table) {
+	if (ip_fib_local_table) {
 		ret = RTN_UNICAST;
-		if (local_table->tb_lookup(local_table, &key, &res) == 0) {
+		if (!ip_fib_local_table->tb_lookup(ip_fib_local_table,
+						   &fl, &res)) {
 			ret = res.type;
 			fib_res_put(&res);
 		}
@@ -207,18 +161,15 @@
 			struct net_device *dev, u32 *spec_dst, u32 *itag)
 {
 	struct in_device *in_dev;
-	struct rt_key key;
+	struct flowi fl = { .nl_u = { .ip4_u =
+				      { .daddr = src,
+					.saddr = dst,
+					.tos = tos } },
+			    .iif = oif };
 	struct fib_result res;
 	int no_addr, rpf;
 	int ret;
 
-	key.dst = src;
-	key.src = dst;
-	key.tos = tos;
-	key.oif = 0;
-	key.iif = oif;
-	key.scope = RT_SCOPE_UNIVERSE;
-
 	no_addr = rpf = 0;
 	read_lock(&inetdev_lock);
 	in_dev = __in_dev_get(dev);
@@ -231,7 +182,7 @@
 	if (in_dev == NULL)
 		goto e_inval;
 
-	if (fib_lookup(&key, &res))
+	if (fib_lookup(&fl, &res))
 		goto last_resort;
 	if (res.type != RTN_UNICAST)
 		goto e_inval_res;
@@ -252,10 +203,10 @@
 		goto last_resort;
 	if (rpf)
 		goto e_inval;
-	key.oif = dev->ifindex;
+	fl.oif = dev->ifindex;
 
 	ret = 0;
-	if (fib_lookup(&key, &res) == 0) {
+	if (fib_lookup(&fl, &res) == 0) {
 		if (res.type == RTN_UNICAST) {
 			*spec_dst = FIB_RES_PREFSRC(res);
 			ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
@@ -643,13 +594,9 @@
 
 void __init ip_fib_init(void)
 {
-#ifdef CONFIG_PROC_FS
-	proc_net_create("route",0,fib_get_procinfo);
-#endif		/* CONFIG_PROC_FS */
-
 #ifndef CONFIG_IP_MULTIPLE_TABLES
-	local_table = fib_hash_init(RT_TABLE_LOCAL);
-	main_table = fib_hash_init(RT_TABLE_MAIN);
+	ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL);
+	ip_fib_main_table  = fib_hash_init(RT_TABLE_MAIN);
 #else
 	fib_rules_init();
 #endif
diff -Nru a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
--- a/net/ipv4/fib_hash.c	Tue Oct 15 20:29:17 2002
+++ b/net/ipv4/fib_hash.c	Tue Oct 15 20:29:17 2002
@@ -266,7 +266,7 @@
 }
 
 static int
-fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
+fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
 {
 	int err;
 	struct fn_zone *fz;
@@ -275,7 +275,7 @@
 	read_lock(&fib_hash_lock);
 	for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
 		struct fib_node *f;
-		fn_key_t k = fz_key(key->dst, fz);
+		fn_key_t k = fz_key(flp->fl4_dst, fz);
 
 		for (f = fz_chain(k, fz); f; f = f->fn_next) {
 			if (!fn_key_eq(k, f->fn_key)) {
@@ -285,17 +285,17 @@
 					continue;
 			}
 #ifdef CONFIG_IP_ROUTE_TOS
-			if (f->fn_tos && f->fn_tos != key->tos)
+			if (f->fn_tos && f->fn_tos != flp->fl4_tos)
 				continue;
 #endif
 			f->fn_state |= FN_S_ACCESSED;
 
 			if (f->fn_state&FN_S_ZOMBIE)
 				continue;
-			if (f->fn_scope < key->scope)
+			if (f->fn_scope < flp->fl4_scope)
 				continue;
 
-			err = fib_semantic_match(f->fn_type, FIB_INFO(f), key, res);
+			err = fib_semantic_match(f->fn_type, FIB_INFO(f), flp, res);
 			if (err == 0) {
 				res->type = f->fn_type;
 				res->scope = f->fn_scope;
@@ -338,7 +338,7 @@
 }
 
 static void
-fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
+fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
 {
 	int order, last_idx;
 	struct fib_node *f;
@@ -747,46 +747,31 @@
 
 #ifdef CONFIG_PROC_FS
 
-static int fn_hash_get_info(struct fib_table *tb, char *buffer, int first, int count)
+static int fn_hash_seq_show(struct fib_table *tb, struct seq_file *seq)
 {
-	struct fn_hash *table = (struct fn_hash*)tb->tb_data;
+	struct fn_hash *table = (struct fn_hash *)tb->tb_data;
 	struct fn_zone *fz;
-	int pos = 0;
-	int n = 0;
 
 	read_lock(&fib_hash_lock);
-	for (fz=table->fn_zone_list; fz; fz = fz->fz_next) {
+	for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
 		int i;
 		struct fib_node *f;
 		int maxslot = fz->fz_divisor;
 		struct fib_node **fp = fz->fz_hash;
 
-		if (fz->fz_nent == 0)
+		if (!fz->fz_nent)
 			continue;
 
-		if (pos + fz->fz_nent <= first) {
-			pos += fz->fz_nent;
-			continue;
-		}
-
-		for (i=0; i < maxslot; i++, fp++) {
-			for (f = *fp; f; f = f->fn_next) {
-				if (++pos <= first)
-					continue;
-				fib_node_get_info(f->fn_type,
-						  f->fn_state&FN_S_ZOMBIE,
+		for (i = 0; i < maxslot; i++, fp++)
+			for (f = *fp; f; f = f->fn_next)
+				fib_node_seq_show(seq, f->fn_type,
+						  f->fn_state & FN_S_ZOMBIE,
 						  FIB_INFO(f),
 						  fz_prefix(f->fn_key, fz),
-						  FZ_MASK(fz), buffer);
-				buffer += 128;
-				if (++n >= count)
-					goto out;
-			}
-		}
+						  FZ_MASK(fz));
 	}
-out:
 	read_unlock(&fib_hash_lock);
-  	return n;
+  	return 0;
 }
 #endif
 
@@ -913,7 +898,7 @@
 	tb->tb_select_default = fn_hash_select_default;
 	tb->tb_dump = fn_hash_dump;
 #ifdef CONFIG_PROC_FS
-	tb->tb_get_info = fn_hash_get_info;
+	tb->tb_seq_show = fn_hash_seq_show;
 #endif
 	memset(tb->tb_data, 0, sizeof(struct fn_hash));
 	return tb;
diff -Nru a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
--- a/net/ipv4/fib_rules.c	Tue Oct 15 20:29:17 2002
+++ b/net/ipv4/fib_rules.c	Tue Oct 15 20:29:17 2002
@@ -307,28 +307,28 @@
 	}
 }
 
-int fib_lookup(const struct rt_key *key, struct fib_result *res)
+int fib_lookup(const struct flowi *flp, struct fib_result *res)
 {
 	int err;
 	struct fib_rule *r, *policy;
 	struct fib_table *tb;
 
-	u32 daddr = key->dst;
-	u32 saddr = key->src;
+	u32 daddr = flp->fl4_dst;
+	u32 saddr = flp->fl4_src;
 
 FRprintk("Lookup: %u.%u.%u.%u <- %u.%u.%u.%u ",
-	NIPQUAD(key->dst), NIPQUAD(key->src));
+	NIPQUAD(flp->fl4_dst), NIPQUAD(flp->fl4_src));
 	read_lock(&fib_rules_lock);
 	for (r = fib_rules; r; r=r->r_next) {
 		if (((saddr^r->r_src) & r->r_srcmask) ||
 		    ((daddr^r->r_dst) & r->r_dstmask) ||
 #ifdef CONFIG_IP_ROUTE_TOS
-		    (r->r_tos && r->r_tos != key->tos) ||
+		    (r->r_tos && r->r_tos != flp->fl4_tos) ||
 #endif
 #ifdef CONFIG_IP_ROUTE_FWMARK
-		    (r->r_fwmark && r->r_fwmark != key->fwmark) ||
+		    (r->r_fwmark && r->r_fwmark != flp->fl4_fwmark) ||
 #endif
-		    (r->r_ifindex && r->r_ifindex != key->iif))
+		    (r->r_ifindex && r->r_ifindex != flp->iif))
 			continue;
 
 FRprintk("tb %d r %d ", r->r_table, r->r_action);
@@ -351,7 +351,7 @@
 
 		if ((tb = fib_get_table(r->r_table)) == NULL)
 			continue;
-		err = tb->tb_lookup(tb, key, res);
+		err = tb->tb_lookup(tb, flp, res);
 		if (err == 0) {
 			res->r = policy;
 			if (policy)
@@ -369,13 +369,13 @@
 	return -ENETUNREACH;
 }
 
-void fib_select_default(const struct rt_key *key, struct fib_result *res)
+void fib_select_default(const struct flowi *flp, struct fib_result *res)
 {
 	if (res->r && res->r->r_action == RTN_UNICAST &&
 	    FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
 		struct fib_table *tb;
 		if ((tb = fib_get_table(res->r->r_table)) != NULL)
-			tb->tb_select_default(tb, key, res);
+			tb->tb_select_default(tb, flp, res);
 	}
 }
 
diff -Nru a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
--- a/net/ipv4/fib_semantics.c	Tue Oct 15 20:29:12 2002
+++ b/net/ipv4/fib_semantics.c	Tue Oct 15 20:29:12 2002
@@ -349,7 +349,6 @@
 	int err;
 
 	if (nh->nh_gw) {
-		struct rt_key key;
 		struct fib_result res;
 
 #ifdef CONFIG_IP_ROUTE_PERVASIVE
@@ -372,16 +371,18 @@
 			nh->nh_scope = RT_SCOPE_LINK;
 			return 0;
 		}
-		memset(&key, 0, sizeof(key));
-		key.dst = nh->nh_gw;
-		key.oif = nh->nh_oif;
-		key.scope = r->rtm_scope + 1;
-
-		/* It is not necessary, but requires a bit of thinking */
-		if (key.scope < RT_SCOPE_LINK)
-			key.scope = RT_SCOPE_LINK;
-		if ((err = fib_lookup(&key, &res)) != 0)
-			return err;
+		{
+			struct flowi fl = { .nl_u = { .ip4_u =
+						      { .daddr = nh->nh_gw,
+							.scope = r->rtm_scope + 1 } },
+					    .oif = nh->nh_oif };
+
+			/* It is not necessary, but requires a bit of thinking */
+			if (fl.fl4_scope < RT_SCOPE_LINK)
+				fl.fl4_scope = RT_SCOPE_LINK;
+			if ((err = fib_lookup(&fl, &res)) != 0)
+				return err;
+		}
 		err = -EINVAL;
 		if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
 			goto out;
@@ -578,7 +579,7 @@
 }
 
 int 
-fib_semantic_match(int type, struct fib_info *fi, const struct rt_key *key, struct fib_result *res)
+fib_semantic_match(int type, struct fib_info *fi, const struct flowi *flp, struct fib_result *res)
 {
 	int err = fib_props[type].error;
 
@@ -603,7 +604,7 @@
 			for_nexthops(fi) {
 				if (nh->nh_flags&RTNH_F_DEAD)
 					continue;
-				if (!key->oif || key->oif == nh->nh_oif)
+				if (!flp->oif || flp->oif == nh->nh_oif)
 					break;
 			}
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
@@ -949,7 +950,7 @@
    fair weighted route distribution.
  */
 
-void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
+void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
 {
 	struct fib_info *fi = res->fi;
 	int w;
@@ -1016,24 +1017,24 @@
 	return flags;
 }
 
-void fib_node_get_info(int type, int dead, struct fib_info *fi, u32 prefix, u32 mask, char *buffer)
+void fib_node_seq_show(struct seq_file *seq, int type, int dead,
+		       struct fib_info *fi, u32 prefix, u32 mask)
 {
-	int len;
+	char bf[128];
 	unsigned flags = fib_flag_trans(type, dead, mask, fi);
 
-	if (fi) {
-		len = sprintf(buffer, "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
-			      fi->fib_dev ? fi->fib_dev->name : "*", prefix,
-			      fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
-			      mask, fi->fib_advmss+40, fi->fib_window, fi->fib_rtt>>3);
-	} else {
-		len = sprintf(buffer, "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
-			      prefix, 0,
-			      flags, 0, 0, 0,
-			      mask, 0, 0, 0);
-	}
-	memset(buffer+len, ' ', 127-len);
-	buffer[127] = '\n';
+	if (fi)
+		snprintf(bf, sizeof(bf),
+			 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+			 fi->fib_dev ? fi->fib_dev->name : "*", prefix,
+			 fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
+			 mask, fi->fib_advmss + 40, fi->fib_window,
+			 fi->fib_rtt >> 3);
+	else
+		snprintf(bf, sizeof(bf),
+			 "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
+			 prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0);
+	seq_printf(seq, "%-127s\n", bf);
 }
 
 #endif
diff -Nru a/net/ipv4/icmp.c b/net/ipv4/icmp.c
--- a/net/ipv4/icmp.c	Tue Oct 15 20:29:21 2002
+++ b/net/ipv4/icmp.c	Tue Oct 15 20:29:21 2002
@@ -418,9 +418,14 @@
 		if (ipc.opt->srr)
 			daddr = icmp_param->replyopts.faddr;
 	}
-	if (ip_route_output(&rt, daddr, rt->rt_spec_dst,
-			    RT_TOS(skb->nh.iph->tos), 0))
-		goto out_unlock;
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = daddr,
+						.saddr = rt->rt_spec_dst,
+						.tos = RT_TOS(skb->nh.iph->tos) } } };
+		if (ip_route_output_key(&rt, &fl))
+			goto out_unlock;
+	}
 	if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
 			       icmp_param->data.icmph.code)) {
 		ip_build_xmit(sk, icmp_glue_bits, icmp_param,
@@ -526,8 +531,8 @@
 	 *	Restore original addresses if packet has been translated.
 	 */
 	if (rt->rt_flags & RTCF_NAT && IPCB(skb_in)->flags & IPSKB_TRANSLATED) {
-		iph->daddr = rt->key.dst;
-		iph->saddr = rt->key.src;
+		iph->daddr = rt->fl.fl4_dst;
+		iph->saddr = rt->fl.fl4_src;
 	}
 #endif
 
@@ -539,9 +544,13 @@
 					   IPTOS_PREC_INTERNETCONTROL) :
 					  iph->tos;
 
-	if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
-		goto out_unlock;
-
+	{
+		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
+							 .saddr = saddr,
+							 .tos = RT_TOS(tos) } } };
+		if (ip_route_output_key(&rt, &fl))
+		    goto out_unlock;
+	}
 	if (ip_options_echo(&icmp_param.replyopts, skb_in))
 		goto ende;
 
@@ -563,9 +572,12 @@
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
 	if (icmp_param.replyopts.srr) {
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = icmp_param.replyopts.faddr,
+						.saddr = saddr,
+						.tos = RT_TOS(tos) } } };
 		ip_rt_put(rt);
-		if (ip_route_output(&rt, icmp_param.replyopts.faddr,
-				    saddr, RT_TOS(tos), 0))
+		if (ip_route_output_key(&rt, &fl))
 			goto out_unlock;
 	}
 
diff -Nru a/net/ipv4/igmp.c b/net/ipv4/igmp.c
--- a/net/ipv4/igmp.c	Tue Oct 15 20:29:23 2002
+++ b/net/ipv4/igmp.c	Tue Oct 15 20:29:23 2002
@@ -207,8 +207,12 @@
 	if (type == IGMP_HOST_LEAVE_MESSAGE)
 		dst = IGMP_ALL_ROUTER;
 
-	if (ip_route_output(&rt, dst, 0, 0, dev->ifindex))
-		return -1;
+	{
+		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst } },
+				    .oif = dev->ifindex };
+		if (ip_route_output_key(&rt, &fl))
+			return -1;
+	}
 	if (rt->rt_src == 0) {
 		ip_rt_put(rt);
 		return -1;
@@ -374,7 +378,7 @@
 	case IGMP_HOST_MEMBERSHIP_REPORT:
 	case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
 		/* Is it our report looped back? */
-		if (((struct rtable*)skb->dst)->key.iif == 0)
+		if (((struct rtable*)skb->dst)->fl.iif == 0)
 			break;
 		igmp_heard_report(in_dev, ih->group);
 		break;
@@ -608,6 +612,8 @@
 
 static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
 {
+	struct flowi fl = { .nl_u = { .ip4_u =
+				      { .daddr = imr->imr_address.s_addr } } };
 	struct rtable *rt;
 	struct net_device *dev = NULL;
 	struct in_device *idev = NULL;
@@ -619,7 +625,7 @@
 		__dev_put(dev);
 	}
 
-	if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) {
+	if (!dev && !ip_route_output_key(&rt, &fl)) {
 		dev = rt->u.dst.dev;
 		ip_rt_put(rt);
 	}
diff -Nru a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
--- a/net/ipv4/ip_gre.c	Tue Oct 15 20:29:19 2002
+++ b/net/ipv4/ip_gre.c	Tue Oct 15 20:29:19 2002
@@ -412,6 +412,7 @@
 	u16 flags;
 	int grehlen = (iph->ihl<<2) + 4;
 	struct sk_buff *skb2;
+	struct flowi fl;
 	struct rtable *rt;
 
 	if (p[1] != htons(ETH_P_IP))
@@ -488,7 +489,10 @@
 	skb2->nh.raw = skb2->data;
 
 	/* Try to guess incoming interface */
-	if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) {
+	memset(&fl, 0, sizeof(fl));
+	fl.fl4_dst = eiph->saddr;
+	fl.fl4_tos = RT_TOS(eiph->tos);
+	if (ip_route_output_key(&rt, &fl)) {
 		kfree_skb(skb2);
 		return;
 	}
@@ -498,7 +502,10 @@
 	if (rt->rt_flags&RTCF_LOCAL) {
 		ip_rt_put(rt);
 		rt = NULL;
-		if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) ||
+		fl.fl4_dst = eiph->daddr;
+		fl.fl4_src = eiph->saddr;
+		fl.fl4_tos = eiph->tos;
+		if (ip_route_output_key(&rt, &fl) ||
 		    rt->u.dst.dev->type != ARPHRD_IPGRE) {
 			ip_rt_put(rt);
 			kfree_skb(skb2);
@@ -619,7 +626,7 @@
 #ifdef CONFIG_NET_IPGRE_BROADCAST
 		if (MULTICAST(iph->daddr)) {
 			/* Looped back packet, drop it! */
-			if (((struct rtable*)skb->dst)->key.iif == 0)
+			if (((struct rtable*)skb->dst)->fl.iif == 0)
 				goto drop;
 			tunnel->stat.multicast++;
 			skb->pkt_type = PACKET_BROADCAST;
@@ -749,9 +756,16 @@
 		tos &= ~1;
 	}
 
-	if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
-		tunnel->stat.tx_carrier_errors++;
-		goto tx_error;
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = dst,
+						.saddr = tiph->saddr,
+						.tos = RT_TOS(tos) } },
+				    .oif = tunnel->parms.link };
+		if (ip_route_output_key(&rt, &fl)) {
+			tunnel->stat.tx_carrier_errors++;
+			goto tx_error;
+		}
 	}
 	tdev = rt->u.dst.dev;
 
@@ -1104,10 +1118,13 @@
 
 	MOD_INC_USE_COUNT;
 	if (MULTICAST(t->parms.iph.daddr)) {
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = t->parms.iph.daddr,
+						.saddr = t->parms.iph.saddr,
+						.tos = RT_TOS(t->parms.iph.tos) } },
+				    .oif = t->parms.link };
 		struct rtable *rt;
-		if (ip_route_output(&rt, t->parms.iph.daddr,
-				    t->parms.iph.saddr, RT_TOS(t->parms.iph.tos), 
-				    t->parms.link)) {
+		if (ip_route_output_key(&rt, &fl)) {
 			MOD_DEC_USE_COUNT;
 			return -EADDRNOTAVAIL;
 		}
@@ -1177,8 +1194,13 @@
 	/* Guess output device to choose reasonable mtu and hard_header_len */
 
 	if (iph->daddr) {
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = iph->daddr,
+						.saddr = iph->saddr,
+						.tos = RT_TOS(iph->tos) } },
+				    .oif = tunnel->parms.link };
 		struct rtable *rt;
-		if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) {
+		if (!ip_route_output_key(&rt, &fl)) {
 			tdev = rt->u.dst.dev;
 			ip_rt_put(rt);
 		}
diff -Nru a/net/ipv4/ip_nat_dumb.c b/net/ipv4/ip_nat_dumb.c
--- a/net/ipv4/ip_nat_dumb.c	Tue Oct 15 20:29:20 2002
+++ b/net/ipv4/ip_nat_dumb.c	Tue Oct 15 20:29:20 2002
@@ -117,23 +117,21 @@
 			if (rt->rt_flags&RTCF_SNAT) {
 				if (ciph->daddr != osaddr) {
 					struct   fib_result res;
-					struct   rt_key key;
 					unsigned flags = 0;
-
-					key.src = ciph->daddr;
-					key.dst = ciph->saddr;
-					key.iif = skb->dev->ifindex;
-					key.oif = 0;
+					struct flowi fl = { .nl_u =
+							    { .ip4_u =
+							      { .daddr = ciph->saddr,
+								.saddr = ciph->daddr,
 #ifdef CONFIG_IP_ROUTE_TOS
-					key.tos = RT_TOS(ciph->tos);
-#endif
-#ifdef CONFIG_IP_ROUTE_FWMARK
-					key.fwmark = 0;
+								.tos = RT_TOS(ciph->tos)
 #endif
+							      } },
+							    .iif = skb->dev->ifindex };
+
 					/* Use fib_lookup() until we get our own
 					 * hash table of NATed hosts -- Rani
 				 	 */
-					if (fib_lookup(&key, &res) == 0) {
+					if (fib_lookup(&fl, &res) == 0) {
 						if (res.r) {
 							ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
 							if (ciph->daddr != idaddr)
diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c	Tue Oct 15 20:29:23 2002
+++ b/net/ipv4/ip_output.c	Tue Oct 15 20:29:23 2002
@@ -372,14 +372,20 @@
 		if(opt && opt->srr)
 			daddr = opt->faddr;
 
-		/* If this fails, retransmit mechanism of transport layer will
-		 * keep trying until route appears or the connection times itself
-		 * out.
-		 */
-		if (ip_route_output(&rt, daddr, inet->saddr,
-				    RT_CONN_FLAGS(sk),
-				    sk->bound_dev_if))
-			goto no_route;
+		{
+			struct flowi fl = { .nl_u = { .ip4_u =
+						      { .daddr = daddr,
+							.saddr = inet->saddr,
+							.tos = RT_CONN_FLAGS(sk) } },
+					    .oif = sk->bound_dev_if };
+
+			/* If this fails, retransmit mechanism of transport layer will
+			 * keep trying until route appears or the connection times itself
+			 * out.
+			 */
+			if (ip_route_output_key(&rt, &fl))
+				goto no_route;
+		}
 		__sk_dst_set(sk, &rt->u.dst);
 		tcp_v4_setup_caps(sk, &rt->u.dst);
 	}
@@ -991,8 +997,14 @@
 			daddr = replyopts.opt.faddr;
 	}
 
-	if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
-		return;
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = daddr,
+						.saddr = rt->rt_spec_dst,
+						.tos = RT_TOS(skb->nh.iph->tos) } } };
+		if (ip_route_output_key(&rt, &fl))
+			return;
+	}
 
 	/* And let IP do all the hard work.
 
diff -Nru a/net/ipv4/ip_proc.c b/net/ipv4/ip_proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/ip_proc.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,373 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		ipv4 proc support
+ *
+ *		Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2002/10/10
+ *
+ *		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; version 2 of the
+ *		License
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <net/neighbour.h>
+#include <net/arp.h>
+#include <net/udp.h>
+#include <linux/rtnetlink.h>
+#include <linux/route.h>
+#include <net/ip_fib.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+
+extern int raw_get_info(char *, char **, off_t, int);
+extern int snmp_get_info(char *, char **, off_t, int);
+extern int netstat_get_info(char *, char **, off_t, int);
+extern int afinet_get_info(char *, char **, off_t, int);
+extern int tcp_get_info(char *, char **, off_t, int);
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_AX25
+
+/* ------------------------------------------------------------------------ */
+/*
+ *	ax25 -> ASCII conversion
+ */
+static char *ax2asc2(ax25_address *a, char *buf)
+{
+	char c, *s;
+	int n;
+
+	for (n = 0, s = buf; n < 6; n++) {
+		c = (a->ax25_call[n] >> 1) & 0x7F;
+
+		if (c != ' ') *s++ = c;
+	}
+	
+	*s++ = '-';
+
+	if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) {
+		*s++ = '1';
+		n -= 10;
+	}
+	
+	*s++ = n + '0';
+	*s++ = '\0';
+
+	if (*buf == '\0' || *buf == '-')
+	   return "*";
+
+	return buf;
+
+}
+#endif /* CONFIG_AX25 */
+
+static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	return (void *)(unsigned long)++*pos;
+}
+
+static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	return (void *)(unsigned long)((++*pos) >=
+				       (NEIGH_HASHMASK +
+					PNEIGH_HASHMASK - 1) ? 0 : *pos);
+}
+
+static void arp_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+#define HBUFFERLEN 30
+
+static __inline__ void arp_format_neigh_table(struct seq_file *seq, int entry)
+{
+	char hbuffer[HBUFFERLEN];
+	const char hexbuf[] = "0123456789ABCDEF";
+	struct neighbour *n;
+	int k, j;
+
+	read_lock_bh(&arp_tbl.lock);
+	for (n = arp_tbl.hash_buckets[entry]; n; n = n->next) {
+		char tbuf[16];
+		struct net_device *dev = n->dev;
+		int hatype = dev->type;
+
+		/* Do not confuse users "arp -a" with magic entries */
+		if (!(n->nud_state & ~NUD_NOARP))
+			continue;
+
+		read_lock(&n->lock);
+		/* Convert hardware address to XX:XX:XX:XX ... form. */
+#ifdef CONFIG_AX25
+		if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM)
+			ax2asc2((ax25_address *)n->ha, hbuffer);
+		else {
+#endif
+		for (k = 0, j = 0; k < HBUFFERLEN - 3 &&
+				   j < dev->addr_len; j++) {
+			hbuffer[k++] = hexbuf[(n->ha[j] >> 4) & 15];
+			hbuffer[k++] = hexbuf[n->ha[j] & 15];
+			hbuffer[k++] = ':';
+		}
+		hbuffer[--k] = 0;
+#ifdef CONFIG_AX25
+		}
+#endif
+		sprintf(tbuf, "%u.%u.%u.%u",
+			NIPQUAD(*(u32*)n->primary_key));
+		seq_printf(seq, "%-16s 0x%-10x0x%-10x%s"
+				"     *        %s\n",
+			   tbuf, hatype, arp_state_to_flags(n), 
+			   hbuffer, dev->name);
+		read_unlock(&n->lock);
+	}
+	read_unlock_bh(&arp_tbl.lock);
+}
+
+static __inline__ void arp_format_pneigh_table(struct seq_file *seq, int entry)
+{
+	struct pneigh_entry *n;
+
+	for (n = arp_tbl.phash_buckets[entry]; n; n = n->next) {
+		struct net_device *dev = n->dev;
+		int hatype = dev ? dev->type : 0;
+		char tbuf[16];
+
+		sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key));
+		seq_printf(seq, "%-16s 0x%-10x0x%-10x%s"
+				"     *        %s\n",
+			   tbuf, hatype, ATF_PUBL | ATF_PERM,
+			   "00:00:00:00:00:00",
+			   dev ? dev->name : "*");
+	}
+}
+
+static int arp_seq_show(struct seq_file *seq, void *v)
+{
+	unsigned long l = (unsigned long)v - 1;
+
+	if (!l)
+		seq_puts(seq, "IP address       HW type     Flags       "
+			      "HW address            Mask     Device\n");
+
+	if (l <= NEIGH_HASHMASK)
+		arp_format_neigh_table(seq, l);
+	else
+		arp_format_pneigh_table(seq, l - NEIGH_HASHMASK);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	return *pos ? NULL : (void *)1;
+}
+
+static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	return NULL;
+}
+
+static void fib_seq_stop(struct seq_file *seq, void *v)
+{
+}
+/* 
+ *	This outputs /proc/net/route.
+ *
+ *	It always works in backward compatibility mode.
+ *	The format of the file is not supposed to be changed.
+ */
+static int fib_seq_show(struct seq_file *seq, void *v)
+{
+	seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "
+			"\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
+			"\tWindow\tIRTT");
+	if (ip_fib_main_table)
+		ip_fib_main_table->tb_seq_show(ip_fib_main_table, seq);
+
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void *udp_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	read_lock(&udp_hash_lock);
+	return (void *)(unsigned long)++*pos;
+}
+
+static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	return (void *)(unsigned long)((++*pos) >=
+				       (UDP_HTABLE_SIZE - 1) ? 0 : *pos);
+}
+
+static void udp_seq_stop(struct seq_file *seq, void *v)
+{
+	read_unlock(&udp_hash_lock);
+}
+
+static void udp_format_sock(struct sock *sp, char *tmpbuf, int i)
+{
+	struct inet_opt *inet = inet_sk(sp);
+	unsigned int dest = inet->daddr;
+	unsigned int src  = inet->rcv_saddr;
+	__u16 destp	  = ntohs(inet->dport);
+	__u16 srcp	  = ntohs(inet->sport);
+
+	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
+		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
+		i, src, srcp, dest, destp, sp->state, 
+		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
+		0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
+		atomic_read(&sp->refcnt), sp);
+}
+
+static int udp_seq_show(struct seq_file *seq, void *v)
+{
+	char tmpbuf[129];
+	struct sock *sk;
+	unsigned long l = (unsigned long)v - 1;
+
+	if (!l)
+		seq_printf(seq, "%-127s\n",
+			   "  sl  local_address rem_address   st tx_queue "
+			   "rx_queue tr tm->when retrnsmt   uid  timeout inode");
+
+	for (sk = udp_hash[l]; sk; sk = sk->next) {
+		if (sk->family != PF_INET)
+			continue;
+		udp_format_sock(sk, tmpbuf, l);
+		seq_printf(seq, "%-127s\n", tmpbuf);
+	}
+	return 0;
+}
+/* ------------------------------------------------------------------------ */
+
+static struct seq_operations arp_seq_ops = {
+	.start  = arp_seq_start,
+	.next   = arp_seq_next,
+	.stop   = arp_seq_stop,
+	.show   = arp_seq_show,
+};
+
+static struct seq_operations fib_seq_ops = {
+	.start  = fib_seq_start,
+	.next   = fib_seq_next,
+	.stop   = fib_seq_stop,
+	.show   = fib_seq_show,
+};
+
+static struct seq_operations udp_seq_ops = {
+	.start  = udp_seq_start,
+	.next   = udp_seq_next,
+	.stop   = udp_seq_stop,
+	.show   = udp_seq_show,
+};
+
+static int arp_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &arp_seq_ops);
+}
+
+static int fib_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &fib_seq_ops);
+}
+
+static int udp_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &udp_seq_ops);
+}
+
+static struct file_operations arp_seq_fops = {
+	.open           = arp_seq_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release	= seq_release,
+};
+
+static struct file_operations fib_seq_fops = {
+	.open           = fib_seq_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release	= seq_release,
+};
+
+static struct file_operations udp_seq_fops = {
+	.open           = udp_seq_open,
+	.read           = seq_read,
+	.llseek         = seq_lseek,
+	.release	= seq_release,
+};
+
+/* ------------------------------------------------------------------------ */
+
+int __init ipv4_proc_init(void)
+{
+	struct proc_dir_entry *p;
+	int rc = 0;
+
+	if (!proc_net_create("raw", 0, raw_get_info))
+		goto out_raw;
+
+	if (!proc_net_create("netstat", 0, netstat_get_info))
+		goto out_netstat;
+
+	if (!proc_net_create("snmp", 0, snmp_get_info))
+		goto out_snmp;
+
+	if (!proc_net_create("sockstat", 0, afinet_get_info))
+		goto out_sockstat;
+
+	if (!proc_net_create("tcp", 0, tcp_get_info))
+		goto out_tcp;
+
+	p = create_proc_entry("udp", S_IRUGO, proc_net);
+	if (!p)
+		goto out_udp;
+	p->proc_fops = &udp_seq_fops;
+
+	p = create_proc_entry("arp", S_IRUGO, proc_net);
+	if (!p)
+		goto out_arp;
+	p->proc_fops = &arp_seq_fops;
+
+	p = create_proc_entry("route", S_IRUGO, proc_net);
+	if (!p)
+		goto out_route;
+	p->proc_fops = &fib_seq_fops;
+out:
+	return rc;
+out_route:
+	remove_proc_entry("route", proc_net);
+out_arp:
+	remove_proc_entry("udp", proc_net);
+out_udp:
+	proc_net_remove("tcp");
+out_tcp:
+	proc_net_remove("sockstat");
+out_sockstat:
+	proc_net_remove("snmp");
+out_snmp:
+	proc_net_remove("netstat");
+out_netstat:
+	proc_net_remove("raw");
+out_raw:
+	rc = -ENOMEM;
+	goto out;
+}
+#else /* CONFIG_PROC_FS */
+int __init ipv4_proc_init(void)
+{
+	return 0;
+}
+#endif /* CONFIG_PROC_FS */
diff -Nru a/net/ipv4/ipip.c b/net/ipv4/ipip.c
--- a/net/ipv4/ipip.c	Tue Oct 15 20:29:23 2002
+++ b/net/ipv4/ipip.c	Tue Oct 15 20:29:23 2002
@@ -355,6 +355,7 @@
 	int rel_code = 0;
 	int rel_info = 0;
 	struct sk_buff *skb2;
+	struct flowi fl;
 	struct rtable *rt;
 
 	if (len < hlen + sizeof(struct iphdr))
@@ -417,7 +418,10 @@
 	skb2->nh.raw = skb2->data;
 
 	/* Try to guess incoming interface */
-	if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) {
+	memset(&fl, 0, sizeof(fl));
+	fl.fl4_daddr = eiph->saddr;
+	fl.fl4_tos = RT_TOS(eiph->tos);
+	if (ip_route_output_key(&rt, &key)) {
 		kfree_skb(skb2);
 		return;
 	}
@@ -427,7 +431,10 @@
 	if (rt->rt_flags&RTCF_LOCAL) {
 		ip_rt_put(rt);
 		rt = NULL;
-		if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) ||
+		fl.fl4_daddr = eiph->daddr;
+		fl.fl4_src = eiph->saddr;
+		fl.fl4_tos = eiph->tos;
+		if (ip_route_output_key(&rt, &fl) ||
 		    rt->u.dst.dev->type != ARPHRD_IPGRE) {
 			ip_rt_put(rt);
 			kfree_skb(skb2);
@@ -560,9 +567,16 @@
 			goto tx_error_icmp;
 	}
 
-	if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
-		tunnel->stat.tx_carrier_errors++;
-		goto tx_error_icmp;
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = dst,
+						.saddr = tiph->saddr,
+						.tos = RT_TOS(tos) } },
+				    .oif = tunnel->parms.link };
+		if (ip_route_output_key(&rt, &fl)) {
+			tunnel->stat.tx_carrier_errors++;
+			goto tx_error_icmp;
+		}
 	}
 	tdev = rt->u.dst.dev;
 
@@ -822,8 +836,13 @@
 	ipip_tunnel_init_gen(dev);
 
 	if (iph->daddr) {
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = iph->daddr,
+						.saddr = iph->saddr,
+						.tos = RT_TOS(iph->tos) } },
+				    .oif = tunnel->parms.link };
 		struct rtable *rt;
-		if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) {
+		if (!ip_route_output_key(&rt, &fl)) {
 			tdev = rt->u.dst.dev;
 			ip_rt_put(rt);
 		}
diff -Nru a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
--- a/net/ipv4/ipmr.c	Tue Oct 15 20:29:17 2002
+++ b/net/ipv4/ipmr.c	Tue Oct 15 20:29:17 2002
@@ -1146,11 +1146,20 @@
 #endif
 
 	if (vif->flags&VIFF_TUNNEL) {
-		if (ip_route_output(&rt, vif->remote, vif->local, RT_TOS(iph->tos), vif->link))
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = vif->remote,
+						.saddr = vif->local,
+						.tos = RT_TOS(iph->tos) } },
+				    .oif = vif->link };
+		if (ip_route_output_key(&rt, &fl))
 			return;
 		encap = sizeof(struct iphdr);
 	} else {
-		if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos), vif->link))
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = iph->daddr,
+						.tos = RT_TOS(iph->tos) } },
+				    .oif = vif->link };
+		if (ip_route_output_key(&rt, &fl))
 			return;
 	}
 
@@ -1244,7 +1253,7 @@
 	if (vif_table[vif].dev != skb->dev) {
 		int true_vifi;
 
-		if (((struct rtable*)skb->dst)->key.iif == 0) {
+		if (((struct rtable*)skb->dst)->fl.iif == 0) {
 			/* It is our own packet, looped back.
 			   Very complicated situation...
 
diff -Nru a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c	Tue Oct 15 20:29:10 2002
+++ b/net/ipv4/netfilter/ip_conntrack_core.c	Tue Oct 15 20:29:11 2002
@@ -75,7 +75,7 @@
 	return protocol == curr->proto;
 }
 
-struct ip_conntrack_protocol *__find_proto(u_int8_t protocol)
+struct ip_conntrack_protocol *__ip_ct_find_proto(u_int8_t protocol)
 {
 	struct ip_conntrack_protocol *p;
 
@@ -93,7 +93,7 @@
 	struct ip_conntrack_protocol *p;
 
 	READ_LOCK(&ip_conntrack_lock);
-	p = __find_proto(protocol);
+	p = __ip_ct_find_proto(protocol);
 	READ_UNLOCK(&ip_conntrack_lock);
 	return p;
 }
@@ -1061,7 +1061,10 @@
 int ip_conntrack_change_expect(struct ip_conntrack_expect *expect,
 			       struct ip_conntrack_tuple *newtuple)
 {
+	int ret;
+
 	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+	WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
 
 	DEBUGP("change_expect:\n");
 	DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
@@ -1074,26 +1077,25 @@
 		    && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
 			         struct ip_conntrack_expect *, newtuple, &expect->mask)) {
 			/* Force NAT to find an unused tuple */
-			return -1;
+			ret = -1;
 		} else {
-			WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
 			memcpy(&expect->ct_tuple, &expect->tuple, sizeof(expect->tuple));
 			memcpy(&expect->tuple, newtuple, sizeof(expect->tuple));
-			WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
-			return 0;
+			ret = 0;
 		}
 	} else {
 		/* Resent packet */
 		DEBUGP("change expect: resent packet\n");
 		if (ip_ct_tuple_equal(&expect->tuple, newtuple)) {
-			return 0;
+			ret = 0;
 		} else {
 			/* Force NAT to choose again the same port */
-			return -1;
+			ret = -1;
 		}
 	}
+	WRITE_UNLOCK(&ip_conntrack_expect_tuple_lock);
 	
-	return -1;
+	return ret;
 }
 
 /* Alter reply tuple (maybe alter helper).  If it's already taken,
diff -Nru a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c	Tue Oct 15 20:29:16 2002
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c	Tue Oct 15 20:29:16 2002
@@ -71,7 +71,7 @@
 	len += sprintf(buffer + len, "use=%u proto=%u ",
 		      atomic_read(&expect->use), expect->tuple.dst.protonum);
 	len += print_tuple(buffer + len, &expect->tuple,
-			   __find_proto(expect->tuple.dst.protonum));
+			   __ip_ct_find_proto(expect->tuple.dst.protonum));
 	len += sprintf(buffer + len, "\n");
 	return len;
 }
@@ -81,7 +81,7 @@
 {
 	unsigned int len;
 	struct ip_conntrack_protocol *proto
-		= __find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+		= __ip_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
 			       .tuple.dst.protonum);
 
 	len = sprintf(buffer, "%-8s %u %lu ",
@@ -361,6 +361,7 @@
 EXPORT_SYMBOL(ip_ct_selective_cleanup);
 EXPORT_SYMBOL(ip_ct_refresh);
 EXPORT_SYMBOL(ip_ct_find_proto);
+EXPORT_SYMBOL(__ip_ct_find_proto);
 EXPORT_SYMBOL(ip_ct_find_helper);
 EXPORT_SYMBOL(ip_conntrack_expect_related);
 EXPORT_SYMBOL(ip_conntrack_change_expect);
diff -Nru a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c
--- a/net/ipv4/netfilter/ip_fw_compat_masq.c	Tue Oct 15 20:29:20 2002
+++ b/net/ipv4/netfilter/ip_fw_compat_masq.c	Tue Oct 15 20:29:20 2002
@@ -68,12 +68,13 @@
 	/* Setup the masquerade, if not already */
 	if (!info->initialized) {
 		u_int32_t newsrc;
+		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->daddr } } };
 		struct rtable *rt;
 		struct ip_nat_multi_range range;
 
 		/* Pass 0 instead of saddr, since it's going to be changed
 		   anyway. */
-		if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
+		if (ip_route_output_key(&rt, &fl) != 0) {
 			DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
 			return NF_DROP;
 		}
diff -Nru a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
--- a/net/ipv4/netfilter/ip_nat_core.c	Tue Oct 15 20:29:12 2002
+++ b/net/ipv4/netfilter/ip_nat_core.c	Tue Oct 15 20:29:12 2002
@@ -209,10 +209,11 @@
 static int
 do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp)
 {
+	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = var_ip } } };
 	struct rtable *rt;
 
 	/* FIXME: IPTOS_TOS(iph->tos) --RR */
-	if (ip_route_output(&rt, var_ip, 0, 0, 0) != 0) {
+	if (ip_route_output_key(&rt, &fl) != 0) {
 		DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n",
 		       NIPQUAD(var_ip));
 		return 0;
@@ -739,7 +740,7 @@
 	int ret = 1;
 
 	MUST_BE_READ_LOCKED(&ip_conntrack_lock);
-	proto = ip_ct_find_proto((*pskb)->nh.iph->protocol);
+	proto = __ip_ct_find_proto((*pskb)->nh.iph->protocol);
 	if (proto->exp_matches_pkt)
 		ret = proto->exp_matches_pkt(exp, pskb);
 
diff -Nru a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c	Tue Oct 15 20:29:17 2002
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c	Tue Oct 15 20:29:17 2002
@@ -69,7 +69,6 @@
 	struct ip_nat_multi_range newrange;
 	u_int32_t newsrc;
 	struct rtable *rt;
-	struct rt_key key;
 
 	IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
 
@@ -84,17 +83,21 @@
 
 	mr = targinfo;
 
-	key.dst = (*pskb)->nh.iph->daddr;
-	key.src = 0; /* Unknown: that's what we're trying to establish */
-	key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
-	key.oif = out->ifindex;
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = (*pskb)->nh.iph->daddr,
+						.tos = (RT_TOS((*pskb)->nh.iph->tos) |
+							RTO_CONN),
 #ifdef CONFIG_IP_ROUTE_FWMARK
-	key.fwmark = (*pskb)->nfmark;
+						.fwmark = (*pskb)->nfmark
 #endif
-	if (ip_route_output_key(&rt, &key) != 0) {
-		/* Shouldn't happen */
-		printk("MASQUERADE: No route: Rusty's brain broke!\n");
-		return NF_DROP;
+					      } },
+				    .oif = out->ifindex };
+		if (ip_route_output_key(&rt, &fl) != 0) {
+			/* Shouldn't happen */
+			printk("MASQUERADE: No route: Rusty's brain broke!\n");
+			return NF_DROP;
+		}
 	}
 
 	newsrc = rt->rt_src;
diff -Nru a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c
--- a/net/ipv4/netfilter/ipt_MIRROR.c	Tue Oct 15 20:29:23 2002
+++ b/net/ipv4/netfilter/ipt_MIRROR.c	Tue Oct 15 20:29:23 2002
@@ -44,12 +44,13 @@
 static int route_mirror(struct sk_buff *skb)
 {
         struct iphdr *iph = skb->nh.iph;
+	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
+						 .saddr = iph->daddr,
+						 .tos = RT_TOS(iph->tos) | RTO_CONN } } };
 	struct rtable *rt;
 
 	/* Backwards */
-	if (ip_route_output(&rt, iph->saddr, iph->daddr,
-			    RT_TOS(iph->tos) | RTO_CONN,
-			    0)) {
+	if (ip_route_output_key(&rt, &fl)) {
 		return 0;
 	}
 
diff -Nru a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
--- a/net/ipv4/netfilter/ipt_REJECT.c	Tue Oct 15 20:29:20 2002
+++ b/net/ipv4/netfilter/ipt_REJECT.c	Tue Oct 15 20:29:20 2002
@@ -130,12 +130,19 @@
 	nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 
 					   nskb->nh.iph->ihl);
 
-	/* Routing: if not headed for us, route won't like source */
-	if (ip_route_output(&rt, nskb->nh.iph->daddr,
-			    local ? nskb->nh.iph->saddr : 0,
-			    RT_TOS(nskb->nh.iph->tos) | RTO_CONN,
-			    0) != 0)
-		goto free_nskb;
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = nskb->nh.iph->daddr,
+						.saddr = (local ?
+							  nskb->nh.iph->saddr :
+							  0),
+						.tos = (RT_TOS(nskb->nh.iph->tos) |
+							RTO_CONN) } } };
+
+		/* Routing: if not headed for us, route won't like source */
+		if (ip_route_output_key(&rt, &fl))
+			goto free_nskb;
+	}
 
 	dst_release(nskb->dst);
 	nskb->dst = &rt->u.dst;
@@ -207,9 +214,14 @@
 
 	tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
 
-	if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
-		return;
-
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = iph->saddr,
+						.saddr = saddr,
+						.tos = RT_TOS(tos) } } };
+		if (ip_route_output_key(&rt, &fl))
+			return;
+	}
 	/* RFC says return as much as we can without exceeding 576 bytes. */
 	length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr);
 
diff -Nru a/net/ipv4/netfilter/ipt_unclean.c b/net/ipv4/netfilter/ipt_unclean.c
--- a/net/ipv4/netfilter/ipt_unclean.c	Tue Oct 15 20:29:17 2002
+++ b/net/ipv4/netfilter/ipt_unclean.c	Tue Oct 15 20:29:17 2002
@@ -216,10 +216,9 @@
 				 csum_partial((char *)udph, datalen, 0)) != 0)
 		return 0;
 
-	/* CHECK: Ports can't be zero. */
-	if (!udph->source || !udph->dest) {
-		limpk("UDP zero ports %u/%u\n",
-		      ntohs(udph->source), ntohs(udph->dest));
+	/* CHECK: Destination port can't be zero. */
+	if (!udph->dest) {
+		limpk("UDP zero destination port\n");
 		return 0;
 	}
 
diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c	Tue Oct 15 20:29:11 2002
+++ b/net/ipv4/raw.c	Tue Oct 15 20:29:11 2002
@@ -295,7 +295,8 @@
 	return 0;
 }
 
-static int raw_sendmsg(struct sock *sk, struct msghdr *msg, int len)
+static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		       int len)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	struct ipcm_cookie ipc;
@@ -402,8 +403,14 @@
 			rfh.saddr = inet->mc_addr;
 	}
 
-	err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif);
-
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = daddr,
+						.saddr = rfh.saddr,
+						.tos = tos } },
+				    .oif = ipc.oif };
+		err = ip_route_output_key(&rt, &fl);
+	}
 	if (err)
 		goto done;
 
@@ -476,8 +483,8 @@
  *	we return it, otherwise we block.
  */
 
-int raw_recvmsg(struct sock *sk, struct msghdr *msg, int len,
-		int noblock, int flags, int *addr_len)
+int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		int len, int noblock, int flags, int *addr_len)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	int copied = 0;
diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c	Tue Oct 15 20:29:23 2002
+++ b/net/ipv4/route.c	Tue Oct 15 20:29:23 2002
@@ -251,7 +251,7 @@
 				(int)r->u.dst.advmss + 40,
 				r->u.dst.window,
 				(int)((r->u.dst.rtt >> 3) + r->u.dst.rttvar),
-				r->key.tos,
+				r->fl.fl4_tos,
 				r->u.dst.hh ?
 					atomic_read(&r->u.dst.hh->hh_refcnt) :
 					-1,
@@ -332,7 +332,7 @@
 	/* Kill broadcast/multicast entries very aggresively, if they
 	   collide in hash table with more useful entries */
 	return (rth->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) &&
-		rth->key.iif && rth->u.rt_next;
+		rth->fl.iif && rth->u.rt_next;
 }
 
 static __inline__ int rt_valuable(struct rtable *rth)
@@ -621,7 +621,7 @@
 
 	write_lock_bh(&rt_hash_table[hash].lock);
 	while ((rth = *rthp) != NULL) {
-		if (memcmp(&rth->key, &rt->key, sizeof(rt->key)) == 0) {
+		if (memcmp(&rth->fl, &rt->fl, sizeof(rt->fl)) == 0) {
 			/* Put it first */
 			*rthp = rth->u.rt_next;
 			rth->u.rt_next = rt_hash_table[hash].chain;
@@ -643,7 +643,7 @@
 	/* Try to bind route to arp only if it is output
 	   route or unicast forwarding path.
 	 */
-	if (rt->rt_type == RTN_UNICAST || rt->key.iif == 0) {
+	if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
 		int err = arp_bind_neighbour(&rt->u.dst);
 		if (err) {
 			write_unlock_bh(&rt_hash_table[hash].lock);
@@ -806,11 +806,11 @@
 			while ((rth = *rthp) != NULL) {
 				struct rtable *rt;
 
-				if (rth->key.dst != daddr ||
-				    rth->key.src != skeys[i] ||
-				    rth->key.tos != tos ||
-				    rth->key.oif != ikeys[k] ||
-				    rth->key.iif != 0) {
+				if (rth->fl.fl4_dst != daddr ||
+				    rth->fl.fl4_src != skeys[i] ||
+				    rth->fl.fl4_tos != tos ||
+				    rth->fl.oif != ikeys[k] ||
+				    rth->fl.iif != 0) {
 					rthp = &rth->u.rt_next;
 					continue;
 				}
@@ -901,14 +901,14 @@
 			ret = NULL;
 		} else if ((rt->rt_flags & RTCF_REDIRECTED) ||
 			   rt->u.dst.expires) {
-			unsigned hash = rt_hash_code(rt->key.dst,
-						     rt->key.src ^
-							(rt->key.oif << 5),
-						     rt->key.tos);
+			unsigned hash = rt_hash_code(rt->fl.fl4_dst,
+						     rt->fl.fl4_src ^
+							(rt->fl.oif << 5),
+						     rt->fl.fl4_tos);
 #if RT_CACHE_DEBUG >= 1
 			printk(KERN_DEBUG "ip_rt_advice: redirect to "
 					  "%u.%u.%u.%u/%02x dropped\n",
-				NIPQUAD(rt->rt_dst), rt->key.tos);
+				NIPQUAD(rt->rt_dst), rt->fl.fl4_tos);
 #endif
 			rt_del(hash, rt);
 			ret = NULL;
@@ -1052,12 +1052,12 @@
 		read_lock(&rt_hash_table[hash].lock);
 		for (rth = rt_hash_table[hash].chain; rth;
 		     rth = rth->u.rt_next) {
-			if (rth->key.dst == daddr &&
-			    rth->key.src == skeys[i] &&
+			if (rth->fl.fl4_dst == daddr &&
+			    rth->fl.fl4_src == skeys[i] &&
 			    rth->rt_dst  == daddr &&
 			    rth->rt_src  == iph->saddr &&
-			    rth->key.tos == tos &&
-			    rth->key.iif == 0 &&
+			    rth->fl.fl4_tos == tos &&
+			    rth->fl.iif == 0 &&
 			    !(rth->u.dst.mxlock & (1 << RTAX_MTU))) {
 				unsigned short mtu = new_mtu;
 
@@ -1162,9 +1162,9 @@
 	u32 src;
 	struct fib_result res;
 
-	if (rt->key.iif == 0)
+	if (rt->fl.iif == 0)
 		src = rt->rt_src;
-	else if (fib_lookup(&rt->key, &res) == 0) {
+	else if (fib_lookup(&rt->fl, &res) == 0) {
 #ifdef CONFIG_IP_ROUTE_NAT
 		if (res.type == RTN_NAT)
 			src = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
@@ -1263,13 +1263,13 @@
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
-	rth->key.dst	= daddr;
+	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
-	rth->key.tos	= tos;
+	rth->fl.fl4_tos	= tos;
 #ifdef CONFIG_IP_ROUTE_FWMARK
-	rth->key.fwmark	= skb->nfmark;
+	rth->fl.fl4_fwmark= skb->nfmark;
 #endif
-	rth->key.src	= saddr;
+	rth->fl.fl4_src	= saddr;
 	rth->rt_src	= saddr;
 #ifdef CONFIG_IP_ROUTE_NAT
 	rth->rt_dst_map	= daddr;
@@ -1279,10 +1279,10 @@
 	rth->u.dst.tclassid = itag;
 #endif
 	rth->rt_iif	=
-	rth->key.iif	= dev->ifindex;
+	rth->fl.iif	= dev->ifindex;
 	rth->u.dst.dev	= &loopback_dev;
 	dev_hold(rth->u.dst.dev);
-	rth->key.oif	= 0;
+	rth->fl.oif	= 0;
 	rth->rt_gateway	= daddr;
 	rth->rt_spec_dst= spec_dst;
 	rth->rt_type	= RTN_MULTICAST;
@@ -1324,10 +1324,19 @@
 int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
 			u8 tos, struct net_device *dev)
 {
-	struct rt_key	key;
 	struct fib_result res;
 	struct in_device *in_dev = in_dev_get(dev);
 	struct in_device *out_dev = NULL;
+	struct flowi fl = { .nl_u = { .ip4_u =
+				      { .daddr = daddr,
+					.saddr = saddr,
+					.tos = tos,
+					.scope = RT_SCOPE_UNIVERSE,
+#ifdef CONFIG_IP_ROUTE_FWMARK
+					.fwmark = skb->nfmark
+#endif
+				      } },
+			    .iif = dev->ifindex };
 	unsigned	flags = 0;
 	u32		itag = 0;
 	struct rtable * rth;
@@ -1341,17 +1350,7 @@
 	if (!in_dev)
 		goto out;
 
-	key.dst		= daddr;
-	key.src		= saddr;
-	key.tos		= tos;
-#ifdef CONFIG_IP_ROUTE_FWMARK
-	key.fwmark	= skb->nfmark;
-#endif
-	key.iif		= dev->ifindex;
-	key.oif		= 0;
-	key.scope	= RT_SCOPE_UNIVERSE;
-
-	hash = rt_hash_code(daddr, saddr ^ (key.iif << 5), tos);
+	hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5), tos);
 
 	/* Check for the most weird martians, which can be not detected
 	   by fib_lookup.
@@ -1375,7 +1374,7 @@
 	/*
 	 *	Now we are ready to route packet.
 	 */
-	if ((err = fib_lookup(&key, &res)) != 0) {
+	if ((err = fib_lookup(&fl, &res)) != 0) {
 		if (!IN_DEV_FORWARD(in_dev))
 			goto e_inval;
 		goto no_route;
@@ -1395,17 +1394,17 @@
 			src_map = fib_rules_policy(saddr, &res, &flags);
 
 		if (res.type == RTN_NAT) {
-			key.dst = fib_rules_map_destination(daddr, &res);
+			fl.fl4_dst = fib_rules_map_destination(daddr, &res);
 			fib_res_put(&res);
 			free_res = 0;
-			if (fib_lookup(&key, &res))
+			if (fib_lookup(&fl, &res))
 				goto e_inval;
 			free_res = 1;
 			if (res.type != RTN_UNICAST)
 				goto e_inval;
 			flags |= RTCF_DNAT;
 		}
-		key.src = src_map;
+		fl.fl4_src = src_map;
 	}
 #endif
 
@@ -1431,8 +1430,8 @@
 		goto martian_destination;
 
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-	if (res.fi->fib_nhs > 1 && key.oif == 0)
-		fib_select_multipath(&key, &res);
+	if (res.fi->fib_nhs > 1 && fl.oif == 0)
+		fib_select_multipath(&fl, &res);
 #endif
 	out_dev = in_dev_get(FIB_RES_DEV(res));
 	if (out_dev == NULL) {
@@ -1469,26 +1468,26 @@
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
-	rth->key.dst	= daddr;
+	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
-	rth->key.tos	= tos;
+	rth->fl.fl4_tos	= tos;
 #ifdef CONFIG_IP_ROUTE_FWMARK
-	rth->key.fwmark	= skb->nfmark;
+	rth->fl.fl4_fwmark= skb->nfmark;
 #endif
-	rth->key.src	= saddr;
+	rth->fl.fl4_src	= saddr;
 	rth->rt_src	= saddr;
 	rth->rt_gateway	= daddr;
 #ifdef CONFIG_IP_ROUTE_NAT
-	rth->rt_src_map	= key.src;
-	rth->rt_dst_map	= key.dst;
+	rth->rt_src_map	= fl.fl4_src;
+	rth->rt_dst_map	= fl.fl4_dst;
 	if (flags&RTCF_DNAT)
-		rth->rt_gateway	= key.dst;
+		rth->rt_gateway	= fl.fl4_dst;
 #endif
 	rth->rt_iif 	=
-	rth->key.iif	= dev->ifindex;
+	rth->fl.iif	= dev->ifindex;
 	rth->u.dst.dev	= out_dev->dev;
 	dev_hold(rth->u.dst.dev);
-	rth->key.oif 	= 0;
+	rth->fl.oif 	= 0;
 	rth->rt_spec_dst= spec_dst;
 
 	rth->u.dst.input = ip_forward;
@@ -1546,26 +1545,25 @@
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
-	rth->key.dst	= daddr;
+	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
-	rth->key.tos	= tos;
+	rth->fl.fl4_tos	= tos;
 #ifdef CONFIG_IP_ROUTE_FWMARK
-	rth->key.fwmark	= skb->nfmark;
+	rth->fl.fl4_fwmark= skb->nfmark;
 #endif
-	rth->key.src	= saddr;
+	rth->fl.fl4_src	= saddr;
 	rth->rt_src	= saddr;
 #ifdef CONFIG_IP_ROUTE_NAT
-	rth->rt_dst_map	= key.dst;
-	rth->rt_src_map	= key.src;
+	rth->rt_dst_map	= fl.fl4_dst;
+	rth->rt_src_map	= fl.fl4_src;
 #endif
 #ifdef CONFIG_NET_CLS_ROUTE
 	rth->u.dst.tclassid = itag;
 #endif
 	rth->rt_iif	=
-	rth->key.iif	= dev->ifindex;
+	rth->fl.iif	= dev->ifindex;
 	rth->u.dst.dev	= &loopback_dev;
 	dev_hold(rth->u.dst.dev);
-	rth->key.oif 	= 0;
 	rth->rt_gateway	= daddr;
 	rth->rt_spec_dst= spec_dst;
 	rth->u.dst.input= ip_local_deliver;
@@ -1643,14 +1641,14 @@
 
 	read_lock(&rt_hash_table[hash].lock);
 	for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) {
-		if (rth->key.dst == daddr &&
-		    rth->key.src == saddr &&
-		    rth->key.iif == iif &&
-		    rth->key.oif == 0 &&
+		if (rth->fl.fl4_dst == daddr &&
+		    rth->fl.fl4_src == saddr &&
+		    rth->fl.iif == iif &&
+		    rth->fl.oif == 0 &&
 #ifdef CONFIG_IP_ROUTE_FWMARK
-		    rth->key.fwmark == skb->nfmark &&
+		    rth->fl.fl4_fwmark == skb->nfmark &&
 #endif
-		    rth->key.tos == tos) {
+		    rth->fl.fl4_tos == tos) {
 			rth->u.dst.lastuse = jiffies;
 			dst_hold(&rth->u.dst);
 			rth->u.dst.__use++;
@@ -1699,9 +1697,22 @@
  * Major route resolver routine.
  */
 
-int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey)
+int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
 {
-	struct rt_key key;
+	u32 tos	= oldflp->fl4_tos & (IPTOS_RT_MASK | RTO_ONLINK);
+	struct flowi fl = { .nl_u = { .ip4_u =
+				      { .daddr = oldflp->fl4_dst,
+					.saddr = oldflp->fl4_src,
+					.tos = tos & IPTOS_RT_MASK,
+					.scope = ((tos & RTO_ONLINK) ?
+						  RT_SCOPE_LINK :
+						  RT_SCOPE_UNIVERSE),
+#ifdef CONFIG_IP_ROUTE_FWMARK
+					.fwmark = oldflp->fl4_fwmark
+#endif
+				      } },
+			    .iif = loopback_dev.ifindex,
+			    .oif = oldflp->oif };
 	struct fib_result res;
 	unsigned flags = 0;
 	struct rtable *rth;
@@ -1709,33 +1720,21 @@
 	unsigned hash;
 	int free_res = 0;
 	int err;
-	u32 tos;
 
-	tos		= oldkey->tos & (IPTOS_RT_MASK | RTO_ONLINK);
-	key.dst		= oldkey->dst;
-	key.src		= oldkey->src;
-	key.tos		= tos & IPTOS_RT_MASK;
-	key.iif		= loopback_dev.ifindex;
-	key.oif		= oldkey->oif;
-#ifdef CONFIG_IP_ROUTE_FWMARK
-	key.fwmark	= oldkey->fwmark;
-#endif
-	key.scope	= (tos & RTO_ONLINK) ? RT_SCOPE_LINK :
-						RT_SCOPE_UNIVERSE;
 	res.fi		= NULL;
 #ifdef CONFIG_IP_MULTIPLE_TABLES
 	res.r		= NULL;
 #endif
 
-	if (oldkey->src) {
+	if (oldflp->fl4_src) {
 		err = -EINVAL;
-		if (MULTICAST(oldkey->src) ||
-		    BADCLASS(oldkey->src) ||
-		    ZERONET(oldkey->src))
+		if (MULTICAST(oldflp->fl4_src) ||
+		    BADCLASS(oldflp->fl4_src) ||
+		    ZERONET(oldflp->fl4_src))
 			goto out;
 
 		/* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */
-		dev_out = ip_dev_find(oldkey->src);
+		dev_out = ip_dev_find(oldflp->fl4_src);
 		if (dev_out == NULL)
 			goto out;
 
@@ -1747,8 +1746,8 @@
 		      of another iface. --ANK
 		 */
 
-		if (oldkey->oif == 0
-		    && (MULTICAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF)) {
+		if (oldflp->oif == 0
+		    && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF)) {
 			/* Special hack: user can direct multicasts
 			   and limited broadcast via necessary interface
 			   without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
@@ -1764,15 +1763,15 @@
 			   Luckily, this hack is good workaround.
 			 */
 
-			key.oif = dev_out->ifindex;
+			fl.oif = dev_out->ifindex;
 			goto make_route;
 		}
 		if (dev_out)
 			dev_put(dev_out);
 		dev_out = NULL;
 	}
-	if (oldkey->oif) {
-		dev_out = dev_get_by_index(oldkey->oif);
+	if (oldflp->oif) {
+		dev_out = dev_get_by_index(oldflp->oif);
 		err = -ENODEV;
 		if (dev_out == NULL)
 			goto out;
@@ -1781,39 +1780,39 @@
 			goto out;	/* Wrong error code */
 		}
 
-		if (LOCAL_MCAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF) {
-			if (!key.src)
-				key.src = inet_select_addr(dev_out, 0,
-								RT_SCOPE_LINK);
+		if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF) {
+			if (!fl.fl4_src)
+				fl.fl4_src = inet_select_addr(dev_out, 0,
+							      RT_SCOPE_LINK);
 			goto make_route;
 		}
-		if (!key.src) {
-			if (MULTICAST(oldkey->dst))
-				key.src = inet_select_addr(dev_out, 0,
-								key.scope);
-			else if (!oldkey->dst)
-				key.src = inet_select_addr(dev_out, 0,
-								RT_SCOPE_HOST);
+		if (!fl.fl4_src) {
+			if (MULTICAST(oldflp->fl4_dst))
+				fl.fl4_src = inet_select_addr(dev_out, 0,
+							      fl.fl4_scope);
+			else if (!oldflp->fl4_dst)
+				fl.fl4_src = inet_select_addr(dev_out, 0,
+							      RT_SCOPE_HOST);
 		}
 	}
 
-	if (!key.dst) {
-		key.dst = key.src;
-		if (!key.dst)
-			key.dst = key.src = htonl(INADDR_LOOPBACK);
+	if (!fl.fl4_dst) {
+		fl.fl4_dst = fl.fl4_src;
+		if (!fl.fl4_dst)
+			fl.fl4_dst = fl.fl4_src = htonl(INADDR_LOOPBACK);
 		if (dev_out)
 			dev_put(dev_out);
 		dev_out = &loopback_dev;
 		dev_hold(dev_out);
-		key.oif = loopback_dev.ifindex;
+		fl.oif = loopback_dev.ifindex;
 		res.type = RTN_LOCAL;
 		flags |= RTCF_LOCAL;
 		goto make_route;
 	}
 
-	if (fib_lookup(&key, &res)) {
+	if (fib_lookup(&fl, &res)) {
 		res.fi = NULL;
-		if (oldkey->oif) {
+		if (oldflp->oif) {
 			/* Apparently, routing tables are wrong. Assume,
 			   that the destination is on link.
 
@@ -1832,9 +1831,9 @@
 			   likely IPv6, but we do not.
 			 */
 
-			if (key.src == 0)
-				key.src = inet_select_addr(dev_out, 0,
-							   RT_SCOPE_LINK);
+			if (fl.fl4_src == 0)
+				fl.fl4_src = inet_select_addr(dev_out, 0,
+							      RT_SCOPE_LINK);
 			res.type = RTN_UNICAST;
 			goto make_route;
 		}
@@ -1849,13 +1848,13 @@
 		goto e_inval;
 
 	if (res.type == RTN_LOCAL) {
-		if (!key.src)
-			key.src = key.dst;
+		if (!fl.fl4_src)
+			fl.fl4_src = fl.fl4_dst;
 		if (dev_out)
 			dev_put(dev_out);
 		dev_out = &loopback_dev;
 		dev_hold(dev_out);
-		key.oif = dev_out->ifindex;
+		fl.oif = dev_out->ifindex;
 		if (res.fi)
 			fib_info_put(res.fi);
 		res.fi = NULL;
@@ -1864,31 +1863,31 @@
 	}
 
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
-	if (res.fi->fib_nhs > 1 && key.oif == 0)
-		fib_select_multipath(&key, &res);
+	if (res.fi->fib_nhs > 1 && fl.oif == 0)
+		fib_select_multipath(&fl, &res);
 	else
 #endif
-	if (!res.prefixlen && res.type == RTN_UNICAST && !key.oif)
-		fib_select_default(&key, &res);
+	if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
+		fib_select_default(&fl, &res);
 
-	if (!key.src)
-		key.src = FIB_RES_PREFSRC(res);
+	if (!fl.fl4_src)
+		fl.fl4_src = FIB_RES_PREFSRC(res);
 
 	if (dev_out)
 		dev_put(dev_out);
 	dev_out = FIB_RES_DEV(res);
 	dev_hold(dev_out);
-	key.oif = dev_out->ifindex;
+	fl.oif = dev_out->ifindex;
 
 make_route:
-	if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK))
+	if (LOOPBACK(fl.fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
 		goto e_inval;
 
-	if (key.dst == 0xFFFFFFFF)
+	if (fl.fl4_dst == 0xFFFFFFFF)
 		res.type = RTN_BROADCAST;
-	else if (MULTICAST(key.dst))
+	else if (MULTICAST(fl.fl4_dst))
 		res.type = RTN_MULTICAST;
-	else if (BADCLASS(key.dst) || ZERONET(key.dst))
+	else if (BADCLASS(fl.fl4_dst) || ZERONET(fl.fl4_dst))
 		goto e_inval;
 
 	if (dev_out->flags & IFF_LOOPBACK)
@@ -1904,7 +1903,7 @@
 		flags |= RTCF_MULTICAST|RTCF_LOCAL;
 		read_lock(&inetdev_lock);
 		if (!__in_dev_get(dev_out) ||
-		    !ip_check_mc(__in_dev_get(dev_out), oldkey->dst))
+		    !ip_check_mc(__in_dev_get(dev_out), oldflp->fl4_dst))
 			flags &= ~RTCF_LOCAL;
 		read_unlock(&inetdev_lock);
 		/* If multicast route do not exist use
@@ -1923,25 +1922,24 @@
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
-	rth->key.dst	= oldkey->dst;
-	rth->key.tos	= tos;
-	rth->key.src	= oldkey->src;
-	rth->key.iif	= 0;
-	rth->key.oif	= oldkey->oif;
+	rth->fl.fl4_dst	= oldflp->fl4_dst;
+	rth->fl.fl4_tos	= tos;
+	rth->fl.fl4_src	= oldflp->fl4_src;
+	rth->fl.oif	= oldflp->oif;
 #ifdef CONFIG_IP_ROUTE_FWMARK
-	rth->key.fwmark	= oldkey->fwmark;
+	rth->fl.fl4_fwmark= oldflp->fl4_fwmark;
 #endif
-	rth->rt_dst	= key.dst;
-	rth->rt_src	= key.src;
+	rth->rt_dst	= fl.fl4_dst;
+	rth->rt_src	= fl.fl4_src;
 #ifdef CONFIG_IP_ROUTE_NAT
-	rth->rt_dst_map	= key.dst;
-	rth->rt_src_map	= key.src;
+	rth->rt_dst_map	= fl.fl4_dst;
+	rth->rt_src_map	= fl.fl4_src;
 #endif
-	rth->rt_iif	= oldkey->oif ? : dev_out->ifindex;
+	rth->rt_iif	= oldflp->oif ? : dev_out->ifindex;
 	rth->u.dst.dev	= dev_out;
 	dev_hold(dev_out);
-	rth->rt_gateway = key.dst;
-	rth->rt_spec_dst= key.src;
+	rth->rt_gateway = fl.fl4_dst;
+	rth->rt_spec_dst= fl.fl4_src;
 
 	rth->u.dst.output=ip_output;
 
@@ -1949,10 +1947,10 @@
 
 	if (flags & RTCF_LOCAL) {
 		rth->u.dst.input = ip_local_deliver;
-		rth->rt_spec_dst = key.dst;
+		rth->rt_spec_dst = fl.fl4_dst;
 	}
 	if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
-		rth->rt_spec_dst = key.src;
+		rth->rt_spec_dst = fl.fl4_src;
 		if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) {
 			rth->u.dst.output = ip_mc_output;
 			rt_cache_stat[smp_processor_id()].out_slow_mc++;
@@ -1962,7 +1960,7 @@
 			struct in_device *in_dev = in_dev_get(dev_out);
 			if (in_dev) {
 				if (IN_DEV_MFORWARD(in_dev) &&
-				    !LOCAL_MCAST(oldkey->dst)) {
+				    !LOCAL_MCAST(oldflp->fl4_dst)) {
 					rth->u.dst.input = ip_mr_input;
 					rth->u.dst.output = ip_mc_output;
 				}
@@ -1976,7 +1974,7 @@
 
 	rth->rt_flags = flags;
 
-	hash = rt_hash_code(oldkey->dst, oldkey->src ^ (oldkey->oif << 5), tos);
+	hash = rt_hash_code(oldflp->fl4_dst, oldflp->fl4_src ^ (oldflp->oif << 5), tos);
 	err = rt_intern_hash(hash, rth, rp);
 done:
 	if (free_res)
@@ -1993,23 +1991,23 @@
 	goto done;
 }
 
-int ip_route_output_key(struct rtable **rp, const struct rt_key *key)
+int ip_route_output_key(struct rtable **rp, const struct flowi *flp)
 {
 	unsigned hash;
 	struct rtable *rth;
 
-	hash = rt_hash_code(key->dst, key->src ^ (key->oif << 5), key->tos);
+	hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5), flp->fl4_tos);
 
 	read_lock_bh(&rt_hash_table[hash].lock);
 	for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) {
-		if (rth->key.dst == key->dst &&
-		    rth->key.src == key->src &&
-		    rth->key.iif == 0 &&
-		    rth->key.oif == key->oif &&
+		if (rth->fl.fl4_dst == flp->fl4_dst &&
+		    rth->fl.fl4_src == flp->fl4_src &&
+		    rth->fl.iif == 0 &&
+		    rth->fl.oif == flp->oif &&
 #ifdef CONFIG_IP_ROUTE_FWMARK
-		    rth->key.fwmark == key->fwmark &&
+		    rth->fl.fl4_fwmark == flp->fl4_fwmark &&
 #endif
-		    !((rth->key.tos ^ key->tos) &
+		    !((rth->fl.fl4_tos ^ flp->fl4_tos) &
 			    (IPTOS_RT_MASK | RTO_ONLINK))) {
 			rth->u.dst.lastuse = jiffies;
 			dst_hold(&rth->u.dst);
@@ -2022,7 +2020,7 @@
 	}
 	read_unlock_bh(&rt_hash_table[hash].lock);
 
-	return ip_route_output_slow(rp, key);
+	return ip_route_output_slow(rp, flp);
 }	
 
 static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
@@ -2042,7 +2040,7 @@
 	r->rtm_family	 = AF_INET;
 	r->rtm_dst_len	= 32;
 	r->rtm_src_len	= 0;
-	r->rtm_tos	= rt->key.tos;
+	r->rtm_tos	= rt->fl.fl4_tos;
 	r->rtm_table	= RT_TABLE_MAIN;
 	r->rtm_type	= rt->rt_type;
 	r->rtm_scope	= RT_SCOPE_UNIVERSE;
@@ -2051,9 +2049,9 @@
 	if (rt->rt_flags & RTCF_NOTIFY)
 		r->rtm_flags |= RTM_F_NOTIFY;
 	RTA_PUT(skb, RTA_DST, 4, &rt->rt_dst);
-	if (rt->key.src) {
+	if (rt->fl.fl4_src) {
 		r->rtm_src_len = 32;
-		RTA_PUT(skb, RTA_SRC, 4, &rt->key.src);
+		RTA_PUT(skb, RTA_SRC, 4, &rt->fl.fl4_src);
 	}
 	if (rt->u.dst.dev)
 		RTA_PUT(skb, RTA_OIF, sizeof(int), &rt->u.dst.dev->ifindex);
@@ -2061,9 +2059,9 @@
 	if (rt->u.dst.tclassid)
 		RTA_PUT(skb, RTA_FLOW, 4, &rt->u.dst.tclassid);
 #endif
-	if (rt->key.iif)
+	if (rt->fl.iif)
 		RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_spec_dst);
-	else if (rt->rt_src != rt->key.src)
+	else if (rt->rt_src != rt->fl.fl4_src)
 		RTA_PUT(skb, RTA_PREFSRC, 4, &rt->rt_src);
 	if (rt->rt_dst != rt->rt_gateway)
 		RTA_PUT(skb, RTA_GATEWAY, 4, &rt->rt_gateway);
@@ -2089,7 +2087,7 @@
 	eptr = (struct rtattr*)skb->tail;
 #endif
 	RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
-	if (rt->key.iif) {
+	if (rt->fl.iif) {
 #ifdef CONFIG_IP_MROUTE
 		u32 dst = rt->rt_dst;
 
@@ -2109,7 +2107,7 @@
 			}
 		} else
 #endif
-			RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->key.iif);
+			RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif);
 	}
 
 	nlh->nlmsg_len = skb->tail - b;
@@ -2163,10 +2161,14 @@
 		if (!err && rt->u.dst.error)
 			err = -rt->u.dst.error;
 	} else {
+		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst,
+							 .saddr = src,
+							 .tos = rtm->rtm_tos } } };
 		int oif = 0;
 		if (rta[RTA_OIF - 1])
 			memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
-		err = ip_route_output(&rt, dst, src, rtm->rtm_tos, oif);
+		fl.oif = oif;
+		err = ip_route_output_key(&rt, &fl);
 	}
 	if (err) {
 		kfree_skb(skb);
diff -Nru a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
--- a/net/ipv4/syncookies.c	Tue Oct 15 20:29:11 2002
+++ b/net/ipv4/syncookies.c	Tue Oct 15 20:29:11 2002
@@ -171,14 +171,17 @@
 	 * hasn't changed since we received the original syn, but I see
 	 * no easy way to do this. 
 	 */
-	if (ip_route_output(&rt,
-			    opt && 
-			    opt->srr ? opt->faddr : req->af.v4_req.rmt_addr,
-			    req->af.v4_req.loc_addr,
-			    RT_CONN_FLAGS(sk),
-			    0)) { 
-		tcp_openreq_free(req);
-		goto out; 
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = ((opt && opt->srr) ?
+							  opt->faddr :
+							  req->af.v4_req.rmt_addr),
+						.saddr = req->af.v4_req.loc_addr,
+						.tos = RT_CONN_FLAGS(sk) } } };
+		if (ip_route_output_key(&rt, &fl)) {
+			tcp_openreq_free(req);
+			goto out; 
+		}
 	}
 
 	/* Try to redo what tcp_v4_send_synack did. */
diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
--- a/net/ipv4/sysctl_net_ipv4.c	Tue Oct 15 20:29:19 2002
+++ b/net/ipv4/sysctl_net_ipv4.c	Tue Oct 15 20:29:19 2002
@@ -221,6 +221,8 @@
 	 &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_TCP_TW_REUSE, "tcp_tw_reuse",
 	 &sysctl_tcp_tw_reuse, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_FRTO, "tcp_frto",
+	 &sysctl_tcp_frto, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Tue Oct 15 20:29:15 2002
+++ b/net/ipv4/tcp.c	Tue Oct 15 20:29:15 2002
@@ -1013,7 +1013,8 @@
 	return tmp;
 }
 
-int tcp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
+int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		int size)
 {
 	struct iovec *iov;
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -1475,7 +1476,7 @@
  *	Probably, code can be easily improved even more.
  */
 
-int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
+int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		int len, int nonblock, int flags, int *addr_len)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c	Tue Oct 15 20:29:12 2002
+++ b/net/ipv4/tcp_input.c	Tue Oct 15 20:29:12 2002
@@ -60,6 +60,7 @@
  *		Pasi Sarolahti,
  *		Panu Kuhlberg:		Experimental audit of TCP (re)transmission
  *					engine. Lots of bugs are found.
+ *		Pasi Sarolahti:		F-RTO for dealing with spurious RTOs
  */
 
 #include <linux/config.h>
@@ -86,6 +87,7 @@
 int sysctl_tcp_stdurg = 0;
 int sysctl_tcp_rfc1337 = 0;
 int sysctl_tcp_max_orphans = NR_FILE;
+int sysctl_tcp_frto = 0;
 
 #define FLAG_DATA		0x01 /* Incoming frame contained data.		*/
 #define FLAG_WIN_UPDATE		0x02 /* Incoming ACK was a window update.	*/
@@ -968,6 +970,89 @@
 	return flag;
 }
 
+/* RTO occurred, but do not yet enter loss state. Instead, transmit two new
+ * segments to see from the next ACKs whether any data was really missing.
+ * If the RTO was spurious, new ACKs should arrive.
+ */
+void tcp_enter_frto(struct sock *sk)
+{
+	struct tcp_opt *tp = tcp_sk(sk);
+	struct sk_buff *skb;
+
+	tp->frto_counter = 1;
+
+	if (tp->ca_state <= TCP_CA_Disorder ||
+            tp->snd_una == tp->high_seq ||
+            (tp->ca_state == TCP_CA_Loss && !tp->retransmits)) {
+		tp->prior_ssthresh = tcp_current_ssthresh(tp);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+	}
+
+	/* Have to clear retransmission markers here to keep the bookkeeping
+	 * in shape, even though we are not yet in Loss state.
+	 * If something was really lost, it is eventually caught up
+	 * in tcp_enter_frto_loss.
+	 */
+	tp->retrans_out = 0;
+	tp->undo_marker = tp->snd_una;
+	tp->undo_retrans = 0;
+
+	for_retrans_queue(skb, sk, tp) {
+		TCP_SKB_CB(skb)->sacked &= ~TCPCB_RETRANS;
+	}
+	tcp_sync_left_out(tp);
+
+	tp->ca_state = TCP_CA_Open;
+	tp->frto_highmark = tp->snd_nxt;
+}
+
+/* Enter Loss state after F-RTO was applied. Dupack arrived after RTO,
+ * which indicates that we should follow the traditional RTO recovery,
+ * i.e. mark everything lost and do go-back-N retransmission.
+ */
+void tcp_enter_frto_loss(struct sock *sk)
+{
+	struct tcp_opt *tp = tcp_sk(sk);
+	struct sk_buff *skb;
+	int cnt = 0;
+
+	tp->sacked_out = 0;
+	tp->lost_out = 0;
+	tp->fackets_out = 0;
+
+	for_retrans_queue(skb, sk, tp) {
+		cnt++;
+		TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST;
+		if (!(TCP_SKB_CB(skb)->sacked&TCPCB_SACKED_ACKED)) {
+
+			/* Do not mark those segments lost that were
+			 * forward transmitted after RTO
+			 */
+			if(!after(TCP_SKB_CB(skb)->end_seq,
+				   tp->frto_highmark)) {
+				TCP_SKB_CB(skb)->sacked |= TCPCB_LOST;
+				tp->lost_out++;
+			}
+		} else {
+			tp->sacked_out++;
+			tp->fackets_out = cnt;
+		}
+	}
+	tcp_sync_left_out(tp);
+
+	tp->snd_cwnd = tp->frto_counter + tcp_packets_in_flight(tp)+1;
+	tp->snd_cwnd_cnt = 0;
+	tp->snd_cwnd_stamp = tcp_time_stamp;
+	tp->undo_marker = 0;
+	tp->frto_counter = 0;
+
+	tp->reordering = min_t(unsigned int, tp->reordering,
+					     sysctl_tcp_reordering);
+	tp->ca_state = TCP_CA_Loss;
+	tp->high_seq = tp->frto_highmark;
+	TCP_ECN_queue_cwr(tp);
+}
+
 void tcp_clear_retrans(struct tcp_opt *tp)
 {
 	tp->left_out = 0;
@@ -1539,7 +1624,8 @@
 	/* E. Check state exit conditions. State can be terminated
 	 *    when high_seq is ACKed. */
 	if (tp->ca_state == TCP_CA_Open) {
-		BUG_TRAP(tp->retrans_out == 0);
+		if (!sysctl_tcp_frto)
+			BUG_TRAP(tp->retrans_out == 0);
 		tp->retrans_stamp = 0;
 	} else if (!before(tp->snd_una, tp->high_seq)) {
 		switch (tp->ca_state) {
@@ -1910,6 +1996,41 @@
 	return flag;
 }
 
+static void tcp_process_frto(struct sock *sk, u32 prior_snd_una)
+{
+	struct tcp_opt *tp = tcp_sk(sk);
+	
+	tcp_sync_left_out(tp);
+	
+	if (tp->snd_una == prior_snd_una ||
+	    !before(tp->snd_una, tp->frto_highmark)) {
+		/* RTO was caused by loss, start retransmitting in
+		 * go-back-N slow start
+		 */
+		tcp_enter_frto_loss(sk);
+		return;
+	}
+
+	if (tp->frto_counter == 1) {
+		/* First ACK after RTO advances the window: allow two new
+		 * segments out.
+		 */
+		tp->snd_cwnd = tcp_packets_in_flight(tp) + 2;
+	} else {
+		/* Also the second ACK after RTO advances the window.
+		 * The RTO was likely spurious. Reduce cwnd and continue
+		 * in congestion avoidance
+		 */
+		tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
+		tcp_moderate_cwnd(tp);
+	}
+
+	/* F-RTO affects on two new ACKs following RTO.
+	 * At latest on third ACK the TCP behavor is back to normal.
+	 */
+	tp->frto_counter = (tp->frto_counter + 1) % 3;
+}
+
 /* This routine deals with incoming acks, but not outgoing ones. */
 static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
 {
@@ -1967,6 +2088,9 @@
 
 	/* See if we can take anything off of the retransmit queue. */
 	flag |= tcp_clean_rtx_queue(sk);
+
+	if (tp->frto_counter)
+		tcp_process_frto(sk, prior_snd_una);
 
 	if (tcp_ack_is_dubious(tp, flag)) {
 		/* Advanve CWND, if state allows this. */
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c	Tue Oct 15 20:29:15 2002
+++ b/net/ipv4/tcp_ipv4.c	Tue Oct 15 20:29:15 2002
@@ -1266,11 +1266,15 @@
 {
 	struct rtable *rt;
 	struct ip_options *opt = req->af.v4_req.opt;
+	struct flowi fl = { .nl_u = { .ip4_u =
+				      { .daddr = ((opt && opt->srr) ?
+						  opt->faddr :
+						  req->af.v4_req.rmt_addr),
+					.saddr = req->af.v4_req.loc_addr,
+					.tos = RT_CONN_FLAGS(sk) } },
+			    .oif = sk->bound_dev_if };
 
-	if (ip_route_output(&rt, ((opt && opt->srr) ? opt->faddr :
-						      req->af.v4_req.rmt_addr),
-			   req->af.v4_req.loc_addr,
-			   RT_CONN_FLAGS(sk), sk->bound_dev_if)) {
+	if (ip_route_output_key(&rt, &fl)) {
 		IP_INC_STATS_BH(IpOutNoRoutes);
 		return NULL;
 	}
@@ -1909,8 +1913,15 @@
 	if (inet->opt && inet->opt->srr)
 		daddr = inet->opt->faddr;
 
-	err = ip_route_output(&rt, daddr, inet->saddr,
-			      RT_CONN_FLAGS(sk), sk->bound_dev_if);
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = daddr,
+						.saddr = inet->saddr,
+						.tos = RT_CONN_FLAGS(sk) } },
+				    .oif = sk->bound_dev_if };
+						
+		err = ip_route_output_key(&rt, &fl);
+	}
 	if (!err) {
 		__sk_dst_set(sk, &rt->u.dst);
 		tcp_v4_setup_caps(sk, &rt->u.dst);
diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
--- a/net/ipv4/tcp_minisocks.c	Tue Oct 15 20:29:13 2002
+++ b/net/ipv4/tcp_minisocks.c	Tue Oct 15 20:29:13 2002
@@ -718,6 +718,9 @@
 		newtp->snd_cwnd = 2;
 		newtp->snd_cwnd_cnt = 0;
 
+		newtp->frto_counter = 0;
+		newtp->frto_highmark = 0;
+
 		newtp->ca_state = TCP_CA_Open;
 		tcp_init_xmit_timers(newsk);
 		skb_queue_head_init(&newtp->out_of_order_queue);
diff -Nru a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
--- a/net/ipv4/tcp_timer.c	Tue Oct 15 20:29:21 2002
+++ b/net/ipv4/tcp_timer.c	Tue Oct 15 20:29:21 2002
@@ -374,7 +374,11 @@
 		}
 	}
 
-	tcp_enter_loss(sk, 0);
+	if (tcp_use_frto(sk)) {
+		tcp_enter_frto(sk);
+	} else {
+		tcp_enter_loss(sk, 0);
+	}
 
 	if (tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)) > 0) {
 		/* Retransmission failed because of local congestion,
diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c
--- a/net/ipv4/udp.c	Tue Oct 15 20:29:12 2002
+++ b/net/ipv4/udp.c	Tue Oct 15 20:29:12 2002
@@ -61,6 +61,7 @@
  *					return ENOTCONN for unconnected sockets (POSIX)
  *		Janos Farkas	:	don't deliver multi/broadcasts to a different
  *					bound-to-device socket
+ *		Arnaldo C. Melo :	move proc routines to ip_proc.c.
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -423,7 +424,8 @@
 				   fraglen);
 }
 
-int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
+int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		int len)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	int ulen = len + sizeof(struct udphdr);
@@ -528,7 +530,12 @@
 		rt = (struct rtable*)sk_dst_check(sk, 0);
 
 	if (rt == NULL) {
-		err = ip_route_output(&rt, daddr, ufh.saddr, tos, ipc.oif);
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = daddr,
+						.saddr = ufh.saddr,
+						.tos = tos } },
+				    .oif = ipc.oif };
+		err = ip_route_output_key(&rt, &fl);
 		if (err)
 			goto out;
 
@@ -635,8 +642,8 @@
  * 	return it, otherwise we block.
  */
 
-int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
-		int noblock, int flags, int *addr_len)
+int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+		int len, int noblock, int flags, int *addr_len)
 {
 	struct inet_opt *inet = inet_sk(sk);
   	struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
@@ -976,66 +983,6 @@
 	UDP_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
 	return(0);
-}
-
-static void get_udp_sock(struct sock *sp, char *tmpbuf, int i)
-{
-	struct inet_opt *inet = inet_sk(sp);
-	unsigned int dest, src;
-	__u16 destp, srcp;
-
-	dest  = inet->daddr;
-	src   = inet->rcv_saddr;
-	destp = ntohs(inet->dport);
-	srcp  = ntohs(inet->sport);
-	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
-		i, src, srcp, dest, destp, sp->state, 
-		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
-		0, 0L, 0,
-		sock_i_uid(sp), 0,
-		sock_i_ino(sp),
-		atomic_read(&sp->refcnt), sp);
-}
-
-int udp_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	int len = 0, num = 0, i;
-	off_t pos = 0;
-	off_t begin;
-	char tmpbuf[129];
-
-	if (offset < 128) 
-		len += sprintf(buffer, "%-127s\n",
-			       "  sl  local_address rem_address   st tx_queue "
-			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");
-	pos = 128;
-	read_lock(&udp_hash_lock);
-	for (i = 0; i < UDP_HTABLE_SIZE; i++) {
-		struct sock *sk;
-
-		for (sk = udp_hash[i]; sk; sk = sk->next, num++) {
-			if (sk->family != PF_INET)
-				continue;
-			pos += 128;
-			if (pos <= offset)
-				continue;
-			get_udp_sock(sk, tmpbuf, i);
-			len += sprintf(buffer+len, "%-127s\n", tmpbuf);
-			if(len >= length)
-				goto out;
-		}
-	}
-out:
-	read_unlock(&udp_hash_lock);
-	begin = len - (pos - offset);
-	*start = buffer + begin;
-	len -= begin;
-	if(len > length)
-		len = length;
-	if (len < 0)
-		len = 0; 
-	return len;
 }
 
 struct proto udp_prot = {
diff -Nru a/net/ipv6/Config.in b/net/ipv6/Config.in
--- a/net/ipv6/Config.in	Tue Oct 15 20:29:17 2002
+++ b/net/ipv6/Config.in	Tue Oct 15 20:29:17 2002
@@ -2,9 +2,6 @@
 # IPv6 configuration
 # 
 
-#bool '    IPv6: flow policy support' CONFIG_RT6_POLICY
-#bool '    IPv6: firewall support' CONFIG_IPV6_FIREWALL
-
 if [ "$CONFIG_NETFILTER" != "n" ]; then
    source net/ipv6/netfilter/Config.in
 fi
diff -Nru a/net/ipv6/Makefile b/net/ipv6/Makefile
--- a/net/ipv6/Makefile	Tue Oct 15 20:29:20 2002
+++ b/net/ipv6/Makefile	Tue Oct 15 20:29:20 2002
@@ -12,7 +12,6 @@
 		exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
 		ip6_flowlabel.o ipv6_syms.o
 
-#obj-$(CONFIG_IPV6_FIREWALL) += ip6_fw.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
--- a/net/ipv6/ip6_fib.c	Tue Oct 15 20:29:14 2002
+++ b/net/ipv6/ip6_fib.c	Tue Oct 15 20:29:14 2002
@@ -452,7 +452,6 @@
 			 */
 
 			if ((iter->rt6i_dev == rt->rt6i_dev) &&
-			    (iter->rt6i_flowr == rt->rt6i_flowr) &&
 			    (ipv6_addr_cmp(&iter->rt6i_gateway,
 					   &rt->rt6i_gateway) == 0)) {
 				if (!(iter->rt6i_flags&RTF_EXPIRES))
diff -Nru a/net/ipv6/ip6_fw.c b/net/ipv6/ip6_fw.c
--- a/net/ipv6/ip6_fw.c	Tue Oct 15 20:29:23 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,390 +0,0 @@
-/*
- *	IPv6 Firewall
- *	Linux INET6 implementation
- *
- *	Authors:
- *	Pedro Roque		<roque@di.fc.ul.pt>	
- *
- *	$Id: ip6_fw.c,v 1.16 2001/10/31 08:17:58 davem Exp $
- *
- *	This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/route.h>
-#include <linux/netdevice.h>
-#include <linux/in6.h>
-#include <linux/udp.h>
-#include <linux/init.h>
-
-#include <net/ipv6.h>
-#include <net/ip6_route.h>
-#include <net/ip6_fw.h>
-#include <net/netlink.h>
-
-static unsigned long ip6_fw_rule_cnt;
-static struct ip6_fw_rule ip6_fw_rule_list = {
-	{0},
-	NULL, NULL,
-	{0},
-	IP6_FW_REJECT
-};
-
-static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args);
-
-struct flow_rule_ops ip6_fw_ops = {
-	ip6_fw_accept
-};
-
-
-static struct rt6_info ip6_fw_null_entry = {
-	{{NULL, 0, 0, NULL,
-	  0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL,
-	  ip6_pkt_discard, ip6_pkt_discard, NULL}},
-	NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0UL,
-	0, &ip6_fw_rule_list, {{{{0}}}, 128}, {{{{0}}}, 128}
-};
-
-static struct fib6_node ip6_fw_fib = {
-	NULL, NULL, NULL, NULL,
-	&ip6_fw_null_entry,
-	0, RTN_ROOT|RTN_TL_ROOT, 0
-};
-
-rwlock_t ip6_fw_lock = RW_LOCK_UNLOCKED;
-
-
-static void ip6_rule_add(struct ip6_fw_rule *rl)
-{
-	struct ip6_fw_rule *next;
-
-	write_lock_bh(&ip6_fw_lock);
-	ip6_fw_rule_cnt++;
-	next = &ip6_fw_rule_list;
-	rl->next = next;
-	rl->prev = next->prev;
-	rl->prev->next = rl;
-	next->prev = rl;
-	write_unlock_bh(&ip6_fw_lock);
-}
-
-static void ip6_rule_del(struct ip6_fw_rule *rl)
-{
-	struct ip6_fw_rule *next, *prev;
-
-	write_lock_bh(&ip6_fw_lock);
-	ip6_fw_rule_cnt--;
-	next = rl->next;
-	prev = rl->prev;
-	next->prev = prev;
-	prev->next = next;
-	write_unlock_bh(&ip6_fw_lock);
-}
-
-static __inline__ struct ip6_fw_rule * ip6_fwrule_alloc(void)
-{
-	struct ip6_fw_rule *rl;
-
-	rl = kmalloc(sizeof(struct ip6_fw_rule), GFP_ATOMIC);
-	if (rl)
-	{
-		memset(rl, 0, sizeof(struct ip6_fw_rule));
-		rl->flowr.ops = &ip6_fw_ops;
-	}
-	return rl;
-}
-
-static __inline__ void ip6_fwrule_free(struct ip6_fw_rule * rl)
-{
-	kfree(rl);
-}
-
-static __inline__ int port_match(int rl_port, int fl_port)
-{
-	int res = 0;
-	if (rl_port == 0 || (rl_port == fl_port))
-		res = 1;
-	return res;
-}
-
-static int ip6_fw_accept_trans(struct ip6_fw_rule *rl,
-			       struct fl_acc_args *args)
-{
-	int res = FLOWR_NODECISION;
-	int proto = 0;
-	int sport = 0;
-	int dport = 0;
-
-	switch (args->type) {
-	case FL_ARG_FORWARD:
-	{
-		struct sk_buff *skb = args->fl_u.skb;
-		struct ipv6hdr *hdr = skb->nh.ipv6h;
-		int len;
-
-		len = skb->len - sizeof(struct ipv6hdr);
-
-		proto = hdr->nexthdr;
-
-		switch (proto) {
-		case IPPROTO_TCP:
-		{
-			struct tcphdr *th;
-
-			if (len < sizeof(struct tcphdr)) {
-				res = FLOWR_ERROR;
-				goto out;
-			}
-			th = (struct tcphdr *)(hdr + 1);
-			sport = th->source;
-			dport = th->dest;
-			break;
-		}
-		case IPPROTO_UDP:
-		{
-			struct udphdr *uh;
-
-			if (len < sizeof(struct udphdr)) {
-				res = FLOWR_ERROR;
-				goto out;
-			}
-			uh = (struct udphdr *)(hdr + 1);
-			sport = uh->source;
-			dport = uh->dest;
-			break;
-		}
-		default:
-			goto out;
-		};
-		break;
-	}
-
-	case FL_ARG_ORIGIN:
-	{
-		proto = args->fl_u.fl_o.flow->proto;
-
-		if (proto == IPPROTO_ICMPV6) {
-			goto out;
-		} else {
-			sport = args->fl_u.fl_o.flow->uli_u.ports.sport;
-			dport = args->fl_u.fl_o.flow->uli_u.ports.dport;
-		}
-		break;
-	}
-
-	if (proto == rl->info.proto &&
-	    port_match(args->fl_u.fl_o.flow->uli_u.ports.sport, sport) &&
-	    port_match(args->fl_u.fl_o.flow->uli_u.ports.dport, dport)) {
-		if (rl->policy & IP6_FW_REJECT)
-			res = FLOWR_SELECT;
-		else
-			res = FLOWR_CLEAR;
-	}
-
-	default:
-#if IP6_FW_DEBUG >= 1
-		printk(KERN_DEBUG "ip6_fw_accept: unknown arg type\n");
-#endif
-		goto out;
-	};
-
-out:
-	return res;
-}
-
-static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args)
-{
-	struct rt6_info *rt;
-	struct ip6_fw_rule *rl;
-	int proto;
-	int res = FLOWR_NODECISION;
-
-	rt = (struct rt6_info *) dst;
-	rl = (struct ip6_fw_rule *) rt->rt6i_flowr;
-
-	proto = rl->info.proto;
-
-	switch (proto) {
-	case 0:
-		if (rl->policy & IP6_FW_REJECT)
-			res = FLOWR_SELECT;
-		else
-			res = FLOWR_CLEAR;
-		break;
-	case IPPROTO_TCP:
-	case IPPROTO_UDP:
-		res = ip6_fw_accept_trans(rl, args);
-		break;
-	case IPPROTO_ICMPV6:
-	};
-
-	return res;
-}
-
-static struct dst_entry * ip6_fw_dup(struct dst_entry *frule,
-				     struct dst_entry *rt,
-				     struct fl_acc_args *args)
-{
-	struct ip6_fw_rule *rl;
-	struct rt6_info *nrt;
-	struct rt6_info *frt;
-
-	frt = (struct rt6_info *) frule;
-
-	rl = (struct ip6_fw_rule *) frt->rt6i_flowr;
-
-	nrt = ip6_rt_copy((struct rt6_info *) rt);
-
-	if (nrt) {
-		nrt->u.dst.input = frule->input;
-		nrt->u.dst.output = frule->output;
-
-		nrt->rt6i_flowr = flow_clone(frt->rt6i_flowr);
-
-		nrt->rt6i_flags |= RTF_CACHE;
-		nrt->rt6i_tstamp = jiffies;
-	}
-
-	return (struct dst_entry *) nrt;
-}
-
-int ip6_fw_reject(struct sk_buff *skb)
-{
-#if IP6_FW_DEBUG >= 1
-	printk(KERN_DEBUG "packet rejected: \n");
-#endif
-
-	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0,
-		    skb->dev);
-	/*
-	 *	send it via netlink, as (rule, skb)
-	 */
-
-	kfree_skb(skb);
-	return 0;
-}
-
-int ip6_fw_discard(struct sk_buff *skb)
-{
-	printk(KERN_DEBUG "ip6_fw: BUG fw_reject called\n");
-	kfree_skb(skb);
-	return 0;
-}
-
-int ip6_fw_msg_add(struct ip6_fw_msg *msg)
-{
-	struct in6_rtmsg rtmsg;
-	struct ip6_fw_rule *rl;
-	struct rt6_info *rt;
-	int err;
-
-	ipv6_addr_copy(&rtmsg.rtmsg_dst, &msg->dst);
-	ipv6_addr_copy(&rtmsg.rtmsg_src, &msg->src);
-	rtmsg.rtmsg_dst_len = msg->dst_len;
-	rtmsg.rtmsg_src_len = msg->src_len;
-	rtmsg.rtmsg_metric = IP6_RT_PRIO_FW;
-
-	rl = ip6_fwrule_alloc();
-
-	if (rl == NULL)
-		return -ENOMEM;
-
-	rl->policy = msg->policy;
-	rl->info.proto = msg->proto;
-	rl->info.uli_u.data = msg->u.data;
-
-	rtmsg.rtmsg_flags = RTF_NONEXTHOP|RTF_POLICY;
-	err = ip6_route_add(&rtmsg);
-
-	if (err) {
-		ip6_fwrule_free(rl);
-		return err;
-	}
-
-	/* The rest will not work for now. --ABK (989725) */
-
-#ifndef notdef
-	ip6_fwrule_free(rl);
-	return -EPERM;
-#else
-	rt->u.dst.error = -EPERM;
-
-	if (msg->policy == IP6_FW_ACCEPT) {
-		/*
-		 *	Accept rules are never selected
-		 *	(i.e. packets use normal forwarding)
-		 */
-		rt->u.dst.input = ip6_fw_discard;
-		rt->u.dst.output = ip6_fw_discard;
-	} else {
-		rt->u.dst.input = ip6_fw_reject;
-		rt->u.dst.output = ip6_fw_reject;
-	}
-
-	ip6_rule_add(rl);
-
-	rt->rt6i_flowr = flow_clone((struct flow_rule *)rl);
-
-	return 0;
-#endif
-}
-
-static int ip6_fw_msgrcv(int unit, struct sk_buff *skb)
-{
-	int count = 0;
-
-	while (skb->len) {
-		struct ip6_fw_msg *msg;
-
-		if (skb->len < sizeof(struct ip6_fw_msg)) {
-			count = -EINVAL;
-			break;
-		}
-
-		msg = (struct ip6_fw_msg *) skb->data;
-		skb_pull(skb, sizeof(struct ip6_fw_msg));
-		count += sizeof(struct ip6_fw_msg);
-
-		switch (msg->action) {
-		case IP6_FW_MSG_ADD:
-			ip6_fw_msg_add(msg);
-			break;
-		case IP6_FW_MSG_DEL:
-			break;
-		default:
-			return -EINVAL;
-		};
-	}
-
-	return count;
-}
-
-static void ip6_fw_destroy(struct flow_rule *rl)
-{
-	ip6_fwrule_free((struct ip6_fw_rule *)rl);
-}
-
-#ifdef MODULE
-#define ip6_fw_init module_init
-#endif
-
-void __init ip6_fw_init(void)
-{
-	netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
-	netlink_detach(NETLINK_IP6_FW);
-}
-#endif
diff -Nru a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
--- a/net/ipv6/netfilter/ip6t_LOG.c	Tue Oct 15 20:29:15 2002
+++ b/net/ipv6/netfilter/ip6t_LOG.c	Tue Oct 15 20:29:15 2002
@@ -289,12 +289,39 @@
 		/* MAC logging for input chain only. */
 		printk("MAC=");
 		if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)ipv6h) {
-			int i;
-			unsigned char *p = (*pskb)->mac.raw;
-			for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
+			if ((*pskb)->dev->type != ARPHRD_SIT){
+			  int i;
+			  unsigned char *p = (*pskb)->mac.raw;
+			  for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
 				printk("%02x%c", *p,
-				       i==(*pskb)->dev->hard_header_len - 1
-				       ? ' ':':');
+			       		i==(*pskb)->dev->hard_header_len - 1
+			       		? ' ':':');
+			} else {
+			  int i;
+			  unsigned char *p = (*pskb)->mac.raw;
+			  if ( p - (ETH_ALEN*2+2) > (*pskb)->head ){
+			    p -= (ETH_ALEN+2);
+			    for (i = 0; i < (ETH_ALEN); i++,p++)
+				printk("%02x%s", *p,
+					i == ETH_ALEN-1 ? "->" : ":");
+			    p -= (ETH_ALEN*2);
+			    for (i = 0; i < (ETH_ALEN); i++,p++)
+				printk("%02x%c", *p,
+					i == ETH_ALEN-1 ? ' ' : ':');
+			  }
+			  
+			  if (((*pskb)->dev->addr_len == 4) &&
+			      (*pskb)->dev->hard_header_len > 20){
+			    printk("TUNNEL=");
+			    p = (*pskb)->mac.raw + 12;
+			    for (i = 0; i < 4; i++,p++)
+				printk("%3d%s", *p,
+					i == 3 ? "->" : ".");
+			    for (i = 0; i < 4; i++,p++)
+				printk("%3d%c", *p,
+					i == 3 ? ' ' : '.');
+			  }
+			}
 		} else
 			printk(" ");
 	}
diff -Nru a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
--- a/net/ipv6/netfilter/ip6table_mangle.c	Tue Oct 15 20:29:16 2002
+++ b/net/ipv6/netfilter/ip6table_mangle.c	Tue Oct 15 20:29:16 2002
@@ -157,7 +157,7 @@
 	hop_limit = (*pskb)->nh.ipv6h->hop_limit;
 
 	/* flowlabel and prio (includes version, which shouldn't change either */
-	flowlabel = (u_int32_t) (*pskb)->nh.ipv6h;
+	flowlabel = *((u_int32_t *) (*pskb)->nh.ipv6h);
 
 	ret = ip6t_do_table(pskb, hook, in, out, &packet_mangler, NULL);
 
diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c	Tue Oct 15 20:29:16 2002
+++ b/net/ipv6/raw.c	Tue Oct 15 20:29:16 2002
@@ -344,7 +344,7 @@
  *	we return it, otherwise we block.
  */
 
-static int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
+static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len,
 		  int noblock, int flags, int *addr_len)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -500,7 +500,7 @@
 }
 
 
-static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
+static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len)
 {
 	struct ipv6_txoptions opt_space;
 	struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c
--- a/net/ipv6/route.c	Tue Oct 15 20:29:12 2002
+++ b/net/ipv6/route.c	Tue Oct 15 20:29:12 2002
@@ -56,8 +56,6 @@
 #include <linux/sysctl.h>
 #endif
 
-#undef CONFIG_RT6_POLICY
-
 /* Set to 3 to get tracing. */
 #define RT6_DEBUG 2
 
@@ -103,16 +101,22 @@
 };
 
 struct rt6_info ip6_null_entry = {
-	{{NULL, ATOMIC_INIT(1), 1, &loopback_dev,
-	  -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	  -ENETUNREACH, NULL, NULL,
-	  ip6_pkt_discard, ip6_pkt_discard,
-#ifdef CONFIG_NET_CLS_ROUTE
-	  0,
-#endif
-	  &ip6_dst_ops}},
-	NULL, {{{0}}}, RTF_REJECT|RTF_NONEXTHOP, ~0U,
-	255, ATOMIC_INIT(1), {NULL}, {{{{0}}}, 0}, {{{{0}}}, 0}
+	.u = {
+		.dst = {
+			.__refcnt	= ATOMIC_INIT(1),
+			.__use		= 1,
+			.dev		= &loopback_dev,
+			.obsolete	= -1,
+			.error		= -ENETUNREACH,
+			.input		= ip6_pkt_discard,
+			.output		= ip6_pkt_discard,
+			.ops		= &ip6_dst_ops
+		}
+	},
+	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
+	.rt6i_metric	= ~(u32) 0,
+	.rt6i_hoplimit	= 255,
+	.rt6i_ref	= ATOMIC_INIT(1),
 };
 
 struct fib6_node ip6_routing_table = {
@@ -121,24 +125,6 @@
 	0, RTN_ROOT|RTN_TL_ROOT|RTN_RTINFO, 0
 };
 
-#ifdef CONFIG_RT6_POLICY
-int	ip6_rt_policy = 0;
-
-struct pol_chain *rt6_pol_list = NULL;
-
-
-static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb);
-static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk);
-
-static struct rt6_info	*rt6_flow_lookup(struct rt6_info *rt,
-					 struct in6_addr *daddr,
-					 struct in6_addr *saddr,
-					 struct fl_acc_args *args);
-
-#else
-#define ip6_rt_policy (0)
-#endif
-
 /* Protects all the ip6 fib */
 
 rwlock_t rt6_lock = RW_LOCK_UNLOCKED;
@@ -386,38 +372,6 @@
 	return &ip6_null_entry;
 }
 
-#ifdef CONFIG_RT6_POLICY
-static __inline__ struct rt6_info *rt6_flow_lookup_in(struct rt6_info *rt,
-						      struct sk_buff *skb)
-{
-	struct in6_addr *daddr, *saddr;
-	struct fl_acc_args arg;
-
-	arg.type = FL_ARG_FORWARD;
-	arg.fl_u.skb = skb;
-
-	saddr = &skb->nh.ipv6h->saddr;
-	daddr = &skb->nh.ipv6h->daddr;
-
-	return rt6_flow_lookup(rt, daddr, saddr, &arg);
-}
-
-static __inline__ struct rt6_info *rt6_flow_lookup_out(struct rt6_info *rt,
-						       struct sock *sk,
-						       struct flowi *fl)
-{
-	struct fl_acc_args arg;
-
-	arg.type = FL_ARG_ORIGIN;
-	arg.fl_u.fl_o.sk = sk;
-	arg.fl_u.fl_o.flow = fl;
-
-	return rt6_flow_lookup(rt, fl->nl_u.ip6_u.daddr, fl->nl_u.ip6_u.saddr,
-			       &arg);
-}
-
-#endif
-
 #define BACKTRACK() \
 if (rt == &ip6_null_entry && strict) { \
        while ((fn = fn->parent) != NULL) { \
@@ -450,53 +404,29 @@
 	rt = fn->leaf;
 
 	if ((rt->rt6i_flags & RTF_CACHE)) {
-		if (ip6_rt_policy == 0) {
-			rt = rt6_device_match(rt, skb->dev->ifindex, strict);
-			BACKTRACK();
-			dst_clone(&rt->u.dst);
-			goto out;
-		}
-
-#ifdef CONFIG_RT6_POLICY
-		if ((rt->rt6i_flags & RTF_FLOW)) {
-			struct rt6_info *sprt;
-
-			for (sprt = rt; sprt; sprt = sprt->u.next) {
-				if (rt6_flow_match_in(sprt, skb)) {
-					rt = sprt;
-					dst_clone(&rt->u.dst);
-					goto out;
-				}
-			}
-		}
-#endif
+		rt = rt6_device_match(rt, skb->dev->ifindex, strict);
+		BACKTRACK();
+		dst_clone(&rt->u.dst);
+		goto out;
 	}
 
 	rt = rt6_device_match(rt, skb->dev->ifindex, 0);
 	BACKTRACK();
 
-	if (ip6_rt_policy == 0) {
-		if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-			read_unlock_bh(&rt6_lock);
+	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
+		read_unlock_bh(&rt6_lock);
 
-			rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
-				     &skb->nh.ipv6h->saddr);
+		rt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
+			     &skb->nh.ipv6h->saddr);
 			
-			if (rt->u.dst.error != -EEXIST || --attempts <= 0)
-				goto out2;
-			/* Race condition! In the gap, when rt6_lock was
-			   released someone could insert this route.  Relookup.
-			 */
-			goto relookup;
-		}
-		dst_clone(&rt->u.dst);
-	} else {
-#ifdef CONFIG_RT6_POLICY
-		rt = rt6_flow_lookup_in(rt, skb);
-#else
-		/* NEVER REACHED */
-#endif
+		if (rt->u.dst.error != -EEXIST || --attempts <= 0)
+			goto out2;
+		/* Race condition! In the gap, when rt6_lock was
+		   released someone could insert this route.  Relookup.
+		*/
+		goto relookup;
 	}
+	dst_clone(&rt->u.dst);
 
 out:
 	read_unlock_bh(&rt6_lock);
@@ -525,26 +455,10 @@
 	rt = fn->leaf;
 
 	if ((rt->rt6i_flags & RTF_CACHE)) {
-		if (ip6_rt_policy == 0) {
-			rt = rt6_device_match(rt, fl->oif, strict);
-			BACKTRACK();
-			dst_clone(&rt->u.dst);
-			goto out;
-		}
-
-#ifdef CONFIG_RT6_POLICY
-		if ((rt->rt6i_flags & RTF_FLOW)) {
-			struct rt6_info *sprt;
-
-			for (sprt = rt; sprt; sprt = sprt->u.next) {
-				if (rt6_flow_match_out(sprt, sk)) {
-					rt = sprt;
-					dst_clone(&rt->u.dst);
-					goto out;
-				}
-			}
-		}
-#endif
+		rt = rt6_device_match(rt, fl->oif, strict);
+		BACKTRACK();
+		dst_clone(&rt->u.dst);
+		goto out;
 	}
 	if (rt->rt6i_flags & RTF_DEFAULT) {
 		if (rt->rt6i_metric >= IP6_RT_PRIO_ADDRCONF)
@@ -554,29 +468,21 @@
 		BACKTRACK();
 	}
 
-	if (ip6_rt_policy == 0) {
-		if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
-			read_unlock_bh(&rt6_lock);
+	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
+		read_unlock_bh(&rt6_lock);
 
-			rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
-				     fl->nl_u.ip6_u.saddr);
+		rt = rt6_cow(rt, fl->nl_u.ip6_u.daddr,
+			     fl->nl_u.ip6_u.saddr);
 			
-			if (rt->u.dst.error != -EEXIST || --attempts <= 0)
-				goto out2;
+		if (rt->u.dst.error != -EEXIST || --attempts <= 0)
+			goto out2;
 
-			/* Race condition! In the gap, when rt6_lock was
-			   released someone could insert this route.  Relookup.
-			 */
-			goto relookup;
-		}
-		dst_clone(&rt->u.dst);
-	} else {
-#ifdef CONFIG_RT6_POLICY
-		rt = rt6_flow_lookup_out(rt, sk, fl);
-#else
-		/* NEVER REACHED */
-#endif
+		/* Race condition! In the gap, when rt6_lock was
+		   released someone could insert this route.  Relookup.
+		*/
+		goto relookup;
 	}
+	dst_clone(&rt->u.dst);
 
 out:
 	read_unlock_bh(&rt6_lock);
@@ -1303,121 +1209,6 @@
 
 	return err;
 }
-
-#ifdef CONFIG_RT6_POLICY
-
-static int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb)
-{
-	struct flow_filter *frule;
-	struct pkt_filter *filter;
-	int res = 1;
-
-	if ((frule = rt->rt6i_filter) == NULL)
-		goto out;
-
-	if (frule->type != FLR_INPUT) {
-		res = 0;
-		goto out;
-	}
-
-	for (filter = frule->u.filter; filter; filter = filter->next) {
-		__u32 *word;
-
-		word = (__u32 *) skb->h.raw;
-		word += filter->offset;
-
-		if ((*word ^ filter->value) & filter->mask) {
-			res = 0;
-			break;
-		}
-	}
-
-out:
-	return res;
-}
-
-static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk)
-{
-	struct flow_filter *frule;
-	int res = 1;
-
-	if ((frule = rt->rt6i_filter) == NULL)
-		goto out;
-
-	if (frule->type != FLR_INPUT) {
-		res = 0;
-		goto out;
-	}
-
-	if (frule->u.sk != sk)
-		res = 0;
-out:
-	return res;
-}
-
-static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt,
-					struct in6_addr *daddr,
-					struct in6_addr *saddr,
-					struct fl_acc_args *args)
-{
-	struct flow_rule *frule;
-	struct rt6_info *nrt = NULL;
-	struct pol_chain *pol;
-
-	for (pol = rt6_pol_list; pol; pol = pol->next) {
-		struct fib6_node *fn;
-		struct rt6_info *sprt;
-
-		fn = fib6_lookup(pol->rules, daddr, saddr);
-
-		do {
-			for (sprt = fn->leaf; sprt; sprt=sprt->u.next) {
-				int res;
-
-				frule = sprt->rt6i_flowr;
-#if RT6_DEBUG >= 2
-				if (frule == NULL) {
-					printk(KERN_DEBUG "NULL flowr\n");
-					goto error;
-				}
-#endif
-				res = frule->ops->accept(rt, sprt, args, &nrt);
-
-				switch (res) {
-				case FLOWR_SELECT:
-					goto found;
-				case FLOWR_CLEAR:
-					goto next_policy;
-				case FLOWR_NODECISION:
-					break;
-				default:
-					goto error;
-				};
-			}
-
-			fn = fn->parent;
-
-		} while ((fn->fn_flags & RTN_TL_ROOT) == 0);
-
-	next_policy:
-	}
-
-error:
-	dst_clone(&ip6_null_entry.u.dst);
-	return &ip6_null_entry;
-
-found:
-	if (nrt == NULL)
-		goto error;
-
-	nrt->rt6i_flags |= RTF_CACHE;
-	dst_clone(&nrt->u.dst);
-	err = rt6_ins(nrt);
-	if (err)
-		nrt->u.dst.error = err;
-	return nrt;
-}
-#endif
 
 static int fib6_ifdown(struct rt6_info *rt, void *arg)
 {
diff -Nru a/net/ipv6/sit.c b/net/ipv6/sit.c
--- a/net/ipv6/sit.c	Tue Oct 15 20:29:21 2002
+++ b/net/ipv6/sit.c	Tue Oct 15 20:29:21 2002
@@ -502,9 +502,16 @@
 		dst = addr6->s6_addr32[3];
 	}
 
-	if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) {
-		tunnel->stat.tx_carrier_errors++;
-		goto tx_error_icmp;
+	{
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = dst,
+						.saddr = tiph->saddr,
+						.tos = RT_TOS(tos) } },
+				    .oif = tunnel->parms.link };
+		if (ip_route_output_key(&rt, &fl)) {
+			tunnel->stat.tx_carrier_errors++;
+			goto tx_error_icmp;
+		}
 	}
 	if (rt->rt_type != RTN_UNICAST) {
 		tunnel->stat.tx_carrier_errors++;
@@ -777,8 +784,13 @@
 	ipip6_tunnel_init_gen(dev);
 
 	if (iph->daddr) {
+		struct flowi fl = { .nl_u = { .ip4_u =
+					      { .daddr = iph->daddr,
+						.saddr = iph->saddr,
+						.tos = RT_TOS(iph->tos) } },
+				    .oif = tunnel->parms.link };
 		struct rtable *rt;
-		if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) {
+		if (!ip_route_output_key(&rt, &fl)) {
 			tdev = rt->u.dst.dev;
 			ip_rt_put(rt);
 		}
diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c
--- a/net/ipv6/udp.c	Tue Oct 15 20:29:15 2002
+++ b/net/ipv6/udp.c	Tue Oct 15 20:29:15 2002
@@ -373,7 +373,7 @@
  * 	return it, otherwise we block.
  */
 
-static int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
+static int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len,
 		  int noblock, int flags, int *addr_len)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -765,7 +765,7 @@
 	return 0;
 }
 
-static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
+static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int ulen)
 {
 	struct ipv6_txoptions opt_space;
 	struct udpv6fakehdr udh;
@@ -794,7 +794,7 @@
 
 	if (sin6) {
 		if (sin6->sin6_family == AF_INET)
-			return udp_sendmsg(sk, msg, ulen);
+			return udp_sendmsg(iocb, sk, msg, ulen);
 
 		if (addr_len < SIN6_LEN_RFC2133)
 			return -EINVAL;
@@ -848,7 +848,7 @@
 		msg->msg_namelen = sizeof(sin);
 		fl6_sock_release(flowlabel);
 
-		return udp_sendmsg(sk, msg, ulen);
+		return udp_sendmsg(iocb, sk, msg, ulen);
 	}
 
 	udh.daddr = NULL;
diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
--- a/net/ipx/af_ipx.c	Tue Oct 15 20:29:12 2002
+++ b/net/ipx/af_ipx.c	Tue Oct 15 20:29:12 2002
@@ -2009,8 +2009,8 @@
 out:	return ret;
 }
 
-static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-	struct scm_cookie *scm)
+static int ipx_sendmsg(struct kiocb *iocb, struct socket *sock,
+	struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct ipx_opt *ipxs = ipx_sk(sk);
@@ -2069,8 +2069,8 @@
 }
 
 
-static int ipx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-		int flags, struct scm_cookie *scm)
+static int ipx_recvmsg(struct kiocb *iocb, struct socket *sock,
+		struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct ipx_opt *ipxs = ipx_sk(sk);
diff -Nru a/net/irda/af_irda.c b/net/irda/af_irda.c
--- a/net/irda/af_irda.c	Tue Oct 15 20:29:15 2002
+++ b/net/irda/af_irda.c	Tue Oct 15 20:29:15 2002
@@ -1253,14 +1253,14 @@
 }
 
 /*
- * Function irda_sendmsg (sock, msg, len, scm)
+ * Function irda_sendmsg (iocb, sock, msg, len, scm)
  *
  *    Send message down to TinyTP. This function is used for both STREAM and
  *    SEQPACK services. This is possible since it forces the client to
  *    fragment the message if necessary
  */
-static int irda_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-			struct scm_cookie *scm)
+static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct irda_sock *self;
@@ -1326,13 +1326,14 @@
 }
 
 /*
- * Function irda_recvmsg_dgram (sock, msg, size, flags, scm)
+ * Function irda_recvmsg_dgram (iocb, sock, msg, size, flags, scm)
  *
  *    Try to receive message and copy it to user. The frame is discarded
  *    after being read, regardless of how much the user actually read
  */
-static int irda_recvmsg_dgram(struct socket *sock, struct msghdr *msg,
-			      int size, int flags, struct scm_cookie *scm)
+static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
+			      struct msghdr *msg, int size, int flags,
+			      struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct irda_sock *self = irda_sk(sk);
@@ -1379,10 +1380,11 @@
 }
 
 /*
- * Function irda_recvmsg_stream (sock, msg, size, flags, scm)
+ * Function irda_recvmsg_stream (iocb, sock, msg, size, flags, scm)
  */
-static int irda_recvmsg_stream(struct socket *sock, struct msghdr *msg,
-			       int size, int flags, struct scm_cookie *scm)
+static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
+			       struct msghdr *msg, int size, int flags,
+			       struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct irda_sock *self = irda_sk(sk);
@@ -1502,14 +1504,14 @@
 }
 
 /*
- * Function irda_sendmsg_dgram (sock, msg, len, scm)
+ * Function irda_sendmsg_dgram (iocb, sock, msg, len, scm)
  *
  *    Send message down to TinyTP for the unreliable sequenced
  *    packet service...
  *
  */
-static int irda_sendmsg_dgram(struct socket *sock, struct msghdr *msg,
-			      int len, struct scm_cookie *scm)
+static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
+			      struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct irda_sock *self;
@@ -1568,14 +1570,14 @@
 }
 
 /*
- * Function irda_sendmsg_ultra (sock, msg, len, scm)
+ * Function irda_sendmsg_ultra (iocb, sock, msg, len, scm)
  *
  *    Send message down to IrLMP for the unreliable Ultra
  *    packet service...
  */
 #ifdef CONFIG_IRDA_ULTRA
-static int irda_sendmsg_ultra(struct socket *sock, struct msghdr *msg,
-			      int len, struct scm_cookie *scm)
+static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
+			      struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct irda_sock *self;
diff -Nru a/net/llc/af_llc.c b/net/llc/af_llc.c
--- a/net/llc/af_llc.c	Tue Oct 15 20:29:11 2002
+++ b/net/llc/af_llc.c	Tue Oct 15 20:29:11 2002
@@ -677,8 +677,9 @@
  *	Copy received data to the socket user.
  *	Returns non-negative upon success, negative otherwise.
  */
-static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-			  int flags, struct scm_cookie *scm)
+static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
+			  struct msghdr *msg, int size, int flags,
+			  struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;
@@ -731,8 +732,8 @@
  *	Transmit data provided by the socket user.
  *	Returns non-negative upon success, negative otherwise.
  */
-static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-			  struct scm_cookie *scm)
+static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock,
+			  struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct llc_opt *llc = llc_sk(sk);
diff -Nru a/net/llc/llc_proc.c b/net/llc/llc_proc.c
--- a/net/llc/llc_proc.c	Tue Oct 15 20:29:12 2002
+++ b/net/llc/llc_proc.c	Tue Oct 15 20:29:12 2002
@@ -258,7 +258,7 @@
 	goto out;
 }
 
-void __exit llc_proc_exit(void)
+void llc_proc_exit(void)
 {
 	remove_proc_entry("socket", llc_proc_dir);
 	remove_proc_entry("core", llc_proc_dir);
@@ -270,7 +270,7 @@
 	return 0;
 }
 
-void __exit llc_proc_exit(void)
+void llc_proc_exit(void)
 {
 }
 #endif /* CONFIG_PROC_FS */
diff -Nru a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
--- a/net/netlink/af_netlink.c	Tue Oct 15 20:29:17 2002
+++ b/net/netlink/af_netlink.c	Tue Oct 15 20:29:17 2002
@@ -570,7 +570,8 @@
 	read_unlock(&nl_table_lock);
 }
 
-static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+static int netlink_sendmsg(struct kiocb *iocb, struct socket *sock,
+			   struct msghdr *msg, int len,
 			   struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -639,7 +640,8 @@
 	return err;
 }
 
-static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, int len,
+static int netlink_recvmsg(struct kiocb *iocb, struct socket *sock,
+			   struct msghdr *msg, int len,
 			   int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
diff -Nru a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
--- a/net/netrom/af_netrom.c	Tue Oct 15 20:29:17 2002
+++ b/net/netrom/af_netrom.c	Tue Oct 15 20:29:17 2002
@@ -966,7 +966,8 @@
 	return 1;
 }
 
-static int nr_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
+		      struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	nr_cb *nr = nr_sk(sk);
@@ -1056,8 +1057,9 @@
 	return len;
 }
 
-static int nr_recvmsg(struct socket *sock, struct msghdr *msg, int size, 
-	int flags, struct scm_cookie *scm)
+static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
+		      struct msghdr *msg, int size, int flags,
+		      struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c	Tue Oct 15 20:29:18 2002
+++ b/net/packet/af_packet.c	Tue Oct 15 20:29:18 2002
@@ -288,7 +288,8 @@
  *	protocol layers and you must therefore supply it with a complete frame
  */
  
-static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg, int len,
+static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
+			       struct msghdr *msg, int len,
 			       struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -665,8 +666,8 @@
 #endif
 
 
-static int packet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-			  struct scm_cookie *scm)
+static int packet_sendmsg(struct kiocb *iocb, struct socket *sock,
+			  struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
@@ -1020,7 +1021,8 @@
  *	If necessary we block.
  */
 
-static int packet_recvmsg(struct socket *sock, struct msghdr *msg, int len,
+static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
+			  struct msghdr *msg, int len,
 			  int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
diff -Nru a/net/rose/af_rose.c b/net/rose/af_rose.c
--- a/net/rose/af_rose.c	Tue Oct 15 20:29:17 2002
+++ b/net/rose/af_rose.c	Tue Oct 15 20:29:17 2002
@@ -1025,8 +1025,8 @@
 	return 1;
 }
 
-static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-				struct scm_cookie *scm)
+static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	rose_cb *rose = rose_sk(sk);
@@ -1189,8 +1189,9 @@
 }
 
 
-static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size,
-		   int flags, struct scm_cookie *scm)
+static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,
+			struct msghdr *msg, int size, int flags,
+			struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	rose_cb *rose = rose_sk(sk);
diff -Nru a/net/rxrpc/Makefile b/net/rxrpc/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/Makefile	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,33 @@
+#
+# Makefile for Linux kernel Rx RPC
+#
+
+export-objs := rxrpc_syms.o
+
+rxrpc-objs := \
+	call.o \
+	connection.o \
+	krxiod.o \
+	krxsecd.o \
+	krxtimod.o \
+	main.o \
+	peer.o \
+	rxrpc_syms.o \
+	transport.o
+
+#ifeq ($(CONFIG_PROC_FS),y)
+rxrpc-objs	+= proc.o
+#endif
+#ifeq ($(CONFIG_SYSCTL),y)
+rxrpc-objs += sysctl.o
+#endif
+
+obj-m  := rxrpc.o
+
+# superfluous for 2.5, but needed for 2.4..
+ifeq "$(VERSION).$(PATCHLEVEL)" "2.4"
+rxrpc.o: $(rxrpc-objs)
+	$(LD) -r -o $@ $(rxrpc-objs)
+endif
+
+include $(TOPDIR)/Rules.make
diff -Nru a/net/rxrpc/call.c b/net/rxrpc/call.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/call.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,2122 @@
+/* call.c: Rx call routines
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include <rxrpc/message.h>
+#include "internal.h"
+
+__RXACCT_DECL(atomic_t rxrpc_call_count);
+__RXACCT_DECL(atomic_t rxrpc_message_count);
+
+LIST_HEAD(rxrpc_calls);
+DECLARE_RWSEM(rxrpc_calls_sem);
+
+unsigned rxrpc_call_rcv_timeout		= 30;
+unsigned rxrpc_call_acks_timeout	= 30;
+unsigned rxrpc_call_dfr_ack_timeout	= 5;
+unsigned short rxrpc_call_max_resend	= 10;
+
+const char *rxrpc_call_states[] = {
+	"COMPLETE",
+	"ERROR",
+	"SRVR_RCV_OPID",
+	"SRVR_RCV_ARGS",
+	"SRVR_GOT_ARGS",
+	"SRVR_SND_REPLY",
+	"SRVR_RCV_FINAL_ACK",
+	"CLNT_SND_ARGS",
+	"CLNT_RCV_REPLY",
+	"CLNT_GOT_REPLY"
+};
+
+const char *rxrpc_call_error_states[] = {
+	"NO_ERROR",
+	"LOCAL_ABORT",
+	"PEER_ABORT",
+	"LOCAL_ERROR",
+	"REMOTE_ERROR"
+};
+
+const char *rxrpc_pkts[] = {
+	"?00", "data", "ack", "busy", "abort", "ackall", "chall", "resp", "debug",
+	"?09", "?10", "?11", "?12", "?13", "?14", "?15"
+};
+
+const char *rxrpc_acks[] = {
+	"---", "REQ", "DUP", "SEQ", "WIN", "MEM", "PNG", "PNR", "DLY", "IDL", "-?-"
+};
+
+static const char _acktype[] = "NA-";
+
+static void rxrpc_call_receive_packet(struct rxrpc_call *call);
+static void rxrpc_call_receive_data_packet(struct rxrpc_call *call, struct rxrpc_message *msg);
+static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call, struct rxrpc_message *msg);
+static void rxrpc_call_definitively_ACK(struct rxrpc_call *call, rxrpc_seq_t higest);
+static void rxrpc_call_resend(struct rxrpc_call *call, rxrpc_seq_t highest);
+static int __rxrpc_call_read_data(struct rxrpc_call *call);
+
+static int rxrpc_call_record_ACK(struct rxrpc_call *call,
+				 struct rxrpc_message *msg,
+				 rxrpc_seq_t seq,
+				 size_t count);
+#define _state(call) \
+	_debug("[[[ state %s ]]]",rxrpc_call_states[call->app_call_state]);
+
+static void rxrpc_call_default_attn_func(struct rxrpc_call *call)
+{
+	wake_up(&call->waitq);
+}
+
+static void rxrpc_call_default_error_func(struct rxrpc_call *call)
+{
+	wake_up(&call->waitq);
+}
+
+static void rxrpc_call_default_aemap_func(struct rxrpc_call *call)
+{
+	switch (call->app_err_state) {
+	case RXRPC_ESTATE_LOCAL_ABORT:
+		call->app_abort_code = -call->app_errno;
+	case RXRPC_ESTATE_PEER_ABORT:
+		call->app_errno = -ECONNABORTED;
+	default:
+		break;
+	}
+}
+
+static void __rxrpc_call_acks_timeout(unsigned long _call)
+{
+	struct rxrpc_call *call = (struct rxrpc_call *) _call;
+
+	_debug("ACKS TIMEOUT %05lu",jiffies - call->cjif);
+
+	call->flags |= RXRPC_CALL_ACKS_TIMO;
+	rxrpc_krxiod_queue_call(call);
+}
+
+static void __rxrpc_call_rcv_timeout(unsigned long _call)
+{
+	struct rxrpc_call *call = (struct rxrpc_call *) _call;
+
+	_debug("RCV TIMEOUT %05lu",jiffies - call->cjif);
+
+	call->flags |= RXRPC_CALL_RCV_TIMO;
+	rxrpc_krxiod_queue_call(call);
+}
+
+static void __rxrpc_call_ackr_timeout(unsigned long _call)
+{
+	struct rxrpc_call *call = (struct rxrpc_call *) _call;
+
+	_debug("ACKR TIMEOUT %05lu",jiffies - call->cjif);
+
+	call->flags |= RXRPC_CALL_ACKR_TIMO;
+	rxrpc_krxiod_queue_call(call);
+}
+
+/*****************************************************************************/
+/*
+ * create a new call record
+ */
+static inline int __rxrpc_create_call(struct rxrpc_connection *conn,
+				      struct rxrpc_call **_call)
+{
+	struct rxrpc_call *call;
+
+	_enter("%p",conn);
+
+	/* allocate and initialise a call record */
+	call = (struct rxrpc_call *) get_zeroed_page(GFP_KERNEL);
+	if (!call) {
+		_leave(" ENOMEM");
+		return -ENOMEM;
+	}
+
+	atomic_set(&call->usage,1);
+
+	init_waitqueue_head(&call->waitq);
+	spin_lock_init(&call->lock);
+	INIT_LIST_HEAD(&call->link);
+	INIT_LIST_HEAD(&call->acks_pendq);
+	INIT_LIST_HEAD(&call->rcv_receiveq);
+	INIT_LIST_HEAD(&call->rcv_krxiodq_lk);
+	INIT_LIST_HEAD(&call->app_readyq);
+	INIT_LIST_HEAD(&call->app_unreadyq);
+	INIT_LIST_HEAD(&call->app_link);
+	INIT_LIST_HEAD(&call->app_attn_link);
+
+	init_timer(&call->acks_timeout);
+	call->acks_timeout.data = (unsigned long) call;
+	call->acks_timeout.function = __rxrpc_call_acks_timeout;
+
+	init_timer(&call->rcv_timeout);
+	call->rcv_timeout.data = (unsigned long) call;
+	call->rcv_timeout.function = __rxrpc_call_rcv_timeout;
+
+	init_timer(&call->ackr_dfr_timo);
+	call->ackr_dfr_timo.data = (unsigned long) call;
+	call->ackr_dfr_timo.function = __rxrpc_call_ackr_timeout;
+
+	call->conn = conn;
+	call->ackr_win_bot = 1;
+	call->ackr_win_top = call->ackr_win_bot + RXRPC_CALL_ACK_WINDOW_SIZE - 1;
+	call->ackr_prev_seq = 0;
+	call->app_mark = RXRPC_APP_MARK_EOF;
+	call->app_attn_func = rxrpc_call_default_attn_func;
+	call->app_error_func = rxrpc_call_default_error_func;
+	call->app_aemap_func = rxrpc_call_default_aemap_func;
+	call->app_scr_alloc = call->app_scratch;
+
+	call->cjif = jiffies;
+
+	_leave(" = 0 (%p)",call);
+
+	*_call = call;
+
+	return 0;
+} /* end __rxrpc_create_call() */
+
+/*****************************************************************************/
+/*
+ * create a new call record for outgoing calls
+ */
+int rxrpc_create_call(struct rxrpc_connection *conn,
+		      rxrpc_call_attn_func_t attn,
+		      rxrpc_call_error_func_t error,
+		      rxrpc_call_aemap_func_t aemap,
+		      struct rxrpc_call **_call)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_call *call;
+	int ret, cix, loop;
+
+	_enter("%p",conn);
+
+	/* allocate and initialise a call record */
+	ret = __rxrpc_create_call(conn,&call);
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	call->app_call_state = RXRPC_CSTATE_CLNT_SND_ARGS;
+	if (attn) call->app_attn_func = attn;
+	if (error) call->app_error_func = error;
+	if (aemap) call->app_aemap_func = aemap;
+
+	_state(call);
+
+	spin_lock(&conn->lock);
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&conn->chanwait,&myself);
+
+ try_again:
+	/* try to find an unused channel */
+	for (cix=0; cix<4; cix++)
+		if (!conn->channels[cix])
+			goto obtained_chan;
+
+	/* no free channels - wait for one to become available */
+	ret = -EINTR;
+	if (signal_pending(current))
+		goto error_unwait;
+
+	spin_unlock(&conn->lock);
+
+	schedule();
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	spin_lock(&conn->lock);
+	goto try_again;
+
+	/* got a channel - now attach to the connection */
+ obtained_chan:
+	remove_wait_queue(&conn->chanwait,&myself);
+	set_current_state(TASK_RUNNING);
+
+	/* concoct a unique call number */
+ next_callid:
+	call->call_id = htonl(++conn->call_counter);
+	for (loop=0; loop<4; loop++)
+		if (conn->channels[loop] && conn->channels[loop]->call_id==call->call_id)
+			goto next_callid;
+
+	rxrpc_get_connection(conn);
+	conn->channels[cix] = call; /* assign _after_ done callid check loop */
+	do_gettimeofday(&conn->atime);
+	call->chan_ix = htonl(cix);
+
+	spin_unlock(&conn->lock);
+
+	down_write(&rxrpc_calls_sem);
+	list_add_tail(&call->call_link,&rxrpc_calls);
+	up_write(&rxrpc_calls_sem);
+
+	__RXACCT(atomic_inc(&rxrpc_call_count));
+	*_call = call;
+
+	_leave(" = 0 (call=%p cix=%u)",call,cix);
+	return 0;
+
+ error_unwait:
+	remove_wait_queue(&conn->chanwait,&myself);
+	set_current_state(TASK_RUNNING);
+	spin_unlock(&conn->lock);
+
+	free_page((unsigned long)call);
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end rxrpc_create_call() */
+
+/*****************************************************************************/
+/*
+ * create a new call record for incoming calls
+ */
+int rxrpc_incoming_call(struct rxrpc_connection *conn,
+			struct rxrpc_message *msg,
+			struct rxrpc_call **_call)
+{
+	struct rxrpc_call *call;
+	unsigned cix;
+	int ret;
+
+	cix = ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK;
+
+	_enter("%p,%u,%u",conn,ntohl(msg->hdr.callNumber),cix);
+
+	/* allocate and initialise a call record */
+	ret = __rxrpc_create_call(conn,&call);
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	call->pkt_rcv_count = 1;
+	call->app_call_state = RXRPC_CSTATE_SRVR_RCV_OPID;
+	call->app_mark = sizeof(u32);
+
+	_state(call);
+
+	/* attach to the connection */
+	ret = -EBUSY;
+	call->chan_ix = htonl(cix);
+	call->call_id = msg->hdr.callNumber;
+
+	spin_lock(&conn->lock);
+
+	if (!conn->channels[cix]) {
+		conn->channels[cix] = call;
+		rxrpc_get_connection(conn);
+		ret = 0;
+	}
+
+	spin_unlock(&conn->lock);
+
+	if (ret<0) free_page((unsigned long)call);
+
+	_leave(" = %p",call);
+
+	if (ret==0) {
+		down_write(&rxrpc_calls_sem);
+		list_add_tail(&call->call_link,&rxrpc_calls);
+		up_write(&rxrpc_calls_sem);
+		__RXACCT(atomic_inc(&rxrpc_call_count));
+		*_call = call;
+	}
+
+	return ret;
+} /* end rxrpc_incoming_call() */
+
+/*****************************************************************************/
+/*
+ * free a call record
+ */
+void rxrpc_put_call(struct rxrpc_call *call)
+{
+	struct rxrpc_connection *conn = call->conn;
+	struct rxrpc_message *msg;
+
+	_enter("%p{u=%d}",call,atomic_read(&call->usage));
+
+	/* sanity check */
+	if (atomic_read(&call->usage)<=0)
+		BUG();
+
+	/* to prevent a race, the decrement and the de-list must be effectively atomic */
+	spin_lock(&conn->lock);
+	if (likely(!atomic_dec_and_test(&call->usage))) {
+		spin_unlock(&conn->lock);
+		_leave("");
+		return;
+	}
+
+	conn->channels[ntohl(call->chan_ix)] = NULL;
+
+	spin_unlock(&conn->lock);
+
+	wake_up(&conn->chanwait);
+
+	rxrpc_put_connection(conn);
+
+	/* clear the timers and dequeue from krxiod */
+	del_timer_sync(&call->acks_timeout);
+	del_timer_sync(&call->rcv_timeout);
+	del_timer_sync(&call->ackr_dfr_timo);
+
+	rxrpc_krxiod_dequeue_call(call);
+
+	/* clean up the contents of the struct */
+	if (call->snd_nextmsg)
+		rxrpc_put_message(call->snd_nextmsg);
+
+	if (call->snd_ping)
+		rxrpc_put_message(call->snd_ping);
+
+	while (!list_empty(&call->acks_pendq)) {
+		msg = list_entry(call->acks_pendq.next,struct rxrpc_message,link);
+		list_del(&msg->link);
+		rxrpc_put_message(msg);
+	}
+
+	while (!list_empty(&call->rcv_receiveq)) {
+		msg = list_entry(call->rcv_receiveq.next,struct rxrpc_message,link);
+		list_del(&msg->link);
+		rxrpc_put_message(msg);
+	}
+
+	while (!list_empty(&call->app_readyq)) {
+		msg = list_entry(call->app_readyq.next,struct rxrpc_message,link);
+		list_del(&msg->link);
+		rxrpc_put_message(msg);
+	}
+
+	while (!list_empty(&call->app_unreadyq)) {
+		msg = list_entry(call->app_unreadyq.next,struct rxrpc_message,link);
+		list_del(&msg->link);
+		rxrpc_put_message(msg);
+	}
+
+	if (call->owner) __MOD_DEC_USE_COUNT(call->owner);
+
+	down_write(&rxrpc_calls_sem);
+	list_del(&call->call_link);
+	up_write(&rxrpc_calls_sem);
+
+	__RXACCT(atomic_dec(&rxrpc_call_count));
+	free_page((unsigned long)call);
+
+	_leave(" [destroyed]");
+} /* end rxrpc_put_call() */
+
+/*****************************************************************************/
+/*
+ * actually generate a normal ACK
+ */
+static inline int __rxrpc_call_gen_normal_ACK(struct rxrpc_call *call, rxrpc_seq_t seq)
+{
+	struct rxrpc_message *msg;
+	struct iovec diov[3];
+	unsigned aux[4];
+	int delta, ret;
+
+	/* ACKs default to DELAY */
+	if (!call->ackr.reason)
+		call->ackr.reason = RXRPC_ACK_DELAY;
+
+	_proto("Rx %05lu Sending ACK { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
+	       jiffies - call->cjif,
+	       ntohs(call->ackr.maxSkew),
+	       ntohl(call->ackr.firstPacket),
+	       ntohl(call->ackr.previousPacket),
+	       ntohl(call->ackr.serial),
+	       rxrpc_acks[call->ackr.reason],
+	       call->ackr.nAcks);
+
+	aux[0] = htonl(call->conn->peer->if_mtu);	/* interface MTU */
+	aux[1] = htonl(1444);				/* max MTU */
+	aux[2] = htonl(16);				/* rwind */
+	aux[3] = htonl(4);				/* max packets */
+
+	diov[0].iov_len  = sizeof(struct rxrpc_ackpacket);
+	diov[0].iov_base = &call->ackr;
+	diov[1].iov_len  = (call->ackr_pend_cnt+3);
+	diov[1].iov_base = call->ackr_array;
+	diov[2].iov_len  = sizeof(aux);
+	diov[2].iov_base = &aux;
+
+	/* build and send the message */
+	ret = rxrpc_conn_newmsg(call->conn,call,RXRPC_PACKET_TYPE_ACK,3,diov,GFP_KERNEL,&msg);
+	if (ret<0)
+		goto out;
+
+	msg->seq = seq;
+	msg->hdr.seq = htonl(seq);
+	msg->hdr.flags |= RXRPC_SLOW_START_OK;
+
+	ret = rxrpc_conn_sendmsg(call->conn,msg);
+	rxrpc_put_message(msg);
+	if (ret<0)
+		goto out;
+	call->pkt_snd_count++;
+
+	/* count how many actual ACKs there were at the front */
+	for (delta=0; delta<call->ackr_pend_cnt; delta++)
+		if (call->ackr_array[delta]!=RXRPC_ACK_TYPE_ACK)
+			break;
+
+	call->ackr_pend_cnt -= delta; /* all ACK'd to this point */
+
+	/* crank the ACK window around */
+	if (delta==0) {
+		/* un-ACK'd window */
+	}
+	else if (delta < RXRPC_CALL_ACK_WINDOW_SIZE) {
+		/* partially ACK'd window
+		 * - shuffle down to avoid losing out-of-sequence packets
+		 */
+		call->ackr_win_bot += delta;
+		call->ackr_win_top += delta;
+
+		memmove(&call->ackr_array[0],
+			&call->ackr_array[delta],
+			call->ackr_pend_cnt);
+
+		memset(&call->ackr_array[call->ackr_pend_cnt],
+		       RXRPC_ACK_TYPE_NACK,
+		       sizeof(call->ackr_array) - call->ackr_pend_cnt);
+	}
+	else {
+		/* fully ACK'd window
+		 * - just clear the whole thing
+		 */
+		memset(&call->ackr_array,RXRPC_ACK_TYPE_NACK,sizeof(call->ackr_array));
+	}
+
+	/* clear this ACK */
+	memset(&call->ackr,0,sizeof(call->ackr));
+
+ out:
+	if (!call->app_call_state) printk("___ STATE 0 ___\n");
+	return ret;
+} /* end __rxrpc_call_gen_normal_ACK() */
+
+/*****************************************************************************/
+/*
+ * note the reception of a packet in the call's ACK records and generate an appropriate ACK packet
+ * if necessary
+ * - returns 0 if packet should be processed, 1 if packet should be ignored and -ve on an error
+ */
+static int rxrpc_call_generate_ACK(struct rxrpc_call *call,
+				   struct rxrpc_header *hdr,
+				   struct rxrpc_ackpacket *ack)
+{
+	struct rxrpc_message *msg;
+	rxrpc_seq_t seq;
+	unsigned offset;
+	int ret = 0, err;
+	u8 special_ACK, do_ACK, force;
+
+	_enter("%p,%p { seq=%d tp=%d fl=%02x }",call,hdr,ntohl(hdr->seq),hdr->type,hdr->flags);
+
+	seq = ntohl(hdr->seq);
+	offset = seq - call->ackr_win_bot;
+	do_ACK = RXRPC_ACK_DELAY;
+	special_ACK = 0;
+	force = (seq==1);
+
+	if (call->ackr_high_seq < seq)
+		call->ackr_high_seq = seq;
+
+	/* deal with generation of obvious special ACKs first */
+	if (ack && ack->reason==RXRPC_ACK_PING) {
+		special_ACK = RXRPC_ACK_PING_RESPONSE;
+		ret = 1;
+		goto gen_ACK;
+	}
+
+	if (seq < call->ackr_win_bot) {
+		special_ACK = RXRPC_ACK_DUPLICATE;
+		ret = 1;
+		goto gen_ACK;
+	}
+
+	if (seq >= call->ackr_win_top) {
+		special_ACK = RXRPC_ACK_EXCEEDS_WINDOW;
+		ret = 1;
+		goto gen_ACK;
+	}
+
+	if (call->ackr_array[offset] != RXRPC_ACK_TYPE_NACK) {
+		special_ACK = RXRPC_ACK_DUPLICATE;
+		ret = 1;
+		goto gen_ACK;
+	}
+
+	/* okay... it's a normal data packet inside the ACK window */
+	call->ackr_array[offset] = RXRPC_ACK_TYPE_ACK;
+
+	if (offset<call->ackr_pend_cnt) {
+	}
+	else if (offset>call->ackr_pend_cnt) {
+		do_ACK = RXRPC_ACK_OUT_OF_SEQUENCE;
+		call->ackr_pend_cnt = offset;
+		goto gen_ACK;
+	}
+
+	if (hdr->flags & RXRPC_REQUEST_ACK) {
+		do_ACK = RXRPC_ACK_REQUESTED;
+	}
+
+	/* generate an ACK on the final packet of a reply just received */
+	if (hdr->flags & RXRPC_LAST_PACKET) {
+		if (call->conn->out_clientflag)
+			force = 1;
+	}
+	else if (!(hdr->flags & RXRPC_MORE_PACKETS)) {
+		do_ACK = RXRPC_ACK_REQUESTED;
+	}
+
+	/* re-ACK packets previously received out-of-order */
+	for (offset++; offset<RXRPC_CALL_ACK_WINDOW_SIZE; offset++)
+		if (call->ackr_array[offset]!=RXRPC_ACK_TYPE_ACK)
+			break;
+
+	call->ackr_pend_cnt = offset;
+
+	/* generate an ACK if we fill up the window */
+	if (call->ackr_pend_cnt >= RXRPC_CALL_ACK_WINDOW_SIZE)
+		force = 1;
+
+ gen_ACK:
+	_debug("%05lu ACKs pend=%u norm=%s special=%s%s",
+	       jiffies - call->cjif,
+	       call->ackr_pend_cnt,rxrpc_acks[do_ACK],rxrpc_acks[special_ACK],
+	       force ? " immediate" :
+	       do_ACK==RXRPC_ACK_REQUESTED ? " merge-req" :
+	       hdr->flags & RXRPC_LAST_PACKET ? " finalise" :
+	       " defer"
+	       );
+
+	/* send any pending normal ACKs if need be */
+	if (call->ackr_pend_cnt>0) {
+		/* fill out the appropriate form */
+		call->ackr.bufferSpace		= htons(RXRPC_CALL_ACK_WINDOW_SIZE);
+		call->ackr.maxSkew		= htons(min(call->ackr_high_seq - seq,65535U));
+		call->ackr.firstPacket		= htonl(call->ackr_win_bot);
+		call->ackr.previousPacket	= call->ackr_prev_seq;
+		call->ackr.serial		= hdr->serial;
+		call->ackr.nAcks		= call->ackr_pend_cnt;
+
+		if (do_ACK==RXRPC_ACK_REQUESTED)
+			call->ackr.reason = do_ACK;
+
+		/* generate the ACK immediately if necessary */
+		if (special_ACK || force) {
+			err = __rxrpc_call_gen_normal_ACK(call,do_ACK==RXRPC_ACK_DELAY ? 0 : seq);
+			if (err<0) {
+				ret = err;
+				goto out;
+			}
+		}
+	}
+
+	if (call->ackr.reason==RXRPC_ACK_REQUESTED)
+		call->ackr_dfr_seq = seq;
+
+	/* start the ACK timer if not running if there are any pending deferred ACKs */
+	if (call->ackr_pend_cnt>0 &&
+	    call->ackr.reason!=RXRPC_ACK_REQUESTED &&
+	    !timer_pending(&call->ackr_dfr_timo)
+	    ) {
+		unsigned long timo;
+
+		timo = rxrpc_call_dfr_ack_timeout + jiffies;
+
+		_debug("START ACKR TIMER for cj=%lu",timo-call->cjif);
+
+		spin_lock(&call->lock);
+		mod_timer(&call->ackr_dfr_timo,timo);
+		spin_unlock(&call->lock);
+	}
+	else if ((call->ackr_pend_cnt==0 || call->ackr.reason==RXRPC_ACK_REQUESTED) &&
+		 timer_pending(&call->ackr_dfr_timo)
+		 ) {
+		/* stop timer if no pending ACKs */
+		_debug("CLEAR ACKR TIMER");
+		del_timer_sync(&call->ackr_dfr_timo);
+	}
+
+	/* send a special ACK if one is required */
+	if (special_ACK) {
+		struct rxrpc_ackpacket ack;
+		struct iovec diov[2];
+		u8 acks[1] = { RXRPC_ACK_TYPE_ACK };
+
+		/* fill out the appropriate form */
+		ack.bufferSpace		= htons(RXRPC_CALL_ACK_WINDOW_SIZE);
+		ack.maxSkew		= htons(min(call->ackr_high_seq - seq,65535U));
+		ack.firstPacket		= htonl(call->ackr_win_bot);
+		ack.previousPacket	= call->ackr_prev_seq;
+		ack.serial		= hdr->serial;
+		ack.reason		= special_ACK;
+		ack.nAcks		= 0;
+		//ack.nAcks = special_ACK==RXRPC_ACK_OUT_OF_SEQUENCE ? 0 : hdr->seq ? 1 : 0;
+
+		_proto("Rx Sending s-ACK { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
+		       ntohs(ack.maxSkew),ntohl(ack.firstPacket),ntohl(ack.previousPacket),
+		       ntohl(ack.serial),rxrpc_acks[ack.reason],ack.nAcks);
+
+		diov[0].iov_len  = sizeof(struct rxrpc_ackpacket);
+		diov[0].iov_base = &ack;
+		diov[1].iov_len  = sizeof(acks);
+		diov[1].iov_base = acks;
+
+		/* build and send the message */
+		err = rxrpc_conn_newmsg(call->conn,call,RXRPC_PACKET_TYPE_ACK,
+					hdr->seq ? 2 : 1,diov,
+					GFP_KERNEL,
+					&msg);
+		if (err<0) {
+			ret = err;
+			goto out;
+		}
+
+		msg->seq = seq;
+		msg->hdr.seq = htonl(seq);
+		msg->hdr.flags |= RXRPC_SLOW_START_OK;
+
+		err = rxrpc_conn_sendmsg(call->conn,msg);
+		rxrpc_put_message(msg);
+		if (err<0) {
+			ret = err;
+			goto out;
+		}
+		call->pkt_snd_count++;
+	}
+
+ out:
+	if (hdr->seq)
+		call->ackr_prev_seq = hdr->seq;
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end rxrpc_call_generate_ACK() */
+
+/*****************************************************************************/
+/*
+ * handle work to be done on a call
+ * - includes packet reception and timeout processing
+ */
+void rxrpc_call_do_stuff(struct rxrpc_call *call)
+{
+	_enter("%p{flags=%lx}",call,call->flags);
+
+	/* handle packet reception */
+	if (call->flags & RXRPC_CALL_RCV_PKT) {
+		_debug("- receive packet");
+		call->flags &= ~RXRPC_CALL_RCV_PKT;
+		rxrpc_call_receive_packet(call);
+	}
+
+	/* handle overdue ACKs */
+	if (call->flags & RXRPC_CALL_ACKS_TIMO) {
+		_debug("- overdue ACK timeout");
+		call->flags &= ~RXRPC_CALL_ACKS_TIMO;
+		rxrpc_call_resend(call,call->snd_seq_count);
+	}
+
+	/* handle lack of reception */
+	if (call->flags & RXRPC_CALL_RCV_TIMO) {
+		_debug("- reception timeout");
+		call->flags &= ~RXRPC_CALL_RCV_TIMO;
+		rxrpc_call_abort(call,-EIO);
+	}
+
+	/* handle deferred ACKs */
+	if (call->flags & RXRPC_CALL_ACKR_TIMO ||
+	    (call->ackr.nAcks>0 && call->ackr.reason==RXRPC_ACK_REQUESTED)
+	    ) {
+		_debug("- deferred ACK timeout: cj=%05lu r=%s n=%u",
+		       jiffies - call->cjif,
+		       rxrpc_acks[call->ackr.reason],
+		       call->ackr.nAcks);
+
+		call->flags &= ~RXRPC_CALL_ACKR_TIMO;
+
+		if (call->ackr.nAcks>0 && call->app_call_state!=RXRPC_CSTATE_ERROR) {
+			/* generate ACK */
+			__rxrpc_call_gen_normal_ACK(call,call->ackr_dfr_seq);
+			call->ackr_dfr_seq = 0;
+		}
+	}
+
+	_leave("");
+
+} /* end rxrpc_call_do_timeout() */
+
+/*****************************************************************************/
+/*
+ * send an abort message at call or connection level
+ * - must be called with call->lock held
+ * - the supplied error code is sent as the packet data
+ */
+static int __rxrpc_call_abort(struct rxrpc_call *call, int errno)
+{
+	struct rxrpc_connection *conn = call->conn;
+	struct rxrpc_message *msg;
+	struct iovec diov[1];
+	int ret;
+	u32 _error;
+
+	_enter("%p{%08x},%p{%d},%d",conn,ntohl(conn->conn_id),call,ntohl(call->call_id),errno);
+
+	/* if this call is already aborted, then just wake up any waiters */
+	if (call->app_call_state==RXRPC_CSTATE_ERROR) {
+		spin_unlock(&call->lock);
+		call->app_error_func(call);
+		_leave(" = 0");
+		return 0;
+	}
+
+	rxrpc_get_call(call);
+
+	/* change the state _with_ the lock still held */
+	call->app_call_state = RXRPC_CSTATE_ERROR;
+	call->app_err_state = RXRPC_ESTATE_LOCAL_ABORT;
+	call->app_errno = errno;
+	call->app_mark = RXRPC_APP_MARK_EOF;
+	call->app_read_buf = NULL;
+	call->app_async_read = 0;
+
+	_state(call);
+
+	/* ask the app to translate the error code */
+	call->app_aemap_func(call);
+
+	spin_unlock(&call->lock);
+
+	/* flush any outstanding ACKs */
+	del_timer_sync(&call->acks_timeout);
+	del_timer_sync(&call->rcv_timeout);
+	del_timer_sync(&call->ackr_dfr_timo);
+
+	if (rxrpc_call_is_ack_pending(call))
+		__rxrpc_call_gen_normal_ACK(call,0);
+
+	/* send the abort packet only if we actually traded some other packets */
+	ret = 0;
+	if (call->pkt_snd_count || call->pkt_rcv_count) {
+		/* actually send the abort */
+		_proto("Rx Sending Call ABORT { data=%d }",call->app_abort_code);
+
+		_error = htonl(call->app_abort_code);
+
+		diov[0].iov_len  = sizeof(_error);
+		diov[0].iov_base = &_error;
+
+		ret = rxrpc_conn_newmsg(conn,call,RXRPC_PACKET_TYPE_ABORT,1,diov,GFP_KERNEL,&msg);
+		if (ret==0) {
+			ret = rxrpc_conn_sendmsg(conn,msg);
+			rxrpc_put_message(msg);
+		}
+	}
+
+	/* tell the app layer to let go */
+	call->app_error_func(call);
+
+	rxrpc_put_call(call);
+
+	_leave(" = %d",ret);
+
+	return ret;
+} /* end __rxrpc_call_abort() */
+
+/*****************************************************************************/
+/*
+ * send an abort message at call or connection level
+ * - the supplied error code is sent as the packet data
+ */
+int rxrpc_call_abort(struct rxrpc_call *call, int error)
+{
+	spin_lock(&call->lock);
+
+	return __rxrpc_call_abort(call,error);
+
+} /* end rxrpc_call_abort() */
+
+/*****************************************************************************/
+/*
+ * process packets waiting for this call
+ */
+static void rxrpc_call_receive_packet(struct rxrpc_call *call)
+{
+	struct rxrpc_message *msg;
+	struct list_head *_p;
+	u32 data32;
+
+	_enter("%p",call);
+
+	rxrpc_get_call(call); /* must not go away too soon if aborted by app-layer */
+
+	while (!list_empty(&call->rcv_receiveq)) {
+		/* try to get next packet */
+		_p = NULL;
+		spin_lock(&call->lock);
+		if (!list_empty(&call->rcv_receiveq)) {
+			_p = call->rcv_receiveq.next;
+			list_del_init(_p);
+		}
+		spin_unlock(&call->lock);
+
+		if (!_p) break;
+
+		msg = list_entry(_p,struct rxrpc_message,link);
+
+		_proto("Rx %05lu Received %s packet (%%%u,#%u,%c%c%c%c%c)",
+		       jiffies - call->cjif,
+		       rxrpc_pkts[msg->hdr.type],
+		       ntohl(msg->hdr.serial),
+		       msg->seq,
+		       msg->hdr.flags & RXRPC_JUMBO_PACKET	? 'j' : '-',
+		       msg->hdr.flags & RXRPC_MORE_PACKETS	? 'm' : '-',
+		       msg->hdr.flags & RXRPC_LAST_PACKET	? 'l' : '-',
+		       msg->hdr.flags & RXRPC_REQUEST_ACK	? 'r' : '-',
+		       msg->hdr.flags & RXRPC_CLIENT_INITIATED	? 'C' : 'S'
+		       );
+
+		switch (msg->hdr.type) {
+			/* deal with data packets */
+		case RXRPC_PACKET_TYPE_DATA:
+			/* ACK the packet if necessary */
+			switch (rxrpc_call_generate_ACK(call,&msg->hdr,NULL)) {
+			case 0: /* useful packet */
+				rxrpc_call_receive_data_packet(call,msg);
+				break;
+			case 1: /* duplicate or out-of-window packet */
+				break;
+			default:
+				rxrpc_put_message(msg);
+				goto out;
+			}
+			break;
+
+			/* deal with ACK packets */
+		case RXRPC_PACKET_TYPE_ACK:
+			rxrpc_call_receive_ack_packet(call,msg);
+			break;
+
+			/* deal with abort packets */
+		case RXRPC_PACKET_TYPE_ABORT:
+			data32 = 0;
+			if (skb_copy_bits(msg->pkt,msg->offset,&data32,sizeof(data32))<0) {
+				printk("Rx Received short ABORT packet\n");
+			}
+			else {
+				data32 = ntohl(data32);
+			}
+
+			_proto("Rx Received Call ABORT { data=%d }",data32);
+
+			spin_lock(&call->lock);
+			call->app_call_state = RXRPC_CSTATE_ERROR;
+			call->app_err_state = RXRPC_ESTATE_PEER_ABORT;
+			call->app_abort_code = data32;
+			call->app_errno = -ECONNABORTED;
+			call->app_mark = RXRPC_APP_MARK_EOF;
+			call->app_read_buf = NULL;
+			call->app_async_read = 0;
+
+			/* ask the app to translate the error code */
+			call->app_aemap_func(call);
+			_state(call);
+			spin_unlock(&call->lock);
+			call->app_error_func(call);
+			break;
+
+		default:
+			/* deal with other packet types */
+			_proto("Rx Unsupported packet type %u (#%u)",msg->hdr.type,msg->seq);
+			break;
+		}
+
+		rxrpc_put_message(msg);
+	}
+
+ out:
+	rxrpc_put_call(call);
+	_leave("");
+} /* end rxrpc_call_receive_packet() */
+
+/*****************************************************************************/
+/*
+ * process next data packet
+ * - as the next data packet arrives:
+ *   - it is queued on app_readyq _if_ it is the next one expected (app_ready_seq+1)
+ *   - it is queued on app_unreadyq _if_ it is not the next one expected
+ *   - if a packet placed on app_readyq completely fills a hole leading up to the first packet
+ *     on app_unreadyq, then packets now in sequence are tranferred to app_readyq
+ * - the application layer can only see packets on app_readyq (app_ready_qty bytes)
+ * - the application layer is prodded every time a new packet arrives
+ */
+static void rxrpc_call_receive_data_packet(struct rxrpc_call *call, struct rxrpc_message *msg)
+{
+	const struct rxrpc_operation *optbl, *op;
+	struct rxrpc_message *pmsg;
+	struct list_head *_p;
+	int ret, lo, hi, rmtimo;
+	u32 opid;
+
+	_enter("%p{%u},%p{%u}",call,ntohl(call->call_id),msg,msg->seq);
+
+	rxrpc_get_message(msg);
+
+	/* add to the unready queue if we'd have to create a hole in the ready queue otherwise */
+	if (msg->seq != call->app_ready_seq+1) {
+		_debug("Call add packet %d to unreadyq",msg->seq);
+
+		/* insert in seq order */
+		list_for_each(_p,&call->app_unreadyq) {
+			pmsg = list_entry(_p,struct rxrpc_message,link);
+			if (pmsg->seq>msg->seq)
+				break;
+		}
+
+		list_add_tail(&msg->link,_p);
+
+		_leave(" [unreadyq]");
+		return;
+	}
+
+	/* next in sequence - simply append into the call's ready queue */
+	_debug("Call add packet %d to readyq (+%d => %d bytes)",
+	       msg->seq,msg->dsize,call->app_ready_qty);
+
+	spin_lock(&call->lock);
+	call->app_ready_seq = msg->seq;
+	call->app_ready_qty += msg->dsize;
+	list_add_tail(&msg->link,&call->app_readyq);
+
+	/* move unready packets to the readyq if we got rid of a hole */
+	while (!list_empty(&call->app_unreadyq)) {
+		pmsg = list_entry(call->app_unreadyq.next,struct rxrpc_message,link);
+
+		if (pmsg->seq != call->app_ready_seq+1)
+			break;
+
+		/* next in sequence - just move list-to-list */
+		_debug("Call transfer packet %d to readyq (+%d => %d bytes)",
+		       pmsg->seq,pmsg->dsize,call->app_ready_qty);
+
+		call->app_ready_seq = pmsg->seq;
+		call->app_ready_qty += pmsg->dsize;
+		list_del_init(&pmsg->link);
+		list_add_tail(&pmsg->link,&call->app_readyq);
+	}
+
+	/* see if we've got the last packet yet */
+	if (!list_empty(&call->app_readyq)) {
+		pmsg = list_entry(call->app_readyq.prev,struct rxrpc_message,link);
+		if (pmsg->hdr.flags & RXRPC_LAST_PACKET) {
+			call->app_last_rcv = 1;
+			_debug("Last packet on readyq");
+		}
+	}
+
+	switch (call->app_call_state) {
+		/* do nothing if call already aborted */
+	case RXRPC_CSTATE_ERROR:
+		spin_unlock(&call->lock);
+		_leave(" [error]");
+		return;
+
+		/* extract the operation ID from an incoming call if that's not yet been done */
+	case RXRPC_CSTATE_SRVR_RCV_OPID:
+		spin_unlock(&call->lock);
+
+		/* handle as yet insufficient data for the operation ID */
+		if (call->app_ready_qty<4) {
+			if (call->app_last_rcv)
+				rxrpc_call_abort(call,-EINVAL); /* trouble - last packet seen */
+
+			_leave("");
+			return;
+		}
+
+		/* pull the operation ID out of the buffer */
+		ret = rxrpc_call_read_data(call,&opid,sizeof(opid),0);
+		if (ret<0) {
+			printk("Unexpected error from read-data: %d\n",ret);
+			if (call->app_call_state!=RXRPC_CSTATE_ERROR)
+				rxrpc_call_abort(call,ret);
+			_leave("");
+			return;
+		}
+		call->app_opcode = ntohl(opid);
+
+		/* locate the operation in the available ops table */
+		optbl = call->conn->service->ops_begin;
+		lo = 0;
+		hi = call->conn->service->ops_end - optbl;
+
+		while (lo<hi) {
+			int mid = (hi+lo) / 2;
+			op = &optbl[mid];
+			if (call->app_opcode==op->id)
+				goto found_op;
+			if (call->app_opcode>op->id)
+				lo = mid+1;
+			else
+				hi = mid;
+		}
+
+		/* search failed */
+		kproto("Rx Client requested operation %d from %s service",
+		       call->app_opcode,call->conn->service->name);
+		rxrpc_call_abort(call,-EINVAL);
+		_leave(" [inval]");
+		return;
+
+	found_op:
+		_proto("Rx Client requested operation %s from %s service",
+		       op->name,call->conn->service->name);
+
+		/* we're now waiting for the argument block (unless the call was aborted) */
+		spin_lock(&call->lock);
+		if (call->app_call_state==RXRPC_CSTATE_SRVR_RCV_OPID ||
+		    call->app_call_state==RXRPC_CSTATE_SRVR_SND_REPLY) {
+			if (!call->app_last_rcv)
+				call->app_call_state = RXRPC_CSTATE_SRVR_RCV_ARGS;
+			else if (call->app_ready_qty>0)
+				call->app_call_state = RXRPC_CSTATE_SRVR_GOT_ARGS;
+			else
+				call->app_call_state = RXRPC_CSTATE_SRVR_SND_REPLY;
+			call->app_mark = op->asize;
+			call->app_user = op->user;
+		}
+		spin_unlock(&call->lock);
+
+		_state(call);
+		break;
+
+	case RXRPC_CSTATE_SRVR_RCV_ARGS:
+		/* change state if just received last packet of arg block */
+		if (call->app_last_rcv)
+			call->app_call_state = RXRPC_CSTATE_SRVR_GOT_ARGS;
+		spin_unlock(&call->lock);
+
+		_state(call);
+		break;
+
+	case RXRPC_CSTATE_CLNT_RCV_REPLY:
+		/* change state if just received last packet of reply block */
+		rmtimo = 0;
+		if (call->app_last_rcv) {
+			call->app_call_state = RXRPC_CSTATE_CLNT_GOT_REPLY;
+			rmtimo = 1;
+		}
+		spin_unlock(&call->lock);
+
+		if (rmtimo) {
+			del_timer_sync(&call->acks_timeout);
+			del_timer_sync(&call->rcv_timeout);
+			del_timer_sync(&call->ackr_dfr_timo);
+		}
+
+		_state(call);
+		break;
+
+	default:
+		/* deal with data reception in an unexpected state */
+		printk("Unexpected state [[[ %u ]]]\n",call->app_call_state);
+		__rxrpc_call_abort(call,-EBADMSG);
+		_leave("");
+		return;
+	}
+
+	if (call->app_call_state==RXRPC_CSTATE_CLNT_RCV_REPLY && call->app_last_rcv)
+		BUG();
+
+	/* otherwise just invoke the data function whenever we can satisfy its desire for more
+	 * data
+	 */
+	_proto("Rx Received Op Data: st=%u qty=%u mk=%u%s",
+	       call->app_call_state,call->app_ready_qty,call->app_mark,
+	       call->app_last_rcv ? " last-rcvd" : "");
+
+	spin_lock(&call->lock);
+
+	ret = __rxrpc_call_read_data(call);
+	switch (ret) {
+	case 0:
+		spin_unlock(&call->lock);
+		call->app_attn_func(call);
+		break;
+	case -EAGAIN:
+		spin_unlock(&call->lock);
+		break;
+	case -ECONNABORTED:
+		spin_unlock(&call->lock);
+		break;
+	default:			
+		__rxrpc_call_abort(call,ret);
+		break;
+	}
+
+	_state(call);
+
+	_leave("");
+
+} /* end rxrpc_call_receive_data_packet() */
+
+/*****************************************************************************/
+/*
+ * received an ACK packet
+ */
+static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call, struct rxrpc_message *msg)
+{
+	struct rxrpc_ackpacket ack;
+	rxrpc_serial_t serial;
+	rxrpc_seq_t seq;
+	int ret;
+
+	_enter("%p{%u},%p{%u}",call,ntohl(call->call_id),msg,msg->seq);
+
+	/* extract the basic ACK record */
+	if (skb_copy_bits(msg->pkt,msg->offset,&ack,sizeof(ack))<0) {
+		printk("Rx Received short ACK packet\n");
+		return;
+	}
+	msg->offset += sizeof(ack);
+
+	serial = ack.serial;
+	seq = ntohl(ack.firstPacket);
+
+	_proto("Rx Received ACK %%%d { b=%hu m=%hu f=%u p=%u s=%u r=%s n=%u }",
+	       ntohl(msg->hdr.serial),
+	       ntohs(ack.bufferSpace),
+	       ntohs(ack.maxSkew),
+	       seq,
+	       ntohl(ack.previousPacket),
+	       ntohl(serial),
+	       rxrpc_acks[ack.reason],
+	       call->ackr.nAcks
+	       );
+
+	/* check the other side isn't ACK'ing a sequence number I haven't sent yet */
+	if (ack.nAcks>0 && (seq > call->snd_seq_count || seq+ack.nAcks-1 > call->snd_seq_count)) {
+		printk("Received ACK (#%u-#%u) for unsent packet\n",seq,seq+ack.nAcks-1);
+		rxrpc_call_abort(call,-EINVAL);
+		_leave("");
+		return;
+	}
+
+	/* deal with RTT calculation */
+	if (serial) {
+		struct rxrpc_message *rttmsg;
+
+		/* find the prompting packet */
+		spin_lock(&call->lock);
+		if (call->snd_ping && call->snd_ping->hdr.serial==serial) {
+			/* it was a ping packet */
+			rttmsg = call->snd_ping;
+			call->snd_ping = NULL;
+			spin_unlock(&call->lock);
+
+			if (rttmsg) {
+				rttmsg->rttdone = 1;
+				rxrpc_peer_calculate_rtt(call->conn->peer,rttmsg,msg);
+				rxrpc_put_message(rttmsg);
+			}
+		}
+		else {
+			struct list_head *_p;
+
+			/* it ought to be a data packet - look in the pending ACK list */
+			list_for_each(_p,&call->acks_pendq) {
+				rttmsg = list_entry(_p,struct rxrpc_message,link);
+				if (rttmsg->hdr.serial==serial) {
+					if (rttmsg->rttdone)
+						break; /* never do RTT twice without resending */
+
+					rttmsg->rttdone = 1;
+					rxrpc_peer_calculate_rtt(call->conn->peer,rttmsg,msg);
+					break;
+				}
+			}
+			spin_unlock(&call->lock);
+		}
+	}
+
+	switch (ack.reason) {
+		/* deal with negative/positive acknowledgement of data packets */
+	case RXRPC_ACK_REQUESTED:
+	case RXRPC_ACK_DELAY:
+	case RXRPC_ACK_IDLE:
+		rxrpc_call_definitively_ACK(call,seq-1);
+
+	case RXRPC_ACK_DUPLICATE:
+	case RXRPC_ACK_OUT_OF_SEQUENCE:
+	case RXRPC_ACK_EXCEEDS_WINDOW:
+		call->snd_resend_cnt = 0;
+		ret = rxrpc_call_record_ACK(call,msg,seq,ack.nAcks);
+		if (ret<0)
+			rxrpc_call_abort(call,ret);
+		break;
+
+		/* respond to ping packets immediately */
+	case RXRPC_ACK_PING:
+		rxrpc_call_generate_ACK(call,&msg->hdr,&ack);
+		break;
+
+		/* only record RTT on ping response packets */
+	case RXRPC_ACK_PING_RESPONSE:
+		if (call->snd_ping) {
+			struct rxrpc_message *rttmsg;
+
+			/* only do RTT stuff if the response matches the retained ping */
+			rttmsg = NULL;
+			spin_lock(&call->lock);
+			if (call->snd_ping && call->snd_ping->hdr.serial==ack.serial) {
+				rttmsg = call->snd_ping;
+				call->snd_ping = NULL;
+			}
+			spin_unlock(&call->lock);
+
+			if (rttmsg) {
+				rttmsg->rttdone = 1;
+				rxrpc_peer_calculate_rtt(call->conn->peer,rttmsg,msg);
+				rxrpc_put_message(rttmsg);
+			}
+		}
+		break;
+
+	default:
+		printk("Unsupported ACK reason %u\n",ack.reason);
+		break;
+	}
+
+	_leave("");
+} /* end rxrpc_call_receive_ack_packet() */
+
+/*****************************************************************************/
+/*
+ * record definitive ACKs for all messages up to and including the one with the 'highest' seq
+ */
+static void rxrpc_call_definitively_ACK(struct rxrpc_call *call, rxrpc_seq_t highest)
+{
+	struct rxrpc_message *msg;
+	int now_complete;
+
+	_enter("%p{ads=%u},%u",call,call->acks_dftv_seq,highest);
+
+	while (call->acks_dftv_seq<highest) {
+		call->acks_dftv_seq++;
+
+		_proto("Definitive ACK on packet #%u",call->acks_dftv_seq);
+
+		/* discard those at front of queue until message with highest ACK is found */
+		spin_lock(&call->lock);
+		msg = NULL;
+		if (!list_empty(&call->acks_pendq)) {
+			msg = list_entry(call->acks_pendq.next,struct rxrpc_message,link);
+			list_del_init(&msg->link); /* dequeue */
+			if (msg->state==RXRPC_MSG_SENT)
+				call->acks_pend_cnt--;
+		}
+		spin_unlock(&call->lock);
+
+		/* insanity check */
+		if (!msg)
+			panic("%s(): acks_pendq unexpectedly empty\n",__FUNCTION__);
+
+		if (msg->seq!=call->acks_dftv_seq)
+			panic("%s(): Packet #%u expected at front of acks_pendq (#%u found)\n",
+			      __FUNCTION__,call->acks_dftv_seq,msg->seq);
+
+		/* discard the message */
+		msg->state = RXRPC_MSG_DONE;
+		rxrpc_put_message(msg);
+	}
+
+	/* if all sent packets are definitively ACK'd then prod any sleepers just in case */
+	now_complete = 0;
+	spin_lock(&call->lock);
+	if (call->acks_dftv_seq==call->snd_seq_count) {
+		if (call->app_call_state!=RXRPC_CSTATE_COMPLETE) {
+			call->app_call_state = RXRPC_CSTATE_COMPLETE;
+			_state(call);
+			now_complete = 1;
+		}
+	}
+	spin_unlock(&call->lock);
+
+	if (now_complete) {
+		del_timer_sync(&call->acks_timeout);
+		del_timer_sync(&call->rcv_timeout);
+		del_timer_sync(&call->ackr_dfr_timo);
+		call->app_attn_func(call);
+	}
+
+	_leave("");
+} /* end rxrpc_call_definitively_ACK() */
+
+/*****************************************************************************/
+/*
+ * record the specified amount of ACKs/NAKs
+ */
+static int rxrpc_call_record_ACK(struct rxrpc_call *call,
+				 struct rxrpc_message *msg,
+				 rxrpc_seq_t seq,
+				 size_t count)
+{
+	struct rxrpc_message *dmsg;
+	struct list_head *_p;
+	rxrpc_seq_t highest;
+	unsigned ix;
+	size_t chunk;
+	char resend, now_complete;
+	u8 acks[16];
+
+	_enter("%p{apc=%u ads=%u},%p,%u,%u",
+	       call,call->acks_pend_cnt,call->acks_dftv_seq,msg,seq,count);
+
+	/* handle re-ACK'ing of definitively ACK'd packets (may be out-of-order ACKs) */
+	if (seq<=call->acks_dftv_seq) {
+		unsigned delta = call->acks_dftv_seq - seq;
+
+		if (count<=delta) {
+			_leave(" = 0 [all definitively ACK'd]");
+			return 0;
+		}
+
+		seq += delta;
+		count -= delta;
+		msg->offset += delta;
+	}
+
+	highest = seq + count - 1;
+	resend = 0;
+	while (count>0) {
+		/* extract up to 16 ACK slots at a time */
+		chunk = min(count,sizeof(acks));
+		count -= chunk;
+
+		memset(acks,2,sizeof(acks));
+
+		if (skb_copy_bits(msg->pkt,msg->offset,&acks,chunk)<0) {
+			printk("Rx Received short ACK packet\n");
+			_leave(" = -EINVAL");
+			return -EINVAL;
+		}
+		msg->offset += chunk;
+
+		/* check that the ACK set is valid */
+		for (ix=0; ix<chunk; ix++) {
+			switch (acks[ix]) {
+			case RXRPC_ACK_TYPE_ACK:
+				break;
+			case RXRPC_ACK_TYPE_NACK:
+				resend = 1;
+				break;
+			default:
+				printk("Rx Received unsupported ACK state %u\n",acks[ix]);
+				_leave(" = -EINVAL");
+				return -EINVAL;
+			}
+		}
+
+		_proto("Rx ACK of packets #%u-#%u [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c] (pend=%u)",
+		       seq,seq+chunk-1,
+		       _acktype[acks[0x0]],
+		       _acktype[acks[0x1]],
+		       _acktype[acks[0x2]],
+		       _acktype[acks[0x3]],
+		       _acktype[acks[0x4]],
+		       _acktype[acks[0x5]],
+		       _acktype[acks[0x6]],
+		       _acktype[acks[0x7]],
+		       _acktype[acks[0x8]],
+		       _acktype[acks[0x9]],
+		       _acktype[acks[0xA]],
+		       _acktype[acks[0xB]],
+		       _acktype[acks[0xC]],
+		       _acktype[acks[0xD]],
+		       _acktype[acks[0xE]],
+		       _acktype[acks[0xF]],
+		       call->acks_pend_cnt
+		       );
+
+		/* mark the packets in the ACK queue as being provisionally ACK'd */
+		ix = 0;
+		spin_lock(&call->lock);
+
+		/* find the first packet ACK'd/NAK'd here */
+		list_for_each(_p,&call->acks_pendq) {
+			dmsg = list_entry(_p,struct rxrpc_message,link);
+			if (dmsg->seq==seq)
+				goto found_first;
+			_debug("- %u: skipping #%u",ix,dmsg->seq);
+		}
+		goto bad_queue;
+
+	found_first:
+		do {
+			_debug("- %u: processing #%u (%c) apc=%u",
+			       ix,dmsg->seq,_acktype[acks[ix]],call->acks_pend_cnt);
+
+			if (acks[ix]==RXRPC_ACK_TYPE_ACK) {
+				if (dmsg->state==RXRPC_MSG_SENT) call->acks_pend_cnt--;
+				dmsg->state = RXRPC_MSG_ACKED;
+			}
+			else {
+				if (dmsg->state==RXRPC_MSG_ACKED) call->acks_pend_cnt++;
+				dmsg->state = RXRPC_MSG_SENT;
+			}
+			ix++;
+			seq++;
+
+			_p = dmsg->link.next;
+			dmsg = list_entry(_p,struct rxrpc_message,link);
+		} while(ix<chunk && _p!=&call->acks_pendq && dmsg->seq==seq);
+
+		if (ix<chunk)
+			goto bad_queue;
+
+		spin_unlock(&call->lock);
+	}
+
+	if (resend)
+		rxrpc_call_resend(call,highest);
+
+	/* if all packets are provisionally ACK'd, then wake up anyone who's waiting for that */
+	now_complete = 0;
+	spin_lock(&call->lock);
+	if (call->acks_pend_cnt==0) {
+		if (call->app_call_state==RXRPC_CSTATE_SRVR_RCV_FINAL_ACK) {
+			call->app_call_state = RXRPC_CSTATE_COMPLETE;
+			_state(call);
+		}
+		now_complete = 1;
+	}
+	spin_unlock(&call->lock);
+
+	if (now_complete) {
+		_debug("- wake up waiters");
+		del_timer_sync(&call->acks_timeout);
+		del_timer_sync(&call->rcv_timeout);
+		del_timer_sync(&call->ackr_dfr_timo);
+		call->app_attn_func(call);
+	}
+
+	_leave(" = 0 (apc=%u)",call->acks_pend_cnt);
+	return 0;
+
+ bad_queue:
+	panic("%s(): acks_pendq in bad state (packet #%u absent)\n",__FUNCTION__,seq);
+
+} /* end rxrpc_call_record_ACK() */
+
+/*****************************************************************************/
+/*
+ * transfer data from the ready packet queue to the asynchronous read buffer
+ * - since this func is the only one going to look at packets queued on app_readyq, we don't need
+ *   a lock to modify or access them, only to modify the queue pointers
+ * - called with call->lock held
+ * - the buffer must be in kernel space
+ * - returns:
+ *	0 if buffer filled
+ *	-EAGAIN if buffer not filled and more data to come
+ *	-EBADMSG if last packet received and insufficient data left
+ *	-ECONNABORTED if the call has in an error state
+ */
+static int __rxrpc_call_read_data(struct rxrpc_call *call)
+{
+	struct rxrpc_message *msg;
+	size_t qty;
+	int ret;
+
+	_enter("%p{as=%d buf=%p qty=%u/%u}",
+	       call,call->app_async_read,call->app_read_buf,call->app_ready_qty,call->app_mark);
+
+	/* check the state */
+	switch (call->app_call_state) {
+	case RXRPC_CSTATE_SRVR_RCV_ARGS:
+	case RXRPC_CSTATE_CLNT_RCV_REPLY:
+		if (call->app_last_rcv) {
+			printk("%s(%p,%p,%d): Inconsistent call state (%s, last pkt)",
+			      __FUNCTION__,call,call->app_read_buf,call->app_mark,
+			      rxrpc_call_states[call->app_call_state]);
+			BUG();
+		}
+		break;
+
+	case RXRPC_CSTATE_SRVR_RCV_OPID:
+	case RXRPC_CSTATE_SRVR_GOT_ARGS:
+	case RXRPC_CSTATE_CLNT_GOT_REPLY:
+		break;
+
+	case RXRPC_CSTATE_SRVR_SND_REPLY:
+		if (!call->app_last_rcv) {
+			printk("%s(%p,%p,%d): Inconsistent call state (%s, not last pkt)",
+			      __FUNCTION__,call,call->app_read_buf,call->app_mark,
+			      rxrpc_call_states[call->app_call_state]);
+			BUG();
+		}
+		_debug("Trying to read data from call in SND_REPLY state");
+		break;
+
+	case RXRPC_CSTATE_ERROR:
+		_leave(" = -ECONNABORTED");
+		return -ECONNABORTED;
+
+	default:
+		printk("reading in unexpected state [[[ %u ]]]\n",call->app_call_state);
+		BUG();
+	}
+
+	/* handle the case of not having an async buffer */
+	if (!call->app_async_read) {
+		if (call->app_mark==RXRPC_APP_MARK_EOF) {
+			ret = call->app_last_rcv ? 0 : -EAGAIN;
+		}
+		else {
+			if (call->app_mark >= call->app_ready_qty) {
+				call->app_mark = RXRPC_APP_MARK_EOF;
+				ret = 0;
+			}
+			else {
+				ret = call->app_last_rcv ? -EBADMSG : -EAGAIN;
+			}
+		}
+
+		_leave(" = %d [no buf]",ret);
+		return 0;
+	}
+
+	while (!list_empty(&call->app_readyq) && call->app_mark>0) {
+		msg = list_entry(call->app_readyq.next,struct rxrpc_message,link);
+
+		/* drag as much data as we need out of this packet */
+		qty = min(call->app_mark,msg->dsize);
+
+		_debug("reading %u from skb=%p off=%lu",qty,msg->pkt,msg->offset);
+
+		if (call->app_read_buf)
+			if (skb_copy_bits(msg->pkt,msg->offset,call->app_read_buf,qty)<0)
+				panic("%s: Failed to copy data from packet: (%p,%p,%d)",
+				      __FUNCTION__,call,call->app_read_buf,qty);
+
+		/* if that packet is now empty, discard it */
+		call->app_ready_qty -= qty;
+		msg->dsize -= qty;
+
+		if (msg->dsize==0) {
+			list_del_init(&msg->link);
+			rxrpc_put_message(msg);
+		}
+		else {
+			msg->offset += qty;
+		}
+
+		call->app_mark -= qty;
+		if (call->app_read_buf) call->app_read_buf += qty;
+	}
+
+	if (call->app_mark==0) {
+		call->app_async_read = 0;
+		call->app_mark = RXRPC_APP_MARK_EOF;
+		call->app_read_buf = NULL;
+
+		/* adjust the state if used up all packets */
+		if (list_empty(&call->app_readyq) && call->app_last_rcv) {
+			switch (call->app_call_state) {
+			case RXRPC_CSTATE_SRVR_RCV_OPID:
+				call->app_call_state = RXRPC_CSTATE_SRVR_SND_REPLY;
+				call->app_mark = RXRPC_APP_MARK_EOF;
+				_state(call);
+				del_timer_sync(&call->rcv_timeout);
+				break;
+			case RXRPC_CSTATE_SRVR_GOT_ARGS:
+				call->app_call_state = RXRPC_CSTATE_SRVR_SND_REPLY;
+				_state(call);
+				del_timer_sync(&call->rcv_timeout);
+				break;
+			default:
+				call->app_call_state = RXRPC_CSTATE_COMPLETE;
+				_state(call);
+				del_timer_sync(&call->acks_timeout);
+				del_timer_sync(&call->ackr_dfr_timo);
+				del_timer_sync(&call->rcv_timeout);
+				break;
+			}
+		}
+
+		_leave(" = 0");
+		return 0;
+	}
+
+	if (call->app_last_rcv) {
+		_debug("Insufficient data (%u/%u)",call->app_ready_qty,call->app_mark);
+		call->app_async_read = 0;
+		call->app_mark = RXRPC_APP_MARK_EOF;
+		call->app_read_buf = NULL;
+
+		_leave(" = -EBADMSG");
+		return -EBADMSG;
+	}
+
+	_leave(" = -EAGAIN");
+	return -EAGAIN;
+} /* end __rxrpc_call_read_data() */
+
+/*****************************************************************************/
+/*
+ * attempt to read the specified amount of data from the call's ready queue into the buffer
+ * provided
+ * - since this func is the only one going to look at packets queued on app_readyq, we don't need
+ *   a lock to modify or access them, only to modify the queue pointers
+ * - if the buffer pointer is NULL, then data is merely drained, not copied
+ * - if flags&RXRPC_CALL_READ_BLOCK, then the function will wait until there is enough data or an
+ *   error will be generated
+ *   - note that the caller must have added the calling task to the call's wait queue beforehand
+ * - if flags&RXRPC_CALL_READ_ALL, then an error will be generated if this function doesn't read
+ *   all available data
+ */
+int rxrpc_call_read_data(struct rxrpc_call *call, void *buffer, size_t size, int flags)
+{
+	int ret;
+
+	_enter("%p{arq=%u},%p,%d,%x",call,call->app_ready_qty,buffer,size,flags);
+
+	spin_lock(&call->lock);
+
+	if (unlikely(!!call->app_read_buf)) {
+		spin_unlock(&call->lock);
+		_leave(" = -EBUSY");
+		return -EBUSY;
+	}
+
+	call->app_mark = size;
+	call->app_read_buf = buffer;
+	call->app_async_read = 1;
+	call->app_read_count++;
+
+	/* read as much data as possible */
+	ret = __rxrpc_call_read_data(call);
+	switch (ret) {
+	case 0:
+		if (flags&RXRPC_CALL_READ_ALL && (!call->app_last_rcv || call->app_ready_qty>0)) {
+			_leave(" = -EBADMSG");
+			__rxrpc_call_abort(call,-EBADMSG);
+			return -EBADMSG;
+		}
+
+		spin_unlock(&call->lock);
+		call->app_attn_func(call);
+		_leave(" = 0");
+		return ret;
+
+	case -ECONNABORTED:
+		spin_unlock(&call->lock);
+		_leave(" = %d [aborted]",ret);
+		return ret;
+
+	default:			
+		__rxrpc_call_abort(call,ret);
+		_leave(" = %d",ret);
+		return ret;
+
+	case -EAGAIN:
+		spin_unlock(&call->lock);
+
+		if (!(flags&RXRPC_CALL_READ_BLOCK)) {
+			_leave(" = -EAGAIN");
+			return -EAGAIN;
+		}
+
+		/* wait for the data to arrive */
+		_debug("blocking for data arrival");
+
+		for (;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (!call->app_async_read || signal_pending(current))
+				break;
+			schedule();
+		}
+		set_current_state(TASK_RUNNING);
+
+		if (signal_pending(current)) {
+			_leave(" = -EINTR");
+			return -EINTR;
+		}
+
+		if (call->app_call_state==RXRPC_CSTATE_ERROR) {
+			_leave(" = -ECONNABORTED");
+			return -ECONNABORTED;
+		}
+
+		_leave(" = 0");
+		return 0;
+	}
+
+} /* end rxrpc_call_read_data() */
+
+/*****************************************************************************/
+/*
+ * write data to a call
+ * - the data may not be sent immediately if it doesn't fill a buffer
+ * - if we can't queue all the data for buffering now, siov[] will have been adjusted to take
+ *   account of what has been sent
+ */
+int rxrpc_call_write_data(struct rxrpc_call *call,
+			  size_t sioc,
+			  struct iovec siov[],
+			  u8 rxhdr_flags,
+			  int alloc_flags,
+			  int dup_data,
+			  size_t *size_sent)
+{
+	struct rxrpc_message *msg;
+	struct iovec *sptr;
+	size_t space, size, chunk, tmp;
+	char *buf;
+	int ret;
+
+	_enter("%p,%u,%p,%02x,%x,%d,%p",call,sioc,siov,rxhdr_flags,alloc_flags,dup_data,size_sent);
+
+	*size_sent = 0;
+	size = 0;
+	ret = -EINVAL;
+
+	/* can't send more if we've sent last packet from this end */
+	switch (call->app_call_state) {
+	case RXRPC_CSTATE_SRVR_SND_REPLY:
+	case RXRPC_CSTATE_CLNT_SND_ARGS:
+		break;
+	case RXRPC_CSTATE_ERROR:
+		ret = call->app_errno;
+	default:
+		goto out;
+	}
+
+	/* calculate how much data we've been given */
+	sptr = siov;
+	for (; sioc>0; sptr++, sioc--) {
+		if (!sptr->iov_len) continue;
+
+		if (!sptr->iov_base)
+			goto out;
+
+		size += sptr->iov_len;
+	}
+
+	_debug("- size=%u mtu=%u",size,call->conn->mtu_size);
+
+	do {
+		/* make sure there's a message under construction */
+		if (!call->snd_nextmsg) {
+			/* no - allocate a message with no data yet attached */
+			ret = rxrpc_conn_newmsg(call->conn,call,RXRPC_PACKET_TYPE_DATA,
+						0,NULL,alloc_flags,&call->snd_nextmsg);
+			if (ret<0)
+				goto out;
+			_debug("- allocated new message [ds=%u]",call->snd_nextmsg->dsize);
+		}
+
+		msg = call->snd_nextmsg;
+		msg->hdr.flags |= rxhdr_flags;
+
+		/* deal with zero-length terminal packet */
+		if (size==0) {
+			if (rxhdr_flags & RXRPC_LAST_PACKET) {
+				ret = rxrpc_call_flush(call);
+				if (ret<0)
+					goto out;
+			}
+			break;
+		}
+
+		/* work out how much space current packet has available */
+		space = call->conn->mtu_size - msg->dsize;
+		chunk = min(space,size);
+
+		_debug("- [before] space=%u chunk=%u",space,chunk);
+
+		while (!siov->iov_len)
+			siov++;
+
+		/* if we are going to have to duplicate the data then coalesce it too */
+		if (dup_data) {
+			/* don't allocate more that 1 page at a time */
+			if (chunk>PAGE_SIZE)
+				chunk = PAGE_SIZE;
+
+			/* allocate a data buffer and attach to the message */
+			buf = kmalloc(chunk,alloc_flags);
+			if (unlikely(!buf)) {
+				if (msg->dsize==sizeof(struct rxrpc_header)) {
+					/* discard an empty msg and wind back the seq counter */
+					rxrpc_put_message(msg);
+					call->snd_nextmsg = NULL;
+					call->snd_seq_count--;
+				}
+
+				ret = -ENOMEM;
+				goto out;
+			}
+
+			tmp = msg->dcount++;
+			set_bit(tmp,&msg->dfree);
+			msg->data[tmp].iov_base = buf;
+			msg->data[tmp].iov_len = chunk;
+			msg->dsize += chunk;
+			*size_sent += chunk;
+			size -= chunk;
+
+			/* load the buffer with data */
+			while (chunk>0) {
+				tmp = min(chunk,siov->iov_len);
+				memcpy(buf,siov->iov_base,tmp);
+				buf += tmp;
+				siov->iov_base += tmp;
+				siov->iov_len -= tmp;
+				if (!siov->iov_len)
+					siov++;
+				chunk -= tmp;
+			}
+		}
+		else {
+			/* we want to attach the supplied buffers directly */
+			while (chunk>0 && msg->dcount<RXRPC_MSG_MAX_IOCS) {
+				tmp = msg->dcount++;
+				msg->data[tmp].iov_base = siov->iov_base;
+				msg->data[tmp].iov_len = siov->iov_len;
+				msg->dsize += siov->iov_len;
+				*size_sent += siov->iov_len;
+				size -= siov->iov_len;
+				chunk -= siov->iov_len;
+				siov++;
+			}
+		}
+
+		_debug("- [loaded] chunk=%u size=%u",chunk,size);
+
+		/* dispatch the message when full, final or requesting ACK */
+		if (msg->dsize>=call->conn->mtu_size || rxhdr_flags) {
+			ret = rxrpc_call_flush(call);
+			if (ret<0)
+				goto out;
+		}
+
+	} while(size>0);
+
+	ret = 0;
+ out:
+	_leave(" = %d (%d queued, %d rem)",ret,*size_sent,size);
+	return ret;
+
+} /* end rxrpc_call_write_data() */
+
+/*****************************************************************************/
+/*
+ * flush outstanding packets to the network
+ */
+int rxrpc_call_flush(struct rxrpc_call *call)
+{
+	struct rxrpc_message *msg;
+	int ret = 0;
+
+	_enter("%p",call);
+
+	rxrpc_get_call(call);
+
+	/* if there's a packet under construction, then dispatch it now */
+	if (call->snd_nextmsg) {
+		msg = call->snd_nextmsg;
+		call->snd_nextmsg = NULL;
+
+		if (msg->hdr.flags & RXRPC_LAST_PACKET) {
+			msg->hdr.flags &= ~RXRPC_MORE_PACKETS;
+			msg->hdr.flags |= RXRPC_REQUEST_ACK;
+		}
+		else {
+			msg->hdr.flags |= RXRPC_MORE_PACKETS;
+		}
+
+		_proto("Sending DATA message { ds=%u dc=%u df=%02lu }",
+		       msg->dsize,msg->dcount,msg->dfree);
+
+		/* queue and adjust call state */
+		spin_lock(&call->lock);
+		list_add_tail(&msg->link,&call->acks_pendq);
+
+		/* decide what to do depending on current state and if this is the last packet */
+		ret = -EINVAL;
+		switch (call->app_call_state) {
+		case RXRPC_CSTATE_SRVR_SND_REPLY:
+			if (msg->hdr.flags & RXRPC_LAST_PACKET) {
+				call->app_call_state = RXRPC_CSTATE_SRVR_RCV_FINAL_ACK;
+				_state(call);
+			}
+			break;
+
+		case RXRPC_CSTATE_CLNT_SND_ARGS:
+			if (msg->hdr.flags & RXRPC_LAST_PACKET) {
+				call->app_call_state = RXRPC_CSTATE_CLNT_RCV_REPLY;
+				_state(call);
+			}
+			break;
+
+		case RXRPC_CSTATE_ERROR:
+			ret = call->app_errno;
+		default:
+			spin_unlock(&call->lock);
+			goto out;
+		}
+
+		call->acks_pend_cnt++;
+
+		mod_timer(&call->acks_timeout,jiffies + rxrpc_call_acks_timeout);
+
+		spin_unlock(&call->lock);
+
+		ret = rxrpc_conn_sendmsg(call->conn,msg);
+		if (ret==0)
+			call->pkt_snd_count++;
+	}
+
+ out:
+	rxrpc_put_call(call);
+
+	_leave(" = %d",ret);
+	return ret;
+
+} /* end rxrpc_call_flush() */
+
+/*****************************************************************************/
+/*
+ * resend NAK'd or unacknowledged packets up to the highest one specified
+ */
+static void rxrpc_call_resend(struct rxrpc_call *call, rxrpc_seq_t highest)
+{
+	struct rxrpc_message *msg;
+	struct list_head *_p;
+	rxrpc_seq_t seq = 0;
+
+	_enter("%p,%u",call,highest);
+
+	_proto("Rx Resend required");
+
+	/* handle too many resends */
+	if (call->snd_resend_cnt>=rxrpc_call_max_resend) {
+		_debug("Aborting due to too many resends (rcv=%d)",call->pkt_rcv_count);
+		rxrpc_call_abort(call,call->pkt_rcv_count>0?-EIO:-ETIMEDOUT);
+		_leave("");
+		return;
+	}
+
+	spin_lock(&call->lock);
+	call->snd_resend_cnt++;
+	for (;;) {
+		/* determine which the next packet we might need to ACK is */
+		if (seq<=call->acks_dftv_seq)
+			seq = call->acks_dftv_seq;
+		seq++;
+
+		if (seq>highest)
+			break;
+
+		/* look for the packet in the pending-ACK queue */
+		list_for_each(_p,&call->acks_pendq) {
+			msg = list_entry(_p,struct rxrpc_message,link);
+			if (msg->seq==seq)
+				goto found_msg;
+		}
+
+		panic("%s(%p,%d): Inconsistent pending-ACK queue (ds=%u sc=%u sq=%u)\n",
+		      __FUNCTION__,call,highest,call->acks_dftv_seq,call->snd_seq_count,seq);
+
+	found_msg:
+		if (msg->state!=RXRPC_MSG_SENT)
+			continue; /* only un-ACK'd packets */
+
+		rxrpc_get_message(msg);
+		spin_unlock(&call->lock);
+
+		/* send each message again (and ignore any errors we might incur) */
+		_proto("Resending DATA message { ds=%u dc=%u df=%02lu }",
+		       msg->dsize,msg->dcount,msg->dfree);
+
+		if (rxrpc_conn_sendmsg(call->conn,msg)==0)
+			call->pkt_snd_count++;
+
+		rxrpc_put_message(msg);
+
+		spin_lock(&call->lock);
+	}
+
+	/* reset the timeout */
+	mod_timer(&call->acks_timeout,jiffies + rxrpc_call_acks_timeout);
+
+	spin_unlock(&call->lock);
+
+	_leave("");
+} /* end rxrpc_call_resend() */
+
+/*****************************************************************************/
+/*
+ * handle an ICMP error being applied to a call
+ */
+void rxrpc_call_handle_error(struct rxrpc_call *call, int local, int errno)
+{
+	_enter("%p{%u},%d",call,ntohl(call->call_id),errno);
+
+	/* if this call is already aborted, then just wake up any waiters */
+	if (call->app_call_state==RXRPC_CSTATE_ERROR) {
+		call->app_error_func(call);
+	}
+	else {
+		/* tell the app layer what happened */
+		spin_lock(&call->lock);
+		call->app_call_state = RXRPC_CSTATE_ERROR;
+		_state(call);
+		if (local)
+			call->app_err_state = RXRPC_ESTATE_LOCAL_ERROR;
+		else
+			call->app_err_state = RXRPC_ESTATE_REMOTE_ERROR;
+		call->app_errno = errno;
+		call->app_mark = RXRPC_APP_MARK_EOF;
+		call->app_read_buf = NULL;
+		call->app_async_read = 0;
+
+		/* map the error */
+		call->app_aemap_func(call);
+
+		del_timer_sync(&call->acks_timeout);
+		del_timer_sync(&call->rcv_timeout);
+		del_timer_sync(&call->ackr_dfr_timo);
+
+		spin_unlock(&call->lock);
+
+		call->app_error_func(call);
+	}
+
+	_leave("");
+} /* end rxrpc_call_handle_error() */
diff -Nru a/net/rxrpc/connection.c b/net/rxrpc/connection.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/connection.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,687 @@
+/* connection.c: Rx connection routines
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include <rxrpc/message.h>
+#include <linux/udp.h>
+#include <linux/ip.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include "internal.h"
+
+__RXACCT_DECL(atomic_t rxrpc_connection_count);
+
+LIST_HEAD(rxrpc_conns);
+DECLARE_RWSEM(rxrpc_conns_sem);
+
+static void __rxrpc_conn_timeout(rxrpc_timer_t *timer)
+{
+	struct rxrpc_connection *conn = list_entry(timer,struct rxrpc_connection,timeout);
+
+	_debug("Rx CONN TIMEOUT [%p{u=%d}]",conn,atomic_read(&conn->usage));
+
+	rxrpc_conn_do_timeout(conn);
+}
+
+static const struct rxrpc_timer_ops rxrpc_conn_timer_ops = {
+	timed_out:	__rxrpc_conn_timeout,
+};
+
+/*****************************************************************************/
+/*
+ * create a new connection record
+ */
+static inline int __rxrpc_create_connection(struct rxrpc_peer *peer,
+					    struct rxrpc_connection **_conn)
+{
+	struct rxrpc_connection *conn;
+
+	_enter("%p",peer);
+
+	/* allocate and initialise a connection record */
+	conn = kmalloc(sizeof(struct rxrpc_connection),GFP_KERNEL);
+	if (!conn) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	memset(conn,0,sizeof(struct rxrpc_connection));
+	atomic_set(&conn->usage,1);
+
+	INIT_LIST_HEAD(&conn->link);
+	init_waitqueue_head(&conn->chanwait);
+	spin_lock_init(&conn->lock);
+	rxrpc_timer_init(&conn->timeout,&rxrpc_conn_timer_ops);
+
+	do_gettimeofday(&conn->atime);
+	conn->mtu_size = 1024;
+	conn->peer = peer;
+	conn->trans = peer->trans;
+
+	__RXACCT(atomic_inc(&rxrpc_connection_count));
+	*_conn = conn;
+	_leave(" = 0 (%p)",conn);
+
+	return 0;
+} /* end __rxrpc_create_connection() */
+
+/*****************************************************************************/
+/*
+ * create a new connection record for outgoing connections
+ */
+int rxrpc_create_connection(struct rxrpc_transport *trans,
+			    u16 port,
+			    u32 addr,
+			    unsigned short service_id,
+			    void *security,
+			    struct rxrpc_connection **_conn)
+{
+	struct rxrpc_connection *conn;
+	struct rxrpc_peer *peer;
+	int ret;
+
+	_enter("%p{%hu},%u,%hu",trans,trans->port,ntohs(port),service_id);
+
+	/* get a peer record */
+	ret = rxrpc_peer_lookup(trans,addr,&peer);
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	/* allocate and initialise a connection record */
+	ret = __rxrpc_create_connection(peer,&conn);
+	if (ret<0) {
+		rxrpc_put_peer(peer);
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	/* fill in the specific bits */
+	conn->addr.sin_family	= AF_INET;
+	conn->addr.sin_port	= port;
+	conn->addr.sin_addr.s_addr = addr;
+
+	conn->in_epoch		= rxrpc_epoch;
+	conn->out_epoch		= rxrpc_epoch;
+	conn->in_clientflag	= 0;
+	conn->out_clientflag	= RXRPC_CLIENT_INITIATED;
+	conn->conn_id		= htonl((unsigned) conn & RXRPC_CIDMASK);
+	conn->service_id	= htons(service_id);
+
+	/* attach to peer */
+	conn->peer = peer;
+
+	write_lock(&peer->conn_lock);
+	list_add_tail(&conn->link,&peer->conn_active);
+	atomic_inc(&peer->conn_count);
+	write_unlock(&peer->conn_lock);
+
+	down_write(&rxrpc_conns_sem);
+	list_add_tail(&conn->proc_link,&rxrpc_conns);
+	up_write(&rxrpc_conns_sem);
+
+	*_conn = conn;
+	_leave(" = 0 (%p)",conn);
+
+	return 0;
+} /* end rxrpc_create_connection() */
+
+/*****************************************************************************/
+/*
+ * lookup the connection for an incoming packet
+ * - create a new connection record for unrecorded incoming connections
+ */
+int rxrpc_connection_lookup(struct rxrpc_peer *peer,
+			    struct rxrpc_message *msg,
+			    struct rxrpc_connection **_conn)
+{
+	struct rxrpc_connection *conn, *candidate = NULL;
+	struct list_head *_p;
+	int ret, fresh = 0;
+	u32 x_epoch, x_connid;
+	u16 x_port, x_secix, x_servid;
+	u8 x_clflag;
+
+	_enter("%p{{%hu}},%u,%hu",
+	       peer,peer->trans->port,ntohs(msg->pkt->h.uh->source),ntohs(msg->hdr.serviceId));
+
+	x_port		= msg->pkt->h.uh->source;
+	x_epoch		= msg->hdr.epoch;
+	x_clflag	= msg->hdr.flags & RXRPC_CLIENT_INITIATED;
+	x_connid	= htonl(ntohl(msg->hdr.cid) & RXRPC_CIDMASK);
+	x_servid	= msg->hdr.serviceId;
+	x_secix		= msg->hdr.securityIndex;
+
+	/* [common case] search the transport's active list first */
+	read_lock(&peer->conn_lock);
+	list_for_each(_p,&peer->conn_active) {
+		conn = list_entry(_p,struct rxrpc_connection,link);
+		if (conn->addr.sin_port		== x_port	&&
+		    conn->in_epoch		== x_epoch	&&
+		    conn->conn_id		== x_connid	&&
+		    conn->security_ix		== x_secix	&&
+		    conn->service_id		== x_servid	&& 
+		    conn->in_clientflag		== x_clflag)
+			goto found_active;
+	}
+	read_unlock(&peer->conn_lock);
+
+	/* [uncommon case] not active 
+	 * - create a candidate for a new record if an inbound connection
+	 * - only examine the graveyard for an outbound connection
+	 */
+	if (x_clflag) {
+		ret = __rxrpc_create_connection(peer,&candidate);
+		if (ret<0) {
+			_leave(" = %d",ret);
+			return ret;
+		}
+
+		/* fill in the specifics */
+		candidate->addr.sin_family	= AF_INET;
+		candidate->addr.sin_port	= x_port;
+		candidate->addr.sin_addr.s_addr = msg->pkt->nh.iph->saddr;
+		candidate->in_epoch		= x_epoch;
+		candidate->out_epoch		= x_epoch;
+		candidate->in_clientflag	= RXRPC_CLIENT_INITIATED;
+		candidate->out_clientflag	= 0;
+		candidate->conn_id		= x_connid;
+		candidate->service_id		= x_servid;
+		candidate->security_ix		= x_secix;
+	}
+
+	/* search the active list again, just in case it appeared whilst we were busy */
+	write_lock(&peer->conn_lock);
+	list_for_each(_p,&peer->conn_active) {
+		conn = list_entry(_p,struct rxrpc_connection,link);
+		if (conn->addr.sin_port		== x_port	&&
+		    conn->in_epoch		== x_epoch	&&
+		    conn->conn_id		== x_connid	&&
+		    conn->security_ix		== x_secix	&&
+		    conn->service_id		== x_servid	&& 
+		    conn->in_clientflag		== x_clflag)
+			goto found_active_second_chance;
+	}
+
+	/* search the transport's graveyard list */
+	spin_lock(&peer->conn_gylock);
+	list_for_each(_p,&peer->conn_graveyard) {
+		conn = list_entry(_p,struct rxrpc_connection,link);
+		if (conn->addr.sin_port		== x_port	&&
+		    conn->in_epoch		== x_epoch	&&
+		    conn->conn_id		== x_connid	&&
+		    conn->security_ix		== x_secix	&&
+		    conn->service_id		== x_servid	&& 
+		    conn->in_clientflag		== x_clflag)
+			goto found_in_graveyard;
+	}
+	spin_unlock(&peer->conn_gylock);
+
+	/* outbound connections aren't created here */
+	if (!x_clflag) {
+		write_unlock(&peer->conn_lock);
+		_leave(" = -ENOENT");
+		return -ENOENT;
+	}
+
+	/* we can now add the new candidate to the list */
+	rxrpc_get_peer(peer);
+	conn = candidate;
+	candidate = NULL;
+	atomic_inc(&peer->conn_count);
+	fresh = 1;
+
+ make_active:
+	list_add_tail(&conn->link,&peer->conn_active);
+
+ success_uwfree:
+	write_unlock(&peer->conn_lock);
+
+	if (candidate) {
+		__RXACCT(atomic_dec(&rxrpc_connection_count));
+		kfree(candidate);
+	}
+
+	if (fresh) {
+		down_write(&rxrpc_conns_sem);
+		list_add_tail(&conn->proc_link,&rxrpc_conns);
+		up_write(&rxrpc_conns_sem);
+	}
+
+ success:
+	*_conn = conn;
+	_leave(" = 0 (%p)",conn);
+	return 0;
+
+	/* handle the connection being found in the active list straight off */
+ found_active:
+	rxrpc_get_connection(conn);
+	read_unlock(&peer->conn_lock);
+	goto success;
+
+	/* handle resurrecting a connection from the graveyard */
+ found_in_graveyard:
+	rxrpc_get_peer(peer);
+	rxrpc_get_connection(conn);
+	rxrpc_krxtimod_del_timer(&conn->timeout);
+	list_del_init(&conn->link);
+	spin_unlock(&peer->conn_gylock);
+	goto make_active;
+
+	/* handle finding the connection on the second time through the active list */
+ found_active_second_chance:
+	rxrpc_get_connection(conn);
+	goto success_uwfree;
+
+} /* end rxrpc_connection_lookup() */
+
+/*****************************************************************************/
+/*
+ * finish using a connection record
+ * - it will be transferred to the peer's connection graveyard when refcount reaches 0
+ */
+void rxrpc_put_connection(struct rxrpc_connection *conn)
+{
+	struct rxrpc_peer *peer = conn->peer;
+
+	_enter("%p{u=%d p=%hu}",conn,atomic_read(&conn->usage),ntohs(conn->addr.sin_port));
+
+	/* sanity check */
+	if (atomic_read(&conn->usage)<=0)
+		BUG();
+
+	spin_lock(&peer->conn_gylock);
+	if (likely(!atomic_dec_and_test(&conn->usage))) {
+		spin_unlock(&peer->conn_gylock);
+		_leave("");
+		return;
+	}
+
+	/* move to graveyard queue */
+	list_del(&conn->link);
+	list_add_tail(&conn->link,&peer->conn_graveyard);
+
+	/* discard in 100 secs */
+	rxrpc_krxtimod_add_timer(&conn->timeout,20*HZ);
+
+	spin_unlock(&peer->conn_gylock);
+
+	rxrpc_put_peer(conn->peer);
+
+	_leave(" [killed]");
+} /* end rxrpc_put_connection() */
+
+/*****************************************************************************/
+/*
+ * free a connection record
+ */
+void rxrpc_conn_do_timeout(struct rxrpc_connection *conn)
+{
+	struct rxrpc_peer *peer;
+
+	_enter("%p{u=%d p=%hu}",conn,atomic_read(&conn->usage),ntohs(conn->addr.sin_port));
+
+	peer = conn->peer;
+
+	if (atomic_read(&conn->usage)<0)
+		BUG();
+
+	/* remove from graveyard if still dead */
+	spin_lock(&peer->conn_gylock);
+	if (atomic_read(&conn->usage)==0) {
+		list_del_init(&conn->link);
+	}
+	else {
+		conn = NULL;
+	}
+	spin_unlock(&peer->conn_gylock);
+
+	if (!conn) {
+		_leave("");
+		return; /* resurrected */
+	}
+
+	_debug("--- Destroying Connection %p ---",conn);
+
+	down_write(&rxrpc_conns_sem);
+	list_del(&conn->proc_link);
+	up_write(&rxrpc_conns_sem);
+
+	__RXACCT(atomic_dec(&rxrpc_connection_count));
+	kfree(conn);
+
+	/* if the graveyard is now empty, wake up anyone waiting for that */
+	if (atomic_dec_and_test(&peer->conn_count))
+		wake_up(&peer->conn_gy_waitq);
+
+	_leave(" [destroyed]");
+} /* end rxrpc_conn_do_timeout() */
+
+/*****************************************************************************/
+/*
+ * clear all connection records from a peer endpoint
+ */
+void rxrpc_conn_clearall(struct rxrpc_peer *peer)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_connection *conn;
+	int err;
+
+	_enter("%p",peer);
+
+	/* there shouldn't be any active conns remaining */
+	if (!list_empty(&peer->conn_active))
+		BUG();
+
+	/* manually timeout all conns in the graveyard */
+	spin_lock(&peer->conn_gylock);
+	while (!list_empty(&peer->conn_graveyard)) {
+		conn = list_entry(peer->conn_graveyard.next,struct rxrpc_connection,link);
+		err = rxrpc_krxtimod_del_timer(&conn->timeout);
+		spin_unlock(&peer->conn_gylock);
+
+		if (err==0)
+			rxrpc_conn_do_timeout(conn);
+
+		spin_lock(&peer->conn_gylock);
+	}
+	spin_unlock(&peer->conn_gylock);
+
+	/* wait for the the conn graveyard to be completely cleared */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&peer->conn_gy_waitq,&myself);
+
+	while (atomic_read(&peer->conn_count)!=0) {
+		schedule();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+	}
+
+	remove_wait_queue(&peer->conn_gy_waitq,&myself);
+	set_current_state(TASK_RUNNING);
+
+	_leave("");
+
+} /* end rxrpc_conn_clearall() */
+
+/*****************************************************************************/
+/*
+ * allocate and prepare a message for sending out through the transport endpoint
+ */
+int rxrpc_conn_newmsg(struct rxrpc_connection *conn,
+		      struct rxrpc_call *call,
+		      u8 type,
+		      int dcount,
+		      struct iovec diov[],
+		      int alloc_flags,
+		      struct rxrpc_message **_msg)
+{
+	struct rxrpc_message *msg;
+	int loop;
+
+	_enter("%p{%d},%p,%u",conn,ntohs(conn->addr.sin_port),call,type);
+
+	if (dcount>3) {
+		_leave(" = -EINVAL");
+		return -EINVAL;
+	}
+
+	msg = kmalloc(sizeof(struct rxrpc_message),alloc_flags);
+	if (!msg) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	memset(msg,0,sizeof(*msg));
+	atomic_set(&msg->usage,1);
+
+	INIT_LIST_HEAD(&msg->link);
+
+	msg->state = RXRPC_MSG_PREPARED;
+
+	msg->hdr.epoch		= conn->out_epoch;
+	msg->hdr.cid		= conn->conn_id | (call ? call->chan_ix : 0);
+	msg->hdr.callNumber	= call ? call->call_id : 0;
+	msg->hdr.type		= type;
+	msg->hdr.flags		= conn->out_clientflag;
+	msg->hdr.securityIndex	= conn->security_ix;
+	msg->hdr.serviceId	= conn->service_id;
+
+	/* generate sequence numbers for data packets */
+	if (call) {
+		switch (type) {
+		case RXRPC_PACKET_TYPE_DATA:
+			msg->seq = ++call->snd_seq_count;
+			msg->hdr.seq = htonl(msg->seq);
+			break;
+		case RXRPC_PACKET_TYPE_ACK:
+			/* ACK sequence numbers are complicated. The following may be wrong:
+			 * - jumbo packet ACKs should have a seq number
+			 * - normal ACKs should not
+			 */
+		default:
+			break;
+		}
+	}
+
+	msg->dcount = dcount + 1;
+	msg->dsize = sizeof(msg->hdr);
+	msg->data[0].iov_len = sizeof(msg->hdr);
+	msg->data[0].iov_base = &msg->hdr;
+
+	for (loop=0; loop<dcount; loop++) {
+		msg->dsize += diov[loop].iov_len;
+		msg->data[loop+1].iov_len  = diov[loop].iov_len;
+		msg->data[loop+1].iov_base = diov[loop].iov_base;
+	}
+
+	__RXACCT(atomic_inc(&rxrpc_message_count));
+	*_msg = msg;
+	_leave(" = 0 (%p) #%d",msg,atomic_read(&rxrpc_message_count));
+	return 0;
+} /* end rxrpc_conn_newmsg() */
+
+/*****************************************************************************/
+/*
+ * free a message
+ */
+void __rxrpc_put_message(struct rxrpc_message *msg)
+{
+	int loop;
+
+	_enter("%p #%d",msg,atomic_read(&rxrpc_message_count));
+
+	if (msg->pkt) kfree_skb(msg->pkt);
+	if (msg->conn) rxrpc_put_connection(msg->conn);
+
+	for (loop=0; loop<8; loop++)
+		if (test_bit(loop,&msg->dfree))
+			kfree(msg->data[loop].iov_base);
+
+	__RXACCT(atomic_dec(&rxrpc_message_count));
+	kfree(msg);
+
+	_leave("");
+} /* end __rxrpc_put_message() */
+
+/*****************************************************************************/
+/*
+ * send a message out through the transport endpoint
+ */
+int rxrpc_conn_sendmsg(struct rxrpc_connection *conn, struct rxrpc_message *msg)
+{
+	struct msghdr msghdr;
+	mm_segment_t oldfs;
+	int ret;
+
+	_enter("%p{%d}",conn,ntohs(conn->addr.sin_port));
+
+	/* fill in some fields in the header */
+	spin_lock(&conn->lock);
+	msg->hdr.serial = htonl(++conn->serial_counter);
+	msg->rttdone = 0;
+	spin_unlock(&conn->lock);
+
+	/* set up the message to be transmitted */
+	msghdr.msg_name		= &conn->addr;
+	msghdr.msg_namelen	= sizeof(conn->addr);
+	msghdr.msg_iov		= msg->data;
+	msghdr.msg_iovlen	= msg->dcount;
+	msghdr.msg_control	= NULL;
+	msghdr.msg_controllen	= 0;
+	msghdr.msg_flags	= MSG_CONFIRM|MSG_DONTWAIT;
+
+	_net("Sending message type %d of %d bytes to %08x:%d",
+	     msg->hdr.type,
+	     msg->dsize,
+	     htonl(conn->addr.sin_addr.s_addr),
+	     htons(conn->addr.sin_port));
+
+	/* send the message */
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sock_sendmsg(conn->trans->socket,&msghdr,msg->dsize);
+	set_fs(oldfs);
+
+	if (ret<0) {
+		msg->state = RXRPC_MSG_ERROR;
+	}
+	else {
+		msg->state = RXRPC_MSG_SENT;
+		ret = 0;
+
+		spin_lock(&conn->lock);
+		do_gettimeofday(&conn->atime);
+		msg->stamp = conn->atime;
+		spin_unlock(&conn->lock);
+	}
+
+	_leave(" = %d",ret);
+
+	return ret;
+} /* end rxrpc_conn_sendmsg() */
+
+/*****************************************************************************/
+/*
+ * deal with a subsequent call packet
+ */
+int rxrpc_conn_receive_call_packet(struct rxrpc_connection *conn,
+				   struct rxrpc_call *call,
+				   struct rxrpc_message *msg)
+{
+	struct rxrpc_message *pmsg;
+	struct list_head *_p;
+	unsigned cix, seq;
+	int ret = 0;
+
+	_enter("%p,%p,%p",conn,call,msg);
+
+	if (!call) {
+		cix = ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK;
+
+		spin_lock(&conn->lock);
+		call = conn->channels[cix];
+
+		if (!call || call->call_id != msg->hdr.callNumber) {
+			spin_unlock(&conn->lock);
+			rxrpc_trans_immediate_abort(conn->trans,msg,-ENOENT);
+			goto out;
+		}
+		else {
+			rxrpc_get_call(call);
+			spin_unlock(&conn->lock);
+		}
+	}
+	else {
+		rxrpc_get_call(call);
+	}
+
+	_proto("Received packet %%%u [%u] on call %hu:%u:%u",
+	       htonl(msg->hdr.serial),
+	       htonl(msg->hdr.seq),
+	       htons(msg->hdr.serviceId),
+	       htonl(conn->conn_id),
+	       htonl(call->call_id));
+
+	call->pkt_rcv_count++;
+
+	if (msg->pkt->dst && msg->pkt->dst->dev)
+		conn->peer->if_mtu = msg->pkt->dst->dev->mtu - msg->pkt->dst->dev->hard_header_len;
+
+	/* queue on the call in seq order */
+	rxrpc_get_message(msg);
+	seq = msg->seq;
+
+	spin_lock(&call->lock);
+	list_for_each(_p,&call->rcv_receiveq) {
+		pmsg = list_entry(_p,struct rxrpc_message,link);
+		if (pmsg->seq>seq)
+			break;
+	}
+	list_add_tail(&msg->link,_p);
+
+	/* reset the activity timeout */
+	call->flags |= RXRPC_CALL_RCV_PKT;
+	mod_timer(&call->rcv_timeout,jiffies + rxrpc_call_rcv_timeout * HZ);
+
+	spin_unlock(&call->lock);
+
+	rxrpc_krxiod_queue_call(call);
+
+	rxrpc_put_call(call);
+ out:
+	_leave(" = %d",ret);
+
+	return ret;
+} /* end rxrpc_conn_receive_call_packet() */
+
+/*****************************************************************************/
+/*
+ * handle an ICMP error being applied to a connection
+ */
+void rxrpc_conn_handle_error(struct rxrpc_connection *conn, int local, int errno)
+{
+	struct rxrpc_call *calls[4];
+	int loop;
+
+	_enter("%p{%d},%d",conn,ntohs(conn->addr.sin_port),errno);
+
+	/* get a ref to all my calls in one go */
+	memset(calls,0,sizeof(calls));
+	spin_lock(&conn->lock);
+
+	for (loop=3; loop>=0; loop--) {
+		if (conn->channels[loop]) {
+			calls[loop] = conn->channels[loop];
+			rxrpc_get_call(calls[loop]);
+		}
+	}
+
+	spin_unlock(&conn->lock);
+
+	/* now kick them all */
+	for (loop=3; loop>=0; loop--) {
+		if (calls[loop]) {
+			rxrpc_call_handle_error(calls[loop],local,errno);
+			rxrpc_put_call(calls[loop]);
+		}
+	}
+
+	_leave("");
+} /* end rxrpc_conn_handle_error() */
diff -Nru a/net/rxrpc/internal.h b/net/rxrpc/internal.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/internal.h	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,107 @@
+/* internal.h: internal Rx RPC stuff
+ *
+ * Copyright (c) 2002   David Howells (dhowells@redhat.com).
+ */
+
+#ifndef RXRPC_INTERNAL_H
+#define RXRPC_INTERNAL_H
+
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+
+/*
+ * debug accounting
+ */
+#if 1
+#define __RXACCT_DECL(X) X
+#define __RXACCT(X) do { X; } while(0) 
+#else
+#define __RXACCT_DECL(X)
+#define __RXACCT(X) do { } while(0)
+#endif
+
+__RXACCT_DECL(extern atomic_t rxrpc_transport_count);
+__RXACCT_DECL(extern atomic_t rxrpc_peer_count);
+__RXACCT_DECL(extern atomic_t rxrpc_connection_count);
+__RXACCT_DECL(extern atomic_t rxrpc_call_count);
+__RXACCT_DECL(extern atomic_t rxrpc_message_count);
+
+/*
+ * debug tracing
+ */
+#define kenter(FMT,...)	printk("==> %s("FMT")\n",__FUNCTION__,##__VA_ARGS__)
+#define kleave(FMT,...)	printk("<== %s()"FMT"\n",__FUNCTION__,##__VA_ARGS__)
+#define kdebug(FMT,...)	printk("    "FMT"\n",##__VA_ARGS__)
+#define kproto(FMT,...)	printk("### "FMT"\n",##__VA_ARGS__)
+#define knet(FMT,...)	printk("    "FMT"\n",##__VA_ARGS__)
+
+#if 0
+#define _enter(FMT,...)	kenter(FMT,##__VA_ARGS__)
+#define _leave(FMT,...)	kleave(FMT,##__VA_ARGS__)
+#define _debug(FMT,...)	kdebug(FMT,##__VA_ARGS__)
+#define _proto(FMT,...)	kproto(FMT,##__VA_ARGS__)
+#define _net(FMT,...)	knet(FMT,##__VA_ARGS__)
+#else
+#define _enter(FMT,...)	do { if (rxrpc_ktrace) kenter(FMT,##__VA_ARGS__); } while(0)
+#define _leave(FMT,...)	do { if (rxrpc_ktrace) kleave(FMT,##__VA_ARGS__); } while(0)
+#define _debug(FMT,...)	do { if (rxrpc_kdebug) kdebug(FMT,##__VA_ARGS__); } while(0)
+#define _proto(FMT,...)	do { if (rxrpc_kproto) kproto(FMT,##__VA_ARGS__); } while(0)
+#define _net(FMT,...)	do { if (rxrpc_knet)   knet  (FMT,##__VA_ARGS__); } while(0)
+#endif
+
+static inline void rxrpc_discard_my_signals(void)
+{
+	while (signal_pending(current)) {
+		siginfo_t sinfo;
+
+		spin_lock_irq(&current->sig->siglock);
+		dequeue_signal(&current->blocked,&sinfo);
+		spin_unlock_irq(&current->sig->siglock);
+	}
+}
+
+/*
+ * call.c
+ */
+extern struct list_head rxrpc_calls;
+extern struct rw_semaphore rxrpc_calls_sem;
+
+/*
+ * connection.c
+ */
+extern struct list_head rxrpc_conns;
+extern struct rw_semaphore rxrpc_conns_sem;
+
+extern void rxrpc_conn_do_timeout(struct rxrpc_connection *conn);
+extern void rxrpc_conn_clearall(struct rxrpc_peer *peer);
+
+/*
+ * peer.c
+ */
+extern struct list_head rxrpc_peers;
+extern struct rw_semaphore rxrpc_peers_sem;
+
+extern void rxrpc_peer_calculate_rtt(struct rxrpc_peer *peer,
+				     struct rxrpc_message *msg,
+				     struct rxrpc_message *resp);
+
+extern void rxrpc_peer_clearall(struct rxrpc_transport *trans);
+
+extern void rxrpc_peer_do_timeout(struct rxrpc_peer *peer);
+
+
+/*
+ * proc.c
+ */
+#ifdef CONFIG_PROC_FS
+extern int rxrpc_proc_init(void);
+extern void rxrpc_proc_cleanup(void);
+#endif
+
+/*
+ * transport.c
+ */
+extern struct list_head rxrpc_proc_transports;
+extern struct rw_semaphore rxrpc_proc_transports_sem;
+
+#endif /* RXRPC_INTERNAL_H */
diff -Nru a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/krxiod.c	Tue Oct 15 20:29:23 2002
@@ -0,0 +1,262 @@
+/* krxiod.c: Rx I/O daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <rxrpc/krxiod.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/call.h>
+#include "internal.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxiod_sleepq);
+static DECLARE_COMPLETION(rxrpc_krxiod_dead);
+
+static atomic_t rxrpc_krxiod_qcount = ATOMIC_INIT(0);
+
+static LIST_HEAD(rxrpc_krxiod_transportq);
+static spinlock_t rxrpc_krxiod_transportq_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(rxrpc_krxiod_callq);
+static spinlock_t rxrpc_krxiod_callq_lock = SPIN_LOCK_UNLOCKED;
+
+static volatile int rxrpc_krxiod_die;
+
+/*****************************************************************************/
+/*
+ * Rx I/O daemon
+ */
+static int rxrpc_krxiod(void *arg)
+{
+	DECLARE_WAITQUEUE(krxiod,current);
+
+	printk("Started krxiod %d\n",current->pid);
+	strcpy(current->comm,"krxiod");
+
+	daemonize();
+
+	/* only certain signals are of interest */
+	spin_lock_irq(&current->sig->siglock);
+	siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+	recalc_sigpending();
+#else
+	recalc_sigpending(current);
+#endif
+	spin_unlock_irq(&current->sig->siglock);
+
+	/* loop around waiting for work to do */
+	do {
+		/* wait for work or to be told to exit */
+		_debug("### Begin Wait");
+		if (!atomic_read(&rxrpc_krxiod_qcount)) {
+			set_current_state(TASK_INTERRUPTIBLE);
+
+			add_wait_queue(&rxrpc_krxiod_sleepq,&krxiod);
+
+			for (;;) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (atomic_read(&rxrpc_krxiod_qcount) ||
+				    rxrpc_krxiod_die ||
+				    signal_pending(current))
+					break;
+
+				schedule();
+			}
+
+			remove_wait_queue(&rxrpc_krxiod_sleepq,&krxiod);
+			set_current_state(TASK_RUNNING);
+		}
+		_debug("### End Wait");
+
+		/* do work if been given some to do */
+		_debug("### Begin Work");
+
+		/* see if there's a transport in need of attention */
+		if (!list_empty(&rxrpc_krxiod_transportq)) {
+			struct rxrpc_transport *trans = NULL;
+
+			spin_lock_irq(&rxrpc_krxiod_transportq_lock);
+
+			if (!list_empty(&rxrpc_krxiod_transportq)) {
+				trans = list_entry(rxrpc_krxiod_transportq.next,
+						   struct rxrpc_transport,krxiodq_link);
+				list_del_init(&trans->krxiodq_link);
+				atomic_dec(&rxrpc_krxiod_qcount);
+
+				/* make sure it hasn't gone away and doesn't go away */
+				if (atomic_read(&trans->usage)>0)
+					rxrpc_get_transport(trans);
+				else
+					trans = NULL;
+			}
+
+			spin_unlock_irq(&rxrpc_krxiod_transportq_lock);
+
+			if (trans) {
+				rxrpc_trans_receive_packet(trans);
+				rxrpc_put_transport(trans);
+			}
+		}
+
+		/* see if there's a call in need of attention */
+		if (!list_empty(&rxrpc_krxiod_callq)) {
+			struct rxrpc_call *call = NULL;
+
+			spin_lock_irq(&rxrpc_krxiod_callq_lock);
+
+			if (!list_empty(&rxrpc_krxiod_callq)) {
+				call = list_entry(rxrpc_krxiod_callq.next,
+						   struct rxrpc_call,rcv_krxiodq_lk);
+				list_del_init(&call->rcv_krxiodq_lk);
+				atomic_dec(&rxrpc_krxiod_qcount);
+
+				/* make sure it hasn't gone away and doesn't go away */
+				if (atomic_read(&call->usage)>0) {
+					_debug("@@@ KRXIOD Begin Attend Call %p",call);
+					rxrpc_get_call(call);
+				}
+				else {
+					call = NULL;
+				}
+			}
+
+			spin_unlock_irq(&rxrpc_krxiod_callq_lock);
+
+			if (call) {
+				rxrpc_call_do_stuff(call);
+				rxrpc_put_call(call);
+				_debug("@@@ KRXIOD End Attend Call %p",call);
+			}
+		}
+
+		_debug("### End Work");
+
+                /* discard pending signals */
+		rxrpc_discard_my_signals();
+
+	} while (!rxrpc_krxiod_die);
+
+	/* and that's all */
+	complete_and_exit(&rxrpc_krxiod_dead,0);
+
+} /* end rxrpc_krxiod() */
+
+/*****************************************************************************/
+/*
+ * start up a krxiod daemon
+ */
+int __init rxrpc_krxiod_init(void)
+{
+	return kernel_thread(rxrpc_krxiod,NULL,0);
+
+} /* end rxrpc_krxiod_init() */
+
+/*****************************************************************************/
+/*
+ * kill the krxiod daemon and wait for it to complete
+ */
+void rxrpc_krxiod_kill(void)
+{
+	rxrpc_krxiod_die = 1;
+	wake_up_all(&rxrpc_krxiod_sleepq);
+	wait_for_completion(&rxrpc_krxiod_dead);
+
+} /* end rxrpc_krxiod_kill() */
+
+/*****************************************************************************/
+/*
+ * queue a transport for attention by krxiod
+ */
+void rxrpc_krxiod_queue_transport(struct rxrpc_transport *trans)
+{
+	unsigned long flags;
+
+	_enter("");
+
+	if (list_empty(&trans->krxiodq_link)) {
+		spin_lock_irqsave(&rxrpc_krxiod_transportq_lock,flags);
+
+		if (list_empty(&trans->krxiodq_link)) {
+			if (atomic_read(&trans->usage)>0) {
+				list_add_tail(&trans->krxiodq_link,&rxrpc_krxiod_transportq);
+				atomic_inc(&rxrpc_krxiod_qcount);
+			}
+		}
+
+		spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock,flags);
+		wake_up_all(&rxrpc_krxiod_sleepq);
+	}
+
+	_leave("");
+
+} /* end rxrpc_krxiod_queue_transport() */
+
+/*****************************************************************************/
+/*
+ * dequeue a transport from krxiod's attention queue
+ */
+void rxrpc_krxiod_dequeue_transport(struct rxrpc_transport *trans)
+{
+	unsigned long flags;
+
+	_enter("");
+
+	spin_lock_irqsave(&rxrpc_krxiod_transportq_lock,flags);
+	if (!list_empty(&trans->krxiodq_link)) {
+		list_del_init(&trans->krxiodq_link);
+		atomic_dec(&rxrpc_krxiod_qcount);
+	}
+	spin_unlock_irqrestore(&rxrpc_krxiod_transportq_lock,flags);
+
+	_leave("");
+
+} /* end rxrpc_krxiod_dequeue_transport() */
+
+/*****************************************************************************/
+/*
+ * queue a call for attention by krxiod
+ */
+void rxrpc_krxiod_queue_call(struct rxrpc_call *call)
+{
+	unsigned long flags;
+
+	if (list_empty(&call->rcv_krxiodq_lk)) {
+		spin_lock_irqsave(&rxrpc_krxiod_callq_lock,flags);
+		if (atomic_read(&call->usage)>0) {
+			list_add_tail(&call->rcv_krxiodq_lk,&rxrpc_krxiod_callq);
+			atomic_inc(&rxrpc_krxiod_qcount);
+		}
+		spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock,flags);
+	}
+	wake_up_all(&rxrpc_krxiod_sleepq);
+	
+} /* end rxrpc_krxiod_queue_call() */
+
+/*****************************************************************************/
+/*
+ * dequeue a call from krxiod's attention queue
+ */
+void rxrpc_krxiod_dequeue_call(struct rxrpc_call *call)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&rxrpc_krxiod_callq_lock,flags);
+	if (!list_empty(&call->rcv_krxiodq_lk)) {
+		list_del_init(&call->rcv_krxiodq_lk);
+		atomic_dec(&rxrpc_krxiod_qcount);
+	}
+	spin_unlock_irqrestore(&rxrpc_krxiod_callq_lock,flags);
+
+} /* end rxrpc_krxiod_dequeue_call() */
diff -Nru a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/krxsecd.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,278 @@
+/* krxsecd.c: Rx security daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This daemon deals with:
+ * - consulting the application as to whether inbound peers and calls should be authorised
+ * - generating security challenges for inbound connections
+ * - responding to security challenges on outbound connections
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <rxrpc/krxsecd.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/message.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/call.h>
+#include <linux/udp.h>
+#include <linux/ip.h>
+#include <net/sock.h>
+#include "internal.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(rxrpc_krxsecd_sleepq);
+static DECLARE_COMPLETION(rxrpc_krxsecd_dead);
+static volatile int rxrpc_krxsecd_die;
+
+static atomic_t rxrpc_krxsecd_qcount;
+
+/* queue of unprocessed inbound messages with seqno #1 and RXRPC_CLIENT_INITIATED flag set */
+static LIST_HEAD(rxrpc_krxsecd_initmsgq);
+static spinlock_t rxrpc_krxsecd_initmsgq_lock = SPIN_LOCK_UNLOCKED;
+
+static void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg);
+
+/*****************************************************************************/
+/*
+ * Rx security daemon
+ */
+static int rxrpc_krxsecd(void *arg)
+{
+	DECLARE_WAITQUEUE(krxsecd,current);
+
+	int die;
+
+	printk("Started krxsecd %d\n",current->pid);
+	strcpy(current->comm,"krxsecd");
+
+	daemonize();
+
+	/* only certain signals are of interest */
+	spin_lock_irq(&current->sig->siglock);
+	siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+	recalc_sigpending();
+#else
+	recalc_sigpending(current);
+#endif
+	spin_unlock_irq(&current->sig->siglock);
+
+	/* loop around waiting for work to do */
+	do {
+		/* wait for work or to be told to exit */
+		_debug("### Begin Wait");
+		if (!atomic_read(&rxrpc_krxsecd_qcount)) {
+			set_current_state(TASK_INTERRUPTIBLE);
+
+			add_wait_queue(&rxrpc_krxsecd_sleepq,&krxsecd);
+
+			for (;;) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				if (atomic_read(&rxrpc_krxsecd_qcount) ||
+				    rxrpc_krxsecd_die ||
+				    signal_pending(current))
+					break;
+
+				schedule();
+			}
+
+			remove_wait_queue(&rxrpc_krxsecd_sleepq,&krxsecd);
+			set_current_state(TASK_RUNNING);
+		}
+		die = rxrpc_krxsecd_die;
+		_debug("### End Wait");
+
+		/* see if there're incoming calls in need of authenticating */
+		_debug("### Begin Inbound Calls");
+
+		if (!list_empty(&rxrpc_krxsecd_initmsgq)) {
+			struct rxrpc_message *msg = NULL;
+
+			spin_lock(&rxrpc_krxsecd_initmsgq_lock);
+
+			if (!list_empty(&rxrpc_krxsecd_initmsgq)) {
+				msg = list_entry(rxrpc_krxsecd_initmsgq.next,
+						 struct rxrpc_message,link);
+				list_del_init(&msg->link);
+				atomic_dec(&rxrpc_krxsecd_qcount);
+			}
+
+			spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
+
+			if (msg) {
+				rxrpc_krxsecd_process_incoming_call(msg);
+				rxrpc_put_message(msg);
+			}
+		}
+
+		_debug("### End Inbound Calls");
+
+                /* discard pending signals */
+		rxrpc_discard_my_signals();
+
+	} while (!die);
+
+	/* and that's all */
+	complete_and_exit(&rxrpc_krxsecd_dead,0);
+
+} /* end rxrpc_krxsecd() */
+
+/*****************************************************************************/
+/*
+ * start up a krxsecd daemon
+ */
+int __init rxrpc_krxsecd_init(void)
+{
+	return kernel_thread(rxrpc_krxsecd,NULL,0);
+
+} /* end rxrpc_krxsecd_init() */
+
+/*****************************************************************************/
+/*
+ * kill the krxsecd daemon and wait for it to complete
+ */
+void rxrpc_krxsecd_kill(void)
+{
+	rxrpc_krxsecd_die = 1;
+	wake_up_all(&rxrpc_krxsecd_sleepq);
+	wait_for_completion(&rxrpc_krxsecd_dead);
+
+} /* end rxrpc_krxsecd_kill() */
+
+/*****************************************************************************/
+/*
+ * clear all pending incoming calls for the specified transport
+ */
+void rxrpc_krxsecd_clear_transport(struct rxrpc_transport *trans)
+{
+	LIST_HEAD(tmp);
+
+	struct rxrpc_message *msg;
+	struct list_head *_p, *_n;
+
+	_enter("%p",trans);
+
+	/* move all the messages for this transport onto a temp list */
+	spin_lock(&rxrpc_krxsecd_initmsgq_lock);
+
+	list_for_each_safe(_p,_n,&rxrpc_krxsecd_initmsgq) {
+		msg = list_entry(_p,struct rxrpc_message,link);
+		if (msg->trans==trans) {
+			list_del(&msg->link);
+			list_add_tail(&msg->link,&tmp);
+			atomic_dec(&rxrpc_krxsecd_qcount);
+		}
+	}
+
+	spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
+
+	/* zap all messages on the temp list */
+	while (!list_empty(&tmp)) {
+		msg = list_entry(tmp.next,struct rxrpc_message,link);
+		list_del_init(&msg->link);
+		rxrpc_put_message(msg);
+	}
+
+	_leave("");
+} /* end rxrpc_krxsecd_clear_transport() */
+
+/*****************************************************************************/
+/*
+ * queue a message on the incoming calls list
+ */
+void rxrpc_krxsecd_queue_incoming_call(struct rxrpc_message *msg)
+{
+	_enter("%p",msg);
+
+	/* queue for processing by krxsecd */
+	spin_lock(&rxrpc_krxsecd_initmsgq_lock);
+
+	if (!rxrpc_krxsecd_die) {
+		rxrpc_get_message(msg);
+		list_add_tail(&msg->link,&rxrpc_krxsecd_initmsgq);
+		atomic_inc(&rxrpc_krxsecd_qcount);
+	}
+
+	spin_unlock(&rxrpc_krxsecd_initmsgq_lock);
+
+	wake_up(&rxrpc_krxsecd_sleepq);
+
+	_leave("");
+} /* end rxrpc_krxsecd_queue_incoming_call() */
+
+/*****************************************************************************/
+/*
+ * process the initial message of an incoming call
+ */
+void rxrpc_krxsecd_process_incoming_call(struct rxrpc_message *msg)
+{
+	struct rxrpc_transport *trans = msg->trans;
+	struct rxrpc_service *srv;
+	struct rxrpc_call *call;
+	struct list_head *_p;
+	unsigned short sid;
+	int ret;
+
+	_enter("%p{tr=%p}",msg,trans);
+
+	ret = rxrpc_incoming_call(msg->conn,msg,&call);
+	if (ret<0)
+		goto out;
+
+	/* find the matching service on the transport */
+	sid = ntohs(msg->hdr.serviceId);
+	srv = NULL;
+
+	spin_lock(&trans->lock);
+	list_for_each(_p,&trans->services) {
+		srv = list_entry(_p,struct rxrpc_service,link);
+		if (srv->service_id==sid && try_inc_mod_count(srv->owner)) {
+			/* found a match (made sure it won't vanish) */
+			_debug("found service '%s'",srv->name);
+			call->owner = srv->owner;
+			break;
+		}
+	}
+	spin_unlock(&trans->lock);
+
+	/* report the new connection
+	 * - the func must inc the call's usage count to keep it
+	 */
+	ret = -ENOENT;
+	if (_p!=&trans->services) {
+		/* attempt to accept the call */
+		call->conn->service = srv;
+		call->app_attn_func = srv->attn_func;
+		call->app_error_func = srv->error_func;
+		call->app_aemap_func = srv->aemap_func;
+
+		ret = srv->new_call(call);
+
+		/* send an abort if an error occurred */
+		if (ret<0) {
+			rxrpc_call_abort(call,ret);
+		}
+		else {
+			/* formally receive and ACK the new packet */
+			ret = rxrpc_conn_receive_call_packet(call->conn,call,msg);
+		}
+	}
+
+	rxrpc_put_call(call);
+ out:
+	if (ret<0)
+		rxrpc_trans_immediate_abort(trans,msg,ret);
+
+	_leave(" (%d)",ret);
+} /* end rxrpc_krxsecd_process_incoming_call() */
diff -Nru a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/krxtimod.c	Tue Oct 15 20:29:24 2002
@@ -0,0 +1,210 @@
+/* krxtimod.c: RXRPC timeout daemon
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/krxtimod.h>
+#include <asm/errno.h>
+#include "internal.h"
+
+static DECLARE_COMPLETION(krxtimod_alive);
+static DECLARE_COMPLETION(krxtimod_dead);
+static DECLARE_WAIT_QUEUE_HEAD(krxtimod_sleepq);
+static int krxtimod_die;
+
+static LIST_HEAD(krxtimod_list);
+static spinlock_t krxtimod_lock = SPIN_LOCK_UNLOCKED;
+
+static int krxtimod(void *arg);
+
+/*****************************************************************************/
+/*
+ * start the timeout daemon
+ */
+int rxrpc_krxtimod_start(void)
+{
+	int ret;
+
+	ret = kernel_thread(krxtimod,NULL,0);
+	if (ret<0)
+		return ret;
+
+	wait_for_completion(&krxtimod_alive);
+
+	return ret;
+} /* end rxrpc_krxtimod_start() */
+
+/*****************************************************************************/
+/*
+ * stop the timeout daemon
+ */
+void rxrpc_krxtimod_kill(void)
+{
+	/* get rid of my daemon */
+	krxtimod_die = 1;
+	wake_up(&krxtimod_sleepq);
+	wait_for_completion(&krxtimod_dead);
+
+} /* end rxrpc_krxtimod_kill() */
+
+/*****************************************************************************/
+/*
+ * timeout processing daemon
+ */
+static int krxtimod(void *arg)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	rxrpc_timer_t *timer;
+
+	printk("Started krxtimod %d\n",current->pid);
+	strcpy(current->comm,"krxtimod");
+
+	daemonize();
+
+	complete(&krxtimod_alive);
+
+	/* only certain signals are of interest */
+	spin_lock_irq(&current->sig->siglock);
+	siginitsetinv(&current->blocked,0);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,3)
+	recalc_sigpending();
+#else
+	recalc_sigpending(current);
+#endif
+	spin_unlock_irq(&current->sig->siglock);
+
+	/* loop around looking for things to attend to */
+ loop:
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&krxtimod_sleepq,&myself);
+
+	for (;;) {
+		unsigned long jif;
+		signed long timeout;
+
+		/* deal with the server being asked to die */
+		if (krxtimod_die) {
+			remove_wait_queue(&krxtimod_sleepq,&myself);
+			_leave("");
+			complete_and_exit(&krxtimod_dead,0);
+		}
+
+		/* discard pending signals */
+		rxrpc_discard_my_signals();
+
+		/* work out the time to elapse before the next event */
+		spin_lock(&krxtimod_lock);
+		if (list_empty(&krxtimod_list)) {
+			timeout = MAX_SCHEDULE_TIMEOUT;
+		}
+		else {
+			timer = list_entry(krxtimod_list.next,rxrpc_timer_t,link);
+			timeout = timer->timo_jif;
+			jif = jiffies;
+
+			if (time_before_eq(timeout,jif))
+				goto immediate;
+
+			else {
+				timeout = (long)timeout - (long)jiffies;
+			}
+		}
+		spin_unlock(&krxtimod_lock);
+
+		schedule_timeout(timeout);
+
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+
+	/* the thing on the front of the queue needs processing
+	 * - we come here with the lock held and timer pointing to the expired entry
+	 */
+ immediate:
+	remove_wait_queue(&krxtimod_sleepq,&myself);
+	set_current_state(TASK_RUNNING);
+
+	_debug("@@@ Begin Timeout of %p",timer);
+
+	/* dequeue the timer */
+	list_del_init(&timer->link);
+	spin_unlock(&krxtimod_lock);
+
+	/* call the timeout function */
+	timer->ops->timed_out(timer);
+
+	_debug("@@@ End Timeout");
+	goto loop;
+
+} /* end krxtimod() */
+
+/*****************************************************************************/
+/*
+ * (re-)queue a timer
+ */
+void rxrpc_krxtimod_add_timer(rxrpc_timer_t *timer, unsigned long timeout)
+{
+	struct list_head *_p;
+	rxrpc_timer_t *ptimer;
+
+	_enter("%p,%lu",timer,timeout);
+
+	spin_lock(&krxtimod_lock);
+
+	list_del(&timer->link);
+
+	/* the timer was deferred or reset - put it back in the queue at the right place */
+	timer->timo_jif = jiffies + timeout;
+
+	list_for_each(_p,&krxtimod_list) {
+		ptimer = list_entry(_p,rxrpc_timer_t,link);
+		if (time_before(timer->timo_jif,ptimer->timo_jif))
+			break;
+	}
+
+	list_add_tail(&timer->link,_p); /* insert before stopping point */
+
+	spin_unlock(&krxtimod_lock);
+
+	wake_up(&krxtimod_sleepq);
+
+	_leave("");
+} /* end rxrpc_krxtimod_queue_vlocation() */
+
+/*****************************************************************************/
+/*
+ * dequeue a timer
+ * - returns 0 if the timer was deleted or -ENOENT if it wasn't queued
+ */
+int rxrpc_krxtimod_del_timer(rxrpc_timer_t *timer)
+{
+	int ret = 0;
+
+	_enter("%p",timer);
+
+	spin_lock(&krxtimod_lock);
+
+	if (list_empty(&timer->link))
+		ret = -ENOENT;
+	else
+		list_del_init(&timer->link);
+
+	spin_unlock(&krxtimod_lock);
+
+	wake_up(&krxtimod_sleepq);
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end rxrpc_krxtimod_del_timer() */
diff -Nru a/net/rxrpc/main.c b/net/rxrpc/main.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/main.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,127 @@
+/* main.c: Rx RPC interface
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/krxiod.h>
+#include <rxrpc/krxsecd.h>
+#include <rxrpc/krxtimod.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include <rxrpc/message.h>
+#include "internal.h"
+
+static int rxrpc_initialise(void);
+static void rxrpc_cleanup(void);
+
+module_init(rxrpc_initialise);
+module_exit(rxrpc_cleanup);
+
+MODULE_DESCRIPTION("Rx RPC implementation");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+u32 rxrpc_epoch;
+
+/*****************************************************************************/
+/*
+ * initialise the Rx module
+ */
+static int rxrpc_initialise(void)
+{
+	int ret;
+
+	/* my epoch value */
+	rxrpc_epoch = htonl(xtime.tv_sec);
+
+	/* register the /proc interface */
+#ifdef CONFIG_PROC_FS
+	ret = rxrpc_proc_init();
+	if (ret<0)
+		return ret;
+#endif
+
+	/* register the sysctl files */
+#ifdef CONFIG_SYSCTL
+	ret = rxrpc_sysctl_init();
+	if (ret<0)
+		goto error_proc;
+#endif
+
+	/* start the krxtimod daemon */
+	ret = rxrpc_krxtimod_start();
+	if (ret<0)
+		goto error_sysctl;
+
+	/* start the krxiod daemon */
+	ret = rxrpc_krxiod_init();
+	if (ret<0)
+		goto error_krxtimod;
+
+	/* start the krxsecd daemon */
+	ret = rxrpc_krxsecd_init();
+	if (ret<0)
+		goto error_krxiod;
+
+	kdebug("\n\n");
+
+	return 0;
+
+ error_krxiod:
+	rxrpc_krxiod_kill();
+ error_krxtimod:
+	rxrpc_krxtimod_kill();
+ error_sysctl:
+#ifdef CONFIG_SYSCTL
+	rxrpc_sysctl_cleanup();
+#endif
+ error_proc:
+#ifdef CONFIG_PROC_FS
+	rxrpc_proc_cleanup();
+#endif
+	return ret;
+} /* end rxrpc_initialise() */
+
+/*****************************************************************************/
+/*
+ * clean up the Rx module
+ */
+static void rxrpc_cleanup(void)
+{
+	kenter("");
+
+	__RXACCT(printk("Outstanding Messages   : %d\n",atomic_read(&rxrpc_message_count)));
+	__RXACCT(printk("Outstanding Calls      : %d\n",atomic_read(&rxrpc_call_count)));
+	__RXACCT(printk("Outstanding Connections: %d\n",atomic_read(&rxrpc_connection_count)));
+	__RXACCT(printk("Outstanding Peers      : %d\n",atomic_read(&rxrpc_peer_count)));
+	__RXACCT(printk("Outstanding Transports : %d\n",atomic_read(&rxrpc_transport_count)));
+
+	rxrpc_krxsecd_kill();
+	rxrpc_krxiod_kill();
+	rxrpc_krxtimod_kill();
+#ifdef CONFIG_SYSCTL
+	rxrpc_sysctl_cleanup();
+#endif
+#ifdef CONFIG_PROC_FS
+	rxrpc_proc_cleanup();
+#endif
+
+	__RXACCT(printk("Outstanding Messages   : %d\n",atomic_read(&rxrpc_message_count)));
+	__RXACCT(printk("Outstanding Calls      : %d\n",atomic_read(&rxrpc_call_count)));
+	__RXACCT(printk("Outstanding Connections: %d\n",atomic_read(&rxrpc_connection_count)));
+	__RXACCT(printk("Outstanding Peers      : %d\n",atomic_read(&rxrpc_peer_count)));
+	__RXACCT(printk("Outstanding Transports : %d\n",atomic_read(&rxrpc_transport_count)));
+
+	kleave();
+} /* end rxrpc_cleanup() */
diff -Nru a/net/rxrpc/peer.c b/net/rxrpc/peer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/peer.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,380 @@
+/* peer.c: Rx RPC peer management
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include <rxrpc/message.h>
+#include <linux/udp.h>
+#include <linux/ip.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+#include "internal.h"
+
+__RXACCT_DECL(atomic_t rxrpc_peer_count);
+LIST_HEAD(rxrpc_peers);
+DECLARE_RWSEM(rxrpc_peers_sem);
+
+static void __rxrpc_peer_timeout(rxrpc_timer_t *timer)
+{
+	struct rxrpc_peer *peer = list_entry(timer,struct rxrpc_peer,timeout);
+
+	_debug("Rx PEER TIMEOUT [%p{u=%d}]",peer,atomic_read(&peer->usage));
+
+	rxrpc_peer_do_timeout(peer);
+}
+
+static const struct rxrpc_timer_ops rxrpc_peer_timer_ops = {
+	.timed_out	= __rxrpc_peer_timeout,
+};
+
+/*****************************************************************************/
+/*
+ * create a peer record
+ */
+static int __rxrpc_create_peer(struct rxrpc_transport *trans, u32 addr, struct rxrpc_peer **_peer)
+{
+	struct rxrpc_peer *peer;
+
+	_enter("%p,%08x",trans,ntohl(addr));
+
+	/* allocate and initialise a peer record */
+	peer = kmalloc(sizeof(struct rxrpc_peer),GFP_KERNEL);
+	if (!peer) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	memset(peer,0,sizeof(struct rxrpc_peer));
+	atomic_set(&peer->usage,1);
+
+	INIT_LIST_HEAD(&peer->link);
+	INIT_LIST_HEAD(&peer->proc_link);
+	INIT_LIST_HEAD(&peer->conn_active);
+	INIT_LIST_HEAD(&peer->conn_graveyard);
+	spin_lock_init(&peer->conn_gylock);
+	init_waitqueue_head(&peer->conn_gy_waitq);
+	rwlock_init(&peer->conn_lock);
+	atomic_set(&peer->conn_count,0);
+	spin_lock_init(&peer->lock);
+	rxrpc_timer_init(&peer->timeout,&rxrpc_peer_timer_ops);
+
+	peer->addr.s_addr = addr;
+
+	peer->trans = trans;
+	peer->ops = trans->peer_ops;
+
+	__RXACCT(atomic_inc(&rxrpc_peer_count));
+	*_peer = peer;
+	_leave(" = 0 (%p)",peer);
+
+	return 0;
+} /* end __rxrpc_create_peer() */
+
+/*****************************************************************************/
+/*
+ * find a peer record on the specified transport
+ * - returns (if successful) with peer record usage incremented
+ * - resurrects it from the graveyard if found there
+ */
+int rxrpc_peer_lookup(struct rxrpc_transport *trans, u32 addr, struct rxrpc_peer **_peer)
+{
+	struct rxrpc_peer *peer, *candidate = NULL;
+	struct list_head *_p;
+	int ret;
+
+	_enter("%p{%hu},%08x",trans,trans->port,ntohl(addr));
+
+	/* [common case] search the transport's active list first */
+	read_lock(&trans->peer_lock);
+	list_for_each(_p,&trans->peer_active) {
+		peer = list_entry(_p,struct rxrpc_peer,link);
+		if (peer->addr.s_addr==addr)
+			goto found_active;
+	}
+	read_unlock(&trans->peer_lock);
+
+	/* [uncommon case] not active - create a candidate for a new record */
+	ret = __rxrpc_create_peer(trans,addr,&candidate);
+	if (ret<0) {
+		_leave(" = %d",ret);
+		return ret;
+	}
+
+	/* search the active list again, just in case it appeared whilst we were busy */
+	write_lock(&trans->peer_lock);
+	list_for_each(_p,&trans->peer_active) {
+		peer = list_entry(_p,struct rxrpc_peer,link);
+		if (peer->addr.s_addr==addr)
+			goto found_active_second_chance;
+	}
+
+	/* search the transport's graveyard list */
+	spin_lock(&trans->peer_gylock);
+	list_for_each(_p,&trans->peer_graveyard) {
+		peer = list_entry(_p,struct rxrpc_peer,link);
+		if (peer->addr.s_addr==addr)
+			goto found_in_graveyard;
+	}
+	spin_unlock(&trans->peer_gylock);
+
+	/* we can now add the new candidate to the list
+	 * - tell the application layer that this peer has been added
+	 */
+	rxrpc_get_transport(trans);
+	peer = candidate;
+	candidate = NULL;
+
+	if (peer->ops && peer->ops->adding) {
+		ret = peer->ops->adding(peer);
+		if (ret<0) {
+			write_unlock(&trans->peer_lock);
+			__RXACCT(atomic_dec(&rxrpc_peer_count));
+			kfree(peer);
+			rxrpc_put_transport(trans);
+			_leave(" = %d",ret);
+			return ret;
+		}
+	}
+
+	atomic_inc(&trans->peer_count);
+
+ make_active:
+	list_add_tail(&peer->link,&trans->peer_active);
+
+ success_uwfree:
+	write_unlock(&trans->peer_lock);
+
+	if (candidate) {
+		__RXACCT(atomic_dec(&rxrpc_peer_count));
+		kfree(candidate);
+	}
+
+	if (list_empty(&peer->proc_link)) {
+		down_write(&rxrpc_peers_sem);
+		list_add_tail(&peer->proc_link,&rxrpc_peers);
+		up_write(&rxrpc_peers_sem);
+	}
+
+ success:
+	*_peer = peer;
+
+	_leave(" = 0 (%p{u=%d cc=%d})",
+	       peer,atomic_read(&peer->usage),atomic_read(&peer->conn_count));
+	return 0;
+
+	/* handle the peer being found in the active list straight off */
+ found_active:
+	rxrpc_get_peer(peer);
+	read_unlock(&trans->peer_lock);
+	goto success;
+
+	/* handle resurrecting a peer from the graveyard */
+ found_in_graveyard:
+	rxrpc_get_peer(peer);
+	rxrpc_get_transport(peer->trans);
+	rxrpc_krxtimod_del_timer(&peer->timeout);
+	list_del_init(&peer->link);
+	spin_unlock(&trans->peer_gylock);
+	goto make_active;
+
+	/* handle finding the peer on the second time through the active list */
+ found_active_second_chance:
+	rxrpc_get_peer(peer);
+	goto success_uwfree;
+
+} /* end rxrpc_peer_lookup() */
+
+/*****************************************************************************/
+/*
+ * finish with a peer record
+ * - it gets sent to the graveyard from where it can be resurrected or timed out
+ */
+void rxrpc_put_peer(struct rxrpc_peer *peer)
+{
+	struct rxrpc_transport *trans = peer->trans;
+
+	_enter("%p{cc=%d a=%08x}",peer,atomic_read(&peer->conn_count),ntohl(peer->addr.s_addr));
+
+	/* sanity check */
+	if (atomic_read(&peer->usage)<=0)
+		BUG();
+
+	write_lock(&trans->peer_lock);
+	spin_lock(&trans->peer_gylock);
+	if (likely(!atomic_dec_and_test(&peer->usage))) {
+		spin_unlock(&trans->peer_gylock);
+		write_unlock(&trans->peer_lock);
+		_leave("");
+		return;
+	}
+
+	/* move to graveyard queue */
+	list_del(&peer->link);
+	write_unlock(&trans->peer_lock);
+
+	list_add_tail(&peer->link,&trans->peer_graveyard);
+
+	if (!list_empty(&peer->conn_active)) BUG();
+
+	/* discard in 600 secs */
+	rxrpc_krxtimod_add_timer(&peer->timeout,100*HZ);
+
+	spin_unlock(&trans->peer_gylock);
+
+	rxrpc_put_transport(trans);
+
+	_leave(" [killed]");
+} /* end rxrpc_put_peer() */
+
+/*****************************************************************************/
+/*
+ * handle a peer timing out in the graveyard
+ * - called from krxtimod
+ */
+void rxrpc_peer_do_timeout(struct rxrpc_peer *peer)
+{
+	struct rxrpc_transport *trans = peer->trans;
+
+	_enter("%p{u=%d cc=%d a=%08x}",
+	       peer,atomic_read(&peer->usage),atomic_read(&peer->conn_count),
+	       ntohl(peer->addr.s_addr));
+
+	if (atomic_read(&peer->usage)<0)
+		BUG();
+
+	/* remove from graveyard if still dead */
+	spin_lock(&trans->peer_gylock);
+	if (atomic_read(&peer->usage)==0)
+		list_del_init(&peer->link);
+	else
+		peer = NULL;
+	spin_unlock(&trans->peer_gylock);
+
+	if (!peer) {
+		_leave("");
+		return; /* resurrected */
+	}
+
+	/* clear all connections on this peer */
+	rxrpc_conn_clearall(peer);
+
+	if (!list_empty(&peer->conn_active)) BUG();
+	if (!list_empty(&peer->conn_graveyard)) BUG();
+
+	/* inform the application layer */
+	if (peer->ops && peer->ops->discarding)
+		peer->ops->discarding(peer);
+
+	if (!list_empty(&peer->proc_link)) {
+		down_write(&rxrpc_peers_sem);
+		list_del(&peer->proc_link);
+		up_write(&rxrpc_peers_sem);
+	}
+
+	__RXACCT(atomic_dec(&rxrpc_peer_count));
+	kfree(peer);
+
+	/* if the graveyard is now empty, wake up anyone waiting for that */
+	if (atomic_dec_and_test(&trans->peer_count))
+		wake_up(&trans->peer_gy_waitq);
+
+	_leave(" [destroyed]");
+} /* end rxrpc_peer_do_timeout() */
+
+/*****************************************************************************/
+/*
+ * clear all peer records from a transport endpoint
+ */
+void rxrpc_peer_clearall(struct rxrpc_transport *trans)
+{
+	DECLARE_WAITQUEUE(myself,current);
+
+	struct rxrpc_peer *peer;
+	int err;
+
+	_enter("%p",trans);
+
+	/* there shouldn't be any active peers remaining */
+	if (!list_empty(&trans->peer_active))
+		BUG();
+
+	/* manually timeout all peers in the graveyard */
+	spin_lock(&trans->peer_gylock);
+	while (!list_empty(&trans->peer_graveyard)) {
+		peer = list_entry(trans->peer_graveyard.next,struct rxrpc_peer,link);
+		_debug("Clearing peer %p\n",peer);
+		err = rxrpc_krxtimod_del_timer(&peer->timeout);
+		spin_unlock(&trans->peer_gylock);
+
+		if (err==0)
+			rxrpc_peer_do_timeout(peer);
+
+		spin_lock(&trans->peer_gylock);
+	}
+	spin_unlock(&trans->peer_gylock);
+
+	/* wait for the the peer graveyard to be completely cleared */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	add_wait_queue(&trans->peer_gy_waitq,&myself);
+
+	while (atomic_read(&trans->peer_count)!=0) {
+		schedule();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+	}
+
+	remove_wait_queue(&trans->peer_gy_waitq,&myself);
+	set_current_state(TASK_RUNNING);
+
+	_leave("");
+
+} /* end rxrpc_peer_clearall() */
+
+/*****************************************************************************/
+/*
+ * calculate and cache the Round-Trip-Time for a message and its response
+ */
+void rxrpc_peer_calculate_rtt(struct rxrpc_peer *peer,
+			      struct rxrpc_message *msg,
+			      struct rxrpc_message *resp)
+{
+	unsigned long long rtt;
+	int loop;
+
+	_enter("%p,%p,%p",peer,msg,resp);
+
+	/* calculate the latest RTT */
+	rtt = resp->stamp.tv_sec - msg->stamp.tv_sec;
+	rtt *= 1000000UL;
+	rtt += resp->stamp.tv_usec - msg->stamp.tv_usec;
+
+	/* add to cache */
+	peer->rtt_cache[peer->rtt_point] = rtt;
+	peer->rtt_point++;
+	peer->rtt_point %= RXRPC_RTT_CACHE_SIZE;
+
+	if (peer->rtt_usage<RXRPC_RTT_CACHE_SIZE) peer->rtt_usage++;
+
+	/* recalculate RTT */
+	for (loop=peer->rtt_usage-1; loop>=0; loop--)
+		rtt += peer->rtt_cache[loop];
+
+	peer->rtt = do_div(rtt,peer->rtt_usage);
+
+	_leave(" RTT=%lu.%lums",peer->rtt/1000,peer->rtt%1000);
+
+} /* end rxrpc_peer_calculate_rtt() */
diff -Nru a/net/rxrpc/proc.c b/net/rxrpc/proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/proc.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,612 @@
+/* proc.c: /proc interface for RxRPC
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <rxrpc/rxrpc.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include <rxrpc/message.h>
+#include "internal.h"
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static inline struct proc_dir_entry *PDE(const struct inode *inode)
+{
+	return (struct proc_dir_entry *)inode->u.generic_ip;
+}
+#endif
+
+static struct proc_dir_entry *proc_rxrpc;
+
+static int rxrpc_proc_transports_open(struct inode *inode, struct file *file);
+static void *rxrpc_proc_transports_start(struct seq_file *p, loff_t *pos);
+static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos);
+static void rxrpc_proc_transports_stop(struct seq_file *p, void *v);
+static int rxrpc_proc_transports_show(struct seq_file *m, void *v);
+
+static struct seq_operations rxrpc_proc_transports_ops = {
+	.start	= rxrpc_proc_transports_start,
+	.next	= rxrpc_proc_transports_next,
+	.stop	= rxrpc_proc_transports_stop,
+	.show	= rxrpc_proc_transports_show,
+};
+
+static struct file_operations rxrpc_proc_transports_fops = {
+	.open		= rxrpc_proc_transports_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int rxrpc_proc_peers_open(struct inode *inode, struct file *file);
+static void *rxrpc_proc_peers_start(struct seq_file *p, loff_t *pos);
+static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos);
+static void rxrpc_proc_peers_stop(struct seq_file *p, void *v);
+static int rxrpc_proc_peers_show(struct seq_file *m, void *v);
+
+static struct seq_operations rxrpc_proc_peers_ops = {
+	.start	= rxrpc_proc_peers_start,
+	.next	= rxrpc_proc_peers_next,
+	.stop	= rxrpc_proc_peers_stop,
+	.show	= rxrpc_proc_peers_show,
+};
+
+static struct file_operations rxrpc_proc_peers_fops = {
+	.open		= rxrpc_proc_peers_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int rxrpc_proc_conns_open(struct inode *inode, struct file *file);
+static void *rxrpc_proc_conns_start(struct seq_file *p, loff_t *pos);
+static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos);
+static void rxrpc_proc_conns_stop(struct seq_file *p, void *v);
+static int rxrpc_proc_conns_show(struct seq_file *m, void *v);
+
+static struct seq_operations rxrpc_proc_conns_ops = {
+	.start	= rxrpc_proc_conns_start,
+	.next	= rxrpc_proc_conns_next,
+	.stop	= rxrpc_proc_conns_stop,
+	.show	= rxrpc_proc_conns_show,
+};
+
+static struct file_operations rxrpc_proc_conns_fops = {
+	.open		= rxrpc_proc_conns_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static int rxrpc_proc_calls_open(struct inode *inode, struct file *file);
+static void *rxrpc_proc_calls_start(struct seq_file *p, loff_t *pos);
+static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos);
+static void rxrpc_proc_calls_stop(struct seq_file *p, void *v);
+static int rxrpc_proc_calls_show(struct seq_file *m, void *v);
+
+static struct seq_operations rxrpc_proc_calls_ops = {
+	.start	= rxrpc_proc_calls_start,
+	.next	= rxrpc_proc_calls_next,
+	.stop	= rxrpc_proc_calls_stop,
+	.show	= rxrpc_proc_calls_show,
+};
+
+static struct file_operations rxrpc_proc_calls_fops = {
+	.open		= rxrpc_proc_calls_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static const char *rxrpc_call_states7[] = {
+	"complet",
+	"error  ",
+	"rcv_op ",
+	"rcv_arg",
+	"got_arg",
+	"snd_rpl",
+	"fin_ack",
+	"snd_arg",
+	"rcv_rpl",
+	"got_rpl"
+};
+
+static const char *rxrpc_call_error_states7[] = {
+	"no_err ",
+	"loc_abt",
+	"rmt_abt",
+	"loc_err",
+	"rmt_err"
+};
+
+/*****************************************************************************/
+/*
+ * initialise the /proc/net/rxrpc/ directory
+ */
+int rxrpc_proc_init(void)
+{
+	struct proc_dir_entry *p;
+
+	proc_rxrpc = proc_mkdir("rxrpc",proc_net);
+	if (!proc_rxrpc)
+		goto error;
+	proc_rxrpc->owner = THIS_MODULE;
+
+	p = create_proc_entry("calls",0,proc_rxrpc);
+	if (!p)
+		goto error_proc;
+	p->proc_fops = &rxrpc_proc_calls_fops;
+	p->owner = THIS_MODULE;
+
+	p = create_proc_entry("connections",0,proc_rxrpc);
+	if (!p)
+		goto error_calls;
+	p->proc_fops = &rxrpc_proc_conns_fops;
+	p->owner = THIS_MODULE;
+
+	p = create_proc_entry("peers",0,proc_rxrpc);
+	if (!p)
+		goto error_calls;
+	p->proc_fops = &rxrpc_proc_peers_fops;
+	p->owner = THIS_MODULE;
+
+	p = create_proc_entry("transports",0,proc_rxrpc);
+	if (!p)
+		goto error_conns;
+	p->proc_fops = &rxrpc_proc_transports_fops;
+	p->owner = THIS_MODULE;
+
+	return 0;
+
+ error_conns:
+	remove_proc_entry("conns",proc_rxrpc);
+ error_calls:
+	remove_proc_entry("calls",proc_rxrpc);
+ error_proc:
+	remove_proc_entry("rxrpc",proc_net);
+ error:
+	return -ENOMEM;
+} /* end rxrpc_proc_init() */
+
+/*****************************************************************************/
+/*
+ * clean up the /proc/net/rxrpc/ directory
+ */
+void rxrpc_proc_cleanup(void)
+{
+	remove_proc_entry("transports",proc_rxrpc);
+	remove_proc_entry("peers",proc_rxrpc);
+	remove_proc_entry("connections",proc_rxrpc);
+	remove_proc_entry("calls",proc_rxrpc);
+
+	remove_proc_entry("rxrpc",proc_net);
+
+} /* end rxrpc_proc_cleanup() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/net/rxrpc/transports" which provides a summary of extant transports
+ */
+static int rxrpc_proc_transports_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *m;
+	int ret;
+
+	ret = seq_open(file,&rxrpc_proc_transports_ops);
+	if (ret<0)
+		return ret;
+
+	m = file->private_data;
+	m->private = PDE(inode)->data;
+
+	return 0;
+} /* end rxrpc_proc_transports_open() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the transports list and return the first item
+ */
+static void *rxrpc_proc_transports_start(struct seq_file *m, loff_t *_pos)
+{
+	struct list_head *_p;
+	loff_t pos = *_pos;
+
+	/* lock the list against modification */
+	down_read(&rxrpc_proc_transports_sem);
+
+	/* allow for the header line */
+	if (!pos)
+		return (void *)1;
+	pos--;
+
+	/* find the n'th element in the list */
+	list_for_each(_p,&rxrpc_proc_transports)
+		if (!pos--)
+			break;
+
+	return _p!=&rxrpc_proc_transports ? _p : NULL;
+} /* end rxrpc_proc_transports_start() */
+
+/*****************************************************************************/
+/*
+ * move to next call in transports list
+ */
+static void *rxrpc_proc_transports_next(struct seq_file *p, void *v, loff_t *pos)
+{
+	struct list_head *_p;
+
+	(*pos)++;
+
+	_p = v;
+	_p = v==(void*)1 ? rxrpc_proc_transports.next : _p->next;
+
+	return _p!=&rxrpc_proc_transports ? _p : NULL;
+} /* end rxrpc_proc_transports_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the transports list
+ */
+static void rxrpc_proc_transports_stop(struct seq_file *p, void *v)
+{
+	up_read(&rxrpc_proc_transports_sem);
+
+} /* end rxrpc_proc_transports_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of call lines
+ */
+static int rxrpc_proc_transports_show(struct seq_file *m, void *v)
+{
+	struct rxrpc_transport *trans = list_entry(v,struct rxrpc_transport,proc_link);
+
+	/* display header on line 1 */
+	if (v == (void *)1) {
+		seq_puts(m, "LOCAL USE\n");
+		return 0;
+	}
+
+	/* display one transport per line on subsequent lines */
+	seq_printf(m,"%5hu %3d\n",
+		   trans->port,
+		   atomic_read(&trans->usage)
+		   );
+
+	return 0;
+} /* end rxrpc_proc_transports_show() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/net/rxrpc/peers" which provides a summary of extant peers
+ */
+static int rxrpc_proc_peers_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *m;
+	int ret;
+
+	ret = seq_open(file,&rxrpc_proc_peers_ops);
+	if (ret<0)
+		return ret;
+
+	m = file->private_data;
+	m->private = PDE(inode)->data;
+
+	return 0;
+} /* end rxrpc_proc_peers_open() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the peers list and return the first item
+ */
+static void *rxrpc_proc_peers_start(struct seq_file *m, loff_t *_pos)
+{
+	struct list_head *_p;
+	loff_t pos = *_pos;
+
+	/* lock the list against modification */
+	down_read(&rxrpc_peers_sem);
+
+	/* allow for the header line */
+	if (!pos)
+		return (void *)1;
+	pos--;
+
+	/* find the n'th element in the list */
+	list_for_each(_p,&rxrpc_peers)
+		if (!pos--)
+			break;
+
+	return _p!=&rxrpc_peers ? _p : NULL;
+} /* end rxrpc_proc_peers_start() */
+
+/*****************************************************************************/
+/*
+ * move to next conn in peers list
+ */
+static void *rxrpc_proc_peers_next(struct seq_file *p, void *v, loff_t *pos)
+{
+	struct list_head *_p;
+
+	(*pos)++;
+
+	_p = v;
+	_p = v==(void*)1 ? rxrpc_peers.next : _p->next;
+
+	return _p!=&rxrpc_peers ? _p : NULL;
+} /* end rxrpc_proc_peers_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the peers list
+ */
+static void rxrpc_proc_peers_stop(struct seq_file *p, void *v)
+{
+	up_read(&rxrpc_peers_sem);
+
+} /* end rxrpc_proc_peers_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of conn lines
+ */
+static int rxrpc_proc_peers_show(struct seq_file *m, void *v)
+{
+	struct rxrpc_peer *peer = list_entry(v,struct rxrpc_peer,proc_link);
+	signed long timeout;
+
+	/* display header on line 1 */
+	if (v == (void *)1) {
+		seq_puts(m,"LOCAL REMOTE   USAGE CONNS  TIMEOUT   MTU RTT(uS)\n");
+		return 0;
+	}
+
+	/* display one peer per line on subsequent lines */
+	timeout = 0;
+	if (!list_empty(&peer->timeout.link))
+		timeout = (signed long)peer->timeout.timo_jif - (signed long)jiffies;
+
+	seq_printf(m,"%5hu %08x %5d %5d %8ld %5u %7lu\n",
+		   peer->trans->port,
+		   ntohl(peer->addr.s_addr),
+		   atomic_read(&peer->usage),
+		   atomic_read(&peer->conn_count),
+		   timeout,
+		   peer->if_mtu,
+		   peer->rtt
+		   );
+
+	return 0;
+} /* end rxrpc_proc_peers_show() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/net/rxrpc/connections" which provides a summary of extant connections
+ */
+static int rxrpc_proc_conns_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *m;
+	int ret;
+
+	ret = seq_open(file,&rxrpc_proc_conns_ops);
+	if (ret<0)
+		return ret;
+
+	m = file->private_data;
+	m->private = PDE(inode)->data;
+
+	return 0;
+} /* end rxrpc_proc_conns_open() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the conns list and return the first item
+ */
+static void *rxrpc_proc_conns_start(struct seq_file *m, loff_t *_pos)
+{
+	struct list_head *_p;
+	loff_t pos = *_pos;
+
+	/* lock the list against modification */
+	down_read(&rxrpc_conns_sem);
+
+	/* allow for the header line */
+	if (!pos)
+		return (void *)1;
+	pos--;
+
+	/* find the n'th element in the list */
+	list_for_each(_p,&rxrpc_conns)
+		if (!pos--)
+			break;
+
+	return _p!=&rxrpc_conns ? _p : NULL;
+} /* end rxrpc_proc_conns_start() */
+
+/*****************************************************************************/
+/*
+ * move to next conn in conns list
+ */
+static void *rxrpc_proc_conns_next(struct seq_file *p, void *v, loff_t *pos)
+{
+	struct list_head *_p;
+
+	(*pos)++;
+
+	_p = v;
+	_p = v==(void*)1 ? rxrpc_conns.next : _p->next;
+
+	return _p!=&rxrpc_conns ? _p : NULL;
+} /* end rxrpc_proc_conns_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the conns list
+ */
+static void rxrpc_proc_conns_stop(struct seq_file *p, void *v)
+{
+	up_read(&rxrpc_conns_sem);
+
+} /* end rxrpc_proc_conns_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of conn lines
+ */
+static int rxrpc_proc_conns_show(struct seq_file *m, void *v)
+{
+	struct rxrpc_connection *conn = list_entry(v,struct rxrpc_connection,proc_link);
+	signed long timeout;
+
+	/* display header on line 1 */
+	if (v == (void *)1) {
+		seq_puts(m,
+			 "LOCAL REMOTE   RPORT SRVC CONN     END SERIALNO CALLNO     MTU  TIMEOUT"
+			 "\n");
+		return 0;
+	}
+
+	/* display one conn per line on subsequent lines */
+	timeout = 0;
+	if (!list_empty(&conn->timeout.link))
+		timeout = (signed long)conn->timeout.timo_jif - (signed long)jiffies;
+
+	seq_printf(m,"%5hu %08x %5hu %04hx %08x %-3.3s %08x %08x %5u %8ld\n",
+		   conn->trans->port,
+		   ntohl(conn->addr.sin_addr.s_addr),
+		   ntohs(conn->addr.sin_port),
+		   ntohs(conn->service_id),
+		   ntohl(conn->conn_id),
+		   conn->out_clientflag ? "CLT" : "SRV",
+		   conn->serial_counter,
+		   conn->call_counter,
+		   conn->mtu_size,
+		   timeout
+		   );
+
+	return 0;
+} /* end rxrpc_proc_conns_show() */
+
+/*****************************************************************************/
+/*
+ * open "/proc/net/rxrpc/calls" which provides a summary of extant calls
+ */
+static int rxrpc_proc_calls_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *m;
+	int ret;
+
+	ret = seq_open(file,&rxrpc_proc_calls_ops);
+	if (ret<0)
+		return ret;
+
+	m = file->private_data;
+	m->private = PDE(inode)->data;
+
+	return 0;
+} /* end rxrpc_proc_calls_open() */
+
+/*****************************************************************************/
+/*
+ * set up the iterator to start reading from the calls list and return the first item
+ */
+static void *rxrpc_proc_calls_start(struct seq_file *m, loff_t *_pos)
+{
+	struct list_head *_p;
+	loff_t pos = *_pos;
+
+	/* lock the list against modification */
+	down_read(&rxrpc_calls_sem);
+
+	/* allow for the header line */
+	if (!pos)
+		return (void *)1;
+	pos--;
+
+	/* find the n'th element in the list */
+	list_for_each(_p,&rxrpc_calls)
+		if (!pos--)
+			break;
+
+	return _p!=&rxrpc_calls ? _p : NULL;
+} /* end rxrpc_proc_calls_start() */
+
+/*****************************************************************************/
+/*
+ * move to next call in calls list
+ */
+static void *rxrpc_proc_calls_next(struct seq_file *p, void *v, loff_t *pos)
+{
+	struct list_head *_p;
+
+	(*pos)++;
+
+	_p = v;
+	_p = v==(void*)1 ? rxrpc_calls.next : _p->next;
+
+	return _p!=&rxrpc_calls ? _p : NULL;
+} /* end rxrpc_proc_calls_next() */
+
+/*****************************************************************************/
+/*
+ * clean up after reading from the calls list
+ */
+static void rxrpc_proc_calls_stop(struct seq_file *p, void *v)
+{
+	up_read(&rxrpc_calls_sem);
+
+} /* end rxrpc_proc_calls_stop() */
+
+/*****************************************************************************/
+/*
+ * display a header line followed by a load of call lines
+ */
+static int rxrpc_proc_calls_show(struct seq_file *m, void *v)
+{
+	struct rxrpc_call *call = list_entry(v,struct rxrpc_call,call_link);
+
+	/* display header on line 1 */
+	if (v == (void *)1) {
+		seq_puts(m,
+			 "LOCAL REMOT SRVC CONN     CALL     DIR USE "
+			 " L STATE   OPCODE ABORT    ERRNO\n"
+			 );
+		return 0;
+	}
+
+	/* display one call per line on subsequent lines */
+	seq_printf(m,
+		   "%5hu %5hu %04hx %08x %08x %s %3u%c"
+		   " %c %-7.7s %6d %08x %5d\n",
+		   call->conn->trans->port,
+		   ntohs(call->conn->addr.sin_port),
+		   ntohs(call->conn->service_id),
+		   ntohl(call->conn->conn_id),
+		   ntohl(call->call_id),
+		   call->conn->service ? "SVC" : "CLT",
+		   atomic_read(&call->usage),
+		   waitqueue_active(&call->waitq) ? 'w' : ' ',
+		   call->app_last_rcv ? 'Y' : '-',
+		   (call->app_call_state!=RXRPC_CSTATE_ERROR ?
+		    rxrpc_call_states7[call->app_call_state] :
+		    rxrpc_call_error_states7[call->app_err_state]),
+		   call->app_opcode,
+		   call->app_abort_code,
+		   call->app_errno
+		   );
+
+	return 0;
+} /* end rxrpc_proc_calls_show() */
diff -Nru a/net/rxrpc/rxrpc_syms.c b/net/rxrpc/rxrpc_syms.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/rxrpc_syms.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,51 @@
+/* rxrpc_syms.c: exported Rx RPC layer interface symbols
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <rxrpc/transport.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include <rxrpc/krxiod.h>
+
+/* call.c */
+EXPORT_SYMBOL(rxrpc_call_rcv_timeout);
+EXPORT_SYMBOL(rxrpc_call_acks_timeout);
+EXPORT_SYMBOL(rxrpc_call_dfr_ack_timeout);
+EXPORT_SYMBOL(rxrpc_call_max_resend);
+EXPORT_SYMBOL(rxrpc_call_states);
+EXPORT_SYMBOL(rxrpc_call_error_states);
+
+EXPORT_SYMBOL(rxrpc_create_call);
+EXPORT_SYMBOL(rxrpc_incoming_call);
+EXPORT_SYMBOL(rxrpc_put_call);
+EXPORT_SYMBOL(rxrpc_call_abort);
+EXPORT_SYMBOL(rxrpc_call_read_data);
+EXPORT_SYMBOL(rxrpc_call_write_data);
+EXPORT_SYMBOL(rxrpc_call_flush);
+
+/* connection.c */
+EXPORT_SYMBOL(rxrpc_create_connection);
+EXPORT_SYMBOL(rxrpc_put_connection);
+
+/* sysctl.c */
+EXPORT_SYMBOL(rxrpc_ktrace);
+EXPORT_SYMBOL(rxrpc_kdebug);
+EXPORT_SYMBOL(rxrpc_kproto);
+EXPORT_SYMBOL(rxrpc_knet);
+
+/* transport.c */
+EXPORT_SYMBOL(rxrpc_create_transport);
+EXPORT_SYMBOL(rxrpc_clear_transport);
+EXPORT_SYMBOL(rxrpc_put_transport);
+EXPORT_SYMBOL(rxrpc_add_service);
+EXPORT_SYMBOL(rxrpc_del_service);
diff -Nru a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/sysctl.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,73 @@
+/* sysctl.c: Rx RPC control
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/sysctl.h>
+#include <linux/config.h>
+#include <rxrpc/types.h>
+#include <rxrpc/rxrpc.h>
+#include <asm/errno.h>
+#include "internal.h"
+
+int rxrpc_ktrace;
+int rxrpc_kdebug;
+int rxrpc_kproto;
+int rxrpc_knet;
+
+#ifdef CONFIG_SYSCTL
+static struct ctl_table_header *rxrpc_sysctl = NULL;
+
+static ctl_table rxrpc_sysctl_table[] = {
+        { 1, "kdebug", &rxrpc_kdebug, sizeof(int), 0644, NULL, &proc_dointvec },
+        { 2, "ktrace", &rxrpc_ktrace, sizeof(int), 0644, NULL, &proc_dointvec },
+        { 3, "kproto", &rxrpc_kproto, sizeof(int), 0644, NULL, &proc_dointvec },
+        { 4, "knet",   &rxrpc_knet,   sizeof(int), 0644, NULL, &proc_dointvec },
+	{ 0 }
+};
+
+static ctl_table rxrpc_dir_sysctl_table[] = {
+	{ 1, "rxrpc", NULL, 0, 0555, rxrpc_sysctl_table },
+	{ 0 }
+};
+#endif /* CONFIG_SYSCTL */
+
+/*****************************************************************************/
+/*
+ * initialise the sysctl stuff for Rx RPC
+ */
+int rxrpc_sysctl_init(void)
+{
+#ifdef CONFIG_SYSCTL
+	rxrpc_sysctl = register_sysctl_table(rxrpc_dir_sysctl_table,0);
+	if (!rxrpc_sysctl)
+		return -ENOMEM;
+#endif /* CONFIG_SYSCTL */
+
+	return 0;
+} /* end rxrpc_sysctl_init() */
+
+/*****************************************************************************/
+/*
+ * clean up the sysctl stuff for Rx RPC
+ */
+void rxrpc_sysctl_cleanup(void)
+{
+#ifdef CONFIG_SYSCTL
+	if (rxrpc_sysctl) {
+		unregister_sysctl_table(rxrpc_sysctl);
+		rxrpc_sysctl = NULL;
+	}
+#endif /* CONFIG_SYSCTL */
+
+} /* end rxrpc_sysctl_cleanup() */
diff -Nru a/net/rxrpc/transport.c b/net/rxrpc/transport.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/rxrpc/transport.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,824 @@
+/* transport.c: Rx Transport routines
+ *
+ * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <rxrpc/transport.h>
+#include <rxrpc/peer.h>
+#include <rxrpc/connection.h>
+#include <rxrpc/call.h>
+#include <rxrpc/message.h>
+#include <rxrpc/krxiod.h>
+#include <rxrpc/krxsecd.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/icmp.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+#include <linux/ipv6.h>	/* this should _really_ be in errqueue.h.. */
+#endif
+#include <linux/errqueue.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include "internal.h"
+
+struct errormsg {
+	struct cmsghdr			cmsg;		/* control message header */
+	struct sock_extended_err	ee;		/* extended error information */
+	struct sockaddr_in		icmp_src;	/* ICMP packet source address */
+};
+
+static spinlock_t rxrpc_transports_lock = SPIN_LOCK_UNLOCKED;
+static struct list_head rxrpc_transports = LIST_HEAD_INIT(rxrpc_transports);
+
+__RXACCT_DECL(atomic_t rxrpc_transport_count);
+LIST_HEAD(rxrpc_proc_transports);
+DECLARE_RWSEM(rxrpc_proc_transports_sem);
+
+static void rxrpc_data_ready(struct sock *sk, int count);
+static void rxrpc_error_report(struct sock *sk);
+static int rxrpc_trans_receive_new_call(struct rxrpc_transport *trans,
+					struct list_head *msgq);
+static void rxrpc_trans_receive_error_report(struct rxrpc_transport *trans);
+
+/*****************************************************************************/
+/*
+ * create a new transport endpoint using the specified UDP port
+ */
+int rxrpc_create_transport(unsigned short port, struct rxrpc_transport **_trans)
+{
+	struct rxrpc_transport *trans;
+	struct sockaddr_in sin;
+	mm_segment_t oldfs;
+	struct sock *sock;
+	int ret, opt;
+
+	_enter("%hu",port);
+
+	trans = kmalloc(sizeof(struct rxrpc_transport),GFP_KERNEL);
+	if (!trans)
+		return -ENOMEM;
+
+	memset(trans,0,sizeof(struct rxrpc_transport));
+	atomic_set(&trans->usage,1);
+	INIT_LIST_HEAD(&trans->services);
+	INIT_LIST_HEAD(&trans->link);
+	INIT_LIST_HEAD(&trans->krxiodq_link);
+	spin_lock_init(&trans->lock);
+	INIT_LIST_HEAD(&trans->peer_active);
+	INIT_LIST_HEAD(&trans->peer_graveyard);
+	spin_lock_init(&trans->peer_gylock);
+	init_waitqueue_head(&trans->peer_gy_waitq);
+	rwlock_init(&trans->peer_lock);
+	atomic_set(&trans->peer_count,0);
+	trans->port = port;
+
+	/* create a UDP socket to be my actual transport endpoint */
+	ret = sock_create(PF_INET,SOCK_DGRAM,IPPROTO_UDP,&trans->socket);
+	if (ret<0)
+		goto error;
+
+	/* use the specified port */
+	if (port) {
+		memset(&sin,0,sizeof(sin));
+		sin.sin_family = AF_INET;
+		sin.sin_port = htons(port);
+		ret = trans->socket->ops->bind(trans->socket,(struct sockaddr *)&sin,sizeof(sin));
+		if (ret<0)
+			goto error;
+	}
+
+	opt = 1;
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = trans->socket->ops->setsockopt(trans->socket,SOL_IP,IP_RECVERR,
+					     (char*)&opt,sizeof(opt));
+	set_fs(oldfs);
+
+	spin_lock(&rxrpc_transports_lock);
+	list_add(&trans->link,&rxrpc_transports);
+	spin_unlock(&rxrpc_transports_lock);
+
+	/* set the socket up */
+	sock = trans->socket->sk;
+	sock->user_data = trans;
+	sock->data_ready = rxrpc_data_ready;
+	sock->error_report = rxrpc_error_report;
+
+	down_write(&rxrpc_proc_transports_sem);
+	list_add_tail(&trans->proc_link,&rxrpc_proc_transports);
+	up_write(&rxrpc_proc_transports_sem);
+
+	__RXACCT(atomic_inc(&rxrpc_transport_count));
+
+	*_trans = trans;
+	_leave(" = 0 (%p)",trans);
+	return 0;
+
+ error:
+	rxrpc_put_transport(trans);
+
+	_leave(" = %d",ret);
+
+	return ret;
+
+} /* end rxrpc_create_transport() */
+
+/*****************************************************************************/
+/*
+ * clear the connections on a transport endpoint
+ */
+void rxrpc_clear_transport(struct rxrpc_transport *trans)
+{
+	//struct rxrpc_connection *conn;
+
+} /* end rxrpc_clear_transport() */
+
+/*****************************************************************************/
+/*
+ * destroy a transport endpoint
+ */
+void rxrpc_put_transport(struct rxrpc_transport *trans)
+{
+	_enter("%p{u=%d p=%hu}",trans,atomic_read(&trans->usage),trans->port);
+
+	if (atomic_read(&trans->usage)<=0)
+		BUG();
+
+	/* to prevent a race, the decrement and the dequeue must be effectively atomic */
+	spin_lock(&rxrpc_transports_lock);
+	if (likely(!atomic_dec_and_test(&trans->usage))) {
+		spin_unlock(&rxrpc_transports_lock);
+		_leave("");
+		return;
+	}
+
+	list_del(&trans->link);
+	spin_unlock(&rxrpc_transports_lock);
+
+	/* finish cleaning up the transport */
+	if (trans->socket)
+		trans->socket->ops->shutdown(trans->socket,2);
+
+	rxrpc_krxsecd_clear_transport(trans);
+	rxrpc_krxiod_dequeue_transport(trans);
+
+	/* discard all peer information */
+	rxrpc_peer_clearall(trans);
+
+	down_write(&rxrpc_proc_transports_sem);
+	list_del(&trans->proc_link);
+	up_write(&rxrpc_proc_transports_sem);
+	__RXACCT(atomic_dec(&rxrpc_transport_count));
+
+	/* close the socket */
+	if (trans->socket) {
+		trans->socket->sk->user_data = NULL;
+		sock_release(trans->socket);
+		trans->socket = NULL;
+	}
+
+	kfree(trans);
+
+	_leave("");
+
+} /* end rxrpc_put_transport() */
+
+/*****************************************************************************/
+/*
+ * add a service to a transport to be listened upon
+ */
+int rxrpc_add_service(struct rxrpc_transport *trans, struct rxrpc_service *newsrv)
+{
+	struct rxrpc_service *srv;
+	struct list_head *_p;
+	int ret = -EEXIST;
+
+	_enter("%p{%hu},%p{%hu}",trans,trans->port,newsrv,newsrv->service_id);
+
+	/* verify that the service ID is not already present */
+	spin_lock(&trans->lock);
+
+	list_for_each(_p,&trans->services) {
+		srv = list_entry(_p,struct rxrpc_service,link);
+		if (srv->service_id==newsrv->service_id)
+			goto out;
+	}
+
+	/* okay - add the transport to the list */
+	list_add_tail(&newsrv->link,&trans->services);
+	rxrpc_get_transport(trans);
+	ret = 0;
+
+ out:
+	spin_unlock(&trans->lock);
+
+	_leave("= %d",ret);
+	return ret;
+
+} /* end rxrpc_add_service() */
+
+/*****************************************************************************/
+/*
+ * remove a service from a transport
+ */
+void rxrpc_del_service(struct rxrpc_transport *trans, struct rxrpc_service *srv)
+{
+	_enter("%p{%hu},%p{%hu}",trans,trans->port,srv,srv->service_id);
+
+	spin_lock(&trans->lock);
+	list_del(&srv->link);
+	spin_unlock(&trans->lock);
+
+	rxrpc_put_transport(trans);
+
+	_leave("");
+
+} /* end rxrpc_del_service() */
+
+/*****************************************************************************/
+/*
+ * INET callback when data has been received on the socket.
+ */
+static void rxrpc_data_ready(struct sock *sk, int count)
+{
+	struct rxrpc_transport *trans;
+
+	_enter("%p{t=%p},%d",sk,sk->user_data,count);
+
+	/* queue the transport for attention by krxiod */
+	trans = (struct rxrpc_transport *) sk->user_data;
+	if (trans)
+		rxrpc_krxiod_queue_transport(trans);
+
+	/* wake up anyone waiting on the socket */
+	if (sk->sleep && waitqueue_active(sk->sleep))
+		wake_up_interruptible(sk->sleep);
+
+	_leave("");
+
+} /* end rxrpc_data_ready() */
+
+/*****************************************************************************/
+/*
+ * INET callback when an ICMP error packet is received
+ * - sk->err is error (EHOSTUNREACH, EPROTO or EMSGSIZE)
+ */
+static void rxrpc_error_report(struct sock *sk)
+{
+	struct rxrpc_transport *trans;
+
+	_enter("%p{t=%p}",sk,sk->user_data);
+
+	/* queue the transport for attention by krxiod */
+	trans = (struct rxrpc_transport *) sk->user_data;
+	if (trans) {
+		trans->error_rcvd = 1;
+		rxrpc_krxiod_queue_transport(trans);
+	}
+
+	/* wake up anyone waiting on the socket */
+	if (sk->sleep && waitqueue_active(sk->sleep))
+		wake_up_interruptible(sk->sleep);
+
+	_leave("");
+
+} /* end rxrpc_error_report() */
+
+/*****************************************************************************/
+/*
+ * split a message up, allocating message records and filling them in from the contents of a
+ * socket buffer
+ */
+static int rxrpc_incoming_msg(struct rxrpc_transport *trans,
+			      struct sk_buff *pkt,
+			      struct list_head *msgq)
+{
+	struct rxrpc_message *msg;
+	int ret;
+
+	_enter("");
+
+	msg = kmalloc(sizeof(struct rxrpc_message),GFP_KERNEL);
+	if (!msg) {
+		_leave(" = -ENOMEM");
+		return -ENOMEM;
+	}
+
+	memset(msg,0,sizeof(*msg));
+	atomic_set(&msg->usage,1);
+	list_add_tail(&msg->link,msgq);
+
+	/* dig out the Rx routing parameters */
+	if (skb_copy_bits(pkt,sizeof(struct udphdr),&msg->hdr,sizeof(msg->hdr))<0) {
+		ret = -EBADMSG;
+		goto error;
+	}
+
+	msg->trans = trans;
+	msg->state = RXRPC_MSG_RECEIVED;
+	msg->stamp = pkt->stamp;
+	msg->seq = ntohl(msg->hdr.seq);
+
+	/* attach the packet */
+	skb_get(pkt);
+	msg->pkt = pkt;
+
+	msg->offset = sizeof(struct udphdr) + sizeof(struct rxrpc_header);
+	msg->dsize = msg->pkt->len - msg->offset;
+
+	_net("Rx Received packet from %s (%08x;%08x,%1x,%d,%s,%02x,%d,%d)",
+	     msg->hdr.flags & RXRPC_CLIENT_INITIATED ? "client" : "server",
+	     ntohl(msg->hdr.epoch),
+	     (ntohl(msg->hdr.cid) & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT,
+	     ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK,
+	     ntohl(msg->hdr.callNumber),
+	     rxrpc_pkts[msg->hdr.type],
+	     msg->hdr.flags,
+	     ntohs(msg->hdr.serviceId),
+	     msg->hdr.securityIndex);
+
+	__RXACCT(atomic_inc(&rxrpc_message_count));
+
+	/* split off jumbo packets */
+	while (msg->hdr.type==RXRPC_PACKET_TYPE_DATA && msg->hdr.flags & RXRPC_JUMBO_PACKET) {
+		struct rxrpc_jumbo_header jumbo;
+		struct rxrpc_message *jumbomsg = msg;
+
+		_debug("split jumbo packet");
+
+		/* quick sanity check */
+		ret = -EBADMSG;
+		if (msg->dsize < RXRPC_JUMBO_DATALEN+sizeof(struct rxrpc_jumbo_header))
+			goto error;
+		if (msg->hdr.flags & RXRPC_LAST_PACKET)
+			goto error;
+
+		/* dig out the secondary header */
+		if (skb_copy_bits(pkt,msg->offset+RXRPC_JUMBO_DATALEN,&jumbo,sizeof(jumbo))<0)
+			goto error;
+
+		/* allocate a new message record */
+		ret = -ENOMEM;
+		msg = kmalloc(sizeof(struct rxrpc_message),GFP_KERNEL);
+		if (!msg)
+			goto error;
+
+		memcpy(msg,jumbomsg,sizeof(*msg));
+		list_add_tail(&msg->link,msgq);
+
+		/* adjust the jumbo packet */
+		jumbomsg->dsize = RXRPC_JUMBO_DATALEN;
+
+		/* attach the packet here too */
+		skb_get(pkt);
+
+		/* adjust the parameters */
+		msg->seq++;
+		msg->hdr.seq = htonl(msg->seq);
+		msg->hdr.serial = htonl(ntohl(msg->hdr.serial) + 1);
+		msg->offset += RXRPC_JUMBO_DATALEN + sizeof(struct rxrpc_jumbo_header);
+		msg->dsize -= RXRPC_JUMBO_DATALEN + sizeof(struct rxrpc_jumbo_header);
+		msg->hdr.flags = jumbo.flags;
+		msg->hdr._rsvd = jumbo._rsvd;
+
+		_net("Rx Split jumbo packet from %s (%08x;%08x,%1x,%d,%s,%02x,%d,%d)",
+		     msg->hdr.flags & RXRPC_CLIENT_INITIATED ? "client" : "server",
+		     ntohl(msg->hdr.epoch),
+		     (ntohl(msg->hdr.cid) & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT,
+		     ntohl(msg->hdr.cid) & RXRPC_CHANNELMASK,
+		     ntohl(msg->hdr.callNumber),
+		     rxrpc_pkts[msg->hdr.type],
+		     msg->hdr.flags,
+		     ntohs(msg->hdr.serviceId),
+		     msg->hdr.securityIndex);
+
+		__RXACCT(atomic_inc(&rxrpc_message_count));
+	}
+
+	_leave(" = 0 #%d",atomic_read(&rxrpc_message_count));
+	return 0;
+
+ error:
+	while (!list_empty(msgq)) {
+		msg = list_entry(msgq->next,struct rxrpc_message,link);
+		list_del_init(&msg->link);
+
+		rxrpc_put_message(msg);
+	}
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end rxrpc_incoming_msg() */
+
+/*****************************************************************************/
+/*
+ * accept a new call
+ * - called from krxiod in process context
+ */
+void rxrpc_trans_receive_packet(struct rxrpc_transport *trans)
+{
+	struct rxrpc_message *msg;
+	struct rxrpc_peer *peer;
+	struct sk_buff *pkt;
+	int ret;
+	u32 addr;
+	u16 port;
+
+	LIST_HEAD(msgq);
+
+	_enter("%p{%d}",trans,trans->port);
+
+	for (;;) {
+		/* deal with outstanting errors first */
+		if (trans->error_rcvd)
+			rxrpc_trans_receive_error_report(trans);
+
+		/* attempt to receive a packet */
+		pkt = skb_recv_datagram(trans->socket->sk,0,1,&ret);
+		if (!pkt) {
+			if (ret==-EAGAIN) {
+				_leave(" EAGAIN");
+				return;
+			}
+
+			/* an icmp error may have occurred */
+			rxrpc_krxiod_queue_transport(trans);
+			_leave(" error %d\n",ret);
+			return;
+		}
+
+		/* we'll probably need to checksum it (didn't call sock_recvmsg) */
+		if (pkt->ip_summed != CHECKSUM_UNNECESSARY) {
+			if ((unsigned short)csum_fold(skb_checksum(pkt,0,pkt->len,pkt->csum))) {
+				kfree_skb(pkt);
+				rxrpc_krxiod_queue_transport(trans);
+				_leave(" CSUM failed");
+				return;
+			}
+		}
+
+		addr = pkt->nh.iph->saddr;
+		port = pkt->h.uh->source;
+
+		_net("Rx Received UDP packet from %08x:%04hu",ntohl(addr),ntohs(port));
+
+		/* unmarshall the Rx parameters and split jumbo packets */
+		ret = rxrpc_incoming_msg(trans,pkt,&msgq);
+		if (ret<0) {
+			kfree_skb(pkt);
+			rxrpc_krxiod_queue_transport(trans);
+			_leave(" bad packet");
+			return;
+		}
+
+		if (list_empty(&msgq)) BUG();
+
+		msg = list_entry(msgq.next,struct rxrpc_message,link);
+
+		/* locate the record for the peer from which it originated */
+		ret = rxrpc_peer_lookup(trans,addr,&peer);
+		if (ret<0) {
+			kdebug("Rx No connections from that peer");
+			rxrpc_trans_immediate_abort(trans,msg,-EINVAL);
+			goto finished_msg;
+		}
+
+		/* try and find a matching connection */
+		ret = rxrpc_connection_lookup(peer,msg,&msg->conn);
+		if (ret<0) {
+			kdebug("Rx Unknown Connection");
+			rxrpc_trans_immediate_abort(trans,msg,-EINVAL);
+			rxrpc_put_peer(peer);
+			goto finished_msg;
+		}
+		rxrpc_put_peer(peer);
+
+		/* deal with the first packet of a new call */
+		if (msg->hdr.flags & RXRPC_CLIENT_INITIATED &&
+		    msg->hdr.type==RXRPC_PACKET_TYPE_DATA &&
+		    ntohl(msg->hdr.seq)==1
+		    ) {
+			_debug("Rx New server call");
+			rxrpc_trans_receive_new_call(trans,&msgq);
+			goto finished_msg;
+		}
+
+		/* deal with subsequent packet(s) of call */
+		_debug("Rx Call packet");
+		while (!list_empty(&msgq)) {
+			msg = list_entry(msgq.next,struct rxrpc_message,link);
+			list_del_init(&msg->link);
+
+			ret = rxrpc_conn_receive_call_packet(msg->conn,NULL,msg);
+			if (ret<0) {
+				rxrpc_trans_immediate_abort(trans,msg,ret);
+				rxrpc_put_message(msg);
+				goto finished_msg;
+			}
+
+			rxrpc_put_message(msg);
+		}
+
+		goto finished_msg;
+
+		/* dispose of the packets */
+	finished_msg:
+		while (!list_empty(&msgq)) {
+			msg = list_entry(msgq.next,struct rxrpc_message,link);
+			list_del_init(&msg->link);
+
+			rxrpc_put_message(msg);
+		}
+		kfree_skb(pkt);
+	}
+
+	_leave("");
+
+} /* end rxrpc_trans_receive_packet() */
+
+/*****************************************************************************/
+/*
+ * accept a new call from a client trying to connect to one of my services
+ * - called in process context
+ */
+static int rxrpc_trans_receive_new_call(struct rxrpc_transport *trans,
+					struct list_head *msgq)
+{
+	struct rxrpc_message *msg;
+
+	_enter("");
+
+	/* only bother with the first packet */
+	msg = list_entry(msgq->next,struct rxrpc_message,link);
+	list_del_init(&msg->link);
+	rxrpc_krxsecd_queue_incoming_call(msg);
+	rxrpc_put_message(msg);
+
+	_leave(" = 0");
+
+	return 0;
+} /* end rxrpc_trans_receive_new_call() */
+
+/*****************************************************************************/
+/*
+ * perform an immediate abort without connection or call structures
+ */
+int rxrpc_trans_immediate_abort(struct rxrpc_transport *trans,
+				struct rxrpc_message *msg,
+				int error)
+{
+	struct rxrpc_header ahdr;
+	struct sockaddr_in sin;
+	struct msghdr msghdr;
+	struct iovec iov[2];
+	mm_segment_t oldfs;
+	int len, ret;
+	u32 _error;
+
+	_enter("%p,%p,%d",trans,msg,error);
+
+	/* don't abort an abort packet */
+	if (msg->hdr.type==RXRPC_PACKET_TYPE_ABORT) {
+		_leave(" = 0");
+		return 0;
+	}
+
+	_error = htonl(-error);
+
+	/* set up the message to be transmitted */
+	memcpy(&ahdr,&msg->hdr,sizeof(ahdr));
+	ahdr.epoch	= msg->hdr.epoch;
+	ahdr.serial	= htonl(1);
+	ahdr.seq	= 0;
+	ahdr.type	= RXRPC_PACKET_TYPE_ABORT;
+	ahdr.flags	= RXRPC_LAST_PACKET | (~msg->hdr.flags & RXRPC_CLIENT_INITIATED);
+
+	iov[0].iov_len	= sizeof(ahdr);
+	iov[0].iov_base	= &ahdr;
+	iov[1].iov_len	= sizeof(_error);
+	iov[1].iov_base	= &_error;
+
+	len = sizeof(ahdr) + sizeof(_error);
+
+	memset(&sin,0,sizeof(sin));
+	sin.sin_family		= AF_INET;
+	sin.sin_port		= msg->pkt->h.uh->source;
+	sin.sin_addr.s_addr	= msg->pkt->nh.iph->saddr;
+
+	msghdr.msg_name		= &sin;
+	msghdr.msg_namelen	= sizeof(sin);
+	msghdr.msg_iov		= iov;
+	msghdr.msg_iovlen	= 2;
+	msghdr.msg_control	= NULL;
+	msghdr.msg_controllen	= 0;
+	msghdr.msg_flags	= MSG_DONTWAIT;
+
+	_net("Sending message type %d of %d bytes to %08x:%d",
+	     ahdr.type,
+	     len,
+	     htonl(sin.sin_addr.s_addr),
+	     htons(sin.sin_port));
+
+	/* send the message */
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sock_sendmsg(trans->socket,&msghdr,len);
+	set_fs(oldfs);
+
+	_leave(" = %d",ret);
+	return ret;
+} /* end rxrpc_trans_immediate_abort() */
+
+/*****************************************************************************/
+/*
+ * receive an ICMP error report and percolate it to all connections heading to the affected
+ * host or port
+ */
+static void rxrpc_trans_receive_error_report(struct rxrpc_transport *trans)
+{
+	struct rxrpc_connection *conn;
+	struct sockaddr_in sin;
+	struct rxrpc_peer *peer;
+	struct list_head connq, *_p;
+	struct errormsg emsg;
+	struct msghdr msg;
+	mm_segment_t oldfs;
+	int local, err;
+	u16 port;
+
+	_enter("%p",trans);
+
+	for (;;) {
+		trans->error_rcvd = 0;
+
+		/* try and receive an error message */
+		msg.msg_name	= &sin;
+		msg.msg_namelen	= sizeof(sin);
+		msg.msg_iov	= NULL;
+		msg.msg_iovlen	= 0;
+		msg.msg_control	= &emsg;
+		msg.msg_controllen = sizeof(emsg);
+		msg.msg_flags	= 0;
+
+		oldfs = get_fs();
+		set_fs(KERNEL_DS);
+		err = sock_recvmsg(trans->socket,&msg,0,MSG_ERRQUEUE|MSG_DONTWAIT|MSG_TRUNC);
+		set_fs(oldfs);
+
+		if (err==-EAGAIN) {
+			_leave("");
+			return;
+		}
+
+		if (err<0) {
+			printk("%s: unable to recv an error report: %d\n",__FUNCTION__,err);
+			_leave("");
+			return;
+		}
+
+		msg.msg_controllen = (char*)msg.msg_control - (char*)&emsg;
+
+		if (msg.msg_controllen<sizeof(emsg.cmsg) || msg.msg_namelen<sizeof(sin)) {
+			printk("%s: short control message (nlen=%u clen=%u fl=%x)\n",
+			       __FUNCTION__,msg.msg_namelen,msg.msg_controllen,msg.msg_flags);
+			continue;
+		}
+
+		_net("Rx Received control message { len=%u level=%u type=%u }",
+		     emsg.cmsg.cmsg_len,emsg.cmsg.cmsg_level,emsg.cmsg.cmsg_type);
+
+		if (sin.sin_family!=AF_INET) {
+			printk("Rx Ignoring error report with non-INET address (fam=%u)",
+			       sin.sin_family);
+			continue;
+		}
+
+		_net("Rx Received message pertaining to host addr=%x port=%hu",
+		     ntohl(sin.sin_addr.s_addr),ntohs(sin.sin_port));
+
+		if (emsg.cmsg.cmsg_level!=SOL_IP || emsg.cmsg.cmsg_type!=IP_RECVERR) {
+			printk("Rx Ignoring unknown error report { level=%u type=%u }",
+			       emsg.cmsg.cmsg_level,emsg.cmsg.cmsg_type);
+			continue;
+		}
+
+		if (msg.msg_controllen<sizeof(emsg.cmsg)+sizeof(emsg.ee)) {
+			printk("%s: short error message (%u)\n",__FUNCTION__,msg.msg_controllen);
+			_leave("");
+			return;
+		}
+
+		port = sin.sin_port;
+
+		switch (emsg.ee.ee_origin) {
+		case SO_EE_ORIGIN_ICMP:
+			local = 0;
+			switch (emsg.ee.ee_type) {
+			case ICMP_DEST_UNREACH:
+				switch (emsg.ee.ee_code) {
+				case ICMP_NET_UNREACH:
+					_net("Rx Received ICMP Network Unreachable");
+					port = 0;
+					err = -ENETUNREACH;
+					break;
+				case ICMP_HOST_UNREACH:
+					_net("Rx Received ICMP Host Unreachable");
+					port = 0;
+					err = -EHOSTUNREACH;
+					break;
+				case ICMP_PORT_UNREACH:
+					_net("Rx Received ICMP Port Unreachable");
+					err = -ECONNREFUSED;
+					break;
+				case ICMP_NET_UNKNOWN:
+					_net("Rx Received ICMP Unknown Network");
+					port = 0;
+					err = -ENETUNREACH;
+					break;
+				case ICMP_HOST_UNKNOWN:
+					_net("Rx Received ICMP Unknown Host");
+					port = 0;
+					err = -EHOSTUNREACH;
+					break;
+				default:
+					_net("Rx Received ICMP DestUnreach { code=%u }",
+					     emsg.ee.ee_code);
+					err = emsg.ee.ee_errno;
+					break;
+				}
+				break;
+
+			case ICMP_TIME_EXCEEDED:
+				_net("Rx Received ICMP TTL Exceeded");
+				err = emsg.ee.ee_errno;
+				break;
+
+			default:
+				_proto("Rx Received ICMP error { type=%u code=%u }",
+				       emsg.ee.ee_type,emsg.ee.ee_code);
+				err = emsg.ee.ee_errno;
+				break;
+			}
+			break;
+
+		case SO_EE_ORIGIN_LOCAL:
+			_proto("Rx Received local error { error=%d }",emsg.ee.ee_errno);
+			local = 1;
+			err = emsg.ee.ee_errno;
+			break;
+
+		case SO_EE_ORIGIN_NONE:
+		case SO_EE_ORIGIN_ICMP6:
+		default:
+			_proto("Rx Received error report { orig=%u }",emsg.ee.ee_origin);
+			local = 0;
+			err = emsg.ee.ee_errno;
+			break;
+		}
+
+		/* find all the connections between this transport and the affected destination */
+		INIT_LIST_HEAD(&connq);
+
+		if (rxrpc_peer_lookup(trans,sin.sin_addr.s_addr,&peer)==0) {
+			read_lock(&peer->conn_lock);
+			list_for_each(_p,&peer->conn_active) {
+				conn = list_entry(_p,struct rxrpc_connection,link);
+				if (port && conn->addr.sin_port!=port)
+					continue;
+				if (!list_empty(&conn->err_link))
+					continue;
+
+				rxrpc_get_connection(conn);
+				list_add_tail(&conn->err_link,&connq);
+			}
+			read_unlock(&peer->conn_lock);
+
+			/* service all those connections */
+			while (!list_empty(&connq)) {
+				conn = list_entry(connq.next,struct rxrpc_connection,err_link);
+				list_del(&conn->err_link);
+
+				rxrpc_conn_handle_error(conn,local,err);
+
+				rxrpc_put_connection(conn);
+			}
+
+			rxrpc_put_peer(peer);
+		}
+	}
+
+	_leave("");
+	return;
+} /* end rxrpc_trans_receive_error_report() */
diff -Nru a/net/sched/cls_route.c b/net/sched/cls_route.c
--- a/net/sched/cls_route.c	Tue Oct 15 20:29:15 2002
+++ b/net/sched/cls_route.c	Tue Oct 15 20:29:15 2002
@@ -154,7 +154,7 @@
 	if (head == NULL)
 		goto old_method;
 
-	iif = ((struct rtable*)dst)->key.iif;
+	iif = ((struct rtable*)dst)->fl.iif;
 
 	h = route4_fastmap_hash(id, iif);
 	if (id == head->fastmap[h].id &&
diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c
--- a/net/sctp/protocol.c	Tue Oct 15 20:29:17 2002
+++ b/net/sctp/protocol.c	Tue Oct 15 20:29:17 2002
@@ -260,16 +260,10 @@
 {
 	int dst_mtu = SCTP_DEFAULT_MAXSEGMENT;
 	struct rtable *rt;
-	struct rt_key key = {
-		.dst   = address->v4.sin_addr.s_addr,
-		.src   = 0,
-		.iif   = 0,
-		.oif   = 0,
-		.tos   = 0,
-		.scope = 0
-	};
+	struct flowi fl = { .nl_u = { .ip4_u =
+				      { .daddr = address->v4.sin_addr.s_addr } } };
 
-	if (ip_route_output_key(&rt, &key)) {
+	if (ip_route_output_key(&rt, &fl)) {
 		SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key"
 				  " failed, returning %d as dst_mtu\n",
 				  dst_mtu);
diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c
--- a/net/sctp/socket.c	Tue Oct 15 20:29:23 2002
+++ b/net/sctp/socket.c	Tue Oct 15 20:29:23 2002
@@ -733,7 +733,8 @@
 
 SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);
 
-SCTP_STATIC int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
+SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
+			     struct msghdr *msg, int size)
 {
 	sctp_opt_t *sp;
 	sctp_endpoint_t *ep;
@@ -1098,8 +1099,8 @@
  */
 static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
 
-SCTP_STATIC int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
-			     int noblock, int flags, int *addr_len)
+SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+			     int len, int noblock, int flags, int *addr_len)
 {
 	sctp_ulpevent_t *event = NULL;
 	sctp_opt_t *sp = sctp_sk(sk);
diff -Nru a/net/socket.c b/net/socket.c
--- a/net/socket.c	Tue Oct 15 20:29:16 2002
+++ b/net/socket.c	Tue Oct 15 20:29:16 2002
@@ -90,10 +90,10 @@
 #include <linux/netfilter.h>
 
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
-static ssize_t sock_read(struct file *file, char *buf,
-			 size_t size, loff_t *ppos);
-static ssize_t sock_write(struct file *file, const char *buf,
-			  size_t size, loff_t *ppos);
+static ssize_t sock_aio_read(struct kiocb *iocb, char *buf,
+			 size_t size, loff_t pos);
+static ssize_t sock_aio_write(struct kiocb *iocb, const char *buf,
+			  size_t size, loff_t pos);
 static int sock_mmap(struct file *file, struct vm_area_struct * vma);
 
 static int sock_close(struct inode *inode, struct file *file);
@@ -117,8 +117,8 @@
 
 static struct file_operations socket_file_ops = {
 	.llseek =	no_llseek,
-	.read =		sock_read,
-	.write =	sock_write,
+	.aio_read =	sock_aio_read,
+	.aio_write =	sock_aio_write,
 	.poll =		sock_poll,
 	.ioctl =	sock_ioctl,
 	.mmap =		sock_mmap,
@@ -517,64 +517,100 @@
 	sock->file=NULL;
 }
 
-int sock_sendmsg(struct socket *sock, struct msghdr *msg, int size)
+static int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int size)
 {
+	struct sock_iocb *si = kiocb_to_siocb(iocb);
 	int err;
-	struct scm_cookie scm;
 
-	err = scm_send(sock, msg, &scm);
+	si->scm = &si->async_scm;
+	si->sock = sock;
+	si->msg = msg;
+	si->size = size;
+
+	err = scm_send(sock, msg, si->scm);
 	if (err >= 0) {
-		err = sock->ops->sendmsg(sock, msg, size, &scm);
-		scm_destroy(&scm);
+		err = sock->ops->sendmsg(iocb, sock, msg, size, si->scm);
+		if (-EIOCBQUEUED != err)
+			scm_destroy(si->scm);
 	}
 	return err;
 }
 
-int sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags)
+int sock_sendmsg(struct socket *sock, struct msghdr *msg, int size)
 {
-	struct scm_cookie scm;
+	struct kiocb iocb;
+	int ret;
+
+	init_sync_kiocb(&iocb, NULL);
+	ret = __sock_sendmsg(&iocb, sock, msg, size);
+	if (-EIOCBQUEUED == ret)
+		ret = wait_on_sync_kiocb(&iocb);
+	return ret;
+}
 
-	memset(&scm, 0, sizeof(scm));
 
-	size = sock->ops->recvmsg(sock, msg, size, flags, &scm);
+int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, int size, int flags)
+{
+	struct sock_iocb *si = kiocb_to_siocb(iocb);
+
+	si->sock = sock;
+	si->scm = &si->async_scm;
+	si->sock = sock;
+	si->msg = msg;
+	si->size = size;
+	si->flags = flags;
+
+	memset(si->scm, 0, sizeof(*si->scm));
+
+	size = sock->ops->recvmsg(iocb, sock, msg, size, flags, si->scm);
 	if (size >= 0)
-		scm_recv(sock, msg, &scm, flags);
+		scm_recv(sock, msg, si->scm, flags);
 
 	return size;
 }
 
+int sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags)
+{
+	struct kiocb iocb;
+	int ret;
+
+        init_sync_kiocb(&iocb, NULL);
+	ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
+	if (-EIOCBQUEUED == ret)
+		ret = wait_on_sync_kiocb(&iocb);
+	return ret;
+}
 
 /*
  *	Read data from a socket. ubuf is a user mode pointer. We make sure the user
  *	area ubuf...ubuf+size-1 is writable before asking the protocol.
  */
 
-static ssize_t sock_read(struct file *file, char *ubuf,
-			 size_t size, loff_t *ppos)
+static ssize_t sock_aio_read(struct kiocb *iocb, char *ubuf,
+			 size_t size, loff_t pos)
 {
+	struct sock_iocb *x = kiocb_to_siocb(iocb);
 	struct socket *sock;
-	struct iovec iov;
-	struct msghdr msg;
 	int flags;
 
-	if (ppos != &file->f_pos)
+	if (pos != 0)
 		return -ESPIPE;
 	if (size==0)		/* Match SYS5 behaviour */
 		return 0;
 
-	sock = SOCKET_I(file->f_dentry->d_inode); 
+	sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode); 
 
-	msg.msg_name=NULL;
-	msg.msg_namelen=0;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	msg.msg_control=NULL;
-	msg.msg_controllen=0;
-	iov.iov_base=ubuf;
-	iov.iov_len=size;
-	flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
+	x->async_msg.msg_name = NULL;
+	x->async_msg.msg_namelen = 0;
+	x->async_msg.msg_iov = &x->async_iov;
+	x->async_msg.msg_iovlen = 1;
+	x->async_msg.msg_control = NULL;
+	x->async_msg.msg_controllen = 0;
+	x->async_iov.iov_base = ubuf;
+	x->async_iov.iov_len = size;
+	flags = !(iocb->ki_filp->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
 
-	return sock_recvmsg(sock, &msg, size, flags);
+	return __sock_recvmsg(iocb, sock, &x->async_msg, size, flags);
 }
 
 
@@ -583,33 +619,32 @@
  *	is readable by the user process.
  */
 
-static ssize_t sock_write(struct file *file, const char *ubuf,
-			  size_t size, loff_t *ppos)
+static ssize_t sock_aio_write(struct kiocb *iocb, const char *ubuf,
+			  size_t size, loff_t pos)
 {
+	struct sock_iocb *x = kiocb_to_siocb(iocb);
 	struct socket *sock;
-	struct msghdr msg;
-	struct iovec iov;
 	
-	if (ppos != &file->f_pos)
+	if (pos != 0)
 		return -ESPIPE;
 	if(size==0)		/* Match SYS5 behaviour */
 		return 0;
 
-	sock = SOCKET_I(file->f_dentry->d_inode); 
+	sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode); 
 
-	msg.msg_name=NULL;
-	msg.msg_namelen=0;
-	msg.msg_iov=&iov;
-	msg.msg_iovlen=1;
-	msg.msg_control=NULL;
-	msg.msg_controllen=0;
-	msg.msg_flags=!(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
+	x->async_msg.msg_name = NULL;
+	x->async_msg.msg_namelen = 0;
+	x->async_msg.msg_iov = &x->async_iov;
+	x->async_msg.msg_iovlen = 1;
+	x->async_msg.msg_control = NULL;
+	x->async_msg.msg_controllen = 0;
+	x->async_msg.msg_flags = !(iocb->ki_filp->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
 	if (sock->type == SOCK_SEQPACKET)
-		msg.msg_flags |= MSG_EOR;
-	iov.iov_base=(void *)ubuf;
-	iov.iov_len=size;
+		x->async_msg.msg_flags |= MSG_EOR;
+	x->async_iov.iov_base = (void *)ubuf;
+	x->async_iov.iov_len = size;
 	
-	return sock_sendmsg(sock, &msg, size);
+	return __sock_sendmsg(iocb, sock, &x->async_msg, size);
 }
 
 ssize_t sock_sendpage(struct file *file, struct page *page,
@@ -691,9 +726,11 @@
 
 	unlock_kernel();
 	sock = SOCKET_I(inode);
+#ifdef CONFIG_NET
 	if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
 		err = dev_ioctl(cmd, (void *)arg);
 	} else
+#endif  /* CONFIG_NET */
 #ifdef WIRELESS_EXT
 	if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
 		err = dev_ioctl(cmd, (void *)arg);
diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c	Tue Oct 15 20:29:17 2002
+++ b/net/unix/af_unix.c	Tue Oct 15 20:29:17 2002
@@ -1175,7 +1175,8 @@
  *	Send AF_UNIX data.
  */
 
-static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+static int unix_dgram_sendmsg(struct kiocb *iocb, struct socket *sock,
+			      struct msghdr *msg, int len,
 			      struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1307,7 +1308,8 @@
 }
 
 		
-static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+static int unix_stream_sendmsg(struct kiocb *iocb, struct socket *sock,
+			       struct msghdr *msg, int len,
 			       struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1415,7 +1417,8 @@
 	}
 }
 
-static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
+			      struct msghdr *msg, int size,
 			      int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1517,7 +1520,8 @@
 
 
 
-static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
+			       struct msghdr *msg, int size,
 			       int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
diff -Nru a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c
--- a/net/wanrouter/af_wanpipe.c	Tue Oct 15 20:29:22 2002
+++ b/net/wanrouter/af_wanpipe.c	Tue Oct 15 20:29:22 2002
@@ -540,8 +540,8 @@
  *      a packet is queued into sk->write_queue.
  *===========================================================*/
 
-static int wanpipe_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-			  struct scm_cookie *scm)
+static int wanpipe_sendmsg(struct kiocb *iocb, struct socket *sock,
+			   struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	wanpipe_opt *wp;
 	struct sock *sk = sock->sk;
@@ -1647,8 +1647,9 @@
  *      to the user. If necessary we block.
  *===========================================================*/
 
-static int wanpipe_recvmsg(struct socket *sock, struct msghdr *msg, int len,
-			  int flags, struct scm_cookie *scm)
+static int wanpipe_recvmsg(struct kiocb *iocb, struct socket *sock,
+			   struct msghdr *msg, int len, int flags,
+			   struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct sk_buff *skb;
diff -Nru a/net/x25/af_x25.c b/net/x25/af_x25.c
--- a/net/x25/af_x25.c	Tue Oct 15 20:29:22 2002
+++ b/net/x25/af_x25.c	Tue Oct 15 20:29:22 2002
@@ -916,8 +916,8 @@
 	goto out;
 }
 
-static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
-		       struct scm_cookie *scm)
+static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
+		       struct msghdr *msg, int len, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
 	struct x25_opt *x25 = x25_sk(sk);
@@ -1091,7 +1091,8 @@
 }
 
 
-static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+static int x25_recvmsg(struct kiocb *iocb, struct socket *sock,
+		       struct msghdr *msg, int size,
 		       int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
diff -Nru a/sound/core/control.c b/sound/core/control.c
--- a/sound/core/control.c	Tue Oct 15 20:29:12 2002
+++ b/sound/core/control.c	Tue Oct 15 20:29:12 2002
@@ -426,52 +426,59 @@
 
 static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *_control)
 {
-	snd_ctl_elem_value_t control;
+	snd_ctl_elem_value_t *control;
 	snd_kcontrol_t *kctl;
 	int result, indirect;
 	
-	if (copy_from_user(&control, _control, sizeof(control)))
+	control = kmalloc(sizeof(*control), GFP_KERNEL);
+	if (control == NULL)
+		return -ENOMEM;	
+	if (copy_from_user(control, _control, sizeof(*control)))
 		return -EFAULT;
 	read_lock(&card->control_rwlock);
-	kctl = snd_ctl_find_id(card, &control.id);
+	kctl = snd_ctl_find_id(card, &control->id);
 	if (kctl == NULL) {
 		result = -ENOENT;
 	} else {
 		indirect = kctl->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
-		if (control.indirect != indirect) {
+		if (control->indirect != indirect) {
 			result = -EACCES;
 		} else {
 			if ((kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) {
-				result = kctl->get(kctl, &control);
+				result = kctl->get(kctl, control);
 				if (result >= 0)
-					control.id = kctl->id;
+					control->id = kctl->id;
 			} else
 				result = -EPERM;
 		}
 	}
 	read_unlock(&card->control_rwlock);
 	if (result >= 0)
-		if (copy_to_user(_control, &control, sizeof(control)))
+		if (copy_to_user(_control, control, sizeof(*control)))
 			return -EFAULT;
+	kfree(control);
 	return result;
 }
 
 static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t *_control)
 {
 	snd_card_t *card = file->card;
-	snd_ctl_elem_value_t control;
+	snd_ctl_elem_value_t *control;
 	snd_kcontrol_t *kctl;
 	int result, indirect;
-	
-	if (copy_from_user(&control, _control, sizeof(control)))
+
+	control = kmalloc(sizeof(*control), GFP_KERNEL);
+	if (control == NULL)
+		return -ENOMEM;	
+	if (copy_from_user(control, _control, sizeof(*control)))
 		return -EFAULT;
 	read_lock(&card->control_rwlock);
-	kctl = snd_ctl_find_id(card, &control.id);
+	kctl = snd_ctl_find_id(card, &control->id);
 	if (kctl == NULL) {
 		result = -ENOENT;
 	} else {
 		indirect = kctl->access & SNDRV_CTL_ELEM_ACCESS_INDIRECT ? 1 : 0;
-		if (control.indirect != indirect) {
+		if (control->indirect != indirect) {
 			result = -EACCES;
 		} else {
 			read_lock(&card->control_owner_lock);
@@ -480,9 +487,9 @@
 			    (kctl->owner != NULL && kctl->owner != file)) {
 				result = -EPERM;
 			} else {
-				result = kctl->put(kctl, &control);
+				result = kctl->put(kctl, control);
 				if (result >= 0)
-					control.id = kctl->id;
+					control->id = kctl->id;
 			}
 			read_unlock(&card->control_owner_lock);
 			if (result > 0) {
@@ -496,8 +503,9 @@
 	read_unlock(&card->control_rwlock);
       __unlocked:
 	if (result >= 0)
-		if (copy_to_user(_control, &control, sizeof(control)))
+		if (copy_to_user(_control, control, sizeof(*control)))
 			return -EFAULT;
+	kfree(control);
 	return result;
 }
 
diff -Nru a/sound/core/info_oss.c b/sound/core/info_oss.c
--- a/sound/core/info_oss.c	Tue Oct 15 20:29:12 2002
+++ b/sound/core/info_oss.c	Tue Oct 15 20:29:12 2002
@@ -28,7 +28,7 @@
 #include <sound/version.h>
 #include <linux/utsname.h>
 
-#ifdef CONFIG_SND_OSSEMUL
+#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
 
 /*
  *  OSS compatible part
diff -Nru a/sound/core/init.c b/sound/core/init.c
--- a/sound/core/init.c	Tue Oct 15 20:29:12 2002
+++ b/sound/core/init.c	Tue Oct 15 20:29:12 2002
@@ -216,7 +216,7 @@
 		snd_iprintf(buffer, "--- no soundcards ---\n");
 }
 
-#ifdef CONFIG_SND_OSSEMUL
+#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
 
 void snd_card_info_read_oss(snd_info_buffer_t * buffer)
 {
diff -Nru a/sound/core/ioctl32/ioctl32.c b/sound/core/ioctl32/ioctl32.c
--- a/sound/core/ioctl32/ioctl32.c	Tue Oct 15 20:29:12 2002
+++ b/sound/core/ioctl32/ioctl32.c	Tue Oct 15 20:29:12 2002
@@ -23,6 +23,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/time.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <sound/core.h>
 #include <sound/control.h>
@@ -264,46 +265,56 @@
 
 static int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
 {
-	// too big?
-	struct sndrv_ctl_elem_value data;
-	struct sndrv_ctl_elem_value32 data32;
+	struct sndrv_ctl_elem_value *data;
+	struct sndrv_ctl_elem_value32 *data32;
 	int err, i;
 	int type;
 	mm_segment_t oldseg;
 
 	/* FIXME: check the sane ioctl.. */
 
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
-		return -EFAULT;
-	memset(&data, 0, sizeof(data));
-	data.id = data32.id;
-	data.indirect = data32.indirect;
-	if (data.indirect) /* FIXME: this is not correct for long arrays */
-		data.value.integer.value_ptr = (void*)TO_PTR(data32.value.integer.value_ptr);
-	type = get_ctl_type(file, &data.id);
-	if (type < 0)
-		return type;
-	if (! data.indirect) {
+	data = kmalloc(sizeof(*data), GFP_KERNEL);
+	data32 = kmalloc(sizeof(*data32), GFP_KERNEL);
+	if (data == NULL || data32 == NULL) {
+		err = -ENOMEM;
+		goto __end;
+	}
+
+	if (copy_from_user(data32, (void*)arg, sizeof(*data32))) {
+		err = -EFAULT;
+		goto __end;
+	}
+	memset(data, 0, sizeof(*data));
+	data->id = data32->id;
+	data->indirect = data32->indirect;
+	if (data->indirect) /* FIXME: this is not correct for long arrays */
+		data->value.integer.value_ptr = (void*)TO_PTR(data32->value.integer.value_ptr);
+	type = get_ctl_type(file, &data->id);
+	if (type < 0) {
+		err = type;
+		goto __end;
+	}
+	if (! data->indirect) {
 		switch (type) {
 		case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
 		case SNDRV_CTL_ELEM_TYPE_INTEGER:
 			for (i = 0; i < 128; i++)
-				data.value.integer.value[i] = data32.value.integer.value[i];
+				data->value.integer.value[i] = data32->value.integer.value[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_INTEGER64:
 			for (i = 0; i < 64; i++)
-				data.value.integer64.value[i] = data32.value.integer64.value[i];
+				data->value.integer64.value[i] = data32->value.integer64.value[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
 			for (i = 0; i < 128; i++)
-				data.value.enumerated.item[i] = data32.value.enumerated.item[i];
+				data->value.enumerated.item[i] = data32->value.enumerated.item[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_BYTES:
-			memcpy(data.value.bytes.data, data32.value.bytes.data,
-			       sizeof(data.value.bytes.data));
+			memcpy(data->value.bytes.data, data32->value.bytes.data,
+			       sizeof(data->value.bytes.data));
 			break;
 		case SNDRV_CTL_ELEM_TYPE_IEC958:
-			data.value.iec958 = data32.value.iec958;
+			data->value.iec958 = data32->value.iec958;
 			break;
 		default:
 			printk("unknown type %d\n", type);
@@ -313,40 +324,46 @@
 
 	oldseg = get_fs();
 	set_fs(KERNEL_DS);
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
 	set_fs(oldseg);
 	if (err < 0)
-		return err;
+		goto __end;
 	/* restore info to 32bit */
-	if (! data.indirect) {
+	if (! data->indirect) {
 		switch (type) {
 		case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
 		case SNDRV_CTL_ELEM_TYPE_INTEGER:
 			for (i = 0; i < 128; i++)
-				data32.value.integer.value[i] = data.value.integer.value[i];
+				data32->value.integer.value[i] = data->value.integer.value[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_INTEGER64:
 			for (i = 0; i < 64; i++)
-				data32.value.integer64.value[i] = data.value.integer64.value[i];
+				data32->value.integer64.value[i] = data->value.integer64.value[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
 			for (i = 0; i < 128; i++)
-				data32.value.enumerated.item[i] = data.value.enumerated.item[i];
+				data32->value.enumerated.item[i] = data->value.enumerated.item[i];
 			break;
 		case SNDRV_CTL_ELEM_TYPE_BYTES:
-			memcpy(data32.value.bytes.data, data.value.bytes.data,
-			       sizeof(data.value.bytes.data));
+			memcpy(data32->value.bytes.data, data->value.bytes.data,
+			       sizeof(data->value.bytes.data));
 			break;
 		case SNDRV_CTL_ELEM_TYPE_IEC958:
-			data32.value.iec958 = data.value.iec958;
+			data32->value.iec958 = data->value.iec958;
 			break;
 		default:
 			break;
 		}
 	}
-	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
-		return -EFAULT;
-	return 0;
+	err = 0;
+	if (copy_to_user((void*)arg, data32, sizeof(*data32)))
+		err = -EFAULT;
+      __end:
+      	if (data32)
+      		kfree(data32);
+	if (data)
+		kfree(data);
+	return err;
 }
 
 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);
diff -Nru a/sound/core/ioctl32/ioctl32.h b/sound/core/ioctl32/ioctl32.h
--- a/sound/core/ioctl32/ioctl32.h	Tue Oct 15 20:29:16 2002
+++ b/sound/core/ioctl32/ioctl32.h	Tue Oct 15 20:29:16 2002
@@ -79,6 +79,44 @@
 	return 0;\
 }
 
+#define DEFINE_ALSA_IOCTL_BIG(type) \
+static int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)\
+{\
+	struct sndrv_##type##32 *data32;\
+	struct sndrv_##type *data;\
+	mm_segment_t oldseg;\
+	int err;\
+	data32 = kmalloc(sizeof(*data32), GFP_KERNEL); \
+	data = kmalloc(sizeof(*data), GFP_KERNEL); \
+	if (data32 == NULL || data == NULL) { \
+		err = -ENOMEM; \
+		goto __end; \
+	}\
+	if (copy_from_user(data32, (void*)arg, sizeof(*data32))) { \
+		err = -EFAULT; \
+		goto __end; \
+	}\
+	memset(data, 0, sizeof(*data));\
+	convert_from_32(type, data, data32);\
+	oldseg = get_fs();\
+	set_fs(KERNEL_DS);\
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);\
+	if (err < 0) \
+		goto __end;\
+	err = 0;\
+	if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\
+		convert_to_32(type, data32, data);\
+		if (copy_to_user((void*)arg, data32, sizeof(*data32)))\
+			err = -EFAULT;\
+	}\
+      __end:\
+      	if (data)\
+      		kfree(data);\
+      	if (data32)\
+      		kfree(data32);\
+	return err;\
+}
+
 #define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \
 static int snd_ioctl32_##name(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file) {\
 	return _snd_ioctl32_##type(fd, cmd, arg, file, native_ctl);\
diff -Nru a/sound/core/ioctl32/pcm32.c b/sound/core/ioctl32/pcm32.c
--- a/sound/core/ioctl32/pcm32.c	Tue Oct 15 20:29:17 2002
+++ b/sound/core/ioctl32/pcm32.c	Tue Oct 15 20:29:17 2002
@@ -20,6 +20,7 @@
 
 #include <sound/driver.h>
 #include <linux/time.h>
+#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include "ioctl32.h"
@@ -172,7 +173,7 @@
 
 DEFINE_ALSA_IOCTL(pcm_uframes_str);
 DEFINE_ALSA_IOCTL(pcm_sframes_str);
-DEFINE_ALSA_IOCTL(pcm_hw_params);
+DEFINE_ALSA_IOCTL_BIG(pcm_hw_params);
 DEFINE_ALSA_IOCTL(pcm_sw_params);
 DEFINE_ALSA_IOCTL(pcm_channel_info);
 DEFINE_ALSA_IOCTL(pcm_status);
@@ -230,7 +231,7 @@
 	snd_pcm_file_t *pcm_file;
 	snd_pcm_substream_t *substream;
 	struct sndrv_xfern32 data32, *srcptr = (struct sndrv_xfern32*)arg;
-	void *bufs[128];
+	void **bufs = NULL;
 	int err = 0, ch, i;
 	u32 *bufptr;
 	mm_segment_t oldseg;
@@ -260,6 +261,9 @@
 		return -EFAULT;
 	__get_user(data32.bufs, &srcptr->bufs);
 	bufptr = (u32*)TO_PTR(data32.bufs);
+	bufs = kmalloc(sizeof(void *) * 128, GFP_KERNEL);
+	if (bufs == NULL)
+		return -ENOMEM;
 	for (i = 0; i < ch; i++) {
 		u32 ptr;
 		if (get_user(ptr, bufptr))
@@ -278,10 +282,11 @@
 		break;
 	}
 	set_fs(oldseg);
-	if (err < 0)
-		return err;
-	if (put_user(err, &srcptr->result))
-		return -EFAULT;
+	if (err >= 0) {
+		if (put_user(err, &srcptr->result))
+			err = -EFAULT;
+	}
+	kfree(bufs);
 	return 0;
 }
 
@@ -343,24 +348,38 @@
 
 static int _snd_ioctl32_pcm_hw_params_old(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
 {
-	struct sndrv_pcm_hw_params_old32 data32;
-	struct sndrv_pcm_hw_params data;
+	struct sndrv_pcm_hw_params_old32 *data32;
+	struct sndrv_pcm_hw_params *data;
 	mm_segment_t oldseg;
 	int err;
 
-	if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
-		return -EFAULT;
-	snd_pcm_hw_convert_from_old_params(&data, &data32);
+	data32 = snd_kcalloc(sizeof(*data32), GFP_KERNEL);
+	data = snd_kcalloc(sizeof(*data), GFP_KERNEL);
+	if (data32 == NULL || data == NULL) {
+		err = -ENOMEM;
+		goto __end;
+	}
+	if (copy_from_user(data32, (void*)arg, sizeof(*data32))) {
+		err = -EFAULT;
+		goto __end;
+	}
+	snd_pcm_hw_convert_from_old_params(data, data32);
 	oldseg = get_fs();
 	set_fs(KERNEL_DS);
-	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
+	err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
 	set_fs(oldseg);
 	if (err < 0)
-		return err;
-	snd_pcm_hw_convert_to_old_params(&data32, &data);
-	if (copy_to_user((void*)arg, &data32, sizeof(data32)))
-		return  -EFAULT;
-	return 0;
+		goto __end;
+	snd_pcm_hw_convert_to_old_params(data32, data);
+	err = 0;
+	if (copy_to_user((void*)arg, data32, sizeof(*data32)))
+		err = -EFAULT;
+      __end:
+      	if (data)
+      		kfree(data);
+      	if (data32)
+      		kfree(data32);
+	return err;
 }
 
 
diff -Nru a/sound/core/memory.c b/sound/core/memory.c
--- a/sound/core/memory.c	Tue Oct 15 20:29:12 2002
+++ b/sound/core/memory.c	Tue Oct 15 20:29:12 2002
@@ -499,10 +499,10 @@
 
 int copy_to_user_fromio(void *dst, unsigned long src, size_t count)
 {
-#if defined(__i386_) || defined(CONFIG_SPARC32)
+#if defined(__i386__) || defined(CONFIG_SPARC32)
 	return copy_to_user(dst, (const void*)src, count) ? -EFAULT : 0;
 #else
-	char buf[1024];
+	char buf[256];
 	while (count) {
 		size_t c = count;
 		if (c > sizeof(buf))
@@ -520,10 +520,10 @@
 
 int copy_from_user_toio(unsigned long dst, const void *src, size_t count)
 {
-#if defined(__i386_) || defined(CONFIG_SPARC32)
+#if defined(__i386__) || defined(CONFIG_SPARC32)
 	return copy_from_user((void*)dst, src, count) ? -EFAULT : 0;
 #else
-	char buf[1024];
+	char buf[256];
 	while (count) {
 		size_t c = count;
 		if (c > sizeof(buf))
diff -Nru a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
--- a/sound/core/oss/mixer_oss.c	Tue Oct 15 20:29:17 2002
+++ b/sound/core/oss/mixer_oss.c	Tue Oct 15 20:29:17 2002
@@ -495,18 +495,25 @@
 					  snd_kcontrol_t *kctl,
 					  int *left, int *right)
 {
-	snd_ctl_elem_info_t uinfo;
-	snd_ctl_elem_value_t uctl;
+	snd_ctl_elem_info_t *uinfo;
+	snd_ctl_elem_value_t *uctl;
 
 	snd_runtime_check(kctl != NULL, return);
-	memset(&uinfo, 0, sizeof(uinfo));
-	memset(&uctl, 0, sizeof(uctl));
-	snd_runtime_check(!kctl->info(kctl, &uinfo), return);
-	snd_runtime_check(!kctl->get(kctl, &uctl), return);
-	snd_runtime_check(uinfo.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo.value.integer.min != 0 || uinfo.value.integer.max != 1, return);
-	*left = snd_mixer_oss_conv1(uctl.value.integer.value[0], uinfo.value.integer.min, uinfo.value.integer.max, &pslot->volume[0]);
-	if (uinfo.count > 1)
-		*right = snd_mixer_oss_conv1(uctl.value.integer.value[1], uinfo.value.integer.min, uinfo.value.integer.max, &pslot->volume[1]);
+	uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC);
+	uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC);
+	if (uinfo == NULL || uctl == NULL)
+		goto __unalloc;
+	snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
+	snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc);
+	snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, return);
+	*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
+	if (uinfo->count > 1)
+		*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
+      __unalloc:
+      	if (uctl)
+      		kfree(uctl);
+      	if (uinfo)
+      		kfree(uinfo);
 }
 
 static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer,
@@ -515,21 +522,28 @@
 					 int *left, int *right,
 					 int route)
 {
-	snd_ctl_elem_info_t uinfo;
-	snd_ctl_elem_value_t uctl;
+	snd_ctl_elem_info_t *uinfo;
+	snd_ctl_elem_value_t *uctl;
 
 	snd_runtime_check(kctl != NULL, return);
-	memset(&uinfo, 0, sizeof(uinfo));
-	memset(&uctl, 0, sizeof(uctl));
-	snd_runtime_check(!kctl->info(kctl, &uinfo), return);
-	snd_runtime_check(!kctl->get(kctl, &uctl), return);
-	if (!uctl.value.integer.value[0]) {
+	uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC);
+	uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC);
+	if (uinfo == NULL || uctl == NULL)
+		goto __unalloc;
+	snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
+	snd_runtime_check(!kctl->get(kctl, uctl), goto __unalloc);
+	if (!uctl->value.integer.value[0]) {
 		*left = 0;
-		if (uinfo.count == 1)
+		if (uinfo->count == 1)
 			*right = 0;
 	}
-	if (uinfo.count > 1 && !uctl.value.integer.value[route ? 3 : 1])
+	if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
 		*right = 0;
+      __unalloc:
+      	if (uctl)
+      		kfree(uctl);
+      	if (uinfo)
+		kfree(uinfo);
 }
 
 static int snd_mixer_oss_get_volume1(snd_mixer_oss_file_t *fmixer,
@@ -566,21 +580,28 @@
 					  snd_kcontrol_t *kctl,
 					  int left, int right)
 {
-	snd_ctl_elem_info_t uinfo;
-	snd_ctl_elem_value_t uctl;
+	snd_ctl_elem_info_t *uinfo;
+	snd_ctl_elem_value_t *uctl;
 	int res;
 
 	snd_runtime_check(kctl != NULL, return);
-	memset(&uinfo, 0, sizeof(uinfo));
-	memset(&uctl, 0, sizeof(uctl));
-	snd_runtime_check(!kctl->info(kctl, &uinfo), return);
-	snd_runtime_check(uinfo.type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo.value.integer.min != 0 || uinfo.value.integer.max != 1, return);
-	uctl.value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo.value.integer.min, uinfo.value.integer.max);
-	if (uinfo.count > 1)
-		uctl.value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo.value.integer.min, uinfo.value.integer.max);
-	snd_runtime_check((res = kctl->put(kctl, &uctl)) >= 0, return);
+	uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC);
+	uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC);
+	if (uinfo == NULL || uctl == NULL)
+		goto __unalloc;
+	snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
+	snd_runtime_check(uinfo->type != SNDRV_CTL_ELEM_TYPE_BOOLEAN || uinfo->value.integer.min != 0 || uinfo->value.integer.max != 1, return);
+	uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
+	if (uinfo->count > 1)
+		uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
+	snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc);
 	if (res > 0)
 		snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+      __unalloc:
+      	if (uctl)
+      		kfree(uctl);
+      	if (uinfo)
+		kfree(uinfo);
 }
 
 static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer,
@@ -589,27 +610,34 @@
 					 int left, int right,
 					 int route)
 {
-	snd_ctl_elem_info_t uinfo;
-	snd_ctl_elem_value_t uctl;
+	snd_ctl_elem_info_t *uinfo;
+	snd_ctl_elem_value_t *uctl;
 	int res;
 
 	snd_runtime_check(kctl != NULL, return);
-	memset(&uinfo, 0, sizeof(uinfo));
-	memset(&uctl, 0, sizeof(uctl));
-	snd_runtime_check(!kctl->info(kctl, &uinfo), return);
-	if (uinfo.count > 1) {
-		uctl.value.integer.value[0] = left > 0 ? 1 : 0;
-		uctl.value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
+	uinfo = snd_kcalloc(sizeof(*uinfo), GFP_ATOMIC);
+	uctl = snd_kcalloc(sizeof(*uctl), GFP_ATOMIC);
+	if (uinfo == NULL || uctl == NULL)
+		goto __unalloc;
+	snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc);
+	if (uinfo->count > 1) {
+		uctl->value.integer.value[0] = left > 0 ? 1 : 0;
+		uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
 		if (route) {
-			uctl.value.integer.value[1] =
-			uctl.value.integer.value[2] = 0;
+			uctl->value.integer.value[1] =
+			uctl->value.integer.value[2] = 0;
 		}
 	} else {
-		uctl.value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
+		uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
 	}
-	snd_runtime_check((res = kctl->put(kctl, &uctl)) >= 0, return);
+	snd_runtime_check((res = kctl->put(kctl, uctl)) >= 0, goto __unalloc);
 	if (res > 0)
 		snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+      __unalloc:
+      	if (uctl)
+      		kfree(uctl);
+      	if (uinfo)
+		kfree(uinfo);
 }
 
 static int snd_mixer_oss_put_volume1(snd_mixer_oss_file_t *fmixer,
@@ -718,17 +746,21 @@
 	snd_kcontrol_t *kctl;
 	snd_mixer_oss_slot_t *pslot;
 	struct slot *slot;
-	snd_ctl_elem_info_t uinfo;
-	snd_ctl_elem_value_t uctl;
+	snd_ctl_elem_info_t *uinfo;
+	snd_ctl_elem_value_t *uctl;
 	int err, idx;
 	
+	uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL);
+	uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL);
+	if (uinfo == NULL || uctl == NULL) {
+		err = -ENOMEM;
+		goto __unlock;
+	}
 	read_lock(&card->control_rwlock);
 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
-	snd_runtime_check(kctl != NULL, return -ENOENT);
-	memset(&uinfo, 0, sizeof(uinfo));
-	memset(&uctl, 0, sizeof(uctl));
-	snd_runtime_check(!(err = kctl->info(kctl, &uinfo)), read_unlock(&card->control_rwlock); return err);
-	snd_runtime_check(!(err = kctl->get(kctl, &uctl)), read_unlock(&card->control_rwlock); return err);
+	snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock);
+	snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock);
+	snd_runtime_check(!(err = kctl->get(kctl, uctl)), goto __unlock);
 	read_unlock(&card->control_rwlock);
 	for (idx = 0; idx < 32; idx++) {
 		if (!(mixer->mask_recsrc & (1 << idx)))
@@ -739,12 +771,21 @@
 			continue;
 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
 			continue;
-		if (slot->capture_item == uctl.value.enumerated.item[0]) {
+		if (slot->capture_item == uctl->value.enumerated.item[0]) {
 			*active_index = idx;
 			break;
 		}
 	}
-	return 0;
+	err = 0;
+	goto __unalloc;
+      __unlock:
+      	read_unlock(&card->control_rwlock);
+      __unalloc:
+      	if (uctl)
+      		kfree(uctl);
+      	if (uinfo)
+      		kfree(uinfo);
+      	return err;
 }
 
 static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, int active_index)
@@ -754,16 +795,20 @@
 	snd_kcontrol_t *kctl;
 	snd_mixer_oss_slot_t *pslot;
 	struct slot *slot = NULL;
-	snd_ctl_elem_info_t uinfo;
-	snd_ctl_elem_value_t uctl;
+	snd_ctl_elem_info_t *uinfo;
+	snd_ctl_elem_value_t *uctl;
 	int err, idx;
 
+	uinfo = snd_kcalloc(sizeof(*uinfo), GFP_KERNEL);
+	uctl = snd_kcalloc(sizeof(*uctl), GFP_KERNEL);
+	if (uinfo == NULL || uctl == NULL) {
+		err = -ENOMEM;
+		goto __unlock;
+	}
 	read_lock(&card->control_rwlock);
 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
-	snd_runtime_check(kctl != NULL, read_unlock(&card->control_rwlock); return -ENOENT);
-	memset(&uinfo, 0, sizeof(uinfo));
-	memset(&uctl, 0, sizeof(uctl));
-	snd_runtime_check(!(err = kctl->info(kctl, &uinfo)), read_unlock(&card->control_rwlock); return err);
+	snd_runtime_check(kctl != NULL, err = -ENOENT; goto __unlock);
+	snd_runtime_check(!(err = kctl->info(kctl, uinfo)), goto __unlock);
 	for (idx = 0; idx < 32; idx++) {
 		if (!(mixer->mask_recsrc & (1 << idx)))
 			continue;
@@ -778,14 +823,19 @@
 		slot = NULL;
 	}
 	snd_runtime_check(slot != NULL, goto __unlock);
-	for (idx = 0; idx < uinfo.count; idx++)
-		uctl.value.enumerated.item[idx] = slot->capture_item;
-	snd_runtime_check((err = kctl->put(kctl, &uctl)) >= 0, );
+	for (idx = 0; idx < uinfo->count; idx++)
+		uctl->value.enumerated.item[idx] = slot->capture_item;
+	snd_runtime_check((err = kctl->put(kctl, uctl)) >= 0, );
 	if (err > 0)
 		snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
+	err = 0;
       __unlock:
 	read_unlock(&card->control_rwlock);
-	return 0;
+	if (uctl)
+		kfree(uctl);
+	if (uinfo)
+		kfree(uinfo);
+	return err;
 }
 
 struct snd_mixer_oss_assign_table {
@@ -1176,9 +1226,11 @@
 			mixer->name[sizeof(mixer->name)-1] = 0;
 		} else
 			strcpy(mixer->name, name);
+#ifdef SNDRV_OSS_INFO_DEV_MIXERS
 		snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
 				      card->number,
 				      mixer->name);
+#endif
 		for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
 			mixer->slots[idx].number = idx;
 		card->mixer_oss = mixer;
@@ -1188,7 +1240,9 @@
 		snd_mixer_oss_t *mixer = card->mixer_oss;
 		if (mixer == NULL)
 			return 0;
+#ifdef SNDRV_OSS_INFO_DEV_MIXERS
 		snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
+#endif
 		snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
 		snd_mixer_oss_proc_done(mixer);
 		return snd_mixer_oss_free1(mixer);
diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c	Tue Oct 15 20:29:20 2002
+++ b/sound/core/oss/pcm_oss.c	Tue Oct 15 20:29:20 2002
@@ -2123,9 +2123,11 @@
 			      pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count && 
 			      !(pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX));
 		sprintf(name, "%s%s", pcm->name, duplex ? " (DUPLEX)" : "");
+#ifdef SNDRV_OSS_INFO_DEV_AUDIO
 		snd_oss_info_register(SNDRV_OSS_INFO_DEV_AUDIO,
 				      pcm->card->number,
 				      name);
+#endif
 		pcm->oss.reg++;
 	}
 	if (snd_adsp_map[pcm->card->number] == pcm->device) {
@@ -2146,7 +2148,9 @@
 		if (snd_dsp_map[pcm->card->number] == pcm->device) {
 			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
 						  pcm->card, 0);
+#ifdef SNDRV_OSS_INFO_DEV_AUDIO
 			snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_AUDIO, pcm->card->number);
+#endif
 		}
 		if (snd_adsp_map[pcm->card->number] == pcm->device)
 			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_PCM,
diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
--- a/sound/core/pcm_lib.c	Tue Oct 15 20:29:16 2002
+++ b/sound/core/pcm_lib.c	Tue Oct 15 20:29:16 2002
@@ -1473,7 +1473,7 @@
 int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params,
 			  snd_pcm_hw_param_t var, unsigned int best, int *dir)
 {
-	snd_pcm_hw_params_t save;
+	snd_pcm_hw_params_t *save = NULL;
 	int v;
 	unsigned int saved_min;
 	int last = 0;
@@ -1493,30 +1493,42 @@
 		maxdir = 1;
 		max--;
 	}
-	save = *params;
+	save = kmalloc(sizeof(*save), GFP_KERNEL);
+	if (save == NULL)
+		return -ENOMEM;
+	*save = *params;
 	saved_min = min;
 	min = snd_pcm_hw_param_min(pcm, params, var, min, &mindir);
 	if (min >= 0) {
-		snd_pcm_hw_params_t params1;
+		snd_pcm_hw_params_t *params1;
 		if (max < 0)
 			goto _end;
 		if ((unsigned int)min == saved_min && mindir == valdir)
 			goto _end;
-		params1 = save;
-		max = snd_pcm_hw_param_max(pcm, &params1, var, max, &maxdir);
-		if (max < 0)
+		params1 = kmalloc(sizeof(*params1), GFP_KERNEL);
+		if (params1 == NULL) {
+			kfree(save);
+			return -ENOMEM;
+		}
+		*params1 = *save;
+		max = snd_pcm_hw_param_max(pcm, params1, var, max, &maxdir);
+		if (max < 0) {
+			kfree(params1);
 			goto _end;
+		}
 		if (boundary_nearer(max, maxdir, best, valdir, min, mindir)) {
-			*params = params1;
+			*params = *params1;
 			last = 1;
 		}
+		kfree(params1);
 	} else {
-		*params = save;
+		*params = *save;
 		max = snd_pcm_hw_param_max(pcm, params, var, max, &maxdir);
 		assert(max >= 0);
 		last = 1;
 	}
  _end:
+ 	kfree(save);
 	if (last)
 		v = snd_pcm_hw_param_last(pcm, params, var, dir);
 	else
@@ -1842,16 +1854,11 @@
 		if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
 			snd_pcm_update_hw_ptr(substream);
 		avail = snd_pcm_playback_avail(runtime);
-		if (runtime->status->state == SNDRV_PCM_STATE_PAUSED ||
-		    runtime->status->state == SNDRV_PCM_STATE_PREPARED) {
-			if (avail < runtime->xfer_align) {
-				err = -EPIPE;
-				goto _end_unlock;
-			}
-		} else if (((avail < runtime->control->avail_min && size > avail) ||
-			    (size >= runtime->xfer_align && avail < runtime->xfer_align))) {
+		if (((avail < runtime->control->avail_min && size > avail) ||
+		   (size >= runtime->xfer_align && avail < runtime->xfer_align))) {
 			wait_queue_t wait;
 			enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
+
 			if (nonblock) {
 				err = -EAGAIN;
 				goto _end_unlock;
@@ -1868,8 +1875,11 @@
 				spin_unlock_irq(&runtime->lock);
 				if (schedule_timeout(10 * HZ) == 0) {
 					spin_lock_irq(&runtime->lock);
-					state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
-					break;
+					if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
+					    runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
+						state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
+						break;
+					}
 				}
 				spin_lock_irq(&runtime->lock);
 				switch (runtime->status->state) {
@@ -1916,10 +1926,6 @@
 		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
 		if (frames > cont)
 			frames = cont;
-		if (frames == 0 && runtime->status->state == SNDRV_PCM_STATE_PAUSED) {
-			err = -EPIPE;
-			goto _end_unlock;
-		}
 		snd_assert(frames != 0,
 			   spin_unlock_irq(&runtime->lock);
 			   return -EINVAL);
@@ -2135,14 +2141,8 @@
 		if (runtime->sleep_min == 0 && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
 			snd_pcm_update_hw_ptr(substream);
 		avail = snd_pcm_capture_avail(runtime);
-		if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) {
-			if (avail < runtime->xfer_align) {
-				err = -EPIPE;
-				goto _end_unlock;
-			}
-		} else if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
+		if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
 			if (avail < runtime->xfer_align) {
-				runtime->status->state = SNDRV_PCM_STATE_SETUP;
 				err = -EPIPE;
 				goto _end_unlock;
 			}
@@ -2150,6 +2150,7 @@
 			   (size >= runtime->xfer_align && avail < runtime->xfer_align)) {
 			wait_queue_t wait;
 			enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state;
+
 			if (nonblock) {
 				err = -EAGAIN;
 				goto _end_unlock;
@@ -2166,8 +2167,11 @@
 				spin_unlock_irq(&runtime->lock);
 				if (schedule_timeout(10 * HZ) == 0) {
 					spin_lock_irq(&runtime->lock);
-					state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
-					break;
+					if (runtime->status->state != SNDRV_PCM_STATE_PREPARED &&
+					    runtime->status->state != SNDRV_PCM_STATE_PAUSED) {
+						state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED;
+						break;
+					}
 				}
 				spin_lock_irq(&runtime->lock);
 				switch (runtime->status->state) {
diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c	Tue Oct 15 20:29:16 2002
+++ b/sound/core/pcm_native.c	Tue Oct 15 20:29:16 2002
@@ -1848,7 +1848,10 @@
 	snd_assert(substream != NULL, return -ENXIO);
 	snd_assert(!atomic_read(&substream->runtime->mmap_count), );
 	pcm = substream->pcm;
-	snd_pcm_capture_drop(substream);
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		snd_pcm_playback_drop(substream);
+	else
+		snd_pcm_capture_drop(substream);
 	fasync_helper(-1, file, 0, &substream->runtime->fasync);
 	down(&pcm->open_mutex);
 	snd_pcm_release_file(pcm_file);
@@ -1959,34 +1962,29 @@
 	return ret;
 }
 
-static int snd_pcm_playback_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res)
+static int snd_pcm_hwsync(snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err = 0;
-	snd_pcm_sframes_t n;
+	int err;
+
 	spin_lock_irq(&runtime->lock);
 	switch (runtime->status->state) {
-	case SNDRV_PCM_STATE_RUNNING:
 	case SNDRV_PCM_STATE_DRAINING:
-		if (snd_pcm_update_hw_ptr(substream) >= 0) {
-			n = snd_pcm_playback_hw_avail(runtime);
-			if (put_user(n, res))
-				err = -EFAULT;
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			goto __badfd;
+	case SNDRV_PCM_STATE_RUNNING:
+		if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
 			break;
-		} else {
-			err = SNDRV_PCM_STATE_RUNNING ? -EPIPE : -EBADFD;
-		}
-		break;
+		/* Fall through */
+	case SNDRV_PCM_STATE_PREPARED:
 	case SNDRV_PCM_STATE_SUSPENDED:
-		if (runtime->status->suspended_state == SNDRV_PCM_STATE_RUNNING) {
-			n = snd_pcm_playback_hw_avail(runtime);
-			if (put_user(n, res))
-				err = -EFAULT;
-		} else {
-			err = -EBADFD;
-		}
+		err = 0;
+		break;
+	case SNDRV_PCM_STATE_XRUN:
+		err = -EPIPE;
 		break;
 	default:
+	      __badfd:
 		err = -EBADFD;
 		break;
 	}
@@ -1994,41 +1992,43 @@
 	return err;
 }
 		
-static int snd_pcm_capture_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res)
+static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t *res)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
-	int err = 0;
+	int err;
 	snd_pcm_sframes_t n;
+
 	spin_lock_irq(&runtime->lock);
 	switch (runtime->status->state) {
+	case SNDRV_PCM_STATE_DRAINING:
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			goto __badfd;
 	case SNDRV_PCM_STATE_RUNNING:
-		if (snd_pcm_update_hw_ptr(substream) >= 0) {
-			n = snd_pcm_capture_avail(runtime);
-			if (put_user(n, res))
-				err = -EFAULT;
+		if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
 			break;
-		}
 		/* Fall through */
-	case SNDRV_PCM_STATE_XRUN:
-		err = -EPIPE;
-		break;
+	case SNDRV_PCM_STATE_PREPARED:
 	case SNDRV_PCM_STATE_SUSPENDED:
-		if (runtime->status->suspended_state == SNDRV_PCM_STATE_RUNNING) {
+		err = 0;
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			n = snd_pcm_playback_hw_avail(runtime);
+		else
 			n = snd_pcm_capture_avail(runtime);
-			if (put_user(n, res))
-				err = -EFAULT;
-		} else {
-			err = -EBADFD;
-		}
+		if (put_user(n, res))
+			err = -EFAULT;
+		break;
+	case SNDRV_PCM_STATE_XRUN:
+		err = -EPIPE;
 		break;
 	default:
+	      __badfd:
 		err = -EBADFD;
 		break;
 	}
 	spin_unlock_irq(&runtime->lock);
 	return err;
 }
-
+		
 static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream,
 				   unsigned int cmd, void *arg);
 static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream,
@@ -2076,6 +2076,10 @@
 		return snd_pcm_resume(substream);
 	case SNDRV_PCM_IOCTL_XRUN:
 		return snd_pcm_xrun(substream);
+	case SNDRV_PCM_IOCTL_HWSYNC:
+		return snd_pcm_hwsync(substream);
+	case SNDRV_PCM_IOCTL_DELAY:
+		return snd_pcm_delay(substream, (snd_pcm_sframes_t *) arg);
 	case SNDRV_PCM_IOCTL_HW_REFINE_OLD:
 		return snd_pcm_hw_refine_old_user(substream, (struct sndrv_pcm_hw_params_old *) arg);
 	case SNDRV_PCM_IOCTL_HW_PARAMS_OLD:
@@ -2110,7 +2114,7 @@
 	{
 		snd_xfern_t xfern, *_xfern = arg;
 		snd_pcm_runtime_t *runtime = substream->runtime;
-		void *bufs[128];
+		void *bufs;
 		snd_pcm_sframes_t result;
 		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 			return -EBADFD;
@@ -2120,9 +2124,15 @@
 			return -EFAULT;
 		if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
 			return -EFAULT;
-		if (copy_from_user(bufs, xfern.bufs, sizeof(*bufs) * runtime->channels))
+		bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL);
+		if (bufs == NULL)
+			return -ENOMEM;
+		if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) {
+			kfree(bufs);
 			return -EFAULT;
+		}
 		result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
+		kfree(bufs);
 		__put_user(result, &_xfern->result);
 		return result < 0 ? result : 0;
 	}
@@ -2150,8 +2160,6 @@
 		return snd_pcm_playback_drain(substream);
 	case SNDRV_PCM_IOCTL_DROP:
 		return snd_pcm_playback_drop(substream);
-	case SNDRV_PCM_IOCTL_DELAY:
-		return snd_pcm_playback_delay(substream, (snd_pcm_sframes_t*) arg);
 	}
 	return snd_pcm_common_ioctl1(substream, cmd, arg);
 }
@@ -2181,7 +2189,7 @@
 	{
 		snd_xfern_t xfern, *_xfern = arg;
 		snd_pcm_runtime_t *runtime = substream->runtime;
-		void *bufs[128];
+		void *bufs;
 		snd_pcm_sframes_t result;
 		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 			return -EBADFD;
@@ -2191,9 +2199,15 @@
 			return -EFAULT;
 		if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
 			return -EFAULT;
-		if (copy_from_user(bufs, xfern.bufs, sizeof(*bufs) * runtime->channels))
+		bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL);
+		if (bufs == NULL)
+			return -ENOMEM;
+		if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) {
+			kfree(bufs);
 			return -EFAULT;
+		}
 		result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
+		kfree(bufs);
 		__put_user(result, &_xfern->result);
 		return result < 0 ? result : 0;
 	}
@@ -2213,8 +2227,6 @@
 		return snd_pcm_capture_drain(substream);
 	case SNDRV_PCM_IOCTL_DROP:
 		return snd_pcm_capture_drop(substream);
-	case SNDRV_PCM_IOCTL_DELAY:
-		return snd_pcm_capture_delay(substream, (snd_pcm_sframes_t*) arg);
 	}
 	return snd_pcm_common_ioctl1(substream, cmd, arg);
 }
@@ -2311,7 +2323,9 @@
 	snd_pcm_runtime_t *runtime;
 	snd_pcm_sframes_t result;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
 	up(&file->f_dentry->d_inode->i_sem);
+#endif
 	pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, result = -ENXIO; goto end);
 	substream = pcm_file->substream;
 	snd_assert(substream != NULL, result = -ENXIO; goto end);
@@ -2329,7 +2343,9 @@
 	if (result > 0)
 		result = frames_to_bytes(runtime, result);
  end:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
 	down(&file->f_dentry->d_inode->i_sem);
+#endif
 	return result;
 }
 
@@ -2343,7 +2359,7 @@
 	snd_pcm_runtime_t *runtime;
 	snd_pcm_sframes_t result;
 	unsigned long i;
-	void *bufs[128];
+	void **bufs;
 	snd_pcm_uframes_t frames;
 
 	pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO);
@@ -2352,16 +2368,20 @@
 	runtime = substream->runtime;
 	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 		return -EBADFD;
-	if (count > 128 || count != runtime->channels)
+	if (count > 1024 || count != runtime->channels)
 		return -EINVAL;
 	if (!frame_aligned(runtime, _vector->iov_len))
 		return -EINVAL;
 	frames = bytes_to_samples(runtime, _vector->iov_len);
+	bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
+	if (bufs == NULL)
+		return -ENOMEM;
 	for (i = 0; i < count; ++i)
 		bufs[i] = _vector[i].iov_base;
 	result = snd_pcm_lib_readv(substream, bufs, frames);
 	if (result > 0)
 		result = frames_to_bytes(runtime, result);
+	kfree(bufs);
 	return result;
 }
 
@@ -2373,10 +2393,12 @@
 	snd_pcm_runtime_t *runtime;
 	snd_pcm_sframes_t result;
 	unsigned long i;
-	void *bufs[128];
+	void **bufs;
 	snd_pcm_uframes_t frames;
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
 	up(&file->f_dentry->d_inode->i_sem);
+#endif
 	pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, result = -ENXIO; goto end);
 	substream = pcm_file->substream;
 	snd_assert(substream != NULL, result = -ENXIO; goto end);
@@ -2391,13 +2413,19 @@
 		goto end;
 	}
 	frames = bytes_to_samples(runtime, _vector->iov_len);
+	bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
+	if (bufs == NULL)
+		return -ENOMEM;
 	for (i = 0; i < count; ++i)
 		bufs[i] = _vector[i].iov_base;
 	result = snd_pcm_lib_writev(substream, bufs, frames);
 	if (result > 0)
 		result = frames_to_bytes(runtime, result);
+	kfree(bufs);
  end:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
 	down(&file->f_dentry->d_inode->i_sem);
+#endif
 	return result;
 }
 #endif
@@ -2422,6 +2450,8 @@
 	avail = snd_pcm_playback_avail(runtime);
 	switch (runtime->status->state) {
 	case SNDRV_PCM_STATE_RUNNING:
+	case SNDRV_PCM_STATE_PREPARED:
+	case SNDRV_PCM_STATE_PAUSED:
 		if (avail >= runtime->control->avail_min) {
 			mask = POLLOUT | POLLWRNORM;
 			break;
@@ -2430,12 +2460,6 @@
 	case SNDRV_PCM_STATE_DRAINING:
 		mask = 0;
 		break;
-	case SNDRV_PCM_STATE_PREPARED:
-		if (avail > 0) {
-			mask = POLLOUT | POLLWRNORM;
-			break;
-		}
-		/* Fall through */
 	default:
 		mask = POLLOUT | POLLWRNORM | POLLERR;
 		break;
@@ -2464,6 +2488,8 @@
 	avail = snd_pcm_capture_avail(runtime);
 	switch (runtime->status->state) {
 	case SNDRV_PCM_STATE_RUNNING:
+	case SNDRV_PCM_STATE_PREPARED:
+	case SNDRV_PCM_STATE_PAUSED:
 		if (avail >= runtime->control->avail_min) {
 			mask = POLLIN | POLLRDNORM;
 			break;
diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c
--- a/sound/core/rawmidi.c	Tue Oct 15 20:29:12 2002
+++ b/sound/core/rawmidi.c	Tue Oct 15 20:29:12 2002
@@ -1425,7 +1425,9 @@
 			snd_printk(KERN_ERR "unable to register OSS rawmidi device %i:%i\n", rmidi->card->number, 0);
 		} else {
 			rmidi->ossreg++;
+#ifdef SNDRV_OSS_INFO_DEV_MIDI
 			snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number, rmidi->name);
+#endif
 		}
 	}
 	if (rmidi->device == snd_amidi_map[rmidi->card->number]) {
@@ -1436,7 +1438,7 @@
 			rmidi->ossreg++;
 		}
 	}
-#endif
+#endif /* CONFIG_SND_OSSEMUL */
 	up(&register_mutex);
 	sprintf(name, "midi%d", rmidi->device);
 	entry = snd_info_create_card_entry(rmidi->card, name, rmidi->card->proc_root);
@@ -1484,13 +1486,15 @@
 	if (rmidi->ossreg) {
 		if (rmidi->device == snd_midi_map[rmidi->card->number]) {
 			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 0);
+#ifdef SNDRV_OSS_INFO_DEV_MIDI
 			snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIDI, rmidi->card->number);
+#endif
 		}
 		if (rmidi->device == snd_amidi_map[rmidi->card->number])
 			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIDI, rmidi->card, 1);
 		rmidi->ossreg = 0;
 	}
-#endif
+#endif /* CONFIG_SND_OSSEMUL */
 	if (rmidi->ops && rmidi->ops->dev_unregister)
 		rmidi->ops->dev_unregister(rmidi);
 	snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
diff -Nru a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c
--- a/sound/core/seq/oss/seq_oss_readq.c	Tue Oct 15 20:29:14 2002
+++ b/sound/core/seq/oss/seq_oss_readq.c	Tue Oct 15 20:29:14 2002
@@ -159,9 +159,10 @@
 	spin_lock_irqsave(&q->lock, *rflags);
 	if (q->qlen == 0) {
 		if (blocking) {
-			snd_seq_sleep_timeout_in_lock(&q->midi_sleep,
-						      &q->lock,
-						      q->pre_event_timeout);
+			spin_unlock(&q->lock);
+			interruptible_sleep_on_timeout(&q->midi_sleep,
+						       q->pre_event_timeout);
+			spin_lock(&q->lock);
 		}
 		if (q->qlen == 0) {
 			spin_unlock_irqrestore(&q->lock, *rflags);
diff -Nru a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
--- a/sound/core/seq/oss/seq_oss_synth.c	Tue Oct 15 20:29:11 2002
+++ b/sound/core/seq/oss/seq_oss_synth.c	Tue Oct 15 20:29:11 2002
@@ -146,8 +146,10 @@
 	debug_printk(("synth %s registered %d\n", rec->name, i));
 	spin_unlock_irqrestore(&register_lock, flags);
 	dev->driver_data = rec;
+#ifdef SNDRV_OSS_INFO_DEV_SYNTH
 	if (i < SNDRV_CARDS)
 		snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, i, rec->name);
+#endif
 	return 0;
 }
 
@@ -178,8 +180,10 @@
 		max_synth_devs = index + 1;
 	}
 	spin_unlock_irqrestore(&register_lock, flags);
+#ifdef SNDRV_OSS_INFO_DEV_SYNTH
 	if (rec->seq_device < SNDRV_CARDS)
 		snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_SYNTH, rec->seq_device);
+#endif
 
 	snd_use_lock_sync(&rec->use_lock);
 	kfree(rec);
diff -Nru a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c
--- a/sound/core/seq/oss/seq_oss_writeq.c	Tue Oct 15 20:29:15 2002
+++ b/sound/core/seq/oss/seq_oss_writeq.c	Tue Oct 15 20:29:15 2002
@@ -122,7 +122,9 @@
 	}
 		
 	/* wait for echo event */
-	snd_seq_sleep_timeout_in_lock(&q->sync_sleep, &q->sync_lock, HZ);
+	spin_unlock(&q->sync_lock);
+	interruptible_sleep_on_timeout(&q->sync_sleep, HZ);
+	spin_lock(&q->sync_lock);
 	if (signal_pending(current)) {
 		/* interrupted - return 0 to finish sync */
 		q->sync_event_put = 0;
diff -Nru a/sound/core/seq/seq.c b/sound/core/seq/seq.c
--- a/sound/core/seq/seq.c	Tue Oct 15 20:29:19 2002
+++ b/sound/core/seq/seq.c	Tue Oct 15 20:29:19 2002
@@ -135,7 +135,7 @@
 EXPORT_SYMBOL(snd_seq_event_port_detach);
   /* seq_lock.c */
 #if defined(__SMP__) || defined(CONFIG_SND_DEBUG)
-EXPORT_SYMBOL(snd_seq_sleep_in_lock);
-EXPORT_SYMBOL(snd_seq_sleep_timeout_in_lock);
+/*EXPORT_SYMBOL(snd_seq_sleep_in_lock);*/
+/*EXPORT_SYMBOL(snd_seq_sleep_timeout_in_lock);*/
 EXPORT_SYMBOL(snd_use_lock_sync_helper);
 #endif
diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
--- a/sound/core/seq/seq_clientmgr.c	Tue Oct 15 20:29:12 2002
+++ b/sound/core/seq/seq_clientmgr.c	Tue Oct 15 20:29:12 2002
@@ -152,9 +152,11 @@
 			}
 		} else if (clientid >= 64 && clientid < 128) {
 			int card = (clientid - 64) / 8;
-			if (card < snd_ecards_limit && ! card_requested[card]) {
-				card_requested[card] = 1;
-				snd_request_card(card);
+			if (card < snd_ecards_limit) {
+				if (! card_requested[card]) {
+					card_requested[card] = 1;
+					snd_request_card(card);
+				}
 				snd_seq_device_load_drivers();
 			}
 		}
diff -Nru a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
--- a/sound/core/seq/seq_fifo.c	Tue Oct 15 20:29:16 2002
+++ b/sound/core/seq/seq_fifo.c	Tue Oct 15 20:29:16 2002
@@ -182,7 +182,9 @@
 			spin_unlock_irqrestore(&f->lock, flags);
 			return -EAGAIN;
 		}
-		snd_seq_sleep_in_lock(&f->input_sleep, &f->lock);
+		spin_unlock(&f->lock);
+		interruptible_sleep_on(&f->input_sleep);
+		spin_lock(&f->lock);
 
 		if (signal_pending(current)) {
 			spin_unlock_irqrestore(&f->lock, flags);
diff -Nru a/sound/core/seq/seq_lock.c b/sound/core/seq/seq_lock.c
--- a/sound/core/seq/seq_lock.c	Tue Oct 15 20:29:16 2002
+++ b/sound/core/seq/seq_lock.c	Tue Oct 15 20:29:16 2002
@@ -25,6 +25,7 @@
 
 #if defined(__SMP__) || defined(CONFIG_SND_DEBUG)
 
+#if 0 /* NOT USED */
 /* (interruptible) sleep_on during the specified spinlock */
 void snd_seq_sleep_in_lock(wait_queue_head_t *p, spinlock_t *lock)
 {
@@ -60,6 +61,7 @@
 
 	return timeout;
 }
+#endif /* NOT USED */
 
 /* wait until all locks are released */
 void snd_use_lock_sync_helper(snd_use_lock_t *lockp, const char *file, int line)
diff -Nru a/sound/core/seq/seq_lock.h b/sound/core/seq/seq_lock.h
--- a/sound/core/seq/seq_lock.h	Tue Oct 15 20:29:17 2002
+++ b/sound/core/seq/seq_lock.h	Tue Oct 15 20:29:17 2002
@@ -20,12 +20,6 @@
 void snd_use_lock_sync_helper(snd_use_lock_t *lock, const char *file, int line);
 #define snd_use_lock_sync(lockp) snd_use_lock_sync_helper(lockp, __BASE_FILE__, __LINE__)
 
-/* (interruptible) sleep_on during the specified spinlock */
-void snd_seq_sleep_in_lock(wait_queue_head_t *p, spinlock_t *lock);
-
-/* (interruptible) sleep_on with timeout during the specified spinlock */
-long snd_seq_sleep_timeout_in_lock(wait_queue_head_t *p, spinlock_t *lock, long timeout);
-
 #else /* SMP || CONFIG_SND_DEBUG */
 
 typedef spinlock_t snd_use_lock_t;	/* dummy */
@@ -33,9 +27,6 @@
 #define snd_use_lock_use(lockp) /**/
 #define snd_use_lock_free(lockp) /**/
 #define snd_use_lock_sync(lockp) /**/
-
-#define snd_seq_sleep_in_lock(p,lock)	interruptible_sleep_on(p)
-#define snd_seq_sleep_timeout_in_lock(p,lock,timeout)	interruptible_sleep_on_timeout(p,timeout)
 
 #endif /* SMP || CONFIG_SND_DEBUG */
 
diff -Nru a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
--- a/sound/core/seq/seq_memory.c	Tue Oct 15 20:29:12 2002
+++ b/sound/core/seq/seq_memory.c	Tue Oct 15 20:29:12 2002
@@ -233,17 +233,21 @@
 		goto __error;
 	}
 	while (pool->free == NULL && ! nonblock && ! pool->closing) {
+
+		spin_unlock(&pool->lock);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
 		/* change semaphore to allow other clients
 		   to access device file */
 		if (file)
 			up(&semaphore_of(file));
-
-		snd_seq_sleep_in_lock(&pool->output_sleep, &pool->lock);
-
+#endif
+		interruptible_sleep_on(&pool->output_sleep);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0)
 		/* restore semaphore again */
 		if (file)
 			down(&semaphore_of(file));
-
+#endif
+		spin_lock(&pool->lock);
 		/* interrupted? */
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
diff -Nru a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c	Tue Oct 15 20:29:19 2002
+++ b/sound/core/sound.c	Tue Oct 15 20:29:19 2002
@@ -318,9 +318,6 @@
 #endif
 	if (register_chrdev(snd_major, "alsa", &snd_fops)) {
 		snd_printk(KERN_ERR "unable to register native major device number %d\n", snd_major);
-#ifdef CONFIG_SND_OSSEMUL
-		snd_oss_cleanup_module();
-#endif
 		return -EIO;
 	}
 #ifdef CONFIG_SND_DEBUG_MEMORY
@@ -330,9 +327,6 @@
 #ifdef CONFIG_SND_DEBUG_MEMORY
 		snd_memory_done();
 #endif
-#ifdef CONFIG_SND_OSSEMUL
-		snd_oss_cleanup_module();
-#endif
 		return -ENOMEM;
 	}
 #ifdef CONFIG_SND_OSSEMUL
@@ -369,7 +363,6 @@
 	
 #ifdef CONFIG_SND_OSSEMUL
 	snd_info_minor_unregister();
-	snd_oss_cleanup_module();
 #endif
 	snd_info_done();
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_APM)
@@ -455,6 +448,7 @@
 EXPORT_SYMBOL(snd_dma_residue);
 #endif
   /* info.c */
+#ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(snd_seq_root);
 EXPORT_SYMBOL(snd_create_proc_entry);
 EXPORT_SYMBOL(snd_remove_proc_entry);
@@ -468,8 +462,9 @@
 EXPORT_SYMBOL(snd_info_free_device);
 EXPORT_SYMBOL(snd_info_register);
 EXPORT_SYMBOL(snd_info_unregister);
+#endif
   /* info_oss.c */
-#ifdef CONFIG_SND_OSSEMUL
+#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
 EXPORT_SYMBOL(snd_oss_info_register);
 #endif
   /* control.c */
diff -Nru a/sound/core/sound_oss.c b/sound/core/sound_oss.c
--- a/sound/core/sound_oss.c	Tue Oct 15 20:29:22 2002
+++ b/sound/core/sound_oss.c	Tue Oct 15 20:29:22 2002
@@ -183,6 +183,8 @@
  *  INFO PART
  */
 
+#ifdef CONFIG_PROC_FS
+
 static snd_info_entry_t *snd_minor_info_oss_entry = NULL;
 
 static void snd_minor_info_oss_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer)
@@ -207,8 +209,11 @@
 	up(&sound_oss_mutex);
 }
 
+#endif /* CONFIG_PROC_FS */
+
 int __init snd_minor_info_oss_init(void)
 {
+#ifdef CONFIG_PROC_FS
 	snd_info_entry_t *entry;
 
 	entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
@@ -222,13 +227,16 @@
 		}
 	}
 	snd_minor_info_oss_entry = entry;
+#endif
 	return 0;
 }
 
 int __exit snd_minor_info_oss_done(void)
 {
+#ifdef CONFIG_PROC_FS
 	if (snd_minor_info_oss_entry)
 		snd_info_unregister(snd_minor_info_oss_entry);
+#endif
 	return 0;
 }
 
@@ -239,10 +247,6 @@
 	for (card = 0; card < SNDRV_CARDS; card++)
 		INIT_LIST_HEAD(&snd_oss_minors_hash[card]);
 	return 0;
-}
-
-void snd_oss_cleanup_module(void)
-{
 }
 
 #endif /* CONFIG_SND_OSSEMUL */
diff -Nru a/sound/core/timer.c b/sound/core/timer.c
--- a/sound/core/timer.c	Tue Oct 15 20:29:17 2002
+++ b/sound/core/timer.c	Tue Oct 15 20:29:17 2002
@@ -1356,7 +1356,7 @@
 	int err;
 	snd_info_entry_t *entry;
 
-#ifdef CONFIG_SND_OSSEMUL
+#ifdef SNDRV_OSS_INFO_DEV_TIMERS
 	snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer");
 #endif
 	if ((entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL)) != NULL) {
@@ -1391,7 +1391,7 @@
 		snd_info_unregister(snd_timer_proc_entry);
 		snd_timer_proc_entry = NULL;
 	}
-#ifdef CONFIG_SND_OSSEMUL
+#ifdef SNDRV_OSS_INFO_DEV_TIMERS
 	snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
 #endif
 }
diff -Nru a/sound/isa/es18xx.c b/sound/isa/es18xx.c
--- a/sound/isa/es18xx.c	Tue Oct 15 20:29:16 2002
+++ b/sound/isa/es18xx.c	Tue Oct 15 20:29:16 2002
@@ -1311,12 +1311,12 @@
 	if (chip->caps & ES18XX_CONTROL) {
 		/* Hardware volume IRQ */
 		snd_es18xx_config_write(chip, 0x27, chip->irq);
-		if (chip->fm_port > SNDRV_AUTO_PORT) {
+		if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) {
 			/* FM I/O */
 			snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8);
 			snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff);
 		}
-		if (chip->mpu_port > SNDRV_AUTO_PORT) {
+		if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
 			/* MPU-401 I/O */
 			snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8);
 			snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff);
@@ -1404,7 +1404,7 @@
 		snd_es18xx_mixer_write(chip, 0x7A, 0x68);
 		/* Enable and set hardware volume interrupt */
 		snd_es18xx_mixer_write(chip, 0x64, 0x06);
-		if (chip->mpu_port > SNDRV_AUTO_PORT) {
+		if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
 			/* MPU401 share irq with audio
 			   Joystick enabled
 			   FM enabled */
@@ -2040,7 +2040,7 @@
 	/* skip csn and logdev initialization - already done in isapnp_configure */
 	isapnp_cfg_begin(pdev->bus->number, pdev->devfn);
 	isapnp_write_byte(0x27, pdev->irq_resource[0].start);	/* Hardware Volume IRQ Number */
-	if (snd_mpu_port[dev] > SNDRV_AUTO_PORT)
+	if (snd_mpu_port[dev] != SNDRV_AUTO_PORT)
 		isapnp_write_byte(0x28, pdev->irq);		/* MPU-401 IRQ Number */
 	isapnp_write_byte(0x72, pdev->irq_resource[0].start);	/* second IRQ */
 	isapnp_cfg_end();
@@ -2147,16 +2147,18 @@
 		return err;
 	}
 
-	if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) {
-		printk(KERN_ERR PFX "opl3 not detected at 0x%lx\n", chip->port);
-	} else {
-		if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
-			snd_card_free(card);
-			return err;
+	if (snd_fm_port[dev] > 0 && snd_fm_port[dev] != SNDRV_AUTO_PORT) {
+		if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) {
+			printk(KERN_ERR PFX "opl3 not detected at 0x%lx\n", chip->fm_port);
+		} else {
+			if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
+				snd_card_free(card);
+				return err;
+			}
 		}
 	}
 
-	if (snd_mpu_port[dev] != SNDRV_AUTO_PORT) {
+	if (snd_mpu_port[dev] > 0 && snd_mpu_port[dev] != SNDRV_AUTO_PORT) {
 		if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX,
 					       chip->mpu_port, 0,
 					       irq, 0,
diff -Nru a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
--- a/sound/isa/opl3sa2.c	Tue Oct 15 20:29:22 2002
+++ b/sound/isa/opl3sa2.c	Tue Oct 15 20:29:22 2002
@@ -22,7 +22,6 @@
 #include <sound/driver.h>
 #include <asm/io.h>
 #include <linux/init.h>
-#include <linux/isapnp.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
 #ifndef LINUX_ISAPNP_H
diff -Nru a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c
--- a/sound/isa/sb/emu8000.c	Tue Oct 15 20:29:16 2002
+++ b/sound/isa/sb/emu8000.c	Tue Oct 15 20:29:16 2002
@@ -1138,11 +1138,13 @@
 		snd_emu8000_free(hw);
 		return err;
 	}
+#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 	if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
 			       sizeof(emu8000_t*), &awe) >= 0) {
 		strcpy(awe->name, "EMU-8000");
 		*(emu8000_t**)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
 	}
+#endif
 	if (awe_ret)
 		*awe_ret = awe;
 
diff -Nru a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
--- a/sound/isa/wavefront/wavefront_synth.c	Tue Oct 15 20:29:16 2002
+++ b/sound/isa/wavefront/wavefront_synth.c	Tue Oct 15 20:29:16 2002
@@ -114,7 +114,7 @@
 
 #ifdef WF_DEBUG
 
-#ifdef NEW_MACRO_VARARGS
+#if defined(NEW_MACRO_VARARGS) || __GNUC__ >= 3
 #define DPRINT(cond, ...) \
        if ((dev->debug & (cond)) == (cond)) { \
 	     snd_printk (__VA_ARGS__); \
diff -Nru a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
--- a/sound/oss/dmabuf.c	Tue Oct 15 20:29:11 2002
+++ b/sound/oss/dmabuf.c	Tue Oct 15 20:29:11 2002
@@ -443,6 +443,7 @@
 		       adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) {
 			long t = dmabuf_timeout(dmap);
 			spin_unlock_irqrestore(&dmap->lock,flags);
+			/* FIXME: not safe may miss events */
 			t = interruptible_sleep_on_timeout(&adev->out_sleeper, t);
 			spin_lock_irqsave(&dmap->lock,flags);
 			if (!t) {
@@ -521,12 +522,11 @@
 	if (!(adev->enable_bits & PCM_ENABLE_INPUT))
 		return 0;
 	if (dmap->dma_mode == DMODE_OUTPUT) {	/* Direction change */
-		unsigned long flags;
 		/* release lock - it's not recursive */
-		spin_unlock_irqrestore(&dmap->lock,flags);
+		spin_unlock_irq(&dmap->lock);
 		DMAbuf_sync(dev);
 		DMAbuf_reset(dev);
-		spin_lock_irqsave(&dmap->lock,flags);
+		spin_lock_irq(&dmap->lock);
 		dmap->dma_mode = DMODE_NONE;
 	}
 	if (!dmap->dma_mode) {
diff -Nru a/sound/pci/Config.help b/sound/pci/Config.help
--- a/sound/pci/Config.help	Tue Oct 15 20:29:13 2002
+++ b/sound/pci/Config.help	Tue Oct 15 20:29:13 2002
@@ -77,7 +77,7 @@
 
 CONFIG_SND_INTEL8X0
   Say 'Y' or 'M' to include support for Intel8x0 based soundcards,
-  SiS 7012, AMD768/8111 and NVidia NForce chips.
+  SiS 7012, AMD768/8111, NVidia NForce and ALi 5455 chips.
 
 CONFIG_SND_SONICVIBES
   Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
diff -Nru a/sound/pci/Config.in b/sound/pci/Config.in
--- a/sound/pci/Config.in	Tue Oct 15 20:29:16 2002
+++ b/sound/pci/Config.in	Tue Oct 15 20:29:16 2002
@@ -4,9 +4,9 @@
 comment 'PCI devices'
 
 dep_tristate 'ALi PCI Audio M5451' CONFIG_SND_ALI5451 $CONFIG_SND
-dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SND_CS46XX $CONFIG_SND
+dep_tristate 'Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x' CONFIG_SND_CS46XX $CONFIG_SND $CONFIG_SOUND_GAMEPORT
 dep_mbool '  Cirrus Logic (Sound Fusion) New DSP support (EXPERIMENTAL)' CONFIG_SND_CS46XX_NEW_DSP $CONFIG_SND_CS46XX $CONFIG_EXPERIMENTAL
-dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND
+dep_tristate 'Cirrus Logic (Sound Fusion) CS4281' CONFIG_SND_CS4281 $CONFIG_SND $CONFIG_SOUND_GAMEPORT
 dep_tristate 'EMU10K1 (SB Live! & Audigy, E-mu APS)' CONFIG_SND_EMU10K1 $CONFIG_SND
 dep_tristate 'Korg 1212 IO' CONFIG_SND_KORG1212 $CONFIG_SND
 dep_tristate 'NeoMagic NM256AV/ZX' CONFIG_SND_NM256 $CONFIG_SND
@@ -14,30 +14,19 @@
 dep_tristate 'RME Digi96, 96/8, 96/8 PRO' CONFIG_SND_RME96 $CONFIG_SND
 dep_tristate 'RME Digi9652 (Hammerfall)' CONFIG_SND_RME9652 $CONFIG_SND
 dep_tristate 'RME Hammerfall DSP Audio' CONFIG_SND_HDSP $CONFIG_SND
-dep_tristate 'Trident 4D-Wave DX/NX; SiS 7018' CONFIG_SND_TRIDENT $CONFIG_SND
+dep_tristate 'Trident 4D-Wave DX/NX; SiS 7018' CONFIG_SND_TRIDENT $CONFIG_SND $CONFIG_SOUND_GAMEPORT
 dep_tristate 'Yamaha YMF724/740/744/754' CONFIG_SND_YMFPCI $CONFIG_SND
 dep_tristate 'Avance Logic ALS4000' CONFIG_SND_ALS4000 $CONFIG_SND
 dep_tristate 'C-Media 8738, 8338' CONFIG_SND_CMIPCI $CONFIG_SND
 dep_tristate '(Creative) Ensoniq AudioPCI 1370' CONFIG_SND_ENS1370 $CONFIG_SND
 dep_tristate '(Creative) Ensoniq AudioPCI 1371/1373' CONFIG_SND_ENS1371 $CONFIG_SND
-dep_tristate 'ESS ES1938/1946 (Solo-1)' CONFIG_SND_ES1938 $CONFIG_SND
+dep_tristate 'ESS ES1938/1946 (Solo-1)' CONFIG_SND_ES1938 $CONFIG_SND $CONFIG_SOUND_GAMEPORT
 dep_tristate 'ESS ES1968/1978 (Maestro-1/2/2E)' CONFIG_SND_ES1968 $CONFIG_SND
 dep_tristate 'ESS Allegro/Maestro3' CONFIG_SND_MAESTRO3 $CONFIG_SND
 dep_tristate 'ForteMedia FM801' CONFIG_SND_FM801 $CONFIG_SND
 dep_tristate 'ICEnsemble ICE1712 (Envy24)' CONFIG_SND_ICE1712 $CONFIG_SND
 dep_tristate 'Intel i8x0/MX440, SiS 7012; Ali 5455; NForce Audio; AMD768/8111' CONFIG_SND_INTEL8X0 $CONFIG_SND
-dep_tristate 'S3 SonicVibes' CONFIG_SND_SONICVIBES $CONFIG_SND
+dep_tristate 'S3 SonicVibes' CONFIG_SND_SONICVIBES $CONFIG_SND $CONFIG_SOUND_GAMEPORT
 dep_tristate 'VIA 82C686A/B, 8233 South Bridge' CONFIG_SND_VIA82XX $CONFIG_SND
-
-# define gameport if necessary
-if [ "$CONFIG_INPUT_GAMEPORT" != "n" ]; then
-  if [ "$CONFIG_SND_CS4281" = "y" \
-       -o "$CONFIG_SND_ES1938" = "y" \
-       -o "$CONFIG_SND_CS46XX" = "y" \
-       -o "$CONFIG_SND_SONICVIBES" = "y" \
-       -o "$CONFIG_SND_TRIDENT" = "y" ]; then
-    define_tristate CONFIG_INPUT_GAMEPORT y
-  fi
-fi
 
 endmenu
diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
--- a/sound/pci/emu10k1/emufx.c	Tue Oct 15 20:29:17 2002
+++ b/sound/pci/emu10k1/emufx.c	Tue Oct 15 20:29:17 2002
@@ -862,6 +862,7 @@
 {
 	int tram;
 
+	memset(icode->tram_valid, 0, sizeof(icode->tram_valid));
 	for (tram = 0; tram < 0xa0; tram++) {
 		set_bit(tram, icode->tram_valid);
 		icode->tram_data_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0);
@@ -885,6 +886,7 @@
 {
 	u32 pc;
 
+	memset(icode->code_valid, 0, sizeof(icode->code_valid));
 	for (pc = 0; pc < 512; pc++) {
 		set_bit(pc, icode->code_valid);
 		icode->code[pc][0] = snd_emu10k1_efx_read(emu, pc * 2);
@@ -1031,7 +1033,7 @@
 	}
 }
 
-static void snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
+static int snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
 {
 	int i = 0, j;
 	unsigned int total = 0;
@@ -1044,7 +1046,7 @@
 	list_for_each(list, &emu->fx8010.gpr_ctl) {
 		ctl = emu10k1_gpr_ctl(list);
 		total++;
-		if (i < icode->gpr_list_control_count) {
+		if (_gctl && i < icode->gpr_list_control_count) {
 			memset(&gctl, 0, sizeof(gctl));
 			id = &ctl->kcontrol->id;
 			gctl.id.iface = id->iface;
@@ -1061,13 +1063,14 @@
 			gctl.min = ctl->min;
 			gctl.max = ctl->max;
 			gctl.translation = ctl->translation;
-			snd_runtime_check(copy_to_user(_gctl, &gctl, sizeof(gctl)) == 0, goto __next);
+			if (copy_to_user(_gctl, &gctl, sizeof(gctl)))
+				return -EFAULT;
+			_gctl++;
+			i++;
 		}
-	      __next:
-		_gctl++;
-		i++;
 	}
 	icode->gpr_list_control_total = total;
+	return 0;
 }
 
 static int snd_emu10k1_icode_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
@@ -1103,6 +1106,8 @@
 
 static int snd_emu10k1_icode_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode)
 {
+	int err;
+
 	down(&emu->fx8010.lock);
 	strncpy(icode->name, emu->fx8010.name, sizeof(icode->name)-1);
 	emu->fx8010.name[sizeof(emu->fx8010.name)-1] = '\0';
@@ -1110,9 +1115,9 @@
 	snd_emu10k1_gpr_peek(emu, icode);
 	snd_emu10k1_tram_peek(emu, icode);
 	snd_emu10k1_code_peek(emu, icode);
-	snd_emu10k1_list_controls(emu, icode);
+	err = snd_emu10k1_list_controls(emu, icode);
 	up(&emu->fx8010.lock);
-	return 0;
+	return err;
 }
 
 static int snd_emu10k1_ipcm_poke(emu10k1_t *emu, emu10k1_fx8010_pcm_t *ipcm)
@@ -2171,9 +2176,13 @@
 		kfree(icode);
 		return res;
 	case SNDRV_EMU10K1_IOCTL_CODE_PEEK:
-		icode = (emu10k1_fx8010_code_t *)snd_kcalloc(sizeof(*icode), GFP_KERNEL);
+		icode = (emu10k1_fx8010_code_t *)kmalloc(sizeof(*icode), GFP_KERNEL);
 		if (icode == NULL)
 			return -ENOMEM;
+		if (copy_from_user(icode, (void *)arg, sizeof(*icode))) {
+			kfree(icode);
+			return -EFAULT;
+		}
 		res = snd_emu10k1_icode_peek(emu, icode);
 		if (res == 0 && copy_to_user((void *)arg, icode, sizeof(*icode))) {
 			kfree(icode);
diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c
--- a/sound/pci/ens1370.c	Tue Oct 15 20:29:15 2002
+++ b/sound/pci/ens1370.c	Tue Oct 15 20:29:15 2002
@@ -30,8 +30,11 @@
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
+#ifdef CHIP1371
 #include <sound/ac97_codec.h>
+#else
 #include <sound/ak4531_codec.h>
+#endif
 #define SNDRV_GET_ID
 #include <sound/initval.h>
 
@@ -352,13 +355,16 @@
 	unsigned int rev;	/* chip revision */
 
 	union {
+#ifdef CHIP1371
 		struct {
 			ac97_t *ac97;
 		} es1371;
+#else
 		struct {
 			int pclkdiv_lock;
 			ak4531_t *ak4531;
 		} es1370;
+#endif
 	} u;
 
 	struct pci_dev *pci;
diff -Nru a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
--- a/sound/pci/ymfpci/ymfpci_main.c	Tue Oct 15 20:29:20 2002
+++ b/sound/pci/ymfpci/ymfpci_main.c	Tue Oct 15 20:29:21 2002
@@ -1538,6 +1538,7 @@
 YMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL),
 YMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL),
 YMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL),
+YMFPCI_DOUBLE("FM Legacy Volume", 0, YDSXGR_LEGACYOUTVOL),
 YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL),
 YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL),
 YMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL),
@@ -2022,6 +2023,7 @@
 	snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
 	snd_ymfpci_writel(chip, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
 	snd_ymfpci_writel(chip, YDSXGR_PRIADCLOOPVOL, 0x3fff3fff);
+	snd_ymfpci_writel(chip, YDSXGR_LEGACYOUTVOL, 0x3fff3fff);
 	
 	return 0;
 }
@@ -2036,6 +2038,7 @@
 	if (chip->res_reg_area) {	/* don't touch busy hardware */
 		snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
 		snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
+		snd_ymfpci_writel(chip, YDSXGR_LEGACYOUTVOL, 0);
 		snd_ymfpci_writel(chip, YDSXGR_STATUS, ~0);
 		snd_ymfpci_disable_dsp(chip);
 		snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0);
@@ -2100,6 +2103,7 @@
 	YDSXGR_SPDIFLOOPVOL,
 	YDSXGR_SPDIFOUTVOL,
 	YDSXGR_ZVOUTVOL,
+	YDSXGR_LEGACYOUTVOL,
 	/* address bases */
 	YDSXGR_PLAYCTRLBASE,
 	YDSXGR_RECCTRLBASE,
@@ -2112,7 +2116,7 @@
 	YDSXGR_ADCFORMAT,
 	YDSXGR_ADCSLOTSR,
 };
-#define YDSXGR_NUM_SAVED_REGS	(sizeof(saved_regs_index)/sizeof(saved_regs_index[0]))
+#define YDSXGR_NUM_SAVED_REGS	ARRAY_SIZE(saved_regs_index)
 
 void snd_ymfpci_suspend(ymfpci_t *chip)
 {
diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- a/sound/usb/usbaudio.c	Tue Oct 15 20:29:19 2002
+++ b/sound/usb/usbaudio.c	Tue Oct 15 20:29:19 2002
@@ -957,6 +957,19 @@
 	if (subs->interface >= 0 && subs->interface != fmt->iface) {
 		usb_set_interface(subs->dev, subs->interface, 0);
 		subs->interface = -1;
+		subs->format = 0;
+	}
+
+	/* set interface */
+	if (subs->interface != fmt->iface || subs->format != fmt->altset_idx) {
+		if (usb_set_interface(dev, fmt->iface, fmt->altset_idx) < 0) {
+			snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
+				   dev->devnum, fmt->iface, fmt->altsetting);
+			return -EIO;
+		}
+		snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altset_idx);
+		subs->interface = fmt->iface;
+		subs->format = fmt->altset_idx;
 	}
 
 	/* create a data pipe */
@@ -965,7 +978,6 @@
 		subs->datapipe = usb_sndisocpipe(dev, ep);
 	else
 		subs->datapipe = usb_rcvisocpipe(dev, ep);
-	subs->format = fmt->altset_idx;
 	subs->syncpipe = subs->syncinterval = 0;
 	subs->maxpacksize = alts->endpoint[0].wMaxPacketSize;
 	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
@@ -998,15 +1010,6 @@
 		subs->syncinterval = alts->endpoint[1].bRefresh;
 	}
 
-	/* set interface */
-	if (usb_set_interface(dev, fmt->iface, fmt->altset_idx) < 0) {
-		snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
-			   dev->devnum, fmt->iface, fmt->altsetting);
-		return -EIO;
-	}
-	snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altset_idx);
-	subs->interface = fmt->iface;
-
 	ep = alts->endpoint[0].bEndpointAddress;
 	/* if endpoint has pitch control, enable it */
 	if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) {
@@ -1171,6 +1174,7 @@
 	snd_usb_substream_t *subs = &as->substream[direction];
 
 	subs->interface = -1;
+	subs->format = 0;
 	runtime->hw = *hw;
 	runtime->private_data = subs;
 	subs->pcm_substream = substream;
@@ -1601,6 +1605,10 @@
 	/* FIXME: correct endianess and sign? */
 	pcm_format = -1;
 	switch (format) {
+	case 0: /* some devices don't define this correctly... */
+		snd_printd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n",
+			   dev->devnum, iface_no, altno);
+		/* fall-through */
 	case USB_AUDIO_FORMAT_PCM:
 		/* check the format byte size */
 		switch (fmt[6]) {
diff -Nru a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
--- a/sound/usb/usbmixer.c	Tue Oct 15 20:29:15 2002
+++ b/sound/usb/usbmixer.c	Tue Oct 15 20:29:15 2002
@@ -42,6 +42,9 @@
 /*
  */
 
+/* ignore error from controls - for debugging */
+/* #define IGNORE_CTL_ERROR */
+
 typedef struct usb_mixer_build mixer_build_t;
 typedef struct usb_audio_term usb_audio_term_t;
 typedef struct usb_mixer_elem_info usb_mixer_elem_info_t;
@@ -55,6 +58,8 @@
 	int name;
 };
 
+struct usbmix_name_map;
+
 struct usb_mixer_build {
 	snd_usb_audio_t *chip;
 	unsigned char *buffer;
@@ -62,6 +67,7 @@
 	unsigned int ctrlif;
 	DECLARE_BITMAP(unitbitmap, 32*32);
 	usb_audio_term_t oterm;
+	const struct usbmix_name_map *map;
 };
 
 struct usb_mixer_elem_info {
@@ -78,7 +84,8 @@
 
 
 enum {
-	USB_FEATURE_MUTE = 0,
+	USB_FEATURE_NONE = 0,
+	USB_FEATURE_MUTE = 1,
 	USB_FEATURE_VOLUME,
 	USB_FEATURE_BASS,
 	USB_FEATURE_MID,
@@ -99,10 +106,72 @@
 	USB_MIXER_U16,
 };
 
+enum {
+	USB_PROC_UPDOWN = 1,
+	USB_PROC_UPDOWN_SWITCH = 1,
+	USB_PROC_UPDOWN_MODE_SEL = 2,
+
+	USB_PROC_PROLOGIC = 2,
+	USB_PROC_PROLOGIC_SWITCH = 1,
+	USB_PROC_PROLOGIC_MODE_SEL = 2,
+
+	USB_PROC_3DENH = 3,
+	USB_PROC_3DENH_SWITCH = 1,
+	USB_PROC_3DENH_SPACE = 2,
+
+	USB_PROC_REVERB = 4,
+	USB_PROC_REVERB_SWITCH = 1,
+	USB_PROC_REVERB_LEVEL = 2,
+	USB_PROC_REVERB_TIME = 3,
+	USB_PROC_REVERB_DELAY = 4,
+
+	USB_PROC_CHORUS = 5,
+	USB_PROC_CHORUS_SWITCH = 1,
+	USB_PROC_CHORUS_LEVEL = 2,
+	USB_PROC_CHORUS_RATE = 3,
+	USB_PROC_CHORUS_DEPTH = 4,
+
+	USB_PROC_DCR = 6,
+	USB_PROC_DCR_SWITCH = 1,
+	USB_PROC_DCR_RATIO = 2,
+	USB_PROC_DCR_MAX_AMP = 3,
+	USB_PROC_DCR_THRESHOLD = 4,
+	USB_PROC_DCR_ATTACK = 5,
+	USB_PROC_DCR_RELEASE = 6,
+};
+
 #define MAX_CHANNELS	10	/* max logical channels */
 
 
 /*
+ * manual mapping of mixer names
+ * if the mixer topology is too complicated and the parsed names are
+ * ambiguous, add the entries in usbmixer_maps.c.
+ */
+#include "usbmixer_maps.c"
+
+/* get the mapped name if the unit matches */
+static int check_mapped_name(mixer_build_t *state, int unitid, int control, char *buf, int buflen)
+{
+	const struct usbmix_name_map *p;
+
+	if (! state->map)
+		return 0;
+
+	for (p = state->map; p->id; p++) {
+		if (p->id == unitid &&
+		    (! control || ! p->control || control == p->control)) {
+			buflen--;
+			strncpy(buf, p->name, buflen);
+			buf[buflen] = 0;
+			return strlen(buf);
+		}
+	}
+	return 0;
+}
+
+
+/*
  * find an audio control unit with the given unit id
  */
 static void *find_audio_control_unit(mixer_build_t *state, unsigned char unit)
@@ -213,8 +282,10 @@
 			    request,
 			    USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
 			    validx, cval->ctrlif | (cval->id << 8),
-			    buf, val_len, HZ) < 0)
+			    buf, val_len, HZ) < 0) {
+		snd_printdd(KERN_ERR "cannot get ctl value: req = 0x%x, idx = 0x%x, val = 0x%x, type = %d\n", request, validx, cval->ctrlif | (cval->id << 8), cval->val_type);
 		return -EINVAL;
+	}
 	*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
 	return 0;
 }
@@ -227,7 +298,7 @@
 /* channel = 0: master, 1 = first channel */
 inline static int get_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int *value)
 {
-	return get_ctl_value(cval, GET_CUR, ((cval->control + 1) << 8) | channel, value);
+	return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value);
 }
 
 /*
@@ -256,7 +327,7 @@
 
 inline static int set_cur_mix_value(usb_mixer_elem_info_t *cval, int channel, int value)
 {
-	return set_ctl_value(cval, SET_CUR, ((cval->control + 1) << 8) | channel, value);
+	return set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, value);
 }
 
 
@@ -291,7 +362,7 @@
 	while (snd_ctl_find_id(card, &kctl->id))
 		kctl->id.index++;
 	if ((err = snd_ctl_add(card, kctl)) < 0) {
-		snd_printk(KERN_ERR "cannot add control\n");
+		snd_printd(KERN_ERR "cannot add control (err = %d)\n", err);
 		snd_ctl_free_one(kctl);
 	}
 	return err;
@@ -483,6 +554,39 @@
  * interface to ALSA control for feature/mixer units
  */
 
+/*
+ * retrieve the minimum and maximum values for the specified control
+ */
+static int get_min_max(usb_mixer_elem_info_t *cval)
+{
+	/* for failsafe */
+	cval->min = 0;
+	cval->max = 1;
+
+	if (cval->val_type == USB_MIXER_BOOLEAN ||
+	    cval->val_type == USB_MIXER_INV_BOOLEAN) {
+		cval->initialized = 1;
+	} else {
+		int minchn = 0;
+		if (cval->cmask) {
+			int i;
+			for (i = 0; i < MAX_CHANNELS; i++)
+				if (cval->cmask & (1 << i)) {
+					minchn = i + 1;
+					break;
+				}
+		}
+		if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
+		    get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
+			snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", cval->id, cval->ctrlif, cval->control, cval->id);
+			return -EINVAL;
+		}
+		cval->initialized = 1;
+	}
+	return 0;
+}
+
+
 /* get a feature/mixer unit info */
 static int mixer_ctl_feature_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
 {	
@@ -499,23 +603,8 @@
 		uinfo->value.integer.min = 0;
 		uinfo->value.integer.max = 1;
 	} else {
-		if (! cval->initialized) {
-			int minchn = 0;
-			if (cval->cmask) {
-				int i;
-				for (i = 0; i < MAX_CHANNELS; i++)
-					if (cval->cmask & (1 << i)) {
-						minchn = i + 1;
-						break;
-					}
-			}
-			if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | minchn, &cval->max) < 0 ||
-			    get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | minchn, &cval->min) < 0) {
-				snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, cval->control);
-				return -EINVAL;
-			}
-			cval->initialized = 1;
-		}
+		if (! cval->initialized)
+			get_min_max(cval);
 		uinfo->value.integer.min = 0;
 		uinfo->value.integer.max = cval->max - cval->min;
 	}
@@ -533,8 +622,14 @@
 		for (c = 0; c < MAX_CHANNELS; c++) {
 			if (cval->cmask & (1 << c)) {
 				err = get_cur_mix_value(cval, c + 1, &val);
+#ifdef IGNORE_CTL_ERROR
 				if (err < 0) {
-					printk("cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
+					ucontrol->value.integer.value[0] = cval->min;
+					return 0;
+				}
+#endif
+				if (err < 0) {
+					snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
 					return err;
 				}
 				val = get_relative_value(cval, val);
@@ -545,8 +640,14 @@
 	} else {
 		/* master channel */
 		err = get_cur_mix_value(cval, 0, &val);
+#ifdef IGNORE_CTL_ERROR
+		if (err < 0) {
+			ucontrol->value.integer.value[0] = cval->min;
+			return 0;
+		}
+#endif
 		if (err < 0) {
-			printk("cannot get current value for control %d master ch: err = %d\n", cval->control, err);
+			snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err);
 			return err;
 		}
 		val = get_relative_value(cval, val);
@@ -567,6 +668,10 @@
 		for (c = 0; c < MAX_CHANNELS; c++) {
 			if (cval->cmask & (1 << c)) {
 				err = get_cur_mix_value(cval, c + 1, &oval);
+#ifdef IGNORE_CTL_ERROR
+				if (err < 0)
+					return 0;
+#endif
 				if (err < 0)
 					return err;
 				val = ucontrol->value.integer.value[cnt];
@@ -581,6 +686,10 @@
 	} else {
 		/* master channel */
 		err = get_cur_mix_value(cval, 0, &oval);
+#ifdef IGNORE_CTL_ERROR
+		if (err < 0)
+			return 0;
+#endif
 		if (err < 0)
 			return err;
 		val = ucontrol->value.integer.value[0];
@@ -610,11 +719,12 @@
 			      unsigned int ctl_mask, int control,
 			      usb_audio_term_t *iterm, int unitid)
 {
-	int len = 0;
+	int len = 0, mapped_name = 0;
 	int nameid = desc[desc[0] - 1];
 	snd_kcontrol_t *kctl;
 	usb_mixer_elem_info_t *cval;
-	int minchn = 0;
+
+	control++; /* change from zero-based to 1-based value */
 
 	if (control == USB_FEATURE_GEQ) {
 		/* FIXME: not supported yet */
@@ -623,7 +733,7 @@
 
 	cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
 	if (! cval) {
-		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
 		return;
 	}
 	cval->chip = state->chip;
@@ -631,42 +741,31 @@
 	cval->id = unitid;
 	cval->control = control;
 	cval->cmask = ctl_mask;
-	cval->val_type = audio_feature_info[control].type;
+	cval->val_type = audio_feature_info[control-1].type;
 	if (ctl_mask == 0)
 		cval->channels = 1;	/* master channel */
 	else {
 		int i, c = 0;
 		for (i = 0; i < 16; i++)
-			if (ctl_mask & (1 << i)) {
-				if (! minchn)
-					minchn = i + 1;
+			if (ctl_mask & (1 << i))
 				c++;
-			}
 		cval->channels = c;
 	}
 
 	/* get min/max values */
-	if (cval->val_type == USB_MIXER_BOOLEAN ||
-	    cval->val_type == USB_MIXER_INV_BOOLEAN) {
-		cval->max = 1;
-		cval->initialized = 1;
-	} else {
-		if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | minchn, &cval->max) < 0 ||
-		    get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | minchn, &cval->min) < 0)
-			snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, control);
-		else
-			cval->initialized = 1;
-	}
+	get_min_max(cval);
 
 	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
 	if (! kctl) {
-		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
 		snd_magic_kfree(cval);
 		return;
 	}
 	kctl->private_free = usb_mixer_elem_free;
 
-	if (nameid)
+	len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name));
+	mapped_name = len != 0;
+	if (! len && nameid)
 		len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
 
 	switch (control) {
@@ -679,7 +778,7 @@
 		 * - if the connected output can be determined, use it.
 		 * - otherwise, anonymous name.
 		 */
-		if (! nameid) {
+		if (! len) {
 			len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 1);
 			if (! len)
 				len = get_term_name(state, &state->oterm, kctl->id.name, sizeof(kctl->id.name), 1);
@@ -690,21 +789,26 @@
 		 * if the connected output is USB stream, then it's likely a
 		 * capture stream.  otherwise it should be playback (hopefully :)
 		 */
-		if (! (state->oterm.type >> 16)) {
+		if (! mapped_name && ! (state->oterm.type >> 16)) {
 			if ((state->oterm.type & 0xff00) == 0x0100) {
-				strcpy(kctl->id.name + len, " Capture");
-				len += 8;
+				if (len + 8 < sizeof(kctl->id.name)) {
+					strcpy(kctl->id.name + len, " Capture");
+					len += 8;
+				}
 			} else {
-				strcpy(kctl->id.name + len, " Playback");
-				len += 9;
+				if (len + 9 < sizeof(kctl->id.name)) {
+					strcpy(kctl->id.name + len, " Playback");
+					len += 9;
+				}
 			}
 		}
-		strcpy(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume");
+		if (len + 7 < sizeof(kctl->id.name))
+			strcpy(kctl->id.name + len, control == USB_FEATURE_MUTE ? " Switch" : " Volume");
 		break;
 
 	default:
-		if (! nameid)
-			strcpy(kctl->id.name, audio_feature_info[control].name);
+		if (! len)
+			strcpy(kctl->id.name, audio_feature_info[control-1].name);
 		break;
 	}
 
@@ -785,7 +889,6 @@
 	int i, len;
 	snd_kcontrol_t *kctl;
 	usb_audio_term_t iterm;
-	int minchn = 0;
 
 	cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
 	if (! cval)
@@ -797,36 +900,33 @@
 	cval->chip = state->chip;
 	cval->ctrlif = state->ctrlif;
 	cval->id = unitid;
-	cval->control = in_ch;
+	cval->control = in_ch + 1; /* based on 1 */
 	cval->val_type = USB_MIXER_S16;
 	for (i = 0; i < num_outs; i++) {
 		if (check_matrix_bitmap(desc + 9 + num_ins, in_ch, i, num_outs)) {
 			cval->cmask |= (1 << i);
 			cval->channels++;
-			if (! minchn)
-				minchn = i + 1;
 		}
 	}
 
 	/* get min/max values */
-	if (get_ctl_value(cval, GET_MAX, ((in_ch+1) << 8) | minchn, &cval->max) < 0 ||
-	    get_ctl_value(cval, GET_MIN, ((in_ch+1) << 8) | minchn, &cval->min) < 0)
-		snd_printk(KERN_ERR "cannot get min/max values for mixer\n");
-	else
-		cval->initialized = 1;
+	get_min_max(cval);
 
 	kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
 	if (! kctl) {
-		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
 		snd_magic_kfree(cval);
 		return;
 	}
 	kctl->private_free = usb_mixer_elem_free;
 
-	len = get_term_name(state, &iterm, kctl->id.name, sizeof(kctl->id.name), 0);
+	len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name));
+	if (! len)
+		len = get_term_name(state, &iterm, kctl->id.name, sizeof(kctl->id.name), 0);
 	if (! len)
 		len = sprintf(kctl->id.name, "Mixer Source %d", in_ch);
-	strcpy(kctl->id.name + len, " Volume");
+	if (len + 7 < sizeof(kctl->id.name))
+		strcpy(kctl->id.name + len, " Volume");
 
 	snd_printdd(KERN_INFO "[%d] MU [%s] ch = %d, val = %d/%d\n",
 		    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
@@ -866,6 +966,12 @@
 	int err, val;
 
 	err = get_cur_ctl_value(cval, cval->control, &val);
+#ifdef IGNORE_CTL_ERROR
+	if (err < 0) {
+		ucontrol->value.integer.value[0] = cval->min;
+		return 0;
+	}
+#endif
 	if (err < 0)
 		return err;
 	val = get_relative_value(cval, val);
@@ -880,6 +986,10 @@
 	int val, oval, err;
 
 	err = get_cur_ctl_value(cval, cval->control, &oval);
+#ifdef IGNORE_CTL_ERROR
+	if (err < 0)
+		return 0;
+#endif
 	if (err < 0)
 		return err;
 	val = ucontrol->value.integer.value[0];
@@ -917,51 +1027,51 @@
 };
 
 static struct procunit_value_info updown_proc_info[] = {
-	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
-	{ 0x02, "Mode Select", USB_MIXER_U8 },
+	{ USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN },
+	{ USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8 },
 	{ 0 }
 };
 static struct procunit_value_info prologic_proc_info[] = {
-	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
-	{ 0x02, "Mode Select", USB_MIXER_U8 },
+	{ USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN },
+	{ USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8 },
 	{ 0 }
 };
 static struct procunit_value_info threed_enh_proc_info[] = {
-	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
-	{ 0x02, "Spaciousness", USB_MIXER_U8 },
+	{ USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN },
+	{ USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 },
 	{ 0 }
 };
 static struct procunit_value_info reverb_proc_info[] = {
-	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
-	{ 0x02, "Level", USB_MIXER_U8 },
-	{ 0x03, "Time", USB_MIXER_U16 },
-	{ 0x04, "Delay", USB_MIXER_U8 },
+	{ USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN },
+	{ USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 },
+	{ USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 },
+	{ USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 },
 	{ 0 }
 };
 static struct procunit_value_info chorus_proc_info[] = {
-	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
-	{ 0x02, "Level", USB_MIXER_U8 },
-	{ 0x03, "Rate", USB_MIXER_U16 },
-	{ 0x04, "Depth", USB_MIXER_U16 },
+	{ USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN },
+	{ USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 },
+	{ USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 },
+	{ USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 },
 	{ 0 }
 };
 static struct procunit_value_info dcr_proc_info[] = {
-	{ 0x01, "Switch", USB_MIXER_BOOLEAN },
-	{ 0x02, "Ratio", USB_MIXER_U16 },
-	{ 0x03, "Max Amp", USB_MIXER_S16 },
-	{ 0x04, "Threshold", USB_MIXER_S16 },
-	{ 0x05, "Attack Time", USB_MIXER_U16 },
-	{ 0x06, "Release Time", USB_MIXER_U16 },
+	{ USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN },
+	{ USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 },
+	{ USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 },
+	{ USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 },
+	{ USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 },
+	{ USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 },
 	{ 0 }
 };
 
 static struct procunit_info procunits[] = {
-	{ 0x01, "Up Down", updown_proc_info },
-	{ 0x02, "Dolby Prologic", prologic_proc_info },
-	{ 0x03, "3D Stereo Extender", threed_enh_proc_info },
-	{ 0x04, "Reverb", reverb_proc_info },
-	{ 0x05, "Chorus", chorus_proc_info },
-	{ 0x06, "DCR", dcr_proc_info },
+	{ USB_PROC_UPDOWN, "Up Down", updown_proc_info },
+	{ USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info },
+	{ USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info },
+	{ USB_PROC_REVERB, "Reverb", reverb_proc_info },
+	{ USB_PROC_CHORUS, "Chorus", chorus_proc_info },
+	{ USB_PROC_DCR, "DCR", dcr_proc_info },
 	{ 0 },
 };
 
@@ -973,7 +1083,7 @@
 	int num_ins = dsc[6];
 	usb_mixer_elem_info_t *cval;
 	snd_kcontrol_t *kctl;
-	int i, err, nameid, type;
+	int i, err, nameid, type, len;
 	struct procunit_info *info;
 	struct procunit_value_info *valinfo;
 	static struct procunit_value_info default_value_info[] = {
@@ -985,7 +1095,7 @@
 	};
 
 	if (dsc[0] < 13 || dsc[0] < 13 + num_ins || dsc[0] < num_ins + dsc[11 + num_ins]) {
-		snd_printk(KERN_ERR "invalid %s descriptor %d\n", name, unitid);
+		snd_printk(KERN_ERR "invalid %s descriptor (id %d)\n", name, unitid);
 		return -EINVAL;
 	}
 
@@ -1010,7 +1120,7 @@
 			continue;
 		cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
 		if (! cval) {
-			snd_printk(KERN_ERR "cannot malloc kcontrol");
+			snd_printk(KERN_ERR "cannot malloc kcontrol\n");
 			return -ENOMEM;
 		}
 		cval->chip = state->chip;
@@ -1021,31 +1131,35 @@
 		cval->channels = 1;
 
 		/* get min/max values */
-		if (get_ctl_value(cval, GET_MAX, cval->control, &cval->max) < 0 ||
-		    get_ctl_value(cval, GET_MIN, cval->control, &cval->min) < 0)
-			snd_printk(KERN_ERR "cannot get min/max values for proc/ext unit\n");
-		else
-			cval->initialized = 1;
+		get_min_max(cval);
 
 		kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
 		if (! kctl) {
-			snd_printk(KERN_ERR "cannot malloc kcontrol");
+			snd_printk(KERN_ERR "cannot malloc kcontrol\n");
 			snd_magic_kfree(cval);
 			return -ENOMEM;
 		}
 		kctl->private_free = usb_mixer_elem_free;
 
-		if (info->name)
-			sprintf(kctl->id.name, "%s %s", info->name, valinfo->suffix);
+		if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name)))
+			;
+		else if (info->name)
+			strcpy(kctl->id.name, info->name);
 		else {
 			nameid = dsc[12 + num_ins + dsc[11 + num_ins]];
-			if (nameid) {
-				int len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
-				strcpy(kctl->id.name + len, valinfo->suffix);
-			} else
-				sprintf(kctl->id.name, "%s %s", name, valinfo->suffix);
+			len = 0;
+			if (nameid)
+				len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
+			if (! len) {
+				strncpy(kctl->id.name, name, sizeof(kctl->id.name) - 1);
+				kctl->id.name[sizeof(kctl->id.name)-1] = 0;
+			}
+		}
+		len = strlen(kctl->id.name);
+		if (len + sizeof(valinfo->suffix) + 1 < sizeof(kctl->id.name)) {
+			kctl->id.name[len] = ' ';
+			strcpy(kctl->id.name + len + 1, valinfo->suffix);
 		}
-
 		snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n",
 			    cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
 		if ((err = add_control_to_empty(state->chip->card, kctl)) < 0)
@@ -1095,6 +1209,12 @@
 	int val, err;
 
 	err = get_cur_ctl_value(cval, 0, &val);
+#ifdef IGNORE_CTL_ERROR
+	if (err < 0) {
+		ucontrol->value.enumerated.item[0] = 0;
+		return 0;
+	}
+#endif
 	if (err < 0)
 		return err;
 	val = get_relative_value(cval, val);
@@ -1109,6 +1229,10 @@
 	int val, oval, err;
 
 	err = get_cur_ctl_value(cval, 0, &oval);
+#ifdef IGNORE_CTL_ERROR
+	if (err < 0)
+		return 0;
+#endif
 	if (err < 0)
 		return err;
 	val = ucontrol->value.enumerated.item[0];
@@ -1158,7 +1282,7 @@
 static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned char *desc)
 {
 	int num_ins = desc[4];
-	int i, err, nameid;
+	int i, err, nameid, len;
 	usb_mixer_elem_info_t *cval;
 	snd_kcontrol_t *kctl;
 	char **namelist;
@@ -1175,7 +1299,7 @@
 
 	cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
 	if (! cval) {
-		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
 		return -ENOMEM;
 	}
 	cval->chip = state->chip;
@@ -1196,7 +1320,7 @@
 #define MAX_ITEM_NAME_LEN	64
 	for (i = 0; i < num_ins; i++) {
 		usb_audio_term_t iterm;
-		int len = 0;
+		len = 0;
 		namelist[i] = kmalloc(MAX_ITEM_NAME_LEN, GFP_KERNEL);
 		if (! namelist[i]) {
 			snd_printk(KERN_ERR "cannot malloc\n");
@@ -1214,7 +1338,7 @@
 
 	kctl = snd_ctl_new1(&mixer_selectunit_ctl, cval);
 	if (! kctl) {
-		snd_printk(KERN_ERR "cannot malloc kcontrol");
+		snd_printk(KERN_ERR "cannot malloc kcontrol\n");
 		snd_magic_kfree(cval);
 		return -ENOMEM;
 	}
@@ -1222,17 +1346,23 @@
 	kctl->private_free = usb_mixer_selector_elem_free;
 
 	nameid = desc[desc[0] - 1];
-	if (nameid)
+	len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name));
+	if (len)
+		;
+	else if (nameid)
 		snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name));
 	else {
-		int len = get_term_name(state, &state->oterm,
-					kctl->id.name, sizeof(kctl->id.name), 0);
+		len = get_term_name(state, &state->oterm,
+				    kctl->id.name, sizeof(kctl->id.name), 0);
 		if (! len)
 			len = sprintf(kctl->id.name, "USB");
-		if ((state->oterm.type & 0xff00) == 0x0100)
-			strcpy(kctl->id.name + len, " Capture Source");
-		else
-			strcpy(kctl->id.name + len, " Playback Source");
+		if ((state->oterm.type & 0xff00) == 0x0100) {
+			if (len + 15 < sizeof(kctl->id.name))
+				strcpy(kctl->id.name + len, " Capture Source");
+		} else {
+			if (len + 16 < sizeof(kctl->id.name))
+				strcpy(kctl->id.name + len, " Playback Source");
+		}
 	}
 
 	snd_printdd(KERN_INFO "[%d] SU [%s] items = %d\n",
@@ -1290,6 +1420,8 @@
 	unsigned char *desc;
 	mixer_build_t state;
 	int err;
+	const struct usbmix_ctl_map *map;
+	struct usb_device_descriptor *dev = &chip->dev->descriptor;
 
 	strcpy(chip->card->mixername, "USB Mixer");
 
@@ -1298,6 +1430,15 @@
 	state.buffer = buffer;
 	state.buflen = buflen;
 	state.ctrlif = ctrlif;
+
+	/* check the mapping table */
+	for (map = usbmix_ctl_maps; map->vendor; map++) {
+		if (map->vendor == dev->idVendor && map->product == dev->idProduct) {
+			state.map = map->map;
+			break;
+		}
+	}
+
 	desc = NULL;
 	while ((desc = snd_usb_find_csint_desc(buffer, buflen, desc, OUTPUT_TERMINAL, ctrlif, -1)) != NULL) {
 		if (desc[0] < 9)
diff -Nru a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/usb/usbmixer_maps.c	Tue Oct 15 20:29:25 2002
@@ -0,0 +1,100 @@
+/*
+ *   Additional mixer mapping
+ *
+ *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+
+struct usbmix_name_map {
+	int id;
+	const char *name;
+	int control;
+};
+
+struct usbmix_ctl_map {
+	int vendor;
+	int product;
+	const struct usbmix_name_map *map;
+};
+	
+/*
+ * USB control mappers for SB Exitigy
+ */
+
+/*
+ * Topology of SB Extigy (see on the wide screen :)
+
+USB_IN[1] --->FU[2]------------------------------+->MU[16]-->PE[17]-+->FU[18]--+->EU[27]--+->EU[21]-->FU[22]--+->FU[23] > Dig_OUT[24]
+                                                 ^                  |          |          |                   |
+USB_IN[3] -+->SU[5]-->FU[6]--+->MU[14] ->PE[15]->+                  |          |          |                   +->FU[25] > Dig_OUT[26]
+           ^                 ^                   |                  |          |          |
+Dig_IN[4] -+                 |                   |                  |          |          +->FU[28]---------------------> Spk_OUT[19]
+                             |                   |                  |          |
+Lin-IN[7] -+-->FU[8]---------+                   |                  |          +----------------------------------------> Hph_OUT[20]
+           |                                     |                  |
+Mic-IN[9] --+->FU[10]----------------------------+                  |
+           ||                                                       |
+           ||  +----------------------------------------------------+
+           VV  V
+           ++--+->SU[11]-->FU[12] --------------------------------------------------------------------------------------> USB_OUT[13]
+*/
+
+static struct usbmix_name_map extigy_map[] = {
+	/* 1: IT pcm */
+	{ 2, "PCM Playback" }, /* FU */
+	/* 3: IT pcm */
+	/* 4: IT digital in */
+	{ 5, "Digital In Playback Source" }, /* SU */
+	{ 6, "Digital In" }, /* FU */
+	/* 7: IT line */
+	{ 8, "Line Playback" }, /* FU */
+	/* 9: IT mic */
+	{ 10, "Mic Playback" }, /* FU */
+	{ 11, "Capture Source" }, /* SU */
+	{ 12, "Capture" }, /* FU */
+	/* 13: OT pcm capture */
+	/* 14: MU (w/o controls) */
+	/* 15: PE (3D enh) */
+	/* 16: MU (w/o controls) */
+	/* 17: PE (updown) */		/* FIXME: what control? */
+	{ 18, "Tone Control - Bass", USB_FEATURE_BASS }, /* FU */
+	{ 18, "Tone Control - Treble", USB_FEATURE_TREBLE }, /* FU */
+	{ 18, "Master Playback" }, /* FU; others */
+	/* 19: OT speaker */
+	/* 20: OT headphone */
+	{ 21, "Digital Out Extension" }, /* EU */ /* FIXME: what? */
+	{ 22, "Digital Out Playback" }, /* FU */
+	{ 23, "Digital Out1 Playback" }, /* FU */  /* FIXME: corresponds to 24 */
+	/* 24: OT digital out */
+	{ 25, "Digital Out2 Playback" }, /* FU */  /* FIXME: corresponds to 26 */
+	/* 26: OT digital out */
+	{ 27, "Output Extension" }, /* EU */ /* FIXME: what? */
+	/* 28: FU (mute) */
+	{ 0 } /* terminator */
+};
+
+
+/*
+ * Control map entries
+ */
+
+static struct usbmix_ctl_map usbmix_ctl_maps[] = {
+	{ 0x41e, 0x3000, extigy_map },
+	{ 0 } /* terminator */
+};
+
diff -Nru a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
--- a/sound/usb/usbquirks.h	Tue Oct 15 20:29:16 2002
+++ b/sound/usb/usbquirks.h	Tue Oct 15 20:29:16 2002
@@ -38,7 +38,7 @@
 
 /* Yamaha devices */
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1000),
+	USB_DEVICE(0x0499, 0x1000),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "UX256",
@@ -47,7 +47,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1001),
+	USB_DEVICE(0x0499, 0x1001),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "MU1000",
@@ -56,7 +56,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1002),
+	USB_DEVICE(0x0499, 0x1002),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "MU2000",
@@ -65,7 +65,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1003),
+	USB_DEVICE(0x0499, 0x1003),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "MU500",
@@ -74,7 +74,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1004),
+	USB_DEVICE(0x0499, 0x1004),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "UW500",
@@ -83,7 +83,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1005),
+	USB_DEVICE(0x0499, 0x1005),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "MOTIF6",
@@ -92,7 +92,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1006),
+	USB_DEVICE(0x0499, 0x1006),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "MOTIF7",
@@ -101,7 +101,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1007),
+	USB_DEVICE(0x0499, 0x1007),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "MOTIF8",
@@ -110,7 +110,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1008),
+	USB_DEVICE(0x0499, 0x1008),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "UX96",
@@ -119,7 +119,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1009),
+	USB_DEVICE(0x0499, 0x1009),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "UX16",
@@ -128,7 +128,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x100a),
+	USB_DEVICE(0x0499, 0x100a),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "EOS BX",
@@ -137,7 +137,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x100e),
+	USB_DEVICE(0x0499, 0x100e),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "S08",
@@ -146,7 +146,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x100f),
+	USB_DEVICE(0x0499, 0x100f),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "CLP-150",
@@ -155,7 +155,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0499, 0x1010),
+	USB_DEVICE(0x0499, 0x1010),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Yamaha",
 		.product_name = "CLP-170",
@@ -177,7 +177,7 @@
  * class-specific descriptors.
  */
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0000),
+	USB_DEVICE(0x0582, 0x0000),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
 		.product_name = "UA-100",
@@ -191,7 +191,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0002),
+	USB_DEVICE(0x0582, 0x0002),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-4",
@@ -205,7 +205,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0003),
+	USB_DEVICE(0x0582, 0x0003),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
 		.product_name = "SC-8850",
@@ -219,7 +219,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0004),
+	USB_DEVICE(0x0582, 0x0004),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
 		.product_name = "U-8",
@@ -233,7 +233,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0005),
+	USB_DEVICE(0x0582, 0x0005),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-2",
@@ -247,7 +247,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0007),
+	USB_DEVICE(0x0582, 0x0007),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
 		.product_name = "SC-8820",
@@ -261,7 +261,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0008),
+	USB_DEVICE(0x0582, 0x0008),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
 		.product_name = "PC-300",
@@ -275,7 +275,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0009),
+	USB_DEVICE(0x0582, 0x0009),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-1",
@@ -289,7 +289,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x000b),
+	USB_DEVICE(0x0582, 0x000b),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
 		.product_name = "SK-500",
@@ -303,7 +303,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x000c),
+	USB_DEVICE(0x0582, 0x000c),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
 		.product_name = "SC-D70",
@@ -317,7 +317,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0012),
+	USB_DEVICE(0x0582, 0x0012),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "Roland",
 		.product_name = "XV-5050",
@@ -331,7 +331,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0014),
+	USB_DEVICE(0x0582, 0x0014),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-880",
@@ -345,7 +345,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0016),
+	USB_DEVICE(0x0582, 0x0016),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "SD-90",
@@ -359,7 +359,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0023),
+	USB_DEVICE(0x0582, 0x0023),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "UM-550",
@@ -373,7 +373,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0027),
+	USB_DEVICE(0x0582, 0x0027),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "SD-20",
@@ -387,7 +387,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x0029),
+	USB_DEVICE(0x0582, 0x0029),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "SD-80",
@@ -401,7 +401,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0582, 0x002b),
+	USB_DEVICE(0x0582, 0x002b),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "EDIROL",
 		.product_name = "UA-700",
@@ -467,7 +467,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0763, 0x2001),
+	USB_DEVICE(0x0763, 0x2001),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "M-Audio",
 		.product_name = "Quattro",
@@ -477,7 +477,7 @@
 	}
 },
 {
-	USB_DEVICE_VENDOR_SPEC(0x0763, 0x2003),
+	USB_DEVICE(0x0763, 0x2003),
 	.driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) {
 		.vendor_name = "M-Audio",
 		.product_name = "AudioPhile",
