## Automatically generated incremental diff
## From:   linux-2.4.22-bk31
## To:     linux-2.4.22-bk32
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.4.22-bk31/CREDITS linux-2.4.22-bk32/CREDITS
--- linux-2.4.22-bk31/CREDITS	2003-10-10 02:50:37.000000000 -0700
+++ linux-2.4.22-bk32/CREDITS	2003-10-10 02:50:45.000000000 -0700
@@ -2976,7 +2976,7 @@
 
 N: Marcelo W. Tosatti
 E: marcelo@parcelfarce.linux.theplanet.co.uk
-E: marcelo.tosatti@cyclades.com.br
+E: marcelo.tosatti@cyclades.com
 D: Miscellaneous kernel hacker (mostly VM/MM work)
 D: 2.4 maintainer
 S: Av Cristovao Colombo, 462. Floresta.
diff -urN linux-2.4.22-bk31/Documentation/Configure.help linux-2.4.22-bk32/Documentation/Configure.help
--- linux-2.4.22-bk31/Documentation/Configure.help	2003-10-10 02:50:37.000000000 -0700
+++ linux-2.4.22-bk32/Documentation/Configure.help	2003-10-10 02:50:45.000000000 -0700
@@ -100,6 +100,15 @@
   like MGA monitors that you are very unlikely to see on today's
   systems.
 
+Prompt for advanced kernel configuration options
+CONFIG_ADVANCED_OPTIONS
+  This option will enable prompting for a variety of advanced kernel
+  configuration options.  These options can cause the kernel to not
+  work if they are set incorrectly, but can be used to optimize certain
+  aspects of kernel memory management.
+
+  Unless you know what you are doing you *should not* enable this option.
+
 Symmetric Multi-Processing support
 CONFIG_SMP
   This enables support for systems with more than one CPU. If you have
@@ -9051,9 +9060,11 @@
 
 AMI MegaRAID support (old driver)
 CONFIG_SCSI_MEGARAID
-  This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490
-  and 467 SCSI host adapters. This is the old and very heavily tested
-  driver but lacks features like clustering.
+  This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490,
+  467, 471 and 493 SCSI host adapters. 
+
+  This is the old and very heavily tested driver but lacks features
+  like clustering.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -9062,14 +9073,15 @@
 
 AMI MegaRAID support (new driver)
 CONFIG_SCSI_MEGARAID2
-This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490
-and 467 SCSI host adapters. This is the newer less tested but more
-featureful driver.
-
-If you want to compile this driver as a module ( = code which can be
-inserted in and removed from the running kernel whenever you want),
-say M here and read <file:Documentation/modules.txt>.  The module
-will be called megaraid2.o.
+  This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490,
+  467, 471, 493 and new Ultra320(518, 520, 531, 532) SCSI host adapters.
+
+  This is the newer less tested but more featureful driver.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called megaraid2.o.
 
 Intel/ICP (former GDT SCSI Disk Array) RAID Controller support
 CONFIG_SCSI_GDTH
@@ -20169,6 +20181,15 @@
   <file:Documentation/modules.txt>. The module will be called
   cpuid.o
 
+x86 BIOS Enhanced Disk Drive support
+CONFIG_EDD
+  Say Y or M here if you want to enable BIOS Enhanced Disk Drive
+  Services real mode BIOS calls to determine which disk
+  BIOS tries boot from.  This information is then exported via /proc.
+
+  This option is experimental, but believed to be safe,
+  and most disk controller BIOS vendors do not yet implement this feature.
+
 SBC-60XX Watchdog Timer
 CONFIG_60XX_WDT
  This driver can be used with the watchdog timer found on some
@@ -24082,6 +24103,38 @@
       /proc/sys/dev/mac_hid/mouse_button2_keycode
       /proc/sys/dev/mac_hid/mouse_button3_keycode
 
+Set high memory pool address
+CONFIG_HIGHMEM_START_BOOL
+  Unless you know what you are doing you *should not* set this option.
+
+  It can be used to override the default PKMAP_BASE address which
+  is the location of the high memory pool.  This can be useful in
+  optimizing virtual memory usage in a system.
+
+Set maximum low memory
+CONFIG_LOWMEM_SIZE_BOOL
+  Unless you know what you are doing you *should not* set this option.
+
+  It can be used to override the standard calculated value of
+  MAX_LOW_MEM. This can be useful in optimizing virtual memory usage
+  in a system.
+
+Set custom kernel base address
+CONFIG_KERNEL_START_BOOL
+  Unless you know what you are doing you *should not* set this option.
+
+  It can be used to override the standard PAGE_OFFSET/KERNELBASE
+  value used by the kernel.  This can be useful in controlling
+  amount of virtual address space available to the kernel.
+
+Set custom user task size
+CONFIG_TASK_SIZE_BOOL
+  Unless you know what you are doing you *should not* set this option.
+
+  It can be used to override the standard TASK_SIZE value used
+  by the kernel.  This can be useful in controlling amount of
+  virtual address space available to user tasks.
+
 Enhanced Real Time Clock Support (/dev/rtc)
 CONFIG_PPC_RTC
   If you say Y here and create a character special file /dev/rtc with
@@ -27139,6 +27192,58 @@
   To use this option, you have to check that the "/proc file system
   support" (CONFIG_PROC_FS) is enabled, too.
 
+PPC4xx DMA controller support
+CONFIG_PPC4xx_DMA
+  Select this to enable support for the PPC4xx general purpose DMA
+  controller.
+
+ttyS0 device
+CONFIG_UART0_TTYS0
+  This option reverses the mapping between the hardware UART and software
+  device.  Selecting UART0 gives the normal mapping of UART0=ttyS0 and
+  UART1=ttyS1.  Selecting UART1 gives the reverse mapping of UART0=ttyS1
+  and UART1=ttyS0.  Most people will use UART0.
+
+PowerPC 405 on-chip ethernet
+CONFIG_IBM_OCP_ENET
+  If you want to use the 405 built-in ethernet select this.
+
+CONFIG_IBM_OCP_ENET_ERROR_MSG
+  Enable this option to print verbose debug messages for troubleshooting.
+
+PowerPC 405 on-chip ethernet -- Number of receive buffers
+CONFIG_IBM_OCP_ENET_RX_BUFF
+  Number of ethernet receive (read) buffers.  Unless you know what you
+  are doing the default should be fine.
+
+PowerPC 405 on-chip ethernet -- Number of transmit buffers
+CONFIG_IBM_OCP_ENET_TX_BUFF
+  Number of ethernet transmit (write) buffers.  Unless you know what
+  you are doing the default should be fine.
+
+PowerPC 405 on-chip ethernet -- Amount of bytes to Reserve on a skb
+CONFIG_IBM_OCP_ENET_SKB_RES
+  Many standard ethernet drivers need to reserve 2 bytes of data
+  on the skb before giving the data ptr to the hardware. This is
+  so the IP data will be 16-byte aligned when it goes up the stack.
+  This is a requirement for some processors and it can cause major
+  slow downs on others. The 405GP dose not have problems with the 
+  misaligned data so the default is 0. If you need to route the
+  incoming ethernet packets to another device that has alignment
+  requirements this can help remove a data copy. A value of 2 can
+  help at getting 16-byte aligned IP data for another device. A
+  larger value can be used when routing to a IP tunnel device.
+  Make sure XXX_DESC_SIZE - XXX_SKB_RES >= 1514, or larger if VLANS
+  are used.
+
+PPC 405 I2C Algorithm
+CONFIG_PPC405_I2C_ALGO
+  Enable this option to use the built-in I2C on your 405.
+
+PPC 405 I2C Adapter
+CONFIG_PPC405_I2C_ADAP
+  Enable this option to use the built-in I2C on your 405.
+
 /proc/efi/vars support
 CONFIG_EFI_VARS
   If you say Y here, you are able to get EFI (Extensible Firmware
diff -urN linux-2.4.22-bk31/Documentation/SubmittingDrivers linux-2.4.22-bk32/Documentation/SubmittingDrivers
--- linux-2.4.22-bk31/Documentation/SubmittingDrivers	2002-11-28 15:53:08.000000000 -0800
+++ linux-2.4.22-bk32/Documentation/SubmittingDrivers	2003-10-10 02:50:45.000000000 -0700
@@ -35,12 +35,12 @@
 
 Linux 2.4:
 	The same rules apply as 2.2. The final contact point for Linux 2.4 
-	submissions is Marcelo Tosatti <marcelo@conectiva.com.br>.
+	submissions is Marcelo Tosatti <marcelo@cyclades.com>.
 
 Linux 2.5:
 	The same rules apply as 2.4 except that you should follow linux-kernel
 	to track changes in API's. The final contact point for Linux 2.5
-	submissions is Linus Torvalds <torvalds@transmeta.com>.
+	submissions is Linus Torvalds <torvalds@osdl.org>.
 
 What Criteria Determine Acceptance
 ----------------------------------
diff -urN linux-2.4.22-bk31/Documentation/i386/zero-page.txt linux-2.4.22-bk32/Documentation/i386/zero-page.txt
--- linux-2.4.22-bk31/Documentation/i386/zero-page.txt	1999-08-30 10:47:02.000000000 -0700
+++ linux-2.4.22-bk32/Documentation/i386/zero-page.txt	2003-10-10 02:50:45.000000000 -0700
@@ -31,6 +31,7 @@
 
 0x1e0	unsigned long	ALT_MEM_K, alternative mem check, in Kb
 0x1e8	char		number of entries in E820MAP (below)
+0x1e9	unsigned char	number of entries in EDDBUF (below)
 0x1f1	char		size of setup.S, number of sectors
 0x1f2	unsigned short	MOUNT_ROOT_RDONLY (if !=0)
 0x1f4	unsigned short	size of compressed kernel-part in the
@@ -66,6 +67,7 @@
 0x220	4 bytes		(setup.S)
 0x224	unsigned short	setup.S heap end pointer
 0x2d0 - 0x600		E820MAP
+0x600 - 0x7D4		EDDBUF (setup.S)
 
 0x800	string, 2K max	COMMAND_LINE, the kernel commandline as
 			copied using CL_OFFSET.
diff -urN linux-2.4.22-bk31/Documentation/laptop-mode.txt linux-2.4.22-bk32/Documentation/laptop-mode.txt
--- linux-2.4.22-bk31/Documentation/laptop-mode.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk32/Documentation/laptop-mode.txt	2003-10-10 02:50:45.000000000 -0700
@@ -0,0 +1,72 @@
+Laptop mode
+===========
+
+This small doc describes the 2.4 laptop mode patch.
+
+Last updated 2003-05-25, Jens Axboe <axboe@suse.de>
+
+Introduction
+------------
+
+A few properties of the Linux vm makes it virtually impossible to attempt
+to spin down the hard drive in a laptop for a longer period of time (more
+than a handful of seconds). This means you are lucky if you can even reach
+the break even point with regards to power consumption, let alone expect any
+decrease.
+
+One problem is the age time of dirty buffers. Linux uses 30 seconds per
+default, so if you dirty any data then flusing of that data will commence
+at most 30 seconds from then. Another is the journal commit interval of
+journalled file systems such as ext3, which is 5 seconds on a stock kernel.
+Both of these are tweakable either from proc/sysctl or as mount options
+though, and thus partly solvable from user space.
+
+The kernel update daemon (kupdated) also runs at specific intervals, flushing
+old dirty data out. Default is every 5 seconds, this too can be tweaked
+from sysctl.
+
+So what does the laptop mode patch do? It attempts to fully utilize the
+hard drive once it has been spun up, flushing the old dirty data out to
+disk. Instead of flushing just the expired data, it will clean everything.
+When a read causes the disk to spin up, we kick off this flushing after
+a few seconds. This means that once the disk spins down again, everything
+is up to date. That allows longer dirty data and journal expire times.
+
+It follows that you have to set long expire times to get long spin downs.
+This means you could potentially loose 10 minutes worth of data, if you
+set a 10 minute expire count instead of just 30 seconds worth. The biggest
+risk here is undoubtedly running out of battery.
+
+Settings
+--------
+
+The main knob is /proc/sys/vm/laptop_mode. Setting that to 1 switches the
+vm (and block layer) to laptop mode. Leaving it to 0 makes the kernel work
+like before. When in laptop mode, you also want to extend the intervals
+desribed above. See the laptop-mode.sh script for how to do that.
+
+It can happen that the disk still keeps spinning up and you don't quite
+know why or what causes it. The laptop mode patch has a little helper for
+that as well, /proc/sys/vm/block_dump. When set to 1, it will dump info to
+the kernel message buffer about what process caused the io. Be very careful
+when playing with this setting, it is advisable to shut down syslog first!
+
+Result
+------
+
+Using the laptop-mode.sh script with its default settings, I get the full
+10 minutes worth of drive spin down. Provided your work load is cached,
+the disk will only spin up every 10 minutes (well actually, 9 minutes and 55
+seconds due to the 5 second delay in flushing dirty data after the last read
+completes). I can't tell you exactly how much extra battery life you will
+gain in laptop mode, it will vary greatly on the laptop and workload in
+question. The only way to know for sure is to try it out. Getting 10% extra
+battery life is not unrealistic.
+
+Notes
+-----
+
+Patch only changes journal expire time for ext3. reiserfs uses a hardwire
+value, should be trivial to adapt though (basically just make it call
+get_buffer_flushtime() and uses that). I have not looked at other
+journalling file systems, I'll happily accept patches to rectify that!
diff -urN linux-2.4.22-bk31/Makefile linux-2.4.22-bk32/Makefile
--- linux-2.4.22-bk31/Makefile	2003-10-10 02:50:37.000000000 -0700
+++ linux-2.4.22-bk32/Makefile	2003-10-10 02:50:45.000000000 -0700
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 22
-EXTRAVERSION = -bk31
+EXTRAVERSION = -bk32
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.22-bk31/arch/i386/boot/setup.S linux-2.4.22-bk32/arch/i386/boot/setup.S
--- linux-2.4.22-bk31/arch/i386/boot/setup.S	2002-08-02 17:39:42.000000000 -0700
+++ linux-2.4.22-bk32/arch/i386/boot/setup.S	2003-10-10 02:50:45.000000000 -0700
@@ -45,6 +45,10 @@
  * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
  * by Robert Schwebel, December 2001 <robert@schwebel.de>
  *
+ * BIOS Enhanced Disk Drive support
+ * by Matt Domsch <Matt_Domsch@dell.com> October 2002
+ * conformant to T13 Committee www.t13.org
+ *   projects 1572D, 1484D, 1386D, 1226DT
  */
 
 #include <linux/config.h>
@@ -53,6 +57,7 @@
 #include <linux/compile.h>
 #include <asm/boot.h>
 #include <asm/e820.h>
+#include <asm/edd.h>
 #include <asm/page.h>
 	
 /* Signature words to ensure LILO loaded us right */
@@ -543,6 +548,70 @@
 done_apm_bios:
 #endif
 
+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
+# Do the BIOS Enhanced Disk Drive calls
+# This consists of two calls:
+#    int 13h ah=41h "Check Extensions Present"
+#    int 13h ah=48h "Get Device Parameters"
+#
+# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
+# in the empty_zero_page at EDDBUF.  The first four bytes of which are
+# used to store the device number, interface support map and version
+# results from fn41.  The following 74 bytes are used to store
+# the results from fn48.  Starting from device 80h, fn41, then fn48
+# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
+# Then the pointer is incremented to store the data for the next call.
+# This repeats until either a device doesn't exist, or until EDDMAXNR
+# devices have been stored.
+# The one tricky part is that ds:si always points four bytes into
+# the structure, and the fn41 results are stored at offsets
+# from there.  This removes the need to increment the pointer for
+# every store, and leaves it ready for the fn48 call.
+# A second one-byte buffer, EDDNR, in the empty_zero_page stores
+# the number of BIOS devices which exist, up to EDDMAXNR.
+# In setup.c, copy_edd() stores both empty_zero_page buffers away
+# for later use, as they would get overwritten otherwise.
+# This code is sensitive to the size of the structs in edd.h
+edd_start:
+						# %ds points to the bootsector
+       						# result buffer for fn48
+    	movw	$EDDBUF+EDDEXTSIZE, %si		# in ds:si, fn41 results
+						# kept just before that
+	movb	$0, (EDDNR)			# zero value at EDDNR
+    	movb	$0x80, %dl			# BIOS device 0x80
+
+edd_check_ext:
+	movb	$CHECKEXTENSIONSPRESENT, %ah    # Function 41
+	movw	$EDDMAGIC1, %bx			# magic
+	int	$0x13				# make the call
+	jc	edd_done			# no more BIOS devices
+
+    	cmpw	$EDDMAGIC2, %bx			# is magic right?
+	jne	edd_next			# nope, next...
+
+    	movb	%dl, %ds:-4(%si)		# store device number
+    	movb	%ah, %ds:-3(%si)		# store version
+	movw	%cx, %ds:-2(%si)		# store extensions
+	incb	(EDDNR)				# note that we stored something
+
+edd_get_device_params:
+	movw	$EDDPARMSIZE, %ds:(%si)		# put size
+    	movb	$GETDEVICEPARAMETERS, %ah	# Function 48
+	int	$0x13				# make the call
+						# Don't check for fail return
+						# it doesn't matter.
+	movw	%si, %ax			# increment si
+	addw	$EDDPARMSIZE+EDDEXTSIZE, %ax
+	movw	%ax, %si
+
+edd_next:
+        incb	%dl				# increment to next device
+       	cmpb	$EDDMAXNR, (EDDNR) 		# Out of space?
+	jb	edd_check_ext			# keep looping
+
+edd_done:
+#endif
+
 # Now we want to move to protected mode ...
 	cmpw	$0, %cs:realmode_swtch
 	jz	rmodeswtch_normal
diff -urN linux-2.4.22-bk31/arch/i386/config.in linux-2.4.22-bk32/arch/i386/config.in
--- linux-2.4.22-bk31/arch/i386/config.in	2003-10-10 02:50:37.000000000 -0700
+++ linux-2.4.22-bk32/arch/i386/config.in	2003-10-10 02:50:45.000000000 -0700
@@ -201,6 +201,10 @@
 tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
 tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   tristate 'BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)' CONFIG_EDD
+fi
+
 choice 'High Memory Support' \
 	"off    CONFIG_NOHIGHMEM \
 	 4GB    CONFIG_HIGHMEM4G \
diff -urN linux-2.4.22-bk31/arch/i386/defconfig linux-2.4.22-bk32/arch/i386/defconfig
--- linux-2.4.22-bk31/arch/i386/defconfig	2003-10-10 02:50:37.000000000 -0700
+++ linux-2.4.22-bk32/arch/i386/defconfig	2003-10-10 02:50:45.000000000 -0700
@@ -56,6 +56,7 @@
 # CONFIG_MICROCODE is not set
 # CONFIG_X86_MSR is not set
 # CONFIG_X86_CPUID is not set
+# CONFIG_EDD is not set
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
 # CONFIG_HIGHMEM64G is not set
diff -urN linux-2.4.22-bk31/arch/i386/kernel/Makefile linux-2.4.22-bk32/arch/i386/kernel/Makefile
--- linux-2.4.22-bk31/arch/i386/kernel/Makefile	2003-10-10 02:50:37.000000000 -0700
+++ linux-2.4.22-bk32/arch/i386/kernel/Makefile	2003-10-10 02:50:45.000000000 -0700
@@ -42,5 +42,6 @@
 obj-$(CONFIG_X86_LOCAL_APIC)	+= mpparse.o apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
+obj-$(CONFIG_EDD)             	+= edd.o
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.4.22-bk31/arch/i386/kernel/edd.c linux-2.4.22-bk32/arch/i386/kernel/edd.c
--- linux-2.4.22-bk31/arch/i386/kernel/edd.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk32/arch/i386/kernel/edd.c	2003-10-10 02:50:45.000000000 -0700
@@ -0,0 +1,672 @@
+/*
+ * linux/arch/i386/kernel/edd.c
+ *  Copyright (C) 2002 Dell Computer Corporation
+ *  by Matt Domsch <Matt_Domsch@dell.com>
+ *
+ * BIOS Enhanced Disk Drive Services (EDD)
+ * conformant to T13 Committee www.t13.org
+ *   projects 1572D, 1484D, 1386D, 1226DT
+ *
+ * This code takes information provided by BIOS EDD calls
+ * fn41 - Check Extensions Present and
+ * fn48 - Get Device Parametes with EDD extensions
+ * made in setup.S, copied to safe structures in setup.c,
+ * and presents it in /proc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 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.
+ *
+ */
+
+/*
+ * TODO:
+ * - move edd.[ch] to better locations if/when one is decided
+ * - keep current with 2.5 EDD code changes
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/limits.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <asm/edd.h>
+
+MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
+MODULE_DESCRIPTION("proc interface to BIOS EDD information");
+MODULE_LICENSE("GPL");
+
+#define EDD_VERSION "0.09 2003-Jan-21"
+#define EDD_DEVICE_NAME_SIZE 16
+#define REPORT_URL "http://domsch.com/linux/edd30/results.html"
+
+#define left (count - (p - page) - 1)
+
+static struct proc_dir_entry *bios_dir;
+
+struct attr_entry {
+	struct proc_dir_entry *entry;
+	struct list_head node;
+};
+
+struct edd_device {
+	char name[EDD_DEVICE_NAME_SIZE];
+	struct edd_info *info;
+	struct proc_dir_entry *dir;
+	struct list_head attr_list;
+};
+
+static struct edd_device *edd_devices[EDDMAXNR];
+
+struct edd_attribute {
+	char *name;
+	int (*show)(char *page, char **start, off_t off,
+		    int count, int *eof, void *data);
+	int (*test) (struct edd_device * edev);
+};
+
+#define EDD_DEVICE_ATTR(_name,_show,_test) \
+struct edd_attribute edd_attr_##_name = { 	\
+	.name = __stringify(_name), \
+	.show	= _show,	    \
+        .test   = _test,            \
+};
+
+static inline struct edd_info *
+edd_dev_get_info(struct edd_device *edev)
+{
+	return edev->info;
+}
+
+static inline void
+edd_dev_set_info(struct edd_device *edev, struct edd_info *info)
+{
+	edev->info = info;
+}
+
+static int
+proc_calc_metrics(char *page, char **start, off_t off,
+		  int count, int *eof, int len)
+{
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+static int
+edd_dump_raw_data(char *b, int count, void *data, int length)
+{
+	char *orig_b = b;
+	char hexbuf[80], ascbuf[20], *h, *a, c;
+	unsigned char *p = data;
+	unsigned long column = 0;
+	int length_printed = 0, d;
+	const char maxcolumn = 16;
+	while (length_printed < length && count > 0) {
+		h = hexbuf;
+		a = ascbuf;
+		for (column = 0;
+		     column < maxcolumn && length_printed < length; column++) {
+			h += sprintf(h, "%02x ", (unsigned char) *p);
+			if (!isprint(*p))
+				c = '.';
+			else
+				c = *p;
+			a += sprintf(a, "%c", c);
+			p++;
+			length_printed++;
+		}
+		/* pad out the line */
+		for (; column < maxcolumn; column++) {
+			h += sprintf(h, "   ");
+			a += sprintf(a, " ");
+		}
+		d = snprintf(b, count, "%s\t%s\n", hexbuf, ascbuf);
+		b += d;
+		count -= d;
+	}
+	return (b - orig_b);
+}
+
+static int
+edd_show_host_bus(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	int i;
+
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (isprint(info->params.host_bus_type[i])) {
+			p += snprintf(p, left, "%c", info->params.host_bus_type[i]);
+		} else {
+			p += snprintf(p, left, " ");
+		}
+	}
+
+	if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
+		p += snprintf(p, left, "\tbase_address: %x\n",
+			     info->params.interface_path.isa.base_address);
+	} else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
+		   !strncmp(info->params.host_bus_type, "PCI", 3)) {
+		p += snprintf(p, left,
+			     "\t%02x:%02x.%d  channel: %u\n",
+			     info->params.interface_path.pci.bus,
+			     info->params.interface_path.pci.slot,
+			     info->params.interface_path.pci.function,
+			     info->params.interface_path.pci.channel);
+	} else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
+		   !strncmp(info->params.host_bus_type, "XPRS", 4) ||
+		   !strncmp(info->params.host_bus_type, "HTPT", 4)) {
+		p += snprintf(p, left,
+			     "\tTBD: %llx\n",
+			     info->params.interface_path.ibnd.reserved);
+
+	} else {
+		p += snprintf(p, left, "\tunknown: %llx\n",
+			     info->params.interface_path.unknown.reserved);
+	}
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_show_interface(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	int i;
+
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	for (i = 0; i < 8; i++) {
+		if (isprint(info->params.interface_type[i])) {
+			p += snprintf(p, left, "%c", info->params.interface_type[i]);
+		} else {
+			p += snprintf(p, left, " ");
+		}
+	}
+	if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
+		p += snprintf(p, left, "\tdevice: %u  lun: %u\n",
+			     info->params.device_path.atapi.device,
+			     info->params.device_path.atapi.lun);
+	} else if (!strncmp(info->params.interface_type, "ATA", 3)) {
+		p += snprintf(p, left, "\tdevice: %u\n",
+			     info->params.device_path.ata.device);
+	} else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
+		p += snprintf(p, left, "\tid: %u  lun: %llu\n",
+			     info->params.device_path.scsi.id,
+			     info->params.device_path.scsi.lun);
+	} else if (!strncmp(info->params.interface_type, "USB", 3)) {
+		p += snprintf(p, left, "\tserial_number: %llx\n",
+			     info->params.device_path.usb.serial_number);
+	} else if (!strncmp(info->params.interface_type, "1394", 4)) {
+		p += snprintf(p, left, "\teui: %llx\n",
+			     info->params.device_path.i1394.eui);
+	} else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
+		p += snprintf(p, left, "\twwid: %llx lun: %llx\n",
+			     info->params.device_path.fibre.wwid,
+			     info->params.device_path.fibre.lun);
+	} else if (!strncmp(info->params.interface_type, "I2O", 3)) {
+		p += snprintf(p, left, "\tidentity_tag: %llx\n",
+			     info->params.device_path.i2o.identity_tag);
+	} else if (!strncmp(info->params.interface_type, "RAID", 4)) {
+		p += snprintf(p, left, "\tidentity_tag: %x\n",
+			     info->params.device_path.raid.array_number);
+	} else if (!strncmp(info->params.interface_type, "SATA", 4)) {
+		p += snprintf(p, left, "\tdevice: %u\n",
+			     info->params.device_path.sata.device);
+	} else {
+		p += snprintf(p, left, "\tunknown: %llx %llx\n",
+			     info->params.device_path.unknown.reserved1,
+			     info->params.device_path.unknown.reserved2);
+	}
+
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+/**
+ * edd_show_raw_data() - unparses EDD information, returned to user-space
+ *
+ * Returns: number of bytes written, or 0 on failure
+ */
+static int
+edd_show_raw_data(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	int i, warn_padding = 0, nonzero_path = 0,
+		len = sizeof (*info) - 4;
+	uint8_t checksum = 0, c = 0;
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
+		len = info->params.length;
+
+	p += snprintf(p, left, "int13 fn48 returned data:\n\n");
+	p += edd_dump_raw_data(p, left, ((char *) info) + 4, len);
+
+	/* Spec violation.  Adaptec AIC7899 returns 0xDDBE
+	   here, when it should be 0xBEDD.
+	 */
+	p += snprintf(p, left, "\n");
+	if (info->params.key == 0xDDBE) {
+		p += snprintf(p, left,
+			     "Warning: Spec violation.  Key should be 0xBEDD, is 0xDDBE\n");
+	}
+
+	if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
+		goto out;
+	}
+
+	for (i = 30; i <= 73; i++) {
+		c = *(((uint8_t *) info) + i + 4);
+		if (c)
+			nonzero_path++;
+		checksum += c;
+	}
+
+	if (checksum) {
+		p += snprintf(p, left,
+			     "Warning: Spec violation.  Device Path checksum invalid.\n");
+	}
+
+	if (!nonzero_path) {
+		p += snprintf(p, left, "Error: Spec violation.  Empty device path.\n");
+		goto out;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (!isprint(info->params.host_bus_type[i])) {
+			warn_padding++;
+		}
+	}
+	for (i = 0; i < 8; i++) {
+		if (!isprint(info->params.interface_type[i])) {
+			warn_padding++;
+		}
+	}
+
+	if (warn_padding) {
+		p += snprintf(p, left,
+			     "Warning: Spec violation.  Padding should be 0x20.\n");
+	}
+
+out:
+	p += snprintf(p, left, "\nPlease check %s\n", REPORT_URL);
+	p += snprintf(p, left, "to see if this device has been reported.  If not,\n");
+	p += snprintf(p, left, "please send the information requested there.\n");
+
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_show_version(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	p += snprintf(p, left, "0x%02x\n", info->version);
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_show_extensions(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
+		p += snprintf(p, left, "Fixed disk access\n");
+	}
+	if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
+		p += snprintf(p, left, "Device locking and ejecting\n");
+	}
+	if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
+		p += snprintf(p, left, "Enhanced Disk Drive support\n");
+	}
+	if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
+		p += snprintf(p, left, "64-bit extensions\n");
+	}
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_show_info_flags(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	if (info->params.info_flags & EDD_INFO_DMA_BOUNDRY_ERROR_TRANSPARENT)
+		p += snprintf(p, left, "DMA boundry error transparent\n");
+	if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
+		p += snprintf(p, left, "geometry valid\n");
+	if (info->params.info_flags & EDD_INFO_REMOVABLE)
+		p += snprintf(p, left, "removable\n");
+	if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
+		p += snprintf(p, left, "write verify\n");
+	if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
+		p += snprintf(p, left, "media change notification\n");
+	if (info->params.info_flags & EDD_INFO_LOCKABLE)
+		p += snprintf(p, left, "lockable\n");
+	if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
+		p += snprintf(p, left, "no media present\n");
+	if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
+		p += snprintf(p, left, "use int13 fn50\n");
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_show_default_cylinders(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->params.num_default_cylinders);
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_show_default_heads(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->params.num_default_heads);
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_show_default_sectors_per_track(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	p += snprintf(p, left, "0x%x\n", info->params.sectors_per_track);
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_show_sectors(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+	struct edd_info *info = data;
+	char *p = page;
+	if (!info || !page || off) {
+		return proc_calc_metrics(page, start, off, count, eof, 0);
+	}
+
+	p += snprintf(p, left, "0x%llx\n", info->params.number_of_sectors);
+	return proc_calc_metrics(page, start, off, count, eof, (p - page));
+}
+
+static int
+edd_has_default_cylinders(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return 0;
+	return info->params.num_default_cylinders > 0;
+}
+
+static int
+edd_has_default_heads(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return 0;
+	return info->params.num_default_heads > 0;
+}
+
+static int
+edd_has_default_sectors_per_track(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return 0;
+	return info->params.sectors_per_track > 0;
+}
+
+static int
+edd_has_edd30(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	int i, nonzero_path = 0;
+	char c;
+
+	if (!edev || !info)
+		return 0;
+
+	if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
+		return 0;
+	}
+
+	for (i = 30; i <= 73; i++) {
+		c = *(((uint8_t *) info) + i + 4);
+		if (c) {
+			nonzero_path++;
+			break;
+		}
+	}
+	if (!nonzero_path) {
+		return 0;
+	}
+
+	return 1;
+}
+
+static EDD_DEVICE_ATTR(raw_data, edd_show_raw_data, NULL);
+static EDD_DEVICE_ATTR(version, edd_show_version, NULL);
+static EDD_DEVICE_ATTR(extensions, edd_show_extensions, NULL);
+static EDD_DEVICE_ATTR(info_flags, edd_show_info_flags, NULL);
+static EDD_DEVICE_ATTR(sectors, edd_show_sectors, NULL);
+static EDD_DEVICE_ATTR(default_cylinders, edd_show_default_cylinders,
+		       edd_has_default_cylinders);
+static EDD_DEVICE_ATTR(default_heads, edd_show_default_heads,
+		       edd_has_default_heads);
+static EDD_DEVICE_ATTR(default_sectors_per_track,
+		       edd_show_default_sectors_per_track,
+		       edd_has_default_sectors_per_track);
+static EDD_DEVICE_ATTR(interface, edd_show_interface,edd_has_edd30);
+static EDD_DEVICE_ATTR(host_bus, edd_show_host_bus, edd_has_edd30);
+
+static struct edd_attribute *def_attrs[] = {
+	&edd_attr_raw_data,
+	&edd_attr_version,
+	&edd_attr_extensions,
+	&edd_attr_info_flags,
+	&edd_attr_sectors,
+	&edd_attr_default_cylinders,
+	&edd_attr_default_heads,
+	&edd_attr_default_sectors_per_track,
+	&edd_attr_interface,
+	&edd_attr_host_bus,
+	NULL,
+};
+
+static inline void
+edd_device_unregister(struct edd_device *edev)
+{
+	struct list_head *pos, *next;
+	struct attr_entry *ae;
+
+	list_for_each_safe(pos, next, &edev->attr_list) {
+		ae = list_entry(pos, struct attr_entry, node);
+		remove_proc_entry(ae->entry->name, edev->dir);
+		list_del(&ae->node);
+		kfree(ae);
+	}
+
+	remove_proc_entry(edev->dir->name, bios_dir);
+}
+
+static int
+edd_populate_dir(struct edd_device *edev)
+{
+	struct edd_attribute *attr;
+	struct attr_entry *ae;
+	int i;
+	int error = 0;
+
+	for (i = 0; (attr=def_attrs[i]); i++) {
+		if (!attr->test || (attr->test && attr->test(edev))) {
+			ae = kmalloc(sizeof (*ae), GFP_KERNEL);
+			if (ae == NULL) {
+				error = 1;
+				break;
+			}
+			INIT_LIST_HEAD(&ae->node);
+			ae->entry =
+				create_proc_read_entry(attr->name, 0444,
+						       edev->dir, attr->show,
+						       edd_dev_get_info(edev));
+			if (ae->entry == NULL) {
+				error = 1;
+				break;
+			}
+			list_add(&ae->node, &edev->attr_list);
+		}
+	}
+
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static int
+edd_make_dir(struct edd_device *edev)
+{
+	int error=1;
+
+	edev->dir = proc_mkdir(edev->name, bios_dir);
+	if (edev->dir != NULL) {
+		edev->dir->mode = (S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
+		error = edd_populate_dir(edev);
+	}
+	return error;
+}
+
+static int
+edd_device_register(struct edd_device *edev, int i)
+{
+	int error;
+
+	if (!edev)
+		return 1;
+	memset(edev, 0, sizeof (*edev));
+	INIT_LIST_HEAD(&edev->attr_list);
+	edd_dev_set_info(edev, &edd[i]);
+	snprintf(edev->name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x",
+		 edd[i].device);
+	error = edd_make_dir(edev);
+	return error;
+}
+
+/**
+ * edd_init() - creates /proc/bios tree of EDD data
+ *
+ * This assumes that eddnr and edd were
+ * assigned in setup.c already.
+ */
+static int __init
+edd_init(void)
+{
+	unsigned int i;
+	int rc = 0;
+	struct edd_device *edev;
+
+	printk(KERN_INFO "BIOS EDD facility v%s, %d devices found\n",
+	       EDD_VERSION, eddnr);
+
+	if (!eddnr) {
+		printk(KERN_INFO "EDD information not available.\n");
+		return 1;
+	}
+
+	bios_dir = proc_mkdir("bios", NULL);
+	if (bios_dir == NULL)
+		return 1;
+
+	for (i = 0; i < eddnr && i < EDDMAXNR && !rc; i++) {
+		edev = kmalloc(sizeof (*edev), GFP_KERNEL);
+		if (!edev) {
+			rc = 1;
+			break;
+		}
+
+		rc = edd_device_register(edev, i);
+		if (rc) {
+			break;
+		}
+		edd_devices[i] = edev;
+	}
+
+	if (rc) {
+		for (i = 0; i < eddnr && i < EDDMAXNR; i++) {
+			if ((edev = edd_devices[i])) {
+				edd_device_unregister(edev);
+				kfree(edev);
+			}
+		}
+
+		remove_proc_entry(bios_dir->name, NULL);
+	}
+
+	return rc;
+}
+
+static void __exit
+edd_exit(void)
+{
+	int i;
+	struct edd_device *edev;
+
+	for (i = 0; i < eddnr && i < EDDMAXNR; i++) {
+		if ((edev = edd_devices[i])) {
+			edd_device_unregister(edev);
+			kfree(edev);
+		}
+	}
+
+	remove_proc_entry(bios_dir->name, NULL);
+}
+
+module_init(edd_init);
+module_exit(edd_exit);
diff -urN linux-2.4.22-bk31/arch/i386/kernel/i386_ksyms.c linux-2.4.22-bk32/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.22-bk31/arch/i386/kernel/i386_ksyms.c	2003-06-13 07:51:29.000000000 -0700
+++ linux-2.4.22-bk32/arch/i386/kernel/i386_ksyms.c	2003-10-10 02:50:45.000000000 -0700
@@ -28,6 +28,7 @@
 #include <asm/desc.h>
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
+#include <asm/edd.h>
 
 extern void dump_thread(struct pt_regs *, struct user *);
 extern spinlock_t rtc_lock;
@@ -180,3 +181,8 @@
 #ifdef CONFIG_MULTIQUAD
 EXPORT_SYMBOL(xquad_portio);
 #endif
+
+#ifdef CONFIG_EDD_MODULE
+EXPORT_SYMBOL(edd);
+EXPORT_SYMBOL(eddnr);
+#endif
diff -urN linux-2.4.22-bk31/arch/i386/kernel/setup.c linux-2.4.22-bk32/arch/i386/kernel/setup.c
--- linux-2.4.22-bk31/arch/i386/kernel/setup.c	2003-10-10 02:50:37.000000000 -0700
+++ linux-2.4.22-bk32/arch/i386/kernel/setup.c	2003-10-10 02:50:45.000000000 -0700
@@ -120,6 +120,7 @@
 #include <asm/dma.h>
 #include <asm/mpspec.h>
 #include <asm/mmu_context.h>
+#include <asm/edd.h>
 /*
  * Machine setup..
  */
@@ -211,6 +212,8 @@
 #define KERNEL_START (*(unsigned long *) (PARAM+0x214))
 #define INITRD_START (*(unsigned long *) (PARAM+0x218))
 #define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
+#define EDD_NR     (*(unsigned char *) (PARAM+EDDNR))
+#define EDD_BUF     ((struct edd_info *) (PARAM+EDDBUF))
 #define COMMAND_LINE ((char *) (PARAM+2048))
 #define COMMAND_LINE_SIZE 256
 
@@ -715,6 +718,23 @@
 	return 0;
 }
 
+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
+unsigned char eddnr;
+struct edd_info edd[EDDMAXNR];
+/**
+ * copy_edd() - Copy the BIOS EDD information
+ *              from empty_zero_page into a safe place.
+ *
+ */
+static inline void copy_edd(void)
+{
+     eddnr = EDD_NR;
+     memcpy(edd, EDD_BUF, sizeof(edd));
+}
+#else
+static inline void copy_edd(void) {}
+#endif
+
 /*
  * Do NOT EVER look at the BIOS memory size location.
  * It does not work on many machines.
@@ -1151,6 +1171,7 @@
 	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
 #endif
 	setup_memory_region();
+	copy_edd();
 
 	if (!MOUNT_ROOT_RDONLY)
 		root_mountflags &= ~MS_RDONLY;
diff -urN linux-2.4.22-bk31/drivers/block/ll_rw_blk.c linux-2.4.22-bk32/drivers/block/ll_rw_blk.c
--- linux-2.4.22-bk31/drivers/block/ll_rw_blk.c	2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.22-bk32/drivers/block/ll_rw_blk.c	2003-10-10 02:50:46.000000000 -0700
@@ -121,6 +121,10 @@
 unsigned long blk_max_low_pfn, blk_max_pfn;
 int blk_nohighio = 0;
 
+int block_dump = 0;
+
+static struct timer_list writeback_timer;
+
 static inline int get_max_sectors(kdev_t dev)
 {
 	if (!max_sectors[MAJOR(dev)])
@@ -1293,6 +1297,9 @@
 	if (waitqueue_active(&bh->b_wait))
 		wake_up(&bh->b_wait);
 
+	if (block_dump)
+		printk(KERN_DEBUG "%s: %s block %lu/%u on %s\n", current->comm, rw == WRITE ? "WRITE" : "READ", bh->b_rsector, count, kdevname(bh->b_rdev));
+
 	put_bh(bh);
 	switch (rw) {
 		case WRITE:
@@ -1413,6 +1420,11 @@
 extern int stram_device_init (void);
 #endif
 
+static void blk_writeback_timer(unsigned long data)
+{
+	wakeup_bdflush();
+	wakeup_kupdate();
+}
 
 /**
  * end_that_request_first - end I/O on one buffer.
@@ -1469,10 +1481,18 @@
 	return 0;
 }
 
+extern int laptop_mode;
+
 void end_that_request_last(struct request *req)
 {
 	struct completion *waiting = req->waiting;
 
+	/*
+	 * schedule the writeout of pending dirty data when the disk is idle
+	 */
+	if (laptop_mode && req->cmd == READ)
+		mod_timer(&writeback_timer, jiffies + 5 * HZ);
+
 	req_finished_io(req);
 	blkdev_release_request(req);
 	if (waiting)
@@ -1500,6 +1520,9 @@
 	blk_max_low_pfn = max_low_pfn - 1;
 	blk_max_pfn = max_pfn - 1;
 
+	init_timer(&writeback_timer);
+	writeback_timer.function = blk_writeback_timer;
+
 #ifdef CONFIG_AMIGA_Z2RAM
 	z2_init();
 #endif
diff -urN linux-2.4.22-bk31/drivers/char/drm/drmP.h linux-2.4.22-bk32/drivers/char/drm/drmP.h
--- linux-2.4.22-bk31/drivers/char/drm/drmP.h	2003-10-10 02:50:38.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/drmP.h	2003-10-10 02:50:46.000000000 -0700
@@ -328,16 +328,16 @@
    if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; }
 
 				/* Mapping helper macros */
-#define DRM_IOREMAP(map, dev)					\
-	(map)->handle = DRM(ioremap)((map)->offset, (map)->size, (dev) )
+#define DRM_IOREMAP(map)						\
+	(map)->handle = DRM(ioremap)( (map)->offset, (map)->size )
 
-#define DRM_IOREMAP_NOCACHE(map, dev)					\
-	(map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size, (dev) )
+#define DRM_IOREMAP_NOCACHE(map)					\
+	(map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size)
 
-#define DRM_IOREMAPFREE(map, dev)						\
+#define DRM_IOREMAPFREE(map)						\
 	do {								\
 		if ( (map)->handle && (map)->size )			\
-			DRM(ioremapfree)( (map)->handle, (map)->size, (dev) );	\
+			DRM(ioremapfree)( (map)->handle, (map)->size );	\
 	} while (0)
 
 #define DRM_FIND_MAP(_map, _o)						\
@@ -789,9 +789,9 @@
 extern unsigned long DRM(alloc_pages)(int order, int area);
 extern void	     DRM(free_pages)(unsigned long address, int order,
 				     int area);
-extern void	     *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev);
-extern void	     *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, drm_device_t *dev);
-extern void	     DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev);
+extern void	     *DRM(ioremap)(unsigned long offset, unsigned long size);
+extern void	     *DRM(ioremap_nocache)(unsigned long offset, unsigned long size);
+extern void	     DRM(ioremapfree)(void *pt, unsigned long size);
 
 #if __REALLY_HAVE_AGP
 extern agp_memory    *DRM(alloc_agp)(int pages, u32 type);
diff -urN linux-2.4.22-bk31/drivers/char/drm/drm_bufs.h linux-2.4.22-bk32/drivers/char/drm/drm_bufs.h
--- linux-2.4.22-bk31/drivers/char/drm/drm_bufs.h	2003-10-10 02:50:38.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/drm_bufs.h	2003-10-10 02:50:46.000000000 -0700
@@ -123,7 +123,7 @@
 					      MTRR_TYPE_WRCOMB, 1 );
 		}
 #endif
-		map->handle = DRM(ioremap)( map->offset, map->size, dev );
+		map->handle = DRM(ioremap)( map->offset, map->size );
 		break;
 
 	case _DRM_SHM:
@@ -245,7 +245,7 @@
 				DRM_DEBUG("mtrr_del = %d\n", retcode);
 			}
 #endif
-			DRM(ioremapfree)(map->handle, map->size, dev);
+			DRM(ioremapfree)(map->handle, map->size);
 			break;
 		case _DRM_SHM:
 			vfree(map->handle);
diff -urN linux-2.4.22-bk31/drivers/char/drm/drm_drv.h linux-2.4.22-bk32/drivers/char/drm/drm_drv.h
--- linux-2.4.22-bk31/drivers/char/drm/drm_drv.h	2003-10-10 02:50:38.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/drm_drv.h	2003-10-10 02:50:46.000000000 -0700
@@ -443,7 +443,7 @@
 					DRM_DEBUG( "mtrr_del=%d\n", retcode );
 				}
 #endif
-				DRM(ioremapfree)( map->handle, map->size, dev );
+				DRM(ioremapfree)( map->handle, map->size );
 				break;
 			case _DRM_SHM:
 				vfree(map->handle);
diff -urN linux-2.4.22-bk31/drivers/char/drm/drm_memory.h linux-2.4.22-bk32/drivers/char/drm/drm_memory.h
--- linux-2.4.22-bk31/drivers/char/drm/drm_memory.h	2003-10-10 02:50:38.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/drm_memory.h	2003-10-10 02:50:46.000000000 -0700
@@ -290,7 +290,7 @@
 	}
 }
 
-void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev)
+void *DRM(ioremap)(unsigned long offset, unsigned long size)
 {
 	void *pt;
 
@@ -313,7 +313,7 @@
 	return pt;
 }
 
-void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, drm_device_t *dev)
+void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size)
 {
 	void *pt;
 
@@ -336,7 +336,7 @@
 	return pt;
 }
 
-void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev)
+void DRM(ioremapfree)(void *pt, unsigned long size)
 {
 	int alloc_count;
 	int free_count;
diff -urN linux-2.4.22-bk31/drivers/char/drm/drm_vm.h linux-2.4.22-bk32/drivers/char/drm/drm_vm.h
--- linux-2.4.22-bk31/drivers/char/drm/drm_vm.h	2003-10-10 02:50:38.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/drm_vm.h	2003-10-10 02:50:46.000000000 -0700
@@ -206,7 +206,7 @@
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
 #endif
-				DRM(ioremapfree)(map->handle, map->size, dev);
+				DRM(ioremapfree)(map->handle, map->size);
 				break;
 			case _DRM_SHM:
 				vfree(map->handle);
diff -urN linux-2.4.22-bk31/drivers/char/drm/i810_dma.c linux-2.4.22-bk32/drivers/char/drm/i810_dma.c
--- linux-2.4.22-bk31/drivers/char/drm/i810_dma.c	2003-10-10 02:50:38.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/i810_dma.c	2003-10-10 02:50:46.000000000 -0700
@@ -276,7 +276,7 @@
 
 	   	if(dev_priv->ring.virtual_start) {
 		   	DRM(ioremapfree)((void *) dev_priv->ring.virtual_start,
-					 dev_priv->ring.Size, dev);
+					 dev_priv->ring.Size);
 		}
 	   	if(dev_priv->hw_status_page != 0UL) {
 		   	pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -292,7 +292,7 @@
 		for (i = 0; i < dma->buf_count; i++) {
 			drm_buf_t *buf = dma->buflist[ i ];
 			drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-			DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev);
+			DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total);
 		}
 	}
    	return 0;
@@ -362,7 +362,7 @@
 	   	*buf_priv->in_use = I810_BUF_FREE;
 
 		buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address,
-							buf->total, dev);
+							buf->total);
 	}
 	return 0;
 }
@@ -415,7 +415,7 @@
 
    	dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base +
 						    init->ring_start,
-						    init->ring_size, dev);
+						    init->ring_size);
 
    	if (dev_priv->ring.virtual_start == NULL) {
 		dev->dev_private = (void *) dev_priv;
diff -urN linux-2.4.22-bk31/drivers/char/drm/mga_dma.c linux-2.4.22-bk32/drivers/char/drm/mga_dma.c
--- linux-2.4.22-bk31/drivers/char/drm/mga_dma.c	2003-10-10 02:50:38.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/mga_dma.c	2003-10-10 02:50:46.000000000 -0700
@@ -556,9 +556,9 @@
 		(drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle +
 				    init->sarea_priv_offset);
 
-	DRM_IOREMAP( dev_priv->warp, dev );
-	DRM_IOREMAP( dev_priv->primary, dev );
-	DRM_IOREMAP( dev_priv->buffers, dev );
+	DRM_IOREMAP( dev_priv->warp );
+	DRM_IOREMAP( dev_priv->primary );
+	DRM_IOREMAP( dev_priv->buffers );
 
 	if(!dev_priv->warp->handle ||
 	   !dev_priv->primary->handle ||
@@ -644,9 +644,9 @@
 	if ( dev->dev_private ) {
 		drm_mga_private_t *dev_priv = dev->dev_private;
 
-		DRM_IOREMAPFREE( dev_priv->warp, dev );
-		DRM_IOREMAPFREE( dev_priv->primary, dev );
-		DRM_IOREMAPFREE( dev_priv->buffers, dev );
+		DRM_IOREMAPFREE( dev_priv->warp );
+		DRM_IOREMAPFREE( dev_priv->primary );
+		DRM_IOREMAPFREE( dev_priv->buffers );
 
 		if ( dev_priv->head != NULL ) {
 			mga_freelist_cleanup( dev );
diff -urN linux-2.4.22-bk31/drivers/char/drm/r128_cce.c linux-2.4.22-bk32/drivers/char/drm/r128_cce.c
--- linux-2.4.22-bk31/drivers/char/drm/r128_cce.c	2003-10-10 02:50:38.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/r128_cce.c	2003-10-10 02:50:46.000000000 -0700
@@ -542,9 +542,9 @@
 				     init->sarea_priv_offset);
 
 	if ( !dev_priv->is_pci ) {
-		DRM_IOREMAP( dev_priv->cce_ring, dev );
-		DRM_IOREMAP( dev_priv->ring_rptr, dev );
-		DRM_IOREMAP( dev_priv->buffers, dev );
+		DRM_IOREMAP( dev_priv->cce_ring );
+		DRM_IOREMAP( dev_priv->ring_rptr );
+		DRM_IOREMAP( dev_priv->buffers );
 		if(!dev_priv->cce_ring->handle ||
 		   !dev_priv->ring_rptr->handle ||
 		   !dev_priv->buffers->handle) {
@@ -618,9 +618,9 @@
 #if __REALLY_HAVE_SG
 		if ( !dev_priv->is_pci ) {
 #endif
-			DRM_IOREMAPFREE( dev_priv->cce_ring, dev );
-			DRM_IOREMAPFREE( dev_priv->ring_rptr, dev );
-			DRM_IOREMAPFREE( dev_priv->buffers, dev );
+			DRM_IOREMAPFREE( dev_priv->cce_ring );
+			DRM_IOREMAPFREE( dev_priv->ring_rptr );
+			DRM_IOREMAPFREE( dev_priv->buffers );
 #if __REALLY_HAVE_SG
 		} else {
 			if (!DRM(ati_pcigart_cleanup)( dev,
diff -urN linux-2.4.22-bk31/drivers/char/drm/radeon_cp.c linux-2.4.22-bk32/drivers/char/drm/radeon_cp.c
--- linux-2.4.22-bk31/drivers/char/drm/radeon_cp.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm/radeon_cp.c	2003-10-10 02:50:46.000000000 -0700
@@ -1145,9 +1145,9 @@
 				       init->sarea_priv_offset);
 
 	if ( !dev_priv->is_pci ) {
-		DRM_IOREMAP( dev_priv->cp_ring, dev );
-		DRM_IOREMAP( dev_priv->ring_rptr, dev );
-		DRM_IOREMAP( dev_priv->buffers, dev );
+		DRM_IOREMAP( dev_priv->cp_ring );
+		DRM_IOREMAP( dev_priv->ring_rptr );
+		DRM_IOREMAP( dev_priv->buffers );
 		if(!dev_priv->cp_ring->handle ||
 		   !dev_priv->ring_rptr->handle ||
 		   !dev_priv->buffers->handle) {
@@ -1266,9 +1266,9 @@
 		drm_radeon_private_t *dev_priv = dev->dev_private;
 
 		if ( !dev_priv->is_pci ) {
-			DRM_IOREMAPFREE( dev_priv->cp_ring, dev );
-			DRM_IOREMAPFREE( dev_priv->ring_rptr, dev );
-			DRM_IOREMAPFREE( dev_priv->buffers, dev );
+			DRM_IOREMAPFREE( dev_priv->cp_ring );
+			DRM_IOREMAPFREE( dev_priv->ring_rptr );
+			DRM_IOREMAPFREE( dev_priv->buffers );
 		} else {
 #if __REALLY_HAVE_SG
 			if (!DRM(ati_pcigart_cleanup)( dev,
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/bufs.c linux-2.4.22-bk32/drivers/char/drm-4.0/bufs.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/bufs.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/bufs.c	2002-02-25 11:37:57.000000000 -0800
@@ -87,7 +87,7 @@
 					     MTRR_TYPE_WRCOMB, 1);
 		}
 #endif
-		map->handle = drm_ioremap(map->offset, map->size, dev);
+		map->handle = drm_ioremap(map->offset, map->size);
 		break;
 			
 
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/drmP.h linux-2.4.22-bk32/drivers/char/drm-4.0/drmP.h
--- linux-2.4.22-bk31/drivers/char/drm-4.0/drmP.h	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/drmP.h	2002-02-25 11:37:57.000000000 -0800
@@ -679,8 +679,8 @@
 extern unsigned long drm_alloc_pages(int order, int area);
 extern void	     drm_free_pages(unsigned long address, int order,
 				    int area);
-extern void	     *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev);
-extern void	     drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev);
+extern void	     *drm_ioremap(unsigned long offset, unsigned long size);
+extern void	     drm_ioremapfree(void *pt, unsigned long size);
 
 #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
 extern agp_memory    *drm_alloc_agp(int pages, u32 type);
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/ffb_drv.c linux-2.4.22-bk32/drivers/char/drm-4.0/ffb_drv.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/ffb_drv.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/ffb_drv.c	2002-11-28 15:53:12.000000000 -0800
@@ -158,7 +158,7 @@
 			switch (map->type) {
 			case _DRM_REGISTERS:
 			case _DRM_FRAME_BUFFER:
-				drm_ioremapfree(map->handle, map->size, dev);
+				drm_ioremapfree(map->handle, map->size);
 				break;
 
 			case _DRM_SHM:
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/gamma_drv.c linux-2.4.22-bk32/drivers/char/drm-4.0/gamma_drv.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/gamma_drv.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/gamma_drv.c	2002-02-25 11:37:57.000000000 -0800
@@ -258,7 +258,7 @@
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
 #endif
-				drm_ioremapfree(map->handle, map->size, dev);
+				drm_ioremapfree(map->handle, map->size);
 				break;
 			case _DRM_SHM:
 				drm_free_pages((unsigned long)map->handle,
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/i810_dma.c linux-2.4.22-bk32/drivers/char/drm-4.0/i810_dma.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/i810_dma.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/i810_dma.c	2003-06-13 07:51:32.000000000 -0700
@@ -305,7 +305,7 @@
 	   
 	   	if(dev_priv->ring.virtual_start) {
 		   	drm_ioremapfree((void *) dev_priv->ring.virtual_start,
-					dev_priv->ring.Size, dev);
+					dev_priv->ring.Size);
 		}
 	   	if(dev_priv->hw_status_page != 0UL) {
 		   	i810_free_page(dev, dev_priv->hw_status_page);
@@ -319,7 +319,7 @@
 		for (i = 0; i < dma->buf_count; i++) {
 			drm_buf_t *buf = dma->buflist[ i ];
 			drm_i810_buf_priv_t *buf_priv = buf->dev_private;
-			drm_ioremapfree(buf_priv->kernel_virtual, buf->total, dev);
+			drm_ioremapfree(buf_priv->kernel_virtual, buf->total);
 		}
 	}
    	return 0;
@@ -393,7 +393,7 @@
 	   	*buf_priv->in_use = I810_BUF_FREE;
 
 		buf_priv->kernel_virtual = drm_ioremap(buf->bus_address, 
-						       buf->total, dev);
+						       buf->total);
 	}
 	return 0;
 }
@@ -430,7 +430,7 @@
 
    	dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base + 
 						   init->ring_start, 
-						   init->ring_size, dev);
+						   init->ring_size);
 
    	dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
    
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/i810_drv.c linux-2.4.22-bk32/drivers/char/drm-4.0/i810_drv.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/i810_drv.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/i810_drv.c	2002-02-25 11:37:57.000000000 -0800
@@ -286,7 +286,7 @@
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
 #endif
-				drm_ioremapfree(map->handle, map->size, dev);
+				drm_ioremapfree(map->handle, map->size);
 				break;
 			case _DRM_SHM:
 				drm_free_pages((unsigned long)map->handle,
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/memory.c linux-2.4.22-bk32/drivers/char/drm-4.0/memory.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/memory.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/memory.c	2002-02-25 11:37:57.000000000 -0800
@@ -296,7 +296,7 @@
 	}
 }
 
-void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev)
+void *drm_ioremap(unsigned long offset, unsigned long size)
 {
 	void *pt;
 	
@@ -319,7 +319,7 @@
 	return pt;
 }
 
-void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev)
+void drm_ioremapfree(void *pt, unsigned long size)
 {
 	int alloc_count;
 	int free_count;
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/mga_dma.c linux-2.4.22-bk32/drivers/char/drm-4.0/mga_dma.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/mga_dma.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/mga_dma.c	2002-02-25 11:37:57.000000000 -0800
@@ -308,7 +308,7 @@
 	temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
 
 	dev_priv->ioremap = drm_ioremap(dev->agp->base + offset,
-					temp, dev);
+					temp);
 	if(dev_priv->ioremap == NULL) {
 		DRM_ERROR("Ioremap failed\n");
 		return -ENOMEM;
@@ -635,7 +635,7 @@
 				    dev_priv->primary_size +
 				    PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE;
 
-			drm_ioremapfree((void *) dev_priv->ioremap, temp, dev);
+			drm_ioremapfree((void *) dev_priv->ioremap, temp);
 		}
 	   	if(dev_priv->status_page != NULL) {
 		   	iounmap(dev_priv->status_page);
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/mga_drv.c linux-2.4.22-bk32/drivers/char/drm-4.0/mga_drv.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/mga_drv.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/mga_drv.c	2002-02-25 11:37:57.000000000 -0800
@@ -286,7 +286,7 @@
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
 #endif
-				drm_ioremapfree(map->handle, map->size, dev);
+				drm_ioremapfree(map->handle, map->size);
 				break;
 			case _DRM_SHM:
 				drm_free_pages((unsigned long)map->handle,
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/r128_cce.c linux-2.4.22-bk32/drivers/char/drm-4.0/r128_cce.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/r128_cce.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/r128_cce.c	2002-02-25 11:37:57.000000000 -0800
@@ -86,12 +86,12 @@
 };
 
 
-#define DO_REMAP(_m, _d) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size, (_d))
+#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size)
 
-#define DO_REMAPFREE(_m, _d)                                                   \
+#define DO_REMAPFREE(_m)                                                    \
 	do {                                                                \
 		if ((_m)->handle && (_m)->size)                             \
-			drm_ioremapfree((_m)->handle, (_m)->size, (_d));    \
+			drm_ioremapfree((_m)->handle, (_m)->size);          \
 	} while (0)
 
 #define DO_FIND_MAP(_m, _o)                                                 \
@@ -481,12 +481,12 @@
 		(drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle +
 				     init->sarea_priv_offset);
 
-	DO_REMAP( dev_priv->cce_ring, dev );
-	DO_REMAP( dev_priv->ring_rptr, dev );
-	DO_REMAP( dev_priv->buffers, dev );
+	DO_REMAP( dev_priv->cce_ring );
+	DO_REMAP( dev_priv->ring_rptr );
+	DO_REMAP( dev_priv->buffers );
 #if 0
 	if ( !dev_priv->is_pci ) {
-		DO_REMAP( dev_priv->agp_textures, dev );
+		DO_REMAP( dev_priv->agp_textures );
 	}
 #endif
 
@@ -521,12 +521,12 @@
 	if ( dev->dev_private ) {
 		drm_r128_private_t *dev_priv = dev->dev_private;
 
-		DO_REMAPFREE( dev_priv->cce_ring, dev );
-		DO_REMAPFREE( dev_priv->ring_rptr, dev );
-		DO_REMAPFREE( dev_priv->buffers, dev );
+		DO_REMAPFREE( dev_priv->cce_ring );
+		DO_REMAPFREE( dev_priv->ring_rptr );
+		DO_REMAPFREE( dev_priv->buffers );
 #if 0
 		if ( !dev_priv->is_pci ) {
-			DO_REMAPFREE( dev_priv->agp_textures, dev );
+			DO_REMAPFREE( dev_priv->agp_textures );
 		}
 #endif
 
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/r128_drv.c linux-2.4.22-bk32/drivers/char/drm-4.0/r128_drv.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/r128_drv.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/r128_drv.c	2002-02-25 11:37:57.000000000 -0800
@@ -296,7 +296,7 @@
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
 #endif
-				drm_ioremapfree(map->handle, map->size, dev);
+				drm_ioremapfree(map->handle, map->size);
 				break;
 			case _DRM_SHM:
 				drm_free_pages((unsigned long)map->handle,
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/radeon_cp.c linux-2.4.22-bk32/drivers/char/drm-4.0/radeon_cp.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/radeon_cp.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/radeon_cp.c	2002-02-25 11:37:57.000000000 -0800
@@ -300,12 +300,12 @@
 };
 
 
-#define DO_IOREMAP(_m, _d) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size, (_d))
+#define DO_IOREMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size)
 
-#define DO_IOREMAPFREE(_m, _d)						\
+#define DO_IOREMAPFREE(_m)						\
 	do {								\
 		if ((_m)->handle && (_m)->size)				\
-			drm_ioremapfree((_m)->handle, (_m)->size, (_d));\
+			drm_ioremapfree((_m)->handle, (_m)->size);	\
 	} while (0)
 
 #define DO_FIND_MAP(_m, _o)						\
@@ -757,12 +757,12 @@
 		(drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle +
 				       init->sarea_priv_offset);
 
-	DO_IOREMAP( dev_priv->cp_ring, dev );
-	DO_IOREMAP( dev_priv->ring_rptr, dev );
-	DO_IOREMAP( dev_priv->buffers, dev );
+	DO_IOREMAP( dev_priv->cp_ring );
+	DO_IOREMAP( dev_priv->ring_rptr );
+	DO_IOREMAP( dev_priv->buffers );
 #if 0
 	if ( !dev_priv->is_pci ) {
-		DO_IOREMAP( dev_priv->agp_textures, dev );
+		DO_IOREMAP( dev_priv->agp_textures );
 	}
 #endif
 
@@ -828,12 +828,12 @@
 	if ( dev->dev_private ) {
 		drm_radeon_private_t *dev_priv = dev->dev_private;
 
-		DO_IOREMAPFREE( dev_priv->cp_ring, dev );
-		DO_IOREMAPFREE( dev_priv->ring_rptr, dev );
-		DO_IOREMAPFREE( dev_priv->buffers, dev );
+		DO_IOREMAPFREE( dev_priv->cp_ring );
+		DO_IOREMAPFREE( dev_priv->ring_rptr );
+		DO_IOREMAPFREE( dev_priv->buffers );
 #if 0
 		if ( !dev_priv->is_pci ) {
-			DO_IOREMAPFREE( dev_priv->agp_textures, dev );
+			DO_IOREMAPFREE( dev_priv->agp_textures );
 		}
 #endif
 
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/radeon_drv.c linux-2.4.22-bk32/drivers/char/drm-4.0/radeon_drv.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/radeon_drv.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/radeon_drv.c	2002-02-25 11:37:57.000000000 -0800
@@ -294,7 +294,7 @@
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
 #endif
-				drm_ioremapfree(map->handle, map->size, dev);
+				drm_ioremapfree(map->handle, map->size);
 				break;
 			case _DRM_SHM:
 				drm_free_pages((unsigned long)map->handle,
diff -urN linux-2.4.22-bk31/drivers/char/drm-4.0/tdfx_drv.c linux-2.4.22-bk32/drivers/char/drm-4.0/tdfx_drv.c
--- linux-2.4.22-bk31/drivers/char/drm-4.0/tdfx_drv.c	2003-10-10 02:50:39.000000000 -0700
+++ linux-2.4.22-bk32/drivers/char/drm-4.0/tdfx_drv.c	2002-11-28 15:53:12.000000000 -0800
@@ -264,7 +264,7 @@
 					DRM_DEBUG("mtrr_del = %d\n", retcode);
 				}
 #endif
-				drm_ioremapfree(map->handle, map->size, dev);
+				drm_ioremapfree(map->handle, map->size);
 				break;
 			case _DRM_SHM:
 				drm_free_pages((unsigned long)map->handle,
diff -urN linux-2.4.22-bk31/drivers/net/pppoe.c linux-2.4.22-bk32/drivers/net/pppoe.c
--- linux-2.4.22-bk31/drivers/net/pppoe.c	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk32/drivers/net/pppoe.c	2003-10-10 02:50:47.000000000 -0700
@@ -654,8 +654,10 @@
 	release_sock(sk);
 	return error;
 err_put:
-	dev_put(po->pppoe_dev);
-	po->pppoe_dev = NULL;
+	if (po->pppoe_dev) {
+		dev_put(po->pppoe_dev);
+		po->pppoe_dev = NULL;
+	}
 	goto end;
 }
 
diff -urN linux-2.4.22-bk31/drivers/scsi/Config.in linux-2.4.22-bk32/drivers/scsi/Config.in
--- linux-2.4.22-bk31/drivers/scsi/Config.in	2003-08-25 04:44:42.000000000 -0700
+++ linux-2.4.22-bk32/drivers/scsi/Config.in	2003-10-10 02:50:47.000000000 -0700
@@ -67,6 +67,7 @@
 dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
 dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI $CONFIG_PCI
 dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI
+dep_tristate 'AMI MegaRAID2 support' CONFIG_SCSI_MEGARAID2 $CONFIG_SCSI
 
 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
 if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then
diff -urN linux-2.4.22-bk31/drivers/scsi/Makefile linux-2.4.22-bk32/drivers/scsi/Makefile
--- linux-2.4.22-bk31/drivers/scsi/Makefile	2003-10-10 02:50:41.000000000 -0700
+++ linux-2.4.22-bk32/drivers/scsi/Makefile	2003-10-10 02:50:47.000000000 -0700
@@ -97,7 +97,7 @@
 obj-$(CONFIG_SCSI_NCR53C7xx)	+= 53c7,8xx.o 
 subdir-$(CONFIG_SCSI_SYM53C8XX_2)	+= sym53c8xx_2
 ifeq ($(CONFIG_SCSI_SYM53C8XX_2),y)
-  obj-$(CONFIG_SCSI_SYM53C8XX_2)	+= sym53c8xx_2/sym53c8xx.o
+  obj-$(CONFIG_SCSI_SYM53C8XX_2)	+= sym53c8xx_2/sym53c8xx_2.o
 endif
 obj-$(CONFIG_SCSI_SYM53C8XX)	+= sym53c8xx.o 
 obj-$(CONFIG_SCSI_NCR53C8XX)	+= ncr53c8xx.o 
@@ -110,7 +110,7 @@
 obj-$(CONFIG_SCSI_DC390T)	+= tmscsim.o
 obj-$(CONFIG_SCSI_AM53C974)	+= AM53C974.o
 obj-$(CONFIG_SCSI_MEGARAID)	+= megaraid.o
-obj-$(CONFIG_SCSI_MEGARAID2)   += megaraid2.o
+obj-$(CONFIG_SCSI_MEGARAID2)	+= megaraid2.o
 obj-$(CONFIG_SCSI_ACARD)	+= atp870u.o
 obj-$(CONFIG_SCSI_SUNESP)	+= esp.o
 obj-$(CONFIG_SCSI_GDTH)		+= gdth.o
diff -urN linux-2.4.22-bk31/drivers/scsi/pcmcia/nsp_cs.h linux-2.4.22-bk32/drivers/scsi/pcmcia/nsp_cs.h
--- linux-2.4.22-bk31/drivers/scsi/pcmcia/nsp_cs.h	2003-10-10 02:50:42.000000000 -0700
+++ linux-2.4.22-bk32/drivers/scsi/pcmcia/nsp_cs.h	2003-10-10 02:50:47.000000000 -0700
@@ -432,7 +432,6 @@
 # define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template)
 # define scsi_host_put(host)            scsi_unregister(host)
 
-typedef void irqreturn_t;
 # define IRQ_NONE      /* */
 # define IRQ_HANDLED   /* */
 # define IRQ_RETVAL(x) /* */
diff -urN linux-2.4.22-bk31/drivers/scsi/sym53c8xx_2/Makefile linux-2.4.22-bk32/drivers/scsi/sym53c8xx_2/Makefile
--- linux-2.4.22-bk31/drivers/scsi/sym53c8xx_2/Makefile	2001-11-09 15:22:54.000000000 -0800
+++ linux-2.4.22-bk32/drivers/scsi/sym53c8xx_2/Makefile	2003-10-10 02:50:47.000000000 -0700
@@ -1,14 +1,14 @@
-# File: drivers/sym53c8xx/Makefile
+# File: drivers/scsi/sym53c8xx_2/Makefile
 # Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver.
 
-list-multi := sym53c8xx.o
-sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_misc.o sym_nvram.o
-obj-$(CONFIG_SCSI_SYM53C8XX_2) := sym53c8xx.o
+list-multi := sym53c8xx_2.o
+sym53c8xx_2-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_misc.o sym_nvram.o
+obj-$(CONFIG_SCSI_SYM53C8XX_2) := sym53c8xx_2.o
 
 EXTRA_CFLAGS += -I.
 
-sym53c8xx.o: $(sym53c8xx-objs)
-	$(LD) -r -o $@ $(sym53c8xx-objs)
+sym53c8xx_2.o: $(sym53c8xx_2-objs)
+	$(LD) -r -o $@ $(sym53c8xx_2-objs)
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.22-bk31/fs/buffer.c linux-2.4.22-bk32/fs/buffer.c
--- linux-2.4.22-bk31/fs/buffer.c	2003-10-10 02:50:42.000000000 -0700
+++ linux-2.4.22-bk32/fs/buffer.c	2003-10-10 02:50:48.000000000 -0700
@@ -88,6 +88,13 @@
 static int osync_buffers_list(struct list_head *);
 static void __refile_buffer(struct buffer_head *);
 
+/*
+ * A global sysctl-controlled flag which puts the machine into "laptop mode"
+ */
+int laptop_mode;
+
+static DECLARE_WAIT_QUEUE_HEAD(kupdate_wait);
+
 /* This is used by some architectures to estimate available memory. */
 atomic_t buffermem_pages = ATOMIC_INIT(0);
 
@@ -1016,7 +1023,7 @@
 	dirty *= 100;
 	dirty_limit = tot * bdf_prm.b_un.nfract_stop_bdflush;
 
-	if (dirty > dirty_limit)
+	if (!laptop_mode && dirty > dirty_limit)
 		return 0;
 	return 1;
 }
@@ -1066,6 +1073,8 @@
 void mark_buffer_dirty(struct buffer_head *bh)
 {
 	if (!atomic_set_buffer_dirty(bh)) {
+		if (block_dump)
+			printk("%s: dirtied buffer\n", current->comm);
 		__mark_dirty(bh);
 		balance_dirty();
 	}
@@ -1077,6 +1086,12 @@
 }
 EXPORT_SYMBOL(set_buffer_flushtime);
 
+inline int get_buffer_flushtime(void)
+{
+	return bdf_prm.b_un.interval;
+}
+EXPORT_SYMBOL(get_buffer_flushtime);
+
 /*
  * A buffer may need to be moved from one buffer list to another
  * (e.g. in case it is not shared any more). Handle this.
@@ -2860,6 +2875,12 @@
 	wake_up_interruptible(&bdflush_wait);
 }
 
+void wakeup_kupdate(void)
+{
+	if (waitqueue_active(&kupdate_wait))
+		wake_up(&kupdate_wait);
+}
+
 /* 
  * Here we attempt to write back old buffers.  We also try to flush inodes 
  * and supers as well, since this function is essentially "update", and 
@@ -2880,7 +2901,9 @@
 
 		spin_lock(&lru_list_lock);
 		bh = lru_list[BUF_DIRTY];
-		if (!bh || time_before(jiffies, bh->b_flushtime))
+		if (!bh)
+			break;
+		if (time_before(jiffies, bh->b_flushtime) && !laptop_mode)
 			break;
 		if (write_some_buffers(NODEV))
 			continue;
@@ -3028,16 +3051,20 @@
 	complete((struct completion *)startup);
 
 	for (;;) {
+		DECLARE_WAITQUEUE(wait, tsk);
+
+		add_wait_queue(&kupdate_wait, &wait);
+
 		/* update interval */
 		interval = bdf_prm.b_un.interval;
 		if (interval) {
 			tsk->state = TASK_INTERRUPTIBLE;
 			schedule_timeout(interval);
 		} else {
-		stop_kupdate:
 			tsk->state = TASK_STOPPED;
 			schedule(); /* wait for SIGCONT */
 		}
+		remove_wait_queue(&kupdate_wait, &wait);
 		/* check for sigstop */
 		if (signal_pending(tsk)) {
 			int sig, stopped = 0;
@@ -3048,13 +3075,17 @@
 			if (sig == SIGSTOP)
 				stopped = 1;
 			spin_unlock_irq(&tsk->sigmask_lock);
-			if (stopped)
-				goto stop_kupdate;
+			if (stopped) {
+				tsk->state = TASK_STOPPED;
+				schedule(); /* wait for SIGCONT */
+			}
 		}
 #ifdef DEBUG
 		printk(KERN_DEBUG "kupdate() activated...\n");
 #endif
 		sync_old_buffers();
+		if (laptop_mode)
+			fsync_dev(NODEV);
 		run_task_queue(&tq_disk);
 	}
 }
diff -urN linux-2.4.22-bk31/fs/exec.c linux-2.4.22-bk32/fs/exec.c
--- linux-2.4.22-bk31/fs/exec.c	2003-10-10 02:50:42.000000000 -0700
+++ linux-2.4.22-bk32/fs/exec.c	2003-10-10 02:50:48.000000000 -0700
@@ -426,11 +426,6 @@
 	struct mm_struct * mm, * old_mm;
 
 	old_mm = current->mm;
-	if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
-		mm_release();
-		exit_mmap(old_mm);
-		return 0;
-	}
 
 	mm = mm_alloc();
 	if (mm) {
diff -urN linux-2.4.22-bk31/fs/jbd/journal.c linux-2.4.22-bk32/fs/jbd/journal.c
--- linux-2.4.22-bk31/fs/jbd/journal.c	2003-08-25 04:44:43.000000000 -0700
+++ linux-2.4.22-bk32/fs/jbd/journal.c	2003-10-10 02:50:48.000000000 -0700
@@ -705,7 +705,7 @@
 	init_MUTEX(&journal->j_checkpoint_sem);
 	init_MUTEX(&journal->j_sem);
 
-	journal->j_commit_interval = (HZ * 5);
+	journal->j_commit_interval = get_buffer_flushtime();
 
 	/* The journal is marked for error until we succeed with recovery! */
 	journal->j_flags = JFS_ABORT;
diff -urN linux-2.4.22-bk31/include/asm-i386/edd.h linux-2.4.22-bk32/include/asm-i386/edd.h
--- linux-2.4.22-bk31/include/asm-i386/edd.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.22-bk32/include/asm-i386/edd.h	2003-10-10 02:50:48.000000000 -0700
@@ -0,0 +1,172 @@
+/*
+ * linux/include/asm-i386/edd.h
+ *  Copyright (C) 2002 Dell Computer Corporation
+ *  by Matt Domsch <Matt_Domsch@dell.com>
+ *
+ * structures and definitions for the int 13h, ax={41,48}h
+ * BIOS Enhanced Disk Drive Services
+ * This is based on the T13 group document D1572 Revision 0 (August 14 2002)
+ * available at http://www.t13.org/docs2002/d1572r0.pdf.  It is
+ * very similar to D1484 Revision 3 http://www.t13.org/docs2002/d1484r3.pdf
+ *
+ * In a nutshell, arch/i386/boot/setup.S populates a scratch table
+ * in the empty_zero_block that contains a list of BIOS-enumerated
+ * boot devices.
+ * In arch/i386/kernel/setup.c, this information is
+ * transferred into the edd structure, and in arch/i386/kernel/edd.c, that
+ * information is used to identify BIOS boot disk.  The code in setup.S
+ * is very sensitive to the size of these structures.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 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.
+ *
+ */
+#ifndef _ASM_I386_EDD_H
+#define _ASM_I386_EDD_H
+
+#define EDDNR 0x1e9		/* addr of number of edd_info structs at EDDBUF
+				   in empty_zero_block - treat this as 1 byte  */
+#define EDDBUF	0x600		/* addr of edd_info structs in empty_zero_block */
+#define EDDMAXNR 6		/* number of edd_info structs starting at EDDBUF  */
+#define EDDEXTSIZE 4		/* change these if you muck with the structures */
+#define EDDPARMSIZE 74
+#define CHECKEXTENSIONSPRESENT 0x41
+#define GETDEVICEPARAMETERS 0x48
+#define EDDMAGIC1 0x55AA
+#define EDDMAGIC2 0xAA55
+
+#ifndef __ASSEMBLY__
+
+#define EDD_EXT_FIXED_DISK_ACCESS           (1 << 0)
+#define EDD_EXT_DEVICE_LOCKING_AND_EJECTING (1 << 1)
+#define EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT (1 << 2)
+#define EDD_EXT_64BIT_EXTENSIONS            (1 << 3)
+
+#define EDD_INFO_DMA_BOUNDRY_ERROR_TRANSPARENT (1 << 0)
+#define EDD_INFO_GEOMETRY_VALID                (1 << 1)
+#define EDD_INFO_REMOVABLE                     (1 << 2)
+#define EDD_INFO_WRITE_VERIFY                  (1 << 3)
+#define EDD_INFO_MEDIA_CHANGE_NOTIFICATION     (1 << 4)
+#define EDD_INFO_LOCKABLE                      (1 << 5)
+#define EDD_INFO_NO_MEDIA_PRESENT              (1 << 6)
+#define EDD_INFO_USE_INT13_FN50                (1 << 7)
+
+struct edd_device_params {
+	u16 length;
+	u16 info_flags;
+	u32 num_default_cylinders;
+	u32 num_default_heads;
+	u32 sectors_per_track;
+	u64 number_of_sectors;
+	u16 bytes_per_sector;
+	u32 dpte_ptr;		/* 0xFFFFFFFF for our purposes */
+	u16 key;		/* = 0xBEDD */
+	u8 device_path_info_length;	/* = 44 */
+	u8 reserved2;
+	u16 reserved3;
+	u8 host_bus_type[4];
+	u8 interface_type[8];
+	union {
+		struct {
+			u16 base_address;
+			u16 reserved1;
+			u32 reserved2;
+		} __attribute__ ((packed)) isa;
+		struct {
+			u8 bus;
+			u8 slot;
+			u8 function;
+			u8 channel;
+			u32 reserved;
+		} __attribute__ ((packed)) pci;
+		/* pcix is same as pci */
+		struct {
+			u64 reserved;
+		} __attribute__ ((packed)) ibnd;
+		struct {
+			u64 reserved;
+		} __attribute__ ((packed)) xprs;
+		struct {
+			u64 reserved;
+		} __attribute__ ((packed)) htpt;
+		struct {
+			u64 reserved;
+		} __attribute__ ((packed)) unknown;
+	} interface_path;
+	union {
+		struct {
+			u8 device;
+			u8 reserved1;
+			u16 reserved2;
+			u32 reserved3;
+			u64 reserved4;
+		} __attribute__ ((packed)) ata;
+		struct {
+			u8 device;
+			u8 lun;
+			u8 reserved1;
+			u8 reserved2;
+			u32 reserved3;
+			u64 reserved4;
+		} __attribute__ ((packed)) atapi;
+		struct {
+			u16 id;
+			u64 lun;
+			u16 reserved1;
+			u32 reserved2;
+		} __attribute__ ((packed)) scsi;
+		struct {
+			u64 serial_number;
+			u64 reserved;
+		} __attribute__ ((packed)) usb;
+		struct {
+			u64 eui;
+			u64 reserved;
+		} __attribute__ ((packed)) i1394;
+		struct {
+			u64 wwid;
+			u64 lun;
+		} __attribute__ ((packed)) fibre;
+		struct {
+			u64 identity_tag;
+			u64 reserved;
+		} __attribute__ ((packed)) i2o;
+		struct {
+			u32 array_number;
+			u32 reserved1;
+			u64 reserved2;
+		} __attribute((packed)) raid;
+		struct {
+			u8 device;
+			u8 reserved1;
+			u16 reserved2;
+			u32 reserved3;
+			u64 reserved4;
+		} __attribute__ ((packed)) sata;
+		struct {
+			u64 reserved1;
+			u64 reserved2;
+		} __attribute__ ((packed)) unknown;
+	} device_path;
+	u8 reserved4;
+	u8 checksum;
+} __attribute__ ((packed));
+
+struct edd_info {
+	u8 device;
+	u8 version;
+	u16 interface_support;
+	struct edd_device_params params;
+} __attribute__ ((packed));
+
+extern struct edd_info edd[EDDMAXNR];
+extern unsigned char eddnr;
+#endif				/*!__ASSEMBLY__ */
+
+#endif				/* _ASM_I386_EDD_H */
diff -urN linux-2.4.22-bk31/include/linux/fs.h linux-2.4.22-bk32/include/linux/fs.h
--- linux-2.4.22-bk31/include/linux/fs.h	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/include/linux/fs.h	2003-10-10 02:50:48.000000000 -0700
@@ -1255,6 +1255,7 @@
 }
 
 extern void set_buffer_flushtime(struct buffer_head *);
+extern inline int get_buffer_flushtime(void);
 extern void balance_dirty(void);
 extern int check_disk_change(kdev_t);
 extern int invalidate_inodes(struct super_block *);
@@ -1445,8 +1446,10 @@
 	return get_hash_table(sb->s_dev, block, sb->s_blocksize);
 }
 extern void wakeup_bdflush(void);
+extern void wakeup_kupdate(void);
 extern void put_unused_buffer_head(struct buffer_head * bh);
 extern struct buffer_head * get_unused_buffer_head(int async);
+extern int block_dump;
 
 extern int brw_page(int, struct page *, kdev_t, int [], int);
 
diff -urN linux-2.4.22-bk31/include/linux/in.h linux-2.4.22-bk32/include/linux/in.h
--- linux-2.4.22-bk31/include/linux/in.h	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/include/linux/in.h	2003-10-10 02:50:48.000000000 -0700
@@ -137,29 +137,29 @@
 
 struct group_req
 {
-	__u32			gr_interface;	/* interface index */
-	struct sockaddr_storage	gr_group;	/* group address */
+	__u32				 gr_interface;	/* interface index */
+	struct __kernel_sockaddr_storage gr_group;	/* group address */
 };
 
 struct group_source_req
 {
-	__u32			gsr_interface;	/* interface index */
-	struct sockaddr_storage	gsr_group;	/* group address */
-	struct sockaddr_storage	gsr_source;	/* source address */
+	__u32				 gsr_interface;	/* interface index */
+	struct __kernel_sockaddr_storage gsr_group;	/* group address */
+	struct __kernel_sockaddr_storage gsr_source;	/* source address */
 };
 
 struct group_filter
 {
-	__u32			gf_interface;	/* interface index */
-	struct sockaddr_storage	gf_group;	/* multicast address */
-	__u32			gf_fmode;	/* filter mode */
-	__u32			gf_numsrc;	/* number of sources */
-	struct sockaddr_storage	gf_slist[1];	/* interface index */
+	__u32				 gf_interface;	/* interface index */
+	struct __kernel_sockaddr_storage gf_group;	/* multicast address */
+	__u32				 gf_fmode;	/* filter mode */
+	__u32				 gf_numsrc;	/* number of sources */
+	struct __kernel_sockaddr_storage gf_slist[1];	/* interface index */
 };
 
 #define GROUP_FILTER_SIZE(numsrc) \
-	(sizeof(struct group_filter) - sizeof(struct sockaddr_storage) \
-	+ (numsrc) * sizeof(struct sockaddr_storage))
+	(sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \
+	+ (numsrc) * sizeof(struct __kernel_sockaddr_storage))
 
 struct in_pktinfo
 {
diff -urN linux-2.4.22-bk31/include/linux/netdevice.h linux-2.4.22-bk32/include/linux/netdevice.h
--- linux-2.4.22-bk31/include/linux/netdevice.h	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/include/linux/netdevice.h	2003-10-10 02:50:48.000000000 -0700
@@ -204,7 +204,7 @@
 	(HH_DATA_MOD - ((__len) & (HH_DATA_MOD - 1)))
 #define HH_DATA_ALIGN(__len) \
 	(((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1))
-	unsigned long	hh_data[HH_DATA_ALIGN(LL_MAX_HEADER)];
+	unsigned long	hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];
 };
 
 /* These flag bits are private to the generic network queueing
diff -urN linux-2.4.22-bk31/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.4.22-bk32/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
--- linux-2.4.22-bk31/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	2002-02-25 11:38:13.000000000 -0800
+++ linux-2.4.22-bk32/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	2003-10-10 02:50:48.000000000 -0700
@@ -62,6 +62,14 @@
 	} dst;
 };
 
+/* This is optimized opposed to a memset of the whole structure.  Everything we
+ * really care about is the  source/destination unions */
+#define IP_CT_TUPLE_U_BLANK(tuple) 				\
+	do {							\
+		(tuple)->src.u.all = 0;				\
+		(tuple)->dst.u.all = 0;				\
+	} while (0)
+
 enum ip_conntrack_dir
 {
 	IP_CT_DIR_ORIGINAL,
diff -urN linux-2.4.22-bk31/include/linux/netfilter_ipv4/ip_nat_rule.h linux-2.4.22-bk32/include/linux/netfilter_ipv4/ip_nat_rule.h
--- linux-2.4.22-bk31/include/linux/netfilter_ipv4/ip_nat_rule.h	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.22-bk32/include/linux/netfilter_ipv4/ip_nat_rule.h	2003-10-10 02:50:48.000000000 -0700
@@ -14,5 +14,10 @@
 			    const struct net_device *out,
 			    struct ip_conntrack *ct,
 			    struct ip_nat_info *info);
+
+extern unsigned int
+alloc_null_binding(struct ip_conntrack *conntrack,
+		   struct ip_nat_info *info,
+		   unsigned int hooknum);
 #endif
 #endif /* _IP_NAT_RULE_H */
diff -urN linux-2.4.22-bk31/include/linux/socket.h linux-2.4.22-bk32/include/linux/socket.h
--- linux-2.4.22-bk31/include/linux/socket.h	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/include/linux/socket.h	2003-10-10 02:50:48.000000000 -0700
@@ -1,6 +1,21 @@
 #ifndef _LINUX_SOCKET_H
 #define _LINUX_SOCKET_H
 
+/*
+ * Desired design of maximum size and alignment (see RFC2553)
+ */
+#define _K_SS_MAXSIZE	128	/* Implementation specific max size */
+#define _K_SS_ALIGNSIZE	(__alignof__ (struct sockaddr *))
+				/* Implementation specific desired alignment */
+
+struct __kernel_sockaddr_storage {
+	unsigned short	ss_family;		/* address family */
+	/* Following field(s) are implementation specific */
+	char		__data[_K_SS_MAXSIZE - sizeof(unsigned short)];
+				/* space to achieve desired size, */
+				/* _SS_MAXSIZE value minus size of ss_family */
+} __attribute__ ((aligned(_K_SS_ALIGNSIZE)));	/* force desired alignment */
+
 #if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
 
 #include <asm/socket.h>			/* arch-dependent defines	*/
@@ -24,20 +39,7 @@
 	int		l_linger;	/* How long to linger for	*/
 };
 
-/*
- * Desired design of maximum size and alignment (see RFC2553)
- */
-#define _SS_MAXSIZE	128	/* Implementation specific max size */
-#define _SS_ALIGNSIZE	(__alignof__ (struct sockaddr *))
-				/* Implementation specific desired alignment */
-
-struct sockaddr_storage {
-	sa_family_t	ss_family;		/* address family */
-	/* Following field(s) are implementation specific */
-	char		__data[_SS_MAXSIZE - sizeof(sa_family_t)];
-				/* space to achieve desired size, */
-				/* _SS_MAXSIZE value minus size of ss_family */
-} __attribute__ ((aligned(_SS_ALIGNSIZE)));	/* force desired alignment */
+#define sockaddr_storage __kernel_sockaddr_storage
 
 /*
  *	As we do 4.4BSD message passing we use a 4.4BSD message passing
diff -urN linux-2.4.22-bk31/include/linux/sysctl.h linux-2.4.22-bk32/include/linux/sysctl.h
--- linux-2.4.22-bk31/include/linux/sysctl.h	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/include/linux/sysctl.h	2003-10-10 02:50:48.000000000 -0700
@@ -154,6 +154,8 @@
 	VM_GFP_DEBUG=18,        /* debug GFP failures */
 	VM_CACHE_SCAN_RATIO=19, /* part of the inactive cache list to scan */
 	VM_MAPPED_RATIO=20,     /* amount of unfreeable pages that triggers swapout */
+	VM_LAPTOP_MODE=21,	/* kernel in laptop flush mode */
+	VM_BLOCK_DUMP=22,	/* dump fs activity to log */
 };
 
 
@@ -245,6 +247,7 @@
 	NET_IPV4_NEIGH=17,
 	NET_IPV4_ROUTE=18,
 	NET_IPV4_FIB_HASH=19,
+	NET_IPV4_NETFILTER=20,
 
 	NET_IPV4_TCP_TIMESTAMPS=33,
 	NET_IPV4_TCP_WINDOW_SCALING=34,
@@ -357,6 +360,24 @@
 	NET_IPV4_CONF_MEDIUM_ID=14,
 };
 
+/* /proc/sys/net/ipv4/netfilter */
+enum
+{
+	NET_IPV4_NF_CONNTRACK_MAX=1,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8,
+	NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9,
+	NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT=10,
+	NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11,
+	NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=12,
+	NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=13,
+};
+ 
 /* /proc/sys/net/ipv6 */
 enum {
 	NET_IPV6_CONF=16,
diff -urN linux-2.4.22-bk31/kernel/sysctl.c linux-2.4.22-bk32/kernel/sysctl.c
--- linux-2.4.22-bk31/kernel/sysctl.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/kernel/sysctl.c	2003-10-10 02:50:48.000000000 -0700
@@ -53,6 +53,8 @@
 extern int core_setuid_ok;
 extern char core_pattern[];
 extern int cad_pid;
+extern int laptop_mode;
+extern int block_dump;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -306,6 +308,10 @@
 	&vm_max_readahead,sizeof(int), 0644, NULL, &proc_dointvec},
 	{VM_MAX_MAP_COUNT, "max_map_count",
 	 &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec},
+	{VM_LAPTOP_MODE, "laptop_mode",
+	 &laptop_mode, sizeof(int), 0644, NULL, &proc_dointvec},
+	{VM_BLOCK_DUMP, "block_dump",
+	 &block_dump, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -urN linux-2.4.22-bk31/mm/filemap.c linux-2.4.22-bk32/mm/filemap.c
--- linux-2.4.22-bk31/mm/filemap.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/mm/filemap.c	2003-10-10 02:50:48.000000000 -0700
@@ -165,6 +165,8 @@
 
 			if (mapping && mapping->host)
 				mark_inode_dirty_pages(mapping->host);
+			if (block_dump)
+				printk(KERN_DEBUG "%s: dirtied page\n", current->comm);
 		}
 	}
 }
@@ -654,6 +656,12 @@
 	struct address_space *mapping, unsigned long offset,
 	struct page **hash)
 {
+	/*
+	 * Yes this is inefficient, however it is needed.  The problem
+	 * is that we could be adding a page to the swap cache while
+	 * another CPU is also modifying page->flags, so the updates
+	 * really do need to be atomic.  -- Rik
+	 */
 	ClearPageUptodate(page);
 	ClearPageError(page);
 	ClearPageDirty(page);
diff -urN linux-2.4.22-bk31/net/8021q/vlan_dev.c linux-2.4.22-bk32/net/8021q/vlan_dev.c
--- linux-2.4.22-bk31/net/8021q/vlan_dev.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/net/8021q/vlan_dev.c	2003-10-10 02:50:48.000000000 -0700
@@ -75,7 +75,11 @@
 static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
 {
 	if (VLAN_DEV_INFO(skb->dev)->flags & 1) {
-		skb = skb_share_check(skb, GFP_ATOMIC);
+		if (skb_shared(skb) || skb_cloned(skb)) {
+			struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
+			kfree(skb);
+			skb = nskb;
+		}
 		if (skb) {
 			/* Lifted from Gleb's VLAN code... */
 			memmove(skb->data - ETH_HLEN,
diff -urN linux-2.4.22-bk31/net/ipv4/igmp.c linux-2.4.22-bk32/net/ipv4/igmp.c
--- linux-2.4.22-bk31/net/ipv4/igmp.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/igmp.c	2003-10-10 02:50:49.000000000 -0700
@@ -1374,8 +1374,9 @@
 	sf_markstate(pmc);
 #endif
 	if (!delta) {
+		err = -EINVAL;
 		if (!pmc->sfcount[sfmode])
-			return -EINVAL;
+			goto out_unlock;
 		pmc->sfcount[sfmode]--;
 	}
 	err = 0;
@@ -1406,6 +1407,7 @@
 		igmp_ifc_event(pmc->interface);
 #endif
 	}
+out_unlock:
 	spin_unlock_bh(&pmc->lock);
 	return err;
 }
diff -urN linux-2.4.22-bk31/net/ipv4/ip_gre.c linux-2.4.22-bk32/net/ipv4/ip_gre.c
--- linux-2.4.22-bk31/net/ipv4/ip_gre.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/ip_gre.c	2003-10-10 02:50:49.000000000 -0700
@@ -807,8 +807,6 @@
 			tunnel->err_count = 0;
 	}
 
-	skb->h.raw = skb->nh.raw;
-
 	max_headroom = ((tdev->hard_header_len+15)&~15)+ gre_hlen;
 
 	if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
@@ -827,6 +825,7 @@
 		old_iph = skb->nh.iph;
 	}
 
+	skb->h.raw = skb->nh.raw;
 	skb->nh.raw = skb_push(skb, gre_hlen);
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	dst_release(skb->dst);
diff -urN linux-2.4.22-bk31/net/ipv4/ipip.c linux-2.4.22-bk32/net/ipv4/ipip.c
--- linux-2.4.22-bk31/net/ipv4/ipip.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/ipip.c	2003-10-10 02:50:49.000000000 -0700
@@ -603,8 +603,6 @@
 			tunnel->err_count = 0;
 	}
 
-	skb->h.raw = skb->nh.raw;
-
 	/*
 	 * Okay, now see if we can stuff it in the buffer as-is.
 	 */
@@ -626,6 +624,7 @@
 		old_iph = skb->nh.iph;
 	}
 
+	skb->h.raw = skb->nh.raw;
 	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	dst_release(skb->dst);
diff -urN linux-2.4.22-bk31/net/ipv4/ipvs/ip_vs_conn.c linux-2.4.22-bk32/net/ipv4/ipvs/ip_vs_conn.c
--- linux-2.4.22-bk31/net/ipv4/ipvs/ip_vs_conn.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/ipvs/ip_vs_conn.c	2003-10-10 02:50:49.000000000 -0700
@@ -903,9 +903,8 @@
 			skb_realloc_headroom(skb, max_headroom);
 		if (!new_skb) {
 			ip_rt_put(rt);
-			kfree_skb(skb);
 			IP_VS_ERR_RL("ip_vs_tunnel_xmit(): no memory\n");
-			return -EINVAL;
+			return NF_DROP;
 		}
 		kfree_skb(skb);
 		skb = new_skb;
diff -urN linux-2.4.22-bk31/net/ipv4/ipvs/ip_vs_ftp.c linux-2.4.22-bk32/net/ipv4/ipvs/ip_vs_ftp.c
--- linux-2.4.22-bk31/net/ipv4/ipvs/ip_vs_ftp.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/ipvs/ip_vs_ftp.c	2003-10-10 02:50:49.000000000 -0700
@@ -88,39 +88,46 @@
 				  __u32 *addr, __u16 *port,
 				  char **start, char **end)
 {
-	unsigned char p1,p2,p3,p4,p5,p6;
+	unsigned char p[6];
+	int i = 0;
 
-	while (data < data_limit) {
-		if (strnicmp(data, pattern, plen) != 0) {
-			data++;
-			continue;
+	if (data_limit - data < plen) {
+		/* check if there is partial match */
+		if (strnicmp(data, pattern, data_limit - data) == 0)
+			return -1;
+		else
+			return 0;
+	}
+
+	if (strnicmp(data, pattern, plen) != 0) {
+		return 0;
+	}
+	*start = data + plen;
+
+	for (data = *start; *data != term; data++) {
+		if (data == data_limit)
+			return -1;
+	}
+	*end = data;
+
+	memset(p, 0, sizeof(p));
+	for (data = *start; data != *end; data++) {
+		if (*data >= '0' && *data <= '9') {
+			p[i] = p[i]*10 + *data - '0';
+		} else if (*data == ',' && i < 5) {
+			i++;
+		} else {
+			/* unexpected character */
+			return -1;
 		}
-		*start = data+plen;
-		p1 = simple_strtoul(data+plen, &data, 10);
-		if (*data != ',')
-			continue;
-		p2 = simple_strtoul(data+1, &data, 10);
-		if (*data != ',')
-			continue;
-		p3 = simple_strtoul(data+1, &data, 10);
-		if (*data != ',')
-			continue;
-		p4 = simple_strtoul(data+1, &data, 10);
-		if (*data != ',')
-			continue;
-		p5 = simple_strtoul(data+1, &data, 10);
-		if (*data != ',')
-			continue;
-		p6 = simple_strtoul(data+1, &data, 10);
-		if (*data != term)
-			continue;
-
-		*end = data;
-		*addr = (p4<<24) | (p3<<16) | (p2<<8) | p1;
-		*port = (p6<<8) | p5;
-		return 1;
 	}
-	return 0;
+
+	if (i != 5)
+		return -1;
+
+	*addr = (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
+	*port = (p[5]<<8) | p[4];
+	return 1;
 }
 
 
@@ -165,7 +172,7 @@
 					   SERVER_STRING,
 					   sizeof(SERVER_STRING)-1, ')',
 					   &from, &port,
-					   &start, &end) == 0)
+					   &start, &end) != 1)
 			return 0;
 
 		IP_VS_DBG(1-debug, "PASV response (%u.%u.%u.%u:%d) -> "
@@ -265,7 +272,7 @@
 	data = data_start = (char *)th + (th->doff << 2);
 	data_limit = skb->tail;
 
-	while (data < data_limit) {
+	while (data <= data_limit - 6) {
 		if (strnicmp(data, "PASV\r\n", 6) == 0) {
 			IP_VS_DBG(1-debug, "got PASV at %d of %d\n",
 				  data - data_start,
@@ -283,13 +290,10 @@
 	 * then create a new connection entry for the coming data
 	 * connection.
 	 */
-	data = data_start;
-	data_limit = skb->h.raw + skb->len - 18;
-
-	if (ip_vs_ftp_get_addrport(data, data_limit,
+	if (ip_vs_ftp_get_addrport(data_start, data_limit,
 				   CLIENT_STRING, sizeof(CLIENT_STRING)-1,
 				   '\r', &to, &port,
-				   &start, &end) == 0)
+				   &start, &end) != 1)
 		return 0;
 
 	IP_VS_DBG(1-debug, "PORT %u.%u.%u.%u:%d detected\n",
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_core.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_core.c	2003-10-10 02:50:49.000000000 -0700
@@ -60,7 +60,7 @@
 LIST_HEAD(protocol_list);
 static LIST_HEAD(helpers);
 unsigned int ip_conntrack_htable_size = 0;
-static int ip_conntrack_max = 0;
+int ip_conntrack_max = 0;
 static atomic_t ip_conntrack_count = ATOMIC_INIT(0);
 struct list_head *ip_conntrack_hash;
 static kmem_cache_t *ip_conntrack_cachep;
@@ -308,7 +308,7 @@
 static void
 destroy_conntrack(struct nf_conntrack *nfct)
 {
-	struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
+	struct ip_conntrack *ct = (struct ip_conntrack *)nfct, *master = NULL;
 	struct ip_conntrack_protocol *proto;
 
 	DEBUGP("destroy_conntrack(%p)\n", ct);
@@ -335,12 +335,15 @@
 			/* can't call __unexpect_related here,
 			 * since it would screw up expect_list */
 			list_del(&ct->master->expected_list);
-			ip_conntrack_put(ct->master->expectant);
+			master = ct->master->expectant;
 		}
 		kfree(ct->master);
 	}
 	WRITE_UNLOCK(&ip_conntrack_lock);
 
+	if (master)
+		ip_conntrack_put(master);
+
 	DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
 	kmem_cache_free(ip_conntrack_cachep, ct);
 	atomic_dec(&ip_conntrack_count);
@@ -1305,9 +1308,14 @@
 getorigdst(struct sock *sk, int optval, void *user, int *len)
 {
 	struct ip_conntrack_tuple_hash *h;
-	struct ip_conntrack_tuple tuple = { { sk->rcv_saddr, { .tcp = { sk->sport } } },
-					    { sk->daddr, { .tcp = { sk->dport } },
-					      IPPROTO_TCP } };
+	struct ip_conntrack_tuple tuple;
+
+	IP_CT_TUPLE_U_BLANK(&tuple);
+	tuple.src.ip = sk->rcv_saddr;
+	tuple.src.u.tcp.port = sk->sport;
+	tuple.dst.ip = sk->daddr;
+	tuple.dst.u.tcp.port = sk->dport;
+	tuple.dst.protonum = IPPROTO_TCP;
 
 	/* We only do TCP at the moment: is there a better way? */
 	if (strcmp(sk->prot->name, "TCP") != 0) {
@@ -1351,29 +1359,6 @@
     SO_ORIGINAL_DST, SO_ORIGINAL_DST+1, &getorigdst,
     0, NULL };
 
-#define NET_IP_CONNTRACK_MAX 2089
-#define NET_IP_CONNTRACK_MAX_NAME "ip_conntrack_max"
-
-#ifdef CONFIG_SYSCTL
-static struct ctl_table_header *ip_conntrack_sysctl_header;
-
-static ctl_table ip_conntrack_table[] = {
-	{ NET_IP_CONNTRACK_MAX, NET_IP_CONNTRACK_MAX_NAME, &ip_conntrack_max,
-	  sizeof(ip_conntrack_max), 0644,  NULL, proc_dointvec },
- 	{ 0 }
-};
-
-static ctl_table ip_conntrack_dir_table[] = {
-	{NET_IPV4, "ipv4", NULL, 0, 0555, ip_conntrack_table, 0, 0, 0, 0, 0},
-	{ 0 }
-};
-
-static ctl_table ip_conntrack_root_table[] = {
-	{CTL_NET, "net", NULL, 0, 0555, ip_conntrack_dir_table, 0, 0, 0, 0, 0},
-	{ 0 }
-};
-#endif /*CONFIG_SYSCTL*/
-
 static int kill_all(const struct ip_conntrack *i, void *data)
 {
 	return 1;
@@ -1383,9 +1368,6 @@
    supposed to kill the mall. */
 void ip_conntrack_cleanup(void)
 {
-#ifdef CONFIG_SYSCTL
-	unregister_sysctl_table(ip_conntrack_sysctl_header);
-#endif
 	ip_ct_attach = NULL;
 	/* This makes sure all current packets have passed through
            netfilter framework.  Roll on, two-stage module
@@ -1464,25 +1446,10 @@
 	for (i = 0; i < ip_conntrack_htable_size; i++)
 		INIT_LIST_HEAD(&ip_conntrack_hash[i]);
 
-/* This is fucking braindead.  There is NO WAY of doing this without
-   the CONFIG_SYSCTL unless you don't want to detect errors.
-   Grrr... --RR */
-#ifdef CONFIG_SYSCTL
-	ip_conntrack_sysctl_header
-		= register_sysctl_table(ip_conntrack_root_table, 0);
-	if (ip_conntrack_sysctl_header == NULL) {
-		goto err_free_ct_cachep;
-	}
-#endif /*CONFIG_SYSCTL*/
-
 	/* For use by ipt_REJECT */
 	ip_ct_attach = ip_conntrack_attach;
 	return ret;
 
-#ifdef CONFIG_SYSCTL
-err_free_ct_cachep:
-	kmem_cache_destroy(ip_conntrack_cachep);
-#endif /*CONFIG_SYSCTL*/
 err_free_hash:
 	vfree(ip_conntrack_hash);
 err_unreg_sockopt:
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_irc.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_irc.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_irc.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_irc.c	2003-10-10 02:50:49.000000000 -0700
@@ -192,7 +192,10 @@
 			DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
 				HIPQUAD(dcc_ip), dcc_port);
 
-			if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)) {
+			/* dcc_ip can be the internal OR external (NAT'ed) IP
+			 * Tiago Sousa <mirage@kaotik.org> */
+			if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)
+			    && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) {
 				if (net_ratelimit())
 					printk(KERN_WARNING
 						"Forged DCC command from "
@@ -218,7 +221,7 @@
 
 			exp->tuple = ((struct ip_conntrack_tuple)
 				{ { 0, { 0 } },
-				  { htonl(dcc_ip), { .tcp = { htons(dcc_port) } },
+				  { ct->tuplehash[dir].tuple.src.ip, { .tcp = { htons(dcc_port) } },
 				    IPPROTO_TCP }});
 			exp->mask = ((struct ip_conntrack_tuple)
 				{ { 0, { 0 } },
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_proto_generic.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_proto_generic.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_proto_generic.c	2003-10-10 02:50:49.000000000 -0700
@@ -4,7 +4,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 
-#define GENERIC_TIMEOUT (600*HZ)
+unsigned long ip_ct_generic_timeout = 600*HZ;
 
 static int generic_pkt_to_tuple(const void *datah, size_t datalen,
 				struct ip_conntrack_tuple *tuple)
@@ -43,7 +43,7 @@
 		       struct iphdr *iph, size_t len,
 		       enum ip_conntrack_info conntrackinfo)
 {
-	ip_ct_refresh(conntrack, GENERIC_TIMEOUT);
+	ip_ct_refresh(conntrack, ip_ct_generic_timeout);
 	return NF_ACCEPT;
 }
 
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_proto_icmp.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2002-11-28 15:53:15.000000000 -0800
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_proto_icmp.c	2003-10-10 02:50:49.000000000 -0700
@@ -6,7 +6,7 @@
 #include <linux/icmp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 
-#define ICMP_TIMEOUT (30*HZ)
+unsigned long ip_ct_icmp_timeout = 30*HZ;
 
 #if 0
 #define DEBUGP printk
@@ -82,7 +82,7 @@
 			ct->timeout.function((unsigned long)ct);
 	} else {
 		atomic_inc(&ct->proto.icmp.count);
-		ip_ct_refresh(ct, ICMP_TIMEOUT);
+		ip_ct_refresh(ct, ip_ct_icmp_timeout);
 	}
 
 	return NF_ACCEPT;
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_proto_tcp.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_proto_tcp.c	2003-10-10 02:50:49.000000000 -0700
@@ -49,20 +49,28 @@
 #define HOURS * 60 MINS
 #define DAYS * 24 HOURS
 
-
-static unsigned long tcp_timeouts[]
-= { 30 MINS, 	/*	TCP_CONNTRACK_NONE,	*/
-    5 DAYS,	/*	TCP_CONNTRACK_ESTABLISHED,	*/
-    2 MINS,	/*	TCP_CONNTRACK_SYN_SENT,	*/
-    60 SECS,	/*	TCP_CONNTRACK_SYN_RECV,	*/
-    2 MINS,	/*	TCP_CONNTRACK_FIN_WAIT,	*/
-    2 MINS,	/*	TCP_CONNTRACK_TIME_WAIT,	*/
-    10 SECS,	/*	TCP_CONNTRACK_CLOSE,	*/
-    60 SECS,	/*	TCP_CONNTRACK_CLOSE_WAIT,	*/
-    30 SECS,	/*	TCP_CONNTRACK_LAST_ACK,	*/
-    2 MINS,	/*	TCP_CONNTRACK_LISTEN,	*/
-};
-
+unsigned long ip_ct_tcp_timeout_syn_sent =      2 MINS;
+unsigned long ip_ct_tcp_timeout_syn_recv =     60 SECS;
+unsigned long ip_ct_tcp_timeout_established =   5 DAYS;
+unsigned long ip_ct_tcp_timeout_fin_wait =      2 MINS;
+unsigned long ip_ct_tcp_timeout_close_wait =    3 DAYS;
+unsigned long ip_ct_tcp_timeout_last_ack =     30 SECS;
+unsigned long ip_ct_tcp_timeout_time_wait =     2 MINS;
+unsigned long ip_ct_tcp_timeout_close =        10 SECS;
+
+static unsigned long * tcp_timeouts[]
+= { 0,                                 /*      TCP_CONNTRACK_NONE */
+    &ip_ct_tcp_timeout_established,    /*      TCP_CONNTRACK_ESTABLISHED,      */
+    &ip_ct_tcp_timeout_syn_sent,       /*      TCP_CONNTRACK_SYN_SENT, */
+    &ip_ct_tcp_timeout_syn_recv,       /*      TCP_CONNTRACK_SYN_RECV, */
+    &ip_ct_tcp_timeout_fin_wait,       /*      TCP_CONNTRACK_FIN_WAIT, */
+    &ip_ct_tcp_timeout_time_wait,      /*      TCP_CONNTRACK_TIME_WAIT,        */
+    &ip_ct_tcp_timeout_close,          /*      TCP_CONNTRACK_CLOSE,    */
+    &ip_ct_tcp_timeout_close_wait,     /*      TCP_CONNTRACK_CLOSE_WAIT,       */
+    &ip_ct_tcp_timeout_last_ack,       /*      TCP_CONNTRACK_LAST_ACK, */
+    0,                                 /*      TCP_CONNTRACK_LISTEN */
+ };
+ 
 #define sNO TCP_CONNTRACK_NONE
 #define sES TCP_CONNTRACK_ESTABLISHED
 #define sSS TCP_CONNTRACK_SYN_SENT
@@ -203,7 +211,7 @@
 			set_bit(IPS_ASSURED_BIT, &conntrack->status);
 
 		WRITE_UNLOCK(&tcp_lock);
-		ip_ct_refresh(conntrack, tcp_timeouts[newconntrack]);
+		ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
 	}
 
 	return NF_ACCEPT;
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_proto_udp.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_proto_udp.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_proto_udp.c	2003-10-10 02:50:49.000000000 -0700
@@ -6,8 +6,8 @@
 #include <linux/udp.h>
 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
 
-#define UDP_TIMEOUT (30*HZ)
-#define UDP_STREAM_TIMEOUT (180*HZ)
+unsigned long ip_ct_udp_timeout = 30*HZ;
+unsigned long ip_ct_udp_timeout_stream = 180*HZ;
 
 static int udp_pkt_to_tuple(const void *datah, size_t datalen,
 			    struct ip_conntrack_tuple *tuple)
@@ -52,11 +52,11 @@
 	/* If we've seen traffic both ways, this is some kind of UDP
 	   stream.  Extend timeout. */
 	if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
-		ip_ct_refresh(conntrack, UDP_STREAM_TIMEOUT);
+		ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream);
 		/* Also, more likely to be important, and not a probe */
 		set_bit(IPS_ASSURED_BIT, &conntrack->status);
 	} else
-		ip_ct_refresh(conntrack, UDP_TIMEOUT);
+		ip_ct_refresh(conntrack, ip_ct_udp_timeout);
 
 	return NF_ACCEPT;
 }
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_standalone.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_conntrack_standalone.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_conntrack_standalone.c	2003-10-10 02:50:49.000000000 -0700
@@ -7,6 +7,7 @@
 /* (c) 1999 Paul `Rusty' Russell.  Licenced under the GNU General
    Public Licence. */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/ip.h>
 #include <linux/netfilter.h>
@@ -16,6 +17,9 @@
 #include <linux/proc_fs.h>
 #include <linux/version.h>
 #include <linux/brlock.h>
+#ifdef CONFIG_SYSCTL
+#include <linux/sysctl.h>
+#endif
 #include <net/checksum.h>
 
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_conntrack_lock)
@@ -239,6 +243,98 @@
 static struct nf_hook_ops ip_conntrack_local_in_ops
 = { { NULL, NULL }, ip_confirm, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_LAST-1 };
 
+/* Sysctl support */
+
+#ifdef CONFIG_SYSCTL
+
+/* From ip_conntrack_core.c */
+extern int ip_conntrack_max;
+
+/* From ip_conntrack_proto_tcp.c */
+extern unsigned long ip_ct_tcp_timeout_syn_sent;
+extern unsigned long ip_ct_tcp_timeout_syn_recv;
+extern unsigned long ip_ct_tcp_timeout_established;
+extern unsigned long ip_ct_tcp_timeout_fin_wait;
+extern unsigned long ip_ct_tcp_timeout_close_wait;
+extern unsigned long ip_ct_tcp_timeout_last_ack;
+extern unsigned long ip_ct_tcp_timeout_time_wait;
+extern unsigned long ip_ct_tcp_timeout_close;
+
+/* From ip_conntrack_proto_udp.c */
+extern unsigned long ip_ct_udp_timeout;
+extern unsigned long ip_ct_udp_timeout_stream;
+
+/* From ip_conntrack_proto_icmp.c */
+extern unsigned long ip_ct_icmp_timeout;
+
+/* From ip_conntrack_proto_icmp.c */
+extern unsigned long ip_ct_generic_timeout;
+
+static struct ctl_table_header *ip_ct_sysctl_header;
+
+static ctl_table ip_ct_sysctl_table[] = {
+	{NET_IPV4_NF_CONNTRACK_MAX, "ip_conntrack_max",
+	 &ip_conntrack_max, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT, "ip_conntrack_tcp_timeout_syn_sent",
+	 &ip_ct_tcp_timeout_syn_sent, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV, "ip_conntrack_tcp_timeout_syn_recv",
+	 &ip_ct_tcp_timeout_syn_recv, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED, "ip_conntrack_tcp_timeout_established",
+	 &ip_ct_tcp_timeout_established, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT, "ip_conntrack_tcp_timeout_fin_wait",
+	 &ip_ct_tcp_timeout_fin_wait, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT, "ip_conntrack_tcp_timeout_close_wait",
+	 &ip_ct_tcp_timeout_close_wait, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK, "ip_conntrack_tcp_timeout_last_ack",
+	 &ip_ct_tcp_timeout_last_ack, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT, "ip_conntrack_tcp_timeout_time_wait",
+	 &ip_ct_tcp_timeout_time_wait, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE, "ip_conntrack_tcp_timeout_close",
+	 &ip_ct_tcp_timeout_close, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT, "ip_conntrack_udp_timeout",
+	 &ip_ct_udp_timeout, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM, "ip_conntrack_udp_timeout_stream",
+	 &ip_ct_udp_timeout_stream, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT, "ip_conntrack_icmp_timeout",
+	 &ip_ct_icmp_timeout, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT, "ip_conntrack_generic_timeout",
+	 &ip_ct_generic_timeout, sizeof(unsigned int), 0644, NULL,
+	 &proc_dointvec_jiffies},
+	{0}
+};
+
+#define NET_IP_CONNTRACK_MAX 2089
+
+static ctl_table ip_ct_netfilter_table[] = {
+	{NET_IPV4_NETFILTER, "netfilter", NULL, 0, 0555, ip_ct_sysctl_table, 0, 0, 0, 0, 0},
+	{NET_IP_CONNTRACK_MAX, "ip_conntrack_max",
+	 &ip_conntrack_max, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{0}
+};
+
+static ctl_table ip_ct_ipv4_table[] = {
+	{NET_IPV4, "ipv4", NULL, 0, 0555, ip_ct_netfilter_table, 0, 0, 0, 0, 0},
+	{0}
+};
+
+static ctl_table ip_ct_net_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, ip_ct_ipv4_table, 0, 0, 0, 0, 0},
+	{0}
+};
+#endif
 static int init_or_cleanup(int init)
 {
 	struct proc_dir_entry *proc;
@@ -274,10 +370,20 @@
 		printk("ip_conntrack: can't register local in hook.\n");
 		goto cleanup_inoutandlocalops;
 	}
+#ifdef CONFIG_SYSCTL
+	ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table, 0);
+	if (ip_ct_sysctl_header == NULL) {
+		printk("ip_conntrack: can't register to sysctl.\n");
+		goto cleanup;
+	}
+#endif
 
 	return ret;
 
  cleanup:
+#ifdef CONFIG_SYSCTL
+ 	unregister_sysctl_table(ip_ct_sysctl_header);
+#endif
 	nf_unregister_hook(&ip_conntrack_local_in_ops);
  cleanup_inoutandlocalops:
 	nf_unregister_hook(&ip_conntrack_out_ops);
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_nat_core.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_nat_core.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_nat_core.c	2003-10-10 02:50:49.000000000 -0700
@@ -515,12 +515,14 @@
 	struct ip_conntrack_tuple new_tuple, inv_tuple, reply;
 	struct ip_conntrack_tuple orig_tp;
 	struct ip_nat_info *info = &conntrack->nat.info;
+	int in_hashes = info->initialized;
 
 	MUST_BE_WRITE_LOCKED(&ip_nat_lock);
 	IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
 		     || hooknum == NF_IP_POST_ROUTING
 		     || hooknum == NF_IP_LOCAL_OUT);
 	IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS);
+	IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
 
 	/* What we've got will look like inverse of reply. Normally
 	   this is what is in the conntrack, except for prior
@@ -637,6 +639,14 @@
 
 	/* It's done. */
 	info->initialized |= (1 << HOOK2MANIP(hooknum));
+
+	if (in_hashes) {
+		IP_NF_ASSERT(info->bysource.conntrack);
+		replace_in_hashes(conntrack, info);
+	} else {
+		place_in_hashes(conntrack, info);
+	}
+
 	return NF_ACCEPT;
 }
 
@@ -755,11 +765,6 @@
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
 
-	/* Skip everything and don't call helpers if there are no
-	 * manips for this connection */
-	if (info->num_manips == 0)
-		return NF_ACCEPT;
-
 	/* Need nat lock to protect against modification, but neither
 	   conntrack (referenced) and helper (deleted with
 	   synchronize_bh()) can vanish. */
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_nat_helper.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_nat_helper.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_nat_helper.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_nat_helper.c	2003-10-10 02:50:49.000000000 -0700
@@ -195,16 +195,11 @@
 		skb_trim(*skb, newlen);
 	}
 
-	/* fix checksum information */
-
 	iph->tot_len = htons(newlen);
-	(*skb)->csum = csum_partial((char *)tcph + tcph->doff*4,
-				    newtcplen - tcph->doff*4, 0);
-
+	/* fix checksum information */
 	tcph->check = 0;
 	tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr,
-				   csum_partial((char *)tcph, tcph->doff*4,
-					   (*skb)->csum));
+				   csum_partial((char *)tcph, newtcplen, 0));
 	ip_send_check(iph);
 
 	return 1;
@@ -299,18 +294,12 @@
 	iph->tot_len = htons(newlen);
 
 	/* fix udp checksum if udp checksum was previously calculated */
-	if ((*skb)->csum != 0) {
-		(*skb)->csum = csum_partial((char *)udph +
-					    sizeof(struct udphdr),
-					    newudplen - sizeof(struct udphdr),
-					    0);
-
+	if (udph->check != 0) {
 		udph->check = 0;
 		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
 						newudplen, IPPROTO_UDP,
 						csum_partial((char *)udph,
-							 sizeof(struct udphdr),
-							(*skb)->csum));
+						             newudplen, 0));
 	}
 
 	ip_send_check(iph);
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_nat_rule.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_nat_rule.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_nat_rule.c	2003-10-10 02:50:49.000000000 -0700
@@ -230,7 +230,7 @@
 	return 1;
 }
 
-static inline unsigned int
+inline unsigned int
 alloc_null_binding(struct ip_conntrack *conntrack,
 		   struct ip_nat_info *info,
 		   unsigned int hooknum)
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ip_nat_standalone.c linux-2.4.22-bk32/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ip_nat_standalone.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ip_nat_standalone.c	2003-10-10 02:50:49.000000000 -0700
@@ -115,7 +115,6 @@
 		/* Seen it before?  This can happen for loopback, retrans,
 		   or local packets.. */
 		if (!(info->initialized & (1 << maniptype))) {
-			int in_hashes = info->initialized;
 			unsigned int ret;
 
 			if (ct->master
@@ -126,9 +125,10 @@
 			} else {
 #ifdef CONFIG_IP_NF_NAT_LOCAL
 				/* LOCAL_IN hook doesn't have a chain!  */
-				if (hooknum == NF_IP_LOCAL_IN) {
-					ret = NF_ACCEPT;
-				} else
+				if (hooknum == NF_IP_LOCAL_IN)
+					ret = alloc_null_binding(ct, info,
+								 hooknum);
+				else
 #endif
 				ret = ip_nat_rule_find(pskb, hooknum, in, out,
 						       ct, info);
@@ -138,13 +138,6 @@
 				WRITE_UNLOCK(&ip_nat_lock);
 				return ret;
 			}
-
-			if (in_hashes) {
-				IP_NF_ASSERT(info->bysource.conntrack);
-				replace_in_hashes(ct, info);
-			} else {
-				place_in_hashes(ct, info);
-			}
 		} else
 			DEBUGP("Already setup manip %s for ct %p\n",
 			       maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
@@ -195,6 +188,7 @@
 	return ip_nat_fn(hooknum, pskb, in, out, okfn);
 }
 
+#ifdef CONFIG_IP_NF_NAT_LOCAL
 static unsigned int
 ip_nat_local_fn(unsigned int hooknum,
 		struct sk_buff **pskb,
@@ -220,6 +214,7 @@
 		return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
 	return ret;
 }
+#endif
 
 /* We must be after connection tracking and before packet filtering. */
 
@@ -229,11 +224,12 @@
 /* After packet filtering, change source */
 static struct nf_hook_ops ip_nat_out_ops
 = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
+
+#ifdef CONFIG_IP_NF_NAT_LOCAL
 /* Before packet filtering, change destination */
 static struct nf_hook_ops ip_nat_local_out_ops
 = { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST };
-
-#ifdef CONFIG_IP_NF_NAT_LOCAL
+/* After packet filtering, change source for reply packets of LOCAL_OUT DNAT */
 static struct nf_hook_ops ip_nat_local_in_ops
 = { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_LOCAL_IN, NF_IP_PRI_NAT_SRC };
 #endif
@@ -301,12 +297,12 @@
 		printk("ip_nat_init: can't register out hook.\n");
 		goto cleanup_inops;
 	}
+#ifdef CONFIG_IP_NF_NAT_LOCAL
 	ret = nf_register_hook(&ip_nat_local_out_ops);
 	if (ret < 0) {
 		printk("ip_nat_init: can't register local out hook.\n");
 		goto cleanup_outops;
 	}
-#ifdef CONFIG_IP_NF_NAT_LOCAL
 	ret = nf_register_hook(&ip_nat_local_in_ops);
 	if (ret < 0) {
 		printk("ip_nat_init: can't register local in hook.\n");
@@ -323,9 +319,9 @@
 #ifdef CONFIG_IP_NF_NAT_LOCAL
 	nf_unregister_hook(&ip_nat_local_in_ops);
  cleanup_localoutops:
-#endif
 	nf_unregister_hook(&ip_nat_local_out_ops);
  cleanup_outops:
+#endif
 	nf_unregister_hook(&ip_nat_out_ops);
  cleanup_inops:
 	nf_unregister_hook(&ip_nat_in_ops);
diff -urN linux-2.4.22-bk31/net/ipv4/netfilter/ipt_unclean.c linux-2.4.22-bk32/net/ipv4/netfilter/ipt_unclean.c
--- linux-2.4.22-bk31/net/ipv4/netfilter/ipt_unclean.c	2003-06-13 07:51:39.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/netfilter/ipt_unclean.c	2003-10-10 02:50:49.000000000 -0700
@@ -259,6 +259,24 @@
 #define	TH_ECE	0x40
 #define	TH_CWR	0x80
 
+/* table of valid flag combinations - ECE and CWR are always valid */
+static u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + 1] =
+{
+	[TH_SYN]			= 1,
+	[TH_SYN|TH_ACK]			= 1,
+	[TH_RST]			= 1,
+	[TH_RST|TH_ACK]			= 1,
+	[TH_RST|TH_ACK|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK]			= 1,
+	[TH_ACK]			= 1,
+	[TH_ACK|TH_PUSH]		= 1,
+	[TH_ACK|TH_URG]			= 1,
+	[TH_ACK|TH_URG|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK|TH_PUSH]		= 1,
+	[TH_FIN|TH_ACK|TH_URG]		= 1,
+	[TH_FIN|TH_ACK|TH_URG|TH_PUSH]	= 1
+};
+
 /* TCP-specific checks. */
 static int
 check_tcp(const struct iphdr *iph,
@@ -330,19 +348,7 @@
 
 	/* CHECK: TCP flags. */
 	tcpflags = (((u_int8_t *)tcph)[13] & ~(TH_ECE|TH_CWR));
-	if (tcpflags != TH_SYN
-	    && tcpflags != (TH_SYN|TH_ACK)
-		&& tcpflags != TH_RST
-	    && tcpflags != (TH_RST|TH_ACK)
-	    && tcpflags != (TH_RST|TH_ACK|TH_PUSH)
-	    && tcpflags != (TH_FIN|TH_ACK)
-	    && tcpflags != TH_ACK
-	    && tcpflags != (TH_ACK|TH_PUSH)
-	    && tcpflags != (TH_ACK|TH_URG)
-	    && tcpflags != (TH_ACK|TH_URG|TH_PUSH)
-	    && tcpflags != (TH_FIN|TH_ACK|TH_PUSH)
-	    && tcpflags != (TH_FIN|TH_ACK|TH_URG)
-	    && tcpflags != (TH_FIN|TH_ACK|TH_URG|TH_PUSH)) {
+	if (!tcp_valid_flags[tcpflags]) {
 		limpk("TCP flags bad: %u\n", tcpflags);
 		return 0;
 	}
diff -urN linux-2.4.22-bk31/net/ipv4/tcp_ipv4.c linux-2.4.22-bk32/net/ipv4/tcp_ipv4.c
--- linux-2.4.22-bk31/net/ipv4/tcp_ipv4.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/tcp_ipv4.c	2003-10-10 02:50:49.000000000 -0700
@@ -189,7 +189,9 @@
 		if (sk != sk2 &&
 		    sk2->reuse <= 1 &&
 		    !ipv6_only_sock(sk2) &&
-		    sk->bound_dev_if == sk2->bound_dev_if) {
+		    (!sk->bound_dev_if ||
+		     !sk2->bound_dev_if ||
+		     sk->bound_dev_if == sk2->bound_dev_if)) {
 			if (!sk_reuse	||
 			    !sk2->reuse	||
 			    sk2->state == TCP_LISTEN) {
diff -urN linux-2.4.22-bk31/net/ipv4/udp.c linux-2.4.22-bk32/net/ipv4/udp.c
--- linux-2.4.22-bk31/net/ipv4/udp.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv4/udp.c	2003-10-10 02:50:49.000000000 -0700
@@ -164,7 +164,9 @@
 			if (sk2->num == snum &&
 			    sk2 != sk &&
 			    !ipv6_only_sock(sk2) &&
-			    sk2->bound_dev_if == sk->bound_dev_if &&
+			    (!sk2->bound_dev_if ||
+			     !sk->bound_dev_if ||
+			     sk2->bound_dev_if == sk->bound_dev_if) &&
 			    (!sk2->rcv_saddr ||
 			     !sk->rcv_saddr ||
 			     sk2->rcv_saddr == sk->rcv_saddr) &&
diff -urN linux-2.4.22-bk31/net/ipv6/mcast.c linux-2.4.22-bk32/net/ipv6/mcast.c
--- linux-2.4.22-bk31/net/ipv6/mcast.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv6/mcast.c	2003-10-10 02:50:49.000000000 -0700
@@ -2020,6 +2020,9 @@
 	struct ifmcaddr6 *i;
 	struct in6_addr maddr;
 
+	/* Deactivate timers */
+	ipv6_mc_down(idev);
+
 	/* Delete all-nodes address. */
 	ipv6_addr_all_nodes(&maddr);
 
diff -urN linux-2.4.22-bk31/net/ipv6/sit.c linux-2.4.22-bk32/net/ipv6/sit.c
--- linux-2.4.22-bk31/net/ipv6/sit.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv6/sit.c	2003-10-10 02:50:50.000000000 -0700
@@ -552,8 +552,6 @@
 			tunnel->err_count = 0;
 	}
 
-	skb->h.raw = skb->nh.raw;
-
 	/*
 	 * Okay, now see if we can stuff it in the buffer as-is.
 	 */
@@ -575,6 +573,7 @@
 		iph6 = skb->nh.ipv6h;
 	}
 
+	skb->h.raw = skb->nh.raw;
 	skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
 	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	dst_release(skb->dst);
diff -urN linux-2.4.22-bk31/net/ipv6/tcp_ipv6.c linux-2.4.22-bk32/net/ipv6/tcp_ipv6.c
--- linux-2.4.22-bk31/net/ipv6/tcp_ipv6.c	2003-10-10 02:50:43.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv6/tcp_ipv6.c	2003-10-10 02:50:50.000000000 -0700
@@ -146,7 +146,9 @@
 			/* We must walk the whole port owner list in this case. -DaveM */
 			for( ; sk2 != NULL; sk2 = sk2->bind_next) {
 				if (sk != sk2 &&
-				    sk->bound_dev_if == sk2->bound_dev_if) {
+				    (!sk->bound_dev_if ||
+				     !sk2->bound_dev_if ||
+				     sk->bound_dev_if == sk2->bound_dev_if)) {
 					if (!sk_reuse	||
 					    !sk2->reuse	||
 					    sk2->state == TCP_LISTEN) {
diff -urN linux-2.4.22-bk31/net/ipv6/udp.c linux-2.4.22-bk32/net/ipv6/udp.c
--- linux-2.4.22-bk31/net/ipv6/udp.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/ipv6/udp.c	2003-10-10 02:50:50.000000000 -0700
@@ -108,7 +108,9 @@
 		     sk2 = sk2->next) {
 			if (sk2->num == snum &&
 			    sk2 != sk &&
-			    sk2->bound_dev_if == sk->bound_dev_if &&
+			    (!sk2->bound_dev_if ||
+			     !sk->bound_dev_if ||
+			     sk2->bound_dev_if == sk->bound_dev_if) &&
 			    ((!sk2->rcv_saddr && !ipv6_only_sock(sk)) ||
 			     (sk2->family == AF_INET6 && 
 			      ipv6_addr_any(&sk2->net_pinfo.af_inet6.rcv_saddr) &&
diff -urN linux-2.4.22-bk31/net/netlink/af_netlink.c linux-2.4.22-bk32/net/netlink/af_netlink.c
--- linux-2.4.22-bk31/net/netlink/af_netlink.c	2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-bk32/net/netlink/af_netlink.c	2003-10-10 02:50:50.000000000 -0700
@@ -846,8 +846,17 @@
 		size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len));
 
 	skb = alloc_skb(size, GFP_KERNEL);
-	if (!skb)
-		return;
+	if (!skb) {
+		struct sock *sk;
+
+		sk = netlink_lookup(in_skb->sk->protocol,
+				    NETLINK_CB(in_skb).pid);
+		if (sk) {
+			sk->err = ENOBUFS;
+			sk->error_report(sk);
+			sock_put(sk);
+		}
+	}
 
 	rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
 			  NLMSG_ERROR, sizeof(struct nlmsgerr));
